diff --git a/clean/audio/nes2net/SOURCE.md b/clean/audio/nes2net/SOURCE.md
new file mode 100644
index 0000000000000000000000000000000000000000..403e67b3a7e1ec2522d61b65a1d59083b751c1a0
--- /dev/null
+++ b/clean/audio/nes2net/SOURCE.md
@@ -0,0 +1,17 @@
+# Source: audio/nes2net
+
+| Field | Value |
+|---|---|
+| Upstream | **UNVERIFIED** -- provenance was lost when this code was vendored |
+| Paper | not recorded |
+| Commit SHA | **not recorded** -- the vendoring step did not preserve it |
+| Mirrored on | 2026-09-15 |
+| Upstream license | no license file present upstream (all rights reserved) |
+
+This is a **mirror**, stripped to the files needed for inference. The full
+untouched snapshot is at `archive/audio__nes2net.tar.gz`.
+
+This code is the work of its original authors and is **not** covered by the
+DeepSafe project license. If you are an author and want this removed, open an
+issue on https://github.com/deepsafehq/deepsafe-bench and it will be taken down
+within 48 hours, no questions asked.
diff --git a/clean/audio/nes2net/__init__.py b/clean/audio/nes2net/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/clean/audio/nes2net/wav2vec2_Nes2Net_X.py b/clean/audio/nes2net/wav2vec2_Nes2Net_X.py
new file mode 100644
index 0000000000000000000000000000000000000000..4d8b5917d96c3217fe457828e619f1c1abbc69a3
--- /dev/null
+++ b/clean/audio/nes2net/wav2vec2_Nes2Net_X.py
@@ -0,0 +1,317 @@
+import math
+
+import fairseq
+import torch
+import torch.nn as nn
+
+___author__ = "Tianchi Liu"
+__email__ = "tianchi_liu@u.nus.edu"
+# modified from the model script from Hemlata Tak
+
+
+class SSLModel(nn.Module):
+ def __init__(self, device):
+ super(SSLModel, self).__init__()
+ cp_path = (
+ "/app/weights/xlsr2_300m.pt" # Change the pre-trained XLSR model path.
+ )
+ model, cfg, task = fairseq.checkpoint_utils.load_model_ensemble_and_task(
+ [cp_path]
+ )
+ self.model = model[0]
+ self.device = device
+ self.out_dim = 1024
+ return
+
+ def extract_feat(self, input_data):
+ # put the model to GPU if it not there
+ if (
+ next(self.model.parameters()).device != input_data.device
+ or next(self.model.parameters()).dtype != input_data.dtype
+ ):
+ self.model.to(input_data.device, dtype=input_data.dtype)
+ self.model.train()
+ if True:
+ # input should be in shape (batch, length)
+ if input_data.ndim == 3:
+ input_tmp = input_data[:, :, 0]
+ else:
+ input_tmp = input_data
+ # [batch, length, dim]
+ emb = self.model(input_tmp, mask=False, features_only=True)["x"]
+ return emb
+
+
+class SEModule(nn.Module):
+ def __init__(self, channels, SE_ratio=8):
+ super(SEModule, self).__init__()
+ self.se = nn.Sequential(
+ nn.AdaptiveAvgPool1d(1),
+ nn.Conv1d(channels, channels // SE_ratio, kernel_size=1, padding=0),
+ nn.ReLU(),
+ nn.Conv1d(channels // SE_ratio, channels, kernel_size=1, padding=0),
+ nn.Sigmoid(),
+ )
+
+ def forward(self, input):
+ x = self.se(input)
+ return input * x
+
+
+class Bottle2neck(nn.Module):
+
+ def __init__(
+ self, inplanes, planes, kernel_size=None, dilation=None, scale=8, SE_ratio=8
+ ):
+ super(Bottle2neck, self).__init__()
+ width = int(math.floor(planes / scale))
+ self.conv1 = nn.Conv1d(inplanes, width * scale, kernel_size=1)
+ self.bn1 = nn.BatchNorm1d(width * scale)
+ self.nums = scale - 1
+ convs = []
+ bns = []
+ weighted_sum = []
+ num_pad = math.floor(kernel_size / 2) * dilation
+ for i in range(self.nums):
+ convs.append(
+ nn.Conv2d(
+ width,
+ width,
+ kernel_size=(kernel_size, 1),
+ dilation=(dilation, 1),
+ padding=(num_pad, 0),
+ )
+ )
+ bns.append(nn.BatchNorm2d(width))
+ initial_value = torch.ones(1, 1, 1, i + 2) * (1 / (i + 2))
+ weighted_sum.append(nn.Parameter(initial_value, requires_grad=True))
+ self.weighted_sum = nn.ParameterList(weighted_sum)
+ self.convs = nn.ModuleList(convs)
+ self.bns = nn.ModuleList(bns)
+ self.conv3 = nn.Conv1d(width * scale, planes, kernel_size=1)
+ self.bn3 = nn.BatchNorm1d(planes)
+ self.relu = nn.ReLU()
+ self.width = width
+ self.se = SEModule(planes, SE_ratio)
+
+ def forward(self, x):
+ residual = x
+ out = self.conv1(x)
+ out = self.relu(out)
+ out = self.bn1(out).unsqueeze(-1) # bz c T 1
+
+ spx = torch.split(out, self.width, 1)
+ sp = spx[self.nums]
+ for i in range(self.nums):
+ sp = torch.cat((sp, spx[i]), -1)
+
+ sp = self.bns[i](self.relu(self.convs[i](sp)))
+ sp_s = sp * self.weighted_sum[i]
+ sp_s = torch.sum(sp_s, dim=-1, keepdim=False)
+
+ if i == 0:
+ out = sp_s
+ else:
+ out = torch.cat((out, sp_s), 1)
+ out = torch.cat((out, spx[self.nums].squeeze(-1)), 1)
+ out = self.conv3(out)
+ out = self.relu(out)
+ out = self.bn3(out)
+ out = self.se(out)
+ out += residual
+ return out
+
+
+class ASTP(nn.Module):
+ """Attentive statistics pooling: Channel- and context-dependent
+ statistics pooling, first used in ECAPA_TDNN.
+ """
+
+ def __init__(self, in_dim, bottleneck_dim=128, global_context_att=False):
+ super(ASTP, self).__init__()
+ self.global_context_att = global_context_att
+
+ # Use Conv1d with stride == 1 rather than Linear, then we don't
+ # need to transpose inputs.
+ if global_context_att:
+ self.linear1 = nn.Conv1d(
+ in_dim * 3, bottleneck_dim, kernel_size=1
+ ) # equals W and b in the paper
+ else:
+ self.linear1 = nn.Conv1d(
+ in_dim, bottleneck_dim, kernel_size=1
+ ) # equals W and b in the paper
+ self.linear2 = nn.Conv1d(
+ bottleneck_dim, in_dim, kernel_size=1
+ ) # equals V and k in the paper
+
+ def forward(self, x):
+ """
+ x: a 3-dimensional tensor in tdnn-based architecture (B,F,T)
+ or a 4-dimensional tensor in resnet architecture (B,C,F,T)
+ 0-dim: batch-dimension, last-dim: time-dimension (frame-dimension)
+ """
+ if len(x.shape) == 4:
+ x = x.reshape(x.shape[0], x.shape[1] * x.shape[2], x.shape[3])
+ assert len(x.shape) == 3
+
+ if self.global_context_att:
+ context_mean = torch.mean(x, dim=-1, keepdim=True).expand_as(x)
+ context_std = torch.sqrt(
+ torch.var(x, dim=-1, keepdim=True) + 1e-10
+ ).expand_as(x)
+ x_in = torch.cat((x, context_mean, context_std), dim=1)
+ else:
+ x_in = x
+
+ # DON'T use ReLU here! ReLU may be hard to converge.
+ alpha = torch.tanh(self.linear1(x_in)) # alpha = F.relu(self.linear1(x_in))
+ alpha = torch.softmax(self.linear2(alpha), dim=2)
+ mean = torch.sum(alpha * x, dim=2)
+ var = torch.sum(alpha * (x**2), dim=2) - mean**2
+ std = torch.sqrt(var.clamp(min=1e-10))
+ return torch.cat([mean, std], dim=1)
+
+
+class Nested_Res2Net_TDNN(nn.Module):
+
+ def __init__(
+ self,
+ Nes_ratio=[8, 8],
+ input_channel=1024,
+ n_output_logits=2,
+ dilation=2,
+ pool_func="mean",
+ SE_ratio=[8],
+ ):
+
+ super(Nested_Res2Net_TDNN, self).__init__()
+ self.Nes_ratio = Nes_ratio[0]
+ assert input_channel % Nes_ratio[0] == 0
+ C = input_channel // Nes_ratio[0]
+ self.C = C
+ Build_in_Res2Nets = []
+ bns = []
+ for i in range(Nes_ratio[0] - 1):
+ Build_in_Res2Nets.append(
+ Bottle2neck(
+ C,
+ C,
+ kernel_size=3,
+ dilation=dilation,
+ scale=Nes_ratio[1],
+ SE_ratio=SE_ratio[0],
+ )
+ )
+ bns.append(nn.BatchNorm1d(C))
+ self.Build_in_Res2Nets = nn.ModuleList(Build_in_Res2Nets)
+ self.bns = nn.ModuleList(bns)
+ self.bn = nn.BatchNorm1d(1024)
+ self.relu = nn.ReLU()
+ self.pool_func = pool_func
+ if pool_func == "mean":
+ self.fc = nn.Linear(1024, n_output_logits)
+ elif pool_func == "ASTP":
+ self.pooling = ASTP(
+ in_dim=input_channel, bottleneck_dim=128, global_context_att=False
+ )
+ self.fc = nn.Linear(2048, n_output_logits)
+
+ def forward(self, x):
+ spx = torch.split(x, self.C, 1)
+ for i in range(self.Nes_ratio - 1):
+ if i == 0:
+ sp = spx[i]
+ else:
+ sp = sp + spx[i]
+ sp = self.Build_in_Res2Nets[i](sp)
+ sp = self.relu(sp)
+ sp = self.bns[i](sp)
+ if i == 0:
+ out = sp
+ else:
+ out = torch.cat((out, sp), 1)
+ out = torch.cat((out, spx[-1]), 1)
+ out = self.bn(out)
+ out = self.relu(out)
+ if self.pool_func == "mean":
+ out = torch.mean(out, dim=-1)
+ elif self.pool_func == "ASTP":
+ out = self.pooling(out)
+ out = self.fc(out)
+ return out
+
+
+class wav2vec2_Nes2Net_no_Res_w_allT(nn.Module):
+ def __init__(self, args, device):
+ super().__init__()
+ self.device = device
+
+ self.n_output_logits = args.n_output_logits
+
+ ####
+ # create network wav2vec 2.0
+ ####
+ self.ssl_model = SSLModel(self.device)
+ self.Nested_Res2Net_TDNN = Nested_Res2Net_TDNN(
+ Nes_ratio=args.Nes_ratio,
+ input_channel=1024,
+ n_output_logits=self.n_output_logits,
+ dilation=args.dilation,
+ pool_func=args.pool_func,
+ SE_ratio=args.SE_ratio,
+ )
+
+ def forward(self, x):
+ # -------pre-trained Wav2vec model fine tunning ------------------------##
+ x_ssl_feat = self.ssl_model.extract_feat(x.squeeze(-1))
+ x_ssl_feat = x_ssl_feat.permute(0, 2, 1)
+ output = self.Nested_Res2Net_TDNN(x_ssl_feat)
+
+ return output
+
+
+if __name__ == "__main__":
+ import argparse
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--n_output_logits", type=int, default=2)
+ parser.add_argument("--dilation", type=int, default=2) # not important
+ parser.add_argument(
+ "--pool_func",
+ type=str,
+ default="mean",
+ choices=["mean", "ASTP"],
+ help="pooling function, choose from mean and ASTP",
+ )
+ parser.add_argument(
+ "--Nes_ratio",
+ type=int,
+ nargs="+",
+ default=[8, 8],
+ help="Nes_ratio, from outer to inner",
+ )
+ parser.add_argument(
+ "--SE_ratio",
+ type=int,
+ nargs="+",
+ default=[1],
+ help="SE downsampling ratio in the bottleneck",
+ )
+ args = parser.parse_args()
+
+ model = wav2vec2_Nes2Net_no_Res_w_allT(args=args, device="cpu")
+ x = torch.rand((4, 32000)).to("cpu")
+ model = model.to("cpu")
+ y = model(x)
+ print(y)
+ trainable_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
+ print("all:", trainable_params)
+ trainable_params = sum(
+ p.numel() for p in model.ssl_model.parameters() if p.requires_grad
+ )
+ print("SSL:", trainable_params)
+ trainable_params = sum(
+ p.numel() for p in model.Nested_Res2Net_TDNN.parameters() if p.requires_grad
+ )
+ print("Backend:", trainable_params)
diff --git a/clean/audio/safeear/.gitignore b/clean/audio/safeear/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..290e216340cefdeac36872c41c79f4217a6dce42
--- /dev/null
+++ b/clean/audio/safeear/.gitignore
@@ -0,0 +1,167 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+# For a library or package, you might want to ignore these files since the code is
+# intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# poetry
+# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
+# This is especially recommended for binary packages to ensure reproducibility, and is more
+# commonly ignored for libraries.
+# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
+#poetry.lock
+
+# pdm
+# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
+#pdm.lock
+# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
+# in version control.
+# https://pdm.fming.dev/#use-with-ide
+.pdm.toml
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
+
+# PyCharm
+# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
+# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
+# and can be added to the global gitignore or merged into this file. For a more nuclear
+# option (not recommended) you can uncomment the following to ignore the entire idea folder.
+#.idea/
+model_zoos/*
+Exps/*
+datas/datasets
+datas/ASVSpoof2019/LA
+datas/ASVSpoof2021/ASVspoof2021_LA_eval
+datas/ASVSpoof2021/keys
+create_tsv.py
\ No newline at end of file
diff --git a/clean/audio/safeear/LICENSE b/clean/audio/safeear/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..7afa6327c9be0d2fc4ddba8c5a6556e340e38b62
--- /dev/null
+++ b/clean/audio/safeear/LICENSE
@@ -0,0 +1,23 @@
+# Creative Commons Attribution 4.0 International License
+
+## License
+
+You are free to:
+
+- Share — copy and redistribute the material in any medium or format
+- Adapt — remix, transform, and build upon the material for any purpose, even commercially.
+
+Under the following terms:
+
+1. **Attribution** — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
+
+2. **No additional restrictions** — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits.
+
+## Other Terms
+
+- This license applies to all types of works, including but not limited to text, images, audio, video, etc.
+- This license does not apply to any third-party materials included in the work, for which you must obtain permission separately.
+
+## Disclaimer
+
+This work is provided on an "as is" basis, without any warranties or conditions of any kind, either express or implied, including but not limited to implied warranties of merchantability, fitness for a particular purpose, or non-infringement.
diff --git a/clean/audio/safeear/README.md b/clean/audio/safeear/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..eac42179818705bb45aee6b45e8a40efcc0b48b8
--- /dev/null
+++ b/clean/audio/safeear/README.md
@@ -0,0 +1,134 @@
+# Safe Ear : Content Privacy-Preserving Audio Deepfake Detection
+
+[](https://arxiv.org/abs/2409.09272)
+[](https://makeapullrequest.com)
+[](https://creativecommons.org/licenses/by/4.0/)
+
+
+
+
+
+By [1] Zhejiang University, [2] Tsinghua University.
+* [Xinfeng Li](https://letterligo.github.io)* [1], [Kai Li](https://cslikai.cn)* [2], Yifan Zheng [1], Chen Yan† [1], Xiaoyu Ji [1], Wenyuan Xu [1].
+
+This repository is an official implementation of the SafeEar accepted to **ACM CCS 2024** (Core-A*, CCF-A, Big4) .
+
+Please also visit our (1) Project Website , (2) Full CVoiceFake Dataset , and (3) Sampled CVoiceFake Dataset .
+
+## 🔥News
+
+[2025-03-18]: Supported the batch testing for ASVspoof 2019 and 2021, fixed some bugs for datasets and trainer.
+
+[2024-12-10]: Fixed all the bugs for training and test, and uploaded the files for data generation `datas/`.
+
+[2024-12-01]: Uploaded the checkpoint for data generation `datas/`.
+
+## ✨Key Highlights:
+
+In this paper, we propose SafeEar, a novel framework that aims to detect deepfake audios without relying on accessing the speech content within. Our key idea is to devise a neural audio codec into a novel decoupling model that well separates the semantic and acoustic information from audio samples, and only use the acoustic information (e.g., prosody and timbre) for deepfake detection. In this way, no semantic content will be exposed to the detector. To overcome the challenge of identifying diverse deepfake audio without semantic clues, we enhance our deepfake detector with multi-head self-attention and codec augmentation. Extensive experiments conducted on four benchmark datasets demonstrate SafeEar’s effectiveness in detecting various deepfake techniques with an equal error rate (EER) down to 2.02%. Simultaneously, it shields five-language speech content from being deciphered by both machine and human auditory analysis, demonstrated by word error rates (WERs) all above 93.93% and our user study. Furthermore, our benchmark constructed for anti-deepfake and anti-content recovery evaluation helps provide a basis for future research in the realms of audio privacy preservation and deepfake detection.
+
+## 🚀Overall Pipeline
+
+
+
+## 🔧Installation
+
+1. Clone the repository:
+
+```shell
+git clone git@github.com:LetterLiGo/SafeEar.git
+cd SafeEar/
+```
+
+2. Create and activate the conda environment:
+
+```shell
+conda create -n safeear python=3.9
+conda activate safeear
+```
+
+3. Install PyTorch and torchvision following the [official instructions](https://pytorch.org). The code requires `python=3.9`, `pytorch=1.13`, `torchvision=0.14`.
+
+
+```shell
+pip install torch==1.13.1+cu116 torchvision==0.14.1+cu116 torchaudio==0.13.1 --extra-index-url https://download.pytorch.org/whl/cu116
+
+```
+4. Install other dependencies:
+
+```shell
+pip install pip==24.0
+pip install -r requirements.txt
+```
+
+## 📊Model Performance
+### ASVspoof 2019 & 2021
+
+### Speech Recognition Performance
+
+
+## Data preparation
+
+### AVSpoof 2019 & 2021
+
+Please download the [ASVspoof 2019](https://datashare.is.ed.ac.uk/handle/10283/3336) and [ASVspoof 2021](https://www.asvspoof.org/index2021.html) datasets and extract them to the `datas/datasets` directory.
+
+```shell
+datas/datasets/ASVspoof2019
+datas/datasets/ASVspoof2021
+```
+
+#### Generate the Hubert L9 feature files
+
+```shell
+mkdir model_zoos
+cd model_zoos
+wget https://dl.fbaipublicfiles.com/hubert/hubert_base_ls960.pt
+wget https://cloud.tsinghua.edu.cn/f/413a0cd2e6f749eea956/?dl=1 -O SpeechTokenizer.pt
+cd ../datas
+# Generate the Hubert L9 feature files for ASVspoof 2019
+python dump_hubert_avg_feature.py datasets/ASVSpoof2019 datasets/ASVSpoof2019_Hubert_L9
+# Generate the Hubert L9 feature files for ASVspoof 2021
+python dump_hubert_avg_feature.py datasets/ASVSpoof2021 datasets/ASVSpoof2021_Hubert_L9
+```
+
+## 📚Training
+
+Before starting training, please modify the parameter configurations in [`configs`](configs).
+
+Use the following commands to start training:
+
+```shell
+python train.py --conf_dir config/train19.yaml
+python train.py --conf_dir config/train21.yaml
+```
+
+## 📈Testing/Inference
+
+To evaluate a model on one or more GPUs, specify the `CUDA_VISIBLE_DEVICES`, `dataset`, `model` and `checkpoint`:
+
+```shell
+python test.py --conf_dir Exps/ASVspoof19/config.yaml
+python test.py --conf_dir Exps/ASVspoof21/config.yaml
+```
+
+## Bugs and Issues
+
+If you meet `RuntimeError: Failed to load audio from <_io.BytesIO object at 0x7f45cb978f90>`, please use the following command to fix it:
+
+```shell
+conda install -c anaconda 'ffmpeg<4.4'
+```
+
+## 📜Citation
+
+If you find our work/code/dataset helpful, please consider citing:
+
+```
+@inproceedings{li2024safeear,
+ author = {Li, Xinfeng and Li, Kai and Zheng, Yifan and Yan, Chen and Ji, Xiaoyu, and Xu, Wenyuan},
+ title = {{SafeEar: Content Privacy-Preserving Audio Deepfake Detection}},
+ booktitle = {Proceedings of the 2024 {ACM} {SIGSAC} Conference on Computer and Communications Security (CCS)}
+ year = {2024},
+}
+```
diff --git a/clean/audio/safeear/SOURCE.md b/clean/audio/safeear/SOURCE.md
new file mode 100644
index 0000000000000000000000000000000000000000..f78f60a0a80beb9f34b0ad54739d2278d75f1234
--- /dev/null
+++ b/clean/audio/safeear/SOURCE.md
@@ -0,0 +1,17 @@
+# Source: audio/safeear
+
+| Field | Value |
+|---|---|
+| Upstream | **UNVERIFIED** -- provenance was lost when this code was vendored |
+| Paper | https://arxiv.org/abs/2409.09272 |
+| Commit SHA | **not recorded** -- the vendoring step did not preserve it |
+| Mirrored on | 2026-09-15 |
+| Upstream license | LICENSE |
+
+This is a **mirror**, stripped to the files needed for inference. The full
+untouched snapshot is at `archive/audio__safeear.tar.gz`.
+
+This code is the work of its original authors and is **not** covered by the
+DeepSafe project license. If you are an author and want this removed, open an
+issue on https://github.com/deepsafehq/deepsafe-bench and it will be taken down
+within 48 hours, no questions asked.
diff --git a/clean/audio/safeear/config/train19.yaml b/clean/audio/safeear/config/train19.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..5d1c58f347f6ce8d3a6b5d3553f4f7eca803c60f
--- /dev/null
+++ b/clean/audio/safeear/config/train19.yaml
@@ -0,0 +1,87 @@
+datamodule:
+ _target_: safeear.datas.asvspoof19.DataModule
+ batch_size: 2
+ num_workers: 8
+ pin_memory: true
+ DataClass_dict:
+ _target_: safeear.datas.asvspoof19.DataClass
+ train_path: ["datas/ASVSpoof2019/train.tsv", "datas/ASVSpoof2019/ASVspoof2019.LA.cm.train.trn.txt", "datas/datasets/ASVSpoof2019_Hubert_L9/ASVspoof2019_LA_train/flac"]
+ val_path: ["datas/ASVSpoof2019/dev.tsv", "datas/ASVSpoof2019/ASVspoof2019.LA.cm.dev.trl.txt", "datas/datasets/ASVSpoof2019_Hubert_L9/ASVspoof2019_LA_dev/flac"]
+ test_path: ["datas/ASVSpoof2019/eval.tsv", "datas/ASVSpoof2019/ASVspoof2019.LA.cm.eval.trl.txt", "datas/datasets/ASVSpoof2019_Hubert_L9/ASVspoof2019_LA_eval/flac"]
+ max_len: 64600
+
+decouple_model:
+ _target_: safeear.models.decouple.SpeechTokenizer
+ n_filters: 64
+ strides: [8,5,4,2]
+ dimension: 1024
+ semantic_dimension: 768
+ bidirectional: true
+ dilation_base: 2
+ residual_kernel_size: 3
+ n_residual_layers: 1
+ lstm_layers: 2
+ activation: ELU
+ codebook_size: 1024
+ n_q: 8
+ sample_rate: 16000
+
+speechtokenizer_path: model_zoos/SpeechTokenizer.pt
+
+detect_model:
+ _target_: safeear.models.safeear.SafeEar1s
+ front:
+ _target_: safeear.models.safeear.SE_Rawformer_front
+ embedding_dim: 1024
+ dropout_rate: 0.1
+ attention_dropout: 0.1
+ stochastic_depth: 0.1
+ num_layers: 2
+ num_heads: 8
+ num_classes: 2
+ positional_embedding: 'sine'
+ mlp_ratio: 1.0
+
+system:
+ _target_: safeear.trainer.safeear_trainer.SafeEarTrainer
+ lr_raw_former: 3.0e-4
+ save_score_path: ${exp.dir}/${exp.name}
+
+exp:
+ dir: Exps/ # 修改
+ name: ASVspoof19 # 修改
+
+early_stopping:
+ _target_: pytorch_lightning.callbacks.EarlyStopping
+ monitor: val_eer # 修改
+ mode: min
+ patience: 40
+ verbose: true
+
+checkpoint:
+ _target_: pytorch_lightning.callbacks.ModelCheckpoint
+ dirpath: ${exp.dir}/${exp.name}/checkpoints
+ monitor: val_eer # 修改
+ mode: min
+ verbose: true
+ save_top_k: 1
+ save_last: true
+ filename: '{epoch}-{val_eer:.4f}' # 修改
+
+logger:
+ _target_: pytorch_lightning.loggers.WandbLogger
+ name: ${exp.name}
+ save_dir: ${exp.dir}/${exp.name}/logs
+ offline: true
+ project: SafeEar
+
+trainer:
+ _target_: pytorch_lightning.Trainer
+ devices: [0]
+ max_epochs: 500
+ sync_batchnorm: true
+ default_root_dir: ${exp.dir}/${exp.name}/
+ accelerator: gpu
+ limit_train_batches: 1.0
+ limit_val_batches: 1.0
+ fast_dev_run: false
\ No newline at end of file
diff --git a/clean/audio/safeear/config/train21.yaml b/clean/audio/safeear/config/train21.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..afe4eb6de5daa34b9a92500a927f4d8976361228
--- /dev/null
+++ b/clean/audio/safeear/config/train21.yaml
@@ -0,0 +1,87 @@
+datamodule:
+ _target_: safeear.datas.asvspoof21.DataModule
+ batch_size: 2
+ num_workers: 8
+ pin_memory: true
+ DataClass_dict:
+ _target_: safeear.datas.asvspoof21.DataClass
+ train_path: ["datas/ASVSpoof2019/train.tsv", "datas/ASVSpoof2019/ASVspoof2019.LA.cm.train.trn.txt", "datas/datasets/ASVSpoof2019_Hubert_L9/ASVspoof2019_LA_train/flac"]
+ val_path: ["datas/ASVSpoof2019/dev.tsv", "datas/ASVSpoof2019/ASVspoof2019.LA.cm.dev.trl.txt", "datas/datasets/ASVSpoof2019_Hubert_L9/ASVspoof2019_LA_dev/flac"]
+ test_path: ["datas/ASVSpoof2021/eval.tsv", "datas/ASVSpoof2021/ASVspoof2021.LA.cm.eval.trl.txt", "datas/datasets/ASVSpoof2021_Hubert_L9"]
+ max_len: 64600
+
+decouple_model:
+ _target_: safeear.models.decouple.SpeechTokenizer
+ n_filters: 64
+ strides: [8,5,4,2]
+ dimension: 1024
+ semantic_dimension: 768
+ bidirectional: true
+ dilation_base: 2
+ residual_kernel_size: 3
+ n_residual_layers: 1
+ lstm_layers: 2
+ activation: ELU
+ codebook_size: 1024
+ n_q: 8
+ sample_rate: 16000
+
+speechtokenizer_path: model_zoos/SpeechTokenizer.pt
+
+detect_model:
+ _target_: safeear.models.safeear.SafeEar1s
+ front:
+ _target_: safeear.models.safeear.SE_Rawformer_front
+ embedding_dim: 1024
+ dropout_rate: 0.1
+ attention_dropout: 0.1
+ stochastic_depth: 0.1
+ num_layers: 2
+ num_heads: 8
+ num_classes: 2
+ positional_embedding: 'sine'
+ mlp_ratio: 1.0
+
+system:
+ _target_: safeear.trainer.safeear_trainer.SafeEarTrainer
+ lr_raw_former: 3.0e-4
+ save_score_path: ${exp.dir}/${exp.name}
+
+exp:
+ dir: Exps/ # 修改
+ name: ASVspoof21 # 修改
+
+early_stopping:
+ _target_: pytorch_lightning.callbacks.EarlyStopping
+ monitor: val_eer # 修改
+ mode: min
+ patience: 40
+ verbose: true
+
+checkpoint:
+ _target_: pytorch_lightning.callbacks.ModelCheckpoint
+ dirpath: ${exp.dir}/${exp.name}/checkpoints
+ monitor: val_eer # 修改
+ mode: min
+ verbose: true
+ save_top_k: 1
+ save_last: true
+ filename: '{epoch}-{val_eer:.4f}' # 修改
+
+logger:
+ _target_: pytorch_lightning.loggers.WandbLogger
+ name: ${exp.name}
+ save_dir: ${exp.dir}/${exp.name}/logs
+ offline: true
+ project: SafeEar
+
+trainer:
+ _target_: pytorch_lightning.Trainer
+ devices: [0]
+ max_epochs: 40
+ sync_batchnorm: true
+ default_root_dir: ${exp.dir}/${exp.name}/
+ accelerator: gpu
+ limit_train_batches: 1.0
+ limit_val_batches: 1.0
+ fast_dev_run: false
diff --git a/clean/audio/safeear/requirements.txt b/clean/audio/safeear/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..581bfa7667488cc011bb2a83670b4447468a3937
--- /dev/null
+++ b/clean/audio/safeear/requirements.txt
@@ -0,0 +1,123 @@
+absl-py==2.1.0
+aiohttp==3.9.0
+aiosignal==1.3.1
+antlr4-python3-runtime==4.8
+appdirs==1.4.4
+asttokens==2.4.1
+async-timeout==4.0.3
+attrs==23.1.0
+audioread==3.0.1
+bitarray==2.8.3
+blessed==1.20.0
+certifi==2022.12.7
+cffi==1.16.0
+charset-normalizer==2.1.1
+click==8.1.7
+cmake==3.25.0
+colorama==0.4.6
+contourpy==1.2.0
+cycler==0.12.1
+Cython==3.0.5
+decorator==5.1.1
+docker-pycreds==0.4.0
+einops==0.7.0
+exceptiongroup==1.2.0
+executing==2.0.1
+# Editable install with no version control (fairseq==1.0.0a0)
+-e fairseq_ours
+fast-bss-eval==0.1.4
+filelock==3.9.0
+fonttools==4.45.0
+frozenlist==1.4.0
+fsspec==2023.10.0
+gitdb==4.0.11
+GitPython==3.1.40
+gpustat==1.1.1
+grpcio==1.63.0
+huggingface-hub==0.19.4
+hydra-core==1.0.7
+idna==3.4
+importlib-resources==6.1.1
+importlib_metadata==7.1.0
+ipdb==0.13.13
+ipython==8.18.1
+jedi==0.19.1
+Jinja2==3.1.2
+joblib==1.4.2
+kiwisolver==1.4.5
+lazy_loader==0.4
+librosa==0.10.2
+lightning-utilities==0.10.0
+lit==15.0.7
+llvmlite==0.42.0
+lxml==4.9.3
+Markdown==3.6
+markdown-it-py==3.0.0
+MarkupSafe==2.1.3
+matplotlib==3.8.2
+matplotlib-inline==0.1.6
+mdurl==0.1.2
+mpmath==1.3.0
+msgpack==1.0.8
+multidict==6.0.4
+networkx==3.0
+numba==0.59.1
+numpy==1.23.5
+nvidia-ml-py==12.535.133
+opencv-python==4.9.0.80
+packaging==23.2
+parso==0.8.3
+pexpect==4.9.0
+Pillow==9.3.0
+platformdirs==4.2.1
+pooch==1.8.1
+portalocker==2.8.2
+prompt-toolkit==3.0.43
+protobuf==4.25.1
+psutil==5.9.6
+ptyprocess==0.7.0
+pure-eval==0.2.2
+pycparser==2.21
+pyDeprecate==0.3.2
+Pygments==2.17.2
+pyparsing==3.1.1
+python-dateutil==2.8.2
+pytorch-lightning==1.6.3
+pytorch-ranger==0.1.1
+PyYAML==6.0.1
+regex==2023.10.3
+requests==2.28.1
+rich==13.7.0
+sacrebleu==2.3.2
+safetensors==0.4.0
+scikit-learn==1.4.2
+scipy==1.11.4
+sentry-sdk==1.36.0
+setproctitle==1.3.3
+six==1.16.0
+smmap==5.0.1
+soundfile>=0.11.0
+soxr==0.3.7
+stack-data==0.6.3
+sympy==1.12
+tabulate==0.9.0
+tensorboard==2.16.2
+tensorboard-data-server==0.7.2
+thop==0.1.1.post2209072238
+threadpoolctl==3.5.0
+timm==0.9.11
+tomli==2.0.1
+torch-mir-eval==0.4
+torch-optimizer==0.3.0
+torchmetrics==1.2.0
+tqdm==4.66.1
+traitlets==5.14.1
+triton==2.0.0
+typing_extensions==4.4.0
+urllib3==1.26.13
+wandb==0.16.0
+wcwidth==0.2.12
+Werkzeug==3.0.2
+yarl==1.9.3
+zipp==3.17.0
+npy_append_array==0.9.16
\ No newline at end of file
diff --git a/clean/audio/safeear/safeear/losses/loss.py b/clean/audio/safeear/safeear/losses/loss.py
new file mode 100644
index 0000000000000000000000000000000000000000..f3a8b924296de6cb506053e2699565bfffccc091
--- /dev/null
+++ b/clean/audio/safeear/safeear/losses/loss.py
@@ -0,0 +1,215 @@
+import torch
+import torch.nn.functional as F
+from torchaudio.transforms import MelSpectrogram
+import numpy as np
+
+def adversarial_g_loss(y_disc_gen):
+ """Hinge loss"""
+ loss = 0.0
+ for i in range(len(y_disc_gen)):
+ stft_loss = F.relu(1 - y_disc_gen[i]).mean().squeeze()
+ loss += stft_loss
+ return loss / len(y_disc_gen)
+
+
+def feature_loss(fmap_r, fmap_gen):
+ loss = 0.0
+ for i in range(len(fmap_r)):
+ for j in range(len(fmap_r[i])):
+ stft_loss = ((fmap_r[i][j] - fmap_gen[i][j]).abs() /
+ (fmap_r[i][j].abs().mean())).mean()
+ loss += stft_loss
+ return loss / (len(fmap_r) * len(fmap_r[0]))
+
+
+def sim_loss(y_disc_r, y_disc_gen):
+ loss = 0.0
+ for i in range(len(y_disc_r)):
+ loss += F.mse_loss(y_disc_r[i], y_disc_gen[i])
+ return loss / len(y_disc_r)
+
+def reconstruction_loss(x, G_x, lamdba_wav=100, sr=16000, eps=1e-7):
+ # NOTE (lsx): hard-coded now
+ L = lamdba_wav * F.mse_loss(x, G_x) # wav L1 loss
+ # loss_sisnr = sisnr_loss(G_x, x) #
+ # L += 0.01*loss_sisnr
+ # 2^6=64 -> 2^10=1024
+ # NOTE (lsx): add 2^11
+ for i in range(6, 12):
+ # for i in range(5, 12): # Encodec setting
+ s = 2**i
+ melspec = MelSpectrogram(
+ sample_rate=sr,
+ n_fft=s,
+ hop_length=s // 4,
+ n_mels=64,
+ wkwargs={"device": x.device}).to(x.device)
+ S_x = melspec(x)
+ S_G_x = melspec(G_x)
+ loss = ((S_x - S_G_x).abs().mean() + (
+ ((torch.log(S_x.abs() + eps) - torch.log(S_G_x.abs() + eps))**2
+ ).mean(dim=-2)**0.5).mean()) / i
+ L += loss
+ return L
+
+
+def criterion_d(y_disc_r, y_disc_gen, fmap_r_det, fmap_gen_det, y_df_hat_r,
+ y_df_hat_g, fmap_f_r, fmap_f_g, y_ds_hat_r, y_ds_hat_g,
+ fmap_s_r, fmap_s_g):
+ """Hinge Loss"""
+ loss = 0.0
+ loss1 = 0.0
+ loss2 = 0.0
+ loss3 = 0.0
+ for i in range(len(y_disc_r)):
+ loss1 += F.relu(1 - y_disc_r[i]).mean() + F.relu(1 + y_disc_gen[
+ i]).mean()
+ for i in range(len(y_df_hat_r)):
+ loss2 += F.relu(1 - y_df_hat_r[i]).mean() + F.relu(1 + y_df_hat_g[
+ i]).mean()
+ for i in range(len(y_ds_hat_r)):
+ loss3 += F.relu(1 - y_ds_hat_r[i]).mean() + F.relu(1 + y_ds_hat_g[
+ i]).mean()
+
+ loss = (loss1 / len(y_disc_gen) + loss2 / len(y_df_hat_r) + loss3 /
+ len(y_ds_hat_r)) / 3.0
+
+ return loss
+
+
+def criterion_g(commit_loss, x, G_x, fmap_r, fmap_gen, y_disc_r, y_disc_gen,
+ y_df_hat_r, y_df_hat_g, fmap_f_r, fmap_f_g, y_ds_hat_r,
+ y_ds_hat_g, fmap_s_r, fmap_s_g, lamdba_wav=100, lamdba_com=1000, lamdba_adv=1, lamdba_feat=1, lamdba_rec=1, sr=16000):
+ adv_g_loss = adversarial_g_loss(y_disc_gen)
+ feat_loss = (feature_loss(fmap_r, fmap_gen) + sim_loss(
+ y_disc_r, y_disc_gen) + feature_loss(fmap_f_r, fmap_f_g) + sim_loss(
+ y_df_hat_r, y_df_hat_g) + feature_loss(fmap_s_r, fmap_s_g) +
+ sim_loss(y_ds_hat_r, y_ds_hat_g)) / 3.0
+ rec_loss = reconstruction_loss(x.contiguous(), G_x.contiguous(), lamdba_wav, sr)
+ total_loss = lamdba_com * commit_loss + lamdba_adv * adv_g_loss + lamdba_feat * feat_loss + lamdba_rec * rec_loss
+ return total_loss, adv_g_loss, feat_loss, rec_loss
+
+
+def adopt_weight(weight, global_step, threshold=0, value=0.):
+ if global_step < threshold:
+ weight = value
+ return weight
+
+
+def adopt_dis_weight(weight, global_step, threshold=0, value=0.):
+ # 0,3,6,9,13....这些时间步,不更新dis
+ if global_step % 3 == 0:
+ weight = value
+ return weight
+
+
+def calculate_adaptive_weight(nll_loss, g_loss, last_layer, lamdba_adv=1):
+ if last_layer is not None:
+ nll_grads = torch.autograd.grad(
+ nll_loss, last_layer, retain_graph=True)[0]
+ g_grads = torch.autograd.grad(g_loss, last_layer, retain_graph=True)[0]
+ else:
+ print('last_layer cannot be none')
+ assert 1 == 2
+ d_weight = torch.norm(nll_grads) / (torch.norm(g_grads) + 1e-4)
+ d_weight = torch.clamp(d_weight, 1.0, 1.0).detach()
+ d_weight = d_weight * lamdba_adv
+ return d_weight
+
+def loss_g(codebook_loss,
+ inputs,
+ reconstructions,
+ fmap_r,
+ fmap_gen,
+ y_disc_r,
+ y_disc_gen,
+ global_step,
+ y_df_hat_r,
+ y_df_hat_g,
+ y_ds_hat_r,
+ y_ds_hat_g,
+ fmap_f_r,
+ fmap_f_g,
+ fmap_s_r,
+ fmap_s_g,
+ lamdba_wav=100,
+ lamdba_com=1000,
+ lamdba_adv=1,
+ lamdba_feat=1,
+ sr=16000,
+ discriminator_iter_start=500
+ ):
+ """
+ args:
+ codebook_loss: commit loss.
+ inputs: ground-truth wav.
+ reconstructions: reconstructed wav.
+ fmap_r: real stft-D feature map.
+ fmap_gen: fake stft-D feature map.
+ y_disc_r: real stft-D logits.
+ y_disc_gen: fake stft-D logits.
+ global_step: global training step.
+ y_df_hat_r: real MPD logits.
+ y_df_hat_g: fake MPD logits.
+ y_ds_hat_r: real MSD logits.
+ y_ds_hat_g: fake MSD logits.
+ fmap_f_r: real MPD feature map.
+ fmap_f_g: fake MPD feature map.
+ fmap_s_r: real MSD feature map.
+ fmap_s_g: fake MSD feature map.
+ """
+ rec_loss = reconstruction_loss(inputs.contiguous(),
+ reconstructions.contiguous(), lamdba_wav, sr)
+ adv_g_loss = adversarial_g_loss(y_disc_gen)
+ adv_mpd_loss = adversarial_g_loss(y_df_hat_g)
+ adv_msd_loss = adversarial_g_loss(y_ds_hat_g)
+ adv_loss = (adv_g_loss + adv_mpd_loss + adv_msd_loss
+ ) / 3.0 # NOTE(lsx): need to divide by 3?
+ feat_loss = feature_loss(
+ fmap_r,
+ fmap_gen) #+ sim_loss(y_disc_r, y_disc_gen) # NOTE(lsx): need logits?
+ feat_loss_mpd = feature_loss(fmap_f_r,
+ fmap_f_g) #+ sim_loss(y_df_hat_r, y_df_hat_g)
+ feat_loss_msd = feature_loss(fmap_s_r,
+ fmap_s_g) #+ sim_loss(y_ds_hat_r, y_ds_hat_g)
+ feat_loss_tot = (feat_loss + feat_loss_mpd + feat_loss_msd) / 3.0
+ d_weight = torch.tensor(1.0)
+ disc_factor = adopt_weight(
+ lamdba_adv, global_step, threshold=discriminator_iter_start)
+ if disc_factor == 0.:
+ fm_loss_wt = 0
+ else:
+ fm_loss_wt = lamdba_feat
+ loss = rec_loss + d_weight * disc_factor * adv_loss + \
+ fm_loss_wt * feat_loss_tot + lamdba_com * codebook_loss
+ return loss, rec_loss, adv_loss, feat_loss_tot, d_weight
+
+def compute_det_curve(target_scores, nontarget_scores):
+
+ n_scores = target_scores.size + nontarget_scores.size
+ all_scores = np.concatenate((target_scores, nontarget_scores))
+ labels = np.concatenate((np.ones(target_scores.size), np.zeros(nontarget_scores.size)))
+
+ # Sort labels based on scores
+ indices = np.argsort(all_scores, kind='mergesort')
+ labels = labels[indices]
+
+ # Compute false rejection and false acceptance rates
+ tar_trial_sums = np.cumsum(labels)
+ nontarget_trial_sums = nontarget_scores.size - (np.arange(1, n_scores + 1) - tar_trial_sums)
+
+ frr = np.concatenate((np.atleast_1d(0), tar_trial_sums / target_scores.size)) # false rejection rates
+ far = np.concatenate((np.atleast_1d(1), nontarget_trial_sums / nontarget_scores.size)) # false acceptance rates
+ thresholds = np.concatenate((np.atleast_1d(all_scores[indices[0]] - 0.001), all_scores[indices])) # Thresholds are the sorted scores
+
+ return frr, far, thresholds
+
+
+def compute_eer(target_scores, nontarget_scores):
+ """ Returns equal error rate (EER) and the corresponding threshold. """
+ frr, far, thresholds = compute_det_curve(target_scores, nontarget_scores)
+ abs_diffs = np.abs(frr - far)
+ min_index = np.argmin(abs_diffs)
+ eer = np.mean((frr[min_index], far[min_index]))
+ print(thresholds[min_index])
+ return eer, thresholds[min_index]
\ No newline at end of file
diff --git a/clean/audio/safeear/safeear/models/decouple.py b/clean/audio/safeear/safeear/models/decouple.py
new file mode 100644
index 0000000000000000000000000000000000000000..ce18f1ebd615aa8e6b14ea32d19b85efaa369adc
--- /dev/null
+++ b/clean/audio/safeear/safeear/models/decouple.py
@@ -0,0 +1,207 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Wed Aug 30 15:47:55 2023
+@author: zhangxin
+"""
+import torch.nn as nn
+from einops import rearrange
+import torch
+
+from .modules.seanet import SEANetEncoder, SEANetDecoder
+from .modules.quantization import ResidualVectorQuantizer
+
+
+class SpeechTokenizer(nn.Module):
+ def __init__(self, n_filters, dimension, strides, lstm_layers, bidirectional, dilation_base, residual_kernel_size, n_residual_layers, activation, sample_rate, n_q, semantic_dimension, codebook_size):
+ '''
+
+ Parameters
+ ----------
+ n_filters : int
+ Number of filters in the SEANet encoder/decoder.
+ dimension : int
+ Dimensionality of the encoder/decoder.
+ strides : list
+ List of stride values for the SEANet encoder/decoder.
+ lstm_layers : int
+ Number of LSTM layers in the encoder/decoder.
+ bidirectional : bool
+ Whether to use bidirectional LSTM in the encoder.
+ dilation_base : int
+ Base dilation rate for the residual blocks in the encoder/decoder.
+ residual_kernel_size : int
+ Kernel size for the residual blocks in the encoder/decoder.
+ n_residual_layers : int
+ Number of residual layers in the encoder/decoder.
+ activation : str
+ Activation function to use in the encoder/decoder.
+ sample_rate : int
+ Sample rate of the audio.
+ n_q : int
+ Number of quantization levels.
+ semantic_dimension : int
+ Dimensionality of the semantic representation.
+ codebook_size : int
+ Size of the codebook for vector quantization.
+
+ '''
+ super().__init__()
+ self.encoder = SEANetEncoder(n_filters=n_filters,
+ dimension=dimension,
+ ratios=strides,
+ lstm=lstm_layers,
+ bidirectional=bidirectional,
+ dilation_base=dilation_base,
+ residual_kernel_size=residual_kernel_size,
+ n_residual_layers=n_residual_layers,
+ activation=activation)
+ self.sample_rate = sample_rate
+ self.n_q = n_q
+ if dimension != semantic_dimension:
+ self.transform = nn.Linear(dimension, semantic_dimension)
+ else:
+ self.transform = nn.Identity()
+ self.quantizer = ResidualVectorQuantizer(dimension=dimension, n_q=n_q, bins=codebook_size)
+ self.decoder = SEANetDecoder(n_filters=n_filters,
+ dimension=dimension,
+ ratios=strides,
+ lstm=lstm_layers,
+ bidirectional=False,
+ dilation_base=dilation_base,
+ residual_kernel_size=residual_kernel_size,
+ n_residual_layers=n_residual_layers,
+ activation=activation)
+
+ @classmethod
+ def load_from_checkpoint(cls,
+ config_path: str,
+ ckpt_path: str):
+ '''
+
+ Parameters
+ ----------
+ config_path : str
+ Path of model configuration file.
+ ckpt_path : str
+ Path of model checkpoint.
+
+ Returns
+ -------
+ model : SpeechTokenizer
+ SpeechTokenizer model.
+
+ '''
+ import json
+ with open(config_path) as f:
+ cfg = json.load(f)
+ model = cls(cfg)
+ params = torch.load(ckpt_path, map_location='cpu')
+ model.load_state_dict(params)
+ return model
+
+
+ def forward(self,
+ x: torch.tensor,
+ n_q: int=None,
+ layers: list=[0]):
+ '''
+
+ Parameters
+ ----------
+ x : torch.tensor
+ Input wavs. Shape: (batch, channels, timesteps).
+ n_q : int, optional
+ Number of quantizers in RVQ used to encode. The default is all layers.
+ layers : list[int], optional
+ Layers of RVQ should return quantized result. The default is the first layer.
+
+ Returns
+ -------
+ o : torch.tensor
+ Output wavs. Shape: (batch, channels, timesteps).
+ commit_loss : torch.tensor
+ Commitment loss from residual vector quantizers.
+ feature : torch.tensor
+ Output of RVQ's first layer. Shape: (batch, timesteps, dimension)
+
+ '''
+ n_q = n_q if n_q else self.n_q
+ e = self.encoder(x)
+ quantized, codes, commit_loss, quantized_list = self.quantizer(e, n_q=n_q, layers=layers)
+ feature = rearrange(quantized_list[0], 'b d t -> b t d') # b,t,1024
+ feature = self.transform(feature) #b,t,768
+ o = self.decoder(quantized)
+ return o, commit_loss, feature, quantized_list[1:]
+
+ def forward_feature(self,
+ x: torch.tensor,
+ layers: list=None):
+ '''
+
+ Parameters
+ ----------
+ x : torch.tensor
+ Input wavs. Shape should be (batch, channels, timesteps).
+ layers : list[int], optional
+ Layers of RVQ should return quantized result. The default is all layers.
+
+ Returns
+ -------
+ quantized_list : list[torch.tensor]
+ Quantized of required layers.
+
+ '''
+ e = self.encoder(x)
+ layers = layers if layers else list(range(self.n_q))
+ quantized, codes, commit_loss, quantized_list = self.quantizer(e, layers=layers)
+ return quantized_list
+
+ def encode(self,
+ x: torch.tensor,
+ n_q: int=None,
+ st: int=None):
+ '''
+
+ Parameters
+ ----------
+ x : torch.tensor
+ Input wavs. Shape: (batch, channels, timesteps).
+ n_q : int, optional
+ Number of quantizers in RVQ used to encode. The default is all layers.
+ st : int, optional
+ Start quantizer index in RVQ. The default is 0.
+
+ Returns
+ -------
+ codes : torch.tensor
+ Output indices for each quantizer. Shape: (n_q, batch, timesteps)
+
+ '''
+ e = self.encoder(x)
+ if st is None:
+ st = 0
+ n_q = n_q if n_q else self.n_q
+ codes = self.quantizer.encode(e, n_q=n_q, st=st)
+ return codes
+
+ def decode(self,
+ codes: torch.tensor,
+ st: int=0):
+ '''
+
+ Parameters
+ ----------
+ codes : torch.tensor
+ Indices for each quantizer. Shape: (n_q, batch, timesteps).
+ st : int, optional
+ Start quantizer index in RVQ. The default is 0.
+
+ Returns
+ -------
+ o : torch.tensor
+ Reconstruct wavs from codes. Shape: (batch, channels, timesteps)
+
+ '''
+ quantized = self.quantizer.decode(codes, st=st)
+ o = self.decoder(quantized)
+ return o
\ No newline at end of file
diff --git a/clean/audio/safeear/safeear/models/discriminator.py b/clean/audio/safeear/safeear/models/discriminator.py
new file mode 100644
index 0000000000000000000000000000000000000000..bb21905875285f386d26b9dbe775ff252ca1179a
--- /dev/null
+++ b/clean/audio/safeear/safeear/models/discriminator.py
@@ -0,0 +1,422 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+"""MS-STFT discriminator, provided here for reference."""
+import typing as tp
+
+import torch
+import torchaudio
+from einops import rearrange
+from torch import nn
+from torch.nn import functional as F
+import einops
+from torch.nn import AvgPool1d
+from torch.nn.utils import spectral_norm
+from torch.nn.utils import weight_norm
+
+FeatureMapType = tp.List[torch.Tensor]
+LogitsType = torch.Tensor
+DiscriminatorOutput = tp.Tuple[tp.List[LogitsType], tp.List[FeatureMapType]]
+
+CONV_NORMALIZATIONS = frozenset([
+ 'none', 'weight_norm', 'spectral_norm', 'time_layer_norm', 'layer_norm',
+ 'time_group_norm'
+])
+
+class ConvLayerNorm(nn.LayerNorm):
+ """
+ Convolution-friendly LayerNorm that moves channels to last dimensions
+ before running the normalization and moves them back to original position right after.
+ """
+
+ def __init__(self,
+ normalized_shape: tp.Union[int, tp.List[int], torch.Size],
+ **kwargs):
+ super().__init__(normalized_shape, **kwargs)
+
+ def forward(self, x):
+ x = einops.rearrange(x, 'b ... t -> b t ...')
+ x = super().forward(x)
+ x = einops.rearrange(x, 'b t ... -> b ... t')
+ return
+
+
+def apply_parametrization_norm(module: nn.Module,
+ norm: str='none') -> nn.Module:
+ assert norm in CONV_NORMALIZATIONS
+ if norm == 'weight_norm':
+ return weight_norm(module)
+ elif norm == 'spectral_norm':
+ return spectral_norm(module)
+ else:
+ # We already check was in CONV_NORMALIZATION, so any other choice
+ # doesn't need reparametrization.
+ return module
+
+
+def get_norm_module(module: nn.Module,
+ causal: bool=False,
+ norm: str='none',
+ **norm_kwargs) -> nn.Module:
+ """Return the proper normalization module. If causal is True, this will ensure the returned
+ module is causal, or return an error if the normalization doesn't support causal evaluation.
+ """
+ assert norm in CONV_NORMALIZATIONS
+ if norm == 'layer_norm':
+ assert isinstance(module, nn.modules.conv._ConvNd)
+ return ConvLayerNorm(module.out_channels, **norm_kwargs)
+ elif norm == 'time_group_norm':
+ if causal:
+ raise ValueError("GroupNorm doesn't support causal evaluation.")
+ assert isinstance(module, nn.modules.conv._ConvNd)
+ return nn.GroupNorm(1, module.out_channels, **norm_kwargs)
+ else:
+ return nn.Identity()
+
+def get_padding(kernel_size, dilation=1):
+ return int((kernel_size * dilation - dilation) / 2)
+
+class NormConv1d(nn.Module):
+ """Wrapper around Conv1d and normalization applied to this conv
+ to provide a uniform interface across normalization approaches.
+ """
+
+ def __init__(self,
+ *args,
+ causal: bool=False,
+ norm: str='none',
+ norm_kwargs: tp.Dict[str, tp.Any]={},
+ **kwargs):
+ super().__init__()
+ self.conv = apply_parametrization_norm(nn.Conv1d(*args, **kwargs), norm)
+ self.norm = get_norm_module(self.conv, causal, norm, **norm_kwargs)
+ self.norm_type = norm
+
+ def forward(self, x):
+ x = self.conv(x)
+ x = self.norm(x)
+ return x
+
+
+class NormConv2d(nn.Module):
+ """Wrapper around Conv2d and normalization applied to this conv
+ to provide a uniform interface across normalization approaches.
+ """
+
+ def __init__(self,
+ *args,
+ norm: str='none',
+ norm_kwargs: tp.Dict[str, tp.Any]={},
+ **kwargs):
+ super().__init__()
+ self.conv = apply_parametrization_norm(nn.Conv2d(*args, **kwargs), norm)
+ self.norm = get_norm_module(
+ self.conv, causal=False, norm=norm, **norm_kwargs)
+ self.norm_type = norm
+
+ def forward(self, x):
+ x = self.conv(x)
+ x = self.norm(x)
+ return x
+
+
+def get_2d_padding(kernel_size: tp.Tuple[int, int],
+ dilation: tp.Tuple[int, int]=(1, 1)):
+ return (((kernel_size[0] - 1) * dilation[0]) // 2, (
+ (kernel_size[1] - 1) * dilation[1]) // 2)
+
+
+class DiscriminatorSTFT(nn.Module):
+ """STFT sub-discriminator.
+ Args:
+ filters (int): Number of filters in convolutions
+ in_channels (int): Number of input channels. Default: 1
+ out_channels (int): Number of output channels. Default: 1
+ n_fft (int): Size of FFT for each scale. Default: 1024
+ hop_length (int): Length of hop between STFT windows for each scale. Default: 256
+ kernel_size (tuple of int): Inner Conv2d kernel sizes. Default: ``(3, 9)``
+ stride (tuple of int): Inner Conv2d strides. Default: ``(1, 2)``
+ dilations (list of int): Inner Conv2d dilation on the time dimension. Default: ``[1, 2, 4]``
+ win_length (int): Window size for each scale. Default: 1024
+ normalized (bool): Whether to normalize by magnitude after stft. Default: True
+ norm (str): Normalization method. Default: `'weight_norm'`
+ activation (str): Activation function. Default: `'LeakyReLU'`
+ activation_params (dict): Parameters to provide to the activation function.
+ growth (int): Growth factor for the filters. Default: 1
+ """
+
+ def __init__(self,
+ filters: int,
+ in_channels: int=1,
+ out_channels: int=1,
+ n_fft: int=1024,
+ hop_length: int=256,
+ win_length: int=1024,
+ max_filters: int=1024,
+ filters_scale: int=1,
+ kernel_size: tp.Tuple[int, int]=(3, 9),
+ dilations: tp.List=[1, 2, 4],
+ stride: tp.Tuple[int, int]=(1, 2),
+ normalized: bool=True,
+ norm: str='weight_norm',
+ activation: str='LeakyReLU',
+ activation_params: dict={'negative_slope': 0.2}):
+ super().__init__()
+ assert len(kernel_size) == 2
+ assert len(stride) == 2
+ self.filters = filters
+ self.in_channels = in_channels
+ self.out_channels = out_channels
+ self.n_fft = n_fft
+ self.hop_length = hop_length
+ self.win_length = win_length
+ self.normalized = normalized
+ self.activation = getattr(torch.nn, activation)(**activation_params)
+ self.spec_transform = torchaudio.transforms.Spectrogram(
+ n_fft=self.n_fft,
+ hop_length=self.hop_length,
+ win_length=self.win_length,
+ window_fn=torch.hann_window,
+ normalized=self.normalized,
+ center=False,
+ pad_mode=None,
+ power=None)
+ spec_channels = 2 * self.in_channels
+ self.convs = nn.ModuleList()
+ self.convs.append(
+ NormConv2d(
+ spec_channels,
+ self.filters,
+ kernel_size=kernel_size,
+ padding=get_2d_padding(kernel_size)))
+ in_chs = min(filters_scale * self.filters, max_filters)
+ for i, dilation in enumerate(dilations):
+ out_chs = min((filters_scale**(i + 1)) * self.filters, max_filters)
+ self.convs.append(
+ NormConv2d(
+ in_chs,
+ out_chs,
+ kernel_size=kernel_size,
+ stride=stride,
+ dilation=(dilation, 1),
+ padding=get_2d_padding(kernel_size, (dilation, 1)),
+ norm=norm))
+ in_chs = out_chs
+ out_chs = min((filters_scale**(len(dilations) + 1)) * self.filters,
+ max_filters)
+ self.convs.append(
+ NormConv2d(
+ in_chs,
+ out_chs,
+ kernel_size=(kernel_size[0], kernel_size[0]),
+ padding=get_2d_padding((kernel_size[0], kernel_size[0])),
+ norm=norm))
+ self.conv_post = NormConv2d(
+ out_chs,
+ self.out_channels,
+ kernel_size=(kernel_size[0], kernel_size[0]),
+ padding=get_2d_padding((kernel_size[0], kernel_size[0])),
+ norm=norm)
+
+ def forward(self, x: torch.Tensor):
+ fmap = []
+ # print('x ', x.shape)
+ z = self.spec_transform(x) # [B, 2, Freq, Frames, 2]
+ # print('z ', z.shape)
+ z = torch.cat([z.real, z.imag], dim=1)
+ # print('cat_z ', z.shape)
+ z = rearrange(z, 'b c w t -> b c t w')
+ for i, layer in enumerate(self.convs):
+ z = layer(z)
+ z = self.activation(z)
+ # print('z i', i, z.shape)
+ fmap.append(z)
+ z = self.conv_post(z)
+ # print('logit ', z.shape)
+ return z, fmap
+
+
+class MultiScaleSTFTDiscriminator(nn.Module):
+ """Multi-Scale STFT (MS-STFT) discriminator.
+ Args:
+ filters (int): Number of filters in convolutions
+ in_channels (int): Number of input channels. Default: 1
+ out_channels (int): Number of output channels. Default: 1
+ n_ffts (Sequence[int]): Size of FFT for each scale
+ hop_lengths (Sequence[int]): Length of hop between STFT windows for each scale
+ win_lengths (Sequence[int]): Window size for each scale
+ **kwargs: additional args for STFTDiscriminator
+ """
+
+ def __init__(self,
+ filters: int,
+ in_channels: int=1,
+ out_channels: int=1,
+ n_ffts: tp.List[int]=[1024, 2048, 512, 256, 128],
+ hop_lengths: tp.List[int]=[256, 512, 128, 64, 32],
+ win_lengths: tp.List[int]=[1024, 2048, 512, 256, 128],
+ **kwargs):
+ super().__init__()
+ assert len(n_ffts) == len(hop_lengths) == len(win_lengths)
+ self.discriminators = nn.ModuleList([
+ DiscriminatorSTFT(
+ filters,
+ in_channels=in_channels,
+ out_channels=out_channels,
+ n_fft=n_ffts[i],
+ win_length=win_lengths[i],
+ hop_length=hop_lengths[i],
+ **kwargs) for i in range(len(n_ffts))
+ ])
+ self.num_discriminators = len(self.discriminators)
+
+ def forward(self, x: torch.Tensor) -> DiscriminatorOutput:
+ logits = []
+ fmaps = []
+ for disc in self.discriminators:
+ logit, fmap = disc(x)
+ logits.append(logit)
+ fmaps.append(fmap)
+ return logits, fmaps
+
+
+class DiscriminatorP(torch.nn.Module):
+ def __init__(self,
+ period,
+ kernel_size=5,
+ stride=3,
+ use_spectral_norm=False,
+ activation: str='LeakyReLU',
+ activation_params: dict={'negative_slope': 0.2}):
+ super(DiscriminatorP, self).__init__()
+ self.period = period
+ norm_f = weight_norm if use_spectral_norm is False else spectral_norm
+ self.activation = getattr(torch.nn, activation)(**activation_params)
+ self.convs = nn.ModuleList([
+ NormConv2d(
+ 1,
+ 32, (kernel_size, 1), (stride, 1),
+ padding=(get_padding(5, 1), 0)),
+ NormConv2d(
+ 32,
+ 32, (kernel_size, 1), (stride, 1),
+ padding=(get_padding(5, 1), 0)),
+ NormConv2d(
+ 32,
+ 32, (kernel_size, 1), (stride, 1),
+ padding=(get_padding(5, 1), 0)),
+ NormConv2d(
+ 32,
+ 32, (kernel_size, 1), (stride, 1),
+ padding=(get_padding(5, 1), 0)),
+ NormConv2d(32, 32, (kernel_size, 1), 1, padding=(2, 0)),
+ ])
+ self.conv_post = NormConv2d(32, 1, (3, 1), 1, padding=(1, 0))
+
+ def forward(self, x):
+ fmap = []
+ # 1d to 2d
+ b, c, t = x.shape
+ if t % self.period != 0: # pad first
+ n_pad = self.period - (t % self.period)
+ x = F.pad(x, (0, n_pad), "reflect")
+ t = t + n_pad
+ x = x.view(b, c, t // self.period, self.period)
+
+ for l in self.convs:
+ x = l(x)
+ x = self.activation(x)
+ fmap.append(x)
+ x = self.conv_post(x)
+ fmap.append(x)
+ x = torch.flatten(x, 1, -1)
+
+ return x, fmap
+
+
+class MultiPeriodDiscriminator(torch.nn.Module):
+ def __init__(self):
+ super(MultiPeriodDiscriminator, self).__init__()
+ self.discriminators = nn.ModuleList([
+ DiscriminatorP(2),
+ DiscriminatorP(3),
+ DiscriminatorP(5),
+ DiscriminatorP(7),
+ DiscriminatorP(11),
+ ])
+
+ def forward(self, y, y_hat):
+ y_d_rs = []
+ y_d_gs = []
+ fmap_rs = []
+ fmap_gs = []
+ for i, d in enumerate(self.discriminators):
+ y_d_r, fmap_r = d(y)
+ y_d_g, fmap_g = d(y_hat)
+ y_d_rs.append(y_d_r)
+ fmap_rs.append(fmap_r)
+ y_d_gs.append(y_d_g)
+ fmap_gs.append(fmap_g)
+ return y_d_rs, y_d_gs, fmap_rs, fmap_gs
+
+
+class DiscriminatorS(torch.nn.Module):
+ def __init__(self,
+ use_spectral_norm=False,
+ activation: str='LeakyReLU',
+ activation_params: dict={'negative_slope': 0.2}):
+ super(DiscriminatorS, self).__init__()
+ self.activation = getattr(torch.nn, activation)(**activation_params)
+ self.convs = nn.ModuleList([
+ NormConv1d(1, 32, 15, 1, padding=7),
+ NormConv1d(32, 32, 41, 2, groups=4, padding=20),
+ NormConv1d(32, 32, 41, 2, groups=16, padding=20),
+ NormConv1d(32, 32, 41, 4, groups=16, padding=20),
+ NormConv1d(32, 32, 41, 4, groups=16, padding=20),
+ NormConv1d(32, 32, 41, 1, groups=16, padding=20),
+ NormConv1d(32, 32, 5, 1, padding=2),
+ ])
+ self.conv_post = NormConv1d(32, 1, 3, 1, padding=1)
+
+ def forward(self, x):
+ fmap = []
+ for l in self.convs:
+ x = l(x)
+ x = self.activation(x)
+ fmap.append(x)
+ x = self.conv_post(x)
+ fmap.append(x)
+ x = torch.flatten(x, 1, -1)
+ return x, fmap
+
+
+class MultiScaleDiscriminator(torch.nn.Module):
+ def __init__(self):
+ super(MultiScaleDiscriminator, self).__init__()
+ self.discriminators = nn.ModuleList([
+ DiscriminatorS(),
+ DiscriminatorS(),
+ DiscriminatorS(),
+ ])
+ self.meanpools = nn.ModuleList(
+ [AvgPool1d(4, 2, padding=2), AvgPool1d(4, 2, padding=2)])
+
+ def forward(self, y, y_hat):
+ y_d_rs = []
+ y_d_gs = []
+ fmap_rs = []
+ fmap_gs = []
+ for i, d in enumerate(self.discriminators):
+ if i != 0:
+ y = self.meanpools[i - 1](y)
+ y_hat = self.meanpools[i - 1](y_hat)
+ y_d_r, fmap_r = d(y)
+ y_d_g, fmap_g = d(y_hat)
+ y_d_rs.append(y_d_r)
+ fmap_rs.append(fmap_r)
+ y_d_gs.append(y_d_g)
+ fmap_gs.append(fmap_g)
+
+ return y_d_rs, y_d_gs, fmap_rs, fmap_gs
diff --git a/clean/audio/safeear/safeear/models/modules/__init__.py b/clean/audio/safeear/safeear/models/modules/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..8d61ab031045422c4000cf26388f24d072572089
--- /dev/null
+++ b/clean/audio/safeear/safeear/models/modules/__init__.py
@@ -0,0 +1,21 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+"""Torch modules."""
+
+# flake8: noqa
+from .conv import (
+ pad1d,
+ unpad1d,
+ NormConv1d,
+ NormConvTranspose1d,
+ NormConv2d,
+ NormConvTranspose2d,
+ SConv1d,
+ SConvTranspose1d,
+)
+from .lstm import SLSTM
+from .seanet import SEANetEncoder, SEANetDecoder
\ No newline at end of file
diff --git a/clean/audio/safeear/safeear/models/modules/conv.py b/clean/audio/safeear/safeear/models/modules/conv.py
new file mode 100644
index 0000000000000000000000000000000000000000..f37963901118e10bfe009e3c6d27e47be06be7cc
--- /dev/null
+++ b/clean/audio/safeear/safeear/models/modules/conv.py
@@ -0,0 +1,252 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+"""Convolutional layers wrappers and utilities."""
+
+import math
+import typing as tp
+import warnings
+
+import torch
+from torch import nn
+from torch.nn import functional as F
+from torch.nn.utils import spectral_norm, weight_norm
+
+from .norm import ConvLayerNorm
+
+
+CONV_NORMALIZATIONS = frozenset(['none', 'weight_norm', 'spectral_norm',
+ 'time_layer_norm', 'layer_norm', 'time_group_norm'])
+
+
+def apply_parametrization_norm(module: nn.Module, norm: str = 'none') -> nn.Module:
+ assert norm in CONV_NORMALIZATIONS
+ if norm == 'weight_norm':
+ return weight_norm(module)
+ elif norm == 'spectral_norm':
+ return spectral_norm(module)
+ else:
+ # We already check was in CONV_NORMALIZATION, so any other choice
+ # doesn't need reparametrization.
+ return module
+
+
+def get_norm_module(module: nn.Module, causal: bool = False, norm: str = 'none', **norm_kwargs) -> nn.Module:
+ """Return the proper normalization module. If causal is True, this will ensure the returned
+ module is causal, or return an error if the normalization doesn't support causal evaluation.
+ """
+ assert norm in CONV_NORMALIZATIONS
+ if norm == 'layer_norm':
+ assert isinstance(module, nn.modules.conv._ConvNd)
+ return ConvLayerNorm(module.out_channels, **norm_kwargs)
+ elif norm == 'time_group_norm':
+ if causal:
+ raise ValueError("GroupNorm doesn't support causal evaluation.")
+ assert isinstance(module, nn.modules.conv._ConvNd)
+ return nn.GroupNorm(1, module.out_channels, **norm_kwargs)
+ else:
+ return nn.Identity()
+
+
+def get_extra_padding_for_conv1d(x: torch.Tensor, kernel_size: int, stride: int,
+ padding_total: int = 0) -> int:
+ """See `pad_for_conv1d`.
+ """
+ length = x.shape[-1]
+ n_frames = (length - kernel_size + padding_total) / stride + 1
+ ideal_length = (math.ceil(n_frames) - 1) * stride + (kernel_size - padding_total)
+ return ideal_length - length
+
+
+def pad_for_conv1d(x: torch.Tensor, kernel_size: int, stride: int, padding_total: int = 0):
+ """Pad for a convolution to make sure that the last window is full.
+ Extra padding is added at the end. This is required to ensure that we can rebuild
+ an output of the same length, as otherwise, even with padding, some time steps
+ might get removed.
+ For instance, with total padding = 4, kernel size = 4, stride = 2:
+ 0 0 1 2 3 4 5 0 0 # (0s are padding)
+ 1 2 3 # (output frames of a convolution, last 0 is never used)
+ 0 0 1 2 3 4 5 0 # (output of tr. conv., but pos. 5 is going to get removed as padding)
+ 1 2 3 4 # once you removed padding, we are missing one time step !
+ """
+ extra_padding = get_extra_padding_for_conv1d(x, kernel_size, stride, padding_total)
+ return F.pad(x, (0, extra_padding))
+
+
+def pad1d(x: torch.Tensor, paddings: tp.Tuple[int, int], mode: str = 'zero', value: float = 0.):
+ """Tiny wrapper around F.pad, just to allow for reflect padding on small input.
+ If this is the case, we insert extra 0 padding to the right before the reflection happen.
+ """
+ length = x.shape[-1]
+ padding_left, padding_right = paddings
+ assert padding_left >= 0 and padding_right >= 0, (padding_left, padding_right)
+ if mode == 'reflect':
+ max_pad = max(padding_left, padding_right)
+ extra_pad = 0
+ if length <= max_pad:
+ extra_pad = max_pad - length + 1
+ x = F.pad(x, (0, extra_pad))
+ padded = F.pad(x, paddings, mode, value)
+ end = padded.shape[-1] - extra_pad
+ return padded[..., :end]
+ else:
+ return F.pad(x, paddings, mode, value)
+
+
+def unpad1d(x: torch.Tensor, paddings: tp.Tuple[int, int]):
+ """Remove padding from x, handling properly zero padding. Only for 1d!"""
+ padding_left, padding_right = paddings
+ assert padding_left >= 0 and padding_right >= 0, (padding_left, padding_right)
+ assert (padding_left + padding_right) <= x.shape[-1]
+ end = x.shape[-1] - padding_right
+ return x[..., padding_left: end]
+
+
+class NormConv1d(nn.Module):
+ """Wrapper around Conv1d and normalization applied to this conv
+ to provide a uniform interface across normalization approaches.
+ """
+ def __init__(self, *args, causal: bool = False, norm: str = 'none',
+ norm_kwargs: tp.Dict[str, tp.Any] = {}, **kwargs):
+ super().__init__()
+ self.conv = apply_parametrization_norm(nn.Conv1d(*args, **kwargs), norm)
+ self.norm = get_norm_module(self.conv, causal, norm, **norm_kwargs)
+ self.norm_type = norm
+
+ def forward(self, x):
+ x = self.conv(x)
+ x = self.norm(x)
+ return x
+
+
+class NormConv2d(nn.Module):
+ """Wrapper around Conv2d and normalization applied to this conv
+ to provide a uniform interface across normalization approaches.
+ """
+ def __init__(self, *args, norm: str = 'none',
+ norm_kwargs: tp.Dict[str, tp.Any] = {}, **kwargs):
+ super().__init__()
+ self.conv = apply_parametrization_norm(nn.Conv2d(*args, **kwargs), norm)
+ self.norm = get_norm_module(self.conv, causal=False, norm=norm, **norm_kwargs)
+ self.norm_type = norm
+
+ def forward(self, x):
+ x = self.conv(x)
+ x = self.norm(x)
+ return x
+
+
+class NormConvTranspose1d(nn.Module):
+ """Wrapper around ConvTranspose1d and normalization applied to this conv
+ to provide a uniform interface across normalization approaches.
+ """
+ def __init__(self, *args, causal: bool = False, norm: str = 'none',
+ norm_kwargs: tp.Dict[str, tp.Any] = {}, **kwargs):
+ super().__init__()
+ self.convtr = apply_parametrization_norm(nn.ConvTranspose1d(*args, **kwargs), norm)
+ self.norm = get_norm_module(self.convtr, causal, norm, **norm_kwargs)
+ self.norm_type = norm
+
+ def forward(self, x):
+ x = self.convtr(x)
+ x = self.norm(x)
+ return x
+
+
+class NormConvTranspose2d(nn.Module):
+ """Wrapper around ConvTranspose2d and normalization applied to this conv
+ to provide a uniform interface across normalization approaches.
+ """
+ def __init__(self, *args, norm: str = 'none',
+ norm_kwargs: tp.Dict[str, tp.Any] = {}, **kwargs):
+ super().__init__()
+ self.convtr = apply_parametrization_norm(nn.ConvTranspose2d(*args, **kwargs), norm)
+ self.norm = get_norm_module(self.convtr, causal=False, norm=norm, **norm_kwargs)
+
+ def forward(self, x):
+ x = self.convtr(x)
+ x = self.norm(x)
+ return x
+
+
+class SConv1d(nn.Module):
+ """Conv1d with some builtin handling of asymmetric or causal padding
+ and normalization.
+ """
+ def __init__(self, in_channels: int, out_channels: int,
+ kernel_size: int, stride: int = 1, dilation: int = 1,
+ groups: int = 1, bias: bool = True, causal: bool = False,
+ norm: str = 'none', norm_kwargs: tp.Dict[str, tp.Any] = {},
+ pad_mode: str = 'reflect'):
+ super().__init__()
+ # warn user on unusual setup between dilation and stride
+ if stride > 1 and dilation > 1:
+ warnings.warn('SConv1d has been initialized with stride > 1 and dilation > 1'
+ f' (kernel_size={kernel_size} stride={stride}, dilation={dilation}).')
+ self.conv = NormConv1d(in_channels, out_channels, kernel_size, stride,
+ dilation=dilation, groups=groups, bias=bias, causal=causal,
+ norm=norm, norm_kwargs=norm_kwargs)
+ self.causal = causal
+ self.pad_mode = pad_mode
+
+ def forward(self, x):
+ B, C, T = x.shape
+ kernel_size = self.conv.conv.kernel_size[0]
+ stride = self.conv.conv.stride[0]
+ dilation = self.conv.conv.dilation[0]
+ padding_total = (kernel_size - 1) * dilation - (stride - 1)
+ extra_padding = get_extra_padding_for_conv1d(x, kernel_size, stride, padding_total)
+ if self.causal:
+ # Left padding for causal
+ x = pad1d(x, (padding_total, extra_padding), mode=self.pad_mode)
+ else:
+ # Asymmetric padding required for odd strides
+ padding_right = padding_total // 2
+ padding_left = padding_total - padding_right
+ x = pad1d(x, (padding_left, padding_right + extra_padding), mode=self.pad_mode)
+ return self.conv(x)
+
+
+class SConvTranspose1d(nn.Module):
+ """ConvTranspose1d with some builtin handling of asymmetric or causal padding
+ and normalization.
+ """
+ def __init__(self, in_channels: int, out_channels: int,
+ kernel_size: int, stride: int = 1, causal: bool = False,
+ norm: str = 'none', trim_right_ratio: float = 1.,
+ norm_kwargs: tp.Dict[str, tp.Any] = {}):
+ super().__init__()
+ self.convtr = NormConvTranspose1d(in_channels, out_channels, kernel_size, stride,
+ causal=causal, norm=norm, norm_kwargs=norm_kwargs)
+ self.causal = causal
+ self.trim_right_ratio = trim_right_ratio
+ assert self.causal or self.trim_right_ratio == 1., \
+ "`trim_right_ratio` != 1.0 only makes sense for causal convolutions"
+ assert self.trim_right_ratio >= 0. and self.trim_right_ratio <= 1.
+
+ def forward(self, x):
+ kernel_size = self.convtr.convtr.kernel_size[0]
+ stride = self.convtr.convtr.stride[0]
+ padding_total = kernel_size - stride
+
+ y = self.convtr(x)
+
+ # We will only trim fixed padding. Extra padding from `pad_for_conv1d` would be
+ # removed at the very end, when keeping only the right length for the output,
+ # as removing it here would require also passing the length at the matching layer
+ # in the encoder.
+ if self.causal:
+ # Trim the padding on the right according to the specified ratio
+ # if trim_right_ratio = 1.0, trim everything from right
+ padding_right = math.ceil(padding_total * self.trim_right_ratio)
+ padding_left = padding_total - padding_right
+ y = unpad1d(y, (padding_left, padding_right))
+ else:
+ # Asymmetric padding required for odd strides
+ padding_right = padding_total // 2
+ padding_left = padding_total - padding_right
+ y = unpad1d(y, (padding_left, padding_right))
+ return y
diff --git a/clean/audio/safeear/safeear/models/modules/lstm.py b/clean/audio/safeear/safeear/models/modules/lstm.py
new file mode 100644
index 0000000000000000000000000000000000000000..f68010d2c46f5b3f0b56c6fc55b8c62f32e08b89
--- /dev/null
+++ b/clean/audio/safeear/safeear/models/modules/lstm.py
@@ -0,0 +1,32 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+"""LSTM layers module."""
+
+from torch import nn
+
+
+class SLSTM(nn.Module):
+ """
+ LSTM without worrying about the hidden state, nor the layout of the data.
+ Expects input as convolutional layout.
+ """
+ def __init__(self, dimension: int, num_layers: int = 2, skip: bool = True, bidirectional: bool=False):
+ super().__init__()
+ self.bidirectional = bidirectional
+ self.skip = skip
+ self.lstm = nn.LSTM(dimension, dimension, num_layers, bidirectional=bidirectional)
+
+ def forward(self, x):
+ x = x.permute(2, 0, 1)
+ y, _ = self.lstm(x)
+ if self.bidirectional:
+ x = x.repeat(1, 1, 2)
+ if self.skip:
+ y = y + x
+ y = y.permute(1, 2, 0)
+ return y
+
diff --git a/clean/audio/safeear/safeear/models/modules/norm.py b/clean/audio/safeear/safeear/models/modules/norm.py
new file mode 100644
index 0000000000000000000000000000000000000000..19970e0a21ea1c10461cb56d776619dd5f64ff36
--- /dev/null
+++ b/clean/audio/safeear/safeear/models/modules/norm.py
@@ -0,0 +1,28 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+"""Normalization modules."""
+
+import typing as tp
+
+import einops
+import torch
+from torch import nn
+
+
+class ConvLayerNorm(nn.LayerNorm):
+ """
+ Convolution-friendly LayerNorm that moves channels to last dimensions
+ before running the normalization and moves them back to original position right after.
+ """
+ def __init__(self, normalized_shape: tp.Union[int, tp.List[int], torch.Size], **kwargs):
+ super().__init__(normalized_shape, **kwargs)
+
+ def forward(self, x):
+ x = einops.rearrange(x, 'b ... t -> b t ...')
+ x = super().forward(x)
+ x = einops.rearrange(x, 'b t ... -> b ... t')
+ return
diff --git a/clean/audio/safeear/safeear/models/modules/quantization/__init__.py b/clean/audio/safeear/safeear/models/modules/quantization/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..bfabe52b8cb6f260cdda6137b34df2f4736bd02f
--- /dev/null
+++ b/clean/audio/safeear/safeear/models/modules/quantization/__init__.py
@@ -0,0 +1,8 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+# flake8: noqa
+from .vq import QuantizedResult, ResidualVectorQuantizer
diff --git a/clean/audio/safeear/safeear/models/modules/quantization/ac.py b/clean/audio/safeear/safeear/models/modules/quantization/ac.py
new file mode 100644
index 0000000000000000000000000000000000000000..f0f3e5dcd385cd273a145effa3f53ce7ccfdc74c
--- /dev/null
+++ b/clean/audio/safeear/safeear/models/modules/quantization/ac.py
@@ -0,0 +1,292 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+"""Arithmetic coder."""
+
+import io
+import math
+import random
+import typing as tp
+import torch
+
+from ..binary import BitPacker, BitUnpacker
+
+
+def build_stable_quantized_cdf(pdf: torch.Tensor, total_range_bits: int,
+ roundoff: float = 1e-8, min_range: int = 2,
+ check: bool = True) -> torch.Tensor:
+ """Turn the given PDF into a quantized CDF that splits
+ [0, 2 ** self.total_range_bits - 1] into chunks of size roughly proportional
+ to the PDF.
+
+ Args:
+ pdf (torch.Tensor): probability distribution, shape should be `[N]`.
+ total_range_bits (int): see `ArithmeticCoder`, the typical range we expect
+ during the coding process is `[0, 2 ** total_range_bits - 1]`.
+ roundoff (float): will round the pdf up to that level to remove difference coming
+ from e.g. evaluating the Language Model on different architectures.
+ min_range (int): minimum range width. Should always be at least 2 for numerical
+ stability. Use this to avoid pathological behavior is a value
+ that is expected to be rare actually happens in real life.
+ check (bool): if True, checks that nothing bad happened, can be deactivated for speed.
+ """
+ pdf = pdf.detach()
+ if roundoff:
+ pdf = (pdf / roundoff).floor() * roundoff
+ # interpolate with uniform distribution to achieve desired minimum probability.
+ total_range = 2 ** total_range_bits
+ cardinality = len(pdf)
+ alpha = min_range * cardinality / total_range
+ assert alpha <= 1, "you must reduce min_range"
+ ranges = (((1 - alpha) * total_range) * pdf).floor().long()
+ ranges += min_range
+ quantized_cdf = torch.cumsum(ranges, dim=-1)
+ if min_range < 2:
+ raise ValueError("min_range must be at least 2.")
+ if check:
+ assert quantized_cdf[-1] <= 2 ** total_range_bits, quantized_cdf[-1]
+ if ((quantized_cdf[1:] - quantized_cdf[:-1]) < min_range).any() or quantized_cdf[0] < min_range:
+ raise ValueError("You must increase your total_range_bits.")
+ return quantized_cdf
+
+
+class ArithmeticCoder:
+ """ArithmeticCoder,
+ Let us take a distribution `p` over `N` symbols, and assume we have a stream
+ of random variables `s_t` sampled from `p`. Let us assume that we have a budget
+ of `B` bits that we can afford to write on device. There are `2**B` possible numbers,
+ corresponding to the range `[0, 2 ** B - 1]`. We can map each of those number to a single
+ sequence `(s_t)` by doing the following:
+
+ 1) Initialize the current range to` [0 ** 2 B - 1]`.
+ 2) For each time step t, split the current range into contiguous chunks,
+ one for each possible outcome, with size roughly proportional to `p`.
+ For instance, if `p = [0.75, 0.25]`, and the range is `[0, 3]`, the chunks
+ would be `{[0, 2], [3, 3]}`.
+ 3) Select the chunk corresponding to `s_t`, and replace the current range with this.
+ 4) When done encoding all the values, just select any value remaining in the range.
+
+ You will notice that this procedure can fail: for instance if at any point in time
+ the range is smaller than `N`, then we can no longer assign a non-empty chunk to each
+ possible outcome. Intuitively, the more likely a value is, the less the range width
+ will reduce, and the longer we can go on encoding values. This makes sense: for any efficient
+ coding scheme, likely outcomes would take less bits, and more of them can be coded
+ with a fixed budget.
+
+ In practice, we do not know `B` ahead of time, but we have a way to inject new bits
+ when the current range decreases below a given limit (given by `total_range_bits`), without
+ having to redo all the computations. If we encode mostly likely values, we will seldom
+ need to inject new bits, but a single rare value can deplete our stock of entropy!
+
+ In this explanation, we assumed that the distribution `p` was constant. In fact, the present
+ code works for any sequence `(p_t)` possibly different for each timestep.
+ We also assume that `s_t ~ p_t`, but that doesn't need to be true, although the smaller
+ the KL between the true distribution and `p_t`, the most efficient the coding will be.
+
+ Args:
+ fo (IO[bytes]): file-like object to which the bytes will be written to.
+ total_range_bits (int): the range `M` described above is `2 ** total_range_bits.
+ Any time the current range width fall under this limit, new bits will
+ be injected to rescale the initial range.
+ """
+
+ def __init__(self, fo: tp.IO[bytes], total_range_bits: int = 24):
+ assert total_range_bits <= 30
+ self.total_range_bits = total_range_bits
+ self.packer = BitPacker(bits=1, fo=fo) # we push single bits at a time.
+ self.low: int = 0
+ self.high: int = 0
+ self.max_bit: int = -1
+ self._dbg: tp.List[tp.Any] = []
+ self._dbg2: tp.List[tp.Any] = []
+
+ @property
+ def delta(self) -> int:
+ """Return the current range width."""
+ return self.high - self.low + 1
+
+ def _flush_common_prefix(self):
+ # If self.low and self.high start with the sames bits,
+ # those won't change anymore as we always just increase the range
+ # by powers of 2, and we can flush them out to the bit stream.
+ assert self.high >= self.low, (self.low, self.high)
+ assert self.high < 2 ** (self.max_bit + 1)
+ while self.max_bit >= 0:
+ b1 = self.low >> self.max_bit
+ b2 = self.high >> self.max_bit
+ if b1 == b2:
+ self.low -= (b1 << self.max_bit)
+ self.high -= (b1 << self.max_bit)
+ assert self.high >= self.low, (self.high, self.low, self.max_bit)
+ assert self.low >= 0
+ self.max_bit -= 1
+ self.packer.push(b1)
+ else:
+ break
+
+ def push(self, symbol: int, quantized_cdf: torch.Tensor):
+ """Push the given symbol on the stream, flushing out bits
+ if possible.
+
+ Args:
+ symbol (int): symbol to encode with the AC.
+ quantized_cdf (torch.Tensor): use `build_stable_quantized_cdf`
+ to build this from your pdf estimate.
+ """
+ while self.delta < 2 ** self.total_range_bits:
+ self.low *= 2
+ self.high = self.high * 2 + 1
+ self.max_bit += 1
+
+ range_low = 0 if symbol == 0 else quantized_cdf[symbol - 1].item()
+ range_high = quantized_cdf[symbol].item() - 1
+ effective_low = int(math.ceil(range_low * (self.delta / (2 ** self.total_range_bits))))
+ effective_high = int(math.floor(range_high * (self.delta / (2 ** self.total_range_bits))))
+ assert self.low <= self.high
+ self.high = self.low + effective_high
+ self.low = self.low + effective_low
+ assert self.low <= self.high, (effective_low, effective_high, range_low, range_high)
+ self._dbg.append((self.low, self.high))
+ self._dbg2.append((self.low, self.high))
+ outs = self._flush_common_prefix()
+ assert self.low <= self.high
+ assert self.max_bit >= -1
+ assert self.max_bit <= 61, self.max_bit
+ return outs
+
+ def flush(self):
+ """Flush the remaining information to the stream.
+ """
+ while self.max_bit >= 0:
+ b1 = (self.low >> self.max_bit) & 1
+ self.packer.push(b1)
+ self.max_bit -= 1
+ self.packer.flush()
+
+
+class ArithmeticDecoder:
+ """ArithmeticDecoder, see `ArithmeticCoder` for a detailed explanation.
+
+ Note that this must be called with **exactly** the same parameters and sequence
+ of quantized cdf as the arithmetic encoder or the wrong values will be decoded.
+
+ If the AC encoder current range is [L, H], with `L` and `H` having the some common
+ prefix (i.e. the same most significant bits), then this prefix will be flushed to the stream.
+ For instances, having read 3 bits `b1 b2 b3`, we know that `[L, H]` is contained inside
+ `[b1 b2 b3 0 ... 0 b1 b3 b3 1 ... 1]`. Now this specific sub-range can only be obtained
+ for a specific sequence of symbols and a binary-search allows us to decode those symbols.
+ At some point, the prefix `b1 b2 b3` will no longer be sufficient to decode new symbols,
+ and we will need to read new bits from the stream and repeat the process.
+
+ """
+ def __init__(self, fo: tp.IO[bytes], total_range_bits: int = 24):
+ self.total_range_bits = total_range_bits
+ self.low: int = 0
+ self.high: int = 0
+ self.current: int = 0
+ self.max_bit: int = -1
+ self.unpacker = BitUnpacker(bits=1, fo=fo) # we pull single bits at a time.
+ # Following is for debugging
+ self._dbg: tp.List[tp.Any] = []
+ self._dbg2: tp.List[tp.Any] = []
+ self._last: tp.Any = None
+
+ @property
+ def delta(self) -> int:
+ return self.high - self.low + 1
+
+ def _flush_common_prefix(self):
+ # Given the current range [L, H], if both have a common prefix,
+ # we know we can remove it from our representation to avoid handling large numbers.
+ while self.max_bit >= 0:
+ b1 = self.low >> self.max_bit
+ b2 = self.high >> self.max_bit
+ if b1 == b2:
+ self.low -= (b1 << self.max_bit)
+ self.high -= (b1 << self.max_bit)
+ self.current -= (b1 << self.max_bit)
+ assert self.high >= self.low
+ assert self.low >= 0
+ self.max_bit -= 1
+ else:
+ break
+
+ def pull(self, quantized_cdf: torch.Tensor) -> tp.Optional[int]:
+ """Pull a symbol, reading as many bits from the stream as required.
+ This returns `None` when the stream has been exhausted.
+
+ Args:
+ quantized_cdf (torch.Tensor): use `build_stable_quantized_cdf`
+ to build this from your pdf estimate. This must be **exatly**
+ the same cdf as the one used at encoding time.
+ """
+ while self.delta < 2 ** self.total_range_bits:
+ bit = self.unpacker.pull()
+ if bit is None:
+ return None
+ self.low *= 2
+ self.high = self.high * 2 + 1
+ self.current = self.current * 2 + bit
+ self.max_bit += 1
+
+ def bin_search(low_idx: int, high_idx: int):
+ # Binary search is not just for coding interviews :)
+ if high_idx < low_idx:
+ raise RuntimeError("Binary search failed")
+ mid = (low_idx + high_idx) // 2
+ range_low = quantized_cdf[mid - 1].item() if mid > 0 else 0
+ range_high = quantized_cdf[mid].item() - 1
+ effective_low = int(math.ceil(range_low * (self.delta / (2 ** self.total_range_bits))))
+ effective_high = int(math.floor(range_high * (self.delta / (2 ** self.total_range_bits))))
+ low = effective_low + self.low
+ high = effective_high + self.low
+ if self.current >= low:
+ if self.current <= high:
+ return (mid, low, high, self.current)
+ else:
+ return bin_search(mid + 1, high_idx)
+ else:
+ return bin_search(low_idx, mid - 1)
+
+ self._last = (self.low, self.high, self.current, self.max_bit)
+ sym, self.low, self.high, self.current = bin_search(0, len(quantized_cdf) - 1)
+ self._dbg.append((self.low, self.high, self.current))
+ self._flush_common_prefix()
+ self._dbg2.append((self.low, self.high, self.current))
+
+ return sym
+
+
+def test():
+ torch.manual_seed(1234)
+ random.seed(1234)
+ for _ in range(4):
+ pdfs = []
+ cardinality = random.randrange(4000)
+ steps = random.randrange(100, 500)
+ fo = io.BytesIO()
+ encoder = ArithmeticCoder(fo)
+ symbols = []
+ for step in range(steps):
+ pdf = torch.softmax(torch.randn(cardinality), dim=0)
+ pdfs.append(pdf)
+ q_cdf = build_stable_quantized_cdf(pdf, encoder.total_range_bits)
+ symbol = torch.multinomial(pdf, 1).item()
+ symbols.append(symbol)
+ encoder.push(symbol, q_cdf)
+ encoder.flush()
+
+ fo.seek(0)
+ decoder = ArithmeticDecoder(fo)
+ for idx, (pdf, symbol) in enumerate(zip(pdfs, symbols)):
+ q_cdf = build_stable_quantized_cdf(pdf, encoder.total_range_bits)
+ decoded_symbol = decoder.pull(q_cdf)
+ assert decoded_symbol == symbol, idx
+ assert decoder.pull(torch.zeros(1)) is None
+
+
+if __name__ == "__main__":
+ test()
diff --git a/clean/audio/safeear/safeear/models/modules/quantization/core_vq.py b/clean/audio/safeear/safeear/models/modules/quantization/core_vq.py
new file mode 100644
index 0000000000000000000000000000000000000000..a5039e8dff71d3926717ae1922658458314cf552
--- /dev/null
+++ b/clean/audio/safeear/safeear/models/modules/quantization/core_vq.py
@@ -0,0 +1,366 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+#
+# This implementation is inspired from
+# https://github.com/lucidrains/vector-quantize-pytorch
+# which is released under MIT License. Hereafter, the original license:
+# MIT License
+#
+# Copyright (c) 2020 Phil Wang
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+"""Core vector quantization implementation."""
+import typing as tp
+
+from einops import rearrange, repeat
+import torch
+from torch import nn
+import torch.nn.functional as F
+
+from .distrib import broadcast_tensors, rank
+
+
+def default(val: tp.Any, d: tp.Any) -> tp.Any:
+ return val if val is not None else d
+
+
+def ema_inplace(moving_avg, new, decay: float):
+ moving_avg.data.mul_(decay).add_(new, alpha=(1 - decay))
+
+
+def laplace_smoothing(x, n_categories: int, epsilon: float = 1e-5):
+ return (x + epsilon) / (x.sum() + n_categories * epsilon)
+
+
+def uniform_init(*shape: int):
+ t = torch.empty(shape)
+ nn.init.kaiming_uniform_(t)
+ return t
+
+
+def sample_vectors(samples, num: int):
+ num_samples, device = samples.shape[0], samples.device
+
+ if num_samples >= num:
+ indices = torch.randperm(num_samples, device=device)[:num]
+ else:
+ indices = torch.randint(0, num_samples, (num,), device=device)
+
+ return samples[indices]
+
+
+def kmeans(samples, num_clusters: int, num_iters: int = 10):
+ dim, dtype = samples.shape[-1], samples.dtype
+
+ means = sample_vectors(samples, num_clusters)
+
+ for _ in range(num_iters):
+ diffs = rearrange(samples, "n d -> n () d") - rearrange(
+ means, "c d -> () c d"
+ )
+ dists = -(diffs ** 2).sum(dim=-1)
+
+ buckets = dists.max(dim=-1).indices
+ bins = torch.bincount(buckets, minlength=num_clusters)
+ zero_mask = bins == 0
+ bins_min_clamped = bins.masked_fill(zero_mask, 1)
+
+ new_means = buckets.new_zeros(num_clusters, dim, dtype=dtype)
+ new_means.scatter_add_(0, repeat(buckets, "n -> n d", d=dim), samples)
+ new_means = new_means / bins_min_clamped[..., None]
+
+ means = torch.where(zero_mask[..., None], means, new_means)
+
+ return means, bins
+
+
+class EuclideanCodebook(nn.Module):
+ """Codebook with Euclidean distance.
+ Args:
+ dim (int): Dimension.
+ codebook_size (int): Codebook size.
+ kmeans_init (bool): Whether to use k-means to initialize the codebooks.
+ If set to true, run the k-means algorithm on the first training batch and use
+ the learned centroids as initialization.
+ kmeans_iters (int): Number of iterations used for k-means algorithm at initialization.
+ decay (float): Decay for exponential moving average over the codebooks.
+ epsilon (float): Epsilon value for numerical stability.
+ threshold_ema_dead_code (int): Threshold for dead code expiration. Replace any codes
+ that have an exponential moving average cluster size less than the specified threshold with
+ randomly selected vector from the current batch.
+ """
+ def __init__(
+ self,
+ dim: int,
+ codebook_size: int,
+ kmeans_init: int = False,
+ kmeans_iters: int = 10,
+ decay: float = 0.99,
+ epsilon: float = 1e-5,
+ threshold_ema_dead_code: int = 2,
+ ):
+ super().__init__()
+ self.decay = decay
+ init_fn: tp.Union[tp.Callable[..., torch.Tensor], tp.Any] = uniform_init if not kmeans_init else torch.zeros
+ embed = init_fn(codebook_size, dim)
+
+ self.codebook_size = codebook_size
+
+ self.kmeans_iters = kmeans_iters
+ self.epsilon = epsilon
+ self.threshold_ema_dead_code = threshold_ema_dead_code
+
+ self.register_buffer("inited", torch.Tensor([not kmeans_init]))
+ self.register_buffer("cluster_size", torch.zeros(codebook_size))
+ self.register_buffer("embed", embed)
+ self.register_buffer("embed_avg", embed.clone())
+
+ @torch.jit.ignore
+ def init_embed_(self, data):
+ if self.inited:
+ return
+
+ embed, cluster_size = kmeans(data, self.codebook_size, self.kmeans_iters)
+ self.embed.data.copy_(embed)
+ self.embed_avg.data.copy_(embed.clone())
+ self.cluster_size.data.copy_(cluster_size)
+ self.inited.data.copy_(torch.Tensor([True]))
+ # Make sure all buffers across workers are in sync after initialization
+ #broadcast_tensors(self.buffers())
+
+ def replace_(self, samples, mask):
+ modified_codebook = torch.where(
+ mask[..., None], sample_vectors(samples, self.codebook_size), self.embed
+ )
+ self.embed.data.copy_(modified_codebook)
+
+ def expire_codes_(self, batch_samples):
+ if self.threshold_ema_dead_code == 0:
+ return
+
+ expired_codes = self.cluster_size < self.threshold_ema_dead_code
+ if not torch.any(expired_codes):
+ return
+
+ batch_samples = rearrange(batch_samples, "... d -> (...) d")
+ self.replace_(batch_samples, mask=expired_codes)
+ #broadcast_tensors(self.buffers())
+
+ def preprocess(self, x):
+ x = rearrange(x, "... d -> (...) d")
+ return x
+
+ def quantize(self, x):
+ embed = self.embed.t()
+ dist = -(
+ x.pow(2).sum(1, keepdim=True)
+ - 2 * x @ embed
+ + embed.pow(2).sum(0, keepdim=True)
+ )
+ embed_ind = dist.max(dim=-1).indices
+ return embed_ind
+
+ def postprocess_emb(self, embed_ind, shape):
+ return embed_ind.view(*shape[:-1])
+
+ def dequantize(self, embed_ind):
+ quantize = F.embedding(embed_ind, self.embed)
+ return quantize
+
+ def encode(self, x):
+ shape = x.shape
+ # pre-process
+ x = self.preprocess(x)
+ # quantize
+ embed_ind = self.quantize(x)
+ # post-process
+ embed_ind = self.postprocess_emb(embed_ind, shape)
+ return embed_ind
+
+ def decode(self, embed_ind):
+ quantize = self.dequantize(embed_ind)
+ return quantize
+
+ def forward(self, x):
+ shape, dtype = x.shape, x.dtype
+ x = self.preprocess(x)
+
+ self.init_embed_(x)
+
+ embed_ind = self.quantize(x)
+ embed_onehot = F.one_hot(embed_ind, self.codebook_size).type(dtype)
+ embed_ind = self.postprocess_emb(embed_ind, shape)
+ quantize = self.dequantize(embed_ind)
+
+ if self.training:
+ # We do the expiry of code at that point as buffers are in sync
+ # and all the workers will take the same decision.
+ self.expire_codes_(x)
+ ema_inplace(self.cluster_size, embed_onehot.sum(0), self.decay)
+ embed_sum = x.t() @ embed_onehot
+ ema_inplace(self.embed_avg, embed_sum.t(), self.decay)
+ cluster_size = (
+ laplace_smoothing(self.cluster_size, self.codebook_size, self.epsilon)
+ * self.cluster_size.sum()
+ )
+ embed_normalized = self.embed_avg / cluster_size.unsqueeze(1)
+ self.embed.data.copy_(embed_normalized)
+
+ return quantize, embed_ind
+
+
+class VectorQuantization(nn.Module):
+ """Vector quantization implementation.
+ Currently supports only euclidean distance.
+ Args:
+ dim (int): Dimension
+ codebook_size (int): Codebook size
+ codebook_dim (int): Codebook dimension. If not defined, uses the specified dimension in dim.
+ decay (float): Decay for exponential moving average over the codebooks.
+ epsilon (float): Epsilon value for numerical stability.
+ kmeans_init (bool): Whether to use kmeans to initialize the codebooks.
+ kmeans_iters (int): Number of iterations used for kmeans initialization.
+ threshold_ema_dead_code (int): Threshold for dead code expiration. Replace any codes
+ that have an exponential moving average cluster size less than the specified threshold with
+ randomly selected vector from the current batch.
+ commitment_weight (float): Weight for commitment loss.
+ """
+ def __init__(
+ self,
+ dim: int,
+ codebook_size: int,
+ codebook_dim: tp.Optional[int] = None,
+ decay: float = 0.99,
+ epsilon: float = 1e-5,
+ kmeans_init: bool = True,
+ kmeans_iters: int = 50,
+ threshold_ema_dead_code: int = 2,
+ commitment_weight: float = 1.,
+ ):
+ super().__init__()
+ _codebook_dim: int = default(codebook_dim, dim)
+
+ requires_projection = _codebook_dim != dim
+ self.project_in = (nn.Linear(dim, _codebook_dim) if requires_projection else nn.Identity())
+ self.project_out = (nn.Linear(_codebook_dim, dim) if requires_projection else nn.Identity())
+
+ self.epsilon = epsilon
+ self.commitment_weight = commitment_weight
+
+ self._codebook = EuclideanCodebook(dim=_codebook_dim, codebook_size=codebook_size,
+ kmeans_init=kmeans_init, kmeans_iters=kmeans_iters,
+ decay=decay, epsilon=epsilon,
+ threshold_ema_dead_code=threshold_ema_dead_code)
+ self.codebook_size = codebook_size
+
+ @property
+ def codebook(self):
+ return self._codebook.embed
+
+ def encode(self, x):
+ x = rearrange(x, "b d n -> b n d")
+ x = self.project_in(x)
+ embed_in = self._codebook.encode(x)
+ return embed_in
+
+ def decode(self, embed_ind):
+ quantize = self._codebook.decode(embed_ind)
+ quantize = self.project_out(quantize)
+ quantize = rearrange(quantize, "b n d -> b d n")
+ return quantize
+
+ def forward(self, x):
+ device = x.device
+ x = rearrange(x, "b d n -> b n d")
+ x = self.project_in(x)
+
+ quantize, embed_ind = self._codebook(x)
+
+ if self.training:
+ quantize = x + (quantize - x).detach()
+
+ loss = torch.tensor([0.0], device=device, requires_grad=self.training)
+
+ if self.training:
+ if self.commitment_weight > 0:
+ commit_loss = F.mse_loss(quantize.detach(), x)
+ loss = loss + commit_loss * self.commitment_weight
+
+ quantize = self.project_out(quantize)
+ quantize = rearrange(quantize, "b n d -> b d n")
+ return quantize, embed_ind, loss
+
+
+class ResidualVectorQuantization(nn.Module):
+ """Residual vector quantization implementation.
+ Follows Algorithm 1. in https://arxiv.org/pdf/2107.03312.pdf
+ """
+ def __init__(self, *, num_quantizers, **kwargs):
+ super().__init__()
+ self.layers = nn.ModuleList(
+ [VectorQuantization(**kwargs) for _ in range(num_quantizers)]
+ )
+
+ def forward(self, x, n_q: tp.Optional[int] = None, layers: tp.Optional[list] = None):
+ quantized_out = 0.0
+ residual = x
+
+ all_losses = []
+ all_indices = []
+ out_quantized = []
+
+ n_q = n_q or len(self.layers)
+
+ for i, layer in enumerate(self.layers[:n_q]):
+ quantized, indices, loss = layer(residual)
+ residual = residual - quantized
+ quantized_out = quantized_out + quantized
+
+ all_indices.append(indices)
+ all_losses.append(loss)
+ if layers and i in layers:
+ out_quantized.append(quantized)
+
+ out_losses, out_indices = map(torch.stack, (all_losses, all_indices))
+ return quantized_out, out_indices, out_losses, out_quantized
+
+ def encode(self, x: torch.Tensor, n_q: tp.Optional[int] = None, st: tp.Optional[int]= None) -> torch.Tensor:
+ residual = x
+ all_indices = []
+ n_q = n_q or len(self.layers)
+ st = st or 0
+ for layer in self.layers[st:n_q]:
+ indices = layer.encode(residual)
+ quantized = layer.decode(indices)
+ residual = residual - quantized
+ all_indices.append(indices)
+ out_indices = torch.stack(all_indices)
+ return out_indices
+
+ def decode(self, q_indices: torch.Tensor, st: int=0) -> torch.Tensor:
+ quantized_out = torch.tensor(0.0, device=q_indices.device)
+ for i, indices in enumerate(q_indices):
+ layer = self.layers[st + i]
+ quantized = layer.decode(indices)
+ quantized_out = quantized_out + quantized
+ return quantized_out
diff --git a/clean/audio/safeear/safeear/models/modules/quantization/distrib.py b/clean/audio/safeear/safeear/models/modules/quantization/distrib.py
new file mode 100644
index 0000000000000000000000000000000000000000..4edc88a532c9cf842bd2ee9a56f2c0b5dcb7c83d
--- /dev/null
+++ b/clean/audio/safeear/safeear/models/modules/quantization/distrib.py
@@ -0,0 +1,126 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+"""Torch distributed utilities."""
+
+import typing as tp
+
+import torch
+
+
+def rank():
+ if torch.distributed.is_initialized():
+ return torch.distributed.get_rank()
+ else:
+ return 0
+
+
+def world_size():
+ if torch.distributed.is_initialized():
+ return torch.distributed.get_world_size()
+ else:
+ return 1
+
+
+def is_distributed():
+ return world_size() > 1
+
+
+def all_reduce(tensor: torch.Tensor, op=torch.distributed.ReduceOp.SUM):
+ if is_distributed():
+ return torch.distributed.all_reduce(tensor, op)
+
+
+def _is_complex_or_float(tensor):
+ return torch.is_floating_point(tensor) or torch.is_complex(tensor)
+
+
+def _check_number_of_params(params: tp.List[torch.Tensor]):
+ # utility function to check that the number of params in all workers is the same,
+ # and thus avoid a deadlock with distributed all reduce.
+ if not is_distributed() or not params:
+ return
+ #print('params[0].device ', params[0].device)
+ tensor = torch.tensor([len(params)], device=params[0].device, dtype=torch.long)
+ all_reduce(tensor)
+ if tensor.item() != len(params) * world_size():
+ # If not all the workers have the same number, for at least one of them,
+ # this inequality will be verified.
+ raise RuntimeError(f"Mismatch in number of params: ours is {len(params)}, "
+ "at least one worker has a different one.")
+
+
+def broadcast_tensors(tensors: tp.Iterable[torch.Tensor], src: int = 0):
+ """Broadcast the tensors from the given parameters to all workers.
+ This can be used to ensure that all workers have the same model to start with.
+ """
+ if not is_distributed():
+ return
+ tensors = [tensor for tensor in tensors if _is_complex_or_float(tensor)]
+ _check_number_of_params(tensors)
+ handles = []
+ for tensor in tensors:
+ # src = int(rank()) # added code
+ handle = torch.distributed.broadcast(tensor.data, src=src, async_op=True)
+ handles.append(handle)
+ for handle in handles:
+ handle.wait()
+
+
+def sync_buffer(buffers, average=True):
+ """
+ Sync grad for buffers. If average is False, broadcast instead of averaging.
+ """
+ if not is_distributed():
+ return
+ handles = []
+ for buffer in buffers:
+ if torch.is_floating_point(buffer.data):
+ if average:
+ handle = torch.distributed.all_reduce(
+ buffer.data, op=torch.distributed.ReduceOp.SUM, async_op=True)
+ else:
+ handle = torch.distributed.broadcast(
+ buffer.data, src=0, async_op=True)
+ handles.append((buffer, handle))
+ for buffer, handle in handles:
+ handle.wait()
+ if average:
+ buffer.data /= world_size
+
+
+def sync_grad(params):
+ """
+ Simpler alternative to DistributedDataParallel, that doesn't rely
+ on any black magic. For simple models it can also be as fast.
+ Just call this on your model parameters after the call to backward!
+ """
+ if not is_distributed():
+ return
+ handles = []
+ for p in params:
+ if p.grad is not None:
+ handle = torch.distributed.all_reduce(
+ p.grad.data, op=torch.distributed.ReduceOp.SUM, async_op=True)
+ handles.append((p, handle))
+ for p, handle in handles:
+ handle.wait()
+ p.grad.data /= world_size()
+
+
+def average_metrics(metrics: tp.Dict[str, float], count=1.):
+ """Average a dictionary of metrics across all workers, using the optional
+ `count` as unormalized weight.
+ """
+ if not is_distributed():
+ return metrics
+ keys, values = zip(*metrics.items())
+ device = 'cuda' if torch.cuda.is_available() else 'cpu'
+ tensor = torch.tensor(list(values) + [1], device=device, dtype=torch.float32)
+ tensor *= count
+ all_reduce(tensor)
+ averaged = (tensor[:-1] / tensor[-1]).cpu().tolist()
+ return dict(zip(keys, averaged))
diff --git a/clean/audio/safeear/safeear/models/modules/quantization/vq.py b/clean/audio/safeear/safeear/models/modules/quantization/vq.py
new file mode 100644
index 0000000000000000000000000000000000000000..490a4f48e2c81ba7425836f4d6df0528f41c8dd0
--- /dev/null
+++ b/clean/audio/safeear/safeear/models/modules/quantization/vq.py
@@ -0,0 +1,108 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+"""Residual vector quantizer implementation."""
+
+from dataclasses import dataclass, field
+import math
+import typing as tp
+
+import torch
+from torch import nn
+
+from .core_vq import ResidualVectorQuantization
+
+
+@dataclass
+class QuantizedResult:
+ quantized: torch.Tensor
+ codes: torch.Tensor
+ bandwidth: torch.Tensor # bandwidth in kb/s used, per batch item.
+ penalty: tp.Optional[torch.Tensor] = None
+ metrics: dict = field(default_factory=dict)
+
+
+class ResidualVectorQuantizer(nn.Module):
+ """Residual Vector Quantizer.
+ Args:
+ dimension (int): Dimension of the codebooks.
+ n_q (int): Number of residual vector quantizers used.
+ bins (int): Codebook size.
+ decay (float): Decay for exponential moving average over the codebooks.
+ kmeans_init (bool): Whether to use kmeans to initialize the codebooks.
+ kmeans_iters (int): Number of iterations used for kmeans initialization.
+ threshold_ema_dead_code (int): Threshold for dead code expiration. Replace any codes
+ that have an exponential moving average cluster size less than the specified threshold with
+ randomly selected vector from the current batch.
+ """
+ def __init__(
+ self,
+ dimension: int = 256,
+ n_q: int = 8,
+ bins: int = 1024,
+ decay: float = 0.99,
+ kmeans_init: bool = True,
+ kmeans_iters: int = 50,
+ threshold_ema_dead_code: int = 2,
+ ):
+ super().__init__()
+ self.n_q = n_q
+ self.dimension = dimension
+ self.bins = bins
+ self.decay = decay
+ self.kmeans_init = kmeans_init
+ self.kmeans_iters = kmeans_iters
+ self.threshold_ema_dead_code = threshold_ema_dead_code
+ self.vq = ResidualVectorQuantization(
+ dim=self.dimension,
+ codebook_size=self.bins,
+ num_quantizers=self.n_q,
+ decay=self.decay,
+ kmeans_init=self.kmeans_init,
+ kmeans_iters=self.kmeans_iters,
+ threshold_ema_dead_code=self.threshold_ema_dead_code,
+ )
+
+ def forward(self, x: torch.Tensor, n_q: tp.Optional[int] = None, layers: tp.Optional[list] = None) -> QuantizedResult:
+ """Residual vector quantization on the given input tensor.
+ Args:
+ x (torch.Tensor): Input tensor.
+ n_q (int): Number of quantizer used to quantize. Default: All quantizers.
+ layers (list): Layer that need to return quantized. Defalt: None.
+ Returns:
+ QuantizedResult:
+ The quantized (or approximately quantized) representation with
+ the associated numbert quantizers and layer quantized required to return.
+ """
+ n_q = n_q if n_q else self.n_q
+ if layers and max(layers) >= n_q:
+ raise ValueError(f'Last layer index in layers: A {max(layers)}. Number of quantizers in RVQ: B {self.n_q}. A must less than B.')
+ quantized, codes, commit_loss, quantized_list = self.vq(x, n_q=n_q, layers=layers)
+ return quantized, codes, torch.mean(commit_loss), quantized_list
+
+
+ def encode(self, x: torch.Tensor, n_q: tp.Optional[int] = None, st: tp.Optional[int] = None) -> torch.Tensor:
+ """Encode a given input tensor with the specified sample rate at the given bandwidth.
+ The RVQ encode method sets the appropriate number of quantizer to use
+ and returns indices for each quantizer.
+ Args:
+ x (torch.Tensor): Input tensor.
+ n_q (int): Number of quantizer used to quantize. Default: All quantizers.
+ st (int): Start to encode input from which layers. Default: 0.
+ """
+ n_q = n_q if n_q else self.n_q
+ st = st or 0
+ codes = self.vq.encode(x, n_q=n_q, st=st)
+ return codes
+
+ def decode(self, codes: torch.Tensor, st: int = 0) -> torch.Tensor:
+ """Decode the given codes to the quantized representation.
+ Args:
+ codes (torch.Tensor): Input indices for each quantizer.
+ st (int): Start to decode input codes from which layers. Default: 0.
+ """
+ quantized = self.vq.decode(codes, st=st)
+ return quantized
diff --git a/clean/audio/safeear/safeear/models/modules/seanet.py b/clean/audio/safeear/safeear/models/modules/seanet.py
new file mode 100644
index 0000000000000000000000000000000000000000..43ba29ff1bd44de9a19027e724e4e0152d4671b0
--- /dev/null
+++ b/clean/audio/safeear/safeear/models/modules/seanet.py
@@ -0,0 +1,275 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+"""Encodec SEANet-based encoder and decoder implementation."""
+
+import typing as tp
+
+import numpy as np
+import torch.nn as nn
+import torch
+
+from . import (
+ SConv1d,
+ SConvTranspose1d,
+ SLSTM
+)
+
+
+@torch.jit.script
+def snake(x, alpha):
+ shape = x.shape
+ x = x.reshape(shape[0], shape[1], -1)
+ x = x + (alpha + 1e-9).reciprocal() * torch.sin(alpha * x).pow(2)
+ x = x.reshape(shape)
+ return x
+
+
+class Snake1d(nn.Module):
+ def __init__(self, channels):
+ super().__init__()
+ self.alpha = nn.Parameter(torch.ones(1, channels, 1))
+
+ def forward(self, x):
+ return snake(x, self.alpha)
+
+class SEANetResnetBlock(nn.Module):
+ """Residual block from SEANet model.
+ Args:
+ dim (int): Dimension of the input/output
+ kernel_sizes (list): List of kernel sizes for the convolutions.
+ dilations (list): List of dilations for the convolutions.
+ activation (str): Activation function.
+ activation_params (dict): Parameters to provide to the activation function
+ norm (str): Normalization method.
+ norm_params (dict): Parameters to provide to the underlying normalization used along with the convolution.
+ causal (bool): Whether to use fully causal convolution.
+ pad_mode (str): Padding mode for the convolutions.
+ compress (int): Reduced dimensionality in residual branches (from Demucs v3)
+ true_skip (bool): Whether to use true skip connection or a simple convolution as the skip connection.
+ """
+ def __init__(self, dim: int, kernel_sizes: tp.List[int] = [3, 1], dilations: tp.List[int] = [1, 1],
+ activation: str = 'ELU', activation_params: dict = {'alpha': 1.0},
+ norm: str = 'weight_norm', norm_params: tp.Dict[str, tp.Any] = {}, causal: bool = False,
+ pad_mode: str = 'reflect', compress: int = 2, true_skip: bool = True):
+ super().__init__()
+ assert len(kernel_sizes) == len(dilations), 'Number of kernel sizes should match number of dilations'
+ act = getattr(nn, activation) if activation != 'Snake' else Snake1d
+ hidden = dim // compress
+ block = []
+ for i, (kernel_size, dilation) in enumerate(zip(kernel_sizes, dilations)):
+ in_chs = dim if i == 0 else hidden
+ out_chs = dim if i == len(kernel_sizes) - 1 else hidden
+ block += [
+ act(**activation_params) if activation != 'Snake' else act(in_chs),
+ SConv1d(in_chs, out_chs, kernel_size=kernel_size, dilation=dilation,
+ norm=norm, norm_kwargs=norm_params,
+ causal=causal, pad_mode=pad_mode),
+ ]
+ self.block = nn.Sequential(*block)
+ self.shortcut: nn.Module
+ if true_skip:
+ self.shortcut = nn.Identity()
+ else:
+ self.shortcut = SConv1d(dim, dim, kernel_size=1, norm=norm, norm_kwargs=norm_params,
+ causal=causal, pad_mode=pad_mode)
+
+ def forward(self, x):
+ return self.shortcut(x) + self.block(x)
+
+
+
+class SEANetEncoder(nn.Module):
+ """SEANet encoder.
+ Args:
+ channels (int): Audio channels.
+ dimension (int): Intermediate representation dimension.
+ n_filters (int): Base width for the model.
+ n_residual_layers (int): nb of residual layers.
+ ratios (Sequence[int]): kernel size and stride ratios. The encoder uses downsampling ratios instead of
+ upsampling ratios, hence it will use the ratios in the reverse order to the ones specified here
+ that must match the decoder order
+ activation (str): Activation function.
+ activation_params (dict): Parameters to provide to the activation function
+ norm (str): Normalization method.
+ norm_params (dict): Parameters to provide to the underlying normalization used along with the convolution.
+ kernel_size (int): Kernel size for the initial convolution.
+ last_kernel_size (int): Kernel size for the initial convolution.
+ residual_kernel_size (int): Kernel size for the residual layers.
+ dilation_base (int): How much to increase the dilation with each layer.
+ causal (bool): Whether to use fully causal convolution.
+ pad_mode (str): Padding mode for the convolutions.
+ true_skip (bool): Whether to use true skip connection or a simple
+ (streamable) convolution as the skip connection in the residual network blocks.
+ compress (int): Reduced dimensionality in residual branches (from Demucs v3).
+ lstm (int): Number of LSTM layers at the end of the encoder.
+ """
+ def __init__(self, channels: int = 1, dimension: int = 128, n_filters: int = 32, n_residual_layers: int = 1,
+ ratios: tp.List[int] = [8, 5, 4, 2], activation: str = 'ELU', activation_params: dict = {'alpha': 1.0},
+ norm: str = 'weight_norm', norm_params: tp.Dict[str, tp.Any] = {}, kernel_size: int = 7,
+ last_kernel_size: int = 7, residual_kernel_size: int = 3, dilation_base: int = 2, causal: bool = False,
+ pad_mode: str = 'reflect', true_skip: bool = False, compress: int = 2, lstm: int = 2, bidirectional:bool = False):
+ super().__init__()
+ self.channels = channels
+ self.dimension = dimension
+ self.n_filters = n_filters
+ self.ratios = list(reversed(ratios))
+ del ratios
+ self.n_residual_layers = n_residual_layers
+ self.hop_length = np.prod(self.ratios) # 计算乘积
+
+ act = getattr(nn, activation) if activation != 'Snake' else Snake1d
+ mult = 1
+ model: tp.List[nn.Module] = [
+ SConv1d(channels, mult * n_filters, kernel_size, norm=norm, norm_kwargs=norm_params,
+ causal=causal, pad_mode=pad_mode)
+ ]
+ # Downsample to raw audio scale
+ for i, ratio in enumerate(self.ratios):
+ # Add residual layers
+ for j in range(n_residual_layers):
+ model += [
+ SEANetResnetBlock(mult * n_filters, kernel_sizes=[residual_kernel_size, 1],
+ dilations=[dilation_base ** j, 1],
+ norm=norm, norm_params=norm_params,
+ activation=activation, activation_params=activation_params,
+ causal=causal, pad_mode=pad_mode, compress=compress, true_skip=true_skip)]
+
+ # Add downsampling layers
+ model += [
+ act(**activation_params) if activation != 'Snake' else act(mult * n_filters),
+ SConv1d(mult * n_filters, mult * n_filters * 2,
+ kernel_size=ratio * 2, stride=ratio,
+ norm=norm, norm_kwargs=norm_params,
+ causal=causal, pad_mode=pad_mode),
+ ]
+ mult *= 2
+
+ if lstm:
+ model += [SLSTM(mult * n_filters, num_layers=lstm, bidirectional=bidirectional)]
+
+ mult = mult * 2 if bidirectional else mult
+ model += [
+ act(**activation_params) if activation != 'Snake' else act(mult * n_filters),
+ SConv1d(mult * n_filters, dimension, last_kernel_size, norm=norm, norm_kwargs=norm_params,
+ causal=causal, pad_mode=pad_mode)
+ ]
+
+ self.model = nn.Sequential(*model)
+
+ def forward(self, x):
+ return self.model(x)
+
+
+class SEANetDecoder(nn.Module):
+ """SEANet decoder.
+ Args:
+ channels (int): Audio channels.
+ dimension (int): Intermediate representation dimension.
+ n_filters (int): Base width for the model.
+ n_residual_layers (int): nb of residual layers.
+ ratios (Sequence[int]): kernel size and stride ratios
+ activation (str): Activation function.
+ activation_params (dict): Parameters to provide to the activation function
+ final_activation (str): Final activation function after all convolutions.
+ final_activation_params (dict): Parameters to provide to the activation function
+ norm (str): Normalization method.
+ norm_params (dict): Parameters to provide to the underlying normalization used along with the convolution.
+ kernel_size (int): Kernel size for the initial convolution.
+ last_kernel_size (int): Kernel size for the initial convolution.
+ residual_kernel_size (int): Kernel size for the residual layers.
+ dilation_base (int): How much to increase the dilation with each layer.
+ causal (bool): Whether to use fully causal convolution.
+ pad_mode (str): Padding mode for the convolutions.
+ true_skip (bool): Whether to use true skip connection or a simple
+ (streamable) convolution as the skip connection in the residual network blocks.
+ compress (int): Reduced dimensionality in residual branches (from Demucs v3).
+ lstm (int): Number of LSTM layers at the end of the encoder.
+ trim_right_ratio (float): Ratio for trimming at the right of the transposed convolution under the causal setup.
+ If equal to 1.0, it means that all the trimming is done at the right.
+ """
+ def __init__(self, channels: int = 1, dimension: int = 128, n_filters: int = 32, n_residual_layers: int = 1,
+ ratios: tp.List[int] = [8, 5, 4, 2], activation: str = 'ELU', activation_params: dict = {'alpha': 1.0},
+ final_activation: tp.Optional[str] = None, final_activation_params: tp.Optional[dict] = None,
+ norm: str = 'weight_norm', norm_params: tp.Dict[str, tp.Any] = {}, kernel_size: int = 7,
+ last_kernel_size: int = 7, residual_kernel_size: int = 3, dilation_base: int = 2, causal: bool = False,
+ pad_mode: str = 'reflect', true_skip: bool = False, compress: int = 2, lstm: int = 2,
+ trim_right_ratio: float = 1.0, bidirectional:bool = False):
+ super().__init__()
+ self.dimension = dimension
+ self.channels = channels
+ self.n_filters = n_filters
+ self.ratios = ratios
+ del ratios
+ self.n_residual_layers = n_residual_layers
+ self.hop_length = np.prod(self.ratios)
+
+ act = getattr(nn, activation) if activation != 'Snake' else Snake1d
+ mult = int(2 ** len(self.ratios))
+ model: tp.List[nn.Module] = [
+ SConv1d(dimension, mult * n_filters, kernel_size, norm=norm, norm_kwargs=norm_params,
+ causal=causal, pad_mode=pad_mode)
+ ]
+
+ if lstm:
+ model += [SLSTM(mult * n_filters, num_layers=lstm, bidirectional=bidirectional)]
+
+ # Upsample to raw audio scale
+ for i, ratio in enumerate(self.ratios):
+ # Add upsampling layers
+ model += [
+ act(**activation_params) if activation != 'Snake' else act(mult * n_filters),
+ SConvTranspose1d(mult * n_filters, mult * n_filters // 2,
+ kernel_size=ratio * 2, stride=ratio,
+ norm=norm, norm_kwargs=norm_params,
+ causal=causal, trim_right_ratio=trim_right_ratio),
+ ]
+ # Add residual layers
+ for j in range(n_residual_layers):
+ model += [
+ SEANetResnetBlock(mult * n_filters // 2, kernel_sizes=[residual_kernel_size, 1],
+ dilations=[dilation_base ** j, 1],
+ activation=activation, activation_params=activation_params,
+ norm=norm, norm_params=norm_params, causal=causal,
+ pad_mode=pad_mode, compress=compress, true_skip=true_skip)]
+
+ mult //= 2
+
+ # Add final layers
+ model += [
+ act(**activation_params) if activation != 'Snake' else act(n_filters),
+ SConv1d(n_filters, channels, last_kernel_size, norm=norm, norm_kwargs=norm_params,
+ causal=causal, pad_mode=pad_mode)
+ ]
+ # Add optional final activation to decoder (eg. tanh)
+ if final_activation is not None:
+ final_act = getattr(nn, final_activation)
+ final_activation_params = final_activation_params or {}
+ model += [
+ final_act(**final_activation_params)
+ ]
+ self.model = nn.Sequential(*model)
+
+ def forward(self, z):
+ y = self.model(z)
+ return y
+
+
+def test():
+ import torch
+ encoder = SEANetEncoder()
+ decoder = SEANetDecoder()
+ x = torch.randn(1, 1, 24000)
+ z = encoder(x)
+ print('z ', z.shape)
+ assert 1==2
+ assert list(z.shape) == [1, 128, 75], z.shape
+ y = decoder(z)
+ assert y.shape == x.shape, (x.shape, y.shape)
+
+
+if __name__ == '__main__':
+ test()
diff --git a/clean/audio/safeear/safeear/models/safeear.py b/clean/audio/safeear/safeear/models/safeear.py
new file mode 100644
index 0000000000000000000000000000000000000000..c3c5300a0b547ea81ef4800532bf956e1633ab43
--- /dev/null
+++ b/clean/audio/safeear/safeear/models/safeear.py
@@ -0,0 +1,959 @@
+import numpy as np
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+from torch.nn import Module, ModuleList, Linear, Dropout, LayerNorm, Identity, Parameter, init
+from timm.models.layers import trunc_normal_, DropPath
+import random
+from typing import Union
+import numpy as np
+import math
+from torch import Tensor
+
+def conv3x3(in_planes, out_planes, stride=1):
+ """3x3 convolution with padding"""
+ return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,
+ padding=1, bias=False)
+
+class SELayer(nn.Module):
+ def __init__(self, channel, reduction=16):
+ super(SELayer, self).__init__()
+ # print('se reduction: ', reduction)
+ # print(channel // reduction)
+ self.avg_pool = nn.AdaptiveAvgPool2d(1) # F_squeeze
+ self.fc = nn.Sequential(
+ nn.Linear(channel, channel // reduction, bias=False),
+ nn.ReLU(inplace=True),
+ nn.Linear(channel // reduction, channel, bias=False),
+ nn.Sigmoid()
+ )
+
+ def forward(self, x): # x: B*C*D*T
+ b, c, _, _ = x.size()
+ y = self.avg_pool(x).view(b, c)
+ y = self.fc(y).view(b, c, 1, 1)
+ return x * y.expand_as(x)
+
+class BasicBlock(nn.Module):
+ expansion = 1
+
+ def __init__(self, inplanes, planes, stride=1, downsample=None):
+ super(BasicBlock, self).__init__()
+ self.conv1 = conv3x3(inplanes, planes, stride)
+ self.bn1 = nn.BatchNorm2d(planes)
+ self.relu = nn.ReLU(inplace=True)
+ self.conv2 = conv3x3(planes, planes)
+ self.bn2 = nn.BatchNorm2d(planes)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x):
+ residual = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+
+ if self.downsample is not None:
+ residual = self.downsample(x)
+
+ out += residual
+ out = self.relu(out)
+
+ return out
+
+class SEBasicBlock(nn.Module):
+ expansion = 1
+
+ def __init__(self, inplanes, planes, stride=1, downsample=None, reduction=16):
+ super(SEBasicBlock, self).__init__()
+ self.conv1 = conv3x3(inplanes, planes, stride)
+ self.bn1 = nn.BatchNorm2d(planes)
+ self.relu = nn.ReLU(inplace=True)
+ self.conv2 = conv3x3(planes, planes, 1)
+ self.bn2 = nn.BatchNorm2d(planes)
+ self.se = SELayer(planes, reduction)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x):
+ residual = x
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+ out = self.se(out)
+
+ if self.downsample is not None:
+ residual = self.downsample(x)
+
+ out += residual
+ out = self.relu(out)
+
+ return out
+
+class Bottleneck(nn.Module):
+ expansion = 2
+
+ def __init__(self, inplanes, planes, stride=1, downsample=None):
+ super(Bottleneck, self).__init__()
+ self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False)
+ self.bn1 = nn.BatchNorm2d(planes)
+ self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
+ self.bn2 = nn.BatchNorm2d(planes)
+ self.conv3 = nn.Conv2d(planes, planes * self.expansion, kernel_size=1, bias=False)
+ self.bn3 = nn.BatchNorm2d(planes * self.expansion)
+ self.relu = nn.ReLU(inplace=True)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x):
+ residual = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+ out = self.relu(out)
+
+ out = self.conv3(out)
+ out = self.bn3(out)
+
+ if self.downsample is not None:
+ residual = self.downsample(x)
+
+ out += residual
+ out = self.relu(out)
+
+ return out
+
+class SEBottleneck(nn.Module):
+ expansion = 2
+
+ def __init__(self, inplanes, planes, stride=1, downsample=None, reduction=16):
+ super(SEBottleneck, self).__init__()
+ self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False)
+ self.bn1 = nn.BatchNorm2d(planes)
+ self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
+ self.bn2 = nn.BatchNorm2d(planes)
+ self.conv3 = nn.Conv2d(planes, planes * self.expansion, kernel_size=1, bias=False)
+ self.bn3 = nn.BatchNorm2d(planes * self.expansion)
+ self.relu = nn.ReLU(inplace=True)
+ self.se = SELayer(planes * self.expansion, reduction)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x):
+ residual = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+ out = self.relu(out)
+
+ out = self.conv3(out)
+ out = self.bn3(out)
+ out = self.se(out)
+
+ if self.downsample is not None:
+ residual = self.downsample(x)
+
+ out += residual
+ out = self.relu(out)
+
+ return out
+
+
+class Bottle2neck(nn.Module):
+ expansion = 2
+
+ def __init__(self,
+ inplanes,
+ planes,
+ stride=1,
+ downsample=None,
+ baseWidth=26,
+ scale=4,
+ stype='normal'):
+ """ Constructor
+ Args:
+ inplanes: input channel dimensionality
+ planes: output channel dimensionality
+ stride: conv stride. Replaces pooling layer.
+ downsample: None when stride = 1
+ baseWidth: basic width of conv3x3
+ scale: number of scale.
+ type: 'normal': normal set. 'stage': first block of a new stage.
+ """
+ super(Bottle2neck, self).__init__()
+
+ width = int(math.floor(planes * (baseWidth / 64.0)))
+ self.conv1 = nn.Conv2d(inplanes,
+ width * scale,
+ kernel_size=1,
+ bias=False)
+ self.bn1 = nn.BatchNorm2d(width * scale)
+
+ if scale == 1:
+ self.nums = 1
+ else:
+ self.nums = scale - 1
+ if stype == 'stage':
+ self.pool = nn.AvgPool2d(kernel_size=3, stride=stride, padding=1)
+ convs = []
+ bns = []
+ for i in range(self.nums):
+ convs.append(
+ nn.Conv2d(width,
+ width,
+ kernel_size=3,
+ stride=stride,
+ padding=1,
+ bias=False))
+ bns.append(nn.BatchNorm2d(width))
+ self.convs = nn.ModuleList(convs)
+ self.bns = nn.ModuleList(bns)
+
+ self.conv3 = nn.Conv2d(width * scale,
+ planes * self.expansion,
+ kernel_size=1,
+ bias=False)
+ self.bn3 = nn.BatchNorm2d(planes * self.expansion)
+
+ self.relu = nn.ReLU(inplace=True)
+ if stride != 1 or inplanes != planes * self.expansion:
+ downsample = nn.Sequential(
+ nn.AvgPool2d(kernel_size=stride,
+ stride=stride,
+ ceil_mode=True,
+ count_include_pad=False),
+ nn.Conv2d(inplanes,
+ planes * self.expansion,
+ kernel_size=1,
+ stride=1,
+ bias=False),
+ nn.BatchNorm2d(planes * self.expansion),
+ )
+ self.downsample = downsample
+ self.stype = stype
+ self.scale = scale
+ self.width = width
+
+ def forward(self, x):
+ residual = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ spx = torch.split(out, self.width, 1)
+ for i in range(self.nums):
+ if i == 0 or self.stype == 'stage':
+ sp = spx[i]
+ else:
+ sp = sp + spx[i]
+ sp = self.convs[i](sp)
+ sp = self.relu(self.bns[i](sp))
+ if i == 0:
+ out = sp
+ else:
+ out = torch.cat((out, sp), 1)
+ if self.scale != 1 and self.stype == 'normal':
+ out = torch.cat((out, spx[self.nums]), 1)
+ elif self.scale != 1 and self.stype == 'stage':
+ out = torch.cat((out, self.pool(spx[self.nums])), 1)
+
+ out = self.conv3(out)
+ out = self.bn3(out)
+
+ if self.downsample is not None:
+ residual = self.downsample(x)
+
+ out += residual
+ out = self.relu(out)
+
+ return out
+
+class SEBottle2neck(nn.Module):
+ expansion = 1
+
+ def __init__(self,
+ inplanes,
+ planes,
+ stride=1,
+ kernel_size = 1,
+ padding=1,
+ downsample=None,
+ baseWidth=26,
+ scale=4,
+ stype='normal'):
+ """ Constructor
+ Args:
+ inplanes: input channel dimensionality
+ planes: output channel dimensionality
+ stride: conv stride. Replaces pooling layer.
+ downsample: None when stride = 1
+ baseWidth: basic width of conv3x3
+ scale: number of scale.
+ type: 'normal': normal set. 'stage': first block of a new stage.
+ """
+ super(SEBottle2neck, self).__init__()
+
+ width = int(math.floor(planes * (baseWidth / 64.0)))
+ self.conv1 = nn.Conv2d(inplanes,
+ width * scale,
+ kernel_size=kernel_size,
+ padding=padding,
+ bias=False)
+ self.bn1 = nn.BatchNorm2d(width * scale)
+
+ if scale == 1:
+ self.nums = 1
+ else:
+ self.nums = scale - 1
+ if stype == 'stage':
+ self.pool = nn.AvgPool2d(kernel_size=3, stride=stride, padding=1)
+ convs = []
+ bns = []
+ for i in range(self.nums):
+ convs.append(
+ nn.Conv2d(width,
+ width,
+ kernel_size=3,
+ stride=stride,
+ padding=1,
+ bias=False))
+ bns.append(nn.BatchNorm2d(width))
+ self.convs = nn.ModuleList(convs)
+ self.bns = nn.ModuleList(bns)
+
+ self.conv3 = nn.Conv2d(width * scale,
+ planes * self.expansion,
+ kernel_size=kernel_size,
+ padding=(0,1),
+ bias=False)
+ self.bn3 = nn.BatchNorm2d(planes * self.expansion)
+ self.se = SELayer(planes * self.expansion, reduction=16)
+ self.relu = nn.ReLU(inplace=True)
+ if inplanes != planes:
+ self.downsample = True
+ self.conv_downsample = nn.Conv2d(in_channels=inplanes,
+ out_channels=planes,
+ padding=(0, 0),
+ kernel_size=(1, 1),
+ stride=1)
+
+ else:
+ self.downsample = False
+ self.stype = stype
+ self.scale = scale
+ self.width = width
+
+ def forward(self, x):
+ residual = x
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ spx = torch.split(out, self.width, 1)
+ for i in range(self.nums):
+ if i == 0 or self.stype == 'stage':
+ sp = spx[i]
+ else:
+ sp = sp + spx[i]
+ sp = self.convs[i](sp)
+ sp = self.relu(self.bns[i](sp))
+ if i == 0:
+ out = sp
+ else:
+ out = torch.cat((out, sp), 1)
+ if self.scale != 1 and self.stype == 'normal':
+ out = torch.cat((out, spx[self.nums]), 1)
+ elif self.scale != 1 and self.stype == 'stage':
+ out = torch.cat((out, self.pool(spx[self.nums])), 1)
+
+ out = self.conv3(out)
+ out = self.bn3(out)
+ out = self.se(out)
+
+ if self.downsample:
+ residual = self.conv_downsample(residual)
+
+ out += residual
+ out = self.relu(out)
+
+ return out
+
+class Res2Net(nn.Module):
+ def __init__(self, block, layers, baseWidth=26, scale=4, m=0.35, num_classes=1000, loss='softmax', **kwargs):
+ self.inplanes = 16
+ super(Res2Net, self).__init__()
+ self.loss = loss
+ self.baseWidth = baseWidth
+ self.scale = scale
+ self.conv1 = nn.Sequential(nn.Conv2d(1, 16, 3, 1, 1, bias=False),
+ nn.BatchNorm2d(16), nn.ReLU(inplace=True),
+ nn.Conv2d(16, 16, 3, 1, 1, bias=False),
+ nn.BatchNorm2d(16), nn.ReLU(inplace=True),
+ nn.Conv2d(16, 16, 3, 1, 1, bias=False))
+ self.bn1 = nn.BatchNorm2d(16)
+ self.relu = nn.ReLU()
+ # self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
+ self.layer1 = self._make_layer(block, 16, layers[0])#64
+ self.layer2 = self._make_layer(block, 32, layers[1], stride=2)#128
+ self.layer3 = self._make_layer(block, 64, layers[2], stride=2)#256
+ self.layer4 = self._make_layer(block, 128, layers[3], stride=2)#512
+ self.avgpool = nn.AdaptiveAvgPool2d(1)
+ # self.stats_pooling = StatsPooling()
+
+ if self.loss == 'softmax':
+ # self.cls_layer = nn.Linear(2*8*128*block.expansion, num_classes)
+ self.cls_layer = nn.Linear(128*block.expansion, num_classes)
+ else:
+ raise NotImplementedError
+
+ for m in self.modules():
+ if isinstance(m, nn.Conv2d):
+ nn.init.kaiming_normal_(m.weight,
+ mode='fan_out',
+ nonlinearity='relu')
+ elif isinstance(m, nn.BatchNorm2d):
+ nn.init.constant_(m.weight, 1)
+ nn.init.constant_(m.bias, 0)
+
+ def _make_layer(self, block, planes, blocks, stride=1):
+ downsample = None
+ if stride != 1 or self.inplanes != planes * block.expansion:
+ downsample = nn.Sequential(
+ nn.AvgPool2d(kernel_size=stride,
+ stride=stride,
+ ceil_mode=True,
+ count_include_pad=False),
+ nn.Conv2d(self.inplanes,
+ planes * block.expansion,
+ kernel_size=1,
+ stride=1,
+ bias=False),
+ nn.BatchNorm2d(planes * block.expansion),
+ )
+
+ layers = []
+ layers.append(
+ block(self.inplanes,
+ planes,
+ stride,
+ downsample=downsample,
+ stype='stage',
+ baseWidth=self.baseWidth,
+ scale=self.scale))
+ self.inplanes = planes * block.expansion
+ for i in range(1, blocks):
+ layers.append(
+ block(self.inplanes,
+ planes,
+ baseWidth=self.baseWidth,
+ scale=self.scale))
+
+ return nn.Sequential(*layers)
+
+ def _forward(self, x):
+ x = x.unsqueeze(dim=1)
+ x = self.conv1(x)
+ x = self.bn1(x)
+ x = self.relu(x)
+ x = self.layer1(x)
+ x = self.layer2(x)
+ x = self.layer3(x)
+ x = self.layer4(x)
+ x = self.avgpool(x)
+ x = torch.flatten(x, 1)
+ x = self.cls_layer(x)
+
+ return F.log_softmax(x, dim=-1)
+
+ def extract(self, x):
+ x = self.conv1(x)
+ x = self.bn1(x)
+ x = self.relu(x)
+ x = self.layer1(x)
+ x = self.layer2(x)
+ x = self.layer3(x)
+ x = self.layer4(x)
+ x = self.avgpool(x)
+ x = torch.flatten(x, 1)
+ return x
+ # Allow for accessing forward method in a inherited class
+ forward = _forward
+
+def se_res2net50_v1b_14w_8s(**kwargs):
+ """Constructs a Res2Net-50_v1b model.
+ Res2Net-50 refers to the Res2Net-50_v1b_26w_4s.
+ """
+ model = Res2Net(SEBottle2neck, [3, 4, 6, 3], baseWidth=14, scale=8, **kwargs)
+ return model
+
+
+class CONV(nn.Module):
+ @staticmethod
+ def to_mel(hz):
+ return 2595 * np.log10(1 + hz / 700)
+
+ @staticmethod
+ def to_hz(mel):
+ return 700 * (10**(mel / 2595) - 1)
+
+ def __init__(self,
+ out_channels,
+ kernel_size,
+ sample_rate=16000,
+ in_channels=1,
+ stride=1,
+ padding=0,
+ dilation=1,
+ bias=False,
+ groups=1,
+ mask=False):
+ super().__init__()
+ if in_channels != 1:
+
+ msg = "SincConv only support one input channel (here, in_channels = {%i})" % (
+ in_channels)
+ raise ValueError(msg)
+ self.out_channels = out_channels
+ self.kernel_size = kernel_size
+ self.sample_rate = sample_rate
+
+ # Forcing the filters to be odd (i.e, perfectly symmetrics)
+ if kernel_size % 2 == 0:
+ self.kernel_size = self.kernel_size + 1
+ self.stride = stride
+ self.padding = padding
+ self.dilation = dilation
+ self.mask = mask
+ if bias:
+ raise ValueError('SincConv does not support bias.')
+ if groups > 1:
+ raise ValueError('SincConv does not support groups.')
+
+ NFFT = 512
+ f = int(self.sample_rate / 2) * np.linspace(0, 1, int(NFFT / 2) + 1)
+ fmel = self.to_mel(f)
+ fmelmax = np.max(fmel)
+ fmelmin = np.min(fmel)
+ filbandwidthsmel = np.linspace(fmelmin, fmelmax, self.out_channels + 1)
+ filbandwidthsf = self.to_hz(filbandwidthsmel)
+
+ self.mel = filbandwidthsf
+ self.hsupp = torch.arange(-(self.kernel_size - 1) / 2,
+ (self.kernel_size - 1) / 2 + 1)
+ self.band_pass = torch.zeros(self.out_channels, self.kernel_size)
+ for i in range(len(self.mel) - 1):
+ fmin = self.mel[i]
+ fmax = self.mel[i + 1]
+ hHigh = (2*fmax/self.sample_rate) * \
+ np.sinc(2*fmax*self.hsupp/self.sample_rate)
+ hLow = (2*fmin/self.sample_rate) * \
+ np.sinc(2*fmin*self.hsupp/self.sample_rate)
+ hideal = hHigh - hLow
+
+ self.band_pass[i, :] = Tensor(np.hamming(
+ self.kernel_size)) * Tensor(hideal)
+
+ def forward(self, x, mask=False):
+ band_pass_filter = self.band_pass.clone().to(x.device)
+ if mask:
+ A = np.random.uniform(0, 20)
+ A = int(A)
+ A0 = random.randint(0, band_pass_filter.shape[0] - A)
+ band_pass_filter[A0:A0 + A, :] = 0
+ else:
+ band_pass_filter = band_pass_filter
+
+ self.filters = (band_pass_filter).view(self.out_channels, 1,
+ self.kernel_size)
+
+ return F.conv1d(x,
+ self.filters,
+ stride=self.stride,
+ padding=self.padding,
+ dilation=self.dilation,
+ bias=None,
+ groups=1)
+
+
+class My_Residual_block(nn.Module):
+ def __init__(self, nb_filts, first=False, conv1=[2, 3, 1, 1, 1, 1], conv2=[2, 3, 0, 1, 1, 3], conv3=[1, 3, 0, 1, 1, 3], pool=(1, 3)):
+ super().__init__()
+ self.first = first
+
+ if not self.first:
+ self.bn1 = nn.BatchNorm2d(num_features=nb_filts[0])
+ self.conv1 = nn.Conv2d(in_channels=nb_filts[0],
+ out_channels=nb_filts[1],
+ kernel_size=(conv1[0], conv1[1]),
+ padding=(conv1[2], conv1[3]),
+ stride=(conv1[4], conv1[5]))
+ self.selu = nn.SELU(inplace=True)
+
+ self.bn2 = nn.BatchNorm2d(num_features=nb_filts[1])
+ self.conv2 = nn.Conv2d(in_channels=nb_filts[1],
+ out_channels=nb_filts[1],
+ kernel_size=(conv2[0], conv2[1]),
+ padding=(conv2[2], conv2[3]),
+ stride=(conv2[4], conv2[5]))
+
+ self.downsample = True
+ self.conv_downsample = nn.Conv2d(in_channels=nb_filts[0],
+ out_channels=nb_filts[1],
+ kernel_size=(conv3[0], conv3[1]),
+ padding=(conv3[2], conv3[3]),
+ stride=(conv3[4], conv3[5]))
+
+ # self.mp = nn.MaxPool2d((1,4))
+ self.mp = nn.MaxPool2d((pool[0], pool[1]))
+
+ def forward(self, x):
+ identity = x
+ if not self.first:
+ out = self.bn1(x)
+ out = self.selu(out)
+ else:
+ out = x
+ out = self.conv1(x)
+
+ out = self.bn2(out)
+ out = self.selu(out)
+ out = self.conv2(out)
+
+ if self.downsample:
+ identity = self.conv_downsample(identity)
+
+ out += identity
+ out = self.mp(out)
+ return out
+
+
+class My_SERes2Net_block(nn.Module):
+ def __init__(self, nb_filts, first=False, conv1=[2, 3, 1, 1, 1, 1], conv2=[3, 3, 1, 1, 1, 3], conv3=[1, 3, 0, 1, 1, 3], pool=(1, 3), radix=2, groups=2):
+ super().__init__()
+ self.first = first
+
+ if not self.first:
+ self.bn1 = nn.BatchNorm2d(num_features=nb_filts[0])
+
+ self.conv1 = SEBottle2neck(inplanes=nb_filts[0],
+ planes=nb_filts[1], kernel_size=(conv1[0], conv1[1]))
+ self.selu = nn.SELU(inplace=True)
+
+ self.bn2 = nn.BatchNorm2d(num_features=nb_filts[1])
+ self.conv2 = nn.Conv2d(in_channels=nb_filts[1],
+ out_channels=nb_filts[1],
+ kernel_size=(conv2[0], conv2[1]),
+ padding=(conv2[2], conv2[3]),
+ stride=(conv2[4], conv2[5]))
+
+ self.downsample = True
+ self.conv_downsample = nn.Conv2d(in_channels=nb_filts[0],
+ out_channels=nb_filts[1],
+ kernel_size=(conv3[0], conv3[1]),
+ padding=(conv3[2], conv3[3]),
+ stride=(conv3[4], conv3[5]))
+
+ self.mp = nn.MaxPool2d((pool[0], pool[1]))
+
+ def forward(self, x):
+ identity = x
+ if not self.first:
+ out = self.bn1(x)
+ out = self.selu(out)
+ else:
+ out = x
+
+ out = self.conv1(x)
+ out = self.bn2(out)
+ out = self.selu(out)
+ out = self.conv2(out)
+ if self.downsample:
+ identity = self.conv_downsample(identity)
+
+ out += identity
+ out = self.mp(out)
+ return out
+
+
+class Attention(Module):
+ """
+ Obtained from timm: github.com:rwightman/pytorch-image-models
+ """
+
+ def __init__(self, dim, num_heads=8, attention_dropout=0.1, projection_dropout=0.1):
+ super().__init__()
+ self.num_heads = num_heads
+ head_dim = dim // self.num_heads
+ self.scale = head_dim ** -0.5
+
+ self.qkv = Linear(dim, dim * 3, bias=False)
+ self.attn_drop = Dropout(attention_dropout)
+ self.proj = Linear(dim, dim)
+ self.proj_drop = Dropout(projection_dropout)
+
+ def forward(self, x):
+ B, N, C = x.shape
+ qkv = self.qkv(x).reshape(B, N, 3, self.num_heads, C //
+ self.num_heads).permute(2, 0, 3, 1, 4)
+ q, k, v = qkv[0], qkv[1], qkv[2]
+
+ attn = (q @ k.transpose(-2, -1)) * self.scale
+ attn = attn.softmax(dim=-1)
+ attn = self.attn_drop(attn)
+
+ x = (attn @ v).transpose(1, 2).reshape(B, N, C)
+ x = self.proj(x)
+ x = self.proj_drop(x)
+ return x
+
+
+class SimpleRelativeAttention(nn.Module):
+ # we implement this relative position embedding here., this is not used in our experiments
+ def __init__(self, dim, seq_length, num_heads=8, qkv_bias=True, qk_scale=None, attn_drop=0.1, proj_drop=0.1):
+ super().__init__()
+ self.dim = dim
+ self.length = seq_length
+ self.num_heads = num_heads
+ head_dim = dim//num_heads
+ self.scale = qk_scale or head_dim**-0.5
+ self.relative_position_table = nn.Parameter(
+ torch.zeros(size=(seq_length*2-1, num_heads)))
+ coords = torch.arange(seq_length)
+ relative_coords = coords[:, None]-coords[None, :]
+ relative_coords = relative_coords+seq_length-1
+ self.register_buffer('relative_index', relative_coords)
+ self.qkv = nn.Linear(dim, dim*3)
+ self.attn_drop = nn.Dropout(attn_drop)
+ self.proj = nn.Linear(dim, dim)
+ self.proj_drop = nn.Dropout(proj_drop)
+
+ trunc_normal_(self.relative_position_table, std=0.02)
+
+ def forward(self, x):
+ B, N, C = x.shape
+ qkv = self.qkv(x).reshape(B, N, 3, self.num_heads, C //
+ self.num_heads).permute(2, 0, 3, 1, 4)
+ q, k, v = qkv[0], qkv[1], qkv[2]
+ q = q*self.scale
+ attn = torch.einsum('bhqe,bhke->bhqk', q, k)
+ relative_position_bias = self.relative_position_table[self.relative_index.reshape(-1)].reshape(
+ self.length, self.length, self.num_heads
+ )
+ relative_position_bias = relative_position_bias.permute(
+ 2, 0, 1).contiguous()
+ attn = attn+relative_position_bias.unsqueeze(0)
+ attn = attn.softmax(-1)
+ attn = self.attn_drop(attn)
+ x = torch.einsum('bnqk,bnqe->bnqe', attn,
+ v).transpose(1, 2).reshape(B, N, C)
+ x = self.proj_drop(self.proj(x))
+ return x
+
+
+class TransformerEncoderLayer(Module):
+ """
+ Inspired by torch.nn.TransformerEncoderLayer and timm.
+ """
+
+ def __init__(self, d_model, nhead, atten=Attention, dim_feedforward=2048, dropout=0.1,
+ attention_dropout=0.1, drop_path_rate=0.1):
+ super(TransformerEncoderLayer, self).__init__()
+ self.pre_norm = LayerNorm(d_model)
+ self.self_attn = atten(dim=d_model, num_heads=nhead,
+ attention_dropout=attention_dropout, projection_dropout=dropout)
+
+ self.linear1 = Linear(d_model, dim_feedforward)
+ self.dropout1 = Dropout(dropout)
+ self.norm1 = LayerNorm(d_model)
+ self.linear2 = Linear(dim_feedforward, d_model)
+ self.dropout2 = Dropout(dropout)
+
+ self.drop_path = DropPath(
+ drop_path_rate) if drop_path_rate > 0 else Identity()
+
+ self.activation = F.gelu
+
+ def forward(self, src: torch.Tensor, *args, **kwargs) -> torch.Tensor:
+ src = src + self.drop_path(self.self_attn(self.pre_norm(src)))
+ src = self.norm1(src)
+ src2 = self.linear2(self.dropout1(self.activation(self.linear1(src))))
+ src = src + self.drop_path(self.dropout2(src2))
+ return src
+
+
+class TransformerClassifier(Module):
+ """
+ Adopted from https://github.com/SHI-Labs/Compact-Transformers.git
+ """
+
+ def __init__(self,
+ embedding_dim=768,
+ num_classes=1000,
+ num_layers=12,
+ num_heads=12,
+ mlp_ratio=4.0,
+ dropout_rate=0.1,
+ attention_dropout=0.1,
+ stochastic_depth_rate=0.1,
+ positional_embedding='sine',
+ sequence_length=10000,
+ *args, **kwargs):
+ super().__init__()
+ positional_embedding = positional_embedding if \
+ positional_embedding in ['sine', 'learnable', 'none'] else 'sine'
+ dim_feedforward = int(embedding_dim * mlp_ratio)
+ self.embedding_dim = embedding_dim
+ self.sequence_length = sequence_length
+
+ assert sequence_length is not None or positional_embedding == 'none'
+
+ if positional_embedding != 'none':
+ if positional_embedding == 'learnable':
+ self.positional_emb = Parameter(torch.zeros(1, sequence_length, embedding_dim),
+ requires_grad=True)
+ init.trunc_normal_(self.positional_emb, std=0.2)
+ else:
+ print('here!!! sinusoidal_embedding')
+ self.positional_emb = Parameter(self.sinusoidal_embedding(sequence_length, embedding_dim),
+ requires_grad=False)
+ else:
+ self.positional_emb = None
+
+ self.dropout = Dropout(p=dropout_rate)
+ dpr = [x.item() for x in torch.linspace(
+ 0, stochastic_depth_rate, num_layers)]
+ self.blocks = ModuleList([
+ TransformerEncoderLayer(d_model=embedding_dim, nhead=num_heads,
+ dim_feedforward=dim_feedforward, dropout=dropout_rate,
+ attention_dropout=attention_dropout, drop_path_rate=dpr[i])
+ for i in range(num_layers)])
+ self.norm = LayerNorm(embedding_dim)
+ self.flattener = nn.Flatten(2, 3)
+ self.attention_pool = Linear(self.embedding_dim, 1)
+ self.fc = Linear(embedding_dim, num_classes)
+ self.apply(self.init_weight)
+
+ def forward(self, x):
+ x = torch.transpose(x,-1,-2)
+ seq_len = x.size(1)
+ x += self.positional_emb[:, :seq_len, :]
+
+ x = self.dropout(x)
+ for blk in self.blocks:
+ x = blk(x)
+ x = self.norm(x)
+
+ feature = torch.matmul(F.softmax(self.attention_pool(
+ x), dim=1).transpose(-1, -2), x).squeeze(-2)
+ logits = self.fc(feature)
+
+ return logits, feature
+
+
+ @staticmethod
+ def init_weight(m):
+ if isinstance(m, Linear):
+ init.trunc_normal_(m.weight, std=.02)
+ if isinstance(m, Linear) and m.bias is not None:
+ init.constant_(m.bias, 0)
+ elif isinstance(m, LayerNorm):
+ init.constant_(m.bias, 0)
+ init.constant_(m.weight, 1.0)
+
+ @staticmethod
+ def sinusoidal_embedding(n_channels, dim):
+ pe = torch.FloatTensor([[p / (10000 ** (2 * (i // 2) / dim)) for i in range(dim)]
+ for p in range(n_channels)])
+ pe[:, 0::2] = torch.sin(pe[:, 0::2])
+ pe[:, 1::2] = torch.cos(pe[:, 1::2])
+ return pe.unsqueeze(0)
+
+class SE_Rawformer_front(nn.Module):
+ def __init__(self, conv1 = [2,3,1,1,1,1],conv2 = [3,3,1,1,1,2],conv3 = [1,3,0,1,1,2]):
+ super().__init__()
+ filts = [70, [1, 32], [32, 32], [32, 64], [64, 64]]
+ self.conv_time = CONV(out_channels=filts[0],
+ kernel_size=128,
+ in_channels=1) # 70 129
+ self.first_bn = nn.BatchNorm2d(num_features=1)
+ self.drop = nn.Dropout(0.5, inplace=True)
+ self.drop_way = nn.Dropout(0.2, inplace=True)
+ self.selu = nn.SELU(inplace=True)
+
+ self.encoder = nn.Sequential(
+ nn.Sequential(My_Residual_block(nb_filts=filts[1], conv1 = conv1,conv2 = [2,3,0,1,1,2],conv3 = conv3,first=True)),
+ nn.Sequential(My_SERes2Net_block(nb_filts=filts[2], conv1 = conv1,conv2 = conv2,conv3 = conv3)),
+ nn.Sequential(My_SERes2Net_block(nb_filts=filts[3], conv1 = conv1,conv2 = conv2,conv3 = conv3)),
+ nn.Sequential(My_SERes2Net_block(nb_filts=filts[4], conv1 = conv1,conv2 = conv2,conv3 = conv3)))
+
+ def forward(self, x, Freq_aug=False):
+ x = self.conv_time(x, mask=Freq_aug)
+ x = x.unsqueeze(dim=1)
+ x = F.max_pool2d(torch.abs(x), (3, 3))
+ x = self.first_bn(x)
+ x = self.selu(x)
+
+ encoder = self.encoder(x)
+ return encoder
+
+
+class SafeEar(nn.Module):
+ def __init__(self,front, *args, **kwargs):
+ super().__init__()
+ # self.front = front
+ self.bottleneck = nn.Sequential(
+ nn.Conv1d(kwargs["embedding_dim"]*7, kwargs["embedding_dim"], kernel_size=1),
+ nn.BatchNorm1d(kwargs["embedding_dim"])
+ )
+ self.classifier = TransformerClassifier(*args, **kwargs)
+
+ def forward(self, encoder):
+ encoder = self.bottleneck(torch.cat(encoder, dim=1))
+ batch_size, feature_dim, frame_num = encoder.size()
+
+ for i in range(0, frame_num, 50):
+ encoder[:, :, i:i+50] = torch.flip(encoder[:, :, i:i+50], dims=[2])
+
+ logits, feature = self.classifier(encoder)
+
+ return logits, feature
+
+
+class SafeEar1s(nn.Module):
+ def __init__(self,front, *args, **kwargs):
+ super().__init__()
+ # self.front = front
+ self.bottleneck = nn.Sequential(
+ nn.Conv1d(kwargs["embedding_dim"]*7, kwargs["embedding_dim"], kernel_size=1),
+ nn.BatchNorm1d(kwargs["embedding_dim"])
+ )
+ self.classifier = TransformerClassifier(*args, **kwargs)
+
+ def forward(self, encoder):
+ encoder = self.bottleneck(torch.cat(encoder, dim=1))
+
+ batch_size, feature_dim, frame_num = encoder.size()
+ for i in range(0, frame_num, 50):
+ end = i+50 if i+50 <= frame_num else frame_num
+ indices = torch.randperm(end - i)
+ encoder[:, :, i:end] = encoder[:, :, i+indices]
+
+ logits, feature = self.classifier(encoder)
+
+ return logits, feature
diff --git a/clean/audio/safeear/safeear/trainer/safeear_trainer.py b/clean/audio/safeear/safeear/trainer/safeear_trainer.py
new file mode 100644
index 0000000000000000000000000000000000000000..7ad0dd55b95549b4f4b74c0ab9a142e0daf29c12
--- /dev/null
+++ b/clean/audio/safeear/safeear/trainer/safeear_trainer.py
@@ -0,0 +1,189 @@
+import math
+import torch
+import pytorch_lightning as pl
+from ..losses.loss import compute_eer
+import numpy as np
+import warnings
+warnings.filterwarnings("ignore")
+
+def get_input(x):
+ x = x.to(memory_format=torch.contiguous_format)
+ return x.float()
+
+class SafeEarTrainer(pl.LightningModule):
+ def __init__(
+ self,
+ decouple_model,
+ detect_model,
+ lr_raw_former,
+ save_score_path
+ ) -> None:
+ super().__init__()
+
+ self.decouple_model = decouple_model
+ self.detect_model = detect_model
+ self.lr_raw_former = lr_raw_former
+ self.save_score_path = save_score_path
+
+ self.detect_loss = torch.nn.BCELoss()
+
+ self.automatic_optimization = False
+
+ self.val_index_loader = []
+ self.val_score_loader = []
+ self.eval_index_loader = []
+ self.eval_score_loader = []
+ self.eval_filename_loader = []
+ self.default_monitor = "val_eer"
+
+ def forward(self, batch, is_train=True):
+ if is_train:
+ x, feat, target = batch
+ else:
+ if len(batch) == 4:
+ x, feat, target, audio_path = batch
+ else:
+ x, feat, target = batch
+ audio_path = None
+ x_wav = get_input(x)
+ with torch.no_grad():
+ self.decouple_model.eval()
+ G_x, commit_loss, last_layer, acoustic_tokens = self.decouple_model(x_wav, layers=[0,1,2,3,4,5,6,7])
+ raw_logits, raw_feature = self.detect_model(acoustic_tokens)
+
+ if is_train:
+ onehot_target = torch.eye(2).to(self.device)[target, :]
+ raw_logits = torch.softmax(raw_logits, dim=-1)
+ raw_former_loss_ = self.detect_loss(raw_logits,onehot_target)
+ return raw_former_loss_, raw_logits, target
+ else:
+ raw_logits = torch.softmax(raw_logits, dim=-1)[:, 0]
+ raw_former_loss_ = 0
+ return audio_path, raw_former_loss_, raw_logits, target
+
+ def training_step(self, batch, batch_idx):
+ raw_opt = self.optimizers()
+
+ raw_former_loss_, raw_logits, target = self(batch, is_train=True)
+ raw_opt.zero_grad()
+ self.manual_backward(raw_former_loss_)
+ raw_opt.step()
+
+ self.log_dict(
+ {
+ 'train_loss': raw_former_loss_
+ },
+ on_step=True,
+ on_epoch=True,
+ prog_bar=True,
+ sync_dist=True,
+ logger=True)
+
+ def validation_step(self, batch, batch_idx):
+ _, raw_former_loss_, raw_logits, target = self(batch, is_train=False)
+
+ self.val_index_loader.append(target)
+ self.val_score_loader.append(raw_logits)
+
+ self.log_dict(
+ {
+ 'val_loss': raw_former_loss_,
+ },
+ on_epoch=True,
+ prog_bar=True,
+ sync_dist=True,
+ logger=True)
+
+ def on_validation_epoch_end(self):
+ all_index = self.all_gather(torch.cat(self.val_index_loader, dim=0)).view(-1).cpu().numpy()
+ all_score = self.all_gather(torch.cat(self.val_score_loader, dim=0)).view(-1).cpu().numpy()
+ val_eer = compute_eer(all_score[all_index == 0], all_score[all_index == 1])[0]
+ other_val_eer = compute_eer(-all_score[all_index == 0], -all_score[all_index == 1])[0]
+ val_eer = min(val_eer, other_val_eer)
+ self.log_dict(
+ {
+ "val_eer": val_eer,
+ },
+ sync_dist=True,
+ on_epoch=True,
+ prog_bar=True,
+ logger=True)
+
+ self.val_index_loader.clear() # free memory
+ self.val_score_loader.clear() # free memory
+
+ self.log_dict(
+ {
+ "lr": self.optimizers().param_groups[0]['lr'],
+ },
+ sync_dist=True,
+ on_epoch=True,
+ prog_bar=False,
+ logger=True
+ )
+
+ adjust_learning_rate(self.optimizers(), self.current_epoch, self.lr_raw_former, self.trainer.max_epochs*0.1, self.trainer.max_epochs)
+
+ def test_step(self, batch, batch_idx):
+
+ audio_path, raw_former_loss_, raw_logits, target = self(batch, is_train=False)
+
+ self.eval_index_loader.append(target)
+ self.eval_score_loader.append(raw_logits)
+ self.eval_filename_loader.append(audio_path)
+ self.log_dict(
+ {
+ 'val_loss_rawformer': raw_former_loss_,
+ },
+ on_epoch=True,
+ prog_bar=True,
+ sync_dist=True,
+ logger=True)
+
+ def on_test_epoch_end(self):
+
+ string_list = [list(item) for item in self.eval_filename_loader]
+
+ all_filename = np.array(string_list)
+ all_filename = all_filename.reshape(-1, 1)
+
+
+ all_index = self.all_gather(torch.cat(self.eval_index_loader, dim=0)).view(-1).cpu().numpy()
+ all_score = self.all_gather(torch.cat(self.eval_score_loader, dim=0)).view(-1).cpu().numpy()
+
+ # gpu_id = torch.cuda.current_device()
+
+ data_to_write = zip(all_filename, all_score,all_index)
+ csv_filename = self.save_score_path + '/score.csv'
+ eval_eer = compute_eer(all_score[all_index == 0], all_score[all_index == 1])[0]
+ other_eval_eer = compute_eer(-all_score[all_index == 0], -all_score[all_index == 1])[0]
+ eval_eer = min(eval_eer, other_eval_eer)
+
+ self.log_dict(
+ {
+ "test_eer": eval_eer,
+ },
+ sync_dist=True,
+ on_epoch=True,
+ prog_bar=True,
+ logger=True)
+
+ self.eval_index_loader.clear() # free memory
+ self.eval_score_loader.clear() # free memory
+ self.eval_filename_loader.clear() # free memory
+
+ def configure_optimizers(self):
+ optimizer_rawformer = torch.optim.AdamW(self.detect_model.parameters(), lr=self.lr_raw_former, weight_decay=1e-4)
+
+ return [optimizer_rawformer]
+
+def adjust_learning_rate(optimizer, epoch, lr, warmup, epochs=100):
+ lr = lr
+ if epoch < warmup:
+ lr = lr / (warmup - epoch)
+ else:
+ lr *= 0.5 * (1. + math.cos(math.pi *
+ (epoch - warmup) / (epochs - warmup)))
+
+ for param_group in optimizer.param_groups:
+ param_group['lr'] = lr
\ No newline at end of file
diff --git a/clean/audio/safeear/safeear/utils/dump_hubert_feature.py b/clean/audio/safeear/safeear/utils/dump_hubert_feature.py
new file mode 100644
index 0000000000000000000000000000000000000000..aac544bba2644e2fcb0bb1d046f38fd390a2a86a
--- /dev/null
+++ b/clean/audio/safeear/safeear/utils/dump_hubert_feature.py
@@ -0,0 +1,108 @@
+# Copyright (c) Facebook, Inc. and its affiliates.
+#
+# This source code is licensed under the MIT license found in the
+# LICENSE file in the root directory of this source tree.
+
+import logging
+import os
+import sys
+import tqdm
+sys.path.append('../../fairseq_ours/') # we recommend an abosulte path here.
+import fairseq
+import soundfile as sf
+import torch
+import torch.nn.functional as F
+from npy_append_array import NpyAppendArray
+from pathlib import Path
+# from feature_utils import get_path_iterator, dump_feature
+
+
+logging.basicConfig(
+ format="%(asctime)s | %(levelname)s | %(name)s | %(message)s",
+ datefmt="%Y-%m-%d %H:%M:%S",
+ level=os.environ.get("LOGLEVEL", "INFO").upper(),
+ stream=sys.stdout,
+)
+logger = logging.getLogger("dump_hubert_feature")
+
+
+class HubertFeatureReader(object):
+ def __init__(self, ckpt_path, layer, max_chunk=1600000):
+ (
+ model,
+ cfg,
+ task,
+ ) = fairseq.checkpoint_utils.load_model_ensemble_and_task([ckpt_path])
+ self.model = model[0].eval().cuda()
+ self.task = task
+ self.layer = layer
+ self.max_chunk = max_chunk
+ logger.info(f"TASK CONFIG:\n{self.task.cfg}")
+ logger.info(f" max_chunk = {self.max_chunk}")
+
+ def read_audio(self, path, ref_len=None):
+ wav, sr = sf.read(path)
+ assert sr == self.task.cfg.sample_rate, sr
+ if wav.ndim == 2:
+ wav = wav.mean(-1)
+ assert wav.ndim == 1, wav.ndim
+ if ref_len is not None and abs(ref_len - len(wav)) > 160:
+ logging.warning(f"ref {ref_len} != read {len(wav)} ({path})")
+ return wav
+
+ def get_feats(self, path, ref_len=None):
+ x = self.read_audio(path, ref_len)
+ with torch.no_grad():
+ x = torch.from_numpy(x).float().cuda()
+ if self.task.cfg.normalize:
+ x = F.layer_norm(x, x.shape)
+ x = x.view(1, -1)
+
+ feat = []
+ for start in range(0, x.size(1), self.max_chunk):
+ x_chunk = x[:, start: start + self.max_chunk]
+ feat_chunk, _, _ = self.model.extract_features(
+ source=x_chunk,
+ padding_mask=None,
+ mask=False,
+ output_layer=self.layer,
+ )
+ feat.append(feat_chunk)
+ return torch.cat(feat, 1).squeeze(0)
+
+def dump_feature(reader,audio_dir,save_dir):
+ save_dir = Path(save_dir)
+ audio_dir = Path(audio_dir)
+
+ audio_files = list(audio_dir.glob("**/*.flac"))
+
+ for audio_file in tqdm.tqdm(audio_files):
+ releative_path = audio_file.relative_to(audio_dir).with_suffix(".npy")
+ save_path = save_dir / releative_path
+ # import pdb; pdb.set_trace()
+ if not save_path.parent.exists():
+ save_path.parent.mkdir(parents=True)
+
+ feat_f = NpyAppendArray(save_path)
+ feat = reader.get_feats(audio_file)
+ feat_f.append(feat.cpu().numpy())
+ logger.info("finished successfully")
+
+def main(audio_dir, save_dir, ckpt_path, layer, max_chunk):
+ reader = HubertFeatureReader(ckpt_path, layer, max_chunk)
+ dump_feature(reader, audio_dir, save_dir)
+
+if __name__ == "__main__":
+ import argparse
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--audio_dir", default="./datasets/ASVSpoof2021/ASVspoof2021_LA_eval/flac")
+ parser.add_argument("--save_dir", default="./datasets/ASVSpoof2021/ASVspoof2021_LA_eval/Hubert_L9")
+
+ parser.add_argument("--ckpt_path", default="./model_zoo/hubert/hubert_base_ls960.pt")
+ parser.add_argument("--layer", type=int, default=9)
+ parser.add_argument("--max_chunk", type=int, default=1600000)
+ args = parser.parse_args()
+ logger.info(args)
+
+ main(**vars(args))
diff --git a/clean/audio/safeear/test.py b/clean/audio/safeear/test.py
new file mode 100644
index 0000000000000000000000000000000000000000..77bb0e4c6ea01a590ff208b6751e143aa44fdf1d
--- /dev/null
+++ b/clean/audio/safeear/test.py
@@ -0,0 +1,78 @@
+import importlib
+import json
+import os
+from typing import Any, Dict, List, Optional, Tuple
+import argparse
+import pytorch_lightning as pl
+import torch
+import hydra
+
+torch.set_float32_matmul_precision("high")
+
+from pytorch_lightning import Callback, LightningDataModule, LightningModule, Trainer
+from pytorch_lightning.strategies.ddp import DDPStrategy
+from omegaconf import DictConfig
+from omegaconf import OmegaConf
+from pytorch_lightning.utilities import rank_zero_only
+
+@rank_zero_only
+def print_only(message: str):
+ """Prints a message only on rank 0."""
+ print(message)
+
+def train(cfg: DictConfig, args) -> Tuple[Dict[str, Any], Dict[str, Any]]:
+
+ # instantiate datamodule
+ print_only(f"Instantiating datamodule <{cfg.datamodule._target_}>")
+ datamodule: LightningDataModule = hydra.utils.instantiate(cfg.datamodule)
+
+ # instantiate decouple model
+ print_only(f"Instantiating decouple model <{cfg.decouple_model._target_}>")
+ decouple_model: torch.nn.Module = hydra.utils.instantiate(cfg.decouple_model)
+ decouple_model.load_state_dict(torch.load(cfg.speechtokenizer_path))
+ # import pdb; pdb.set_trace()
+
+ # instantiate detect model
+ print(f"Instantiating detect model <{cfg.detect_model._target_}>")
+ detect_model: torch.nn.Module = hydra.utils.instantiate(cfg.detect_model)
+ # import pdb; pdb.set_trace()
+
+ # instantiate system
+ print_only(f"Instantiating system <{cfg.system._target_}>")
+ system: LightningModule = hydra.utils.instantiate(
+ cfg.system,
+ decouple_model=decouple_model,
+ detect_model=detect_model,
+ )
+
+ # instantiate trainer
+ print_only(f"Instantiating trainer <{cfg.trainer._target_}>")
+ trainer: Trainer = hydra.utils.instantiate(
+ cfg.trainer,
+ strategy=DDPStrategy(find_unused_parameters=True),
+ )
+
+ trainer.test(system, datamodule=datamodule, ckpt_path=args.ckpt_path)
+
+if __name__ == "__main__":
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "--conf_dir",
+ default="local/conf.yml",
+ help="Full path to save best validation model",
+ )
+ parser.add_argument(
+ "--ckpt_path",
+ help="Full path to save best validation model",
+ )
+
+ args = parser.parse_args()
+ cfg = OmegaConf.load(args.conf_dir)
+
+ os.makedirs(os.path.join(cfg.exp.dir, cfg.exp.name), exist_ok=True)
+ # 保存配置到新的文件
+ OmegaConf.save(cfg, os.path.join(cfg.exp.dir, cfg.exp.name, "config.yaml"))
+
+ train(cfg, args)
+
\ No newline at end of file
diff --git a/clean/audio/safeear/train.py b/clean/audio/safeear/train.py
new file mode 100644
index 0000000000000000000000000000000000000000..a71f408a76fa6d4892bf972e1975463ca4a271ee
--- /dev/null
+++ b/clean/audio/safeear/train.py
@@ -0,0 +1,102 @@
+import importlib
+import json
+import os
+import warnings
+warnings.filterwarnings("ignore")
+from typing import Any, Dict, List, Optional, Tuple
+import argparse
+import pytorch_lightning as pl
+import torch
+import hydra
+
+torch.set_float32_matmul_precision("high")
+
+from pytorch_lightning import Callback, LightningDataModule, LightningModule, Trainer
+from pytorch_lightning.strategies.ddp import DDPStrategy
+from omegaconf import DictConfig
+from omegaconf import OmegaConf
+from pytorch_lightning.utilities import rank_zero_only
+
+@rank_zero_only
+def print_only(message: str):
+ """Prints a message only on rank 0."""
+ print(message)
+
+def train(cfg: DictConfig) -> Tuple[Dict[str, Any], Dict[str, Any]]:
+
+ # instantiate datamodule
+ print_only(f"Instantiating datamodule <{cfg.datamodule._target_}>")
+ datamodule: LightningDataModule = hydra.utils.instantiate(cfg.datamodule)
+ datamodule.setup()
+
+ # instantiate decouple model
+ print_only(f"Instantiating decouple model <{cfg.decouple_model._target_}>")
+ decouple_model: torch.nn.Module = hydra.utils.instantiate(cfg.decouple_model)
+ decouple_model.load_state_dict(torch.load(cfg.speechtokenizer_path))
+ # import pdb; pdb.set_trace()
+
+ # instantiate detect model
+ print(f"Instantiating detect model <{cfg.detect_model._target_}>")
+ detect_model: torch.nn.Module = hydra.utils.instantiate(cfg.detect_model)
+ # import pdb; pdb.set_trace()
+
+ # instantiate system
+ print_only(f"Instantiating system <{cfg.system._target_}>")
+ system: LightningModule = hydra.utils.instantiate(
+ cfg.system,
+ decouple_model=decouple_model,
+ detect_model=detect_model,
+ )
+ # instantiate callbacks
+ callbacks: List[Callback] = []
+ if cfg.get("early_stopping"):
+ print_only(f"Instantiating early_stopping <{cfg.early_stopping._target_}>")
+ callbacks.append(hydra.utils.instantiate(cfg.early_stopping))
+ if cfg.get("checkpoint"):
+ print_only(f"Instantiating checkpoint <{cfg.checkpoint._target_}>")
+ checkpoint: pl.callbacks.ModelCheckpoint = hydra.utils.instantiate(cfg.checkpoint)
+ callbacks.append(checkpoint)
+
+ # instantiate logger
+ print_only(f"Instantiating logger <{cfg.logger._target_}>")
+ os.makedirs(os.path.join(cfg.exp.dir, cfg.exp.name, "logs"), exist_ok=True)
+ logger = hydra.utils.instantiate(cfg.logger)
+
+ # instantiate trainer
+ print_only(f"Instantiating trainer <{cfg.trainer._target_}>")
+ trainer: Trainer = hydra.utils.instantiate(
+ cfg.trainer,
+ callbacks=callbacks,
+ logger=logger,
+ strategy=DDPStrategy(find_unused_parameters=True),
+ )
+
+ trainer.fit(system, datamodule=datamodule)
+ print_only("Training finished!")
+ best_k = {k: v.item() for k, v in checkpoint.best_k_models.items()}
+ with open(os.path.join(cfg.exp.dir, cfg.exp.name, "best_k_models.json"), "w") as f:
+ json.dump(best_k, f, indent=0)
+
+ import wandb
+ if wandb.run:
+ print_only("Closing wandb!")
+ wandb.finish()
+
+if __name__ == "__main__":
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "--conf_dir",
+ default="local/conf.yml",
+ help="Full path to save best validation model",
+ )
+
+ args = parser.parse_args()
+ cfg = OmegaConf.load(args.conf_dir)
+
+ os.makedirs(os.path.join(cfg.exp.dir, cfg.exp.name), exist_ok=True)
+ # 保存配置到新的文件
+ OmegaConf.save(cfg, os.path.join(cfg.exp.dir, cfg.exp.name, "config.yaml"))
+
+ train(cfg)
+
diff --git a/clean/audio/shiftyspeech/.env b/clean/audio/shiftyspeech/.env
new file mode 100644
index 0000000000000000000000000000000000000000..3d3f446144d3d3463b50d3f7a6946eda40b00b51
--- /dev/null
+++ b/clean/audio/shiftyspeech/.env
@@ -0,0 +1,2 @@
+WANDB_API_KEY=""
+WANDB_PROJECT_NAME="SSL-AASIST"
\ No newline at end of file
diff --git a/clean/audio/shiftyspeech/LICENSE b/clean/audio/shiftyspeech/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..24853134ee78c4a7d7c21398fd5546193b8ffb43
--- /dev/null
+++ b/clean/audio/shiftyspeech/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2022 Hemlata
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/clean/audio/shiftyspeech/RawBoost.py b/clean/audio/shiftyspeech/RawBoost.py
new file mode 100644
index 0000000000000000000000000000000000000000..2c48cdc299024b4e1227e6392dd530edb4cda159
--- /dev/null
+++ b/clean/audio/shiftyspeech/RawBoost.py
@@ -0,0 +1,143 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+import copy
+
+import numpy as np
+from scipy import signal
+
+"""
+ Hemlata Tak, Madhu Kamble, Jose Patino, Massimiliano Todisco, Nicholas Evans.
+ RawBoost: A Raw Data Boosting and Augmentation Method applied to Automatic Speaker Verification Anti-Spoofing.
+ In Proc. ICASSP 2022, pp:6382--6386.
+"""
+
+
+def randRange(x1, x2, integer):
+ y = np.random.uniform(low=x1, high=x2, size=(1,))
+ if integer:
+ y = int(y)
+ return y
+
+
+def normWav(x, always):
+ if always:
+ x = x / np.amax(abs(x))
+ elif np.amax(abs(x)) > 1:
+ x = x / np.amax(abs(x))
+ return x
+
+
+def genNotchCoeffs(
+ nBands, minF, maxF, minBW, maxBW, minCoeff, maxCoeff, minG, maxG, fs
+):
+ b = 1
+ for i in range(0, nBands):
+ fc = randRange(minF, maxF, 0)
+ bw = randRange(minBW, maxBW, 0)
+ c = randRange(minCoeff, maxCoeff, 1)
+
+ if c / 2 == int(c / 2):
+ c = c + 1
+ f1 = fc - bw / 2
+ f2 = fc + bw / 2
+ if f1 <= 0:
+ f1 = 1 / 1000
+ if f2 >= fs / 2:
+ f2 = fs / 2 - 1 / 1000
+ b = np.convolve(
+ signal.firwin(c, [float(f1), float(f2)], window="hamming", fs=fs), b
+ )
+
+ G = randRange(minG, maxG, 0)
+ _, h = signal.freqz(b, 1, fs=fs)
+ b = pow(10, G / 20) * b / np.amax(abs(h))
+ return b
+
+
+def filterFIR(x, b):
+ N = b.shape[0] + 1
+ xpad = np.pad(x, (0, N), "constant")
+ y = signal.lfilter(b, 1, xpad)
+ y = y[int(N / 2) : int(y.shape[0] - N / 2)]
+ return y
+
+
+# Linear and non-linear convolutive noise
+def LnL_convolutive_noise(
+ x,
+ N_f,
+ nBands,
+ minF,
+ maxF,
+ minBW,
+ maxBW,
+ minCoeff,
+ maxCoeff,
+ minG,
+ maxG,
+ minBiasLinNonLin,
+ maxBiasLinNonLin,
+ fs,
+):
+ y = [0] * x.shape[0]
+ for i in range(0, N_f):
+ if i == 1:
+ minG = minG - minBiasLinNonLin
+ maxG = maxG - maxBiasLinNonLin
+ b = genNotchCoeffs(
+ nBands, minF, maxF, minBW, maxBW, minCoeff, maxCoeff, minG, maxG, fs
+ )
+ y = y + filterFIR(np.power(x, (i + 1)), b)
+ y = y - np.mean(y)
+ y = normWav(y, 0)
+ return y
+
+
+# Impulsive signal dependent noise
+def ISD_additive_noise(x, P, g_sd):
+ beta = randRange(0, P, 0)
+
+ y = copy.deepcopy(x)
+ x_len = x.shape[0]
+ n = int(x_len * (beta / 100))
+ p = np.random.permutation(x_len)[:n]
+ f_r = np.multiply(
+ ((2 * np.random.rand(p.shape[0])) - 1), ((2 * np.random.rand(p.shape[0])) - 1)
+ )
+ r = g_sd * x[p] * f_r
+ y[p] = x[p] + r
+ y = normWav(y, 0)
+ return y
+
+
+# Stationary signal independent noise
+
+
+def SSI_additive_noise(
+ x,
+ SNRmin,
+ SNRmax,
+ nBands,
+ minF,
+ maxF,
+ minBW,
+ maxBW,
+ minCoeff,
+ maxCoeff,
+ minG,
+ maxG,
+ fs,
+):
+ noise = np.random.normal(0, 1, x.shape[0])
+ b = genNotchCoeffs(
+ nBands, minF, maxF, minBW, maxBW, minCoeff, maxCoeff, minG, maxG, fs
+ )
+ noise = filterFIR(noise, b)
+ noise = normWav(noise, 1)
+ SNR = randRange(SNRmin, SNRmax, 0)
+ noise = (
+ noise / np.linalg.norm(noise, 2) * np.linalg.norm(x, 2) / 10.0 ** (0.05 * SNR)
+ )
+ x = x + noise
+ return x
diff --git a/clean/audio/shiftyspeech/SOURCE.md b/clean/audio/shiftyspeech/SOURCE.md
new file mode 100644
index 0000000000000000000000000000000000000000..8e60979b98713b0db7b17bf8221dece7cfbf191b
--- /dev/null
+++ b/clean/audio/shiftyspeech/SOURCE.md
@@ -0,0 +1,17 @@
+# Source: audio/shiftyspeech
+
+| Field | Value |
+|---|---|
+| Upstream | **UNVERIFIED** -- provenance was lost when this code was vendored |
+| Paper | not recorded |
+| Commit SHA | **not recorded** -- the vendoring step did not preserve it |
+| Mirrored on | 2026-09-15 |
+| Upstream license | LICENSE |
+
+This is a **mirror**, stripped to the files needed for inference. The full
+untouched snapshot is at `archive/audio__shiftyspeech.tar.gz`.
+
+This code is the work of its original authors and is **not** covered by the
+DeepSafe project license. If you are an author and want this removed, open an
+issue on https://github.com/deepsafehq/deepsafe-bench and it will be taken down
+within 48 hours, no questions asked.
diff --git a/clean/audio/shiftyspeech/Simplified_CM_solution.py b/clean/audio/shiftyspeech/Simplified_CM_solution.py
new file mode 100644
index 0000000000000000000000000000000000000000..cf247e1e0ab8c1781b743dbee28302c71a880301
--- /dev/null
+++ b/clean/audio/shiftyspeech/Simplified_CM_solution.py
@@ -0,0 +1,227 @@
+import math
+from collections import OrderedDict
+
+import fairseq
+import numpy as np
+import scipy.io as sio
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+from torch import Tensor
+from torch.autograd import Variable
+from torch.nn.parameter import Parameter
+from torch.utils import data
+
+___author__ = "Hemlata Tak"
+__email__ = "tak@eurecom.fr"
+
+# from losses_anti_spoofing import AMSoftmax
+
+############################
+## FOR fine-tuning SSL MODEL
+############################
+
+
+class SSLModel(nn.Module):
+ def __init__(self, device):
+ super(SSLModel, self).__init__()
+
+ cp_path = "/change_to_path_to_pre_trained_model_XLR_300M/xlsr2_300m.pt"
+ model, cfg, task = fairseq.checkpoint_utils.load_model_ensemble_and_task(
+ [cp_path]
+ )
+ self.model = model[0]
+ self.device = device
+ self.out_dim = 1024
+ return
+
+ def extract_feat(self, input_data):
+
+ # put the model to GPU if it not there
+ if (
+ next(self.model.parameters()).device != input_data.device
+ or next(self.model.parameters()).dtype != input_data.dtype
+ ):
+ self.model.to(input_data.device, dtype=input_data.dtype)
+ self.model.train()
+
+ if True:
+ # input should be in shape (batch, length)
+ if input_data.ndim == 3:
+ input_tmp = input_data[:, :, 0]
+ else:
+ input_tmp = input_data
+
+ # [batch, length, dim]
+ emb = self.model(input_tmp, mask=False, features_only=True)["x"]
+ return emb
+
+
+# ---------Graph attention simple back-end------------------------#
+"""
+ Hemlata Tak, Jee-weon Jung, Jose Patino, Madhu Kamble, Massimiliano Todisco, Nicholas Evans.
+ End-to-end spectro-temporal graph attention networks for speaker verification anti-spoofing and speech deepfake detection.
+ In Proc. Automatic Speaker Verification and Spoofing Countermeasures Challenge 2021 Interspeech 2021 satellite workshop.
+"""
+
+
+class GraphAttentionLayer(nn.Module):
+ def __init__(self, in_dim, out_dim, **kwargs):
+ super(GraphAttentionLayer, self).__init__()
+
+ # attention map
+ self.att_proj = nn.Linear(in_dim, out_dim)
+ self.att_weight = self._init_new_params(out_dim, 1)
+
+ # project
+ self.proj_with_att = nn.Linear(in_dim, out_dim)
+ self.proj_without_att = nn.Linear(in_dim, out_dim)
+
+ # batch norm
+ self.bn = nn.BatchNorm1d(out_dim)
+
+ # dropout for inputs
+ self.input_drop = nn.Dropout(p=0.2)
+
+ self.act = nn.SELU(inplace=True)
+
+ def forward(self, x):
+ """
+ x :(#bs, #node, #dim)
+ """
+ # apply input dropout
+ x = self.input_drop(x)
+
+ # derive attention map
+ att_map = self._derive_att_map(x)
+
+ # projection
+ x = self._project(x, att_map)
+
+ # apply batch norm
+ x = self._apply_BN(x)
+ x = self.act(x)
+
+ return x
+
+ def _pairwise_mul_nodes(self, x):
+ """
+ Calculates pairwise multiplication of nodes.
+ - for attention map
+ x :(#bs, #node, #dim)
+ out_shape :(#bs, #node, #node, #dim)
+ """
+
+ nb_nodes = x.size(1)
+ x = x.unsqueeze(2).expand(-1, -1, nb_nodes, -1)
+ x_mirror = x.transpose(1, 2)
+
+ return x * x_mirror
+
+ def _derive_att_map(self, x):
+ """
+ x :(#bs, #node, #dim)
+ out_shape :(#bs, #node, #node, 1)
+ """
+ att_map = self._pairwise_mul_nodes(x)
+ att_map = torch.tanh(
+ self.att_proj(att_map)
+ ) # size: (#bs, #node, #node, #dim_out)
+ att_map = torch.matmul(att_map, self.att_weight) # size: (#bs, #node, #node, 1)
+ att_map = F.softmax(att_map, dim=-2)
+
+ return att_map
+
+ def _project(self, x, att_map):
+ x1 = self.proj_with_att(torch.matmul(att_map.squeeze(-1), x))
+ x2 = self.proj_without_att(x)
+
+ return x1 + x2
+
+ def _apply_BN(self, x):
+ org_size = x.size()
+ x = x.view(-1, org_size[-1])
+ x = self.bn(x)
+ x = x.view(org_size)
+
+ return x
+
+ def _init_new_params(self, *size):
+ out = nn.Parameter(torch.FloatTensor(*size))
+ nn.init.xavier_normal_(out)
+ return out
+
+
+class GraphPool(nn.Module):
+ def __init__(self, k: float, in_dim: int, p):
+ super().__init__()
+ self.k = k
+ self.sigmoid = nn.Sigmoid()
+ self.proj = nn.Linear(in_dim, 1)
+ self.drop = nn.Dropout(p=p) if p > 0 else nn.Identity()
+ self.in_dim = in_dim
+
+ def forward(self, h):
+ Z = self.drop(h)
+ weights = self.proj(Z)
+ scores = self.sigmoid(weights)
+ new_h = self.top_k_graph(scores, h, self.k)
+
+ return new_h
+
+ def top_k_graph(self, scores, h, k):
+ """
+ args
+ =====
+ scores: attention-based weights (#bs, #node, 1)
+ h: graph data (#bs, #node, #dim)
+ k: ratio of remaining nodes, (float)
+ returns
+ =====
+ h: graph pool applied data (#bs, #node', #dim)
+ """
+ _, n_nodes, n_feat = h.size()
+ n_nodes = max(int(n_nodes * k), 1)
+ _, idx = torch.topk(scores, n_nodes, dim=1)
+ idx = idx.expand(-1, -1, n_feat)
+
+ h = h * scores
+ h = torch.gather(h, 1, idx)
+
+ return h
+
+
+class Model(nn.Module):
+ def __init__(self, d_args, device):
+ super(Model, self).__init__()
+
+ # SSL model
+ self.device = device
+ self.ssl_model = SSLModel(self.device)
+ self.LL = nn.Linear(self.ssl_model.out_dim, 128)
+ self.first_bn = nn.BatchNorm1d(num_features=128)
+ self.selu = nn.SELU(inplace=True)
+
+ # graph module layer
+ self.GAT_layer = GraphAttentionLayer(128, 64)
+ self.proj = nn.Linear(64, 1)
+ self.pool = GraphPool(0.8, 64, 0.3)
+
+ # classifier head
+ self.proj_node = nn.Linear(53, 2)
+
+ def forward(self, x_inp, Freq_aug=False):
+ # SSL wav2vec 2.0 model
+ x_ssl_feat = self.ssl_model.extract_feat(x_inp.squeeze(-1))
+ x_SSL = self.LL(x_ssl_feat) # (bs,frame_number,feat_out_dim)
+ x_SSL = x_SSL.transpose(1, 2) # (bs,feat_out_dim,frame_number)
+
+ x = F.max_pool1d(x_SSL, (3))
+ x = self.first_bn(x)
+ x = self.selu(x)
+
+ x = self.GAT_layer(x.transpose(1, 2))
+ x = self.pool(x)
+ x = self.proj(x).flatten(1)
+ output = self.proj_node(x)
+ return output
diff --git a/clean/audio/shiftyspeech/data_utils.py b/clean/audio/shiftyspeech/data_utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..5ca02a8d1d7cafdea37a291d568dd39ccf6ca3f6
--- /dev/null
+++ b/clean/audio/shiftyspeech/data_utils.py
@@ -0,0 +1,292 @@
+import os
+import random
+from random import randrange
+
+import librosa
+import numpy as np
+import torch
+import torch.nn as nn
+from RawBoost import (
+ ISD_additive_noise,
+ LnL_convolutive_noise,
+ SSI_additive_noise,
+ normWav,
+)
+from torch import Tensor
+from torch.utils.data import Dataset
+
+__author__ = "Hemlata Tak"
+__email__ = "tak@eurecom.fr"
+
+
+def genSpoof_list(dir_meta, is_train=False, is_eval=False):
+ d_meta = {}
+ file_list = []
+ with open(dir_meta, "r") as f:
+ l_meta = f.readlines()
+
+ if is_train:
+ for line in l_meta:
+ key, label = line.strip().split()
+ file_list.append(key)
+ d_meta[key] = 1 if label == "bonafide" else 0
+ return d_meta, file_list
+
+ elif is_eval:
+ for line in l_meta:
+ key, _ = line.strip().split(" ")
+ file_list.append(key)
+ return file_list
+ else:
+ for line in l_meta:
+ key, label = line.strip().split()
+ file_list.append(key)
+ d_meta[key] = 1 if label == "bonafide" else 0
+ return d_meta, file_list
+
+
+def pad(x, max_len=64600):
+ x_len = x.shape[0]
+ if x_len >= max_len:
+ return x[:max_len]
+ # need to pad
+ num_repeats = int(max_len / x_len) + 1
+ padded_x = np.tile(x, (1, num_repeats))[:, :max_len][0]
+ return padded_x
+
+
+class Dataset_ASVspoof2019_train(Dataset):
+ def __init__(self, args, metafile, algo):
+ """self.list_IDs : list of strings (each string: utt key),
+ self.labels: dictionary (key: utt key, value: label integer)"""
+
+ self.uttpath_labels = []
+ with open(metafile, "r") as f:
+ for line in f:
+ items = line.strip().split()
+ lb = 1 if items[-1] == "bonafide" else 0
+ self.uttpath_labels.append((items[0], lb))
+
+ self.algo = algo
+ self.args = args
+ self.cut = 64600 # take ~4 sec audio (64600 samples)
+
+ def __len__(self):
+ return len(self.uttpath_labels)
+
+ def __getitem__(self, index):
+ path, target = self.uttpath_labels[index]
+ X, fs = librosa.load(path, sr=16000)
+ Y = process_Rawboost_feature(X, fs, self.args, self.algo)
+ X_pad = pad(Y, self.cut)
+ x_inp = Tensor(X_pad)
+ return x_inp, target
+
+
+class Dataset_ASVspoof2021_eval(Dataset):
+ def __init__(self, list_IDs):
+ """self.list_IDs : list of strings (each string: utt key),"""
+
+ self.list_IDs = list_IDs
+ self.cut = 64600 # take ~4 sec audio (64600 samples)
+
+ def __len__(self):
+ return len(self.list_IDs)
+
+ def __getitem__(self, index):
+ utt_id = self.list_IDs[index]
+ X, fs = librosa.load(utt_id, sr=16000)
+ X_pad = pad(X, self.cut)
+ x_inp = Tensor(X_pad)
+ return x_inp, utt_id
+
+
+# --------------RawBoost data augmentation algorithms---------------------------##
+def process_Rawboost_feature(feature, sr, args, algo):
+
+ # Data process by Convolutive noise (1st algo)
+ if algo == 1:
+
+ feature = LnL_convolutive_noise(
+ feature,
+ args.N_f,
+ args.nBands,
+ args.minF,
+ args.maxF,
+ args.minBW,
+ args.maxBW,
+ args.minCoeff,
+ args.maxCoeff,
+ args.minG,
+ args.maxG,
+ args.minBiasLinNonLin,
+ args.maxBiasLinNonLin,
+ sr,
+ )
+
+ # Data process by Impulsive noise (2nd algo)
+ elif algo == 2:
+
+ feature = ISD_additive_noise(feature, args.P, args.g_sd)
+
+ # Data process by coloured additive noise (3rd algo)
+ elif algo == 3:
+
+ feature = SSI_additive_noise(
+ feature,
+ args.SNRmin,
+ args.SNRmax,
+ args.nBands,
+ args.minF,
+ args.maxF,
+ args.minBW,
+ args.maxBW,
+ args.minCoeff,
+ args.maxCoeff,
+ args.minG,
+ args.maxG,
+ sr,
+ )
+
+ # Data process by all 3 algo. together in series (1+2+3)
+ elif algo == 4:
+
+ feature = LnL_convolutive_noise(
+ feature,
+ args.N_f,
+ args.nBands,
+ args.minF,
+ args.maxF,
+ args.minBW,
+ args.maxBW,
+ args.minCoeff,
+ args.maxCoeff,
+ args.minG,
+ args.maxG,
+ args.minBiasLinNonLin,
+ args.maxBiasLinNonLin,
+ sr,
+ )
+ feature = ISD_additive_noise(feature, args.P, args.g_sd)
+ feature = SSI_additive_noise(
+ feature,
+ args.SNRmin,
+ args.SNRmax,
+ args.nBands,
+ args.minF,
+ args.maxF,
+ args.minBW,
+ args.maxBW,
+ args.minCoeff,
+ args.maxCoeff,
+ args.minG,
+ args.maxG,
+ sr,
+ )
+
+ # Data process by 1st two algo. together in series (1+2)
+ elif algo == 5:
+
+ feature = LnL_convolutive_noise(
+ feature,
+ args.N_f,
+ args.nBands,
+ args.minF,
+ args.maxF,
+ args.minBW,
+ args.maxBW,
+ args.minCoeff,
+ args.maxCoeff,
+ args.minG,
+ args.maxG,
+ args.minBiasLinNonLin,
+ args.maxBiasLinNonLin,
+ sr,
+ )
+ feature = ISD_additive_noise(feature, args.P, args.g_sd)
+
+ # Data process by 1st and 3rd algo. together in series (1+3)
+ elif algo == 6:
+
+ feature = LnL_convolutive_noise(
+ feature,
+ args.N_f,
+ args.nBands,
+ args.minF,
+ args.maxF,
+ args.minBW,
+ args.maxBW,
+ args.minCoeff,
+ args.maxCoeff,
+ args.minG,
+ args.maxG,
+ args.minBiasLinNonLin,
+ args.maxBiasLinNonLin,
+ sr,
+ )
+ feature = SSI_additive_noise(
+ feature,
+ args.SNRmin,
+ args.SNRmax,
+ args.nBands,
+ args.minF,
+ args.maxF,
+ args.minBW,
+ args.maxBW,
+ args.minCoeff,
+ args.maxCoeff,
+ args.minG,
+ args.maxG,
+ sr,
+ )
+
+ # Data process by 2nd and 3rd algo. together in series (2+3)
+ elif algo == 7:
+
+ feature = ISD_additive_noise(feature, args.P, args.g_sd)
+ feature = SSI_additive_noise(
+ feature,
+ args.SNRmin,
+ args.SNRmax,
+ args.nBands,
+ args.minF,
+ args.maxF,
+ args.minBW,
+ args.maxBW,
+ args.minCoeff,
+ args.maxCoeff,
+ args.minG,
+ args.maxG,
+ sr,
+ )
+
+ # Data process by 1st two algo. together in Parallel (1||2)
+ elif algo == 8:
+
+ feature1 = LnL_convolutive_noise(
+ feature,
+ args.N_f,
+ args.nBands,
+ args.minF,
+ args.maxF,
+ args.minBW,
+ args.maxBW,
+ args.minCoeff,
+ args.maxCoeff,
+ args.minG,
+ args.maxG,
+ args.minBiasLinNonLin,
+ args.maxBiasLinNonLin,
+ sr,
+ )
+ feature2 = ISD_additive_noise(feature, args.P, args.g_sd)
+
+ feature_para = feature1 + feature2
+ feature = normWav(feature_para, 0) # normalized resultant waveform
+
+ # original data without Rawboost processing
+ else:
+
+ feature = feature
+
+ return feature
diff --git a/clean/audio/shiftyspeech/model.py b/clean/audio/shiftyspeech/model.py
new file mode 100644
index 0000000000000000000000000000000000000000..8a84f2122255f07e858fcc9d97f643d7da3bce2d
--- /dev/null
+++ b/clean/audio/shiftyspeech/model.py
@@ -0,0 +1,603 @@
+import random
+from typing import Union
+
+import fairseq
+import numpy as np
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+from torch import Tensor
+
+___author__ = "Hemlata Tak"
+__email__ = "tak@eurecom.fr"
+
+############################
+## FOR fine-tuned SSL MODEL
+############################
+
+
+class SSLModel(nn.Module):
+ def __init__(self, device):
+ super(SSLModel, self).__init__()
+
+ cp_path = "models/xlsr2_300m.pt" # Change the pre-trained XLSR model path.
+ model, cfg, task = fairseq.checkpoint_utils.load_model_ensemble_and_task(
+ [cp_path]
+ )
+ self.model = model[0]
+ self.device = device
+ self.out_dim = 1024
+ return
+
+ def extract_feat(self, input_data):
+
+ # put the model to GPU if it not there
+ if (
+ next(self.model.parameters()).device != input_data.device
+ or next(self.model.parameters()).dtype != input_data.dtype
+ ):
+ self.model.to(input_data.device, dtype=input_data.dtype)
+ self.model.train()
+
+ if True:
+ # input should be in shape (batch, length)
+ if input_data.ndim == 3:
+ input_tmp = input_data[:, :, 0]
+ else:
+ input_tmp = input_data
+
+ # [batch, length, dim]
+ emb = self.model(input_tmp, mask=False, features_only=True)["x"]
+ return emb
+
+
+# ---------AASIST back-end------------------------#
+""" Jee-weon Jung, Hee-Soo Heo, Hemlata Tak, Hye-jin Shim, Joon Son Chung, Bong-Jin Lee, Ha-Jin Yu and Nicholas Evans.
+ AASIST: Audio Anti-Spoofing Using Integrated Spectro-Temporal Graph Attention Networks.
+ In Proc. ICASSP 2022, pp: 6367--6371."""
+
+
+class GraphAttentionLayer(nn.Module):
+ def __init__(self, in_dim, out_dim, **kwargs):
+ super().__init__()
+
+ # attention map
+ self.att_proj = nn.Linear(in_dim, out_dim)
+ self.att_weight = self._init_new_params(out_dim, 1)
+
+ # project
+ self.proj_with_att = nn.Linear(in_dim, out_dim)
+ self.proj_without_att = nn.Linear(in_dim, out_dim)
+
+ # batch norm
+ self.bn = nn.BatchNorm1d(out_dim)
+
+ # dropout for inputs
+ self.input_drop = nn.Dropout(p=0.2)
+
+ # activate
+ self.act = nn.SELU(inplace=True)
+
+ # temperature
+ self.temp = 1.0
+ if "temperature" in kwargs:
+ self.temp = kwargs["temperature"]
+
+ def forward(self, x):
+ """
+ x :(#bs, #node, #dim)
+ """
+ # apply input dropout
+ x = self.input_drop(x)
+
+ # derive attention map
+ att_map = self._derive_att_map(x)
+
+ # projection
+ x = self._project(x, att_map)
+
+ # apply batch norm
+ x = self._apply_BN(x)
+ x = self.act(x)
+ return x
+
+ def _pairwise_mul_nodes(self, x):
+ """
+ Calculates pairwise multiplication of nodes.
+ - for attention map
+ x :(#bs, #node, #dim)
+ out_shape :(#bs, #node, #node, #dim)
+ """
+
+ nb_nodes = x.size(1)
+ x = x.unsqueeze(2).expand(-1, -1, nb_nodes, -1)
+ x_mirror = x.transpose(1, 2)
+
+ return x * x_mirror
+
+ def _derive_att_map(self, x):
+ """
+ x :(#bs, #node, #dim)
+ out_shape :(#bs, #node, #node, 1)
+ """
+ att_map = self._pairwise_mul_nodes(x)
+ # size: (#bs, #node, #node, #dim_out)
+ att_map = torch.tanh(self.att_proj(att_map))
+ # size: (#bs, #node, #node, 1)
+ att_map = torch.matmul(att_map, self.att_weight)
+
+ # apply temperature
+ att_map = att_map / self.temp
+
+ att_map = F.softmax(att_map, dim=-2)
+
+ return att_map
+
+ def _project(self, x, att_map):
+ x1 = self.proj_with_att(torch.matmul(att_map.squeeze(-1), x))
+ x2 = self.proj_without_att(x)
+
+ return x1 + x2
+
+ def _apply_BN(self, x):
+ org_size = x.size()
+ x = x.view(-1, org_size[-1])
+ x = self.bn(x)
+ x = x.view(org_size)
+
+ return x
+
+ def _init_new_params(self, *size):
+ out = nn.Parameter(torch.FloatTensor(*size))
+ nn.init.xavier_normal_(out)
+ return out
+
+
+class HtrgGraphAttentionLayer(nn.Module):
+ def __init__(self, in_dim, out_dim, **kwargs):
+ super().__init__()
+
+ self.proj_type1 = nn.Linear(in_dim, in_dim)
+ self.proj_type2 = nn.Linear(in_dim, in_dim)
+
+ # attention map
+ self.att_proj = nn.Linear(in_dim, out_dim)
+ self.att_projM = nn.Linear(in_dim, out_dim)
+
+ self.att_weight11 = self._init_new_params(out_dim, 1)
+ self.att_weight22 = self._init_new_params(out_dim, 1)
+ self.att_weight12 = self._init_new_params(out_dim, 1)
+ self.att_weightM = self._init_new_params(out_dim, 1)
+
+ # project
+ self.proj_with_att = nn.Linear(in_dim, out_dim)
+ self.proj_without_att = nn.Linear(in_dim, out_dim)
+
+ self.proj_with_attM = nn.Linear(in_dim, out_dim)
+ self.proj_without_attM = nn.Linear(in_dim, out_dim)
+
+ # batch norm
+ self.bn = nn.BatchNorm1d(out_dim)
+
+ # dropout for inputs
+ self.input_drop = nn.Dropout(p=0.2)
+
+ # activate
+ self.act = nn.SELU(inplace=True)
+
+ # temperature
+ self.temp = 1.0
+ if "temperature" in kwargs:
+ self.temp = kwargs["temperature"]
+
+ def forward(self, x1, x2, master=None):
+ """
+ x1 :(#bs, #node, #dim)
+ x2 :(#bs, #node, #dim)
+ """
+
+ num_type1 = x1.size(1)
+ num_type2 = x2.size(1)
+
+ x1 = self.proj_type1(x1)
+
+ x2 = self.proj_type2(x2)
+
+ x = torch.cat([x1, x2], dim=1)
+
+ if master is None:
+ master = torch.mean(x, dim=1, keepdim=True)
+
+ # apply input dropout
+ x = self.input_drop(x)
+
+ # derive attention map
+ att_map = self._derive_att_map(x, num_type1, num_type2)
+
+ # directional edge for master node
+ master = self._update_master(x, master)
+
+ # projection
+ x = self._project(x, att_map)
+
+ # apply batch norm
+ x = self._apply_BN(x)
+ x = self.act(x)
+
+ x1 = x.narrow(1, 0, num_type1)
+
+ x2 = x.narrow(1, num_type1, num_type2)
+
+ return x1, x2, master
+
+ def _update_master(self, x, master):
+
+ att_map = self._derive_att_map_master(x, master)
+ master = self._project_master(x, master, att_map)
+
+ return master
+
+ def _pairwise_mul_nodes(self, x):
+ """
+ Calculates pairwise multiplication of nodes.
+ - for attention map
+ x :(#bs, #node, #dim)
+ out_shape :(#bs, #node, #node, #dim)
+ """
+
+ nb_nodes = x.size(1)
+ x = x.unsqueeze(2).expand(-1, -1, nb_nodes, -1)
+ x_mirror = x.transpose(1, 2)
+
+ return x * x_mirror
+
+ def _derive_att_map_master(self, x, master):
+ """
+ x :(#bs, #node, #dim)
+ out_shape :(#bs, #node, #node, 1)
+ """
+ att_map = x * master
+ att_map = torch.tanh(self.att_projM(att_map))
+
+ att_map = torch.matmul(att_map, self.att_weightM)
+
+ # apply temperature
+ att_map = att_map / self.temp
+
+ att_map = F.softmax(att_map, dim=-2)
+
+ return att_map
+
+ def _derive_att_map(self, x, num_type1, num_type2):
+ """
+ x :(#bs, #node, #dim)
+ out_shape :(#bs, #node, #node, 1)
+ """
+ att_map = self._pairwise_mul_nodes(x)
+ # size: (#bs, #node, #node, #dim_out)
+ att_map = torch.tanh(self.att_proj(att_map))
+ # size: (#bs, #node, #node, 1)
+
+ att_board = torch.zeros_like(att_map[:, :, :, 0]).unsqueeze(-1)
+
+ att_board[:, :num_type1, :num_type1, :] = torch.matmul(
+ att_map[:, :num_type1, :num_type1, :], self.att_weight11
+ )
+ att_board[:, num_type1:, num_type1:, :] = torch.matmul(
+ att_map[:, num_type1:, num_type1:, :], self.att_weight22
+ )
+ att_board[:, :num_type1, num_type1:, :] = torch.matmul(
+ att_map[:, :num_type1, num_type1:, :], self.att_weight12
+ )
+ att_board[:, num_type1:, :num_type1, :] = torch.matmul(
+ att_map[:, num_type1:, :num_type1, :], self.att_weight12
+ )
+
+ att_map = att_board
+
+ # apply temperature
+ att_map = att_map / self.temp
+
+ att_map = F.softmax(att_map, dim=-2)
+
+ return att_map
+
+ def _project(self, x, att_map):
+ x1 = self.proj_with_att(torch.matmul(att_map.squeeze(-1), x))
+ x2 = self.proj_without_att(x)
+
+ return x1 + x2
+
+ def _project_master(self, x, master, att_map):
+
+ x1 = self.proj_with_attM(torch.matmul(att_map.squeeze(-1).unsqueeze(1), x))
+ x2 = self.proj_without_attM(master)
+
+ return x1 + x2
+
+ def _apply_BN(self, x):
+ org_size = x.size()
+ x = x.view(-1, org_size[-1])
+ x = self.bn(x)
+ x = x.view(org_size)
+
+ return x
+
+ def _init_new_params(self, *size):
+ out = nn.Parameter(torch.FloatTensor(*size))
+ nn.init.xavier_normal_(out)
+ return out
+
+
+class GraphPool(nn.Module):
+ def __init__(self, k: float, in_dim: int, p: Union[float, int]):
+ super().__init__()
+ self.k = k
+ self.sigmoid = nn.Sigmoid()
+ self.proj = nn.Linear(in_dim, 1)
+ self.drop = nn.Dropout(p=p) if p > 0 else nn.Identity()
+ self.in_dim = in_dim
+
+ def forward(self, h):
+ Z = self.drop(h)
+ weights = self.proj(Z)
+ scores = self.sigmoid(weights)
+ new_h = self.top_k_graph(scores, h, self.k)
+
+ return new_h
+
+ def top_k_graph(self, scores, h, k):
+ """
+ args
+ =====
+ scores: attention-based weights (#bs, #node, 1)
+ h: graph data (#bs, #node, #dim)
+ k: ratio of remaining nodes, (float)
+ returns
+ =====
+ h: graph pool applied data (#bs, #node', #dim)
+ """
+ _, n_nodes, n_feat = h.size()
+ n_nodes = max(int(n_nodes * k), 1)
+ _, idx = torch.topk(scores, n_nodes, dim=1)
+ idx = idx.expand(-1, -1, n_feat)
+
+ h = h * scores
+ h = torch.gather(h, 1, idx)
+
+ return h
+
+
+class Residual_block(nn.Module):
+ def __init__(self, nb_filts, first=False):
+ super().__init__()
+ self.first = first
+
+ if not self.first:
+ self.bn1 = nn.BatchNorm2d(num_features=nb_filts[0])
+ self.conv1 = nn.Conv2d(
+ in_channels=nb_filts[0],
+ out_channels=nb_filts[1],
+ kernel_size=(2, 3),
+ padding=(1, 1),
+ stride=1,
+ )
+ self.selu = nn.SELU(inplace=True)
+
+ self.bn2 = nn.BatchNorm2d(num_features=nb_filts[1])
+ self.conv2 = nn.Conv2d(
+ in_channels=nb_filts[1],
+ out_channels=nb_filts[1],
+ kernel_size=(2, 3),
+ padding=(0, 1),
+ stride=1,
+ )
+
+ if nb_filts[0] != nb_filts[1]:
+ self.downsample = True
+ self.conv_downsample = nn.Conv2d(
+ in_channels=nb_filts[0],
+ out_channels=nb_filts[1],
+ padding=(0, 1),
+ kernel_size=(1, 3),
+ stride=1,
+ )
+
+ else:
+ self.downsample = False
+
+ def forward(self, x):
+ identity = x
+ if not self.first:
+ out = self.bn1(x)
+ out = self.selu(out)
+ else:
+ out = x
+
+ out = self.conv1(x)
+
+ out = self.bn2(out)
+ out = self.selu(out)
+
+ out = self.conv2(out)
+
+ if self.downsample:
+ identity = self.conv_downsample(identity)
+
+ out += identity
+
+ return out
+
+
+class Model(nn.Module):
+ def __init__(self, args, device):
+ super().__init__()
+ self.device = device
+
+ # AASIST parameters
+ filts = [128, [1, 32], [32, 32], [32, 64], [64, 64]]
+ gat_dims = [64, 32]
+ pool_ratios = [0.5, 0.5, 0.5, 0.5]
+ temperatures = [2.0, 2.0, 100.0, 100.0]
+
+ ####
+ # create network wav2vec 2.0
+ ####
+ self.ssl_model = SSLModel(self.device)
+ self.LL = nn.Linear(self.ssl_model.out_dim, 128)
+
+ self.first_bn = nn.BatchNorm2d(num_features=1)
+ self.first_bn1 = nn.BatchNorm2d(num_features=64)
+ self.drop = nn.Dropout(0.5, inplace=True)
+ self.drop_way = nn.Dropout(0.2, inplace=True)
+ self.selu = nn.SELU(inplace=True)
+
+ # RawNet2 encoder
+ self.encoder = nn.Sequential(
+ nn.Sequential(Residual_block(nb_filts=filts[1], first=True)),
+ nn.Sequential(Residual_block(nb_filts=filts[2])),
+ nn.Sequential(Residual_block(nb_filts=filts[3])),
+ nn.Sequential(Residual_block(nb_filts=filts[4])),
+ nn.Sequential(Residual_block(nb_filts=filts[4])),
+ nn.Sequential(Residual_block(nb_filts=filts[4])),
+ )
+
+ self.attention = nn.Sequential(
+ nn.Conv2d(64, 128, kernel_size=(1, 1)),
+ nn.SELU(inplace=True),
+ nn.BatchNorm2d(128),
+ nn.Conv2d(128, 64, kernel_size=(1, 1)),
+ )
+ # position encoding
+ self.pos_S = nn.Parameter(torch.randn(1, 42, filts[-1][-1]))
+
+ self.master1 = nn.Parameter(torch.randn(1, 1, gat_dims[0]))
+ self.master2 = nn.Parameter(torch.randn(1, 1, gat_dims[0]))
+
+ # Graph module
+ self.GAT_layer_S = GraphAttentionLayer(
+ filts[-1][-1], gat_dims[0], temperature=temperatures[0]
+ )
+ self.GAT_layer_T = GraphAttentionLayer(
+ filts[-1][-1], gat_dims[0], temperature=temperatures[1]
+ )
+ # HS-GAL layer
+ self.HtrgGAT_layer_ST11 = HtrgGraphAttentionLayer(
+ gat_dims[0], gat_dims[1], temperature=temperatures[2]
+ )
+ self.HtrgGAT_layer_ST12 = HtrgGraphAttentionLayer(
+ gat_dims[1], gat_dims[1], temperature=temperatures[2]
+ )
+ self.HtrgGAT_layer_ST21 = HtrgGraphAttentionLayer(
+ gat_dims[0], gat_dims[1], temperature=temperatures[2]
+ )
+ self.HtrgGAT_layer_ST22 = HtrgGraphAttentionLayer(
+ gat_dims[1], gat_dims[1], temperature=temperatures[2]
+ )
+
+ # Graph pooling layers
+ self.pool_S = GraphPool(pool_ratios[0], gat_dims[0], 0.3)
+ self.pool_T = GraphPool(pool_ratios[1], gat_dims[0], 0.3)
+ self.pool_hS1 = GraphPool(pool_ratios[2], gat_dims[1], 0.3)
+ self.pool_hT1 = GraphPool(pool_ratios[2], gat_dims[1], 0.3)
+
+ self.pool_hS2 = GraphPool(pool_ratios[2], gat_dims[1], 0.3)
+ self.pool_hT2 = GraphPool(pool_ratios[2], gat_dims[1], 0.3)
+
+ self.out_layer = nn.Linear(5 * gat_dims[1], 2)
+
+ def forward(self, x):
+ # -------pre-trained Wav2vec model fine tunning ------------------------##
+ x_ssl_feat = self.ssl_model.extract_feat(x.squeeze(-1))
+ x = self.LL(x_ssl_feat) # (bs,frame_number,feat_out_dim)
+
+ # post-processing on front-end features
+ x = x.transpose(1, 2) # (bs,feat_out_dim,frame_number)
+ x = x.unsqueeze(dim=1) # add channel
+ x = F.max_pool2d(x, (3, 3))
+ x = self.first_bn(x)
+ x = self.selu(x)
+
+ # RawNet2-based encoder
+ x = self.encoder(x)
+ x = self.first_bn1(x)
+ x = self.selu(x)
+
+ w = self.attention(x)
+
+ # ------------SA for spectral feature-------------#
+ w1 = F.softmax(w, dim=-1)
+ m = torch.sum(x * w1, dim=-1)
+ e_S = m.transpose(1, 2) + self.pos_S
+
+ # graph module layer
+ gat_S = self.GAT_layer_S(e_S)
+ out_S = self.pool_S(gat_S) # (#bs, #node, #dim)
+
+ # ------------SA for temporal feature-------------#
+ w2 = F.softmax(w, dim=-2)
+ m1 = torch.sum(x * w2, dim=-2)
+
+ e_T = m1.transpose(1, 2)
+
+ # graph module layer
+ gat_T = self.GAT_layer_T(e_T)
+ out_T = self.pool_T(gat_T)
+
+ # learnable master node
+ master1 = self.master1.expand(x.size(0), -1, -1)
+ master2 = self.master2.expand(x.size(0), -1, -1)
+
+ # inference 1
+ out_T1, out_S1, master1 = self.HtrgGAT_layer_ST11(
+ out_T, out_S, master=self.master1
+ )
+
+ out_S1 = self.pool_hS1(out_S1)
+ out_T1 = self.pool_hT1(out_T1)
+
+ out_T_aug, out_S_aug, master_aug = self.HtrgGAT_layer_ST12(
+ out_T1, out_S1, master=master1
+ )
+ out_T1 = out_T1 + out_T_aug
+ out_S1 = out_S1 + out_S_aug
+ master1 = master1 + master_aug
+
+ # inference 2
+ out_T2, out_S2, master2 = self.HtrgGAT_layer_ST21(
+ out_T, out_S, master=self.master2
+ )
+ out_S2 = self.pool_hS2(out_S2)
+ out_T2 = self.pool_hT2(out_T2)
+
+ out_T_aug, out_S_aug, master_aug = self.HtrgGAT_layer_ST22(
+ out_T2, out_S2, master=master2
+ )
+ out_T2 = out_T2 + out_T_aug
+ out_S2 = out_S2 + out_S_aug
+ master2 = master2 + master_aug
+
+ out_T1 = self.drop_way(out_T1)
+ out_T2 = self.drop_way(out_T2)
+ out_S1 = self.drop_way(out_S1)
+ out_S2 = self.drop_way(out_S2)
+ master1 = self.drop_way(master1)
+ master2 = self.drop_way(master2)
+
+ out_T = torch.max(out_T1, out_T2)
+ out_S = torch.max(out_S1, out_S2)
+ master = torch.max(master1, master2)
+
+ # Readout operation
+ T_max, _ = torch.max(torch.abs(out_T), dim=1)
+ T_avg = torch.mean(out_T, dim=1)
+
+ S_max, _ = torch.max(torch.abs(out_S), dim=1)
+ S_avg = torch.mean(out_S, dim=1)
+
+ last_hidden = torch.cat([T_max, T_avg, S_max, S_avg, master.squeeze(1)], dim=1)
+
+ last_hidden = self.drop(last_hidden)
+ output = self.out_layer(last_hidden)
+
+ return output
diff --git a/clean/audio/shiftyspeech/startup_config.py b/clean/audio/shiftyspeech/startup_config.py
new file mode 100644
index 0000000000000000000000000000000000000000..b482bd43721e1dcb496577a5a39bcc229d2a7af2
--- /dev/null
+++ b/clean/audio/shiftyspeech/startup_config.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+"""
+startup_config
+
+Startup configuration utilities
+
+"""
+
+from __future__ import absolute_import
+
+import importlib
+import os
+import random
+import sys
+
+import numpy as np
+import torch
+
+__author__ = "Xin Wang"
+__email__ = "wangxin@nii.ac.jp"
+__copyright__ = "Copyright 2020, Xin Wang"
+
+
+def set_random_seed(random_seed, args=None):
+ """set_random_seed(random_seed, args=None)
+
+ Set the random_seed for numpy, python, and cudnn
+
+ input
+ -----
+ random_seed: integer random seed
+ args: argue parser
+ """
+
+ # initialization
+ torch.manual_seed(random_seed)
+ random.seed(random_seed)
+ np.random.seed(random_seed)
+ os.environ["PYTHONHASHSEED"] = str(random_seed)
+
+ # For torch.backends.cudnn.deterministic
+ # Note: this default configuration may result in RuntimeError
+ # see https://pytorch.org/docs/stable/notes/randomness.html
+ if args is None:
+ cudnn_deterministic = True
+ cudnn_benchmark = False
+ else:
+ cudnn_deterministic = args.cudnn_deterministic_toggle
+ cudnn_benchmark = args.cudnn_benchmark_toggle
+
+ if not cudnn_deterministic:
+ print("cudnn_deterministic set to False")
+ if cudnn_benchmark:
+ print("cudnn_benchmark set to True")
+
+ if torch.cuda.is_available():
+ torch.cuda.manual_seed_all(random_seed)
+ torch.backends.cudnn.deterministic = cudnn_deterministic
+ torch.backends.cudnn.benchmark = cudnn_benchmark
+ return
diff --git a/clean/audio/shiftyspeech/train.py b/clean/audio/shiftyspeech/train.py
new file mode 100644
index 0000000000000000000000000000000000000000..86eeb35bb700309939f1f26952b4943003f32261
--- /dev/null
+++ b/clean/audio/shiftyspeech/train.py
@@ -0,0 +1,446 @@
+import argparse
+import os
+import sys
+
+import librosa
+import numpy as np
+import torch
+import wandb
+import yaml
+from data_utils import (
+ Dataset_ASVspoof2019_train,
+ Dataset_ASVspoof2021_eval,
+ genSpoof_list,
+ pad,
+ process_Rawboost_feature,
+)
+from dotenv import load_dotenv
+from model import Model
+from sklearn.metrics import roc_auc_score
+from startup_config import set_random_seed
+from tensorboardX import SummaryWriter
+from torch import Tensor, nn
+from torch.utils.data import DataLoader
+from tqdm import tqdm
+
+__author__ = "Hemlata Tak"
+__email__ = "tak@eurecom.fr"
+
+
+def compute_det_curve(target_scores, nontarget_scores):
+
+ n_scores = target_scores.size + nontarget_scores.size
+ all_scores = np.concatenate((target_scores, nontarget_scores))
+ labels = np.concatenate(
+ (np.ones(target_scores.size), np.zeros(nontarget_scores.size))
+ )
+
+ indices = np.argsort(all_scores, kind="mergesort")
+ labels = labels[indices]
+ tar_trial_sums = np.cumsum(labels)
+ nontarget_trial_sums = nontarget_scores.size - (
+ np.arange(1, n_scores + 1) - tar_trial_sums
+ )
+
+ frr = np.concatenate((np.atleast_1d(0), tar_trial_sums / target_scores.size))
+ far = np.concatenate(
+ (np.atleast_1d(1), nontarget_trial_sums / nontarget_scores.size)
+ )
+ # Thresholds are the sorted scores
+ thresholds = np.concatenate(
+ (np.atleast_1d(all_scores[indices[0]] - 0.001), all_scores[indices])
+ )
+
+ return frr, far, thresholds
+
+
+def compute_eer(target_scores, nontarget_scores):
+ """Returns equal error rate (EER) and the corresponding threshold."""
+ frr, far, thresholds = compute_det_curve(target_scores, nontarget_scores)
+ abs_diffs = np.abs(frr - far)
+ min_index = np.argmin(abs_diffs)
+ eer = np.mean((frr[min_index], far[min_index]))
+ return eer, thresholds[min_index], frr, far
+
+
+def calculate_tDCF_EER(cm_scores_file, output_file, printout=True):
+ # Load CM scores
+ cm_data = np.genfromtxt(cm_scores_file, dtype=str)
+ cm_utt_id = cm_data[:, 0]
+ cm_keys = cm_data[:, 1]
+ cm_scores = cm_data[:, 2].astype(float)
+ # Extract bona fide (real human) and spoof scores from the CM scores
+ bona_cm = cm_scores[cm_keys == "bonafide"]
+ spoof_cm = cm_scores[cm_keys == "spoof"]
+ all_scores = np.concatenate([bona_cm, spoof_cm])
+ all_true_labels = np.concatenate([np.ones_like(bona_cm), np.zeros_like(spoof_cm)])
+
+ auc = roc_auc_score(all_true_labels, all_scores, max_fpr=0.05)
+ eer_cm, eer_threshold, frr, far = compute_eer(bona_cm, spoof_cm)
+
+ if printout:
+ with open(output_file, "w") as f_res:
+ f_res.write("\nCM SYSTEM\n")
+ f_res.write(
+ "\tEER\t\t= {:8.9f} % "
+ "(Equal error rate for countermeasure)\n".format(eer_cm * 100)
+ )
+ f_res.write("\t pAUC with max fpr - 0.05 is :{}".format(auc))
+
+
+def evaluate_accuracy(dev_loader, model, device, args):
+ val_loss = 0.0
+ num_total = 0.0
+ algo = args.algo
+ cut = 64600
+ model.eval()
+
+ weight = torch.FloatTensor([0.1, 0.9]).to(device)
+ criterion = nn.CrossEntropyLoss(weight=weight)
+ progress_bar = tqdm(dev_loader, desc=f"Epoch {epoch+1}/{args.num_epochs}")
+ for current_step, (batch_pths, batch_y) in enumerate(progress_bar):
+ batch_x = batch_pths
+ batch_size = batch_x.size(0)
+ num_total += batch_size
+ batch_x = batch_x.to(device)
+ batch_y = batch_y.view(-1).type(torch.int64).to(device)
+ batch_out = model(batch_x)
+
+ batch_loss = criterion(batch_out, batch_y)
+ val_loss += batch_loss.item() * batch_size
+
+ val_loss /= num_total
+
+ return val_loss
+
+
+def produce_evaluation_file(dataset, model, device, save_path, trial_path):
+ data_loader = DataLoader(dataset, batch_size=10, shuffle=False, drop_last=False)
+ num_correct = 0.0
+ num_total = 0.0
+ model.eval()
+ with open(trial_path, "r") as f_trl:
+ trial_lines = f_trl.readlines()
+
+ fname_list = []
+ score_list = []
+
+ for batch_x, utt_id in data_loader:
+
+ batch_size = batch_x.size(0)
+ batch_x = batch_x.to(device)
+
+ batch_out = model(batch_x)
+
+ batch_score = (batch_out[:, 1]).data.cpu().numpy().ravel()
+ # add outputs
+ fname_list.extend(utt_id)
+ score_list.extend(batch_score.tolist())
+ assert len(trial_lines) == len(fname_list) == len(score_list)
+
+ with open(save_path, "a+") as fh:
+ for fname, cm, trl in zip(fname_list, score_list, trial_lines):
+ utt_id, key = trl.strip().split(" ")
+ assert fname == utt_id
+ fh.write("{} {} {}\n".format(fname, key, cm))
+ fh.close()
+ print("Scores saved to {}".format(save_path))
+
+
+def train_epoch(train_loader, model, lr, optim, device, args):
+ running_loss = 0
+
+ num_total = 0.0
+ algo = args.algo
+ model.train()
+ cut = 64600
+ # set objective (Loss) functions
+ weight = torch.FloatTensor([0.1, 0.9]).to(device)
+ criterion = nn.CrossEntropyLoss(weight=weight)
+ progress_bar = tqdm(train_loader, desc=f"Epoch {epoch+1}/{args.num_epochs}")
+ for current_step, (batch_pths, batch_y) in enumerate(progress_bar):
+ batch_x = batch_pths
+ batch_size = batch_x.size(0)
+ num_total += batch_size
+
+ batch_x = batch_x.to(device)
+ batch_y = batch_y.view(-1).type(torch.int64).to(device)
+ batch_out = model(batch_x)
+
+ batch_loss = criterion(batch_out, batch_y)
+
+ running_loss += batch_loss.item() * batch_size
+
+ optimizer.zero_grad()
+ batch_loss.backward()
+ optimizer.step()
+
+ running_loss /= num_total
+
+ return running_loss
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description="SSL-AASIST baseline system")
+
+ # Hyperparameters
+ parser.add_argument("--batch_size", type=int, default=64)
+ parser.add_argument("--num_epochs", type=int, default=100)
+ parser.add_argument("--lr", type=float, default=0.000001)
+ parser.add_argument("--weight_decay", type=float, default=0.0001)
+ parser.add_argument("--model_name", type=str, default="SSL-AASIST")
+ parser.add_argument("--loss", type=str, default="weighted_CCE")
+ parser.add_argument("--trn_list_path", default=None, help="path to train file")
+ parser.add_argument("--dev_list_path", default=None, help="path to validation file")
+ parser.add_argument("--test_list_path", default=None, help="path to test file")
+ parser.add_argument(
+ "--test_score_dir", default=None, help="path to save test scores"
+ )
+ # model
+ parser.add_argument(
+ "--seed", type=int, default=1234, help="random seed (default: 1234)"
+ )
+ parser.add_argument("--save_path", type=str, default=".", help="Model save path")
+ parser.add_argument("--model_path", type=str, default=None, help="Model checkpoint")
+ parser.add_argument(
+ "--comment", type=str, default=None, help="Comment to describe the saved model"
+ )
+ # Auxiliary arguments
+
+ parser.add_argument("--eval", action="store_true", default=False, help="eval mode")
+ parser.add_argument("--eval_part", type=int, default=0)
+ # backend options
+ parser.add_argument(
+ "--cudnn-deterministic-toggle",
+ action="store_false",
+ default=True,
+ help="use cudnn-deterministic? (default true)",
+ )
+
+ parser.add_argument(
+ "--cudnn-benchmark-toggle",
+ action="store_true",
+ default=False,
+ help="use cudnn-benchmark? (default false)",
+ )
+
+ ##===================================================Rawboost data augmentation ======================================================================#
+
+ parser.add_argument(
+ "--algo",
+ type=int,
+ default=5,
+ help="Rawboost algos discriptions. 0: No augmentation 1: LnL_convolutive_noise, 2: ISD_additive_noise, 3: SSI_additive_noise, 4: series algo (1+2+3), \
+ 5: series algo (1+2), 6: series algo (1+3), 7: series algo(2+3), 8: parallel algo(1,2) .[default=0]",
+ )
+
+ # LnL_convolutive_noise parameters
+ parser.add_argument(
+ "--nBands",
+ type=int,
+ default=5,
+ help="number of notch filters.The higher the number of bands, the more aggresive the distortions is.[default=5]",
+ )
+ parser.add_argument(
+ "--minF",
+ type=int,
+ default=20,
+ help="minimum centre frequency [Hz] of notch filter.[default=20] ",
+ )
+ parser.add_argument(
+ "--maxF",
+ type=int,
+ default=8000,
+ help="maximum centre frequency [Hz] (
+
+A Sanity Check for AI-generated Image Detection
+
+[Shilin Yan](https://scholar.google.com/citations?user=2VhjOykAAAAJ&hl=zh-CN&oi=ao)1† , Ouxiang Li1,2† , Jiayin Cai1† , [Yanbin Hao](https://scholar.google.com/citations?user=vhPSOkEAAAAJ&hl=en&oi=ao)2 , [Xiaolong Jiang](https://scholar.google.com/citations?user=G0Ow8j8AAAAJ&hl=en&oi=ao)1 , [Yao Hu](https://scholar.google.com/citations?user=LIu7k7wAAAAJ&hl=en)1 , [Weidi Xie](https://scholar.google.com/citations?user=Vtrqj4gAAAAJ&hl=en)3‡
+
+
+
+
+
+1 Xiaohongshu Inc. 2 University of Science and Technology of China 3 Shanghai Jiao Tong University
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+## 🔥 News
+* [2025-01-23]🎉🎉🎉 AIDE is accepted by ICLR 2025.
+* [2024-12-29]🔥🔥🔥 We release the Chamelon dataset.
+* [2024-06-20]🔥🔥🔥 We release the code and checkpoints of AIDE.
+
+
+## 🔍 Chameleon
+
+
+**License**:
+```
+Chameleon is only used for academic research. Commercial use in any form is prohibited.
+```
+
+🌟🌟🌟 If you need the Chameleon dataset, please send an email to **tattoo.ysl@gmail.com**. 🔥🔥🔥
+
+
+
+**Comparison of `Chameleon` with existing benchmarks.**
+
+
+
+We visualize two contemporary AI-generated image benchmarks, namely:
+
+- **(a) AIGCDetect Benchmark**
+- **(b) GenImage Benchmark**
+
+where all images are generated from publicly available generators, such as ProGAN (GAN-based), SD v1.4 (DM-based), and Midjourney (commercial API). These images are generated by unconditional situations or conditioned on simple prompts (e.g., *photo of a plane*) without delicate manual adjustments, thereby inclined to generate obvious artifacts in consistency and semantics (marked with red boxes ).
+
+In contrast, our **`Chameleon`** dataset in **(c)** aims to simulate real-world scenarios by collecting diverse images from online websites, where these online images are carefully adjusted by photographers and AI artists.
+
+
+
+## 👀 Method
+
+We conduct a sanity check on **"whether the task of AI-generated image detection has been solved"**. To start with, we present **Chameleon** dataset, consisting AI-generated images that are genuinely challenging for human perception. To quantify the generalization of existing methods, we evaluate 9 off-the-shelf AI-generated image detectors on **Chameleon** dataset. Upon analysis, almost all models classify AI-generated images as real ones. Later, we propose **AIDE**~(**A**I-generated **I**mage **DE**tector with Hybrid Features), which leverages multiple experts to simultaneously extract visual artifacts and noise patterns.
+
+
+
+
+
+
+## Requirements
+
+We test the codes in the following environments, other versions may also be compatible:
+
+- CUDA 11.8
+- Python 3.10
+- Pytorch 2.0.1
+
+
+## Setup
+
+First, clone the repository locally.
+
+```
+https://github.com/shilinyan99/AIDE
+```
+
+Then, install Pytorch 2.0.1 using the conda environment.
+```
+conda install pytorch==2.0.1 torchvision==0.15.2 torchaudio==2.0.2 -c pytorch
+```
+
+Lastly, install the necessary packages and pycocotools.
+
+```
+pip install -r requirements.txt
+```
+
+
+## Get Started
+
+### Training
+
+```
+./scripts/train.sh --data_path [/path/to/train_data] --eval_data_path [/path/to/eval_data] --resnet_path [/path/to/pretrained_resnet_path] --convnext_path [/path/to/pretrained_convnext_path] --output_dir [/path/to/output_dir] [other args]
+```
+
+For example, training on ProGAN, run the following command:
+
+```
+./scripts/train.sh --data_path dataset/progan/train --eval_data_path dataset/progan/eval --resnet_path pretrained_ckpts/resnet50.pth --convnext_path pretrained_ckpts/open_clip_pytorch_model.bin --output_dir results/progan_train
+```
+
+### Inference
+
+Inference using the trained model.
+```
+./scripts/eval.sh --data_path [/path/to/train_data] --eval_data_path [/path/to/eval_data] --resume [/path/to/progan_train] --eval True --output_dir [/path/to/output_dir]
+```
+
+For example, evaluating the progan_train model, run the following command:
+
+```
+./scripts/eval.sh --data_path dataset/progan/train --eval_data_path dataset/progan/eval --resume results/progan_train/progan_train.pth --eval True --output_dir results/progan_train
+```
+
+
+
+## Dataset
+
+### Training Set
+We adopt the training set in [CNNSpot](https://github.com/peterwang512/CNNDetection) and [GenImage](https://github.com/Andrew-Zhu/GenImage).
+
+### Test Set
+The whole test set we used in our experiments can be downloaded from [AIGCDetectBenchmark](https://github.com/Ekko-zn/AIGCDetectBenchmark?tab=readme-ov-file) and [GenImage](https://github.com/Andrew-Zhu/GenImage).
+
+
+## Model Zoo
+
+Our training checkpoints can be downloaded from [link](https://drive.google.com/drive/folders/1qx76UFvDpgCxaPLBCmsA2WY-SSzeJrd4?usp=sharing).
+
+## Acknowledgement
+
+This repo is based on [ConvNeXt](https://github.com/facebookresearch/ConvNeXt-V2). We also refer to the repositories [CNNSpot](https://github.com/peterwang512/CNNDetection)、[AIGCDetectBenchmark](https://github.com/Ekko-zn/AIGCDetectBenchmark?tab=readme-ov-file)、[GenImage](https://github.com/Andrew-Zhu/GenImage) and [DNF](https://github.com/YichiCS/DNF). Thanks for their wonderful works.
+
+## Citation
+
+```
+@article{yan2024sanity,
+ title={A Sanity Check for AI-generated Image Detection},
+ author={Yan, Shilin and Li, Ouxiang and Cai, Jiayin and Hao, Yanbin and Jiang, Xiaolong and Hu, Yao and Xie, Weidi},
+ journal={arXiv preprint arXiv:2406.19435},
+ year={2024}
+}
+```
+
+## Contact
+If you have any question about this project, please feel free to contact tattoo.ysl@gmail.com.
diff --git a/clean/image/aide/SOURCE.md b/clean/image/aide/SOURCE.md
new file mode 100644
index 0000000000000000000000000000000000000000..92fa373cbbeadc1b2334d39e49372e616a822213
--- /dev/null
+++ b/clean/image/aide/SOURCE.md
@@ -0,0 +1,17 @@
+# Source: image/aide
+
+| Field | Value |
+|---|---|
+| Upstream | https://github.com/shilinyan99/AIDE |
+| Paper | https://arxiv.org/abs/2406.19435 |
+| Commit SHA | **not recorded** -- the vendoring step did not preserve it |
+| Mirrored on | 2026-09-15 |
+| Upstream license | LICENSE |
+
+This is a **mirror**, stripped to the files needed for inference. The full
+untouched snapshot is at `archive/image__aide.tar.gz`.
+
+This code is the work of its original authors and is **not** covered by the
+DeepSafe project license. If you are an author and want this removed, open an
+issue on https://github.com/deepsafehq/deepsafe-bench and it will be taken down
+within 48 hours, no questions asked.
diff --git a/clean/image/aide/data/__init__.py b/clean/image/aide/data/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/clean/image/aide/data/dct.py b/clean/image/aide/data/dct.py
new file mode 100644
index 0000000000000000000000000000000000000000..0a0fe80983a4c203e163e06eafd8c8bc349bca5c
--- /dev/null
+++ b/clean/image/aide/data/dct.py
@@ -0,0 +1,107 @@
+"""DCT frequency decomposition module for AIDE.
+
+Source: https://github.com/shilinyan99/AIDE (ICLR 2025)
+Selects the most and least frequency-active image patches for
+multi-view input to the AIDE deepfake detector.
+"""
+
+import torch
+import torch.nn as nn
+import numpy as np
+
+
+def DCT_mat(size):
+ m = [[(np.sqrt(1./size) if i == 0 else np.sqrt(2./size)) * np.cos((j + 0.5) * np.pi * i / size) for j in range(size)] for i in range(size)]
+ return m
+
+def generate_filter(start, end, size):
+ return [[0. if i + j > end or i + j < start else 1. for j in range(size)] for i in range(size)]
+
+def norm_sigma(x):
+ return 2. * torch.sigmoid(x) - 1.
+
+class Filter(nn.Module):
+ def __init__(self, size, band_start, band_end, use_learnable=False, norm=False):
+ super(Filter, self).__init__()
+ self.use_learnable = use_learnable
+ self.base = nn.Parameter(torch.tensor(generate_filter(band_start, band_end, size)), requires_grad=False)
+ if self.use_learnable:
+ self.learnable = nn.Parameter(torch.randn(size, size), requires_grad=True)
+ self.learnable.data.normal_(0., 0.1)
+ self.norm = norm
+ if norm:
+ self.ft_num = nn.Parameter(torch.sum(torch.tensor(generate_filter(band_start, band_end, size))), requires_grad=False)
+
+ def forward(self, x):
+ if self.use_learnable:
+ filt = self.base + norm_sigma(self.learnable)
+ else:
+ filt = self.base
+ if self.norm:
+ y = x * filt / self.ft_num
+ else:
+ y = x * filt
+ return y
+
+class DCT_base_Rec_Module(nn.Module):
+ def __init__(self, window_size=32, stride=16, output=256, grade_N=6, level_fliter=[0]):
+ super().__init__()
+ assert output % window_size == 0
+ assert len(level_fliter) > 0
+ self.window_size = window_size
+ self.grade_N = grade_N
+ self.level_N = len(level_fliter)
+ self.N = (output // window_size) * (output // window_size)
+ self._DCT_patch = nn.Parameter(torch.tensor(DCT_mat(window_size)).float(), requires_grad=False)
+ self._DCT_patch_T = nn.Parameter(torch.transpose(torch.tensor(DCT_mat(window_size)).float(), 0, 1), requires_grad=False)
+ self.unfold = nn.Unfold(kernel_size=(window_size, window_size), stride=stride)
+ self.fold0 = nn.Fold(output_size=(window_size, window_size), kernel_size=(window_size, window_size), stride=window_size)
+ level_f = [Filter(window_size, 0, window_size * 2)]
+ self.level_filters = nn.ModuleList([level_f[i] for i in level_fliter])
+ self.grade_filters = nn.ModuleList([Filter(window_size, window_size * 2. / grade_N * i, window_size * 2. / grade_N * (i+1), norm=True) for i in range(grade_N)])
+
+ def forward(self, x):
+ N = self.N
+ grade_N = self.grade_N
+ level_N = self.level_N
+ window_size = self.window_size
+ C, W, H = x.shape
+ x_unfold = self.unfold(x.unsqueeze(0)).squeeze(0)
+ _, L = x_unfold.shape
+ x_unfold = x_unfold.transpose(0, 1).reshape(L, C, window_size, window_size)
+ x_dct = self._DCT_patch @ x_unfold @ self._DCT_patch_T
+ y_list = []
+ for i in range(self.level_N):
+ x_pass = self.level_filters[i](x_dct)
+ y = self._DCT_patch_T @ x_pass @ self._DCT_patch
+ y_list.append(y)
+ level_x_unfold = torch.cat(y_list, dim=1)
+ grade = torch.zeros(L).to(x.device)
+ w, k = 1, 2
+ for _ in range(grade_N):
+ _x = torch.abs(x_dct)
+ _x = torch.log(_x + 1)
+ _x = self.grade_filters[_](_x)
+ _x = torch.sum(_x, dim=[1,2,3])
+ grade += w * _x
+ w *= k
+ _, idx = torch.sort(grade)
+ max_idx = torch.flip(idx, dims=[0])[:N]
+ maxmax_idx = max_idx[0]
+ maxmax_idx1 = max_idx[1] if len(max_idx) > 1 else max_idx[0]
+ min_idx = idx[:N]
+ minmin_idx = idx[0]
+ minmin_idx1 = idx[1] if len(min_idx) > 1 else idx[0]
+ x_minmin = torch.index_select(level_x_unfold, 0, minmin_idx)
+ x_maxmax = torch.index_select(level_x_unfold, 0, maxmax_idx)
+ x_minmin1 = torch.index_select(level_x_unfold, 0, minmin_idx1)
+ x_maxmax1 = torch.index_select(level_x_unfold, 0, maxmax_idx1)
+ x_minmin = x_minmin.reshape(1, level_N*C*window_size*window_size).transpose(0, 1)
+ x_maxmax = x_maxmax.reshape(1, level_N*C*window_size*window_size).transpose(0, 1)
+ x_minmin1 = x_minmin1.reshape(1, level_N*C*window_size*window_size).transpose(0, 1)
+ x_maxmax1 = x_maxmax1.reshape(1, level_N*C*window_size*window_size).transpose(0, 1)
+ x_minmin = self.fold0(x_minmin)
+ x_maxmax = self.fold0(x_maxmax)
+ x_minmin1 = self.fold0(x_minmin1)
+ x_maxmax1 = self.fold0(x_maxmax1)
+ return x_minmin, x_maxmax, x_minmin1, x_maxmax1
diff --git a/clean/image/aide/engine_finetune.py b/clean/image/aide/engine_finetune.py
new file mode 100644
index 0000000000000000000000000000000000000000..e356fc9d83b6622ace43e5a7c68c4badf908818e
--- /dev/null
+++ b/clean/image/aide/engine_finetune.py
@@ -0,0 +1,197 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+
+# All rights reserved.
+
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+import os
+import math
+from typing import Iterable, Optional
+
+import torch
+import torch.distributed as dist
+from timm.data import Mixup
+from timm.utils import accuracy, ModelEma
+
+import utils
+from utils import adjust_learning_rate
+from scipy.special import softmax
+from sklearn.metrics import (
+ average_precision_score,
+ accuracy_score
+)
+import numpy as np
+
+
+def train_one_epoch(model: torch.nn.Module, criterion: torch.nn.Module,
+ data_loader: Iterable, optimizer: torch.optim.Optimizer,
+ device: torch.device, epoch: int, loss_scaler, max_norm: float = 0,
+ model_ema: Optional[ModelEma] = None, mixup_fn: Optional[Mixup] = None,
+ log_writer=None, args=None):
+ model.train(True)
+ metric_logger = utils.MetricLogger(delimiter=" ")
+ metric_logger.add_meter('lr', utils.SmoothedValue(window_size=1, fmt='{value:.6f}'))
+ header = 'Epoch: [{}]'.format(epoch)
+ print_freq = 20
+
+ update_freq = args.update_freq
+ use_amp = args.use_amp
+ optimizer.zero_grad()
+
+ for data_iter_step, (samples, targets) in enumerate(metric_logger.log_every(data_loader, print_freq, header)):
+ # we use a per iteration (instead of per epoch) lr scheduler
+ if data_iter_step % update_freq == 0:
+ adjust_learning_rate(optimizer, data_iter_step / len(data_loader) + epoch, args)
+
+ samples = samples.to(device, non_blocking=True)
+ targets = targets.to(device, non_blocking=True)
+
+ if mixup_fn is not None:
+ samples, targets = mixup_fn(samples, targets)
+
+ if use_amp:
+ with torch.cuda.amp.autocast():
+ output = model(samples)
+ loss = criterion(output, targets)
+ else: # full precision
+ output = model(samples)
+ loss = criterion(output, targets)
+
+ loss_value = loss.item()
+
+ if not math.isfinite(loss_value):
+ print("Loss is {}, stopping training".format(loss_value))
+ assert math.isfinite(loss_value)
+
+ if use_amp:
+ # this attribute is added by timm on one optimizer (adahessian)
+ is_second_order = hasattr(optimizer, 'is_second_order') and optimizer.is_second_order
+ loss /= update_freq
+ grad_norm = loss_scaler(loss, optimizer, clip_grad=max_norm,
+ parameters=model.parameters(), create_graph=is_second_order,
+ update_grad=(data_iter_step + 1) % update_freq == 0)
+ if (data_iter_step + 1) % update_freq == 0:
+ optimizer.zero_grad()
+ if model_ema is not None:
+ model_ema.update(model)
+ else: # full precision
+ loss /= update_freq
+ loss.backward()
+ if (data_iter_step + 1) % update_freq == 0:
+ optimizer.step()
+ optimizer.zero_grad()
+ if model_ema is not None:
+ model_ema.update(model)
+
+ torch.cuda.synchronize()
+
+ if mixup_fn is None:
+ class_acc = (output.max(-1)[-1] == targets).float().mean()
+ else:
+ class_acc = None
+
+ metric_logger.update(loss=loss_value)
+ metric_logger.update(class_acc=class_acc)
+ min_lr = 10.
+ max_lr = 0.
+ for group in optimizer.param_groups:
+ min_lr = min(min_lr, group["lr"])
+ max_lr = max(max_lr, group["lr"])
+
+ metric_logger.update(lr=max_lr)
+ metric_logger.update(min_lr=min_lr)
+ weight_decay_value = None
+ for group in optimizer.param_groups:
+ if group["weight_decay"] > 0:
+ weight_decay_value = group["weight_decay"]
+ metric_logger.update(weight_decay=weight_decay_value)
+ if use_amp:
+ metric_logger.update(grad_norm=grad_norm)
+ if log_writer is not None:
+ log_writer.update(loss=loss_value, head="loss")
+ log_writer.update(class_acc=class_acc, head="loss")
+ log_writer.update(lr=max_lr, head="opt")
+ log_writer.update(min_lr=min_lr, head="opt")
+ log_writer.update(weight_decay=weight_decay_value, head="opt")
+ if use_amp:
+ log_writer.update(grad_norm=grad_norm, head="opt")
+ log_writer.set_step()
+
+ # gather the stats from all processes
+ metric_logger.synchronize_between_processes()
+ print("Averaged stats:", metric_logger)
+ return {k: meter.global_avg for k, meter in metric_logger.meters.items()}
+
+@torch.no_grad()
+def evaluate(data_loader, model, device, use_amp=False):
+ criterion = torch.nn.CrossEntropyLoss()
+
+ metric_logger = utils.MetricLogger(delimiter=" ")
+ header = 'Test:'
+
+ # switch to evaluation mode
+ model.eval()
+
+ for index, batch in enumerate(metric_logger.log_every(data_loader, 10, header)):
+ images = batch[0]
+ target = batch[-1]
+
+ images = images.to(device, non_blocking=True)
+ target = target.to(device, non_blocking=True)
+
+ # compute output
+ if use_amp:
+ with torch.cuda.amp.autocast(dytpe=torch.bfloat16):
+ output = model(images)
+ if isinstance(output, dict):
+ output = output['logits']
+ loss = criterion(output, target)
+ else:
+ output = model(images) #[bs, num_cls]
+ if isinstance(output, dict):
+ output = output['logits']
+
+ loss = criterion(output, target)
+
+ if index == 0:
+ predictions = output
+ labels = target
+ else:
+ predictions = torch.cat((predictions, output), 0)
+ labels = torch.cat((labels, target), 0)
+
+ torch.cuda.synchronize()
+
+ acc1, acc5 = accuracy(output, target, topk=(1, 2))
+
+ batch_size = images.shape[0]
+ metric_logger.update(loss=loss.item())
+ metric_logger.meters['acc1'].update(acc1.item(), n=batch_size)
+ metric_logger.meters['acc5'].update(acc5.item(), n=batch_size)
+ # gather the stats from all processes
+ metric_logger.synchronize_between_processes()
+ print('* Acc@1 {top1.global_avg:.3f} Acc@5 {top5.global_avg:.3f} loss {losses.global_avg:.3f}'
+ .format(top1=metric_logger.acc1, top5=metric_logger.acc5, losses=metric_logger.loss))
+
+
+ output_ddp = [torch.zeros_like(predictions) for _ in range(utils.get_world_size())]
+ dist.all_gather(output_ddp, predictions)
+ labels_ddp = [torch.zeros_like(labels) for _ in range(utils.get_world_size())]
+ dist.all_gather(labels_ddp, labels)
+
+ output_all = torch.concat(output_ddp, dim=0)
+ labels_all = torch.concat(labels_ddp, dim=0)
+
+
+ y_pred = softmax(output_all.detach().cpu().numpy(), axis=1)[:, 1]
+ y_true = labels_all.detach().cpu().numpy()
+ y_true = y_true.astype(int)
+
+
+ acc = accuracy_score(y_true, y_pred > 0.5)
+ ap = average_precision_score(y_true, y_pred)
+
+
+
+ return {k: meter.global_avg for k, meter in metric_logger.meters.items()}, acc, ap
\ No newline at end of file
diff --git a/clean/image/aide/main_finetune.py b/clean/image/aide/main_finetune.py
new file mode 100644
index 0000000000000000000000000000000000000000..e5e5b47c9ab5348809dcb82b17fd8b038d4dc0d0
--- /dev/null
+++ b/clean/image/aide/main_finetune.py
@@ -0,0 +1,449 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+
+# All rights reserved.
+
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+
+import argparse
+import datetime
+import numpy as np
+import time
+import json
+import os
+from pathlib import Path
+
+import torch
+import torch.backends.cudnn as cudnn
+
+from timm.models.layers import trunc_normal_
+from timm.data.mixup import Mixup
+from timm.loss import LabelSmoothingCrossEntropy, SoftTargetCrossEntropy
+from timm.utils import ModelEma
+from optim_factory import create_optimizer, LayerDecayValueAssigner
+
+from data.datasets import TrainDataset, TestDataset
+from engine_finetune import train_one_epoch, evaluate
+
+import utils
+from utils import NativeScalerWithGradNormCount as NativeScaler
+from utils import str2bool, remap_checkpoint_keys
+import models.AIDE as AIDE
+import csv
+import warnings
+
+warnings.filterwarnings('ignore')
+
+def get_args_parser():
+ parser = argparse.ArgumentParser('Resnet fine-tuning', add_help=False)
+ parser.add_argument('--batch_size', default=64, type=int,
+ help='Per GPU batch size')
+ parser.add_argument('--epochs', default=100, type=int)
+ parser.add_argument('--update_freq', default=1, type=int,
+ help='gradient accumulation steps')
+
+ # Model parameters
+ parser.add_argument('--model', default='AIDE', type=str, metavar='MODEL',
+ help='Name of model to train')
+ parser.add_argument('--resnet_path', default=None, type=str, metavar='MODEL',
+ help='Path of resnet model')
+ parser.add_argument('--convnext_path', default=None, type=str, metavar='MODEL',
+ help='Path of ConvNeXt of model ')
+
+ # EMA related parameters
+ parser.add_argument('--model_ema', type=str2bool, default=False)
+ parser.add_argument('--model_ema_decay', type=float, default=0.9999, help='')
+ parser.add_argument('--model_ema_force_cpu', type=str2bool, default=False, help='')
+ parser.add_argument('--model_ema_eval', type=str2bool, default=False, help='Using ema to eval during training.')
+
+ # Optimization parameters
+ parser.add_argument('--clip_grad', type=float, default=None, metavar='NORM',
+ help='Clip gradient norm (default: None, no clipping)')
+ parser.add_argument('--weight_decay', type=float, default=0.,
+ help='weight decay (default: 0.05)')
+ parser.add_argument('--lr', type=float, default=None, metavar='LR',
+ help='learning rate (absolute lr)')
+ parser.add_argument('--blr', type=float, default=5e-4, metavar='LR',
+ help='base learning rate: absolute_lr = base_lr * total_batch_size / 256')
+ parser.add_argument('--layer_decay', type=float, default=1.0)
+ parser.add_argument('--min_lr', type=float, default=1e-6, metavar='LR',
+ help='lower lr bound for cyclic schedulers that hit 0 (1e-6)')
+ parser.add_argument('--warmup_epochs', type=int, default=0, metavar='N',
+ help='epochs to warmup LR, if scheduler supports')
+
+ parser.add_argument('--warmup_steps', type=int, default=-1, metavar='N',
+ help='num of steps to warmup LR, will overload warmup_epochs if set > 0')
+ parser.add_argument('--opt', default='adamw', type=str, metavar='OPTIMIZER',
+ help='Optimizer (default: "adamw"')
+ parser.add_argument('--opt_eps', default=1e-8, type=float, metavar='EPSILON',
+ help='Optimizer Epsilon (default: 1e-8)')
+ parser.add_argument('--opt_betas', default=None, type=float, nargs='+', metavar='BETA',
+ help='Optimizer Betas (default: None, use opt default)')
+ parser.add_argument('--momentum', type=float, default=0.9, metavar='M',
+ help='SGD momentum (default: 0.9)')
+ parser.add_argument('--weight_decay_end', type=float, default=None, help="""Final value of the
+ weight decay. We use a cosine schedule for WD and using a larger decay by
+ the end of training improves performance for ViTs.""")
+
+ # Augmentation parameters
+ parser.add_argument('--color_jitter', type=float, default=None, metavar='PCT',
+ help='Color jitter factor (enabled only when not using Auto/RandAug)')
+ parser.add_argument('--aa', type=str, default='rand-m9-mstd0.5-inc1', metavar='NAME',
+ help='Use AutoAugment policy. "v0" or "original". " + "(default: rand-m9-mstd0.5-inc1)')
+ parser.add_argument('--smoothing', type=float, default=0.1,
+ help='Label smoothing (default: 0.1)')
+
+ parser.add_argument('--train_interpolation', type=str, default='bicubic',
+ help='Training interpolation (random, bilinear, bicubic default: "bicubic")')
+
+ # * Random Erase params
+ parser.add_argument('--reprob', type=float, default=0.25, metavar='PCT',
+ help='Random erase prob (default: 0.25)')
+ parser.add_argument('--remode', type=str, default='pixel',
+ help='Random erase mode (default: "pixel")')
+ parser.add_argument('--recount', type=int, default=1,
+ help='Random erase count (default: 1)')
+ parser.add_argument('--resplit', type=str2bool, default=False,
+ help='Do not random erase first (clean) augmentation split')
+
+ # * Mixup params
+ parser.add_argument('--mixup', type=float, default=0.,
+ help='mixup alpha, mixup enabled if > 0.')
+ parser.add_argument('--cutmix', type=float, default=0.,
+ help='cutmix alpha, cutmix enabled if > 0.')
+ parser.add_argument('--cutmix_minmax', type=float, nargs='+', default=None,
+ help='cutmix min/max ratio, overrides alpha and enables cutmix if set (default: None)')
+ parser.add_argument('--mixup_prob', type=float, default=1.0,
+ help='Probability of performing mixup or cutmix when either/both is enabled')
+ parser.add_argument('--mixup_switch_prob', type=float, default=0.5,
+ help='Probability of switching to cutmix when both mixup and cutmix enabled')
+ parser.add_argument('--mixup_mode', type=str, default='batch',
+ help='How to apply mixup/cutmix params. Per "batch", "pair", or "elem"')
+
+ # * Finetuning params
+ parser.add_argument('--finetune', default='',
+ help='finetune from checkpoint')
+ parser.add_argument('--head_init_scale', default=0.001, type=float,
+ help='classifier head initial scale, typically adjusted in fine-tuning')
+ parser.add_argument('--model_key', default='model|module', type=str,
+ help='which key to load from saved state dict, usually model or model_ema')
+ parser.add_argument('--model_prefix', default='', type=str)
+
+ # Dataset parameters
+ parser.add_argument('--data_path', default='path/dataset', type=str,
+ help='dataset path')
+ parser.add_argument('--nb_classes', default=2, type=int,
+ help='number of the classification types')
+ parser.add_argument('--output_dir', default='',
+ help='path where to save, empty for no saving')
+ parser.add_argument('--log_dir', default=None,
+ help='path where to tensorboard log')
+ parser.add_argument('--device', default='cuda',
+ help='device to use for training / testing')
+ parser.add_argument('--seed', default=0, type=int)
+ parser.add_argument('--resume', default='',
+ help='resume from checkpoint')
+
+ parser.add_argument('--eval_data_path', default=None, type=str,
+ help='dataset path for evaluation')
+ parser.add_argument('--imagenet_default_mean_and_std', type=str2bool, default=True)
+ parser.add_argument('--data_set', default='IMNET', choices=['CIFAR', 'IMNET', 'image_folder'],
+ type=str, help='ImageNet dataset path')
+ parser.add_argument('--auto_resume', type=str2bool, default=True)
+ parser.add_argument('--save_ckpt', type=str2bool, default=True)
+ parser.add_argument('--save_ckpt_freq', default=1, type=int)
+ parser.add_argument('--save_ckpt_num', default=100, type=int)
+
+ parser.add_argument('--start_epoch', default=0, type=int, metavar='N',
+ help='start epoch')
+ parser.add_argument('--eval', type=str2bool, default=False,
+ help='Perform evaluation only')
+ parser.add_argument('--dist_eval', type=str2bool, default=True,
+ help='Enabling distributed evaluation')
+ parser.add_argument('--disable_eval', type=str2bool, default=False,
+ help='Disabling evaluation during training')
+ parser.add_argument('--num_workers', default=16, type=int)
+ parser.add_argument('--pin_mem', type=str2bool, default=True,
+ help='Pin CPU memory in DataLoader for more efficient (sometimes) transfer to GPU.')
+
+ # Evaluation parameters
+ parser.add_argument('--crop_pct', type=float, default=None)
+
+ # distributed training parameters
+ parser.add_argument('--world_size', default=1, type=int,
+ help='number of distributed processes')
+ parser.add_argument('--local_rank', default=-1, type=int)
+ parser.add_argument('--dist_on_itp', type=str2bool, default=False)
+ parser.add_argument('--dist_url', default='env://',
+ help='url used to set up distributed training')
+
+ parser.add_argument('--use_amp', type=str2bool, default=False,
+ help="Use apex AMP (Automatic Mixed Precision) or not")
+ return parser
+
+def main(args):
+ utils.init_distributed_mode(args)
+ print(args)
+ device = torch.device(args.device)
+
+ # fix the seed for reproducibility
+ seed = args.seed + utils.get_rank()
+ torch.manual_seed(seed)
+ np.random.seed(seed)
+ cudnn.benchmark = True
+
+ dataset_train = TrainDataset(is_train=True, args=args)
+
+ if args.disable_eval:
+ args.dist_eval = False
+ dataset_val = None
+ else:
+ dataset_val = TrainDataset(is_train=False, args=args)
+
+ num_tasks = utils.get_world_size()
+ global_rank = utils.get_rank()
+
+ sampler_train = torch.utils.data.DistributedSampler(
+ dataset_train, num_replicas=num_tasks, rank=global_rank, shuffle=True, seed=args.seed,
+ )
+ print("Sampler_train = %s" % str(sampler_train))
+ if args.dist_eval:
+ if len(dataset_val) % num_tasks != 0:
+ print('Warning: Enabling distributed evaluation with an eval dataset not divisible by process number. '
+ 'This will slightly alter validation results as extra duplicate entries are added to achieve '
+ 'equal num of samples per-process.')
+ sampler_val = torch.utils.data.DistributedSampler(
+ dataset_val, num_replicas=num_tasks, rank=global_rank, shuffle=False)
+ else:
+ sampler_val = torch.utils.data.SequentialSampler(dataset_val)
+
+ if global_rank == 0 and args.log_dir is not None:
+ os.makedirs(args.log_dir, exist_ok=True)
+ log_writer = utils.TensorboardLogger(log_dir=args.log_dir)
+ else:
+ log_writer = None
+
+ data_loader_train = torch.utils.data.DataLoader(
+ dataset_train, sampler=sampler_train,
+ batch_size=args.batch_size,
+ num_workers=args.num_workers,
+ pin_memory=args.pin_mem,
+ drop_last=True,
+ )
+ if dataset_val is not None:
+ data_loader_val = torch.utils.data.DataLoader(
+ dataset_val, sampler=sampler_val,
+ batch_size=args.batch_size,
+ num_workers=args.num_workers,
+ pin_memory=args.pin_mem,
+ drop_last=False
+ )
+ else:
+ data_loader_val = None
+
+ mixup_fn = None
+ mixup_active = args.mixup > 0 or args.cutmix > 0. or args.cutmix_minmax is not None
+ if mixup_active:
+ print("Mixup is activated!")
+ mixup_fn = Mixup(
+ mixup_alpha=args.mixup, cutmix_alpha=args.cutmix, cutmix_minmax=args.cutmix_minmax,
+ prob=args.mixup_prob, switch_prob=args.mixup_switch_prob, mode=args.mixup_mode,
+ label_smoothing=args.smoothing, num_classes=args.nb_classes)
+
+
+ model = AIDE.__dict__[args.model](
+ resnet_path=args.resnet_path,
+ convnext_path=args.convnext_path
+ )
+
+ model.to(device)
+
+ model_ema = None
+ if args.model_ema:
+ # Important to create EMA model after cuda(), DP wrapper, and AMP but before SyncBN and DDP wrapper
+ model_ema = ModelEma(
+ model,
+ decay=args.model_ema_decay,
+ device='cpu' if args.model_ema_force_cpu else '',
+ resume='')
+ print("Using EMA with decay = %.8f" % args.model_ema_decay)
+
+ model_without_ddp = model
+ n_parameters = sum(p.numel() for p in model.parameters() if p.requires_grad)
+
+ print("Model = %s" % str(model_without_ddp))
+ print('number of params:', n_parameters)
+
+ eff_batch_size = args.batch_size * args.update_freq * utils.get_world_size()
+ num_training_steps_per_epoch = len(dataset_train) // eff_batch_size
+
+ if args.lr is None:
+ args.lr = args.blr * eff_batch_size / 256
+
+ print("base lr: %.2e" % (args.lr * 256 / eff_batch_size))
+ print("actual lr: %.2e" % args.lr)
+
+ print("accumulate grad iterations: %d" % args.update_freq)
+ print("effective batch size: %d" % eff_batch_size)
+
+ assigner = None
+
+ if args.distributed:
+ model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.gpu], find_unused_parameters=True)
+ model_without_ddp = model.module
+
+ optimizer = create_optimizer(
+ args, model_without_ddp, skip_list=None,
+ get_num_layer=assigner.get_layer_id if assigner is not None else None,
+ get_layer_scale=assigner.get_scale if assigner is not None else None)
+ loss_scaler = NativeScaler()
+
+ if mixup_fn is not None:
+ # smoothing is handled with mixup label transform
+ criterion = SoftTargetCrossEntropy()
+ elif args.smoothing > 0.:
+ criterion = LabelSmoothingCrossEntropy(smoothing=args.smoothing)
+ else:
+ criterion = torch.nn.CrossEntropyLoss()
+
+ print("criterion = %s" % str(criterion))
+
+ utils.auto_load_model(
+ args=args, model=model, model_without_ddp=model_without_ddp,
+ optimizer=optimizer, loss_scaler=loss_scaler, model_ema=model_ema)
+
+ if args.eval:
+ print(f"Eval only mode")
+
+ vals = os.listdir(args.eval_data_path)
+ if len(vals) == 16:
+ vals = ["progan", "stylegan", "biggan", "cyclegan", "stargan", "gaugan", "stylegan2", "whichfaceisreal", "ADM", "Glide", "Midjourney", "stable_diffusion_v_1_4", "stable_diffusion_v_1_5", "VQDM", "wukong", "DALLE2"]
+ if len(vals) == 8:
+ vals = ["Midjourney", "stable_diffusion_v_1_4", "stable_diffusion_v_1_5", "ADM", "glide", "wukong", "VQDM", "BigGAN"]
+ eval_data_path = args.eval_data_path
+
+ rows = [["{} model testing on...".format(args.resume)],
+ ['testset', 'accuracy', 'avg precision']]
+
+ for v_id, val in enumerate(vals):
+
+ args.eval_data_path = os.path.join(args.eval_data_path, val)
+ dataset_val = TestDataset(is_train=False, args=args)
+ args.eval_data_path = eval_data_path
+
+ if args.dist_eval:
+ if len(dataset_val) % num_tasks != 0:
+ print('Warning: Enabling distributed evaluation with an eval dataset not divisible by process number. '
+ 'This will slightly alter validation results as extra duplicate entries are added to achieve '
+ 'equal num of samples per-process.')
+ sampler_val = torch.utils.data.DistributedSampler(
+ dataset_val, num_replicas=num_tasks, rank=global_rank, shuffle=False)
+ else:
+ sampler_val = torch.utils.data.SequentialSampler(dataset_val)
+
+ data_loader_val = torch.utils.data.DataLoader(
+ dataset_val, sampler=sampler_val,
+ batch_size=args.batch_size,
+ num_workers=args.num_workers,
+ pin_memory=args.pin_mem,
+ drop_last=False
+ )
+
+
+ test_stats, acc, ap = evaluate(data_loader_val, model, device)
+ print(f"Accuracy of the network on {len(dataset_val)} test images: {test_stats['acc1']:.5f}%")
+
+ print(f"test dataset is {val} acc: {acc}, ap: {ap}")
+ print("***********************************")
+
+ rows.append([val, acc, ap])
+
+
+ test_dataset_name = args.eval_data_path.split('/')[-2]
+
+ csv_name = os.path.join(args.output_dir, f'{os.path.basename(args.resume)}_{test_dataset_name}.csv')
+ with open(csv_name, 'w') as f:
+ csv_writer = csv.writer(f, delimiter=',')
+ csv_writer.writerows(rows)
+ return
+
+ max_accuracy = 0.0
+ if args.model_ema and args.model_ema_eval:
+ max_accuracy_ema = 0.0
+
+ print("Start training for %d epochs" % args.epochs)
+ start_time = time.time()
+ for epoch in range(args.start_epoch, args.epochs):
+ if args.distributed:
+ data_loader_train.sampler.set_epoch(epoch)
+ if log_writer is not None:
+ log_writer.set_step(epoch * num_training_steps_per_epoch * args.update_freq)
+ train_stats = train_one_epoch(
+ model, criterion, data_loader_train,
+ optimizer, device, epoch, loss_scaler,
+ args.clip_grad, model_ema, mixup_fn,
+ log_writer=log_writer,
+ args=args
+ )
+ if args.output_dir and args.save_ckpt:
+ if (epoch + 1) % args.save_ckpt_freq == 0 or epoch + 1 == args.epochs:
+ utils.save_model(
+ args=args, model=model, model_without_ddp=model_without_ddp, optimizer=optimizer,
+ loss_scaler=loss_scaler, epoch=epoch, model_ema=model_ema)
+ if data_loader_val is not None:
+ test_stats, acc, ap = evaluate(data_loader_val, model, device, use_amp=args.use_amp)
+ print(f"Accuracy of the model on the {len(dataset_val)} test images: {test_stats['acc1']:.1f}%, ap: {ap}.")
+ if max_accuracy < test_stats["acc1"]:
+ max_accuracy = test_stats["acc1"]
+ if args.output_dir and args.save_ckpt:
+ utils.save_model(
+ args=args, model=model, model_without_ddp=model_without_ddp, optimizer=optimizer,
+ loss_scaler=loss_scaler, epoch="best", model_ema=model_ema)
+ print(f'Max accuracy: {max_accuracy:.2f}%')
+
+ if log_writer is not None:
+ log_writer.update(test_acc1=test_stats['acc1'], head="perf", step=epoch)
+ log_writer.update(test_acc5=test_stats['acc5'], head="perf", step=epoch)
+ log_writer.update(test_loss=test_stats['loss'], head="perf", step=epoch)
+
+ log_stats = {**{f'train_{k}': v for k, v in train_stats.items()},
+ **{f'test_{k}': v for k, v in test_stats.items()},
+ 'epoch': epoch,
+ 'n_parameters': n_parameters}
+
+ # repeat testing routines for EMA, if ema eval is turned on
+ if args.model_ema and args.model_ema_eval:
+ test_stats_ema, acc, ap = evaluate(data_loader_val, model_ema.ema, device, use_amp=args.use_amp)
+ print(f"Accuracy of the model EMA on {len(dataset_val)} test images: {test_stats_ema['acc1']:.1f}%, ap: {ap}")
+ if max_accuracy_ema < test_stats_ema["acc1"]:
+ max_accuracy_ema = test_stats_ema["acc1"]
+ if args.output_dir and args.save_ckpt:
+ utils.save_model(
+ args=args, model=model, model_without_ddp=model_without_ddp, optimizer=optimizer,
+ loss_scaler=loss_scaler, epoch="best-ema", model_ema=model_ema)
+ print(f'Max EMA accuracy: {max_accuracy_ema:.2f}%')
+ if log_writer is not None:
+ log_writer.update(test_acc1_ema=test_stats_ema['acc1'], head="perf", step=epoch)
+ log_stats.update({**{f'test_{k}_ema': v for k, v in test_stats_ema.items()}})
+ else:
+ log_stats = {**{f'train_{k}': v for k, v in train_stats.items()},
+ 'epoch': epoch,
+ 'n_parameters': n_parameters}
+
+ if args.output_dir and utils.is_main_process():
+ if log_writer is not None:
+ log_writer.flush()
+ with open(os.path.join(args.output_dir, "log.txt"), mode="a", encoding="utf-8") as f:
+ f.write(json.dumps(log_stats) + "\n")
+
+ total_time = time.time() - start_time
+ total_time_str = str(datetime.timedelta(seconds=int(total_time)))
+ print('Training time {}'.format(total_time_str))
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser('AIDE traning', parents=[get_args_parser()])
+ args = parser.parse_args()
+ if args.output_dir:
+ Path(args.output_dir).mkdir(parents=True, exist_ok=True)
+ main(args)
diff --git a/clean/image/aide/models/AIDE.py b/clean/image/aide/models/AIDE.py
new file mode 100644
index 0000000000000000000000000000000000000000..053805afad55edf61c9d9de4d2c499418dbb4674
--- /dev/null
+++ b/clean/image/aide/models/AIDE.py
@@ -0,0 +1,298 @@
+import torch.nn as nn
+import torch.utils.model_zoo as model_zoo
+import torch
+import clip
+import open_clip
+from .srm_filter_kernel import all_normalized_hpf_list
+import numpy as np
+
+class HPF(nn.Module):
+ def __init__(self):
+ super(HPF, self).__init__()
+
+ #Load 30 SRM Filters
+ all_hpf_list_5x5 = []
+
+ for hpf_item in all_normalized_hpf_list:
+ if hpf_item.shape[0] == 3:
+ hpf_item = np.pad(hpf_item, pad_width=((1, 1), (1, 1)), mode='constant')
+
+ all_hpf_list_5x5.append(hpf_item)
+
+ hpf_weight = torch.Tensor(all_hpf_list_5x5).view(30, 1, 5, 5).contiguous()
+ hpf_weight = torch.nn.Parameter(hpf_weight.repeat(1, 3, 1, 1), requires_grad=False)
+
+
+ self.hpf = nn.Conv2d(3, 30, kernel_size=5, padding=2, bias=False)
+ self.hpf.weight = hpf_weight
+
+
+ def forward(self, input):
+
+ output = self.hpf(input)
+
+ return output
+
+
+
+def conv3x3(in_planes, out_planes, stride=1):
+ """3x3 convolution with padding"""
+ return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,
+ padding=1, bias=False)
+
+
+def conv1x1(in_planes, out_planes, stride=1):
+ """1x1 convolution"""
+ return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False)
+
+
+class BasicBlock(nn.Module):
+ expansion = 1
+
+ def __init__(self, inplanes, planes, stride=1, downsample=None):
+ super(BasicBlock, self).__init__()
+ self.conv1 = conv3x3(inplanes, planes, stride)
+ self.bn1 = nn.BatchNorm2d(planes)
+ self.relu = nn.ReLU(inplace=True)
+ self.conv2 = conv3x3(planes, planes)
+ self.bn2 = nn.BatchNorm2d(planes)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x):
+ identity = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+
+ if self.downsample is not None:
+ identity = self.downsample(x)
+
+ out += identity
+ out = self.relu(out)
+
+ return out
+
+
+class Bottleneck(nn.Module):
+ expansion = 4
+
+ def __init__(self, inplanes, planes, stride=1, downsample=None):
+ super(Bottleneck, self).__init__()
+ self.conv1 = conv1x1(inplanes, planes)
+ self.bn1 = nn.BatchNorm2d(planes)
+ self.conv2 = conv3x3(planes, planes, stride)
+ self.bn2 = nn.BatchNorm2d(planes)
+ self.conv3 = conv1x1(planes, planes * self.expansion)
+ self.bn3 = nn.BatchNorm2d(planes * self.expansion)
+ self.relu = nn.ReLU(inplace=True)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x):
+ identity = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+ out = self.relu(out)
+
+ out = self.conv3(out)
+ out = self.bn3(out)
+
+ if self.downsample is not None:
+ identity = self.downsample(x)
+
+ out += identity
+ out = self.relu(out)
+
+ return out
+
+
+class ResNet(nn.Module):
+
+ def __init__(self, block, layers, num_classes=1000, zero_init_residual=True):
+ super(ResNet, self).__init__()
+
+ self.inplanes = 64
+ self.conv1 = nn.Conv2d(30, 64, kernel_size=7, stride=2, padding=3,
+ bias=False)
+ self.bn1 = nn.BatchNorm2d(64)
+ self.relu = nn.ReLU(inplace=True)
+ self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
+ self.layer1 = self._make_layer(block, 64, layers[0])
+ self.layer2 = self._make_layer(block, 128, layers[1], stride=2)
+ self.layer3 = self._make_layer(block, 256, layers[2], stride=2)
+ self.layer4 = self._make_layer(block, 512, layers[3], stride=2)
+ self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
+ self.fc = nn.Linear(512 * block.expansion, num_classes)
+
+ for m in self.modules():
+ if isinstance(m, nn.Conv2d):
+ nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
+ elif isinstance(m, nn.BatchNorm2d):
+ nn.init.constant_(m.weight, 1)
+ nn.init.constant_(m.bias, 0)
+
+ # Zero-initialize the last BN in each residual branch,
+ # so that the residual branch starts with zeros, and each residual block behaves like an identity.
+ # This improves the model by 0.2~0.3% according to https://arxiv.org/abs/1706.02677
+ if zero_init_residual:
+ for m in self.modules():
+ if isinstance(m, Bottleneck):
+ nn.init.constant_(m.bn3.weight, 0)
+ elif isinstance(m, BasicBlock):
+ nn.init.constant_(m.bn2.weight, 0)
+
+ def _make_layer(self, block, planes, blocks, stride=1):
+ downsample = None
+ if stride != 1 or self.inplanes != planes * block.expansion:
+ downsample = nn.Sequential(
+ conv1x1(self.inplanes, planes * block.expansion, stride),
+ nn.BatchNorm2d(planes * block.expansion),
+ )
+
+ layers = []
+ layers.append(block(self.inplanes, planes, stride, downsample))
+ self.inplanes = planes * block.expansion
+ for _ in range(1, blocks):
+ layers.append(block(self.inplanes, planes))
+
+ return nn.Sequential(*layers)
+
+ def forward(self, x):
+
+ x = self.conv1(x)
+ x = self.bn1(x)
+ x = self.relu(x)
+ x = self.maxpool(x)
+
+ x = self.layer1(x)
+ x = self.layer2(x)
+ x = self.layer3(x)
+ x = self.layer4(x)
+
+ x = self.avgpool(x)
+ x = x.view(x.size(0), -1)
+
+
+ return x
+
+class Mlp(nn.Module):
+ """ MLP as used in Vision Transformer, MLP-Mixer and related networks
+ """
+
+ def __init__(self, in_features, hidden_features=None, out_features=None, act_layer=nn.GELU):
+ super().__init__()
+ out_features = out_features or in_features
+ hidden_features = hidden_features or in_features
+
+ self.fc1 = nn.Linear(in_features, hidden_features)
+ self.act = act_layer()
+ self.fc2 = nn.Linear(hidden_features, out_features)
+
+ def forward(self, x):
+ x = self.fc1(x)
+ x = self.act(x)
+ x = self.fc2(x)
+ return x
+
+class AIDE_Model(nn.Module):
+
+ def __init__(self, resnet_path, convnext_path):
+ super(AIDE_Model, self).__init__()
+ self.hpf = HPF()
+ self.model_min = ResNet(Bottleneck, [3, 4, 6, 3])
+ self.model_max = ResNet(Bottleneck, [3, 4, 6, 3])
+
+ if resnet_path is not None:
+ pretrained_dict = torch.load(resnet_path, map_location='cpu')
+
+ model_min_dict = self.model_min.state_dict()
+ model_max_dict = self.model_max.state_dict()
+
+ for k in pretrained_dict.keys():
+ if k in model_min_dict and pretrained_dict[k].size() == model_min_dict[k].size():
+ model_min_dict[k] = pretrained_dict[k]
+ model_max_dict[k] = pretrained_dict[k]
+ else:
+ print(f"Skipping layer {k} because of size mismatch")
+
+ self.fc = Mlp(2048 + 256 , 1024, 2)
+
+ print("build model with convnext_xxl")
+ self.openclip_convnext_xxl, _, _ = open_clip.create_model_and_transforms(
+ "convnext_xxlarge", pretrained=convnext_path
+ )
+
+ self.openclip_convnext_xxl = self.openclip_convnext_xxl.visual.trunk
+ self.openclip_convnext_xxl.head.global_pool = nn.Identity()
+ self.openclip_convnext_xxl.head.flatten = nn.Identity()
+
+ self.openclip_convnext_xxl.eval()
+
+ self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
+ self.convnext_proj = nn.Sequential(
+ nn.Linear(3072, 256),
+
+ )
+ for param in self.openclip_convnext_xxl.parameters():
+ param.requires_grad = False
+
+
+
+ def forward(self, x):
+
+ b, t, c, h, w = x.shape
+
+ x_minmin = x[:, 0] #[b, c, h, w]
+ x_maxmax = x[:, 1]
+ x_minmin1 = x[:, 2]
+ x_maxmax1 = x[:, 3]
+ tokens = x[:, 4]
+
+ x_minmin = self.hpf(x_minmin)
+ x_maxmax = self.hpf(x_maxmax)
+ x_minmin1 = self.hpf(x_minmin1)
+ x_maxmax1 = self.hpf(x_maxmax1)
+
+ with torch.no_grad():
+
+ clip_mean = torch.Tensor([0.48145466, 0.4578275, 0.40821073])
+ clip_mean = clip_mean.to(tokens, non_blocking=True).view(3, 1, 1)
+ clip_std = torch.Tensor([0.26862954, 0.26130258, 0.27577711])
+ clip_std = clip_std.to(tokens, non_blocking=True).view(3, 1, 1)
+ dinov2_mean = torch.Tensor([0.485, 0.456, 0.406]).to(tokens, non_blocking=True).view(3, 1, 1)
+ dinov2_std = torch.Tensor([0.229, 0.224, 0.225]).to(tokens, non_blocking=True).view(3, 1, 1)
+
+ local_convnext_image_feats = self.openclip_convnext_xxl(
+ tokens * (dinov2_std / clip_std) + (dinov2_mean - clip_mean) / clip_std
+ ) #[b, 3072, 8, 8]
+ assert local_convnext_image_feats.size()[1:] == (3072, 8, 8)
+ local_convnext_image_feats = self.avgpool(local_convnext_image_feats).view(tokens.size(0), -1)
+ x_0 = self.convnext_proj(local_convnext_image_feats)
+
+ x_min = self.model_min(x_minmin)
+ x_max = self.model_max(x_maxmax)
+ x_min1 = self.model_min(x_minmin1)
+ x_max1 = self.model_max(x_maxmax1)
+
+ x_1 = (x_min + x_max + x_min1 + x_max1) / 4
+
+ x = torch.cat([x_0, x_1], dim=1)
+
+ x = self.fc(x)
+
+ return x
+
+def AIDE(resnet_path, convnext_path):
+ model = AIDE_Model(resnet_path, convnext_path)
+ return model
+
diff --git a/clean/image/aide/models/__init__.py b/clean/image/aide/models/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/clean/image/aide/models/srm_filter_kernel.py b/clean/image/aide/models/srm_filter_kernel.py
new file mode 100644
index 0000000000000000000000000000000000000000..36eda56b8ad18f4500ba8826a634bfb8d923ab67
--- /dev/null
+++ b/clean/image/aide/models/srm_filter_kernel.py
@@ -0,0 +1,220 @@
+
+import numpy as np
+
+filter_class_1 = [
+ np.array([
+ [1, 0, 0],
+ [0, -1, 0],
+ [0, 0, 0]
+ ], dtype=np.float32),
+ np.array([
+ [0, 1, 0],
+ [0, -1, 0],
+ [0, 0, 0]
+ ], dtype=np.float32),
+ np.array([
+ [0, 0, 1],
+ [0, -1, 0],
+ [0, 0, 0]
+ ], dtype=np.float32),
+ np.array([
+ [0, 0, 0],
+ [1, -1, 0],
+ [0, 0, 0]
+ ], dtype=np.float32),
+ np.array([
+ [0, 0, 0],
+ [0, -1, 1],
+ [0, 0, 0]
+ ], dtype=np.float32),
+ np.array([
+ [0, 0, 0],
+ [0, -1, 0],
+ [1, 0, 0]
+ ], dtype=np.float32),
+ np.array([
+ [0, 0, 0],
+ [0, -1, 0],
+ [0, 1, 0]
+ ], dtype=np.float32),
+ np.array([
+ [0, 0, 0],
+ [0, -1, 0],
+ [0, 0, 1]
+ ], dtype=np.float32)
+]
+
+
+filter_class_2 = [
+ np.array([
+ [1, 0, 0],
+ [0, -2, 0],
+ [0, 0, 1]
+ ], dtype=np.float32),
+ np.array([
+ [0, 1, 0],
+ [0, -2, 0],
+ [0, 1, 0]
+ ], dtype=np.float32),
+ np.array([
+ [0, 0, 1],
+ [0, -2, 0],
+ [1, 0, 0]
+ ], dtype=np.float32),
+ np.array([
+ [0, 0, 0],
+ [1, -2, 1],
+ [0, 0, 0]
+ ], dtype=np.float32),
+]
+
+
+filter_class_3 = [
+ np.array([
+ [-1, 0, 0, 0, 0],
+ [0, 3, 0, 0, 0],
+ [0, 0, -3, 0, 0],
+ [0, 0, 0, 1, 0],
+ [0, 0, 0, 0, 0]
+ ], dtype=np.float32),
+ np.array([
+ [0, 0, -1, 0, 0],
+ [0, 0, 3, 0, 0],
+ [0, 0, -3, 0, 0],
+ [0, 0, 1, 0, 0],
+ [0, 0, 0, 0, 0]
+ ], dtype=np.float32),
+ np.array([
+ [0, 0, 0, 0, -1],
+ [0, 0, 0, 3, 0],
+ [0, 0, -3, 0, 0],
+ [0, 1, 0, 0, 0],
+ [0, 0, 0, 0, 0]
+ ], dtype=np.float32),
+ np.array([
+ [0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0],
+ [0, 1, -3, 3, -1],
+ [0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0]
+ ], dtype=np.float32),
+ np.array([
+ [0, 0, 0, 0, 0],
+ [0, 1, 0, 0, 0],
+ [0, 0, -3, 0, 0],
+ [0, 0, 0, 3, 0],
+ [0, 0, 0, 0, -1]
+ ], dtype=np.float32),
+ np.array([
+ [0, 0, 0, 0, 0],
+ [0, 0, 1, 0, 0],
+ [0, 0, -3, 0, 0],
+ [0, 0, 3, 0, 0],
+ [0, 0, -1, 0, 0]
+ ], dtype=np.float32),
+ np.array([
+ [0, 0, 0, 0, 0],
+ [0, 0, 0, 1, 0],
+ [0, 0, -3, 0, 0],
+ [0, 3, 0, 0, 0],
+ [-1, 0, 0, 0, 0]
+ ], dtype=np.float32),
+ np.array([
+ [0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0],
+ [-1, 3, -3, 1, 0],
+ [0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0]
+ ], dtype=np.float32)
+]
+
+
+filter_edge_3x3 = [
+ np.array([
+ [-1, 2, -1],
+ [2, -4, 2],
+ [0, 0, 0]
+ ], dtype=np.float32),
+ np.array([
+ [0, 2, -1],
+ [0, -4, 2],
+ [0, 2, -1]
+ ], dtype=np.float32),
+ np.array([
+ [0, 0, 0],
+ [2, -4, 2],
+ [-1, 2, -1]
+ ], dtype=np.float32),
+ np.array([
+ [-1, 2, 0],
+ [2, -4, 0],
+ [-1, 2, 0]
+ ], dtype=np.float32),
+]
+
+filter_edge_5x5 = [
+ np.array([
+ [-1, 2, -2, 2, -1],
+ [2, -6, 8, -6, 2],
+ [-2, 8, -12, 8, -2],
+ [0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0]
+ ], dtype=np.float32),
+ np.array([
+ [0, 0, -2, 2, -1],
+ [0, 0, 8, -6, 2],
+ [0, 0, -12, 8, -2],
+ [0, 0, 8, -6, 2],
+ [0, 0, -2, 2, -1]
+ ], dtype=np.float32),
+ np.array([
+ [0, 0, 0, 0, 0],
+ [0, 0, 0, 0, 0],
+ [-2, 8, -12, 8, -2],
+ [2, -6, 8, -6, 2],
+ [-1, 2, -2, 2, -1]
+ ], dtype=np.float32),
+ np.array([
+ [-1, 2, -2, 0, 0],
+ [2, -6, 8, 0, 0],
+ [-2, 8, -12, 0, 0],
+ [2, -6, 8, 0, 0],
+ [-1, 2, -2, 0, 0]
+ ], dtype=np.float32),
+]
+
+square_3x3 = np.array([
+ [-1, 2, -1],
+ [2, -4, 2],
+ [-1, 2, -1]
+], dtype=np.float32)
+
+square_5x5 = np.array([
+ [-1, 2, -2, 2, -1],
+ [2, -6, 8, -6, 2],
+ [-2, 8, -12, 8, -2],
+ [2, -6, 8, -6, 2],
+ [-1, 2, -2, 2, -1]
+], dtype=np.float32)
+
+
+all_hpf_list = filter_class_1 + filter_class_2 + filter_class_3 + filter_edge_3x3 + filter_edge_5x5 + [square_3x3, square_5x5]
+
+hpf_3x3_list = filter_class_1 + filter_class_2 + filter_edge_3x3 + [square_3x3]
+hpf_5x5_list = filter_class_3 + filter_edge_5x5 + [square_5x5]
+
+normalized_filter_class_2 = [hpf / 2 for hpf in filter_class_2]
+normalized_filter_class_3 = [hpf / 3 for hpf in filter_class_3]
+normalized_filter_edge_3x3 = [hpf / 4 for hpf in filter_edge_3x3]
+normalized_square_3x3 = square_3x3 / 4
+normalized_filter_edge_5x5 = [hpf / 12 for hpf in filter_edge_5x5]
+normalized_square_5x5 = square_5x5 / 12
+
+all_normalized_hpf_list = filter_class_1 + normalized_filter_class_2 + normalized_filter_class_3 + \
+ normalized_filter_edge_3x3 + normalized_filter_edge_5x5 + [normalized_square_3x3, normalized_square_5x5]
+
+normalized_hpf_3x3_list = filter_class_1 + normalized_filter_class_2 + normalized_filter_edge_3x3 + [normalized_square_3x3]
+normalized_hpf_5x5_list = normalized_filter_class_3 + normalized_filter_edge_5x5 + [normalized_square_5x5]
+
+normalized_3x3_list = normalized_filter_edge_3x3 + [normalized_square_3x3]
+normalized_5x5_list = normalized_filter_edge_5x5 + [normalized_square_5x5]
\ No newline at end of file
diff --git a/clean/image/aide/models/utils.py b/clean/image/aide/models/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..b6fc59d6ccf5652f437a491507c44222e042c3e7
--- /dev/null
+++ b/clean/image/aide/models/utils.py
@@ -0,0 +1,116 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+
+# All rights reserved.
+
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+
+import numpy.random as random
+
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+# from MinkowskiEngine import SparseTensor
+
+# class MinkowskiGRN(nn.Module):
+# """ GRN layer for sparse tensors.
+# """
+# def __init__(self, dim):
+# super().__init__()
+# self.gamma = nn.Parameter(torch.zeros(1, dim))
+# self.beta = nn.Parameter(torch.zeros(1, dim))
+
+# def forward(self, x):
+# cm = x.coordinate_manager
+# in_key = x.coordinate_map_key
+
+# Gx = torch.norm(x.F, p=2, dim=0, keepdim=True)
+# Nx = Gx / (Gx.mean(dim=-1, keepdim=True) + 1e-6)
+# return SparseTensor(
+# self.gamma * (x.F * Nx) + self.beta + x.F,
+# coordinate_map_key=in_key,
+# coordinate_manager=cm)
+
+# class MinkowskiDropPath(nn.Module):
+# """ Drop Path for sparse tensors.
+# """
+
+# def __init__(self, drop_prob: float = 0., scale_by_keep: bool = True):
+# super(MinkowskiDropPath, self).__init__()
+# self.drop_prob = drop_prob
+# self.scale_by_keep = scale_by_keep
+
+# def forward(self, x):
+# if self.drop_prob == 0. or not self.training:
+# return x
+# cm = x.coordinate_manager
+# in_key = x.coordinate_map_key
+# keep_prob = 1 - self.drop_prob
+# mask = torch.cat([
+# torch.ones(len(_)) if random.uniform(0, 1) > self.drop_prob
+# else torch.zeros(len(_)) for _ in x.decomposed_coordinates
+# ]).view(-1, 1).to(x.device)
+# if keep_prob > 0.0 and self.scale_by_keep:
+# mask.div_(keep_prob)
+# return SparseTensor(
+# x.F * mask,
+# coordinate_map_key=in_key,
+# coordinate_manager=cm)
+
+# class MinkowskiLayerNorm(nn.Module):
+# """ Channel-wise layer normalization for sparse tensors.
+# """
+
+# def __init__(
+# self,
+# normalized_shape,
+# eps=1e-6,
+# ):
+# super(MinkowskiLayerNorm, self).__init__()
+# self.ln = nn.LayerNorm(normalized_shape, eps=eps)
+# def forward(self, input):
+# output = self.ln(input.F)
+# return SparseTensor(
+# output,
+# coordinate_map_key=input.coordinate_map_key,
+# coordinate_manager=input.coordinate_manager)
+
+class LayerNorm(nn.Module):
+ """ LayerNorm that supports two data formats: channels_last (default) or channels_first.
+ The ordering of the dimensions in the inputs. channels_last corresponds to inputs with
+ shape (batch_size, height, width, channels) while channels_first corresponds to inputs
+ with shape (batch_size, channels, height, width).
+ """
+ def __init__(self, normalized_shape, eps=1e-6, data_format="channels_last"):
+ super().__init__()
+ self.weight = nn.Parameter(torch.ones(normalized_shape))
+ self.bias = nn.Parameter(torch.zeros(normalized_shape))
+ self.eps = eps
+ self.data_format = data_format
+ if self.data_format not in ["channels_last", "channels_first"]:
+ raise NotImplementedError
+ self.normalized_shape = (normalized_shape, )
+
+ def forward(self, x):
+ if self.data_format == "channels_last":
+ return F.layer_norm(x, self.normalized_shape, self.weight, self.bias, self.eps)
+ elif self.data_format == "channels_first":
+ u = x.mean(1, keepdim=True)
+ s = (x - u).pow(2).mean(1, keepdim=True)
+ x = (x - u) / torch.sqrt(s + self.eps)
+ x = self.weight[:, None, None] * x + self.bias[:, None, None]
+ return x
+
+class GRN(nn.Module):
+ """ GRN (Global Response Normalization) layer
+ """
+ def __init__(self, dim):
+ super().__init__()
+ self.gamma = nn.Parameter(torch.zeros(1, 1, 1, dim))
+ self.beta = nn.Parameter(torch.zeros(1, 1, 1, dim))
+
+ def forward(self, x):
+ Gx = torch.norm(x, p=2, dim=(1,2), keepdim=True)
+ Nx = Gx / (Gx.mean(dim=-1, keepdim=True) + 1e-6)
+ return self.gamma * (x * Nx) + self.beta + x
\ No newline at end of file
diff --git a/clean/image/aide/optim_factory.py b/clean/image/aide/optim_factory.py
new file mode 100644
index 0000000000000000000000000000000000000000..27103c2687210f82233d65ba0a46e22bfc1b671d
--- /dev/null
+++ b/clean/image/aide/optim_factory.py
@@ -0,0 +1,222 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+
+# All rights reserved.
+
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+
+import torch
+from torch import optim as optim
+
+from timm.optim.adafactor import Adafactor
+from timm.optim.adahessian import Adahessian
+from timm.optim.adamp import AdamP
+from timm.optim.lookahead import Lookahead
+from timm.optim.nadam import Nadam
+# from timm.optim.novograd import NovoGrad
+# from timm.optim.nvnovograd import NvNovoGrad
+from timm.optim.radam import RAdam
+from timm.optim.rmsprop_tf import RMSpropTF
+from timm.optim.sgdp import SGDP
+
+import json
+
+try:
+ from apex.optimizers import FusedNovoGrad, FusedAdam, FusedLAMB, FusedSGD
+ has_apex = True
+except ImportError:
+ has_apex = False
+
+
+def get_num_layer_for_convnext_single(var_name, depths):
+ """
+ Each layer is assigned distinctive layer ids
+ """
+ if var_name.startswith("downsample_layers"):
+ stage_id = int(var_name.split('.')[1])
+ layer_id = sum(depths[:stage_id]) + 1
+ return layer_id
+
+ elif var_name.startswith("stages"):
+ stage_id = int(var_name.split('.')[1])
+ block_id = int(var_name.split('.')[2])
+ layer_id = sum(depths[:stage_id]) + block_id + 1
+ return layer_id
+
+ else:
+ return sum(depths) + 1
+
+
+def get_num_layer_for_convnext(var_name):
+ """
+ Divide [3, 3, 27, 3] layers into 12 groups; each group is three
+ consecutive blocks, including possible neighboring downsample layers;
+ adapted from https://github.com/microsoft/unilm/blob/master/beit/optim_factory.py
+ """
+ num_max_layer = 12
+ if var_name.startswith("downsample_layers"):
+ stage_id = int(var_name.split('.')[1])
+ if stage_id == 0:
+ layer_id = 0
+ elif stage_id == 1 or stage_id == 2:
+ layer_id = stage_id + 1
+ elif stage_id == 3:
+ layer_id = 12
+ return layer_id
+
+ elif var_name.startswith("stages"):
+ stage_id = int(var_name.split('.')[1])
+ block_id = int(var_name.split('.')[2])
+ if stage_id == 0 or stage_id == 1:
+ layer_id = stage_id + 1
+ elif stage_id == 2:
+ layer_id = 3 + block_id // 3
+ elif stage_id == 3:
+ layer_id = 12
+ return layer_id
+ else:
+ return num_max_layer + 1
+
+class LayerDecayValueAssigner(object):
+ def __init__(self, values, depths=[3,3,27,3], layer_decay_type='single'):
+ self.values = values
+ self.depths = depths
+ self.layer_decay_type = layer_decay_type
+
+ def get_scale(self, layer_id):
+ return self.values[layer_id]
+
+ def get_layer_id(self, var_name):
+ if self.layer_decay_type == 'single':
+ return get_num_layer_for_convnext_single(var_name, self.depths)
+ else:
+ return get_num_layer_for_convnext(var_name)
+
+
+def get_parameter_groups(model, weight_decay=1e-5, skip_list=(), get_num_layer=None, get_layer_scale=None):
+ parameter_group_names = {}
+ parameter_group_vars = {}
+
+ for name, param in model.named_parameters():
+ if not param.requires_grad:
+ continue # frozen weights
+ if len(param.shape) == 1 or name.endswith(".bias") or name in skip_list or \
+ name.endswith(".gamma") or name.endswith(".beta"):
+ group_name = "no_decay"
+ this_weight_decay = 0.
+ else:
+ group_name = "decay"
+ this_weight_decay = weight_decay
+ if get_num_layer is not None:
+ layer_id = get_num_layer(name)
+ group_name = "layer_%d_%s" % (layer_id, group_name)
+ else:
+ layer_id = None
+
+ if group_name not in parameter_group_names:
+ if get_layer_scale is not None:
+ scale = get_layer_scale(layer_id)
+ else:
+ scale = 1.
+
+ parameter_group_names[group_name] = {
+ "weight_decay": this_weight_decay,
+ "params": [],
+ "lr_scale": scale
+ }
+ parameter_group_vars[group_name] = {
+ "weight_decay": this_weight_decay,
+ "params": [],
+ "lr_scale": scale
+ }
+
+ parameter_group_vars[group_name]["params"].append(param)
+ parameter_group_names[group_name]["params"].append(name)
+ print("Param groups = %s" % json.dumps(parameter_group_names, indent=2))
+ return list(parameter_group_vars.values())
+
+
+def create_optimizer(args, model, get_num_layer=None, get_layer_scale=None, filter_bias_and_bn=True, skip_list=None):
+ opt_lower = args.opt.lower()
+ weight_decay = args.weight_decay
+ # if weight_decay and filter_bias_and_bn:
+ if filter_bias_and_bn:
+ skip = {}
+ if skip_list is not None:
+ skip = skip_list
+ elif hasattr(model, 'no_weight_decay'):
+ skip = model.no_weight_decay()
+ parameters = get_parameter_groups(model, weight_decay, skip, get_num_layer, get_layer_scale)
+ weight_decay = 0.
+ else:
+ parameters = model.parameters()
+
+ if 'fused' in opt_lower:
+ assert has_apex and torch.cuda.is_available(), 'APEX and CUDA required for fused optimizers'
+
+ opt_args = dict(lr=args.lr, weight_decay=weight_decay)
+ if hasattr(args, 'opt_eps') and args.opt_eps is not None:
+ opt_args['eps'] = args.opt_eps
+ if hasattr(args, 'opt_betas') and args.opt_betas is not None:
+ opt_args['betas'] = args.opt_betas
+
+ opt_split = opt_lower.split('_')
+ opt_lower = opt_split[-1]
+ if opt_lower == 'sgd' or opt_lower == 'nesterov':
+ opt_args.pop('eps', None)
+ optimizer = optim.SGD(parameters, momentum=args.momentum, nesterov=True, **opt_args)
+ elif opt_lower == 'momentum':
+ opt_args.pop('eps', None)
+ optimizer = optim.SGD(parameters, momentum=args.momentum, nesterov=False, **opt_args)
+ elif opt_lower == 'adam':
+ optimizer = optim.Adam(parameters, **opt_args)
+ elif opt_lower == 'adamw':
+ optimizer = optim.AdamW(parameters, **opt_args)
+ elif opt_lower == 'nadam':
+ optimizer = Nadam(parameters, **opt_args)
+ elif opt_lower == 'radam':
+ optimizer = RAdam(parameters, **opt_args)
+ elif opt_lower == 'adamp':
+ optimizer = AdamP(parameters, wd_ratio=0.01, nesterov=True, **opt_args)
+ elif opt_lower == 'sgdp':
+ optimizer = SGDP(parameters, momentum=args.momentum, nesterov=True, **opt_args)
+ elif opt_lower == 'adadelta':
+ optimizer = optim.Adadelta(parameters, **opt_args)
+ elif opt_lower == 'adafactor':
+ if not args.lr:
+ opt_args['lr'] = None
+ optimizer = Adafactor(parameters, **opt_args)
+ elif opt_lower == 'adahessian':
+ optimizer = Adahessian(parameters, **opt_args)
+ elif opt_lower == 'rmsprop':
+ optimizer = optim.RMSprop(parameters, alpha=0.9, momentum=args.momentum, **opt_args)
+ elif opt_lower == 'rmsproptf':
+ optimizer = RMSpropTF(parameters, alpha=0.9, momentum=args.momentum, **opt_args)
+ elif opt_lower == 'novograd':
+ optimizer = NovoGrad(parameters, **opt_args)
+ elif opt_lower == 'nvnovograd':
+ optimizer = NvNovoGrad(parameters, **opt_args)
+ elif opt_lower == 'fusedsgd':
+ opt_args.pop('eps', None)
+ optimizer = FusedSGD(parameters, momentum=args.momentum, nesterov=True, **opt_args)
+ elif opt_lower == 'fusedmomentum':
+ opt_args.pop('eps', None)
+ optimizer = FusedSGD(parameters, momentum=args.momentum, nesterov=False, **opt_args)
+ elif opt_lower == 'fusedadam':
+ optimizer = FusedAdam(parameters, adam_w_mode=False, **opt_args)
+ elif opt_lower == 'fusedadamw':
+ optimizer = FusedAdam(parameters, adam_w_mode=True, **opt_args)
+ elif opt_lower == 'fusedlamb':
+ optimizer = FusedLAMB(parameters, **opt_args)
+ elif opt_lower == 'fusednovograd':
+ opt_args.setdefault('betas', (0.95, 0.98))
+ optimizer = FusedNovoGrad(parameters, **opt_args)
+ else:
+ assert False and "Invalid optimizer"
+
+ if len(opt_split) > 1:
+ if opt_split[0] == 'lookahead':
+ optimizer = Lookahead(optimizer)
+
+ return optimizer
diff --git a/clean/image/aide/requirements.txt b/clean/image/aide/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d072b8dd2b1fccc6dfd685d5e7dbaa38598753de
--- /dev/null
+++ b/clean/image/aide/requirements.txt
@@ -0,0 +1,37 @@
+einops==0.6.1
+fairscale==0.4.13
+filelock==3.13.1
+ftfy==6.1.3
+h5py==3.10.0
+imgaug==0.2.6
+keras==2.11.0
+kornia==0.7.2
+kornia_rs==0.1.2
+lmdb==1.4.1
+matplotlib==3.7.4
+matplotlib-inline==0.1.6
+numpy==1.24.3
+omegaconf==2.3.0
+open-clip-torch==2.24.0
+openai-clip==1.0.1
+openpyxl==3.1.2
+pandas==2.0.3
+Pillow==9.5.0
+safetensors==0.4.1
+scikit-image==0.20.0
+scikit-learn==1.3.2
+scipy==1.9.1
+sentencepiece==0.2.0
+streamlit==1.30.0
+tenacity==8.2.3
+tensorboard==2.11.2
+tensorboard-data-server==0.6.1
+tensorboard-plugin-wit==1.8.1
+tensorboardX==2.6.2.2
+timm==0.9.6
+torch==1.11.0
+torch-fidelity==0.3.0
+torchmetrics==0.6.0
+torchsummary==1.5.1
+torchvision==0.12.0
+tqdm==4.66.1
diff --git a/clean/image/aide/scripts/eval.sh b/clean/image/aide/scripts/eval.sh
new file mode 100644
index 0000000000000000000000000000000000000000..6438f26d982fa4548b1299436966a54ec2e39998
--- /dev/null
+++ b/clean/image/aide/scripts/eval.sh
@@ -0,0 +1,21 @@
+
+GPU_NUM=8
+WORLD_SIZE=1
+RANK=0
+MASTER_ADDR=localhost
+MASTER_PORT=29572
+
+DISTRIBUTED_ARGS="
+ --nproc_per_node $GPU_NUM \
+ --nnodes $WORLD_SIZE \
+ --node_rank $RANK \
+ --master_addr $MASTER_ADDR \
+ --master_port $MASTER_PORT
+"
+PY_ARGS=${@:1} # Any other arguments
+python -m torch.distributed.launch $DISTRIBUTED_ARGS main_finetune.py \
+ --model AIDE \
+ --batch_size 32 \
+ --blr 5e-4 \
+ --epochs 5 \
+ ${PY_ARGS}
diff --git a/clean/image/aide/scripts/train.sh b/clean/image/aide/scripts/train.sh
new file mode 100644
index 0000000000000000000000000000000000000000..d781a2a63c06acfcb8123369486404ec3a4aa9ee
--- /dev/null
+++ b/clean/image/aide/scripts/train.sh
@@ -0,0 +1,24 @@
+
+GPU_NUM=8
+WORLD_SIZE=1
+RANK=0
+MASTER_ADDR=localhost
+MASTER_PORT=29512
+
+
+DISTRIBUTED_ARGS="
+ --nproc_per_node $GPU_NUM \
+ --nnodes $WORLD_SIZE \
+ --node_rank $RANK \
+ --master_addr $MASTER_ADDR \
+ --master_port $MASTER_PORT
+"
+
+PY_ARGS=${@:1} # Any other arguments
+
+python -m torch.distributed.launch $DISTRIBUTED_ARGS main_finetune.py \
+ --model AIDE \
+ --batch_size 32 \
+ --blr 1e-4 \
+ --epochs 20 \
+ ${PY_ARGS}
diff --git a/clean/image/aide/utils.py b/clean/image/aide/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..923e5d0242e3032e2fd3e9af2ffa6cf0ffa425da
--- /dev/null
+++ b/clean/image/aide/utils.py
@@ -0,0 +1,578 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+
+# All rights reserved.
+
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+
+import os
+import math
+import time
+from collections import defaultdict, deque
+import datetime
+import numpy as np
+from timm.utils import get_state_dict
+
+from pathlib import Path
+
+import torch
+import torch.distributed as dist
+from torch import inf
+
+from tensorboardX import SummaryWriter
+from collections import OrderedDict
+
+def str2bool(v):
+ """
+ Converts string to bool type; enables command line
+ arguments in the format of '--arg1 true --arg2 false'
+ """
+ if isinstance(v, bool):
+ return v
+ if v.lower() in ('yes', 'true', 't', 'y', '1'):
+ return True
+ elif v.lower() in ('no', 'false', 'f', 'n', '0'):
+ return False
+ else:
+ raise argparse.ArgumentTypeError('Boolean value expected.')
+
+class SmoothedValue(object):
+ """Track a series of values and provide access to smoothed values over a
+ window or the global series average.
+ """
+
+ def __init__(self, window_size=20, fmt=None):
+ if fmt is None:
+ fmt = "{median:.4f} ({global_avg:.4f})"
+ self.deque = deque(maxlen=window_size)
+ self.total = 0.0
+ self.count = 0
+ self.fmt = fmt
+
+ def update(self, value, n=1):
+ self.deque.append(value)
+ self.count += n
+ self.total += value * n
+
+ def synchronize_between_processes(self):
+ """
+ Warning: does not synchronize the deque!
+ """
+ if not is_dist_avail_and_initialized():
+ return
+ t = torch.tensor([self.count, self.total], dtype=torch.float64, device='cuda')
+ dist.barrier()
+ dist.all_reduce(t)
+ t = t.tolist()
+ self.count = int(t[0])
+ self.total = t[1]
+
+ @property
+ def median(self):
+ d = torch.tensor(list(self.deque))
+ return d.median().item()
+
+ @property
+ def avg(self):
+ d = torch.tensor(list(self.deque), dtype=torch.float32)
+ return d.mean().item()
+
+ @property
+ def global_avg(self):
+ return self.total / self.count
+
+ @property
+ def max(self):
+ return max(self.deque)
+
+ @property
+ def value(self):
+ return self.deque[-1]
+
+ def __str__(self):
+ return self.fmt.format(
+ median=self.median,
+ avg=self.avg,
+ global_avg=self.global_avg,
+ max=self.max,
+ value=self.value)
+
+
+class MetricLogger(object):
+ def __init__(self, delimiter="\t"):
+ self.meters = defaultdict(SmoothedValue)
+ self.delimiter = delimiter
+
+ def update(self, **kwargs):
+ for k, v in kwargs.items():
+ if v is None:
+ continue
+ if isinstance(v, torch.Tensor):
+ v = v.item()
+ assert isinstance(v, (float, int))
+ self.meters[k].update(v)
+
+ def __getattr__(self, attr):
+ if attr in self.meters:
+ return self.meters[attr]
+ if attr in self.__dict__:
+ return self.__dict__[attr]
+ raise AttributeError("'{}' object has no attribute '{}'".format(
+ type(self).__name__, attr))
+
+ def __str__(self):
+ loss_str = []
+ for name, meter in self.meters.items():
+ loss_str.append(
+ "{}: {}".format(name, str(meter))
+ )
+ return self.delimiter.join(loss_str)
+
+ def synchronize_between_processes(self):
+ for meter in self.meters.values():
+ meter.synchronize_between_processes()
+
+ def add_meter(self, name, meter):
+ self.meters[name] = meter
+
+ def log_every(self, iterable, print_freq, header=None):
+ i = 0
+ if not header:
+ header = ''
+ start_time = time.time()
+ end = time.time()
+ iter_time = SmoothedValue(fmt='{avg:.4f}')
+ data_time = SmoothedValue(fmt='{avg:.4f}')
+ space_fmt = ':' + str(len(str(len(iterable)))) + 'd'
+ log_msg = [
+ header,
+ '[{0' + space_fmt + '}/{1}]',
+ 'eta: {eta}',
+ '{meters}',
+ 'time: {time}',
+ 'data: {data}'
+ ]
+ if torch.cuda.is_available():
+ log_msg.append('max mem: {memory:.0f}')
+ log_msg = self.delimiter.join(log_msg)
+ MB = 1024.0 * 1024.0
+ for obj in iterable:
+ data_time.update(time.time() - end)
+ yield obj
+ iter_time.update(time.time() - end)
+ if i % print_freq == 0 or i == len(iterable) - 1:
+ eta_seconds = iter_time.global_avg * (len(iterable) - i)
+ eta_string = str(datetime.timedelta(seconds=int(eta_seconds)))
+ if torch.cuda.is_available():
+ print(log_msg.format(
+ i, len(iterable), eta=eta_string,
+ meters=str(self),
+ time=str(iter_time), data=str(data_time),
+ memory=torch.cuda.max_memory_allocated() / MB))
+ else:
+ print(log_msg.format(
+ i, len(iterable), eta=eta_string,
+ meters=str(self),
+ time=str(iter_time), data=str(data_time)))
+ i += 1
+ end = time.time()
+ total_time = time.time() - start_time
+ total_time_str = str(datetime.timedelta(seconds=int(total_time)))
+ print('{} Total time: {} ({:.4f} s / it)'.format(
+ header, total_time_str, total_time / len(iterable)))
+
+
+class TensorboardLogger(object):
+ def __init__(self, log_dir):
+ self.writer = SummaryWriter(logdir=log_dir)
+ self.step = 0
+
+ def set_step(self, step=None):
+ if step is not None:
+ self.step = step
+ else:
+ self.step += 1
+
+ def update(self, head='scalar', step=None, **kwargs):
+ for k, v in kwargs.items():
+ if v is None:
+ continue
+ if isinstance(v, torch.Tensor):
+ v = v.item()
+ assert isinstance(v, (float, int))
+ self.writer.add_scalar(head + "/" + k, v, self.step if step is None else step)
+
+ def flush(self):
+ self.writer.flush()
+
+
+class WandbLogger(object):
+ def __init__(self, args):
+ self.args = args
+
+ try:
+ import wandb
+ self._wandb = wandb
+ except ImportError:
+ raise ImportError(
+ "To use the Weights and Biases Logger please install wandb."
+ "Run `pip install wandb` to install it."
+ )
+
+ # Initialize a W&B run
+ if self._wandb.run is None:
+ self._wandb.init(
+ project=args.project,
+ config=args
+ )
+
+ def log_epoch_metrics(self, metrics, commit=True):
+ """
+ Log train/test metrics onto W&B.
+ """
+ # Log number of model parameters as W&B summary
+ self._wandb.summary['n_parameters'] = metrics.get('n_parameters', None)
+ metrics.pop('n_parameters', None)
+
+ # Log current epoch
+ self._wandb.log({'epoch': metrics.get('epoch')}, commit=False)
+ metrics.pop('epoch')
+
+ for k, v in metrics.items():
+ if 'train' in k:
+ self._wandb.log({f'Global Train/{k}': v}, commit=False)
+ elif 'test' in k:
+ self._wandb.log({f'Global Test/{k}': v}, commit=False)
+
+ self._wandb.log({})
+
+ def log_checkpoints(self):
+ output_dir = self.args.output_dir
+ model_artifact = self._wandb.Artifact(
+ self._wandb.run.id + "_model", type="model"
+ )
+
+ model_artifact.add_dir(output_dir)
+ self._wandb.log_artifact(model_artifact, aliases=["latest", "best"])
+
+ def set_steps(self):
+ # Set global training step
+ self._wandb.define_metric('Rank-0 Batch Wise/*', step_metric='Rank-0 Batch Wise/global_train_step')
+ # Set epoch-wise step
+ self._wandb.define_metric('Global Train/*', step_metric='epoch')
+ self._wandb.define_metric('Global Test/*', step_metric='epoch')
+
+
+def setup_for_distributed(is_master):
+ """
+ This function disables printing when not in master process
+ """
+ import builtins as __builtin__
+ builtin_print = __builtin__.print
+
+ def print(*args, **kwargs):
+ force = kwargs.pop('force', False)
+ if is_master or force:
+ builtin_print(*args, **kwargs)
+
+ __builtin__.print = print
+
+
+def is_dist_avail_and_initialized():
+ if not dist.is_available():
+ return False
+ if not dist.is_initialized():
+ return False
+ return True
+
+
+def get_world_size():
+ if not is_dist_avail_and_initialized():
+ return 1
+ return dist.get_world_size()
+
+
+def get_rank():
+ if not is_dist_avail_and_initialized():
+ return 0
+ return dist.get_rank()
+
+
+def is_main_process():
+ return get_rank() == 0
+
+
+def save_on_master(*args, **kwargs):
+ if is_main_process():
+ torch.save(*args, **kwargs)
+
+def init_distributed_mode(args):
+
+ if args.dist_on_itp:
+ args.rank = int(os.environ['OMPI_COMM_WORLD_RANK'])
+ args.world_size = int(os.environ['OMPI_COMM_WORLD_SIZE'])
+ args.gpu = int(os.environ['OMPI_COMM_WORLD_LOCAL_RANK'])
+ args.dist_url = "tcp://%s:%s" % (os.environ['MASTER_ADDR'], os.environ['MASTER_PORT'])
+ os.environ['LOCAL_RANK'] = str(args.gpu)
+ os.environ['RANK'] = str(args.rank)
+ os.environ['WORLD_SIZE'] = str(args.world_size)
+ # ["RANK", "WORLD_SIZE", "MASTER_ADDR", "MASTER_PORT", "LOCAL_RANK"]
+ elif 'RANK' in os.environ and 'WORLD_SIZE' in os.environ:
+ args.rank = int(os.environ["RANK"])
+ args.world_size = int(os.environ['WORLD_SIZE'])
+ args.gpu = int(os.environ['LOCAL_RANK'])
+ elif 'SLURM_PROCID' in os.environ:
+ args.rank = int(os.environ['SLURM_PROCID'])
+ args.gpu = args.rank % torch.cuda.device_count()
+
+ os.environ['RANK'] = str(args.rank)
+ os.environ['LOCAL_RANK'] = str(args.gpu)
+ os.environ['WORLD_SIZE'] = str(args.world_size)
+ else:
+ print('Not using distributed mode')
+ args.distributed = False
+ return
+
+ args.distributed = True
+
+ torch.cuda.set_device(args.gpu)
+ args.dist_backend = 'nccl'
+ print('| distributed init (rank {}): {}, gpu {}'.format(
+ args.rank, args.dist_url, args.gpu), flush=True)
+ torch.distributed.init_process_group(backend=args.dist_backend, init_method=args.dist_url,
+ world_size=args.world_size, rank=args.rank)
+ torch.distributed.barrier()
+ setup_for_distributed(args.rank == 0)
+
+def all_reduce_mean(x):
+ world_size = get_world_size()
+ if world_size > 1:
+ x_reduce = torch.tensor(x).cuda()
+ dist.all_reduce(x_reduce)
+ x_reduce /= world_size
+ return x_reduce.item()
+ else:
+ return x
+
+def load_state_dict(model, state_dict, prefix='', ignore_missing="relative_position_index"):
+ missing_keys = []
+ unexpected_keys = []
+ error_msgs = []
+ # copy state_dict so _load_from_state_dict can modify it
+ metadata = getattr(state_dict, '_metadata', None)
+ state_dict = state_dict.copy()
+ if metadata is not None:
+ state_dict._metadata = metadata
+
+ def load(module, prefix=''):
+ local_metadata = {} if metadata is None else metadata.get(
+ prefix[:-1], {})
+ module._load_from_state_dict(
+ state_dict, prefix, local_metadata, True, missing_keys, unexpected_keys, error_msgs)
+ for name, child in module._modules.items():
+ if child is not None:
+ load(child, prefix + name + '.')
+
+ load(model, prefix=prefix)
+
+ warn_missing_keys = []
+ ignore_missing_keys = []
+ for key in missing_keys:
+ keep_flag = True
+ for ignore_key in ignore_missing.split('|'):
+ if ignore_key in key:
+ keep_flag = False
+ break
+ if keep_flag:
+ warn_missing_keys.append(key)
+ else:
+ ignore_missing_keys.append(key)
+
+ missing_keys = warn_missing_keys
+
+ if len(missing_keys) > 0:
+ print("Weights of {} not initialized from pretrained model: {}".format(
+ model.__class__.__name__, missing_keys))
+ if len(unexpected_keys) > 0:
+ print("Weights from pretrained model not used in {}: {}".format(
+ model.__class__.__name__, unexpected_keys))
+ if len(ignore_missing_keys) > 0:
+ print("Ignored weights of {} not initialized from pretrained model: {}".format(
+ model.__class__.__name__, ignore_missing_keys))
+ if len(error_msgs) > 0:
+ print('\n'.join(error_msgs))
+
+
+class NativeScalerWithGradNormCount:
+ state_dict_key = "amp_scaler"
+
+ def __init__(self):
+ self._scaler = torch.cuda.amp.GradScaler()
+
+ def __call__(self, loss, optimizer, clip_grad=None, parameters=None, create_graph=False, update_grad=True):
+ self._scaler.scale(loss).backward(create_graph=create_graph)
+ if update_grad:
+ if clip_grad is not None:
+ assert parameters is not None
+ self._scaler.unscale_(optimizer) # unscale the gradients of optimizer's assigned params in-place
+ norm = torch.nn.utils.clip_grad_norm_(parameters, clip_grad)
+ else:
+ self._scaler.unscale_(optimizer)
+ norm = get_grad_norm_(parameters)
+ self._scaler.step(optimizer)
+ self._scaler.update()
+ else:
+ norm = None
+ return norm
+
+ def state_dict(self):
+ return self._scaler.state_dict()
+
+ def load_state_dict(self, state_dict):
+ self._scaler.load_state_dict(state_dict)
+
+
+def get_grad_norm_(parameters, norm_type: float = 2.0) -> torch.Tensor:
+ if isinstance(parameters, torch.Tensor):
+ parameters = [parameters]
+ parameters = [p for p in parameters if p.grad is not None]
+ norm_type = float(norm_type)
+ if len(parameters) == 0:
+ return torch.tensor(0.)
+ device = parameters[0].grad.device
+ if norm_type == inf:
+ total_norm = max(p.grad.detach().abs().max().to(device) for p in parameters)
+ else:
+ total_norm = torch.norm(torch.stack([torch.norm(p.grad.detach(), norm_type).to(device) for p in parameters]), norm_type)
+ return total_norm
+
+def save_model(args, epoch, model, model_without_ddp, optimizer, loss_scaler, model_ema=None):
+ output_dir = Path(args.output_dir)
+ epoch_name = str(epoch)
+ checkpoint_paths = [output_dir / ('checkpoint-%s.pth' % epoch_name)]
+ for checkpoint_path in checkpoint_paths:
+ to_save = {
+ 'model': model_without_ddp.state_dict(),
+ 'optimizer': optimizer.state_dict(),
+ 'epoch': epoch,
+ 'scaler': loss_scaler.state_dict(),
+ 'args': args,
+ }
+
+ if model_ema is not None:
+ to_save['model_ema'] = get_state_dict(model_ema)
+
+ save_on_master(to_save, checkpoint_path)
+
+ if is_main_process() and isinstance(epoch, int):
+ to_del = epoch - args.save_ckpt_num * args.save_ckpt_freq
+ old_ckpt = output_dir / ('checkpoint-%s.pth' % to_del)
+ if os.path.exists(old_ckpt):
+ os.remove(old_ckpt)
+
+def auto_load_model(args, model, model_without_ddp, optimizer, loss_scaler, model_ema=None):
+ output_dir = Path(args.output_dir)
+ if args.auto_resume and len(args.resume) == 0:
+ import glob
+ all_checkpoints = glob.glob(os.path.join(output_dir, 'checkpoint-*.pth'))
+ latest_ckpt = -1
+ for ckpt in all_checkpoints:
+ t = ckpt.split('-')[-1].split('.')[0]
+ if t.isdigit():
+ latest_ckpt = max(int(t), latest_ckpt)
+ if latest_ckpt >= 0:
+ args.resume = os.path.join(output_dir, 'checkpoint-%d.pth' % latest_ckpt)
+ print("Auto resume checkpoint: %s" % args.resume)
+
+ if args.resume:
+ if args.resume.startswith('https'):
+ checkpoint = torch.hub.load_state_dict_from_url(
+ args.resume, map_location='cpu', check_hash=True)
+ else:
+ checkpoint = torch.load(args.resume, map_location='cpu')
+
+ model_without_ddp.load_state_dict(checkpoint['model'])
+ print("Resume checkpoint %s" % args.resume)
+ if 'optimizer' in checkpoint and 'epoch' in checkpoint:
+ optimizer.load_state_dict(checkpoint['optimizer'])
+ if not isinstance(checkpoint['epoch'], str): # does not support resuming with 'best', 'best-ema'
+ args.start_epoch = checkpoint['epoch'] + 1
+ else:
+ assert args.eval, 'Does not support resuming with checkpoint-best'
+ if hasattr(args, 'model_ema') and args.model_ema:
+ if 'model_ema' in checkpoint.keys():
+ model_ema.ema.load_state_dict(checkpoint['model_ema'])
+ else:
+ model_ema.ema.load_state_dict(checkpoint['model'])
+ if 'scaler' in checkpoint:
+ loss_scaler.load_state_dict(checkpoint['scaler'])
+ print("With optim & sched!")
+
+def cosine_scheduler(base_value, final_value, epochs, niter_per_ep, warmup_epochs=0,
+ start_warmup_value=0, warmup_steps=-1):
+ warmup_schedule = np.array([])
+ warmup_iters = warmup_epochs * niter_per_ep
+ if warmup_steps > 0:
+ warmup_iters = warmup_steps
+ print("Set warmup steps = %d" % warmup_iters)
+ if warmup_epochs > 0:
+ warmup_schedule = np.linspace(start_warmup_value, base_value, warmup_iters)
+
+ iters = np.arange(epochs * niter_per_ep - warmup_iters)
+ schedule = np.array(
+ [final_value + 0.5 * (base_value - final_value) * (1 + math.cos(math.pi * i / (len(iters)))) for i in iters])
+
+ schedule = np.concatenate((warmup_schedule, schedule))
+
+ assert len(schedule) == epochs * niter_per_ep
+ return schedule
+
+def adjust_learning_rate(optimizer, epoch, args):
+ """Decay the learning rate with half-cycle cosine after warmup"""
+ if epoch < args.warmup_epochs:
+ lr = args.lr * epoch / args.warmup_epochs
+ else:
+ lr = args.min_lr + (args.lr - args.min_lr) * 0.5 * \
+ (1. + math.cos(math.pi * (epoch - args.warmup_epochs) / (args.epochs - args.warmup_epochs)))
+ for param_group in optimizer.param_groups:
+ if "lr_scale" in param_group:
+ param_group["lr"] = lr * param_group["lr_scale"]
+ else:
+ param_group["lr"] = lr
+ return lr
+
+def remap_checkpoint_keys(ckpt):
+ new_ckpt = OrderedDict()
+ for k, v in ckpt.items():
+ if k.startswith('encoder'):
+ k = '.'.join(k.split('.')[1:]) # remove encoder in the name
+ if k.endswith('kernel'):
+ k = '.'.join(k.split('.')[:-1]) # remove kernel in the name
+ new_k = k + '.weight'
+ if len(v.shape) == 3: # resahpe standard convolution
+ kv, in_dim, out_dim = v.shape
+ ks = int(math.sqrt(kv))
+ new_ckpt[new_k] = v.permute(2, 1, 0).\
+ reshape(out_dim, in_dim, ks, ks).transpose(3, 2)
+ elif len(v.shape) == 2: # reshape depthwise convolution
+ kv, dim = v.shape
+ ks = int(math.sqrt(kv))
+ new_ckpt[new_k] = v.permute(1, 0).\
+ reshape(dim, 1, ks, ks).transpose(3, 2)
+ continue
+ elif 'ln' in k or 'linear' in k:
+ k = k.split('.')
+ k.pop(-2) # remove ln and linear in the name
+ new_k = '.'.join(k)
+ else:
+ new_k = k
+ new_ckpt[new_k] = v
+
+ # reshape grn affine parameters and biases
+ for k, v in new_ckpt.items():
+ if k.endswith('bias') and len(v.shape) != 1:
+ new_ckpt[k] = v.reshape(-1)
+ # elif 'grn' in k:
+ # new_ckpt[k] = v.unsqueeze(0).unsqueeze(1)
+ return new_ckpt
\ No newline at end of file
diff --git a/clean/image/cospy/.gitignore b/clean/image/cospy/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..e590da532e2c928cbc4f3fab8dd5cd48f5051a58
--- /dev/null
+++ b/clean/image/cospy/.gitignore
@@ -0,0 +1,11 @@
+__pycache__/
+ckpt/
+data/test/AIGCDetectionBenchMark/test
+data/test/Co-Spy-Bench/real_image_examples
+data/test/Co-Spy-Bench/synthetic
+data/train/progan/train
+data/train/progan/val
+data/train/sd-v1_4/mscoco2017
+data/train/sd-v1_4/stable-diffusion-v1-4
+pretrained/progan
+pretrained/sd-v1_4
diff --git a/clean/image/cospy/LICENSE b/clean/image/cospy/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..4ba4b5e9c15b4c9be378ae45506f49839fd33716
--- /dev/null
+++ b/clean/image/cospy/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2025 Siyuan Cheng
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/clean/image/cospy/README.md b/clean/image/cospy/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..308b0ca684fa2fea7207024dbe1243f9808ce7fa
--- /dev/null
+++ b/clean/image/cospy/README.md
@@ -0,0 +1,337 @@
+
+
+
+
+# CO-SPY: Combining Semantic and Pixel Features to Detect Synthetic Images by AI
+
+
+
+
+
+
+
+Table of Contents
+=================
+- [Table of Contents](#table-of-contents)
+ - [Overview](#overview)
+ - [CO-SPY-Bench](#co-spy-bench)
+ - [Main Code Architecutre](#main-code-architecture)
+ - [Environments](#environments)
+ - [Prerequisites](#prerequisites)
+ - [Download Datasets](#download-datasets)
+ - [Download Pre-trained Weights](#download-pre-trained-weights)
+ - [Experiments](#experiments)
+ - [Evaluation of Pre-trained Detectors](#evaluation-of-pre-trained-detectors)
+ - [Inference on a Single Image](#inference-on-a-single-image)
+ - [Training](#training)
+ - [Citation](#citation)
+ - [Acknowledgement](#acknowledgement)
+
+## Overview
+- This is the official implementation for CVPR 2025 paper "[CO-SPY: Combining Semantic and Pixel Features to Detect Synthetic Images by AI](https://openaccess.thecvf.com/content/CVPR2025/html/Cheng_CO-SPY_Combining_Semantic_and_Pixel_Features_to_Detect_Synthetic_Images_CVPR_2025_paper.html)".
+- [[arXiv](https://arxiv.org/abs/2503.18286)\] | \[[poster](https://www.cs.purdue.edu/homes/cheng535/static/slides/COSPY_poster.pdf)\]
+
+
+
+## CO-SPY-Bench
+We have released our benchmark on [Huggingface](https://huggingface.co/datasets/ruojiruoli/Co-Spy-Bench), designed to offer diverse and comprehensive coverage of the latest generative models:
+- Captions are sourced from five real-world datasets: MSCOCO2017, CC3M, Flickr, TextCaps, and SBU.
+- Synthetic images are generated using 22 different models, covering a wide range of architectures.
+- Diverse generation parameters, such as diffusion steps and guidance scales, are used to enrich variability.
+
+## Main Code Architecture
+ .
+ ├── data # Dataset folder
+ │ ├── in_the_wild # CO-SPY-Bench in-the-wild synthetic samples
+ │ ├── test # Test dataset (CO-SPY-Bench & AIGCDetectionBenchMark)
+ │ └── train # Training dataset (DRCT-2M & CNNDet)
+ ├── dataSets # Various dataset classes
+ ├── detectors # Various detector classes
+ │ ├── progan # Detectors for CNNDet training set
+ │ └── sd-v1_4 # Detectors for DRCT-2M training set
+ ├── pretrained # Pre-trained weights
+ ├── main.py # Main function
+ ├── evaluate.py # Evaluation function
+ ├── main.py # Main function (Entry point)
+ ├── train.py # Training function
+ ├── train.sh # Recommended training script
+ └── utils.py # Utility functions
+
+## Environments
+```bash
+# Create python environment (optional)
+conda env create -f environment.yml
+source activate cospy
+```
+
+## Prerequisites
+Please download the required datasets and pre-trained weights for full evaluation.
+
+### Download Datasets
+Make sure you have `7z` an `unzip` installed. You can install them via conda:
+```bash
+conda install p7zip
+conda install unzip
+```
+
+To download the training and test datasets, run the following commands respectively:
+```bash
+###############################
+# Download the training dataset
+###############################
+# Download CNNDet (ProGAN) training set
+cd data/train/progan
+sh download.sh
+
+# Download DRCT-2M (Stable Diffusion v1.4) training set
+cd data/train/sd-v1_4
+sh download.sh
+
+###############################
+# Download the test dataset
+###############################
+# Download AIGCDetectionBenchMark test set
+cd data/test/AIGCDetectionBenchMark
+python download.py
+
+# Download CO-SPY-Bench test set
+cd data/test/Co-Spy-Bench
+sh download.sh
+```
+
+Finally, the directory structure should look like this:
+```
+.
+├── data
+│ ├── test
+│ │ ├── AIGCDetectionBenchMark
+│ │ │ └── test
+│ │ └── Co-Spy-Bench
+│ │ ├── real_image_examples
+│ │ └── synthetic
+│ └── train
+│ ├── progan
+│ │ ├── train
+│ │ └── val
+│ └── sd-v1_4
+│ ├── mscoco2017
+│ └── stable_diffusion_v1-4
+```
+*Note: Please ensure the use of these datasets complies with the original licenses.*
+
+
+> Please refer to `data/in_the_wild/README.md` for detailed instructions on accessing the **CO-SPY-Bench in-the-wild synthetic samples**.
+>
+> *Note: Some samples are temporarily unavailable (e.g., [instavibe.ai](https://www.instavibe.ai/)). As we cannot confirm whether redistributing these images would violate the original sources’ intellectual property rights, we choose not to release them at this time. This decision and its rationale are discussed in [Issue #6](https://github.com/Megum1/CO-SPY/issues/6). We apologize for any inconvenience this may cause.*
+
+
+### Download Pre-trained Weights
+```bash
+# Download the pre-trained weights
+cd pretrained
+sh download.sh
+# It contains the pre-trained weights on CNNDet (`progan`) and DRCT-2M (`sd-v1_4`) training sets.
+```
+
+
+
+## Experiments
+We provide the source code for training and evaluating the CO-SPY detector.
+
+### Evaluation of Pre-trained Detectors
+To evaluate the pre-trained detector (trained on DRCT-2M (`sd-v1_4`)) on [CO-SPY-Bench](https://huggingface.co/datasets/ruojiruoli/Co-Spy-Bench), run
+```bash
+python main.py --gpu 0 --phase eval --train_dataset sd-v1_4 --pretrain
+```
+When finished, evaluation results will be saved to `ckpt/sd-v1_4/fusion/pretrain_Co-Spy-Bench`.
+
+
+📊 Results (click to expand)
+
+
+Results are highly consistent with the original results reported in Table 2, with slight differences arising from improvements in hyper-parameter settings.
+Original results can be referred to in Issue #7 .
+
+
+## Average Precision (AP)
+| Detector | CC3M | FLICKR | MSCOCO | TEXTCAPS | SBU |
+|----------|------|--------|---------|----------|-----|
+| ldm-text2im-large-256 | 95.61 | 99.93 | 99.87 | 98.82 | 99.73 |
+| stable-diffusion-v1-4 | 91.95 | 99.74 | 99.81 | 97.82 | 98.66 |
+| stable-diffusion-v1-5 | 91.44 | 99.71 | 99.67 | 97.46 | 98.66 |
+| SSD-1B | 89.07 | 99.33 | 99.17 | 95.17 | 98.22 |
+| tiny-sd | 85.52 | 99.11 | 98.92 | 95.41 | 98.01 |
+| SegMoE-SD-4x2-v0 | 90.09 | 99.49 | 99.49 | 96.93 | 98.72 |
+| small-sd | 86.91 | 99.08 | 99.14 | 95.62 | 98.28 |
+| stable-diffusion-2-1 | 90.83 | 99.61 | 99.73 | 97.74 | 98.53 |
+| stable-diffusion-3-medium-diffusers | 86.56 | 99.13 | 99.06 | 94.67 | 97.86 |
+| sdxl-turbo | 97.09 | 99.86 | 99.81 | 97.69 | 99.81 |
+| stable-diffusion-2 | 86.63 | 99.44 | 99.33 | 95.87 | 97.59 |
+| stable-diffusion-xl-base-1.0 | 80.06 | 98.53 | 98.40 | 90.05 | 94.92 |
+| playground-v2.5-1024px-aesthetic | 90.87 | 99.75 | 99.73 | 96.92 | 98.65 |
+| playground-v2-1024px-aesthetic | 91.18 | 99.81 | 99.73 | 97.46 | 98.82 |
+| playground-v2-512px-base | 84.11 | 98.47 | 98.66 | 94.62 | 96.98 |
+| playground-v2-256px-base | 86.73 | 99.24 | 99.03 | 96.64 | 97.80 |
+| PixArt-XL-2-1024-MS | 93.31 | 99.94 | 99.90 | 98.55 | 99.53 |
+| PixArt-XL-2-512x512 | 94.39 | 99.93 | 99.93 | 98.54 | 99.58 |
+| lcm-lora-sdxl | 97.00 | 99.98 | 99.96 | 99.14 | 99.84 |
+| lcm-lora-sdv1-5 | 98.28 | 99.98 | 99.97 | 99.51 | 99.92 |
+| FLUX.1-schnell | 88.58 | 99.52 | 99.44 | 94.69 | 98.28 |
+| FLUX.1-dev | 88.44 | 99.61 | 99.50 | 94.57 | 98.09 |
+| **Average** | **89.39** | **99.46** | **99.40** | **96.52** | **98.50** |
+
+## Accuracy
+| Detector | CC3M | FLICKR | MSCOCO | TEXTCAPS | SBU |
+|----------|------|--------|---------|----------|-----|
+| ldm-text2im-large-256 | 88.45 | 97.10 | 96.73 | 94.68 | 94.65 |
+| stable-diffusion-v1-4 | 83.73 | 93.65 | 96.03 | 92.10 | 84.45 |
+| stable-diffusion-v1-5 | 82.73 | 92.85 | 95.25 | 91.33 | 83.23 |
+| SSD-1B | 80.33 | 87.58 | 88.88 | 85.23 | 80.93 |
+| tiny-sd | 76.38 | 83.25 | 85.43 | 86.63 | 78.85 |
+| SegMoE-SD-4x2-v0 | 82.23 | 88.88 | 92.20 | 89.38 | 84.03 |
+| small-sd | 77.78 | 84.23 | 87.45 | 87.05 | 80.00 |
+| stable-diffusion-2-1 | 82.60 | 92.58 | 94.03 | 91.65 | 83.48 |
+| stable-diffusion-3-medium-diffusers | 77.70 | 86.95 | 88.23 | 83.85 | 79.10 |
+| sdxl-turbo | 90.45 | 95.53 | 96.35 | 91.95 | 96.40 |
+| stable-diffusion-2 | 78.80 | 88.68 | 90.55 | 87.80 | 76.58 |
+| stable-diffusion-xl-base-1.0 | 70.13 | 80.60 | 83.53 | 76.68 | 67.33 |
+| playground-v2.5-1024px-aesthetic | 83.90 | 93.93 | 94.65 | 89.70 | 84.00 |
+| playground-v2-1024px-aesthetic | 83.45 | 95.15 | 94.58 | 90.93 | 84.95 |
+| playground-v2-512px-base | 74.28 | 83.23 | 86.35 | 84.58 | 74.50 |
+| playground-v2-256px-base | 77.50 | 87.50 | 88.10 | 89.35 | 78.95 |
+| PixArt-XL-2-1024-MS | 86.80 | 97.73 | 97.83 | 94.00 | 93.38 |
+| PixArt-XL-2-512x512 | 87.18 | 97.13 | 98.13 | 93.65 | 93.35 |
+| lcm-lora-sdxl | 91.40 | 99.03 | 98.85 | 95.25 | 96.98 |
+| lcm-lora-sdv1-5 | 91.98 | 99.15 | 99.28 | 96.33 | 98.28 |
+| FLUX.1-schnell | 80.05 | 90.15 | 90.88 | 84.58 | 80.68 |
+| FLUX.1-dev | 79.93 | 92.43 | 92.05 | 83.68 | 81.40 |
+| **Average** | **82.22** | **91.24** | **92.24** | **89.20** | **84.34**
+
+
+
+
+
+To evaluate the pre-trained detector (trained on CNNDet (`progan`)) on [AIGCDetectionBenchMark](https://github.com/Ekko-zn/AIGCDetectBenchmark), run
+```bash
+python main.py --gpu 1 --phase eval --train_dataset progan --pretrain
+```
+When finished, evaluation results will be saved to `ckpt/progan/fusion/pretrain_AIGCDetectionBenchMark`.
+
+
+📊 Results (click to expand)
+
+
+Results are highly consistent with the original results reported in Table 8 in Appendix K, with slight differences arising from improvements in hyper-parameter settings.
+
+
+| Model | AP | Accuracy |
+|-------|------|----------|
+| ADM | 89.98 | 79.17 |
+| biggan | 98.00 | 94.30 |
+| cyclegan | 99.47 | 98.98 |
+| DALLE2 | 97.14 | 87.80 |
+| gaugan | 98.24 | 95.05 |
+| Glide | 96.71 | 90.40 |
+| Midjourney | 94.55 | 87.19 |
+| progan | 100.00 | 100.00 |
+| stable_diffusion_v_1_4 | 92.99 | 85.34 |
+| stable_diffusion_v_1_5 | 92.96 | 85.44 |
+| stargan | 99.98 | 99.45 |
+| stylegan | 99.69 | 94.81 |
+| stylegan2 | 99.85 | 94.89 |
+| VQDM | 91.96 | 85.83 |
+| whichfaceisreal | 82.27 | 80.55 |
+| wukong | 89.59 | 80.06 |
+| **Average** | **95.21** | **90.58** |
+
+
+
+Evaluation results contain three files, including:
+- `evaluation.log`: detailed evaluation log.
+- `output.json`: predicted synthetic probabilities for each sample.
+- `result.json`: evaluation metrics (dataset size, AP and accuracy) for each test source.
+
+### Inference on a Single Image
+To run inference on a single image (e.g., using the pre-trained detector trained on DRCT-2M):
+```bash
+python main.py --gpu 0 --phase test --train_dataset sd-v1_4 --pretrain
+# The script will prompt for the image file path:
+# "Please enter the image filepath for scanning: "
+imgs/test.png
+# Output (probability - decision):
+# "CO-SPY Prediction: 0.854 - AI-Generated"
+```
+
+### Training
+We provide two training pipelines: (1) end-to-end training and (2) best practice of training semantic and artifact branches separately, followed by calibrating the combined detector.
+
+```bash
+# Train an end-to-end CO-SPY detector for 10 epochs on DRCT-2M
+python main.py --gpu 0 --phase train --mode end2end --train_dataset sd-v1_4 --epochs 10
+# Train an end-to-end CO-SPY detector for 10 epochs on CNNDet
+python main.py --gpu 1 --phase train --mode end2end --train_dataset progan --epochs 10
+```
+The trained model will be saved to `ckpt//end2end`.
+
+*The end-to-end training may not yield optimal performance due to the conflicting nature of semantic and artifact features. We recommend the following best practice for training.*
+```bash
+# Train an optimal CO-SPY detector using the best practice script on DRCT-2M
+bash train.sh --gpu 2 --dataset sd-v1_4
+# Train an optimal CO-SPY detector using the best practice script on CNNDet
+bash train.sh --gpu 2 --dataset progan
+```
+The trained models will be saved to `ckpt//fusion`.
+
+You can also customize the training parameters for the training of each branch and the calibration step:
+```bash
+# Train the semantic component (on CNNDet training set as an example)
+python main.py \
+ --phase train \
+ --gpu 0 \
+ --mode branch \
+ --branch semantic \
+ --train_dataset progan \
+ --epochs 10
+# Train the artifact component
+python main.py \
+ --phase train \
+ --gpu 1 \
+ --mode branch \
+ --branch artifact \
+ --train_dataset progan \
+ --epochs 20
+# Calibrate the combined CO-SPY detector
+python main.py \
+ --phase train \
+ --gpu 2 \
+ --mode fusion \
+ --train_dataset progan \
+ --epochs 2
+```
+The trained branch models and the calibrated fusion model will be saved to `ckpt/progan/semantic`, `ckpt/progan/artifact`, and `ckpt/progan/fusion`, respectively.
+
+After training, you can evaluate the trained model on the test datasets by just changing the `--phase` to `eval` and specifying the `--train_dataset` and `--mode` accordingly. For example, to evaluate the fusion model (best practice), trained on CNNDet, on AIGCDetectionBenchMark, run:
+```bash
+python main.py --gpu 0 --phase eval --train_dataset progan --mode fusion
+```
+
+## Citation
+Please cite our paper if you find it useful for your research.😀
+
+```bibtex
+@inproceedings{Cheng_2025_CVPR,
+ author = {Cheng, Siyuan and Lyu, Lingjuan and Wang, Zhenting and Zhang, Xiangyu and Sehwag, Vikash},
+ title = {CO-SPY: Combining Semantic and Pixel Features to Detect Synthetic Images by AI},
+ booktitle = {Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR)},
+ month = {June},
+ year = {2025},
+ pages = {13455-13465}
+}
+```
+
+## Acknowledgement
+We gratefully acknowledge these outstanding works, which have deeply inspired our project!
+- [CNNDetection](https://github.com/PeterWang512/CNNDetection)
+- [UniversalFakeDetect](https://github.com/WisconsinAIVision/UniversalFakeDetect)
+- [NPR-DeepfakeDetection](https://github.com/chuangchuangtan/NPR-DeepfakeDetection)
+- [DRCT](https://github.com/beibuwandeluori/DRCT)
diff --git a/clean/image/cospy/SOURCE.md b/clean/image/cospy/SOURCE.md
new file mode 100644
index 0000000000000000000000000000000000000000..61c85f57738190ea4db2227158479e8a952c8f18
--- /dev/null
+++ b/clean/image/cospy/SOURCE.md
@@ -0,0 +1,17 @@
+# Source: image/cospy
+
+| Field | Value |
+|---|---|
+| Upstream | https://github.com/Megum1/CO-SPY |
+| Paper | https://arxiv.org/abs/2503.18286 |
+| Commit SHA | **not recorded** -- the vendoring step did not preserve it |
+| Mirrored on | 2026-09-15 |
+| Upstream license | LICENSE |
+
+This is a **mirror**, stripped to the files needed for inference. The full
+untouched snapshot is at `archive/image__cospy.tar.gz`.
+
+This code is the work of its original authors and is **not** covered by the
+DeepSafe project license. If you are an author and want this removed, open an
+issue on https://github.com/deepsafehq/deepsafe-bench and it will be taken down
+within 48 hours, no questions asked.
diff --git a/clean/image/cospy/dataSets/__init__.py b/clean/image/cospy/dataSets/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..ecb7a92c483a5b8dd269d8ba545ca55c5217d308
--- /dev/null
+++ b/clean/image/cospy/dataSets/__init__.py
@@ -0,0 +1,67 @@
+from .dataset import TrainDataset, CoSpyBenchTestDataset, AIGCDetectTestDataset
+
+
+# Co-Spy-Bench: List of evaluated real datasets
+CoSpyBench_DATASET_LIST = ["mscoco", "flickr", "cc3m", "textcaps", "sbu"]
+
+# Co-Spy-Bench: List of evaluated generative models
+CoSpyBench_MODEL_LIST = [
+ # CompVis
+ "CompVis@ldm-text2im-large-256",
+ "CompVis@stable-diffusion-v1-4",
+ # runwayml
+ "runwayml@stable-diffusion-v1-5",
+ # segmind
+ "segmind@SSD-1B",
+ "segmind@tiny-sd",
+ "segmind@SegMoE-SD-4x2-v0",
+ "segmind@small-sd",
+ # stabilityai
+ "stabilityai@stable-diffusion-2-1",
+ "stabilityai@stable-diffusion-3-medium-diffusers",
+ "stabilityai@sdxl-turbo",
+ "stabilityai@stable-diffusion-2",
+ "stabilityai@stable-diffusion-xl-base-1.0",
+ # playgroundai
+ "playgroundai@playground-v2.5-1024px-aesthetic",
+ "playgroundai@playground-v2-1024px-aesthetic",
+ "playgroundai@playground-v2-512px-base",
+ "playgroundai@playground-v2-256px-base",
+ # PixArt-alpha
+ "PixArt-alpha@PixArt-XL-2-1024-MS",
+ "PixArt-alpha@PixArt-XL-2-512x512",
+ # latent-consistency
+ "latent-consistency@lcm-lora-sdxl",
+ "latent-consistency@lcm-lora-sdv1-5",
+ # black-forest-labs
+ "black-forest-labs@FLUX.1-schnell",
+ "black-forest-labs@FLUX.1-dev",
+]
+
+# AIGCDetectionBenchMark: List of evaluated real datasets
+AIGCDetectionBenchMark_DATASET_LIST = ["test"]
+
+# AIGCDetectionBenchMark: List of evaluated generative models
+AIGCDetectionBenchMark_MODEL_LIST = [
+ "ADM",
+ "biggan",
+ "cyclegan",
+ "DALLE2",
+ "gaugan",
+ "Glide",
+ "Midjourney",
+ "progan",
+ "stable_diffusion_v_1_4",
+ "stable_diffusion_v_1_5",
+ "stargan",
+ "stylegan",
+ "stylegan2",
+ "VQDM",
+ "whichfaceisreal",
+ "wukong",
+]
+
+
+__all__ = ["TrainDataset", "CoSpyBenchTestDataset", "AIGCDetectTestDataset",
+ "CoSpyBench_DATASET_LIST", "CoSpyBench_MODEL_LIST",
+ "AIGCDetectionBenchMark_DATASET_LIST", "AIGCDetectionBenchMark_MODEL_LIST"]
diff --git a/clean/image/cospy/dataSets/cospy_real.py b/clean/image/cospy/dataSets/cospy_real.py
new file mode 100644
index 0000000000000000000000000000000000000000..e9f5925ba812e04e7d6edfe2dcefc3267e30ec40
--- /dev/null
+++ b/clean/image/cospy/dataSets/cospy_real.py
@@ -0,0 +1,93 @@
+import os
+import json
+import torch
+import numpy as np
+from PIL import Image
+import datasets as ds
+
+
+class MSCOCO2017(torch.utils.data.Dataset):
+ def __init__(self, split='val', transform=None):
+ # Split [train: 118287, val: 5000]
+ image_dir = f"data/train/sd-v1_4/mscoco2017/{split}2017"
+ self.image_list = [os.path.join(image_dir, f) for f in os.listdir(image_dir) if f.endswith(('.jpg'))]
+ self.image_list.sort()
+ caption_filepath = f"data/train/sd-v1_4/stable-diffusion-v1-4/{split}2017_gen.json"
+ with open(caption_filepath, 'r') as f:
+ self.captions = json.load(f)
+
+ # Preprocess the images
+ self.transform = transform
+
+ def __len__(self):
+ return len(self.image_list)
+
+ def __getitem__(self, idx):
+ image_filepath = self.image_list[idx]
+ image = Image.open(image_filepath).convert('RGB')
+ if self.transform:
+ image = self.transform(image)
+ # Get the captions
+ image_id = os.path.basename(image_filepath)
+ caption = self.captions[image_id]
+ return image, caption
+
+
+class Flickr30k(torch.utils.data.Dataset):
+ def __init__(self, split='test', transform=None):
+ # Split [test: 31014]
+ self.dataset = ds.load_dataset("nlphuji/flickr30k")[split]
+
+ # Preprocess the images
+ self.transform = transform
+
+ def __len__(self):
+ return len(self.dataset)
+
+ def __getitem__(self, idx):
+ example = self.dataset[idx]
+ # PIL RGB image
+ image = example['image']
+ if self.transform:
+ image = self.transform(image)
+ # A list of valid captions
+ caption_list = example['caption']
+ # Randomly select a caption
+ caption = np.random.choice(caption_list)
+ return image, caption
+
+
+class OtherReal(torch.utils.data.Dataset):
+ def __init__(self, dataset_name, transform=None):
+ # Load the test samples from other real datasets (CC3M, SBU, TextCaps)
+ # Note: there are only 2,000 examples for each dataset
+ root_dir = "data/test/Co-Spy-Bench/real_image_examples"
+ if dataset_name == "cc3m":
+ self.image_dir = os.path.join(root_dir, "CC3M")
+ elif dataset_name == "sbu":
+ self.image_dir = os.path.join(root_dir, "SBU")
+ elif dataset_name == "textcaps":
+ self.image_dir = os.path.join(root_dir, "TextCaps")
+ else:
+ raise ValueError(f"Dataset {dataset_name} not supported in OtherReal class.")
+
+ self.image_list = [f for f in os.listdir(self.image_dir) if f.endswith(('.jpg'))]
+ self.image_list.sort()
+
+ # Preprocess the images
+ self.transform = transform
+
+ def __len__(self):
+ return len(self.image_list)
+
+ def __getitem__(self, idx):
+ img_name = self.image_list[idx]
+ img_path = os.path.join(self.image_dir, img_name)
+ image = Image.open(img_path).convert('RGB')
+ if self.transform:
+ image = self.transform(image)
+ caption_filepath = img_path.replace('.jpg', '.json')
+ with open(caption_filepath, 'r') as f:
+ caption_data = json.load(f)
+ caption = caption_data['caption']
+ return image, caption
diff --git a/clean/image/cospy/dataSets/dataset.py b/clean/image/cospy/dataSets/dataset.py
new file mode 100644
index 0000000000000000000000000000000000000000..050fadc79b8521cd1c67a5295c229cc8b906f50c
--- /dev/null
+++ b/clean/image/cospy/dataSets/dataset.py
@@ -0,0 +1,148 @@
+import os
+import numpy as np
+from PIL import Image
+from tqdm import tqdm
+from torch.utils.data import Dataset
+
+from utils import get_list, png_to_jpeg
+from .cospy_real import MSCOCO2017, Flickr30k, OtherReal
+
+
+class TrainDataset(Dataset):
+ def __init__(self, train_dataset, split="train", add_jpeg=False, transform=None):
+ assert split in ["train", "val"]
+ # Root directory of the training datasets
+ root_dir = f"data/train/{train_dataset}"
+
+ # Load the dataset for training
+ if train_dataset == "progan":
+ real_list = get_list(os.path.join(root_dir, split), must_contain='0_real')
+ fake_list = get_list(os.path.join(root_dir, split), must_contain='1_fake')
+ elif train_dataset == "sd-v1_4":
+ real_list = get_list(os.path.join(root_dir, "mscoco2017", f"{split}2017"))
+ fake_list = get_list(os.path.join(root_dir, "stable-diffusion-v1-4", f"{split}2017"))
+
+ # Setting the labels for the dataset
+ self.labels_dict = {}
+ for i in real_list:
+ self.labels_dict[i] = 0
+ for i in fake_list:
+ self.labels_dict[i] = 1
+
+ # Construct the entire dataset
+ self.total_list = real_list + fake_list
+ np.random.shuffle(self.total_list)
+
+ # JPEG compression
+ self.add_jpeg = add_jpeg
+
+ # Transformations
+ self.transform = transform
+
+ def __len__(self):
+ return len(self.total_list)
+
+ def __getitem__(self, idx):
+ img_path = self.total_list[idx]
+ label = self.labels_dict[img_path]
+ image = Image.open(img_path).convert("RGB")
+
+ # Add JPEG compression
+ if self.add_jpeg:
+ image = png_to_jpeg(image, quality=95)
+
+ # Apply the transformation
+ if self.transform is not None:
+ image = self.transform(image)
+ return image, label
+
+
+class CoSpyBenchTestDataset(Dataset):
+ def __init__(self, dataset, model, num_real=2000, add_jpeg=True, transform=None):
+ # Root path of the Co-Spy-Bench dataset
+ root_path = "data/test/Co-Spy-Bench/synthetic"
+
+ # Load fake images
+ fake_dir = os.path.join(root_path, dataset, model)
+ fake_list = [i for i in os.listdir(fake_dir) if i.endswith(".png")]
+ fake_list.sort()
+ self.fake = [os.path.join(fake_dir, i) for i in fake_list]
+
+ # Take the real images from the dataset
+ if dataset == "mscoco":
+ self.real = MSCOCO2017()
+ elif dataset == "flickr":
+ self.real = Flickr30k()
+ else:
+ self.real = OtherReal(dataset)
+
+ # Ensure the number of real and fake images are the same
+ self.num_real = min(num_real, len(self.real), len(self.fake))
+ self.image_idx = list(range(self.num_real * 2))
+ # First half is real, second half is fake
+ self.labels = [0] * self.num_real + [1] * self.num_real
+
+ # JPEG compression
+ self.add_jpeg = add_jpeg
+
+ # Transformations
+ self.transform = transform
+
+ def __len__(self):
+ return len(self.image_idx)
+
+ def __getitem__(self, idx):
+ if idx < self.num_real:
+ image, _ = self.real[idx]
+ else:
+ image = Image.open(self.fake[idx - self.num_real]).convert("RGB")
+
+ # JPEG compression
+ if self.add_jpeg:
+ image = png_to_jpeg(image, quality=95)
+
+ # Transformations
+ if self.transform is not None:
+ image = self.transform(image)
+ label = self.labels[idx]
+
+ return image, label
+
+
+class AIGCDetectTestDataset(Dataset):
+ def __init__(self, dataset, model, transform=None):
+ # Root path of the AIGCDetectionBenchMark dataset
+ root_path = "data/test/AIGCDetectionBenchMark"
+
+ # Load images
+ image_dir = os.path.join(root_path, dataset, model)
+ real_list = get_list(image_dir, must_contain='0_real')
+ fake_list = get_list(image_dir, must_contain='1_fake')
+
+ # Setting the labels for the dataset
+ self.labels_dict = {}
+ for i in real_list:
+ self.labels_dict[i] = 0
+ for i in fake_list:
+ self.labels_dict[i] = 1
+
+ # Construct the entire dataset
+ self.total_list = real_list + fake_list
+ np.random.shuffle(self.total_list)
+
+ # Transformations
+ self.transform = transform
+
+ def __len__(self):
+ return len(self.total_list)
+
+ def __getitem__(self, idx):
+ img_path = self.total_list[idx]
+ label = self.labels_dict[img_path]
+ image = Image.open(img_path).convert("RGB")
+
+ # Transformations
+ if self.transform is not None:
+ image = self.transform(image)
+
+ return image, label
diff --git a/clean/image/cospy/detectors/progan/__init__.py b/clean/image/cospy/detectors/progan/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..c9411800ca98dd45775d08a0160c377ab08421ed
--- /dev/null
+++ b/clean/image/cospy/detectors/progan/__init__.py
@@ -0,0 +1,7 @@
+from .base import BaseDetector
+from .artifact import ArtifactDetector
+from .semantic import SemanticDetector
+from .fusion import CoSpyFusionDetector
+from .end2end import End2EndDetector
+
+__all__ = ["BaseDetector", "ArtifactDetector", "SemanticDetector", "CoSpyFusionDetector", "End2EndDetector"]
diff --git a/clean/image/cospy/detectors/progan/artifact.py b/clean/image/cospy/detectors/progan/artifact.py
new file mode 100644
index 0000000000000000000000000000000000000000..e3382b3248280b19d3cb18e7eaf8434846e53b4a
--- /dev/null
+++ b/clean/image/cospy/detectors/progan/artifact.py
@@ -0,0 +1,145 @@
+import torch
+import torch.nn as nn
+from torch.nn import functional as F
+
+from .base import BaseDetector
+
+
+class ArtifactDetector(BaseDetector):
+ def __init__(self, dim_artifact=512, num_classes=1):
+ super(ArtifactDetector, self).__init__()
+
+ # Load the artifact encoder based on NPR
+ self.artifact_encoder = ResNet(Bottleneck, [3, 4, 6, 3])
+
+ # Classifier
+ self.fc = torch.nn.Linear(dim_artifact, num_classes)
+
+ # Build transforms
+ self._build_transforms()
+
+ def forward(self, x, return_feat=False):
+ feat = self.artifact_encoder(x)
+ out = self.fc(feat)
+ if return_feat:
+ return feat, out
+ return out
+
+
+# Define the artifact encoder (based on NPR)
+def conv1x1(in_planes, out_planes, stride=1):
+ """1x1 convolution"""
+ return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False)
+
+
+def conv3x3(in_planes, out_planes, stride=1):
+ """3x3 convolution with padding"""
+ return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,
+ padding=1, bias=False)
+
+
+class Bottleneck(nn.Module):
+ expansion = 4
+
+ def __init__(self, inplanes, planes, stride=1, downsample=None):
+ super(Bottleneck, self).__init__()
+ self.conv1 = conv1x1(inplanes, planes)
+ self.bn1 = nn.BatchNorm2d(planes)
+ self.conv2 = conv3x3(planes, planes, stride)
+ self.bn2 = nn.BatchNorm2d(planes)
+ self.conv3 = conv1x1(planes, planes * self.expansion)
+ self.bn3 = nn.BatchNorm2d(planes * self.expansion)
+ self.relu = nn.ReLU(inplace=True)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x):
+ identity = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+ out = self.relu(out)
+
+ out = self.conv3(out)
+ out = self.bn3(out)
+
+ if self.downsample is not None:
+ identity = self.downsample(x)
+
+ out += identity
+ out = self.relu(out)
+
+ return out
+
+
+class ResNet(nn.Module):
+
+ def __init__(self, block, layers, num_classes=1):
+ super(ResNet, self).__init__()
+
+ self.unfoldSize = 2
+ self.unfoldIndex = 0
+ assert self.unfoldSize > 1
+ assert -1 < self.unfoldIndex and self.unfoldIndex < self.unfoldSize*self.unfoldSize
+ self.inplanes = 64
+ self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=2, padding=1, bias=False)
+ self.bn1 = nn.BatchNorm2d(64)
+ self.relu = nn.ReLU(inplace=True)
+ self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
+ self.layer1 = self._make_layer(block, 64 , layers[0])
+ self.layer2 = self._make_layer(block, 128, layers[1], stride=2)
+ self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
+ self.fc1 = nn.Linear(512, num_classes)
+
+ for m in self.modules():
+ if isinstance(m, nn.Conv2d):
+ nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
+ elif isinstance(m, nn.BatchNorm2d):
+ nn.init.constant_(m.weight, 1)
+ nn.init.constant_(m.bias, 0)
+
+ def _make_layer(self, block, planes, blocks, stride=1):
+ downsample = None
+ if stride != 1 or self.inplanes != planes * block.expansion:
+ downsample = nn.Sequential(
+ conv1x1(self.inplanes, planes * block.expansion, stride),
+ nn.BatchNorm2d(planes * block.expansion),
+ )
+
+ layers = []
+ layers.append(block(self.inplanes, planes, stride, downsample))
+ self.inplanes = planes * block.expansion
+ for _ in range(1, blocks):
+ layers.append(block(self.inplanes, planes))
+
+ return nn.Sequential(*layers)
+
+ def interpolate(self, img, factor):
+ return F.interpolate(
+ F.interpolate(img,
+ scale_factor=factor,
+ mode='nearest',
+ recompute_scale_factor=True),
+ scale_factor=1 / factor,
+ mode='nearest',
+ recompute_scale_factor=True)
+
+ def forward(self, x):
+ artifact = x - self.interpolate(x, 0.5)
+
+ x = self.conv1(artifact * 2.0 / 3.0)
+ x = self.bn1(x)
+ x = self.relu(x)
+ x = self.maxpool(x)
+
+ x = self.layer1(x)
+ x = self.layer2(x)
+
+ x = self.avgpool(x)
+ x = x.view(x.size(0), -1)
+
+ return x
diff --git a/clean/image/cospy/detectors/progan/base.py b/clean/image/cospy/detectors/progan/base.py
new file mode 100644
index 0000000000000000000000000000000000000000..03b6d6cf90375b699cdcd25bbce96f9d0a591233
--- /dev/null
+++ b/clean/image/cospy/detectors/progan/base.py
@@ -0,0 +1,81 @@
+import torch
+from abc import ABC, abstractmethod
+from torchvision import transforms
+from utils import data_augment
+
+
+class BaseDetector(torch.nn.Module, ABC):
+ """Abstract base class for all detectors."""
+
+ def __init__(self):
+ super(BaseDetector, self).__init__()
+
+ # Default normalization (ImageNet)
+ self.mean = [0.485, 0.456, 0.406]
+ self.std = [0.229, 0.224, 0.225]
+
+ # Default resolution
+ self.loadSize = 256
+ self.cropSize = 224
+
+ # Default data augmentation config
+ self.blur_prob = 0.0
+ self.blur_sig = [0.0, 3.0]
+ self.jpg_prob = 0.0
+ self.jpg_method = ['cv2', 'pil']
+ self.jpg_qual = list(range(30, 101))
+
+ @property
+ def aug_config(self):
+ return {
+ "blur_prob": self.blur_prob,
+ "blur_sig": self.blur_sig,
+ "jpg_prob": self.jpg_prob,
+ "jpg_method": self.jpg_method,
+ "jpg_qual": self.jpg_qual,
+ }
+
+ def _build_transforms(self):
+ """Build train and test transforms based on current config."""
+ crop_func = transforms.RandomCrop(self.cropSize)
+ flip_func = transforms.RandomHorizontalFlip()
+ rz_func = transforms.Resize(self.loadSize)
+ aug_func = transforms.Lambda(lambda x: data_augment(x, self.aug_config))
+
+ self.train_transform = transforms.Compose([
+ rz_func,
+ aug_func,
+ crop_func,
+ flip_func,
+ transforms.ToTensor(),
+ transforms.Normalize(mean=self.mean, std=self.std),
+ ])
+
+ self.test_transform = transforms.Compose([
+ rz_func,
+ crop_func,
+ transforms.ToTensor(),
+ transforms.Normalize(mean=self.mean, std=self.std),
+ ])
+
+ @abstractmethod
+ def forward(self, x, return_feat=False):
+ """Forward pass of the detector."""
+ pass
+
+ def predict(self, inputs):
+ """Prediction function."""
+ inputs = inputs.to(next(self.parameters()).device)
+ outputs = self.forward(inputs)
+ prediction = outputs.sigmoid().flatten().tolist()
+ return prediction
+
+ def save_weights(self, weights_path):
+ """Save model weights to a file."""
+ save_params = {k: v.cpu() for k, v in self.state_dict().items()}
+ torch.save(save_params, weights_path)
+
+ def load_weights(self, weights_path):
+ """Load model weights from a file."""
+ weights = torch.load(weights_path, map_location='cpu')
+ self.load_state_dict(weights, strict=False)
diff --git a/clean/image/cospy/detectors/progan/end2end.py b/clean/image/cospy/detectors/progan/end2end.py
new file mode 100644
index 0000000000000000000000000000000000000000..3aacd4ae438778afb36e495969085687a5b40849
--- /dev/null
+++ b/clean/image/cospy/detectors/progan/end2end.py
@@ -0,0 +1,101 @@
+import torch
+import random
+from torchvision import transforms
+from utils import data_augment, weights2cpu
+from .base import BaseDetector
+from .semantic import SemanticDetector
+from .artifact import ArtifactDetector
+
+
+class End2EndDetector(BaseDetector):
+ """CO-SPY End-to-End Detector."""
+
+ def __init__(self, num_classes=1):
+ super(End2EndDetector, self).__init__()
+
+ # Load the semantic detector
+ self.sem = SemanticDetector()
+ self.sem_dim = self.sem.fc.in_features
+
+ # Load the artifact detector
+ self.art = ArtifactDetector()
+ self.art_dim = self.art.fc.in_features
+
+ # Classifier
+ self.fc = torch.nn.Linear(self.sem_dim + self.art_dim, num_classes)
+
+ # Transformations inside the forward function
+ # Including the normalization and resizing (only for the artifact detector)
+ self.sem_transform = transforms.Compose([
+ transforms.Normalize(self.sem.mean, self.sem.std)
+ ])
+ self.art_transform = transforms.Compose([
+ transforms.Normalize(self.art.mean, self.art.std)
+ ])
+
+ # Build transforms (no normalization, done in forward)
+ self._build_transforms()
+
+ def _build_transforms(self):
+ """Build transforms without normalization (normalization done per-branch in forward)."""
+
+ crop_func = transforms.RandomCrop(self.cropSize)
+ flip_func = transforms.RandomHorizontalFlip()
+ rz_func = transforms.Resize(self.loadSize)
+ aug_func = transforms.Lambda(lambda x: data_augment(x, self.aug_config))
+
+ self.train_transform = transforms.Compose([
+ flip_func,
+ aug_func,
+ rz_func,
+ crop_func,
+ transforms.ToTensor(),
+ ])
+
+ self.test_transform = transforms.Compose([
+ rz_func,
+ crop_func,
+ transforms.ToTensor(),
+ ])
+
+ def forward(self, x, return_feat=False, dropout_rate=0.3):
+ x_sem = self.sem_transform(x)
+ x_art = self.art_transform(x)
+
+ # Forward pass
+ sem_feat, sem_coeff = self.sem(x_sem, return_feat=True)
+ art_feat, art_coeff = self.art(x_art, return_feat=True)
+
+ # Dropout during training
+ if self.training:
+ if random.random() < dropout_rate:
+ # Randomly select a feature to drop
+ idx_drop = random.randint(0, 1)
+ if idx_drop == 0:
+ sem_coeff = torch.zeros_like(sem_coeff)
+ else:
+ art_coeff = torch.zeros_like(art_coeff)
+
+ # Concatenate the features
+ feat = torch.cat([sem_coeff * sem_feat, art_coeff * art_feat], dim=1)
+ out = self.fc(feat)
+
+ if return_feat:
+ return feat, out
+ return out
+
+ def save_weights(self, weights_path):
+ save_params = {
+ "sem_fc": weights2cpu(self.sem.fc.state_dict()),
+ "art_fc": weights2cpu(self.art.fc.state_dict()),
+ "art_encoder": weights2cpu(self.art.artifact_encoder.state_dict()),
+ "classifier": weights2cpu(self.fc.state_dict()),
+ }
+ torch.save(save_params, weights_path)
+
+ def load_weights(self, weights_path):
+ weights = torch.load(weights_path, map_location='cpu')
+ self.sem.fc.load_state_dict(weights["sem_fc"])
+ self.art.fc.load_state_dict(weights["art_fc"])
+ self.art.artifact_encoder.load_state_dict(weights["art_encoder"])
+ self.fc.load_state_dict(weights["classifier"])
diff --git a/clean/image/cospy/detectors/progan/fusion.py b/clean/image/cospy/detectors/progan/fusion.py
new file mode 100644
index 0000000000000000000000000000000000000000..c33ed927a310da4b382552af7c2f046ba46b11ab
--- /dev/null
+++ b/clean/image/cospy/detectors/progan/fusion.py
@@ -0,0 +1,86 @@
+import torch
+from torchvision import transforms
+
+from .base import BaseDetector
+from .semantic import SemanticDetector
+from .artifact import ArtifactDetector
+
+
+class CoSpyFusionDetector(BaseDetector):
+ """CO-SPY Fusion Detector (calibrate and fuse semantic and artifact detectors)."""
+
+ def __init__(self, semantic_weights_path, artifact_weights_path, num_classes=1):
+ super(CoSpyFusionDetector, self).__init__()
+
+ # Load the semantic detector
+ self.sem = SemanticDetector()
+ self.sem.load_weights(semantic_weights_path)
+
+ # Load the artifact detector
+ self.art = ArtifactDetector()
+ self.art.load_weights(artifact_weights_path)
+
+ # Freeze the two pre-trained models
+ for param in self.sem.parameters():
+ param.requires_grad = False
+ for param in self.art.parameters():
+ param.requires_grad = False
+
+ # Classifier
+ self.fc = torch.nn.Linear(2, num_classes)
+
+ # Transformations inside the forward function
+ self.sem_transform = transforms.Compose([
+ transforms.Normalize(self.sem.mean, self.sem.std)
+ ])
+ self.art_transform = transforms.Compose([
+ transforms.Normalize(self.art.mean, self.art.std)
+ ])
+
+ # Build transforms (no normalization, done in forward)
+ self._build_fusion_transforms()
+
+ def _build_fusion_transforms(self):
+ """Build transforms without normalization (normalization done per-branch in forward)."""
+ from utils import data_augment
+
+ crop_func = transforms.RandomCrop(self.cropSize)
+ flip_func = transforms.RandomHorizontalFlip()
+ rz_func = transforms.Resize(self.loadSize)
+ aug_func = transforms.Lambda(lambda x: data_augment(x, self.aug_config))
+
+ self.train_transform = transforms.Compose([
+ flip_func,
+ aug_func,
+ rz_func,
+ crop_func,
+ transforms.ToTensor(),
+ ])
+
+ self.test_transform = transforms.Compose([
+ rz_func,
+ crop_func,
+ transforms.ToTensor(),
+ ])
+
+ def forward(self, x, return_feat=False):
+ x_sem = self.sem_transform(x)
+ x_art = self.art_transform(x)
+ pred_sem = self.sem(x_sem)
+ pred_art = self.art(x_art)
+ feat = torch.cat([pred_sem, pred_art], dim=1)
+ out = self.fc(feat)
+ if return_feat:
+ return feat, out
+ return out
+
+ def save_weights(self, weights_path):
+ # Only save the fc layer (sub-detectors are frozen)
+ save_params = {"fc.weight": self.fc.weight.cpu(), "fc.bias": self.fc.bias.cpu()}
+ torch.save(save_params, weights_path)
+
+ def load_weights(self, weights_path):
+ # Load only the fc layer
+ weights = torch.load(weights_path, map_location='cpu')
+ self.fc.weight.data = weights["fc.weight"]
+ self.fc.bias.data = weights["fc.bias"]
diff --git a/clean/image/cospy/detectors/progan/semantic.py b/clean/image/cospy/detectors/progan/semantic.py
new file mode 100644
index 0000000000000000000000000000000000000000..16dc26ec3f2d36e4e4ccdaf142bb678b6c4d368a
--- /dev/null
+++ b/clean/image/cospy/detectors/progan/semantic.py
@@ -0,0 +1,48 @@
+import torch
+from transformers import CLIPModel
+
+from .base import BaseDetector
+
+
+class SemanticDetector(BaseDetector):
+ def __init__(self, dim_clip=768, num_classes=1):
+ super(SemanticDetector, self).__init__()
+
+ # Get the pre-trained CLIP
+ model_name = "openai/clip-vit-large-patch14"
+ self.clip = CLIPModel.from_pretrained(model_name)
+
+ # Freeze the CLIP visual encoder
+ self.clip.requires_grad_(False)
+
+ # Classifier
+ self.fc = torch.nn.Linear(dim_clip, num_classes)
+
+ # CLIP normalization
+ self.mean = [0.48145466, 0.45782750, 0.40821073]
+ self.std = [0.26862954, 0.26130258, 0.27577711]
+
+ # Data augmentation (override defaults)
+ self.blur_prob = 0.5
+ self.jpg_prob = 0.5
+
+ # Build transforms
+ self._build_transforms()
+
+ def forward(self, x, return_feat=False):
+ feat = self.clip.get_image_features(x)
+ out = self.fc(feat)
+ if return_feat:
+ return feat, out
+ return out
+
+ def save_weights(self, weights_path):
+ # Only save the fc layer (CLIP is frozen)
+ save_params = {"fc.weight": self.fc.weight.cpu(), "fc.bias": self.fc.bias.cpu()}
+ torch.save(save_params, weights_path)
+
+ def load_weights(self, weights_path):
+ # Load only the fc layer
+ weights = torch.load(weights_path, map_location='cpu')
+ self.fc.weight.data = weights["fc.weight"]
+ self.fc.bias.data = weights["fc.bias"]
diff --git a/clean/image/cospy/detectors/sd-v1_4/__init__.py b/clean/image/cospy/detectors/sd-v1_4/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..c9411800ca98dd45775d08a0160c377ab08421ed
--- /dev/null
+++ b/clean/image/cospy/detectors/sd-v1_4/__init__.py
@@ -0,0 +1,7 @@
+from .base import BaseDetector
+from .artifact import ArtifactDetector
+from .semantic import SemanticDetector
+from .fusion import CoSpyFusionDetector
+from .end2end import End2EndDetector
+
+__all__ = ["BaseDetector", "ArtifactDetector", "SemanticDetector", "CoSpyFusionDetector", "End2EndDetector"]
diff --git a/clean/image/cospy/detectors/sd-v1_4/artifact.py b/clean/image/cospy/detectors/sd-v1_4/artifact.py
new file mode 100644
index 0000000000000000000000000000000000000000..a808c1900f7696afde77a022d1629b3648e64290
--- /dev/null
+++ b/clean/image/cospy/detectors/sd-v1_4/artifact.py
@@ -0,0 +1,200 @@
+import torch
+import torch.nn as nn
+from diffusers import StableDiffusionPipeline
+from torchvision import transforms
+from utils import data_augment
+from .base import BaseDetector
+
+
+class ArtifactDetector(BaseDetector):
+ def __init__(self, dim_artifact=512, num_classes=1):
+ super(ArtifactDetector, self).__init__()
+
+ # Load the pre-trained VAE
+ model_id = "CompVis/stable-diffusion-v1-4"
+ vae = StableDiffusionPipeline.from_pretrained(model_id).vae
+ vae.requires_grad_(False)
+ self.artifact_encoder = VAEReconEncoder(vae)
+
+ # Classifier
+ self.fc = torch.nn.Linear(dim_artifact, num_classes)
+
+ # Build transforms
+ self._build_transforms()
+
+ def _build_transforms(self):
+ # Normalization
+ self.mean = [0.0, 0.0, 0.0]
+ self.std = [1.0, 1.0, 1.0]
+
+ # Resolution
+ self.loadSize = 256
+ self.cropSize = 224
+
+ # Data augmentation
+ self.blur_prob = 0.0
+ self.blur_sig = [0.0, 3.0]
+ self.jpg_prob = 0.5
+ self.jpg_method = ['cv2', 'pil']
+ self.jpg_qual = list(range(70, 96))
+
+ # Define the augmentation configuration
+ self.aug_config = {
+ "blur_prob": self.blur_prob,
+ "blur_sig": self.blur_sig,
+ "jpg_prob": self.jpg_prob,
+ "jpg_method": self.jpg_method,
+ "jpg_qual": self.jpg_qual,
+ }
+
+ # Pre-processing
+ crop_func = transforms.RandomCrop(self.cropSize)
+ flip_func = transforms.RandomHorizontalFlip()
+ rz_func = transforms.Resize(self.loadSize)
+ aug_func = transforms.Lambda(lambda x: data_augment(x, self.aug_config))
+
+ self.train_transform = transforms.Compose([
+ aug_func,
+ rz_func,
+ crop_func,
+ flip_func,
+ transforms.ToTensor(),
+ transforms.Normalize(mean=self.mean, std=self.std),
+ ])
+
+ self.test_transform = transforms.Compose([
+ rz_func,
+ crop_func,
+ transforms.ToTensor(),
+ transforms.Normalize(mean=self.mean, std=self.std),
+ ])
+
+ def forward(self, x, return_feat=False):
+ feat = self.artifact_encoder(x)
+ out = self.fc(feat)
+ if return_feat:
+ return feat, out
+ return out
+
+
+# Helper functions for ResNet
+def conv3x3(in_planes, out_planes, stride=1):
+ """3x3 convolution with padding"""
+ return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, padding=1, bias=False)
+
+
+def conv1x1(in_planes, out_planes, stride=1):
+ """1x1 convolution"""
+ return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False)
+
+
+class Bottleneck(nn.Module):
+ expansion = 4
+
+ def __init__(self, inplanes, planes, stride=1, downsample=None):
+ super(Bottleneck, self).__init__()
+ self.conv1 = conv1x1(inplanes, planes)
+ self.bn1 = nn.BatchNorm2d(planes)
+ self.conv2 = conv3x3(planes, planes, stride)
+ self.bn2 = nn.BatchNorm2d(planes)
+ self.conv3 = conv1x1(planes, planes * self.expansion)
+ self.bn3 = nn.BatchNorm2d(planes * self.expansion)
+ self.relu = nn.ReLU(inplace=True)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x):
+ identity = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+ out = self.relu(out)
+
+ out = self.conv3(out)
+ out = self.bn3(out)
+
+ if self.downsample is not None:
+ identity = self.downsample(x)
+
+ out += identity
+ out = self.relu(out)
+
+ return out
+
+
+class VAEReconEncoder(nn.Module):
+ def __init__(self, vae, block=Bottleneck):
+ super(VAEReconEncoder, self).__init__()
+
+ # Define the ResNet model
+ self.inplanes = 64
+ self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=2, padding=1, bias=False)
+ self.bn1 = nn.BatchNorm2d(64)
+ self.relu = nn.ReLU(inplace=True)
+ self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
+
+ # ResNet-50 is [3, 4, 6, 3]
+ self.layer1 = self._make_layer(block, 64, 3)
+ self.layer2 = self._make_layer(block, 128, 4, stride=2)
+
+ self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
+
+ # Kaiming initialization
+ for m in self.modules():
+ if isinstance(m, nn.Conv2d):
+ nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
+ elif isinstance(m, nn.BatchNorm2d):
+ nn.init.constant_(m.weight, 1)
+ nn.init.constant_(m.bias, 0)
+
+ # Load the VAE model
+ self.vae = vae
+
+ def _make_layer(self, block, planes, blocks, stride=1):
+ downsample = None
+ if stride != 1 or self.inplanes != planes * block.expansion:
+ downsample = nn.Sequential(
+ conv1x1(self.inplanes, planes * block.expansion, stride),
+ nn.BatchNorm2d(planes * block.expansion),
+ )
+
+ layers = []
+ layers.append(block(self.inplanes, planes, stride, downsample))
+ self.inplanes = planes * block.expansion
+ for _ in range(1, blocks):
+ layers.append(block(self.inplanes, planes))
+
+ return nn.Sequential(*layers)
+
+ def reconstruct(self, x):
+ with torch.no_grad():
+ latent = self.vae.encode(x).latent_dist.mean
+ decoded = self.vae.decode(latent).sample
+ return decoded
+
+ def forward(self, x):
+ # Reconstruct
+ x_recon = self.reconstruct(x)
+ # Compute the artifacts
+ x = x - x_recon
+
+ # Scale the artifacts
+ x = x / 7. * 100.
+
+ # Forward pass
+ x = self.conv1(x)
+ x = self.bn1(x)
+ x = self.relu(x)
+ x = self.maxpool(x)
+
+ x = self.layer1(x)
+ x = self.layer2(x)
+
+ x = self.avgpool(x)
+ x = x.view(x.size(0), -1)
+
+ return x
diff --git a/clean/image/cospy/detectors/sd-v1_4/base.py b/clean/image/cospy/detectors/sd-v1_4/base.py
new file mode 100644
index 0000000000000000000000000000000000000000..79313e4e60b262eb616de38336002b266842327b
--- /dev/null
+++ b/clean/image/cospy/detectors/sd-v1_4/base.py
@@ -0,0 +1,36 @@
+import torch
+from abc import ABC, abstractmethod
+
+
+class BaseDetector(torch.nn.Module, ABC):
+ """Abstract base class for all detectors."""
+
+ def __init__(self):
+ super(BaseDetector, self).__init__()
+
+ @abstractmethod
+ def _build_transforms(self):
+ """Build train and test transforms."""
+ pass
+
+ @abstractmethod
+ def forward(self, x, return_feat=False):
+ """Forward pass of the detector."""
+ pass
+
+ def predict(self, inputs):
+ """Prediction function."""
+ inputs = inputs.to(next(self.parameters()).device)
+ outputs = self.forward(inputs)
+ prediction = outputs.sigmoid().flatten().tolist()
+ return prediction
+
+ def save_weights(self, weights_path):
+ """Save model weights to a file."""
+ save_params = {k: v.cpu() for k, v in self.state_dict().items()}
+ torch.save(save_params, weights_path)
+
+ def load_weights(self, weights_path):
+ """Load model weights from a file."""
+ weights = torch.load(weights_path, map_location='cpu')
+ self.load_state_dict(weights, strict=False)
diff --git a/clean/image/cospy/detectors/sd-v1_4/end2end.py b/clean/image/cospy/detectors/sd-v1_4/end2end.py
new file mode 100644
index 0000000000000000000000000000000000000000..c931c0cd4389fa916e80e210dd89e15dea3b14bc
--- /dev/null
+++ b/clean/image/cospy/detectors/sd-v1_4/end2end.py
@@ -0,0 +1,122 @@
+import torch
+import random
+from torchvision import transforms
+from utils import data_augment, weights2cpu
+from .base import BaseDetector
+from .semantic import SemanticDetector
+from .artifact import ArtifactDetector
+
+
+class End2EndDetector(BaseDetector):
+ """CO-SPY End-to-End Detector."""
+
+ def __init__(self, num_classes=1):
+ super(End2EndDetector, self).__init__()
+
+ # Load the semantic detector
+ self.sem = SemanticDetector()
+ self.sem_dim = self.sem.fc.in_features
+
+ # Load the artifact detector
+ self.art = ArtifactDetector()
+ self.art_dim = self.art.fc.in_features
+
+ # Classifier
+ self.fc = torch.nn.Linear(self.sem_dim + self.art_dim, num_classes)
+
+ # Transformations inside the forward function
+ # Including the normalization and resizing (only for the artifact detector)
+ self.sem_transform = transforms.Compose([
+ transforms.Normalize(self.sem.mean, self.sem.std)
+ ])
+ self.art_transform = transforms.Compose([
+ transforms.Resize(self.art.cropSize, antialias=False),
+ transforms.Normalize(self.art.mean, self.art.std)
+ ])
+
+ # Build transforms (no normalization, done in forward)
+ self._build_transforms()
+
+ def _build_transforms(self):
+ """Build transforms without normalization (normalization done per-branch in forward)."""
+
+ # Resolution
+ self.loadSize = 384
+ self.cropSize = 384
+
+ # Data augmentation
+ self.blur_prob = 0.0
+ self.blur_sig = [0.0, 3.0]
+ self.jpg_prob = 0.5
+ self.jpg_method = ['cv2', 'pil']
+ self.jpg_qual = list(range(70, 96))
+
+ # Define the augmentation configuration
+ self.aug_config = {
+ "blur_prob": self.blur_prob,
+ "blur_sig": self.blur_sig,
+ "jpg_prob": self.jpg_prob,
+ "jpg_method": self.jpg_method,
+ "jpg_qual": self.jpg_qual,
+ }
+
+ crop_func = transforms.RandomCrop(self.cropSize)
+ flip_func = transforms.RandomHorizontalFlip()
+ rz_func = transforms.Resize(self.loadSize)
+ aug_func = transforms.Lambda(lambda x: data_augment(x, self.aug_config))
+
+ self.train_transform = transforms.Compose([
+ flip_func,
+ aug_func,
+ rz_func,
+ crop_func,
+ transforms.ToTensor(),
+ ])
+
+ self.test_transform = transforms.Compose([
+ rz_func,
+ crop_func,
+ transforms.ToTensor(),
+ ])
+
+ def forward(self, x, return_feat=False, dropout_rate=0.3):
+ x_sem = self.sem_transform(x)
+ x_art = self.art_transform(x)
+
+ # Forward pass
+ sem_feat, sem_coeff = self.sem(x_sem, return_feat=True)
+ art_feat, art_coeff = self.art(x_art, return_feat=True)
+
+ # Dropout during training
+ if self.training:
+ if random.random() < dropout_rate:
+ # Randomly select a feature to drop
+ idx_drop = random.randint(0, 1)
+ if idx_drop == 0:
+ sem_coeff = torch.zeros_like(sem_coeff)
+ else:
+ art_coeff = torch.zeros_like(art_coeff)
+
+ # Concatenate the features
+ feat = torch.cat([sem_coeff * sem_feat, art_coeff * art_feat], dim=1)
+ out = self.fc(feat)
+
+ if return_feat:
+ return feat, out
+ return out
+
+ def save_weights(self, weights_path):
+ save_params = {
+ "sem_fc": weights2cpu(self.sem.fc.state_dict()),
+ "art_fc": weights2cpu(self.art.fc.state_dict()),
+ "art_encoder": weights2cpu(self.art.artifact_encoder.state_dict()),
+ "classifier": weights2cpu(self.fc.state_dict()),
+ }
+ torch.save(save_params, weights_path)
+
+ def load_weights(self, weights_path):
+ weights = torch.load(weights_path, map_location='cpu')
+ self.sem.fc.load_state_dict(weights["sem_fc"])
+ self.art.fc.load_state_dict(weights["art_fc"])
+ self.art.artifact_encoder.load_state_dict(weights["art_encoder"])
+ self.fc.load_state_dict(weights["classifier"])
diff --git a/clean/image/cospy/detectors/sd-v1_4/fusion.py b/clean/image/cospy/detectors/sd-v1_4/fusion.py
new file mode 100644
index 0000000000000000000000000000000000000000..cd1a84ff383eb6ef47289cf4bb759b21e8e35669
--- /dev/null
+++ b/clean/image/cospy/detectors/sd-v1_4/fusion.py
@@ -0,0 +1,107 @@
+import torch
+from torchvision import transforms
+from utils import data_augment
+from .base import BaseDetector
+from .semantic import SemanticDetector
+from .artifact import ArtifactDetector
+
+
+class CoSpyFusionDetector(BaseDetector):
+ """CO-SPY Fusion Detector (calibrate and fuse semantic and artifact detectors)."""
+
+ def __init__(self, semantic_weights_path, artifact_weights_path, num_classes=1):
+ super(CoSpyFusionDetector, self).__init__()
+
+ # Load the semantic detector
+ self.sem = SemanticDetector()
+ self.sem.load_weights(semantic_weights_path)
+
+ # Load the artifact detector
+ self.art = ArtifactDetector()
+ self.art.load_weights(artifact_weights_path)
+
+ # Freeze the two pre-trained models
+ for param in self.sem.parameters():
+ param.requires_grad = False
+ for param in self.art.parameters():
+ param.requires_grad = False
+
+ # Classifier
+ self.fc = torch.nn.Linear(2, num_classes)
+
+ # Transformations inside the forward function
+ # Including the normalization and resizing (only for the artifact detector)
+ self.sem_transform = transforms.Compose([
+ transforms.Normalize(self.sem.mean, self.sem.std)
+ ])
+ self.art_transform = transforms.Compose([
+ transforms.Resize(self.art.cropSize, antialias=False),
+ transforms.Normalize(self.art.mean, self.art.std)
+ ])
+
+ # Build transforms (no normalization, done in forward)
+ self._build_transforms()
+
+ def _build_transforms(self):
+ """Build transforms without normalization (normalization done per-branch in forward)."""
+
+ # Resolution
+ self.loadSize = 384
+ self.cropSize = 384
+
+ # Data augmentation
+ self.blur_prob = 0.0
+ self.blur_sig = [0.0, 3.0]
+ self.jpg_prob = 0.5
+ self.jpg_method = ['cv2', 'pil']
+ self.jpg_qual = list(range(70, 96))
+
+ # Define the augmentation configuration
+ self.aug_config = {
+ "blur_prob": self.blur_prob,
+ "blur_sig": self.blur_sig,
+ "jpg_prob": self.jpg_prob,
+ "jpg_method": self.jpg_method,
+ "jpg_qual": self.jpg_qual,
+ }
+
+ crop_func = transforms.RandomCrop(self.cropSize)
+ flip_func = transforms.RandomHorizontalFlip()
+ rz_func = transforms.Resize(self.loadSize)
+ aug_func = transforms.Lambda(lambda x: data_augment(x, self.aug_config))
+
+ self.train_transform = transforms.Compose([
+ flip_func,
+ aug_func,
+ rz_func,
+ crop_func,
+ transforms.ToTensor(),
+ ])
+
+ self.test_transform = transforms.Compose([
+ rz_func,
+ crop_func,
+ transforms.ToTensor(),
+ ])
+
+ def forward(self, x, return_feat=False):
+ x_sem = self.sem_transform(x)
+ x_art = self.art_transform(x)
+ pred_sem = self.sem(x_sem)
+ pred_art = self.art(x_art)
+ feat = torch.cat([pred_sem, pred_art], dim=1)
+ out = self.fc(feat)
+ if return_feat:
+ return feat, out
+ return out
+
+ def save_weights(self, weights_path):
+ # Only save the fc layer (sub-detectors are frozen)
+ save_params = {"fc.weight": self.fc.weight.cpu(), "fc.bias": self.fc.bias.cpu()}
+ torch.save(save_params, weights_path)
+
+ def load_weights(self, weights_path):
+ # Load only the fc layer
+ weights = torch.load(weights_path, map_location='cpu')
+ self.fc.weight.data = weights["fc.weight"]
+ self.fc.bias.data = weights["fc.bias"]
diff --git a/clean/image/cospy/detectors/sd-v1_4/semantic.py b/clean/image/cospy/detectors/sd-v1_4/semantic.py
new file mode 100644
index 0000000000000000000000000000000000000000..ff9b08138da36a11512a15fb0362e2459ecb7e45
--- /dev/null
+++ b/clean/image/cospy/detectors/sd-v1_4/semantic.py
@@ -0,0 +1,89 @@
+import torch
+import open_clip
+from torchvision import transforms
+from utils import data_augment
+from .base import BaseDetector
+
+
+class SemanticDetector(BaseDetector):
+ def __init__(self, dim_clip=1152, num_classes=1):
+ super(SemanticDetector, self).__init__()
+
+ # Get the pre-trained CLIP (SigLIP)
+ model_name = "ViT-SO400M-14-SigLIP-384"
+ version = "webli"
+ self.clip, _, _ = open_clip.create_model_and_transforms(model_name, pretrained=version)
+
+ # Freeze the CLIP visual encoder
+ self.clip.requires_grad_(False)
+
+ # Classifier
+ self.fc = torch.nn.Linear(dim_clip, num_classes)
+
+ # Build transforms
+ self._build_transforms()
+
+ def _build_transforms(self):
+ # Normalization
+ self.mean = [0.5, 0.5, 0.5]
+ self.std = [0.5, 0.5, 0.5]
+
+ # Resolution
+ self.loadSize = 384
+ self.cropSize = 384
+
+ # Data augmentation
+ self.blur_prob = 0.5
+ self.blur_sig = [0.0, 3.0]
+ self.jpg_prob = 0.5
+ self.jpg_method = ['cv2', 'pil']
+ self.jpg_qual = list(range(30, 101))
+
+ # Define the augmentation configuration
+ self.aug_config = {
+ "blur_prob": self.blur_prob,
+ "blur_sig": self.blur_sig,
+ "jpg_prob": self.jpg_prob,
+ "jpg_method": self.jpg_method,
+ "jpg_qual": self.jpg_qual,
+ }
+
+ # Pre-processing
+ crop_func = transforms.RandomCrop(self.cropSize)
+ flip_func = transforms.RandomHorizontalFlip()
+ rz_func = transforms.Resize(self.loadSize)
+ aug_func = transforms.Lambda(lambda x: data_augment(x, self.aug_config))
+
+ self.train_transform = transforms.Compose([
+ rz_func,
+ aug_func,
+ crop_func,
+ flip_func,
+ transforms.ToTensor(),
+ transforms.Normalize(mean=self.mean, std=self.std),
+ ])
+
+ self.test_transform = transforms.Compose([
+ rz_func,
+ crop_func,
+ transforms.ToTensor(),
+ transforms.Normalize(mean=self.mean, std=self.std),
+ ])
+
+ def forward(self, x, return_feat=False):
+ feat = self.clip.encode_image(x)
+ out = self.fc(feat)
+ if return_feat:
+ return feat, out
+ return out
+
+ def save_weights(self, weights_path):
+ # Only save the fc layer (CLIP is frozen)
+ save_params = {"fc.weight": self.fc.weight.cpu(), "fc.bias": self.fc.bias.cpu()}
+ torch.save(save_params, weights_path)
+
+ def load_weights(self, weights_path):
+ # Only load the fc layer
+ weights = torch.load(weights_path, map_location='cpu')
+ self.fc.weight.data = weights["fc.weight"]
+ self.fc.bias.data = weights["fc.bias"]
diff --git a/clean/image/cospy/environment.yml b/clean/image/cospy/environment.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b9ab51459e14e99fe1f06d3b20feea84fc46638a
--- /dev/null
+++ b/clean/image/cospy/environment.yml
@@ -0,0 +1,105 @@
+name: cospy
+channels:
+ - defaults
+dependencies:
+ - _libgcc_mutex=0.1=main
+ - _openmp_mutex=5.1=1_gnu
+ - ca-certificates=2025.2.25=h06a4308_0
+ - ld_impl_linux-64=2.40=h12ee557_0
+ - libffi=3.4.4=h6a678d5_1
+ - libgcc-ng=11.2.0=h1234567_1
+ - libgomp=11.2.0=h1234567_1
+ - libstdcxx-ng=11.2.0=h1234567_1
+ - ncurses=6.4=h6a678d5_0
+ - openssl=3.0.16=h5eee18b_0
+ - pip=24.2=py38h06a4308_0
+ - python=3.8.18=h955ad1f_0
+ - readline=8.2=h5eee18b_0
+ - setuptools=75.1.0=py38h06a4308_0
+ - sqlite=3.45.3=h5eee18b_0
+ - tk=8.6.14=h39e8969_0
+ - wheel=0.44.0=py38h06a4308_0
+ - xz=5.6.4=h5eee18b_1
+ - zlib=1.2.13=h5eee18b_1
+ - pip:
+ - accelerate==1.0.1
+ - aiohappyeyeballs==2.4.4
+ - aiohttp==3.10.11
+ - aiosignal==1.3.1
+ - async-timeout==5.0.1
+ - attrs==25.3.0
+ - certifi==2025.1.31
+ - charset-normalizer==3.4.1
+ - contourpy==1.1.1
+ - cycler==0.12.1
+ - datasets==3.1.0
+ - diffusers==0.32.2
+ - dill==0.3.8
+ - filelock==3.16.1
+ - fonttools==4.56.0
+ - frozenlist==1.5.0
+ - fsspec==2024.9.0
+ - ftfy==6.2.3
+ - huggingface-hub==0.29.3
+ - idna==3.10
+ - importlib-metadata==8.5.0
+ - importlib-resources==6.4.5
+ - jinja2==3.1.6
+ - joblib==1.4.2
+ - kiwisolver==1.4.7
+ - loguru==0.7.3
+ - markupsafe==2.1.5
+ - matplotlib==3.7.5
+ - mpmath==1.3.0
+ - multidict==6.1.0
+ - multiprocess==0.70.16
+ - networkx==3.1
+ - numpy==1.24.4
+ - nvidia-cublas-cu12==12.1.3.1
+ - nvidia-cuda-cupti-cu12==12.1.105
+ - nvidia-cuda-nvrtc-cu12==12.1.105
+ - nvidia-cuda-runtime-cu12==12.1.105
+ - nvidia-cudnn-cu12==9.1.0.70
+ - nvidia-cufft-cu12==11.0.2.54
+ - nvidia-curand-cu12==10.3.2.106
+ - nvidia-cusolver-cu12==11.4.5.107
+ - nvidia-cusparse-cu12==12.1.0.106
+ - nvidia-nccl-cu12==2.20.5
+ - nvidia-nvjitlink-cu12==12.8.93
+ - nvidia-nvtx-cu12==12.1.105
+ - open-clip-torch==2.31.0
+ - opencv-python==4.11.0.86
+ - packaging==24.2
+ - pandas==2.0.3
+ - pillow==10.4.0
+ - propcache==0.2.0
+ - psutil==7.0.0
+ - pyarrow==17.0.0
+ - pycocotools==2.0.7
+ - pyparsing==3.1.4
+ - python-dateutil==2.9.0.post0
+ - pytz==2025.1
+ - pyyaml==6.0.2
+ - regex==2024.11.6
+ - requests==2.32.3
+ - safetensors==0.5.3
+ - scikit-learn==1.3.2
+ - scipy==1.10.1
+ - six==1.17.0
+ - sympy==1.13.3
+ - threadpoolctl==3.5.0
+ - timm==1.0.15
+ - tokenizers==0.20.3
+ - torch==2.4.1
+ - torchvision==0.19.1
+ - tqdm==4.67.1
+ - transformers==4.46.3
+ - triton==3.0.0
+ - typing-extensions==4.12.2
+ - tzdata==2025.1
+ - urllib3==2.2.3
+ - wcwidth==0.2.13
+ - xxhash==3.5.0
+ - yarl==1.15.2
+ - zipp==3.20.2
+prefix: /connect4/cheng535-new/anaconda3/envs/cospy
diff --git a/clean/image/cospy/evaluate.py b/clean/image/cospy/evaluate.py
new file mode 100644
index 0000000000000000000000000000000000000000..e809ad3d5e33d688d236c3b9603a544e668307ad
--- /dev/null
+++ b/clean/image/cospy/evaluate.py
@@ -0,0 +1,170 @@
+import os
+import json
+import torch
+import importlib
+import numpy as np
+from tqdm import tqdm
+from PIL import Image
+from loguru import logger
+
+from dataSets import *
+from utils import seed_torch, evaluate
+
+import warnings
+warnings.filterwarnings("ignore")
+
+
+# Load pre-trained models for evaluation
+class Detector:
+ def __init__(self,
+ device: str,
+ mode: str = "fusion",
+ train_dataset: str = "sd-v1_4",
+ pretrain: bool = False,
+ ckpt: str = "ckpt",
+ batch_size: int = 32):
+
+ # Device
+ self.device = device
+ self.mode = mode
+ self.train_dataset = train_dataset
+ self.pretrain = pretrain
+ self.ckpt = ckpt
+ self.batch_size = batch_size
+
+ # Dynamically import the detector module from either "progan" or "sd-v1_4"
+ detector_module = importlib.import_module(f"detectors.{train_dataset}")
+
+ # Get the detector and load weights based on mode
+ if pretrain:
+ # Only provide pre-trained weights for fusion mode
+ # Hardcode to fusion mode
+ self.mode = "fusion"
+ # Load the fusion detector with pre-trained weights
+ semantic_weights_path = f"pretrained/{self.train_dataset}/semantic_weights.pth"
+ artifact_weights_path = f"pretrained/{self.train_dataset}/artifact_weights.pth"
+ fusion_weights_path = f"pretrained/{self.train_dataset}/fusion_weights.pth"
+ if not os.path.exists(semantic_weights_path) or not os.path.exists(artifact_weights_path) or not os.path.exists(fusion_weights_path):
+ raise ValueError("The pre-trained weights are not complete for evaluation")
+ CoSpyFusionDetector = getattr(detector_module, "CoSpyFusionDetector")
+ self.model = CoSpyFusionDetector(
+ semantic_weights_path=semantic_weights_path,
+ artifact_weights_path=artifact_weights_path)
+ self.model.load_weights(fusion_weights_path)
+ else:
+ if self.mode == "fusion":
+ semantic_weights_path = os.path.join(self.ckpt, self.train_dataset, "semantic", "best_model.pth")
+ artifact_weights_path = os.path.join(self.ckpt, self.train_dataset, "artifact", "best_model.pth")
+ fusion_weights_path = os.path.join(self.ckpt, self.train_dataset, "fusion", "best_model.pth")
+ if not os.path.exists(semantic_weights_path) or not os.path.exists(artifact_weights_path) or not os.path.exists(fusion_weights_path):
+ raise ValueError("Semantic, Artifact or Fusion weights path does not exist for fusion mode")
+ CoSpyFusionDetector = getattr(detector_module, "CoSpyFusionDetector")
+ self.model = CoSpyFusionDetector(
+ semantic_weights_path=semantic_weights_path,
+ artifact_weights_path=artifact_weights_path)
+ self.model.load_weights(fusion_weights_path)
+ elif self.mode == "end2end":
+ End2EndDetector = getattr(detector_module, "End2EndDetector")
+ self.model = End2EndDetector()
+ end2end_weights_path = os.path.join(self.ckpt, self.train_dataset, "end2end", "best_model.pth")
+ if not os.path.exists(end2end_weights_path):
+ raise ValueError("End2End weights path does not exist for end2end mode")
+ self.model.load_weights(end2end_weights_path)
+ else:
+ raise ValueError(f"Unknown mode: {self.mode}")
+
+ # Put the model on the device and set to eval
+ self.model.to(self.device)
+ self.model.eval()
+
+ def evaluate_benchmark(self):
+ # Select the appropriate test dataset and evaluation lists
+ if self.train_dataset == "progan":
+ benchmark_name = "AIGCDetectionBenchMark"
+ TestDataset = AIGCDetectTestDataset
+ eval_dataset_list = AIGCDetectionBenchMark_DATASET_LIST
+ eval_model_list = AIGCDetectionBenchMark_MODEL_LIST
+ elif self.train_dataset == "sd-v1_4":
+ benchmark_name = "Co-Spy-Bench"
+ TestDataset = CoSpyBenchTestDataset
+ eval_dataset_list = CoSpyBench_DATASET_LIST
+ eval_model_list = CoSpyBench_MODEL_LIST
+ else:
+ raise ValueError(f"Unknown train dataset: {self.train_dataset}")
+
+ # Set the saving directory
+ if self.pretrain:
+ save_dir = os.path.join(self.ckpt, self.train_dataset, self.mode, f"pretrain_{benchmark_name}")
+ else:
+ save_dir = os.path.join(self.ckpt, self.train_dataset, self.mode, f"eval_{benchmark_name}")
+ if not os.path.exists(save_dir):
+ os.makedirs(save_dir)
+
+ # Setup logger
+ log_path = f"{save_dir}/evaluation.log"
+ if os.path.exists(log_path):
+ os.remove(log_path)
+
+ logger_id = logger.add(
+ log_path,
+ format="{time:MM-DD at HH:mm:ss} | {level} | {module}:{line} | {message}",
+ level="DEBUG",
+ )
+
+ # Save raw model prediction
+ save_output_path = os.path.join(save_dir, "output.json")
+ # Save summarized evaluation result
+ save_result_path = os.path.join(save_dir, "result.json")
+
+ # Begin the evaluation
+ result_all = {}
+ output_all = {}
+ for dataset_name in eval_dataset_list:
+ result_all[dataset_name] = {}
+ output_all[dataset_name] = {}
+ for model_name in eval_model_list:
+ test_dataset = TestDataset(dataset=dataset_name, model=model_name, transform=self.model.test_transform)
+ test_loader = torch.utils.data.DataLoader(test_dataset,
+ batch_size=self.batch_size,
+ shuffle=False,
+ num_workers=4,
+ pin_memory=True)
+
+ # Evaluate the model
+ y_pred, y_true = [], []
+ for (images, labels) in tqdm(test_loader, desc=f"Evaluating {benchmark_name} - {dataset_name} - {model_name}"):
+ y_pred.extend(self.model.predict(images))
+ y_true.extend(labels.tolist())
+
+ ap, accuracy = evaluate(y_pred, y_true)
+ logger.info(f"Evaluate on {benchmark_name} - {dataset_name} - {model_name} | Size {len(y_true)} | AP {ap*100:.2f}% | Accuracy {accuracy*100:.2f}%")
+
+ result_all[dataset_name][model_name] = {"size": len(y_true), "AP": ap, "Accuracy": accuracy}
+ output_all[dataset_name][model_name] = {"y_pred": y_pred, "y_true": y_true}
+
+ # Save the results
+ with open(save_result_path, "w") as f:
+ json.dump(result_all, f, indent=4)
+
+ with open(save_output_path, "w") as f:
+ json.dump(output_all, f, indent=4)
+
+ def scan(self):
+ # Load the image
+ image_filepath = input("Please enter the image filepath for scanning: ")
+ if not os.path.exists(image_filepath):
+ print(f"Image file not found: {image_filepath}")
+ image_filepath = input("Please enter the image filepath for scanning: ")
+
+ image = Image.open(image_filepath).convert("RGB")
+ image = self.model.test_transform(image)
+ image = image.unsqueeze(0)
+ image = image.to(self.device)
+
+ # Make the prediction
+ prediction = self.model.predict(image)[0]
+
+ if prediction > 0.5:
+ print(f"Co-Spy Prediction: {prediction:.3f} - AI-Generated")
+ else:
+ print(f"Co-Spy Prediction: {prediction:.3f} - Real")
diff --git a/clean/image/cospy/main.py b/clean/image/cospy/main.py
new file mode 100644
index 0000000000000000000000000000000000000000..21cbf2390779679d4a7ca467c5b3637b61c5793e
--- /dev/null
+++ b/clean/image/cospy/main.py
@@ -0,0 +1,117 @@
+import torch
+from train import Trainer
+from evaluate import Detector
+from utils import seed_torch
+
+
+def main(args):
+ #########################################
+ # Phase 1: Training
+ #########################################
+ if args.phase == "train":
+ # Initialize Trainer
+ trainer = Trainer(
+ mode=args.mode,
+ device=args.device,
+ branch=args.branch,
+ train_dataset=args.train_dataset,
+ label_smooth=args.label_smooth,
+ ckpt=args.ckpt,
+ epochs=args.epochs,
+ batch_size=args.batch_size
+ )
+ # Start training
+ trainer.train()
+ #########################################
+ # Phase 2: Evaluation
+ #########################################
+ elif args.phase == "eval":
+ # Initialize Detector
+ detector = Detector(
+ device=args.device,
+ mode=args.mode,
+ train_dataset=args.train_dataset,
+ pretrain=args.pretrain,
+ ckpt=args.ckpt,
+ batch_size=args.batch_size
+ )
+ # Start evaluation
+ detector.evaluate_benchmark()
+ ##########################################
+ # Phase 3: Test on a single image
+ ##########################################
+ elif args.phase == "test":
+ # Initialize Detector
+ detector = Detector(
+ device=args.device,
+ mode=args.mode,
+ train_dataset=args.train_dataset,
+ pretrain=args.pretrain,
+ ckpt=args.ckpt,
+ batch_size=args.batch_size
+ )
+ # Test on a single image
+ score = detector.scan()
+ else:
+ raise ValueError(f"Unknown phase: {args.phase}")
+
+
+if __name__ == "__main__":
+ import argparse
+ parser = argparse.ArgumentParser("Co-Spy: Combining Semantic and Pixel Features to Detect Synthetic Images by AI")
+ parser.add_argument("--gpu",
+ type=int,
+ default=0,
+ help="GPU id to use")
+ parser.add_argument("--phase",
+ type=str,
+ default="test",
+ choices=["train", "eval", "test"],
+ help="Select the phase to run Co-Spy: train / eval / test")
+ parser.add_argument("--mode",
+ type=str,
+ default="fusion",
+ choices=["branch", "fusion", "end2end"],
+ help="Select the mode of Co-Spy training")
+ parser.add_argument("--train_dataset",
+ type=str,
+ default="sd-v1_4",
+ help="Training dataset")
+ parser.add_argument("--branch",
+ type=str,
+ default="artifact",
+ choices=["artifact", "semantic"],
+ help="Branch detector (for branch mode)")
+ parser.add_argument("--label_smooth",
+ action="store_true",
+ help="Whether to use label smoothing during training")
+ parser.add_argument("--pretrain",
+ action="store_true",
+ help="Whether to use pre-trained weights for evaluation")
+ parser.add_argument("--ckpt",
+ type=str,
+ default="ckpt",
+ help="Checkpoint directory")
+ parser.add_argument("--epochs",
+ type=int,
+ default=20,
+ help="Number of training epochs")
+ parser.add_argument("--batch_size",
+ type=int,
+ default=32,
+ help="Batch size")
+ parser.add_argument("--seed",
+ type=int,
+ default=1024,
+ help="Random seed")
+
+ args = parser.parse_args()
+
+ # Set random seed
+ seed_torch(args.seed)
+
+ # Set GPU device
+ args.device = f"cuda:{args.gpu}" if torch.cuda.is_available() else "cpu"
+
+ # Run the experiment
+ main(args)
diff --git a/clean/image/cospy/pretrained/download.sh b/clean/image/cospy/pretrained/download.sh
new file mode 100644
index 0000000000000000000000000000000000000000..1661445ce12f1020fd182c8c8f40478c604785b2
--- /dev/null
+++ b/clean/image/cospy/pretrained/download.sh
@@ -0,0 +1,13 @@
+# Download pre-trained weights for CO-SPY
+# Pre-trained weights on CNNDet (ProGAN)
+wget https://huggingface.co/ruojiruoli/Co-Spy-Pretrained-Weights/resolve/main/progan.zip
+unzip progan.zip
+rm progan.zip
+
+# Pre-trained weights on DRCT-2M (Stable Diffusion v1.4)
+wget https://huggingface.co/ruojiruoli/Co-Spy-Pretrained-Weights/resolve/main/sd-v1_4.zip
+unzip sd-v1_4.zip
+rm sd-v1_4.zip
+
+# Clean up unnecessary files
+rm -rf __MACOSX
diff --git a/clean/image/cospy/train.py b/clean/image/cospy/train.py
new file mode 100644
index 0000000000000000000000000000000000000000..80d0f5347c7c12c2d704f18f89849cb8a13e4dfe
--- /dev/null
+++ b/clean/image/cospy/train.py
@@ -0,0 +1,211 @@
+import os
+import time
+import torch
+import importlib
+from loguru import logger
+
+from utils import seed_torch, evaluate
+from dataSets import TrainDataset
+
+import warnings
+warnings.filterwarnings("ignore")
+
+
+class Trainer:
+ def __init__(self,
+ mode: str,
+ device: str,
+ branch: str,
+ train_dataset: str,
+ label_smooth: bool = False,
+ ckpt: str = "ckpt",
+ epochs: int = 20,
+ batch_size: int = 32):
+
+ self.device = device
+ self.mode = mode
+ self.branch = branch
+ self.train_dataset = train_dataset
+ self.label_smooth = label_smooth
+ self.ckpt = ckpt
+ self.epochs = epochs
+ self.batch_size = batch_size
+
+ # Dynamically import the detector module from either "progan" or "sd-v1_4"
+ detector_module = importlib.import_module(f"detectors.{train_dataset}")
+
+ # Get the detector based on mode
+ if self.mode == "branch":
+ ArtifactDetector = getattr(detector_module, "ArtifactDetector")
+ SemanticDetector = getattr(detector_module, "SemanticDetector")
+ if self.branch == "artifact":
+ self.model = ArtifactDetector()
+ elif self.branch == "semantic":
+ self.model = SemanticDetector()
+ else:
+ raise ValueError(f"Unknown detector: {self.branch}")
+ elif self.mode == "fusion":
+ semantic_weights_path = os.path.join(self.ckpt, self.train_dataset, "semantic", "best_model.pth")
+ artifact_weights_path = os.path.join(self.ckpt, self.train_dataset, "artifact", "best_model.pth")
+ if not os.path.exists(semantic_weights_path) or not os.path.exists(artifact_weights_path):
+ raise ValueError("Semantic or Artifact weights path does not exist for fusion mode")
+ CoSpyFusionDetector = getattr(detector_module, "CoSpyFusionDetector")
+ self.model = CoSpyFusionDetector(
+ semantic_weights_path=semantic_weights_path,
+ artifact_weights_path=artifact_weights_path)
+ elif self.mode == "end2end":
+ End2EndDetector = getattr(detector_module, "End2EndDetector")
+ self.model = End2EndDetector()
+ else:
+ raise ValueError(f"Unknown mode: {self.mode}")
+
+ self.model.to(self.device)
+
+ # Initialize the fc layer
+ torch.nn.init.normal_(self.model.fc.weight.data, 0.0, 0.02)
+ if self.mode == "end2end":
+ torch.nn.init.normal_(self.model.sem.fc.weight.data, 0.0, 0.02)
+ torch.nn.init.normal_(self.model.art.fc.weight.data, 0.0, 0.02)
+
+ # Optimizer
+ _beta1 = 0.9
+ _weight_decay = 0.0
+ params = [p for p in self.model.parameters() if p.requires_grad]
+ logger.info(f"Trainable parameters: {len(params)}")
+
+ self._lr = 1e-4 if self.mode != "fusion" else 1e-1
+ self.optimizer = torch.optim.AdamW(params, lr=self._lr, betas=(_beta1, 0.999), weight_decay=_weight_decay)
+
+ # Loss function
+ if self.label_smooth:
+ self.criterion = LabelSmoothingBCEWithLogits(smoothing=0.1)
+ else:
+ self.criterion = torch.nn.BCEWithLogitsLoss()
+
+ # Scheduler
+ self.delr_freq = 10
+
+ def train_step(self, batch_data):
+ inputs, labels = batch_data
+ inputs, labels = inputs.to(self.device), labels.to(self.device)
+
+ self.optimizer.zero_grad()
+ outputs = self.model(inputs)
+ loss = self.criterion(outputs, labels.unsqueeze(1).float())
+ loss.backward()
+ self.optimizer.step()
+
+ eval_loss = loss.item()
+ y_pred = outputs.sigmoid().flatten().tolist()
+ y_true = labels.tolist()
+ return eval_loss, y_pred, y_true
+
+ def scheduler(self, status_dict):
+ epoch = status_dict["epoch"]
+ if epoch % self.delr_freq == 0 and epoch != 0:
+ for param_group in self.optimizer.param_groups:
+ param_group["lr"] *= 0.9
+ self._lr = param_group["lr"]
+
+ def train(self):
+ # Determine data split and transform based on mode
+ if self.mode == "fusion":
+ train_split, val_split = "val", "val"
+ train_transform = self.model.test_transform
+ test_transform = self.model.test_transform
+ else: # branch or end2end mode
+ train_split, val_split = "train", "val"
+ train_transform = self.model.train_transform
+ test_transform = self.model.test_transform
+
+ # Determine save directory
+ if self.mode == "branch":
+ subdir = self.branch
+ else:
+ subdir = self.mode
+ # Set the saving directory
+ model_dir = os.path.join(self.ckpt, self.train_dataset, subdir)
+ if not os.path.exists(model_dir):
+ os.makedirs(model_dir)
+
+ # Setup logger
+ log_path = f"{model_dir}/training.log"
+ if os.path.exists(log_path):
+ os.remove(log_path)
+
+ logger_id = logger.add(
+ log_path,
+ format="{time:MM-DD at HH:mm:ss} | {level} | {module}:{line} | {message}",
+ level="DEBUG",
+ )
+
+ # Add JPEG compression for sd-v1_4 dataset
+ self.add_jpeg = True if self.train_dataset == "sd-v1_4" else False
+
+ # Load the training and validation dataset
+ train_dataset = TrainDataset(train_dataset=self.train_dataset,
+ split=train_split,
+ add_jpeg=self.add_jpeg,
+ transform=train_transform)
+ train_loader = torch.utils.data.DataLoader(train_dataset,
+ batch_size=self.batch_size,
+ shuffle=True,
+ num_workers=4,
+ pin_memory=True)
+ val_dataset = TrainDataset(train_dataset=self.train_dataset,
+ split=val_split,
+ add_jpeg=self.add_jpeg,
+ transform=test_transform)
+ val_loader = torch.utils.data.DataLoader(val_dataset,
+ batch_size=self.batch_size,
+ shuffle=False,
+ num_workers=4,
+ pin_memory=True)
+
+ logger.info(f"Train size {len(train_dataset)} | Val size {len(val_dataset)}")
+
+ # Train the detector
+ best_acc = 0
+ for epoch in range(self.epochs):
+ self.model.train()
+ time_start = time.time()
+ for step_id, batch_data in enumerate(train_loader):
+ eval_loss, y_pred, y_true = self.train_step(batch_data)
+ ap, accuracy = evaluate(y_pred, y_true)
+
+ if (step_id + 1) % 100 == 0:
+ time_end = time.time()
+ logger.info(f"Epoch {epoch} | Batch {step_id + 1}/{len(train_loader)} | Loss {eval_loss:.4f} | AP {ap*100:.2f}% | Accuracy {accuracy*100:.2f}% | Time {time_end-time_start:.2f}s")
+ time_start = time.time()
+
+ # Evaluate the model
+ self.model.eval()
+ y_pred, y_true = [], []
+ for (images, labels) in val_loader:
+ y_pred.extend(self.model.predict(images))
+ y_true.extend(labels.tolist())
+
+ ap, accuracy = evaluate(y_pred, y_true)
+ eval_type = "Test" if self.mode == "branch" else "Total"
+ logger.info(f"Epoch {epoch} | {eval_type} AP {ap*100:.2f}% | {eval_type} Accuracy {accuracy*100:.2f}%")
+
+ # Schedule the training
+ status_dict = {"epoch": epoch, "AP": ap, "Accuracy": accuracy}
+ self.scheduler(status_dict)
+
+ # Save the model
+ if accuracy >= best_acc:
+ best_acc = accuracy
+ self.model.save_weights(f"{model_dir}/best_model.pth")
+ logger.info(f"Best model saved with accuracy {best_acc*100:.2f}%")
+
+ if epoch % 5 == 0:
+ self.model.save_weights(f"{model_dir}/epoch_{epoch}.pth")
+ logger.info(f"Model saved at epoch {epoch}")
+
+ # Save the final model
+ self.model.save_weights(f"{model_dir}/final_model.pth")
+ logger.info("Final model saved")
+
+ # Remove the logger
+ logger.remove(logger_id)
diff --git a/clean/image/cospy/train.sh b/clean/image/cospy/train.sh
new file mode 100644
index 0000000000000000000000000000000000000000..bf886e2fc777f36c94e8338f83fc9b84aa063a5b
--- /dev/null
+++ b/clean/image/cospy/train.sh
@@ -0,0 +1,41 @@
+#!/bin/bash
+
+while [[ $# -gt 0 ]]; do
+ case $1 in
+ --dataset)
+ dataset="$2"
+ shift 2
+ ;;
+ --gpu)
+ gpu="$2"
+ shift 2
+ ;;
+ *)
+ echo "Unknown argument: $1"
+ exit 1
+ ;;
+ esac
+done
+
+python main.py \
+ --phase train \
+ --gpu $gpu \
+ --mode branch \
+ --branch artifact \
+ --train_dataset $dataset \
+ --epochs 20
+
+python main.py \
+ --phase train \
+ --gpu $gpu \
+ --mode branch \
+ --branch semantic \
+ --train_dataset $dataset \
+ --epochs 10
+
+python main.py \
+ --phase train \
+ --gpu $gpu \
+ --mode fusion \
+ --train_dataset $dataset \
+ --epochs 2
diff --git a/clean/image/cospy/utils.py b/clean/image/cospy/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..e72b7b71bafaa00434e50886617bfbe64cc8af47
--- /dev/null
+++ b/clean/image/cospy/utils.py
@@ -0,0 +1,182 @@
+import os
+import cv2
+import torch
+import pickle
+import random
+import numpy as np
+from io import BytesIO
+from PIL import Image, ImageFile
+from torchvision import transforms
+import torchvision.transforms.functional as TF
+from scipy.ndimage.filters import gaussian_filter
+from sklearn.metrics import average_precision_score
+
+ImageFile.LOAD_TRUNCATED_IMAGES = True
+
+
+# Set random seed
+def seed_torch(seed):
+ random.seed(seed)
+ os.environ['PYTHONHASHSEED'] = str(seed)
+ np.random.seed(seed)
+ torch.manual_seed(seed)
+ torch.cuda.manual_seed(seed)
+ torch.cuda.manual_seed_all(seed)
+ torch.backends.cudnn.benchmark = False
+ torch.backends.cudnn.deterministic = True
+
+
+# Load dataset
+def recursively_read(rootdir, must_contain, exts=["png", "PNG", "jpg", "JPG", "jpeg", "JPEG"]):
+ out = []
+ for r, d, f in os.walk(rootdir):
+ for file in f:
+ if (file.split('.')[1] in exts) and (must_contain in os.path.join(r, file)):
+ out.append(os.path.join(r, file))
+ return out
+
+
+def get_list(path, must_contain=''):
+ if ".pickle" in path:
+ with open(path, 'rb') as f:
+ image_list = pickle.load(f)
+ image_list = [item for item in image_list if must_contain in item]
+ else:
+ image_list = recursively_read(path, must_contain)
+ return image_list
+
+
+# Data augmentation techniques
+def data_augment(img, aug_config):
+ img = np.array(img)
+ if img.ndim == 2:
+ img = np.expand_dims(img, axis=2)
+ img = np.repeat(img, 3, axis=2)
+
+ if random.random() < aug_config["blur_prob"]:
+ sig = sample_continuous(aug_config["blur_sig"])
+ gaussian_blur(img, sig)
+
+ if random.random() < aug_config["jpg_prob"]:
+ method = sample_discrete(aug_config["jpg_method"])
+ qual = sample_discrete(aug_config["jpg_qual"])
+ img = jpeg_from_key(img, qual, method)
+
+ return Image.fromarray(img)
+
+
+# Data augmentation techniques
+def tensor_data_augment(images, aug_config):
+ device = images.device
+ images = images.detach().cpu().permute(0, 2, 3, 1).numpy()
+ images = np.uint8(images * 255.)
+ outputs = []
+ for img in images:
+ if random.random() < aug_config["blur_prob"]:
+ sig = sample_continuous(aug_config["blur_sig"])
+ gaussian_blur(img, sig)
+
+ if random.random() < aug_config["jpg_prob"]:
+ method = sample_discrete(aug_config["jpg_method"])
+ qual = sample_discrete(aug_config["jpg_qual"])
+ img = jpeg_from_key(img, qual, method)
+ outputs.append(img)
+ outputs = np.stack(outputs)
+ outputs = torch.from_numpy(outputs).to(device).permute(0, 3, 1, 2).float() / 255.
+ return outputs
+
+
+# Sample continuous or discrete values
+def sample_continuous(s):
+ if len(s) == 1:
+ return s[0]
+ if len(s) == 2:
+ rg = s[1] - s[0]
+ return random.random() * rg + s[0]
+ raise ValueError("Length of iterable s should be 1 or 2.")
+
+
+def sample_discrete(s):
+ if len(s) == 1:
+ return s[0]
+ return random.choice(s)
+
+
+# Gaussian blur
+def gaussian_blur(img, sigma):
+ gaussian_filter(img[:,:,0], output=img[:,:,0], sigma=sigma)
+ gaussian_filter(img[:,:,1], output=img[:,:,1], sigma=sigma)
+ gaussian_filter(img[:,:,2], output=img[:,:,2], sigma=sigma)
+
+
+# JPEG compression
+def cv2_jpg(img, compress_val):
+ img_cv2 = img[:,:,::-1]
+ encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), compress_val]
+ result, encimg = cv2.imencode('.jpg', img_cv2, encode_param)
+ decimg = cv2.imdecode(encimg, 1)
+ return decimg[:,:,::-1]
+
+
+def pil_jpg(img, compress_val):
+ out = BytesIO()
+ img = Image.fromarray(img)
+ img.save(out, format='jpeg', quality=compress_val)
+ img = Image.open(out)
+ # load from memory before ByteIO closes
+ img = np.array(img)
+ out.close()
+ return img
+
+
+def png_to_jpeg(img, quality=95):
+ # Convert the PNG image to JPEG
+ # Input: PIL image
+ # Output: PIL image
+ out = BytesIO()
+ img.save(out, format='jpeg', quality=quality)
+ img = np.array(Image.open(out))
+ # Load from memory before ByteIO closes
+ out.close()
+ img = Image.fromarray(img)
+ return img
+
+
+def jpeg_from_key(img, compress_val, key):
+ jpeg_dict = {'cv2': cv2_jpg, 'pil': pil_jpg}
+ method = jpeg_dict[key]
+ return method(img, compress_val)
+
+
+# Custom resize function
+def custom_resize(img, rz_interp, loadSize):
+ rz_dict = {'bilinear': Image.BILINEAR,
+ 'bicubic': Image.BICUBIC,
+ 'lanczos': Image.LANCZOS,
+ 'nearest': Image.NEAREST}
+ interp = sample_discrete(rz_interp)
+ return TF.resize(img, loadSize, interpolation=rz_dict[interp])
+
+
+def weights2cpu(weights):
+ for key in weights:
+ weights[key] = weights[key].cpu()
+ return weights
+
+
+# Define the label smoothing loss
+class LabelSmoothingBCEWithLogits(torch.nn.Module):
+ def __init__(self, smoothing=0.1):
+ super(LabelSmoothingBCEWithLogits, self).__init__()
+ self.smoothing = smoothing
+
+ def forward(self, pred, target):
+ target = target.float() * (1.0 - self.smoothing) + 0.5 * self.smoothing
+ loss = torch.nn.functional.binary_cross_entropy_with_logits(pred, target, reduction='mean')
+ return loss
+
+
+def evaluate(y_pred, y_true):
+ ap = average_precision_score(y_true, y_pred)
+ accuracy = ((np.array(y_pred) > 0.5) == y_true).mean()
+ return ap, accuracy
diff --git a/clean/image/effort/DeepfakeBench/analysis/logits_decision_boundary.py b/clean/image/effort/DeepfakeBench/analysis/logits_decision_boundary.py
new file mode 100644
index 0000000000000000000000000000000000000000..4c7899d240a99cf9b802696aa0a92082e1f87960
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/analysis/logits_decision_boundary.py
@@ -0,0 +1,404 @@
+"""
+eval pretained model.
+"""
+import os
+import numpy as np
+from os.path import join
+import cv2
+import random
+import datetime
+import time
+import yaml
+import pickle
+from tqdm import tqdm
+from copy import deepcopy
+from PIL import Image as pil_image
+from metrics.utils import get_test_metrics
+import torch
+import torch.nn as nn
+import torch.nn.parallel
+import torch.backends.cudnn as cudnn
+import torch.nn.functional as F
+import matplotlib.pyplot as plt
+import torch.utils.data
+import torch.optim as optim
+
+from dataset.abstract_dataset import DeepfakeAbstractBaseDataset
+from dataset.ff_blend import FFBlendDataset
+from dataset.fwa_blend import FWABlendDataset
+from dataset.pair_dataset import pairDataset
+
+from trainer.trainer import Trainer
+from detectors import DETECTOR
+from metrics.base_metrics_class import Recorder
+from collections import defaultdict
+
+import argparse
+from logger import create_logger
+
+parser = argparse.ArgumentParser(description='Process some paths.')
+parser.add_argument('--detector_path', type=str,
+ default='/home/zhiyuanyan/DeepfakeBench/training/config/detector/resnet34.yaml',
+ help='path to detector YAML file')
+parser.add_argument("--test_dataset", nargs="+")
+parser.add_argument("--model_name", nargs="+")
+parser.add_argument('--weights_path', type=str,
+ default='/mntcephfs/lab_data/zhiyuanyan/benchmark_results/auc_draw/cnn_aug/resnet34_2023-05-20-16-57-22/test/FaceForensics++/ckpt_epoch_9_best.pth')
+#parser.add_argument("--lmdb", action='store_true', default=False)
+args = parser.parse_args()
+
+device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
+
+on_2060 = "2060" in torch.cuda.get_device_name()
+def init_seed(config):
+ if config['manualSeed'] is None:
+ config['manualSeed'] = random.randint(1, 10000)
+ random.seed(config['manualSeed'])
+ torch.manual_seed(config['manualSeed'])
+ if config['cuda']:
+ torch.cuda.manual_seed_all(config['manualSeed'])
+
+
+def prepare_testing_data(config):
+ def get_test_data_loader(config, test_name):
+ # update the config dictionary with the specific testing dataset
+ config = config.copy() # create a copy of config to avoid altering the original one
+ config['test_dataset'] = test_name # specify the current test dataset
+ test_set = DeepfakeAbstractBaseDataset(
+ config=config,
+ mode='test',
+ )
+ test_data_loader = \
+ torch.utils.data.DataLoader(
+ dataset=test_set,
+ batch_size=config['test_batchSize'],
+ shuffle=False,
+ num_workers=int(config['workers']),
+ collate_fn=test_set.collate_fn,
+ drop_last=False
+ )
+ return test_data_loader
+
+ assert len(config['test_dataset'])==1
+ test_data_loader = get_test_data_loader(config, config['test_dataset'][0])
+ return test_data_loader
+
+
+def choose_metric(config):
+ metric_scoring = config['metric_scoring']
+ if metric_scoring not in ['eer', 'auc', 'acc', 'ap']:
+ raise NotImplementedError('metric {} is not implemented'.format(metric_scoring))
+ return metric_scoring
+
+
+def plot_logit_distribution(real_logits, fake_logits, save_path):
+ plt.figure(figsize=(8, 8))
+
+ # 绘制散点图
+ plt.scatter(real_logits[:, 0], real_logits[:, 1], color='blue', label='Real', alpha=0.2)
+ plt.scatter(fake_logits[:, 0], fake_logits[:, 1], color='red', label='Fake', alpha=0.2)
+
+ # 添加过原点的决策边界 x = y
+ min_val = min(real_logits[:, 0].min(), real_logits[:, 1].min(), fake_logits[:, 0].min(), fake_logits[:, 1].min())
+ max_val = max(real_logits[:, 0].max(), real_logits[:, 1].max(), fake_logits[:, 0].max(), fake_logits[:, 1].max())
+ x_vals = np.linspace(min_val, max_val, 100)
+ plt.plot(x_vals, x_vals, color='black', linestyle='--', label='Decision Boundary (x = y)')
+
+ # 设置标题和标签
+ plt.title('Logit Outputs for Real and Fake Classes')
+ plt.xlabel('Logit for Real Class')
+ plt.ylabel('Logit for Fake Class')
+ plt.legend()
+ plt.grid(True)
+
+ # 保存图像
+ plt.tight_layout()
+ os.makedirs(save_path, exist_ok=True)
+ plt.savefig(os.path.join(save_path, args.test_dataset[0] + '.png'))
+ plt.show()
+
+
+def calculate_logits_and_confidence(model, data_loader):
+ model.eval()
+
+ real_logits = []
+ fake_logits = []
+ real_confidences = []
+ fake_confidences = []
+
+ for i, data_dict in tqdm(enumerate(data_loader), total=len(data_loader)):
+ # get data
+ data, label, mask, landmark = \
+ data_dict['image'], data_dict['label'], data_dict['mask'], data_dict['landmark']
+ label = torch.where(data_dict['label'] != 0, 1, 0)
+ # move data to GPU
+ data_dict['image'], data_dict['label'] = data.to(device), label.to(device)
+ if mask is not None:
+ data_dict['mask'] = mask.to(device)
+ if landmark is not None:
+ data_dict['landmark'] = landmark.to(device)
+
+ # model forward without considering gradient computation
+ predictions = inference(model, data_dict)
+ output = predictions['cls']
+ logits = output.detach().cpu()
+ confidences = F.softmax(logits, dim=-1)
+
+ for i in range(logits.size(0)):
+ if label[i] == 0:
+ real_logits.append(logits[i])
+ real_confidences.append(confidences[i])
+ else:
+ fake_logits.append(logits[i])
+ fake_confidences.append(confidences[i])
+
+
+ real_logits = torch.stack(real_logits, dim=0)
+ fake_logits = torch.stack(fake_logits, dim=0)
+ real_confidences = torch.stack(real_confidences, dim=0)
+ fake_confidences = torch.stack(fake_confidences, dim=0)
+
+ return real_logits, fake_logits, real_confidences, fake_confidences
+
+
+
+def test_one_dataset(model, data_loader):
+ prediction_lists = []
+ feature_lists = []
+ label_lists = []
+ for i, data_dict in tqdm(enumerate(data_loader), total=len(data_loader)):
+ # get data
+ data, label, mask, landmark = \
+ data_dict['image'], data_dict['label'], data_dict['mask'], data_dict['landmark']
+ label = torch.where(data_dict['label'] != 0, 1, 0)
+ # move data to GPU
+ data_dict['image'], data_dict['label'] = data.to(device), label.to(device)
+ if mask is not None:
+ data_dict['mask'] = mask.to(device)
+ if landmark is not None:
+ data_dict['landmark'] = landmark.to(device)
+
+ # model forward without considering gradient computation
+ predictions = inference(model, data_dict)
+ label_lists += list(data_dict['label'].cpu().detach().numpy())
+ prediction_lists += list(predictions['prob'].cpu().detach().numpy())
+ feature_lists += list(predictions['feat'].cpu().detach().numpy())
+
+ return np.array(prediction_lists), np.array(label_lists),np.array(feature_lists)
+
+def test_epoch(model, test_data_loaders):
+ # set model to eval mode
+ model.eval()
+
+ # define test recorder
+ metrics_all_datasets = {}
+
+ # testing for all test data
+ keys = test_data_loaders.keys()
+ for key in keys:
+ data_dict = test_data_loaders[key].dataset.data_dict
+ # compute loss for each dataset
+ predictions_nps, label_nps,feat_nps = test_one_dataset(model, test_data_loaders[key])
+
+ # compute metric for each dataset
+ metric_one_dataset = get_test_metrics(y_pred=predictions_nps, y_true=label_nps,
+ img_names=data_dict['image'])
+ metrics_all_datasets[key] = metric_one_dataset
+
+ # info for each dataset
+ tqdm.write(f"dataset: {key}")
+ for k, v in metric_one_dataset.items():
+ tqdm.write(f"{k}: {v}")
+
+ return metrics_all_datasets
+
+@torch.no_grad()
+def inference(model, data_dict):
+ predictions = model(data_dict, inference=True)
+ return predictions
+
+
+def main():
+ # parse options and load config
+ with open(args.detector_path, 'r') as f:
+ config = yaml.safe_load(f)
+ with open('./training/config/test_config.yaml', 'r') as f:
+ config2 = yaml.safe_load(f)
+ config.update(config2)
+ if on_2060:
+ config['lmdb_dir'] = r'I:\transform_2_lmdb'
+ config['train_batchSize'] = 10
+ config['workers'] = 0
+ else:
+ config['workers'] = 8
+ config['lmdb_dir'] = r'/mnt/chongqinggeminiceph1fs/geminicephfs/mm-base-vision/jikangcheng/data/LMDBs'
+ weights_path = None
+ # If arguments are provided, they will overwrite the yaml settings
+ if args.test_dataset:
+ config['test_dataset'] = args.test_dataset
+ if args.weights_path:
+ config['weights_path'] = args.weights_path
+ weights_path = args.weights_path
+
+ # init seed
+ init_seed(config)
+
+ # set cudnn benchmark if needed
+ if config['cudnn']:
+ cudnn.benchmark = True
+
+ # prepare the testing data loader
+ test_data_loader = prepare_testing_data(config)
+
+ # prepare the model (detector)
+ model_class = DETECTOR[config['model_name']]
+ model = model_class(config).to(device).eval()
+ if weights_path:
+ try:
+ epoch = int(weights_path.split('/')[-1].split('.')[0].split('_')[2])
+ except:
+ epoch = 0
+ ckpt = torch.load(weights_path, map_location=device)
+ new_weights = {}
+ for key, value in ckpt.items():
+ new_key = key.replace('module.', '')
+ new_weights[new_key] = value
+
+ model.load_state_dict(new_weights, strict=True)
+ print('===> Load checkpoint done!')
+ else:
+ print('Fail to load the pre-trained weights')
+
+ # # start testing
+ # best_metric = test_epoch(model, test_data_loaders)
+ # print('===> Test Done!')
+
+ # Box plot
+ real_logits, fake_logits, real_confidences, fake_confidences = calculate_logits_and_confidence(model, test_data_loader)
+
+ # Plot the logit distribution in 2D space
+ save_path = f"scatter_plot/visualization/{args.model_name[0]}"
+ if not os.path.exists(save_path):
+ os.makedirs(save_path)
+
+ plot_logit_distribution(real_logits, fake_logits, save_path)
+
+
+ save_path = f"box_plot/visualization/{args.model_name[0]}"
+ if not os.path.exists(save_path):
+ os.makedirs(save_path)
+
+ import pandas as pd
+ import matplotlib.pyplot as plt
+ import seaborn as sns
+
+ # Convert tensors to numpy arrays
+ # logits_real = real_logits.cpu().numpy().reshape(-1)
+ # logits_fake = fake_logits.cpu().numpy().reshape(-1)
+
+ # real_confidences = real_confidences.cpu().numpy().reshape(-1)
+ # fake_confidences = fake_confidences.cpu().numpy().reshape(-1)
+
+ # logits_real = torch.cat([real_logits[0], fake_logits[0]]).cpu().numpy().reshape(-1)
+ # logits_fake = torch.cat([real_logits[1], fake_logits[1]]).cpu().numpy().reshape(-1)
+
+
+
+ # Set Seaborn style
+ sns.set_style("whitegrid")
+ plt.rcParams['font.size'] = 14
+ plt.rcParams['axes.labelsize'] = 14
+ plt.rcParams['axes.titlesize'] = 16
+ plt.rcParams['xtick.labelsize'] = 12
+ plt.rcParams['ytick.labelsize'] = 12
+ plt.rcParams['legend.fontsize'] = 14
+
+ # Create subplots
+ fig, axs = plt.subplots(2, 1, figsize=(8, 8))
+
+
+
+ if real_logits.shape[-1] == 2:
+ logits_real = (real_logits[:, 0].cpu().numpy(), fake_logits[:, 0].cpu().numpy())
+ logits_fake = (real_logits[:, 1].cpu().numpy(), fake_logits[:, 1].cpu().numpy())
+
+ real_confidences_list = (real_confidences[:, 0].cpu().numpy(), fake_confidences[:, 0].cpu().numpy())
+ fake_confidences_list = (real_confidences[:, 1].cpu().numpy(), fake_confidences[:, 1].cpu().numpy())
+
+ # Plot histograms and KDE for logits
+ sns.histplot(logits_real[0], bins=30, kde=True, stat='probability', label='real', color=sns.color_palette("Blues")[-1], ax=axs[0])
+ sns.histplot(logits_real[1], bins=30, kde=True, stat='probability', label='fake', color=sns.color_palette("Reds")[-1], ax=axs[0])
+ axs[0].set_ylim(0, 0.15)
+ axs[0].legend()
+
+ # sns.histplot(logits_fake[0], bins=30, kde=True, stat='probability', color=sns.color_palette("Blues")[-1], ax=axs[0, 1])
+ # sns.histplot(logits_fake[1], bins=30, kde=True, stat='probability', color=sns.color_palette("Reds")[-1], ax=axs[0, 1])
+ # axs[0, 1].set_ylim(0, 0.15)
+ # axs[0, 1].legend()
+
+ # Plot histograms and KDE for confidences
+ sns.histplot(real_confidences_list[0], bins=30, kde=True, stat='probability', label='real', color=sns.color_palette("Blues")[-1], ax=axs[1])
+ sns.histplot(real_confidences_list[1], bins=30, kde=True, stat='probability', label='fake', color=sns.color_palette("Reds")[-1], ax=axs[1])
+ axs[1].legend()
+ # sns.histplot(fake_confidences_list[0], bins=30, kde=True, stat='probability', color=sns.color_palette("Blues")[-1], ax=axs[1])
+ # sns.histplot(fake_confidences_list[1], bins=30, kde=True, stat='probability', color=sns.color_palette("Reds")[-1], ax=axs[1])
+
+ # Set titles
+ axs[0].set_title('Logit Distribution of Real and Fake Classes')
+ # axs[0, 1].set_title('Fake Logits')
+ axs[1].set_title('Confidence Distribution of Real and Fake Classes')
+ # axs[1, 1].set_title('Fake Confidences')
+
+ # Show the plot
+ plt.tight_layout()
+ save_ = os.path.join(save_path, args.test_dataset[0] + '.png')
+ plt.savefig(save_)
+
+ # # Create a DataFrame with logits and confidences as columns
+ # df_real = pd.DataFrame({'logits_real': logits_real, 'real_confidences': real_confidences})
+ # df_fake = pd.DataFrame({'logits_fake': logits_fake, 'fake_confidences': fake_confidences})
+
+ # # Write DataFrame to csv file
+ # df_real.to_csv('output_logits_real.csv', index=False)
+ # df_fake.to_csv('output_logits_fake.csv', index=False)
+
+
+
+
+ elif real_logits.shape[-1] == 1:
+
+ logits_real = real_logits.cpu().numpy().flatten()
+ logits_fake = fake_logits.cpu().numpy().flatten()
+ real_confidences_list = real_confidences.cpu().numpy().flatten()
+ fake_confidences_list = fake_confidences.cpu().numpy().flatten()
+
+ # Plot histograms and KDE for logits
+ sns.histplot(logits_fake, bins=30, kde=True, stat='probability', label='real', color=sns.color_palette("Blues")[-1], ax=axs[0])
+ sns.histplot(logits_real, bins=30, kde=True, stat='probability', label='fake', color=sns.color_palette("Reds")[-1], ax=axs[0])
+ axs[0].set_ylim(0, 0.7)
+ axs[0].legend()
+
+ # Plot histograms and KDE for confidences
+ sns.histplot(real_confidences_list, bins=30, kde=True, stat='probability', label='real', color=sns.color_palette("Blues")[-1], ax=axs[1])
+ sns.histplot(fake_confidences_list, bins=30, kde=True, stat='probability', label='fake', color=sns.color_palette("Reds")[-1], ax=axs[1])
+ axs[1].legend()
+
+ # Set titles
+ axs[0].set_title('Logit Distribution of Real and Fake Classes')
+ axs[1].set_title('Confidence Distribution of Real and Fake Classes')
+
+ # Show the plot
+ plt.tight_layout()
+ save_ = os.path.join(save_path, args.test_dataset[0] + '.png')
+ plt.savefig(save_)
+
+
+
+
+ else:
+ raise ValueError('The number of classes is not 1 or 2')
+
+
+
+if __name__ == '__main__':
+ main()
diff --git a/clean/image/effort/DeepfakeBench/analysis/pca_rank.py b/clean/image/effort/DeepfakeBench/analysis/pca_rank.py
new file mode 100644
index 0000000000000000000000000000000000000000..cd7d14193f543c68f6bea2535f7aedc375579dad
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/analysis/pca_rank.py
@@ -0,0 +1,122 @@
+import os
+import numpy as np
+import pandas as pd
+import matplotlib.pyplot as plt
+import seaborn as sns
+from sklearn.decomposition import PCA
+import pickle
+import torch
+import torch.nn as nn
+
+color_map = ['tab:blue', 'tab:orange', 'tab:green', 'tab:red', 'tab:purple']
+label_dict = {
+ 0: 'FF-Real', 1: 'FF-Fake', 2: 'CDF-Real', 3: 'CDF-Fake', 4: 'FF-Fsh'
+}
+
+
+
+
+import argparse
+parser = argparse.ArgumentParser(description='Process some paths.')
+parser.add_argument("--test_dataset", nargs="+", default=['FF-DF'])
+parser.add_argument("--model_name", nargs="+")
+args = parser.parse_args()
+
+
+
+def plot_explained_variance(explained_variance_ratio, cumulative_explained_variance_ratio, save_path):
+ plt.figure(figsize=(10, 8))
+ plt.plot(explained_variance_ratio[:200], marker='o', alpha=0.4, markersize=12)
+ plt.title('Explained Variance Ratio of Principal Components', fontsize=24, weight='bold', y=1.05)
+ plt.xlabel('Principal Component Index', fontsize=24, weight='bold')
+ plt.ylabel('Explained Variance Ratio', fontsize=24, weight='bold')
+ plt.tick_params(axis='both', labelsize=20) # 或者设置成24,如果希望和轴标签一样大
+ plt.grid(True)
+ plt.savefig(os.path.join(save_path, 'explained_variance_ratio.png'), dpi=300)
+
+ plt.figure(figsize=(10, 8))
+ plt.plot(cumulative_explained_variance_ratio[:200], marker='o', alpha=0.4, markersize=12)
+ plt.title('Cumulative Explained Variance Ratio', fontsize=24, weight='bold', y=1.05)
+ plt.xlabel('Number of Principal Components', fontsize=24, weight='bold')
+ plt.ylabel('Cumulative Explained Variance Ratio', fontsize=24, weight='bold')
+ plt.grid(True)
+ plt.savefig(os.path.join(save_path, 'cumulative_explained_variance_ratio.png'), dpi=300)
+
+def main():
+ base_dir = './zhiyuanyan/DeepfakeBenchv2/features'
+ model_name = args.model_name[0]
+ base_dir = os.path.join(base_dir, model_name)
+ test_dataset = args.test_dataset
+ all_testing_data = []
+ all_testing_label = []
+ pool = nn.AdaptiveAvgPool2d((1, 1))
+
+ for name in os.listdir(base_dir):
+ if name in test_dataset:
+ with open(os.path.join(base_dir, name, 'tsne.pkl'), 'rb') as f:
+ data = pickle.load(f)
+ feat = data['feat']
+ print(f'shape of {name}:', feat.shape)
+ if feat.ndim == 4: # pool
+ print(f'shape of {name} before pooling:', feat.shape)
+ feat = torch.from_numpy(feat)
+ feat = pool(feat).squeeze()
+ feat = feat.numpy()
+ print(f'shape of {name} after pooling:', feat.shape)
+ label = data['label']
+ if name == 'Celeb-DF-v2':
+ label = label + 2
+ elif name == 'FaceShifter':
+ label_mask = (label == 1)
+ feat = feat[label_mask]
+ label = label[label_mask] * 4
+ all_testing_data.append(feat)
+ all_testing_label.append(label)
+ all_testing_data = np.concatenate(all_testing_data, axis=0)
+ all_testing_label = np.concatenate(all_testing_label, axis=0)
+ print('Total number of samples:', len(all_testing_label))
+ print('Label distribution:', np.unique(all_testing_label, return_counts=True))
+
+ # Perform PCA analysis
+ feat = all_testing_data
+ pca = PCA(n_components=min(feat.shape[0], feat.shape[1]))
+ pca.fit(feat)
+ explained_variance_ratio = pca.explained_variance_ratio_
+ cumulative_explained_variance_ratio = np.cumsum(explained_variance_ratio)
+
+ # Plot explained variance ratio and cumulative explained variance ratio
+ save_path = './zhiyuanyan/DeepfakeBenchv2/pca_results/' + model_name
+ os.makedirs(save_path, exist_ok=True)
+ plot_explained_variance(explained_variance_ratio, cumulative_explained_variance_ratio, save_path)
+
+ # Output the number of principal components needed to explain 90% variance
+ num_components_90 = np.argmax(cumulative_explained_variance_ratio >= 0.9) + 1
+ print(f'Number of principal components explaining 90% variance: {num_components_90}')
+ print(f'Feature dimension: {feat.shape[1]}')
+
+ # 计算特征值衰减系数
+ eigenvalues = pca.explained_variance_
+ decay_rate = np.diff(np.log(eigenvalues)) / np.diff(np.arange(len(eigenvalues)))
+ print("平均衰减率:", np.mean(decay_rate[:100]))
+
+ # Optional: Plot scatter plot of the first two principal components
+ feat_transformed = pca.transform(feat)[:, :2]
+ numerical_labels = all_testing_label
+ labels = [label_dict[label] for label in numerical_labels]
+
+ plt.figure(figsize=(10, 8))
+ sns.scatterplot(
+ x=feat_transformed[:, 0],
+ y=feat_transformed[:, 1],
+ hue=labels,
+ palette=color_map[:len(np.unique(numerical_labels))],
+ alpha=0.4
+ )
+ plt.title('Scatter Plot of the First Two Principal Components', fontsize=20)
+ plt.xlabel('Principal Component 1', fontsize=20)
+ plt.ylabel('Principal Component 2', fontsize=20)
+ plt.legend(title='Classes', loc='best')
+ plt.savefig(os.path.join(save_path, 'pca_scatter.png'), dpi=300)
+
+if __name__ == '__main__':
+ main()
\ No newline at end of file
diff --git a/clean/image/effort/DeepfakeBench/preprocessing/dataset_json/readme.txt b/clean/image/effort/DeepfakeBench/preprocessing/dataset_json/readme.txt
new file mode 100644
index 0000000000000000000000000000000000000000..44b4905491d315a315daf57d954eaac3be8ae737
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/preprocessing/dataset_json/readme.txt
@@ -0,0 +1,9 @@
+-----
+
+Links of the provided JSON Files:
+
+DF40:https://drive.google.com/drive/folders/1rh-82Rn0pqQ7xzLDKBv9gdjy-sbxYC8-?usp=drive_link
+
+DeepfakeBench: https://drive.google.com/drive/folders/1T4ajtH-7PTAmDYWjn27XNOONXs7KjQWk?usp=drive_link
+
+-----
\ No newline at end of file
diff --git a/clean/image/effort/DeepfakeBench/training/__init__.py b/clean/image/effort/DeepfakeBench/training/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/clean/image/effort/DeepfakeBench/training/config/__init__.py b/clean/image/effort/DeepfakeBench/training/config/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..eec7c2d57b94a1fff5f3af445959378441f9c2cf
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/config/__init__.py
@@ -0,0 +1,12 @@
+# ------------------------------------------------------------------------------
+# Copyright (c) Microsoft
+# Licensed under the MIT License.
+# Written by Ke Sun (sunk@mail.ustc.edu.cn)
+# ------------------------------------------------------------------------------
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+from .default import _C as config
+from .default import update_config
+from .models import MODEL_EXTRAS
diff --git a/clean/image/effort/DeepfakeBench/training/config/detector/effort.yaml b/clean/image/effort/DeepfakeBench/training/config/detector/effort.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..780c1411382859b4c175ac7ce1b4deb84d4c1502
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/config/detector/effort.yaml
@@ -0,0 +1,88 @@
+# log dir
+log_dir: ./zhiyuanyan/logs/benchv2/icml25/release
+
+# model setting
+pretrained: 'no need to provide this for the effort model'
+model_name: effort # model name
+backbone_name: vit # backbone name
+
+#backbone setting
+backbone_config:
+ mode: original
+ num_classes: 2
+ inc: 3
+ dropout: false
+
+# dataset
+all_dataset: [FaceForensics++, FF-F2F, FF-DF, FF-FS, FF-NT, FaceShifter, DeepFakeDetection, Celeb-DF-v1, Celeb-DF-v2, DFDCP, DFDC, DeeperForensics-1.0, UADFV]
+train_dataset: [FaceForensics++]
+test_dataset: [Celeb-DF-v2, FaceShifter, DeeperForensics-1.0]
+
+compression: c23 # compression-level for videos
+train_batchSize: 32 # training batch size
+test_batchSize: 32 # test batch size
+workers: 8 # number of data loading workers
+frame_num: {'train': 8, 'test': 8} # number of frames to use per video in training and testing
+resolution: 224 # resolution of output image to network
+with_mask: false # whether to include mask information in the input
+with_landmark: false # whether to include facial landmark information in the input
+
+
+# data augmentation
+use_data_augmentation: true # Add this flag to enable/disable data augmentation
+data_aug:
+ flip_prob: 0.5
+ rotate_prob: 0.5
+ rotate_limit: [-10, 10]
+ blur_prob: 0.5
+ blur_limit: [3, 7]
+ brightness_prob: 0.5
+ brightness_limit: [-0.1, 0.1]
+ contrast_limit: [-0.1, 0.1]
+ quality_lower: 40
+ quality_upper: 100
+
+# mean and std for normalization
+mean: [0.48145466, 0.4578275, 0.40821073]
+std: [0.26862954, 0.26130258, 0.27577711]
+
+# optimizer config
+optimizer:
+ # choose between 'adam' and 'sgd'
+ type: adam
+ adam:
+ lr: 0.0002 # learning rate
+ beta1: 0.9 # beta1 for Adam optimizer
+ beta2: 0.999 # beta2 for Adam optimizer
+ eps: 0.00000001 # epsilon for Adam optimizer
+ weight_decay: 0.0005 # weight decay for regularization
+ amsgrad: false
+ sgd:
+ lr: 0.0002 # learning rate
+ momentum: 0.9 # momentum for SGD optimizer
+ weight_decay: 0.0005 # weight decay for regularization
+
+# training config
+lr_scheduler: null # learning rate scheduler
+nEpochs: 10 # number of epochs to train for
+start_epoch: 0 # manual epoch number (useful for restarts)
+save_epoch: 1 # interval epochs for saving models
+rec_iter: 100 # interval iterations for recording
+logdir: ./logs # folder to output images and logs
+manualSeed: 1024 # manual seed for random number generation
+save_ckpt: true # whether to save checkpoint
+save_feat: true # whether to save features
+
+# loss function
+loss_func: cross_entropy # loss function to use
+losstype: null
+
+# metric
+metric_scoring: auc # metric for evaluation (auc, acc, eer, ap)
+
+# cuda
+ngpu: 1 # number of GPUs to use
+cuda: true # whether to use CUDA acceleration
+cudnn: true # whether to use CuDNN for convolution operations
+
+save_avg: true
diff --git a/clean/image/effort/DeepfakeBench/training/config/test_config.yaml b/clean/image/effort/DeepfakeBench/training/config/test_config.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..281dc31d2223d40df80e3bc3e2dd8b448ccf23d4
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/config/test_config.yaml
@@ -0,0 +1,232 @@
+mode: test
+lmdb: False
+dataset_root_rgb: './datasets'
+lmdb_dir: 'I:\transform_2_lmdb'
+dataset_json_folder: '/Youtu_Pangu_Security_Public/youtu-pangu-public/zhiyuanyan/DeepfakeBenchv2/preprocessing/dataset_json'
+
+# label settings
+label_dict:
+ # DFD
+ DFD_fake: 1
+ DFD_real: 0
+ # FF++ + FaceShifter(FF-real+FF-FH)
+ FF-SH: 1
+ FF-F2F: 1
+ FF-DF: 1
+ FF-FS: 1
+ FF-NT: 1
+ FF-FH: 1
+ FF-real: 0
+ # CelebDF
+ CelebDFv1_real: 0
+ CelebDFv1_fake: 1
+ CelebDFv2_real: 0
+ CelebDFv2_fake: 1
+ # DFDCP
+ DFDCP_Real: 0
+ DFDCP_FakeA: 1
+ DFDCP_FakeB: 1
+ # DFDC
+ DFDC_Fake: 1
+ DFDC_Real: 0
+ # DeeperForensics-1.0
+ DF_fake: 1
+ DF_real: 0
+ # UADFV
+ UADFV_Fake: 1
+ UADFV_Real: 0
+ # roop
+ roop_Fake: 1
+ roop_Real: 0
+
+ # DF40 all
+ FSAll_Fake: 1
+ FSAll_Real: 0
+ FRAll_Fake: 1
+ FRAll_Real: 0
+ EFSAll_Fake: 1
+ EFSAll_Real: 0
+
+
+ DFR_Real: 0
+ DFR_Fake: 1
+ WDF_Real: 0
+ WDF_Fake: 1
+ FFIW_Real: 0
+ FFIW_Fake: 1
+
+ SRI_fake: 1
+ SRI_real: 0
+
+ # DF40
+ e4s_Fake: 1
+ e4s_Real: 0
+
+ MidJourney_Fake: 1
+ MidJourney_Real: 0
+
+ deepfacelab_Fake: 1
+ deepfacelab_Real: 0
+
+ danet_Fake: 1
+ danet_Real: 0
+
+ fomm_Fake: 1
+ fomm_Real: 0
+
+ e4e_Fake: 1
+ e4e_Real: 0
+
+ hyperreenact_Fake: 1
+ hyperreenact_Real: 0
+
+ MRAA_Fake: 1
+ MRAA_Real: 0
+
+ one_shot_free_Fake: 1
+ one_shot_free_Real: 0
+
+ pirender_Fake: 1
+ pirender_Real: 0
+
+ tpsm_Fake: 1
+ tpsm_Real: 0
+
+ facedancer_Fake: 1
+ facedancer_Real: 0
+
+ facevid2vid_Fake: 1
+ facevid2vid_Real: 0
+
+ mcnet_Fake: 1
+ mcnet_Real: 0
+
+ fsgan_Fake: 1
+ fsgan_Real: 0
+
+ lia_Fake: 1
+ lia_Real: 0
+
+ mraa_Fake: 1
+ mraa_Real: 0
+
+ inswap_Fake: 1
+ inswap_Real: 0
+
+ simswap_Fake: 1
+ simswap_Real: 0
+
+ sadtalker_Fake: 1
+ sadtalker_Real: 0
+
+ wav2lip_Fake: 1
+ wav2lip_Real: 0
+
+ uniface_Fake: 1
+ uniface_Real: 0
+
+ blendface_Fake: 1
+ blendface_Real: 0
+
+ mobileswap_Fake: 1
+ mobileswap_Real: 0
+
+ faceswap_Fake: 1
+ faceswap_Real: 0
+
+ dalle2_face_Fake: 1
+ dalle2_face_Real: 0
+
+ MidJourney_Fake: 1
+ MidJourney_Real: 0
+
+ heygen_Fake: 1
+ heygen_Real: 0
+
+ whichisreal_Fake: 1
+ whichisreal_Real: 0
+
+ StyleGAN2_Fake: 1
+ StyleGAN2_Real: 0
+
+ StyleGAN3_Fake: 1
+ StyleGAN3_Real: 0
+
+ StyleGANXL_Fake: 1
+ StyleGANXL_Real: 0
+
+ ddim_Fake: 1
+ ddim_Real: 0
+
+ DiT_Fake: 1
+ DiT_Real: 0
+
+ pixart_Fake: 1
+ pixart_Real: 0
+
+ SiT_Fake: 1
+ SiT_Real: 0
+
+ sd1.5_Fake: 1
+ sd1.5_Real: 0
+
+ sd2.1_Fake: 1
+ sd2.1_Real: 0
+
+ VQGAN_Fake: 1
+ VQGAN_Real: 0
+
+ stargan_Fake: 1
+ stargan_Real: 0
+
+ starganv2_Fake: 1
+ starganv2_Real: 0
+
+ styleclip_Fake: 1
+ styleclip_Real: 0
+
+ CollabDiff_Fake: 1
+ CollabDiff_Real: 0
+
+ rddm_Fake: 1
+ rddm_Real: 0
+
+ # GenImage
+ adm_Fake: 1
+ adm_Real: 0
+
+ pixart_Fake: 1
+ pixart_Real: 0
+
+ biggan_Fake: 1
+ biggan_Real: 0
+
+ glide_Fake: 1
+ glide_Real: 0
+
+ midjourney_Fake: 1
+ midjourney_Real: 0
+
+ sdv4_Fake: 1
+ sdv4_Real: 0
+
+ sdv5_Fake: 1
+ sdv5_Real: 0
+
+ vqdm_Fake: 1
+ vqdm_Real: 0
+
+ wukong_Fake: 1
+ wukong_Real: 0
+
+ GPA_fake: 1
+ GPA_real: 0
+
+ Chameleon_Fake: 1
+ Chameleon_Real: 0
+
+ GPT4o_Fake: 1
+ GPT4o_Real: 0
+
+ VIP_Real: 0
+ VIP_Fake: 1
diff --git a/clean/image/effort/DeepfakeBench/training/config/train_config.yaml b/clean/image/effort/DeepfakeBench/training/config/train_config.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..ae17f48ec54cfadb8a71dbd2fa8f4e6a557880c8
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/config/train_config.yaml
@@ -0,0 +1,225 @@
+mode: train
+lmdb: False
+dry_run: false
+dataset_root_rgb: './datasets'
+lmdb_dir: 'I:\transform_2_lmdb'
+dataset_json_folder: '/Youtu_Pangu_Security_Public/youtu-pangu-public/zhiyuanyan/DeepfakeBenchv2/preprocessing/dataset_json'
+SWA: False
+
+# label settings
+label_dict:
+ # DFD
+ DFD_fake: 1
+ DFD_real: 0
+ # FF++ + FaceShifter(FF-real+FF-FH)
+ FF-SH: 1
+ FF-F2F: 1
+ FF-DF: 1
+ FF-FS: 1
+ FF-NT: 1
+ FF-FH: 1
+ FF-real: 0
+ # CelebDF
+ CelebDFv1_real: 0
+ CelebDFv1_fake: 1
+ CelebDFv2_real: 0
+ CelebDFv2_fake: 1
+ # DFDCP
+ DFDCP_Real: 0
+ DFDCP_FakeA: 1
+ DFDCP_FakeB: 1
+ # DFDC
+ DFDC_Fake: 1
+ DFDC_Real: 0
+ # DeeperForensics-1.0
+ DF_fake: 1
+ DF_real: 0
+ # UADFV
+ UADFV_Fake: 1
+ UADFV_Real: 0
+ # Roop
+ roop_Real: 0
+ roop_Fake: 1
+
+
+ # DF40
+ FSAll_Fake: 1
+ FSAll_Real: 0
+
+ FRAll_Fake: 1
+ FRAll_Real: 0
+
+ EFSAll_Fake: 1
+ EFSAll_Real: 0
+
+ DF40_train_Fake: 1
+ DF40_train_Real: 0
+
+ e4s_Fake: 1
+ e4s_Real: 0
+
+ danet_Fake: 1
+ danet_Real: 0
+
+ fomm_Fake: 1
+ fomm_Real: 0
+
+ Collaborative_Diffusion_Fake: 1
+ Collaborative_Diffusion_Real: 0
+
+ e4e_Fake: 1
+ e4e_Real: 0
+
+ hyperreenact_Fake: 1
+ hyperreenact_Real: 0
+
+ MRAA_Fake: 1
+ MRAA_Real: 0
+
+ one_shot_free_Fake: 1
+ one_shot_free_Real: 0
+
+ pirender_Fake: 1
+ pirender_Real: 0
+
+ tpsm_Fake: 1
+ tpsm_Real: 0
+
+ facedancer_Fake: 1
+ facedancer_Real: 0
+
+ facevid2vid_Fake: 1
+ facevid2vid_Real: 0
+
+ mcnet_Fake: 1
+ mcnet_Real: 0
+
+ mraa_Fake: 1
+ mraa_Real: 0
+
+ fsgan_Fake: 1
+ fsgan_Real: 0
+
+ lia_Fake: 1
+ lia_Real: 0
+
+ inswap_Fake: 1
+ inswap_Real: 0
+
+ simswap_Fake: 1
+ simswap_Real: 0
+
+ sadtalker_Fake: 1
+ sadtalker_Real: 0
+
+ wav2lip_Fake: 1
+ wav2lip_Real: 0
+
+ uniface_Fake: 1
+ uniface_Real: 0
+
+ blendface_Fake: 1
+ blendface_Real: 0
+
+ mobileswap_Fake: 1
+ mobileswap_Real: 0
+
+ faceswap_Fake: 1
+ faceswap_Real: 0
+
+ dalle2_face_Fake: 1
+ dalle2_face_Real: 0
+
+ MidJourney_Fake: 1
+ MidJourney_Real: 0
+
+ heygen_Fake: 1
+ heygen_Real: 0
+
+ whichisreal_Fake: 1
+ whichisreal_Real: 0
+
+ StyleGAN2_Fake: 1
+ StyleGAN2_Real: 0
+
+ StyleGAN3_Fake: 1
+ StyleGAN3_Real: 0
+
+ StyleGANXL_Fake: 1
+ StyleGANXL_Real: 0
+
+ ddim_Fake: 1
+ ddim_Real: 0
+
+ DiT_Fake: 1
+ DiT_Real: 0
+
+ pixart_Fake: 1
+ pixart_Real: 0
+
+ SiT_Fake: 1
+ SiT_Real: 0
+
+ sd1.5_Fake: 1
+ sd1.5_Real: 0
+
+ sd2.1_Fake: 1
+ sd2.1_Real: 0
+
+ VQGAN_Fake: 1
+ VQGAN_Real: 0
+
+ rddm_Fake: 1
+ rddm_Real: 0
+
+ pixart_Fake: 1
+ pixart_Real: 0
+
+ stargan_Fake: 1
+ stargan_Real: 0
+
+ starganv2_Fake: 1
+ starganv2_Real: 0
+
+ styleclip_Fake: 1
+ styleclip_Real: 0
+
+ deepfacelab_Fake: 1
+ deepfacelab_Real: 0
+
+ CollabDiff_Fake: 1
+ CollabDiff_Real: 0
+
+ e4e_Fake: 1
+ e4e_Real: 0
+
+ # GenImage
+ adm_Fake: 1
+ adm_Real: 0
+
+ biggan_Fake: 2
+ biggan_Real: 0
+
+ glide_Fake: 3
+ glide_Real: 0
+
+ midjourney_Fake: 4
+ midjourney_Real: 0
+
+ sdv4_Fake: 5
+ sdv4_Real: 0
+
+ sdv5_Fake: 6
+ sdv5_Real: 0
+
+ vqdm_Fake: 7
+ vqdm_Real: 0
+
+ wukong_Fake: 8
+ wukong_Real: 0
+
+ GPA_fake: 1
+ GPA_real: 0
+
+ Chameleon_Fake: 1
+ Chameleon_Real: 0
diff --git a/clean/image/effort/DeepfakeBench/training/demo.py b/clean/image/effort/DeepfakeBench/training/demo.py
new file mode 100644
index 0000000000000000000000000000000000000000..d4ad5efe45e3459883d5f2b07d36abf830bf593b
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/demo.py
@@ -0,0 +1,268 @@
+import numpy as np
+import cv2
+import random
+import yaml
+import pickle
+from tqdm import tqdm
+from PIL import Image as pil_image
+import dlib
+import torch
+import torch.nn as nn
+import torch.nn.parallel
+import torch.nn.functional as F
+import torch.utils.data
+from torchvision import transforms
+from trainer.trainer import Trainer
+from detectors import DETECTOR
+from collections import defaultdict
+from PIL import Image as pil_image
+from imutils import face_utils
+from skimage import transform as trans
+import torchvision.transforms as T
+import os
+from os.path import join
+from typing import Tuple, List
+from pathlib import Path
+
+"""
+Usage:
+ python infer.py \
+ --detector_config ./training/config/detector/effort.yaml \
+ --weights ../../DeepfakeBenchv2/training/weights/easy_clipl14_cdf.pth \
+ --image ./id9_id6_0009.jpg \
+ --landmark_model ../../DeepfakeBenchv2/preprocessing/dlib_tools/shape_predictor_81_face_landmarks.dat
+"""
+
+import argparse
+
+device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
+
+
+@torch.no_grad()
+def inference(model, data_dict):
+ data, label = data_dict['image'], data_dict['label']
+ # move data to GPU
+ data_dict['image'], data_dict['label'] = data.to(device), label.to(device)
+ predictions = model(data_dict, inference=True)
+ return predictions
+
+
+# preprocess the input image --> cropped face, resize = 256, adding a dimension of batch (output shape: 1x3x256x256)
+def get_keypts(image, face, predictor, face_detector):
+ # detect the facial landmarks for the selected face
+ shape = predictor(image, face)
+
+ # select the key points for the eyes, nose, and mouth
+ leye = np.array([shape.part(37).x, shape.part(37).y]).reshape(-1, 2)
+ reye = np.array([shape.part(44).x, shape.part(44).y]).reshape(-1, 2)
+ nose = np.array([shape.part(30).x, shape.part(30).y]).reshape(-1, 2)
+ lmouth = np.array([shape.part(49).x, shape.part(49).y]).reshape(-1, 2)
+ rmouth = np.array([shape.part(55).x, shape.part(55).y]).reshape(-1, 2)
+
+ pts = np.concatenate([leye, reye, nose, lmouth, rmouth], axis=0)
+
+ return pts
+
+def extract_aligned_face_dlib(face_detector, predictor, image, res=224, mask=None):
+ def img_align_crop(img, landmark=None, outsize=None, scale=1.3, mask=None):
+ """
+ align and crop the face according to the given bbox and landmarks
+ landmark: 5 key points
+ """
+
+ M = None
+ target_size = [112, 112]
+ dst = np.array([
+ [30.2946, 51.6963],
+ [65.5318, 51.5014],
+ [48.0252, 71.7366],
+ [33.5493, 92.3655],
+ [62.7299, 92.2041]], dtype=np.float32)
+
+ if target_size[1] == 112:
+ dst[:, 0] += 8.0
+
+ dst[:, 0] = dst[:, 0] * outsize[0] / target_size[0]
+ dst[:, 1] = dst[:, 1] * outsize[1] / target_size[1]
+
+ target_size = outsize
+
+ margin_rate = scale - 1
+ x_margin = target_size[0] * margin_rate / 2.
+ y_margin = target_size[1] * margin_rate / 2.
+
+ # move
+ dst[:, 0] += x_margin
+ dst[:, 1] += y_margin
+
+ # resize
+ dst[:, 0] *= target_size[0] / (target_size[0] + 2 * x_margin)
+ dst[:, 1] *= target_size[1] / (target_size[1] + 2 * y_margin)
+
+ src = landmark.astype(np.float32)
+
+ # use skimage tranformation
+ tform = trans.SimilarityTransform()
+ tform.estimate(src, dst)
+ M = tform.params[0:2, :]
+
+ # M: use opencv
+ # M = cv2.getAffineTransform(src[[0,1,2],:],dst[[0,1,2],:])
+
+ img = cv2.warpAffine(img, M, (target_size[1], target_size[0]))
+
+ if outsize is not None:
+ img = cv2.resize(img, (outsize[1], outsize[0]))
+
+ if mask is not None:
+ mask = cv2.warpAffine(mask, M, (target_size[1], target_size[0]))
+ mask = cv2.resize(mask, (outsize[1], outsize[0]))
+ return img, mask
+ else:
+ return img
+
+ # Image size
+ height, width = image.shape[:2]
+
+ # Convert to rgb
+ rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
+
+ # Detect with dlib
+ faces = face_detector(rgb, 1)
+ if len(faces):
+ # For now only take the biggest face
+ face = max(faces, key=lambda rect: rect.width() * rect.height())
+
+ # Get the landmarks/parts for the face in box d only with the five key points
+ landmarks = get_keypts(rgb, face, predictor, face_detector)
+
+ # Align and crop the face
+ cropped_face = img_align_crop(rgb, landmarks, outsize=(res, res), mask=mask)
+ cropped_face = cv2.cvtColor(cropped_face, cv2.COLOR_RGB2BGR)
+
+ # Extract the all landmarks from the aligned face
+ face_align = face_detector(cropped_face, 1)
+ landmark = predictor(cropped_face, face_align[0])
+ landmark = face_utils.shape_to_np(landmark)
+
+ return cropped_face, landmark,face
+
+ else:
+ return None, None
+
+
+def load_detector(detector_cfg: str, weights: str):
+ with open(detector_cfg, "r") as f:
+ cfg = yaml.safe_load(f)
+
+ model_cls = DETECTOR[cfg["model_name"]]
+ model = model_cls(cfg).to(device)
+
+ ckpt = torch.load(weights, map_location=device)
+ state = ckpt.get("state_dict", ckpt)
+ state = {k.replace("module.", ""): v for k, v in state.items()}
+ model.load_state_dict(state, strict=False) # FIXME ⚠
+ model.eval()
+ print("[✓] Detector loaded.")
+ return model
+
+
+def preprocess_face(img_bgr: np.ndarray):
+ """BGR → tensor"""
+ img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)
+ img_rgb = cv2.resize(img_rgb, (224, 224), interpolation=cv2.INTER_LINEAR)
+ transform = T.Compose([
+ T.ToTensor(),
+ T.Normalize([0.48145466, 0.4578275, 0.40821073],
+ [0.26862954, 0.26130258, 0.27577711]),
+ ])
+ return transform(pil_image.fromarray(img_rgb)).unsqueeze(0) # 1×3×H×W
+
+
+@torch.inference_mode()
+def infer_single_image(
+ img_bgr: np.ndarray,
+ face_detector,
+ landmark_predictor,
+ model,
+) -> Tuple[int, float]:
+ """Return (cls_out, prob)"""
+ if face_detector is None or landmark_predictor is None:
+ face_aligned = img_bgr
+ else:
+ face_aligned, _, _ = extract_aligned_face_dlib(
+ face_detector, landmark_predictor, img_bgr, res=224
+ )
+
+ face_tensor = preprocess_face(face_aligned).to(device)
+ data = {"image": face_tensor, "label": torch.tensor([0]).to(device)}
+ preds = inference(model, data)
+ cls_out = preds["cls"].squeeze().cpu().numpy() # 0/1
+ prob = preds["prob"].squeeze().cpu().numpy() # prob
+ return cls_out, prob
+
+
+IMG_EXTS = {'.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.webp'}
+def collect_image_paths(path_str: str) -> List[Path]:
+ p = Path(path_str)
+ if not p.exists():
+ raise FileNotFoundError(f"[Error] Path does not exist: {path_str}")
+
+ if p.is_file():
+ if p.suffix.lower() not in IMG_EXTS:
+ raise ValueError(f"[Error] Invalid image format: {p.name}")
+ return [p]
+
+ img_list = [fp for fp in p.iterdir() if fp.is_file() and fp.suffix.lower() in IMG_EXTS]
+ if not img_list:
+ raise RuntimeError(f"[Error] No valid image files found in directory: {path_str}")
+
+ return sorted(img_list)
+
+
+def parse_args():
+ p = argparse.ArgumentParser(
+ description="Deepfake image inference (single image version)"
+ )
+ p.add_argument("--detector_config", default='training/config/detector/effort.yaml',
+ help="YAML 配置文件路径")
+ p.add_argument("--weights", required=True,
+ help="Detector 预训练权重")
+ p.add_argument("--image", required=True,
+ help="tested image")
+ p.add_argument("--landmark_model", default=False,
+ help="dlib 81 landmarks dat 文件 / 如果不需要裁剪人脸就是False")
+ return p.parse_args()
+
+
+def main():
+ args = parse_args()
+
+ model = load_detector(args.detector_config, args.weights)
+ if args.landmark_model:
+ face_det = dlib.get_frontal_face_detector()
+ shape_predictor = dlib.shape_predictor(args.landmark_model)
+ else:
+ face_det, shape_predictor = None, None
+
+ img_paths = collect_image_paths(args.image)
+ multiple = len(img_paths) > 1
+ if multiple:
+ print(f"Collected {len(img_paths)} images in total,let's infer them...\n")
+
+ # ---------- infer ----------
+ for idx, img_path in enumerate(img_paths, 1):
+ img = cv2.imread(str(img_path))
+ if img is None:
+ print(f"[Warning] loading wrong,skip: {img_path}", file=sys.stderr)
+ continue
+
+ cls, prob = infer_single_image(img, face_det, shape_predictor, model)
+ print(
+ f"[{idx}/{len(img_paths)}] {img_path.name:>30} | Pred Label: {cls} "
+ f"(0=Real, 1=Fake) | Fake Prob: {prob:.4f}"
+ )
+
+
+if __name__ == "__main__":
+ main()
diff --git a/clean/image/effort/DeepfakeBench/training/detectors/__init__.py b/clean/image/effort/DeepfakeBench/training/detectors/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..95452704d19f9f74d793b3df6031b8c82d30c1a3
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/detectors/__init__.py
@@ -0,0 +1,10 @@
+import os
+import sys
+current_file_path = os.path.abspath(__file__)
+parent_dir = os.path.dirname(os.path.dirname(current_file_path))
+project_root_dir = os.path.dirname(parent_dir)
+sys.path.append(parent_dir)
+sys.path.append(project_root_dir)
+
+from utils.registry import DETECTOR
+from .effort_detector import EffortDetector
diff --git a/clean/image/effort/DeepfakeBench/training/detectors/base_detector.py b/clean/image/effort/DeepfakeBench/training/detectors/base_detector.py
new file mode 100644
index 0000000000000000000000000000000000000000..935d102215d37f735419ce32d5b1a8b50b817531
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/detectors/base_detector.py
@@ -0,0 +1,78 @@
+# author: Zhiyuan Yan
+# email: zhiyuanyan@link.cuhk.edu.cn
+# date: 2023-0706
+# description: Abstract Class for the Deepfake Detector
+
+import abc
+import torch
+import torch.nn as nn
+from typing import Union
+
+class AbstractDetector(nn.Module, metaclass=abc.ABCMeta):
+ """
+ All deepfake detectors should subclass this class.
+ """
+ def __init__(self, config=None, load_param: Union[bool, str] = False):
+ """
+ config: (dict)
+ configurations for the model
+ load_param: (False | True | Path(str))
+ False Do not read; True Read the default path; Path Read the required path
+ """
+ super().__init__()
+
+ @abc.abstractmethod
+ def features(self, data_dict: dict) -> torch.tensor:
+ """
+ Returns the features from the backbone given the input data.
+ """
+ pass
+
+ @abc.abstractmethod
+ def forward(self, data_dict: dict, inference=False) -> dict:
+ """
+ Forward pass through the model, returning the prediction dictionary.
+ """
+ pass
+
+ @abc.abstractmethod
+ def classifier(self, features: torch.tensor) -> torch.tensor:
+ """
+ Classifies the features into classes.
+ """
+ pass
+
+ @abc.abstractmethod
+ def build_backbone(self, config):
+ """
+ Builds the backbone of the model.
+ """
+ pass
+
+ @abc.abstractmethod
+ def build_loss(self, config):
+ """
+ Builds the loss function for the model.
+ """
+ pass
+
+ @abc.abstractmethod
+ def get_losses(self, data_dict: dict, pred_dict: dict) -> dict:
+ """
+ Returns the losses for the model.
+ """
+ pass
+
+ @abc.abstractmethod
+ def get_train_metrics(self, data_dict: dict, pred_dict: dict) -> dict:
+ """
+ Returns the training metrics for the model.
+ """
+ pass
+
+ @abc.abstractmethod
+ def get_test_metrics(self):
+ """
+ Returns the testing metrics for the model.
+ """
+ pass
diff --git a/clean/image/effort/DeepfakeBench/training/detectors/effort_detector.py b/clean/image/effort/DeepfakeBench/training/detectors/effort_detector.py
new file mode 100644
index 0000000000000000000000000000000000000000..c9784ba965addaf69b094d4c8786267bdd218e3c
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/detectors/effort_detector.py
@@ -0,0 +1,347 @@
+import os
+import math
+import datetime
+import logging
+import numpy as np
+from sklearn import metrics
+from typing import Union
+from collections import defaultdict
+
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+import torch.optim as optim
+from torch.nn import DataParallel
+from torch.utils.tensorboard import SummaryWriter
+
+from metrics.base_metrics_class import calculate_metrics_for_train
+
+from .base_detector import AbstractDetector
+from detectors import DETECTOR
+from networks import BACKBONE
+from loss import LOSSFUNC
+
+import loralib as lora
+from transformers import AutoProcessor, CLIPModel, ViTModel, ViTConfig
+
+logger = logging.getLogger(__name__)
+
+
+@DETECTOR.register_module(module_name='effort')
+class EffortDetector(nn.Module):
+ def __init__(self, config=None):
+ super(EffortDetector, self).__init__()
+ self.config = config
+ self.backbone = self.build_backbone(config)
+ self.head = nn.Linear(1024, 2)
+ self.loss_func = nn.CrossEntropyLoss()
+ self.prob, self.label = [], []
+ self.correct, self.total = 0, 0
+
+ def build_backbone(self, config):
+ # ⚠⚠⚠ Download CLIP model using the below link
+ # https://drive.google.com/drive/folders/1fm3Jd8lFMiSP1qgdmsxfqlJZGpr_bXsx?usp=drive_link
+
+ # mean: [0.48145466, 0.4578275, 0.40821073]
+ # std: [0.26862954, 0.26130258, 0.27577711]
+
+ # ViT-L/14 224*224
+ clip_model = CLIPModel.from_pretrained("../models--openai--clip-vit-large-patch14") # the path of this folder in your disk (download from the above link)
+
+ # Apply SVD to self_attn layers only
+ # ViT-L/14 224*224: 1024-1
+ clip_model.vision_model = apply_svd_residual_to_self_attn(clip_model.vision_model, r=1024-1)
+
+ #for name, param in clip_model.vision_model.named_parameters():
+ # print('{}: {}'.format(name, param.requires_grad))
+ #num_param = sum(p.numel() for p in clip_model.vision_model.parameters() if p.requires_grad)
+ #num_total_param = sum(p.numel() for p in clip_model.vision_model.parameters())
+ #print('Number of total parameters: {}, tunable parameters: {}'.format(num_total_param, num_param))
+
+ return clip_model.vision_model
+
+ def features(self, data_dict: dict) -> torch.tensor:
+ feat = self.backbone(data_dict['image'])['pooler_output']
+ return feat
+
+ def classifier(self, features: torch.tensor) -> torch.tensor:
+ return self.head(features)
+
+ #def get_losses(self, data_dict: dict, pred_dict: dict) -> dict:
+ # label = data_dict['label']
+ # pred = pred_dict['cls']
+ # loss = self.loss_func(pred, label)
+ #
+ # if self.training:
+ # # Regularization term
+ # lambda_reg = 1.0
+ # reg_term = 0.0
+ # num_reg = 0
+ # for module in self.backbone.modules():
+ # if isinstance(module, SVDResidualLinear):
+ # reg_term += module.compute_orthogonal_loss()
+ # reg_term += module.compute_keepsv_loss()
+ # num_reg += 1
+ #
+ # loss += lambda_reg * reg_term / num_reg
+ #
+ # loss_dict = {'overall': loss}
+ # return loss_dict
+
+ def compute_weight_loss(self):
+ weight_sum_dict = {}
+ num_weight_dict = {}
+ for name, module in self.backbone.named_modules():
+ if isinstance(module, SVDResidualLinear):
+ weight_curr = module.compute_current_weight()
+ if str(weight_curr.size()) not in weight_sum_dict.keys():
+ weight_sum_dict[str(weight_curr.size())] = weight_curr
+ num_weight_dict[str(weight_curr.size())] = 1
+ else:
+ weight_sum_dict[str(weight_curr.size())] += weight_curr
+ num_weight_dict[str(weight_curr.size())] += 1
+
+ loss2 = 0.0
+ for k in weight_sum_dict.keys():
+ _, S_sum, _ = torch.linalg.svd(weight_sum_dict[k], full_matrices=False)
+ loss2 += -torch.mean(S_sum)
+ loss2 /= len(weight_sum_dict.keys())
+ return loss2
+
+ def get_losses(self, data_dict: dict, pred_dict: dict) -> dict:
+ label = data_dict['label'] # Tensor of shape [batch_size]
+ pred = pred_dict['cls'] # Tensor of shape [batch_size, num_classes]
+
+ # Compute overall loss using all samples
+ loss = self.loss_func(pred, label)
+
+ # Create masks for real and fake classes
+ mask_real = label == 0 # Boolean tensor
+ mask_fake = label == 1 # Boolean tensor
+
+ # Compute loss for real class
+ if mask_real.sum() > 0:
+ pred_real = pred[mask_real]
+ label_real = label[mask_real]
+ loss_real = self.loss_func(pred_real, label_real)
+ else:
+ # No real samples in batch
+ loss_real = torch.tensor(0.0, device=pred.device)
+
+ # Compute loss for fake class
+ if mask_fake.sum() > 0:
+ pred_fake = pred[mask_fake]
+ label_fake = label[mask_fake]
+ loss_fake = self.loss_func(pred_fake, label_fake)
+ else:
+ # No fake samples in batch
+ loss_fake = torch.tensor(0.0, device=pred.device)
+
+
+ # loss2 = self.compute_weight_loss()
+ # overall_loss = loss + loss2
+
+ # Return a dictionary with all losses
+ loss_dict = {
+ 'overall': loss,
+ 'real_loss': loss_real,
+ 'fake_loss': loss_fake,
+ # 'erank_loss': loss2
+ }
+ return loss_dict
+
+ def get_train_metrics(self, data_dict: dict, pred_dict: dict) -> dict:
+ label = data_dict['label']
+ pred = pred_dict['cls']
+ # compute metrics for batch data
+ auc, eer, acc, ap = calculate_metrics_for_train(label.detach(), pred.detach())
+ metric_batch_dict = {'acc': acc, 'auc': auc, 'eer': eer, 'ap': ap}
+ return metric_batch_dict
+
+ def forward(self, data_dict: dict, inference=False) -> dict:
+ # get the features by backbone
+ features = self.features(data_dict)
+ # get the prediction by classifier
+ pred = self.classifier(features)
+ # get the probability of the pred
+ prob = torch.softmax(pred, dim=1)[:, 1]
+ # build the prediction dict for each output
+ pred_dict = {'cls': pred, 'prob': prob, 'feat': features}
+
+ return pred_dict
+
+
+# Custom module to represent the residual using SVD components
+class SVDResidualLinear(nn.Module):
+ def __init__(self, in_features, out_features, r, bias=True, init_weight=None):
+ super(SVDResidualLinear, self).__init__()
+ self.in_features = in_features
+ self.out_features = out_features
+ self.r = r # Number of top singular values to exclude
+
+ # Original weights (fixed)
+ self.weight_main = nn.Parameter(torch.Tensor(out_features, in_features), requires_grad=False)
+ if init_weight is not None:
+ self.weight_main.data.copy_(init_weight)
+ else:
+ nn.init.kaiming_uniform_(self.weight_main, a=math.sqrt(5))
+
+ # Bias
+ if bias:
+ self.bias = nn.Parameter(torch.Tensor(out_features))
+ nn.init.zeros_(self.bias)
+ else:
+ self.register_parameter('bias', None)
+
+ def compute_current_weight(self):
+ if self.S_residual is not None:
+ return self.weight_main + self.U_residual @ torch.diag(self.S_residual) @ self.V_residual
+ else:
+ return self.weight_main
+
+ def forward(self, x):
+ if hasattr(self, 'U_residual') and hasattr(self, 'V_residual') and self.S_residual is not None:
+ # Reconstruct the residual weight
+ residual_weight = self.U_residual @ torch.diag(self.S_residual) @ self.V_residual
+ # Total weight is the fixed main weight plus the residual
+ weight = self.weight_main + residual_weight
+ else:
+ # If residual components are not set, use only the main weight
+ weight = self.weight_main
+
+ return F.linear(x, weight, self.bias)
+
+ def compute_orthogonal_loss(self):
+ if self.S_residual is not None:
+ # According to the properties of orthogonal matrices: A^TA = I
+ UUT = torch.cat((self.U_r, self.U_residual), dim=1) @ torch.cat((self.U_r, self.U_residual), dim=1).t()
+ VVT = torch.cat((self.V_r, self.V_residual), dim=0) @ torch.cat((self.V_r, self.V_residual), dim=0).t()
+ # print(self.U_r.size(), self.U_residual.size()) # torch.Size([1024, 1023]) torch.Size([1024, 1])
+ # print(self.V_r.size(), self.V_residual.size()) # torch.Size([1023, 1024]) torch.Size([1, 1024])
+ # UUT = self.U_residual @ self.U_residual.t()
+ # VVT = self.V_residual @ self.V_residual.t()
+
+ # Construct an identity matrix
+ UUT_identity = torch.eye(UUT.size(0), device=UUT.device)
+ VVT_identity = torch.eye(VVT.size(0), device=VVT.device)
+
+ # Using frobenius norm to compute loss
+ loss = 0.5 * torch.norm(UUT - UUT_identity, p='fro') + 0.5 * torch.norm(VVT - VVT_identity, p='fro')
+ else:
+ loss = 0.0
+
+ return loss
+
+ def compute_keepsv_loss(self):
+ if (self.S_residual is not None) and (self.weight_original_fnorm is not None):
+ # Total current weight is the fixed main weight plus the residual
+ weight_current = self.weight_main + self.U_residual @ torch.diag(self.S_residual) @ self.V_residual
+ # Frobenius norm of current weight
+ weight_current_fnorm = torch.norm(weight_current, p='fro')
+
+ loss = torch.abs(weight_current_fnorm ** 2 - self.weight_original_fnorm ** 2)
+ # loss = torch.abs(weight_current_fnorm ** 2 + 0.01 * self.weight_main_fnorm ** 2 - 1.01 * self.weight_original_fnorm ** 2)
+ else:
+ loss = 0.0
+
+ return loss
+
+ def compute_fn_loss(self):
+ if (self.S_residual is not None):
+ weight_current = self.weight_main + self.U_residual @ torch.diag(self.S_residual) @ self.V_residual
+ weight_current_fnorm = torch.norm(weight_current, p='fro')
+
+ loss = weight_current_fnorm ** 2
+ else:
+ loss = 0.0
+
+ return loss
+
+# Function to replace nn.Linear modules within self_attn modules with SVDResidualLinear
+def apply_svd_residual_to_self_attn(model, r):
+ for name, module in model.named_children():
+ if 'self_attn' in name:
+ # Replace nn.Linear layers in this module
+ for sub_name, sub_module in module.named_modules():
+ if isinstance(sub_module, nn.Linear):
+ # Get parent module within self_attn
+ parent_module = module
+ sub_module_names = sub_name.split('.')
+ for module_name in sub_module_names[:-1]:
+ parent_module = getattr(parent_module, module_name)
+ # Replace the nn.Linear layer with SVDResidualLinear
+ setattr(parent_module, sub_module_names[-1], replace_with_svd_residual(sub_module, r))
+ else:
+ # Recursively apply to child modules
+ apply_svd_residual_to_self_attn(module, r)
+ # After replacing, set requires_grad for residual components
+ for param_name, param in model.named_parameters():
+ if any(x in param_name for x in ['S_residual', 'U_residual', 'V_residual']):
+ param.requires_grad = True
+ else:
+ param.requires_grad = False
+ return model
+
+
+# Function to replace a module with SVDResidualLinear
+def replace_with_svd_residual(module, r):
+ if isinstance(module, nn.Linear):
+ in_features = module.in_features
+ out_features = module.out_features
+ bias = module.bias is not None
+
+ # Create SVDResidualLinear module
+ new_module = SVDResidualLinear(in_features, out_features, r, bias=bias, init_weight=module.weight.data.clone())
+
+ if bias and module.bias is not None:
+ new_module.bias.data.copy_(module.bias.data)
+
+ new_module.weight_original_fnorm = torch.norm(module.weight.data, p='fro')
+
+ # Perform SVD on the original weight
+ _svd_device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")
+ U, S, Vh = torch.linalg.svd(module.weight.data.to(_svd_device), full_matrices=False)
+ U, S, Vh = U.cpu(), S.cpu(), Vh.cpu()
+
+ # Determine r based on the rank of the weight matrix
+ r = min(r, len(S)) # Ensure r does not exceed the number of singular values
+
+ # Keep top r singular components (main weight)
+ U_r = U[:, :r] # Shape: (out_features, r)
+ S_r = S[:r] # Shape: (r,)
+ Vh_r = Vh[:r, :] # Shape: (r, in_features)
+
+ # Reconstruct the main weight (fixed)
+ weight_main = U_r @ torch.diag(S_r) @ Vh_r
+
+ # Calculate the frobenius norm of main weight
+ new_module.weight_main_fnorm = torch.norm(weight_main.data, p='fro')
+
+ # Set the main weight
+ new_module.weight_main.data.copy_(weight_main)
+
+ # Residual components (trainable)
+ U_residual = U[:, r:] # Shape: (out_features, n - r)
+ S_residual = S[r:] # Shape: (n - r,)
+ Vh_residual = Vh[r:, :] # Shape: (n - r, in_features)
+
+ if len(S_residual) > 0:
+ new_module.S_residual = nn.Parameter(S_residual.clone())
+ new_module.U_residual = nn.Parameter(U_residual.clone())
+ new_module.V_residual = nn.Parameter(Vh_residual.clone())
+
+ new_module.S_r = nn.Parameter(S_r.clone(), requires_grad=False)
+ new_module.U_r = nn.Parameter(U_r.clone(), requires_grad=False)
+ new_module.V_r = nn.Parameter(Vh_r.clone(), requires_grad=False)
+ else:
+ new_module.S_residual = None
+ new_module.U_residual = None
+ new_module.V_residual = None
+
+ new_module.S_r = None
+ new_module.U_r = None
+ new_module.V_r = None
+
+ return new_module
+ else:
+ return module
diff --git a/clean/image/effort/DeepfakeBench/training/logger.py b/clean/image/effort/DeepfakeBench/training/logger.py
new file mode 100644
index 0000000000000000000000000000000000000000..831c8679c128d91740d1ca3fb9fdae56dfe1b1b4
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/logger.py
@@ -0,0 +1,27 @@
+import os
+import logging
+
+def create_logger(log_path):
+ # Create log path
+ if os.path.isdir(os.path.dirname(log_path)):
+ os.makedirs(os.path.dirname(log_path), exist_ok=True)
+
+ # Create logger object
+ logger = logging.getLogger()
+ logger.setLevel(logging.INFO)
+
+ # Create file handler and set the formatter
+ fh = logging.FileHandler(log_path)
+ formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
+ fh.setFormatter(formatter)
+
+ # Add the file handler to the logger
+ logger.addHandler(fh)
+
+ # Add a stream handler to print to console
+ sh = logging.StreamHandler()
+ sh.setLevel(logging.INFO) # Set logging level for stream handler
+ sh.setFormatter(formatter)
+ logger.addHandler(sh)
+
+ return logger
\ No newline at end of file
diff --git a/clean/image/effort/DeepfakeBench/training/loss/__init__.py b/clean/image/effort/DeepfakeBench/training/loss/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..d25bdf89a79b7a322c9ad4a1bdfa489d39ee4310
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/loss/__init__.py
@@ -0,0 +1,12 @@
+from utils.registry import LOSSFUNC
+from .cross_entropy_loss import CrossEntropyLoss
+from .consistency_loss import ConsistencyCos
+from .capsule_loss import CapsuleLoss
+from .bce_loss import BCELoss
+from .am_softmax import AMSoftmaxLoss
+from .am_softmax import AMSoftmax_OHEM
+from .contrastive_regularization import ContrastiveLoss
+from .l1_loss import L1Loss
+from .id_loss import IDLoss
+from .vgg_loss import VGGLoss
+from .js_loss import JS_Loss
\ No newline at end of file
diff --git a/clean/image/effort/DeepfakeBench/training/loss/abstract_loss_func.py b/clean/image/effort/DeepfakeBench/training/loss/abstract_loss_func.py
new file mode 100644
index 0000000000000000000000000000000000000000..45d3324ed53be4310867b326e9eaabd265634138
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/loss/abstract_loss_func.py
@@ -0,0 +1,17 @@
+import torch.nn as nn
+
+class AbstractLossClass(nn.Module):
+ """Abstract class for loss functions."""
+ def __init__(self):
+ super(AbstractLossClass, self).__init__()
+
+ def forward(self, pred, label):
+ """
+ Args:
+ pred: prediction of the model
+ label: ground truth label
+
+ Return:
+ loss: loss value
+ """
+ raise NotImplementedError('Each subclass should implement the forward method.')
diff --git a/clean/image/effort/DeepfakeBench/training/loss/am_softmax.py b/clean/image/effort/DeepfakeBench/training/loss/am_softmax.py
new file mode 100644
index 0000000000000000000000000000000000000000..8a43a4287f7c036392c69c30e1a518a7710b41e1
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/loss/am_softmax.py
@@ -0,0 +1,145 @@
+"""
+ Copyright (c) 2018 Intel Corporation
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+"""
+
+import math
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+from torch.nn import Parameter
+import torch as th
+
+from loss.abstract_loss_func import AbstractLossClass
+from utils.registry import LOSSFUNC
+
+
+#------------ AMSoftmax Loss ----------------------
+
+def focal_loss(input_values, gamma):
+ """Computes the focal loss"""
+ p = torch.exp(-input_values)
+ loss = (1 - p) ** gamma * input_values
+ return loss.mean()
+
+
+@LOSSFUNC.register_module(module_name="am_softmax")
+class AMSoftmaxLoss(AbstractLossClass):
+ """Computes the AM-Softmax loss with cos or arc margin"""
+ margin_types = ['cos', 'arc']
+
+ def __init__(self, margin_type='cos', gamma=0., m=0.5, s=30, t=1.):
+ super().__init__()
+ assert margin_type in AMSoftmaxLoss.margin_types
+ self.margin_type = margin_type
+ assert gamma >= 0
+ self.gamma = gamma
+ assert m > 0
+ self.m = m
+ assert s > 0
+ self.s = s
+ self.cos_m = math.cos(m)
+ self.sin_m = math.sin(m)
+ self.th = math.cos(math.pi - m)
+ assert t >= 1
+ self.t = t
+
+ def forward(self, cos_theta, target):
+ if self.margin_type == 'cos':
+ phi_theta = cos_theta - self.m
+ else:
+ sine = torch.sqrt(1.0 - torch.pow(cos_theta, 2))
+ phi_theta = cos_theta * self.cos_m - sine * self.sin_m #cos(theta+m)
+ phi_theta = torch.where(cos_theta > self.th, phi_theta, cos_theta - self.sin_m * self.m)
+
+ index = torch.zeros_like(cos_theta, dtype=torch.uint8)
+ index.scatter_(1, target.data.view(-1, 1), 1)
+ output = torch.where(index, phi_theta, cos_theta)
+
+ if self.gamma == 0 and self.t == 1.:
+ return F.cross_entropy(self.s*output, target)
+
+ if self.t > 1:
+ h_theta = self.t - 1 + self.t*cos_theta
+ support_vecs_mask = (1 - index) * \
+ torch.lt(torch.masked_select(phi_theta, index).view(-1, 1).repeat(1, h_theta.shape[1]) - cos_theta, 0)
+ output = torch.where(support_vecs_mask, h_theta, output)
+ return F.cross_entropy(self.s*output, target)
+
+ return focal_loss(F.cross_entropy(self.s*output, target, reduction='none'), self.gamma)
+
+
+@LOSSFUNC.register_module(module_name="am_softmax_ohem")
+class AMSoftmax_OHEM(AbstractLossClass):
+ """Computes the AM-Softmax loss with cos or arc margin"""
+ margin_types = ['cos', 'arc']
+
+ def __init__(self, margin_type='cos', gamma=0., m=0.5, s=30, t=1., ratio=1.):
+ super(self).__init__()
+ assert margin_type in AMSoftmaxLoss.margin_types
+ self.margin_type = margin_type
+ assert gamma >= 0
+ self.gamma = gamma
+ assert m > 0
+ self.m = m
+ assert s > 0
+ self.s = s
+ self.cos_m = math.cos(m)
+ self.sin_m = math.sin(m)
+ self.th = math.cos(math.pi - m)
+ assert t >= 1
+ self.t = t
+ self.ratio = ratio
+
+
+ # ------- online hard example mining --------------------
+ def get_subidx(self,x,y,ratio):
+ num_inst = x.size(0)
+ num_hns = int(ratio * num_inst)
+ x_ = x.clone()
+ inst_losses = th.autograd.Variable(th.zeros(num_inst)).cuda()
+
+ for idx, label in enumerate(y.data):
+ inst_losses[idx] = -x_.data[idx, label]
+
+ _, idxs = inst_losses.topk(num_hns)
+ return idxs
+
+
+ def forward(self, cos_theta, target):
+ if self.margin_type == 'cos':
+ phi_theta = cos_theta - self.m
+ else:
+ sine = torch.sqrt(1.0 - torch.pow(cos_theta, 2))
+ phi_theta = cos_theta * self.cos_m - sine * self.sin_m #cos(theta+m)
+ phi_theta = torch.where(cos_theta > self.th, phi_theta, cos_theta - self.sin_m * self.m)
+
+ index = torch.zeros_like(cos_theta, dtype=torch.uint8)
+ index.scatter_(1, target.data.view(-1, 1), 1)
+ output = torch.where(index, phi_theta, cos_theta)
+
+ out = F.log_softmax(output,dim=1)
+ idxs = self.get_subidx(out,target,self.ratio) # select hard examples
+
+ output2 = output.index_select(0, idxs)
+ target2 = target.index_select(0, idxs)
+
+ if self.gamma == 0 and self.t == 1.:
+ return F.cross_entropy(self.s*output2, target2)
+
+ if self.t > 1:
+ h_theta = self.t - 1 + self.t*cos_theta
+ support_vecs_mask = (1 - index) * \
+ torch.lt(torch.masked_select(phi_theta, index).view(-1, 1).repeat(1, h_theta.shape[1]) - cos_theta, 0)
+ output2 = torch.where(support_vecs_mask, h_theta, output2)
+ return F.cross_entropy(self.s*output2, target2)
+
+ return focal_loss(F.cross_entropy(self.s*output2, target2, reduction='none'), self.gamma)
\ No newline at end of file
diff --git a/clean/image/effort/DeepfakeBench/training/loss/bce_loss.py b/clean/image/effort/DeepfakeBench/training/loss/bce_loss.py
new file mode 100644
index 0000000000000000000000000000000000000000..4d71b5e6e4b2b9d6bc25fdd9262d9f66d475e619
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/loss/bce_loss.py
@@ -0,0 +1,26 @@
+import torch.nn as nn
+from loss.abstract_loss_func import AbstractLossClass
+from utils.registry import LOSSFUNC
+
+
+@LOSSFUNC.register_module(module_name="bce")
+class BCELoss(AbstractLossClass):
+ def __init__(self):
+ super().__init__()
+ self.loss_fn = nn.BCELoss()
+
+ def forward(self, inputs, targets):
+ """
+ Computes the bce loss.
+
+ Args:
+ inputs: A PyTorch tensor of size (batch_size, num_classes) containing the predicted scores.
+ targets: A PyTorch tensor of size (batch_size) containing the ground-truth class indices.
+
+ Returns:
+ A scalar tensor representing the bce loss.
+ """
+ # Compute the bce loss
+ loss = self.loss_fn(inputs, targets.float())
+
+ return loss
\ No newline at end of file
diff --git a/clean/image/effort/DeepfakeBench/training/loss/capsule_loss.py b/clean/image/effort/DeepfakeBench/training/loss/capsule_loss.py
new file mode 100644
index 0000000000000000000000000000000000000000..7e2adad9ced2d1eade1ad80bf7b1cd84cf60ea9b
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/loss/capsule_loss.py
@@ -0,0 +1,28 @@
+import torch.nn as nn
+from loss.abstract_loss_func import AbstractLossClass
+from utils.registry import LOSSFUNC
+
+
+@LOSSFUNC.register_module(module_name="capsule_loss")
+class CapsuleLoss(AbstractLossClass):
+ def __init__(self):
+ super().__init__()
+ self.cross_entropy_loss = nn.CrossEntropyLoss()
+
+ def forward(self, inputs, targets):
+ """
+ Computes the capsule loss.
+
+ Args:
+ inputs: A PyTorch tensor of size (batch_size, num_classes) containing the predicted scores.
+ targets: A PyTorch tensor of size (batch_size) containing the ground-truth class indices.
+
+ Returns:
+ A scalar tensor representing the capsule loss.
+ """
+ # Compute the capsule loss
+ loss_t = self.cross_entropy_loss(inputs[:,0,:], targets)
+
+ for i in range(inputs.size(1) - 1):
+ loss_t = loss_t + self.cross_entropy_loss(inputs[:,i+1,:], targets)
+ return loss_t
diff --git a/clean/image/effort/DeepfakeBench/training/loss/classNseg_loss.py b/clean/image/effort/DeepfakeBench/training/loss/classNseg_loss.py
new file mode 100644
index 0000000000000000000000000000000000000000..4f81f2b577805e5d45f88ccf2ce21c7cd73d3802
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/loss/classNseg_loss.py
@@ -0,0 +1,64 @@
+import torch
+from torch import nn
+from loss.abstract_loss_func import AbstractLossClass
+from utils.registry import LOSSFUNC
+
+
+@LOSSFUNC.register_module(module_name="classNseg_loss")
+class ClassNsegLoss(AbstractLossClass):
+ def __init__(self):
+ super().__init__()
+ self.gamma = 1.0 # weight decay. default=5.0
+ self.act_loss_fn = ActivationLoss()
+ self.rect_loss_fn = ReconstructionLoss()
+ self.seg_loss_fn = SegmentationLoss()
+
+ def forward(self, inputs, targets):
+
+ zero_abs = torch.abs(latent[:,0]).view(latent.shape[0], -1)
+ zero = zero_abs.mean(dim=1)
+
+ one_abs = torch.abs(latent[:,1]).view(latent.shape[0], -1)
+ one = one_abs.mean(dim=1)
+
+ loss_act = self.act_loss_fn(zero, one, labels_data)
+ loss_act_data = loss_act.item()
+
+ loss_seg = self.seg_loss_fn(seg, mask)
+ loss_seg = loss_seg * self.gamma
+ loss_seg_data = loss_seg.item()
+
+ loss_rect = self.rect_loss_fn(rect, rgb)
+ loss_rect = loss_rect * self.gamma
+ loss_rect_data = loss_rect.item()
+ loss_total = loss_act + loss_seg + loss_rect
+ return loss_total, loss_act_data, loss_seg_data, loss_rect_data
+
+
+class ActivationLoss(nn.Module):
+ def __init__(self):
+ super(ActivationLoss, self).__init__()
+
+ def forward(self, zero, one, labels):
+
+ loss_act = torch.abs(one - labels.data) + torch.abs(zero - (1.0 - labels.data))
+ return 1 / labels.shape[0] * loss_act.sum()
+
+class ReconstructionLoss(nn.Module):
+ def __init__(self):
+ super(ReconstructionLoss, self).__init__()
+ self.loss = nn.MSELoss()
+
+ def forward(self, reconstruction, groundtruth):
+
+ return self.loss(reconstruction, groundtruth.data)
+
+class SegmentationLoss(nn.Module):
+ def __init__(self):
+ super(SegmentationLoss, self).__init__()
+ self.loss = nn.CrossEntropyLoss()
+
+ def forward(self, segment, groundtruth):
+
+ return self.loss(segment.view(segment.shape[0], segment.shape[1], segment.shape[2] * segment.shape[3]),
+ groundtruth.data.view(groundtruth.shape[0], groundtruth.shape[1] * groundtruth.shape[2]))
diff --git a/clean/image/effort/DeepfakeBench/training/loss/consistency_loss.py b/clean/image/effort/DeepfakeBench/training/loss/consistency_loss.py
new file mode 100644
index 0000000000000000000000000000000000000000..50e666aad8bbdd659c136d5506d1dbd2a7675685
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/loss/consistency_loss.py
@@ -0,0 +1,54 @@
+import torch.nn as nn
+import torch
+from loss.abstract_loss_func import AbstractLossClass
+from utils.registry import LOSSFUNC
+
+
+@LOSSFUNC.register_module(module_name="consistency_loss")
+class ConsistencyCos(nn.Module):
+ def __init__(self):
+ super(ConsistencyCos, self).__init__()
+ # # CrossEntropy Loss
+ # weight=torch.Tensor([4.0, 1.0])
+ # if torch.cuda.is_available():
+ # weight = weight.cuda()
+ # self.loss_fn = nn.CrossEntropyLoss(weight)
+ self.loss_fn = nn.CrossEntropyLoss()
+ self.mse_fn = nn.MSELoss()
+
+ def forward(self, feat, inputs, targets):
+ feat = nn.functional.normalize(feat, dim=1)
+ feat_0 = feat[:int(feat.size(0)/2),:]
+ feat_1 = feat[int(feat.size(0)/2): 2*int(feat.size(0)/2),:]
+
+ cos = torch.einsum('nc,nc->n', [feat_0, feat_1]).unsqueeze(-1)
+ labels = torch.ones((cos.shape[0],1), dtype=torch.float, requires_grad=False)
+ if torch.cuda.is_available():
+ labels = labels.cuda()
+ self.consistency_rate = 1.0
+ loss = self.consistency_rate * self.mse_fn(cos, labels) + self.loss_fn(inputs, targets)
+ return loss
+
+#
+##FIXME to be implemented
+class ConsistencyL2(nn.Module):
+ def __init__(self):
+ super(ConsistencyL2, self).__init__()
+ self.mse_fn = nn.MSELoss()
+
+ def forward(self, feat):
+ feat_0 = feat[:int(feat.size(0)/2),:]
+ feat_1 = feat[int(feat.size(0)/2):,:]
+ loss = self.mse_fn(feat_0, feat_1)
+ return loss
+
+class ConsistencyL1(nn.Module):
+ def __init__(self):
+ super(ConsistencyL1, self).__init__()
+ self.L1_fn = nn.L1Loss()
+
+ def forward(self, feat):
+ feat_0 = feat[:int(feat.size(0)/2),:]
+ feat_1 = feat[int(feat.size(0)/2):,:]
+ loss = self.L1_fn(feat_0, feat_1)
+ return loss
\ No newline at end of file
diff --git a/clean/image/effort/DeepfakeBench/training/loss/contrastive_regularization.py b/clean/image/effort/DeepfakeBench/training/loss/contrastive_regularization.py
new file mode 100644
index 0000000000000000000000000000000000000000..e067dac81fc9befb6b8e434df8a70cadf3b9807c
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/loss/contrastive_regularization.py
@@ -0,0 +1,78 @@
+import random
+from collections import defaultdict
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+from loss.abstract_loss_func import AbstractLossClass
+from utils.registry import LOSSFUNC
+
+
+def swap_spe_features(type_list, value_list):
+ type_list = type_list.cpu().numpy().tolist()
+ # get index
+ index_list = list(range(len(type_list)))
+
+ # init a dict, where its key is the type and value is the index
+ spe_dict = defaultdict(list)
+
+ # do for-loop to get spe dict
+ for i, one_type in enumerate(type_list):
+ spe_dict[one_type].append(index_list[i])
+
+ # shuffle the value list of each key
+ for keys in spe_dict.keys():
+ random.shuffle(spe_dict[keys])
+
+ # generate a new index list for the value list
+ new_index_list = []
+ for one_type in type_list:
+ value = spe_dict[one_type].pop()
+ new_index_list.append(value)
+
+ # swap the value_list by new_index_list
+ value_list_new = value_list[new_index_list]
+
+ return value_list_new
+
+
+@LOSSFUNC.register_module(module_name="contrastive_regularization")
+class ContrastiveLoss(AbstractLossClass):
+ def __init__(self, margin=1.0):
+ super().__init__()
+ self.margin = margin
+
+ def contrastive_loss(self, anchor, positive, negative):
+ dist_pos = F.pairwise_distance(anchor, positive)
+ dist_neg = F.pairwise_distance(anchor, negative)
+ # Compute loss as the distance between anchor and negative minus the distance between anchor and positive
+ loss = torch.mean(torch.clamp(dist_pos - dist_neg + self.margin, min=0.0))
+ return loss
+
+ def forward(self, common, specific, spe_label):
+ # prepare
+ bs = common.shape[0]
+ real_common, fake_common = common.chunk(2)
+ ### common real
+ idx_list = list(range(0, bs//2))
+ random.shuffle(idx_list)
+ real_common_anchor = common[idx_list]
+ ### common fake
+ idx_list = list(range(bs//2, bs))
+ random.shuffle(idx_list)
+ fake_common_anchor = common[idx_list]
+ ### specific
+ specific_anchor = swap_spe_features(spe_label, specific)
+ real_specific_anchor, fake_specific_anchor = specific_anchor.chunk(2)
+ real_specific, fake_specific = specific.chunk(2)
+
+ # Compute the contrastive loss of common between real and fake
+ loss_realcommon = self.contrastive_loss(real_common, real_common_anchor, fake_common_anchor)
+ loss_fakecommon = self.contrastive_loss(fake_common, fake_common_anchor, real_common_anchor)
+
+ # Comupte the constrastive loss of specific between real and fake
+ loss_realspecific = self.contrastive_loss(real_specific, real_specific_anchor, fake_specific_anchor)
+ loss_fakespecific = self.contrastive_loss(fake_specific, fake_specific_anchor, real_specific_anchor)
+
+ # Compute the final loss as the sum of all contrastive losses
+ loss = loss_realcommon + loss_fakecommon + loss_fakespecific + loss_realspecific
+ return loss
\ No newline at end of file
diff --git a/clean/image/effort/DeepfakeBench/training/loss/cross_entropy_loss.py b/clean/image/effort/DeepfakeBench/training/loss/cross_entropy_loss.py
new file mode 100644
index 0000000000000000000000000000000000000000..bb1c11c168a7f1ac61bec91f1ed68dd77524e795
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/loss/cross_entropy_loss.py
@@ -0,0 +1,26 @@
+import torch.nn as nn
+from loss.abstract_loss_func import AbstractLossClass
+from utils.registry import LOSSFUNC
+
+
+@LOSSFUNC.register_module(module_name="cross_entropy")
+class CrossEntropyLoss(AbstractLossClass):
+ def __init__(self):
+ super().__init__()
+ self.loss_fn = nn.CrossEntropyLoss()
+
+ def forward(self, inputs, targets):
+ """
+ Computes the cross-entropy loss.
+
+ Args:
+ inputs: A PyTorch tensor of size (batch_size, num_classes) containing the predicted scores.
+ targets: A PyTorch tensor of size (batch_size) containing the ground-truth class indices.
+
+ Returns:
+ A scalar tensor representing the cross-entropy loss.
+ """
+ # Compute the cross-entropy loss
+ loss = self.loss_fn(inputs, targets)
+
+ return loss
\ No newline at end of file
diff --git a/clean/image/effort/DeepfakeBench/training/loss/det_loss.py b/clean/image/effort/DeepfakeBench/training/loss/det_loss.py
new file mode 100644
index 0000000000000000000000000000000000000000..a6acfa30d8c48871c467c3fb97e2b0d88ba874b6
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/loss/det_loss.py
@@ -0,0 +1,165 @@
+# import torch.nn as nn
+# from loss.abstract_loss_func import AbstractLossClass
+# from utils.registry import LOSSFUNC
+
+
+# @LOSSFUNC.register_module(module_name="det_loss")
+# class DETLoss(AbstractLossClass):
+# def __init__(self):
+# super().__init__()
+# self.loss_fn = nn.BCELoss()
+
+# def forward(self, inputs, targets):
+# """
+# Computes the bce loss.
+
+# Args:
+# inputs: A PyTorch tensor of size (batch_size, num_classes) containing the predicted scores.
+# targets: A PyTorch tensor of size (batch_size) containing the ground-truth class indices.
+
+# Returns:
+# A scalar tensor representing the bce loss.
+# """
+# # Compute the bce loss
+# loss = self.loss_fn(inputs, targets.float())
+
+# return loss
+
+
+# # loss init
+# det_criterion = MultiBoxLoss(
+# cfg['det_loss']['num_classes'],
+# cfg['det_loss']['overlap_thresh'],
+# cfg['det_loss']['prior_for_matching'],
+# cfg['det_loss']['bkg_label'],
+# cfg['det_loss']['neg_mining'],
+# cfg['det_loss']['neg_pos'],
+# cfg['det_loss']['neg_overlap'],
+# cfg['det_loss']['encode_target'],
+# cfg['det_loss']['use_gpu']
+# )
+# criterion = nn.CrossEntropyLoss()
+
+# loss_end_cls = criterion(outputs, labels)
+# loss_l, loss_c = det_criterion(
+# (locations, confidence),
+# confidence_labels, location_labels
+# )
+# acc = sum(outputs.max(-1).indices == labels).item() / labels.shape[0]
+# det_loss = 0.1 * (loss_l + loss_c)
+# loss = det_loss + loss_end_cls
+# loss.backward()
+
+
+# class MultiBoxLoss(nn.Module):
+# """SSD Weighted Loss Function
+# Compute Targets:
+# 1) Produce Confidence Target Indices by matching ground truth boxes
+# with (default) 'priorboxes' that have jaccard index > threshold parameter
+# (default threshold: 0.5).
+# 2) Produce localization target by 'encoding' variance into offsets of ground
+# truth boxes and their matched 'priorboxes'.
+# 3) Hard negative mining to filter the excessive number of negative examples
+# that comes with using a large number of default bounding boxes.
+# (default negative:positive ratio 3:1)
+# Objective Loss:
+# L(x,c,l,g) = (Lconf(x, c) + αLloc(x,l,g)) / N
+# Where, Lconf is the CrossEntropy Loss and Lloc is the SmoothL1 Loss
+# weighted by α which is set to 1 by cross val.
+# Args:
+# c: class confidences,
+# l: predicted boxes,
+# g: ground truth boxes
+# N: number of matched default boxes
+# See: https://arxiv.org/pdf/1512.02325.pdf for more details.
+# """
+
+# def __init__(self, num_classes, overlap_thresh, prior_for_matching,
+# bkg_label, neg_mining, neg_pos, neg_overlap, encode_target,
+# use_gpu=True):
+# super(MultiBoxLoss, self).__init__()
+# self.use_gpu = use_gpu
+# self.num_classes = num_classes
+# self.threshold = overlap_thresh
+# self.background_label = bkg_label
+# self.encode_target = encode_target
+# self.use_prior_for_matching = prior_for_matching
+# self.do_neg_mining = neg_mining
+# self.negpos_ratio = neg_pos
+# self.neg_overlap = neg_overlap
+# self.variance = [0.1, 0.2] # cfg['variance']
+
+# # def forward(self, predictions, targets):
+# def forward(self, predictions, conf_t, loc_t):
+# """Multibox Loss
+# Args:
+# predictions (tuple): A tuple containing loc preds, conf preds,
+# and prior boxes from SSD net.
+# conf shape: torch.size(batch_size,num_priors,num_classes)
+# loc shape: torch.size(batch_size,num_priors,4)
+# priors shape: torch.size(num_priors,4)
+
+# targets (tensor): Ground truth boxes and labels for a batch,
+# shape: [batch_size,num_objs,5] (last idx is the label).
+# """
+# '''
+# priors = priors[:loc_data.size(1), :]
+# num_priors = (priors.size(0))
+# num_classes = self.num_classes
+
+# # match priors (default boxes) and ground truth boxes
+# loc_t = torch.Tensor(num, num_priors, 4)
+# conf_t = torch.LongTensor(num, num_priors)
+# for idx in range(num):
+# truths = targets[idx][:, :-1].data
+# labels = targets[idx][:, -1].data
+# defaults = priors.data
+# match(self.threshold, truths, defaults, self.variance, labels,
+# loc_t, conf_t, idx)
+# '''
+# loc_data, conf_data = predictions
+# num = loc_data.size(0)
+# if self.use_gpu:
+# loc_t = loc_t.cuda()
+# conf_t = conf_t.cuda()
+# # wrap targets
+# loc_t = Variable(loc_t, requires_grad=False)
+# conf_t = Variable(conf_t, requires_grad=False)
+
+# pos = conf_t > 0
+# num_pos = pos.sum(dim=1, keepdim=True)
+
+# # Localization Loss (Smooth L1)
+# # Shape: [batch,num_priors,4]
+# pos_idx = pos.unsqueeze(pos.dim()).expand_as(loc_data)
+# loc_p = loc_data[pos_idx].view(-1, 4)
+# loc_t = loc_t[pos_idx].view(-1, 4)
+# loss_l = F.smooth_l1_loss(loc_p, loc_t, size_average=False)
+
+# # Compute max conf across batch for hard negative mining
+# batch_conf = conf_data.view(-1, self.num_classes)
+# loss_c = log_sum_exp(batch_conf) - batch_conf.gather(1, conf_t.view(-1, 1))
+
+# # Hard Negative Mining
+# # loss_c[pos] = 0 # filter out pos boxes for now
+# loss_c[pos.view(-1, 1)] = 0
+# loss_c = loss_c.view(num, -1)
+# _, loss_idx = loss_c.sort(1, descending=True)
+# _, idx_rank = loss_idx.sort(1)
+# num_pos = pos.long().sum(1, keepdim=True)
+# num_neg = torch.clamp(self.negpos_ratio*num_pos, max=pos.size(1)-1)
+# neg = idx_rank < num_neg.expand_as(idx_rank)
+
+# # Confidence Loss Including Positive and Negative Examples
+# pos_idx = pos.unsqueeze(2).expand_as(conf_data)
+# neg_idx = neg.unsqueeze(2).expand_as(conf_data)
+# conf_p = conf_data[(pos_idx+neg_idx).gt(0)].view(-1, self.num_classes)
+# targets_weighted = conf_t[(pos+neg).gt(0)]
+# loss_c = F.cross_entropy(conf_p, targets_weighted, size_average=False)
+
+# # Sum of losses: L(x,c,l,g) = (Lconf(x, c) + αLloc(x,l,g)) / N
+
+# N = num_pos.data.sum() if num_pos.data.sum() else 1
+# loss_l /= N
+# loss_c /= N
+# return loss_l, loss_c
\ No newline at end of file
diff --git a/clean/image/effort/DeepfakeBench/training/loss/id_loss.py b/clean/image/effort/DeepfakeBench/training/loss/id_loss.py
new file mode 100644
index 0000000000000000000000000000000000000000..1c10579957a6a34213766d3809051c99da4a1bd1
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/loss/id_loss.py
@@ -0,0 +1,16 @@
+import torch
+import torch.nn as nn
+from loss.abstract_loss_func import AbstractLossClass
+from utils.registry import LOSSFUNC
+
+@LOSSFUNC.register_module(module_name="id_loss")
+class IDLoss(AbstractLossClass):
+ def __init__(self, margin=0.5):
+ super().__init__()
+ self.cosine_similarity = nn.CosineSimilarity(dim=1, eps=1e-6)
+ self.margin = margin
+
+ def forward(self, x1, x2):
+ cosine_similarity = self.cosine_similarity(x1, x2)
+ theta = torch.acos(cosine_similarity)
+ return 1 - torch.cos(theta + self.margin)
\ No newline at end of file
diff --git a/clean/image/effort/DeepfakeBench/training/loss/js_loss.py b/clean/image/effort/DeepfakeBench/training/loss/js_loss.py
new file mode 100644
index 0000000000000000000000000000000000000000..e70a3d7485bba8fcd51503a9fdc94327ce3cea78
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/loss/js_loss.py
@@ -0,0 +1,32 @@
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+from loss.abstract_loss_func import AbstractLossClass
+from utils.registry import LOSSFUNC
+
+
+@LOSSFUNC.register_module(module_name="jsloss")
+class JS_Loss(AbstractLossClass):
+ def __init__(self):
+ super().__init__()
+
+ def forward(self, inputs, targets):
+ """
+ Computes the Jensen-Shannon divergence loss.
+ """
+ # Compute the probability distributions
+ inputs_prob = F.softmax(inputs, dim=1)
+ targets_prob = F.softmax(targets, dim=1)
+
+ # Compute the average probability distribution
+ avg_prob = (inputs_prob + targets_prob) / 2
+
+ # Compute the KL divergence component for each distribution
+ kl_div_loss = nn.KLDivLoss(reduction='batchmean')
+ kl_inputs = kl_div_loss(inputs_prob.log(), avg_prob)
+ kl_targets = kl_div_loss(targets_prob.log(), avg_prob)
+
+ # Compute the Jensen-Shannon divergence
+ loss = 0.5 * (kl_inputs + kl_targets)
+
+ return loss
\ No newline at end of file
diff --git a/clean/image/effort/DeepfakeBench/training/loss/l1_loss.py b/clean/image/effort/DeepfakeBench/training/loss/l1_loss.py
new file mode 100644
index 0000000000000000000000000000000000000000..4db12aae3cec995471bfc24b69ba563d49fa6e58
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/loss/l1_loss.py
@@ -0,0 +1,19 @@
+import torch.nn as nn
+from loss.abstract_loss_func import AbstractLossClass
+from utils.registry import LOSSFUNC
+
+
+@LOSSFUNC.register_module(module_name="l1loss")
+class L1Loss(AbstractLossClass):
+ def __init__(self):
+ super().__init__()
+ self.loss_fn = nn.L1Loss()
+
+ def forward(self, inputs, targets):
+ """
+ Computes the l1 loss.
+ """
+ # Compute the l1 loss
+ loss = self.loss_fn(inputs, targets)
+
+ return loss
\ No newline at end of file
diff --git a/clean/image/effort/DeepfakeBench/training/loss/vgg_loss.py b/clean/image/effort/DeepfakeBench/training/loss/vgg_loss.py
new file mode 100644
index 0000000000000000000000000000000000000000..62353ea538b962a49a07d5c3a07cf63106a76906
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/loss/vgg_loss.py
@@ -0,0 +1,152 @@
+"""A VGG-based perceptual loss function for PyTorch."""
+
+import torch
+from torch import nn
+from torch.nn import functional as F
+from torchvision import models, transforms
+import torch
+import torch.nn as nn
+from loss.abstract_loss_func import AbstractLossClass
+from utils.registry import LOSSFUNC
+
+
+device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
+
+
+class Lambda(nn.Module):
+ """Wraps a callable in an :class:`nn.Module` without registering it."""
+
+ def __init__(self, func):
+ super().__init__()
+ object.__setattr__(self, 'forward', func)
+
+ def extra_repr(self):
+ return getattr(self.forward, '__name__', type(self.forward).__name__) + '()'
+
+
+class WeightedLoss(nn.ModuleList):
+ """A weighted combination of multiple loss functions."""
+
+ def __init__(self, losses, weights, verbose=False):
+ super().__init__()
+ for loss in losses:
+ self.append(loss if isinstance(loss, nn.Module) else Lambda(loss))
+ self.weights = weights
+ self.verbose = verbose
+
+ def _print_losses(self, losses):
+ for i, loss in enumerate(losses):
+ print(f'({i}) {type(self[i]).__name__}: {loss.item()}')
+
+ def forward(self, *args, **kwargs):
+ losses = []
+ for loss, weight in zip(self, self.weights):
+ losses.append(loss(*args, **kwargs) * weight)
+ if self.verbose:
+ self._print_losses(losses)
+ return sum(losses)
+
+
+class TVLoss(nn.Module):
+ """Total variation loss (Lp penalty on image gradient magnitude).
+ The input must be 4D. If a target (second parameter) is passed in, it is
+ ignored.
+ ``p=1`` yields the vectorial total variation norm. It is a generalization
+ of the originally proposed (isotropic) 2D total variation norm (see
+ (see https://en.wikipedia.org/wiki/Total_variation_denoising) for color
+ images. On images with a single channel it is equal to the 2D TV norm.
+ ``p=2`` yields a variant that is often used for smoothing out noise in
+ reconstructions of images from neural network feature maps (see Mahendran
+ and Vevaldi, "Understanding Deep Image Representations by Inverting
+ Them", https://arxiv.org/abs/1412.0035)
+ :attr:`reduction` can be set to ``'mean'``, ``'sum'``, or ``'none'``
+ similarly to the loss functions in :mod:`torch.nn`. The default is
+ ``'mean'``.
+ """
+
+ def __init__(self, p, reduction='mean', eps=1e-8):
+ super().__init__()
+ if p not in {1, 2}:
+ raise ValueError('p must be 1 or 2')
+ if reduction not in {'mean', 'sum', 'none'}:
+ raise ValueError("reduction must be 'mean', 'sum', or 'none'")
+ self.p = p
+ self.reduction = reduction
+ self.eps = eps
+
+ def forward(self, input, target=None):
+ input = F.pad(input, (0, 1, 0, 1), 'replicate')
+ x_diff = input[..., :-1, :-1] - input[..., :-1, 1:]
+ y_diff = input[..., :-1, :-1] - input[..., 1:, :-1]
+ diff = x_diff**2 + y_diff**2
+ if self.p == 1:
+ diff = (diff + self.eps).mean(dim=1, keepdims=True).sqrt()
+ if self.reduction == 'mean':
+ return diff.mean()
+ if self.reduction == 'sum':
+ return diff.sum()
+ return diff
+
+
+@LOSSFUNC.register_module(module_name="vgg_loss")
+class VGGLoss(AbstractLossClass):
+ """Computes the VGG perceptual loss between two batches of images.
+ The input and target must be 4D tensors with three channels
+ ``(B, 3, H, W)`` and must have equivalent shapes. Pixel values should be
+ normalized to the range 0–1.
+ The VGG perceptual loss is the mean squared difference between the features
+ computed for the input and target at layer :attr:`layer` (default 8, or
+ ``relu2_2``) of the pretrained model specified by :attr:`model` (either
+ ``'vgg16'`` (default) or ``'vgg19'``).
+ If :attr:`shift` is nonzero, a random shift of at most :attr:`shift`
+ pixels in both height and width will be applied to all images in the input
+ and target. The shift will only be applied when the loss function is in
+ training mode, and will not be applied if a precomputed feature map is
+ supplied as the target.
+ :attr:`reduction` can be set to ``'mean'``, ``'sum'``, or ``'none'``
+ similarly to the loss functions in :mod:`torch.nn`. The default is
+ ``'mean'``.
+ :meth:`get_features()` may be used to precompute the features for the
+ target, to speed up the case where inputs are compared against the same
+ target over and over. To use the precomputed features, pass them in as
+ :attr:`target` and set :attr:`target_is_features` to :code:`True`.
+ Instances of :class:`VGGLoss` must be manually converted to the same
+ device and dtype as their inputs.
+ """
+
+ models = {'vgg16': models.vgg16, 'vgg19': models.vgg19}
+
+ def __init__(self, model='vgg16', layer=8, shift=0, reduction='mean'):
+ super().__init__()
+ self.instancenorm = nn.InstanceNorm2d(512, affine=False)
+ self.shift = shift
+ self.reduction = reduction
+ self.normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406],
+ std=[0.229, 0.224, 0.225])
+ self.model = self.models[model](pretrained=True).features[:layer+1]
+ self.model.eval()
+ self.model.requires_grad_(False)
+ self.model.to(device)
+
+ def get_features(self, input):
+ return self.model(self.normalize(input))
+
+ def train(self, mode=True):
+ self.training = mode
+
+ def forward(self, input, target, target_is_features=False):
+ if target_is_features:
+ input_feats = self.get_features(input)
+ target_feats = target
+ else:
+ sep = input.shape[0]
+ batch = torch.cat([input, target])
+ if self.shift and self.training:
+ padded = F.pad(batch, [self.shift] * 4, mode='replicate')
+ batch = transforms.RandomCrop(batch.shape[2:])(padded)
+ feats = self.get_features(batch)
+ input_feats, target_feats = feats[:sep], feats[sep:]
+ # input_feats, target_feats = \
+ # self.instancenorm(input_feats), \
+ # self.instancenorm(target_feats)
+ return F.mse_loss(input_feats, target_feats, reduction=self.reduction)
\ No newline at end of file
diff --git a/clean/image/effort/DeepfakeBench/training/metrics/__init__.py b/clean/image/effort/DeepfakeBench/training/metrics/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..676145d777810e4a51bdaf59fdec4f5358aae349
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/metrics/__init__.py
@@ -0,0 +1,7 @@
+import os
+import sys
+current_file_path = os.path.abspath(__file__)
+parent_dir = os.path.dirname(os.path.dirname(current_file_path))
+project_root_dir = os.path.dirname(parent_dir)
+sys.path.append(parent_dir)
+sys.path.append(project_root_dir)
diff --git a/clean/image/effort/DeepfakeBench/training/metrics/base_metrics_class.py b/clean/image/effort/DeepfakeBench/training/metrics/base_metrics_class.py
new file mode 100644
index 0000000000000000000000000000000000000000..4e3f33b3707e0adc53e5c68848bc4c51132e53ca
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/metrics/base_metrics_class.py
@@ -0,0 +1,205 @@
+import numpy as np
+from sklearn import metrics
+from collections import defaultdict
+import torch
+import torch.nn as nn
+
+
+def get_accracy(output, label):
+ _, prediction = torch.max(output, 1) # argmax
+ correct = (prediction == label).sum().item()
+ accuracy = correct / prediction.size(0)
+ return accuracy
+
+
+def get_prediction(output, label):
+ prob = nn.functional.softmax(output, dim=1)[:, 1]
+ prob = prob.view(prob.size(0), 1)
+ label = label.view(label.size(0), 1)
+ #print(prob.size(), label.size())
+ datas = torch.cat((prob, label.float()), dim=1)
+ return datas
+
+
+def calculate_metrics_for_train(label, output):
+ if output.size(1) == 2:
+ prob = torch.softmax(output, dim=1)[:, 1]
+ else:
+ prob = output
+
+ # Accuracy
+ _, prediction = torch.max(output, 1)
+ correct = (prediction == label).sum().item()
+ accuracy = correct / prediction.size(0)
+
+ # Average Precision
+ y_true = label.cpu().detach().numpy()
+ y_pred = prob.cpu().detach().numpy()
+ ap = metrics.average_precision_score(y_true, y_pred)
+
+ # AUC and EER
+ try:
+ fpr, tpr, thresholds = metrics.roc_curve(label.squeeze().cpu().numpy(),
+ prob.squeeze().cpu().numpy(),
+ pos_label=1)
+ except:
+ # for the case when we only have one sample
+ return None, None, accuracy, ap
+
+ if np.isnan(fpr[0]) or np.isnan(tpr[0]):
+ # for the case when all the samples within a batch is fake/real
+ auc, eer = None, None
+ else:
+ auc = metrics.auc(fpr, tpr)
+ fnr = 1 - tpr
+ eer = fpr[np.nanargmin(np.absolute((fnr - fpr)))]
+
+ return auc, eer, accuracy, ap
+
+
+# ------------ compute average metrics of batches---------------------
+class Metrics_batch():
+ def __init__(self):
+ self.tprs = []
+ self.mean_fpr = np.linspace(0, 1, 100)
+ self.aucs = []
+ self.eers = []
+ self.aps = []
+
+ self.correct = 0
+ self.total = 0
+ self.losses = []
+
+ def update(self, label, output):
+ acc = self._update_acc(label, output)
+ if output.size(1) == 2:
+ prob = torch.softmax(output, dim=1)[:, 1]
+ else:
+ prob = output
+ #label = 1-label
+ #prob = torch.softmax(output, dim=1)[:, 1]
+ auc, eer = self._update_auc(label, prob)
+ ap = self._update_ap(label, prob)
+
+ return acc, auc, eer, ap
+
+ def _update_auc(self, lab, prob):
+ fpr, tpr, thresholds = metrics.roc_curve(lab.squeeze().cpu().numpy(),
+ prob.squeeze().cpu().numpy(),
+ pos_label=1)
+ if np.isnan(fpr[0]) or np.isnan(tpr[0]):
+ return -1, -1
+
+ auc = metrics.auc(fpr, tpr)
+ interp_tpr = np.interp(self.mean_fpr, fpr, tpr)
+ interp_tpr[0] = 0.0
+ self.tprs.append(interp_tpr)
+ self.aucs.append(auc)
+
+ # return auc
+
+ # EER
+ fnr = 1 - tpr
+ eer = fpr[np.nanargmin(np.absolute((fnr - fpr)))]
+ self.eers.append(eer)
+
+ return auc, eer
+
+ def _update_acc(self, lab, output):
+ _, prediction = torch.max(output, 1) # argmax
+ correct = (prediction == lab).sum().item()
+ accuracy = correct / prediction.size(0)
+ # self.accs.append(accuracy)
+ self.correct = self.correct+correct
+ self.total = self.total+lab.size(0)
+ return accuracy
+
+ def _update_ap(self, label, prob):
+ y_true = label.cpu().detach().numpy()
+ y_pred = prob.cpu().detach().numpy()
+ ap = metrics.average_precision_score(y_true,y_pred)
+ self.aps.append(ap)
+
+ return np.mean(ap)
+
+ def get_mean_metrics(self):
+ mean_acc, std_acc = self.correct/self.total, 0
+ mean_auc, std_auc = self._mean_auc()
+ mean_err, std_err = np.mean(self.eers), np.std(self.eers)
+ mean_ap, std_ap = np.mean(self.aps), np.std(self.aps)
+
+ return {'acc':mean_acc, 'auc':mean_auc, 'eer':mean_err, 'ap':mean_ap}
+
+ def _mean_auc(self):
+ mean_tpr = np.mean(self.tprs, axis=0)
+ mean_tpr[-1] = 1.0
+ mean_auc = metrics.auc(self.mean_fpr, mean_tpr)
+ std_auc = np.std(self.aucs)
+ return mean_auc, std_auc
+
+ def clear(self):
+ self.tprs.clear()
+ self.aucs.clear()
+ # self.accs.clear()
+ self.correct=0
+ self.total=0
+ self.eers.clear()
+ self.aps.clear()
+ self.losses.clear()
+
+
+# ------------ compute average metrics of all data ---------------------
+class Metrics_all():
+ def __init__(self):
+ self.probs = []
+ self.labels = []
+ self.correct = 0
+ self.total = 0
+
+ def store(self, label, output):
+ prob = torch.softmax(output, dim=1)[:, 1]
+ _, prediction = torch.max(output, 1) # argmax
+ correct = (prediction == label).sum().item()
+ self.correct += correct
+ self.total += label.size(0)
+ self.labels.append(label.squeeze().cpu().numpy())
+ self.probs.append(prob.squeeze().cpu().numpy())
+
+ def get_metrics(self):
+ y_pred = np.concatenate(self.probs)
+ y_true = np.concatenate(self.labels)
+ # auc
+ fpr, tpr, thresholds = metrics.roc_curve(y_true,y_pred,pos_label=1)
+ auc = metrics.auc(fpr, tpr)
+ # eer
+ fnr = 1 - tpr
+ eer = fpr[np.nanargmin(np.absolute((fnr - fpr)))]
+ # ap
+ ap = metrics.average_precision_score(y_true,y_pred)
+ # acc
+ acc = self.correct / self.total
+ return {'acc':acc, 'auc':auc, 'eer':eer, 'ap':ap}
+
+ def clear(self):
+ self.probs.clear()
+ self.labels.clear()
+ self.correct = 0
+ self.total = 0
+
+
+# only used to record a series of scalar value
+class Recorder:
+ def __init__(self):
+ self.sum = 0
+ self.num = 0
+ def update(self, item, num=1):
+ if item is not None:
+ self.sum += item * num
+ self.num += num
+ def average(self):
+ if self.num == 0:
+ return None
+ return self.sum/self.num
+ def clear(self):
+ self.sum = 0
+ self.num = 0
diff --git a/clean/image/effort/DeepfakeBench/training/metrics/registry.py b/clean/image/effort/DeepfakeBench/training/metrics/registry.py
new file mode 100644
index 0000000000000000000000000000000000000000..86e256c18d0ad522de79149a154f676fd0bdb414
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/metrics/registry.py
@@ -0,0 +1,20 @@
+class Registry(object):
+ def __init__(self):
+ self.data = {}
+
+ def register_module(self, module_name=None):
+ def _register(cls):
+ name = module_name
+ if module_name is None:
+ name = cls.__name__
+ self.data[name] = cls
+ return cls
+ return _register
+
+ def __getitem__(self, key):
+ return self.data[key]
+
+BACKBONE = Registry()
+DETECTOR = Registry()
+TRAINER = Registry()
+LOSSFUNC = Registry()
diff --git a/clean/image/effort/DeepfakeBench/training/metrics/utils.py b/clean/image/effort/DeepfakeBench/training/metrics/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..55fe8665d6883fdd6b043bbc8366d65b19441a47
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/metrics/utils.py
@@ -0,0 +1,176 @@
+from sklearn import metrics
+import numpy as np
+
+
+def parse_metric_for_print(metric_dict):
+ if metric_dict is None:
+ return "\n"
+ str = "\n"
+ str += "================================ Each dataset best metric ================================ \n"
+ for key, value in metric_dict.items():
+ if key != 'avg':
+ str= str+ f"| {key}: "
+ for k,v in value.items():
+ str = str + f" {k}={v} "
+ str= str+ "| \n"
+ else:
+ str += "============================================================================================= \n"
+ str += "================================== Average best metric ====================================== \n"
+ avg_dict = value
+ for avg_key, avg_value in avg_dict.items():
+ if avg_key == 'dataset_dict':
+ for key,value in avg_value.items():
+ str = str + f"| {key}: {value} | \n"
+ else:
+ str = str + f"| avg {avg_key}: {avg_value} | \n"
+ str += "============================================================================================="
+ return str
+
+
+# def get_test_metrics(y_pred, y_true, img_names):
+# def get_video_metrics(image, pred, label):
+# result_dict = {}
+# new_label = []
+# new_pred = []
+# # print(image[0])
+# # print(pred.shape)
+# # print(label.shape)
+# for item in np.transpose(np.stack((image, pred, label)), (1, 0)):
+# # 分割字符串,获取'a'和'b'的值
+# s = item[0]
+# if '\\' in s:
+# parts = s.split('\\')
+# else:
+# parts = s.split('/')
+# a = parts[-2]
+# b = parts[-1]
+
+# # 如果'a'的值还没有在字典中,添加一个新的键值对
+# if a not in result_dict:
+# result_dict[a] = []
+
+# # 将'b'的值添加到'a'的列表中
+# result_dict[a].append(item)
+# image_arr = list(result_dict.values())
+# # 将字典的值转换为一个列表,得到二维数组
+
+# for video in image_arr:
+# pred_sum = 0
+# label_sum = 0
+# leng = 0
+# for frame in video:
+# pred_sum += float(frame[1])
+# label_sum += int(frame[2])
+# leng += 1
+# new_pred.append(pred_sum / leng)
+# new_label.append(int(label_sum / leng))
+# fpr, tpr, thresholds = metrics.roc_curve(new_label, new_pred)
+# v_auc = metrics.auc(fpr, tpr)
+# fnr = 1 - tpr
+# v_eer = fpr[np.nanargmin(np.absolute((fnr - fpr)))]
+# return v_auc, v_eer
+
+
+# y_pred = y_pred.squeeze()
+# # auc
+# fpr, tpr, thresholds = metrics.roc_curve(y_true, y_pred, pos_label=1)
+# auc = metrics.auc(fpr, tpr)
+# # eer
+# fnr = 1 - tpr
+# eer = fpr[np.nanargmin(np.absolute((fnr - fpr)))]
+# # ap
+# ap = metrics.average_precision_score(y_true, y_pred)
+# # acc
+# prediction_class = (y_pred > 0.5).astype(int)
+# correct = (prediction_class == np.clip(y_true, a_min=0, a_max=1)).sum().item()
+# acc = correct / len(prediction_class)
+# if type(img_names[0]) is not list:
+# # calculate video-level auc for the frame-level methods.
+# try:
+# v_auc, _ = get_video_metrics(img_names, y_pred, y_true)
+# except Exception as e:
+# print(e)
+# v_auc=auc
+# else:
+# # video-level methods
+# v_auc=auc
+
+# return {'acc': acc, 'auc': auc, 'eer': eer, 'ap': ap, 'pred': y_pred, 'video_auc': v_auc, 'label': y_true}
+
+
+
+
+
+def get_test_metrics(y_pred, y_true, img_names):
+ def get_video_metrics(image, pred, label):
+ result_dict = {}
+ new_label = []
+ new_pred = []
+ for item in np.transpose(np.stack((image, pred, label)), (1, 0)):
+ s = item[0]
+ if '\\' in s:
+ parts = s.split('\\')
+ else:
+ parts = s.split('/')
+ a = parts[-2]
+ b = parts[-1]
+
+ if a not in result_dict:
+ result_dict[a] = []
+
+ result_dict[a].append(item)
+ image_arr = list(result_dict.values())
+
+ for video in image_arr:
+ pred_sum = 0
+ label_sum = 0
+ leng = 0
+ for frame in video:
+ pred_sum += float(frame[1])
+ label_sum += int(frame[2])
+ leng += 1
+ new_pred.append(pred_sum / leng)
+ new_label.append(int(label_sum / leng))
+
+ fpr, tpr, thresholds = metrics.roc_curve(new_label, new_pred)
+ v_auc = metrics.auc(fpr, tpr)
+ fnr = 1 - tpr
+ v_eer = fpr[np.nanargmin(np.absolute((fnr - fpr)))]
+
+ # Calculate video-level acc
+ prediction_class = (np.array(new_pred) > 0.5).astype(int)
+ correct = (prediction_class == np.array(new_label)).sum().item()
+ v_acc = correct / len(prediction_class)
+
+ return v_auc, v_eer, v_acc
+
+
+ y_pred = y_pred.squeeze()
+ # auc
+ fpr, tpr, thresholds = metrics.roc_curve(y_true, y_pred, pos_label=1)
+ auc = metrics.auc(fpr, tpr)
+ # eer
+ fnr = 1 - tpr
+ eer = fpr[np.nanargmin(np.absolute((fnr - fpr)))]
+ # ap
+ ap = metrics.average_precision_score(y_true, y_pred)
+ # acc
+ prediction_class = (y_pred > 0.5).astype(int)
+ correct = (prediction_class == np.clip(y_true, a_min=0, a_max=1)).sum().item()
+ acc = correct / len(prediction_class)
+ if type(img_names[0]) is not list:
+ # calculate video-level auc for the frame-level methods.
+ try:
+ v_auc, v_eer, v_acc = get_video_metrics(img_names, y_pred, y_true)
+ return {'acc': acc, 'auc': auc, 'eer': eer, 'ap': ap, 'pred': y_pred, 'video_auc': v_auc, 'video_eer': v_eer, 'video_acc': v_acc, 'label': y_true}
+ except Exception as e:
+ print(e)
+ v_auc=auc
+ return {'acc': acc, 'auc': auc, 'eer': eer, 'ap': ap, 'pred': y_pred, 'label': y_true}
+ else:
+ # video-level methods
+ v_auc=auc
+ v_eer=eer
+ v_acc=acc
+ return {'acc': acc, 'auc': auc, 'eer': eer, 'ap': ap, 'pred': y_pred, 'video_auc': v_auc, 'video_eer': v_eer, 'video_acc': v_acc, 'label': y_true}
+
diff --git a/clean/image/effort/DeepfakeBench/training/networks/__init__.py b/clean/image/effort/DeepfakeBench/training/networks/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..9daf1a387c03c3ab553d68dde34fa6fd4b495627
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/networks/__init__.py
@@ -0,0 +1,5 @@
+from utils.registry import BACKBONE
+from .xception import Xception
+from .mesonet import Meso4, MesoInception4
+from .resnet34 import ResNet34
+from .efficientnetb4 import EfficientNetB4
diff --git a/clean/image/effort/DeepfakeBench/training/networks/adaface.py b/clean/image/effort/DeepfakeBench/training/networks/adaface.py
new file mode 100644
index 0000000000000000000000000000000000000000..21730fdac4bed733ba2cde876884f5b46d8ea230
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/networks/adaface.py
@@ -0,0 +1,414 @@
+from collections import namedtuple
+import torch
+import torch.nn as nn
+from torch.nn import Dropout
+from torch.nn import MaxPool2d
+from torch.nn import Sequential
+from torch.nn import Conv2d, Linear
+from torch.nn import BatchNorm1d, BatchNorm2d
+from torch.nn import ReLU, Sigmoid
+from torch.nn import Module
+from torch.nn import PReLU
+import os
+
+def build_model(model_name='ir_50'):
+ if model_name == 'ir_101':
+ return IR_101(input_size=(112,112))
+ elif model_name == 'ir_50':
+ return IR_50(input_size=(112,112))
+ elif model_name == 'ir_se_50':
+ return IR_SE_50(input_size=(112,112))
+ elif model_name == 'ir_34':
+ return IR_34(input_size=(112,112))
+ elif model_name == 'ir_18':
+ return IR_18(input_size=(112,112))
+ else:
+ raise ValueError('not a correct model name', model_name)
+
+def initialize_weights(modules):
+ """ Weight initilize, conv2d and linear is initialized with kaiming_normal
+ """
+ for m in modules:
+ if isinstance(m, nn.Conv2d):
+ nn.init.kaiming_normal_(m.weight,
+ mode='fan_out',
+ nonlinearity='relu')
+ if m.bias is not None:
+ m.bias.data.zero_()
+ elif isinstance(m, nn.BatchNorm2d):
+ m.weight.data.fill_(1)
+ m.bias.data.zero_()
+ elif isinstance(m, nn.Linear):
+ nn.init.kaiming_normal_(m.weight,
+ mode='fan_out',
+ nonlinearity='relu')
+ if m.bias is not None:
+ m.bias.data.zero_()
+
+
+class Flatten(Module):
+ """ Flat tensor
+ """
+ def forward(self, input):
+ return input.view(input.size(0), -1)
+
+
+class LinearBlock(Module):
+ """ Convolution block without no-linear activation layer
+ """
+ def __init__(self, in_c, out_c, kernel=(1, 1), stride=(1, 1), padding=(0, 0), groups=1):
+ super(LinearBlock, self).__init__()
+ self.conv = Conv2d(in_c, out_c, kernel, stride, padding, groups=groups, bias=False)
+ self.bn = BatchNorm2d(out_c)
+
+ def forward(self, x):
+ x = self.conv(x)
+ x = self.bn(x)
+ return x
+
+
+class GNAP(Module):
+ """ Global Norm-Aware Pooling block
+ """
+ def __init__(self, in_c):
+ super(GNAP, self).__init__()
+ self.bn1 = BatchNorm2d(in_c, affine=False)
+ self.pool = nn.AdaptiveAvgPool2d((1, 1))
+ self.bn2 = BatchNorm1d(in_c, affine=False)
+
+ def forward(self, x):
+ x = self.bn1(x)
+ x_norm = torch.norm(x, 2, 1, True)
+ x_norm_mean = torch.mean(x_norm)
+ weight = x_norm_mean / x_norm
+ x = x * weight
+ x = self.pool(x)
+ x = x.view(x.shape[0], -1)
+ feature = self.bn2(x)
+ return feature
+
+
+class GDC(Module):
+ """ Global Depthwise Convolution block
+ """
+ def __init__(self, in_c, embedding_size):
+ super(GDC, self).__init__()
+ self.conv_6_dw = LinearBlock(in_c, in_c,
+ groups=in_c,
+ kernel=(7, 7),
+ stride=(1, 1),
+ padding=(0, 0))
+ self.conv_6_flatten = Flatten()
+ self.linear = Linear(in_c, embedding_size, bias=False)
+ self.bn = BatchNorm1d(embedding_size, affine=False)
+
+ def forward(self, x):
+ x = self.conv_6_dw(x)
+ x = self.conv_6_flatten(x)
+ x = self.linear(x)
+ x = self.bn(x)
+ return x
+
+
+class SEModule(Module):
+ """ SE block
+ """
+ def __init__(self, channels, reduction):
+ super(SEModule, self).__init__()
+ self.avg_pool = nn.AdaptiveAvgPool2d(1)
+ self.fc1 = Conv2d(channels, channels // reduction,
+ kernel_size=1, padding=0, bias=False)
+
+ nn.init.xavier_uniform_(self.fc1.weight.data)
+
+ self.relu = ReLU(inplace=True)
+ self.fc2 = Conv2d(channels // reduction, channels,
+ kernel_size=1, padding=0, bias=False)
+
+ self.sigmoid = Sigmoid()
+
+ def forward(self, x):
+ module_input = x
+ x = self.avg_pool(x)
+ x = self.fc1(x)
+ x = self.relu(x)
+ x = self.fc2(x)
+ x = self.sigmoid(x)
+
+ return module_input * x
+
+
+
+class BasicBlockIR(Module):
+ """ BasicBlock for IRNet
+ """
+ def __init__(self, in_channel, depth, stride):
+ super(BasicBlockIR, self).__init__()
+ if in_channel == depth:
+ self.shortcut_layer = MaxPool2d(1, stride)
+ else:
+ self.shortcut_layer = Sequential(
+ Conv2d(in_channel, depth, (1, 1), stride, bias=False),
+ BatchNorm2d(depth))
+ self.res_layer = Sequential(
+ BatchNorm2d(in_channel),
+ Conv2d(in_channel, depth, (3, 3), (1, 1), 1, bias=False),
+ BatchNorm2d(depth),
+ PReLU(depth),
+ Conv2d(depth, depth, (3, 3), stride, 1, bias=False),
+ BatchNorm2d(depth))
+
+ def forward(self, x):
+ shortcut = self.shortcut_layer(x)
+ res = self.res_layer(x)
+
+ return res + shortcut
+
+
+class BottleneckIR(Module):
+ """ BasicBlock with bottleneck for IRNet
+ """
+ def __init__(self, in_channel, depth, stride):
+ super(BottleneckIR, self).__init__()
+ reduction_channel = depth // 4
+ if in_channel == depth:
+ self.shortcut_layer = MaxPool2d(1, stride)
+ else:
+ self.shortcut_layer = Sequential(
+ Conv2d(in_channel, depth, (1, 1), stride, bias=False),
+ BatchNorm2d(depth))
+ self.res_layer = Sequential(
+ BatchNorm2d(in_channel),
+ Conv2d(in_channel, reduction_channel, (1, 1), (1, 1), 0, bias=False),
+ BatchNorm2d(reduction_channel),
+ PReLU(reduction_channel),
+ Conv2d(reduction_channel, reduction_channel, (3, 3), (1, 1), 1, bias=False),
+ BatchNorm2d(reduction_channel),
+ PReLU(reduction_channel),
+ Conv2d(reduction_channel, depth, (1, 1), stride, 0, bias=False),
+ BatchNorm2d(depth))
+
+ def forward(self, x):
+ shortcut = self.shortcut_layer(x)
+ res = self.res_layer(x)
+
+ return res + shortcut
+
+
+class BasicBlockIRSE(BasicBlockIR):
+ def __init__(self, in_channel, depth, stride):
+ super(BasicBlockIRSE, self).__init__(in_channel, depth, stride)
+ self.res_layer.add_module("se_block", SEModule(depth, 16))
+
+
+class BottleneckIRSE(BottleneckIR):
+ def __init__(self, in_channel, depth, stride):
+ super(BottleneckIRSE, self).__init__(in_channel, depth, stride)
+ self.res_layer.add_module("se_block", SEModule(depth, 16))
+
+
+class Bottleneck(namedtuple('Block', ['in_channel', 'depth', 'stride'])):
+ '''A named tuple describing a ResNet block.'''
+
+
+def get_block(in_channel, depth, num_units, stride=2):
+
+ return [Bottleneck(in_channel, depth, stride)] +\
+ [Bottleneck(depth, depth, 1) for i in range(num_units - 1)]
+
+
+def get_blocks(num_layers):
+ if num_layers == 18:
+ blocks = [
+ get_block(in_channel=64, depth=64, num_units=2),
+ get_block(in_channel=64, depth=128, num_units=2),
+ get_block(in_channel=128, depth=256, num_units=2),
+ get_block(in_channel=256, depth=512, num_units=2)
+ ]
+ elif num_layers == 34:
+ blocks = [
+ get_block(in_channel=64, depth=64, num_units=3),
+ get_block(in_channel=64, depth=128, num_units=4),
+ get_block(in_channel=128, depth=256, num_units=6),
+ get_block(in_channel=256, depth=512, num_units=3)
+ ]
+ elif num_layers == 50:
+ blocks = [
+ get_block(in_channel=64, depth=64, num_units=3),
+ get_block(in_channel=64, depth=128, num_units=4),
+ get_block(in_channel=128, depth=256, num_units=14),
+ get_block(in_channel=256, depth=512, num_units=3)
+ ]
+ elif num_layers == 100:
+ blocks = [
+ get_block(in_channel=64, depth=64, num_units=3),
+ get_block(in_channel=64, depth=128, num_units=13),
+ get_block(in_channel=128, depth=256, num_units=30),
+ get_block(in_channel=256, depth=512, num_units=3)
+ ]
+ elif num_layers == 152:
+ blocks = [
+ get_block(in_channel=64, depth=256, num_units=3),
+ get_block(in_channel=256, depth=512, num_units=8),
+ get_block(in_channel=512, depth=1024, num_units=36),
+ get_block(in_channel=1024, depth=2048, num_units=3)
+ ]
+ elif num_layers == 200:
+ blocks = [
+ get_block(in_channel=64, depth=256, num_units=3),
+ get_block(in_channel=256, depth=512, num_units=24),
+ get_block(in_channel=512, depth=1024, num_units=36),
+ get_block(in_channel=1024, depth=2048, num_units=3)
+ ]
+
+ return blocks
+
+
+class Backbone(Module):
+ def __init__(self, input_size, num_layers, mode='ir'):
+ """ Args:
+ input_size: input_size of backbone
+ num_layers: num_layers of backbone
+ mode: support ir or irse
+ """
+ super(Backbone, self).__init__()
+ assert input_size[0] in [112, 224], \
+ "input_size should be [112, 112] or [224, 224]"
+ assert num_layers in [18, 34, 50, 100, 152, 200], \
+ "num_layers should be 18, 34, 50, 100 or 152"
+ assert mode in ['ir', 'ir_se'], \
+ "mode should be ir or ir_se"
+ self.input_layer = Sequential(Conv2d(3, 64, (3, 3), 1, 1, bias=False),
+ BatchNorm2d(64), PReLU(64))
+ blocks = get_blocks(num_layers)
+ if num_layers <= 100:
+ if mode == 'ir':
+ unit_module = BasicBlockIR
+ elif mode == 'ir_se':
+ unit_module = BasicBlockIRSE
+ output_channel = 512
+ else:
+ if mode == 'ir':
+ unit_module = BottleneckIR
+ elif mode == 'ir_se':
+ unit_module = BottleneckIRSE
+ output_channel = 2048
+
+ if input_size[0] == 112:
+ self.output_layer = Sequential(BatchNorm2d(output_channel),
+ Dropout(0.4), Flatten(),
+ Linear(output_channel * 7 * 7, 512),
+ BatchNorm1d(512, affine=False))
+ else:
+ self.output_layer = Sequential(
+ BatchNorm2d(output_channel), Dropout(0.4), Flatten(),
+ Linear(output_channel * 14 * 14, 512),
+ BatchNorm1d(512, affine=False))
+
+ modules = []
+ for block in blocks:
+ for bottleneck in block:
+ modules.append(
+ unit_module(bottleneck.in_channel, bottleneck.depth,
+ bottleneck.stride))
+ self.body = Sequential(*modules)
+
+ initialize_weights(self.modules())
+
+
+ def forward(self, x):
+
+ # current code only supports one extra image
+ # it comes with a extra dimension for number of extra image. We will just squeeze it out for now
+ x = self.input_layer(x)
+
+ for idx, module in enumerate(self.body):
+ x = module(x)
+
+ x = self.output_layer(x)
+ norm = torch.norm(x, 2, 1, True)
+ output = torch.div(x, norm)
+
+ return output, norm
+
+
+
+def IR_18(input_size):
+ """ Constructs a ir-18 model.
+ """
+ model = Backbone(input_size, 18, 'ir')
+
+ return model
+
+
+def IR_34(input_size):
+ """ Constructs a ir-34 model.
+ """
+ model = Backbone(input_size, 34, 'ir')
+
+ return model
+
+
+def IR_50(input_size):
+ """ Constructs a ir-50 model.
+ """
+ model = Backbone(input_size, 50, 'ir')
+
+ return model
+
+
+def IR_101(input_size):
+ """ Constructs a ir-101 model.
+ """
+ model = Backbone(input_size, 100, 'ir')
+
+ return model
+
+
+def IR_152(input_size):
+ """ Constructs a ir-152 model.
+ """
+ model = Backbone(input_size, 152, 'ir')
+
+ return model
+
+
+def IR_200(input_size):
+ """ Constructs a ir-200 model.
+ """
+ model = Backbone(input_size, 200, 'ir')
+
+ return model
+
+
+def IR_SE_50(input_size):
+ """ Constructs a ir_se-50 model.
+ """
+ model = Backbone(input_size, 50, 'ir_se')
+
+ return model
+
+
+def IR_SE_101(input_size):
+ """ Constructs a ir_se-101 model.
+ """
+ model = Backbone(input_size, 100, 'ir_se')
+
+ return model
+
+
+def IR_SE_152(input_size):
+ """ Constructs a ir_se-152 model.
+ """
+ model = Backbone(input_size, 152, 'ir_se')
+
+ return model
+
+
+def IR_SE_200(input_size):
+ """ Constructs a ir_se-200 model.
+ """
+ model = Backbone(input_size, 200, 'ir_se')
+
+ return model
+
diff --git a/clean/image/effort/DeepfakeBench/training/networks/base_backbone.py b/clean/image/effort/DeepfakeBench/training/networks/base_backbone.py
new file mode 100644
index 0000000000000000000000000000000000000000..8cbb14439c4c8da93d12edd0f0af442d8f460698
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/networks/base_backbone.py
@@ -0,0 +1,32 @@
+import abc
+import torch
+from typing import Union
+
+class AbstractBackbone(abc.ABC):
+ """
+ All backbones for detectors should subclass this class.
+ """
+ def __init__(self, config, load_param: Union[bool, str] = False):
+ """
+ config: (dict)
+ configurations for the model
+ load_param: (False | True | Path(str))
+ False Do not read; True Read the default path; Path Read the required path
+ """
+ pass
+
+ @abc.abstractmethod
+ def features(self, data_dict: dict) -> torch.tensor:
+ """
+ """
+
+ @abc.abstractmethod
+ def classifier(self, features: torch.tensor) -> torch.tensor:
+ """
+ """
+
+ def init_weights(self, pretrained_path: Union[bool, str]):
+ """
+ This method can be optionally implemented by subclasses.
+ """
+ pass
\ No newline at end of file
diff --git a/clean/image/effort/DeepfakeBench/training/networks/cls_hrnet.py b/clean/image/effort/DeepfakeBench/training/networks/cls_hrnet.py
new file mode 100644
index 0000000000000000000000000000000000000000..2c04a0e05817e7a3d91dd2af895aae7c5dc67403
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/networks/cls_hrnet.py
@@ -0,0 +1,569 @@
+'''
+# author: Zhiyuan Yan
+# email: zhiyuanyan@link.cuhk.edu.cn
+# date: 2023-0706
+
+# ------------------------------------------------------------------------------
+# Copyright (c) Microsoft
+# Licensed under the MIT License.
+# Written by Bin Xiao (Bin.Xiao@microsoft.com)
+# Modified by Ke Sun (sunk@mail.ustc.edu.cn)
+# ------------------------------------------------------------------------------
+
+The code is mainly modified from the below link:
+https://github.com/HRNet/HRNet-Image-Classification/tree/master
+'''
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import os
+import logging
+import functools
+
+import numpy as np
+from typing import Union
+
+import torch
+import torch.nn as nn
+import torch._utils
+import torch.nn.functional as F
+
+BN_MOMENTUM = 0.1
+logger = logging.getLogger(__name__)
+
+
+def conv3x3(in_planes, out_planes, stride=1):
+ """3x3 convolution with padding"""
+ return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,
+ padding=1, bias=False)
+
+
+class BasicBlock(nn.Module):
+ expansion = 1
+
+ def __init__(self, inplanes, planes, stride=1, downsample=None):
+ super(BasicBlock, self).__init__()
+ self.conv1 = conv3x3(inplanes, planes, stride)
+ self.bn1 = nn.BatchNorm2d(planes, momentum=BN_MOMENTUM)
+ self.relu = nn.ReLU(inplace=True)
+ self.conv2 = conv3x3(planes, planes)
+ self.bn2 = nn.BatchNorm2d(planes, momentum=BN_MOMENTUM)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x):
+ residual = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+
+ if self.downsample is not None:
+ residual = self.downsample(x)
+
+ out += residual
+ out = self.relu(out)
+
+ return out
+
+
+class Bottleneck(nn.Module):
+ expansion = 4
+
+ def __init__(self, inplanes, planes, stride=1, downsample=None):
+ super(Bottleneck, self).__init__()
+ self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False)
+ self.bn1 = nn.BatchNorm2d(planes, momentum=BN_MOMENTUM)
+ self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride,
+ padding=1, bias=False)
+ self.bn2 = nn.BatchNorm2d(planes, momentum=BN_MOMENTUM)
+ self.conv3 = nn.Conv2d(planes, planes * self.expansion, kernel_size=1,
+ bias=False)
+ self.bn3 = nn.BatchNorm2d(planes * self.expansion,
+ momentum=BN_MOMENTUM)
+ self.relu = nn.ReLU(inplace=True)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x):
+ residual = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+ out = self.relu(out)
+
+ out = self.conv3(out)
+ out = self.bn3(out)
+
+ if self.downsample is not None:
+ residual = self.downsample(x)
+
+ out += residual
+ out = self.relu(out)
+
+ return out
+
+
+class HighResolutionModule(nn.Module):
+ def __init__(self, num_branches, blocks, num_blocks, num_inchannels,
+ num_channels, fuse_method, multi_scale_output=True):
+ super(HighResolutionModule, self).__init__()
+ self._check_branches(
+ num_branches, blocks, num_blocks, num_inchannels, num_channels)
+
+ self.num_inchannels = num_inchannels
+ self.fuse_method = fuse_method
+ self.num_branches = num_branches
+
+ self.multi_scale_output = multi_scale_output
+
+ self.branches = self._make_branches(
+ num_branches, blocks, num_blocks, num_channels)
+ self.fuse_layers = self._make_fuse_layers()
+ self.relu = nn.ReLU(False)
+
+ def _check_branches(self, num_branches, blocks, num_blocks,
+ num_inchannels, num_channels):
+ if num_branches != len(num_blocks):
+ error_msg = 'NUM_BRANCHES({}) <> NUM_BLOCKS({})'.format(
+ num_branches, len(num_blocks))
+ logger.error(error_msg)
+ raise ValueError(error_msg)
+
+ if num_branches != len(num_channels):
+ error_msg = 'NUM_BRANCHES({}) <> NUM_CHANNELS({})'.format(
+ num_branches, len(num_channels))
+ logger.error(error_msg)
+ raise ValueError(error_msg)
+
+ if num_branches != len(num_inchannels):
+ error_msg = 'NUM_BRANCHES({}) <> NUM_INCHANNELS({})'.format(
+ num_branches, len(num_inchannels))
+ logger.error(error_msg)
+ raise ValueError(error_msg)
+
+ def _make_one_branch(self, branch_index, block, num_blocks, num_channels,
+ stride=1):
+ downsample = None
+ if stride != 1 or \
+ self.num_inchannels[branch_index] != num_channels[branch_index] * block.expansion:
+ downsample = nn.Sequential(
+ nn.Conv2d(self.num_inchannels[branch_index],
+ num_channels[branch_index] * block.expansion,
+ kernel_size=1, stride=stride, bias=False),
+ nn.BatchNorm2d(num_channels[branch_index] * block.expansion,
+ momentum=BN_MOMENTUM),
+ )
+
+ layers = []
+ layers.append(block(self.num_inchannels[branch_index],
+ num_channels[branch_index], stride, downsample))
+ self.num_inchannels[branch_index] = \
+ num_channels[branch_index] * block.expansion
+ for i in range(1, num_blocks[branch_index]):
+ layers.append(block(self.num_inchannels[branch_index],
+ num_channels[branch_index]))
+
+ return nn.Sequential(*layers)
+
+ def _make_branches(self, num_branches, block, num_blocks, num_channels):
+ branches = []
+
+ for i in range(num_branches):
+ branches.append(
+ self._make_one_branch(i, block, num_blocks, num_channels))
+
+ return nn.ModuleList(branches)
+
+ def _make_fuse_layers(self):
+ if self.num_branches == 1:
+ return None
+
+ num_branches = self.num_branches
+ num_inchannels = self.num_inchannels
+ fuse_layers = []
+ for i in range(num_branches if self.multi_scale_output else 1):
+ fuse_layer = []
+ for j in range(num_branches):
+ if j > i:
+ fuse_layer.append(nn.Sequential(
+ nn.Conv2d(num_inchannels[j],
+ num_inchannels[i],
+ 1,
+ 1,
+ 0,
+ bias=False),
+ nn.BatchNorm2d(num_inchannels[i],
+ momentum=BN_MOMENTUM),
+ nn.Upsample(scale_factor=2**(j-i), mode='nearest')))
+ elif j == i:
+ fuse_layer.append(None)
+ else:
+ conv3x3s = []
+ for k in range(i-j):
+ if k == i - j - 1:
+ num_outchannels_conv3x3 = num_inchannels[i]
+ conv3x3s.append(nn.Sequential(
+ nn.Conv2d(num_inchannels[j],
+ num_outchannels_conv3x3,
+ 3, 2, 1, bias=False),
+ nn.BatchNorm2d(num_outchannels_conv3x3,
+ momentum=BN_MOMENTUM)))
+ else:
+ num_outchannels_conv3x3 = num_inchannels[j]
+ conv3x3s.append(nn.Sequential(
+ nn.Conv2d(num_inchannels[j],
+ num_outchannels_conv3x3,
+ 3, 2, 1, bias=False),
+ nn.BatchNorm2d(num_outchannels_conv3x3,
+ momentum=BN_MOMENTUM),
+ nn.ReLU(False)))
+ fuse_layer.append(nn.Sequential(*conv3x3s))
+ fuse_layers.append(nn.ModuleList(fuse_layer))
+
+ return nn.ModuleList(fuse_layers)
+
+ def get_num_inchannels(self):
+ return self.num_inchannels
+
+ def forward(self, x):
+ if self.num_branches == 1:
+ return [self.branches[0](x[0])]
+
+ for i in range(self.num_branches):
+ x[i] = self.branches[i](x[i])
+
+ x_fuse = []
+ for i in range(len(self.fuse_layers)):
+ y = x[0] if i == 0 else self.fuse_layers[i][0](x[0])
+ for j in range(1, self.num_branches):
+ if i == j:
+ y = y + x[j]
+ else:
+ y = y + self.fuse_layers[i][j](x[j])
+ x_fuse.append(self.relu(y))
+
+ return x_fuse
+
+
+blocks_dict = {
+ 'BASIC': BasicBlock,
+ 'BOTTLENECK': Bottleneck
+}
+
+
+class HighResolutionNet(nn.Module):
+
+ def __init__(self, cfg):
+ super(HighResolutionNet, self).__init__()
+
+ self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=2, padding=1,
+ bias=False)
+ self.bn1 = nn.BatchNorm2d(64, momentum=BN_MOMENTUM)
+ self.conv2 = nn.Conv2d(64, 64, kernel_size=3, stride=2, padding=1,
+ bias=False)
+ self.bn2 = nn.BatchNorm2d(64, momentum=BN_MOMENTUM)
+ self.relu = nn.ReLU(inplace=True)
+
+ self.stage1_cfg = cfg['MODEL']['EXTRA']['STAGE1']
+ num_channels = self.stage1_cfg['NUM_CHANNELS'][0]
+ block = blocks_dict[self.stage1_cfg['BLOCK']]
+ num_blocks = self.stage1_cfg['NUM_BLOCKS'][0]
+ self.layer1 = self._make_layer(block, 64, num_channels, num_blocks)
+ stage1_out_channel = block.expansion*num_channels
+
+ self.stage2_cfg = cfg['MODEL']['EXTRA']['STAGE2']
+ num_channels = self.stage2_cfg['NUM_CHANNELS']
+ block = blocks_dict[self.stage2_cfg['BLOCK']]
+ num_channels = [
+ num_channels[i] * block.expansion for i in range(len(num_channels))]
+ self.transition1 = self._make_transition_layer(
+ [stage1_out_channel], num_channels)
+ self.stage2, pre_stage_channels = self._make_stage(
+ self.stage2_cfg, num_channels)
+
+ self.stage3_cfg = cfg['MODEL']['EXTRA']['STAGE3']
+ num_channels = self.stage3_cfg['NUM_CHANNELS']
+ block = blocks_dict[self.stage3_cfg['BLOCK']]
+ num_channels = [
+ num_channels[i] * block.expansion for i in range(len(num_channels))]
+ self.transition2 = self._make_transition_layer(
+ pre_stage_channels, num_channels)
+ self.stage3, pre_stage_channels = self._make_stage(
+ self.stage3_cfg, num_channels)
+
+ self.stage4_cfg = cfg['MODEL']['EXTRA']['STAGE4']
+ num_channels = self.stage4_cfg['NUM_CHANNELS']
+ block = blocks_dict[self.stage4_cfg['BLOCK']]
+ num_channels = [
+ num_channels[i] * block.expansion for i in range(len(num_channels))]
+ self.transition3 = self._make_transition_layer(
+ pre_stage_channels, num_channels)
+ self.stage4, pre_stage_channels = self._make_stage(
+ self.stage4_cfg, num_channels, multi_scale_output=True)
+
+ # Classification Head
+ self.incre_modules, self.downsamp_modules, \
+ self.final_layer = self._make_head(pre_stage_channels)
+
+ self.fc = nn.Linear(2048, 1000)
+
+
+ def _make_head(self, pre_stage_channels):
+ head_block = Bottleneck
+ head_channels = [32, 64, 128, 256]
+
+ # Increasing the #channels on each resolution
+ # from C, 2C, 4C, 8C to 128, 256, 512, 1024
+ incre_modules = []
+ for i, channels in enumerate(pre_stage_channels):
+ incre_module = self._make_layer(head_block,
+ channels,
+ head_channels[i],
+ 1,
+ stride=1)
+ incre_modules.append(incre_module)
+ incre_modules = nn.ModuleList(incre_modules)
+
+ # downsampling modules
+ downsamp_modules = []
+ for i in range(len(pre_stage_channels)-1):
+ in_channels = head_channels[i] * head_block.expansion
+ out_channels = head_channels[i+1] * head_block.expansion
+
+ downsamp_module = nn.Sequential(
+ nn.Conv2d(in_channels=in_channels,
+ out_channels=out_channels,
+ kernel_size=3,
+ stride=2,
+ padding=1),
+ nn.BatchNorm2d(out_channels, momentum=BN_MOMENTUM),
+ nn.ReLU(inplace=True)
+ )
+
+ downsamp_modules.append(downsamp_module)
+ downsamp_modules = nn.ModuleList(downsamp_modules)
+
+ final_layer = nn.Sequential(
+ nn.Conv2d(
+ in_channels=head_channels[3] * head_block.expansion,
+ out_channels=2048,
+ kernel_size=1,
+ stride=1,
+ padding=0
+ ),
+ nn.BatchNorm2d(2048, momentum=BN_MOMENTUM),
+ nn.ReLU(inplace=True)
+ )
+
+ return incre_modules, downsamp_modules, final_layer
+
+ def _make_transition_layer(
+ self, num_channels_pre_layer, num_channels_cur_layer):
+ num_branches_cur = len(num_channels_cur_layer)
+ num_branches_pre = len(num_channels_pre_layer)
+
+ transition_layers = []
+ for i in range(num_branches_cur):
+ if i < num_branches_pre:
+ if num_channels_cur_layer[i] != num_channels_pre_layer[i]:
+ transition_layers.append(nn.Sequential(
+ nn.Conv2d(num_channels_pre_layer[i],
+ num_channels_cur_layer[i],
+ 3,
+ 1,
+ 1,
+ bias=False),
+ nn.BatchNorm2d(
+ num_channels_cur_layer[i], momentum=BN_MOMENTUM),
+ nn.ReLU(inplace=True)))
+ else:
+ transition_layers.append(None)
+ else:
+ conv3x3s = []
+ for j in range(i+1-num_branches_pre):
+ inchannels = num_channels_pre_layer[-1]
+ outchannels = num_channels_cur_layer[i] \
+ if j == i-num_branches_pre else inchannels
+ conv3x3s.append(nn.Sequential(
+ nn.Conv2d(
+ inchannels, outchannels, 3, 2, 1, bias=False),
+ nn.BatchNorm2d(outchannels, momentum=BN_MOMENTUM),
+ nn.ReLU(inplace=True)))
+ transition_layers.append(nn.Sequential(*conv3x3s))
+
+ return nn.ModuleList(transition_layers)
+
+ def _make_layer(self, block, inplanes, planes, blocks, stride=1):
+ downsample = None
+ if stride != 1 or inplanes != planes * block.expansion:
+ downsample = nn.Sequential(
+ nn.Conv2d(inplanes, planes * block.expansion,
+ kernel_size=1, stride=stride, bias=False),
+ nn.BatchNorm2d(planes * block.expansion, momentum=BN_MOMENTUM),
+ )
+
+ layers = []
+ layers.append(block(inplanes, planes, stride, downsample))
+ inplanes = planes * block.expansion
+ for i in range(1, blocks):
+ layers.append(block(inplanes, planes))
+
+ return nn.Sequential(*layers)
+
+ def _make_stage(self, layer_config, num_inchannels,
+ multi_scale_output=True):
+ num_modules = layer_config['NUM_MODULES']
+ num_branches = layer_config['NUM_BRANCHES']
+ num_blocks = layer_config['NUM_BLOCKS']
+ num_channels = layer_config['NUM_CHANNELS']
+ block = blocks_dict[layer_config['BLOCK']]
+ fuse_method = layer_config['FUSE_METHOD']
+
+ modules = []
+ for i in range(num_modules):
+ # multi_scale_output is only used last module
+ if not multi_scale_output and i == num_modules - 1:
+ reset_multi_scale_output = False
+ else:
+ reset_multi_scale_output = True
+
+ modules.append(
+ HighResolutionModule(num_branches,
+ block,
+ num_blocks,
+ num_inchannels,
+ num_channels,
+ fuse_method,
+ reset_multi_scale_output)
+ )
+ num_inchannels = modules[-1].get_num_inchannels()
+
+ return nn.Sequential(*modules), num_inchannels
+
+ def forward(self, x):
+ x = self.conv1(x)
+ x = self.bn1(x)
+ x = self.relu(x)
+ x = self.conv2(x)
+ x = self.bn2(x)
+ x = self.relu(x)
+ x = self.layer1(x)
+
+ x_list = []
+ for i in range(self.stage2_cfg['NUM_BRANCHES']):
+ if self.transition1[i] is not None:
+ x_list.append(self.transition1[i](x))
+ else:
+ x_list.append(x)
+ y_list = self.stage2(x_list)
+
+ x_list = []
+ for i in range(self.stage3_cfg['NUM_BRANCHES']):
+ if self.transition2[i] is not None:
+ x_list.append(self.transition2[i](y_list[-1]))
+ else:
+ x_list.append(y_list[i])
+ y_list = self.stage3(x_list)
+
+ x_list = []
+ for i in range(self.stage4_cfg['NUM_BRANCHES']):
+ if self.transition3[i] is not None:
+ x_list.append(self.transition3[i](y_list[-1]))
+ else:
+ x_list.append(y_list[i])
+ y_list = self.stage4(x_list)
+
+ # Classification Head
+ y = self.incre_modules[0](y_list[0])
+ for i in range(len(self.downsamp_modules)):
+ y = self.incre_modules[i+1](y_list[i+1]) + \
+ self.downsamp_modules[i](y)
+
+ y = self.final_layer(y)
+
+ if torch._C._get_tracing_state():
+ y = y.flatten(start_dim=2).mean(dim=2)
+ else:
+ y = F.avg_pool2d(y, kernel_size=y.size()
+ [2:]).view(y.size(0), -1)
+
+ y = self.fc(y)
+
+ return y
+
+ def features(self, x):
+ x = self.conv1(x)
+ x = self.bn1(x)
+ x = self.relu(x)
+ x = self.conv2(x)
+ x = self.bn2(x)
+ x = self.relu(x)
+ x = self.layer1(x)
+
+ x_list = []
+ for i in range(self.stage2_cfg['NUM_BRANCHES']):
+ if self.transition1[i] is not None:
+ x_list.append(self.transition1[i](x))
+ else:
+ x_list.append(x)
+ y_list = self.stage2(x_list)
+
+ x_list = []
+ for i in range(self.stage3_cfg['NUM_BRANCHES']):
+ if self.transition2[i] is not None:
+ x_list.append(self.transition2[i](y_list[-1]))
+ else:
+ x_list.append(y_list[i])
+ y_list = self.stage3(x_list)
+
+ x_list = []
+ for i in range(self.stage4_cfg['NUM_BRANCHES']):
+ if self.transition3[i] is not None:
+ x_list.append(self.transition3[i](y_list[-1]))
+ else:
+ x_list.append(y_list[i])
+ y_list = self.stage4(x_list)
+
+ # Upsampling
+ x0, x1, x2, x3 = y_list
+ x0_h, x0_w = x0.size(2), x0.size(3)
+ x1 = F.upsample(x1, size=(x0_h, x0_w), mode='bilinear')
+ x2 = F.upsample(x2, size=(x0_h, x0_w), mode='bilinear')
+ x3 = F.upsample(x3, size=(x0_h, x0_w), mode='bilinear')
+
+ x_out = torch.cat([x0, x1, x2, x3], 1)
+
+ #print(x_out.size())
+
+ return x_out
+
+ def classifier(self, x):
+ # Classification Head
+ y = self.incre_modules[0](x[0])
+ for i in range(len(self.downsamp_modules)):
+ y = self.incre_modules[i+1](x[i+1]) + \
+ self.downsamp_modules[i](y)
+
+ y = self.final_layer(y)
+
+ if torch._C._get_tracing_state():
+ y = y.flatten(start_dim=2).mean(dim=2)
+ else:
+ y = F.avg_pool2d(y, kernel_size=y.size()
+ [2:]).view(y.size(0), -1)
+
+ y = self.fc(y)
+
+def get_cls_net(config, **kwargs):
+ model = HighResolutionNet(config, **kwargs)
+ return model
diff --git a/clean/image/effort/DeepfakeBench/training/networks/efficientnetb4.py b/clean/image/effort/DeepfakeBench/training/networks/efficientnetb4.py
new file mode 100644
index 0000000000000000000000000000000000000000..e39fa07896903006aa5782d5e26109ef3704cc2e
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/networks/efficientnetb4.py
@@ -0,0 +1,79 @@
+'''
+# author: Zhiyuan Yan
+# email: zhiyuanyan@link.cuhk.edu.cn
+# date: 2023-0706
+
+The code is for EfficientNetB4 backbone.
+'''
+
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+from typing import Union
+from efficientnet_pytorch import EfficientNet
+from utils.registry import BACKBONE
+
+
+@BACKBONE.register_module(module_name="efficientnetb4")
+class EfficientNetB4(nn.Module):
+ def __init__(self, efficientnetb4_config):
+ super(EfficientNetB4, self).__init__()
+ """ Constructor
+ Args:
+ efficientnetb4_config: configuration file with the dict format
+ """
+ self.num_classes = efficientnetb4_config["num_classes"]
+ inc = efficientnetb4_config["inc"]
+ self.dropout = efficientnetb4_config["dropout"]
+ self.mode = efficientnetb4_config["mode"]
+
+ # Load the EfficientNet-B4 model without pre-trained weights
+ self.efficientnet = EfficientNet.from_pretrained('efficientnet-b4') # FIXME: load the pretrained weights from online
+ # self.efficientnet = EfficientNet.from_name('efficientnet-b4')
+
+ # Modify the first convolutional layer to accept input tensors with 'inc' channels
+ self.efficientnet._conv_stem = nn.Conv2d(inc, 48, kernel_size=3, stride=2, bias=False)
+
+ # Remove the last layer (the classifier) from the EfficientNet-B4 model
+ self.efficientnet._fc = nn.Identity()
+
+ if self.dropout:
+ # Add dropout layer if specified
+ self.dropout_layer = nn.Dropout(p=self.dropout)
+
+ # Initialize the last_layer layer
+ self.last_layer = nn.Linear(1792, self.num_classes)
+
+ if self.mode == 'adjust_channel':
+ self.adjust_channel = nn.Sequential(
+ nn.Conv2d(1792, 512, 1, 1),
+ nn.BatchNorm2d(512),
+ nn.ReLU(inplace=True),
+ )
+
+ def features(self, x):
+ # Extract features from the EfficientNet-B4 model
+ x = self.efficientnet.extract_features(x)
+ if self.mode == 'adjust_channel':
+ x = self.adjust_channel(x)
+ return x
+
+ def classifier(self, x):
+ x = F.adaptive_avg_pool2d(x, (1, 1))
+ x = x.view(x.size(0), -1)
+
+ # Apply dropout if specified
+ if self.dropout:
+ x = self.dropout_layer(x)
+
+ # Apply last_layer layer
+ x = self.last_layer(x)
+ return x
+
+ def forward(self, x):
+ # Extract features and apply classifier layer
+ x = self.features(x)
+ x = F.adaptive_avg_pool2d(x, (1, 1))
+ x = x.view(x.size(0), -1)
+ x = self.classifier(x)
+ return x
diff --git a/clean/image/effort/DeepfakeBench/training/networks/iresnet.py b/clean/image/effort/DeepfakeBench/training/networks/iresnet.py
new file mode 100644
index 0000000000000000000000000000000000000000..12a454cb9acc227b8968806cf3c47c4145e6304b
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/networks/iresnet.py
@@ -0,0 +1,191 @@
+import torch
+from torch import nn
+import torch.nn.functional as F
+
+__all__ = ['iresnet18', 'iresnet34', 'iresnet50', 'iresnet100', 'iresnet200']
+
+def set_requires_grad(model, val):
+ for p in model.parameters():
+ p.requires_grad = val
+
+def conv3x3(in_planes, out_planes, stride=1, groups=1, dilation=1):
+ """3x3 convolution with padding"""
+ return nn.Conv2d(in_planes,
+ out_planes,
+ kernel_size=3,
+ stride=stride,
+ padding=dilation,
+ groups=groups,
+ bias=False,
+ dilation=dilation)
+
+
+def conv1x1(in_planes, out_planes, stride=1):
+ """1x1 convolution"""
+ return nn.Conv2d(in_planes,
+ out_planes,
+ kernel_size=1,
+ stride=stride,
+ bias=False)
+
+
+class IBasicBlock(nn.Module):
+ expansion = 1
+ def __init__(self, inplanes, planes, stride=1, downsample=None,
+ groups=1, base_width=64, dilation=1):
+ super(IBasicBlock, self).__init__()
+ if groups != 1 or base_width != 64:
+ raise ValueError('BasicBlock only supports groups=1 and base_width=64')
+ if dilation > 1:
+ raise NotImplementedError("Dilation > 1 not supported in BasicBlock")
+ self.bn1 = nn.BatchNorm2d(inplanes, eps=1e-05,)
+ self.conv1 = conv3x3(inplanes, planes)
+ self.bn2 = nn.BatchNorm2d(planes, eps=1e-05,)
+ self.prelu = nn.PReLU(planes)
+ self.conv2 = conv3x3(planes, planes, stride)
+ self.bn3 = nn.BatchNorm2d(planes, eps=1e-05,)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x):
+ identity = x
+ out = self.bn1(x)
+ out = self.conv1(out)
+ out = self.bn2(out)
+ out = self.prelu(out)
+ out = self.conv2(out)
+ out = self.bn3(out)
+ if self.downsample is not None:
+ identity = self.downsample(x)
+ out += identity
+ return out
+
+
+class IResNet(nn.Module):
+ def __init__(self,
+ block, layers, dropout=0, num_features=512, zero_init_residual=False,
+ groups=1, width_per_group=64, replace_stride_with_dilation=None, fp16=False, fc_scale=7*7):
+ super(IResNet, self).__init__()
+ self.fp16 = fp16
+ self.inplanes = 64
+ self.dilation = 1
+ if replace_stride_with_dilation is None:
+ replace_stride_with_dilation = [False, False, False]
+ if len(replace_stride_with_dilation) != 3:
+ raise ValueError("replace_stride_with_dilation should be None "
+ "or a 3-element tuple, got {}".format(replace_stride_with_dilation))
+ self.groups = groups
+ self.base_width = width_per_group
+ self.conv1 = nn.Conv2d(3, self.inplanes, kernel_size=3, stride=1, padding=1, bias=False)
+ self.bn1 = nn.BatchNorm2d(self.inplanes, eps=1e-05)
+ self.prelu = nn.PReLU(self.inplanes)
+ self.layer1 = self._make_layer(block, 64, layers[0], stride=2)
+ self.layer2 = self._make_layer(block,
+ 128,
+ layers[1],
+ stride=2,
+ dilate=replace_stride_with_dilation[0])
+
+ self.layer3 = self._make_layer(block,
+ 256,
+ layers[2],
+ stride=2,
+ dilate=replace_stride_with_dilation[1])
+ set_requires_grad(self.layer1, False)
+ set_requires_grad(self.layer2, False)
+ set_requires_grad(self.layer3, False)
+ self.layer4 = self._make_layer(block,
+ 512,
+ layers[3],
+ stride=2,
+ dilate=replace_stride_with_dilation[2])
+ self.bn2 = nn.BatchNorm2d(512 * block.expansion, eps=1e-05,)
+ self.dropout = nn.Dropout(p=dropout, inplace=True)
+ self.fc = nn.Linear(512 * block.expansion * fc_scale, num_features)
+ self.features = nn.BatchNorm1d(num_features, eps=1e-05)
+ nn.init.constant_(self.features.weight, 1.0)
+ self.features.weight.requires_grad = False
+
+ for m in self.modules():
+ if isinstance(m, nn.Conv2d):
+ nn.init.normal_(m.weight, 0, 0.1)
+ elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
+ nn.init.constant_(m.weight, 1)
+ nn.init.constant_(m.bias, 0)
+
+ if zero_init_residual:
+ for m in self.modules():
+ if isinstance(m, IBasicBlock):
+ nn.init.constant_(m.bn2.weight, 0)
+
+ def _make_layer(self, block, planes, blocks, stride=1, dilate=False):
+ downsample = None
+ previous_dilation = self.dilation
+ if dilate:
+ self.dilation *= stride
+ stride = 1
+ if stride != 1 or self.inplanes != planes * block.expansion:
+ downsample = nn.Sequential(
+ conv1x1(self.inplanes, planes * block.expansion, stride),
+ nn.BatchNorm2d(planes * block.expansion, eps=1e-05, ),
+ )
+ layers = []
+ layers.append(
+ block(self.inplanes, planes, stride, downsample, self.groups,
+ self.base_width, previous_dilation))
+ self.inplanes = planes * block.expansion
+ for _ in range(1, blocks):
+ layers.append(
+ block(self.inplanes,
+ planes,
+ groups=self.groups,
+ base_width=self.base_width,
+ dilation=self.dilation))
+
+ return nn.Sequential(*layers)
+
+ def forward(self, x):
+ with torch.cuda.amp.autocast(self.fp16):
+ x = self.conv1(x)
+ x = self.bn1(x)
+ x = self.prelu(x)
+ x = self.layer1(x)
+ x = self.layer2(x)
+ x = self.layer3(x)
+ x = self.layer4(x)
+ x = self.bn2(x)
+ x = self.dropout(x)
+ x = F.avg_pool2d(x, kernel_size=2, stride=2, padding=0)
+ return x
+
+
+def _iresnet(arch, block, layers, pretrained, progress, **kwargs):
+ model = IResNet(block, layers, **kwargs)
+ if pretrained:
+ raise ValueError()
+ return model
+
+
+def iresnet18(pretrained=False, progress=True, **kwargs):
+ return _iresnet('iresnet18', IBasicBlock, [2, 2, 2, 2], pretrained,
+ progress, **kwargs)
+
+
+def iresnet34(pretrained=False, progress=True, **kwargs):
+ return _iresnet('iresnet34', IBasicBlock, [3, 4, 6, 3], pretrained,
+ progress, **kwargs)
+
+
+def iresnet50(pretrained=False, progress=True, **kwargs):
+ return _iresnet('iresnet50', IBasicBlock, [3, 4, 14, 3], pretrained,
+ progress, **kwargs)
+
+
+def iresnet100(pretrained=False, progress=True, **kwargs):
+ return _iresnet('iresnet100', IBasicBlock, [3, 13, 30, 3], pretrained,
+ progress, **kwargs)
+
+
+def iresnet200(pretrained=False, progress=True, **kwargs):
+ return _iresnet('iresnet200', IBasicBlock, [6, 26, 60, 6], pretrained,
+ progress, **kwargs)
diff --git a/clean/image/effort/DeepfakeBench/training/networks/mesonet.py b/clean/image/effort/DeepfakeBench/training/networks/mesonet.py
new file mode 100644
index 0000000000000000000000000000000000000000..bb4df43794f301ea6802ca16e1265ab45d183ab8
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/networks/mesonet.py
@@ -0,0 +1,189 @@
+'''
+# author: Zhiyuan Yan
+# email: zhiyuanyan@link.cuhk.edu.cn
+# date: 2023-0706
+
+The code is mainly modified from the below link:
+https://github.com/HongguLiu/MesoNet-Pytorch
+'''
+
+import os
+import argparse
+import logging
+
+import math
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+
+import torch.utils.model_zoo as model_zoo
+from torch.nn import init
+from typing import Union
+from utils.registry import BACKBONE
+
+logger = logging.getLogger(__name__)
+
+@BACKBONE.register_module(module_name="meso4")
+class Meso4(nn.Module):
+ def __init__(self, meso4_config):
+ super(Meso4, self).__init__()
+ self.num_classes = meso4_config["num_classes"]
+ inc = meso4_config["inc"]
+ self.conv1 = nn.Conv2d(inc, 8, 3, padding=1, bias=False)
+ self.bn1 = nn.BatchNorm2d(8)
+ self.relu = nn.ReLU(inplace=True)
+ self.leakyrelu = nn.LeakyReLU(0.1)
+
+ self.conv2 = nn.Conv2d(8, 8, 5, padding=2, bias=False)
+ self.bn2 = nn.BatchNorm2d(16)
+ self.conv3 = nn.Conv2d(8, 16, 5, padding=2, bias=False)
+ self.conv4 = nn.Conv2d(16, 16, 5, padding=2, bias=False)
+ self.maxpooling1 = nn.MaxPool2d(kernel_size=(2, 2))
+ self.maxpooling2 = nn.MaxPool2d(kernel_size=(4, 4))
+ #flatten: x = x.view(x.size(0), -1)
+ self.dropout = nn.Dropout2d(0.5)
+ self.fc1 = nn.Linear(16*8*8, 16)
+ self.fc2 = nn.Linear(16, self.num_classes)
+
+
+ def features(self, input):
+ x = self.conv1(input) #(8, 256, 256)
+ x = self.relu(x)
+ x = self.bn1(x)
+ x = self.maxpooling1(x) #(8, 128, 128)
+
+ x = self.conv2(x) #(8, 128, 128)
+ x = self.relu(x)
+ x = self.bn1(x)
+ x = self.maxpooling1(x) #(8, 64, 64)
+
+ x = self.conv3(x) #(16, 64, 64)
+ x = self.relu(x)
+ x = self.bn2(x)
+ x = self.maxpooling1(x) #(16, 32, 32)
+
+ x = self.conv4(x) #(16, 32, 32)
+ x = self.relu(x)
+ x = self.bn2(x)
+ x = self.maxpooling2(x) #(16, 8, 8)
+ x = x.view(x.size(0), -1) #(Batch, 16*8*8)
+
+ return x
+
+ def classifier(self, feature):
+ out = self.dropout(feature)
+ out = self.fc1(out) #(Batch, 16)
+ out = self.leakyrelu(out)
+ out = self.dropout(out)
+ out = self.fc2(out)
+ return out
+
+ def forward(self, input):
+ x = self.features(input)
+ out = self.classifier(x)
+ return out, x
+
+
+@BACKBONE.register_module(module_name="meso4Inception")
+class MesoInception4(nn.Module):
+ def __init__(self, mesoInception4_config):
+ super(MesoInception4, self).__init__()
+ self.num_classes = mesoInception4_config["num_classes"]
+ inc = mesoInception4_config["inc"]
+ #InceptionLayer1
+ self.Incption1_conv1 = nn.Conv2d(3, 1, 1, padding=0, bias=False)
+ self.Incption1_conv2_1 = nn.Conv2d(3, 4, 1, padding=0, bias=False)
+ self.Incption1_conv2_2 = nn.Conv2d(4, 4, 3, padding=1, bias=False)
+ self.Incption1_conv3_1 = nn.Conv2d(3, 4, 1, padding=0, bias=False)
+ self.Incption1_conv3_2 = nn.Conv2d(4, 4, 3, padding=2, dilation=2, bias=False)
+ self.Incption1_conv4_1 = nn.Conv2d(3, 2, 1, padding=0, bias=False)
+ self.Incption1_conv4_2 = nn.Conv2d(2, 2, 3, padding=3, dilation=3, bias=False)
+ self.Incption1_bn = nn.BatchNorm2d(11)
+
+
+ #InceptionLayer2
+ self.Incption2_conv1 = nn.Conv2d(11, 2, 1, padding=0, bias=False)
+ self.Incption2_conv2_1 = nn.Conv2d(11, 4, 1, padding=0, bias=False)
+ self.Incption2_conv2_2 = nn.Conv2d(4, 4, 3, padding=1, bias=False)
+ self.Incption2_conv3_1 = nn.Conv2d(11, 4, 1, padding=0, bias=False)
+ self.Incption2_conv3_2 = nn.Conv2d(4, 4, 3, padding=2, dilation=2, bias=False)
+ self.Incption2_conv4_1 = nn.Conv2d(11, 2, 1, padding=0, bias=False)
+ self.Incption2_conv4_2 = nn.Conv2d(2, 2, 3, padding=3, dilation=3, bias=False)
+ self.Incption2_bn = nn.BatchNorm2d(12)
+
+ #Normal Layer
+ self.conv1 = nn.Conv2d(12, 16, 5, padding=2, bias=False)
+ self.relu = nn.ReLU(inplace=True)
+ self.leakyrelu = nn.LeakyReLU(0.1)
+ self.bn1 = nn.BatchNorm2d(16)
+ self.maxpooling1 = nn.MaxPool2d(kernel_size=(2, 2))
+
+ self.conv2 = nn.Conv2d(16, 16, 5, padding=2, bias=False)
+ self.maxpooling2 = nn.MaxPool2d(kernel_size=(4, 4))
+
+ self.dropout = nn.Dropout2d(0.5)
+ self.fc1 = nn.Linear(16*8*8, 16)
+ self.fc2 = nn.Linear(16, self.num_classes)
+
+
+ #InceptionLayer
+ def InceptionLayer1(self, input):
+ x1 = self.Incption1_conv1(input)
+ x2 = self.Incption1_conv2_1(input)
+ x2 = self.Incption1_conv2_2(x2)
+ x3 = self.Incption1_conv3_1(input)
+ x3 = self.Incption1_conv3_2(x3)
+ x4 = self.Incption1_conv4_1(input)
+ x4 = self.Incption1_conv4_2(x4)
+ y = torch.cat((x1, x2, x3, x4), 1)
+ y = self.Incption1_bn(y)
+ y = self.maxpooling1(y)
+
+ return y
+
+ def InceptionLayer2(self, input):
+ x1 = self.Incption2_conv1(input)
+ x2 = self.Incption2_conv2_1(input)
+ x2 = self.Incption2_conv2_2(x2)
+ x3 = self.Incption2_conv3_1(input)
+ x3 = self.Incption2_conv3_2(x3)
+ x4 = self.Incption2_conv4_1(input)
+ x4 = self.Incption2_conv4_2(x4)
+ y = torch.cat((x1, x2, x3, x4), 1)
+ y = self.Incption2_bn(y)
+ y = self.maxpooling1(y)
+
+ return y
+
+
+ def features(self, input):
+ x = self.InceptionLayer1(input) #(Batch, 11, 128, 128)
+ x = self.InceptionLayer2(x) #(Batch, 12, 64, 64)
+
+ x = self.conv1(x) #(Batch, 16, 64 ,64)
+ x = self.relu(x)
+ x = self.bn1(x)
+ x = self.maxpooling1(x) #(Batch, 16, 32, 32)
+
+ x = self.conv2(x) #(Batch, 16, 32, 32)
+ x = self.relu(x)
+ x = self.bn1(x)
+ x = self.maxpooling2(x) #(Batch, 16, 8, 8)
+
+ x = x.view(x.size(0), -1) #(Batch, 16*8*8)
+
+ return x
+
+ def classifier(self, feature):
+
+ out = self.dropout(feature)
+ out = self.fc1(out) #(Batch, 16)
+ out = self.leakyrelu(out)
+ out = self.dropout(out)
+ out = self.fc2(out)
+ return out
+
+ def forward(self, input):
+ x = self.features(input)
+ out = self.classifier(x)
+ return out, x
diff --git a/clean/image/effort/DeepfakeBench/training/networks/resnet.py b/clean/image/effort/DeepfakeBench/training/networks/resnet.py
new file mode 100644
index 0000000000000000000000000000000000000000..64d649ab427b06444a9b4b17c53869640ebbe2b6
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/networks/resnet.py
@@ -0,0 +1,501 @@
+# -*- coding: utf-8 -*-
+"""
+Created on 18-5-21 下午5:26
+
+@author: ronghuaiyang
+"""
+import torch
+import torch.nn as nn
+import math
+import torch.utils.model_zoo as model_zoo
+import torch.nn.utils.weight_norm as weight_norm
+import torch.nn.functional as F
+
+
+# __all__ = ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101',
+# 'resnet152']
+
+
+model_urls = {
+ 'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth',
+ 'resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth',
+ 'resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth',
+ 'resnet101': 'https://download.pytorch.org/models/resnet101-5d3b4d8f.pth',
+ 'resnet152': 'https://download.pytorch.org/models/resnet152-b121ed2d.pth',
+}
+
+
+def conv3x3(in_planes, out_planes, stride=1):
+ """3x3 convolution with padding"""
+ return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,
+ padding=1, bias=False)
+
+
+class AdaIN(nn.Module):
+ def __init__(self, eps=1e-5):
+ super().__init__()
+ self.eps = eps
+ # self.l1 = nn.Linear(num_classes, in_channel*4, bias=True) #bias is good :)
+
+ def c_norm(self, x, bs, ch, eps=1e-7):
+ # assert isinstance(x, torch.cuda.FloatTensor)
+ x_var = x.var(dim=-1) + eps
+ x_std = x_var.sqrt().view(bs, ch, 1, 1)
+ x_mean = x.mean(dim=-1).view(bs, ch, 1, 1)
+ return x_std, x_mean
+
+ def forward(self, x, y):
+ assert x.size(0)==y.size(0)
+ size = x.size()
+ bs, ch = size[:2]
+ x_ = x.view(bs, ch, -1)
+ y_ = y.reshape(bs, ch, -1)
+ x_std, x_mean = self.c_norm(x_, bs, ch, eps=self.eps)
+ y_std, y_mean = self.c_norm(y_, bs, ch, eps=self.eps)
+ out = ((x - x_mean.expand(size)) / x_std.expand(size)) \
+ * y_std.expand(size) + y_mean.expand(size)
+ return out
+
+
+class BasicBlock(nn.Module):
+ expansion = 1
+
+ def __init__(self, inplanes, planes, stride=1, downsample=None):
+ super(BasicBlock, self).__init__()
+ self.conv1 = conv3x3(inplanes, planes, stride)
+ self.bn1 = nn.BatchNorm2d(planes)
+ self.relu = nn.ReLU(inplace=True)
+ self.conv2 = conv3x3(planes, planes)
+ self.bn2 = nn.BatchNorm2d(planes)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x):
+ residual = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+
+ if self.downsample is not None:
+ residual = self.downsample(x)
+
+ out += residual
+ out = self.relu(out)
+
+ return out
+
+
+class BasicBlock_adain(nn.Module):
+ expansion = 1
+
+ def __init__(self, inplanes, planes, stride=1, downsample=None):
+ super(BasicBlock_adain, self).__init__()
+ self.conv1 = conv3x3(inplanes, planes, stride)
+ self.adain1 = AdaIN()
+ self.relu = nn.ReLU(inplace=True)
+ self.conv2 = conv3x3(planes, planes)
+ self.adain2 = AdaIN()
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, feat): # x is content, c is style
+ x, c = feat
+ residual = x
+
+ x = self.conv1(x)
+ out = self.adain1(x, c)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.adain2(out, c)
+
+ if self.downsample is not None:
+ residual = self.downsample(residual)
+
+ out += residual
+ out = self.relu(out)
+
+ return (out, c)
+
+
+class IRBlock(nn.Module):
+ expansion = 1
+
+ def __init__(self, inplanes, planes, stride=1, downsample=None, use_se=True):
+ super(IRBlock, self).__init__()
+ self.bn0 = nn.BatchNorm2d(inplanes)
+ self.conv1 = conv3x3(inplanes, inplanes)
+ self.bn1 = nn.BatchNorm2d(inplanes)
+ self.prelu = nn.PReLU()
+ self.conv2 = conv3x3(inplanes, planes, stride)
+ self.bn2 = nn.BatchNorm2d(planes)
+ self.downsample = downsample
+ self.stride = stride
+ self.use_se = use_se
+ if self.use_se:
+ self.se = SEBlock(planes)
+
+ def forward(self, x):
+ residual = x
+ out = self.bn0(x)
+ out = self.conv1(out)
+ out = self.bn1(out)
+ out = self.prelu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+ if self.use_se:
+ out = self.se(out)
+
+ if self.downsample is not None:
+ residual = self.downsample(x)
+
+ out += residual
+ out = self.prelu(out)
+
+ return out
+
+
+class IRBlock_3conv(nn.Module):
+ expansion = 1
+
+ def __init__(self, inplanes, planes, stride=1, downsample=None, use_se=True):
+ super(IRBlock_3conv, self).__init__()
+ self.bn0 = nn.BatchNorm2d(inplanes)
+ self.conv1 = conv3x3(inplanes, inplanes)
+ self.bn1 = nn.BatchNorm2d(inplanes)
+ self.prelu1 = nn.PReLU()
+ self.conv2 = conv3x3(inplanes, planes, stride)
+ self.bn2 = nn.BatchNorm2d(planes)
+ self.prelu2 = nn.PReLU()
+ self.conv3 = conv3x3(planes, planes)
+ self.bn3 = nn.BatchNorm2d(planes)
+ self.downsample = downsample
+ self.stride = stride
+ self.use_se = use_se
+ if self.use_se:
+ self.se = SEBlock(planes)
+ self.prelu = nn.PReLU()
+
+ def forward(self, x):
+ residual = x
+ out = self.bn0(x)
+ out = self.conv1(out)
+ out = self.bn1(out)
+ out = self.prelu1(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+ out = self.prelu2(out)
+
+ out = self.conv3(out)
+ out = self.bn3(out)
+ if self.use_se:
+ out = self.se(out)
+
+ if self.downsample is not None:
+ residual = self.downsample(x)
+
+ out += residual
+ out = self.prelu(out)
+
+ return out
+
+
+class Bottleneck(nn.Module):
+ expansion = 4
+
+ def __init__(self, inplanes, planes, stride=1, downsample=None):
+ super(Bottleneck, self).__init__()
+ self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False)
+ self.bn1 = nn.BatchNorm2d(planes)
+ self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride,
+ padding=1, bias=False)
+ self.bn2 = nn.BatchNorm2d(planes)
+ self.conv3 = nn.Conv2d(
+ planes, planes * self.expansion, kernel_size=1, bias=False)
+ self.bn3 = nn.BatchNorm2d(planes * self.expansion)
+ self.relu = nn.ReLU(inplace=True)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x):
+ residual = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+ out = self.relu(out)
+
+ out = self.conv3(out)
+ out = self.bn3(out)
+
+ if self.downsample is not None:
+ residual = self.downsample(x)
+
+ out += residual
+ out = self.relu(out)
+
+ return out
+
+
+class SEBlock(nn.Module):
+ def __init__(self, channel, reduction=16):
+ super(SEBlock, self).__init__()
+ self.avg_pool = nn.AdaptiveAvgPool2d(1)
+ self.fc = nn.Sequential(
+ nn.Linear(channel, channel // reduction),
+ nn.PReLU(),
+ nn.Linear(channel // reduction, channel),
+ nn.Sigmoid()
+ )
+
+ def forward(self, x):
+ b, c, _, _ = x.size()
+ y = self.avg_pool(x).view(b, c)
+ y = self.fc(y).view(b, c, 1, 1)
+ return x * y
+
+
+class ResNetFace(nn.Module):
+ def __init__(self, block, layers, use_se=True, inc=3):
+ self.inplanes = 64
+ self.use_se = use_se
+ super(ResNetFace, self).__init__()
+ self.conv1 = nn.Conv2d(inc, 64, kernel_size=3, padding=1, bias=False)
+ self.bn1 = nn.BatchNorm2d(64)
+ self.prelu = nn.PReLU()
+ self.maxpool = nn.MaxPool2d(kernel_size=2, stride=2)
+ self.layer1 = self._make_layer(block, 64, layers[0])
+ self.layer2 = self._make_layer(block, 128, layers[1], stride=2)
+ self.layer3 = self._make_layer(block, 256, layers[2], stride=2)
+ self.layer4 = self._make_layer(block, 512, layers[3], stride=2)
+ self.bn4 = nn.BatchNorm2d(512)
+ #self.dropout = nn.Dropout()
+ self.fc5 = nn.Linear(512 * 8 * 8, 512)
+ #self.bn5 = nn.BatchNorm1d(512)
+
+ for m in self.modules():
+ if isinstance(m, nn.Conv2d):
+ nn.init.xavier_normal_(m.weight)
+ elif isinstance(m, nn.BatchNorm2d) or isinstance(m, nn.BatchNorm1d):
+ nn.init.constant_(m.weight, 1)
+ nn.init.constant_(m.bias, 0)
+ elif isinstance(m, nn.Linear):
+ nn.init.xavier_normal_(m.weight)
+ nn.init.constant_(m.bias, 0)
+
+ def _make_layer(self, block, planes, blocks, stride=1):
+ downsample = None
+ if stride != 1 or self.inplanes != planes * block.expansion:
+ downsample = nn.Sequential(
+ nn.Conv2d(self.inplanes, planes * block.expansion,
+ kernel_size=1, stride=stride, bias=False),
+ nn.BatchNorm2d(planes * block.expansion),
+ )
+ layers = []
+ layers.append(block(self.inplanes, planes, stride,
+ downsample, use_se=self.use_se))
+ self.inplanes = planes
+ for i in range(1, blocks):
+ layers.append(block(self.inplanes, planes, use_se=self.use_se))
+
+ return nn.Sequential(*layers)
+
+ def features(self, x):
+ x = self.conv1(x)
+ x = self.bn1(x)
+ x = self.prelu(x)
+ x = self.maxpool(x)
+
+ x = self.layer1(x)
+ x = self.layer2(x)
+ x = self.layer3(x)
+ x = self.layer4(x)
+ x = self.bn4(x)
+
+ return x
+
+ def classifier(self, x):
+ x = x.view(x.size(0), -1)
+ x = self.fc5(x)
+
+ return x
+
+ def forward(self, x):
+ x = self.conv1(x)
+ x = self.bn1(x)
+ x = self.prelu(x)
+ x = self.maxpool(x)
+
+ x = self.layer1(x)
+ x = self.layer2(x)
+ x = self.layer3(x)
+ x = self.layer4(x)
+ x = self.bn4(x)
+ #x = self.dropout(x)
+ x = x.view(x.size(0), -1)
+ x = self.fc5(x)
+ #x = self.bn5(x)
+
+ return x
+
+
+class ResNet(nn.Module):
+
+ def __init__(self, block, layers, basedim=32, inc=1):
+ self.inplanes = basedim
+ super(ResNet, self).__init__()
+ # self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3,
+ # bias=False)
+ self.conv1 = nn.Conv2d(inc, self.inplanes, kernel_size=3, stride=1, padding=1,
+ bias=False)
+ self.bn1 = nn.BatchNorm2d(self.inplanes)
+ self.relu = nn.ReLU(inplace=True)
+ # self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
+ self.layer1 = self._make_layer(block, basedim, layers[0], stride=2)
+ self.layer2 = self._make_layer(block, 2*basedim, layers[1], stride=2)
+ self.layer3 = self._make_layer(block, 4*basedim, layers[2], stride=2)
+ self.layer4 = self._make_layer(block, 8*basedim, layers[3], stride=2)
+ # self.avgpool = nn.AvgPool2d(8, stride=1)
+ # self.fc = nn.Linear(512 * block.expansion, num_classes)
+ self.fc5 = nn.Linear(512 * 8 * 8, 512)
+
+ for m in self.modules():
+ if isinstance(m, nn.Conv2d):
+ nn.init.kaiming_normal_(
+ m.weight, mode='fan_out', nonlinearity='relu')
+ elif isinstance(m, nn.BatchNorm2d):
+ nn.init.constant_(m.weight, 1)
+ nn.init.constant_(m.bias, 0)
+
+ def _make_layer(self, block, planes, blocks, stride=1):
+ downsample = None
+ if stride != 1 or self.inplanes != planes * block.expansion:
+ downsample = nn.Sequential(
+ nn.Conv2d(self.inplanes, planes * block.expansion,
+ kernel_size=1, stride=stride, bias=False),
+ nn.BatchNorm2d(planes * block.expansion),
+ )
+
+ layers = []
+ layers.append(block(self.inplanes, planes, stride, downsample))
+ self.inplanes = planes * block.expansion
+ for i in range(1, blocks):
+ layers.append(block(self.inplanes, planes))
+
+ return nn.Sequential(*layers)
+
+ def features(self, x):
+ x = self.conv1(x)
+ x = self.bn1(x)
+ x = self.relu(x)
+ # x = self.maxpool(x)
+
+ x = self.layer1(x)
+ x = self.layer2(x)
+ x = self.layer3(x)
+ x = self.layer4(x)
+
+ return x
+
+ def classifier(self, x):
+ x = x.view(x.size(0), -1)
+ x = self.fc5(x)
+
+ return x
+
+ def forward(self, x):
+ x = self.conv1(x)
+ x = self.bn1(x)
+ x = self.relu(x)
+ # x = self.maxpool(x)
+
+ x = self.layer1(x)
+ x = self.layer2(x)
+ x = self.layer3(x)
+ x = self.layer4(x)
+ # x = nn.AvgPool2d(kernel_size=x.size()[2:])(x)
+ # x = self.avgpool(x)
+ x = x.view(x.size(0), -1)
+ x = self.fc5(x)
+
+ return x
+
+
+def resnet18(pretrained=False, **kwargs):
+ """Constructs a ResNet-18 model.
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ """
+ model = ResNet(BasicBlock, [2, 2, 2, 2], **kwargs)
+ if pretrained:
+ model.load_state_dict(model_zoo.load_url(model_urls['resnet18']))
+ return model
+
+
+def resnet34(pretrained=False, **kwargs):
+ """Constructs a ResNet-34 model.
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ """
+ model = ResNet(BasicBlock, [3, 4, 6, 3], **kwargs)
+ if pretrained:
+ model.load_state_dict(model_zoo.load_url(model_urls['resnet34']))
+ return model
+
+
+def resnet50(pretrained=False, **kwargs):
+ """Constructs a ResNet-50 model.
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ """
+ model = ResNet(Bottleneck, [3, 4, 6, 3], **kwargs)
+ if pretrained:
+ model.load_state_dict(model_zoo.load_url(model_urls['resnet50']))
+ return model
+
+
+def resnet101(pretrained=False, **kwargs):
+ """Constructs a ResNet-101 model.
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ """
+ model = ResNet(Bottleneck, [3, 4, 23, 3], **kwargs)
+ if pretrained:
+ model.load_state_dict(model_zoo.load_url(model_urls['resnet101']))
+ return model
+
+
+def resnet152(pretrained=False, **kwargs):
+ """Constructs a ResNet-152 model.
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ """
+ model = ResNet(Bottleneck, [3, 8, 36, 3], **kwargs)
+ if pretrained:
+ model.load_state_dict(model_zoo.load_url(model_urls['resnet152']))
+ return model
+
+
+def resnet_face18(use_se=True, **kwargs):
+ model = ResNetFace(IRBlock, [2, 2, 2, 2], use_se=use_se, **kwargs)
+ return model
+
+
+def resnet_face62(use_se=True, **kwargs):
+ model = ResNetFace(IRBlock_3conv, [3, 4, 10, 3], use_se=use_se, **kwargs)
+ return model
+
+if __name__ == "__main__":
+ net = HR_resnet()
+ dummy = torch.rand(10,3,256,256)
+ x = net(dummy)
+ print('output:', x.size())
diff --git a/clean/image/effort/DeepfakeBench/training/networks/resnet34.py b/clean/image/effort/DeepfakeBench/training/networks/resnet34.py
new file mode 100644
index 0000000000000000000000000000000000000000..e6fc2d2c42e1e6ae26f3b92ab0f419e0db183392
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/networks/resnet34.py
@@ -0,0 +1,60 @@
+'''
+# author: Zhiyuan Yan
+# email: zhiyuanyan@link.cuhk.edu.cn
+# date: 2023-0706
+
+The code is for ResNet34 backbone.
+'''
+
+import os
+import logging
+from typing import Union
+import torch
+import torchvision
+import torch.nn as nn
+import torch.nn.functional as F
+from utils.registry import BACKBONE
+
+logger = logging.getLogger(__name__)
+
+@BACKBONE.register_module(module_name="resnet34")
+class ResNet34(nn.Module):
+ def __init__(self, resnet_config):
+ super(ResNet34, self).__init__()
+ """ Constructor
+ Args:
+ resnet_config: configuration file with the dict format
+ """
+ self.num_classes = resnet_config["num_classes"]
+ inc = resnet_config["inc"]
+ self.mode = resnet_config["mode"]
+
+ # Define layers of the backbone
+ resnet = torchvision.models.resnet34(pretrained=True) # FIXME: download the pretrained weights from online
+ # resnet.conv1 = nn.Conv2d(inc, 64, kernel_size=7, stride=2, padding=3, bias=False)
+ self.resnet = torch.nn.Sequential(*list(resnet.children())[:-2])
+ self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
+ self.fc = nn.Linear(512, self.num_classes)
+
+ if self.mode == 'adjust_channel':
+ self.adjust_channel = nn.Sequential(
+ nn.Conv2d(512, 512, 1, 1),
+ nn.BatchNorm2d(512),
+ nn.ReLU(inplace=True),
+ )
+
+
+ def features(self, inp):
+ x = self.resnet(inp)
+ return x
+
+ def classifier(self, features):
+ x = self.avgpool(features)
+ x = x.view(x.size(0), -1)
+ x = self.fc(x)
+ return x
+
+ def forward(self, inp):
+ x = self.features(inp)
+ out = self.classifier(x)
+ return out
diff --git a/clean/image/effort/DeepfakeBench/training/networks/vgg.py b/clean/image/effort/DeepfakeBench/training/networks/vgg.py
new file mode 100644
index 0000000000000000000000000000000000000000..da74f9c6a1ca1a93470cefeb68781ddee05d3460
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/networks/vgg.py
@@ -0,0 +1,143 @@
+"""A VGG-based perceptual loss function for PyTorch."""
+
+import torch
+from torch import nn
+from torch.nn import functional as F
+from torchvision import models, transforms
+
+
+class Lambda(nn.Module):
+ """Wraps a callable in an :class:`nn.Module` without registering it."""
+
+ def __init__(self, func):
+ super().__init__()
+ object.__setattr__(self, 'forward', func)
+
+ def extra_repr(self):
+ return getattr(self.forward, '__name__', type(self.forward).__name__) + '()'
+
+
+class WeightedLoss(nn.ModuleList):
+ """A weighted combination of multiple loss functions."""
+
+ def __init__(self, losses, weights, verbose=False):
+ super().__init__()
+ for loss in losses:
+ self.append(loss if isinstance(loss, nn.Module) else Lambda(loss))
+ self.weights = weights
+ self.verbose = verbose
+
+ def _print_losses(self, losses):
+ for i, loss in enumerate(losses):
+ print(f'({i}) {type(self[i]).__name__}: {loss.item()}')
+
+ def forward(self, *args, **kwargs):
+ losses = []
+ for loss, weight in zip(self, self.weights):
+ losses.append(loss(*args, **kwargs) * weight)
+ if self.verbose:
+ self._print_losses(losses)
+ return sum(losses)
+
+
+class TVLoss(nn.Module):
+ """Total variation loss (Lp penalty on image gradient magnitude).
+ The input must be 4D. If a target (second parameter) is passed in, it is
+ ignored.
+ ``p=1`` yields the vectorial total variation norm. It is a generalization
+ of the originally proposed (isotropic) 2D total variation norm (see
+ (see https://en.wikipedia.org/wiki/Total_variation_denoising) for color
+ images. On images with a single channel it is equal to the 2D TV norm.
+ ``p=2`` yields a variant that is often used for smoothing out noise in
+ reconstructions of images from neural network feature maps (see Mahendran
+ and Vevaldi, "Understanding Deep Image Representations by Inverting
+ Them", https://arxiv.org/abs/1412.0035)
+ :attr:`reduction` can be set to ``'mean'``, ``'sum'``, or ``'none'``
+ similarly to the loss functions in :mod:`torch.nn`. The default is
+ ``'mean'``.
+ """
+
+ def __init__(self, p, reduction='mean', eps=1e-8):
+ super().__init__()
+ if p not in {1, 2}:
+ raise ValueError('p must be 1 or 2')
+ if reduction not in {'mean', 'sum', 'none'}:
+ raise ValueError("reduction must be 'mean', 'sum', or 'none'")
+ self.p = p
+ self.reduction = reduction
+ self.eps = eps
+
+ def forward(self, input, target=None):
+ input = F.pad(input, (0, 1, 0, 1), 'replicate')
+ x_diff = input[..., :-1, :-1] - input[..., :-1, 1:]
+ y_diff = input[..., :-1, :-1] - input[..., 1:, :-1]
+ diff = x_diff**2 + y_diff**2
+ if self.p == 1:
+ diff = (diff + self.eps).mean(dim=1, keepdims=True).sqrt()
+ if self.reduction == 'mean':
+ return diff.mean()
+ if self.reduction == 'sum':
+ return diff.sum()
+ return diff
+
+
+class VGGLoss(nn.Module):
+ """Computes the VGG perceptual loss between two batches of images.
+ The input and target must be 4D tensors with three channels
+ ``(B, 3, H, W)`` and must have equivalent shapes. Pixel values should be
+ normalized to the range 0–1.
+ The VGG perceptual loss is the mean squared difference between the features
+ computed for the input and target at layer :attr:`layer` (default 8, or
+ ``relu2_2``) of the pretrained model specified by :attr:`model` (either
+ ``'vgg16'`` (default) or ``'vgg19'``).
+ If :attr:`shift` is nonzero, a random shift of at most :attr:`shift`
+ pixels in both height and width will be applied to all images in the input
+ and target. The shift will only be applied when the loss function is in
+ training mode, and will not be applied if a precomputed feature map is
+ supplied as the target.
+ :attr:`reduction` can be set to ``'mean'``, ``'sum'``, or ``'none'``
+ similarly to the loss functions in :mod:`torch.nn`. The default is
+ ``'mean'``.
+ :meth:`get_features()` may be used to precompute the features for the
+ target, to speed up the case where inputs are compared against the same
+ target over and over. To use the precomputed features, pass them in as
+ :attr:`target` and set :attr:`target_is_features` to :code:`True`.
+ Instances of :class:`VGGLoss` must be manually converted to the same
+ device and dtype as their inputs.
+ """
+
+ models = {'vgg16': models.vgg16, 'vgg19': models.vgg19}
+
+ def __init__(self, model='vgg16', layer=8, shift=0, reduction='mean'):
+ super().__init__()
+ self.instancenorm = nn.InstanceNorm2d(512, affine=False)
+ self.shift = shift
+ self.reduction = reduction
+ self.normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406],
+ std=[0.229, 0.224, 0.225])
+ self.model = self.models[model](pretrained=True).features[:layer+1]
+ self.model.eval()
+ self.model.requires_grad_(False)
+
+ def get_features(self, input):
+ return self.model(self.normalize(input))
+
+ def train(self, mode=True):
+ self.training = mode
+
+ def forward(self, input, target, target_is_features=False):
+ if target_is_features:
+ input_feats = self.get_features(input)
+ target_feats = target
+ else:
+ sep = input.shape[0]
+ batch = torch.cat([input, target])
+ if self.shift and self.training:
+ padded = F.pad(batch, [self.shift] * 4, mode='replicate')
+ batch = transforms.RandomCrop(batch.shape[2:])(padded)
+ feats = self.get_features(batch)
+ input_feats, target_feats = feats[:sep], feats[sep:]
+ # input_feats, target_feats = \
+ # self.instancenorm(input_feats), \
+ # self.instancenorm(target_feats)
+ return F.mse_loss(input_feats, target_feats, reduction=self.reduction)
\ No newline at end of file
diff --git a/clean/image/effort/DeepfakeBench/training/networks/xception.py b/clean/image/effort/DeepfakeBench/training/networks/xception.py
new file mode 100644
index 0000000000000000000000000000000000000000..8c61d9d37d959d0d99100f139ab64d8b5d62140a
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/networks/xception.py
@@ -0,0 +1,272 @@
+'''
+# author: Zhiyuan Yan
+# email: zhiyuanyan@link.cuhk.edu.cn
+# date: 2023-0706
+
+The code is mainly modified from GitHub link below:
+https://github.com/ondyari/FaceForensics/blob/master/classification/network/xception.py
+'''
+
+import os
+import argparse
+import logging
+
+import math
+import torch
+# import pretrainedmodels
+import torch.nn as nn
+import torch.nn.functional as F
+
+import torch.utils.model_zoo as model_zoo
+from torch.nn import init
+from typing import Union
+from utils.registry import BACKBONE
+
+logger = logging.getLogger(__name__)
+
+
+
+class SeparableConv2d(nn.Module):
+ def __init__(self, in_channels, out_channels, kernel_size=1, stride=1, padding=0, dilation=1, bias=False):
+ super(SeparableConv2d, self).__init__()
+
+ self.conv1 = nn.Conv2d(in_channels, in_channels, kernel_size,
+ stride, padding, dilation, groups=in_channels, bias=bias)
+ self.pointwise = nn.Conv2d(
+ in_channels, out_channels, 1, 1, 0, 1, 1, bias=bias)
+
+ def forward(self, x):
+ x = self.conv1(x)
+ x = self.pointwise(x)
+ return x
+
+
+class Block(nn.Module):
+ def __init__(self, in_filters, out_filters, reps, strides=1, start_with_relu=True, grow_first=True):
+ super(Block, self).__init__()
+
+ if out_filters != in_filters or strides != 1:
+ self.skip = nn.Conv2d(in_filters, out_filters,
+ 1, stride=strides, bias=False)
+ self.skipbn = nn.BatchNorm2d(out_filters)
+ else:
+ self.skip = None
+
+ self.relu = nn.ReLU(inplace=True)
+ rep = []
+
+ filters = in_filters
+ if grow_first: # whether the number of filters grows first
+ rep.append(self.relu)
+ rep.append(SeparableConv2d(in_filters, out_filters,
+ 3, stride=1, padding=1, bias=False))
+ rep.append(nn.BatchNorm2d(out_filters))
+ filters = out_filters
+
+ for i in range(reps-1):
+ rep.append(self.relu)
+ rep.append(SeparableConv2d(filters, filters,
+ 3, stride=1, padding=1, bias=False))
+ rep.append(nn.BatchNorm2d(filters))
+
+ if not grow_first:
+ rep.append(self.relu)
+ rep.append(SeparableConv2d(in_filters, out_filters,
+ 3, stride=1, padding=1, bias=False))
+ rep.append(nn.BatchNorm2d(out_filters))
+
+ if not start_with_relu:
+ rep = rep[1:]
+ else:
+ rep[0] = nn.ReLU(inplace=False)
+
+ if strides != 1:
+ rep.append(nn.MaxPool2d(3, strides, 1))
+ self.rep = nn.Sequential(*rep)
+
+ def forward(self, inp):
+ x = self.rep(inp)
+
+ if self.skip is not None:
+ skip = self.skip(inp)
+ skip = self.skipbn(skip)
+ else:
+ skip = inp
+
+ x += skip
+ return x
+
+def add_gaussian_noise(ins, mean=0, stddev=0.2):
+ noise = ins.data.new(ins.size()).normal_(mean, stddev)
+ return ins + noise
+
+
+@BACKBONE.register_module(module_name="xception")
+class Xception(nn.Module):
+ """
+ Xception optimized for the ImageNet dataset, as specified in
+ https://arxiv.org/pdf/1610.02357.pdf
+ """
+
+ def __init__(self, xception_config):
+ """ Constructor
+ Args:
+ xception_config: configuration file with the dict format
+ """
+ super(Xception, self).__init__()
+ self.num_classes = xception_config["num_classes"]
+ self.mode = xception_config["mode"]
+ inc = xception_config["inc"]
+ dropout = xception_config["dropout"]
+
+ # Entry flow
+ self.conv1 = nn.Conv2d(inc, 32, 3, 2, 0, bias=False)
+
+ self.bn1 = nn.BatchNorm2d(32)
+ self.relu = nn.ReLU(inplace=True)
+
+ self.conv2 = nn.Conv2d(32, 64, 3, bias=False)
+ self.bn2 = nn.BatchNorm2d(64)
+ # do relu here
+
+ self.block1 = Block(
+ 64, 128, 2, 2, start_with_relu=False, grow_first=True)
+ self.block2 = Block(
+ 128, 256, 2, 2, start_with_relu=True, grow_first=True)
+ self.block3 = Block(
+ 256, 728, 2, 2, start_with_relu=True, grow_first=True)
+
+ # middle flow
+ self.block4 = Block(
+ 728, 728, 3, 1, start_with_relu=True, grow_first=True)
+ self.block5 = Block(
+ 728, 728, 3, 1, start_with_relu=True, grow_first=True)
+ self.block6 = Block(
+ 728, 728, 3, 1, start_with_relu=True, grow_first=True)
+ self.block7 = Block(
+ 728, 728, 3, 1, start_with_relu=True, grow_first=True)
+
+ self.block8 = Block(
+ 728, 728, 3, 1, start_with_relu=True, grow_first=True)
+ self.block9 = Block(
+ 728, 728, 3, 1, start_with_relu=True, grow_first=True)
+ self.block10 = Block(
+ 728, 728, 3, 1, start_with_relu=True, grow_first=True)
+ self.block11 = Block(
+ 728, 728, 3, 1, start_with_relu=True, grow_first=True)
+
+ # Exit flow
+ self.block12 = Block(
+ 728, 1024, 2, 2, start_with_relu=True, grow_first=False)
+
+ self.conv3 = SeparableConv2d(1024, 1536, 3, 1, 1)
+ self.bn3 = nn.BatchNorm2d(1536)
+
+ # do relu here
+ self.conv4 = SeparableConv2d(1536, 2048, 3, 1, 1)
+ self.bn4 = nn.BatchNorm2d(2048)
+
+ self.last_linear = nn.Linear(2048, self.num_classes)
+ if dropout:
+ self.last_linear = nn.Sequential(
+ nn.Dropout(p=dropout),
+ nn.Linear(2048, self.num_classes)
+ )
+
+ self.adjust_channel = nn.Sequential(
+ nn.Conv2d(2048, 512, 1, 1),
+ nn.BatchNorm2d(512),
+ nn.ReLU(inplace=True),
+ )
+
+ def fea_part1_0(self, x):
+ x = self.conv1(x)
+ x = self.bn1(x)
+ x = self.relu(x)
+
+ return x
+
+ def fea_part1_1(self, x):
+
+ x = self.conv2(x)
+ x = self.bn2(x)
+ x = self.relu(x)
+
+ return x
+
+ def fea_part1(self, x):
+ x = self.conv1(x)
+ x = self.bn1(x)
+ x = self.relu(x)
+
+ x = self.conv2(x)
+ x = self.bn2(x)
+ x = self.relu(x)
+
+ return x
+
+ def fea_part2(self, x):
+ x = self.block1(x)
+ x = self.block2(x)
+ x = self.block3(x)
+
+ return x
+
+ def fea_part3(self, x):
+ if self.mode == "shallow_xception":
+ return x
+ else:
+ x = self.block4(x)
+ x = self.block5(x)
+ x = self.block6(x)
+ x = self.block7(x)
+ return x
+
+ def fea_part4(self, x):
+ if self.mode == "shallow_xception":
+ x = self.block12(x)
+ else:
+ x = self.block8(x)
+ x = self.block9(x)
+ x = self.block10(x)
+ x = self.block11(x)
+ x = self.block12(x)
+ return x
+
+ def fea_part5(self, x):
+ x = self.conv3(x)
+ x = self.bn3(x)
+ x = self.relu(x)
+
+ x = self.conv4(x)
+ x = self.bn4(x)
+
+ return x
+
+ def features(self, input):
+ x = self.fea_part1(input)
+
+ x = self.fea_part2(x)
+ x = self.fea_part3(x)
+ x = self.fea_part4(x)
+
+ x = self.fea_part5(x)
+
+ if self.mode == 'adjust_channel':
+ x = self.adjust_channel(x)
+
+ return x
+
+ def classifier(self, features):
+ x = self.relu(features)
+
+ if len(x.shape) == 4:
+ x = F.adaptive_avg_pool2d(x, (1, 1))
+ x = x.view(x.size(0), -1)
+ out = self.last_linear(x)
+ return out
+
+ def forward(self, input):
+ x = self.features(input)
+ out = self.classifier(x)
+ return out, x
diff --git a/clean/image/effort/DeepfakeBench/training/networks/xception_ffd.py b/clean/image/effort/DeepfakeBench/training/networks/xception_ffd.py
new file mode 100644
index 0000000000000000000000000000000000000000..5f23ddae50da43390081167dd199d31a1118c889
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/networks/xception_ffd.py
@@ -0,0 +1,267 @@
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+
+import os
+import sys
+
+class SeparableConv2d(nn.Module):
+ def __init__(self, c_in, c_out, ks, stride=1, padding=0, dilation=1, bias=False):
+ super(SeparableConv2d, self).__init__()
+ self.c = nn.Conv2d(c_in, c_in, ks, stride, padding, dilation, groups=c_in, bias=bias)
+ self.pointwise = nn.Conv2d(c_in, c_out, 1, 1, 0, 1, 1, bias=bias)
+
+ def forward(self, x):
+ x = self.c(x)
+ x = self.pointwise(x)
+ return x
+
+class Block(nn.Module):
+ def __init__(self, c_in, c_out, reps, stride=1, start_with_relu=True, grow_first=True):
+ super(Block, self).__init__()
+
+ self.skip = None
+ self.skip_bn = None
+ if c_out != c_in or stride!= 1:
+ self.skip = nn.Conv2d(c_in, c_out, 1, stride=stride, bias=False)
+ self.skip_bn = nn.BatchNorm2d(c_out)
+
+ self.relu = nn.ReLU(inplace=True)
+
+ rep = []
+ c = c_in
+ if grow_first:
+ rep.append(self.relu)
+ rep.append(SeparableConv2d(c_in, c_out, 3, stride=1, padding=1, bias=False))
+ rep.append(nn.BatchNorm2d(c_out))
+ c = c_out
+
+ for i in range(reps - 1):
+ rep.append(self.relu)
+ rep.append(SeparableConv2d(c, c, 3, stride=1, padding=1, bias=False))
+ rep.append(nn.BatchNorm2d(c))
+
+ if not grow_first:
+ rep.append(self.relu)
+ rep.append(SeparableConv2d(c_in, c_out, 3, stride=1, padding=1, bias=False))
+ rep.append(nn.BatchNorm2d(c_out))
+
+ if not start_with_relu:
+ rep = rep[1:]
+ else:
+ rep[0] = nn.ReLU(inplace=False)
+
+ if stride != 1:
+ rep.append(nn.MaxPool2d(3, stride, 1))
+ self.rep = nn.Sequential(*rep)
+
+ def forward(self, inp):
+ x = self.rep(inp)
+
+ if self.skip is not None:
+ y = self.skip(inp)
+ y = self.skip_bn(y)
+ else:
+ y = inp
+
+ x += y
+ return x
+
+class RegressionMap(nn.Module):
+ def __init__(self, c_in):
+ super(RegressionMap, self).__init__()
+ self.c = SeparableConv2d(c_in, 1, 3, stride=1, padding=1, bias=False)
+ self.s = nn.Sigmoid()
+
+ def forward(self, x):
+ mask = self.c(x)
+ mask = self.s(mask)
+ return mask, None
+
+class TemplateMap(nn.Module):
+ def __init__(self, c_in, templates):
+ super(TemplateMap, self).__init__()
+ self.c = Block(c_in, 364, 2, 2, start_with_relu=True, grow_first=False)
+ self.l = nn.Linear(364, 10)
+ self.relu = nn.ReLU(inplace=True)
+
+ self.templates = templates
+
+ def forward(self, x):
+ v = self.c(x)
+ v = self.relu(v)
+ v = F.adaptive_avg_pool2d(v, (1,1))
+ v = v.view(v.size(0), -1)
+ v = self.l(v)
+ mask = torch.mm(v, self.templates.reshape(10,361))
+ mask = mask.reshape(x.shape[0], 1, 19, 19)
+
+ return mask, v
+
+class PCATemplateMap(nn.Module):
+ def __init__(self, templates):
+ super(PCATemplateMap, self).__init__()
+ self.templates = templates
+
+ def forward(self, x):
+ fe = x.view(x.shape[0], x.shape[1], x.shape[2]*x.shape[3])
+ fe = torch.transpose(fe, 1, 2)
+ mu = torch.mean(fe, 2, keepdim=True)
+ fea_diff = fe - mu
+
+ cov_fea = torch.bmm(fea_diff, torch.transpose(fea_diff, 1, 2))
+ B = self.templates.reshape(1, 10, 361).repeat(x.shape[0], 1, 1)
+ D = torch.bmm(torch.bmm(B, cov_fea), torch.transpose(B, 1, 2))
+ eigen_value, eigen_vector = D.symeig(eigenvectors=True)
+ index = torch.tensor([9]).cuda()
+ eigen = torch.index_select(eigen_vector, 2, index)
+
+ v = eigen.squeeze(-1)
+ mask = torch.mm(v, self.templates.reshape(10, 361))
+ mask = mask.reshape(x.shape[0], 1, 19, 19)
+ return mask, v
+
+class Xception(nn.Module):
+ """
+ Xception optimized for the ImageNet dataset, as specified in
+ https://arxiv.org/pdf/1610.02357.pdf
+ """
+ def __init__(self, maptype, templates, num_classes=1000):
+ super(Xception, self).__init__()
+ self.num_classes = num_classes
+
+ self.conv1 = nn.Conv2d(3, 32, 3,2, 0, bias=False)
+ self.bn1 = nn.BatchNorm2d(32)
+ self.relu = nn.ReLU(inplace=True)
+
+ self.conv2 = nn.Conv2d(32,64,3,bias=False)
+ self.bn2 = nn.BatchNorm2d(64)
+
+ self.block1=Block(64,128,2,2,start_with_relu=False,grow_first=True)
+ self.block2=Block(128,256,2,2,start_with_relu=True,grow_first=True)
+ self.block3=Block(256,728,2,2,start_with_relu=True,grow_first=True)
+ self.block4=Block(728,728,3,1,start_with_relu=True,grow_first=True)
+ self.block5=Block(728,728,3,1,start_with_relu=True,grow_first=True)
+ self.block6=Block(728,728,3,1,start_with_relu=True,grow_first=True)
+ self.block7=Block(728,728,3,1,start_with_relu=True,grow_first=True)
+ self.block8=Block(728,728,3,1,start_with_relu=True,grow_first=True)
+ self.block9=Block(728,728,3,1,start_with_relu=True,grow_first=True)
+ self.block10=Block(728,728,3,1,start_with_relu=True,grow_first=True)
+ self.block11=Block(728,728,3,1,start_with_relu=True,grow_first=True)
+ self.block12=Block(728,1024,2,2,start_with_relu=True,grow_first=False)
+
+ self.conv3 = SeparableConv2d(1024,1536,3,1,1)
+ self.bn3 = nn.BatchNorm2d(1536)
+
+ self.conv4 = SeparableConv2d(1536,2048,3,1,1)
+ self.bn4 = nn.BatchNorm2d(2048)
+
+ self.last_linear = nn.Linear(2048, num_classes)
+
+ if maptype == 'none':
+ self.map = [1, None]
+ elif maptype == 'reg':
+ self.map = RegressionMap(728)
+ elif maptype == 'tmp':
+ self.map = TemplateMap(728, templates)
+ elif maptype == 'pca_tmp':
+ self.map = PCATemplateMap(728)
+ else:
+ print('Unknown map type: `{0}`'.format(maptype))
+ sys.exit()
+
+ def features(self, input):
+ x = self.conv1(input)
+ x = self.bn1(x)
+ x = self.relu(x)
+
+ x = self.conv2(x)
+ x = self.bn2(x)
+ x = self.relu(x)
+
+ x = self.block1(x)
+ x = self.block2(x)
+ x = self.block3(x)
+ x = self.block4(x)
+ x = self.block5(x)
+ x = self.block6(x)
+ x = self.block7(x)
+ mask, vec = self.map(x)
+ x = x * mask
+ x = self.block8(x)
+ x = self.block9(x)
+ x = self.block10(x)
+ x = self.block11(x)
+ x = self.block12(x)
+ x = self.conv3(x)
+ x = self.bn3(x)
+ x = self.relu(x)
+
+ x = self.conv4(x)
+ x = self.bn4(x)
+ return x, mask, vec
+
+ def logits(self, features):
+ x = self.relu(features)
+ x = F.adaptive_avg_pool2d(x, (1, 1))
+ x = x.view(x.size(0), -1)
+ x = self.last_linear(x)
+ return x
+
+ def forward(self, input):
+ x, mask, vec = self.features(input)
+ x = self.logits(x)
+ return x, mask, vec
+
+def init_weights(m):
+ classname = m.__class__.__name__
+ if classname.find('SeparableConv2d') != -1:
+ m.c.weight.data.normal_(0.0, 0.01)
+ if m.c.bias is not None:
+ m.c.bias.data.fill_(0)
+ m.pointwise.weight.data.normal_(0.0, 0.01)
+ if m.pointwise.bias is not None:
+ m.pointwise.bias.data.fill_(0)
+ elif classname.find('Conv') != -1 or classname.find('Linear') != -1:
+ m.weight.data.normal_(0.0, 0.01)
+ if m.bias is not None:
+ m.bias.data.fill_(0)
+ elif classname.find('BatchNorm') != -1:
+ m.weight.data.normal_(1.0, 0.01)
+ m.bias.data.fill_(0)
+ elif classname.find('LSTM') != -1:
+ for i in m._parameters:
+ if i.__class__.__name__.find('weight') != -1:
+ i.data.normal_(0.0, 0.01)
+ elif i.__class__.__name__.find('bias') != -1:
+ i.bias.data.fill_(0)
+
+class Model:
+ def __init__(self, maptype='None', templates=None, num_classes=2, load_pretrain=True):
+ model = Xception(maptype, templates, num_classes=num_classes)
+ if load_pretrain:
+ state_dict = torch.load('./xception-b5690688.pth')
+ for name, weights in state_dict:
+ if 'pointwise' in name:
+ state_dict[name] = weights.unsqueeze(-1).unsqueeze(-1)
+ del state_dict['fc.weight']
+ del state_dict['fc.bias']
+ model.load_state_dict(state_dict, False)
+ else:
+ model.apply(init_weights)
+ self.model = model
+
+ def save(self, epoch, optim, model_dir):
+ state = {'net': self.model.state_dict(), 'optim': optim.state_dict()}
+ torch.save(state, '{0}/{1:06d}.tar'.format(model_dir, epoch))
+ print('Saved model `{0}`'.format(epoch))
+
+ def load(self, epoch, model_dir):
+ filename = '{0}{1:06d}.tar'.format(model_dir, epoch)
+ print('Loading model from {0}'.format(filename))
+ if os.path.exists(filename):
+ state = torch.load(filename)
+ self.model.load_state_dict(state['net'])
+ else:
+ print('Failed to load model from {0}'.format(filename))
+
diff --git a/clean/image/effort/DeepfakeBench/training/optimizor/LinearLR.py b/clean/image/effort/DeepfakeBench/training/optimizor/LinearLR.py
new file mode 100644
index 0000000000000000000000000000000000000000..80bc70dbae46bb9f76aa65afe6f4a1b95dd25619
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/optimizor/LinearLR.py
@@ -0,0 +1,20 @@
+import torch
+from torch.optim import SGD
+from torch.optim.lr_scheduler import _LRScheduler
+
+class LinearDecayLR(_LRScheduler):
+ def __init__(self, optimizer, n_epoch, start_decay, last_epoch=-1):
+ self.start_decay=start_decay
+ self.n_epoch=n_epoch
+ super(LinearDecayLR, self).__init__(optimizer, last_epoch)
+
+ def get_lr(self):
+ last_epoch = self.last_epoch
+ n_epoch=self.n_epoch
+ b_lr=self.base_lrs[0]
+ start_decay=self.start_decay
+ if last_epoch>start_decay:
+ lr=b_lr-b_lr/(n_epoch-start_decay)*(last_epoch-start_decay)
+ else:
+ lr=b_lr
+ return [lr]
\ No newline at end of file
diff --git a/clean/image/effort/DeepfakeBench/training/optimizor/SAM.py b/clean/image/effort/DeepfakeBench/training/optimizor/SAM.py
new file mode 100644
index 0000000000000000000000000000000000000000..7b8d1dc52726ffea22553ce96a6e0d37a902fbff
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/optimizor/SAM.py
@@ -0,0 +1,77 @@
+# borrowed from
+
+import torch
+
+import torch
+import torch.nn as nn
+
+def disable_running_stats(model):
+ def _disable(module):
+ if isinstance(module, nn.BatchNorm2d):
+ module.backup_momentum = module.momentum
+ module.momentum = 0
+
+ model.apply(_disable)
+
+def enable_running_stats(model):
+ def _enable(module):
+ if isinstance(module, nn.BatchNorm2d) and hasattr(module, "backup_momentum"):
+ module.momentum = module.backup_momentum
+
+ model.apply(_enable)
+
+class SAM(torch.optim.Optimizer):
+ def __init__(self, params, base_optimizer, rho=0.05, **kwargs):
+ assert rho >= 0.0, f"Invalid rho, should be non-negative: {rho}"
+
+ defaults = dict(rho=rho, **kwargs)
+ super(SAM, self).__init__(params, defaults)
+
+ self.base_optimizer = base_optimizer(self.param_groups, **kwargs)
+ self.param_groups = self.base_optimizer.param_groups
+
+ @torch.no_grad()
+ def first_step(self, zero_grad=False):
+ grad_norm = self._grad_norm()
+ for group in self.param_groups:
+ scale = group["rho"] / (grad_norm + 1e-12)
+
+ for p in group["params"]:
+ if p.grad is None: continue
+ e_w = p.grad * scale.to(p)
+ p.add_(e_w) # climb to the local maximum "w + e(w)"
+ self.state[p]["e_w"] = e_w
+
+ if zero_grad: self.zero_grad()
+
+ @torch.no_grad()
+ def second_step(self, zero_grad=False):
+ for group in self.param_groups:
+ for p in group["params"]:
+ if p.grad is None: continue
+ p.sub_(self.state[p]["e_w"]) # get back to "w" from "w + e(w)"
+
+ self.base_optimizer.step() # do the actual "sharpness-aware" update
+
+ if zero_grad: self.zero_grad()
+
+ @torch.no_grad()
+ def step(self, closure=None):
+ assert closure is not None, "Sharpness Aware Minimization requires closure, but it was not provided"
+ closure = torch.enable_grad()(closure) # the closure should do a full forward-backward pass
+
+ self.first_step(zero_grad=True)
+ closure()
+ self.second_step()
+
+ def _grad_norm(self):
+ shared_device = self.param_groups[0]["params"][0].device # put everything on the same device, in case of model parallelism
+ norm = torch.norm(
+ torch.stack([
+ p.grad.norm(p=2).to(shared_device)
+ for group in self.param_groups for p in group["params"]
+ if p.grad is not None
+ ]),
+ p=2
+ )
+ return norm
\ No newline at end of file
diff --git a/clean/image/effort/DeepfakeBench/training/test.py b/clean/image/effort/DeepfakeBench/training/test.py
new file mode 100644
index 0000000000000000000000000000000000000000..13a22ed9533b18454609b41ee81dbbca9a2a848e
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/test.py
@@ -0,0 +1,253 @@
+"""
+eval pretained model.
+"""
+import os
+import numpy as np
+from os.path import join
+import cv2
+import random
+import datetime
+import time
+import yaml
+import pickle
+from tqdm import tqdm
+from copy import deepcopy
+from PIL import Image as pil_image
+from metrics.utils import get_test_metrics
+import torch
+import torch.nn as nn
+import torch.nn.parallel
+import torch.backends.cudnn as cudnn
+import torch.nn.functional as F
+import torch.utils.data
+import torch.optim as optim
+
+from dataset.abstract_dataset import DeepfakeAbstractBaseDataset
+
+from trainer.trainer import Trainer
+from detectors import DETECTOR
+from metrics.base_metrics_class import Recorder
+from collections import defaultdict
+
+import argparse
+from logger import create_logger
+
+parser = argparse.ArgumentParser(description='Process some paths.')
+parser.add_argument('--detector_path', type=str,
+ default='./training/config/detector/effort.yaml',
+ help='path to detector YAML file')
+parser.add_argument("--test_dataset", nargs="+")
+parser.add_argument('--weights_path', type=str,
+ default='./weights/effort_ckpt.pth')
+#parser.add_argument("--lmdb", action='store_true', default=False)
+args = parser.parse_args()
+
+device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
+
+on_2060 = "2060" in torch.cuda.get_device_name()
+def init_seed(config):
+ if config['manualSeed'] is None:
+ config['manualSeed'] = random.randint(1, 10000)
+ random.seed(config['manualSeed'])
+ torch.manual_seed(config['manualSeed'])
+ if config['cuda']:
+ torch.cuda.manual_seed_all(config['manualSeed'])
+
+
+def prepare_testing_data(config):
+ def get_test_data_loader(config, test_name):
+ # update the config dictionary with the specific testing dataset
+ config = config.copy() # create a copy of config to avoid altering the original one
+ config['test_dataset'] = test_name # specify the current test dataset
+ test_set = DeepfakeAbstractBaseDataset(
+ config=config,
+ mode='test',
+ )
+ test_data_loader = \
+ torch.utils.data.DataLoader(
+ dataset=test_set,
+ batch_size=config['test_batchSize'],
+ shuffle=False,
+ num_workers=int(config['workers']),
+ collate_fn=test_set.collate_fn,
+ drop_last=False
+ )
+ return test_data_loader
+
+ test_data_loaders = {}
+ for one_test_name in config['test_dataset']:
+ test_data_loaders[one_test_name] = get_test_data_loader(config, one_test_name)
+ return test_data_loaders
+
+
+def choose_metric(config):
+ metric_scoring = config['metric_scoring']
+ if metric_scoring not in ['eer', 'auc', 'acc', 'ap']:
+ raise NotImplementedError('metric {} is not implemented'.format(metric_scoring))
+ return metric_scoring
+
+
+def test_one_dataset(model, data_loader):
+ prediction_lists = []
+ feature_lists = []
+ label_lists = []
+ for i, data_dict in tqdm(enumerate(data_loader), total=len(data_loader)):
+ # get data
+ data, label, mask, landmark = \
+ data_dict['image'], data_dict['label'], data_dict['mask'], data_dict['landmark']
+ label = torch.where(data_dict['label'] != 0, 1, 0)
+ # move data to GPU
+ data_dict['image'], data_dict['label'] = data.to(device), label.to(device)
+ if mask is not None:
+ data_dict['mask'] = mask.to(device)
+ if landmark is not None:
+ data_dict['landmark'] = landmark.to(device)
+
+ # model forward without considering gradient computation
+ predictions = inference(model, data_dict)
+ label_lists += list(data_dict['label'].cpu().detach().numpy())
+ prediction_lists += list(predictions['prob'].cpu().detach().numpy())
+ feature_lists += list(predictions['feat'].cpu().detach().numpy())
+
+ return np.array(prediction_lists), np.array(label_lists),np.array(feature_lists)
+
+def test_epoch(model, test_data_loaders):
+ # set model to eval mode
+ model.eval()
+
+ # define test recorder
+ metrics_all_datasets = {}
+
+ # testing for all test data
+ keys = test_data_loaders.keys()
+ for key in keys:
+ data_dict = test_data_loaders[key].dataset.data_dict
+ # compute loss for each dataset
+ predictions_nps, label_nps,feat_nps = test_one_dataset(model, test_data_loaders[key])
+
+ # compute metric for each dataset
+ metric_one_dataset = get_test_metrics(y_pred=predictions_nps, y_true=label_nps,
+ img_names=data_dict['image'])
+ metrics_all_datasets[key] = metric_one_dataset
+
+ # info for each dataset
+ tqdm.write(f"dataset: {key}")
+ for k, v in metric_one_dataset.items():
+ tqdm.write(f"{k}: {v}")
+
+ return metrics_all_datasets
+
+@torch.no_grad()
+def inference(model, data_dict):
+ predictions = model(data_dict, inference=True)
+ return predictions
+
+
+
+
+def main():
+ # parse options and load config
+ with open(args.detector_path, 'r') as f:
+ config = yaml.safe_load(f)
+ with open('./training/config/test_config.yaml', 'r') as f:
+ config2 = yaml.safe_load(f)
+ config.update(config2)
+ if on_2060:
+ config['lmdb_dir'] = r'I:\transform_2_lmdb'
+ config['train_batchSize'] = 10
+ config['workers'] = 0
+ else:
+ config['workers'] = 8
+ config['lmdb_dir'] = r'/mnt/chongqinggeminiceph1fs/geminicephfs/mm-base-vision/jikangcheng/data/LMDBs'
+ weights_path = None
+ # If arguments are provided, they will overwrite the yaml settings
+ if args.test_dataset:
+ config['test_dataset'] = args.test_dataset
+ if args.weights_path:
+ config['weights_path'] = args.weights_path
+ weights_path = args.weights_path
+
+ # init seed
+ init_seed(config)
+
+ # set cudnn benchmark if needed
+ if config['cudnn']:
+ cudnn.benchmark = True
+
+ # prepare the testing data loader
+ test_data_loaders = prepare_testing_data(config)
+
+ # prepare the model (detector)
+ model_class = DETECTOR[config['model_name']]
+ model = model_class(config).to(device)
+ total_trainable_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
+ print(f"Total number of trainable parameters in the model: {total_trainable_params}")
+ epoch = 0
+ if weights_path:
+ try:
+ epoch = int(weights_path.split('/')[-1].split('.')[0].split('_')[2])
+ except:
+ epoch = 0
+ ckpt = torch.load(weights_path, map_location=device)
+ if 'state_dict' in ckpt:
+ ckpt = ckpt['state_dict']
+
+ # # 加载模型的状态字典
+ # model_dict = model.state_dict()
+ # new_ckpt={}
+ # for key in ckpt.keys():
+ # # 替换键
+ # new_key = key.replace('common_encoder_f','student_encoder')
+ # # 将旧的值复制到新的键下
+ # new_ckpt[new_key] = ckpt[key]
+ # # 获取ckpt和model的key集合
+ # ckpt_keys = set(new_ckpt.keys())
+ # model_keys = set(model_dict.keys())
+ #
+ # # 找出共同的key
+ # common_keys = ckpt_keys & model_keys
+ # print("Common keys:")
+ # for key in common_keys:
+ # print(key)
+ #
+ # # 找出只在ckpt中的key
+ # ckpt_unique_keys = ckpt_keys - model_keys
+ # print("\nKeys only in ckpt:")
+ # for key in ckpt_unique_keys:
+ # print(key)
+ #
+ # # 找出只在model中的key
+ # model_unique_keys = model_keys - ckpt_keys
+ # print("\nKeys only in model:")
+ # for key in model_unique_keys:
+ # print(key)
+
+ # 创建一个新的字典,删除module前缀
+ new_weights = {}
+ for key, value in ckpt.items():
+ new_key = key.replace('module.', '') # 删除module前缀
+ #new_key = 'backbone.' + new_key # 删除module前缀
+ # if 'base_model.' in new_key:
+ # new_key = new_key.replace('base_model.', 'backbone.')
+ # if 'classifier.' in new_key:
+ # new_key = new_key.replace('classifier.', 'head.')
+ new_weights[new_key] = value
+
+
+ model.load_state_dict(new_weights, strict=True)
+ print('===> Load checkpoint done!')
+ else:
+ print('Fail to load the pre-trained weights')
+
+ # clip_rank_results = analyze_clip_effective_rank(model.backbone)
+
+ # for layer_name, rank in clip_rank_results.items():
+ # print(f"Layer: {layer_name}, Effective Rank: {rank}")
+
+
+ # start testing
+ best_metric = test_epoch(model, test_data_loaders)
+ print('===> Test Done!')
+
+if __name__ == '__main__':
+ main()
diff --git a/clean/image/effort/DeepfakeBench/training/train.py b/clean/image/effort/DeepfakeBench/training/train.py
new file mode 100644
index 0000000000000000000000000000000000000000..607a613e1d0e6f7ae2fed743cb116cfb654722e0
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/train.py
@@ -0,0 +1,277 @@
+# author: Zhiyuan Yan
+# email: zhiyuanyan@link.cuhk.edu.cn
+# date: 2023-03-30
+# description: training code.
+
+import os
+import argparse
+from os.path import join
+import cv2
+import random
+import datetime
+import time
+import yaml
+from tqdm import tqdm
+import numpy as np
+from datetime import timedelta
+from copy import deepcopy
+from PIL import Image as pil_image
+
+import torch
+import torch.nn as nn
+import torch.nn.parallel
+import torch.backends.cudnn as cudnn
+import torch.utils.data
+import torch.optim as optim
+from torch.utils.data.distributed import DistributedSampler
+import torch.distributed as dist
+
+from optimizor.SAM import SAM
+from optimizor.LinearLR import LinearDecayLR
+
+from trainer.trainer import Trainer
+from detectors import DETECTOR
+from dataset import *
+from metrics.utils import parse_metric_for_print
+from logger import create_logger, RankFilter
+
+
+parser = argparse.ArgumentParser(description='Process some paths.')
+parser.add_argument('--detector_path', type=str,
+ default='/data/home/zhiyuanyan/DeepfakeBenchv2/training/config/detector/effort.yaml',
+ help='path to detector YAML file')
+parser.add_argument("--train_dataset", nargs="+")
+parser.add_argument("--test_dataset", nargs="+")
+parser.add_argument('--no-save_ckpt', dest='save_ckpt', action='store_false', default=True)
+parser.add_argument('--no-save_feat', dest='save_feat', action='store_false', default=True)
+parser.add_argument("--ddp", action='store_true', default=False)
+parser.add_argument('--local_rank', type=int, default=0)
+args = parser.parse_args()
+torch.cuda.set_device(args.local_rank)
+
+
+def init_seed(config):
+ if config['manualSeed'] is None:
+ config['manualSeed'] = random.randint(1, 10000)
+ random.seed(config['manualSeed'])
+ if config['cuda']:
+ torch.manual_seed(config['manualSeed'])
+ torch.cuda.manual_seed_all(config['manualSeed'])
+
+
+def prepare_training_data(config):
+ # Only use the blending dataset class in training
+ train_set = DeepfakeAbstractBaseDataset(
+ config=config,
+ mode='train',
+ )
+ if config['ddp']:
+ sampler = DistributedSampler(train_set)
+ train_data_loader = \
+ torch.utils.data.DataLoader(
+ dataset=train_set,
+ batch_size=config['train_batchSize'],
+ num_workers=int(config['workers']),
+ collate_fn=train_set.collate_fn,
+ sampler=sampler
+ )
+ else:
+ train_data_loader = \
+ torch.utils.data.DataLoader(
+ dataset=train_set,
+ batch_size=config['train_batchSize'],
+ shuffle=True,
+ num_workers=int(config['workers']),
+ collate_fn=train_set.collate_fn,
+ )
+ return train_data_loader
+
+
+def prepare_testing_data(config):
+ def get_test_data_loader(config, test_name):
+ # update the config dictionary with the specific testing dataset
+ config = config.copy() # create a copy of config to avoid altering the original one
+ config['test_dataset'] = test_name # specify the current test dataset
+
+ test_set = DeepfakeAbstractBaseDataset(
+ config=config,
+ mode='test',
+ )
+
+ test_data_loader = \
+ torch.utils.data.DataLoader(
+ dataset=test_set,
+ batch_size=config['test_batchSize'],
+ shuffle=False,
+ num_workers=int(config['workers']),
+ collate_fn=test_set.collate_fn,
+ drop_last = (test_name=='DeepFakeDetection'),
+ )
+
+ return test_data_loader
+
+ test_data_loaders = {}
+ for one_test_name in config['test_dataset']:
+ test_data_loaders[one_test_name] = get_test_data_loader(config, one_test_name)
+ return test_data_loaders
+
+
+def choose_optimizer(model, config):
+ opt_name = config['optimizer']['type']
+ if opt_name == 'sgd':
+ optimizer = optim.SGD(
+ params=model.parameters(),
+ lr=config['optimizer'][opt_name]['lr'],
+ momentum=config['optimizer'][opt_name]['momentum'],
+ weight_decay=config['optimizer'][opt_name]['weight_decay']
+ )
+ return optimizer
+ elif opt_name == 'adam':
+ optimizer = optim.Adam(
+ params=model.parameters(),
+ lr=config['optimizer'][opt_name]['lr'],
+ weight_decay=config['optimizer'][opt_name]['weight_decay'],
+ betas=(config['optimizer'][opt_name]['beta1'], config['optimizer'][opt_name]['beta2']),
+ eps=config['optimizer'][opt_name]['eps'],
+ amsgrad=config['optimizer'][opt_name]['amsgrad'],
+ )
+ return optimizer
+ elif opt_name == 'sam':
+ optimizer = SAM(
+ model.parameters(),
+ optim.SGD,
+ lr=config['optimizer'][opt_name]['lr'],
+ momentum=config['optimizer'][opt_name]['momentum'],
+ )
+ else:
+ raise NotImplementedError('Optimizer {} is not implemented'.format(config['optimizer']))
+ return optimizer
+
+
+def choose_scheduler(config, optimizer):
+ if config['lr_scheduler'] is None:
+ return None
+ elif config['lr_scheduler'] == 'step':
+ scheduler = optim.lr_scheduler.StepLR(
+ optimizer,
+ step_size=config['lr_step'],
+ gamma=config['lr_gamma'],
+ )
+ return scheduler
+ elif config['lr_scheduler'] == 'cosine':
+ scheduler = optim.lr_scheduler.CosineAnnealingLR(
+ optimizer,
+ T_max=config['lr_T_max'],
+ eta_min=config['lr_eta_min'],
+ )
+ return scheduler
+ elif config['lr_scheduler'] == 'linear':
+ scheduler = LinearDecayLR(
+ optimizer,
+ config['nEpochs'],
+ int(config['nEpochs']/4),
+ )
+ else:
+ raise NotImplementedError('Scheduler {} is not implemented'.format(config['lr_scheduler']))
+
+
+def choose_metric(config):
+ metric_scoring = config['metric_scoring']
+ if metric_scoring not in ['eer', 'auc', 'acc', 'ap']:
+ raise NotImplementedError('metric {} is not implemented'.format(metric_scoring))
+ return metric_scoring
+
+
+def main():
+ # parse options and load config
+ with open(args.detector_path, 'r') as f:
+ config = yaml.safe_load(f)
+ with open('./training/config/train_config.yaml', 'r') as f:
+ config2 = yaml.safe_load(f)
+ config.update(config2)
+ config['local_rank']=args.local_rank
+ if config['dry_run']:
+ config['nEpochs'] = 0
+ config['save_feat']=False
+ # If arguments are provided, they will overwrite the yaml settings
+ if args.train_dataset:
+ config['train_dataset'] = args.train_dataset
+ if args.test_dataset:
+ config['test_dataset'] = args.test_dataset
+ config['save_ckpt'] = args.save_ckpt
+ config['save_feat'] = args.save_feat
+ if config['lmdb']:
+ config['dataset_json_folder'] = 'preprocessing/dataset_json_v3'
+ # create logger
+ logger_path = config['log_dir']
+ os.makedirs(logger_path, exist_ok=True)
+ logger = create_logger(os.path.join(logger_path, 'training.log'))
+ logger.info('Save log to {}'.format(logger_path))
+ config['ddp']= args.ddp
+ # print configuration
+ logger.info("--------------- Configuration ---------------")
+ params_string = "Parameters: \n"
+ for key, value in config.items():
+ params_string += "{}: {}".format(key, value) + "\n"
+ logger.info(params_string)
+
+ # init seed
+ init_seed(config)
+
+ # set cudnn benchmark if needed
+ if config['cudnn']:
+ cudnn.benchmark = True
+ if config['ddp']:
+ # dist.init_process_group(backend='gloo')
+ dist.init_process_group(
+ backend='nccl',
+ timeout=timedelta(minutes=30)
+ )
+ logger.addFilter(RankFilter(0))
+ # prepare the training data loader
+ train_data_loader = prepare_training_data(config)
+
+ # prepare the testing data loader
+ test_data_loaders = prepare_testing_data(config)
+
+ # prepare the model (detector)
+ model_class = DETECTOR[config['model_name']]
+ model = model_class(config)
+
+ # prepare the optimizer
+ optimizer = choose_optimizer(model, config)
+
+ # prepare the scheduler
+ scheduler = choose_scheduler(config, optimizer)
+
+ # prepare the metric
+ metric_scoring = choose_metric(config)
+
+ # prepare the trainer
+ trainer = Trainer(config, model, optimizer, scheduler, logger, metric_scoring)
+
+ # start training
+ for epoch in range(config['start_epoch'], config['nEpochs'] + 1):
+ trainer.model.epoch = epoch
+ best_metric = trainer.train_epoch(
+ epoch=epoch,
+ train_data_loader=train_data_loader,
+ test_data_loaders=test_data_loaders,
+ )
+ if best_metric is not None:
+ logger.info(f"===> Epoch[{epoch}] end with testing {metric_scoring}: {parse_metric_for_print(best_metric)}!")
+ logger.info("Stop Training on best Testing metric {}".format(parse_metric_for_print(best_metric)))
+ # update
+ if 'svdd' in config['model_name']:
+ model.update_R(epoch)
+ if scheduler is not None:
+ scheduler.step()
+
+ # close the tensorboard writers
+ for writer in trainer.writers.values():
+ writer.close()
+
+
+
+if __name__ == '__main__':
+ main()
diff --git a/clean/image/effort/DeepfakeBench/training/trainer/__init__.py b/clean/image/effort/DeepfakeBench/training/trainer/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..c96d5a5f7af796495ee04bbc29924f239a89ded8
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/trainer/__init__.py
@@ -0,0 +1,2 @@
+from trainer.trainer import Trainer
+from utils.registry import TRAINER
\ No newline at end of file
diff --git a/clean/image/effort/DeepfakeBench/training/trainer/base_trainer.py b/clean/image/effort/DeepfakeBench/training/trainer/base_trainer.py
new file mode 100644
index 0000000000000000000000000000000000000000..e1402752b994f82702349e5c7c8d98b1fc7d1519
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/trainer/base_trainer.py
@@ -0,0 +1,50 @@
+import datetime
+from copy import deepcopy
+from abc import ABC, abstractmethod
+
+
+class BaseTrainer(ABC):
+ """
+ """
+
+ def __init__(
+ self,
+ config,
+ model,
+ optimizer,
+ scheduler,
+ writer,
+ ):
+ # check if all the necessary components are implemented
+ if config is None or model is None or optimizer is None or scheduler is None or writer is None:
+ raise NotImplementedError("config, model, optimizier, scheduler, and tensorboard writer must be implemented")
+
+ self.config = config
+ self.model = model
+ self.optimizer = optimizer
+ self.scheduler = scheduler
+ self.writer = writer
+
+ @abstractmethod
+ def speed_up(self):
+ pass
+
+ @abstractmethod
+ def setTrain(self):
+ pass
+
+ @abstractmethod
+ def setEval(self):
+ pass
+
+ @abstractmethod
+ def load_ckpt(self, model_path):
+ pass
+
+ @abstractmethod
+ def save_ckpt(self, dataset, epoch, iters, best=False):
+ pass
+
+ @abstractmethod
+ def inference(self, data_dict):
+ pass
diff --git a/clean/image/effort/DeepfakeBench/training/trainer/trainer.py b/clean/image/effort/DeepfakeBench/training/trainer/trainer.py
new file mode 100644
index 0000000000000000000000000000000000000000..07063c231056887cdaa84ed62a1892199e521401
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/trainer/trainer.py
@@ -0,0 +1,467 @@
+# author: Zhiyuan Yan
+# email: zhiyuanyan@link.cuhk.edu.cn
+# date: 2023-03-30
+# description: trainer
+import os
+import sys
+current_file_path = os.path.abspath(__file__)
+parent_dir = os.path.dirname(os.path.dirname(current_file_path))
+project_root_dir = os.path.dirname(parent_dir)
+sys.path.append(parent_dir)
+sys.path.append(project_root_dir)
+
+import pickle
+import datetime
+import logging
+import numpy as np
+from copy import deepcopy
+from collections import defaultdict
+from tqdm import tqdm
+import time
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+import torch.optim as optim
+from torch.nn import DataParallel
+from torch.utils.tensorboard import SummaryWriter
+from metrics.base_metrics_class import Recorder
+from torch.optim.swa_utils import AveragedModel, SWALR
+from torch import distributed as dist
+from torch.nn.parallel import DistributedDataParallel as DDP
+from sklearn import metrics
+from metrics.utils import get_test_metrics
+
+FFpp_pool=['FaceForensics++','FF-DF','FF-F2F','FF-FS','FF-NT']#
+device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
+
+
+class Trainer(object):
+ def __init__(
+ self,
+ config,
+ model,
+ optimizer,
+ scheduler,
+ logger,
+ metric_scoring='auc',
+ time_now = datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S'),
+ swa_model=None
+ ):
+ # check if all the necessary components are implemented
+ if config is None or model is None or optimizer is None or logger is None:
+ raise ValueError("config, model, optimizier, logger, and tensorboard writer must be implemented")
+
+ self.config = config
+ self.model = model
+ self.optimizer = optimizer
+ self.scheduler = scheduler
+ self.swa_model = swa_model
+ self.writers = {} # dict to maintain different tensorboard writers for each dataset and metric
+ self.logger = logger
+ self.metric_scoring = metric_scoring
+ # maintain the best metric of all epochs
+ self.best_metrics_all_time = defaultdict(
+ lambda: defaultdict(lambda: float('-inf')
+ if self.metric_scoring != 'eer' else float('inf'))
+ )
+ self.speed_up() # move model to GPU
+
+ # get current time
+ self.timenow = time_now
+ # create directory path
+ if 'task_target' not in config:
+ self.log_dir = os.path.join(
+ self.config['log_dir'],
+ self.config['model_name'] + '_' + self.timenow
+ )
+ else:
+ task_str = f"_{config['task_target']}" if config['task_target'] is not None else ""
+ self.log_dir = os.path.join(
+ self.config['log_dir'],
+ self.config['model_name'] + task_str + '_' + self.timenow
+ )
+ os.makedirs(self.log_dir, exist_ok=True)
+
+ def get_writer(self, phase, dataset_key, metric_key):
+ writer_key = f"{phase}-{dataset_key}-{metric_key}"
+ if writer_key not in self.writers:
+ # update directory path
+ writer_path = os.path.join(
+ self.log_dir,
+ phase,
+ dataset_key,
+ metric_key,
+ "metric_board"
+ )
+ os.makedirs(writer_path, exist_ok=True)
+ # update writers dictionary
+ self.writers[writer_key] = SummaryWriter(writer_path)
+ return self.writers[writer_key]
+
+
+ def speed_up(self):
+ self.model.to(device)
+ self.model.device = device
+ if self.config['ddp'] == True:
+ num_gpus = torch.cuda.device_count()
+ print(f'avai gpus: {num_gpus}')
+ # local_rank=[i for i in range(0,num_gpus)]
+ self.model = DDP(self.model, device_ids=[self.config['local_rank']],find_unused_parameters=True, output_device=self.config['local_rank'])
+ #self.optimizer = nn.DataParallel(self.optimizer, device_ids=[int(os.environ['LOCAL_RANK'])])
+
+ def setTrain(self):
+ self.model.train()
+ self.train = True
+
+ def setEval(self):
+ self.model.eval()
+ self.train = False
+
+ def load_ckpt(self, model_path):
+ if os.path.isfile(model_path):
+ saved = torch.load(model_path, map_location='cpu')
+ suffix = model_path.split('.')[-1]
+ if suffix == 'p':
+ self.model.load_state_dict(saved.state_dict())
+ else:
+ self.model.load_state_dict(saved)
+ self.logger.info('Model found in {}'.format(model_path))
+ else:
+ raise NotImplementedError(
+ "=> no model found at '{}'".format(model_path))
+
+ def save_ckpt(self, phase, dataset_key,ckpt_info=None):
+ save_dir = os.path.join(self.log_dir, phase, dataset_key)
+ os.makedirs(save_dir, exist_ok=True)
+ ckpt_name = f"ckpt_best.pth"
+ save_path = os.path.join(save_dir, ckpt_name)
+ if self.config['ddp'] == True:
+ torch.save(self.model.state_dict(), save_path)
+ else:
+ if 'svdd' in self.config['model_name']:
+ torch.save({'R': self.model.R,
+ 'c': self.model.c,
+ 'state_dict': self.model.state_dict(),}, save_path)
+ else:
+ torch.save(self.model.state_dict(), save_path)
+ self.logger.info(f"Checkpoint saved to {save_path}, current ckpt is {ckpt_info}")
+
+ def save_swa_ckpt(self):
+ save_dir = self.log_dir
+ os.makedirs(save_dir, exist_ok=True)
+ ckpt_name = f"swa.pth"
+ save_path = os.path.join(save_dir, ckpt_name)
+ torch.save(self.swa_model.state_dict(), save_path)
+ self.logger.info(f"SWA Checkpoint saved to {save_path}")
+
+
+ def save_feat(self, phase, fea, dataset_key):
+ save_dir = os.path.join(self.log_dir, phase, dataset_key)
+ os.makedirs(save_dir, exist_ok=True)
+ features = fea
+ feat_name = f"feat_best.npy"
+ save_path = os.path.join(save_dir, feat_name)
+ np.save(save_path, features)
+ self.logger.info(f"Feature saved to {save_path}")
+
+ def save_data_dict(self, phase, data_dict, dataset_key):
+ save_dir = os.path.join(self.log_dir, phase, dataset_key)
+ os.makedirs(save_dir, exist_ok=True)
+ file_path = os.path.join(save_dir, f'data_dict_{phase}.pickle')
+ with open(file_path, 'wb') as file:
+ pickle.dump(data_dict, file)
+ self.logger.info(f"data_dict saved to {file_path}")
+
+ def save_metrics(self, phase, metric_one_dataset, dataset_key):
+ save_dir = os.path.join(self.log_dir, phase, dataset_key)
+ os.makedirs(save_dir, exist_ok=True)
+ file_path = os.path.join(save_dir, 'metric_dict_best.pickle')
+ with open(file_path, 'wb') as file:
+ pickle.dump(metric_one_dataset, file)
+ self.logger.info(f"Metrics saved to {file_path}")
+
+ def train_step(self,data_dict):
+ if self.config['optimizer']['type']=='sam':
+ for i in range(2):
+ predictions = self.model(data_dict)
+ losses = self.model.get_losses(data_dict, predictions)
+ if i == 0:
+ pred_first = predictions
+ losses_first = losses
+ self.optimizer.zero_grad()
+ losses['overall'].backward()
+ if i == 0:
+ self.optimizer.first_step(zero_grad=True)
+ else:
+ self.optimizer.second_step(zero_grad=True)
+ return losses_first, pred_first
+ else:
+
+ predictions = self.model(data_dict)
+ if type(self.model) is DDP:
+ losses = self.model.module.get_losses(data_dict, predictions)
+ else:
+ losses = self.model.get_losses(data_dict, predictions)
+ self.optimizer.zero_grad()
+ losses['overall'].backward()
+ #self.model.module.set_mask_grad()
+ self.optimizer.step()
+
+
+ return losses,predictions
+
+
+ def train_epoch(
+ self,
+ epoch,
+ train_data_loader,
+ test_data_loaders=None,
+ ):
+
+ self.logger.info("===> Epoch[{}] start!".format(epoch))
+ if epoch>=1:
+ times_per_epoch = 2
+ else:
+ times_per_epoch = 2
+
+
+ #times_per_epoch=4
+
+ test_step = len(train_data_loader) // times_per_epoch # test 10 times per epoch
+ step_cnt = epoch * len(train_data_loader)
+
+ # save the training data_dict
+ data_dict = train_data_loader.dataset.data_dict
+ self.save_data_dict('train', data_dict, ','.join(self.config['train_dataset']))
+ # define training recorder
+ train_recorder_loss = defaultdict(Recorder)
+ train_recorder_metric = defaultdict(Recorder)
+
+ for iteration, data_dict in tqdm(enumerate(train_data_loader),total=len(train_data_loader)):
+ self.setTrain()
+ # more elegant and more scalable way of moving data to GPU
+ for key in data_dict.keys():
+ if data_dict[key]!=None and key!='name':
+ data_dict[key]=data_dict[key].cuda()
+
+ losses,predictions=self.train_step(data_dict)
+
+ # update learning rate
+
+ if 'SWA' in self.config and self.config['SWA'] and epoch>self.config['swa_start']:
+ self.swa_model.update_parameters(self.model)
+
+ # compute training metric for each batch data
+ if type(self.model) is DDP:
+ batch_metrics = self.model.module.get_train_metrics(data_dict, predictions)
+ else:
+ batch_metrics = self.model.get_train_metrics(data_dict, predictions)
+
+ # store data by recorder
+ ## store metric
+ for name, value in batch_metrics.items():
+ train_recorder_metric[name].update(value)
+ ## store loss
+ for name, value in losses.items():
+ train_recorder_loss[name].update(value)
+
+ # run tensorboard to visualize the training process
+ if iteration % 300 == 0 and self.config['local_rank']==0:
+ if self.config['SWA'] and (epoch>self.config['swa_start'] or self.config['dry_run']):
+ self.scheduler.step()
+ # info for loss
+ loss_str = f"Iter: {step_cnt} "
+ for k, v in train_recorder_loss.items():
+ v_avg = v.average()
+ if v_avg == None:
+ loss_str += f"training-loss, {k}: not calculated"
+ continue
+ loss_str += f"training-loss, {k}: {v_avg} "
+ # tensorboard-1. loss
+ writer = self.get_writer('train', ','.join(self.config['train_dataset']), k)
+ writer.add_scalar(f'train_loss/{k}', v_avg, global_step=step_cnt)
+ self.logger.info(loss_str)
+ # info for metric
+ metric_str = f"Iter: {step_cnt} "
+ for k, v in train_recorder_metric.items():
+ v_avg = v.average()
+ if v_avg == None:
+ metric_str += f"training-metric, {k}: not calculated "
+ continue
+ metric_str += f"training-metric, {k}: {v_avg} "
+ # tensorboard-2. metric
+ writer = self.get_writer('train', ','.join(self.config['train_dataset']), k)
+ writer.add_scalar(f'train_metric/{k}', v_avg, global_step=step_cnt)
+ self.logger.info(metric_str)
+
+
+
+ # clear recorder.
+ # Note we only consider the current 300 samples for computing batch-level loss/metric
+ for name, recorder in train_recorder_loss.items(): # clear loss recorder
+ recorder.clear()
+ for name, recorder in train_recorder_metric.items(): # clear metric recorder
+ recorder.clear()
+
+ # run test
+ #if True:
+ if (step_cnt+1) % test_step == 0:
+ if test_data_loaders is not None and (not self.config['ddp'] ):
+ self.logger.info("===> Test start!")
+ test_best_metric = self.test_epoch(
+ epoch,
+ iteration,
+ test_data_loaders,
+ step_cnt,
+ )
+ elif test_data_loaders is not None and (self.config['ddp'] and dist.get_rank() == 0):
+ self.logger.info("===> Test start!")
+ test_best_metric = self.test_epoch(
+ epoch,
+ iteration,
+ test_data_loaders,
+ step_cnt,
+ )
+ else:
+ test_best_metric = None
+
+ # total_end_time = time.time()
+ # total_elapsed_time = total_end_time - total_start_time
+ # print("总花费的时间: {:.2f} 秒".format(total_elapsed_time))
+ step_cnt += 1
+ return test_best_metric
+
+ def get_respect_acc(self,prob,label):
+ pred = np.where(prob > 0.5, 1, 0)
+ judge = (pred == label)
+ zero_num = len(label) - np.count_nonzero(label)
+ acc_fake = np.count_nonzero(judge[zero_num:]) / len(judge[zero_num:])
+ acc_real = np.count_nonzero(judge[:zero_num]) / len(judge[:zero_num])
+ return acc_real,acc_fake
+
+ def test_one_dataset(self, data_loader):
+ # define test recorder
+ test_recorder_loss = defaultdict(Recorder)
+ prediction_lists = []
+ feature_lists=[]
+ label_lists = []
+ for i, data_dict in tqdm(enumerate(data_loader),total=len(data_loader)):
+ # get data
+ if 'label_spe' in data_dict:
+ data_dict.pop('label_spe') # remove the specific label
+ data_dict['label'] = torch.where(data_dict['label']!=0, 1, 0) # fix the label to 0 and 1 only
+ # move data to GPU elegantly
+ for key in data_dict.keys():
+ if data_dict[key]!=None:
+ data_dict[key]=data_dict[key].cuda()
+ # model forward without considering gradient computation
+ predictions = self.inference(data_dict)
+ label_lists += list(data_dict['label'].cpu().detach().numpy())
+ prediction_lists += list(predictions['prob'].cpu().detach().numpy())
+ feature_lists += list(predictions['feat'].cpu().detach().numpy())
+ if type(self.model) is not AveragedModel:
+ # compute all losses for each batch data
+ with torch.no_grad():
+ if type(self.model) is DDP:
+ losses = self.model.module.get_losses(data_dict, predictions)
+ else:
+ losses = self.model.get_losses(data_dict, predictions)
+
+ # store data by recorder
+ for name, value in losses.items():
+ test_recorder_loss[name].update(value)
+
+ return test_recorder_loss, np.array(prediction_lists), np.array(label_lists),np.array(feature_lists)
+
+ def save_best(self,epoch,iteration,step,losses_one_dataset_recorder,key,metric_one_dataset):
+ best_metric = self.best_metrics_all_time[key].get(self.metric_scoring,
+ float('-inf') if self.metric_scoring != 'eer' else float(
+ 'inf'))
+ # Check if the current score is an improvement
+ improved = (metric_one_dataset[self.metric_scoring] > best_metric) if self.metric_scoring != 'eer' else (
+ metric_one_dataset[self.metric_scoring] < best_metric)
+ if improved:
+ # Update the best metric
+ self.best_metrics_all_time[key][self.metric_scoring] = metric_one_dataset[self.metric_scoring]
+ if key == 'avg':
+ self.best_metrics_all_time[key]['dataset_dict'] = metric_one_dataset['dataset_dict']
+ # Save checkpoint, feature, and metrics if specified in config
+ if self.config['save_ckpt'] and key not in FFpp_pool:
+ self.save_ckpt('test', key, f"{epoch}+{iteration}")
+ self.save_metrics('test', metric_one_dataset, key)
+ if losses_one_dataset_recorder is not None:
+ # info for each dataset
+ loss_str = f"dataset: {key} step: {step} "
+ for k, v in losses_one_dataset_recorder.items():
+ writer = self.get_writer('test', key, k)
+ v_avg = v.average()
+ if v_avg == None:
+ print(f'{k} is not calculated')
+ continue
+ # tensorboard-1. loss
+ writer.add_scalar(f'test_losses/{k}', v_avg, global_step=step)
+ loss_str += f"testing-loss, {k}: {v_avg} "
+ self.logger.info(loss_str)
+ # tqdm.write(loss_str)
+ metric_str = f"dataset: {key} step: {step} "
+ for k, v in metric_one_dataset.items():
+ if k == 'pred' or k == 'label' or k=='dataset_dict':
+ continue
+ metric_str += f"testing-metric, {k}: {v} "
+ # tensorboard-2. metric
+ writer = self.get_writer('test', key, k)
+ writer.add_scalar(f'test_metrics/{k}', v, global_step=step)
+ if 'pred' in metric_one_dataset:
+ acc_real, acc_fake = self.get_respect_acc(metric_one_dataset['pred'], metric_one_dataset['label'])
+ metric_str += f'testing-metric, acc_real:{acc_real}; acc_fake:{acc_fake}'
+ writer.add_scalar(f'test_metrics/acc_real', acc_real, global_step=step)
+ writer.add_scalar(f'test_metrics/acc_fake', acc_fake, global_step=step)
+ self.logger.info(metric_str)
+
+ def test_epoch(self, epoch, iteration, test_data_loaders, step):
+ # set model to eval mode
+ self.setEval()
+
+ # define test recorder
+ losses_all_datasets = {}
+ metrics_all_datasets = {}
+ best_metrics_per_dataset = defaultdict(dict) # best metric for each dataset, for each metric
+ avg_metric = {'acc': 0, 'auc': 0, 'eer': 0, 'ap': 0,'video_auc': 0,'dataset_dict':{}}
+ # testing for all test data
+ keys = test_data_loaders.keys()
+ for key in keys:
+ # save the testing data_dict
+ data_dict = test_data_loaders[key].dataset.data_dict
+ self.save_data_dict('test', data_dict, key)
+
+ # compute loss for each dataset
+ losses_one_dataset_recorder, predictions_nps, label_nps, feature_nps = self.test_one_dataset(test_data_loaders[key])
+ # print(f'stack len:{predictions_nps.shape};{label_nps.shape};{len(data_dict["image"])}')
+ losses_all_datasets[key] = losses_one_dataset_recorder
+ metric_one_dataset=get_test_metrics(y_pred=predictions_nps,y_true=label_nps,img_names=data_dict['image'])
+ for metric_name, value in metric_one_dataset.items():
+ if metric_name in avg_metric:
+ avg_metric[metric_name]+=value
+ avg_metric['dataset_dict'][key] = metric_one_dataset[self.metric_scoring]
+ if type(self.model) is AveragedModel:
+ metric_str = f"Iter Final for SWA: "
+ for k, v in metric_one_dataset.items():
+ metric_str += f"testing-metric, {k}: {v} "
+ self.logger.info(metric_str)
+ continue
+ self.save_best(epoch,iteration,step,losses_one_dataset_recorder,key,metric_one_dataset)
+
+ if len(keys)>0 and self.config.get('save_avg',False):
+ # calculate avg value
+ for key in avg_metric:
+ if key != 'dataset_dict':
+ avg_metric[key] /= len(keys)
+ self.save_best(epoch, iteration, step, None, 'avg', avg_metric)
+
+ self.logger.info('===> Test Done!')
+ return self.best_metrics_all_time # return all types of mean metrics for determining the best ckpt
+
+ @torch.no_grad()
+ def inference(self, data_dict):
+ predictions = self.model(data_dict, inference=True)
+ return predictions
diff --git a/clean/image/effort/DeepfakeBench/training/utils/__init__.py b/clean/image/effort/DeepfakeBench/training/utils/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/clean/image/effort/DeepfakeBench/training/utils/metrics.py b/clean/image/effort/DeepfakeBench/training/utils/metrics.py
new file mode 100644
index 0000000000000000000000000000000000000000..b9c69c71b6be0e26822c313fb52b0893808be1ee
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/utils/metrics.py
@@ -0,0 +1,170 @@
+import numpy as np
+from sklearn import metrics
+import torch
+import torch.nn as nn
+
+def get_accracy(output, label):
+ _, prediction = torch.max(output, 1) # argmax
+ correct = (prediction == label).sum().item()
+ accuracy = correct / prediction.size(0)
+
+ return accuracy
+
+
+def get_prediction(output, label):
+ prob = nn.functional.softmax(output, dim=1)[:, 1]
+ prob = prob.view(prob.size(0), 1)
+ label = label.view(label.size(0), 1)
+ #print(prob.size(), label.size())
+ datas = torch.cat((prob, label.float()), dim=1)
+ return datas
+
+
+def calculate_metrics(label, output):
+ if output.size(1) == 2:
+ prob = torch.softmax(output, dim=1)[:, 1]
+ else:
+ prob = output
+
+ # Accuracy
+ _, prediction = torch.max(output, 1)
+ correct = (prediction == label).sum().item()
+ accuracy = correct / prediction.size(0)
+
+ # AUC and EER
+ fpr, tpr, thresholds = metrics.roc_curve(label.squeeze().cpu().numpy(),
+ prob.squeeze().cpu().numpy(),
+ pos_label=1)
+ if np.isnan(fpr[0]) or np.isnan(tpr[0]):
+ auc, eer = -1, -1
+ else:
+ auc = metrics.auc(fpr, tpr)
+ fnr = 1 - tpr
+ eer = fpr[np.nanargmin(np.absolute((fnr - fpr)))]
+
+ # Average Precision
+ y_true = label.cpu().detach().numpy()
+ y_pred = prob.cpu().detach().numpy()
+ ap = metrics.average_precision_score(y_true, y_pred)
+
+ return auc, eer, accuracy, ap
+
+
+# ------------ compute average metrics of batches---------------------
+class Metrics_batches_mean():
+ def __init__(self):
+ self.tprs = []
+ self.mean_fpr = np.linspace(0, 1, 100)
+ self.aucs = []
+ self.eers = []
+ self.aps = []
+
+ self.correct = 0
+ self.total = 0
+
+ def update(self, label, output):
+ acc = self._update_acc(label, output)
+ if output.size(1) == 2:
+ prob = torch.softmax(output, dim=1)[:, 1]
+ else:
+ prob = output
+ #label = 1-label
+ #prob = torch.softmax(output, dim=1)[:, 1]
+ auc, eer = self._update_auc(label, prob)
+ ap = self._update_ap(label, prob)
+
+ return acc, auc, eer, ap
+
+ def _update_auc(self, lab, prob):
+ fpr, tpr, thresholds = metrics.roc_curve(lab.squeeze().cpu().numpy(),
+ prob.squeeze().cpu().numpy(),
+ pos_label=1)
+ if np.isnan(fpr[0]) or np.isnan(tpr[0]):
+ return -1, -1
+
+ auc = metrics.auc(fpr, tpr)
+ interp_tpr = np.interp(self.mean_fpr, fpr, tpr)
+ interp_tpr[0] = 0.0
+ self.tprs.append(interp_tpr)
+ self.aucs.append(auc)
+
+ # return auc
+
+ # EER
+ fnr = 1 - tpr
+ eer = fpr[np.nanargmin(np.absolute((fnr - fpr)))]
+ self.eers.append(eer)
+
+ return auc, eer
+
+ def _update_acc(self, lab, output):
+ _, prediction = torch.max(output, 1) # argmax
+ correct = (prediction == lab).sum().item()
+ accuracy = correct / prediction.size(0)
+ # self.accs.append(accuracy)
+ self.correct = self.correct+correct
+ self.total = self.total+lab.size(0)
+ return accuracy
+
+ def _update_ap(self, label, prob):
+ y_true = label.cpu().detach().numpy()
+ y_pred = prob.cpu().detach().numpy()
+ ap = metrics.average_precision_score(y_true,y_pred)
+ self.aps.append(ap)
+
+ return np.mean(ap)
+
+
+ def get_mean_metrics(self):
+ mean_acc, std_acc = self.correct/self.total, 0
+ mean_auc, std_auc = self._mean_auc()
+ mean_err, std_err = np.mean(self.eers), np.std(self.eers)
+ mean_ap, std_ap = np.mean(self.aps), np.std(self.aps)
+
+ return mean_acc, std_acc, mean_auc, std_auc, mean_err, std_err, mean_ap, std_ap
+
+ def _mean_auc(self):
+ mean_tpr = np.mean(self.tprs, axis=0)
+ mean_tpr[-1] = 1.0
+ mean_auc = metrics.auc(self.mean_fpr, mean_tpr)
+ std_auc = np.std(self.aucs)
+ return mean_auc, std_auc
+
+ def clear(self):
+ self.tprs.clear()
+ self.aucs.clear()
+ # self.accs.clear()
+ self.correct=0
+ self.total=0
+ self.eers.clear()
+ self.aps.clear()
+
+
+class Metrics_all():
+ def __init__(self):
+ self.probs = []
+ self.labels = []
+
+ def store(self, label, output):
+ prob = torch.softmax(output, dim=1)[:, 1]
+ self.labels.append(label.squeeze().cpu().numpy())
+ self.probs.append(prob.squeeze().cpu().numpy())
+
+
+ def get_metrics(self):
+ y_pred = np.concatenate(self.probs)
+ y_true = np.concatenate(self.labels)
+ fpr, tpr, thresholds = metrics.roc_curve(y_true,y_pred,pos_label=1)
+ auc = metrics.auc(fpr, tpr)
+
+ # EER
+ fnr = 1 - tpr
+ eer = fpr[np.nanargmin(np.absolute((fnr - fpr)))]
+
+ ap = metrics.average_precision_score(y_true,y_pred)
+
+ return 0, 0, auc, 0, eer, 0, ap, 0
+
+ def clear(self):
+ self.probs.clear()
+ self.labels.clear()
\ No newline at end of file
diff --git a/clean/image/effort/DeepfakeBench/training/utils/registry.py b/clean/image/effort/DeepfakeBench/training/utils/registry.py
new file mode 100644
index 0000000000000000000000000000000000000000..86e256c18d0ad522de79149a154f676fd0bdb414
--- /dev/null
+++ b/clean/image/effort/DeepfakeBench/training/utils/registry.py
@@ -0,0 +1,20 @@
+class Registry(object):
+ def __init__(self):
+ self.data = {}
+
+ def register_module(self, module_name=None):
+ def _register(cls):
+ name = module_name
+ if module_name is None:
+ name = cls.__name__
+ self.data[name] = cls
+ return cls
+ return _register
+
+ def __getitem__(self, key):
+ return self.data[key]
+
+BACKBONE = Registry()
+DETECTOR = Registry()
+TRAINER = Registry()
+LOSSFUNC = Registry()
diff --git a/clean/image/effort/README.md b/clean/image/effort/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..1b6920c73acefc6c7992e8e59f92924ce2f481d3
--- /dev/null
+++ b/clean/image/effort/README.md
@@ -0,0 +1,182 @@
+# Effort: Orthogonal Subspace Decomposition for Generalizable AI-Generated Image Detection ([Paper](https://arxiv.org/abs/2411.15633); [Checkpoints](https://drive.google.com/drive/folders/19kQwGDjF18uk78EnnypxxOLaG4Aa4v1h?usp=sharing))
+
+[](https://creativecommons.org/licenses/by-nc/4.0/)   
+
+> 🎉🎉🎉 **Our paper has been accepted by ICML 2025 Oral 🏆!**
+
+Welcome to our work **Effort**, for detecting AI-generated images (AIGIs).
+
+In this work, we propose: (1) a **very very easy and effective method** for generalization AIGI detection😀; and (2) a **novel analysis tool** for quantifying the "degree of model's overfitting"😊.
+
+
+The figure below provides a brief introduction to our method: our method can be **plug-and-play inserted** into *any* vit-based large models such as CLIP.
+
+
+
+
+
+
+
+
+If you want to know a **very high-level code implementation of our method**, see below.
+
+```
+# 🟩 Perform SVD on the original weight
+U, S, Vh = torch.linalg.svd(module.weight.data, full_matrices=False)
+
+# 🟨 Keep top r singular components (main weight)
+U_r = U[:, :r] # 🔵 Shape: (out_features, r)
+S_r = S[:r] # 🔵 Shape: (r,)
+Vh_r = Vh[:r, :] # 🔵 Shape: (r, in_features)
+
+# 🟪 Reconstruct the main weight (fixed)
+weight_main = U_r @ torch.diag(S_r) @ Vh_r
+
+# 🟥 Residual components (trainable)
+U_residual = U[:, r:] # 🔵 Shape: (out_features, n - r)
+S_residual = S[r:] # 🔵 Shape: (n - r,)
+Vh_residual = Vh[r:, :] # 🔵 Shape: (n - r, in_features)
+```
+
+If you want to see **more method-specific implementation details**, please see the file [effort_implementation.py](https://github.com/YZY-stack/Effort-AIGI-Detection/blob/main/DeepfakeBench/training/detectors/effort_detector.py).
+
+---
+
+
+The following two tables display the **part results** of our method on **both the (face) deepfake detection benchmark and the (natural) AIGI detection benchmark**. Please refer to our paper for more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+---
+
+
+## ⏳ Quick Start (if you just want to do the *inference*)
+[Back to top]
+
+
+### 1. Installation
+Please run the following script to install the required libraries:
+
+```
+sh install.sh
+```
+
+### 2. Download checkpoints
+If you are a deepfake player, more interested in face deepfake detection:
+- The checkpoint of "CLIP-L14 + our Effort" **training on FaceForensics++** are released at [Google Drive](https://drive.google.com/file/d/1m4fyJecABU-Yk3bJ4b1WhUwQa0xCkMLI/view?usp=drive_link).
+
+If you are interested in detecting general AI-generated images, we provide two checkpoints that are trained on GenImage and Chameleon datasets, respectively:
+- The checkpoint of "CLIP-L14 + our Effort" **training on GenImage (sdv1.4)** are released at [Google Drive](https://drive.google.com/file/d/1UXf1hC9FC1yV93uKwXSkdtepsgpIAU9d/view?usp=sharing).
+- The checkpoint of "CLIP-L14 + our Effort" **training on Chameleon (sdv1.4)** are released at [Google Drive](https://drive.google.com/file/d/1GlJ1y4xmTdqV0FfIcyBwNNU6cQird9DR/view?usp=sharing).
+
+
+### 3. Run demo
+You can then infer **one image *or* one folder with several images** using the pretrained weights.
+
+Specifically, run the following line:
+
+```
+cd DeepfakeBench/
+
+python3 training/demo.py --detector_config training/config/detector/effort.yaml --weights ./training/weights/{NAME_OF_THE_CKPT}.pth --image {IMAGE_PATH or IMAGE_FOLDER}
+```
+
+After running the above line, you can obtain the prediction results (fake probabilities) for each image.
+
+
+Note, you are processing a **face image**, please add the ``--landmark_model ./preprocessing/shape_predictor_81_face_landmarks.dat`` to **extract the facial region** for inference, as our model (trained on face deepfakes) used this face extractor for processing faces.
+
+
+---
+
+
+## 💻 Reproduction and Benchmarking Evaluation
+
+[Back to top]
+
+Since I am the creator and developer of [DeepfakeBench](https://github.com/SCLBD/DeepfakeBench), the **data, codebase, and benchmarking protocols are mainly used from it**. If you are a researcher in (face) deepfake detection, I highly recommend you try DeepfakeBench.
+
+If you want to **try other codebases, such as UnivFD**, we provide a folder `UniversalFakeDetect_Benchmark/` to reproduce and implement our method using its codebase. Using this codebase, you can then **reproduce the results of Table 2 of our manuscript**.
+
+Below, we provide the **detailed procedure to use DeepfakeBench to reproduce the results** of our paper, such as Table 1.
+
+
+### 1. Download datasets
+
+If you want to reproduce the results of each deepfake dataset, you can download the processed datasets (have already finished preprocessing such as frame extraction and face cropping) from [DeepfakeBench](https://github.com/SCLBD/DeepfakeBench). For evaluating more diverse fake methods (such as SimSwap, BlendFace, DeepFaceLab, etc), you are recommended to use the just-released [DF40 dataset](https://github.com/YZY-stack/DF40) (with 40 distinct forgery methods implemented).
+
+
+
+### 2. Preprocessing (**optional**)
+
+If you only want to use the processed data we provided, you can skip this step.
+
+Otherwise, you need to use the following codes for doing **data preprocessing strictly following DeepfakeBench**.
+
+
+### 3. Rearrangement (**optional**)
+
+> "Rearrangment" here means that we need to **create a *JSON file* for each dataset for collecting all frames within different folders**. Please refer to **DeepfakeBench** and **DF40** for the provided JSON files for each dataset.
+
+After running the above line, you will obtain the JSON files for each dataset in the `./preprocessing/dataset_json` folder. The rearranged structure organizes the data in a hierarchical manner, grouping videos based on their labels and data splits (*i.e.,* train, test, validation). Each video is represented as a dictionary entry containing relevant metadata, including file paths, labels, compression levels (if applicable), *etc*.
+
+
+
+### 4. Training
+
+First, you can run the following lines to train the model:
+- For multiple GPUs:
+```
+python3 -m torch.distributed.launch --nproc_per_node=4 training/train.py \
+--detector_path ./training/config/detector/effort.yaml \
+--train_dataset FaceForensics++ \
+--test_dataset Celeb-DF-v2 \
+--ddp
+```
+- For a single GPU:
+```
+python3 training/train.py \
+--detector_path ./training/config/detector/effort.yaml \
+--train_dataset FaceForensics++ \
+--test_dataset Celeb-DF-v2 \
+```
+
+### 5. Testing
+
+Once you finish training, you can test the model on several deepfake datasets such as DF40.
+
+```
+python3 training/test.py \
+--detector_path ./training/config/detector/effort.yaml \
+--test_dataset simswap_ff blendface_ff uniface_ff fomm_ff deepfacelab \
+--weights_path ./training/weights/{CKPT}.pth
+```
+Then, you can obtain similar evaluation results reported in our manuscript.
+
+
+---
+
+## 📕 Citation
+If you find our work helpful to your research, please consider citing our paper as follows:
+```
+@article{yan2024effort,
+ title={Effort: Efficient Orthogonal Modeling for Generalizable AI-Generated Image Detection},
+ author={Yan, Zhiyuan and Wang, Jiangming and Wang, Zhendong and Jin, Peng and Zhang, Ke-Yue and Chen, Shen and Yao, Taiping and Ding, Shouhong and Wu, Baoyuan and Yuan, Li},
+ journal={arXiv preprint arXiv:2411.15633},
+ year={2024}
+}
+```
+
+
diff --git a/clean/image/effort/SOURCE.md b/clean/image/effort/SOURCE.md
new file mode 100644
index 0000000000000000000000000000000000000000..63cebec5b0661dad8fa530ff89f58439a9cd0ad2
--- /dev/null
+++ b/clean/image/effort/SOURCE.md
@@ -0,0 +1,17 @@
+# Source: image/effort
+
+| Field | Value |
+|---|---|
+| Upstream | https://github.com/YZY-stack/Effort-AIGI-Detection |
+| Paper | https://arxiv.org/abs/2411.15633 |
+| Commit SHA | **not recorded** -- the vendoring step did not preserve it |
+| Mirrored on | 2026-09-15 |
+| Upstream license | no license file present upstream (all rights reserved) |
+
+This is a **mirror**, stripped to the files needed for inference. The full
+untouched snapshot is at `archive/image__effort.tar.gz`.
+
+This code is the work of its original authors and is **not** covered by the
+DeepSafe project license. If you are an author and want this removed, open an
+issue on https://github.com/deepsafehq/deepsafe-bench and it will be taken down
+within 48 hours, no questions asked.
diff --git a/clean/image/effort/UniversalFakeDetect_Benchmark/dataset_paths.py b/clean/image/effort/UniversalFakeDetect_Benchmark/dataset_paths.py
new file mode 100644
index 0000000000000000000000000000000000000000..6e5f7ce81c71a410f4b7254760fa713e871b2d38
--- /dev/null
+++ b/clean/image/effort/UniversalFakeDetect_Benchmark/dataset_paths.py
@@ -0,0 +1,136 @@
+DATASET_PATHS = [
+
+ dict(
+ real_path='/Youtu_Pangu_Security_Public/etoilefu/CNNDetection/dataset/test/progan',
+ fake_path='/Youtu_Pangu_Security_Public/etoilefu/CNNDetection/dataset/test/progan',
+ data_mode='wang2020',
+ key='progan'
+ ),
+
+ dict(
+ real_path='/Youtu_Pangu_Security_Public/etoilefu/CNNDetection/dataset/test/cyclegan',
+ fake_path='/Youtu_Pangu_Security_Public/etoilefu/CNNDetection/dataset/test/cyclegan',
+ data_mode='wang2020',
+ key='cyclegan'
+ ),
+
+ dict(
+ real_path='/Youtu_Pangu_Security_Public/etoilefu/CNNDetection/dataset/test/biggan/', # Imagenet
+ fake_path='/Youtu_Pangu_Security_Public/etoilefu/CNNDetection/dataset/test/biggan/',
+ data_mode='wang2020',
+ key='biggan'
+ ),
+
+ dict(
+ real_path='/Youtu_Pangu_Security_Public/etoilefu/CNNDetection/dataset/test/stylegan',
+ fake_path='/Youtu_Pangu_Security_Public/etoilefu/CNNDetection/dataset/test/stylegan',
+ data_mode='wang2020',
+ key='stylegan'
+ ),
+
+ dict(
+ real_path='/Youtu_Pangu_Security_Public/etoilefu/CNNDetection/dataset/test/gaugan', # It is COCO
+ fake_path='/Youtu_Pangu_Security_Public/etoilefu/CNNDetection/dataset/test/gaugan',
+ data_mode='wang2020',
+ key='gaugan'
+ ),
+
+ dict(
+ real_path='/Youtu_Pangu_Security_Public/etoilefu/CNNDetection/dataset/test/stargan',
+ fake_path='/Youtu_Pangu_Security_Public/etoilefu/CNNDetection/dataset/test/stargan',
+ data_mode='wang2020',
+ key='stargan'
+ ),
+
+ dict(
+ real_path='/Youtu_Pangu_Security_Public/etoilefu/CNNDetection/dataset/test/deepfake',
+ fake_path='/Youtu_Pangu_Security_Public/etoilefu/CNNDetection/dataset/test/deepfake',
+ data_mode='wang2020',
+ key='deepfake'
+ ),
+
+ dict(
+ real_path='/Youtu_Pangu_Security_Public/etoilefu/CNNDetection/dataset/test/seeingdark',
+ fake_path='/Youtu_Pangu_Security_Public/etoilefu/CNNDetection/dataset/test/seeingdark',
+ data_mode='wang2020',
+ key='sitd'
+ ),
+
+ dict(
+ real_path='/Youtu_Pangu_Security_Public/etoilefu/CNNDetection/dataset/test/san',
+ fake_path='/Youtu_Pangu_Security_Public/etoilefu/CNNDetection/dataset/test/san',
+ data_mode='wang2020',
+ key='san'
+ ),
+
+ dict(
+ real_path='/Youtu_Pangu_Security_Public/etoilefu/CNNDetection/dataset/test/crn', # Images from some video games
+ fake_path='/Youtu_Pangu_Security_Public/etoilefu/CNNDetection/dataset/test/crn',
+ data_mode='wang2020',
+ key='crn'
+ ),
+
+ dict(
+ real_path='/Youtu_Pangu_Security_Public/etoilefu/CNNDetection/dataset/test/imle', # Images from some video games
+ fake_path='/Youtu_Pangu_Security_Public/etoilefu/CNNDetection/dataset/test/imle',
+ data_mode='wang2020',
+ key='imle'
+ ),
+
+ dict(
+ real_path='/Youtu_Pangu_Security/jeremiewang/dataset/open/diffusion_datasets/imagenet',
+ fake_path='/Youtu_Pangu_Security/jeremiewang/dataset/open/diffusion_datasets/guided',
+ data_mode='wang2020',
+ key='guided'
+ ),
+
+ dict(
+ real_path='/Youtu_Pangu_Security/jeremiewang/dataset/open/diffusion_datasets/laion',
+ fake_path='/Youtu_Pangu_Security/jeremiewang/dataset/open/diffusion_datasets/ldm_200',
+ data_mode='wang2020',
+ key='ldm_200'
+ ),
+
+ dict(
+ real_path='/Youtu_Pangu_Security/jeremiewang/dataset/open/diffusion_datasets/laion',
+ fake_path='/Youtu_Pangu_Security/jeremiewang/dataset/open/diffusion_datasets/ldm_200_cfg',
+ data_mode='wang2020',
+ key='ldm_200_cfg'
+ ),
+
+ dict(
+ real_path='/Youtu_Pangu_Security/jeremiewang/dataset/open/diffusion_datasets/laion',
+ fake_path='/Youtu_Pangu_Security/jeremiewang/dataset/open/diffusion_datasets/ldm_100',
+ data_mode='wang2020',
+ key='ldm_100'
+ ),
+
+ dict(
+ real_path='/Youtu_Pangu_Security/jeremiewang/dataset/open/diffusion_datasets/laion',
+ fake_path='/Youtu_Pangu_Security/jeremiewang/dataset/open/diffusion_datasets/glide_100_27',
+ data_mode='wang2020',
+ key='glide_100_27'
+ ),
+
+ dict(
+ real_path='/Youtu_Pangu_Security/jeremiewang/dataset/open/diffusion_datasets/laion',
+ fake_path='/Youtu_Pangu_Security/jeremiewang/dataset/open/diffusion_datasets/glide_50_27',
+ data_mode='wang2020',
+ key='glide_50_27'
+ ),
+
+ dict(
+ real_path='/Youtu_Pangu_Security/jeremiewang/dataset/open/diffusion_datasets/laion',
+ fake_path='/Youtu_Pangu_Security/jeremiewang/dataset/open/diffusion_datasets/glide_100_10',
+ data_mode='wang2020',
+ key='glide_100_10'
+ ),
+
+ dict(
+ real_path='/Youtu_Pangu_Security/jeremiewang/dataset/open/diffusion_datasets/laion',
+ fake_path='/Youtu_Pangu_Security/jeremiewang/dataset/open/diffusion_datasets/dalle',
+ data_mode='wang2020',
+ key='dalle'
+ ),
+
+]
diff --git a/clean/image/effort/UniversalFakeDetect_Benchmark/earlystop.py b/clean/image/effort/UniversalFakeDetect_Benchmark/earlystop.py
new file mode 100644
index 0000000000000000000000000000000000000000..01296e3419acddaf0e92a69477fddb3be9440cf5
--- /dev/null
+++ b/clean/image/effort/UniversalFakeDetect_Benchmark/earlystop.py
@@ -0,0 +1,44 @@
+import numpy as np
+import torch
+
+
+class EarlyStopping:
+ """Early stops the training if validation loss doesn't improve after a given patience."""
+ def __init__(self, patience=1, verbose=False, delta=0):
+ """
+ Args:
+ patience (int): How long to wait after last time validation loss improved.
+ Default: 7
+ verbose (bool): If True, prints a message for each validation loss improvement.
+ Default: False
+ delta (float): Minimum change in the monitored quantity to qualify as an improvement.
+ Default: 0
+ """
+ self.patience = patience
+ self.verbose = verbose
+ self.counter = 0
+ self.best_score = None
+ self.early_stop = False
+ self.score_max = -np.Inf
+ self.delta = delta
+
+ def __call__(self, score, model):
+ if self.best_score is None:
+ self.best_score = score
+ self.save_checkpoint(score, model)
+ elif score < self.best_score - self.delta:
+ self.counter += 1
+ print(f'EarlyStopping counter: {self.counter} out of {self.patience}')
+ if self.counter >= self.patience:
+ self.early_stop = True
+ else:
+ self.best_score = score
+ self.save_checkpoint(score, model)
+ self.counter = 0
+
+ def save_checkpoint(self, score, model):
+ '''Saves model when validation loss decrease.'''
+ if self.verbose:
+ print(f'Validation accuracy increased ({self.score_max:.6f} --> {score:.6f}). Saving model ...')
+ model.save_networks('best')
+ self.score_max = score
\ No newline at end of file
diff --git a/clean/image/effort/UniversalFakeDetect_Benchmark/models/__init__.py b/clean/image/effort/UniversalFakeDetect_Benchmark/models/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..4417c51d2232e5bf7febbdf1b07582f7a4d1524e
--- /dev/null
+++ b/clean/image/effort/UniversalFakeDetect_Benchmark/models/__init__.py
@@ -0,0 +1,18 @@
+from .clip_models import ClipModel
+
+
+VALID_NAMES = {
+ 'CLIP:ViT-B/16_svd':'/Youtu_Pangu_Security_Public/youtu-pangu-public/jeremiewang/pretrained_model/huggingface/openai/clip-vit-base-patch16/',
+ 'CLIP:ViT-B/32_svd':'/Youtu_Pangu_Security_Public/youtu-pangu-public/jeremiewang/pretrained_model/huggingface/openai/clip-vit-base-patch32/',
+ 'CLIP:ViT-L/14_svd':'/Youtu_Pangu_Security_Public/youtu-pangu-public/zhiyuanyan/huggingface/hub/models--openai--clip-vit-large-patch14/snapshots/32bd64288804d66eefd0ccbe215aa642df71cc41/',
+ 'SigLIP:ViT-L/16_256_svd':'/Youtu_Pangu_Security_Public/youtu-pangu-public/jeremiewang/pretrained_model/huggingface/google/siglip-large-patch16-256/',
+ 'BEiTv2:ViT-L/16_svd':'/Youtu_Pangu_Security_Public/youtu-pangu-public/jeremiewang/pretrained_model/BEiT-v2/beitv2_large_patch16_224_pt1k_ft21k.pth',
+}
+
+
+def get_model(name, opt):
+ assert name in VALID_NAMES.keys()
+ if name.startswith("CLIP:"):
+ return ClipModel(VALID_NAMES[name], opt)
+ else:
+ assert False
diff --git a/clean/image/effort/UniversalFakeDetect_Benchmark/models/base_model.py b/clean/image/effort/UniversalFakeDetect_Benchmark/models/base_model.py
new file mode 100644
index 0000000000000000000000000000000000000000..684bdd31004eb9d5664da1aba08dc3ba3b7c4d80
--- /dev/null
+++ b/clean/image/effort/UniversalFakeDetect_Benchmark/models/base_model.py
@@ -0,0 +1,58 @@
+import os
+import torch
+import torch.nn as nn
+from torch.nn import init
+from torch.optim import lr_scheduler
+
+
+class BaseModel(nn.Module):
+ def __init__(self, opt):
+ super(BaseModel, self).__init__()
+ self.opt = opt
+ self.total_steps = 0
+ self.save_dir = os.path.join(opt.checkpoints_dir, opt.name)
+ self.device = torch.device('cuda:{}'.format(opt.gpu_ids[0])) if opt.gpu_ids else torch.device('cpu')
+
+ def save_networks(self, save_filename):
+ save_path = os.path.join(self.save_dir, save_filename)
+
+ # serialize model and optimizer to dict
+ state_dict = {
+ 'model': self.model.state_dict(),
+ 'optimizer' : self.optimizer.state_dict(),
+ 'total_steps' : self.total_steps,
+ }
+
+ torch.save(state_dict, save_path)
+
+
+ def eval(self):
+ self.model.eval()
+
+ def test(self):
+ with torch.no_grad():
+ self.forward()
+
+
+def init_weights(net, init_type='normal', gain=0.02):
+ def init_func(m):
+ classname = m.__class__.__name__
+ if hasattr(m, 'weight') and (classname.find('Conv') != -1 or classname.find('Linear') != -1):
+ if init_type == 'normal':
+ init.normal_(m.weight.data, 0.0, gain)
+ elif init_type == 'xavier':
+ init.xavier_normal_(m.weight.data, gain=gain)
+ elif init_type == 'kaiming':
+ init.kaiming_normal_(m.weight.data, a=0, mode='fan_in')
+ elif init_type == 'orthogonal':
+ init.orthogonal_(m.weight.data, gain=gain)
+ else:
+ raise NotImplementedError('initialization method [%s] is not implemented' % init_type)
+ if hasattr(m, 'bias') and m.bias is not None:
+ init.constant_(m.bias.data, 0.0)
+ elif classname.find('BatchNorm2d') != -1:
+ init.normal_(m.weight.data, 1.0, gain)
+ init.constant_(m.bias.data, 0.0)
+
+ print('initialize network with %s' % init_type)
+ net.apply(init_func)
diff --git a/clean/image/effort/UniversalFakeDetect_Benchmark/models/clip_models.py b/clean/image/effort/UniversalFakeDetect_Benchmark/models/clip_models.py
new file mode 100644
index 0000000000000000000000000000000000000000..1b787f0ebb2ec915e2960ce462e35d0356d91ccf
--- /dev/null
+++ b/clean/image/effort/UniversalFakeDetect_Benchmark/models/clip_models.py
@@ -0,0 +1,167 @@
+import math
+from PIL import Image
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+from transformers import AutoProcessor, CLIPModel, ViTModel, ViTConfig
+import loralib as lora
+
+
+class ClipModel(nn.Module):
+ def __init__(self, name, opt, num_classes=1):
+ super(ClipModel, self).__init__()
+ self.use_svd = opt.use_svd
+
+ if self.use_svd:
+ self.model = CLIPModel.from_pretrained(name)
+ self.model.vision_model = apply_svd_residual_to_self_attn(self.model.vision_model, r=1024-1)
+
+ for name, param in self.model.vision_model.named_parameters():
+ print('{}: {}'.format(name, param.requires_grad))
+ num_param = sum(p.numel() for p in self.model.vision_model.parameters() if p.requires_grad)
+ num_total_param = sum(p.numel() for p in self.model.vision_model.parameters())
+ print('Number of total parameters: {}, tunable parameters: {}'.format(num_total_param, num_param))
+
+ self.fc = nn.Linear( 1024, num_classes )
+ else:
+ self.model = CLIPModel.from_pretrained(name)
+
+ for name, param in self.model.vision_model.named_parameters():
+ print('{}: {}'.format(name, param.requires_grad))
+ num_param = sum(p.numel() for p in self.model.vision_model.parameters() if p.requires_grad)
+ num_total_param = sum(p.numel() for p in self.model.vision_model.parameters())
+ print('Number of total parameters: {}, tunable parameters: {}'.format(num_total_param, num_param))
+
+ self.fc = nn.Linear( 1024, num_classes )
+
+ def forward(self, x, return_feature=False):
+ features = self.model.vision_model(x)['pooler_output']
+
+ if return_feature:
+ return features
+ return self.fc(features)
+
+
+# Custom module to represent the residual using SVD components
+class SVDResidualLinear(nn.Module):
+ def __init__(self, in_features, out_features, r, bias=True, init_weight=None):
+ super(SVDResidualLinear, self).__init__()
+ self.in_features = in_features
+ self.out_features = out_features
+ self.r = r # Number of top singular values to exclude
+
+ # Main weight (fixed)
+ self.weight_main = nn.Parameter(torch.Tensor(out_features, in_features), requires_grad=False)
+ if init_weight is not None:
+ self.weight_main.data.copy_(init_weight)
+ else:
+ nn.init.kaiming_uniform_(self.weight_main, a=math.sqrt(5))
+
+ # Bias
+ if bias:
+ self.bias = nn.Parameter(torch.Tensor(out_features))
+ nn.init.zeros_(self.bias)
+ else:
+ self.register_parameter('bias', None)
+
+ # SVD components
+ self.S_r = None
+ self.U_r = None
+ self.V_r = None
+ self.S_residual = None
+ self.U_residual = None
+ self.V_residual = None
+
+ def forward(self, x):
+ if self.S_residual is not None:
+ # Reconstruct the residual weight
+ residual_weight = self.U_residual @ torch.diag(self.S_residual) @ self.V_residual
+ # Total weight is the fixed main weight plus the residual
+ weight = self.weight_main + residual_weight
+ else:
+ # If residual components are not set, use only the main weight
+ weight = self.weight_main
+
+ return F.linear(x, weight, self.bias)
+
+
+# Function to replace nn.Linear modules within self_attn modules with SVDResidualLinear
+def apply_svd_residual_to_self_attn(model, r):
+ for name, module in model.named_children():
+ # if ('self_attn' in name) or ('mlp' in name):
+ if ('self_attn' in name):
+ # Replace nn.Linear layers in this module
+ for sub_name, sub_module in module.named_modules():
+ if isinstance(sub_module, nn.Linear):
+ # Get parent module within self_attn
+ parent_module = module
+ sub_module_names = sub_name.split('.')
+ for module_name in sub_module_names[:-1]:
+ parent_module = getattr(parent_module, module_name)
+ # Replace the nn.Linear layer with SVDResidualLinear
+ setattr(parent_module, sub_module_names[-1], replace_with_svd_residual(sub_module, r))
+ else:
+ # Recursively apply to child modules
+ apply_svd_residual_to_self_attn(module, r)
+ # After replacing, set requires_grad for residual components
+ for param_name, param in model.named_parameters():
+ if any(x in param_name for x in ['S_residual', 'U_residual', 'V_residual']):
+ param.requires_grad = True
+ else:
+ param.requires_grad = False
+ return model
+
+
+# Function to replace a module with SVDResidualLinear
+def replace_with_svd_residual(module, r):
+ if isinstance(module, nn.Linear):
+ in_features = module.in_features
+ out_features = module.out_features
+ bias = module.bias is not None
+
+ # Create SVDResidualLinear module
+ new_module = SVDResidualLinear(in_features, out_features, r, bias=bias, init_weight=module.weight.data.clone())
+
+ if bias and module.bias is not None:
+ new_module.bias.data.copy_(module.bias.data)
+
+ # Calculate the frobenius norm of original weight
+ new_module.weight_original_fnorm = torch.norm(module.weight.data, p='fro')
+
+ # Perform SVD on the original weight
+ U, S, Vh = torch.linalg.svd(module.weight.data, full_matrices=False)
+
+ # Determine r based on the rank of the weight matrix
+ r = min(r, len(S)) # Ensure r does not exceed the number of singular values
+
+ # Keep top r singular components (main weight)
+ U_r = U[:, :r] # Shape: (out_features, r)
+ S_r = S[:r] # Shape: (r,)
+ Vh_r = Vh[:r, :] # Shape: (r, in_features)
+
+ # Reconstruct the main weight (fixed)
+ weight_main = U_r @ torch.diag(S_r) @ Vh_r
+
+ # Calculate the frobenius norm of main weight
+ new_module.weight_main_fnorm = torch.norm(weight_main.data, p='fro')
+
+ # Set the main weight
+ new_module.weight_main.data.copy_(weight_main)
+
+ # Residual components (trainable)
+ U_residual = U[:, r:] # Shape: (out_features, n - r)
+ S_residual = S[r:] # Shape: (n - r,)
+ Vh_residual = Vh[r:, :] # Shape: (n - r, in_features)
+
+ if len(S_residual) > 0:
+ new_module.S_residual = nn.Parameter(S_residual.clone())
+ new_module.U_residual = nn.Parameter(U_residual.clone())
+ new_module.V_residual = nn.Parameter(Vh_residual.clone())
+ else:
+ new_module.S_residual = None
+ new_module.U_residual = None
+ new_module.V_residual = None
+
+ return new_module
+ else:
+ return module
\ No newline at end of file
diff --git a/clean/image/effort/UniversalFakeDetect_Benchmark/models/trainer.py b/clean/image/effort/UniversalFakeDetect_Benchmark/models/trainer.py
new file mode 100644
index 0000000000000000000000000000000000000000..fd9d5e7cd0c6a1aa1adcafb0c3550ec4ce002404
--- /dev/null
+++ b/clean/image/effort/UniversalFakeDetect_Benchmark/models/trainer.py
@@ -0,0 +1,71 @@
+import functools
+import torch
+import torch.nn as nn
+from .base_model import BaseModel, init_weights
+import sys
+from models import get_model
+
+
+class Trainer(BaseModel):
+ def name(self):
+ return 'Trainer'
+
+ def __init__(self, opt):
+ super(Trainer, self).__init__(opt)
+ self.opt = opt
+ self.model = get_model(opt.arch, opt)
+ self.lr = opt.lr
+ torch.nn.init.normal_(self.model.fc.weight.data, 0.0, opt.init_gain)
+
+ if opt.fix_backbone:
+ params = []
+ for name, p in self.model.named_parameters():
+ if name=="fc.weight" or name=="fc.bias":
+ params.append(p)
+ else:
+ p.requires_grad = False
+ else:
+ print("Your backbone is not fixed. Are you sure you want to proceed? If this is a mistake, enable the --fix_backbone command during training and rerun")
+ # import time
+ # time.sleep(3)
+ params = self.model.parameters()
+
+ if opt.optim == 'adam':
+ self.optimizer = torch.optim.AdamW(params, lr=opt.lr, betas=(opt.beta1, 0.999), weight_decay=opt.weight_decay)
+ elif opt.optim == 'sgd':
+ self.optimizer = torch.optim.SGD(params, lr=opt.lr, momentum=0.0, weight_decay=opt.weight_decay)
+ else:
+ raise ValueError("optim should be [adam, sgd]")
+
+ self.loss_fn = nn.BCEWithLogitsLoss()
+
+ self.model.to(opt.gpu_ids[0])
+
+ def adjust_learning_rate(self, min_lr=1e-6):
+ for param_group in self.optimizer.param_groups:
+ param_group['lr'] *= 0.8
+ self.lr = param_group['lr']
+ if param_group['lr'] < min_lr:
+ return False
+ return True
+
+ def set_input(self, input):
+ self.input = input[0].to(self.device)
+ self.label = input[1].to(self.device).float()
+
+ def forward(self):
+ self.output = self.model(self.input)
+ self.output = self.output.view(-1).unsqueeze(1)
+
+ def get_loss(self):
+ return self.loss_fn(self.output.squeeze(1), self.label)
+
+ def optimize_parameters(self):
+ self.forward()
+ self.loss = self.loss_fn(self.output.squeeze(1), self.label)
+ self.optimizer.zero_grad()
+ self.loss.backward()
+ self.optimizer.step()
+
+
+
diff --git a/clean/image/effort/UniversalFakeDetect_Benchmark/options/__init__.py b/clean/image/effort/UniversalFakeDetect_Benchmark/options/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/clean/image/effort/UniversalFakeDetect_Benchmark/options/base_options.py b/clean/image/effort/UniversalFakeDetect_Benchmark/options/base_options.py
new file mode 100644
index 0000000000000000000000000000000000000000..e669d7256f54d7f75e2a11c9e892ca3547f2be29
--- /dev/null
+++ b/clean/image/effort/UniversalFakeDetect_Benchmark/options/base_options.py
@@ -0,0 +1,118 @@
+import argparse
+import os
+import util
+import torch
+
+
+class BaseOptions():
+ def __init__(self):
+ self.initialized = False
+
+ def initialize(self, parser):
+ parser.add_argument('--mode', default='binary')
+ parser.add_argument('--arch', type=str, default='res50', help='see my_models/__init__.py')
+ parser.add_argument('--fix_backbone', action='store_true')
+ parser.add_argument('--use_svd', action='store_true')
+
+ # data augmentation
+ parser.add_argument('--rz_interp', default='bilinear')
+ parser.add_argument('--blur_prob', type=float, default=0.5)
+ parser.add_argument('--blur_sig', default='0.0,3.0')
+ parser.add_argument('--jpg_prob', type=float, default=0.5)
+ parser.add_argument('--jpg_method', default='cv2,pil')
+ parser.add_argument('--jpg_qual', default='30,100')
+
+
+ parser.add_argument('--real_list_path', default=None, help='only used if data_mode==ours: path for the list of real images, which should contain train.pickle and val.pickle')
+ parser.add_argument('--fake_list_path', default=None, help='only used if data_mode==ours: path for the list of fake images, which should contain train.pickle and val.pickle')
+ parser.add_argument('--wang2020_data_path', default=None, help='only used if data_mode==wang2020 it should contain train and test folders')
+ parser.add_argument('--data_mode', default='ours', help='wang2020 or ours')
+ parser.add_argument('--data_label', default='train', help='label to decide whether train or validation dataset')
+ parser.add_argument('--weight_decay', type=float, default=0.0, help='loss weight for l2 reg')
+
+ parser.add_argument('--class_bal', action='store_true') # what is this ?
+ parser.add_argument('--batch_size', type=int, default=256, help='input batch size')
+ parser.add_argument('--loadSize', type=int, default=256, help='scale images to this size')
+ parser.add_argument('--cropSize', type=int, default=224, help='then crop to this size')
+ parser.add_argument('--gpu_ids', type=str, default='0', help='gpu ids: e.g. 0 0,1,2, 0,2. use -1 for CPU')
+ parser.add_argument('--name', type=str, default='experiment_name', help='name of the experiment. It decides where to store samples and models')
+ parser.add_argument('--num_threads', default=4, type=int, help='# threads for loading data')
+ parser.add_argument('--checkpoints_dir', type=str, default='./checkpoints', help='models are saved here')
+ parser.add_argument('--serial_batches', action='store_true', help='if true, takes images in order to make batches, otherwise takes them randomly')
+ parser.add_argument('--resize_or_crop', type=str, default='scale_and_crop', help='scaling and cropping of images at load time [resize_and_crop|crop|scale_width|scale_width_and_crop|none]')
+ parser.add_argument('--no_flip', action='store_true', help='if specified, do not flip the images for data augmentation')
+ parser.add_argument('--init_type', type=str, default='normal', help='network initialization [normal|xavier|kaiming|orthogonal]')
+ parser.add_argument('--init_gain', type=float, default=0.02, help='scaling factor for normal, xavier and orthogonal.')
+ parser.add_argument('--suffix', default='', type=str, help='customized suffix: opt.name = opt.name + suffix: e.g., {model}_{netG}_size{loadSize}')
+ self.initialized = True
+ return parser
+
+ def gather_options(self):
+ # initialize parser with basic options
+ if not self.initialized:
+ parser = argparse.ArgumentParser(
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+ parser = self.initialize(parser)
+
+ # get the basic options
+ opt, _ = parser.parse_known_args()
+ self.parser = parser
+
+ return parser.parse_args()
+
+ def print_options(self, opt):
+ message = ''
+ message += '----------------- Options ---------------\n'
+ for k, v in sorted(vars(opt).items()):
+ comment = ''
+ default = self.parser.get_default(k)
+ if v != default:
+ comment = '\t[default: %s]' % str(default)
+ message += '{:>25}: {:<30}{}\n'.format(str(k), str(v), comment)
+ message += '----------------- End -------------------'
+ print(message)
+
+ # save to the disk
+ expr_dir = os.path.join(opt.checkpoints_dir, opt.name)
+ util.mkdirs(expr_dir)
+ file_name = os.path.join(expr_dir, 'opt.txt')
+ with open(file_name, 'wt') as opt_file:
+ opt_file.write(message)
+ opt_file.write('\n')
+
+ def parse(self, print_options=True):
+
+ opt = self.gather_options()
+ opt.isTrain = self.isTrain # train or test
+
+ # process opt.suffix
+ if opt.suffix:
+ suffix = ('_' + opt.suffix.format(**vars(opt))) if opt.suffix != '' else ''
+ opt.name = opt.name + suffix
+
+ if print_options:
+ self.print_options(opt)
+
+ # set gpu ids
+ str_ids = opt.gpu_ids.split(',')
+ opt.gpu_ids = []
+ for str_id in str_ids:
+ id = int(str_id)
+ if id >= 0:
+ opt.gpu_ids.append(id)
+ if len(opt.gpu_ids) > 0:
+ torch.cuda.set_device(opt.gpu_ids[0])
+
+ # additional
+ #opt.classes = opt.classes.split(',')
+ opt.rz_interp = opt.rz_interp.split(',')
+ opt.blur_sig = [float(s) for s in opt.blur_sig.split(',')]
+ opt.jpg_method = opt.jpg_method.split(',')
+ opt.jpg_qual = [int(s) for s in opt.jpg_qual.split(',')]
+ if len(opt.jpg_qual) == 2:
+ opt.jpg_qual = list(range(opt.jpg_qual[0], opt.jpg_qual[1] + 1))
+ elif len(opt.jpg_qual) > 2:
+ raise ValueError("Shouldn't have more than 2 values for --jpg_qual.")
+
+ self.opt = opt
+ return self.opt
diff --git a/clean/image/effort/UniversalFakeDetect_Benchmark/options/test_options.py b/clean/image/effort/UniversalFakeDetect_Benchmark/options/test_options.py
new file mode 100644
index 0000000000000000000000000000000000000000..f824c7aae81d325bf81e16c5a5e2c1931ccd5b34
--- /dev/null
+++ b/clean/image/effort/UniversalFakeDetect_Benchmark/options/test_options.py
@@ -0,0 +1,13 @@
+from .base_options import BaseOptions
+
+
+class TestOptions(BaseOptions):
+ def initialize(self, parser):
+ parser = BaseOptions.initialize(self, parser)
+ parser.add_argument('--model_path')
+ parser.add_argument('--no_resize', action='store_true')
+ parser.add_argument('--no_crop', action='store_true')
+ parser.add_argument('--eval', action='store_true', help='use eval mode during test time.')
+
+ self.isTrain = False
+ return parser
diff --git a/clean/image/effort/UniversalFakeDetect_Benchmark/options/train_options.py b/clean/image/effort/UniversalFakeDetect_Benchmark/options/train_options.py
new file mode 100644
index 0000000000000000000000000000000000000000..032cd8129f09fb6ed487c74d8d9eb72eb7798cc8
--- /dev/null
+++ b/clean/image/effort/UniversalFakeDetect_Benchmark/options/train_options.py
@@ -0,0 +1,22 @@
+from .base_options import BaseOptions
+
+
+class TrainOptions(BaseOptions):
+ def initialize(self, parser):
+ parser = BaseOptions.initialize(self, parser)
+ parser.add_argument('--earlystop_epoch', type=int, default=5)
+ parser.add_argument('--data_aug', action='store_true', help='if specified, perform additional data augmentation (photometric, blurring, jpegging)')
+ parser.add_argument('--optim', type=str, default='adam', help='optim to use [sgd, adam]')
+ parser.add_argument('--new_optim', action='store_true', help='new optimizer instead of loading the optim state')
+ parser.add_argument('--loss_freq', type=int, default=500, help='frequency of showing loss on tensorboard')
+ parser.add_argument('--save_epoch_freq', type=int, default=1, help='frequency of saving checkpoints at the end of epochs')
+ parser.add_argument('--epoch_count', type=int, default=1, help='the starting epoch count, we save the model by , +, ...')
+ parser.add_argument('--last_epoch', type=int, default=-1, help='starting epoch count for scheduler intialization')
+ parser.add_argument('--train_split', type=str, default='train', help='train, val, test, etc')
+ parser.add_argument('--val_split', type=str, default='val', help='train, val, test, etc')
+ parser.add_argument('--niter', type=int, default=100, help='total epoches')
+ parser.add_argument('--beta1', type=float, default=0.9, help='momentum term of adam')
+ parser.add_argument('--lr', type=float, default=0.0001, help='initial learning rate for adam')
+
+ self.isTrain = True
+ return parser
diff --git a/clean/image/effort/UniversalFakeDetect_Benchmark/results/clip_vitl14_svd/iters_18000/acc0.txt b/clean/image/effort/UniversalFakeDetect_Benchmark/results/clip_vitl14_svd/iters_18000/acc0.txt
new file mode 100644
index 0000000000000000000000000000000000000000..20d1b1750ede60d5629fe80e2f9113fbe7a4615c
--- /dev/null
+++ b/clean/image/effort/UniversalFakeDetect_Benchmark/results/clip_vitl14_svd/iters_18000/acc0.txt
@@ -0,0 +1,41 @@
+-----------------------------------------
+thres: 0.5
+progan: 100.0 100.0 100.0
+thres: 0.5
+cyclegan: 99.7 100.0 99.85
+thres: 0.5
+biggan: 99.5 99.7 99.6
+thres: 0.5
+stylegan: 100.0 90.1 95.05
+thres: 0.5
+gaugan: 99.2 100.0 99.6
+thres: 0.5
+stargan: 100.0 100.0 100.0
+thres: 0.5
+deepfake: 100.0 75.2 87.6
+thres: 0.5
+sitd: 91.0 94.0 92.5
+thres: 0.5
+san: 100.0 62.0 81.0
+thres: 0.5
+crn: 97.8 100.0 98.9
+thres: 0.5
+imle: 97.8 100.0 98.9
+thres: 0.5
+guided: 99.7 38.6 69.15
+thres: 0.5
+ldm_200: 100.0 98.6 99.3
+thres: 0.5
+ldm_200_cfg: 100.0 93.6 96.8
+thres: 0.5
+ldm_100: 100.0 98.9 99.45
+thres: 0.5
+glide_100_27: 100.0 94.9 97.45
+thres: 0.5
+glide_50_27: 100.0 95.6 97.8
+thres: 0.5
+glide_100_10: 100.0 94.3 97.15
+thres: 0.5
+dalle: 100.0 96.1 98.05
+avg: 99.19 91.14 95.17
+-----------------------------------------
diff --git a/clean/image/effort/UniversalFakeDetect_Benchmark/results/clip_vitl14_svd/iters_18000/acc1.txt b/clean/image/effort/UniversalFakeDetect_Benchmark/results/clip_vitl14_svd/iters_18000/acc1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b7fe24ac7b9f259fc9bfc41c866db2b88c34319e
--- /dev/null
+++ b/clean/image/effort/UniversalFakeDetect_Benchmark/results/clip_vitl14_svd/iters_18000/acc1.txt
@@ -0,0 +1,41 @@
+-----------------------------------------
+thres: 0.5002928899193648
+progan: 100.0 100.0 100.0
+thres: 0.999847412109375
+cyclegan: 99.9 99.9 99.9
+thres: 0.9992189407348633
+biggan: 100.0 99.4 99.7
+thres: 4.657595854951069e-05
+stylegan: 100.0 97.1 98.55
+thres: 0.998432993888855
+gaugan: 100.0 100.0 100.0
+thres: 0.5262151546776295
+stargan: 100.0 100.0 100.0
+thres: 0.002418691059574485
+deepfake: 98.2 93.7 95.95
+thres: 0.892815351486206
+sitd: 97.0 92.0 94.5
+thres: 0.0004463841032702476
+san: 96.0 82.0 89.0
+thres: 0.9999018907546997
+crn: 99.8 99.8 99.8
+thres: 0.9999430179595947
+imle: 99.8 99.7 99.75
+thres: 4.349513255874626e-05
+guided: 87.0 89.2 88.1
+thres: 0.011746786534786224
+ldm_200: 100.0 99.2 99.6
+thres: 0.001133577199652791
+ldm_200_cfg: 99.7 98.5 99.1
+thres: 0.0033982524182647467
+ldm_100: 99.9 99.8 99.85
+thres: 0.0011845811968669295
+glide_100_27: 99.7 98.4 99.05
+thres: 0.001386432908475399
+glide_50_27: 99.7 99.2 99.45
+thres: 0.0010550597216933966
+glide_100_10: 99.6 99.2 99.4
+thres: 0.0013092183507978916
+dalle: 99.7 98.8 99.25
+avg: 98.74 98.74 97.94
+-----------------------------------------
diff --git a/clean/image/effort/UniversalFakeDetect_Benchmark/results/clip_vitl14_svd/iters_18000/ap.txt b/clean/image/effort/UniversalFakeDetect_Benchmark/results/clip_vitl14_svd/iters_18000/ap.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4a936910fd1b6d3b4adc30b0d983727ecdb97f31
--- /dev/null
+++ b/clean/image/effort/UniversalFakeDetect_Benchmark/results/clip_vitl14_svd/iters_18000/ap.txt
@@ -0,0 +1,22 @@
+-----------------------------------------
+progan: 100.0
+cyclegan: 100.0
+biggan: 99.99
+stylegan: 99.77
+gaugan: 100.0
+stargan: 100.0
+deepfake: 98.95
+sitd: 97.53
+san: 96.22
+crn: 100.0
+imle: 100.0
+guided: 95.39
+ldm_200: 99.99
+ldm_200_cfg: 99.89
+ldm_100: 100.0
+glide_100_27: 99.87
+glide_50_27: 99.92
+glide_100_10: 99.98
+dalle: 99.96
+avg: 99.34
+-----------------------------------------
diff --git a/clean/image/effort/UniversalFakeDetect_Benchmark/script/test.sh b/clean/image/effort/UniversalFakeDetect_Benchmark/script/test.sh
new file mode 100644
index 0000000000000000000000000000000000000000..6c651ebdf9489c1d06f9982d0704d97897210c5f
--- /dev/null
+++ b/clean/image/effort/UniversalFakeDetect_Benchmark/script/test.sh
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+
+PYTHONPATH="$(dirname $0)/..":$PYTHONPATH \
+CUDA_VISIBLE_DEVICES=0 python validate.py \
+ --arch CLIP:ViT-L/14_svd \
+ --ckpt checkpoints/clip_vitl14_svd/model_iters_18000.pth \
+ --result_folder results/clip_vitl14_svd/iters_18000 \
+ --use_svd
\ No newline at end of file
diff --git a/clean/image/effort/UniversalFakeDetect_Benchmark/script/train_svd.sh b/clean/image/effort/UniversalFakeDetect_Benchmark/script/train_svd.sh
new file mode 100644
index 0000000000000000000000000000000000000000..7d7f0449c9c17821a74ba9048a50be77fa5ec21d
--- /dev/null
+++ b/clean/image/effort/UniversalFakeDetect_Benchmark/script/train_svd.sh
@@ -0,0 +1,40 @@
+#!/usr/bin/env bash
+
+# clip svd
+PYTHONPATH="$(dirname $0)/..":$PYTHONPATH \
+CUDA_VISIBLE_DEVICES=1 python train.py \
+ --name clip_vitl14_svd \
+ --wang2020_data_path /Youtu_Pangu_Security_Public/etoilefu/CNNDetection/dataset/ \
+ --data_mode wang2020 \
+ --arch CLIP:ViT-L/14_svd \
+ --batch_size 48 \
+ --loadSize 256 \
+ --cropSize 224 \
+ --lr 0.0002 \
+ --use_svd
+
+# siglip svd
+# PYTHONPATH="$(dirname $0)/..":$PYTHONPATH \
+# CUDA_VISIBLE_DEVICES=1 python train.py \
+# --name siglip_vitl14_svd \
+# --wang2020_data_path /Youtu_Pangu_Security_Public/etoilefu/CNNDetection/dataset/ \
+# --data_mode wang2020 \
+# --arch SigLIP:ViT-L/16_256_svd \
+# --batch_size 48 \
+# --loadSize 256 \
+# --cropSize 256 \
+# --lr 0.0002 \
+# --use_svd
+
+# beitv2 svd
+# PYTHONPATH="$(dirname $0)/..":$PYTHONPATH \
+# CUDA_VISIBLE_DEVICES=1 python train.py \
+# --name beitv2_vitl14_svd \
+# --wang2020_data_path /Youtu_Pangu_Security_Public/etoilefu/CNNDetection/dataset/ \
+# --data_mode wang2020 \
+# --arch BEiTv2:ViT-L/16_svd \
+# --batch_size 48 \
+# --loadSize 256 \
+# --cropSize 224 \
+# --lr 0.0002 \
+# --use_svd
\ No newline at end of file
diff --git a/clean/image/effort/UniversalFakeDetect_Benchmark/train.py b/clean/image/effort/UniversalFakeDetect_Benchmark/train.py
new file mode 100644
index 0000000000000000000000000000000000000000..735b8662aae6f5e4dd851215fa1c2086278a6f26
--- /dev/null
+++ b/clean/image/effort/UniversalFakeDetect_Benchmark/train.py
@@ -0,0 +1,93 @@
+import os
+import time
+import random
+from tensorboardX import SummaryWriter
+
+from validate import validate, find_best_threshold, RealFakeDataset
+from data import create_dataloader
+from earlystop import EarlyStopping
+from models.trainer import Trainer
+from options.train_options import TrainOptions
+from dataset_paths import DATASET_PATHS
+import torch
+import numpy as np
+
+
+SEED = 0
+def set_seed():
+ torch.manual_seed(SEED)
+ torch.cuda.manual_seed(SEED)
+ torch.cuda.manual_seed_all(SEED)
+ np.random.seed(SEED)
+ random.seed(SEED)
+ torch.backends.cudnn.deterministic = True
+ torch.backends.cudnn.benchmark = False
+
+
+def get_val_opt():
+ val_opt = TrainOptions().parse(print_options=False)
+ val_opt.isTrain = False
+ val_opt.no_resize = False
+ val_opt.no_crop = False
+ val_opt.serial_batches = True
+ val_opt.data_label = 'val'
+
+ return val_opt
+
+
+if __name__ == '__main__':
+ opt = TrainOptions().parse()
+ val_opt = get_val_opt()
+
+ set_seed()
+
+ model = Trainer(opt)
+
+ data_loader = create_dataloader(opt)
+ val_loader = create_dataloader(val_opt)
+
+ train_writer = SummaryWriter(os.path.join(opt.checkpoints_dir, opt.name, "train"))
+ val_writer = SummaryWriter(os.path.join(opt.checkpoints_dir, opt.name, "val"))
+
+ early_stopping = EarlyStopping(patience=opt.earlystop_epoch, delta=-0.001, verbose=True)
+ start_time = time.time()
+ print ("Length of data loader: %d" %(len(data_loader)))
+ with open( os.path.join(opt.checkpoints_dir, opt.name,'log.txt'), 'a') as f:
+ f.write("Length of data loader: %d \n" %(len(data_loader)) )
+ for epoch in range(opt.niter):
+ model.save_networks( 'model_epoch_init.pth' )
+
+ for i, data in enumerate(data_loader):
+ model.total_steps += 1
+
+ model.set_input(data)
+ model.optimize_parameters()
+
+ if model.total_steps % opt.loss_freq == 0:
+ print("Train loss: {} at step: {}".format(model.loss, model.total_steps))
+ train_writer.add_scalar('loss', model.loss, model.total_steps)
+ print("Iter time: ", ((time.time()-start_time)/model.total_steps) )
+ with open( os.path.join(opt.checkpoints_dir, opt.name,'log.txt'), 'a') as f:
+ f.write(f"Iter time: {(time.time()-start_time)/model.total_steps}, Lr: {model.lr}, Train loss: {model.loss} at step: {model.total_steps}\n")
+
+ if model.total_steps in [50,100,500,550,600,650,700,800,900,1000,1200,1500,2000,3000,5000,8000,10000,12000,18000,20000,23000,25000]: # save models at these iters
+ model.train()
+ model.save_networks('model_iters_%s.pth' % model.total_steps)
+
+ # if model.total_steps % 500 == 0:
+ # model.adjust_learning_rate()
+
+ if epoch % opt.save_epoch_freq == 0:
+ print('saving the model at the end of epoch %d' % (epoch))
+ model.train()
+ model.save_networks( 'model_epoch_%s.pth' % epoch )
+
+ # Validation
+ model.eval()
+ ap, r_acc, f_acc, acc = validate(model.model, val_loader)
+ val_writer.add_scalar('accuracy', acc, model.total_steps)
+ val_writer.add_scalar('ap', ap, model.total_steps)
+ print("(Val @ epoch {}) acc: {}; ap: {}".format(epoch, acc, ap))
+
+ model.train()
+
diff --git a/clean/image/effort/UniversalFakeDetect_Benchmark/util.py b/clean/image/effort/UniversalFakeDetect_Benchmark/util.py
new file mode 100644
index 0000000000000000000000000000000000000000..53f23f80e7f9a37c9be67cbd81c7c67f8594706a
--- /dev/null
+++ b/clean/image/effort/UniversalFakeDetect_Benchmark/util.py
@@ -0,0 +1,21 @@
+import os
+import torch
+
+
+def mkdirs(paths):
+ if isinstance(paths, list) and not isinstance(paths, str):
+ for path in paths:
+ mkdir(path)
+ else:
+ mkdir(paths)
+
+
+def mkdir(path):
+ if not os.path.exists(path):
+ os.makedirs(path)
+
+
+def unnormalize(tens, mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]):
+ # assume tensor of shape NxCxHxW
+ return tens * torch.Tensor(std)[None, :, None, None] + torch.Tensor(
+ mean)[None, :, None, None]
\ No newline at end of file
diff --git a/clean/image/effort/UniversalFakeDetect_Benchmark/validate.py b/clean/image/effort/UniversalFakeDetect_Benchmark/validate.py
new file mode 100644
index 0000000000000000000000000000000000000000..53da394816e8658f2da11cee77a557ed0a821948
--- /dev/null
+++ b/clean/image/effort/UniversalFakeDetect_Benchmark/validate.py
@@ -0,0 +1,359 @@
+import argparse
+from ast import arg
+import os
+import math
+import csv
+import torch
+import torchvision.transforms as transforms
+import torch.utils.data
+import numpy as np
+from sklearn.metrics import average_precision_score, precision_recall_curve, accuracy_score
+from torch.utils.data import Dataset
+import sys
+from models import get_model
+from PIL import Image
+import pickle
+from tqdm import tqdm
+from io import BytesIO
+from copy import deepcopy
+from dataset_paths import DATASET_PATHS
+import random
+import shutil
+from scipy.ndimage.filters import gaussian_filter
+
+
+SEED = 0
+def set_seed():
+ torch.manual_seed(SEED)
+ torch.cuda.manual_seed(SEED)
+ np.random.seed(SEED)
+ random.seed(SEED)
+
+
+MEAN = {
+ "imagenet":[0.485, 0.456, 0.406],
+ "clip":[0.48145466, 0.4578275, 0.40821073],
+ "beitv2": [0.485, 0.456, 0.406],
+ "siglip": [0.5, 0.5, 0.5],
+}
+
+STD = {
+ "imagenet":[0.229, 0.224, 0.225],
+ "clip":[0.26862954, 0.26130258, 0.27577711],
+ "beitv2": [0.229, 0.224, 0.225],
+ "siglip": [0.5, 0.5, 0.5],
+}
+
+
+def translate_duplicate(img, cropSize):
+ if min(img.size) < cropSize:
+ width, height = img.size
+
+ new_width = width * math.ceil(cropSize/width)
+ new_height = height * math.ceil(cropSize/height)
+
+ new_img = Image.new('RGB', (new_width, new_height))
+ for i in range(0, new_width, width):
+ for j in range(0, new_height, height):
+ new_img.paste(img, (i, j))
+ return new_img
+ else:
+ return img
+
+
+def find_best_threshold(y_true, y_pred):
+ "We assume first half is real 0, and the second half is fake 1"
+
+ N = y_true.shape[0]
+
+ if y_pred[0:N//2].max() <= y_pred[N//2:N].min(): # perfectly separable case
+ return (y_pred[0:N//2].max() + y_pred[N//2:N].min()) / 2
+
+ best_acc = 0
+ best_thres = 0
+ for thres in y_pred:
+ temp = deepcopy(y_pred)
+ temp[temp>=thres] = 1
+ temp[temp= best_acc:
+ best_thres = thres
+ best_acc = acc
+
+ return best_thres
+
+
+def png2jpg(img, quality):
+ out = BytesIO()
+ img.save(out, format='jpeg', quality=quality) # ranging from 0-95, 75 is default
+ img = Image.open(out)
+ # load from memory before ByteIO closes
+ img = np.array(img)
+ out.close()
+
+ return Image.fromarray(img)
+
+
+def gaussian_blur(img, sigma):
+ img = np.array(img)
+
+ gaussian_filter(img[:,:,0], output=img[:,:,0], sigma=sigma)
+ gaussian_filter(img[:,:,1], output=img[:,:,1], sigma=sigma)
+ gaussian_filter(img[:,:,2], output=img[:,:,2], sigma=sigma)
+
+ return Image.fromarray(img)
+
+
+def calculate_acc(y_true, y_pred, thres):
+ r_acc = accuracy_score(y_true[y_true==0], y_pred[y_true==0] > thres)
+ f_acc = accuracy_score(y_true[y_true==1], y_pred[y_true==1] > thres)
+ acc = accuracy_score(y_true, y_pred > thres)
+
+ return r_acc, f_acc, acc
+
+
+def validate(model, loader, find_thres=False):
+ with torch.no_grad():
+ y_true, y_pred = [], []
+ print ("Length of dataset: %d" %(len(loader)))
+ for img, label in loader:
+ in_tens = img.cuda()
+
+ y_pred.extend(model(in_tens).sigmoid().flatten().tolist())
+ # y_pred.extend(model(in_tens).softmax(dim=1)[:, 1].flatten().tolist())
+ y_true.extend(label.flatten().tolist())
+
+ y_true, y_pred = np.array(y_true), np.array(y_pred)
+
+ # Get AP
+ ap = average_precision_score(y_true, y_pred)
+
+ # Acc based on 0.5
+ r_acc0, f_acc0, acc0 = calculate_acc(y_true, y_pred, 0.5)
+ if not find_thres:
+ return ap, r_acc0, f_acc0, acc0
+
+ # Acc based on the best thres
+ best_thres = find_best_threshold(y_true, y_pred)
+ r_acc1, f_acc1, acc1 = calculate_acc(y_true, y_pred, best_thres)
+
+ return ap, r_acc0, f_acc0, acc0, r_acc1, f_acc1, acc1, best_thres
+
+
+
+
+def recursively_read(rootdir, must_contain, classes=[], exts=["png", "jpg", "JPEG", "jpeg"]):
+ out = []
+ for r, d, f in os.walk(rootdir):
+ for file in f:
+ if (file.split('.')[1] in exts) and (must_contain in os.path.join(r, file)):
+ if len(classes) == 0:
+ out.append(os.path.join(r, file))
+ elif os.path.join(r, file).split('/')[-3] in classes:
+ out.append(os.path.join(r, file))
+
+ return out
+
+
+def get_list(path, must_contain='', classes=[]):
+ if ".pickle" in path:
+ with open(path, 'rb') as f:
+ image_list = pickle.load(f)
+ image_list = [ item for item in image_list if must_contain in item ]
+ else:
+ image_list = recursively_read(path, must_contain, classes)
+
+ return image_list
+
+
+class RealFakeDataset(Dataset):
+ def __init__(self, real_path,
+ fake_path,
+ data_mode,
+ max_sample,
+ arch,
+ jpeg_quality=None,
+ gaussian_sigma=None):
+
+ assert data_mode in ["wang2020", "ours"]
+ self.jpeg_quality = jpeg_quality
+ self.gaussian_sigma = gaussian_sigma
+
+ # = = = = = = data path = = = = = = = = = #
+ if type(real_path) == str and type(fake_path) == str:
+ real_list, fake_list = self.read_path(real_path, fake_path, data_mode, max_sample)
+ else:
+ real_list = []
+ fake_list = []
+ for real_p, fake_p in zip(real_path, fake_path):
+ real_l, fake_l = self.read_path(real_p, fake_p, data_mode, max_sample)
+ real_list += real_l
+ fake_list += fake_l
+
+ self.total_list = real_list + fake_list
+
+
+ # = = = = = = label = = = = = = = = = #
+ self.labels_dict = {}
+ for i in real_list:
+ self.labels_dict[i] = 0
+ for i in fake_list:
+ self.labels_dict[i] = 1
+
+ if arch.lower().startswith("imagenet"):
+ stat_from = "imagenet"
+ elif arch.lower().startswith("clip"):
+ stat_from = "clip"
+ elif arch.lower().startswith("siglip"):
+ stat_from = "siglip"
+ elif arch.lower().startswith("beitv2"):
+ stat_from = "beitv2"
+
+ self.transform = transforms.Compose([
+ # transforms.Resize((256, 256)),
+ transforms.Lambda(lambda img: translate_duplicate(img, 256)),
+ transforms.CenterCrop(224) if stat_from != "siglip" else transforms.CenterCrop(256),
+ transforms.ToTensor(),
+ transforms.Normalize( mean=MEAN[stat_from], std=STD[stat_from] ),
+ ])
+
+ def read_path(self, real_path, fake_path, data_mode, max_sample):
+ if data_mode == 'wang2020':
+ real_list = get_list(real_path, must_contain='0_real')
+ fake_list = get_list(fake_path, must_contain='1_fake')
+ else:
+ real_list = get_list(real_path)
+ fake_list = get_list(fake_path)
+
+ if max_sample is not None:
+ if (max_sample > len(real_list)) or (max_sample > len(fake_list)):
+ max_sample = 100
+ print("not enough images, max_sample falling to 100")
+ random.shuffle(real_list)
+ random.shuffle(fake_list)
+ real_list = real_list[0:max_sample]
+ fake_list = fake_list[0:max_sample]
+
+ assert len(real_list) == len(fake_list)
+
+ return real_list, fake_list
+
+ def __len__(self):
+ return len(self.total_list)
+
+ def __getitem__(self, idx):
+ img_path = self.total_list[idx]
+
+ label = self.labels_dict[img_path]
+ img = Image.open(img_path).convert("RGB")
+
+ if self.gaussian_sigma is not None:
+ img = gaussian_blur(img, self.gaussian_sigma)
+ if self.jpeg_quality is not None:
+ img = png2jpg(img, self.jpeg_quality)
+
+ img = self.transform(img)
+
+ return img, label
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+ parser.add_argument('--real_path', type=str, default=None, help='dir name or a pickle')
+ parser.add_argument('--fake_path', type=str, default=None, help='dir name or a pickle')
+ parser.add_argument('--data_mode', type=str, default=None, help='wang2020 or ours')
+ parser.add_argument('--max_sample', type=int, default=1000, help='only check this number of images for both fake/real')
+
+ parser.add_argument('--arch', type=str, default='res50')
+ parser.add_argument('--ckpt', type=str, default='./pretrained_weights/fc_weights.pth')
+
+ parser.add_argument('--result_folder', type=str, default='result', help='')
+ parser.add_argument('--batch_size', type=int, default=128)
+
+ parser.add_argument('--jpeg_quality', type=int, default=None, help="100, 90, 80, ... 30. Used to test robustness of our model. Not apply if None")
+ parser.add_argument('--gaussian_sigma', type=int, default=None, help="0,1,2,3,4. Used to test robustness of our model. Not apply if None")
+
+ parser.add_argument('--use_svd', action='store_true')
+ parser.add_argument('--use_lora', action='store_true')
+
+ opt = parser.parse_args()
+
+ os.makedirs(opt.result_folder, exist_ok=True)
+
+ model = get_model(opt.arch, opt)
+ if opt.use_svd:
+ state_dict = torch.load(opt.ckpt, map_location='cpu')['model']
+ model.load_state_dict(state_dict)
+ else:
+ state_dict = torch.load(opt.ckpt, map_location='cpu')['model']
+ model.fc.load_state_dict(state_dict)
+
+ print ("Model loaded..")
+ model.eval()
+ model.cuda()
+
+ if (opt.real_path == None) or (opt.fake_path == None) or (opt.data_mode == None):
+ dataset_paths = DATASET_PATHS
+ else:
+ dataset_paths = [ dict(real_path=opt.real_path, fake_path=opt.fake_path, data_mode=opt.data_mode) ]
+
+ with open( os.path.join(opt.result_folder,'ap.txt'), 'a') as f:
+ f.write('-----------------------------------------'+'\n' )
+ with open( os.path.join(opt.result_folder,'acc0.txt'), 'a') as f:
+ f.write('-----------------------------------------'+'\n' )
+ with open( os.path.join(opt.result_folder,'acc1.txt'), 'a') as f:
+ f.write('-----------------------------------------'+'\n' )
+
+ ap_avg, r_acc0_avg, f_acc0_avg, acc0_avg, r_acc1_avg, f_acc1_avg, acc1_avg = 0, 0, 0, 0, 0, 0, 0
+ for dataset_path in (dataset_paths):
+ set_seed()
+
+ dataset = RealFakeDataset( dataset_path['real_path'],
+ dataset_path['fake_path'],
+ dataset_path['data_mode'],
+ opt.max_sample,
+ opt.arch,
+ jpeg_quality=opt.jpeg_quality,
+ gaussian_sigma=opt.gaussian_sigma,
+ )
+
+ loader = torch.utils.data.DataLoader(dataset, batch_size=opt.batch_size, shuffle=False, num_workers=4)
+ ap, r_acc0, f_acc0, acc0, r_acc1, f_acc1, acc1, best_thres = validate(model, loader, find_thres=True)
+ with open( os.path.join(opt.result_folder,'acc0.txt'), 'a') as f:
+ f.write(f"thres: 0.5\n")
+ with open( os.path.join(opt.result_folder,'acc1.txt'), 'a') as f:
+ f.write(f"thres: {best_thres}\n")
+
+ ap_avg += ap
+ r_acc0_avg += r_acc0
+ f_acc0_avg += f_acc0
+ acc0_avg += acc0
+ r_acc1_avg += r_acc1
+ f_acc1_avg += r_acc1
+ acc1_avg += acc1
+
+ with open( os.path.join(opt.result_folder,'ap.txt'), 'a') as f:
+ f.write(dataset_path['key']+': ' + str(round(ap*100, 2))+'\n' )
+ with open( os.path.join(opt.result_folder,'acc0.txt'), 'a') as f:
+ f.write(dataset_path['key']+': ' + str(round(r_acc0*100, 2))+' '+str(round(f_acc0*100, 2))+' '+str(round(acc0*100, 2))+'\n' )
+ with open( os.path.join(opt.result_folder,'acc1.txt'), 'a') as f:
+ f.write(dataset_path['key']+': ' + str(round(r_acc1*100, 2))+' '+str(round(f_acc1*100, 2))+' '+str(round(acc1*100, 2))+'\n' )
+
+ ap_avg /= len(dataset_paths)
+ r_acc0_avg /= len(dataset_paths)
+ f_acc0_avg /= len(dataset_paths)
+ acc0_avg /= len(dataset_paths)
+ r_acc1_avg /= len(dataset_paths)
+ f_acc1_avg /= len(dataset_paths)
+ acc1_avg /= len(dataset_paths)
+
+ with open( os.path.join(opt.result_folder,'ap.txt'), 'a') as f:
+ f.write('avg: ' + str(round(ap_avg*100, 2))+'\n' )
+ f.write('-----------------------------------------'+'\n' )
+ with open( os.path.join(opt.result_folder,'acc0.txt'), 'a') as f:
+ f.write('avg: ' + str(round(r_acc0_avg*100, 2))+' '+str(round(f_acc0_avg*100, 2))+' '+str(round(acc0_avg*100, 2))+'\n' )
+ f.write('-----------------------------------------'+'\n' )
+ with open( os.path.join(opt.result_folder,'acc1.txt'), 'a') as f:
+ f.write('avg: ' + str(round(r_acc1_avg*100, 2))+' '+str(round(f_acc1_avg*100, 2))+' '+str(round(acc1_avg*100, 2))+'\n' )
+ f.write('-----------------------------------------'+'\n' )
\ No newline at end of file
diff --git a/clean/image/effort/install.sh b/clean/image/effort/install.sh
new file mode 100644
index 0000000000000000000000000000000000000000..b0ba2738e2a4191cbd0d40eb972cf41aef63b360
--- /dev/null
+++ b/clean/image/effort/install.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+pip install numpy==1.21.5
+pip install pandas==1.4.2
+pip install Pillow==9.0.1
+pip install dlib==19.24.0
+pip install imageio==2.9.0
+pip install imgaug==0.4.0
+pip install tqdm==4.61.0
+pip install scipy==1.7.3
+pip install seaborn==0.11.2
+pip install pyyaml==6.0
+pip install imutils==0.5.4
+pip install opencv-python==4.6.0.66
+pip install scikit-image==0.19.2
+pip install scikit-learn==1.0.2
+pip install albumentations==1.1.0
+pip install torch==1.12.0+cu113 torchvision==0.13.0+cu113 torchaudio==0.12.0 --extra-index-url https://download.pytorch.org/whl/cu113
+pip install efficientnet-pytorch==0.7.1
+pip install timm==0.6.12
+pip install segmentation-models-pytorch==0.3.2
+pip install torchtoolbox==0.1.8.2
+pip install tensorboard==2.10.1
+pip install setuptools==59.5.0
+pip install loralib
+pip install einops
+pip install transformers
+pip install filterpy
+pip install simplejson
+pip install kornia
+pip install fvcore
+pip install imgaug==0.4.0
+pip install git+https://github.com/openai/CLIP.git
diff --git a/clean/image/fsd/.gitignore b/clean/image/fsd/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..7579d281285624f503dae661196ea4e3c2e654fb
--- /dev/null
+++ b/clean/image/fsd/.gitignore
@@ -0,0 +1,8 @@
+__pycache__/
+*.pyc
+*.egg-info/
+.venv/
+dist/
+build/
+internal/
+weights/
diff --git a/clean/image/fsd/CITATION.cff b/clean/image/fsd/CITATION.cff
new file mode 100644
index 0000000000000000000000000000000000000000..83eb011baef5a1120bd9832a6ebf84708df78bb6
--- /dev/null
+++ b/clean/image/fsd/CITATION.cff
@@ -0,0 +1,44 @@
+cff-version: 1.2.0
+message: "If you use this software, please cite it as below."
+title: "Forensic Self-Descriptions Are All You Need for Zero-Shot Detection, Open-Set Source Attribution, and Clustering of AI-generated Images"
+type: software
+authors:
+ - given-names: Tai D.
+ family-names: Nguyen
+ email: tdn47@drexel.edu
+ affiliation: Drexel University
+ - given-names: Aref
+ family-names: Azizpour
+ affiliation: Drexel University
+ - given-names: Matthew C.
+ family-names: Stamm
+ affiliation: Drexel University
+repository-code: "https://github.com/ductai199x/Forensic-Self-Descriptions-CVPR25"
+url: "https://arxiv.org/abs/2503.21003"
+license: CC-BY-NC-SA-4.0
+keywords:
+ - deepfake detection
+ - ai-generated image detection
+ - image forensics
+ - zero-shot detection
+ - computer vision
+ - pytorch
+ - cvpr 2025
+ - stable diffusion
+ - midjourney
+ - generative ai
+preferred-citation:
+ type: conference-paper
+ title: "Forensic Self-Descriptions Are All You Need for Zero-Shot Detection, Open-Set Source Attribution, and Clustering of AI-generated Images"
+ authors:
+ - given-names: Tai D.
+ family-names: Nguyen
+ - given-names: Aref
+ family-names: Azizpour
+ - given-names: Matthew C.
+ family-names: Stamm
+ collection-title: "Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR)"
+ year: 2025
+ month: 6
+ start: 3040
+ end: 3050
diff --git a/clean/image/fsd/LICENSE b/clean/image/fsd/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..682189be62f508be84a0bac99fe8f552a33d4929
--- /dev/null
+++ b/clean/image/fsd/LICENSE
@@ -0,0 +1,22 @@
+Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
+
+Copyright (c) 2025 Tai D. Nguyen, Multimedia Information Security Lab, Drexel University
+
+This work is licensed under the Creative Commons
+Attribution-NonCommercial-ShareAlike 4.0 International License.
+
+You are free to:
+ - Share: copy and redistribute the material in any medium or format
+ - Adapt: remix, transform, and build upon the material
+
+Under the following terms:
+ - Attribution: You must give appropriate credit, provide a link to the
+ license, and indicate if changes were made.
+ - NonCommercial: You may not use the material for commercial purposes.
+ - ShareAlike: If you remix, transform, or build upon the material, you
+ must distribute your contributions under the same license.
+
+No additional restrictions: You may not apply legal terms or technological
+measures that legally restrict others from doing anything the license permits.
+
+Full license text: https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode
diff --git a/clean/image/fsd/README.md b/clean/image/fsd/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..7a5d3c8227d57f1f39a5631595fd2eafdbe3731c
--- /dev/null
+++ b/clean/image/fsd/README.md
@@ -0,0 +1,228 @@
+# Forensic Self-Descriptions (FSD): Zero-Shot AI-Generated Image Detection
+
+[](https://cvpr.thecvf.com/)
+[](https://arxiv.org/abs/2503.21003)
+[](https://creativecommons.org/licenses/by-nc-sa/4.0/)
+[](https://arxiv.org/abs/2503.21003)
+
+**Zero-shot AI-generated image detection -- trained only on real images, generalizes to any unseen generator.**
+
+Official PyTorch implementation of **"Forensic Self-Descriptions Are All You Need for Zero-Shot Detection, Open-Set Source Attribution, and Clustering of AI-generated Images"** (CVPR 2025) by Tai D. Nguyen, Aref Azizpour, and Matthew C. Stamm.
+
+> **TL;DR:** FSD is a deepfake / AI-generated image detector that achieves **96.0% average AUC** across 24 generators (Stable Diffusion, Midjourney, DALL-E, StyleGAN, etc.) while being trained **exclusively on real photographs** — no synthetic training data required.
+
+
+
+
+
+
+
+
+
+## Updates
+
+- **2026-03**: Added source attribution -- identify which AI generator created an image (14 sources supported).
+- **2026-03**: Weights now auto-download from GitHub releases on first use.
+- **2026-02**: Released inference code and pre-trained model weights for AI-generated image detection.
+
+## Roadmap
+
+- [x] Code for open-set source attribution
+- [ ] Code for unsupervised clustering
+
+## Overview
+
+FSD is a self-supervised forensic method that detects AI-generated images without needing to train on any specific generator. It works by:
+
+1. **Forensic Residual Extraction (FRE)**: Constrained prediction-error filters extract pixel-level forensic residuals
+2. **Multi-scale FSD computation**: Residuals are analyzed across scales to produce a compact 960-dimensional forensic descriptor
+3. **GMM scoring**: A Gaussian Mixture Model scores each descriptor, yielding a z-score where more negative values indicate AI-generated content
+
+## Results
+
+FSD achieves **state-of-the-art** zero-shot synthetic image detection while being **completely zero-shot** -- it is trained **only on real images** and has never seen any synthetic image during training. Unlike most competing methods which require synthetic training data from specific generators, FSD generalizes to any generator out of the box.
+
+**Zero-shot detection performance** (average AUC across 24 generators including ProGAN, StyleGAN 1-3, GigaGAN, GLIDE, Stable Diffusion 1.5-3.0, DALLE, Midjourney, Firefly, etc.):
+
+| Method | Training Data | COCO17 | IN-1k | IN-22k | MIDB | Average |
+|--------|:---:|:---:|:---:|:---:|:---:|:---:|
+| CNNDet | Real + Synthetic | 0.756 | 0.714 | 0.733 | 0.683 | 0.722 |
+| PatchFor | Real + Synthetic | 0.833 | 0.823 | 0.845 | 0.790 | 0.823 |
+| UFD | Real + Synthetic | 0.903 | 0.862 | 0.815 | 0.612 | 0.798 |
+| LGrad | Real + Synthetic | 0.819 | 0.770 | 0.866 | 0.824 | 0.820 |
+| DE-FAKE | Real + Synthetic | 0.765 | 0.749 | 0.617 | 0.791 | 0.731 |
+| Aeroblade | Training-Free | 0.728 | 0.741 | 0.582 | 0.646 | 0.674 |
+| ZED | Real Only | 0.751 | 0.676 | 0.716 | 0.747 | 0.723 |
+| NPR | Real + Synthetic | 0.945 | 0.900 | 0.900 | 0.957 | 0.926 |
+| **Ours (FSD)** | **Real Only** | **0.968** | **0.962** | **0.941** | **0.971** | **0.960** |
+
+See [the paper](https://arxiv.org/abs/2503.21003) for full results on source attribution and clustering.
+
+## Installation
+
+This project uses [uv](https://docs.astral.sh/uv/) for dependency management.
+
+```bash
+git clone https://github.com/ductai199x/Forensic-Self-Descriptions-CVPR25.git
+cd Forensic-Self-Descriptions-CVPR25
+
+# Install dependencies and create virtual environment
+uv sync
+
+# Activate the virtual environment
+source .venv/bin/activate
+```
+
+## Quick Start
+
+### Python API
+
+```python
+from fsd import FSDDetector
+
+# Detection only
+detector = FSDDetector.load()
+result = detector.score("photo.jpg")
+
+print(result.z_score) # e.g., -3.5 (negative = likely fake)
+print(result.is_fake) # True/False based on threshold
+```
+
+Score multiple images:
+```python
+results = detector.score_batch(["img1.jpg", "img2.png", "img3.webp"])
+for path, result in zip(paths, results):
+ print(f"{path}: z={result.z_score:.4f} {'FAKE' if result.is_fake else 'REAL'}")
+```
+
+#### Source Attribution
+
+Identify which AI generator created an image:
+
+```python
+# Load with attribution support
+detector = FSDDetector.load(attribution=True)
+result = detector.attribute("suspicious_image.jpg")
+
+print(result.source) # e.g., "Stable Diffusion XL"
+print(result.confidence) # e.g., 0.95
+print(result.is_fake) # True
+print(result.scores) # per-source log-likelihoods
+```
+
+Supported sources: DALL-E 3, Stable Diffusion 1.5/3/XL, Midjourney v6, Adobe Firefly, StyleGAN2/3, ProGAN, GigaGAN, Grok, GPT-Image 1/1.5, and more.
+
+### Command Line
+
+```bash
+# Single image
+fsd-score photo.jpg
+
+# Multiple images
+fsd-score img1.jpg img2.png img3.webp
+
+# Directory of images
+fsd-score --dir path/to/images/
+
+# With source attribution
+fsd-score photo.jpg --attribute
+
+# Custom threshold (default: -2.0, more negative = stricter)
+fsd-score photo.jpg --threshold -3.0
+
+# Use GPU
+fsd-score photo.jpg --device cuda
+
+# CSV output
+fsd-score --dir images/ --csv > results.csv
+```
+
+### Gradio Demo
+
+An interactive web demo for testing images in your browser:
+
+```bash
+# Launch (auto-detects GPU)
+uv run demo.py
+
+# Create a public shareable link
+uv run demo.py --share
+
+# Force CPU-only
+uv run demo.py --device cpu
+```
+
+### Multi-GPU / Ray Serve
+
+For scoring large batches across multiple GPUs, start the Ray Serve service first, then score images against it:
+
+```bash
+# Start the scoring service (auto-detects GPUs)
+fsd-score-ray serve
+
+# In another terminal, score images against the running service
+fsd-score-ray score photo.jpg
+fsd-score-ray score --dir path/to/images/ --csv > results.csv
+```
+
+Configure the service:
+```bash
+# Custom port and GPU allocation
+fsd-score-ray serve --port 9000 --num-gpus 4 --gpu-per-replica 0.5
+
+# Score against non-default port
+fsd-score-ray score --url http://localhost:9000 --dir images/
+```
+
+You can also query the service directly via HTTP:
+```bash
+curl -X POST http://localhost:8000 \
+ -H "Content-Type: application/json" \
+ -d '{"path": "/absolute/path/to/image.jpg"}'
+```
+
+## Interpreting Results
+
+The detector outputs a **z-score** for each image:
+- **z > -2**: Likely real
+- **z < -2**: Likely AI-generated (default threshold)
+- **z < -3**: High confidence AI-generated
+
+> **Note:** Detection is significantly more reliable than attribution. Detection is zero-shot (trained only on real images) and generalizes to any generator with 96% average AUC. Attribution, on the other hand, can only identify sources it has been trained on and may misclassify images from unknown generators. Always trust the detection result over the attribution result.
+
+## Pre-trained Weights
+
+Weights are automatically downloaded from [GitHub releases](https://github.com/ductai199x/Forensic-Self-Descriptions-CVPR25/releases) on first use and cached to `~/.cache/fsd/`. No manual download needed.
+
+**Detection weights:**
+- `fre.pt` -- Forensic Residual Extractor (constrained convolution, ~10 KB)
+- `gmm.pt` -- Gaussian Mixture Model (K=5, tied covariance, ~15 MB)
+- `fsd_transforms.pt` -- Detection feature transforms (~40 MB)
+- `config.json` -- Model configuration and scoring parameters
+
+**Attribution weights** (downloaded when `attribution=True`):
+- `attribution_transforms.pt` -- Attribution feature transform (~26 MB)
+- `source_gmms.pt` -- Per-source GMMs for 14 generators (~207 MB)
+
+## Citation
+
+If you find this work useful, please cite:
+
+```bibtex
+@InProceedings{Nguyen_2025_CVPR,
+ author = {Nguyen, Tai D. and Azizpour, Aref and Stamm, Matthew C.},
+ title = {Forensic Self-Descriptions Are All You Need for Zero-Shot Detection, Open-Set Source Attribution, and Clustering of AI-generated Images},
+ booktitle = {Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR)},
+ month = {June},
+ year = {2025},
+ pages = {3040-3050}
+}
+```
+
+## Acknowledgments
+
+This work was conducted at the [Multimedia Information Security Lab (MISL)](https://misl.ece.drexel.edu/) at Drexel University under the supervision of Dr. Matthew C. Stamm.
+
+## License
+
+This project is licensed under [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/) -- research use only, no commercial use, share-alike.
diff --git a/clean/image/fsd/SOURCE.md b/clean/image/fsd/SOURCE.md
new file mode 100644
index 0000000000000000000000000000000000000000..36e5264e455fbe23604ebae1caac41a19b2e281f
--- /dev/null
+++ b/clean/image/fsd/SOURCE.md
@@ -0,0 +1,17 @@
+# Source: image/fsd
+
+| Field | Value |
+|---|---|
+| Upstream | https://github.com/ductai199x/Forensic-Self-Descriptions-CVPR25 |
+| Paper | https://arxiv.org/abs/2503.21003 |
+| Commit SHA | **not recorded** -- the vendoring step did not preserve it |
+| Mirrored on | 2026-09-15 |
+| Upstream license | LICENSE |
+
+This is a **mirror**, stripped to the files needed for inference. The full
+untouched snapshot is at `archive/image__fsd.tar.gz`.
+
+This code is the work of its original authors and is **not** covered by the
+DeepSafe project license. If you are an author and want this removed, open an
+issue on https://github.com/deepsafehq/deepsafe-bench and it will be taken down
+within 48 hours, no questions asked.
diff --git a/clean/image/fsd/demo.py b/clean/image/fsd/demo.py
new file mode 100644
index 0000000000000000000000000000000000000000..7508c562683acfd287b1978a017c799a0948ce8c
--- /dev/null
+++ b/clean/image/fsd/demo.py
@@ -0,0 +1,469 @@
+"""Gradio demo for FSD: Detecting AI-Generated Images via Forensic Self-Descriptions.
+
+Usage:
+ uv run demo.py
+ uv run demo.py --share
+ uv run demo.py --device cpu
+"""
+
+import argparse
+
+import gradio as gr
+from PIL import Image
+# Register HEIF/HEIC support before any image loading
+try:
+ from pillow_heif import register_heif_opener
+
+ register_heif_opener()
+except ImportError:
+ pass
+
+from fsd import FSDDetector, DetectionResult, AttributionResult
+
+# ---------------------------------------------------------------------------
+# Palette (dark theme, user-provided from coolors.co)
+# ---------------------------------------------------------------------------
+JET_BLACK = "#2d3142" # dark bg
+BEIGE = "#e9edde" # primary text on dark
+BANANA_CREAM = "#e7e247" # warning / uncertain accent
+GLAUCOUS = "#5c80bc" # links, buttons, secondary accent
+PEARL_AQUA = "#69d1c5" # positive / real accent
+
+CARD_BG = "#363b50" # slightly lighter than jet for cards
+MUTED = "#9a9eb0" # subdued text
+
+
+# ---------------------------------------------------------------------------
+# Result rendering
+# ---------------------------------------------------------------------------
+
+def _verdict(z: float, threshold: float):
+ if z >= -1.0:
+ return ("Real", "Forensic signature is consistent with real photographs.", "verdict-real")
+ if z >= threshold:
+ return ("Likely Real", "Leans toward real, but not a definitive match.", "verdict-likely-real")
+ if z >= threshold - 1.0:
+ return ("Likely AI", "Shows signs of AI generation in its forensic signature.", "verdict-likely-ai")
+ return ("AI-Generated", "Forensic signature strongly deviates from real photographs.", "verdict-ai")
+
+
+def _prob_fake(z: float, threshold: float = -2.0, k: float = 2.0) -> float:
+ """Sigmoid centered at the decision threshold so z=threshold -> exactly 50%.
+
+ k=2.0 gives: z=0 -> 2%, z=-1 -> 12%, z=-2 -> 50%, z=-3 -> 88%, z=-4 -> 98%.
+ """
+ import math
+ return 1.0 / (1.0 + math.exp(-k * (threshold - z)))
+
+
+def _build_attribution_html(attr_result: AttributionResult) -> str:
+ """Build horizontal bar chart HTML for source attribution scores."""
+ # Scores are already calibrated probabilities (z-score-normalized softmax)
+ ranked = sorted(attr_result.scores.items(), key=lambda x: x[1], reverse=True)
+
+ bars_html = ""
+ for name, prob in ranked:
+ pct = prob * 100
+ is_best = (name == attr_result.source)
+ bar_cls = "attr-bar-best" if is_best else ""
+ label_cls = "attr-label-best" if is_best else ""
+ bars_html += f"""
+
+
{name}
+
+
{pct:.1f}%
+
"""
+
+ return f"""
+
+
+
+ Predicted source: {attr_result.source}
+ ({attr_result.confidence:.1%} confidence)
+
+
{bars_html}
+
+
"""
+
+
+def build_result_html(result, attr_result=None) -> str:
+ z = result.z_score
+ threshold = result.threshold
+ label, desc, css_cls = _verdict(z, threshold)
+ p_fake = _prob_fake(z, threshold)
+ pct = max(0, min(100, (z + 5.0) / 6.0 * 100))
+
+ attribution_html = ""
+ if attr_result is not None:
+ if attr_result.source == "Real":
+ attribution_html = """
+
+
+
+ Source could not be identified — the generator may not be in our
+ database or confidence is too low for a reliable match.
+
+
"""
+ else:
+ attribution_html = _build_attribution_html(attr_result)
+
+ return f"""
+
+
{label}
+
{desc}
+
+
+
+
+ AI-Generated
+ Real
+
+
+
+
+
+
{p_fake:.0%}
+
Probability AI-Generated
+
+
+
+
{result.raw_score:.2f}
+
Raw Score
+
+
+ {attribution_html}
+
+ """
+
+
+PLACEHOLDER_HTML = """
+
+
Upload an image to check if it is AI-generated and identify its source.
+
+"""
+
+
+# ---------------------------------------------------------------------------
+# CSS — palette accents on top of Soft theme (which handles dark mode)
+# ---------------------------------------------------------------------------
+
+CSS = f"""
+/* light mode: tint page background so white cards have contrast */
+:root:not(.dark) {{
+ --body-background-fill: #e4e6df !important;
+ --background-fill-primary: #e4e6df !important;
+ --background-fill-secondary: #ffffff !important;
+ --block-background-fill: #ffffff !important;
+ --panel-background-fill: #ffffff !important;
+}}
+
+/* layout */
+.gradio-container {{ max-width: 1000px !important; margin: auto; }}
+footer {{ display: none !important; }}
+
+
+/* header */
+.app-header {{ text-align:center; padding:28px 0 16px; }}
+.app-header h1 {{ font-size:28px; font-weight:800; margin:0; color: var(--body-text-color); }}
+.app-header p {{ margin:8px 0 0; font-size:15px; color: var(--body-text-color); opacity:0.7; }}
+.app-header a {{ color:{GLAUCOUS}; text-decoration:underline; text-underline-offset:3px; }}
+
+/* result card */
+.result-card {{
+ border-radius: 14px;
+ padding: 28px;
+ background: var(--background-fill-secondary);
+ border: 1px solid var(--border-color-accent);
+ box-shadow: 0 2px 8px rgba(0,0,0,.06);
+ min-height: 240px;
+ display: flex; flex-direction: column; justify-content: center;
+}}
+.result-card.placeholder {{
+ text-align: center; min-height: 320px; align-items: center;
+ border: 2px dashed var(--border-color-accent);
+ background: transparent;
+ box-shadow: none;
+}}
+.result-card.placeholder p {{
+ margin: 0; font-size: 16px; color: var(--body-text-color); opacity:0.6;
+}}
+
+/* verdict accent stripe — matches gauge gradient */
+.verdict-real {{ border-left: 5px solid #22c55e; }}
+.verdict-likely-real {{ border-left: 5px solid #84cc16; }}
+.verdict-likely-ai {{ border-left: 5px solid #f97316; }}
+.verdict-ai {{ border-left: 5px solid #ef4444; }}
+
+.verdict-real .verdict-label {{ color: #22c55e; }}
+.verdict-likely-real .verdict-label {{ color: #84cc16; }}
+.verdict-likely-ai .verdict-label {{ color: #f97316; }}
+.verdict-ai .verdict-label {{ color: #ef4444; }}
+
+/* verdict text */
+.verdict-label {{ font-size:26px; font-weight:800; line-height:1; }}
+.verdict-desc {{ font-size:15px; margin:8px 0 22px; color: var(--body-text-color); opacity:0.8; }}
+
+/* gauge */
+.gauge {{ margin-bottom:24px; }}
+.gauge-track {{
+ height:8px; border-radius:4px; position:relative;
+ background: linear-gradient(to right, #ef4444, #f97316, #eab308, #84cc16, #22c55e);
+}}
+.gauge-marker {{
+ position:absolute; top:-6px;
+ width:6px; height:20px; border-radius:3px;
+ background: var(--body-text-color);
+ transform:translateX(-50%);
+ box-shadow: 0 1px 4px rgba(0,0,0,.4);
+}}
+.gauge-labels {{
+ display:flex; justify-content:space-between;
+ font-size:12px; margin-top:5px;
+ color: var(--body-text-color-subdued); text-transform:uppercase; letter-spacing:.04em;
+}}
+
+/* stats */
+.stats-row {{ display:flex; gap:10px; flex-wrap:wrap; }}
+.stat {{
+ flex:1; min-width:80px; text-align:center;
+ padding:12px 8px; border-radius:10px;
+ background: var(--background-fill-primary);
+ border: 1px solid var(--border-color-accent);
+ box-shadow: 0 1px 3px rgba(0,0,0,.04);
+}}
+.stat-value {{
+ font-size: clamp(14px, 3.5vw, 20px);
+ font-weight:700; font-variant-numeric:tabular-nums;
+ color: var(--body-text-color);
+ overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
+}}
+.stat-label {{
+ font-size:12px; text-transform:uppercase; letter-spacing:.05em;
+ color: var(--body-text-color-subdued); margin-top:2px;
+}}
+
+/* info box */
+.info-box {{
+ font-size:14px; line-height:1.7;
+ padding:18px 22px; border-radius:10px; margin-top:12px;
+ background: var(--background-fill-secondary);
+ color: var(--body-text-color);
+ border: 1px solid var(--border-color-accent);
+ box-shadow: 0 2px 8px rgba(0,0,0,.06);
+ opacity: 0.85;
+}}
+.info-box b {{ opacity:1; }}
+.info-box .steps {{
+ margin:8px 0 16px; padding-left:20px; line-height:1.8;
+}}
+.info-box .steps li {{ margin-bottom:4px; }}
+.info-box .interpret-table {{
+ width:100%; border-collapse:collapse; margin:8px 0 12px;
+}}
+.info-box .interpret-table td {{
+ padding:8px 10px; border-bottom:1px solid var(--border-color-accent); vertical-align:top;
+ font-size:14px;
+}}
+.info-box .interpret-table tr:last-child td {{ border-bottom:none; }}
+.info-box .interpret-table td:first-child {{ white-space:nowrap; width:170px; }}
+.info-box .note {{
+ margin:10px 0 0; font-size:13px; font-style:italic; opacity:0.7;
+}}
+
+/* attribution */
+.attribution-section {{
+ margin-top: 20px;
+ padding-top: 18px;
+ border-top: 1px solid var(--border-color-accent);
+}}
+.attr-header {{
+ font-size: 16px; font-weight: 700;
+ color: var(--body-text-color);
+ margin-bottom: 6px;
+}}
+.attr-predicted {{
+ font-size: 14px;
+ color: var(--body-text-color); opacity: 0.85;
+ margin-bottom: 14px;
+}}
+.attr-chart {{ display: flex; flex-direction: column; gap: 6px; }}
+.attr-row {{
+ display: flex; align-items: center; gap: 8px;
+}}
+.attr-name {{
+ width: 140px; min-width: 140px;
+ font-size: 12px; text-align: right;
+ color: var(--body-text-color-subdued);
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
+}}
+.attr-track {{
+ flex: 1; height: 14px; border-radius: 7px;
+ background: var(--background-fill-primary);
+ border: 1px solid var(--border-color-accent);
+ overflow: hidden;
+}}
+.attr-fill {{
+ height: 100%; border-radius: 7px;
+ background: {GLAUCOUS}; opacity: 0.5;
+ transition: width 0.4s ease;
+}}
+.attr-fill.attr-bar-best {{
+ background: #ef4444; opacity: 0.9;
+}}
+.attr-pct {{
+ width: 48px; min-width: 48px;
+ font-size: 12px; font-weight: 600;
+ font-variant-numeric: tabular-nums;
+ color: var(--body-text-color-subdued);
+}}
+.attr-label-best {{
+ color: var(--body-text-color) !important;
+ font-weight: 700 !important;
+}}
+
+/* button */
+.analyze-btn {{
+ background: {GLAUCOUS} !important;
+ border: none !important;
+ color: white !important;
+ font-weight: 600 !important;
+ border-radius: 10px !important;
+}}
+.analyze-btn:hover {{ background: #4a6da6 !important; }}
+
+/* image input elevation */
+#img-input {{
+ box-shadow: 0 8px 32px rgba(92,128,188,.35) !important;
+ border: 1px solid var(--border-color-accent) !important;
+}}
+:root:not(.dark) #img-input {{
+ box-shadow: 0 8px 32px rgba(0,0,0,.25) !important;
+}}
+
+"""
+
+
+# ---------------------------------------------------------------------------
+# App
+# ---------------------------------------------------------------------------
+
+def create_demo(device: str = "cpu") -> gr.Blocks:
+ print(f"Loading FSD detector on device={device} ...")
+ try:
+ detector = FSDDetector.load(device=device, attribution=True)
+ has_attribution = True
+ print("Detector ready (with attribution).")
+ except Exception:
+ detector = FSDDetector.load(device=device)
+ has_attribution = False
+ print("Detector ready (detection only, attribution weights not found).")
+
+ def analyze(image):
+ if image is None:
+ return PLACEHOLDER_HTML
+ try:
+ pil_img = Image.open(image)
+ except Exception as exc:
+ return f'Could not open image: {exc}
'
+ result = detector.score(pil_img)
+ attr_result = None
+ if has_attribution and result.is_fake:
+ attr_result = detector.attribute(pil_img)
+ return build_result_html(result, attr_result)
+
+ with gr.Blocks(title="FSD - AI Image Detector") as demo:
+
+ gr.HTML("""
+
+ """)
+
+ with gr.Row(equal_height=False):
+ with gr.Column(scale=1):
+ image_input = gr.Image(
+ type="filepath",
+ sources=["upload", "clipboard"],
+ label="Input Image",
+ height=360,
+ elem_id="img-input",
+ format="png",
+ )
+ analyze_btn = gr.Button("Analyze", variant="primary", elem_classes=["analyze-btn"])
+
+ with gr.Column(scale=1):
+ result_output = gr.HTML(value=PLACEHOLDER_HTML)
+
+ gr.HTML("""
+
+
How it works
+
+ Forensic Residual Extraction — Learned prediction-error filters
+ capture subtle pixel-level traces that differ between real cameras and AI generators.
+ Self-Description Computation — Multi-scale patch analysis produces
+ a compact 960-dimensional forensic fingerprint of the image.
+ Statistical Scoring — A Gaussian Mixture Model, trained exclusively
+ on real photographs, measures how well the fingerprint matches natural image statistics.
+ Z-Score & Decision — The score is normalized into a z-score
+ (standard deviations from the real-image mean). More negative = less like a real photo.
+ Source Attribution — If an image is flagged as AI-generated,
+ per-source statistical models identify which generator most likely produced it.
+
+
+
Interpreting the results
+
+ Z-score above −1
+ Forensic signature matches real photographs — very likely real.
+ Z-score −1 to −2
+ Still within the real range — likely a genuine photograph.
+ Z-score −2 to −3
+ Crosses the detection threshold — likely AI-generated.
+ Z-score below −3
+ Far beyond the threshold — very likely AI-generated.
+
+
+
+ This detector is trained only on real photographs and has never seen AI-generated images.
+ It generalizes to new generators zero-shot, but accuracy may vary with heavy JPEG
+ compression, screenshots, or other post-processing.
+
+
+ """)
+
+ image_input.change(fn=analyze, inputs=[image_input], outputs=[result_output])
+ analyze_btn.click(fn=analyze, inputs=[image_input], outputs=[result_output])
+
+ return demo
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description="FSD Gradio Demo")
+ parser.add_argument("--device", default="auto", choices=["cpu", "cuda", "auto"])
+ parser.add_argument("--share", action="store_true")
+ parser.add_argument("--port", type=int, default=7860)
+ args = parser.parse_args()
+
+ demo = create_demo(device=args.device)
+ theme = gr.themes.Soft(
+ font=gr.themes.GoogleFont("Inter"),
+ font_mono=gr.themes.GoogleFont("JetBrains Mono"),
+ )
+ # Force dark mode unless user explicitly overrides with ?__theme=light
+ js_dark = """() => {
+ if (!window.location.search.includes('__theme=light')) {
+ document.querySelector('body').classList.toggle('dark', true);
+ }
+ }"""
+ demo.launch(share=args.share, server_port=args.port, show_error=True, theme=theme, css=CSS, js=js_dark)
diff --git a/clean/image/fsd/fsd/__init__.py b/clean/image/fsd/fsd/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..8eff52e676d7b7294361430174792186b6334369
--- /dev/null
+++ b/clean/image/fsd/fsd/__init__.py
@@ -0,0 +1,26 @@
+"""FSD: Detecting AI-Generated Images via Forensic Self-Descriptions.
+
+Paper: https://arxiv.org/abs/2503.21003 (CVPR 2025)
+
+Quick start:
+ from fsd import FSDDetector
+
+ detector = FSDDetector.load() # auto-downloads weights on first use
+ result = detector.score("photo.jpg")
+ print(result.z_score, result.is_fake)
+"""
+
+__version__ = "1.2.0"
+
+from .detector import FSDDetector, DetectionResult
+from .attribution import AttributionResult
+from .weights import download_weights, get_weights_dir
+
+__all__ = [
+ "FSDDetector",
+ "DetectionResult",
+ "AttributionResult",
+ "download_weights",
+ "get_weights_dir",
+ "__version__",
+]
diff --git a/clean/image/fsd/fsd/attribution.py b/clean/image/fsd/fsd/attribution.py
new file mode 100644
index 0000000000000000000000000000000000000000..13e40b5ce36779c0c76fb7af26a6e991c8f76a1c
--- /dev/null
+++ b/clean/image/fsd/fsd/attribution.py
@@ -0,0 +1,112 @@
+"""Source attribution for AI-generated images.
+
+Given an image already detected as AI-generated, identifies which generator
+produced it by scoring against per-source GMMs.
+
+Usage:
+ from fsd import FSDDetector
+
+ detector = FSDDetector.load(attribution=True)
+ result = detector.attribute("fake_photo.jpg")
+ print(result.source, result.confidence)
+"""
+
+import torch
+
+from dataclasses import dataclass
+
+from .gmm import TorchGMM
+
+
+@dataclass
+class AttributionResult:
+ """Result of source attribution for a single image.
+
+ Attributes:
+ source: Predicted source name (e.g., "DALL-E 3", "Stable Diffusion XL").
+ confidence: Confidence score (temperature-scaled softmax probability).
+ scores: Dict mapping each source name to its probability.
+ z_score: Detection z-score (from the detection pipeline).
+ is_fake: Whether the image was detected as fake.
+ """
+
+ source: str
+ confidence: float
+ scores: dict[str, float]
+ z_score: float
+ is_fake: bool
+
+ def __repr__(self):
+ return (
+ f"AttributionResult(source={self.source!r}, confidence={self.confidence:.3f}, "
+ f"z_score={self.z_score:.4f}, is_fake={self.is_fake})"
+ )
+
+
+def load_source_gmms(path, device="cpu"):
+ """Load packed per-source GMMs from a single weights file.
+
+ Args:
+ path: Path to the .pt file containing all source GMMs.
+ device: Device to load onto.
+
+ Returns:
+ Dict mapping source name to TorchGMM instance.
+ """
+ data = torch.load(path, map_location="cpu", weights_only=True)
+ source_gmms = {}
+
+ for source in data["sources"]:
+ name = source["name"]
+ gmm = TorchGMM(
+ n_components=int(source["n_components"]),
+ covariance_type=source["covariance_type"],
+ device="cpu",
+ )
+ gmm.means_ = source["means_"].to(dtype=torch.float64)
+ gmm.weights_ = source["weights_"].to(dtype=torch.float64)
+ gmm.covariances_ = source["covariances_"].to(dtype=torch.float64)
+ gmm.precisions_cholesky_ = source["precisions_cholesky_"].to(dtype=torch.float64)
+ gmm._update_inference_cache()
+
+ if device != "cpu":
+ gmm.to(device)
+
+ source_gmms[name] = gmm
+
+ return source_gmms
+
+
+_CONFIDENCE_TEMPERATURE = 750.0
+
+
+def classify(fsd_vec, source_gmms):
+ """Classify a single FSD vector by scoring against all source GMMs.
+
+ Args:
+ fsd_vec: (1, D) projected FSD tensor.
+ source_gmms: Dict mapping source name to TorchGMM.
+
+ Returns:
+ (source_name, confidence, scores_dict) where:
+ - source_name: name of the best-matching source
+ - confidence: temperature-scaled softmax probability of the best source
+ - scores_dict: dict mapping each source name to its probability
+ """
+ names = list(source_gmms.keys())
+ log_liks = {}
+ for name, gmm in source_gmms.items():
+ log_liks[name] = gmm.score_samples(fsd_vec).item()
+
+ # Classification: argmax over raw log-likelihoods
+ ll_tensor = torch.tensor([log_liks[n] for n in names], dtype=torch.float64)
+ best_idx = ll_tensor.argmax().item()
+
+ # Confidence: temperature-scaled softmax over log-likelihood differences.
+ # T=750 calibrated on measured LL gaps so that median-confidence samples
+ # get ~90% and hard/ambiguous samples get ~50-60%.
+ shifted = ll_tensor - ll_tensor.max()
+ probs = torch.softmax(shifted / _CONFIDENCE_TEMPERATURE, dim=0)
+
+ prob_dict = {n: p.item() for n, p in zip(names, probs)}
+ return names[best_idx], probs[best_idx].item(), prob_dict
diff --git a/clean/image/fsd/fsd/cli.py b/clean/image/fsd/fsd/cli.py
new file mode 100644
index 0000000000000000000000000000000000000000..185a3bb8d39a948f3cc30b0546bd9f7565ac6d52
--- /dev/null
+++ b/clean/image/fsd/fsd/cli.py
@@ -0,0 +1,112 @@
+"""Command-line interface for FSD scoring.
+
+Usage:
+ fsd-score photo.jpg
+ fsd-score img1.jpg img2.png img3.webp
+ fsd-score --dir path/to/images/
+ fsd-score photo.jpg --threshold -3.0
+ fsd-score photo.jpg --device cuda
+ fsd-score photo.jpg --weights-dir ./weights
+"""
+
+import sys
+
+from pathlib import Path
+
+import click
+
+
+IMAGE_EXTENSIONS = {
+ ".jpg",
+ ".jpeg",
+ ".png",
+ ".bmp",
+ ".tiff",
+ ".tif",
+ ".webp",
+ ".heif",
+ ".heic",
+}
+
+
+def _resolve_weights_dir(attribution=False):
+ """Find or auto-download weights directory."""
+ from .weights import get_weights_dir
+ return get_weights_dir(attribution=attribution)
+
+
+@click.command()
+@click.argument("images", nargs=-1, type=click.Path(exists=True))
+@click.option("--dir", "image_dir", type=click.Path(exists=True), help="Directory of images to score.")
+@click.option("--threshold", type=float, default=None, help="Z-score threshold (default: -2.0). More negative = stricter.")
+@click.option("--device", type=str, default="auto", help="Device: auto, cpu, or cuda.")
+@click.option("--weights-dir", type=click.Path(exists=True), default=None, help="Path to weights directory.")
+@click.option("--csv", "csv_output", is_flag=True, help="Output results as CSV.")
+@click.option("--attribute", is_flag=True, help="Also identify the source generator.")
+def main(images, image_dir, threshold, device, weights_dir, csv_output, attribute):
+ """Score images for AI-generated content using Forensic Self-Descriptions.
+
+ More negative z-scores indicate higher likelihood of being AI-generated.
+ Use --attribute to also identify which AI generator produced the image.
+ """
+ from .detector import FSDDetector
+
+ # Collect image paths
+ image_paths = list(images)
+ if image_dir:
+ dir_path = Path(image_dir)
+ for ext in IMAGE_EXTENSIONS:
+ image_paths.extend(str(p) for p in dir_path.glob(f"*{ext}"))
+ image_paths.extend(str(p) for p in dir_path.glob(f"*{ext.upper()}"))
+
+ if not image_paths:
+ click.echo("Error: No images specified. Provide image paths or use --dir.", err=True)
+ sys.exit(1)
+
+ # Deduplicate and sort
+ image_paths = sorted(set(image_paths))
+
+ # Load detector (auto-downloads weights if needed)
+ try:
+ if weights_dir is None:
+ detector = FSDDetector.load(device=device, threshold=threshold, attribution=attribute)
+ else:
+ detector = FSDDetector.load(weights_dir, device=device, threshold=threshold, attribution=attribute)
+ except RuntimeError as e:
+ click.echo(f"Error: {e}", err=True)
+ sys.exit(1)
+ click.echo(f"Scoring {len(image_paths)} image(s)...\n", err=True)
+
+ # CSV header
+ if csv_output:
+ if attribute:
+ click.echo("file,z_score,is_fake,source,confidence")
+ else:
+ click.echo("file,z_score,raw_score,is_fake,threshold")
+
+ # Score images
+ for path in image_paths:
+ try:
+ if attribute:
+ result = detector.attribute(path)
+ if csv_output:
+ click.echo(f"{path},{result.z_score:.6f},{result.is_fake},{result.source},{result.confidence:.4f}")
+ else:
+ label = "FAKE" if result.is_fake else "REAL"
+ click.echo(f"[{label}] z={result.z_score:+.4f} source={result.source} ({result.confidence:.1%}) {path}")
+ else:
+ result = detector.score(path)
+ if csv_output:
+ click.echo(f"{path},{result.z_score:.6f},{result.raw_score:.6f},{result.is_fake},{result.threshold}")
+ else:
+ label = "FAKE" if result.is_fake else "REAL"
+ click.echo(f"[{label}] z={result.z_score:+.4f} {path}")
+ except Exception as e:
+ if csv_output:
+ click.echo(f"{path},,,error: {e}")
+ else:
+ click.echo(f"[ERROR] {path}: {e}", err=True)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/clean/image/fsd/fsd/cli_ray.py b/clean/image/fsd/fsd/cli_ray.py
new file mode 100644
index 0000000000000000000000000000000000000000..13853e4bcf3eff903be0bd8198357546a6c8f148
--- /dev/null
+++ b/clean/image/fsd/fsd/cli_ray.py
@@ -0,0 +1,176 @@
+"""Ray-based CLI for parallel FSD scoring across multiple GPUs.
+
+Usage:
+ # Start the scoring service:
+ fsd-score-ray serve
+
+ # Score images against the running service:
+ fsd-score-ray score photo.jpg img2.png img3.webp
+ fsd-score-ray score --dir path/to/images/
+"""
+
+import json
+import sys
+from concurrent.futures import ThreadPoolExecutor, as_completed
+from pathlib import Path
+from urllib.request import Request, urlopen
+from urllib.error import HTTPError, URLError
+
+import click
+
+from .cli import IMAGE_EXTENSIONS, _resolve_weights_dir
+
+
+@click.group()
+def main():
+ """FSD scoring with Ray Serve for multi-GPU parallel processing.
+
+ Start the service with 'serve', then score images with 'score'.
+ """
+ pass
+
+
+@main.command()
+@click.argument("images", nargs=-1, type=click.Path(exists=True))
+@click.option("--dir", "image_dir", type=click.Path(exists=True), help="Directory of images to score.")
+@click.option("--url", default="http://localhost:8000", help="URL of the running fsd-score-ray serve instance.")
+@click.option("--csv", "csv_output", is_flag=True, help="Output results as CSV.")
+@click.option("--workers", type=int, default=32, help="Number of concurrent requests.")
+def score(images, image_dir, url, csv_output, workers):
+ """Score images against a running FSD Ray Serve instance.
+
+ Start the service first with: fsd-score-ray serve
+ """
+ image_paths = list(images)
+ if image_dir:
+ dir_path = Path(image_dir)
+ for ext in IMAGE_EXTENSIONS:
+ image_paths.extend(str(p) for p in dir_path.glob(f"*{ext}"))
+ image_paths.extend(str(p) for p in dir_path.glob(f"*{ext.upper()}"))
+
+ if not image_paths:
+ click.echo("Error: No images specified. Provide image paths or use --dir.", err=True)
+ sys.exit(1)
+
+ image_paths = sorted(set(image_paths))
+
+ # Check service is reachable (HTTPError means service is up but rejected GET)
+ try:
+ urlopen(url, timeout=2)
+ except HTTPError:
+ pass # Service is up, just doesn't handle GET
+ except URLError:
+ click.echo(f"Error: Cannot reach service at {url}. Start it first with: fsd-score-ray serve", err=True)
+ sys.exit(1)
+
+ click.echo(f"Scoring {len(image_paths)} image(s) via {url}...\n", err=True)
+
+ if csv_output:
+ click.echo("file,z_score,raw_score,is_fake,threshold")
+
+ def _score_one(path):
+ abs_path = str(Path(path).resolve())
+ body = json.dumps({"path": abs_path}).encode()
+ req = Request(url, data=body, headers={"Content-Type": "application/json"})
+ with urlopen(req, timeout=300) as resp:
+ return path, json.loads(resp.read())
+
+ with ThreadPoolExecutor(max_workers=workers) as pool:
+ futures = {pool.submit(_score_one, p): p for p in image_paths}
+ for future in as_completed(futures):
+ path = futures[future]
+ try:
+ path, result = future.result()
+ if "error" in result:
+ if csv_output:
+ click.echo(f"{path},,,error: {result['error']}")
+ else:
+ click.echo(f"[ERROR] {path}: {result['error']}", err=True)
+ else:
+ if csv_output:
+ click.echo(f"{path},{result['z_score']:.6f},{result['raw_score']:.6f},{result['is_fake']},{result['threshold']}")
+ else:
+ label = "FAKE" if result["is_fake"] else "REAL"
+ click.echo(f"[{label}] z={result['z_score']:+.4f} {path}")
+ except Exception as e:
+ if csv_output:
+ click.echo(f"{path},,,error: {e}")
+ else:
+ click.echo(f"[ERROR] {path}: {e}", err=True)
+
+
+@main.command()
+@click.option("--host", default="0.0.0.0", help="Host to bind to.")
+@click.option("--port", type=int, default=8000, help="Port to bind to.")
+@click.option("--threshold", type=float, default=None, help="Z-score threshold (default: -2.0).")
+@click.option("--weights-dir", type=click.Path(exists=True), default=None, help="Path to weights directory.")
+@click.option("--num-gpus", type=int, default=None, help="Number of GPUs (default: all available).")
+@click.option("--gpu-per-replica", type=float, default=1.0, help="GPU fraction per replica.")
+def serve(host, port, threshold, weights_dir, num_gpus, gpu_per_replica):
+ """Start a persistent HTTP scoring service.
+
+ Once running, score images with 'fsd-score-ray score' or via HTTP:
+
+ \b
+ curl -X POST http://localhost:8000 \\
+ -H "Content-Type: application/json" \\
+ -d '{"path": "/absolute/path/to/image.jpg"}'
+
+ \b
+ Response:
+ {"z_score": -3.5, "raw_score": -2512.3, "is_fake": true, "threshold": -2.0}
+ """
+ if weights_dir is None:
+ try:
+ weights_dir = _resolve_weights_dir()
+ except RuntimeError as e:
+ click.echo(f"Error: {e}", err=True)
+ sys.exit(1)
+
+ if threshold is None:
+ with open(Path(weights_dir) / "config.json") as f:
+ threshold = json.load(f)["scoring"]["default_threshold"]
+
+ try:
+ import ray
+ except ImportError:
+ click.echo(
+ "Error: Ray is required. Install with: pip install 'fsd-detector[ray]'",
+ err=True,
+ )
+ sys.exit(1)
+
+ ray.init(ignore_reinit_error=True)
+
+ from ray import serve as ray_serve
+
+ click.echo(f"Starting Ray Serve on {host}:{port}...", err=True)
+ ray_serve.start(http_options={"host": host, "port": port})
+
+ from .serve import build_app
+
+ handle, num_replicas = build_app(
+ weights_dir=weights_dir,
+ threshold=threshold,
+ num_gpus=num_gpus,
+ gpu_per_replica=gpu_per_replica,
+ )
+
+ click.echo(f"\nFSD scoring service running at http://{host}:{port} ({num_replicas} replica(s))", err=True)
+ click.echo("Score images with:", err=True)
+ click.echo(f" fsd-score-ray score --url http://localhost:{port} photo.jpg", err=True)
+ click.echo("\nPress Ctrl+C to stop.", err=True)
+
+ try:
+ import signal
+
+ signal.pause()
+ except KeyboardInterrupt:
+ click.echo("\nShutting down...", err=True)
+ finally:
+ ray_serve.shutdown()
+ ray.shutdown()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/clean/image/fsd/fsd/detector.py b/clean/image/fsd/fsd/detector.py
new file mode 100644
index 0000000000000000000000000000000000000000..511df15081d2da07cf93abc3e72a8242300ba990
--- /dev/null
+++ b/clean/image/fsd/fsd/detector.py
@@ -0,0 +1,267 @@
+"""High-level FSD detector API.
+
+Usage:
+ from fsd import FSDDetector
+
+ detector = FSDDetector.load()
+ result = detector.score("photo.jpg")
+ print(result) # DetectionResult(z_score=-3.5, is_fake=True, ...)
+
+ # With source attribution
+ detector = FSDDetector.load(attribution=True)
+ result = detector.attribute("fake_photo.jpg")
+ print(result.source, result.confidence)
+"""
+
+import json
+import torch
+
+from dataclasses import dataclass
+from pathlib import Path
+from typing import Union
+
+from .fre import FRE
+from .fsd_computation import compute_fsd
+from .gmm import load_gmm
+from .projection import apply_projections, load_transforms
+
+
+@dataclass
+class DetectionResult:
+ """Result of scoring a single image.
+
+ Attributes:
+ z_score: Normalized score. More negative = more likely AI-generated.
+ raw_score: Raw GMM log-likelihood before normalization.
+ is_fake: Whether the z-score falls below the threshold.
+ threshold: The z-score threshold used.
+ """
+
+ z_score: float
+ raw_score: float
+ is_fake: bool
+ threshold: float
+
+ def __repr__(self):
+ label = "FAKE" if self.is_fake else "REAL"
+ return f"DetectionResult(z_score={self.z_score:.4f}, is_fake={self.is_fake} [{label}], threshold={self.threshold})"
+
+
+class FSDDetector:
+ """Forensic Self-Description detector for AI-generated images.
+
+ Loads pre-trained weights and provides a simple scoring API.
+ """
+
+ def __init__(self, fre, gmm, projections, config, threshold,
+ attribution_projections=None, source_gmms=None):
+ self.fre = fre
+ self.gmm = gmm
+ self.projections = projections
+ self.config = config
+ self.threshold = threshold
+ self.train_mean = config["scoring"]["train_mean"]
+ self.train_std = config["scoring"]["train_std"]
+ self.attribution_projections = attribution_projections or []
+ self.source_gmms = source_gmms
+
+ @classmethod
+ def load(cls, weights_dir=None, device="auto", threshold=None, attribution=False):
+ """Load pre-trained detector.
+
+ Args:
+ weights_dir: Path to directory containing config.json and weight files.
+ If None, uses versioned cache or auto-downloads from GitHub releases.
+ device: Device to load onto. "auto" selects CUDA if available.
+ threshold: Z-score threshold for fake detection. If None, uses the
+ default from config.json. More negative = stricter.
+ attribution: If True, also load source attribution weights.
+ Enables the attribute() method.
+
+ Returns:
+ FSDDetector instance ready for scoring.
+ """
+ if weights_dir is None:
+ from .weights import get_weights_dir
+ weights_dir = get_weights_dir(attribution=attribution)
+ weights_dir = Path(weights_dir)
+
+ if device == "auto":
+ device = "cuda" if torch.cuda.is_available() else "cpu"
+
+ # Disable TF32 on Ampere+ GPUs to ensure numerical consistency with CPU.
+ # TF32 reduces float32 mantissa to 10 bits, causing divergent FRE residuals
+ # that get amplified through the constrained least-squares solver.
+ if device != "cpu":
+ torch.backends.cuda.matmul.allow_tf32 = False
+ torch.backends.cudnn.allow_tf32 = False
+
+ # Load config
+ with open(weights_dir / "config.json") as f:
+ config = json.load(f)
+
+ if threshold is None:
+ threshold = config["scoring"]["default_threshold"]
+
+ # Load FRE
+ fre = FRE.from_pretrained(weights_dir / config["fre"]["weights_file"], device=device)
+
+ # Load GMM
+ gmm = load_gmm(weights_dir / config["gmm"]["weights_file"], device=device)
+
+ # Load learned transforms
+ projections = load_transforms(
+ weights_dir / config["transforms"]["weights_file"], device=device
+ )
+
+ # Load attribution weights if requested
+ attribution_projections = None
+ source_gmms = None
+ if attribution:
+ attr_config = config.get("attribution")
+ if attr_config is None:
+ raise RuntimeError(
+ "Attribution weights not found in config.json. "
+ "Ensure you have the latest weights with attribution support."
+ )
+ attribution_projections = load_transforms(
+ weights_dir / attr_config["weights_file"], device=device
+ )
+ from .attribution import load_source_gmms
+ source_gmms = load_source_gmms(
+ weights_dir / attr_config["source_gmms_file"], device=device
+ )
+
+ return cls(fre, gmm, projections, config, threshold,
+ attribution_projections, source_gmms)
+
+ def score(self, image) -> DetectionResult:
+ """Score a single image.
+
+ Args:
+ image: File path (str/Path), PIL Image, or grayscale tensor (1, H, W).
+
+ Returns:
+ DetectionResult with z_score, raw_score, is_fake, and threshold.
+ """
+ fsd_config = self.config["fsd"]
+ fsd_vec = compute_fsd(
+ image,
+ self.fre,
+ kernel_size=fsd_config["kernel_size"],
+ num_scales=fsd_config["num_scales"],
+ max_size=fsd_config["max_size"],
+ resize_mode=fsd_config["resize_mode"],
+ )
+
+ # Apply learned transforms
+ device = self.fre.device
+ fsd_vec = fsd_vec.to(device).unsqueeze(0) # (1, D)
+ with torch.no_grad():
+ fsd_vec = apply_projections(fsd_vec, self.projections)
+
+ # Score with GMM
+ raw_score = self.gmm.score_samples(fsd_vec).item()
+ z_score = (raw_score - self.train_mean) / self.train_std
+
+ return DetectionResult(
+ z_score=z_score,
+ raw_score=raw_score,
+ is_fake=z_score < self.threshold,
+ threshold=self.threshold,
+ )
+
+ def score_batch(self, images, show_progress=True) -> list[DetectionResult]:
+ """Score multiple images.
+
+ Args:
+ images: Iterable of file paths, PIL Images, or tensors.
+ show_progress: Whether to show a tqdm progress bar.
+
+ Returns:
+ List of DetectionResult, one per image.
+ """
+ images = list(images)
+ if show_progress:
+ try:
+ from tqdm import tqdm
+
+ images = tqdm(images, desc="Scoring", unit="img")
+ except ImportError:
+ pass
+
+ return [self.score(img) for img in images]
+
+ def attribute(self, image):
+ """Identify the source of an AI-generated image.
+
+ Requires loading with attribution=True. Runs the full detection pipeline
+ plus attribution-specific transforms and per-source GMM scoring.
+
+ Args:
+ image: File path (str/Path), PIL Image, or grayscale tensor (1, H, W).
+
+ Returns:
+ AttributionResult with source name, confidence, per-source scores,
+ z_score, and is_fake.
+ """
+ if self.source_gmms is None:
+ raise RuntimeError(
+ "Attribution not loaded. Use FSDDetector.load(attribution=True)."
+ )
+
+ from .attribution import AttributionResult, classify
+
+ fsd_config = self.config["fsd"]
+ fsd_vec = compute_fsd(
+ image,
+ self.fre,
+ kernel_size=fsd_config["kernel_size"],
+ num_scales=fsd_config["num_scales"],
+ max_size=fsd_config["max_size"],
+ resize_mode=fsd_config["resize_mode"],
+ )
+
+ device = self.fre.device
+ fsd_vec = fsd_vec.to(device).unsqueeze(0) # (1, D)
+
+ with torch.no_grad():
+ # Detection transforms
+ fsd_det = apply_projections(fsd_vec, self.projections)
+
+ # Detection score
+ raw_score = self.gmm.score_samples(fsd_det).item()
+ z_score = (raw_score - self.train_mean) / self.train_std
+
+ # Attribution transforms (applied on top of detection)
+ fsd_attr = apply_projections(fsd_det, self.attribution_projections)
+
+ # Classify source
+ source, confidence, scores = classify(fsd_attr, self.source_gmms)
+
+ return AttributionResult(
+ source=source,
+ confidence=confidence,
+ scores=scores,
+ z_score=z_score,
+ is_fake=z_score < self.threshold,
+ )
+
+ def compute_fsd(self, image) -> torch.Tensor:
+ """Advanced: compute the raw FSD vector (before scoring).
+
+ Args:
+ image: File path (str/Path), PIL Image, or grayscale tensor (1, H, W).
+
+ Returns:
+ 1D float64 tensor of dimension K * (kernel_size^2 - 1).
+ """
+ fsd_config = self.config["fsd"]
+ return compute_fsd(
+ image,
+ self.fre,
+ kernel_size=fsd_config["kernel_size"],
+ num_scales=fsd_config["num_scales"],
+ max_size=fsd_config["max_size"],
+ resize_mode=fsd_config["resize_mode"],
+ )
diff --git a/clean/image/fsd/fsd/fre.py b/clean/image/fsd/fsd/fre.py
new file mode 100644
index 0000000000000000000000000000000000000000..bc87bba97da4ccdb9d8348425a1d6cf3449361ab
--- /dev/null
+++ b/clean/image/fsd/fsd/fre.py
@@ -0,0 +1,110 @@
+"""Forensic Residual Extractor (FRE).
+
+Constrained convolution that extracts forensic residuals from grayscale images.
+The residual is computed as: residual = image - conv(image).
+"""
+
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+
+
+class ConstrainedConv2d(nn.Module):
+ """Convolution with prediction-error filter constraints.
+
+ Weights are constrained so that each filter sums to zero at the center
+ and the off-center elements sum to one, enforcing a prediction-error
+ structure.
+ """
+
+ def __init__(self, in_channels, out_channels, kernel_size):
+ super().__init__()
+ self.in_channels = in_channels
+ self.out_channels = out_channels
+ self.kernel_size = kernel_size
+
+ w = torch.empty((out_channels, in_channels, kernel_size, kernel_size))
+ nn.init.xavier_normal_(w, 1 / 3)
+ self.w = nn.Parameter(w)
+ one_middle = torch.zeros((kernel_size * kernel_size,))
+ one_middle[kernel_size * kernel_size // 2] = 1
+ self.one_middle = nn.Parameter(one_middle, requires_grad=False)
+
+ def constrain(self, w: torch.Tensor, one_middle: torch.Tensor = None) -> torch.Tensor:
+ if one_middle is None:
+ one_middle = self.one_middle
+ w = w.view(-1, self.kernel_size * self.kernel_size)
+ w = w - w.mean(1)[..., None] + 1 / (self.kernel_size * self.kernel_size - 1)
+ scaling_coeff = (w * (1 - one_middle)).sum(1)
+ w = w / scaling_coeff[..., None]
+ w = w - w * self.one_middle
+ w = w.view(self.out_channels, self.in_channels, self.kernel_size, self.kernel_size)
+ return w
+
+ @property
+ def constrained_w(self):
+ return self.constrain(self.w)
+
+ def forward(self, x):
+ # Constrain weights in the input's dtype so that float64 inputs get
+ # float64 constraint math, avoiding GPU float32 rounding divergence.
+ w = self.w if x.dtype == self.w.dtype else self.w.to(x.dtype)
+ one_middle = self.one_middle if x.dtype == self.one_middle.dtype else self.one_middle.to(x.dtype)
+ w = self.constrain(w, one_middle)
+ y = F.conv2d(x, w, padding=self.kernel_size // 2)
+ return y
+
+
+class FRE(nn.Module):
+ """Forensic Residual Extractor.
+
+ Computes forensic residuals: residual = image - constrained_conv(image).
+
+ Args:
+ in_channels: Number of input channels (1 for grayscale).
+ out_channels: Number of output residual channels.
+ kernel_size: Convolution kernel size.
+ """
+
+ def __init__(self, in_channels=1, out_channels=8, kernel_size=15):
+ super().__init__()
+ self.conv = ConstrainedConv2d(in_channels, out_channels, kernel_size)
+
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
+ """Compute forensic residuals.
+
+ Args:
+ x: (1, H, W) or (B, 1, H, W) grayscale image tensor, values in 0-255.
+
+ Returns:
+ Residual tensor of shape (K, H, W) or (B, K, H, W).
+ """
+ return x - self.conv(x)
+
+ @classmethod
+ def from_pretrained(cls, path, device="cpu"):
+ """Load FRE from a plain state_dict file.
+
+ The config (in_channels, out_channels, kernel_size) is inferred from
+ the weight tensor shape.
+
+ Args:
+ path: Path to the .pt state_dict file.
+ device: Device to load onto.
+
+ Returns:
+ FRE model in eval mode.
+ """
+ state_dict = torch.load(path, map_location=device, weights_only=True)
+ # Infer config from weight shape: (out_channels, in_channels, kernel_size, kernel_size)
+ w = state_dict["w"]
+ out_channels, in_channels, kernel_size, _ = w.shape
+ fre = cls(in_channels=in_channels, out_channels=out_channels, kernel_size=kernel_size)
+ fre.conv.load_state_dict(state_dict)
+ fre = fre.to(device)
+ fre.eval()
+ return fre
+
+ @property
+ def device(self):
+ return self.conv.w.device
diff --git a/clean/image/fsd/fsd/fsd_computation.py b/clean/image/fsd/fsd/fsd_computation.py
new file mode 100644
index 0000000000000000000000000000000000000000..089f1da7a20d9b9409b3d389ebfba68378758efd
--- /dev/null
+++ b/clean/image/fsd/fsd/fsd_computation.py
@@ -0,0 +1,157 @@
+"""Forensic Self-Description (FSD) computation.
+
+Extracts a fixed-length FSD vector from an image by:
+1. Computing forensic residuals via the FRE
+2. Multi-scale patch decomposition
+3. Constrained least squares solving (KKT system)
+
+The resulting FSD is a compact descriptor of the image's forensic characteristics.
+"""
+
+import torch
+import torch.nn.functional as F
+
+from PIL import Image
+
+
+def _solve_constrained_least_squares(
+ patches_list,
+ mask,
+ center,
+ K,
+ n_features,
+ device,
+ chunk_size=16384,
+ lambda_reg=1e-5,
+):
+ """Memory-efficient constrained least squares via chunked accumulation.
+
+ Solves for the FSD vector using KKT conditions with sum-to-one constraints
+ per channel. Accumulates X^T X and X^T y in chunks to avoid materializing
+ the full design matrix.
+ """
+ total_features = K * n_features
+
+ XTX = torch.zeros(total_features, total_features, dtype=torch.float64, device=device)
+ XTy = torch.zeros(total_features, dtype=torch.float64, device=device)
+
+ for scale_patches in patches_list:
+ for i in range(0, scale_patches.shape[0], chunk_size):
+ chunk = scale_patches[i : i + chunk_size]
+ x = chunk[:, :, mask].reshape(-1, total_features).to(torch.float64)
+ y = chunk[:, :, center, center].sum(dim=1).to(torch.float64)
+ XTX += x.T @ x
+ XTy += x.T @ y
+
+ # Regularization for numerical stability
+ XTX += lambda_reg * torch.eye(total_features, device=device, dtype=torch.float64)
+
+ # KKT system: sum-to-one constraint per channel
+ A = torch.zeros(K, total_features, device=device, dtype=torch.float64)
+ for k in range(K):
+ A[k, k * n_features : (k + 1) * n_features] = 1
+ b = torch.ones(K, device=device, dtype=torch.float64)
+
+ top = torch.cat([XTX, A.T], dim=1)
+ bottom = torch.cat([A, torch.zeros(K, K, device=device, dtype=torch.float64)], dim=1)
+ LHS = torch.cat([top, bottom], dim=0)
+ RHS = torch.cat([XTy, b], dim=0)
+
+ solution = torch.linalg.solve(LHS, RHS)
+ return solution[:total_features]
+
+
+def compute_fsd(
+ image,
+ fre,
+ kernel_size=11,
+ num_scales=3,
+ max_size=1024,
+ resize_mode="resize_and_crop",
+):
+ """Compute Forensic Self-Description from an image.
+
+ Args:
+ image: PIL Image, file path (str/Path), or grayscale tensor (1, H, W).
+ fre: FRE model instance.
+ kernel_size: Patch size for FSD extraction.
+ num_scales: Number of downsampling scales.
+ max_size: Maximum dimension after resize/crop.
+ resize_mode: One of "resize", "crop", "resize_and_crop".
+
+ Returns:
+ FSD vector as a 1D float64 tensor of dimension K * (kernel_size^2 - 1).
+ """
+ device = fre.device
+
+ # Handle input types
+ if isinstance(image, (str,)):
+ image = Image.open(image)
+ from pathlib import Path as _Path
+
+ if isinstance(image, _Path):
+ image = Image.open(image)
+ if isinstance(image, Image.Image):
+ if image.mode != "L":
+ image = image.convert("L")
+ image_t = torch.from_numpy(__import__("numpy").array(image)).double().unsqueeze(0) # (1, H, W)
+ elif isinstance(image, torch.Tensor):
+ image_t = image.double()
+ if image_t.ndim == 2:
+ image_t = image_t.unsqueeze(0)
+ else:
+ raise TypeError(f"Unsupported image type: {type(image)}")
+
+ K = fre.conv.out_channels
+ fre_kernel_size = fre.conv.kernel_size
+ border_size = fre_kernel_size // 2
+ B = kernel_size
+ center = B // 2
+ mask = torch.ones(B, B, dtype=torch.bool, device=device)
+ mask[center, center] = False
+ n_features = mask.sum().item() # B^2 - 1
+
+ with torch.no_grad():
+ # Compute forensic residuals
+ residuals = fre(image_t.to(device))
+ residuals = residuals[:, border_size:-border_size, border_size:-border_size]
+
+ # Resize and/or crop
+ if "resize" in resize_mode:
+ h, w = residuals.shape[-2:]
+ scale_factor = max_size / min(h, w)
+ new_h, new_w = round(h * scale_factor), round(w * scale_factor)
+ residuals = F.interpolate(
+ residuals[None, ...],
+ size=(new_h, new_w),
+ mode="bilinear",
+ antialias=False,
+ align_corners=False,
+ )[0]
+ if "crop" in resize_mode:
+ h, w = residuals.shape[-2:]
+ crop_h = max_size if h > max_size else h
+ crop_w = max_size if w > max_size else w
+ start_h = (h - crop_h) // 2
+ start_w = (w - crop_w) // 2
+ residuals = residuals[:, start_h : start_h + crop_h, start_w : start_w + crop_w]
+
+ # Multi-scale patch extraction
+ patches = []
+ for l in range(num_scales):
+ scaled = F.interpolate(
+ residuals[None, ...],
+ scale_factor=1 / 2**l,
+ mode="bilinear",
+ antialias=False,
+ align_corners=False,
+ )
+ scaled = F.pad(scaled, (B // 2, B // 2, B // 2, B // 2), mode="reflect")
+ unfolded = scaled[0].unfold(1, B, 1).unfold(2, B, 1)
+ unfolded = unfolded.reshape(K, -1, B, B).permute(1, 0, 2, 3)
+ patches.append(unfolded)
+
+ # Solve constrained least squares
+ fsd = _solve_constrained_least_squares(patches, mask, center, K, n_features, device)
+
+ return fsd.cpu()
diff --git a/clean/image/fsd/fsd/gmm.py b/clean/image/fsd/fsd/gmm.py
new file mode 100644
index 0000000000000000000000000000000000000000..274b84ac2f67a6dff930e8cb9a94f5f27a034e77
--- /dev/null
+++ b/clean/image/fsd/fsd/gmm.py
@@ -0,0 +1,467 @@
+"""GPU-accelerated Gaussian Mixture Model using PyTorch.
+
+Faithful reimplementation of sklearn's GaussianMixture EM algorithm.
+Produces identical results (within float64 tolerance) when given the same
+initialization. Supports "full" and "tied" covariance types.
+
+Usage:
+ from fsd.gmm import TorchGMM, load_gmm
+
+ # Inference from pre-trained weights
+ gmm = load_gmm("path/to/gmm.pt", device="cuda")
+ log_lik = gmm.score_samples(X)
+
+ # Training a new GMM
+ gmm = TorchGMM(n_components=5, covariance_type="tied", device="cuda")
+ gmm.fit(X)
+"""
+
+import math
+import numpy as np
+import torch
+
+from scipy.special import logsumexp as scipy_logsumexp
+
+
+class TorchGMM:
+ """GPU-accelerated Gaussian Mixture Model matching sklearn's algorithm.
+
+ Parameters match sklearn.mixture.GaussianMixture for drop-in replacement.
+ """
+
+ def __init__(
+ self,
+ n_components=5,
+ covariance_type="full",
+ tol=1e-6,
+ reg_covar=1e-6,
+ max_iter=100,
+ n_init=1,
+ random_state=2026,
+ verbose=0,
+ device="cuda",
+ ):
+ if covariance_type not in ("full", "tied"):
+ raise ValueError(f"covariance_type must be 'full' or 'tied', got '{covariance_type}'")
+
+ self.n_components = n_components
+ self.covariance_type = covariance_type
+ self.tol = tol
+ self.reg_covar = reg_covar
+ self.max_iter = max_iter
+ self.n_init = n_init
+ self.random_state = random_state
+ self.verbose = verbose
+ self.device = torch.device(device)
+
+ # Fitted attributes (set by fit())
+ self.means_ = None
+ self.weights_ = None
+ self.covariances_ = None
+ self.precisions_cholesky_ = None
+ self.converged_ = False
+ self.n_iter_ = 0
+ self.lower_bound_ = -math.inf
+
+ # Precomputed inference cache (set by _update_inference_cache)
+ self._log_det_ = None
+ self._log_weights_ = None
+ self._log_const_ = None
+ self._means_prec_ = None
+
+ def to(self, device):
+ """Move all fitted parameters to a new device. Returns self."""
+ device = torch.device(device)
+ self.device = device
+ for attr in ("means_", "weights_", "covariances_", "precisions_cholesky_"):
+ v = getattr(self, attr, None)
+ if v is not None:
+ setattr(self, attr, v.to(device))
+ self._update_inference_cache()
+ return self
+
+ def _to_tensor(self, X):
+ """Convert input to float64 tensor on self.device."""
+ if isinstance(X, np.ndarray):
+ X = torch.from_numpy(X)
+ return X.to(dtype=torch.float64, device=self.device)
+
+ def _update_inference_cache(self):
+ """Precompute derived quantities for fast score_samples."""
+ if self.precisions_cholesky_ is None:
+ return
+
+ pc = self.precisions_cholesky_
+ if self.covariance_type == "full":
+ self._log_det_ = pc.diagonal(dim1=-2, dim2=-1).log().sum(dim=-1)
+ K = self.n_components
+ self._means_prec_ = torch.stack([self.means_[k] @ pc[k] for k in range(K)])
+ else: # tied
+ self._log_det_ = pc.diagonal().log().sum()
+ self._means_prec_ = self.means_ @ pc
+
+ self._log_weights_ = self.weights_.log()
+
+ D = self.means_.shape[1]
+ log_const = -0.5 * D * math.log(2 * math.pi)
+ self._log_const_ = log_const + self._log_det_
+
+ def _initialize(self, X, random_state):
+ """KMeans initialization matching sklearn's default init_params='kmeans'."""
+ from sklearn.cluster import KMeans
+
+ N, D = X.shape
+ K = self.n_components
+
+ X_cpu = X.cpu().numpy()
+ km = KMeans(n_clusters=K, n_init=1, random_state=random_state)
+ labels = km.fit_predict(X_cpu)
+
+ resp = torch.zeros(N, K, dtype=torch.float64, device=self.device)
+ resp[torch.arange(N), torch.from_numpy(labels).to(self.device)] = 1.0
+
+ nk, means, covariances = self._estimate_gaussian_parameters(X, resp)
+
+ self.weights_ = nk / N
+ self.means_ = means
+ self.covariances_ = covariances
+ self.precisions_cholesky_ = self._compute_precision_cholesky(covariances)
+ self._update_inference_cache()
+
+ def _estimate_gaussian_parameters(self, X, resp):
+ """Compute nk, means, covariances from responsibilities."""
+ eps = torch.finfo(torch.float64).eps
+ nk = resp.sum(dim=0) + 10 * eps
+ means = (resp.T @ X) / nk.unsqueeze(1)
+
+ if self.covariance_type == "full":
+ covariances = self._estimate_covariances_full(X, resp, nk, means)
+ else:
+ covariances = self._estimate_covariances_tied(X, resp, nk, means)
+
+ return nk, means, covariances
+
+ def _estimate_covariances_full(self, X, resp, nk, means):
+ """Compute per-component covariances. Returns (K, D, D)."""
+ K = self.n_components
+ D = X.shape[1]
+ covariances = torch.empty(K, D, D, dtype=torch.float64, device=self.device)
+
+ for k in range(K):
+ diff = X - means[k]
+ covariances[k] = (resp[:, k].unsqueeze(0) * diff.T) @ diff / nk[k]
+ covariances[k].diagonal().add_(self.reg_covar)
+
+ return covariances
+
+ def _estimate_covariances_tied(self, X, resp, nk, means):
+ """Compute tied (shared) covariance. Returns (D, D)."""
+ K = self.n_components
+ D = X.shape[1]
+ covariance = torch.zeros(D, D, dtype=torch.float64, device=self.device)
+
+ for k in range(K):
+ diff = X - means[k]
+ covariance += (resp[:, k].unsqueeze(0) * diff.T) @ diff
+
+ covariance /= nk.sum()
+ covariance.diagonal().add_(self.reg_covar)
+ return covariance
+
+ def _compute_precision_cholesky(self, covariances):
+ """Compute upper-triangular precision Cholesky from covariances."""
+ if self.covariance_type == "full":
+ K, D, _ = covariances.shape
+ L = torch.linalg.cholesky(covariances)
+ I_K = torch.eye(D, dtype=torch.float64, device=self.device).expand(K, -1, -1)
+ L_inv = torch.linalg.solve_triangular(L, I_K, upper=False)
+ return L_inv.mT
+ else: # tied
+ D = covariances.shape[0]
+ L = torch.linalg.cholesky(covariances)
+ I_D = torch.eye(D, dtype=torch.float64, device=self.device)
+ L_inv = torch.linalg.solve_triangular(L, I_D, upper=False)
+ return L_inv.T
+
+ def _estimate_log_prob(self, X):
+ """Compute per-component log Gaussian probabilities. Returns (N, K)."""
+ N, D = X.shape
+ K = self.n_components
+ log_det = self._log_det_ if self._log_det_ is not None else self._compute_log_det_raw()
+
+ log_prob = torch.empty(N, K, dtype=torch.float64, device=self.device)
+
+ if self.covariance_type == "full":
+ for k in range(K):
+ prec_chol = self.precisions_cholesky_[k]
+ y = X @ prec_chol - self.means_[k] @ prec_chol
+ log_prob[:, k] = (y * y).sum(dim=1)
+ else: # tied
+ prec_chol = self.precisions_cholesky_
+ X_transformed = X @ prec_chol
+ for k in range(K):
+ y = X_transformed - self.means_[k] @ prec_chol
+ log_prob[:, k] = (y * y).sum(dim=1)
+
+ log_const = -0.5 * D * math.log(2 * math.pi)
+ if self.covariance_type == "full":
+ return log_const + log_det.unsqueeze(0) - 0.5 * log_prob
+ else:
+ return log_const + log_det - 0.5 * log_prob
+
+ def _compute_log_det_raw(self):
+ """Fallback: compute log det without cache."""
+ pc = self.precisions_cholesky_
+ if self.covariance_type == "full":
+ return pc.diagonal(dim1=-2, dim2=-1).log().sum(dim=-1)
+ else:
+ return pc.diagonal().log().sum()
+
+ def _estimate_weighted_log_prob(self, X):
+ """Log prob + log weights. Returns (N, K)."""
+ return self._estimate_log_prob(X) + self.weights_.log()
+
+ def _e_step(self, X):
+ """E-step: compute responsibilities.
+
+ Returns:
+ mean_log_likelihood: scalar (the lower bound)
+ log_resp: (N, K) log responsibilities
+ """
+ weighted_log_prob = self._estimate_weighted_log_prob(X)
+ log_prob_norm = torch.logsumexp(weighted_log_prob, dim=1)
+ log_resp = weighted_log_prob - log_prob_norm.unsqueeze(1)
+ return log_prob_norm.mean().item(), log_resp
+
+ def _m_step(self, X, log_resp):
+ """M-step: update parameters from responsibilities."""
+ resp = log_resp.exp()
+ nk, means, covariances = self._estimate_gaussian_parameters(X, resp)
+
+ self.weights_ = nk / nk.sum()
+ self.means_ = means
+ self.covariances_ = covariances
+ self.precisions_cholesky_ = self._compute_precision_cholesky(covariances)
+ self._update_inference_cache()
+
+ def _get_parameters(self):
+ """Snapshot current parameters."""
+ return {
+ "weights": self.weights_.clone(),
+ "means": self.means_.clone(),
+ "covariances": self.covariances_.clone(),
+ "precisions_cholesky": self.precisions_cholesky_.clone(),
+ }
+
+ def _set_parameters(self, params):
+ """Restore parameters from snapshot."""
+ self.weights_ = params["weights"]
+ self.means_ = params["means"]
+ self.covariances_ = params["covariances"]
+ self.precisions_cholesky_ = params["precisions_cholesky"]
+ self._update_inference_cache()
+
+ def fit(self, X):
+ """Fit GMM via EM algorithm.
+
+ Requires scikit-learn for KMeans initialization.
+ Install with: pip install fsd-detector[fit]
+
+ Args:
+ X: (N, D) tensor or numpy array.
+
+ Returns:
+ self
+ """
+ X = self._to_tensor(X)
+ N, D = X.shape
+
+ if N < self.n_components:
+ raise ValueError(
+ f"Expected n_samples >= n_components, got {N} samples and {self.n_components} components"
+ )
+
+ rng = np.random.RandomState(self.random_state)
+ max_lower_bound = -math.inf
+ best_params = None
+ best_n_iter = 0
+
+ for init_idx in range(self.n_init):
+ if self.verbose >= 1:
+ print(f"Initialization {init_idx + 1}/{self.n_init}")
+
+ self._initialize(X, random_state=rng)
+
+ lower_bound = -math.inf
+ converged = False
+
+ for n_iter in range(1, self.max_iter + 1):
+ prev_lower_bound = lower_bound
+ lower_bound, log_resp = self._e_step(X)
+ self._m_step(X, log_resp)
+
+ change = lower_bound - prev_lower_bound
+
+ if self.verbose >= 2:
+ print(f" Iteration {n_iter:4d} LL={lower_bound:.6f} change={change:+.2e}")
+
+ if abs(change) < self.tol:
+ converged = True
+ if self.verbose >= 1:
+ print(f" Converged at iteration {n_iter} (change={change:+.2e})")
+ break
+
+ if self.verbose >= 1 and not converged:
+ print(f" Did not converge after {self.max_iter} iterations")
+
+ if lower_bound > max_lower_bound:
+ max_lower_bound = lower_bound
+ best_params = self._get_parameters()
+ best_n_iter = n_iter
+ self.converged_ = converged
+
+ if best_params is not None:
+ self._set_parameters(best_params)
+ self.n_iter_ = best_n_iter
+ self.lower_bound_ = max_lower_bound
+
+ # Final E-step (matches sklearn)
+ _, log_resp = self._e_step(X)
+
+ return self
+
+ def score_samples(self, X):
+ """Per-sample log-likelihood.
+
+ Uses numpy on CPU for minimal overhead, PyTorch on CUDA for GPU speed.
+
+ Args:
+ X: (N, D) tensor or numpy array.
+
+ Returns:
+ (N,) tensor of log p(x_i) on self.device.
+ """
+ if self.device.type == "cpu":
+ return self._score_samples_numpy(X)
+ else:
+ X = self._to_tensor(X)
+ with torch.no_grad():
+ return torch.logsumexp(self._estimate_weighted_log_prob(X), dim=1)
+
+ def _score_samples_numpy(self, X):
+ """Fast CPU inference using numpy (avoids PyTorch dispatch overhead)."""
+ if isinstance(X, torch.Tensor):
+ X = X.detach().cpu().numpy()
+ X = np.asarray(X, dtype=np.float64)
+ N, D = X.shape
+ K = self.n_components
+
+ prec_chol = self.precisions_cholesky_.numpy()
+ means_prec = self._means_prec_.numpy()
+ log_weights = self._log_weights_.numpy()
+
+ if self.covariance_type == "full":
+ log_const = self._log_const_.numpy()
+ else:
+ log_const = float(self._log_const_)
+
+ weighted_log_prob = np.empty((N, K), dtype=np.float64)
+
+ if self.covariance_type == "full":
+ for k in range(K):
+ y = X @ prec_chol[k] - means_prec[k]
+ mahal_sq = np.sum(y * y, axis=1)
+ weighted_log_prob[:, k] = log_const[k] - 0.5 * mahal_sq + log_weights[k]
+ else: # tied
+ X_transformed = X @ prec_chol
+ for k in range(K):
+ y = X_transformed - means_prec[k]
+ mahal_sq = np.sum(y * y, axis=1)
+ weighted_log_prob[:, k] = log_const - 0.5 * mahal_sq + log_weights[k]
+
+ result = scipy_logsumexp(weighted_log_prob, axis=1)
+ return torch.from_numpy(result)
+
+ def score(self, X):
+ """Mean log-likelihood (scalar)."""
+ return self.score_samples(X).mean().item()
+
+ def predict(self, X):
+ """Predict component labels.
+
+ Args:
+ X: (N, D) tensor or numpy array.
+
+ Returns:
+ (N,) tensor of component indices.
+ """
+ X = self._to_tensor(X)
+ with torch.no_grad():
+ _, log_resp = self._e_step(X)
+ return log_resp.argmax(dim=1)
+
+ def predict_proba(self, X):
+ """Predict posterior probabilities.
+
+ Args:
+ X: (N, D) tensor or numpy array.
+
+ Returns:
+ (N, K) tensor of responsibilities.
+ """
+ X = self._to_tensor(X)
+ with torch.no_grad():
+ _, log_resp = self._e_step(X)
+ return log_resp.exp()
+
+ def bic(self, X):
+ """Bayesian Information Criterion."""
+ X = self._to_tensor(X)
+ N = X.shape[0]
+ return -2 * self.score(X) * N + self._n_parameters(X.shape[1]) * math.log(N)
+
+ def aic(self, X):
+ """Akaike Information Criterion."""
+ X = self._to_tensor(X)
+ N = X.shape[0]
+ return -2 * self.score(X) * N + 2 * self._n_parameters(X.shape[1])
+
+ def _n_parameters(self, D):
+ """Number of free parameters."""
+ K = self.n_components
+ mean_params = K * D
+ weight_params = K - 1
+ if self.covariance_type == "full":
+ cov_params = K * D * (D + 1) // 2
+ else: # tied
+ cov_params = D * (D + 1) // 2
+ return mean_params + weight_params + cov_params
+
+
+def load_gmm(path, device="cpu"):
+ """Load a pre-trained GMM from a .pt weights file.
+
+ Args:
+ path: Path to the .pt file containing GMM parameters.
+ device: Device to load onto.
+
+ Returns:
+ TorchGMM instance ready for inference.
+ """
+ data = torch.load(path, map_location="cpu", weights_only=True)
+
+ gmm = TorchGMM(
+ n_components=int(data["n_components"]),
+ covariance_type=data["covariance_type"],
+ device="cpu",
+ )
+ gmm.means_ = data["means_"]
+ gmm.weights_ = data["weights_"]
+ gmm.covariances_ = data["covariances_"]
+ gmm.precisions_cholesky_ = data["precisions_cholesky_"]
+ gmm._update_inference_cache()
+
+ if device != "cpu":
+ gmm.to(device)
+
+ return gmm
diff --git a/clean/image/fsd/fsd/projection.py b/clean/image/fsd/fsd/projection.py
new file mode 100644
index 0000000000000000000000000000000000000000..dce61abef5f40cd781e415d32e16edbd6198943b
--- /dev/null
+++ b/clean/image/fsd/fsd/projection.py
@@ -0,0 +1,78 @@
+"""Learned feature transforms applied to FSD vectors."""
+
+import torch
+import torch.nn as nn
+
+
+class FeatureTransform(nn.Module):
+ """Learned residual feature transform: f(x) = x + MLP(x).
+
+ Two architectures are supported, selected by constructor arguments:
+ - Narrow (default): dim → hidden → hidden → dim (3 linear layers)
+ - Wide: dim → h1 → h2 → h3 → h2 → h1 → dim (6 linear layers)
+ """
+
+ def __init__(self, dim=960, hidden=128, *, h1=None, h2=None, h3=None):
+ super().__init__()
+ if h1 is not None:
+ # Wide (hourglass) architecture
+ self.net = nn.Sequential(
+ nn.Linear(dim, h1, dtype=torch.float64),
+ nn.GELU(),
+ nn.Linear(h1, h2, dtype=torch.float64),
+ nn.GELU(),
+ nn.Linear(h2, h3, dtype=torch.float64),
+ nn.GELU(),
+ nn.Linear(h3, h2, dtype=torch.float64),
+ nn.GELU(),
+ nn.Linear(h2, h1, dtype=torch.float64),
+ nn.GELU(),
+ nn.Linear(h1, dim, dtype=torch.float64),
+ )
+ else:
+ # Narrow (default) architecture
+ self.net = nn.Sequential(
+ nn.Linear(dim, hidden, dtype=torch.float64),
+ nn.GELU(),
+ nn.Linear(hidden, hidden, dtype=torch.float64),
+ nn.GELU(),
+ nn.Linear(hidden, dim, dtype=torch.float64),
+ )
+
+ def forward(self, x):
+ return x + self.net(x)
+
+
+def apply_projections(x, projections):
+ """Apply transforms in sequence. No-op if list is empty."""
+ for proj in projections:
+ x = proj(x)
+ return x
+
+
+def _make_transform(config):
+ """Instantiate a FeatureTransform from a config dict."""
+ if "h1" in config:
+ return FeatureTransform(dim=config["dim"], h1=config["h1"], h2=config["h2"], h3=config["h3"])
+ return FeatureTransform(dim=config["dim"], hidden=config["hidden"])
+
+
+def load_transforms(path, device="cpu"):
+ """Load pre-trained transforms from a single weights file.
+
+ Args:
+ path: Path to the .pt file.
+ device: Device to load onto.
+
+ Returns:
+ List of FeatureTransform modules in eval mode.
+ """
+ data = torch.load(path, map_location=device, weights_only=True)
+ config = data["config"]
+ transforms = []
+ for state_dict in data["transforms"]:
+ t = _make_transform(config)
+ t.load_state_dict(state_dict)
+ t = t.to(device).eval()
+ transforms.append(t)
+ return transforms
diff --git a/clean/image/fsd/fsd/serve.py b/clean/image/fsd/fsd/serve.py
new file mode 100644
index 0000000000000000000000000000000000000000..066b22f9171cc5da991d04c787e5549716b3cd06
--- /dev/null
+++ b/clean/image/fsd/fsd/serve.py
@@ -0,0 +1,176 @@
+"""Ray Serve deployment for FSD scoring.
+
+Deploys the full scoring pipeline across multiple GPUs via Ray Serve.
+Each replica loads its own copy of the model on a dedicated GPU fraction.
+
+Usage via CLI:
+ fsd-score-ray serve
+ fsd-score-ray score --dir ./images/
+"""
+
+import json
+import logging
+import traceback
+
+import torch
+from pathlib import Path
+from ray import serve
+from starlette.requests import Request as StarletteRequest
+from starlette.responses import JSONResponse
+
+from .fre import FRE
+from .fsd_computation import compute_fsd
+from .gmm import load_gmm
+from .projection import apply_projections, load_transforms
+
+
+@serve.deployment(
+ ray_actor_options={"num_gpus": 1, "num_cpus": 1},
+ max_ongoing_requests=1,
+)
+class FSDScorer:
+ """Ray Serve deployment that scores images for AI-generated content.
+
+ Accepts JSON requests with either a file path or base64-encoded image.
+ """
+
+ def __init__(self, weights_dir: str, threshold: float = -2.0):
+ self._logger = logging.getLogger("ray.serve")
+ weights_dir = Path(weights_dir)
+ self.threshold = threshold
+ self.device = "cuda" if torch.cuda.is_available() else "cpu"
+
+ # Load config
+ with open(weights_dir / "config.json") as f:
+ self.config = json.load(f)
+
+ # Load FRE
+ self.fre = FRE.from_pretrained(
+ weights_dir / self.config["fre"]["weights_file"], device=self.device
+ )
+
+ # Load GMM
+ self.gmm = load_gmm(
+ weights_dir / self.config["gmm"]["weights_file"], device=self.device
+ )
+ self.train_mean = self.config["scoring"]["train_mean"]
+ self.train_std = self.config["scoring"]["train_std"]
+
+ # Load learned transforms
+ self.projections = load_transforms(
+ weights_dir / self.config["transforms"]["weights_file"], device=self.device
+ )
+
+ self._logger.info(f"FSDScorer ready on {self.device}")
+
+ def _score_image(self, image) -> dict:
+ """Score a single image (path string or PIL Image)."""
+ fsd_config = self.config["fsd"]
+ fsd_vec = compute_fsd(
+ image,
+ self.fre,
+ kernel_size=fsd_config["kernel_size"],
+ num_scales=fsd_config["num_scales"],
+ max_size=fsd_config["max_size"],
+ resize_mode=fsd_config["resize_mode"],
+ )
+
+ fsd_vec = fsd_vec.to(self.device).unsqueeze(0)
+ with torch.no_grad():
+ fsd_vec = apply_projections(fsd_vec, self.projections)
+
+ raw_score = self.gmm.score_samples(fsd_vec).item()
+ z_score = (raw_score - self.train_mean) / self.train_std
+
+ return {
+ "z_score": z_score,
+ "raw_score": raw_score,
+ "is_fake": z_score < self.threshold,
+ "threshold": self.threshold,
+ }
+
+ async def score(self, image_path: str) -> dict:
+ """Score an image by file path. Used for programmatic Ray calls."""
+ try:
+ return self._score_image(image_path)
+ except Exception as e:
+ self._logger.error(f"Error scoring {image_path}: {repr(e)}")
+ return {"error": repr(e), "path": image_path}
+
+ async def __call__(self, request: StarletteRequest) -> JSONResponse:
+ """HTTP endpoint. Accepts JSON with 'path' or 'image_b64'."""
+ try:
+ data = await request.json()
+ except Exception:
+ return JSONResponse(status_code=400, content={"error": "Invalid JSON body"})
+
+ try:
+ if "path" in data:
+ result = self._score_image(data["path"])
+ elif "image_b64" in data:
+ import base64
+ from io import BytesIO
+ from PIL import Image
+
+ image_bytes = base64.b64decode(data["image_b64"])
+ image = Image.open(BytesIO(image_bytes))
+ result = self._score_image(image)
+ else:
+ return JSONResponse(
+ status_code=422,
+ content={"error": "Request must contain 'path' or 'image_b64'"},
+ )
+ return JSONResponse(content=result)
+ except Exception as e:
+ self._logger.error(f"Error: {repr(e)}\n{traceback.format_exc()}")
+ return JSONResponse(
+ status_code=500,
+ content={"error": repr(e)},
+ )
+
+
+def build_app(
+ weights_dir=None,
+ threshold=-2.0,
+ num_gpus=None,
+ gpu_per_replica=1.0,
+):
+ """Build and deploy the Ray Serve application.
+
+ Args:
+ weights_dir: Path to weights directory.
+ threshold: Z-score threshold.
+ num_gpus: Total GPUs to use. If None, uses all available.
+ gpu_per_replica: GPU fraction per replica.
+
+ Returns:
+ (handle, num_replicas) tuple.
+ """
+ import ray
+
+ if num_gpus is None:
+ if ray.is_initialized():
+ num_gpus = int(ray.cluster_resources().get("GPU", 1))
+ else:
+ num_gpus = torch.cuda.device_count() or 1
+
+ num_replicas = max(1, int(num_gpus / gpu_per_replica))
+ if weights_dir is None:
+ from .weights import get_weights_dir
+ weights_dir = get_weights_dir()
+ weights_dir = str(Path(weights_dir).resolve())
+
+ app = FSDScorer.options(
+ ray_actor_options={"num_gpus": gpu_per_replica, "num_cpus": 1},
+ num_replicas=num_replicas,
+ max_ongoing_requests=1,
+ ).bind(weights_dir=weights_dir, threshold=threshold)
+
+ handle = serve.run(
+ app,
+ route_prefix="/",
+ name="fsd-scorer",
+ blocking=False,
+ )
+
+ return handle, num_replicas
diff --git a/clean/image/fsd/fsd/weights.py b/clean/image/fsd/fsd/weights.py
new file mode 100644
index 0000000000000000000000000000000000000000..efabaf8b0ea69624ff752e36e0a076b755f0015f
--- /dev/null
+++ b/clean/image/fsd/fsd/weights.py
@@ -0,0 +1,106 @@
+"""Auto-download and cache pre-trained weights from GitHub releases."""
+
+import sys
+from pathlib import Path
+from urllib.request import urlopen, Request
+from urllib.error import URLError
+
+# GitHub release URL pattern
+_REPO = "ductai199x/Forensic-Self-Descriptions-CVPR25"
+_RELEASE_TAG = "v1.2.0"
+_BASE_URL = f"https://github.com/{_REPO}/releases/download/{_RELEASE_TAG}"
+
+_WEIGHT_FILES = ["config.json", "fre.pt", "gmm.pt", "fsd_transforms.pt"]
+_ATTRIBUTION_FILES = ["attribution_transforms.pt", "source_gmms.pt"]
+
+_CACHE_DIR = Path.home() / ".cache" / "fsd" / _RELEASE_TAG
+
+
+def get_weights_dir(attribution=False):
+ """Find or download pre-trained weights.
+
+ Search order:
+ 1. ~/.cache/fsd// (versioned cache, auto-downloaded)
+ 2. Auto-download from GitHub releases if not cached
+
+ To use custom weights, pass the directory explicitly to
+ ``FSDDetector.load(weights_dir="path/to/weights/")``.
+
+ Args:
+ attribution: If True, also ensure attribution weight files are present.
+
+ Returns:
+ Path to weights directory containing config.json and weight files.
+ """
+ def _has_weights(d, need_attribution=False):
+ if not (d / "config.json").exists():
+ return False
+ if need_attribution:
+ return all((d / f).exists() for f in _ATTRIBUTION_FILES)
+ return True
+
+ # 1. Versioned cache
+ if _has_weights(_CACHE_DIR, attribution):
+ return _CACHE_DIR
+
+ # 2. Auto-download
+ return download_weights(attribution=attribution)
+
+
+def download_weights(dest=None, attribution=False):
+ """Download pre-trained weights from GitHub releases.
+
+ Args:
+ dest: Destination directory. Defaults to ~/.cache/fsd//.
+ attribution: If True, also download attribution weight files.
+
+ Returns:
+ Path to the weights directory.
+ """
+ dest = Path(dest) if dest is not None else _CACHE_DIR
+ dest.mkdir(parents=True, exist_ok=True)
+
+ files = _WEIGHT_FILES + (_ATTRIBUTION_FILES if attribution else [])
+ for filename in files:
+ filepath = dest / filename
+ if filepath.exists():
+ continue
+
+ url = f"{_BASE_URL}/{filename}"
+ print(f"Downloading {filename}...", end=" ", flush=True, file=sys.stderr)
+
+ try:
+ req = Request(url, headers={"User-Agent": "fsd-detector"})
+ with urlopen(req, timeout=300) as resp:
+ total = resp.headers.get("Content-Length")
+ total = int(total) if total else None
+
+ # Download to temp file then rename (atomic)
+ tmp = filepath.with_suffix(".tmp")
+ downloaded = 0
+ with open(tmp, "wb") as f:
+ while True:
+ chunk = resp.read(1 << 20) # 1MB chunks
+ if not chunk:
+ break
+ f.write(chunk)
+ downloaded += len(chunk)
+ if total:
+ pct = downloaded * 100 // total
+ print(f"\rDownloading {filename}... {pct}%", end="", flush=True, file=sys.stderr)
+
+ tmp.rename(filepath)
+ size_mb = downloaded / (1 << 20)
+ print(f"\rDownloading {filename}... done ({size_mb:.1f} MB)", file=sys.stderr)
+
+ except (URLError, OSError) as e:
+ # Clean up partial download
+ tmp = filepath.with_suffix(".tmp")
+ tmp.unlink(missing_ok=True)
+ raise RuntimeError(
+ f"Failed to download {filename} from {url}: {e}\n"
+ f"You can download weights manually from:\n"
+ f" https://github.com/{_REPO}/releases/tag/{_RELEASE_TAG}"
+ ) from e
+
+ return dest
diff --git a/clean/image/fsd/pyproject.toml b/clean/image/fsd/pyproject.toml
new file mode 100644
index 0000000000000000000000000000000000000000..c0d1a1d2a97a84502e42d86b4dd6c76df29d05d6
--- /dev/null
+++ b/clean/image/fsd/pyproject.toml
@@ -0,0 +1,36 @@
+[build-system]
+requires = ["setuptools >= 68.0"]
+build-backend = "setuptools.build_meta"
+
+[project]
+name = "fsd-detector"
+version = "1.1.0"
+description = "Detecting AI-Generated Images via Forensic Self-Descriptions (CVPR 2025)"
+readme = "README.md"
+license = "CC-BY-NC-SA-4.0"
+requires-python = ">=3.12"
+authors = [
+ { name = "Tai D. Nguyen", email = "tdn47@drexel.edu" },
+]
+dependencies = [
+ "torch >= 2.10.0",
+ "scipy >= 1.17.0",
+ "pillow >= 12.1.0",
+ "click >= 8.3.1",
+ "tqdm >= 4.67.3",
+ "scikit-learn >= 1.8.0",
+ "pillow-heif >= 1.2.0",
+ "ray[serve] >= 2.53.0",
+ "gradio>=6.9.0",
+]
+
+[project.scripts]
+fsd-score = "fsd.cli:main"
+fsd-score-ray = "fsd.cli_ray:main"
+
+[project.urls]
+Repository = "https://github.com/ductai199x/Forensic-Self-Descriptions-CVPR25"
+Paper = "https://arxiv.org/abs/2503.21003"
+
+[tool.setuptools.packages.find]
+include = ["fsd*"]
diff --git a/clean/image/fsd/uv.lock b/clean/image/fsd/uv.lock
new file mode 100644
index 0000000000000000000000000000000000000000..c4df44cc36916128712350f6229853beb54570d5
--- /dev/null
+++ b/clean/image/fsd/uv.lock
@@ -0,0 +1,3030 @@
+version = 1
+revision = 2
+requires-python = ">=3.12"
+resolution-markers = [
+ "python_full_version >= '3.14' and sys_platform == 'win32'",
+ "python_full_version >= '3.14' and sys_platform == 'emscripten'",
+ "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'",
+ "python_full_version == '3.13.*' and sys_platform == 'win32'",
+ "python_full_version == '3.13.*' and sys_platform == 'emscripten'",
+ "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'",
+ "python_full_version < '3.13' and sys_platform == 'win32'",
+ "python_full_version < '3.13' and sys_platform == 'emscripten'",
+ "python_full_version < '3.13' and sys_platform != 'emscripten' and sys_platform != 'win32'",
+]
+
+[[package]]
+name = "aiofiles"
+version = "24.1.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/0b/03/a88171e277e8caa88a4c77808c20ebb04ba74cc4681bf1e9416c862de237/aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c", size = 30247, upload-time = "2024-06-24T11:02:03.584Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a5/45/30bb92d442636f570cb5651bc661f52b610e2eec3f891a5dc3a4c3667db0/aiofiles-24.1.0-py3-none-any.whl", hash = "sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5", size = 15896, upload-time = "2024-06-24T11:02:01.529Z" },
+]
+
+[[package]]
+name = "aiohappyeyeballs"
+version = "2.6.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" },
+]
+
+[[package]]
+name = "aiohttp"
+version = "3.13.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "aiohappyeyeballs" },
+ { name = "aiosignal" },
+ { name = "attrs" },
+ { name = "frozenlist" },
+ { name = "multidict" },
+ { name = "propcache" },
+ { name = "yarl" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/50/42/32cf8e7704ceb4481406eb87161349abb46a57fee3f008ba9cb610968646/aiohttp-3.13.3.tar.gz", hash = "sha256:a949eee43d3782f2daae4f4a2819b2cb9b0c5d3b7f7a927067cc84dafdbb9f88", size = 7844556, upload-time = "2026-01-03T17:33:05.204Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a0/be/4fc11f202955a69e0db803a12a062b8379c970c7c84f4882b6da17337cc1/aiohttp-3.13.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b903a4dfee7d347e2d87697d0713be59e0b87925be030c9178c5faa58ea58d5c", size = 739732, upload-time = "2026-01-03T17:30:14.23Z" },
+ { url = "https://files.pythonhosted.org/packages/97/2c/621d5b851f94fa0bb7430d6089b3aa970a9d9b75196bc93bb624b0db237a/aiohttp-3.13.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a45530014d7a1e09f4a55f4f43097ba0fd155089372e105e4bff4ca76cb1b168", size = 494293, upload-time = "2026-01-03T17:30:15.96Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/43/4be01406b78e1be8320bb8316dc9c42dbab553d281c40364e0f862d5661c/aiohttp-3.13.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:27234ef6d85c914f9efeb77ff616dbf4ad2380be0cda40b4db086ffc7ddd1b7d", size = 493533, upload-time = "2026-01-03T17:30:17.431Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/a8/5a35dc56a06a2c90d4742cbf35294396907027f80eea696637945a106f25/aiohttp-3.13.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d32764c6c9aafb7fb55366a224756387cd50bfa720f32b88e0e6fa45b27dcf29", size = 1737839, upload-time = "2026-01-03T17:30:19.422Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/62/4b9eeb331da56530bf2e198a297e5303e1c1ebdceeb00fe9b568a65c5a0c/aiohttp-3.13.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b1a6102b4d3ebc07dad44fbf07b45bb600300f15b552ddf1851b5390202ea2e3", size = 1703932, upload-time = "2026-01-03T17:30:21.756Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/f6/af16887b5d419e6a367095994c0b1332d154f647e7dc2bd50e61876e8e3d/aiohttp-3.13.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c014c7ea7fb775dd015b2d3137378b7be0249a448a1612268b5a90c2d81de04d", size = 1771906, upload-time = "2026-01-03T17:30:23.932Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/83/397c634b1bcc24292fa1e0c7822800f9f6569e32934bdeef09dae7992dfb/aiohttp-3.13.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2b8d8ddba8f95ba17582226f80e2de99c7a7948e66490ef8d947e272a93e9463", size = 1871020, upload-time = "2026-01-03T17:30:26Z" },
+ { url = "https://files.pythonhosted.org/packages/86/f6/a62cbbf13f0ac80a70f71b1672feba90fdb21fd7abd8dbf25c0105fb6fa3/aiohttp-3.13.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ae8dd55c8e6c4257eae3a20fd2c8f41edaea5992ed67156642493b8daf3cecc", size = 1755181, upload-time = "2026-01-03T17:30:27.554Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/87/20a35ad487efdd3fba93d5843efdfaa62d2f1479eaafa7453398a44faf13/aiohttp-3.13.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:01ad2529d4b5035578f5081606a465f3b814c542882804e2e8cda61adf5c71bf", size = 1561794, upload-time = "2026-01-03T17:30:29.254Z" },
+ { url = "https://files.pythonhosted.org/packages/de/95/8fd69a66682012f6716e1bc09ef8a1a2a91922c5725cb904689f112309c4/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bb4f7475e359992b580559e008c598091c45b5088f28614e855e42d39c2f1033", size = 1697900, upload-time = "2026-01-03T17:30:31.033Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/66/7b94b3b5ba70e955ff597672dad1691333080e37f50280178967aff68657/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c19b90316ad3b24c69cd78d5c9b4f3aa4497643685901185b65166293d36a00f", size = 1728239, upload-time = "2026-01-03T17:30:32.703Z" },
+ { url = "https://files.pythonhosted.org/packages/47/71/6f72f77f9f7d74719692ab65a2a0252584bf8d5f301e2ecb4c0da734530a/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:96d604498a7c782cb15a51c406acaea70d8c027ee6b90c569baa6e7b93073679", size = 1740527, upload-time = "2026-01-03T17:30:34.695Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/b4/75ec16cbbd5c01bdaf4a05b19e103e78d7ce1ef7c80867eb0ace42ff4488/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:084911a532763e9d3dd95adf78a78f4096cd5f58cdc18e6fdbc1b58417a45423", size = 1554489, upload-time = "2026-01-03T17:30:36.864Z" },
+ { url = "https://files.pythonhosted.org/packages/52/8f/bc518c0eea29f8406dcf7ed1f96c9b48e3bc3995a96159b3fc11f9e08321/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7a4a94eb787e606d0a09404b9c38c113d3b099d508021faa615d70a0131907ce", size = 1767852, upload-time = "2026-01-03T17:30:39.433Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/f2/a07a75173124f31f11ea6f863dc44e6f09afe2bca45dd4e64979490deab1/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:87797e645d9d8e222e04160ee32aa06bc5c163e8499f24db719e7852ec23093a", size = 1722379, upload-time = "2026-01-03T17:30:41.081Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/4a/1a3fee7c21350cac78e5c5cef711bac1b94feca07399f3d406972e2d8fcd/aiohttp-3.13.3-cp312-cp312-win32.whl", hash = "sha256:b04be762396457bef43f3597c991e192ee7da460a4953d7e647ee4b1c28e7046", size = 428253, upload-time = "2026-01-03T17:30:42.644Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/b7/76175c7cb4eb73d91ad63c34e29fc4f77c9386bba4a65b53ba8e05ee3c39/aiohttp-3.13.3-cp312-cp312-win_amd64.whl", hash = "sha256:e3531d63d3bdfa7e3ac5e9b27b2dd7ec9df3206a98e0b3445fa906f233264c57", size = 455407, upload-time = "2026-01-03T17:30:44.195Z" },
+ { url = "https://files.pythonhosted.org/packages/97/8a/12ca489246ca1faaf5432844adbfce7ff2cc4997733e0af120869345643a/aiohttp-3.13.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5dff64413671b0d3e7d5918ea490bdccb97a4ad29b3f311ed423200b2203e01c", size = 734190, upload-time = "2026-01-03T17:30:45.832Z" },
+ { url = "https://files.pythonhosted.org/packages/32/08/de43984c74ed1fca5c014808963cc83cb00d7bb06af228f132d33862ca76/aiohttp-3.13.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:87b9aab6d6ed88235aa2970294f496ff1a1f9adcd724d800e9b952395a80ffd9", size = 491783, upload-time = "2026-01-03T17:30:47.466Z" },
+ { url = "https://files.pythonhosted.org/packages/17/f8/8dd2cf6112a5a76f81f81a5130c57ca829d101ad583ce57f889179accdda/aiohttp-3.13.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:425c126c0dc43861e22cb1c14ba4c8e45d09516d0a3ae0a3f7494b79f5f233a3", size = 490704, upload-time = "2026-01-03T17:30:49.373Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/40/a46b03ca03936f832bc7eaa47cfbb1ad012ba1be4790122ee4f4f8cba074/aiohttp-3.13.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7f9120f7093c2a32d9647abcaf21e6ad275b4fbec5b55969f978b1a97c7c86bf", size = 1720652, upload-time = "2026-01-03T17:30:50.974Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/7e/917fe18e3607af92657e4285498f500dca797ff8c918bd7d90b05abf6c2a/aiohttp-3.13.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:697753042d57f4bf7122cab985bf15d0cef23c770864580f5af4f52023a56bd6", size = 1692014, upload-time = "2026-01-03T17:30:52.729Z" },
+ { url = "https://files.pythonhosted.org/packages/71/b6/cefa4cbc00d315d68973b671cf105b21a609c12b82d52e5d0c9ae61d2a09/aiohttp-3.13.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6de499a1a44e7de70735d0b39f67c8f25eb3d91eb3103be99ca0fa882cdd987d", size = 1759777, upload-time = "2026-01-03T17:30:54.537Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/e3/e06ee07b45e59e6d81498b591fc589629be1553abb2a82ce33efe2a7b068/aiohttp-3.13.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:37239e9f9a7ea9ac5bf6b92b0260b01f8a22281996da609206a84df860bc1261", size = 1861276, upload-time = "2026-01-03T17:30:56.512Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/24/75d274228acf35ceeb2850b8ce04de9dd7355ff7a0b49d607ee60c29c518/aiohttp-3.13.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f76c1e3fe7d7c8afad7ed193f89a292e1999608170dcc9751a7462a87dfd5bc0", size = 1743131, upload-time = "2026-01-03T17:30:58.256Z" },
+ { url = "https://files.pythonhosted.org/packages/04/98/3d21dde21889b17ca2eea54fdcff21b27b93f45b7bb94ca029c31ab59dc3/aiohttp-3.13.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fc290605db2a917f6e81b0e1e0796469871f5af381ce15c604a3c5c7e51cb730", size = 1556863, upload-time = "2026-01-03T17:31:00.445Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/84/da0c3ab1192eaf64782b03971ab4055b475d0db07b17eff925e8c93b3aa5/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4021b51936308aeea0367b8f006dc999ca02bc118a0cc78c303f50a2ff6afb91", size = 1682793, upload-time = "2026-01-03T17:31:03.024Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/0f/5802ada182f575afa02cbd0ec5180d7e13a402afb7c2c03a9aa5e5d49060/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:49a03727c1bba9a97d3e93c9f93ca03a57300f484b6e935463099841261195d3", size = 1716676, upload-time = "2026-01-03T17:31:04.842Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/8c/714d53bd8b5a4560667f7bbbb06b20c2382f9c7847d198370ec6526af39c/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3d9908a48eb7416dc1f4524e69f1d32e5d90e3981e4e37eb0aa1cd18f9cfa2a4", size = 1733217, upload-time = "2026-01-03T17:31:06.868Z" },
+ { url = "https://files.pythonhosted.org/packages/7d/79/e2176f46d2e963facea939f5be2d26368ce543622be6f00a12844d3c991f/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2712039939ec963c237286113c68dbad80a82a4281543f3abf766d9d73228998", size = 1552303, upload-time = "2026-01-03T17:31:08.958Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/6a/28ed4dea1759916090587d1fe57087b03e6c784a642b85ef48217b0277ae/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7bfdc049127717581866fa4708791220970ce291c23e28ccf3922c700740fdc0", size = 1763673, upload-time = "2026-01-03T17:31:10.676Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/35/4a3daeb8b9fab49240d21c04d50732313295e4bd813a465d840236dd0ce1/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8057c98e0c8472d8846b9c79f56766bcc57e3e8ac7bfd510482332366c56c591", size = 1721120, upload-time = "2026-01-03T17:31:12.575Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/9f/d643bb3c5fb99547323e635e251c609fbbc660d983144cfebec529e09264/aiohttp-3.13.3-cp313-cp313-win32.whl", hash = "sha256:1449ceddcdbcf2e0446957863af03ebaaa03f94c090f945411b61269e2cb5daf", size = 427383, upload-time = "2026-01-03T17:31:14.382Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/f1/ab0395f8a79933577cdd996dd2f9aa6014af9535f65dddcf88204682fe62/aiohttp-3.13.3-cp313-cp313-win_amd64.whl", hash = "sha256:693781c45a4033d31d4187d2436f5ac701e7bbfe5df40d917736108c1cc7436e", size = 453899, upload-time = "2026-01-03T17:31:15.958Z" },
+ { url = "https://files.pythonhosted.org/packages/99/36/5b6514a9f5d66f4e2597e40dea2e3db271e023eb7a5d22defe96ba560996/aiohttp-3.13.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:ea37047c6b367fd4bd632bff8077449b8fa034b69e812a18e0132a00fae6e808", size = 737238, upload-time = "2026-01-03T17:31:17.909Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/49/459327f0d5bcd8c6c9ca69e60fdeebc3622861e696490d8674a6d0cb90a6/aiohttp-3.13.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6fc0e2337d1a4c3e6acafda6a78a39d4c14caea625124817420abceed36e2415", size = 492292, upload-time = "2026-01-03T17:31:19.919Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/0b/b97660c5fd05d3495b4eb27f2d0ef18dc1dc4eff7511a9bf371397ff0264/aiohttp-3.13.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c685f2d80bb67ca8c3837823ad76196b3694b0159d232206d1e461d3d434666f", size = 493021, upload-time = "2026-01-03T17:31:21.636Z" },
+ { url = "https://files.pythonhosted.org/packages/54/d4/438efabdf74e30aeceb890c3290bbaa449780583b1270b00661126b8aae4/aiohttp-3.13.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e377758516d262bde50c2584fc6c578af272559c409eecbdd2bae1601184d6", size = 1717263, upload-time = "2026-01-03T17:31:23.296Z" },
+ { url = "https://files.pythonhosted.org/packages/71/f2/7bddc7fd612367d1459c5bcf598a9e8f7092d6580d98de0e057eb42697ad/aiohttp-3.13.3-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:34749271508078b261c4abb1767d42b8d0c0cc9449c73a4df494777dc55f0687", size = 1669107, upload-time = "2026-01-03T17:31:25.334Z" },
+ { url = "https://files.pythonhosted.org/packages/00/5a/1aeaecca40e22560f97610a329e0e5efef5e0b5afdf9f857f0d93839ab2e/aiohttp-3.13.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:82611aeec80eb144416956ec85b6ca45a64d76429c1ed46ae1b5f86c6e0c9a26", size = 1760196, upload-time = "2026-01-03T17:31:27.394Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/f8/0ff6992bea7bd560fc510ea1c815f87eedd745fe035589c71ce05612a19a/aiohttp-3.13.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2fff83cfc93f18f215896e3a190e8e5cb413ce01553901aca925176e7568963a", size = 1843591, upload-time = "2026-01-03T17:31:29.238Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/d1/e30e537a15f53485b61f5be525f2157da719819e8377298502aebac45536/aiohttp-3.13.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bbe7d4cecacb439e2e2a8a1a7b935c25b812af7a5fd26503a66dadf428e79ec1", size = 1720277, upload-time = "2026-01-03T17:31:31.053Z" },
+ { url = "https://files.pythonhosted.org/packages/84/45/23f4c451d8192f553d38d838831ebbc156907ea6e05557f39563101b7717/aiohttp-3.13.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b928f30fe49574253644b1ca44b1b8adbd903aa0da4b9054a6c20fc7f4092a25", size = 1548575, upload-time = "2026-01-03T17:31:32.87Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/ed/0a42b127a43712eda7807e7892c083eadfaf8429ca8fb619662a530a3aab/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7b5e8fe4de30df199155baaf64f2fcd604f4c678ed20910db8e2c66dc4b11603", size = 1679455, upload-time = "2026-01-03T17:31:34.76Z" },
+ { url = "https://files.pythonhosted.org/packages/2e/b5/c05f0c2b4b4fe2c9d55e73b6d3ed4fd6c9dc2684b1d81cbdf77e7fad9adb/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:8542f41a62bcc58fc7f11cf7c90e0ec324ce44950003feb70640fc2a9092c32a", size = 1687417, upload-time = "2026-01-03T17:31:36.699Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/6b/915bc5dad66aef602b9e459b5a973529304d4e89ca86999d9d75d80cbd0b/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:5e1d8c8b8f1d91cd08d8f4a3c2b067bfca6ec043d3ff36de0f3a715feeedf926", size = 1729968, upload-time = "2026-01-03T17:31:38.622Z" },
+ { url = "https://files.pythonhosted.org/packages/11/3b/e84581290a9520024a08640b63d07673057aec5ca548177a82026187ba73/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:90455115e5da1c3c51ab619ac57f877da8fd6d73c05aacd125c5ae9819582aba", size = 1545690, upload-time = "2026-01-03T17:31:40.57Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/04/0c3655a566c43fd647c81b895dfe361b9f9ad6d58c19309d45cff52d6c3b/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:042e9e0bcb5fba81886c8b4fbb9a09d6b8a00245fd8d88e4d989c1f96c74164c", size = 1746390, upload-time = "2026-01-03T17:31:42.857Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/53/71165b26978f719c3419381514c9690bd5980e764a09440a10bb816ea4ab/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2eb752b102b12a76ca02dff751a801f028b4ffbbc478840b473597fc91a9ed43", size = 1702188, upload-time = "2026-01-03T17:31:44.984Z" },
+ { url = "https://files.pythonhosted.org/packages/29/a7/cbe6c9e8e136314fa1980da388a59d2f35f35395948a08b6747baebb6aa6/aiohttp-3.13.3-cp314-cp314-win32.whl", hash = "sha256:b556c85915d8efaed322bf1bdae9486aa0f3f764195a0fb6ee962e5c71ef5ce1", size = 433126, upload-time = "2026-01-03T17:31:47.463Z" },
+ { url = "https://files.pythonhosted.org/packages/de/56/982704adea7d3b16614fc5936014e9af85c0e34b58f9046655817f04306e/aiohttp-3.13.3-cp314-cp314-win_amd64.whl", hash = "sha256:9bf9f7a65e7aa20dd764151fb3d616c81088f91f8df39c3893a536e279b4b984", size = 459128, upload-time = "2026-01-03T17:31:49.2Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/2a/3c79b638a9c3d4658d345339d22070241ea341ed4e07b5ac60fb0f418003/aiohttp-3.13.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:05861afbbec40650d8a07ea324367cb93e9e8cc7762e04dd4405df99fa65159c", size = 769512, upload-time = "2026-01-03T17:31:51.134Z" },
+ { url = "https://files.pythonhosted.org/packages/29/b9/3e5014d46c0ab0db8707e0ac2711ed28c4da0218c358a4e7c17bae0d8722/aiohttp-3.13.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2fc82186fadc4a8316768d61f3722c230e2c1dcab4200d52d2ebdf2482e47592", size = 506444, upload-time = "2026-01-03T17:31:52.85Z" },
+ { url = "https://files.pythonhosted.org/packages/90/03/c1d4ef9a054e151cd7839cdc497f2638f00b93cbe8043983986630d7a80c/aiohttp-3.13.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0add0900ff220d1d5c5ebbf99ed88b0c1bbf87aa7e4262300ed1376a6b13414f", size = 510798, upload-time = "2026-01-03T17:31:54.91Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/76/8c1e5abbfe8e127c893fe7ead569148a4d5a799f7cf958d8c09f3eedf097/aiohttp-3.13.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:568f416a4072fbfae453dcf9a99194bbb8bdeab718e08ee13dfa2ba0e4bebf29", size = 1868835, upload-time = "2026-01-03T17:31:56.733Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/ac/984c5a6f74c363b01ff97adc96a3976d9c98940b8969a1881575b279ac5d/aiohttp-3.13.3-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:add1da70de90a2569c5e15249ff76a631ccacfe198375eead4aadf3b8dc849dc", size = 1720486, upload-time = "2026-01-03T17:31:58.65Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/9a/b7039c5f099c4eb632138728828b33428585031a1e658d693d41d07d89d1/aiohttp-3.13.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:10b47b7ba335d2e9b1239fa571131a87e2d8ec96b333e68b2a305e7a98b0bae2", size = 1847951, upload-time = "2026-01-03T17:32:00.989Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/02/3bec2b9a1ba3c19ff89a43a19324202b8eb187ca1e928d8bdac9bbdddebd/aiohttp-3.13.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3dd4dce1c718e38081c8f35f323209d4c1df7d4db4bab1b5c88a6b4d12b74587", size = 1941001, upload-time = "2026-01-03T17:32:03.122Z" },
+ { url = "https://files.pythonhosted.org/packages/37/df/d879401cedeef27ac4717f6426c8c36c3091c6e9f08a9178cc87549c537f/aiohttp-3.13.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34bac00a67a812570d4a460447e1e9e06fae622946955f939051e7cc895cfab8", size = 1797246, upload-time = "2026-01-03T17:32:05.255Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/15/be122de1f67e6953add23335c8ece6d314ab67c8bebb3f181063010795a7/aiohttp-3.13.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a19884d2ee70b06d9204b2727a7b9f983d0c684c650254679e716b0b77920632", size = 1627131, upload-time = "2026-01-03T17:32:07.607Z" },
+ { url = "https://files.pythonhosted.org/packages/12/12/70eedcac9134cfa3219ab7af31ea56bc877395b1ac30d65b1bc4b27d0438/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5f8ca7f2bb6ba8348a3614c7918cc4bb73268c5ac2a207576b7afea19d3d9f64", size = 1795196, upload-time = "2026-01-03T17:32:09.59Z" },
+ { url = "https://files.pythonhosted.org/packages/32/11/b30e1b1cd1f3054af86ebe60df96989c6a414dd87e27ad16950eee420bea/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:b0d95340658b9d2f11d9697f59b3814a9d3bb4b7a7c20b131df4bcef464037c0", size = 1782841, upload-time = "2026-01-03T17:32:11.445Z" },
+ { url = "https://files.pythonhosted.org/packages/88/0d/d98a9367b38912384a17e287850f5695c528cff0f14f791ce8ee2e4f7796/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:a1e53262fd202e4b40b70c3aff944a8155059beedc8a89bba9dc1f9ef06a1b56", size = 1795193, upload-time = "2026-01-03T17:32:13.705Z" },
+ { url = "https://files.pythonhosted.org/packages/43/a5/a2dfd1f5ff5581632c7f6a30e1744deda03808974f94f6534241ef60c751/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:d60ac9663f44168038586cab2157e122e46bdef09e9368b37f2d82d354c23f72", size = 1621979, upload-time = "2026-01-03T17:32:15.965Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/f0/12973c382ae7c1cccbc4417e129c5bf54c374dfb85af70893646e1f0e749/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:90751b8eed69435bac9ff4e3d2f6b3af1f57e37ecb0fbeee59c0174c9e2d41df", size = 1822193, upload-time = "2026-01-03T17:32:18.219Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/5f/24155e30ba7f8c96918af1350eb0663e2430aad9e001c0489d89cd708ab1/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fc353029f176fd2b3ec6cfc71be166aba1936fe5d73dd1992ce289ca6647a9aa", size = 1769801, upload-time = "2026-01-03T17:32:20.25Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/f8/7314031ff5c10e6ece114da79b338ec17eeff3a079e53151f7e9f43c4723/aiohttp-3.13.3-cp314-cp314t-win32.whl", hash = "sha256:2e41b18a58da1e474a057b3d35248d8320029f61d70a37629535b16a0c8f3767", size = 466523, upload-time = "2026-01-03T17:32:22.215Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/63/278a98c715ae467624eafe375542d8ba9b4383a016df8fdefe0ae28382a7/aiohttp-3.13.3-cp314-cp314t-win_amd64.whl", hash = "sha256:44531a36aa2264a1860089ffd4dce7baf875ee5a6079d5fb42e261c704ef7344", size = 499694, upload-time = "2026-01-03T17:32:24.546Z" },
+]
+
+[[package]]
+name = "aiohttp-cors"
+version = "0.8.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "aiohttp" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/d89e846a5444b3d5eb8985a6ddb0daef3774928e1bfbce8e84ec97b0ffa7/aiohttp_cors-0.8.1.tar.gz", hash = "sha256:ccacf9cb84b64939ea15f859a146af1f662a6b1d68175754a07315e305fb1403", size = 38626, upload-time = "2025-03-31T14:16:20.048Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/98/3b/40a68de458904bcc143622015fff2352b6461cd92fd66d3527bf1c6f5716/aiohttp_cors-0.8.1-py3-none-any.whl", hash = "sha256:3180cf304c5c712d626b9162b195b1db7ddf976a2a25172b35bb2448b890a80d", size = 25231, upload-time = "2025-03-31T14:16:18.478Z" },
+]
+
+[[package]]
+name = "aiosignal"
+version = "1.4.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "frozenlist" },
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" },
+]
+
+[[package]]
+name = "annotated-doc"
+version = "0.0.4"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288, upload-time = "2025-11-10T22:07:42.062Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303, upload-time = "2025-11-10T22:07:40.673Z" },
+]
+
+[[package]]
+name = "annotated-types"
+version = "0.7.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
+]
+
+[[package]]
+name = "anyio"
+version = "4.12.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "idna" },
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/96/f0/5eb65b2bb0d09ac6776f2eb54adee6abe8228ea05b20a5ad0e4945de8aac/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703", size = 228685, upload-time = "2026-01-06T11:45:21.246Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" },
+]
+
+[[package]]
+name = "attrs"
+version = "25.4.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251, upload-time = "2025-10-06T13:54:44.725Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" },
+]
+
+[[package]]
+name = "audioop-lts"
+version = "0.2.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/38/53/946db57842a50b2da2e0c1e34bd37f36f5aadba1a929a3971c5d7841dbca/audioop_lts-0.2.2.tar.gz", hash = "sha256:64d0c62d88e67b98a1a5e71987b7aa7b5bcffc7dcee65b635823dbdd0a8dbbd0", size = 30686, upload-time = "2025-08-05T16:43:17.409Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/de/d4/94d277ca941de5a507b07f0b592f199c22454eeaec8f008a286b3fbbacd6/audioop_lts-0.2.2-cp313-abi3-macosx_10_13_universal2.whl", hash = "sha256:fd3d4602dc64914d462924a08c1a9816435a2155d74f325853c1f1ac3b2d9800", size = 46523, upload-time = "2025-08-05T16:42:20.836Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/5a/656d1c2da4b555920ce4177167bfeb8623d98765594af59702c8873f60ec/audioop_lts-0.2.2-cp313-abi3-macosx_10_13_x86_64.whl", hash = "sha256:550c114a8df0aafe9a05442a1162dfc8fec37e9af1d625ae6060fed6e756f303", size = 27455, upload-time = "2025-08-05T16:42:22.283Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/83/ea581e364ce7b0d41456fb79d6ee0ad482beda61faf0cab20cbd4c63a541/audioop_lts-0.2.2-cp313-abi3-macosx_11_0_arm64.whl", hash = "sha256:9a13dc409f2564de15dd68be65b462ba0dde01b19663720c68c1140c782d1d75", size = 26997, upload-time = "2025-08-05T16:42:23.849Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/3b/e8964210b5e216e5041593b7d33e97ee65967f17c282e8510d19c666dab4/audioop_lts-0.2.2-cp313-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:51c916108c56aa6e426ce611946f901badac950ee2ddaf302b7ed35d9958970d", size = 85844, upload-time = "2025-08-05T16:42:25.208Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/2e/0a1c52faf10d51def20531a59ce4c706cb7952323b11709e10de324d6493/audioop_lts-0.2.2-cp313-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:47eba38322370347b1c47024defbd36374a211e8dd5b0dcbce7b34fdb6f8847b", size = 85056, upload-time = "2025-08-05T16:42:26.559Z" },
+ { url = "https://files.pythonhosted.org/packages/75/e8/cd95eef479656cb75ab05dfece8c1f8c395d17a7c651d88f8e6e291a63ab/audioop_lts-0.2.2-cp313-abi3-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba7c3a7e5f23e215cb271516197030c32aef2e754252c4c70a50aaff7031a2c8", size = 93892, upload-time = "2025-08-05T16:42:27.902Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/1e/a0c42570b74f83efa5cca34905b3eef03f7ab09fe5637015df538a7f3345/audioop_lts-0.2.2-cp313-abi3-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:def246fe9e180626731b26e89816e79aae2276f825420a07b4a647abaa84becc", size = 96660, upload-time = "2025-08-05T16:42:28.9Z" },
+ { url = "https://files.pythonhosted.org/packages/50/d5/8a0ae607ca07dbb34027bac8db805498ee7bfecc05fd2c148cc1ed7646e7/audioop_lts-0.2.2-cp313-abi3-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e160bf9df356d841bb6c180eeeea1834085464626dc1b68fa4e1d59070affdc3", size = 79143, upload-time = "2025-08-05T16:42:29.929Z" },
+ { url = "https://files.pythonhosted.org/packages/12/17/0d28c46179e7910bfb0bb62760ccb33edb5de973052cb2230b662c14ca2e/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4b4cd51a57b698b2d06cb9993b7ac8dfe89a3b2878e96bc7948e9f19ff51dba6", size = 84313, upload-time = "2025-08-05T16:42:30.949Z" },
+ { url = "https://files.pythonhosted.org/packages/84/ba/bd5d3806641564f2024e97ca98ea8f8811d4e01d9b9f9831474bc9e14f9e/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_ppc64le.whl", hash = "sha256:4a53aa7c16a60a6857e6b0b165261436396ef7293f8b5c9c828a3a203147ed4a", size = 93044, upload-time = "2025-08-05T16:42:31.959Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/5e/435ce8d5642f1f7679540d1e73c1c42d933331c0976eb397d1717d7f01a3/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_riscv64.whl", hash = "sha256:3fc38008969796f0f689f1453722a0f463da1b8a6fbee11987830bfbb664f623", size = 78766, upload-time = "2025-08-05T16:42:33.302Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/3b/b909e76b606cbfd53875693ec8c156e93e15a1366a012f0b7e4fb52d3c34/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_s390x.whl", hash = "sha256:15ab25dd3e620790f40e9ead897f91e79c0d3ce65fe193c8ed6c26cffdd24be7", size = 87640, upload-time = "2025-08-05T16:42:34.854Z" },
+ { url = "https://files.pythonhosted.org/packages/30/e7/8f1603b4572d79b775f2140d7952f200f5e6c62904585d08a01f0a70393a/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:03f061a1915538fd96272bac9551841859dbb2e3bf73ebe4a23ef043766f5449", size = 86052, upload-time = "2025-08-05T16:42:35.839Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/96/c37846df657ccdda62ba1ae2b6534fa90e2e1b1742ca8dcf8ebd38c53801/audioop_lts-0.2.2-cp313-abi3-win32.whl", hash = "sha256:3bcddaaf6cc5935a300a8387c99f7a7fbbe212a11568ec6cf6e4bc458c048636", size = 26185, upload-time = "2025-08-05T16:42:37.04Z" },
+ { url = "https://files.pythonhosted.org/packages/34/a5/9d78fdb5b844a83da8a71226c7bdae7cc638861085fff7a1d707cb4823fa/audioop_lts-0.2.2-cp313-abi3-win_amd64.whl", hash = "sha256:a2c2a947fae7d1062ef08c4e369e0ba2086049a5e598fda41122535557012e9e", size = 30503, upload-time = "2025-08-05T16:42:38.427Z" },
+ { url = "https://files.pythonhosted.org/packages/34/25/20d8fde083123e90c61b51afb547bb0ea7e77bab50d98c0ab243d02a0e43/audioop_lts-0.2.2-cp313-abi3-win_arm64.whl", hash = "sha256:5f93a5db13927a37d2d09637ccca4b2b6b48c19cd9eda7b17a2e9f77edee6a6f", size = 24173, upload-time = "2025-08-05T16:42:39.704Z" },
+ { url = "https://files.pythonhosted.org/packages/58/a7/0a764f77b5c4ac58dc13c01a580f5d32ae8c74c92020b961556a43e26d02/audioop_lts-0.2.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:73f80bf4cd5d2ca7814da30a120de1f9408ee0619cc75da87d0641273d202a09", size = 47096, upload-time = "2025-08-05T16:42:40.684Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/ed/ebebedde1a18848b085ad0fa54b66ceb95f1f94a3fc04f1cd1b5ccb0ed42/audioop_lts-0.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:106753a83a25ee4d6f473f2be6b0966fc1c9af7e0017192f5531a3e7463dce58", size = 27748, upload-time = "2025-08-05T16:42:41.992Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/6e/11ca8c21af79f15dbb1c7f8017952ee8c810c438ce4e2b25638dfef2b02c/audioop_lts-0.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fbdd522624141e40948ab3e8cdae6e04c748d78710e9f0f8d4dae2750831de19", size = 27329, upload-time = "2025-08-05T16:42:42.987Z" },
+ { url = "https://files.pythonhosted.org/packages/84/52/0022f93d56d85eec5da6b9da6a958a1ef09e80c39f2cc0a590c6af81dcbb/audioop_lts-0.2.2-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:143fad0311e8209ece30a8dbddab3b65ab419cbe8c0dde6e8828da25999be911", size = 92407, upload-time = "2025-08-05T16:42:44.336Z" },
+ { url = "https://files.pythonhosted.org/packages/87/1d/48a889855e67be8718adbc7a01f3c01d5743c325453a5e81cf3717664aad/audioop_lts-0.2.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dfbbc74ec68a0fd08cfec1f4b5e8cca3d3cd7de5501b01c4b5d209995033cde9", size = 91811, upload-time = "2025-08-05T16:42:45.325Z" },
+ { url = "https://files.pythonhosted.org/packages/98/a6/94b7213190e8077547ffae75e13ed05edc488653c85aa5c41472c297d295/audioop_lts-0.2.2-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cfcac6aa6f42397471e4943e0feb2244549db5c5d01efcd02725b96af417f3fe", size = 100470, upload-time = "2025-08-05T16:42:46.468Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/e9/78450d7cb921ede0cfc33426d3a8023a3bda755883c95c868ee36db8d48d/audioop_lts-0.2.2-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:752d76472d9804ac60f0078c79cdae8b956f293177acd2316cd1e15149aee132", size = 103878, upload-time = "2025-08-05T16:42:47.576Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/e2/cd5439aad4f3e34ae1ee852025dc6aa8f67a82b97641e390bf7bd9891d3e/audioop_lts-0.2.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:83c381767e2cc10e93e40281a04852facc4cd9334550e0f392f72d1c0a9c5753", size = 84867, upload-time = "2025-08-05T16:42:49.003Z" },
+ { url = "https://files.pythonhosted.org/packages/68/4b/9d853e9076c43ebba0d411e8d2aa19061083349ac695a7d082540bad64d0/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c0022283e9556e0f3643b7c3c03f05063ca72b3063291834cca43234f20c60bb", size = 90001, upload-time = "2025-08-05T16:42:50.038Z" },
+ { url = "https://files.pythonhosted.org/packages/58/26/4bae7f9d2f116ed5593989d0e521d679b0d583973d203384679323d8fa85/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:a2d4f1513d63c795e82948e1305f31a6d530626e5f9f2605408b300ae6095093", size = 99046, upload-time = "2025-08-05T16:42:51.111Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/67/a9f4fb3e250dda9e9046f8866e9fa7d52664f8985e445c6b4ad6dfb55641/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:c9c8e68d8b4a56fda8c025e538e639f8c5953f5073886b596c93ec9b620055e7", size = 84788, upload-time = "2025-08-05T16:42:52.198Z" },
+ { url = "https://files.pythonhosted.org/packages/70/f7/3de86562db0121956148bcb0fe5b506615e3bcf6e63c4357a612b910765a/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:96f19de485a2925314f5020e85911fb447ff5fbef56e8c7c6927851b95533a1c", size = 94472, upload-time = "2025-08-05T16:42:53.59Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/32/fd772bf9078ae1001207d2df1eef3da05bea611a87dd0e8217989b2848fa/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e541c3ef484852ef36545f66209444c48b28661e864ccadb29daddb6a4b8e5f5", size = 92279, upload-time = "2025-08-05T16:42:54.632Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/41/affea7181592ab0ab560044632571a38edaf9130b84928177823fbf3176a/audioop_lts-0.2.2-cp313-cp313t-win32.whl", hash = "sha256:d5e73fa573e273e4f2e5ff96f9043858a5e9311e94ffefd88a3186a910c70917", size = 26568, upload-time = "2025-08-05T16:42:55.627Z" },
+ { url = "https://files.pythonhosted.org/packages/28/2b/0372842877016641db8fc54d5c88596b542eec2f8f6c20a36fb6612bf9ee/audioop_lts-0.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:9191d68659eda01e448188f60364c7763a7ca6653ed3f87ebb165822153a8547", size = 30942, upload-time = "2025-08-05T16:42:56.674Z" },
+ { url = "https://files.pythonhosted.org/packages/ee/ca/baf2b9cc7e96c179bb4a54f30fcd83e6ecb340031bde68f486403f943768/audioop_lts-0.2.2-cp313-cp313t-win_arm64.whl", hash = "sha256:c174e322bb5783c099aaf87faeb240c8d210686b04bd61dfd05a8e5a83d88969", size = 24603, upload-time = "2025-08-05T16:42:57.571Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/73/413b5a2804091e2c7d5def1d618e4837f1cb82464e230f827226278556b7/audioop_lts-0.2.2-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:f9ee9b52f5f857fbaf9d605a360884f034c92c1c23021fb90b2e39b8e64bede6", size = 47104, upload-time = "2025-08-05T16:42:58.518Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/8c/daa3308dc6593944410c2c68306a5e217f5c05b70a12e70228e7dd42dc5c/audioop_lts-0.2.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:49ee1a41738a23e98d98b937a0638357a2477bc99e61b0f768a8f654f45d9b7a", size = 27754, upload-time = "2025-08-05T16:43:00.132Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/86/c2e0f627168fcf61781a8f72cab06b228fe1da4b9fa4ab39cfb791b5836b/audioop_lts-0.2.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5b00be98ccd0fc123dcfad31d50030d25fcf31488cde9e61692029cd7394733b", size = 27332, upload-time = "2025-08-05T16:43:01.666Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/bd/35dce665255434f54e5307de39e31912a6f902d4572da7c37582809de14f/audioop_lts-0.2.2-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a6d2e0f9f7a69403e388894d4ca5ada5c47230716a03f2847cfc7bd1ecb589d6", size = 92396, upload-time = "2025-08-05T16:43:02.991Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/d2/deeb9f51def1437b3afa35aeb729d577c04bcd89394cb56f9239a9f50b6f/audioop_lts-0.2.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f9b0b8a03ef474f56d1a842af1a2e01398b8f7654009823c6d9e0ecff4d5cfbf", size = 91811, upload-time = "2025-08-05T16:43:04.096Z" },
+ { url = "https://files.pythonhosted.org/packages/76/3b/09f8b35b227cee28cc8231e296a82759ed80c1a08e349811d69773c48426/audioop_lts-0.2.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2b267b70747d82125f1a021506565bdc5609a2b24bcb4773c16d79d2bb260bbd", size = 100483, upload-time = "2025-08-05T16:43:05.085Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/15/05b48a935cf3b130c248bfdbdea71ce6437f5394ee8533e0edd7cfd93d5e/audioop_lts-0.2.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0337d658f9b81f4cd0fdb1f47635070cc084871a3d4646d9de74fdf4e7c3d24a", size = 103885, upload-time = "2025-08-05T16:43:06.197Z" },
+ { url = "https://files.pythonhosted.org/packages/83/80/186b7fce6d35b68d3d739f228dc31d60b3412105854edb975aa155a58339/audioop_lts-0.2.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:167d3b62586faef8b6b2275c3218796b12621a60e43f7e9d5845d627b9c9b80e", size = 84899, upload-time = "2025-08-05T16:43:07.291Z" },
+ { url = "https://files.pythonhosted.org/packages/49/89/c78cc5ac6cb5828f17514fb12966e299c850bc885e80f8ad94e38d450886/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0d9385e96f9f6da847f4d571ce3cb15b5091140edf3db97276872647ce37efd7", size = 89998, upload-time = "2025-08-05T16:43:08.335Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/4b/6401888d0c010e586c2ca50fce4c903d70a6bb55928b16cfbdfd957a13da/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:48159d96962674eccdca9a3df280e864e8ac75e40a577cc97c5c42667ffabfc5", size = 99046, upload-time = "2025-08-05T16:43:09.367Z" },
+ { url = "https://files.pythonhosted.org/packages/de/f8/c874ca9bb447dae0e2ef2e231f6c4c2b0c39e31ae684d2420b0f9e97ee68/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:8fefe5868cd082db1186f2837d64cfbfa78b548ea0d0543e9b28935ccce81ce9", size = 84843, upload-time = "2025-08-05T16:43:10.749Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/c0/0323e66f3daebc13fd46b36b30c3be47e3fc4257eae44f1e77eb828c703f/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:58cf54380c3884fb49fdd37dfb7a772632b6701d28edd3e2904743c5e1773602", size = 94490, upload-time = "2025-08-05T16:43:12.131Z" },
+ { url = "https://files.pythonhosted.org/packages/98/6b/acc7734ac02d95ab791c10c3f17ffa3584ccb9ac5c18fd771c638ed6d1f5/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:088327f00488cdeed296edd9215ca159f3a5a5034741465789cad403fcf4bec0", size = 92297, upload-time = "2025-08-05T16:43:13.139Z" },
+ { url = "https://files.pythonhosted.org/packages/13/c3/c3dc3f564ce6877ecd2a05f8d751b9b27a8c320c2533a98b0c86349778d0/audioop_lts-0.2.2-cp314-cp314t-win32.whl", hash = "sha256:068aa17a38b4e0e7de771c62c60bbca2455924b67a8814f3b0dee92b5820c0b3", size = 27331, upload-time = "2025-08-05T16:43:14.19Z" },
+ { url = "https://files.pythonhosted.org/packages/72/bb/b4608537e9ffcb86449091939d52d24a055216a36a8bf66b936af8c3e7ac/audioop_lts-0.2.2-cp314-cp314t-win_amd64.whl", hash = "sha256:a5bf613e96f49712073de86f20dbdd4014ca18efd4d34ed18c75bd808337851b", size = 31697, upload-time = "2025-08-05T16:43:15.193Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/22/91616fe707a5c5510de2cac9b046a30defe7007ba8a0c04f9c08f27df312/audioop_lts-0.2.2-cp314-cp314t-win_arm64.whl", hash = "sha256:b492c3b040153e68b9fdaff5913305aaaba5bb433d8a7f73d5cf6a64ed3cc1dd", size = 25206, upload-time = "2025-08-05T16:43:16.444Z" },
+]
+
+[[package]]
+name = "brotli"
+version = "1.2.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f7/16/c92ca344d646e71a43b8bb353f0a6490d7f6e06210f8554c8f874e454285/brotli-1.2.0.tar.gz", hash = "sha256:e310f77e41941c13340a95976fe66a8a95b01e783d430eeaf7a2f87e0a57dd0a", size = 7388632, upload-time = "2025-11-05T18:39:42.86Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/11/ee/b0a11ab2315c69bb9b45a2aaed022499c9c24a205c3a49c3513b541a7967/brotli-1.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:35d382625778834a7f3061b15423919aa03e4f5da34ac8e02c074e4b75ab4f84", size = 861543, upload-time = "2025-11-05T18:38:24.183Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/2f/29c1459513cd35828e25531ebfcbf3e92a5e49f560b1777a9af7203eb46e/brotli-1.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7a61c06b334bd99bc5ae84f1eeb36bfe01400264b3c352f968c6e30a10f9d08b", size = 444288, upload-time = "2025-11-05T18:38:25.139Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/6f/feba03130d5fceadfa3a1bb102cb14650798c848b1df2a808356f939bb16/brotli-1.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:acec55bb7c90f1dfc476126f9711a8e81c9af7fb617409a9ee2953115343f08d", size = 1528071, upload-time = "2025-11-05T18:38:26.081Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/38/f3abb554eee089bd15471057ba85f47e53a44a462cfce265d9bf7088eb09/brotli-1.2.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:260d3692396e1895c5034f204f0db022c056f9e2ac841593a4cf9426e2a3faca", size = 1626913, upload-time = "2025-11-05T18:38:27.284Z" },
+ { url = "https://files.pythonhosted.org/packages/03/a7/03aa61fbc3c5cbf99b44d158665f9b0dd3d8059be16c460208d9e385c837/brotli-1.2.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:072e7624b1fc4d601036ab3f4f27942ef772887e876beff0301d261210bca97f", size = 1419762, upload-time = "2025-11-05T18:38:28.295Z" },
+ { url = "https://files.pythonhosted.org/packages/21/1b/0374a89ee27d152a5069c356c96b93afd1b94eae83f1e004b57eb6ce2f10/brotli-1.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:adedc4a67e15327dfdd04884873c6d5a01d3e3b6f61406f99b1ed4865a2f6d28", size = 1484494, upload-time = "2025-11-05T18:38:29.29Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/57/69d4fe84a67aef4f524dcd075c6eee868d7850e85bf01d778a857d8dbe0a/brotli-1.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7a47ce5c2288702e09dc22a44d0ee6152f2c7eda97b3c8482d826a1f3cfc7da7", size = 1593302, upload-time = "2025-11-05T18:38:30.639Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/3b/39e13ce78a8e9a621c5df3aeb5fd181fcc8caba8c48a194cd629771f6828/brotli-1.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:af43b8711a8264bb4e7d6d9a6d004c3a2019c04c01127a868709ec29962b6036", size = 1487913, upload-time = "2025-11-05T18:38:31.618Z" },
+ { url = "https://files.pythonhosted.org/packages/62/28/4d00cb9bd76a6357a66fcd54b4b6d70288385584063f4b07884c1e7286ac/brotli-1.2.0-cp312-cp312-win32.whl", hash = "sha256:e99befa0b48f3cd293dafeacdd0d191804d105d279e0b387a32054c1180f3161", size = 334362, upload-time = "2025-11-05T18:38:32.939Z" },
+ { url = "https://files.pythonhosted.org/packages/1c/4e/bc1dcac9498859d5e353c9b153627a3752868a9d5f05ce8dedd81a2354ab/brotli-1.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:b35c13ce241abdd44cb8ca70683f20c0c079728a36a996297adb5334adfc1c44", size = 369115, upload-time = "2025-11-05T18:38:33.765Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/d4/4ad5432ac98c73096159d9ce7ffeb82d151c2ac84adcc6168e476bb54674/brotli-1.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9e5825ba2c9998375530504578fd4d5d1059d09621a02065d1b6bfc41a8e05ab", size = 861523, upload-time = "2025-11-05T18:38:34.67Z" },
+ { url = "https://files.pythonhosted.org/packages/91/9f/9cc5bd03ee68a85dc4bc89114f7067c056a3c14b3d95f171918c088bf88d/brotli-1.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0cf8c3b8ba93d496b2fae778039e2f5ecc7cff99df84df337ca31d8f2252896c", size = 444289, upload-time = "2025-11-05T18:38:35.6Z" },
+ { url = "https://files.pythonhosted.org/packages/2e/b6/fe84227c56a865d16a6614e2c4722864b380cb14b13f3e6bef441e73a85a/brotli-1.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c8565e3cdc1808b1a34714b553b262c5de5fbda202285782173ec137fd13709f", size = 1528076, upload-time = "2025-11-05T18:38:36.639Z" },
+ { url = "https://files.pythonhosted.org/packages/55/de/de4ae0aaca06c790371cf6e7ee93a024f6b4bb0568727da8c3de112e726c/brotli-1.2.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:26e8d3ecb0ee458a9804f47f21b74845cc823fd1bb19f02272be70774f56e2a6", size = 1626880, upload-time = "2025-11-05T18:38:37.623Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/16/a1b22cbea436642e071adcaf8d4b350a2ad02f5e0ad0da879a1be16188a0/brotli-1.2.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67a91c5187e1eec76a61625c77a6c8c785650f5b576ca732bd33ef58b0dff49c", size = 1419737, upload-time = "2025-11-05T18:38:38.729Z" },
+ { url = "https://files.pythonhosted.org/packages/46/63/c968a97cbb3bdbf7f974ef5a6ab467a2879b82afbc5ffb65b8acbb744f95/brotli-1.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4ecdb3b6dc36e6d6e14d3a1bdc6c1057c8cbf80db04031d566eb6080ce283a48", size = 1484440, upload-time = "2025-11-05T18:38:39.916Z" },
+ { url = "https://files.pythonhosted.org/packages/06/9d/102c67ea5c9fc171f423e8399e585dabea29b5bc79b05572891e70013cdd/brotli-1.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3e1b35d56856f3ed326b140d3c6d9db91740f22e14b06e840fe4bb1923439a18", size = 1593313, upload-time = "2025-11-05T18:38:41.24Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/4a/9526d14fa6b87bc827ba1755a8440e214ff90de03095cacd78a64abe2b7d/brotli-1.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:54a50a9dad16b32136b2241ddea9e4df159b41247b2ce6aac0b3276a66a8f1e5", size = 1487945, upload-time = "2025-11-05T18:38:42.277Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/e8/3fe1ffed70cbef83c5236166acaed7bb9c766509b157854c80e2f766b38c/brotli-1.2.0-cp313-cp313-win32.whl", hash = "sha256:1b1d6a4efedd53671c793be6dd760fcf2107da3a52331ad9ea429edf0902f27a", size = 334368, upload-time = "2025-11-05T18:38:43.345Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/91/e739587be970a113b37b821eae8097aac5a48e5f0eca438c22e4c7dd8648/brotli-1.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:b63daa43d82f0cdabf98dee215b375b4058cce72871fd07934f179885aad16e8", size = 369116, upload-time = "2025-11-05T18:38:44.609Z" },
+ { url = "https://files.pythonhosted.org/packages/17/e1/298c2ddf786bb7347a1cd71d63a347a79e5712a7c0cba9e3c3458ebd976f/brotli-1.2.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:6c12dad5cd04530323e723787ff762bac749a7b256a5bece32b2243dd5c27b21", size = 863080, upload-time = "2025-11-05T18:38:45.503Z" },
+ { url = "https://files.pythonhosted.org/packages/84/0c/aac98e286ba66868b2b3b50338ffbd85a35c7122e9531a73a37a29763d38/brotli-1.2.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:3219bd9e69868e57183316ee19c84e03e8f8b5a1d1f2667e1aa8c2f91cb061ac", size = 445453, upload-time = "2025-11-05T18:38:46.433Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/f1/0ca1f3f99ae300372635ab3fe2f7a79fa335fee3d874fa7f9e68575e0e62/brotli-1.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:963a08f3bebd8b75ac57661045402da15991468a621f014be54e50f53a58d19e", size = 1528168, upload-time = "2025-11-05T18:38:47.371Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/a6/2ebfc8f766d46df8d3e65b880a2e220732395e6d7dc312c1e1244b0f074a/brotli-1.2.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9322b9f8656782414b37e6af884146869d46ab85158201d82bab9abbcb971dc7", size = 1627098, upload-time = "2025-11-05T18:38:48.385Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/2f/0976d5b097ff8a22163b10617f76b2557f15f0f39d6a0fe1f02b1a53e92b/brotli-1.2.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cf9cba6f5b78a2071ec6fb1e7bd39acf35071d90a81231d67e92d637776a6a63", size = 1419861, upload-time = "2025-11-05T18:38:49.372Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/97/d76df7176a2ce7616ff94c1fb72d307c9a30d2189fe877f3dd99af00ea5a/brotli-1.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7547369c4392b47d30a3467fe8c3330b4f2e0f7730e45e3103d7d636678a808b", size = 1484594, upload-time = "2025-11-05T18:38:50.655Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/93/14cf0b1216f43df5609f5b272050b0abd219e0b54ea80b47cef9867b45e7/brotli-1.2.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:fc1530af5c3c275b8524f2e24841cbe2599d74462455e9bae5109e9ff42e9361", size = 1593455, upload-time = "2025-11-05T18:38:51.624Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/73/3183c9e41ca755713bdf2cc1d0810df742c09484e2e1ddd693bee53877c1/brotli-1.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d2d085ded05278d1c7f65560aae97b3160aeb2ea2c0b3e26204856beccb60888", size = 1488164, upload-time = "2025-11-05T18:38:53.079Z" },
+ { url = "https://files.pythonhosted.org/packages/64/6a/0c78d8f3a582859236482fd9fa86a65a60328a00983006bcf6d83b7b2253/brotli-1.2.0-cp314-cp314-win32.whl", hash = "sha256:832c115a020e463c2f67664560449a7bea26b0c1fdd690352addad6d0a08714d", size = 339280, upload-time = "2025-11-05T18:38:54.02Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/10/56978295c14794b2c12007b07f3e41ba26acda9257457d7085b0bb3bb90c/brotli-1.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:e7c0af964e0b4e3412a0ebf341ea26ec767fa0b4cf81abb5e897c9338b5ad6a3", size = 375639, upload-time = "2025-11-05T18:38:55.67Z" },
+]
+
+[[package]]
+name = "certifi"
+version = "2026.2.25"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/af/2d/7bf41579a8986e348fa033a31cdd0e4121114f6bce2457e8876010b092dd/certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7", size = 155029, upload-time = "2026-02-25T02:54:17.342Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", size = 153684, upload-time = "2026-02-25T02:54:15.766Z" },
+]
+
+[[package]]
+name = "cffi"
+version = "2.0.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pycparser", marker = "implementation_name != 'PyPy'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" },
+ { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" },
+ { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" },
+ { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" },
+ { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" },
+ { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" },
+ { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" },
+ { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" },
+ { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" },
+ { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" },
+ { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" },
+ { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" },
+ { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" },
+ { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" },
+]
+
+[[package]]
+name = "charset-normalizer"
+version = "3.4.5"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/1d/35/02daf95b9cd686320bb622eb148792655c9412dbb9b67abb5694e5910a24/charset_normalizer-3.4.5.tar.gz", hash = "sha256:95adae7b6c42a6c5b5b559b1a99149f090a57128155daeea91732c8d970d8644", size = 134804, upload-time = "2026-03-06T06:03:19.46Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9c/b6/9ee9c1a608916ca5feae81a344dffbaa53b26b90be58cc2159e3332d44ec/charset_normalizer-3.4.5-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ed97c282ee4f994ef814042423a529df9497e3c666dca19be1d4cd1129dc7ade", size = 280976, upload-time = "2026-03-06T06:01:15.276Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/d8/a54f7c0b96f1df3563e9190f04daf981e365a9b397eedfdfb5dbef7e5c6c/charset_normalizer-3.4.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0294916d6ccf2d069727d65973c3a1ca477d68708db25fd758dd28b0827cff54", size = 189356, upload-time = "2026-03-06T06:01:16.511Z" },
+ { url = "https://files.pythonhosted.org/packages/42/69/2bf7f76ce1446759a5787cb87d38f6a61eb47dbbdf035cfebf6347292a65/charset_normalizer-3.4.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dc57a0baa3eeedd99fafaef7511b5a6ef4581494e8168ee086031744e2679467", size = 206369, upload-time = "2026-03-06T06:01:17.853Z" },
+ { url = "https://files.pythonhosted.org/packages/10/9c/949d1a46dab56b959d9a87272482195f1840b515a3380e39986989a893ae/charset_normalizer-3.4.5-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ed1a9a204f317ef879b32f9af507d47e49cd5e7f8e8d5d96358c98373314fc60", size = 203285, upload-time = "2026-03-06T06:01:19.473Z" },
+ { url = "https://files.pythonhosted.org/packages/67/5c/ae30362a88b4da237d71ea214a8c7eb915db3eec941adda511729ac25fa2/charset_normalizer-3.4.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7ad83b8f9379176c841f8865884f3514d905bcd2a9a3b210eaa446e7d2223e4d", size = 196274, upload-time = "2026-03-06T06:01:20.728Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/07/c9f2cb0e46cb6d64fdcc4f95953747b843bb2181bda678dc4e699b8f0f9a/charset_normalizer-3.4.5-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:a118e2e0b5ae6b0120d5efa5f866e58f2bb826067a646431da4d6a2bdae7950e", size = 184715, upload-time = "2026-03-06T06:01:22.194Z" },
+ { url = "https://files.pythonhosted.org/packages/36/64/6b0ca95c44fddf692cd06d642b28f63009d0ce325fad6e9b2b4d0ef86a52/charset_normalizer-3.4.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:754f96058e61a5e22e91483f823e07df16416ce76afa4ebf306f8e1d1296d43f", size = 193426, upload-time = "2026-03-06T06:01:23.795Z" },
+ { url = "https://files.pythonhosted.org/packages/50/bc/a730690d726403743795ca3f5bb2baf67838c5fea78236098f324b965e40/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0c300cefd9b0970381a46394902cd18eaf2aa00163f999590ace991989dcd0fc", size = 191780, upload-time = "2026-03-06T06:01:25.053Z" },
+ { url = "https://files.pythonhosted.org/packages/97/4f/6c0bc9af68222b22951552d73df4532b5be6447cee32d58e7e8c74ecbb7b/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c108f8619e504140569ee7de3f97d234f0fbae338a7f9f360455071ef9855a95", size = 185805, upload-time = "2026-03-06T06:01:26.294Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/b9/a523fb9b0ee90814b503452b2600e4cbc118cd68714d57041564886e7325/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:d1028de43596a315e2720a9849ee79007ab742c06ad8b45a50db8cdb7ed4a82a", size = 208342, upload-time = "2026-03-06T06:01:27.55Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/61/c59e761dee4464050713e50e27b58266cc8e209e518c0b378c1580c959ba/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:19092dde50335accf365cce21998a1c6dd8eafd42c7b226eb54b2747cdce2fac", size = 193661, upload-time = "2026-03-06T06:01:29.051Z" },
+ { url = "https://files.pythonhosted.org/packages/1c/43/729fa30aad69783f755c5ad8649da17ee095311ca42024742701e202dc59/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4354e401eb6dab9aed3c7b4030514328a6c748d05e1c3e19175008ca7de84fb1", size = 204819, upload-time = "2026-03-06T06:01:30.298Z" },
+ { url = "https://files.pythonhosted.org/packages/87/33/d9b442ce5a91b96fc0840455a9e49a611bbadae6122778d0a6a79683dd31/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a68766a3c58fde7f9aaa22b3786276f62ab2f594efb02d0a1421b6282e852e98", size = 198080, upload-time = "2026-03-06T06:01:31.478Z" },
+ { url = "https://files.pythonhosted.org/packages/56/5a/b8b5a23134978ee9885cee2d6995f4c27cc41f9baded0a9685eabc5338f0/charset_normalizer-3.4.5-cp312-cp312-win32.whl", hash = "sha256:1827734a5b308b65ac54e86a618de66f935a4f63a8a462ff1e19a6788d6c2262", size = 132630, upload-time = "2026-03-06T06:01:33.056Z" },
+ { url = "https://files.pythonhosted.org/packages/70/53/e44a4c07e8904500aec95865dc3f6464dc3586a039ef0df606eb3ac38e35/charset_normalizer-3.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:728c6a963dfab66ef865f49286e45239384249672cd598576765acc2a640a636", size = 142856, upload-time = "2026-03-06T06:01:34.489Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/aa/c5628f7cad591b1cf45790b7a61483c3e36cf41349c98af7813c483fd6e8/charset_normalizer-3.4.5-cp312-cp312-win_arm64.whl", hash = "sha256:75dfd1afe0b1647449e852f4fb428195a7ed0588947218f7ba929f6538487f02", size = 132982, upload-time = "2026-03-06T06:01:35.641Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/48/9f34ec4bb24aa3fdba1890c1bddb97c8a4be1bd84ef5c42ac2352563ad05/charset_normalizer-3.4.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ac59c15e3f1465f722607800c68713f9fbc2f672b9eb649fe831da4019ae9b23", size = 280788, upload-time = "2026-03-06T06:01:37.126Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/09/6003e7ffeb90cc0560da893e3208396a44c210c5ee42efff539639def59b/charset_normalizer-3.4.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:165c7b21d19365464e8f70e5ce5e12524c58b48c78c1f5a57524603c1ab003f8", size = 188890, upload-time = "2026-03-06T06:01:38.73Z" },
+ { url = "https://files.pythonhosted.org/packages/42/1e/02706edf19e390680daa694d17e2b8eab4b5f7ac285e2a51168b4b22ee6b/charset_normalizer-3.4.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:28269983f25a4da0425743d0d257a2d6921ea7d9b83599d4039486ec5b9f911d", size = 206136, upload-time = "2026-03-06T06:01:40.016Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/87/942c3def1b37baf3cf786bad01249190f3ca3d5e63a84f831e704977de1f/charset_normalizer-3.4.5-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d27ce22ec453564770d29d03a9506d449efbb9fa13c00842262b2f6801c48cce", size = 202551, upload-time = "2026-03-06T06:01:41.522Z" },
+ { url = "https://files.pythonhosted.org/packages/94/0a/af49691938dfe175d71b8a929bd7e4ace2809c0c5134e28bc535660d5262/charset_normalizer-3.4.5-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0625665e4ebdddb553ab185de5db7054393af8879fb0c87bd5690d14379d6819", size = 195572, upload-time = "2026-03-06T06:01:43.208Z" },
+ { url = "https://files.pythonhosted.org/packages/20/ea/dfb1792a8050a8e694cfbde1570ff97ff74e48afd874152d38163d1df9ae/charset_normalizer-3.4.5-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:c23eb3263356d94858655b3e63f85ac5d50970c6e8febcdde7830209139cc37d", size = 184438, upload-time = "2026-03-06T06:01:44.755Z" },
+ { url = "https://files.pythonhosted.org/packages/72/12/c281e2067466e3ddd0595bfaea58a6946765ace5c72dfa3edc2f5f118026/charset_normalizer-3.4.5-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e6302ca4ae283deb0af68d2fbf467474b8b6aedcd3dab4db187e07f94c109763", size = 193035, upload-time = "2026-03-06T06:01:46.051Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/4f/3792c056e7708e10464bad0438a44708886fb8f92e3c3d29ec5e2d964d42/charset_normalizer-3.4.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e51ae7d81c825761d941962450f50d041db028b7278e7b08930b4541b3e45cb9", size = 191340, upload-time = "2026-03-06T06:01:47.547Z" },
+ { url = "https://files.pythonhosted.org/packages/e7/86/80ddba897127b5c7a9bccc481b0cd36c8fefa485d113262f0fe4332f0bf4/charset_normalizer-3.4.5-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:597d10dec876923e5c59e48dbd366e852eacb2b806029491d307daea6b917d7c", size = 185464, upload-time = "2026-03-06T06:01:48.764Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/00/b5eff85ba198faacab83e0e4b6f0648155f072278e3b392a82478f8b988b/charset_normalizer-3.4.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5cffde4032a197bd3b42fd0b9509ec60fb70918d6970e4cc773f20fc9180ca67", size = 208014, upload-time = "2026-03-06T06:01:50.371Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/11/d36f70be01597fd30850dde8a1269ebc8efadd23ba5785808454f2389bde/charset_normalizer-3.4.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2da4eedcb6338e2321e831a0165759c0c620e37f8cd044a263ff67493be8ffb3", size = 193297, upload-time = "2026-03-06T06:01:51.933Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/1d/259eb0a53d4910536c7c2abb9cb25f4153548efb42800c6a9456764649c0/charset_normalizer-3.4.5-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:65a126fb4b070d05340a84fc709dd9e7c75d9b063b610ece8a60197a291d0adf", size = 204321, upload-time = "2026-03-06T06:01:53.887Z" },
+ { url = "https://files.pythonhosted.org/packages/84/31/faa6c5b9d3688715e1ed1bb9d124c384fe2fc1633a409e503ffe1c6398c1/charset_normalizer-3.4.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c7a80a9242963416bd81f99349d5f3fce1843c303bd404f204918b6d75a75fd6", size = 197509, upload-time = "2026-03-06T06:01:56.439Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/a5/c7d9dd1503ffc08950b3260f5d39ec2366dd08254f0900ecbcf3a6197c7c/charset_normalizer-3.4.5-cp313-cp313-win32.whl", hash = "sha256:f1d725b754e967e648046f00c4facc42d414840f5ccc670c5670f59f83693e4f", size = 132284, upload-time = "2026-03-06T06:01:57.812Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/0f/57072b253af40c8aa6636e6de7d75985624c1eb392815b2f934199340a89/charset_normalizer-3.4.5-cp313-cp313-win_amd64.whl", hash = "sha256:e37bd100d2c5d3ba35db9c7c5ba5a9228cbcffe5c4778dc824b164e5257813d7", size = 142630, upload-time = "2026-03-06T06:01:59.062Z" },
+ { url = "https://files.pythonhosted.org/packages/31/41/1c4b7cc9f13bd9d369ce3bc993e13d374ce25fa38a2663644283ecf422c1/charset_normalizer-3.4.5-cp313-cp313-win_arm64.whl", hash = "sha256:93b3b2cc5cf1b8743660ce77a4f45f3f6d1172068207c1defc779a36eea6bb36", size = 133254, upload-time = "2026-03-06T06:02:00.281Z" },
+ { url = "https://files.pythonhosted.org/packages/43/be/0f0fd9bb4a7fa4fb5067fb7d9ac693d4e928d306f80a0d02bde43a7c4aee/charset_normalizer-3.4.5-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8197abe5ca1ffb7d91e78360f915eef5addff270f8a71c1fc5be24a56f3e4873", size = 280232, upload-time = "2026-03-06T06:02:01.508Z" },
+ { url = "https://files.pythonhosted.org/packages/28/02/983b5445e4bef49cd8c9da73a8e029f0825f39b74a06d201bfaa2e55142a/charset_normalizer-3.4.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2aecdb364b8a1802afdc7f9327d55dad5366bc97d8502d0f5854e50712dbc5f", size = 189688, upload-time = "2026-03-06T06:02:02.857Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/88/152745c5166437687028027dc080e2daed6fe11cfa95a22f4602591c42db/charset_normalizer-3.4.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a66aa5022bf81ab4b1bebfb009db4fd68e0c6d4307a1ce5ef6a26e5878dfc9e4", size = 206833, upload-time = "2026-03-06T06:02:05.127Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/0f/ebc15c8b02af2f19be9678d6eed115feeeccc45ce1f4b098d986c13e8769/charset_normalizer-3.4.5-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d77f97e515688bd615c1d1f795d540f32542d514242067adcb8ef532504cb9ee", size = 202879, upload-time = "2026-03-06T06:02:06.446Z" },
+ { url = "https://files.pythonhosted.org/packages/38/9c/71336bff6934418dc8d1e8a1644176ac9088068bc571da612767619c97b3/charset_normalizer-3.4.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01a1ed54b953303ca7e310fafe0fe347aab348bd81834a0bcd602eb538f89d66", size = 195764, upload-time = "2026-03-06T06:02:08.763Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/95/ce92fde4f98615661871bc282a856cf9b8a15f686ba0af012984660d480b/charset_normalizer-3.4.5-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:b2d37d78297b39a9eb9eb92c0f6df98c706467282055419df141389b23f93362", size = 183728, upload-time = "2026-03-06T06:02:10.137Z" },
+ { url = "https://files.pythonhosted.org/packages/1c/e7/f5b4588d94e747ce45ae680f0f242bc2d98dbd4eccfab73e6160b6893893/charset_normalizer-3.4.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e71bbb595973622b817c042bd943c3f3667e9c9983ce3d205f973f486fec98a7", size = 192937, upload-time = "2026-03-06T06:02:11.663Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/29/9d94ed6b929bf9f48bf6ede6e7474576499f07c4c5e878fb186083622716/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4cd966c2559f501c6fd69294d082c2934c8dd4719deb32c22961a5ac6db0df1d", size = 192040, upload-time = "2026-03-06T06:02:13.489Z" },
+ { url = "https://files.pythonhosted.org/packages/15/d2/1a093a1cf827957f9445f2fe7298bcc16f8fc5e05c1ed2ad1af0b239035e/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:d5e52d127045d6ae01a1e821acfad2f3a1866c54d0e837828538fabe8d9d1bd6", size = 184107, upload-time = "2026-03-06T06:02:14.83Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/7d/82068ce16bd36135df7b97f6333c5d808b94e01d4599a682e2337ed5fd14/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:30a2b1a48478c3428d047ed9690d57c23038dac838a87ad624c85c0a78ebeb39", size = 208310, upload-time = "2026-03-06T06:02:16.165Z" },
+ { url = "https://files.pythonhosted.org/packages/84/4e/4dfb52307bb6af4a5c9e73e482d171b81d36f522b21ccd28a49656baa680/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:d8ed79b8f6372ca4254955005830fd61c1ccdd8c0fac6603e2c145c61dd95db6", size = 192918, upload-time = "2026-03-06T06:02:18.144Z" },
+ { url = "https://files.pythonhosted.org/packages/08/a4/159ff7da662cf7201502ca89980b8f06acf3e887b278956646a8aeb178ab/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:c5af897b45fa606b12464ccbe0014bbf8c09191e0a66aab6aa9d5cf6e77e0c94", size = 204615, upload-time = "2026-03-06T06:02:19.821Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/62/0dd6172203cb6b429ffffc9935001fde42e5250d57f07b0c28c6046deb6b/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1088345bcc93c58d8d8f3d783eca4a6e7a7752bbff26c3eee7e73c597c191c2e", size = 197784, upload-time = "2026-03-06T06:02:21.86Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/5e/1aab5cb737039b9c59e63627dc8bbc0d02562a14f831cc450e5f91d84ce1/charset_normalizer-3.4.5-cp314-cp314-win32.whl", hash = "sha256:ee57b926940ba00bca7ba7041e665cc956e55ef482f851b9b65acb20d867e7a2", size = 133009, upload-time = "2026-03-06T06:02:23.289Z" },
+ { url = "https://files.pythonhosted.org/packages/40/65/e7c6c77d7aaa4c0d7974f2e403e17f0ed2cb0fc135f77d686b916bf1eead/charset_normalizer-3.4.5-cp314-cp314-win_amd64.whl", hash = "sha256:4481e6da1830c8a1cc0b746b47f603b653dadb690bcd851d039ffaefe70533aa", size = 143511, upload-time = "2026-03-06T06:02:26.195Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/91/52b0841c71f152f563b8e072896c14e3d83b195c188b338d3cc2e582d1d4/charset_normalizer-3.4.5-cp314-cp314-win_arm64.whl", hash = "sha256:97ab7787092eb9b50fb47fa04f24c75b768a606af1bcba1957f07f128a7219e4", size = 133775, upload-time = "2026-03-06T06:02:27.473Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/60/3a621758945513adfd4db86827a5bafcc615f913dbd0b4c2ed64a65731be/charset_normalizer-3.4.5-py3-none-any.whl", hash = "sha256:9db5e3fcdcee89a78c04dffb3fe33c79f77bd741a624946db2591c81b2fc85b0", size = 55455, upload-time = "2026-03-06T06:03:17.827Z" },
+]
+
+[[package]]
+name = "click"
+version = "8.3.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" },
+]
+
+[[package]]
+name = "colorama"
+version = "0.4.6"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
+]
+
+[[package]]
+name = "colorful"
+version = "0.5.8"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/82/31/109ef4bedeb32b4202e02ddb133162457adc4eb890a9ed9c05c9dd126ed0/colorful-0.5.8.tar.gz", hash = "sha256:bb16502b198be2f1c42ba3c52c703d5f651d826076817185f0294c1a549a7445", size = 209361, upload-time = "2025-10-29T11:53:21.663Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c3/11/25cdf9d5fc21efd30134fc74c43702c6f7ef09ebae8ed927f1283403ad8d/colorful-0.5.8-py2.py3-none-any.whl", hash = "sha256:a9381fdda3337fbaba5771991020abc69676afa102646650b759927892875992", size = 201334, upload-time = "2025-10-29T11:53:20.251Z" },
+]
+
+[[package]]
+name = "cryptography"
+version = "46.0.5"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/60/04/ee2a9e8542e4fa2773b81771ff8349ff19cdd56b7258a0cc442639052edb/cryptography-46.0.5.tar.gz", hash = "sha256:abace499247268e3757271b2f1e244b36b06f8515cf27c4d49468fc9eb16e93d", size = 750064, upload-time = "2026-02-10T19:18:38.255Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f7/81/b0bb27f2ba931a65409c6b8a8b358a7f03c0e46eceacddff55f7c84b1f3b/cryptography-46.0.5-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:351695ada9ea9618b3500b490ad54c739860883df6c1f555e088eaf25b1bbaad", size = 7176289, upload-time = "2026-02-10T19:17:08.274Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/9e/6b4397a3e3d15123de3b1806ef342522393d50736c13b20ec4c9ea6693a6/cryptography-46.0.5-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c18ff11e86df2e28854939acde2d003f7984f721eba450b56a200ad90eeb0e6b", size = 4275637, upload-time = "2026-02-10T19:17:10.53Z" },
+ { url = "https://files.pythonhosted.org/packages/63/e7/471ab61099a3920b0c77852ea3f0ea611c9702f651600397ac567848b897/cryptography-46.0.5-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d7e3d356b8cd4ea5aff04f129d5f66ebdc7b6f8eae802b93739ed520c47c79b", size = 4424742, upload-time = "2026-02-10T19:17:12.388Z" },
+ { url = "https://files.pythonhosted.org/packages/37/53/a18500f270342d66bf7e4d9f091114e31e5ee9e7375a5aba2e85a91e0044/cryptography-46.0.5-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:50bfb6925eff619c9c023b967d5b77a54e04256c4281b0e21336a130cd7fc263", size = 4277528, upload-time = "2026-02-10T19:17:13.853Z" },
+ { url = "https://files.pythonhosted.org/packages/22/29/c2e812ebc38c57b40e7c583895e73c8c5adb4d1e4a0cc4c5a4fdab2b1acc/cryptography-46.0.5-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:803812e111e75d1aa73690d2facc295eaefd4439be1023fefc4995eaea2af90d", size = 4947993, upload-time = "2026-02-10T19:17:15.618Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/e7/237155ae19a9023de7e30ec64e5d99a9431a567407ac21170a046d22a5a3/cryptography-46.0.5-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ee190460e2fbe447175cda91b88b84ae8322a104fc27766ad09428754a618ed", size = 4456855, upload-time = "2026-02-10T19:17:17.221Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/87/fc628a7ad85b81206738abbd213b07702bcbdada1dd43f72236ef3cffbb5/cryptography-46.0.5-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:f145bba11b878005c496e93e257c1e88f154d278d2638e6450d17e0f31e558d2", size = 3984635, upload-time = "2026-02-10T19:17:18.792Z" },
+ { url = "https://files.pythonhosted.org/packages/84/29/65b55622bde135aedf4565dc509d99b560ee4095e56989e815f8fd2aa910/cryptography-46.0.5-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:e9251e3be159d1020c4030bd2e5f84d6a43fe54b6c19c12f51cde9542a2817b2", size = 4277038, upload-time = "2026-02-10T19:17:20.256Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/36/45e76c68d7311432741faf1fbf7fac8a196a0a735ca21f504c75d37e2558/cryptography-46.0.5-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:47fb8a66058b80e509c47118ef8a75d14c455e81ac369050f20ba0d23e77fee0", size = 4912181, upload-time = "2026-02-10T19:17:21.825Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/1a/c1ba8fead184d6e3d5afcf03d569acac5ad063f3ac9fb7258af158f7e378/cryptography-46.0.5-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:4c3341037c136030cb46e4b1e17b7418ea4cbd9dd207e4a6f3b2b24e0d4ac731", size = 4456482, upload-time = "2026-02-10T19:17:25.133Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/e5/3fb22e37f66827ced3b902cf895e6a6bc1d095b5b26be26bd13c441fdf19/cryptography-46.0.5-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:890bcb4abd5a2d3f852196437129eb3667d62630333aacc13dfd470fad3aaa82", size = 4405497, upload-time = "2026-02-10T19:17:26.66Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/df/9d58bb32b1121a8a2f27383fabae4d63080c7ca60b9b5c88be742be04ee7/cryptography-46.0.5-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:80a8d7bfdf38f87ca30a5391c0c9ce4ed2926918e017c29ddf643d0ed2778ea1", size = 4667819, upload-time = "2026-02-10T19:17:28.569Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/ed/325d2a490c5e94038cdb0117da9397ece1f11201f425c4e9c57fe5b9f08b/cryptography-46.0.5-cp311-abi3-win32.whl", hash = "sha256:60ee7e19e95104d4c03871d7d7dfb3d22ef8a9b9c6778c94e1c8fcc8365afd48", size = 3028230, upload-time = "2026-02-10T19:17:30.518Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/5a/ac0f49e48063ab4255d9e3b79f5def51697fce1a95ea1370f03dc9db76f6/cryptography-46.0.5-cp311-abi3-win_amd64.whl", hash = "sha256:38946c54b16c885c72c4f59846be9743d699eee2b69b6988e0a00a01f46a61a4", size = 3480909, upload-time = "2026-02-10T19:17:32.083Z" },
+ { url = "https://files.pythonhosted.org/packages/00/13/3d278bfa7a15a96b9dc22db5a12ad1e48a9eb3d40e1827ef66a5df75d0d0/cryptography-46.0.5-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:94a76daa32eb78d61339aff7952ea819b1734b46f73646a07decb40e5b3448e2", size = 7119287, upload-time = "2026-02-10T19:17:33.801Z" },
+ { url = "https://files.pythonhosted.org/packages/67/c8/581a6702e14f0898a0848105cbefd20c058099e2c2d22ef4e476dfec75d7/cryptography-46.0.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5be7bf2fb40769e05739dd0046e7b26f9d4670badc7b032d6ce4db64dddc0678", size = 4265728, upload-time = "2026-02-10T19:17:35.569Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/4a/ba1a65ce8fc65435e5a849558379896c957870dd64fecea97b1ad5f46a37/cryptography-46.0.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe346b143ff9685e40192a4960938545c699054ba11d4f9029f94751e3f71d87", size = 4408287, upload-time = "2026-02-10T19:17:36.938Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/67/8ffdbf7b65ed1ac224d1c2df3943553766914a8ca718747ee3871da6107e/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:c69fd885df7d089548a42d5ec05be26050ebcd2283d89b3d30676eb32ff87dee", size = 4270291, upload-time = "2026-02-10T19:17:38.748Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/e5/f52377ee93bc2f2bba55a41a886fd208c15276ffbd2569f2ddc89d50e2c5/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:8293f3dea7fc929ef7240796ba231413afa7b68ce38fd21da2995549f5961981", size = 4927539, upload-time = "2026-02-10T19:17:40.241Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/02/cfe39181b02419bbbbcf3abdd16c1c5c8541f03ca8bda240debc467d5a12/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:1abfdb89b41c3be0365328a410baa9df3ff8a9110fb75e7b52e66803ddabc9a9", size = 4442199, upload-time = "2026-02-10T19:17:41.789Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/96/2fcaeb4873e536cf71421a388a6c11b5bc846e986b2b069c79363dc1648e/cryptography-46.0.5-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:d66e421495fdb797610a08f43b05269e0a5ea7f5e652a89bfd5a7d3c1dee3648", size = 3960131, upload-time = "2026-02-10T19:17:43.379Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/d2/b27631f401ddd644e94c5cf33c9a4069f72011821cf3dc7309546b0642a0/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:4e817a8920bfbcff8940ecfd60f23d01836408242b30f1a708d93198393a80b4", size = 4270072, upload-time = "2026-02-10T19:17:45.481Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/a7/60d32b0370dae0b4ebe55ffa10e8599a2a59935b5ece1b9f06edb73abdeb/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:68f68d13f2e1cb95163fa3b4db4bf9a159a418f5f6e7242564fc75fcae667fd0", size = 4892170, upload-time = "2026-02-10T19:17:46.997Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/b9/cf73ddf8ef1164330eb0b199a589103c363afa0cf794218c24d524a58eab/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:a3d1fae9863299076f05cb8a778c467578262fae09f9dc0ee9b12eb4268ce663", size = 4441741, upload-time = "2026-02-10T19:17:48.661Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/eb/eee00b28c84c726fe8fa0158c65afe312d9c3b78d9d01daf700f1f6e37ff/cryptography-46.0.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c4143987a42a2397f2fc3b4d7e3a7d313fbe684f67ff443999e803dd75a76826", size = 4396728, upload-time = "2026-02-10T19:17:50.058Z" },
+ { url = "https://files.pythonhosted.org/packages/65/f4/6bc1a9ed5aef7145045114b75b77c2a8261b4d38717bd8dea111a63c3442/cryptography-46.0.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7d731d4b107030987fd61a7f8ab512b25b53cef8f233a97379ede116f30eb67d", size = 4652001, upload-time = "2026-02-10T19:17:51.54Z" },
+ { url = "https://files.pythonhosted.org/packages/86/ef/5d00ef966ddd71ac2e6951d278884a84a40ffbd88948ef0e294b214ae9e4/cryptography-46.0.5-cp314-cp314t-win32.whl", hash = "sha256:c3bcce8521d785d510b2aad26ae2c966092b7daa8f45dd8f44734a104dc0bc1a", size = 3003637, upload-time = "2026-02-10T19:17:52.997Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/57/f3f4160123da6d098db78350fdfd9705057aad21de7388eacb2401dceab9/cryptography-46.0.5-cp314-cp314t-win_amd64.whl", hash = "sha256:4d8ae8659ab18c65ced284993c2265910f6c9e650189d4e3f68445ef82a810e4", size = 3469487, upload-time = "2026-02-10T19:17:54.549Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/fa/a66aa722105ad6a458bebd64086ca2b72cdd361fed31763d20390f6f1389/cryptography-46.0.5-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:4108d4c09fbbf2789d0c926eb4152ae1760d5a2d97612b92d508d96c861e4d31", size = 7170514, upload-time = "2026-02-10T19:17:56.267Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/04/c85bdeab78c8bc77b701bf0d9bdcf514c044e18a46dcff330df5448631b0/cryptography-46.0.5-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1f30a86d2757199cb2d56e48cce14deddf1f9c95f1ef1b64ee91ea43fe2e18", size = 4275349, upload-time = "2026-02-10T19:17:58.419Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/32/9b87132a2f91ee7f5223b091dc963055503e9b442c98fc0b8a5ca765fab0/cryptography-46.0.5-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:039917b0dc418bb9f6edce8a906572d69e74bd330b0b3fea4f79dab7f8ddd235", size = 4420667, upload-time = "2026-02-10T19:18:00.619Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/a6/a7cb7010bec4b7c5692ca6f024150371b295ee1c108bdc1c400e4c44562b/cryptography-46.0.5-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ba2a27ff02f48193fc4daeadf8ad2590516fa3d0adeeb34336b96f7fa64c1e3a", size = 4276980, upload-time = "2026-02-10T19:18:02.379Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/7c/c4f45e0eeff9b91e3f12dbd0e165fcf2a38847288fcfd889deea99fb7b6d/cryptography-46.0.5-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:61aa400dce22cb001a98014f647dc21cda08f7915ceb95df0c9eaf84b4b6af76", size = 4939143, upload-time = "2026-02-10T19:18:03.964Z" },
+ { url = "https://files.pythonhosted.org/packages/37/19/e1b8f964a834eddb44fa1b9a9976f4e414cbb7aa62809b6760c8803d22d1/cryptography-46.0.5-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ce58ba46e1bc2aac4f7d9290223cead56743fa6ab94a5d53292ffaac6a91614", size = 4453674, upload-time = "2026-02-10T19:18:05.588Z" },
+ { url = "https://files.pythonhosted.org/packages/db/ed/db15d3956f65264ca204625597c410d420e26530c4e2943e05a0d2f24d51/cryptography-46.0.5-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:420d0e909050490d04359e7fdb5ed7e667ca5c3c402b809ae2563d7e66a92229", size = 3978801, upload-time = "2026-02-10T19:18:07.167Z" },
+ { url = "https://files.pythonhosted.org/packages/41/e2/df40a31d82df0a70a0daf69791f91dbb70e47644c58581d654879b382d11/cryptography-46.0.5-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:582f5fcd2afa31622f317f80426a027f30dc792e9c80ffee87b993200ea115f1", size = 4276755, upload-time = "2026-02-10T19:18:09.813Z" },
+ { url = "https://files.pythonhosted.org/packages/33/45/726809d1176959f4a896b86907b98ff4391a8aa29c0aaaf9450a8a10630e/cryptography-46.0.5-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:bfd56bb4b37ed4f330b82402f6f435845a5f5648edf1ad497da51a8452d5d62d", size = 4901539, upload-time = "2026-02-10T19:18:11.263Z" },
+ { url = "https://files.pythonhosted.org/packages/99/0f/a3076874e9c88ecb2ecc31382f6e7c21b428ede6f55aafa1aa272613e3cd/cryptography-46.0.5-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:a3d507bb6a513ca96ba84443226af944b0f7f47dcc9a399d110cd6146481d24c", size = 4452794, upload-time = "2026-02-10T19:18:12.914Z" },
+ { url = "https://files.pythonhosted.org/packages/02/ef/ffeb542d3683d24194a38f66ca17c0a4b8bf10631feef44a7ef64e631b1a/cryptography-46.0.5-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9f16fbdf4da055efb21c22d81b89f155f02ba420558db21288b3d0035bafd5f4", size = 4404160, upload-time = "2026-02-10T19:18:14.375Z" },
+ { url = "https://files.pythonhosted.org/packages/96/93/682d2b43c1d5f1406ed048f377c0fc9fc8f7b0447a478d5c65ab3d3a66eb/cryptography-46.0.5-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ced80795227d70549a411a4ab66e8ce307899fad2220ce5ab2f296e687eacde9", size = 4667123, upload-time = "2026-02-10T19:18:15.886Z" },
+ { url = "https://files.pythonhosted.org/packages/45/2d/9c5f2926cb5300a8eefc3f4f0b3f3df39db7f7ce40c8365444c49363cbda/cryptography-46.0.5-cp38-abi3-win32.whl", hash = "sha256:02f547fce831f5096c9a567fd41bc12ca8f11df260959ecc7c3202555cc47a72", size = 3010220, upload-time = "2026-02-10T19:18:17.361Z" },
+ { url = "https://files.pythonhosted.org/packages/48/ef/0c2f4a8e31018a986949d34a01115dd057bf536905dca38897bacd21fac3/cryptography-46.0.5-cp38-abi3-win_amd64.whl", hash = "sha256:556e106ee01aa13484ce9b0239bca667be5004efb0aabbed28d353df86445595", size = 3467050, upload-time = "2026-02-10T19:18:18.899Z" },
+]
+
+[[package]]
+name = "cuda-bindings"
+version = "12.9.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "cuda-pathfinder", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
+]
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a9/c1/dabe88f52c3e3760d861401bb994df08f672ec893b8f7592dc91626adcf3/cuda_bindings-12.9.4-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fda147a344e8eaeca0c6ff113d2851ffca8f7dfc0a6c932374ee5c47caa649c8", size = 12151019, upload-time = "2025-10-21T14:51:43.167Z" },
+ { url = "https://files.pythonhosted.org/packages/63/56/e465c31dc9111be3441a9ba7df1941fe98f4aa6e71e8788a3fb4534ce24d/cuda_bindings-12.9.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:32bdc5a76906be4c61eb98f546a6786c5773a881f3b166486449b5d141e4a39f", size = 11906628, upload-time = "2025-10-21T14:51:49.905Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/84/1e6be415e37478070aeeee5884c2022713c1ecc735e6d82d744de0252eee/cuda_bindings-12.9.4-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:56e0043c457a99ac473ddc926fe0dc4046694d99caef633e92601ab52cbe17eb", size = 11925991, upload-time = "2025-10-21T14:51:56.535Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/af/6dfd8f2ed90b1d4719bc053ff8940e494640fe4212dc3dd72f383e4992da/cuda_bindings-12.9.4-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8b72ee72a9cc1b531db31eebaaee5c69a8ec3500e32c6933f2d3b15297b53686", size = 11922703, upload-time = "2025-10-21T14:52:03.585Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/19/90ac264acc00f6df8a49378eedec9fd2db3061bf9263bf9f39fd3d8377c3/cuda_bindings-12.9.4-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d80bffc357df9988dca279734bc9674c3934a654cab10cadeed27ce17d8635ee", size = 11924658, upload-time = "2025-10-21T14:52:10.411Z" },
+]
+
+[[package]]
+name = "cuda-pathfinder"
+version = "1.4.2"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/92/de/8ca2b613042550dcf9ef50c596c8b1f602afda92cf9032ac28a73f6ee410/cuda_pathfinder-1.4.2-py3-none-any.whl", hash = "sha256:eb354abc20278f8609dc5b666a24648655bef5613c6dfe78a238a6fd95566754", size = 44779, upload-time = "2026-03-10T21:57:30.974Z" },
+]
+
+[[package]]
+name = "distlib"
+version = "0.4.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" },
+]
+
+[[package]]
+name = "fastapi"
+version = "0.135.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "annotated-doc" },
+ { name = "pydantic" },
+ { name = "starlette" },
+ { name = "typing-extensions" },
+ { name = "typing-inspection" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/e7/7b/f8e0211e9380f7195ba3f3d40c292594fd81ba8ec4629e3854c353aaca45/fastapi-0.135.1.tar.gz", hash = "sha256:d04115b508d936d254cea545b7312ecaa58a7b3a0f84952535b4c9afae7668cd", size = 394962, upload-time = "2026-03-01T18:18:29.369Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e4/72/42e900510195b23a56bde950d26a51f8b723846bfcaa0286e90287f0422b/fastapi-0.135.1-py3-none-any.whl", hash = "sha256:46e2fc5745924b7c840f71ddd277382af29ce1cdb7d5eab5bf697e3fb9999c9e", size = 116999, upload-time = "2026-03-01T18:18:30.831Z" },
+]
+
+[[package]]
+name = "ffmpy"
+version = "1.0.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/7d/d2/1c4c582d71bcc65c76fa69fab85de6257d50fdf6fd4a2317c53917e9a581/ffmpy-1.0.0.tar.gz", hash = "sha256:b12932e95435c8820f1cd041024402765f821971e4bae753b327fc02a6e12f8b", size = 5101, upload-time = "2025-11-11T06:24:23.856Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/55/56/dd3669eccebb6d8ac81e624542ebd53fe6f08e1b8f2f8d50aeb7e3b83f99/ffmpy-1.0.0-py3-none-any.whl", hash = "sha256:5640e5f0fd03fb6236d0e119b16ccf6522db1c826fdf35dcb87087b60fd7504f", size = 5614, upload-time = "2025-11-11T06:24:22.818Z" },
+]
+
+[[package]]
+name = "filelock"
+version = "3.25.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/b3/8b/4c32ecde6bea6486a2a5d05340e695174351ff6b06cf651a74c005f9df00/filelock-3.25.1.tar.gz", hash = "sha256:b9a2e977f794ef94d77cdf7d27129ac648a61f585bff3ca24630c1629f701aa9", size = 40319, upload-time = "2026-03-09T19:38:47.309Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a9/b8/2f664b56a3b4b32d28d3d106c71783073f712ba43ff6d34b9ea0ce36dc7b/filelock-3.25.1-py3-none-any.whl", hash = "sha256:18972df45473c4aa2c7921b609ee9ca4925910cc3a0fb226c96b92fc224ef7bf", size = 26720, upload-time = "2026-03-09T19:38:45.718Z" },
+]
+
+[[package]]
+name = "frozenlist"
+version = "1.8.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875, upload-time = "2025-10-06T05:38:17.865Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/69/29/948b9aa87e75820a38650af445d2ef2b6b8a6fab1a23b6bb9e4ef0be2d59/frozenlist-1.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1", size = 87782, upload-time = "2025-10-06T05:36:06.649Z" },
+ { url = "https://files.pythonhosted.org/packages/64/80/4f6e318ee2a7c0750ed724fa33a4bdf1eacdc5a39a7a24e818a773cd91af/frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b", size = 50594, upload-time = "2025-10-06T05:36:07.69Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4", size = 50448, upload-time = "2025-10-06T05:36:08.78Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/bd/d91c5e39f490a49df14320f4e8c80161cfcce09f1e2cde1edd16a551abb3/frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383", size = 242411, upload-time = "2025-10-06T05:36:09.801Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/83/f61505a05109ef3293dfb1ff594d13d64a2324ac3482be2cedc2be818256/frozenlist-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f423a119f4777a4a056b66ce11527366a8bb92f54e541ade21f2374433f6d4", size = 243014, upload-time = "2025-10-06T05:36:11.394Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/cb/cb6c7b0f7d4023ddda30cf56b8b17494eb3a79e3fda666bf735f63118b35/frozenlist-1.8.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3462dd9475af2025c31cc61be6652dfa25cbfb56cbbf52f4ccfe029f38decaf8", size = 234909, upload-time = "2025-10-06T05:36:12.598Z" },
+ { url = "https://files.pythonhosted.org/packages/31/c5/cd7a1f3b8b34af009fb17d4123c5a778b44ae2804e3ad6b86204255f9ec5/frozenlist-1.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4c800524c9cd9bac5166cd6f55285957fcfc907db323e193f2afcd4d9abd69b", size = 250049, upload-time = "2025-10-06T05:36:14.065Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/01/2f95d3b416c584a1e7f0e1d6d31998c4a795f7544069ee2e0962a4b60740/frozenlist-1.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d6a5df73acd3399d893dafc71663ad22534b5aa4f94e8a2fabfe856c3c1b6a52", size = 256485, upload-time = "2025-10-06T05:36:15.39Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/03/024bf7720b3abaebcff6d0793d73c154237b85bdf67b7ed55e5e9596dc9a/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:405e8fe955c2280ce66428b3ca55e12b3c4e9c336fb2103a4937e891c69a4a29", size = 237619, upload-time = "2025-10-06T05:36:16.558Z" },
+ { url = "https://files.pythonhosted.org/packages/69/fa/f8abdfe7d76b731f5d8bd217827cf6764d4f1d9763407e42717b4bed50a0/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:908bd3f6439f2fef9e85031b59fd4f1297af54415fb60e4254a95f75b3cab3f3", size = 250320, upload-time = "2025-10-06T05:36:17.821Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/3c/b051329f718b463b22613e269ad72138cc256c540f78a6de89452803a47d/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:294e487f9ec720bd8ffcebc99d575f7eff3568a08a253d1ee1a0378754b74143", size = 246820, upload-time = "2025-10-06T05:36:19.046Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/ae/58282e8f98e444b3f4dd42448ff36fa38bef29e40d40f330b22e7108f565/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:74c51543498289c0c43656701be6b077f4b265868fa7f8a8859c197006efb608", size = 250518, upload-time = "2025-10-06T05:36:20.763Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/96/007e5944694d66123183845a106547a15944fbbb7154788cbf7272789536/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:776f352e8329135506a1d6bf16ac3f87bc25b28e765949282dcc627af36123aa", size = 239096, upload-time = "2025-10-06T05:36:22.129Z" },
+ { url = "https://files.pythonhosted.org/packages/66/bb/852b9d6db2fa40be96f29c0d1205c306288f0684df8fd26ca1951d461a56/frozenlist-1.8.0-cp312-cp312-win32.whl", hash = "sha256:433403ae80709741ce34038da08511d4a77062aa924baf411ef73d1146e74faf", size = 39985, upload-time = "2025-10-06T05:36:23.661Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/af/38e51a553dd66eb064cdf193841f16f077585d4d28394c2fa6235cb41765/frozenlist-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:34187385b08f866104f0c0617404c8eb08165ab1272e884abc89c112e9c00746", size = 44591, upload-time = "2025-10-06T05:36:24.958Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/06/1dc65480ab147339fecc70797e9c2f69d9cea9cf38934ce08df070fdb9cb/frozenlist-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:fe3c58d2f5db5fbd18c2987cba06d51b0529f52bc3a6cdc33d3f4eab725104bd", size = 40102, upload-time = "2025-10-06T05:36:26.333Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/40/0832c31a37d60f60ed79e9dfb5a92e1e2af4f40a16a29abcc7992af9edff/frozenlist-1.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8d92f1a84bb12d9e56f818b3a746f3efba93c1b63c8387a73dde655e1e42282a", size = 85717, upload-time = "2025-10-06T05:36:27.341Z" },
+ { url = "https://files.pythonhosted.org/packages/30/ba/b0b3de23f40bc55a7057bd38434e25c34fa48e17f20ee273bbde5e0650f3/frozenlist-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96153e77a591c8adc2ee805756c61f59fef4cf4073a9275ee86fe8cba41241f7", size = 49651, upload-time = "2025-10-06T05:36:28.855Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f21f00a91358803399890ab167098c131ec2ddd5f8f5fd5fe9c9f2c6fcd91e40", size = 49417, upload-time = "2025-10-06T05:36:29.877Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/4e/e4691508f9477ce67da2015d8c00acd751e6287739123113a9fca6f1604e/frozenlist-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fb30f9626572a76dfe4293c7194a09fb1fe93ba94c7d4f720dfae3b646b45027", size = 234391, upload-time = "2025-10-06T05:36:31.301Z" },
+ { url = "https://files.pythonhosted.org/packages/40/76/c202df58e3acdf12969a7895fd6f3bc016c642e6726aa63bd3025e0fc71c/frozenlist-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaa352d7047a31d87dafcacbabe89df0aa506abb5b1b85a2fb91bc3faa02d822", size = 233048, upload-time = "2025-10-06T05:36:32.531Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/c0/8746afb90f17b73ca5979c7a3958116e105ff796e718575175319b5bb4ce/frozenlist-1.8.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:03ae967b4e297f58f8c774c7eabcce57fe3c2434817d4385c50661845a058121", size = 226549, upload-time = "2025-10-06T05:36:33.706Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/eb/4c7eefc718ff72f9b6c4893291abaae5fbc0c82226a32dcd8ef4f7a5dbef/frozenlist-1.8.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6292f1de555ffcc675941d65fffffb0a5bcd992905015f85d0592201793e0e5", size = 239833, upload-time = "2025-10-06T05:36:34.947Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/4e/e5c02187cf704224f8b21bee886f3d713ca379535f16893233b9d672ea71/frozenlist-1.8.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29548f9b5b5e3460ce7378144c3010363d8035cea44bc0bf02d57f5a685e084e", size = 245363, upload-time = "2025-10-06T05:36:36.534Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/96/cb85ec608464472e82ad37a17f844889c36100eed57bea094518bf270692/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ec3cc8c5d4084591b4237c0a272cc4f50a5b03396a47d9caaf76f5d7b38a4f11", size = 229314, upload-time = "2025-10-06T05:36:38.582Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/6f/4ae69c550e4cee66b57887daeebe006fe985917c01d0fff9caab9883f6d0/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:517279f58009d0b1f2e7c1b130b377a349405da3f7621ed6bfae50b10adf20c1", size = 243365, upload-time = "2025-10-06T05:36:40.152Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/58/afd56de246cf11780a40a2c28dc7cbabbf06337cc8ddb1c780a2d97e88d8/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:db1e72ede2d0d7ccb213f218df6a078a9c09a7de257c2fe8fcef16d5925230b1", size = 237763, upload-time = "2025-10-06T05:36:41.355Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/36/cdfaf6ed42e2644740d4a10452d8e97fa1c062e2a8006e4b09f1b5fd7d63/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b4dec9482a65c54a5044486847b8a66bf10c9cb4926d42927ec4e8fd5db7fed8", size = 240110, upload-time = "2025-10-06T05:36:42.716Z" },
+ { url = "https://files.pythonhosted.org/packages/03/a8/9ea226fbefad669f11b52e864c55f0bd57d3c8d7eb07e9f2e9a0b39502e1/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:21900c48ae04d13d416f0e1e0c4d81f7931f73a9dfa0b7a8746fb2fe7dd970ed", size = 233717, upload-time = "2025-10-06T05:36:44.251Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/0b/1b5531611e83ba7d13ccc9988967ea1b51186af64c42b7a7af465dcc9568/frozenlist-1.8.0-cp313-cp313-win32.whl", hash = "sha256:8b7b94a067d1c504ee0b16def57ad5738701e4ba10cec90529f13fa03c833496", size = 39628, upload-time = "2025-10-06T05:36:45.423Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/cf/174c91dbc9cc49bc7b7aab74d8b734e974d1faa8f191c74af9b7e80848e6/frozenlist-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:878be833caa6a3821caf85eb39c5ba92d28e85df26d57afb06b35b2efd937231", size = 43882, upload-time = "2025-10-06T05:36:46.796Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/17/502cd212cbfa96eb1388614fe39a3fc9ab87dbbe042b66f97acb57474834/frozenlist-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:44389d135b3ff43ba8cc89ff7f51f5a0bb6b63d829c8300f79a2fe4fe61bcc62", size = 39676, upload-time = "2025-10-06T05:36:47.8Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/5c/3bbfaa920dfab09e76946a5d2833a7cbdf7b9b4a91c714666ac4855b88b4/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e25ac20a2ef37e91c1b39938b591457666a0fa835c7783c3a8f33ea42870db94", size = 89235, upload-time = "2025-10-06T05:36:48.78Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/d6/f03961ef72166cec1687e84e8925838442b615bd0b8854b54923ce5b7b8a/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07cdca25a91a4386d2e76ad992916a85038a9b97561bf7a3fd12d5d9ce31870c", size = 50742, upload-time = "2025-10-06T05:36:49.837Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/bb/a6d12b7ba4c3337667d0e421f7181c82dda448ce4e7ad7ecd249a16fa806/frozenlist-1.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4e0c11f2cc6717e0a741f84a527c52616140741cd812a50422f83dc31749fb52", size = 51725, upload-time = "2025-10-06T05:36:50.851Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/71/d1fed0ffe2c2ccd70b43714c6cab0f4188f09f8a67a7914a6b46ee30f274/frozenlist-1.8.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b3210649ee28062ea6099cfda39e147fa1bc039583c8ee4481cb7811e2448c51", size = 284533, upload-time = "2025-10-06T05:36:51.898Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/1f/fb1685a7b009d89f9bf78a42d94461bc06581f6e718c39344754a5d9bada/frozenlist-1.8.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:581ef5194c48035a7de2aefc72ac6539823bb71508189e5de01d60c9dcd5fa65", size = 292506, upload-time = "2025-10-06T05:36:53.101Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/3b/b991fe1612703f7e0d05c0cf734c1b77aaf7c7d321df4572e8d36e7048c8/frozenlist-1.8.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3ef2d026f16a2b1866e1d86fc4e1291e1ed8a387b2c333809419a2f8b3a77b82", size = 274161, upload-time = "2025-10-06T05:36:54.309Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/ec/c5c618767bcdf66e88945ec0157d7f6c4a1322f1473392319b7a2501ded7/frozenlist-1.8.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5500ef82073f599ac84d888e3a8c1f77ac831183244bfd7f11eaa0289fb30714", size = 294676, upload-time = "2025-10-06T05:36:55.566Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/ce/3934758637d8f8a88d11f0585d6495ef54b2044ed6ec84492a91fa3b27aa/frozenlist-1.8.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50066c3997d0091c411a66e710f4e11752251e6d2d73d70d8d5d4c76442a199d", size = 300638, upload-time = "2025-10-06T05:36:56.758Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/4f/a7e4d0d467298f42de4b41cbc7ddaf19d3cfeabaf9ff97c20c6c7ee409f9/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5c1c8e78426e59b3f8005e9b19f6ff46e5845895adbde20ece9218319eca6506", size = 283067, upload-time = "2025-10-06T05:36:57.965Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/48/c7b163063d55a83772b268e6d1affb960771b0e203b632cfe09522d67ea5/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:eefdba20de0d938cec6a89bd4d70f346a03108a19b9df4248d3cf0d88f1b0f51", size = 292101, upload-time = "2025-10-06T05:36:59.237Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/d0/2366d3c4ecdc2fd391e0afa6e11500bfba0ea772764d631bbf82f0136c9d/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cf253e0e1c3ceb4aaff6df637ce033ff6535fb8c70a764a8f46aafd3d6ab798e", size = 289901, upload-time = "2025-10-06T05:37:00.811Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/94/daff920e82c1b70e3618a2ac39fbc01ae3e2ff6124e80739ce5d71c9b920/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:032efa2674356903cd0261c4317a561a6850f3ac864a63fc1583147fb05a79b0", size = 289395, upload-time = "2025-10-06T05:37:02.115Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/20/bba307ab4235a09fdcd3cc5508dbabd17c4634a1af4b96e0f69bfe551ebd/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6da155091429aeba16851ecb10a9104a108bcd32f6c1642867eadaee401c1c41", size = 283659, upload-time = "2025-10-06T05:37:03.711Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/00/04ca1c3a7a124b6de4f8a9a17cc2fcad138b4608e7a3fc5877804b8715d7/frozenlist-1.8.0-cp313-cp313t-win32.whl", hash = "sha256:0f96534f8bfebc1a394209427d0f8a63d343c9779cda6fc25e8e121b5fd8555b", size = 43492, upload-time = "2025-10-06T05:37:04.915Z" },
+ { url = "https://files.pythonhosted.org/packages/59/5e/c69f733a86a94ab10f68e496dc6b7e8bc078ebb415281d5698313e3af3a1/frozenlist-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5d63a068f978fc69421fb0e6eb91a9603187527c86b7cd3f534a5b77a592b888", size = 48034, upload-time = "2025-10-06T05:37:06.343Z" },
+ { url = "https://files.pythonhosted.org/packages/16/6c/be9d79775d8abe79b05fa6d23da99ad6e7763a1d080fbae7290b286093fd/frozenlist-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf0a7e10b077bf5fb9380ad3ae8ce20ef919a6ad93b4552896419ac7e1d8e042", size = 41749, upload-time = "2025-10-06T05:37:07.431Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/c8/85da824b7e7b9b6e7f7705b2ecaf9591ba6f79c1177f324c2735e41d36a2/frozenlist-1.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cee686f1f4cadeb2136007ddedd0aaf928ab95216e7691c63e50a8ec066336d0", size = 86127, upload-time = "2025-10-06T05:37:08.438Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/e8/a1185e236ec66c20afd72399522f142c3724c785789255202d27ae992818/frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:119fb2a1bd47307e899c2fac7f28e85b9a543864df47aa7ec9d3c1b4545f096f", size = 49698, upload-time = "2025-10-06T05:37:09.48Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/93/72b1736d68f03fda5fdf0f2180fb6caaae3894f1b854d006ac61ecc727ee/frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4970ece02dbc8c3a92fcc5228e36a3e933a01a999f7094ff7c23fbd2beeaa67c", size = 49749, upload-time = "2025-10-06T05:37:10.569Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/b2/fabede9fafd976b991e9f1b9c8c873ed86f202889b864756f240ce6dd855/frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:cba69cb73723c3f329622e34bdbf5ce1f80c21c290ff04256cff1cd3c2036ed2", size = 231298, upload-time = "2025-10-06T05:37:11.993Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/3b/d9b1e0b0eed36e70477ffb8360c49c85c8ca8ef9700a4e6711f39a6e8b45/frozenlist-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:778a11b15673f6f1df23d9586f83c4846c471a8af693a22e066508b77d201ec8", size = 232015, upload-time = "2025-10-06T05:37:13.194Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/94/be719d2766c1138148564a3960fc2c06eb688da592bdc25adcf856101be7/frozenlist-1.8.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0325024fe97f94c41c08872db482cf8ac4800d80e79222c6b0b7b162d5b13686", size = 225038, upload-time = "2025-10-06T05:37:14.577Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/09/6712b6c5465f083f52f50cf74167b92d4ea2f50e46a9eea0523d658454ae/frozenlist-1.8.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:97260ff46b207a82a7567b581ab4190bd4dfa09f4db8a8b49d1a958f6aa4940e", size = 240130, upload-time = "2025-10-06T05:37:15.781Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/d4/cd065cdcf21550b54f3ce6a22e143ac9e4836ca42a0de1022da8498eac89/frozenlist-1.8.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:54b2077180eb7f83dd52c40b2750d0a9f175e06a42e3213ce047219de902717a", size = 242845, upload-time = "2025-10-06T05:37:17.037Z" },
+ { url = "https://files.pythonhosted.org/packages/62/c3/f57a5c8c70cd1ead3d5d5f776f89d33110b1addae0ab010ad774d9a44fb9/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2f05983daecab868a31e1da44462873306d3cbfd76d1f0b5b69c473d21dbb128", size = 229131, upload-time = "2025-10-06T05:37:18.221Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/52/232476fe9cb64f0742f3fde2b7d26c1dac18b6d62071c74d4ded55e0ef94/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:33f48f51a446114bc5d251fb2954ab0164d5be02ad3382abcbfe07e2531d650f", size = 240542, upload-time = "2025-10-06T05:37:19.771Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/85/07bf3f5d0fb5414aee5f47d33c6f5c77bfe49aac680bfece33d4fdf6a246/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:154e55ec0655291b5dd1b8731c637ecdb50975a2ae70c606d100750a540082f7", size = 237308, upload-time = "2025-10-06T05:37:20.969Z" },
+ { url = "https://files.pythonhosted.org/packages/11/99/ae3a33d5befd41ac0ca2cc7fd3aa707c9c324de2e89db0e0f45db9a64c26/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:4314debad13beb564b708b4a496020e5306c7333fa9a3ab90374169a20ffab30", size = 238210, upload-time = "2025-10-06T05:37:22.252Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/60/b1d2da22f4970e7a155f0adde9b1435712ece01b3cd45ba63702aea33938/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:073f8bf8becba60aa931eb3bc420b217bb7d5b8f4750e6f8b3be7f3da85d38b7", size = 231972, upload-time = "2025-10-06T05:37:23.5Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/ab/945b2f32de889993b9c9133216c068b7fcf257d8595a0ac420ac8677cab0/frozenlist-1.8.0-cp314-cp314-win32.whl", hash = "sha256:bac9c42ba2ac65ddc115d930c78d24ab8d4f465fd3fc473cdedfccadb9429806", size = 40536, upload-time = "2025-10-06T05:37:25.581Z" },
+ { url = "https://files.pythonhosted.org/packages/59/ad/9caa9b9c836d9ad6f067157a531ac48b7d36499f5036d4141ce78c230b1b/frozenlist-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3e0761f4d1a44f1d1a47996511752cf3dcec5bbdd9cc2b4fe595caf97754b7a0", size = 44330, upload-time = "2025-10-06T05:37:26.928Z" },
+ { url = "https://files.pythonhosted.org/packages/82/13/e6950121764f2676f43534c555249f57030150260aee9dcf7d64efda11dd/frozenlist-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:d1eaff1d00c7751b7c6662e9c5ba6eb2c17a2306ba5e2a37f24ddf3cc953402b", size = 40627, upload-time = "2025-10-06T05:37:28.075Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/c7/43200656ecc4e02d3f8bc248df68256cd9572b3f0017f0a0c4e93440ae23/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d3bb933317c52d7ea5004a1c442eef86f426886fba134ef8cf4226ea6ee1821d", size = 89238, upload-time = "2025-10-06T05:37:29.373Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/29/55c5f0689b9c0fb765055629f472c0de484dcaf0acee2f7707266ae3583c/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8009897cdef112072f93a0efdce29cd819e717fd2f649ee3016efd3cd885a7ed", size = 50738, upload-time = "2025-10-06T05:37:30.792Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2c5dcbbc55383e5883246d11fd179782a9d07a986c40f49abe89ddf865913930", size = 51739, upload-time = "2025-10-06T05:37:32.127Z" },
+ { url = "https://files.pythonhosted.org/packages/62/1c/3d8622e60d0b767a5510d1d3cf21065b9db874696a51ea6d7a43180a259c/frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:39ecbc32f1390387d2aa4f5a995e465e9e2f79ba3adcac92d68e3e0afae6657c", size = 284186, upload-time = "2025-10-06T05:37:33.21Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/14/aa36d5f85a89679a85a1d44cd7a6657e0b1c75f61e7cad987b203d2daca8/frozenlist-1.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92db2bf818d5cc8d9c1f1fc56b897662e24ea5adb36ad1f1d82875bd64e03c24", size = 292196, upload-time = "2025-10-06T05:37:36.107Z" },
+ { url = "https://files.pythonhosted.org/packages/05/23/6bde59eb55abd407d34f77d39a5126fb7b4f109a3f611d3929f14b700c66/frozenlist-1.8.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dc43a022e555de94c3b68a4ef0b11c4f747d12c024a520c7101709a2144fb37", size = 273830, upload-time = "2025-10-06T05:37:37.663Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/3f/22cff331bfad7a8afa616289000ba793347fcd7bc275f3b28ecea2a27909/frozenlist-1.8.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb89a7f2de3602cfed448095bab3f178399646ab7c61454315089787df07733a", size = 294289, upload-time = "2025-10-06T05:37:39.261Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/89/5b057c799de4838b6c69aa82b79705f2027615e01be996d2486a69ca99c4/frozenlist-1.8.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:33139dc858c580ea50e7e60a1b0ea003efa1fd42e6ec7fdbad78fff65fad2fd2", size = 300318, upload-time = "2025-10-06T05:37:43.213Z" },
+ { url = "https://files.pythonhosted.org/packages/30/de/2c22ab3eb2a8af6d69dc799e48455813bab3690c760de58e1bf43b36da3e/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:168c0969a329b416119507ba30b9ea13688fafffac1b7822802537569a1cb0ef", size = 282814, upload-time = "2025-10-06T05:37:45.337Z" },
+ { url = "https://files.pythonhosted.org/packages/59/f7/970141a6a8dbd7f556d94977858cfb36fa9b66e0892c6dd780d2219d8cd8/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:28bd570e8e189d7f7b001966435f9dac6718324b5be2990ac496cf1ea9ddb7fe", size = 291762, upload-time = "2025-10-06T05:37:46.657Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/15/ca1adae83a719f82df9116d66f5bb28bb95557b3951903d39135620ef157/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b2a095d45c5d46e5e79ba1e5b9cb787f541a8dee0433836cea4b96a2c439dcd8", size = 289470, upload-time = "2025-10-06T05:37:47.946Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/83/dca6dc53bf657d371fbc88ddeb21b79891e747189c5de990b9dfff2ccba1/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:eab8145831a0d56ec9c4139b6c3e594c7a83c2c8be25d5bcf2d86136a532287a", size = 289042, upload-time = "2025-10-06T05:37:49.499Z" },
+ { url = "https://files.pythonhosted.org/packages/96/52/abddd34ca99be142f354398700536c5bd315880ed0a213812bc491cff5e4/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:974b28cf63cc99dfb2188d8d222bc6843656188164848c4f679e63dae4b0708e", size = 283148, upload-time = "2025-10-06T05:37:50.745Z" },
+ { url = "https://files.pythonhosted.org/packages/af/d3/76bd4ed4317e7119c2b7f57c3f6934aba26d277acc6309f873341640e21f/frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df", size = 44676, upload-time = "2025-10-06T05:37:52.222Z" },
+ { url = "https://files.pythonhosted.org/packages/89/76/c615883b7b521ead2944bb3480398cbb07e12b7b4e4d073d3752eb721558/frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd", size = 49451, upload-time = "2025-10-06T05:37:53.425Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/a3/5982da14e113d07b325230f95060e2169f5311b1017ea8af2a29b374c289/frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79", size = 42507, upload-time = "2025-10-06T05:37:54.513Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" },
+]
+
+[[package]]
+name = "fsd-detector"
+version = "1.1.0"
+source = { editable = "." }
+dependencies = [
+ { name = "click" },
+ { name = "gradio" },
+ { name = "pillow" },
+ { name = "pillow-heif" },
+ { name = "ray", extra = ["serve"] },
+ { name = "scikit-learn" },
+ { name = "scipy" },
+ { name = "torch" },
+ { name = "tqdm" },
+]
+
+[package.metadata]
+requires-dist = [
+ { name = "click", specifier = ">=8.3.1" },
+ { name = "gradio", specifier = ">=6.9.0" },
+ { name = "pillow", specifier = ">=12.1.0" },
+ { name = "pillow-heif", specifier = ">=1.2.0" },
+ { name = "ray", extras = ["serve"], specifier = ">=2.53.0" },
+ { name = "scikit-learn", specifier = ">=1.8.0" },
+ { name = "scipy", specifier = ">=1.17.0" },
+ { name = "torch", specifier = ">=2.10.0" },
+ { name = "tqdm", specifier = ">=4.67.3" },
+]
+
+[[package]]
+name = "fsspec"
+version = "2026.2.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/51/7c/f60c259dcbf4f0c47cc4ddb8f7720d2dcdc8888c8e5ad84c73ea4531cc5b/fsspec-2026.2.0.tar.gz", hash = "sha256:6544e34b16869f5aacd5b90bdf1a71acb37792ea3ddf6125ee69a22a53fb8bff", size = 313441, upload-time = "2026-02-05T21:50:53.743Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e6/ab/fb21f4c939bb440104cc2b396d3be1d9b7a9fd3c6c2a53d98c45b3d7c954/fsspec-2026.2.0-py3-none-any.whl", hash = "sha256:98de475b5cb3bd66bedd5c4679e87b4fdfe1a3bf4d707b151b3c07e58c9a2437", size = 202505, upload-time = "2026-02-05T21:50:51.819Z" },
+]
+
+[[package]]
+name = "google-api-core"
+version = "2.30.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "google-auth" },
+ { name = "googleapis-common-protos" },
+ { name = "proto-plus" },
+ { name = "protobuf" },
+ { name = "requests" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/22/98/586ec94553b569080caef635f98a3723db36a38eac0e3d7eb3ea9d2e4b9a/google_api_core-2.30.0.tar.gz", hash = "sha256:02edfa9fab31e17fc0befb5f161b3bf93c9096d99aed584625f38065c511ad9b", size = 176959, upload-time = "2026-02-18T20:28:11.926Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/45/27/09c33d67f7e0dcf06d7ac17d196594e66989299374bfb0d4331d1038e76b/google_api_core-2.30.0-py3-none-any.whl", hash = "sha256:80be49ee937ff9aba0fd79a6eddfde35fe658b9953ab9b79c57dd7061afa8df5", size = 173288, upload-time = "2026-02-18T20:28:10.367Z" },
+]
+
+[[package]]
+name = "google-auth"
+version = "2.49.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "cryptography" },
+ { name = "pyasn1-modules" },
+ { name = "rsa" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/7d/59/7371175bfd949abfb1170aa076352131d7281bd9449c0f978604fc4431c3/google_auth-2.49.0.tar.gz", hash = "sha256:9cc2d9259d3700d7a257681f81052db6737495a1a46b610597f4b8bafe5286ae", size = 333444, upload-time = "2026-03-06T21:53:06.07Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/37/45/de64b823b639103de4b63dd193480dce99526bd36be6530c2dba85bf7817/google_auth-2.49.0-py3-none-any.whl", hash = "sha256:f893ef7307f19cf53700b7e2f61b5a6affe3aa0edf9943b13788920ab92d8d87", size = 240676, upload-time = "2026-03-06T21:52:38.304Z" },
+]
+
+[[package]]
+name = "googleapis-common-protos"
+version = "1.73.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "protobuf" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/99/96/a0205167fa0154f4a542fd6925bdc63d039d88dab3588b875078107e6f06/googleapis_common_protos-1.73.0.tar.gz", hash = "sha256:778d07cd4fbeff84c6f7c72102f0daf98fa2bfd3fa8bea426edc545588da0b5a", size = 147323, upload-time = "2026-03-06T21:53:09.727Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/69/28/23eea8acd65972bbfe295ce3666b28ac510dfcb115fac089d3edb0feb00a/googleapis_common_protos-1.73.0-py3-none-any.whl", hash = "sha256:dfdaaa2e860f242046be561e6d6cb5c5f1541ae02cfbcb034371aadb2942b4e8", size = 297578, upload-time = "2026-03-06T21:52:33.933Z" },
+]
+
+[[package]]
+name = "gradio"
+version = "6.9.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "aiofiles" },
+ { name = "anyio" },
+ { name = "audioop-lts", marker = "python_full_version >= '3.13'" },
+ { name = "brotli" },
+ { name = "fastapi" },
+ { name = "ffmpy" },
+ { name = "gradio-client" },
+ { name = "groovy" },
+ { name = "httpx" },
+ { name = "huggingface-hub" },
+ { name = "jinja2" },
+ { name = "markupsafe" },
+ { name = "numpy" },
+ { name = "orjson" },
+ { name = "packaging" },
+ { name = "pandas" },
+ { name = "pillow" },
+ { name = "pydantic" },
+ { name = "pydub" },
+ { name = "python-multipart" },
+ { name = "pytz" },
+ { name = "pyyaml" },
+ { name = "safehttpx" },
+ { name = "semantic-version" },
+ { name = "starlette" },
+ { name = "tomlkit" },
+ { name = "typer" },
+ { name = "typing-extensions" },
+ { name = "uvicorn" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/bd/83/29bdbf94b212512e3c775482d390f5b699a72d71a2c431dea367a6e45a37/gradio-6.9.0.tar.gz", hash = "sha256:593e60e33233f3586452ebfa9f741817c5ae849a98cc70945f3ccb8dc895eb22", size = 57904480, upload-time = "2026-03-06T17:44:26.025Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b3/8b/dc357ab966544e4dc898a2fee326d755c5f54da82af71a1a802e3476e78e/gradio-6.9.0-py3-none-any.whl", hash = "sha256:c173dd330c9247002a42222c85d76c0ecee65437eff808084e360862e7bbd24f", size = 42940853, upload-time = "2026-03-06T17:44:22.009Z" },
+]
+
+[[package]]
+name = "gradio-client"
+version = "2.3.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "fsspec" },
+ { name = "httpx" },
+ { name = "huggingface-hub" },
+ { name = "packaging" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/97/d2/de2037f5eff13a5145cdf6982fd34c9735f0806e8a2ee5d4bfe9a7d25a54/gradio_client-2.3.0.tar.gz", hash = "sha256:1c700dc60e65bae4386ba7cf3732b9f9d5bcf5fb8eb451df3944fe092d7d9a29", size = 57552, upload-time = "2026-03-06T17:44:38.247Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/99/6a/41752781399811afbf8ac858f63c20eff354ed35169daa39604aefced4e8/gradio_client-2.3.0-py3-none-any.whl", hash = "sha256:9ec51a927888fc188e123a0ac5ad341d9265b325539a399554d1fc2604942e74", size = 58531, upload-time = "2026-03-06T17:44:36.961Z" },
+]
+
+[[package]]
+name = "groovy"
+version = "0.1.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/52/36/bbdede67400277bef33d3ec0e6a31750da972c469f75966b4930c753218f/groovy-0.1.2.tar.gz", hash = "sha256:25c1dc09b3f9d7e292458aa762c6beb96ea037071bf5e917fc81fb78d2231083", size = 17325, upload-time = "2025-02-28T20:24:56.068Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/28/27/3d6dcadc8a3214d8522c1e7f6a19554e33659be44546d44a2f7572ac7d2a/groovy-0.1.2-py3-none-any.whl", hash = "sha256:7f7975bab18c729a257a8b1ae9dcd70b7cafb1720481beae47719af57c35fa64", size = 14090, upload-time = "2025-02-28T20:24:55.152Z" },
+]
+
+[[package]]
+name = "grpcio"
+version = "1.78.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/06/8a/3d098f35c143a89520e568e6539cc098fcd294495910e359889ce8741c84/grpcio-1.78.0.tar.gz", hash = "sha256:7382b95189546f375c174f53a5fa873cef91c4b8005faa05cc5b3beea9c4f1c5", size = 12852416, upload-time = "2026-02-06T09:57:18.093Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/4e/f4/7384ed0178203d6074446b3c4f46c90a22ddf7ae0b3aee521627f54cfc2a/grpcio-1.78.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:f9ab915a267fc47c7e88c387a3a28325b58c898e23d4995f765728f4e3dedb97", size = 5913985, upload-time = "2026-02-06T09:55:26.832Z" },
+ { url = "https://files.pythonhosted.org/packages/81/ed/be1caa25f06594463f685b3790b320f18aea49b33166f4141bfdc2bfb236/grpcio-1.78.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3f8904a8165ab21e07e58bf3e30a73f4dffc7a1e0dbc32d51c61b5360d26f43e", size = 11811853, upload-time = "2026-02-06T09:55:29.224Z" },
+ { url = "https://files.pythonhosted.org/packages/24/a7/f06d151afc4e64b7e3cc3e872d331d011c279aaab02831e40a81c691fb65/grpcio-1.78.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:859b13906ce098c0b493af92142ad051bf64c7870fa58a123911c88606714996", size = 6475766, upload-time = "2026-02-06T09:55:31.825Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/a8/4482922da832ec0082d0f2cc3a10976d84a7424707f25780b82814aafc0a/grpcio-1.78.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:b2342d87af32790f934a79c3112641e7b27d63c261b8b4395350dad43eff1dc7", size = 7170027, upload-time = "2026-02-06T09:55:34.7Z" },
+ { url = "https://files.pythonhosted.org/packages/54/bf/f4a3b9693e35d25b24b0b39fa46d7d8a3c439e0a3036c3451764678fec20/grpcio-1.78.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:12a771591ae40bc65ba67048fa52ef4f0e6db8279e595fd349f9dfddeef571f9", size = 6690766, upload-time = "2026-02-06T09:55:36.902Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/b9/521875265cc99fe5ad4c5a17010018085cae2810a928bf15ebe7d8bcd9cc/grpcio-1.78.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:185dea0d5260cbb2d224c507bf2a5444d5abbb1fa3594c1ed7e4c709d5eb8383", size = 7266161, upload-time = "2026-02-06T09:55:39.824Z" },
+ { url = "https://files.pythonhosted.org/packages/05/86/296a82844fd40a4ad4a95f100b55044b4f817dece732bf686aea1a284147/grpcio-1.78.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:51b13f9aed9d59ee389ad666b8c2214cc87b5de258fa712f9ab05f922e3896c6", size = 8253303, upload-time = "2026-02-06T09:55:42.353Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/e4/ea3c0caf5468537f27ad5aab92b681ed7cc0ef5f8c9196d3fd42c8c2286b/grpcio-1.78.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fd5f135b1bd58ab088930b3c613455796dfa0393626a6972663ccdda5b4ac6ce", size = 7698222, upload-time = "2026-02-06T09:55:44.629Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/47/7f05f81e4bb6b831e93271fb12fd52ba7b319b5402cbc101d588f435df00/grpcio-1.78.0-cp312-cp312-win32.whl", hash = "sha256:94309f498bcc07e5a7d16089ab984d42ad96af1d94b5a4eb966a266d9fcabf68", size = 4066123, upload-time = "2026-02-06T09:55:47.644Z" },
+ { url = "https://files.pythonhosted.org/packages/ad/e7/d6914822c88aa2974dbbd10903d801a28a19ce9cd8bad7e694cbbcf61528/grpcio-1.78.0-cp312-cp312-win_amd64.whl", hash = "sha256:9566fe4ababbb2610c39190791e5b829869351d14369603702e890ef3ad2d06e", size = 4797657, upload-time = "2026-02-06T09:55:49.86Z" },
+ { url = "https://files.pythonhosted.org/packages/05/a9/8f75894993895f361ed8636cd9237f4ab39ef87fd30db17467235ed1c045/grpcio-1.78.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:ce3a90455492bf8bfa38e56fbbe1dbd4f872a3d8eeaf7337dc3b1c8aa28c271b", size = 5920143, upload-time = "2026-02-06T09:55:52.035Z" },
+ { url = "https://files.pythonhosted.org/packages/55/06/0b78408e938ac424100100fd081189451b472236e8a3a1f6500390dc4954/grpcio-1.78.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:2bf5e2e163b356978b23652c4818ce4759d40f4712ee9ec5a83c4be6f8c23a3a", size = 11803926, upload-time = "2026-02-06T09:55:55.494Z" },
+ { url = "https://files.pythonhosted.org/packages/88/93/b59fe7832ff6ae3c78b813ea43dac60e295fa03606d14d89d2e0ec29f4f3/grpcio-1.78.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8f2ac84905d12918e4e55a16da17939eb63e433dc11b677267c35568aa63fc84", size = 6478628, upload-time = "2026-02-06T09:55:58.533Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/df/e67e3734527f9926b7d9c0dde6cd998d1d26850c3ed8eeec81297967ac67/grpcio-1.78.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:b58f37edab4a3881bc6c9bca52670610e0c9ca14e2ea3cf9debf185b870457fb", size = 7173574, upload-time = "2026-02-06T09:56:01.786Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/62/cc03fffb07bfba982a9ec097b164e8835546980aec25ecfa5f9c1a47e022/grpcio-1.78.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:735e38e176a88ce41840c21bb49098ab66177c64c82426e24e0082500cc68af5", size = 6692639, upload-time = "2026-02-06T09:56:04.529Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/9a/289c32e301b85bdb67d7ec68b752155e674ee3ba2173a1858f118e399ef3/grpcio-1.78.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2045397e63a7a0ee7957c25f7dbb36ddc110e0cfb418403d110c0a7a68a844e9", size = 7268838, upload-time = "2026-02-06T09:56:08.397Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/79/1be93f32add280461fa4773880196572563e9c8510861ac2da0ea0f892b6/grpcio-1.78.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a9f136fbafe7ccf4ac7e8e0c28b31066e810be52d6e344ef954a3a70234e1702", size = 8251878, upload-time = "2026-02-06T09:56:10.914Z" },
+ { url = "https://files.pythonhosted.org/packages/65/65/793f8e95296ab92e4164593674ae6291b204bb5f67f9d4a711489cd30ffa/grpcio-1.78.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:748b6138585379c737adc08aeffd21222abbda1a86a0dca2a39682feb9196c20", size = 7695412, upload-time = "2026-02-06T09:56:13.593Z" },
+ { url = "https://files.pythonhosted.org/packages/1c/9f/1e233fe697ecc82845942c2822ed06bb522e70d6771c28d5528e4c50f6a4/grpcio-1.78.0-cp313-cp313-win32.whl", hash = "sha256:271c73e6e5676afe4fc52907686670c7cea22ab2310b76a59b678403ed40d670", size = 4064899, upload-time = "2026-02-06T09:56:15.601Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/27/d86b89e36de8a951501fb06a0f38df19853210f341d0b28f83f4aa0ffa08/grpcio-1.78.0-cp313-cp313-win_amd64.whl", hash = "sha256:f2d4e43ee362adfc05994ed479334d5a451ab7bc3f3fee1b796b8ca66895acb4", size = 4797393, upload-time = "2026-02-06T09:56:17.882Z" },
+ { url = "https://files.pythonhosted.org/packages/29/f2/b56e43e3c968bfe822fa6ce5bca10d5c723aa40875b48791ce1029bb78c7/grpcio-1.78.0-cp314-cp314-linux_armv7l.whl", hash = "sha256:e87cbc002b6f440482b3519e36e1313eb5443e9e9e73d6a52d43bd2004fcfd8e", size = 5920591, upload-time = "2026-02-06T09:56:20.758Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/81/1f3b65bd30c334167bfa8b0d23300a44e2725ce39bba5b76a2460d85f745/grpcio-1.78.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:c41bc64626db62e72afec66b0c8a0da76491510015417c127bfc53b2fe6d7f7f", size = 11813685, upload-time = "2026-02-06T09:56:24.315Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/1c/bbe2f8216a5bd3036119c544d63c2e592bdf4a8ec6e4a1867592f4586b26/grpcio-1.78.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8dfffba826efcf366b1e3ccc37e67afe676f290e13a3b48d31a46739f80a8724", size = 6487803, upload-time = "2026-02-06T09:56:27.367Z" },
+ { url = "https://files.pythonhosted.org/packages/16/5c/a6b2419723ea7ddce6308259a55e8e7593d88464ce8db9f4aa857aba96fa/grpcio-1.78.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:74be1268d1439eaaf552c698cdb11cd594f0c49295ae6bb72c34ee31abbe611b", size = 7173206, upload-time = "2026-02-06T09:56:29.876Z" },
+ { url = "https://files.pythonhosted.org/packages/df/1e/b8801345629a415ea7e26c83d75eb5dbe91b07ffe5210cc517348a8d4218/grpcio-1.78.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:be63c88b32e6c0f1429f1398ca5c09bc64b0d80950c8bb7807d7d7fb36fb84c7", size = 6693826, upload-time = "2026-02-06T09:56:32.305Z" },
+ { url = "https://files.pythonhosted.org/packages/34/84/0de28eac0377742679a510784f049738a80424b17287739fc47d63c2439e/grpcio-1.78.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3c586ac70e855c721bda8f548d38c3ca66ac791dc49b66a8281a1f99db85e452", size = 7277897, upload-time = "2026-02-06T09:56:34.915Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/9c/ad8685cfe20559a9edb66f735afdcb2b7d3de69b13666fdfc542e1916ebd/grpcio-1.78.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:35eb275bf1751d2ffbd8f57cdbc46058e857cf3971041521b78b7db94bdaf127", size = 8252404, upload-time = "2026-02-06T09:56:37.553Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/05/33a7a4985586f27e1de4803887c417ec7ced145ebd069bc38a9607059e2b/grpcio-1.78.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:207db540302c884b8848036b80db352a832b99dfdf41db1eb554c2c2c7800f65", size = 7696837, upload-time = "2026-02-06T09:56:40.173Z" },
+ { url = "https://files.pythonhosted.org/packages/73/77/7382241caf88729b106e49e7d18e3116216c778e6a7e833826eb96de22f7/grpcio-1.78.0-cp314-cp314-win32.whl", hash = "sha256:57bab6deef2f4f1ca76cc04565df38dc5713ae6c17de690721bdf30cb1e0545c", size = 4142439, upload-time = "2026-02-06T09:56:43.258Z" },
+ { url = "https://files.pythonhosted.org/packages/48/b2/b096ccce418882fbfda4f7496f9357aaa9a5af1896a9a7f60d9f2b275a06/grpcio-1.78.0-cp314-cp314-win_amd64.whl", hash = "sha256:dce09d6116df20a96acfdbf85e4866258c3758180e8c49845d6ba8248b6d0bbb", size = 4929852, upload-time = "2026-02-06T09:56:45.885Z" },
+]
+
+[[package]]
+name = "h11"
+version = "0.16.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
+]
+
+[[package]]
+name = "hf-xet"
+version = "1.3.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/8b/cb/9bb543bd987ffa1ee48202cc96a756951b734b79a542335c566148ade36c/hf_xet-1.3.2.tar.gz", hash = "sha256:e130ee08984783d12717444e538587fa2119385e5bd8fc2bb9f930419b73a7af", size = 643646, upload-time = "2026-02-27T17:26:08.051Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/49/75/462285971954269432aad2e7938c5c7ff9ec7d60129cec542ab37121e3d6/hf_xet-1.3.2-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:335a8f36c55fd35a92d0062f4e9201b4015057e62747b7e7001ffb203c0ee1d2", size = 3761019, upload-time = "2026-02-27T17:25:49.441Z" },
+ { url = "https://files.pythonhosted.org/packages/35/56/987b0537ddaf88e17192ea09afa8eca853e55f39a4721578be436f8409df/hf_xet-1.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c1ae4d3a716afc774e66922f3cac8206bfa707db13f6a7e62dfff74bfc95c9a8", size = 3521565, upload-time = "2026-02-27T17:25:47.469Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/5c/7e4a33a3d689f77761156cc34558047569e54af92e4d15a8f493229f6767/hf_xet-1.3.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d6dbdf231efac0b9b39adcf12a07f0c030498f9212a18e8c50224d0e84ab803d", size = 4176494, upload-time = "2026-02-27T17:25:40.247Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/b3/71e856bf9d9a69b3931837e8bf22e095775f268c8edcd4a9e8c355f92484/hf_xet-1.3.2-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:c1980abfb68ecf6c1c7983379ed7b1e2b49a1aaf1a5aca9acc7d48e5e2e0a961", size = 3955601, upload-time = "2026-02-27T17:25:38.376Z" },
+ { url = "https://files.pythonhosted.org/packages/63/d7/aecf97b3f0a981600a67ff4db15e2d433389d698a284bb0ea5d8fcdd6f7f/hf_xet-1.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:1c88fbd90ad0d27c46b77a445f0a436ebaa94e14965c581123b68b1c52f5fd30", size = 4154770, upload-time = "2026-02-27T17:25:56.756Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/e1/3af961f71a40e09bf5ee909842127b6b00f5ab4ee3817599dc0771b79893/hf_xet-1.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:35b855024ca37f2dd113ac1c08993e997fbe167b9d61f9ef66d3d4f84015e508", size = 4394161, upload-time = "2026-02-27T17:25:58.111Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/c3/859509bade9178e21b8b1db867b8e10e9f817ab9ac1de77cb9f461ced765/hf_xet-1.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:31612ba0629046e425ba50375685a2586e11fb9144270ebabd75878c3eaf6378", size = 3637377, upload-time = "2026-02-27T17:26:10.611Z" },
+ { url = "https://files.pythonhosted.org/packages/05/7f/724cfbef4da92d577b71f68bf832961c8919f36c60d28d289a9fc9d024d4/hf_xet-1.3.2-cp313-cp313t-win_arm64.whl", hash = "sha256:433c77c9f4e132b562f37d66c9b22c05b5479f243a1f06a120c1c06ce8b1502a", size = 3497875, upload-time = "2026-02-27T17:26:09.034Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/75/9d54c1ae1d05fb704f977eca1671747babf1957f19f38ae75c5933bc2dc1/hf_xet-1.3.2-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:c34e2c7aefad15792d57067c1c89b2b02c1bbaeabd7f8456ae3d07b4bbaf4094", size = 3761076, upload-time = "2026-02-27T17:25:55.42Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/8a/08a24b6c6f52b5d26848c16e4b6d790bb810d1bf62c3505bed179f7032d3/hf_xet-1.3.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:4bc995d6c41992831f762096020dc14a65fdf3963f86ffed580b596d04de32e3", size = 3521745, upload-time = "2026-02-27T17:25:54.217Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/db/a75cf400dd8a1a8acf226a12955ff6ee999f272dfc0505bafd8079a61267/hf_xet-1.3.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:959083c89dee30f7d6f890b36cdadda823386c4de63b1a30384a75bfd2ae995d", size = 4176301, upload-time = "2026-02-27T17:25:46.044Z" },
+ { url = "https://files.pythonhosted.org/packages/01/40/6c4c798ffdd83e740dd3925c4e47793b07442a9efa3bc3866ba141a82365/hf_xet-1.3.2-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:cfa760888633b08c01b398d212ce7e8c0d7adac6c86e4b20dfb2397d8acd78ee", size = 3955437, upload-time = "2026-02-27T17:25:44.703Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/09/9a3aa7c5f07d3e5cc57bb750d12a124ffa72c273a87164bd848f9ac5cc14/hf_xet-1.3.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3155a02e083aa21fd733a7485c7c36025e49d5975c8d6bda0453d224dd0b0ac4", size = 4154535, upload-time = "2026-02-27T17:26:05.207Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/e0/831f7fa6d90cb47a230bc23284b502c700e1483bbe459437b3844cdc0776/hf_xet-1.3.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:91b1dc03c31cbf733d35dc03df7c5353686233d86af045e716f1e0ea4a2673cf", size = 4393891, upload-time = "2026-02-27T17:26:06.607Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/96/6ed472fdce7f8b70f5da6e3f05be76816a610063003bfd6d9cea0bbb58a3/hf_xet-1.3.2-cp314-cp314t-win_amd64.whl", hash = "sha256:211f30098512d95e85ad03ae63bd7dd2c4df476558a5095d09f9e38e78cbf674", size = 3637583, upload-time = "2026-02-27T17:26:17.349Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/e8/a069edc4570b3f8e123c0b80fadc94530f3d7b01394e1fc1bb223339366c/hf_xet-1.3.2-cp314-cp314t-win_arm64.whl", hash = "sha256:4a6817c41de7c48ed9270da0b02849347e089c5ece9a0e72ae4f4b3a57617f82", size = 3497977, upload-time = "2026-02-27T17:26:14.966Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/28/dbb024e2e3907f6f3052847ca7d1a2f7a3972fafcd53ff79018977fcb3e4/hf_xet-1.3.2-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:f93b7595f1d8fefddfede775c18b5c9256757824f7f6832930b49858483cd56f", size = 3763961, upload-time = "2026-02-27T17:25:52.537Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/71/b99aed3823c9d1795e4865cf437d651097356a3f38c7d5877e4ac544b8e4/hf_xet-1.3.2-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:a85d3d43743174393afe27835bde0cd146e652b5fcfdbcd624602daef2ef3259", size = 3526171, upload-time = "2026-02-27T17:25:50.968Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/ca/907890ce6ef5598b5920514f255ed0a65f558f820515b18db75a51b2f878/hf_xet-1.3.2-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7c2a054a97c44e136b1f7f5a78f12b3efffdf2eed3abc6746fc5ea4b39511633", size = 4180750, upload-time = "2026-02-27T17:25:43.125Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/ad/bc7f41f87173d51d0bce497b171c4ee0cbde1eed2d7b4216db5d0ada9f50/hf_xet-1.3.2-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:06b724a361f670ae557836e57801b82c75b534812e351a87a2c739f77d1e0635", size = 3961035, upload-time = "2026-02-27T17:25:41.837Z" },
+ { url = "https://files.pythonhosted.org/packages/73/38/600f4dda40c4a33133404d9fe644f1d35ff2d9babb4d0435c646c63dd107/hf_xet-1.3.2-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:305f5489d7241a47e0458ef49334be02411d1d0f480846363c1c8084ed9916f7", size = 4161378, upload-time = "2026-02-27T17:26:00.365Z" },
+ { url = "https://files.pythonhosted.org/packages/00/b3/7bc1ff91d1ac18420b7ad1e169b618b27c00001b96310a89f8a9294fe509/hf_xet-1.3.2-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:06cdbde243c85f39a63b28e9034321399c507bcd5e7befdd17ed2ccc06dfe14e", size = 4398020, upload-time = "2026-02-27T17:26:03.977Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/0b/99bfd948a3ed3620ab709276df3ad3710dcea61976918cce8706502927af/hf_xet-1.3.2-cp37-abi3-win_amd64.whl", hash = "sha256:9298b47cce6037b7045ae41482e703c471ce36b52e73e49f71226d2e8e5685a1", size = 3641624, upload-time = "2026-02-27T17:26:13.542Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/02/9a6e4ca1f3f73a164c0cd48e41b3cc56585dcc37e809250de443d673266f/hf_xet-1.3.2-cp37-abi3-win_arm64.whl", hash = "sha256:83d8ec273136171431833a6957e8f3af496bee227a0fe47c7b8b39c106d1749a", size = 3503976, upload-time = "2026-02-27T17:26:12.123Z" },
+]
+
+[[package]]
+name = "httpcore"
+version = "1.0.9"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "certifi" },
+ { name = "h11" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" },
+]
+
+[[package]]
+name = "httptools"
+version = "0.7.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/b5/46/120a669232c7bdedb9d52d4aeae7e6c7dfe151e99dc70802e2fc7a5e1993/httptools-0.7.1.tar.gz", hash = "sha256:abd72556974f8e7c74a259655924a717a2365b236c882c3f6f8a45fe94703ac9", size = 258961, upload-time = "2025-10-10T03:55:08.559Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/53/7f/403e5d787dc4942316e515e949b0c8a013d84078a915910e9f391ba9b3ed/httptools-0.7.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:38e0c83a2ea9746ebbd643bdfb521b9aa4a91703e2cd705c20443405d2fd16a5", size = 206280, upload-time = "2025-10-10T03:54:39.274Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/0d/7f3fd28e2ce311ccc998c388dd1c53b18120fda3b70ebb022b135dc9839b/httptools-0.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f25bbaf1235e27704f1a7b86cd3304eabc04f569c828101d94a0e605ef7205a5", size = 110004, upload-time = "2025-10-10T03:54:40.403Z" },
+ { url = "https://files.pythonhosted.org/packages/84/a6/b3965e1e146ef5762870bbe76117876ceba51a201e18cc31f5703e454596/httptools-0.7.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2c15f37ef679ab9ecc06bfc4e6e8628c32a8e4b305459de7cf6785acd57e4d03", size = 517655, upload-time = "2025-10-10T03:54:41.347Z" },
+ { url = "https://files.pythonhosted.org/packages/11/7d/71fee6f1844e6fa378f2eddde6c3e41ce3a1fb4b2d81118dd544e3441ec0/httptools-0.7.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7fe6e96090df46b36ccfaf746f03034e5ab723162bc51b0a4cf58305324036f2", size = 511440, upload-time = "2025-10-10T03:54:42.452Z" },
+ { url = "https://files.pythonhosted.org/packages/22/a5/079d216712a4f3ffa24af4a0381b108aa9c45b7a5cc6eb141f81726b1823/httptools-0.7.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f72fdbae2dbc6e68b8239defb48e6a5937b12218e6ffc2c7846cc37befa84362", size = 495186, upload-time = "2025-10-10T03:54:43.937Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/9e/025ad7b65278745dee3bd0ebf9314934c4592560878308a6121f7f812084/httptools-0.7.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e99c7b90a29fd82fea9ef57943d501a16f3404d7b9ee81799d41639bdaae412c", size = 499192, upload-time = "2025-10-10T03:54:45.003Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/de/40a8f202b987d43afc4d54689600ff03ce65680ede2f31df348d7f368b8f/httptools-0.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:3e14f530fefa7499334a79b0cf7e7cd2992870eb893526fb097d51b4f2d0f321", size = 86694, upload-time = "2025-10-10T03:54:45.923Z" },
+ { url = "https://files.pythonhosted.org/packages/09/8f/c77b1fcbfd262d422f12da02feb0d218fa228d52485b77b953832105bb90/httptools-0.7.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6babce6cfa2a99545c60bfef8bee0cc0545413cb0018f617c8059a30ad985de3", size = 202889, upload-time = "2025-10-10T03:54:47.089Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/1a/22887f53602feaa066354867bc49a68fc295c2293433177ee90870a7d517/httptools-0.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:601b7628de7504077dd3dcb3791c6b8694bbd967148a6d1f01806509254fb1ca", size = 108180, upload-time = "2025-10-10T03:54:48.052Z" },
+ { url = "https://files.pythonhosted.org/packages/32/6a/6aaa91937f0010d288d3d124ca2946d48d60c3a5ee7ca62afe870e3ea011/httptools-0.7.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:04c6c0e6c5fb0739c5b8a9eb046d298650a0ff38cf42537fc372b28dc7e4472c", size = 478596, upload-time = "2025-10-10T03:54:48.919Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/70/023d7ce117993107be88d2cbca566a7c1323ccbaf0af7eabf2064fe356f6/httptools-0.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:69d4f9705c405ae3ee83d6a12283dc9feba8cc6aaec671b412917e644ab4fa66", size = 473268, upload-time = "2025-10-10T03:54:49.993Z" },
+ { url = "https://files.pythonhosted.org/packages/32/4d/9dd616c38da088e3f436e9a616e1d0cc66544b8cdac405cc4e81c8679fc7/httptools-0.7.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:44c8f4347d4b31269c8a9205d8a5ee2df5322b09bbbd30f8f862185bb6b05346", size = 455517, upload-time = "2025-10-10T03:54:51.066Z" },
+ { url = "https://files.pythonhosted.org/packages/1d/3a/a6c595c310b7df958e739aae88724e24f9246a514d909547778d776799be/httptools-0.7.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:465275d76db4d554918aba40bf1cbebe324670f3dfc979eaffaa5d108e2ed650", size = 458337, upload-time = "2025-10-10T03:54:52.196Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/82/88e8d6d2c51edc1cc391b6e044c6c435b6aebe97b1abc33db1b0b24cd582/httptools-0.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:322d00c2068d125bd570f7bf78b2d367dad02b919d8581d7476d8b75b294e3e6", size = 85743, upload-time = "2025-10-10T03:54:53.448Z" },
+ { url = "https://files.pythonhosted.org/packages/34/50/9d095fcbb6de2d523e027a2f304d4551855c2f46e0b82befd718b8b20056/httptools-0.7.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:c08fe65728b8d70b6923ce31e3956f859d5e1e8548e6f22ec520a962c6757270", size = 203619, upload-time = "2025-10-10T03:54:54.321Z" },
+ { url = "https://files.pythonhosted.org/packages/07/f0/89720dc5139ae54b03f861b5e2c55a37dba9a5da7d51e1e824a1f343627f/httptools-0.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7aea2e3c3953521c3c51106ee11487a910d45586e351202474d45472db7d72d3", size = 108714, upload-time = "2025-10-10T03:54:55.163Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/cb/eea88506f191fb552c11787c23f9a405f4c7b0c5799bf73f2249cd4f5228/httptools-0.7.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0e68b8582f4ea9166be62926077a3334064d422cf08ab87d8b74664f8e9058e1", size = 472909, upload-time = "2025-10-10T03:54:56.056Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/4a/a548bdfae6369c0d078bab5769f7b66f17f1bfaa6fa28f81d6be6959066b/httptools-0.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:df091cf961a3be783d6aebae963cc9b71e00d57fa6f149025075217bc6a55a7b", size = 470831, upload-time = "2025-10-10T03:54:57.219Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/31/14df99e1c43bd132eec921c2e7e11cda7852f65619bc0fc5bdc2d0cb126c/httptools-0.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f084813239e1eb403ddacd06a30de3d3e09a9b76e7894dcda2b22f8a726e9c60", size = 452631, upload-time = "2025-10-10T03:54:58.219Z" },
+ { url = "https://files.pythonhosted.org/packages/22/d2/b7e131f7be8d854d48cb6d048113c30f9a46dca0c9a8b08fcb3fcd588cdc/httptools-0.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7347714368fb2b335e9063bc2b96f2f87a9ceffcd9758ac295f8bbcd3ffbc0ca", size = 452910, upload-time = "2025-10-10T03:54:59.366Z" },
+ { url = "https://files.pythonhosted.org/packages/53/cf/878f3b91e4e6e011eff6d1fa9ca39f7eb17d19c9d7971b04873734112f30/httptools-0.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:cfabda2a5bb85aa2a904ce06d974a3f30fb36cc63d7feaddec05d2050acede96", size = 88205, upload-time = "2025-10-10T03:55:00.389Z" },
+]
+
+[[package]]
+name = "httpx"
+version = "0.28.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "anyio" },
+ { name = "certifi" },
+ { name = "httpcore" },
+ { name = "idna" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" },
+]
+
+[[package]]
+name = "huggingface-hub"
+version = "1.6.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "filelock" },
+ { name = "fsspec" },
+ { name = "hf-xet", marker = "platform_machine == 'AMD64' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" },
+ { name = "httpx" },
+ { name = "packaging" },
+ { name = "pyyaml" },
+ { name = "tqdm" },
+ { name = "typer" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/d5/7a/304cec37112382c4fe29a43bcb0d5891f922785d18745883d2aa4eb74e4b/huggingface_hub-1.6.0.tar.gz", hash = "sha256:d931ddad8ba8dfc1e816bf254810eb6f38e5c32f60d4184b5885662a3b167325", size = 717071, upload-time = "2026-03-06T14:19:18.524Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/92/e3/e3a44f54c8e2f28983fcf07f13d4260b37bd6a0d3a081041bc60b91d230e/huggingface_hub-1.6.0-py3-none-any.whl", hash = "sha256:ef40e2d5cb85e48b2c067020fa5142168342d5108a1b267478ed384ecbf18961", size = 612874, upload-time = "2026-03-06T14:19:16.844Z" },
+]
+
+[[package]]
+name = "idna"
+version = "3.11"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" },
+]
+
+[[package]]
+name = "importlib-metadata"
+version = "8.7.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "zipp" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/f3/49/3b30cad09e7771a4982d9975a8cbf64f00d4a1ececb53297f1d9a7be1b10/importlib_metadata-8.7.1.tar.gz", hash = "sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb", size = 57107, upload-time = "2025-12-21T10:00:19.278Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151", size = 27865, upload-time = "2025-12-21T10:00:18.329Z" },
+]
+
+[[package]]
+name = "jinja2"
+version = "3.1.6"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "markupsafe" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" },
+]
+
+[[package]]
+name = "joblib"
+version = "1.5.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/41/f2/d34e8b3a08a9cc79a50b2208a93dce981fe615b64d5a4d4abee421d898df/joblib-1.5.3.tar.gz", hash = "sha256:8561a3269e6801106863fd0d6d84bb737be9e7631e33aaed3fb9ce5953688da3", size = 331603, upload-time = "2025-12-15T08:41:46.427Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl", hash = "sha256:5fc3c5039fc5ca8c0276333a188bbd59d6b7ab37fe6632daa76bc7f9ec18e713", size = 309071, upload-time = "2025-12-15T08:41:44.973Z" },
+]
+
+[[package]]
+name = "jsonschema"
+version = "4.26.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "attrs" },
+ { name = "jsonschema-specifications" },
+ { name = "referencing" },
+ { name = "rpds-py" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/b3/fc/e067678238fa451312d4c62bf6e6cf5ec56375422aee02f9cb5f909b3047/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326", size = 366583, upload-time = "2026-01-07T13:41:07.246Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce", size = 90630, upload-time = "2026-01-07T13:41:05.306Z" },
+]
+
+[[package]]
+name = "jsonschema-specifications"
+version = "2025.9.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "referencing" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" },
+]
+
+[[package]]
+name = "markdown-it-py"
+version = "4.0.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "mdurl" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" },
+]
+
+[[package]]
+name = "markupsafe"
+version = "3.0.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" },
+ { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" },
+ { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" },
+ { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" },
+ { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" },
+ { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" },
+ { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" },
+ { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" },
+ { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" },
+ { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" },
+ { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" },
+ { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" },
+ { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" },
+ { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" },
+ { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" },
+ { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" },
+ { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" },
+ { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" },
+ { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" },
+ { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" },
+ { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" },
+ { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" },
+ { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" },
+ { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" },
+ { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" },
+]
+
+[[package]]
+name = "mdurl"
+version = "0.1.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
+]
+
+[[package]]
+name = "mpmath"
+version = "1.3.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" },
+]
+
+[[package]]
+name = "msgpack"
+version = "1.1.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/4d/f2/bfb55a6236ed8725a96b0aa3acbd0ec17588e6a2c3b62a93eb513ed8783f/msgpack-1.1.2.tar.gz", hash = "sha256:3b60763c1373dd60f398488069bcdc703cd08a711477b5d480eecc9f9626f47e", size = 173581, upload-time = "2025-10-08T09:15:56.596Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ad/bd/8b0d01c756203fbab65d265859749860682ccd2a59594609aeec3a144efa/msgpack-1.1.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:70a0dff9d1f8da25179ffcf880e10cf1aad55fdb63cd59c9a49a1b82290062aa", size = 81939, upload-time = "2025-10-08T09:15:01.472Z" },
+ { url = "https://files.pythonhosted.org/packages/34/68/ba4f155f793a74c1483d4bdef136e1023f7bcba557f0db4ef3db3c665cf1/msgpack-1.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:446abdd8b94b55c800ac34b102dffd2f6aa0ce643c55dfc017ad89347db3dbdb", size = 85064, upload-time = "2025-10-08T09:15:03.764Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/60/a064b0345fc36c4c3d2c743c82d9100c40388d77f0b48b2f04d6041dbec1/msgpack-1.1.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c63eea553c69ab05b6747901b97d620bb2a690633c77f23feb0c6a947a8a7b8f", size = 417131, upload-time = "2025-10-08T09:15:05.136Z" },
+ { url = "https://files.pythonhosted.org/packages/65/92/a5100f7185a800a5d29f8d14041f61475b9de465ffcc0f3b9fba606e4505/msgpack-1.1.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:372839311ccf6bdaf39b00b61288e0557916c3729529b301c52c2d88842add42", size = 427556, upload-time = "2025-10-08T09:15:06.837Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/87/ffe21d1bf7d9991354ad93949286f643b2bb6ddbeab66373922b44c3b8cc/msgpack-1.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2929af52106ca73fcb28576218476ffbb531a036c2adbcf54a3664de124303e9", size = 404920, upload-time = "2025-10-08T09:15:08.179Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/41/8543ed2b8604f7c0d89ce066f42007faac1eaa7d79a81555f206a5cdb889/msgpack-1.1.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:be52a8fc79e45b0364210eef5234a7cf8d330836d0a64dfbb878efa903d84620", size = 415013, upload-time = "2025-10-08T09:15:09.83Z" },
+ { url = "https://files.pythonhosted.org/packages/41/0d/2ddfaa8b7e1cee6c490d46cb0a39742b19e2481600a7a0e96537e9c22f43/msgpack-1.1.2-cp312-cp312-win32.whl", hash = "sha256:1fff3d825d7859ac888b0fbda39a42d59193543920eda9d9bea44d958a878029", size = 65096, upload-time = "2025-10-08T09:15:11.11Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/ec/d431eb7941fb55a31dd6ca3404d41fbb52d99172df2e7707754488390910/msgpack-1.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:1de460f0403172cff81169a30b9a92b260cb809c4cb7e2fc79ae8d0510c78b6b", size = 72708, upload-time = "2025-10-08T09:15:12.554Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/31/5b1a1f70eb0e87d1678e9624908f86317787b536060641d6798e3cf70ace/msgpack-1.1.2-cp312-cp312-win_arm64.whl", hash = "sha256:be5980f3ee0e6bd44f3a9e9dea01054f175b50c3e6cdb692bc9424c0bbb8bf69", size = 64119, upload-time = "2025-10-08T09:15:13.589Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/31/b46518ecc604d7edf3a4f94cb3bf021fc62aa301f0cb849936968164ef23/msgpack-1.1.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4efd7b5979ccb539c221a4c4e16aac1a533efc97f3b759bb5a5ac9f6d10383bf", size = 81212, upload-time = "2025-10-08T09:15:14.552Z" },
+ { url = "https://files.pythonhosted.org/packages/92/dc/c385f38f2c2433333345a82926c6bfa5ecfff3ef787201614317b58dd8be/msgpack-1.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:42eefe2c3e2af97ed470eec850facbe1b5ad1d6eacdbadc42ec98e7dcf68b4b7", size = 84315, upload-time = "2025-10-08T09:15:15.543Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/68/93180dce57f684a61a88a45ed13047558ded2be46f03acb8dec6d7c513af/msgpack-1.1.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1fdf7d83102bf09e7ce3357de96c59b627395352a4024f6e2458501f158bf999", size = 412721, upload-time = "2025-10-08T09:15:16.567Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/ba/459f18c16f2b3fc1a1ca871f72f07d70c07bf768ad0a507a698b8052ac58/msgpack-1.1.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fac4be746328f90caa3cd4bc67e6fe36ca2bf61d5c6eb6d895b6527e3f05071e", size = 424657, upload-time = "2025-10-08T09:15:17.825Z" },
+ { url = "https://files.pythonhosted.org/packages/38/f8/4398c46863b093252fe67368b44edc6c13b17f4e6b0e4929dbf0bdb13f23/msgpack-1.1.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fffee09044073e69f2bad787071aeec727183e7580443dfeb8556cbf1978d162", size = 402668, upload-time = "2025-10-08T09:15:19.003Z" },
+ { url = "https://files.pythonhosted.org/packages/28/ce/698c1eff75626e4124b4d78e21cca0b4cc90043afb80a507626ea354ab52/msgpack-1.1.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5928604de9b032bc17f5099496417f113c45bc6bc21b5c6920caf34b3c428794", size = 419040, upload-time = "2025-10-08T09:15:20.183Z" },
+ { url = "https://files.pythonhosted.org/packages/67/32/f3cd1667028424fa7001d82e10ee35386eea1408b93d399b09fb0aa7875f/msgpack-1.1.2-cp313-cp313-win32.whl", hash = "sha256:a7787d353595c7c7e145e2331abf8b7ff1e6673a6b974ded96e6d4ec09f00c8c", size = 65037, upload-time = "2025-10-08T09:15:21.416Z" },
+ { url = "https://files.pythonhosted.org/packages/74/07/1ed8277f8653c40ebc65985180b007879f6a836c525b3885dcc6448ae6cb/msgpack-1.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:a465f0dceb8e13a487e54c07d04ae3ba131c7c5b95e2612596eafde1dccf64a9", size = 72631, upload-time = "2025-10-08T09:15:22.431Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/db/0314e4e2db56ebcf450f277904ffd84a7988b9e5da8d0d61ab2d057df2b6/msgpack-1.1.2-cp313-cp313-win_arm64.whl", hash = "sha256:e69b39f8c0aa5ec24b57737ebee40be647035158f14ed4b40e6f150077e21a84", size = 64118, upload-time = "2025-10-08T09:15:23.402Z" },
+ { url = "https://files.pythonhosted.org/packages/22/71/201105712d0a2ff07b7873ed3c220292fb2ea5120603c00c4b634bcdafb3/msgpack-1.1.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e23ce8d5f7aa6ea6d2a2b326b4ba46c985dbb204523759984430db7114f8aa00", size = 81127, upload-time = "2025-10-08T09:15:24.408Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/9f/38ff9e57a2eade7bf9dfee5eae17f39fc0e998658050279cbb14d97d36d9/msgpack-1.1.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6c15b7d74c939ebe620dd8e559384be806204d73b4f9356320632d783d1f7939", size = 84981, upload-time = "2025-10-08T09:15:25.812Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/a9/3536e385167b88c2cc8f4424c49e28d49a6fc35206d4a8060f136e71f94c/msgpack-1.1.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:99e2cb7b9031568a2a5c73aa077180f93dd2e95b4f8d3b8e14a73ae94a9e667e", size = 411885, upload-time = "2025-10-08T09:15:27.22Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/40/dc34d1a8d5f1e51fc64640b62b191684da52ca469da9cd74e84936ffa4a6/msgpack-1.1.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:180759d89a057eab503cf62eeec0aa61c4ea1200dee709f3a8e9397dbb3b6931", size = 419658, upload-time = "2025-10-08T09:15:28.4Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/ef/2b92e286366500a09a67e03496ee8b8ba00562797a52f3c117aa2b29514b/msgpack-1.1.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:04fb995247a6e83830b62f0b07bf36540c213f6eac8e851166d8d86d83cbd014", size = 403290, upload-time = "2025-10-08T09:15:29.764Z" },
+ { url = "https://files.pythonhosted.org/packages/78/90/e0ea7990abea5764e4655b8177aa7c63cdfa89945b6e7641055800f6c16b/msgpack-1.1.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8e22ab046fa7ede9e36eeb4cfad44d46450f37bb05d5ec482b02868f451c95e2", size = 415234, upload-time = "2025-10-08T09:15:31.022Z" },
+ { url = "https://files.pythonhosted.org/packages/72/4e/9390aed5db983a2310818cd7d3ec0aecad45e1f7007e0cda79c79507bb0d/msgpack-1.1.2-cp314-cp314-win32.whl", hash = "sha256:80a0ff7d4abf5fecb995fcf235d4064b9a9a8a40a3ab80999e6ac1e30b702717", size = 66391, upload-time = "2025-10-08T09:15:32.265Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/f1/abd09c2ae91228c5f3998dbd7f41353def9eac64253de3c8105efa2082f7/msgpack-1.1.2-cp314-cp314-win_amd64.whl", hash = "sha256:9ade919fac6a3e7260b7f64cea89df6bec59104987cbea34d34a2fa15d74310b", size = 73787, upload-time = "2025-10-08T09:15:33.219Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/b0/9d9f667ab48b16ad4115c1935d94023b82b3198064cb84a123e97f7466c1/msgpack-1.1.2-cp314-cp314-win_arm64.whl", hash = "sha256:59415c6076b1e30e563eb732e23b994a61c159cec44deaf584e5cc1dd662f2af", size = 66453, upload-time = "2025-10-08T09:15:34.225Z" },
+ { url = "https://files.pythonhosted.org/packages/16/67/93f80545eb1792b61a217fa7f06d5e5cb9e0055bed867f43e2b8e012e137/msgpack-1.1.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:897c478140877e5307760b0ea66e0932738879e7aa68144d9b78ea4c8302a84a", size = 85264, upload-time = "2025-10-08T09:15:35.61Z" },
+ { url = "https://files.pythonhosted.org/packages/87/1c/33c8a24959cf193966ef11a6f6a2995a65eb066bd681fd085afd519a57ce/msgpack-1.1.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a668204fa43e6d02f89dbe79a30b0d67238d9ec4c5bd8a940fc3a004a47b721b", size = 89076, upload-time = "2025-10-08T09:15:36.619Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/6b/62e85ff7193663fbea5c0254ef32f0c77134b4059f8da89b958beb7696f3/msgpack-1.1.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5559d03930d3aa0f3aacb4c42c776af1a2ace2611871c84a75afe436695e6245", size = 435242, upload-time = "2025-10-08T09:15:37.647Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/47/5c74ecb4cc277cf09f64e913947871682ffa82b3b93c8dad68083112f412/msgpack-1.1.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:70c5a7a9fea7f036b716191c29047374c10721c389c21e9ffafad04df8c52c90", size = 432509, upload-time = "2025-10-08T09:15:38.794Z" },
+ { url = "https://files.pythonhosted.org/packages/24/a4/e98ccdb56dc4e98c929a3f150de1799831c0a800583cde9fa022fa90602d/msgpack-1.1.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f2cb069d8b981abc72b41aea1c580ce92d57c673ec61af4c500153a626cb9e20", size = 415957, upload-time = "2025-10-08T09:15:40.238Z" },
+ { url = "https://files.pythonhosted.org/packages/da/28/6951f7fb67bc0a4e184a6b38ab71a92d9ba58080b27a77d3e2fb0be5998f/msgpack-1.1.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d62ce1f483f355f61adb5433ebfd8868c5f078d1a52d042b0a998682b4fa8c27", size = 422910, upload-time = "2025-10-08T09:15:41.505Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/03/42106dcded51f0a0b5284d3ce30a671e7bd3f7318d122b2ead66ad289fed/msgpack-1.1.2-cp314-cp314t-win32.whl", hash = "sha256:1d1418482b1ee984625d88aa9585db570180c286d942da463533b238b98b812b", size = 75197, upload-time = "2025-10-08T09:15:42.954Z" },
+ { url = "https://files.pythonhosted.org/packages/15/86/d0071e94987f8db59d4eeb386ddc64d0bb9b10820a8d82bcd3e53eeb2da6/msgpack-1.1.2-cp314-cp314t-win_amd64.whl", hash = "sha256:5a46bf7e831d09470ad92dff02b8b1ac92175ca36b087f904a0519857c6be3ff", size = 85772, upload-time = "2025-10-08T09:15:43.954Z" },
+ { url = "https://files.pythonhosted.org/packages/81/f2/08ace4142eb281c12701fc3b93a10795e4d4dc7f753911d836675050f886/msgpack-1.1.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d99ef64f349d5ec3293688e91486c5fdb925ed03807f64d98d205d2713c60b46", size = 70868, upload-time = "2025-10-08T09:15:44.959Z" },
+]
+
+[[package]]
+name = "multidict"
+version = "6.7.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/1a/c2/c2d94cbe6ac1753f3fc980da97b3d930efe1da3af3c9f5125354436c073d/multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d", size = 102010, upload-time = "2026-01-26T02:46:45.979Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/8d/9c/f20e0e2cf80e4b2e4b1c365bf5fe104ee633c751a724246262db8f1a0b13/multidict-6.7.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a90f75c956e32891a4eda3639ce6dd86e87105271f43d43442a3aedf3cddf172", size = 76893, upload-time = "2026-01-26T02:43:52.754Z" },
+ { url = "https://files.pythonhosted.org/packages/fe/cf/18ef143a81610136d3da8193da9d80bfe1cb548a1e2d1c775f26b23d024a/multidict-6.7.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fccb473e87eaa1382689053e4a4618e7ba7b9b9b8d6adf2027ee474597128cd", size = 45456, upload-time = "2026-01-26T02:43:53.893Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/65/1caac9d4cd32e8433908683446eebc953e82d22b03d10d41a5f0fefe991b/multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0fa96985700739c4c7853a43c0b3e169360d6855780021bfc6d0f1ce7c123e7", size = 43872, upload-time = "2026-01-26T02:43:55.041Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/3b/d6bd75dc4f3ff7c73766e04e705b00ed6dbbaccf670d9e05a12b006f5a21/multidict-6.7.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cb2a55f408c3043e42b40cc8eecd575afa27b7e0b956dfb190de0f8499a57a53", size = 251018, upload-time = "2026-01-26T02:43:56.198Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/80/c959c5933adedb9ac15152e4067c702a808ea183a8b64cf8f31af8ad3155/multidict-6.7.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb0ce7b2a32d09892b3dd6cc44877a0d02a33241fafca5f25c8b6b62374f8b75", size = 258883, upload-time = "2026-01-26T02:43:57.499Z" },
+ { url = "https://files.pythonhosted.org/packages/86/85/7ed40adafea3d4f1c8b916e3b5cc3a8e07dfcdcb9cd72800f4ed3ca1b387/multidict-6.7.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c3a32d23520ee37bf327d1e1a656fec76a2edd5c038bf43eddfa0572ec49c60b", size = 242413, upload-time = "2026-01-26T02:43:58.755Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/57/b8565ff533e48595503c785f8361ff9a4fde4d67de25c207cd0ba3befd03/multidict-6.7.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9c90fed18bffc0189ba814749fdcc102b536e83a9f738a9003e569acd540a733", size = 268404, upload-time = "2026-01-26T02:44:00.216Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/50/9810c5c29350f7258180dfdcb2e52783a0632862eb334c4896ac717cebcb/multidict-6.7.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:da62917e6076f512daccfbbde27f46fed1c98fee202f0559adec8ee0de67f71a", size = 269456, upload-time = "2026-01-26T02:44:02.202Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/8d/5e5be3ced1d12966fefb5c4ea3b2a5b480afcea36406559442c6e31d4a48/multidict-6.7.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bfde23ef6ed9db7eaee6c37dcec08524cb43903c60b285b172b6c094711b3961", size = 256322, upload-time = "2026-01-26T02:44:03.56Z" },
+ { url = "https://files.pythonhosted.org/packages/31/6e/d8a26d81ac166a5592782d208dd90dfdc0a7a218adaa52b45a672b46c122/multidict-6.7.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3758692429e4e32f1ba0df23219cd0b4fc0a52f476726fff9337d1a57676a582", size = 253955, upload-time = "2026-01-26T02:44:04.845Z" },
+ { url = "https://files.pythonhosted.org/packages/59/4c/7c672c8aad41534ba619bcd4ade7a0dc87ed6b8b5c06149b85d3dd03f0cd/multidict-6.7.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:398c1478926eca669f2fd6a5856b6de9c0acf23a2cb59a14c0ba5844fa38077e", size = 251254, upload-time = "2026-01-26T02:44:06.133Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/bd/84c24de512cbafbdbc39439f74e967f19570ce7924e3007174a29c348916/multidict-6.7.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c102791b1c4f3ab36ce4101154549105a53dc828f016356b3e3bcae2e3a039d3", size = 252059, upload-time = "2026-01-26T02:44:07.518Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/ba/f5449385510825b73d01c2d4087bf6d2fccc20a2d42ac34df93191d3dd03/multidict-6.7.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a088b62bd733e2ad12c50dad01b7d0166c30287c166e137433d3b410add807a6", size = 263588, upload-time = "2026-01-26T02:44:09.382Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/11/afc7c677f68f75c84a69fe37184f0f82fce13ce4b92f49f3db280b7e92b3/multidict-6.7.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3d51ff4785d58d3f6c91bdbffcb5e1f7ddfda557727043aa20d20ec4f65e324a", size = 259642, upload-time = "2026-01-26T02:44:10.73Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/17/ebb9644da78c4ab36403739e0e6e0e30ebb135b9caf3440825001a0bddcb/multidict-6.7.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc5907494fccf3e7d3f94f95c91d6336b092b5fc83811720fae5e2765890dfba", size = 251377, upload-time = "2026-01-26T02:44:12.042Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/a4/840f5b97339e27846c46307f2530a2805d9d537d8b8bd416af031cad7fa0/multidict-6.7.1-cp312-cp312-win32.whl", hash = "sha256:28ca5ce2fd9716631133d0e9a9b9a745ad7f60bac2bccafb56aa380fc0b6c511", size = 41887, upload-time = "2026-01-26T02:44:14.245Z" },
+ { url = "https://files.pythonhosted.org/packages/80/31/0b2517913687895f5904325c2069d6a3b78f66cc641a86a2baf75a05dcbb/multidict-6.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcee94dfbd638784645b066074b338bc9cc155d4b4bffa4adce1615c5a426c19", size = 46053, upload-time = "2026-01-26T02:44:15.371Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/5b/aba28e4ee4006ae4c7df8d327d31025d760ffa992ea23812a601d226e682/multidict-6.7.1-cp312-cp312-win_arm64.whl", hash = "sha256:ba0a9fb644d0c1a2194cf7ffb043bd852cea63a57f66fbd33959f7dae18517bf", size = 43307, upload-time = "2026-01-26T02:44:16.852Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/22/929c141d6c0dba87d3e1d38fbdf1ba8baba86b7776469f2bc2d3227a1e67/multidict-6.7.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2b41f5fed0ed563624f1c17630cb9941cf2309d4df00e494b551b5f3e3d67a23", size = 76174, upload-time = "2026-01-26T02:44:18.509Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/75/bc704ae15fee974f8fccd871305e254754167dce5f9e42d88a2def741a1d/multidict-6.7.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84e61e3af5463c19b67ced91f6c634effb89ef8bfc5ca0267f954451ed4bb6a2", size = 45116, upload-time = "2026-01-26T02:44:19.745Z" },
+ { url = "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:935434b9853c7c112eee7ac891bc4cb86455aa631269ae35442cb316790c1445", size = 43524, upload-time = "2026-01-26T02:44:21.571Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/3c/414842ef8d5a1628d68edee29ba0e5bcf235dbfb3ccd3ea303a7fe8c72ff/multidict-6.7.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:432feb25a1cb67fe82a9680b4d65fb542e4635cb3166cd9c01560651ad60f177", size = 249368, upload-time = "2026-01-26T02:44:22.803Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/32/befed7f74c458b4a525e60519fe8d87eef72bb1e99924fa2b0f9d97a221e/multidict-6.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e82d14e3c948952a1a85503817e038cba5905a3352de76b9a465075d072fba23", size = 256952, upload-time = "2026-01-26T02:44:24.306Z" },
+ { url = "https://files.pythonhosted.org/packages/03/d6/c878a44ba877f366630c860fdf74bfb203c33778f12b6ac274936853c451/multidict-6.7.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4cfb48c6ea66c83bcaaf7e4dfa7ec1b6bbcf751b7db85a328902796dfde4c060", size = 240317, upload-time = "2026-01-26T02:44:25.772Z" },
+ { url = "https://files.pythonhosted.org/packages/68/49/57421b4d7ad2e9e60e25922b08ceb37e077b90444bde6ead629095327a6f/multidict-6.7.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1d540e51b7e8e170174555edecddbd5538105443754539193e3e1061864d444d", size = 267132, upload-time = "2026-01-26T02:44:27.648Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/fe/ec0edd52ddbcea2a2e89e174f0206444a61440b40f39704e64dc807a70bd/multidict-6.7.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:273d23f4b40f3dce4d6c8a821c741a86dec62cded82e1175ba3d99be128147ed", size = 268140, upload-time = "2026-01-26T02:44:29.588Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/73/6e1b01cbeb458807aa0831742232dbdd1fa92bfa33f52a3f176b4ff3dc11/multidict-6.7.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d624335fd4fa1c08a53f8b4be7676ebde19cd092b3895c421045ca87895b429", size = 254277, upload-time = "2026-01-26T02:44:30.902Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/b2/5fb8c124d7561a4974c342bc8c778b471ebbeb3cc17df696f034a7e9afe7/multidict-6.7.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:12fad252f8b267cc75b66e8fc51b3079604e8d43a75428ffe193cd9e2195dfd6", size = 252291, upload-time = "2026-01-26T02:44:32.31Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/96/51d4e4e06bcce92577fcd488e22600bd38e4fd59c20cb49434d054903bd2/multidict-6.7.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:03ede2a6ffbe8ef936b92cb4529f27f42be7f56afcdab5ab739cd5f27fb1cbf9", size = 250156, upload-time = "2026-01-26T02:44:33.734Z" },
+ { url = "https://files.pythonhosted.org/packages/db/6b/420e173eec5fba721a50e2a9f89eda89d9c98fded1124f8d5c675f7a0c0f/multidict-6.7.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:90efbcf47dbe33dcf643a1e400d67d59abeac5db07dc3f27d6bdeae497a2198c", size = 249742, upload-time = "2026-01-26T02:44:35.222Z" },
+ { url = "https://files.pythonhosted.org/packages/44/a3/ec5b5bd98f306bc2aa297b8c6f11a46714a56b1e6ef5ebda50a4f5d7c5fb/multidict-6.7.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5c4b9bfc148f5a91be9244d6264c53035c8a0dcd2f51f1c3c6e30e30ebaa1c84", size = 262221, upload-time = "2026-01-26T02:44:36.604Z" },
+ { url = "https://files.pythonhosted.org/packages/cd/f7/e8c0d0da0cd1e28d10e624604e1a36bcc3353aaebdfdc3a43c72bc683a12/multidict-6.7.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:401c5a650f3add2472d1d288c26deebc540f99e2fb83e9525007a74cd2116f1d", size = 258664, upload-time = "2026-01-26T02:44:38.008Z" },
+ { url = "https://files.pythonhosted.org/packages/52/da/151a44e8016dd33feed44f730bd856a66257c1ee7aed4f44b649fb7edeb3/multidict-6.7.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:97891f3b1b3ffbded884e2916cacf3c6fc87b66bb0dde46f7357404750559f33", size = 249490, upload-time = "2026-01-26T02:44:39.386Z" },
+ { url = "https://files.pythonhosted.org/packages/87/af/a3b86bf9630b732897f6fc3f4c4714b90aa4361983ccbdcd6c0339b21b0c/multidict-6.7.1-cp313-cp313-win32.whl", hash = "sha256:e1c5988359516095535c4301af38d8a8838534158f649c05dd1050222321bcb3", size = 41695, upload-time = "2026-01-26T02:44:41.318Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/35/e994121b0e90e46134673422dd564623f93304614f5d11886b1b3e06f503/multidict-6.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:960c83bf01a95b12b08fd54324a4eb1d5b52c88932b5cba5d6e712bb3ed12eb5", size = 45884, upload-time = "2026-01-26T02:44:42.488Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/61/42d3e5dbf661242a69c97ea363f2d7b46c567da8eadef8890022be6e2ab0/multidict-6.7.1-cp313-cp313-win_arm64.whl", hash = "sha256:563fe25c678aaba333d5399408f5ec3c383ca5b663e7f774dd179a520b8144df", size = 43122, upload-time = "2026-01-26T02:44:43.664Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/b3/e6b21c6c4f314bb956016b0b3ef2162590a529b84cb831c257519e7fde44/multidict-6.7.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:c76c4bec1538375dad9d452d246ca5368ad6e1c9039dadcf007ae59c70619ea1", size = 83175, upload-time = "2026-01-26T02:44:44.894Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/76/23ecd2abfe0957b234f6c960f4ade497f55f2c16aeb684d4ecdbf1c95791/multidict-6.7.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:57b46b24b5d5ebcc978da4ec23a819a9402b4228b8a90d9c656422b4bdd8a963", size = 48460, upload-time = "2026-01-26T02:44:46.106Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/57/a0ed92b23f3a042c36bc4227b72b97eca803f5f1801c1ab77c8a212d455e/multidict-6.7.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e954b24433c768ce78ab7929e84ccf3422e46deb45a4dc9f93438f8217fa2d34", size = 46930, upload-time = "2026-01-26T02:44:47.278Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/66/02ec7ace29162e447f6382c495dc95826bf931d3818799bbef11e8f7df1a/multidict-6.7.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3bd231490fa7217cc832528e1cd8752a96f0125ddd2b5749390f7c3ec8721b65", size = 242582, upload-time = "2026-01-26T02:44:48.604Z" },
+ { url = "https://files.pythonhosted.org/packages/58/18/64f5a795e7677670e872673aca234162514696274597b3708b2c0d276cce/multidict-6.7.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:253282d70d67885a15c8a7716f3a73edf2d635793ceda8173b9ecc21f2fb8292", size = 250031, upload-time = "2026-01-26T02:44:50.544Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/ed/e192291dbbe51a8290c5686f482084d31bcd9d09af24f63358c3d42fd284/multidict-6.7.1-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0b4c48648d7649c9335cf1927a8b87fa692de3dcb15faa676c6a6f1f1aabda43", size = 228596, upload-time = "2026-01-26T02:44:51.951Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/7e/3562a15a60cf747397e7f2180b0a11dc0c38d9175a650e75fa1b4d325e15/multidict-6.7.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:98bc624954ec4d2c7cb074b8eefc2b5d0ce7d482e410df446414355d158fe4ca", size = 257492, upload-time = "2026-01-26T02:44:53.902Z" },
+ { url = "https://files.pythonhosted.org/packages/24/02/7d0f9eae92b5249bb50ac1595b295f10e263dd0078ebb55115c31e0eaccd/multidict-6.7.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1b99af4d9eec0b49927b4402bcbb58dea89d3e0db8806a4086117019939ad3dd", size = 255899, upload-time = "2026-01-26T02:44:55.316Z" },
+ { url = "https://files.pythonhosted.org/packages/00/e3/9b60ed9e23e64c73a5cde95269ef1330678e9c6e34dd4eb6b431b85b5a10/multidict-6.7.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6aac4f16b472d5b7dc6f66a0d49dd57b0e0902090be16594dc9ebfd3d17c47e7", size = 247970, upload-time = "2026-01-26T02:44:56.783Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/06/538e58a63ed5cfb0bd4517e346b91da32fde409d839720f664e9a4ae4f9d/multidict-6.7.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:21f830fe223215dffd51f538e78c172ed7c7f60c9b96a2bf05c4848ad49921c3", size = 245060, upload-time = "2026-01-26T02:44:58.195Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/2f/d743a3045a97c895d401e9bd29aaa09b94f5cbdf1bd561609e5a6c431c70/multidict-6.7.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f5dd81c45b05518b9aa4da4aa74e1c93d715efa234fd3e8a179df611cc85e5f4", size = 235888, upload-time = "2026-01-26T02:44:59.57Z" },
+ { url = "https://files.pythonhosted.org/packages/38/83/5a325cac191ab28b63c52f14f1131f3b0a55ba3b9aa65a6d0bf2a9b921a0/multidict-6.7.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:eb304767bca2bb92fb9c5bd33cedc95baee5bb5f6c88e63706533a1c06ad08c8", size = 243554, upload-time = "2026-01-26T02:45:01.054Z" },
+ { url = "https://files.pythonhosted.org/packages/20/1f/9d2327086bd15da2725ef6aae624208e2ef828ed99892b17f60c344e57ed/multidict-6.7.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c9035dde0f916702850ef66460bc4239d89d08df4d02023a5926e7446724212c", size = 252341, upload-time = "2026-01-26T02:45:02.484Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/2c/2a1aa0280cf579d0f6eed8ee5211c4f1730bd7e06c636ba2ee6aafda302e/multidict-6.7.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:af959b9beeb66c822380f222f0e0a1889331597e81f1ded7f374f3ecb0fd6c52", size = 246391, upload-time = "2026-01-26T02:45:03.862Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/03/7ca022ffc36c5a3f6e03b179a5ceb829be9da5783e6fe395f347c0794680/multidict-6.7.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:41f2952231456154ee479651491e94118229844dd7226541788be783be2b5108", size = 243422, upload-time = "2026-01-26T02:45:05.296Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/1d/b31650eab6c5778aceed46ba735bd97f7c7d2f54b319fa916c0f96e7805b/multidict-6.7.1-cp313-cp313t-win32.whl", hash = "sha256:df9f19c28adcb40b6aae30bbaa1478c389efd50c28d541d76760199fc1037c32", size = 47770, upload-time = "2026-01-26T02:45:06.754Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/5b/2d2d1d522e51285bd61b1e20df8f47ae1a9d80839db0b24ea783b3832832/multidict-6.7.1-cp313-cp313t-win_amd64.whl", hash = "sha256:d54ecf9f301853f2c5e802da559604b3e95bb7a3b01a9c295c6ee591b9882de8", size = 53109, upload-time = "2026-01-26T02:45:08.044Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/a3/cc409ba012c83ca024a308516703cf339bdc4b696195644a7215a5164a24/multidict-6.7.1-cp313-cp313t-win_arm64.whl", hash = "sha256:5a37ca18e360377cfda1d62f5f382ff41f2b8c4ccb329ed974cc2e1643440118", size = 45573, upload-time = "2026-01-26T02:45:09.349Z" },
+ { url = "https://files.pythonhosted.org/packages/91/cc/db74228a8be41884a567e88a62fd589a913708fcf180d029898c17a9a371/multidict-6.7.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8f333ec9c5eb1b7105e3b84b53141e66ca05a19a605368c55450b6ba208cb9ee", size = 75190, upload-time = "2026-01-26T02:45:10.651Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/22/492f2246bb5b534abd44804292e81eeaf835388901f0c574bac4eeec73c5/multidict-6.7.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a407f13c188f804c759fc6a9f88286a565c242a76b27626594c133b82883b5c2", size = 44486, upload-time = "2026-01-26T02:45:11.938Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/4f/733c48f270565d78b4544f2baddc2fb2a245e5a8640254b12c36ac7ac68e/multidict-6.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0e161ddf326db5577c3a4cc2d8648f81456e8a20d40415541587a71620d7a7d1", size = 43219, upload-time = "2026-01-26T02:45:14.346Z" },
+ { url = "https://files.pythonhosted.org/packages/24/bb/2c0c2287963f4259c85e8bcbba9182ced8d7fca65c780c38e99e61629d11/multidict-6.7.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1e3a8bb24342a8201d178c3b4984c26ba81a577c80d4d525727427460a50c22d", size = 245132, upload-time = "2026-01-26T02:45:15.712Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/f9/44d4b3064c65079d2467888794dea218d1601898ac50222ab8a9a8094460/multidict-6.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97231140a50f5d447d3164f994b86a0bed7cd016e2682f8650d6a9158e14fd31", size = 252420, upload-time = "2026-01-26T02:45:17.293Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/13/78f7275e73fa17b24c9a51b0bd9d73ba64bb32d0ed51b02a746eb876abe7/multidict-6.7.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6b10359683bd8806a200fd2909e7c8ca3a7b24ec1d8132e483d58e791d881048", size = 233510, upload-time = "2026-01-26T02:45:19.356Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/25/8167187f62ae3cbd52da7893f58cb036b47ea3fb67138787c76800158982/multidict-6.7.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:283ddac99f7ac25a4acadbf004cb5ae34480bbeb063520f70ce397b281859362", size = 264094, upload-time = "2026-01-26T02:45:20.834Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/e7/69a3a83b7b030cf283fb06ce074a05a02322359783424d7edf0f15fe5022/multidict-6.7.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:538cec1e18c067d0e6103aa9a74f9e832904c957adc260e61cd9d8cf0c3b3d37", size = 260786, upload-time = "2026-01-26T02:45:22.818Z" },
+ { url = "https://files.pythonhosted.org/packages/fe/3b/8ec5074bcfc450fe84273713b4b0a0dd47c0249358f5d82eb8104ffe2520/multidict-6.7.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eee46ccb30ff48a1e35bb818cc90846c6be2b68240e42a78599166722cea709", size = 248483, upload-time = "2026-01-26T02:45:24.368Z" },
+ { url = "https://files.pythonhosted.org/packages/48/5a/d5a99e3acbca0e29c5d9cba8f92ceb15dce78bab963b308ae692981e3a5d/multidict-6.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa263a02f4f2dd2d11a7b1bb4362aa7cb1049f84a9235d31adf63f30143469a0", size = 248403, upload-time = "2026-01-26T02:45:25.982Z" },
+ { url = "https://files.pythonhosted.org/packages/35/48/e58cd31f6c7d5102f2a4bf89f96b9cf7e00b6c6f3d04ecc44417c00a5a3c/multidict-6.7.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:2e1425e2f99ec5bd36c15a01b690a1a2456209c5deed58f95469ffb46039ccbb", size = 240315, upload-time = "2026-01-26T02:45:27.487Z" },
+ { url = "https://files.pythonhosted.org/packages/94/33/1cd210229559cb90b6786c30676bb0c58249ff42f942765f88793b41fdce/multidict-6.7.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:497394b3239fc6f0e13a78a3e1b61296e72bf1c5f94b4c4eb80b265c37a131cd", size = 245528, upload-time = "2026-01-26T02:45:28.991Z" },
+ { url = "https://files.pythonhosted.org/packages/64/f2/6e1107d226278c876c783056b7db43d800bb64c6131cec9c8dfb6903698e/multidict-6.7.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:233b398c29d3f1b9676b4b6f75c518a06fcb2ea0b925119fb2c1bc35c05e1601", size = 258784, upload-time = "2026-01-26T02:45:30.503Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/c1/11f664f14d525e4a1b5327a82d4de61a1db604ab34c6603bb3c2cc63ad34/multidict-6.7.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:93b1818e4a6e0930454f0f2af7dfce69307ca03cdcfb3739bf4d91241967b6c1", size = 251980, upload-time = "2026-01-26T02:45:32.603Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/9f/75a9ac888121d0c5bbd4ecf4eead45668b1766f6baabfb3b7f66a410e231/multidict-6.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f33dc2a3abe9249ea5d8360f969ec7f4142e7ac45ee7014d8f8d5acddf178b7b", size = 243602, upload-time = "2026-01-26T02:45:34.043Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/e7/50bf7b004cc8525d80dbbbedfdc7aed3e4c323810890be4413e589074032/multidict-6.7.1-cp314-cp314-win32.whl", hash = "sha256:3ab8b9d8b75aef9df299595d5388b14530839f6422333357af1339443cff777d", size = 40930, upload-time = "2026-01-26T02:45:36.278Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/bf/52f25716bbe93745595800f36fb17b73711f14da59ed0bb2eba141bc9f0f/multidict-6.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:5e01429a929600e7dab7b166062d9bb54a5eed752384c7384c968c2afab8f50f", size = 45074, upload-time = "2026-01-26T02:45:37.546Z" },
+ { url = "https://files.pythonhosted.org/packages/97/ab/22803b03285fa3a525f48217963da3a65ae40f6a1b6f6cf2768879e208f9/multidict-6.7.1-cp314-cp314-win_arm64.whl", hash = "sha256:4885cb0e817aef5d00a2e8451d4665c1808378dc27c2705f1bf4ef8505c0d2e5", size = 42471, upload-time = "2026-01-26T02:45:38.889Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/6d/f9293baa6146ba9507e360ea0292b6422b016907c393e2f63fc40ab7b7b5/multidict-6.7.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0458c978acd8e6ea53c81eefaddbbee9c6c5e591f41b3f5e8e194780fe026581", size = 82401, upload-time = "2026-01-26T02:45:40.254Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/68/53b5494738d83558d87c3c71a486504d8373421c3e0dbb6d0db48ad42ee0/multidict-6.7.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:c0abd12629b0af3cf590982c0b413b1e7395cd4ec026f30986818ab95bfaa94a", size = 48143, upload-time = "2026-01-26T02:45:41.635Z" },
+ { url = "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:14525a5f61d7d0c94b368a42cff4c9a4e7ba2d52e2672a7b23d84dc86fb02b0c", size = 46507, upload-time = "2026-01-26T02:45:42.99Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/fc/6800d0e5b3875568b4083ecf5f310dcf91d86d52573160834fb4bfcf5e4f/multidict-6.7.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17307b22c217b4cf05033dabefe68255a534d637c6c9b0cc8382718f87be4262", size = 239358, upload-time = "2026-01-26T02:45:44.376Z" },
+ { url = "https://files.pythonhosted.org/packages/41/75/4ad0973179361cdf3a113905e6e088173198349131be2b390f9fa4da5fc6/multidict-6.7.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a7e590ff876a3eaf1c02a4dfe0724b6e69a9e9de6d8f556816f29c496046e59", size = 246884, upload-time = "2026-01-26T02:45:47.167Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/9c/095bb28b5da139bd41fb9a5d5caff412584f377914bd8787c2aa98717130/multidict-6.7.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5fa6a95dfee63893d80a34758cd0e0c118a30b8dcb46372bf75106c591b77889", size = 225878, upload-time = "2026-01-26T02:45:48.698Z" },
+ { url = "https://files.pythonhosted.org/packages/07/d0/c0a72000243756e8f5a277b6b514fa005f2c73d481b7d9e47cd4568aa2e4/multidict-6.7.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a0543217a6a017692aa6ae5cc39adb75e587af0f3a82288b1492eb73dd6cc2a4", size = 253542, upload-time = "2026-01-26T02:45:50.164Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/6b/f69da15289e384ecf2a68837ec8b5ad8c33e973aa18b266f50fe55f24b8c/multidict-6.7.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f99fe611c312b3c1c0ace793f92464d8cd263cc3b26b5721950d977b006b6c4d", size = 252403, upload-time = "2026-01-26T02:45:51.779Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/76/b9669547afa5a1a25cd93eaca91c0da1c095b06b6d2d8ec25b713588d3a1/multidict-6.7.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9004d8386d133b7e6135679424c91b0b854d2d164af6ea3f289f8f2761064609", size = 244889, upload-time = "2026-01-26T02:45:53.27Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/a9/a50d2669e506dad33cfc45b5d574a205587b7b8a5f426f2fbb2e90882588/multidict-6.7.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e628ef0e6859ffd8273c69412a2465c4be4a9517d07261b33334b5ec6f3c7489", size = 241982, upload-time = "2026-01-26T02:45:54.919Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/bb/1609558ad8b456b4827d3c5a5b775c93b87878fd3117ed3db3423dfbce1b/multidict-6.7.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:841189848ba629c3552035a6a7f5bf3b02eb304e9fea7492ca220a8eda6b0e5c", size = 232415, upload-time = "2026-01-26T02:45:56.981Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/59/6f61039d2aa9261871e03ab9dc058a550d240f25859b05b67fd70f80d4b3/multidict-6.7.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:ce1bbd7d780bb5a0da032e095c951f7014d6b0a205f8318308140f1a6aba159e", size = 240337, upload-time = "2026-01-26T02:45:58.698Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/29/fdc6a43c203890dc2ae9249971ecd0c41deaedfe00d25cb6564b2edd99eb/multidict-6.7.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b26684587228afed0d50cf804cc71062cc9c1cdf55051c4c6345d372947b268c", size = 248788, upload-time = "2026-01-26T02:46:00.862Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/14/a153a06101323e4cf086ecee3faadba52ff71633d471f9685c42e3736163/multidict-6.7.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9f9af11306994335398293f9958071019e3ab95e9a707dc1383a35613f6abcb9", size = 242842, upload-time = "2026-01-26T02:46:02.824Z" },
+ { url = "https://files.pythonhosted.org/packages/41/5f/604ae839e64a4a6efc80db94465348d3b328ee955e37acb24badbcd24d83/multidict-6.7.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b4938326284c4f1224178a560987b6cf8b4d38458b113d9b8c1db1a836e640a2", size = 240237, upload-time = "2026-01-26T02:46:05.898Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/60/c3a5187bf66f6fb546ff4ab8fb5a077cbdd832d7b1908d4365c7f74a1917/multidict-6.7.1-cp314-cp314t-win32.whl", hash = "sha256:98655c737850c064a65e006a3df7c997cd3b220be4ec8fe26215760b9697d4d7", size = 48008, upload-time = "2026-01-26T02:46:07.468Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/f7/addf1087b860ac60e6f382240f64fb99f8bfb532bb06f7c542b83c29ca61/multidict-6.7.1-cp314-cp314t-win_amd64.whl", hash = "sha256:497bde6223c212ba11d462853cfa4f0ae6ef97465033e7dc9940cdb3ab5b48e5", size = 53542, upload-time = "2026-01-26T02:46:08.809Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/81/4629d0aa32302ef7b2ec65c75a728cc5ff4fa410c50096174c1632e70b3e/multidict-6.7.1-cp314-cp314t-win_arm64.whl", hash = "sha256:2bbd113e0d4af5db41d5ebfe9ccaff89de2120578164f86a5d17d5a576d1e5b2", size = 44719, upload-time = "2026-01-26T02:46:11.146Z" },
+ { url = "https://files.pythonhosted.org/packages/81/08/7036c080d7117f28a4af526d794aab6a84463126db031b007717c1a6676e/multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56", size = 12319, upload-time = "2026-01-26T02:46:44.004Z" },
+]
+
+[[package]]
+name = "networkx"
+version = "3.6.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/6a/51/63fe664f3908c97be9d2e4f1158eb633317598cfa6e1fc14af5383f17512/networkx-3.6.1.tar.gz", hash = "sha256:26b7c357accc0c8cde558ad486283728b65b6a95d85ee1cd66bafab4c8168509", size = 2517025, upload-time = "2025-12-08T17:02:39.908Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl", hash = "sha256:d47fbf302e7d9cbbb9e2555a0d267983d2aa476bac30e90dfbe5669bd57f3762", size = 2068504, upload-time = "2025-12-08T17:02:38.159Z" },
+]
+
+[[package]]
+name = "numpy"
+version = "2.4.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/10/8b/c265f4823726ab832de836cdd184d0986dcf94480f81e8739692a7ac7af2/numpy-2.4.3.tar.gz", hash = "sha256:483a201202b73495f00dbc83796c6ae63137a9bdade074f7648b3e32613412dd", size = 20727743, upload-time = "2026-03-09T07:58:53.426Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a9/ed/6388632536f9788cea23a3a1b629f25b43eaacd7d7377e5d6bc7b9deb69b/numpy-2.4.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:61b0cbabbb6126c8df63b9a3a0c4b1f44ebca5e12ff6997b80fcf267fb3150ef", size = 16669628, upload-time = "2026-03-09T07:56:24.252Z" },
+ { url = "https://files.pythonhosted.org/packages/74/1b/ee2abfc68e1ce728b2958b6ba831d65c62e1b13ce3017c13943f8f9b5b2e/numpy-2.4.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7395e69ff32526710748f92cd8c9849b361830968ea3e24a676f272653e8983e", size = 14696872, upload-time = "2026-03-09T07:56:26.991Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/d1/780400e915ff5638166f11ca9dc2c5815189f3d7cf6f8759a1685e586413/numpy-2.4.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:abdce0f71dcb4a00e4e77f3faf05e4616ceccfe72ccaa07f47ee79cda3b7b0f4", size = 5203489, upload-time = "2026-03-09T07:56:29.414Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/bb/baffa907e9da4cc34a6e556d6d90e032f6d7a75ea47968ea92b4858826c4/numpy-2.4.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:48da3a4ee1336454b07497ff7ec83903efa5505792c4e6d9bf83d99dc07a1e18", size = 6550814, upload-time = "2026-03-09T07:56:32.225Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/12/8c9f0c6c95f76aeb20fc4a699c33e9f827fa0d0f857747c73bb7b17af945/numpy-2.4.3-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:32e3bef222ad6b052280311d1d60db8e259e4947052c3ae7dd6817451fc8a4c5", size = 15666601, upload-time = "2026-03-09T07:56:34.461Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/79/cc665495e4d57d0aa6fbcc0aa57aa82671dfc78fbf95fe733ed86d98f52a/numpy-2.4.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e7dd01a46700b1967487141a66ac1a3cf0dd8ebf1f08db37d46389401512ca97", size = 16621358, upload-time = "2026-03-09T07:56:36.852Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/40/b4ecb7224af1065c3539f5ecfff879d090de09608ad1008f02c05c770cb3/numpy-2.4.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:76f0f283506c28b12bba319c0fab98217e9f9b54e6160e9c79e9f7348ba32e9c", size = 17016135, upload-time = "2026-03-09T07:56:39.337Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/b1/6a88e888052eed951afed7a142dcdf3b149a030ca59b4c71eef085858e43/numpy-2.4.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:737f630a337364665aba3b5a77e56a68cc42d350edd010c345d65a3efa3addcc", size = 18345816, upload-time = "2026-03-09T07:56:42.31Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/8f/103a60c5f8c3d7fc678c19cd7b2476110da689ccb80bc18050efbaeae183/numpy-2.4.3-cp312-cp312-win32.whl", hash = "sha256:26952e18d82a1dbbc2f008d402021baa8d6fc8e84347a2072a25e08b46d698b9", size = 5960132, upload-time = "2026-03-09T07:56:44.851Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/7c/f5ee1bf6ed888494978046a809df2882aad35d414b622893322df7286879/numpy-2.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:65f3c2455188f09678355f5cae1f959a06b778bc66d535da07bf2ef20cd319d5", size = 12316144, upload-time = "2026-03-09T07:56:47.057Z" },
+ { url = "https://files.pythonhosted.org/packages/71/46/8d1cb3f7a00f2fb6394140e7e6623696e54c6318a9d9691bb4904672cf42/numpy-2.4.3-cp312-cp312-win_arm64.whl", hash = "sha256:2abad5c7fef172b3377502bde47892439bae394a71bc329f31df0fd829b41a9e", size = 10220364, upload-time = "2026-03-09T07:56:49.849Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/d0/1fe47a98ce0df229238b77611340aff92d52691bcbc10583303181abf7fc/numpy-2.4.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b346845443716c8e542d54112966383b448f4a3ba5c66409771b8c0889485dd3", size = 16665297, upload-time = "2026-03-09T07:56:52.296Z" },
+ { url = "https://files.pythonhosted.org/packages/27/d9/4e7c3f0e68dfa91f21c6fb6cf839bc829ec920688b1ce7ec722b1a6202fb/numpy-2.4.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2629289168f4897a3c4e23dc98d6f1731f0fc0fe52fb9db19f974041e4cc12b9", size = 14691853, upload-time = "2026-03-09T07:56:54.992Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/66/bd096b13a87549683812b53ab211e6d413497f84e794fb3c39191948da97/numpy-2.4.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:bb2e3cf95854233799013779216c57e153c1ee67a0bf92138acca0e429aefaee", size = 5198435, upload-time = "2026-03-09T07:56:57.184Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/2f/687722910b5a5601de2135c891108f51dfc873d8e43c8ed9f4ebb440b4a2/numpy-2.4.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:7f3408ff897f8ab07a07fbe2823d7aee6ff644c097cc1f90382511fe982f647f", size = 6546347, upload-time = "2026-03-09T07:56:59.531Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/ec/7971c4e98d86c564750393fab8d7d83d0a9432a9d78bb8a163a6dc59967a/numpy-2.4.3-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:decb0eb8a53c3b009b0962378065589685d66b23467ef5dac16cbe818afde27f", size = 15664626, upload-time = "2026-03-09T07:57:01.385Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/eb/7daecbea84ec935b7fc732e18f532073064a3816f0932a40a17f3349185f/numpy-2.4.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d5f51900414fc9204a0e0da158ba2ac52b75656e7dce7e77fb9f84bfa343b4cc", size = 16608916, upload-time = "2026-03-09T07:57:04.008Z" },
+ { url = "https://files.pythonhosted.org/packages/df/58/2a2b4a817ffd7472dca4421d9f0776898b364154e30c95f42195041dc03b/numpy-2.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6bd06731541f89cdc01b261ba2c9e037f1543df7472517836b78dfb15bd6e476", size = 17015824, upload-time = "2026-03-09T07:57:06.347Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/ca/627a828d44e78a418c55f82dd4caea8ea4a8ef24e5144d9e71016e52fb40/numpy-2.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:22654fe6be0e5206f553a9250762c653d3698e46686eee53b399ab90da59bd92", size = 18334581, upload-time = "2026-03-09T07:57:09.114Z" },
+ { url = "https://files.pythonhosted.org/packages/cd/c0/76f93962fc79955fcba30a429b62304332345f22d4daec1cb33653425643/numpy-2.4.3-cp313-cp313-win32.whl", hash = "sha256:d71e379452a2f670ccb689ec801b1218cd3983e253105d6e83780967e899d687", size = 5958618, upload-time = "2026-03-09T07:57:11.432Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/3c/88af0040119209b9b5cb59485fa48b76f372c73068dbf9254784b975ac53/numpy-2.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:0a60e17a14d640f49146cb38e3f105f571318db7826d9b6fef7e4dce758faecd", size = 12312824, upload-time = "2026-03-09T07:57:13.586Z" },
+ { url = "https://files.pythonhosted.org/packages/58/ce/3d07743aced3d173f877c3ef6a454c2174ba42b584ab0b7e6d99374f51ed/numpy-2.4.3-cp313-cp313-win_arm64.whl", hash = "sha256:c9619741e9da2059cd9c3f206110b97583c7152c1dc9f8aafd4beb450ac1c89d", size = 10221218, upload-time = "2026-03-09T07:57:16.183Z" },
+ { url = "https://files.pythonhosted.org/packages/62/09/d96b02a91d09e9d97862f4fc8bfebf5400f567d8eb1fe4b0cc4795679c15/numpy-2.4.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7aa4e54f6469300ebca1d9eb80acd5253cdfa36f2c03d79a35883687da430875", size = 14819570, upload-time = "2026-03-09T07:57:18.564Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/ca/0b1aba3905fdfa3373d523b2b15b19029f4f3031c87f4066bd9d20ef6c6b/numpy-2.4.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d1b90d840b25874cf5cd20c219af10bac3667db3876d9a495609273ebe679070", size = 5326113, upload-time = "2026-03-09T07:57:21.052Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/63/406e0fd32fcaeb94180fd6a4c41e55736d676c54346b7efbce548b94a914/numpy-2.4.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:a749547700de0a20a6718293396ec237bb38218049cfce788e08fcb716e8cf73", size = 6646370, upload-time = "2026-03-09T07:57:22.804Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/d0/10f7dc157d4b37af92720a196be6f54f889e90dcd30dce9dc657ed92c257/numpy-2.4.3-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94f3c4a151a2e529adf49c1d54f0f57ff8f9b233ee4d44af623a81553ab86368", size = 15723499, upload-time = "2026-03-09T07:57:24.693Z" },
+ { url = "https://files.pythonhosted.org/packages/66/f1/d1c2bf1161396629701bc284d958dc1efa3a5a542aab83cf11ee6eb4cba5/numpy-2.4.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22c31dc07025123aedf7f2db9e91783df13f1776dc52c6b22c620870dc0fab22", size = 16657164, upload-time = "2026-03-09T07:57:27.676Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/be/cca19230b740af199ac47331a21c71e7a3d0ba59661350483c1600d28c37/numpy-2.4.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:148d59127ac95979d6f07e4d460f934ebdd6eed641db9c0db6c73026f2b2101a", size = 17081544, upload-time = "2026-03-09T07:57:30.664Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/c5/9602b0cbb703a0936fb40f8a95407e8171935b15846de2f0776e08af04c7/numpy-2.4.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a97cbf7e905c435865c2d939af3d93f99d18eaaa3cabe4256f4304fb51604349", size = 18380290, upload-time = "2026-03-09T07:57:33.763Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/81/9f24708953cd30be9ee36ec4778f4b112b45165812f2ada4cc5ea1c1f254/numpy-2.4.3-cp313-cp313t-win32.whl", hash = "sha256:be3b8487d725a77acccc9924f65fd8bce9af7fac8c9820df1049424a2115af6c", size = 6082814, upload-time = "2026-03-09T07:57:36.491Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/9e/52f6eaa13e1a799f0ab79066c17f7016a4a8ae0c1aefa58c82b4dab690b4/numpy-2.4.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1ec84fd7c8e652b0f4aaaf2e6e9cc8eaa9b1b80a537e06b2e3a2fb176eedcb26", size = 12452673, upload-time = "2026-03-09T07:57:38.281Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/04/b8cece6ead0b30c9fbd99bb835ad7ea0112ac5f39f069788c5558e3b1ab2/numpy-2.4.3-cp313-cp313t-win_arm64.whl", hash = "sha256:120df8c0a81ebbf5b9020c91439fccd85f5e018a927a39f624845be194a2be02", size = 10290907, upload-time = "2026-03-09T07:57:40.747Z" },
+ { url = "https://files.pythonhosted.org/packages/70/ae/3936f79adebf8caf81bd7a599b90a561334a658be4dcc7b6329ebf4ee8de/numpy-2.4.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:5884ce5c7acfae1e4e1b6fde43797d10aa506074d25b531b4f54bde33c0c31d4", size = 16664563, upload-time = "2026-03-09T07:57:43.817Z" },
+ { url = "https://files.pythonhosted.org/packages/9b/62/760f2b55866b496bb1fa7da2a6db076bef908110e568b02fcfc1422e2a3a/numpy-2.4.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:297837823f5bc572c5f9379b0c9f3a3365f08492cbdc33bcc3af174372ebb168", size = 14702161, upload-time = "2026-03-09T07:57:46.169Z" },
+ { url = "https://files.pythonhosted.org/packages/32/af/a7a39464e2c0a21526fb4fb76e346fb172ebc92f6d1c7a07c2c139cc17b1/numpy-2.4.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:a111698b4a3f8dcbe54c64a7708f049355abd603e619013c346553c1fd4ca90b", size = 5208738, upload-time = "2026-03-09T07:57:48.506Z" },
+ { url = "https://files.pythonhosted.org/packages/29/8c/2a0cf86a59558fa078d83805589c2de490f29ed4fb336c14313a161d358a/numpy-2.4.3-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:4bd4741a6a676770e0e97fe9ab2e51de01183df3dcbcec591d26d331a40de950", size = 6543618, upload-time = "2026-03-09T07:57:50.591Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/b8/612ce010c0728b1c363fa4ea3aa4c22fe1c5da1de008486f8c2f5cb92fae/numpy-2.4.3-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:54f29b877279d51e210e0c80709ee14ccbbad647810e8f3d375561c45ef613dd", size = 15680676, upload-time = "2026-03-09T07:57:52.34Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/7e/4f120ecc54ba26ddf3dc348eeb9eb063f421de65c05fc961941798feea18/numpy-2.4.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:679f2a834bae9020f81534671c56fd0cc76dd7e5182f57131478e23d0dc59e24", size = 16613492, upload-time = "2026-03-09T07:57:54.91Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/86/1b6020db73be330c4b45d5c6ee4295d59cfeef0e3ea323959d053e5a6909/numpy-2.4.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d84f0f881cb2225c2dfd7f78a10a5645d487a496c6668d6cc39f0f114164f3d0", size = 17031789, upload-time = "2026-03-09T07:57:57.641Z" },
+ { url = "https://files.pythonhosted.org/packages/07/3a/3b90463bf41ebc21d1b7e06079f03070334374208c0f9a1f05e4ae8455e7/numpy-2.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d213c7e6e8d211888cc359bab7199670a00f5b82c0978b9d1c75baf1eddbeac0", size = 18339941, upload-time = "2026-03-09T07:58:00.577Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/74/6d736c4cd962259fd8bae9be27363eb4883a2f9069763747347544c2a487/numpy-2.4.3-cp314-cp314-win32.whl", hash = "sha256:52077feedeff7c76ed7c9f1a0428558e50825347b7545bbb8523da2cd55c547a", size = 6007503, upload-time = "2026-03-09T07:58:03.331Z" },
+ { url = "https://files.pythonhosted.org/packages/48/39/c56ef87af669364356bb011922ef0734fc49dad51964568634c72a009488/numpy-2.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:0448e7f9caefb34b4b7dd2b77f21e8906e5d6f0365ad525f9f4f530b13df2afc", size = 12444915, upload-time = "2026-03-09T07:58:06.353Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/1f/ab8528e38d295fd349310807496fabb7cf9fe2e1f70b97bc20a483ea9d4a/numpy-2.4.3-cp314-cp314-win_arm64.whl", hash = "sha256:b44fd60341c4d9783039598efadd03617fa28d041fc37d22b62d08f2027fa0e7", size = 10494875, upload-time = "2026-03-09T07:58:08.734Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/ef/b7c35e4d5ef141b836658ab21a66d1a573e15b335b1d111d31f26c8ef80f/numpy-2.4.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0a195f4216be9305a73c0e91c9b026a35f2161237cf1c6de9b681637772ea657", size = 14822225, upload-time = "2026-03-09T07:58:11.034Z" },
+ { url = "https://files.pythonhosted.org/packages/cd/8d/7730fa9278cf6648639946cc816e7cc89f0d891602584697923375f801ed/numpy-2.4.3-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:cd32fbacb9fd1bf041bf8e89e4576b6f00b895f06d00914820ae06a616bdfef7", size = 5328769, upload-time = "2026-03-09T07:58:13.67Z" },
+ { url = "https://files.pythonhosted.org/packages/47/01/d2a137317c958b074d338807c1b6a383406cdf8b8e53b075d804cc3d211d/numpy-2.4.3-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:2e03c05abaee1f672e9d67bc858f300b5ccba1c21397211e8d77d98350972093", size = 6649461, upload-time = "2026-03-09T07:58:15.912Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/34/812ce12bc0f00272a4b0ec0d713cd237cb390666eb6206323d1cc9cedbb2/numpy-2.4.3-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7d1ce23cce91fcea443320a9d0ece9b9305d4368875bab09538f7a5b4131938a", size = 15725809, upload-time = "2026-03-09T07:58:17.787Z" },
+ { url = "https://files.pythonhosted.org/packages/25/c0/2aed473a4823e905e765fee3dc2cbf504bd3e68ccb1150fbdabd5c39f527/numpy-2.4.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c59020932feb24ed49ffd03704fbab89f22aa9c0d4b180ff45542fe8918f5611", size = 16655242, upload-time = "2026-03-09T07:58:20.476Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/c8/7e052b2fc87aa0e86de23f20e2c42bd261c624748aa8efd2c78f7bb8d8c6/numpy-2.4.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9684823a78a6cd6ad7511fc5e25b07947d1d5b5e2812c93fe99d7d4195130720", size = 17080660, upload-time = "2026-03-09T07:58:23.067Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/3d/0876746044db2adcb11549f214d104f2e1be00f07a67edbb4e2812094847/numpy-2.4.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0200b25c687033316fb39f0ff4e3e690e8957a2c3c8d22499891ec58c37a3eb5", size = 18380384, upload-time = "2026-03-09T07:58:25.839Z" },
+ { url = "https://files.pythonhosted.org/packages/07/12/8160bea39da3335737b10308df4f484235fd297f556745f13092aa039d3b/numpy-2.4.3-cp314-cp314t-win32.whl", hash = "sha256:5e10da9e93247e554bb1d22f8edc51847ddd7dde52d85ce31024c1b4312bfba0", size = 6154547, upload-time = "2026-03-09T07:58:28.289Z" },
+ { url = "https://files.pythonhosted.org/packages/42/f3/76534f61f80d74cc9cdf2e570d3d4eeb92c2280a27c39b0aaf471eda7b48/numpy-2.4.3-cp314-cp314t-win_amd64.whl", hash = "sha256:45f003dbdffb997a03da2d1d0cb41fbd24a87507fb41605c0420a3db5bd4667b", size = 12633645, upload-time = "2026-03-09T07:58:30.384Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/b6/7c0d4334c15983cec7f92a69e8ce9b1e6f31857e5ee3a413ac424e6bd63d/numpy-2.4.3-cp314-cp314t-win_arm64.whl", hash = "sha256:4d382735cecd7bcf090172489a525cd7d4087bc331f7df9f60ddc9a296cf208e", size = 10565454, upload-time = "2026-03-09T07:58:33.031Z" },
+]
+
+[[package]]
+name = "nvidia-cublas-cu12"
+version = "12.8.4.1"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/dc/61/e24b560ab2e2eaeb3c839129175fb330dfcfc29e5203196e5541a4c44682/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142", size = 594346921, upload-time = "2025-03-07T01:44:31.254Z" },
+]
+
+[[package]]
+name = "nvidia-cuda-cupti-cu12"
+version = "12.8.90"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f8/02/2adcaa145158bf1a8295d83591d22e4103dbfd821bcaf6f3f53151ca4ffa/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182", size = 10248621, upload-time = "2025-03-07T01:40:21.213Z" },
+]
+
+[[package]]
+name = "nvidia-cuda-nvrtc-cu12"
+version = "12.8.93"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/05/6b/32f747947df2da6994e999492ab306a903659555dddc0fbdeb9d71f75e52/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994", size = 88040029, upload-time = "2025-03-07T01:42:13.562Z" },
+]
+
+[[package]]
+name = "nvidia-cuda-runtime-cu12"
+version = "12.8.90"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/0d/9b/a997b638fcd068ad6e4d53b8551a7d30fe8b404d6f1804abf1df69838932/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90", size = 954765, upload-time = "2025-03-07T01:40:01.615Z" },
+]
+
+[[package]]
+name = "nvidia-cudnn-cu12"
+version = "9.10.2.21"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "nvidia-cublas-cu12", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
+]
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ba/51/e123d997aa098c61d029f76663dedbfb9bc8dcf8c60cbd6adbe42f76d049/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8", size = 706758467, upload-time = "2025-06-06T21:54:08.597Z" },
+]
+
+[[package]]
+name = "nvidia-cufft-cu12"
+version = "11.3.3.83"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "nvidia-nvjitlink-cu12", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
+]
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/1f/13/ee4e00f30e676b66ae65b4f08cb5bcbb8392c03f54f2d5413ea99a5d1c80/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74", size = 193118695, upload-time = "2025-03-07T01:45:27.821Z" },
+]
+
+[[package]]
+name = "nvidia-cufile-cu12"
+version = "1.13.1.3"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/bb/fe/1bcba1dfbfb8d01be8d93f07bfc502c93fa23afa6fd5ab3fc7c1df71038a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc", size = 1197834, upload-time = "2025-03-07T01:45:50.723Z" },
+]
+
+[[package]]
+name = "nvidia-curand-cu12"
+version = "10.3.9.90"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/fb/aa/6584b56dc84ebe9cf93226a5cde4d99080c8e90ab40f0c27bda7a0f29aa1/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9", size = 63619976, upload-time = "2025-03-07T01:46:23.323Z" },
+]
+
+[[package]]
+name = "nvidia-cusolver-cu12"
+version = "11.7.3.90"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "nvidia-cublas-cu12", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
+ { name = "nvidia-cusparse-cu12", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
+ { name = "nvidia-nvjitlink-cu12", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
+]
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/85/48/9a13d2975803e8cf2777d5ed57b87a0b6ca2cc795f9a4f59796a910bfb80/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450", size = 267506905, upload-time = "2025-03-07T01:47:16.273Z" },
+]
+
+[[package]]
+name = "nvidia-cusparse-cu12"
+version = "12.5.8.93"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "nvidia-nvjitlink-cu12", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
+]
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c2/f5/e1854cb2f2bcd4280c44736c93550cc300ff4b8c95ebe370d0aa7d2b473d/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b", size = 288216466, upload-time = "2025-03-07T01:48:13.779Z" },
+]
+
+[[package]]
+name = "nvidia-cusparselt-cu12"
+version = "0.7.1"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/56/79/12978b96bd44274fe38b5dde5cfb660b1d114f70a65ef962bcbbed99b549/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623", size = 287193691, upload-time = "2025-02-26T00:15:44.104Z" },
+]
+
+[[package]]
+name = "nvidia-nccl-cu12"
+version = "2.27.5"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/6e/89/f7a07dc961b60645dbbf42e80f2bc85ade7feb9a491b11a1e973aa00071f/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ad730cf15cb5d25fe849c6e6ca9eb5b76db16a80f13f425ac68d8e2e55624457", size = 322348229, upload-time = "2025-06-26T04:11:28.385Z" },
+]
+
+[[package]]
+name = "nvidia-nvjitlink-cu12"
+version = "12.8.93"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f6/74/86a07f1d0f42998ca31312f998bd3b9a7eff7f52378f4f270c8679c77fb9/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88", size = 39254836, upload-time = "2025-03-07T01:49:55.661Z" },
+]
+
+[[package]]
+name = "nvidia-nvshmem-cu12"
+version = "3.4.5"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b5/09/6ea3ea725f82e1e76684f0708bbedd871fc96da89945adeba65c3835a64c/nvidia_nvshmem_cu12-3.4.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:042f2500f24c021db8a06c5eec2539027d57460e1c1a762055a6554f72c369bd", size = 139103095, upload-time = "2025-09-06T00:32:31.266Z" },
+]
+
+[[package]]
+name = "nvidia-nvtx-cu12"
+version = "12.8.90"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954, upload-time = "2025-03-07T01:42:44.131Z" },
+]
+
+[[package]]
+name = "opencensus"
+version = "0.11.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "google-api-core" },
+ { name = "opencensus-context" },
+ { name = "six" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/15/a7/a46dcffa1b63084f9f17fe3c8cb20724c4c8f91009fd0b2cfdb27d5d2b35/opencensus-0.11.4.tar.gz", hash = "sha256:cbef87d8b8773064ab60e5c2a1ced58bbaa38a6d052c41aec224958ce544eff2", size = 64966, upload-time = "2024-01-03T18:04:07.085Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b5/ed/9fbdeb23a09e430d87b7d72d430484b88184633dc50f6bfb792354b6f661/opencensus-0.11.4-py2.py3-none-any.whl", hash = "sha256:a18487ce68bc19900336e0ff4655c5a116daf10c1b3685ece8d971bddad6a864", size = 128225, upload-time = "2024-01-03T18:04:05.127Z" },
+]
+
+[[package]]
+name = "opencensus-context"
+version = "0.1.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/4c/96/3b6f638f6275a8abbd45e582448723bffa29c1fb426721dedb5c72f7d056/opencensus-context-0.1.3.tar.gz", hash = "sha256:a03108c3c10d8c80bb5ddf5c8a1f033161fa61972a9917f9b9b3a18517f0088c", size = 4066, upload-time = "2022-08-03T22:20:22.359Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/10/68/162c97ea78c957d68ecf78a5c5041d2e25bd5562bdf5d89a6cbf7f8429bf/opencensus_context-0.1.3-py2.py3-none-any.whl", hash = "sha256:073bb0590007af276853009fac7e4bab1d523c3f03baf4cb4511ca38967c6039", size = 5060, upload-time = "2022-08-03T22:20:20.352Z" },
+]
+
+[[package]]
+name = "opentelemetry-api"
+version = "1.40.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "importlib-metadata" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/2c/1d/4049a9e8698361cc1a1aa03a6c59e4fa4c71e0c0f94a30f988a6876a2ae6/opentelemetry_api-1.40.0.tar.gz", hash = "sha256:159be641c0b04d11e9ecd576906462773eb97ae1b657730f0ecf64d32071569f", size = 70851, upload-time = "2026-03-04T14:17:21.555Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5f/bf/93795954016c522008da367da292adceed71cca6ee1717e1d64c83089099/opentelemetry_api-1.40.0-py3-none-any.whl", hash = "sha256:82dd69331ae74b06f6a874704be0cfaa49a1650e1537d4a813b86ecef7d0ecf9", size = 68676, upload-time = "2026-03-04T14:17:01.24Z" },
+]
+
+[[package]]
+name = "opentelemetry-exporter-prometheus"
+version = "0.61b0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "opentelemetry-api" },
+ { name = "opentelemetry-sdk" },
+ { name = "prometheus-client" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/4a/20/9e818fd364d12e8d0cfdce4a3b2d82e24d98c4ceebb315de6b6770b5f214/opentelemetry_exporter_prometheus-0.61b0.tar.gz", hash = "sha256:7c4919bd8e79abd62b610767e80f42c9c3a06c5183f4dd9141eedeb57aea284b", size = 15136, upload-time = "2026-03-04T14:17:26.275Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/02/4a/b65d40e94d1d930aee73a1a2857211ee6ab10ce3686cbdae5eea78cd9d34/opentelemetry_exporter_prometheus-0.61b0-py3-none-any.whl", hash = "sha256:3013b41f4370143d48d219a2351473761423e5882fa4c213811eaefacba39cb7", size = 13149, upload-time = "2026-03-04T14:17:08.983Z" },
+]
+
+[[package]]
+name = "opentelemetry-proto"
+version = "1.40.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "protobuf" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/4c/77/dd38991db037fdfce45849491cb61de5ab000f49824a00230afb112a4392/opentelemetry_proto-1.40.0.tar.gz", hash = "sha256:03f639ca129ba513f5819810f5b1f42bcb371391405d99c168fe6937c62febcd", size = 45667, upload-time = "2026-03-04T14:17:31.194Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b9/b2/189b2577dde745b15625b3214302605b1353436219d42b7912e77fa8dc24/opentelemetry_proto-1.40.0-py3-none-any.whl", hash = "sha256:266c4385d88923a23d63e353e9761af0f47a6ed0d486979777fe4de59dc9b25f", size = 72073, upload-time = "2026-03-04T14:17:16.673Z" },
+]
+
+[[package]]
+name = "opentelemetry-sdk"
+version = "1.40.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "opentelemetry-api" },
+ { name = "opentelemetry-semantic-conventions" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/58/fd/3c3125b20ba18ce2155ba9ea74acb0ae5d25f8cd39cfd37455601b7955cc/opentelemetry_sdk-1.40.0.tar.gz", hash = "sha256:18e9f5ec20d859d268c7cb3c5198c8d105d073714db3de50b593b8c1345a48f2", size = 184252, upload-time = "2026-03-04T14:17:31.87Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2c/c5/6a852903d8bfac758c6dc6e9a68b015d3c33f2f1be5e9591e0f4b69c7e0a/opentelemetry_sdk-1.40.0-py3-none-any.whl", hash = "sha256:787d2154a71f4b3d81f20524a8ce061b7db667d24e46753f32a7bc48f1c1f3f1", size = 141951, upload-time = "2026-03-04T14:17:17.961Z" },
+]
+
+[[package]]
+name = "opentelemetry-semantic-conventions"
+version = "0.61b0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "opentelemetry-api" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/6d/c0/4ae7973f3c2cfd2b6e321f1675626f0dab0a97027cc7a297474c9c8f3d04/opentelemetry_semantic_conventions-0.61b0.tar.gz", hash = "sha256:072f65473c5d7c6dc0355b27d6c9d1a679d63b6d4b4b16a9773062cb7e31192a", size = 145755, upload-time = "2026-03-04T14:17:32.664Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b2/37/cc6a55e448deaa9b27377d087da8615a3416d8ad523d5960b78dbeadd02a/opentelemetry_semantic_conventions-0.61b0-py3-none-any.whl", hash = "sha256:fa530a96be229795f8cef353739b618148b0fe2b4b3f005e60e262926c4d38e2", size = 231621, upload-time = "2026-03-04T14:17:19.33Z" },
+]
+
+[[package]]
+name = "orjson"
+version = "3.11.7"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/53/45/b268004f745ede84e5798b48ee12b05129d19235d0e15267aa57dcdb400b/orjson-3.11.7.tar.gz", hash = "sha256:9b1a67243945819ce55d24a30b59d6a168e86220452d2c96f4d1f093e71c0c49", size = 6144992, upload-time = "2026-02-02T15:38:49.29Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/80/bf/76f4f1665f6983385938f0e2a5d7efa12a58171b8456c252f3bae8a4cf75/orjson-3.11.7-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:bd03ea7606833655048dab1a00734a2875e3e86c276e1d772b2a02556f0d895f", size = 228545, upload-time = "2026-02-02T15:37:46.376Z" },
+ { url = "https://files.pythonhosted.org/packages/79/53/6c72c002cb13b5a978a068add59b25a8bdf2800ac1c9c8ecdb26d6d97064/orjson-3.11.7-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:89e440ebc74ce8ab5c7bc4ce6757b4a6b1041becb127df818f6997b5c71aa60b", size = 125224, upload-time = "2026-02-02T15:37:47.697Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/83/10e48852865e5dd151bdfe652c06f7da484578ed02c5fca938e3632cb0b8/orjson-3.11.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ede977b5fe5ac91b1dffc0a517ca4542d2ec8a6a4ff7b2652d94f640796342a", size = 128154, upload-time = "2026-02-02T15:37:48.954Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/52/a66e22a2b9abaa374b4a081d410edab6d1e30024707b87eab7c734afe28d/orjson-3.11.7-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b7b1dae39230a393df353827c855a5f176271c23434cfd2db74e0e424e693e10", size = 123548, upload-time = "2026-02-02T15:37:50.187Z" },
+ { url = "https://files.pythonhosted.org/packages/de/38/605d371417021359f4910c496f764c48ceb8997605f8c25bf1dfe58c0ebe/orjson-3.11.7-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed46f17096e28fb28d2975834836a639af7278aa87c84f68ab08fbe5b8bd75fa", size = 129000, upload-time = "2026-02-02T15:37:51.426Z" },
+ { url = "https://files.pythonhosted.org/packages/44/98/af32e842b0ffd2335c89714d48ca4e3917b42f5d6ee5537832e069a4b3ac/orjson-3.11.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3726be79e36e526e3d9c1aceaadbfb4a04ee80a72ab47b3f3c17fefb9812e7b8", size = 141686, upload-time = "2026-02-02T15:37:52.607Z" },
+ { url = "https://files.pythonhosted.org/packages/96/0b/fc793858dfa54be6feee940c1463370ece34b3c39c1ca0aa3845f5ba9892/orjson-3.11.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0724e265bc548af1dedebd9cb3d24b4e1c1e685a343be43e87ba922a5c5fff2f", size = 130812, upload-time = "2026-02-02T15:37:53.944Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/91/98a52415059db3f374757d0b7f0f16e3b5cd5976c90d1c2b56acaea039e6/orjson-3.11.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7745312efa9e11c17fbd3cb3097262d079da26930ae9ae7ba28fb738367cbad", size = 133440, upload-time = "2026-02-02T15:37:55.615Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/b6/cb540117bda61791f46381f8c26c8f93e802892830a6055748d3bb1925ab/orjson-3.11.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f904c24bdeabd4298f7a977ef14ca2a022ca921ed670b92ecd16ab6f3d01f867", size = 138386, upload-time = "2026-02-02T15:37:56.814Z" },
+ { url = "https://files.pythonhosted.org/packages/63/1a/50a3201c334a7f17c231eee5f841342190723794e3b06293f26e7cf87d31/orjson-3.11.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b9fc4d0f81f394689e0814617aadc4f2ea0e8025f38c226cbf22d3b5ddbf025d", size = 408853, upload-time = "2026-02-02T15:37:58.291Z" },
+ { url = "https://files.pythonhosted.org/packages/87/cd/8de1c67d0be44fdc22701e5989c0d015a2adf391498ad42c4dc589cd3013/orjson-3.11.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:849e38203e5be40b776ed2718e587faf204d184fc9a008ae441f9442320c0cab", size = 144130, upload-time = "2026-02-02T15:38:00.163Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/fe/d605d700c35dd55f51710d159fc54516a280923cd1b7e47508982fbb387d/orjson-3.11.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4682d1db3bcebd2b64757e0ddf9e87ae5f00d29d16c5cdf3a62f561d08cc3dd2", size = 134818, upload-time = "2026-02-02T15:38:01.507Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/e4/15ecc67edb3ddb3e2f46ae04475f2d294e8b60c1825fbe28a428b93b3fbd/orjson-3.11.7-cp312-cp312-win32.whl", hash = "sha256:f4f7c956b5215d949a1f65334cf9d7612dde38f20a95f2315deef167def91a6f", size = 127923, upload-time = "2026-02-02T15:38:02.75Z" },
+ { url = "https://files.pythonhosted.org/packages/34/70/2e0855361f76198a3965273048c8e50a9695d88cd75811a5b46444895845/orjson-3.11.7-cp312-cp312-win_amd64.whl", hash = "sha256:bf742e149121dc5648ba0a08ea0871e87b660467ef168a3a5e53bc1fbd64bb74", size = 125007, upload-time = "2026-02-02T15:38:04.032Z" },
+ { url = "https://files.pythonhosted.org/packages/68/40/c2051bd19fc467610fed469dc29e43ac65891571138f476834ca192bc290/orjson-3.11.7-cp312-cp312-win_arm64.whl", hash = "sha256:26c3b9132f783b7d7903bf1efb095fed8d4a3a85ec0d334ee8beff3d7a4749d5", size = 126089, upload-time = "2026-02-02T15:38:05.297Z" },
+ { url = "https://files.pythonhosted.org/packages/89/25/6e0e52cac5aab51d7b6dcd257e855e1dec1c2060f6b28566c509b4665f62/orjson-3.11.7-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:1d98b30cc1313d52d4af17d9c3d307b08389752ec5f2e5febdfada70b0f8c733", size = 228390, upload-time = "2026-02-02T15:38:06.8Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/29/a77f48d2fc8a05bbc529e5ff481fb43d914f9e383ea2469d4f3d51df3d00/orjson-3.11.7-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:d897e81f8d0cbd2abb82226d1860ad2e1ab3ff16d7b08c96ca00df9d45409ef4", size = 125189, upload-time = "2026-02-02T15:38:08.181Z" },
+ { url = "https://files.pythonhosted.org/packages/89/25/0a16e0729a0e6a1504f9d1a13cdd365f030068aab64cec6958396b9969d7/orjson-3.11.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:814be4b49b228cfc0b3c565acf642dd7d13538f966e3ccde61f4f55be3e20785", size = 128106, upload-time = "2026-02-02T15:38:09.41Z" },
+ { url = "https://files.pythonhosted.org/packages/66/da/a2e505469d60666a05ab373f1a6322eb671cb2ba3a0ccfc7d4bc97196787/orjson-3.11.7-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d06e5c5fed5caedd2e540d62e5b1c25e8c82431b9e577c33537e5fa4aa909539", size = 123363, upload-time = "2026-02-02T15:38:10.73Z" },
+ { url = "https://files.pythonhosted.org/packages/23/bf/ed73f88396ea35c71b38961734ea4a4746f7ca0768bf28fd551d37e48dd0/orjson-3.11.7-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:31c80ce534ac4ea3739c5ee751270646cbc46e45aea7576a38ffec040b4029a1", size = 129007, upload-time = "2026-02-02T15:38:12.138Z" },
+ { url = "https://files.pythonhosted.org/packages/73/3c/b05d80716f0225fc9008fbf8ab22841dcc268a626aa550561743714ce3bf/orjson-3.11.7-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f50979824bde13d32b4320eedd513431c921102796d86be3eee0b58e58a3ecd1", size = 141667, upload-time = "2026-02-02T15:38:13.398Z" },
+ { url = "https://files.pythonhosted.org/packages/61/e8/0be9b0addd9bf86abfc938e97441dcd0375d494594b1c8ad10fe57479617/orjson-3.11.7-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e54f3808e2b6b945078c41aa8d9b5834b28c50843846e97807e5adb75fa9705", size = 130832, upload-time = "2026-02-02T15:38:14.698Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/ec/c68e3b9021a31d9ec15a94931db1410136af862955854ed5dd7e7e4f5bff/orjson-3.11.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a12b80df61aab7b98b490fe9e4879925ba666fccdfcd175252ce4d9035865ace", size = 133373, upload-time = "2026-02-02T15:38:16.109Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/45/f3466739aaafa570cc8e77c6dbb853c48bf56e3b43738020e2661e08b0ac/orjson-3.11.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:996b65230271f1a97026fd0e6a753f51fbc0c335d2ad0c6201f711b0da32693b", size = 138307, upload-time = "2026-02-02T15:38:17.453Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/84/9f7f02288da1ffb31405c1be07657afd1eecbcb4b64ee2817b6fe0f785fa/orjson-3.11.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ab49d4b2a6a1d415ddb9f37a21e02e0d5dbfe10b7870b21bf779fc21e9156157", size = 408695, upload-time = "2026-02-02T15:38:18.831Z" },
+ { url = "https://files.pythonhosted.org/packages/18/07/9dd2f0c0104f1a0295ffbe912bc8d63307a539b900dd9e2c48ef7810d971/orjson-3.11.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:390a1dce0c055ddf8adb6aa94a73b45a4a7d7177b5c584b8d1c1947f2ba60fb3", size = 144099, upload-time = "2026-02-02T15:38:20.28Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/66/857a8e4a3292e1f7b1b202883bcdeb43a91566cf59a93f97c53b44bd6801/orjson-3.11.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1eb80451a9c351a71dfaf5b7ccc13ad065405217726b59fdbeadbcc544f9d223", size = 134806, upload-time = "2026-02-02T15:38:22.186Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/5b/6ebcf3defc1aab3a338ca777214966851e92efb1f30dc7fc8285216e6d1b/orjson-3.11.7-cp313-cp313-win32.whl", hash = "sha256:7477aa6a6ec6139c5cb1cc7b214643592169a5494d200397c7fc95d740d5fcf3", size = 127914, upload-time = "2026-02-02T15:38:23.511Z" },
+ { url = "https://files.pythonhosted.org/packages/00/04/c6f72daca5092e3117840a1b1e88dfc809cc1470cf0734890d0366b684a1/orjson-3.11.7-cp313-cp313-win_amd64.whl", hash = "sha256:b9f95dcdea9d4f805daa9ddf02617a89e484c6985fa03055459f90e87d7a0757", size = 124986, upload-time = "2026-02-02T15:38:24.836Z" },
+ { url = "https://files.pythonhosted.org/packages/03/ba/077a0f6f1085d6b806937246860fafbd5b17f3919c70ee3f3d8d9c713f38/orjson-3.11.7-cp313-cp313-win_arm64.whl", hash = "sha256:800988273a014a0541483dc81021247d7eacb0c845a9d1a34a422bc718f41539", size = 126045, upload-time = "2026-02-02T15:38:26.216Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/1e/745565dca749813db9a093c5ebc4bac1a9475c64d54b95654336ac3ed961/orjson-3.11.7-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:de0a37f21d0d364954ad5de1970491d7fbd0fb1ef7417d4d56a36dc01ba0c0a0", size = 228391, upload-time = "2026-02-02T15:38:27.757Z" },
+ { url = "https://files.pythonhosted.org/packages/46/19/e40f6225da4d3aa0c8dc6e5219c5e87c2063a560fe0d72a88deb59776794/orjson-3.11.7-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:c2428d358d85e8da9d37cba18b8c4047c55222007a84f97156a5b22028dfbfc0", size = 125188, upload-time = "2026-02-02T15:38:29.241Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/7e/c4de2babef2c0817fd1f048fd176aa48c37bec8aef53d2fa932983032cce/orjson-3.11.7-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c4bc6c6ac52cdaa267552544c73e486fecbd710b7ac09bc024d5a78555a22f6", size = 128097, upload-time = "2026-02-02T15:38:30.618Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/74/233d360632bafd2197f217eee7fb9c9d0229eac0c18128aee5b35b0014fe/orjson-3.11.7-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd0d68edd7dfca1b2eca9361a44ac9f24b078de3481003159929a0573f21a6bf", size = 123364, upload-time = "2026-02-02T15:38:32.363Z" },
+ { url = "https://files.pythonhosted.org/packages/79/51/af79504981dd31efe20a9e360eb49c15f06df2b40e7f25a0a52d9ae888e8/orjson-3.11.7-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:623ad1b9548ef63886319c16fa317848e465a21513b31a6ad7b57443c3e0dcf5", size = 129076, upload-time = "2026-02-02T15:38:33.68Z" },
+ { url = "https://files.pythonhosted.org/packages/67/e2/da898eb68b72304f8de05ca6715870d09d603ee98d30a27e8a9629abc64b/orjson-3.11.7-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6e776b998ac37c0396093d10290e60283f59cfe0fc3fccbd0ccc4bd04dd19892", size = 141705, upload-time = "2026-02-02T15:38:34.989Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/89/15364d92acb3d903b029e28d834edb8780c2b97404cbf7929aa6b9abdb24/orjson-3.11.7-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:652c6c3af76716f4a9c290371ba2e390ede06f6603edb277b481daf37f6f464e", size = 130855, upload-time = "2026-02-02T15:38:36.379Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/8b/ecdad52d0b38d4b8f514be603e69ccd5eacf4e7241f972e37e79792212ec/orjson-3.11.7-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a56df3239294ea5964adf074c54bcc4f0ccd21636049a2cf3ca9cf03b5d03cf1", size = 133386, upload-time = "2026-02-02T15:38:37.704Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/0e/45e1dcf10e17d0924b7c9162f87ec7b4ca79e28a0548acf6a71788d3e108/orjson-3.11.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:bda117c4148e81f746655d5a3239ae9bd00cb7bc3ca178b5fc5a5997e9744183", size = 138295, upload-time = "2026-02-02T15:38:39.096Z" },
+ { url = "https://files.pythonhosted.org/packages/63/d7/4d2e8b03561257af0450f2845b91fbd111d7e526ccdf737267108075e0ba/orjson-3.11.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:23d6c20517a97a9daf1d48b580fcdc6f0516c6f4b5038823426033690b4d2650", size = 408720, upload-time = "2026-02-02T15:38:40.634Z" },
+ { url = "https://files.pythonhosted.org/packages/78/cf/d45343518282108b29c12a65892445fc51f9319dc3c552ceb51bb5905ed2/orjson-3.11.7-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:8ff206156006da5b847c9304b6308a01e8cdbc8cce824e2779a5ba71c3def141", size = 144152, upload-time = "2026-02-02T15:38:42.262Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/3a/d6001f51a7275aacd342e77b735c71fa04125a3f93c36fee4526bc8c654e/orjson-3.11.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:962d046ee1765f74a1da723f4b33e3b228fe3a48bd307acce5021dfefe0e29b2", size = 134814, upload-time = "2026-02-02T15:38:43.627Z" },
+ { url = "https://files.pythonhosted.org/packages/1d/d3/f19b47ce16820cc2c480f7f1723e17f6d411b3a295c60c8ad3aa9ff1c96a/orjson-3.11.7-cp314-cp314-win32.whl", hash = "sha256:89e13dd3f89f1c38a9c9eba5fbf7cdc2d1feca82f5f290864b4b7a6aac704576", size = 127997, upload-time = "2026-02-02T15:38:45.06Z" },
+ { url = "https://files.pythonhosted.org/packages/12/df/172771902943af54bf661a8d102bdf2e7f932127968080632bda6054b62c/orjson-3.11.7-cp314-cp314-win_amd64.whl", hash = "sha256:845c3e0d8ded9c9271cd79596b9b552448b885b97110f628fb687aee2eed11c1", size = 124985, upload-time = "2026-02-02T15:38:46.388Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/1c/f2a8d8a1b17514660a614ce5f7aac74b934e69f5abc2700cc7ced882a009/orjson-3.11.7-cp314-cp314-win_arm64.whl", hash = "sha256:4a2e9c5be347b937a2e0203866f12bba36082e89b402ddb9e927d5822e43088d", size = 126038, upload-time = "2026-02-02T15:38:47.703Z" },
+]
+
+[[package]]
+name = "packaging"
+version = "26.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" },
+]
+
+[[package]]
+name = "pandas"
+version = "3.0.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "numpy" },
+ { name = "python-dateutil" },
+ { name = "tzdata", marker = "sys_platform == 'emscripten' or sys_platform == 'win32'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/2e/0c/b28ed414f080ee0ad153f848586d61d1878f91689950f037f976ce15f6c8/pandas-3.0.1.tar.gz", hash = "sha256:4186a699674af418f655dbd420ed87f50d56b4cd6603784279d9eef6627823c8", size = 4641901, upload-time = "2026-02-17T22:20:16.434Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/37/51/b467209c08dae2c624873d7491ea47d2b47336e5403309d433ea79c38571/pandas-3.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:476f84f8c20c9f5bc47252b66b4bb25e1a9fc2fa98cead96744d8116cb85771d", size = 10344357, upload-time = "2026-02-17T22:18:38.262Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/f1/e2567ffc8951ab371db2e40b2fe068e36b81d8cf3260f06ae508700e5504/pandas-3.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0ab749dfba921edf641d4036c4c21c0b3ea70fea478165cb98a998fb2a261955", size = 9884543, upload-time = "2026-02-17T22:18:41.476Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/39/327802e0b6d693182403c144edacbc27eb82907b57062f23ef5a4c4a5ea7/pandas-3.0.1-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8e36891080b87823aff3640c78649b91b8ff6eea3c0d70aeabd72ea43ab069b", size = 10396030, upload-time = "2026-02-17T22:18:43.822Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/fe/89d77e424365280b79d99b3e1e7d606f5165af2f2ecfaf0c6d24c799d607/pandas-3.0.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:532527a701281b9dd371e2f582ed9094f4c12dd9ffb82c0c54ee28d8ac9520c4", size = 10876435, upload-time = "2026-02-17T22:18:45.954Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/a6/2a75320849dd154a793f69c951db759aedb8d1dd3939eeacda9bdcfa1629/pandas-3.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:356e5c055ed9b0da1580d465657bc7d00635af4fd47f30afb23025352ba764d1", size = 11405133, upload-time = "2026-02-17T22:18:48.533Z" },
+ { url = "https://files.pythonhosted.org/packages/58/53/1d68fafb2e02d7881df66aa53be4cd748d25cbe311f3b3c85c93ea5d30ca/pandas-3.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9d810036895f9ad6345b8f2a338dd6998a74e8483847403582cab67745bff821", size = 11932065, upload-time = "2026-02-17T22:18:50.837Z" },
+ { url = "https://files.pythonhosted.org/packages/75/08/67cc404b3a966b6df27b38370ddd96b3b023030b572283d035181854aac5/pandas-3.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:536232a5fe26dd989bd633e7a0c450705fdc86a207fec7254a55e9a22950fe43", size = 9741627, upload-time = "2026-02-17T22:18:53.905Z" },
+ { url = "https://files.pythonhosted.org/packages/86/4f/caf9952948fb00d23795f09b893d11f1cacb384e666854d87249530f7cbe/pandas-3.0.1-cp312-cp312-win_arm64.whl", hash = "sha256:0f463ebfd8de7f326d38037c7363c6dacb857c5881ab8961fb387804d6daf2f7", size = 9052483, upload-time = "2026-02-17T22:18:57.31Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/48/aad6ec4f8d007534c091e9a7172b3ec1b1ee6d99a9cbb936b5eab6c6cf58/pandas-3.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5272627187b5d9c20e55d27caf5f2cd23e286aba25cadf73c8590e432e2b7262", size = 10317509, upload-time = "2026-02-17T22:18:59.498Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/14/5990826f779f79148ae9d3a2c39593dc04d61d5d90541e71b5749f35af95/pandas-3.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:661e0f665932af88c7877f31da0dc743fe9c8f2524bdffe23d24fdcb67ef9d56", size = 9860561, upload-time = "2026-02-17T22:19:02.265Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/80/f01ff54664b6d70fed71475543d108a9b7c888e923ad210795bef04ffb7d/pandas-3.0.1-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:75e6e292ff898679e47a2199172593d9f6107fd2dd3617c22c2946e97d5df46e", size = 10365506, upload-time = "2026-02-17T22:19:05.017Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/85/ab6d04733a7d6ff32bfc8382bf1b07078228f5d6ebec5266b91bfc5c4ff7/pandas-3.0.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1ff8cf1d2896e34343197685f432450ec99a85ba8d90cce2030c5eee2ef98791", size = 10873196, upload-time = "2026-02-17T22:19:07.204Z" },
+ { url = "https://files.pythonhosted.org/packages/48/a9/9301c83d0b47c23ac5deab91c6b39fd98d5b5db4d93b25df8d381451828f/pandas-3.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:eca8b4510f6763f3d37359c2105df03a7a221a508f30e396a51d0713d462e68a", size = 11370859, upload-time = "2026-02-17T22:19:09.436Z" },
+ { url = "https://files.pythonhosted.org/packages/59/fe/0c1fc5bd2d29c7db2ab372330063ad555fb83e08422829c785f5ec2176ca/pandas-3.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:06aff2ad6f0b94a17822cf8b83bbb563b090ed82ff4fe7712db2ce57cd50d9b8", size = 11924584, upload-time = "2026-02-17T22:19:11.562Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/7d/216a1588b65a7aa5f4535570418a599d943c85afb1d95b0876fc00aa1468/pandas-3.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:9fea306c783e28884c29057a1d9baa11a349bbf99538ec1da44c8476563d1b25", size = 9742769, upload-time = "2026-02-17T22:19:13.926Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/cb/810a22a6af9a4e97c8ab1c946b47f3489c5bca5adc483ce0ffc84c9cc768/pandas-3.0.1-cp313-cp313-win_arm64.whl", hash = "sha256:a8d37a43c52917427e897cb2e429f67a449327394396a81034a4449b99afda59", size = 9043855, upload-time = "2026-02-17T22:19:16.09Z" },
+ { url = "https://files.pythonhosted.org/packages/92/fa/423c89086cca1f039cf1253c3ff5b90f157b5b3757314aa635f6bf3e30aa/pandas-3.0.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d54855f04f8246ed7b6fc96b05d4871591143c46c0b6f4af874764ed0d2d6f06", size = 10752673, upload-time = "2026-02-17T22:19:18.304Z" },
+ { url = "https://files.pythonhosted.org/packages/22/23/b5a08ec1f40020397f0faba72f1e2c11f7596a6169c7b3e800abff0e433f/pandas-3.0.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4e1b677accee34a09e0dc2ce5624e4a58a1870ffe56fc021e9caf7f23cd7668f", size = 10404967, upload-time = "2026-02-17T22:19:20.726Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/81/94841f1bb4afdc2b52a99daa895ac2c61600bb72e26525ecc9543d453ebc/pandas-3.0.1-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a9cabbdcd03f1b6cd254d6dda8ae09b0252524be1592594c00b7895916cb1324", size = 10320575, upload-time = "2026-02-17T22:19:24.919Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/8b/2ae37d66a5342a83adadfd0cb0b4bf9c3c7925424dd5f40d15d6cfaa35ee/pandas-3.0.1-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5ae2ab1f166668b41e770650101e7090824fd34d17915dd9cd479f5c5e0065e9", size = 10710921, upload-time = "2026-02-17T22:19:27.181Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/61/772b2e2757855e232b7ccf7cb8079a5711becb3a97f291c953def15a833f/pandas-3.0.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6bf0603c2e30e2cafac32807b06435f28741135cb8697eae8b28c7d492fc7d76", size = 11334191, upload-time = "2026-02-17T22:19:29.411Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/08/b16c6df3ef555d8495d1d265a7963b65be166785d28f06a350913a4fac78/pandas-3.0.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6c426422973973cae1f4a23e51d4ae85974f44871b24844e4f7de752dd877098", size = 11782256, upload-time = "2026-02-17T22:19:32.34Z" },
+ { url = "https://files.pythonhosted.org/packages/55/80/178af0594890dee17e239fca96d3d8670ba0f5ff59b7d0439850924a9c09/pandas-3.0.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b03f91ae8c10a85c1613102c7bef5229b5379f343030a3ccefeca8a33414cf35", size = 10485047, upload-time = "2026-02-17T22:19:34.605Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/8b/4bb774a998b97e6c2fd62a9e6cfdaae133b636fd1c468f92afb4ae9a447a/pandas-3.0.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:99d0f92ed92d3083d140bf6b97774f9f13863924cf3f52a70711f4e7588f9d0a", size = 10322465, upload-time = "2026-02-17T22:19:36.803Z" },
+ { url = "https://files.pythonhosted.org/packages/72/3a/5b39b51c64159f470f1ca3b1c2a87da290657ca022f7cd11442606f607d1/pandas-3.0.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3b66857e983208654294bb6477b8a63dee26b37bdd0eb34d010556e91261784f", size = 9910632, upload-time = "2026-02-17T22:19:39.001Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/f7/b449ffb3f68c11da12fc06fbf6d2fa3a41c41e17d0284d23a79e1c13a7e4/pandas-3.0.1-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:56cf59638bf24dc9bdf2154c81e248b3289f9a09a6d04e63608c159022352749", size = 10440535, upload-time = "2026-02-17T22:19:41.157Z" },
+ { url = "https://files.pythonhosted.org/packages/55/77/6ea82043db22cb0f2bbfe7198da3544000ddaadb12d26be36e19b03a2dc5/pandas-3.0.1-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c1a9f55e0f46951874b863d1f3906dcb57df2d9be5c5847ba4dfb55b2c815249", size = 10893940, upload-time = "2026-02-17T22:19:43.493Z" },
+ { url = "https://files.pythonhosted.org/packages/03/30/f1b502a72468c89412c1b882a08f6eed8a4ee9dc033f35f65d0663df6081/pandas-3.0.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1849f0bba9c8a2fb0f691d492b834cc8dadf617e29015c66e989448d58d011ee", size = 11442711, upload-time = "2026-02-17T22:19:46.074Z" },
+ { url = "https://files.pythonhosted.org/packages/0d/f0/ebb6ddd8fc049e98cabac5c2924d14d1dda26a20adb70d41ea2e428d3ec4/pandas-3.0.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c3d288439e11b5325b02ae6e9cc83e6805a62c40c5a6220bea9beb899c073b1c", size = 11963918, upload-time = "2026-02-17T22:19:48.838Z" },
+ { url = "https://files.pythonhosted.org/packages/09/f8/8ce132104074f977f907442790eaae24e27bce3b3b454e82faa3237ff098/pandas-3.0.1-cp314-cp314-win_amd64.whl", hash = "sha256:93325b0fe372d192965f4cca88d97667f49557398bbf94abdda3bf1b591dbe66", size = 9862099, upload-time = "2026-02-17T22:19:51.081Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/b7/6af9aac41ef2456b768ef0ae60acf8abcebb450a52043d030a65b4b7c9bd/pandas-3.0.1-cp314-cp314-win_arm64.whl", hash = "sha256:97ca08674e3287c7148f4858b01136f8bdfe7202ad25ad04fec602dd1d29d132", size = 9185333, upload-time = "2026-02-17T22:19:53.266Z" },
+ { url = "https://files.pythonhosted.org/packages/66/fc/848bb6710bc6061cb0c5badd65b92ff75c81302e0e31e496d00029fe4953/pandas-3.0.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:58eeb1b2e0fb322befcf2bbc9ba0af41e616abadb3d3414a6bc7167f6cbfce32", size = 10772664, upload-time = "2026-02-17T22:19:55.806Z" },
+ { url = "https://files.pythonhosted.org/packages/69/5c/866a9bbd0f79263b4b0db6ec1a341be13a1473323f05c122388e0f15b21d/pandas-3.0.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:cd9af1276b5ca9e298bd79a26bda32fa9cc87ed095b2a9a60978d2ca058eaf87", size = 10421286, upload-time = "2026-02-17T22:19:58.091Z" },
+ { url = "https://files.pythonhosted.org/packages/51/a4/2058fb84fb1cfbfb2d4a6d485e1940bb4ad5716e539d779852494479c580/pandas-3.0.1-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94f87a04984d6b63788327cd9f79dda62b7f9043909d2440ceccf709249ca988", size = 10342050, upload-time = "2026-02-17T22:20:01.376Z" },
+ { url = "https://files.pythonhosted.org/packages/22/1b/674e89996cc4be74db3c4eb09240c4bb549865c9c3f5d9b086ff8fcfbf00/pandas-3.0.1-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85fe4c4df62e1e20f9db6ebfb88c844b092c22cd5324bdcf94bfa2fc1b391221", size = 10740055, upload-time = "2026-02-17T22:20:04.328Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/f8/e954b750764298c22fa4614376531fe63c521ef517e7059a51f062b87dca/pandas-3.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:331ca75a2f8672c365ae25c0b29e46f5ac0c6551fdace8eec4cd65e4fac271ff", size = 11357632, upload-time = "2026-02-17T22:20:06.647Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/02/c6e04b694ffd68568297abd03588b6d30295265176a5c01b7459d3bc35a3/pandas-3.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:15860b1fdb1973fffade772fdb931ccf9b2f400a3f5665aef94a00445d7d8dd5", size = 11810974, upload-time = "2026-02-17T22:20:08.946Z" },
+ { url = "https://files.pythonhosted.org/packages/89/41/d7dfb63d2407f12055215070c42fc6ac41b66e90a2946cdc5e759058398b/pandas-3.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:44f1364411d5670efa692b146c748f4ed013df91ee91e9bec5677fb1fd58b937", size = 10884622, upload-time = "2026-02-17T22:20:11.711Z" },
+ { url = "https://files.pythonhosted.org/packages/68/b0/34937815889fa982613775e4b97fddd13250f11012d769949c5465af2150/pandas-3.0.1-cp314-cp314t-win_arm64.whl", hash = "sha256:108dd1790337a494aa80e38def654ca3f0968cf4f362c85f44c15e471667102d", size = 9452085, upload-time = "2026-02-17T22:20:14.331Z" },
+]
+
+[[package]]
+name = "pillow"
+version = "12.1.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/1f/42/5c74462b4fd957fcd7b13b04fb3205ff8349236ea74c7c375766d6c82288/pillow-12.1.1.tar.gz", hash = "sha256:9ad8fa5937ab05218e2b6a4cff30295ad35afd2f83ac592e68c0d871bb0fdbc4", size = 46980264, upload-time = "2026-02-11T04:23:07.146Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/07/d3/8df65da0d4df36b094351dce696f2989bec731d4f10e743b1c5f4da4d3bf/pillow-12.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ab323b787d6e18b3d91a72fc99b1a2c28651e4358749842b8f8dfacd28ef2052", size = 5262803, upload-time = "2026-02-11T04:20:47.653Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/71/5026395b290ff404b836e636f51d7297e6c83beceaa87c592718747e670f/pillow-12.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:adebb5bee0f0af4909c30db0d890c773d1a92ffe83da908e2e9e720f8edf3984", size = 4657601, upload-time = "2026-02-11T04:20:49.328Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/2e/1001613d941c67442f745aff0f7cc66dd8df9a9c084eb497e6a543ee6f7e/pillow-12.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bb66b7cc26f50977108790e2456b7921e773f23db5630261102233eb355a3b79", size = 6234995, upload-time = "2026-02-11T04:20:51.032Z" },
+ { url = "https://files.pythonhosted.org/packages/07/26/246ab11455b2549b9233dbd44d358d033a2f780fa9007b61a913c5b2d24e/pillow-12.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aee2810642b2898bb187ced9b349e95d2a7272930796e022efaf12e99dccd293", size = 8045012, upload-time = "2026-02-11T04:20:52.882Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/8b/07587069c27be7535ac1fe33874e32de118fbd34e2a73b7f83436a88368c/pillow-12.1.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a0b1cd6232e2b618adcc54d9882e4e662a089d5768cd188f7c245b4c8c44a397", size = 6349638, upload-time = "2026-02-11T04:20:54.444Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/79/6df7b2ee763d619cda2fb4fea498e5f79d984dae304d45a8999b80d6cf5c/pillow-12.1.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7aac39bcf8d4770d089588a2e1dd111cbaa42df5a94be3114222057d68336bd0", size = 7041540, upload-time = "2026-02-11T04:20:55.97Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/5e/2ba19e7e7236d7529f4d873bdaf317a318896bac289abebd4bb00ef247f0/pillow-12.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ab174cd7d29a62dd139c44bf74b698039328f45cb03b4596c43473a46656b2f3", size = 6462613, upload-time = "2026-02-11T04:20:57.542Z" },
+ { url = "https://files.pythonhosted.org/packages/03/03/31216ec124bb5c3dacd74ce8efff4cc7f52643653bad4825f8f08c697743/pillow-12.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:339ffdcb7cbeaa08221cd401d517d4b1fe7a9ed5d400e4a8039719238620ca35", size = 7166745, upload-time = "2026-02-11T04:20:59.196Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/e7/7c4552d80052337eb28653b617eafdef39adfb137c49dd7e831b8dc13bc5/pillow-12.1.1-cp312-cp312-win32.whl", hash = "sha256:5d1f9575a12bed9e9eedd9a4972834b08c97a352bd17955ccdebfeca5913fa0a", size = 6328823, upload-time = "2026-02-11T04:21:01.385Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/17/688626d192d7261bbbf98846fc98995726bddc2c945344b65bec3a29d731/pillow-12.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:21329ec8c96c6e979cd0dfd29406c40c1d52521a90544463057d2aaa937d66a6", size = 7033367, upload-time = "2026-02-11T04:21:03.536Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/fe/a0ef1f73f939b0eca03ee2c108d0043a87468664770612602c63266a43c4/pillow-12.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:af9a332e572978f0218686636610555ae3defd1633597be015ed50289a03c523", size = 2453811, upload-time = "2026-02-11T04:21:05.116Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/11/6db24d4bd7685583caeae54b7009584e38da3c3d4488ed4cd25b439de486/pillow-12.1.1-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:d242e8ac078781f1de88bf823d70c1a9b3c7950a44cdf4b7c012e22ccbcd8e4e", size = 4062689, upload-time = "2026-02-11T04:21:06.804Z" },
+ { url = "https://files.pythonhosted.org/packages/33/c0/ce6d3b1fe190f0021203e0d9b5b99e57843e345f15f9ef22fcd43842fd21/pillow-12.1.1-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:02f84dfad02693676692746df05b89cf25597560db2857363a208e393429f5e9", size = 4138535, upload-time = "2026-02-11T04:21:08.452Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/c6/d5eb6a4fb32a3f9c21a8c7613ec706534ea1cf9f4b3663e99f0d83f6fca8/pillow-12.1.1-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:e65498daf4b583091ccbb2556c7000abf0f3349fcd57ef7adc9a84a394ed29f6", size = 3601364, upload-time = "2026-02-11T04:21:10.194Z" },
+ { url = "https://files.pythonhosted.org/packages/14/a1/16c4b823838ba4c9c52c0e6bbda903a3fe5a1bdbf1b8eb4fff7156f3e318/pillow-12.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6c6db3b84c87d48d0088943bf33440e0c42370b99b1c2a7989216f7b42eede60", size = 5262561, upload-time = "2026-02-11T04:21:11.742Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/ad/ad9dc98ff24f485008aa5cdedaf1a219876f6f6c42a4626c08bc4e80b120/pillow-12.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8b7e5304e34942bf62e15184219a7b5ad4ff7f3bb5cca4d984f37df1a0e1aee2", size = 4657460, upload-time = "2026-02-11T04:21:13.786Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/1b/f1a4ea9a895b5732152789326202a82464d5254759fbacae4deea3069334/pillow-12.1.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:18e5bddd742a44b7e6b1e773ab5db102bd7a94c32555ba656e76d319d19c3850", size = 6232698, upload-time = "2026-02-11T04:21:15.949Z" },
+ { url = "https://files.pythonhosted.org/packages/95/f4/86f51b8745070daf21fd2e5b1fe0eb35d4db9ca26e6d58366562fb56a743/pillow-12.1.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc44ef1f3de4f45b50ccf9136999d71abb99dca7706bc75d222ed350b9fd2289", size = 8041706, upload-time = "2026-02-11T04:21:17.723Z" },
+ { url = "https://files.pythonhosted.org/packages/29/9b/d6ecd956bb1266dd1045e995cce9b8d77759e740953a1c9aad9502a0461e/pillow-12.1.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5a8eb7ed8d4198bccbd07058416eeec51686b498e784eda166395a23eb99138e", size = 6346621, upload-time = "2026-02-11T04:21:19.547Z" },
+ { url = "https://files.pythonhosted.org/packages/71/24/538bff45bde96535d7d998c6fed1a751c75ac7c53c37c90dc2601b243893/pillow-12.1.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:47b94983da0c642de92ced1702c5b6c292a84bd3a8e1d1702ff923f183594717", size = 7038069, upload-time = "2026-02-11T04:21:21.378Z" },
+ { url = "https://files.pythonhosted.org/packages/94/0e/58cb1a6bc48f746bc4cb3adb8cabff73e2742c92b3bf7a220b7cf69b9177/pillow-12.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:518a48c2aab7ce596d3bf79d0e275661b846e86e4d0e7dec34712c30fe07f02a", size = 6460040, upload-time = "2026-02-11T04:21:23.148Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/57/9045cb3ff11eeb6c1adce3b2d60d7d299d7b273a2e6c8381a524abfdc474/pillow-12.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a550ae29b95c6dc13cf69e2c9dc5747f814c54eeb2e32d683e5e93af56caa029", size = 7164523, upload-time = "2026-02-11T04:21:25.01Z" },
+ { url = "https://files.pythonhosted.org/packages/73/f2/9be9cb99f2175f0d4dbadd6616ce1bf068ee54a28277ea1bf1fbf729c250/pillow-12.1.1-cp313-cp313-win32.whl", hash = "sha256:a003d7422449f6d1e3a34e3dd4110c22148336918ddbfc6a32581cd54b2e0b2b", size = 6332552, upload-time = "2026-02-11T04:21:27.238Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/eb/b0834ad8b583d7d9d42b80becff092082a1c3c156bb582590fcc973f1c7c/pillow-12.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:344cf1e3dab3be4b1fa08e449323d98a2a3f819ad20f4b22e77a0ede31f0faa1", size = 7040108, upload-time = "2026-02-11T04:21:29.462Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/7d/fc09634e2aabdd0feabaff4a32f4a7d97789223e7c2042fd805ea4b4d2c2/pillow-12.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:5c0dd1636633e7e6a0afe7bf6a51a14992b7f8e60de5789018ebbdfae55b040a", size = 2453712, upload-time = "2026-02-11T04:21:31.072Z" },
+ { url = "https://files.pythonhosted.org/packages/19/2a/b9d62794fc8a0dd14c1943df68347badbd5511103e0d04c035ffe5cf2255/pillow-12.1.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0330d233c1a0ead844fc097a7d16c0abff4c12e856c0b325f231820fee1f39da", size = 5264880, upload-time = "2026-02-11T04:21:32.865Z" },
+ { url = "https://files.pythonhosted.org/packages/26/9d/e03d857d1347fa5ed9247e123fcd2a97b6220e15e9cb73ca0a8d91702c6e/pillow-12.1.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5dae5f21afb91322f2ff791895ddd8889e5e947ff59f71b46041c8ce6db790bc", size = 4660616, upload-time = "2026-02-11T04:21:34.97Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/ec/8a6d22afd02570d30954e043f09c32772bfe143ba9285e2fdb11284952cd/pillow-12.1.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2e0c664be47252947d870ac0d327fea7e63985a08794758aa8af5b6cb6ec0c9c", size = 6269008, upload-time = "2026-02-11T04:21:36.623Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/1d/6d875422c9f28a4a361f495a5f68d9de4a66941dc2c619103ca335fa6446/pillow-12.1.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:691ab2ac363b8217f7d31b3497108fb1f50faab2f75dfb03284ec2f217e87bf8", size = 8073226, upload-time = "2026-02-11T04:21:38.585Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/cd/134b0b6ee5eda6dc09e25e24b40fdafe11a520bc725c1d0bbaa5e00bf95b/pillow-12.1.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e9e8064fb1cc019296958595f6db671fba95209e3ceb0c4734c9baf97de04b20", size = 6380136, upload-time = "2026-02-11T04:21:40.562Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/a9/7628f013f18f001c1b98d8fffe3452f306a70dc6aba7d931019e0492f45e/pillow-12.1.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:472a8d7ded663e6162dafdf20015c486a7009483ca671cece7a9279b512fcb13", size = 7067129, upload-time = "2026-02-11T04:21:42.521Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/f8/66ab30a2193b277785601e82ee2d49f68ea575d9637e5e234faaa98efa4c/pillow-12.1.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:89b54027a766529136a06cfebeecb3a04900397a3590fd252160b888479517bf", size = 6491807, upload-time = "2026-02-11T04:21:44.22Z" },
+ { url = "https://files.pythonhosted.org/packages/da/0b/a877a6627dc8318fdb84e357c5e1a758c0941ab1ddffdafd231983788579/pillow-12.1.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:86172b0831b82ce4f7877f280055892b31179e1576aa00d0df3bb1bbf8c3e524", size = 7190954, upload-time = "2026-02-11T04:21:46.114Z" },
+ { url = "https://files.pythonhosted.org/packages/83/43/6f732ff85743cf746b1361b91665d9f5155e1483817f693f8d57ea93147f/pillow-12.1.1-cp313-cp313t-win32.whl", hash = "sha256:44ce27545b6efcf0fdbdceb31c9a5bdea9333e664cda58a7e674bb74608b3986", size = 6336441, upload-time = "2026-02-11T04:21:48.22Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/44/e865ef3986611bb75bfabdf94a590016ea327833f434558801122979cd0e/pillow-12.1.1-cp313-cp313t-win_amd64.whl", hash = "sha256:a285e3eb7a5a45a2ff504e31f4a8d1b12ef62e84e5411c6804a42197c1cf586c", size = 7045383, upload-time = "2026-02-11T04:21:50.015Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/c6/f4fb24268d0c6908b9f04143697ea18b0379490cb74ba9e8d41b898bd005/pillow-12.1.1-cp313-cp313t-win_arm64.whl", hash = "sha256:cc7d296b5ea4d29e6570dabeaed58d31c3fea35a633a69679fb03d7664f43fb3", size = 2456104, upload-time = "2026-02-11T04:21:51.633Z" },
+ { url = "https://files.pythonhosted.org/packages/03/d0/bebb3ffbf31c5a8e97241476c4cf8b9828954693ce6744b4a2326af3e16b/pillow-12.1.1-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:417423db963cb4be8bac3fc1204fe61610f6abeed1580a7a2cbb2fbda20f12af", size = 4062652, upload-time = "2026-02-11T04:21:53.19Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/c0/0e16fb0addda4851445c28f8350d8c512f09de27bbb0d6d0bbf8b6709605/pillow-12.1.1-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:b957b71c6b2387610f556a7eb0828afbe40b4a98036fc0d2acfa5a44a0c2036f", size = 4138823, upload-time = "2026-02-11T04:22:03.088Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/fb/6170ec655d6f6bb6630a013dd7cf7bc218423d7b5fa9071bf63dc32175ae/pillow-12.1.1-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:097690ba1f2efdeb165a20469d59d8bb03c55fb6621eb2041a060ae8ea3e9642", size = 3601143, upload-time = "2026-02-11T04:22:04.909Z" },
+ { url = "https://files.pythonhosted.org/packages/59/04/dc5c3f297510ba9a6837cbb318b87dd2b8f73eb41a43cc63767f65cb599c/pillow-12.1.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:2815a87ab27848db0321fb78c7f0b2c8649dee134b7f2b80c6a45c6831d75ccd", size = 5266254, upload-time = "2026-02-11T04:22:07.656Z" },
+ { url = "https://files.pythonhosted.org/packages/05/30/5db1236b0d6313f03ebf97f5e17cda9ca060f524b2fcc875149a8360b21c/pillow-12.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:f7ed2c6543bad5a7d5530eb9e78c53132f93dfa44a28492db88b41cdab885202", size = 4657499, upload-time = "2026-02-11T04:22:09.613Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/18/008d2ca0eb612e81968e8be0bbae5051efba24d52debf930126d7eaacbba/pillow-12.1.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:652a2c9ccfb556235b2b501a3a7cf3742148cd22e04b5625c5fe057ea3e3191f", size = 6232137, upload-time = "2026-02-11T04:22:11.434Z" },
+ { url = "https://files.pythonhosted.org/packages/70/f1/f14d5b8eeb4b2cd62b9f9f847eb6605f103df89ef619ac68f92f748614ea/pillow-12.1.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d6e4571eedf43af33d0fc233a382a76e849badbccdf1ac438841308652a08e1f", size = 8042721, upload-time = "2026-02-11T04:22:13.321Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/d6/17824509146e4babbdabf04d8171491fa9d776f7061ff6e727522df9bd03/pillow-12.1.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b574c51cf7d5d62e9be37ba446224b59a2da26dc4c1bb2ecbe936a4fb1a7cb7f", size = 6347798, upload-time = "2026-02-11T04:22:15.449Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/ee/c85a38a9ab92037a75615aba572c85ea51e605265036e00c5b67dfafbfe2/pillow-12.1.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a37691702ed687799de29a518d63d4682d9016932db66d4e90c345831b02fb4e", size = 7039315, upload-time = "2026-02-11T04:22:17.24Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/f3/bc8ccc6e08a148290d7523bde4d9a0d6c981db34631390dc6e6ec34cacf6/pillow-12.1.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f95c00d5d6700b2b890479664a06e754974848afaae5e21beb4d83c106923fd0", size = 6462360, upload-time = "2026-02-11T04:22:19.111Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/ab/69a42656adb1d0665ab051eec58a41f169ad295cf81ad45406963105408f/pillow-12.1.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:559b38da23606e68681337ad74622c4dbba02254fc9cb4488a305dd5975c7eeb", size = 7165438, upload-time = "2026-02-11T04:22:21.041Z" },
+ { url = "https://files.pythonhosted.org/packages/02/46/81f7aa8941873f0f01d4b55cc543b0a3d03ec2ee30d617a0448bf6bd6dec/pillow-12.1.1-cp314-cp314-win32.whl", hash = "sha256:03edcc34d688572014ff223c125a3f77fb08091e4607e7745002fc214070b35f", size = 6431503, upload-time = "2026-02-11T04:22:22.833Z" },
+ { url = "https://files.pythonhosted.org/packages/40/72/4c245f7d1044b67affc7f134a09ea619d4895333d35322b775b928180044/pillow-12.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:50480dcd74fa63b8e78235957d302d98d98d82ccbfac4c7e12108ba9ecbdba15", size = 7176748, upload-time = "2026-02-11T04:22:24.64Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/ad/8a87bdbe038c5c698736e3348af5c2194ffb872ea52f11894c95f9305435/pillow-12.1.1-cp314-cp314-win_arm64.whl", hash = "sha256:5cb1785d97b0c3d1d1a16bc1d710c4a0049daefc4935f3a8f31f827f4d3d2e7f", size = 2544314, upload-time = "2026-02-11T04:22:26.685Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/9d/efd18493f9de13b87ede7c47e69184b9e859e4427225ea962e32e56a49bc/pillow-12.1.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:1f90cff8aa76835cba5769f0b3121a22bd4eb9e6884cfe338216e557a9a548b8", size = 5268612, upload-time = "2026-02-11T04:22:29.884Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/f1/4f42eb2b388eb2ffc660dcb7f7b556c1015c53ebd5f7f754965ef997585b/pillow-12.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1f1be78ce9466a7ee64bfda57bdba0f7cc499d9794d518b854816c41bf0aa4e9", size = 4660567, upload-time = "2026-02-11T04:22:31.799Z" },
+ { url = "https://files.pythonhosted.org/packages/01/54/df6ef130fa43e4b82e32624a7b821a2be1c5653a5fdad8469687a7db4e00/pillow-12.1.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:42fc1f4677106188ad9a55562bbade416f8b55456f522430fadab3cef7cd4e60", size = 6269951, upload-time = "2026-02-11T04:22:33.921Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/48/618752d06cc44bb4aae8ce0cd4e6426871929ed7b46215638088270d9b34/pillow-12.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:98edb152429ab62a1818039744d8fbb3ccab98a7c29fc3d5fcef158f3f1f68b7", size = 8074769, upload-time = "2026-02-11T04:22:35.877Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/bd/f1d71eb39a72fa088d938655afba3e00b38018d052752f435838961127d8/pillow-12.1.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d470ab1178551dd17fdba0fef463359c41aaa613cdcd7ff8373f54be629f9f8f", size = 6381358, upload-time = "2026-02-11T04:22:37.698Z" },
+ { url = "https://files.pythonhosted.org/packages/64/ef/c784e20b96674ed36a5af839305f55616f8b4f8aa8eeccf8531a6e312243/pillow-12.1.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6408a7b064595afcab0a49393a413732a35788f2a5092fdc6266952ed67de586", size = 7068558, upload-time = "2026-02-11T04:22:39.597Z" },
+ { url = "https://files.pythonhosted.org/packages/73/cb/8059688b74422ae61278202c4e1ad992e8a2e7375227be0a21c6b87ca8d5/pillow-12.1.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5d8c41325b382c07799a3682c1c258469ea2ff97103c53717b7893862d0c98ce", size = 6493028, upload-time = "2026-02-11T04:22:42.73Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/da/e3c008ed7d2dd1f905b15949325934510b9d1931e5df999bb15972756818/pillow-12.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c7697918b5be27424e9ce568193efd13d925c4481dd364e43f5dff72d33e10f8", size = 7191940, upload-time = "2026-02-11T04:22:44.543Z" },
+ { url = "https://files.pythonhosted.org/packages/01/4a/9202e8d11714c1fc5951f2e1ef362f2d7fbc595e1f6717971d5dd750e969/pillow-12.1.1-cp314-cp314t-win32.whl", hash = "sha256:d2912fd8114fc5545aa3a4b5576512f64c55a03f3ebcca4c10194d593d43ea36", size = 6438736, upload-time = "2026-02-11T04:22:46.347Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/ca/cbce2327eb9885476b3957b2e82eb12c866a8b16ad77392864ad601022ce/pillow-12.1.1-cp314-cp314t-win_amd64.whl", hash = "sha256:4ceb838d4bd9dab43e06c363cab2eebf63846d6a4aeaea283bbdfd8f1a8ed58b", size = 7182894, upload-time = "2026-02-11T04:22:48.114Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/d2/de599c95ba0a973b94410477f8bf0b6f0b5e67360eb89bcb1ad365258beb/pillow-12.1.1-cp314-cp314t-win_arm64.whl", hash = "sha256:7b03048319bfc6170e93bd60728a1af51d3dd7704935feb228c4d4faab35d334", size = 2546446, upload-time = "2026-02-11T04:22:50.342Z" },
+]
+
+[[package]]
+name = "pillow-heif"
+version = "1.3.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pillow" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/cd/58/2df4fc42840633e01c97b75965cb1bc6e14425973b92382391650e97e4b7/pillow_heif-1.3.0.tar.gz", hash = "sha256:af8d2bda85e395677d5bb50d7bda3b5655c946cc95b913b5e7222fabacbb467f", size = 17133211, upload-time = "2026-02-27T12:21:36.465Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/67/f7/e0b13500470421536fdfe01acfc4c56daccd3d23655605aa04cfb30cc58c/pillow_heif-1.3.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:079abbcaeb42ef0849a33f35c1a96ccd431feb56b242a0d4f8435a1c8ca02c7d", size = 4667382, upload-time = "2026-02-27T12:20:45.149Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/fb/beb62f26231e7c76d235e993d18b4ddb3d2d427e93539b8e6eb8dc188fa7/pillow_heif-1.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76c33f80ec111492642b98309db98516a7fba9677dcda9ec5fe9111b7e38d720", size = 3392733, upload-time = "2026-02-27T12:20:46.606Z" },
+ { url = "https://files.pythonhosted.org/packages/14/58/3d86e237b3a20c909f62a50e8cb3492ed6206675136d1ebddb168920261b/pillow_heif-1.3.0-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:33b838d06e2fd730f806af5a76bfc4cd3de9d146d88d37572e40f7a4c4ff8221", size = 5844247, upload-time = "2026-02-27T12:20:49.669Z" },
+ { url = "https://files.pythonhosted.org/packages/58/2a/826faf3df8c9ef9a19dc96bdfff34cf76f8b025540d5f931903d2c64f25c/pillow_heif-1.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f92b387af891cf5d98f52e79eeaf51ee7955a54fe2deeec12bfb7519e41464b5", size = 5578692, upload-time = "2026-02-27T12:20:51.219Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/4e/59f74fede18e3e06f98a448488df2fa4e5de1c159419d47ca345a51a0da0/pillow_heif-1.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f9f73246836f93f99343cbc3052b61d212d27e59ddf40262d494a1e3e54af31a", size = 6885928, upload-time = "2026-02-27T12:20:52.934Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/e4/bce83d2f4d703f418d252b509a6c9d6de52dc7c4eedcf6a286f871dea824/pillow_heif-1.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:84c3816742c2e49176e651895e73c555b9c3b0f3561d60230242f3be0c9d272b", size = 6511151, upload-time = "2026-02-27T12:20:54.236Z" },
+ { url = "https://files.pythonhosted.org/packages/41/c2/87d433a9681c79e0926d8a113ea153d592ec49d1d7aa7278ee798bc490f2/pillow_heif-1.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:5f0db0bf49162fb1d73d13340a9576b3a2805bde026a9a40038bcc1a0878d710", size = 5483578, upload-time = "2026-02-27T12:20:55.715Z" },
+ { url = "https://files.pythonhosted.org/packages/81/c3/9effa6ab5c2c2ffb80228143c578a9a2a8e2f059dd9d067ec6ff6f6c89db/pillow_heif-1.3.0-cp313-cp313-macosx_10_15_x86_64.whl", hash = "sha256:641c50a064aa9ad6626a6b2b914b65855202f937d573d53838e344feb2e8c6d1", size = 4667379, upload-time = "2026-02-27T12:20:57.561Z" },
+ { url = "https://files.pythonhosted.org/packages/23/eb/b6b52e3655f366b95301f18aecd2d35487cace18d17134b80ad0f70cc1eb/pillow_heif-1.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9390dd7987887aa09779fbd88bbab715c732c9ad3a71d6707284035e3ca93379", size = 3392725, upload-time = "2026-02-27T12:20:59.52Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/b3/b69610e9565fc8bcaf2303f412e857c0439d23cc18cf866c72a96ec6b2e6/pillow_heif-1.3.0-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e8444ccb330015e1db930207d269886e4b6c666121cd9e5fdad88735950b09f", size = 5844285, upload-time = "2026-02-27T12:21:00.771Z" },
+ { url = "https://files.pythonhosted.org/packages/47/8c/be44f6dea425a9756ff418cb03f5ee75ed1c7dd1ff9bee1f3893b2b82da4/pillow_heif-1.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7d30054ccc97ecbe5ee3fa486a505ccc33bfbb27f005ad624ddb4c17b80ddd57", size = 5578691, upload-time = "2026-02-27T12:21:02.193Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/74/e12d49346a39e2204b408a835b31b2fd9a5d51f97ce3a6015cf22ca09a54/pillow_heif-1.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dc1b9c9efdf8345d703118449ff69696d0827bdf28e3b52f82015f5714f7c23e", size = 6885923, upload-time = "2026-02-27T12:21:03.782Z" },
+ { url = "https://files.pythonhosted.org/packages/80/a6/51c937a9433f5ae9c625b686ee338bdf0080a1661f7eb34daaf75424ee77/pillow_heif-1.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ee26b2155721e7f5f7b10fa93ca2ad3be59547c5c5e5d9d50e6ea17531b81d60", size = 6511216, upload-time = "2026-02-27T12:21:05.134Z" },
+ { url = "https://files.pythonhosted.org/packages/63/0a/bb8435e127f75b434166022471bbabf11c8c1fc3d48c8595fd6ab36c2785/pillow_heif-1.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:17ecbbadfe10ea12a65c1c12354dc1ed8ae1e5d1b7092ea753641b029f7d6f9e", size = 5483570, upload-time = "2026-02-27T12:21:06.566Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/17/aa056f8edb71396dd1131abcd0c6feab00097ceec89a12fc62d2dbc3ccf5/pillow_heif-1.3.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:8267a73d3b2d07a47a96428bd8cd4c406e1637a94f29d4c16ce08b31b8e50a07", size = 4667395, upload-time = "2026-02-27T12:21:08.16Z" },
+ { url = "https://files.pythonhosted.org/packages/19/1f/da50ccd271a2878d17df359301dc2f7a79ec1cbb6e92c19ccc8c6219d497/pillow_heif-1.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:36bbea7679467caa3a154db11c04f1ca2fa8591e886f06f40f7831c14b58d771", size = 3392800, upload-time = "2026-02-27T12:21:09.668Z" },
+ { url = "https://files.pythonhosted.org/packages/11/bc/1f89d927c1293cf283bc5d0ae6735d268d2de9749aa6fb94342ec838a457/pillow_heif-1.3.0-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ea3a4b2de4b6c63407af72afdac901616807c6e6a030fe77851d227bca3727a", size = 5844547, upload-time = "2026-02-27T12:21:10.826Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/04/d781b23f8bff125c8dd8da63d928a35e38f2b727e89582a1fd323664e968/pillow_heif-1.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05149bd26b08dae5af7a389af6db13cef4f12c7871db73d84e40a1f3c83b0142", size = 5578827, upload-time = "2026-02-27T12:21:12.06Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/98/8dcdaafcf9bd8b26ed0569dc93653dc20a06faef7bfbdd4ba05c091c5b60/pillow_heif-1.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f8b7a50058fc3152f42b68aa2b30601249f61aa5c6c27876af076785c7051fd9", size = 6886088, upload-time = "2026-02-27T12:21:13.635Z" },
+ { url = "https://files.pythonhosted.org/packages/99/26/93f3c8bfffb7e8fe0244bf86117235c49c23980e61320e7484c03ac836e2/pillow_heif-1.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:edb3ef437e8841475db14721f0529e600bb55c41b549ad1794a0831e28f33bac", size = 6511291, upload-time = "2026-02-27T12:21:15.354Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/f9/a8c72619ec212eb2612730fa2b3068e2d4b59e0a0957c2e8418aa4cff59e/pillow_heif-1.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:bdd6695d5be0d98ae0e9a5f88fe26f1a6eca0a5b6d43d0a92a97f89fea5842f7", size = 5640949, upload-time = "2026-02-27T12:21:16.647Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/31/92ce30e1ada892e18a03042bd5a8414f655304a78a36790e657f14265fed/pillow_heif-1.3.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:65c5d05cb7f5e1eadbe9c605ae3a4dd3ef953adb33e7d809d5fb56f8a6753588", size = 4668365, upload-time = "2026-02-27T12:21:18.004Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/2b/789fa3c82063a780e84de667771b8ec30bc328511855f15a83a3c77011ec/pillow_heif-1.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:dc177fbdf598770cad4afa99c082a30b9d090e60c39656904338717803ae59b2", size = 3393554, upload-time = "2026-02-27T12:21:19.642Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/a4/4f8075f03c1d06d7afd674e263a3f57b7b24130c39b1544555b3b03ed369/pillow_heif-1.3.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:71f88d180547bb5112b56310c8c5e338d8358320a402c80afabc6b2f39eadddb", size = 5849609, upload-time = "2026-02-27T12:21:20.953Z" },
+ { url = "https://files.pythonhosted.org/packages/0d/08/e33a10bc84ade1b4ec56bdc765735bbfd452513e33537df68107edc0eb86/pillow_heif-1.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9acee893186bdde6140d30a7dc6d7c928e4ad3007989764f6e54a7a517faa332", size = 5582931, upload-time = "2026-02-27T12:21:22.571Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/45/6afc0f29701e0c9b911b33a35760ae6e2c581fc49b431dcce22ed18abfba/pillow_heif-1.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7cf893689132bec18f0c55a505da9ebf3a8feb33dd354fe2ac050f20f4f862e0", size = 6891268, upload-time = "2026-02-27T12:21:24.021Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/0a/0d6a69f76f277692555d0e687dbf3e31d03cf76fffa3ced1fea51a18c481/pillow_heif-1.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:54404c9b6f0323114527579f54cc966b47206f99d943e47d73e1091ab0b9d2ba", size = 6515405, upload-time = "2026-02-27T12:21:25.336Z" },
+ { url = "https://files.pythonhosted.org/packages/39/21/716856a36c1cc30a8f1354bf6423f251b1f50851af3e13b9cf084a13d2e3/pillow_heif-1.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:18c7c35a9d98ed9eaaf2db601ee43425ebccc698801df9c008aa04e00756a22e", size = 5641581, upload-time = "2026-02-27T12:21:26.642Z" },
+]
+
+[[package]]
+name = "platformdirs"
+version = "4.9.4"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/19/56/8d4c30c8a1d07013911a8fdbd8f89440ef9f08d07a1b50ab8ca8be5a20f9/platformdirs-4.9.4.tar.gz", hash = "sha256:1ec356301b7dc906d83f371c8f487070e99d3ccf9e501686456394622a01a934", size = 28737, upload-time = "2026-03-05T18:34:13.271Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/63/d7/97f7e3a6abb67d8080dd406fd4df842c2be0efaf712d1c899c32a075027c/platformdirs-4.9.4-py3-none-any.whl", hash = "sha256:68a9a4619a666ea6439f2ff250c12a853cd1cbd5158d258bd824a7df6be2f868", size = 21216, upload-time = "2026-03-05T18:34:12.172Z" },
+]
+
+[[package]]
+name = "prometheus-client"
+version = "0.24.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f0/58/a794d23feb6b00fc0c72787d7e87d872a6730dd9ed7c7b3e954637d8f280/prometheus_client-0.24.1.tar.gz", hash = "sha256:7e0ced7fbbd40f7b84962d5d2ab6f17ef88a72504dcf7c0b40737b43b2a461f9", size = 85616, upload-time = "2026-01-14T15:26:26.965Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/74/c3/24a2f845e3917201628ecaba4f18bab4d18a337834c1df2a159ee9d22a42/prometheus_client-0.24.1-py3-none-any.whl", hash = "sha256:150db128af71a5c2482b36e588fc8a6b95e498750da4b17065947c16070f4055", size = 64057, upload-time = "2026-01-14T15:26:24.42Z" },
+]
+
+[[package]]
+name = "propcache"
+version = "0.4.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442, upload-time = "2025-10-08T19:49:02.291Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a2/0f/f17b1b2b221d5ca28b4b876e8bb046ac40466513960646bda8e1853cdfa2/propcache-0.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e153e9cd40cc8945138822807139367f256f89c6810c2634a4f6902b52d3b4e2", size = 80061, upload-time = "2025-10-08T19:46:46.075Z" },
+ { url = "https://files.pythonhosted.org/packages/76/47/8ccf75935f51448ba9a16a71b783eb7ef6b9ee60f5d14c7f8a8a79fbeed7/propcache-0.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cd547953428f7abb73c5ad82cbb32109566204260d98e41e5dfdc682eb7f8403", size = 46037, upload-time = "2025-10-08T19:46:47.23Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/b6/5c9a0e42df4d00bfb4a3cbbe5cf9f54260300c88a0e9af1f47ca5ce17ac0/propcache-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f048da1b4f243fc44f205dfd320933a951b8d89e0afd4c7cacc762a8b9165207", size = 47324, upload-time = "2025-10-08T19:46:48.384Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/d3/6c7ee328b39a81ee877c962469f1e795f9db87f925251efeb0545e0020d0/propcache-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ec17c65562a827bba85e3872ead335f95405ea1674860d96483a02f5c698fa72", size = 225505, upload-time = "2025-10-08T19:46:50.055Z" },
+ { url = "https://files.pythonhosted.org/packages/01/5d/1c53f4563490b1d06a684742cc6076ef944bc6457df6051b7d1a877c057b/propcache-0.4.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:405aac25c6394ef275dee4c709be43745d36674b223ba4eb7144bf4d691b7367", size = 230242, upload-time = "2025-10-08T19:46:51.815Z" },
+ { url = "https://files.pythonhosted.org/packages/20/e1/ce4620633b0e2422207c3cb774a0ee61cac13abc6217763a7b9e2e3f4a12/propcache-0.4.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0013cb6f8dde4b2a2f66903b8ba740bdfe378c943c4377a200551ceb27f379e4", size = 238474, upload-time = "2025-10-08T19:46:53.208Z" },
+ { url = "https://files.pythonhosted.org/packages/46/4b/3aae6835b8e5f44ea6a68348ad90f78134047b503765087be2f9912140ea/propcache-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15932ab57837c3368b024473a525e25d316d8353016e7cc0e5ba9eb343fbb1cf", size = 221575, upload-time = "2025-10-08T19:46:54.511Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/a5/8a5e8678bcc9d3a1a15b9a29165640d64762d424a16af543f00629c87338/propcache-0.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:031dce78b9dc099f4c29785d9cf5577a3faf9ebf74ecbd3c856a7b92768c3df3", size = 216736, upload-time = "2025-10-08T19:46:56.212Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/63/b7b215eddeac83ca1c6b934f89d09a625aa9ee4ba158338854c87210cc36/propcache-0.4.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ab08df6c9a035bee56e31af99be621526bd237bea9f32def431c656b29e41778", size = 213019, upload-time = "2025-10-08T19:46:57.595Z" },
+ { url = "https://files.pythonhosted.org/packages/57/74/f580099a58c8af587cac7ba19ee7cb418506342fbbe2d4a4401661cca886/propcache-0.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4d7af63f9f93fe593afbf104c21b3b15868efb2c21d07d8732c0c4287e66b6a6", size = 220376, upload-time = "2025-10-08T19:46:59.067Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/ee/542f1313aff7eaf19c2bb758c5d0560d2683dac001a1c96d0774af799843/propcache-0.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cfc27c945f422e8b5071b6e93169679e4eb5bf73bbcbf1ba3ae3a83d2f78ebd9", size = 226988, upload-time = "2025-10-08T19:47:00.544Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/18/9c6b015dd9c6930f6ce2229e1f02fb35298b847f2087ea2b436a5bfa7287/propcache-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:35c3277624a080cc6ec6f847cbbbb5b49affa3598c4535a0a4682a697aaa5c75", size = 215615, upload-time = "2025-10-08T19:47:01.968Z" },
+ { url = "https://files.pythonhosted.org/packages/80/9e/e7b85720b98c45a45e1fca6a177024934dc9bc5f4d5dd04207f216fc33ed/propcache-0.4.1-cp312-cp312-win32.whl", hash = "sha256:671538c2262dadb5ba6395e26c1731e1d52534bfe9ae56d0b5573ce539266aa8", size = 38066, upload-time = "2025-10-08T19:47:03.503Z" },
+ { url = "https://files.pythonhosted.org/packages/54/09/d19cff2a5aaac632ec8fc03737b223597b1e347416934c1b3a7df079784c/propcache-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:cb2d222e72399fcf5890d1d5cc1060857b9b236adff2792ff48ca2dfd46c81db", size = 41655, upload-time = "2025-10-08T19:47:04.973Z" },
+ { url = "https://files.pythonhosted.org/packages/68/ab/6b5c191bb5de08036a8c697b265d4ca76148efb10fa162f14af14fb5f076/propcache-0.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:204483131fb222bdaaeeea9f9e6c6ed0cac32731f75dfc1d4a567fc1926477c1", size = 37789, upload-time = "2025-10-08T19:47:06.077Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/df/6d9c1b6ac12b003837dde8a10231a7344512186e87b36e855bef32241942/propcache-0.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:43eedf29202c08550aac1d14e0ee619b0430aaef78f85864c1a892294fbc28cf", size = 77750, upload-time = "2025-10-08T19:47:07.648Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/e8/677a0025e8a2acf07d3418a2e7ba529c9c33caf09d3c1f25513023c1db56/propcache-0.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d62cdfcfd89ccb8de04e0eda998535c406bf5e060ffd56be6c586cbcc05b3311", size = 44780, upload-time = "2025-10-08T19:47:08.851Z" },
+ { url = "https://files.pythonhosted.org/packages/89/a4/92380f7ca60f99ebae761936bc48a72a639e8a47b29050615eef757cb2a7/propcache-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cae65ad55793da34db5f54e4029b89d3b9b9490d8abe1b4c7ab5d4b8ec7ebf74", size = 46308, upload-time = "2025-10-08T19:47:09.982Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/48/c5ac64dee5262044348d1d78a5f85dd1a57464a60d30daee946699963eb3/propcache-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:333ddb9031d2704a301ee3e506dc46b1fe5f294ec198ed6435ad5b6a085facfe", size = 208182, upload-time = "2025-10-08T19:47:11.319Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/0c/cd762dd011a9287389a6a3eb43aa30207bde253610cca06824aeabfe9653/propcache-0.4.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fd0858c20f078a32cf55f7e81473d96dcf3b93fd2ccdb3d40fdf54b8573df3af", size = 211215, upload-time = "2025-10-08T19:47:13.146Z" },
+ { url = "https://files.pythonhosted.org/packages/30/3e/49861e90233ba36890ae0ca4c660e95df565b2cd15d4a68556ab5865974e/propcache-0.4.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:678ae89ebc632c5c204c794f8dab2837c5f159aeb59e6ed0539500400577298c", size = 218112, upload-time = "2025-10-08T19:47:14.913Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/8b/544bc867e24e1bd48f3118cecd3b05c694e160a168478fa28770f22fd094/propcache-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d472aeb4fbf9865e0c6d622d7f4d54a4e101a89715d8904282bb5f9a2f476c3f", size = 204442, upload-time = "2025-10-08T19:47:16.277Z" },
+ { url = "https://files.pythonhosted.org/packages/50/a6/4282772fd016a76d3e5c0df58380a5ea64900afd836cec2c2f662d1b9bb3/propcache-0.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4d3df5fa7e36b3225954fba85589da77a0fe6a53e3976de39caf04a0db4c36f1", size = 199398, upload-time = "2025-10-08T19:47:17.962Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/ec/d8a7cd406ee1ddb705db2139f8a10a8a427100347bd698e7014351c7af09/propcache-0.4.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ee17f18d2498f2673e432faaa71698032b0127ebf23ae5974eeaf806c279df24", size = 196920, upload-time = "2025-10-08T19:47:19.355Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/6c/f38ab64af3764f431e359f8baf9e0a21013e24329e8b85d2da32e8ed07ca/propcache-0.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:580e97762b950f993ae618e167e7be9256b8353c2dcd8b99ec100eb50f5286aa", size = 203748, upload-time = "2025-10-08T19:47:21.338Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/e3/fa846bd70f6534d647886621388f0a265254d30e3ce47e5c8e6e27dbf153/propcache-0.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:501d20b891688eb8e7aa903021f0b72d5a55db40ffaab27edefd1027caaafa61", size = 205877, upload-time = "2025-10-08T19:47:23.059Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/39/8163fc6f3133fea7b5f2827e8eba2029a0277ab2c5beee6c1db7b10fc23d/propcache-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a0bd56e5b100aef69bd8562b74b46254e7c8812918d3baa700c8a8009b0af66", size = 199437, upload-time = "2025-10-08T19:47:24.445Z" },
+ { url = "https://files.pythonhosted.org/packages/93/89/caa9089970ca49c7c01662bd0eeedfe85494e863e8043565aeb6472ce8fe/propcache-0.4.1-cp313-cp313-win32.whl", hash = "sha256:bcc9aaa5d80322bc2fb24bb7accb4a30f81e90ab8d6ba187aec0744bc302ad81", size = 37586, upload-time = "2025-10-08T19:47:25.736Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/ab/f76ec3c3627c883215b5c8080debb4394ef5a7a29be811f786415fc1e6fd/propcache-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:381914df18634f5494334d201e98245c0596067504b9372d8cf93f4bb23e025e", size = 40790, upload-time = "2025-10-08T19:47:26.847Z" },
+ { url = "https://files.pythonhosted.org/packages/59/1b/e71ae98235f8e2ba5004d8cb19765a74877abf189bc53fc0c80d799e56c3/propcache-0.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:8873eb4460fd55333ea49b7d189749ecf6e55bf85080f11b1c4530ed3034cba1", size = 37158, upload-time = "2025-10-08T19:47:27.961Z" },
+ { url = "https://files.pythonhosted.org/packages/83/ce/a31bbdfc24ee0dcbba458c8175ed26089cf109a55bbe7b7640ed2470cfe9/propcache-0.4.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:92d1935ee1f8d7442da9c0c4fa7ac20d07e94064184811b685f5c4fada64553b", size = 81451, upload-time = "2025-10-08T19:47:29.445Z" },
+ { url = "https://files.pythonhosted.org/packages/25/9c/442a45a470a68456e710d96cacd3573ef26a1d0a60067e6a7d5e655621ed/propcache-0.4.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:473c61b39e1460d386479b9b2f337da492042447c9b685f28be4f74d3529e566", size = 46374, upload-time = "2025-10-08T19:47:30.579Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/bf/b1d5e21dbc3b2e889ea4327044fb16312a736d97640fb8b6aa3f9c7b3b65/propcache-0.4.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c0ef0aaafc66fbd87842a3fe3902fd889825646bc21149eafe47be6072725835", size = 48396, upload-time = "2025-10-08T19:47:31.79Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/04/5b4c54a103d480e978d3c8a76073502b18db0c4bc17ab91b3cb5092ad949/propcache-0.4.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95393b4d66bfae908c3ca8d169d5f79cd65636ae15b5e7a4f6e67af675adb0e", size = 275950, upload-time = "2025-10-08T19:47:33.481Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/c1/86f846827fb969c4b78b0af79bba1d1ea2156492e1b83dea8b8a6ae27395/propcache-0.4.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c07fda85708bc48578467e85099645167a955ba093be0a2dcba962195676e859", size = 273856, upload-time = "2025-10-08T19:47:34.906Z" },
+ { url = "https://files.pythonhosted.org/packages/36/1d/fc272a63c8d3bbad6878c336c7a7dea15e8f2d23a544bda43205dfa83ada/propcache-0.4.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:af223b406d6d000830c6f65f1e6431783fc3f713ba3e6cc8c024d5ee96170a4b", size = 280420, upload-time = "2025-10-08T19:47:36.338Z" },
+ { url = "https://files.pythonhosted.org/packages/07/0c/01f2219d39f7e53d52e5173bcb09c976609ba30209912a0680adfb8c593a/propcache-0.4.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a78372c932c90ee474559c5ddfffd718238e8673c340dc21fe45c5b8b54559a0", size = 263254, upload-time = "2025-10-08T19:47:37.692Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/18/cd28081658ce597898f0c4d174d4d0f3c5b6d4dc27ffafeef835c95eb359/propcache-0.4.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:564d9f0d4d9509e1a870c920a89b2fec951b44bf5ba7d537a9e7c1ccec2c18af", size = 261205, upload-time = "2025-10-08T19:47:39.659Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/71/1f9e22eb8b8316701c2a19fa1f388c8a3185082607da8e406a803c9b954e/propcache-0.4.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:17612831fda0138059cc5546f4d12a2aacfb9e47068c06af35c400ba58ba7393", size = 247873, upload-time = "2025-10-08T19:47:41.084Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/65/3d4b61f36af2b4eddba9def857959f1016a51066b4f1ce348e0cf7881f58/propcache-0.4.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:41a89040cb10bd345b3c1a873b2bf36413d48da1def52f268a055f7398514874", size = 262739, upload-time = "2025-10-08T19:47:42.51Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/42/26746ab087faa77c1c68079b228810436ccd9a5ce9ac85e2b7307195fd06/propcache-0.4.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e35b88984e7fa64aacecea39236cee32dd9bd8c55f57ba8a75cf2399553f9bd7", size = 263514, upload-time = "2025-10-08T19:47:43.927Z" },
+ { url = "https://files.pythonhosted.org/packages/94/13/630690fe201f5502d2403dd3cfd451ed8858fe3c738ee88d095ad2ff407b/propcache-0.4.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f8b465489f927b0df505cbe26ffbeed4d6d8a2bbc61ce90eb074ff129ef0ab1", size = 257781, upload-time = "2025-10-08T19:47:45.448Z" },
+ { url = "https://files.pythonhosted.org/packages/92/f7/1d4ec5841505f423469efbfc381d64b7b467438cd5a4bbcbb063f3b73d27/propcache-0.4.1-cp313-cp313t-win32.whl", hash = "sha256:2ad890caa1d928c7c2965b48f3a3815c853180831d0e5503d35cf00c472f4717", size = 41396, upload-time = "2025-10-08T19:47:47.202Z" },
+ { url = "https://files.pythonhosted.org/packages/48/f0/615c30622316496d2cbbc29f5985f7777d3ada70f23370608c1d3e081c1f/propcache-0.4.1-cp313-cp313t-win_amd64.whl", hash = "sha256:f7ee0e597f495cf415bcbd3da3caa3bd7e816b74d0d52b8145954c5e6fd3ff37", size = 44897, upload-time = "2025-10-08T19:47:48.336Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/ca/6002e46eccbe0e33dcd4069ef32f7f1c9e243736e07adca37ae8c4830ec3/propcache-0.4.1-cp313-cp313t-win_arm64.whl", hash = "sha256:929d7cbe1f01bb7baffb33dc14eb5691c95831450a26354cd210a8155170c93a", size = 39789, upload-time = "2025-10-08T19:47:49.876Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/5c/bca52d654a896f831b8256683457ceddd490ec18d9ec50e97dfd8fc726a8/propcache-0.4.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3f7124c9d820ba5548d431afb4632301acf965db49e666aa21c305cbe8c6de12", size = 78152, upload-time = "2025-10-08T19:47:51.051Z" },
+ { url = "https://files.pythonhosted.org/packages/65/9b/03b04e7d82a5f54fb16113d839f5ea1ede58a61e90edf515f6577c66fa8f/propcache-0.4.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:c0d4b719b7da33599dfe3b22d3db1ef789210a0597bc650b7cee9c77c2be8c5c", size = 44869, upload-time = "2025-10-08T19:47:52.594Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/fa/89a8ef0468d5833a23fff277b143d0573897cf75bd56670a6d28126c7d68/propcache-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9f302f4783709a78240ebc311b793f123328716a60911d667e0c036bc5dcbded", size = 46596, upload-time = "2025-10-08T19:47:54.073Z" },
+ { url = "https://files.pythonhosted.org/packages/86/bd/47816020d337f4a746edc42fe8d53669965138f39ee117414c7d7a340cfe/propcache-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c80ee5802e3fb9ea37938e7eecc307fb984837091d5fd262bb37238b1ae97641", size = 206981, upload-time = "2025-10-08T19:47:55.715Z" },
+ { url = "https://files.pythonhosted.org/packages/df/f6/c5fa1357cc9748510ee55f37173eb31bfde6d94e98ccd9e6f033f2fc06e1/propcache-0.4.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ed5a841e8bb29a55fb8159ed526b26adc5bdd7e8bd7bf793ce647cb08656cdf4", size = 211490, upload-time = "2025-10-08T19:47:57.499Z" },
+ { url = "https://files.pythonhosted.org/packages/80/1e/e5889652a7c4a3846683401a48f0f2e5083ce0ec1a8a5221d8058fbd1adf/propcache-0.4.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:55c72fd6ea2da4c318e74ffdf93c4fe4e926051133657459131a95c846d16d44", size = 215371, upload-time = "2025-10-08T19:47:59.317Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/f2/889ad4b2408f72fe1a4f6a19491177b30ea7bf1a0fd5f17050ca08cfc882/propcache-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8326e144341460402713f91df60ade3c999d601e7eb5ff8f6f7862d54de0610d", size = 201424, upload-time = "2025-10-08T19:48:00.67Z" },
+ { url = "https://files.pythonhosted.org/packages/27/73/033d63069b57b0812c8bd19f311faebeceb6ba31b8f32b73432d12a0b826/propcache-0.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:060b16ae65bc098da7f6d25bf359f1f31f688384858204fe5d652979e0015e5b", size = 197566, upload-time = "2025-10-08T19:48:02.604Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/89/ce24f3dc182630b4e07aa6d15f0ff4b14ed4b9955fae95a0b54c58d66c05/propcache-0.4.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:89eb3fa9524f7bec9de6e83cf3faed9d79bffa560672c118a96a171a6f55831e", size = 193130, upload-time = "2025-10-08T19:48:04.499Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/24/ef0d5fd1a811fb5c609278d0209c9f10c35f20581fcc16f818da959fc5b4/propcache-0.4.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:dee69d7015dc235f526fe80a9c90d65eb0039103fe565776250881731f06349f", size = 202625, upload-time = "2025-10-08T19:48:06.213Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/02/98ec20ff5546f68d673df2f7a69e8c0d076b5abd05ca882dc7ee3a83653d/propcache-0.4.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5558992a00dfd54ccbc64a32726a3357ec93825a418a401f5cc67df0ac5d9e49", size = 204209, upload-time = "2025-10-08T19:48:08.432Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/87/492694f76759b15f0467a2a93ab68d32859672b646aa8a04ce4864e7932d/propcache-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c9b822a577f560fbd9554812526831712c1436d2c046cedee4c3796d3543b144", size = 197797, upload-time = "2025-10-08T19:48:09.968Z" },
+ { url = "https://files.pythonhosted.org/packages/ee/36/66367de3575db1d2d3f3d177432bd14ee577a39d3f5d1b3d5df8afe3b6e2/propcache-0.4.1-cp314-cp314-win32.whl", hash = "sha256:ab4c29b49d560fe48b696cdcb127dd36e0bc2472548f3bf56cc5cb3da2b2984f", size = 38140, upload-time = "2025-10-08T19:48:11.232Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/2a/a758b47de253636e1b8aef181c0b4f4f204bf0dd964914fb2af90a95b49b/propcache-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:5a103c3eb905fcea0ab98be99c3a9a5ab2de60228aa5aceedc614c0281cf6153", size = 41257, upload-time = "2025-10-08T19:48:12.707Z" },
+ { url = "https://files.pythonhosted.org/packages/34/5e/63bd5896c3fec12edcbd6f12508d4890d23c265df28c74b175e1ef9f4f3b/propcache-0.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:74c1fb26515153e482e00177a1ad654721bf9207da8a494a0c05e797ad27b992", size = 38097, upload-time = "2025-10-08T19:48:13.923Z" },
+ { url = "https://files.pythonhosted.org/packages/99/85/9ff785d787ccf9bbb3f3106f79884a130951436f58392000231b4c737c80/propcache-0.4.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:824e908bce90fb2743bd6b59db36eb4f45cd350a39637c9f73b1c1ea66f5b75f", size = 81455, upload-time = "2025-10-08T19:48:15.16Z" },
+ { url = "https://files.pythonhosted.org/packages/90/85/2431c10c8e7ddb1445c1f7c4b54d886e8ad20e3c6307e7218f05922cad67/propcache-0.4.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c2b5e7db5328427c57c8e8831abda175421b709672f6cfc3d630c3b7e2146393", size = 46372, upload-time = "2025-10-08T19:48:16.424Z" },
+ { url = "https://files.pythonhosted.org/packages/01/20/b0972d902472da9bcb683fa595099911f4d2e86e5683bcc45de60dd05dc3/propcache-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6f6ff873ed40292cd4969ef5310179afd5db59fdf055897e282485043fc80ad0", size = 48411, upload-time = "2025-10-08T19:48:17.577Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/e3/7dc89f4f21e8f99bad3d5ddb3a3389afcf9da4ac69e3deb2dcdc96e74169/propcache-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49a2dc67c154db2c1463013594c458881a069fcf98940e61a0569016a583020a", size = 275712, upload-time = "2025-10-08T19:48:18.901Z" },
+ { url = "https://files.pythonhosted.org/packages/20/67/89800c8352489b21a8047c773067644e3897f02ecbbd610f4d46b7f08612/propcache-0.4.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:005f08e6a0529984491e37d8dbc3dd86f84bd78a8ceb5fa9a021f4c48d4984be", size = 273557, upload-time = "2025-10-08T19:48:20.762Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/a1/b52b055c766a54ce6d9c16d9aca0cad8059acd9637cdf8aa0222f4a026ef/propcache-0.4.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5c3310452e0d31390da9035c348633b43d7e7feb2e37be252be6da45abd1abcc", size = 280015, upload-time = "2025-10-08T19:48:22.592Z" },
+ { url = "https://files.pythonhosted.org/packages/48/c8/33cee30bd890672c63743049f3c9e4be087e6780906bfc3ec58528be59c1/propcache-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c3c70630930447f9ef1caac7728c8ad1c56bc5015338b20fed0d08ea2480b3a", size = 262880, upload-time = "2025-10-08T19:48:23.947Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/b1/8f08a143b204b418285c88b83d00edbd61afbc2c6415ffafc8905da7038b/propcache-0.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8e57061305815dfc910a3634dcf584f08168a8836e6999983569f51a8544cd89", size = 260938, upload-time = "2025-10-08T19:48:25.656Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/12/96e4664c82ca2f31e1c8dff86afb867348979eb78d3cb8546a680287a1e9/propcache-0.4.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:521a463429ef54143092c11a77e04056dd00636f72e8c45b70aaa3140d639726", size = 247641, upload-time = "2025-10-08T19:48:27.207Z" },
+ { url = "https://files.pythonhosted.org/packages/18/ed/e7a9cfca28133386ba52278136d42209d3125db08d0a6395f0cba0c0285c/propcache-0.4.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:120c964da3fdc75e3731aa392527136d4ad35868cc556fd09bb6d09172d9a367", size = 262510, upload-time = "2025-10-08T19:48:28.65Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/76/16d8bf65e8845dd62b4e2b57444ab81f07f40caa5652b8969b87ddcf2ef6/propcache-0.4.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:d8f353eb14ee3441ee844ade4277d560cdd68288838673273b978e3d6d2c8f36", size = 263161, upload-time = "2025-10-08T19:48:30.133Z" },
+ { url = "https://files.pythonhosted.org/packages/e7/70/c99e9edb5d91d5ad8a49fa3c1e8285ba64f1476782fed10ab251ff413ba1/propcache-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ab2943be7c652f09638800905ee1bab2c544e537edb57d527997a24c13dc1455", size = 257393, upload-time = "2025-10-08T19:48:31.567Z" },
+ { url = "https://files.pythonhosted.org/packages/08/02/87b25304249a35c0915d236575bc3574a323f60b47939a2262b77632a3ee/propcache-0.4.1-cp314-cp314t-win32.whl", hash = "sha256:05674a162469f31358c30bcaa8883cb7829fa3110bf9c0991fe27d7896c42d85", size = 42546, upload-time = "2025-10-08T19:48:32.872Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/ef/3c6ecf8b317aa982f309835e8f96987466123c6e596646d4e6a1dfcd080f/propcache-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:990f6b3e2a27d683cb7602ed6c86f15ee6b43b1194736f9baaeb93d0016633b1", size = 46259, upload-time = "2025-10-08T19:48:34.226Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/2d/346e946d4951f37eca1e4f55be0f0174c52cd70720f84029b02f296f4a38/propcache-0.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:ecef2343af4cc68e05131e45024ba34f6095821988a9d0a02aa7c73fcc448aa9", size = 40428, upload-time = "2025-10-08T19:48:35.441Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" },
+]
+
+[[package]]
+name = "proto-plus"
+version = "1.27.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "protobuf" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/3a/02/8832cde80e7380c600fbf55090b6ab7b62bd6825dbedde6d6657c15a1f8e/proto_plus-1.27.1.tar.gz", hash = "sha256:912a7460446625b792f6448bade9e55cd4e41e6ac10e27009ef71a7f317fa147", size = 56929, upload-time = "2026-02-02T17:34:49.035Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5d/79/ac273cbbf744691821a9cca88957257f41afe271637794975ca090b9588b/proto_plus-1.27.1-py3-none-any.whl", hash = "sha256:e4643061f3a4d0de092d62aa4ad09fa4756b2cbb89d4627f3985018216f9fefc", size = 50480, upload-time = "2026-02-02T17:34:47.339Z" },
+]
+
+[[package]]
+name = "protobuf"
+version = "6.33.5"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ba/25/7c72c307aafc96fa87062aa6291d9f7c94836e43214d43722e86037aac02/protobuf-6.33.5.tar.gz", hash = "sha256:6ddcac2a081f8b7b9642c09406bc6a4290128fce5f471cddd165960bb9119e5c", size = 444465, upload-time = "2026-01-29T21:51:33.494Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b1/79/af92d0a8369732b027e6d6084251dd8e782c685c72da161bd4a2e00fbabb/protobuf-6.33.5-cp310-abi3-win32.whl", hash = "sha256:d71b040839446bac0f4d162e758bea99c8251161dae9d0983a3b88dee345153b", size = 425769, upload-time = "2026-01-29T21:51:21.751Z" },
+ { url = "https://files.pythonhosted.org/packages/55/75/bb9bc917d10e9ee13dee8607eb9ab963b7cf8be607c46e7862c748aa2af7/protobuf-6.33.5-cp310-abi3-win_amd64.whl", hash = "sha256:3093804752167bcab3998bec9f1048baae6e29505adaf1afd14a37bddede533c", size = 437118, upload-time = "2026-01-29T21:51:24.022Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/6b/e48dfc1191bc5b52950246275bf4089773e91cb5ba3592621723cdddca62/protobuf-6.33.5-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:a5cb85982d95d906df1e2210e58f8e4f1e3cdc088e52c921a041f9c9a0386de5", size = 427766, upload-time = "2026-01-29T21:51:25.413Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/b1/c79468184310de09d75095ed1314b839eb2f72df71097db9d1404a1b2717/protobuf-6.33.5-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:9b71e0281f36f179d00cbcb119cb19dec4d14a81393e5ea220f64b286173e190", size = 324638, upload-time = "2026-01-29T21:51:26.423Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/f5/65d838092fd01c44d16037953fd4c2cc851e783de9b8f02b27ec4ffd906f/protobuf-6.33.5-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:8afa18e1d6d20af15b417e728e9f60f3aa108ee76f23c3b2c07a2c3b546d3afd", size = 339411, upload-time = "2026-01-29T21:51:27.446Z" },
+ { url = "https://files.pythonhosted.org/packages/9b/53/a9443aa3ca9ba8724fdfa02dd1887c1bcd8e89556b715cfbacca6b63dbec/protobuf-6.33.5-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:cbf16ba3350fb7b889fca858fb215967792dc125b35c7976ca4818bee3521cf0", size = 323465, upload-time = "2026-01-29T21:51:28.925Z" },
+ { url = "https://files.pythonhosted.org/packages/57/bf/2086963c69bdac3d7cff1cc7ff79b8ce5ea0bec6797a017e1be338a46248/protobuf-6.33.5-py3-none-any.whl", hash = "sha256:69915a973dd0f60f31a08b8318b73eab2bd6a392c79184b3612226b0a3f8ec02", size = 170687, upload-time = "2026-01-29T21:51:32.557Z" },
+]
+
+[[package]]
+name = "py-spy"
+version = "0.4.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/19/e2/ff811a367028b87e86714945bb9ecb5c1cc69114a8039a67b3a862cef921/py_spy-0.4.1.tar.gz", hash = "sha256:e53aa53daa2e47c2eef97dd2455b47bb3a7e7f962796a86cc3e7dbde8e6f4db4", size = 244726, upload-time = "2025-07-31T19:33:25.172Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/14/e3/3a32500d845bdd94f6a2b4ed6244982f42ec2bc64602ea8fcfe900678ae7/py_spy-0.4.1-py2.py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:809094208c6256c8f4ccadd31e9a513fe2429253f48e20066879239ba12cd8cc", size = 3682508, upload-time = "2025-07-31T19:33:13.753Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/bf/e4d280e9e0bec71d39fc646654097027d4bbe8e04af18fb68e49afcff404/py_spy-0.4.1-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:1fb8bf71ab8df95a95cc387deed6552934c50feef2cf6456bc06692a5508fd0c", size = 1796395, upload-time = "2025-07-31T19:33:15.325Z" },
+ { url = "https://files.pythonhosted.org/packages/df/79/9ed50bb0a9de63ed023aa2db8b6265b04a7760d98c61eb54def6a5fddb68/py_spy-0.4.1-py2.py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee776b9d512a011d1ad3907ed53ae32ce2f3d9ff3e1782236554e22103b5c084", size = 2034938, upload-time = "2025-07-31T19:33:17.194Z" },
+ { url = "https://files.pythonhosted.org/packages/53/a5/36862e3eea59f729dfb70ee6f9e14b051d8ddce1aa7e70e0b81d9fe18536/py_spy-0.4.1-py2.py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:532d3525538254d1859b49de1fbe9744df6b8865657c9f0e444bf36ce3f19226", size = 2658968, upload-time = "2025-07-31T19:33:18.916Z" },
+ { url = "https://files.pythonhosted.org/packages/08/f8/9ea0b586b065a623f591e5e7961282ec944b5fbbdca33186c7c0296645b3/py_spy-0.4.1-py2.py3-none-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4972c21890b6814017e39ac233c22572c4a61fd874524ebc5ccab0f2237aee0a", size = 2147541, upload-time = "2025-07-31T19:33:20.565Z" },
+ { url = "https://files.pythonhosted.org/packages/68/fb/bc7f639aed026bca6e7beb1e33f6951e16b7d315594e7635a4f7d21d63f4/py_spy-0.4.1-py2.py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6a80ec05eb8a6883863a367c6a4d4f2d57de68466f7956b6367d4edd5c61bb29", size = 2763338, upload-time = "2025-07-31T19:33:22.202Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/da/fcc9a9fcd4ca946ff402cff20348e838b051d69f50f5d1f5dca4cd3c5eb8/py_spy-0.4.1-py2.py3-none-win_amd64.whl", hash = "sha256:d92e522bd40e9bf7d87c204033ce5bb5c828fca45fa28d970f58d71128069fdc", size = 1818784, upload-time = "2025-07-31T19:33:23.802Z" },
+]
+
+[[package]]
+name = "pyasn1"
+version = "0.6.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/fe/b6/6e630dff89739fcd427e3f72b3d905ce0acb85a45d4ec3e2678718a3487f/pyasn1-0.6.2.tar.gz", hash = "sha256:9b59a2b25ba7e4f8197db7686c09fb33e658b98339fadb826e9512629017833b", size = 146586, upload-time = "2026-01-16T18:04:18.534Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/44/b5/a96872e5184f354da9c84ae119971a0a4c221fe9b27a4d94bd43f2596727/pyasn1-0.6.2-py3-none-any.whl", hash = "sha256:1eb26d860996a18e9b6ed05e7aae0e9fc21619fcee6af91cca9bad4fbea224bf", size = 83371, upload-time = "2026-01-16T18:04:17.174Z" },
+]
+
+[[package]]
+name = "pyasn1-modules"
+version = "0.4.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pyasn1" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892, upload-time = "2025-03-28T02:41:22.17Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" },
+]
+
+[[package]]
+name = "pycparser"
+version = "3.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" },
+]
+
+[[package]]
+name = "pydantic"
+version = "2.12.5"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "annotated-types" },
+ { name = "pydantic-core" },
+ { name = "typing-extensions" },
+ { name = "typing-inspection" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591, upload-time = "2025-11-26T15:11:46.471Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580, upload-time = "2025-11-26T15:11:44.605Z" },
+]
+
+[[package]]
+name = "pydantic-core"
+version = "2.41.5"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5f/5d/5f6c63eebb5afee93bcaae4ce9a898f3373ca23df3ccaef086d0233a35a7/pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7", size = 2110990, upload-time = "2025-11-04T13:39:58.079Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/32/9c2e8ccb57c01111e0fd091f236c7b371c1bccea0fa85247ac55b1e2b6b6/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0", size = 1896003, upload-time = "2025-11-04T13:39:59.956Z" },
+ { url = "https://files.pythonhosted.org/packages/68/b8/a01b53cb0e59139fbc9e4fda3e9724ede8de279097179be4ff31f1abb65a/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69", size = 1919200, upload-time = "2025-11-04T13:40:02.241Z" },
+ { url = "https://files.pythonhosted.org/packages/38/de/8c36b5198a29bdaade07b5985e80a233a5ac27137846f3bc2d3b40a47360/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75", size = 2052578, upload-time = "2025-11-04T13:40:04.401Z" },
+ { url = "https://files.pythonhosted.org/packages/00/b5/0e8e4b5b081eac6cb3dbb7e60a65907549a1ce035a724368c330112adfdd/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05", size = 2208504, upload-time = "2025-11-04T13:40:06.072Z" },
+ { url = "https://files.pythonhosted.org/packages/77/56/87a61aad59c7c5b9dc8caad5a41a5545cba3810c3e828708b3d7404f6cef/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc", size = 2335816, upload-time = "2025-11-04T13:40:07.835Z" },
+ { url = "https://files.pythonhosted.org/packages/0d/76/941cc9f73529988688a665a5c0ecff1112b3d95ab48f81db5f7606f522d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c", size = 2075366, upload-time = "2025-11-04T13:40:09.804Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/43/ebef01f69baa07a482844faaa0a591bad1ef129253ffd0cdaa9d8a7f72d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5", size = 2171698, upload-time = "2025-11-04T13:40:12.004Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/87/41f3202e4193e3bacfc2c065fab7706ebe81af46a83d3e27605029c1f5a6/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c", size = 2132603, upload-time = "2025-11-04T13:40:13.868Z" },
+ { url = "https://files.pythonhosted.org/packages/49/7d/4c00df99cb12070b6bccdef4a195255e6020a550d572768d92cc54dba91a/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294", size = 2329591, upload-time = "2025-11-04T13:40:15.672Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/6a/ebf4b1d65d458f3cda6a7335d141305dfa19bdc61140a884d165a8a1bbc7/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1", size = 2319068, upload-time = "2025-11-04T13:40:17.532Z" },
+ { url = "https://files.pythonhosted.org/packages/49/3b/774f2b5cd4192d5ab75870ce4381fd89cf218af999515baf07e7206753f0/pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d", size = 1985908, upload-time = "2025-11-04T13:40:19.309Z" },
+ { url = "https://files.pythonhosted.org/packages/86/45/00173a033c801cacf67c190fef088789394feaf88a98a7035b0e40d53dc9/pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815", size = 2020145, upload-time = "2025-11-04T13:40:21.548Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/22/91fbc821fa6d261b376a3f73809f907cec5ca6025642c463d3488aad22fb/pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3", size = 1976179, upload-time = "2025-11-04T13:40:23.393Z" },
+ { url = "https://files.pythonhosted.org/packages/87/06/8806241ff1f70d9939f9af039c6c35f2360cf16e93c2ca76f184e76b1564/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9", size = 2120403, upload-time = "2025-11-04T13:40:25.248Z" },
+ { url = "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34", size = 1896206, upload-time = "2025-11-04T13:40:27.099Z" },
+ { url = "https://files.pythonhosted.org/packages/15/df/a4c740c0943e93e6500f9eb23f4ca7ec9bf71b19e608ae5b579678c8d02f/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0", size = 1919307, upload-time = "2025-11-04T13:40:29.806Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/e3/6324802931ae1d123528988e0e86587c2072ac2e5394b4bc2bc34b61ff6e/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33", size = 2063258, upload-time = "2025-11-04T13:40:33.544Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/d4/2230d7151d4957dd79c3044ea26346c148c98fbf0ee6ebd41056f2d62ab5/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e", size = 2214917, upload-time = "2025-11-04T13:40:35.479Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/9f/eaac5df17a3672fef0081b6c1bb0b82b33ee89aa5cec0d7b05f52fd4a1fa/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2", size = 2332186, upload-time = "2025-11-04T13:40:37.436Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586", size = 2073164, upload-time = "2025-11-04T13:40:40.289Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/e3/f6e262673c6140dd3305d144d032f7bd5f7497d3871c1428521f19f9efa2/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d", size = 2179146, upload-time = "2025-11-04T13:40:42.809Z" },
+ { url = "https://files.pythonhosted.org/packages/75/c7/20bd7fc05f0c6ea2056a4565c6f36f8968c0924f19b7d97bbfea55780e73/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740", size = 2137788, upload-time = "2025-11-04T13:40:44.752Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/8d/34318ef985c45196e004bc46c6eab2eda437e744c124ef0dbe1ff2c9d06b/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e", size = 2340133, upload-time = "2025-11-04T13:40:46.66Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/59/013626bf8c78a5a5d9350d12e7697d3d4de951a75565496abd40ccd46bee/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858", size = 2324852, upload-time = "2025-11-04T13:40:48.575Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/d9/c248c103856f807ef70c18a4f986693a46a8ffe1602e5d361485da502d20/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36", size = 1994679, upload-time = "2025-11-04T13:40:50.619Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/8b/341991b158ddab181cff136acd2552c9f35bd30380422a639c0671e99a91/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11", size = 2019766, upload-time = "2025-11-04T13:40:52.631Z" },
+ { url = "https://files.pythonhosted.org/packages/73/7d/f2f9db34af103bea3e09735bb40b021788a5e834c81eedb541991badf8f5/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd", size = 1981005, upload-time = "2025-11-04T13:40:54.734Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/28/46b7c5c9635ae96ea0fbb779e271a38129df2550f763937659ee6c5dbc65/pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a", size = 2119622, upload-time = "2025-11-04T13:40:56.68Z" },
+ { url = "https://files.pythonhosted.org/packages/74/1a/145646e5687e8d9a1e8d09acb278c8535ebe9e972e1f162ed338a622f193/pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14", size = 1891725, upload-time = "2025-11-04T13:40:58.807Z" },
+ { url = "https://files.pythonhosted.org/packages/23/04/e89c29e267b8060b40dca97bfc64a19b2a3cf99018167ea1677d96368273/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1", size = 1915040, upload-time = "2025-11-04T13:41:00.853Z" },
+ { url = "https://files.pythonhosted.org/packages/84/a3/15a82ac7bd97992a82257f777b3583d3e84bdb06ba6858f745daa2ec8a85/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66", size = 2063691, upload-time = "2025-11-04T13:41:03.504Z" },
+ { url = "https://files.pythonhosted.org/packages/74/9b/0046701313c6ef08c0c1cf0e028c67c770a4e1275ca73131563c5f2a310a/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869", size = 2213897, upload-time = "2025-11-04T13:41:05.804Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/cd/6bac76ecd1b27e75a95ca3a9a559c643b3afcd2dd62086d4b7a32a18b169/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2", size = 2333302, upload-time = "2025-11-04T13:41:07.809Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/d2/ef2074dc020dd6e109611a8be4449b98cd25e1b9b8a303c2f0fca2f2bcf7/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375", size = 2064877, upload-time = "2025-11-04T13:41:09.827Z" },
+ { url = "https://files.pythonhosted.org/packages/18/66/e9db17a9a763d72f03de903883c057b2592c09509ccfe468187f2a2eef29/pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553", size = 2180680, upload-time = "2025-11-04T13:41:12.379Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/9e/3ce66cebb929f3ced22be85d4c2399b8e85b622db77dad36b73c5387f8f8/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90", size = 2138960, upload-time = "2025-11-04T13:41:14.627Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/62/205a998f4327d2079326b01abee48e502ea739d174f0a89295c481a2272e/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07", size = 2339102, upload-time = "2025-11-04T13:41:16.868Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/0d/f05e79471e889d74d3d88f5bd20d0ed189ad94c2423d81ff8d0000aab4ff/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb", size = 2326039, upload-time = "2025-11-04T13:41:18.934Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/e1/e08a6208bb100da7e0c4b288eed624a703f4d129bde2da475721a80cab32/pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23", size = 1995126, upload-time = "2025-11-04T13:41:21.418Z" },
+ { url = "https://files.pythonhosted.org/packages/48/5d/56ba7b24e9557f99c9237e29f5c09913c81eeb2f3217e40e922353668092/pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf", size = 2015489, upload-time = "2025-11-04T13:41:24.076Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/bb/f7a190991ec9e3e0ba22e4993d8755bbc4a32925c0b5b42775c03e8148f9/pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0", size = 1977288, upload-time = "2025-11-04T13:41:26.33Z" },
+ { url = "https://files.pythonhosted.org/packages/92/ed/77542d0c51538e32e15afe7899d79efce4b81eee631d99850edc2f5e9349/pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a", size = 2120255, upload-time = "2025-11-04T13:41:28.569Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3", size = 1863760, upload-time = "2025-11-04T13:41:31.055Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/f0/e5e6b99d4191da102f2b0eb9687aaa7f5bea5d9964071a84effc3e40f997/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c", size = 1878092, upload-time = "2025-11-04T13:41:33.21Z" },
+ { url = "https://files.pythonhosted.org/packages/71/48/36fb760642d568925953bcc8116455513d6e34c4beaa37544118c36aba6d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612", size = 2053385, upload-time = "2025-11-04T13:41:35.508Z" },
+ { url = "https://files.pythonhosted.org/packages/20/25/92dc684dd8eb75a234bc1c764b4210cf2646479d54b47bf46061657292a8/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d", size = 2218832, upload-time = "2025-11-04T13:41:37.732Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/09/f53e0b05023d3e30357d82eb35835d0f6340ca344720a4599cd663dca599/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9", size = 2327585, upload-time = "2025-11-04T13:41:40Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/4e/2ae1aa85d6af35a39b236b1b1641de73f5a6ac4d5a7509f77b814885760c/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660", size = 2041078, upload-time = "2025-11-04T13:41:42.323Z" },
+ { url = "https://files.pythonhosted.org/packages/cd/13/2e215f17f0ef326fc72afe94776edb77525142c693767fc347ed6288728d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9", size = 2173914, upload-time = "2025-11-04T13:41:45.221Z" },
+ { url = "https://files.pythonhosted.org/packages/02/7a/f999a6dcbcd0e5660bc348a3991c8915ce6599f4f2c6ac22f01d7a10816c/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3", size = 2129560, upload-time = "2025-11-04T13:41:47.474Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/b1/6c990ac65e3b4c079a4fb9f5b05f5b013afa0f4ed6780a3dd236d2cbdc64/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf", size = 2329244, upload-time = "2025-11-04T13:41:49.992Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/02/3c562f3a51afd4d88fff8dffb1771b30cfdfd79befd9883ee094f5b6c0d8/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470", size = 2331955, upload-time = "2025-11-04T13:41:54.079Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload-time = "2025-11-04T13:41:56.606Z" },
+ { url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload-time = "2025-11-04T13:41:58.889Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769, upload-time = "2025-11-04T13:42:01.186Z" },
+ { url = "https://files.pythonhosted.org/packages/09/32/59b0c7e63e277fa7911c2fc70ccfb45ce4b98991e7ef37110663437005af/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd", size = 2110495, upload-time = "2025-11-04T13:42:49.689Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/81/05e400037eaf55ad400bcd318c05bb345b57e708887f07ddb2d20e3f0e98/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc", size = 1915388, upload-time = "2025-11-04T13:42:52.215Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/0d/e3549b2399f71d56476b77dbf3cf8937cec5cd70536bdc0e374a421d0599/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56", size = 1942879, upload-time = "2025-11-04T13:42:56.483Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/07/34573da085946b6a313d7c42f82f16e8920bfd730665de2d11c0c37a74b5/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", size = 2139017, upload-time = "2025-11-04T13:42:59.471Z" },
+]
+
+[[package]]
+name = "pydub"
+version = "0.25.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/fe/9a/e6bca0eed82db26562c73b5076539a4a08d3cffd19c3cc5913a3e61145fd/pydub-0.25.1.tar.gz", hash = "sha256:980a33ce9949cab2a569606b65674d748ecbca4f0796887fd6f46173a7b0d30f", size = 38326, upload-time = "2021-03-10T02:09:54.659Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a6/53/d78dc063216e62fc55f6b2eebb447f6a4b0a59f55c8406376f76bf959b08/pydub-0.25.1-py2.py3-none-any.whl", hash = "sha256:65617e33033874b59d87db603aa1ed450633288aefead953b30bded59cb599a6", size = 32327, upload-time = "2021-03-10T02:09:53.503Z" },
+]
+
+[[package]]
+name = "pygments"
+version = "2.19.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
+]
+
+[[package]]
+name = "python-dateutil"
+version = "2.9.0.post0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "six" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" },
+]
+
+[[package]]
+name = "python-discovery"
+version = "1.1.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "filelock" },
+ { name = "platformdirs" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/d7/7e/9f3b0dd3a074a6c3e1e79f35e465b1f2ee4b262d619de00cfce523cc9b24/python_discovery-1.1.3.tar.gz", hash = "sha256:7acca36e818cd88e9b2ba03e045ad7e93e1713e29c6bbfba5d90202310b7baa5", size = 56945, upload-time = "2026-03-10T15:08:15.038Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e7/80/73211fc5bfbfc562369b4aa61dc1e4bf07dc7b34df7b317e4539316b809c/python_discovery-1.1.3-py3-none-any.whl", hash = "sha256:90e795f0121bc84572e737c9aa9966311b9fde44ffb88a5953b3ec9b31c6945e", size = 31485, upload-time = "2026-03-10T15:08:13.06Z" },
+]
+
+[[package]]
+name = "python-dotenv"
+version = "1.2.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" },
+]
+
+[[package]]
+name = "python-multipart"
+version = "0.0.22"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/94/01/979e98d542a70714b0cb2b6728ed0b7c46792b695e3eaec3e20711271ca3/python_multipart-0.0.22.tar.gz", hash = "sha256:7340bef99a7e0032613f56dc36027b959fd3b30a787ed62d310e951f7c3a3a58", size = 37612, upload-time = "2026-01-25T10:15:56.219Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/1b/d0/397f9626e711ff749a95d96b7af99b9c566a9bb5129b8e4c10fc4d100304/python_multipart-0.0.22-py3-none-any.whl", hash = "sha256:2b2cd894c83d21bf49d702499531c7bafd057d730c201782048f7945d82de155", size = 24579, upload-time = "2026-01-25T10:15:54.811Z" },
+]
+
+[[package]]
+name = "pytz"
+version = "2026.1.post1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/56/db/b8721d71d945e6a8ac63c0fc900b2067181dbb50805958d4d4661cf7d277/pytz-2026.1.post1.tar.gz", hash = "sha256:3378dde6a0c3d26719182142c56e60c7f9af7e968076f31aae569d72a0358ee1", size = 321088, upload-time = "2026-03-03T07:47:50.683Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/10/99/781fe0c827be2742bcc775efefccb3b048a3a9c6ce9aec0cbf4a101677e5/pytz-2026.1.post1-py2.py3-none-any.whl", hash = "sha256:f2fd16142fda348286a75e1a524be810bb05d444e5a081f37f7affc635035f7a", size = 510489, upload-time = "2026-03-03T07:47:49.167Z" },
+]
+
+[[package]]
+name = "pyyaml"
+version = "6.0.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" },
+ { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" },
+ { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" },
+ { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" },
+ { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" },
+ { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" },
+ { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" },
+ { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" },
+ { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" },
+ { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" },
+ { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" },
+ { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" },
+ { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" },
+ { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" },
+ { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" },
+ { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" },
+ { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" },
+ { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" },
+]
+
+[[package]]
+name = "ray"
+version = "2.54.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "click" },
+ { name = "filelock" },
+ { name = "jsonschema" },
+ { name = "msgpack" },
+ { name = "packaging" },
+ { name = "protobuf" },
+ { name = "pyyaml" },
+ { name = "requests" },
+]
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/0e/16/45eefb51eb1767342a6dbf41af0b432279e422e56160705fcd1098a7ec53/ray-2.54.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:cf5c33b4b13850ec24a5bd5f9d9e0a8161f8e586bfd297e52913d170dec447fe", size = 70084880, upload-time = "2026-02-18T04:05:22.007Z" },
+ { url = "https://files.pythonhosted.org/packages/60/ad/e07aca3637e9c3ec4857ec4366208099cf8488ece8061a9925ba29b66382/ray-2.54.0-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:795ae21d6b764245d3f521bc5833446d58569e7dfde9c5777417eb285d87450f", size = 72107346, upload-time = "2026-02-18T04:05:27.999Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/b9/cc5ea8460c3dc602e6b7198277a7c59ba2b8929374ab22efa8df9f3deac8/ray-2.54.0-cp312-cp312-manylinux2014_x86_64.whl", hash = "sha256:a972afd5aa3dda99d0b2f369b5f62e5dd95865ab7d37bf2e0a0e0d2cfbd9b325", size = 72967230, upload-time = "2026-02-18T04:05:33.771Z" },
+ { url = "https://files.pythonhosted.org/packages/de/d7/744de3b1bb881701330ddcbb2f6efaccd65915d564ece899a3838f9fb105/ray-2.54.0-cp312-cp312-win_amd64.whl", hash = "sha256:2ee074ede491d0aacfa339c003f5d7a15826e1e2a72ce873234ccbc0446e19b3", size = 27427353, upload-time = "2026-02-18T04:05:38.853Z" },
+ { url = "https://files.pythonhosted.org/packages/7f/f2/5c0161d10445e703b7d01413ab54ec1cc5e27032555279d296df89b9c4ee/ray-2.54.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:5ad77961fea16c697a0fb0e51216dd39c0bec28868cde54ac668edd58d12b8ae", size = 70030991, upload-time = "2026-02-18T04:05:43.966Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/8c/4a4a38eaec6e9614076a96967f58540f4f8d4aa0c793f43150c5df23cb9a/ray-2.54.0-cp313-cp313-manylinux2014_aarch64.whl", hash = "sha256:8952c23a8aa94f10728c2d16e0dc3732d09aa0e6254801757ff494984a214f45", size = 72013826, upload-time = "2026-02-18T04:05:49.866Z" },
+ { url = "https://files.pythonhosted.org/packages/42/ac/e7ec2a406bd755f61c7090460fa5ab3f09b00c3c2d8db6d0b559f78a30eb/ray-2.54.0-cp313-cp313-manylinux2014_x86_64.whl", hash = "sha256:ab89e6089abb6e46fb98fdd96d399b31a852d79127cd8ac00746c61d93defa2c", size = 72880209, upload-time = "2026-02-18T04:05:55.498Z" },
+]
+
+[package.optional-dependencies]
+serve = [
+ { name = "aiohttp" },
+ { name = "aiohttp-cors" },
+ { name = "colorful" },
+ { name = "fastapi" },
+ { name = "grpcio" },
+ { name = "opencensus" },
+ { name = "opentelemetry-exporter-prometheus" },
+ { name = "opentelemetry-proto" },
+ { name = "opentelemetry-sdk" },
+ { name = "prometheus-client" },
+ { name = "py-spy" },
+ { name = "pydantic" },
+ { name = "requests" },
+ { name = "smart-open" },
+ { name = "starlette" },
+ { name = "uvicorn", extra = ["standard"] },
+ { name = "virtualenv" },
+ { name = "watchfiles" },
+]
+
+[[package]]
+name = "referencing"
+version = "0.37.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "attrs" },
+ { name = "rpds-py" },
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036, upload-time = "2025-10-13T15:30:48.871Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766, upload-time = "2025-10-13T15:30:47.625Z" },
+]
+
+[[package]]
+name = "requests"
+version = "2.32.5"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "certifi" },
+ { name = "charset-normalizer" },
+ { name = "idna" },
+ { name = "urllib3" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" },
+]
+
+[[package]]
+name = "rich"
+version = "14.3.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "markdown-it-py" },
+ { name = "pygments" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/b3/c6/f3b320c27991c46f43ee9d856302c70dc2d0fb2dba4842ff739d5f46b393/rich-14.3.3.tar.gz", hash = "sha256:b8daa0b9e4eef54dd8cf7c86c03713f53241884e814f4e2f5fb342fe520f639b", size = 230582, upload-time = "2026-02-19T17:23:12.474Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/14/25/b208c5683343959b670dc001595f2f3737e051da617f66c31f7c4fa93abc/rich-14.3.3-py3-none-any.whl", hash = "sha256:793431c1f8619afa7d3b52b2cdec859562b950ea0d4b6b505397612db8d5362d", size = 310458, upload-time = "2026-02-19T17:23:13.732Z" },
+]
+
+[[package]]
+name = "rpds-py"
+version = "0.30.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/20/af/3f2f423103f1113b36230496629986e0ef7e199d2aa8392452b484b38ced/rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84", size = 69469, upload-time = "2025-11-30T20:24:38.837Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/03/e7/98a2f4ac921d82f33e03f3835f5bf3a4a40aa1bfdc57975e74a97b2b4bdd/rpds_py-0.30.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a161f20d9a43006833cd7068375a94d035714d73a172b681d8881820600abfad", size = 375086, upload-time = "2025-11-30T20:22:17.93Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/a1/bca7fd3d452b272e13335db8d6b0b3ecde0f90ad6f16f3328c6fb150c889/rpds_py-0.30.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6abc8880d9d036ecaafe709079969f56e876fcf107f7a8e9920ba6d5a3878d05", size = 359053, upload-time = "2025-11-30T20:22:19.297Z" },
+ { url = "https://files.pythonhosted.org/packages/65/1c/ae157e83a6357eceff62ba7e52113e3ec4834a84cfe07fa4b0757a7d105f/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca28829ae5f5d569bb62a79512c842a03a12576375d5ece7d2cadf8abe96ec28", size = 390763, upload-time = "2025-11-30T20:22:21.661Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/36/eb2eb8515e2ad24c0bd43c3ee9cd74c33f7ca6430755ccdb240fd3144c44/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a1010ed9524c73b94d15919ca4d41d8780980e1765babf85f9a2f90d247153dd", size = 408951, upload-time = "2025-11-30T20:22:23.408Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/65/ad8dc1784a331fabbd740ef6f71ce2198c7ed0890dab595adb9ea2d775a1/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8d1736cfb49381ba528cd5baa46f82fdc65c06e843dab24dd70b63d09121b3f", size = 514622, upload-time = "2025-11-30T20:22:25.16Z" },
+ { url = "https://files.pythonhosted.org/packages/63/8e/0cfa7ae158e15e143fe03993b5bcd743a59f541f5952e1546b1ac1b5fd45/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d948b135c4693daff7bc2dcfc4ec57237a29bd37e60c2fabf5aff2bbacf3e2f1", size = 414492, upload-time = "2025-11-30T20:22:26.505Z" },
+ { url = "https://files.pythonhosted.org/packages/60/1b/6f8f29f3f995c7ffdde46a626ddccd7c63aefc0efae881dc13b6e5d5bb16/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47f236970bccb2233267d89173d3ad2703cd36a0e2a6e92d0560d333871a3d23", size = 394080, upload-time = "2025-11-30T20:22:27.934Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/d5/a266341051a7a3ca2f4b750a3aa4abc986378431fc2da508c5034d081b70/rpds_py-0.30.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:2e6ecb5a5bcacf59c3f912155044479af1d0b6681280048b338b28e364aca1f6", size = 408680, upload-time = "2025-11-30T20:22:29.341Z" },
+ { url = "https://files.pythonhosted.org/packages/10/3b/71b725851df9ab7a7a4e33cf36d241933da66040d195a84781f49c50490c/rpds_py-0.30.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a8fa71a2e078c527c3e9dc9fc5a98c9db40bcc8a92b4e8858e36d329f8684b51", size = 423589, upload-time = "2025-11-30T20:22:31.469Z" },
+ { url = "https://files.pythonhosted.org/packages/00/2b/e59e58c544dc9bd8bd8384ecdb8ea91f6727f0e37a7131baeff8d6f51661/rpds_py-0.30.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:73c67f2db7bc334e518d097c6d1e6fed021bbc9b7d678d6cc433478365d1d5f5", size = 573289, upload-time = "2025-11-30T20:22:32.997Z" },
+ { url = "https://files.pythonhosted.org/packages/da/3e/a18e6f5b460893172a7d6a680e86d3b6bc87a54c1f0b03446a3c8c7b588f/rpds_py-0.30.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5ba103fb455be00f3b1c2076c9d4264bfcb037c976167a6047ed82f23153f02e", size = 599737, upload-time = "2025-11-30T20:22:34.419Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/e2/714694e4b87b85a18e2c243614974413c60aa107fd815b8cbc42b873d1d7/rpds_py-0.30.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7cee9c752c0364588353e627da8a7e808a66873672bcb5f52890c33fd965b394", size = 563120, upload-time = "2025-11-30T20:22:35.903Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/ab/d5d5e3bcedb0a77f4f613706b750e50a5a3ba1c15ccd3665ecc636c968fd/rpds_py-0.30.0-cp312-cp312-win32.whl", hash = "sha256:1ab5b83dbcf55acc8b08fc62b796ef672c457b17dbd7820a11d6c52c06839bdf", size = 223782, upload-time = "2025-11-30T20:22:37.271Z" },
+ { url = "https://files.pythonhosted.org/packages/39/3b/f786af9957306fdc38a74cef405b7b93180f481fb48453a114bb6465744a/rpds_py-0.30.0-cp312-cp312-win_amd64.whl", hash = "sha256:a090322ca841abd453d43456ac34db46e8b05fd9b3b4ac0c78bcde8b089f959b", size = 240463, upload-time = "2025-11-30T20:22:39.021Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/d2/b91dc748126c1559042cfe41990deb92c4ee3e2b415f6b5234969ffaf0cc/rpds_py-0.30.0-cp312-cp312-win_arm64.whl", hash = "sha256:669b1805bd639dd2989b281be2cfd951c6121b65e729d9b843e9639ef1fd555e", size = 230868, upload-time = "2025-11-30T20:22:40.493Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/dc/d61221eb88ff410de3c49143407f6f3147acf2538c86f2ab7ce65ae7d5f9/rpds_py-0.30.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f83424d738204d9770830d35290ff3273fbb02b41f919870479fab14b9d303b2", size = 374887, upload-time = "2025-11-30T20:22:41.812Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/32/55fb50ae104061dbc564ef15cc43c013dc4a9f4527a1f4d99baddf56fe5f/rpds_py-0.30.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e7536cd91353c5273434b4e003cbda89034d67e7710eab8761fd918ec6c69cf8", size = 358904, upload-time = "2025-11-30T20:22:43.479Z" },
+ { url = "https://files.pythonhosted.org/packages/58/70/faed8186300e3b9bdd138d0273109784eea2396c68458ed580f885dfe7ad/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2771c6c15973347f50fece41fc447c054b7ac2ae0502388ce3b6738cd366e3d4", size = 389945, upload-time = "2025-11-30T20:22:44.819Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/a8/073cac3ed2c6387df38f71296d002ab43496a96b92c823e76f46b8af0543/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0a59119fc6e3f460315fe9d08149f8102aa322299deaa5cab5b40092345c2136", size = 407783, upload-time = "2025-11-30T20:22:46.103Z" },
+ { url = "https://files.pythonhosted.org/packages/77/57/5999eb8c58671f1c11eba084115e77a8899d6e694d2a18f69f0ba471ec8b/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:76fec018282b4ead0364022e3c54b60bf368b9d926877957a8624b58419169b7", size = 515021, upload-time = "2025-11-30T20:22:47.458Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/af/5ab4833eadc36c0a8ed2bc5c0de0493c04f6c06de223170bd0798ff98ced/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:692bef75a5525db97318e8cd061542b5a79812d711ea03dbc1f6f8dbb0c5f0d2", size = 414589, upload-time = "2025-11-30T20:22:48.872Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/de/f7192e12b21b9e9a68a6d0f249b4af3fdcdff8418be0767a627564afa1f1/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9027da1ce107104c50c81383cae773ef5c24d296dd11c99e2629dbd7967a20c6", size = 394025, upload-time = "2025-11-30T20:22:50.196Z" },
+ { url = "https://files.pythonhosted.org/packages/91/c4/fc70cd0249496493500e7cc2de87504f5aa6509de1e88623431fec76d4b6/rpds_py-0.30.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:9cf69cdda1f5968a30a359aba2f7f9aa648a9ce4b580d6826437f2b291cfc86e", size = 408895, upload-time = "2025-11-30T20:22:51.87Z" },
+ { url = "https://files.pythonhosted.org/packages/58/95/d9275b05ab96556fefff73a385813eb66032e4c99f411d0795372d9abcea/rpds_py-0.30.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a4796a717bf12b9da9d3ad002519a86063dcac8988b030e405704ef7d74d2d9d", size = 422799, upload-time = "2025-11-30T20:22:53.341Z" },
+ { url = "https://files.pythonhosted.org/packages/06/c1/3088fc04b6624eb12a57eb814f0d4997a44b0d208d6cace713033ff1a6ba/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5d4c2aa7c50ad4728a094ebd5eb46c452e9cb7edbfdb18f9e1221f597a73e1e7", size = 572731, upload-time = "2025-11-30T20:22:54.778Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/42/c612a833183b39774e8ac8fecae81263a68b9583ee343db33ab571a7ce55/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ba81a9203d07805435eb06f536d95a266c21e5b2dfbf6517748ca40c98d19e31", size = 599027, upload-time = "2025-11-30T20:22:56.212Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/60/525a50f45b01d70005403ae0e25f43c0384369ad24ffe46e8d9068b50086/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:945dccface01af02675628334f7cf49c2af4c1c904748efc5cf7bbdf0b579f95", size = 563020, upload-time = "2025-11-30T20:22:58.2Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/5d/47c4655e9bcd5ca907148535c10e7d489044243cc9941c16ed7cd53be91d/rpds_py-0.30.0-cp313-cp313-win32.whl", hash = "sha256:b40fb160a2db369a194cb27943582b38f79fc4887291417685f3ad693c5a1d5d", size = 223139, upload-time = "2025-11-30T20:23:00.209Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/e1/485132437d20aa4d3e1d8b3fb5a5e65aa8139f1e097080c2a8443201742c/rpds_py-0.30.0-cp313-cp313-win_amd64.whl", hash = "sha256:806f36b1b605e2d6a72716f321f20036b9489d29c51c91f4dd29a3e3afb73b15", size = 240224, upload-time = "2025-11-30T20:23:02.008Z" },
+ { url = "https://files.pythonhosted.org/packages/24/95/ffd128ed1146a153d928617b0ef673960130be0009c77d8fbf0abe306713/rpds_py-0.30.0-cp313-cp313-win_arm64.whl", hash = "sha256:d96c2086587c7c30d44f31f42eae4eac89b60dabbac18c7669be3700f13c3ce1", size = 230645, upload-time = "2025-11-30T20:23:03.43Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/1b/b10de890a0def2a319a2626334a7f0ae388215eb60914dbac8a3bae54435/rpds_py-0.30.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:eb0b93f2e5c2189ee831ee43f156ed34e2a89a78a66b98cadad955972548be5a", size = 364443, upload-time = "2025-11-30T20:23:04.878Z" },
+ { url = "https://files.pythonhosted.org/packages/0d/bf/27e39f5971dc4f305a4fb9c672ca06f290f7c4e261c568f3dea16a410d47/rpds_py-0.30.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:922e10f31f303c7c920da8981051ff6d8c1a56207dbdf330d9047f6d30b70e5e", size = 353375, upload-time = "2025-11-30T20:23:06.342Z" },
+ { url = "https://files.pythonhosted.org/packages/40/58/442ada3bba6e8e6615fc00483135c14a7538d2ffac30e2d933ccf6852232/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdc62c8286ba9bf7f47befdcea13ea0e26bf294bda99758fd90535cbaf408000", size = 383850, upload-time = "2025-11-30T20:23:07.825Z" },
+ { url = "https://files.pythonhosted.org/packages/14/14/f59b0127409a33c6ef6f5c1ebd5ad8e32d7861c9c7adfa9a624fc3889f6c/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47f9a91efc418b54fb8190a6b4aa7813a23fb79c51f4bb84e418f5476c38b8db", size = 392812, upload-time = "2025-11-30T20:23:09.228Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/66/e0be3e162ac299b3a22527e8913767d869e6cc75c46bd844aa43fb81ab62/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f3587eb9b17f3789ad50824084fa6f81921bbf9a795826570bda82cb3ed91f2", size = 517841, upload-time = "2025-11-30T20:23:11.186Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/55/fa3b9cf31d0c963ecf1ba777f7cf4b2a2c976795ac430d24a1f43d25a6ba/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39c02563fc592411c2c61d26b6c5fe1e51eaa44a75aa2c8735ca88b0d9599daa", size = 408149, upload-time = "2025-11-30T20:23:12.864Z" },
+ { url = "https://files.pythonhosted.org/packages/60/ca/780cf3b1a32b18c0f05c441958d3758f02544f1d613abf9488cd78876378/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51a1234d8febafdfd33a42d97da7a43f5dcb120c1060e352a3fbc0c6d36e2083", size = 383843, upload-time = "2025-11-30T20:23:14.638Z" },
+ { url = "https://files.pythonhosted.org/packages/82/86/d5f2e04f2aa6247c613da0c1dd87fcd08fa17107e858193566048a1e2f0a/rpds_py-0.30.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:eb2c4071ab598733724c08221091e8d80e89064cd472819285a9ab0f24bcedb9", size = 396507, upload-time = "2025-11-30T20:23:16.105Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/9a/453255d2f769fe44e07ea9785c8347edaf867f7026872e76c1ad9f7bed92/rpds_py-0.30.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6bdfdb946967d816e6adf9a3d8201bfad269c67efe6cefd7093ef959683c8de0", size = 414949, upload-time = "2025-11-30T20:23:17.539Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/31/622a86cdc0c45d6df0e9ccb6becdba5074735e7033c20e401a6d9d0e2ca0/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c77afbd5f5250bf27bf516c7c4a016813eb2d3e116139aed0096940c5982da94", size = 565790, upload-time = "2025-11-30T20:23:19.029Z" },
+ { url = "https://files.pythonhosted.org/packages/1c/5d/15bbf0fb4a3f58a3b1c67855ec1efcc4ceaef4e86644665fff03e1b66d8d/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:61046904275472a76c8c90c9ccee9013d70a6d0f73eecefd38c1ae7c39045a08", size = 590217, upload-time = "2025-11-30T20:23:20.885Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/61/21b8c41f68e60c8cc3b2e25644f0e3681926020f11d06ab0b78e3c6bbff1/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c5f36a861bc4b7da6516dbdf302c55313afa09b81931e8280361a4f6c9a2d27", size = 555806, upload-time = "2025-11-30T20:23:22.488Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/39/7e067bb06c31de48de3eb200f9fc7c58982a4d3db44b07e73963e10d3be9/rpds_py-0.30.0-cp313-cp313t-win32.whl", hash = "sha256:3d4a69de7a3e50ffc214ae16d79d8fbb0922972da0356dcf4d0fdca2878559c6", size = 211341, upload-time = "2025-11-30T20:23:24.449Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/4d/222ef0b46443cf4cf46764d9c630f3fe4abaa7245be9417e56e9f52b8f65/rpds_py-0.30.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f14fc5df50a716f7ece6a80b6c78bb35ea2ca47c499e422aa4463455dd96d56d", size = 225768, upload-time = "2025-11-30T20:23:25.908Z" },
+ { url = "https://files.pythonhosted.org/packages/86/81/dad16382ebbd3d0e0328776d8fd7ca94220e4fa0798d1dc5e7da48cb3201/rpds_py-0.30.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:68f19c879420aa08f61203801423f6cd5ac5f0ac4ac82a2368a9fcd6a9a075e0", size = 362099, upload-time = "2025-11-30T20:23:27.316Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/60/19f7884db5d5603edf3c6bce35408f45ad3e97e10007df0e17dd57af18f8/rpds_py-0.30.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ec7c4490c672c1a0389d319b3a9cfcd098dcdc4783991553c332a15acf7249be", size = 353192, upload-time = "2025-11-30T20:23:29.151Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/c4/76eb0e1e72d1a9c4703c69607cec123c29028bff28ce41588792417098ac/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f251c812357a3fed308d684a5079ddfb9d933860fc6de89f2b7ab00da481e65f", size = 384080, upload-time = "2025-11-30T20:23:30.785Z" },
+ { url = "https://files.pythonhosted.org/packages/72/87/87ea665e92f3298d1b26d78814721dc39ed8d2c74b86e83348d6b48a6f31/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac98b175585ecf4c0348fd7b29c3864bda53b805c773cbf7bfdaffc8070c976f", size = 394841, upload-time = "2025-11-30T20:23:32.209Z" },
+ { url = "https://files.pythonhosted.org/packages/77/ad/7783a89ca0587c15dcbf139b4a8364a872a25f861bdb88ed99f9b0dec985/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3e62880792319dbeb7eb866547f2e35973289e7d5696c6e295476448f5b63c87", size = 516670, upload-time = "2025-11-30T20:23:33.742Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/3c/2882bdac942bd2172f3da574eab16f309ae10a3925644e969536553cb4ee/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e7fc54e0900ab35d041b0601431b0a0eb495f0851a0639b6ef90f7741b39a18", size = 408005, upload-time = "2025-11-30T20:23:35.253Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/81/9a91c0111ce1758c92516a3e44776920b579d9a7c09b2b06b642d4de3f0f/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47e77dc9822d3ad616c3d5759ea5631a75e5809d5a28707744ef79d7a1bcfcad", size = 382112, upload-time = "2025-11-30T20:23:36.842Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/8e/1da49d4a107027e5fbc64daeab96a0706361a2918da10cb41769244b805d/rpds_py-0.30.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:b4dc1a6ff022ff85ecafef7979a2c6eb423430e05f1165d6688234e62ba99a07", size = 399049, upload-time = "2025-11-30T20:23:38.343Z" },
+ { url = "https://files.pythonhosted.org/packages/df/5a/7ee239b1aa48a127570ec03becbb29c9d5a9eb092febbd1699d567cae859/rpds_py-0.30.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4559c972db3a360808309e06a74628b95eaccbf961c335c8fe0d590cf587456f", size = 415661, upload-time = "2025-11-30T20:23:40.263Z" },
+ { url = "https://files.pythonhosted.org/packages/70/ea/caa143cf6b772f823bc7929a45da1fa83569ee49b11d18d0ada7f5ee6fd6/rpds_py-0.30.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:0ed177ed9bded28f8deb6ab40c183cd1192aa0de40c12f38be4d59cd33cb5c65", size = 565606, upload-time = "2025-11-30T20:23:42.186Z" },
+ { url = "https://files.pythonhosted.org/packages/64/91/ac20ba2d69303f961ad8cf55bf7dbdb4763f627291ba3d0d7d67333cced9/rpds_py-0.30.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ad1fa8db769b76ea911cb4e10f049d80bf518c104f15b3edb2371cc65375c46f", size = 591126, upload-time = "2025-11-30T20:23:44.086Z" },
+ { url = "https://files.pythonhosted.org/packages/21/20/7ff5f3c8b00c8a95f75985128c26ba44503fb35b8e0259d812766ea966c7/rpds_py-0.30.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:46e83c697b1f1c72b50e5ee5adb4353eef7406fb3f2043d64c33f20ad1c2fc53", size = 553371, upload-time = "2025-11-30T20:23:46.004Z" },
+ { url = "https://files.pythonhosted.org/packages/72/c7/81dadd7b27c8ee391c132a6b192111ca58d866577ce2d9b0ca157552cce0/rpds_py-0.30.0-cp314-cp314-win32.whl", hash = "sha256:ee454b2a007d57363c2dfd5b6ca4a5d7e2c518938f8ed3b706e37e5d470801ed", size = 215298, upload-time = "2025-11-30T20:23:47.696Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/d2/1aaac33287e8cfb07aab2e6b8ac1deca62f6f65411344f1433c55e6f3eb8/rpds_py-0.30.0-cp314-cp314-win_amd64.whl", hash = "sha256:95f0802447ac2d10bcc69f6dc28fe95fdf17940367b21d34e34c737870758950", size = 228604, upload-time = "2025-11-30T20:23:49.501Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/95/ab005315818cc519ad074cb7784dae60d939163108bd2b394e60dc7b5461/rpds_py-0.30.0-cp314-cp314-win_arm64.whl", hash = "sha256:613aa4771c99f03346e54c3f038e4cc574ac09a3ddfb0e8878487335e96dead6", size = 222391, upload-time = "2025-11-30T20:23:50.96Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/68/154fe0194d83b973cdedcdcc88947a2752411165930182ae41d983dcefa6/rpds_py-0.30.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:7e6ecfcb62edfd632e56983964e6884851786443739dbfe3582947e87274f7cb", size = 364868, upload-time = "2025-11-30T20:23:52.494Z" },
+ { url = "https://files.pythonhosted.org/packages/83/69/8bbc8b07ec854d92a8b75668c24d2abcb1719ebf890f5604c61c9369a16f/rpds_py-0.30.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a1d0bc22a7cdc173fedebb73ef81e07faef93692b8c1ad3733b67e31e1b6e1b8", size = 353747, upload-time = "2025-11-30T20:23:54.036Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/00/ba2e50183dbd9abcce9497fa5149c62b4ff3e22d338a30d690f9af970561/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d08f00679177226c4cb8c5265012eea897c8ca3b93f429e546600c971bcbae7", size = 383795, upload-time = "2025-11-30T20:23:55.556Z" },
+ { url = "https://files.pythonhosted.org/packages/05/6f/86f0272b84926bcb0e4c972262f54223e8ecc556b3224d281e6598fc9268/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5965af57d5848192c13534f90f9dd16464f3c37aaf166cc1da1cae1fd5a34898", size = 393330, upload-time = "2025-11-30T20:23:57.033Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/e9/0e02bb2e6dc63d212641da45df2b0bf29699d01715913e0d0f017ee29438/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a4e86e34e9ab6b667c27f3211ca48f73dba7cd3d90f8d5b11be56e5dbc3fb4e", size = 518194, upload-time = "2025-11-30T20:23:58.637Z" },
+ { url = "https://files.pythonhosted.org/packages/ee/ca/be7bca14cf21513bdf9c0606aba17d1f389ea2b6987035eb4f62bd923f25/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5d3e6b26f2c785d65cc25ef1e5267ccbe1b069c5c21b8cc724efee290554419", size = 408340, upload-time = "2025-11-30T20:24:00.2Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/c7/736e00ebf39ed81d75544c0da6ef7b0998f8201b369acf842f9a90dc8fce/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:626a7433c34566535b6e56a1b39a7b17ba961e97ce3b80ec62e6f1312c025551", size = 383765, upload-time = "2025-11-30T20:24:01.759Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/3f/da50dfde9956aaf365c4adc9533b100008ed31aea635f2b8d7b627e25b49/rpds_py-0.30.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:acd7eb3f4471577b9b5a41baf02a978e8bdeb08b4b355273994f8b87032000a8", size = 396834, upload-time = "2025-11-30T20:24:03.687Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/00/34bcc2565b6020eab2623349efbdec810676ad571995911f1abdae62a3a0/rpds_py-0.30.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fe5fa731a1fa8a0a56b0977413f8cacac1768dad38d16b3a296712709476fbd5", size = 415470, upload-time = "2025-11-30T20:24:05.232Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/28/882e72b5b3e6f718d5453bd4d0d9cf8df36fddeb4ddbbab17869d5868616/rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:74a3243a411126362712ee1524dfc90c650a503502f135d54d1b352bd01f2404", size = 565630, upload-time = "2025-11-30T20:24:06.878Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/97/04a65539c17692de5b85c6e293520fd01317fd878ea1995f0367d4532fb1/rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:3e8eeb0544f2eb0d2581774be4c3410356eba189529a6b3e36bbbf9696175856", size = 591148, upload-time = "2025-11-30T20:24:08.445Z" },
+ { url = "https://files.pythonhosted.org/packages/85/70/92482ccffb96f5441aab93e26c4d66489eb599efdcf96fad90c14bbfb976/rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:dbd936cde57abfee19ab3213cf9c26be06d60750e60a8e4dd85d1ab12c8b1f40", size = 556030, upload-time = "2025-11-30T20:24:10.956Z" },
+ { url = "https://files.pythonhosted.org/packages/20/53/7c7e784abfa500a2b6b583b147ee4bb5a2b3747a9166bab52fec4b5b5e7d/rpds_py-0.30.0-cp314-cp314t-win32.whl", hash = "sha256:dc824125c72246d924f7f796b4f63c1e9dc810c7d9e2355864b3c3a73d59ade0", size = 211570, upload-time = "2025-11-30T20:24:12.735Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/02/fa464cdfbe6b26e0600b62c528b72d8608f5cc49f96b8d6e38c95d60c676/rpds_py-0.30.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27f4b0e92de5bfbc6f86e43959e6edd1425c33b5e69aab0984a72047f2bcf1e3", size = 226532, upload-time = "2025-11-30T20:24:14.634Z" },
+]
+
+[[package]]
+name = "rsa"
+version = "4.9.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pyasn1" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034, upload-time = "2025-04-16T09:51:18.218Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload-time = "2025-04-16T09:51:17.142Z" },
+]
+
+[[package]]
+name = "safehttpx"
+version = "0.1.7"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "httpx" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/89/d1/4282284d9cf1ee873607a46442da977fc3c985059315ab23610be31d5885/safehttpx-0.1.7.tar.gz", hash = "sha256:db201c0978c41eddb8bb480f3eee59dd67304fdd91646035e9d9a720049a9d23", size = 10385, upload-time = "2025-10-24T18:30:09.783Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2e/a3/0f0b7d78e2f1eb9e8e1afbff1d2bff8d60144aee17aca51c065b516743dd/safehttpx-0.1.7-py3-none-any.whl", hash = "sha256:c4f4a162db6993464d7ca3d7cc4af0ffc6515a606dfd220b9f82c6945d869cde", size = 8959, upload-time = "2025-10-24T18:30:08.733Z" },
+]
+
+[[package]]
+name = "scikit-learn"
+version = "1.8.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "joblib" },
+ { name = "numpy" },
+ { name = "scipy" },
+ { name = "threadpoolctl" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/0e/d4/40988bf3b8e34feec1d0e6a051446b1f66225f8529b9309becaeef62b6c4/scikit_learn-1.8.0.tar.gz", hash = "sha256:9bccbb3b40e3de10351f8f5068e105d0f4083b1a65fa07b6634fbc401a6287fd", size = 7335585, upload-time = "2025-12-10T07:08:53.618Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/90/74/e6a7cc4b820e95cc38cf36cd74d5aa2b42e8ffc2d21fe5a9a9c45c1c7630/scikit_learn-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5fb63362b5a7ddab88e52b6dbb47dac3fd7dafeee740dc6c8d8a446ddedade8e", size = 8548242, upload-time = "2025-12-10T07:07:51.568Z" },
+ { url = "https://files.pythonhosted.org/packages/49/d8/9be608c6024d021041c7f0b3928d4749a706f4e2c3832bbede4fb4f58c95/scikit_learn-1.8.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:5025ce924beccb28298246e589c691fe1b8c1c96507e6d27d12c5fadd85bfd76", size = 8079075, upload-time = "2025-12-10T07:07:53.697Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/47/f187b4636ff80cc63f21cd40b7b2d177134acaa10f6bb73746130ee8c2e5/scikit_learn-1.8.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4496bb2cf7a43ce1a2d7524a79e40bc5da45cf598dbf9545b7e8316ccba47bb4", size = 8660492, upload-time = "2025-12-10T07:07:55.574Z" },
+ { url = "https://files.pythonhosted.org/packages/97/74/b7a304feb2b49df9fafa9382d4d09061a96ee9a9449a7cbea7988dda0828/scikit_learn-1.8.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a0bcfe4d0d14aec44921545fd2af2338c7471de9cb701f1da4c9d85906ab847a", size = 8931904, upload-time = "2025-12-10T07:07:57.666Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/c4/0ab22726a04ede56f689476b760f98f8f46607caecff993017ac1b64aa5d/scikit_learn-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:35c007dedb2ffe38fe3ee7d201ebac4a2deccd2408e8621d53067733e3c74809", size = 8019359, upload-time = "2025-12-10T07:07:59.838Z" },
+ { url = "https://files.pythonhosted.org/packages/24/90/344a67811cfd561d7335c1b96ca21455e7e472d281c3c279c4d3f2300236/scikit_learn-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:8c497fff237d7b4e07e9ef1a640887fa4fb765647f86fbe00f969ff6280ce2bb", size = 7641898, upload-time = "2025-12-10T07:08:01.36Z" },
+ { url = "https://files.pythonhosted.org/packages/03/aa/e22e0768512ce9255eba34775be2e85c2048da73da1193e841707f8f039c/scikit_learn-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0d6ae97234d5d7079dc0040990a6f7aeb97cb7fa7e8945f1999a429b23569e0a", size = 8513770, upload-time = "2025-12-10T07:08:03.251Z" },
+ { url = "https://files.pythonhosted.org/packages/58/37/31b83b2594105f61a381fc74ca19e8780ee923be2d496fcd8d2e1147bd99/scikit_learn-1.8.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:edec98c5e7c128328124a029bceb09eda2d526997780fef8d65e9a69eead963e", size = 8044458, upload-time = "2025-12-10T07:08:05.336Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/5a/3f1caed8765f33eabb723596666da4ebbf43d11e96550fb18bdec42b467b/scikit_learn-1.8.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:74b66d8689d52ed04c271e1329f0c61635bcaf5b926db9b12d58914cdc01fe57", size = 8610341, upload-time = "2025-12-10T07:08:07.732Z" },
+ { url = "https://files.pythonhosted.org/packages/38/cf/06896db3f71c75902a8e9943b444a56e727418f6b4b4a90c98c934f51ed4/scikit_learn-1.8.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8fdf95767f989b0cfedb85f7ed8ca215d4be728031f56ff5a519ee1e3276dc2e", size = 8900022, upload-time = "2025-12-10T07:08:09.862Z" },
+ { url = "https://files.pythonhosted.org/packages/1c/f9/9b7563caf3ec8873e17a31401858efab6b39a882daf6c1bfa88879c0aa11/scikit_learn-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:2de443b9373b3b615aec1bb57f9baa6bb3a9bd093f1269ba95c17d870422b271", size = 7989409, upload-time = "2025-12-10T07:08:12.028Z" },
+ { url = "https://files.pythonhosted.org/packages/49/bd/1f4001503650e72c4f6009ac0c4413cb17d2d601cef6f71c0453da2732fc/scikit_learn-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:eddde82a035681427cbedded4e6eff5e57fa59216c2e3e90b10b19ab1d0a65c3", size = 7619760, upload-time = "2025-12-10T07:08:13.688Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/7d/a630359fc9dcc95496588c8d8e3245cc8fd81980251079bc09c70d41d951/scikit_learn-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:7cc267b6108f0a1499a734167282c00c4ebf61328566b55ef262d48e9849c735", size = 8826045, upload-time = "2025-12-10T07:08:15.215Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/56/a0c86f6930cfcd1c7054a2bc417e26960bb88d32444fe7f71d5c2cfae891/scikit_learn-1.8.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:fe1c011a640a9f0791146011dfd3c7d9669785f9fed2b2a5f9e207536cf5c2fd", size = 8420324, upload-time = "2025-12-10T07:08:17.561Z" },
+ { url = "https://files.pythonhosted.org/packages/46/1e/05962ea1cebc1cf3876667ecb14c283ef755bf409993c5946ade3b77e303/scikit_learn-1.8.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72358cce49465d140cc4e7792015bb1f0296a9742d5622c67e31399b75468b9e", size = 8680651, upload-time = "2025-12-10T07:08:19.952Z" },
+ { url = "https://files.pythonhosted.org/packages/fe/56/a85473cd75f200c9759e3a5f0bcab2d116c92a8a02ee08ccd73b870f8bb4/scikit_learn-1.8.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:80832434a6cc114f5219211eec13dcbc16c2bac0e31ef64c6d346cde3cf054cb", size = 8925045, upload-time = "2025-12-10T07:08:22.11Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/b7/64d8cfa896c64435ae57f4917a548d7ac7a44762ff9802f75a79b77cb633/scikit_learn-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ee787491dbfe082d9c3013f01f5991658b0f38aa8177e4cd4bf434c58f551702", size = 8507994, upload-time = "2025-12-10T07:08:23.943Z" },
+ { url = "https://files.pythonhosted.org/packages/5e/37/e192ea709551799379958b4c4771ec507347027bb7c942662c7fbeba31cb/scikit_learn-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf97c10a3f5a7543f9b88cbf488d33d175e9146115a451ae34568597ba33dcde", size = 7869518, upload-time = "2025-12-10T07:08:25.71Z" },
+ { url = "https://files.pythonhosted.org/packages/24/05/1af2c186174cc92dcab2233f327336058c077d38f6fe2aceb08e6ab4d509/scikit_learn-1.8.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:c22a2da7a198c28dd1a6e1136f19c830beab7fdca5b3e5c8bba8394f8a5c45b3", size = 8528667, upload-time = "2025-12-10T07:08:27.541Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/25/01c0af38fe969473fb292bba9dc2b8f9b451f3112ff242c647fee3d0dfe7/scikit_learn-1.8.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:6b595b07a03069a2b1740dc08c2299993850ea81cce4fe19b2421e0c970de6b7", size = 8066524, upload-time = "2025-12-10T07:08:29.822Z" },
+ { url = "https://files.pythonhosted.org/packages/be/ce/a0623350aa0b68647333940ee46fe45086c6060ec604874e38e9ab7d8e6c/scikit_learn-1.8.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:29ffc74089f3d5e87dfca4c2c8450f88bdc61b0fc6ed5d267f3988f19a1309f6", size = 8657133, upload-time = "2025-12-10T07:08:31.865Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/cb/861b41341d6f1245e6ca80b1c1a8c4dfce43255b03df034429089ca2a2c5/scikit_learn-1.8.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fb65db5d7531bccf3a4f6bec3462223bea71384e2cda41da0f10b7c292b9e7c4", size = 8923223, upload-time = "2025-12-10T07:08:34.166Z" },
+ { url = "https://files.pythonhosted.org/packages/76/18/a8def8f91b18cd1ba6e05dbe02540168cb24d47e8dcf69e8d00b7da42a08/scikit_learn-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:56079a99c20d230e873ea40753102102734c5953366972a71d5cb39a32bc40c6", size = 8096518, upload-time = "2025-12-10T07:08:36.339Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/77/482076a678458307f0deb44e29891d6022617b2a64c840c725495bee343f/scikit_learn-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:3bad7565bc9cf37ce19a7c0d107742b320c1285df7aab1a6e2d28780df167242", size = 7754546, upload-time = "2025-12-10T07:08:38.128Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/d1/ef294ca754826daa043b2a104e59960abfab4cf653891037d19dd5b6f3cf/scikit_learn-1.8.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:4511be56637e46c25721e83d1a9cea9614e7badc7040c4d573d75fbe257d6fd7", size = 8848305, upload-time = "2025-12-10T07:08:41.013Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/e2/b1f8b05138ee813b8e1a4149f2f0d289547e60851fd1bb268886915adbda/scikit_learn-1.8.0-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:a69525355a641bf8ef136a7fa447672fb54fe8d60cab5538d9eb7c6438543fb9", size = 8432257, upload-time = "2025-12-10T07:08:42.873Z" },
+ { url = "https://files.pythonhosted.org/packages/26/11/c32b2138a85dcb0c99f6afd13a70a951bfdff8a6ab42d8160522542fb647/scikit_learn-1.8.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c2656924ec73e5939c76ac4c8b026fc203b83d8900362eb2599d8aee80e4880f", size = 8678673, upload-time = "2025-12-10T07:08:45.362Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/57/51f2384575bdec454f4fe4e7a919d696c9ebce914590abf3e52d47607ab8/scikit_learn-1.8.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15fc3b5d19cc2be65404786857f2e13c70c83dd4782676dd6814e3b89dc8f5b9", size = 8922467, upload-time = "2025-12-10T07:08:47.408Z" },
+ { url = "https://files.pythonhosted.org/packages/35/4d/748c9e2872637a57981a04adc038dacaa16ba8ca887b23e34953f0b3f742/scikit_learn-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:00d6f1d66fbcf4eba6e356e1420d33cc06c70a45bb1363cd6f6a8e4ebbbdece2", size = 8774395, upload-time = "2025-12-10T07:08:49.337Z" },
+ { url = "https://files.pythonhosted.org/packages/60/22/d7b2ebe4704a5e50790ba089d5c2ae308ab6bb852719e6c3bd4f04c3a363/scikit_learn-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:f28dd15c6bb0b66ba09728cf09fd8736c304be29409bd8445a080c1280619e8c", size = 8002647, upload-time = "2025-12-10T07:08:51.601Z" },
+]
+
+[[package]]
+name = "scipy"
+version = "1.17.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "numpy" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/7a/97/5a3609c4f8d58b039179648e62dd220f89864f56f7357f5d4f45c29eb2cc/scipy-1.17.1.tar.gz", hash = "sha256:95d8e012d8cb8816c226aef832200b1d45109ed4464303e997c5b13122b297c0", size = 30573822, upload-time = "2026-02-23T00:26:24.851Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/35/48/b992b488d6f299dbe3f11a20b24d3dda3d46f1a635ede1c46b5b17a7b163/scipy-1.17.1-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:35c3a56d2ef83efc372eaec584314bd0ef2e2f0d2adb21c55e6ad5b344c0dcb8", size = 31610954, upload-time = "2026-02-23T00:17:49.855Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/02/cf107b01494c19dc100f1d0b7ac3cc08666e96ba2d64db7626066cee895e/scipy-1.17.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:fcb310ddb270a06114bb64bbe53c94926b943f5b7f0842194d585c65eb4edd76", size = 28172662, upload-time = "2026-02-23T00:18:01.64Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/a9/599c28631bad314d219cf9ffd40e985b24d603fc8a2f4ccc5ae8419a535b/scipy-1.17.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:cc90d2e9c7e5c7f1a482c9875007c095c3194b1cfedca3c2f3291cdc2bc7c086", size = 20344366, upload-time = "2026-02-23T00:18:12.015Z" },
+ { url = "https://files.pythonhosted.org/packages/35/f5/906eda513271c8deb5af284e5ef0206d17a96239af79f9fa0aebfe0e36b4/scipy-1.17.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:c80be5ede8f3f8eded4eff73cc99a25c388ce98e555b17d31da05287015ffa5b", size = 22704017, upload-time = "2026-02-23T00:18:21.502Z" },
+ { url = "https://files.pythonhosted.org/packages/da/34/16f10e3042d2f1d6b66e0428308ab52224b6a23049cb2f5c1756f713815f/scipy-1.17.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e19ebea31758fac5893a2ac360fedd00116cbb7628e650842a6691ba7ca28a21", size = 32927842, upload-time = "2026-02-23T00:18:35.367Z" },
+ { url = "https://files.pythonhosted.org/packages/01/8e/1e35281b8ab6d5d72ebe9911edcdffa3f36b04ed9d51dec6dd140396e220/scipy-1.17.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:02ae3b274fde71c5e92ac4d54bc06c42d80e399fec704383dcd99b301df37458", size = 35235890, upload-time = "2026-02-23T00:18:49.188Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/5c/9d7f4c88bea6e0d5a4f1bc0506a53a00e9fcb198de372bfe4d3652cef482/scipy-1.17.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8a604bae87c6195d8b1045eddece0514d041604b14f2727bbc2b3020172045eb", size = 35003557, upload-time = "2026-02-23T00:18:54.74Z" },
+ { url = "https://files.pythonhosted.org/packages/65/94/7698add8f276dbab7a9de9fb6b0e02fc13ee61d51c7c3f85ac28b65e1239/scipy-1.17.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f590cd684941912d10becc07325a3eeb77886fe981415660d9265c4c418d0bea", size = 37625856, upload-time = "2026-02-23T00:19:00.307Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/84/dc08d77fbf3d87d3ee27f6a0c6dcce1de5829a64f2eae85a0ecc1f0daa73/scipy-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:41b71f4a3a4cab9d366cd9065b288efc4d4f3c0b37a91a8e0947fb5bd7f31d87", size = 36549682, upload-time = "2026-02-23T00:19:07.67Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/98/fe9ae9ffb3b54b62559f52dedaebe204b408db8109a8c66fdd04869e6424/scipy-1.17.1-cp312-cp312-win_arm64.whl", hash = "sha256:f4115102802df98b2b0db3cce5cb9b92572633a1197c77b7553e5203f284a5b3", size = 24547340, upload-time = "2026-02-23T00:19:12.024Z" },
+ { url = "https://files.pythonhosted.org/packages/76/27/07ee1b57b65e92645f219b37148a7e7928b82e2b5dbeccecb4dff7c64f0b/scipy-1.17.1-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:5e3c5c011904115f88a39308379c17f91546f77c1667cea98739fe0fccea804c", size = 31590199, upload-time = "2026-02-23T00:19:17.192Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/ae/db19f8ab842e9b724bf5dbb7db29302a91f1e55bc4d04b1025d6d605a2c5/scipy-1.17.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:6fac755ca3d2c3edcb22f479fceaa241704111414831ddd3bc6056e18516892f", size = 28154001, upload-time = "2026-02-23T00:19:22.241Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/58/3ce96251560107b381cbd6e8413c483bbb1228a6b919fa8652b0d4090e7f/scipy-1.17.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:7ff200bf9d24f2e4d5dc6ee8c3ac64d739d3a89e2326ba68aaf6c4a2b838fd7d", size = 20325719, upload-time = "2026-02-23T00:19:26.329Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/83/15087d945e0e4d48ce2377498abf5ad171ae013232ae31d06f336e64c999/scipy-1.17.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:4b400bdc6f79fa02a4d86640310dde87a21fba0c979efff5248908c6f15fad1b", size = 22683595, upload-time = "2026-02-23T00:19:30.304Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/e0/e58fbde4a1a594c8be8114eb4aac1a55bcd6587047efc18a61eb1f5c0d30/scipy-1.17.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2b64ca7d4aee0102a97f3ba22124052b4bd2152522355073580bf4845e2550b6", size = 32896429, upload-time = "2026-02-23T00:19:35.536Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/5f/f17563f28ff03c7b6799c50d01d5d856a1d55f2676f537ca8d28c7f627cd/scipy-1.17.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:581b2264fc0aa555f3f435a5944da7504ea3a065d7029ad60e7c3d1ae09c5464", size = 35203952, upload-time = "2026-02-23T00:19:42.259Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/a5/9afd17de24f657fdfe4df9a3f1ea049b39aef7c06000c13db1530d81ccca/scipy-1.17.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:beeda3d4ae615106d7094f7e7cef6218392e4465cc95d25f900bebabfded0950", size = 34979063, upload-time = "2026-02-23T00:19:47.547Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/13/88b1d2384b424bf7c924f2038c1c409f8d88bb2a8d49d097861dd64a57b2/scipy-1.17.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6609bc224e9568f65064cfa72edc0f24ee6655b47575954ec6339534b2798369", size = 37598449, upload-time = "2026-02-23T00:19:53.238Z" },
+ { url = "https://files.pythonhosted.org/packages/35/e5/d6d0e51fc888f692a35134336866341c08655d92614f492c6860dc45bb2c/scipy-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:37425bc9175607b0268f493d79a292c39f9d001a357bebb6b88fdfaff13f6448", size = 36510943, upload-time = "2026-02-23T00:20:50.89Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/fd/3be73c564e2a01e690e19cc618811540ba5354c67c8680dce3281123fb79/scipy-1.17.1-cp313-cp313-win_arm64.whl", hash = "sha256:5cf36e801231b6a2059bf354720274b7558746f3b1a4efb43fcf557ccd484a87", size = 24545621, upload-time = "2026-02-23T00:20:55.871Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/6b/17787db8b8114933a66f9dcc479a8272e4b4da75fe03b0c282f7b0ade8cd/scipy-1.17.1-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:d59c30000a16d8edc7e64152e30220bfbd724c9bbb08368c054e24c651314f0a", size = 31936708, upload-time = "2026-02-23T00:19:58.694Z" },
+ { url = "https://files.pythonhosted.org/packages/38/2e/524405c2b6392765ab1e2b722a41d5da33dc5c7b7278184a8ad29b6cb206/scipy-1.17.1-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:010f4333c96c9bb1a4516269e33cb5917b08ef2166d5556ca2fd9f082a9e6ea0", size = 28570135, upload-time = "2026-02-23T00:20:03.934Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/c3/5bd7199f4ea8556c0c8e39f04ccb014ac37d1468e6cfa6a95c6b3562b76e/scipy-1.17.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:2ceb2d3e01c5f1d83c4189737a42d9cb2fc38a6eeed225e7515eef71ad301dce", size = 20741977, upload-time = "2026-02-23T00:20:07.935Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/b8/8ccd9b766ad14c78386599708eb745f6b44f08400a5fd0ade7cf89b6fc93/scipy-1.17.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:844e165636711ef41f80b4103ed234181646b98a53c8f05da12ca5ca289134f6", size = 23029601, upload-time = "2026-02-23T00:20:12.161Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/a0/3cb6f4d2fb3e17428ad2880333cac878909ad1a89f678527b5328b93c1d4/scipy-1.17.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:158dd96d2207e21c966063e1635b1063cd7787b627b6f07305315dd73d9c679e", size = 33019667, upload-time = "2026-02-23T00:20:17.208Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/c3/2d834a5ac7bf3a0c806ad1508efc02dda3c8c61472a56132d7894c312dea/scipy-1.17.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:74cbb80d93260fe2ffa334efa24cb8f2f0f622a9b9febf8b483c0b865bfb3475", size = 35264159, upload-time = "2026-02-23T00:20:23.087Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/77/d3ed4becfdbd217c52062fafe35a72388d1bd82c2d0ba5ca19d6fcc93e11/scipy-1.17.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:dbc12c9f3d185f5c737d801da555fb74b3dcfa1a50b66a1a93e09190f41fab50", size = 35102771, upload-time = "2026-02-23T00:20:28.636Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/12/d19da97efde68ca1ee5538bb261d5d2c062f0c055575128f11a2730e3ac1/scipy-1.17.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:94055a11dfebe37c656e70317e1996dc197e1a15bbcc351bcdd4610e128fe1ca", size = 37665910, upload-time = "2026-02-23T00:20:34.743Z" },
+ { url = "https://files.pythonhosted.org/packages/06/1c/1172a88d507a4baaf72c5a09bb6c018fe2ae0ab622e5830b703a46cc9e44/scipy-1.17.1-cp313-cp313t-win_amd64.whl", hash = "sha256:e30bdeaa5deed6bc27b4cc490823cd0347d7dae09119b8803ae576ea0ce52e4c", size = 36562980, upload-time = "2026-02-23T00:20:40.575Z" },
+ { url = "https://files.pythonhosted.org/packages/70/b0/eb757336e5a76dfa7911f63252e3b7d1de00935d7705cf772db5b45ec238/scipy-1.17.1-cp313-cp313t-win_arm64.whl", hash = "sha256:a720477885a9d2411f94a93d16f9d89bad0f28ca23c3f8daa521e2dcc3f44d49", size = 24856543, upload-time = "2026-02-23T00:20:45.313Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/83/333afb452af6f0fd70414dc04f898647ee1423979ce02efa75c3b0f2c28e/scipy-1.17.1-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:a48a72c77a310327f6a3a920092fa2b8fd03d7deaa60f093038f22d98e096717", size = 31584510, upload-time = "2026-02-23T00:21:01.015Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/a6/d05a85fd51daeb2e4ea71d102f15b34fedca8e931af02594193ae4fd25f7/scipy-1.17.1-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:45abad819184f07240d8a696117a7aacd39787af9e0b719d00285549ed19a1e9", size = 28170131, upload-time = "2026-02-23T00:21:05.888Z" },
+ { url = "https://files.pythonhosted.org/packages/db/7b/8624a203326675d7746a254083a187398090a179335b2e4a20e2ddc46e83/scipy-1.17.1-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:3fd1fcdab3ea951b610dc4cef356d416d5802991e7e32b5254828d342f7b7e0b", size = 20342032, upload-time = "2026-02-23T00:21:09.904Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/35/2c342897c00775d688d8ff3987aced3426858fd89d5a0e26e020b660b301/scipy-1.17.1-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:7bdf2da170b67fdf10bca777614b1c7d96ae3ca5794fd9587dce41eb2966e866", size = 22678766, upload-time = "2026-02-23T00:21:14.313Z" },
+ { url = "https://files.pythonhosted.org/packages/ef/f2/7cdb8eb308a1a6ae1e19f945913c82c23c0c442a462a46480ce487fdc0ac/scipy-1.17.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:adb2642e060a6549c343603a3851ba76ef0b74cc8c079a9a58121c7ec9fe2350", size = 32957007, upload-time = "2026-02-23T00:21:19.663Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/2e/7eea398450457ecb54e18e9d10110993fa65561c4f3add5e8eccd2b9cd41/scipy-1.17.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eee2cfda04c00a857206a4330f0c5e3e56535494e30ca445eb19ec624ae75118", size = 35221333, upload-time = "2026-02-23T00:21:25.278Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/77/5b8509d03b77f093a0d52e606d3c4f79e8b06d1d38c441dacb1e26cacf46/scipy-1.17.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d2650c1fb97e184d12d8ba010493ee7b322864f7d3d00d3f9bb97d9c21de4068", size = 35042066, upload-time = "2026-02-23T00:21:31.358Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/df/18f80fb99df40b4070328d5ae5c596f2f00fffb50167e31439e932f29e7d/scipy-1.17.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:08b900519463543aa604a06bec02461558a6e1cef8fdbb8098f77a48a83c8118", size = 37612763, upload-time = "2026-02-23T00:21:37.247Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/39/f0e8ea762a764a9dc52aa7dabcfad51a354819de1f0d4652b6a1122424d6/scipy-1.17.1-cp314-cp314-win_amd64.whl", hash = "sha256:3877ac408e14da24a6196de0ddcace62092bfc12a83823e92e49e40747e52c19", size = 37290984, upload-time = "2026-02-23T00:22:35.023Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/56/fe201e3b0f93d1a8bcf75d3379affd228a63d7e2d80ab45467a74b494947/scipy-1.17.1-cp314-cp314-win_arm64.whl", hash = "sha256:f8885db0bc2bffa59d5c1b72fad7a6a92d3e80e7257f967dd81abb553a90d293", size = 25192877, upload-time = "2026-02-23T00:22:39.798Z" },
+ { url = "https://files.pythonhosted.org/packages/96/ad/f8c414e121f82e02d76f310f16db9899c4fcde36710329502a6b2a3c0392/scipy-1.17.1-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:1cc682cea2ae55524432f3cdff9e9a3be743d52a7443d0cba9017c23c87ae2f6", size = 31949750, upload-time = "2026-02-23T00:21:42.289Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/b0/c741e8865d61b67c81e255f4f0a832846c064e426636cd7de84e74d209be/scipy-1.17.1-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:2040ad4d1795a0ae89bfc7e8429677f365d45aa9fd5e4587cf1ea737f927b4a1", size = 28585858, upload-time = "2026-02-23T00:21:47.706Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/1b/3985219c6177866628fa7c2595bfd23f193ceebbe472c98a08824b9466ff/scipy-1.17.1-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:131f5aaea57602008f9822e2115029b55d4b5f7c070287699fe45c661d051e39", size = 20757723, upload-time = "2026-02-23T00:21:52.039Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/19/2a04aa25050d656d6f7b9e7b685cc83d6957fb101665bfd9369ca6534563/scipy-1.17.1-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:9cdc1a2fcfd5c52cfb3045feb399f7b3ce822abdde3a193a6b9a60b3cb5854ca", size = 23043098, upload-time = "2026-02-23T00:21:56.185Z" },
+ { url = "https://files.pythonhosted.org/packages/86/f1/3383beb9b5d0dbddd030335bf8a8b32d4317185efe495374f134d8be6cce/scipy-1.17.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e3dcd57ab780c741fde8dc68619de988b966db759a3c3152e8e9142c26295ad", size = 33030397, upload-time = "2026-02-23T00:22:01.404Z" },
+ { url = "https://files.pythonhosted.org/packages/41/68/8f21e8a65a5a03f25a79165ec9d2b28c00e66dc80546cf5eb803aeeff35b/scipy-1.17.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a9956e4d4f4a301ebf6cde39850333a6b6110799d470dbbb1e25326ac447f52a", size = 35281163, upload-time = "2026-02-23T00:22:07.024Z" },
+ { url = "https://files.pythonhosted.org/packages/84/8d/c8a5e19479554007a5632ed7529e665c315ae7492b4f946b0deb39870e39/scipy-1.17.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:a4328d245944d09fd639771de275701ccadf5f781ba0ff092ad141e017eccda4", size = 35116291, upload-time = "2026-02-23T00:22:12.585Z" },
+ { url = "https://files.pythonhosted.org/packages/52/52/e57eceff0e342a1f50e274264ed47497b59e6a4e3118808ee58ddda7b74a/scipy-1.17.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a77cbd07b940d326d39a1d1b37817e2ee4d79cb30e7338f3d0cddffae70fcaa2", size = 37682317, upload-time = "2026-02-23T00:22:18.513Z" },
+ { url = "https://files.pythonhosted.org/packages/11/2f/b29eafe4a3fbc3d6de9662b36e028d5f039e72d345e05c250e121a230dd4/scipy-1.17.1-cp314-cp314t-win_amd64.whl", hash = "sha256:eb092099205ef62cd1782b006658db09e2fed75bffcae7cc0d44052d8aa0f484", size = 37345327, upload-time = "2026-02-23T00:22:24.442Z" },
+ { url = "https://files.pythonhosted.org/packages/07/39/338d9219c4e87f3e708f18857ecd24d22a0c3094752393319553096b98af/scipy-1.17.1-cp314-cp314t-win_arm64.whl", hash = "sha256:200e1050faffacc162be6a486a984a0497866ec54149a01270adc8a59b7c7d21", size = 25489165, upload-time = "2026-02-23T00:22:29.563Z" },
+]
+
+[[package]]
+name = "semantic-version"
+version = "2.10.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/7d/31/f2289ce78b9b473d582568c234e104d2a342fd658cc288a7553d83bb8595/semantic_version-2.10.0.tar.gz", hash = "sha256:bdabb6d336998cbb378d4b9db3a4b56a1e3235701dc05ea2690d9a997ed5041c", size = 52289, upload-time = "2022-05-26T13:35:23.454Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/6a/23/8146aad7d88f4fcb3a6218f41a60f6c2d4e3a72de72da1825dc7c8f7877c/semantic_version-2.10.0-py2.py3-none-any.whl", hash = "sha256:de78a3b8e0feda74cabc54aab2da702113e33ac9d9eb9d2389bcf1f58b7d9177", size = 15552, upload-time = "2022-05-26T13:35:21.206Z" },
+]
+
+[[package]]
+name = "setuptools"
+version = "82.0.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/4f/db/cfac1baf10650ab4d1c111714410d2fbb77ac5a616db26775db562c8fab2/setuptools-82.0.1.tar.gz", hash = "sha256:7d872682c5d01cfde07da7bccc7b65469d3dca203318515ada1de5eda35efbf9", size = 1152316, upload-time = "2026-03-09T12:47:17.221Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9d/76/f789f7a86709c6b087c5a2f52f911838cad707cc613162401badc665acfe/setuptools-82.0.1-py3-none-any.whl", hash = "sha256:a59e362652f08dcd477c78bb6e7bd9d80a7995bc73ce773050228a348ce2e5bb", size = 1006223, upload-time = "2026-03-09T12:47:15.026Z" },
+]
+
+[[package]]
+name = "shellingham"
+version = "1.5.4"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" },
+]
+
+[[package]]
+name = "six"
+version = "1.17.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
+]
+
+[[package]]
+name = "smart-open"
+version = "7.5.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "wrapt" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/e8/be/a66598b305763861a9ab15ff0f2fbc44e47b1ce7a776797337a4eef37c66/smart_open-7.5.1.tar.gz", hash = "sha256:3f08e16827c4733699e6b2cc40328a3568f900cb12ad9a3ad233ba6c872d9fe7", size = 54034, upload-time = "2026-02-23T11:01:28.979Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5e/ea/dcdecd68acebb49d3fd560473a43499b1635076f7f1ae8641c060fe7ce74/smart_open-7.5.1-py3-none-any.whl", hash = "sha256:3e07cbbd9c8a908bcb8e25d48becf1a5cbb4886fa975e9f34c672ed171df2318", size = 64108, upload-time = "2026-02-23T11:01:27.429Z" },
+]
+
+[[package]]
+name = "starlette"
+version = "0.52.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "anyio" },
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/c4/68/79977123bb7be889ad680d79a40f339082c1978b5cfcf62c2d8d196873ac/starlette-0.52.1.tar.gz", hash = "sha256:834edd1b0a23167694292e94f597773bc3f89f362be6effee198165a35d62933", size = 2653702, upload-time = "2026-01-18T13:34:11.062Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl", hash = "sha256:0029d43eb3d273bc4f83a08720b4912ea4b071087a3b48db01b7c839f7954d74", size = 74272, upload-time = "2026-01-18T13:34:09.188Z" },
+]
+
+[[package]]
+name = "sympy"
+version = "1.14.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "mpmath" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921, upload-time = "2025-04-27T18:05:01.611Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" },
+]
+
+[[package]]
+name = "threadpoolctl"
+version = "3.6.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/b7/4d/08c89e34946fce2aec4fbb45c9016efd5f4d7f24af8e5d93296e935631d8/threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e", size = 21274, upload-time = "2025-03-13T13:49:23.031Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb", size = 18638, upload-time = "2025-03-13T13:49:21.846Z" },
+]
+
+[[package]]
+name = "tomlkit"
+version = "0.13.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/cc/18/0bbf3884e9eaa38819ebe46a7bd25dcd56b67434402b66a58c4b8e552575/tomlkit-0.13.3.tar.gz", hash = "sha256:430cf247ee57df2b94ee3fbe588e71d362a941ebb545dec29b53961d61add2a1", size = 185207, upload-time = "2025-06-05T07:13:44.947Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/bd/75/8539d011f6be8e29f339c42e633aae3cb73bffa95dd0f9adec09b9c58e85/tomlkit-0.13.3-py3-none-any.whl", hash = "sha256:c89c649d79ee40629a9fda55f8ace8c6a1b42deb912b2a8fd8d942ddadb606b0", size = 38901, upload-time = "2025-06-05T07:13:43.546Z" },
+]
+
+[[package]]
+name = "torch"
+version = "2.10.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "cuda-bindings", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "filelock" },
+ { name = "fsspec" },
+ { name = "jinja2" },
+ { name = "networkx" },
+ { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "nvidia-cufile-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "nvidia-cusparselt-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "nvidia-nvshmem-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "setuptools" },
+ { name = "sympy" },
+ { name = "triton", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "typing-extensions" },
+]
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d3/54/a2ba279afcca44bbd320d4e73675b282fcee3d81400ea1b53934efca6462/torch-2.10.0-2-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:13ec4add8c3faaed8d13e0574f5cd4a323c11655546f91fbe6afa77b57423574", size = 79498202, upload-time = "2026-02-10T21:44:52.603Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/23/2c9fe0c9c27f7f6cb865abcea8a4568f29f00acaeadfc6a37f6801f84cb4/torch-2.10.0-2-cp313-none-macosx_11_0_arm64.whl", hash = "sha256:e521c9f030a3774ed770a9c011751fb47c4d12029a3d6522116e48431f2ff89e", size = 79498254, upload-time = "2026-02-10T21:44:44.095Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/7a/abada41517ce0011775f0f4eacc79659bc9bc6c361e6bfe6f7052a6b9363/torch-2.10.0-3-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:98c01b8bb5e3240426dcde1446eed6f40c778091c8544767ef1168fc663a05a6", size = 915622781, upload-time = "2026-03-11T14:17:11.354Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/c6/4dfe238342ffdcec5aef1c96c457548762d33c40b45a1ab7033bb26d2ff2/torch-2.10.0-3-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:80b1b5bfe38eb0e9f5ff09f206dcac0a87aadd084230d4a36eea5ec5232c115b", size = 915627275, upload-time = "2026-03-11T14:16:11.325Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/f0/72bf18847f58f877a6a8acf60614b14935e2f156d942483af1ffc081aea0/torch-2.10.0-3-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:46b3574d93a2a8134b3f5475cfb98e2eb46771794c57015f6ad1fb795ec25e49", size = 915523474, upload-time = "2026-03-11T14:17:44.422Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/39/590742415c3030551944edc2ddc273ea1fdfe8ffb2780992e824f1ebee98/torch-2.10.0-3-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:b1d5e2aba4eb7f8e87fbe04f86442887f9167a35f092afe4c237dfcaaef6e328", size = 915632474, upload-time = "2026-03-11T14:15:13.666Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/8e/34949484f764dde5b222b7fe3fede43e4a6f0da9d7f8c370bb617d629ee2/torch-2.10.0-3-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:0228d20b06701c05a8f978357f657817a4a63984b0c90745def81c18aedfa591", size = 915523882, upload-time = "2026-03-11T14:14:46.311Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/af/758e242e9102e9988969b5e621d41f36b8f258bb4a099109b7a4b4b50ea4/torch-2.10.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:5fd4117d89ffd47e3dcc71e71a22efac24828ad781c7e46aaaf56bf7f2796acf", size = 145996088, upload-time = "2026-01-21T16:24:44.171Z" },
+ { url = "https://files.pythonhosted.org/packages/23/8e/3c74db5e53bff7ed9e34c8123e6a8bfef718b2450c35eefab85bb4a7e270/torch-2.10.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:787124e7db3b379d4f1ed54dd12ae7c741c16a4d29b49c0226a89bea50923ffb", size = 915711952, upload-time = "2026-01-21T16:23:53.503Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/01/624c4324ca01f66ae4c7cd1b74eb16fb52596dce66dbe51eff95ef9e7a4c/torch-2.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:2c66c61f44c5f903046cc696d088e21062644cbe541c7f1c4eaae88b2ad23547", size = 113757972, upload-time = "2026-01-21T16:24:39.516Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/5c/dee910b87c4d5c0fcb41b50839ae04df87c1cfc663cf1b5fca7ea565eeaa/torch-2.10.0-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:6d3707a61863d1c4d6ebba7be4ca320f42b869ee657e9b2c21c736bf17000294", size = 79498198, upload-time = "2026-01-21T16:24:34.704Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/6f/f2e91e34e3fcba2e3fc8d8f74e7d6c22e74e480bbd1db7bc8900fdf3e95c/torch-2.10.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:5c4d217b14741e40776dd7074d9006fd28b8a97ef5654db959d8635b2fe5f29b", size = 146004247, upload-time = "2026-01-21T16:24:29.335Z" },
+ { url = "https://files.pythonhosted.org/packages/98/fb/5160261aeb5e1ee12ee95fe599d0541f7c976c3701d607d8fc29e623229f/torch-2.10.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:6b71486353fce0f9714ca0c9ef1c850a2ae766b409808acd58e9678a3edb7738", size = 915716445, upload-time = "2026-01-21T16:22:45.353Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/16/502fb1b41e6d868e8deb5b0e3ae926bbb36dab8ceb0d1b769b266ad7b0c3/torch-2.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:c2ee399c644dc92ef7bc0d4f7e74b5360c37cdbe7c5ba11318dda49ffac2bc57", size = 113757050, upload-time = "2026-01-21T16:24:19.204Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/0b/39929b148f4824bc3ad6f9f72a29d4ad865bcf7ebfc2fa67584773e083d2/torch-2.10.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:3202429f58309b9fa96a614885eace4b7995729f44beb54d3e4a47773649d382", size = 79851305, upload-time = "2026-01-21T16:24:09.209Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/14/21fbce63bc452381ba5f74a2c0a959fdf5ad5803ccc0c654e752e0dbe91a/torch-2.10.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:aae1b29cd68e50a9397f5ee897b9c24742e9e306f88a807a27d617f07adb3bd8", size = 146005472, upload-time = "2026-01-21T16:22:29.022Z" },
+ { url = "https://files.pythonhosted.org/packages/54/fd/b207d1c525cb570ef47f3e9f836b154685011fce11a2f444ba8a4084d042/torch-2.10.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:6021db85958db2f07ec94e1bc77212721ba4920c12a18dc552d2ae36a3eb163f", size = 915612644, upload-time = "2026-01-21T16:21:47.019Z" },
+ { url = "https://files.pythonhosted.org/packages/36/53/0197f868c75f1050b199fe58f9bf3bf3aecac9b4e85cc9c964383d745403/torch-2.10.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff43db38af76fda183156153983c9a096fc4c78d0cd1e07b14a2314c7f01c2c8", size = 113997015, upload-time = "2026-01-21T16:23:00.767Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/13/e76b4d9c160e89fff48bf16b449ea324bda84745d2ab30294c37c2434c0d/torch-2.10.0-cp313-none-macosx_11_0_arm64.whl", hash = "sha256:cdf2a523d699b70d613243211ecaac14fe9c5df8a0b0a9c02add60fb2a413e0f", size = 79498248, upload-time = "2026-01-21T16:23:09.315Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/93/716b5ac0155f1be70ed81bacc21269c3ece8dba0c249b9994094110bfc51/torch-2.10.0-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:bf0d9ff448b0218e0433aeb198805192346c4fd659c852370d5cc245f602a06a", size = 79464992, upload-time = "2026-01-21T16:23:05.162Z" },
+ { url = "https://files.pythonhosted.org/packages/69/2b/51e663ff190c9d16d4a8271203b71bc73a16aa7619b9f271a69b9d4a936b/torch-2.10.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:233aed0659a2503b831d8a67e9da66a62c996204c0bba4f4c442ccc0c68a3f60", size = 146018567, upload-time = "2026-01-21T16:22:23.393Z" },
+ { url = "https://files.pythonhosted.org/packages/5e/cd/4b95ef7f293b927c283db0b136c42be91c8ec6845c44de0238c8c23bdc80/torch-2.10.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:682497e16bdfa6efeec8cde66531bc8d1fbbbb4d8788ec6173c089ed3cc2bfe5", size = 915721646, upload-time = "2026-01-21T16:21:16.983Z" },
+ { url = "https://files.pythonhosted.org/packages/56/97/078a007208f8056d88ae43198833469e61a0a355abc0b070edd2c085eb9a/torch-2.10.0-cp314-cp314-win_amd64.whl", hash = "sha256:6528f13d2a8593a1a412ea07a99812495bec07e9224c28b2a25c0a30c7da025c", size = 113752373, upload-time = "2026-01-21T16:22:13.471Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/94/71994e7d0d5238393df9732fdab607e37e2b56d26a746cb59fdb415f8966/torch-2.10.0-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:f5ab4ba32383061be0fb74bda772d470140a12c1c3b58a0cfbf3dae94d164c28", size = 79850324, upload-time = "2026-01-21T16:22:09.494Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/65/1a05346b418ea8ccd10360eef4b3e0ce688fba544e76edec26913a8d0ee0/torch-2.10.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:716b01a176c2a5659c98f6b01bf868244abdd896526f1c692712ab36dbaf9b63", size = 146006482, upload-time = "2026-01-21T16:22:18.42Z" },
+ { url = "https://files.pythonhosted.org/packages/1d/b9/5f6f9d9e859fc3235f60578fa64f52c9c6e9b4327f0fe0defb6de5c0de31/torch-2.10.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:d8f5912ba938233f86361e891789595ff35ca4b4e2ac8fe3670895e5976731d6", size = 915613050, upload-time = "2026-01-21T16:20:49.035Z" },
+ { url = "https://files.pythonhosted.org/packages/66/4d/35352043ee0eaffdeff154fad67cd4a31dbed7ff8e3be1cc4549717d6d51/torch-2.10.0-cp314-cp314t-win_amd64.whl", hash = "sha256:71283a373f0ee2c89e0f0d5f446039bdabe8dbc3c9ccf35f0f784908b0acd185", size = 113995816, upload-time = "2026-01-21T16:22:05.312Z" },
+]
+
+[[package]]
+name = "tqdm"
+version = "4.67.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/09/a9/6ba95a270c6f1fbcd8dac228323f2777d886cb206987444e4bce66338dd4/tqdm-4.67.3.tar.gz", hash = "sha256:7d825f03f89244ef73f1d4ce193cb1774a8179fd96f31d7e1dcde62092b960bb", size = 169598, upload-time = "2026-02-03T17:35:53.048Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl", hash = "sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf", size = 78374, upload-time = "2026-02-03T17:35:50.982Z" },
+]
+
+[[package]]
+name = "triton"
+version = "3.6.0"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ab/a8/cdf8b3e4c98132f965f88c2313a4b493266832ad47fb52f23d14d4f86bb5/triton-3.6.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:74caf5e34b66d9f3a429af689c1c7128daba1d8208df60e81106b115c00d6fca", size = 188266850, upload-time = "2026-01-20T16:00:43.041Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/0b/37d991d8c130ce81a8728ae3c25b6e60935838e9be1b58791f5997b24a54/triton-3.6.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:10c7f76c6e72d2ef08df639e3d0d30729112f47a56b0c81672edc05ee5116ac9", size = 188289450, upload-time = "2026-01-20T16:00:49.136Z" },
+ { url = "https://files.pythonhosted.org/packages/35/f8/9c66bfc55361ec6d0e4040a0337fb5924ceb23de4648b8a81ae9d33b2b38/triton-3.6.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d002e07d7180fd65e622134fbd980c9a3d4211fb85224b56a0a0efbd422ab72f", size = 188400296, upload-time = "2026-01-20T16:00:56.042Z" },
+ { url = "https://files.pythonhosted.org/packages/df/3d/9e7eee57b37c80cec63322c0231bb6da3cfe535a91d7a4d64896fcb89357/triton-3.6.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a17a5d5985f0ac494ed8a8e54568f092f7057ef60e1b0fa09d3fd1512064e803", size = 188273063, upload-time = "2026-01-20T16:01:07.278Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/56/6113c23ff46c00aae423333eb58b3e60bdfe9179d542781955a5e1514cb3/triton-3.6.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:46bd1c1af4b6704e554cad2eeb3b0a6513a980d470ccfa63189737340c7746a7", size = 188397994, upload-time = "2026-01-20T16:01:14.236Z" },
+]
+
+[[package]]
+name = "typer"
+version = "0.24.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "annotated-doc" },
+ { name = "click" },
+ { name = "rich" },
+ { name = "shellingham" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/f5/24/cb09efec5cc954f7f9b930bf8279447d24618bb6758d4f6adf2574c41780/typer-0.24.1.tar.gz", hash = "sha256:e39b4732d65fbdcde189ae76cf7cd48aeae72919dea1fdfc16593be016256b45", size = 118613, upload-time = "2026-02-21T16:54:40.609Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/4a/91/48db081e7a63bb37284f9fbcefda7c44c277b18b0e13fbc36ea2335b71e6/typer-0.24.1-py3-none-any.whl", hash = "sha256:112c1f0ce578bfb4cab9ffdabc68f031416ebcc216536611ba21f04e9aa84c9e", size = 56085, upload-time = "2026-02-21T16:54:41.616Z" },
+]
+
+[[package]]
+name = "typing-extensions"
+version = "4.15.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
+]
+
+[[package]]
+name = "typing-inspection"
+version = "0.4.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" },
+]
+
+[[package]]
+name = "tzdata"
+version = "2025.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772, upload-time = "2025-12-13T17:45:35.667Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload-time = "2025-12-13T17:45:33.889Z" },
+]
+
+[[package]]
+name = "urllib3"
+version = "2.6.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" },
+]
+
+[[package]]
+name = "uvicorn"
+version = "0.41.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "click" },
+ { name = "h11" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/32/ce/eeb58ae4ac36fe09e3842eb02e0eb676bf2c53ae062b98f1b2531673efdd/uvicorn-0.41.0.tar.gz", hash = "sha256:09d11cf7008da33113824ee5a1c6422d89fbc2ff476540d69a34c87fab8b571a", size = 82633, upload-time = "2026-02-16T23:07:24.1Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/83/e4/d04a086285c20886c0daad0e026f250869201013d18f81d9ff5eada73a88/uvicorn-0.41.0-py3-none-any.whl", hash = "sha256:29e35b1d2c36a04b9e180d4007ede3bcb32a85fbdfd6c6aeb3f26839de088187", size = 68783, upload-time = "2026-02-16T23:07:22.357Z" },
+]
+
+[package.optional-dependencies]
+standard = [
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+ { name = "httptools" },
+ { name = "python-dotenv" },
+ { name = "pyyaml" },
+ { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" },
+ { name = "watchfiles" },
+ { name = "websockets" },
+]
+
+[[package]]
+name = "uvloop"
+version = "0.22.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/06/f0/18d39dbd1971d6d62c4629cc7fa67f74821b0dc1f5a77af43719de7936a7/uvloop-0.22.1.tar.gz", hash = "sha256:6c84bae345b9147082b17371e3dd5d42775bddce91f885499017f4607fdaf39f", size = 2443250, upload-time = "2025-10-16T22:17:19.342Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3d/ff/7f72e8170be527b4977b033239a83a68d5c881cc4775fca255c677f7ac5d/uvloop-0.22.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:fe94b4564e865d968414598eea1a6de60adba0c040ba4ed05ac1300de402cd42", size = 1359936, upload-time = "2025-10-16T22:16:29.436Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/c6/e5d433f88fd54d81ef4be58b2b7b0cea13c442454a1db703a1eea0db1a59/uvloop-0.22.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:51eb9bd88391483410daad430813d982010f9c9c89512321f5b60e2cddbdddd6", size = 752769, upload-time = "2025-10-16T22:16:30.493Z" },
+ { url = "https://files.pythonhosted.org/packages/24/68/a6ac446820273e71aa762fa21cdcc09861edd3536ff47c5cd3b7afb10eeb/uvloop-0.22.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:700e674a166ca5778255e0e1dc4e9d79ab2acc57b9171b79e65feba7184b3370", size = 4317413, upload-time = "2025-10-16T22:16:31.644Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/6f/e62b4dfc7ad6518e7eff2516f680d02a0f6eb62c0c212e152ca708a0085e/uvloop-0.22.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b5b1ac819a3f946d3b2ee07f09149578ae76066d70b44df3fa990add49a82e4", size = 4426307, upload-time = "2025-10-16T22:16:32.917Z" },
+ { url = "https://files.pythonhosted.org/packages/90/60/97362554ac21e20e81bcef1150cb2a7e4ffdaf8ea1e5b2e8bf7a053caa18/uvloop-0.22.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e047cc068570bac9866237739607d1313b9253c3051ad84738cbb095be0537b2", size = 4131970, upload-time = "2025-10-16T22:16:34.015Z" },
+ { url = "https://files.pythonhosted.org/packages/99/39/6b3f7d234ba3964c428a6e40006340f53ba37993f46ed6e111c6e9141d18/uvloop-0.22.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:512fec6815e2dd45161054592441ef76c830eddaad55c8aa30952e6fe1ed07c0", size = 4296343, upload-time = "2025-10-16T22:16:35.149Z" },
+ { url = "https://files.pythonhosted.org/packages/89/8c/182a2a593195bfd39842ea68ebc084e20c850806117213f5a299dfc513d9/uvloop-0.22.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:561577354eb94200d75aca23fbde86ee11be36b00e52a4eaf8f50fb0c86b7705", size = 1358611, upload-time = "2025-10-16T22:16:36.833Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/14/e301ee96a6dc95224b6f1162cd3312f6d1217be3907b79173b06785f2fe7/uvloop-0.22.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cdf5192ab3e674ca26da2eada35b288d2fa49fdd0f357a19f0e7c4e7d5077c8", size = 751811, upload-time = "2025-10-16T22:16:38.275Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/02/654426ce265ac19e2980bfd9ea6590ca96a56f10c76e63801a2df01c0486/uvloop-0.22.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e2ea3d6190a2968f4a14a23019d3b16870dd2190cd69c8180f7c632d21de68d", size = 4288562, upload-time = "2025-10-16T22:16:39.375Z" },
+ { url = "https://files.pythonhosted.org/packages/15/c0/0be24758891ef825f2065cd5db8741aaddabe3e248ee6acc5e8a80f04005/uvloop-0.22.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0530a5fbad9c9e4ee3f2b33b148c6a64d47bbad8000ea63704fa8260f4cf728e", size = 4366890, upload-time = "2025-10-16T22:16:40.547Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/53/8369e5219a5855869bcee5f4d317f6da0e2c669aecf0ef7d371e3d084449/uvloop-0.22.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bc5ef13bbc10b5335792360623cc378d52d7e62c2de64660616478c32cd0598e", size = 4119472, upload-time = "2025-10-16T22:16:41.694Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/ba/d69adbe699b768f6b29a5eec7b47dd610bd17a69de51b251126a801369ea/uvloop-0.22.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1f38ec5e3f18c8a10ded09742f7fb8de0108796eb673f30ce7762ce1b8550cad", size = 4239051, upload-time = "2025-10-16T22:16:43.224Z" },
+ { url = "https://files.pythonhosted.org/packages/90/cd/b62bdeaa429758aee8de8b00ac0dd26593a9de93d302bff3d21439e9791d/uvloop-0.22.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3879b88423ec7e97cd4eba2a443aa26ed4e59b45e6b76aabf13fe2f27023a142", size = 1362067, upload-time = "2025-10-16T22:16:44.503Z" },
+ { url = "https://files.pythonhosted.org/packages/0d/f8/a132124dfda0777e489ca86732e85e69afcd1ff7686647000050ba670689/uvloop-0.22.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4baa86acedf1d62115c1dc6ad1e17134476688f08c6efd8a2ab076e815665c74", size = 752423, upload-time = "2025-10-16T22:16:45.968Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/94/94af78c156f88da4b3a733773ad5ba0b164393e357cc4bd0ab2e2677a7d6/uvloop-0.22.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:297c27d8003520596236bdb2335e6b3f649480bd09e00d1e3a99144b691d2a35", size = 4272437, upload-time = "2025-10-16T22:16:47.451Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/35/60249e9fd07b32c665192cec7af29e06c7cd96fa1d08b84f012a56a0b38e/uvloop-0.22.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c1955d5a1dd43198244d47664a5858082a3239766a839b2102a269aaff7a4e25", size = 4292101, upload-time = "2025-10-16T22:16:49.318Z" },
+ { url = "https://files.pythonhosted.org/packages/02/62/67d382dfcb25d0a98ce73c11ed1a6fba5037a1a1d533dcbb7cab033a2636/uvloop-0.22.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b31dc2fccbd42adc73bc4e7cdbae4fc5086cf378979e53ca5d0301838c5682c6", size = 4114158, upload-time = "2025-10-16T22:16:50.517Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/7a/f1171b4a882a5d13c8b7576f348acfe6074d72eaf52cccef752f748d4a9f/uvloop-0.22.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:93f617675b2d03af4e72a5333ef89450dfaa5321303ede6e67ba9c9d26878079", size = 4177360, upload-time = "2025-10-16T22:16:52.646Z" },
+ { url = "https://files.pythonhosted.org/packages/79/7b/b01414f31546caf0919da80ad57cbfe24c56b151d12af68cee1b04922ca8/uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:37554f70528f60cad66945b885eb01f1bb514f132d92b6eeed1c90fd54ed6289", size = 1454790, upload-time = "2025-10-16T22:16:54.355Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/31/0bb232318dd838cad3fa8fb0c68c8b40e1145b32025581975e18b11fab40/uvloop-0.22.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:b76324e2dc033a0b2f435f33eb88ff9913c156ef78e153fb210e03c13da746b3", size = 796783, upload-time = "2025-10-16T22:16:55.906Z" },
+ { url = "https://files.pythonhosted.org/packages/42/38/c9b09f3271a7a723a5de69f8e237ab8e7803183131bc57c890db0b6bb872/uvloop-0.22.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:badb4d8e58ee08dad957002027830d5c3b06aea446a6a3744483c2b3b745345c", size = 4647548, upload-time = "2025-10-16T22:16:57.008Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/37/945b4ca0ac27e3dc4952642d4c900edd030b3da6c9634875af6e13ae80e5/uvloop-0.22.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b91328c72635f6f9e0282e4a57da7470c7350ab1c9f48546c0f2866205349d21", size = 4467065, upload-time = "2025-10-16T22:16:58.206Z" },
+ { url = "https://files.pythonhosted.org/packages/97/cc/48d232f33d60e2e2e0b42f4e73455b146b76ebe216487e862700457fbf3c/uvloop-0.22.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:daf620c2995d193449393d6c62131b3fbd40a63bf7b307a1527856ace637fe88", size = 4328384, upload-time = "2025-10-16T22:16:59.36Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/16/c1fd27e9549f3c4baf1dc9c20c456cd2f822dbf8de9f463824b0c0357e06/uvloop-0.22.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6cde23eeda1a25c75b2e07d39970f3374105d5eafbaab2a4482be82f272d5a5e", size = 4296730, upload-time = "2025-10-16T22:17:00.744Z" },
+]
+
+[[package]]
+name = "virtualenv"
+version = "21.2.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "distlib" },
+ { name = "filelock" },
+ { name = "platformdirs" },
+ { name = "python-discovery" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/aa/92/58199fe10049f9703c2666e809c4f686c54ef0a68b0f6afccf518c0b1eb9/virtualenv-21.2.0.tar.gz", hash = "sha256:1720dc3a62ef5b443092e3f499228599045d7fea4c79199770499df8becf9098", size = 5840618, upload-time = "2026-03-09T17:24:38.013Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c6/59/7d02447a55b2e55755011a647479041bc92a82e143f96a8195cb33bd0a1c/virtualenv-21.2.0-py3-none-any.whl", hash = "sha256:1bd755b504931164a5a496d217c014d098426cddc79363ad66ac78125f9d908f", size = 5825084, upload-time = "2026-03-09T17:24:35.378Z" },
+]
+
+[[package]]
+name = "watchfiles"
+version = "1.1.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "anyio" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/c2/c9/8869df9b2a2d6c59d79220a4db37679e74f807c559ffe5265e08b227a210/watchfiles-1.1.1.tar.gz", hash = "sha256:a173cb5c16c4f40ab19cecf48a534c409f7ea983ab8fed0741304a1c0a31b3f2", size = 94440, upload-time = "2025-10-14T15:06:21.08Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/74/d5/f039e7e3c639d9b1d09b07ea412a6806d38123f0508e5f9b48a87b0a76cc/watchfiles-1.1.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:8c89f9f2f740a6b7dcc753140dd5e1ab9215966f7a3530d0c0705c83b401bd7d", size = 404745, upload-time = "2025-10-14T15:04:46.731Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/96/a881a13aa1349827490dab2d363c8039527060cfcc2c92cc6d13d1b1049e/watchfiles-1.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bd404be08018c37350f0d6e34676bd1e2889990117a2b90070b3007f172d0610", size = 391769, upload-time = "2025-10-14T15:04:48.003Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/5b/d3b460364aeb8da471c1989238ea0e56bec24b6042a68046adf3d9ddb01c/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8526e8f916bb5b9a0a777c8317c23ce65de259422bba5b31325a6fa6029d33af", size = 449374, upload-time = "2025-10-14T15:04:49.179Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/44/5769cb62d4ed055cb17417c0a109a92f007114a4e07f30812a73a4efdb11/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2edc3553362b1c38d9f06242416a5d8e9fe235c204a4072e988ce2e5bb1f69f6", size = 459485, upload-time = "2025-10-14T15:04:50.155Z" },
+ { url = "https://files.pythonhosted.org/packages/19/0c/286b6301ded2eccd4ffd0041a1b726afda999926cf720aab63adb68a1e36/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30f7da3fb3f2844259cba4720c3fc7138eb0f7b659c38f3bfa65084c7fc7abce", size = 488813, upload-time = "2025-10-14T15:04:51.059Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/2b/8530ed41112dd4a22f4dcfdb5ccf6a1baad1ff6eed8dc5a5f09e7e8c41c7/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8979280bdafff686ba5e4d8f97840f929a87ed9cdf133cbbd42f7766774d2aa", size = 594816, upload-time = "2025-10-14T15:04:52.031Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/d2/f5f9fb49489f184f18470d4f99f4e862a4b3e9ac2865688eb2099e3d837a/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dcc5c24523771db3a294c77d94771abcfcb82a0e0ee8efd910c37c59ec1b31bb", size = 475186, upload-time = "2025-10-14T15:04:53.064Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/68/5707da262a119fb06fbe214d82dd1fe4a6f4af32d2d14de368d0349eb52a/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1db5d7ae38ff20153d542460752ff397fcf5c96090c1230803713cf3147a6803", size = 456812, upload-time = "2025-10-14T15:04:55.174Z" },
+ { url = "https://files.pythonhosted.org/packages/66/ab/3cbb8756323e8f9b6f9acb9ef4ec26d42b2109bce830cc1f3468df20511d/watchfiles-1.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:28475ddbde92df1874b6c5c8aaeb24ad5be47a11f87cde5a28ef3835932e3e94", size = 630196, upload-time = "2025-10-14T15:04:56.22Z" },
+ { url = "https://files.pythonhosted.org/packages/78/46/7152ec29b8335f80167928944a94955015a345440f524d2dfe63fc2f437b/watchfiles-1.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:36193ed342f5b9842edd3532729a2ad55c4160ffcfa3700e0d54be496b70dd43", size = 622657, upload-time = "2025-10-14T15:04:57.521Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/bf/95895e78dd75efe9a7f31733607f384b42eb5feb54bd2eb6ed57cc2e94f4/watchfiles-1.1.1-cp312-cp312-win32.whl", hash = "sha256:859e43a1951717cc8de7f4c77674a6d389b106361585951d9e69572823f311d9", size = 272042, upload-time = "2025-10-14T15:04:59.046Z" },
+ { url = "https://files.pythonhosted.org/packages/87/0a/90eb755f568de2688cb220171c4191df932232c20946966c27a59c400850/watchfiles-1.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:91d4c9a823a8c987cce8fa2690923b069966dabb196dd8d137ea2cede885fde9", size = 288410, upload-time = "2025-10-14T15:05:00.081Z" },
+ { url = "https://files.pythonhosted.org/packages/36/76/f322701530586922fbd6723c4f91ace21364924822a8772c549483abed13/watchfiles-1.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:a625815d4a2bdca61953dbba5a39d60164451ef34c88d751f6c368c3ea73d404", size = 278209, upload-time = "2025-10-14T15:05:01.168Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/f4/f750b29225fe77139f7ae5de89d4949f5a99f934c65a1f1c0b248f26f747/watchfiles-1.1.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:130e4876309e8686a5e37dba7d5e9bc77e6ed908266996ca26572437a5271e18", size = 404321, upload-time = "2025-10-14T15:05:02.063Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/f9/f07a295cde762644aa4c4bb0f88921d2d141af45e735b965fb2e87858328/watchfiles-1.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5f3bde70f157f84ece3765b42b4a52c6ac1a50334903c6eaf765362f6ccca88a", size = 391783, upload-time = "2025-10-14T15:05:03.052Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/11/fc2502457e0bea39a5c958d86d2cb69e407a4d00b85735ca724bfa6e0d1a/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14e0b1fe858430fc0251737ef3824c54027bedb8c37c38114488b8e131cf8219", size = 449279, upload-time = "2025-10-14T15:05:04.004Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/1f/d66bc15ea0b728df3ed96a539c777acfcad0eb78555ad9efcaa1274688f0/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f27db948078f3823a6bb3b465180db8ebecf26dd5dae6f6180bd87383b6b4428", size = 459405, upload-time = "2025-10-14T15:05:04.942Z" },
+ { url = "https://files.pythonhosted.org/packages/be/90/9f4a65c0aec3ccf032703e6db02d89a157462fbb2cf20dd415128251cac0/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:059098c3a429f62fc98e8ec62b982230ef2c8df68c79e826e37b895bc359a9c0", size = 488976, upload-time = "2025-10-14T15:05:05.905Z" },
+ { url = "https://files.pythonhosted.org/packages/37/57/ee347af605d867f712be7029bb94c8c071732a4b44792e3176fa3c612d39/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfb5862016acc9b869bb57284e6cb35fdf8e22fe59f7548858e2f971d045f150", size = 595506, upload-time = "2025-10-14T15:05:06.906Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/78/cc5ab0b86c122047f75e8fc471c67a04dee395daf847d3e59381996c8707/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:319b27255aacd9923b8a276bb14d21a5f7ff82564c744235fc5eae58d95422ae", size = 474936, upload-time = "2025-10-14T15:05:07.906Z" },
+ { url = "https://files.pythonhosted.org/packages/62/da/def65b170a3815af7bd40a3e7010bf6ab53089ef1b75d05dd5385b87cf08/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c755367e51db90e75b19454b680903631d41f9e3607fbd941d296a020c2d752d", size = 456147, upload-time = "2025-10-14T15:05:09.138Z" },
+ { url = "https://files.pythonhosted.org/packages/57/99/da6573ba71166e82d288d4df0839128004c67d2778d3b566c138695f5c0b/watchfiles-1.1.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c22c776292a23bfc7237a98f791b9ad3144b02116ff10d820829ce62dff46d0b", size = 630007, upload-time = "2025-10-14T15:05:10.117Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/51/7439c4dd39511368849eb1e53279cd3454b4a4dbace80bab88feeb83c6b5/watchfiles-1.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:3a476189be23c3686bc2f4321dd501cb329c0a0469e77b7b534ee10129ae6374", size = 622280, upload-time = "2025-10-14T15:05:11.146Z" },
+ { url = "https://files.pythonhosted.org/packages/95/9c/8ed97d4bba5db6fdcdb2b298d3898f2dd5c20f6b73aee04eabe56c59677e/watchfiles-1.1.1-cp313-cp313-win32.whl", hash = "sha256:bf0a91bfb5574a2f7fc223cf95eeea79abfefa404bf1ea5e339c0c1560ae99a0", size = 272056, upload-time = "2025-10-14T15:05:12.156Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/f3/c14e28429f744a260d8ceae18bf58c1d5fa56b50d006a7a9f80e1882cb0d/watchfiles-1.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:52e06553899e11e8074503c8e716d574adeeb7e68913115c4b3653c53f9bae42", size = 288162, upload-time = "2025-10-14T15:05:13.208Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/61/fe0e56c40d5cd29523e398d31153218718c5786b5e636d9ae8ae79453d27/watchfiles-1.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:ac3cc5759570cd02662b15fbcd9d917f7ecd47efe0d6b40474eafd246f91ea18", size = 277909, upload-time = "2025-10-14T15:05:14.49Z" },
+ { url = "https://files.pythonhosted.org/packages/79/42/e0a7d749626f1e28c7108a99fb9bf524b501bbbeb9b261ceecde644d5a07/watchfiles-1.1.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:563b116874a9a7ce6f96f87cd0b94f7faf92d08d0021e837796f0a14318ef8da", size = 403389, upload-time = "2025-10-14T15:05:15.777Z" },
+ { url = "https://files.pythonhosted.org/packages/15/49/08732f90ce0fbbc13913f9f215c689cfc9ced345fb1bcd8829a50007cc8d/watchfiles-1.1.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3ad9fe1dae4ab4212d8c91e80b832425e24f421703b5a42ef2e4a1e215aff051", size = 389964, upload-time = "2025-10-14T15:05:16.85Z" },
+ { url = "https://files.pythonhosted.org/packages/27/0d/7c315d4bd5f2538910491a0393c56bf70d333d51bc5b34bee8e68e8cea19/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce70f96a46b894b36eba678f153f052967a0d06d5b5a19b336ab0dbbd029f73e", size = 448114, upload-time = "2025-10-14T15:05:17.876Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/24/9e096de47a4d11bc4df41e9d1e61776393eac4cb6eb11b3e23315b78b2cc/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cb467c999c2eff23a6417e58d75e5828716f42ed8289fe6b77a7e5a91036ca70", size = 460264, upload-time = "2025-10-14T15:05:18.962Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/0f/e8dea6375f1d3ba5fcb0b3583e2b493e77379834c74fd5a22d66d85d6540/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:836398932192dae4146c8f6f737d74baeac8b70ce14831a239bdb1ca882fc261", size = 487877, upload-time = "2025-10-14T15:05:20.094Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/5b/df24cfc6424a12deb41503b64d42fbea6b8cb357ec62ca84a5a3476f654a/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:743185e7372b7bc7c389e1badcc606931a827112fbbd37f14c537320fca08620", size = 595176, upload-time = "2025-10-14T15:05:21.134Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/b5/853b6757f7347de4e9b37e8cc3289283fb983cba1ab4d2d7144694871d9c/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:afaeff7696e0ad9f02cbb8f56365ff4686ab205fcf9c4c5b6fdfaaa16549dd04", size = 473577, upload-time = "2025-10-14T15:05:22.306Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/f7/0a4467be0a56e80447c8529c9fce5b38eab4f513cb3d9bf82e7392a5696b/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f7eb7da0eb23aa2ba036d4f616d46906013a68caf61b7fdbe42fc8b25132e77", size = 455425, upload-time = "2025-10-14T15:05:23.348Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/e0/82583485ea00137ddf69bc84a2db88bd92ab4a6e3c405e5fb878ead8d0e7/watchfiles-1.1.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:831a62658609f0e5c64178211c942ace999517f5770fe9436be4c2faeba0c0ef", size = 628826, upload-time = "2025-10-14T15:05:24.398Z" },
+ { url = "https://files.pythonhosted.org/packages/28/9a/a785356fccf9fae84c0cc90570f11702ae9571036fb25932f1242c82191c/watchfiles-1.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:f9a2ae5c91cecc9edd47e041a930490c31c3afb1f5e6d71de3dc671bfaca02bf", size = 622208, upload-time = "2025-10-14T15:05:25.45Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/f4/0872229324ef69b2c3edec35e84bd57a1289e7d3fe74588048ed8947a323/watchfiles-1.1.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:d1715143123baeeaeadec0528bb7441103979a1d5f6fd0e1f915383fea7ea6d5", size = 404315, upload-time = "2025-10-14T15:05:26.501Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/22/16d5331eaed1cb107b873f6ae1b69e9ced582fcf0c59a50cd84f403b1c32/watchfiles-1.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:39574d6370c4579d7f5d0ad940ce5b20db0e4117444e39b6d8f99db5676c52fd", size = 390869, upload-time = "2025-10-14T15:05:27.649Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/7e/5643bfff5acb6539b18483128fdc0ef2cccc94a5b8fbda130c823e8ed636/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7365b92c2e69ee952902e8f70f3ba6360d0d596d9299d55d7d386df84b6941fb", size = 449919, upload-time = "2025-10-14T15:05:28.701Z" },
+ { url = "https://files.pythonhosted.org/packages/51/2e/c410993ba5025a9f9357c376f48976ef0e1b1aefb73b97a5ae01a5972755/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bfff9740c69c0e4ed32416f013f3c45e2ae42ccedd1167ef2d805c000b6c71a5", size = 460845, upload-time = "2025-10-14T15:05:30.064Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/a4/2df3b404469122e8680f0fcd06079317e48db58a2da2950fb45020947734/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b27cf2eb1dda37b2089e3907d8ea92922b673c0c427886d4edc6b94d8dfe5db3", size = 489027, upload-time = "2025-10-14T15:05:31.064Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/84/4587ba5b1f267167ee715b7f66e6382cca6938e0a4b870adad93e44747e6/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:526e86aced14a65a5b0ec50827c745597c782ff46b571dbfe46192ab9e0b3c33", size = 595615, upload-time = "2025-10-14T15:05:32.074Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/0f/c6988c91d06e93cd0bb3d4a808bcf32375ca1904609835c3031799e3ecae/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04e78dd0b6352db95507fd8cb46f39d185cf8c74e4cf1e4fbad1d3df96faf510", size = 474836, upload-time = "2025-10-14T15:05:33.209Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/36/ded8aebea91919485b7bbabbd14f5f359326cb5ec218cd67074d1e426d74/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c85794a4cfa094714fb9c08d4a218375b2b95b8ed1666e8677c349906246c05", size = 455099, upload-time = "2025-10-14T15:05:34.189Z" },
+ { url = "https://files.pythonhosted.org/packages/98/e0/8c9bdba88af756a2fce230dd365fab2baf927ba42cd47521ee7498fd5211/watchfiles-1.1.1-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:74d5012b7630714b66be7b7b7a78855ef7ad58e8650c73afc4c076a1f480a8d6", size = 630626, upload-time = "2025-10-14T15:05:35.216Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/84/a95db05354bf2d19e438520d92a8ca475e578c647f78f53197f5a2f17aaf/watchfiles-1.1.1-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:8fbe85cb3201c7d380d3d0b90e63d520f15d6afe217165d7f98c9c649654db81", size = 622519, upload-time = "2025-10-14T15:05:36.259Z" },
+ { url = "https://files.pythonhosted.org/packages/1d/ce/d8acdc8de545de995c339be67711e474c77d643555a9bb74a9334252bd55/watchfiles-1.1.1-cp314-cp314-win32.whl", hash = "sha256:3fa0b59c92278b5a7800d3ee7733da9d096d4aabcfabb9a928918bd276ef9b9b", size = 272078, upload-time = "2025-10-14T15:05:37.63Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/c9/a74487f72d0451524be827e8edec251da0cc1fcf111646a511ae752e1a3d/watchfiles-1.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:c2047d0b6cea13b3316bdbafbfa0c4228ae593d995030fda39089d36e64fc03a", size = 287664, upload-time = "2025-10-14T15:05:38.95Z" },
+ { url = "https://files.pythonhosted.org/packages/df/b8/8ac000702cdd496cdce998c6f4ee0ca1f15977bba51bdf07d872ebdfc34c/watchfiles-1.1.1-cp314-cp314-win_arm64.whl", hash = "sha256:842178b126593addc05acf6fce960d28bc5fae7afbaa2c6c1b3a7b9460e5be02", size = 277154, upload-time = "2025-10-14T15:05:39.954Z" },
+ { url = "https://files.pythonhosted.org/packages/47/a8/e3af2184707c29f0f14b1963c0aace6529f9d1b8582d5b99f31bbf42f59e/watchfiles-1.1.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:88863fbbc1a7312972f1c511f202eb30866370ebb8493aef2812b9ff28156a21", size = 403820, upload-time = "2025-10-14T15:05:40.932Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/ec/e47e307c2f4bd75f9f9e8afbe3876679b18e1bcec449beca132a1c5ffb2d/watchfiles-1.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:55c7475190662e202c08c6c0f4d9e345a29367438cf8e8037f3155e10a88d5a5", size = 390510, upload-time = "2025-10-14T15:05:41.945Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/a0/ad235642118090f66e7b2f18fd5c42082418404a79205cdfca50b6309c13/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f53fa183d53a1d7a8852277c92b967ae99c2d4dcee2bfacff8868e6e30b15f7", size = 448408, upload-time = "2025-10-14T15:05:43.385Z" },
+ { url = "https://files.pythonhosted.org/packages/df/85/97fa10fd5ff3332ae17e7e40e20784e419e28521549780869f1413742e9d/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6aae418a8b323732fa89721d86f39ec8f092fc2af67f4217a2b07fd3e93c6101", size = 458968, upload-time = "2025-10-14T15:05:44.404Z" },
+ { url = "https://files.pythonhosted.org/packages/47/c2/9059c2e8966ea5ce678166617a7f75ecba6164375f3b288e50a40dc6d489/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f096076119da54a6080e8920cbdaac3dbee667eb91dcc5e5b78840b87415bd44", size = 488096, upload-time = "2025-10-14T15:05:45.398Z" },
+ { url = "https://files.pythonhosted.org/packages/94/44/d90a9ec8ac309bc26db808a13e7bfc0e4e78b6fc051078a554e132e80160/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00485f441d183717038ed2e887a7c868154f216877653121068107b227a2f64c", size = 596040, upload-time = "2025-10-14T15:05:46.502Z" },
+ { url = "https://files.pythonhosted.org/packages/95/68/4e3479b20ca305cfc561db3ed207a8a1c745ee32bf24f2026a129d0ddb6e/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a55f3e9e493158d7bfdb60a1165035f1cf7d320914e7b7ea83fe22c6023b58fc", size = 473847, upload-time = "2025-10-14T15:05:47.484Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/55/2af26693fd15165c4ff7857e38330e1b61ab8c37d15dc79118cdba115b7a/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c91ed27800188c2ae96d16e3149f199d62f86c7af5f5f4d2c61a3ed8cd3666c", size = 455072, upload-time = "2025-10-14T15:05:48.928Z" },
+ { url = "https://files.pythonhosted.org/packages/66/1d/d0d200b10c9311ec25d2273f8aad8c3ef7cc7ea11808022501811208a750/watchfiles-1.1.1-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:311ff15a0bae3714ffb603e6ba6dbfba4065ab60865d15a6ec544133bdb21099", size = 629104, upload-time = "2025-10-14T15:05:49.908Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/bd/fa9bb053192491b3867ba07d2343d9f2252e00811567d30ae8d0f78136fe/watchfiles-1.1.1-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:a916a2932da8f8ab582f242c065f5c81bed3462849ca79ee357dd9551b0e9b01", size = 622112, upload-time = "2025-10-14T15:05:50.941Z" },
+]
+
+[[package]]
+name = "websockets"
+version = "16.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/04/24/4b2031d72e840ce4c1ccb255f693b15c334757fc50023e4db9537080b8c4/websockets-16.0.tar.gz", hash = "sha256:5f6261a5e56e8d5c42a4497b364ea24d94d9563e8fbd44e78ac40879c60179b5", size = 179346, upload-time = "2026-01-10T09:23:47.181Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/84/7b/bac442e6b96c9d25092695578dda82403c77936104b5682307bd4deb1ad4/websockets-16.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:71c989cbf3254fbd5e84d3bff31e4da39c43f884e64f2551d14bb3c186230f00", size = 177365, upload-time = "2026-01-10T09:22:46.787Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/fe/136ccece61bd690d9c1f715baaeefd953bb2360134de73519d5df19d29ca/websockets-16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8b6e209ffee39ff1b6d0fa7bfef6de950c60dfb91b8fcead17da4ee539121a79", size = 175038, upload-time = "2026-01-10T09:22:47.999Z" },
+ { url = "https://files.pythonhosted.org/packages/40/1e/9771421ac2286eaab95b8575b0cb701ae3663abf8b5e1f64f1fd90d0a673/websockets-16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:86890e837d61574c92a97496d590968b23c2ef0aeb8a9bc9421d174cd378ae39", size = 175328, upload-time = "2026-01-10T09:22:49.809Z" },
+ { url = "https://files.pythonhosted.org/packages/18/29/71729b4671f21e1eaa5d6573031ab810ad2936c8175f03f97f3ff164c802/websockets-16.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9b5aca38b67492ef518a8ab76851862488a478602229112c4b0d58d63a7a4d5c", size = 184915, upload-time = "2026-01-10T09:22:51.071Z" },
+ { url = "https://files.pythonhosted.org/packages/97/bb/21c36b7dbbafc85d2d480cd65df02a1dc93bf76d97147605a8e27ff9409d/websockets-16.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e0334872c0a37b606418ac52f6ab9cfd17317ac26365f7f65e203e2d0d0d359f", size = 186152, upload-time = "2026-01-10T09:22:52.224Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/34/9bf8df0c0cf88fa7bfe36678dc7b02970c9a7d5e065a3099292db87b1be2/websockets-16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a0b31e0b424cc6b5a04b8838bbaec1688834b2383256688cf47eb97412531da1", size = 185583, upload-time = "2026-01-10T09:22:53.443Z" },
+ { url = "https://files.pythonhosted.org/packages/47/88/4dd516068e1a3d6ab3c7c183288404cd424a9a02d585efbac226cb61ff2d/websockets-16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:485c49116d0af10ac698623c513c1cc01c9446c058a4e61e3bf6c19dff7335a2", size = 184880, upload-time = "2026-01-10T09:22:55.033Z" },
+ { url = "https://files.pythonhosted.org/packages/91/d6/7d4553ad4bf1c0421e1ebd4b18de5d9098383b5caa1d937b63df8d04b565/websockets-16.0-cp312-cp312-win32.whl", hash = "sha256:eaded469f5e5b7294e2bdca0ab06becb6756ea86894a47806456089298813c89", size = 178261, upload-time = "2026-01-10T09:22:56.251Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/f0/f3a17365441ed1c27f850a80b2bc680a0fa9505d733fe152fdf5e98c1c0b/websockets-16.0-cp312-cp312-win_amd64.whl", hash = "sha256:5569417dc80977fc8c2d43a86f78e0a5a22fee17565d78621b6bb264a115d4ea", size = 178693, upload-time = "2026-01-10T09:22:57.478Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/9c/baa8456050d1c1b08dd0ec7346026668cbc6f145ab4e314d707bb845bf0d/websockets-16.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:878b336ac47938b474c8f982ac2f7266a540adc3fa4ad74ae96fea9823a02cc9", size = 177364, upload-time = "2026-01-10T09:22:59.333Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/0c/8811fc53e9bcff68fe7de2bcbe75116a8d959ac699a3200f4847a8925210/websockets-16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:52a0fec0e6c8d9a784c2c78276a48a2bdf099e4ccc2a4cad53b27718dbfd0230", size = 175039, upload-time = "2026-01-10T09:23:01.171Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/82/39a5f910cb99ec0b59e482971238c845af9220d3ab9fa76dd9162cda9d62/websockets-16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e6578ed5b6981005df1860a56e3617f14a6c307e6a71b4fff8c48fdc50f3ed2c", size = 175323, upload-time = "2026-01-10T09:23:02.341Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/28/0a25ee5342eb5d5f297d992a77e56892ecb65e7854c7898fb7d35e9b33bd/websockets-16.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:95724e638f0f9c350bb1c2b0a7ad0e83d9cc0c9259f3ea94e40d7b02a2179ae5", size = 184975, upload-time = "2026-01-10T09:23:03.756Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/66/27ea52741752f5107c2e41fda05e8395a682a1e11c4e592a809a90c6a506/websockets-16.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0204dc62a89dc9d50d682412c10b3542d748260d743500a85c13cd1ee4bde82", size = 186203, upload-time = "2026-01-10T09:23:05.01Z" },
+ { url = "https://files.pythonhosted.org/packages/37/e5/8e32857371406a757816a2b471939d51c463509be73fa538216ea52b792a/websockets-16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:52ac480f44d32970d66763115edea932f1c5b1312de36df06d6b219f6741eed8", size = 185653, upload-time = "2026-01-10T09:23:06.301Z" },
+ { url = "https://files.pythonhosted.org/packages/9b/67/f926bac29882894669368dc73f4da900fcdf47955d0a0185d60103df5737/websockets-16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6e5a82b677f8f6f59e8dfc34ec06ca6b5b48bc4fcda346acd093694cc2c24d8f", size = 184920, upload-time = "2026-01-10T09:23:07.492Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/a1/3d6ccdcd125b0a42a311bcd15a7f705d688f73b2a22d8cf1c0875d35d34a/websockets-16.0-cp313-cp313-win32.whl", hash = "sha256:abf050a199613f64c886ea10f38b47770a65154dc37181bfaff70c160f45315a", size = 178255, upload-time = "2026-01-10T09:23:09.245Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/ae/90366304d7c2ce80f9b826096a9e9048b4bb760e44d3b873bb272cba696b/websockets-16.0-cp313-cp313-win_amd64.whl", hash = "sha256:3425ac5cf448801335d6fdc7ae1eb22072055417a96cc6b31b3861f455fbc156", size = 178689, upload-time = "2026-01-10T09:23:10.483Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/1d/e88022630271f5bd349ed82417136281931e558d628dd52c4d8621b4a0b2/websockets-16.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8cc451a50f2aee53042ac52d2d053d08bf89bcb31ae799cb4487587661c038a0", size = 177406, upload-time = "2026-01-10T09:23:12.178Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/78/e63be1bf0724eeb4616efb1ae1c9044f7c3953b7957799abb5915bffd38e/websockets-16.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:daa3b6ff70a9241cf6c7fc9e949d41232d9d7d26fd3522b1ad2b4d62487e9904", size = 175085, upload-time = "2026-01-10T09:23:13.511Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/f4/d3c9220d818ee955ae390cf319a7c7a467beceb24f05ee7aaaa2414345ba/websockets-16.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:fd3cb4adb94a2a6e2b7c0d8d05cb94e6f1c81a0cf9dc2694fb65c7e8d94c42e4", size = 175328, upload-time = "2026-01-10T09:23:14.727Z" },
+ { url = "https://files.pythonhosted.org/packages/63/bc/d3e208028de777087e6fb2b122051a6ff7bbcca0d6df9d9c2bf1dd869ae9/websockets-16.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:781caf5e8eee67f663126490c2f96f40906594cb86b408a703630f95550a8c3e", size = 185044, upload-time = "2026-01-10T09:23:15.939Z" },
+ { url = "https://files.pythonhosted.org/packages/ad/6e/9a0927ac24bd33a0a9af834d89e0abc7cfd8e13bed17a86407a66773cc0e/websockets-16.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:caab51a72c51973ca21fa8a18bd8165e1a0183f1ac7066a182ff27107b71e1a4", size = 186279, upload-time = "2026-01-10T09:23:17.148Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/ca/bf1c68440d7a868180e11be653c85959502efd3a709323230314fda6e0b3/websockets-16.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:19c4dc84098e523fd63711e563077d39e90ec6702aff4b5d9e344a60cb3c0cb1", size = 185711, upload-time = "2026-01-10T09:23:18.372Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/f8/fdc34643a989561f217bb477cbc47a3a07212cbda91c0e4389c43c296ebf/websockets-16.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a5e18a238a2b2249c9a9235466b90e96ae4795672598a58772dd806edc7ac6d3", size = 184982, upload-time = "2026-01-10T09:23:19.652Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/d1/574fa27e233764dbac9c52730d63fcf2823b16f0856b3329fc6268d6ae4f/websockets-16.0-cp314-cp314-win32.whl", hash = "sha256:a069d734c4a043182729edd3e9f247c3b2a4035415a9172fd0f1b71658a320a8", size = 177915, upload-time = "2026-01-10T09:23:21.458Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/f1/ae6b937bf3126b5134ce1f482365fde31a357c784ac51852978768b5eff4/websockets-16.0-cp314-cp314-win_amd64.whl", hash = "sha256:c0ee0e63f23914732c6d7e0cce24915c48f3f1512ec1d079ed01fc629dab269d", size = 178381, upload-time = "2026-01-10T09:23:22.715Z" },
+ { url = "https://files.pythonhosted.org/packages/06/9b/f791d1db48403e1f0a27577a6beb37afae94254a8c6f08be4a23e4930bc0/websockets-16.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:a35539cacc3febb22b8f4d4a99cc79b104226a756aa7400adc722e83b0d03244", size = 177737, upload-time = "2026-01-10T09:23:24.523Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/40/53ad02341fa33b3ce489023f635367a4ac98b73570102ad2cdd770dacc9a/websockets-16.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:b784ca5de850f4ce93ec85d3269d24d4c82f22b7212023c974c401d4980ebc5e", size = 175268, upload-time = "2026-01-10T09:23:25.781Z" },
+ { url = "https://files.pythonhosted.org/packages/74/9b/6158d4e459b984f949dcbbb0c5d270154c7618e11c01029b9bbd1bb4c4f9/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:569d01a4e7fba956c5ae4fc988f0d4e187900f5497ce46339c996dbf24f17641", size = 175486, upload-time = "2026-01-10T09:23:27.033Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/2d/7583b30208b639c8090206f95073646c2c9ffd66f44df967981a64f849ad/websockets-16.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:50f23cdd8343b984957e4077839841146f67a3d31ab0d00e6b824e74c5b2f6e8", size = 185331, upload-time = "2026-01-10T09:23:28.259Z" },
+ { url = "https://files.pythonhosted.org/packages/45/b0/cce3784eb519b7b5ad680d14b9673a31ab8dcb7aad8b64d81709d2430aa8/websockets-16.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:152284a83a00c59b759697b7f9e9cddf4e3c7861dd0d964b472b70f78f89e80e", size = 186501, upload-time = "2026-01-10T09:23:29.449Z" },
+ { url = "https://files.pythonhosted.org/packages/19/60/b8ebe4c7e89fb5f6cdf080623c9d92789a53636950f7abacfc33fe2b3135/websockets-16.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bc59589ab64b0022385f429b94697348a6a234e8ce22544e3681b2e9331b5944", size = 186062, upload-time = "2026-01-10T09:23:31.368Z" },
+ { url = "https://files.pythonhosted.org/packages/88/a8/a080593f89b0138b6cba1b28f8df5673b5506f72879322288b031337c0b8/websockets-16.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:32da954ffa2814258030e5a57bc73a3635463238e797c7375dc8091327434206", size = 185356, upload-time = "2026-01-10T09:23:32.627Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/b6/b9afed2afadddaf5ebb2afa801abf4b0868f42f8539bfe4b071b5266c9fe/websockets-16.0-cp314-cp314t-win32.whl", hash = "sha256:5a4b4cc550cb665dd8a47f868c8d04c8230f857363ad3c9caf7a0c3bf8c61ca6", size = 178085, upload-time = "2026-01-10T09:23:33.816Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/3e/28135a24e384493fa804216b79a6a6759a38cc4ff59118787b9fb693df93/websockets-16.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b14dc141ed6d2dde437cddb216004bcac6a1df0935d79656387bd41632ba0bbd", size = 178531, upload-time = "2026-01-10T09:23:35.016Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/28/258ebab549c2bf3e64d2b0217b973467394a9cea8c42f70418ca2c5d0d2e/websockets-16.0-py3-none-any.whl", hash = "sha256:1637db62fad1dc833276dded54215f2c7fa46912301a24bd94d45d46a011ceec", size = 171598, upload-time = "2026-01-10T09:23:45.395Z" },
+]
+
+[[package]]
+name = "wrapt"
+version = "2.1.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/2e/64/925f213fdcbb9baeb1530449ac71a4d57fc361c053d06bf78d0c5c7cd80c/wrapt-2.1.2.tar.gz", hash = "sha256:3996a67eecc2c68fd47b4e3c564405a5777367adfd9b8abb58387b63ee83b21e", size = 81678, upload-time = "2026-03-06T02:53:25.134Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/4c/b6/1db817582c49c7fcbb7df6809d0f515af29d7c2fbf57eb44c36e98fb1492/wrapt-2.1.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ff2aad9c4cda28a8f0653fc2d487596458c2a3f475e56ba02909e950a9efa6a9", size = 61255, upload-time = "2026-03-06T02:52:45.663Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/16/9b02a6b99c09227c93cd4b73acc3678114154ec38da53043c0ddc1fba0dc/wrapt-2.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6433ea84e1cfacf32021d2a4ee909554ade7fd392caa6f7c13f1f4bf7b8e8748", size = 61848, upload-time = "2026-03-06T02:53:48.728Z" },
+ { url = "https://files.pythonhosted.org/packages/af/aa/ead46a88f9ec3a432a4832dfedb84092fc35af2d0ba40cd04aea3889f247/wrapt-2.1.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c20b757c268d30d6215916a5fa8461048d023865d888e437fab451139cad6c8e", size = 121433, upload-time = "2026-03-06T02:54:40.328Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/9f/742c7c7cdf58b59085a1ee4b6c37b013f66ac33673a7ef4aaed5e992bc33/wrapt-2.1.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79847b83eb38e70d93dc392c7c5b587efe65b3e7afcc167aa8abd5d60e8761c8", size = 123013, upload-time = "2026-03-06T02:53:26.58Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/44/2c3dd45d53236b7ed7c646fcf212251dc19e48e599debd3926b52310fafb/wrapt-2.1.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f8fba1bae256186a83d1875b2b1f4e2d1242e8fac0f58ec0d7e41b26967b965c", size = 117326, upload-time = "2026-03-06T02:53:11.547Z" },
+ { url = "https://files.pythonhosted.org/packages/74/e2/b17d66abc26bd96f89dec0ecd0ef03da4a1286e6ff793839ec431b9fae57/wrapt-2.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e3d3b35eedcf5f7d022291ecd7533321c4775f7b9cd0050a31a68499ba45757c", size = 121444, upload-time = "2026-03-06T02:54:09.5Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/62/e2977843fdf9f03daf1586a0ff49060b1b2fc7ff85a7ea82b6217c1ae36e/wrapt-2.1.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:6f2c5390460de57fa9582bc8a1b7a6c86e1a41dfad74c5225fc07044c15cc8d1", size = 116237, upload-time = "2026-03-06T02:54:03.884Z" },
+ { url = "https://files.pythonhosted.org/packages/88/dd/27fc67914e68d740bce512f11734aec08696e6b17641fef8867c00c949fc/wrapt-2.1.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7dfa9f2cf65d027b951d05c662cc99ee3bd01f6e4691ed39848a7a5fffc902b2", size = 120563, upload-time = "2026-03-06T02:53:20.412Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/9f/b750b3692ed2ef4705cb305bd68858e73010492b80e43d2a4faa5573cbe7/wrapt-2.1.2-cp312-cp312-win32.whl", hash = "sha256:eba8155747eb2cae4a0b913d9ebd12a1db4d860fc4c829d7578c7b989bd3f2f0", size = 58198, upload-time = "2026-03-06T02:53:37.732Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/b2/feecfe29f28483d888d76a48f03c4c4d8afea944dbee2b0cd3380f9df032/wrapt-2.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:1c51c738d7d9faa0b3601708e7e2eda9bf779e1b601dce6c77411f2a1b324a63", size = 60441, upload-time = "2026-03-06T02:52:47.138Z" },
+ { url = "https://files.pythonhosted.org/packages/44/e1/e328f605d6e208547ea9fd120804fcdec68536ac748987a68c47c606eea8/wrapt-2.1.2-cp312-cp312-win_arm64.whl", hash = "sha256:c8e46ae8e4032792eb2f677dbd0d557170a8e5524d22acc55199f43efedd39bf", size = 58836, upload-time = "2026-03-06T02:53:22.053Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/7a/d936840735c828b38d26a854e85d5338894cda544cb7a85a9d5b8b9c4df7/wrapt-2.1.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787fd6f4d67befa6fe2abdffcbd3de2d82dfc6fb8a6d850407c53332709d030b", size = 61259, upload-time = "2026-03-06T02:53:41.922Z" },
+ { url = "https://files.pythonhosted.org/packages/5e/88/9a9b9a90ac8ca11c2fdb6a286cb3a1fc7dd774c00ed70929a6434f6bc634/wrapt-2.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4bdf26e03e6d0da3f0e9422fd36bcebf7bc0eeb55fdf9c727a09abc6b9fe472e", size = 61851, upload-time = "2026-03-06T02:52:48.672Z" },
+ { url = "https://files.pythonhosted.org/packages/03/a9/5b7d6a16fd6533fed2756900fc8fc923f678179aea62ada6d65c92718c00/wrapt-2.1.2-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bbac24d879aa22998e87f6b3f481a5216311e7d53c7db87f189a7a0266dafffb", size = 121446, upload-time = "2026-03-06T02:54:14.013Z" },
+ { url = "https://files.pythonhosted.org/packages/45/bb/34c443690c847835cfe9f892be78c533d4f32366ad2888972c094a897e39/wrapt-2.1.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:16997dfb9d67addc2e3f41b62a104341e80cac52f91110dece393923c0ebd5ca", size = 123056, upload-time = "2026-03-06T02:54:10.829Z" },
+ { url = "https://files.pythonhosted.org/packages/93/b9/ff205f391cb708f67f41ea148545f2b53ff543a7ac293b30d178af4d2271/wrapt-2.1.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:162e4e2ba7542da9027821cb6e7c5e068d64f9a10b5f15512ea28e954893a267", size = 117359, upload-time = "2026-03-06T02:53:03.623Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/3d/1ea04d7747825119c3c9a5e0874a40b33594ada92e5649347c457d982805/wrapt-2.1.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f29c827a8d9936ac320746747a016c4bc66ef639f5cd0d32df24f5eacbf9c69f", size = 121479, upload-time = "2026-03-06T02:53:45.844Z" },
+ { url = "https://files.pythonhosted.org/packages/78/cc/ee3a011920c7a023b25e8df26f306b2484a531ab84ca5c96260a73de76c0/wrapt-2.1.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:a9dd9813825f7ecb018c17fd147a01845eb330254dff86d3b5816f20f4d6aaf8", size = 116271, upload-time = "2026-03-06T02:54:46.356Z" },
+ { url = "https://files.pythonhosted.org/packages/98/fd/e5ff7ded41b76d802cf1191288473e850d24ba2e39a6ec540f21ae3b57cb/wrapt-2.1.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6f8dbdd3719e534860d6a78526aafc220e0241f981367018c2875178cf83a413", size = 120573, upload-time = "2026-03-06T02:52:50.163Z" },
+ { url = "https://files.pythonhosted.org/packages/47/c5/242cae3b5b080cd09bacef0591691ba1879739050cc7c801ff35c8886b66/wrapt-2.1.2-cp313-cp313-win32.whl", hash = "sha256:5c35b5d82b16a3bc6e0a04349b606a0582bc29f573786aebe98e0c159bc48db6", size = 58205, upload-time = "2026-03-06T02:53:47.494Z" },
+ { url = "https://files.pythonhosted.org/packages/12/69/c358c61e7a50f290958809b3c61ebe8b3838ea3e070d7aac9814f95a0528/wrapt-2.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:f8bc1c264d8d1cf5b3560a87bbdd31131573eb25f9f9447bb6252b8d4c44a3a1", size = 60452, upload-time = "2026-03-06T02:53:30.038Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/66/c8a6fcfe321295fd8c0ab1bd685b5a01462a9b3aa2f597254462fc2bc975/wrapt-2.1.2-cp313-cp313-win_arm64.whl", hash = "sha256:3beb22f674550d5634642c645aba4c72a2c66fb185ae1aebe1e955fae5a13baf", size = 58842, upload-time = "2026-03-06T02:52:52.114Z" },
+ { url = "https://files.pythonhosted.org/packages/da/55/9c7052c349106e0b3f17ae8db4b23a691a963c334de7f9dbd60f8f74a831/wrapt-2.1.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0fc04bc8664a8bc4c8e00b37b5355cffca2535209fba1abb09ae2b7c76ddf82b", size = 63075, upload-time = "2026-03-06T02:53:19.108Z" },
+ { url = "https://files.pythonhosted.org/packages/09/a8/ce7b4006f7218248dd71b7b2b732d0710845a0e49213b18faef64811ffef/wrapt-2.1.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a9b9d50c9af998875a1482a038eb05755dfd6fe303a313f6a940bb53a83c3f18", size = 63719, upload-time = "2026-03-06T02:54:33.452Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/e5/2ca472e80b9e2b7a17f106bb8f9df1db11e62101652ce210f66935c6af67/wrapt-2.1.2-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2d3ff4f0024dd224290c0eabf0240f1bfc1f26363431505fb1b0283d3b08f11d", size = 152643, upload-time = "2026-03-06T02:52:42.721Z" },
+ { url = "https://files.pythonhosted.org/packages/36/42/30f0f2cefca9d9cbf6835f544d825064570203c3e70aa873d8ae12e23791/wrapt-2.1.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3278c471f4468ad544a691b31bb856374fbdefb7fee1a152153e64019379f015", size = 158805, upload-time = "2026-03-06T02:54:25.441Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/67/d08672f801f604889dcf58f1a0b424fe3808860ede9e03affc1876b295af/wrapt-2.1.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a8914c754d3134a3032601c6984db1c576e6abaf3fc68094bb8ab1379d75ff92", size = 145990, upload-time = "2026-03-06T02:53:57.456Z" },
+ { url = "https://files.pythonhosted.org/packages/68/a7/fd371b02e73babec1de6ade596e8cd9691051058cfdadbfd62a5898f3295/wrapt-2.1.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:ff95d4264e55839be37bafe1536db2ab2de19da6b65f9244f01f332b5286cfbf", size = 155670, upload-time = "2026-03-06T02:54:55.309Z" },
+ { url = "https://files.pythonhosted.org/packages/86/2d/9fe0095dfdb621009f40117dcebf41d7396c2c22dca6eac779f4c007b86c/wrapt-2.1.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:76405518ca4e1b76fbb1b9f686cff93aebae03920cc55ceeec48ff9f719c5f67", size = 144357, upload-time = "2026-03-06T02:54:24.092Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/b6/ec7b4a254abbe4cde9fa15c5d2cca4518f6b07d0f1b77d4ee9655e30280e/wrapt-2.1.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c0be8b5a74c5824e9359b53e7e58bef71a729bacc82e16587db1c4ebc91f7c5a", size = 150269, upload-time = "2026-03-06T02:53:31.268Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/6b/2fabe8ebf148f4ee3c782aae86a795cc68ffe7d432ef550f234025ce0cfa/wrapt-2.1.2-cp313-cp313t-win32.whl", hash = "sha256:f01277d9a5fc1862f26f7626da9cf443bebc0abd2f303f41c5e995b15887dabd", size = 59894, upload-time = "2026-03-06T02:54:15.391Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/fb/9ba66fc2dedc936de5f8073c0217b5d4484e966d87723415cc8262c5d9c2/wrapt-2.1.2-cp313-cp313t-win_amd64.whl", hash = "sha256:84ce8f1c2104d2f6daa912b1b5b039f331febfeee74f8042ad4e04992bd95c8f", size = 63197, upload-time = "2026-03-06T02:54:41.943Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/1c/012d7423c95d0e337117723eb8ecf73c622ce15a97847e84cf3f8f26cd7e/wrapt-2.1.2-cp313-cp313t-win_arm64.whl", hash = "sha256:a93cd767e37faeddbe07d8fc4212d5cba660af59bdb0f6372c93faaa13e6e679", size = 60363, upload-time = "2026-03-06T02:54:48.093Z" },
+ { url = "https://files.pythonhosted.org/packages/39/25/e7ea0b417db02bb796182a5316398a75792cd9a22528783d868755e1f669/wrapt-2.1.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:1370e516598854e5b4366e09ce81e08bfe94d42b0fd569b88ec46cc56d9164a9", size = 61418, upload-time = "2026-03-06T02:53:55.706Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/0f/fa539e2f6a770249907757eaeb9a5ff4deb41c026f8466c1c6d799088a9b/wrapt-2.1.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6de1a3851c27e0bd6a04ca993ea6f80fc53e6c742ee1601f486c08e9f9b900a9", size = 61914, upload-time = "2026-03-06T02:52:53.37Z" },
+ { url = "https://files.pythonhosted.org/packages/53/37/02af1867f5b1441aaeda9c82deed061b7cd1372572ddcd717f6df90b5e93/wrapt-2.1.2-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:de9f1a2bbc5ac7f6012ec24525bdd444765a2ff64b5985ac6e0692144838542e", size = 120417, upload-time = "2026-03-06T02:54:30.74Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/b7/0138a6238c8ba7476c77cf786a807f871672b37f37a422970342308276e7/wrapt-2.1.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:970d57ed83fa040d8b20c52fe74a6ae7e3775ae8cff5efd6a81e06b19078484c", size = 122797, upload-time = "2026-03-06T02:54:51.539Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/ad/819ae558036d6a15b7ed290d5b14e209ca795dd4da9c58e50c067d5927b0/wrapt-2.1.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3969c56e4563c375861c8df14fa55146e81ac11c8db49ea6fb7f2ba58bc1ff9a", size = 117350, upload-time = "2026-03-06T02:54:37.651Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/2d/afc18dc57a4600a6e594f77a9ae09db54f55ba455440a54886694a84c71b/wrapt-2.1.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:57d7c0c980abdc5f1d98b11a2aa3bb159790add80258c717fa49a99921456d90", size = 121223, upload-time = "2026-03-06T02:54:35.221Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/5b/5ec189b22205697bc56eb3b62aed87a1e0423e9c8285d0781c7a83170d15/wrapt-2.1.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:776867878e83130c7a04237010463372e877c1c994d449ca6aaafeab6aab2586", size = 116287, upload-time = "2026-03-06T02:54:19.654Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/2d/f84939a7c9b5e6cdd8a8d0f6a26cabf36a0f7e468b967720e8b0cd2bdf69/wrapt-2.1.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:fab036efe5464ec3291411fabb80a7a39e2dd80bae9bcbeeca5087fdfa891e19", size = 119593, upload-time = "2026-03-06T02:54:16.697Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/fe/ccd22a1263159c4ac811ab9374c061bcb4a702773f6e06e38de5f81a1bdc/wrapt-2.1.2-cp314-cp314-win32.whl", hash = "sha256:e6ed62c82ddf58d001096ae84ce7f833db97ae2263bff31c9b336ba8cfe3f508", size = 58631, upload-time = "2026-03-06T02:53:06.498Z" },
+ { url = "https://files.pythonhosted.org/packages/65/0a/6bd83be7bff2e7efaac7b4ac9748da9d75a34634bbbbc8ad077d527146df/wrapt-2.1.2-cp314-cp314-win_amd64.whl", hash = "sha256:467e7c76315390331c67073073d00662015bb730c566820c9ca9b54e4d67fd04", size = 60875, upload-time = "2026-03-06T02:53:50.252Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/c0/0b3056397fe02ff80e5a5d72d627c11eb885d1ca78e71b1a5c1e8c7d45de/wrapt-2.1.2-cp314-cp314-win_arm64.whl", hash = "sha256:da1f00a557c66225d53b095a97eace0fc5349e3bfda28fa34ffae238978ee575", size = 59164, upload-time = "2026-03-06T02:53:59.128Z" },
+ { url = "https://files.pythonhosted.org/packages/71/ed/5d89c798741993b2371396eb9d4634f009ff1ad8a6c78d366fe2883ea7a6/wrapt-2.1.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:62503ffbc2d3a69891cf29beeaccdb4d5e0a126e2b6a851688d4777e01428dbb", size = 63163, upload-time = "2026-03-06T02:52:54.873Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/8c/05d277d182bf36b0a13d6bd393ed1dec3468a25b59d01fba2dd70fe4d6ae/wrapt-2.1.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c7e6cd120ef837d5b6f860a6ea3745f8763805c418bb2f12eeb1fa6e25f22d22", size = 63723, upload-time = "2026-03-06T02:52:56.374Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/27/6c51ec1eff4413c57e72d6106bb8dec6f0c7cdba6503d78f0fa98767bcc9/wrapt-2.1.2-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3769a77df8e756d65fbc050333f423c01ae012b4f6731aaf70cf2bef61b34596", size = 152652, upload-time = "2026-03-06T02:53:23.79Z" },
+ { url = "https://files.pythonhosted.org/packages/db/4c/d7dd662d6963fc7335bfe29d512b02b71cdfa23eeca7ab3ac74a67505deb/wrapt-2.1.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a76d61a2e851996150ba0f80582dd92a870643fa481f3b3846f229de88caf044", size = 158807, upload-time = "2026-03-06T02:53:35.742Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/4d/1e5eea1a78d539d346765727422976676615814029522c76b87a95f6bcdd/wrapt-2.1.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6f97edc9842cf215312b75fe737ee7c8adda75a89979f8e11558dfff6343cc4b", size = 146061, upload-time = "2026-03-06T02:52:57.574Z" },
+ { url = "https://files.pythonhosted.org/packages/89/bc/62cabea7695cd12a288023251eeefdcb8465056ddaab6227cb78a2de005b/wrapt-2.1.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:4006c351de6d5007aa33a551f600404ba44228a89e833d2fadc5caa5de8edfbf", size = 155667, upload-time = "2026-03-06T02:53:39.422Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/99/6f2888cd68588f24df3a76572c69c2de28287acb9e1972bf0c83ce97dbc1/wrapt-2.1.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:a9372fc3639a878c8e7d87e1556fa209091b0a66e912c611e3f833e2c4202be2", size = 144392, upload-time = "2026-03-06T02:54:22.41Z" },
+ { url = "https://files.pythonhosted.org/packages/40/51/1dfc783a6c57971614c48e361a82ca3b6da9055879952587bc99fe1a7171/wrapt-2.1.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3144b027ff30cbd2fca07c0a87e67011adb717eb5f5bd8496325c17e454257a3", size = 150296, upload-time = "2026-03-06T02:54:07.848Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/38/cbb8b933a0201076c1f64fc42883b0023002bdc14a4964219154e6ff3350/wrapt-2.1.2-cp314-cp314t-win32.whl", hash = "sha256:3b8d15e52e195813efe5db8cec156eebe339aaf84222f4f4f051a6c01f237ed7", size = 60539, upload-time = "2026-03-06T02:54:00.594Z" },
+ { url = "https://files.pythonhosted.org/packages/82/dd/e5176e4b241c9f528402cebb238a36785a628179d7d8b71091154b3e4c9e/wrapt-2.1.2-cp314-cp314t-win_amd64.whl", hash = "sha256:08ffa54146a7559f5b8df4b289b46d963a8e74ed16ba3687f99896101a3990c5", size = 63969, upload-time = "2026-03-06T02:54:39Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/99/79f17046cf67e4a95b9987ea129632ba8bcec0bc81f3fb3d19bdb0bd60cd/wrapt-2.1.2-cp314-cp314t-win_arm64.whl", hash = "sha256:72aaa9d0d8e4ed0e2e98019cea47a21f823c9dd4b43c7b77bba6679ffcca6a00", size = 60554, upload-time = "2026-03-06T02:53:14.132Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/c7/8528ac2dfa2c1e6708f647df7ae144ead13f0a31146f43c7264b4942bf12/wrapt-2.1.2-py3-none-any.whl", hash = "sha256:b8fd6fa2b2c4e7621808f8c62e8317f4aae56e59721ad933bac5239d913cf0e8", size = 43993, upload-time = "2026-03-06T02:53:12.905Z" },
+]
+
+[[package]]
+name = "yarl"
+version = "1.23.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "idna" },
+ { name = "multidict" },
+ { name = "propcache" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/23/6e/beb1beec874a72f23815c1434518bfc4ed2175065173fb138c3705f658d4/yarl-1.23.0.tar.gz", hash = "sha256:53b1ea6ca88ebd4420379c330aea57e258408dd0df9af0992e5de2078dc9f5d5", size = 194676, upload-time = "2026-03-01T22:07:53.373Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/88/8a/94615bc31022f711add374097ad4144d569e95ff3c38d39215d07ac153a0/yarl-1.23.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1932b6b8bba8d0160a9d1078aae5838a66039e8832d41d2992daa9a3a08f7860", size = 124737, upload-time = "2026-03-01T22:05:12.897Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/6f/c6554045d59d64052698add01226bc867b52fe4a12373415d7991fdca95d/yarl-1.23.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:411225bae281f114067578891bc75534cfb3d92a3b4dfef7a6ca78ba354e6069", size = 87029, upload-time = "2026-03-01T22:05:14.376Z" },
+ { url = "https://files.pythonhosted.org/packages/19/2a/725ecc166d53438bc88f76822ed4b1e3b10756e790bafd7b523fe97c322d/yarl-1.23.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:13a563739ae600a631c36ce096615fe307f131344588b0bc0daec108cdb47b25", size = 86310, upload-time = "2026-03-01T22:05:15.71Z" },
+ { url = "https://files.pythonhosted.org/packages/99/30/58260ed98e6ff7f90ba84442c1ddd758c9170d70327394a6227b310cd60f/yarl-1.23.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9cbf44c5cb4a7633d078788e1b56387e3d3cf2b8139a3be38040b22d6c3221c8", size = 97587, upload-time = "2026-03-01T22:05:17.384Z" },
+ { url = "https://files.pythonhosted.org/packages/76/0a/8b08aac08b50682e65759f7f8dde98ae8168f72487e7357a5d684c581ef9/yarl-1.23.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:53ad387048f6f09a8969631e4de3f1bf70c50e93545d64af4f751b2498755072", size = 92528, upload-time = "2026-03-01T22:05:18.804Z" },
+ { url = "https://files.pythonhosted.org/packages/52/07/0b7179101fe5f8385ec6c6bb5d0cb9f76bd9fb4a769591ab6fb5cdbfc69a/yarl-1.23.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4a59ba56f340334766f3a4442e0efd0af895fae9e2b204741ef885c446b3a1a8", size = 105339, upload-time = "2026-03-01T22:05:20.235Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/8a/36d82869ab5ec829ca8574dfcb92b51286fcfb1e9c7a73659616362dc880/yarl-1.23.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:803a3c3ce4acc62eaf01eaca1208dcf0783025ef27572c3336502b9c232005e7", size = 105061, upload-time = "2026-03-01T22:05:22.268Z" },
+ { url = "https://files.pythonhosted.org/packages/66/3e/868e5c3364b6cee19ff3e1a122194fa4ce51def02c61023970442162859e/yarl-1.23.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a3d2bff8f37f8d0f96c7ec554d16945050d54462d6e95414babaa18bfafc7f51", size = 100132, upload-time = "2026-03-01T22:05:23.638Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/26/9c89acf82f08a52cb52d6d39454f8d18af15f9d386a23795389d1d423823/yarl-1.23.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c75eb09e8d55bceb4367e83496ff8ef2bc7ea6960efb38e978e8073ea59ecb67", size = 99289, upload-time = "2026-03-01T22:05:25.749Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/54/5b0db00d2cb056922356104468019c0a132e89c8d3ab67d8ede9f4483d2a/yarl-1.23.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877b0738624280e34c55680d6054a307aa94f7d52fa0e3034a9cc6e790871da7", size = 96950, upload-time = "2026-03-01T22:05:27.318Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/40/10fa93811fd439341fad7e0718a86aca0de9548023bbb403668d6555acab/yarl-1.23.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b5405bb8f0e783a988172993cfc627e4d9d00432d6bbac65a923041edacf997d", size = 93960, upload-time = "2026-03-01T22:05:28.738Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/d2/8ae2e6cd77d0805f4526e30ec43b6f9a3dfc542d401ac4990d178e4bf0cf/yarl-1.23.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1c3a3598a832590c5a3ce56ab5576361b5688c12cb1d39429cf5dba30b510760", size = 104703, upload-time = "2026-03-01T22:05:30.438Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/0c/b3ceacf82c3fe21183ce35fa2acf5320af003d52bc1fcf5915077681142e/yarl-1.23.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:8419ebd326430d1cbb7efb5292330a2cf39114e82df5cc3d83c9a0d5ebeaf2f2", size = 98325, upload-time = "2026-03-01T22:05:31.835Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/e0/12900edd28bdab91a69bd2554b85ad7b151f64e8b521fe16f9ad2f56477a/yarl-1.23.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:be61f6fff406ca40e3b1d84716fde398fc08bc63dd96d15f3a14230a0973ed86", size = 105067, upload-time = "2026-03-01T22:05:33.358Z" },
+ { url = "https://files.pythonhosted.org/packages/15/61/74bb1182cf79c9bbe4eb6b1f14a57a22d7a0be5e9cedf8e2d5c2086474c3/yarl-1.23.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ceb13c5c858d01321b5d9bb65e4cf37a92169ea470b70fec6f236b2c9dd7e34", size = 100285, upload-time = "2026-03-01T22:05:35.4Z" },
+ { url = "https://files.pythonhosted.org/packages/69/7f/cd5ef733f2550de6241bd8bd8c3febc78158b9d75f197d9c7baa113436af/yarl-1.23.0-cp312-cp312-win32.whl", hash = "sha256:fffc45637bcd6538de8b85f51e3df3223e4ad89bccbfca0481c08c7fc8b7ed7d", size = 82359, upload-time = "2026-03-01T22:05:36.811Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/be/25216a49daeeb7af2bec0db22d5e7df08ed1d7c9f65d78b14f3b74fd72fc/yarl-1.23.0-cp312-cp312-win_amd64.whl", hash = "sha256:f69f57305656a4852f2a7203efc661d8c042e6cc67f7acd97d8667fb448a426e", size = 87674, upload-time = "2026-03-01T22:05:38.171Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/35/aeab955d6c425b227d5b7247eafb24f2653fedc32f95373a001af5dfeb9e/yarl-1.23.0-cp312-cp312-win_arm64.whl", hash = "sha256:6e87a6e8735b44816e7db0b2fbc9686932df473c826b0d9743148432e10bb9b9", size = 81879, upload-time = "2026-03-01T22:05:40.006Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/4b/a0a6e5d0ee8a2f3a373ddef8a4097d74ac901ac363eea1440464ccbe0898/yarl-1.23.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:16c6994ac35c3e74fb0ae93323bf8b9c2a9088d55946109489667c510a7d010e", size = 123796, upload-time = "2026-03-01T22:05:41.412Z" },
+ { url = "https://files.pythonhosted.org/packages/67/b6/8925d68af039b835ae876db5838e82e76ec87b9782ecc97e192b809c4831/yarl-1.23.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4a42e651629dafb64fd5b0286a3580613702b5809ad3f24934ea87595804f2c5", size = 86547, upload-time = "2026-03-01T22:05:42.841Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/50/06d511cc4b8e0360d3c94af051a768e84b755c5eb031b12adaaab6dec6e5/yarl-1.23.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7c6b9461a2a8b47c65eef63bb1c76a4f1c119618ffa99ea79bc5bb1e46c5821b", size = 85854, upload-time = "2026-03-01T22:05:44.85Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/f4/4e30b250927ffdab4db70da08b9b8d2194d7c7b400167b8fbeca1e4701ca/yarl-1.23.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2569b67d616eab450d262ca7cb9f9e19d2f718c70a8b88712859359d0ab17035", size = 98351, upload-time = "2026-03-01T22:05:46.836Z" },
+ { url = "https://files.pythonhosted.org/packages/86/fc/4118c5671ea948208bdb1492d8b76bdf1453d3e73df051f939f563e7dcc5/yarl-1.23.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e9d9a4d06d3481eab79803beb4d9bd6f6a8e781ec078ac70d7ef2dcc29d1bea5", size = 92711, upload-time = "2026-03-01T22:05:48.316Z" },
+ { url = "https://files.pythonhosted.org/packages/56/11/1ed91d42bd9e73c13dc9e7eb0dd92298d75e7ac4dd7f046ad0c472e231cd/yarl-1.23.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f514f6474e04179d3d33175ed3f3e31434d3130d42ec153540d5b157deefd735", size = 106014, upload-time = "2026-03-01T22:05:50.028Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/c9/74e44e056a23fbc33aca71779ef450ca648a5bc472bdad7a82339918f818/yarl-1.23.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fda207c815b253e34f7e1909840fd14299567b1c0eb4908f8c2ce01a41265401", size = 105557, upload-time = "2026-03-01T22:05:51.416Z" },
+ { url = "https://files.pythonhosted.org/packages/66/fe/b1e10b08d287f518994f1e2ff9b6d26f0adeecd8dd7d533b01bab29a3eda/yarl-1.23.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34b6cf500e61c90f305094911f9acc9c86da1a05a7a3f5be9f68817043f486e4", size = 101559, upload-time = "2026-03-01T22:05:52.872Z" },
+ { url = "https://files.pythonhosted.org/packages/72/59/c5b8d94b14e3d3c2a9c20cb100119fd534ab5a14b93673ab4cc4a4141ea5/yarl-1.23.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d7504f2b476d21653e4d143f44a175f7f751cd41233525312696c76aa3dbb23f", size = 100502, upload-time = "2026-03-01T22:05:54.954Z" },
+ { url = "https://files.pythonhosted.org/packages/77/4f/96976cb54cbfc5c9fd73ed4c51804f92f209481d1fb190981c0f8a07a1d7/yarl-1.23.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:578110dd426f0d209d1509244e6d4a3f1a3e9077655d98c5f22583d63252a08a", size = 98027, upload-time = "2026-03-01T22:05:56.409Z" },
+ { url = "https://files.pythonhosted.org/packages/63/6e/904c4f476471afdbad6b7e5b70362fb5810e35cd7466529a97322b6f5556/yarl-1.23.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:609d3614d78d74ebe35f54953c5bbd2ac647a7ddb9c30a5d877580f5e86b22f2", size = 95369, upload-time = "2026-03-01T22:05:58.141Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/40/acfcdb3b5f9d68ef499e39e04d25e141fe90661f9d54114556cf83be8353/yarl-1.23.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4966242ec68afc74c122f8459abd597afd7d8a60dc93d695c1334c5fd25f762f", size = 105565, upload-time = "2026-03-01T22:06:00.286Z" },
+ { url = "https://files.pythonhosted.org/packages/5e/c6/31e28f3a6ba2869c43d124f37ea5260cac9c9281df803c354b31f4dd1f3c/yarl-1.23.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:e0fd068364a6759bc794459f0a735ab151d11304346332489c7972bacbe9e72b", size = 99813, upload-time = "2026-03-01T22:06:01.712Z" },
+ { url = "https://files.pythonhosted.org/packages/08/1f/6f65f59e72d54aa467119b63fc0b0b1762eff0232db1f4720cd89e2f4a17/yarl-1.23.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:39004f0ad156da43e86aa71f44e033de68a44e5a31fc53507b36dd253970054a", size = 105632, upload-time = "2026-03-01T22:06:03.188Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/c4/18b178a69935f9e7a338127d5b77d868fdc0f0e49becd286d51b3a18c61d/yarl-1.23.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e5723c01a56c5028c807c701aa66722916d2747ad737a046853f6c46f4875543", size = 101895, upload-time = "2026-03-01T22:06:04.651Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/54/f5b870b5505663911dba950a8e4776a0dbd51c9c54c0ae88e823e4b874a0/yarl-1.23.0-cp313-cp313-win32.whl", hash = "sha256:1b6b572edd95b4fa8df75de10b04bc81acc87c1c7d16bcdd2035b09d30acc957", size = 82356, upload-time = "2026-03-01T22:06:06.04Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/84/266e8da36879c6edcd37b02b547e2d9ecdfea776be49598e75696e3316e1/yarl-1.23.0-cp313-cp313-win_amd64.whl", hash = "sha256:baaf55442359053c7d62f6f8413a62adba3205119bcb6f49594894d8be47e5e3", size = 87515, upload-time = "2026-03-01T22:06:08.107Z" },
+ { url = "https://files.pythonhosted.org/packages/00/fd/7e1c66efad35e1649114fa13f17485f62881ad58edeeb7f49f8c5e748bf9/yarl-1.23.0-cp313-cp313-win_arm64.whl", hash = "sha256:fb4948814a2a98e3912505f09c9e7493b1506226afb1f881825368d6fb776ee3", size = 81785, upload-time = "2026-03-01T22:06:10.181Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/fc/119dd07004f17ea43bb91e3ece6587759edd7519d6b086d16bfbd3319982/yarl-1.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:aecfed0b41aa72b7881712c65cf764e39ce2ec352324f5e0837c7048d9e6daaa", size = 130719, upload-time = "2026-03-01T22:06:11.708Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/0d/9f2348502fbb3af409e8f47730282cd6bc80dec6630c1e06374d882d6eb2/yarl-1.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a41bcf68efd19073376eb8cf948b8d9be0af26256403e512bb18f3966f1f9120", size = 89690, upload-time = "2026-03-01T22:06:13.429Z" },
+ { url = "https://files.pythonhosted.org/packages/50/93/e88f3c80971b42cfc83f50a51b9d165a1dbf154b97005f2994a79f212a07/yarl-1.23.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:cde9a2ecd91668bcb7f077c4966d8ceddb60af01b52e6e3e2680e4cf00ad1a59", size = 89851, upload-time = "2026-03-01T22:06:15.53Z" },
+ { url = "https://files.pythonhosted.org/packages/1c/07/61c9dd8ba8f86473263b4036f70fb594c09e99c0d9737a799dfd8bc85651/yarl-1.23.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5023346c4ee7992febc0068e7593de5fa2bf611848c08404b35ebbb76b1b0512", size = 95874, upload-time = "2026-03-01T22:06:17.553Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/e9/f9ff8ceefba599eac6abddcfb0b3bee9b9e636e96dbf54342a8577252379/yarl-1.23.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d1009abedb49ae95b136a8904a3f71b342f849ffeced2d3747bf29caeda218c4", size = 88710, upload-time = "2026-03-01T22:06:19.004Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/78/0231bfcc5d4c8eec220bc2f9ef82cb4566192ea867a7c5b4148f44f6cbcd/yarl-1.23.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a8d00f29b42f534cc8aa3931cfe773b13b23e561e10d2b26f27a8d309b0e82a1", size = 101033, upload-time = "2026-03-01T22:06:21.203Z" },
+ { url = "https://files.pythonhosted.org/packages/cd/9b/30ea5239a61786f18fd25797151a17fbb3be176977187a48d541b5447dd4/yarl-1.23.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:95451e6ce06c3e104556d73b559f5da6c34a069b6b62946d3ad66afcd51642ea", size = 100817, upload-time = "2026-03-01T22:06:22.738Z" },
+ { url = "https://files.pythonhosted.org/packages/62/e2/a4980481071791bc83bce2b7a1a1f7adcabfa366007518b4b845e92eeee3/yarl-1.23.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:531ef597132086b6cf96faa7c6c1dcd0361dd5f1694e5cc30375907b9b7d3ea9", size = 97482, upload-time = "2026-03-01T22:06:24.21Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/1e/304a00cf5f6100414c4b5a01fc7ff9ee724b62158a08df2f8170dfc72a2d/yarl-1.23.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:88f9fb0116fbfcefcab70f85cf4b74a2b6ce5d199c41345296f49d974ddb4123", size = 95949, upload-time = "2026-03-01T22:06:25.697Z" },
+ { url = "https://files.pythonhosted.org/packages/68/03/093f4055ed4cae649ac53bca3d180bd37102e9e11d048588e9ab0c0108d0/yarl-1.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e7b0460976dc75cb87ad9cc1f9899a4b97751e7d4e77ab840fc9b6d377b8fd24", size = 95839, upload-time = "2026-03-01T22:06:27.309Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/28/4c75ebb108f322aa8f917ae10a8ffa4f07cae10a8a627b64e578617df6a0/yarl-1.23.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:115136c4a426f9da976187d238e84139ff6b51a20839aa6e3720cd1026d768de", size = 90696, upload-time = "2026-03-01T22:06:29.048Z" },
+ { url = "https://files.pythonhosted.org/packages/23/9c/42c2e2dd91c1a570402f51bdf066bfdb1241c2240ba001967bad778e77b7/yarl-1.23.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:ead11956716a940c1abc816b7df3fa2b84d06eaed8832ca32f5c5e058c65506b", size = 100865, upload-time = "2026-03-01T22:06:30.525Z" },
+ { url = "https://files.pythonhosted.org/packages/74/05/1bcd60a8a0a914d462c305137246b6f9d167628d73568505fce3f1cb2e65/yarl-1.23.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:fe8f8f5e70e6dbdfca9882cd9deaac058729bcf323cf7a58660901e55c9c94f6", size = 96234, upload-time = "2026-03-01T22:06:32.692Z" },
+ { url = "https://files.pythonhosted.org/packages/90/b2/f52381aac396d6778ce516b7bc149c79e65bfc068b5de2857ab69eeea3b7/yarl-1.23.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:a0e317df055958a0c1e79e5d2aa5a5eaa4a6d05a20d4b0c9c3f48918139c9fc6", size = 100295, upload-time = "2026-03-01T22:06:34.268Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/e8/638bae5bbf1113a659b2435d8895474598afe38b4a837103764f603aba56/yarl-1.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f0fd84de0c957b2d280143522c4f91a73aada1923caee763e24a2b3fda9f8a5", size = 97784, upload-time = "2026-03-01T22:06:35.864Z" },
+ { url = "https://files.pythonhosted.org/packages/80/25/a3892b46182c586c202629fc2159aa13975d3741d52ebd7347fd501d48d5/yarl-1.23.0-cp313-cp313t-win32.whl", hash = "sha256:93a784271881035ab4406a172edb0faecb6e7d00f4b53dc2f55919d6c9688595", size = 88313, upload-time = "2026-03-01T22:06:37.39Z" },
+ { url = "https://files.pythonhosted.org/packages/43/68/8c5b36aa5178900b37387937bc2c2fe0e9505537f713495472dcf6f6fccc/yarl-1.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:dd00607bffbf30250fe108065f07453ec124dbf223420f57f5e749b04295e090", size = 94932, upload-time = "2026-03-01T22:06:39.579Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/cc/d79ba8292f51f81f4dc533a8ccfb9fc6992cabf0998ed3245de7589dc07c/yarl-1.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:ac09d42f48f80c9ee1635b2fcaa819496a44502737660d3c0f2ade7526d29144", size = 84786, upload-time = "2026-03-01T22:06:41.988Z" },
+ { url = "https://files.pythonhosted.org/packages/90/98/b85a038d65d1b92c3903ab89444f48d3cee490a883477b716d7a24b1a78c/yarl-1.23.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:21d1b7305a71a15b4794b5ff22e8eef96ff4a6d7f9657155e5aa419444b28912", size = 124455, upload-time = "2026-03-01T22:06:43.615Z" },
+ { url = "https://files.pythonhosted.org/packages/39/54/bc2b45559f86543d163b6e294417a107bb87557609007c007ad889afec18/yarl-1.23.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:85610b4f27f69984932a7abbe52703688de3724d9f72bceb1cca667deff27474", size = 86752, upload-time = "2026-03-01T22:06:45.425Z" },
+ { url = "https://files.pythonhosted.org/packages/24/f9/e8242b68362bffe6fb536c8db5076861466fc780f0f1b479fc4ffbebb128/yarl-1.23.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:23f371bd662cf44a7630d4d113101eafc0cfa7518a2760d20760b26021454719", size = 86291, upload-time = "2026-03-01T22:06:46.974Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/d8/d1cb2378c81dd729e98c716582b1ccb08357e8488e4c24714658cc6630e8/yarl-1.23.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4a80f77dc1acaaa61f0934176fccca7096d9b1ff08c8ba9cddf5ae034a24319", size = 99026, upload-time = "2026-03-01T22:06:48.459Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/ff/7196790538f31debe3341283b5b0707e7feb947620fc5e8236ef28d44f72/yarl-1.23.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:bd654fad46d8d9e823afbb4f87c79160b5a374ed1ff5bde24e542e6ba8f41434", size = 92355, upload-time = "2026-03-01T22:06:50.306Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/56/25d58c3eddde825890a5fe6aa1866228377354a3c39262235234ab5f616b/yarl-1.23.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:682bae25f0a0dd23a056739f23a134db9f52a63e2afd6bfb37ddc76292bbd723", size = 106417, upload-time = "2026-03-01T22:06:52.1Z" },
+ { url = "https://files.pythonhosted.org/packages/51/8a/882c0e7bc8277eb895b31bce0138f51a1ba551fc2e1ec6753ffc1e7c1377/yarl-1.23.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a82836cab5f197a0514235aaf7ffccdc886ccdaa2324bc0aafdd4ae898103039", size = 106422, upload-time = "2026-03-01T22:06:54.424Z" },
+ { url = "https://files.pythonhosted.org/packages/42/2b/fef67d616931055bf3d6764885990a3ac647d68734a2d6a9e1d13de437a2/yarl-1.23.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c57676bdedc94cd3bc37724cf6f8cd2779f02f6aba48de45feca073e714fe52", size = 101915, upload-time = "2026-03-01T22:06:55.895Z" },
+ { url = "https://files.pythonhosted.org/packages/18/6a/530e16aebce27c5937920f3431c628a29a4b6b430fab3fd1c117b26ff3f6/yarl-1.23.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c7f8dc16c498ff06497c015642333219871effba93e4a2e8604a06264aca5c5c", size = 100690, upload-time = "2026-03-01T22:06:58.21Z" },
+ { url = "https://files.pythonhosted.org/packages/88/08/93749219179a45e27b036e03260fda05190b911de8e18225c294ac95bbc9/yarl-1.23.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:5ee586fb17ff8f90c91cf73c6108a434b02d69925f44f5f8e0d7f2f260607eae", size = 98750, upload-time = "2026-03-01T22:06:59.794Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/cf/ea424a004969f5d81a362110a6ac1496d79efdc6d50c2c4b2e3ea0fc2519/yarl-1.23.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:17235362f580149742739cc3828b80e24029d08cbb9c4bda0242c7b5bc610a8e", size = 94685, upload-time = "2026-03-01T22:07:01.375Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/b7/14341481fe568e2b0408bcf1484c652accafe06a0ade9387b5d3fd9df446/yarl-1.23.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:0793e2bd0cf14234983bbb371591e6bea9e876ddf6896cdcc93450996b0b5c85", size = 106009, upload-time = "2026-03-01T22:07:03.151Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/e6/5c744a9b54f4e8007ad35bce96fbc9218338e84812d36f3390cea616881a/yarl-1.23.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:3650dc2480f94f7116c364096bc84b1d602f44224ef7d5c7208425915c0475dd", size = 100033, upload-time = "2026-03-01T22:07:04.701Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/23/e3bfc188d0b400f025bc49d99793d02c9abe15752138dcc27e4eaf0c4a9e/yarl-1.23.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f40e782d49630ad384db66d4d8b73ff4f1b8955dc12e26b09a3e3af064b3b9d6", size = 106483, upload-time = "2026-03-01T22:07:06.231Z" },
+ { url = "https://files.pythonhosted.org/packages/72/42/f0505f949a90b3f8b7a363d6cbdf398f6e6c58946d85c6d3a3bc70595b26/yarl-1.23.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:94f8575fbdf81749008d980c17796097e645574a3b8c28ee313931068dad14fe", size = 102175, upload-time = "2026-03-01T22:07:08.4Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/65/b39290f1d892a9dd671d1c722014ca062a9c35d60885d57e5375db0404b5/yarl-1.23.0-cp314-cp314-win32.whl", hash = "sha256:c8aa34a5c864db1087d911a0b902d60d203ea3607d91f615acd3f3108ac32169", size = 83871, upload-time = "2026-03-01T22:07:09.968Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/5b/9b92f54c784c26e2a422e55a8d2607ab15b7ea3349e28359282f84f01d43/yarl-1.23.0-cp314-cp314-win_amd64.whl", hash = "sha256:63e92247f383c85ab00dd0091e8c3fa331a96e865459f5ee80353c70a4a42d70", size = 89093, upload-time = "2026-03-01T22:07:11.501Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/7d/8a84dc9381fd4412d5e7ff04926f9865f6372b4c2fd91e10092e65d29eb8/yarl-1.23.0-cp314-cp314-win_arm64.whl", hash = "sha256:70efd20be968c76ece7baa8dafe04c5be06abc57f754d6f36f3741f7aa7a208e", size = 83384, upload-time = "2026-03-01T22:07:13.069Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/8d/d2fad34b1c08aa161b74394183daa7d800141aaaee207317e82c790b418d/yarl-1.23.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:9a18d6f9359e45722c064c97464ec883eb0e0366d33eda61cb19a244bf222679", size = 131019, upload-time = "2026-03-01T22:07:14.903Z" },
+ { url = "https://files.pythonhosted.org/packages/19/ff/33009a39d3ccf4b94d7d7880dfe17fb5816c5a4fe0096d9b56abceea9ac7/yarl-1.23.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:2803ed8b21ca47a43da80a6fd1ed3019d30061f7061daa35ac54f63933409412", size = 89894, upload-time = "2026-03-01T22:07:17.372Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/f1/dab7ac5e7306fb79c0190766a3c00b4cb8d09a1f390ded68c85a5934faf5/yarl-1.23.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:394906945aa8b19fc14a61cf69743a868bb8c465efe85eee687109cc540b98f4", size = 89979, upload-time = "2026-03-01T22:07:19.361Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/b1/08e95f3caee1fad6e65017b9f26c1d79877b502622d60e517de01e72f95d/yarl-1.23.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:71d006bee8397a4a89f469b8deb22469fe7508132d3c17fa6ed871e79832691c", size = 95943, upload-time = "2026-03-01T22:07:21.266Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/cc/6409f9018864a6aa186c61175b977131f373f1988e198e031236916e87e4/yarl-1.23.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:62694e275c93d54f7ccedcfef57d42761b2aad5234b6be1f3e3026cae4001cd4", size = 88786, upload-time = "2026-03-01T22:07:23.129Z" },
+ { url = "https://files.pythonhosted.org/packages/76/40/cc22d1d7714b717fde2006fad2ced5efe5580606cb059ae42117542122f3/yarl-1.23.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a31de1613658308efdb21ada98cbc86a97c181aa050ba22a808120bb5be3ab94", size = 101307, upload-time = "2026-03-01T22:07:24.689Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/0d/476c38e85ddb4c6ec6b20b815bdd779aa386a013f3d8b85516feee55c8dc/yarl-1.23.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fb1e8b8d66c278b21d13b0a7ca22c41dd757a7c209c6b12c313e445c31dd3b28", size = 100904, upload-time = "2026-03-01T22:07:26.287Z" },
+ { url = "https://files.pythonhosted.org/packages/72/32/0abe4a76d59adf2081dcb0397168553ece4616ada1c54d1c49d8936c74f8/yarl-1.23.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50f9d8d531dfb767c565f348f33dd5139a6c43f5cbdf3f67da40d54241df93f6", size = 97728, upload-time = "2026-03-01T22:07:27.906Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/35/7b30f4810fba112f60f5a43237545867504e15b1c7647a785fbaf588fac2/yarl-1.23.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:575aa4405a656e61a540f4a80eaa5260f2a38fff7bfdc4b5f611840d76e9e277", size = 95964, upload-time = "2026-03-01T22:07:30.198Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/86/ed7a73ab85ef00e8bb70b0cb5421d8a2a625b81a333941a469a6f4022828/yarl-1.23.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:041b1a4cefacf65840b4e295c6985f334ba83c30607441ae3cf206a0eed1a2e4", size = 95882, upload-time = "2026-03-01T22:07:32.132Z" },
+ { url = "https://files.pythonhosted.org/packages/19/90/d56967f61a29d8498efb7afb651e0b2b422a1e9b47b0ab5f4e40a19b699b/yarl-1.23.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:d38c1e8231722c4ce40d7593f28d92b5fc72f3e9774fe73d7e800ec32299f63a", size = 90797, upload-time = "2026-03-01T22:07:34.404Z" },
+ { url = "https://files.pythonhosted.org/packages/72/00/8b8f76909259f56647adb1011d7ed8b321bcf97e464515c65016a47ecdf0/yarl-1.23.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:d53834e23c015ee83a99377db6e5e37d8484f333edb03bd15b4bc312cc7254fb", size = 101023, upload-time = "2026-03-01T22:07:35.953Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/e2/cab11b126fb7d440281b7df8e9ddbe4851e70a4dde47a202b6642586b8d9/yarl-1.23.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:2e27c8841126e017dd2a054a95771569e6070b9ee1b133366d8b31beb5018a41", size = 96227, upload-time = "2026-03-01T22:07:37.594Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/9b/2c893e16bfc50e6b2edf76c1a9eb6cb0c744346197e74c65e99ad8d634d0/yarl-1.23.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:76855800ac56f878847a09ce6dba727c93ca2d89c9e9d63002d26b916810b0a2", size = 100302, upload-time = "2026-03-01T22:07:39.334Z" },
+ { url = "https://files.pythonhosted.org/packages/28/ec/5498c4e3a6d5f1003beb23405671c2eb9cdbf3067d1c80f15eeafe301010/yarl-1.23.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e09fd068c2e169a7070d83d3bde728a4d48de0549f975290be3c108c02e499b4", size = 98202, upload-time = "2026-03-01T22:07:41.717Z" },
+ { url = "https://files.pythonhosted.org/packages/fe/c3/cd737e2d45e70717907f83e146f6949f20cc23cd4bf7b2688727763aa458/yarl-1.23.0-cp314-cp314t-win32.whl", hash = "sha256:73309162a6a571d4cbd3b6a1dcc703c7311843ae0d1578df6f09be4e98df38d4", size = 90558, upload-time = "2026-03-01T22:07:43.433Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/19/3774d162f6732d1cfb0b47b4140a942a35ca82bb19b6db1f80e9e7bdc8f8/yarl-1.23.0-cp314-cp314t-win_amd64.whl", hash = "sha256:4503053d296bc6e4cbd1fad61cf3b6e33b939886c4f249ba7c78b602214fabe2", size = 97610, upload-time = "2026-03-01T22:07:45.773Z" },
+ { url = "https://files.pythonhosted.org/packages/51/47/3fa2286c3cb162c71cdb34c4224d5745a1ceceb391b2bd9b19b668a8d724/yarl-1.23.0-cp314-cp314t-win_arm64.whl", hash = "sha256:44bb7bef4ea409384e3f8bc36c063d77ea1b8d4a5b2706956c0d6695f07dcc25", size = 86041, upload-time = "2026-03-01T22:07:49.026Z" },
+ { url = "https://files.pythonhosted.org/packages/69/68/c8739671f5699c7dc470580a4f821ef37c32c4cb0b047ce223a7f115757f/yarl-1.23.0-py3-none-any.whl", hash = "sha256:a2df6afe50dea8ae15fa34c9f824a3ee958d785fd5d089063d960bae1daa0a3f", size = 48288, upload-time = "2026-03-01T22:07:51.388Z" },
+]
+
+[[package]]
+name = "zipp"
+version = "3.23.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547, upload-time = "2025-06-08T17:06:39.4Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" },
+]
diff --git a/clean/image/npr/README.md b/clean/image/npr/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..bc341d59ee9a81c3b447b1535a3ad23e7090aea6
--- /dev/null
+++ b/clean/image/npr/README.md
@@ -0,0 +1,260 @@
+# Rethinking the Up-Sampling Operations in CNN-based Generative Network for Generalizable Deepfake Detection
+
+
+
+ Beijing Jiaotong University, YanShan University, A*Star
+
+
+
+
+Reference github repository for the paper [Rethinking the Up-Sampling Operations in CNN-based Generative Network for Generalizable Deepfake Detection](https://arxiv.org/abs/2312.10461).
+```
+@misc{tan2023rethinking,
+ title={Rethinking the Up-Sampling Operations in CNN-based Generative Network for Generalizable Deepfake Detection},
+ author={Chuangchuang Tan and Huan Liu and Yao Zhao and Shikui Wei and Guanghua Gu and Ping Liu and Yunchao Wei},
+ year={2023},
+ eprint={2312.10461},
+ archivePrefix={arXiv},
+ primaryClass={cs.CV}
+}
+```
+
+## News 🆕
+- `2024/02`: NPR is accepted by CVPR 2024! Congratulations and thanks to my all co-authors!
+- `2024/05`: [🤗Online Demo](https://huggingface.co/spaces/tancc/Generalizable_Deepfake_Detection-NPR-CVPR2024)
+
+
+
+## Environment setup
+**Classification environment:**
+We recommend installing the required packages by running the command:
+```sh
+pip install -r requirements.txt
+```
+In order to ensure the reproducibility of the results, we provide the following suggestions:
+- Docker image: nvcr.io/nvidia/tensorflow:21.02-tf1-py3
+- Conda environment: [./pytorch18/bin/python](https://drive.google.com/file/d/16MK7KnPebBZx5yeN6jqJ49k7VWbEYQPr/view)
+- Random seed during testing period: [Random seed](https://github.com/chuangchuangtan/NPR-DeepfakeDetection/blob/b4e1bfa59ec58542ab5b1e78a3b75b54df67f3b8/test.py#L14)
+
+## Getting the data
+
+| | paper | Url |
+|:----------------------:|:-----:|:-----:|
+| Train set | [CNNDetection CVPR2020](https://github.com/PeterWang512/CNNDetection) | [Baidudrive](https://pan.baidu.com/s/1l-rXoVhoc8xJDl20Cdwy4Q?pwd=ft8b) |
+| Val set | [CNNDetection CVPR2020](https://github.com/PeterWang512/CNNDetection) | [Baidudrive](https://pan.baidu.com/s/1l-rXoVhoc8xJDl20Cdwy4Q?pwd=ft8b) |
+| Table1 Test | [CNNDetection CVPR2020](https://github.com/PeterWang512/CNNDetection) | [Baidudrive](https://pan.baidu.com/s/1l-rXoVhoc8xJDl20Cdwy4Q?pwd=ft8b) |
+| Table2 Test | [FreqNet AAAI2024](https://github.com/chuangchuangtan/FreqNet-DeepfakeDetection) | [googledrive](https://drive.google.com/drive/folders/11E0Knf9J1qlv2UuTnJSOFUjIIi90czSj?usp=sharing) |
+| Table3 Test | [DIRE ICCV2023](https://github.com/ZhendongWang6/DIRE) | [googledrive](https://drive.google.com/drive/folders/1jZE4hg6SxRvKaPYO_yyMeJN_DOcqGMEf?usp=sharing) |
+| Table4 Test | [UniversalFakeDetect CVPR2023](https://github.com/Yuheng-Li/UniversalFakeDetect) | [googledrive](https://drive.google.com/drive/folders/1nkCXClC7kFM01_fqmLrVNtnOYEFPtWO-?usp=sharing)|
+| Table5 Test | Diffusion1kStep | [googledrive](https://drive.google.com/drive/folders/14f0vApTLiukiPvIHukHDzLujrvJpDpRq?usp=sharing) |
+
+```
+pip install gdown==4.7.1
+
+chmod 777 ./download_dataset.sh
+
+./download_dataset.sh
+```
+## Directory structure
+
+ Click to expand the folder tree structure.
+
+```
+datasets
+|-- ForenSynths_train_val
+| |-- train
+| | |-- car
+| | |-- cat
+| | |-- chair
+| | `-- horse
+| `-- val
+| | |-- car
+| | |-- cat
+| | |-- chair
+| | `-- horse
+| |-- test
+| |-- biggan
+| |-- cyclegan
+| |-- deepfake
+| |-- gaugan
+| |-- progan
+| |-- stargan
+| |-- stylegan
+| `-- stylegan2
+`-- Generalization_Test
+ |-- ForenSynths_test # Table1
+ | |-- biggan
+ | |-- cyclegan
+ | |-- deepfake
+ | |-- gaugan
+ | |-- progan
+ | |-- stargan
+ | |-- stylegan
+ | `-- stylegan2
+ |-- GANGen-Detection # Table2
+ | |-- AttGAN
+ | |-- BEGAN
+ | |-- CramerGAN
+ | |-- InfoMaxGAN
+ | |-- MMDGAN
+ | |-- RelGAN
+ | |-- S3GAN
+ | |-- SNGAN
+ | `-- STGAN
+ |-- DiffusionForensics # Table3
+ | |-- adm
+ | |-- ddpm
+ | |-- iddpm
+ | |-- ldm
+ | |-- pndm
+ | |-- sdv1_new
+ | |-- sdv2
+ | `-- vqdiffusion
+ `-- UniversalFakeDetect # Table4
+ | |-- dalle
+ | |-- glide_100_10
+ | |-- glide_100_27
+ | |-- glide_50_27
+ | |-- guided # Also known as ADM.
+ | |-- ldm_100
+ | |-- ldm_200
+ | `-- ldm_200_cfg
+ |-- Diffusion1kStep # Table5
+ |-- DALLE
+ |-- ddpm
+ |-- guided-diffusion # Also known as ADM.
+ |-- improved-diffusion # Also known as IDDPM.
+ `-- midjourney
+
+
+```
+
+
+## Training the model
+```sh
+CUDA_VISIBLE_DEVICES=0 ./pytorch18/bin/python train.py --name 4class-resnet-car-cat-chair-horse --dataroot ./datasets/ForenSynths_train_val --classes car,cat,chair,horse --batch_size 32 --delr_freq 10 --lr 0.0002 --niter 50
+```
+
+## Testing the detector
+Modify the dataroot in test.py.
+```sh
+CUDA_VISIBLE_DEVICES=0 ./pytorch18/bin/python test.py --model_path ./NPR.pth --batch_size {BS}
+```
+
+## Detection Results
+
+### [AIGCDetectBenchmark](https://drive.google.com/drive/folders/1p4ewuAo7d5LbNJ4cKyh10Xl9Fg2yoFOw) using [ProGAN-4class checkpoint](https://github.com/chuangchuangtan/NPR-DeepfakeDetection/blob/main/model_epoch_last_3090.pth)
+
+When testing on AIGCDetectBenchmark, set no_resize and no_crop to True, and set batch_size to 1.
+To deal with images of odd sizes, add the following code in [network/resnet.py](https://github.com/chuangchuangtan/NPR-DeepfakeDetection/blob/e2dbbe673c69c0c7237726e809a725a0308ec43d/networks/resnet.py#L163).
+```
+n,c,w,h = x.shape
+if w%2 == 1 : x = x[:,:,:-1,:]
+if h%2 == 1 : x = x[:,:,:,:-1]
+```
+
+| Generator | CNNSpot | FreDect | Fusing | GramNet | LNP | LGrad | DIRE-G | DIRE-D | UnivFD | RPTCon | NPR |
+| :---------:| :-----: |:-------:| :--------:|:-------:|:-------:|:-------:|:-------:|:------:|:-------:|:-------:|:----:|
+| ProGAN | 100.00 | 99.36 | 100.00 | 99.99 | 99.67 | 99.83 | 95.19 | 52.75 | 99.81 | 100.00 | 99.9 |
+| StyleGan | 90.17 | 78.02 | 85.20 | 87.05 | 91.75 | 91.08 | 83.03 | 51.31 | 84.93 | 92.77 | 96.1 |
+| BigGAN | 71.17 | 81.97 | 77.40 | 67.33 | 77.75 | 85.62 | 70.12 | 49.70 | 95.08 | 95.80 | 87.3 |
+| CycleGAN | 87.62 | 78.77 | 87.00 | 86.07 | 84.10 | 86.94 | 74.19 | 49.58 | 98.33 | 70.17 | 90.3 |
+| StarGAN | 94.60 | 94.62 | 97.00 | 95.05 | 99.92 | 99.27 | 95.47 | 46.72 | 95.75 | 99.97 | 99.6 |
+| GauGAN | 81.42 | 80.57 | 77.00 | 69.35 | 75.39 | 78.46 | 67.79 | 51.23 | 99.47 | 71.58 | 85.4 |
+| Stylegan2 | 86.91 | 66.19 | 83.30 | 87.28 | 94.64 | 85.32 | 75.31 | 51.72 | 74.96 | 89.55 | 98.1 |
+| WFIR | 91.65 | 50.75 | 66.80 | 86.80 | 70.85 | 55.70 | 58.05 | 53.30 | 86.90 | 85.80 | 60.7 |
+| ADM | 60.39 | 63.42 | 49.00 | 58.61 | 84.73 | 67.15 | 75.78 | 98.25 | 66.87 | 82.17 | 84.9 |
+| Glide | 58.07 | 54.13 | 57.20 | 54.50 | 80.52 | 66.11 | 71.75 | 92.42 | 62.46 | 83.79 | 96.7 |
+| Midjourney | 51.39 | 45.87 | 52.20 | 50.02 | 65.55 | 65.35 | 58.01 | 89.45 | 56.13 | 90.12 | 92.6 |
+| SDv1.4 | 50.57 | 38.79 | 51.00 | 51.70 | 85.55 | 63.02 | 49.74 | 91.24 | 63.66 | 95.38 | 97.4 |
+| SDv1.5 | 50.53 | 39.21 | 51.40 | 52.16 | 85.67 | 63.67 | 49.83 | 91.63 | 63.49 | 95.30 | 97.5 |
+| VQDM | 56.46 | 77.80 | 55.10 | 52.86 | 74.46 | 72.99 | 53.68 | 91.90 | 85.31 | 88.91 | 90.1 |
+| Wukong | 51.03 | 40.30 | 51.70 | 50.76 | 82.06 | 59.55 | 54.46 | 90.90 | 70.93 | 91.07 | 91.7 |
+| DALLE2 | 50.45 | 34.70 | 52.80 | 49.25 | 88.75 | 65.45 | 66.48 | 92.45 | 50.75 | 96.60 | 99.6 |
+| Average | 70.78 | 64.03 | 68.38 | 68.67 | 83.84 | 75.34 | 68.68 | 71.53 | 78.43 | 89.31 | **91.7** |
+
+### [GenImage](https://github.com/GenImage-Dataset/GenImage)
+
+
+ (1) Change "resize" to "translate and duplicate". (2) Set random seed to 70. (3) During testing, set no_crop to False.
+
+(1)
+```
+dset = datasets.ImageFolder(
+ root,
+ transforms.Compose([
+ # rz_func,
+ transforms.Lambda(lambda img: translate_duplicate(img, opt.cropSize)),
+ crop_func,
+ flip_func,
+ transforms.ToTensor(),
+ transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
+ ]))
+
+import math
+def translate_duplicate(img, cropSize):
+ if min(img.size) < cropSize:
+ width, height = img.size
+
+ new_width = width * math.ceil(cropSize/width)
+ new_height = height * math.ceil(cropSize/height)
+
+ new_img = Image.new('RGB', (new_width, new_height))
+ for i in range(0, new_width, width):
+ for j in range(0, new_height, height):
+ new_img.paste(img, (i, j))
+ return new_img
+ else:
+ return img
+```
+(2)
+Set [random seed](https://github.com/chuangchuangtan/NPR-DeepfakeDetection/blob/bed4c2c9eb9b2000e9a24233d3b010afa3452f12/train.py#L48) to 70.
+
+(3)
+During testing, set [no_crop](https://github.com/chuangchuangtan/NPR-DeepfakeDetection/blob/bed4c2c9eb9b2000e9a24233d3b010afa3452f12/train.py#L69) to False. And set [test config](https://github.com/chuangchuangtan/NPR-DeepfakeDetection/blob/bed4c2c9eb9b2000e9a24233d3b010afa3452f12/train.py#L30)
+```
+vals = ['ADM', 'biggan', 'glide', 'midjourney', 'sdv5', 'vqdm', 'wukong']
+multiclass = [ 0, 0, 0, 0, 0, 0, 0 ]
+```
+
+
+```
+./pytorch18/bin/python train.py --dataroot {GenImage Path} --name sdv4_bs32_ --batch_size 32 --lr 0.0002 --niter 1 --cropSize 224 --classes sdv4
+```
+
+Train with sdv4 as the training set, using a random seed of 70. [Pretrained checkpoint](https://drive.google.com/drive/folders/1_mD17F94xMbJqEAsWRW1gVsZ5db6YamI?usp=sharing).
+
+|Generator | Acc. | A.P. |
+|:----------:|:----:|:----:|
+| ADM | 87.8 | 96.0 |
+| biggan | 80.7 | 89.8 |
+| glide | 93.2 | 99.1 |
+| midjourney | 91.7 | 97.9 |
+| sdv5 | 94.4 | 99.9 |
+| vqdm | 88.7 | 96.1 |
+| wukong | 94.0 | 99.7 |
+| Mean | 90.1 | 96.9 |
+
+
+
+## Acknowledgments
+
+This repository borrows partially from the [CNNDetection](https://github.com/peterwang512/CNNDetection).
diff --git a/clean/image/npr/SOURCE.md b/clean/image/npr/SOURCE.md
new file mode 100644
index 0000000000000000000000000000000000000000..452da84045d92156be3eae80f4be99c265b6b5ac
--- /dev/null
+++ b/clean/image/npr/SOURCE.md
@@ -0,0 +1,17 @@
+# Source: image/npr
+
+| Field | Value |
+|---|---|
+| Upstream | https://github.com/chuangchuangtan/NPR-DeepfakeDetection |
+| Paper | https://arxiv.org/abs/2312.10461 |
+| Commit SHA | **not recorded** -- the vendoring step did not preserve it |
+| Mirrored on | 2026-09-15 |
+| Upstream license | no license file present upstream (all rights reserved) |
+
+This is a **mirror**, stripped to the files needed for inference. The full
+untouched snapshot is at `archive/image__npr.tar.gz`.
+
+This code is the work of its original authors and is **not** covered by the
+DeepSafe project license. If you are an author and want this removed, open an
+issue on https://github.com/deepsafehq/deepsafe-bench and it will be taken down
+within 48 hours, no questions asked.
diff --git a/clean/image/npr/download_dataset.sh b/clean/image/npr/download_dataset.sh
new file mode 100644
index 0000000000000000000000000000000000000000..41480868d59c8238d821902933209fd36ae0c9ea
--- /dev/null
+++ b/clean/image/npr/download_dataset.sh
@@ -0,0 +1,53 @@
+
+pwd=$(cd $(dirname $0); pwd)
+echo pwd: $pwd
+
+# pip install gdown==4.7.1
+
+mkdir dataset
+cd dataset
+
+# --proxy http://ip:port
+
+
+
+# https://github.com/Yuheng-Li/UniversalFakeDetect
+# https://drive.google.com/drive/folders/1nkCXClC7kFM01_fqmLrVNtnOYEFPtWO-
+gdown https://drive.google.com/drive/folders/1nkCXClC7kFM01_fqmLrVNtnOYEFPtWO- -O ./UniversalFakeDetect --folder
+cd ./UniversalFakeDetect
+ls | xargs -I pa sh -c "tar -zxvf pa; rm pa"
+cd $pwd/dataset
+
+# https://github.com/chuangchuangtan/FreqNet-DeepfakeDetection
+# https://drive.google.com/drive/folders/11E0Knf9J1qlv2UuTnJSOFUjIIi90czSj?usp=sharing
+gdown https://drive.google.com/drive/folders/11E0Knf9J1qlv2UuTnJSOFUjIIi90czSj -O ./GANGen-Detection --folder
+
+cd ./GANGen-Detection
+ls | xargs -I pa sh -c "tar -zxvf pa; rm pa"
+cd $pwd/dataset
+
+# https://github.com/ZhendongWang6/DIRE
+# https://drive.google.com/drive/folders/1tKsOU-6FDdstrrKLPYuZ7RpQwtOSHxUD?usp=sharing
+gdown https://drive.google.com/drive/folders/1tKsOU-6FDdstrrKLPYuZ7RpQwtOSHxUD -O ./DiffusionForensics --folder
+
+cd ./DiffusionForensics
+ls | xargs -I pa sh -c "tar -zxvf pa; rm pa"
+cd $pwd/dataset
+
+# https://github.com/Ekko-zn/AIGCDetectBenchmark
+# https://drive.google.com/drive/folders/1BUv1MT1cm90QN3WTMHLEr8PXBsKGxKC9?usp=sharing
+gdown https://drive.google.com/drive/folders/1BUv1MT1cm90QN3WTMHLEr8PXBsKGxKC9 -O ./AIGCDetect_testset --folder
+zip -s- test.zip -O test_full.zip
+unzip test_full.zip -d ./AIGCDetect_testset
+cd $pwd/dataset
+
+gdown https://drive.google.com/drive/folders/14f0vApTLiukiPvIHukHDzLujrvJpDpRq -O ./Diffusion1kStep --folder
+cd ./Diffusion1kStep
+ls | xargs -I pa sh -c "tar -zxvf pa; rm pa"
+cd $pwd/dataset
+
+
+# https://github.com/peterwang512/CNNDetection
+gdown 'https://drive.google.com/u/0/uc?id=1z_fD3UKgWQyOTZIBbYSaQ-hz4AzUrLC1' -O CNN_synth_testset.zip --continue
+tar -zxvf CNN_synth_testset.zip -C ./ForenSynths
+
diff --git a/clean/image/npr/networks/__init__.py b/clean/image/npr/networks/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/clean/image/npr/networks/base_model.py b/clean/image/npr/networks/base_model.py
new file mode 100644
index 0000000000000000000000000000000000000000..1e1024d01e417a118ac7047d21a9ffa9f561c82a
--- /dev/null
+++ b/clean/image/npr/networks/base_model.py
@@ -0,0 +1,91 @@
+# from pix2pix
+import os
+import torch
+import torch.nn as nn
+from torch.nn import init
+from torch.optim import lr_scheduler
+
+
+class BaseModel(nn.Module):
+ def __init__(self, opt):
+ super(BaseModel, self).__init__()
+ self.opt = opt
+ self.total_steps = 0
+ self.isTrain = opt.isTrain
+ self.lr = opt.lr
+ self.save_dir = os.path.join(opt.checkpoints_dir, opt.name)
+ self.device = torch.device('cuda:{}'.format(opt.gpu_ids[0])) if opt.gpu_ids else torch.device('cpu')
+
+ def save_networks(self, epoch):
+ save_filename = 'model_epoch_%s.pth' % epoch
+ save_path = os.path.join(self.save_dir, save_filename)
+
+ # serialize model and optimizer to dict
+ # state_dict = {
+ # 'model': self.model.state_dict(),
+ # 'optimizer' : self.optimizer.state_dict(),
+ # 'total_steps' : self.total_steps,
+ # }
+
+ torch.save(self.model.state_dict(), save_path)
+ print(f'Saving model {save_path}')
+
+ # load models from the disk
+ def load_networks(self, epoch):
+ load_filename = 'model_epoch_%s.pth' % epoch
+ load_path = os.path.join(self.save_dir, load_filename)
+
+ print('loading the model from %s' % load_path)
+ # if you are using PyTorch newer than 0.4 (e.g., built from
+ # GitHub source), you can remove str() on self.device
+ state_dict = torch.load(load_path, map_location=self.device)
+ if hasattr(state_dict, '_metadata'):
+ del state_dict._metadata
+
+ self.model.load_state_dict(state_dict['model'])
+ self.total_steps = state_dict['total_steps']
+
+ if self.isTrain and not self.opt.new_optim:
+ self.optimizer.load_state_dict(state_dict['optimizer'])
+ ### move optimizer state to GPU
+ for state in self.optimizer.state.values():
+ for k, v in state.items():
+ if torch.is_tensor(v):
+ state[k] = v.to(self.device)
+
+ for g in self.optimizer.param_groups:
+ g['lr'] = self.opt.lr
+
+ def eval(self):
+ self.model.eval()
+
+ def train(self):
+ self.model.train()
+
+ def test(self):
+ with torch.no_grad():
+ self.forward()
+
+
+def init_weights(net, init_type='normal', gain=0.02):
+ def init_func(m):
+ classname = m.__class__.__name__
+ if hasattr(m, 'weight') and (classname.find('Conv') != -1 or classname.find('Linear') != -1):
+ if init_type == 'normal':
+ init.normal_(m.weight.data, 0.0, gain)
+ elif init_type == 'xavier':
+ init.xavier_normal_(m.weight.data, gain=gain)
+ elif init_type == 'kaiming':
+ init.kaiming_normal_(m.weight.data, a=0, mode='fan_in')
+ elif init_type == 'orthogonal':
+ init.orthogonal_(m.weight.data, gain=gain)
+ else:
+ raise NotImplementedError('initialization method [%s] is not implemented' % init_type)
+ if hasattr(m, 'bias') and m.bias is not None:
+ init.constant_(m.bias.data, 0.0)
+ elif classname.find('BatchNorm2d') != -1:
+ init.normal_(m.weight.data, 1.0, gain)
+ init.constant_(m.bias.data, 0.0)
+
+ print('initialize network with %s' % init_type)
+ net.apply(init_func)
diff --git a/clean/image/npr/networks/resnet.py b/clean/image/npr/networks/resnet.py
new file mode 100644
index 0000000000000000000000000000000000000000..2a5f40ae344bb6e292c89cfb265dbf059829e5b4
--- /dev/null
+++ b/clean/image/npr/networks/resnet.py
@@ -0,0 +1,235 @@
+import torch.nn as nn
+import torch.utils.model_zoo as model_zoo
+from torch.nn import functional as F
+from typing import Any, cast, Dict, List, Optional, Union
+import numpy as np
+
+__all__ = ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101',
+ 'resnet152']
+
+
+model_urls = {
+ 'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth',
+ 'resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth',
+ 'resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth',
+ 'resnet101': 'https://download.pytorch.org/models/resnet101-5d3b4d8f.pth',
+ 'resnet152': 'https://download.pytorch.org/models/resnet152-b121ed2d.pth',
+}
+
+
+def conv3x3(in_planes, out_planes, stride=1):
+ """3x3 convolution with padding"""
+ return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,
+ padding=1, bias=False)
+
+
+def conv1x1(in_planes, out_planes, stride=1):
+ """1x1 convolution"""
+ return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False)
+
+
+class BasicBlock(nn.Module):
+ expansion = 1
+
+ def __init__(self, inplanes, planes, stride=1, downsample=None):
+ super(BasicBlock, self).__init__()
+ self.conv1 = conv3x3(inplanes, planes, stride)
+ self.bn1 = nn.BatchNorm2d(planes)
+ self.relu = nn.ReLU(inplace=True)
+ self.conv2 = conv3x3(planes, planes)
+ self.bn2 = nn.BatchNorm2d(planes)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x):
+ identity = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+
+ if self.downsample is not None:
+ identity = self.downsample(x)
+
+ out += identity
+ out = self.relu(out)
+
+ return out
+
+
+class Bottleneck(nn.Module):
+ expansion = 4
+
+ def __init__(self, inplanes, planes, stride=1, downsample=None):
+ super(Bottleneck, self).__init__()
+ self.conv1 = conv1x1(inplanes, planes)
+ self.bn1 = nn.BatchNorm2d(planes)
+ self.conv2 = conv3x3(planes, planes, stride)
+ self.bn2 = nn.BatchNorm2d(planes)
+ self.conv3 = conv1x1(planes, planes * self.expansion)
+ self.bn3 = nn.BatchNorm2d(planes * self.expansion)
+ self.relu = nn.ReLU(inplace=True)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x):
+ identity = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+ out = self.relu(out)
+
+ out = self.conv3(out)
+ out = self.bn3(out)
+
+ if self.downsample is not None:
+ identity = self.downsample(x)
+
+ out += identity
+ out = self.relu(out)
+
+ return out
+
+
+class ResNet(nn.Module):
+
+ def __init__(self, block, layers, num_classes=1, zero_init_residual=False):
+ super(ResNet, self).__init__()
+
+ self.unfoldSize = 2
+ self.unfoldIndex = 0
+ assert self.unfoldSize > 1
+ assert -1 < self.unfoldIndex and self.unfoldIndex < self.unfoldSize*self.unfoldSize
+ self.inplanes = 64
+ self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=2, padding=1, bias=False)
+ self.bn1 = nn.BatchNorm2d(64)
+ self.relu = nn.ReLU(inplace=True)
+ self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
+ self.layer1 = self._make_layer(block, 64 , layers[0])
+ self.layer2 = self._make_layer(block, 128, layers[1], stride=2)
+ self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
+ # self.fc1 = nn.Linear(512 * block.expansion, 1)
+ self.fc1 = nn.Linear(512, num_classes)
+
+ for m in self.modules():
+ if isinstance(m, nn.Conv2d):
+ nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
+ elif isinstance(m, nn.BatchNorm2d):
+ nn.init.constant_(m.weight, 1)
+ nn.init.constant_(m.bias, 0)
+
+ # Zero-initialize the last BN in each residual branch,
+ # so that the residual branch starts with zeros, and each residual block behaves like an identity.
+ # This improves the model by 0.2~0.3% according to https://arxiv.org/abs/1706.02677
+ if zero_init_residual:
+ for m in self.modules():
+ if isinstance(m, Bottleneck):
+ nn.init.constant_(m.bn3.weight, 0)
+ elif isinstance(m, BasicBlock):
+ nn.init.constant_(m.bn2.weight, 0)
+
+ def _make_layer(self, block, planes, blocks, stride=1):
+ downsample = None
+ if stride != 1 or self.inplanes != planes * block.expansion:
+ downsample = nn.Sequential(
+ conv1x1(self.inplanes, planes * block.expansion, stride),
+ nn.BatchNorm2d(planes * block.expansion),
+ )
+
+ layers = []
+ layers.append(block(self.inplanes, planes, stride, downsample))
+ self.inplanes = planes * block.expansion
+ for _ in range(1, blocks):
+ layers.append(block(self.inplanes, planes))
+
+ return nn.Sequential(*layers)
+ def interpolate(self, img, factor):
+ return F.interpolate(F.interpolate(img, scale_factor=factor, mode='nearest', recompute_scale_factor=True), scale_factor=1/factor, mode='nearest', recompute_scale_factor=True)
+ def forward(self, x):
+ # n,c,w,h = x.shape
+ # if -1*w%2 != 0: x = x[:,:,:w%2*-1,: ]
+ # if -1*h%2 != 0: x = x[:,:,: ,:h%2*-1]
+ # factor = 0.5
+ # x_half = F.interpolate(x, scale_factor=factor, mode='nearest', recompute_scale_factor=True)
+ # x_re = F.interpolate(x_half, scale_factor=1/factor, mode='nearest', recompute_scale_factor=True)
+ # NPR = x - x_re
+ # n,c,w,h = x.shape
+ # if w%2 == 1 : x = x[:,:,:-1,:]
+ # if h%2 == 1 : x = x[:,:,:,:-1]
+ NPR = x - self.interpolate(x, 0.5)
+
+ x = self.conv1(NPR*2.0/3.0)
+ x = self.bn1(x)
+ x = self.relu(x)
+ x = self.maxpool(x)
+
+ x = self.layer1(x)
+ x = self.layer2(x)
+
+ x = self.avgpool(x)
+ x = x.view(x.size(0), -1)
+ x = self.fc1(x)
+
+ return x
+
+
+def resnet18(pretrained=False, **kwargs):
+ """Constructs a ResNet-18 model.
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ """
+ model = ResNet(BasicBlock, [2, 2, 2, 2], **kwargs)
+ if pretrained:
+ model.load_state_dict(model_zoo.load_url(model_urls['resnet18']))
+ return model
+
+
+def resnet34(pretrained=False, **kwargs):
+ """Constructs a ResNet-34 model.
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ """
+ model = ResNet(BasicBlock, [3, 4, 6, 3], **kwargs)
+ if pretrained:
+ model.load_state_dict(model_zoo.load_url(model_urls['resnet34']))
+ return model
+
+
+def resnet50(pretrained=False, **kwargs):
+ """Constructs a ResNet-50 model.
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ """
+ model = ResNet(Bottleneck, [3, 4, 6, 3], **kwargs)
+ if pretrained:
+ model.load_state_dict(model_zoo.load_url(model_urls['resnet50']))
+ return model
+
+
+def resnet101(pretrained=False, **kwargs):
+ """Constructs a ResNet-101 model.
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ """
+ model = ResNet(Bottleneck, [3, 4, 23, 3], **kwargs)
+ if pretrained:
+ model.load_state_dict(model_zoo.load_url(model_urls['resnet101']))
+ return model
+
+
+def resnet152(pretrained=False, **kwargs):
+ """Constructs a ResNet-152 model.
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ """
+ model = ResNet(Bottleneck, [3, 8, 36, 3], **kwargs)
+ if pretrained:
+ model.load_state_dict(model_zoo.load_url(model_urls['resnet152']))
+ return model
diff --git a/clean/image/npr/networks/trainer.py b/clean/image/npr/networks/trainer.py
new file mode 100644
index 0000000000000000000000000000000000000000..217006e9e9b02b558bffa04600ab446c28d0e93e
--- /dev/null
+++ b/clean/image/npr/networks/trainer.py
@@ -0,0 +1,66 @@
+import functools
+import torch
+import torch.nn as nn
+from networks.resnet import resnet50
+from networks.base_model import BaseModel, init_weights
+
+
+class Trainer(BaseModel):
+ def name(self):
+ return 'Trainer'
+
+ def __init__(self, opt):
+ super(Trainer, self).__init__(opt)
+
+ if self.isTrain and not opt.continue_train:
+ self.model = resnet50(pretrained=False, num_classes=1)
+
+ if not self.isTrain or opt.continue_train:
+ self.model = resnet50(num_classes=1)
+
+ if self.isTrain:
+ self.loss_fn = nn.BCEWithLogitsLoss()
+ # initialize optimizers
+ if opt.optim == 'adam':
+ self.optimizer = torch.optim.Adam(filter(lambda p: p.requires_grad, self.model.parameters()),
+ lr=opt.lr, betas=(opt.beta1, 0.999))
+ elif opt.optim == 'sgd':
+ self.optimizer = torch.optim.SGD(filter(lambda p: p.requires_grad, self.model.parameters()),
+ lr=opt.lr, momentum=0.0, weight_decay=0)
+ else:
+ raise ValueError("optim should be [adam, sgd]")
+
+ if not self.isTrain or opt.continue_train:
+ self.load_networks(opt.epoch)
+ self.model.to(opt.gpu_ids[0])
+
+
+ def adjust_learning_rate(self, min_lr=1e-6):
+ for param_group in self.optimizer.param_groups:
+ param_group['lr'] *= 0.9
+ if param_group['lr'] < min_lr:
+ return False
+ self.lr = param_group['lr']
+ print('*'*25)
+ print(f'Changing lr from {param_group["lr"]/0.9} to {param_group["lr"]}')
+ print('*'*25)
+ return True
+
+ def set_input(self, input):
+ self.input = input[0].to(self.device)
+ self.label = input[1].to(self.device).float()
+
+
+ def forward(self):
+ self.output = self.model(self.input)
+
+ def get_loss(self):
+ return self.loss_fn(self.output.squeeze(1), self.label)
+
+ def optimize_parameters(self):
+ self.forward()
+ self.loss = self.loss_fn(self.output.squeeze(1), self.label)
+ self.optimizer.zero_grad()
+ self.loss.backward()
+ self.optimizer.step()
+
diff --git a/clean/image/npr/options/__init__.py b/clean/image/npr/options/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/clean/image/npr/options/base_options.py b/clean/image/npr/options/base_options.py
new file mode 100644
index 0000000000000000000000000000000000000000..1f67932869cb1e76049b9dbdee7ec606c3b541cc
--- /dev/null
+++ b/clean/image/npr/options/base_options.py
@@ -0,0 +1,118 @@
+import argparse
+import os
+import time
+import util
+import torch
+#import models
+#import data
+
+
+class BaseOptions():
+ def __init__(self):
+ self.initialized = False
+
+ def initialize(self, parser):
+ parser.add_argument('--mode', default='binary')
+ parser.add_argument('--arch', type=str, default='res50', help='architecture for binary classification')
+
+ # data augmentation
+ parser.add_argument('--rz_interp', default='bilinear')
+ parser.add_argument('--blur_prob', type=float, default=0)
+ parser.add_argument('--blur_sig', default='0.5')
+ parser.add_argument('--jpg_prob', type=float, default=0)
+ parser.add_argument('--jpg_method', default='cv2')
+ parser.add_argument('--jpg_qual', default='75')
+
+ parser.add_argument('--dataroot', default='./dataset/', help='path to images (should have subfolders trainA, trainB, valA, valB, etc)')
+ parser.add_argument('--classes', default='', help='image classes to train on')
+ parser.add_argument('--class_bal', action='store_true')
+ parser.add_argument('--batch_size', type=int, default=64, help='input batch size')
+ parser.add_argument('--loadSize', type=int, default=256, help='scale images to this size')
+ parser.add_argument('--cropSize', type=int, default=224, help='then crop to this size')
+ parser.add_argument('--gpu_ids', type=str, default='0', help='gpu ids: e.g. 0 0,1,2, 0,2. use -1 for CPU')
+ parser.add_argument('--name', type=str, default='experiment_name', help='name of the experiment. It decides where to store samples and models')
+ parser.add_argument('--epoch', type=str, default='latest', help='which epoch to load? set to latest to use latest cached model')
+ parser.add_argument('--num_threads', default=8, type=int, help='# threads for loading data')
+ parser.add_argument('--checkpoints_dir', type=str, default='./checkpoints', help='models are saved here')
+ parser.add_argument('--serial_batches', action='store_true', help='if true, takes images in order to make batches, otherwise takes them randomly')
+ parser.add_argument('--resize_or_crop', type=str, default='scale_and_crop', help='scaling and cropping of images at load time [resize_and_crop|crop|scale_width|scale_width_and_crop|none]')
+ parser.add_argument('--no_flip', action='store_true', help='if specified, do not flip the images for data augmentation')
+ parser.add_argument('--init_type', type=str, default='normal', help='network initialization [normal|xavier|kaiming|orthogonal]')
+ parser.add_argument('--init_gain', type=float, default=0.02, help='scaling factor for normal, xavier and orthogonal.')
+ parser.add_argument('--suffix', default='', type=str, help='customized suffix: opt.name = opt.name + suffix: e.g., {model}_{netG}_size{loadSize}')
+ parser.add_argument('--delr_freq', type=int, default=20, help='frequency of changing lr')
+
+
+ self.initialized = True
+ return parser
+
+ def gather_options(self):
+ # initialize parser with basic options
+ if not self.initialized:
+ parser = argparse.ArgumentParser(
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+ parser = self.initialize(parser)
+
+ # get the basic options
+ opt, _ = parser.parse_known_args()
+ self.parser = parser
+
+ return opt #parser.parse_args()
+
+ def print_options(self, opt):
+ message = ''
+ message += '----------------- Options ---------------\n'
+ for k, v in sorted(vars(opt).items()):
+ comment = ''
+ default = self.parser.get_default(k)
+ if v != default:
+ comment = '\t[default: %s]' % str(default)
+ message += '{:>25}: {:<30}{}\n'.format(str(k), str(v), comment)
+ message += '----------------- End -------------------'
+ print(message)
+
+ # save to the disk
+
+ expr_dir = os.path.join(opt.checkpoints_dir, opt.name)
+ util.mkdirs(expr_dir)
+ file_name = os.path.join(expr_dir, 'opt.txt')
+ with open(file_name, 'wt') as opt_file:
+ opt_file.write(message)
+ opt_file.write('\n')
+
+ def parse(self, print_options=True):
+
+ opt = self.gather_options()
+ opt.isTrain = self.isTrain # train or test
+ opt.name = opt.name + time.strftime("%Y_%m_%d_%H_%M_%S", time.localtime())
+ # process opt.suffix
+ if opt.suffix:
+ suffix = ('_' + opt.suffix.format(**vars(opt))) if opt.suffix != '' else ''
+ opt.name = opt.name + suffix
+
+ if print_options:
+ self.print_options(opt)
+
+ # set gpu ids
+ str_ids = opt.gpu_ids.split(',')
+ opt.gpu_ids = []
+ for str_id in str_ids:
+ id = int(str_id)
+ if id >= 0:
+ opt.gpu_ids.append(id)
+ if len(opt.gpu_ids) > 0:
+ torch.cuda.set_device(opt.gpu_ids[0])
+
+ # additional
+ opt.classes = opt.classes.split(',')
+ opt.rz_interp = opt.rz_interp.split(',')
+ opt.blur_sig = [float(s) for s in opt.blur_sig.split(',')]
+ opt.jpg_method = opt.jpg_method.split(',')
+ opt.jpg_qual = [int(s) for s in opt.jpg_qual.split(',')]
+ if len(opt.jpg_qual) == 2:
+ opt.jpg_qual = list(range(opt.jpg_qual[0], opt.jpg_qual[1] + 1))
+ elif len(opt.jpg_qual) > 2:
+ raise ValueError("Shouldn't have more than 2 values for --jpg_qual.")
+
+ self.opt = opt
+ return self.opt
diff --git a/clean/image/npr/options/test_options.py b/clean/image/npr/options/test_options.py
new file mode 100644
index 0000000000000000000000000000000000000000..1dba350e3cadf758c2dc39e99a55b4e844e7b16d
--- /dev/null
+++ b/clean/image/npr/options/test_options.py
@@ -0,0 +1,17 @@
+from .base_options import BaseOptions
+
+
+class TestOptions(BaseOptions):
+ def initialize(self, parser):
+ parser = BaseOptions.initialize(self, parser)
+ # parser.add_argument('--dataroot')
+ parser.add_argument('--model_path')
+ parser.add_argument('--no_resize', action='store_true')
+ parser.add_argument('--no_crop', action='store_true')
+ parser.add_argument('--eval', action='store_true', help='use eval mode during test time.')
+ parser.add_argument('--earlystop_epoch', type=int, default=15)
+ parser.add_argument('--lr', type=float, default=0.00002, help='initial learning rate for adam')
+ parser.add_argument('--niter', type=int, default=0, help='# of iter at starting learning rate')
+
+ self.isTrain = False
+ return parser
diff --git a/clean/image/npr/options/train_options.py b/clean/image/npr/options/train_options.py
new file mode 100644
index 0000000000000000000000000000000000000000..c0eeb5f8e71e910358b42a33a0f86a11edccc31c
--- /dev/null
+++ b/clean/image/npr/options/train_options.py
@@ -0,0 +1,26 @@
+from .base_options import BaseOptions
+
+
+class TrainOptions(BaseOptions):
+ def initialize(self, parser):
+ parser = BaseOptions.initialize(self, parser)
+ parser.add_argument('--earlystop_epoch', type=int, default=15)
+ parser.add_argument('--data_aug', action='store_true', help='if specified, perform additional data augmentation (photometric, blurring, jpegging)')
+ parser.add_argument('--optim', type=str, default='adam', help='optim to use [sgd, adam]')
+ parser.add_argument('--new_optim', action='store_true', help='new optimizer instead of loading the optim state')
+ parser.add_argument('--loss_freq', type=int, default=400, help='frequency of showing loss on tensorboard')
+ parser.add_argument('--save_latest_freq', type=int, default=2000, help='frequency of saving the latest results')
+ parser.add_argument('--save_epoch_freq', type=int, default=20, help='frequency of saving checkpoints at the end of epochs')
+ parser.add_argument('--continue_train', action='store_true', help='continue training: load the latest model')
+ parser.add_argument('--epoch_count', type=int, default=1, help='the starting epoch count, we save the model by , +, ...')
+ parser.add_argument('--last_epoch', type=int, default=-1, help='starting epoch count for scheduler intialization')
+ parser.add_argument('--train_split', type=str, default='train', help='train, val, test, etc')
+ parser.add_argument('--val_split', type=str, default='val', help='train, val, test, etc')
+ parser.add_argument('--niter', type=int, default=1000, help='# of iter at starting learning rate')
+ parser.add_argument('--beta1', type=float, default=0.9, help='momentum term of adam')
+ parser.add_argument('--lr', type=float, default=0.0001, help='initial learning rate for adam')
+ # parser.add_argument('--model_path')
+ # parser.add_argument('--no_resize', action='store_true')
+ # parser.add_argument('--no_crop', action='store_true')
+ self.isTrain = True
+ return parser
diff --git a/clean/image/npr/requirements.txt b/clean/image/npr/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..5229c276fd6097939ede4e2f015a95352cb177ec
--- /dev/null
+++ b/clean/image/npr/requirements.txt
@@ -0,0 +1,7 @@
+scipy
+scikit-learn
+numpy
+opencv_python
+Pillow
+torch>=1.2.0
+torchvision
diff --git a/clean/image/npr/test.py b/clean/image/npr/test.py
new file mode 100644
index 0000000000000000000000000000000000000000..07966fbe294b93c0eb1f09b4bc119a05c4275817
--- /dev/null
+++ b/clean/image/npr/test.py
@@ -0,0 +1,73 @@
+import sys
+import time
+import os
+import csv
+import torch
+from util import Logger, printSet
+from validate import validate
+from networks.resnet import resnet50
+from options.test_options import TestOptions
+import networks.resnet as resnet
+import numpy as np
+import random
+import random
+def seed_torch(seed=1029):
+ random.seed(seed)
+ os.environ['PYTHONHASHSEED'] = str(seed)
+ np.random.seed(seed)
+ torch.manual_seed(seed)
+ torch.cuda.manual_seed(seed)
+ torch.cuda.manual_seed_all(seed) # if you are using multi-GPU.
+ torch.backends.cudnn.benchmark = False
+ torch.backends.cudnn.deterministic = True
+ torch.backends.cudnn.enabled = False
+seed_torch(100)
+DetectionTests = {
+ 'ForenSynths': { 'dataroot' : '/opt/data/private/DeepfakeDetection/ForenSynths/',
+ 'no_resize' : False, # Due to the different shapes of images in the dataset, resizing is required during batch detection.
+ 'no_crop' : True,
+ },
+
+ 'GANGen-Detection': { 'dataroot' : '/opt/data/private/DeepfakeDetection/GANGen-Detection/',
+ 'no_resize' : True,
+ 'no_crop' : True,
+ },
+
+ 'DiffusionForensics': { 'dataroot' : '/opt/data/private/DeepfakeDetection/DiffusionForensics/',
+ 'no_resize' : False, # Due to the different shapes of images in the dataset, resizing is required during batch detection.
+ 'no_crop' : True,
+ },
+
+ 'UniversalFakeDetect': { 'dataroot' : '/opt/data/private/DeepfakeDetection/UniversalFakeDetect/',
+ 'no_resize' : False, # Due to the different shapes of images in the dataset, resizing is required during batch detection.
+ 'no_crop' : True,
+ },
+
+ }
+
+
+opt = TestOptions().parse(print_options=False)
+print(f'Model_path {opt.model_path}')
+
+# get model
+model = resnet50(num_classes=1)
+model.load_state_dict(torch.load(opt.model_path, map_location='cpu'), strict=True)
+model.cuda()
+model.eval()
+
+for testSet in DetectionTests.keys():
+ dataroot = DetectionTests[testSet]['dataroot']
+ printSet(testSet)
+
+ accs = [];aps = []
+ print(time.strftime("%Y_%m_%d_%H_%M_%S", time.localtime()))
+ for v_id, val in enumerate(os.listdir(dataroot)):
+ opt.dataroot = '{}/{}'.format(dataroot, val)
+ opt.classes = '' #os.listdir(opt.dataroot) if multiclass[v_id] else ['']
+ opt.no_resize = DetectionTests[testSet]['no_resize']
+ opt.no_crop = DetectionTests[testSet]['no_crop']
+ acc, ap, _, _, _, _ = validate(model, opt)
+ accs.append(acc);aps.append(ap)
+ print("({} {:12}) acc: {:.1f}; ap: {:.1f}".format(v_id, val, acc*100, ap*100))
+ print("({} {:10}) acc: {:.1f}; ap: {:.1f}".format(v_id+1,'Mean', np.array(accs).mean()*100, np.array(aps).mean()*100));print('*'*25)
+
diff --git a/clean/image/npr/train.py b/clean/image/npr/train.py
new file mode 100644
index 0000000000000000000000000000000000000000..48d5a3183e65cf6d0ee6a6b91c717bef4e7c47b4
--- /dev/null
+++ b/clean/image/npr/train.py
@@ -0,0 +1,111 @@
+import os
+import sys
+import time
+import torch
+import torch.nn
+import argparse
+from PIL import Image
+from tensorboardX import SummaryWriter
+import numpy as np
+from validate import validate
+from data import create_dataloader
+from networks.trainer import Trainer
+from options.train_options import TrainOptions
+from options.test_options import TestOptions
+from util import Logger
+
+import random
+def seed_torch(seed=1029):
+ random.seed(seed)
+ os.environ['PYTHONHASHSEED'] = str(seed)
+ np.random.seed(seed)
+ torch.manual_seed(seed)
+ torch.cuda.manual_seed(seed)
+ torch.cuda.manual_seed_all(seed) # if you are using multi-GPU.
+ torch.backends.cudnn.benchmark = False
+ torch.backends.cudnn.deterministic = True
+ torch.backends.cudnn.enabled = False
+
+
+# test config
+vals = ['progan', 'stylegan', 'stylegan2', 'biggan', 'cyclegan', 'stargan', 'gaugan', 'deepfake']
+multiclass = [1, 1, 1, 0, 1, 0, 0, 0]
+
+
+def get_val_opt():
+ val_opt = TrainOptions().parse(print_options=False)
+ val_opt.dataroot = '{}/{}/'.format(val_opt.dataroot, val_opt.val_split)
+ val_opt.isTrain = False
+ val_opt.no_resize = False
+ val_opt.no_crop = False
+ val_opt.serial_batches = True
+
+ return val_opt
+
+
+if __name__ == '__main__':
+ opt = TrainOptions().parse()
+ seed_torch(100)
+ Testdataroot = os.path.join(opt.dataroot, 'test')
+ opt.dataroot = '{}/{}/'.format(opt.dataroot, opt.train_split)
+ Logger(os.path.join(opt.checkpoints_dir, opt.name, 'log.log'))
+ print(' '.join(list(sys.argv)) )
+ val_opt = get_val_opt()
+ Testopt = TestOptions().parse(print_options=False)
+ data_loader = create_dataloader(opt)
+
+ train_writer = SummaryWriter(os.path.join(opt.checkpoints_dir, opt.name, "train"))
+ val_writer = SummaryWriter(os.path.join(opt.checkpoints_dir, opt.name, "val"))
+
+ model = Trainer(opt)
+
+ def testmodel():
+ print('*'*25);accs = [];aps = []
+ print(time.strftime("%Y_%m_%d_%H_%M_%S", time.localtime()))
+ for v_id, val in enumerate(vals):
+ Testopt.dataroot = '{}/{}'.format(Testdataroot, val)
+ Testopt.classes = os.listdir(Testopt.dataroot) if multiclass[v_id] else ['']
+ Testopt.no_resize = False
+ Testopt.no_crop = True
+ acc, ap, _, _, _, _ = validate(model.model, Testopt)
+ accs.append(acc);aps.append(ap)
+ print("({} {:10}) acc: {:.1f}; ap: {:.1f}".format(v_id, val, acc*100, ap*100))
+ print("({} {:10}) acc: {:.1f}; ap: {:.1f}".format(v_id+1,'Mean', np.array(accs).mean()*100, np.array(aps).mean()*100));print('*'*25)
+ print(time.strftime("%Y_%m_%d_%H_%M_%S", time.localtime()))
+ model.eval();testmodel();
+ model.train()
+ print(f'cwd: {os.getcwd()}')
+ for epoch in range(opt.niter):
+ epoch_start_time = time.time()
+ iter_data_time = time.time()
+ epoch_iter = 0
+
+ for i, data in enumerate(data_loader):
+ model.total_steps += 1
+ epoch_iter += opt.batch_size
+
+ model.set_input(data)
+ model.optimize_parameters()
+
+ if model.total_steps % opt.loss_freq == 0:
+ print(time.strftime("%Y_%m_%d_%H_%M_%S", time.localtime()), "Train loss: {} at step: {} lr {}".format(model.loss, model.total_steps, model.lr))
+ train_writer.add_scalar('loss', model.loss, model.total_steps)
+
+ if epoch % opt.delr_freq == 0 and epoch != 0:
+ print(time.strftime("%Y_%m_%d_%H_%M_%S", time.localtime()), 'changing lr at the end of epoch %d, iters %d' %
+ (epoch, model.total_steps))
+ model.adjust_learning_rate()
+
+
+ # Validation
+ model.eval()
+ acc, ap = validate(model.model, val_opt)[:2]
+ val_writer.add_scalar('accuracy', acc, model.total_steps)
+ val_writer.add_scalar('ap', ap, model.total_steps)
+ print("(Val @ epoch {}) acc: {}; ap: {}".format(epoch, acc, ap))
+ testmodel()
+ model.train()
+
+ model.eval();testmodel()
+ model.save_networks('last')
+
diff --git a/clean/image/npr/util.py b/clean/image/npr/util.py
new file mode 100644
index 0000000000000000000000000000000000000000..a41c60c8e33f942fe6cf8f09d57b0d538acb378b
--- /dev/null
+++ b/clean/image/npr/util.py
@@ -0,0 +1,48 @@
+import sys
+import os
+import torch
+
+
+def mkdirs(paths):
+ if isinstance(paths, list) and not isinstance(paths, str):
+ for path in paths:
+ mkdir(path)
+ else:
+ mkdir(paths)
+
+
+def mkdir(path):
+ if not os.path.exists(path):
+ os.makedirs(path)
+
+
+def unnormalize(tens, mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]):
+ # assume tensor of shape NxCxHxW
+ return tens * torch.Tensor(std)[None, :, None, None] + torch.Tensor(
+ mean)[None, :, None, None]
+
+
+
+
+class Logger(object):
+ """Log stdout messages."""
+
+ def __init__(self, outfile):
+ self.terminal = sys.stdout
+ self.log = open(outfile, "a")
+ sys.stdout = self
+
+ def write(self, message):
+ self.terminal.write(message)
+ self.log.write(message)
+
+ def flush(self):
+ self.terminal.flush()
+
+
+def printSet(set_str):
+ set_str = str(set_str)
+ num = len(set_str)
+ print("="*num*3)
+ print(" "*num + set_str)
+ print("="*num*3)
\ No newline at end of file
diff --git a/clean/image/npr/validate.py b/clean/image/npr/validate.py
new file mode 100644
index 0000000000000000000000000000000000000000..1f55e0fc6bd2d49cfada6b69d3f0fa354fe667f7
--- /dev/null
+++ b/clean/image/npr/validate.py
@@ -0,0 +1,42 @@
+import torch
+import numpy as np
+from networks.resnet import resnet50
+from sklearn.metrics import average_precision_score, precision_recall_curve, accuracy_score
+from options.test_options import TestOptions
+from data import create_dataloader
+
+
+def validate(model, opt):
+ data_loader = create_dataloader(opt)
+
+ with torch.no_grad():
+ y_true, y_pred = [], []
+ for img, label in data_loader:
+ in_tens = img.cuda()
+ y_pred.extend(model(in_tens).sigmoid().flatten().tolist())
+ y_true.extend(label.flatten().tolist())
+
+ y_true, y_pred = np.array(y_true), np.array(y_pred)
+ r_acc = accuracy_score(y_true[y_true==0], y_pred[y_true==0] > 0.5)
+ f_acc = accuracy_score(y_true[y_true==1], y_pred[y_true==1] > 0.5)
+ acc = accuracy_score(y_true, y_pred > 0.5)
+ ap = average_precision_score(y_true, y_pred)
+ return acc, ap, r_acc, f_acc, y_true, y_pred
+
+
+if __name__ == '__main__':
+ opt = TestOptions().parse(print_options=False)
+
+ model = resnet50(num_classes=1)
+ state_dict = torch.load(opt.model_path, map_location='cpu')
+ model.load_state_dict(state_dict['model'])
+ model.cuda()
+ model.eval()
+
+ acc, avg_precision, r_acc, f_acc, y_true, y_pred = validate(model, opt)
+
+ print("accuracy:", acc)
+ print("average precision:", avg_precision)
+
+ print("accuracy of real images:", r_acc)
+ print("accuracy of fake images:", f_acc)
diff --git a/clean/image/universal/LICENSE b/clean/image/universal/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..7bcf6bcca73c769ede1f597bb73794e567039fb8
--- /dev/null
+++ b/clean/image/universal/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2025 Wisconsin AI and Vision Lab (WAIV)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/clean/image/universal/README.md b/clean/image/universal/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..393d091108d187521780a0c53f1260fa8967cad6
--- /dev/null
+++ b/clean/image/universal/README.md
@@ -0,0 +1,110 @@
+# Detecting fake images
+
+**Towards Universal Fake Image Detectors that Generalize Across Generative Models**
+[Utkarsh Ojha*](https://utkarshojha.github.io/), [Yuheng Li*](https://yuheng-li.github.io/), [Yong Jae Lee](https://pages.cs.wisc.edu/~yongjaelee/)
+(*Equal contribution)
+CVPR 2023
+
+[[Project Page](https://utkarshojha.github.io/universal-fake-detection/)] [[Paper](https://arxiv.org/abs/2302.10174)]
+
+
+ >
+ Using images from one type of generative model (e.g., GAN), detect fake images from other breeds (e.g., Diffusion models)
+
+
+## Contents
+
+- [Setup](#setup)
+- [Pretrained model](#weights)
+- [Data](#data)
+- [Evaluation](#evaluation)
+- [Training](#training)
+
+
+## Setup
+
+1. Clone this repository
+```bash
+git clone https://github.com/Yuheng-Li/UniversalFakeDetect
+cd UniversalFakeDetect
+```
+
+2. Install the necessary libraries
+```bash
+pip install torch torchvision
+```
+
+## Data
+
+- Of the 19 models studied overall (Table 1/2 in the main paper), 11 are taken from a [previous work](https://arxiv.org/abs/1912.11035). Download the test set, i.e., real/fake images for those 11 models given by the authors from [here](https://drive.google.com/file/d/1z_fD3UKgWQyOTZIBbYSaQ-hz4AzUrLC1/view) (dataset size ~19GB).
+- Download the file and unzip it in `datasets/test`. You could also use the bash scripts provided by the authors, as described [here](https://github.com/PeterWang512/CNNDetection#download-the-dataset) in their code repository.
+- This should create a directory structure as follows:
+```
+
+datasets
+└── test
+ ├── progan
+ │── cyclegan
+ │── biggan
+ │ .
+ │ .
+
+```
+- Each directory (e.g., progan) will contain real/fake images under `0_real` and `1_fake` folders respectively.
+- Dataset for the diffusion models (e.g., LDM/Glide) can be found [here](https://drive.google.com/file/d/1FXlGIRh_Ud3cScMgSVDbEWmPDmjcrm1t/view?usp=drive_link). Note that in the paper (Table 2/3), we had reported the results over 10k randomly sampled images. Since providing that many images for all the domains will take up too much space, we are only releasing 1k images for each domain; i.e., 1k images fake images and 1k real images for each domain (e.g., LDM-200).
+- Download and unzip the file into `./diffusion_datasets` directory.
+
+
+## Evaluation
+
+- You can evaluate the model on all the dataset at once by running:
+```bash
+python validate.py --arch=CLIP:ViT-L/14 --ckpt=pretrained_weights/fc_weights.pth --result_folder=clip_vitl14
+```
+
+- You can also evaluate the model on one generative model by specifying the paths of real and fake datasets
+```bash
+python validate.py --arch=CLIP:ViT-L/14 --ckpt=pretrained_weights/fc_weights.pth --result_folder=clip_vitl14 --real_path datasets/test/progan/0_real --fake_path datasets/test/progan/1_fake
+```
+
+Note that if no arguments are provided for `real_path` and `fake_path`, the script will perform the evaluation on all the domains specified in `dataset_paths.py`.
+
+- The results will be stored in `results/` in two files: `ap.txt` stores the Average Prevision for each of the test domains, and `acc.txt` stores the accuracy (with 0.5 as the threshold) for the same domains.
+
+## Training
+
+- Our main model is trained on the same dataset used by the authors of [this work](https://arxiv.org/abs/1912.11035). Download the official training dataset provided [here](https://drive.google.com/file/d/1iVNBV0glknyTYGA9bCxT_d0CVTOgGcKh/view) (dataset size ~ 72GB).
+
+- Download and unzip the dataset in `datasets/train` directory. The overall structure should look like the following:
+```
+datasets
+└── train
+ └── progan
+ ├── airplane
+ │── bird
+ │── boat
+ │ .
+ │ .
+```
+- A total of 20 different object categories, with each folder containing the corresponding real and fake images in `0_real` and `1_fake` folders.
+- The model can then be trained with the following command:
+```bash
+python train.py --name=clip_vitl14 --wang2020_data_path=datasets/ --data_mode=wang2020 --arch=CLIP:ViT-L/14 --fix_backbone
+```
+- **Important**: do not forget to use the `--fix_backbone` argument during training, which makes sure that the only the linear layer's parameters will be trained.
+
+## Acknowledgement
+
+We would like to thank [Sheng-Yu Wang](https://github.com/PeterWang512) for releasing the real/fake images from different generative models. Our training pipeline is also inspired by his [open-source code](https://github.com/PeterWang512/CNNDetection). We would also like to thank [CompVis](https://github.com/CompVis) for releasing the pre-trained [LDMs](https://github.com/CompVis/latent-diffusion) and [LAION](https://laion.ai/) for open-sourcing [LAION-400M dataset](https://laion.ai/blog/laion-400-open-dataset/).
+
+## Citation
+
+If you find our work helpful in your research, please cite it using the following:
+```bibtex
+@inproceedings{ojha2023fakedetect,
+ title={Towards Universal Fake Image Detectors that Generalize Across Generative Models},
+ author={Ojha, Utkarsh and Li, Yuheng and Lee, Yong Jae},
+ booktitle={CVPR},
+ year={2023},
+}
+```
diff --git a/clean/image/universal/SOURCE.md b/clean/image/universal/SOURCE.md
new file mode 100644
index 0000000000000000000000000000000000000000..508f8d17e20754ad7db494574dfb49b69cf7e8ce
--- /dev/null
+++ b/clean/image/universal/SOURCE.md
@@ -0,0 +1,17 @@
+# Source: image/universal
+
+| Field | Value |
+|---|---|
+| Upstream | https://github.com/Yuheng-Li/UniversalFakeDetect |
+| Paper | https://arxiv.org/abs/2302.10174 |
+| Commit SHA | **not recorded** -- the vendoring step did not preserve it |
+| Mirrored on | 2026-09-15 |
+| Upstream license | LICENSE |
+
+This is a **mirror**, stripped to the files needed for inference. The full
+untouched snapshot is at `archive/image__universal.tar.gz`.
+
+This code is the work of its original authors and is **not** covered by the
+DeepSafe project license. If you are an author and want this removed, open an
+issue on https://github.com/deepsafehq/deepsafe-bench and it will be taken down
+within 48 hours, no questions asked.
diff --git a/clean/image/universal/dataset_paths.py b/clean/image/universal/dataset_paths.py
new file mode 100644
index 0000000000000000000000000000000000000000..3e1c8acfecfda1f209e29cb109e1ad26c64a0ab4
--- /dev/null
+++ b/clean/image/universal/dataset_paths.py
@@ -0,0 +1,153 @@
+DATASET_PATHS = [
+
+
+ dict(
+ real_path='../FAKE_IMAGES/CNN/test/progan',
+ fake_path='../FAKE_IMAGES/CNN/test/progan',
+ data_mode='wang2020',
+ key='progan'
+ ),
+
+ dict(
+ real_path='../FAKE_IMAGES/CNN/test/cyclegan',
+ fake_path='../FAKE_IMAGES/CNN/test/cyclegan',
+ data_mode='wang2020',
+ key='cyclegan'
+ ),
+
+ dict(
+ real_path='../FAKE_IMAGES/CNN/test/biggan/', # Imagenet
+ fake_path='../FAKE_IMAGES/CNN/test/biggan/',
+ data_mode='wang2020',
+ key='biggan'
+ ),
+
+
+ dict(
+ real_path='../FAKE_IMAGES/CNN/test/stylegan',
+ fake_path='../FAKE_IMAGES/CNN/test/stylegan',
+ data_mode='wang2020',
+ key='stylegan'
+ ),
+
+
+ dict(
+ real_path='../FAKE_IMAGES/CNN/test/gaugan', # It is COCO
+ fake_path='../FAKE_IMAGES/CNN/test/gaugan',
+ data_mode='wang2020',
+ key='gaugan'
+ ),
+
+
+ dict(
+ real_path='../FAKE_IMAGES/CNN/test/stargan',
+ fake_path='../FAKE_IMAGES/CNN/test/stargan',
+ data_mode='wang2020',
+ key='stargan'
+ ),
+
+
+ dict(
+ real_path='../FAKE_IMAGES/CNN/test/deepfake',
+ fake_path='../FAKE_IMAGES/CNN/test/deepfake',
+ data_mode='wang2020',
+ key='deepfake'
+ ),
+
+
+ dict(
+ real_path='../FAKE_IMAGES/CNN/test/seeingdark',
+ fake_path='../FAKE_IMAGES/CNN/test/seeingdark',
+ data_mode='wang2020',
+ key='sitd'
+ ),
+
+
+ dict(
+ real_path='../FAKE_IMAGES/CNN/test/san',
+ fake_path='../FAKE_IMAGES/CNN/test/san',
+ data_mode='wang2020',
+ key='san'
+ ),
+
+
+ dict(
+ real_path='../FAKE_IMAGES/CNN/test/crn', # Images from some video games
+ fake_path='../FAKE_IMAGES/CNN/test/crn',
+ data_mode='wang2020',
+ key='crn'
+ ),
+
+
+ dict(
+ real_path='../FAKE_IMAGES/CNN/test/imle', # Images from some video games
+ fake_path='../FAKE_IMAGES/CNN/test/imle',
+ data_mode='wang2020',
+ key='imle'
+ ),
+
+
+ dict(
+ real_path='./diffusion_datasets/imagenet',
+ fake_path='./diffusion_datasets/guided',
+ data_mode='wang2020',
+ key='guided'
+ ),
+
+
+ dict(
+ real_path='./diffusion_datasets/laion',
+ fake_path='./diffusion_datasets/ldm_200',
+ data_mode='wang2020',
+ key='ldm_200'
+ ),
+
+ dict(
+ real_path='./diffusion_datasets/laion',
+ fake_path='./diffusion_datasets/ldm_200_cfg',
+ data_mode='wang2020',
+ key='ldm_200_cfg'
+ ),
+
+ dict(
+ real_path='./diffusion_datasets/laion',
+ fake_path='./diffusion_datasets/ldm_100',
+ data_mode='wang2020',
+ key='ldm_100'
+ ),
+
+
+ dict(
+ real_path='./diffusion_datasets/laion',
+ fake_path='./diffusion_datasets/glide_100_27',
+ data_mode='wang2020',
+ key='glide_100_27'
+ ),
+
+
+ dict(
+ real_path='./diffusion_datasets/laion',
+ fake_path='./diffusion_datasets/glide_50_27',
+ data_mode='wang2020',
+ key='glide_50_27'
+ ),
+
+
+ dict(
+ real_path='./diffusion_datasets/laion',
+ fake_path='./diffusion_datasets/glide_100_10',
+ data_mode='wang2020',
+ key='glide_100_10'
+ ),
+
+
+ dict(
+ real_path='./diffusion_datasets/laion',
+ fake_path='./diffusion_datasets/dalle',
+ data_mode='wang2020',
+ key='dalle'
+ ),
+
+
+
+]
diff --git a/clean/image/universal/models/__init__.py b/clean/image/universal/models/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..d7b790b40d29d1f3bf02f398f3522eea8e4c2c22
--- /dev/null
+++ b/clean/image/universal/models/__init__.py
@@ -0,0 +1,43 @@
+from .clip_models import CLIPModel
+from .imagenet_models import ImagenetModel
+
+
+VALID_NAMES = [
+ 'Imagenet:resnet18',
+ 'Imagenet:resnet34',
+ 'Imagenet:resnet50',
+ 'Imagenet:resnet101',
+ 'Imagenet:resnet152',
+ 'Imagenet:vgg11',
+ 'Imagenet:vgg19',
+ 'Imagenet:swin-b',
+ 'Imagenet:swin-s',
+ 'Imagenet:swin-t',
+ 'Imagenet:vit_b_16',
+ 'Imagenet:vit_b_32',
+ 'Imagenet:vit_l_16',
+ 'Imagenet:vit_l_32',
+
+ 'CLIP:RN50',
+ 'CLIP:RN101',
+ 'CLIP:RN50x4',
+ 'CLIP:RN50x16',
+ 'CLIP:RN50x64',
+ 'CLIP:ViT-B/32',
+ 'CLIP:ViT-B/16',
+ 'CLIP:ViT-L/14',
+ 'CLIP:ViT-L/14@336px',
+]
+
+
+
+
+
+def get_model(name):
+ assert name in VALID_NAMES
+ if name.startswith("Imagenet:"):
+ return ImagenetModel(name[9:])
+ elif name.startswith("CLIP:"):
+ return CLIPModel(name[5:])
+ else:
+ assert False
diff --git a/clean/image/universal/models/clip/__init__.py b/clean/image/universal/models/clip/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..dcc5619538c0f7c782508bdbd9587259d805e0d9
--- /dev/null
+++ b/clean/image/universal/models/clip/__init__.py
@@ -0,0 +1 @@
+from .clip import *
diff --git a/clean/image/universal/models/clip/bpe_simple_vocab_16e6.txt.gz b/clean/image/universal/models/clip/bpe_simple_vocab_16e6.txt.gz
new file mode 100644
index 0000000000000000000000000000000000000000..36a15856e00a06a9fbed8cdd34d2393fea4a3113
--- /dev/null
+++ b/clean/image/universal/models/clip/bpe_simple_vocab_16e6.txt.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:924691ac288e54409236115652ad4aa250f48203de50a9e4722a6ecd48d6804a
+size 1356917
diff --git a/clean/image/universal/models/clip/clip.py b/clean/image/universal/models/clip/clip.py
new file mode 100644
index 0000000000000000000000000000000000000000..257511e1d40c120e0d64a0f1562d44b2b8a40a17
--- /dev/null
+++ b/clean/image/universal/models/clip/clip.py
@@ -0,0 +1,237 @@
+import hashlib
+import os
+import urllib
+import warnings
+from typing import Any, Union, List
+from pkg_resources import packaging
+
+import torch
+from PIL import Image
+from torchvision.transforms import Compose, Resize, CenterCrop, ToTensor, Normalize
+from tqdm import tqdm
+
+from .model import build_model
+from .simple_tokenizer import SimpleTokenizer as _Tokenizer
+
+try:
+ from torchvision.transforms import InterpolationMode
+ BICUBIC = InterpolationMode.BICUBIC
+except ImportError:
+ BICUBIC = Image.BICUBIC
+
+
+if packaging.version.parse(torch.__version__) < packaging.version.parse("1.7.1"):
+ warnings.warn("PyTorch version 1.7.1 or higher is recommended")
+
+
+__all__ = ["available_models", "load", "tokenize"]
+_tokenizer = _Tokenizer()
+
+_MODELS = {
+ "RN50": "https://openaipublic.azureedge.net/clip/models/afeb0e10f9e5a86da6080e35cf09123aca3b358a0c3e3b6c78a7b63bc04b6762/RN50.pt",
+ "RN101": "https://openaipublic.azureedge.net/clip/models/8fa8567bab74a42d41c5915025a8e4538c3bdbe8804a470a72f30b0d94fab599/RN101.pt",
+ "RN50x4": "https://openaipublic.azureedge.net/clip/models/7e526bd135e493cef0776de27d5f42653e6b4c8bf9e0f653bb11773263205fdd/RN50x4.pt",
+ "RN50x16": "https://openaipublic.azureedge.net/clip/models/52378b407f34354e150460fe41077663dd5b39c54cd0bfd2b27167a4a06ec9aa/RN50x16.pt",
+ "RN50x64": "https://openaipublic.azureedge.net/clip/models/be1cfb55d75a9666199fb2206c106743da0f6468c9d327f3e0d0a543a9919d9c/RN50x64.pt",
+ "ViT-B/32": "https://openaipublic.azureedge.net/clip/models/40d365715913c9da98579312b702a82c18be219cc2a73407c4526f58eba950af/ViT-B-32.pt",
+ "ViT-B/16": "https://openaipublic.azureedge.net/clip/models/5806e77cd80f8b59890b7e101eabd078d9fb84e6937f9e85e4ecb61988df416f/ViT-B-16.pt",
+ "ViT-L/14": "https://openaipublic.azureedge.net/clip/models/b8cca3fd41ae0c99ba7e8951adf17d267cdb84cd88be6f7c2e0eca1737a03836/ViT-L-14.pt",
+ "ViT-L/14@336px": "https://openaipublic.azureedge.net/clip/models/3035c92b350959924f9f00213499208652fc7ea050643e8b385c2dac08641f02/ViT-L-14-336px.pt",
+}
+
+
+def _download(url: str, root: str):
+ os.makedirs(root, exist_ok=True)
+ filename = os.path.basename(url)
+
+ expected_sha256 = url.split("/")[-2]
+ download_target = os.path.join(root, filename)
+
+ if os.path.exists(download_target) and not os.path.isfile(download_target):
+ raise RuntimeError(f"{download_target} exists and is not a regular file")
+
+ if os.path.isfile(download_target):
+ if hashlib.sha256(open(download_target, "rb").read()).hexdigest() == expected_sha256:
+ return download_target
+ else:
+ warnings.warn(f"{download_target} exists, but the SHA256 checksum does not match; re-downloading the file")
+
+ with urllib.request.urlopen(url) as source, open(download_target, "wb") as output:
+ with tqdm(total=int(source.info().get("Content-Length")), ncols=80, unit='iB', unit_scale=True, unit_divisor=1024) as loop:
+ while True:
+ buffer = source.read(8192)
+ if not buffer:
+ break
+
+ output.write(buffer)
+ loop.update(len(buffer))
+
+ if hashlib.sha256(open(download_target, "rb").read()).hexdigest() != expected_sha256:
+ raise RuntimeError("Model has been downloaded but the SHA256 checksum does not not match")
+
+ return download_target
+
+
+def _convert_image_to_rgb(image):
+ return image.convert("RGB")
+
+
+def _transform(n_px):
+ return Compose([
+ Resize(n_px, interpolation=BICUBIC),
+ CenterCrop(n_px),
+ _convert_image_to_rgb,
+ ToTensor(),
+ Normalize((0.48145466, 0.4578275, 0.40821073), (0.26862954, 0.26130258, 0.27577711)),
+ ])
+
+
+def available_models() -> List[str]:
+ """Returns the names of available CLIP models"""
+ return list(_MODELS.keys())
+
+
+def load(name: str, device: Union[str, torch.device] = "cuda" if torch.cuda.is_available() else "cpu", jit: bool = False, download_root: str = None):
+ """Load a CLIP model
+
+ Parameters
+ ----------
+ name : str
+ A model name listed by `clip.available_models()`, or the path to a model checkpoint containing the state_dict
+
+ device : Union[str, torch.device]
+ The device to put the loaded model
+
+ jit : bool
+ Whether to load the optimized JIT model or more hackable non-JIT model (default).
+
+ download_root: str
+ path to download the model files; by default, it uses "~/.cache/clip"
+
+ Returns
+ -------
+ model : torch.nn.Module
+ The CLIP model
+
+ preprocess : Callable[[PIL.Image], torch.Tensor]
+ A torchvision transform that converts a PIL image into a tensor that the returned model can take as its input
+ """
+ if name in _MODELS:
+ model_path = _download(_MODELS[name], download_root or os.path.expanduser("~/.cache/clip"))
+ elif os.path.isfile(name):
+ model_path = name
+ else:
+ raise RuntimeError(f"Model {name} not found; available models = {available_models()}")
+
+ with open(model_path, 'rb') as opened_file:
+ try:
+ # loading JIT archive
+ model = torch.jit.load(opened_file, map_location=device if jit else "cpu").eval()
+ state_dict = None
+ except RuntimeError:
+ # loading saved state dict
+ if jit:
+ warnings.warn(f"File {model_path} is not a JIT archive. Loading as a state dict instead")
+ jit = False
+ state_dict = torch.load(opened_file, map_location="cpu")
+
+ if not jit:
+ model = build_model(state_dict or model.state_dict()).to(device)
+ if str(device) == "cpu":
+ model.float()
+ return model, _transform(model.visual.input_resolution)
+
+ # patch the device names
+ device_holder = torch.jit.trace(lambda: torch.ones([]).to(torch.device(device)), example_inputs=[])
+ device_node = [n for n in device_holder.graph.findAllNodes("prim::Constant") if "Device" in repr(n)][-1]
+
+ def patch_device(module):
+ try:
+ graphs = [module.graph] if hasattr(module, "graph") else []
+ except RuntimeError:
+ graphs = []
+
+ if hasattr(module, "forward1"):
+ graphs.append(module.forward1.graph)
+
+ for graph in graphs:
+ for node in graph.findAllNodes("prim::Constant"):
+ if "value" in node.attributeNames() and str(node["value"]).startswith("cuda"):
+ node.copyAttributes(device_node)
+
+ model.apply(patch_device)
+ patch_device(model.encode_image)
+ patch_device(model.encode_text)
+
+ # patch dtype to float32 on CPU
+ if str(device) == "cpu":
+ float_holder = torch.jit.trace(lambda: torch.ones([]).float(), example_inputs=[])
+ float_input = list(float_holder.graph.findNode("aten::to").inputs())[1]
+ float_node = float_input.node()
+
+ def patch_float(module):
+ try:
+ graphs = [module.graph] if hasattr(module, "graph") else []
+ except RuntimeError:
+ graphs = []
+
+ if hasattr(module, "forward1"):
+ graphs.append(module.forward1.graph)
+
+ for graph in graphs:
+ for node in graph.findAllNodes("aten::to"):
+ inputs = list(node.inputs())
+ for i in [1, 2]: # dtype can be the second or third argument to aten::to()
+ if inputs[i].node()["value"] == 5:
+ inputs[i].node().copyAttributes(float_node)
+
+ model.apply(patch_float)
+ patch_float(model.encode_image)
+ patch_float(model.encode_text)
+
+ model.float()
+
+ return model, _transform(model.input_resolution.item())
+
+
+def tokenize(texts: Union[str, List[str]], context_length: int = 77, truncate: bool = False) -> Union[torch.IntTensor, torch.LongTensor]:
+ """
+ Returns the tokenized representation of given input string(s)
+
+ Parameters
+ ----------
+ texts : Union[str, List[str]]
+ An input string or a list of input strings to tokenize
+
+ context_length : int
+ The context length to use; all CLIP models use 77 as the context length
+
+ truncate: bool
+ Whether to truncate the text in case its encoding is longer than the context length
+
+ Returns
+ -------
+ A two-dimensional tensor containing the resulting tokens, shape = [number of input strings, context_length].
+ We return LongTensor when torch version is <1.8.0, since older index_select requires indices to be long.
+ """
+ if isinstance(texts, str):
+ texts = [texts]
+
+ sot_token = _tokenizer.encoder["<|startoftext|>"]
+ eot_token = _tokenizer.encoder["<|endoftext|>"]
+ all_tokens = [[sot_token] + _tokenizer.encode(text) + [eot_token] for text in texts]
+ if packaging.version.parse(torch.__version__) < packaging.version.parse("1.8.0"):
+ result = torch.zeros(len(all_tokens), context_length, dtype=torch.long)
+ else:
+ result = torch.zeros(len(all_tokens), context_length, dtype=torch.int)
+
+ for i, tokens in enumerate(all_tokens):
+ if len(tokens) > context_length:
+ if truncate:
+ tokens = tokens[:context_length]
+ tokens[-1] = eot_token
+ else:
+ raise RuntimeError(f"Input {texts[i]} is too long for context length {context_length}")
+ result[i, :len(tokens)] = torch.tensor(tokens)
+
+ return result
diff --git a/clean/image/universal/models/clip/model.py b/clean/image/universal/models/clip/model.py
new file mode 100644
index 0000000000000000000000000000000000000000..c60bda69ab0d35af0b64517d32595d9c03f8721c
--- /dev/null
+++ b/clean/image/universal/models/clip/model.py
@@ -0,0 +1,452 @@
+from collections import OrderedDict
+from typing import Tuple, Union
+
+import numpy as np
+import torch
+import torch.nn.functional as F
+from torch import nn
+
+
+class Bottleneck(nn.Module):
+ expansion = 4
+
+ def __init__(self, inplanes, planes, stride=1):
+ super().__init__()
+
+ # all conv layers have stride 1. an avgpool is performed after the second convolution when stride > 1
+ self.conv1 = nn.Conv2d(inplanes, planes, 1, bias=False)
+ self.bn1 = nn.BatchNorm2d(planes)
+ self.relu1 = nn.ReLU(inplace=True)
+
+ self.conv2 = nn.Conv2d(planes, planes, 3, padding=1, bias=False)
+ self.bn2 = nn.BatchNorm2d(planes)
+ self.relu2 = nn.ReLU(inplace=True)
+
+ self.avgpool = nn.AvgPool2d(stride) if stride > 1 else nn.Identity()
+
+ self.conv3 = nn.Conv2d(planes, planes * self.expansion, 1, bias=False)
+ self.bn3 = nn.BatchNorm2d(planes * self.expansion)
+ self.relu3 = nn.ReLU(inplace=True)
+
+ self.downsample = None
+ self.stride = stride
+
+ if stride > 1 or inplanes != planes * Bottleneck.expansion:
+ # downsampling layer is prepended with an avgpool, and the subsequent convolution has stride 1
+ self.downsample = nn.Sequential(OrderedDict([
+ ("-1", nn.AvgPool2d(stride)),
+ ("0", nn.Conv2d(inplanes, planes * self.expansion, 1, stride=1, bias=False)),
+ ("1", nn.BatchNorm2d(planes * self.expansion))
+ ]))
+
+ def forward(self, x: torch.Tensor):
+ identity = x
+
+ out = self.relu1(self.bn1(self.conv1(x)))
+ out = self.relu2(self.bn2(self.conv2(out)))
+ out = self.avgpool(out)
+ out = self.bn3(self.conv3(out))
+
+ if self.downsample is not None:
+ identity = self.downsample(x)
+
+ out += identity
+ out = self.relu3(out)
+ return out
+
+
+class AttentionPool2d(nn.Module):
+ def __init__(self, spacial_dim: int, embed_dim: int, num_heads: int, output_dim: int = None):
+ super().__init__()
+ self.positional_embedding = nn.Parameter(torch.randn(spacial_dim ** 2 + 1, embed_dim) / embed_dim ** 0.5)
+ self.k_proj = nn.Linear(embed_dim, embed_dim)
+ self.q_proj = nn.Linear(embed_dim, embed_dim)
+ self.v_proj = nn.Linear(embed_dim, embed_dim)
+ self.c_proj = nn.Linear(embed_dim, output_dim or embed_dim)
+ self.num_heads = num_heads
+
+ def forward(self, x):
+ x = x.flatten(start_dim=2).permute(2, 0, 1) # NCHW -> (HW)NC
+ x = torch.cat([x.mean(dim=0, keepdim=True), x], dim=0) # (HW+1)NC
+ x = x + self.positional_embedding[:, None, :].to(x.dtype) # (HW+1)NC
+ x, _ = F.multi_head_attention_forward(
+ query=x[:1], key=x, value=x,
+ embed_dim_to_check=x.shape[-1],
+ num_heads=self.num_heads,
+ q_proj_weight=self.q_proj.weight,
+ k_proj_weight=self.k_proj.weight,
+ v_proj_weight=self.v_proj.weight,
+ in_proj_weight=None,
+ in_proj_bias=torch.cat([self.q_proj.bias, self.k_proj.bias, self.v_proj.bias]),
+ bias_k=None,
+ bias_v=None,
+ add_zero_attn=False,
+ dropout_p=0,
+ out_proj_weight=self.c_proj.weight,
+ out_proj_bias=self.c_proj.bias,
+ use_separate_proj_weight=True,
+ training=self.training,
+ need_weights=False
+ )
+ return x.squeeze(0)
+
+
+class ModifiedResNet(nn.Module):
+ """
+ A ResNet class that is similar to torchvision's but contains the following changes:
+ - There are now 3 "stem" convolutions as opposed to 1, with an average pool instead of a max pool.
+ - Performs anti-aliasing strided convolutions, where an avgpool is prepended to convolutions with stride > 1
+ - The final pooling layer is a QKV attention instead of an average pool
+ """
+
+ def __init__(self, layers, output_dim, heads, input_resolution=224, width=64):
+ super().__init__()
+ self.output_dim = output_dim
+ self.input_resolution = input_resolution
+
+ # the 3-layer stem
+ self.conv1 = nn.Conv2d(3, width // 2, kernel_size=3, stride=2, padding=1, bias=False)
+ self.bn1 = nn.BatchNorm2d(width // 2)
+ self.relu1 = nn.ReLU(inplace=True)
+ self.conv2 = nn.Conv2d(width // 2, width // 2, kernel_size=3, padding=1, bias=False)
+ self.bn2 = nn.BatchNorm2d(width // 2)
+ self.relu2 = nn.ReLU(inplace=True)
+ self.conv3 = nn.Conv2d(width // 2, width, kernel_size=3, padding=1, bias=False)
+ self.bn3 = nn.BatchNorm2d(width)
+ self.relu3 = nn.ReLU(inplace=True)
+ self.avgpool = nn.AvgPool2d(2)
+
+ # residual layers
+ self._inplanes = width # this is a *mutable* variable used during construction
+ self.layer1 = self._make_layer(width, layers[0])
+ self.layer2 = self._make_layer(width * 2, layers[1], stride=2)
+ self.layer3 = self._make_layer(width * 4, layers[2], stride=2)
+ self.layer4 = self._make_layer(width * 8, layers[3], stride=2)
+
+ embed_dim = width * 32 # the ResNet feature dimension
+ self.attnpool = AttentionPool2d(input_resolution // 32, embed_dim, heads, output_dim)
+
+ def _make_layer(self, planes, blocks, stride=1):
+ layers = [Bottleneck(self._inplanes, planes, stride)]
+
+ self._inplanes = planes * Bottleneck.expansion
+ for _ in range(1, blocks):
+ layers.append(Bottleneck(self._inplanes, planes))
+
+ return nn.Sequential(*layers)
+
+ def forward(self, x):
+ def stem(x):
+ x = self.relu1(self.bn1(self.conv1(x)))
+ x = self.relu2(self.bn2(self.conv2(x)))
+ x = self.relu3(self.bn3(self.conv3(x)))
+ x = self.avgpool(x)
+ return x
+
+ x = x.type(self.conv1.weight.dtype)
+ x = stem(x)
+ x = self.layer1(x)
+ x = self.layer2(x)
+ x = self.layer3(x)
+ x = self.layer4(x)
+ x = self.attnpool(x)
+
+ return x
+
+
+class LayerNorm(nn.LayerNorm):
+ """Subclass torch's LayerNorm to handle fp16."""
+
+ def forward(self, x: torch.Tensor):
+ orig_type = x.dtype
+ ret = super().forward(x.type(torch.float32))
+ return ret.type(orig_type)
+
+
+class QuickGELU(nn.Module):
+ def forward(self, x: torch.Tensor):
+ return x * torch.sigmoid(1.702 * x)
+
+
+class ResidualAttentionBlock(nn.Module):
+ def __init__(self, d_model: int, n_head: int, attn_mask: torch.Tensor = None):
+ super().__init__()
+
+ self.attn = nn.MultiheadAttention(d_model, n_head)
+ self.ln_1 = LayerNorm(d_model)
+ self.mlp = nn.Sequential(OrderedDict([
+ ("c_fc", nn.Linear(d_model, d_model * 4)),
+ ("gelu", QuickGELU()),
+ ("c_proj", nn.Linear(d_model * 4, d_model))
+ ]))
+ self.ln_2 = LayerNorm(d_model)
+ self.attn_mask = attn_mask
+
+ def attention(self, x: torch.Tensor):
+ self.attn_mask = self.attn_mask.to(dtype=x.dtype, device=x.device) if self.attn_mask is not None else None
+ return self.attn(x, x, x, need_weights=False, attn_mask=self.attn_mask)[0]
+
+ def forward(self, x: torch.Tensor):
+ x = x + self.attention(self.ln_1(x))
+ x = x + self.mlp(self.ln_2(x))
+ return x
+
+
+class Transformer(nn.Module):
+ def __init__(self, width: int, layers: int, heads: int, attn_mask: torch.Tensor = None):
+ super().__init__()
+ self.width = width
+ self.layers = layers
+ self.resblocks = nn.Sequential(*[ResidualAttentionBlock(width, heads, attn_mask) for _ in range(layers)])
+
+ def forward(self, x: torch.Tensor):
+ out = {}
+ for idx, layer in enumerate(self.resblocks.children()):
+ x = layer(x)
+ out['layer'+str(idx)] = x[0] # shape:LND. choose cls token feature
+ return out, x
+
+ # return self.resblocks(x) # This is the original code
+
+
+class VisionTransformer(nn.Module):
+ def __init__(self, input_resolution: int, patch_size: int, width: int, layers: int, heads: int, output_dim: int):
+ super().__init__()
+ self.input_resolution = input_resolution
+ self.output_dim = output_dim
+ self.conv1 = nn.Conv2d(in_channels=3, out_channels=width, kernel_size=patch_size, stride=patch_size, bias=False)
+
+ scale = width ** -0.5
+ self.class_embedding = nn.Parameter(scale * torch.randn(width))
+ self.positional_embedding = nn.Parameter(scale * torch.randn((input_resolution // patch_size) ** 2 + 1, width))
+ self.ln_pre = LayerNorm(width)
+
+ self.transformer = Transformer(width, layers, heads)
+
+ self.ln_post = LayerNorm(width)
+ self.proj = nn.Parameter(scale * torch.randn(width, output_dim))
+
+
+
+ def forward(self, x: torch.Tensor):
+ x = self.conv1(x) # shape = [*, width, grid, grid]
+ x = x.reshape(x.shape[0], x.shape[1], -1) # shape = [*, width, grid ** 2]
+ x = x.permute(0, 2, 1) # shape = [*, grid ** 2, width]
+ x = torch.cat([self.class_embedding.to(x.dtype) + torch.zeros(x.shape[0], 1, x.shape[-1], dtype=x.dtype, device=x.device), x], dim=1) # shape = [*, grid ** 2 + 1, width]
+ x = x + self.positional_embedding.to(x.dtype)
+ x = self.ln_pre(x)
+
+ x = x.permute(1, 0, 2) # NLD -> LND
+ out, x = self.transformer(x)
+ x = x.permute(1, 0, 2) # LND -> NLD
+
+ x = self.ln_post(x[:, 0, :])
+
+
+ out['before_projection'] = x
+
+ if self.proj is not None:
+ x = x @ self.proj
+ out['after_projection'] = x
+
+ # Return both intermediate features and final clip feature
+ # return out
+
+ # This only returns CLIP features
+ return x
+
+
+class CLIP(nn.Module):
+ def __init__(self,
+ embed_dim: int,
+ # vision
+ image_resolution: int,
+ vision_layers: Union[Tuple[int, int, int, int], int],
+ vision_width: int,
+ vision_patch_size: int,
+ # text
+ context_length: int,
+ vocab_size: int,
+ transformer_width: int,
+ transformer_heads: int,
+ transformer_layers: int
+ ):
+ super().__init__()
+
+ self.context_length = context_length
+
+ if isinstance(vision_layers, (tuple, list)):
+ vision_heads = vision_width * 32 // 64
+ self.visual = ModifiedResNet(
+ layers=vision_layers,
+ output_dim=embed_dim,
+ heads=vision_heads,
+ input_resolution=image_resolution,
+ width=vision_width
+ )
+ else:
+ vision_heads = vision_width // 64
+ self.visual = VisionTransformer(
+ input_resolution=image_resolution,
+ patch_size=vision_patch_size,
+ width=vision_width,
+ layers=vision_layers,
+ heads=vision_heads,
+ output_dim=embed_dim
+ )
+
+ self.transformer = Transformer(
+ width=transformer_width,
+ layers=transformer_layers,
+ heads=transformer_heads,
+ attn_mask=self.build_attention_mask()
+ )
+
+ self.vocab_size = vocab_size
+ self.token_embedding = nn.Embedding(vocab_size, transformer_width)
+ self.positional_embedding = nn.Parameter(torch.empty(self.context_length, transformer_width))
+ self.ln_final = LayerNorm(transformer_width)
+
+ self.text_projection = nn.Parameter(torch.empty(transformer_width, embed_dim))
+ self.logit_scale = nn.Parameter(torch.ones([]) * np.log(1 / 0.07))
+
+ self.initialize_parameters()
+
+ def initialize_parameters(self):
+ nn.init.normal_(self.token_embedding.weight, std=0.02)
+ nn.init.normal_(self.positional_embedding, std=0.01)
+
+ if isinstance(self.visual, ModifiedResNet):
+ if self.visual.attnpool is not None:
+ std = self.visual.attnpool.c_proj.in_features ** -0.5
+ nn.init.normal_(self.visual.attnpool.q_proj.weight, std=std)
+ nn.init.normal_(self.visual.attnpool.k_proj.weight, std=std)
+ nn.init.normal_(self.visual.attnpool.v_proj.weight, std=std)
+ nn.init.normal_(self.visual.attnpool.c_proj.weight, std=std)
+
+ for resnet_block in [self.visual.layer1, self.visual.layer2, self.visual.layer3, self.visual.layer4]:
+ for name, param in resnet_block.named_parameters():
+ if name.endswith("bn3.weight"):
+ nn.init.zeros_(param)
+
+ proj_std = (self.transformer.width ** -0.5) * ((2 * self.transformer.layers) ** -0.5)
+ attn_std = self.transformer.width ** -0.5
+ fc_std = (2 * self.transformer.width) ** -0.5
+ for block in self.transformer.resblocks:
+ nn.init.normal_(block.attn.in_proj_weight, std=attn_std)
+ nn.init.normal_(block.attn.out_proj.weight, std=proj_std)
+ nn.init.normal_(block.mlp.c_fc.weight, std=fc_std)
+ nn.init.normal_(block.mlp.c_proj.weight, std=proj_std)
+
+ if self.text_projection is not None:
+ nn.init.normal_(self.text_projection, std=self.transformer.width ** -0.5)
+
+ def build_attention_mask(self):
+ # lazily create causal attention mask, with full attention between the vision tokens
+ # pytorch uses additive attention mask; fill with -inf
+ mask = torch.empty(self.context_length, self.context_length)
+ mask.fill_(float("-inf"))
+ mask.triu_(1) # zero out the lower diagonal
+ return mask
+
+ @property
+ def dtype(self):
+ return self.visual.conv1.weight.dtype
+
+ def encode_image(self, image):
+ return self.visual(image.type(self.dtype))
+
+ def encode_text(self, text):
+ x = self.token_embedding(text).type(self.dtype) # [batch_size, n_ctx, d_model]
+
+ x = x + self.positional_embedding.type(self.dtype)
+ x = x.permute(1, 0, 2) # NLD -> LND
+ x = self.transformer(x)
+ x = x.permute(1, 0, 2) # LND -> NLD
+ x = self.ln_final(x).type(self.dtype)
+
+ # x.shape = [batch_size, n_ctx, transformer.width]
+ # take features from the eot embedding (eot_token is the highest number in each sequence)
+ x = x[torch.arange(x.shape[0]), text.argmax(dim=-1)] @ self.text_projection
+
+ return x
+
+ def forward(self, image, text):
+ image_features = self.encode_image(image)
+ text_features = self.encode_text(text)
+
+ # normalized features
+ image_features = image_features / image_features.norm(dim=1, keepdim=True)
+ text_features = text_features / text_features.norm(dim=1, keepdim=True)
+
+ # cosine similarity as logits
+ logit_scale = self.logit_scale.exp()
+ logits_per_image = logit_scale * image_features @ text_features.t()
+ logits_per_text = logits_per_image.t()
+
+ # shape = [global_batch_size, global_batch_size]
+ return logits_per_image, logits_per_text
+
+
+def convert_weights(model: nn.Module):
+ """Convert applicable model parameters to fp16"""
+
+ def _convert_weights_to_fp16(l):
+ if isinstance(l, (nn.Conv1d, nn.Conv2d, nn.Linear)):
+ l.weight.data = l.weight.data.half()
+ if l.bias is not None:
+ l.bias.data = l.bias.data.half()
+
+ if isinstance(l, nn.MultiheadAttention):
+ for attr in [*[f"{s}_proj_weight" for s in ["in", "q", "k", "v"]], "in_proj_bias", "bias_k", "bias_v"]:
+ tensor = getattr(l, attr)
+ if tensor is not None:
+ tensor.data = tensor.data.half()
+
+ for name in ["text_projection", "proj"]:
+ if hasattr(l, name):
+ attr = getattr(l, name)
+ if attr is not None:
+ attr.data = attr.data.half()
+
+ model.apply(_convert_weights_to_fp16)
+
+
+def build_model(state_dict: dict):
+ vit = "visual.proj" in state_dict
+
+ if vit:
+ vision_width = state_dict["visual.conv1.weight"].shape[0]
+ vision_layers = len([k for k in state_dict.keys() if k.startswith("visual.") and k.endswith(".attn.in_proj_weight")])
+ vision_patch_size = state_dict["visual.conv1.weight"].shape[-1]
+ grid_size = round((state_dict["visual.positional_embedding"].shape[0] - 1) ** 0.5)
+ image_resolution = vision_patch_size * grid_size
+ else:
+ counts: list = [len(set(k.split(".")[2] for k in state_dict if k.startswith(f"visual.layer{b}"))) for b in [1, 2, 3, 4]]
+ vision_layers = tuple(counts)
+ vision_width = state_dict["visual.layer1.0.conv1.weight"].shape[0]
+ output_width = round((state_dict["visual.attnpool.positional_embedding"].shape[0] - 1) ** 0.5)
+ vision_patch_size = None
+ assert output_width ** 2 + 1 == state_dict["visual.attnpool.positional_embedding"].shape[0]
+ image_resolution = output_width * 32
+
+ embed_dim = state_dict["text_projection"].shape[1]
+ context_length = state_dict["positional_embedding"].shape[0]
+ vocab_size = state_dict["token_embedding.weight"].shape[0]
+ transformer_width = state_dict["ln_final.weight"].shape[0]
+ transformer_heads = transformer_width // 64
+ transformer_layers = len(set(k.split(".")[2] for k in state_dict if k.startswith("transformer.resblocks")))
+
+ model = CLIP(
+ embed_dim,
+ image_resolution, vision_layers, vision_width, vision_patch_size,
+ context_length, vocab_size, transformer_width, transformer_heads, transformer_layers
+ )
+
+ for key in ["input_resolution", "context_length", "vocab_size"]:
+ if key in state_dict:
+ del state_dict[key]
+
+ convert_weights(model)
+ model.load_state_dict(state_dict)
+ return model.eval()
diff --git a/clean/image/universal/models/clip/simple_tokenizer.py b/clean/image/universal/models/clip/simple_tokenizer.py
new file mode 100644
index 0000000000000000000000000000000000000000..0a66286b7d5019c6e221932a813768038f839c91
--- /dev/null
+++ b/clean/image/universal/models/clip/simple_tokenizer.py
@@ -0,0 +1,132 @@
+import gzip
+import html
+import os
+from functools import lru_cache
+
+import ftfy
+import regex as re
+
+
+@lru_cache()
+def default_bpe():
+ return os.path.join(os.path.dirname(os.path.abspath(__file__)), "bpe_simple_vocab_16e6.txt.gz")
+
+
+@lru_cache()
+def bytes_to_unicode():
+ """
+ Returns list of utf-8 byte and a corresponding list of unicode strings.
+ The reversible bpe codes work on unicode strings.
+ This means you need a large # of unicode characters in your vocab if you want to avoid UNKs.
+ When you're at something like a 10B token dataset you end up needing around 5K for decent coverage.
+ This is a signficant percentage of your normal, say, 32K bpe vocab.
+ To avoid that, we want lookup tables between utf-8 bytes and unicode strings.
+ And avoids mapping to whitespace/control characters the bpe code barfs on.
+ """
+ bs = list(range(ord("!"), ord("~")+1))+list(range(ord("¡"), ord("¬")+1))+list(range(ord("®"), ord("ÿ")+1))
+ cs = bs[:]
+ n = 0
+ for b in range(2**8):
+ if b not in bs:
+ bs.append(b)
+ cs.append(2**8+n)
+ n += 1
+ cs = [chr(n) for n in cs]
+ return dict(zip(bs, cs))
+
+
+def get_pairs(word):
+ """Return set of symbol pairs in a word.
+ Word is represented as tuple of symbols (symbols being variable-length strings).
+ """
+ pairs = set()
+ prev_char = word[0]
+ for char in word[1:]:
+ pairs.add((prev_char, char))
+ prev_char = char
+ return pairs
+
+
+def basic_clean(text):
+ text = ftfy.fix_text(text)
+ text = html.unescape(html.unescape(text))
+ return text.strip()
+
+
+def whitespace_clean(text):
+ text = re.sub(r'\s+', ' ', text)
+ text = text.strip()
+ return text
+
+
+class SimpleTokenizer(object):
+ def __init__(self, bpe_path: str = default_bpe()):
+ self.byte_encoder = bytes_to_unicode()
+ self.byte_decoder = {v: k for k, v in self.byte_encoder.items()}
+ merges = gzip.open(bpe_path).read().decode("utf-8").split('\n')
+ merges = merges[1:49152-256-2+1]
+ merges = [tuple(merge.split()) for merge in merges]
+ vocab = list(bytes_to_unicode().values())
+ vocab = vocab + [v+'' for v in vocab]
+ for merge in merges:
+ vocab.append(''.join(merge))
+ vocab.extend(['<|startoftext|>', '<|endoftext|>'])
+ self.encoder = dict(zip(vocab, range(len(vocab))))
+ self.decoder = {v: k for k, v in self.encoder.items()}
+ self.bpe_ranks = dict(zip(merges, range(len(merges))))
+ self.cache = {'<|startoftext|>': '<|startoftext|>', '<|endoftext|>': '<|endoftext|>'}
+ self.pat = re.compile(r"""<\|startoftext\|>|<\|endoftext\|>|'s|'t|'re|'ve|'m|'ll|'d|[\p{L}]+|[\p{N}]|[^\s\p{L}\p{N}]+""", re.IGNORECASE)
+
+ def bpe(self, token):
+ if token in self.cache:
+ return self.cache[token]
+ word = tuple(token[:-1]) + ( token[-1] + '',)
+ pairs = get_pairs(word)
+
+ if not pairs:
+ return token+''
+
+ while True:
+ bigram = min(pairs, key = lambda pair: self.bpe_ranks.get(pair, float('inf')))
+ if bigram not in self.bpe_ranks:
+ break
+ first, second = bigram
+ new_word = []
+ i = 0
+ while i < len(word):
+ try:
+ j = word.index(first, i)
+ new_word.extend(word[i:j])
+ i = j
+ except:
+ new_word.extend(word[i:])
+ break
+
+ if word[i] == first and i < len(word)-1 and word[i+1] == second:
+ new_word.append(first+second)
+ i += 2
+ else:
+ new_word.append(word[i])
+ i += 1
+ new_word = tuple(new_word)
+ word = new_word
+ if len(word) == 1:
+ break
+ else:
+ pairs = get_pairs(word)
+ word = ' '.join(word)
+ self.cache[token] = word
+ return word
+
+ def encode(self, text):
+ bpe_tokens = []
+ text = whitespace_clean(basic_clean(text)).lower()
+ for token in re.findall(self.pat, text):
+ token = ''.join(self.byte_encoder[b] for b in token.encode('utf-8'))
+ bpe_tokens.extend(self.encoder[bpe_token] for bpe_token in self.bpe(token).split(' '))
+ return bpe_tokens
+
+ def decode(self, tokens):
+ text = ''.join([self.decoder[token] for token in tokens])
+ text = bytearray([self.byte_decoder[c] for c in text]).decode('utf-8', errors="replace").replace('', ' ')
+ return text
diff --git a/clean/image/universal/models/clip_models.py b/clean/image/universal/models/clip_models.py
new file mode 100644
index 0000000000000000000000000000000000000000..44de4db8ee4dd77690970fc76eb671b1b3a43882
--- /dev/null
+++ b/clean/image/universal/models/clip_models.py
@@ -0,0 +1,24 @@
+from .clip import clip
+from PIL import Image
+import torch.nn as nn
+
+
+CHANNELS = {
+ "RN50" : 1024,
+ "ViT-L/14" : 768
+}
+
+class CLIPModel(nn.Module):
+ def __init__(self, name, num_classes=1):
+ super(CLIPModel, self).__init__()
+
+ self.model, self.preprocess = clip.load(name, device="cpu") # self.preprecess will not be used during training, which is handled in Dataset class
+ self.fc = nn.Linear( CHANNELS[name], num_classes )
+
+
+ def forward(self, x, return_feature=False):
+ features = self.model.encode_image(x)
+ if return_feature:
+ return features
+ return self.fc(features)
+
diff --git a/clean/image/universal/models/imagenet_models.py b/clean/image/universal/models/imagenet_models.py
new file mode 100644
index 0000000000000000000000000000000000000000..20a40b916793d926c915aa2f62602651613fec04
--- /dev/null
+++ b/clean/image/universal/models/imagenet_models.py
@@ -0,0 +1,40 @@
+from .resnet import resnet18, resnet34, resnet50, resnet101, resnet152
+from .vision_transformer import vit_b_16, vit_b_32, vit_l_16, vit_l_32
+
+from torchvision import transforms
+from PIL import Image
+import torch
+import torch.nn as nn
+
+
+model_dict = {
+ 'resnet18': resnet18,
+ 'resnet34': resnet34,
+ 'resnet50': resnet50,
+ 'resnet101': resnet101,
+ 'resnet152': resnet152,
+ 'vit_b_16': vit_b_16,
+ 'vit_b_32': vit_b_32,
+ 'vit_l_16': vit_l_16,
+ 'vit_l_32': vit_l_32
+}
+
+
+CHANNELS = {
+ "resnet50" : 2048,
+ "vit_b_16" : 768,
+}
+
+
+
+class ImagenetModel(nn.Module):
+ def __init__(self, name, num_classes=1):
+ super(ImagenetModel, self).__init__()
+
+ self.model = model_dict[name](pretrained=True)
+ self.fc = nn.Linear(CHANNELS[name], num_classes) #manually define a fc layer here
+
+
+ def forward(self, x):
+ feature = self.model(x)["penultimate"]
+ return self.fc(feature)
diff --git a/clean/image/universal/models/resnet.py b/clean/image/universal/models/resnet.py
new file mode 100644
index 0000000000000000000000000000000000000000..a78e3d65e263cb9dbd1afa0e1a88dba9f5ddd164
--- /dev/null
+++ b/clean/image/universal/models/resnet.py
@@ -0,0 +1,337 @@
+import torch
+from torch import Tensor
+import torch.nn as nn
+from typing import Type, Any, Callable, Union, List, Optional
+
+try:
+ from torch.hub import load_state_dict_from_url
+except ImportError:
+ from torch.utils.model_zoo import load_url as load_state_dict_from_url
+
+
+model_urls = {
+ 'resnet18': 'https://download.pytorch.org/models/resnet18-f37072fd.pth',
+ 'resnet34': 'https://download.pytorch.org/models/resnet34-b627a593.pth',
+ 'resnet50': 'https://download.pytorch.org/models/resnet50-0676ba61.pth',
+ 'resnet101': 'https://download.pytorch.org/models/resnet101-63fe2227.pth',
+ 'resnet152': 'https://download.pytorch.org/models/resnet152-394f9c45.pth',
+ 'resnext50_32x4d': 'https://download.pytorch.org/models/resnext50_32x4d-7cdf4587.pth',
+ 'resnext101_32x8d': 'https://download.pytorch.org/models/resnext101_32x8d-8ba56ff5.pth',
+ 'wide_resnet50_2': 'https://download.pytorch.org/models/wide_resnet50_2-95faca4d.pth',
+ 'wide_resnet101_2': 'https://download.pytorch.org/models/wide_resnet101_2-32ee1156.pth',
+}
+
+
+
+
+def conv3x3(in_planes: int, out_planes: int, stride: int = 1, groups: int = 1, dilation: int = 1) -> nn.Conv2d:
+ """3x3 convolution with padding"""
+ return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,
+ padding=dilation, groups=groups, bias=False, dilation=dilation)
+
+
+def conv1x1(in_planes: int, out_planes: int, stride: int = 1) -> nn.Conv2d:
+ """1x1 convolution"""
+ return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False)
+
+
+class BasicBlock(nn.Module):
+ expansion: int = 1
+
+ def __init__(
+ self,
+ inplanes: int,
+ planes: int,
+ stride: int = 1,
+ downsample: Optional[nn.Module] = None,
+ groups: int = 1,
+ base_width: int = 64,
+ dilation: int = 1,
+ norm_layer: Optional[Callable[..., nn.Module]] = None
+ ) -> None:
+ super(BasicBlock, self).__init__()
+ if norm_layer is None:
+ norm_layer = nn.BatchNorm2d
+ if groups != 1 or base_width != 64:
+ raise ValueError('BasicBlock only supports groups=1 and base_width=64')
+ if dilation > 1:
+ raise NotImplementedError("Dilation > 1 not supported in BasicBlock")
+ # Both self.conv1 and self.downsample layers downsample the input when stride != 1
+ self.conv1 = conv3x3(inplanes, planes, stride)
+ self.bn1 = norm_layer(planes)
+ self.relu = nn.ReLU(inplace=True)
+ self.conv2 = conv3x3(planes, planes)
+ self.bn2 = norm_layer(planes)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x: Tensor) -> Tensor:
+ identity = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+
+ if self.downsample is not None:
+ identity = self.downsample(x)
+
+ out += identity
+ out = self.relu(out)
+
+ return out
+
+
+class Bottleneck(nn.Module):
+ # Bottleneck in torchvision places the stride for downsampling at 3x3 convolution(self.conv2)
+ # while original implementation places the stride at the first 1x1 convolution(self.conv1)
+ # according to "Deep residual learning for image recognition"https://arxiv.org/abs/1512.03385.
+ # This variant is also known as ResNet V1.5 and improves accuracy according to
+ # https://ngc.nvidia.com/catalog/model-scripts/nvidia:resnet_50_v1_5_for_pytorch.
+
+ expansion: int = 4
+
+ def __init__(
+ self,
+ inplanes: int,
+ planes: int,
+ stride: int = 1,
+ downsample: Optional[nn.Module] = None,
+ groups: int = 1,
+ base_width: int = 64,
+ dilation: int = 1,
+ norm_layer: Optional[Callable[..., nn.Module]] = None
+ ) -> None:
+ super(Bottleneck, self).__init__()
+ if norm_layer is None:
+ norm_layer = nn.BatchNorm2d
+ width = int(planes * (base_width / 64.)) * groups
+ # Both self.conv2 and self.downsample layers downsample the input when stride != 1
+ self.conv1 = conv1x1(inplanes, width)
+ self.bn1 = norm_layer(width)
+ self.conv2 = conv3x3(width, width, stride, groups, dilation)
+ self.bn2 = norm_layer(width)
+ self.conv3 = conv1x1(width, planes * self.expansion)
+ self.bn3 = norm_layer(planes * self.expansion)
+ self.relu = nn.ReLU(inplace=True)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x: Tensor) -> Tensor:
+ identity = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+ out = self.relu(out)
+
+ out = self.conv3(out)
+ out = self.bn3(out)
+
+ if self.downsample is not None:
+ identity = self.downsample(x)
+
+ out += identity
+ out = self.relu(out)
+
+ return out
+
+
+class ResNet(nn.Module):
+
+ def __init__(
+ self,
+ block: Type[Union[BasicBlock, Bottleneck]],
+ layers: List[int],
+ num_classes: int = 1000,
+ zero_init_residual: bool = False,
+ groups: int = 1,
+ width_per_group: int = 64,
+ replace_stride_with_dilation: Optional[List[bool]] = None,
+ norm_layer: Optional[Callable[..., nn.Module]] = None
+ ) -> None:
+ super(ResNet, self).__init__()
+ if norm_layer is None:
+ norm_layer = nn.BatchNorm2d
+ self._norm_layer = norm_layer
+
+ self.inplanes = 64
+ self.dilation = 1
+ if replace_stride_with_dilation is None:
+ # each element in the tuple indicates if we should replace
+ # the 2x2 stride with a dilated convolution instead
+ replace_stride_with_dilation = [False, False, False]
+ if len(replace_stride_with_dilation) != 3:
+ raise ValueError("replace_stride_with_dilation should be None "
+ "or a 3-element tuple, got {}".format(replace_stride_with_dilation))
+ self.groups = groups
+ self.base_width = width_per_group
+ self.conv1 = nn.Conv2d(3, self.inplanes, kernel_size=7, stride=2, padding=3,
+ bias=False)
+ self.bn1 = norm_layer(self.inplanes)
+ self.relu = nn.ReLU(inplace=True)
+ self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
+ self.layer1 = self._make_layer(block, 64, layers[0])
+ self.layer2 = self._make_layer(block, 128, layers[1], stride=2,
+ dilate=replace_stride_with_dilation[0])
+ self.layer3 = self._make_layer(block, 256, layers[2], stride=2,
+ dilate=replace_stride_with_dilation[1])
+ self.layer4 = self._make_layer(block, 512, layers[3], stride=2,
+ dilate=replace_stride_with_dilation[2])
+ self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
+ self.fc = nn.Linear(512 * block.expansion, num_classes)
+
+ for m in self.modules():
+ if isinstance(m, nn.Conv2d):
+ nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
+ elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
+ nn.init.constant_(m.weight, 1)
+ nn.init.constant_(m.bias, 0)
+
+ # Zero-initialize the last BN in each residual branch,
+ # so that the residual branch starts with zeros, and each residual block behaves like an identity.
+ # This improves the model by 0.2~0.3% according to https://arxiv.org/abs/1706.02677
+ if zero_init_residual:
+ for m in self.modules():
+ if isinstance(m, Bottleneck):
+ nn.init.constant_(m.bn3.weight, 0) # type: ignore[arg-type]
+ elif isinstance(m, BasicBlock):
+ nn.init.constant_(m.bn2.weight, 0) # type: ignore[arg-type]
+
+ def _make_layer(self, block: Type[Union[BasicBlock, Bottleneck]], planes: int, blocks: int,
+ stride: int = 1, dilate: bool = False) -> nn.Sequential:
+ norm_layer = self._norm_layer
+ downsample = None
+ previous_dilation = self.dilation
+ if dilate:
+ self.dilation *= stride
+ stride = 1
+ if stride != 1 or self.inplanes != planes * block.expansion:
+ downsample = nn.Sequential(
+ conv1x1(self.inplanes, planes * block.expansion, stride),
+ norm_layer(planes * block.expansion),
+ )
+
+ layers = []
+ layers.append(block(self.inplanes, planes, stride, downsample, self.groups,
+ self.base_width, previous_dilation, norm_layer))
+ self.inplanes = planes * block.expansion
+ for _ in range(1, blocks):
+ layers.append(block(self.inplanes, planes, groups=self.groups,
+ base_width=self.base_width, dilation=self.dilation,
+ norm_layer=norm_layer))
+
+ return nn.Sequential(*layers)
+
+ def _forward_impl(self, x):
+ # The comment resolution is based on input size is 224*224 imagenet
+ out = {}
+ x = self.conv1(x)
+ x = self.bn1(x)
+ x = self.relu(x)
+ x = self.maxpool(x)
+ out['f0'] = x # N*64*56*56
+
+ x = self.layer1(x)
+ out['f1'] = x # N*64*56*56
+
+ x = self.layer2(x)
+ out['f2'] = x # N*128*28*28
+
+ x = self.layer3(x)
+ out['f3'] = x # N*256*14*14
+
+ x = self.layer4(x)
+ out['f4'] = x # N*512*7*7
+
+ x = self.avgpool(x)
+ x = torch.flatten(x, 1)
+ out['penultimate'] = x # N*512
+
+ x = self.fc(x)
+ out['logits'] = x # N*1000
+
+ # return all features
+ return out
+
+ # return final classification result
+ # return x
+
+ def forward(self, x):
+ return self._forward_impl(x)
+
+
+def _resnet(
+ arch: str,
+ block: Type[Union[BasicBlock, Bottleneck]],
+ layers: List[int],
+ pretrained: bool,
+ progress: bool,
+ **kwargs: Any
+) -> ResNet:
+ model = ResNet(block, layers, **kwargs)
+ if pretrained:
+ state_dict = load_state_dict_from_url(model_urls[arch], progress=progress)
+ model.load_state_dict(state_dict)
+ return model
+
+
+def resnet18(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> ResNet:
+ r"""ResNet-18 model from
+ `"Deep Residual Learning for Image Recognition" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return _resnet('resnet18', BasicBlock, [2, 2, 2, 2], pretrained, progress, **kwargs)
+
+
+def resnet34(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> ResNet:
+ r"""ResNet-34 model from
+ `"Deep Residual Learning for Image Recognition" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return _resnet('resnet34', BasicBlock, [3, 4, 6, 3], pretrained, progress, **kwargs)
+
+
+def resnet50(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> ResNet:
+ r"""ResNet-50 model from
+ `"Deep Residual Learning for Image Recognition" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return _resnet('resnet50', Bottleneck, [3, 4, 6, 3], pretrained, progress, **kwargs)
+
+
+def resnet101(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> ResNet:
+ r"""ResNet-101 model from
+ `"Deep Residual Learning for Image Recognition" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return _resnet('resnet101', Bottleneck, [3, 4, 23, 3], pretrained, progress, **kwargs)
+
+
+def resnet152(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> ResNet:
+ r"""ResNet-152 model from
+ `"Deep Residual Learning for Image Recognition" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return _resnet('resnet152', Bottleneck, [3, 8, 36, 3], pretrained, progress, **kwargs)
+
diff --git a/clean/image/universal/models/vgg.py b/clean/image/universal/models/vgg.py
new file mode 100644
index 0000000000000000000000000000000000000000..a30a1df18a64f9ab2ca309b264cd4e8409b0cf64
--- /dev/null
+++ b/clean/image/universal/models/vgg.py
@@ -0,0 +1,120 @@
+import torch
+import torch.nn as nn
+from typing import Union, List, Dict, Any, cast
+import torchvision
+import torch.nn.functional as F
+
+
+
+
+
+class VGG(torch.nn.Module):
+ def __init__(self, arch_type, pretrained, progress):
+ super().__init__()
+
+ self.layer1 = torch.nn.Sequential()
+ self.layer2 = torch.nn.Sequential()
+ self.layer3 = torch.nn.Sequential()
+ self.layer4 = torch.nn.Sequential()
+ self.layer5 = torch.nn.Sequential()
+
+ if arch_type == 'vgg11':
+ official_vgg = torchvision.models.vgg11(pretrained=pretrained, progress=progress)
+ blocks = [ [0,2], [2,5], [5,10], [10,15], [15,20] ]
+ last_idx = 20
+ elif arch_type == 'vgg19':
+ official_vgg = torchvision.models.vgg19(pretrained=pretrained, progress=progress)
+ blocks = [ [0,4], [4,9], [9,18], [18,27], [27,36] ]
+ last_idx = 36
+ else:
+ raise NotImplementedError
+
+
+ for x in range( *blocks[0] ):
+ self.layer1.add_module(str(x), official_vgg.features[x])
+ for x in range( *blocks[1] ):
+ self.layer2.add_module(str(x), official_vgg.features[x])
+ for x in range( *blocks[2] ):
+ self.layer3.add_module(str(x), official_vgg.features[x])
+ for x in range( *blocks[3] ):
+ self.layer4.add_module(str(x), official_vgg.features[x])
+ for x in range( *blocks[4] ):
+ self.layer5.add_module(str(x), official_vgg.features[x])
+
+ self.max_pool = official_vgg.features[last_idx]
+ self.avgpool = nn.AdaptiveAvgPool2d((7, 7))
+
+ self.fc1 = official_vgg.classifier[0]
+ self.fc2 = official_vgg.classifier[3]
+ self.fc3 = official_vgg.classifier[6]
+ self.dropout = nn.Dropout()
+
+
+ def forward(self, x):
+ out = {}
+
+ x = self.layer1(x)
+ out['f0'] = x
+
+ x = self.layer2(x)
+ out['f1'] = x
+
+ x = self.layer3(x)
+ out['f2'] = x
+
+ x = self.layer4(x)
+ out['f3'] = x
+
+ x = self.layer5(x)
+ out['f4'] = x
+
+ x = self.max_pool(x)
+ x = self.avgpool(x)
+ x = x.view(-1,512*7*7)
+
+ x = self.fc1(x)
+ x = F.relu(x)
+ x = self.dropout(x)
+ x = self.fc2(x)
+ x = F.relu(x)
+ out['penultimate'] = x
+ x = self.dropout(x)
+ x = self.fc3(x)
+ out['logits'] = x
+
+ return out
+
+
+
+
+
+
+
+
+
+
+def vgg11(pretrained=False, progress=True):
+ r"""VGG 11-layer model (configuration "A") from
+ `"Very Deep Convolutional Networks For Large-Scale Image Recognition" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return VGG('vgg11', pretrained, progress)
+
+
+
+def vgg19(pretrained=False, progress=True):
+ r"""VGG 19-layer model (configuration "E")
+ `"Very Deep Convolutional Networks For Large-Scale Image Recognition" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return VGG('vgg19', pretrained, progress)
+
+
+
+
diff --git a/clean/image/universal/models/vision_transformer.py b/clean/image/universal/models/vision_transformer.py
new file mode 100644
index 0000000000000000000000000000000000000000..618e9626ca43f1afdb3419e19be11f3a3048f81e
--- /dev/null
+++ b/clean/image/universal/models/vision_transformer.py
@@ -0,0 +1,481 @@
+import math
+from collections import OrderedDict
+from functools import partial
+from typing import Any, Callable, List, NamedTuple, Optional
+
+import torch
+import torch.nn as nn
+
+# from .._internally_replaced_utils import load_state_dict_from_url
+from .vision_transformer_misc import ConvNormActivation
+from .vision_transformer_utils import _log_api_usage_once
+
+try:
+ from torch.hub import load_state_dict_from_url
+except ImportError:
+ from torch.utils.model_zoo import load_url as load_state_dict_from_url
+
+# __all__ = [
+# "VisionTransformer",
+# "vit_b_16",
+# "vit_b_32",
+# "vit_l_16",
+# "vit_l_32",
+# ]
+
+model_urls = {
+ "vit_b_16": "https://download.pytorch.org/models/vit_b_16-c867db91.pth",
+ "vit_b_32": "https://download.pytorch.org/models/vit_b_32-d86f8d99.pth",
+ "vit_l_16": "https://download.pytorch.org/models/vit_l_16-852ce7e3.pth",
+ "vit_l_32": "https://download.pytorch.org/models/vit_l_32-c7638314.pth",
+}
+
+
+class ConvStemConfig(NamedTuple):
+ out_channels: int
+ kernel_size: int
+ stride: int
+ norm_layer: Callable[..., nn.Module] = nn.BatchNorm2d
+ activation_layer: Callable[..., nn.Module] = nn.ReLU
+
+
+class MLPBlock(nn.Sequential):
+ """Transformer MLP block."""
+
+ def __init__(self, in_dim: int, mlp_dim: int, dropout: float):
+ super().__init__()
+ self.linear_1 = nn.Linear(in_dim, mlp_dim)
+ self.act = nn.GELU()
+ self.dropout_1 = nn.Dropout(dropout)
+ self.linear_2 = nn.Linear(mlp_dim, in_dim)
+ self.dropout_2 = nn.Dropout(dropout)
+
+ nn.init.xavier_uniform_(self.linear_1.weight)
+ nn.init.xavier_uniform_(self.linear_2.weight)
+ nn.init.normal_(self.linear_1.bias, std=1e-6)
+ nn.init.normal_(self.linear_2.bias, std=1e-6)
+
+
+class EncoderBlock(nn.Module):
+ """Transformer encoder block."""
+
+ def __init__(
+ self,
+ num_heads: int,
+ hidden_dim: int,
+ mlp_dim: int,
+ dropout: float,
+ attention_dropout: float,
+ norm_layer: Callable[..., torch.nn.Module] = partial(nn.LayerNorm, eps=1e-6),
+ ):
+ super().__init__()
+ self.num_heads = num_heads
+
+ # Attention block
+ self.ln_1 = norm_layer(hidden_dim)
+ self.self_attention = nn.MultiheadAttention(hidden_dim, num_heads, dropout=attention_dropout, batch_first=True)
+ self.dropout = nn.Dropout(dropout)
+
+ # MLP block
+ self.ln_2 = norm_layer(hidden_dim)
+ self.mlp = MLPBlock(hidden_dim, mlp_dim, dropout)
+
+ def forward(self, input: torch.Tensor):
+ torch._assert(input.dim() == 3, f"Expected (seq_length, batch_size, hidden_dim) got {input.shape}")
+ x = self.ln_1(input)
+ x, _ = self.self_attention(query=x, key=x, value=x, need_weights=False)
+ x = self.dropout(x)
+ x = x + input
+
+ y = self.ln_2(x)
+ y = self.mlp(y)
+ return x + y
+
+
+class Encoder(nn.Module):
+ """Transformer Model Encoder for sequence to sequence translation."""
+
+ def __init__(
+ self,
+ seq_length: int,
+ num_layers: int,
+ num_heads: int,
+ hidden_dim: int,
+ mlp_dim: int,
+ dropout: float,
+ attention_dropout: float,
+ norm_layer: Callable[..., torch.nn.Module] = partial(nn.LayerNorm, eps=1e-6),
+ ):
+ super().__init__()
+ # Note that batch_size is on the first dim because
+ # we have batch_first=True in nn.MultiAttention() by default
+ self.pos_embedding = nn.Parameter(torch.empty(1, seq_length, hidden_dim).normal_(std=0.02)) # from BERT
+ self.dropout = nn.Dropout(dropout)
+ layers: OrderedDict[str, nn.Module] = OrderedDict()
+ for i in range(num_layers):
+ layers[f"encoder_layer_{i}"] = EncoderBlock(
+ num_heads,
+ hidden_dim,
+ mlp_dim,
+ dropout,
+ attention_dropout,
+ norm_layer,
+ )
+ self.layers = nn.Sequential(layers)
+ self.ln = norm_layer(hidden_dim)
+
+ def forward(self, input: torch.Tensor):
+ torch._assert(input.dim() == 3, f"Expected (batch_size, seq_length, hidden_dim) got {input.shape}")
+ input = input + self.pos_embedding
+ return self.ln(self.layers(self.dropout(input)))
+
+
+class VisionTransformer(nn.Module):
+ """Vision Transformer as per https://arxiv.org/abs/2010.11929."""
+
+ def __init__(
+ self,
+ image_size: int,
+ patch_size: int,
+ num_layers: int,
+ num_heads: int,
+ hidden_dim: int,
+ mlp_dim: int,
+ dropout: float = 0.0,
+ attention_dropout: float = 0.0,
+ num_classes: int = 1000,
+ representation_size: Optional[int] = None,
+ norm_layer: Callable[..., torch.nn.Module] = partial(nn.LayerNorm, eps=1e-6),
+ conv_stem_configs: Optional[List[ConvStemConfig]] = None,
+ ):
+ super().__init__()
+ _log_api_usage_once(self)
+ torch._assert(image_size % patch_size == 0, "Input shape indivisible by patch size!")
+ self.image_size = image_size
+ self.patch_size = patch_size
+ self.hidden_dim = hidden_dim
+ self.mlp_dim = mlp_dim
+ self.attention_dropout = attention_dropout
+ self.dropout = dropout
+ self.num_classes = num_classes
+ self.representation_size = representation_size
+ self.norm_layer = norm_layer
+
+ if conv_stem_configs is not None:
+ # As per https://arxiv.org/abs/2106.14881
+ seq_proj = nn.Sequential()
+ prev_channels = 3
+ for i, conv_stem_layer_config in enumerate(conv_stem_configs):
+ seq_proj.add_module(
+ f"conv_bn_relu_{i}",
+ ConvNormActivation(
+ in_channels=prev_channels,
+ out_channels=conv_stem_layer_config.out_channels,
+ kernel_size=conv_stem_layer_config.kernel_size,
+ stride=conv_stem_layer_config.stride,
+ norm_layer=conv_stem_layer_config.norm_layer,
+ activation_layer=conv_stem_layer_config.activation_layer,
+ ),
+ )
+ prev_channels = conv_stem_layer_config.out_channels
+ seq_proj.add_module(
+ "conv_last", nn.Conv2d(in_channels=prev_channels, out_channels=hidden_dim, kernel_size=1)
+ )
+ self.conv_proj: nn.Module = seq_proj
+ else:
+ self.conv_proj = nn.Conv2d(
+ in_channels=3, out_channels=hidden_dim, kernel_size=patch_size, stride=patch_size
+ )
+
+ seq_length = (image_size // patch_size) ** 2
+
+ # Add a class token
+ self.class_token = nn.Parameter(torch.zeros(1, 1, hidden_dim))
+ seq_length += 1
+
+ self.encoder = Encoder(
+ seq_length,
+ num_layers,
+ num_heads,
+ hidden_dim,
+ mlp_dim,
+ dropout,
+ attention_dropout,
+ norm_layer,
+ )
+ self.seq_length = seq_length
+
+ heads_layers: OrderedDict[str, nn.Module] = OrderedDict()
+ if representation_size is None:
+ heads_layers["head"] = nn.Linear(hidden_dim, num_classes)
+ else:
+ heads_layers["pre_logits"] = nn.Linear(hidden_dim, representation_size)
+ heads_layers["act"] = nn.Tanh()
+ heads_layers["head"] = nn.Linear(representation_size, num_classes)
+
+ self.heads = nn.Sequential(heads_layers)
+
+ if isinstance(self.conv_proj, nn.Conv2d):
+ # Init the patchify stem
+ fan_in = self.conv_proj.in_channels * self.conv_proj.kernel_size[0] * self.conv_proj.kernel_size[1]
+ nn.init.trunc_normal_(self.conv_proj.weight, std=math.sqrt(1 / fan_in))
+ if self.conv_proj.bias is not None:
+ nn.init.zeros_(self.conv_proj.bias)
+ elif self.conv_proj.conv_last is not None and isinstance(self.conv_proj.conv_last, nn.Conv2d):
+ # Init the last 1x1 conv of the conv stem
+ nn.init.normal_(
+ self.conv_proj.conv_last.weight, mean=0.0, std=math.sqrt(2.0 / self.conv_proj.conv_last.out_channels)
+ )
+ if self.conv_proj.conv_last.bias is not None:
+ nn.init.zeros_(self.conv_proj.conv_last.bias)
+
+ if hasattr(self.heads, "pre_logits") and isinstance(self.heads.pre_logits, nn.Linear):
+ fan_in = self.heads.pre_logits.in_features
+ nn.init.trunc_normal_(self.heads.pre_logits.weight, std=math.sqrt(1 / fan_in))
+ nn.init.zeros_(self.heads.pre_logits.bias)
+
+ if isinstance(self.heads.head, nn.Linear):
+ nn.init.zeros_(self.heads.head.weight)
+ nn.init.zeros_(self.heads.head.bias)
+
+ def _process_input(self, x: torch.Tensor) -> torch.Tensor:
+ n, c, h, w = x.shape
+ p = self.patch_size
+ torch._assert(h == self.image_size, "Wrong image height!")
+ torch._assert(w == self.image_size, "Wrong image width!")
+ n_h = h // p
+ n_w = w // p
+
+ # (n, c, h, w) -> (n, hidden_dim, n_h, n_w)
+ x = self.conv_proj(x)
+ # (n, hidden_dim, n_h, n_w) -> (n, hidden_dim, (n_h * n_w))
+ x = x.reshape(n, self.hidden_dim, n_h * n_w)
+
+ # (n, hidden_dim, (n_h * n_w)) -> (n, (n_h * n_w), hidden_dim)
+ # The self attention layer expects inputs in the format (N, S, E)
+ # where S is the source sequence length, N is the batch size, E is the
+ # embedding dimension
+ x = x.permute(0, 2, 1)
+
+ return x
+
+ def forward(self, x: torch.Tensor):
+ out = {}
+
+ # Reshape and permute the input tensor
+ x = self._process_input(x)
+ n = x.shape[0]
+
+ # Expand the class token to the full batch
+ batch_class_token = self.class_token.expand(n, -1, -1)
+ x = torch.cat([batch_class_token, x], dim=1)
+
+
+ x = self.encoder(x)
+ img_feature = x[:,1:]
+ H = W = int(self.image_size / self.patch_size)
+ out['f4'] = img_feature.view(n, H, W, self.hidden_dim).permute(0,3,1,2)
+
+ # Classifier "token" as used by standard language architectures
+ x = x[:, 0]
+ out['penultimate'] = x
+
+ x = self.heads(x) # I checked that for all pretrained ViT, this is just a fc
+ out['logits'] = x
+
+ return out
+
+
+def _vision_transformer(
+ arch: str,
+ patch_size: int,
+ num_layers: int,
+ num_heads: int,
+ hidden_dim: int,
+ mlp_dim: int,
+ pretrained: bool,
+ progress: bool,
+ **kwargs: Any,
+) -> VisionTransformer:
+ image_size = kwargs.pop("image_size", 224)
+
+ model = VisionTransformer(
+ image_size=image_size,
+ patch_size=patch_size,
+ num_layers=num_layers,
+ num_heads=num_heads,
+ hidden_dim=hidden_dim,
+ mlp_dim=mlp_dim,
+ **kwargs,
+ )
+
+ if pretrained:
+ if arch not in model_urls:
+ raise ValueError(f"No checkpoint is available for model type '{arch}'!")
+ state_dict = load_state_dict_from_url(model_urls[arch], progress=progress)
+ model.load_state_dict(state_dict)
+
+ return model
+
+
+def vit_b_16(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> VisionTransformer:
+ """
+ Constructs a vit_b_16 architecture from
+ `"An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return _vision_transformer(
+ arch="vit_b_16",
+ patch_size=16,
+ num_layers=12,
+ num_heads=12,
+ hidden_dim=768,
+ mlp_dim=3072,
+ pretrained=pretrained,
+ progress=progress,
+ **kwargs,
+ )
+
+
+def vit_b_32(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> VisionTransformer:
+ """
+ Constructs a vit_b_32 architecture from
+ `"An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return _vision_transformer(
+ arch="vit_b_32",
+ patch_size=32,
+ num_layers=12,
+ num_heads=12,
+ hidden_dim=768,
+ mlp_dim=3072,
+ pretrained=pretrained,
+ progress=progress,
+ **kwargs,
+ )
+
+
+def vit_l_16(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> VisionTransformer:
+ """
+ Constructs a vit_l_16 architecture from
+ `"An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return _vision_transformer(
+ arch="vit_l_16",
+ patch_size=16,
+ num_layers=24,
+ num_heads=16,
+ hidden_dim=1024,
+ mlp_dim=4096,
+ pretrained=pretrained,
+ progress=progress,
+ **kwargs,
+ )
+
+
+def vit_l_32(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> VisionTransformer:
+ """
+ Constructs a vit_l_32 architecture from
+ `"An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return _vision_transformer(
+ arch="vit_l_32",
+ patch_size=32,
+ num_layers=24,
+ num_heads=16,
+ hidden_dim=1024,
+ mlp_dim=4096,
+ pretrained=pretrained,
+ progress=progress,
+ **kwargs,
+ )
+
+
+def interpolate_embeddings(
+ image_size: int,
+ patch_size: int,
+ model_state: "OrderedDict[str, torch.Tensor]",
+ interpolation_mode: str = "bicubic",
+ reset_heads: bool = False,
+) -> "OrderedDict[str, torch.Tensor]":
+ """This function helps interpolating positional embeddings during checkpoint loading,
+ especially when you want to apply a pre-trained model on images with different resolution.
+
+ Args:
+ image_size (int): Image size of the new model.
+ patch_size (int): Patch size of the new model.
+ model_state (OrderedDict[str, torch.Tensor]): State dict of the pre-trained model.
+ interpolation_mode (str): The algorithm used for upsampling. Default: bicubic.
+ reset_heads (bool): If true, not copying the state of heads. Default: False.
+
+ Returns:
+ OrderedDict[str, torch.Tensor]: A state dict which can be loaded into the new model.
+ """
+ # Shape of pos_embedding is (1, seq_length, hidden_dim)
+ pos_embedding = model_state["encoder.pos_embedding"]
+ n, seq_length, hidden_dim = pos_embedding.shape
+ if n != 1:
+ raise ValueError(f"Unexpected position embedding shape: {pos_embedding.shape}")
+
+ new_seq_length = (image_size // patch_size) ** 2 + 1
+
+ # Need to interpolate the weights for the position embedding.
+ # We do this by reshaping the positions embeddings to a 2d grid, performing
+ # an interpolation in the (h, w) space and then reshaping back to a 1d grid.
+ if new_seq_length != seq_length:
+ # The class token embedding shouldn't be interpolated so we split it up.
+ seq_length -= 1
+ new_seq_length -= 1
+ pos_embedding_token = pos_embedding[:, :1, :]
+ pos_embedding_img = pos_embedding[:, 1:, :]
+
+ # (1, seq_length, hidden_dim) -> (1, hidden_dim, seq_length)
+ pos_embedding_img = pos_embedding_img.permute(0, 2, 1)
+ seq_length_1d = int(math.sqrt(seq_length))
+ torch._assert(seq_length_1d * seq_length_1d == seq_length, "seq_length is not a perfect square!")
+
+ # (1, hidden_dim, seq_length) -> (1, hidden_dim, seq_l_1d, seq_l_1d)
+ pos_embedding_img = pos_embedding_img.reshape(1, hidden_dim, seq_length_1d, seq_length_1d)
+ new_seq_length_1d = image_size // patch_size
+
+ # Perform interpolation.
+ # (1, hidden_dim, seq_l_1d, seq_l_1d) -> (1, hidden_dim, new_seq_l_1d, new_seq_l_1d)
+ new_pos_embedding_img = nn.functional.interpolate(
+ pos_embedding_img,
+ size=new_seq_length_1d,
+ mode=interpolation_mode,
+ align_corners=True,
+ )
+
+ # (1, hidden_dim, new_seq_l_1d, new_seq_l_1d) -> (1, hidden_dim, new_seq_length)
+ new_pos_embedding_img = new_pos_embedding_img.reshape(1, hidden_dim, new_seq_length)
+
+ # (1, hidden_dim, new_seq_length) -> (1, new_seq_length, hidden_dim)
+ new_pos_embedding_img = new_pos_embedding_img.permute(0, 2, 1)
+ new_pos_embedding = torch.cat([pos_embedding_token, new_pos_embedding_img], dim=1)
+
+ model_state["encoder.pos_embedding"] = new_pos_embedding
+
+ if reset_heads:
+ model_state_copy: "OrderedDict[str, torch.Tensor]" = OrderedDict()
+ for k, v in model_state.items():
+ if not k.startswith("heads"):
+ model_state_copy[k] = v
+ model_state = model_state_copy
+
+ return model_state
diff --git a/clean/image/universal/models/vision_transformer_misc.py b/clean/image/universal/models/vision_transformer_misc.py
new file mode 100644
index 0000000000000000000000000000000000000000..7915f036c00f0d9c57c176e621afc9f1e69dcb30
--- /dev/null
+++ b/clean/image/universal/models/vision_transformer_misc.py
@@ -0,0 +1,163 @@
+from typing import Callable, List, Optional
+
+import torch
+from torch import Tensor
+
+from .vision_transformer_utils import _log_api_usage_once
+
+
+interpolate = torch.nn.functional.interpolate
+
+
+# This is not in nn
+class FrozenBatchNorm2d(torch.nn.Module):
+ """
+ BatchNorm2d where the batch statistics and the affine parameters are fixed
+
+ Args:
+ num_features (int): Number of features ``C`` from an expected input of size ``(N, C, H, W)``
+ eps (float): a value added to the denominator for numerical stability. Default: 1e-5
+ """
+
+ def __init__(
+ self,
+ num_features: int,
+ eps: float = 1e-5,
+ ):
+ super().__init__()
+ _log_api_usage_once(self)
+ self.eps = eps
+ self.register_buffer("weight", torch.ones(num_features))
+ self.register_buffer("bias", torch.zeros(num_features))
+ self.register_buffer("running_mean", torch.zeros(num_features))
+ self.register_buffer("running_var", torch.ones(num_features))
+
+ def _load_from_state_dict(
+ self,
+ state_dict: dict,
+ prefix: str,
+ local_metadata: dict,
+ strict: bool,
+ missing_keys: List[str],
+ unexpected_keys: List[str],
+ error_msgs: List[str],
+ ):
+ num_batches_tracked_key = prefix + "num_batches_tracked"
+ if num_batches_tracked_key in state_dict:
+ del state_dict[num_batches_tracked_key]
+
+ super()._load_from_state_dict(
+ state_dict, prefix, local_metadata, strict, missing_keys, unexpected_keys, error_msgs
+ )
+
+ def forward(self, x: Tensor) -> Tensor:
+ # move reshapes to the beginning
+ # to make it fuser-friendly
+ w = self.weight.reshape(1, -1, 1, 1)
+ b = self.bias.reshape(1, -1, 1, 1)
+ rv = self.running_var.reshape(1, -1, 1, 1)
+ rm = self.running_mean.reshape(1, -1, 1, 1)
+ scale = w * (rv + self.eps).rsqrt()
+ bias = b - rm * scale
+ return x * scale + bias
+
+ def __repr__(self) -> str:
+ return f"{self.__class__.__name__}({self.weight.shape[0]}, eps={self.eps})"
+
+
+class ConvNormActivation(torch.nn.Sequential):
+ """
+ Configurable block used for Convolution-Normalzation-Activation blocks.
+
+ Args:
+ in_channels (int): Number of channels in the input image
+ out_channels (int): Number of channels produced by the Convolution-Normalzation-Activation block
+ kernel_size: (int, optional): Size of the convolving kernel. Default: 3
+ stride (int, optional): Stride of the convolution. Default: 1
+ padding (int, tuple or str, optional): Padding added to all four sides of the input. Default: None, in wich case it will calculated as ``padding = (kernel_size - 1) // 2 * dilation``
+ groups (int, optional): Number of blocked connections from input channels to output channels. Default: 1
+ norm_layer (Callable[..., torch.nn.Module], optional): Norm layer that will be stacked on top of the convolutiuon layer. If ``None`` this layer wont be used. Default: ``torch.nn.BatchNorm2d``
+ activation_layer (Callable[..., torch.nn.Module], optinal): Activation function which will be stacked on top of the normalization layer (if not None), otherwise on top of the conv layer. If ``None`` this layer wont be used. Default: ``torch.nn.ReLU``
+ dilation (int): Spacing between kernel elements. Default: 1
+ inplace (bool): Parameter for the activation layer, which can optionally do the operation in-place. Default ``True``
+ bias (bool, optional): Whether to use bias in the convolution layer. By default, biases are included if ``norm_layer is None``.
+
+ """
+
+ def __init__(
+ self,
+ in_channels: int,
+ out_channels: int,
+ kernel_size: int = 3,
+ stride: int = 1,
+ padding: Optional[int] = None,
+ groups: int = 1,
+ norm_layer: Optional[Callable[..., torch.nn.Module]] = torch.nn.BatchNorm2d,
+ activation_layer: Optional[Callable[..., torch.nn.Module]] = torch.nn.ReLU,
+ dilation: int = 1,
+ inplace: Optional[bool] = True,
+ bias: Optional[bool] = None,
+ ) -> None:
+ if padding is None:
+ padding = (kernel_size - 1) // 2 * dilation
+ if bias is None:
+ bias = norm_layer is None
+ layers = [
+ torch.nn.Conv2d(
+ in_channels,
+ out_channels,
+ kernel_size,
+ stride,
+ padding,
+ dilation=dilation,
+ groups=groups,
+ bias=bias,
+ )
+ ]
+ if norm_layer is not None:
+ layers.append(norm_layer(out_channels))
+ if activation_layer is not None:
+ params = {} if inplace is None else {"inplace": inplace}
+ layers.append(activation_layer(**params))
+ super().__init__(*layers)
+ _log_api_usage_once(self)
+ self.out_channels = out_channels
+
+
+class SqueezeExcitation(torch.nn.Module):
+ """
+ This block implements the Squeeze-and-Excitation block from https://arxiv.org/abs/1709.01507 (see Fig. 1).
+ Parameters ``activation``, and ``scale_activation`` correspond to ``delta`` and ``sigma`` in in eq. 3.
+
+ Args:
+ input_channels (int): Number of channels in the input image
+ squeeze_channels (int): Number of squeeze channels
+ activation (Callable[..., torch.nn.Module], optional): ``delta`` activation. Default: ``torch.nn.ReLU``
+ scale_activation (Callable[..., torch.nn.Module]): ``sigma`` activation. Default: ``torch.nn.Sigmoid``
+ """
+
+ def __init__(
+ self,
+ input_channels: int,
+ squeeze_channels: int,
+ activation: Callable[..., torch.nn.Module] = torch.nn.ReLU,
+ scale_activation: Callable[..., torch.nn.Module] = torch.nn.Sigmoid,
+ ) -> None:
+ super().__init__()
+ _log_api_usage_once(self)
+ self.avgpool = torch.nn.AdaptiveAvgPool2d(1)
+ self.fc1 = torch.nn.Conv2d(input_channels, squeeze_channels, 1)
+ self.fc2 = torch.nn.Conv2d(squeeze_channels, input_channels, 1)
+ self.activation = activation()
+ self.scale_activation = scale_activation()
+
+ def _scale(self, input: Tensor) -> Tensor:
+ scale = self.avgpool(input)
+ scale = self.fc1(scale)
+ scale = self.activation(scale)
+ scale = self.fc2(scale)
+ return self.scale_activation(scale)
+
+ def forward(self, input: Tensor) -> Tensor:
+ scale = self._scale(input)
+ return scale * input
diff --git a/clean/image/universal/models/vision_transformer_utils.py b/clean/image/universal/models/vision_transformer_utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..6d3293d103d0e186a1244e7cc0c6e3bde63d1df3
--- /dev/null
+++ b/clean/image/universal/models/vision_transformer_utils.py
@@ -0,0 +1,549 @@
+import math
+import pathlib
+import warnings
+from types import FunctionType
+from typing import Any, BinaryIO, List, Optional, Tuple, Union
+
+import numpy as np
+import torch
+from PIL import Image, ImageColor, ImageDraw, ImageFont
+
+__all__ = [
+ "make_grid",
+ "save_image",
+ "draw_bounding_boxes",
+ "draw_segmentation_masks",
+ "draw_keypoints",
+ "flow_to_image",
+]
+
+
+@torch.no_grad()
+def make_grid(
+ tensor: Union[torch.Tensor, List[torch.Tensor]],
+ nrow: int = 8,
+ padding: int = 2,
+ normalize: bool = False,
+ value_range: Optional[Tuple[int, int]] = None,
+ scale_each: bool = False,
+ pad_value: float = 0.0,
+ **kwargs,
+) -> torch.Tensor:
+ """
+ Make a grid of images.
+
+ Args:
+ tensor (Tensor or list): 4D mini-batch Tensor of shape (B x C x H x W)
+ or a list of images all of the same size.
+ nrow (int, optional): Number of images displayed in each row of the grid.
+ The final grid size is ``(B / nrow, nrow)``. Default: ``8``.
+ padding (int, optional): amount of padding. Default: ``2``.
+ normalize (bool, optional): If True, shift the image to the range (0, 1),
+ by the min and max values specified by ``value_range``. Default: ``False``.
+ value_range (tuple, optional): tuple (min, max) where min and max are numbers,
+ then these numbers are used to normalize the image. By default, min and max
+ are computed from the tensor.
+ range (tuple. optional):
+ .. warning::
+ This parameter was deprecated in ``0.12`` and will be removed in ``0.14``. Please use ``value_range``
+ instead.
+ scale_each (bool, optional): If ``True``, scale each image in the batch of
+ images separately rather than the (min, max) over all images. Default: ``False``.
+ pad_value (float, optional): Value for the padded pixels. Default: ``0``.
+
+ Returns:
+ grid (Tensor): the tensor containing grid of images.
+ """
+ if not torch.jit.is_scripting() and not torch.jit.is_tracing():
+ _log_api_usage_once(make_grid)
+ if not (torch.is_tensor(tensor) or (isinstance(tensor, list) and all(torch.is_tensor(t) for t in tensor))):
+ raise TypeError(f"tensor or list of tensors expected, got {type(tensor)}")
+
+ if "range" in kwargs.keys():
+ warnings.warn(
+ "The parameter 'range' is deprecated since 0.12 and will be removed in 0.14. "
+ "Please use 'value_range' instead."
+ )
+ value_range = kwargs["range"]
+
+ # if list of tensors, convert to a 4D mini-batch Tensor
+ if isinstance(tensor, list):
+ tensor = torch.stack(tensor, dim=0)
+
+ if tensor.dim() == 2: # single image H x W
+ tensor = tensor.unsqueeze(0)
+ if tensor.dim() == 3: # single image
+ if tensor.size(0) == 1: # if single-channel, convert to 3-channel
+ tensor = torch.cat((tensor, tensor, tensor), 0)
+ tensor = tensor.unsqueeze(0)
+
+ if tensor.dim() == 4 and tensor.size(1) == 1: # single-channel images
+ tensor = torch.cat((tensor, tensor, tensor), 1)
+
+ if normalize is True:
+ tensor = tensor.clone() # avoid modifying tensor in-place
+ if value_range is not None:
+ assert isinstance(
+ value_range, tuple
+ ), "value_range has to be a tuple (min, max) if specified. min and max are numbers"
+
+ def norm_ip(img, low, high):
+ img.clamp_(min=low, max=high)
+ img.sub_(low).div_(max(high - low, 1e-5))
+
+ def norm_range(t, value_range):
+ if value_range is not None:
+ norm_ip(t, value_range[0], value_range[1])
+ else:
+ norm_ip(t, float(t.min()), float(t.max()))
+
+ if scale_each is True:
+ for t in tensor: # loop over mini-batch dimension
+ norm_range(t, value_range)
+ else:
+ norm_range(tensor, value_range)
+
+ assert isinstance(tensor, torch.Tensor)
+ if tensor.size(0) == 1:
+ return tensor.squeeze(0)
+
+ # make the mini-batch of images into a grid
+ nmaps = tensor.size(0)
+ xmaps = min(nrow, nmaps)
+ ymaps = int(math.ceil(float(nmaps) / xmaps))
+ height, width = int(tensor.size(2) + padding), int(tensor.size(3) + padding)
+ num_channels = tensor.size(1)
+ grid = tensor.new_full((num_channels, height * ymaps + padding, width * xmaps + padding), pad_value)
+ k = 0
+ for y in range(ymaps):
+ for x in range(xmaps):
+ if k >= nmaps:
+ break
+ # Tensor.copy_() is a valid method but seems to be missing from the stubs
+ # https://pytorch.org/docs/stable/tensors.html#torch.Tensor.copy_
+ grid.narrow(1, y * height + padding, height - padding).narrow( # type: ignore[attr-defined]
+ 2, x * width + padding, width - padding
+ ).copy_(tensor[k])
+ k = k + 1
+ return grid
+
+
+@torch.no_grad()
+def save_image(
+ tensor: Union[torch.Tensor, List[torch.Tensor]],
+ fp: Union[str, pathlib.Path, BinaryIO],
+ format: Optional[str] = None,
+ **kwargs,
+) -> None:
+ """
+ Save a given Tensor into an image file.
+
+ Args:
+ tensor (Tensor or list): Image to be saved. If given a mini-batch tensor,
+ saves the tensor as a grid of images by calling ``make_grid``.
+ fp (string or file object): A filename or a file object
+ format(Optional): If omitted, the format to use is determined from the filename extension.
+ If a file object was used instead of a filename, this parameter should always be used.
+ **kwargs: Other arguments are documented in ``make_grid``.
+ """
+
+ if not torch.jit.is_scripting() and not torch.jit.is_tracing():
+ _log_api_usage_once(save_image)
+ grid = make_grid(tensor, **kwargs)
+ # Add 0.5 after unnormalizing to [0, 255] to round to nearest integer
+ ndarr = grid.mul(255).add_(0.5).clamp_(0, 255).permute(1, 2, 0).to("cpu", torch.uint8).numpy()
+ im = Image.fromarray(ndarr)
+ im.save(fp, format=format)
+
+
+@torch.no_grad()
+def draw_bounding_boxes(
+ image: torch.Tensor,
+ boxes: torch.Tensor,
+ labels: Optional[List[str]] = None,
+ colors: Optional[Union[List[Union[str, Tuple[int, int, int]]], str, Tuple[int, int, int]]] = None,
+ fill: Optional[bool] = False,
+ width: int = 1,
+ font: Optional[str] = None,
+ font_size: int = 10,
+) -> torch.Tensor:
+
+ """
+ Draws bounding boxes on given image.
+ The values of the input image should be uint8 between 0 and 255.
+ If fill is True, Resulting Tensor should be saved as PNG image.
+
+ Args:
+ image (Tensor): Tensor of shape (C x H x W) and dtype uint8.
+ boxes (Tensor): Tensor of size (N, 4) containing bounding boxes in (xmin, ymin, xmax, ymax) format. Note that
+ the boxes are absolute coordinates with respect to the image. In other words: `0 <= xmin < xmax < W` and
+ `0 <= ymin < ymax < H`.
+ labels (List[str]): List containing the labels of bounding boxes.
+ colors (color or list of colors, optional): List containing the colors
+ of the boxes or single color for all boxes. The color can be represented as
+ PIL strings e.g. "red" or "#FF00FF", or as RGB tuples e.g. ``(240, 10, 157)``.
+ By default, random colors are generated for boxes.
+ fill (bool): If `True` fills the bounding box with specified color.
+ width (int): Width of bounding box.
+ font (str): A filename containing a TrueType font. If the file is not found in this filename, the loader may
+ also search in other directories, such as the `fonts/` directory on Windows or `/Library/Fonts/`,
+ `/System/Library/Fonts/` and `~/Library/Fonts/` on macOS.
+ font_size (int): The requested font size in points.
+
+ Returns:
+ img (Tensor[C, H, W]): Image Tensor of dtype uint8 with bounding boxes plotted.
+ """
+
+ if not torch.jit.is_scripting() and not torch.jit.is_tracing():
+ _log_api_usage_once(draw_bounding_boxes)
+ if not isinstance(image, torch.Tensor):
+ raise TypeError(f"Tensor expected, got {type(image)}")
+ elif image.dtype != torch.uint8:
+ raise ValueError(f"Tensor uint8 expected, got {image.dtype}")
+ elif image.dim() != 3:
+ raise ValueError("Pass individual images, not batches")
+ elif image.size(0) not in {1, 3}:
+ raise ValueError("Only grayscale and RGB images are supported")
+
+ num_boxes = boxes.shape[0]
+
+ if labels is None:
+ labels: Union[List[str], List[None]] = [None] * num_boxes # type: ignore[no-redef]
+ elif len(labels) != num_boxes:
+ raise ValueError(
+ f"Number of boxes ({num_boxes}) and labels ({len(labels)}) mismatch. Please specify labels for each box."
+ )
+
+ if colors is None:
+ colors = _generate_color_palette(num_boxes)
+ elif isinstance(colors, list):
+ if len(colors) < num_boxes:
+ raise ValueError(f"Number of colors ({len(colors)}) is less than number of boxes ({num_boxes}). ")
+ else: # colors specifies a single color for all boxes
+ colors = [colors] * num_boxes
+
+ colors = [(ImageColor.getrgb(color) if isinstance(color, str) else color) for color in colors]
+
+ # Handle Grayscale images
+ if image.size(0) == 1:
+ image = torch.tile(image, (3, 1, 1))
+
+ ndarr = image.permute(1, 2, 0).cpu().numpy()
+ img_to_draw = Image.fromarray(ndarr)
+ img_boxes = boxes.to(torch.int64).tolist()
+
+ if fill:
+ draw = ImageDraw.Draw(img_to_draw, "RGBA")
+ else:
+ draw = ImageDraw.Draw(img_to_draw)
+
+ txt_font = ImageFont.load_default() if font is None else ImageFont.truetype(font=font, size=font_size)
+
+ for bbox, color, label in zip(img_boxes, colors, labels): # type: ignore[arg-type]
+ if fill:
+ fill_color = color + (100,)
+ draw.rectangle(bbox, width=width, outline=color, fill=fill_color)
+ else:
+ draw.rectangle(bbox, width=width, outline=color)
+
+ if label is not None:
+ margin = width + 1
+ draw.text((bbox[0] + margin, bbox[1] + margin), label, fill=color, font=txt_font)
+
+ return torch.from_numpy(np.array(img_to_draw)).permute(2, 0, 1).to(dtype=torch.uint8)
+
+
+@torch.no_grad()
+def draw_segmentation_masks(
+ image: torch.Tensor,
+ masks: torch.Tensor,
+ alpha: float = 0.8,
+ colors: Optional[Union[List[Union[str, Tuple[int, int, int]]], str, Tuple[int, int, int]]] = None,
+) -> torch.Tensor:
+
+ """
+ Draws segmentation masks on given RGB image.
+ The values of the input image should be uint8 between 0 and 255.
+
+ Args:
+ image (Tensor): Tensor of shape (3, H, W) and dtype uint8.
+ masks (Tensor): Tensor of shape (num_masks, H, W) or (H, W) and dtype bool.
+ alpha (float): Float number between 0 and 1 denoting the transparency of the masks.
+ 0 means full transparency, 1 means no transparency.
+ colors (color or list of colors, optional): List containing the colors
+ of the masks or single color for all masks. The color can be represented as
+ PIL strings e.g. "red" or "#FF00FF", or as RGB tuples e.g. ``(240, 10, 157)``.
+ By default, random colors are generated for each mask.
+
+ Returns:
+ img (Tensor[C, H, W]): Image Tensor, with segmentation masks drawn on top.
+ """
+
+ if not torch.jit.is_scripting() and not torch.jit.is_tracing():
+ _log_api_usage_once(draw_segmentation_masks)
+ if not isinstance(image, torch.Tensor):
+ raise TypeError(f"The image must be a tensor, got {type(image)}")
+ elif image.dtype != torch.uint8:
+ raise ValueError(f"The image dtype must be uint8, got {image.dtype}")
+ elif image.dim() != 3:
+ raise ValueError("Pass individual images, not batches")
+ elif image.size()[0] != 3:
+ raise ValueError("Pass an RGB image. Other Image formats are not supported")
+ if masks.ndim == 2:
+ masks = masks[None, :, :]
+ if masks.ndim != 3:
+ raise ValueError("masks must be of shape (H, W) or (batch_size, H, W)")
+ if masks.dtype != torch.bool:
+ raise ValueError(f"The masks must be of dtype bool. Got {masks.dtype}")
+ if masks.shape[-2:] != image.shape[-2:]:
+ raise ValueError("The image and the masks must have the same height and width")
+
+ num_masks = masks.size()[0]
+ if colors is not None and num_masks > len(colors):
+ raise ValueError(f"There are more masks ({num_masks}) than colors ({len(colors)})")
+
+ if colors is None:
+ colors = _generate_color_palette(num_masks)
+
+ if not isinstance(colors, list):
+ colors = [colors]
+ if not isinstance(colors[0], (tuple, str)):
+ raise ValueError("colors must be a tuple or a string, or a list thereof")
+ if isinstance(colors[0], tuple) and len(colors[0]) != 3:
+ raise ValueError("It seems that you passed a tuple of colors instead of a list of colors")
+
+ out_dtype = torch.uint8
+
+ colors_ = []
+ for color in colors:
+ if isinstance(color, str):
+ color = ImageColor.getrgb(color)
+ colors_.append(torch.tensor(color, dtype=out_dtype))
+
+ img_to_draw = image.detach().clone()
+ # TODO: There might be a way to vectorize this
+ for mask, color in zip(masks, colors_):
+ img_to_draw[:, mask] = color[:, None]
+
+ out = image * (1 - alpha) + img_to_draw * alpha
+ return out.to(out_dtype)
+
+
+@torch.no_grad()
+def draw_keypoints(
+ image: torch.Tensor,
+ keypoints: torch.Tensor,
+ connectivity: Optional[List[Tuple[int, int]]] = None,
+ colors: Optional[Union[str, Tuple[int, int, int]]] = None,
+ radius: int = 2,
+ width: int = 3,
+) -> torch.Tensor:
+
+ """
+ Draws Keypoints on given RGB image.
+ The values of the input image should be uint8 between 0 and 255.
+
+ Args:
+ image (Tensor): Tensor of shape (3, H, W) and dtype uint8.
+ keypoints (Tensor): Tensor of shape (num_instances, K, 2) the K keypoints location for each of the N instances,
+ in the format [x, y].
+ connectivity (List[Tuple[int, int]]]): A List of tuple where,
+ each tuple contains pair of keypoints to be connected.
+ colors (str, Tuple): The color can be represented as
+ PIL strings e.g. "red" or "#FF00FF", or as RGB tuples e.g. ``(240, 10, 157)``.
+ radius (int): Integer denoting radius of keypoint.
+ width (int): Integer denoting width of line connecting keypoints.
+
+ Returns:
+ img (Tensor[C, H, W]): Image Tensor of dtype uint8 with keypoints drawn.
+ """
+
+ if not torch.jit.is_scripting() and not torch.jit.is_tracing():
+ _log_api_usage_once(draw_keypoints)
+ if not isinstance(image, torch.Tensor):
+ raise TypeError(f"The image must be a tensor, got {type(image)}")
+ elif image.dtype != torch.uint8:
+ raise ValueError(f"The image dtype must be uint8, got {image.dtype}")
+ elif image.dim() != 3:
+ raise ValueError("Pass individual images, not batches")
+ elif image.size()[0] != 3:
+ raise ValueError("Pass an RGB image. Other Image formats are not supported")
+
+ if keypoints.ndim != 3:
+ raise ValueError("keypoints must be of shape (num_instances, K, 2)")
+
+ ndarr = image.permute(1, 2, 0).cpu().numpy()
+ img_to_draw = Image.fromarray(ndarr)
+ draw = ImageDraw.Draw(img_to_draw)
+ img_kpts = keypoints.to(torch.int64).tolist()
+
+ for kpt_id, kpt_inst in enumerate(img_kpts):
+ for inst_id, kpt in enumerate(kpt_inst):
+ x1 = kpt[0] - radius
+ x2 = kpt[0] + radius
+ y1 = kpt[1] - radius
+ y2 = kpt[1] + radius
+ draw.ellipse([x1, y1, x2, y2], fill=colors, outline=None, width=0)
+
+ if connectivity:
+ for connection in connectivity:
+ start_pt_x = kpt_inst[connection[0]][0]
+ start_pt_y = kpt_inst[connection[0]][1]
+
+ end_pt_x = kpt_inst[connection[1]][0]
+ end_pt_y = kpt_inst[connection[1]][1]
+
+ draw.line(
+ ((start_pt_x, start_pt_y), (end_pt_x, end_pt_y)),
+ width=width,
+ )
+
+ return torch.from_numpy(np.array(img_to_draw)).permute(2, 0, 1).to(dtype=torch.uint8)
+
+
+# Flow visualization code adapted from https://github.com/tomrunia/OpticalFlow_Visualization
+@torch.no_grad()
+def flow_to_image(flow: torch.Tensor) -> torch.Tensor:
+
+ """
+ Converts a flow to an RGB image.
+
+ Args:
+ flow (Tensor): Flow of shape (N, 2, H, W) or (2, H, W) and dtype torch.float.
+
+ Returns:
+ img (Tensor): Image Tensor of dtype uint8 where each color corresponds
+ to a given flow direction. Shape is (N, 3, H, W) or (3, H, W) depending on the input.
+ """
+
+ if flow.dtype != torch.float:
+ raise ValueError(f"Flow should be of dtype torch.float, got {flow.dtype}.")
+
+ orig_shape = flow.shape
+ if flow.ndim == 3:
+ flow = flow[None] # Add batch dim
+
+ if flow.ndim != 4 or flow.shape[1] != 2:
+ raise ValueError(f"Input flow should have shape (2, H, W) or (N, 2, H, W), got {orig_shape}.")
+
+ max_norm = torch.sum(flow ** 2, dim=1).sqrt().max()
+ epsilon = torch.finfo((flow).dtype).eps
+ normalized_flow = flow / (max_norm + epsilon)
+ img = _normalized_flow_to_image(normalized_flow)
+
+ if len(orig_shape) == 3:
+ img = img[0] # Remove batch dim
+ return img
+
+
+@torch.no_grad()
+def _normalized_flow_to_image(normalized_flow: torch.Tensor) -> torch.Tensor:
+
+ """
+ Converts a batch of normalized flow to an RGB image.
+
+ Args:
+ normalized_flow (torch.Tensor): Normalized flow tensor of shape (N, 2, H, W)
+ Returns:
+ img (Tensor(N, 3, H, W)): Flow visualization image of dtype uint8.
+ """
+
+ N, _, H, W = normalized_flow.shape
+ device = normalized_flow.device
+ flow_image = torch.zeros((N, 3, H, W), dtype=torch.uint8, device=device)
+ colorwheel = _make_colorwheel().to(device) # shape [55x3]
+ num_cols = colorwheel.shape[0]
+ norm = torch.sum(normalized_flow ** 2, dim=1).sqrt()
+ a = torch.atan2(-normalized_flow[:, 1, :, :], -normalized_flow[:, 0, :, :]) / torch.pi
+ fk = (a + 1) / 2 * (num_cols - 1)
+ k0 = torch.floor(fk).to(torch.long)
+ k1 = k0 + 1
+ k1[k1 == num_cols] = 0
+ f = fk - k0
+
+ for c in range(colorwheel.shape[1]):
+ tmp = colorwheel[:, c]
+ col0 = tmp[k0] / 255.0
+ col1 = tmp[k1] / 255.0
+ col = (1 - f) * col0 + f * col1
+ col = 1 - norm * (1 - col)
+ flow_image[:, c, :, :] = torch.floor(255 * col)
+ return flow_image
+
+
+def _make_colorwheel() -> torch.Tensor:
+ """
+ Generates a color wheel for optical flow visualization as presented in:
+ Baker et al. "A Database and Evaluation Methodology for Optical Flow" (ICCV, 2007)
+ URL: http://vision.middlebury.edu/flow/flowEval-iccv07.pdf.
+
+ Returns:
+ colorwheel (Tensor[55, 3]): Colorwheel Tensor.
+ """
+
+ RY = 15
+ YG = 6
+ GC = 4
+ CB = 11
+ BM = 13
+ MR = 6
+
+ ncols = RY + YG + GC + CB + BM + MR
+ colorwheel = torch.zeros((ncols, 3))
+ col = 0
+
+ # RY
+ colorwheel[0:RY, 0] = 255
+ colorwheel[0:RY, 1] = torch.floor(255 * torch.arange(0, RY) / RY)
+ col = col + RY
+ # YG
+ colorwheel[col : col + YG, 0] = 255 - torch.floor(255 * torch.arange(0, YG) / YG)
+ colorwheel[col : col + YG, 1] = 255
+ col = col + YG
+ # GC
+ colorwheel[col : col + GC, 1] = 255
+ colorwheel[col : col + GC, 2] = torch.floor(255 * torch.arange(0, GC) / GC)
+ col = col + GC
+ # CB
+ colorwheel[col : col + CB, 1] = 255 - torch.floor(255 * torch.arange(CB) / CB)
+ colorwheel[col : col + CB, 2] = 255
+ col = col + CB
+ # BM
+ colorwheel[col : col + BM, 2] = 255
+ colorwheel[col : col + BM, 0] = torch.floor(255 * torch.arange(0, BM) / BM)
+ col = col + BM
+ # MR
+ colorwheel[col : col + MR, 2] = 255 - torch.floor(255 * torch.arange(MR) / MR)
+ colorwheel[col : col + MR, 0] = 255
+ return colorwheel
+
+
+def _generate_color_palette(num_objects: int):
+ palette = torch.tensor([2 ** 25 - 1, 2 ** 15 - 1, 2 ** 21 - 1])
+ return [tuple((i * palette) % 255) for i in range(num_objects)]
+
+
+def _log_api_usage_once(obj: Any) -> None:
+
+ """
+ Logs API usage(module and name) within an organization.
+ In a large ecosystem, it's often useful to track the PyTorch and
+ TorchVision APIs usage. This API provides the similar functionality to the
+ logging module in the Python stdlib. It can be used for debugging purpose
+ to log which methods are used and by default it is inactive, unless the user
+ manually subscribes a logger via the `SetAPIUsageLogger method `_.
+ Please note it is triggered only once for the same API call within a process.
+ It does not collect any data from open-source users since it is no-op by default.
+ For more information, please refer to
+ * PyTorch note: https://pytorch.org/docs/stable/notes/large_scale_deployments.html#api-usage-logging;
+ * Logging policy: https://github.com/pytorch/vision/issues/5052;
+
+ Args:
+ obj (class instance or method): an object to extract info from.
+ """
+ if not obj.__module__.startswith("torchvision"):
+ return
+ name = obj.__class__.__name__
+ if isinstance(obj, FunctionType):
+ name = obj.__name__
+ torch._C._log_api_usage_once(f"{obj.__module__}.{name}")
diff --git a/clean/image/universal/networks/__init__.py b/clean/image/universal/networks/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/clean/image/universal/networks/base_model.py b/clean/image/universal/networks/base_model.py
new file mode 100644
index 0000000000000000000000000000000000000000..684bdd31004eb9d5664da1aba08dc3ba3b7c4d80
--- /dev/null
+++ b/clean/image/universal/networks/base_model.py
@@ -0,0 +1,58 @@
+import os
+import torch
+import torch.nn as nn
+from torch.nn import init
+from torch.optim import lr_scheduler
+
+
+class BaseModel(nn.Module):
+ def __init__(self, opt):
+ super(BaseModel, self).__init__()
+ self.opt = opt
+ self.total_steps = 0
+ self.save_dir = os.path.join(opt.checkpoints_dir, opt.name)
+ self.device = torch.device('cuda:{}'.format(opt.gpu_ids[0])) if opt.gpu_ids else torch.device('cpu')
+
+ def save_networks(self, save_filename):
+ save_path = os.path.join(self.save_dir, save_filename)
+
+ # serialize model and optimizer to dict
+ state_dict = {
+ 'model': self.model.state_dict(),
+ 'optimizer' : self.optimizer.state_dict(),
+ 'total_steps' : self.total_steps,
+ }
+
+ torch.save(state_dict, save_path)
+
+
+ def eval(self):
+ self.model.eval()
+
+ def test(self):
+ with torch.no_grad():
+ self.forward()
+
+
+def init_weights(net, init_type='normal', gain=0.02):
+ def init_func(m):
+ classname = m.__class__.__name__
+ if hasattr(m, 'weight') and (classname.find('Conv') != -1 or classname.find('Linear') != -1):
+ if init_type == 'normal':
+ init.normal_(m.weight.data, 0.0, gain)
+ elif init_type == 'xavier':
+ init.xavier_normal_(m.weight.data, gain=gain)
+ elif init_type == 'kaiming':
+ init.kaiming_normal_(m.weight.data, a=0, mode='fan_in')
+ elif init_type == 'orthogonal':
+ init.orthogonal_(m.weight.data, gain=gain)
+ else:
+ raise NotImplementedError('initialization method [%s] is not implemented' % init_type)
+ if hasattr(m, 'bias') and m.bias is not None:
+ init.constant_(m.bias.data, 0.0)
+ elif classname.find('BatchNorm2d') != -1:
+ init.normal_(m.weight.data, 1.0, gain)
+ init.constant_(m.bias.data, 0.0)
+
+ print('initialize network with %s' % init_type)
+ net.apply(init_func)
diff --git a/clean/image/universal/networks/lpf.py b/clean/image/universal/networks/lpf.py
new file mode 100644
index 0000000000000000000000000000000000000000..f64030bd9a73786f249e03b4d6ce02b32d5ecf92
--- /dev/null
+++ b/clean/image/universal/networks/lpf.py
@@ -0,0 +1,120 @@
+# Copyright (c) 2019, Adobe Inc. All rights reserved.
+#
+# This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike
+# 4.0 International Public License. To view a copy of this license, visit
+# https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode.
+
+import torch
+import torch.nn.parallel
+import numpy as np
+import torch.nn as nn
+import torch.nn.functional as F
+from IPython import embed
+
+class Downsample(nn.Module):
+ def __init__(self, pad_type='reflect', filt_size=3, stride=2, channels=None, pad_off=0):
+ super(Downsample, self).__init__()
+ self.filt_size = filt_size
+ self.pad_off = pad_off
+ self.pad_sizes = [int(1.*(filt_size-1)/2), int(np.ceil(1.*(filt_size-1)/2)), int(1.*(filt_size-1)/2), int(np.ceil(1.*(filt_size-1)/2))]
+ self.pad_sizes = [pad_size+pad_off for pad_size in self.pad_sizes]
+ self.stride = stride
+ self.off = int((self.stride-1)/2.)
+ self.channels = channels
+
+ # print('Filter size [%i]'%filt_size)
+ if(self.filt_size==1):
+ a = np.array([1.,])
+ elif(self.filt_size==2):
+ a = np.array([1., 1.])
+ elif(self.filt_size==3):
+ a = np.array([1., 2., 1.])
+ elif(self.filt_size==4):
+ a = np.array([1., 3., 3., 1.])
+ elif(self.filt_size==5):
+ a = np.array([1., 4., 6., 4., 1.])
+ elif(self.filt_size==6):
+ a = np.array([1., 5., 10., 10., 5., 1.])
+ elif(self.filt_size==7):
+ a = np.array([1., 6., 15., 20., 15., 6., 1.])
+
+ filt = torch.Tensor(a[:,None]*a[None,:])
+ filt = filt/torch.sum(filt)
+ self.register_buffer('filt', filt[None,None,:,:].repeat((self.channels,1,1,1)))
+
+ self.pad = get_pad_layer(pad_type)(self.pad_sizes)
+
+ def forward(self, inp):
+ if(self.filt_size==1):
+ if(self.pad_off==0):
+ return inp[:,:,::self.stride,::self.stride]
+ else:
+ return self.pad(inp)[:,:,::self.stride,::self.stride]
+ else:
+ return F.conv2d(self.pad(inp), self.filt, stride=self.stride, groups=inp.shape[1])
+
+def get_pad_layer(pad_type):
+ if(pad_type in ['refl','reflect']):
+ PadLayer = nn.ReflectionPad2d
+ elif(pad_type in ['repl','replicate']):
+ PadLayer = nn.ReplicationPad2d
+ elif(pad_type=='zero'):
+ PadLayer = nn.ZeroPad2d
+ else:
+ print('Pad type [%s] not recognized'%pad_type)
+ return PadLayer
+
+
+class Downsample1D(nn.Module):
+ def __init__(self, pad_type='reflect', filt_size=3, stride=2, channels=None, pad_off=0):
+ super(Downsample1D, self).__init__()
+ self.filt_size = filt_size
+ self.pad_off = pad_off
+ self.pad_sizes = [int(1. * (filt_size - 1) / 2), int(np.ceil(1. * (filt_size - 1) / 2))]
+ self.pad_sizes = [pad_size + pad_off for pad_size in self.pad_sizes]
+ self.stride = stride
+ self.off = int((self.stride - 1) / 2.)
+ self.channels = channels
+
+ # print('Filter size [%i]' % filt_size)
+ if(self.filt_size == 1):
+ a = np.array([1., ])
+ elif(self.filt_size == 2):
+ a = np.array([1., 1.])
+ elif(self.filt_size == 3):
+ a = np.array([1., 2., 1.])
+ elif(self.filt_size == 4):
+ a = np.array([1., 3., 3., 1.])
+ elif(self.filt_size == 5):
+ a = np.array([1., 4., 6., 4., 1.])
+ elif(self.filt_size == 6):
+ a = np.array([1., 5., 10., 10., 5., 1.])
+ elif(self.filt_size == 7):
+ a = np.array([1., 6., 15., 20., 15., 6., 1.])
+
+ filt = torch.Tensor(a)
+ filt = filt / torch.sum(filt)
+ self.register_buffer('filt', filt[None, None, :].repeat((self.channels, 1, 1)))
+
+ self.pad = get_pad_layer_1d(pad_type)(self.pad_sizes)
+
+ def forward(self, inp):
+ if(self.filt_size == 1):
+ if(self.pad_off == 0):
+ return inp[:, :, ::self.stride]
+ else:
+ return self.pad(inp)[:, :, ::self.stride]
+ else:
+ return F.conv1d(self.pad(inp), self.filt, stride=self.stride, groups=inp.shape[1])
+
+
+def get_pad_layer_1d(pad_type):
+ if(pad_type in ['refl', 'reflect']):
+ PadLayer = nn.ReflectionPad1d
+ elif(pad_type in ['repl', 'replicate']):
+ PadLayer = nn.ReplicationPad1d
+ elif(pad_type == 'zero'):
+ PadLayer = nn.ZeroPad1d
+ else:
+ print('Pad type [%s] not recognized' % pad_type)
+ return PadLayer
diff --git a/clean/image/universal/networks/resnet_lpf.py b/clean/image/universal/networks/resnet_lpf.py
new file mode 100644
index 0000000000000000000000000000000000000000..f9e34254eadc00e701245d03ffd86c25c114ce3f
--- /dev/null
+++ b/clean/image/universal/networks/resnet_lpf.py
@@ -0,0 +1,313 @@
+# This code is built from the PyTorch examples repository: https://github.com/pytorch/vision/tree/master/torchvision/models.
+# Copyright (c) 2017 Torch Contributors.
+# The Pytorch examples are available under the BSD 3-Clause License.
+#
+# ==========================================================================================
+#
+# Adobe’s modifications are Copyright 2019 Adobe. All rights reserved.
+# Adobe’s modifications are licensed under the Creative Commons Attribution-NonCommercial-ShareAlike
+# 4.0 International Public License (CC-NC-SA-4.0). To view a copy of the license, visit
+# https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode.
+#
+# ==========================================================================================
+#
+# BSD-3 License
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+
+import torch.nn as nn
+import torch.utils.model_zoo as model_zoo
+from .lpf import *
+
+__all__ = ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101',
+ 'resnet152', 'resnext50_32x4d', 'resnext101_32x8d']
+
+
+# model_urls = {
+# 'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth',
+# 'resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth',
+# 'resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth',
+# 'resnet101': 'https://download.pytorch.org/models/resnet101-5d3b4d8f.pth',
+# 'resnet152': 'https://download.pytorch.org/models/resnet152-b121ed2d.pth',
+# }
+
+
+def conv3x3(in_planes, out_planes, stride=1, groups=1):
+ """3x3 convolution with padding"""
+ return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,
+ padding=1, groups=groups, bias=False)
+
+def conv1x1(in_planes, out_planes, stride=1):
+ """1x1 convolution"""
+ return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False)
+
+class BasicBlock(nn.Module):
+ expansion = 1
+
+ def __init__(self, inplanes, planes, stride=1, downsample=None, groups=1, norm_layer=None, filter_size=1):
+ super(BasicBlock, self).__init__()
+ if norm_layer is None:
+ norm_layer = nn.BatchNorm2d
+ if groups != 1:
+ raise ValueError('BasicBlock only supports groups=1')
+ # Both self.conv1 and self.downsample layers downsample the input when stride != 1
+ self.conv1 = conv3x3(inplanes, planes)
+ self.bn1 = norm_layer(planes)
+ self.relu = nn.ReLU(inplace=True)
+ if(stride==1):
+ self.conv2 = conv3x3(planes,planes)
+ else:
+ self.conv2 = nn.Sequential(Downsample(filt_size=filter_size, stride=stride, channels=planes),
+ conv3x3(planes, planes),)
+ self.bn2 = norm_layer(planes)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x):
+ identity = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+
+ if self.downsample is not None:
+ identity = self.downsample(x)
+
+ out += identity
+ out = self.relu(out)
+
+ return out
+
+
+class Bottleneck(nn.Module):
+ expansion = 4
+
+ def __init__(self, inplanes, planes, stride=1, downsample=None, groups=1, norm_layer=None, filter_size=1):
+ super(Bottleneck, self).__init__()
+ if norm_layer is None:
+ norm_layer = nn.BatchNorm2d
+ # Both self.conv2 and self.downsample layers downsample the input when stride != 1
+ self.conv1 = conv1x1(inplanes, planes)
+ self.bn1 = norm_layer(planes)
+ self.conv2 = conv3x3(planes, planes, groups) # stride moved
+ self.bn2 = norm_layer(planes)
+ if(stride==1):
+ self.conv3 = conv1x1(planes, planes * self.expansion)
+ else:
+ self.conv3 = nn.Sequential(Downsample(filt_size=filter_size, stride=stride, channels=planes),
+ conv1x1(planes, planes * self.expansion))
+ self.bn3 = norm_layer(planes * self.expansion)
+ self.relu = nn.ReLU(inplace=True)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x):
+ identity = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+ out = self.relu(out)
+
+ out = self.conv3(out)
+ out = self.bn3(out)
+
+ if self.downsample is not None:
+ identity = self.downsample(x)
+
+ out += identity
+ out = self.relu(out)
+
+ return out
+
+
+class ResNet(nn.Module):
+
+ def __init__(self, block, layers, num_classes=1000, zero_init_residual=False,
+ groups=1, width_per_group=64, norm_layer=None, filter_size=1, pool_only=True):
+ super(ResNet, self).__init__()
+ if norm_layer is None:
+ norm_layer = nn.BatchNorm2d
+ planes = [int(width_per_group * groups * 2 ** i) for i in range(4)]
+ self.inplanes = planes[0]
+
+ if(pool_only):
+ self.conv1 = nn.Conv2d(3, planes[0], kernel_size=7, stride=2, padding=3, bias=False)
+ else:
+ self.conv1 = nn.Conv2d(3, planes[0], kernel_size=7, stride=1, padding=3, bias=False)
+ self.bn1 = norm_layer(planes[0])
+ self.relu = nn.ReLU(inplace=True)
+
+ if(pool_only):
+ self.maxpool = nn.Sequential(*[nn.MaxPool2d(kernel_size=2, stride=1),
+ Downsample(filt_size=filter_size, stride=2, channels=planes[0])])
+ else:
+ self.maxpool = nn.Sequential(*[Downsample(filt_size=filter_size, stride=2, channels=planes[0]),
+ nn.MaxPool2d(kernel_size=2, stride=1),
+ Downsample(filt_size=filter_size, stride=2, channels=planes[0])])
+
+ self.layer1 = self._make_layer(block, planes[0], layers[0], groups=groups, norm_layer=norm_layer)
+ self.layer2 = self._make_layer(block, planes[1], layers[1], stride=2, groups=groups, norm_layer=norm_layer, filter_size=filter_size)
+ self.layer3 = self._make_layer(block, planes[2], layers[2], stride=2, groups=groups, norm_layer=norm_layer, filter_size=filter_size)
+ self.layer4 = self._make_layer(block, planes[3], layers[3], stride=2, groups=groups, norm_layer=norm_layer, filter_size=filter_size)
+ self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
+ self.fc = nn.Linear(planes[3] * block.expansion, num_classes)
+
+ for m in self.modules():
+ if isinstance(m, nn.Conv2d):
+ if(m.in_channels!=m.out_channels or m.out_channels!=m.groups or m.bias is not None):
+ # don't want to reinitialize downsample layers, code assuming normal conv layers will not have these characteristics
+ nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
+ else:
+ print('Not initializing')
+ elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
+ nn.init.constant_(m.weight, 1)
+ nn.init.constant_(m.bias, 0)
+
+ # Zero-initialize the last BN in each residual branch,
+ # so that the residual branch starts with zeros, and each residual block behaves like an identity.
+ # This improves the model by 0.2~0.3% according to https://arxiv.org/abs/1706.02677
+ if zero_init_residual:
+ for m in self.modules():
+ if isinstance(m, Bottleneck):
+ nn.init.constant_(m.bn3.weight, 0)
+ elif isinstance(m, BasicBlock):
+ nn.init.constant_(m.bn2.weight, 0)
+
+ def _make_layer(self, block, planes, blocks, stride=1, groups=1, norm_layer=None, filter_size=1):
+ if norm_layer is None:
+ norm_layer = nn.BatchNorm2d
+ downsample = None
+ if stride != 1 or self.inplanes != planes * block.expansion:
+ # downsample = nn.Sequential(
+ # conv1x1(self.inplanes, planes * block.expansion, stride, filter_size=filter_size),
+ # norm_layer(planes * block.expansion),
+ # )
+
+ downsample = [Downsample(filt_size=filter_size, stride=stride, channels=self.inplanes),] if(stride !=1) else []
+ downsample += [conv1x1(self.inplanes, planes * block.expansion, 1),
+ norm_layer(planes * block.expansion)]
+ # print(downsample)
+ downsample = nn.Sequential(*downsample)
+
+ layers = []
+ layers.append(block(self.inplanes, planes, stride, downsample, groups, norm_layer, filter_size=filter_size))
+ self.inplanes = planes * block.expansion
+ for _ in range(1, blocks):
+ layers.append(block(self.inplanes, planes, groups=groups, norm_layer=norm_layer, filter_size=filter_size))
+
+ return nn.Sequential(*layers)
+
+ def forward(self, x):
+ x = self.conv1(x)
+ x = self.bn1(x)
+ x = self.relu(x)
+ x = self.maxpool(x)
+
+ x = self.layer1(x)
+ x = self.layer2(x)
+ x = self.layer3(x)
+ x = self.layer4(x)
+
+ x = self.avgpool(x)
+ x = x.view(x.size(0), -1)
+ x = self.fc(x)
+
+ return x
+
+
+def resnet18(pretrained=False, filter_size=1, pool_only=True, **kwargs):
+ """Constructs a ResNet-18 model.
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ """
+ model = ResNet(BasicBlock, [2, 2, 2, 2], filter_size=filter_size, pool_only=pool_only, **kwargs)
+ if pretrained:
+ model.load_state_dict(model_zoo.load_url(model_urls['resnet18']))
+ return model
+
+
+def resnet34(pretrained=False, filter_size=1, pool_only=True, **kwargs):
+ """Constructs a ResNet-34 model.
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ """
+ model = ResNet(BasicBlock, [3, 4, 6, 3], filter_size=filter_size, pool_only=pool_only, **kwargs)
+ if pretrained:
+ model.load_state_dict(model_zoo.load_url(model_urls['resnet34']))
+ return model
+
+
+def resnet50(pretrained=False, filter_size=1, pool_only=True, **kwargs):
+ """Constructs a ResNet-50 model.
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ """
+ model = ResNet(Bottleneck, [3, 4, 6, 3], filter_size=filter_size, pool_only=pool_only, **kwargs)
+ if pretrained:
+ model.load_state_dict(model_zoo.load_url(model_urls['resnet50']))
+ return model
+
+
+def resnet101(pretrained=False, filter_size=1, pool_only=True, **kwargs):
+ """Constructs a ResNet-101 model.
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ """
+ model = ResNet(Bottleneck, [3, 4, 23, 3], filter_size=filter_size, pool_only=pool_only, **kwargs)
+ if pretrained:
+ model.load_state_dict(model_zoo.load_url(model_urls['resnet101']))
+ return model
+
+
+def resnet152(pretrained=False, filter_size=1, pool_only=True, **kwargs):
+ """Constructs a ResNet-152 model.
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ """
+ model = ResNet(Bottleneck, [3, 8, 36, 3], filter_size=filter_size, pool_only=pool_only, **kwargs)
+ if pretrained:
+ model.load_state_dict(model_zoo.load_url(model_urls['resnet152']))
+ return model
+
+
+def resnext50_32x4d(pretrained=False, filter_size=1, pool_only=True, **kwargs):
+ model = ResNet(Bottleneck, [3, 4, 6, 3], groups=4, width_per_group=32, filter_size=filter_size, pool_only=pool_only, **kwargs)
+ # if pretrained:
+ # model.load_state_dict(model_zoo.load_url(model_urls['resnet50']))
+ return model
+
+
+def resnext101_32x8d(pretrained=False, filter_size=1, pool_only=True, **kwargs):
+ model = ResNet(Bottleneck, [3, 4, 23, 3], groups=8, width_per_group=32, filter_size=filter_size, pool_only=pool_only, **kwargs)
+ # if pretrained:
+ # model.load_state_dict(model_zoo.load_url(model_urls['resnet50']))
+ return model
diff --git a/clean/image/universal/networks/trainer.py b/clean/image/universal/networks/trainer.py
new file mode 100644
index 0000000000000000000000000000000000000000..73d5bc0bcf5d48117e473900b38088c738f9c555
--- /dev/null
+++ b/clean/image/universal/networks/trainer.py
@@ -0,0 +1,74 @@
+import functools
+import torch
+import torch.nn as nn
+from networks.base_model import BaseModel, init_weights
+import sys
+from models import get_model
+
+class Trainer(BaseModel):
+ def name(self):
+ return 'Trainer'
+
+ def __init__(self, opt):
+ super(Trainer, self).__init__(opt)
+ self.opt = opt
+ self.model = get_model(opt.arch)
+ torch.nn.init.normal_(self.model.fc.weight.data, 0.0, opt.init_gain)
+
+ if opt.fix_backbone:
+ params = []
+ for name, p in self.model.named_parameters():
+ if name=="fc.weight" or name=="fc.bias":
+ params.append(p)
+ else:
+ p.requires_grad = False
+ else:
+ print("Your backbone is not fixed. Are you sure you want to proceed? If this is a mistake, enable the --fix_backbone command during training and rerun")
+ import time
+ time.sleep(3)
+ params = self.model.parameters()
+
+
+
+ if opt.optim == 'adam':
+ self.optimizer = torch.optim.AdamW(params, lr=opt.lr, betas=(opt.beta1, 0.999), weight_decay=opt.weight_decay)
+ elif opt.optim == 'sgd':
+ self.optimizer = torch.optim.SGD(params, lr=opt.lr, momentum=0.0, weight_decay=opt.weight_decay)
+ else:
+ raise ValueError("optim should be [adam, sgd]")
+
+ self.loss_fn = nn.BCEWithLogitsLoss()
+
+ self.model.to(opt.gpu_ids[0])
+
+
+ def adjust_learning_rate(self, min_lr=1e-6):
+ for param_group in self.optimizer.param_groups:
+ param_group['lr'] /= 10.
+ if param_group['lr'] < min_lr:
+ return False
+ return True
+
+
+ def set_input(self, input):
+ self.input = input[0].to(self.device)
+ self.label = input[1].to(self.device).float()
+
+
+ def forward(self):
+ self.output = self.model(self.input)
+ self.output = self.output.view(-1).unsqueeze(1)
+
+
+ def get_loss(self):
+ return self.loss_fn(self.output.squeeze(1), self.label)
+
+ def optimize_parameters(self):
+ self.forward()
+ self.loss = self.loss_fn(self.output.squeeze(1), self.label)
+ self.optimizer.zero_grad()
+ self.loss.backward()
+ self.optimizer.step()
+
+
+
diff --git a/clean/image/universal/options/__init__.py b/clean/image/universal/options/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/clean/image/universal/options/base_options.py b/clean/image/universal/options/base_options.py
new file mode 100644
index 0000000000000000000000000000000000000000..69d35b17cf409eac0a55a74ed187f23028cb93c5
--- /dev/null
+++ b/clean/image/universal/options/base_options.py
@@ -0,0 +1,117 @@
+import argparse
+import os
+import util
+import torch
+
+
+class BaseOptions():
+ def __init__(self):
+ self.initialized = False
+
+ def initialize(self, parser):
+ parser.add_argument('--mode', default='binary')
+ parser.add_argument('--arch', type=str, default='res50', help='see my_models/__init__.py')
+ parser.add_argument('--fix_backbone', action='store_true')
+
+ # data augmentation
+ parser.add_argument('--rz_interp', default='bilinear')
+ parser.add_argument('--blur_prob', type=float, default=0.5)
+ parser.add_argument('--blur_sig', default='0.0,3.0')
+ parser.add_argument('--jpg_prob', type=float, default=0.5)
+ parser.add_argument('--jpg_method', default='cv2,pil')
+ parser.add_argument('--jpg_qual', default='30,100')
+
+
+ parser.add_argument('--real_list_path', default=None, help='only used if data_mode==ours: path for the list of real images, which should contain train.pickle and val.pickle')
+ parser.add_argument('--fake_list_path', default=None, help='only used if data_mode==ours: path for the list of fake images, which should contain train.pickle and val.pickle')
+ parser.add_argument('--wang2020_data_path', default=None, help='only used if data_mode==wang2020 it should contain train and test folders')
+ parser.add_argument('--data_mode', default='ours', help='wang2020 or ours')
+ parser.add_argument('--data_label', default='train', help='label to decide whether train or validation dataset')
+ parser.add_argument('--weight_decay', type=float, default=0.0, help='loss weight for l2 reg')
+
+ parser.add_argument('--class_bal', action='store_true') # what is this ?
+ parser.add_argument('--batch_size', type=int, default=256, help='input batch size')
+ parser.add_argument('--loadSize', type=int, default=256, help='scale images to this size')
+ parser.add_argument('--cropSize', type=int, default=224, help='then crop to this size')
+ parser.add_argument('--gpu_ids', type=str, default='0', help='gpu ids: e.g. 0 0,1,2, 0,2. use -1 for CPU')
+ parser.add_argument('--name', type=str, default='experiment_name', help='name of the experiment. It decides where to store samples and models')
+ parser.add_argument('--num_threads', default=4, type=int, help='# threads for loading data')
+ parser.add_argument('--checkpoints_dir', type=str, default='./checkpoints', help='models are saved here')
+ parser.add_argument('--serial_batches', action='store_true', help='if true, takes images in order to make batches, otherwise takes them randomly')
+ parser.add_argument('--resize_or_crop', type=str, default='scale_and_crop', help='scaling and cropping of images at load time [resize_and_crop|crop|scale_width|scale_width_and_crop|none]')
+ parser.add_argument('--no_flip', action='store_true', help='if specified, do not flip the images for data augmentation')
+ parser.add_argument('--init_type', type=str, default='normal', help='network initialization [normal|xavier|kaiming|orthogonal]')
+ parser.add_argument('--init_gain', type=float, default=0.02, help='scaling factor for normal, xavier and orthogonal.')
+ parser.add_argument('--suffix', default='', type=str, help='customized suffix: opt.name = opt.name + suffix: e.g., {model}_{netG}_size{loadSize}')
+ self.initialized = True
+ return parser
+
+ def gather_options(self):
+ # initialize parser with basic options
+ if not self.initialized:
+ parser = argparse.ArgumentParser(
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+ parser = self.initialize(parser)
+
+ # get the basic options
+ opt, _ = parser.parse_known_args()
+ self.parser = parser
+
+ return parser.parse_args()
+
+ def print_options(self, opt):
+ message = ''
+ message += '----------------- Options ---------------\n'
+ for k, v in sorted(vars(opt).items()):
+ comment = ''
+ default = self.parser.get_default(k)
+ if v != default:
+ comment = '\t[default: %s]' % str(default)
+ message += '{:>25}: {:<30}{}\n'.format(str(k), str(v), comment)
+ message += '----------------- End -------------------'
+ print(message)
+
+ # save to the disk
+ expr_dir = os.path.join(opt.checkpoints_dir, opt.name)
+ util.mkdirs(expr_dir)
+ file_name = os.path.join(expr_dir, 'opt.txt')
+ with open(file_name, 'wt') as opt_file:
+ opt_file.write(message)
+ opt_file.write('\n')
+
+ def parse(self, print_options=True):
+
+ opt = self.gather_options()
+ opt.isTrain = self.isTrain # train or test
+
+ # process opt.suffix
+ if opt.suffix:
+ suffix = ('_' + opt.suffix.format(**vars(opt))) if opt.suffix != '' else ''
+ opt.name = opt.name + suffix
+
+ if print_options:
+ self.print_options(opt)
+
+ # set gpu ids
+ str_ids = opt.gpu_ids.split(',')
+ opt.gpu_ids = []
+ for str_id in str_ids:
+ id = int(str_id)
+ if id >= 0:
+ opt.gpu_ids.append(id)
+ if len(opt.gpu_ids) > 0:
+ torch.cuda.set_device(opt.gpu_ids[0])
+
+ # additional
+ #opt.classes = opt.classes.split(',')
+ opt.rz_interp = opt.rz_interp.split(',')
+ opt.blur_sig = [float(s) for s in opt.blur_sig.split(',')]
+ opt.jpg_method = opt.jpg_method.split(',')
+ opt.jpg_qual = [int(s) for s in opt.jpg_qual.split(',')]
+ if len(opt.jpg_qual) == 2:
+ opt.jpg_qual = list(range(opt.jpg_qual[0], opt.jpg_qual[1] + 1))
+ elif len(opt.jpg_qual) > 2:
+ raise ValueError("Shouldn't have more than 2 values for --jpg_qual.")
+
+ self.opt = opt
+ return self.opt
diff --git a/clean/image/universal/options/test_options.py b/clean/image/universal/options/test_options.py
new file mode 100644
index 0000000000000000000000000000000000000000..f824c7aae81d325bf81e16c5a5e2c1931ccd5b34
--- /dev/null
+++ b/clean/image/universal/options/test_options.py
@@ -0,0 +1,13 @@
+from .base_options import BaseOptions
+
+
+class TestOptions(BaseOptions):
+ def initialize(self, parser):
+ parser = BaseOptions.initialize(self, parser)
+ parser.add_argument('--model_path')
+ parser.add_argument('--no_resize', action='store_true')
+ parser.add_argument('--no_crop', action='store_true')
+ parser.add_argument('--eval', action='store_true', help='use eval mode during test time.')
+
+ self.isTrain = False
+ return parser
diff --git a/clean/image/universal/options/train_options.py b/clean/image/universal/options/train_options.py
new file mode 100644
index 0000000000000000000000000000000000000000..e7f1e54cea63ef424ad84d1ccaa1538e74119466
--- /dev/null
+++ b/clean/image/universal/options/train_options.py
@@ -0,0 +1,22 @@
+from .base_options import BaseOptions
+
+
+class TrainOptions(BaseOptions):
+ def initialize(self, parser):
+ parser = BaseOptions.initialize(self, parser)
+ parser.add_argument('--earlystop_epoch', type=int, default=5)
+ parser.add_argument('--data_aug', action='store_true', help='if specified, perform additional data augmentation (photometric, blurring, jpegging)')
+ parser.add_argument('--optim', type=str, default='adam', help='optim to use [sgd, adam]')
+ parser.add_argument('--new_optim', action='store_true', help='new optimizer instead of loading the optim state')
+ parser.add_argument('--loss_freq', type=int, default=400, help='frequency of showing loss on tensorboard')
+ parser.add_argument('--save_epoch_freq', type=int, default=1, help='frequency of saving checkpoints at the end of epochs')
+ parser.add_argument('--epoch_count', type=int, default=1, help='the starting epoch count, we save the model by , +, ...')
+ parser.add_argument('--last_epoch', type=int, default=-1, help='starting epoch count for scheduler intialization')
+ parser.add_argument('--train_split', type=str, default='train', help='train, val, test, etc')
+ parser.add_argument('--val_split', type=str, default='val', help='train, val, test, etc')
+ parser.add_argument('--niter', type=int, default=100, help='total epoches')
+ parser.add_argument('--beta1', type=float, default=0.9, help='momentum term of adam')
+ parser.add_argument('--lr', type=float, default=0.0001, help='initial learning rate for adam')
+
+ self.isTrain = True
+ return parser
diff --git a/clean/image/universal/pretrained_weights/fc_weights.pth b/clean/image/universal/pretrained_weights/fc_weights.pth
new file mode 100644
index 0000000000000000000000000000000000000000..989708188fa14aa3f7ddfcddb579d7b9426d5e8e
--- /dev/null
+++ b/clean/image/universal/pretrained_weights/fc_weights.pth
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:477100745713bcc957beb2b40859536859b6483fd6301b3b9293151b194c7847
+size 4083
diff --git a/clean/image/universal/test.sh b/clean/image/universal/test.sh
new file mode 100644
index 0000000000000000000000000000000000000000..983d05b7c4cf0e8b0a977b835849a102fa8b75fc
--- /dev/null
+++ b/clean/image/universal/test.sh
@@ -0,0 +1 @@
+CUDA_VISIBLE_DEVICES=0 python3 validate.py --arch=CLIP:ViT-L/14 --ckpt=pretrained_weights/fc_weights.pth --result_folder=clip_vitl14
diff --git a/clean/image/universal/train.py b/clean/image/universal/train.py
new file mode 100644
index 0000000000000000000000000000000000000000..c24917730db61c90f62015ca68572b83219e2050
--- /dev/null
+++ b/clean/image/universal/train.py
@@ -0,0 +1,85 @@
+import os
+import time
+from tensorboardX import SummaryWriter
+
+from validate import validate
+from data import create_dataloader
+from earlystop import EarlyStopping
+from networks.trainer import Trainer
+from options.train_options import TrainOptions
+
+
+"""Currently assumes jpg_prob, blur_prob 0 or 1"""
+def get_val_opt():
+ val_opt = TrainOptions().parse(print_options=False)
+ val_opt.isTrain = False
+ val_opt.no_resize = False
+ val_opt.no_crop = False
+ val_opt.serial_batches = True
+ val_opt.data_label = 'val'
+ val_opt.jpg_method = ['pil']
+ if len(val_opt.blur_sig) == 2:
+ b_sig = val_opt.blur_sig
+ val_opt.blur_sig = [(b_sig[0] + b_sig[1]) / 2]
+ if len(val_opt.jpg_qual) != 1:
+ j_qual = val_opt.jpg_qual
+ val_opt.jpg_qual = [int((j_qual[0] + j_qual[-1]) / 2)]
+
+ return val_opt
+
+
+
+if __name__ == '__main__':
+ opt = TrainOptions().parse()
+ val_opt = get_val_opt()
+
+ model = Trainer(opt)
+
+ data_loader = create_dataloader(opt)
+ val_loader = create_dataloader(val_opt)
+
+ train_writer = SummaryWriter(os.path.join(opt.checkpoints_dir, opt.name, "train"))
+ val_writer = SummaryWriter(os.path.join(opt.checkpoints_dir, opt.name, "val"))
+
+ early_stopping = EarlyStopping(patience=opt.earlystop_epoch, delta=-0.001, verbose=True)
+ start_time = time.time()
+ print ("Length of data loader: %d" %(len(data_loader)))
+ for epoch in range(opt.niter):
+
+ for i, data in enumerate(data_loader):
+ model.total_steps += 1
+
+ model.set_input(data)
+ model.optimize_parameters()
+
+ if model.total_steps % opt.loss_freq == 0:
+ print("Train loss: {} at step: {}".format(model.loss, model.total_steps))
+ train_writer.add_scalar('loss', model.loss, model.total_steps)
+ print("Iter time: ", ((time.time()-start_time)/model.total_steps) )
+
+ if model.total_steps in [10,30,50,100,1000,5000,10000] and False: # save models at these iters
+ model.save_networks('model_iters_%s.pth' % model.total_steps)
+
+ if epoch % opt.save_epoch_freq == 0:
+ print('saving the model at the end of epoch %d' % (epoch))
+ model.save_networks( 'model_epoch_best.pth' )
+ model.save_networks( 'model_epoch_%s.pth' % epoch )
+
+ # Validation
+ model.eval()
+ ap, r_acc, f_acc, acc = validate(model.model, val_loader)
+ val_writer.add_scalar('accuracy', acc, model.total_steps)
+ val_writer.add_scalar('ap', ap, model.total_steps)
+ print("(Val @ epoch {}) acc: {}; ap: {}".format(epoch, acc, ap))
+
+ early_stopping(acc, model)
+ if early_stopping.early_stop:
+ cont_train = model.adjust_learning_rate()
+ if cont_train:
+ print("Learning rate dropped by 10, continue training...")
+ early_stopping = EarlyStopping(patience=opt.earlystop_epoch, delta=-0.002, verbose=True)
+ else:
+ print("Early stopping.")
+ break
+ model.train()
+
diff --git a/clean/image/universal/validate.py b/clean/image/universal/validate.py
new file mode 100644
index 0000000000000000000000000000000000000000..4887014457e584b5801e868a229db98bbd70117c
--- /dev/null
+++ b/clean/image/universal/validate.py
@@ -0,0 +1,312 @@
+import argparse
+from ast import arg
+import os
+import csv
+import torch
+import torchvision.transforms as transforms
+import torch.utils.data
+import numpy as np
+from sklearn.metrics import average_precision_score, precision_recall_curve, accuracy_score
+from torch.utils.data import Dataset
+import sys
+from models import get_model
+from PIL import Image
+import pickle
+from tqdm import tqdm
+from io import BytesIO
+from copy import deepcopy
+from dataset_paths import DATASET_PATHS
+import random
+import shutil
+from scipy.ndimage.filters import gaussian_filter
+
+SEED = 0
+def set_seed():
+ torch.manual_seed(SEED)
+ torch.cuda.manual_seed(SEED)
+ np.random.seed(SEED)
+ random.seed(SEED)
+
+
+MEAN = {
+ "imagenet":[0.485, 0.456, 0.406],
+ "clip":[0.48145466, 0.4578275, 0.40821073]
+}
+
+STD = {
+ "imagenet":[0.229, 0.224, 0.225],
+ "clip":[0.26862954, 0.26130258, 0.27577711]
+}
+
+
+
+
+
+def find_best_threshold(y_true, y_pred):
+ "We assume first half is real 0, and the second half is fake 1"
+
+ N = y_true.shape[0]
+
+ if y_pred[0:N//2].max() <= y_pred[N//2:N].min(): # perfectly separable case
+ return (y_pred[0:N//2].max() + y_pred[N//2:N].min()) / 2
+
+ best_acc = 0
+ best_thres = 0
+ for thres in y_pred:
+ temp = deepcopy(y_pred)
+ temp[temp>=thres] = 1
+ temp[temp= best_acc:
+ best_thres = thres
+ best_acc = acc
+
+ return best_thres
+
+
+
+def png2jpg(img, quality):
+ out = BytesIO()
+ img.save(out, format='jpeg', quality=quality) # ranging from 0-95, 75 is default
+ img = Image.open(out)
+ # load from memory before ByteIO closes
+ img = np.array(img)
+ out.close()
+ return Image.fromarray(img)
+
+
+def gaussian_blur(img, sigma):
+ img = np.array(img)
+
+ gaussian_filter(img[:,:,0], output=img[:,:,0], sigma=sigma)
+ gaussian_filter(img[:,:,1], output=img[:,:,1], sigma=sigma)
+ gaussian_filter(img[:,:,2], output=img[:,:,2], sigma=sigma)
+
+ return Image.fromarray(img)
+
+
+
+def calculate_acc(y_true, y_pred, thres):
+ r_acc = accuracy_score(y_true[y_true==0], y_pred[y_true==0] > thres)
+ f_acc = accuracy_score(y_true[y_true==1], y_pred[y_true==1] > thres)
+ acc = accuracy_score(y_true, y_pred > thres)
+ return r_acc, f_acc, acc
+
+
+def validate(model, loader, find_thres=False):
+
+ with torch.no_grad():
+ y_true, y_pred = [], []
+ print ("Length of dataset: %d" %(len(loader)))
+ for img, label in loader:
+ in_tens = img.cuda()
+
+ y_pred.extend(model(in_tens).sigmoid().flatten().tolist())
+ y_true.extend(label.flatten().tolist())
+
+ y_true, y_pred = np.array(y_true), np.array(y_pred)
+
+ # ================== save this if you want to plot the curves =========== #
+ # torch.save( torch.stack( [torch.tensor(y_true), torch.tensor(y_pred)] ), 'baseline_predication_for_pr_roc_curve.pth' )
+ # exit()
+ # =================================================================== #
+
+ # Get AP
+ ap = average_precision_score(y_true, y_pred)
+
+ # Acc based on 0.5
+ r_acc0, f_acc0, acc0 = calculate_acc(y_true, y_pred, 0.5)
+ if not find_thres:
+ return ap, r_acc0, f_acc0, acc0
+
+
+ # Acc based on the best thres
+ best_thres = find_best_threshold(y_true, y_pred)
+ r_acc1, f_acc1, acc1 = calculate_acc(y_true, y_pred, best_thres)
+
+ return ap, r_acc0, f_acc0, acc0, r_acc1, f_acc1, acc1, best_thres
+
+
+
+
+
+
+# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = #
+
+
+
+
+def recursively_read(rootdir, must_contain, exts=["png", "jpg", "JPEG", "jpeg", "bmp"]):
+ out = []
+ for r, d, f in os.walk(rootdir):
+ for file in f:
+ if (file.split('.')[1] in exts) and (must_contain in os.path.join(r, file)):
+ out.append(os.path.join(r, file))
+ return out
+
+
+def get_list(path, must_contain=''):
+ if ".pickle" in path:
+ with open(path, 'rb') as f:
+ image_list = pickle.load(f)
+ image_list = [ item for item in image_list if must_contain in item ]
+ else:
+ image_list = recursively_read(path, must_contain)
+ return image_list
+
+
+
+
+
+class RealFakeDataset(Dataset):
+ def __init__(self, real_path,
+ fake_path,
+ data_mode,
+ max_sample,
+ arch,
+ jpeg_quality=None,
+ gaussian_sigma=None):
+
+ assert data_mode in ["wang2020", "ours"]
+ self.jpeg_quality = jpeg_quality
+ self.gaussian_sigma = gaussian_sigma
+
+ # = = = = = = data path = = = = = = = = = #
+ if type(real_path) == str and type(fake_path) == str:
+ real_list, fake_list = self.read_path(real_path, fake_path, data_mode, max_sample)
+ else:
+ real_list = []
+ fake_list = []
+ for real_p, fake_p in zip(real_path, fake_path):
+ real_l, fake_l = self.read_path(real_p, fake_p, data_mode, max_sample)
+ real_list += real_l
+ fake_list += fake_l
+
+ self.total_list = real_list + fake_list
+
+
+ # = = = = = = label = = = = = = = = = #
+
+ self.labels_dict = {}
+ for i in real_list:
+ self.labels_dict[i] = 0
+ for i in fake_list:
+ self.labels_dict[i] = 1
+
+ stat_from = "imagenet" if arch.lower().startswith("imagenet") else "clip"
+ self.transform = transforms.Compose([
+ transforms.CenterCrop(224),
+ transforms.ToTensor(),
+ transforms.Normalize( mean=MEAN[stat_from], std=STD[stat_from] ),
+ ])
+
+
+ def read_path(self, real_path, fake_path, data_mode, max_sample):
+
+ if data_mode == 'wang2020':
+ real_list = get_list(real_path, must_contain='0_real')
+ fake_list = get_list(fake_path, must_contain='1_fake')
+ else:
+ real_list = get_list(real_path)
+ fake_list = get_list(fake_path)
+
+
+ if max_sample is not None:
+ if (max_sample > len(real_list)) or (max_sample > len(fake_list)):
+ max_sample = 100
+ print("not enough images, max_sample falling to 100")
+ random.shuffle(real_list)
+ random.shuffle(fake_list)
+ real_list = real_list[0:max_sample]
+ fake_list = fake_list[0:max_sample]
+
+ assert len(real_list) == len(fake_list)
+
+ return real_list, fake_list
+
+
+
+ def __len__(self):
+ return len(self.total_list)
+
+ def __getitem__(self, idx):
+
+ img_path = self.total_list[idx]
+
+ label = self.labels_dict[img_path]
+ img = Image.open(img_path).convert("RGB")
+
+ if self.gaussian_sigma is not None:
+ img = gaussian_blur(img, self.gaussian_sigma)
+ if self.jpeg_quality is not None:
+ img = png2jpg(img, self.jpeg_quality)
+
+ img = self.transform(img)
+ return img, label
+
+
+
+
+
+if __name__ == '__main__':
+
+
+ parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+ parser.add_argument('--real_path', type=str, default=None, help='dir name or a pickle')
+ parser.add_argument('--fake_path', type=str, default=None, help='dir name or a pickle')
+ parser.add_argument('--data_mode', type=str, default=None, help='wang2020 or ours')
+ parser.add_argument('--max_sample', type=int, default=1000, help='only check this number of images for both fake/real')
+
+ parser.add_argument('--arch', type=str, default='res50')
+ parser.add_argument('--ckpt', type=str, default='./pretrained_weights/fc_weights.pth')
+
+ parser.add_argument('--result_folder', type=str, default='result', help='')
+ parser.add_argument('--batch_size', type=int, default=128)
+
+ parser.add_argument('--jpeg_quality', type=int, default=None, help="100, 90, 80, ... 30. Used to test robustness of our model. Not apply if None")
+ parser.add_argument('--gaussian_sigma', type=int, default=None, help="0,1,2,3,4. Used to test robustness of our model. Not apply if None")
+
+
+ opt = parser.parse_args()
+
+
+ if os.path.exists(opt.result_folder):
+ shutil.rmtree(opt.result_folder)
+ os.makedirs(opt.result_folder)
+
+ model = get_model(opt.arch)
+ state_dict = torch.load(opt.ckpt, map_location='cpu')
+ model.fc.load_state_dict(state_dict)
+ print ("Model loaded..")
+ model.eval()
+ model.cuda()
+
+ if (opt.real_path == None) or (opt.fake_path == None) or (opt.data_mode == None):
+ dataset_paths = DATASET_PATHS
+ else:
+ dataset_paths = [ dict(real_path=opt.real_path, fake_path=opt.fake_path, data_mode=opt.data_mode) ]
+
+
+
+ for dataset_path in (dataset_paths):
+ set_seed()
+
+ dataset = RealFakeDataset( dataset_path['real_path'],
+ dataset_path['fake_path'],
+ dataset_path['data_mode'],
+ opt.max_sample,
+ opt.arch,
+ jpeg_quality=opt.jpeg_quality,
+ gaussian_sigma=opt.gaussian_sigma,
+ )
+
+ loader = torch.utils.data.DataLoader(dataset, batch_size=opt.batch_size, shuffle=False, num_workers=4)
+ ap, r_acc0, f_acc0, acc0, r_acc1, f_acc1, acc1, best_thres = validate(model, loader, find_thres=True)
+
+ with open( os.path.join(opt.result_folder,'ap.txt'), 'a') as f:
+ f.write(dataset_path['key']+': ' + str(round(ap*100, 2))+'\n' )
+
+ with open( os.path.join(opt.result_folder,'acc0.txt'), 'a') as f:
+ f.write(dataset_path['key']+': ' + str(round(r_acc0*100, 2))+' '+str(round(f_acc0*100, 2))+' '+str(round(acc0*100, 2))+'\n' )
+
diff --git a/clean/image/yermandy/.gitignore b/clean/image/yermandy/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..a5d17de4a4457afba2a4267f091f379fd8e8837b
--- /dev/null
+++ b/clean/image/yermandy/.gitignore
@@ -0,0 +1,12 @@
+__pycache__
+.vscode
+
+/config
+/datasets
+/outputs
+/runs
+/weights
+
+x.py
+y.py
+z.py
\ No newline at end of file
diff --git a/clean/image/yermandy/.project-root b/clean/image/yermandy/.project-root
new file mode 100644
index 0000000000000000000000000000000000000000..29575ae1d00627ae11eb501608ce64b5b16a510c
--- /dev/null
+++ b/clean/image/yermandy/.project-root
@@ -0,0 +1 @@
+# Do not remove, this file is used by the project to determine the root of the project
diff --git a/clean/image/yermandy/LICENSE b/clean/image/yermandy/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..2a7c37c99286ffa4a0fd09c7b823e33696496b68
--- /dev/null
+++ b/clean/image/yermandy/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2025 Andy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/clean/image/yermandy/README.md b/clean/image/yermandy/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..7043fc28a5e9128725fa51102d61a1599ef17e8f
--- /dev/null
+++ b/clean/image/yermandy/README.md
@@ -0,0 +1,142 @@
+# ❗ Updated WACV 2026 paper announcement ❗
+
+We are excited to announce that our [new paper](https://arxiv.org/abs/2508.06248) has been accepted to WACV 2026! The updated version includes additional experiments, models, and insights. Check out the latest version on [GitHub](https://github.com/yermandy/GenD).
+
+---
+
+## Unlocking the Hidden Potential of CLIP in Generalizable Deepfake Detection
+
+[](https://arxiv.org/abs/2503.19683)
+[](https://huggingface.co/yermandy/deepfake-detection)
+
+This is the official repository for the paper:
+
+**[Unlocking the Hidden Potential of CLIP in Generalizable Deepfake Detection](https://arxiv.org/abs/2503.19683)**.
+
+### Abstract
+
+> This paper tackles the challenge of detecting partially manipulated facial deepfakes, which involve subtle alterations to specific facial features while retaining the overall context, posing a greater detection difficulty than fully synthetic faces. We leverage the Contrastive Language-Image Pre-training (CLIP) model, specifically its ViT-L/14 visual encoder, to develop a generalizable detection method that performs robustly across diverse datasets and unknown forgery techniques with minimal modifications to the original model. The proposed approach utilizes parameter-efficient fine-tuning (PEFT) techniques, such as LN-tuning, to adjust a small subset of the model's parameters, preserving CLIP's pre-trained knowledge and reducing overfitting. A tailored preprocessing pipeline optimizes the method for facial images, while regularization strategies, including L2 normalization and metric learning on a hyperspherical manifold, enhance generalization. Trained on the FaceForensics++ dataset and evaluated in a cross-dataset fashion on Celeb-DF-v2, DFDC, FFIW, and others, the proposed method achieves competitive detection accuracy comparable to or outperforming much more complex state-of-the-art techniques. This work highlights the efficacy of CLIP's visual encoder in facial deepfake detection and establishes a simple, powerful baseline for future research, advancing the field of generalizable deepfake detection.
+
+
+## Set up environment
+
+``` bash
+conda create --name dfdet python=3.12 uv
+conda activate dfdet
+uv pip install -r requirements.txt
+```
+
+## Minimal inference example
+
+**❗ Important note**: sample images are already preprocessed. To get the same results as in the paper, you need to preprocess images using DeepfakeBench [preprocessing](https://github.com/SCLBD/DeepfakeBench/blob/fb6171a8e1db2ae0f017d9f3a12be31fd9e0a3fb/preprocessing/preprocess.py) pipeline.
+
+### Minimal dependencies (torch + transformers)
+
+This example requires only `torch` and `transformers` to run. This is an easy-to-integrate solution. The model has been traced and saved to a [`model.torchscript`](https://huggingface.co/yermandy/deepfake-detection/tree/main) file. Run:
+
+``` bash
+python inference_torchscript.py
+```
+
+Results might be a little bit different than in **precise inference** ↓
+
+### Precise inference (full dependencies)
+
+Read `inference.py`, it automatically downloads the model from [huggingface](https://huggingface.co/yermandy/deepfake-detection/tree/main) and runs inference on sample images.
+
+``` bash
+python inference.py
+```
+
+## Training
+
+### Minimal example without external data
+
+#### Run Training
+
+You can adjust training configuration in `get_train_config` function in `run.py` or override them with command line arguments. Command line arguments have higher priority.
+
+Example changing configurations in `get_train_config`:
+
+1. Set `config.wandb = True` for logging to wandb
+
+2. Set `config.devices = [2]` for using GPU number 2
+
+``` bash
+python run.py --train
+```
+
+#### Run testing (for example, on other dataset)
+
+``` bash
+python run.py --test
+```
+
+---
+
+### Full training
+
+#### Prepare the dataset
+
+To fully train the model, you need to download datasets, preprocess them, and create a file with paths to the images.
+
+For example, if you want to work with the [FaceForensics++](https://github.com/ondyari/FaceForensics) dataset, follow these steps:
+
+1. Download the dataset first from the [official source](https://github.com/ondyari/FaceForensics)
+
+2. Preprocess the dataset using [DeepfakeBench](https://github.com/SCLBD/DeepfakeBench)
+
+3. Place images in the recommended directory structure: `datasets / / / / `, see `src/dataset/deepfake.py` for more details
+
+``` bash
+datasets
+└── FF
+ ├── DF
+ │ └── 000_003
+ │ ├── 025.png
+ │ └── 038.png
+ ├── F2F
+ │ └── 000_003
+ │ ├── 019.png
+ │ └── 029.png
+ ├── FS
+ │ └── 000_003
+ │ ├── 019.png
+ │ └── 029.png
+ ├── NT
+ │ └── 000_003
+ │ ├── 019.png
+ │ └── 029.png
+ └── real
+ └── 000
+ ├── 025.png
+ └── 038.png
+```
+
+4. Create files with paths to images similar to the ones in `config/datasets` directory. Get inspired by this script:
+
+``` bash
+sh scripts/prepare_FF.sh
+```
+
+#### Run training
+
+Adjust training configuration as needed before executing the command below:
+
+``` bash
+python run.py --train
+```
+
+### Cite
+
+``` bibtex
+@article{yermakov-2025-deepfake-detection,
+ title={Unlocking the Hidden Potential of CLIP in Generalizable Deepfake Detection},
+ author={Andrii Yermakov and Jan Cech and Jiri Matas},
+ year={2025},
+ eprint={2503.19683},
+ archivePrefix={arXiv},
+ primaryClass={cs.CV},
+ url={https://arxiv.org/abs/2503.19683},
+}
+```
diff --git a/clean/image/yermandy/SOURCE.md b/clean/image/yermandy/SOURCE.md
new file mode 100644
index 0000000000000000000000000000000000000000..53ef04117881fe6fa2e851a257a1d74b1a8e7cd1
--- /dev/null
+++ b/clean/image/yermandy/SOURCE.md
@@ -0,0 +1,17 @@
+# Source: image/yermandy
+
+| Field | Value |
+|---|---|
+| Upstream | https://github.com/yermandy/GenD |
+| Paper | https://arxiv.org/abs/2508.06248 |
+| Commit SHA | **not recorded** -- the vendoring step did not preserve it |
+| Mirrored on | 2026-09-15 |
+| Upstream license | LICENSE |
+
+This is a **mirror**, stripped to the files needed for inference. The full
+untouched snapshot is at `archive/image__yermandy.tar.gz`.
+
+This code is the work of its original authors and is **not** covered by the
+DeepSafe project license. If you are an author and want this removed, open an
+issue on https://github.com/deepsafehq/deepsafe-bench and it will be taken down
+within 48 hours, no questions asked.
diff --git a/clean/image/yermandy/inference.py b/clean/image/yermandy/inference.py
new file mode 100644
index 0000000000000000000000000000000000000000..67b3f769621e1baa7c0df7970d4f6f3580fd258b
--- /dev/null
+++ b/clean/image/yermandy/inference.py
@@ -0,0 +1,74 @@
+import torch
+from huggingface_hub import hf_hub_download
+from lightning.fabric import Fabric
+from PIL import Image
+
+from src.config import Config
+from src.model.dfdet import DeepfakeDetectionModel
+
+DEVICES = [0]
+
+torch.set_float32_matmul_precision("high")
+
+# Check if weights/model.ckpt exists, if not, download it from huggingface
+repo_id = "yermandy/deepfake-detection"
+filename = "model.ckpt"
+
+model_path = hf_hub_download(repo_id=repo_id, filename=filename, local_dir="weights")
+
+# Load checkpoint
+ckpt = torch.load(model_path, map_location="cpu")
+
+run_name = ckpt["hyper_parameters"]["run_name"]
+print(run_name)
+
+# Initialize model from config
+model = DeepfakeDetectionModel(Config(**ckpt["hyper_parameters"]))
+model.eval()
+
+# Load model state dict
+model.load_state_dict(ckpt["state_dict"])
+
+# Get preprocessing function
+preprocessing = model.get_preprocessing()
+
+# Load some images
+paths = [
+ "datasets/CDFv2/Celeb-synthesis/id0_id1_0000/000.png",
+ "datasets/CDFv2/Celeb-synthesis/id0_id1_0000/045.png",
+ "datasets/CDFv2/Celeb-synthesis/id0_id1_0000/030.png",
+ "datasets/CDFv2/Celeb-synthesis/id0_id1_0000/015.png",
+ "datasets/CDFv2/YouTube-real/00000/000.png",
+ "datasets/CDFv2/YouTube-real/00000/014.png",
+ "datasets/CDFv2/YouTube-real/00000/028.png",
+ "datasets/CDFv2/YouTube-real/00000/043.png",
+ "datasets/CDFv2/Celeb-real/id0_0000/045.png",
+ "datasets/CDFv2/Celeb-real/id0_0000/030.png",
+ "datasets/CDFv2/Celeb-real/id0_0000/015.png",
+ "datasets/CDFv2/Celeb-real/id0_0000/000.png",
+]
+
+# To pillow images
+pillow_images = [Image.open(image) for image in paths]
+
+# To tensors
+batch_images = torch.stack([preprocessing(image) for image in pillow_images])
+
+precision = ckpt["hyper_parameters"]["precision"]
+fabric = Fabric(accelerator="cuda", devices=DEVICES, precision=precision)
+fabric.launch()
+model = fabric.setup_module(model)
+
+# perform inference
+with torch.no_grad():
+ # Move batch_images to the correct device and dtype
+ batch_images = batch_images.to(fabric.device).to(model.dtype)
+
+ # Forward pass
+ output = model(batch_images)
+
+# logits to probabilities
+softmax_output = output.logits_labels.softmax(dim=1).cpu().numpy()
+
+for path, (p_real, p_fake) in zip(paths, softmax_output):
+ print(f"p(real) = {p_real:.4f}, p(fake) = {p_fake:.4f}, image: {path}")
diff --git a/clean/image/yermandy/inference_torchscript.py b/clean/image/yermandy/inference_torchscript.py
new file mode 100644
index 0000000000000000000000000000000000000000..557ff606fb23b03c9a9d70c14fb5ed87e460328a
--- /dev/null
+++ b/clean/image/yermandy/inference_torchscript.py
@@ -0,0 +1,65 @@
+import torch
+from huggingface_hub import hf_hub_download
+from PIL import Image
+from transformers import CLIPProcessor
+
+DEVICE = "cuda:0"
+DTYPE = torch.bfloat16
+
+
+torch.set_float32_matmul_precision("high")
+
+# Check if weights/model.torchscript exists, if not, download it from huggingface
+repo_id = "yermandy/deepfake-detection"
+filename = "model.torchscript"
+
+model_path = hf_hub_download(repo_id=repo_id, filename=filename, local_dir="weights")
+
+# Load checkpoint
+model = torch.jit.load(model_path, map_location=DEVICE)
+
+# Load preprocessing function
+preprocess = CLIPProcessor.from_pretrained("openai/clip-vit-large-patch14")
+
+# Load some images
+paths = [
+ "datasets/CDFv2/Celeb-synthesis/id0_id1_0000/000.png",
+ "datasets/CDFv2/Celeb-synthesis/id0_id1_0000/045.png",
+ "datasets/CDFv2/Celeb-synthesis/id0_id1_0000/030.png",
+ "datasets/CDFv2/Celeb-synthesis/id0_id1_0000/015.png",
+ "datasets/CDFv2/YouTube-real/00000/000.png",
+ "datasets/CDFv2/YouTube-real/00000/014.png",
+ "datasets/CDFv2/YouTube-real/00000/028.png",
+ "datasets/CDFv2/YouTube-real/00000/043.png",
+ "datasets/CDFv2/Celeb-real/id0_0000/045.png",
+ "datasets/CDFv2/Celeb-real/id0_0000/030.png",
+ "datasets/CDFv2/Celeb-real/id0_0000/015.png",
+ "datasets/CDFv2/Celeb-real/id0_0000/000.png",
+]
+
+# To pillow images
+pillow_images = [Image.open(image) for image in paths]
+
+# To tensors
+batch_images = torch.stack(
+ [preprocess(images=image, return_tensors="pt")["pixel_values"][0] for image in pillow_images]
+)
+
+# Set model to evaluation mode
+model.eval()
+
+# Move model to the correct device and dtype
+model = model.to(DEVICE).to(DTYPE)
+
+# Move inputs to the correct device and dtype
+batch_images = batch_images.to(DEVICE).to(DTYPE)
+
+with torch.no_grad():
+ with torch.autocast(device_type="cuda", dtype=DTYPE):
+ # Forward pass
+ output = model(batch_images)
+
+ softmax_output = output.softmax(dim=1).cpu().numpy()
+
+for path, (p_real, p_fake) in zip(paths, softmax_output):
+ print(f"p(real) = {p_real:.4f}, p(fake) = {p_fake:.4f}, image: {path}")
diff --git a/clean/image/yermandy/pyproject.toml b/clean/image/yermandy/pyproject.toml
new file mode 100644
index 0000000000000000000000000000000000000000..b5eeb0819074b2128b33dfcbb6d899b91495c2b8
--- /dev/null
+++ b/clean/image/yermandy/pyproject.toml
@@ -0,0 +1,35 @@
+[tool.ruff]
+line-length = 120
+
+[tool.ruff.lint]
+ignore = [
+ "C901", # complex condition
+ "E501", # line too long
+ "F401", # imported but unused
+ "F403", # from module import * used; unable to detect undefined names
+ "F405", # name may be undefined, or defined from star imports: module
+ "E741", # ambiguous variable name
+]
+
+select = [
+ "C", # flake8-comprehensions
+ "E", "W", # pycodestyle
+ "F", # pyflakes
+ "I", # isort
+]
+
+[tool.ruff.lint.isort]
+force-to-top = ["autoroot", "autorootcwd"]
+
+[tool.ruff.lint.per-file-ignores]
+"**/__init__.py" = ["E402"]
+
+[tool.pyright]
+exclude = [
+ "**/__pycache__",
+ "wandb",
+ "datasets",
+ "outputs",
+ "runs",
+]
+typeCheckingMode = "off"
\ No newline at end of file
diff --git a/clean/image/yermandy/requirements.txt b/clean/image/yermandy/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7fb58413770d4dbc968655c646df90bc8433b5c9
--- /dev/null
+++ b/clean/image/yermandy/requirements.txt
@@ -0,0 +1,17 @@
+torch==2.6.0
+torchaudio==2.6.0
+torchvision==0.21.0
+lightning==2.5.0
+transformers==4.50.0
+tqdm==4.67.1 # progress bar
+timm==1.0.14 # torch models
+matplotlib==3.10.0 # visualization
+seaborn==0.13.2 # visualization
+scikit-learn==1.6.1 # metrics
+rich==13.9.4 # logging
+wandb==0.19.4 # logging
+pydantic==2.9.2 # config
+ruff==0.9.3 # formatting
+fire==0.7.0 # CLI
+peft==0.14.0 # parameter-efficient fine-tuning
+# ipykernel==6.29.5 # jupyter
\ No newline at end of file
diff --git a/clean/image/yermandy/run.py b/clean/image/yermandy/run.py
new file mode 100644
index 0000000000000000000000000000000000000000..e8e1560db38b5b2e99770fb47b1f3de424f5d643
--- /dev/null
+++ b/clean/image/yermandy/run.py
@@ -0,0 +1,214 @@
+import os
+from glob import glob
+
+import fire
+import lightning as pl
+import matplotlib.pyplot as plt
+import numpy as np
+import pandas as pd
+import rich
+import torch
+import torch.nn as nn
+import yaml
+from lightning import Trainer
+from lightning.pytorch import callbacks as pl_callbacks
+from lightning.pytorch import loggers as pl_loggers
+from rich import traceback
+
+from src import dataset as datasets
+from src import model as models
+from src.config import Backbone, Config, Head, load_config
+from src.utils import files
+from src.utils.checks import checks
+from src.utils.model_checkpoint import ModelCheckpointParallel
+
+traceback.install()
+
+
+def main(config: Config, train: bool):
+ checks(config)
+
+ torch.set_float32_matmul_precision("high") # Set the precision for matmul operations
+
+ model = models.DeepfakeDetectionModel(config, verbose=True)
+
+ if config.checkpoint:
+ model.load_state_dict(torch.load(config.checkpoint, map_location="cpu", weights_only=True)["state_dict"])
+
+ data_module = datasets.DeepfakeDataModule(config, model.get_preprocessing())
+
+ loggers: list = [pl_loggers.CSVLogger(config.run_dir, name=config.run_name, version="")]
+
+ if config.wandb:
+ wandb_logger = pl_loggers.WandbLogger(
+ project="deepfake",
+ name=config.run_name,
+ save_dir=f"{config.run_dir}/{config.run_name}",
+ tags=config.wandb_tags,
+ )
+ loggers.append(wandb_logger)
+
+ callbacks = [
+ pl_callbacks.RichProgressBar(),
+ ModelCheckpointParallel(filename="best_mAP", monitor="val/mAP_video", mode="max"),
+ ]
+
+ trainer = Trainer(
+ devices=config.devices,
+ max_epochs=config.max_epochs,
+ precision=config.precision,
+ accumulate_grad_batches=config.batch_size // config.mini_batch_size,
+ fast_dev_run=config.fast_dev_run,
+ log_every_n_steps=100,
+ overfit_batches=config.overfit_batches,
+ limit_train_batches=config.limit_train_batches,
+ limit_val_batches=config.limit_val_batches,
+ limit_test_batches=config.limit_test_batches,
+ deterministic=config.deterministic,
+ detect_anomaly=config.detect_anomaly,
+ logger=loggers,
+ callbacks=callbacks,
+ default_root_dir=config.run_dir,
+ )
+
+ if train:
+ trainer.fit(model, data_module)
+
+ ckpt_path = f"{config.run_dir}/{config.run_name}/checkpoints/{config.checkpoint_for_testing}.ckpt"
+ trainer.test(model, data_module, ckpt_path=ckpt_path)
+
+ else:
+ assert config.checkpoint is not None, "Checkpoint is required for testing"
+ trainer.test(model, data_module)
+
+ if config.wandb:
+ wandb_logger.finalize("success")
+ wandb_logger.experiment.finish()
+
+
+def get_train_config() -> Config:
+ config = Config()
+
+ config.run_name = "example-run"
+ config.run_dir = "runs/train"
+ config.wandb = False
+
+ config.num_workers = 12
+ config.devices = [2]
+
+ config.backbone = Backbone.CLIP_L_14
+ config.freeze_feature_extractor = True
+ config.peft.enabled = True
+ config.peft.ln_tuning.enabled = True
+ config.head = Head.LinearNorm
+ config.num_classes = 2
+ config.loss.ce_labels = 1.0
+ config.slerp_feature_augmentation = True
+
+ config.batch_size = config.mini_batch_size = 128
+ config.lr_scheduler = "cosine"
+ config.lr = 8e-5
+ config.min_lr = 5e-5
+ config.weight_decay = 0
+ config.max_epochs = 10
+
+ limit_val_files = 16384
+ config.limit_val_files = limit_val_files
+ config.limit_val_batches = limit_val_files // config.mini_batch_size
+
+ config.binary_labels = True
+ config.trn_files = [
+ "config/datasets/FF/test/DF.txt",
+ "config/datasets/FF/test/F2F.txt",
+ "config/datasets/FF/test/FS.txt",
+ "config/datasets/FF/test/NT.txt",
+ "config/datasets/FF/test/real.txt",
+ ]
+ config.val_files = [
+ "config/datasets/CDFv2/test/Celeb-synthesis.txt",
+ "config/datasets/CDFv2/test/Celeb-real.txt",
+ "config/datasets/CDFv2/test/YouTube-real.txt",
+ ]
+
+ config.tst_files = {
+ "CDF": [
+ "config/datasets/CDFv2/test/Celeb-synthesis.txt",
+ "config/datasets/CDFv2/test/Celeb-real.txt",
+ "config/datasets/CDFv2/test/YouTube-real.txt",
+ ]
+ }
+
+ return config
+
+
+def get_test_config() -> Config:
+ config_path = "runs/train/example-run/hparams.yaml"
+ new_run_name = "example-run"
+
+ config = load_config(config_path)
+
+ config.run_name = new_run_name
+ config.run_dir = "runs/test"
+ config.checkpoint = config_path.replace("hparams.yaml", "checkpoints/best_mAP.ckpt")
+ config.wandb = False
+ config.wandb_tags.extend(["test"])
+
+ config.num_workers = 12
+ config.batch_size = config.mini_batch_size = 512
+ config.devices = [0]
+
+ config.tst_files = {
+ "CDF": [
+ "config/datasets/CDFv2/test/Celeb-synthesis.txt",
+ "config/datasets/CDFv2/test/Celeb-real.txt",
+ "config/datasets/CDFv2/test/YouTube-real.txt",
+ ]
+ }
+
+ return config
+
+
+def get_debug_config(config: Config) -> Config:
+ #! Debug
+
+ config.run_name = "tmp"
+
+ config.devices = [2]
+
+ config.num_workers = 8
+ # config.batch_size = config.mini_batch_size = 512
+ config.max_epochs = 1
+ config.limit_train_batches = 12
+ config.limit_val_batches = 12
+ config.limit_test_batches = 12
+ config.deterministic = True
+ config.detect_anomaly = True
+
+ return config
+
+
+def entry(train: bool = False, test: bool = False, debug: bool = False, **kwargs):
+ if train:
+ config = get_train_config()
+
+ elif test:
+ config = get_test_config()
+
+ else:
+ raise ValueError("Either --train or --test must be provided")
+
+ # Overwrite config with debug values
+ if debug:
+ config = config.model_copy(update=dict(get_debug_config(config)))
+
+ # Parse command line arguments
+ config = config.model_copy(update=kwargs)
+
+ # Revalidate the config - checks if user provided valid values
+ config = Config(**dict(config))
+
+ main(config, train)
+
+
+if __name__ == "__main__":
+ fire.Fire(entry)
diff --git a/clean/image/yermandy/scripts/prepare_FF.sh b/clean/image/yermandy/scripts/prepare_FF.sh
new file mode 100644
index 0000000000000000000000000000000000000000..075165d50873fe97f6382b3ee0870fcc688b801e
--- /dev/null
+++ b/clean/image/yermandy/scripts/prepare_FF.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+if [ ! -f ".project-root" ]; then
+ echo "Please run this script from the root of the project"
+ exit 1
+fi
+
+DATASET_DIR=datasets/FF
+CONFIG_DIR=config/datasets/FF
+
+mkdir -p $DATASET_DIR
+mkdir -p $CONFIG_DIR/test
+
+find $DATASET_DIR/DF/* -type f | sort > $CONFIG_DIR/test/DF.txt
+find $DATASET_DIR/F2F/* -type f | sort > $CONFIG_DIR/test/F2F.txt
+find $DATASET_DIR/FS/* -type f | sort > $CONFIG_DIR/test/FS.txt
+find $DATASET_DIR/NT/* -type f | sort > $CONFIG_DIR/test/NT.txt
+find $DATASET_DIR/real/* -type f | sort > $CONFIG_DIR/test/real.txt
diff --git a/clean/image/yermandy/src/config.py b/clean/image/yermandy/src/config.py
new file mode 100644
index 0000000000000000000000000000000000000000..08b9b2a78b6938acf539999ee95274f75907a21b
--- /dev/null
+++ b/clean/image/yermandy/src/config.py
@@ -0,0 +1,157 @@
+from enum import Enum
+from typing import Literal
+
+from pydantic import BaseModel as Validation
+
+Scheduler = Literal["cosine"]
+
+Precision = Literal[
+ 16,
+ 32,
+ 64,
+ "16",
+ "16-true",
+ "16-mixed",
+ "bf16-true",
+ "bf16-mixed",
+ "32",
+ "32-true",
+ "64",
+ "64-true",
+]
+
+
+class Head(str, Enum):
+ Linear = "linear"
+ LinearNorm = "LinearNorm"
+
+ @staticmethod
+ def needs_patches(head: str) -> bool:
+ return head not in [
+ Head.Linear,
+ Head.LinearNorm,
+ ]
+
+
+class Backbone(str, Enum):
+ # https://huggingface.co/docs/transformers/en/model_doc/clip
+ CLIP_B_16 = "openai/clip-vit-base-patch16"
+ CLIP_B_32 = "openai/clip-vit-base-patch32"
+ CLIP_L_14 = "openai/clip-vit-large-patch14"
+ CLIP_L_14_336 = "openai/clip-vit-large-patch14-336"
+
+
+class Loss(Validation):
+ # Cross-entropy loss (multi-class classification)
+ ce_labels: float = 0.0 # Loss weight
+ label_smoothing: float = 0.0
+ # Binary cross-entropy loss (multi-label classification)
+ bce_labels: float = 0.0 # Loss weight
+ # Uniformity and alignment loss
+ uniformity: float = 0.0 # Loss weight
+ alignment_labels: float = 0.0 # Loss weight
+
+
+class LoRA(Validation):
+ enabled: bool = False # Enable LoRA
+ target_modules: list[str] | str = ["out_proj"] # Target modules
+ rank: int = 1 # Rank of the decomposition
+ alpha: int = 32 # Scaling factor
+ dropout: float = 0.1 # Dropout probability
+ bias: str = "none" # Bias configuration
+ use_rslora: bool = False # Use rsLoRA
+ use_dora: bool = False # Use DoRA
+
+
+class LNTuning(Validation):
+ enabled: bool = False # Enable LayerNorm tuning
+ target_modules: list[str] | str = [
+ "pre_layrnorm",
+ "layer_norm1",
+ "layer_norm2",
+ "post_layernorm",
+ "layernorm",
+ ] # Target modules
+
+
+class PEFT(Validation):
+ enabled: bool = False # Enable PEFT
+ lora: None | LoRA = LoRA() # LORA configuration
+ ln_tuning: None | LNTuning = LNTuning() # LayerNorm tuning configuration
+
+
+class Config(Validation, validate_assignment=True):
+ # Run configuration
+ run_name: str = "exp-name-1" # Name of the run
+ run_dir: str = "runs/exp" # Directory to save the run
+ seed: int = 42 # Random seed for reproducibility
+ throw_exception_if_run_exists: bool = False # Throw an exception if the run directory exists
+
+ # Model configuration
+ num_classes: int = 2
+ checkpoint: None | str = None # Path to a checkpoint to load
+ backbone: str = Backbone.CLIP_B_32 # Backbone model to use
+ freeze_feature_extractor: bool = True # Freeze the feature extractor
+ unfreeze_layers: list[str] = [] # Layers to unfreeze
+ head: str = Head.Linear # Head model to use
+ proj_feat_dim: int = 128 # Dimension of projected features
+ normalize_features: bool = False # Normalize features of penultimate layer
+
+ # PEFT configuration
+ peft: PEFT = PEFT()
+
+ # Latent augmentations
+ slerp_feature_augmentation: bool = False # Use Slerp feature augmentation
+ slerp_feature_augmentation_range: list[float] = [0.0, 1.0] # Range of the Slerp feature augmentation
+
+ # Data configuration
+ trn_files: list[str] | dict[str, list[str]] = [] # Files containing paths to training samples
+ val_files: list[str] | dict[str, list[str]] = [] # Files containing paths to validation samples
+ tst_files: list[str] | dict[str, list[str]] = [] # Files containing paths to test samples
+ limit_trn_files: None | int = None # Limit the number of training files
+ limit_val_files: None | int = None # Limit the number of validation files
+ limit_tst_files: None | int = None # Limit the number of test files
+ binary_labels: bool = True # Use binary labels
+
+ # Optimization configuration
+ lr: float = 0.0003 # Learning rate (initial / base)
+ min_lr: float = 1e-6 # Minimum learning rate
+ lr_scheduler: None | Scheduler = "cosine" # Learning rate scheduler
+ weight_decay: float = 0.0 # AdamW weight decay
+ betas: list[float] = [0.9, 0.999] # AdamW betas
+ loss: Loss = Loss() # Loss function to use
+
+ # Training configuration (managed by Lightning Trainer)
+ max_epochs: int = 1 # Number of epochs to train
+ batch_size: int = 512 # Required batch size to perform one step
+ mini_batch_size: int = 512 # Mini batch size per device
+ num_workers: int = 12 # Number of workers for the DataLoader
+ devices: list[int] | str | int = "auto" # Devices to use for training
+ precision: Precision = "bf16-mixed" # Precision for the model
+ fast_dev_run: int | bool = False # Run a fast development run
+ overfit_batches: int | float = 0.0 # Overfit on a subset of the data
+ limit_train_batches: None | int | float = None # Limit the number of training batches
+ limit_test_batches: None | int | float = None # Limit the number of test batches
+ limit_val_batches: None | int | float = None # Limit the number of validation batches
+ deterministic: None | bool = None # Set random seed for reproducibility
+ detect_anomaly: bool = False # Detect anomalies in the model
+ checkpoint_for_testing: str = "best_mAP" # Checkpoint to use for testing
+
+ # Logging
+ wandb: bool = False # Log metrics to Weights & Biases
+ wandb_tags: list[str] = [] # Tags to use for Weights & Biases
+
+ # Post-processing
+ make_binary_before_video_aggregation: bool = True # Make binary labels before video aggregation
+
+
+def load_config(path: str) -> Config:
+ import yaml
+
+ # read yaml config
+ with open(path, "r") as f:
+ config = yaml.safe_load(f)
+
+ # overwrite config
+ config = Config(**config)
+ return config
diff --git a/clean/image/yermandy/src/dataset/__init__.py b/clean/image/yermandy/src/dataset/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/clean/image/yermandy/src/dataset/base.py b/clean/image/yermandy/src/dataset/base.py
new file mode 100644
index 0000000000000000000000000000000000000000..2c405236c16c40ee75cead4b9364bb0217008b7f
--- /dev/null
+++ b/clean/image/yermandy/src/dataset/base.py
@@ -0,0 +1,5 @@
+"""Stub BaseDataset for inference-only loading."""
+
+
+class BaseDataset:
+ pass
diff --git a/clean/image/yermandy/src/debugging/cifar_dataset.py b/clean/image/yermandy/src/debugging/cifar_dataset.py
new file mode 100644
index 0000000000000000000000000000000000000000..799b4046c8ee7892cc9e71b83d06dbae1d782a5f
--- /dev/null
+++ b/clean/image/yermandy/src/debugging/cifar_dataset.py
@@ -0,0 +1,77 @@
+from typing import Callable
+
+import numpy as np
+from torchvision.datasets import CIFAR10
+
+from ..config import Config
+from ..dataset import BaseDataModule
+
+
+class CIFAR10Dataset(CIFAR10):
+ def __init__(
+ self,
+ train: bool = True,
+ preprocess: None | Callable = None,
+ augmentations: None | Callable = None,
+ ):
+ super().__init__(root="datasets/other/", train=train, download=True)
+ self.preprocess = preprocess
+ self.augmentations = augmentations
+
+ def __getitem__(self, idx):
+ image, label = super().__getitem__(idx)
+ if self.augmentations is not None:
+ image = self.augmentations(image)
+ if self.preprocess is not None:
+ image = self.preprocess(image)
+ return {
+ "image": image,
+ "label": label,
+ "path": f"{idx}: {label}",
+ "idx": idx,
+ }
+
+ def print_statistics(self):
+ print(f"Number of samples: {len(self)}")
+ unique, counts = np.unique(self.targets, return_counts=True)
+ print("Class distribution")
+ names = self.get_class_names()
+ for u, c in zip(unique, counts):
+ print(f"Class {u} ({names[u]}): {c}")
+
+ def get_class_names(self) -> dict[int, str]:
+ return {
+ 0: "airplane",
+ 1: "automobile",
+ 2: "bird",
+ 3: "cat",
+ 4: "deer",
+ 5: "dog",
+ 6: "frog",
+ 7: "horse",
+ 8: "ship",
+ 9: "truck",
+ }
+
+
+class CIFAR10DataModule(BaseDataModule):
+ def __init__(self, config: Config, preprocess: None | Callable = None):
+ super().__init__(config, preprocess)
+
+ def setup(self, stage: str):
+ # Initialize datasets
+ if stage == "fit" or stage == "validate":
+ self.train_dataset = CIFAR10Dataset(train=True, preprocess=self.preprocess)
+ self.val_dataset = CIFAR10Dataset(train=False, preprocess=self.preprocess)
+
+ print("\nTrain dataset")
+ self.train_dataset.print_statistics()
+
+ print("\nValidation dataset")
+ self.val_dataset.print_statistics()
+
+ if stage == "test":
+ self.test_dataset = CIFAR10Dataset(train=False, preprocess=self.preprocess)
+
+ print("\nTest dataset")
+ self.test_dataset.print_statistics()
diff --git a/clean/image/yermandy/src/debugging/mnist_dataset.py b/clean/image/yermandy/src/debugging/mnist_dataset.py
new file mode 100644
index 0000000000000000000000000000000000000000..457ffc13e71f61ca3aaa7ead41c4eb5197612981
--- /dev/null
+++ b/clean/image/yermandy/src/debugging/mnist_dataset.py
@@ -0,0 +1,66 @@
+from typing import Callable
+
+import numpy as np
+from torchvision.datasets import MNIST
+
+from ..config import Config
+from ..dataset import BaseDataModule
+
+
+class MNISTDataset(MNIST):
+ def __init__(
+ self,
+ train: bool = True,
+ preprocess: None | Callable = None,
+ augmentations: None | Callable = None,
+ ):
+ super().__init__(root="datasets/other/", train=train, download=True)
+ self.preprocess = preprocess
+ self.augmentations = augmentations
+
+ def __getitem__(self, idx):
+ image, label = super().__getitem__(idx)
+ if self.augmentations is not None:
+ image = self.augmentations(image)
+ if self.preprocess is not None:
+ image = self.preprocess(image)
+ return {
+ "image": image,
+ "label": label,
+ "path": f"{idx}: {label}",
+ "idx": idx,
+ }
+
+ def print_statistics(self):
+ print(f"Number of samples: {len(self)}")
+ unique, counts = np.unique(self.targets, return_counts=True)
+ print("Class distribution")
+ names = self.get_class_names()
+ for u, c in zip(unique, counts):
+ print(f"Class {u} ({names[u]}): {c}")
+
+ def get_class_names(self) -> dict[int, str]:
+ return {i: str(i) for i in range(10)}
+
+
+class MNISTDataModule(BaseDataModule):
+ def __init__(self, config: Config, preprocess: None | Callable = None):
+ super().__init__(config, preprocess)
+
+ def setup(self, stage: str):
+ # Initialize datasets
+ if stage == "fit" or stage == "validate":
+ self.train_dataset = MNISTDataset(train=True, preprocess=self.preprocess)
+ self.val_dataset = MNISTDataset(train=False, preprocess=self.preprocess)
+
+ print("\nTrain dataset")
+ self.train_dataset.print_statistics()
+
+ print("\nValidation dataset")
+ self.val_dataset.print_statistics()
+
+ if stage == "test":
+ self.test_dataset = MNISTDataset(train=False, preprocess=self.preprocess)
+
+ print("\nTest dataset")
+ self.test_dataset.print_statistics()
diff --git a/clean/image/yermandy/src/encoders/clip_encoder.py b/clean/image/yermandy/src/encoders/clip_encoder.py
new file mode 100644
index 0000000000000000000000000000000000000000..2d5bab700af3f403320b6fed51e1fb7dc32c7dce
--- /dev/null
+++ b/clean/image/yermandy/src/encoders/clip_encoder.py
@@ -0,0 +1,90 @@
+import numpy as np
+import torch
+import torch.nn as nn
+from PIL import Image
+from transformers import CLIPModel, CLIPProcessor
+
+
+class CLIPEncoder(nn.Module):
+ def __init__(self, model_name="openai/clip-vit-large-patch14"):
+ """
+ Models:
+ 1. openai/clip-vit-base-patch16 | 768 features
+ 2. openai/clip-vit-base-patch32 | 768 features
+ 3. openai/clip-vit-large-patch14 | 1024 features
+
+ See more in src/config.py
+ """
+
+ super().__init__()
+
+ try:
+ self._preprocess = CLIPProcessor.from_pretrained(model_name)
+ except Exception:
+ self._preprocess = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch16")
+
+ clip: CLIPModel = CLIPModel.from_pretrained(model_name)
+
+ # take vision model from CLIP, maps image to vision_embed_dim
+ self.vision_model = clip.vision_model
+
+ self.model_name = model_name
+
+ self.features_dim = self.vision_model.config.hidden_size
+
+ # take visual_projection, maps vision_embed_dim to projection_dim
+ # self.visual_projection = clip.visual_projection
+
+ def preprocess(self, image: Image) -> torch.Tensor:
+ return self._preprocess(images=image, return_tensors="pt")["pixel_values"][0]
+
+ def forward(self, preprocessed_images: torch.Tensor) -> torch.Tensor:
+ return self.vision_model(preprocessed_images).pooler_output
+
+ def get_features_dim(self):
+ return self.features_dim
+
+
+class CLIPEncoderPatches(CLIPEncoder):
+ def __init__(self, model_name):
+ """
+ See CLIPEncoder
+ """
+ super().__init__(model_name)
+
+ def forward(self, preprocessed_images: torch.Tensor) -> torch.Tensor:
+ embeddings = self.vision_model(preprocessed_images).last_hidden_state
+
+ # for clip-large-patch14, we have [B, 257, 1024]
+ # we want to reshape to take N by N patches, so that we have [B, N, N, 1024]
+ embeddings = embeddings[:, 1:]
+ B, T, _ = embeddings.shape
+ N = int(np.sqrt(T))
+ embeddings = embeddings.reshape(B, N, N, -1)
+
+ # To [B, C, H, W]
+ embeddings = embeddings.permute(0, 3, 1, 2)
+
+ return embeddings
+
+ def get_features_dim(self):
+ config = self.vision_model.config
+ hidden_size = config.hidden_size
+ num_patches = config.image_size // config.patch_size
+ return hidden_size, num_patches
+
+
+if __name__ == "__main__":
+ model = CLIPEncoder("openai/clip-vit-base-patch16")
+
+ path1 = "datasets/FF/real/000/000.png"
+ path2 = "datasets/FF/real/000/000.png"
+
+ image1 = Image.open(path1)
+ image2 = Image.open(path2)
+
+ preprocessed = [model.preprocess(image) for image in [image1, image2]]
+ preprocessed = torch.stack(preprocessed)
+ outputs = model(preprocessed)
+
+ print(outputs.shape)
diff --git a/clean/image/yermandy/src/heads/head.py b/clean/image/yermandy/src/heads/head.py
new file mode 100644
index 0000000000000000000000000000000000000000..959ebf5d816497e70c188ac6c511262debff1f81
--- /dev/null
+++ b/clean/image/yermandy/src/heads/head.py
@@ -0,0 +1,28 @@
+from dataclasses import dataclass
+
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+
+
+@dataclass
+class HeadOutput:
+ logits_labels: None | torch.Tensor = None
+ logits_source: None | torch.Tensor = None
+ features: torch.Tensor = None
+
+
+class LinearProbe(nn.Module):
+ def __init__(self, input_dim, num_classes, normalize_inputs=False):
+ super(LinearProbe, self).__init__()
+ self.linear = nn.Linear(input_dim, num_classes)
+ self.normalize_inputs = normalize_inputs
+
+ def forward(self, x):
+ if self.normalize_inputs:
+ x = F.normalize(x, p=2, dim=1)
+ logits = self.linear(x)
+
+ # Let features always be normalized
+ features = x if self.normalize_inputs else F.normalize(x, p=2, dim=1)
+ return HeadOutput(logits_labels=logits, features=features)
diff --git a/clean/image/yermandy/src/loss.py b/clean/image/yermandy/src/loss.py
new file mode 100644
index 0000000000000000000000000000000000000000..6b2ef741d0015620c50aff18ba6b4b37cbb26b75
--- /dev/null
+++ b/clean/image/yermandy/src/loss.py
@@ -0,0 +1,81 @@
+from dataclasses import dataclass
+
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+
+from src.losses.unifalign import alignment, uniformity
+from src.utils import logger
+
+from .config import Loss as LossConfig
+
+
+@dataclass
+class LossInputs:
+ logits_labels: None | torch.Tensor = None
+ labels: None | torch.Tensor = None
+ embeddings: None | torch.Tensor = None
+
+
+@dataclass
+class LossOutputs:
+ ce_labels: None | float = None
+ bce_labels: None | float = None
+ uniformity: None | float = None
+ alignment_labels: None | float = None
+ total: int | torch.Tensor = 0
+
+
+class Loss(nn.Module):
+ def __init__(self, loss_config: LossConfig):
+ super().__init__()
+ self.config = loss_config
+
+ def forward(
+ self,
+ inputs: LossInputs,
+ ) -> LossOutputs:
+ loss_outputs = LossOutputs()
+
+ if inputs.logits_labels is not None:
+ if self.config.ce_labels:
+ L = self.config.ce_labels * F.cross_entropy(
+ inputs.logits_labels, inputs.labels, label_smoothing=self.config.label_smoothing
+ )
+ loss_outputs.ce_labels = L.item()
+ loss_outputs.total += L
+
+ if inputs.embeddings is not None:
+ # L2 normalize embeddings
+ # See 3.1 https://arxiv.org/pdf/2004.11362
+ # embeddings = F.normalize(inputs.embeddings, p=2, dim=1)
+ embeddings = inputs.embeddings
+
+ # check that embeddings are normalized
+ if not torch.allclose(
+ embeddings.norm(p=2, dim=1), torch.ones(embeddings.size(0), device=embeddings.device)
+ ):
+ logger.print_warning_once("[yellow]Embeddings are not normalized")
+
+ if inputs.labels is not None:
+ if self.config.alignment_labels:
+ L = self.config.alignment_labels * alignment(embeddings, inputs.labels)
+ loss_outputs.alignment_labels = L.item()
+ loss_outputs.total += L
+
+ if self.config.uniformity:
+ L = self.config.uniformity * uniformity(embeddings)
+ loss_outputs.uniformity = L.item()
+ loss_outputs.total += L
+
+ if isinstance(loss_outputs.total, int):
+ logger.print_warning_once("[yellow]Total loss is 0. Check if loss coefficients are set correctly.")
+
+ if isinstance(loss_outputs.total, torch.Tensor) and loss_outputs.total.isnan():
+ logger.print_warning("[yellow]Total loss is nan")
+ loss_outputs.total = inputs.logits_labels.sum() * 0
+
+ return loss_outputs
+
+ def __call__(self, inputs: LossInputs) -> LossOutputs:
+ return super().__call__(inputs)
diff --git a/clean/image/yermandy/src/losses/unifalign.py b/clean/image/yermandy/src/losses/unifalign.py
new file mode 100644
index 0000000000000000000000000000000000000000..a4006e50547da3e64e276a2de7a7b7e60e460b9f
--- /dev/null
+++ b/clean/image/yermandy/src/losses/unifalign.py
@@ -0,0 +1,90 @@
+import torch
+
+
+def alignment(
+ embeddings: torch.Tensor,
+ labels: torch.Tensor,
+ alpha: float = 2,
+):
+ """
+ https://arxiv.org/pdf/2005.10242
+
+ Label-aware Alignment loss.
+
+ Calculates alignment for embeddings of samples with the SAME label
+ within a batch, assuming embeddings are already unit-normalized.
+
+ Args:
+ embeddings: Tensor [N, D] - Batch of unit-normalized embeddings.
+ labels: Tensor [N] - Corresponding labels.
+ alpha: Power to raise squared distance (hyperparameter, default=2).
+
+ Returns:
+ Tensor: Label-aware Alignment loss (scalar). Returns 0 if no positive pairs.
+ """
+ assert embeddings.size(0) == labels.size(0), "Embeddings and labels must have the same size."
+
+ n_samples = embeddings.size(0)
+ if n_samples < 2:
+ return torch.tensor(0.0, device=embeddings.device)
+
+ # Create a pairwise label comparison matrix (N x N), exclude self-pairs
+ labels_equal_mask = (labels[:, None] == labels[None, :]).triu(diagonal=1)
+
+ positive_indices = torch.nonzero(labels_equal_mask, as_tuple=False)
+ if positive_indices.numel() == 0:
+ return torch.tensor(0.0, device=embeddings.device)
+
+ # Get embeddings of positive pairs
+ x = embeddings[positive_indices[:, 0]]
+ y = embeddings[positive_indices[:, 1]]
+
+ # Calculate alignment loss
+ return (x - y).norm(p=2, dim=1).pow(alpha).mean()
+
+
+def uniformity(
+ x: torch.Tensor,
+ t: float = 2,
+ clip_value: float = 1e-6,
+):
+ """
+ https://arxiv.org/pdf/2005.10242
+
+ Calculates the Uniformity loss.
+
+ Args:
+ x: [N, D] - Batch of feature embeddings.
+ t: Temperature parameter (hyperparameter).
+
+ Returns:
+ Tensor: Uniformity loss value (scalar).
+ """
+ return torch.pdist(x, p=2).pow(2).mul(-t).exp().mean().clamp(min=clip_value).log()
+
+
+if __name__ == "__main__":
+ embeddings = torch.tensor(
+ [
+ [1.0, 0.0],
+ [1.0, 0.0],
+ [1.0, 1.0],
+ [0.0, 1.0],
+ [0.0, 1.0],
+ ],
+ )
+ embeddings /= embeddings.norm(p=2, dim=1, keepdim=True)
+
+ labels = torch.tensor([0, 0, 0, 1, 1])
+
+ print("Embeddings:")
+ print(embeddings.numpy())
+
+ print("\nLabels:")
+ print(labels.numpy())
+
+ alignment_loss = alignment(embeddings, labels, alpha=2)
+ print("\nAlignment loss:", alignment_loss.item())
+
+ uniformity_loss = uniformity(embeddings, t=2, clip_value=1e-6)
+ print("Uniformity loss:", uniformity_loss.item())
diff --git a/clean/image/yermandy/src/metrics.py b/clean/image/yermandy/src/metrics.py
new file mode 100644
index 0000000000000000000000000000000000000000..80447c036a1328916aafb1cbf63d17bf2feaf5de
--- /dev/null
+++ b/clean/image/yermandy/src/metrics.py
@@ -0,0 +1,83 @@
+import numpy as np
+from scipy.interpolate import interp1d
+from scipy.optimize import brentq
+from sklearn import metrics as M
+
+
+def ovr_roc(labels: np.ndarray, probs: np.ndarray):
+ """
+ Calculate the One-vs-Rest (OvR) Receiver Operating Characteristic (ROC) and Area Under the ROC Curve (AUROC) for each class.
+
+ Parameters:
+ labels (np.ndarray): Array of true class labels.
+ probs (np.ndarray): Array of predicted probabilities for each class.
+
+ Returns:
+ tuple: A tuple containing:
+ - aurocs (list): List of AUROC values for each class.
+ - fprs (list): List of false positive rates for each class.
+ - tprs (list): List of true positive rates for each class.
+ - ths (list): List of thresholds for each class.
+ - ovr_macro_auroc (float): Macro-averaged AUROC for the OvR setting.
+ """
+ num_classes = probs.shape[1]
+ labels_one_hot = np.eye(num_classes)[labels]
+ fprs, tprs, ths = [], [], []
+
+ # Why OvR with macro avg: https://chatgpt.com/share/677e448d-5bc0-8006-b9b5-081427b02857
+ ovr_macro_auroc = M.roc_auc_score(labels_one_hot, probs, multi_class="ovr", average="macro")
+
+ # Calculate OvR ROC and AUROC for each class
+ for i in range(num_classes):
+ _fpr, _tpr, _ths = M.roc_curve(labels_one_hot[:, i], probs[:, i])
+ fprs.append(_fpr)
+ tprs.append(_tpr)
+ ths.append(_ths)
+
+ return fprs, tprs, ths, ovr_macro_auroc
+
+
+def ovr_prc(labels: np.ndarray, probs: np.ndarray):
+ """
+ Calculate the One-vs-Rest (OvR) Precision-Recall Curve (PRC) and the mean Average Precision (mAP) for a multi-class classification problem.
+
+ Args:
+ labels (np.ndarray): Array of true class labels with shape (n_samples,).
+ probs (np.ndarray): Array of predicted probabilities with shape (n_samples, n_classes).
+
+ Returns:
+ tuple: A tuple containing:
+ - precs (list of np.ndarray): List of precision values for each class.
+ - recs (list of np.ndarray): List of recall values for each class.
+ - ths (list of np.ndarray): List of threshold values for each class.
+ - ovr_macro_ap (float): The mean Average Precision (mAP) score.
+ """
+ num_classes = probs.shape[1]
+ labels_one_hot = np.eye(num_classes)[labels]
+ precs, recs, ths = [], [], []
+
+ # The same as mAP (mean Average Precision)
+ ovr_macro_ap = M.average_precision_score(labels_one_hot, probs, average="macro")
+
+ # Calculate OvR PRC for each class
+ for i in range(num_classes):
+ _prec, _rec, _ths = M.precision_recall_curve(labels_one_hot[:, i], probs[:, i])
+ precs.append(_prec)
+ recs.append(_rec)
+ ths.append(_ths)
+
+ return precs, recs, ths, ovr_macro_ap
+
+
+# TODO: verify claim
+#! Notice: this might not work as expected if p(y=1) != 1 - p(y=0)
+def calculate_eer(y_true: np.ndarray, y_score: np.ndarray):
+ """
+ Returns the equal error rate for a binary classifier output
+ """
+ fpr, tpr, thresholds = M.roc_curve(y_true, y_score[:, 1], pos_label=1)
+ try:
+ eer = brentq(lambda x: 1.0 - x - interp1d(fpr, tpr)(x), 0.0, 1.0)
+ except ValueError:
+ eer = 1.0
+ return eer
diff --git a/clean/image/yermandy/src/model/__init__.py b/clean/image/yermandy/src/model/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..11501a0a4c4ee1013202941ba660862a88fd035e
--- /dev/null
+++ b/clean/image/yermandy/src/model/__init__.py
@@ -0,0 +1 @@
+from .dfdet import DeepfakeDetectionModel
diff --git a/clean/image/yermandy/src/model/dfdet.py b/clean/image/yermandy/src/model/dfdet.py
new file mode 100644
index 0000000000000000000000000000000000000000..f4be93898c8929e5d6ce9ea1a7740763522069c5
--- /dev/null
+++ b/clean/image/yermandy/src/model/dfdet.py
@@ -0,0 +1,649 @@
+from dataclasses import dataclass
+from typing import Callable, Literal
+
+import lightning as pl
+import numpy as np
+import pandas as pd
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+import wandb
+from lightning import seed_everything
+from lightning.pytorch.loggers import WandbLogger
+from PIL import Image
+from sklearn import metrics as M
+from torch import optim
+from torch.optim.lr_scheduler import CosineAnnealingLR
+from torchmetrics import CatMetric
+
+from src import metrics, plots
+from src.config import Backbone, Config, Head
+from src.dataset.base import BaseDataset
+from src.heads import head
+from src.loss import Loss, LossInputs, LossOutputs
+from src.losses import unifalign
+from src.utils import logger
+
+
+class OutputsForMetrics(nn.Module):
+ def __init__(self):
+ super().__init__()
+ self.probs = CatMetric()
+ self.labels = CatMetric()
+ self.idx = CatMetric()
+
+ def reset(self):
+ self.probs.reset()
+ self.labels.reset()
+ self.idx.reset()
+
+
+@dataclass
+class Batch:
+ images: None | torch.Tensor
+ labels: None | torch.Tensor
+ identity: None | torch.Tensor
+ source: None | torch.Tensor
+ idx: None | torch.Tensor
+ paths: None | list[str]
+
+ def __getitem__(self, key):
+ # if batch["image"] is called, return batch.images
+ return getattr(self, key)
+
+ @staticmethod
+ def from_dict(batch: dict):
+ return Batch(
+ images=batch.get("image"),
+ labels=batch.get("label"),
+ identity=batch.get("identity"),
+ source=batch.get("source"),
+ idx=batch.get("idx"),
+ paths=batch.get("path"),
+ )
+
+
+def slerp(A: torch.Tensor, B: torch.Tensor, t: torch.Tensor | float) -> torch.Tensor:
+ """
+ Spherical linear interpolation between two batched points A and B on a unit hypersphere.
+
+ Parameters:
+ - A: First set of points, shape (batch_size, d).
+ - B: Second set of points, shape (batch_size, d).
+ - t: Interpolation parameter in range [0, 1], shape (batch_size, 1) or single value.
+
+ Returns:
+ - torch.Tensor: Interpolated points, shape (batch_size, d).
+ """
+ # Ensure inputs are unit vectors
+ A = F.normalize(A, dim=-1)
+ B = F.normalize(B, dim=-1)
+
+ # Compute dot product for each pair of points
+ dot = torch.sum(A * B, dim=-1, keepdim=True).clamp(-1 + 1e-7, 1 - 1e-7) # Avoid numerical issues
+
+ # Compute the angle for each pair
+ theta = torch.acos(dot)
+
+ # Slerp formula
+ sin_theta = torch.sin(theta)
+ t_theta = t * theta
+ coeff_a = torch.sin(theta - t_theta) / sin_theta
+ coeff_b = torch.sin(t_theta) / sin_theta
+
+ # Compute the interpolated points
+ interpolated = coeff_a * A + coeff_b * B
+
+ return interpolated
+
+
+def compute_across_videos(files: list, probs: np.ndarray, labels: np.ndarray):
+ """
+ Calculate mean probs for each video across all frames
+ """
+
+ # Get all before the last /
+ # For example: a/b/c/d -> a/b/c
+ videos = [f[: -f[::-1].find("/")] for f in files]
+
+ # Group by video: video -> [indices]
+ video2idx = {v: [] for v in videos}
+ for i, v in enumerate(videos):
+ video2idx[v].append(i)
+
+ # Calculate mean probs for each video across all frames
+ video2probs = {v: [] for v in videos}
+ video2labels = {v: [] for v in videos}
+ for v, idxs in video2idx.items():
+ video2probs[v] = np.mean(probs[idxs], axis=0)
+ video2labels[v] = int(labels[idxs[0]])
+
+ video_probs = np.array(list(video2probs.values()))
+ video_labels = np.array(list(video2labels.values()))
+
+ return video_probs, video_labels
+
+
+class DeepfakeDetectionModel(pl.LightningModule):
+ def __init__(self, config: Config, verbose: bool = False):
+ super().__init__()
+ self.config = config
+ self.save_hyperparameters(config.model_dump())
+
+ if verbose:
+ logger.print(config)
+
+ seed_everything(self.config.seed, workers=True, verbose=verbose)
+
+ self._init_feature_extractor()
+ self._init_head()
+ self._freeze_parameters()
+ self._init_peft()
+ self._init_loss()
+ self._init_metrics()
+
+ if verbose:
+ self.print_trainable_parameters()
+
+ def _init_metrics(self):
+ self.train_step_outputs = OutputsForMetrics()
+ self.val_step_outputs = OutputsForMetrics()
+ self.test_step_outputs = OutputsForMetrics()
+
+ def _init_feature_extractor(self):
+ backbone = self.config.backbone.lower()
+
+ if "clip" in backbone or "FaRL" in backbone:
+ if Head.needs_patches(self.config.head):
+ from src.encoders.clip_encoder import CLIPEncoderPatches
+
+ self.feature_extractor = CLIPEncoderPatches(backbone)
+
+ else:
+ from src.encoders.clip_encoder import CLIPEncoder
+
+ self.feature_extractor = CLIPEncoder(backbone)
+
+ else:
+ raise ValueError(f"Unknown backbone: {backbone}")
+
+ # self.feature_extractor.eval()
+ # self.feature_extractor.to(self.device)
+
+ def _init_peft(self):
+ if self.config.peft.enabled:
+ from peft import get_peft_model
+
+ if self.config.peft.lora is not None and self.config.peft.lora.enabled:
+ from peft import LoraConfig
+
+ peft_config = LoraConfig(
+ target_modules=self.config.peft.lora.target_modules,
+ r=self.config.peft.lora.rank,
+ lora_alpha=self.config.peft.lora.alpha,
+ lora_dropout=self.config.peft.lora.dropout,
+ bias=self.config.peft.lora.bias,
+ use_rslora=self.config.peft.lora.use_rslora,
+ use_dora=self.config.peft.lora.use_dora,
+ )
+
+ elif self.config.peft.ln_tuning is not None and self.config.peft.ln_tuning.enabled:
+ from peft import LNTuningConfig
+
+ peft_config = LNTuningConfig(target_modules=self.config.peft.ln_tuning.target_modules)
+
+ else:
+ raise ValueError("Unknown PEFT configuration")
+
+ backbone = self.feature_extractor
+ training_parameters = {name for name, param in backbone.named_parameters() if param.requires_grad}
+
+ self.feature_extractor = get_peft_model(self.feature_extractor, peft_config)
+
+ for name, param in backbone.named_parameters():
+ if name in training_parameters:
+ param.requires_grad = True
+
+ def _init_head(self):
+ features_dim = self.feature_extractor.get_features_dim()
+
+ match self.config.head:
+ case Head.Linear:
+ self.model = head.LinearProbe(features_dim, self.config.num_classes)
+
+ case Head.LinearNorm:
+ self.model = head.LinearProbe(features_dim, self.config.num_classes, True)
+
+ case _:
+ raise ValueError(f"Unknown head: {self.config.head}")
+
+ # self.model.eval()
+ # self.model.to(self.device)
+
+ def _freeze_parameters(self):
+ # Freeze feature extractor
+ self.feature_extractor.requires_grad_(not self.config.freeze_feature_extractor)
+
+ if len(self.config.unfreeze_layers) > 0:
+ for name, param in self.named_parameters():
+ if any(layer in name for layer in self.config.unfreeze_layers):
+ param.requires_grad = True
+
+ def print_trainable_parameters(self):
+ logger.print("\n🔥 [red bold]Trainable parameters:")
+ for name, param in self.named_parameters():
+ if param.requires_grad:
+ logger.print(f"[red]{name} shape = {tuple(param.shape)}")
+
+ all_params = sum(p.numel() for p in self.parameters())
+ trainable_params = sum(p.numel() for p in self.parameters() if p.requires_grad)
+ logger.print(
+ f"Total parameters: {all_params}, trainable: {trainable_params}, %: {trainable_params / all_params * 100:.4f}"
+ )
+
+ def _init_loss(self):
+ self.criterion = Loss(self.config.loss)
+
+ def get_preprocessing(self) -> Callable[[Image.Image], torch.Tensor]:
+ return self.feature_extractor.preprocess
+
+ def forward(self, inputs) -> head.HeadOutput:
+ features = self.feature_extractor(inputs)
+ outputs = self.model(features)
+ return outputs
+
+ def log_loss(self, loss: LossOutputs, stage: str):
+ if loss.total is not None:
+ self.log(f"{stage}/loss", loss.total, prog_bar=True, on_epoch=True)
+ if loss.ce_labels is not None:
+ self.log(f"{stage}/loss_ce", loss.ce_labels, prog_bar=True, on_epoch=True)
+
+ def log_aliunif(self, outputs: head.HeadOutput, labels: torch.Tensor, stage: str):
+ alignment = unifalign.alignment(outputs.features, labels)
+ uniformity = unifalign.uniformity(outputs.features)
+ self.log(f"{stage}/alignment", alignment, prog_bar=True, on_epoch=True)
+ self.log(f"{stage}/uniformity", uniformity, prog_bar=True, on_epoch=True)
+
+ def get_probs(self, outputs: head.HeadOutput):
+ return outputs.logits_labels.softmax(1)
+
+ def get_batch(self, batch: dict) -> Batch:
+ return Batch.from_dict(batch)
+
+ def slerp_feature_augmentation(self, batch: Batch, features: torch.Tensor):
+ # Perform slerp on features, each class independently, vectorized
+
+ if self.training and self.config.slerp_feature_augmentation:
+ labels = batch.labels
+
+ # Iterate over each unique class label
+ for class_label in torch.unique(labels):
+ class_mask = labels == class_label
+
+ # If there are fewer than 2 features for the class, skip slerp
+ if class_mask.sum() < 2:
+ continue
+
+ # Get the features for the current class
+ class_features = features[class_mask]
+
+ # Sample pairs of embeddings from the current class
+ num_embeddings = len(class_features)
+ indices2 = torch.randperm(num_embeddings)
+ A = class_features
+ B = class_features[indices2]
+
+ # Generate a random interpolation parameter t for each embedding in the batch
+ t = torch.rand((num_embeddings, 1), device=features.device, dtype=features.dtype)
+
+ # Extend range from [0, 1] to [t0, t1]
+ t0, t1 = self.config.slerp_feature_augmentation_range
+ t = t * (t1 - t0) + t0
+
+ # autocast
+ augmented_embeddings = slerp(A, B, t) # Perform slerp
+
+ # Update the features for the current class
+ features[class_mask] = augmented_embeddings.to(features.dtype)
+
+ return features
+
+ def training_step(self, batch, batch_idx):
+ batch = self.get_batch(batch)
+ # outputs = self.forward(batch.images)
+ features = self.feature_extractor(batch.images)
+ features = self.slerp_feature_augmentation(batch, features)
+ outputs = self.model(features)
+
+ loss_inputs = LossInputs(
+ logits_labels=outputs.logits_labels,
+ labels=batch.labels,
+ embeddings=outputs.features,
+ )
+ loss = self.criterion(loss_inputs)
+ probs = self.get_probs(outputs)
+
+ self.log_loss(loss, "train")
+ self.log_aliunif(outputs, batch.labels, "train")
+
+ # Save outputs for metrics calculation
+ self.train_step_outputs.labels.update(batch.labels)
+ self.train_step_outputs.probs.update(probs.detach())
+ self.train_step_outputs.idx.update(batch.idx)
+
+ return loss.total
+
+ def on_train_start(self):
+ logger.print(f"[blue]Logs: {self.logger.log_dir}")
+ self.log("num_train_files", len(self.trainer.datamodule.train_dataset))
+ self.log("num_val_files", len(self.trainer.datamodule.val_dataset))
+
+ def on_test_start(self):
+ logger.print(f"[blue]Logs: {self.logger.log_dir}")
+ self.log("num_test_files", len(self.trainer.datamodule.test_dataset))
+
+ def sources_probs_to_binary(self, probs: np.ndarray) -> np.ndarray:
+ # probs[:, 0] # is real probs
+ # probs[:, 1:] # is fake probs (for each generator)
+ return np.stack([probs[:, 0], probs[:, 1:].max(axis=1)], 1)
+
+ def log_metrics(
+ self,
+ probs: np.ndarray,
+ labels: np.ndarray,
+ stage: Literal["train", "test", "val"],
+ prefix: str,
+ level: Literal["frame", "video"],
+ dataset: BaseDataset,
+ ):
+ """
+ Images are saved to
+ `log_dir / prefix / level_metrics / metric.png`
+ """
+
+ log_dir = self.logger.log_dir
+
+ Stage = stage.capitalize()
+
+ # Compute ROC and PR curves for every class
+ fprs, tprs, roc_ths, ovr_macro_auroc = metrics.ovr_roc(labels, probs)
+ precs, recs, pr_ths, ovr_macro_ap = metrics.ovr_prc(labels, probs)
+
+ # Compute EER (Equal Error Rate)
+ if self.config.num_classes == 2:
+ eer = metrics.calculate_eer(labels, probs)
+ self.log(f"{prefix}/eer_{level}", eer)
+
+ # Compute predictions by argmax rule
+ preds = probs.argmax(1)
+
+ # Log metrics
+ self.log(f"{prefix}/auroc_{level}", ovr_macro_auroc)
+ self.log(f"{prefix}/acc_{level}", M.accuracy_score(labels, preds))
+ self.log(f"{prefix}/balanced_acc_{level}", M.balanced_accuracy_score(labels, preds))
+ self.log(f"{prefix}/f1_score_{level}", M.f1_score(labels, preds, average="macro"))
+ self.log(f"{prefix}/mAP_{level}", ovr_macro_ap)
+
+ class_names = dataset.get_class_names()
+
+ plots.plot_probs_distribution(
+ probs,
+ labels,
+ class_names,
+ f"{log_dir}/{prefix}/{level}_metrics/{stage}_probs_distribution.png",
+ )
+
+ plots.plot_roc_curve(
+ fprs,
+ tprs,
+ roc_ths,
+ f"{Stage} ROC ({level}-level)",
+ f"{log_dir}/{prefix}/{level}_metrics/{stage}_roc_{level}.png",
+ 0.01,
+ class_names,
+ )
+
+ plots.plot_prc_curve(
+ precs,
+ recs,
+ pr_ths,
+ f"{Stage} PR Curve ({level}-level)",
+ f"{log_dir}/{prefix}/{level}_metrics/{stage}_pr_curve.png",
+ 0.01,
+ class_names,
+ )
+
+ plots.plot_f1_curve(
+ precs,
+ recs,
+ pr_ths,
+ f"{Stage} F1 Curve ({level}-level)",
+ f"{log_dir}/{prefix}/{level}_metrics/{stage}_f1_curve.png",
+ 0.01,
+ class_names,
+ )
+
+ # Confusion matrix
+ conf = M.confusion_matrix(labels, preds)
+ plots.plot_confusion_matrix(
+ conf,
+ class_names,
+ f"{Stage} Confusion Matrix ({level}-level)",
+ f"{log_dir}/{prefix}/{level}_metrics/{stage}_confusion.png",
+ )
+ plots.plot_confusion_matrix(
+ conf,
+ class_names,
+ f"{Stage} Confusion Matrix ({level}-level)",
+ f"{log_dir}/{prefix}/{level}_metrics/{stage}_confusion_norm.png",
+ True,
+ )
+
+ if any(isinstance(l, WandbLogger) for l in self.loggers):
+ wandb_logger = [l for l in self.loggers if isinstance(l, WandbLogger)][0]
+
+ wandb_logger.log_metrics(
+ {
+ f"confusion/{stage}_{level}": wandb.plot.confusion_matrix(
+ probs=probs,
+ y_true=labels,
+ class_names=["real", "fake"],
+ title=f"{Stage} Confusion Matrix {level.capitalize()}",
+ )
+ }
+ )
+
+ def log_all_metrics(
+ self,
+ outputs_for_metrics: OutputsForMetrics,
+ stage: Literal["train", "test", "val"],
+ dataset: BaseDataset,
+ ):
+ # Merge all predictions and labels across processes
+ labels = outputs_for_metrics.labels.compute().cpu().int().numpy()
+ probs = outputs_for_metrics.probs.compute().cpu().numpy()
+ idx = outputs_for_metrics.idx.compute().cpu().int().numpy()
+ files = [dataset.files[i] for i in idx] # Get files in the same order as the rest
+ outputs_for_metrics.reset()
+
+ if self.config.make_binary_before_video_aggregation:
+ if probs.shape[1] > 2:
+ probs = self.sources_probs_to_binary(probs)
+
+ # Compute probs and labels for videos
+ video_probs, video_labels = compute_across_videos(files, probs, labels)
+
+ # Convery to binary if sources are used
+ if not self.config.make_binary_before_video_aggregation:
+ if probs.shape[1] > 2:
+ probs = self.sources_probs_to_binary(probs)
+ video_probs = self.sources_probs_to_binary(video_probs)
+
+ self.log_metrics(probs, labels, stage, stage, "frame", dataset)
+ self.log_metrics(video_probs, video_labels, stage, stage, "video", dataset)
+
+ # if trn_files / val_files / tst_files is dict, separate metrics for each dataset
+ if dataset.dataset2files is not None:
+ if not self.config.make_binary_before_video_aggregation:
+ logger.print_warning(
+ "`make_binary_before_video_aggregation=False` is not supported when trn_files / val_files / tst_files is dict"
+ )
+
+ file2index = {f: i for i, f in enumerate(files)}
+ for dataset_name, dataset_files in dataset.dataset2files.items():
+ # Get files only for current dataset
+ dataset_files = np.intersect1d(files, dataset_files)
+ file_indices = [file2index[f] for f in dataset_files]
+ dataset_probs = probs[file_indices]
+ dataset_labels = labels[file_indices]
+ dataset_files = [files[i] for i in file_indices]
+
+ self.log_metrics(
+ dataset_probs,
+ dataset_labels,
+ stage,
+ f"{stage}/dataset/{dataset_name}",
+ "frame",
+ dataset,
+ )
+
+ dataset_video_probs, dataset_video_labels = compute_across_videos(
+ dataset_files, dataset_probs, dataset_labels
+ )
+
+ self.log_metrics(
+ dataset_video_probs,
+ dataset_video_labels,
+ stage,
+ f"{stage}/dataset/{dataset_name}",
+ "video",
+ dataset,
+ )
+
+ def on_train_epoch_end(self):
+ if self.logger.log_dir is None:
+ # TODO: figure out why logger.log_dir can be None
+ return
+
+ # Log learning rate
+ self.log("lr", self.trainer.optimizers[0].param_groups[0]["lr"])
+
+ # Log weights norms
+ try:
+ self.log("model/linear-W-norm", self.model.linear.weight.norm().item())
+ self.log("model/linear-b-norm", self.model.linear.bias.norm().item())
+ except Exception:
+ pass
+
+ dataset = self.trainer.datamodule.train_dataset
+ self.log_all_metrics(self.train_step_outputs, "train", dataset)
+
+ def validation_step(self, batch, batch_idx):
+ batch = self.get_batch(batch)
+ outputs = self.forward(batch.images)
+ loss_inputs = LossInputs(
+ logits_labels=outputs.logits_labels,
+ labels=batch.labels,
+ embeddings=outputs.features,
+ )
+ loss = self.criterion(loss_inputs)
+ probs = self.get_probs(outputs)
+
+ self.log_loss(loss, "val")
+ self.log_aliunif(outputs, batch.labels, "val")
+ self.val_step_outputs.labels.update(batch.labels)
+ self.val_step_outputs.probs.update(probs.detach())
+ self.val_step_outputs.idx.update(batch.idx)
+
+ def on_validation_epoch_end(self):
+ if self.logger.log_dir is None:
+ # TODO: figure out why logger.log_dir can be None
+ return
+
+ dataset = self.trainer.datamodule.val_dataset
+ self.log_all_metrics(self.val_step_outputs, "val", dataset)
+
+ def test_step(self, batch, batch_idx):
+ batch = self.get_batch(batch)
+ outputs = self.forward(batch.images)
+ loss_inputs = LossInputs(
+ logits_labels=outputs.logits_labels,
+ labels=batch.labels,
+ embeddings=outputs.features,
+ )
+ loss = self.criterion(loss_inputs)
+ probs = self.get_probs(outputs)
+
+ self.log_loss(loss, "test")
+ self.log_aliunif(outputs, batch.labels, "test")
+ self.test_step_outputs.labels.update(batch.labels)
+ self.test_step_outputs.probs.update(probs.detach())
+ self.test_step_outputs.idx.update(batch.idx)
+
+ def on_test_epoch_end(self):
+ if self.logger.log_dir is None:
+ # TODO: figure out why logger.log_dir can be None
+ return
+
+ # Concatenate all predictions and labels
+ probs = self.test_step_outputs.probs.compute().cpu().numpy()
+ labels = self.test_step_outputs.labels.compute().cpu().int().numpy()
+ idx = self.test_step_outputs.idx.compute().cpu().int().numpy()
+
+ dataset = self.trainer.datamodule.test_dataset
+
+ files = [dataset.files[i] for i in idx]
+
+ # preds is a 2D array of shape (num_samples, num_classes)
+ probs = {f"prob_class_{i}": np.round(probs[:, i], 4) for i in range(probs.shape[1])}
+ table = pd.DataFrame({"files": files, "labels": labels, **probs})
+
+ # Save to CSV
+ table.to_csv(f"{self.logger.log_dir}/test_predictions.csv", index=False, float_format="%.4f")
+
+ self.log_all_metrics(self.test_step_outputs, "test", dataset)
+
+ def configure_optimizers(self):
+ self.trainer.fit_loop.setup_data() # because we need an access to the dataloader
+
+ # Separate parameters for weight decay and no weight decay
+ decay_params = []
+ no_decay_params = []
+ for name, param in self.named_parameters():
+ if not param.requires_grad:
+ continue
+ if "bias" in name or "norm" in name:
+ no_decay_params.append(param)
+ else:
+ decay_params.append(param)
+
+ optimizer_grouped_parameters = [
+ {"params": decay_params, "weight_decay": self.config.weight_decay},
+ {"params": no_decay_params, "weight_decay": 0.0},
+ ]
+
+ # Configure optimizer
+ optimizer = optim.AdamW(
+ optimizer_grouped_parameters,
+ lr=self.config.lr,
+ weight_decay=self.config.weight_decay,
+ betas=self.config.betas,
+ )
+
+ optimizers = {"optimizer": optimizer}
+
+ # Configure LR scheduler
+ if self.config.lr_scheduler == "cosine":
+ #! be careful when running experiments with limit_train_batches
+ if self.config.limit_train_batches is not None:
+ logger.print_warning_once("lr scheduling and limit_train_batches are not compatible")
+ T_max = self.config.max_epochs * len(self.trainer.train_dataloader)
+ scheduler = CosineAnnealingLR(optimizer, T_max=T_max, eta_min=self.config.min_lr)
+
+ optimizers["lr_scheduler"] = {
+ "scheduler": scheduler,
+ "interval": "step",
+ "frequency": 1,
+ }
+
+ return optimizers
diff --git a/clean/image/yermandy/src/plots.py b/clean/image/yermandy/src/plots.py
new file mode 100644
index 0000000000000000000000000000000000000000..b718e6977490956011cc2f5c0ca7adc8f6853095
--- /dev/null
+++ b/clean/image/yermandy/src/plots.py
@@ -0,0 +1,286 @@
+import os
+
+import matplotlib.pyplot as plt
+import numpy as np
+import seaborn as sns
+from numpy import ndarray
+from sklearn import metrics as M
+
+from src.utils.decorators import TryExcept
+
+
+@TryExcept("plot_curve")
+def plot_curve(
+ xs: list[ndarray],
+ ys: list[ndarray],
+ auc_threshold: float = 0.01,
+ class_names: None | dict[int, str] = None,
+):
+ # Create figure with larger size and better aspect ratio
+ plt.figure(figsize=(10, 8), tight_layout=True)
+
+ # Create two subplots - one for the plot, one for the legend
+ gs = plt.GridSpec(1, 2, width_ratios=[4, 1])
+ ax_plot = plt.subplot(gs[0])
+ ax_legend = plt.subplot(gs[1])
+
+ palette = sns.husl_palette(len(xs))
+ linestyles = ["-", "--", "-.", ":"]
+
+ # Plot curves on the main axis
+ active_classes = []
+ for c, (x, y) in enumerate(zip(xs, ys)):
+ auc = M.auc(x, y)
+ if auc >= auc_threshold: # Only plot and include in legend if AUC > threshold
+ class_name = f"{c}: {class_names[c]}" if class_names else c
+ label = f"{class_name} (AUC: {auc:.2f})"
+ linestyle = linestyles[c % len(linestyles)]
+ line = ax_plot.plot(x, y, label=label, linewidth=1.5, color=palette[c], linestyle=linestyle)
+ active_classes.append((line[0], label))
+
+ # Set square aspect ratio
+ ax_plot.set_aspect("equal")
+
+ # Set limits explicitly to ensure square plot
+ ax_plot.set_xlim(-0.02, 1.02) # Slight padding for better visibility
+ ax_plot.set_ylim(-0.02, 1.02)
+
+ # Customize the main plot
+ ax_plot.grid(True, linestyle="--", alpha=0.3)
+
+ # Create legend in the second subplot
+ ax_legend.axis("off") # Hide the axis
+ if active_classes:
+ lines, labels = zip(*active_classes)
+ ax_legend.legend(lines, labels, loc="center left", fontsize=10, borderaxespad=0)
+
+ return ax_plot
+
+
+@TryExcept("plot_roc_curve")
+def plot_roc_curve(
+ fprs: list[ndarray],
+ tprs: list[ndarray],
+ ths: list[ndarray],
+ title: str = "ROC",
+ path: str = "roc_curve.png",
+ auc_threshold: float = 0.01,
+ class_names: None | dict[int, str] = None,
+):
+ """
+ Plot ROC curve for multiple classes.
+ """
+ ax_plot = plot_curve(fprs, tprs, auc_threshold, class_names)
+
+ # Add the diagonal line
+ ax_plot.plot([0, 1], [0, 1], color="black", linestyle="--", alpha=0.5)
+
+ ax_plot.set_xlabel("False Positive Rate (FPR)", fontsize=12)
+ ax_plot.set_ylabel("True Positive Rate (TPR)", fontsize=12)
+ ax_plot.set_title(title, fontsize=14, pad=20)
+
+ # Save with high quality
+ os.makedirs(os.path.dirname(path), exist_ok=True)
+ plt.savefig(path, dpi=300, bbox_inches="tight")
+ plt.close()
+
+
+@TryExcept("plot_prc_curve")
+def plot_prc_curve(
+ prcs: list[ndarray],
+ recs: list[ndarray],
+ ths: list[ndarray],
+ title: str = "PRC",
+ path: str = "pr_curve.png",
+ auc_threshold: float = 0.01,
+ class_names: None | dict[int, str] = None,
+ show_f1_lines: bool = True,
+):
+ """
+ Plot Precision-Recall curve for multiple classes.
+ """
+ ax_plot = plot_curve(recs, prcs, auc_threshold, class_names)
+
+ if show_f1_lines:
+ f_scores = np.linspace(0.1, 0.9, num=9) # F1 scores to plot
+ for f_score in f_scores:
+ r = np.linspace(0.001, 1, 100) # Recall
+ p = f_score * r / (2 * r - f_score) # Precision for given F1 score
+ mask = p > 0
+ ax_plot.plot(r[mask], p[mask], color="gray", alpha=0.2, linestyle="--")
+ ax_plot.annotate("F1={0:0.1f}".format(f_score), xy=(0.95, p[-1] - 0.02), alpha=0.2)
+
+ # Customize the main plot
+ ax_plot.set_xlabel("Recall", fontsize=12)
+ ax_plot.set_ylabel("Precision", fontsize=12)
+ ax_plot.set_title(title, fontsize=14, pad=20)
+
+ # Save with high quality
+ os.makedirs(os.path.dirname(path), exist_ok=True)
+ plt.savefig(path, dpi=300, bbox_inches="tight")
+ plt.close()
+
+
+@TryExcept("plot_f1_curve")
+def plot_f1_curve(
+ prcs: list[ndarray],
+ recs: list[ndarray],
+ ths: list[ndarray],
+ title: str = "F1",
+ path: str = "f1_curve.png",
+ auc_threshold: float = 0.01,
+ class_names: None | dict[int, str] = None,
+):
+ """
+ Plot F1 curve for multiple classes
+ """
+ f1s = []
+ for prc, rec in zip(prcs, recs):
+ with np.errstate(divide="ignore", invalid="ignore"):
+ f1 = np.where((prc + rec) == 0, 0, 2 * prc * rec / (prc + rec))
+ f1 = f1[:-1]
+ f1s.append(f1)
+
+ ax_plot = plot_curve(ths, f1s, auc_threshold, class_names)
+
+ # Customize the main plot
+ ax_plot.set_xlabel("Threshold", fontsize=12)
+ ax_plot.set_ylabel("F1 Score", fontsize=12)
+
+ # Save with high quality
+ os.makedirs(os.path.dirname(path), exist_ok=True)
+ plt.savefig(path, dpi=300, bbox_inches="tight")
+ plt.close()
+
+
+@TryExcept("plot_confusion_matrix")
+def plot_confusion_matrix(
+ confusion_matrix: ndarray,
+ class_names: None | dict[int, str] = None,
+ title: str = "Confusion Matrix",
+ path: str = "confusion_matrix.png",
+ normalize: bool = False,
+):
+ """
+ Plot confusion matrix
+ """
+ N = len(confusion_matrix)
+ size = max(10, N / 2)
+ plt.figure(figsize=(size, size), tight_layout=True)
+ fmt = "d"
+ if normalize:
+ confusion_matrix = confusion_matrix / confusion_matrix.sum(axis=1, keepdims=True) * 100
+ confusion_matrix[np.isnan(confusion_matrix)] = 0
+ fmt = ".2f"
+
+ labels = [f"{k}: {v}" for k, v in class_names.items()] if class_names else None
+ sns.heatmap(
+ confusion_matrix,
+ annot=True,
+ fmt=fmt,
+ cmap="Blues",
+ xticklabels=labels,
+ yticklabels=labels,
+ annot_kws={"fontsize": 8},
+ )
+ plt.xlabel("Predicted", fontsize=12)
+ plt.ylabel("Actual", fontsize=12)
+ plt.title(title, fontsize=14, pad=20)
+ dirname = os.path.dirname(path)
+ if dirname:
+ os.makedirs(dirname, exist_ok=True)
+ plt.savefig(path, dpi=100, bbox_inches="tight")
+ plt.close()
+
+
+@TryExcept("plot_tsne")
+def plot_tsne(
+ tsne_features: np.ndarray, # (N, 2)
+ set_ids: np.ndarray, # (N,)
+ id2label: dict[int, str], # dict {id: label}
+ output_path: str,
+):
+ assert isinstance(tsne_features, np.ndarray)
+ assert isinstance(set_ids, np.ndarray)
+ assert isinstance(id2label, dict)
+
+ plt.figure(figsize=(25, 25))
+
+ palette = sns.husl_palette(len(id2label))
+ id2color = {id: palette[i] for i, id in enumerate(id2label)}
+
+ for id, label in id2label.items():
+ mask = set_ids == id
+
+ if not np.any(mask):
+ continue
+
+ xs = tsne_features[mask, 0]
+ ys = tsne_features[mask, 1]
+
+ if "real" in label:
+ marker = "."
+ else:
+ marker = "x"
+
+ plt.scatter(xs, ys, c=[id2color[id]] * len(xs), marker=marker, label=label)
+
+ for x, y, label in zip(xs, ys, set_ids[mask]):
+ plt.text(x, y, label, c=id2color[id], fontsize=9)
+
+ plt.legend(loc="best", title="Models")
+
+ plt.tight_layout()
+
+ os.makedirs(os.path.dirname(output_path), exist_ok=True)
+ plt.savefig(output_path)
+ plt.savefig(output_path.replace(".png", ".svg"))
+
+
+@TryExcept("plot_probs_distribution")
+def plot_probs_distribution(
+ probs: np.ndarray, # (N, C)
+ labels: np.ndarray, # (N,)
+ class_names: dict[int, str], # dict {id: label}
+ output_path: str,
+):
+ n_classes = len(class_names)
+ fig, axes = plt.subplots(n_classes, 1, figsize=(10, 4 * n_classes))
+ palette = sns.husl_palette(n_classes)
+
+ # Find global min and max for x-axis limits
+ x_min = probs.min()
+ x_max = probs.max()
+
+ for idx, (class_idx, class_name) in enumerate(class_names.items()):
+ ax = axes[idx]
+
+ # Get probabilities for current class
+ class_mask = labels == class_idx
+ class_probs = probs[class_mask]
+
+ # Plot probability distribution for each possible class prediction
+ for pred_idx, pred_name in class_names.items():
+ pred_probs = class_probs[:, pred_idx]
+ sns.histplot(
+ data=pred_probs,
+ label=pred_name,
+ color=palette[pred_idx],
+ alpha=0.2,
+ # bins=30,
+ stat="probability",
+ kde=True,
+ element="step",
+ ax=ax,
+ )
+
+ ax.set_xlabel("Scores")
+ ax.set_ylabel("Probability")
+ ax.set_title(f"True Class: {class_name}", color=palette[class_idx])
+ ax.set_xlim(x_min, x_max)
+ ax.legend()
+
+ plt.tight_layout()
+ os.makedirs(os.path.dirname(output_path), exist_ok=True)
+ plt.savefig(output_path, dpi=300, bbox_inches="tight")
+ plt.close()
diff --git a/clean/image/yermandy/src/utils/checks.py b/clean/image/yermandy/src/utils/checks.py
new file mode 100644
index 0000000000000000000000000000000000000000..704f1f52ec0b29a4f5f51a78aee1fc1110d11ede
--- /dev/null
+++ b/clean/image/yermandy/src/utils/checks.py
@@ -0,0 +1,47 @@
+import os
+import shutil
+
+from ..config import Config
+from . import logger
+
+
+def checks(config: Config):
+ save_dir = f"{config.run_dir}/{config.run_name}"
+
+ if "tmp" in config.run_name:
+ logger.print_warning("Using 'tmp' in run name. Wandb will not be used.")
+ config.wandb = False
+
+ if os.path.exists(save_dir) and "tmp" not in save_dir:
+ if config.throw_exception_if_run_exists:
+ raise FileExistsError(f"Folder {save_dir} exists, remove it or use 'tmp' in run name")
+ logger.print()
+ logger.print_warning(f"folder [magenta]{save_dir}[/] exists, remove it or use 'tmp' in run name")
+ logger.print("Enter [green bold]R[/] to replace")
+ key = input()
+ if key not in ["R"]:
+ logger.print_error("Aborted")
+ exit()
+ if key == "R":
+ logger.print_warning(f"Folder [magenta]{save_dir}[/] is removed")
+ shutil.rmtree(str(save_dir))
+
+ if config.binary_labels and config.num_classes != 2:
+ raise ValueError("Binary labels is only supported for 2 classes")
+
+ def get_files_from_dict_values(d: list[str] | dict[str, list[str]]):
+ if isinstance(d, list):
+ return d
+ return [f for sublist in d.values() for f in sublist]
+
+ trn_files = get_files_from_dict_values(config.trn_files)
+ if not all(os.path.exists(f) for f in trn_files):
+ raise FileNotFoundError(f"Some train files are not found: {trn_files}")
+
+ val_files = get_files_from_dict_values(config.val_files)
+ if not all(os.path.exists(f) for f in val_files):
+ raise FileNotFoundError(f"Some val files are not found: {val_files}")
+
+ tst_files = get_files_from_dict_values(config.tst_files)
+ if not all(os.path.exists(f) for f in tst_files):
+ raise FileNotFoundError(f"Some test files are not found: {tst_files}")
diff --git a/clean/image/yermandy/src/utils/constants.py b/clean/image/yermandy/src/utils/constants.py
new file mode 100644
index 0000000000000000000000000000000000000000..b3b80703c2be98957a11f1711f80524a6b1afccb
--- /dev/null
+++ b/clean/image/yermandy/src/utils/constants.py
@@ -0,0 +1,8 @@
+import os
+
+# See more: https://pytorch.org/docs/stable/elastic/run.html#environment-variables
+RANK = int(os.getenv("LOCAL_RANK", 0))
+IS_GLOBAL_ZERO = RANK == 0
+NODE_RANK = int(os.getenv("NODE_RANK", 0))
+LOCAL_RANK = int(os.getenv("LOCAL_RANK", 0))
+WORLD_SIZE = int(os.getenv("WORLD_SIZE", 1))
diff --git a/clean/image/yermandy/src/utils/decorators.py b/clean/image/yermandy/src/utils/decorators.py
new file mode 100644
index 0000000000000000000000000000000000000000..beceb0bcbedad0ba9155be56b08685f2f4f0854c
--- /dev/null
+++ b/clean/image/yermandy/src/utils/decorators.py
@@ -0,0 +1,38 @@
+import contextlib
+import functools
+
+from .logger import print_error
+
+
+class TryExcept(contextlib.ContextDecorator):
+ """Usage: @TryExcept() decorator or 'with TryExcept():' context manager."""
+
+ def __init__(self, msg="", verbose=True):
+ """Initialize TryExcept class with optional message and verbosity settings."""
+ self.msg = msg
+ self.verbose = verbose
+
+ def __call__(self, func):
+ """
+ Allows the instance to be used as a decorator.
+ """
+
+ @functools.wraps(func)
+ def wrapper(*args, **kwargs):
+ try:
+ return func(*args, **kwargs)
+ except Exception as e:
+ msg = f"{self.msg}{': ' if self.msg else ''}[red]{e}[/red]"
+ print_error(f"caught by [green]{func.__name__}[/green] decorator. {msg}")
+
+ return wrapper
+
+ def __enter__(self):
+ """Executes when entering TryExcept context, initializes instance."""
+ return self
+
+ def __exit__(self, exc_type, value, traceback):
+ """Defines behavior when exiting a 'with' block, prints error message if necessary."""
+ if self.verbose and value:
+ print_error(f"{self.msg}{': ' if self.msg else ''}{value}")
+ return True
diff --git a/clean/image/yermandy/src/utils/files.py b/clean/image/yermandy/src/utils/files.py
new file mode 100644
index 0000000000000000000000000000000000000000..70e1c61ea8a745f72f18b5226d40cbef0e87550a
--- /dev/null
+++ b/clean/image/yermandy/src/utils/files.py
@@ -0,0 +1,161 @@
+def get_FF_train_files():
+ return [
+ "config/datasets/FF/train/DF.txt",
+ "config/datasets/FF/train/F2F.txt",
+ "config/datasets/FF/train/FS.txt",
+ "config/datasets/FF/train/NT.txt",
+ "config/datasets/FF/train/real.txt",
+ ]
+
+
+def get_FF_val_files():
+ return [
+ "config/datasets/FF/val/DF.txt",
+ "config/datasets/FF/val/F2F.txt",
+ "config/datasets/FF/val/FS.txt",
+ "config/datasets/FF/val/NT.txt",
+ "config/datasets/FF/val/real.txt",
+ ]
+
+
+def get_FF_test_files():
+ return [
+ "config/datasets/FF/test/DF.txt",
+ "config/datasets/FF/test/F2F.txt",
+ "config/datasets/FF/test/FS.txt",
+ "config/datasets/FF/test/NT.txt",
+ "config/datasets/FF/test/real.txt",
+ ]
+
+
+def get_FF_DF_test_files():
+ return [
+ "config/datasets/FF/test/DF.txt",
+ "config/datasets/FF/test/real.txt",
+ ]
+
+
+def get_FF_F2F_test_files():
+ return [
+ "config/datasets/FF/test/F2F.txt",
+ "config/datasets/FF/test/real.txt",
+ ]
+
+
+def get_FF_FS_test_files():
+ return [
+ "config/datasets/FF/test/FS.txt",
+ "config/datasets/FF/test/real.txt",
+ ]
+
+
+def get_FF_NT_test_files():
+ return [
+ "config/datasets/FF/test/NT.txt",
+ "config/datasets/FF/test/real.txt",
+ ]
+
+
+def get_CDF_all_files():
+ return [
+ "config/datasets/CDFv2/all/Celeb-synthesis.txt",
+ "config/datasets/CDFv2/all/YouTube-real.txt",
+ "config/datasets/CDFv2/all/Celeb-real.txt",
+ ]
+
+
+def get_CDF_test_files():
+ return [
+ "config/datasets/CDFv2/test/Celeb-synthesis.txt",
+ "config/datasets/CDFv2/test/YouTube-real.txt",
+ "config/datasets/CDFv2/test/Celeb-real.txt",
+ ]
+
+
+def get_FF_FaceFusion_train_files():
+ return [
+ "config/datasets/FaceFusion/train/ff_inswapper_128_fp16.txt",
+ ]
+
+
+def get_CDF_FaceFusion_test_files():
+ return [
+ "config/datasets/FaceFusion/test/cdf_hififace_unofficial_256.txt",
+ "config/datasets/FaceFusion/test/cdf_inswapper_128_fp16.txt",
+ "config/datasets/CDFv2/test/YouTube-real.txt",
+ "config/datasets/CDFv2/test/Celeb-real.txt",
+ ]
+
+
+def get_DFD_files():
+ return [
+ "config/datasets/DFD/fake.txt",
+ "config/datasets/DFD/real.txt",
+ ]
+
+
+def get_DFDC_test_files():
+ return [
+ "config/datasets/DFDC/test/fake.txt",
+ "config/datasets/DFDC/test/real.txt",
+ ]
+
+
+def get_FSh_test_files():
+ return [
+ "config/datasets/FSh/test/fake.txt",
+ "config/datasets/FSh/test/real.txt",
+ ]
+
+
+def get_UADFD_files():
+ return [
+ "config/datasets/UADFD/fake.txt",
+ "config/datasets/UADFD/real.txt",
+ ]
+
+
+def get_DFDM_files():
+ return [
+ "config/datasets/DFDM/all/dfaker.txt",
+ "config/datasets/DFDM/all/dfl.txt",
+ "config/datasets/DFDM/all/iae.txt",
+ "config/datasets/DFDM/all/lightweight.txt",
+ "config/datasets/CDFv2/all/Celeb-real.txt",
+ ]
+
+
+def get_FFIW_files():
+ return [
+ "config/datasets/FFIW/fake.txt",
+ "config/datasets/FFIW/real.txt",
+ ]
+
+
+def get_AVLips_files():
+ return [
+ "config/datasets/AVLips/fake.txt",
+ "config/datasets/AVLips/real.txt",
+ ]
+
+
+def get_DeepSpeak_test_files():
+ return [
+ "config/datasets/DeepSpeak/test-facefusion_gan.txt",
+ "config/datasets/DeepSpeak/test-facefusion_live.txt",
+ "config/datasets/DeepSpeak/test-facefusion.txt",
+ "config/datasets/DeepSpeak/test-real.txt",
+ "config/datasets/DeepSpeak/test-retalking.txt",
+ "config/datasets/DeepSpeak/test-wav2lip.txt",
+ ]
+
+
+def get_DeepSpeak_train_files():
+ return [
+ "config/datasets/DeepSpeak/train-facefusion_gan.txt",
+ "config/datasets/DeepSpeak/train-facefusion_live.txt",
+ "config/datasets/DeepSpeak/train-facefusion.txt",
+ "config/datasets/DeepSpeak/train-real.txt",
+ "config/datasets/DeepSpeak/train-retalking.txt",
+ "config/datasets/DeepSpeak/train-wav2lip.txt",
+ ]
diff --git a/clean/image/yermandy/src/utils/logger.py b/clean/image/yermandy/src/utils/logger.py
new file mode 100644
index 0000000000000000000000000000000000000000..89973b049a778a223ad3fec0f77c15f785db5f4f
--- /dev/null
+++ b/clean/image/yermandy/src/utils/logger.py
@@ -0,0 +1,39 @@
+from rich import print as rprint
+
+from .constants import IS_GLOBAL_ZERO
+
+__all__ = ["print_error", "print_info", "print_warning", "print", "print_warning_once"]
+
+printed_warnings = set()
+
+
+def print_error(text="", only_zero_rank=False):
+ if only_zero_rank and not IS_GLOBAL_ZERO:
+ return
+ rprint(f"[red bold]ERROR: [/red bold]{text}")
+
+
+def print_warning(text="", only_zero_rank=False):
+ if only_zero_rank and not IS_GLOBAL_ZERO:
+ return
+ rprint(f"[yellow bold]WARNING: [/yellow bold]{text}")
+
+
+def print_warning_once(text="", only_zero_rank=False):
+ global printed_warnings
+ if text in printed_warnings:
+ return
+ printed_warnings.add(text)
+ print_warning(text, only_zero_rank)
+
+
+def print_info(text="", only_zero_rank=True):
+ if only_zero_rank and not IS_GLOBAL_ZERO:
+ return
+ rprint(f"[blue bold]INFO: [/blue bold]{text}")
+
+
+def print(text="", only_zero_rank=True):
+ if only_zero_rank and not IS_GLOBAL_ZERO:
+ return
+ rprint(text)
diff --git a/clean/image/yermandy/src/utils/model_checkpoint.py b/clean/image/yermandy/src/utils/model_checkpoint.py
new file mode 100644
index 0000000000000000000000000000000000000000..08001bb7b755359a3f6377999c1015738a51e6d0
--- /dev/null
+++ b/clean/image/yermandy/src/utils/model_checkpoint.py
@@ -0,0 +1,50 @@
+from concurrent.futures import ThreadPoolExecutor
+
+from lightning.pytorch import callbacks as pl_callbacks
+from typing_extensions import override
+
+from src.utils import logger
+
+
+class ModelCheckpointParallel(pl_callbacks.ModelCheckpoint):
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.threads = []
+ self.thread_pool = ThreadPoolExecutor(1, thread_name_prefix="ModelCheckpointParallel")
+
+ @override
+ def on_train_batch_end(self, *args, **kwargs):
+ trainer = args[0]
+ if self._should_skip_saving_checkpoint(trainer):
+ return
+ self.threads.append(self.thread_pool.submit(super().on_train_batch_end, *args, **kwargs))
+
+ @override
+ def on_train_epoch_end(self, *args, **kwargs):
+ trainer = args[0]
+ if not self._should_skip_saving_checkpoint(trainer) and self._should_save_on_train_epoch_end(trainer):
+ self.threads.append(self.thread_pool.submit(super().on_train_epoch_end, *args, **kwargs))
+
+ @override
+ def on_validation_end(self, *args, **kwargs):
+ trainer = args[0]
+ if not self._should_skip_saving_checkpoint(trainer) and not self._should_save_on_train_epoch_end(trainer):
+ self.threads.append(self.thread_pool.submit(super().on_validation_end, *args, **kwargs))
+
+ def wait(self):
+ for thread in self.threads:
+ try:
+ thread.result()
+ except Exception as e:
+ logger.print_error(f"Exception during checkpoint saving in thread: {e}")
+ self.thread_pool.shutdown(wait=True)
+ self.thread_pool = ThreadPoolExecutor(1, thread_name_prefix="ModelCheckpointParallel")
+ self.threads = []
+
+ @override
+ def on_train_end(self, *args, **kwargs):
+ self.wait()
+
+ @override
+ def on_test_start(self, *args, **kwargs):
+ self.wait()
diff --git a/clean/image/yermandy/src/utils/wb.py b/clean/image/yermandy/src/utils/wb.py
new file mode 100644
index 0000000000000000000000000000000000000000..18f084fc7c8ec224c2b58961aa6c965909b6a0aa
--- /dev/null
+++ b/clean/image/yermandy/src/utils/wb.py
@@ -0,0 +1,100 @@
+import numpy as np
+import pandas as pd
+import wandb
+
+from .decorators import TryExcept
+
+
+@TryExcept()
+def create_custom_wandb_metric(
+ xs: list,
+ ys: list,
+ classes: list,
+ title: str = "Precision Recall Curve",
+ x_axis_title: str = "Recall",
+ y_axis_title: str = "Precision",
+):
+ """Creates a custom wandb metric similar to default wandb.plot.pr_curve
+
+ Args:
+ xs: list of N values to plot on the x-axis
+ ys: list of N values to plot on the y-axis
+ classes: class labels for each point (list of N values)
+ title: plot title
+
+ Returns:
+ wandb object to log
+ """
+ df = pd.DataFrame(
+ {
+ "class": classes,
+ "y": ys,
+ "x": xs,
+ }
+ ).round(3)
+
+ return wandb.plot_table(
+ "wandb/area-under-curve/v0",
+ wandb.Table(dataframe=df),
+ {"x": "x", "y": "y", "class": "class"},
+ {
+ "title": title,
+ "x-axis-title": x_axis_title,
+ "y-axis-title": y_axis_title,
+ },
+ )
+
+
+@TryExcept()
+def plot_curve_wandb(
+ xs: np.ndarray,
+ ys: np.ndarray,
+ names: list = [],
+ id: str = "precision-recall",
+ title: str = "Precision Recall Curve",
+ x_axis_title: str = "Recall",
+ y_axis_title: str = "Precision",
+ num_xs: int = 100,
+ only_mean: bool = True,
+):
+ """adds a metric curve to wandb
+
+ Args:
+ xs: np.array of N values
+ ys: np.array of C by N values where C is the number of classes
+ names: dict of class names
+ id: log id in wandb
+ title: plot title in wandb
+ num_xs: number of points to interpolate to
+ only_mean: if True, only the mean curve is plotted
+ """
+ # create new xs
+ xs_new = np.linspace(xs[0], xs[-1], num_xs)
+
+ # create arrays for logging
+ xs_log = xs_new.tolist()
+ ys_log = np.interp(xs_new, xs, np.mean(ys, axis=0)).tolist()
+ classes = ["mean"] * len(xs_log)
+
+ if not only_mean and len(names) == len(ys):
+ for i, y in enumerate(ys):
+ # add new xs
+ xs_log.extend(xs_new)
+ # interpolate y to new xs
+ ys_log.extend(np.interp(xs_new, xs, y))
+ # add class names
+ classes.extend([names[i]] * len(xs_new))
+
+ wandb.log(
+ {
+ id: create_custom_wandb_metric(
+ xs_log,
+ ys_log,
+ classes,
+ title,
+ x_axis_title,
+ y_axis_title,
+ )
+ },
+ commit=False,
+ )
diff --git a/clean/video/dfd_fcg/.gitignore b/clean/video/dfd_fcg/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..bcf1a76ca3f21213a2506010a202decc90276c96
--- /dev/null
+++ b/clean/video/dfd_fcg/.gitignore
@@ -0,0 +1,20 @@
+logs
+__pycache__
+.ipynb_checkpoints
+.DS_Store
+*.swp
+wandb/
+*.env
+datasets/
+datasets
+.cache/
+.cache
+lightning_logs/
+.lr_find_*
+RealForensicPreds/
+results/
+checkpoint/
+.vscode/
+resources/cropped/
+resources/frame_data/
+*.pt
\ No newline at end of file
diff --git a/clean/video/dfd_fcg/SOURCE.md b/clean/video/dfd_fcg/SOURCE.md
new file mode 100644
index 0000000000000000000000000000000000000000..c11a9a51b78482f4eb425934f806f2719e71ebb8
--- /dev/null
+++ b/clean/video/dfd_fcg/SOURCE.md
@@ -0,0 +1,17 @@
+# Source: video/dfd_fcg
+
+| Field | Value |
+|---|---|
+| Upstream | **UNVERIFIED** -- provenance was lost when this code was vendored |
+| Paper | https://arxiv.org/abs/2404.05583 |
+| Commit SHA | **not recorded** -- the vendoring step did not preserve it |
+| Mirrored on | 2026-09-15 |
+| Upstream license | no license file present upstream (all rights reserved) |
+
+This is a **mirror**, stripped to the files needed for inference. The full
+untouched snapshot is at `archive/video__dfd_fcg.tar.gz`.
+
+This code is the work of its original authors and is **not** covered by the
+DeepSafe project license. If you are an author and want this removed, open an
+issue on https://github.com/deepsafehq/deepsafe-bench and it will be taken down
+within 48 hours, no questions asked.
diff --git a/clean/video/dfd_fcg/configs/base.yaml b/clean/video/dfd_fcg/configs/base.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..6bc41d16a04af1df75b717f17c14ace8bf3a864a
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/base.yaml
@@ -0,0 +1,102 @@
+# lightning.pytorch==2.0.7
+seed_everything: 1019
+trainer:
+ accelerator: auto
+ strategy: auto
+ devices: 4
+ num_nodes: 1
+ precision: 16
+ logger: logger.yaml
+ callbacks: null
+ fast_dev_run: false
+ max_epochs: 30
+ min_epochs: null
+ max_steps: -1
+ min_steps: null
+ max_time: null
+ limit_train_batches: null
+ limit_val_batches: 10
+ limit_test_batches: null
+ limit_predict_batches: null
+ overfit_batches: 0.0
+ val_check_interval: 1.0
+ check_val_every_n_epoch: 1
+ num_sanity_val_steps: null
+ log_every_n_steps: 10
+ enable_checkpointing: null
+ enable_progress_bar: null
+ enable_model_summary: null
+ accumulate_grad_batches: 1
+ gradient_clip_val: 0.1
+ gradient_clip_algorithm: norm
+ deterministic: true
+ benchmark: null
+ inference_mode: true
+ use_distributed_sampler: true
+ profiler: null
+ detect_anomaly: false
+ barebones: false
+ plugins: null
+ sync_batchnorm: false
+ reload_dataloaders_every_n_epochs: 0
+ default_root_dir: "./logs/"
+early_stop:
+ monitor: "valid/FFPP/auc"
+ min_delta: 0.0
+ patience: 10
+ verbose: false
+ mode: max
+ strict: true
+ check_finite: true
+ stopping_threshold: null
+ divergence_threshold: null
+ check_on_train_epoch_end: null
+ log_rank_zero_only: false
+checkpoint:
+ dirpath: null
+ filename: null
+ monitor: "valid/FFPP/auc"
+ verbose: false
+ save_last: true
+ save_top_k: 1
+ save_weights_only: false
+ mode: max
+ auto_insert_metric_name: true
+ every_n_train_steps: null
+ train_time_interval: null
+ every_n_epochs: null
+ save_on_train_epoch_end: null
+lr_monitor:
+ logging_interval: epoch
+ log_momentum: false
+progress_bar:
+ refresh_rate: 1
+ leave: false
+ theme:
+ description: '#8250E5'
+ progress_bar: '#7FFF00'
+ progress_bar_finished: '#7FFF00'
+ progress_bar_pulse: '#7FFF00'
+ batch_progress: '#5398FE'
+ time: grey54
+ processing_speed: grey70
+ metrics: white
+ console_kwargs: null
+optimizer:
+ lr: 0.0001
+ betas:
+ - 0.9
+ - 0.999
+ eps: 1.0e-08
+ weight_decay: 0.001
+ amsgrad: false
+ maximize: false
+ foreach: null
+ differentiable: false
+lr_scheduler:
+ start_factor: 1.0
+ end_factor: 1.0
+ total_iters: 1
+ last_epoch: -1
+ verbose: false
+data: data.yaml
\ No newline at end of file
diff --git a/clean/video/dfd_fcg/configs/clip/L14/evl.yaml b/clean/video/dfd_fcg/configs/clip/L14/evl.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..161bb75501ad7a688f38dbfb45566a8aa3a5569e
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/clip/L14/evl.yaml
@@ -0,0 +1,7 @@
+model:
+ class_path: src.model.clip.evl.EfficientVideoLearner
+ init_args:
+ num_frames: 10
+ architecture: ViT-L/14
+trainer:
+ accumulate_grad_batches: 1
\ No newline at end of file
diff --git a/clean/video/dfd_fcg/configs/clip/L14/ffg.yaml b/clean/video/dfd_fcg/configs/clip/L14/ffg.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..0f3e56895b27dffd167c19d0ccb2fde6033363ed
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/clip/L14/ffg.yaml
@@ -0,0 +1,15 @@
+model:
+ class_path: src.model.clip.svl.FFGSynoVideoLearner
+ init_args:
+ num_frames: 10
+ architecture: ViT-L/14
+ ksize_s: 5
+ ksize_t: 5
+ s_k_attr: 'k'
+ s_v_attr: 'emb'
+ t_attrs: ["q","k","v"]
+ face_feature_path: "misc/L14_real_semantic_patches_v4_2000.pickle"
+ face_parts: ["lips","skin","eyes","nose"]
+
+trainer:
+ accumulate_grad_batches: 1
\ No newline at end of file
diff --git a/clean/video/dfd_fcg/configs/clip/L14/fulltune.yaml b/clean/video/dfd_fcg/configs/clip/L14/fulltune.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..30572d2b53800e8ada497861d45751b3eabf8e76
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/clip/L14/fulltune.yaml
@@ -0,0 +1,6 @@
+model:
+ class_path: src.model.clip.finetune.FullTuneVideoLearner
+ init_args:
+ architecture: ViT-L/14
+trainer:
+ accumulate_grad_batches: 1
diff --git a/clean/video/dfd_fcg/configs/clip/L14/linear.yaml b/clean/video/dfd_fcg/configs/clip/L14/linear.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..1091fb9dc191f376030c2afd24a4b21da1290079
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/clip/L14/linear.yaml
@@ -0,0 +1,6 @@
+model:
+ class_path: src.model.clip.linear.LinearVideoLearner
+ init_args:
+ architecture: ViT-L/14
+trainer:
+ accumulate_grad_batches: 1
\ No newline at end of file
diff --git a/clean/video/dfd_fcg/configs/clip/L14/svl.yaml b/clean/video/dfd_fcg/configs/clip/L14/svl.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c7d7285e97d93fc640b06113785dd6f161b5fa00
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/clip/L14/svl.yaml
@@ -0,0 +1,12 @@
+model:
+ class_path: src.model.clip.svl.SynoVideoLearner
+ init_args:
+ num_frames: 10
+ architecture: ViT-L/14
+ ksize_s: 5
+ ksize_t: 5
+ s_k_attr: 'k'
+ s_v_attr: 'emb'
+ t_attrs: ["q","k","v"]
+trainer:
+ accumulate_grad_batches: 1
\ No newline at end of file
diff --git a/clean/video/dfd_fcg/configs/clip/L14/vpt.yaml b/clean/video/dfd_fcg/configs/clip/L14/vpt.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d26e13b934b95cdf4caf2330927d5bce72a532a1
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/clip/L14/vpt.yaml
@@ -0,0 +1,7 @@
+model:
+ class_path: src.model.clip.vpt.PromptedLinearVideoLearner
+ init_args:
+ architecture: ViT-L/14
+ num_prompts: 1
+trainer:
+ accumulate_grad_batches: 1
diff --git a/clean/video/dfd_fcg/configs/data.yaml b/clean/video/dfd_fcg/configs/data.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..b7ffd5aaefb51732836cb06f6afbdff6805e378a
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/data.yaml
@@ -0,0 +1,54 @@
+class_path: src.dataset.base.ODDeepFakeDataModule
+init_args:
+ batch_size: 20
+ num_workers: 4
+ clip_duration: 3
+ num_frames: 10
+ train_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ batch_size: 30
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: FORCE_PAIR
+ augmentations:
+ - NORMAL
+ - VIDEO
+ - VIDEO_RRC
+ - FRAME
+ force_random_speed: null
+ data_dir: 'datasets/ffpp/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 3
+ val_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ data_dir: 'datasets/ffpp/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
+ - class_path: src.dataset.cdf.CDFDataModule
+ init_args:
+ data_dir: 'datasets/cdf/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
+ - class_path: src.dataset.dfdc.DFDCDataModule
+ init_args:
+ data_dir: 'datasets/dfdc/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
+ - class_path: src.dataset.fsh.FShDataModule
+ init_args:
+ compressions: ['c23']
+ data_dir: 'datasets/ffpp/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
\ No newline at end of file
diff --git a/clean/video/dfd_fcg/configs/inference.yaml b/clean/video/dfd_fcg/configs/inference.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..0e8e8942e5de10a5519b50d40b04cd122b9c5128
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/inference.yaml
@@ -0,0 +1,39 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ # - class_path: src.dataset.ffpp.FFPPDataModule
+ # init_args:
+ # df_types: ['REAL','DF','FS','F2F','NT']
+ # compressions: ['c23']
+ # strategy: NORMAL
+ # augmentations:
+ # - NONE
+ # force_random_speed: null
+ # data_dir: 'datasets/ffpp/'
+ # vid_ext: .avi
+ - class_path: src.dataset.cdf.CDFDataModule
+ init_args:
+ data_dir: 'datasets/cdf/'
+ vid_ext: .avi
+ - class_path: src.dataset.dfdc.DFDCDataModule
+ init_args:
+ data_dir: 'datasets/dfdc/'
+ vid_ext: .avi
+ - class_path: src.dataset.fsh.FShDataModule
+ init_args:
+ data_dir: 'datasets/ffpp/'
+ compressions: ['c23']
+ vid_ext: .avi
+ - class_path: src.dataset.dfo.DFoDataModule
+ init_args:
+ data_dir: 'datasets/dfo/'
+ vid_ext: .avi
+ # - class_path: src.dataset.wdf.WDFDataModule
+ # init_args:
+ # data_dir: 'datasets/wdf/'
+ # vid_ext: .avi
+ # - class_path: src.dataset.heygen.HeyGenDataModule
+ # init_args:
+ # data_dir: 'datasets/heygen/'
+ # vid_ext: .avi
\ No newline at end of file
diff --git a/clean/video/dfd_fcg/configs/logger.yaml b/clean/video/dfd_fcg/configs/logger.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..4fd862f49f84ea6a0f4a838b6b650989fb37e86e
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/logger.yaml
@@ -0,0 +1,14 @@
+class_path: lightning.pytorch.loggers.WandbLogger
+init_args:
+ name: null
+ save_dir: './logs/'
+ version: null
+ offline: false
+ dir: null
+ id: null
+ anonymous: null
+ project: 'DFD-FCG'
+ log_model: false
+ prefix: ''
+ checkpoint_name: null
+ entity: ""
\ No newline at end of file
diff --git a/clean/video/dfd_fcg/configs/loo/DF.yaml b/clean/video/dfd_fcg/configs/loo/DF.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..46522f829e0443b5be3d22748a0166ff974ae2b4
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/loo/DF.yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/ffpp/'
+ vid_ext: .avi
\ No newline at end of file
diff --git a/clean/video/dfd_fcg/configs/loo/F2F.yaml b/clean/video/dfd_fcg/configs/loo/F2F.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..cf77de2501b055113d6ad67415d017d9662aa35a
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/loo/F2F.yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','F2F']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/ffpp/'
+ vid_ext: .avi
\ No newline at end of file
diff --git a/clean/video/dfd_fcg/configs/loo/FS.yaml b/clean/video/dfd_fcg/configs/loo/FS.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..5d568f2722d1e8bb6374aedbf7e9ebf123001017
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/loo/FS.yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','FS']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/ffpp/'
+ vid_ext: .avi
\ No newline at end of file
diff --git a/clean/video/dfd_fcg/configs/loo/NT.yaml b/clean/video/dfd_fcg/configs/loo/NT.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..09da3c08cd41a575c081a8b8c933d1bd145d39b7
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/loo/NT.yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/ffpp/'
+ vid_ext: .avi
\ No newline at end of file
diff --git a/clean/video/dfd_fcg/configs/robustness/BW(1).yaml b/clean/video/dfd_fcg/configs/robustness/BW(1).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..bfe8b11ee569ef747f9f3504b373f988ab6c0a8b
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/BW(1).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/BW/1/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/BW(2).yaml b/clean/video/dfd_fcg/configs/robustness/BW(2).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..98dec180357145074f687164853fb36e2712917e
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/BW(2).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/BW/2/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/BW(3).yaml b/clean/video/dfd_fcg/configs/robustness/BW(3).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c3eed3cbe8e753c5412ceeb4a6a69a3b69ef79f5
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/BW(3).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/BW/3/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/BW(4).yaml b/clean/video/dfd_fcg/configs/robustness/BW(4).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..a3ff8f62981bf94bc1d8246787727f60630f2090
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/BW(4).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/BW/4/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/BW(5).yaml b/clean/video/dfd_fcg/configs/robustness/BW(5).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f012bb175ee4f44306f5266e128e112ef9335f93
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/BW(5).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/BW/5/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/CC(1).yaml b/clean/video/dfd_fcg/configs/robustness/CC(1).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..1f8f5f07bf9593f2a2d128c9b4145951eeaaa8ae
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/CC(1).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/CC/1/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/CC(2).yaml b/clean/video/dfd_fcg/configs/robustness/CC(2).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..75d3bb0c9a9e6b52cfffd0e2e37140c11384a066
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/CC(2).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/CC/2/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/CC(3).yaml b/clean/video/dfd_fcg/configs/robustness/CC(3).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..9f75ef937ccb538935c9ee5b6389bdfd461d7c11
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/CC(3).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/CC/3/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/CC(4).yaml b/clean/video/dfd_fcg/configs/robustness/CC(4).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..37df333768cd8bd3b11cc6c349b909b2904b4f3f
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/CC(4).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/CC/4/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/CC(5).yaml b/clean/video/dfd_fcg/configs/robustness/CC(5).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f0cc908407ee70d3c2ef4efd03824d98b5dea068
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/CC(5).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/CC/5/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/CS(1).yaml b/clean/video/dfd_fcg/configs/robustness/CS(1).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..8befe836ce3dda5e0dd899b3524181371f3622f9
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/CS(1).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/CS/1/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/CS(2).yaml b/clean/video/dfd_fcg/configs/robustness/CS(2).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..dcec3c637add6038f8985d2772655b8b27e4de38
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/CS(2).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/CS/2/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/CS(3).yaml b/clean/video/dfd_fcg/configs/robustness/CS(3).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..64d3c685156c690663352cbfd3479c1e1d3dc8cf
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/CS(3).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/CS/3/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/CS(4).yaml b/clean/video/dfd_fcg/configs/robustness/CS(4).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..23297f48350c3a0273d59f82aa87367dd1b0369d
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/CS(4).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/CS/4/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/CS(5).yaml b/clean/video/dfd_fcg/configs/robustness/CS(5).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..380ca46268191956a15bd6ae31976138c89da577
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/CS(5).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/CS/5/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/GB(1).yaml b/clean/video/dfd_fcg/configs/robustness/GB(1).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..e943d51ef71c9d5d116a4d611b5b43adba48166f
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/GB(1).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/GB/1/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/GB(2).yaml b/clean/video/dfd_fcg/configs/robustness/GB(2).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..04bad5c6b8ec045888b5cd0795fff8fa0fe16a68
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/GB(2).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/GB/2/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/GB(3).yaml b/clean/video/dfd_fcg/configs/robustness/GB(3).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..504265a055ef1e619b36f65e97306932cbdca842
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/GB(3).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/GB/3/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/GB(4).yaml b/clean/video/dfd_fcg/configs/robustness/GB(4).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..6e1f1ac89024dd82bbd92708f578b0e2c984d54d
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/GB(4).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/GB/4/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/GB(5).yaml b/clean/video/dfd_fcg/configs/robustness/GB(5).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..7ef6ab58d17150e70cb230ff303dac265cb6bb17
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/GB(5).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/GB/5/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/GNC(1).yaml b/clean/video/dfd_fcg/configs/robustness/GNC(1).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..0ee338206c5fd4f508aedd7f29e48bb1ae776c74
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/GNC(1).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/GNC/1/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/GNC(2).yaml b/clean/video/dfd_fcg/configs/robustness/GNC(2).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..6c7f598e7814032e89d3561094d0a0a625d68aea
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/GNC(2).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/GNC/2/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/GNC(3).yaml b/clean/video/dfd_fcg/configs/robustness/GNC(3).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..0aa872909067c8a5abcf5093e5ca178550004bbe
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/GNC(3).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/GNC/3/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/GNC(4).yaml b/clean/video/dfd_fcg/configs/robustness/GNC(4).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f18c8911e433b27cac7754a7236615c49095cd69
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/GNC(4).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/GNC/4/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/GNC(5).yaml b/clean/video/dfd_fcg/configs/robustness/GNC(5).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..eff0dbcb21468b2376a99194e7a99a4bb40baf92
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/GNC(5).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/GNC/5/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/JPEG(1).yaml b/clean/video/dfd_fcg/configs/robustness/JPEG(1).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..34df961d124571eb2d53eed34479e76f75108f3e
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/JPEG(1).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/JPEG/1/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/JPEG(2).yaml b/clean/video/dfd_fcg/configs/robustness/JPEG(2).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d2e41669b281955be72fdeb9df3990454528c9f5
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/JPEG(2).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/JPEG/2/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/JPEG(3).yaml b/clean/video/dfd_fcg/configs/robustness/JPEG(3).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..7f712441e237f14d3dac4dd3d219394bf984da1e
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/JPEG(3).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/JPEG/3/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/JPEG(4).yaml b/clean/video/dfd_fcg/configs/robustness/JPEG(4).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..390c3ab57d45a0a58e42f2b47caa13843757f239
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/JPEG(4).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/JPEG/4/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/JPEG(5).yaml b/clean/video/dfd_fcg/configs/robustness/JPEG(5).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c00b4333e1c58650459a0f6fd3346cf78fc1c6d5
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/JPEG(5).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/JPEG/5/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/VC(1).yaml b/clean/video/dfd_fcg/configs/robustness/VC(1).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..5068a29747572c63897cf4b669ed8bc662ee1bc9
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/VC(1).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/VC/1/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/VC(2).yaml b/clean/video/dfd_fcg/configs/robustness/VC(2).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..482b48c2ad05e23d981c48b6f9d71f91d70f2625
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/VC(2).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/VC/2/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/VC(3).yaml b/clean/video/dfd_fcg/configs/robustness/VC(3).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..46080156a6d814d8f7ef22304fca0ec5fe8b9949
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/VC(3).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/VC/3/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/VC(4).yaml b/clean/video/dfd_fcg/configs/robustness/VC(4).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..1323f3ca40022ca22fdbc0aa6cbf1f75345f91da
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/VC(4).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/VC/4/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/robustness/VC(5).yaml b/clean/video/dfd_fcg/configs/robustness/VC(5).yaml
new file mode 100644
index 0000000000000000000000000000000000000000..da4cc376c35e315617b7c18111148411383ef770
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/robustness/VC(5).yaml
@@ -0,0 +1,14 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/VC/5/'
+ vid_ext: .avi
diff --git a/clean/video/dfd_fcg/configs/scenario/LOO/DF.yaml b/clean/video/dfd_fcg/configs/scenario/LOO/DF.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..3066eaf16ed4679f957c5df83e69b69f7bc5cf1e
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/scenario/LOO/DF.yaml
@@ -0,0 +1,32 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ train_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ batch_size: 30
+ df_types: ['REAL','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: FORCE_PAIR
+ augmentations:
+ - NORMAL
+ - VIDEO
+ - VIDEO_RRC
+ - FRAME
+ force_random_speed: null
+ data_dir: 'datasets/ffpp/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 3
+ val_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','NT','FS','F2F']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ data_dir: 'datasets/ffpp/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
\ No newline at end of file
diff --git a/clean/video/dfd_fcg/configs/scenario/LOO/F2F.yaml b/clean/video/dfd_fcg/configs/scenario/LOO/F2F.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..e16cf54b03388ab26d4c95583c6465ba6cc24d8a
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/scenario/LOO/F2F.yaml
@@ -0,0 +1,32 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ train_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ batch_size: 30
+ df_types: ['REAL','DF','FS','NT']
+ compressions: ['c23']
+ strategy: FORCE_PAIR
+ augmentations:
+ - NORMAL
+ - VIDEO
+ - VIDEO_RRC
+ - FRAME
+ force_random_speed: null
+ data_dir: 'datasets/ffpp/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 3
+ val_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ data_dir: 'datasets/ffpp/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
\ No newline at end of file
diff --git a/clean/video/dfd_fcg/configs/scenario/LOO/FS.yaml b/clean/video/dfd_fcg/configs/scenario/LOO/FS.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..4bf5fad5be1c1b8dbc9948dcd79195b10ede94de
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/scenario/LOO/FS.yaml
@@ -0,0 +1,32 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ train_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ batch_size: 30
+ df_types: ['REAL','DF','F2F','NT']
+ compressions: ['c23']
+ strategy: FORCE_PAIR
+ augmentations:
+ - NORMAL
+ - VIDEO
+ - VIDEO_RRC
+ - FRAME
+ force_random_speed: null
+ data_dir: 'datasets/ffpp/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 3
+ val_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ data_dir: 'datasets/ffpp/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
\ No newline at end of file
diff --git a/clean/video/dfd_fcg/configs/scenario/LOO/NT.yaml b/clean/video/dfd_fcg/configs/scenario/LOO/NT.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..7dcd5d9abfdfdc79f979bdfdea9f8d5bc7a5766c
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/scenario/LOO/NT.yaml
@@ -0,0 +1,32 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ train_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ batch_size: 30
+ df_types: ['REAL','DF','FS','F2F']
+ compressions: ['c23']
+ strategy: FORCE_PAIR
+ augmentations:
+ - NORMAL
+ - VIDEO
+ - VIDEO_RRC
+ - FRAME
+ force_random_speed: null
+ data_dir: 'datasets/ffpp/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 3
+ val_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ data_dir: 'datasets/ffpp/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
\ No newline at end of file
diff --git a/clean/video/dfd_fcg/configs/scenario/compression/c40.yaml b/clean/video/dfd_fcg/configs/scenario/compression/c40.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..a77223236690d4e4b6633fafa8f6ceb72e7bbd20
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/scenario/compression/c40.yaml
@@ -0,0 +1,55 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ batch_size: 20
+ num_workers: 4
+ clip_duration: 3
+ num_frames: 10
+ train_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ batch_size: 30
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c40']
+ strategy: FORCE_PAIR
+ augmentations:
+ - NORMAL
+ - VIDEO
+ - VIDEO_RRC
+ - FRAME
+ force_random_speed: null
+ data_dir: 'datasets/ffpp/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 3
+ val_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c40']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ data_dir: 'datasets/ffpp/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
+ - class_path: src.dataset.cdf.CDFDataModule
+ init_args:
+ data_dir: 'datasets/cdf/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
+ - class_path: src.dataset.dfdc.DFDCDataModule
+ init_args:
+ data_dir: 'datasets/dfdc/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
+ - class_path: src.dataset.fsh.FShDataModule
+ init_args:
+ compressions: ['c40']
+ data_dir: 'datasets/ffpp/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
\ No newline at end of file
diff --git a/clean/video/dfd_fcg/configs/scenario/compression/raw.yaml b/clean/video/dfd_fcg/configs/scenario/compression/raw.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..9d54564f5a885f7c4b9532f10fb87732425d3ecc
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/scenario/compression/raw.yaml
@@ -0,0 +1,55 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ batch_size: 20
+ num_workers: 4
+ clip_duration: 3
+ num_frames: 10
+ train_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ batch_size: 30
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['raw']
+ strategy: FORCE_PAIR
+ augmentations:
+ - NORMAL
+ - VIDEO
+ - VIDEO_RRC
+ - FRAME
+ force_random_speed: null
+ data_dir: 'datasets/ffpp/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 3
+ val_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['raw']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ data_dir: 'datasets/ffpp/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
+ - class_path: src.dataset.cdf.CDFDataModule
+ init_args:
+ data_dir: 'datasets/cdf/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
+ - class_path: src.dataset.dfdc.DFDCDataModule
+ init_args:
+ data_dir: 'datasets/dfdc/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
+ - class_path: src.dataset.fsh.FShDataModule
+ init_args:
+ compressions: ['raw']
+ data_dir: 'datasets/ffpp/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
\ No newline at end of file
diff --git a/clean/video/dfd_fcg/configs/scenario/partial/10.yaml b/clean/video/dfd_fcg/configs/scenario/partial/10.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..fcd76edb569307639d65da35dcfa4e7e8c7b709e
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/scenario/partial/10.yaml
@@ -0,0 +1,56 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ batch_size: 20
+ num_workers: 4
+ clip_duration: 3
+ num_frames: 10
+ train_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ batch_size: 30
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: FORCE_PAIR
+ augmentations:
+ - NORMAL
+ - VIDEO
+ - VIDEO_RRC
+ - FRAME
+ force_random_speed: null
+ data_dir: 'datasets/ffpp/'
+ vid_ext: '.avi'
+ pack: false
+ ratio: 0.1
+ max_clips: 3
+ val_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ data_dir: 'datasets/ffpp/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
+ - class_path: src.dataset.cdf.CDFDataModule
+ init_args:
+ data_dir: 'datasets/cdf/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
+ - class_path: src.dataset.dfdc.DFDCDataModule
+ init_args:
+ data_dir: 'datasets/dfdc/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
+ - class_path: src.dataset.fsh.FShDataModule
+ init_args:
+ compressions: ['c23']
+ data_dir: 'datasets/ffpp/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
\ No newline at end of file
diff --git a/clean/video/dfd_fcg/configs/scenario/partial/25.yaml b/clean/video/dfd_fcg/configs/scenario/partial/25.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..b83215271c4d143422ea5769b3c71fc8ae42f39c
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/scenario/partial/25.yaml
@@ -0,0 +1,56 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ batch_size: 20
+ num_workers: 4
+ clip_duration: 3
+ num_frames: 10
+ train_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ batch_size: 30
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: FORCE_PAIR
+ augmentations:
+ - NORMAL
+ - VIDEO
+ - VIDEO_RRC
+ - FRAME
+ force_random_speed: null
+ data_dir: 'datasets/ffpp/'
+ vid_ext: '.avi'
+ pack: false
+ ratio: 0.25
+ max_clips: 3
+ val_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ data_dir: 'datasets/ffpp/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
+ - class_path: src.dataset.cdf.CDFDataModule
+ init_args:
+ data_dir: 'datasets/cdf/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
+ - class_path: src.dataset.dfdc.DFDCDataModule
+ init_args:
+ data_dir: 'datasets/dfdc/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
+ - class_path: src.dataset.fsh.FShDataModule
+ init_args:
+ compressions: ['c23']
+ data_dir: 'datasets/ffpp/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
\ No newline at end of file
diff --git a/clean/video/dfd_fcg/configs/scenario/partial/50.yaml b/clean/video/dfd_fcg/configs/scenario/partial/50.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..935664fbe1b1b3fbf87ba0d0edcbd3e8331d524d
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/scenario/partial/50.yaml
@@ -0,0 +1,56 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ batch_size: 20
+ num_workers: 4
+ clip_duration: 3
+ num_frames: 10
+ train_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ batch_size: 30
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: FORCE_PAIR
+ augmentations:
+ - NORMAL
+ - VIDEO
+ - VIDEO_RRC
+ - FRAME
+ force_random_speed: null
+ data_dir: 'datasets/ffpp/'
+ vid_ext: '.avi'
+ pack: false
+ ratio: 0.50
+ max_clips: 3
+ val_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ data_dir: 'datasets/ffpp/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
+ - class_path: src.dataset.cdf.CDFDataModule
+ init_args:
+ data_dir: 'datasets/cdf/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
+ - class_path: src.dataset.dfdc.DFDCDataModule
+ init_args:
+ data_dir: 'datasets/dfdc/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
+ - class_path: src.dataset.fsh.FShDataModule
+ init_args:
+ compressions: ['c23']
+ data_dir: 'datasets/ffpp/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
\ No newline at end of file
diff --git a/clean/video/dfd_fcg/configs/scenario/partial/75.yaml b/clean/video/dfd_fcg/configs/scenario/partial/75.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..3f0056eeb64b1cebb407b206aad45190fe95d209
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/scenario/partial/75.yaml
@@ -0,0 +1,56 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ batch_size: 20
+ num_workers: 4
+ clip_duration: 3
+ num_frames: 10
+ train_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ batch_size: 30
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: FORCE_PAIR
+ augmentations:
+ - NORMAL
+ - VIDEO
+ - VIDEO_RRC
+ - FRAME
+ force_random_speed: null
+ data_dir: 'datasets/ffpp/'
+ vid_ext: '.avi'
+ pack: false
+ ratio: 0.75
+ max_clips: 3
+ val_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ data_dir: 'datasets/ffpp/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
+ - class_path: src.dataset.cdf.CDFDataModule
+ init_args:
+ data_dir: 'datasets/cdf/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
+ - class_path: src.dataset.dfdc.DFDCDataModule
+ init_args:
+ data_dir: 'datasets/dfdc/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
+ - class_path: src.dataset.fsh.FShDataModule
+ init_args:
+ compressions: ['c23']
+ data_dir: 'datasets/ffpp/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
\ No newline at end of file
diff --git a/clean/video/dfd_fcg/configs/scenario/robust/robust.yaml b/clean/video/dfd_fcg/configs/scenario/robust/robust.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..821ad01661d3f0faf67ff6ac234644e0aceecd75
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/scenario/robust/robust.yaml
@@ -0,0 +1,33 @@
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ batch_size: 20
+ num_workers: 4
+ clip_duration: 3
+ num_frames: 10
+ train_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ batch_size: 30
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: FORCE_PAIR
+ augmentations:
+ - ROBUSTNESS
+ force_random_speed: null
+ data_dir: 'datasets/ffpp/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 3
+ val_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ data_dir: 'datasets/ffpp/'
+ vid_ext: '.avi'
+ pack: false
+ max_clips: 1
\ No newline at end of file
diff --git a/clean/video/dfd_fcg/configs/test.yaml b/clean/video/dfd_fcg/configs/test.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..25f2599db75d635d156eed55870693fb15909a60
--- /dev/null
+++ b/clean/video/dfd_fcg/configs/test.yaml
@@ -0,0 +1,14 @@
+trainer:
+ logger:
+ init_args:
+ offline: true
+ limit_train_batches: 30
+ limit_val_batches: 30
+ accumulate_grad_batches: 1
+data:
+ init_args:
+ batch_size: 1
+ num_workers: 0
+ train_datamodules:
+ - init_args:
+ batch_size: 1
\ No newline at end of file
diff --git a/clean/video/dfd_fcg/demo.py b/clean/video/dfd_fcg/demo.py
new file mode 100644
index 0000000000000000000000000000000000000000..1ca03bb234fe3bc95f45ad78b1c55cf8617d94e5
--- /dev/null
+++ b/clean/video/dfd_fcg/demo.py
@@ -0,0 +1,192 @@
+import os
+import cv2
+import sys
+import yaml
+import json
+import math
+import torch
+import pickle
+import shutil
+import logging
+import warnings
+import argparse
+import numpy as np
+
+
+from os import path
+from datetime import datetime
+from torchvision.io import VideoReader
+from src.utility.builtin import ODTrainer, ODLightningCLI
+
+
+def parse_args(args=None):
+ parser = argparse.ArgumentParser()
+ parser.add_argument("model_cfg_path", type=str)
+ parser.add_argument("model_ckpt_path", type=str)
+ parser.add_argument("video_path", type=str)
+ parser.add_argument("--out_path", type=str, default=None)
+ parser.add_argument("--threshold", type=float, default=0.5)
+ parser.add_argument("--precision", type=str, default="16")
+ parser.add_argument("--batch_size", type=int, default=30)
+ return parser.parse_args(args=args)
+
+
+def configure_logging():
+ logging_fmt = "[%(levelname)s][%(filename)s:%(lineno)d]: %(message)s"
+ logging.basicConfig(level="INFO", format=logging_fmt)
+ warnings.filterwarnings(action="ignore")
+
+
+@torch.inference_mode()
+def demo_driver(cli, ckpt_path, video_path, out_path, batch_size, threshold):
+ # setup model
+ model = cli.model
+
+ try:
+ model = model.__class__.load_from_checkpoint(ckpt_path)
+ except Exception as e:
+ print(f"Unable to load model from checkpoint in strict mode: {e}")
+ print(f"Loading model from checkpoint in non-strict mode.")
+ model = model.__class__.load_from_checkpoint(ckpt_path, strict=False)
+
+ model.eval()
+ transforms = model.transform
+
+ BATCH = batch_size
+ stride = 0.333
+
+ # load original video
+ vid_reader = VideoReader(video_path, "video", num_threads=1)
+ vid_ext = os.path.splitext(video_path)[-1]
+ vid_name = os.path.split(video_path)[1].replace(vid_ext, "")
+ fps = vid_reader.get_metadata()["video"]["fps"][0]
+
+ frames = []
+ for frame_data in vid_reader:
+ frames.append(frame_data["data"])
+ frames = torch.stack(frames)
+ del vid_reader
+ _, H, W = frames[0].shape
+
+ # load bboxes of original video
+ with open(video_path.replace("videos", "frame_data").replace(vid_ext, ".pickle"), "rb") as f:
+ fdata = pickle.load(f)
+ bboxes = []
+ for data in fdata:
+ data["bboxes"] = [
+ bbox.reshape(2, -1)
+ if len(bbox.shape) == 1 else bbox
+ for bbox in data["bboxes"]
+ ]
+ face_idx = np.argsort([
+ np.linalg.norm((bbox[0] - bbox[1])) for bbox in data["bboxes"]
+ ])[-1]
+ bboxes.append(data["bboxes"][face_idx])
+
+ # load face cropped video
+ vid_reader = VideoReader(
+ video_path.replace("/videos", "/cropped/videos").replace(vid_ext, ".avi"),
+ "video",
+ num_threads=1
+ )
+ cropped_frames = []
+ for frame_data in vid_reader:
+ cropped_frames.append(frame_data["data"])
+ cropped_frames = torch.stack(cropped_frames)
+ del vid_reader
+
+ # sample frames and inference
+ indices = torch.tensor([int(math.floor(i * stride * fps)) for i in range(10)], dtype=torch.long)
+ probs = []
+ i = 0
+ clip_count = len(cropped_frames) - indices[-1]
+ while (i < clip_count):
+ batch = min(clip_count - i, BATCH)
+ clips = torch.stack([
+ transforms(cropped_frames[indices + i + j]) for j in range(batch)
+ ]).to("cuda")
+ results = model.evaluate(clips)
+ probs.extend(results["logits"].softmax(dim=-1)[:, 1].flatten().cpu().tolist())
+ i += batch
+
+ # draw and write to video
+ bbox_frames = []
+ for frame, bbox, prob in zip(frames[indices[-1]:], bboxes[indices[-1]:], probs):
+ frame = frame.permute(1, 2, 0).numpy()
+ frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
+ thickness = int(np.linalg.norm(bbox[0] - bbox[1]) * 0.01)
+ color = (0, 255, 0) if prob < threshold else (0, 0, 255)
+ category = "REAL" if prob < threshold else "FAKE"
+ frame = cv2.rectangle(
+ frame,
+ bbox[0].astype(int),
+ bbox[1].astype(int),
+ color,
+ thickness
+ )
+ frame = cv2.putText(
+ frame,
+ f'{round(prob,2)}',
+ [int(bbox[0][0]), int(bbox[1][1] - thickness)],
+ cv2.FONT_HERSHEY_SIMPLEX,
+ 1, color, thickness, cv2.LINE_AA
+ )
+
+ frame = cv2.putText(
+ frame,
+ category,
+ [int(bbox[0][0]), int(bbox[0][1] - thickness)],
+ cv2.FONT_HERSHEY_SIMPLEX,
+ 1, color, thickness, cv2.LINE_AA
+ )
+
+ bbox_frames.append(frame)
+
+ out_path = (f'pred_{vid_name}.avi' if out_path is None else out_path)
+
+ writer = cv2.VideoWriter(
+ out_path,
+ cv2.VideoWriter_fourcc('X', 'V', 'I', 'D'),
+ fps,
+ (W, H)
+ )
+
+ for frame in bbox_frames:
+ writer.write(frame)
+
+ writer.release()
+
+
+if __name__ == "__main__":
+ configure_logging()
+
+ params = parse_args()
+
+ cli = ODLightningCLI(
+ run=False,
+ trainer_class=ODTrainer,
+ save_config_callback=None,
+ parser_kwargs={
+ "parser_mode": "omegaconf"
+ },
+ auto_configure_optimizers=False,
+ seed_everything_default=1019,
+ args=[
+ '-c', params.model_cfg_path,
+ '--trainer.logger=null',
+ f'--trainer.devices=1',
+ f'--trainer.precision={params.precision}',
+ ],
+ )
+
+ ckpt_path = params.model_ckpt_path
+ video_path = params.video_path
+
+ demo_driver(
+ cli=cli,
+ ckpt_path=ckpt_path,
+ video_path=video_path,
+ batch_size=params.batch_size,
+ threshold=params.threshold,
+ out_path=params.out_path
+ )
diff --git a/clean/video/dfd_fcg/environment.yml b/clean/video/dfd_fcg/environment.yml
new file mode 100644
index 0000000000000000000000000000000000000000..2e28c606a69d4f1d1d8999f73ae12f1a8cb5f63f
--- /dev/null
+++ b/clean/video/dfd_fcg/environment.yml
@@ -0,0 +1,129 @@
+name: dfd-fcg
+channels:
+ - defaults
+dependencies:
+ - _libgcc_mutex=0.1
+ - _openmp_mutex=5.1
+ - ca-certificates=2023.12.12
+ - ld_impl_linux-64=2.38
+ - libffi=3.4.4
+ - libgcc-ng=11.2.0
+ - libgomp=11.2.0
+ - libstdcxx-ng=11.2.0
+ - ncurses=6.4
+ - openssl=3.0.13
+ - pip=23.3.1
+ - python=3.8.18
+ - readline=8.2
+ - setuptools=68.2.2
+ - sqlite=3.41.2
+ - tk=8.6.12
+ - wheel=0.41.2
+ - xz=5.4.6
+ - zlib=1.2.13
+ - pip:
+ - aiohttp==3.9.3
+ - aiosignal==1.3.1
+ - albumentations==1.4.0
+ - antlr4-python3-runtime==4.9.3
+ - appdirs==1.4.4
+ - async-timeout==4.0.3
+ - attrs==23.2.0
+ - av==11.0.0
+ - bitsandbytes==0.41.0
+ - certifi==2024.2.2
+ - charset-normalizer==3.3.2
+ - click==8.1.7
+ - contourpy==1.1.1
+ - cycler==0.12.1
+ - docker-pycreds==0.4.0
+ - docstring-parser==0.15
+ - face-alignment==1.4.1
+ - filelock==3.13.1
+ - fonttools==4.49.0
+ - frozenlist==1.4.1
+ - fsspec==2024.2.0
+ - ftfy==6.1.3
+ - gitdb==4.0.11
+ - gitpython==3.1.42
+ - huggingface-hub==0.21.3
+ - hydra-core==1.3.2
+ - idna==3.6
+ - imageio==2.34.0
+ - importlib-resources==6.1.2
+ - jinja2==3.1.3
+ - joblib==1.3.2
+ - jsonargparse==4.27.5
+ - kiwisolver==1.4.5
+ - lazy-loader==0.3
+ - lightning==2.2.0.post0
+ - lightning-utilities==0.10.1
+ - markdown-it-py==3.0.0
+ - markupsafe==2.1.5
+ - matplotlib==3.7.5
+ - mdurl==0.1.2
+ - mpmath==1.3.0
+ - multidict==6.0.5
+ - networkx==3.1
+ - numpy==1.24.4
+ - nvidia-cublas-cu12==12.1.3.1
+ - nvidia-cuda-cupti-cu12==12.1.105
+ - nvidia-cuda-nvrtc-cu12==12.1.105
+ - nvidia-cuda-runtime-cu12==12.1.105
+ - nvidia-cudnn-cu12==8.9.2.26
+ - nvidia-cufft-cu12==11.0.2.54
+ - nvidia-curand-cu12==10.3.2.106
+ - nvidia-cusolver-cu12==11.4.5.107
+ - nvidia-cusparse-cu12==12.1.0.106
+ - nvidia-nccl-cu12==2.19.3
+ - nvidia-nvjitlink-cu12==12.3.101
+ - nvidia-nvtx-cu12==12.1.105
+ - omegaconf==2.3.0
+ - open-clip-torch==2.24.0
+ - opencv-python==4.9.0.80
+ - opencv-python-headless==4.9.0.80
+ - packaging==23.2
+ - pandas==2.0.3
+ - pillow==10.2.0
+ - protobuf==4.25.3
+ - psutil==5.9.8
+ - pygments==2.17.2
+ - pyparsing==3.1.1
+ - python-dateutil==2.9.0.post0
+ - pytorch-lightning==2.2.0.post0
+ - pytz==2024.1
+ - pywavelets==1.4.1
+ - pyyaml==6.0.1
+ - qudida==0.0.4
+ - regex==2023.12.25
+ - requests==2.31.0
+ - rich==13.7.1
+ - safetensors==0.4.2
+ - scikit-image==0.21.0
+ - scikit-learn==1.3.2
+ - scipy==1.10.1
+ - sentencepiece==0.2.0
+ - sentry-sdk==1.40.6
+ - setproctitle==1.3.3
+ - six==1.16.0
+ - smmap==5.0.1
+ - sympy==1.12
+ - tensorboardx==2.6.2.2
+ - threadpoolctl==3.3.0
+ - tifffile==2023.7.10
+ - timm==0.9.16
+ - torch==2.2.1
+ - torchaudio==2.2.1
+ - torchmetrics==1.3.1
+ - torchvision==0.17.1
+ - tqdm==4.66.2
+ - triton==2.2.0
+ - typeshed-client==2.5.1
+ - typing-extensions==4.10.0
+ - tzdata==2024.1
+ - urllib3==2.2.1
+ - wandb==0.16.3
+ - wcwidth==0.2.13
+ - yarl==1.9.4
+ - zipp==3.17.0
+prefix: /home/od/miniconda3/envs/dfd-fcg
diff --git a/clean/video/dfd_fcg/inference.py b/clean/video/dfd_fcg/inference.py
new file mode 100644
index 0000000000000000000000000000000000000000..423f82ddcbb4fc83357d8d5ed1cb922fab370f9f
--- /dev/null
+++ b/clean/video/dfd_fcg/inference.py
@@ -0,0 +1,187 @@
+import os
+import sys
+import yaml
+import json
+import torch
+import pickle
+import shutil
+import logging
+import warnings
+import argparse
+
+
+from os import path
+from datetime import datetime
+from torchmetrics.classification import AUROC, Accuracy
+from src.utility.builtin import ODTrainer, ODLightningCLI
+
+
+def parse_args(args=None):
+ parser = argparse.ArgumentParser()
+ parser.add_argument("model_cfg_path", type=str)
+ parser.add_argument("data_cfg_path", type=str)
+ parser.add_argument("model_ckpt_path", type=str)
+ parser.add_argument("--precision", type=str, default="16")
+ parser.add_argument("--devices", type=int, default=-1)
+ parser.add_argument("--notes", type=str, default='')
+ return parser.parse_args(args=args)
+
+
+class StatsRecorder:
+ def __init__(self, label):
+ self.label = label
+ self.prob = 0
+ self.count = 0
+
+ def update(self, prob, label):
+ assert label == self.label
+ self.prob += prob
+ self.count += 1
+
+ def compute(self):
+ return {
+ "label": self.label,
+ "prob": self.prob / self.count
+ }
+
+
+def configure_logging():
+ logging_fmt = "[%(levelname)s][%(filename)s:%(lineno)d]: %(message)s"
+ logging.basicConfig(level="INFO", format=logging_fmt)
+ warnings.filterwarnings(action="ignore")
+
+
+@torch.inference_mode()
+def inference_driver(cli, cfg_dir, ckpt_path, notes=None):
+
+ timestamp = datetime.now().strftime("%m%dT%H%M%S")
+
+ trainer = cli.trainer
+
+ # setup model
+ model = cli.model
+
+ try:
+ model = model.__class__.load_from_checkpoint(ckpt_path)
+ except Exception as e:
+ print(f"Unable to load model from checkpoint in strict mode: {e}")
+ print(f"Loading model from checkpoint in non-strict mode.")
+ model = model.__class__.load_from_checkpoint(ckpt_path, strict=False)
+
+ model.eval()
+
+ # setup dataset
+ datamodule = cli.datamodule
+ datamodule.prepare_data()
+ datamodule.affine_model(cli.model)
+ datamodule.setup('test')
+
+ stats = {}
+ report = {}
+
+ test_dataloaders = datamodule.test_dataloader()
+
+ for dts_name, dataloader in test_dataloaders.items():
+ # iterate all videos
+ auc_calc = AUROC(task="BINARY", num_classes=2)
+ acc_calc = Accuracy(task="BINARY", num_classes=2)
+ dataset = dataloader.dataset
+ dts_stats = {}
+
+ # perform ddp prediction
+ batch_results = trainer.predict(
+ model=model,
+ dataloaders=[dataloader]
+ )
+
+ gathered_results = [None] * torch.distributed.get_world_size()
+ torch.distributed.all_gather_object(gathered_results, batch_results)
+ torch.distributed.barrier()
+
+ if (trainer.is_global_zero):
+ # fetch predict results and aggregate.
+ for batch_results in gathered_results:
+ for batch_result in batch_results:
+ probs = batch_result["probs"]
+ names = batch_result["names"]
+ y = batch_result["y"]
+ for prob, label, name in zip(probs, y, names):
+ if (not name in dts_stats):
+ dts_stats[name] = StatsRecorder(label)
+ dts_stats[name].update(prob, label)
+
+ # compute the average probability.
+ for k in dts_stats:
+ dts_stats[k] = dts_stats[k].compute()
+
+ # add straying videos into metric calculation
+ for k, v in dataset.stray_videos.items():
+ dts_stats[k] = dict(
+ label=v,
+ prob=0.5,
+ stray=1
+ )
+
+ # compute the metric scores
+ dataset_labels = []
+ dataset_probs = []
+ for v in dts_stats.values():
+ dataset_labels.append(v["label"])
+ dataset_probs.append(v["prob"])
+ dataset_labels = torch.tensor(dataset_labels)
+ dataset_probs = torch.tensor(dataset_probs)
+ accuracy = acc_calc(dataset_probs, dataset_labels).item()
+ roc_auc = auc_calc(dataset_probs, dataset_labels).item()
+ accuracy = round(accuracy, 3)
+ roc_auc = round(roc_auc, 3)
+ logging.info(f'[{dts_name}] accuracy: {accuracy}, roc_auc: {roc_auc}')
+ stats[dts_name] = dts_stats
+ report[dts_name] = {
+ "accuracy": accuracy,
+ "roc_auc": roc_auc
+ }
+
+ if (trainer.is_global_zero):
+ # save report and stats.
+ with open(path.join(cfg_dir, f'report_{timestamp}.json'), "w") as f:
+ json.dump(report, f, sort_keys=True, indent=4, separators=(',', ': '))
+
+ with open(path.join(cfg_dir, f'stats_{timestamp}.pickle'), "wb") as f:
+ pickle.dump(stats, f)
+
+ return report
+
+
+if __name__ == "__main__":
+ configure_logging()
+
+ params = parse_args()
+
+ cli = ODLightningCLI(
+ run=False,
+ trainer_class=ODTrainer,
+ save_config_callback=None,
+ parser_kwargs={
+ "parser_mode": "omegaconf"
+ },
+ auto_configure_optimizers=False,
+ seed_everything_default=1019,
+ args=[
+ '-c', params.model_cfg_path,
+ '-c', params.data_cfg_path,
+ '--trainer.logger=null',
+ f'--trainer.devices={params.devices}',
+ f'--trainer.precision={params.precision}',
+ ],
+ )
+
+ cfg_dir = os.path.split(params.model_cfg_path)[0]
+ ckpt_path = params.model_ckpt_path
+ notes = params.notes
+
+ inference_driver(
+ cli=cli,
+ cfg_dir=cfg_dir,
+ ckpt_path=ckpt_path,
+ notes=notes
+ )
diff --git a/clean/video/dfd_fcg/main.py b/clean/video/dfd_fcg/main.py
new file mode 100644
index 0000000000000000000000000000000000000000..9609ded1782f616217d8b7dcdb69decbbf82549f
--- /dev/null
+++ b/clean/video/dfd_fcg/main.py
@@ -0,0 +1,123 @@
+import os
+import gc
+import json
+import torch
+import logging
+import warnings
+import lightning.pytorch as pl
+
+from lightning.pytorch.utilities import rank_zero_only
+from src.utility.builtin import ODTrainer, ODLightningCLI
+from inference import inference_driver
+torch.set_float32_matmul_precision('high')
+
+
+def configure_logging():
+ logging_fmt = "[%(levelname)s][%(filename)s:%(lineno)d]: %(message)s"
+ logging.basicConfig(level="INFO", format=logging_fmt)
+ warnings.filterwarnings(action="ignore")
+
+ # disable warnings from the xformers efficient attention module due to torch.user_deterministic_algorithms(True,warn_only=True)
+ warnings.filterwarnings(
+ action="ignore",
+ message=".*efficient_attention_forward_cutlass.*",
+ category=UserWarning
+ )
+
+ # logging.basicConfig(level="DEBUG", format=logging_fmt)
+
+
+def configure_cli():
+ return ODLightningCLI(
+ run=False,
+ trainer_class=ODTrainer,
+ save_config_kwargs={
+ 'config_filename': 'setting.yaml'
+ },
+ auto_configure_optimizers=True,
+ seed_everything_default=1019
+ )
+
+
+def inference(cli):
+ # inference the best model
+ cfg_dir = cli.trainer.log_dir
+ ckpt_path = cli.trainer.checkpoint_callback.best_model_path
+
+ results = inference_driver(
+ cli=cli,
+ cfg_dir=cfg_dir,
+ ckpt_path=ckpt_path,
+ )
+
+ # log inference results
+ cli.trainer.logger.experiment.log(
+ {
+ "/".join(["infer", dts_name, metric]): value
+ for dts_name, metrics in results.items()
+ for metric, value in metrics.items()
+ },
+ commit=True
+ )
+
+ return results
+
+
+def cli_main():
+ # logging configuration
+ configure_logging()
+
+ # initialize cli
+ cli = configure_cli()
+
+ # update experiment notes
+ cli.trainer.logger.experiment.notes = cli.config.notes
+ cli.trainer.logger.experiment.save()
+
+ # monitor model gradient and parameter histograms
+ # (this severely slow down the training speed)
+ # cli.trainer.logger.experiment.watch(cli.model, log='all', log_graph=False)
+
+ # load & configure datasets
+ cli.datamodule.affine_model(cli.model)
+ cli.datamodule.affine_trainer(cli.trainer)
+
+ # determine the purpose of the given checkpoint
+ cont_ckpt_path = None
+ if not cli.config.ckpt_path is None:
+ if cli.config.ckpt_mode == "cont":
+ cont_ckpt_path = cli.config.ckpt_path
+ elif cli.config.ckpt_mode == "tune":
+ cli.model.load_state_dict(torch.load(cli.config.ckpt_path)["state_dict"])
+ else:
+ raise NotImplementedError()
+
+ # run
+ cli.trainer.fit(
+ cli.model,
+ datamodule=cli.datamodule,
+ ckpt_path=cont_ckpt_path
+ )
+
+ # after training:
+ # 1. unwatch model
+ # cli.trainer.logger.experiment.unwatch(cli.model)
+ # 2. save the config
+ cli.trainer.logger.experiment.save(
+ glob_str=os.path.join(cli.trainer.log_dir, 'setting.yaml'),
+ base_path=cli.trainer.log_dir,
+ policy="now"
+ )
+
+ gc.collect()
+ torch.cuda.empty_cache()
+
+ # inference the best model.
+ scores = inference(cli=cli)
+
+ # finally
+ cli.trainer.logger.experiment.finish()
+
+
+if __name__ == "__main__":
+ cli_main()
diff --git a/clean/video/dfd_fcg/misc/20words_mean_face.npy b/clean/video/dfd_fcg/misc/20words_mean_face.npy
new file mode 100644
index 0000000000000000000000000000000000000000..fc5cd3103270737752bebaec497c39b49b2af970
--- /dev/null
+++ b/clean/video/dfd_fcg/misc/20words_mean_face.npy
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:dbf68b2044171e1160716df7c53e8bbfaa0ee8c61fb41171d04cb6092bb81422
+size 1168
diff --git a/clean/video/dfd_fcg/misc/L14_real_semantic_patches_v4_2000.pickle b/clean/video/dfd_fcg/misc/L14_real_semantic_patches_v4_2000.pickle
new file mode 100644
index 0000000000000000000000000000000000000000..2556569be6ccd1431d4139b816031ca15fe00d81
--- /dev/null
+++ b/clean/video/dfd_fcg/misc/L14_real_semantic_patches_v4_2000.pickle
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:438555d515700f0fdc4a1f2af2ca620d879fa7c91ca7018579e23aae94f0f72a
+size 2100301
diff --git a/clean/video/dfd_fcg/readme.md b/clean/video/dfd_fcg/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..66a3bf3bc773be72e8f821be2fa8fe94cda83177
--- /dev/null
+++ b/clean/video/dfd_fcg/readme.md
@@ -0,0 +1,275 @@
+
+
[CVPR'25] Towards More General Video-based Deepfake Detection through Facial Component Guided Adaptation for Foundation Model (DFD-FCG)
+
+
+ Yue-Hua Han
+ 1,3,4
+
+ Tai-Ming Huang
+ 1,3,4
+
+ Kai-Lung Hua
+ 2,4
+
+ Jun-Cheng Chen
+ 1
+
+
+ 1 Academia Sinica,
+ 2 Microsoft,
+ 3 National Taiwan University,
+
+ 4 National Taiwan University of Science and Technology
+
+
+
+
+
+
+## 🥇Abstract
+
+Generative models have enabled the creation of highly realistic facial-synthetic images, raising significant concerns due to their potential for misuse. Despite rapid advancements in the field of deepfake detection, developing efficient approaches to leverage foundation models for improved generalizability to unseen forgery samples remains challenging. To address this challenge, we propose a novel side-network-based decoder that extracts spatial and temporal cues using the CLIP image encoder for generalized video-based Deepfake detection. Additionally, we introduce Facial Component Guidance (FCG) to enhance spatial learning generalizability by encouraging the model to focus on key facial regions. By leveraging the generic features of a vision-language foundation model, our approach demonstrates promising generalizability on challenging Deepfake datasets while also exhibiting superiority in training data efficiency, parameter efficiency, and model robustness.
+
+
+## 📝TODOs
+ - [x] Training + Evaluation Code
+ - [x] Model Weights
+ - [x] Inference Code
+ - [ ] HeyGen Evaluation Dataset
+
+
+## 🙌News
+ - June 08: We have released the [model checkpoint](https://drive.google.com/file/d/1ydD5rnaaF0i2zLE7NidLtAhjonHoVQOk/view?usp=sharing) and provided inference code for single videos! Checkout [this section](#inference---demo-video) for further details!
+
+## 🚀Installation
+```shell
+# conda environment
+conda env create -f environment.yml
+```
+
+## 📂Dataset Structure
+The structure of the **pre-processed datasets** for our project, the video files (*.avi) have been processed to only retain the aligned face. We use soft-links **(ln -s)** to manage and link the folders containing pre-processed videos on different drives.
+```shell
+datasets
+├── cdf
+│ ├── FAKE
+│ │ └── videos
+│ │ └── *.avi
+│ ├── REAL
+│ │ └── videos
+│ │ └── *.avi
+│ └── csv_files
+│ ├── test_fake.csv
+│ └── test_real.csv
+├── dfdc
+│ ├── csv_files
+│ │ └── test.csv
+│ └── videos
+├── dfo
+│ ├── FAKE
+│ │ └── videos
+│ │ └── *.avi
+│ ├── REAL
+│ │ └── videos
+│ │ └── *.avi
+│ └── csv_files
+│ ├── test_fake.csv
+│ └── test_real.csv
+├── ffpp
+│ ├── DF
+│ │ ├── c23
+│ │ │ └── videos
+│ │ │ └── *.avi
+│ │ ├── c40
+│ │ │ └── videos
+│ │ │ └── *.avi
+│ │ └── raw
+│ │ └── videos
+│ │ │ └── *.avi
+│ ├── F2F ...
+│ ├── FS ...
+│ ├── FSh ...
+│ ├── NT ...
+│ ├── real ...
+│ └── csv_files
+│ ├── test.json
+│ ├── train.json
+│ └── val.json
+|
+└── robustness
+ ├── BW
+ │ ├── 1
+ │ │ ├── DF
+ │ │ │ └── c23
+ │ │ │ └── videos
+ │ │ │ └── *.avi
+ │ │ ├── F2F ...
+ │ │ ├── FS ...
+ │ │ ├── FSh ...
+ │ │ ├── NT ...
+ │ │ ├── real ...
+ │ │ │
+ │ │ └── csv_files
+ │ │ ├── test.json
+ │ │ ├── train.json
+ │ │ └── val.json
+ │ │
+ │ │
+ │ │
+ . .
+ . .
+ . .
+```
+
+
+## 🔧Dataset Pre-processing
+### Generic Pre-processing
+This phase performs the required pre-processing for our method, this includes *facial alignment (using the mean face from LRW)* and *facial cropping*.
+```bash
+# First, fetch all the landmarks & bboxes of the video frames.
+python -m src.preprocess.fetch_landmark_bbox \
+--root-dir="/storage/FaceForensicC23" \ # The root folder of the dataset
+--video-dir="videos" \ # The root folder of the videos
+--fdata-dir="frame_data" \ # The folder to save the extracted frame data
+--glob-exp="*/*" \ # The glob expression to search through the root video folder
+--split-num=1 \ # Split the dataset into several parts for parallel process.
+--part-num=1 \ # The part of dataset to process for parallel process.
+--batch=1 \ # The batch size for the 2D-FAN face data extraction. (suggestion: 1)
+--max-res=800 # The maximum resolution for either side of the image
+
+# Then, crop all the faces from the original videos.
+python -m src.preprocess.crop_main_face \
+--root-dir="/storage/FaceForensicC23/" \ # The root folder of the dataset
+--video-dir="videos" \ # The root folder of the videos
+--fdata-dir="frame_data" \ # The folder to fetch the frame data for landmarks and bboxes
+--glob-exp="*/*" \ # The glob expression to search through the root video folder
+--crop-dir="cropped" \ # The folder to save the cropped videos
+--crop-width=150 \ # The width for the cropped videos
+--crop-height=150 \ # The height for the cropped videos
+--mean-face="./misc/20words_mean_face.npy" # The mean face for face aligned cropping.
+--replace \ # Control whether to replace existing cropped videos
+--workers=1 # Number of works to perform parallel process (default: cpu / 2 )
+```
+
+
+### Robustness Pre-processing
+This phase requires the pre-processed facial landmarks to perform facial cropping, please refer to the **Generic Pre-processing** for further detail.
+```bash
+# First, we add perturbation to all the videos.
+python -m src.preprocess.phase1_apply_all_to_videos \
+--dts-root="/storage/FaceForensicC23" \ # The root folder of the dataset
+--vid-dir="videos" \ # The root folder of the videos
+--rob-dir="robustness" \ # The folder to save the perturbed videos
+--glob-exp="*/*.mp4" \ # The glob expression to search through the root video folder
+--split=1 \ # Split the dataset into several parts for parallel process.
+--part=1 \ # The part of dataset to process for parallel process.
+--workers=1 # Number of works to perform parallel process (default: cpu / 2 )
+
+# Then, crop all the faces from the perturbed videos.
+python -m src.preprocess.phase2_face_crop_all_videos \
+(setup/run/clean) # the three phase operations
+--root-dir="/storage/FaceForensicC23/" \ # The root folder of the dataset
+--rob-dir="videos" \ # The root folder of the robustness videos
+--fd-dir="frame_data" \ # The folder to fetch the frame data for landmarks and bboxes
+--glob-exp="*/*/*/*.mp4" \ # The glob expression to search through the root video folder
+--crop-dir="cropped_robust" \ # The folder to save the cropped videos
+--mean-face="./misc/20words_mean_face.npy" \ # The mean face for face aligned cropping.
+--workers=1 # Number of works to perform parallel process (default: cpu / 2 )
+```
+
+## 🤖Training & Evaluation
+### Training - Preset Settings
+In `./scripts`, scripts are provided to start the training process for the settings mentioned in our paper.
+These settings are configured to run on a cluster with `V100*4`.
+```bash
+bash ./scripts/model/ffg_l14.sh # begin training process
+```
+### Training - Custom Settings
+Our project is built on `pytorch-lightning (2.2.0)`, please refer the [official manual](https://lightning.ai/docs/pytorch/2.2.0/common/trainer.html#trainer-class-api) and adjust the following files for advance configurations:
+```bash
+./configs/base.yaml # major training settings (e.g. epochs, optimizer, batch size, mixed-precision ...)
+./configs/data.yaml # settings for the training & validation dataset
+./configs/inference.yaml # settings for the evaluation dataset (extension of data.yaml)
+./configs/logger.yaml # settings for the WandB logger
+./configs/clip/L14/ffg.yaml # settings for the main model
+./configs/test.yaml # settings for debugging (offline logging, small batch size, short epochs ...)
+```
+The following command starts the training process with the provided settings:
+```bash
+# For debugging, add '--config configs/test.yaml' after the '--config configs/clip/L14/ffg.yaml'.
+python main.py \
+--config configs/base.yaml \
+--config configs/clip/L14/ffg.yaml
+
+# Fine-grained control is supported with the pytorch-lightning-cli.
+python main.py \
+--config configs/base.yaml \
+--config configs/clip/L14/ffg.yaml \
+--optimizer.lr=1e-5 \
+--trainer.max_epochs=10 \
+--data.init_args.train_datamodules.init_args.batch_size=5
+```
+### Evaluation - Standard
+To perform evaluation on datasets, run the following command:
+```bash
+python inference.py \
+"logs/fcg_l14/setting.yaml" \ # model settings
+"./configs/inference.yaml" \ # evaluation dataset settings
+"logs/fcg_l14/checkpoint.ckpt" \ # model checkpoint
+"--devices=4" # number of devices to compute in parallel
+```
+### Evaluation - Robustness
+We provide tools in `./scripts/tools/` to simplify the robustness evaluation task: `create-robust-config.sh` creates an evaluation config for each perturbation types and `inference-robust.sh` runs through all the datasets with the specified model.
+
+## 😎Inference - Demo Video
+To run inference on a single video with an indicator, please download our model checkpoint and execute the following commands:
+```bash
+# Pre-Processing: fetch facial landmark and bounding box
+python -m src.preprocess.fetch_landmark_bbox \
+--root-dir="./resources" \
+--video-dir="videos" \
+--fdata-dir="frame_data" \
+--glob-exp="*"
+# Pre-Processing: crop out the facial regions
+python -m src.preprocess.crop_main_face \
+--root-dir="./resources" \
+--video-dir="videos" \
+--fdata-dir="frame_data" \
+--crop-dir="cropped" \
+--glob-exp="*"
+# Main Process
+python -m demo \
+"checkpoint/setting.yaml" \ # the model setting of the checkpoint
+"checkpoint/weights.ckpt" \ # the model weights of the checkpoint
+"resources/videos/000_003.mp4" \ # the video to process
+--out_path="test.avi" \ # the output path of the processed video
+--threshold=0.5 \ # the threshold for the real/fake indicator
+--batch_size=30 # the input batch size of the model (~10G VRAM when batch_size=30 )
+```
+The following is a sample frame from the processed video:
+
+
+
+
+
+
+## 🔗 BibTeX
+If you find our efforts helpful, please cite our paper and leave a star for further updates!
+```bibtex
+
+@inproceedings{cvpr25_dfd_fcg,
+ title={Towards More General Video-based Deepfake Detection through Facial Component Guided Adaptation for Foundation Model},
+ author={Yue-Hua Han, Tai-Ming Huang, Kai-Lung Hua, Jun-Cheng Chen},
+ booktitle={Proceedings of the Conference on Computer Vision and Pattern Recognition (CVPR)},
+ year={2025}
+}
+```
+
+
+## 📭 Contact
+The provided code and weights are only available for research purpose only.
+If you have further questions (including commercial use), please contact [Dr. Jun-Cheng Chen](pullpull@citi.sinica.edu.tw).
diff --git a/clean/video/dfd_fcg/scripts/ablation/ffg.sh b/clean/video/dfd_fcg/scripts/ablation/ffg.sh
new file mode 100644
index 0000000000000000000000000000000000000000..be80b480ae6d13a68d90fc6ea09647670e240112
--- /dev/null
+++ b/clean/video/dfd_fcg/scripts/ablation/ffg.sh
@@ -0,0 +1,6 @@
+python -m main \
+--config configs/base.yaml \
+--config configs/models/svl.yaml \
+--model.init_args.num_synos=4 \
+--config configs/generic/inference.yaml \
+--notes="no ffg guidance"
diff --git a/clean/video/dfd_fcg/scripts/ablation/focal.sh b/clean/video/dfd_fcg/scripts/ablation/focal.sh
new file mode 100644
index 0000000000000000000000000000000000000000..e27b94e5415f24f918ddfb2b0e90c5a2914fe599
--- /dev/null
+++ b/clean/video/dfd_fcg/scripts/ablation/focal.sh
@@ -0,0 +1,6 @@
+python -m main \
+--config configs/base.yaml \
+--config configs/models/ffg.yaml \
+--model.init_args.is_focal_loss=false \
+--config configs/generic/inference.yaml \
+--notes="no focal loss"
diff --git a/clean/video/dfd_fcg/scripts/ablation/s_branch.sh b/clean/video/dfd_fcg/scripts/ablation/s_branch.sh
new file mode 100644
index 0000000000000000000000000000000000000000..f53514b62e19b1dc981b6509465d7444adb2ce95
--- /dev/null
+++ b/clean/video/dfd_fcg/scripts/ablation/s_branch.sh
@@ -0,0 +1,6 @@
+python -m main \
+--config configs/base.yaml \
+--config configs/models/svl.yaml \
+--model.init_args.op_mode=["T"] \
+--config configs/generic/inference.yaml \
+--notes="no spatial branch"
diff --git a/clean/video/dfd_fcg/scripts/ablation/t_branch.sh b/clean/video/dfd_fcg/scripts/ablation/t_branch.sh
new file mode 100644
index 0000000000000000000000000000000000000000..7a86857b369d4ac309f20b09cf549ce96a79a6db
--- /dev/null
+++ b/clean/video/dfd_fcg/scripts/ablation/t_branch.sh
@@ -0,0 +1,6 @@
+python -m main \
+--config configs/base.yaml \
+--config configs/models/ffg.yaml \
+--model.init_args.op_mode=["S"] \
+--config configs/generic/inference.yaml \
+--notes="no temporal branch"
diff --git a/clean/video/dfd_fcg/scripts/base.sh b/clean/video/dfd_fcg/scripts/base.sh
new file mode 100644
index 0000000000000000000000000000000000000000..5943aee44cb391d6861ee2a58fca48cb56a69dc6
--- /dev/null
+++ b/clean/video/dfd_fcg/scripts/base.sh
@@ -0,0 +1,3 @@
+python -m main \
+--config configs/base.yaml \
+--config configs/models/ffg.yaml
diff --git a/clean/video/dfd_fcg/scripts/loo/DF.sh b/clean/video/dfd_fcg/scripts/loo/DF.sh
new file mode 100644
index 0000000000000000000000000000000000000000..73c04e0a7affb724a1aea712359b557e07aedaf1
--- /dev/null
+++ b/clean/video/dfd_fcg/scripts/loo/DF.sh
@@ -0,0 +1,6 @@
+python -m main \
+--config configs/base.yaml \
+--config configs/models/ffg.yaml \
+--config configs/scenario/LOO/DF.yaml \
+--config configs/loo/DF.yaml \
+--notes="LOO DF"
diff --git a/clean/video/dfd_fcg/scripts/loo/F2F.sh b/clean/video/dfd_fcg/scripts/loo/F2F.sh
new file mode 100644
index 0000000000000000000000000000000000000000..5c8cccfec2cd46761b0e01cb7c8cdca991899404
--- /dev/null
+++ b/clean/video/dfd_fcg/scripts/loo/F2F.sh
@@ -0,0 +1,6 @@
+python -m main \
+--config configs/base.yaml \
+--config configs/models/ffg.yaml \
+--config configs/scenario/LOO/F2F.yaml \
+--config configs/loo/F2F.yaml \
+--notes="LOO F2F"
diff --git a/clean/video/dfd_fcg/scripts/loo/FS.sh b/clean/video/dfd_fcg/scripts/loo/FS.sh
new file mode 100644
index 0000000000000000000000000000000000000000..cdbde903e6fd0aa6987f591bbdca44abdb20f60f
--- /dev/null
+++ b/clean/video/dfd_fcg/scripts/loo/FS.sh
@@ -0,0 +1,6 @@
+python -m main \
+--config configs/base.yaml \
+--config configs/models/ffg.yaml \
+--config configs/scenario/LOO/FS.yaml \
+--config configs/loo/FS.yaml \
+--notes="LOO FS"
diff --git a/clean/video/dfd_fcg/scripts/loo/NT.sh b/clean/video/dfd_fcg/scripts/loo/NT.sh
new file mode 100644
index 0000000000000000000000000000000000000000..b3ff9909beb08a96006013d54145e87fe5f2e561
--- /dev/null
+++ b/clean/video/dfd_fcg/scripts/loo/NT.sh
@@ -0,0 +1,6 @@
+python -m main \
+--config configs/base.yaml \
+--config configs/models/ffg.yaml \
+--config configs/scenario/LOO/NT.yaml \
+--config configs/loo/NT.yaml \
+--notes="LOO NT"
diff --git a/clean/video/dfd_fcg/scripts/model/evl_l14.sh b/clean/video/dfd_fcg/scripts/model/evl_l14.sh
new file mode 100644
index 0000000000000000000000000000000000000000..05c2630e4977f32fd1718d3148a6aafbd40fe207
--- /dev/null
+++ b/clean/video/dfd_fcg/scripts/model/evl_l14.sh
@@ -0,0 +1,7 @@
+python -m main \
+--config configs/base.yaml \
+--config configs/models/evl.yaml \
+--data.init_args.train_datamodules.init_args.batch_size=40 \
+--trainer.accumulate_grad_batches=5 \
+--config configs/inference.yaml \
+--notes="full evl_l14"
diff --git a/clean/video/dfd_fcg/scripts/model/ffg_l14.sh b/clean/video/dfd_fcg/scripts/model/ffg_l14.sh
new file mode 100644
index 0000000000000000000000000000000000000000..fe032564af24744807f40982bf6e519b3915da67
--- /dev/null
+++ b/clean/video/dfd_fcg/scripts/model/ffg_l14.sh
@@ -0,0 +1,5 @@
+python -m main \
+--config configs/base.yaml \
+--config configs/models/ffg.yaml \
+--config configs/inference.yaml \
+--notes="full ffg_l14"
diff --git a/clean/video/dfd_fcg/scripts/model/fulltune_l14.sh b/clean/video/dfd_fcg/scripts/model/fulltune_l14.sh
new file mode 100644
index 0000000000000000000000000000000000000000..630bd270d004370d4eafcd6fe79e0ea73f0afe1d
--- /dev/null
+++ b/clean/video/dfd_fcg/scripts/model/fulltune_l14.sh
@@ -0,0 +1,7 @@
+python -m main \
+--config configs/version/Share/final/base.yaml \
+--config configs/version/Share/final/clip/L14/fulltune.yaml \
+--optimizer.lr=1e-5 \
+--trainer.accumulate_grad_batches=15 \
+--config configs/inference.yaml \
+--notes="full fulltune_l14"
diff --git a/clean/video/dfd_fcg/scripts/model/linear_l14.sh b/clean/video/dfd_fcg/scripts/model/linear_l14.sh
new file mode 100644
index 0000000000000000000000000000000000000000..76b2f4228189b25d97cdeaf97bae237eeecf9c14
--- /dev/null
+++ b/clean/video/dfd_fcg/scripts/model/linear_l14.sh
@@ -0,0 +1,5 @@
+python -m main \
+--config configs/base.yaml \
+--config configs/models/linear.yaml \
+--config configs/inference.yaml \
+--notes="full linear_l14"
diff --git a/clean/video/dfd_fcg/scripts/model/svl_l14.sh b/clean/video/dfd_fcg/scripts/model/svl_l14.sh
new file mode 100644
index 0000000000000000000000000000000000000000..ee488f4a03b8d7367309d1ed1aa9f688f1f16585
--- /dev/null
+++ b/clean/video/dfd_fcg/scripts/model/svl_l14.sh
@@ -0,0 +1,5 @@
+python -m main \
+--config configs/base.yaml \
+--config configs/models/svl.yaml \
+--config configs/inference.yaml \
+--notes="full svl_l14"
diff --git a/clean/video/dfd_fcg/scripts/model/vpt_deep_l14.sh b/clean/video/dfd_fcg/scripts/model/vpt_deep_l14.sh
new file mode 100644
index 0000000000000000000000000000000000000000..97afda4dccd86dfef560dac90f28daca35f853cf
--- /dev/null
+++ b/clean/video/dfd_fcg/scripts/model/vpt_deep_l14.sh
@@ -0,0 +1,6 @@
+python -m main \
+--config configs/base.yaml \
+--config configs/models/vpt.yaml \
+--trainer.accumulate_grad_batches=10 \
+--config configs/inference.yaml \
+--notes="full vpt_l14"
diff --git a/clean/video/dfd_fcg/scripts/model/vpt_shallow_l14.sh b/clean/video/dfd_fcg/scripts/model/vpt_shallow_l14.sh
new file mode 100644
index 0000000000000000000000000000000000000000..97afda4dccd86dfef560dac90f28daca35f853cf
--- /dev/null
+++ b/clean/video/dfd_fcg/scripts/model/vpt_shallow_l14.sh
@@ -0,0 +1,6 @@
+python -m main \
+--config configs/base.yaml \
+--config configs/models/vpt.yaml \
+--trainer.accumulate_grad_batches=10 \
+--config configs/inference.yaml \
+--notes="full vpt_l14"
diff --git a/clean/video/dfd_fcg/scripts/partial/10.sh b/clean/video/dfd_fcg/scripts/partial/10.sh
new file mode 100644
index 0000000000000000000000000000000000000000..b9e4aa129a3fbb01dab099c9a2a68e352a835177
--- /dev/null
+++ b/clean/video/dfd_fcg/scripts/partial/10.sh
@@ -0,0 +1,6 @@
+python -m main \
+--config configs/base.yaml \
+--config configs/models/ffg.yaml \
+--config configs/scenario/partial/10.yaml \
+--config configs/generic/inference.yaml \
+--notes="full ffg_l14_10%"
diff --git a/clean/video/dfd_fcg/scripts/partial/25.sh b/clean/video/dfd_fcg/scripts/partial/25.sh
new file mode 100644
index 0000000000000000000000000000000000000000..3e99fe215ad0a2f830c222c9845876c2fc49356d
--- /dev/null
+++ b/clean/video/dfd_fcg/scripts/partial/25.sh
@@ -0,0 +1,6 @@
+python -m main \
+--config configs/base.yaml \
+--config configs/models/ffg.yaml \
+--config configs/scenario/partial/25.yaml \
+--config configs/generic/inference.yaml \
+--notes="full ffg_l14_25%"
diff --git a/clean/video/dfd_fcg/scripts/partial/50.sh b/clean/video/dfd_fcg/scripts/partial/50.sh
new file mode 100644
index 0000000000000000000000000000000000000000..275914a8bce855eca389a770447aa47ae9976641
--- /dev/null
+++ b/clean/video/dfd_fcg/scripts/partial/50.sh
@@ -0,0 +1,6 @@
+python -m main \
+--config configs/base.yaml \
+--config configs/models/ffg.yaml \
+--config configs/scenario/partial/50.yaml \
+--config configs/generic/inference.yaml \
+--notes="full ffg_l14_50%"
diff --git a/clean/video/dfd_fcg/scripts/partial/75.sh b/clean/video/dfd_fcg/scripts/partial/75.sh
new file mode 100644
index 0000000000000000000000000000000000000000..69768321d1deeddf311bd3619008d4570e6fcabf
--- /dev/null
+++ b/clean/video/dfd_fcg/scripts/partial/75.sh
@@ -0,0 +1,6 @@
+python -m main \
+--config configs/base.yaml \
+--config configs/models/ffg.yaml \
+--config configs/scenario/partial/75.yaml \
+--config configs/generic/inference.yaml \
+--notes="full ffg_l14_75%"
diff --git a/clean/video/dfd_fcg/scripts/parts/no_eyes.sh b/clean/video/dfd_fcg/scripts/parts/no_eyes.sh
new file mode 100644
index 0000000000000000000000000000000000000000..9a4dd3a5fd3a11229df8d1de9f221f536bb3628f
--- /dev/null
+++ b/clean/video/dfd_fcg/scripts/parts/no_eyes.sh
@@ -0,0 +1,6 @@
+python -m main \
+--config configs/base.yaml \
+--config configs/models/ffg.yaml \
+--model.init_args.face_parts=["lips","skin","nose"] \
+--config configs/generic/inference.yaml \
+--notes="parts_no_eyes"
diff --git a/clean/video/dfd_fcg/scripts/parts/no_lips.sh b/clean/video/dfd_fcg/scripts/parts/no_lips.sh
new file mode 100644
index 0000000000000000000000000000000000000000..36c67c12e9ef9621dae05c3753929dee275d3689
--- /dev/null
+++ b/clean/video/dfd_fcg/scripts/parts/no_lips.sh
@@ -0,0 +1,6 @@
+python -m main \
+--config configs/base.yaml \
+--config configs/models/ffg.yaml \
+--model.init_args.face_parts=["skin","eyes","nose"] \
+--config configs/generic/inference.yaml \
+--notes="parts_no_lips"
diff --git a/clean/video/dfd_fcg/scripts/parts/no_nose.sh b/clean/video/dfd_fcg/scripts/parts/no_nose.sh
new file mode 100644
index 0000000000000000000000000000000000000000..8d794aff3fac51f1d9e05b258cd78bbc4391aceb
--- /dev/null
+++ b/clean/video/dfd_fcg/scripts/parts/no_nose.sh
@@ -0,0 +1,6 @@
+python -m main \
+--config configs/base.yaml \
+--config configs/models/ffg.yaml \
+--model.init_args.face_parts=["lips","skin","eyes"] \
+--config configs/generic/inference.yaml \
+--notes="parts_no_nose"
diff --git a/clean/video/dfd_fcg/scripts/parts/no_skin.sh b/clean/video/dfd_fcg/scripts/parts/no_skin.sh
new file mode 100644
index 0000000000000000000000000000000000000000..5907e3f7c4be5173e47edbaba9f2339ce7f68ec6
--- /dev/null
+++ b/clean/video/dfd_fcg/scripts/parts/no_skin.sh
@@ -0,0 +1,6 @@
+python -m main \
+--config configs/base.yaml \
+--config configs/models/ffg.yaml \
+--model.init_args.face_parts=["lips","eyes","nose"] \
+--config configs/generic/inference.yaml \
+--notes="parts_no_skin"
diff --git a/clean/video/dfd_fcg/scripts/robust/robust.sh b/clean/video/dfd_fcg/scripts/robust/robust.sh
new file mode 100644
index 0000000000000000000000000000000000000000..594987ee3aa3d8832177faa7f8a9aff95758b1fa
--- /dev/null
+++ b/clean/video/dfd_fcg/scripts/robust/robust.sh
@@ -0,0 +1,5 @@
+python -m main \
+--config configs/base.yaml \
+--config configs/models/ffg.yaml \
+--config configs/scenario/robust/robust.yaml \
+--notes="ROBUSTNESS"
diff --git a/clean/video/dfd_fcg/scripts/tools/cli_check.py b/clean/video/dfd_fcg/scripts/tools/cli_check.py
new file mode 100644
index 0000000000000000000000000000000000000000..1d6456d6892da66bb06604c5b8f82538355e54d9
--- /dev/null
+++ b/clean/video/dfd_fcg/scripts/tools/cli_check.py
@@ -0,0 +1,4 @@
+from main import configure_cli
+
+if __name__ == "__main__":
+ cli = configure_cli()
diff --git a/clean/video/dfd_fcg/scripts/tools/create-robust-configs.sh b/clean/video/dfd_fcg/scripts/tools/create-robust-configs.sh
new file mode 100644
index 0000000000000000000000000000000000000000..17511e16591438d8b5741ccd1209f8ef203f1403
--- /dev/null
+++ b/clean/video/dfd_fcg/scripts/tools/create-robust-configs.sh
@@ -0,0 +1,24 @@
+TYPES="CS CC BW GNC GB JPEG VC"
+LEVELS="1 2 3 4 5"
+for T in $TYPES;
+do
+ for L in $LEVELS;
+ do
+ cat << EOT > "configs/robustness/$T($L).yaml"
+data:
+ class_path: src.dataset.base.ODDeepFakeDataModule
+ init_args:
+ test_datamodules:
+ - class_path: src.dataset.ffpp.FFPPDataModule
+ init_args:
+ df_types: ['REAL','DF','FS','F2F','NT']
+ compressions: ['c23']
+ strategy: NORMAL
+ augmentations:
+ - NONE
+ force_random_speed: null
+ data_dir: 'datasets/robustness/$T/$L/'
+ vid_ext: .avi
+EOT
+ done
+done
\ No newline at end of file
diff --git a/clean/video/dfd_fcg/scripts/tools/inference-robust.sh b/clean/video/dfd_fcg/scripts/tools/inference-robust.sh
new file mode 100644
index 0000000000000000000000000000000000000000..4e38c4c67b5a002f1f47282458997616be62601d
--- /dev/null
+++ b/clean/video/dfd_fcg/scripts/tools/inference-robust.sh
@@ -0,0 +1,16 @@
+TYPES="CS CC BW GNC GB JPEG VC"
+LEVELS="1 2 3 4 5"
+CKPT="logs/best/checkpoint.ckpt"
+SETTING="logs/best/setting.yaml"
+for T in $TYPES;
+do
+ for L in $LEVELS;
+ do
+ python -m inference \
+ $SETTING \
+ "./configs/robustness/$T($L).yaml" \
+ $CKPT \
+ --notes "$T($L)" \
+ --devices -1
+ done
+done
\ No newline at end of file
diff --git a/clean/video/dfd_fcg/src/clip/__init__.py b/clean/video/dfd_fcg/src/clip/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..dcc5619538c0f7c782508bdbd9587259d805e0d9
--- /dev/null
+++ b/clean/video/dfd_fcg/src/clip/__init__.py
@@ -0,0 +1 @@
+from .clip import *
diff --git a/clean/video/dfd_fcg/src/clip/bpe_simple_vocab_16e6.txt.gz b/clean/video/dfd_fcg/src/clip/bpe_simple_vocab_16e6.txt.gz
new file mode 100644
index 0000000000000000000000000000000000000000..36a15856e00a06a9fbed8cdd34d2393fea4a3113
--- /dev/null
+++ b/clean/video/dfd_fcg/src/clip/bpe_simple_vocab_16e6.txt.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:924691ac288e54409236115652ad4aa250f48203de50a9e4722a6ecd48d6804a
+size 1356917
diff --git a/clean/video/dfd_fcg/src/clip/clip.py b/clean/video/dfd_fcg/src/clip/clip.py
new file mode 100644
index 0000000000000000000000000000000000000000..c714255869f73327b1b00aa5bf736c78321a1368
--- /dev/null
+++ b/clean/video/dfd_fcg/src/clip/clip.py
@@ -0,0 +1,270 @@
+import hashlib
+import os
+import urllib
+import warnings
+from typing import Any, Union, List
+from pkg_resources import packaging
+
+import torch
+from PIL import Image
+from torchvision.transforms import Compose, Resize, CenterCrop, ToTensor, Normalize
+from tqdm import tqdm
+
+from .model_syno import build_model
+from .simple_tokenizer import SimpleTokenizer as _Tokenizer
+
+try:
+ from torchvision.transforms import InterpolationMode
+ BICUBIC = InterpolationMode.BICUBIC
+except ImportError:
+ BICUBIC = Image.BICUBIC
+
+
+if packaging.version.parse(torch.__version__) < packaging.version.parse("1.7.1"):
+ warnings.warn("PyTorch version 1.7.1 or higher is recommended")
+
+
+__all__ = ["available_models", "load", "tokenize"]
+_tokenizer = _Tokenizer()
+
+_MODELS = {
+ "RN50": "https://openaipublic.azureedge.net/clip/models/afeb0e10f9e5a86da6080e35cf09123aca3b358a0c3e3b6c78a7b63bc04b6762/RN50.pt",
+ "RN101": "https://openaipublic.azureedge.net/clip/models/8fa8567bab74a42d41c5915025a8e4538c3bdbe8804a470a72f30b0d94fab599/RN101.pt",
+ "RN50x4": "https://openaipublic.azureedge.net/clip/models/7e526bd135e493cef0776de27d5f42653e6b4c8bf9e0f653bb11773263205fdd/RN50x4.pt",
+ "RN50x16": "https://openaipublic.azureedge.net/clip/models/52378b407f34354e150460fe41077663dd5b39c54cd0bfd2b27167a4a06ec9aa/RN50x16.pt",
+ "RN50x64": "https://openaipublic.azureedge.net/clip/models/be1cfb55d75a9666199fb2206c106743da0f6468c9d327f3e0d0a543a9919d9c/RN50x64.pt",
+ "ViT-B/32": "https://openaipublic.azureedge.net/clip/models/40d365715913c9da98579312b702a82c18be219cc2a73407c4526f58eba950af/ViT-B-32.pt",
+ "ViT-B/16": "https://openaipublic.azureedge.net/clip/models/5806e77cd80f8b59890b7e101eabd078d9fb84e6937f9e85e4ecb61988df416f/ViT-B-16.pt",
+ "ViT-L/14": "https://openaipublic.azureedge.net/clip/models/b8cca3fd41ae0c99ba7e8951adf17d267cdb84cd88be6f7c2e0eca1737a03836/ViT-L-14.pt",
+ "ViT-L/14@336px": "https://openaipublic.azureedge.net/clip/models/3035c92b350959924f9f00213499208652fc7ea050643e8b385c2dac08641f02/ViT-L-14-336px.pt",
+}
+
+
+def _download(url: str, root: str):
+ os.makedirs(root, exist_ok=True)
+ filename = os.path.basename(url)
+
+ expected_sha256 = url.split("/")[-2]
+ download_target = os.path.join(root, filename)
+
+ if os.path.exists(download_target) and not os.path.isfile(download_target):
+ raise RuntimeError(f"{download_target} exists and is not a regular file")
+
+ if os.path.isfile(download_target):
+ if hashlib.sha256(open(download_target, "rb").read()).hexdigest() == expected_sha256:
+ return download_target
+ else:
+ warnings.warn(f"{download_target} exists, but the SHA256 checksum does not match; re-downloading the file")
+
+ with urllib.request.urlopen(url) as source, open(download_target, "wb") as output:
+ with tqdm(total=int(source.info().get("Content-Length")), ncols=80, unit='iB', unit_scale=True, unit_divisor=1024) as loop:
+ while True:
+ buffer = source.read(8192)
+ if not buffer:
+ break
+
+ output.write(buffer)
+ loop.update(len(buffer))
+
+ if hashlib.sha256(open(download_target, "rb").read()).hexdigest() != expected_sha256:
+ raise RuntimeError("Model has been downloaded but the SHA256 checksum does not not match")
+
+ return download_target
+
+
+def _convert_image_to_rgb(image):
+ if (isinstance(image, Image.Image)):
+ return image.convert("RGB")
+ else:
+ return image
+
+
+def _to_tensor(image):
+ if (isinstance(image, torch.Tensor)):
+ if ((image.max() - 1) > 1e-4):
+ image = image / 255
+ return image.float()
+ else:
+ return ToTensor()(image)
+
+
+def _transform(n_px):
+ return Compose([
+ Resize(n_px, interpolation=BICUBIC, antialias=True),
+ CenterCrop(n_px),
+ _convert_image_to_rgb,
+ _to_tensor,
+ Normalize((0.48145466, 0.4578275, 0.40821073), (0.26862954, 0.26130258, 0.27577711)),
+ ])
+
+
+def available_models() -> List[str]:
+ """Returns the names of available CLIP models"""
+ return list(_MODELS.keys())
+
+
+def load(provider: str, device: Union[str, torch.device] = "cuda" if torch.cuda.is_available() else "cpu", jit: bool = False, download_root: str = None, **model_kargs):
+ """Load a CLIP model
+
+ Parameters
+ ----------
+ name : str
+ A model name listed by `clip.available_models()`, or the path to a model checkpoint containing the state_dict
+
+ device : Union[str, torch.device]
+ The device to put the loaded model
+
+ jit : bool
+ Whether to load the optimized JIT model or more hackable non-JIT model (default).
+
+ download_root: str
+ path to download the model files; by default, it uses "~/.cache/clip"
+
+ Returns
+ -------
+ model : torch.nn.Module
+ The CLIP model
+
+ preprocess : Callable[[PIL.Image], torch.Tensor]
+ A torchvision transform that converts a PIL image into a tensor that the returned model can take as its input
+ """
+
+ if type(provider) == str:
+ name = provider
+ if name in _MODELS:
+ model_path = _download(_MODELS[name], download_root or os.path.expanduser("~/.cache/clip"))
+ elif os.path.isfile(name):
+ model_path = name
+ else:
+ raise RuntimeError(f"Model {name} not found; available models = {available_models()}")
+
+ try:
+ with open(model_path, 'rb') as opened_file:
+ # loading JIT archive
+ model = torch.jit.load(opened_file, map_location=device if jit else "cpu").eval()
+ state_dict = None
+ except RuntimeError:
+ with open(model_path, 'rb') as opened_file:
+ # loading saved state dict
+ if jit:
+ warnings.warn(f"File {model_path} is not a JIT archive. Loading as a state dict instead")
+ jit = False
+ state_dict = torch.load(opened_file, map_location="cpu")
+
+ elif type(provider) == dict or issubclass(type(provider), dict):
+ state_dict = provider
+ if jit:
+ warnings.warn(f"Providing state dict, which is not a JIT archive file path.")
+ jit = False
+
+ else:
+ raise Exception("Invalid model provider")
+
+ if not jit:
+ model = build_model(state_dict or model.state_dict(), **model_kargs).to(device)
+ if str(device) == "cpu":
+ model.float()
+ return model, _transform(model.visual.input_resolution)
+
+ # patch the device names
+ device_holder = torch.jit.trace(lambda: torch.ones([]).to(torch.device(device)), example_inputs=[])
+ device_node = [n for n in device_holder.graph.findAllNodes("prim::Constant") if "Device" in repr(n)][-1]
+
+ def _node_get(node: torch._C.Node, key: str):
+ """Gets attributes of a node which is polymorphic over return type.
+
+ From https://github.com/pytorch/pytorch/pull/82628
+ """
+ sel = node.kindOf(key)
+ return getattr(node, sel)(key)
+
+ def patch_device(module):
+ try:
+ graphs = [module.graph] if hasattr(module, "graph") else []
+ except RuntimeError:
+ graphs = []
+
+ if hasattr(module, "forward1"):
+ graphs.append(module.forward1.graph)
+
+ for graph in graphs:
+ for node in graph.findAllNodes("prim::Constant"):
+ if "value" in node.attributeNames() and str(_node_get(node, "value")).startswith("cuda"):
+ node.copyAttributes(device_node)
+
+ model.apply(patch_device)
+ patch_device(model.encode_image)
+ patch_device(model.encode_text)
+
+ # patch dtype to float32 on CPU
+ if str(device) == "cpu":
+ float_holder = torch.jit.trace(lambda: torch.ones([]).float(), example_inputs=[])
+ float_input = list(float_holder.graph.findNode("aten::to").inputs())[1]
+ float_node = float_input.node()
+
+ def patch_float(module):
+ try:
+ graphs = [module.graph] if hasattr(module, "graph") else []
+ except RuntimeError:
+ graphs = []
+
+ if hasattr(module, "forward1"):
+ graphs.append(module.forward1.graph)
+
+ for graph in graphs:
+ for node in graph.findAllNodes("aten::to"):
+ inputs = list(node.inputs())
+ for i in [1, 2]: # dtype can be the second or third argument to aten::to()
+ if _node_get(inputs[i].node(), "value") == 5:
+ inputs[i].node().copyAttributes(float_node)
+
+ model.apply(patch_float)
+ patch_float(model.encode_image)
+ patch_float(model.encode_text)
+
+ model.float()
+
+ return model, _transform(model.input_resolution.item())
+
+
+def tokenize(texts: Union[str, List[str]], context_length: int = 77, truncate: bool = False) -> Union[torch.IntTensor, torch.LongTensor]:
+ """
+ Returns the tokenized representation of given input string(s)
+
+ Parameters
+ ----------
+ texts : Union[str, List[str]]
+ An input string or a list of input strings to tokenize
+
+ context_length : int
+ The context length to use; all CLIP models use 77 as the context length
+
+ truncate: bool
+ Whether to truncate the text in case its encoding is longer than the context length
+
+ Returns
+ -------
+ A two-dimensional tensor containing the resulting tokens, shape = [number of input strings, context_length].
+ We return LongTensor when torch version is <1.8.0, since older index_select requires indices to be long.
+ """
+ if isinstance(texts, str):
+ texts = [texts]
+
+ sot_token = _tokenizer.encoder["<|startoftext|>"]
+ eot_token = _tokenizer.encoder["<|endoftext|>"]
+ all_tokens = [[sot_token] + _tokenizer.encode(text) + [eot_token] for text in texts]
+ if packaging.version.parse(torch.__version__) < packaging.version.parse("1.8.0"):
+ result = torch.zeros(len(all_tokens), context_length, dtype=torch.long)
+ else:
+ result = torch.zeros(len(all_tokens), context_length, dtype=torch.int)
+
+ for i, tokens in enumerate(all_tokens):
+ if len(tokens) > context_length:
+ if truncate:
+ tokens = tokens[:context_length]
+ tokens[-1] = eot_token
+ else:
+ raise RuntimeError(f"Input {texts[i]} is too long for context length {context_length}")
+ result[i, :len(tokens)] = torch.tensor(tokens)
+
+ return result
diff --git a/clean/video/dfd_fcg/src/clip/model.py b/clean/video/dfd_fcg/src/clip/model.py
new file mode 100644
index 0000000000000000000000000000000000000000..33d6c11a6bf738ce6678732c573e4068cacd1460
--- /dev/null
+++ b/clean/video/dfd_fcg/src/clip/model.py
@@ -0,0 +1,530 @@
+from collections import OrderedDict
+from typing import Tuple, Union
+
+import numpy as np
+import torch
+import torch.nn.functional as F
+from torch import nn
+
+
+class Bottleneck(nn.Module):
+ expansion = 4
+
+ def __init__(self, inplanes, planes, stride=1):
+ super().__init__()
+
+ # all conv layers have stride 1. an avgpool is performed after the second convolution when stride > 1
+ self.conv1 = nn.Conv2d(inplanes, planes, 1, bias=False)
+ self.bn1 = nn.BatchNorm2d(planes)
+ self.relu1 = nn.ReLU(inplace=True)
+
+ self.conv2 = nn.Conv2d(planes, planes, 3, padding=1, bias=False)
+ self.bn2 = nn.BatchNorm2d(planes)
+ self.relu2 = nn.ReLU(inplace=True)
+
+ self.avgpool = nn.AvgPool2d(stride) if stride > 1 else nn.Identity()
+
+ self.conv3 = nn.Conv2d(planes, planes * self.expansion, 1, bias=False)
+ self.bn3 = nn.BatchNorm2d(planes * self.expansion)
+ self.relu3 = nn.ReLU(inplace=True)
+
+ self.downsample = None
+ self.stride = stride
+
+ if stride > 1 or inplanes != planes * Bottleneck.expansion:
+ # downsampling layer is prepended with an avgpool, and the subsequent convolution has stride 1
+ self.downsample = nn.Sequential(OrderedDict([
+ ("-1", nn.AvgPool2d(stride)),
+ ("0", nn.Conv2d(inplanes, planes * self.expansion, 1, stride=1, bias=False)),
+ ("1", nn.BatchNorm2d(planes * self.expansion))
+ ]))
+
+ def forward(self, x: torch.Tensor):
+ identity = x
+
+ out = self.relu1(self.bn1(self.conv1(x)))
+ out = self.relu2(self.bn2(self.conv2(out)))
+ out = self.avgpool(out)
+ out = self.bn3(self.conv3(out))
+
+ if self.downsample is not None:
+ identity = self.downsample(x)
+
+ out += identity
+ out = self.relu3(out)
+ return out
+
+
+class AttentionPool2d(nn.Module):
+ def __init__(self, spacial_dim: int, embed_dim: int, num_heads: int, output_dim: int = None):
+ super().__init__()
+ self.positional_embedding = nn.Parameter(torch.randn(spacial_dim ** 2 + 1, embed_dim) / embed_dim ** 0.5)
+ self.k_proj = nn.Linear(embed_dim, embed_dim)
+ self.q_proj = nn.Linear(embed_dim, embed_dim)
+ self.v_proj = nn.Linear(embed_dim, embed_dim)
+ self.c_proj = nn.Linear(embed_dim, output_dim or embed_dim)
+ self.num_heads = num_heads
+
+ def forward(self, x):
+ x = x.flatten(start_dim=2).permute(2, 0, 1) # NCHW -> (HW)NC
+ x = torch.cat([x.mean(dim=0, keepdim=True), x], dim=0) # (HW+1)NC
+ x = x + self.positional_embedding[:, None, :].to(x.dtype) # (HW+1)NC
+ x, _ = F.multi_head_attention_forward(
+ query=x[:1], key=x, value=x,
+ embed_dim_to_check=x.shape[-1],
+ num_heads=self.num_heads,
+ q_proj_weight=self.q_proj.weight,
+ k_proj_weight=self.k_proj.weight,
+ v_proj_weight=self.v_proj.weight,
+ in_proj_weight=None,
+ in_proj_bias=torch.cat([self.q_proj.bias, self.k_proj.bias, self.v_proj.bias]),
+ bias_k=None,
+ bias_v=None,
+ add_zero_attn=False,
+ dropout_p=0,
+ out_proj_weight=self.c_proj.weight,
+ out_proj_bias=self.c_proj.bias,
+ use_separate_proj_weight=True,
+ training=self.training,
+ need_weights=False
+ )
+ return x.squeeze(0)
+
+
+class ModifiedResNet(nn.Module):
+ """
+ A ResNet class that is similar to torchvision's but contains the following changes:
+ - There are now 3 "stem" convolutions as opposed to 1, with an average pool instead of a max pool.
+ - Performs anti-aliasing strided convolutions, where an avgpool is prepended to convolutions with stride > 1
+ - The final pooling layer is a QKV attention instead of an average pool
+ """
+
+ def __init__(self, layers, output_dim, heads, input_resolution=224, width=64):
+ super().__init__()
+ self.output_dim = output_dim
+ self.input_resolution = input_resolution
+
+ # the 3-layer stem
+ self.conv1 = nn.Conv2d(3, width // 2, kernel_size=3, stride=2, padding=1, bias=False)
+ self.bn1 = nn.BatchNorm2d(width // 2)
+ self.relu1 = nn.ReLU(inplace=True)
+ self.conv2 = nn.Conv2d(width // 2, width // 2, kernel_size=3, padding=1, bias=False)
+ self.bn2 = nn.BatchNorm2d(width // 2)
+ self.relu2 = nn.ReLU(inplace=True)
+ self.conv3 = nn.Conv2d(width // 2, width, kernel_size=3, padding=1, bias=False)
+ self.bn3 = nn.BatchNorm2d(width)
+ self.relu3 = nn.ReLU(inplace=True)
+ self.avgpool = nn.AvgPool2d(2)
+
+ # residual layers
+ self._inplanes = width # this is a *mutable* variable used during construction
+ self.layer1 = self._make_layer(width, layers[0])
+ self.layer2 = self._make_layer(width * 2, layers[1], stride=2)
+ self.layer3 = self._make_layer(width * 4, layers[2], stride=2)
+ self.layer4 = self._make_layer(width * 8, layers[3], stride=2)
+
+ embed_dim = width * 32 # the ResNet feature dimension
+ self.attnpool = AttentionPool2d(input_resolution // 32, embed_dim, heads, output_dim)
+
+ def _make_layer(self, planes, blocks, stride=1):
+ layers = [Bottleneck(self._inplanes, planes, stride)]
+
+ self._inplanes = planes * Bottleneck.expansion
+ for _ in range(1, blocks):
+ layers.append(Bottleneck(self._inplanes, planes))
+
+ return nn.Sequential(*layers)
+
+ def forward(self, x):
+ def stem(x):
+ x = self.relu1(self.bn1(self.conv1(x)))
+ x = self.relu2(self.bn2(self.conv2(x)))
+ x = self.relu3(self.bn3(self.conv3(x)))
+ x = self.avgpool(x)
+ return x
+
+ x = x.type(self.conv1.weight.dtype)
+ x = stem(x)
+ x = self.layer1(x)
+ x = self.layer2(x)
+ x = self.layer3(x)
+ x = self.layer4(x)
+ x = self.attnpool(x)
+
+ return x
+
+
+class LayerNorm(nn.LayerNorm):
+ """Subclass torch's LayerNorm to handle fp16."""
+
+ def forward(self, x: torch.Tensor):
+ orig_type = x.dtype
+ ret = super().forward(x.type(torch.float32))
+ return ret.type(orig_type)
+
+
+class QuickGELU(nn.Module):
+ def forward(self, x: torch.Tensor):
+ return x * torch.sigmoid(1.702 * x)
+
+
+class MultiheadAttentionAttrExtract(nn.Module):
+ '''
+ Simple reimplementation of nn.MultiheadAttention with key, value return
+ '''
+
+ def __init__(self, embed_dim, n_head, attn_record=False):
+ super().__init__()
+
+ self.in_proj_weight = nn.Parameter(torch.empty((3 * embed_dim, embed_dim)))
+ self.in_proj_bias = nn.Parameter(torch.empty(3 * embed_dim))
+ self.out_proj = nn.Linear(embed_dim, embed_dim)
+
+ self.n_head = n_head
+ self.attr = {}
+
+ # recordings
+ self.attn_record = attn_record
+ self.aff = None
+
+ def pop_attr(self):
+ if (not self.attr):
+ return None
+ ret = self.get_attr()
+ self.attr.clear()
+ return ret
+
+ def get_attr(self):
+ return {k: self.attr[k] for k in self.attr}
+
+ def set_attr(self, q, k, v, out):
+ self.attr = dict(q=q, k=k, v=v, out=out)
+
+ def forward(self, x, attn_mask=None):
+ self.pop_attr()
+ x = x.transpose(0, 1)
+ q, k, v = F.linear(x, self.in_proj_weight, self.in_proj_bias).chunk(3, dim=-1)
+
+ view_as = (*q.shape[:2], self.n_head, -1)
+ q = q.view(*view_as)
+ k = k.view(*view_as)
+ v = v.view(*view_as)
+
+ aff = torch.einsum('nqhc,nkhc->nqkh', q / (q.size(-1) ** 0.5), k)
+ if (not type(attn_mask) == type(None)):
+ aff += attn_mask.unsqueeze(-1)
+ aff = aff.softmax(dim=-2)
+ mix = torch.einsum('nqlh,nlhc->nqhc', aff, v)
+
+ out = self.out_proj(mix.flatten(-2))
+ self.set_attr(q, k, v, out)
+
+ if self.attn_record:
+ self.aff = aff
+ out = out.transpose(0, 1)
+ return out
+
+
+class ResidualAttentionBlock(nn.Module):
+ def __init__(self, d_model: int, n_head: int, attn_mask: torch.Tensor = None):
+ super().__init__()
+ # origin
+ # self.attn = nn.MultiheadAttention(d_model, n_head)
+
+ # modified
+ self.attn = MultiheadAttentionAttrExtract(d_model, n_head)
+
+ self.ln_1 = LayerNorm(d_model)
+ self.mlp = nn.Sequential(OrderedDict([
+ ("c_fc", nn.Linear(d_model, d_model * 4)),
+ ("gelu", QuickGELU()),
+ ("c_proj", nn.Linear(d_model * 4, d_model))
+ ]))
+ self.ln_2 = LayerNorm(d_model)
+ self.attn_mask = attn_mask
+
+ def attention(self, x: torch.Tensor):
+ # origin
+ # self.attn_mask = self.attn_mask.to(dtype=x.dtype, device=x.device) if self.attn_mask is not None else None
+ # return self.attn(x, x, x, need_weights=False, attn_mask=self.attn_mask)[0]
+
+ # modified
+ self.attn_mask = self.attn_mask.to(dtype=x.dtype, device=x.device) if self.attn_mask is not None else None
+ return self.attn(x, self.attn_mask)
+
+ def forward(self, x: torch.Tensor):
+ x = x + self.attention(self.ln_1(x))
+ x = x + self.mlp(self.ln_2(x))
+ return x
+
+
+class Transformer(nn.Module):
+ def __init__(self, width: int, layers: int, heads: int, attn_mask: torch.Tensor = None):
+ super().__init__()
+ self.width = width
+ self.heads = heads
+ self.layers = layers
+ self.resblocks = nn.Sequential(*[ResidualAttentionBlock(width, heads, attn_mask) for _ in range(layers)])
+
+ def forward(self, x: torch.Tensor):
+ return self.resblocks(x)
+
+
+class VisionTransformer(nn.Module):
+ def __init__(self, input_resolution: int, patch_size: int, width: int, layers: int, heads: int, output_dim: int):
+ super().__init__()
+ self.input_resolution = input_resolution
+ self.patch_size = patch_size
+ self.output_dim = output_dim
+ self.conv1 = nn.Conv2d(in_channels=3, out_channels=width, kernel_size=patch_size, stride=patch_size, bias=False)
+
+ scale = width ** -0.5
+ self.class_embedding = nn.Parameter(scale * torch.randn(width))
+ self.positional_embedding = nn.Parameter(scale * torch.randn((input_resolution // patch_size) ** 2 + 1, width))
+ self.ln_pre = LayerNorm(width)
+
+ self.transformer = Transformer(width, layers, heads)
+
+ self.ln_post = LayerNorm(width)
+ self.proj = nn.Parameter(scale * torch.randn(width, output_dim))
+
+ def forward(self, x: torch.Tensor):
+ x = self.conv1(x) # shape = [*, width, grid, grid]
+ x = x.reshape(x.shape[0], x.shape[1], -1) # shape = [*, width, grid ** 2]
+ x = x.permute(0, 2, 1) # shape = [*, grid ** 2, width]
+ x = torch.cat(
+ [
+ self.class_embedding.to(x.dtype) +
+ torch.zeros(
+ x.shape[0],
+ 1,
+ x.shape[-1],
+ dtype=x.dtype,
+ device=x.device
+ ),
+ x
+ ],
+ dim=1
+ ) # shape = [*, grid ** 2 + 1, width]
+ x = x + self.positional_embedding.to(x.dtype)
+ x = self.ln_pre(x)
+
+ x = x.permute(1, 0, 2) # NLD -> LND
+ x = self.transformer(x)
+ x = x.permute(1, 0, 2) # LND -> NLD
+
+ x = self.ln_post(x[:, 0, :])
+
+ if self.proj is not None:
+ x = x @ self.proj
+
+ return x
+
+
+class CLIP(nn.Module):
+ def __init__(
+ self,
+ embed_dim: int,
+ # vision
+ image_resolution: int,
+ vision_layers: Union[Tuple[int, int, int, int], int],
+ vision_width: int,
+ vision_patch_size: int,
+ # text
+ context_length: int,
+ vocab_size: int,
+ transformer_width: int,
+ transformer_heads: int,
+ transformer_layers: int
+ ):
+ super().__init__()
+
+ self.context_length = context_length
+
+ if isinstance(vision_layers, (tuple, list)):
+ vision_heads = vision_width * 32 // 64
+ self.visual = ModifiedResNet(
+ layers=vision_layers,
+ output_dim=embed_dim,
+ heads=vision_heads,
+ input_resolution=image_resolution,
+ width=vision_width
+ )
+ else:
+ vision_heads = vision_width // 64
+ self.visual = VisionTransformer(
+ input_resolution=image_resolution,
+ patch_size=vision_patch_size,
+ width=vision_width,
+ layers=vision_layers,
+ heads=vision_heads,
+ output_dim=embed_dim
+ )
+
+ self.transformer = Transformer(
+ width=transformer_width,
+ layers=transformer_layers,
+ heads=transformer_heads,
+ attn_mask=self.build_attention_mask()
+ )
+
+ self.vocab_size = vocab_size
+ self.token_embedding = nn.Embedding(vocab_size, transformer_width)
+ self.positional_embedding = nn.Parameter(torch.empty(self.context_length, transformer_width))
+ self.ln_final = LayerNorm(transformer_width)
+
+ self.text_projection = nn.Parameter(torch.empty(transformer_width, embed_dim))
+ self.logit_scale = nn.Parameter(torch.ones([]) * np.log(1 / 0.07))
+
+ self.initialize_parameters()
+
+ def initialize_parameters(self):
+ nn.init.normal_(self.token_embedding.weight, std=0.02)
+ nn.init.normal_(self.positional_embedding, std=0.01)
+
+ if isinstance(self.visual, ModifiedResNet):
+ if self.visual.attnpool is not None:
+ std = self.visual.attnpool.c_proj.in_features ** -0.5
+ nn.init.normal_(self.visual.attnpool.q_proj.weight, std=std)
+ nn.init.normal_(self.visual.attnpool.k_proj.weight, std=std)
+ nn.init.normal_(self.visual.attnpool.v_proj.weight, std=std)
+ nn.init.normal_(self.visual.attnpool.c_proj.weight, std=std)
+
+ for resnet_block in [self.visual.layer1, self.visual.layer2, self.visual.layer3, self.visual.layer4]:
+ for name, param in resnet_block.named_parameters():
+ if name.endswith("bn3.weight"):
+ nn.init.zeros_(param)
+
+ proj_std = (self.transformer.width ** -0.5) * ((2 * self.transformer.layers) ** -0.5)
+ attn_std = self.transformer.width ** -0.5
+ fc_std = (2 * self.transformer.width) ** -0.5
+ for block in self.transformer.resblocks:
+ nn.init.normal_(block.attn.in_proj_weight, std=attn_std)
+ nn.init.normal_(block.attn.out_proj.weight, std=proj_std)
+ nn.init.normal_(block.mlp.c_fc.weight, std=fc_std)
+ nn.init.normal_(block.mlp.c_proj.weight, std=proj_std)
+
+ if self.text_projection is not None:
+ nn.init.normal_(self.text_projection, std=self.transformer.width ** -0.5)
+
+ def build_attention_mask(self):
+ # lazily create causal attention mask, with full attention between the vision tokens
+ # pytorch uses additive attention mask; fill with -inf
+ mask = torch.empty(self.context_length, self.context_length)
+ mask.fill_(float("-inf"))
+ mask.triu_(1) # zero out the lower diagonal
+ return mask
+
+ @property
+ def dtype(self):
+ return self.visual.conv1.weight.dtype
+
+ def encode_image(self, image):
+ return self.visual(image.type(self.dtype))
+
+ def encode_text(self, text):
+ x = self.token_embedding(text).type(self.dtype) # [batch_size, n_ctx, d_model]
+
+ x = x + self.positional_embedding.type(self.dtype)
+ x = x.permute(1, 0, 2) # NLD -> LND
+ x = self.transformer(x)
+ x = x.permute(1, 0, 2) # LND -> NLD
+ x = self.ln_final(x).type(self.dtype)
+
+ # x.shape = [batch_size, n_ctx, transformer.width]
+ # take features from the eot embedding (eot_token is the highest number in each sequence)
+ x = x[torch.arange(x.shape[0]), text.argmax(dim=-1)] @ self.text_projection
+
+ return x
+
+ def forward(self, image, text):
+ image_features = self.encode_image(image)
+ text_features = self.encode_text(text)
+
+ # normalized features
+ image_features = image_features / image_features.norm(dim=1, keepdim=True)
+ text_features = text_features / text_features.norm(dim=1, keepdim=True)
+
+ # cosine similarity as logits
+ logit_scale = self.logit_scale.exp()
+ logits_per_image = logit_scale * image_features @ text_features.t()
+ logits_per_text = logits_per_image.t()
+
+ # shape = [global_batch_size, global_batch_size]
+ return logits_per_image, logits_per_text
+
+
+def convert_weights(model: nn.Module):
+ """Convert applicable model parameters to fp16"""
+
+ def _convert_weights_to_fp16(l):
+ if isinstance(l, (nn.Conv1d, nn.Conv2d, nn.Linear)):
+ l.weight.data = l.weight.data.half()
+ if l.bias is not None:
+ l.bias.data = l.bias.data.half()
+
+ if isinstance(l, nn.MultiheadAttention):
+ for attr in [*[f"{s}_proj_weight" for s in ["in", "q", "k", "v"]], "in_proj_bias", "bias_k", "bias_v"]:
+ tensor = getattr(l, attr)
+ if tensor is not None:
+ tensor.data = tensor.data.half()
+
+ for name in ["text_projection", "proj"]:
+ if hasattr(l, name):
+ attr = getattr(l, name)
+ if attr is not None:
+ attr.data = attr.data.half()
+
+ model.apply(_convert_weights_to_fp16)
+
+
+def build_model(state_dict: dict):
+ vit = "visual.proj" in state_dict
+
+ if vit:
+ vision_width = state_dict["visual.conv1.weight"].shape[0]
+ vision_layers = len(
+ [
+ k for k in state_dict.keys()
+ if k.startswith("visual.") and k.endswith(".attn.in_proj_weight")
+ ]
+ )
+ vision_patch_size = state_dict["visual.conv1.weight"].shape[-1]
+ grid_size = round((state_dict["visual.positional_embedding"].shape[0] - 1) ** 0.5)
+ image_resolution = vision_patch_size * grid_size
+ else:
+ counts: list = [
+ len(
+ set(k.split(".")[2]
+ for k in state_dict
+ if k.startswith(f"visual.layer{b}"))
+ )
+ for b in [1, 2, 3, 4]
+ ]
+ vision_layers = tuple(counts)
+ vision_width = state_dict["visual.layer1.0.conv1.weight"].shape[0]
+ output_width = round((state_dict["visual.attnpool.positional_embedding"].shape[0] - 1) ** 0.5)
+ vision_patch_size = None
+ assert output_width ** 2 + 1 == state_dict["visual.attnpool.positional_embedding"].shape[0]
+ image_resolution = output_width * 32
+
+ embed_dim = state_dict["text_projection"].shape[1]
+ context_length = state_dict["positional_embedding"].shape[0]
+ vocab_size = state_dict["token_embedding.weight"].shape[0]
+ transformer_width = state_dict["ln_final.weight"].shape[0]
+ transformer_heads = transformer_width // 64
+ transformer_layers = len(set(k.split(".")[2] for k in state_dict if k.startswith("transformer.resblocks")))
+
+ model = CLIP(
+ embed_dim,
+ image_resolution, vision_layers, vision_width, vision_patch_size,
+ context_length, vocab_size, transformer_width, transformer_heads, transformer_layers
+ )
+
+ for key in ["input_resolution", "context_length", "vocab_size"]:
+ if key in state_dict:
+ del state_dict[key]
+
+ convert_weights(model)
+ model.load_state_dict(state_dict)
+ return model.eval()
diff --git a/clean/video/dfd_fcg/src/clip/model_syno.py b/clean/video/dfd_fcg/src/clip/model_syno.py
new file mode 100644
index 0000000000000000000000000000000000000000..7581ca8d5e07016d76902e11750265a51abb8366
--- /dev/null
+++ b/clean/video/dfd_fcg/src/clip/model_syno.py
@@ -0,0 +1,703 @@
+import torch
+import random
+import pickle
+import numpy as np
+import torch.nn.functional as F
+from torch import nn
+
+
+from enum import IntEnum, auto, IntFlag
+from collections import OrderedDict
+from typing import Tuple, Union, List
+
+
+class Bottleneck(nn.Module):
+ expansion = 4
+
+ def __init__(self, inplanes, planes, stride=1):
+ super().__init__()
+
+ # all conv layers have stride 1. an avgpool is performed after the second convolution when stride > 1
+ self.conv1 = nn.Conv2d(inplanes, planes, 1, bias=False)
+ self.bn1 = nn.BatchNorm2d(planes)
+ self.relu1 = nn.ReLU(inplace=True)
+
+ self.conv2 = nn.Conv2d(planes, planes, 3, padding=1, bias=False)
+ self.bn2 = nn.BatchNorm2d(planes)
+ self.relu2 = nn.ReLU(inplace=True)
+
+ self.avgpool = nn.AvgPool2d(stride) if stride > 1 else nn.Identity()
+
+ self.conv3 = nn.Conv2d(planes, planes * self.expansion, 1, bias=False)
+ self.bn3 = nn.BatchNorm2d(planes * self.expansion)
+ self.relu3 = nn.ReLU(inplace=True)
+
+ self.downsample = None
+ self.stride = stride
+
+ if stride > 1 or inplanes != planes * Bottleneck.expansion:
+ # downsampling layer is prepended with an avgpool, and the subsequent convolution has stride 1
+ self.downsample = nn.Sequential(OrderedDict([
+ ("-1", nn.AvgPool2d(stride)),
+ ("0", nn.Conv2d(inplanes, planes *
+ self.expansion, 1, stride=1, bias=False)),
+ ("1", nn.BatchNorm2d(planes * self.expansion))
+ ]))
+
+ def forward(self, x: torch.Tensor):
+ identity = x
+
+ out = self.relu1(self.bn1(self.conv1(x)))
+ out = self.relu2(self.bn2(self.conv2(out)))
+ out = self.avgpool(out)
+ out = self.bn3(self.conv3(out))
+
+ if self.downsample is not None:
+ identity = self.downsample(x)
+
+ out += identity
+ out = self.relu3(out)
+ return out
+
+
+class AttentionPool2d(nn.Module):
+ def __init__(self, spacial_dim: int, embed_dim: int, num_heads: int, output_dim: int = None):
+ super().__init__()
+ self.positional_embedding = nn.Parameter(torch.randn(
+ spacial_dim ** 2 + 1, embed_dim) / embed_dim ** 0.5)
+ self.k_proj = nn.Linear(embed_dim, embed_dim)
+ self.q_proj = nn.Linear(embed_dim, embed_dim)
+ self.v_proj = nn.Linear(embed_dim, embed_dim)
+ self.c_proj = nn.Linear(embed_dim, output_dim or embed_dim)
+ self.num_heads = num_heads
+
+ def forward(self, x):
+ x = x.flatten(start_dim=2).permute(2, 0, 1) # NCHW -> (HW)NC
+ x = torch.cat([x.mean(dim=0, keepdim=True), x], dim=0) # (HW+1)NC
+ x = x + self.positional_embedding[:, None, :].to(x.dtype) # (HW+1)NC
+ x, _ = F.multi_head_attention_forward(
+ query=x[:1], key=x, value=x,
+ embed_dim_to_check=x.shape[-1],
+ num_heads=self.num_heads,
+ q_proj_weight=self.q_proj.weight,
+ k_proj_weight=self.k_proj.weight,
+ v_proj_weight=self.v_proj.weight,
+ in_proj_weight=None,
+ in_proj_bias=torch.cat(
+ [self.q_proj.bias, self.k_proj.bias, self.v_proj.bias]),
+ bias_k=None,
+ bias_v=None,
+ add_zero_attn=False,
+ dropout_p=0,
+ out_proj_weight=self.c_proj.weight,
+ out_proj_bias=self.c_proj.bias,
+ use_separate_proj_weight=True,
+ training=self.training,
+ need_weights=False
+ )
+ return x.squeeze(0)
+
+
+class ModifiedResNet(nn.Module):
+ """
+ A ResNet class that is similar to torchvision's but contains the following changes:
+ - There are now 3 "stem" convolutions as opposed to 1, with an average pool instead of a max pool.
+ - Performs anti-aliasing strided convolutions, where an avgpool is prepended to convolutions with stride > 1
+ - The final pooling layer is a QKV attention instead of an average pool
+ """
+
+ def __init__(self, layers, output_dim, heads, input_resolution=224, width=64):
+ super().__init__()
+ self.output_dim = output_dim
+ self.input_resolution = input_resolution
+
+ # the 3-layer stem
+ self.conv1 = nn.Conv2d(3, width // 2, kernel_size=3,
+ stride=2, padding=1, bias=False)
+ self.bn1 = nn.BatchNorm2d(width // 2)
+ self.relu1 = nn.ReLU(inplace=True)
+ self.conv2 = nn.Conv2d(width // 2, width // 2,
+ kernel_size=3, padding=1, bias=False)
+ self.bn2 = nn.BatchNorm2d(width // 2)
+ self.relu2 = nn.ReLU(inplace=True)
+ self.conv3 = nn.Conv2d(
+ width // 2, width, kernel_size=3, padding=1, bias=False)
+ self.bn3 = nn.BatchNorm2d(width)
+ self.relu3 = nn.ReLU(inplace=True)
+ self.avgpool = nn.AvgPool2d(2)
+
+ # residual layers
+ self._inplanes = width # this is a *mutable* variable used during construction
+ self.layer1 = self._make_layer(width, layers[0])
+ self.layer2 = self._make_layer(width * 2, layers[1], stride=2)
+ self.layer3 = self._make_layer(width * 4, layers[2], stride=2)
+ self.layer4 = self._make_layer(width * 8, layers[3], stride=2)
+
+ embed_dim = width * 32 # the ResNet feature dimension
+ self.attnpool = AttentionPool2d(
+ input_resolution // 32, embed_dim, heads, output_dim)
+
+ def _make_layer(self, planes, blocks, stride=1):
+ layers = [Bottleneck(self._inplanes, planes, stride)]
+
+ self._inplanes = planes * Bottleneck.expansion
+ for _ in range(1, blocks):
+ layers.append(Bottleneck(self._inplanes, planes))
+
+ return nn.Sequential(*layers)
+
+ def forward(self, x):
+ def stem(x):
+ x = self.relu1(self.bn1(self.conv1(x)))
+ x = self.relu2(self.bn2(self.conv2(x)))
+ x = self.relu3(self.bn3(self.conv3(x)))
+ x = self.avgpool(x)
+ return x
+
+ x = x.type(self.conv1.weight.dtype)
+ x = stem(x)
+ x = self.layer1(x)
+ x = self.layer2(x)
+ x = self.layer3(x)
+ x = self.layer4(x)
+ x = self.attnpool(x)
+
+ return x
+
+
+class LayerNorm(nn.LayerNorm):
+ """Subclass torch's LayerNorm to handle fp16."""
+
+ def forward(self, x: torch.Tensor):
+ orig_type = x.dtype
+ ret = super().forward(x.type(torch.float32))
+ return ret.type(orig_type)
+
+
+class QuickGELU(nn.Module):
+ def forward(self, x: torch.Tensor):
+ return x * torch.sigmoid(1.702 * x)
+
+
+############# ORIGINAL #############
+# preserve for text modules
+class ResidualAttentionBlock(nn.Module):
+ def __init__(self, d_model: int, n_head: int, attn_mask: torch.Tensor = None):
+ super().__init__()
+
+ self.attn = nn.MultiheadAttention(d_model, n_head)
+ self.ln_1 = LayerNorm(d_model)
+ self.mlp = nn.Sequential(OrderedDict([
+ ("c_fc", nn.Linear(d_model, d_model * 4)),
+ ("gelu", QuickGELU()),
+ ("c_proj", nn.Linear(d_model * 4, d_model))
+ ]))
+ self.ln_2 = LayerNorm(d_model)
+ self.attn_mask = attn_mask
+
+ def attention(self, x: torch.Tensor):
+ self.attn_mask = self.attn_mask.to(
+ dtype=x.dtype, device=x.device) if self.attn_mask is not None else None
+ return self.attn(x, x, x, need_weights=False, attn_mask=self.attn_mask)[0]
+
+ def forward(self, x: torch.Tensor):
+ x = x + self.attention(self.ln_1(x))
+ x = x + self.mlp(self.ln_2(x))
+ return x
+
+
+class Transformer(nn.Module):
+ def __init__(self, width: int, layers: int, heads: int, attn_mask: torch.Tensor = None):
+ super().__init__()
+ self.width = width
+ self.layers = layers
+ self.resblocks = nn.Sequential(
+ *[ResidualAttentionBlock(width, heads, attn_mask) for _ in range(layers)])
+
+ def forward(self, x: torch.Tensor):
+ return self.resblocks(x)
+####################################
+
+
+class MultiheadAttentionAttrExtract(nn.Module):
+ '''
+ Simple reimplementation of nn.MultiheadAttention with key, value return
+ '''
+
+ def __init__(
+ self,
+ embed_dim,
+ n_head,
+ attn_record=False
+ ):
+ super().__init__()
+
+ self.in_proj_weight = nn.Parameter(torch.empty((3 * embed_dim, embed_dim)))
+ self.in_proj_bias = nn.Parameter(torch.empty(3 * embed_dim))
+ self.out_proj = nn.Linear(embed_dim, embed_dim)
+
+ self.n_head = n_head
+
+ # recordings
+ self.attn_record = attn_record
+ self.aff = None
+
+ def forward(
+ self,
+ x: torch.Tensor
+ ):
+ # x.shape = (batch, frames, grid**2 + 1, width)
+ batch, frames = x.shape[:2]
+
+ # Original ViT Self-Attention
+ q, k, v = F.linear(
+ x,
+ self.in_proj_weight,
+ self.in_proj_bias
+ ).chunk(3, dim=-1)
+
+ view_as = (*q.shape[:3], self.n_head, -1)
+
+ q = q.view(*view_as)
+ k = k.view(*view_as)
+ v = v.view(*view_as)
+
+ aff = torch.einsum('ntqhc,ntkhc->ntqkh', q / (q.size(-1) ** 0.5), k)
+
+ aff = aff.softmax(dim=-2)
+ mix = torch.einsum('ntqlh,ntlhc->ntqhc', aff, v)
+
+ out = self.out_proj(mix.flatten(-2))
+
+ # record attentions
+ if self.attn_record:
+ self.aff = aff
+
+ return dict(
+ q=q,
+ k=k,
+ v=v,
+ out=out
+ )
+
+
+class VResidualAttentionBlock(nn.Module):
+ def __init__(
+ self,
+ d_model: int,
+ n_head: int,
+ mlp_ratio: int,
+ block_index: int,
+ attn_record: bool = False,
+ store_attrs: List[str] = [],
+ ):
+ super().__init__()
+ # modified
+ self.attn = MultiheadAttentionAttrExtract(
+ d_model,
+ n_head,
+ attn_record=attn_record
+ )
+
+ self.block_index = block_index
+ self.store_attrs = store_attrs
+
+ self.ln_1 = LayerNorm(d_model)
+ self.mlp = nn.Sequential(OrderedDict([
+ ("c_fc", nn.Linear(d_model, int(d_model * mlp_ratio))),
+ ("gelu", QuickGELU()),
+ ("c_proj", nn.Linear(int(d_model * mlp_ratio), d_model))
+ ]))
+ self.ln_2 = LayerNorm(d_model)
+
+ # preserve attrs
+ self.attr = {}
+
+ def pop_attr(self):
+ ret = self.get_attr()
+ self.attr.clear()
+ return ret
+
+ def get_attr(self):
+ return {k: self.attr[k] for k in self.attr}
+
+ def set_attr(self, **attr):
+ self.attr = {
+ k: attr[k]
+ for k in attr
+ if k in self.store_attrs
+ }
+
+ def attention(self, x: torch.Tensor):
+ return self.attn(x)
+
+ def forward(self, x: torch.Tensor):
+ self.pop_attr()
+ data = self.attention(self.ln_1(x))
+
+ x = x + data["out"]
+ x = x + self.mlp(self.ln_2(x))
+
+ data["emb"] = x
+ self.set_attr(**data)
+
+ return data
+
+
+class VTransformer(nn.Module):
+ def __init__(
+ self,
+ width: int,
+ layers: int,
+ heads: int,
+ mlp_ratio: int,
+ num_frames: int,
+ attn_record: bool = False,
+ store_attrs: List[str] = []
+ ):
+ super().__init__()
+ self.width = width
+ self.heads = heads
+ self.layers = layers
+
+ self.resblocks = nn.Sequential(*[
+ VResidualAttentionBlock(
+ d_model=width,
+ n_head=heads,
+ block_index=i,
+ mlp_ratio=mlp_ratio,
+ attn_record=attn_record,
+ store_attrs=store_attrs
+ )
+ for i in range(layers)
+ ])
+
+ def forward(self, x: torch.Tensor):
+ for blk in self.resblocks:
+ x = blk(x)["emb"]
+ return x
+
+
+class VisionTransformer(nn.Module):
+ def __init__(
+ self,
+ input_resolution: int,
+ patch_size: int,
+ width: int,
+ layers: int,
+ heads: int,
+ output_dim: int,
+ mlp_ratio: int,
+ num_frames: int,
+ attn_record: bool = False,
+ store_attrs: List[str] = [],
+ ):
+ super().__init__()
+ self.input_resolution = input_resolution
+ self.patch_size = patch_size
+ self.patch_num = (input_resolution // patch_size) ** 2
+ self.output_dim = output_dim
+
+ self.conv1 = nn.Conv2d(
+ in_channels=3,
+ out_channels=width,
+ kernel_size=patch_size,
+ stride=patch_size,
+ bias=False
+ )
+
+ scale = width ** -0.5
+ self.class_embedding = nn.Parameter(scale * torch.randn(width))
+ self.positional_embedding = nn.Parameter(scale * torch.randn((input_resolution // patch_size) ** 2 + 1, width))
+ self.ln_pre = LayerNorm(width)
+
+ self.transformer = VTransformer(
+ # structure
+ width,
+ layers,
+ heads,
+ mlp_ratio,
+ num_frames=num_frames,
+ # generic
+ attn_record=attn_record,
+ store_attrs=store_attrs
+ )
+
+ self.ln_post = LayerNorm(width)
+ self.proj = nn.Parameter(scale * torch.randn(width, output_dim))
+
+ def _prepare(self, x: torch.Tensor):
+ batch, frames = x.shape[:2]
+ # x.shape = [batch, frames, 3, px, px]
+ x = self.conv1(x.flatten(0, 1)).unflatten(0, (batch, frames))
+ # x.shape = [batch, frames, width, grid, grid]
+ x = x.flatten(-2).transpose(-1, -2)
+ # x.shape = [batch, frames, grid ** 2, width]
+ x = torch.cat(
+ [
+ self.class_embedding.to(x.dtype) +
+ torch.zeros(
+ x.shape[0],
+ x.shape[1],
+ 1,
+ x.shape[-1],
+ dtype=x.dtype,
+ device=x.device
+ ),
+ x
+ ],
+ dim=-2
+ ) # shape = [batch, frames, grid ** 2 + 1, width]
+ x = x + self.positional_embedding.to(x.dtype)
+ x = self.ln_pre(x)
+ return x
+
+ def _transformer(self, x: torch.Tensor):
+ x = self.transformer(x)
+ return x
+
+ def _finalize(self, x: torch.Tensor):
+ x = self.ln_post(x[..., 0, :])
+
+ if self.proj is not None:
+ x = x @ self.proj
+ return x
+
+ def forward(self, x: torch.Tensor):
+ x = self._prepare(x)
+ x = self._transformer(x)
+ x = self._finalize(x)
+ return x
+
+
+class CLIP(nn.Module):
+ def __init__(
+ self,
+ embed_dim: int,
+ # vision
+ image_resolution: int,
+ vision_layers: Union[Tuple[int, int, int, int], int],
+ vision_width: int,
+ vision_patch_size: int,
+ vision_mlp_ratio: int,
+ # text
+ context_length: int,
+ vocab_size: int,
+ transformer_width: int,
+ transformer_heads: int,
+ transformer_layers: int,
+ store_attrs: List[str] = [],
+ # video
+ num_frames=1,
+ **model_kargs
+ ):
+ super().__init__()
+
+ self.context_length = context_length
+
+ if isinstance(vision_layers, (tuple, list)):
+ vision_heads = vision_width * 32 // 64
+ self.visual = ModifiedResNet(
+ layers=vision_layers,
+ output_dim=embed_dim,
+ heads=vision_heads,
+ input_resolution=image_resolution,
+ width=vision_width
+ )
+ else:
+ vision_heads = vision_width // 64
+ self.visual = VisionTransformer(
+ num_frames=num_frames,
+ input_resolution=image_resolution,
+ patch_size=vision_patch_size,
+ width=vision_width,
+ layers=vision_layers,
+ heads=vision_heads,
+ output_dim=embed_dim,
+ mlp_ratio=vision_mlp_ratio,
+ store_attrs=store_attrs,
+ ** model_kargs
+ )
+
+ self.transformer = Transformer(
+ width=transformer_width,
+ layers=transformer_layers,
+ heads=transformer_heads,
+ attn_mask=self.build_attention_mask()
+ )
+
+ self.vocab_size = vocab_size
+ self.token_embedding = nn.Embedding(vocab_size, transformer_width)
+ self.positional_embedding = nn.Parameter(
+ torch.empty(self.context_length, transformer_width))
+ self.ln_final = LayerNorm(transformer_width)
+
+ self.text_projection = nn.Parameter(
+ torch.empty(transformer_width, embed_dim))
+ self.logit_scale = nn.Parameter(torch.ones([]) * np.log(1 / 0.07))
+
+ self.initialize_parameters()
+
+ def initialize_parameters(self):
+ nn.init.normal_(self.token_embedding.weight, std=0.02)
+ nn.init.normal_(self.positional_embedding, std=0.01)
+
+ if isinstance(self.visual, ModifiedResNet):
+ if self.visual.attnpool is not None:
+ std = self.visual.attnpool.c_proj.in_features ** -0.5
+ nn.init.normal_(self.visual.attnpool.q_proj.weight, std=std)
+ nn.init.normal_(self.visual.attnpool.k_proj.weight, std=std)
+ nn.init.normal_(self.visual.attnpool.v_proj.weight, std=std)
+ nn.init.normal_(self.visual.attnpool.c_proj.weight, std=std)
+
+ for resnet_block in [self.visual.layer1, self.visual.layer2, self.visual.layer3, self.visual.layer4]:
+ for name, param in resnet_block.named_parameters():
+ if name.endswith("bn3.weight"):
+ nn.init.zeros_(param)
+
+ proj_std = (self.transformer.width ** -0.5) * \
+ ((2 * self.transformer.layers) ** -0.5)
+ attn_std = self.transformer.width ** -0.5
+ fc_std = (2 * self.transformer.width) ** -0.5
+ for block in self.transformer.resblocks:
+ nn.init.normal_(block.attn.in_proj_weight, std=attn_std)
+ nn.init.normal_(block.attn.out_proj.weight, std=proj_std)
+ nn.init.normal_(block.mlp.c_fc.weight, std=fc_std)
+ nn.init.normal_(block.mlp.c_proj.weight, std=proj_std)
+
+ if self.text_projection is not None:
+ nn.init.normal_(self.text_projection,
+ std=self.transformer.width ** -0.5)
+
+ def build_attention_mask(self):
+ # lazily create causal attention mask, with full attention between the vision tokens
+ # pytorch uses additive attention mask; fill with -inf
+ mask = torch.empty(self.context_length, self.context_length)
+ mask.fill_(float("-inf"))
+ mask.triu_(1) # zero out the lower diagonal
+ return mask
+
+ @property
+ def dtype(self):
+ return self.visual.conv1.weight.dtype
+
+ def encode_frames(self, image):
+ return self.visual(image.type(self.dtype))
+
+ def encode_text(self, text):
+ x = self.token_embedding(text).type(
+ self.dtype) # [batch_size, n_ctx, d_model]
+
+ x = x + self.positional_embedding.type(self.dtype)
+ x = x.permute(1, 0, 2) # NLD -> LND
+ x = self.transformer(x)
+ x = x.permute(1, 0, 2) # LND -> NLD
+ x = self.ln_final(x).type(self.dtype)
+
+ # x.shape = [batch_size, n_ctx, transformer.width]
+ # take features from the eot embedding (eot_token is the highest number in each sequence)
+ x = x[torch.arange(x.shape[0]), text.argmax(dim=-1)
+ ] @ self.text_projection
+
+ return x
+
+ def forward(self, image, text):
+ image_features = self.encode_frames(image)
+ text_features = self.encode_text(text)
+
+ # normalized features
+ image_features = image_features / image_features.norm(dim=-1, keepdim=True)
+ text_features = text_features / text_features.norm(dim=-1, keepdim=True)
+
+ # cosine similarity as logits
+ logit_scale = self.logit_scale.exp()
+ logits_per_image = logit_scale * image_features @ text_features.transpose(-1, -2)
+ logits_per_text = logits_per_image.transpose(-1, -2)
+
+ # shape = [global_batch_size, global_batch_size]
+ return logits_per_image, logits_per_text
+
+
+def convert_weights(model: nn.Module):
+ """Convert applicable model parameters to fp16"""
+
+ def _convert_weights_to_fp16(l):
+ if isinstance(l, (nn.Conv1d, nn.Conv2d, nn.Linear)):
+ l.weight.data = l.weight.data.half()
+ if l.bias is not None:
+ l.bias.data = l.bias.data.half()
+
+ if isinstance(l, nn.MultiheadAttention):
+ for attr in [*[f"{s}_proj_weight" for s in ["in", "q", "k", "v"]], "in_proj_bias", "bias_k", "bias_v"]:
+ tensor = getattr(l, attr)
+ if tensor is not None:
+ tensor.data = tensor.data.half()
+
+ for name in ["text_projection", "proj"]:
+ if hasattr(l, name):
+ attr = getattr(l, name)
+ if attr is not None:
+ attr.data = attr.data.half()
+
+ model.apply(_convert_weights_to_fp16)
+
+
+def build_model(state_dict: dict, **model_kargs):
+ vit = "visual.proj" in state_dict
+
+ if vit:
+ vision_width = state_dict["visual.conv1.weight"].shape[0]
+ vision_layers = len(
+ [
+ k for k in state_dict.keys()
+ if k.startswith("visual.") and k.endswith(".attn.in_proj_weight")
+ ]
+ )
+ vision_patch_size = state_dict["visual.conv1.weight"].shape[-1]
+ vision_mlp_ratio = (
+ state_dict["visual.transformer.resblocks.0.mlp.c_fc.weight"].shape[0] /
+ state_dict["visual.transformer.resblocks.0.mlp.c_fc.weight"].shape[1]
+ )
+ grid_size = round(
+ (state_dict["visual.positional_embedding"].shape[0] - 1) ** 0.5)
+ image_resolution = vision_patch_size * grid_size
+ else:
+ counts: list = [
+ len(
+ set(k.split(".")[2]
+ for k in state_dict
+ if k.startswith(f"visual.layer{b}"))
+ )
+ for b in [1, 2, 3, 4]
+ ]
+ vision_layers = tuple(counts)
+ vision_width = state_dict["visual.layer1.0.conv1.weight"].shape[0]
+ output_width = round(
+ (state_dict["visual.attnpool.positional_embedding"].shape[0] - 1) ** 0.5)
+ vision_patch_size = None
+ vision_mlp_ratio = None
+ assert output_width ** 2 + \
+ 1 == state_dict["visual.attnpool.positional_embedding"].shape[0]
+ image_resolution = output_width * 32
+
+ embed_dim = state_dict["text_projection"].shape[1]
+ context_length = state_dict["positional_embedding"].shape[0]
+ vocab_size = state_dict["token_embedding.weight"].shape[0]
+ transformer_width = state_dict["ln_final.weight"].shape[0]
+ transformer_heads = transformer_width // 64
+ transformer_layers = len(set(k.split(".")[2] for k in state_dict if k.startswith("transformer.resblocks")))
+
+ model = CLIP(
+ embed_dim,
+ image_resolution, vision_layers, vision_width, vision_patch_size, vision_mlp_ratio,
+ context_length, vocab_size, transformer_width, transformer_heads, transformer_layers,
+ **model_kargs
+ )
+
+ for key in ["input_resolution", "context_length", "vocab_size"]:
+ if key in state_dict:
+ del state_dict[key]
+
+ convert_weights(model)
+ model.load_state_dict(state_dict, strict=False)
+ return model.eval()
diff --git a/clean/video/dfd_fcg/src/clip/simple_tokenizer.py b/clean/video/dfd_fcg/src/clip/simple_tokenizer.py
new file mode 100644
index 0000000000000000000000000000000000000000..0a66286b7d5019c6e221932a813768038f839c91
--- /dev/null
+++ b/clean/video/dfd_fcg/src/clip/simple_tokenizer.py
@@ -0,0 +1,132 @@
+import gzip
+import html
+import os
+from functools import lru_cache
+
+import ftfy
+import regex as re
+
+
+@lru_cache()
+def default_bpe():
+ return os.path.join(os.path.dirname(os.path.abspath(__file__)), "bpe_simple_vocab_16e6.txt.gz")
+
+
+@lru_cache()
+def bytes_to_unicode():
+ """
+ Returns list of utf-8 byte and a corresponding list of unicode strings.
+ The reversible bpe codes work on unicode strings.
+ This means you need a large # of unicode characters in your vocab if you want to avoid UNKs.
+ When you're at something like a 10B token dataset you end up needing around 5K for decent coverage.
+ This is a signficant percentage of your normal, say, 32K bpe vocab.
+ To avoid that, we want lookup tables between utf-8 bytes and unicode strings.
+ And avoids mapping to whitespace/control characters the bpe code barfs on.
+ """
+ bs = list(range(ord("!"), ord("~")+1))+list(range(ord("¡"), ord("¬")+1))+list(range(ord("®"), ord("ÿ")+1))
+ cs = bs[:]
+ n = 0
+ for b in range(2**8):
+ if b not in bs:
+ bs.append(b)
+ cs.append(2**8+n)
+ n += 1
+ cs = [chr(n) for n in cs]
+ return dict(zip(bs, cs))
+
+
+def get_pairs(word):
+ """Return set of symbol pairs in a word.
+ Word is represented as tuple of symbols (symbols being variable-length strings).
+ """
+ pairs = set()
+ prev_char = word[0]
+ for char in word[1:]:
+ pairs.add((prev_char, char))
+ prev_char = char
+ return pairs
+
+
+def basic_clean(text):
+ text = ftfy.fix_text(text)
+ text = html.unescape(html.unescape(text))
+ return text.strip()
+
+
+def whitespace_clean(text):
+ text = re.sub(r'\s+', ' ', text)
+ text = text.strip()
+ return text
+
+
+class SimpleTokenizer(object):
+ def __init__(self, bpe_path: str = default_bpe()):
+ self.byte_encoder = bytes_to_unicode()
+ self.byte_decoder = {v: k for k, v in self.byte_encoder.items()}
+ merges = gzip.open(bpe_path).read().decode("utf-8").split('\n')
+ merges = merges[1:49152-256-2+1]
+ merges = [tuple(merge.split()) for merge in merges]
+ vocab = list(bytes_to_unicode().values())
+ vocab = vocab + [v+'' for v in vocab]
+ for merge in merges:
+ vocab.append(''.join(merge))
+ vocab.extend(['<|startoftext|>', '<|endoftext|>'])
+ self.encoder = dict(zip(vocab, range(len(vocab))))
+ self.decoder = {v: k for k, v in self.encoder.items()}
+ self.bpe_ranks = dict(zip(merges, range(len(merges))))
+ self.cache = {'<|startoftext|>': '<|startoftext|>', '<|endoftext|>': '<|endoftext|>'}
+ self.pat = re.compile(r"""<\|startoftext\|>|<\|endoftext\|>|'s|'t|'re|'ve|'m|'ll|'d|[\p{L}]+|[\p{N}]|[^\s\p{L}\p{N}]+""", re.IGNORECASE)
+
+ def bpe(self, token):
+ if token in self.cache:
+ return self.cache[token]
+ word = tuple(token[:-1]) + ( token[-1] + '',)
+ pairs = get_pairs(word)
+
+ if not pairs:
+ return token+''
+
+ while True:
+ bigram = min(pairs, key = lambda pair: self.bpe_ranks.get(pair, float('inf')))
+ if bigram not in self.bpe_ranks:
+ break
+ first, second = bigram
+ new_word = []
+ i = 0
+ while i < len(word):
+ try:
+ j = word.index(first, i)
+ new_word.extend(word[i:j])
+ i = j
+ except:
+ new_word.extend(word[i:])
+ break
+
+ if word[i] == first and i < len(word)-1 and word[i+1] == second:
+ new_word.append(first+second)
+ i += 2
+ else:
+ new_word.append(word[i])
+ i += 1
+ new_word = tuple(new_word)
+ word = new_word
+ if len(word) == 1:
+ break
+ else:
+ pairs = get_pairs(word)
+ word = ' '.join(word)
+ self.cache[token] = word
+ return word
+
+ def encode(self, text):
+ bpe_tokens = []
+ text = whitespace_clean(basic_clean(text)).lower()
+ for token in re.findall(self.pat, text):
+ token = ''.join(self.byte_encoder[b] for b in token.encode('utf-8'))
+ bpe_tokens.extend(self.encoder[bpe_token] for bpe_token in self.bpe(token).split(' '))
+ return bpe_tokens
+
+ def decode(self, tokens):
+ text = ''.join([self.decoder[token] for token in tokens])
+ text = bytearray([self.byte_decoder[c] for c in text]).decode('utf-8', errors="replace").replace('', ' ')
+ return text
diff --git a/clean/video/dfd_fcg/src/example.py b/clean/video/dfd_fcg/src/example.py
new file mode 100644
index 0000000000000000000000000000000000000000..f23ccd86b11895777347e4573f4c2a240496c04b
--- /dev/null
+++ b/clean/video/dfd_fcg/src/example.py
@@ -0,0 +1,108 @@
+
+import lightning.pytorch as pl
+
+from torch import optim, nn
+from functools import partial
+from torchvision.datasets import MNIST
+from torch.utils.data import random_split, DataLoader
+
+from model.clip.lprobe import LinearProbe
+
+
+# define the LightningModule
+class EasyCLIPClassifier(pl.LightningModule):
+ def __init__(self, output_dim=10):
+ super().__init__()
+ self.save_hyperparameters()
+ self.model = LinearProbe(output_dim=output_dim)
+
+ @property
+ def transform(self):
+ return self.model.transform
+
+ @property
+ def n_px(self):
+ return self.model.model.visual.input_resolution
+
+ def training_step(self, batch, batch_idx):
+ # training_step defines the train loop.
+ # it is independent of forward
+ x, y = batch
+ x = self.model(x)
+ loss = nn.functional.cross_entropy(x, y)
+ self.log(
+ "train/loss",
+ loss,
+ batch_size=x.shape[0]
+ )
+ return loss
+
+ def test_step(self, batch, batch_idx, dataloader_idx=0):
+ # this is the test loop
+ x, y = batch
+ x = self.model(x)
+ loss = nn.functional.cross_entropy(x, y)
+ self.log(
+ f"test/loss",
+ loss,
+ batch_size=x.shape[0]
+ )
+ return loss
+
+ def validation_step(self, batch, batch_idx, dataloader_idx=0):
+ # this is the validation loop
+ x, y = batch
+ x = self.model(x)
+ loss = nn.functional.cross_entropy(x, y)
+ self.log(
+ f"valid/loss",
+ loss,
+ batch_size=x.shape[0]
+ )
+ return loss
+
+ def configure_optimizers(self):
+ optimizer = optim.AdamW(self.parameters(), lr=1e-3)
+ return optimizer
+
+
+class MNISTDataModule(pl.LightningDataModule):
+ def __init__(self, data_dir: str = "./datasets/", batch_size: int = 64, num_workers: int = 8):
+ super().__init__()
+ self.data_dir = data_dir
+ self.transform = None
+ self.batch_size = batch_size
+ self.num_workers = num_workers
+
+ def affine_model(self, model):
+ self.transform = model.transform
+
+ def prepare_data(self):
+ # download
+ MNIST(self.data_dir, train=True, download=True)
+ MNIST(self.data_dir, train=False, download=True)
+
+ def setup(self, stage: str):
+ # Assign train/val datasets for use in dataloaders
+ if stage == "fit":
+ mnist_full = MNIST(self.data_dir, train=True, transform=self.transform)
+ self.mnist_train, self.mnist_val = random_split(mnist_full, [55000, 5000])
+
+ # Assign test dataset for use in dataloader(s)
+ if stage == "test":
+ self.mnist_test = MNIST(self.data_dir, train=False, transform=self.transform)
+
+ if stage == "predict":
+ self.mnist_predict = MNIST(self.data_dir, train=False, transform=self.transform)
+
+ def train_dataloader(self):
+ return DataLoader(self.mnist_train, batch_size=self.batch_size, num_workers=self.num_workers)
+
+ def val_dataloader(self):
+ return DataLoader(self.mnist_val, batch_size=self.batch_size, num_workers=self.num_workers)
+
+ def test_dataloader(self):
+ return DataLoader(self.mnist_test, batch_size=self.batch_size, num_workers=self.num_workers)
+
+ def predict_dataloader(self):
+ return DataLoader(self.mnist_predict, batch_size=self.batch_size, num_workers=self.num_workers)
diff --git a/clean/video/dfd_fcg/src/model/base.py b/clean/video/dfd_fcg/src/model/base.py
new file mode 100644
index 0000000000000000000000000000000000000000..1edf92ad4c5c2a0e0a80b13d8e2a607cc0d34557
--- /dev/null
+++ b/clean/video/dfd_fcg/src/model/base.py
@@ -0,0 +1,192 @@
+import torch
+import torch.nn as nn
+import lightning.pytorch as pl
+
+from torch import optim
+from functools import partial
+from torchmetrics import Metric
+from torchmetrics.aggregation import MeanMetric
+from torchmetrics.classification import AUROC, Accuracy, BinaryConfusionMatrix, AveragePrecision
+
+
+class GenericStatistics(Metric):
+ def __init__(self):
+ super().__init__()
+ self.add_state("values", default=torch.tensor([]), dist_reduce_fx="sum")
+
+ def update(self, values: torch.Tensor):
+ assert len(values.shape) == 1
+
+ self.values = torch.cat([self.values, values])
+
+ def compute(self):
+ return torch.stack(
+ [
+ torch.mean(self.values),
+ torch.std(self.values)
+ ]
+ )
+
+
+class ODClassifier(pl.LightningModule):
+ def __init__(self):
+ super().__init__()
+ params = dict(add_dataloader_idx=False, rank_zero_only=True)
+ self.log = partial(self.log, **params)
+ self.log_dict = partial(self.log_dict, **params)
+ self.model = None
+
+ def forward(self, *args, **kargs):
+ return self.model(*args, **kargs)
+
+ @property
+ def transform(self):
+ raise NotImplementedError()
+
+ @property
+ def n_px(self):
+ raise NotImplementedError()
+
+ def training_step(self, batch, batch_idx):
+ results = [self.shared_step(batch[dts_name], 'train') for dts_name in batch]
+ return sum([_results['loss'] for _results in results])
+
+ def test_step(self, batch, batch_idx, dataloader_idx=0):
+ result = self.shared_step(batch, 'test')
+ return result['loss']
+
+ def validation_step(self, batch, batch_idx, dataloader_idx=0):
+ result = self.shared_step(batch, 'valid')
+ return result['loss']
+
+ def shared_step(self, batch, stage):
+ x, y, z = batch["xyz"]
+ indices = batch["indices"]
+ dts_name = batch["dts_name"]
+ logits = self(x, **z)
+ loss = nn.functional.cross_entropy(logits, y)
+ self.log(
+ f"{stage}/{dts_name}/loss",
+ loss,
+ batch_size=x.shape[0]
+ )
+ return {
+ "logits": logits,
+ "labels": y,
+ "loss": loss,
+ "dts_name": dts_name,
+ "indices": indices
+ }
+
+ def evaluate(self, x, **kargs):
+ return self.model(x, **kargs)
+
+ def on_validation_model_train(self):
+ self.model.train()
+
+
+class ODBinaryMetricClassifier(ODClassifier):
+ def __init__(self):
+ super().__init__()
+ self.dts_metrics = {}
+ self.metric_map = {
+ "auc": partial(AUROC, task="BINARY", num_classes=2),
+ "acc": partial(Accuracy, task="BINARY", num_classes=2),
+ "cm": partial(BinaryConfusionMatrix, normalize="true"),
+ "ap": partial(AveragePrecision, task="BINARY", num_classes=2),
+ "loss": MeanMetric,
+ # "stats/real": GenericStatistics,
+ # "stats/fake": GenericStatistics
+ }
+
+ def get_metric(self, dts_name, metric_name, device):
+ if (not dts_name in self.dts_metrics):
+ self.dts_metrics[dts_name] = {}
+ if (not metric_name in self.dts_metrics[dts_name]):
+ self.dts_metrics[dts_name][metric_name] = self.metric_map[metric_name]().to(device)
+ return self.dts_metrics[dts_name][metric_name]
+
+ def reset_metrics(self):
+ for dts_name, metrics in self.dts_metrics.items():
+ for metric_name, metric_obj in metrics.items():
+ metric_obj.reset()
+ self.dts_metrics.clear()
+
+ # shared procedures
+ def shared_metric_update_procedure(self, result):
+ # save metrics
+ logits = result['logits'].detach().softmax(dim=-1)
+ labels = result['labels'].detach()
+ loss = result["loss"].detach()
+ self.get_metric(result['dts_name'], 'auc', logits.device).update(logits[:, 1], labels)
+ self.get_metric(result['dts_name'], 'acc', logits.device).update(logits[:, 1], labels)
+ self.get_metric(result['dts_name'], 'ap', logits.device).update(logits[:, 1], labels)
+ self.get_metric(result['dts_name'], 'cm', logits.device).update(logits[:, 1], labels)
+ self.get_metric(result['dts_name'], 'loss', logits.device).update(loss)
+ labels = labels.to(dtype=bool)
+ # self.get_metric(result['dts_name'], 'stats/real', logits.device).update(logits[~labels, 0])
+ # self.get_metric(result['dts_name'], 'stats/fake', logits.device).update(logits[labels, 1])
+
+ def shared_beg_epoch_procedure(self, phase):
+ self.reset_metrics()
+
+ def shared_end_epoch_procedure(self, phase):
+ log_datas = {}
+ for dts_name, metrics in self.dts_metrics.items():
+ for metric_name, metric_obj in metrics.items():
+ values = metric_obj.compute().flatten()
+ name = f'{phase}/{dts_name}/{metric_name}'
+ if (len(values) == 1):
+ log_datas[name] = values
+ else:
+ for i, v in enumerate(values):
+ log_datas[f"{name}/#{i}"] = v
+ self.log_dict(log_datas)
+ self.reset_metrics()
+
+ # validation
+ def on_validation_epoch_start(self) -> None:
+ self.shared_beg_epoch_procedure('valid')
+
+ def validation_step(self, batch, batch_idx, dataloader_idx=0):
+ result = self.shared_step(batch, 'valid')
+ self.shared_metric_update_procedure(result)
+ return result['loss']
+
+ def on_validation_epoch_end(self) -> None:
+ self.shared_end_epoch_procedure('valid')
+
+ # test
+ def on_test_epoch_start(self) -> None:
+ self.shared_beg_epoch_procedure('test')
+
+ def test_step(self, batch, batch_idx, dataloader_idx=0):
+ result = self.shared_step(batch, 'test')
+ self.shared_metric_update_procedure(result)
+ return result['loss']
+
+ def on_test_epoch_end(self) -> None:
+ self.shared_end_epoch_procedure('test')
+
+ # predict
+ def predict_step(self, batch, batch_idx, dataloader_idx=0):
+ x, y, z = batch["xyz"]
+ dts_name = batch['dts_name']
+ names = batch["names"]
+ z = {
+ _k: z[_k]
+ for _k in z
+ }
+ y = y.tolist()
+ results = self.evaluate(
+ x,
+ **z
+ )
+ probs = results["logits"].softmax(dim=-1)[:, 1].flatten().cpu()
+
+ return dict(
+ y=y,
+ probs=probs,
+ names=names,
+ dts_name=dts_name
+ )
diff --git a/clean/video/dfd_fcg/src/model/clip/__init__.py b/clean/video/dfd_fcg/src/model/clip/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e9a832b2e768e86127b84f52833e7817889063e3
--- /dev/null
+++ b/clean/video/dfd_fcg/src/model/clip/__init__.py
@@ -0,0 +1,132 @@
+import torch
+import random
+import logging
+import open_clip
+import torch.nn as nn
+import src.clip.clip as CLIP
+
+
+def load_model(architecture, **kargs):
+ # architecture parameter split
+ # e.g: ViT-B/16|laion2b_s34b_b79k
+ params = architecture.split('|')
+
+ clip_arch = params[0]
+ if (len(params) == 1):
+ model, transform = CLIP.load(
+ clip_arch,
+ "cpu",
+ **kargs
+ )
+
+ elif (len(params) == 2):
+ open_pretrain = params[1]
+
+ _model, _, _ = open_clip.create_model_and_transforms(
+ clip_arch.replace("/", "-"),
+ pretrained=open_pretrain,
+ device="cpu"
+ )
+
+ model, transform = CLIP.load(
+ _model.state_dict(),
+ "cpu",
+ **kargs
+ )
+ del _model
+
+ elif (len(params) > 2):
+ raise NotImplementedError()
+
+ return model, transform
+
+
+class VideoAttrExtractor(nn.Module):
+ def __init__(
+ self,
+ architecture,
+ text_embed,
+ store_attrs=[],
+ attn_record=False,
+ pretrain=None
+ ):
+ super().__init__()
+ self.model, self.transform = load_model(
+ architecture,
+ store_attrs=store_attrs,
+ attn_record=attn_record
+ )
+ self.model = self.model.visual.float()
+
+ if (pretrain):
+ logging.info("Loading image encoder pretrain weights...")
+ state_dict = torch.load(pretrain, "cpu")
+ try:
+ self.model.load_state_dict(state_dict, strict=True)
+ except:
+ conflicts = self.model.load_state_dict(state_dict, strict=False)
+ logging.warning(
+ f"during visual pretrain weights loading, disabling strict mode with conflicts:\n{conflicts}"
+ )
+
+ self.model.requires_grad_(False)
+
+ if not text_embed:
+ self.model.proj = None
+ self.feat_dim = self.model.transformer.width
+ else:
+ self.feat_dim = self.model.output_dim
+
+ @property
+ def n_px(self):
+ return self.model.input_resolution
+
+ @property
+ def n_layers(self):
+ return self.model.transformer.layers
+
+ @property
+ def n_heads(self):
+ return self.model.transformer.heads
+
+ @property
+ def patch_size(self):
+ return self.model.patch_size
+
+ @property
+ def patch_num(self):
+ return self.model.patch_num
+
+ @property
+ def n_patch(self):
+ return int(self.n_px // self.patch_size)
+
+ @property
+ def embed_dim(self):
+ return self.feat_dim
+
+ def forward(self, x):
+ b, t = x.shape[:2]
+
+ # pass throught for attributes
+ embeds = self.model(x)
+ # retrieve all layer attributes
+ layer_attrs = []
+ for blk in self.model.transformer.resblocks:
+ attrs = blk.pop_attr()
+ layer_attrs.append(attrs)
+ return dict(
+ layer_attrs=layer_attrs,
+ embeds=embeds
+ )
+
+ def train(self, mode=True):
+ self.model.eval()
+ return self
+
+
+if __name__ == "__main__":
+ VideoAttrExtractor(
+ "ViT-L/14|laion2b_s32b_b82k",
+ text_embed=False
+ )
diff --git a/clean/video/dfd_fcg/src/model/clip/evl.py b/clean/video/dfd_fcg/src/model/clip/evl.py
new file mode 100644
index 0000000000000000000000000000000000000000..25b6e73214fa3c89c48c1b54dae908a6247bce52
--- /dev/null
+++ b/clean/video/dfd_fcg/src/model/clip/evl.py
@@ -0,0 +1,684 @@
+import torch
+from torch import nn
+
+from collections import OrderedDict
+import numpy as np
+from typing import Tuple, List, Dict
+
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+
+###
+from src.model.base import ODBinaryMetricClassifier
+from src.model.clip import VideoAttrExtractor
+from src.utility.loss import focal_loss
+
+'''
+QuickGELU and LayerNorm w/ fp16 from official CLIP repo
+(https://github.com/openai/CLIP/blob/3b473b0e682c091a9e53623eebc1ca1657385717/clip/model.py)
+'''
+
+
+class QuickGELU(nn.Module):
+ def forward(self, x: torch.Tensor):
+ return x * torch.sigmoid(1.702 * x)
+
+
+class LayerNorm(nn.LayerNorm):
+ """Subclass torch's LayerNorm to handle fp16."""
+
+ def forward(self, x: torch.Tensor):
+ orig_type = x.dtype
+ ret = super().forward(x.type(torch.float32))
+ return ret.type(orig_type)
+
+
+class Attention(nn.Module):
+ '''
+ A generalized attention module with more flexibility.
+ '''
+
+ def __init__(
+ self, q_in_dim: int, k_in_dim: int, v_in_dim: int,
+ qk_proj_dim: int, v_proj_dim: int, num_heads: int, out_dim: int,
+ return_all_features: bool = False,
+ ):
+ super().__init__()
+
+ self.q_proj = nn.Linear(q_in_dim, qk_proj_dim)
+ self.k_proj = nn.Linear(k_in_dim, qk_proj_dim)
+ self.v_proj = nn.Linear(v_in_dim, v_proj_dim)
+ self.out_proj = nn.Linear(v_proj_dim, out_dim)
+
+ self.num_heads = num_heads
+ self.return_all_features = return_all_features
+ assert qk_proj_dim % num_heads == 0 and v_proj_dim % num_heads == 0
+
+ self._initialize_weights()
+
+ def _initialize_weights(self):
+ for m in (self.q_proj, self.k_proj, self.v_proj, self.out_proj):
+ nn.init.xavier_uniform_(m.weight)
+ nn.init.constant_(m.bias, 0.)
+
+ def forward(self, q: torch.Tensor, k: torch.Tensor, v: torch.Tensor):
+ assert q.ndim == 3 and k.ndim == 3 and v.ndim == 3
+ N = q.size(0)
+ assert k.size(0) == N and v.size(0) == N
+ Lq, Lkv = q.size(1), k.size(1)
+ assert v.size(1) == Lkv
+
+ q, k, v = self.q_proj(q), self.k_proj(k), self.v_proj(v)
+
+ H = self.num_heads
+ Cqk, Cv = q.size(-1) // H, v.size(-1) // H
+
+ q = q.view(N, Lq, H, Cqk)
+ k = k.view(N, Lkv, H, Cqk)
+ v = v.view(N, Lkv, H, Cv)
+
+ aff = torch.einsum('nqhc,nkhc->nqkh', q / (Cqk ** 0.5), k)
+ aff = aff.softmax(dim=-2)
+ mix = torch.einsum('nqlh,nlhc->nqhc', aff, v)
+
+ out = self.out_proj(mix.flatten(-2))
+
+ if self.return_all_features:
+ return dict(q=q, k=k, v=v, aff=aff, out=out)
+ else:
+ return out
+
+
+class PatchEmbed2D(nn.Module):
+
+ def __init__(
+ self,
+ patch_size: Tuple[int, int] = (16, 16),
+ in_channels: int = 3,
+ embed_dim: int = 768,
+ ):
+ super().__init__()
+
+ self.patch_size = patch_size
+ self.in_channels = in_channels
+
+ self.proj = nn.Linear(np.prod(patch_size) * in_channels, embed_dim)
+
+ def _initialize_weights(self, x):
+ nn.init.kaiming_normal_(self.proj.weight, 0.)
+ nn.init.constant_(self.proj.bias, 0.)
+
+ def forward(self, x: torch.Tensor):
+ B, C, H, W = x.size()
+ pH, pW = self.patch_size
+
+ assert C == self.in_channels and H % pH == 0 and W % pW == 0
+
+ x = x.view(B, C, H // pH, pH, W // pW, pW).permute(0, 2, 4, 1, 3, 5).flatten(3).flatten(1, 2)
+ x = self.proj(x)
+
+ return x
+
+
+class TransformerEncoderLayer(nn.Module):
+
+ def __init__(
+ self,
+ in_feature_dim: int = 768,
+ qkv_dim: int = 768,
+ num_heads: int = 12,
+ mlp_factor: float = 4.0,
+ mlp_dropout: float = 0.0,
+ act: nn.Module = QuickGELU,
+ return_all_features: bool = False,
+ ):
+ super().__init__()
+
+ self.return_all_features = return_all_features
+
+ self.attn = Attention(
+ q_in_dim=in_feature_dim, k_in_dim=in_feature_dim, v_in_dim=in_feature_dim,
+ qk_proj_dim=qkv_dim, v_proj_dim=qkv_dim, num_heads=num_heads, out_dim=in_feature_dim,
+ return_all_features=return_all_features,
+ )
+
+ mlp_dim = round(mlp_factor * in_feature_dim)
+ self.mlp = nn.Sequential(OrderedDict([
+ ('fc1', nn.Linear(in_feature_dim, mlp_dim)),
+ ('act', act()),
+ ('dropout', nn.Dropout(mlp_dropout)),
+ ('fc2', nn.Linear(mlp_dim, in_feature_dim)),
+ ]))
+
+ self.norm1 = LayerNorm(in_feature_dim)
+ self.norm2 = LayerNorm(in_feature_dim)
+
+ self._initialize_weights()
+
+ def _initialize_weights(self):
+ for m in (self.mlp[0], self.mlp[-1]):
+ nn.init.xavier_uniform_(m.weight)
+ nn.init.normal_(m.bias, std=1e-6)
+
+ def forward(self, x: torch.Tensor):
+ if self.return_all_features:
+ ret_dict = {}
+
+ x_norm = self.norm1(x)
+ attn_out = self.attn(x_norm, x_norm, x_norm)
+ ret_dict['q'] = attn_out['q']
+ ret_dict['k'] = attn_out['k']
+ ret_dict['v'] = attn_out['v']
+ ret_dict['attn_out'] = attn_out['out']
+ x = x + attn_out['out']
+
+ x = x + self.mlp(self.norm2(x))
+ ret_dict['out'] = x
+
+ return ret_dict
+
+ else:
+ x_norm = self.norm1(x)
+ x = x + self.attn(x_norm, x_norm, x_norm)
+ x = x + self.mlp(self.norm2(x))
+
+ return x
+
+
+class TransformerDecoderLayer(nn.Module):
+
+ def __init__(
+ self,
+ in_feature_dim: int = 768,
+ qkv_dim: int = 768,
+ num_heads: int = 12,
+ mlp_factor: float = 4.0,
+ mlp_dropout: float = 0.0,
+ act: nn.Module = QuickGELU,
+ ):
+ super().__init__()
+
+ self.attn = Attention(
+ q_in_dim=in_feature_dim, k_in_dim=in_feature_dim, v_in_dim=in_feature_dim,
+ qk_proj_dim=qkv_dim, v_proj_dim=qkv_dim, num_heads=num_heads, out_dim=in_feature_dim,
+ )
+
+ mlp_dim = round(mlp_factor * in_feature_dim)
+ self.mlp = nn.Sequential(OrderedDict([
+ ('fc1', nn.Linear(in_feature_dim, mlp_dim)),
+ ('act', act()),
+ ('dropout', nn.Dropout(mlp_dropout)),
+ ('fc2', nn.Linear(mlp_dim, in_feature_dim)),
+ ]))
+
+ self.norm1 = LayerNorm(in_feature_dim)
+ self.norm2 = LayerNorm(in_feature_dim)
+ self.norm3 = LayerNorm(in_feature_dim)
+
+ self._initialize_weights()
+
+ def _initialize_weights(self):
+ for m in (self.mlp[0], self.mlp[-1]):
+ nn.init.xavier_uniform_(m.weight)
+ nn.init.normal_(m.bias, std=1e-6)
+
+ def forward(self, x: torch.Tensor, y: torch.Tensor):
+ y_norm = self.norm3(y)
+ x = x + self.attn(self.norm1(x), y_norm, y_norm)
+ x = x + self.mlp(self.norm2(x))
+
+ return x
+
+
+class VisionTransformer2D(nn.Module):
+
+ def __init__(
+ self,
+ feature_dim: int = 768,
+ input_size: Tuple[int, int] = (224, 224),
+ patch_size: Tuple[int, int] = (16, 16),
+ num_heads: int = 12,
+ num_layers: int = 12,
+ mlp_factor: float = 4.0,
+ act: nn.Module = QuickGELU,
+ return_all_features: bool = False,
+ ln_pre: bool = False,
+ ):
+ super().__init__()
+
+ self.return_all_features = return_all_features
+
+ self.patch_embed = PatchEmbed2D(patch_size=patch_size, embed_dim=feature_dim)
+ self.num_patches = np.prod([x // y for x, y in zip(input_size, patch_size)]) + 1
+
+ self.cls_token = nn.Parameter(torch.zeros([feature_dim]))
+ self.pos_embed = nn.Parameter(torch.zeros([self.num_patches, feature_dim]))
+
+ self.blocks = nn.ModuleList([
+ TransformerEncoderLayer(
+ in_feature_dim=feature_dim, qkv_dim=feature_dim, num_heads=num_heads, mlp_factor=mlp_factor, act=act,
+ return_all_features=return_all_features,
+ ) for _ in range(num_layers)
+ ])
+
+ if ln_pre:
+ self.ln_pre = LayerNorm(feature_dim)
+ else:
+ self.ln_pre = nn.Identity()
+
+ self._initialize_weights()
+
+ def _initialize_weights(self):
+ nn.init.normal_(self.cls_token, std=0.02)
+ nn.init.normal_(self.pos_embed, std=0.02)
+
+ def forward(self, x: torch.Tensor):
+ dtype = self.patch_embed.proj.weight.dtype
+ x = x.to(dtype)
+
+ x = self.patch_embed(x)
+ x = torch.cat([self.cls_token.view(1, 1, -1).repeat(x.size(0), 1, 1), x], dim=1)
+ x = x + self.pos_embed
+
+ x = self.ln_pre(x)
+
+ if self.return_all_features:
+ all_features = []
+ for blk in self.blocks:
+ x = blk(x)
+ all_features.append(x)
+ x = x['out']
+ return all_features
+
+ else:
+ for blk in self.blocks:
+ x = blk(x)
+ return x
+
+
+vit_presets = {
+ 'ViT-B/16-lnpre': dict(
+ feature_dim=768,
+ input_size=(224, 224),
+ patch_size=(16, 16),
+ num_heads=12,
+ num_layers=12,
+ mlp_factor=4.0,
+ ln_pre=True,
+ ),
+ 'ViT-L/14-lnpre': dict(
+ feature_dim=1024,
+ input_size=(224, 224),
+ patch_size=(14, 14),
+ num_heads=16,
+ num_layers=24,
+ mlp_factor=4.0,
+ ln_pre=True,
+ ),
+}
+
+
+class TransformerDecoderLayer(nn.Module):
+
+ def __init__(
+ self,
+ in_feature_dim: int = 768,
+ qkv_dim: int = 768,
+ num_heads: int = 12,
+ mlp_factor: float = 4.0,
+ mlp_dropout: float = 0.0,
+ act: nn.Module = QuickGELU,
+ ):
+ super().__init__()
+
+ self.attn = Attention(
+ q_in_dim=in_feature_dim, k_in_dim=in_feature_dim, v_in_dim=in_feature_dim,
+ qk_proj_dim=qkv_dim, v_proj_dim=qkv_dim, num_heads=num_heads, out_dim=in_feature_dim,
+ )
+
+ mlp_dim = round(mlp_factor * in_feature_dim)
+ self.mlp = nn.Sequential(OrderedDict([
+ ('fc1', nn.Linear(in_feature_dim, mlp_dim)),
+ ('act', act()),
+ ('dropout', nn.Dropout(mlp_dropout)),
+ ('fc2', nn.Linear(mlp_dim, in_feature_dim)),
+ ]))
+
+ self.norm1 = LayerNorm(in_feature_dim)
+ self.norm2 = LayerNorm(in_feature_dim)
+ self.norm3 = LayerNorm(in_feature_dim)
+
+ self._initialize_weights()
+
+ def _initialize_weights(self):
+ for m in (self.mlp[0], self.mlp[-1]):
+ nn.init.xavier_uniform_(m.weight)
+ nn.init.normal_(m.bias, std=1e-6)
+
+ def forward(self, x: torch.Tensor, y: torch.Tensor):
+ y_norm = self.norm3(y)
+ x = x + self.attn(self.norm1(x), y_norm, y_norm)
+ x = x + self.mlp(self.norm2(x))
+
+ return x
+
+
+class TemporalCrossAttention(nn.Module):
+
+ def __init__(
+ self,
+ spatial_size: Tuple[int, int] = (14, 14),
+ feature_dim: int = 768,
+ ):
+ super().__init__()
+
+ self.spatial_size = spatial_size
+
+ w_size = np.prod([x * 2 - 1 for x in spatial_size])
+ self.w1 = nn.Parameter(torch.zeros([w_size, feature_dim]))
+ self.w2 = nn.Parameter(torch.zeros([w_size, feature_dim]))
+
+ idx_tensor = torch.zeros([np.prod(spatial_size) for _ in (0, 1)], dtype=torch.long)
+ for q in range(np.prod(spatial_size)):
+ qi, qj = q // spatial_size[1], q % spatial_size[1]
+ for k in range(np.prod(spatial_size)):
+ ki, kj = k // spatial_size[1], k % spatial_size[1]
+ i_offs = qi - ki + spatial_size[0] - 1
+ j_offs = qj - kj + spatial_size[1] - 1
+ idx_tensor[q, k] = i_offs * (spatial_size[1] * 2 - 1) + j_offs
+ self.idx_tensor = idx_tensor
+
+ def forward_half(self, q: torch.Tensor, k: torch.Tensor, w: torch.Tensor) -> torch.Tensor:
+ q, k = q[:, :, 1:], k[:, :, 1:] # remove cls token
+
+ assert q.size() == k.size()
+ assert q.size(2) == np.prod(self.spatial_size)
+
+ attn = torch.einsum('ntqhd,ntkhd->ntqkh', q / (q.size(-1) ** 0.5), k)
+ attn = attn.softmax(dim=-2).mean(dim=-1) # L, L, N, T
+
+ self.idx_tensor = self.idx_tensor.to(w.device)
+ w_unroll = w[self.idx_tensor] # L, L, C
+ ret = torch.einsum('ntqk,qkc->ntqc', attn, w_unroll)
+
+ return ret
+
+ def forward(self, q: torch.Tensor, k: torch.Tensor):
+ N, T, L, H, D = q.size()
+ assert L == np.prod(self.spatial_size) + 1
+
+ ret = torch.zeros([N, T, L, self.w1.size(-1)], device='cuda')
+ ret[:, 1:, 1:, :] += self.forward_half(q[:, 1:, :, :, :], k[:, :-1, :, :, :], self.w1)
+ ret[:, :-1, 1:, :] += self.forward_half(q[:, :-1, :, :, :], k[:, 1:, :, :, :], self.w2)
+
+ return ret
+
+
+class EVLDecoder(nn.Module):
+
+ def __init__(
+ self,
+ num_frames: int = 8,
+ spatial_size: Tuple[int, int] = (14, 14),
+ num_layers: int = 4,
+ in_feature_dim: int = 768,
+ qkv_dim: int = 768,
+ num_heads: int = 12,
+ mlp_factor: float = 4.0,
+ enable_temporal_conv: bool = True,
+ enable_temporal_pos_embed: bool = True,
+ enable_temporal_cross_attention: bool = True,
+ mlp_dropout: float = 0.5,
+ ):
+ super().__init__()
+
+ self.enable_temporal_conv = enable_temporal_conv
+ self.enable_temporal_pos_embed = enable_temporal_pos_embed
+ self.enable_temporal_cross_attention = enable_temporal_cross_attention
+ self.num_layers = num_layers
+
+ self.decoder_layers = nn.ModuleList(
+ [TransformerDecoderLayer(in_feature_dim, qkv_dim, num_heads, mlp_factor, mlp_dropout)
+ for _ in range(num_layers)]
+ )
+
+ if enable_temporal_conv:
+ self.temporal_conv = nn.ModuleList(
+ [nn.Conv1d(in_feature_dim, in_feature_dim, kernel_size=3, stride=1,
+ padding=1, groups=in_feature_dim) for _ in range(num_layers)]
+ )
+ if enable_temporal_pos_embed:
+ self.temporal_pos_embed = nn.ParameterList(
+ [nn.Parameter(torch.zeros([num_frames, in_feature_dim])) for _ in range(num_layers)]
+ )
+ if enable_temporal_cross_attention:
+ self.cross_attention = nn.ModuleList(
+ [TemporalCrossAttention(spatial_size, in_feature_dim) for _ in range(num_layers)]
+ )
+
+ self.cls_token = nn.Parameter(torch.zeros([in_feature_dim]))
+
+ def _initialize_weights(self):
+ nn.init.normal_(self.cls_token, std=0.02)
+
+ def forward(self, in_features: List[Dict[str, torch.Tensor]]):
+ N, T, L, C = in_features[0]['out'].size()
+ assert len(in_features) == self.num_layers
+ x = self.cls_token.view(1, 1, -1).repeat(N, 1, 1)
+
+ for i in range(self.num_layers):
+ frame_features = in_features[i]['out']
+
+ if self.enable_temporal_conv:
+ feat = in_features[i]['out']
+ feat = feat.permute(0, 2, 3, 1).contiguous().flatten(0, 1) # N * L, C, T
+ feat = self.temporal_conv[i](feat)
+ feat = feat.view(N, L, C, T).permute(0, 3, 1, 2).contiguous() # N, T, L, C
+ frame_features += feat
+
+ if self.enable_temporal_pos_embed:
+ frame_features += self.temporal_pos_embed[i].view(1, T, 1, C)
+
+ if self.enable_temporal_cross_attention:
+ frame_features += self.cross_attention[i](in_features[i]['q'], in_features[i]['k'])
+
+ frame_features = frame_features.flatten(1, 2) # N, T * L, C
+
+ x = self.decoder_layers[i](x, frame_features)
+
+ return x.squeeze(1)
+
+
+class EVLVideoAttrExtractor(VideoAttrExtractor):
+
+ def __init__(
+ self,
+ architecture,
+ num_frames=1,
+ decoder_layers=4,
+ attn_record=False
+ ):
+ super(EVLVideoAttrExtractor, self).__init__(
+ architecture=architecture,
+ text_embed=False,
+ store_attrs=["q", "k", "out"],
+ attn_record=attn_record
+ )
+
+ self.decoder = EVLDecoder(
+ num_frames=num_frames,
+ spatial_size=(self.n_patch, self.n_patch),
+ num_layers=decoder_layers,
+ in_feature_dim=self.embed_dim,
+ qkv_dim=self.embed_dim,
+ num_heads=self.n_heads,
+ mlp_factor=4.0,
+ enable_temporal_conv=True,
+ enable_temporal_pos_embed=True,
+ enable_temporal_cross_attention=True,
+ mlp_dropout=0.5
+ )
+ self.decoder_layers = decoder_layers
+
+ def forward(self, x):
+ results = super(EVLVideoAttrExtractor, self).forward(x)
+
+ # remove cls_token attrs
+ # layer_attrs = results["layer_attrs"]
+ # for i in range(len(layer_attrs)):
+ # for k in layer_attrs[i]:
+ # layer_attrs[i][k] = layer_attrs[i][k][:, :, 1:]
+
+ reps = self.decoder(results["layer_attrs"][-self.decoder_layers:])
+ results["reps"] = reps
+ return results
+
+ def train(self, mode=True):
+ super().train(mode)
+ if (mode):
+ self.model.eval()
+ return self
+
+
+class BinaryLinearClassifier(nn.Module):
+ def __init__(
+ self,
+ *args,
+ **kargs,
+ ):
+ super().__init__()
+ self.encoder = EVLVideoAttrExtractor(
+ *args,
+ **kargs
+ )
+ self.head = self.make_linear(self.encoder.embed_dim)
+
+ def make_linear(self, embed_dim):
+ linear = nn.Linear(
+ embed_dim,
+ 2
+ )
+ return nn.Sequential(
+ nn.LayerNorm(embed_dim),
+ linear
+ )
+
+ @property
+ def transform(self):
+ return self.encoder.transform
+
+ @property
+ def n_px(self):
+ return self.encoder.model.input_resolution
+
+ def forward(self, x, *args, **kargs):
+ results = self.encoder(x)
+ logits = self.head(results["reps"])
+ return dict(
+ logits=logits,
+ ** results
+ )
+
+
+class EfficientVideoLearner(ODBinaryMetricClassifier):
+ def __init__(
+ self,
+ architecture: str = 'ViT-B/16',
+ num_frames: int = 1,
+ attn_record: bool = False,
+ decoder_layers: int = 4,
+
+ is_focal_loss: bool = True,
+
+ cls_weight: float = 10.0,
+ label_weights: List[float] = [1, 1],
+ ):
+ super().__init__()
+ self.save_hyperparameters()
+ params = dict(
+ architecture=architecture,
+ attn_record=attn_record,
+ num_frames=num_frames,
+ decoder_layers=decoder_layers
+ )
+ self.model = BinaryLinearClassifier(**params)
+ self.label_weights = torch.tensor(label_weights)
+ self.cls_weight = cls_weight
+ self.is_focal_loss = is_focal_loss
+
+ @property
+ def transform(self):
+ return self.model.transform
+
+ @property
+ def n_px(self):
+ return self.model.n_px
+
+ def shared_step(self, batch, stage):
+ x, y, z = batch["xyz"]
+ indices = batch["indices"]
+ dts_name = batch["dts_name"]
+ names = batch["names"]
+
+ output = self(x, **z)
+ logits = output["logits"]
+ loss = 0
+ # classification loss
+ if (stage == "train"):
+ if self.is_focal_loss:
+ cls_loss = focal_loss(
+ logits,
+ y,
+ gamma=4,
+ weight=(
+ self.label_weights.to(y.device)
+ if stage == "train" else
+ None
+ )
+ )
+ else:
+ cls_loss = nn.functional.cross_entropy(
+ logits,
+ y,
+ reduction="none",
+ weight=(
+ self.label_weights.to(y.device)
+ if stage == "train" else
+ None
+ )
+ )
+ loss += cls_loss.mean() * self.cls_weight
+ self.log(
+ f"{stage}/{dts_name}/loss",
+ cls_loss.mean(),
+ batch_size=logits.shape[0]
+ )
+ else:
+ # classification loss
+ cls_loss = nn.functional.cross_entropy(
+ logits,
+ y,
+ reduction="none",
+ weight=None
+ )
+ loss += cls_loss.mean()
+
+ return {
+ "logits": logits,
+ "labels": y,
+ "loss": loss,
+ "dts_name": dts_name,
+ "indices": indices,
+ "output": output
+ }
+
+
+if __name__ == "__main__":
+ frames = 5
+ model = EfficientVideoLearner(num_frames=frames, attn_record=True)
+ model.to("cuda")
+ logit = model(torch.randn(9, frames, 3, 224, 224).to("cuda"))["logits"]
+ logit.sum().backward()
+ print([k for k, v in model.named_parameters() if v.requires_grad])
+ print("done")
diff --git a/clean/video/dfd_fcg/src/model/clip/finetune.py b/clean/video/dfd_fcg/src/model/clip/finetune.py
new file mode 100644
index 0000000000000000000000000000000000000000..6f4551e0160f848098866f1113c6d15c06dd4d96
--- /dev/null
+++ b/clean/video/dfd_fcg/src/model/clip/finetune.py
@@ -0,0 +1,149 @@
+import wandb
+import torch
+import pickle
+import torch.nn as nn
+
+from typing import List
+
+from src.model.base import ODBinaryMetricClassifier
+from src.model.clip import VideoAttrExtractor
+from src.utility.loss import focal_loss
+
+
+class BinaryLinearClassifier(nn.Module):
+ def __init__(
+ self,
+ *args,
+ **kargs,
+ ):
+ super().__init__()
+ self.encoder = VideoAttrExtractor(
+ *args,
+ **kargs
+ )
+ self.encoder.model.requires_grad_(True)
+ self.projs = self.make_linear(self.encoder.embed_dim)
+
+ def make_linear(self, embed_dim):
+ linear = nn.Linear(
+ embed_dim,
+ 2
+ )
+ nn.init.normal_(linear.weight, std=0.001)
+ nn.init.normal_(linear.bias, std=0.001)
+ return linear
+
+ @property
+ def transform(self):
+ return self.encoder.transform
+
+ @property
+ def n_px(self):
+ return self.encoder.model.input_resolution
+
+ def forward(self, x, *args, **kargs):
+ results = self.encoder(x)
+ embeds = results["embeds"]
+ logits = self.projs(embeds.mean(1))
+ return dict(
+ logits=logits,
+ ** results
+ )
+
+
+class FullTuneVideoLearner(ODBinaryMetricClassifier):
+ def __init__(
+ self,
+ architecture: str = 'ViT-B/16',
+ text_embed: bool = False,
+ attn_record: bool = False,
+ pretrain: str = None,
+ label_weights: List[float] = [1, 1],
+ cls_weight: float = 10.0,
+ store_attrs: List[str] = [],
+ ):
+ super().__init__()
+ self.save_hyperparameters()
+ params = dict(
+ architecture=architecture,
+ text_embed=text_embed,
+ attn_record=attn_record,
+ pretrain=pretrain,
+ store_attrs=store_attrs,
+ )
+ self.model = BinaryLinearClassifier(**params)
+ self.label_weights = torch.tensor(label_weights)
+ self.cls_weight = cls_weight
+
+ @property
+ def transform(self):
+ return self.model.transform
+
+ @property
+ def n_px(self):
+ return self.model.n_px
+
+ def shared_step(self, batch, stage):
+ x, y, z = batch["xyz"]
+ indices = batch["indices"]
+ dts_name = batch["dts_name"]
+ names = batch["names"]
+
+ output = self(x, **z)
+ logits = output["logits"]
+ loss = 0
+ # classification loss
+ if (stage == "train"):
+ cls_loss = focal_loss(
+ logits,
+ y,
+ gamma=4,
+ weight=(
+ self.label_weights.to(y.device)
+ if stage == "train" else
+ None
+ )
+ )
+ loss += cls_loss.mean() * self.cls_weight
+ self.log(
+ f"{stage}/{dts_name}/loss",
+ cls_loss.mean(),
+ batch_size=logits.shape[0]
+ )
+ else:
+ # classification loss
+ cls_loss = nn.functional.cross_entropy(
+ logits,
+ y,
+ reduction="none",
+ weight=(
+ self.label_weights.to(y.device)
+ if stage == "train" else
+ None
+ )
+ )
+ loss += cls_loss.mean()
+
+ return {
+ "logits": logits,
+ "labels": y,
+ "loss": loss,
+ "dts_name": dts_name,
+ "indices": indices,
+ "output": output
+ }
+
+
+if __name__ == "__main__":
+ frames = 5
+ model = BinaryLinearClassifier(
+ architecture="ViT-L/14",
+ attn_record=True,
+ text_embed=False
+ )
+ model.to("cuda")
+ result = model(torch.randn(5, frames, 3, 224, 224).to("cuda"))
+ logit = result["logits"]
+ logit.sum().backward()
+ print([m for m, v in model.named_parameters() if v.requires_grad])
+ print("done")
diff --git a/clean/video/dfd_fcg/src/model/clip/linear.py b/clean/video/dfd_fcg/src/model/clip/linear.py
new file mode 100644
index 0000000000000000000000000000000000000000..26142c04eee00573ecae94c0ea1229529734d99f
--- /dev/null
+++ b/clean/video/dfd_fcg/src/model/clip/linear.py
@@ -0,0 +1,149 @@
+import wandb
+import torch
+import pickle
+import torch.nn as nn
+
+from typing import List
+
+from src.model.base import ODBinaryMetricClassifier
+from src.model.clip import VideoAttrExtractor
+from src.utility.loss import focal_loss
+
+
+class BinaryLinearClassifier(nn.Module):
+ def __init__(
+ self,
+ *args,
+ **kargs,
+ ):
+ super().__init__()
+ self.encoder = VideoAttrExtractor(
+ *args,
+ **kargs
+ )
+
+ self.projs = self.make_linear(self.encoder.embed_dim)
+
+ def make_linear(self, embed_dim):
+ linear = nn.Linear(
+ embed_dim,
+ 2
+ )
+ nn.init.normal_(linear.weight, std=0.001)
+ nn.init.normal_(linear.bias, std=0.001)
+ return linear
+
+ @property
+ def transform(self):
+ return self.encoder.transform
+
+ @property
+ def n_px(self):
+ return self.encoder.model.input_resolution
+
+ def forward(self, x, *args, **kargs):
+ results = self.encoder(x)
+ embeds = results["embeds"]
+ logits = self.projs(embeds.mean(1))
+ return dict(
+ logits=logits,
+ ** results
+ )
+
+
+class LinearVideoLearner(ODBinaryMetricClassifier):
+ def __init__(
+ self,
+ architecture: str = 'ViT-B/16',
+ text_embed: bool = False,
+ attn_record: bool = False,
+ pretrain: str = None,
+ label_weights: List[float] = [1, 1],
+ cls_weight: float = 10.0,
+ store_attrs: List[str] = [],
+ ):
+ super().__init__()
+ self.save_hyperparameters()
+ params = dict(
+ architecture=architecture,
+ text_embed=text_embed,
+ attn_record=attn_record,
+ pretrain=pretrain,
+ store_attrs=store_attrs,
+ )
+ self.model = BinaryLinearClassifier(**params)
+ self.label_weights = torch.tensor(label_weights)
+ self.cls_weight = cls_weight
+
+ @property
+ def transform(self):
+ return self.model.transform
+
+ @property
+ def n_px(self):
+ return self.model.n_px
+
+ def shared_step(self, batch, stage):
+ x, y, z = batch["xyz"]
+ indices = batch["indices"]
+ dts_name = batch["dts_name"]
+ names = batch["names"]
+
+ output = self(x, **z)
+ logits = output["logits"]
+ loss = 0
+ # classification loss
+ if (stage == "train"):
+ cls_loss = focal_loss(
+ logits,
+ y,
+ gamma=4,
+ weight=(
+ self.label_weights.to(y.device)
+ if stage == "train" else
+ None
+ )
+ )
+ loss += cls_loss.mean() * self.cls_weight
+ self.log(
+ f"{stage}/{dts_name}/loss",
+ cls_loss.mean(),
+ batch_size=logits.shape[0]
+ )
+ else:
+ # classification loss
+ cls_loss = nn.functional.cross_entropy(
+ logits,
+ y,
+ reduction="none",
+ weight=(
+ self.label_weights.to(y.device)
+ if stage == "train" else
+ None
+ )
+ )
+ loss += cls_loss.mean()
+
+ return {
+ "logits": logits,
+ "labels": y,
+ "loss": loss,
+ "dts_name": dts_name,
+ "indices": indices,
+ "output": output
+ }
+
+
+if __name__ == "__main__":
+ frames = 5
+ model = BinaryLinearClassifier(
+ architecture="ViT-L/14",
+ attn_record=True,
+ text_embed=False
+ )
+ model.to("cuda")
+ result = model(torch.randn(9, frames, 3, 224, 224).to("cuda"))
+ logit = result["logits"]
+ logit.sum().backward()
+ print([m for m, v in model.named_parameters() if v.requires_grad])
+ print("done")
diff --git a/clean/video/dfd_fcg/src/model/clip/svl.py b/clean/video/dfd_fcg/src/model/clip/svl.py
new file mode 100644
index 0000000000000000000000000000000000000000..ad4caf8b2f0f3958eeb54413ec48f762eeecb004
--- /dev/null
+++ b/clean/video/dfd_fcg/src/model/clip/svl.py
@@ -0,0 +1,975 @@
+import wandb
+import torch
+import pickle
+import random
+
+import torch.nn as nn
+import torch.nn.functional as F
+
+from operator import or_
+from typing import List
+from functools import reduce
+from enum import IntFlag, auto
+
+from src.model.base import ODBinaryMetricClassifier
+from src.model.clip import VideoAttrExtractor
+from src.utility.loss import focal_loss
+
+
+class OpMode(IntFlag):
+ S = auto() # spatial
+ T = auto() # temporal
+
+
+def call_module(module):
+ def fn(*args, **kwargs):
+ return module(*args, **kwargs)
+ return fn
+
+
+def get_module(module):
+ def fn():
+ return module
+ return fn
+
+
+class SynoBlock(nn.Module):
+ def __init__(
+ self,
+ n_synos,
+ d_model,
+ n_head,
+ n_patch,
+ n_frames,
+ ksize_t,
+ ksize_s,
+ t_attrs,
+ s_k_attr,
+ s_v_attr,
+ op_mode,
+ store_attrs=[],
+ attn_record=False
+ ):
+ super().__init__()
+
+ # parameters
+ self.n_patch = n_patch
+ self.t_attrs = t_attrs
+ self.s_k_attr = s_k_attr
+ self.s_v_attr = s_v_attr
+
+ self.op_mode = op_mode
+
+ if (OpMode.T in op_mode):
+ # modules
+ self.t_conv = self.make_2dconv(
+ ksize_t,
+ sum([
+ 1 if attr in ["out", "emb"] else n_head
+ for attr in t_attrs
+ ]),
+ 1
+ )
+
+ self.t_proj = nn.Sequential(
+ nn.LayerNorm(n_frames**2),
+ nn.Linear(
+ n_frames**2,
+ n_frames
+ ),
+ nn.GELU(),
+ nn.Linear(
+ n_frames,
+ n_frames**2
+ )
+ )
+
+ self.p_conv = self.make_2dconv(
+ ksize_s,
+ n_frames ** 2,
+ 1
+ )
+
+ if (OpMode.S in op_mode):
+
+ self.syno_embedding = nn.Parameter(
+ torch.zeros(n_synos, d_model)
+ )
+
+ # attribute storage
+ self.store_attrs = store_attrs
+ self.attr = {}
+
+ # attention map recording
+ self.attn_record = attn_record
+ self.aff = None
+
+ def make_2dconv(self, ksize, in_c, out_c, groups=1):
+ conv = nn.Conv2d(
+ in_channels=in_c,
+ out_channels=out_c,
+ kernel_size=ksize,
+ stride=1,
+ padding=ksize // 2,
+ groups=groups,
+ bias=True
+ )
+
+ nn.init.normal_(conv.weight, std=0.001)
+ nn.init.zeros_(conv.bias)
+
+ return conv
+
+ def pop_attr(self):
+ ret = self.get_attr()
+ self.attr.clear()
+ return ret
+
+ def get_attr(self):
+ return {k: self.attr[k] for k in self.attr}
+
+ def set_attr(self, **attr):
+ self.attr = {
+ k: attr[k]
+ for k in attr
+ if k in self.store_attrs
+ }
+
+ def temporal_detection(self, attrs):
+ b, t, l, h, d = attrs['q'][:, :, 1:].shape # ignore cls token
+ p = self.n_patch # p = l ** 0.5
+
+ affs = []
+ for attr in self.t_attrs:
+ _attr = attrs[attr][:, :, 1:] # ignore cls token
+
+ if (len(_attr.shape) == 4):
+ _attr = _attr.unsqueeze(-2)
+
+ _attr = _attr.permute(0, 2, 1, 3, 4)
+
+ aff = torch.einsum(
+ 'nlqhc,nlkhc->nlqkh',
+ _attr / (_attr.size(-1) ** 0.5),
+ _attr
+ )
+
+ aff = aff.softmax(dim=-2)
+
+ aff = aff.flatten(0, 1) # shape = (n*l,t,t,h)
+ aff = aff.permute(0, 3, 1, 2) # shape = (n*l,h,t,t)
+ affs.append(aff)
+
+ aff = torch.cat(affs, dim=1) # shape = (n*l, 3*h, t, t)
+
+ aff = self.t_conv(aff) # shape = (n*l, r, t, t) where r is number of filters
+
+ aff = aff.unflatten(0, (b, p, p)).flatten(3) # shape = (n, p, p, t*t)
+ aff = aff + self.t_proj(aff)
+ aff = aff.permute(0, 3, 1, 2) # shape = (n, t*t, p, p)
+
+ aff = self.p_conv(aff) # shape = (n, 1, p, p)
+
+ y = aff.flatten(1)
+
+ return dict(y=y) # shape = (n, p*p)
+
+ def spatial_detection(self, attrs):
+ b, t, l, h, d = attrs['q'][:, :, 1:].shape # ignore cls token
+
+ _k = attrs[self.s_k_attr][:, :, 1:] # ignore cls token
+ _v = attrs[self.s_v_attr][:, :, 1:] # ignore cls token
+
+ # prepare query
+ s_q = self.syno_embedding.unsqueeze(0).repeat(b, 1, 1) # shape = (b, synos, width)
+
+ if (len(_k.shape) == 5):
+ _k = _k.flatten(-2).contiguous() # match shape
+
+ if (len(_v.shape) == 5):
+ _v = _v.flatten(-2).contiguous() # match shape
+
+ # ===============================
+ # Version 1: Original Attention Module (Square Normalized)
+ # s_aff = torch.einsum(
+ # 'nqw,ntkw->ntqk',
+ # s_q / (s_q.size(-1) ** 0.5),
+ # _k
+ # )
+
+ # s_aff = s_aff.softmax(dim=-1)
+
+ # Version 2: Modified Attention Module (Cosine Similarity)
+ s_aff = torch.einsum(
+ 'nqw,ntkw->ntqk',
+ s_q / (s_q.norm(dim=-1, keepdim=True) + 1e-4),
+ _k / (_k.norm(dim=-1, keepdim=True) + 1e-4)
+ )
+
+ s_aff = (s_aff * 100).softmax(dim=-1)
+ # ===============================
+ s_mix = torch.einsum(
+ 'ntql,ntlw->ntqw',
+ s_aff,
+ _v
+ )
+
+ y = s_mix.flatten(1, 2).mean(dim=1) # shape = (b,w)
+
+ if self.attn_record:
+ self.aff = s_aff
+
+ return dict(s_q=s_q, y=y)
+
+ def forward(self, attrs):
+ self.pop_attr()
+ y_t = 0
+ y_s = 0
+ if OpMode.T in self.op_mode:
+ ret_t = self.temporal_detection(attrs)
+ y_t = ret_t.pop('y')
+ self.set_attr(
+ **ret_t
+ )
+ if OpMode.S in self.op_mode:
+ ret_s = self.spatial_detection(attrs)
+ y_s = ret_s.pop('y')
+ self.set_attr(
+ **ret_s
+ )
+
+ return y_t, y_s
+
+
+class SynoDecoder(nn.Module):
+ def __init__(
+ self,
+ encoder,
+ num_synos,
+ num_frames,
+ ksize_s,
+ ksize_t,
+ t_attrs,
+ s_k_attr,
+ s_v_attr,
+ op_mode,
+ store_attrs=[],
+ attn_record=False
+ ):
+ super().__init__()
+ d_model = encoder.transformer.width
+ n_head = encoder.transformer.heads
+ n_patch = int((encoder.patch_num)**0.5)
+
+ self.encoder = get_module(encoder)
+
+ self.decoder_layers = nn.ModuleList([
+ SynoBlock(
+ n_synos=num_synos,
+ d_model=d_model,
+ n_head=n_head,
+ n_patch=n_patch,
+ n_frames=num_frames,
+ ksize_t=ksize_t,
+ ksize_s=ksize_s,
+ t_attrs=t_attrs,
+ s_k_attr=s_k_attr,
+ s_v_attr=s_v_attr,
+ op_mode=op_mode,
+ store_attrs=store_attrs,
+ attn_record=attn_record
+ )
+ for _ in range(encoder.transformer.layers)
+ ])
+ self.op_mode = op_mode
+ self.feat_t_dim = n_patch**2
+ self.feat_s_dim = d_model
+
+ @property
+ def spatial_dim(self):
+ return self.feat_s_dim
+
+ @property
+ def temporal_dim(self):
+ return self.feat_t_dim
+
+ def forward(self, x):
+ b = x.shape[0]
+ layer_output = dict(
+ y_t=[],
+ y_s=[]
+ )
+
+ # first, we prepare the encoder before the transformer layers.
+ x = self.encoder()._prepare(x)
+
+ # now, we alternate between synoptic and encoder layers
+ for enc_blk, dec_blk in zip(
+ self.encoder().transformer.resblocks,
+ self.decoder_layers
+ ):
+ data = enc_blk(x)
+ x = data["emb"]
+ y_t, y_s = dec_blk(data)
+ layer_output["y_t"].append(y_t)
+ layer_output["y_s"].append(y_s)
+
+ # last, we are done with the encoder, therefore skipping the _finalize step.
+ # x = self.encoder()._finalize(x)
+
+ # aggregate the layer outputs
+ y_s = sum(layer_output["y_s"])
+ y_t = sum(layer_output["y_t"])
+
+ return y_s, y_t
+
+
+class SynoVideoAttrExtractor(VideoAttrExtractor):
+ def __init__(
+ self,
+ # VideoAttrExtractor
+ architecture,
+ text_embed,
+ pretrain=None,
+ store_attrs=[],
+ attn_record=False,
+ # synoptic
+ ksize_t=3,
+ ksize_s=3,
+ num_synos=1,
+ num_frames=1,
+ s_k_attr="k",
+ s_v_attr="v",
+ op_mode=(OpMode.S | OpMode.T),
+ t_attrs=["q", "k", "v"],
+ ):
+ super(SynoVideoAttrExtractor, self).__init__(
+ architecture=architecture,
+ text_embed=text_embed,
+ store_attrs=store_attrs,
+ attn_record=attn_record,
+ pretrain=pretrain
+ )
+ self.decoder = SynoDecoder(
+ encoder=self.model,
+ num_synos=num_synos,
+ num_frames=num_frames,
+ t_attrs=t_attrs,
+ ksize_t=ksize_t,
+ ksize_s=ksize_s,
+ s_k_attr=s_k_attr,
+ s_v_attr=s_v_attr,
+ op_mode=op_mode,
+ store_attrs=store_attrs,
+ attn_record=attn_record
+ )
+
+ @property
+ def spatial_dim(self):
+ return self.decoder.spatial_dim
+
+ @property
+ def temporal_dim(self):
+ return self.decoder.temporal_dim
+
+ def forward(self, x):
+ syno_s, syno_t = self.decoder(x=x)
+
+ layer_attrs = []
+ for enc_blk, dec_blk in zip(self.model.transformer.resblocks, self.decoder.decoder_layers):
+ layer_attrs.append(
+ {
+ **enc_blk.pop_attr(),
+ **dec_blk.pop_attr()
+ }
+ )
+
+ return dict(
+ layer_attrs=layer_attrs,
+ syno_s=syno_s,
+ syno_t=syno_t
+ )
+
+ def train(self, mode=True):
+ super().train(mode)
+ if (mode):
+ self.model.eval()
+ self.decoder.train()
+ return self
+
+
+class BinaryLinearClassifier(nn.Module):
+ def __init__(
+ self,
+ *args,
+ op_mode,
+ **kargs,
+
+ ):
+ super().__init__()
+ self.encoder = SynoVideoAttrExtractor(
+ *args,
+ **kargs,
+ op_mode=op_mode
+ )
+ self.op_mode = op_mode
+ if (OpMode.S in self.op_mode):
+ self.s_ln = nn.LayerNorm(self.encoder.spatial_dim)
+ self.s_head = nn.Linear(self.encoder.spatial_dim, 2)
+
+ if (OpMode.T in self.op_mode):
+ self.t_ln = nn.LayerNorm(self.encoder.temporal_dim)
+ self.t_head = nn.Linear(self.encoder.temporal_dim, 2)
+
+ if (self.op_mode == (OpMode.T | OpMode.S)):
+ self.a_head = nn.Linear(
+ self.encoder.temporal_dim + self.encoder.spatial_dim,
+ 2
+ )
+
+ @property
+ def transform(self):
+ return self.encoder.transform
+
+ @property
+ def n_px(self):
+ return self.encoder.model.input_resolution
+
+ def forward(self, x, *args, **kargs):
+ results = self.encoder(x)
+ logits_ = dict()
+ if (OpMode.S in self.op_mode):
+ _s = self.s_ln(results["syno_s"])
+ logits_s = self.s_head(_s)
+ logits_["logits_s"] = logits_s
+ logits_["logits"] = logits_s
+
+ if (OpMode.T in self.op_mode):
+ _t = self.t_ln(results["syno_t"])
+ logits_t = self.t_head(_t)
+ logits = logits_t
+ logits_["logits_t"] = logits_t
+ logits_["logits"] = logits_t
+
+ if (self.op_mode == (OpMode.S | OpMode.T)):
+ logits_a = self.a_head(torch.cat([_s, _t], dim=-1))
+ logits = torch.log(
+ (
+ logits_s.softmax(dim=-1) +
+ logits_t.softmax(dim=-1) +
+ logits_a.softmax(dim=-1)
+ ) / 3 + 1e-4
+ )
+ logits_["logits_a"] = logits_a
+ logits_["logits"] = logits
+
+ return dict(
+ **logits_,
+ ** results
+ )
+
+
+class SynoVideoLearner(ODBinaryMetricClassifier):
+ def __init__(
+ self,
+ num_synos: int = 1,
+ num_frames: int = 1,
+ ksize_s: int = 3,
+ ksize_t: int = 3,
+ t_attrs: List[str] = ["q", "k", "v"],
+ s_k_attr: str = "k",
+ s_v_attr: str = "v",
+ op_mode: List[str] = ["S", "T"],
+ architecture: str = 'ViT-B/16',
+ text_embed: bool = False,
+ pretrain: str = None,
+
+ attn_record: bool = False,
+
+ store_attrs: List[str] = [],
+ is_focal_loss: bool = True,
+
+ cls_weight: float = 10.0,
+ label_weights: List[float] = [1, 1],
+ ):
+ super().__init__()
+ self.save_hyperparameters()
+ op_mode = reduce(or_, [OpMode[m] for m in op_mode])
+ params = dict(
+ architecture=architecture,
+ text_embed=text_embed,
+ attn_record=attn_record,
+ pretrain=pretrain,
+ num_synos=num_synos,
+ num_frames=num_frames,
+ ksize_s=ksize_s,
+ ksize_t=ksize_t,
+ store_attrs=store_attrs,
+ t_attrs=t_attrs,
+ s_k_attr=s_k_attr,
+ s_v_attr=s_v_attr,
+ op_mode=op_mode
+ )
+ self.model = BinaryLinearClassifier(**params)
+
+ self.label_weights = torch.tensor(label_weights)
+ self.cls_weight = cls_weight
+ self.is_focal_loss = is_focal_loss
+
+ @property
+ def transform(self):
+ return self.model.transform
+
+ @property
+ def n_px(self):
+ return self.model.n_px
+
+ def shared_step(self, batch, stage):
+ x, y, z = batch["xyz"]
+ indices = batch["indices"]
+ dts_name = batch["dts_name"]
+ names = batch["names"]
+
+ output = self(x, **z)
+ logits = output["logits"]
+ loss = 0
+ # classification loss
+ if (stage == "train"):
+ logits = [output[k] for k in output if "logits_" in k]
+ y = y.repeat(len(logits))
+ logits = torch.cat(logits, dim=0)
+ if self.is_focal_loss:
+ cls_loss = focal_loss(
+ logits,
+ y,
+ gamma=4,
+ weight=(
+ self.label_weights.to(y.device)
+ if stage == "train" else
+ None
+ )
+ )
+ else:
+ cls_loss = nn.functional.cross_entropy(
+ logits,
+ y,
+ reduction="none",
+ weight=(
+ self.label_weights.to(y.device)
+ if stage == "train" else
+ None
+ )
+ )
+ loss += cls_loss.mean() * self.cls_weight
+ self.log(
+ f"{stage}/{dts_name}/loss",
+ cls_loss.mean(),
+ batch_size=logits.shape[0]
+ )
+ else:
+ # classification loss
+ cls_loss = nn.functional.cross_entropy(
+ logits,
+ y,
+ reduction="none",
+ weight=None
+ )
+ loss += cls_loss.mean()
+
+ return {
+ "logits": logits,
+ "labels": y,
+ "loss": loss,
+ "dts_name": dts_name,
+ "indices": indices,
+ "output": output
+ }
+
+
+class FFGSynoVideoLearner(SynoVideoLearner):
+ def __init__(
+ self,
+ # ffg
+ face_feature_path: str,
+ face_parts: List[str] = [
+ "lips",
+ "skin",
+ "eyes",
+ "nose"
+ ],
+ face_attn_attr: str = "k",
+ syno_attn_attr: str = "s_q",
+ ffg_temper: float = 30,
+ ffg_weight: float = 1.5,
+ ffg_layers: int = -1,
+ ffg_reverse: bool = False,
+
+ # generic
+ architecture: str = 'ViT-B/16',
+ text_embed: bool = False,
+ pretrain: str = None,
+
+ num_frames: int = 1,
+ ksize_s: int = 3,
+ ksize_t: int = 3,
+ t_attrs: List[str] = ["q", "k", "v"],
+ s_k_attr: str = "k",
+ s_v_attr: str = "v",
+ op_mode: List[str] = ["S", "T"],
+ attn_record: bool = False,
+
+ store_attrs: List[str] = [],
+ is_focal_loss: bool = True,
+
+ cls_weight: float = 10.0,
+ label_weights: List[float] = [1, 1],
+ ):
+ assert 'S' in op_mode, "FFG must include the spatial branch for operation."
+
+ self.num_face_parts = len(face_parts)
+ self.face_attn_attr = face_attn_attr
+ self.syno_attn_attr = syno_attn_attr
+ self.ffg_temper = ffg_temper
+ self.ffg_weight = ffg_weight
+ self.ffg_layers = ffg_layers
+ self.ffg_reverse = ffg_reverse
+
+ super().__init__(
+ num_frames=num_frames,
+ num_synos=self.num_face_parts,
+ ksize_s=ksize_s,
+ ksize_t=ksize_t,
+ op_mode=op_mode,
+ t_attrs=t_attrs,
+ s_k_attr=s_k_attr,
+ s_v_attr=s_v_attr,
+ architecture=architecture,
+ text_embed=text_embed,
+ attn_record=attn_record,
+ pretrain=pretrain,
+ store_attrs=set([*store_attrs, self.syno_attn_attr]),
+ cls_weight=cls_weight,
+ label_weights=label_weights,
+ is_focal_loss=is_focal_loss
+ )
+
+ self.save_hyperparameters()
+
+ with open(face_feature_path, "rb") as f:
+ _face_features = pickle.load(f)
+ self.face_features = torch.stack(
+ [
+ torch.stack([
+ _face_features[self.face_attn_attr][p][l]
+ for p in face_parts
+ ])
+ for l in range(self.model.encoder.model.transformer.layers)
+ ]
+ )
+ self.face_features = self.face_features.unsqueeze(1)
+
+ for i, dec_blk in enumerate(self.model.encoder.decoder.decoder_layers):
+ dec_blk.syno_embedding.data = self.face_features[i].squeeze(0).data.clone()
+
+ def shared_step(self, batch, stage):
+ result = super().shared_step(batch, stage)
+
+ if (stage == "train"):
+ dts_name = result["dts_name"]
+ x = batch["xyz"][0]
+
+ # face feature guided loss
+ target_attn_attrs = torch.stack(
+ [
+ attrs[self.syno_attn_attr]
+ for attrs in result["output"]["layer_attrs"]
+ ]
+ ) # qs.shape = [layer,b,t,syno,patch,head]
+
+ if (len(target_attn_attrs.shape) == 4):
+ # shape = [l, b, synos, head*width]
+ # for: out, emb
+ pass
+ elif (len(target_attn_attrs.shape) == 5):
+ # shape = [l, b, synos, head,width]
+ # for: q, k, v
+ target_attn_attrs = target_attn_attrs.flatten(-2)
+ elif (len(target_attn_attrs.shape) == 6):
+ # shape = [l, b, t, synos, head, width]
+ # for: q, k, v
+ target_attn_attrs = target_attn_attrs.mean(2).flatten(-2)
+ else:
+ raise NotImplementedError()
+
+ face_features = self.face_features.to(
+ dtype=target_attn_attrs.dtype,
+ device=target_attn_attrs.device
+ )
+
+ if self.ffg_layers == -1:
+ pass
+ elif self.ffg_layers > 0:
+ if (self.ffg_reverse):
+ face_features = face_features[: self.ffg_layers]
+ target_attn_attrs = target_attn_attrs[: self.ffg_layers]
+ else:
+ layers = (
+ self.model.encoder.model.transformer.layers -
+ self.ffg_layers
+ )
+ face_features = face_features[layers:]
+ target_attn_attrs = target_attn_attrs[layers:]
+ else:
+ raise NotImplementedError()
+
+ l, b, q = target_attn_attrs.shape[:3]
+ face_features = face_features / face_features.norm(dim=-1, keepdim=True)
+ target_attn_attrs = target_attn_attrs / target_attn_attrs.norm(dim=-1, keepdim=True)
+
+ logits = self.ffg_temper * (target_attn_attrs @ face_features.transpose(-1, -2))
+
+ cls_sim = torch.nn.functional.cross_entropy(
+ logits.flatten(0, 2),
+ (
+ torch.arange(
+ 0,
+ self.num_face_parts
+ )
+ .repeat((l * b))
+ .to(x.device)
+ ),
+ reduction="none"
+ ).mean()
+
+ self.log(
+ f"{stage}/{dts_name}/syno_sim",
+ cls_sim,
+ batch_size=x.shape[0]
+ )
+ result["loss"] += cls_sim * self.ffg_weight
+
+ return result
+
+
+class FFESynoVideoLearner(SynoVideoLearner):
+ def __init__(
+ self,
+ # ffg
+ face_feature_path: str,
+ face_parts: List[str] = [
+ "lips",
+ "skin",
+ "eyes",
+ "nose"
+ ],
+ face_attn_attr: str = "k",
+ syno_attn_attr: str = "s_q",
+ ffg_temper: float = 30,
+ ffg_weight: float = 1.5,
+ ffg_layers: int = -1,
+ ffg_reverse: bool = False,
+ ffe_weight: float = 100,
+ grad_temper: float = 100,
+
+ # generic
+ architecture: str = 'ViT-B/16',
+ text_embed: bool = False,
+ pretrain: str = None,
+
+ num_frames: int = 1,
+ ksize_s: int = 3,
+ ksize_t: int = 3,
+ t_attrs: List[str] = ["q", "k", "v"],
+ s_k_attr: str = "k",
+ s_v_attr: str = "v",
+ op_mode: List[str] = ["S", "T"],
+ attn_record: bool = True,
+
+ store_attrs: List[str] = [],
+ is_focal_loss: bool = True,
+
+ cls_weight: float = 10.0,
+ label_weights: List[float] = [1, 1],
+ ):
+ assert 'S' in op_mode, "FFG must include the spatial branch for operation."
+
+ self.num_face_parts = len(face_parts)
+ self.face_attn_attr = face_attn_attr
+ self.syno_attn_attr = syno_attn_attr
+ self.ffg_temper = ffg_temper
+ self.ffg_weight = ffg_weight
+ self.ffg_layers = ffg_layers
+ self.ffg_reverse = ffg_reverse
+ self.ffe_weight = ffe_weight
+ self.grad_temper = grad_temper
+
+ super().__init__(
+ num_frames=num_frames,
+ num_synos=self.num_face_parts,
+ ksize_s=ksize_s,
+ ksize_t=ksize_t,
+ op_mode=op_mode,
+ t_attrs=t_attrs,
+ s_k_attr=s_k_attr,
+ s_v_attr=s_v_attr,
+ architecture=architecture,
+ text_embed=text_embed,
+ attn_record=attn_record,
+ pretrain=pretrain,
+ store_attrs=set([*store_attrs, self.syno_attn_attr]),
+ cls_weight=cls_weight,
+ label_weights=label_weights,
+ is_focal_loss=is_focal_loss
+ )
+
+ self.save_hyperparameters()
+
+ with open(face_feature_path, "rb") as f:
+ _face_features = pickle.load(f)
+ self.face_features = torch.stack(
+ [
+ torch.stack([
+ _face_features[self.face_attn_attr][p][l]
+ for p in face_parts
+ ])
+ for l in range(self.model.encoder.model.transformer.layers)
+ ]
+ )
+ self.face_features = self.face_features.unsqueeze(1)
+
+ for i, dec_blk in enumerate(self.model.encoder.decoder.decoder_layers):
+ dec_blk.syno_embedding.data = self.face_features[i].squeeze(0).data.clone()
+
+ def shared_step(self, batch, stage):
+ result = super().shared_step(batch, stage)
+
+ if (stage == "train"):
+ dts_name = result["dts_name"]
+ x = batch["xyz"][0]
+
+ # face feature guided loss
+ target_attn_attrs = torch.stack(
+ [
+ attrs[self.syno_attn_attr]
+ for attrs in result["output"]["layer_attrs"]
+ ]
+ ) # qs.shape = [layer,b,t,syno,patch,head]
+
+ if (len(target_attn_attrs.shape) == 4):
+ # shape = [l, b, synos, head*width]
+ # for: out, emb
+ pass
+ elif (len(target_attn_attrs.shape) == 5):
+ # shape = [l, b, synos, head,width]
+ # for: q, k, v
+ target_attn_attrs = target_attn_attrs.flatten(-2)
+ elif (len(target_attn_attrs.shape) == 6):
+ # shape = [l, b, t, synos, head, width]
+ # for: q, k, v
+ target_attn_attrs = target_attn_attrs.mean(2).flatten(-2)
+ else:
+ raise NotImplementedError()
+
+ face_features = self.face_features.to(
+ dtype=target_attn_attrs.dtype,
+ device=target_attn_attrs.device
+ )
+
+ if self.ffg_layers == -1:
+ pass
+ elif self.ffg_layers > 0:
+ if (self.ffg_reverse):
+ face_features = face_features[: self.ffg_layers]
+ target_attn_attrs = target_attn_attrs[: self.ffg_layers]
+ else:
+ layers = (
+ self.model.encoder.model.transformer.layers -
+ self.ffg_layers
+ )
+ face_features = face_features[layers:]
+ target_attn_attrs = target_attn_attrs[layers:]
+ else:
+ raise NotImplementedError()
+
+ l, b, q = target_attn_attrs.shape[:3]
+ face_features = face_features / face_features.norm(dim=-1, keepdim=True)
+ target_attn_attrs = target_attn_attrs / target_attn_attrs.norm(dim=-1, keepdim=True)
+
+ logits = self.ffg_temper * (target_attn_attrs @ face_features.transpose(-1, -2))
+
+ cls_sim = torch.nn.functional.cross_entropy(
+ logits.flatten(0, 2),
+ (
+ torch.arange(
+ 0,
+ self.num_face_parts
+ )
+ .repeat((l * b))
+ .to(x.device)
+ ),
+ reduction="none"
+ ).mean()
+
+ self.log(
+ f"{stage}/{dts_name}/syno_sim",
+ cls_sim,
+ batch_size=x.shape[0]
+ )
+
+ result["loss"] += cls_sim * self.ffg_weight
+
+ grad_raw_grid = (
+ torch.stack(
+ torch.autograd.grad(
+ result["loss"],
+ [layer.aff for layer in self.model.encoder.decoder.decoder_layers],
+ grad_outputs=torch.ones_like(result["loss"]),
+ retain_graph=True,
+ create_graph=True
+ )
+ ).abs() * self.grad_temper
+ )
+
+ attn_grid = (
+ torch.stack(
+ [layer.aff for layer in self.model.encoder.decoder.decoder_layers]
+ )
+ ).detach()
+
+ grad_align = torch.nn.functional.kl_div(
+ torch.nn.functional.log_softmax(grad_raw_grid.flatten(3), dim=-1),
+ attn_grid.flatten(3),
+ )
+
+ self.log(
+ f"{stage}/{dts_name}/grad_align",
+ grad_align,
+ batch_size=x.shape[0]
+ )
+
+ result["loss"] += grad_align * self.ffe_weight
+
+ return result
+
+
+if __name__ == "__main__":
+
+ frames = 5
+ # # AttrExtractor Test
+ model = FFGSynoVideoLearner(
+ face_feature_path="misc/L14_real_semantic_patches_v2_2000.pickle",
+ architecture="ViT-L/14",
+ num_frames=frames
+ )
+ model.to("cuda")
+ results = model(torch.randn(9, frames, 3, 224, 224).to("cuda"))
+ synos = results["logits"]
+ synos.sum().backward()
+
+ # model = GlitchBlock(n_head=12, n_patch=14, n_filt=10, ksize=3, n_frames=frames)
+ # model.to("cuda")
+ # logits = model({
+ # "q": torch.randn(1, frames, 197, 12, 64).to("cuda"),
+ # "k": torch.randn(1, frames, 197, 12, 64).to("cuda")
+ # })
+ print("done")
diff --git a/clean/video/dfd_fcg/src/model/clip/vpt.py b/clean/video/dfd_fcg/src/model/clip/vpt.py
new file mode 100644
index 0000000000000000000000000000000000000000..c0106fc4868f7d8d47b270de38e73ac379f0ec49
--- /dev/null
+++ b/clean/video/dfd_fcg/src/model/clip/vpt.py
@@ -0,0 +1,238 @@
+import wandb
+import torch
+import pickle
+import random
+
+import torch.nn as nn
+import torch.nn.functional as F
+
+from operator import or_
+from typing import List
+from functools import reduce
+from enum import IntFlag, auto
+
+from src.model.base import ODBinaryMetricClassifier
+from src.model.clip import VideoAttrExtractor
+from src.utility.loss import focal_loss
+
+
+class PromptMode(IntFlag):
+ DEEP = auto() # spatial
+ SHALLOW = auto() # temporal
+
+
+class PromptedVideoAttrExtractor(VideoAttrExtractor):
+ def __init__(
+ self,
+ # VideoAttrExtractor
+ architecture,
+ text_embed,
+ pretrain=None,
+ store_attrs=[],
+ attn_record=False,
+ # visual prompting
+ num_prompts=1,
+ prompt_mode=PromptMode.DEEP
+ ):
+ super(PromptedVideoAttrExtractor, self).__init__(
+ architecture=architecture,
+ text_embed=text_embed,
+ store_attrs=store_attrs,
+ attn_record=attn_record,
+ pretrain=pretrain
+ )
+ self.num_prompts = num_prompts
+ self.prompt_mode = prompt_mode
+
+ if (prompt_mode == PromptMode.DEEP):
+ # shape = batch,frames,layers,prompts,dim
+ self.visual_prompts = nn.Parameter(torch.zeros(1, 1, self.n_layers, num_prompts, self.feat_dim), requires_grad=True)
+ elif (prompt_mode == PromptMode.SHALLOW):
+ # shape = batch,frames,layers,prompts,dim
+ self.visual_prompts = nn.Parameter(torch.zeros(1, 1, 1, num_prompts, self.feat_dim), requires_grad=True)
+ nn.init.normal_(self.visual_prompts, std=0.001)
+
+ def forward(self, x):
+
+ # first, we prepare the encoder before the transformer layers.
+ x = self.model._prepare(x)
+
+ x = torch.cat([x, self.visual_prompts[:, :, 0].repeat(x.shape[0], x.shape[1], 1, 1)], dim=-2)
+
+ # now, we alternate between synoptic and encoder layers
+ for i, enc_blk in enumerate(self.model.transformer.resblocks):
+ if i > 0 and self.prompt_mode == PromptMode.DEEP:
+ x[:, :, :self.num_prompts] = (
+ x[:, :, :self.num_prompts] +
+ self.visual_prompts[:, :, i].repeat(x.shape[0], x.shape[1], 1, 1)
+ )
+ data = enc_blk(x)
+ x = data["emb"]
+
+ layer_attrs = []
+ for enc_blk in self.model.transformer.resblocks:
+ layer_attrs.append(
+ {
+ **enc_blk.pop_attr()
+ }
+ )
+
+ embeds = x[:, :, :self.num_prompts].mean(dim=2)
+
+ return dict(
+ layer_attrs=layer_attrs,
+ embeds=embeds
+ )
+
+ def train(self, mode=True):
+ super().train(mode)
+
+ if (mode):
+ self.model.eval()
+
+ return self
+
+
+class BinaryLinearClassifier(nn.Module):
+ def __init__(
+ self,
+ *args,
+ **kargs,
+ ):
+ super().__init__()
+ self.encoder = PromptedVideoAttrExtractor(
+ *args,
+ **kargs
+ )
+
+ self.projs = self.make_linear(self.encoder.embed_dim)
+
+ def make_linear(self, embed_dim):
+ linear = nn.Linear(
+ embed_dim,
+ 2
+ )
+ nn.init.normal_(linear.weight, std=0.001)
+ nn.init.normal_(linear.bias, std=0.001)
+ return linear
+
+ @property
+ def transform(self):
+ return self.encoder.transform
+
+ @property
+ def n_px(self):
+ return self.encoder.model.input_resolution
+
+ def forward(self, x, *args, **kargs):
+ results = self.encoder(x)
+ embeds = results["embeds"]
+ logits = self.projs(embeds.mean(1))
+ return dict(
+ logits=logits,
+ ** results
+ )
+
+
+class PromptedLinearVideoLearner(ODBinaryMetricClassifier):
+ def __init__(
+ self,
+ architecture: str = 'ViT-B/16',
+ text_embed: bool = False,
+ attn_record: bool = False,
+ pretrain: str = None,
+ label_weights: List[float] = [1, 1],
+ cls_weight: float = 10.0,
+ store_attrs: List[str] = [],
+ num_prompts=1,
+ prompt_mode=PromptMode.DEEP
+ ):
+ super().__init__()
+ self.save_hyperparameters()
+ params = dict(
+ architecture=architecture,
+ text_embed=text_embed,
+ attn_record=attn_record,
+ pretrain=pretrain,
+ store_attrs=store_attrs,
+ num_prompts=num_prompts,
+ prompt_mode=PromptMode[prompt_mode]
+ )
+ self.model = BinaryLinearClassifier(**params)
+ self.label_weights = torch.tensor(label_weights)
+ self.cls_weight = cls_weight
+
+ @property
+ def transform(self):
+ return self.model.transform
+
+ @property
+ def n_px(self):
+ return self.model.n_px
+
+ def shared_step(self, batch, stage):
+ x, y, z = batch["xyz"]
+ indices = batch["indices"]
+ dts_name = batch["dts_name"]
+ names = batch["names"]
+
+ output = self(x, **z)
+ logits = output["logits"]
+ loss = 0
+ # classification loss
+ if (stage == "train"):
+ cls_loss = focal_loss(
+ logits,
+ y,
+ gamma=4,
+ weight=(
+ self.label_weights.to(y.device)
+ if stage == "train" else
+ None
+ )
+ )
+ loss += cls_loss.mean() * self.cls_weight
+ self.log(
+ f"{stage}/{dts_name}/loss",
+ cls_loss.mean(),
+ batch_size=logits.shape[0]
+ )
+ else:
+ # classification loss
+ cls_loss = nn.functional.cross_entropy(
+ logits,
+ y,
+ reduction="none",
+ weight=(
+ self.label_weights.to(y.device)
+ if stage == "train" else
+ None
+ )
+ )
+ loss += cls_loss.mean()
+
+ return {
+ "logits": logits,
+ "labels": y,
+ "loss": loss,
+ "dts_name": dts_name,
+ "indices": indices,
+ "output": output
+ }
+
+
+if __name__ == "__main__":
+ frames = 5
+ model = BinaryLinearClassifier(
+ architecture="ViT-L/14",
+ attn_record=False,
+ text_embed=False,
+ num_prompts=4,
+ prompt_mode=PromptMode.SHALLOW
+ )
+ model.to("cuda")
+ result = model(torch.randn(5, frames, 3, 224, 224).to("cuda"))
+ logit = result["logits"]
+ logit.sum().backward()
+ print([m for m, v in model.named_parameters() if v.requires_grad])
+ print("done")
diff --git a/clean/video/dfd_fcg/src/preprocess/crop_main_face.py b/clean/video/dfd_fcg/src/preprocess/crop_main_face.py
new file mode 100644
index 0000000000000000000000000000000000000000..5b83ef335697001411cbb9826339e58136207e60
--- /dev/null
+++ b/clean/video/dfd_fcg/src/preprocess/crop_main_face.py
@@ -0,0 +1,512 @@
+import os
+import cv2
+import pickle
+import argparse
+import numpy as np
+from glob import glob
+from tqdm import tqdm
+from typing import List
+from os.path import exists
+from dataclasses import dataclass
+from multiprocessing import Pool, cpu_count
+
+
+def load_args(args):
+ parser = argparse.ArgumentParser(
+ description='Pre-processing'
+ )
+ parser.add_argument(
+ '--root-dir', default=None, help='video directory'
+ )
+ parser.add_argument(
+ '--mean-face', default='./misc/20words_mean_face.npy', help='mean face path'
+ )
+ parser.add_argument(
+ '--crop-size', default=150, type=int, help='width of face crop'
+ )
+ parser.add_argument(
+ '--target-size', default=256, type=int, help='the target width of affined faces.'
+ )
+ parser.add_argument(
+ '--start-idx', default=15, type=int, help='start of landmark frame_idx'
+ )
+ parser.add_argument(
+ '--stop-idx', default=68, type=int, help='end of landmark frame_idx'
+ )
+ parser.add_argument(
+ '--window-margin', default=12, type=int, help='window margin for smoothed landmarks'
+ )
+ parser.add_argument(
+ '--video-dir', default="videos", type=str, help='video folder'
+ )
+ parser.add_argument(
+ '--fdata-dir', default="frame_data", type=str, help='frame data folder'
+ )
+ parser.add_argument(
+ '--glob-exp', default="*/*", type=str, help='additional glob expressions.'
+ )
+ parser.add_argument(
+ '--crop-dir', default="cropped", type=str, help="folder destination to save the process results."
+ )
+ parser.add_argument(
+ '--max-pad-secs', default=3, type=int, help="maximum seconds to pad for the untrack faces."
+ )
+ parser.add_argument(
+ '--min-crop-rate', default=0.9, type=float, help="minimum ratio of duration with tracked faces."
+ )
+
+ parser.add_argument(
+ '--d-rate', type=float, default=0.65, help="the maximum distance between the landmarks according to the ratio of face size."
+ )
+
+ parser.add_argument(
+ '--replace', action="store_true", default=False
+ )
+
+ parser.add_argument(
+ '--workers', default=int(cpu_count() / 2), type=int
+ )
+
+ args = parser.parse_args(args)
+
+ return args
+
+
+class FaceData:
+ def __init__(self, _lm, _bbox, _idx):
+ self.ema_lm = _lm # shape = (68, 2)
+ self.ema_bbox = _bbox # shape = (2, 2)
+ self.lm = [_lm]
+ self.bbox = [_bbox]
+ self.idx = [_idx]
+ self.paddings = 0
+
+ def last_landmark(self):
+ return self.ema_lm
+
+ def last_bbox(self):
+ return self.ema_bbox
+
+ def face_size(self):
+ bbox = self.last_bbox()
+ return np.linalg.norm(bbox[0] - bbox[1], axis=-1)
+
+ def d_lm(self, landmarks):
+ return np.mean(
+ np.linalg.norm(landmarks - self.last_landmark(), axis=-1),
+ axis=1
+ )
+
+ def d_bbox(self, bboxes):
+ return np.mean(
+ np.linalg.norm(bboxes - self.last_bbox(), axis=-1),
+ axis=1
+ )
+
+ def pad(self):
+ self.paddings += 1
+
+ def add(self, _lm, _bbox, _idx):
+ self.ema_lm = self.ema_lm * 0.5 + _lm * 0.5
+ self.ema_bbox = self.ema_bbox * 0.5 + _bbox * 0.5
+ self.lm.append(_lm)
+ self.bbox.append(_bbox)
+ self.idx.append(_idx)
+
+ if (self.paddings > 0):
+ self.paddings = 0
+
+ def __len__(self):
+ return len(self.lm)
+
+
+def get_main_face_data(frame_landmarks, frame_bboxes, d_rate, max_paddings):
+ # post-process the extracted frame faces.
+ # create face identity database to track landmark motion.
+ face_dbs = []
+ num_frames = len(frame_landmarks)
+ for frame_idx, landmarks, bboxes in zip(range(num_frames), frame_landmarks, frame_bboxes):
+
+ if (
+ landmarks == None or len(landmarks) == 0 or
+ bboxes == None or len(bboxes) == 0
+ ):
+ for face in face_dbs:
+ face.pad()
+
+ else:
+ assert len(landmarks) == len(bboxes), "length of landmark and bbox in frame mismatch."
+ num_faces = len(landmarks)
+ landmarks = np.stack(landmarks)
+ bboxes = np.stack(bboxes)
+
+ matched_indices = {}
+
+ # find and connect with the closest face in the database.
+ for db_idx, db_face in enumerate(face_dbs):
+ # face landmark and bbox motion distance.
+ d = db_face.d_bbox(bboxes) + db_face.d_lm(landmarks)
+
+ # the motion continues if the landmark motion distance is lower than 100.
+ if (np.min(d) > db_face.face_size() * d_rate * 2):
+ continue
+ # get the closest face in the database.
+ closest_idx = np.argmin(d)
+ proximity = d[closest_idx]
+
+ if (
+ (not closest_idx in matched_indices) or
+ (matched_indices[closest_idx]["d"] > proximity)
+ ):
+ matched_indices[closest_idx] = dict(d=proximity, db_idx=db_idx)
+
+ # (hacky!) pad current frame in advance, in further process, tracked faces will reset the padding.
+ for db_face in face_dbs:
+ db_face.pad()
+
+ # finalize and update the database entity.
+ for face_idx, save_data in matched_indices.items():
+ face_dbs[save_data["db_idx"]].add(landmarks[face_idx], bboxes[face_idx], frame_idx)
+
+ # create new database entity for untracked landmarks.
+ for face_idx, landmark, bbox in zip(range(num_faces), landmarks, bboxes):
+ if face_idx in matched_indices:
+ continue
+ else:
+ face_dbs.append(FaceData(landmark, bbox, frame_idx))
+
+ # report only the most consistant face in the video.
+ main_face = sorted(face_dbs, key=lambda x: len(x), reverse=True)[0]
+
+ return main_face.lm, main_face.bbox, main_face.idx
+
+
+def save_video(
+ filename,
+ frames,
+ fps
+):
+ fourcc = cv2.VideoWriter_fourcc("F", "F", "V", "1")
+ writer = cv2.VideoWriter(filename, fourcc, fps, (frames.shape[2], frames.shape[1]))
+ for frame in frames:
+ writer.write(frame)
+ writer.release() # close the writer
+
+
+def affine_transform(
+ frame,
+ bboxes,
+ landmarks,
+ reference,
+ target_size,
+ stable_points=(28, 33, 36, 39, 42, 45, 48, 54),
+ interpolation=cv2.INTER_LINEAR,
+ border_mode=cv2.BORDER_CONSTANT,
+ border_value=0
+):
+ stable_reference = np.vstack([reference[x] for x in stable_points])
+ stable_reference[:, 0] *= (target_size / 256)
+ stable_reference[:, 1] *= (target_size / 256)
+
+ # Warp the face patch and the landmarks
+ transform = cv2.estimateAffinePartial2D(
+ np.vstack([landmarks[x] for x in stable_points]),
+ stable_reference, method=cv2.LMEDS
+ )[0]
+
+ transformed_frame = cv2.warpAffine(
+ frame,
+ transform,
+ dsize=(target_size, target_size),
+ flags=interpolation,
+ borderMode=border_mode,
+ borderValue=border_value
+ )
+ transformed_landmarks = np.matmul(
+ landmarks,
+ transform[:, :2].transpose()
+ ) + transform[:, 2].transpose()
+
+ transformed_bboxes = np.matmul(
+ bboxes,
+ transform[:, :2].transpose()
+ ) + transform[:, 2].transpose()
+
+ return transformed_frame, transformed_landmarks, transformed_bboxes
+
+
+def crop_driver(
+ img,
+ bboxes,
+ landmarks,
+ size,
+ start_idx,
+ stop_idx
+):
+ center_x, center_y = np.mean(landmarks[start_idx:stop_idx], axis=0)
+
+ if center_y - size < 0:
+ center_y = size + 1
+ elif (center_y + size) > img.shape[0]:
+ center_y = img.shape[0] - size - 1
+
+ if center_x - size < 0:
+ center_x = size + 1
+ elif (center_x + size) > img.shape[1]:
+ center_x = img.shape[1] - size - 1
+
+ uy, by = int(center_y - size), int(center_y + size)
+ lx, rx = int(center_x - size), int(center_x + size)
+ cutted_img = np.copy(img[uy:by, lx:rx])
+ cutted_landmarks = np.copy(landmarks) - [lx, uy]
+ cutted_bboxes = np.copy(bboxes) - [lx, uy]
+
+ return cutted_img, cutted_landmarks, cutted_bboxes
+
+
+def crop_patch(
+ frames,
+ landmarks,
+ bboxes,
+ indices,
+ reference,
+ window_margin,
+ start_idx,
+ stop_idx,
+ crop_size,
+ target_size,
+):
+ assert len(landmarks) == len(bboxes), f"length of landmarks and bboxes mismatch."
+
+ crop_frames = []
+ crop_bboxes = []
+ crop_landmarks = []
+
+ length = len(frames)
+
+ # preprocess for window margin
+ _landmarks = [None for _ in range(length)]
+ _bboxes = [None for _ in range(length)]
+ for i, idx in enumerate(indices):
+ _landmarks[idx] = landmarks[i]
+ _bboxes[idx] = bboxes[i]
+
+ for frame_idx in range(length):
+ # check landmark exists
+ if (not frame_idx in indices):
+ crop_frame = np.zeros((crop_size, crop_size, 3), dtype=np.uint8)
+ crop_landmark = None
+ crop_bbox = None
+ else:
+ frame = frames[frame_idx]
+ margin = min(window_margin // 2, frame_idx, length - 1 - frame_idx)
+
+ # smoothed landmarks
+ smoothed_landmarks = np.mean(
+ [
+ _landmarks[i]
+ for i in range(frame_idx - margin, frame_idx + margin + 1)
+ if (not _landmarks[i] is None)
+ ],
+ axis=0
+ )
+ smoothed_landmarks += (_landmarks[frame_idx].mean(axis=0) - smoothed_landmarks.mean(axis=0))
+ # smoothed bboxes
+ smoothed_bboxes = np.mean(
+ [
+ _bboxes[i]
+ for i in range(frame_idx - margin, frame_idx + margin + 1)
+ if (not _bboxes[i] is None)
+ ],
+ axis=0
+ )
+ smoothed_bboxes += (_bboxes[frame_idx].mean(axis=0) - smoothed_bboxes.mean(axis=0))
+ # affine transform
+ transformed_frame, transformed_landmarks, transformed_bboxes = affine_transform(
+ frame,
+ smoothed_bboxes,
+ smoothed_landmarks,
+ reference,
+ target_size=target_size
+ )
+ crop_frame, crop_landmark, crop_bbox = crop_driver(
+ transformed_frame,
+ transformed_bboxes,
+ transformed_landmarks,
+ crop_size // 2,
+ start_idx=start_idx,
+ stop_idx=stop_idx
+ )
+
+ assert crop_frame.shape[0] == crop_frame.shape[1] == crop_size, "crop size doesn't match."
+
+ crop_frames.append(crop_frame)
+ crop_landmarks.append(crop_landmark)
+ crop_bboxes.append(crop_bbox)
+
+ # convert to numpy array for better extensibility.
+ crop_frames = np.array(crop_frames)
+ crop_landmarks = crop_landmarks
+ crop_bboxes = crop_bboxes
+
+ return crop_frames, crop_landmarks, crop_bboxes
+
+
+def get_video_frames(video_path):
+ cap = cv2.VideoCapture(video_path)
+ fps = round(cap.get(cv2.CAP_PROP_FPS))
+ frames = []
+ while cap.isOpened():
+ ret, frame = cap.read()
+ if not ret:
+ break
+ frames.append(frame.copy())
+ cap.release()
+ return fps, frames
+
+
+def get_video_frame_data(fdata_path):
+ with open(fdata_path, "rb") as f:
+ frame_data = pickle.load(f)
+ frame_landmarks = [[] if frame is None else frame["landmarks"] for frame in frame_data]
+ frame_bboxes = [[] if frame is None else frame["bboxes"] for frame in frame_data]
+
+ assert len(frame_landmarks) == len(frame_bboxes), f"length of landmark and bbox mismatch."
+
+ _98_to_68_mapping = [
+ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24,
+ 26, 28, 30, 32, 33, 34, 35, 36, 37, 42, 43, 44,
+ 45, 46, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
+ 61, 63, 64, 65, 67, 68, 69, 71, 72, 73, 75, 76,
+ 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
+ 89, 90, 91, 92, 93, 94, 95
+ ]
+
+ frame_landmarks = [
+ [
+ (lm[_98_to_68_mapping] if len(lm) == 98 else lm)
+ for lm in landmarks
+ ]
+ for landmarks in frame_landmarks
+ ]
+
+ # assert len(frame_landmarks[0][0]) == 68, "landmark should be 68 points."
+
+ frame_bboxes = [
+ [
+ (
+ bbox.reshape((2, 2))
+ if len(bbox.shape) == 1 else
+ bbox
+ )
+ for bbox in bboxes
+ ]
+ for bboxes in frame_bboxes
+ ]
+
+ return frame_landmarks, frame_bboxes
+
+
+@dataclass
+class RunnerParams:
+ video_path: str
+ args: argparse.Namespace
+
+
+def runner(params: RunnerParams):
+ try:
+ args = params.args
+ video_path = params.video_path
+
+ rel_video_path = os.path.splitext(os.path.relpath(video_path, args.video_root))[0]
+ fdata_path = os.path.join(args.fdata_root, rel_video_path) + ".pickle"
+ crop_video_path = os.path.join(args.crop_root, args.video_dir, rel_video_path) + ".avi"
+ crop_fdata_path = os.path.join(args.crop_root, args.fdata_dir, rel_video_path) + ".pickle"
+
+ if (exists(f"{crop_video_path}") and exists(f"{crop_fdata_path}") and not args.replace):
+ return
+
+ fps, frames = get_video_frames(video_path)
+
+ frame_landmarks, frame_bboxes = get_video_frame_data(fdata_path)
+
+ assert len(frames) == len(frame_landmarks) == len(frame_bboxes)
+
+ landmarks, bboxes, indices = get_main_face_data(
+ frame_landmarks=frame_landmarks,
+ frame_bboxes=frame_bboxes,
+ d_rate=args.d_rate,
+ max_paddings=fps * args.max_pad_secs
+ )
+
+ if (len(landmarks) < len(frames) * args.min_crop_rate):
+ raise Exception("number of tracked landmarks below the minimum ratio of frames.")
+
+ crop_frames, crop_landmarks, crop_bboxes = crop_patch(
+ frames,
+ landmarks,
+ bboxes,
+ indices,
+ args.reference,
+ window_margin=args.window_margin,
+ start_idx=args.start_idx,
+ stop_idx=args.stop_idx,
+ crop_size=args.crop_size,
+ target_size=args.target_size
+ )
+
+ # save video
+ os.makedirs(os.path.dirname(crop_video_path), exist_ok=True)
+
+ save_video(crop_video_path, crop_frames, fps)
+
+ # save frame data
+ os.makedirs(os.path.dirname(crop_fdata_path), exist_ok=True)
+
+ with open(crop_fdata_path, "wb") as f:
+ assert crop_bboxes[0].shape == (2, 2)
+ pickle.dump(
+ [
+ dict(landmarks=[landmarks], bboxes=[bboxes])
+ for landmarks, bboxes in zip(crop_landmarks, crop_bboxes)
+ ],
+ f
+ )
+ except Exception as e:
+ print("Video Process Error:", video_path, e)
+
+
+def main(args=None):
+ args = load_args(args)
+ args.reference = np.load(args.mean_face)
+
+ args.video_root = os.path.join(args.root_dir, args.video_dir)
+ args.fdata_root = os.path.join(args.root_dir, args.fdata_dir)
+ args.crop_root = os.path.join(args.root_dir, args.crop_dir)
+
+ video_files = sorted(glob(os.path.join(args.video_root, args.glob_exp)))
+
+ if (args.workers == 0):
+ for video_path in tqdm(video_files):
+ runner(RunnerParams(args=args, video_path=video_path))
+
+ else:
+ with Pool(args.workers) as p:
+ for _ in tqdm(
+ p.imap_unordered(
+ runner,
+ [
+ RunnerParams(
+ args=args,
+ video_path=video_path
+ )
+ for video_path in video_files
+ ]
+ ),
+ total=len(video_files)
+ ):
+ continue
+
+
+if __name__ == "__main__":
+ main()
diff --git a/clean/video/dfd_fcg/src/preprocess/fetch_landmark_bbox.py b/clean/video/dfd_fcg/src/preprocess/fetch_landmark_bbox.py
new file mode 100644
index 0000000000000000000000000000000000000000..49202cf87d4bf3ead2abeae7d0e12691c81547eb
--- /dev/null
+++ b/clean/video/dfd_fcg/src/preprocess/fetch_landmark_bbox.py
@@ -0,0 +1,152 @@
+import os
+import cv2
+import math
+import torch
+import pickle
+import argparse
+import numpy as np
+from tqdm import tqdm
+from glob import glob
+import face_alignment
+
+
+def load_args(args):
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--root-dir", type=str, default="")
+ parser.add_argument("--video-dir", type=str, default="videos")
+ parser.add_argument("--fdata-dir", type=str, default="frame_data")
+ parser.add_argument("--glob-exp", type=str, default="*/*")
+ parser.add_argument("--split-num", type=int, default=1)
+ parser.add_argument("--part-num", type=int, default=1)
+ parser.add_argument("--batch", type=int, default=1)
+ parser.add_argument("--max-res", type=int, default=800)
+ args = parser.parse_args(args)
+
+ assert args.part_num > 0 and args.split_num > 0, "split and part value should be > 0"
+
+ args.part_num = args.part_num - 1
+
+ return args
+
+
+@torch.inference_mode()
+def landmark_extract(fn, org_path, batch_size, max_res):
+
+ cap_org = cv2.VideoCapture(org_path)
+
+ try:
+ width = cap_org.get(cv2.CAP_PROP_FRAME_WIDTH)
+ height = cap_org.get(cv2.CAP_PROP_FRAME_HEIGHT)
+ frames = []
+
+ # determine the scaling factor to shrink the size of input image(for efficiency).
+ if (max(height, width) > max_res):
+ scale = max_res / max(height, width)
+ else:
+ scale = 1
+
+ while (1):
+ ret_org, frame_org = cap_org.read()
+ if (not ret_org):
+ break
+ frame_org = cv2.cvtColor(frame_org, cv2.COLOR_BGR2RGB)
+ frame_org = cv2.resize(frame_org, None, fx=scale, fy=scale)
+ frames.append(frame_org)
+
+ frame_count = len(frames)
+ frame_faces = [None for _ in range(frame_count)]
+ batch_indices = []
+ batch_frames = []
+
+ for cnt_frame in range(frame_count):
+ batch_frames.append(frames[cnt_frame])
+ batch_indices.append(cnt_frame)
+
+ if (len(batch_frames) == batch_size or (cnt_frame == (frame_count - 1) and len(batch_frames) > 0)):
+
+ results = fn(torch.tensor(np.stack(batch_frames).transpose((0, 3, 1, 2))))
+ batch_size = len(results[0])
+
+ batch_landmarks = results[0]
+ batch_bboxes = results[2]
+
+ for index, frame_landmarks, frame_bboxes in zip(batch_indices, batch_landmarks, batch_bboxes):
+ if (len(frame_landmarks) > 0):
+ frame_landmarks = frame_landmarks.reshape(-1, 68, 2) / scale
+ frame_landmarks = [lm for lm in frame_landmarks]
+ frame_bboxes = [bbox[:-1] / scale for bbox in frame_bboxes]
+ frame_faces[index] = {
+ "landmarks": frame_landmarks,
+ "bboxes": frame_bboxes
+ }
+
+ batch_frames.clear()
+ batch_indices.clear()
+
+ return frame_faces
+
+ except Exception as e:
+ raise e
+
+ finally:
+ cap_org.release()
+
+
+def main(args=None):
+ # This file extract video landmarks from a given folder.
+ # In addition, the landmarks are tracked with landmarks from previous frames.
+ # By doing so, we expect to extract the most consistently appeared faces from a given video.
+ # Note that under 'pack' save mode, the extracted faces must match the length of the video.
+ # That's to say, if there exists a single frame without appearing faces in the video, the extract operation fails.
+
+ args = load_args(args=args)
+
+ model = face_alignment.FaceAlignment(
+ face_alignment.LandmarksType.TWO_D,
+ face_detector='sfd',
+ dtype=torch.float16, # float16 to boost efficiency.
+ flip_input=False,
+ device="cuda",
+ )
+
+ def driver(x): return model.get_landmarks_from_batch(x, return_bboxes=True)
+
+ if (not args.root_dir[-1] == "/"):
+ args.root_dir += "/"
+
+ video_files = sorted(glob(os.path.join(args.root_dir, args.video_dir, args.glob_exp)))
+ _, video_ext = os.path.splitext(video_files[0])
+
+ # splitting
+ split_size = math.ceil(len(video_files) / args.split_num)
+ video_files = video_files[args.part_num * split_size:(args.part_num + 1) * split_size]
+ n_videos = len(video_files)
+
+ print("{} videos in {}".format(n_videos, args.root_dir))
+ print("path sample:{}".format(video_files[0]))
+
+ cont = input(f"Processing Part {args.part_num+1}/{args.split_num}, Confirm?(y/n)")
+ if (not cont.lower() == "y"):
+ print("abort.")
+ return
+
+ for i in tqdm(range(n_videos)):
+ lm_path = video_files[i].replace(args.video_dir, args.fdata_dir).replace(video_ext, '.pickle')
+
+ if (os.path.exists(lm_path)):
+ continue
+
+ datas = landmark_extract(
+ fn=driver,
+ org_path=video_files[i],
+ batch_size=args.batch,
+ max_res=args.max_res
+ )
+
+ os.makedirs(os.path.split(lm_path)[0], exist_ok=True)
+ with open(lm_path, "wb") as f:
+ pickle.dump(datas, f)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/clean/video/dfd_fcg/src/preprocess/robustness/distortions.py b/clean/video/dfd_fcg/src/preprocess/robustness/distortions.py
new file mode 100644
index 0000000000000000000000000000000000000000..4a7faaf72a396593e3309266ec6e3bc0fb7f5c1b
--- /dev/null
+++ b/clean/video/dfd_fcg/src/preprocess/robustness/distortions.py
@@ -0,0 +1,92 @@
+import math
+import os
+import random
+
+import cv2
+import numpy as np
+
+
+def bgr2ycbcr(img_bgr):
+ img_bgr = img_bgr.astype(np.float32)
+ img_ycrcb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2YCR_CB)
+ img_ycbcr = img_ycrcb[:, :, (0, 2, 1)].astype(np.float32)
+ # to [16/255, 235/255]
+ img_ycbcr[:, :, 0] = (img_ycbcr[:, :, 0] * (235 - 16) + 16) / 255.0
+ # to [16/255, 240/255]
+ img_ycbcr[:, :, 1:] = (img_ycbcr[:, :, 1:] * (240 - 16) + 16) / 255.0
+
+ return img_ycbcr
+
+
+def ycbcr2bgr(img_ycbcr):
+ img_ycbcr = img_ycbcr.astype(np.float32)
+ # to [0, 1]
+ img_ycbcr[:, :, 0] = (img_ycbcr[:, :, 0] * 255.0 - 16) / (235 - 16)
+ # to [0, 1]
+ img_ycbcr[:, :, 1:] = (img_ycbcr[:, :, 1:] * 255.0 - 16) / (240 - 16)
+ img_ycrcb = img_ycbcr[:, :, (0, 2, 1)].astype(np.float32)
+ img_bgr = cv2.cvtColor(img_ycrcb, cv2.COLOR_YCR_CB2BGR)
+
+ return img_bgr
+
+
+def color_saturation(img, param):
+ ycbcr = bgr2ycbcr(img)
+ ycbcr[:, :, 1] = 0.5 + (ycbcr[:, :, 1] - 0.5) * param
+ ycbcr[:, :, 2] = 0.5 + (ycbcr[:, :, 2] - 0.5) * param
+ img = ycbcr2bgr(ycbcr).astype(np.uint8)
+
+ return img
+
+
+def color_contrast(img, param):
+ img = img.astype(np.float32) * param
+ img = img.astype(np.uint8)
+
+ return img
+
+
+def block_wise(img, param):
+ width = 8
+ block = np.ones((width, width, 3)).astype(int) * 128
+ param = min(img.shape[0], img.shape[1]) // 256 * param
+ for i in range(param):
+ r_w = random.randint(0, img.shape[1] - 1 - width)
+ r_h = random.randint(0, img.shape[0] - 1 - width)
+ img[r_h:r_h + width, r_w:r_w + width, :] = block
+
+ return img
+
+
+def gaussian_noise_color(img, param):
+ ycbcr = bgr2ycbcr(img) / 255
+ size_a = ycbcr.shape
+ b = (ycbcr + math.sqrt(param) *
+ np.random.randn(size_a[0], size_a[1], size_a[2])) * 255
+ b = ycbcr2bgr(b)
+ img = np.clip(b, 0, 255).astype(np.uint8)
+
+ return img
+
+
+def gaussian_blur(img, param):
+ img = cv2.GaussianBlur(img, (param, param), param * 1.0 / 6)
+
+ return img
+
+
+def jpeg_compression(img, param):
+ h, w, _ = img.shape
+ s_h = h // param
+ s_w = w // param
+ img = cv2.resize(img, (s_w, s_h))
+ img = cv2.resize(img, (w, h))
+
+ return img
+
+
+def video_compression(vid_in, vid_out, param):
+ cmd = f'ffmpeg -i {vid_in} -crf {param} -y {vid_out}'
+ os.system(cmd)
+
+ return
diff --git a/clean/video/dfd_fcg/src/preprocess/robustness/phase1_apply_all_to_videos.py b/clean/video/dfd_fcg/src/preprocess/robustness/phase1_apply_all_to_videos.py
new file mode 100644
index 0000000000000000000000000000000000000000..58231d6beb804c946cb7f09e65806fc7607fff87
--- /dev/null
+++ b/clean/video/dfd_fcg/src/preprocess/robustness/phase1_apply_all_to_videos.py
@@ -0,0 +1,240 @@
+import os
+import math
+import argparse
+from multiprocessing import Process, Pool
+from glob import glob
+
+
+import argparse
+import copy
+import os
+import random
+
+import cv2
+from tqdm import tqdm
+from dataclasses import dataclass
+from .distortions import (block_wise, color_contrast, color_saturation,
+ gaussian_blur, gaussian_noise_color, jpeg_compression,
+ video_compression)
+
+
+def parse_args():
+ parser = argparse.ArgumentParser(description='Add a distortion to video.')
+ parser.add_argument(
+ '--dts-root',
+ type=str,
+ default="/scratch1/users/od/FaceForensicC23/"
+ )
+ parser.add_argument(
+ '--vid-dir',
+ type=str,
+ default="videos"
+ )
+ parser.add_argument(
+ '--glob-exp',
+ type=str,
+ default="*/*.mp4"
+ )
+
+ parser.add_argument(
+ '--rob-dir',
+ type=str,
+ default="robustness"
+ )
+
+ parser.add_argument(
+ '--workers',
+ type=int,
+ default=1
+ )
+ parser.add_argument(
+ '--split',
+ type=int,
+ default=1
+ )
+ parser.add_argument(
+ '--part',
+ type=int,
+ default=1
+ )
+
+ args = parser.parse_args()
+
+ return args
+
+
+def get_distortion_parameter(type, level):
+ param_dict = dict() # a dict of list
+ param_dict['CS'] = [0.4, 0.3, 0.2, 0.1, 0.0] # smaller, worse
+ param_dict['CC'] = [0.85, 0.725, 0.6, 0.475, 0.35] # smaller, worse
+ param_dict['BW'] = [16, 32, 48, 64, 80] # larger, worse
+ param_dict['GNC'] = [0.001, 0.002, 0.005, 0.01, 0.05] # larger, worse
+ param_dict['GB'] = [7, 9, 13, 17, 21] # larger, worse
+ param_dict['JPEG'] = [2, 3, 4, 5, 6] # larger, worse
+ param_dict['VC'] = [30, 32, 35, 38, 40] # larger, worse
+
+ # level starts from 1, list starts from 0
+ return param_dict[type][level - 1]
+
+
+def get_distortion_function(type):
+ func_dict = dict() # a dict of function
+ func_dict['CS'] = color_saturation
+ func_dict['CC'] = color_contrast
+ func_dict['BW'] = block_wise
+ func_dict['GNC'] = gaussian_noise_color
+ func_dict['GB'] = gaussian_blur
+ func_dict['JPEG'] = jpeg_compression
+ func_dict['VC'] = video_compression
+
+ return func_dict[type]
+
+
+def apply_distortion_log(type, level):
+ if type == 'CS':
+ print(f'Apply level-{level} color saturation change distortion...')
+ elif type == 'CC':
+ print(f'Apply level-{level} color contrast change distortion...')
+ elif type == 'BW':
+ print(f'Apply level-{level} local block-wise distortion...')
+ elif type == 'GNC':
+ print(f'Apply level-{level} white Gaussian noise in color components '
+ 'distortion...')
+ elif type == 'GB':
+ print(f'Apply level-{level} Gaussian blur distortion...')
+ elif type == 'JPEG':
+ print(f'Apply level-{level} JPEG compression distortion...')
+ elif type == 'VC':
+ print(f'Apply level-{level} video compression distortion...')
+
+
+@dataclass
+class Params:
+ src: str
+ dts_root: str
+ video_root: str
+ rob_dir: str
+
+
+def main(params: Params):
+ src, dts_root, video_root, rob_dir = params.src, params.dts_root, params.video_root, params.rob_dir
+
+ type_list = ['CS', 'CC', 'BW', 'GNC', 'GB', 'JPEG', 'VC']
+ level_list = [1, 2, 3, 4, 5]
+
+ if ("FSh" in src):
+ return
+
+ frame_list = None
+
+ for type in type_list:
+ for level in level_list:
+ tgt = os.path.join(
+ dts_root,
+ rob_dir,
+ f"{type}/{level}",
+ os.path.relpath(src, video_root)
+ )
+
+ if (os.path.exists(tgt)):
+ continue
+
+ if (frame_list is None):
+ # extract frames
+ vid = cv2.VideoCapture(src)
+ fps = vid.get(cv2.CAP_PROP_FPS)
+ fourcc = int(vid.get(cv2.CAP_PROP_FOURCC))
+ w = int(vid.get(cv2.CAP_PROP_FRAME_WIDTH))
+ h = int(vid.get(cv2.CAP_PROP_FRAME_HEIGHT))
+ frame_count = int(vid.get(cv2.CAP_PROP_FRAME_COUNT))
+ print(f'Input video fps: {fps}')
+ print(f'Input video fourcc: {fourcc}')
+ print(f'Input video frame size: {w} * {h}')
+ print(f'Input video frame count: {frame_count}')
+ print('Extracting frames...')
+ frame_list = []
+ while True:
+ success, frame = vid.read()
+ if not success:
+ break
+ frame_list.append(frame)
+ vid.release()
+ assert len(frame_list) == frame_count
+
+ # create output root
+ root = os.path.split(tgt)[0]
+ root = '.' if root == '' else root
+ os.makedirs(root, exist_ok=True)
+
+ # get distortion parameter
+ dist_param = get_distortion_parameter(type, level)
+
+ # get distortion function
+ dist_function = get_distortion_function(type)
+
+ # apply distortion
+ if type == 'VC':
+ apply_distortion_log(type, level)
+ dist_function(src, tgt, dist_param)
+ else:
+
+ # add distortion to the frame and write to the new video at 'tgt'
+ writer = cv2.VideoWriter(
+ f'{tgt[:-4]}_tmp.avi',
+ cv2.VideoWriter_fourcc('X', 'V', 'I', 'D'),
+ fps,
+ (w, h)
+ )
+
+ apply_distortion_log(type, level)
+
+ for frame in tqdm(frame_list):
+ new_frame = dist_function(frame.copy(), dist_param)
+ writer.write(new_frame)
+
+ writer.release()
+
+ cmd = f'ffmpeg -hide_banner -loglevel error -i {tgt[:-4]}_tmp.avi -y {tgt}'
+ os.system(cmd)
+
+ if os.path.exists(f'{tgt[:-4]}_tmp.avi'):
+ os.remove(f'{tgt[:-4]}_tmp.avi')
+
+ print('Finished.')
+
+
+if __name__ == "__main__":
+ args = parse_args()
+
+ dts_root = args.dts_root
+ vid_dir = args.vid_dir
+ rob_dir = args.rob_dir
+
+ video_root = os.path.join(dts_root, vid_dir)
+ glob_exp = args.glob_exp
+
+ videos = sorted(glob(os.path.join(video_root, glob_exp)))
+
+ part_vids = math.ceil(len(videos) / args.split)
+ start = (args.part - 1) * part_vids
+ end = start + part_vids
+
+ videos = videos[start:end]
+
+ worker_vids = math.ceil(len(videos) / args.workers)
+
+ with Pool(args.workers) as p:
+ for _ in tqdm(
+ p.imap_unordered(main, [
+ Params(
+ src=src,
+ dts_root=dts_root,
+ video_root=video_root,
+ rob_dir=rob_dir
+ )
+ for src in videos
+ ])
+ ):
+ continue
+
+ print("done")
diff --git a/clean/video/dfd_fcg/src/preprocess/robustness/phase1_check.py b/clean/video/dfd_fcg/src/preprocess/robustness/phase1_check.py
new file mode 100644
index 0000000000000000000000000000000000000000..bce6c39168a64803abe0544c12cd790f3cecba2a
--- /dev/null
+++ b/clean/video/dfd_fcg/src/preprocess/robustness/phase1_check.py
@@ -0,0 +1,49 @@
+import cv2
+from glob import glob
+from tqdm import tqdm
+from multiprocessing import Pool
+
+# VIDEO_DIR = "/scratch1/users/od/CelebDF/Real/videos/*.mp4"
+VIDEO_DIR = "/scratch1/users/od/FaceForensicC23/videos/*/*.mp4"
+ROB_DIR = "robustness"
+
+videos = glob(VIDEO_DIR)
+
+print("Total videos:", len(videos))
+
+type_list = ['CS', 'CC', 'BW', 'GNC', 'GB', 'JPEG', 'VC']
+level_list = [1, 2, 3, 4, 5]
+
+
+def runner(video):
+ unmatch = []
+
+ cap = cv2.VideoCapture(video)
+ frames = cap.get(cv2.CAP_PROP_FRAME_COUNT)
+ cap.release()
+ for t in type_list:
+ for l in level_list:
+ rob_video = video.replace("videos", f"robustness/{t}/{l}")
+ cap = cv2.VideoCapture(rob_video)
+ if (not frames == cap.get(cv2.CAP_PROP_FRAME_COUNT)):
+ unmatch.append(rob_video)
+ cap.release()
+
+ return unmatch
+
+
+results = []
+with Pool(10) as p:
+
+ for result in tqdm(
+ p.imap_unordered(
+ runner,
+ videos
+ ),
+ total=len(videos)
+ ):
+ results.extend(result)
+
+
+for i in results:
+ print(i)
diff --git a/clean/video/dfd_fcg/src/preprocess/robustness/phase2_face_crop_all_videos.py b/clean/video/dfd_fcg/src/preprocess/robustness/phase2_face_crop_all_videos.py
new file mode 100644
index 0000000000000000000000000000000000000000..a394dfbcc6ccbac79948b51e4c3c10aeb577ba69
--- /dev/null
+++ b/clean/video/dfd_fcg/src/preprocess/robustness/phase2_face_crop_all_videos.py
@@ -0,0 +1,88 @@
+import os
+import argparse
+from glob import glob
+from src.preprocess.crop_main_face import main as crop_entrance
+
+
+def parse_args():
+ parser = argparse.ArgumentParser(description='Add a distortion to video.')
+
+ parser.add_argument("action", type=str)
+
+ parser.add_argument(
+ '--dts-root',
+ type=str,
+ default="/scratch1/users/od/FaceForensicC23/"
+ )
+
+ parser.add_argument(
+ '--glob-exp',
+ type=str,
+ default="*/*/*/*.mp4"
+ )
+
+ parser.add_argument(
+ '--rob-dir',
+ type=str,
+ default="robustness"
+ )
+
+ parser.add_argument(
+ '--fd-dir',
+ type=str,
+ default="frame_data"
+ )
+
+ parser.add_argument(
+ '--crop-dir',
+ type=str,
+ default="cropped_robust"
+ )
+
+ parser.add_argument(
+ '--mean-face',
+ type=str,
+ default="./misc/20words_mean_face.npy"
+ )
+
+ parser.add_argument(
+ '--workers',
+ type=int,
+ default=1
+ )
+
+ args = parser.parse_args()
+
+ return args
+
+
+if __name__ == "__main__":
+ args = parse_args()
+ rob_root = os.path.join(args.dts_root, args.rob_dir)
+ fd_root = os.path.join(args.dts_root, args.fd_dir)
+
+ type_list = ['CS', 'CC', 'BW', 'GNC', 'GB', 'JPEG', 'VC']
+ level_list = ['1', '2', '3', '4', '5']
+
+ if args.action == "setup":
+ for t in type_list:
+ for l in level_list:
+ p1 = os.path.join(fd_root)
+ p2 = os.path.join(fd_root, t)
+ os.makedirs(p2, exist_ok=True)
+ p2 = os.path.join(p2, l)
+ os.system(f"ln -s {p1} {p2}")
+ elif args.action == "run":
+ crop_entrance(
+ [
+ "--root-dir", args.dts_root,
+ "--video-dir", args.rob_dir,
+ "--mean-face", args.mean_face,
+ "--glob-exp", args.glob_exp,
+ "--crop-dir", args.crop_dir
+ ]
+ )
+ elif args.action == "clean":
+ for t in type_list:
+ p = os.path.join(fd_root, t)
+ os.system(f"rm -rf {p}")
diff --git a/clean/video/dfd_fcg/src/preprocess/robustness/readme.md b/clean/video/dfd_fcg/src/preprocess/robustness/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..f3fd750f88829a659868715b89c9083072231612
--- /dev/null
+++ b/clean/video/dfd_fcg/src/preprocess/robustness/readme.md
@@ -0,0 +1 @@
+We borrow two modules from [DeeperForensics](https://github.com/EndlessSora/DeeperForensics-1.0/tree/master/perturbation) to apply all perturbations on the video dataset, please refer to the repo for more detail about the distortions and their configurations.
\ No newline at end of file
diff --git a/clean/video/dfd_fcg/src/preprocess/show_frame_landmark_bbox.py b/clean/video/dfd_fcg/src/preprocess/show_frame_landmark_bbox.py
new file mode 100644
index 0000000000000000000000000000000000000000..b024ea585adea7fd25c7753991ac54e40e682c41
--- /dev/null
+++ b/clean/video/dfd_fcg/src/preprocess/show_frame_landmark_bbox.py
@@ -0,0 +1,47 @@
+# %%
+import cv2
+import pickle
+import matplotlib.pyplot as plt
+from src.preprocess.crop_main_face import get_video_frame_data, get_video_frames
+
+
+def get_video_frames(video_path):
+ cap = cv2.VideoCapture(video_path)
+ fps = round(cap.get(cv2.CAP_PROP_FPS))
+ frames = []
+ while cap.isOpened():
+ ret, frame = cap.read()
+ if not ret:
+ break
+ frames.append(frame.copy())
+ cap.release()
+ return fps, frames
+
+
+def get_video_frame_data(fdata_path):
+ with open(fdata_path, "rb") as f:
+ frame_data = pickle.load(f)
+ frame_landmarks = [frame["landmarks"] if not frame is None else [] for frame in frame_data]
+ frame_bboxes = [frame["bboxes"] if not frame is None else [] for frame in frame_data]
+
+ assert len(frame_landmarks) == len(frame_bboxes)
+
+ if (len(frame_bboxes[0][0].shape) == 1):
+ frame_bboxes = [[bbox.reshape((2, 2)) for bbox in bboxes]for bboxes in frame_bboxes]
+
+ return frame_landmarks, frame_bboxes
+
+
+video_path = "/home/od/stock/FaceForensicC23/videos/real/950.mp4"
+fdata_path = "/home/od/stock/FaceForensicC23/frame_data/real/950.pickle"
+
+fps, frames = get_video_frames(video_path)
+frame_landmarks, frame_bboxes = get_video_frame_data(fdata_path)
+
+import random
+
+idx = random.randrange(0, len(frames))
+plt.imshow(cv2.cvtColor(frames[idx], cv2.COLOR_BGR2RGB))
+for lm, bbox in zip(frame_landmarks[idx], frame_bboxes[idx]):
+ plt.scatter(lm[:, 0], lm[:, 1], s=1, c="r")
+ plt.scatter(bbox[:, 0], bbox[:, 1], s=1, c="g")
diff --git a/clean/video/dfd_fcg/src/utility/builtin.py b/clean/video/dfd_fcg/src/utility/builtin.py
new file mode 100644
index 0000000000000000000000000000000000000000..2afe537d7ed639b7e9374e5cdfa55b626e2be5a0
--- /dev/null
+++ b/clean/video/dfd_fcg/src/utility/builtin.py
@@ -0,0 +1,95 @@
+import os
+import torch
+import lightning as pl
+
+from typing import Optional
+from lightning.fabric.utilities.types import _PATH
+from lightning.pytorch.trainer.trainer import Trainer
+from lightning.pytorch.callbacks import ModelCheckpoint
+from lightning.pytorch.loggers.tensorboard import TensorBoardLogger
+from lightning.pytorch.cli import LightningCLI, SaveConfigCallback
+from lightning.pytorch.callbacks import EarlyStopping, LearningRateMonitor, RichProgressBar
+
+
+class ODLightningCLI(LightningCLI):
+ def add_arguments_to_parser(self, parser):
+ parser.add_lightning_class_args(EarlyStopping, "early_stop")
+ parser.set_defaults(
+ {
+ "early_stop.patience": 10,
+ }
+ )
+ parser.add_lightning_class_args(ODModelCheckpoint, "checkpoint")
+ parser.set_defaults(
+ {
+ 'checkpoint.save_last': True,
+ 'checkpoint.save_top_k': 1,
+ }
+ )
+
+ parser.add_lightning_class_args(LearningRateMonitor, "lr_monitor")
+ parser.set_defaults(
+ {
+ 'lr_monitor.log_momentum': True,
+ 'lr_monitor.logging_interval': 'step'
+ }
+ )
+
+ parser.add_lightning_class_args(RichProgressBar, "progress_bar")
+
+ parser.add_optimizer_args(torch.optim.AdamW)
+ parser.add_lr_scheduler_args(torch.optim.lr_scheduler.LinearLR)
+
+ parser.add_argument("--notes", default="")
+ parser.add_argument("--ckpt_path", default=None)
+ parser.add_argument("--ckpt_mode", default="cont")
+
+
+class ODTrainer(Trainer):
+ # rewrite the log_dir property to sync with logger configurations.
+ @property
+ def log_dir(self) -> Optional[str]:
+ """The directory for the current experiment. Use this to save images to, etc...
+
+ .. note:: You must call this on all processes. Failing to do so will cause your program to stall forever.
+
+ .. code-block:: python
+
+ def training_step(self, batch, batch_idx):
+ img = ...
+ save_img(img, self.trainer.log_dir)
+ """
+ if len(self.loggers) > 0:
+ if not isinstance(self.loggers[0], TensorBoardLogger):
+ dirpath = self.loggers[0].save_dir
+ else:
+ dirpath = self.loggers[0].log_dir
+ name = self.loggers[0].name
+ version = self.loggers[0].version
+ version = version if isinstance(version, str) else f"version_{version}"
+ dirpath = os.path.join(dirpath, str(name), version)
+ else:
+ dirpath = self.default_root_dir
+
+ dirpath = self.strategy.broadcast(dirpath)
+ return dirpath
+
+
+class ODModelCheckpoint(ModelCheckpoint):
+ # force overwrite the name mangling for checkpoint directory resolution to sync with the trainer's log directory.
+ def _ModelCheckpoint__resolve_ckpt_dir(self, trainer: "pl.Trainer") -> _PATH:
+ """Determines model checkpoint save directory at runtime. Reference attributes from the trainer's logger to
+ determine where to save checkpoints. The path for saving weights is set in this priority:
+
+ 1. The ``ModelCheckpoint``'s ``dirpath`` if passed in
+ 2. The ``Logger``'s ``log_dir`` if the trainer has loggers
+ 3. The ``Trainer``'s ``default_root_dir`` if the trainer has no loggers
+
+ The path gets extended with subdirectory "checkpoints".
+
+ """
+ if self.dirpath is not None:
+ # short circuit if dirpath was passed to ModelCheckpoint
+ return self.dirpath
+
+ return os.path.join(trainer.log_dir, "checkpoints")
diff --git a/clean/video/dfd_fcg/src/utility/loss.py b/clean/video/dfd_fcg/src/utility/loss.py
new file mode 100644
index 0000000000000000000000000000000000000000..8c1f94755ee452ecedf7dd8c842fa21004272d62
--- /dev/null
+++ b/clean/video/dfd_fcg/src/utility/loss.py
@@ -0,0 +1,33 @@
+import torch
+
+
+def focal_loss(input, target, gamma=2, weight=None):
+ # Code based on: https://github.com/clcarwin/focal_loss_pytorch/blob/master/focalloss.py
+ assert len(input.shape) == 2
+ assert len(target.shape) == 1
+ # input.shape = N,C
+ # target.shape = N
+ target = target.unsqueeze(1)
+
+ logpt = torch.log_softmax(input, dim=-1)
+ logpt = torch.clamp(logpt, max=-0.01, min=-5)
+ logpt = logpt.gather(1, target)
+ logpt = logpt.view(-1)
+ pt = torch.tensor(logpt.data.exp())
+
+ if (not weight is None):
+ # target.shape = N, 1
+ weight = torch.tensor(
+ weight,
+ device=input.device,
+ dtype=input.dtype
+ )
+ at = weight.gather(0, target.data.view(-1))
+ else:
+ at = 1
+
+ logpt = logpt * at
+
+ loss = -1 * (1 - pt)**gamma * logpt
+
+ return loss
diff --git a/clean/video/dfd_fcg/src/utility/visualize.py b/clean/video/dfd_fcg/src/utility/visualize.py
new file mode 100644
index 0000000000000000000000000000000000000000..0de2259c079c6c017cc7686208a125c79a2e41c9
--- /dev/null
+++ b/clean/video/dfd_fcg/src/utility/visualize.py
@@ -0,0 +1,23 @@
+from os import path, makedirs
+import matplotlib.pyplot as plt
+
+
+def dataset_entity_visualize(entity_data, normalized=False, unit=2, save=True, base_dir="./misc/extern/test/", save_prefix=""):
+ if save:
+ makedirs(base_dir, exist_ok=True)
+ clips = entity_data['clips']
+ idx = entity_data['idx']
+ df_type = entity_data['df_type']
+ vid_path = entity_data['vid_path']
+ num_clips, num_frames = clips.shape[:2]
+ plt.figure(figsize=(unit * num_frames * 0.9, unit * num_clips), layout="constrained")
+ plt.suptitle(f"#{idx},{df_type}\n{vid_path}", fontsize=unit * 9)
+ for i, clip in enumerate(clips):
+ plt.subplot(num_clips, 1, i + 1)
+ plt.gca().axis('off')
+ plt.imshow(clip.permute(2, 0, 3, 1).flatten(1, 2).numpy())
+ if save:
+ plt.savefig(path.join(base_dir, f"{save_prefix}{idx}.jpg"))
+ else:
+ plt.show()
+ plt.close()
diff --git a/clean/video/fakestormer/LICENSE b/clean/video/fakestormer/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..a251c2be404e71aadcf03faaf2310ae89d7f7f9c
--- /dev/null
+++ b/clean/video/fakestormer/LICENSE
@@ -0,0 +1,14 @@
+SnT academic license
+(based on the MIT license with academic limitations)
+
+Copyright 2025 University of Luxembourg
+
+Permission is hereby granted, free of charge, to any academic and research institution and researcher obtaining a copy of this software, all derivative works and associated documentation files (the “Software”), to deal in the Software for academic research and development, testing, validation and academic or scientific research purposes only, including without limitation the rights to use, copy, modify, merge, and/or publish copies of the Software, and to permit persons to whom the Software are furnished to do so for such purposes only, subject to the following conditions:
+
+All copies or substantial portions of the Software shall include the above copyright notice and this permission notice.
+
+All copies of the Software shall be distributed under the terms of this license only.
+
+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Any other use of the Software requires a separate license agreement. Should you be interested in making other uses of the Software, please send an email to snt-tto@uni.lu.
diff --git a/clean/video/fakestormer/NOTICE b/clean/video/fakestormer/NOTICE
new file mode 100644
index 0000000000000000000000000000000000000000..0565e669ae2d8594c7fa898d23e24070755d466c
--- /dev/null
+++ b/clean/video/fakestormer/NOTICE
@@ -0,0 +1,8 @@
+FakeSTormer is © 2024 - 2025 University of Luxembourg
+
+Authors:
+- Dat NGUYEN
+- Marcella ASTRID
+- Anis KACEM
+- Enjie GHORBEL
+- Djamila AOUADA
diff --git a/clean/video/fakestormer/README.md b/clean/video/fakestormer/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..060383b0db8c6e938a49a5d518ba4acf019b2548
--- /dev/null
+++ b/clean/video/fakestormer/README.md
@@ -0,0 +1,187 @@
+# [ICCV2025] [FakeSTormer] Vulnerability-Aware Spatio-Temporal Learning for Generalizable Deepfake Video Detection
+
+
+This is an official implementation of FakeSTormer! [[📜Paper](https://openaccess.thecvf.com/content/ICCV2025/papers/Nguyen_Vulnerability-Aware_Spatio-Temporal_Learning_for_Generalizable_Deepfake_Video_Detection_ICCV_2025_paper.pdf)]
+
+
+## Updates
+- [x] 26/11/2025:*Official release of code (v1) and pretrained weights 🌈.*
+- [x] 08/07/2025: *First version pre-released for this open source code 🌱.*
+- [x] 26/06/2025: *FakeSTormer has been accepted to ICCV2025 🎉.*
+
+
+## Abstract
+Detecting deepfake videos is highly challenging given the complexity of characterizing spatio-temporal artifacts. Most existing methods rely on binary classifiers trained using real and fake image sequences, therefore hindering their generalization capabilities to unseen generation methods. Moreover, with the constant progress in generative Artificial Intelligence (AI), deepfake artifacts are becoming imperceptible at both the spatial and the temporal levels, making them extremely difficult to capture. To address these issues, we propose a fine-grained deepfake video detection approach called FakeSTormer that enforces the modeling of subtle spatio-temporal inconsistencies while avoiding overfitting. Specifically, we introduce a multi-task learning framework that incorporates two auxiliary branches for explicitly attending artifact-prone spatial and temporal regions. Additionally, we propose a video-level data synthesis strategy that generates pseudo-fake videos with subtle spatio-temporal artifacts, providing high-quality samples and hand-free annotations for our additional branches. Extensive experiments on several challenging benchmarks demonstrate the superiority of our approach compared to recent state-of-the-art methods.
+
+
+## Main Results
+Results on 6 datasets ([CDF2](https://github.com/yuezunli/celeb-deepfakeforensics), [DFW](https://github.com/deepfakeinthewild/deepfake-in-the-wild), [DFD](https://blog.research.google/2019/09/contributing-data-to-deepfake-detection.html), [DFDC, DFDCP](https://ai.meta.com/datasets/dfdc/), and [DiffSwap](https://openaccess.thecvf.com/content/CVPR2023/papers/Zhao_DiffSwap_High-Fidelity_and_Controllable_Face_Swapping_via_3D-Aware_Masked_Diffusion_CVPR_2023_paper.pdf)) under cross-dataset evaluation setting reported by AUC (%) at video-level.
+
+| | CDF2 | DFW | DFD | DFDC | DFDCP | DiffSwap |
+|--|--------|------------|------------|------------|---------|-----------|
+|||||||
+
+
+## Recommended Environment
+*For experimental purposes, we encourage the installation of the following libraries. Both Conda or Python virtual env should work.*
+
+* CUDA: 11.4
+* [Python](https://www.python.org/): >= 3.8.x
+* [PyTorch](https://pytorch.org/get-started/previous-versions/): 1.8.0
+* [TensorboardX](https://github.com/lanpa/tensorboardX): 2.5.1
+* [ImgAug](https://github.com/aleju/imgaug): 0.4.0
+* [Scikit-image](https://scikit-image.org/): 0.17.2
+* [Torchvision](https://pytorch.org/vision/stable/index.html): 0.9.0
+* [Albumentations](https://albumentations.ai/): 1.1.0
+* [mmcv](https://github.com/open-mmlab/mmcv): 1.6.1
+* [natsort](https://pypi.org/project/natsort/): 8.4.0
+
+
+
+## Pre-trained Models
+* 📌 *The pre-trained weights of FakeSTormer can be found [here](https://www.dropbox.com/scl/fo/elk2szqf0du4l6zm5job9/AAdVmNH--6ywHBZGNQJlR5o?rlkey=j8xesf2fu4ahxdw99w5ndrkb2&st=fe6drzpx&dl=0)*
+
+
+## Docker Build (Optional)
+*We further provide an optional Docker file that can be used to build a working env with Docker. More detailed steps can be found [here](dockerfiles/README.md).*
+
+1. Install docker to the system (skip the step if docker has already been installed):
+ ```shell
+ sudo apt install docker
+ ```
+2. To start your docker environment, please go to the folder **dockerfiles**:
+ ```shell
+ cd dockerfiles
+ ```
+3. Create a docker image (you can put any name you want):
+ ```shell
+ docker build --tag 'fakestormer' .
+ ```
+
+
+## Quickstart
+1. **Preparation**
+
+ 1. ***Prepare environment***
+
+ Installing main packages as the recommended environment. *Note that we recommend building mmcv from source as below.*
+ > git clone https://github.com/open-mmlab/mmcv.git \
+ cd mmcv \
+ git checkout v1.6.1 \
+ MMCV_WITH_OPS=1 pip install -e .
+
+ 2. ***Prepare dataset***
+
+ 1. Downloading [FF++](https://github.com/ondyari/FaceForensics) *Original* dataset for training data preparation. Following the original split convention, it is firstly used to randomly extract frames and facial crops:
+ ```
+ python package_utils/images_crop.py -d {dataset} \
+ -c {compression} \
+ -n {num_frames} \
+ -t {task}
+ ```
+ (*This script can also be utilized for cropping faces in other datasets such as [CDF2](https://github.com/yuezunli/celeb-deepfakeforensics), [DFD](https://blog.research.google/2019/09/contributing-data-to-deepfake-detection.html), [DFDCP, DFDC](https://ai.meta.com/datasets/dfdc/) for cross-evaluation test. You do not need to run crop for [DFW](https://github.com/deepfakeinthewild/deepfake-in-the-wild) as the data is already preprocessed*).
+
+ | Parameter | Value | Definition |
+ | --- | --- | --- |
+ | -d | Subfolder in each dataset. For example: *['Face2Face','Deepfakes','FaceSwap','NeuralTextures', ...]*| You can use one of those datasets.|
+ | -c | *['raw','c23','c40']*| You can use one of those compressions|
+ | -n | *256* | Number of frames (*default* 32 for val/test and 256 for train) |
+ | -t | *['train', 'val', 'test']* | Default train|
+
+ These faces cropped are saved for online pseudo-fake generation in the training process, following the data structure below:
+
+ ```
+ ROOT = '/data/deepfake_cluster/datasets_df'
+ └── Celeb-DFv2
+ └──...
+ └── FF++
+ └── c0
+ └── c23
+ ├── test
+ │ └── videos
+ │ └── Deepfakes
+ | ├── 000_003
+ | ├── 044_945
+ | ├── 138_142
+ | ├── ...
+ │ ├── Face2Face
+ │ ├── FaceSwap
+ │ ├── NeuralTextures
+ │ └── original
+ | └── frames
+ ├── train
+ │ └── videos
+ │ └── aligned
+ | ├── 001
+ | ├── 002
+ | ├── ...
+ │ └── original
+ | ├── 001
+ | ├── 002
+ | ├── ...
+ | └── frames
+ └── val
+ └── videos
+ ├── aligned
+ └── original
+ └── frames
+ └── c40
+ ```
+
+ 2. Downloading **Dlib** [[81]](https://github.com/codeniko/shape_predictor_81_face_landmarks) facial landmarks detector pretrained and place into ```/pretrained/``` for *SBI* synthesis.
+
+ 3. Landmarks detection. After completing the following script running, a file that stores metadata information of the data is saved at ```processed_data/c23/{SPLIT}_FaceForensics_videos_.json```.
+ ```
+ python package_utils/geo_landmarks_extraction.py \
+ --config configs/data_preprocessing_c23.yaml \
+ --extract_landmarks
+ ```
+
+2. **Training script**
+
+ We offer a number of config files for different compression levels of training data. For *c23*, opening ```configs/temporal/FakeSTormer_base_c23.yaml```, please make sure you set ```TRAIN: True``` and ```FROM_FILE: True``` and run:
+ ```
+ .scripts/fakestormer_sbi.sh
+ ```
+
+ Otherwise, with *[c0, c40]*, the config file is ```configs/temporal/FakeSTormer_base_[c0, c40].yaml```. You can also find other configs for other network architectures in the ```configs/``` folder.
+
+
+3. **Testing script**
+
+ Opening ```configs/temporal/FakeSTormer_base_c23.yaml```, with ```subtask: eval``` in the *test* section, we support evaluation mode, please turn off ```TRAIN: False``` and ```FROM_FILE: False``` and run:
+ ```
+ .scripts/test_fakestormer.sh
+ ```
+ For others (.e.g., data compression levels, network architectures), please change the path of the corresponding config file.
+
+ > ⚠️ *Please make sure you set the correct path to your downloaded pre-trained weights in the config files.*
+
+ > ℹ️ *Flip test can be used by setting ```flip_test: True```*
+
+ > ℹ️ *The mode for single video inference is also provided, please set ```sub_task: test_vid``` and pass a video path as an argument in test.py*
+
+
+## Contact
+Please contact dat.nguyen@uni.lu. Any questions or discussions are welcomed!
+
+
+## License
+This software is © University of Luxembourg and is licensed under the snt academic license. See [LICENSE](LICENSE)
+
+
+## Acknowledge
+We acknowledge the excellent implementation from [OpenMMLab](https://github.com/open-mmlab) ([mmengine](https://github.com/open-mmlab/mmengine), [mmcv](https://github.com/open-mmlab/mmcv)), [SBI](https://github.com/mapooon/SelfBlendedImages), and [LAA-Net](https://github.com/10Ring/LAA-Net).
+
+
+## Citation
+Please kindly consider citing our papers in your publications.
+```
+@inproceedings{nguyen2025vulnerability,
+ title={Vulnerability-Aware Spatio-Temporal Learning for Generalizable Deepfake Video Detection},
+ author={Nguyen, Dat and Astrid, Marcella and Kacem, Anis and Ghorbel, Enjie and Aouada, Djamila},
+ booktitle={Proceedings of the IEEE/CVF International Conference on Computer Vision},
+ pages={10786--10796},
+ year={2025}
+}
+```
diff --git a/clean/video/fakestormer/SOURCE.md b/clean/video/fakestormer/SOURCE.md
new file mode 100644
index 0000000000000000000000000000000000000000..2231add3d939da025cf72fad639e8114986b9e35
--- /dev/null
+++ b/clean/video/fakestormer/SOURCE.md
@@ -0,0 +1,17 @@
+# Source: video/fakestormer
+
+| Field | Value |
+|---|---|
+| Upstream | **UNVERIFIED** -- provenance was lost when this code was vendored |
+| Paper | not recorded |
+| Commit SHA | **not recorded** -- the vendoring step did not preserve it |
+| Mirrored on | 2026-09-15 |
+| Upstream license | LICENSE |
+
+This is a **mirror**, stripped to the files needed for inference. The full
+untouched snapshot is at `archive/video__fakestormer.tar.gz`.
+
+This code is the work of its original authors and is **not** covered by the
+DeepSafe project license. If you are an author and want this removed, open an
+issue on https://github.com/deepsafehq/deepsafe-bench and it will be taken down
+within 48 hours, no questions asked.
diff --git a/clean/video/fakestormer/Third_Party_License_Notice b/clean/video/fakestormer/Third_Party_License_Notice
new file mode 100644
index 0000000000000000000000000000000000000000..728074becf0d25831d1868a35adc309af6415ae4
--- /dev/null
+++ b/clean/video/fakestormer/Third_Party_License_Notice
@@ -0,0 +1,1606 @@
+FakeSTormer is © 2024 - 2025 University of Luxembourg
+Developed by: Dat Nguyen at CVI2/SnT
+
+FakeSTormer is licensed under the SnT academic license (see #LICENSE)
+
+FakeSTormer includes the following components:
+
+From PyTorch:
+
+Copyright (c) 2016- Facebook, Inc (Adam Paszke)
+Copyright (c) 2014- Facebook, Inc (Soumith Chintala)
+Copyright (c) 2011-2014 Idiap Research Institute (Ronan Collobert)
+Copyright (c) 2012-2014 Deepmind Technologies (Koray Kavukcuoglu)
+Copyright (c) 2011-2012 NEC Laboratories America (Koray Kavukcuoglu)
+Copyright (c) 2011-2013 NYU (Clement Farabet)
+Copyright (c) 2006-2010 NEC Laboratories America (Ronan Collobert, Leon Bottou, Iain Melvin, Jason Weston)
+Copyright (c) 2006 Idiap Research Institute (Samy Bengio)
+Copyright (c) 2001-2004 Idiap Research Institute (Ronan Collobert, Samy Bengio, Johnny Mariethoz)
+
+
+From Caffe2:
+
+Copyright (c) 2016-present, Facebook Inc. All rights reserved.
+
+All contributions by Facebook:
+Copyright (c) 2016 Facebook Inc.
+
+All contributions by Google:
+Copyright (c) 2015 Google Inc.
+All rights reserved.
+
+All contributions by Yangqing Jia:
+Copyright (c) 2015 Yangqing Jia
+All rights reserved.
+
+All contributions by Kakao Brain:
+Copyright 2019-2020 Kakao Brain
+
+All contributions by Cruise LLC:
+Copyright (c) 2022 Cruise LLC.
+All rights reserved.
+
+All contributions from Caffe:
+Copyright(c) 2013, 2014, 2015, the respective contributors
+All rights reserved.
+
+All other contributions:
+Copyright(c) 2015, 2016 the respective contributors
+All rights reserved.
+
+Caffe2 uses a copyright model similar to Caffe: each contributor holds
+copyright over their contributions to Caffe2. The project versioning records
+all such contribution and copyright details. If a contributor wants to further
+mark their specific copyright on a particular contribution, they should
+indicate their copyright solely in the commit message of the change when it is
+committed.
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+3. Neither the names of Facebook, Deepmind Technologies, NYU, NEC Laboratories America
+ and IDIAP Research Institute nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+
+From TorchVision:
+
+BSD 3-Clause License
+
+Copyright (c) Soumith Chintala 2016,
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+* Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+From Tensorboard:
+
+Copyright 2017 The TensorFlow Authors. All rights reserved.
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2017, The TensorFlow Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
+From TensorboardX:
+
+MIT License
+
+Copyright (c) 2017 Tzu-Wei Huang
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+From ImgAug:
+
+The MIT License (MIT)
+
+Copyright (c) 2015 aleju
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+From Torchcam:
+
+Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
+From Dlib:
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+
+From Matplotlib:
+
+License agreement for matplotlib versions 1.3.0 and later
+=========================================================
+
+1. This LICENSE AGREEMENT is between the Matplotlib Development Team
+("MDT"), and the Individual or Organization ("Licensee") accessing and
+otherwise using matplotlib software in source or binary form and its
+associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, MDT
+hereby grants Licensee a nonexclusive, royalty-free, world-wide license
+to reproduce, analyze, test, perform and/or display publicly, prepare
+derivative works, distribute, and otherwise use matplotlib
+alone or in any derivative version, provided, however, that MDT's
+License Agreement and MDT's notice of copyright, i.e., "Copyright (c)
+2012- Matplotlib Development Team; All Rights Reserved" are retained in
+matplotlib alone or in any derivative version prepared by
+Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on or
+incorporates matplotlib or any part thereof, and wants to
+make the derivative work available to others as provided herein, then
+Licensee hereby agrees to include in any such work a brief summary of
+the changes made to matplotlib .
+
+4. MDT is making matplotlib available to Licensee on an "AS
+IS" basis. MDT MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, MDT MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF MATPLOTLIB
+WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. MDT SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF MATPLOTLIB
+ FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR
+LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING
+MATPLOTLIB , OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF
+THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any
+relationship of agency, partnership, or joint venture between MDT and
+Licensee. This License Agreement does not grant permission to use MDT
+trademarks or trade name in a trademark sense to endorse or promote
+products or services of Licensee, or any third party.
+
+8. By copying, installing or otherwise using matplotlib ,
+Licensee agrees to be bound by the terms and conditions of this License
+Agreement.
+
+License agreement for matplotlib versions prior to 1.3.0
+========================================================
+
+1. This LICENSE AGREEMENT is between John D. Hunter ("JDH"), and the
+Individual or Organization ("Licensee") accessing and otherwise using
+matplotlib software in source or binary form and its associated
+documentation.
+
+2. Subject to the terms and conditions of this License Agreement, JDH
+hereby grants Licensee a nonexclusive, royalty-free, world-wide license
+to reproduce, analyze, test, perform and/or display publicly, prepare
+derivative works, distribute, and otherwise use matplotlib
+alone or in any derivative version, provided, however, that JDH's
+License Agreement and JDH's notice of copyright, i.e., "Copyright (c)
+2002-2011 John D. Hunter; All Rights Reserved" are retained in
+matplotlib alone or in any derivative version prepared by
+Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on or
+incorporates matplotlib or any part thereof, and wants to
+make the derivative work available to others as provided herein, then
+Licensee hereby agrees to include in any such work a brief summary of
+the changes made to matplotlib.
+
+4. JDH is making matplotlib available to Licensee on an "AS
+IS" basis. JDH MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, JDH MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF MATPLOTLIB
+WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. JDH SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF MATPLOTLIB
+ FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR
+LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING
+MATPLOTLIB , OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF
+THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any
+relationship of agency, partnership, or joint venture between JDH and
+Licensee. This License Agreement does not grant permission to use JDH
+trademarks or trade name in a trademark sense to endorse or promote
+products or services of Licensee, or any third party.
+
+8. By copying, installing or otherwise using matplotlib,
+Licensee agrees to be bound by the terms and conditions of this License
+Agreement.
+
+
+From tqdm:
+
+`tqdm` is a product of collaborative work.
+Unless otherwise stated, all authors (see commit logs) retain copyright
+for their respective work, and release the work under the MIT licence
+(text below).
+
+Exceptions or notable authors are listed below
+in reverse chronological order:
+
+* files: *
+ MPL-2.0 2015-2024 (c) Casper da Costa-Luis
+ [casperdcl](https://github.com/casperdcl).
+* files: tqdm/_tqdm.py
+ MIT 2016 (c) [PR #96] on behalf of Google Inc.
+* files: tqdm/_tqdm.py README.rst .gitignore
+ MIT 2013 (c) Noam Yorav-Raphael, original author.
+
+[PR #96]: https://github.com/tqdm/tqdm/pull/96
+
+
+Mozilla Public Licence (MPL) v. 2.0 - Exhibit A
+-----------------------------------------------
+
+This Source Code Form is subject to the terms of the
+Mozilla Public License, v. 2.0.
+If a copy of the MPL was not distributed with this project,
+You can obtain one at https://mozilla.org/MPL/2.0/.
+
+
+MIT License (MIT)
+-----------------
+
+Copyright (c) 2013 noamraph
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+From scikit-image:
+
+Copyright: 2009-2022 the scikit-image team
+License: BSD-3-Clause
+
+Files: doc/source/themes/scikit-image/layout.html
+Copyright: 2007-2010 the Sphinx team
+License: BSD-3-Clause
+
+Files: skimage/feature/_canny.py
+ skimage/filters/edges.py
+ skimage/filters/_rank_order.py
+ skimage/morphology/_skeletonize.py
+ skimage/morphology/tests/test_watershed.py
+ skimage/morphology/watershed.py
+ skimage/segmentation/heap_general.pxi
+ skimage/segmentation/heap_watershed.pxi
+ skimage/segmentation/_watershed.py
+ skimage/segmentation/_watershed_cy.pyx
+Copyright: 2003-2009 Massachusetts Institute of Technology
+ 2009-2011 Broad Institute
+ 2003 Lee Kamentsky
+ 2003-2005 Peter J. Verveer
+License: BSD-3-Clause
+
+Files: skimage/filters/thresholding.py
+ skimage/graph/_mcp.pyx
+ skimage/graph/heap.pyx
+Copyright: 2009-2015 Board of Regents of the University of
+ Wisconsin-Madison, Broad Institute of MIT and Harvard,
+ and Max Planck Institute of Molecular Cell Biology and
+ Genetics
+ 2009 Zachary Pincus
+ 2009 Almar Klein
+License: BSD-2-Clause
+
+File: skimage/morphology/grayreconstruct.py
+ skimage/morphology/tests/test_reconstruction.py
+Copyright: 2003-2009 Massachusetts Institute of Technology
+ 2009-2011 Broad Institute
+ 2003 Lee Kamentsky
+License: BSD-3-Clause
+
+File: skimage/morphology/_grayreconstruct.pyx
+Copyright: 2003-2009 Massachusetts Institute of Technology
+ 2009-2011 Broad Institute
+ 2003 Lee Kamentsky
+ 2022 Gregory Lee (added a 64-bit integer variant for large images)
+License: BSD-3-Clause
+
+File: skimage/segmentation/_expand_labels.py
+Copyright: 2020 Broad Institute
+ 2020 CellProfiler team
+License: BSD-3-Clause
+
+File: skimage/exposure/_adapthist.py
+Copyright: 1994 Karel Zuiderveld
+License: BSD-3-Clause
+
+Function: skimage/morphology/_skeletonize_cy.pyx:_skeletonize_loop
+Copyright: 2003-2009 Massachusetts Institute of Technology
+ 2009-2011 Broad Institute
+ 2003 Lee Kamentsky
+License: BSD-3-Clause
+
+Function: skimage/_shared/version_requirements.py:_check_version
+Copyright: 2013 The IPython Development Team
+License: BSD-3-Clause
+
+Function: skimage/_shared/version_requirements.py:is_installed
+Copyright: 2009-2011 Pierre Raybaut
+License: MIT
+
+File: skimage/feature/_fisher_vector.py
+Copyright: 2014 2014 Dan Oneata
+License: MIT
+
+File: skimage/_vendored/numpy_lookfor.py
+Copyright: 2005-2023, NumPy Developers
+License: BSD-3-Clause
+
+
+License: BSD-2-Clause
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE HOLDERS OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+License: BSD-3-Clause
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. Neither the name of the University nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE HOLDERS OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+License: MIT
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+From opencv-python:
+
+MIT License
+
+Copyright (c) Olli-Pekka Heinisuo
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+From numpy:
+
+Copyright (c) 2005-2024, NumPy Developers.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+
+ * Neither the name of the NumPy Developers nor the names of any
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+From python-box:
+
+MIT License
+
+Copyright (c) 2017-2023 Chris Griffith
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+From Imutils:
+
+The MIT License (MIT)
+
+Copyright (c) 2015-2016 Adrian Rosebrock, http://www.pyimagesearch.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+
+From Pillow:
+
+The Python Imaging Library (PIL) is
+
+ Copyright © 1997-2011 by Secret Labs AB
+ Copyright © 1995-2011 by Fredrik Lundh
+
+Pillow is the friendly PIL fork. It is
+
+ Copyright © 2010-2024 by Jeffrey A. Clark (Alex) and contributors.
+
+Like PIL, Pillow is licensed under the open source HPND License:
+
+By obtaining, using, and/or copying this software and/or its associated
+documentation, you agree that you have read, understood, and will comply
+with the following terms and conditions:
+
+Permission to use, copy, modify and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appears in all copies, and that
+both that copyright notice and this permission notice appear in supporting
+documentation, and that the name of Secret Labs AB or the author not be
+used in advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR BE LIABLE FOR ANY SPECIAL,
+INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+
+From PyYAML:
+
+Copyright (c) 2017-2021 Ingy döt Net
+Copyright (c) 2006-2016 Kirill Simonov
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+From scipy:
+
+Copyright (c) 2001-2002 Enthought, Inc. 2003-2024, SciPy Developers.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+From scikit-learn:
+
+BSD 3-Clause License
+
+Copyright (c) 2007-2023 The scikit-learn developers.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+* Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+From simplejson:
+
+simplejson is dual-licensed software. It is available under the terms
+of the MIT license, or the Academic Free License version 2.1. The full
+text of each license agreement is included below. This code is also
+licensed to the Python Software Foundation (PSF) under a Contributor
+Agreement.
+
+MIT License
+===========
+
+Copyright (c) 2006 Bob Ippolito
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+Academic Free License v. 2.1
+============================
+
+Copyright (c) 2006 Bob Ippolito. All rights reserved.
+
+This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following notice immediately following the copyright notice for the Original Work:
+
+Licensed under the Academic Free License version 2.1
+
+1) Grant of Copyright License. Licensor hereby grants You a world-wide, royalty-free, non-exclusive, perpetual, sublicenseable license to do the following:
+
+a) to reproduce the Original Work in copies;
+
+b) to prepare derivative works ("Derivative Works") based upon the Original Work;
+
+c) to distribute copies of the Original Work and Derivative Works to the public;
+
+d) to perform the Original Work publicly; and
+
+e) to display the Original Work publicly.
+
+2) Grant of Patent License. Licensor hereby grants You a world-wide, royalty-free, non-exclusive, perpetual, sublicenseable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, to make, use, sell and offer for sale the Original Work and Derivative Works.
+
+3) Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor hereby agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work, and by publishing the address of that information repository in a notice immediately following the copyright notice that applies to the Original Work.
+
+4) Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior written permission of the Licensor. Nothing in this License shall be deemed to grant any rights to trademarks, copyrights, patents, trade secrets or any other intellectual property of Licensor except as expressly stated herein. No patent license is granted to make, use, sell or offer to sell embodiments of any patent claims other than the licensed claims defined in Section 2. No right is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under different terms from this License any Original Work that Licensor otherwise would have a right to license.
+
+5) This section intentionally omitted.
+
+6) Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work.
+
+7) Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately proceeding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to Original Work is granted hereunder except under this disclaimer.
+
+8) Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to any person for any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to liability for death or personal injury resulting from Licensor's negligence to the extent applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so this exclusion and limitation may not apply to You.
+
+9) Acceptance and Termination. If You distribute copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. Nothing else but this License (or another written agreement between Licensor and You) grants You permission to create Derivative Works based upon the Original Work or to exercise any of the rights granted in Section 1 herein, and any attempt to do so except under the terms of this License (or another written agreement between Licensor and You) is expressly prohibited by U.S. copyright law, the equivalent laws of other countries, and by international treaty. Therefore, by exercising any of the rights granted to You in Section 1 herein, You indicate Your acceptance of this License and all of its terms and conditions.
+
+10) Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware.
+
+11) Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of the U.S. Copyright Act, 17 U.S.C. § 101 et seq., the equivalent laws of other countries, and international treaty. This section shall survive the termination of this License.
+
+12) Attorneys Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License.
+
+13) Miscellaneous. This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable.
+
+14) Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+
+15) Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You.
+
+This license is Copyright (C) 2003-2004 Lawrence E. Rosen. All rights reserved. Permission is hereby granted to copy and distribute this license without modification. This license may not be modified without the express written permission of its copyright owner.
+
+
+From pandas:
+
+SD 3-Clause License
+
+Copyright (c) 2008-2011, AQR Capital Management, LLC, Lambda Foundry, Inc. and PyData Development Team
+All rights reserved.
+
+Copyright (c) 2011-2024, Open source contributors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+* Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+From shape_predictor_81_face_landmarks:
+
+BSD 3-Clause License
+
+Copyright (c) 2019, Nikolay Feldman
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+* Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+From retinaface:
+
+MIT License
+
+Copyright (c) 2020 Vladimir Iglovikov
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+From EfficientNet-PyTorch:
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
+From albumentations:
+
+MIT License
+
+Copyright (c) 2017 Buslaev Alexander, Alexander Parinov, Vladimir Iglovikov
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+From SAM:
+
+MIT License
+
+Copyright (c) 2021 David Samuel
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+From natsort:
+
+Copyright (c) 2012-2023 Seth M. Morton
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+************END OF THIRD-PARTY SOFTWARE NOTICES AND INFORMATION**********
diff --git a/clean/video/fakestormer/configs/base.yaml b/clean/video/fakestormer/configs/base.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..1faca4d31ec18af2bc8a153a05f024c8f59e2cbb
--- /dev/null
+++ b/clean/video/fakestormer/configs/base.yaml
@@ -0,0 +1,79 @@
+TASK: heatmap
+PRECISION: float32
+DATASET:
+ type: HeatmapFaceForensic
+ TRAIN: True
+ ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c23/
+ # FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ FAKETYPE: [FaceXRay]
+ IMAGE_SUFFIX: jpg
+ FROM_FILE: True
+ NUM_WORKERS: 8
+ PIN_MEMORY: True
+ IMAGE_SIZE: [256, 256]
+ HEATMAP_SIZE: [64, 64]
+ SIGMA: 2
+ HEATMAP_TYPE: gaussian
+ DATA:
+ TYPE: images
+ TRAIN:
+ ANNO_FILE: FaceXRay/train/train_FF_Xray.json
+ VAL:
+ ANNO_FILE: FaceXRay/val/val_FF_Xray.json
+ TEST:
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [256, 256, 0] #h, w, p=probability. If no affine transform, set p=1
+ color:
+ type: ColorJitterTransform
+ clahe: 0.5
+ colorjitter: 0.5
+ gaussianblur: 0.5
+ jpegcompression: 0.5
+ rgbshift: 0.5
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+ DEBUG: False
+MODEL:
+ type: SimpleClassificationDF
+ backbone:
+ type: ResNet
+ num_layers: 50
+ drop_ratio: 0.5
+ mode: ir_se
+ head:
+ type: SimpleClassificationHead
+ drop_ratio: 0.5
+ in_planes: 512
+TRAIN:
+ gpus: [0,1,2,3]
+ batch_size: 32
+ lr: 0.001
+ epochs: 100
+ begin_epoch: 0
+ warm_up: 5
+ every_val_epochs: 3
+ loss:
+ type: CombinedLoss
+ use_target_weight: False
+ optimizer: Adam
+ distributed: False
+ pretrained: pretrained/model_ir_se50.pth
+ tensorboard: True
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [50, 80, 90]
+ gamma: 0.1
+PREPROCESSING:
+ DATASET: FaceForensics
+ SPLIT: train
+ ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c23/
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ IMAGE_SUFFIX: jpg
+ DATA_TYPE: images
+ LABEL: real
+ facial_lm_pretrained: pretrained/shape_predictor_68_face_landmarks.dat
diff --git a/clean/video/fakestormer/configs/get_config.py b/clean/video/fakestormer/configs/get_config.py
new file mode 100644
index 0000000000000000000000000000000000000000..e47c3393fdbabb52d5063bda7b5604fe68a27ae1
--- /dev/null
+++ b/clean/video/fakestormer/configs/get_config.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+import os
+
+from yaml import dump, load
+
+try:
+ from yaml import CDumper as Dumper
+ from yaml import CLoader as Loader
+except ImportError:
+ from yaml import Loader, Dumper
+
+from box import Box as edict
+
+
+def load_config(cfg):
+ with open(cfg) as f:
+ config = load(f, Loader=Loader)
+
+ return edict(config)
diff --git a/clean/video/fakestormer/configs/preprocessing/data_preprocessing_c0.yaml b/clean/video/fakestormer/configs/preprocessing/data_preprocessing_c0.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..9f499a523d4212dfd294786f0d1275c70ddc729a
--- /dev/null
+++ b/clean/video/fakestormer/configs/preprocessing/data_preprocessing_c0.yaml
@@ -0,0 +1,16 @@
+PREPROCESSING:
+ DATASET: FF++
+ COMPRESSION: c0
+ SPLIT: val
+ ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ # FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ FAKETYPE: [original]
+ IMAGE_SUFFIX: png
+ DATA_TYPE: videos
+ LABEL: [real]
+ facial_lm_pretrained: pretrained/shape_predictor_81_face_landmarks.dat
+ N_LANDMARKS: 81
+ SAMPLING:
+ ACTIVE: False
+ NUMBERS: 8
+ DEBUG: False
diff --git a/clean/video/fakestormer/configs/preprocessing/data_preprocessing_c23.yaml b/clean/video/fakestormer/configs/preprocessing/data_preprocessing_c23.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d071da68974c657dc13b640e72de68c4176a089b
--- /dev/null
+++ b/clean/video/fakestormer/configs/preprocessing/data_preprocessing_c23.yaml
@@ -0,0 +1,16 @@
+PREPROCESSING:
+ DATASET: FaceForensics
+ COMPRESSION: c23
+ SPLIT: train
+ ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c23/
+ # FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ FAKETYPE: [original]
+ IMAGE_SUFFIX: png
+ DATA_TYPE: videos
+ LABEL: [real]
+ facial_lm_pretrained: pretrained/shape_predictor_81_face_landmarks.dat
+ N_LANDMARKS: 81
+ SAMPLING:
+ ACTIVE: False
+ NUMBERS: 8
+ DEBUG: False
diff --git a/clean/video/fakestormer/configs/spatial/binary_cls/efns/efn_4.yaml b/clean/video/fakestormer/configs/spatial/binary_cls/efns/efn_4.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..0dc7d27a39fbd9b8a5fd20c8dfc6be9313d578ce
--- /dev/null
+++ b/clean/video/fakestormer/configs/spatial/binary_cls/efns/efn_4.yaml
@@ -0,0 +1,160 @@
+TASK: EFNB4_BCE_Adam_5e4_Batch32_50epochs_abl_FS
+PRECISION: float64
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: False
+
+DATASET:
+ type: BinaryFaceForensic
+ DATA_TYPE: image
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c0
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 7
+ PIN_MEMORY: True
+ IMAGE_SIZE: [256, 256]
+ HEATMAP_SIZE: [28, 28] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 1
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: gaussian
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: frames
+ SAMPLES_PER_VIDEO:
+ ACTIVE: False
+ TRAIN: 8 # Dynamically random number of frames in each epoch
+ VAL: 8
+ TEST: 128
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ # ROOT: /home/users/XXX/data/DFW/
+ FROM_FILE: False
+ # FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # FAKETYPE: [new_fake_train, new_real_train]
+ # FAKETYPE: [original, NeuralTextures]
+ # FAKETYPE: [original, Face2Face]
+ # FAKETYPE: [original, Deepfakes]
+ FAKETYPE: [original, FaceSwap]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/train_81_FF++_processed.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ # ROOT: /home/users/XXX/data/DFW/
+ FROM_FILE: False
+ # FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures] # Choosing Deepfake techniques to be loaded for dataloader
+ # FAKETYPE: [fake_test, real_test]
+ # FAKETYPE: [original, NeuralTextures]
+ # FAKETYPE: [original, Face2Face]
+ # FAKETYPE: [original, Deepfakes]
+ FAKETYPE: [original, FaceSwap]
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/val_81_FF++_processed.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: Celeb-DFv1
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /project/home/p200249/XXX/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ # ROOT: /project/home/p200249/XXX/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ # ROOT: /project/home/p200249/XXX/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ # ROOT: /project/home/p200249/XXX/DFW/
+ FROM_FILE: False
+ # FAKETYPE: [original, Deepfakes]
+ # FAKETYPE: [original, Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake, real]
+ # FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ # FAKETYPE: [fake_test, real_test]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [256, 256, 1] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ cropping: [0.15, 0.5] #Format: [crop_limit, prob]
+ scale: [0.15, 0.5] #Format: [scale_limit, prob]
+ rand_erasing: [0.0, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.5, 0.5, 0.5]
+ std: [0.5, 0.5, 0.5]
+ DEBUG: False
+
+MODEL:
+ type: PoseEfficientNet
+ model_name: efficientnet-b4
+ num_layers: B4
+ include_top: True
+ num_classes: 1
+ include_hm_decoder: False
+ INIT_WEIGHTS:
+ pretrained: True
+ advprop: True
+
+TRAIN:
+ gpus: [0]
+ batch_size: 32
+ lr: 0.0005
+ epochs: 50
+ begin_epoch: -1
+ warm_up: 5
+ every_val_epochs: 1
+ loss:
+ type: BinaryCrossEntropy
+ reduction: mean
+ optimizer: Adam
+ distributed: False
+ pretrained: ''
+ tensorboard: True
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: False
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+ booster: 1
+ start_decay: 4
+
+TEST:
+ gpus: [0,1,2,3]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: True
+ video_level: True
+ pretrained: 'logs/10-01-2024/TopDownDetector_ViTSmall112_hm10_8SBI_NonOverlap100_MSE_AdamW_IN_5e5_FZ5_Batch32_200epochs_Drop0.2_AVG_model_best.pth'
diff --git a/clean/video/fakestormer/configs/spatial/binary_cls/vits/vit_small_112p16.yaml b/clean/video/fakestormer/configs/spatial/binary_cls/vits/vit_small_112p16.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..19d65db341d1dcc7b02a5bb36472412692b1dea7
--- /dev/null
+++ b/clean/video/fakestormer/configs/spatial/binary_cls/vits/vit_small_112p16.yaml
@@ -0,0 +1,180 @@
+TASK: ViTSmall112_BCE_AdamW_IN_5e5_Batch32_50epochs_Drop0.2_abl_p16_FS
+PRECISION: float64
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: False
+
+DATASET:
+ type: BinaryFaceForensic
+ DATA_TYPE: image
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c0
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 7
+ PIN_MEMORY: True
+ IMAGE_SIZE: [112, 112]
+ HEATMAP_SIZE: [7, 7] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 1
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: gaussian
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: frames
+ SAMPLES_PER_VIDEO:
+ ACTIVE: False
+ TRAIN: 8 # Dynamically random number of frames in each epoch
+ VAL: 8
+ TEST: 128
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ # ROOT: /home/users/XXX/data/DFW/
+ FROM_FILE: False
+ # FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # FAKETYPE: [new_fake_train, new_real_train]
+ # FAKETYPE: [original, NeuralTextures]
+ # FAKETYPE: [original, Face2Face]
+ # FAKETYPE: [original, Deepfakes]
+ FAKETYPE: [original, FaceSwap]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/train_81_FF++_processed.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ # ROOT: /home/users/XXX/data/DFW/
+ FROM_FILE: False
+ # FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures] # Choosing Deepfake techniques to be loaded for dataloader
+ # FAKETYPE: [fake_test, real_test]
+ # FAKETYPE: [original, NeuralTextures]
+ # FAKETYPE: [original, Face2Face]
+ # FAKETYPE: [original, Deepfakes]
+ FAKETYPE: [original, FaceSwap]
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/val_81_FF++_processed.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: Celeb-DFv1
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /project/home/p200249/XXX/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ # ROOT: /project/home/p200249/XXX/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ # ROOT: /project/home/p200249/XXX/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ # ROOT: /project/home/p200249/XXX/DFW/
+ FROM_FILE: False
+ # FAKETYPE: [original, Deepfakes]
+ # FAKETYPE: [original, Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake, real]
+ # FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ # FAKETYPE: [fake_test, real_test]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [112, 112, 1] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ cropping: [0.15, 0.5] #Format: [crop_limit, prob]
+ scale: [0.15, 0.5] #Format: [scale_limit, prob]
+ rand_erasing: [0.0, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+ DEBUG: False
+
+MODEL:
+ type: TopDownDetector
+ backbone:
+ type: ViT
+ img_size: [112, 112]
+ patch_size: 16
+ embed_dim: 384
+ depth: 12
+ num_heads: 6
+ mlp_ratio: 4
+ drop_path_rate: 0.2
+ qkv_bias: True
+ class_token: True
+ pretrained: pretrained/dino_deitsmall16_pretrain.pth
+ # pretrained: null
+ keypoint_head:
+ type: TopdownHeatmapSimpleHead
+ in_channels: 384
+ heads:
+ # hm: 1
+ cls: 1
+ num_deconv_layers: 0 #Config n deconv layers to build the decoder
+ num_deconv_filters: [256, 256]
+ num_deconv_kernels: [4, 4]
+ loss_keypoint:
+ type: JointsMSELoss
+ use_target_weight: False
+ extra:
+ final_conv_kernel: 3
+ num_conv_layers: 1
+
+TRAIN:
+ gpus: [0]
+ batch_size: 32
+ lr: 0.00005
+ epochs: 50
+ begin_epoch: -1
+ warm_up: 5
+ every_val_epochs: 1
+ loss:
+ type: BinaryCrossEntropy
+ reduction: mean
+ optimizer: AdamW
+ distributed: False
+ pretrained: ''
+ tensorboard: True
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: False
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+ booster: 1
+ start_decay: 4
+
+TEST:
+ gpus: [0,1,2,3]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: True
+ video_level: True
+ pretrained: 'logs/10-01-2024/TopDownDetector_ViTSmall112_hm10_8SBI_NonOverlap100_MSE_AdamW_IN_5e5_FZ5_Batch32_200epochs_Drop0.2_AVG_model_best.pth'
diff --git a/clean/video/fakestormer/configs/spatial/binary_cls/vits/vit_small_112p8.yaml b/clean/video/fakestormer/configs/spatial/binary_cls/vits/vit_small_112p8.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..7e716fe1c0991f206d66075c6137d590d3a00292
--- /dev/null
+++ b/clean/video/fakestormer/configs/spatial/binary_cls/vits/vit_small_112p8.yaml
@@ -0,0 +1,180 @@
+TASK: ViTSmall112_BCE_AdamW_IN_5e5_Batch32_50epochs_Drop0.2_abl_p8_FS
+PRECISION: float64
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: False
+
+DATASET:
+ type: BinaryFaceForensic
+ DATA_TYPE: image
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c0
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 7
+ PIN_MEMORY: True
+ IMAGE_SIZE: [112, 112]
+ HEATMAP_SIZE: [14, 14] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 1
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: gaussian
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: frames
+ SAMPLES_PER_VIDEO:
+ ACTIVE: False
+ TRAIN: 8 # Dynamically random number of frames in each epoch
+ VAL: 8
+ TEST: 128
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ # ROOT: /home/users/XXX/data/DFW/
+ FROM_FILE: False
+ # FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # FAKETYPE: [new_fake_train, new_real_train]
+ # FAKETYPE: [original, NeuralTextures]
+ # FAKETYPE: [original, Face2Face]
+ # FAKETYPE: [original, Deepfakes]
+ FAKETYPE: [original, FaceSwap]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/train_81_FF++_processed.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ # ROOT: /home/users/XXX/data/DFW/
+ FROM_FILE: False
+ # FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures] # Choosing Deepfake techniques to be loaded for dataloader
+ # FAKETYPE: [fake_test, real_test]
+ # FAKETYPE: [original, NeuralTextures]
+ # FAKETYPE: [original, Face2Face]
+ # FAKETYPE: [original, Deepfakes]
+ FAKETYPE: [original, FaceSwap]
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/val_81_FF++_processed.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: Celeb-DFv1
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /project/home/p200249/XXX/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ # ROOT: /project/home/p200249/XXX/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ # ROOT: /project/home/p200249/XXX/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ # ROOT: /project/home/p200249/XXX/DFW/
+ FROM_FILE: False
+ # FAKETYPE: [original, Deepfakes]
+ # FAKETYPE: [original, Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake, real]
+ # FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ # FAKETYPE: [fake_test, real_test]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [112, 112, 1] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ cropping: [0.15, 0.5] #Format: [crop_limit, prob]
+ scale: [0.15, 0.5] #Format: [scale_limit, prob]
+ rand_erasing: [0.0, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+ DEBUG: False
+
+MODEL:
+ type: TopDownDetector
+ backbone:
+ type: ViT
+ img_size: [112, 112]
+ patch_size: 8
+ embed_dim: 384
+ depth: 12
+ num_heads: 6
+ mlp_ratio: 4
+ drop_path_rate: 0.2
+ qkv_bias: True
+ class_token: True
+ pretrained: pretrained/dino_deitsmall8_pretrain.pth
+ # pretrained: null
+ keypoint_head:
+ type: TopdownHeatmapSimpleHead
+ in_channels: 384
+ heads:
+ # hm: 1
+ cls: 1
+ num_deconv_layers: 0 #Config n deconv layers to build the decoder
+ num_deconv_filters: [256, 256]
+ num_deconv_kernels: [4, 4]
+ loss_keypoint:
+ type: JointsMSELoss
+ use_target_weight: False
+ extra:
+ final_conv_kernel: 3
+ num_conv_layers: 1
+
+TRAIN:
+ gpus: [0]
+ batch_size: 32
+ lr: 0.00005
+ epochs: 50
+ begin_epoch: -1
+ warm_up: 5
+ every_val_epochs: 1
+ loss:
+ type: BinaryCrossEntropy
+ reduction: mean
+ optimizer: AdamW
+ distributed: False
+ pretrained: ''
+ tensorboard: True
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: False
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+ booster: 1
+ start_decay: 4
+
+TEST:
+ gpus: [0,1,2,3]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: True
+ video_level: True
+ pretrained: 'logs/10-01-2024/TopDownDetector_ViTSmall112_hm10_8SBI_NonOverlap100_MSE_AdamW_IN_5e5_FZ5_Batch32_200epochs_Drop0.2_AVG_model_best.pth'
diff --git a/clean/video/fakestormer/configs/spatial/binary_cls/vits/vit_small_224p8.yaml b/clean/video/fakestormer/configs/spatial/binary_cls/vits/vit_small_224p8.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..7e716fe1c0991f206d66075c6137d590d3a00292
--- /dev/null
+++ b/clean/video/fakestormer/configs/spatial/binary_cls/vits/vit_small_224p8.yaml
@@ -0,0 +1,180 @@
+TASK: ViTSmall112_BCE_AdamW_IN_5e5_Batch32_50epochs_Drop0.2_abl_p8_FS
+PRECISION: float64
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: False
+
+DATASET:
+ type: BinaryFaceForensic
+ DATA_TYPE: image
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c0
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 7
+ PIN_MEMORY: True
+ IMAGE_SIZE: [112, 112]
+ HEATMAP_SIZE: [14, 14] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 1
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: gaussian
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: frames
+ SAMPLES_PER_VIDEO:
+ ACTIVE: False
+ TRAIN: 8 # Dynamically random number of frames in each epoch
+ VAL: 8
+ TEST: 128
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ # ROOT: /home/users/XXX/data/DFW/
+ FROM_FILE: False
+ # FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # FAKETYPE: [new_fake_train, new_real_train]
+ # FAKETYPE: [original, NeuralTextures]
+ # FAKETYPE: [original, Face2Face]
+ # FAKETYPE: [original, Deepfakes]
+ FAKETYPE: [original, FaceSwap]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/train_81_FF++_processed.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ # ROOT: /home/users/XXX/data/DFW/
+ FROM_FILE: False
+ # FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures] # Choosing Deepfake techniques to be loaded for dataloader
+ # FAKETYPE: [fake_test, real_test]
+ # FAKETYPE: [original, NeuralTextures]
+ # FAKETYPE: [original, Face2Face]
+ # FAKETYPE: [original, Deepfakes]
+ FAKETYPE: [original, FaceSwap]
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/val_81_FF++_processed.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: Celeb-DFv1
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /project/home/p200249/XXX/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ # ROOT: /project/home/p200249/XXX/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ # ROOT: /project/home/p200249/XXX/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ # ROOT: /project/home/p200249/XXX/DFW/
+ FROM_FILE: False
+ # FAKETYPE: [original, Deepfakes]
+ # FAKETYPE: [original, Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake, real]
+ # FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ # FAKETYPE: [fake_test, real_test]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [112, 112, 1] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ cropping: [0.15, 0.5] #Format: [crop_limit, prob]
+ scale: [0.15, 0.5] #Format: [scale_limit, prob]
+ rand_erasing: [0.0, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+ DEBUG: False
+
+MODEL:
+ type: TopDownDetector
+ backbone:
+ type: ViT
+ img_size: [112, 112]
+ patch_size: 8
+ embed_dim: 384
+ depth: 12
+ num_heads: 6
+ mlp_ratio: 4
+ drop_path_rate: 0.2
+ qkv_bias: True
+ class_token: True
+ pretrained: pretrained/dino_deitsmall8_pretrain.pth
+ # pretrained: null
+ keypoint_head:
+ type: TopdownHeatmapSimpleHead
+ in_channels: 384
+ heads:
+ # hm: 1
+ cls: 1
+ num_deconv_layers: 0 #Config n deconv layers to build the decoder
+ num_deconv_filters: [256, 256]
+ num_deconv_kernels: [4, 4]
+ loss_keypoint:
+ type: JointsMSELoss
+ use_target_weight: False
+ extra:
+ final_conv_kernel: 3
+ num_conv_layers: 1
+
+TRAIN:
+ gpus: [0]
+ batch_size: 32
+ lr: 0.00005
+ epochs: 50
+ begin_epoch: -1
+ warm_up: 5
+ every_val_epochs: 1
+ loss:
+ type: BinaryCrossEntropy
+ reduction: mean
+ optimizer: AdamW
+ distributed: False
+ pretrained: ''
+ tensorboard: True
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: False
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+ booster: 1
+ start_decay: 4
+
+TEST:
+ gpus: [0,1,2,3]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: True
+ video_level: True
+ pretrained: 'logs/10-01-2024/TopDownDetector_ViTSmall112_hm10_8SBI_NonOverlap100_MSE_AdamW_IN_5e5_FZ5_Batch32_200epochs_Drop0.2_AVG_model_best.pth'
diff --git a/clean/video/fakestormer/configs/spatial/binary_cls/xcepts/xcept.yaml b/clean/video/fakestormer/configs/spatial/binary_cls/xcepts/xcept.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..011398f572d211804271b290757d5d63552dd4a5
--- /dev/null
+++ b/clean/video/fakestormer/configs/spatial/binary_cls/xcepts/xcept.yaml
@@ -0,0 +1,156 @@
+TASK: Exeption_BCE_Adam_5e4_Batch32_50epochs_abl_F2F
+PRECISION: float64
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: False
+
+DATASET:
+ type: BinaryFaceForensic
+ DATA_TYPE: image
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c0
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 14
+ PIN_MEMORY: True
+ IMAGE_SIZE: [256, 256]
+ HEATMAP_SIZE: [28, 28] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 1
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: gaussian
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: frames
+ SAMPLES_PER_VIDEO:
+ ACTIVE: False
+ TRAIN: 8 # Dynamically random number of frames in each epoch
+ VAL: 8
+ TEST: 128
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ # ROOT: /home/users/XXX/data/DFW/
+ FROM_FILE: False
+ # FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # FAKETYPE: [new_fake_train, new_real_train]
+ # FAKETYPE: [fake_test, real_test]
+ # FAKETYPE: [original, NeuralTextures]
+ FAKETYPE: [original, Face2Face]
+ # FAKETYPE: [original, Deepfakes]
+ # FAKETYPE: [original, FaceSwap]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/train_81_FF++_processed.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ # ROOT: /home/users/XXX/data/DFW/
+ FROM_FILE: False
+ # FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures] # Choosing Deepfake techniques to be loaded for dataloader
+ # FAKETYPE: [fake_test, real_test]
+ # FAKETYPE: [original, NeuralTextures]
+ FAKETYPE: [original, Face2Face]
+ # FAKETYPE: [original, Deepfakes]
+ # FAKETYPE: [original, FaceSwap]
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/val_81_FF++_processed.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: Celeb-DFv1
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /project/home/p200249/XXX/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ # ROOT: /project/home/p200249/XXX/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ # ROOT: /project/home/p200249/XXX/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ # ROOT: /project/home/p200249/XXX/DFW/
+ FROM_FILE: False
+ # FAKETYPE: [original, Deepfakes]
+ # FAKETYPE: [original, Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake, real]
+ # FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ # FAKETYPE: [fake_test, real_test]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [256, 256, 1] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ cropping: [0.15, 0.5] #Format: [crop_limit, prob]
+ scale: [0.15, 0.5] #Format: [scale_limit, prob]
+ rand_erasing: [0.0, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.5, 0.5, 0.5]
+ std: [0.5, 0.5, 0.5]
+ DEBUG: False
+
+MODEL:
+ type: Xception
+ num_classes: 1
+ INIT_WEIGHTS:
+ pretrained: True
+
+TRAIN:
+ gpus: [0,1]
+ batch_size: 16
+ lr: 0.0005
+ epochs: 50
+ begin_epoch: -1
+ warm_up: 5
+ every_val_epochs: 1
+ loss:
+ type: BinaryCrossEntropy
+ reduction: mean
+ optimizer: Adam
+ distributed: False
+ pretrained: ''
+ tensorboard: True
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: False
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+ booster: 1
+ start_decay: 4
+
+TEST:
+ gpus: [0,1,2,3]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: True
+ video_level: True
+ pretrained: 'logs/10-01-2024/TopDownDetector_ViTSmall112_hm10_8SBI_NonOverlap100_MSE_AdamW_IN_5e5_FZ5_Batch32_200epochs_Drop0.2_AVG_model_best.pth'
diff --git a/clean/video/fakestormer/configs/spatial/efn4_fpn_hm.yaml b/clean/video/fakestormer/configs/spatial/efn4_fpn_hm.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..675d428cee3a016963a136954fb1496a3ebd13e5
--- /dev/null
+++ b/clean/video/fakestormer/configs/spatial/efn4_fpn_hm.yaml
@@ -0,0 +1,147 @@
+TASK: EFN_hm100_FPN_NoBasedCLS_Focal_C3_256Cstency10_32FXRayv1_SAM(Adam)
+PRECISION: float64
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: True
+DATASET:
+ type: HeatmapFaceForensic
+ NAME: Celeb-DFv1 # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ TRAIN: False #Switch to True for training mode, False for testing mode
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ # FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ COMPRESSION: c0
+ IMAGE_SUFFIX: png
+ FROM_FILE: False
+ NUM_WORKERS: 7
+ PIN_MEMORY: True
+ IMAGE_SIZE: [384, 384]
+ HEATMAP_SIZE: [96, 96] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 2
+ ADAPTIVE_SIGMA: True
+ HEATMAP_TYPE: gaussian
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: frames
+ SAMPLES_PER_VIDEO:
+ ACTIVE: True
+ TRAIN: 32
+ VAL: 32
+ TEST: 32
+ TRAIN:
+ FAKETYPE: [FaceXRay]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/dynamic_trainBI_FFv2.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ FAKETYPE: [FaceXRay]
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/dynamic_valBI_FFv2.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ # FAKETYPE: [original, Deepfakes]
+ # FAKETYPE: [original, Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake, real]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [384, 384, 0] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ cropping: [0.15, 0.5] #Format: [crop_limit, prob]
+ scale: [0.15, 0.5] #Format: [scale_limit, prob]
+ rand_erasing: [0.5, 3] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+ DEBUG: False
+ DYNAMIC_FXRAY: True
+MODEL:
+ type: PoseEfficientNet
+ model_name: efficientnet-b4
+ num_layers: B4
+ include_top: False
+ include_hm_decoder: True
+ head_conv: 64
+ use_c2: False
+ use_c3: True
+ use_c4: True
+ use_c51: True
+ fpn: True
+ heads:
+ hm: 1
+ cls: 1
+ cstency: 256
+ INIT_WEIGHTS:
+ pretrained: True
+TRAIN:
+ gpus: [0]
+ batch_size: 32
+ lr: 0.00025
+ epochs: 100
+ begin_epoch: 0
+ warm_up: 6
+ every_val_epochs: 1
+ loss:
+ type: CombinedFocalLoss
+ use_target_weight: False
+ cls_lmda: 1
+ dst_hm_cls_lmda: 0
+ offset_lmda: 0
+ hm_lmda: 100
+ cstency_lmda: 10
+ mse_reduction: sum
+ ce_reduction: mean
+ optimizer: SAM
+ distributed: False
+ pretrained: ''
+ tensorboard: True
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: True
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+TEST:
+ gpus: [0]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: False
+ pretrained: 'logs/20-02-2023/PoseEfficientNet_EFN_hm100_FPN_Based_CLS_Focal_NoC2_256Cstency10_32FXRayv2_SAM(Adam)_model_best.pth'
+PREPROCESSING:
+ DATASET: FaceForensics
+ SPLIT: train
+ ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c23/
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ IMAGE_SUFFIX: jpg
+ DATA_TYPE: images
+ LABEL: [real, fake]
+ facial_lm_pretrained: pretrained/shape_predictor_68_face_landmarks.dat
+ DEBUG: False
diff --git a/clean/video/fakestormer/configs/spatial/efn4_fpn_hm_adv.yaml b/clean/video/fakestormer/configs/spatial/efn4_fpn_hm_adv.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c97167c6892b2d69b6d5e13c7ac501bef4f958ac
--- /dev/null
+++ b/clean/video/fakestormer/configs/spatial/efn4_fpn_hm_adv.yaml
@@ -0,0 +1,165 @@
+TASK: EFN_hm10_EFPN_NoBasedCLS_Focal_C3_256Cst100_32FXRayv2_SAM(Adam)_ADV_Era1_OutSigmoid_1e7_boost500_UnFZ
+PRECISION: float64
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: True
+DATASET:
+ type: HeatmapFaceForensic
+ DATA_TYPE: image
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c0
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 28
+ PIN_MEMORY: True
+ IMAGE_SIZE: [384, 384]
+ HEATMAP_SIZE: [96, 96] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 2
+ ADAPTIVE_SIGMA: True
+ HEATMAP_TYPE: gaussian
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: frames
+ SAMPLES_PER_VIDEO:
+ ACTIVE: True
+ TRAIN: 32 # Dynamically random number of frames in each epoch
+ VAL: 32
+ TEST: 32
+ DIST: [1., 1.] # Distribution of Real, Fake - 1.,1. by default
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/dynamic_trainBI_FFv2.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures] # Choosing Deepfake techniques to be loaded for dataloader
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/dynamic_valBI_FFv2.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: FF++
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ # ROOT: /project/home/p200249/XXX/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ FROM_FILE: False
+ # FAKETYPE: [original, Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # FAKETYPE: [frames_BW_5/original, frames_BW_5/Deepfakes, frames_BW_5/Face2Face, frames_BW_5/FaceSwap, frames_BW_5/NeuralTextures]
+ FAKETYPE: [frames_JPEG_1/original, frames_JPEG_1/Deepfakes, frames_JPEG_1/Face2Face, frames_JPEG_1/FaceSwap, frames_JPEG_1/NeuralTextures,
+ frames_JPEG_2/original, frames_JPEG_2/Deepfakes, frames_JPEG_2/Face2Face, frames_JPEG_2/FaceSwap, frames_JPEG_2/NeuralTextures,
+ frames_JPEG_3/original, frames_JPEG_3/Deepfakes, frames_JPEG_3/Face2Face, frames_JPEG_3/FaceSwap, frames_JPEG_3/NeuralTextures,
+ frames_JPEG_4/original, frames_JPEG_4/Deepfakes, frames_JPEG_4/Face2Face, frames_JPEG_4/FaceSwap, frames_JPEG_4/NeuralTextures,
+ frames_JPEG_5/original, frames_JPEG_5/Deepfakes, frames_JPEG_5/Face2Face, frames_JPEG_5/FaceSwap, frames_JPEG_5/NeuralTextures]
+ # FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake, real]
+ # FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ # FAKETYPE: [real_test, fake_test]
+ # ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [384, 384, 0] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ cropping: [0.15, 0.5] #Format: [crop_limit, prob]
+ scale: [0.15, 0.5] #Format: [scale_limit, prob]
+ rand_erasing: [0.5, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.5, 0.5, 0.5]
+ std: [0.5, 0.5, 0.5]
+ DEBUG: False
+ DYNAMIC_FXRAY: True
+MODEL:
+ type: PoseEfficientNet
+ model_name: efficientnet-b4
+ num_layers: B4
+ include_top: False
+ include_hm_decoder: True
+ head_conv: 64
+ use_c2: False
+ use_c3: True
+ use_c4: True
+ use_c51: True
+ efpn: True
+ tfpn: False
+ se_layer: False
+ norm_c2: False
+ heads:
+ hm: 1
+ cls: 1
+ cstency: 256
+ INIT_WEIGHTS:
+ pretrained: True
+ advprop: True
+TRAIN:
+ gpus: [0]
+ batch_size: 16
+ lr: 0.0000001
+ epochs: 100
+ begin_epoch: -1
+ warm_up: 6
+ every_val_epochs: 1
+ loss:
+ type: CombinedFocalLoss
+ use_target_weight: False
+ cls_lmda: 1
+ dst_hm_cls_lmda: 0
+ offset_lmda: 0
+ hm_lmda: 10
+ cstency_lmda: 100
+ mse_reduction: sum
+ ce_reduction: mean
+ optimizer: SAM
+ distributed: False
+ pretrained: ''
+ tensorboard: False
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: False
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+TEST:
+ gpus: [0]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: True
+ video_level: True
+ apr: True # Average precision/recall or normal precision/recall
+ no_shot_preds: 1
+ pred_file: /project/home/p200249/XXX/saved_predictions/laanet_wBI_DFDC_100_100.json # File to save predictions
+ save_preds: False
+ pretrained: 'pretrained/PoseEfficientNet_EFN_hm100_EFPN_NoBasedCLS_Focal_C3_256Cst100_8FXRayv2_SAM(Adam)_ADV_Era1_OutSigmoid_5e5_model_best.pth'
diff --git a/clean/video/fakestormer/configs/spatial/efn4_fpn_sbi_adv.yaml b/clean/video/fakestormer/configs/spatial/efn4_fpn_sbi_adv.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..06446a290a2f6c9832faf7dde32eb31cde2afc8e
--- /dev/null
+++ b/clean/video/fakestormer/configs/spatial/efn4_fpn_sbi_adv.yaml
@@ -0,0 +1,180 @@
+TASK: EFN_hm10_EFPN_NoBasedCLS_Focal_C3_256Cst100_8SBI_SAM(Adam)_ADV_Era1_OutSigmoid_1e7_boost500_UnFZ
+PRECISION: float64
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: True
+DATASET:
+ type: SBIFaceForensic
+ DATA_TYPE: image
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c0
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 7
+ PIN_MEMORY: True
+ IMAGE_SIZE: [384, 384]
+ HEATMAP_SIZE: [96, 96] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 2
+ ADAPTIVE_SIGMA: True
+ HEATMAP_TYPE: gaussian
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: frames
+ SAMPLES_PER_VIDEO:
+ ACTIVE: False
+ TRAIN: 8 # Dynamically random number of frames in each epoch
+ VAL: 8
+ TEST: 32
+ DIST: [1., 1.] # Distribution of Real, Fake - 1.,1. by default
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/train_81_FF++_processed.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures] # Choosing Deepfake techniques to be loaded for dataloader
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/val_81_FF++_processed.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: FF++
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ # ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /project/home/p200249/XXX/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ # ROOT: /project/home/p200249/XXX/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ # ROOT: /project/home/p200249/XXX/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ # ROOT: /project/home/p200249/XXX/DFW/
+ # ROOT: /project/home/p200249/XXX/DiffSwap/
+ # ROOT: /project/home/p200249/XXX/DF40_test/
+ FROM_FILE: False
+ # FAKETYPE: [original, Face2Face]
+ # FAKETYPE: [frames_JPEG_1/original, frames_JPEG_1/Deepfakes, frames_JPEG_1/Face2Face, frames_JPEG_1/FaceSwap, frames_JPEG_1/NeuralTextures]
+ FAKETYPE: [frames_JPEG_1/original, frames_JPEG_1/Deepfakes, frames_JPEG_1/Face2Face, frames_JPEG_1/FaceSwap, frames_JPEG_1/NeuralTextures,
+ frames_JPEG_2/original, frames_JPEG_2/Deepfakes, frames_JPEG_2/Face2Face, frames_JPEG_2/FaceSwap, frames_JPEG_2/NeuralTextures,
+ frames_JPEG_3/original, frames_JPEG_3/Deepfakes, frames_JPEG_3/Face2Face, frames_JPEG_3/FaceSwap, frames_JPEG_3/NeuralTextures,
+ frames_JPEG_4/original, frames_JPEG_4/Deepfakes, frames_JPEG_4/Face2Face, frames_JPEG_4/FaceSwap, frames_JPEG_4/NeuralTextures,
+ frames_JPEG_5/original, frames_JPEG_5/Deepfakes, frames_JPEG_5/Face2Face, frames_JPEG_5/FaceSwap, frames_JPEG_5/NeuralTextures]
+ # FAKETYPE: [Celeb-real-0.6-0.8-v2, Celeb-synthesis-0.6-0.8-v2, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake, real]
+ # FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ # FAKETYPE: [fake_test, real_test]
+ # FAKETYPE: [Real_DiffSwap1, DiffSwap_1]
+ # FAKETYPE: [blendface, danet, deepfacelab, e4e, e4s, facedancer, faceswap, facevid2vid, fomm, fsgan, heygen,
+ # hyperreenact, inswap, lia, mcnet, mobileswap, MRAA, one_shot_free, pirender, sadtalker, simswap, tpsm, uniface,
+ # wav2lip, real_videos]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [384, 384, 0] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ cropping: [0.15, 0.5] #Format: [crop_limit, prob]
+ scale: [0.15, 0.5] #Format: [scale_limit, prob]
+ rand_erasing: [0.5, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.5, 0.5, 0.5]
+ std: [0.5, 0.5, 0.5]
+ DEBUG: False
+ DYNAMIC_FXRAY: True
+MODEL:
+ type: PoseEfficientNet
+ model_name: efficientnet-b4
+ num_layers: B4
+ include_top: False
+ include_hm_decoder: True
+ head_conv: 64
+ use_c2: False
+ use_c3: True
+ use_c4: True
+ use_c51: True
+ efpn: True
+ tfpn: False
+ se_layer: False
+ norm_c2: False
+ heads:
+ hm: 1
+ cls: 1
+ cstency: 256
+ INIT_WEIGHTS:
+ pretrained: True
+ advprop: True
+TRAIN:
+ gpus: [0]
+ batch_size: 8
+ lr: 0.0000001
+ epochs: 100
+ begin_epoch: -1
+ warm_up: 6
+ every_val_epochs: 1
+ loss:
+ type: CombinedFocalLoss
+ use_target_weight: False
+ cls_lmda: 1
+ dst_hm_cls_lmda: 0
+ offset_lmda: 0
+ hm_lmda: 10
+ cstency_lmda: 100
+ mse_reduction: sum
+ ce_reduction: mean
+ optimizer: SAM
+ distributed: False
+ pretrained: ''
+ tensorboard: False
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: False
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+ booster: 1
+ start_decay: 8
+TEST:
+ gpus: [0]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: True
+ video_level: True
+ apr: True # Average precision/recall or normal precision/recall
+ no_shot_preds: 1
+ pred_file: /project/home/p200249/XXX/saved_predictions/laanet_DiffSwap_100_100.json # File to save predictions
+ save_preds: True
+ pretrained: pretrained/PoseEfficientNet_EFN_hm100_EFPN_NoBasedCLS_Focal_C3_256Cst100_8FXRayv2_SAM(Adam)_ADV_Era1_OutSigmoid_5e5_model_best.pth
diff --git a/clean/video/fakestormer/configs/spatial/hrnet_sbi.yaml b/clean/video/fakestormer/configs/spatial/hrnet_sbi.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..a7ab3ece0262d23a7ee1e7612d3654e13c8bdc68
--- /dev/null
+++ b/clean/video/fakestormer/configs/spatial/hrnet_sbi.yaml
@@ -0,0 +1,170 @@
+TASK: heatmap_sbi_separated_CLS_Focal_C2
+PRECISION: float64
+METRICS_BASE: combine
+DATASET:
+ type: SBIFaceForensic
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c23/
+ # ROOT: /home/users/XXX/data/FaceForensics++/c23/
+ # FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ IMAGE_SUFFIX: jpg
+ FROM_FILE: True
+ NUM_WORKERS: 8
+ PIN_MEMORY: True
+ IMAGE_SIZE: [384, 384]
+ HEATMAP_SIZE: [96, 96] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 3
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: gaussian
+ DATA:
+ TYPE: images
+ SAMPLES_PER_VIDEO: 32
+ TRAIN:
+ FAKETYPE: [FaceXRay]
+ # ANNO_FILE: FaceXRay/train/train_FF_Xray.json
+ # ANNO_FILE: FaceXRay/train/new_trainBI_FF.json
+ ANNO_FILE: processed_data/new_valBI_FF.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ FAKETYPE: [FaceXRay]
+ # ANNO_FILE: FaceXRay/val/val_FF_Xray.json
+ ANNO_FILE: processed_data/new_valBI_FF.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ FAKETYPE: [FaceXRay]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [256, 256, 0] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ jpegcompression: 0.5
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+ DEBUG: False
+ DYNAMIC_FXRAY: True
+MODEL:
+ type: PoseHighResolutionNet
+ INIT_WEIGHTS:
+ pretrained: 'pretrained/hrnet_w48-8ef0771d.pth'
+ MODEL:
+ NAME: pose_hrnet
+ NUM_JOINTS: 1
+ HEATMAP_SIZE: [96, 96]
+ cls_based_hm: True
+ heads:
+ hm: 1
+ cls: 1
+ EXTRA:
+ PRETRAINED_LAYERS:
+ - 'conv1'
+ - 'bn1'
+ - 'conv2'
+ - 'bn2'
+ - 'layer1'
+ - 'transition1'
+ - 'stage2'
+ - 'transition2'
+ - 'stage3'
+ - 'transition3'
+ - 'stage4'
+ FINAL_CONV_KERNEL: 1
+ STAGE2:
+ NUM_MODULES: 1
+ NUM_BRANCHES: 2
+ BLOCK: BASIC
+ NUM_BLOCKS:
+ - 4
+ - 4
+ NUM_CHANNELS:
+ - 48
+ - 96
+ FUSE_METHOD: SUM
+ STAGE3:
+ NUM_MODULES: 4
+ NUM_BRANCHES: 3
+ BLOCK: BASIC
+ NUM_BLOCKS:
+ - 4
+ - 4
+ - 4
+ NUM_CHANNELS:
+ - 48
+ - 96
+ - 192
+ FUSE_METHOD: SUM
+ STAGE4:
+ NUM_MODULES: 3
+ NUM_BRANCHES: 4
+ BLOCK: BASIC
+ NUM_BLOCKS:
+ - 4
+ - 4
+ - 4
+ - 4
+ NUM_CHANNELS:
+ - 48
+ - 96
+ - 192
+ - 384
+ FUSE_METHOD: SUM
+TRAIN:
+ gpus: [0,1,2]
+ batch_size: 16
+ lr: 0.001
+ epochs: 30
+ begin_epoch: 0
+ warm_up: 5
+ every_val_epochs: 1
+ loss:
+ type: CombinedFocalLoss
+ use_target_weight: False
+ cls_lmda: 0.08
+ # dst_lmda: 0.05
+ reduction: 'mean'
+ # dist_cal: False
+ cls_cal: True
+ combine_compute: False
+ optimizer: SAM
+ distributed: False
+ # pretrained: 'logs/05-12-2022/PoseResNet_heatmap_FPN_Separated_CLS_Focal_NoFrZ_model_best.pth'
+ tensorboard: True
+ resume: False
+ lr_scheduler:
+ type: LinearDecayLR
+ milestones: [5, 12]
+ gamma: 0.5
+ freeze_backbone: False
+ debug:
+ save_hm_gt: True
+ save_hm_pred: True
+TEST:
+ gpus: [0,1,2]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ # pretrained: 'logs/05-12-2022/PoseResNet_heatmap_FPN_Separated_CLS_Focal_NoFrZ_model_best.pth'
+PREPROCESSING:
+ DATASET: FaceForensics
+ SPLIT: train
+ ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c23/
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ IMAGE_SUFFIX: jpg
+ DATA_TYPE: images
+ LABEL: [real, fake]
+ facial_lm_pretrained: pretrained/shape_predictor_68_face_landmarks.dat
+ DEBUG: False
diff --git a/clean/video/fakestormer/configs/spatial/resnet_fpn_hm.yaml b/clean/video/fakestormer/configs/spatial/resnet_fpn_hm.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f9e67ef529105897440753bf399a5f150b693a08
--- /dev/null
+++ b/clean/video/fakestormer/configs/spatial/resnet_fpn_hm.yaml
@@ -0,0 +1,153 @@
+TASK: PoseRes50_100hm_EFPN_NoBased_CLS_Focal_C2_256Cst100_32FXRayv2_SAM(Adam)_Era1_OutSigmoid_5e5_div4_FZ
+PRECISION: float64
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: True
+DATASET:
+ type: HeatmapFaceForensic
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c0
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 7
+ PIN_MEMORY: True
+ IMAGE_SIZE: [256, 256]
+ HEATMAP_SIZE: [64, 64] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 2
+ ADAPTIVE_SIGMA: True
+ HEATMAP_TYPE: gaussian
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: frames
+ SAMPLES_PER_VIDEO:
+ ACTIVE: True
+ TRAIN: 32 # Dynamically random number of frames in each epoch
+ VAL: 32
+ TEST: 32
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/dynamic_trainBI_FFv2.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures] # Choosing Deepfake techniques to be loaded for dataloader
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/dynamic_valBI_FFv2.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: Celeb-DFv1
+ ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /data/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ FROM_FILE: False
+ # FAKETYPE: [original, Deepfakes]
+ # FAKETYPE: [original, Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake, real]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [256, 256, 0] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ cropping: [0.15, 0.5] #Format: [crop_limit, prob]
+ scale: [0.15, 0.5] #Format: [scale_limit, prob]
+ rand_erasing: [0.5, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+ DEBUG: False
+ DYNAMIC_FXRAY: True
+MODEL:
+ type: PoseResNet
+ num_layers: 50
+ block: Bottleneck
+ layers: [3, 4, 6, 3]
+ heads:
+ hm: 1
+ cls: 1
+ cstency: 256
+ head_conv: 64
+ dropout_prob: 0.5
+ fpn: True
+ cls_based_hm: False
+ use_c2: True
+ INIT_WEIGHTS:
+ pretrained: True
+ num_layers: 50
+TRAIN:
+ gpus: [0]
+ batch_size: 32
+ lr: 0.00005
+ epochs: 100
+ begin_epoch: -1
+ warm_up: 6
+ every_val_epochs: 1
+ loss:
+ type: CombinedFocalLoss
+ use_target_weight: False
+ cls_lmda: 1
+ dst_hm_cls_lmda: 0
+ offset_lmda: 0
+ hm_lmda: 100
+ cstency_lmda: 100
+ mse_reduction: sum
+ ce_reduction: mean
+ optimizer: SAM
+ distributed: False
+ # pretrained: ''
+ tensorboard: True
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: True
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+TEST:
+ gpus: [0]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: False
+ pretrained: 'logs/03-03-2023/PoseResNet_PoseRes50_100hm_FPN_NoBased_CLS_Focal_NoC2_256Cstency10_32FXRayv2_SAM(Adam)_NoErasing_model_best.pth'
+PREPROCESSING:
+ DATASET: FaceForensics
+ SPLIT: train
+ ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c23/
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ IMAGE_SUFFIX: jpg
+ DATA_TYPE: images
+ LABEL: [real, fake]
+ facial_lm_pretrained: pretrained/shape_predictor_68_face_landmarks.dat
+ DEBUG: False
diff --git a/clean/video/fakestormer/configs/spatial/resnet_fpn_hm_deepfakes.yaml b/clean/video/fakestormer/configs/spatial/resnet_fpn_hm_deepfakes.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d65e890f6234dde1d303ddf501d80b42893aa3b2
--- /dev/null
+++ b/clean/video/fakestormer/configs/spatial/resnet_fpn_hm_deepfakes.yaml
@@ -0,0 +1,115 @@
+TASK: heatmap_FPN_Separated_CLS_Focal_Deepfakes
+PRECISION: float64
+DATASET:
+ type: HeatmapFaceForensic
+ TRAIN: False #Switch to True for training mode, False for testing mode
+ ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c23/
+ # ROOT: /home/users/XXX/data/FaceForensics++/c23/
+ # FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ IMAGE_SUFFIX: jpg
+ FROM_FILE: False
+ NUM_WORKERS: 14
+ PIN_MEMORY: True
+ IMAGE_SIZE: [256, 256]
+ HEATMAP_SIZE: [64, 64] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 2
+ ADAPTIVE_SIGMA: True
+ HEATMAP_TYPE: gaussian
+ DATA:
+ TYPE: images
+ TRAIN:
+ FAKETYPE: [Deepfakes_FaceXRay]
+ ANNO_FILE: Deepfakes_FaceXRay/val/val_FF_Deepfakes_Xray.json
+ # ANNO_FILE: FaceXRay/train/new_trainBI_FF.json
+ # ANNO_FILE: processed_data/new_valBI_FF.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ FAKETYPE: [Deepfakes_FaceXRay]
+ ANNO_FILE: Deepfakes_FaceXRay/val/val_FF_Deepfakes_Xray.json
+ # ANNO_FILE: processed_data/new_valBI_FF.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ FAKETYPE: [Deepfakes]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [256, 256, 0] # h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.3
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ jpegcompression: 0.5
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+ DEBUG: False
+ DYNAMIC_FXRAY: False
+MODEL:
+ type: PoseResNet
+ num_layers: 50
+ # block: Bottleneck
+ layers: [3, 4, 6, 3]
+ heads:
+ hm: 1
+ cls: 1
+ head_conv: 64
+ dropout_prob: 0.5
+ fpn: True
+ cls_based_hm: False
+ use_c2: False
+TRAIN:
+ gpus: [0,1,2,3]
+ batch_size: 32
+ lr: 0.001
+ epochs: 30
+ begin_epoch: 0
+ warm_up: 6
+ every_val_epochs: 1
+ loss:
+ type: CombinedFocalLoss
+ use_target_weight: False
+ cls_lmda: 1
+ # dst_lmda: 0.05
+ reduction: 'mean'
+ # dist_cal: False
+ cls_cal: True
+ optimizer: Adam
+ distributed: False
+ # pretrained: 'logs/05-12-2022/PoseResNet_heatmap_FPN_Separated_CLS_Focal_NoFrZ_model_best.pth'
+ tensorboard: True
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [6, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: False
+ debug:
+ save_hm_gt: True
+ save_hm_pred: True
+TEST:
+ gpus: [0,1,2,3]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ pretrained: 'logs/08-12-2022/PoseResNet_heatmap_FPN_Separated_CLS_Focal_Deepfakes_model_best.pth'
+PREPROCESSING:
+ DATASET: FaceForensics
+ SPLIT: train
+ ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c23/
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ IMAGE_SUFFIX: jpg
+ DATA_TYPE: images
+ LABEL: [real, fake]
+ facial_lm_pretrained: pretrained/shape_predictor_68_face_landmarks.dat
+ DEBUG: False
diff --git a/clean/video/fakestormer/configs/spatial/resnet_fpn_hmbin.yaml b/clean/video/fakestormer/configs/spatial/resnet_fpn_hmbin.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..65d272ed59ff458c502b37b5645101b844f7932a
--- /dev/null
+++ b/clean/video/fakestormer/configs/spatial/resnet_fpn_hmbin.yaml
@@ -0,0 +1,102 @@
+TASK: heatmapbin
+PRECISION: float64
+DATASET:
+ type: HeatmapFaceForensic
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c23/
+ # FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ IMAGE_SUFFIX: jpg
+ FROM_FILE: True
+ NUM_WORKERS: 8
+ PIN_MEMORY: True
+ IMAGE_SIZE: [256, 256]
+ HEATMAP_SIZE: [64, 64]
+ SIGMA: 2
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: gaussian
+ DATA:
+ TYPE: images
+ TRAIN:
+ FAKETYPE: [FaceXRay]
+ ANNO_FILE: FaceXRay/train/train_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ FAKETYPE: [FaceXRay]
+ ANNO_FILE: FaceXRay/val/val_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ FAKETYPE: [NeuralTextures]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [256, 256, 0] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ color:
+ type: ColorJitterTransform
+ clahe: 0.5
+ colorjitter: 0.5
+ gaussianblur: 0.5
+ jpegcompression: 0.0
+ rgbshift: 0.5
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+ DEBUG: False
+ DYNAMIC_FXRAY: False
+MODEL:
+ type: PoseResNet
+ num_layers: 50
+ # block: Bottleneck
+ layers: [3, 4, 6, 3]
+ heads:
+ hm: 1
+ cls: 1
+ head_conv: 64
+ is_fpn: False
+ dropout_prob: 0.4
+TRAIN:
+ gpus: [0,1,2,3]
+ batch_size: 32
+ lr: 0.001
+ epochs: 30
+ begin_epoch: 0
+ warm_up: 6
+ every_val_epochs: 1
+ loss:
+ type: HeatmapBinaryLoss
+ use_target_weight: False
+ cls_lmda: 0.05
+ reduction: 'mean'
+ cls_cal: True
+ optimizer: Adam
+ distributed: False
+ pretrained: 'logs/23-11-2022/PoseResNet_heatmapbin_model_best.pth'
+ tensorboard: True
+ resume: True
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: True
+ debug:
+ save_hm_gt: True
+ save_hm_pred: True
+TEST:
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ pretrained: 'logs/16-11-2022/PoseResNet_model_best.pth'
+PREPROCESSING:
+ DATASET: FaceForensics
+ SPLIT: train
+ ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c23/
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ IMAGE_SUFFIX: jpg
+ DATA_TYPE: images
+ LABEL: [real, fake]
+ facial_lm_pretrained: pretrained/shape_predictor_68_face_landmarks.dat
+ DEBUG: False
diff --git a/clean/video/fakestormer/configs/spatial/resnet_fpn_sbi.yaml b/clean/video/fakestormer/configs/spatial/resnet_fpn_sbi.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..26793c43cbe38e4883de1e7b40df15dc53978e7b
--- /dev/null
+++ b/clean/video/fakestormer/configs/spatial/resnet_fpn_sbi.yaml
@@ -0,0 +1,133 @@
+TASK: heatmap_sbi_Separated_CLS_Focal_NoC2_50_SoftDISCRE
+PRECISION: float64
+METRICS_BASE: combine
+SEED: 5
+DATASET:
+ type: SBIFaceForensic
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c23/
+ # ROOT: /home/users/XXX/data/FaceForensics++/c23/
+ # FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ IMAGE_SUFFIX: jpg
+ FROM_FILE: True
+ NUM_WORKERS: 4
+ PIN_MEMORY: True
+ IMAGE_SIZE: [256, 256]
+ HEATMAP_SIZE: [64, 64] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 2
+ ADAPTIVE_SIGMA: True
+ HEATMAP_TYPE: gaussian
+ SPLIT_IMAGE: True
+ DATA:
+ TYPE: images
+ SAMPLES_PER_VIDEO:
+ ACTIVE: True
+ TRAIN: 32
+ VAL: 32
+ TEST: 32
+ TRAIN:
+ FAKETYPE: [FaceSBI]
+ # ANNO_FILE: FaceXRay/train/train_FF_Xray.json
+ ANNO_FILE: FaceSBI/train/train_FF_SBI.json
+ ANNO_FILE_R: processed_data/train_81_FF++_processed.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ FAKETYPE: [FaceSBI]
+ ANNO_FILE: FaceSBI/val/val_FF_SBI.json
+ ANNO_FILE_R: processed_data/val_81_FF++_processed.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ FAKETYPE: [FaceSBI]
+ ANNO_FILE_R: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [256, 256, 0] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ #Either Scaling or Cropping, not do at the same time
+ cropping: [0.75, 1.25, 1] #Format: [low, high, prob]
+ scale: [0.1, 0.25, 1] #Format: [shift, scale, prob]
+ erasing: 0.5
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ jpegcompression: 0.5
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+ DEBUG: False
+ DYNAMIC_FXRAY: True
+MODEL:
+ type: PoseResNet
+ num_layers: 50
+ # block: Bottleneck
+ layers: [3, 4, 6, 3]
+ heads:
+ hm: 1
+ cls: 1
+ # offset: 1
+ head_conv: 64
+ dropout_prob: 0.5
+ fpn: True
+ cls_based_hm: False
+ use_c2: False
+ INIT_WEIGHTS:
+ pretrained: True
+ num_layers: 50
+TRAIN:
+ gpus: [0]
+ batch_size: 16
+ lr: 0.0001
+ epochs: 50
+ begin_epoch: 0
+ warm_up: 3
+ every_val_epochs: 1
+ loss:
+ type: CombinedFocalLoss
+ use_target_weight: False
+ cls_lmda: 1
+ dst_hm_cls_lmda: 0.01
+ offset_lmda: 0
+ hm_lmda: 100
+ mse_reduction: sum
+ ce_reduction: mean
+ optimizer: SAM
+ distributed: False
+ # pretrained: 'logs/09-01-2023/PoseResNet_heatmap_sbi_Separated_CLS_Focal_NoC2_50_SoftDISCRE_model_best.pth'
+ tensorboard: True
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [25, 35, 45]
+ gamma: 0.5
+ freeze_backbone: True
+ debug:
+ active: True
+ save_hm_gt: True
+ save_hm_pred: True
+TEST:
+ gpus: [0,1,2,3]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ pretrained: 'logs/28-12-2022/PoseResNet_heatmap_sbi_based_CLS_Focal_C2_101_model_best.pth'
+PREPROCESSING:
+ DATASET: FaceForensics
+ SPLIT: train
+ ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c23/
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ IMAGE_SUFFIX: jpg
+ DATA_TYPE: images
+ LABEL: [real, fake]
+ facial_lm_pretrained: pretrained/shape_predictor_68_face_landmarks.dat
+ DEBUG: False
diff --git a/clean/video/fakestormer/configs/spatial/swin_bi_small.yaml b/clean/video/fakestormer/configs/spatial/swin_bi_small.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..cb9e4009422357c5ab7e9cc3b39a92bdb050ebd3
--- /dev/null
+++ b/clean/video/fakestormer/configs/spatial/swin_bi_small.yaml
@@ -0,0 +1,180 @@
+TASK: SwinSmall224_hm10_16BI_Overlap100_Focal_AdamW_IN_1e7_FZ5_200epochs_Drop0.2_Boost250
+PRECISION: float64
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: True
+
+DATASET:
+ type: FakeSFormerBI
+ DATA_TYPE: image
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c0
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 7
+ PIN_MEMORY: True
+ IMAGE_SIZE: [224, 224]
+ HEATMAP_SIZE: [14, 14] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 1
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: gaussian
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: frames
+ SAMPLES_PER_VIDEO:
+ ACTIVE: True
+ TRAIN: 16 # Dynamically random number of frames in each epoch
+ VAL: 16
+ TEST: 32
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/dynamic_trainBI_FFv2.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures] # Choosing Deepfake techniques to be loaded for dataloader
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/dynamic_valBI_FFv2.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: DFDC
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ # ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /project/home/p200249/XXX/DFDCP/
+ ROOT: /home/users/XXX/data/DFDC/
+ # ROOT: /project/home/p200249/XXX/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ # ROOT: /project/home/p200249/XXX/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ # ROOT: /project/home/p200249/XXX/DFW/
+ FROM_FILE: False
+ # FAKETYPE: [original, Deepfakes]
+ # FAKETYPE: [original, Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ FAKETYPE: [fake, real]
+ # FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ # FAKETYPE: [fake_test, real_test]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [224, 224, 0] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ cropping: [0.15, 0.5] #Format: [crop_limit, prob]
+ scale: [0.15, 0.5] #Format: [scale_limit, prob]
+ rand_erasing: [0.0, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+ DEBUG: False
+ DYNAMIC_FXRAY: True
+ DYNAMIC_BLENDING_PROB: False
+ TARGET_OVERLAP: True
+
+MODEL:
+ type: TopDownDetector
+ backbone:
+ type: SwinTransformer
+ embed_dims: 96
+ depths: [2, 2, 18, 2]
+ num_heads: [3, 6, 12, 24]
+ window_size: 7
+ mlp_ratio: 4
+ qkv_bias: True
+ drop_rate: 0.
+ attn_drop_rate: 0.
+ drop_path_rate: 0.2
+ patch_norm: True
+ with_cp: False
+ convert_weights: True
+ pretrained: pretrained/swin_small_patch4_window7_224_22k.pth
+ keypoint_head:
+ type: TopdownHeatmapSimpleHead
+ in_channels: 768
+ heads:
+ hm: 1
+ cls: 1
+ num_deconv_layers: 1 #Config n deconv layers to build the decoder
+ num_deconv_filters: [768]
+ num_deconv_kernels: [4]
+ loss_keypoint:
+ type: JointsMSELoss
+ use_target_weight: False
+ extra:
+ final_conv_kernel: 3
+ num_conv_layers: 1
+
+TRAIN:
+ gpus: [0]
+ batch_size: 32
+ lr: 0.0000001
+ epochs: 200
+ begin_epoch: -1
+ warm_up: 5
+ every_val_epochs: 1
+ loss:
+ type: CombinedFocalLoss
+ use_target_weight: False
+ cls_lmda: 1
+ dst_hm_cls_lmda: 0
+ offset_lmda: 0
+ hm_lmda: 10
+ cstency_lmda: 0
+ mse_reduction: mean
+ ce_reduction: mean
+ optimizer: AdamW
+ distributed: False
+ pretrained: ''
+ tensorboard: False
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: True
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+ booster: 250
+ start_decay: 4
+
+TEST:
+ gpus: [0]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: True
+ video_level: True
+ pretrained: 'logs/12-03-2024/TopDownDetector_SwinSmall224_hm10_16BI_Overlap100_Focal_AdamW_IN_1e7_FZ5_Batch32_200epochs_Drop0.2_model_best.pth'
diff --git a/clean/video/fakestormer/configs/spatial/swin_sbi_base.yaml b/clean/video/fakestormer/configs/spatial/swin_sbi_base.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..8e902c1e0cd1116b7400a047540401680f58d0a2
--- /dev/null
+++ b/clean/video/fakestormer/configs/spatial/swin_sbi_base.yaml
@@ -0,0 +1,197 @@
+TASK: SwinBase224_hm10_8SBI_NonOverlap100_MSE_AdamW_IN_5e5_FZ5_Batch32_200epochs_Drop0.2
+PRECISION: float64
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: True
+
+DATASET:
+ type: FakeSFormerSBI
+ DATA_TYPE: image
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c0
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 7
+ PIN_MEMORY: True
+ IMAGE_SIZE: [224, 224]
+ HEATMAP_SIZE: [14, 14] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 1
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: gaussian
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: frames
+ SAMPLES_PER_VIDEO:
+ ACTIVE: True
+ TRAIN: 8 # Dynamically random number of frames in each epoch
+ VAL: 8
+ TEST: 32
+ DIST: [1., 1.] # Distribution of Real, Fake - 1.,1. by default
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/train_81_FF++_processed.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures] # Choosing Deepfake techniques to be loaded for dataloader
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/val_81_FF++_processed.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: FF++
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /project/home/p200249/XXX/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ # ROOT: /project/home/p200249/XXX/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ # ROOT: /project/home/p200249/XXX/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ # ROOT: /project/home/p200249/XXX/DFW/
+ # ROOT: /project/home/p200249/XXX/DF40_test/
+ # ROOT: /project/home/p200249/XXX/DiffSwap/
+ FROM_FILE: False
+ # FAKETYPE: [original, Deepfakes]
+ # FAKETYPE: [original, Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ FAKETYPE: [original_pixel_random, Deepfakes_pixel_random, Face2Face_pixel_random, FaceSwap_pixel_random, NeuralTextures_pixel_random]
+ # FAKETYPE: [frames_CS_1/original, frames_CS_1/Deepfakes, frames_CS_1/Face2Face, frames_CS_1/FaceSwap, frames_CS_1/NeuralTextures,
+ # frames_CS_2/original, frames_CS_2/Deepfakes, frames_CS_2/Face2Face, frames_CS_2/FaceSwap, frames_CS_2/NeuralTextures,
+ # frames_CS_3/original, frames_CS_3/Deepfakes, frames_CS_3/Face2Face, frames_CS_3/FaceSwap, frames_CS_3/NeuralTextures,
+ # frames_CS_4/original, frames_CS_4/Deepfakes, frames_CS_4/Face2Face, frames_CS_4/FaceSwap, frames_CS_4/NeuralTextures,
+ # frames_CS_5/original, frames_CS_5/Deepfakes, frames_CS_5/Face2Face, frames_CS_5/FaceSwap, frames_CS_5/NeuralTextures]
+ # FAKETYPE: [Celeb-real-0.97-1.0-v2, Celeb-synthesis-0.97-1.0-v2, YouTube-real]
+ # FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake, real]
+ # FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ # FAKETYPE: [fake_test, real_test]
+ # FAKETYPE: [mobileswap, real_videos]
+ # FAKETYPE: [Real_DiffSwap1, DiffSwap_1]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [224, 224, 0] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ cropping: [0.15, 0.5] #Format: [crop_limit, prob]
+ scale: [0.15, 0.5] #Format: [scale_limit, prob]
+ rand_erasing: [0.0, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+ DEBUG: False
+ DYNAMIC_FXRAY: True
+ DYNAMIC_BLENDING_PROB: False
+ TARGET_OVERLAP: False
+
+MODEL:
+ type: TopDownDetector
+ backbone:
+ type: SwinTransformer
+ embed_dims: 128
+ depths: [2, 2, 18, 2]
+ num_heads: [4, 8, 16, 32]
+ window_size: 7
+ mlp_ratio: 4
+ qkv_bias: True
+ drop_rate: 0.
+ attn_drop_rate: 0.
+ drop_path_rate: 0.2
+ patch_norm: True
+ with_cp: False
+ convert_weights: True
+ # pretrained: pretrained/swin_base_patch4_window7_224_22k.pth
+ keypoint_head:
+ type: TopdownHeatmapSimpleHead
+ in_channels: 512
+ heads:
+ hm: 1
+ cls: 1
+ num_deconv_layers: 0 #Config n deconv layers to build the decoder
+ num_deconv_filters: [512]
+ num_deconv_kernels: [4]
+ loss_keypoint:
+ type: JointsMSELoss
+ use_target_weight: False
+ extra:
+ final_conv_kernel: 3
+ num_conv_layers: 1
+ INIT_WEIGHTS:
+ pretrained: pretrained/swin_base_patch4_window7_224_22k.pth
+
+TRAIN:
+ gpus: [0,1,2,3]
+ batch_size: 32
+ lr: 0.00005
+ epochs: 200
+ begin_epoch: -1
+ warm_up: 5
+ every_val_epochs: 1
+ loss:
+ type: CombinedMSELoss
+ use_target_weight: False
+ cls_lmda: 1
+ dst_hm_cls_lmda: 0
+ offset_lmda: 0
+ hm_lmda: 10
+ cstency_lmda: 0
+ mse_reduction: mean
+ ce_reduction: mean
+ optimizer: AdamW
+ distributed: False
+ pretrained: ''
+ tensorboard: False
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: True
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+
+TEST:
+ gpus: [0]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: True
+ video_level: True
+ apr: True # Average precision/recall or normal precision/recall
+ no_shot_preds: 1
+ pred_file: /project/home/p200249/XXX/saved_predictions/FakeSwin-B_DiffSwap_100_100.json # File to save predictions
+ save_preds: False
+ pretrained: pretrained/fakeformer/TopDownDetector_SwinBase224_hm10_8SBI_NonOverlap100_MSE_AdamW_MAE_5e5_FZ5_Batch32_200epochs_Drop0.2_model_best.pth
diff --git a/clean/video/fakestormer/configs/spatial/swin_sbi_small.yaml b/clean/video/fakestormer/configs/spatial/swin_sbi_small.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..790ea28721e73bf191bc566add146f436bb9b5d5
--- /dev/null
+++ b/clean/video/fakestormer/configs/spatial/swin_sbi_small.yaml
@@ -0,0 +1,201 @@
+TASK: SwinSmall224_hm10_8SBI_Overlap100_Focal_AdamW_IN22k_1e3_FZ5_Cutout_abl
+PRECISION: float64
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: True
+
+DATASET:
+ type: FakeSFormerSBI
+ DATA_TYPE: image
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c0
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 7
+ PIN_MEMORY: True
+ IMAGE_SIZE: [224, 224]
+ HEATMAP_SIZE: [14, 14] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 1
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: gaussian
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: frames
+ SAMPLES_PER_VIDEO:
+ ACTIVE: True
+ TRAIN: 8 # Dynamically random number of frames in each epoch
+ VAL: 8
+ TEST: 32
+ DIST: [1., 1.] # Distribution of Real, Fake - 1.,1. by default
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/train_81_FF++_processed.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures] # Choosing Deepfake techniques to be loaded for dataloader
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/val_81_FF++_processed.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: FF++
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ # ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /project/home/p200249/XXX/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ # ROOT: /project/home/p200249/XXX/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ # ROOT: /project/home/p200249/XXX/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ # ROOT: /project/home/p200249/XXX/DFW/
+ # ROOT: /project/home/p200249/XXX/DF40_test/
+ # ROOT: /project/home/p200249/XXX/DiffSwap/
+ # ROOT: /home/users/XXX/data/Combine/
+ FROM_FILE: False
+ # FAKETYPE: [original, Deepfakes]
+ FAKETYPE: [original, Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # FAKETYPE: [original_pixel_random, Deepfakes_pixel_random, Face2Face_pixel_random, FaceSwap_pixel_random, NeuralTextures_pixel_random]
+ # FAKETYPE: [Celeb-real-0.6-0.8-v2, Celeb-synthesis-0.6-0.8-v2, YouTube-real]
+ # FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake, real]
+ # FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ # FAKETYPE: [fake_test, real_test]
+ # FAKETYPE: [Celeb_DFv1-real, Celeb_DFv2-real, DeepFakeDetection, Deepfakes, FaceSwap, method_A, NeuralTextures,
+ # original_videos, YouTube_DFv1-real, Celeb_DFv1-synthesis, Celeb_DFv2-synthesis, DeepFakeDetection_original, Face2Face,
+ # fake_test, method_B, original, real_test, YouTube_DFv2-real]
+ # FAKETYPE: [e4s, real_videos]
+ # FAKETYPE: [Real_DiffSwap1, DiffSwap_1]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [224, 224, 0] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ cropping: [0.15, 0.5] #Format: [crop_limit, prob]
+ scale: [0.15, 0.5] #Format: [scale_limit, prob]
+ rand_erasing: [0.5, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+ DEBUG: False
+ DYNAMIC_FXRAY: True
+ DYNAMIC_BLENDING_PROB: False
+ TARGET_OVERLAP: True
+
+MODEL:
+ type: TopDownDetector
+ backbone:
+ type: SwinTransformer
+ embed_dims: 96
+ depths: [2, 2, 18, 2]
+ num_heads: [3, 6, 12, 24]
+ window_size: 7
+ mlp_ratio: 4
+ qkv_bias: True
+ drop_rate: 0.
+ attn_drop_rate: 0.
+ drop_path_rate: 0.2
+ patch_norm: True
+ with_cp: False
+ convert_weights: True
+ # pretrained: pretrained/swin_small_patch4_window7_224.pth
+ keypoint_head:
+ type: TopdownHeatmapSimpleHead
+ in_channels: 768
+ heads:
+ # hm: 1
+ cls: 1
+ num_deconv_layers: 1 #Config n deconv layers to build the decoder
+ num_deconv_filters: [384]
+ num_deconv_kernels: [4]
+ loss_keypoint:
+ type: JointsMSELoss
+ use_target_weight: False
+ extra:
+ final_conv_kernel: 3
+ num_conv_layers: 1
+ INIT_WEIGHTS:
+ pretrained: pretrained/swin_small_patch4_window7_224_22k.pth
+
+TRAIN:
+ gpus: [0,1,2,3]
+ batch_size: 32
+ lr: 0.001
+ epochs: 100
+ begin_epoch: -1
+ warm_up: 5
+ every_val_epochs: 1
+ accumulation_steps: 1
+ use_amp: False
+ loss:
+ type: CombinedFocalLoss # For L2-Att
+ use_target_weight: False
+ cls_lmda: 1
+ dst_hm_cls_lmda: 0
+ offset_lmda: 0
+ hm_lmda: 10
+ cstency_lmda: 0
+ mse_reduction: mean
+ ce_reduction: mean
+ # type: BinaryCrossEntropy # For binary only
+ # reduction: mean
+ optimizer: AdamW
+ distributed: False
+ pretrained: ''
+ tensorboard: False
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: True
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+ booster: 1
+ start_decay: 10
+
+TEST:
+ gpus: [0]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: True
+ video_level: True
+ apr: True # Average precision/recall or normal precision/recall
+ no_shot_preds: 1
+ pred_file: /project/home/p200249/XXX/saved_predictions/FakeSwin_CDF2_100_100.json # File to save predictions
+ save_preds: False
+ pretrained: logs/29-10-2025/TopDownDetector_SwinSmall224_hm0_8SBI_Overlap100_BCE_AdamW_IN22k_5e4_FZ5_0Cutout_abl_model_best.pth
diff --git a/clean/video/fakestormer/configs/spatial/swin_sbi_tiny.yaml b/clean/video/fakestormer/configs/spatial/swin_sbi_tiny.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..276608e93755f9942473eacf0a8502d791865358
--- /dev/null
+++ b/clean/video/fakestormer/configs/spatial/swin_sbi_tiny.yaml
@@ -0,0 +1,178 @@
+TASK: SwinTiny224_hm10_16SBI_Overlap100_MSE_AdamW_IN_5e5_FZ5_Batch32_200epochs_Drop0.2
+PRECISION: float64
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: True
+
+DATASET:
+ type: FakeSFormerSBI
+ DATA_TYPE: image
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c0
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 32
+ PIN_MEMORY: True
+ IMAGE_SIZE: [224, 224]
+ HEATMAP_SIZE: [14, 14] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 1
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: gaussian
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: frames
+ SAMPLES_PER_VIDEO:
+ ACTIVE: True
+ TRAIN: 16 # Dynamically random number of frames in each epoch
+ VAL: 16
+ TEST: 32
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/train_81_FF++_processed.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures] # Choosing Deepfake techniques to be loaded for dataloader
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/val_81_FF++_processed.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: Celeb-DFv2
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ # ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /project/home/p200249/XXX/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ # ROOT: /project/home/p200249/XXX/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ # ROOT: /project/home/p200249/XXX/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ # ROOT: /project/home/p200249/XXX/DFW/
+ FROM_FILE: False
+ # FAKETYPE: [original, Deepfakes]
+ # FAKETYPE: [original, Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake, real]
+ # FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ # FAKETYPE: [fake_test, real_test]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [224, 224, 0] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ cropping: [0.15, 0.5] #Format: [crop_limit, prob]
+ scale: [0.15, 0.5] #Format: [scale_limit, prob]
+ rand_erasing: [0.0, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+ DEBUG: False
+ DYNAMIC_FXRAY: True
+ DYNAMIC_BLENDING_PROB: False
+ TARGET_OVERLAP: True
+
+MODEL:
+ type: TopDownDetector
+ backbone:
+ type: SwinTransformer
+ embed_dims: 96
+ depths: [2, 2, 6, 2]
+ num_heads: [3, 6, 12, 24]
+ window_size: 7
+ mlp_ratio: 4
+ qkv_bias: True
+ drop_rate: 0.
+ attn_drop_rate: 0.
+ drop_path_rate: 0.2
+ patch_norm: True
+ with_cp: False
+ convert_weights: True
+ pretrained: pretrained/swin_tiny_patch4_window7_224.pth
+ keypoint_head:
+ type: TopdownHeatmapSimpleHead
+ in_channels: 768
+ heads:
+ hm: 1
+ cls: 1
+ num_deconv_layers: 1 #Config n deconv layers to build the decoder
+ num_deconv_filters: [384]
+ num_deconv_kernels: [4]
+ loss_keypoint:
+ type: JointsMSELoss
+ use_target_weight: False
+ extra:
+ final_conv_kernel: 3
+ num_conv_layers: 1
+
+TRAIN:
+ gpus: [0,1,2,3]
+ batch_size: 32
+ lr: 0.00005
+ epochs: 200
+ begin_epoch: -1
+ warm_up: 5
+ every_val_epochs: 1
+ loss:
+ type: CombinedMSELoss
+ use_target_weight: False
+ cls_lmda: 1
+ dst_hm_cls_lmda: 0
+ offset_lmda: 0
+ hm_lmda: 10
+ cstency_lmda: 0
+ mse_reduction: mean
+ ce_reduction: mean
+ optimizer: AdamW
+ distributed: False
+ pretrained: ''
+ tensorboard: False
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: True
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+
+TEST:
+ gpus: [0,1,2,3]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: True
+ video_level: True
+ pretrained: 'logs/12-01-2024/TopDownDetector_SwinTiny224_hm10_32SBI_Overlap100_MSE_AdamW_IN_5e5_FZ5_Batch32_200epochs_Drop0.2_model_best.pth'
diff --git a/clean/video/fakestormer/configs/spatial/vit_bi_small.yaml b/clean/video/fakestormer/configs/spatial/vit_bi_small.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d226cff7e98ca824575e916f422dc6bc46a2825c
--- /dev/null
+++ b/clean/video/fakestormer/configs/spatial/vit_bi_small.yaml
@@ -0,0 +1,184 @@
+TASK: ViTSmall112_hm100_32BI_Overlap100_MSE_AdamW_5e5_FZ5_Batch32_200epochs_Drop0.2
+PRECISION: float64
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: True
+
+DATASET:
+ type: FakeSFormerBI
+ DATA_TYPE: image
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c0
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 7
+ PIN_MEMORY: True
+ IMAGE_SIZE: [112, 112]
+ HEATMAP_SIZE: [14, 14] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 1
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: gaussian
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: frames
+ SAMPLES_PER_VIDEO:
+ ACTIVE: False
+ TRAIN: 32 # Dynamically random number of frames in each epoch
+ VAL: 32
+ TEST: 32
+ DIST: [1., 1.] # Distribution of Real, Fake - 1.,1. by default
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/dynamic_trainBI_FFv2.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures] # Choosing Deepfake techniques to be loaded for dataloader
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/dynamic_valBI_FFv2.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: DFW
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ # ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /project/home/p200249/XXX/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ # ROOT: /project/home/p200249/XXX/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ # ROOT: /project/home/p200249/XXX/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ ROOT: /project/home/p200249/XXX/DFW/
+ FROM_FILE: False
+ # FAKETYPE: [original, Deepfakes]
+ # FAKETYPE: [original, Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake, real]
+ # FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ FAKETYPE: [fake_test, real_test]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [112, 112, 0] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ cropping: [0.15, 0.5] #Format: [crop_limit, prob]
+ scale: [0.15, 0.5] #Format: [scale_limit, prob]
+ rand_erasing: [0.5, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+ DEBUG: False
+ DYNAMIC_FXRAY: True
+ DYNAMIC_BLENDING_PROB: False
+ TARGET_OVERLAP: True
+
+MODEL:
+ type: TopDownDetector
+ backbone:
+ type: ViT
+ img_size: [112, 112]
+ patch_size: 8
+ embed_dim: 384
+ depth: 12
+ num_heads: 6
+ mlp_ratio: 4
+ drop_path_rate: 0.2
+ qkv_bias: True
+ class_token: True
+ # pretrained: pretrained/dino_deitsmall8_pretrain.pth
+ keypoint_head:
+ type: TopdownHeatmapSimpleHead
+ in_channels: 384
+ heads:
+ hm: 1
+ cls: 1
+ num_deconv_layers: 0 #Config n deconv layers to build the decoder
+ num_deconv_filters: [256, 256]
+ num_deconv_kernels: [4, 4]
+ loss_keypoint:
+ type: JointsMSELoss
+ use_target_weight: False
+ extra:
+ final_conv_kernel: 3
+ num_conv_layers: 1
+ INIT_WEIGHTS:
+ pretrained: pretrained/dino_deitsmall8_pretrain.pth
+
+TRAIN:
+ gpus: [0,1,2,3]
+ batch_size: 32
+ lr: 0.00005
+ epochs: 200
+ begin_epoch: -1
+ warm_up: 5
+ every_val_epochs: 1
+ accumulation_steps: 1
+ use_amp: False
+ loss:
+ type: CombinedFocalLoss
+ use_target_weight: False
+ cls_lmda: 1
+ dst_hm_cls_lmda: 0
+ offset_lmda: 0
+ hm_lmda: 0
+ cstency_lmda: 0
+ mse_reduction: mean
+ ce_reduction: mean
+ optimizer: AdamW
+ distributed: False
+ pretrained: ''
+ tensorboard: False
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: True
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+
+TEST:
+ gpus: [0]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: True
+ video_level: True
+ apr: True # Average precision/recall or normal precision/recall
+ no_shot_preds: 1
+ pred_file: /project/home/p200249/XXX/saved_predictions/FakeFormer_wBI_DFW_100_100.json # File to save predictions
+ save_preds: True
+ pretrained: pretrained/fakeformer/TopDownDetector_ViTSmall112_hm10_8SBI_Overlap100_MSE_AdamW_IN_5e5_FZ5_Batch32_200epochs_Drop0.2_Decay1e4_model_best.pth
diff --git a/clean/video/fakestormer/configs/spatial/vit_sbi_base.yaml b/clean/video/fakestormer/configs/spatial/vit_sbi_base.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f0225675a083abde4da6dfe9779e5a0c98fa09b4
--- /dev/null
+++ b/clean/video/fakestormer/configs/spatial/vit_sbi_base.yaml
@@ -0,0 +1,187 @@
+TASK: ViTBase224_hm10_8SBI_NonOverlap100_MSE_AdamW_IN_5e5_FZ5_Batch32_200epochs_Drop0.3
+PRECISION: float64
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: True
+
+DATASET:
+ type: FakeSFormerSBI
+ DATA_TYPE: image
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c0
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 7
+ PIN_MEMORY: True
+ IMAGE_SIZE: [224, 224]
+ HEATMAP_SIZE: [14, 14] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 1
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: gaussian
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: frames
+ SAMPLES_PER_VIDEO:
+ ACTIVE: True
+ TRAIN: 8 # Dynamically random number of frames in each epoch
+ VAL: 8
+ TEST: 32
+ DIST: [1., 1.] # Distribution of Real, Fake - 1.,1. by default
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/train_81_FF++_processed.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures] # Choosing Deepfake techniques to be loaded for dataloader
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/val_81_FF++_processed.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: DiffSwap
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ # ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /project/home/p200249/XXX/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ # ROOT: /project/home/p200249/XXX/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ # ROOT: /project/home/p200249/XXX/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ # ROOT: /project/home/p200249/XXX/DFW/
+ ROOT: /project/home/p200249/XXX/DiffSwap/
+ # ROOT: /project/home/p200249/XXX/DF40_test/
+ FROM_FILE: False
+ # FAKETYPE: [original, Deepfakes]
+ # FAKETYPE: [original, Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # FAKETYPE: [Celeb-real-0.6-0.8-v2, Celeb-synthesis-0.6-0.8-v2, YouTube-real]
+ # FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake, real]
+ # FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ # FAKETYPE: [fake_test, real_test]
+ FAKETYPE: [Real_DiffSwap1, DiffSwap_1]
+ # FAKETYPE: [mobileswap, real_videos]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [224, 224, 0] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ cropping: [0.15, 0.5] #Format: [crop_limit, prob]
+ scale: [0.15, 0.5] #Format: [scale_limit, prob]
+ rand_erasing: [0.0, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+ DEBUG: False
+ DYNAMIC_FXRAY: True
+ DYNAMIC_BLENDING_PROB: False
+ TARGET_OVERLAP: False
+
+MODEL:
+ type: TopDownDetector
+ backbone:
+ type: ViT
+ img_size: [224, 224]
+ patch_size: 16
+ embed_dim: 768
+ depth: 12
+ num_heads: 12
+ mlp_ratio: 4
+ drop_path_rate: 0.3
+ qkv_bias: True
+ class_token: True
+ # pretrained: pretrained/dino_vitbase16_pretrain.pth
+ keypoint_head:
+ type: TopdownHeatmapSimpleHead
+ in_channels: 768
+ heads:
+ hm: 1
+ cls: 1
+ num_deconv_layers: 0 #Config n deconv layers to build the decoder
+ num_deconv_filters: [256, 256]
+ num_deconv_kernels: [4, 4]
+ loss_keypoint:
+ type: JointsMSELoss
+ use_target_weight: False
+ extra:
+ final_conv_kernel: 3
+ num_conv_layers: 1
+ INIT_WEIGHTS:
+ pretrained: pretrained/dino_vitbase16_pretrain.pth
+
+TRAIN:
+ gpus: [0,1,2,3]
+ batch_size: 32
+ lr: 0.00005
+ epochs: 200
+ begin_epoch: -1
+ warm_up: 5
+ every_val_epochs: 1
+ loss:
+ type: CombinedMSELoss
+ use_target_weight: False
+ cls_lmda: 1
+ dst_hm_cls_lmda: 0
+ offset_lmda: 0
+ hm_lmda: 10
+ cstency_lmda: 0
+ mse_reduction: mean
+ ce_reduction: mean
+ optimizer: AdamW
+ distributed: False
+ pretrained: ''
+ tensorboard: False
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: True
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+
+TEST:
+ gpus: [0]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: True
+ video_level: True
+ apr: True # Average precision/recall or normal precision/recall
+ no_shot_preds: 1
+ pred_file: /project/home/p200249/XXX/saved_predictions/FakeFormer-B_DiffSwap_100_100.json # File to save predictions
+ save_preds: True
+ pretrained: pretrained/fakeformer/TopDownDetector_ViTBase224_hm10_8SBI_NonOverlap100_MSE_AdamW_IN_5e5_FZ5_Batch32_200epochs_Drop0.3_model_best.pth
diff --git a/clean/video/fakestormer/configs/spatial/vit_sbi_large.yaml b/clean/video/fakestormer/configs/spatial/vit_sbi_large.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..59767190e46178ebd8df4ffd2b32a8260fc4e7c4
--- /dev/null
+++ b/clean/video/fakestormer/configs/spatial/vit_sbi_large.yaml
@@ -0,0 +1,171 @@
+TASK: ViTLarge224_hm1_8SBI_NonOverlap100_MSE_AdamW_MAE_1e4_FZ5_Batch16_200epochs
+PRECISION: float64
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: True
+
+DATASET:
+ type: FakeSFormerSBI
+ DATA_TYPE: image
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c0
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 36
+ PIN_MEMORY: True
+ IMAGE_SIZE: [224, 224]
+ HEATMAP_SIZE: [14, 14] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 1
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: gaussian
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: frames
+ SAMPLES_PER_VIDEO:
+ ACTIVE: True
+ TRAIN: 8 # Dynamically random number of frames in each epoch
+ VAL: 8
+ TEST: 32
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/train_81_FF++_processed.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures] # Choosing Deepfake techniques to be loaded for dataloader
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/val_81_FF++_processed.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: Celeb-DFv1
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /home/users/XXX/data/Celeb-DFv1/
+ ROOT: /project/home/p200249/XXX/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /project/home/p200249/XXX/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ # ROOT: /project/home/p200249/XXX/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ FROM_FILE: False
+ # FAKETYPE: [original, Deepfakes]
+ # FAKETYPE: [original, Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake, real]
+ # FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ # FAKETYPE: [fake_test, real_test]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [224, 224, 0] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ cropping: [0.15, 0.5] #Format: [crop_limit, prob]
+ scale: [0.15, 0.5] #Format: [scale_limit, prob]
+ rand_erasing: [0.0, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+ DEBUG: False
+ DYNAMIC_FXRAY: True
+ DYNAMIC_BLENDING_PROB: False
+ TARGET_OVERLAP: False
+
+MODEL:
+ type: TopDownDetector
+ backbone:
+ type: ViT
+ img_size: [224, 224]
+ patch_size: 16
+ embed_dim: 1024
+ depth: 24
+ num_heads: 16
+ mlp_ratio: 4
+ qkv_bias: True
+ class_token: True
+ pretrained: pretrained/mae_pretrain_vit_large.pth
+ keypoint_head:
+ type: TopdownHeatmapSimpleHead
+ in_channels: 1024
+ heads:
+ hm: 1
+ cls: 1
+ num_deconv_layers: 0 #Config n deconv layers to build the decoder
+ num_deconv_filters: [256, 256]
+ num_deconv_kernels: [4, 4]
+ loss_keypoint:
+ type: JointsMSELoss
+ use_target_weight: False
+ extra:
+ final_conv_kernel: 3
+ num_conv_layers: 1
+
+TRAIN:
+ gpus: [0,1,2,3]
+ batch_size: 16
+ lr: 0.0001
+ epochs: 200
+ begin_epoch: -1
+ warm_up: 5
+ every_val_epochs: 1
+ loss:
+ type: CombinedMSELoss
+ use_target_weight: False
+ cls_lmda: 1
+ dst_hm_cls_lmda: 0
+ offset_lmda: 0
+ hm_lmda: 1
+ cstency_lmda: 0
+ mse_reduction: mean
+ ce_reduction: mean
+ optimizer: AdamW
+ distributed: False
+ pretrained: ''
+ tensorboard: False
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: True
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+
+TEST:
+ gpus: [0]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: True
+ video_level: True
+ pretrained: 'logs/14-12-2023/TopDownDetector_ViTLarge224_hm1_8SBI_NonOverlap100_MSE_AdamW_MAE_1e4_FZ5_Batch16_200epochs_model_best.pth'
diff --git a/clean/video/fakestormer/configs/spatial/vit_sbi_small.yaml b/clean/video/fakestormer/configs/spatial/vit_sbi_small.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..ff45c683c4c794646a289dd86494d6a6c9b87bac
--- /dev/null
+++ b/clean/video/fakestormer/configs/spatial/vit_sbi_small.yaml
@@ -0,0 +1,208 @@
+TASK: ViTSmall112_hm0_8SBI_Overlap100_BCE_AdamW_IN22k_5e4_FZ5_0Cutout_abl
+PRECISION: float64
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: True
+
+DATASET:
+ type: FakeSFormerSBI
+ DATA_TYPE: image
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c0
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 7
+ PIN_MEMORY: True
+ IMAGE_SIZE: [112, 112]
+ HEATMAP_SIZE: [14, 14] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 1
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: gaussian
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: frames
+ SAMPLES_PER_VIDEO:
+ ACTIVE: True
+ TRAIN: 8 # Dynamically random number of frames in each epoch
+ VAL: 8
+ TEST: 32
+ DIST: [1., 1.] # Distribution of Real, Fake - 1.,1. by default
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/train_81_FF++_processed.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures] # Choosing Deepfake techniques to be loaded for dataloader
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/val_81_FF++_processed.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: DFD
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /project/home/p200249/XXX/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ # ROOT: /project/home/p200249/XXX/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ ROOT: /project/home/p200249/XXX/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ # ROOT: /project/home/p200249/XXX/DFW/
+ # ROOT: /project/home/p200249/XXX/DF40_test/
+ # ROOT: /project/home/p200249/XXX/DiffSwap/
+ # ROOT: /home/users/XXX/data/Combine/
+ FROM_FILE: False
+ # FAKETYPE: [original, Deepfakes]
+ # FAKETYPE: [original, Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # FAKETYPE: [original_pixel_random, Deepfakes_pixel_random, Face2Face_pixel_random, FaceSwap_pixel_random, NeuralTextures_pixel_random]
+ # FAKETYPE: [frames_JPEG_1/original, frames_JPEG_1/Deepfakes, frames_JPEG_1/Face2Face, frames_JPEG_1/FaceSwap, frames_JPEG_1/NeuralTextures,
+ # frames_JPEG_2/original, frames_JPEG_2/Deepfakes, frames_JPEG_2/Face2Face, frames_JPEG_2/FaceSwap, frames_JPEG_2/NeuralTextures,
+ # frames_JPEG_3/original, frames_JPEG_3/Deepfakes, frames_JPEG_3/Face2Face, frames_JPEG_3/FaceSwap, frames_JPEG_3/NeuralTextures,
+ # frames_JPEG_4/original, frames_JPEG_4/Deepfakes, frames_JPEG_4/Face2Face, frames_JPEG_4/FaceSwap, frames_JPEG_4/NeuralTextures,
+ # frames_JPEG_5/original, frames_JPEG_5/Deepfakes, frames_JPEG_5/Face2Face, frames_JPEG_5/FaceSwap, frames_JPEG_5/NeuralTextures]
+ # FAKETYPE: [Celeb-real-0.97-1.0-v2, Celeb-synthesis-0.97-1.0-v2, YouTube-real]
+ # FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake, real]
+ FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ # FAKETYPE: [fake_test, real_test]
+ # FAKETYPE: [blendface, danet, deepfacelab, e4e, e4s, facedancer, faceswap, facevid2vid, fomm, fsgan, heygen,
+ # hyperreenact, inswap, lia, mcnet, mobileswap, MRAA, one_shot_free, pirender, sadtalker, simswap, tpsm, uniface,
+ # wav2lip, real_videos]
+ # FAKETYPE: [Real_DiffSwap1, DiffSwap_1]
+ # FAKETYPE: [Celeb_DFv1-real, Celeb_DFv2-real, DeepFakeDetection, Deepfakes, FaceSwap, method_A, NeuralTextures,
+ # original_videos, YouTube_DFv1-real, Celeb_DFv1-synthesis, Celeb_DFv2-synthesis, DeepFakeDetection_original, Face2Face,
+ # fake_test, method_B, original, real_test, YouTube_DFv2-real]
+ # FAKETYPE: [fomm, real_videos]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [112, 112, 0] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ cropping: [0.15, 0.5] #Format: [crop_limit, prob]
+ scale: [0.15, 0.5] #Format: [scale_limit, prob]
+ rand_erasing: [0.0, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+ DEBUG: False
+ DYNAMIC_FXRAY: True
+ DYNAMIC_BLENDING_PROB: False
+ TARGET_OVERLAP: True
+
+MODEL:
+ type: TopDownDetector
+ backbone:
+ type: ViT
+ img_size: [112, 112]
+ patch_size: 8
+ embed_dim: 384
+ depth: 12
+ num_heads: 6
+ mlp_ratio: 4
+ drop_path_rate: 0.2
+ qkv_bias: True
+ class_token: True
+ keypoint_head:
+ type: TopdownHeatmapSimpleHead
+ in_channels: 384
+ heads:
+ hm: 1
+ cls: 1
+ num_deconv_layers: 0 #Config n deconv layers to build the decoder
+ num_deconv_filters: [256]
+ num_deconv_kernels: [4]
+ loss_keypoint:
+ type: JointsMSELoss
+ use_target_weight: False
+ extra:
+ final_conv_kernel: 3
+ num_conv_layers: 1
+ # conv_2direction: False
+ # features: 2D
+ INIT_WEIGHTS:
+ pretrained: pretrained/dino_deitsmall8_pretrain.pth
+
+TRAIN:
+ gpus: [0,1,2,3]
+ batch_size: 32
+ lr: 0.0005
+ epochs: 100
+ begin_epoch: -1
+ warm_up: 5
+ every_val_epochs: 1
+ accumulation_steps: 1
+ use_amp: False
+ loss:
+ # type: CombinedFocalLoss # For L2-Att
+ # use_target_weight: False
+ # cls_lmda: 1
+ # dst_hm_cls_lmda: 0
+ # offset_lmda: 0
+ # hm_lmda: 10
+ # cstency_lmda: 0
+ # mse_reduction: mean
+ # ce_reduction: mean
+ type: BinaryCrossEntropy # For binary only
+ reduction: mean
+ optimizer: AdamW
+ distributed: False
+ pretrained: ''
+ tensorboard: False
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: True
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+ booster: 1
+ start_decay: 10
+
+TEST:
+ gpus: [0]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: True
+ video_level: True
+ apr: True # Average precision/recall or normal precision/recall
+ no_shot_preds: 1
+ pred_file: /project/home/p200249/XXX/saved_predictions/FakeFormer_DF40_FOMM_100_100.json # File to save predictions
+ save_preds: False
+ pretrained: logs/30-10-2025/TopDownDetector_ViTSmall112_hm10_8SBI_Overlap100_Focal_AdamW_IN22k_1e3_FZ5_Cutout_abl_model_best.pth
diff --git a/clean/video/fakestormer/configs/spatial/xception_sbi.yaml b/clean/video/fakestormer/configs/spatial/xception_sbi.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c1f14d7c86d8e7d7d682571ff845c07f6856bb27
--- /dev/null
+++ b/clean/video/fakestormer/configs/spatial/xception_sbi.yaml
@@ -0,0 +1,169 @@
+TASK: Xception_bin_sbi_abl
+PRECISION: float64
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: True
+
+DATASET:
+ type: FakeSFormerSBI
+ DATA_TYPE: image
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c0
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 28
+ PIN_MEMORY: True
+ IMAGE_SIZE: [299, 299]
+ HEATMAP_SIZE: [96, 96] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 3
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: gaussian
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: frames
+ SAMPLES_PER_VIDEO:
+ ACTIVE: True
+ TRAIN: 8 # Dynamically random number of frames in each epoch
+ VAL: 8
+ TEST: 32
+ DIST: [1., 1.] # Distribution of Real, Fake - 1.,1. by default
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/train_81_FF++_processed.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures] # Choosing Deepfake techniques to be loaded for dataloader
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/val_81_FF++_processed.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: Celeb-DFv2
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ # ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /project/home/p200249/XXX/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ # ROOT: /project/home/p200249/XXX/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ # ROOT: /project/home/p200249/XXX/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ # ROOT: /project/home/p200249/XXX/DFW/
+ # ROOT: /home/users/XXX/data/Combine/
+ FROM_FILE: False
+ # FAKETYPE: [original, Deepfakes]
+ # FAKETYPE: [original, Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ FAKETYPE: [Celeb-real-0.95-0.97-v2, Celeb-synthesis-0.95-0.97-v2, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake, real]
+ # FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ # FAKETYPE: [fake_test, real_test]
+ # FAKETYPE: [Celeb_DFv1-real, Celeb_DFv2-real, DeepFakeDetection, Deepfakes, FaceSwap, method_A, NeuralTextures,
+ # original_videos, YouTube_DFv1-real, Celeb_DFv1-synthesis, Celeb_DFv2-synthesis, DeepFakeDetection_original, Face2Face,
+ # fake_test, method_B, original, real_test, YouTube_DFv2-real]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [380, 380, 0] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ #Either Scaling or Cropping, not do at the same time
+ cropping: [0.15, 0.5] #Format: [crop_limit, prob]
+ scale: [0.15, 0.5] #Format: [scale_limit, prob]
+ rand_erasing: [0.5, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.5, 0.5, 0.5]
+ std: [0.5, 0.5, 0.5]
+ DEBUG: False
+ DYNAMIC_FXRAY: True
+ DYNAMIC_BLENDING_PROB: False
+ TARGET_OVERLAP: True
+
+MODEL:
+ type: TopDownDetector
+ backbone:
+ type: Xception
+ keypoint_head:
+ type: TopdownHeatmapSimpleHead
+ in_channels: 2048
+ heads:
+ cls: 1
+ num_deconv_layers: 0 #Config n deconv layers to build the decoder
+ num_deconv_filters: [256]
+ num_deconv_kernels: [4]
+ loss_keypoint:
+ type: JointsMSELoss
+ use_target_weight: False
+ INIT_WEIGHTS:
+ pretrained: True
+
+TRAIN:
+ gpus: [0,1,2,3]
+ batch_size: 32
+ lr: 0.0001
+ epochs: 100
+ begin_epoch: -1
+ warm_up: 5
+ every_val_epochs: 1
+ accumulation_steps: 1
+ use_amp: False
+ loss:
+ type: BinaryCrossEntropy
+ reduction: mean
+ optimizer: SAM
+ distributed: False
+ pretrained: ''
+ tensorboard: False
+ resume: False
+ lr_scheduler:
+ # type: LinearDecayLR
+ milestones: [30]
+ gamma: 0.5
+ freeze_backbone: True
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+ booster: 1
+ start_decay: 4
+TEST:
+ gpus: [0]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: True
+ video_level: True
+ apr: True # Average precision/recall or normal precision/recall
+ no_shot_preds: 1
+ pred_file: /project/home/p200249/XXX/saved_predictions/FakeFormer_DF40_90_10.json # File to save predictions
+ save_preds: False # VERY CAREFUL
+ pretrained: logs/15-09-2025/TopDownDetector_Xception_bin_sbi_abl_model_best.pth
diff --git a/clean/video/fakestormer/configs/temporal/FakeSFormer_base_c0.yaml b/clean/video/fakestormer/configs/temporal/FakeSFormer_base_c0.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d8e84ea97c9a09a078b6ecc5706c1a874853f24b
--- /dev/null
+++ b/clean/video/fakestormer/configs/temporal/FakeSFormer_base_c0.yaml
@@ -0,0 +1,213 @@
+TASK: C0_ViTBase224_ST_hm100_tempLOC0.2_4SBI_SAM_mp0.01_temp2_0vidAug_0.25_temp_normlmsFT_IN_1e7
+PRECISION: float64
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: True
+
+DATASET:
+ type: FakeSFormerSBI
+ DATA_TYPE: video
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c0
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 28
+ PIN_MEMORY: True
+ IMAGE_SIZE: [224, 224]
+ HEATMAP_SIZE: [14, 14] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 1
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: m_std_normalized
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: videos # We employ "sequential sampling" as "videos" type for Training while "uniform sampling" as "frames" type for Testing
+ SAMPLES_PER_VIDEO:
+ ACTIVE: True
+ TRAIN: 4 # Dynamically random number of frames in each epoch
+ VAL: 4
+ TEST: 4
+ NUM_FRAMES: 4
+ DIST: [1., 1.] # Distribution of Real, Fake - 1.,1. by default
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/train_FF++_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures] # Choosing Deepfake techniques to be loaded for dataloader
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/val_FF++_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: Celeb-DFv2
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ # ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /project/home/p200249/XXX/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ # ROOT: /project/home/p200249/XXX/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ # ROOT: /project/home/p200249/XXX/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ # ROOT: /project/home/p200249/XXX/DFW/
+ # ROOT: /project/home/p200249/XXX/DeeperForensics/
+ # ROOT: /project/home/p200249/XXX/DiffSwap/
+ # ROOT: /project/home/p200249/XXX/DF40_test/
+ FROM_FILE: False
+ # FAKETYPE: [original, Deepfakes]
+ # FAKETYPE: [original, Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake, real]
+ # FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ # FAKETYPE: [fake_test, real_test]
+ # FAKETYPE: [fake_val, real_val]
+ # FAKETYPE: [DFo_source_videos, DFo_manipulated_videos]
+ # FAKETYPE: [Real_DiffSwap1, DiffSwap_1]
+ # FAKETYPE: [blendface, danet, deepfacelab, e4e, e4s, facedancer, faceswap, facevid2vid, fomm, fsgan, heygen,
+ # hyperreenact, inswap, lia, mcnet, mobileswap, MRAA, one_shot_free, pirender, sadtalker, simswap, tpsm, uniface,
+ # wav2lip, real_videos]
+ # FAKETYPE: [mobileswap, real_videos]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [224, 224, 0] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ cropping: [0.15, 0.] #Format: [crop_limit, prob]
+ scale: [0.15, 0.] #Format: [scale_limit, prob]
+ rand_erasing: [0.0, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+ DEBUG: False
+ DYNAMIC_FXRAY: True
+ DYNAMIC_BLENDING_PROB: True # Normally only use for temporal modeling
+ TARGET_OVERLAP: True
+ MASK_PROB: 0.01
+ TEMP_MASKOUT: False
+
+MODEL:
+ type: TopDownDetector
+ backbone:
+ type: TimeViT
+ img_size: [224, 224]
+ patch_size: 16
+ embed_dim: 768
+ depth: 12
+ num_heads: 12
+ mlp_ratio: 4
+ drop_path_rate: 0.3
+ qkv_bias: True
+ class_token: True
+ register_token: False
+ temp_token: True
+ attention_type: divided_space_time #joint_space_time, space_only
+ num_frames: 4
+ low_level_enhanced: False
+ keypoint_head:
+ type: TopdownHeatmapSimpleHead
+ in_channels: 768
+ hm_size: [14, 14] #img_size // patch_size
+ heads:
+ hm: 1
+ cls: 1
+ temp_loc: 4
+ # num_deconv_layers: 0 #Config n deconv layers to build the decoder
+ # num_deconv_filters: [256, 256]
+ # num_deconv_kernels: [4, 4]
+ loss_keypoint:
+ type: JointsMSELoss
+ use_target_weight: False
+ extra:
+ final_conv_kernel: 3
+ num_conv_layers: 1
+ conv_2direction: False
+ use_temp_token: True
+ features: 3D
+ avg_pool: False
+ INIT_WEIGHTS:
+ pretrained: pretrained/mae_pretrain_vit_base.pth
+
+TRAIN:
+ gpus: [0,1,2,3]
+ batch_size: 16
+ lr: 0.0000001
+ epochs: 120
+ begin_epoch: -1
+ warm_up: 5
+ every_val_epochs: 1
+ accumulation_steps: 1
+ use_amp: False
+ loss:
+ type: CombinedMSELoss
+ use_target_weight: False
+ cls_lmda: 0.8
+ dst_hm_cls_lmda: 0
+ offset_lmda: 0
+ hm_lmda: 100
+ cstency_lmda: 0
+ tmp_loc_lmda: 0.2
+ mse_reduction: mean
+ ce_reduction: mean
+ use_ce: False
+ temperature: 2
+ optimizer: SAM
+ distributed: False
+ pretrained: ''
+ tensorboard: False
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: True
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+ booster: 500
+ start_decay: 4
+
+TEST:
+ gpus: [0]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: False
+ video_level: True
+ apr: True # Average precision/recall or normal precision/recall
+ no_shot_preds: 1
+ pred_file: /project/home/p200249/XXX/saved_predictions/fakestormer_DF40_90_10.json # File to save predictions
+ save_preds: False
+ pretrained: logs/03-12-2024/TopDownDetector_C0_ViTBase224_ST_hm100_tempLOC0.2_4SBI_SAM_mp0.01_temp2_0vidAug_0.35_temp_normlms_IN_model_best.pth
diff --git a/clean/video/fakestormer/configs/temporal/FakeSFormer_base_c23.yaml b/clean/video/fakestormer/configs/temporal/FakeSFormer_base_c23.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..54659169bc7ab430d5a8fc175a839912419f6d98
--- /dev/null
+++ b/clean/video/fakestormer/configs/temporal/FakeSFormer_base_c23.yaml
@@ -0,0 +1,206 @@
+TASK: C23_ViTBase224_ST_hm100_tempLOC0.2_4SBI_SAM_mp0.01_temp2_0vidAug_0.25_temp_0normlms_0CSP_spatialHead
+PRECISION: float64
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: True
+
+DATASET:
+ type: FakeSFormerSBI
+ DATA_TYPE: video
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c23
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 32
+ PIN_MEMORY: True
+ IMAGE_SIZE: [224, 224]
+ HEATMAP_SIZE: [14, 14] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 1
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: m_std_normalized
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: videos # We employ "sequential sampling" as "videos" type for Training while "uniform sampling" as "frames" type for Testing (better results)
+ SAMPLES_PER_VIDEO:
+ ACTIVE: True
+ TRAIN: 4 # Dynamically random number of frames in each epoch
+ VAL: 4
+ TEST: 4
+ NUM_FRAMES: 4
+ DIST: [1., 1.] # Distribution of Real, Fake - 1.,1. by default
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c23/train_FaceForensics_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures] # Choosing Deepfake techniques to be loaded for dataloader
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c23/val_FaceForensics_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: Celeb-DFv2
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /project/home/p200249/XXX/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ # ROOT: /project/home/p200249/XXX/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ # ROOT: /project/home/p200249/XXX/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ # ROOT: /project/home/p200249/XXX/DFW/
+ # ROOT: /project/home/p200249/XXX/DeeperForensics/
+ # ROOT: /project/home/p200249/XXX/DiffSwap/
+ FROM_FILE: False
+ # FAKETYPE: [original, Deepfakes]
+ # FAKETYPE: [frames_BW_5/original, frames_BW_5/Deepfakes, frames_BW_5/Face2Face, frames_BW_5/FaceSwap, frames_BW_5/NeuralTextures]
+ FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake, real]
+ # FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ # FAKETYPE: [fake_test, real_test]
+ # FAKETYPE: [DFo_source_videos, DFo_manipulated_videos]
+ # FAKETYPE: [Real_DiffSwap1, DiffSwap_1]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [224, 224, 0] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ cropping: [0.15, 0.] #Format: [crop_limit, prob]
+ scale: [0.15, 0.] #Format: [scale_limit, prob]
+ rand_erasing: [0.0, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+ DEBUG: False
+ DYNAMIC_FXRAY: True
+ DYNAMIC_BLENDING_PROB: True # Normally only use for temporal modeling
+ TARGET_OVERLAP: True
+ MASK_PROB: 0.01
+ TEMP_MASKOUT: False
+
+MODEL:
+ type: TopDownDetector
+ backbone:
+ type: TimeViT
+ img_size: [224, 224]
+ patch_size: 16
+ embed_dim: 768
+ depth: 12
+ num_heads: 12
+ mlp_ratio: 4
+ drop_path_rate: 0.3
+ qkv_bias: True
+ class_token: True
+ register_token: False
+ temp_token: True
+ attention_type: divided_space_time #joint_space_time, space_only
+ num_frames: 4
+ low_level_enhanced: False
+ keypoint_head:
+ type: TopdownHeatmapSimpleHead
+ in_channels: 768
+ hm_size: [14, 14] #img_size // patch_size
+ heads:
+ hm: 1
+ cls: 1
+ temp_loc: 4
+ # num_deconv_layers: 0 #Config n deconv layers to build the decoder
+ # num_deconv_filters: [256, 256]
+ # num_deconv_kernels: [4, 4]
+ loss_keypoint:
+ type: JointsMSELoss
+ use_target_weight: False
+ extra:
+ final_conv_kernel: 3
+ num_conv_layers: 1
+ conv_2direction: False
+ use_temp_token: True
+ features: 3D
+ avg_pool: False
+ INIT_WEIGHTS:
+ pretrained: pretrained/mae_pretrain_vit_base.pth
+
+TRAIN:
+ gpus: [0,1,2,3]
+ batch_size: 16
+ lr: 0.0000001
+ epochs: 200
+ begin_epoch: -1
+ warm_up: 5
+ every_val_epochs: 1
+ accumulation_steps: 1
+ use_amp: False
+ loss:
+ type: CombinedMSELoss
+ use_target_weight: False
+ cls_lmda: 0.8
+ dst_hm_cls_lmda: 0
+ offset_lmda: 0
+ hm_lmda: 100
+ cstency_lmda: 0
+ tmp_loc_lmda: 0.2
+ mse_reduction: mean
+ ce_reduction: mean
+ use_ce: False
+ temperature: 2
+ optimizer: SAM
+ distributed: False
+ pretrained: ''
+ tensorboard: False
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: True
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+ booster: 500
+ start_decay: 4
+
+TEST:
+ gpus: [0]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: False
+ video_level: True
+ apr: True # Average precision/recall or normal precision/recall
+ no_shot_preds: 1
+ pred_file: /project/home/p200249/XXX/saved_predictions/fakestormer_DF40_90_10.json # File to save predictions
+ save_preds: False
+ pretrained: 'logs/20-10-2024_FakeSTomer_gassian_abl/TopDownDetector_C23_ViTBase224_ST_hm100_tempLOC0.2_4SBI_SAM_mp0.01_temp2_0vidAug_0.35_temp_normlms_gaussian_abl_model_best.pth'
diff --git a/clean/video/fakestormer/configs/temporal/FakeSFormer_base_c23_224p8.yaml b/clean/video/fakestormer/configs/temporal/FakeSFormer_base_c23_224p8.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..3679e8e20865552398673c876e26debc34a5cf96
--- /dev/null
+++ b/clean/video/fakestormer/configs/temporal/FakeSFormer_base_c23_224p8.yaml
@@ -0,0 +1,200 @@
+TASK: C23_ViTBase224p8_ST_hm10_tempLOC0.2_4SBI_SAM_mp0.01_temp2_0vidAug_0.35_temp_normlms_normREAL
+PRECISION: float64
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: True
+
+DATASET:
+ type: FakeSFormerSBI
+ DATA_TYPE: video
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c23
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 32
+ PIN_MEMORY: True
+ IMAGE_SIZE: [224, 224]
+ HEATMAP_SIZE: [28, 28] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 1
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: m_std_normalized
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: videos # We employ "sequential sampling" as "videos" type for Training while "uniform sampling" as "frames" type for Testing
+ SAMPLES_PER_VIDEO:
+ ACTIVE: True
+ TRAIN: 4 # Dynamically random number of frames in each epoch
+ VAL: 4
+ TEST: 4
+ NUM_FRAMES: 4
+ DIST: [1., 1.] # Distribution of Real, Fake - 1.,1. by default
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c23/train_FaceForensics_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures] # Choosing Deepfake techniques to be loaded for dataloader
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c23/val_FaceForensics_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: Celeb-DFv2
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /project/home/p200249/XXX/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ # ROOT: /project/home/p200249/XXX/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ # ROOT: /project/home/p200249/XXX/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ # ROOT: /project/home/p200249/XXX/DFW/
+ # ROOT: /project/home/p200249/XXX/DeeperForensics/
+ FROM_FILE: False
+ # FAKETYPE: [original, Deepfakes]
+ # FAKETYPE: [frames_BW_5/original, frames_BW_5/Deepfakes, frames_BW_5/Face2Face, frames_BW_5/FaceSwap, frames_BW_5/NeuralTextures]
+ FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake, real]
+ # FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ # FAKETYPE: [fake_test, real_test]
+ # FAKETYPE: [DFo_source_videos, DFo_manipulated_videos]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [224, 224, 0] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ cropping: [0.15, 0.] #Format: [crop_limit, prob]
+ scale: [0.15, 0.] #Format: [scale_limit, prob]
+ rand_erasing: [0.0, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+ DEBUG: False
+ DYNAMIC_FXRAY: True
+ DYNAMIC_BLENDING_PROB: True # Normally only use for temporal modeling
+ TARGET_OVERLAP: True
+ MASK_PROB: 0.01
+ TEMP_MASKOUT: False
+
+MODEL:
+ type: TopDownDetector
+ backbone:
+ type: TimeViT
+ img_size: [224, 224]
+ patch_size: 8
+ embed_dim: 768
+ depth: 12
+ num_heads: 12
+ mlp_ratio: 4
+ drop_path_rate: 0.3
+ qkv_bias: True
+ class_token: True
+ register_token: False
+ temp_token: True
+ attention_type: divided_space_time #joint_space_time, space_only
+ num_frames: 4
+ low_level_enhanced: False
+ keypoint_head:
+ type: TopdownHeatmapSimpleHead
+ in_channels: 768
+ hm_size: [14, 14] #img_size // patch_size
+ heads:
+ hm: 1
+ cls: 1
+ temp_loc: 4
+ num_deconv_layers: 0 #Config n deconv layers to build the decoder
+ num_deconv_filters: [256, 256]
+ num_deconv_kernels: [4, 4]
+ loss_keypoint:
+ type: JointsMSELoss
+ use_target_weight: False
+ extra:
+ final_conv_kernel: 3
+ num_conv_layers: 1
+ conv_2direction: False
+ use_temp_token: True
+ features: 3D
+ INIT_WEIGHTS:
+ pretrained: pretrained/dino_vitbase8_pretrain.pth
+
+TRAIN:
+ gpus: [0,1,2,3]
+ batch_size: 2
+ lr: 0.00005
+ epochs: 100
+ begin_epoch: -1
+ warm_up: 6
+ every_val_epochs: 1
+ accumulation_steps: 8
+ use_amp: True
+ loss:
+ type: CombinedMSELoss
+ use_target_weight: False
+ cls_lmda: 0.8
+ dst_hm_cls_lmda: 0
+ offset_lmda: 0
+ hm_lmda: 10
+ cstency_lmda: 0
+ tmp_loc_lmda: 0.2
+ mse_reduction: mean
+ ce_reduction: mean
+ use_ce: False
+ temperature: 2
+ optimizer: AdamW
+ distributed: False
+ pretrained: ''
+ tensorboard: False
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: True
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+ booster: 1
+ start_decay: 2.5
+
+TEST:
+ gpus: [0]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: False
+ video_level: True
+ no_shot_preds: 1
+ pretrained: 'logs/13-09-2024_BestOVA_FakeSTormer/TopDownDetector_C23_ViTBase224_ST_hm100_tempLOC0.2_4SBI_SAM_mp0.01_temp2_0vidAug_0.35_temp_normlms_normREAL_model_best.pth'
diff --git a/clean/video/fakestormer/configs/temporal/FakeSFormer_base_c40.yaml b/clean/video/fakestormer/configs/temporal/FakeSFormer_base_c40.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..2013d6fd2673904a1227e86530ddb2425c0ac83f
--- /dev/null
+++ b/clean/video/fakestormer/configs/temporal/FakeSFormer_base_c40.yaml
@@ -0,0 +1,203 @@
+TASK: C40_ViTBase224_ST_hm100_tempLOC0.1_4SBI_SAM_mp0.01_temp2_0vidAug_0.35_temp_normlms_normREALtarget
+PRECISION: float64
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: True
+
+DATASET:
+ type: FakeSFormerSBI
+ DATA_TYPE: video
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c40
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 32
+ PIN_MEMORY: True
+ IMAGE_SIZE: [224, 224]
+ HEATMAP_SIZE: [14, 14] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 1
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: m_std_normalized
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: videos # We employ "sequential sampling" as "videos" type for Training while "uniform sampling" as "frames" type for Testing (better results)
+ SAMPLES_PER_VIDEO:
+ ACTIVE: True
+ TRAIN: 4 # Dynamically random number of frames in each epoch
+ VAL: 4
+ TEST: 4
+ NUM_FRAMES: 4
+ DIST: [1., 1.] # Distribution of Real, Fake - 1.,1. by default
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c40/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c40/train_FaceForensics_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c40/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures] # Choosing Deepfake techniques to be loaded for dataloader
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c40/val_FaceForensics_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: FF++
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c40/
+ # ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /project/home/p200249/XXX/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ # ROOT: /project/home/p200249/XXX/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ # ROOT: /project/home/p200249/XXX/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ # ROOT: /project/home/p200249/XXX/DFW/
+ # ROOT: /project/home/p200249/XXX/DeeperForensics/
+ FROM_FILE: False
+ FAKETYPE: [original, Deepfakes]
+ # FAKETYPE: [videos_BW_5/original, videos_BW_5/Deepfakes, videos_BW_5/Face2Face, videos_BW_5/FaceSwap, videos_BW_5/NeuralTextures]
+ # FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake, real]
+ # FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ # FAKETYPE: [fake_test, real_test]
+ # FAKETYPE: [DFo_source_videos, DFo_manipulated_videos]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [224, 224, 0] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ cropping: [0.15, 0.] #Format: [crop_limit, prob]
+ scale: [0.15, 0.] #Format: [scale_limit, prob]
+ rand_erasing: [0.0, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+ DEBUG: False
+ DYNAMIC_FXRAY: True
+ DYNAMIC_BLENDING_PROB: True # Normally only use for temporal modeling
+ TARGET_OVERLAP: True
+ MASK_PROB: 0.01
+ TEMP_MASKOUT: False
+
+MODEL:
+ type: TopDownDetector
+ backbone:
+ type: TimeViT
+ img_size: [224, 224]
+ patch_size: 16
+ embed_dim: 768
+ depth: 12
+ num_heads: 12
+ mlp_ratio: 4
+ drop_path_rate: 0.3
+ qkv_bias: True
+ class_token: True
+ register_token: False
+ temp_token: True
+ attention_type: divided_space_time #joint_space_time, space_only
+ num_frames: 4
+ low_level_enhanced: False
+ keypoint_head:
+ type: TopdownHeatmapSimpleHead
+ in_channels: 768
+ hm_size: [14, 14] #img_size // patch_size
+ heads:
+ hm: 1
+ cls: 1
+ temp_loc: 4
+ num_deconv_layers: 0 #Config n deconv layers to build the decoder
+ num_deconv_filters: [256, 256]
+ num_deconv_kernels: [4, 4]
+ loss_keypoint:
+ type: JointsMSELoss
+ use_target_weight: False
+ extra:
+ final_conv_kernel: 3
+ num_conv_layers: 1
+ conv_2direction: False
+ use_temp_token: True
+ features: 3D
+ INIT_WEIGHTS:
+ pretrained: pretrained/mae_pretrain_vit_base.pth
+
+TRAIN:
+ gpus: [0,1,2,3]
+ batch_size: 16
+ lr: 0.00005
+ epochs: 100
+ begin_epoch: -1
+ warm_up: 3
+ every_val_epochs: 1
+ accumulation_steps: 1
+ use_amp: False
+ loss:
+ type: CombinedMSELoss
+ use_target_weight: False
+ cls_lmda: 0.9
+ dst_hm_cls_lmda: 0
+ offset_lmda: 0
+ hm_lmda: 100
+ cstency_lmda: 0
+ tmp_loc_lmda: 0.1
+ mse_reduction: mean
+ ce_reduction: mean
+ use_ce: False
+ temperature: 2
+ optimizer: SAM
+ distributed: False
+ pretrained: ''
+ tensorboard: False
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: True
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+ booster: 1
+ start_decay: 2.5
+
+TEST:
+ gpus: [0]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: False
+ video_level: True
+ no_shot_preds: 1
+ pretrained: 'logs/13-09-2024/TopDownDetector_C40_ViTBase224_ST_hm100_tempLOC0.1_4SBI_SAM_mp0.01_temp2_0vidAug_0.35_temp_normlms_normREALtarget_model_best.pth'
diff --git a/clean/video/fakestormer/configs/temporal/FakeSFormer_large_c23.yaml b/clean/video/fakestormer/configs/temporal/FakeSFormer_large_c23.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..bbc6cbd4e406e56f67175357ac9767cbd510b666
--- /dev/null
+++ b/clean/video/fakestormer/configs/temporal/FakeSFormer_large_c23.yaml
@@ -0,0 +1,198 @@
+TASK: ViTLarge224_ST_hm100_tempLOC0.2_4SBI_AdamW_mp0.01_temp2_reload_0vidAug
+PRECISION: float64
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: True
+
+DATASET:
+ type: FakeSFormerSBI
+ DATA_TYPE: video
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c23
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 32
+ PIN_MEMORY: True
+ IMAGE_SIZE: [224, 224]
+ HEATMAP_SIZE: [14, 14] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 1
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: m_std_normalized
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: videos # We employ "sequential sampling" as "videos" type for Training while "uniform sampling" as "frames" type for Testing (better results)
+ SAMPLES_PER_VIDEO:
+ ACTIVE: True
+ TRAIN: 4 # Dynamically random number of frames in each epoch
+ VAL: 4
+ TEST: 4
+ NUM_FRAMES: 4
+ DIST: [1., 1.] # Distribution of Real, Fake - 1.,1. by default
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c23/train_FaceForensics_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures] # Choosing Deepfake techniques to be loaded for dataloader
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c23/val_FaceForensics_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: Celeb-DFv2
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /project/home/p200249/XXX/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ # ROOT: /project/home/p200249/XXX/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ # ROOT: /project/home/p200249/XXX/DeeperForensics/
+ FROM_FILE: False
+ # FAKETYPE: [original, Face2Face, FaceSwap, NeuralTextures]
+ # FAKETYPE: [original, Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake, real]
+ # FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ # FAKETYPE: [fake_test, real_test]
+ # FAKETYPE: [DFo_source_videos, DFo_manipulated_videos]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [224, 224, 0] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ cropping: [0.15, 0.] #Format: [crop_limit, prob]
+ scale: [0.15, 0.] #Format: [scale_limit, prob]
+ rand_erasing: [0.0, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+ DEBUG: False
+ DYNAMIC_FXRAY: True
+ DYNAMIC_BLENDING_PROB: True # Normally only use for temporal modeling
+ TARGET_OVERLAP: True
+ MASK_PROB: 0.01
+ TEMP_MASKOUT: False
+
+MODEL:
+ type: TopDownDetector
+ backbone:
+ type: TimeViT
+ img_size: [224, 224]
+ patch_size: 16
+ embed_dim: 1024
+ depth: 24
+ num_heads: 16
+ mlp_ratio: 4
+ drop_path_rate: 0.3
+ qkv_bias: True
+ class_token: True
+ register_token: False
+ temp_token: True
+ attention_type: divided_space_time #joint_space_time, space_only
+ num_frames: 4
+ low_level_enhanced: False
+ keypoint_head:
+ type: TopdownHeatmapSimpleHead
+ in_channels: 1024
+ hm_size: [14, 14] #img_size // patch_size
+ heads:
+ hm: 1
+ cls: 1
+ temp_loc: 4
+ num_deconv_layers: 0 #Config n deconv layers to build the decoder
+ num_deconv_filters: [256, 256]
+ num_deconv_kernels: [4, 4]
+ loss_keypoint:
+ type: JointsMSELoss
+ use_target_weight: False
+ extra:
+ final_conv_kernel: 3
+ num_conv_layers: 1
+ conv_2direction: False
+ use_temp_token: True
+ features: 3D
+ INIT_WEIGHTS:
+ pretrained: pretrained/mae_pretrain_vit_large.pth
+
+TRAIN:
+ gpus: [0,1,2,3]
+ batch_size: 4
+ lr: 0.00005
+ epochs: 100
+ begin_epoch: -1
+ warm_up: 6
+ every_val_epochs: 1
+ accumulation_steps: 4
+ use_amp: True
+ loss:
+ type: CombinedMSELoss
+ use_target_weight: False
+ cls_lmda: 0.8
+ dst_hm_cls_lmda: 0
+ offset_lmda: 0
+ hm_lmda: 100
+ cstency_lmda: 0
+ tmp_loc_lmda: 0.2
+ mse_reduction: mean
+ ce_reduction: mean
+ use_ce: False
+ temperature: 2
+ optimizer: AdamW
+ distributed: False
+ pretrained: ''
+ tensorboard: False
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: True
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+ booster: 1
+ start_decay: 4
+
+TEST:
+ gpus: [0]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: False
+ video_level: True
+ no_shot_preds: 1
+ pretrained: ''
diff --git a/clean/video/fakestormer/configs/temporal/FakeSFormer_small.yaml b/clean/video/fakestormer/configs/temporal/FakeSFormer_small.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..ffd117d57f7a18cb55dc0da3f66b000142c04ba9
--- /dev/null
+++ b/clean/video/fakestormer/configs/temporal/FakeSFormer_small.yaml
@@ -0,0 +1,187 @@
+TASK: ViTSmall112_ST_hm10_tempLOC0.1_4SBI_DymIntens_MSE_AdamW_5e5_boost1_mp0.01_discrete_fsdyn_fullSA_m_std
+PRECISION: float64
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: False
+
+DATASET:
+ type: FakeSFormerSBI
+ DATA_TYPE: video
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c0
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 32
+ PIN_MEMORY: True
+ IMAGE_SIZE: [112, 112]
+ HEATMAP_SIZE: [14, 14] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 1
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: m_std_normalized
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: videos # frames or videos
+ SAMPLES_PER_VIDEO:
+ ACTIVE: True
+ TRAIN: 4 # Dynamically random number of frames in each epoch
+ VAL: 4
+ TEST: 4
+ NUM_FRAMES: 4
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/train_FF++_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c0/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures] # Choosing Deepfake techniques to be loaded for dataloader
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/val_FF++_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: FF++
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200328/XXX/data/FaceForensics++/c23/
+ # ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ # ROOT: /project/home/p200328/XXX/data/Celeb-DFv2/
+ # ROOT: /project/home/p200328/XXX/data/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ FROM_FILE: False
+ FAKETYPE: [original, NeuralTextures]
+ # FAKETYPE: [original, Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake, real]
+ # FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ # FAKETYPE: [fake_test, real_test]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [112, 112, 0] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0
+ cropping: [0.15, 0] #Format: [crop_limit, prob]
+ scale: [0.15, 0] #Format: [scale_limit, prob]
+ rand_erasing: [0.0, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+ DEBUG: False
+ DYNAMIC_FXRAY: True
+ DYNAMIC_BLENDING_PROB: True # Normally only use for temporal modeling
+ TARGET_OVERLAP: True
+ MASK_PROB: 0.01
+
+MODEL:
+ type: TopDownDetector
+ backbone:
+ type: TimeViT
+ img_size: [112, 112]
+ patch_size: 8
+ embed_dim: 384
+ depth: 12
+ num_heads: 6
+ mlp_ratio: 4
+ drop_path_rate: 0.3
+ qkv_bias: True
+ class_token: True
+ register_token: True
+ attention_type: divided_space_time #joint_space_time, space_only
+ num_frames: 8
+ pretrained: pretrained/dino_deitsmall8_pretrain.pth
+ keypoint_head:
+ type: TopdownHeatmapSimpleHead
+ in_channels: 384
+ hm_size: [14, 14] #img_size // patch_size
+ heads:
+ hm: 1
+ cls: 1
+ temp_loc: 4
+ num_deconv_layers: 0 #Config n deconv layers to build the decoder
+ num_deconv_filters: [256, 256]
+ num_deconv_kernels: [4, 4]
+ loss_keypoint:
+ type: JointsMSELoss
+ use_target_weight: False
+ extra:
+ final_conv_kernel: 3
+ num_conv_layers: 1
+ conv_2direction: True
+ use_temp_token: True
+ features: 3D
+
+TRAIN:
+ gpus: [0,1,2,3]
+ batch_size: 4
+ lr: 0.00005
+ epochs: 200
+ begin_epoch: -1
+ warm_up: 3
+ every_val_epochs: 1
+ loss:
+ type: CombinedMSELoss
+ use_target_weight: False
+ cls_lmda: 1
+ dst_hm_cls_lmda: 0
+ offset_lmda: 0
+ hm_lmda: 10
+ cstency_lmda: 0
+ tmp_loc_lmda: 0.1
+ mse_reduction: mean
+ ce_reduction: mean
+ use_ce: False
+ optimizer: AdamW
+ distributed: False
+ pretrained: ''
+ tensorboard: False
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: True
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+ booster: 1
+ start_decay: 4
+
+TEST:
+ gpus: [0]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: False
+ video_level: True
+ no_shot_preds: 3
+ pretrained: 'logs/18-07-2024/TopDownDetector_ViTSmall112_ST_hm10_tempLOC0.1_4SBI_DymIntens_MSE_SAM(AdamW)_5e5_boost1_mp0.01_discrete_fsdyn_fullSA_m_std_model_best.pth'
diff --git a/clean/video/fakestormer/configs/temporal/FakeSFormer_small_c23.yaml b/clean/video/fakestormer/configs/temporal/FakeSFormer_small_c23.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..ae2e2a4fe3176b72bce90bab691015235ced9065
--- /dev/null
+++ b/clean/video/fakestormer/configs/temporal/FakeSFormer_small_c23.yaml
@@ -0,0 +1,195 @@
+TASK: ViTSmall112_ST_hm100_tempLOC0.3_8SBI_DymIntens_MSE_SAM(AdamW)_5e5_boost1_mp0.01_fsdyn_fullSA_m_std_c23_no_compress
+PRECISION: float64
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: False
+
+DATASET:
+ type: FakeSFormerSBI
+ DATA_TYPE: video
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c23
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 32
+ PIN_MEMORY: True
+ IMAGE_SIZE: [112, 112]
+ HEATMAP_SIZE: [14, 14] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 1
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: m_std_normalized
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: videos # frames or videos
+ SAMPLES_PER_VIDEO:
+ ACTIVE: True
+ TRAIN: 4 # Dynamically random number of frames in each epoch
+ VAL: 4
+ TEST: 4
+ NUM_FRAMES: 4
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /home/users/XXX/data/FaceForensics++/c23/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c23/train_FaceForensics_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /home/users/XXX/data/FaceForensics++/c23/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures] # Choosing Deepfake techniques to be loaded for dataloader
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c23/val_FaceForensics_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: FF++
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /project/home/p200249/XXX/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ # ROOT: /project/home/p200249/XXX/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ # ROOT: /project/home/p200249/XXX/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ # ROOT: /project/home/p200249/XXX/DFW/
+ # ROOT: /project/home/p200328/XXX/data/DeeperForensics/
+ FROM_FILE: False
+ # FAKETYPE: [original, FaceSwap]
+ FAKETYPE: [original, Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake, real]
+ # FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ # FAKETYPE: [fake_test, real_test]
+ # FAKETYPE: [DFo_source_videos, DFo_manipulated_videos]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [112, 112, 0] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0
+ cropping: [0.15, 0] #Format: [crop_limit, prob]
+ scale: [0.15, 0] #Format: [scale_limit, prob]
+ rand_erasing: [0.0, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+ DEBUG: False
+ DYNAMIC_FXRAY: True
+ DYNAMIC_BLENDING_PROB: True # Normally only use for temporal modeling
+ TARGET_OVERLAP: True
+ MASK_PROB: 0.01
+
+MODEL:
+ type: TopDownDetector
+ backbone:
+ type: TimeViT
+ img_size: [112, 112]
+ patch_size: 8
+ embed_dim: 384
+ depth: 12
+ num_heads: 6
+ mlp_ratio: 4
+ drop_path_rate: 0.3
+ qkv_bias: True
+ class_token: True
+ register_token: True
+ attention_type: divided_space_time #joint_space_time, space_only
+ num_frames: 8
+ pretrained: pretrained/dino_deitsmall8_pretrain.pth
+ keypoint_head:
+ type: TopdownHeatmapSimpleHead
+ in_channels: 384
+ hm_size: [14, 14] #img_size // patch_size
+ heads:
+ hm: 1
+ cls: 1
+ temp_loc: 4
+ num_deconv_layers: 0 #Config n deconv layers to build the decoder
+ num_deconv_filters: [256, 256]
+ num_deconv_kernels: [4, 4]
+ loss_keypoint:
+ type: JointsMSELoss
+ use_target_weight: False
+ extra:
+ final_conv_kernel: 3
+ num_conv_layers: 1
+ conv_2direction: True
+ use_temp_token: True
+ features: 3D
+
+TRAIN:
+ gpus: [0,1,2,3]
+ batch_size: 4
+ lr: 0.00005
+ epochs: 100
+ begin_epoch: -1
+ warm_up: 3
+ every_val_epochs: 1
+ accumulation_steps: 1
+ loss:
+ type: CombinedMSELoss
+ use_target_weight: False
+ cls_lmda: 0.7
+ dst_hm_cls_lmda: 0
+ offset_lmda: 0
+ hm_lmda: 100
+ cstency_lmda: 0
+ tmp_loc_lmda: 0.3
+ mse_reduction: mean
+ ce_reduction: mean
+ use_ce: False
+ optimizer: SAM
+ distributed: False
+ pretrained: ''
+ tensorboard: False
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: True
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+ booster: 1
+ start_decay: 2
+
+TEST:
+ gpus: [0]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: True
+ video_level: True
+ no_shot_preds: 1
+ pretrained: 'logs/18-07-2024/TopDownDetector_ViTSmall112_ST_hm10_tempLOC0.1_8SBI_DymIntens_MSE_SAM(AdamW)_5e5_boost1_mp0.01_discrete_fsdyn_fullSA_m_std_model_best.pth'
diff --git a/clean/video/fakestormer/configs/temporal/FakeSFormer_small_c23_224p16.yaml b/clean/video/fakestormer/configs/temporal/FakeSFormer_small_c23_224p16.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d86bd1908f53d9a5c63a9ebc8c6c2a7b93993d37
--- /dev/null
+++ b/clean/video/fakestormer/configs/temporal/FakeSFormer_small_c23_224p16.yaml
@@ -0,0 +1,194 @@
+TASK: ViTSmall224_hm100_tempLOC0.5_4SBI_DymIntens_MSE_SAM(AdamW)_mp0.01_fsdyn_fullSA_m_std_c23_0aug_newmaskdeform_test
+PRECISION: float
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: False
+
+DATASET:
+ type: FakeSFormerSBI
+ DATA_TYPE: video
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c23
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 32
+ PIN_MEMORY: True
+ IMAGE_SIZE: [224, 224]
+ HEATMAP_SIZE: [14, 14] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 1
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: m_std_normalized
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: videos # frames or videos
+ SAMPLES_PER_VIDEO:
+ ACTIVE: True
+ TRAIN: 4 # Dynamically random number of frames in each epoch
+ VAL: 4
+ TEST: 4
+ NUM_FRAMES: 4
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /home/users/XXX/data/FaceForensics++/c23/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c23/train_FaceForensics_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /home/users/XXX/data/FaceForensics++/c23/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures] # Choosing Deepfake techniques to be loaded for dataloader
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c23/val_FaceForensics_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: FF++
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv1/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /project/home/p200328/XXX/data/DFDCP/
+ # ROOT: /project/home/p200249/XXX/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ # ROOT: /project/home/p200328/XXX/data/DeeperForensics/
+ FROM_FILE: False
+ FAKETYPE: [original, NeuralTextures]
+ # FAKETYPE: [original, Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake, real]
+ # FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ # FAKETYPE: [fake_test, real_test]
+ # FAKETYPE: [DFo_source_videos, DFo_manipulated_videos]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [224, 224, 0] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0
+ cropping: [0.15, 0] #Format: [crop_limit, prob]
+ scale: [0.15, 0] #Format: [scale_limit, prob]
+ rand_erasing: [0.0, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+ DEBUG: False
+ DYNAMIC_FXRAY: True
+ DYNAMIC_BLENDING_PROB: True # Normally only use for temporal modeling
+ TARGET_OVERLAP: True
+ MASK_PROB: 0.01
+
+MODEL:
+ type: TopDownDetector
+ backbone:
+ type: TimeViT
+ img_size: [224, 224]
+ patch_size: 16
+ embed_dim: 384
+ depth: 12
+ num_heads: 6
+ mlp_ratio: 4
+ drop_path_rate: 0.3
+ qkv_bias: True
+ class_token: True
+ register_token: True
+ attention_type: divided_space_time #joint_space_time, space_only
+ num_frames: 4
+ pretrained: pretrained/dino_deitsmall16_pretrain.pth
+ keypoint_head:
+ type: TopdownHeatmapSimpleHead
+ in_channels: 384
+ hm_size: [14, 14] #img_size // patch_size
+ heads:
+ hm: 1
+ cls: 1
+ temp_loc: 4
+ num_deconv_layers: 0 #Config n deconv layers to build the decoder
+ num_deconv_filters: [256, 256]
+ num_deconv_kernels: [4, 4]
+ loss_keypoint:
+ type: JointsMSELoss
+ use_target_weight: False
+ extra:
+ final_conv_kernel: 3
+ num_conv_layers: 1
+ conv_2direction: True
+ use_temp_token: True
+ features: 3D
+
+TRAIN:
+ gpus: [0,1,2,3]
+ batch_size: 16
+ lr: 0.00005
+ epochs: 100
+ begin_epoch: -1
+ warm_up: 5
+ every_val_epochs: 1
+ accumulation_steps: 1
+ loss:
+ type: CombinedMSELoss
+ use_target_weight: False
+ cls_lmda: 0.5
+ dst_hm_cls_lmda: 0
+ offset_lmda: 0
+ hm_lmda: 100
+ cstency_lmda: 0
+ tmp_loc_lmda: 0.5
+ mse_reduction: mean
+ ce_reduction: mean
+ use_ce: False
+ optimizer: SAM
+ distributed: False
+ pretrained: ''
+ tensorboard: False
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: True
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+ booster: 1
+ start_decay: 4
+
+TEST:
+ gpus: [0]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: False
+ video_level: True
+ no_shot_preds: 1
+ pretrained: 'logs/04-08-2024/TopDownDetector_ViTSmall224_hm100_tempLOC0.3_4SBI_DymIntens_MSE_SAM(AdamW)_mp0.01_fsdyn_fullSA_m_std_c23_0comp_model_best.pth'
diff --git a/clean/video/fakestormer/configs/temporal/FakeSFormer_small_c23_224p8.yaml b/clean/video/fakestormer/configs/temporal/FakeSFormer_small_c23_224p8.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..02b42eb7b7bb408ce144f9e3a8aa4ba854f27c13
--- /dev/null
+++ b/clean/video/fakestormer/configs/temporal/FakeSFormer_small_c23_224p8.yaml
@@ -0,0 +1,197 @@
+TASK: ViTSmall224p8_ST_hm100_tempLOC0.5_4SBI_SAM_mp0.01_temp2_reload_0vidAug_0.5_harderBI
+PRECISION: float64
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: False
+
+DATASET:
+ type: FakeSFormerSBI
+ DATA_TYPE: video
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c23
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 32
+ PIN_MEMORY: True
+ IMAGE_SIZE: [224, 224]
+ HEATMAP_SIZE: [28, 28] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 1
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: m_std_normalized
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: videos # frames or videos
+ SAMPLES_PER_VIDEO:
+ ACTIVE: True
+ TRAIN: 4 # Dynamically random number of frames in each epoch
+ VAL: 4
+ TEST: 4
+ NUM_FRAMES: 4
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /home/users/XXX/data/FaceForensics++/c23/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c23/train_FaceForensics_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /home/users/XXX/data/FaceForensics++/c23/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures] # Choosing Deepfake techniques to be loaded for dataloader
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c23/val_FaceForensics_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: FF++
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /project/home/p200328/XXX/data/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ # ROOT: /project/home/p200328/XXX/data/DeeperForensics/
+ FROM_FILE: False
+ # FAKETYPE: [original, NeuralTextures]
+ FAKETYPE: [original, Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake, real]
+ # FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ # FAKETYPE: [fake_test, real_test]
+ # FAKETYPE: [DFo_source_videos, DFo_manipulated_videos]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [112, 112, 0] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0
+ cropping: [0.15, 0] #Format: [crop_limit, prob]
+ scale: [0.15, 0] #Format: [scale_limit, prob]
+ rand_erasing: [0.0, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+ DEBUG: False
+ DYNAMIC_FXRAY: True
+ DYNAMIC_BLENDING_PROB: True # Normally only use for temporal modeling
+ TARGET_OVERLAP: True
+ MASK_PROB: 0.01
+ TEMP_MASKOUT: False
+
+MODEL:
+ type: TopDownDetector
+ backbone:
+ type: TimeViT
+ img_size: [224, 224]
+ patch_size: 8
+ embed_dim: 384
+ depth: 12
+ num_heads: 6
+ mlp_ratio: 4
+ drop_path_rate: 0.3
+ qkv_bias: True
+ class_token: True
+ register_token: True
+ attention_type: divided_space_time #joint_space_time, space_only
+ num_frames: 4
+ low_level_enhanced: False
+ keypoint_head:
+ type: TopdownHeatmapSimpleHead
+ in_channels: 384
+ hm_size: [28, 28] #img_size // patch_size
+ heads:
+ hm: 1
+ cls: 1
+ temp_loc: 4
+ num_deconv_layers: 0 #Config n deconv layers to build the decoder
+ num_deconv_filters: [256, 256]
+ num_deconv_kernels: [4, 4]
+ loss_keypoint:
+ type: JointsMSELoss
+ use_target_weight: False
+ extra:
+ final_conv_kernel: 3
+ num_conv_layers: 1
+ conv_2direction: True
+ use_temp_token: True
+ features: 3D
+ INIT_WEIGHTS:
+ pretrained: pretrained/dino_deitsmall8_pretrain.pth
+
+TRAIN:
+ gpus: [0,1,2,3]
+ batch_size: 8
+ lr: 0.00005
+ epochs: 100
+ begin_epoch: -1
+ warm_up: 5
+ every_val_epochs: 1
+ accumulation_steps: 1
+ use_amp: False
+ loss:
+ type: CombinedMSELoss
+ use_target_weight: False
+ cls_lmda: 0.5
+ dst_hm_cls_lmda: 0
+ offset_lmda: 0
+ hm_lmda: 100
+ cstency_lmda: 0
+ tmp_loc_lmda: 0.5
+ mse_reduction: mean
+ ce_reduction: mean
+ use_ce: False
+ temperature: 2
+ optimizer: SAM
+ distributed: False
+ pretrained: ''
+ tensorboard: False
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: False
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+ booster: 1
+ start_decay: 4
+
+TEST:
+ gpus: [0]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: False
+ video_level: True
+ no_shot_preds: 1
+ pretrained: 'logs/28-08-2024/TopDownDetector_ViTSmall224p8_ST_hm10_tempLOC0.5_4SBI_SAM_mp0.01_temp2_reload_0vidAug_0.5_harderBI_model_best.pth'
diff --git a/clean/video/fakestormer/configs/temporal/FakeSwin3D_base_c0.yaml b/clean/video/fakestormer/configs/temporal/FakeSwin3D_base_c0.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..ff16e2be5a54eb7de1f39ff4d1fa40678e06ded1
--- /dev/null
+++ b/clean/video/fakestormer/configs/temporal/FakeSwin3D_base_c0.yaml
@@ -0,0 +1,206 @@
+TASK: C0_Swin3DBase224_hm10_128CST100_EFPN_C3_32SBI_AdamW_temp2_0.25_normlms_1e8
+PRECISION: float64
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: True
+
+DATASET:
+ type: FakeSFormerSBI
+ DATA_TYPE: video
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c23
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 28
+ PIN_MEMORY: True
+ IMAGE_SIZE: [224, 224]
+ HEATMAP_SIZE: [56, 56] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 1
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: m_std_normalized
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: videos
+ SAMPLES_PER_VIDEO:
+ ACTIVE: True
+ TRAIN: 32 # Dynamically random number of frames in each epoch
+ VAL: 32
+ TEST: 32
+ NUM_FRAMES: 32
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/train_FF++_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures] # Choosing Deepfake techniques to be loaded for dataloader
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c0/val_FF++_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: Celeb-DFv2
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /project/home/p200249/XXX/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ # ROOT: /project/home/p200249/XXX/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ # ROOT: /project/home/p200249/XXX/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ # ROOT: /project/home/p200249/XXX/DFW/
+ # ROOT: /project/home/p200249/XXX/DeeperForensics/
+ FROM_FILE: False
+ # FAKETYPE: [original, Deepfakes]
+ # FAKETYPE: [frames_BW_5/original, frames_BW_5/Deepfakes, frames_BW_5/Face2Face, frames_BW_5/FaceSwap, frames_BW_5/NeuralTextures]
+ FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake, real]
+ # FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ # FAKETYPE: [fake_test, real_test]
+ # FAKETYPE: [DFo_source_videos, DFo_manipulated_videos]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [224, 224, 0] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ cropping: [0.15, 0.] #Format: [crop_limit, prob]
+ scale: [0.15, 0.] #Format: [scale_limit, prob]
+ rand_erasing: [0.0, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+ DEBUG: False
+ DYNAMIC_FXRAY: True
+ DYNAMIC_BLENDING_PROB: True # Normally only use for temporal modeling
+ TARGET_OVERLAP: True
+ MASK_PROB: 0.
+ TEMP_MASKOUT: False
+
+MODEL:
+ type: TopDownDetector
+ backbone:
+ type: SwinTransformer3D
+ embed_dim: 128
+ patch_size: [2,4,4]
+ depths: [2,2,18,2]
+ num_heads: [4,8,16,32]
+ window_size: [8,7,7]
+ mlp_ratio: 4
+ qkv_bias: True
+ drop_rate: 0.
+ attn_drop_rate: 0.
+ drop_path_rate: 0.2
+ patch_norm: True
+ pretrained2d: True
+ pretrained: pretrained/swin_base_patch4_window7_224_22k.pth
+ neck:
+ type: EFPN3D
+ in_channels: 1024
+ num_deconv_layers: 4 #Config n deconv layers to build the decoder
+ num_deconv_filters: [1024, 512, 256, 128]
+ num_deconv_kernels: [[1,1,1], [1,4,4], [1,4,4], [4,4,4]]
+ num_deconv_strides: [[1,1,1], [1,2,2], [1,2,2], [2,2,2]]
+ efpn: True
+ keypoint_head:
+ type: TopdownHeatmapSimpleHead
+ in_channels: 128
+ hm_size: [14, 14] #img_size // patch_size
+ heads:
+ hm: 1
+ cls: 1
+ cstency: 128
+ loss_keypoint:
+ type: JointsMSELoss
+ use_target_weight: False
+ extra:
+ final_conv_kernel: 3
+ num_conv_layers: 1
+ conv_2direction: False
+ use_temp_token: True
+ features: 3D
+ avg_pool: True
+ act: GELU
+ INIT_WEIGHTS:
+ pretrained: pretrained/swin_base_patch4_window7_224_22k.pth
+
+TRAIN:
+ gpus: [0,1,2,3]
+ batch_size: 2
+ lr: 0.0000001
+ epochs: 200
+ begin_epoch: -1
+ warm_up: 10
+ every_val_epochs: 1
+ accumulation_steps: 8
+ use_amp: True
+ loss:
+ type: CombinedMSELoss
+ use_target_weight: False
+ cls_lmda: 1
+ dst_hm_cls_lmda: 0
+ offset_lmda: 0
+ hm_lmda: 10
+ cstency_lmda: 100
+ tmp_loc_lmda: 0
+ mse_reduction: mean
+ ce_reduction: mean
+ use_ce: False
+ feature: 3D
+ temperature: 2
+ optimizer: AdamW
+ distributed: False
+ pretrained: ''
+ tensorboard: False
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: True
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+ booster: 500
+ start_decay: 4
+
+TEST:
+ gpus: [0]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: False
+ video_level: True
+ no_shot_preds: 1
+ pretrained: 'logs/22-01-2025/TopDownDetector_C23_Swin3DBase224_hm10_256CST100_EFPN_C3_32SBI_AdamW_temp2_0.25_normlms_normREAL_1e8_model_best.pth'
diff --git a/clean/video/fakestormer/configs/temporal/FakeSwin3D_base_c23.yaml b/clean/video/fakestormer/configs/temporal/FakeSwin3D_base_c23.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..27b483d65a8e64ce0b1aa0b7cba76d6750b2d9eb
--- /dev/null
+++ b/clean/video/fakestormer/configs/temporal/FakeSwin3D_base_c23.yaml
@@ -0,0 +1,206 @@
+TASK: C23_Swin3DBase224_hm10_128CST100_EFPN_C3_4SBI_AdamW_temp2_0.25_normlms_1e8
+PRECISION: float64
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: True
+
+DATASET:
+ type: FakeSFormerSBI
+ DATA_TYPE: video
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c23
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 28
+ PIN_MEMORY: True
+ IMAGE_SIZE: [224, 224]
+ HEATMAP_SIZE: [56, 56] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 1
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: m_std_normalized
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: frames
+ SAMPLES_PER_VIDEO:
+ ACTIVE: True
+ TRAIN: 32 # Dynamically random number of frames in each epoch
+ VAL: 32
+ TEST: 32
+ NUM_FRAMES: 32
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c23/train_FaceForensics_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures] # Choosing Deepfake techniques to be loaded for dataloader
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c23/val_FaceForensics_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: DFDC
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /project/home/p200249/XXX/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ ROOT: /project/home/p200249/XXX/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ # ROOT: /project/home/p200249/XXX/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ # ROOT: /project/home/p200249/XXX/DFW/
+ # ROOT: /project/home/p200249/XXX/DeeperForensics/
+ FROM_FILE: False
+ # FAKETYPE: [original, Deepfakes]
+ # FAKETYPE: [frames_BW_5/original, frames_BW_5/Deepfakes, frames_BW_5/Face2Face, frames_BW_5/FaceSwap, frames_BW_5/NeuralTextures]
+ # FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ FAKETYPE: [fake, real]
+ # FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ # FAKETYPE: [fake_test, real_test]
+ # FAKETYPE: [DFo_source_videos, DFo_manipulated_videos]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [224, 224, 0] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ cropping: [0.15, 0.] #Format: [crop_limit, prob]
+ scale: [0.15, 0.] #Format: [scale_limit, prob]
+ rand_erasing: [0.0, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+ DEBUG: False
+ DYNAMIC_FXRAY: True
+ DYNAMIC_BLENDING_PROB: True # Normally only use for temporal modeling
+ TARGET_OVERLAP: True
+ MASK_PROB: 0.
+ TEMP_MASKOUT: False
+
+MODEL:
+ type: TopDownDetector
+ backbone:
+ type: SwinTransformer3D
+ embed_dim: 128
+ patch_size: [2,4,4]
+ depths: [2,2,18,2]
+ num_heads: [4,8,16,32]
+ window_size: [8,7,7]
+ mlp_ratio: 4
+ qkv_bias: True
+ drop_rate: 0.
+ attn_drop_rate: 0.
+ drop_path_rate: 0.2
+ patch_norm: True
+ pretrained2d: True
+ pretrained: pretrained/swin_base_patch4_window7_224_22k.pth
+ neck:
+ type: EFPN3D
+ in_channels: 1024
+ num_deconv_layers: 4 #Config n deconv layers to build the decoder
+ num_deconv_filters: [1024, 512, 256, 128]
+ num_deconv_kernels: [[1,1,1], [1,4,4], [1,4,4], [4,4,4]]
+ num_deconv_strides: [[1,1,1], [1,2,2], [1,2,2], [2,2,2]]
+ efpn: True
+ keypoint_head:
+ type: TopdownHeatmapSimpleHead
+ in_channels: 128
+ hm_size: [14, 14] #img_size // patch_size
+ heads:
+ hm: 1
+ cls: 1
+ cstency: 128
+ loss_keypoint:
+ type: JointsMSELoss
+ use_target_weight: False
+ extra:
+ final_conv_kernel: 3
+ num_conv_layers: 1
+ conv_2direction: False
+ use_temp_token: True
+ features: 3D
+ avg_pool: True
+ act: GELU
+ INIT_WEIGHTS:
+ pretrained: pretrained/swin_base_patch4_window7_224_22k.pth
+
+TRAIN:
+ gpus: [0,1,2,3]
+ batch_size: 8
+ lr: 0.00000001
+ epochs: 100
+ begin_epoch: -1
+ warm_up: 5
+ every_val_epochs: 1
+ accumulation_steps: 1
+ use_amp: False
+ loss:
+ type: CombinedMSELoss
+ use_target_weight: False
+ cls_lmda: 1
+ dst_hm_cls_lmda: 0
+ offset_lmda: 0
+ hm_lmda: 10
+ cstency_lmda: 100
+ tmp_loc_lmda: 0
+ mse_reduction: mean
+ ce_reduction: mean
+ use_ce: False
+ feature: 3D
+ temperature: 2
+ optimizer: AdamW
+ distributed: False
+ pretrained: ''
+ tensorboard: False
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: False
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+ booster: 5000
+ start_decay: 4
+
+TEST:
+ gpus: [0]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: False
+ video_level: True
+ no_shot_preds: 1
+ pretrained: 'logs/18-03-2025/TopDownDetector_C23_Swin3DBase224_hm10_128CST100_EFPN_C3_32SBI_AdamW_temp2_0.25_normlms_1e7_model_best.pth'
diff --git a/clean/video/fakestormer/configs/temporal/ResNet3D_EFPN3D_hm3D_c23.yaml b/clean/video/fakestormer/configs/temporal/ResNet3D_EFPN3D_hm3D_c23.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..052f30491258b142cb7252a70c34588ea7661c6a
--- /dev/null
+++ b/clean/video/fakestormer/configs/temporal/ResNet3D_EFPN3D_hm3D_c23.yaml
@@ -0,0 +1,204 @@
+TASK: C23_ResNet3D224_hm10_256CST100_EFPN_C2_32SBI_AdamW_temp2_0.25_normlms_1e7_mstd
+PRECISION: float64
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: True
+
+DATASET:
+ type: FakeSFormerSBI
+ DATA_TYPE: video
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c23
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 32
+ PIN_MEMORY: True
+ IMAGE_SIZE: [224, 224]
+ HEATMAP_SIZE: [56, 56] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 1
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: m_std_normalized
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: videos
+ SAMPLES_PER_VIDEO:
+ ACTIVE: True
+ TRAIN: 32 # Dynamically random number of frames in each epoch
+ VAL: 32
+ TEST: 32
+ NUM_FRAMES: 32
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c23/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c23/train_FaceForensics_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c23/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: True
+ FAKETYPE: [Deepfakes, Face2Face, FaceSwap, NeuralTextures] # Choosing Deepfake techniques to be loaded for dataloader
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c23/val_FaceForensics_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: Celeb-DFv2
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c23/
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv2/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /project/home/p200249/XXX/DFDCP/
+ # ROOT: /data/deepfake_cluster/datasets_df/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ # ROOT: /project/home/p200249/XXX/DFDC/
+ # ROOT: /data/deepfake_cluster/datasets_df/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ # ROOT: /project/home/p200249/XXX/DFD/
+ # ROOT: /data/deepfake_cluster/datasets_df/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ # ROOT: /project/home/p200249/XXX/DFW/
+ # ROOT: /data/deepfake_cluster/datasets_df/DFW/
+ # ROOT: /project/home/p200249/XXX/DeeperForensics/
+ FROM_FILE: False
+ # FAKETYPE: [original, Deepfakes, Face2Face, FaceSwap, NeuralTextures]
+ # FAKETYPE: [original, FaceShifter]
+ # FAKETYPE: [videos_BW_5/original, videos_BW_5/Deepfakes, videos_BW_5/Face2Face, videos_BW_5/FaceSwap, videos_BW_5/NeuralTextures]
+ FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake_method, real_method]
+ # FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ # FAKETYPE: [fake_test, real_test]
+ # FAKETYPE: [DFo_source_videos, DFo_manipulated_videos]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [224, 224, 0] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ cropping: [0.15, 0.] #Format: [crop_limit, prob]
+ scale: [0.15, 0.] #Format: [scale_limit, prob]
+ rand_erasing: [0.0, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+ DEBUG: False
+ DYNAMIC_FXRAY: True
+ DYNAMIC_BLENDING_PROB: True # Normally only use for temporal modeling
+ TARGET_OVERLAP: True
+ MASK_PROB: 0.
+ TEMP_MASKOUT: False
+
+MODEL:
+ type: TopDownDetector
+ backbone:
+ type: ResNet3D
+ block: Bottleneck
+ layers: [3, 4, 6, 3]
+ block_inplanes: [64, 128, 256, 512]
+ neck:
+ type: EFPN3D
+ in_channels: 2048
+ num_deconv_layers: 4 #Config n deconv layers to build the decoder
+ num_deconv_filters: [1024, 512, 256, 128]
+ num_deconv_kernels: [[4,4,4], [4,4,4], [4,4,4], [4,1,1]]
+ num_deconv_strides: [[2,2,2], [2,2,2], [2,2,2], [2,1,1]]
+ efpn: True
+ keypoint_head:
+ type: TopdownHeatmapSimpleHead
+ in_channels: 128
+ heads:
+ cls: 1
+ hm: 1
+ cstency: 128
+ loss_keypoint:
+ type: JointsMSELoss
+ use_target_weight: False
+ extra:
+ final_conv_kernel: 3
+ num_conv_layers: 1
+ conv_2direction: False
+ use_temp_token: True
+ features: 3D
+ avg_pool: True
+ act: RELU
+ INIT_WEIGHTS:
+ pretrained: pretrained/r3d50_KS_200ep.pth
+
+TRAIN:
+ gpus: [0,1,2,3]
+ batch_size: 4
+ lr: 0.0000001
+ epochs: 200
+ begin_epoch: -1
+ warm_up: 10
+ every_val_epochs: 1
+ accumulation_steps: 4
+ use_amp: True
+ loss:
+ type: CombinedMSELoss
+ use_target_weight: False
+ cls_lmda: 1
+ dst_hm_cls_lmda: 0
+ offset_lmda: 0
+ hm_lmda: 10
+ cstency_lmda: 100
+ tmp_loc_lmda: 0
+ mse_reduction: mean
+ ce_reduction: mean
+ use_ce: False
+ feature: 3D
+ temperature: 2
+ optimizer: AdamW
+ distributed: False
+ pretrained: ''
+ tensorboard: False
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: True
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+ booster: 500
+ start_decay: 4
+
+TEST:
+ gpus: [0]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: False
+ video_level: True
+ no_shot_preds: 1
+ pretrained: 'logs/30-09-2024/TopDownDetector_C23_Res3D224_hm0_tempLOC0_8SBI_Adam_mp0.01_temp1_0vidAug_0.35_normlms_SBV_ablation_model_best.pth'
diff --git a/clean/video/fakestormer/configs/temporal/bin_cls/ResNet3D_c23.yaml b/clean/video/fakestormer/configs/temporal/bin_cls/ResNet3D_c23.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..ef2fceea9d28e80ea3f68cd244a120683f174dc8
--- /dev/null
+++ b/clean/video/fakestormer/configs/temporal/bin_cls/ResNet3D_c23.yaml
@@ -0,0 +1,166 @@
+TASK: C23_Res3D224_binary_8SBI_Adam_0vidAug_Deepfakes
+PRECISION: float32
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: False
+
+DATASET:
+ type: BinaryFaceForensic
+ DATA_TYPE: video
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c23
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 32
+ PIN_MEMORY: True
+ IMAGE_SIZE: [224, 224]
+ HEATMAP_SIZE: [14, 14] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 1
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: m_std_normalized
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: frames
+ SAMPLES_PER_VIDEO:
+ ACTIVE: True
+ TRAIN: 8 # Dynamically random number of frames in each epoch
+ VAL: 8
+ TEST: 8
+ NUM_FRAMES: 8
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: False
+ FAKETYPE: [original, Deepfakes]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c23/train_FaceForensics_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: False
+ FAKETYPE: [original, Deepfakes] # Choosing Deepfake techniques to be loaded for dataloader
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c23/val_FaceForensics_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: DFW
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /project/home/p200249/XXX/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ # ROOT: /project/home/p200249/XXX/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ # ROOT: /project/home/p200249/XXX/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ ROOT: /project/home/p200249/XXX/DFW/
+ # ROOT: /project/home/p200249/XXX/DeeperForensics/
+ FROM_FILE: False
+ # FAKETYPE: [original, Deepfakes, FaceSwap, Face2Face, NeuralTextures]
+ # FAKETYPE: [videos_BW_5/original, videos_BW_5/Deepfakes, videos_BW_5/Face2Face, videos_BW_5/FaceSwap, videos_BW_5/NeuralTextures]
+ # FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake, real]
+ # FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ FAKETYPE: [fake_test, real_test]
+ # FAKETYPE: [DFo_source_videos, DFo_manipulated_videos]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [224, 224, 1] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ cropping: [0.15, 0.5] #Format: [crop_limit, prob]
+ scale: [0.15, 0.5] #Format: [scale_limit, prob]
+ rand_erasing: [0.0, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+
+MODEL:
+ type: TopDownDetector
+ backbone:
+ type: ResNet3D
+ block: Bottleneck
+ layers: [3, 4, 6, 3]
+ block_inplanes: [64, 128, 256, 512]
+ keypoint_head:
+ type: TopdownHeatmapSimpleHead
+ in_channels: 2048
+ heads:
+ cls: 1
+ num_deconv_layers: 0 #Config n deconv layers to build the decoder
+ num_deconv_filters: [256, 256]
+ num_deconv_kernels: [4, 4]
+ loss_keypoint:
+ type: JointsMSELoss
+ use_target_weight: False
+ extra:
+ final_conv_kernel: 3
+ num_conv_layers: 1
+ INIT_WEIGHTS:
+ pretrained: null
+
+TRAIN:
+ gpus: [0,1,2,3]
+ batch_size: 16
+ lr: 0.00005
+ epochs: 100
+ begin_epoch: -1
+ warm_up: 3
+ every_val_epochs: 1
+ accumulation_steps: 1
+ use_amp: False
+ loss:
+ type: BinaryCrossEntropy
+ reduction: mean
+ optimizer: Adam
+ distributed: False
+ pretrained: ''
+ tensorboard: False
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: True
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+ booster: 1
+ start_decay: 2.5
+
+TEST:
+ gpus: [0]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: False
+ video_level: True
+ no_shot_preds: 1
+ pretrained: 'logs/17-09-2024/TopDownDetector_C23_Res3D224_binary_8SBI_Adam_0vidAug_Deepfakes_model_best.pth'
diff --git a/clean/video/fakestormer/configs/temporal/bin_cls/ResNet3D_c40.yaml b/clean/video/fakestormer/configs/temporal/bin_cls/ResNet3D_c40.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..1233deee5e9cbbd51b94e3f1e189a224ccd5009c
--- /dev/null
+++ b/clean/video/fakestormer/configs/temporal/bin_cls/ResNet3D_c40.yaml
@@ -0,0 +1,166 @@
+TASK: C40_Res3D224_binary_8SBI_Adam_0vidAug_NeuralTextures
+PRECISION: float32
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: False
+
+DATASET:
+ type: BinaryFaceForensic
+ DATA_TYPE: video
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c40
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 32
+ PIN_MEMORY: True
+ IMAGE_SIZE: [224, 224]
+ HEATMAP_SIZE: [14, 14] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 1
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: m_std_normalized
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: videos
+ SAMPLES_PER_VIDEO:
+ ACTIVE: True
+ TRAIN: 8 # Dynamically random number of frames in each epoch
+ VAL: 8
+ TEST: 8
+ NUM_FRAMES: 8
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c40/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: False
+ FAKETYPE: [original, NeuralTextures]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c23/train_FaceForensics_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c40/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: False
+ FAKETYPE: [original, NeuralTextures] # Choosing Deepfake techniques to be loaded for dataloader
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c23/val_FaceForensics_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: FF++
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c40/
+ # ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /project/home/p200249/XXX/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ # ROOT: /project/home/p200249/XXX/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ # ROOT: /project/home/p200249/XXX/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ # ROOT: /project/home/p200249/XXX/DFW/
+ # ROOT: /project/home/p200249/XXX/DeeperForensics/
+ FROM_FILE: False
+ FAKETYPE: [original, Deepfakes]
+ # FAKETYPE: [videos_BW_5/original, videos_BW_5/Deepfakes, videos_BW_5/Face2Face, videos_BW_5/FaceSwap, videos_BW_5/NeuralTextures]
+ # FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake, real]
+ # FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ # FAKETYPE: [fake_test, real_test]
+ # FAKETYPE: [DFo_source_videos, DFo_manipulated_videos]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [224, 224, 1] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ cropping: [0.15, 0.5] #Format: [crop_limit, prob]
+ scale: [0.15, 0.5] #Format: [scale_limit, prob]
+ rand_erasing: [0.0, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+
+MODEL:
+ type: TopDownDetector
+ backbone:
+ type: ResNet3D
+ block: Bottleneck
+ layers: [3, 4, 6, 3]
+ block_inplanes: [64, 128, 256, 512]
+ keypoint_head:
+ type: TopdownHeatmapSimpleHead
+ in_channels: 2048
+ heads:
+ cls: 1
+ num_deconv_layers: 0 #Config n deconv layers to build the decoder
+ num_deconv_filters: [256, 256]
+ num_deconv_kernels: [4, 4]
+ loss_keypoint:
+ type: JointsMSELoss
+ use_target_weight: False
+ extra:
+ final_conv_kernel: 3
+ num_conv_layers: 1
+ INIT_WEIGHTS:
+ pretrained: null
+
+TRAIN:
+ gpus: [0,1,2,3]
+ batch_size: 16
+ lr: 0.00005
+ epochs: 100
+ begin_epoch: -1
+ warm_up: 3
+ every_val_epochs: 1
+ accumulation_steps: 1
+ use_amp: False
+ loss:
+ type: BinaryCrossEntropy
+ reduction: mean
+ optimizer: Adam
+ distributed: False
+ pretrained: ''
+ tensorboard: False
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: True
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+ booster: 1
+ start_decay: 2.5
+
+TEST:
+ gpus: [0]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: False
+ video_level: True
+ no_shot_preds: 1
+ pretrained: 'logs/02-10-2024/TopDownDetector_C40_Res3D224_binary_8SBI_Adam_0vidAug_NeuralTextures_model_best.pth'
diff --git a/clean/video/fakestormer/configs/temporal/bin_cls/TimeSFormer_base_c23.yaml b/clean/video/fakestormer/configs/temporal/bin_cls/TimeSFormer_base_c23.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..94df7b21216391e0beb5dadc75a9785179cf5994
--- /dev/null
+++ b/clean/video/fakestormer/configs/temporal/bin_cls/TimeSFormer_base_c23.yaml
@@ -0,0 +1,181 @@
+TASK: C23_TimeBase224_ST_binary_8SBI_AdamW_0vidAug_temp_FaceSwap
+PRECISION: float32
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: False
+
+DATASET:
+ type: BinaryFaceForensic
+ DATA_TYPE: video
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c23
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 32
+ PIN_MEMORY: True
+ IMAGE_SIZE: [224, 224]
+ HEATMAP_SIZE: [14, 14] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 1
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: m_std_normalized
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: videos
+ SAMPLES_PER_VIDEO:
+ ACTIVE: True
+ TRAIN: 8 # Dynamically random number of frames in each epoch
+ VAL: 8
+ TEST: 8
+ NUM_FRAMES: 8
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: False
+ FAKETYPE: [original, FaceSwap]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c23/train_FaceForensics_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: False
+ FAKETYPE: [original, FaceSwap] # Choosing Deepfake techniques to be loaded for dataloader
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c23/val_FaceForensics_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: Celeb-DFv2
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ # ROOT: /project/home/p200249/XXX/FaceForensics++/c23/
+ # ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /project/home/p200249/XXX/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ # ROOT: /project/home/p200249/XXX/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ # ROOT: /project/home/p200249/XXX/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ # ROOT: /project/home/p200249/XXX/DFW/
+ # ROOT: /project/home/p200249/XXX/DeeperForensics/
+ FROM_FILE: False
+ # FAKETYPE: [original, FaceSwap]
+ # FAKETYPE: [videos_BW_5/original, videos_BW_5/Deepfakes, videos_BW_5/Face2Face, videos_BW_5/FaceSwap, videos_BW_5/NeuralTextures]
+ FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake, real]
+ # FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ # FAKETYPE: [fake_test, real_test]
+ # FAKETYPE: [DFo_source_videos, DFo_manipulated_videos]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [224, 224, 1] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ cropping: [0.15, 0.5] #Format: [crop_limit, prob]
+ scale: [0.15, 0.5] #Format: [scale_limit, prob]
+ rand_erasing: [0.0, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+
+MODEL:
+ type: TopDownDetector
+ backbone:
+ type: TimeViT
+ img_size: [224, 224]
+ patch_size: 16
+ embed_dim: 768
+ depth: 12
+ num_heads: 12
+ mlp_ratio: 4
+ drop_path_rate: 0.3
+ qkv_bias: True
+ class_token: True
+ register_token: False
+ temp_token: True
+ attention_type: divided_space_time #joint_space_time, space_only
+ num_frames: 8
+ low_level_enhanced: False
+ keypoint_head:
+ type: TopdownHeatmapSimpleHead
+ in_channels: 768
+ hm_size: [14, 14] #img_size // patch_size
+ heads:
+ cls: 1
+ num_deconv_layers: 0 #Config n deconv layers to build the decoder
+ num_deconv_filters: [256, 256]
+ num_deconv_kernels: [4, 4]
+ loss_keypoint:
+ type: JointsMSELoss
+ use_target_weight: False
+ extra:
+ final_conv_kernel: 3
+ num_conv_layers: 1
+ conv_2direction: False
+ use_temp_token: True
+ features: 3D
+ INIT_WEIGHTS:
+ pretrained: null
+
+TRAIN:
+ gpus: [0,1,2,3]
+ batch_size: 16
+ lr: 0.00005
+ epochs: 100
+ begin_epoch: -1
+ warm_up: 3
+ every_val_epochs: 1
+ accumulation_steps: 1
+ use_amp: False
+ loss:
+ type: BinaryCrossEntropy
+ reduction: mean
+ optimizer: AdamW
+ distributed: False
+ pretrained: ''
+ tensorboard: False
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: True
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+ booster: 1
+ start_decay: 2.5
+
+TEST:
+ gpus: [0]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: False
+ video_level: True
+ no_shot_preds: 1
+ pretrained: 'logs/03-10-2024/TopDownDetector_C23_TimeBase224_ST_binary_8SBI_AdamW_0vidAug_temp_FaceSwap_model_best.pth'
diff --git a/clean/video/fakestormer/configs/temporal/bin_cls/TimeSFormer_base_c40.yaml b/clean/video/fakestormer/configs/temporal/bin_cls/TimeSFormer_base_c40.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..b62fdf3390fbe87fc00f146ae81cf248112bfd76
--- /dev/null
+++ b/clean/video/fakestormer/configs/temporal/bin_cls/TimeSFormer_base_c40.yaml
@@ -0,0 +1,181 @@
+TASK: C40_TimeBase224_ST_binary_8SBI_AdamW_0vidAug_temp_NeuralTextures
+PRECISION: float32
+METRICS_BASE: binary
+SEED: 317
+DATA_RELOAD: False
+
+DATASET:
+ type: BinaryFaceForensic
+ DATA_TYPE: video
+ TRAIN: True #Switch to True for training mode, False for testing mode
+ COMPRESSION: c40
+ IMAGE_SUFFIX: png
+ NUM_WORKERS: 32
+ PIN_MEMORY: True
+ IMAGE_SIZE: [224, 224]
+ HEATMAP_SIZE: [14, 14] #[IMAGE_SIZE//4, IMAGE_SIZE//4]
+ SIGMA: 1
+ ADAPTIVE_SIGMA: False
+ HEATMAP_TYPE: m_std_normalized
+ SPLIT_IMAGE: False
+ DATA:
+ TYPE: videos
+ SAMPLES_PER_VIDEO:
+ ACTIVE: True
+ TRAIN: 8 # Dynamically random number of frames in each epoch
+ VAL: 8
+ TEST: 8
+ NUM_FRAMES: 8
+ TRAIN:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c40/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: False
+ FAKETYPE: [original, NeuralTextures]
+ # ANNO_FILE: train/frames/FaceXRay/train_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c23/train_FaceForensics_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ VAL:
+ NAME: FF++ # This field to define datasets that can be used to train/in-dataset/cross-dataset evaluation
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c40/
+ # ROOT: /data/deepfake_cluster/datasets_df/FaceForensics++/c0/
+ FROM_FILE: False
+ FAKETYPE: [original, NeuralTextures] # Choosing Deepfake techniques to be loaded for dataloader
+ # ANNO_FILE: val/frames/FaceXRay/val_FF_FaceXRay.json
+ ANNO_FILE: processed_data/c23/val_FaceForensics_videos_81.json
+ LABEL_FOLDER: [real, fake]
+ TEST:
+ NAME: FF++
+ # ROOT: /home/users/XXX/data/FaceForensics++/c0/
+ ROOT: /project/home/p200249/XXX/FaceForensics++/c40/
+ # ROOT: /home/users/XXX/data/Celeb-DFv1/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv1/
+ # ROOT: /data/deepfake_cluster/datasets_df/Celeb-DFv1/
+ # ROOT: /home/users/XXX/data/Celeb-DFv2/
+ # ROOT: /project/home/p200249/XXX/Celeb-DFv2/
+ # ROOT: /home/users/XXX/data/DFDCP/
+ # ROOT: /project/home/p200249/XXX/DFDCP/
+ # ROOT: /home/users/XXX/data/DFDC/
+ # ROOT: /project/home/p200249/XXX/DFDC/
+ # ROOT: /home/users/XXX/data/DFD/
+ # ROOT: /project/home/p200249/XXX/DFD/
+ # ROOT: /home/users/XXX/data/DFW/
+ # ROOT: /project/home/p200249/XXX/DFW/
+ # ROOT: /project/home/p200249/XXX/DeeperForensics/
+ FROM_FILE: False
+ FAKETYPE: [original, FaceSwap]
+ # FAKETYPE: [videos_BW_5/original, videos_BW_5/Deepfakes, videos_BW_5/Face2Face, videos_BW_5/FaceSwap, videos_BW_5/NeuralTextures]
+ # FAKETYPE: [Celeb-real, Celeb-synthesis, YouTube-real]
+ # FAKETYPE: [method_A, method_B, original_videos]
+ # FAKETYPE: [fake, real]
+ # FAKETYPE: [DeepFakeDetection_original, DeepFakeDetection]
+ # FAKETYPE: [fake_test, real_test]
+ # FAKETYPE: [DFo_source_videos, DFo_manipulated_videos]
+ ANNO_FILE: FaceXRay/test/test_FF_Xray.json
+ LABEL_FOLDER: [real, fake]
+ TRANSFORM:
+ geometry:
+ type: GeometryTransform
+ resize: [224, 224, 1] #h, w, p=probability. If no affine transform, set p=1
+ normalize: 0
+ horizontal_flip: 0.5
+ cropping: [0.15, 0.5] #Format: [crop_limit, prob]
+ scale: [0.15, 0.5] #Format: [scale_limit, prob]
+ rand_erasing: [0.0, 1] #Format: [p, max_count]
+ color:
+ type: ColorJitterTransform
+ clahe: 0.0
+ colorjitter: 0.3
+ gaussianblur: 0.3
+ gaussnoise: 0.3
+ jpegcompression: [0.5, 40, 100] # prob, lower and upper quality respectively
+ rgbshift: 0.3
+ randomcontrast: 0.0
+ randomgamma: 0.5
+ randombrightness: 1
+ huesat: 1
+ normalize:
+ mean: [0.485, 0.456, 0.406]
+ std: [0.229, 0.224, 0.225]
+
+MODEL:
+ type: TopDownDetector
+ backbone:
+ type: TimeViT
+ img_size: [224, 224]
+ patch_size: 16
+ embed_dim: 768
+ depth: 12
+ num_heads: 12
+ mlp_ratio: 4
+ drop_path_rate: 0.3
+ qkv_bias: True
+ class_token: True
+ register_token: False
+ temp_token: True
+ attention_type: divided_space_time #joint_space_time, space_only
+ num_frames: 8
+ low_level_enhanced: False
+ keypoint_head:
+ type: TopdownHeatmapSimpleHead
+ in_channels: 768
+ hm_size: [14, 14] #img_size // patch_size
+ heads:
+ cls: 1
+ num_deconv_layers: 0 #Config n deconv layers to build the decoder
+ num_deconv_filters: [256, 256]
+ num_deconv_kernels: [4, 4]
+ loss_keypoint:
+ type: JointsMSELoss
+ use_target_weight: False
+ extra:
+ final_conv_kernel: 3
+ num_conv_layers: 1
+ conv_2direction: False
+ use_temp_token: True
+ features: 3D
+ INIT_WEIGHTS:
+ pretrained: null
+
+TRAIN:
+ gpus: [0,1,2,3]
+ batch_size: 16
+ lr: 0.00005
+ epochs: 100
+ begin_epoch: -1
+ warm_up: 3
+ every_val_epochs: 1
+ accumulation_steps: 1
+ use_amp: False
+ loss:
+ type: BinaryCrossEntropy
+ reduction: mean
+ optimizer: AdamW
+ distributed: False
+ pretrained: ''
+ tensorboard: False
+ resume: False
+ lr_scheduler:
+ # type: MultiStepLR
+ milestones: [5, 15, 20, 25]
+ gamma: 0.5
+ freeze_backbone: True
+ debug:
+ active: False
+ save_hm_gt: True
+ save_hm_pred: True
+ booster: 1
+ start_decay: 2.5
+
+TEST:
+ gpus: [0]
+ subtask: 'eval'
+ test_file: ''
+ vis_hm: True
+ threshold: 0.5
+ flip_test: False
+ video_level: True
+ no_shot_preds: 1
+ pretrained: 'logs/03-10-2024/TopDownDetector_C40_TimeBase224_ST_binary_8SBI_AdamW_0vidAug_temp_NeuralTextures_model_best.pth'
diff --git a/clean/video/fakestormer/datasets/__init__.py b/clean/video/fakestormer/datasets/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..2fa76c040a21d56ea365398bcff98e9866f2eacc
--- /dev/null
+++ b/clean/video/fakestormer/datasets/__init__.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+from .builder import DATASETS, PIPELINES, build_dataset
+from .face_forensic_binary import BinaryFaceForensic
+from .face_forensic_hm import HeatmapFaceForensic
+from .face_forensic_sbi import SBIFaceForensic
+from .fakesformer_bi import FakeSFormerBI
+from .fakesformer_sbi import FakeSFormerSBI
+from .pipelines import *
+
+__all__ = [
+ "GeometryTransform",
+ "BinaryFaceForensic",
+ "ColorJitterTransform",
+ "PIPELINES",
+ "DATASETS",
+ "build_dataset",
+ "HeatmapFaceForensic",
+ "SBIFaceForensic",
+ "FakeSFormerSBI",
+ "FakeSFormerBI",
+]
diff --git a/clean/video/fakestormer/datasets/builder.py b/clean/video/fakestormer/datasets/builder.py
new file mode 100644
index 0000000000000000000000000000000000000000..35f09797618a41e24f0933fad3408696987a36f8
--- /dev/null
+++ b/clean/video/fakestormer/datasets/builder.py
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+import os
+import sys
+from typing import Any, Dict, Optional
+
+if not os.getcwd() in sys.path:
+ sys.path.append(os.getcwd())
+
+from register.register import Registry, build_from_cfg
+
+PIPELINES = Registry("Pipeline", build_func=build_from_cfg)
+DATASETS = Registry("Dataset", build_func=build_from_cfg)
+
+
+def build_pipeline(
+ cfg,
+ pipeline: Registry,
+ build_func=build_from_cfg,
+ default_args: Optional[Dict] = None,
+) -> Any:
+ return build_func(cfg, pipeline, default_args)
+
+
+def build_dataset(
+ cfg,
+ dataset: Registry,
+ build_func=build_from_cfg,
+ default_args: Optional[Dict] = None,
+) -> Any:
+ return build_func(cfg, dataset, default_args)
diff --git a/clean/video/fakestormer/datasets/celebDF_v1.py b/clean/video/fakestormer/datasets/celebDF_v1.py
new file mode 100644
index 0000000000000000000000000000000000000000..dfa23f74ff8cd4c121f356541048249cb3666346
--- /dev/null
+++ b/clean/video/fakestormer/datasets/celebDF_v1.py
@@ -0,0 +1,41 @@
+# -*- coding: utf-8 -*-
+import os
+from glob import glob
+
+import numpy as np
+
+from .builder import DATASETS
+from .common import CommonDataset
+
+
+@DATASETS.register_module()
+class CDFV1(CommonDataset):
+ def __init__(self, cfg, **kwargs):
+ super().__init__(cfg, **kwargs)
+
+ def _load_from_path(self, split):
+ assert os.path.exists(
+ self._cfg.DATA[self.split.upper()].ROOT
+ ), "Root path to dataset can not be None!"
+ data = self._cfg["DATA"]
+ data_type = data.TYPE
+ fake_types = self._cfg.DATA[split.upper()]["FAKETYPE"]
+ img_paths, labels, mask_paths, ot_props = [], [], [], []
+
+ # Load image data for each type of fake techniques
+ for idx, ft in enumerate(fake_types):
+ data_dir = os.path.join(
+ self._cfg.DATA[self.split.upper()].ROOT, self.split, data_type, ft
+ )
+ if not os.path.exists(data_dir):
+ raise ValueError("Data Directory can not be invalid!")
+
+ for sub_dir in os.listdir(data_dir):
+ sub_dir_path = os.path.join(data_dir, sub_dir)
+ img_paths_ = glob(f"{sub_dir_path}/*.{self._cfg.IMAGE_SUFFIX}")
+
+ img_paths.extend(img_paths_)
+ labels.extend(np.full(len(img_paths_), int("Celeb-synthesis" in ft)))
+
+ print("{} image paths have been loaded from CDFv1!".format(len(img_paths)))
+ return img_paths, labels, mask_paths, ot_props
diff --git a/clean/video/fakestormer/datasets/celebDF_v2.py b/clean/video/fakestormer/datasets/celebDF_v2.py
new file mode 100644
index 0000000000000000000000000000000000000000..61c7de7d9e982f9d82add4afba40c5b8e27db569
--- /dev/null
+++ b/clean/video/fakestormer/datasets/celebDF_v2.py
@@ -0,0 +1,58 @@
+# -*- coding: utf-8 -*-
+import os
+from glob import glob
+
+import numpy as np
+
+from .builder import DATASETS
+from .common import CommonDataset
+
+
+@DATASETS.register_module()
+class CDFV2(CommonDataset):
+ def __init__(self, cfg, **kwargs):
+ super().__init__(cfg, **kwargs)
+
+ def _load_from_path(self, split):
+ assert os.path.exists(
+ self._cfg.DATA[self.split.upper()].ROOT
+ ), "Root path to dataset can not be None!"
+ data = self._cfg["DATA"]
+ data_type = data.TYPE
+ fake_types = self._cfg.DATA[split.upper()]["FAKETYPE"]
+ img_paths, labels, mask_paths, ot_props = [], [], [], []
+
+ count = 0
+ n_samples = 100000
+
+ # Load image data for each type of fake techniques
+ for idx, ft in enumerate(fake_types):
+ data_dir = os.path.join(
+ self._cfg.DATA[self.split.upper()].ROOT, self.split, data_type, ft
+ )
+ if not os.path.exists(data_dir):
+ raise ValueError("Data Directory can not be invalid!")
+
+ for sub_dir in os.listdir(data_dir):
+ sub_dir_path = os.path.join(data_dir, sub_dir)
+ img_paths_ = glob(f"{sub_dir_path}/*.{self._cfg.IMAGE_SUFFIX}")
+
+ if "Celeb-synthesis" in ft:
+ if count < n_samples:
+ n_add = (
+ len(img_paths_)
+ if ((n_samples - count) > len(img_paths_))
+ else (n_samples - count)
+ )
+ count += n_add
+ print(f"n fake samples added --- {count}")
+ else:
+ continue
+ else:
+ n_add = len(img_paths_)
+
+ img_paths.extend(img_paths_[:n_add])
+ labels.extend(np.full(n_add, int("Celeb-synthesis" in ft)))
+
+ print("{} image paths have been loaded from CDFv2!".format(len(img_paths)))
+ return img_paths, labels, mask_paths, ot_props
diff --git a/clean/video/fakestormer/datasets/combine.py b/clean/video/fakestormer/datasets/combine.py
new file mode 100644
index 0000000000000000000000000000000000000000..2f69a304f4fac0411b498b1fa89f97f82c08d25d
--- /dev/null
+++ b/clean/video/fakestormer/datasets/combine.py
@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+import os
+from glob import glob
+
+import numpy as np
+
+from .builder import DATASETS
+from .common import CommonDataset
+
+
+@DATASETS.register_module()
+class Combine(CommonDataset):
+ def __init__(self, cfg, **kwargs):
+ super().__init__(cfg, **kwargs)
+
+ def _load_from_path(self, split):
+ assert os.path.exists(
+ self._cfg.DATA[self.split.upper()].ROOT
+ ), "Root path to dataset can not be None!"
+ data = self._cfg["DATA"]
+ data_type = data.TYPE
+ fake_types = self._cfg.DATA[split.upper()]["FAKETYPE"]
+ img_paths, labels, mask_paths, ot_props = [], [], [], []
+
+ # Load image data for each type of fake techniques
+ for idx, ft in enumerate(fake_types):
+ data_dir = os.path.join(
+ self._cfg.DATA[self.split.upper()].ROOT, self.split, data_type, ft
+ )
+ if not os.path.exists(data_dir):
+ raise ValueError("Data Directory can not be invalid!")
+
+ for sub_dir in os.listdir(data_dir):
+ sub_dir_path = os.path.join(data_dir, sub_dir)
+ # sub_dir_path = data_dir
+ img_paths_ = glob(f"{sub_dir_path}/*.{self._cfg.IMAGE_SUFFIX}")
+
+ img_paths.extend(img_paths_)
+ labels.extend(
+ np.full(
+ len(img_paths_),
+ int(("real" not in ft) and ("original" not in ft)),
+ )
+ )
+
+ print("{} image paths have been loaded from Combine!".format(len(img_paths)))
+ return img_paths, labels, mask_paths, ot_props
diff --git a/clean/video/fakestormer/datasets/common.py b/clean/video/fakestormer/datasets/common.py
new file mode 100644
index 0000000000000000000000000000000000000000..c716a3ec3fdfdc5eaaa3b5268d8304692a02ac9b
--- /dev/null
+++ b/clean/video/fakestormer/datasets/common.py
@@ -0,0 +1,717 @@
+# -*- coding: utf-8 -*-
+import math
+import os
+import random
+import sys
+from abc import ABC, abstractmethod
+from glob import glob
+
+import numpy as np
+import simplejson as json
+from box import Box as edict
+from natsort import natsorted
+from package_utils.image_utils import cal_mask_wh, gaussian_radius
+from package_utils.transform import final_transform
+from package_utils.utils import file_extention
+from PIL import Image
+from torch.utils.data import Dataset
+
+from .builder import DATASETS
+from .utils import _extract_data_based_dist
+
+PREFIX_PATH = "/data/deepfake_cluster/datasets_df/FaceForensics++/c0/"
+
+
+class ParameterStore:
+ _instance = None
+ _parameters = {}
+
+ @classmethod
+ def get_instance(cls):
+ if cls._instance is None:
+ cls._instance = cls()
+ return cls._instance
+
+ @classmethod
+ def add_parameters(cls, param_name, param_value):
+ cls._parameters[param_name] = param_value
+
+ @classmethod
+ def get_parameters(cls, param_name):
+ return cls._parameters.get(param_name)
+
+ @classmethod
+ def del_parameters(cls):
+ for k in cls._parameters.keys():
+ del cls._parameters[k]
+
+ @classmethod
+ def has_key(cls, key):
+ return key in cls._parameters
+
+ @classmethod
+ def reset(cls):
+ cls._parameters.clear()
+ cls._instance = None
+
+
+@DATASETS.register_module()
+class CommonDataset(Dataset, ABC):
+ def __init__(self, cfg, **kwargs):
+ super().__init__()
+ self._cfg = edict(cfg) if not isinstance(cfg, edict) else cfg
+ self.dataset = self._cfg.DATA[self.split.upper()].NAME
+ # self.train = self._cfg["TRAIN"]
+ self.train = self.split != "test"
+ self.final_transforms = final_transform(self._cfg)
+ self.sigma_adaptive = self._cfg.ADAPTIVE_SIGMA
+ self.sampler_active = self._cfg.DATA.SAMPLES_PER_VIDEO.ACTIVE
+ self.samples_per_video = self._cfg.DATA.SAMPLES_PER_VIDEO[self.split.upper()]
+ self.sampler_dist = (
+ self._cfg.DATA.SAMPLES_PER_VIDEO.DIST
+ ) # Distribution of [Real, Fake]
+ self.heatmap_w = self._cfg.HEATMAP_SIZE[1]
+ self.heatmap_h = self._cfg.HEATMAP_SIZE[0]
+ self.split_image = self._cfg.SPLIT_IMAGE
+ self.compression = self._cfg.COMPRESSION
+ self.data_type = self._cfg.DATA_TYPE
+
+ if kwargs is not None:
+ for k, v in kwargs.items():
+ if v is None:
+ raise ValueError(f"{k}:{v} retrieve a None value!")
+ self.__setattr__(k, v)
+
+ @abstractmethod
+ def _load_from_path(self, split):
+ return NotImplemented
+
+ def _load_from_file(self, split, anno_file=None):
+ """
+ @split: train/val
+ This function for loading data from file for 4 types of manipulated images FF++ and FaceXray generation data
+ """
+ assert os.path.exists(
+ self._cfg.DATA[self.split.upper()].ROOT
+ ), "Root path to dataset can not be invalid!"
+ data_cfg = self._cfg.DATA
+
+ if anno_file is None:
+ anno_file = data_cfg[split.upper()].ANNO_FILE
+ if not os.access(anno_file, os.R_OK):
+ anno_file = os.path.join(self._cfg.DATA[self.split.upper()].ROOT, anno_file)
+ assert os.access(anno_file, os.R_OK), "Annotation file can not be invalid!!"
+
+ f_name, f_extention = file_extention(anno_file)
+ data = None
+ image_paths, labels, mask_paths, ot_props = [], [], [], []
+ f = open(anno_file)
+ if f_extention == ".json":
+ data = json.load(f)
+ data = edict(data)[
+ "data"
+ ] # A list of proprocessed data objects containing image properties
+
+ for item in data:
+ assert (
+ "image_path" in item.keys()
+ ), "Image path must be available in item dict!"
+ image_path = item.image_path
+ ot_prop = {}
+
+ # Custom base on the specific data structure
+ if not "label" in item.keys():
+ lb = ("fake" in image_path) or (
+ ("original" not in image_path) and ("aligned" not in image_path)
+ )
+ else:
+ lb = item.label == "fake"
+ lb_encoded = int(lb)
+ labels.append(lb_encoded)
+
+ if PREFIX_PATH in item.image_path:
+ image_path = item.image_path.replace(
+ PREFIX_PATH, self._cfg.DATA[self.split.upper()].ROOT
+ )
+ else:
+ image_path = os.path.join(
+ self._cfg.DATA[self.split.upper()].ROOT, item.image_path
+ )
+ image_paths.append(image_path)
+
+ # Appending more data properties for data loader
+ if "mask_path" in item.keys():
+ mask_path = item.mask_path
+ if PREFIX_PATH in item.mask_path:
+ mask_path = item.mask_path.replace(
+ PREFIX_PATH, self._cfg.DATA[self.split.upper()].ROOT
+ )
+ else:
+ mask_path = os.path.join(
+ self._cfg.DATA[self.split.upper()].ROOT, item.mask_path
+ )
+ mask_paths.append(mask_path)
+ if "best_match" in item.keys():
+ best_match = item.best_match
+ best_match = [
+ os.path.join(self._cfg.DATA[self.split.upper()].ROOT, bm)
+ for bm in best_match
+ if self._cfg.DATA[self.split.upper()].ROOT not in bm
+ ]
+ ot_prop["best_match"] = best_match
+ for lms_key in ["aligned_lms", "orig_lms"]:
+ if lms_key in item.keys():
+ f_lms = np.array(item[lms_key])
+ ot_prop[lms_key] = f_lms
+
+ ot_props.append(ot_prop)
+ else:
+ raise Exception(
+ f"{f_extention} has not been supported yet! Please change to Json file!"
+ )
+
+ print("{} image paths have been loaded!".format(len(image_paths)))
+ return image_paths, labels, mask_paths, ot_props
+
+ def _gen_vul_parts(self, blending_mask):
+ H, W, C = blending_mask.shape
+ Hp, Wp = self.heatmap_h, self.heatmap_w
+ py, px = int(H // Hp), int(W // Wp)
+
+ assert (H // Hp) == (W // Wp)
+ vul_parts = np.zeros((Hp, Wp))
+
+ for i in range(0, Hp):
+ for j in range(0, Wp):
+ blending_part = blending_mask[
+ (py * i) : (py * (i + 1)), (px * j) : (px * (j + 1)), 0
+ ]
+ part_intensity = np.mean(blending_part)
+ vul_parts[i, j] = part_intensity
+ vul_parts_out = np.tile(vul_parts[:, :, np.newaxis], (1, 1, 3)).astype(np.uint8)
+
+ return vul_parts_out
+
+ def _mask_out_vulnerability(self, input, mask, fake_intensity, mask_prob=0.9):
+ if self.dynamic_blending_prob:
+ p_h = self._cfg.IMAGE_SIZE[0] // self.heatmap_h
+ p_w = self._cfg.IMAGE_SIZE[1] // self.heatmap_w
+
+ max_value = max(0.1, mask[..., 0].max())
+ upper_bound_intensity = min(1.0, fake_intensity)
+ upper_bound_value = max(
+ 0.1, mask[mask[..., 0] < max_value * upper_bound_intensity].max()
+ )
+ target_mask_ = (mask[..., 0] > upper_bound_value).astype(int)
+
+ # Randomly mask out mask if the input is real
+ if np.count_nonzero(target_mask_) == 0:
+ pos_matrix = (self.heatmap_h, self.heatmap_w)
+ all_indices = [
+ (i, j) for i in range(self.heatmap_h) for j in range(self.heatmap_w)
+ ]
+ selected_indices = np.random.choice(
+ len(all_indices),
+ size=math.floor(mask_prob * np.prod((pos_matrix))),
+ replace=False,
+ )
+ selected_indices_2d = [all_indices[i] for i in selected_indices]
+ i_indices, j_indices = zip(*selected_indices_2d)
+ else:
+ all_indices = [
+ (i, j)
+ for i in range(self.heatmap_h)
+ for j in range(self.heatmap_w)
+ if (
+ (target_mask_[i, j] == 0)
+ and (mask[..., 0][i, j] < upper_bound_value)
+ )
+ ]
+ idxes = np.where(target_mask_ == 1)
+ n_mask_pos_h = len(idxes[0])
+ pos_matrix = (self.heatmap_h, self.heatmap_w)
+
+ if len(all_indices) < math.floor(
+ mask_prob * np.prod((pos_matrix)) - n_mask_pos_h
+ ):
+ size = math.ceil(len(all_indices) * mask_prob)
+ else:
+ size = max(
+ 0, math.floor(mask_prob * np.prod((pos_matrix)) - n_mask_pos_h)
+ )
+
+ selected_indices = np.random.choice(
+ len(all_indices), size=size, replace=False
+ )
+ selected_indices_2d = [all_indices[i] for i in selected_indices]
+ i_indices_, j_indices_ = zip(*selected_indices_2d)
+ i_indices = np.hstack((idxes[0], np.array(i_indices_)))
+ j_indices = np.hstack((idxes[1], np.array(j_indices_)))
+
+ target_mask_[i_indices, j_indices] = 1
+ idxes = np.where(target_mask_ == 1)
+ masked_matrix = 1 - target_mask_
+
+ for i, j in zip(idxes[0], idxes[1]):
+ input[
+ int(i * p_h) : int((i + 1) * p_h),
+ int(j * p_w) : int((j + 1) * p_w),
+ :,
+ ] = np.zeros((1, 1, input.shape[2]), dtype=input.dtype)
+ # mask[i, j] = np.zeros((mask.shape[2]), dtype=mask.dtype)
+
+ return input, mask, masked_matrix, upper_bound_value
+
+ def _mask_out_vulnerability2(self, input, mask, fake_intensity, **kwargs):
+ mask_prob = kwargs.get("mask_prob")
+ param_store_ins = ParameterStore.get_instance()
+ masked_matrix = param_store_ins.get_parameters("masked_matrix")
+
+ p_h = self._cfg.IMAGE_SIZE[0] // self.heatmap_h
+ p_w = self._cfg.IMAGE_SIZE[1] // self.heatmap_w
+ upper_bound_value = None
+
+ if self.dynamic_blending_prob:
+ if masked_matrix is not None:
+ upper_bound_value = max(1, np.max(mask[..., 0] * masked_matrix))
+ fake_intensity = upper_bound_value / 255
+ target_mask_ = 1 - masked_matrix
+ idxes = np.where(target_mask_ == 1)
+ else:
+ max_value = max(1, mask[..., 0].max())
+ max_f_intensity = max_value / 255
+ fake_intensity = min(fake_intensity, max_f_intensity)
+
+ upper_bound_value = max(
+ 1, mask[mask[..., 0] < 255 * fake_intensity].max()
+ )
+ target_mask_ = (mask[..., 0] > upper_bound_value).astype(int)
+
+ # Randomly mask out mask if the input is real
+ if np.count_nonzero(target_mask_) == 0:
+ pos_matrix = (self.heatmap_h, self.heatmap_w)
+ all_indices = [
+ (i, j)
+ for i in range(self.heatmap_h)
+ for j in range(self.heatmap_w)
+ ]
+ selected_indices = np.random.choice(
+ len(all_indices),
+ size=math.ceil(mask_prob * np.prod((pos_matrix))),
+ replace=False,
+ )
+ selected_indices_2d = [all_indices[i] for i in selected_indices]
+ i_indices, j_indices = zip(*selected_indices_2d)
+ else:
+ all_indices = [
+ (i, j)
+ for i in range(self.heatmap_h)
+ for j in range(self.heatmap_w)
+ if (
+ (target_mask_[i, j] == 0)
+ and (mask[..., 0][i, j] < upper_bound_value)
+ )
+ ]
+ idxes = np.where(target_mask_ == 1)
+ n_mask_pos_h = len(idxes[0])
+ pos_matrix = (self.heatmap_h, self.heatmap_w)
+
+ if len(all_indices) < math.floor(
+ mask_prob * np.prod((pos_matrix)) - n_mask_pos_h
+ ):
+ size = math.ceil(len(all_indices) * mask_prob)
+ else:
+ size = max(
+ 1,
+ math.ceil(mask_prob * np.prod((pos_matrix)) - n_mask_pos_h),
+ )
+
+ selected_indices = np.random.choice(
+ len(all_indices), size=size, replace=False
+ )
+ selected_indices_2d = [all_indices[i] for i in selected_indices]
+ i_indices_, j_indices_ = zip(*selected_indices_2d)
+ i_indices = np.hstack((idxes[0], np.array(i_indices_)))
+ j_indices = np.hstack((idxes[1], np.array(j_indices_)))
+
+ target_mask_[i_indices, j_indices] = 1
+ idxes = np.where(target_mask_ == 1)
+ masked_matrix = 1 - target_mask_
+ param_store_ins.add_parameters("masked_matrix", masked_matrix)
+
+ for i, j in zip(idxes[0], idxes[1]):
+ rand_val = np.random.randint(0, 255)
+ input[
+ int(i * p_h) : int((i + 1) * p_h),
+ int(j * p_w) : int((j + 1) * p_w),
+ :,
+ ] = np.full((1, 1, input.shape[2]), 0, dtype=input.dtype)
+ # mask[i, j] = np.zeros((mask.shape[2]), dtype=mask.dtype)
+
+ return input, mask, masked_matrix, upper_bound_value, fake_intensity
+
+ def _encode_temporal_target(self, target_mask, **kwargs):
+ """
+ Adaptively encode targets based on the vulnerability levels for spatial-temporal outputs (3D)
+ """
+ assert self.heatmap_type in ["gaussian", "m_std_normalized", "max_normalized"]
+
+ if isinstance(target_mask, list):
+ target_mask = np.array(target_mask)
+
+ saved_params = {}
+ hm_w = self._cfg.HEATMAP_SIZE[1]
+ hm_h = self._cfg.HEATMAP_SIZE[0]
+ ndim = len(target_mask)
+ heatmap = np.zeros((ndim, hm_h, hm_w), dtype=np.float32) # dimension d, h, w
+ # cstency_hm = np.zeros((ndim, hm_h, hm_w), dtype=np.float32)
+
+ derivative = np.diff(target_mask[:, :, :, 0], axis=0)
+ derivative = np.absolute(derivative)
+ d_max = max(1, np.max(derivative))
+
+ if bool(derivative.max()) and kwargs.get("vis_derivative"):
+ idx = kwargs.get("idx")
+ for i in range(len(derivative)):
+ di = derivative[i].astype(np.uint8)
+ di = np.repeat(di[:, :, np.newaxis], 3, axis=2)
+ Image.fromarray(di).save(f"samples/debugs/derivative_f_{idx}_{i}.png")
+
+ if self.heatmap_type == "gaussian":
+ x = np.arange(0, hm_w, 1, float)
+ y = np.arange(0, hm_h, 1, float)
+ y = np.expand_dims(y, -1)
+ z = np.arange(0, ndim, 1, float)
+ z = np.expand_dims((np.expand_dims(z, -1)), -1)
+ derivative = np.concatenate(
+ (np.zeros_like(derivative[0][np.newaxis, ...]), derivative), axis=0
+ )
+ centers = np.where(derivative == max(0.1, derivative.max()))
+
+ for i, j, k in zip(centers[0], centers[1], centers[2]):
+ heatmap_ijk = np.exp(
+ -(
+ ((z - i) ** 2) / (2.0 * (self.sigma / 2) ** 2)
+ + ((y - j) ** 2) / (2.0 * (self.sigma / 2) ** 2)
+ + ((x - k) ** 2) / (2.0 * (self.sigma / 2) ** 2)
+ )
+ )
+ heatmap = np.maximum(heatmap_ijk, heatmap)
+ elif self.heatmap_type == "m_std_normalized":
+ d_m = kwargs.get("d_mean") or np.mean(derivative)
+ d_std = kwargs.get("d_std") or np.std(derivative)
+ derivative = np.concatenate(
+ (np.zeros_like(derivative[0][np.newaxis, ...]), derivative), axis=0
+ )
+ # Calculating the 3D self-consistency map
+ # cstency_hm = 255 - np.absolute(d_max - derivative)
+
+ if d_std != 0:
+ heatmap = (derivative - d_m) / d_std
+
+ saved_params = {"d_mean": d_m, "d_std": d_std}
+ elif self.heatmap_type == "max_normalized":
+ derivative = np.concatenate(
+ (np.zeros_like(derivative[0][np.newaxis, ...]), derivative), axis=0
+ )
+ # Calculating the 3D self-consistency map
+ # cstency_hm = 255 - np.absolute(d_max - derivative)
+ if d_max != 0:
+ heatmap[1:] = derivative / d_max
+ else:
+ raise ValueError("Now only support gaussian or mean std normalization")
+
+ return heatmap, derivative / d_max, saved_params
+
+ def _encode_target(self, target_mask, fake_intensity=0.5):
+ """
+ Adaptively encode targets based on the vulnerability levels
+ """
+ assert (
+ self.heatmap_type == "gaussian"
+ ), "Only Gaussian Heatmap is supported now!"
+ hm_w = self._cfg.HEATMAP_SIZE[1]
+ hm_h = self._cfg.HEATMAP_SIZE[0]
+ heatmap = np.zeros((1, hm_h, hm_w), dtype=np.float32)
+
+ # Draw heatmap for blending region
+ max_val_all = target_mask[..., 0].max()
+ max_val = max_val_all if max_val_all > 0 else 255
+
+ # Select value to draw attention masks
+ if self.data_type == "video":
+ lower_bound_intensity = max(0.0, (fake_intensity - 0.1))
+ upper_bound_intensity = min(1.0, (fake_intensity + 0.1))
+ target_mask_ = (
+ (target_mask[..., 0] >= 255 * lower_bound_intensity)
+ & (target_mask[..., 0] < 255 * upper_bound_intensity)
+ ).astype(np.int8)
+ else:
+ target_mask_ = (target_mask[..., 0] >= max_val * fake_intensity).astype(
+ np.int8
+ )
+
+ points = np.where(target_mask_ == 1)
+
+ for j, i in zip(points[0], points[1]):
+ if self.sigma_adaptive:
+ w_sbi, h_sbi = cal_mask_wh((j, i), target_mask[..., 0])
+ radius = gaussian_radius((h_sbi, w_sbi))
+ self.sigma = radius / 3 + 1e-4
+ tmp = self.sigma * 3
+ size = tmp * 2 + 1
+ ul = [int(i - tmp), int(j - tmp)]
+ br = [int(i + tmp + 1), int(j + tmp + 1)]
+ x = np.arange(0, size, 1, np.float32)
+ y = x[:, np.newaxis]
+
+ x0 = y0 = size // 2
+ g = np.exp(-((x - x0) ** 2 + (y - y0) ** 2) / (2 * (self.sigma**2)))
+
+ g_x = max(0, -ul[0]), min(br[0], hm_w) - ul[0]
+ g_y = max(0, -ul[1]), min(br[1], hm_h) - ul[1]
+
+ img_x = max(0, ul[0]), min(br[0], hm_w)
+ img_y = max(0, ul[1]), min(br[1], hm_h)
+
+ heatmap[0][img_y[0] : img_y[1], img_x[0] : img_x[1]] = np.maximum(
+ g[g_y[0] : g_y[1], g_x[0] : g_x[1]],
+ heatmap[0][img_y[0] : img_y[1], img_x[0] : img_x[1]],
+ )
+
+ return heatmap, None
+
+ def _encode_target_v1(self, target_mask, fake_intensity=0.5):
+ assert (
+ self.heatmap_type == "gaussian"
+ ), "Only Gaussian Heatmap is supported now!"
+ # fake_ratio = [0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
+ n_outputs = 1
+ hm_w = self._cfg.HEATMAP_SIZE[1]
+ hm_h = self._cfg.HEATMAP_SIZE[0]
+ patches = [[0, 0], [0, 1 / 2], [1 / 2, 0], [1 / 2, 1 / 2]]
+ target_H, target_W = target_mask[..., 0].shape[:2]
+ heatmap = np.zeros((n_outputs, target_H, target_W), dtype=np.float32)
+ cstency_hm = np.zeros((n_outputs, target_H, target_W), dtype=np.float32)
+ max_val_all = target_mask[..., 0].max()
+
+ # Draw heatmap for blending region
+ for fr in range(len(patches)):
+ # target_mask_ = np.where(((target_mask[..., 0] > 255*fake_ratio[fr]) & (target_mask[..., 0] <= 255*fake_ratio[fr+1])), 1, 0)
+ p_x1, p_y1 = int(target_W * patches[fr][0]), int(target_H * patches[fr][1])
+ p_x2, p_y2 = int(target_W * (patches[fr][0] + 1 / 2)), int(
+ target_H * (patches[fr][1] + 1 / 2)
+ )
+
+ max_value = target_mask[p_y1:p_y2, p_x1:p_x2, 0].max()
+ max_value = max_value if max_value > 0 else 1
+ target_mask_ = (target_mask[p_y1:p_y2, p_x1:p_x2, 0] == (max_value)).astype(
+ np.uint8
+ )
+ points = np.where(target_mask_ == 1)
+
+ if len(points[0]):
+ p = (points[0] + p_y1, points[1] + p_x1)
+
+ for j, i in zip(p[0], p[1]):
+ if self.sigma_adaptive:
+ w_sbi, h_sbi = cal_mask_wh((j, i), target_mask[..., 0])
+ radius = gaussian_radius((h_sbi, w_sbi))
+ self.sigma = radius / 3 + 1e-4
+ tmp = self.sigma * 3
+ size = tmp * 2 + 1
+ ul = [int(i - tmp), int(j - tmp)]
+ br = [int(i + tmp + 1), int(j + tmp + 1)]
+ x = np.arange(0, size, 1, np.float32)
+ y = x[:, np.newaxis]
+
+ x0 = y0 = size // 2
+ g = np.exp(-((x - x0) ** 2 + (y - y0) ** 2) / (2 * (self.sigma**2)))
+
+ g_x = max(0, -ul[0]), min(br[0], hm_w) - ul[0]
+ g_y = max(0, -ul[1]), min(br[1], hm_h) - ul[1]
+
+ img_x = max(0, ul[0]), min(br[0], hm_w)
+ img_y = max(0, ul[1]), min(br[1], hm_h)
+
+ heatmap[0][img_y[0] : img_y[1], img_x[0] : img_x[1]] = np.maximum(
+ g[g_y[0] : g_y[1], g_x[0] : g_x[1]],
+ heatmap[0][img_y[0] : img_y[1], img_x[0] : img_x[1]],
+ )
+
+ if n_outputs > 1:
+ cstency_hm[fr][p_y1:p_y2, p_x1:p_x2] = 255 - np.absolute(
+ max_value - target_mask[p_y1:p_y2, p_x1:p_x2, 0]
+ )
+ else:
+ cstency_hm[0][p_y1:p_y2, p_x1:p_x2] = 255 - np.absolute(
+ max_val_all - target_mask[p_y1:p_y2, p_x1:p_x2, 0]
+ )
+
+ return heatmap, cstency_hm
+
+ def _encode_target_v2(self, target_mask, fake_intensity=0.5):
+ assert (
+ self.heatmap_type == "gaussian"
+ ), "Only Gaussian Heatmap is supported now!"
+ n_outputs = 1
+ hm_w = self._cfg.HEATMAP_SIZE[1]
+ hm_h = self._cfg.HEATMAP_SIZE[0]
+ target_H, target_W = target_mask[..., 0].shape[:2]
+ heatmap = np.zeros((n_outputs, target_H, target_W), dtype=np.float32)
+ cstency_hm = np.zeros((n_outputs, target_H, target_W), dtype=np.float32)
+
+ # Draw heatmap for blending region
+ target_mask_ = (target_mask[..., 0] > 128).astype(np.uint8)
+ points = np.where(target_mask_ == 1)
+
+ if len(points[0]):
+ p = (int(points[0].mean()), int(points[1].mean()))
+ j, i = p
+
+ if self.sigma_adaptive:
+ w_sbi, h_sbi = cal_mask_wh((j, i), target_mask[..., 0])
+ radius = gaussian_radius((h_sbi, w_sbi))
+ self.sigma = radius / 3 + 1e-4
+ tmp = self.sigma * 3
+ size = tmp * 2 + 1
+ ul = [int(i - tmp), int(j - tmp)]
+ br = [int(i + tmp + 1), int(j + tmp + 1)]
+ x = np.arange(0, size, 1, np.float32)
+ y = x[:, np.newaxis]
+
+ x0 = y0 = size // 2
+ g = np.exp(-((x - x0) ** 2 + (y - y0) ** 2) / (2 * (self.sigma**2)))
+
+ g_x = max(0, -ul[0]), min(br[0], hm_w) - ul[0]
+ g_y = max(0, -ul[1]), min(br[1], hm_h) - ul[1]
+
+ img_x = max(0, ul[0]), min(br[0], hm_w)
+ img_y = max(0, ul[1]), min(br[1], hm_h)
+
+ heatmap[0][img_y[0] : img_y[1], img_x[0] : img_x[1]] = np.maximum(
+ g[g_y[0] : g_y[1], g_x[0] : g_x[1]],
+ heatmap[0][img_y[0] : img_y[1], img_x[0] : img_x[1]],
+ )
+
+ cstency_hm[0] = 255 - np.absolute(
+ target_mask[j, i, 0] - target_mask[..., 0]
+ )
+
+ return heatmap, cstency_hm
+
+ def _sampler(self, image_paths, labels, epoch=0, **params):
+ if self.sampler_dist[0] != 1.0 or self.sampler_dist[1] != 1.0:
+ image_paths, labels, params = _extract_data_based_dist(
+ self.data_type, image_paths, labels, self.sampler_dist, **params
+ )
+
+ vid_dict = {}
+ data = {"image_paths": [], "labels": []}
+
+ for k, v in params.items():
+ if v is not None and len(v):
+ data[k] = []
+
+ for idx, ip in enumerate(image_paths):
+ f_name = ip.split("/")[-1]
+
+ if self.compression in ["c0", "c23", "c40"]:
+ vid_id = os.path.dirname(ip)
+ if self.dataset == "FF++" and self.train:
+ f_type = ip.split("/")[-3]
+ vid_id = "_".join([f_type, vid_id])
+ else:
+ raise NotImplementedError(
+ "Only c23, c40, and c0 compression mode is supported now! Please check again!"
+ )
+ lb = labels[idx]
+
+ data_per_vid = dict(image=ip, label=lb)
+ for k, v in params.items():
+ if k in data.keys():
+ data_per_vid[k] = v[idx]
+
+ if vid_id in vid_dict.keys():
+ vid_dict[vid_id].append(data_per_vid)
+ else:
+ vid_dict[vid_id] = [data_per_vid]
+
+ if self.data_type == "image":
+ """
+ Samples data for the mode of working with single images
+ """
+ for vid_id in vid_dict.keys():
+ if self.train:
+ samples_per_vid = random.choices(
+ vid_dict[vid_id], k=self.samples_per_video
+ )
+ else:
+ samples_per_vid = random.sample(
+ vid_dict[vid_id], k=len(vid_dict[vid_id])
+ )
+
+ for spl in samples_per_vid:
+ data["image_paths"].append(spl["image"])
+ data["labels"].append(spl["label"])
+ for k in params.keys():
+ if k in data.keys():
+ data[k].append(spl[k])
+ return data
+ elif self.data_type == "video":
+ # Sorting to obtain successive frames for videos, important for temporal modeling
+ for vid_id in vid_dict.keys():
+ vid_dict[vid_id] = natsorted(vid_dict[vid_id], key=lambda x: x["image"])
+
+ # if self.train:
+ """
+ Generate new video data for training
+ """
+ assert "NUM_FRAMES" in self._cfg.DATA.SAMPLES_PER_VIDEO
+ new_vid_dict = {}
+ n_fs = self._cfg.DATA.SAMPLES_PER_VIDEO.NUM_FRAMES
+
+ for vid_id in vid_dict.keys():
+ vid_len = len(vid_dict[vid_id])
+ start_idx = 0 if epoch == 0 else np.random.randint(0, n_fs - 1)
+
+ for k in range(start_idx, vid_len, n_fs):
+ try:
+ if (k + n_fs) <= vid_len:
+ new_vid_id = "+++".join(
+ [vid_id, str(k)]
+ ) # Adding index segment to original video to create sub videos
+ new_vid_dict[new_vid_id] = vid_dict[vid_id][k : (k + n_fs)]
+ except:
+ break
+
+ return new_vid_dict
+ else:
+ raise ValueError(
+ f'{self.data_type} has not been supported! Only "image" or "video" data can be extracted!'
+ )
+
+ def select_encode_method(self, version=0, dimension="spatial"):
+ if dimension == "spatial":
+ if version == 2:
+ return self._encode_target_v2
+ elif version == 1:
+ return self._encode_target_v1
+ else:
+ return self._encode_target
+ elif dimension == "temporal":
+ return self._encode_temporal_target
+ else:
+ raise ValueError(f"The input {dimension} has not been supported yet!")
+
+ @abstractmethod
+ def __len__(self):
+ return NotImplemented
+
+ @abstractmethod
+ def __getitem__(self, idx):
+ return NotImplemented
+
+ @property
+ def __repr__(self):
+ return self.__class__.__name__
diff --git a/clean/video/fakestormer/datasets/df40.py b/clean/video/fakestormer/datasets/df40.py
new file mode 100644
index 0000000000000000000000000000000000000000..b98cfebc66d3649cf292e34baadf97c2e1902fc6
--- /dev/null
+++ b/clean/video/fakestormer/datasets/df40.py
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+import os
+from glob import glob
+
+import numpy as np
+
+from .builder import DATASETS
+from .common import CommonDataset
+
+
+@DATASETS.register_module()
+class DF40(CommonDataset):
+ def __init__(self, cfg, **kwargs):
+ super().__init__(cfg, **kwargs)
+
+ def _load_from_path(self, split):
+ # Check if the root directory exists.
+ root_dir = self._cfg.DATA[self.split.upper()].ROOT
+ assert os.path.exists(root_dir), "Root path to dataset cannot be None!"
+
+ data = self._cfg["DATA"]
+ data_type = data.TYPE
+ fake_types = self._cfg.DATA[split.upper()]["FAKETYPE"]
+ img_paths, labels, mask_paths, ot_props = [], [], [], []
+
+ # Load image data for each type of fake technique.
+ for ft in fake_types:
+ # Construct path: ROOT/split/fake_type (skipping data_type)
+ data_dir = os.path.join(root_dir, self.split, data_type, ft)
+ if not os.path.exists(data_dir):
+ raise ValueError("Data Directory is invalid!")
+
+ # Define common image extensions.
+ extensions = ["jpg", "jpeg", "png", "tif", "webp"]
+ img_paths_ = []
+ # Recursively search for images in the fake type directory.
+ for ext in extensions:
+ pattern = os.path.join(data_dir, "**", f"*.{ext}")
+ img_paths_.extend(glob(pattern, recursive=True))
+
+ # Extend the main lists with the images and corresponding labels.
+ img_paths.extend(img_paths_)
+ labels.extend(np.full(len(img_paths_), int(ft != "real_videos")))
+
+ print("{} image paths have been loaded from DF40!".format(len(img_paths)))
+ return img_paths, labels, mask_paths, ot_props
diff --git a/clean/video/fakestormer/datasets/dfd.py b/clean/video/fakestormer/datasets/dfd.py
new file mode 100644
index 0000000000000000000000000000000000000000..62649bdb74b309d8807f19f9527c0227a52ad4ec
--- /dev/null
+++ b/clean/video/fakestormer/datasets/dfd.py
@@ -0,0 +1,41 @@
+# -*- coding: utf-8 -*-
+import os
+from glob import glob
+
+import numpy as np
+
+from .builder import DATASETS
+from .common import CommonDataset
+
+
+@DATASETS.register_module()
+class DFD(CommonDataset):
+ def __init__(self, cfg, **kwargs):
+ super().__init__(cfg, **kwargs)
+
+ def _load_from_path(self, split):
+ assert os.path.exists(
+ self._cfg.DATA[self.split.upper()].ROOT
+ ), "Root path to dataset can not be None!"
+ data = self._cfg["DATA"]
+ data_type = data.TYPE
+ fake_types = self._cfg.DATA[split.upper()]["FAKETYPE"]
+ img_paths, labels, mask_paths, ot_props = [], [], [], []
+
+ # Load image data for each type of fake techniques
+ for idx, ft in enumerate(fake_types):
+ data_dir = os.path.join(
+ self._cfg.DATA[self.split.upper()].ROOT, self.split, data_type, ft
+ )
+ if not os.path.exists(data_dir):
+ raise ValueError("Data Directory can not be invalid!")
+
+ for sub_dir in os.listdir(data_dir):
+ sub_dir_path = os.path.join(data_dir, sub_dir)
+ img_paths_ = glob(f"{sub_dir_path}/*.{self._cfg.IMAGE_SUFFIX}")
+
+ img_paths.extend(img_paths_)
+ labels.extend(np.full(len(img_paths_), int(ft == "DeepFakeDetection")))
+
+ print("{} image paths have been loaded from DFD!".format(len(img_paths)))
+ return img_paths, labels, mask_paths, ot_props
diff --git a/clean/video/fakestormer/datasets/dfdc.py b/clean/video/fakestormer/datasets/dfdc.py
new file mode 100644
index 0000000000000000000000000000000000000000..997d34befbeab2668bae022308c436c84e6372b5
--- /dev/null
+++ b/clean/video/fakestormer/datasets/dfdc.py
@@ -0,0 +1,41 @@
+# -*- coding: utf-8 -*-
+import os
+from glob import glob
+
+import numpy as np
+
+from .builder import DATASETS
+from .common import CommonDataset
+
+
+@DATASETS.register_module()
+class DFDC(CommonDataset):
+ def __init__(self, cfg, **kwargs):
+ super().__init__(cfg, **kwargs)
+
+ def _load_from_path(self, split):
+ assert os.path.exists(
+ self._cfg.DATA[self.split.upper()].ROOT
+ ), "Root path to dataset can not be None!"
+ data = self._cfg["DATA"]
+ data_type = data.TYPE
+ fake_types = self._cfg.DATA[split.upper()]["FAKETYPE"]
+ img_paths, labels, mask_paths, ot_props = [], [], [], []
+
+ # Load image data for each type of fake techniques
+ for idx, ft in enumerate(fake_types):
+ data_dir = os.path.join(
+ self._cfg.DATA[self.split.upper()].ROOT, self.split, data_type, ft
+ )
+ if not os.path.exists(data_dir):
+ raise ValueError("Data Directory can not be invalid!")
+
+ for sub_dir in os.listdir(data_dir):
+ sub_dir_path = os.path.join(data_dir, sub_dir)
+ img_paths_ = glob(f"{sub_dir_path}/*.{self._cfg.IMAGE_SUFFIX}")
+
+ img_paths.extend(img_paths_)
+ labels.extend(np.full(len(img_paths_), int(ft == "fake")))
+
+ print("{} image paths have been loaded from DFDC!".format(len(img_paths)))
+ return img_paths, labels, mask_paths, ot_props
diff --git a/clean/video/fakestormer/datasets/dfdcp.py b/clean/video/fakestormer/datasets/dfdcp.py
new file mode 100644
index 0000000000000000000000000000000000000000..a0198bd0fc30fdee74b73c9040491ff0fd0b1423
--- /dev/null
+++ b/clean/video/fakestormer/datasets/dfdcp.py
@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+import os
+from glob import glob
+
+import numpy as np
+
+from .builder import DATASETS
+from .common import CommonDataset
+
+
+@DATASETS.register_module()
+class DFDCP(CommonDataset):
+ def __init__(self, cfg, **kwargs):
+ super().__init__(cfg, **kwargs)
+
+ def _load_from_path(self, split):
+ assert os.path.exists(
+ self._cfg.DATA[self.split.upper()].ROOT
+ ), "Root path to dataset can not be None!"
+ data = self._cfg["DATA"]
+ data_type = data.TYPE
+ fake_types = self._cfg.DATA[split.upper()]["FAKETYPE"]
+ img_paths, labels, mask_paths, ot_props = [], [], [], []
+
+ # Load image data for each type of fake techniques
+ for idx, ft in enumerate(fake_types):
+ data_dir = os.path.join(
+ self._cfg.DATA[self.split.upper()].ROOT, self.split, data_type, ft
+ )
+ if not os.path.exists(data_dir):
+ raise ValueError("Data Directory can not be invalid!")
+
+ for sub_dir in os.listdir(data_dir):
+ sub_dir_path = os.path.join(data_dir, sub_dir)
+ img_paths_ = glob(f"{sub_dir_path}/*.{self._cfg.IMAGE_SUFFIX}")
+
+ img_paths.extend(img_paths_)
+ labels.extend(
+ np.full(
+ len(img_paths_), int((ft == "method_A") or (ft == "method_B"))
+ )
+ )
+
+ print("{} image paths have been loaded from DFDCP!".format(len(img_paths)))
+ return img_paths, labels, mask_paths, ot_props
diff --git a/clean/video/fakestormer/datasets/dfo.py b/clean/video/fakestormer/datasets/dfo.py
new file mode 100644
index 0000000000000000000000000000000000000000..b360108c2ea5e867fe87c473c8707979c1df88e3
--- /dev/null
+++ b/clean/video/fakestormer/datasets/dfo.py
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+import os
+from glob import glob
+
+import numpy as np
+
+from .builder import DATASETS
+from .common import CommonDataset
+
+
+@DATASETS.register_module()
+class DFo(CommonDataset):
+ def __init__(self, cfg, **kwargs):
+ super().__init__(cfg, **kwargs)
+
+ def _load_from_path(self, split):
+ assert os.path.exists(
+ self._cfg.DATA[self.split.upper()].ROOT
+ ), "Root path to dataset can not be None!"
+ data = self._cfg["DATA"]
+ data_type = data.TYPE
+ fake_types = self._cfg.DATA[split.upper()]["FAKETYPE"]
+ img_paths, labels, mask_paths, ot_props = [], [], [], []
+
+ # Load image data for each type of fake techniques
+ for idx, ft in enumerate(fake_types):
+ data_dir = os.path.join(
+ self._cfg.DATA[self.split.upper()].ROOT, self.split, data_type, ft
+ )
+ if not os.path.exists(data_dir):
+ raise ValueError("Data Directory can not be invalid!")
+
+ for sub_dir in os.listdir(data_dir):
+ sub_dir_path = os.path.join(data_dir, sub_dir)
+ # sub_dir_path = data_dir
+ img_paths_ = glob(f"{sub_dir_path}/*.{self._cfg.IMAGE_SUFFIX}")
+
+ img_paths.extend(img_paths_)
+ labels.extend(np.full(len(img_paths_), int("manipulated" in ft)))
+
+ print(
+ "{} image paths have been loaded from DeeperForensics!".format(
+ len(img_paths)
+ )
+ )
+ return img_paths, labels, mask_paths, ot_props
diff --git a/clean/video/fakestormer/datasets/dfw.py b/clean/video/fakestormer/datasets/dfw.py
new file mode 100644
index 0000000000000000000000000000000000000000..4e374150446bfecc72539c9e0f1c732df2e1fd36
--- /dev/null
+++ b/clean/video/fakestormer/datasets/dfw.py
@@ -0,0 +1,42 @@
+# -*- coding: utf-8 -*-
+import os
+from glob import glob
+
+import numpy as np
+
+from .builder import DATASETS
+from .common import CommonDataset
+
+
+@DATASETS.register_module()
+class DFW(CommonDataset):
+ def __init__(self, cfg, **kwargs):
+ super().__init__(cfg, **kwargs)
+
+ def _load_from_path(self, split):
+ assert os.path.exists(
+ self._cfg.DATA[self.split.upper()].ROOT
+ ), "Root path to dataset can not be None!"
+ data = self._cfg["DATA"]
+ data_type = data.TYPE
+ fake_types = self._cfg.DATA[split.upper()]["FAKETYPE"]
+ img_paths, labels, mask_paths, ot_props = [], [], [], []
+
+ # Load image data for each type of fake techniques
+ for idx, ft in enumerate(fake_types):
+ data_dir = os.path.join(
+ self._cfg.DATA[self.split.upper()].ROOT, self.split, data_type, ft
+ )
+ if not os.path.exists(data_dir):
+ raise ValueError("Data Directory can not be invalid!")
+
+ for sub_dir in os.listdir(data_dir):
+ sub_dir_path = os.path.join(data_dir, sub_dir)
+ # sub_dir_path = data_dir
+ img_paths_ = glob(f"{sub_dir_path}/*.{self._cfg.IMAGE_SUFFIX}")
+
+ img_paths.extend(img_paths_)
+ labels.extend(np.full(len(img_paths_), int("fake" in ft)))
+
+ print("{} image paths have been loaded from DFW!".format(len(img_paths)))
+ return img_paths, labels, mask_paths, ot_props
diff --git a/clean/video/fakestormer/datasets/diffswap.py b/clean/video/fakestormer/datasets/diffswap.py
new file mode 100644
index 0000000000000000000000000000000000000000..ef26e46129b2a92b259a63ee03fbc7cf544512e7
--- /dev/null
+++ b/clean/video/fakestormer/datasets/diffswap.py
@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+import os
+from glob import glob
+
+import numpy as np
+
+from .builder import DATASETS
+from .common import CommonDataset
+
+
+@DATASETS.register_module()
+class DiffSwap(CommonDataset):
+ def __init__(self, cfg, **kwargs):
+ super().__init__(cfg, **kwargs)
+
+ def _load_from_path(self, split):
+ assert os.path.exists(
+ self._cfg.DATA[self.split.upper()].ROOT
+ ), "Root path to dataset can not be None!"
+ data = self._cfg["DATA"]
+ data_type = data.TYPE
+ fake_types = self._cfg.DATA[split.upper()]["FAKETYPE"]
+ img_paths, labels, mask_paths, ot_props = [], [], [], []
+
+ # Load image data for each type of fake techniques
+ for idx, ft in enumerate(fake_types):
+ data_dir = os.path.join(
+ self._cfg.DATA[self.split.upper()].ROOT, self.split, data_type, ft
+ )
+ if not os.path.exists(data_dir):
+ raise ValueError("Data Directory can not be invalid!")
+
+ if not os.path.isdir(data_dir):
+ continue
+
+ for sub_dir in os.listdir(data_dir):
+ sub_dir_path = os.path.join(data_dir, sub_dir)
+ # sub_dir_path = data_dir
+ img_paths_ = glob(f"{sub_dir_path}/*.{self._cfg.IMAGE_SUFFIX}")
+
+ img_paths.extend(img_paths_)
+ labels.extend(np.full(len(img_paths_), int("Real" not in ft)))
+
+ print("{} image paths have been loaded from DiffSwap!".format(len(img_paths)))
+ return img_paths, labels, mask_paths, ot_props
diff --git a/clean/video/fakestormer/datasets/face_forensic_binary.py b/clean/video/fakestormer/datasets/face_forensic_binary.py
new file mode 100644
index 0000000000000000000000000000000000000000..e323f886c842b5692aa4dff27efd1eb63bc47cd0
--- /dev/null
+++ b/clean/video/fakestormer/datasets/face_forensic_binary.py
@@ -0,0 +1,180 @@
+# -*- coding: utf-8 -*-
+import os
+import sys
+from abc import abstractmethod
+from random import shuffle
+
+import numpy as np
+import torch
+from package_utils.image_utils import load_image
+from PIL import Image
+from torch.utils.data import default_collate
+
+from .builder import DATASETS, PIPELINES, build_pipeline
+from .master import MasterDataset
+
+
+@DATASETS.register_module()
+class BinaryFaceForensic(MasterDataset):
+ def __init__(self, config, split, **kwargs):
+ """
+ @params:
+ config: Dataset config
+ split: train/val/test which directs to the split folders
+ """
+ self.split = split
+ if kwargs is not None:
+ for k, v in kwargs.items():
+ if v is None:
+ raise ValueError(f"{k}:{v} retrieve a None value!")
+ self.__setattr__(k, v)
+ super().__init__(config, **kwargs)
+
+ # Load data
+ self.data_sampler = self._load_data(split)
+
+ # Parse data
+ self._parsing_data()
+
+ # Calling transform methods for inputs
+ self.geo_transform = build_pipeline(config.TRANSFORM.geometry, PIPELINES)
+ self.colorjitter_transform = build_pipeline(config.TRANSFORM.color, PIPELINES)
+
+ def _load_data(self, split, anno_file=None, epoch=0):
+ from_file = self._cfg.DATA[self.split.upper()].FROM_FILE
+
+ if epoch == 0:
+ if not from_file:
+ self.image_paths, self.labels, self.mask_paths, self.ot_props = (
+ self._load_from_path(split)
+ )
+ else:
+ self.image_paths, self.labels, self.mask_paths, self.ot_props = (
+ self._load_from_file(split, anno_file=anno_file)
+ )
+
+ assert (
+ len(self.image_paths) != 0
+ ), "Image paths have not been loaded! Please check image directory!"
+ assert (
+ len(self.labels) != 0
+ ), "Labels have not been loaded! Please check annotation file!"
+
+ if self.sampler_active:
+ print("Running sampler...")
+ params = dict(
+ mask_paths=self.mask_paths, ot_props=self.ot_props, epoch=epoch
+ )
+ data_sampler = self._sampler(self.image_paths, self.labels, **params)
+ return data_sampler
+
+ def _parsing_data(self):
+ assert self.data_type in ["image", "video"]
+ # Parsing data for training
+ if self.data_type == "video":
+ return
+ self.image_paths, self.labels = (
+ self.data_sampler["image_paths"],
+ self.data_sampler["labels"],
+ )
+
+ def _load_img(self, img_path):
+ return load_image(img_path)
+
+ def __len__(self):
+ if self.data_type == "image":
+ assert "image_paths" in self.data_sampler.keys()
+ return len(self.labels)
+ elif self.data_type == "video":
+ return len(self.data_sampler.keys())
+ else:
+ raise ValueError(
+ f'{self.data_type} has not been supported. Please use "image" or "video" instead!'
+ )
+
+ def __getitem__(self, idx):
+ if self.data_type == "image":
+ return self.__getitem_path__(idx=idx)
+ elif self.data_type == "video":
+ return self.__getitem_video__(idx=idx)
+ else:
+ raise ValueError(
+ f"{self.data_type} has not been supported. Only image or video are used for training!"
+ )
+
+ def __getitem_path__(self, idx):
+ img_path = self.image_paths[idx]
+ label = np.expand_dims(self.labels[idx], axis=-1)
+ img = self._load_img(img_path)
+
+ # Applying geo transform to inputs
+ geo_transfomed = self.geo_transform(img)
+ img_trans = geo_transfomed["image"]
+
+ # Applying color transform to inputs
+ color_transfomed = self.colorjitter_transform(img_trans)
+ img_trans = color_transfomed["image"]
+
+ # Normalise + Convert numpy array to tensor
+ img_trans = img_trans / 255
+ img_trans = self.final_transforms(img_trans)
+ return img_trans, label
+
+ def __getitem_video__(self, idx):
+ inputs = []
+ vid_id = [*self.data_sampler.keys()][idx]
+ vid_data = self.data_sampler[vid_id]
+
+ label = np.expand_dims(vid_data[0]["label"], axis=-1)
+
+ f_idxes = range(0, self.samples_per_video)
+ for ix, f_idx in enumerate(f_idxes):
+ it = vid_data[f_idx]
+ img_path = it["image"]
+ img = self._load_img(img_path)
+
+ if self.train:
+ # Applying geo transform to inputs
+ geo_transfomed = self.geo_transform(img)
+ img_trans = geo_transfomed["image"]
+
+ # Applying color transform to inputs
+ color_transfomed = self.colorjitter_transform(img_trans)
+ img_trans = color_transfomed["image"]
+
+ # Normalise + Convert numpy array to tensor
+ img_trans = img_trans / 255
+ else:
+ img_trans = img / 255
+ img_trans = self.final_transforms(img_trans)
+ inputs.append(img_trans)
+ inputs = torch.tensor(np.array([ip.numpy() for ip in inputs]))
+ inputs = inputs.transpose(0, 1)
+
+ if self.train:
+ return inputs, label
+ else:
+ return inputs, label, vid_id.split("-")[0]
+
+ def train_collate_fn(self, batch):
+ return default_collate(batch)
+
+
+if __name__ == "__main__":
+ from configs.get_config import load_config
+ from datasets import *
+ from pipelines.color_transform import ColorJitterTransform
+ from pipelines.geo_transform import GeometryTransform
+ from torch.utils.data import DataLoader
+
+ PIPELINES.register_module(module=GeometryTransform)
+ PIPELINES.register_module(module=ColorJitterTransform)
+
+ config = load_config("configs/temporal/bin_cls/TimeSFormer_base_c23.yaml")
+ bin_ff = DATASETS.build(
+ cfg=config.DATASET, default_args=dict(split="val", config=config.DATASET)
+ )
+ bin_ff_loader = DataLoader(bin_ff, batch_size=10, shuffle=True)
+ for b, (X, y) in enumerate(bin_ff_loader):
+ print(f"X.shape - {X.shape}, y shape - {y.shape}")
+ break
diff --git a/clean/video/fakestormer/datasets/face_forensic_hm.py b/clean/video/fakestormer/datasets/face_forensic_hm.py
new file mode 100644
index 0000000000000000000000000000000000000000..4c4653b1d3a1dc0201d7a73c1d2ed1a404e0eeae
--- /dev/null
+++ b/clean/video/fakestormer/datasets/face_forensic_hm.py
@@ -0,0 +1,447 @@
+# -*- coding: utf-8 -*-
+import random
+
+import cv2
+import numpy as np
+import torch
+from imgaug import augmenters as iaa
+from package_utils.bi_online_generation import (
+ blendImages,
+ colorTransfer,
+ random_erode_dilate,
+ random_get_hull,
+)
+from package_utils.image_utils import load_image
+from package_utils.transform import (
+ get_affine_transform,
+ get_center_scale,
+)
+from package_utils.utils import draw_landmarks, vis_heatmap
+from PIL import Image
+from skimage import transform as sktransform
+
+from .builder import DATASETS, PIPELINES, build_pipeline
+from .master import MasterDataset
+
+
+@DATASETS.register_module()
+class HeatmapFaceForensic(MasterDataset):
+ def __init__(self, config, split, **kwargs):
+ """
+ @params:
+ config: Dataset config
+ split: train/val/test which directs to the split folders
+ """
+ self.split = split
+ super().__init__(config, **kwargs)
+ if kwargs is not None:
+ for k, v in kwargs.items():
+ if v is None:
+ raise ValueError(f"{k}:{v} retrieve a None value!")
+ self.__setattr__(k, v)
+ self.rot = 0
+ self.pixel_std = 200
+ self.target_w = self._cfg.IMAGE_SIZE[1]
+ self.target_h = self._cfg.IMAGE_SIZE[0]
+ self.aspect_ratio = self.target_w * 1.0 / self.target_h
+ self.sigma = self._cfg.SIGMA
+ self.heatmap_type = self._cfg.HEATMAP_TYPE
+ self.debug = self._cfg.DEBUG
+ # self.train = self._cfg.TRAIN
+ self.dynamic_fxray = self._cfg.DYNAMIC_FXRAY
+
+ # Load data
+ self.image_paths, self.labels, self.mask_paths, self.ot_props = self._load_data(
+ split
+ )
+
+ # predefine mask distortion
+ self.distortion = iaa.Sequential([iaa.PiecewiseAffine(scale=(0.01, 0.15))])
+
+ # Calling transform methods for inputs
+ self.geo_transform = build_pipeline(config.TRANSFORM.geometry, PIPELINES)
+ self.colorjitter_transform = build_pipeline(config.TRANSFORM.color, PIPELINES)
+
+ def _load_data(self, split):
+ from_file = self._cfg.DATA[self.split.upper()].FROM_FILE
+
+ if not from_file:
+ image_paths, labels, mask_paths, ot_props = self._load_from_path(split)
+ else:
+ image_paths, labels, mask_paths, ot_props = self._load_from_file(split)
+
+ if self.sampler_active and self.train:
+ print("Running sampler...")
+ params = dict(mask_paths=mask_paths, ot_props=ot_props)
+ data_sampler = self._sampler(image_paths, labels, **params)
+ image_paths, labels = data_sampler["image_paths"], data_sampler["labels"]
+ if len(mask_paths):
+ mask_paths = data_sampler["mask_paths"]
+ if len(ot_props):
+ ot_props = data_sampler["ot_props"]
+ print(f"n samples after running sampling --- {len(image_paths)}")
+
+ assert (
+ len(image_paths) != 0
+ ), "Image paths have not been loaded! Please check image directory!"
+ assert (
+ len(labels) != 0
+ ), "Labels have not been loaded! Please check annotation file!"
+ # if not self.dynamic_fxray or self.split == 'val':
+ if from_file and not (self.dynamic_fxray):
+ assert (
+ len(mask_paths) != 0
+ ), "Mask paths have not been loaded! Please check mask directory!"
+ return image_paths, labels, mask_paths, ot_props
+
+ def _reload_data(self):
+ self.image_paths, self.labels, self.mask_paths, self.ot_props = self._load_data(
+ self.split
+ )
+
+ def _gen_BI(
+ self, background_face, background_landmark, foreground_face_path, idx=None
+ ):
+ foreground_face = load_image(foreground_face_path)
+
+ # down sample before blending
+ aug_size = random.randint(128, 317)
+ background_landmark = background_landmark * (aug_size / 317)
+ foreground_face = sktransform.resize(
+ foreground_face, (aug_size, aug_size), preserve_range=True
+ ).astype(np.uint8)
+ background_face = sktransform.resize(
+ background_face, (aug_size, aug_size), preserve_range=True
+ ).astype(np.uint8)
+
+ # get random type of initial blending mask
+ mask = random_get_hull(background_landmark, background_face)
+
+ if self.debug:
+ Image.fromarray((mask * 255).astype(np.uint8)).save(
+ f"samples/debugs/orig_CH_{idx}.jpg"
+ )
+
+ # random deform mask
+ mask = self.distortion.augment_image(mask)
+ mask = random_erode_dilate(mask)
+
+ if self.debug:
+ Image.fromarray((mask * 255).astype(np.uint8)).save(
+ f"samples/debugs/deformed_CH_{idx}.jpg"
+ )
+
+ # filte empty mask after deformation
+ if np.sum(mask) == 0:
+ raise NotImplementedError
+
+ # apply color transfer
+ foreground_face = colorTransfer(background_face, foreground_face, mask * 255)
+
+ # blend two face
+ blended_face, mask = blendImages(foreground_face, background_face, mask * 255)
+ blended_face = blended_face.astype(np.uint8)
+
+ # resize back to default resolution
+ blended_face = sktransform.resize(
+ blended_face, (317, 317), preserve_range=True
+ ).astype(np.uint8)
+ mask = sktransform.resize(mask, (317, 317), preserve_range=True)
+ mask = mask[:, :, 0:1]
+ return blended_face, mask
+
+ def _gen_target(
+ self, background_face, background_landmark, foreground_face_path, idx=None
+ ):
+ data_type = "real" if random.randint(0, 1) else "fake"
+
+ if not background_landmark.any():
+ data_type = "real"
+
+ if data_type == "fake":
+ face_img, mask = self._gen_BI(
+ background_face, background_landmark, foreground_face_path, idx=idx
+ )
+ mask = (1 - mask) * mask * 4
+ else:
+ face_img = background_face
+ mask = np.zeros((317, 317, 1))
+
+ face_img = Image.fromarray(face_img)
+ # randomly downsample after BI pipeline
+ if random.randint(0, 1):
+ aug_size = random.randint(64, 317)
+ if random.randint(0, 1):
+ face_img = face_img.resize((aug_size, aug_size), Image.BILINEAR)
+ else:
+ face_img = face_img.resize((aug_size, aug_size), Image.NEAREST)
+ face_img = face_img.resize((317, 317), Image.BILINEAR)
+ face_img = np.array(face_img)
+
+ face_img = face_img[60:(317), 30:(287), :]
+ mask = mask[60:(317), 30:(287), :]
+ mask = np.repeat(mask, 3, 2)
+ mask = (mask * 255).astype(np.uint8)
+ return face_img, mask, int(data_type == "fake")
+
+ def __len__(self):
+ return len(self.labels)
+
+ def __getitem__(self, idx):
+ flag = True
+ while flag:
+ try:
+ img_path = self.image_paths[idx]
+ label = self.labels[idx]
+ vid_id = img_path.split("/")[-2]
+ img = load_image(img_path)
+ mask = None
+
+ if self.debug:
+ Image.fromarray(img).save(f"samples/debugs/orig_{idx}.jpg")
+
+ # Applying color transform to inputs
+ if self.split == "train":
+ color_transfomed = self.colorjitter_transform(img)
+ img = color_transfomed["image"]
+
+ # if not self.dynamic_fxray or self.split == 'val':
+ if not self.dynamic_fxray:
+ if bool(self.mask_paths):
+ mask_path = self.mask_paths[idx]
+ mask = load_image(mask_path)
+ else:
+ if self.train:
+ best_match = (
+ self.ot_props[idx]["best_match"]
+ if len(self.ot_props[idx]["best_match"])
+ else []
+ )
+ if len(self.ot_props[idx]["aligned_lms"]):
+ f_lms = self.ot_props[idx]["aligned_lms"]
+ elif len(self.ot_props[idx]["orig_lms"]):
+ f_lms = self.ot_props[idx]["orig_lms"]
+ else:
+ f_lms = []
+
+ if self.debug:
+ img_lms_draw = draw_landmarks(img, f_lms)
+ Image.fromarray(img_lms_draw).save(
+ f"samples/debugs/orig_{idx}_lms.jpg"
+ )
+
+ if len(best_match):
+ best_match_idx = random.randint(0, len(best_match) - 1)
+ best_match_path = best_match[best_match_idx]
+ img, mask, label = self._gen_target(
+ img, f_lms, best_match_path, idx=idx
+ )
+ else:
+ img, mask, label = self._gen_target(img, np.array([]), "")
+ else:
+ img = cv2.resize(img, (317, 317))
+ # Best croppings from 18-299 for testing
+ img = img[18:(299), 18:(299), :]
+ target = None
+
+ if mask is not None:
+ assert (
+ mask.shape[:2] == img.shape[:2]
+ ), "Color Image and Mask must have the same shape!"
+
+ # Applying geo transform to inputs and masks
+ if self.split == "train":
+ geo_transfomed = self.geo_transform(img, mask=mask)
+ img = geo_transfomed["image"]
+ mask = geo_transfomed["mask"]
+
+ # Applying affine transform
+ c, s = get_center_scale(
+ img.shape[:2], self.aspect_ratio, pixel_std=self.pixel_std
+ )
+ trans = get_affine_transform(c, s, self.rot, self._cfg.IMAGE_SIZE)
+ trans_heatmap = get_affine_transform(
+ c, s, self.rot, self._cfg.HEATMAP_SIZE
+ )
+
+ input = cv2.warpAffine(
+ img,
+ trans,
+ (int(self._cfg.IMAGE_SIZE[0]), int(self._cfg.IMAGE_SIZE[1])),
+ flags=cv2.INTER_LINEAR,
+ )
+
+ if mask is not None:
+ target = cv2.warpAffine(
+ mask,
+ trans_heatmap,
+ (
+ int(self._cfg.HEATMAP_SIZE[0]),
+ int(self._cfg.HEATMAP_SIZE[1]),
+ ),
+ flags=cv2.INTER_LINEAR,
+ )
+
+ # Target encoding
+ # 0 for original, 1 for FXRay, 2 for NoFXRay. If 2, comment: mask = (1 - mask) * mask * 4
+ heatmap, cstency_hm = (
+ self.select_encode_method(version=1)(target)
+ if (
+ target is not None
+ and self.heatmap_type == "gaussian"
+ and self.train
+ )
+ else (None, None)
+ )
+
+ if self.debug:
+ Image.fromarray(input).save(f"samples/debugs/affine_{idx}.jpg")
+ Image.fromarray(target).save(
+ f"samples/debugs/mask_affine_{idx}.jpg"
+ )
+ vis_heatmap(
+ input,
+ cstency_hm / 255,
+ f"samples/debugs/cstency_mask_{idx}.jpg",
+ )
+ vis_heatmap(input, heatmap, f"samples/debugs/hm_{idx}.jpg")
+
+ if self.train:
+ if self.split_image:
+ patch_img_trans = []
+ patch_heatmap = []
+ patch_cstency_hm = []
+ patch_target = []
+ patch_label = np.expand_dims(np.tile(label, len(heatmap)), -1)
+
+ for i, (k, l) in enumerate(
+ [[0, 0], [1 / 2, 0], [0, 1 / 2], [1 / 2, 1 / 2]]
+ ):
+ input_ = input[
+ int(self.target_h * k) : int(
+ self.target_h * (k + 1 / 2)
+ ),
+ int(self.target_w * l) : int(
+ self.target_w * (l + 1 / 2)
+ ),
+ :,
+ ]
+ heatmap_ = heatmap[i][
+ int(self.heatmap_h * k) : int(
+ self.heatmap_h * (k + 1 / 2)
+ ),
+ int(self.heatmap_w * l) : int(
+ self.heatmap_w * (l + 1 / 2)
+ ),
+ ]
+ cstency_ = cstency_hm[i][
+ int(self.heatmap_h * k) : int(
+ self.heatmap_h * (k + 1 / 2)
+ ),
+ int(self.heatmap_w * l) : int(
+ self.heatmap_w * (l + 1 / 2)
+ ),
+ ]
+ target_ = target[..., 0][
+ int(self.heatmap_h * k) : int(
+ self.heatmap_h * (k + 1 / 2)
+ ),
+ int(self.heatmap_w * l) : int(
+ self.heatmap_w * (l + 1 / 2)
+ ),
+ ]
+
+ # Normalise + Convert numpy array to tensor
+ input_ = input_ / 255
+ patch_img_trans.append(self.final_transforms(input_))
+
+ patch_heatmap.append(heatmap_)
+ patch_cstency_hm.append(cstency_ / 255)
+ patch_target.append(target_ / 255)
+ else:
+ patch_img_trans = self.final_transforms(input / 255)
+ patch_heatmap = heatmap
+ patch_cstency_hm = cstency_hm / 255
+ patch_target = target / 255
+ patch_label = np.expand_dims(label, axis=-1)
+ # patch_label = label
+ else:
+ # Normalise + Convert numpy array to tensor
+ img_trans = input / 255
+ img_trans = self.final_transforms(img_trans)
+ label = np.expand_dims(label, axis=-1)
+ flag = False
+ except Exception as e:
+ print("There is an exception during loading data, please check --- ", e)
+ idx = torch.randint(low=0, high=self.__len__(), size=(1,)).item()
+
+ if self.train:
+ return (
+ patch_img_trans,
+ patch_label,
+ patch_target,
+ patch_heatmap,
+ patch_cstency_hm,
+ )
+ else:
+ meta = {"vid_id": vid_id, "img_path": img_path}
+ return img_trans, label, meta
+
+ def train_collate_fn(self, batch):
+ batch_data = {}
+ img, label, target, hm, cstency_hm = zip(*batch)
+
+ # Collating data in case of using spliting images into patches
+ if self.split_image:
+ hm_H, hm_W = hm[0][0].shape
+
+ img = np.reshape(img, (-1))
+ hm = np.reshape(hm, (-1, 1, hm_H, hm_W))
+ cstency_hm = np.reshape(cstency_hm, (-1, 1, hm_H, hm_W))
+ target = np.reshape(target, (-1, 1, hm_H, hm_W))
+ label = np.reshape(label, (-1, 1))
+
+ img = torch.tensor([it.numpy() for it in img])
+ heatmap = torch.tensor(hm).float()
+ cstency_heatmap = torch.tensor(cstency_hm).float()
+ target = torch.tensor(target).float()
+ label = torch.tensor(label)
+
+ batch_data["img"] = img
+ batch_data["label"] = label
+ batch_data["target"] = target
+ batch_data["heatmap"] = heatmap
+ batch_data["cstency"] = cstency_heatmap
+
+ return batch_data
+
+
+if __name__ == "__main__":
+ # from datasets import *
+ from configs.get_config import load_config
+ from pipelines.color_transform import ColorJitterTransform
+ from pipelines.geo_transform import GeometryTransform
+ from torch.utils.data import DataLoader
+
+ PIPELINES.register_module(module=GeometryTransform)
+ PIPELINES.register_module(module=ColorJitterTransform)
+
+ config = load_config("configs/efn4_fpn_hm_adv.yaml")
+ hm_ff = DATASETS.build(
+ cfg=config.DATASET, default_args=dict(split="train", config=config.DATASET)
+ )
+ hm_ff_loader = DataLoader(
+ hm_ff, batch_size=10, shuffle=False, collate_fn=hm_ff.train_collate_fn
+ )
+ for b, batch_data in enumerate(hm_ff_loader):
+ inputs, labels, targets, heatmaps, cstency_heatmap = (
+ batch_data["img"],
+ batch_data["label"],
+ batch_data["target"],
+ batch_data["heatmap"],
+ batch_data["cstency_heatmap"],
+ )
+ print(
+ f"X.shape - {inputs.shape}, y shape - {labels.shape}, heatmaps - {heatmaps.shape}, consistency -- {cstency_heatmap.shape}"
+ )
+ break
diff --git a/clean/video/fakestormer/datasets/face_forensic_sbi.py b/clean/video/fakestormer/datasets/face_forensic_sbi.py
new file mode 100644
index 0000000000000000000000000000000000000000..c92e169efd99e5fc1c9b2168c74fb73ad1837b1c
--- /dev/null
+++ b/clean/video/fakestormer/datasets/face_forensic_sbi.py
@@ -0,0 +1,463 @@
+# -*- coding: utf-8 -*-
+import os
+import random
+import sys
+
+import cv2
+import numpy as np
+import torch
+import torch.nn.functional as F
+from package_utils.image_utils import crop_by_margin, load_image
+from package_utils.transform import get_affine_transform, get_center_scale
+from package_utils.utils import draw_landmarks, draw_most_vul_points, vis_heatmap
+from PIL import Image
+
+from .builder import DATASETS, PIPELINES, build_pipeline
+from .master import MasterDataset
+from .pipelines.geo_transform import get_transforms
+from .sbi.utils import *
+
+
+@DATASETS.register_module()
+class SBIFaceForensic(MasterDataset):
+ def __init__(self, config, split, **kwargs):
+ """
+ @params:
+ config: Dataset config
+ split: train/val/test which directs to the split folders
+ """
+ self.split = split
+ super(SBIFaceForensic, self).__init__(config, **kwargs)
+ if kwargs is not None:
+ for k, v in kwargs.items():
+ if v is None:
+ raise ValueError(f"{k}:{v} retrieve a None value!")
+ self.__setattr__(k, v)
+ self.rot = 0
+ self.pixel_std = 200
+ self.target_w = self._cfg.IMAGE_SIZE[1]
+ self.target_h = self._cfg.IMAGE_SIZE[0]
+ self.aspect_ratio = self.target_w * 1.0 / self.target_h
+ self.sigma = self._cfg.SIGMA
+ self.heatmap_type = self._cfg.HEATMAP_TYPE
+ self.debug = self._cfg.DEBUG
+ # self.train = self._cfg.TRAIN
+ self.dynamic_fxray = self._cfg.DYNAMIC_FXRAY
+
+ # Load data
+ self.image_paths_r, self.labels_r, self.mask_paths_r, self.ot_props_r = (
+ self._load_data(split)
+ )
+
+ # Calling transform methods for inputs
+ self.geo_transform = build_pipeline(
+ config.TRANSFORM.geometry,
+ PIPELINES,
+ default_args={"additional_targets": {"image_f": "image", "mask_f": "mask"}},
+ )
+ # self.colorjitter_transform = build_pipeline(config.TRANSFORM.color, PIPELINES)
+
+ self.transforms = get_transforms()
+
+ def __len__(self):
+ return len(self.labels_r)
+
+ def _load_img(self, img_path):
+ return load_image(img_path)
+
+ def _reload_data(self):
+ self.image_paths, self.labels, self.mask_paths, self.ot_props = self._load_data(
+ self.split
+ )
+
+ def _load_data(self, split, anno_file=None):
+ from_file = self._cfg.DATA[self.split.upper()].FROM_FILE
+
+ if not from_file:
+ image_paths, labels, mask_paths, ot_props = self._load_from_path(split)
+ else:
+ image_paths, labels, mask_paths, ot_props = self._load_from_file(
+ split, anno_file=anno_file
+ )
+
+ assert (
+ len(image_paths) != 0
+ ), "Image paths have not been loaded! Please check image directory!"
+ assert (
+ len(labels) != 0
+ ), "Labels have not been loaded! Please check annotation file!"
+ if not self.dynamic_fxray:
+ assert (
+ len(mask_paths) != 0
+ ), "Mask paths have not been loaded! Please check mask directory!"
+
+ if self.sampler_active:
+ print("Running sampler...")
+ params = dict(mask_paths=mask_paths, ot_props=ot_props)
+ data_sampler = self._sampler(image_paths, labels, **params)
+ image_paths, labels = data_sampler["image_paths"], data_sampler["labels"]
+ if len(mask_paths):
+ mask_paths = data_sampler["mask_paths"]
+ if len(ot_props):
+ ot_props = data_sampler["ot_props"]
+ print(f"n samples after running sampling --- {len(image_paths)}")
+ return image_paths, labels, mask_paths, ot_props
+
+ def __getitem__(self, idx):
+ flag = True
+ while flag:
+ try:
+ # Selecting data from data list
+ img_path = self.image_paths_r[idx]
+ label = self.labels_r[idx]
+ vid_id = img_path.split("/")[-2]
+ img = self._load_img(img_path)
+ if self.split == "test":
+ # Best is 17,17 and 0.0 and 5,5
+ img = crop_by_margin(img, margin=[5, 5])
+
+ img_f = None
+ mask = None
+ mask_f = None
+
+ # if not self.dynamic_fxray or self.split == 'val':
+ if not self.dynamic_fxray:
+ if bool(self.mask_paths_r):
+ mask_path = self.mask_paths_r[idx]
+ mask = self._load_img(mask_path)
+ else:
+ mask = np.zeros((img.shape[0], img.shape[1], 3))
+ else:
+ if self.train:
+ if len(self.ot_props_r[idx]["aligned_lms"]):
+ f_lms = self.ot_props_r[idx]["aligned_lms"]
+ elif len(self.ot_props_r[idx]["orig_lms"]):
+ f_lms = self.ot_props_r[idx]["orig_lms"]
+ else:
+ f_lms = []
+ f_lms = np.array(f_lms)
+ if not f_lms.any():
+ raise ValueError(
+ "Can not find fake copy image of empty landmarks!"
+ )
+
+ if len(f_lms) > 68:
+ f_lms = reorder_landmark(f_lms)
+
+ # if self.debug:
+ # img_lms_draw = draw_landmarks(img, f_lms)
+ # Image.fromarray(img_lms_draw).save(f'samples/debugs/orig_{idx}_lms.jpg')
+
+ if self.split == "train":
+ if np.random.rand() < 0.5:
+ img, ___, f_lms, __ = sbi_hflip(img, None, f_lms, None)
+
+ margin = np.random.randint(5, 25)
+ img_f, mask_f, img, mask, fake_intensity = gen_target(
+ img, f_lms, margin=[margin, margin], index=idx, debug=False
+ )
+ target = None
+ target_f = None
+
+ if mask is not None:
+ assert (
+ mask.shape[:2] == img.shape[:2]
+ ), "Color Image and Mask must have the same shape!"
+
+ # Applying affine transform
+ c, s = get_center_scale(
+ img.shape[:2], self.aspect_ratio, pixel_std=self.pixel_std
+ )
+
+ # Applying geo transform to images and masks
+ if self.split == "train":
+ geo_transfomed = self.geo_transform(
+ img, mask=mask, image_f=img_f, mask_f=mask_f
+ )
+ img = geo_transfomed["image"]
+ mask = geo_transfomed["mask"]
+ img_f = geo_transfomed["image_f"]
+ mask_f = geo_transfomed["mask_f"]
+
+ trans = get_affine_transform(
+ c, s, self.rot, self._cfg.IMAGE_SIZE, pixel_std=self.pixel_std
+ )
+ trans_heatmap = get_affine_transform(
+ c, s, self.rot, self._cfg.HEATMAP_SIZE, pixel_std=self.pixel_std
+ )
+
+ input = cv2.warpAffine(
+ img,
+ trans,
+ (int(self._cfg.IMAGE_SIZE[0]), int(self._cfg.IMAGE_SIZE[1])),
+ flags=cv2.INTER_LINEAR,
+ )
+
+ if img_f is not None:
+ input_f = cv2.warpAffine(
+ img_f,
+ trans,
+ (int(self._cfg.IMAGE_SIZE[0]), int(self._cfg.IMAGE_SIZE[1])),
+ flags=cv2.INTER_LINEAR,
+ )
+
+ if mask is not None:
+ target = cv2.warpAffine(
+ mask,
+ trans_heatmap,
+ (
+ int(self._cfg.HEATMAP_SIZE[0]),
+ int(self._cfg.HEATMAP_SIZE[1]),
+ ),
+ flags=cv2.INTER_LINEAR,
+ )
+
+ if mask_f is not None:
+ target_f = cv2.warpAffine(
+ mask_f,
+ trans_heatmap,
+ (
+ int(self._cfg.HEATMAP_SIZE[0]),
+ int(self._cfg.HEATMAP_SIZE[1]),
+ ),
+ flags=cv2.INTER_LINEAR,
+ )
+
+ # Drawing the most vulnerable points (MVPs)
+ if self.debug:
+ mvp_f_drawed = draw_most_vul_points(target_f)
+ mvp_drawed = draw_most_vul_points(target)
+ Image.fromarray(mvp_f_drawed).save(
+ f"samples/debugs/mvp_f_{idx}.jpg"
+ )
+ Image.fromarray(mvp_drawed).save(f"samples/debugs/mvp_{idx}.jpg")
+
+ # Target encoding
+ # 0 for original, 1 for FXRay, 2 for NoFXRay. If 2, comment: mask = (1 - mask) * mask * 4
+ heatmap, cstency_hm = (
+ self.select_encode_method(version=1)(target)
+ if (
+ target is not None
+ and self.heatmap_type == "gaussian"
+ and self.train
+ )
+ else (None, None)
+ )
+ heatmap_f, cstency_hm_f = (
+ self.select_encode_method(version=1)(target_f)
+ if (
+ target_f is not None
+ and self.heatmap_type == "gaussian"
+ and self.train
+ )
+ else (None, None)
+ )
+
+ # Applying transform for blending images
+ if self.train:
+ if target_f is None:
+ transformed = self.transforms(image=input.astype("uint8"))
+ input = transformed["image"]
+ else:
+ transformed = self.transforms(
+ image=input.astype("uint8"), image_f=input_f.astype("uint8")
+ )
+ input = transformed["image"]
+ input_f = transformed["image_f"]
+
+ if self.debug:
+ Image.fromarray(input).save(f"samples/debugs/affine_{idx}.jpg")
+ Image.fromarray(input_f).save(f"samples/debugs/affine_f_{idx}.jpg")
+ Image.fromarray(target).save(
+ f"samples/debugs/mask_affine_{idx}.jpg"
+ )
+ Image.fromarray(target_f).save(
+ f"samples/debugs/mask_affine_f_{idx}.jpg"
+ )
+ Image.fromarray(mask).save(f"samples/debugs/mask_{idx}.jpg")
+ Image.fromarray(mask_f).save(f"samples/debugs/mask_f_{idx}.jpg")
+ vis_heatmap(
+ input,
+ cstency_hm_f / 255,
+ f"samples/debugs/cstency_mask_f_{idx}.jpg",
+ )
+ vis_heatmap(
+ input,
+ cstency_hm / 255,
+ f"samples/debugs/cstency_mask_{idx}.jpg",
+ )
+ vis_heatmap(input, heatmap, f"samples/debugs/hm_{idx}.jpg")
+ vis_heatmap(input_f, heatmap_f, f"samples/debugs/hm_f_{idx}.jpg")
+
+ if self.train:
+ # if self.split_image:
+ # patch_img_trans = []
+ # patch_heatmap_r = []
+ # patch_img_trans_f = []
+ # patch_heatmap_f = []
+ # patch_target_r = []
+ # patch_target_f = []
+
+ # for i, (k, l) in enumerate([[0,0], [1/2,0], [0,1/2], [1/2,1/2]]):
+ # input_ = input[int(self.target_h*k): int(self.target_h*(k+1/2)), int(self.target_w*l): int(self.target_w*(l+1/2)), :]
+ # input_f_ = input_f[int(self.target_h*k): int(self.target_h*(k+1/2)), int(self.target_w*l): int(self.target_w*(l+1/2)), :]
+ # heatmap_ = heatmap[i][int(self.heatmap_h*k): int(self.heatmap_h*(k+1/2)), int(self.heatmap_w*l): int(self.heatmap_w*(l+1/2))]
+ # heatmap_f_ = heatmap_f[i][int(self.heatmap_h*k): int(self.heatmap_h*(k+1/2)), int(self.heatmap_w*l): int(self.heatmap_w*(l+1/2))]
+ # target_ = target[..., 0][int(self.heatmap_h*k): int(self.heatmap_h*(k+1/2)), int(self.heatmap_w*l): int(self.heatmap_w*(l+1/2))]
+ # target_f_ = target_f[..., 0][int(self.heatmap_h*k): int(self.heatmap_h*(k+1/2)), int(self.heatmap_w*l): int(self.heatmap_w*(l+1/2))]
+
+ # # Flipping
+ # if np.random.random() < 0.5:
+ # input_ = input_[:, ::-1, :]
+ # input_f_ = input_f_[:, ::-1, :]
+ # heatmap_f_ = heatmap_f_[:, ::-1]
+
+ # #Normalise + Convert numpy array to tensor
+ # input_f_ = input_f_/255
+ # patch_img_trans_f.append(self.final_transforms(input_f_))
+
+ # input_ = input_/255
+ # patch_img_trans.append(self.final_transforms(input_))
+
+ # patch_heatmap_r.append(heatmap_)
+ # patch_heatmap_f.append(heatmap_f_)
+ # patch_target_r.append(target_/255)
+ # patch_target_f.append(target_f_/255)
+ # else:
+ patch_img_trans = self.final_transforms(input / 255)
+ patch_img_trans_f = self.final_transforms(input_f / 255)
+ patch_heatmap_f = heatmap_f
+ patch_heatmap_r = heatmap
+ patch_target_f = target_f / 255
+ patch_target_r = target / 255
+ patch_cstency_r = cstency_hm / 255
+ patch_cstency_f = cstency_hm_f / 255
+ else:
+ # Normalise + Convert numpy array to tensor
+ img_trans = input / 255
+ img_trans = self.final_transforms(img_trans)
+
+ label = np.expand_dims(label, axis=-1)
+ flag = False
+ except Exception as e:
+ # print(f'There is something wrong! Please check the DataLoader!, {e}')
+ flag = True
+ idx = torch.randint(low=0, high=self.__len__(), size=(1,)).item()
+
+ if self.train:
+ return (
+ patch_img_trans_f,
+ patch_heatmap_f,
+ patch_target_f,
+ patch_cstency_f,
+ patch_img_trans,
+ patch_heatmap_r,
+ patch_target_r,
+ patch_cstency_r,
+ )
+ else:
+ meta = {"vid_id": vid_id, "img_path": img_path}
+ return img_trans, label, meta
+
+ def train_collate_fn(self, batch):
+ batch_data = {}
+
+ img_f, hm_f, target_f, cst_f, img_r, hm_r, target_r, cst_r = zip(*batch)
+
+ # Collating data in case of using spliting images into patches
+ # if self.split_image:
+ # hm_H, hm_W = hm_r[0][0].shape
+
+ # img_f = np.reshape(img_f, (-1))
+ # hm_f = np.reshape(hm_f, (-1, 1, hm_H, hm_W))
+ # target_f = np.reshape(target_f, (-1, 1, hm_H, hm_W))
+ # img_r = np.reshape(img_r, (-1))
+ # hm_r = np.reshape(hm_r, (-1, 1, hm_H, hm_W))
+ # target_r = np.reshape(target_r, (-1, 1, hm_H, hm_W))
+
+ img = torch.cat(
+ [
+ torch.tensor(np.array([it.numpy() for it in img_r])),
+ torch.tensor(np.array([it.numpy() for it in img_f])),
+ ],
+ 0,
+ )
+ heatmap = torch.cat(
+ [
+ torch.tensor(np.array(hm_r)).float(),
+ torch.tensor(np.array(hm_f)).float(),
+ ],
+ 0,
+ )
+ target = torch.cat(
+ [
+ torch.tensor(np.array(target_r)).float(),
+ torch.tensor(np.array(target_f)).float(),
+ ],
+ 0,
+ )
+ label = torch.tensor([[0]] * len(img_r) + [[1]] * len(img_f))
+ # label = torch.tensor([0] * len(img_r) + [1]*len(img_f))
+ cst = torch.cat(
+ [
+ torch.tensor(np.array(cst_r)).float(),
+ torch.tensor(np.array(cst_f)).float(),
+ ],
+ 0,
+ )
+
+ b_size = label.size(0)
+
+ # Permute idxes
+ idxes = torch.randperm(b_size)
+ img, label, target, heatmap, cst = (
+ img[idxes],
+ label[idxes],
+ target[idxes],
+ heatmap[idxes],
+ cst[idxes],
+ )
+
+ batch_data["img"] = img
+ batch_data["label"] = label
+ batch_data["target"] = target
+ batch_data["heatmap"] = heatmap
+ batch_data["cstency"] = cst
+
+ return batch_data
+
+ def train_worker_init_fn(self, worker_id):
+ # print('Current state {} --- worker id {}'.format(np.random.get_state()[1][0], worker_id))
+ np.random.seed(np.random.get_state()[1][0] + worker_id)
+
+
+if __name__ == "__main__":
+ from configs.get_config import load_config
+ from pipelines.geo_transform import GeometryTransform
+ from torch.utils.data import DataLoader
+
+ PIPELINES.register_module(module=GeometryTransform)
+
+ config = load_config("configs/efn4_fpn_sbi_adv.yaml")
+ hm_ff = DATASETS.build(
+ cfg=config.DATASET, default_args=dict(split="train", config=config.DATASET)
+ )
+ hm_ff_loader = DataLoader(
+ hm_ff,
+ batch_size=10,
+ shuffle=True,
+ collate_fn=hm_ff.train_collate_fn,
+ worker_init_fn=hm_ff.train_worker_init_fn,
+ )
+
+ for b, batch_data in enumerate(hm_ff_loader):
+ inputs, labels, heatmaps, consistencies = (
+ batch_data["img"],
+ batch_data["label"],
+ batch_data["heatmap"],
+ batch_data["cstency"],
+ )
+ print(
+ f"X.shape - {inputs.shape}, y shape - {labels.shape}, heatmap shape - {heatmaps.shape}, {heatmaps.max()}, cst shape - {consistencies.shape}"
+ )
+ break
diff --git a/clean/video/fakestormer/datasets/fakesformer_bi.py b/clean/video/fakestormer/datasets/fakesformer_bi.py
new file mode 100644
index 0000000000000000000000000000000000000000..6cdee4afac2dafc3c6f794ececfb8c3d7281b64d
--- /dev/null
+++ b/clean/video/fakestormer/datasets/fakesformer_bi.py
@@ -0,0 +1,394 @@
+# -*- coding: utf-8 -*-
+import random
+
+import cv2
+import numpy as np
+import torch
+from imgaug import augmenters as iaa
+from package_utils.bi_online_generation import (
+ blendImages,
+ colorTransfer,
+ random_erode_dilate,
+ random_get_hull,
+)
+from package_utils.image_utils import load_image
+from package_utils.transform import (
+ get_affine_transform,
+ get_center_scale,
+)
+from package_utils.utils import draw_landmarks, vis_heatmap
+from PIL import Image
+from skimage import transform as sktransform
+
+from .builder import DATASETS, PIPELINES, build_pipeline
+from .master import MasterDataset
+
+
+@DATASETS.register_module()
+class FakeSFormerBI(MasterDataset):
+ def __init__(self, config, split, **kwargs):
+ """
+ @params:
+ config: Dataset config
+ split: train/val/test which directs to the split folders
+ """
+ self.split = split
+ super().__init__(config, **kwargs)
+ if kwargs is not None:
+ for k, v in kwargs.items():
+ if v is None:
+ raise ValueError(f"{k}:{v} retrieve a None value!")
+ self.__setattr__(k, v)
+ self.rot = 0
+ self.pixel_std = 200
+ self.target_w = self._cfg.IMAGE_SIZE[1]
+ self.target_h = self._cfg.IMAGE_SIZE[0]
+ self.aspect_ratio = self.target_w * 1.0 / self.target_h
+ self.sigma = self._cfg.SIGMA
+ self.heatmap_type = self._cfg.HEATMAP_TYPE
+ self.debug = self._cfg.DEBUG
+ self.dynamic_fxray = self._cfg.DYNAMIC_FXRAY
+ self.target_overlap = self._cfg.TARGET_OVERLAP
+
+ # Load data
+ self.image_paths, self.labels, self.mask_paths, self.ot_props = self._load_data(
+ split
+ )
+
+ # predefine mask distortion
+ self.distortion = iaa.Sequential([iaa.PiecewiseAffine(scale=(0.01, 0.15))])
+
+ # Calling transform methods for inputs
+ self.geo_transform = build_pipeline(config.TRANSFORM.geometry, PIPELINES)
+ self.colorjitter_transform = build_pipeline(config.TRANSFORM.color, PIPELINES)
+
+ def _load_data(self, split):
+ from_file = self._cfg.DATA[self.split.upper()].FROM_FILE
+
+ if not from_file:
+ image_paths, labels, mask_paths, ot_props = self._load_from_path(split)
+ else:
+ image_paths, labels, mask_paths, ot_props = self._load_from_file(split)
+
+ if self.sampler_active and self.train:
+ print("Running sampler...")
+ params = dict(mask_paths=mask_paths, ot_props=ot_props)
+ data_sampler = self._sampler(image_paths, labels, **params)
+ image_paths, labels = data_sampler["image_paths"], data_sampler["labels"]
+ if len(mask_paths):
+ mask_paths = data_sampler["mask_paths"]
+ if len(ot_props):
+ ot_props = data_sampler["ot_props"]
+ print(f"n samples after running sampling --- {len(image_paths)}")
+
+ assert (
+ len(image_paths) != 0
+ ), "Image paths have not been loaded! Please check image directory!"
+ assert (
+ len(labels) != 0
+ ), "Labels have not been loaded! Please check annotation file!"
+ # if not self.dynamic_fxray or self.split == 'val':
+ if from_file and not (self.dynamic_fxray):
+ assert (
+ len(mask_paths) != 0
+ ), "Mask paths have not been loaded! Please check mask directory!"
+ return image_paths, labels, mask_paths, ot_props
+
+ def _reload_data(self):
+ self.image_paths, self.labels, self.mask_paths, self.ot_props = self._load_data(
+ self.split
+ )
+
+ def _gen_BI(
+ self, background_face, background_landmark, foreground_face_path, idx=None
+ ):
+ foreground_face = load_image(foreground_face_path)
+
+ # down sample before blending
+ aug_size = random.randint(128, 317)
+ background_landmark = background_landmark * (aug_size / 317)
+ foreground_face = sktransform.resize(
+ foreground_face, (aug_size, aug_size), preserve_range=True
+ ).astype(np.uint8)
+ background_face = sktransform.resize(
+ background_face, (aug_size, aug_size), preserve_range=True
+ ).astype(np.uint8)
+
+ # get random type of initial blending mask
+ mask = random_get_hull(background_landmark, background_face)
+
+ # if self.debug:
+ # Image.fromarray((mask*255).astype(np.uint8)).save(f'samples/debugs/orig_CH_{idx}.jpg')
+
+ # random deform mask
+ mask = self.distortion.augment_image(mask)
+ mask = random_erode_dilate(mask)
+
+ # if self.debug:
+ # Image.fromarray((mask*255).astype(np.uint8)).save(f'samples/debugs/deformed_CH_{idx}.jpg')
+
+ # filte empty mask after deformation
+ if np.sum(mask) == 0:
+ raise NotImplementedError
+
+ # apply color transfer
+ foreground_face = colorTransfer(background_face, foreground_face, mask * 255)
+
+ # blend two face
+ blended_face, mask = blendImages(foreground_face, background_face, mask * 255)
+ blended_face = blended_face.astype(np.uint8)
+
+ # resize back to default resolution
+ blended_face = sktransform.resize(
+ blended_face, (317, 317), preserve_range=True
+ ).astype(np.uint8)
+ mask = sktransform.resize(mask, (317, 317), preserve_range=True)
+ mask = mask[:, :, 0:1]
+ return blended_face, mask
+
+ def _gen_target(
+ self, background_face, background_landmark, foreground_face_path, idx=None
+ ):
+ data_label = "real" if random.randint(0, 1) else "fake"
+
+ if not background_landmark.any():
+ data_label = "real"
+
+ if data_label == "fake":
+ face_img, mask = self._gen_BI(
+ background_face, background_landmark, foreground_face_path, idx=idx
+ )
+ mask = (1 - mask) * mask * 4
+ else:
+ face_img = background_face
+ mask = np.zeros((317, 317, 1))
+
+ face_img = Image.fromarray(face_img)
+ # randomly downsample after BI pipeline
+ if random.randint(0, 1):
+ aug_size = random.randint(64, 317)
+ if random.randint(0, 1):
+ face_img = face_img.resize((aug_size, aug_size), Image.BILINEAR)
+ else:
+ face_img = face_img.resize((aug_size, aug_size), Image.NEAREST)
+ face_img = face_img.resize((317, 317), Image.BILINEAR)
+ face_img = np.array(face_img)
+
+ soft_margin = np.random.randint(-30, 30)
+
+ face_img = face_img[
+ 30 + soft_margin : (287 + soft_margin),
+ 30 + soft_margin : (287 + soft_margin),
+ :,
+ ]
+ mask = mask[
+ 30 + soft_margin : (287 + soft_margin),
+ 30 + soft_margin : (287 + soft_margin),
+ :,
+ ]
+ mask = np.repeat(mask, 3, 2)
+ mask = (mask * 255).astype(np.uint8)
+ return face_img, mask, int(data_label == "fake")
+
+ def __len__(self):
+ return len(self.labels)
+
+ def __getitem__(self, idx):
+ flag = True
+ while flag:
+ try:
+ img_path = self.image_paths[idx]
+ label = self.labels[idx]
+ vid_id = img_path.split("/")[-2]
+ img = load_image(img_path)
+ mask = None
+
+ # if self.debug:
+ # Image.fromarray(img).save(f'samples/debugs/orig_{idx}.jpg')
+
+ # Applying color transform to inputs
+ if self.split == "train":
+ color_transfomed = self.colorjitter_transform(img)
+ img = color_transfomed["image"]
+
+ # if not self.dynamic_fxray or self.split == 'val':
+ if not self.dynamic_fxray:
+ if bool(self.mask_paths):
+ mask_path = self.mask_paths[idx]
+ mask = load_image(mask_path)
+ else:
+ if self.train:
+ best_match = (
+ self.ot_props[idx]["best_match"]
+ if len(self.ot_props[idx]["best_match"])
+ else []
+ )
+ if len(self.ot_props[idx]["aligned_lms"]):
+ f_lms = self.ot_props[idx]["aligned_lms"]
+ elif len(self.ot_props[idx]["orig_lms"]):
+ f_lms = self.ot_props[idx]["orig_lms"]
+ else:
+ f_lms = []
+
+ # if self.debug:
+ # img_lms_draw = draw_landmarks(img, f_lms)
+ # Image.fromarray(img_lms_draw).save(f'samples/debugs/orig_{idx}_lms.jpg')
+
+ if len(best_match):
+ best_match_idx = random.randint(0, len(best_match) - 10)
+ best_match_path = best_match[best_match_idx]
+ img, mask, label = self._gen_target(
+ img, f_lms, best_match_path, idx=idx
+ )
+ else:
+ img, mask, label = self._gen_target(img, np.array([]), "")
+ else:
+ img = cv2.resize(img, (317, 317))
+ # Best croppings from 18-299 for testing
+ img = img[18:(299), 18:(299), :]
+ target = None
+
+ if mask is not None:
+ assert (
+ mask.shape[:2] == img.shape[:2]
+ ), "Color Image and Mask must have the same shape!"
+
+ # Applying geo transform to inputs and masks
+ if self.split == "train":
+ geo_transfomed = self.geo_transform(img, mask=mask)
+ img = geo_transfomed["image"]
+ mask = geo_transfomed["mask"]
+
+ # Applying affine transform
+ c, s = get_center_scale(
+ img.shape[:2], self.aspect_ratio, pixel_std=self.pixel_std
+ )
+ trans = get_affine_transform(c, s, self.rot, self._cfg.IMAGE_SIZE)
+ trans_heatmap = get_affine_transform(
+ c, s, self.rot, self._cfg.HEATMAP_SIZE
+ )
+
+ input = cv2.warpAffine(
+ img,
+ trans,
+ (int(self._cfg.IMAGE_SIZE[0]), int(self._cfg.IMAGE_SIZE[1])),
+ flags=cv2.INTER_LINEAR,
+ )
+
+ if mask is not None:
+ if self.target_overlap:
+ target = cv2.warpAffine(
+ mask,
+ trans_heatmap,
+ (
+ int(self._cfg.HEATMAP_SIZE[0]),
+ int(self._cfg.HEATMAP_SIZE[1]),
+ ),
+ flags=cv2.INTER_LINEAR,
+ )
+ else:
+ mask = cv2.warpAffine(
+ mask,
+ trans,
+ (
+ int(self._cfg.IMAGE_SIZE[0]),
+ int(self._cfg.IMAGE_SIZE[1]),
+ ),
+ flags=cv2.INTER_LINEAR,
+ )
+ target = self._gen_vul_parts(blending_mask=mask)
+
+ # Target encoding
+ # 0 for original, 1 for FXRay, 2 for NoFXRay. If 2, comment: mask = (1 - mask) * mask * 4
+ heatmap, cstency_hm = (
+ self.select_encode_method(version=0)(target, fake_intensity=1.0)
+ if (
+ target is not None
+ and self.heatmap_type == "gaussian"
+ and self.train
+ )
+ else (None, None)
+ )
+
+ if self.debug:
+ Image.fromarray(input).save(f"samples/debugs/affine_{idx}.jpg")
+ # Image.fromarray(target).save(f'samples/debugs/mask_affine_{idx}.jpg')
+ vis_heatmap(input, heatmap, f"samples/debugs/hm_{idx}.jpg")
+
+ if self.train:
+ patch_img_trans = self.final_transforms(input / 255)
+ patch_heatmap = heatmap
+ patch_label = np.expand_dims(label, axis=-1)
+ # patch_label = label
+ else:
+ # Normalise + Convert numpy array to tensor
+ img_trans = input / 255
+ img_trans = self.final_transforms(img_trans)
+ label = np.expand_dims(label, axis=-1)
+ flag = False
+ except Exception as e:
+ print("There is an exception during loading data, please check --- ", e)
+ idx = torch.randint(low=0, high=self.__len__(), size=(1,)).item()
+
+ if self.train:
+ return patch_img_trans, patch_label, patch_heatmap
+ else:
+ meta = {"vid_id": vid_id, "img_path": img_path}
+ return img_trans, label, meta
+
+ def train_collate_fn(self, batch):
+ batch_data = {}
+ img, label, hm = zip(*batch)
+
+ # Collating data in case of using spliting images into patches
+ if self.split_image:
+ hm_H, hm_W = hm[0][0].shape
+
+ img = np.reshape(img, (-1))
+ hm = np.reshape(hm, (-1, 1, hm_H, hm_W))
+ # cstency_hm = np.reshape(cstency_hm, (-1, 1, hm_H, hm_W))
+ # target = np.reshape(target, (-1, 1, hm_H, hm_W))
+ label = np.reshape(label, (-1, 1))
+
+ img = torch.tensor(np.array([it.numpy() for it in img]))
+ heatmap = torch.tensor(np.array(hm)).float()
+ # cstency_heatmap = torch.tensor(cstency_hm).float()
+ # target = torch.tensor(target).float()
+ label = torch.tensor(np.array(label))
+
+ batch_data["img"] = img
+ batch_data["label"] = label
+ # batch_data["target"] = target
+ batch_data["heatmap"] = heatmap
+ # batch_data["cstency"] = cstency_heatmap
+
+ return batch_data
+
+
+if __name__ == "__main__":
+ # from datasets import *
+ from configs.get_config import load_config
+ from pipelines.color_transform import ColorJitterTransform
+ from pipelines.geo_transform import GeometryTransform
+ from torch.utils.data import DataLoader
+
+ PIPELINES.register_module(module=GeometryTransform)
+ PIPELINES.register_module(module=ColorJitterTransform)
+
+ config = load_config("configs/spatial/vit_bi_base.yaml")
+ hm_ff = DATASETS.build(
+ cfg=config.DATASET, default_args=dict(split="val", config=config.DATASET)
+ )
+ hm_ff_loader = DataLoader(
+ hm_ff, batch_size=10, shuffle=False, collate_fn=hm_ff.train_collate_fn
+ )
+ for b, batch_data in enumerate(hm_ff_loader):
+ inputs, labels, heatmaps = (
+ batch_data["img"],
+ batch_data["label"],
+ batch_data["heatmap"],
+ )
+ print(
+ f"X.shape - {inputs.shape}, y shape - {labels.shape}, heatmaps - {heatmaps.shape}"
+ )
+ break
diff --git a/clean/video/fakestormer/datasets/fakesformer_sbi.py b/clean/video/fakestormer/datasets/fakesformer_sbi.py
new file mode 100644
index 0000000000000000000000000000000000000000..fd97cc8e34cdaca517200d6d959eb865f90d9e45
--- /dev/null
+++ b/clean/video/fakestormer/datasets/fakesformer_sbi.py
@@ -0,0 +1,1074 @@
+# -*- coding: utf-8 -*-
+import os
+import random
+import sys
+
+import cv2
+import numpy as np
+import torch
+import torch.nn.functional as F
+from numpy.random import randint
+from package_utils.image_utils import crop_by_margin, load_image
+from package_utils.transform import get_affine_transform, get_center_scale
+from package_utils.utils import (
+ draw_landmarks,
+ draw_most_vul_points,
+ vis_3d_heatmap,
+ vis_heatmap,
+)
+from PIL import Image
+
+from .builder import DATASETS, PIPELINES, build_pipeline
+from .common import ParameterStore
+from .master import MasterDataset
+from .pipelines.geo_transform import get_transforms
+from .sbi.utils import *
+
+
+@DATASETS.register_module()
+class FakeSFormerSBI(MasterDataset):
+ def __init__(self, config, split, **kwargs):
+ """
+ @params:
+ config: Dataset config
+ split: train/val/test which directs to the split folders
+ """
+ self.split = split
+ super(FakeSFormerSBI, self).__init__(config, **kwargs)
+ if kwargs is not None:
+ for k, v in kwargs.items():
+ if v is None:
+ raise ValueError(f"{k}:{v} retrieve a None value!")
+ self.__setattr__(k, v)
+ self.rot = 0
+ self.pixel_std = 200
+ self.target_w = self._cfg.IMAGE_SIZE[1]
+ self.target_h = self._cfg.IMAGE_SIZE[0]
+ self.aspect_ratio = self.target_w * 1.0 / self.target_h
+ self.sigma = self._cfg.SIGMA
+ self.heatmap_type = self._cfg.HEATMAP_TYPE
+ self.debug = self._cfg.DEBUG
+ self.dynamic_blending_prob = self._cfg.DYNAMIC_BLENDING_PROB
+ self.dynamic_fxray = self._cfg.DYNAMIC_FXRAY
+ self.target_overlap = self._cfg.TARGET_OVERLAP
+ if self.data_type == "video":
+ self.mask_prob = self._cfg.MASK_PROB
+ self.temp_maskout = self._cfg.TEMP_MASKOUT
+
+ # Load data
+ self.data_sampler = self._load_data(split)
+
+ # Parse data
+ self._parsing_data()
+
+ # Calling transform methods for inputs
+ self.geo_transform = build_pipeline(
+ config.TRANSFORM.geometry,
+ PIPELINES,
+ default_args={"additional_targets": {"image_f": "image", "mask_f": "mask"}},
+ )
+
+ # predefine mask distortion
+ self.distortion = iaa.Sequential([iaa.PiecewiseAffine(scale=(0.01, 0.15))])
+
+ self.transforms = get_transforms(data_type=self.data_type)
+
+ def __len__(self):
+ if self.data_type == "image":
+ assert "image_paths" in self.data_sampler.keys()
+ return len(self.labels_r)
+ elif self.data_type == "video":
+ return len(self.data_sampler.keys())
+ else:
+ raise ValueError(
+ f'{self.data_type} has not been supported. Please use "image" or "video" instead!'
+ )
+
+ def _load_img(self, img_path):
+ return load_image(img_path)
+
+ def _reload_data(self, epoch=0):
+ self.data_sampler = self._load_data(self.split, epoch=epoch)
+
+ def _load_data(self, split, anno_file=None, epoch=0):
+ from_file = self._cfg.DATA[self.split.upper()].FROM_FILE
+
+ if epoch == 0:
+ if not from_file:
+ self.image_paths, self.labels, self.mask_paths, self.ot_props = (
+ self._load_from_path(split)
+ )
+ else:
+ self.image_paths, self.labels, self.mask_paths, self.ot_props = (
+ self._load_from_file(split, anno_file=anno_file)
+ )
+
+ assert (
+ len(self.image_paths) != 0
+ ), "Image paths have not been loaded! Please check image directory!"
+ assert (
+ len(self.labels) != 0
+ ), "Labels have not been loaded! Please check annotation file!"
+ if not self.dynamic_fxray:
+ assert (
+ len(self.mask_paths) != 0
+ ), "Mask paths have not been loaded! Please check mask directory!"
+
+ if self.sampler_active:
+ print("Running sampler...")
+ params = dict(
+ mask_paths=self.mask_paths, ot_props=self.ot_props, epoch=epoch
+ )
+ data_sampler = self._sampler(self.image_paths, self.labels, **params)
+ return data_sampler
+
+ def _parsing_data(self):
+ assert self.data_type in ["image", "video"]
+ # Parsing data for training
+ if self.data_type == "video":
+ return
+
+ self.image_paths_r, self.labels_r = (
+ self.data_sampler["image_paths"],
+ self.data_sampler["labels"],
+ )
+ if "mask_paths" in self.data_sampler.keys() and len(
+ self.data_sampler["mask_paths"]
+ ):
+ self.mask_paths_r = self.data_sampler["mask_paths"]
+ if "ot_props" in self.data_sampler.keys() and len(
+ self.data_sampler["ot_props"]
+ ):
+ self.ot_props_r = self.data_sampler["ot_props"]
+
+ def __getitem_path__(self, idx):
+ param_store_ins = ParameterStore.get_instance()
+ # Use to store func parameters that can be reused to generate multiple blending, e.g. SBI synthesis frames
+ param_store_ins.add_parameters("data_type", self.data_type)
+ flag = True
+
+ while flag:
+ try:
+ # Selecting data from data list
+ img_path = self.image_paths_r[idx]
+ label = self.labels_r[idx]
+ vid_id = img_path.split("/")[-2]
+ img = self._load_img(img_path)
+ if self.split == "test":
+ # Best is 9,9 and 0.0 and 11,11
+ img = crop_by_margin(img, margin=[9, 9])
+
+ img_f = None
+ mask = None
+ mask_f = None
+
+ # if not self.dynamic_fxray or self.split == 'val':
+ if not self.dynamic_fxray:
+ if bool(self.mask_paths_r):
+ mask_path = self.mask_paths_r[idx]
+ mask = self._load_img(mask_path)
+ else:
+ mask = np.zeros((img.shape[0], img.shape[1], 3))
+ else:
+ if self.train:
+ if len(self.ot_props_r[idx]["aligned_lms"]):
+ f_lms = self.ot_props_r[idx]["aligned_lms"]
+ elif len(self.ot_props_r[idx]["orig_lms"]):
+ f_lms = self.ot_props_r[idx]["orig_lms"]
+ else:
+ f_lms = []
+ f_lms = np.array(f_lms)
+ if not f_lms.any():
+ raise ValueError(
+ "Can not find fake copy image of empty landmarks!"
+ )
+
+ if len(f_lms) > 68:
+ f_lms = reorder_landmark(f_lms)
+
+ # if self.debug:
+ # img_lms_draw = draw_landmarks(img, f_lms)
+ # Image.fromarray(img_lms_draw).save(f'samples/debugs/orig_{idx}_lms.jpg')
+
+ if self.split == "train":
+ if np.random.rand() < 0.5:
+ img, ___, f_lms, __ = sbi_hflip(img, None, f_lms, None)
+
+ margin = np.random.randint(5, 25)
+ img_f, mask_f, img, mask, fake_intensity = gen_target(
+ img,
+ f_lms,
+ margin=[margin, margin],
+ index=idx,
+ debug=False,
+ dynamic_blending_prob=self.dynamic_blending_prob,
+ )
+ target = None
+ target_f = None
+
+ if mask is not None:
+ assert (
+ mask.shape[:2] == img.shape[:2]
+ ), "Color Image and Mask must have the same shape!"
+
+ # Applying affine transform
+ c, s = get_center_scale(
+ img.shape[:2], self.aspect_ratio, pixel_std=self.pixel_std
+ )
+
+ # Applying geo transform to images and masks
+ if self.split == "train":
+ geo_transfomed = self.geo_transform(
+ img, mask=mask, image_f=img_f, mask_f=mask_f
+ )
+ img = geo_transfomed["image"]
+ mask = geo_transfomed["mask"]
+ img_f = geo_transfomed["image_f"]
+ mask_f = geo_transfomed["mask_f"]
+
+ trans = get_affine_transform(
+ c, s, self.rot, self._cfg.IMAGE_SIZE, pixel_std=self.pixel_std
+ )
+ trans_heatmap = get_affine_transform(
+ c, s, self.rot, self._cfg.HEATMAP_SIZE, pixel_std=self.pixel_std
+ )
+
+ input = cv2.warpAffine(
+ img,
+ trans,
+ (int(self._cfg.IMAGE_SIZE[0]), int(self._cfg.IMAGE_SIZE[1])),
+ flags=cv2.INTER_LINEAR,
+ )
+
+ if img_f is not None:
+ input_f = cv2.warpAffine(
+ img_f,
+ trans,
+ (int(self._cfg.IMAGE_SIZE[0]), int(self._cfg.IMAGE_SIZE[1])),
+ flags=cv2.INTER_LINEAR,
+ )
+
+ if mask is not None:
+ if self.target_overlap:
+ target = cv2.warpAffine(
+ mask,
+ trans_heatmap,
+ (
+ int(self._cfg.HEATMAP_SIZE[0]),
+ int(self._cfg.HEATMAP_SIZE[1]),
+ ),
+ flags=cv2.INTER_LINEAR,
+ )
+ else:
+ mask = cv2.warpAffine(
+ mask,
+ trans,
+ (
+ int(self._cfg.IMAGE_SIZE[0]),
+ int(self._cfg.IMAGE_SIZE[1]),
+ ),
+ flags=cv2.INTER_LINEAR,
+ )
+ target = self._gen_vul_parts(blending_mask=mask)
+
+ if mask_f is not None:
+ if self.target_overlap:
+ target_f = cv2.warpAffine(
+ mask_f,
+ trans_heatmap,
+ (
+ int(self._cfg.HEATMAP_SIZE[0]),
+ int(self._cfg.HEATMAP_SIZE[1]),
+ ),
+ flags=cv2.INTER_LINEAR,
+ )
+ else:
+ mask_f = cv2.warpAffine(
+ mask_f,
+ trans,
+ (
+ int(self._cfg.IMAGE_SIZE[0]),
+ int(self._cfg.IMAGE_SIZE[1]),
+ ),
+ flags=cv2.INTER_LINEAR,
+ )
+ target_f = self._gen_vul_parts(blending_mask=mask_f)
+
+ # Drawing the most vulnerable parts (MVPs)
+ if self.debug:
+ mvp_f_drawed = draw_most_vul_points(target_f)
+ mvp_drawed = draw_most_vul_points(target)
+ Image.fromarray(mvp_f_drawed).save(
+ f"samples/fakeformer_debugs/mvp_f_{idx}.jpg"
+ )
+ Image.fromarray(mvp_drawed).save(
+ f"samples/fakeformer_debugs/mvp_{idx}.jpg"
+ )
+
+ # Target encoding
+ # 0 for original, 1 for FXRay, 2 for NoFXRay. If 2, comment: mask = (1 - mask) * mask * 4
+ heatmap_f, cstency_hm_f = (
+ self.select_encode_method(version=0)(target_f, fake_intensity=1.0)
+ if (
+ target_f is not None
+ and self.heatmap_type == "gaussian"
+ and self.train
+ )
+ else (None, None)
+ )
+ heatmap, cstency_hm = (
+ self.select_encode_method(version=0)(target, fake_intensity=1.0)
+ if (
+ target is not None
+ and self.heatmap_type == "gaussian"
+ and self.train
+ )
+ else (None, None)
+ )
+
+ # Applying transform for blending images
+ if self.train:
+ if target_f is None:
+ transformed = self.transforms(image=input.astype("uint8"))
+ input = transformed["image"]
+ else:
+ transformed = self.transforms(
+ image=input.astype("uint8"), image_f=input_f.astype("uint8")
+ )
+ input = transformed["image"]
+ input_f = transformed["image_f"]
+
+ if self.debug:
+ Image.fromarray(input).save(
+ f"samples/fakeformer_debugs/affine_{idx}.jpg"
+ )
+ Image.fromarray(input_f).save(
+ f"samples/fakeformer_debugs/affine_f_{idx}.jpg"
+ )
+ Image.fromarray(np.tile(target, 3)).save(
+ f"samples/fakeformer_debugs/mask_affine_{idx}.jpg"
+ )
+ Image.fromarray(np.tile(target_f, 3)).save(
+ f"samples/fakeformer_debugs/mask_affine_f_{idx}.jpg"
+ )
+ Image.fromarray(mask).save(
+ f"samples/fakeformer_debugs/mask_{idx}.jpg"
+ )
+ Image.fromarray(mask_f).save(
+ f"samples/fakeformer_debugs/mask_f_{idx}.jpg"
+ )
+ if cstency_hm is not None:
+ vis_heatmap(
+ input,
+ cstency_hm_f / 255,
+ f"samples/fakeformer_debugs/cstency_mask_f_{idx}.jpg",
+ )
+ vis_heatmap(
+ input,
+ cstency_hm / 255,
+ f"samples/fakeformer_debugs/cstency_mask_{idx}.jpg",
+ )
+ vis_heatmap(
+ input, heatmap, f"samples/fakeformer_debugs/hm_{idx}.jpg"
+ )
+ vis_heatmap(
+ input_f, heatmap_f, f"samples/fakeformer_debugs/hm_f_{idx}.jpg"
+ )
+
+ if self.train:
+ patch_img_trans = self.final_transforms(input / 255)
+ patch_img_trans_f = self.final_transforms(input_f / 255)
+ patch_heatmap_f = heatmap_f
+ patch_heatmap_r = heatmap
+ patch_target_f = target_f / 255
+ patch_target_r = target / 255
+ patch_cstency_r = (
+ cstency_hm / 255 if cstency_hm is not None else None
+ )
+ patch_cstency_f = (
+ cstency_hm_f / 255 if cstency_hm_f is not None else None
+ )
+ else:
+ # Normalise + Convert numpy array to tensor
+ img_trans = input / 255
+ img_trans = self.final_transforms(img_trans)
+
+ label = np.expand_dims(label, axis=-1)
+ flag = False
+ except Exception as e:
+ print(f"There is something wrong! Please check the DataLoader!, {e}")
+ flag = True
+ idx = torch.randint(low=0, high=self.__len__(), size=(1,)).item()
+
+ if self.train:
+ return (
+ patch_img_trans_f,
+ patch_heatmap_f,
+ patch_target_f,
+ patch_cstency_f,
+ patch_img_trans,
+ patch_heatmap_r,
+ patch_target_r,
+ patch_cstency_r,
+ )
+ else:
+ meta = {"vid_id": vid_id, "img_path": img_path}
+ return img_trans, label, meta
+
+ def __getitem_video__(self, idx):
+ param_store_ins = ParameterStore.get_instance()
+ # Use to store func parameters that can be reused to generate multiple blending, e.g. SBI synthesis frames
+ param_store_ins.add_parameters("data_type", self.data_type)
+ flag = True
+
+ while flag:
+ try:
+ # Real data section
+ inputs = []
+ targets = []
+ temp_loc = np.zeros(self.samples_per_video)
+ masked_matrixes = []
+
+ # Fake data section
+ inputs_f = []
+ targets_f = []
+ labels = []
+ temp_loc_f = np.ones(self.samples_per_video)
+ masked_matrixes_f = []
+
+ vid_id = [*self.data_sampler.keys()][idx]
+ vid_data = self.data_sampler[vid_id]
+
+ # f_idxes = randint(0, len(vid_data), self.samples_per_video) #randint might generate duplicate values, be careful!
+ f_idxes = range(0, self.samples_per_video)
+ pre_lms = None
+ vid_path = None
+
+ if self.train:
+ seq_det = self.distortion.to_deterministic()
+ margin_ = np.random.randint(5, 25)
+ else:
+ # Optimal hyper-param for testing
+ margin_ = (
+ 15 # 0 for DFW, 5 for DFDCP, 13 for DFD, and 15 for the others
+ )
+
+ for ix, f_idx in enumerate(f_idxes):
+ it = vid_data[f_idx]
+ img_path = it["image"]
+ if ix == 0:
+ vid_path = os.path.dirname(img_path)
+ label = it["label"]
+ img = self._load_img(img_path)
+ if self.split == "test":
+ img = crop_by_margin(
+ img, margin=[margin_, margin_]
+ ) # Best is 17,17 and 0.0 and 5,5
+
+ img_f = None
+ mask = None
+ mask_f = None
+
+ # if not self.dynamic_fxray or self.split == 'val':
+ if self.train:
+ assert (
+ self.dynamic_fxray
+ ), "Online blending (dynamic_fxray) is always TRUE when working with SBI!"
+ if "ot_props" in it.keys():
+ ot_props = it["ot_props"]
+
+ if (
+ len(ot_props["aligned_lms"]) and "aligned" in img_path
+ ): # only take aligned lms when input already aligned
+ f_lms = ot_props["aligned_lms"]
+ elif len(ot_props["orig_lms"]):
+ f_lms = ot_props["orig_lms"]
+ else:
+ f_lms = []
+ f_lms = np.array(f_lms)
+ if not f_lms.any():
+ raise ValueError(
+ "Can not find fake copy image of empty landmarks!"
+ )
+
+ if len(f_lms) > 68:
+ f_lms = reorder_landmark(f_lms)
+ # Compute the variation of lms between each frame
+ if f_idx != 0:
+ l2_lms_dis = np.linalg.norm(f_lms - pre_lms) / len(
+ f_lms
+ )
+ # print(f'Change of norm of landmark distance --- {l2_lms_dis}')
+ if l2_lms_dis > 0.35:
+ f_lms = pre_lms + (f_lms - pre_lms) / (
+ round(l2_lms_dis / 0.2)
+ )
+ pre_lms = f_lms
+
+ if self.debug:
+ img_lms_draw = draw_landmarks(img, f_lms)
+ Image.fromarray(img_lms_draw).save(
+ f"samples/debugs/orig_{idx}_{f_idx}_lms.jpg"
+ )
+
+ if self.split == "train":
+ rand_flip = param_store_ins.get_parameters("rand_flip")
+ if rand_flip is None:
+ rand_flip = np.random.rand() < 0.5
+ param_store_ins.add_parameters(
+ "rand_flip", rand_flip
+ )
+
+ if rand_flip < 0.5:
+ img, ___, f_lms, __ = sbi_hflip(
+ img, None, f_lms, None
+ )
+
+ img_f, mask_f, img, mask, fake_intensity = gen_target(
+ img,
+ f_lms,
+ margin=[margin_, margin_],
+ index=f_idx,
+ debug=False,
+ dynamic_blending_prob=self.dynamic_blending_prob,
+ distortion=seq_det,
+ )
+
+ target = None
+ target_f = None
+
+ if mask is not None:
+ assert (
+ mask.shape[:2] == img.shape[:2]
+ ), "Color Image and Mask must have the same shape!"
+
+ # Applying affine transform
+ c, s = get_center_scale(
+ img.shape[:2], self.aspect_ratio, pixel_std=self.pixel_std
+ )
+
+ # Applying geo transform to images and masks
+ # if self.split == 'train':
+ # geo_transfomed = self.geo_transform(img, mask=mask, image_f=img_f, mask_f=mask_f)
+ # img = geo_transfomed['image']
+ # mask = geo_transfomed['mask']
+ # img_f = geo_transfomed['image_f']
+ # mask_f = geo_transfomed['mask_f']
+
+ trans = get_affine_transform(
+ c, s, self.rot, self._cfg.IMAGE_SIZE, pixel_std=self.pixel_std
+ )
+ trans_heatmap = get_affine_transform(
+ c, s, self.rot, self._cfg.HEATMAP_SIZE, pixel_std=self.pixel_std
+ )
+
+ input = cv2.warpAffine(
+ img,
+ trans,
+ (int(self._cfg.IMAGE_SIZE[0]), int(self._cfg.IMAGE_SIZE[1])),
+ flags=cv2.INTER_LINEAR,
+ )
+
+ if img_f is not None:
+ input_f = cv2.warpAffine(
+ img_f,
+ trans,
+ (
+ int(self._cfg.IMAGE_SIZE[0]),
+ int(self._cfg.IMAGE_SIZE[1]),
+ ),
+ flags=cv2.INTER_LINEAR,
+ )
+
+ if mask is not None:
+ if self.target_overlap:
+ target = cv2.warpAffine(
+ mask,
+ trans_heatmap,
+ (
+ int(self._cfg.HEATMAP_SIZE[0]),
+ int(self._cfg.HEATMAP_SIZE[1]),
+ ),
+ flags=cv2.INTER_LINEAR,
+ )
+ else:
+ mask = cv2.warpAffine(
+ mask,
+ trans,
+ (
+ int(self._cfg.IMAGE_SIZE[0]),
+ int(self._cfg.IMAGE_SIZE[1]),
+ ),
+ flags=cv2.INTER_LINEAR,
+ )
+ target = self._gen_vul_parts(blending_mask=mask)
+
+ if mask_f is not None:
+ if self.target_overlap:
+ target_f = cv2.warpAffine(
+ mask_f,
+ trans_heatmap,
+ (
+ int(self._cfg.HEATMAP_SIZE[0]),
+ int(self._cfg.HEATMAP_SIZE[1]),
+ ),
+ flags=cv2.INTER_LINEAR,
+ )
+ else:
+ mask_f = cv2.warpAffine(
+ mask_f,
+ trans,
+ (
+ int(self._cfg.IMAGE_SIZE[0]),
+ int(self._cfg.IMAGE_SIZE[1]),
+ ),
+ flags=cv2.INTER_LINEAR,
+ )
+ target_f = self._gen_vul_parts(blending_mask=mask_f)
+
+ # Drawing the most vulnerable parts (MVPs)
+ if self.debug:
+ mvp_drawed = draw_most_vul_points(target_f)
+ Image.fromarray(mvp_drawed).save(
+ f"samples/debugs/mvp_{idx}_{f_idx}_{fake_intensity}.png"
+ )
+
+ # Applying transform for blending images
+ if self.train:
+ if target_f is None:
+ if f_idx == 0:
+ transformed = self.transforms(
+ image=input.astype(np.uint8)
+ )
+ input = transformed["image"]
+ replay_params = transformed["replay"]
+ param_store_ins.add_parameters(
+ "replay_transform", replay_params
+ )
+ else:
+ replay_params = param_store_ins.get_parameters(
+ "replay_transform"
+ )
+ data = alb.ReplayCompose.replay(
+ replay_params, image=input.astype(np.uint8)
+ )
+ input = data["image"]
+ else:
+ if f_idx == 0:
+ transformed = self.transforms(
+ image=input.astype(np.uint8),
+ image_f=input_f.astype(np.uint8),
+ )
+ input = transformed["image"]
+ input_f = transformed["image_f"]
+ replay_params = transformed["replay"]
+ param_store_ins.add_parameters(
+ "replay_transform", replay_params
+ )
+ else:
+ replay_params = param_store_ins.get_parameters(
+ "replay_transform"
+ )
+ data = alb.ReplayCompose.replay(
+ replay_params,
+ image=input.astype(np.uint8),
+ image_f=input_f.astype(np.uint8),
+ )
+ input = data["image"]
+ input_f = data["image_f"]
+
+ mask_out_rand = (
+ param_store_ins.get_parameters("mask_out_rand")
+ or np.random.rand()
+ )
+ label = 1
+ if f_idx == 0:
+ param_store_ins.add_parameters(
+ "mask_out_rand", mask_out_rand
+ )
+ if mask_out_rand > 0.5 and self.mask_prob > 0:
+ # Mask out vulnerabilities
+ (
+ input_f,
+ target_f,
+ masked_matrix_f,
+ upper_bound_value,
+ fake_intensity,
+ ) = self._mask_out_vulnerability2(
+ input_f,
+ target_f,
+ fake_intensity=fake_intensity,
+ mask_prob=self.mask_prob,
+ )
+ if upper_bound_value == 1:
+ label = 0
+
+ temp_loc_f[f_idx] = (
+ fake_intensity # Updating temporal location value, default 0
+ )
+ input, target, masked_matrix, upper_bound_value, _ = (
+ self._mask_out_vulnerability2(
+ input,
+ target,
+ fake_intensity=fake_intensity,
+ mask_prob=self.mask_prob,
+ )
+ )
+ else:
+ masked_matrix = np.ones_like(target[..., 0])
+ masked_matrix_f = np.ones_like(target_f[..., 0])
+
+ targets.append(target)
+ targets_f.append(target_f)
+ masked_matrixes.append(masked_matrix)
+ masked_matrixes_f.append(masked_matrix_f)
+
+ if self.debug:
+ # Image.fromarray(mask).save(f'samples/debugs/mask_{fake_intensity}.jpg')
+ # Image.fromarray(mask_f).save(f'samples/debugs/mask_f_{fake_intensity}.jpg')
+ Image.fromarray(input).save(
+ f"samples/debugs/affine_{idx}_{f_idx}_{fake_intensity}.jpg"
+ )
+ Image.fromarray(input_f).save(
+ f"samples/debugs/affine_f_{idx}_{f_idx}_{fake_intensity}.png"
+ )
+ # Image.fromarray(target).save(f'samples/debugs/mask_affine_{idx}_{f_idx}_{fake_intensity}.jpg')
+ Image.fromarray(target_f).save(
+ f"samples/debugs/mask_affine_f_{idx}_{f_idx}_{fake_intensity}.png"
+ )
+ Image.fromarray(mask_f).save(
+ f"samples/debugs/mask_f_{idx}_{f_idx}_{fake_intensity}.png"
+ )
+
+ if self.train:
+ img_trans = self.final_transforms(input / 255)
+ img_trans_f = self.final_transforms(input_f / 255)
+ inputs_f.append(img_trans_f)
+ else:
+ # Normalise + Convert numpy array to tensor
+ img_trans = input / 255
+ img_trans = self.final_transforms(img_trans)
+
+ inputs.append(img_trans)
+ labels.append(label)
+
+ if self.train and self.temp_maskout:
+ if np.random.rand() < 0.5:
+ start_idx = np.random.randint(0, len(inputs) - 1)
+ end_idx = min(
+ len(inputs),
+ start_idx + np.random.randint(1, int(len(inputs) / 2 + 1)),
+ )
+ targets_f = np.array(targets_f)
+ targets = np.array(targets)
+
+ if np.random.rand() > 0.5: # Repeat
+ # inputs_f[start_idx:end_idx] = inputs[start_idx:end_idx]
+ inputs_f[start_idx:end_idx] = (
+ inputs_f[start_idx]
+ .unsqueeze(0)
+ .repeat(end_idx - start_idx, 1, 1, 1)
+ )
+ targets_f[start_idx:end_idx] = targets_f[
+ np.newaxis, start_idx
+ ].repeat(end_idx - start_idx, 0)
+ temp_loc_f[start_idx:end_idx] = temp_loc_f[
+ np.newaxis, start_idx
+ ].repeat(end_idx - start_idx)
+ else: # Temporal cutout
+ zero_transform = self.final_transforms(
+ np.zeros(
+ (
+ int(self._cfg.IMAGE_SIZE[0]),
+ int(self._cfg.IMAGE_SIZE[1]),
+ 3,
+ )
+ )
+ )
+
+ # Assigning values for the range from start_idx to end_idx
+ inputs_f.extend(inputs_f[start_idx:end_idx])
+ targets_f = np.append(
+ targets_f, targets_f[start_idx:end_idx], 0
+ )
+ temp_loc_f = np.append(
+ temp_loc_f, temp_loc_f[start_idx:end_idx], 0
+ )
+
+ inputs_f[start_idx:end_idx] = zero_transform.unsqueeze(
+ 0
+ ).repeat(end_idx - start_idx, 1, 1, 1)
+ targets_f[start_idx:end_idx] = targets[start_idx:end_idx]
+ temp_loc_f[start_idx:end_idx] = temp_loc[start_idx:end_idx]
+
+ inputs_f = inputs_f[: self.samples_per_video]
+ targets_f = targets_f[: self.samples_per_video]
+ temp_loc_f = temp_loc_f[: self.samples_per_video]
+
+ labels[start_idx:end_idx] = [
+ 0 for i in range(end_idx - start_idx)
+ ]
+
+ # Target encoding
+ # 0 for original, 1 for FXRay, 2 for NoFXRay. If 2, find and comment the line: mask = (1 - mask) * mask * 4
+ heatmap_f, cstency_hm_f, normalized_params = (
+ self.select_encode_method(version=0, dimension="temporal")(
+ targets_f, fake_intensity=fake_intensity
+ )
+ if (len(targets_f) and self.train)
+ else (None, None, None)
+ )
+ heatmap, cstency_hm, _ = (
+ self.select_encode_method(version=0, dimension="temporal")(
+ targets, fake_intensity=fake_intensity, **normalized_params
+ )
+ if (len(targets) and self.train)
+ else (None, None, None)
+ )
+
+ # Debugging 3D heatmap
+ if self.debug:
+ vis_3d_heatmap(heatmap, f"samples/debugs/hm_{idx}_{f_idx}.png")
+ vis_3d_heatmap(heatmap_f, f"samples/debugs/hm_f_{idx}_{f_idx}.png")
+ vis_3d_heatmap(
+ cstency_hm, f"samples/debugs/cstency_{idx}_{f_idx}.png"
+ )
+ vis_3d_heatmap(
+ cstency_hm_f, f"samples/debugs/cstency_f_{idx}_{f_idx}.png"
+ )
+
+ # End for loop
+ if not self.train:
+ inputs = torch.tensor(
+ np.array([[j.numpy() for j in i] for i in inputs])
+ ).transpose(0, 1)
+ labels = torch.tensor(np.array([np.array(it) for it in labels]))
+ label = torch.max(labels).unsqueeze(0)
+ else:
+ label = np.max(labels)
+ if label == 0:
+ raise ValueError(
+ "There is at least one frame containing artifacts!"
+ )
+
+ flag = False
+ ParameterStore.reset()
+ except Exception as e:
+ print(f"There is something wrong! Please check the DataLoader!, {e}")
+ flag = True
+ idx = torch.randint(low=0, high=self.__len__(), size=(1,)).item()
+
+ if self.train:
+ return (
+ inputs,
+ inputs_f,
+ heatmap,
+ heatmap_f,
+ 0,
+ 1,
+ temp_loc,
+ temp_loc_f,
+ masked_matrixes,
+ masked_matrixes_f,
+ cstency_hm,
+ cstency_hm_f,
+ )
+ else:
+ meta = {"vid_id": vid_id.split("+++")[0], "vid_path": vid_path}
+ return inputs, label, meta
+
+ def __getitem__(self, idx):
+ if self.data_type == "image":
+ return self.__getitem_path__(idx=idx)
+ elif self.data_type == "video":
+ return self.__getitem_video__(idx=idx)
+ else:
+ raise ValueError(
+ f"{self.data_type} has not been supported. Only image or video are used for training!"
+ )
+
+ def train_collate_fn(self, batch):
+ batch_data = {}
+
+ if self.data_type == "image":
+ img_f, hm_f, target_f, cst_f, img_r, hm_r, target_r, cst_r = zip(*batch)
+
+ img = torch.cat(
+ [
+ torch.tensor(np.array([it.numpy() for it in img_r])),
+ torch.tensor(np.array([it.numpy() for it in img_f])),
+ ],
+ 0,
+ )
+ heatmap = torch.cat(
+ [
+ torch.tensor(np.array(hm_r)).float(),
+ torch.tensor(np.array(hm_f)).float(),
+ ],
+ 0,
+ )
+ target = torch.cat(
+ [
+ torch.tensor(np.array(target_r)).float(),
+ torch.tensor(np.array(target_f)).float(),
+ ],
+ 0,
+ )
+ label = torch.tensor([[0]] * len(img_r) + [[1]] * len(img_f))
+ cst = (
+ torch.cat(
+ [
+ torch.tensor(np.array(cst_r)).float(),
+ torch.tensor(np.array(cst_f)).float(),
+ ],
+ 0,
+ )
+ if None not in cst_r
+ else None
+ )
+
+ b_size = label.size(0)
+
+ # Permute idxes
+ idxes = torch.randperm(b_size)
+ img, label, target, heatmap = (
+ img[idxes],
+ label[idxes],
+ target[idxes],
+ heatmap[idxes],
+ )
+ if cst is not None:
+ cst = cst[idxes]
+
+ batch_data["img"] = img
+ batch_data["label"] = label
+ batch_data["target"] = target
+ batch_data["heatmap"] = heatmap
+ batch_data["cstency"] = cst
+ else:
+ (
+ img_r,
+ img_f,
+ hm_r,
+ hm_f,
+ label_r,
+ label_f,
+ temp_loc_r,
+ temp_loc_f,
+ mask_idx_r,
+ mask_idx_f,
+ cst_r,
+ cst_f,
+ ) = zip(*batch)
+
+ img = torch.cat(
+ [
+ torch.tensor(
+ np.array([[j.numpy() for j in i] for i in img_r])
+ ).transpose(1, 2),
+ torch.tensor(
+ np.array([[j.numpy() for j in i] for i in img_f])
+ ).transpose(1, 2),
+ ],
+ 0,
+ )
+ label = torch.cat(
+ [
+ torch.tensor([i for i in label_r]),
+ torch.tensor([i for i in label_f]),
+ ],
+ 0,
+ ).unsqueeze(1)
+ hm = torch.cat(
+ [
+ torch.tensor(np.array(hm_r)).float(),
+ torch.tensor(np.array(hm_f)).float(),
+ ],
+ 0,
+ ).unsqueeze(1)
+ temp_loc = torch.cat(
+ [
+ torch.tensor(np.array([i for i in temp_loc_r])),
+ torch.tensor(np.array([i for i in temp_loc_f])),
+ ],
+ 0,
+ )
+ mask_idx = torch.cat(
+ [
+ torch.tensor(np.array(mask_idx_r)),
+ torch.tensor(np.array(mask_idx_f)),
+ ],
+ 0,
+ ).unsqueeze(1)
+ cst = torch.cat(
+ [
+ torch.tensor(np.array(cst_r)).float(),
+ torch.tensor(np.array(cst_f)).float(),
+ ],
+ 0,
+ ).unsqueeze(1)
+
+ b_size = label.size(0)
+
+ # Permute idxes
+ idxes = torch.randperm(b_size)
+ img, label, hm, temp_loc, mask_idx, cst = (
+ img[idxes],
+ label[idxes],
+ hm[idxes],
+ temp_loc[idxes],
+ mask_idx[idxes],
+ cst[idxes],
+ )
+
+ batch_data["img"] = img
+ batch_data["label"] = label
+ batch_data["heatmap"] = hm
+ batch_data["temp_loc"] = temp_loc
+ batch_data["mask_out_p"] = mask_idx
+ batch_data["cstency"] = cst
+
+ return batch_data
+
+ def train_worker_init_fn(self, worker_id):
+ # print('Current state {} --- worker id {}'.format(np.random.get_state()[1][0], worker_id))
+ np.random.seed(np.random.get_state()[1][0] + worker_id)
+
+
+if __name__ == "__main__":
+ from configs.get_config import load_config
+ from pipelines.geo_transform import GeometryTransform
+ from torch.utils.data import DataLoader
+
+ PIPELINES.register_module(module=GeometryTransform)
+
+ config = load_config("configs/temporal/ResNet3D_EFPN3D_hm3D_c23.yaml")
+
+ # Seed
+ seed = 529
+ random.seed(seed)
+ torch.manual_seed(seed)
+ np.random.seed(seed)
+ torch.cuda.manual_seed(seed)
+
+ hm_ff = DATASETS.build(
+ cfg=config.DATASET, default_args=dict(split="val", config=config.DATASET)
+ )
+ hm_ff_loader = DataLoader(
+ hm_ff,
+ batch_size=8,
+ shuffle=True,
+ collate_fn=hm_ff.train_collate_fn,
+ worker_init_fn=hm_ff.train_worker_init_fn,
+ )
+
+ for b, batch_data in enumerate(hm_ff_loader):
+ inputs, labels, heatmaps = (
+ batch_data["img"],
+ batch_data["label"],
+ batch_data["heatmap"],
+ )
+ print(
+ f"X.shape - {inputs.shape}, y shape - {labels.shape}, heatmap shape - {heatmaps.shape}"
+ )
+ break
diff --git a/clean/video/fakestormer/datasets/ff.py b/clean/video/fakestormer/datasets/ff.py
new file mode 100644
index 0000000000000000000000000000000000000000..9844a63f9094dc81607806e8320437411f161495
--- /dev/null
+++ b/clean/video/fakestormer/datasets/ff.py
@@ -0,0 +1,42 @@
+# -*- coding: utf-8 -*-
+import os
+from glob import glob
+
+import numpy as np
+
+from .builder import DATASETS
+from .common import CommonDataset
+
+
+@DATASETS.register_module()
+class FF(CommonDataset):
+ def __init__(self, cfg, **kwargs):
+ super().__init__(cfg, **kwargs)
+
+ def _load_from_path(self, split):
+ assert os.path.exists(
+ self._cfg.DATA[self.split.upper()].ROOT
+ ), "Root path to dataset can not be None!"
+ data = self._cfg["DATA"]
+ data_type = data.TYPE
+ fake_types = self._cfg.DATA[split.upper()]["FAKETYPE"]
+ label_folders = self._cfg.DATA[split.upper()]["LABEL_FOLDER"]
+ img_paths, labels, mask_paths, ot_props = [], [], [], []
+
+ # Load image data for each type of fake techniques
+ for idx, ft in enumerate(fake_types):
+ data_dir = os.path.join(
+ self._cfg.DATA[self.split.upper()].ROOT, self.split, data_type, ft
+ )
+ if not os.path.exists(data_dir):
+ raise ValueError("Data Directory can not be invalid!")
+
+ for sub_dir in os.listdir(data_dir):
+ sub_dir_path = os.path.join(data_dir, sub_dir)
+ img_paths_ = glob(f"{sub_dir_path}/*.{self._cfg.IMAGE_SUFFIX}")
+
+ img_paths.extend(img_paths_)
+ labels.extend(np.full(len(img_paths_), int("original" not in ft)))
+
+ print("{} image paths have been loaded from FF++!".format(len(img_paths)))
+ return img_paths, labels, mask_paths, ot_props
diff --git a/clean/video/fakestormer/datasets/master.py b/clean/video/fakestormer/datasets/master.py
new file mode 100644
index 0000000000000000000000000000000000000000..18d546bd481bf5709c06cc36f348d462a2ffd104
--- /dev/null
+++ b/clean/video/fakestormer/datasets/master.py
@@ -0,0 +1,48 @@
+# -*- coding: utf-8 -*-
+from .builder import DATASETS
+from .celebDF_v1 import CDFV1
+from .celebDF_v2 import CDFV2
+from .combine import Combine
+from .df40 import DF40
+from .dfd import DFD
+from .dfdc import DFDC
+from .dfdcp import DFDCP
+from .dfo import DFo
+from .dfw import DFW
+from .diffswap import DiffSwap
+from .ff import FF
+
+
+@DATASETS.register_module()
+class MasterDataset(
+ CDFV1, FF, DFDCP, CDFV2, DFDC, DFD, DFW, DFo, DiffSwap, DF40, Combine
+):
+ def __init__(self, cfg, **kwargs):
+ super().__init__(cfg, **kwargs)
+
+ def _load_from_path(self, split):
+ # Explicitly overide some main methods from the dataset config
+ if self.dataset == "FF++":
+ return MasterDataset.__mro__[2]._load_from_path(self, split=split)
+ elif self.dataset == "Celeb-DFv1":
+ return MasterDataset.__mro__[1]._load_from_path(self, split=split)
+ elif self.dataset == "DFDCP":
+ return MasterDataset.__mro__[3]._load_from_path(self, split=split)
+ elif self.dataset == "Celeb-DFv2":
+ return MasterDataset.__mro__[4]._load_from_path(self, split=split)
+ elif self.dataset == "DFDC":
+ return MasterDataset.__mro__[5]._load_from_path(self, split=split)
+ elif self.dataset == "DFD":
+ return MasterDataset.__mro__[6]._load_from_path(self, split=split)
+ elif self.dataset == "DFW":
+ return MasterDataset.__mro__[7]._load_from_path(self, split=split)
+ elif self.dataset == "DFo":
+ return MasterDataset.__mro__[8]._load_from_path(self, split=split)
+ elif self.dataset == "DiffSwap":
+ return MasterDataset.__mro__[9]._load_from_path(self, split=split)
+ elif self.dataset == "DF40":
+ return MasterDataset.__mro__[10]._load_from_path(self, split=split)
+ elif self.dataset == "Combine":
+ return MasterDataset.__mro__[11]._load_from_path(self, split=split)
+ else:
+ return NotImplementedError(f"{self.dataset} has not been supported yet!")
diff --git a/clean/video/fakestormer/datasets/pipelines/__init__.py b/clean/video/fakestormer/datasets/pipelines/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..3be7f6cb584fa2e32c5a9f17f7511fc0ee65e738
--- /dev/null
+++ b/clean/video/fakestormer/datasets/pipelines/__init__.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+from .color_transform import ColorJitterTransform
+from .geo_transform import GeometryTransform
+
+__all__ = ["GeometryTransform", "ColorJitterTransform"]
diff --git a/clean/video/fakestormer/datasets/pipelines/color_transform.py b/clean/video/fakestormer/datasets/pipelines/color_transform.py
new file mode 100644
index 0000000000000000000000000000000000000000..d2175d72e0a423f8ec822bdc6cd38502565378dd
--- /dev/null
+++ b/clean/video/fakestormer/datasets/pipelines/color_transform.py
@@ -0,0 +1,193 @@
+import os
+import sys
+
+if not os.getcwd() in sys.path:
+ sys.path.append(os.getcwd())
+
+import albumentations as A
+from datasets.builder import PIPELINES
+
+
+@PIPELINES.register_module()
+class ColorJitterTransform(object):
+ def __init__(
+ self,
+ clahe: float,
+ colorjitter: float,
+ gaussianblur: float,
+ jpegcompression: list,
+ rgbshift: float,
+ randomcontrast: float,
+ randomgamma: float,
+ randombrightness: float,
+ huesat: float,
+ gaussnoise: float,
+ *args,
+ **kwargs,
+ ):
+ super().__init__()
+ self.clahe = clahe
+ self.colorjitter = colorjitter
+ self.gaussianblur = gaussianblur
+ self.jpegcompression = jpegcompression
+ self.rgbshift = rgbshift
+ self.randomcontrast = randomcontrast
+ self.randomgamma = randomgamma
+ self.randombrightness = randombrightness
+ self.huesat = huesat
+ self.gaussnoise = gaussnoise
+
+ if kwargs is not None:
+ for k, v in kwargs.items():
+ if v is None:
+ raise ValueError(f"{k}:{v} retrieve a None value!")
+ self.__setattr__(k, v)
+
+ def _CLAHE(self, clip_limit=4.0, tile_grid_size=(8, 8), always_apply=False, p=0.5):
+ return A.CLAHE(
+ clip_limit=clip_limit,
+ tile_grid_size=tile_grid_size,
+ always_apply=always_apply,
+ p=p,
+ )
+
+ def _colorjitter(
+ self,
+ brightness=0.2,
+ contrast=0.2,
+ saturation=0.2,
+ hue=0.2,
+ always_apply=False,
+ p=0.5,
+ ):
+ return A.ColorJitter(
+ brightness=brightness,
+ contrast=contrast,
+ saturation=saturation,
+ hue=hue,
+ always_apply=always_apply,
+ p=p,
+ )
+
+ def _gaussianblur(
+ self, blur_limit=(3, 7), sigma_limit=0, always_apply=False, p=0.5
+ ):
+ return A.GaussianBlur(
+ blur_limit=blur_limit,
+ sigma_limit=sigma_limit,
+ always_apply=always_apply,
+ p=p,
+ )
+
+ def _gauss_noise(
+ self,
+ var_limit=(10.0, 50.0),
+ mean=0,
+ per_channel=True,
+ always_apply=False,
+ p=0.5,
+ ):
+ return A.GaussNoise(
+ var_limit=var_limit,
+ mean=mean,
+ per_channel=per_channel,
+ always_apply=always_apply,
+ p=p,
+ )
+
+ def _jpegcompression(
+ self, quality_lower=70, quality_upper=100, always_apply=False, p=0.5
+ ):
+ return A.ImageCompression(
+ quality_lower=quality_lower,
+ quality_upper=quality_upper,
+ always_apply=always_apply,
+ p=p,
+ )
+
+ def _rgbshift(
+ self,
+ r_shift_limit=20,
+ g_shift_limit=20,
+ b_shift_limit=20,
+ always_apply=False,
+ p=0.5,
+ ):
+ return A.RGBShift(
+ r_shift_limit=r_shift_limit,
+ g_shift_limit=g_shift_limit,
+ b_shift_limit=b_shift_limit,
+ always_apply=always_apply,
+ p=p,
+ )
+
+ def _randomcontrast(self, limit=0.2, always_apply=False, p=0.5):
+ return A.RandomContrast(limit=limit, always_apply=always_apply, p=p)
+
+ def _randombrightness(
+ self,
+ brightness_limit=0.1,
+ contrast_limit=0.1,
+ brightness_by_max=True,
+ always_apply=False,
+ p=0.5,
+ ):
+ return A.RandomBrightnessContrast(
+ brightness_limit=brightness_limit,
+ contrast_limit=contrast_limit,
+ brightness_by_max=brightness_by_max,
+ always_apply=always_apply,
+ p=p,
+ )
+
+ def _randomgamma(self, gamma_limit=(80, 120), eps=None, always_apply=False, p=0.5):
+ return A.RandomGamma(
+ gamma_limit=gamma_limit, eps=eps, always_apply=always_apply, p=p
+ )
+
+ def _huesaturation(
+ self,
+ hue_shift_limit=20,
+ sat_shift_limit=20,
+ val_shift_limit=20,
+ always_apply=False,
+ p=0.5,
+ ):
+ return A.HueSaturationValue(
+ hue_shift_limit=hue_shift_limit,
+ sat_shift_limit=sat_shift_limit,
+ val_shift_limit=val_shift_limit,
+ always_apply=always_apply,
+ p=p,
+ )
+
+ def __call__(self, x):
+ transforms = [
+ A.Compose(
+ [
+ self._CLAHE(p=self.clahe),
+ self._randomcontrast(p=self.randomcontrast),
+ self._colorjitter(p=self.colorjitter),
+ self._jpegcompression(
+ p=self.jpegcompression[0],
+ quality_lower=self.jpegcompression[1],
+ quality_upper=self.jpegcompression[2],
+ ),
+ self._rgbshift(p=self.rgbshift),
+ self._randomgamma(p=self.randomgamma),
+ ]
+ ),
+ A.OneOf(
+ [
+ self._gaussianblur(p=self.gaussianblur),
+ self._gauss_noise(p=self.gaussnoise),
+ ]
+ ),
+ A.OneOf(
+ [
+ self._randombrightness(p=self.randombrightness),
+ self._huesaturation(p=self.huesat),
+ ]
+ ),
+ ]
+ return A.Compose(transforms)(image=x)
diff --git a/clean/video/fakestormer/datasets/pipelines/functional.py b/clean/video/fakestormer/datasets/pipelines/functional.py
new file mode 100644
index 0000000000000000000000000000000000000000..2730494f2301b94bbc8debbe5c9394fb227544a8
--- /dev/null
+++ b/clean/video/fakestormer/datasets/pipelines/functional.py
@@ -0,0 +1,11 @@
+# -*- coding: utf-8 -*-
+import numpy as np
+
+
+def _get_pixels(per_pixel, rand_color, patch_size, dtype=np.float32):
+ if per_pixel:
+ return np.random.randint(0, 255, patch_size).astype(dtype=dtype)
+ elif rand_color:
+ return np.random.randint(0, 255, (1, 1, patch_size[2])).astype(dtype=dtype)
+ else:
+ return np.zeros((1, 1, patch_size[2]), dtype=dtype)
diff --git a/clean/video/fakestormer/datasets/pipelines/geo_transform.py b/clean/video/fakestormer/datasets/pipelines/geo_transform.py
new file mode 100644
index 0000000000000000000000000000000000000000..d7c39de0f531bd0cd77ff59606c0b4f7f7d27d71
--- /dev/null
+++ b/clean/video/fakestormer/datasets/pipelines/geo_transform.py
@@ -0,0 +1,372 @@
+# -*- coding: utf-8 -*-
+import math
+import os
+import random
+import sys
+from typing import Dict
+
+if not os.getcwd() in sys.path:
+ sys.path.append(os.getcwd())
+
+import albumentations as A
+import cv2
+import numpy as np
+from albumentations.augmentations.transforms import DualTransform
+from albumentations.core.transforms_interface import ImageOnlyTransform
+from datasets.builder import PIPELINES
+
+from .functional import _get_pixels
+
+
+@PIPELINES.register_module()
+class GeometryTransform(object):
+ def __init__(
+ self,
+ resize: list,
+ normalize: float,
+ horizontal_flip: float,
+ scale: list,
+ cropping: list,
+ rand_erasing: list,
+ *args,
+ **kwargs,
+ ):
+ super().__init__()
+ self.resize = resize # [H, W, p]
+ self.normalize = normalize # p
+ self.horizontal_flip = horizontal_flip # p
+ self.cropping = cropping # [crop_limit, p]
+ self.scale = scale # [scale_limit, p]
+ self.rand_erasing = rand_erasing # p
+
+ if kwargs is not None:
+ for k, v in kwargs.items():
+ if v is None:
+ raise ValueError(f"{k}:{v} retrieve a None value!")
+ self.__setattr__(k, v)
+
+ def _resize(self):
+ hr, wr, p = self.resize
+ return A.Resize(hr, wr, interpolation=2, p=p)
+
+ # We offen use normalize transform from torch, so set p=0.0
+ def _normalize(self, p=0.0):
+ return A.Normalize(p=p)
+
+ def _horizontal_flip(self, p=0.5, always_apply=False):
+ return A.HorizontalFlip(always_apply=always_apply, p=p)
+
+ def _random_scale(
+ self, p=0.5, always_apply=False, scale_limit=0.1, interpolation=1
+ ):
+ return A.RandomScale(
+ scale_limit=scale_limit,
+ interpolation=interpolation,
+ always_apply=always_apply,
+ p=p,
+ )
+
+ def _random_crop(
+ self, p=0.5, always_apply=False, crop_limit=0.1, img_h=256, img_w=256
+ ):
+ crop_h = int((1 - np.random.choice(np.arange(0.0, crop_limit, 0.01))) * img_h)
+ crop_w = int((1 - np.random.choice(np.arange(0.0, crop_limit, 0.01))) * img_w)
+ return A.RandomCrop(height=crop_h, width=crop_w, always_apply=always_apply, p=p)
+
+ def _random_erasing(self, p=0.5, always_apply=False, max_count=3, mode="const"):
+ return RandomErasing(
+ p=p, always_apply=always_apply, mode=mode, max_count=max_count
+ )
+
+ def __call__(self, x, mask=None, image_f=None, mask_f=None):
+ x_h, x_w = x.shape[:2]
+
+ if hasattr(self, "additional_targets"):
+ additional_targets = self.__getattribute__("additional_targets")
+ else:
+ additional_targets = {}
+
+ transform = A.Compose(
+ [
+ A.OneOf(
+ [
+ self._random_crop(
+ p=self.cropping[1],
+ crop_limit=self.cropping[0],
+ img_h=x_h,
+ img_w=x_w,
+ ),
+ self._random_scale(p=self.scale[1], scale_limit=self.scale[0]),
+ self._random_erasing(
+ p=self.rand_erasing[0],
+ mode="const",
+ max_count=self.rand_erasing[1],
+ ),
+ ]
+ ),
+ A.Compose(
+ [
+ self._resize(),
+ self._normalize(p=self.normalize),
+ self._horizontal_flip(p=self.horizontal_flip),
+ ]
+ ),
+ ],
+ additional_targets=additional_targets,
+ )
+
+ if mask is not None:
+ if mask_f is not None:
+ assert (
+ image_f is not None
+ ), "Image Fake sample can not be None in case of Mask sample!"
+ assert len(
+ additional_targets.keys()
+ ), "Additional targets for Albumentations can not be None!"
+ return transform(image=x, mask=mask, image_f=image_f, mask_f=mask_f)
+ else:
+ return transform(image=x, mask=mask)
+ else:
+ return transform(image=x)
+
+
+class RandomErasing(DualTransform):
+ def __init__(
+ self,
+ always_apply: bool = False,
+ p: float = 0.5,
+ min_area=0.02,
+ max_area=1 / 3,
+ min_aspect=0.3,
+ max_aspect=None,
+ mode="const",
+ min_count=1,
+ max_count=None,
+ num_splits=0,
+ img_h=257,
+ img_w=257,
+ img_chan=3,
+ ):
+ super(RandomErasing, self).__init__(always_apply, p)
+ self.min_area = min_area
+ self.max_area = max_area
+ max_aspect = max_aspect or 1 / min_aspect
+ self.log_aspect_ratio = (math.log(min_aspect), math.log(max_aspect))
+ self.min_count = min_count
+ self.max_count = max_count or min_count
+ self.num_splits = num_splits
+ mode = mode.lower()
+ self.rand_color = False
+ self.per_pixel = False
+ self.img_h = img_h
+ self.img_w = img_w
+ self.img_chan = img_chan
+
+ if mode == "rand":
+ self.rand_color = True # per block random normal
+ elif mode == "pixel":
+ self.per_pixel = True # per pixel random normal
+ else:
+ assert not mode or mode == "const"
+
+ def apply(self, img: np.array, **params):
+ return self._erase(img, **params)
+
+ def get_params(self) -> Dict:
+ area = self.img_h * self.img_w
+ count = (
+ self.min_count
+ if self.min_count == self.max_count
+ else random.randint(self.min_count, self.max_count)
+ )
+
+ tops, lefts, ws, hs = [], [], [], []
+ for _ in range(count):
+ for attempt in range(10):
+ target_area = (
+ random.uniform(self.min_area, self.max_area) * area / count
+ )
+ aspect_ratio = math.exp(random.uniform(*self.log_aspect_ratio))
+ h = int(round(math.sqrt(target_area * aspect_ratio)))
+ w = int(round(math.sqrt(target_area / aspect_ratio)))
+
+ if w < self.img_w and h < self.img_h:
+ top = random.randint(0, self.img_h - h)
+ left = random.randint(0, self.img_w - w)
+
+ tops.append(top)
+ lefts.append(left)
+ ws.append(w)
+ hs.append(h)
+ break
+ return {
+ "tops": tops,
+ "lefts": lefts,
+ "ws": ws,
+ "hs": hs,
+ "img_chan": self.img_chan,
+ }
+
+ def _erase(
+ self,
+ img: np.array,
+ tops: list,
+ lefts: list,
+ hs: list,
+ ws: list,
+ img_chan: int,
+ **params,
+ ):
+ for i in range(len(tops)):
+ top = tops[i]
+ left = lefts[i]
+ w = ws[i]
+ h = hs[i]
+
+ img[top : top + h, left : left + w, :] = _get_pixels(
+ self.per_pixel, self.rand_color, (h, w, img_chan), dtype=img.dtype
+ )
+ return img
+
+
+class RandomDownScale(ImageOnlyTransform):
+ def __init__(
+ self, always_apply: bool = False, p: float = 0.5, ratio_list: list = [2, 4]
+ ):
+ self.ratio_list = ratio_list
+ super().__init__(p=p, always_apply=always_apply)
+
+ def apply(self, img: np.ndarray, ratio: int, **params):
+ return self.randomdownscale(img, ratio, **params)
+
+ def get_params(self):
+ ratio = self.ratio_list[np.random.randint(len(self.ratio_list))]
+ return {"ratio": ratio}
+
+ def randomdownscale(self, img, ratio, **kwargs):
+ keep_ratio = True
+ keep_input_shape = True
+ H, W, C = img.shape
+
+ # r = np.random.uniform(2, 4)
+ img_ds = cv2.resize(
+ img, (int(W / ratio), int(H / ratio)), interpolation=cv2.INTER_NEAREST
+ )
+ if keep_input_shape:
+ img_ds = cv2.resize(img_ds, (W, H), interpolation=cv2.INTER_LINEAR)
+
+ return img_ds
+
+ def get_transform_init_args_names(self):
+ return ("ratio_list",)
+
+
+def get_source_transforms(data_type="image"):
+ """
+ Transforms specially design for SBI synthesis
+ """
+ assert data_type in ["image", "video"]
+ if data_type == "image":
+ return A.Compose(
+ [
+ A.Compose(
+ [
+ A.RGBShift((-20, 20), (-20, 20), (-20, 20), p=0.3),
+ A.HueSaturationValue(
+ hue_shift_limit=(-0.3, 0.3),
+ sat_shift_limit=(-0.3, 0.3),
+ val_shift_limit=(-0.3, 0.3),
+ p=1,
+ ),
+ A.RandomBrightnessContrast(
+ brightness_limit=(-0.1, 0.1),
+ contrast_limit=(-0.1, 0.1),
+ p=1,
+ ),
+ ],
+ p=1,
+ ),
+ A.OneOf(
+ [
+ RandomDownScale(p=1),
+ A.Sharpen(alpha=(0.2, 0.5), lightness=(0.5, 1.0), p=1),
+ ],
+ p=1,
+ ),
+ ],
+ p=1.0,
+ )
+ else:
+ return A.ReplayCompose(
+ [
+ A.Compose(
+ [
+ A.RGBShift((-20, 20), (-20, 20), (-20, 20), p=0.3),
+ A.HueSaturationValue(
+ hue_shift_limit=(-0.3, 0.3),
+ sat_shift_limit=(-0.3, 0.3),
+ val_shift_limit=(-0.3, 0.3),
+ p=1,
+ ),
+ A.RandomBrightnessContrast(
+ brightness_limit=(-0.1, 0.1),
+ contrast_limit=(-0.1, 0.1),
+ p=1,
+ ),
+ ],
+ p=1,
+ ),
+ A.OneOf(
+ [
+ RandomDownScale(p=1),
+ A.Sharpen(alpha=(0.2, 0.5), lightness=(0.5, 1.0), p=1),
+ ],
+ p=1,
+ ),
+ ],
+ p=1.0,
+ )
+
+
+def get_transforms(data_type="image"):
+ """
+ Transforms specially design for SBI synthesis
+ """
+ assert data_type in ["image", "video"]
+
+ if data_type == "image":
+ return A.Compose(
+ [
+ A.RGBShift((-20, 20), (-20, 20), (-20, 20), p=0.3),
+ A.HueSaturationValue(
+ hue_shift_limit=(-0.3, 0.3),
+ sat_shift_limit=(-0.3, 0.3),
+ val_shift_limit=(-0.3, 0.3),
+ p=0.3,
+ ),
+ A.RandomBrightnessContrast(
+ brightness_limit=(-0.3, 0.3), contrast_limit=(-0.3, 0.3), p=0.3
+ ),
+ A.ImageCompression(quality_lower=40, quality_upper=100, p=0.5),
+ ],
+ additional_targets={"image_f": "image"},
+ p=1.0,
+ )
+ else:
+ return A.ReplayCompose(
+ [
+ A.RGBShift((-20, 20), (-20, 20), (-20, 20), p=0.3),
+ A.HueSaturationValue(
+ hue_shift_limit=(-0.3, 0.3),
+ sat_shift_limit=(-0.3, 0.3),
+ val_shift_limit=(-0.3, 0.3),
+ p=0.3,
+ ),
+ A.RandomBrightnessContrast(
+ brightness_limit=(-0.3, 0.3), contrast_limit=(-0.3, 0.3), p=0.3
+ ),
+ A.ImageCompression(quality_lower=40, quality_upper=100, p=0.5),
+ ],
+ additional_targets={"image_f": "image"},
+ p=1.0,
+ )
diff --git a/clean/video/fakestormer/datasets/sbi/utils.py b/clean/video/fakestormer/datasets/sbi/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..e8fb51471d3a980eba15fda107e03a297cbfd1fb
--- /dev/null
+++ b/clean/video/fakestormer/datasets/sbi/utils.py
@@ -0,0 +1,354 @@
+# -*- coding: utf-8 -*-
+import os
+import random
+import sys
+
+if os.getcwd() not in sys.path:
+ sys.path.insert(0, os.getcwd())
+
+import albumentations as alb
+import cv2
+import numpy as np
+from imgaug import augmenters as iaa
+from package_utils.bi_online_generation import blendImages, random_erode_dilate
+from package_utils.deepfake_mask import dynamic_blend, random_get_hull
+from package_utils.image_utils import load_image
+from package_utils.transform import randaffine
+from PIL import Image
+from skimage import transform as sktransform
+
+from ..common import ParameterStore
+from ..pipelines.geo_transform import get_source_transforms
+
+
+def gen_SBI(img, landmark, **kwargs):
+ """
+ This function is adapted to process SBI generation for both image-level and video-level
+ """
+ index = kwargs.get("index")
+ assert index is not None
+ debug = kwargs.get("debug") or False
+
+ param_store_ins = ParameterStore.get_instance()
+
+ use_lms68 = param_store_ins.get_parameters("use_lms68") or False
+ data_type = param_store_ins.get_parameters("data_type")
+ assert data_type is not None
+
+ if (
+ (data_type == "image" and np.random.rand() < 0.25)
+ or (data_type == "video" and index == 0 and np.random.rand() < 0.25)
+ or use_lms68
+ ):
+ landmark = landmark[:68]
+
+ if not param_store_ins.has_key("use_lms68") and data_type == "video":
+ param_store_ins.add_parameters("use_lms68", True)
+
+ # Getting ConvexHull
+ mask, hull_type = random_get_hull(
+ landmark, img, hull_type=param_store_ins.get_parameters("hull_type")
+ )
+ if index == 0 and data_type == "video":
+ param_store_ins.add_parameters("hull_type", hull_type)
+
+ # For debugging
+ if index is not None and debug:
+ # Image.fromarray(img).save(f'samples/debugs/BG_{index}.jpg')
+ Image.fromarray((mask * 255).astype(np.uint8)).save(
+ f"samples/debugs/ConvexHull_{index}.jpg"
+ )
+
+ source = img.copy()
+ rand_value = param_store_ins.get_parameters("rand_value") or np.random.rand()
+ if index == 0 and data_type == "video":
+ param_store_ins.add_parameters("rand_value", rand_value)
+
+ if rand_value < 0.5:
+ if data_type == "video":
+ if index == 0:
+ transform = get_source_transforms(data_type=data_type)
+ data = transform(image=source.astype(np.uint8))
+ source = data["image"]
+ replay_params = data["replay"]
+ param_store_ins.add_parameters("s_replay_params", replay_params)
+ else:
+ replay_params = param_store_ins.get_parameters("s_replay_params")
+ data = alb.ReplayCompose.replay(
+ replay_params, image=source.astype(np.uint8)
+ )
+ source = data["image"]
+ else:
+ source = get_source_transforms()(image=source.astype(np.uint8))["image"]
+ else:
+ if data_type == "video":
+ if index == 0:
+ transform = get_source_transforms(data_type=data_type)
+ data = transform(image=img.astype(np.uint8))
+ img = data["image"]
+ replay_params = data["replay"]
+ param_store_ins.add_parameters("i_replay_params", replay_params)
+ else:
+ replay_params = param_store_ins.get_parameters("i_replay_params")
+ data = alb.ReplayCompose.replay(
+ replay_params, image=img.astype(np.uint8)
+ )
+ img = data["image"]
+ else:
+ img = get_source_transforms()(image=img.astype(np.uint8))["image"]
+
+ # if index is not None and debug:
+ # Image.fromarray(source.astype(np.uint8)).save(f'samples/debugs/FG_{index}.jpg')
+
+ if data_type == "image":
+ source, mask, _ = randaffine(source, mask[:, :, 0])
+ else:
+ # if use_lms68:
+ # seq_distortion = kwargs.get('distortion')
+ # img_h, img_w, img_c = mask.shape
+ # aug_size = param_store_ins.get_parameters('aug_size') or random.randint(int(img_h*0.8), int(img_h/0.8))
+ # mask = sktransform.resize(mask,(aug_size,aug_size),preserve_range=True) # resize mask before deformation
+ # mask = seq_distortion.augment_image(mask)
+ # mask, ksize, rand_erode = random_erode_dilate(mask,
+ # ksize=param_store_ins.get_parameters('ksize'),
+ # rand_erode=param_store_ins.get_parameters('rand_erode')) # mask of shape (H,W,3)
+ # mask = sktransform.resize(mask,(img_h,img_w),preserve_range=True) # getting back mask
+ # mask = mask[:,:,0]
+
+ # # filte empty mask after deformation
+ # if np.sum(mask) == 0 :
+ # raise ValueError('Deformed mask has no facial region for blending!!!')
+
+ # if not param_store_ins.has_key('ksize'):
+ # param_store_ins.add_parameters('ksize', ksize)
+ # if not param_store_ins.has_key('rand_erode'):
+ # param_store_ins.add_parameters('rand_erode', rand_erode)
+ # if not param_store_ins.has_key('aug_size'):
+ # param_store_ins.add_parameters('aug_size', aug_size)
+ # else:
+ if index == 0:
+ source, mask, fg_replay_params = randaffine(
+ source, mask[:, :, 0], index=index, data_type=data_type
+ )
+ param_store_ins.add_parameters(
+ "f_replay_params", fg_replay_params["f_replay_params"]
+ )
+ param_store_ins.add_parameters(
+ "g_replay_params", fg_replay_params["g_replay_params"]
+ )
+ else:
+ f_replay_params = param_store_ins.get_parameters("f_replay_params")
+ g_replay_params = param_store_ins.get_parameters("g_replay_params")
+ source, mask, _ = randaffine(
+ source,
+ mask[:, :, 0],
+ index=index,
+ data_type=data_type,
+ f_replay_params=f_replay_params,
+ g_replay_params=g_replay_params,
+ ) # mask of shape (H, W)
+
+ # Getting Deformed ConvexHull
+ if index is not None and debug:
+ Image.fromarray((mask * 255).astype(np.uint8)).save(
+ f"samples/debugs/Deformed_ConvexHull_{index}.jpg"
+ )
+
+ if data_type == "image":
+ img_blended, mask, _ = dynamic_blend(source, img, mask)
+ else:
+ # use_BI = param_store_ins.get_parameters('use_BI') or np.random.rand() > 0.5
+ # if not param_store_ins.has_key('use_BI'):
+ # param_store_ins.add_parameters('use_BI', use_BI)
+ # if use_lms68:
+ # if index == 0:
+ # img_blended, mask, blending_params = blendImages(source,
+ # img,
+ # mask*255)
+ # param_store_ins.add_parameters('blending_params', blending_params)
+ # else:
+ # img_blended, mask, _ = blendImages(source,
+ # img,
+ # mask*255,
+ # **param_store_ins.get_parameters('blending_params'))
+ # mask = mask[:,:,0:1]
+ # else:
+ if index == 0:
+ img_blended, mask, blending_params = dynamic_blend(source, img, mask)
+ param_store_ins.add_parameters("blending_params", blending_params)
+ else:
+ blending_params = param_store_ins.get_parameters("blending_params")
+ img_blended, mask, _ = dynamic_blend(source, img, mask, **blending_params)
+ img_blended = img_blended.astype(np.uint8)
+ img = img.astype(np.uint8)
+
+ return img, img_blended, mask
+
+
+def gen_target(background_face, background_landmark, margin=[20, 20], **kwargs):
+ index = kwargs.get("index")
+ assert index is not None
+
+ if isinstance(background_face, str):
+ background_face = load_image(background_face)
+
+ background_face, face_img, mask_f = gen_SBI(
+ background_face, background_landmark, **kwargs
+ )
+ mask_f = (1 - mask_f) * mask_f * 4
+ mask_r = np.zeros((mask_f.shape[0], mask_f.shape[1], 1))
+
+ margin_x, margin_y = margin
+ H, W = len(face_img), len(face_img[0])
+ face_img = face_img[margin_y : (H - margin_y), margin_x : (W - margin_x), :]
+ background_face = background_face[
+ margin_y : (H - margin_y), margin_x : (W - margin_x), :
+ ]
+
+ mask_f = mask_f[margin_y : (H - margin_y), margin_x : (W - margin_x), :]
+ mask_r = mask_r[margin_y : (H - margin_y), margin_x : (W - margin_x), :]
+
+ mask_f, mask_r = np.repeat(mask_f, 3, 2), np.repeat(mask_r, 3, 2)
+ mask_f, mask_r = (mask_f * 255).astype(np.uint8), (mask_r * 255).astype(np.uint8)
+
+ # lower_bound = [0.5,0.75,1,1]
+ # fake_intensity = np.random.uniform(lower_bound[np.random.randint(len(lower_bound))], 1.)
+ fake_intensity = np.random.uniform(0.5, 1.0)
+ return face_img, mask_f, background_face, mask_r, fake_intensity
+
+
+def reorder_landmark(landmark):
+ landmark_add = np.zeros((13, 2))
+ for idx, idx_l in enumerate([77, 75, 76, 68, 69, 70, 71, 80, 72, 73, 79, 74, 78]):
+ landmark_add[idx] = landmark[idx_l]
+ landmark[68:] = landmark_add
+ return landmark
+
+
+def sbi_hflip(img, mask=None, landmark=None, bbox=None):
+ H, W = img.shape[:2]
+ if landmark is not None:
+ landmark = landmark.copy()
+
+ if bbox is not None:
+ bbox = bbox.copy()
+
+ if landmark is not None:
+ landmark_new = np.zeros_like(landmark)
+
+ landmark_new[:17] = landmark[:17][::-1]
+ landmark_new[17:27] = landmark[17:27][::-1]
+
+ landmark_new[27:31] = landmark[27:31]
+ landmark_new[31:36] = landmark[31:36][::-1]
+
+ landmark_new[36:40] = landmark[42:46][::-1]
+ landmark_new[40:42] = landmark[46:48][::-1]
+
+ landmark_new[42:46] = landmark[36:40][::-1]
+ landmark_new[46:48] = landmark[40:42][::-1]
+
+ landmark_new[48:55] = landmark[48:55][::-1]
+ landmark_new[55:60] = landmark[55:60][::-1]
+
+ landmark_new[60:65] = landmark[60:65][::-1]
+ landmark_new[65:68] = landmark[65:68][::-1]
+ if len(landmark) == 68:
+ pass
+ elif len(landmark) == 81:
+ landmark_new[68:81] = landmark[68:81][::-1]
+ else:
+ raise NotImplementedError
+ landmark_new[:, 0] = W - landmark_new[:, 0]
+ else:
+ landmark_new = None
+
+ if bbox is not None:
+ bbox_new = np.zeros_like(bbox)
+ bbox_new[0, 0] = bbox[1, 0]
+ bbox_new[1, 0] = bbox[0, 0]
+ bbox_new[:, 0] = W - bbox_new[:, 0]
+ bbox_new[:, 1] = bbox[:, 1].copy()
+ if len(bbox) > 2:
+ bbox_new[2, 0] = W - bbox[3, 0]
+ bbox_new[2, 1] = bbox[3, 1]
+ bbox_new[3, 0] = W - bbox[2, 0]
+ bbox_new[3, 1] = bbox[2, 1]
+ bbox_new[4, 0] = W - bbox[4, 0]
+ bbox_new[4, 1] = bbox[4, 1]
+ bbox_new[5, 0] = W - bbox[6, 0]
+ bbox_new[5, 1] = bbox[6, 1]
+ bbox_new[6, 0] = W - bbox[5, 0]
+ bbox_new[6, 1] = bbox[5, 1]
+ else:
+ bbox_new = None
+
+ if mask is not None:
+ mask = mask[:, ::-1]
+ else:
+ mask = None
+ img = img[:, ::-1].copy()
+ return img, mask, landmark_new, bbox_new
+
+
+def BI_postprocessing(img, face_img, mask):
+ param_store_ins = ParameterStore.get_instance()
+ face_img = Image.fromarray(face_img)
+ img = Image.fromarray(img)
+
+ # randomly downsample after BI pipeline
+ rand_val_post = param_store_ins.get_parameters("rand_val_post") or random.randint(
+ 0, 1
+ )
+ if rand_val_post:
+ aug_size = param_store_ins.get_parameters("post_aug_size") or random.randint(
+ 64, 317
+ )
+ rand_resize = param_store_ins.get_parameters("rand_resize") or random.randint(
+ 0, 1
+ )
+
+ if rand_resize:
+ face_img = face_img.resize((aug_size, aug_size), Image.BILINEAR)
+ img = img.resize((aug_size, aug_size), Image.BILINEAR)
+ else:
+ face_img = face_img.resize((aug_size, aug_size), Image.NEAREST)
+ img = img.resize((aug_size, aug_size), Image.NEAREST)
+
+ if not param_store_ins.has_key("post_aug_size"):
+ param_store_ins.add_parameters("post_aug_size", aug_size)
+
+ if not param_store_ins.has_key("rand_resize"):
+ param_store_ins.add_parameters("rand_resize", rand_resize)
+
+ if not param_store_ins.has_key("rand_val_post"):
+ param_store_ins.add_parameters("rand_val_post", rand_val_post)
+
+ face_img = face_img.resize((317, 317), Image.BILINEAR)
+ img = img.resize((317, 317), Image.BILINEAR)
+ face_img = np.array(face_img)
+ img = np.array(img)
+
+ soft_margin = param_store_ins.get_parameters("soft_margin") or np.random.randint(
+ -30, 30
+ )
+ if not param_store_ins.has_key("soft_margin"):
+ param_store_ins.add_parameters("soft_margin", soft_margin)
+
+ face_img = face_img[
+ 30 + soft_margin : (287 + soft_margin),
+ 30 + soft_margin : (287 + soft_margin),
+ :,
+ ]
+ img = img[
+ 30 + soft_margin : (287 + soft_margin),
+ 30 + soft_margin : (287 + soft_margin),
+ :,
+ ]
+ mask = mask[
+ 30 + soft_margin : (287 + soft_margin),
+ 30 + soft_margin : (287 + soft_margin),
+ :,
+ ]
+
+ return img, face_img, mask
diff --git a/clean/video/fakestormer/datasets/utils.py b/clean/video/fakestormer/datasets/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..a6b3c6fdb6ed9c080a893dc90147287108e5b1ae
--- /dev/null
+++ b/clean/video/fakestormer/datasets/utils.py
@@ -0,0 +1,128 @@
+# -*- coding: utf-8 -*-
+import os
+import random
+
+import numpy as np
+
+
+def _extract_data_based_dist(
+ data_type: str, image_paths: list, labels: list, dist: list, **params
+):
+ def sampling_frames(image_paths: list, labels: list, dist: list, **params):
+ """
+ Extracting image paths and labels based on given distribution
+ """
+ total_f = sum(labels)
+ total_r = len(labels) - total_f
+
+ assert (
+ total_f > 0
+ ), "Number of fake images must be greater than 0 for distribution sampling!"
+ assert (
+ total_r > 0
+ ), "Number of real images must be greater than 0 for distribution sampling!"
+
+ r_dist, f_dist = dist[0], dist[1]
+
+ idxes = sorted(range(0, len(labels)), key=lambda k: labels[k])
+ r_idxes = idxes[:total_r]
+ f_idxes = idxes[total_r:]
+
+ print(f"Original Number of Fake images --- {len(f_idxes)}")
+ print(f"Original Number of Real images --- {len(r_idxes)}")
+
+ if int((total_f / f_dist) * r_dist) > total_r:
+ total_f = int((total_r / r_dist) * f_dist)
+ f_idxes = random.sample(f_idxes, total_f)
+ else:
+ total_r = int((total_f / f_dist) * r_dist)
+ r_idxes = random.sample(r_idxes, total_r)
+
+ print(
+ f"Number of Fake images --- {len(f_idxes)} given Fake distribution --- {f_dist}"
+ )
+ print(
+ f"Number of Real images --- {len(r_idxes)} given Real distribution --- {r_dist}"
+ )
+
+ new_idxes = r_idxes + f_idxes
+
+ image_paths = [image_paths[i] for i in new_idxes]
+ labels = np.array(labels)[new_idxes]
+
+ for k, v in params.items():
+ if v is not None and len(v):
+ params[k] = [v[i] for i in new_idxes]
+
+ return image_paths, labels, params
+
+ def sampling_videos(image_paths: list, labels: list, dist: list, **params):
+ """
+ Extracting image paths and labels based on given distribution for video data
+ """
+ f_vid_ids = []
+ r_vid_ids = []
+ for ip in image_paths:
+ faketype = ip.split("/")[8]
+ vid_id = os.path.dirname(ip)
+ if (
+ faketype == "real_videos"
+ or "real" in faketype
+ or "original" in faketype
+ ):
+ r_vid_ids.append(vid_id)
+ else:
+ f_vid_ids.append(vid_id)
+
+ f_vid_ids = list(set(f_vid_ids))
+ r_vid_ids = list(set(r_vid_ids))
+ total_f = len(f_vid_ids)
+ total_r = len(r_vid_ids)
+
+ assert (
+ total_f > 0
+ ), "Number of fake videos must be greater than 0 for distribution sampling!"
+ assert (
+ total_r > 0
+ ), "Number of real videos must be greater than 0 for distribution sampling!"
+ print(f"Original Number of Fake videos --- {total_f}")
+ print(f"Original Number of Real videos --- {total_r}")
+
+ r_dist, f_dist = dist[0], dist[1]
+
+ if int((total_f / f_dist) * r_dist) > total_r:
+ total_f = int((total_r / r_dist) * f_dist)
+ f_vid_ids = random.sample(f_vid_ids, total_f)
+ else:
+ total_r = int((total_f / f_dist) * r_dist)
+ r_vid_ids = random.sample(r_vid_ids, total_r)
+
+ print(
+ f"Number of Fake videos --- {len(f_vid_ids)} given Fake distribution --- {f_dist}"
+ )
+ print(
+ f"Number of Real videos --- {len(r_vid_ids)} given Real distribution --- {r_dist}"
+ )
+
+ vid_ids = r_vid_ids + f_vid_ids
+ new_idxes = []
+
+ for i in range(len(labels)):
+ ip = image_paths[i]
+ vid_id = "/".join([ip.split("/")[-3], ip.split("/")[-2]])
+ if vid_id in vid_ids:
+ new_idxes.append(i)
+
+ image_paths = [image_paths[i] for i in new_idxes]
+ labels = np.array(labels)[new_idxes]
+
+ for k, v in params.items():
+ if v is not None and len(v):
+ params[k] = [v[i] for i in new_idxes]
+
+ return image_paths, labels, params
+
+ if data_type == "image":
+ return sampling_frames(image_paths, labels, dist, **params)
+ else:
+ return sampling_videos(image_paths, labels, dist, **params)
diff --git a/clean/video/fakestormer/dockerfiles/README.md b/clean/video/fakestormer/dockerfiles/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..fc135f5a640c1159aa76356a309c6079c65e4f83
--- /dev/null
+++ b/clean/video/fakestormer/dockerfiles/README.md
@@ -0,0 +1,59 @@
+## Docker Build (Optional)
+*We further provide an optional Docker file which can be used to build working env with Docker.*
+
+1. Install docker to the system (skip the step if docker has been already installed):
+ ```shell
+ sudo apt install docker
+ ```
+2. To start your docker environment, please go to the folder **dockerfiles**:
+ ```shell
+ cd dockerfiles
+ ```
+3. Create a docker image (you can put any name you want):
+ ```shell
+ docker build --tag 'fakestormer' .
+ ```
+4. Check the status of the image created:
+ 1. Run command:
+ ``` shell
+ docker image ls
+ ```
+ 2. You should see something similiar:
+
+ |REPOSITORY| IMAGE ID|CREATED| SIZE |TAG|
+ |----------|---------|-------|------|---|
+ |fakestormer| efd422370750|12 minutes ago| 18.4GB |latest |
+5. Run a container from the created image:
+ 1. Run command
+ ```shell
+ docker run -v : --gpus 'all,capabilities=utility' -it fakestormer /bin/bash
+ ```
+ 2. Check the container created:
+ 1. Run command:
+ ```shell
+ docker ps
+ ```
+ 2. Check the result:
+ CONTAINER ID|IMAGE|COMMAND|CREATED|STATUS|PORTS|NAMES|
+ |-----------|-----|-------|-------|------|-----|-----|
+ |0203c192febb|fakestormer|"/bin/bash"| 29 seconds ago |Up 28 seconds | |determined_cannon|
+ 3. To access the docker container:
+ ```shell
+ docker exec -it 0203c192febb /bin/bash
+ ```
+ 4. To start the container:
+ ```shell
+ docker start 0203c192febb
+ ```
+ 5. To stop the container:
+ ```shell
+ docker stop 0203c192febb
+ ```
+
+6. Inside the docker container, you can clone or mount the repository from outside:
+ ```shell
+ cd /workspace/
+ git clone https://github.com/10Ring/FakeSTormer.git
+ cd FakeSTormer/
+ ```
+7. Now you are ready for [*QuickStart*](#quickstart)
diff --git a/clean/video/fakestormer/lib/core_function.py b/clean/video/fakestormer/lib/core_function.py
new file mode 100644
index 0000000000000000000000000000000000000000..3295477e3e0decdc92e6b63a9ce77752298886a3
--- /dev/null
+++ b/clean/video/fakestormer/lib/core_function.py
@@ -0,0 +1,552 @@
+# -*- coding: utf-8 -*-
+import os
+import time
+from typing import Union
+
+import torch
+from lib.metrics import bin_calculate_auc_ap_ar, get_acc_mesure_func
+from logs.logger import board_writing
+from numpy import arange
+from package_utils.utils import debugging_panel
+from tqdm import tqdm
+
+
+class AverageMeter(object):
+ """Computes and stores the average and current value"""
+
+ def __init__(self):
+ self.reset()
+
+ def reset(self):
+ self.val = 0
+ self.avg = 0
+ self.sum = 0
+ self.count = 0
+
+ def update(self, val, n=1):
+ self.val = val
+ self.sum += val * n
+ self.count += n
+ self.avg = self.sum / self.count if self.count != 0 else 0
+
+
+def get_batch_data(batch_data: Union[dict]):
+ """
+ Parsing data for model consumption (train/val/test)
+ """
+ inputs = batch_data["img"] if isinstance(batch_data, dict) else batch_data[0]
+ labels = batch_data["label"] if isinstance(batch_data, dict) else batch_data[1]
+ heatmaps = None
+ cstency_heatmaps = None
+ offsets = None
+ targets = None
+ temp_locs = None
+ maskout_pes = None
+
+ if "heatmap" in batch_data:
+ heatmaps = batch_data["heatmap"]
+
+ if "target" in batch_data:
+ targets = batch_data["target"]
+
+ if "cstency" in batch_data:
+ cstency_heatmaps = batch_data["cstency"]
+
+ if "offset" in batch_data:
+ offsets = batch_data["offset"]
+
+ if "temp_loc" in batch_data:
+ temp_locs = batch_data["temp_loc"]
+
+ if "mask_out_p" in batch_data:
+ maskout_pes = batch_data["mask_out_p"]
+
+ return (
+ inputs,
+ labels,
+ targets,
+ heatmaps,
+ cstency_heatmaps,
+ offsets,
+ temp_locs,
+ maskout_pes,
+ )
+
+
+def train(
+ cfg,
+ model,
+ critetion,
+ optimizer,
+ epoch,
+ data_loader,
+ logger,
+ writer,
+ devices,
+ trainIters,
+ metrics_base="combine",
+ scaler=None,
+):
+ calculate_acc = get_acc_mesure_func(metrics_base)
+ batch_time = AverageMeter()
+ data_time = AverageMeter()
+ losses = AverageMeter()
+ acc = AverageMeter()
+
+ # Switch to train mode
+ model.train()
+ data_loader = tqdm(data_loader, dynamic_ncols=True)
+ accumulation_steps = cfg.TRAIN.accumulation_steps if cfg.TRAIN.use_amp else 1
+ start = time.time()
+ optimizer.zero_grad()
+ for i, batch_data in enumerate(data_loader):
+ (
+ inputs,
+ labels,
+ targets,
+ heatmaps,
+ cstency_heatmaps,
+ offsets,
+ temp_locs,
+ maskout_pes,
+ ) = get_batch_data(batch_data)
+ inputs = inputs.cuda().to(non_blocking=True, dtype=torch.float)
+ labels = labels.cuda().to(non_blocking=True, dtype=torch.float)
+ maskout_pes = (
+ maskout_pes.cuda().to(non_blocking=True)
+ if maskout_pes is not None
+ else None
+ )
+ # additional_targets = {"maskout_pes": maskout_pes}
+
+ # Measuring data loading time
+ data_time.update(time.time() - start)
+ loop = arange(1) if cfg.TRAIN.optimizer != "SAM" else arange(2)
+
+ for idx in loop:
+ with torch.cuda.amp.autocast(enabled=cfg.TRAIN.use_amp):
+ # outputs = model(inputs, **additional_targets)
+ outputs = model(inputs)
+ if isinstance(outputs, list):
+ outputs = outputs[0]
+
+ # In case outputs contain a dict key
+ if isinstance(outputs, dict):
+ outputs_cls = outputs["cls"]
+ outputs_hm = outputs["hm"] if "hm" in outputs.keys() else None
+ outputs_offset = (
+ outputs["offset"] if "offset" in outputs.keys() else None
+ )
+ outputs_cstency = (
+ outputs["cstency"] if "cstency" in outputs.keys() else None
+ )
+ outputs_temp_loc = (
+ outputs["temp_loc"] if "temp_loc" in outputs.keys() else None
+ )
+
+ if idx == 0:
+ first_outputs_hm = outputs_hm
+ first_outputs_cls = outputs_cls
+
+ if "Combined" in cfg.TRAIN.loss.type:
+ # labels = labels.cuda().to(non_blocking=True).long()
+
+ if offsets is not None:
+ offsets = offsets.cuda().to(non_blocking=True)
+
+ if cstency_heatmaps is not None:
+ cstency_heatmaps = cstency_heatmaps.cuda().to(non_blocking=True)
+
+ if temp_locs is not None:
+ temp_locs = temp_locs.cuda().to(non_blocking=True)
+
+ if cfg.TRAIN.loss.type != "CombinedHeatmapBinaryLoss":
+ heatmaps = heatmaps.cuda().to(non_blocking=True)
+ else:
+ heatmaps = targets.cuda().to(non_blocking=True)
+
+ loss_ = critetion(
+ outputs_hm,
+ heatmaps,
+ outputs_cls,
+ labels,
+ offset_preds=outputs_offset,
+ offset_gts=offsets,
+ cstency_preds=outputs_cstency,
+ cstency_gts=cstency_heatmaps,
+ temp_loc_preds=outputs_temp_loc,
+ temp_loc_gts=temp_locs,
+ hm_mask=maskout_pes,
+ )
+ loss = loss_["hm"]
+ if "cls" in loss_.keys():
+ loss += loss_["cls"]
+ if "dst_hm_cls" in loss_.keys():
+ loss += loss_["dst_hm_cls"]
+ if "offset" in loss_.keys():
+ loss += loss_["offset"]
+ if "cstency" in loss_.keys():
+ loss += loss_["cstency"]
+ if "temp_loc" in loss_.keys():
+ loss += loss_["temp_loc"]
+ else:
+ loss = critetion(outputs_cls, labels)
+
+ loss /= accumulation_steps
+
+ # gradients accumulation for larger batch
+ if cfg.TRAIN.use_amp:
+ scaler(
+ cfg,
+ loss,
+ optimizer,
+ parameters=model.parameters(),
+ step=idx,
+ update_grad=(i + 1) % accumulation_steps == 0,
+ )
+ if (i + 1) % accumulation_steps == 0:
+ optimizer.zero_grad()
+ else:
+ loss.backward()
+
+ if cfg.TRAIN.optimizer != "SAM":
+ optimizer.step()
+ else:
+ if idx == 0:
+ optimizer.first_step(zero_grad=True)
+ else:
+ optimizer.second_step(zero_grad=True)
+ optimizer.zero_grad()
+
+ if cfg.TRAIN.use_amp:
+ torch.cuda.synchronize()
+
+ if cfg.TRAIN.debug.active:
+ debugging_panel(
+ cfg.TRAIN.debug,
+ inputs,
+ heatmaps,
+ first_outputs_hm,
+ i,
+ batch_cls_pred=first_outputs_cls,
+ )
+
+ if metrics_base == "binary":
+ acc_ = calculate_acc(first_outputs_cls, targets=targets, labels=labels)
+ elif metrics_base == "heatmap":
+ acc_ = calculate_acc(first_outputs_hm, targets=targets, labels=labels)
+ else:
+ acc_ = calculate_acc(
+ first_outputs_hm,
+ first_outputs_cls,
+ targets=targets,
+ labels=labels,
+ cls_lamda=critetion.cls_lmda,
+ )
+
+ if isinstance(inputs, list):
+ batch_size = inputs[0].size(0)
+ else:
+ batch_size = inputs.size(0)
+
+ # Measure accuracy and record loss
+ losses.update(loss.item() * accumulation_steps, n=batch_size)
+ acc.update(acc_, n=batch_size)
+
+ batch_time.update(time.time() - start)
+ start = time.time()
+
+ # Logging
+ if i % 5 == 0:
+ params = {}
+ if "Combined" in cfg.TRAIN.loss.type:
+ if (
+ hasattr(critetion, "dst_hm_cls_lmda")
+ and critetion.dst_hm_cls_lmda > 0
+ ):
+ params["loss_dst"] = loss_["dst_hm_cls"].item()
+ if hasattr(critetion, "offset_lmda") and critetion.offset_lmda > 0:
+ params["loss_offset"] = loss_["offset"].item()
+ if "cstency" in loss_.keys():
+ params["loss_cstency"] = loss_["cstency"].item()
+ if "temp_loc" in loss_.keys():
+ params["loss_temp_loc"] = loss_["temp_loc"].item()
+ logger.epochInfor(
+ epoch,
+ i,
+ len(data_loader),
+ batch_time=batch_time,
+ data_time=data_time,
+ losses=losses,
+ acc=acc,
+ speed=batch_size / batch_time.val,
+ loss_cls=loss_["cls"].item(),
+ **params,
+ )
+ else:
+ logger.epochInfor(
+ epoch,
+ i,
+ len(data_loader),
+ batch_time=batch_time,
+ data_time=data_time,
+ losses=losses,
+ acc=acc,
+ speed=batch_size / batch_time.val,
+ )
+
+ trainIters += 1
+ if cfg.TRAIN.tensorboard:
+ board_writing(writer, losses.avg, acc.avg, trainIters, "Train")
+ return losses, acc, trainIters
+
+
+def validate(
+ cfg,
+ model,
+ critetion,
+ epoch,
+ data_loader,
+ logger,
+ writer,
+ devices,
+ valIters,
+ metrics_base="combine",
+):
+ calculate_acc = get_acc_mesure_func(metrics_base)
+ batch_time = AverageMeter()
+ data_time = AverageMeter()
+ losses = AverageMeter()
+ acc = AverageMeter()
+
+ # Switch to test mode
+ model.eval()
+ data_loader = tqdm(data_loader, dynamic_ncols=True)
+ start = time.time()
+ with torch.no_grad():
+ for i, batch_data in enumerate(data_loader):
+ (
+ inputs,
+ labels,
+ targets,
+ heatmaps,
+ cstency_heatmaps,
+ offsets,
+ temp_locs,
+ maskout_pes,
+ ) = get_batch_data(batch_data)
+ inputs = inputs.to(devices, non_blocking=True, dtype=torch.float).cuda()
+ labels = labels.cuda().to(non_blocking=True, dtype=torch.float)
+ maskout_pes = (
+ maskout_pes.cuda().to(non_blocking=True)
+ if maskout_pes is not None
+ else None
+ )
+ # additional_targets = {"maskout_pes": maskout_pes}
+
+ # Measuring data loading time
+ data_time.update(time.time() - start)
+
+ # outputs = model(inputs, **additional_targets)
+ outputs = model(inputs)
+ if isinstance(outputs, list):
+ outputs = outputs[0]
+
+ # In case outputs contain a dict key
+ if isinstance(outputs, dict):
+ outputs_cls = outputs["cls"]
+ outputs_hm = outputs["hm"] if "hm" in outputs.keys() else None
+ outputs_offset = (
+ outputs["offset"] if "offset" in outputs.keys() else None
+ )
+ outputs_cstency = (
+ outputs["cstency"] if "cstency" in outputs.keys() else None
+ )
+ outputs_temp_loc = (
+ outputs["temp_loc"] if "temp_loc" in outputs.keys() else None
+ )
+
+ if "Combined" in cfg.TRAIN.loss.type:
+ # labels = labels.cuda().to(non_blocking=True).long()
+
+ if offsets is not None:
+ offsets = offsets.cuda().to(non_blocking=True)
+
+ if cstency_heatmaps is not None:
+ cstency_heatmaps = cstency_heatmaps.cuda().to(non_blocking=True)
+
+ if temp_locs is not None:
+ temp_locs = temp_locs.cuda().to(non_blocking=True)
+
+ if cfg.TRAIN.loss.type != "CombinedHeatmapBinaryLoss":
+ heatmaps = heatmaps.cuda().to(non_blocking=True)
+ else:
+ heatmaps = targets.cuda().to(non_blocking=True)
+
+ loss_ = critetion(
+ outputs_hm,
+ heatmaps,
+ outputs_cls,
+ labels,
+ offset_preds=outputs_offset,
+ offset_gts=offsets,
+ cstency_preds=outputs_cstency,
+ cstency_gts=cstency_heatmaps,
+ temp_loc_preds=outputs_temp_loc,
+ temp_loc_gts=temp_locs,
+ hm_mask=maskout_pes,
+ )
+ loss = loss_["hm"]
+ if "cls" in loss_.keys():
+ loss += loss_["cls"]
+ if "dst_hm_cls" in loss_.keys():
+ loss += loss_["dst_hm_cls"]
+ if "offset" in loss_.keys():
+ loss += loss_["offset"]
+ if "cstency" in loss_.keys():
+ loss += loss_["cstency"]
+ if "temp_loc" in loss_.keys():
+ loss += loss_["temp_loc"]
+ else:
+ loss = critetion(outputs_cls, labels)
+
+ if cfg.TRAIN.debug.active:
+ debugging_panel(
+ cfg.TRAIN.debug,
+ inputs,
+ heatmaps,
+ outputs_hm,
+ i,
+ batch_cls_pred=outputs_cls,
+ split="val",
+ )
+
+ if metrics_base == "binary":
+ acc_ = calculate_acc(outputs_cls, targets=targets, labels=labels)
+ elif metrics_base == "heatmap":
+ acc_ = calculate_acc(outputs_hm, targets=targets, labels=labels)
+ else:
+ acc_ = calculate_acc(
+ outputs_hm,
+ outputs_cls,
+ targets=targets,
+ labels=labels,
+ cls_lamda=critetion.cls_lmda,
+ )
+
+ if isinstance(inputs, list):
+ batch_size = inputs[0].size(0)
+ else:
+ batch_size = inputs.size(0)
+
+ # Measure accuracy and record loss
+ losses.update(loss.item(), n=batch_size)
+ acc.update(acc_, n=batch_size)
+
+ batch_time.update(time.time() - start)
+ start = time.time()
+
+ valIters += 1
+ if cfg.TRAIN.tensorboard:
+ board_writing(writer, losses.avg, acc.avg, valIters, "Val")
+
+ # Logging
+ params = {}
+ if "Combined" in cfg.TRAIN.loss.type:
+ if (
+ hasattr(critetion, "dst_hm_cls_lmda")
+ and critetion.dst_hm_cls_lmda > 0
+ ):
+ params["loss_dst"] = loss_["dst_hm_cls"].item()
+ if hasattr(critetion, "offset_lmda") and critetion.offset_lmda > 0:
+ params["loss_offset"] = loss_["offset"].item()
+ if "cstency" in loss_.keys():
+ params["loss_cstency"] = loss_["cstency"].item()
+ if "temp_loc" in loss_.keys():
+ params["loss_temp_loc"] = loss_["temp_loc"].item()
+ logger.epochInfor(
+ epoch,
+ i,
+ len(data_loader),
+ batch_time=batch_time,
+ data_time=data_time,
+ losses=losses,
+ acc=acc,
+ speed=batch_size / batch_time.val,
+ loss_cls=loss_["cls"].item(),
+ **params,
+ )
+ else:
+ logger.epochInfor(
+ epoch,
+ i,
+ len(data_loader),
+ batch_time=batch_time,
+ data_time=data_time,
+ losses=losses,
+ acc=acc,
+ speed=batch_size / batch_time.val,
+ )
+ return losses, acc, valIters
+
+
+def test(
+ cfg,
+ model,
+ critetion,
+ epoch,
+ data_loader,
+ logger,
+ writer,
+ devices,
+ valIters,
+ metrics_base="combine",
+):
+ calculate_acc = get_acc_mesure_func(metrics_base)
+ total_preds = torch.tensor([]).cuda().to(dtype=torch.float)
+ total_labels = torch.tensor([]).cuda().to(dtype=torch.float)
+
+ # Switch to test mode
+ model.eval()
+ test_dataloader = tqdm(data_loader, dynamic_ncols=True)
+ with torch.no_grad():
+ for b, (inputs, labels, vid_ids) in enumerate(test_dataloader):
+ inputs = inputs.to(dtype=torch.float).cuda()
+ labels = labels.to(dtype=torch.float).cuda()
+
+ outputs = model(inputs)
+ # Applying Flip test
+ if isinstance(outputs, list):
+ outputs = outputs[0]
+
+ # In case outputs contain a dict key
+ if isinstance(outputs, dict):
+ # hm_outputs = outputs['hm'] if 'hm' in outputs.keys() else None
+ cls_outputs = outputs["cls"]
+ # outputs_temp_loc = outputs['temp_loc'] if 'temp_loc' in outputs.keys() else None
+
+ total_preds = torch.cat((total_preds, cls_outputs), 0)
+ total_labels = torch.cat((total_labels, labels), 0)
+
+ acc_ = calculate_acc(
+ total_preds, targets=None, labels=total_labels, threshold=cfg.TEST.threshold
+ )
+ metrics = bin_calculate_auc_ap_ar(
+ total_preds,
+ total_labels,
+ metrics_base=metrics_base,
+ threshold=cfg.TEST.threshold,
+ )
+ auc_, ap_, ar_, mf1_ = (
+ metrics["auc"],
+ metrics["ap"],
+ metrics["ar"],
+ metrics["mf1"],
+ )
+
+ logger.info(
+ f"Current ACC, AUC, AP, AR, mF1 for {cfg.DATASET.DATA.TEST.FAKETYPE} --- {cfg.DATASET.DATA.TEST.LABEL_FOLDER} -- \
+ {acc_*100} -- {auc_*100} -- {ap_*100} -- {ar_*100} -- {mf1_*100}"
+ )
+
+ return acc_, auc_, ap_, ar_
diff --git a/clean/video/fakestormer/lib/metrics.py b/clean/video/fakestormer/lib/metrics.py
new file mode 100644
index 0000000000000000000000000000000000000000..c25e662345713ca5b0dfa616130a988f9a8c5e88
--- /dev/null
+++ b/clean/video/fakestormer/lib/metrics.py
@@ -0,0 +1,201 @@
+# -*- coding: utf-8 -*-
+import os
+
+import numpy as np
+import torch
+from losses.losses import _avg_sigmoid, _sigmoid
+from scipy.stats import beta, gaussian_kde
+from sklearn import metrics as cal_metrics
+from sklearn.metrics import (
+ average_precision_score,
+ balanced_accuracy_score,
+ f1_score,
+ precision_score,
+ recall_score,
+)
+
+
+def bin_calculate_acc(preds, labels, targets=None, threshold=0.5):
+ if torch.is_tensor(preds):
+ if preds.shape[-1] > 1:
+ preds = preds.softmax(dim=-1)
+ if preds.shape[-1] == 2:
+ preds = preds[:, -1]
+ else:
+ preds = preds.max(dim=-1, keepdim=True).values
+ labels = labels.max(dim=-1, keepdim=True).values
+ else:
+ preds = preds.sigmoid()
+
+ preds = preds.detach().cpu().numpy()
+ labels = labels.detach().cpu().numpy()
+
+ preds_ = (preds >= threshold).astype(int)
+ acc = np.mean((preds_ == labels).astype(int), axis=0)
+
+ if acc.ndim >= 1:
+ return acc[0]
+ else:
+ return acc
+
+
+def hm_calculate_acc(preds, targets=None, labels=None, threshold=0.5):
+ cls_ = _avg_sigmoid(preds)
+ acc = bin_calculate_acc(cls_, labels, threshold=threshold)
+ return acc
+
+
+def hm_bin_calculate_acc(
+ hm_preds, cls_preds, targets=None, labels=None, cls_lamda=0.05
+):
+ # Select top hm_preds
+ hm_preds_ = _sigmoid(hm_preds.clone())
+ hm_preds_ = torch.reshape(hm_preds_, (hm_preds_.shape[0], hm_preds_.shape[1], -1))
+ top_k = torch.topk(hm_preds_, 10, -1).values
+ mean_hm_preds = torch.mean(top_k, -1)
+
+ cls_preds_ = cls_lamda * cls_preds + (1 - cls_lamda) * mean_hm_preds
+ acc = bin_calculate_acc(cls_preds_, labels)
+ return acc
+
+
+def bin_calculate_auc_ap_ar(
+ cls_preds,
+ labels,
+ metrics_base="binary",
+ hm_preds=None,
+ cls_lamda=0.1,
+ threshold=0.5,
+ apr=True,
+):
+ assert metrics_base in [
+ "binary",
+ "heatmap",
+ "combine",
+ ], "Metric base is only one of these values [binary, heatmap, combine]"
+
+ if torch.is_tensor(cls_preds):
+ if cls_preds.shape[-1] > 1:
+ cls_preds = cls_preds.softmax(dim=-1)
+ if cls_preds.shape[-1] == 2:
+ cls_preds = cls_preds[:, -1]
+ else:
+ cls_preds = cls_preds.max(dim=-1, keepdim=True).values
+ labels = labels.max(dim=-1, keepdim=True).values
+ else:
+ cls_preds = cls_preds.sigmoid()
+
+ if metrics_base == "combine":
+ assert (
+ hm_preds is not None
+ ), "Heatmap predict can not be None if metrics-base is combine"
+ hm_preds = _sigmoid(hm_preds)
+ hm_preds = torch.reshape(hm_preds, (hm_preds.shape[0], 1, -1))
+ top_k = torch.topk(hm_preds, 10, -1).values
+ mean_hm_preds = torch.mean(top_k, -1)
+ cls_preds = cls_lamda * cls_preds + (1 - cls_lamda) * mean_hm_preds
+
+ labels = labels.cpu().numpy()
+ cls_preds = cls_preds.cpu().numpy()
+ fpr, tpr, thresholds = cal_metrics.roc_curve(labels, cls_preds, pos_label=1)
+
+ metrics = {}
+ distances = np.sqrt((1 - tpr) ** 2 + fpr**2)
+ optimal_idx = np.argmin(distances)
+ optimal_threshold = thresholds[optimal_idx]
+ top_k_min_indices = np.argsort(distances)[:5]
+ top_k_thresholds = thresholds[top_k_min_indices]
+ metrics["best_thr"] = optimal_threshold
+ metrics["thr_var"] = np.var(top_k_thresholds, ddof=1)
+
+ # AUC
+ metrics["auc"] = cal_metrics.auc(fpr, tpr)
+
+ if apr:
+ # AP metric
+ ap = average_precision_score(labels, cls_preds)
+ metrics["ap"] = ap
+
+ # AR metric
+ ar = recall_score(labels, (cls_preds >= threshold).astype(int), average="macro")
+ metrics["ar"] = ar
+
+ # mF1 metric
+ metrics["mf1"] = (ap * ar * 2) / (ap + ar)
+
+ return metrics
+ else:
+ # False Negative Rate
+ fnr = 1 - tpr
+ eer_threshold = thresholds[np.nanargmin(np.absolute(fpr - fnr))]
+ eer = fpr[np.nanargmin(np.absolute(fpr - fnr))]
+ metrics["eer"] = eer
+
+ metrics["bacc"] = balanced_accuracy_score(
+ labels, (cls_preds >= threshold).astype(int)
+ )
+
+ metrics["p"] = precision_score(labels, (cls_preds >= threshold).astype(int))
+
+ metrics["r"] = recall_score(labels, (cls_preds >= threshold).astype(int))
+
+ metrics["s"] = recall_score(
+ labels, (cls_preds >= threshold).astype(int), pos_label=0
+ )
+
+ metrics["f1"] = f1_score(labels, (cls_preds >= threshold).astype(int))
+
+ return metrics
+
+
+def get_acc_mesure_func(task="binary"):
+ if task == "binary":
+ return bin_calculate_acc
+ elif task == "heatmap":
+ return hm_calculate_acc
+ else:
+ return hm_bin_calculate_acc
+
+
+# Compute Empirical CDF
+def empirical_cdf(data):
+ sorted_data = np.sort(data)
+ return sorted_data, np.arange(1, len(sorted_data) + 1) / len(sorted_data)
+
+
+# Transformations
+def apply_cdf_transform(neg_data, pos_data, cdf_type="empirical"):
+ if cdf_type == "empirical":
+ return (
+ empirical_cdf(neg_data)[1],
+ empirical_cdf(pos_data)[1],
+ ) # Get the ECDF values
+ elif cdf_type == "kde":
+ kde_data1 = gaussian_kde(neg_data)
+ kde_data2 = gaussian_kde(pos_data)
+
+ x_values = np.linspace(0, 1, 11) # 0.0; 0.1; 0.2; ...
+
+ cdf1 = np.cumsum(kde_data1(x_values))
+ cdf1 /= cdf1[-1]
+
+ cdf2 = np.cumsum(kde_data2(x_values))
+ cdf2 /= cdf2[-1]
+ return cdf1, cdf2
+ elif cdf_type == "para":
+ alp1, bta1, _, _ = beta.fit(neg_data, floc=0, fscale=1.0001)
+ alp2, bta2, _, _ = beta.fit(pos_data, floc=0, fscale=1.0001)
+
+ x_values = np.linspace(0, 1, 11) # 0.0; 0.1; 0.2; ...
+
+ cdf1 = beta.cdf(x_values, alp1, bta1)
+ cdf2 = beta.cdf(x_values, alp2, bta2)
+ return cdf1, cdf2
+ elif cdf_type == "quantile":
+ q = np.linspace(0, 1, min(len(neg_data), len(pos_data))) # Matching quantiles
+ F_inv_P0 = np.quantile(neg_data, q)
+ F_inv_P1 = np.quantile(pos_data, q)
+
+ return F_inv_P0, F_inv_P1
+ else:
+ raise ValueError("Unknown CDF type")
diff --git a/clean/video/fakestormer/lib/optimizers/sam.py b/clean/video/fakestormer/lib/optimizers/sam.py
new file mode 100644
index 0000000000000000000000000000000000000000..8247fbf4e0d1ed50169a897f238ac67a594e7bde
--- /dev/null
+++ b/clean/video/fakestormer/lib/optimizers/sam.py
@@ -0,0 +1,96 @@
+# -*- coding: utf-8 -*-
+import torch
+import torch.nn as nn
+
+
+def disable_running_stats(model):
+ def _disable(module):
+ if isinstance(module, nn.BatchNorm2d):
+ module.backup_momentum = module.momentum
+ module.momentum = 0
+
+ model.apply(_disable)
+
+
+def enable_running_stats(model):
+ def _enable(module):
+ if isinstance(module, nn.BatchNorm2d) and hasattr(module, "backup_momentum"):
+ module.momentum = module.backup_momentum
+
+ model.apply(_enable)
+
+
+class SAM(torch.optim.Optimizer):
+ def __init__(self, params, base_optimizer, rho=0.05, **kwargs):
+ assert rho >= 0.0, f"Invalid rho, should be non-negative: {rho}"
+
+ defaults = dict(rho=rho, **kwargs)
+ super(SAM, self).__init__(params, defaults)
+
+ self.base_optimizer = base_optimizer(self.param_groups, **kwargs)
+ self.param_groups = self.base_optimizer.param_groups
+
+ @torch.no_grad()
+ def first_step(self, zero_grad=False):
+ grad_norm = self._grad_norm()
+ for group in self.param_groups:
+ scale = group["rho"] / (grad_norm + 1e-12)
+
+ for p in group["params"]:
+ if p.grad is None:
+ continue
+ e_w = p.grad * scale.to(p)
+ p.add_(e_w) # climb to the local maximum "w + e(w)"
+ self.state[p]["e_w"] = e_w
+
+ if zero_grad:
+ self.zero_grad()
+
+ @torch.no_grad()
+ def second_step(self, zero_grad=False, scaler=None):
+ for group in self.param_groups:
+ for p in group["params"]:
+ if p.grad is None:
+ continue
+ p.sub_(self.state[p]["e_w"]) # get back to "w" from "w + e(w)"
+
+ if scaler is None:
+ self.base_optimizer.step() # do the actual "sharpness-aware" update
+ else:
+ scaler.step(self.base_optimizer)
+
+ if zero_grad:
+ self.zero_grad()
+
+ if scaler is not None:
+ return scaler
+
+ @torch.no_grad()
+ def step(self, closure=None):
+ assert (
+ closure is not None
+ ), "Sharpness Aware Minimization requires closure, but it was not provided"
+ closure = torch.enable_grad()(
+ closure
+ ) # the closure should do a full forward-backward pass
+
+ self.first_step(zero_grad=True)
+ closure()
+ self.second_step()
+
+ def _grad_norm(self):
+ shared_device = self.param_groups[0]["params"][
+ 0
+ ].device # put everything on the same device, in case of model parallelism
+ norm = torch.norm(
+ torch.stack(
+ [
+ p.grad.norm(p=2).to(shared_device)
+ for group in self.param_groups
+ for p in group["params"]
+ if p.grad is not None
+ ]
+ ),
+ p=2,
+ )
+ return norm
diff --git a/clean/video/fakestormer/lib/scheduler/linear_decay.py b/clean/video/fakestormer/lib/scheduler/linear_decay.py
new file mode 100644
index 0000000000000000000000000000000000000000..a218e60ee69a54f454f324fbef46a77071f07243
--- /dev/null
+++ b/clean/video/fakestormer/lib/scheduler/linear_decay.py
@@ -0,0 +1,38 @@
+# -*- coding: utf-8 -*-
+import torch
+from torch.optim import SGD
+from torch.optim.lr_scheduler import _LRScheduler
+
+
+class LinearDecayLR(_LRScheduler):
+ def __init__(self, optimizer, n_epoch, start_decay, last_epoch=-1, booster=2):
+ self.start_decay = start_decay
+ self.n_epoch = n_epoch
+ self.booster = booster
+ super(LinearDecayLR, self).__init__(optimizer, last_epoch)
+
+ def get_lr(self):
+ last_epoch = self.last_epoch
+ n_epoch = self.n_epoch
+ b_lr = self.base_lrs[-1]
+
+ if last_epoch > 0:
+ try:
+ cur_lr = self.get_last_lr()
+ except:
+ cur_lr = b_lr * self.booster
+ start_decay = self.start_decay
+
+ if last_epoch >= start_decay:
+ lr = b_lr * self.booster - (b_lr * self.booster) / (
+ n_epoch - start_decay
+ ) * (last_epoch - start_decay)
+ else:
+ if last_epoch < start_decay:
+ lr = b_lr + (b_lr * self.booster - b_lr) / start_decay * last_epoch
+ else:
+ lr = cur_lr
+
+ self._last_lr = lr
+ print(f"Active Learning Rate --- {lr}")
+ return [lr]
diff --git a/clean/video/fakestormer/logs/logger.py b/clean/video/fakestormer/logs/logger.py
new file mode 100644
index 0000000000000000000000000000000000000000..655ae2871372e8788a1c800918bf6571350f6920
--- /dev/null
+++ b/clean/video/fakestormer/logs/logger.py
@@ -0,0 +1,109 @@
+# -*- coding: utf-8 -*-
+import logging
+import os
+from datetime import datetime
+from types import MethodType
+
+import torch
+import torch.nn.functional as F
+from mmcv.utils import get_logger
+from package_utils.utils import make_dir
+
+LOG_DIR = "logs/{}".format(datetime.today().strftime("%d-%m-%Y"))
+make_dir(LOG_DIR)
+
+
+class Logger:
+ def __init__(self, task="training", workdir=LOG_DIR):
+ super().__init__()
+ self.logger = logging.getLogger("")
+ self.logger.setLevel(logging.INFO)
+
+ file_handler = logging.FileHandler("{}/{}.log".format(workdir, task))
+ stream_handler = logging.StreamHandler()
+ self.logger.addHandler(file_handler)
+ self.logger.addHandler(stream_handler)
+ self.logger.epochInfor = MethodType(self.epochInfor, self.logger)
+ self.info = self.logger.info
+
+ def epochInfor(
+ self,
+ epoch,
+ idx,
+ length,
+ batch_time,
+ speed,
+ data_time,
+ losses,
+ acc,
+ loss_cls=None,
+ **kwargs,
+ ):
+ msg = (
+ "Epoch: [{0}][{1}/{2}]\t"
+ "Time {batch_time.val:.3f}s ({batch_time.avg:.3f}s)\t"
+ "Speed {speed:.1f} samples/s\t"
+ "Data {data_time.val:.3f}s ({data_time.avg:.3f}s)\t"
+ "Loss {loss.val:.5f} ({loss.avg:.5f})\t"
+ "Accuracy {acc.val:.3f} ({acc.avg:.3f})".format(
+ epoch,
+ idx,
+ length,
+ batch_time=batch_time,
+ speed=speed,
+ data_time=data_time,
+ loss=losses,
+ acc=acc,
+ )
+ )
+ if loss_cls is not None:
+ msg += "\t Cls Loss: {loss_cls:.5f}".format(loss_cls=loss_cls)
+
+ for k, v in kwargs.items():
+ if v is not None:
+ msg += f"\t {k}: {v:.5f}"
+
+ self.logger.info(msg)
+
+
+def board_writing(writer, loss, acc, iterations, dataset="Train"):
+ writer.add_scalar("{}/loss".format(dataset), loss, iterations)
+ writer.add_scalar("{}/acc".format(dataset), acc, iterations)
+
+
+def debug_writing(writer, outputs, labels, inputs, iterations):
+ tmp_tar = torch.unsqueeze(labels.cpu().data[0], dim=1)
+ # tmp_out = torch.unsqueeze(outputs.cpu().data[0], dim=1)
+
+ tmp_inp = inputs.cpu().data[0]
+ tmp_inp[0] += 0.406
+ tmp_inp[1] += 0.457
+ tmp_inp[2] += 0.480
+
+ tmp_inp[0] += torch.sum(
+ F.interpolate(tmp_tar, scale_factor=4, mode="bilinear"), dim=0
+ )[0]
+ tmp_inp.clamp_(0, 1)
+
+ writer.add_image("Data/input", tmp_inp, iterations)
+
+
+def get_root_logger(log_file=None, log_level=logging.INFO):
+ """Use `get_logger` method in mmcv to get the root logger.
+
+ The logger will be initialized if it has not been initialized. By default a
+ StreamHandler will be added. If `log_file` is specified, a FileHandler will
+ also be added. The name of the root logger is the top-level package name,
+ e.g., "mmpose".
+
+ Args:
+ log_file (str | None): The log filename. If specified, a FileHandler
+ will be added to the root logger.
+ log_level (int): The root logger level. Note that only the process of
+ rank 0 is affected, while other processes will set the level to
+ "Error" and be silent most of the time.
+
+ Returns:
+ logging.Logger: The root logger.
+ """
+ return get_logger(LOG_DIR, log_file, log_level)
diff --git a/clean/video/fakestormer/losses/__init__.py b/clean/video/fakestormer/losses/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..6a92031f4fe8b37a637cb268e7d6f239c516e39c
--- /dev/null
+++ b/clean/video/fakestormer/losses/__init__.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+from .builder import LOSSES, build_losses
+from .losses import BinaryCrossEntropy
+
+__all__ = ["LOSSES", "build_losses", "BinaryCrossEntropy"]
diff --git a/clean/video/fakestormer/losses/builder.py b/clean/video/fakestormer/losses/builder.py
new file mode 100644
index 0000000000000000000000000000000000000000..3602ef6e21758e2de844ed9cad4f0294ab5aaa8a
--- /dev/null
+++ b/clean/video/fakestormer/losses/builder.py
@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+from typing import Any, Dict, Optional
+
+from register.register import Registry, build_from_cfg
+
+LOSSES = Registry("Loss")
+
+
+def build_losses(
+ cfg,
+ loss_func: Registry,
+ build_func=build_from_cfg,
+ default_args: Optional[Dict] = None,
+) -> Any:
+ return build_func(cfg, loss_func, default_args)
diff --git a/clean/video/fakestormer/losses/losses.py b/clean/video/fakestormer/losses/losses.py
new file mode 100644
index 0000000000000000000000000000000000000000..62aa97883c9e368cf346bb0a5f3b5acffb51a9b2
--- /dev/null
+++ b/clean/video/fakestormer/losses/losses.py
@@ -0,0 +1,485 @@
+# -*- coding: utf-8 -*-
+import math
+
+import numpy as np
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+from torch.nn import BCELoss, CrossEntropyLoss
+from torch.nn.functional import binary_cross_entropy
+
+from .builder import LOSSES
+
+
+def _sigmoid(hm):
+ x = hm
+ y = torch.clamp(x.sigmoid_(), min=1e-4, max=1 - 1e-4)
+ return y
+
+
+def _avg_sigmoid(hm):
+ if hm.dim() == 4:
+ x = torch.mean(hm, [2, 3])
+ else:
+ x = hm
+ y = torch.clamp(x.sigmoid_(), min=1e-4, max=1 - 1e-4)
+ return y
+
+
+def f_cstency(cstency_hm_preds, cstency_hm_gt, feature="2D"):
+ # Heatmap here that is original is returned from model without any modification
+ cstency_matrix = torch.zeros_like(cstency_hm_gt).cuda()
+ b_size = cstency_hm_preds.size(0)
+
+ indices_ = cstency_hm_gt.view(b_size, -1).argmax(dim=-1)
+
+ cst_hm_dim = cstency_hm_preds.size(1)
+
+ if feature == "2D":
+ # Handling 2D output features
+ cst_hm_h = cstency_hm_preds.size(2)
+ cst_hm_w = cstency_hm_preds.size(3)
+
+ cstency_matrix_ = torch.matmul(
+ cstency_hm_preds.view(b_size, cst_hm_dim, -1)[
+ np.arange(b_size), :, indices_
+ ].view(b_size, 1, cst_hm_dim),
+ cstency_hm_preds.view(b_size, cst_hm_dim, -1),
+ )
+ cstency_matrix_ = cstency_matrix_.view(
+ b_size, cstency_hm_gt.size(1), cst_hm_h, cst_hm_w
+ ) / math.sqrt(cst_hm_dim)
+ elif feature == "3D":
+ # Handling 3D output features
+ cst_hm_d = cstency_hm_preds.size(2)
+ cst_hm_h = cstency_hm_preds.size(3)
+ cst_hm_w = cstency_hm_preds.size(4)
+
+ cstency_matrix_ = torch.matmul(
+ cstency_hm_preds.view(b_size, cst_hm_dim, -1)[
+ np.arange(b_size), :, indices_
+ ].view(b_size, 1, cst_hm_dim),
+ cstency_hm_preds.view(b_size, cst_hm_dim, -1),
+ )
+ cstency_matrix_ = cstency_matrix_.view(
+ b_size, cstency_hm_gt.size(1), cst_hm_d, cst_hm_h, cst_hm_w
+ ) / math.sqrt(cst_hm_dim)
+ else:
+ raise ValueError(f"{feature} output shape has not been supported!")
+
+ cstency_matrix = cstency_matrix_.sigmoid_()
+
+ return cstency_matrix
+
+
+def _neg_pos_loss(hm_pred, hm_gt):
+ pos_idxes = hm_gt > 0
+ neg_idxes = ~pos_idxes
+ batch_size = hm_gt.size(0)
+ neg_pos_gt, neg_pos_pred = (
+ torch.zeros(batch_size, 1, dtype=torch.float).cuda(),
+ torch.zeros(batch_size, 1, dtype=torch.float).cuda(),
+ )
+ hm_pred_ = torch.squeeze(torch.clone(hm_pred))
+
+ for i in range(batch_size):
+ neg_pos_gt[i] = torch.sum(hm_gt[i][pos_idxes[i, :, :]]) - torch.sum(
+ hm_gt[i][neg_idxes[i, :, :]]
+ )
+ neg_pos_pred[i] = torch.sum(hm_pred_[i][pos_idxes[i, :, :]]) - torch.sum(
+ hm_pred_[i][neg_idxes[i, :, :]]
+ )
+
+ return torch.abs(neg_pos_pred), torch.abs(neg_pos_gt)
+
+
+def _neg_loss(pred, gt, epsilon=0.1, noise_distribution=0.2, alpha=0.25, **kwargs):
+ """Modified focal loss. Exactly the same as CornerNet.
+ Runs faster and costs a little bit more memory
+ Arguments:
+ pred (batch x c x h x w)
+ gt_regr (batch x c x h x w)
+ """
+ hm_mask = kwargs.get(
+ "hm_mask"
+ ) # Removing non-computed self-attention positions in total loss
+
+ loss = 0
+ pos_inds = gt.eq(1.0).float()
+ neg_inds = gt.lt(1.0).float()
+ b_size = gt.shape[0]
+
+ if hm_mask is not None:
+ pos_inds = hm_mask * pos_inds
+ neg_inds = hm_mask * neg_inds
+
+ neg_weights = torch.pow(1 - gt, 4)
+
+ # pos_loss = torch.log(pred) * torch.pow(1 - pred, 2) * pos_inds * alpha
+ pos_loss = (1 - epsilon) * torch.log(pred) * torch.pow(1 - pred, 2) * pos_inds
+ pos_loss_noise = (
+ epsilon
+ * torch.log(pred)
+ * torch.pow(1 - pred, 2)
+ * noise_distribution
+ * pos_inds
+ )
+ pos_loss = pos_loss + pos_loss_noise
+ neg_loss = torch.log(1 - pred) * torch.pow(pred, 2) * neg_inds * neg_weights
+
+ num_pos = pos_inds.float().sum()
+ pos_loss = pos_loss.sum()
+ neg_loss = neg_loss.sum()
+
+ if num_pos == 0:
+ loss = loss - neg_loss
+ else:
+ loss = loss - (pos_loss + neg_loss) / num_pos
+ loss *= alpha
+ return loss
+
+
+def _distance_hm_cls_loss(
+ cos_sim_ins, hm_preds, hm_gts, label_preds, label_gts, alpha=0.25
+):
+ b_size = hm_preds.size(0)
+ hm_preds = hm_preds.view(b_size, -1)
+ hm_gts = hm_gts.view(b_size, -1)
+ pos_hm_loss = 0.0
+ neg_hm_loss = 0.0
+
+ for i in range(0, b_size // 2):
+ for j in range(0, b_size // 2):
+ pos_hm_loss += (1 / 2) * (1 - cos_sim_ins(hm_preds[i], hm_preds[j]))
+ neg_hm_loss += (1 / 2) * (
+ 1 - cos_sim_ins(hm_preds[i], hm_preds[j + b_size // 2])
+ )
+
+ cos_loss = pos_hm_loss / ((b_size // 2) ** 2) - neg_hm_loss / ((b_size // 2) ** 2)
+ cos_loss = cos_loss * alpha
+ return cos_loss
+
+
+@LOSSES.register_module()
+class BaseLoss(nn.Module):
+ def __init__(self, cfg, **kwargs):
+ self.cfg = cfg
+ super().__init__()
+
+ for k, v in kwargs.items():
+ if v is not None:
+ self.__setattr__(k, v)
+ # Critetion ins
+ self.mse_critetion = nn.MSELoss(reduction=self.cfg.mse_reduction)
+ if hasattr(self, "use_ce") and getattr(self, "use_ce"):
+ self.bce_critetion = nn.CrossEntropyLoss(reduction=self.ce_reduction)
+ else:
+ self.bce_critetion = nn.BCEWithLogitsLoss(
+ reduction=self.cfg.ce_reduction
+ ) # For Binary Cross Entropy Loss
+ self.ce_critetion = CrossEntropyLoss(
+ reduction=self.cfg.ce_reduction
+ ) # For Cross Entropy Loss in general
+
+ # Lambda coefs
+ self.offset_lmda = self.cfg.offset_lmda
+ self.cls_lmda = self.cfg.cls_lmda
+ self.dst_hm_cls_lmda = self.cfg.dst_hm_cls_lmda
+ self.hm_lmda = self.cfg.hm_lmda
+ self.cstency_lmda = self.cfg.cstency_lmda
+
+ # Others
+ self.cos_sim_ins = nn.CosineSimilarity(dim=0, eps=1e-6)
+
+ def _offset_loss(self, preds, gts, apply_filter=False):
+ loss = 0
+ coefs = gts.gt(0).float() if apply_filter else 1
+ n_coefs = coefs.float().sum()
+
+ loss = 0.5 * self.mse_critetion(preds * coefs, gts * coefs)
+ loss /= n_coefs + 1e-6
+ loss *= self.offset_lmda
+ return loss
+
+ def _cls_loss(self, preds, gts):
+ loss = 0
+ loss = self.bce_critetion(preds, gts)
+ loss *= self.cls_lmda
+ return loss
+
+ def _consistency_loss(self, preds, gts, feature="2D"):
+ loss = torch.zeros(1).cuda()
+ encode_preds = f_cstency(preds, gts, feature=feature)
+ # loss = self.bce_critetion(encode_preds.view(-1, 1), gts.view(-1, 1))
+ loss = self.mse_critetion(encode_preds, gts)
+ loss *= self.cstency_lmda
+ return loss.sum()
+
+ def _temp_loc_loss(self, preds, gts, alpha=0.25, gamma=2):
+ """
+ Calculating loss for temporal location
+ agrs:
+ preds: output prediction of temporal location
+ gts: gt of temporal location
+ """
+ loss = self.bce_critetion(
+ preds.view(-1).unsqueeze(-1), gts.view(-1).unsqueeze(-1)
+ )
+ loss *= self.cfg.tmp_loc_lmda
+ return loss
+
+
+@LOSSES.register_module()
+class BinaryCrossEntropy(nn.Module):
+ def __init__(self, cfg, reduction="mean"):
+ super(BinaryCrossEntropy, self).__init__()
+ self.reduction = reduction
+ self.bce = nn.BCEWithLogitsLoss(reduction=self.reduction)
+
+ def __call__(self, pred, y):
+ return self.bce(pred, y)
+
+
+@LOSSES.register_module()
+class CombinedFocalLoss(BaseLoss):
+ """nn.Module warpper for focal loss"""
+
+ def __init__(self, cfg, use_target_weight, **kwargs):
+ super(CombinedFocalLoss, self).__init__(cfg, **kwargs)
+ self.hm_loss = _neg_loss
+ self.feature = kwargs.get("feature") or "2D"
+
+ def forward(
+ self,
+ hm_outputs,
+ hm_targets,
+ cls_preds,
+ cls_gts,
+ hm_mask=None,
+ offset_preds=None,
+ offset_gts=None,
+ cstency_preds=None,
+ cstency_gts=None,
+ target_weight=None,
+ temp_loc_preds=None,
+ temp_loc_gts=None,
+ ):
+ loss_return = {}
+ hm_outputs_ = torch.clone(hm_outputs)
+ hm_outputs_ = _sigmoid(hm_outputs_)
+ if hm_targets.dim() == 3:
+ hm_targets = torch.unsqueeze(hm_targets, 1)
+
+ loss_hm = self.hm_loss(
+ hm_outputs_, hm_targets, alpha=self.hm_lmda, hm_mask=hm_mask
+ )
+ loss_return["hm"] = loss_hm
+ loss_return["cls"] = self._cls_loss(cls_preds, cls_gts)
+
+ if self.dst_hm_cls_lmda > 0:
+ loss_return["dst_hm_cls"] = _distance_hm_cls_loss(
+ self.cos_sim_ins,
+ hm_outputs,
+ hm_targets,
+ cls_preds,
+ cls_gts,
+ alpha=self.dst_hm_cls_lmda,
+ )
+
+ if self.offset_lmda > 0 and offset_preds is not None:
+ loss_return["offset"] = self._offset_loss(
+ offset_preds, offset_gts, apply_filter=True
+ )
+
+ if self.cstency_lmda > 0 and cstency_preds is not None:
+ loss_return["cstency"] = self._consistency_loss(
+ cstency_preds, cstency_gts, feature=self.feature
+ )
+
+ if temp_loc_preds is not None and self.cfg.tmp_loc_lmda is not None:
+ loss_temp_loc = self._temp_loc_loss(temp_loc_preds, temp_loc_gts)
+ loss_return["temp_loc"] = loss_temp_loc
+
+ return loss_return
+
+
+@LOSSES.register_module()
+class JointsMSELoss(nn.Module):
+ def __init__(self, use_target_weight, reduction="mean", lmda=1):
+ super(JointsMSELoss, self).__init__()
+ self.reduction = reduction
+ self.criterion = nn.MSELoss(reduction=reduction)
+ self.use_target_weight = use_target_weight
+ self.lmda = lmda
+
+ def forward(self, output, target, target_weight=None, **kwargs):
+ hm_mask = kwargs.get("hm_mask")
+ batch_size = output.size(0)
+ num_joints = output.size(1)
+ heatmaps_pred = output.reshape((batch_size, num_joints, -1)).split(1, 1)
+ heatmaps_gt = target.reshape((batch_size, num_joints, -1)).split(1, 1)
+ if hm_mask is not None:
+ hm_mask_ = hm_mask.reshape((batch_size, num_joints, -1)).split(1, 1)
+ loss = 0
+
+ for idx in range(num_joints):
+ heatmap_pred = heatmaps_pred[idx].squeeze()
+ heatmap_gt = heatmaps_gt[idx].squeeze()
+ if self.use_target_weight and target_weight is not None:
+ loss += 0.5 * self.criterion(
+ heatmap_pred.mul(target_weight[:, idx]),
+ heatmap_gt.mul(target_weight[:, idx]),
+ )
+ else:
+ if hm_mask is not None:
+ heatmap_pred = heatmap_pred * hm_mask_[idx].squeeze()
+ heatmap_gt = heatmap_gt * hm_mask_[idx].squeeze()
+ loss += 0.5 * self.criterion(heatmap_pred, heatmap_gt)
+
+ if self.reduction != "mean":
+ loss = loss * self.lmda / num_joints
+ else:
+ loss = loss * self.lmda
+
+ return loss
+
+
+@LOSSES.register_module()
+class CombinedMSELoss(BaseLoss):
+ def __init__(self, cfg, use_target_weight=False, **kwargs):
+ super(CombinedMSELoss, self).__init__(cfg=cfg, **kwargs)
+ self.criterion_hm = JointsMSELoss(
+ use_target_weight=use_target_weight,
+ reduction=self.cfg.mse_reduction,
+ lmda=self.cfg.hm_lmda,
+ )
+ self.use_target_weight = use_target_weight
+ self.feature = kwargs.get("feature") or "2D"
+
+ def forward(
+ self,
+ hm_outputs,
+ hm_targets,
+ cls_preds,
+ cls_gts,
+ hm_mask=None,
+ target_weight=None,
+ cstency_preds=None,
+ cstency_gts=None,
+ temp_loc_preds=None,
+ temp_loc_gts=None,
+ **kwargs,
+ ):
+ loss_return = {}
+ loss_hm = self.criterion_hm(
+ hm_outputs, hm_targets, target_weight=target_weight, hm_mask=hm_mask
+ )
+ loss_return["hm"] = loss_hm
+
+ loss_cls = self._cls_loss(cls_preds / self.temperature, cls_gts)
+ loss_return["cls"] = loss_cls
+
+ if self.cstency_lmda > 0 and cstency_preds is not None:
+ loss_return["cstency"] = self._consistency_loss(
+ cstency_preds, cstency_gts, feature=self.feature
+ )
+
+ if temp_loc_preds is not None and self.cfg.tmp_loc_lmda is not None:
+ loss_temp_loc = self._temp_loc_loss(temp_loc_preds, temp_loc_gts)
+ loss_return["temp_loc"] = loss_temp_loc
+
+ return loss_return
+
+
+@LOSSES.register_module()
+class CombinedHeatmapBinaryLoss(nn.Module):
+ def __init__(
+ self, use_target_weight, cls_lmda=0.2, reduction="mean", cls_cal=True, **kwargs
+ ):
+ super(CombinedHeatmapBinaryLoss, self).__init__()
+ self.criterion_cls = BinaryCrossEntropy(reduction=reduction)
+ self.criterion_hm = BinaryCrossEntropy(reduction=reduction)
+ self.use_target_weight = use_target_weight
+ self.cls_lmda = cls_lmda if cls_cal else 0
+ self.cls_cal = cls_cal
+
+ def forward(self, hm_outputs, hm_targets, cls_preds, cls_gts, target_weight=None):
+ batch_size = hm_outputs.size(0)
+ hm_targets = hm_targets[:, :, :, 0]
+ hm_h = hm_outputs.size(2)
+ hm_w = hm_outputs.size(3)
+ total_pixels = hm_h * hm_w
+ loss_hm = torch.zeros(1).cuda()
+ hm_outputs_ = torch.clone(hm_outputs)
+ hm_outputs_ = _sigmoid(hm_outputs_)
+
+ for i in range(hm_h):
+ for j in range(hm_w):
+ loss_hm_ = self.criterion_hm(
+ hm_outputs_[:, :, i, j], torch.unsqueeze(hm_targets[:, i, j], 1)
+ )
+ loss_hm += loss_hm_
+
+ loss_hm = loss_hm / total_pixels
+ loss_return = {}
+ loss_return["hm"] = loss_hm
+
+ loss_cls = self.criterion_cls(cls_preds, cls_gts)
+ loss_return["cls"] = loss_cls
+ return loss_return
+
+
+@LOSSES.register_module()
+class CombinedPolyLoss(nn.Module):
+ """
+ PolyLoss: A Polynomial Expansion Perspective of Classification Loss Functions
+ """
+
+ def __init__(
+ self,
+ use_target_weight,
+ epsilon=2.0,
+ cls_lmda=0.05,
+ reduction="mean",
+ cls_cal=True,
+ **kwargs,
+ ):
+ super(CombinedPolyLoss, self).__init__()
+ self.cls_critetion = BinaryCrossEntropy(reduction=reduction)
+ self.use_target_weight = use_target_weight
+ self.epsilon = epsilon
+ self.cls_lmda = cls_lmda if cls_cal else 0
+ self.reduction = reduction
+ self.cls_cal = cls_cal
+
+ def forward(self, hm_outputs, hm_targets, cls_preds, cls_gts):
+ batch_size = hm_outputs.size(0)
+ n_classes = hm_outputs.size(1)
+ hm_h = hm_outputs.size(2)
+ hm_w = hm_outputs.size(3)
+ total_pixels = hm_h * hm_w
+ poly_loss = torch.zeros(batch_size, 1).cuda()
+ hm_outputs_ = _sigmoid(hm_outputs)
+
+ for i in range(hm_h):
+ for j in range(hm_w):
+ ce = binary_cross_entropy(
+ hm_outputs_[:, :, i, j],
+ torch.unsqueeze(hm_targets[:, i, j], -1),
+ reduction="none",
+ )
+ pt = hm_outputs_[:, :, i, j]
+ pt = torch.squeeze(pt)
+ pt = torch.where(hm_targets[:, i, j] > 0, pt, 1 - pt)
+ poly_loss += ce + self.epsilon * (1.0 - torch.unsqueeze(pt, -1))
+
+ if self.reduction == "mean":
+ poly_loss = poly_loss.sum() / total_pixels / batch_size
+ else:
+ poly_loss = poly_loss.sum()
+ loss_return = {}
+ loss_return["hm"] = poly_loss
+
+ loss_cls = self.cls_critetion(cls_preds, cls_gts)
+ loss_return["cls"] = loss_cls * self.cls_lmda
+ return loss_return
diff --git a/clean/video/fakestormer/models/__init__.py b/clean/video/fakestormer/models/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..0e79a1504a6cc94e37644af9a91dc288e636974b
--- /dev/null
+++ b/clean/video/fakestormer/models/__init__.py
@@ -0,0 +1,57 @@
+# -*- coding: utf-8 -*-
+from .builder import MODELS, build_model
+from .networks.backbones import (
+ ResNet3D,
+ SwinTransformer,
+ SwinTransformer3D,
+ TimeViT,
+ ViT,
+ Xception,
+)
+from .networks.backbones.arcface import (
+ SimpleClassificationDF,
+)
+from .networks.common import *
+from .networks.detectors import TopDownDetector
+from .networks.heads.hm_simple_head import TopdownHeatmapSimpleHead
+from .networks.mrsa_resnet import Bottleneck, PoseResNet, resnet_spec
+from .networks.necks import EFPN3D
+from .networks.pose_efficientNet import PoseEfficientNet
+from .networks.pose_hrnet import PoseHighResolutionNet
+from .utils import (
+ freeze_backbone,
+ load_model,
+ load_pretrained,
+ n_param_model,
+ preset_model,
+ save_model,
+ unfreeze_backbone,
+)
+
+__all__ = [
+ "SimpleClassificationDF",
+ "PoseResNet",
+ "MODELS",
+ "build_model",
+ "load_pretrained",
+ "freeze_backbone",
+ "resnet_spec",
+ "n_param_model",
+ "load_model",
+ "save_model",
+ "unfreeze_backbone",
+ "Bottleneck",
+ "preset_model",
+ "PoseHighResolutionNet",
+ "Xception",
+ "PoseEfficientNet",
+ "TopDownDetector",
+ "ViT",
+ "TopdownHeatmapSimpleHead",
+ "TimeViT",
+ "SwinTransformer",
+ "ResNet3D",
+ "Xception",
+ "SwinTransformer3D",
+ "EFPN3D",
+]
diff --git a/clean/video/fakestormer/models/builder.py b/clean/video/fakestormer/models/builder.py
new file mode 100644
index 0000000000000000000000000000000000000000..47f605ab1e84b61a59e375de95516fded85915f5
--- /dev/null
+++ b/clean/video/fakestormer/models/builder.py
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+import os
+import sys
+from typing import Any, Dict, Optional
+
+if not os.getcwd() in sys.path:
+ sys.path.append(os.getcwd())
+
+from register.register import Registry, build_from_cfg
+from torch.nn import Sequential
+
+
+def build_model_from_cfg(cfg, registry, default_args=None):
+ """Build a PyTorch model from config dict(s). Different from
+ ``build_from_cfg``, if cfg is a list, a ``nn.Sequential`` will be built.
+ Args:
+ cfg (dict, list[dict]): The config of modules, is is either a config
+ dict or a list of config dicts. If cfg is a list, a
+ the built modules will be wrapped with ``nn.Sequential``.
+ registry (:obj:`Registry`): A registry the module belongs to.
+ default_args (dict, optional): Default arguments to build the module.
+ Defaults to None.
+ Returns:
+ nn.Module: A built nn module.
+ """
+ if isinstance(cfg, list):
+ modules = [build_from_cfg(cfg_, registry, default_args) for cfg_ in cfg]
+ return Sequential(*modules)
+ else:
+ return build_from_cfg(cfg, registry, default_args)
+
+
+MODELS = Registry("model", build_func=build_model_from_cfg)
+HEADS = MODELS
+BACKBONES = MODELS
+DETECTORS = MODELS
+NECKS = MODELS
+
+
+def build_model(
+ cfg: Dict,
+ model: Registry,
+ build_func=build_model_from_cfg,
+ default_args: Optional[Dict] = None,
+) -> Any:
+ return build_func(cfg, model, default_args)
diff --git a/clean/video/fakestormer/models/networks/backbones/__init__.py b/clean/video/fakestormer/models/networks/backbones/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..b012fa9f3f3374d9c242e1a568a7d87d729bd5e0
--- /dev/null
+++ b/clean/video/fakestormer/models/networks/backbones/__init__.py
@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+from .resnet3d import ResNet3D
+from .swin import SwinTransformer
+from .swin3d import SwinTransformer3D
+from .vit import TimeViT, ViT
+from .xception import Xception
+
+__all__ = [
+ "ViT",
+ "TimeViT",
+ "SwinTransformer",
+ "ResNet3D",
+ "Xception",
+ "SwinTransformer3D",
+]
diff --git a/clean/video/fakestormer/models/networks/backbones/arcface.py b/clean/video/fakestormer/models/networks/backbones/arcface.py
new file mode 100644
index 0000000000000000000000000000000000000000..33ee14e492c661bfa1abb38457bfc09874155ae2
--- /dev/null
+++ b/clean/video/fakestormer/models/networks/backbones/arcface.py
@@ -0,0 +1,484 @@
+# -*- coding: utf-8 -*-
+import math
+import os
+from collections import namedtuple
+
+import torch
+import torch.nn.functional as F
+from torch.nn import (
+ AdaptiveAvgPool2d,
+ AvgPool2d,
+ BatchNorm1d,
+ BatchNorm2d,
+ Conv2d,
+ Dropout,
+ Dropout2d,
+ Linear,
+ MaxPool2d,
+ Module,
+ Parameter,
+ PReLU,
+ ReLU,
+ Sequential,
+ Sigmoid,
+ Softmax,
+)
+
+from ...builder import (
+ BACKBONES,
+ HEADS,
+ MODELS,
+ build_model,
+)
+
+################################## Original Arcface Model #############################################################
+
+
+class Flatten(Module):
+ def forward(self, input):
+ return input.view(input.size(0), -1)
+
+
+def l2_norm(input, axis=1):
+ norm = torch.norm(input, 2, axis, True)
+ output = torch.div(input, norm)
+ return output
+
+
+class SEModule(Module):
+ def __init__(self, channels, reduction):
+ super(SEModule, self).__init__()
+ self.avg_pool = AdaptiveAvgPool2d(1)
+ self.fc1 = Conv2d(
+ channels, channels // reduction, kernel_size=1, padding=0, bias=False
+ )
+ self.relu = ReLU(inplace=True)
+ self.fc2 = Conv2d(
+ channels // reduction, channels, kernel_size=1, padding=0, bias=False
+ )
+ self.sigmoid = Sigmoid()
+
+ def forward(self, x):
+ module_input = x
+ x = self.avg_pool(x)
+ x = self.fc1(x)
+ x = self.relu(x)
+ x = self.fc2(x)
+ x = self.sigmoid(x)
+ return module_input * x
+
+
+class bottleneck_IR(Module):
+ def __init__(self, in_channel, depth, stride):
+ super(bottleneck_IR, self).__init__()
+ if in_channel == depth:
+ self.shortcut_layer = MaxPool2d(1, stride)
+ else:
+ self.shortcut_layer = Sequential(
+ Conv2d(in_channel, depth, (1, 1), stride, bias=False),
+ BatchNorm2d(depth),
+ )
+ self.res_layer = Sequential(
+ BatchNorm2d(in_channel),
+ Conv2d(in_channel, depth, (3, 3), (1, 1), 1, bias=False),
+ PReLU(depth),
+ Conv2d(depth, depth, (3, 3), stride, 1, bias=False),
+ BatchNorm2d(depth),
+ )
+
+ def forward(self, x):
+ shortcut = self.shortcut_layer(x)
+ res = self.res_layer(x)
+ return res + shortcut
+
+
+class bottleneck_IR_SE(Module):
+ def __init__(self, in_channel, depth, stride):
+ super(bottleneck_IR_SE, self).__init__()
+ if in_channel == depth:
+ self.shortcut_layer = MaxPool2d(1, stride)
+ else:
+ self.shortcut_layer = Sequential(
+ Conv2d(in_channel, depth, (1, 1), stride, bias=False),
+ BatchNorm2d(depth),
+ )
+ self.res_layer = Sequential(
+ BatchNorm2d(in_channel),
+ Conv2d(in_channel, depth, (3, 3), (1, 1), 1, bias=False),
+ PReLU(depth),
+ Conv2d(depth, depth, (3, 3), stride, 1, bias=False),
+ BatchNorm2d(depth),
+ SEModule(depth, 16),
+ )
+
+ def forward(self, x):
+ shortcut = self.shortcut_layer(x)
+ res = self.res_layer(x)
+ return res + shortcut
+
+
+class Bottleneck(namedtuple("Block", ["in_channel", "depth", "stride"])):
+ """A named tuple describing a ResNet block."""
+
+
+def get_block(in_channel, depth, num_units, stride=2):
+ return [Bottleneck(in_channel, depth, stride)] + [
+ Bottleneck(depth, depth, 1) for i in range(num_units - 1)
+ ]
+
+
+def get_blocks(num_layers):
+ if num_layers == 50:
+ blocks = [
+ get_block(in_channel=64, depth=64, num_units=3),
+ get_block(in_channel=64, depth=128, num_units=4),
+ get_block(in_channel=128, depth=256, num_units=14),
+ get_block(in_channel=256, depth=512, num_units=3),
+ ]
+ elif num_layers == 100:
+ blocks = [
+ get_block(in_channel=64, depth=64, num_units=3),
+ get_block(in_channel=64, depth=128, num_units=13),
+ get_block(in_channel=128, depth=256, num_units=30),
+ get_block(in_channel=256, depth=512, num_units=3),
+ ]
+ elif num_layers == 152:
+ blocks = [
+ get_block(in_channel=64, depth=64, num_units=3),
+ get_block(in_channel=64, depth=128, num_units=8),
+ get_block(in_channel=128, depth=256, num_units=36),
+ get_block(in_channel=256, depth=512, num_units=3),
+ ]
+ return blocks
+
+
+@BACKBONES.register_module()
+class ResNet(Module):
+ def __init__(self, num_layers=50, drop_ratio=0.6, mode="ir", **kwargs):
+ """
+ Implementation for ResNet 50, 101, 152 with/out SE module
+ """
+ super(ResNet, self).__init__()
+ assert num_layers in [50, 100, 152], "num_layers should be 50,100, or 152"
+ assert mode in ["ir", "ir_se"], "mode should be ir or ir_se"
+ blocks = get_blocks(num_layers)
+ if mode == "ir":
+ unit_module = bottleneck_IR
+ elif mode == "ir_se":
+ unit_module = bottleneck_IR_SE
+ self.input_layer = Sequential(
+ Conv2d(3, 64, (3, 3), 1, 1, bias=False), BatchNorm2d(64), PReLU(64)
+ )
+ self.output_layer = Sequential(
+ BatchNorm2d(512),
+ Dropout(drop_ratio),
+ Flatten(),
+ Linear(512 * 7 * 7, 512),
+ BatchNorm1d(512),
+ )
+ modules = []
+ for block in blocks:
+ for bottleneck in block:
+ modules.append(
+ unit_module(
+ bottleneck.in_channel, bottleneck.depth, bottleneck.stride
+ )
+ )
+ self.body = Sequential(*modules)
+
+ def forward(self, x):
+ x = self.input_layer(x)
+ x = self.body(x)
+ x = self.output_layer(x)
+ x = l2_norm(x)
+ return x
+
+
+@HEADS.register_module()
+class SimpleClassificationHead(Module):
+ def __init__(self, drop_ratio=0.6, in_planes=512, **kwargs):
+ super(SimpleClassificationHead, self).__init__()
+ self.classification_head = Sequential(
+ Dropout(drop_ratio),
+ Linear(in_planes, 256),
+ BatchNorm1d(256),
+ Dropout(drop_ratio),
+ Linear(256, 128),
+ BatchNorm1d(128),
+ Dropout(drop_ratio),
+ Linear(128, 64),
+ BatchNorm1d(64),
+ Dropout(drop_ratio),
+ Linear(64, 32),
+ BatchNorm1d(32),
+ # Dropout(drop_ratio),
+ Linear(32, 1),
+ Sigmoid(),
+ )
+
+ def forward(self, x):
+ x = self.classification_head(x)
+ return x
+
+
+@MODELS.register_module()
+class SimpleClassificationDF(Module):
+ def __init__(self, cfg: dict, **kwargs):
+ super(SimpleClassificationDF, self).__init__()
+ assert "backbone" in cfg, "Config for Backbones is mandatory!"
+ assert "head" in cfg, "Config for Heads is mandatory!"
+
+ self.backbone = BACKBONES.get(cfg.backbone.type)(**cfg.backbone)
+ self.head = HEADS.get(cfg.head.type)(**cfg.head)
+ self.model = Sequential(*[self.backbone, self.head])
+
+ def forward(self, x):
+ x = self.model(x)
+ return x
+
+
+################################## MobileFaceNet #############################################################
+
+
+class Conv_block(Module):
+ def __init__(
+ self, in_c, out_c, kernel=(1, 1), stride=(1, 1), padding=(0, 0), groups=1
+ ):
+ super(Conv_block, self).__init__()
+ self.conv = Conv2d(
+ in_c,
+ out_channels=out_c,
+ kernel_size=kernel,
+ groups=groups,
+ stride=stride,
+ padding=padding,
+ bias=False,
+ )
+ self.bn = BatchNorm2d(out_c)
+ self.prelu = PReLU(out_c)
+
+ def forward(self, x):
+ x = self.conv(x)
+ x = self.bn(x)
+ x = self.prelu(x)
+ return x
+
+
+class Linear_block(Module):
+ def __init__(
+ self, in_c, out_c, kernel=(1, 1), stride=(1, 1), padding=(0, 0), groups=1
+ ):
+ super(Linear_block, self).__init__()
+ self.conv = Conv2d(
+ in_c,
+ out_channels=out_c,
+ kernel_size=kernel,
+ groups=groups,
+ stride=stride,
+ padding=padding,
+ bias=False,
+ )
+ self.bn = BatchNorm2d(out_c)
+
+ def forward(self, x):
+ x = self.conv(x)
+ x = self.bn(x)
+ return x
+
+
+class Depth_Wise(Module):
+ def __init__(
+ self,
+ in_c,
+ out_c,
+ residual=False,
+ kernel=(3, 3),
+ stride=(2, 2),
+ padding=(1, 1),
+ groups=1,
+ ):
+ super(Depth_Wise, self).__init__()
+ self.conv = Conv_block(
+ in_c, out_c=groups, kernel=(1, 1), padding=(0, 0), stride=(1, 1)
+ )
+ self.conv_dw = Conv_block(
+ groups, groups, groups=groups, kernel=kernel, padding=padding, stride=stride
+ )
+ self.project = Linear_block(
+ groups, out_c, kernel=(1, 1), padding=(0, 0), stride=(1, 1)
+ )
+ self.residual = residual
+
+ def forward(self, x):
+ if self.residual:
+ short_cut = x
+ x = self.conv(x)
+ x = self.conv_dw(x)
+ x = self.project(x)
+ if self.residual:
+ output = short_cut + x
+ else:
+ output = x
+ return output
+
+
+class Residual(Module):
+ def __init__(
+ self, c, num_block, groups, kernel=(3, 3), stride=(1, 1), padding=(1, 1)
+ ):
+ super(Residual, self).__init__()
+ modules = []
+ for _ in range(num_block):
+ modules.append(
+ Depth_Wise(
+ c,
+ c,
+ residual=True,
+ kernel=kernel,
+ padding=padding,
+ stride=stride,
+ groups=groups,
+ )
+ )
+ self.model = Sequential(*modules)
+
+ def forward(self, x):
+ return self.model(x)
+
+
+class MobileFaceNet(Module):
+ def __init__(self, embedding_size):
+ super(MobileFaceNet, self).__init__()
+ self.conv1 = Conv_block(3, 64, kernel=(3, 3), stride=(2, 2), padding=(1, 1))
+ self.conv2_dw = Conv_block(
+ 64, 64, kernel=(3, 3), stride=(1, 1), padding=(1, 1), groups=64
+ )
+ self.conv_23 = Depth_Wise(
+ 64, 64, kernel=(3, 3), stride=(2, 2), padding=(1, 1), groups=128
+ )
+ self.conv_3 = Residual(
+ 64, num_block=4, groups=128, kernel=(3, 3), stride=(1, 1), padding=(1, 1)
+ )
+ self.conv_34 = Depth_Wise(
+ 64, 128, kernel=(3, 3), stride=(2, 2), padding=(1, 1), groups=256
+ )
+ self.conv_4 = Residual(
+ 128, num_block=6, groups=256, kernel=(3, 3), stride=(1, 1), padding=(1, 1)
+ )
+ self.conv_45 = Depth_Wise(
+ 128, 128, kernel=(3, 3), stride=(2, 2), padding=(1, 1), groups=512
+ )
+ self.conv_5 = Residual(
+ 128, num_block=2, groups=256, kernel=(3, 3), stride=(1, 1), padding=(1, 1)
+ )
+ self.conv_6_sep = Conv_block(
+ 128, 512, kernel=(1, 1), stride=(1, 1), padding=(0, 0)
+ )
+ self.conv_6_dw = Linear_block(
+ 512, 512, groups=512, kernel=(7, 7), stride=(1, 1), padding=(0, 0)
+ )
+ self.conv_6_flatten = Flatten()
+ self.linear = Linear(512, embedding_size, bias=False)
+ self.bn = BatchNorm1d(embedding_size)
+
+ def forward(self, x):
+ out = self.conv1(x)
+ out = self.conv2_dw(out)
+ out = self.conv_23(out)
+ out = self.conv_3(out)
+ out = self.conv_34(out)
+ out = self.conv_4(out)
+ out = self.conv_45(out)
+ out = self.conv_5(out)
+ out = self.conv_6_sep(out)
+ out = self.conv_6_dw(out)
+ out = self.conv_6_flatten(out)
+ out = self.linear(out)
+ out = self.bn(out)
+
+ return l2_norm(out)
+
+
+################################## Arcface head #############################################################
+
+
+class Arcface(Module):
+ # implementation of additive margin softmax loss in https://arxiv.org/abs/1801.05599
+ def __init__(self, embedding_size=512, classnum=51332, s=64.0, m=0.5):
+ super(Arcface, self).__init__()
+ self.classnum = classnum
+ self.kernel = Parameter(torch.Tensor(embedding_size, classnum))
+ # initial kernel
+ self.kernel.data.uniform_(-1, 1).renorm_(2, 1, 1e-5).mul_(1e5)
+ self.m = m # the margin value, default is 0.5
+ self.s = s # scalar value default is 64, see normface https://arxiv.org/abs/1704.06369
+ self.cos_m = math.cos(m)
+ self.sin_m = math.sin(m)
+ self.mm = self.sin_m * m # issue 1
+ self.threshold = math.cos(math.pi - m)
+
+ def forward(self, embbedings, label):
+ # weights norm
+ nB = len(embbedings)
+ kernel_norm = l2_norm(self.kernel, axis=0)
+ # cos(theta+m)
+ cos_theta = torch.mm(embbedings, kernel_norm)
+ # output = torch.mm(embbedings,kernel_norm)
+ cos_theta = cos_theta.clamp(-1, 1) # for numerical stability
+ cos_theta_2 = torch.pow(cos_theta, 2)
+ sin_theta_2 = 1 - cos_theta_2
+ sin_theta = torch.sqrt(sin_theta_2)
+ cos_theta_m = cos_theta * self.cos_m - sin_theta * self.sin_m
+ # this condition controls the theta+m should in range [0, pi]
+ # 0<=theta+m<=pi
+ # -m<=theta<=pi-m
+ cond_v = cos_theta - self.threshold
+ cond_mask = cond_v <= 0
+ keep_val = cos_theta - self.mm # when theta not in [0,pi], use cosface instead
+ cos_theta_m[cond_mask] = keep_val[cond_mask]
+ output = (
+ cos_theta * 1.0
+ ) # a little bit hacky way to prevent in_place operation on cos_theta
+ idx_ = torch.arange(0, nB, dtype=torch.long)
+ output[idx_, label] = cos_theta_m[idx_, label]
+ output *= (
+ self.s
+ ) # scale up in order to make softmax work, first introduced in normface
+ return output
+
+
+################################## Cosface head #############################################################
+
+
+class Am_softmax(Module):
+ # implementation of additive margin softmax loss in https://arxiv.org/abs/1801.05599
+ def __init__(self, embedding_size=512, classnum=51332):
+ super(Am_softmax, self).__init__()
+ self.classnum = classnum
+ self.kernel = Parameter(torch.Tensor(embedding_size, classnum))
+ # initial kernel
+ self.kernel.data.uniform_(-1, 1).renorm_(2, 1, 1e-5).mul_(1e5)
+ self.m = 0.35 # additive margin recommended by the paper
+ self.s = 30.0 # see normface https://arxiv.org/abs/1704.06369
+
+ def forward(self, embbedings, label):
+ kernel_norm = l2_norm(self.kernel, axis=0)
+ cos_theta = torch.mm(embbedings, kernel_norm)
+ cos_theta = cos_theta.clamp(-1, 1) # for numerical stability
+ phi = cos_theta - self.m
+ label = label.view(-1, 1) # size=(B,1)
+ index = cos_theta.data * 0.0 # size=(B,Classnum)
+ index.scatter_(1, label.data.view(-1, 1), 1)
+ index = index.byte()
+ output = cos_theta * 1.0
+ output[index] = phi[index] # only change the correct predicted output
+ output *= (
+ self.s
+ ) # scale up in order to make softmax work, first introduced in normface
+ return output
+
+
+if __name__ == "__main__":
+ cfg = dict(num_layers=50, drop_ratio=0.6, mode="ir", type="Backbone")
+ backbone = MODELS.build(cfg)
+ print(backbone)
diff --git a/clean/video/fakestormer/models/networks/backbones/base.py b/clean/video/fakestormer/models/networks/backbones/base.py
new file mode 100644
index 0000000000000000000000000000000000000000..1154ff8b3d6d1e9a51eac290ad8186115d0be3b3
--- /dev/null
+++ b/clean/video/fakestormer/models/networks/backbones/base.py
@@ -0,0 +1,50 @@
+# Copyright (c) OpenMMLab. All rights reserved.
+import logging
+from abc import ABCMeta, abstractmethod
+
+import torch.nn as nn
+from models.utils import load_checkpoint
+
+
+class BaseBackbone(nn.Module, metaclass=ABCMeta):
+ """Base backbone.
+
+ This class defines the basic functions of a backbone. Any backbone that
+ inherits this class should at least define its own `forward` function.
+ """
+
+ def init_weights(self, pretrained=None, patch_padding="pad", part_features=None):
+ """Init backbone weights.
+
+ Args:
+ pretrained (str | None): If pretrained is a string, then it
+ initializes backbone weights by loading the pretrained
+ checkpoint. If pretrained is None, then it follows default
+ initializer or customized initializer in subclasses.
+ """
+ if isinstance(pretrained, str):
+ logger = logging.getLogger()
+ load_checkpoint(
+ self,
+ pretrained,
+ strict=False,
+ logger=logger,
+ patch_padding=patch_padding,
+ part_features=part_features,
+ )
+ elif pretrained is None:
+ # use default initializer or customized initializer in subclasses
+ pass
+ else:
+ raise TypeError(
+ "pretrained must be a str or None." f" But received {type(pretrained)}."
+ )
+
+ @abstractmethod
+ def forward(self, x):
+ """Forward function.
+
+ Args:
+ x (Tensor | tuple[Tensor]): x could be a torch.Tensor or a tuple of
+ torch.Tensor, containing input data for forward computation.
+ """
diff --git a/clean/video/fakestormer/models/networks/backbones/efficientNet.py b/clean/video/fakestormer/models/networks/backbones/efficientNet.py
new file mode 100644
index 0000000000000000000000000000000000000000..f38e265d058dfa8ca82998fcdf26451a591c55b8
--- /dev/null
+++ b/clean/video/fakestormer/models/networks/backbones/efficientNet.py
@@ -0,0 +1,592 @@
+# -*- coding: utf-8 -*-
+import collections
+import math
+import re
+from functools import partial
+
+import torch
+import torch.nn as nn
+from torch.nn import functional as F
+from torch.utils import model_zoo
+
+# Parameters for the entire model (stem, all blocks, and head)
+GlobalParams = collections.namedtuple(
+ "GlobalParams",
+ [
+ "width_coefficient",
+ "depth_coefficient",
+ "image_size",
+ "dropout_rate",
+ "num_classes",
+ "batch_norm_momentum",
+ "batch_norm_epsilon",
+ "drop_connect_rate",
+ "depth_divisor",
+ "min_depth",
+ "include_top",
+ "include_hm_decoder",
+ "head_conv",
+ "heads",
+ "num_layers",
+ "INIT_WEIGHTS",
+ "use_c2",
+ "use_c3",
+ "use_c4",
+ "use_c51",
+ "efpn",
+ "se_layer",
+ "tfpn",
+ "norm_c2",
+ ],
+)
+
+# Parameters for an individual model block
+BlockArgs = collections.namedtuple(
+ "BlockArgs",
+ [
+ "num_repeat",
+ "kernel_size",
+ "stride",
+ "expand_ratio",
+ "input_filters",
+ "output_filters",
+ "se_ratio",
+ "id_skip",
+ ],
+)
+
+# Set GlobalParams and BlockArgs's defaults
+GlobalParams.__new__.__defaults__ = (None,) * len(GlobalParams._fields)
+BlockArgs.__new__.__defaults__ = (None,) * len(BlockArgs._fields)
+
+
+# Swish activation function
+if hasattr(nn, "SiLU"):
+ Swish = nn.SiLU
+else:
+ # For compatibility with old PyTorch versions
+ class Swish(nn.Module):
+ def forward(self, x):
+ return x * torch.sigmoid(x)
+
+
+def round_filters(filters, global_params):
+ """Calculate and round number of filters based on width multiplier.
+ Use width_coefficient, depth_divisor and min_depth of global_params.
+ Args:
+ filters (int): Filters number to be calculated.
+ global_params (namedtuple): Global params of the model.
+ Returns:
+ new_filters: New filters number after calculating.
+ """
+ multiplier = global_params.width_coefficient
+ if not multiplier:
+ return filters
+ # TODO: modify the params names.
+ # maybe the names (width_divisor,min_width)
+ # are more suitable than (depth_divisor,min_depth).
+ divisor = global_params.depth_divisor
+ min_depth = global_params.min_depth
+ filters *= multiplier
+ min_depth = min_depth or divisor # pay attention to this line when using min_depth
+ # follow the formula transferred from official TensorFlow implementation
+ new_filters = max(min_depth, int(filters + divisor / 2) // divisor * divisor)
+ if new_filters < 0.9 * filters: # prevent rounding by more than 10%
+ new_filters += divisor
+ return int(new_filters)
+
+
+def round_repeats(repeats, global_params):
+ """Calculate module's repeat number of a block based on depth multiplier.
+ Use depth_coefficient of global_params.
+ Args:
+ repeats (int): num_repeat to be calculated.
+ global_params (namedtuple): Global params of the model.
+ Returns:
+ new repeat: New repeat number after calculating.
+ """
+ multiplier = global_params.depth_coefficient
+ if not multiplier:
+ return repeats
+ # follow the formula transferred from official TensorFlow implementation
+ return int(math.ceil(multiplier * repeats))
+
+
+def drop_connect(inputs, p, training):
+ """Drop connect.
+ Args:
+ input (tensor: BCWH): Input of this structure.
+ p (float: 0.0~1.0): Probability of drop connection.
+ training (bool): The running mode.
+ Returns:
+ output: Output after drop connection.
+ """
+ assert 0 <= p <= 1, "p must be in range of [0,1]"
+
+ if not training:
+ return inputs
+
+ batch_size = inputs.shape[0]
+ keep_prob = 1 - p
+
+ # generate binary_tensor mask according to probability (p for 0, 1-p for 1)
+ random_tensor = keep_prob
+ random_tensor += torch.rand(
+ [batch_size, 1, 1, 1], dtype=inputs.dtype, device=inputs.device
+ )
+ binary_tensor = torch.floor(random_tensor)
+
+ output = inputs / keep_prob * binary_tensor
+ return output
+
+
+def get_same_padding_conv2d(image_size=None):
+ """Chooses static padding if you have specified an image size, and dynamic padding otherwise.
+ Static padding is necessary for ONNX exporting of models.
+ Args:
+ image_size (int or tuple): Size of the image.
+ Returns:
+ Conv2dDynamicSamePadding or Conv2dStaticSamePadding.
+ """
+ if image_size is None:
+ return Conv2dDynamicSamePadding
+ else:
+ return partial(Conv2dStaticSamePadding, image_size=image_size)
+
+
+class Conv2dDynamicSamePadding(nn.Conv2d):
+ """2D Convolutions like TensorFlow, for a dynamic image size.
+ The padding is operated in forward function by calculating dynamically.
+ """
+
+ # Tips for 'SAME' mode padding.
+ # Given the following:
+ # i: width or height
+ # s: stride
+ # k: kernel size
+ # d: dilation
+ # p: padding
+ # Output after Conv2d:
+ # o = floor((i+p-((k-1)*d+1))/s+1)
+ # If o equals i, i = floor((i+p-((k-1)*d+1))/s+1),
+ # => p = (i-1)*s+((k-1)*d+1)-i
+
+ def __init__(
+ self,
+ in_channels,
+ out_channels,
+ kernel_size,
+ stride=1,
+ dilation=1,
+ groups=1,
+ bias=True,
+ ):
+ super().__init__(
+ in_channels, out_channels, kernel_size, stride, 0, dilation, groups, bias
+ )
+ self.stride = self.stride if len(self.stride) == 2 else [self.stride[0]] * 2
+
+ def forward(self, x):
+ ih, iw = x.size()[-2:]
+ kh, kw = self.weight.size()[-2:]
+ sh, sw = self.stride
+ oh, ow = math.ceil(ih / sh), math.ceil(
+ iw / sw
+ ) # change the output size according to stride ! ! !
+ pad_h = max((oh - 1) * self.stride[0] + (kh - 1) * self.dilation[0] + 1 - ih, 0)
+ pad_w = max((ow - 1) * self.stride[1] + (kw - 1) * self.dilation[1] + 1 - iw, 0)
+ if pad_h > 0 or pad_w > 0:
+ x = F.pad(
+ x, [pad_w // 2, pad_w - pad_w // 2, pad_h // 2, pad_h - pad_h // 2]
+ )
+ return F.conv2d(
+ x,
+ self.weight,
+ self.bias,
+ self.stride,
+ self.padding,
+ self.dilation,
+ self.groups,
+ )
+
+
+class Conv2dStaticSamePadding(nn.Conv2d):
+ """2D Convolutions like TensorFlow's 'SAME' mode, with the given input image size.
+ The padding mudule is calculated in construction function, then used in forward.
+ """
+
+ # With the same calculation as Conv2dDynamicSamePadding
+
+ def __init__(
+ self,
+ in_channels,
+ out_channels,
+ kernel_size,
+ stride=1,
+ image_size=None,
+ **kwargs,
+ ):
+ super().__init__(in_channels, out_channels, kernel_size, stride, **kwargs)
+ self.stride = self.stride if len(self.stride) == 2 else [self.stride[0]] * 2
+
+ # Calculate padding based on image size and save it
+ assert image_size is not None
+ ih, iw = (image_size, image_size) if isinstance(image_size, int) else image_size
+ kh, kw = self.weight.size()[-2:]
+ sh, sw = self.stride
+ oh, ow = math.ceil(ih / sh), math.ceil(iw / sw)
+ pad_h = max((oh - 1) * self.stride[0] + (kh - 1) * self.dilation[0] + 1 - ih, 0)
+ pad_w = max((ow - 1) * self.stride[1] + (kw - 1) * self.dilation[1] + 1 - iw, 0)
+ if pad_h > 0 or pad_w > 0:
+ self.static_padding = nn.ZeroPad2d(
+ (pad_w // 2, pad_w - pad_w // 2, pad_h // 2, pad_h - pad_h // 2)
+ )
+ else:
+ self.static_padding = nn.Identity()
+
+ def forward(self, x):
+ x = self.static_padding(x)
+ x = F.conv2d(
+ x,
+ self.weight,
+ self.bias,
+ self.stride,
+ self.padding,
+ self.dilation,
+ self.groups,
+ )
+ return x
+
+
+def get_model_params(model_name, override_params):
+ """Get the block args and global params for a given model name.
+ Args:
+ model_name (str): Model's name.
+ override_params (dict): A dict to modify global_params.
+ Returns:
+ blocks_args, global_params
+ """
+ if model_name.startswith("efficientnet"):
+ w, d, s, p = efficientnet_params(model_name)
+ # note: all models have drop connect rate = 0.2
+ blocks_args, global_params = efficientnet(
+ width_coefficient=w, depth_coefficient=d, dropout_rate=p, image_size=s
+ )
+ else:
+ raise NotImplementedError(
+ "model name is not pre-defined: {}".format(model_name)
+ )
+ if override_params:
+ # ValueError will be raised here if override_params has fields not included in global_params.
+ global_params = global_params._replace(**override_params)
+ return blocks_args, global_params
+
+
+def efficientnet_params(model_name):
+ """Map EfficientNet model name to parameter coefficients.
+ Args:
+ model_name (str): Model name to be queried.
+ Returns:
+ params_dict[model_name]: A (width,depth,res,dropout) tuple.
+ """
+ params_dict = {
+ # Coefficients: width,depth,res,dropout
+ "efficientnet-b0": (1.0, 1.0, 224, 0.2),
+ "efficientnet-b1": (1.0, 1.1, 240, 0.2),
+ "efficientnet-b2": (1.1, 1.2, 260, 0.3),
+ "efficientnet-b3": (1.2, 1.4, 300, 0.3),
+ "efficientnet-b4": (1.4, 1.8, 380, 0.4),
+ "efficientnet-b5": (1.6, 2.2, 456, 0.4),
+ "efficientnet-b6": (1.8, 2.6, 528, 0.5),
+ "efficientnet-b7": (2.0, 3.1, 600, 0.5),
+ "efficientnet-b8": (2.2, 3.6, 672, 0.5),
+ "efficientnet-l2": (4.3, 5.3, 800, 0.5),
+ }
+ return params_dict[model_name]
+
+
+def efficientnet(
+ width_coefficient=None,
+ depth_coefficient=None,
+ image_size=None,
+ dropout_rate=0.2,
+ drop_connect_rate=0.2,
+ num_classes=1000,
+ include_top=True,
+ include_hm_decoder=False,
+ head_conv=None,
+ heads=None,
+ use_c2=False,
+ use_c3=False,
+ use_c4=False,
+ use_c51=False,
+ num_layers=None,
+ INIT_WEIGHTS=None,
+ efpn=False,
+ se_layer=False,
+ tfpn=False,
+ norm_c2=False,
+):
+ """Create BlockArgs and GlobalParams for efficientnet model.
+ Args:
+ width_coefficient (float)
+ depth_coefficient (float)
+ image_size (int)
+ dropout_rate (float)
+ drop_connect_rate (float)
+ num_classes (int)
+ Meaning as the name suggests.
+ Returns:
+ blocks_args, global_params.
+ """
+
+ # Blocks args for the whole model(efficientnet-b0 by default)
+ # It will be modified in the construction of EfficientNet Class according to model
+ blocks_args = [
+ "r1_k3_s11_e1_i32_o16_se0.25",
+ "r2_k3_s22_e6_i16_o24_se0.25",
+ "r2_k5_s22_e6_i24_o40_se0.25",
+ "r3_k3_s22_e6_i40_o80_se0.25",
+ "r3_k5_s11_e6_i80_o112_se0.25",
+ "r4_k5_s22_e6_i112_o192_se0.25",
+ "r1_k3_s11_e6_i192_o320_se0.25",
+ ]
+ blocks_args = BlockDecoder.decode(blocks_args)
+
+ global_params = GlobalParams(
+ width_coefficient=width_coefficient,
+ depth_coefficient=depth_coefficient,
+ image_size=image_size,
+ dropout_rate=dropout_rate,
+ num_classes=num_classes,
+ batch_norm_momentum=0.99,
+ batch_norm_epsilon=1e-3,
+ drop_connect_rate=drop_connect_rate,
+ depth_divisor=8,
+ min_depth=None,
+ include_top=include_top,
+ include_hm_decoder=include_hm_decoder,
+ head_conv=head_conv,
+ heads=heads,
+ use_c2=use_c2,
+ use_c3=use_c3,
+ use_c4=use_c4,
+ use_c51=use_c51,
+ efpn=efpn,
+ tfpn=tfpn,
+ se_layer=se_layer,
+ num_layers=num_layers,
+ norm_c2=norm_c2,
+ INIT_WEIGHTS=INIT_WEIGHTS,
+ )
+
+ return blocks_args, global_params
+
+
+class BlockDecoder(object):
+ """Block Decoder for readability,
+ straight from the official TensorFlow repository.
+ """
+
+ @staticmethod
+ def _decode_block_string(block_string):
+ """Get a block through a string notation of arguments.
+ Args:
+ block_string (str): A string notation of arguments.
+ Examples: 'r1_k3_s11_e1_i32_o16_se0.25_noskip'.
+ Returns:
+ BlockArgs: The namedtuple defined at the top of this file.
+ """
+ assert isinstance(block_string, str)
+
+ ops = block_string.split("_")
+ options = {}
+ for op in ops:
+ splits = re.split(r"(\d.*)", op)
+ if len(splits) >= 2:
+ key, value = splits[:2]
+ options[key] = value
+
+ # Check stride
+ assert ("s" in options and len(options["s"]) == 1) or (
+ len(options["s"]) == 2 and options["s"][0] == options["s"][1]
+ )
+
+ return BlockArgs(
+ num_repeat=int(options["r"]),
+ kernel_size=int(options["k"]),
+ stride=[int(options["s"][0])],
+ expand_ratio=int(options["e"]),
+ input_filters=int(options["i"]),
+ output_filters=int(options["o"]),
+ se_ratio=float(options["se"]) if "se" in options else None,
+ id_skip=("noskip" not in block_string),
+ )
+
+ @staticmethod
+ def _encode_block_string(block):
+ """Encode a block to a string.
+ Args:
+ block (namedtuple): A BlockArgs type argument.
+ Returns:
+ block_string: A String form of BlockArgs.
+ """
+ args = [
+ "r%d" % block.num_repeat,
+ "k%d" % block.kernel_size,
+ "s%d%d" % (block.strides[0], block.strides[1]),
+ "e%s" % block.expand_ratio,
+ "i%d" % block.input_filters,
+ "o%d" % block.output_filters,
+ ]
+ if 0 < block.se_ratio <= 1:
+ args.append("se%s" % block.se_ratio)
+ if block.id_skip is False:
+ args.append("noskip")
+ return "_".join(args)
+
+ @staticmethod
+ def decode(string_list):
+ """Decode a list of string notations to specify blocks inside the network.
+ Args:
+ string_list (list[str]): A list of strings, each string is a notation of block.
+ Returns:
+ blocks_args: A list of BlockArgs namedtuples of block args.
+ """
+ assert isinstance(string_list, list)
+ blocks_args = []
+ for block_string in string_list:
+ blocks_args.append(BlockDecoder._decode_block_string(block_string))
+ return blocks_args
+
+ @staticmethod
+ def encode(blocks_args):
+ """Encode a list of BlockArgs to a list of strings.
+ Args:
+ blocks_args (list[namedtuples]): A list of BlockArgs namedtuples of block args.
+ Returns:
+ block_strings: A list of strings, each string is a notation of block.
+ """
+ block_strings = []
+ for block in blocks_args:
+ block_strings.append(BlockDecoder._encode_block_string(block))
+ return block_strings
+
+
+class SwishImplementation(torch.autograd.Function):
+ @staticmethod
+ def forward(ctx, i):
+ result = i * torch.sigmoid(i)
+ ctx.save_for_backward(i)
+ return result
+
+ @staticmethod
+ def backward(ctx, grad_output):
+ i = ctx.saved_tensors[0]
+ sigmoid_i = torch.sigmoid(i)
+ return grad_output * (sigmoid_i * (1 + i * (1 - sigmoid_i)))
+
+
+def get_width_and_height_from_size(x):
+ """Obtain height and width from x.
+ Args:
+ x (int, tuple or list): Data size.
+ Returns:
+ size: A tuple or list (H,W).
+ """
+ if isinstance(x, int):
+ return x, x
+ if isinstance(x, list) or isinstance(x, tuple):
+ return x
+ else:
+ raise TypeError()
+
+
+def calculate_output_image_size(input_image_size, stride):
+ """Calculates the output image size when using Conv2dSamePadding with a stride.
+ Necessary for static padding. Thanks to mannatsingh for pointing this out.
+ Args:
+ input_image_size (int, tuple or list): Size of input image.
+ stride (int, tuple or list): Conv2d operation's stride.
+ Returns:
+ output_image_size: A list [H,W].
+ """
+ if input_image_size is None:
+ return None
+ image_height, image_width = get_width_and_height_from_size(input_image_size)
+ stride = stride if isinstance(stride, int) else stride[0]
+ image_height = int(math.ceil(image_height / stride))
+ image_width = int(math.ceil(image_width / stride))
+ return [image_height, image_width]
+
+
+class MemoryEfficientSwish(nn.Module):
+ def forward(self, x):
+ return SwishImplementation.apply(x)
+
+
+url_map_advprop = {
+ "efficientnet-b0": "https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b0-b64d5a18.pth",
+ "efficientnet-b1": "https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b1-0f3ce85a.pth",
+ "efficientnet-b2": "https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b2-6e9d97e5.pth",
+ "efficientnet-b3": "https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b3-cdd7c0f4.pth",
+ "efficientnet-b4": "https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b4-44fb3a87.pth",
+ "efficientnet-b5": "https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b5-86493f6b.pth",
+ "efficientnet-b6": "https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b6-ac80338e.pth",
+ "efficientnet-b7": "https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b7-4652b6dd.pth",
+ "efficientnet-b8": "https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b8-22a8fe65.pth",
+}
+
+
+url_map = {
+ "efficientnet-b0": "https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b0-355c32eb.pth",
+ "efficientnet-b1": "https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b1-f1951068.pth",
+ "efficientnet-b2": "https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b2-8bb594d6.pth",
+ "efficientnet-b3": "https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b3-5fb5a3c3.pth",
+ "efficientnet-b4": "https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b4-6ed6700e.pth",
+ "efficientnet-b5": "https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b5-b6417697.pth",
+ "efficientnet-b6": "https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b6-c76e70fd.pth",
+ "efficientnet-b7": "https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b7-dcc49843.pth",
+}
+
+
+def load_pretrained_weights(
+ model, model_name, weights_path=None, load_fc=True, advprop=False, verbose=True
+):
+ """Loads pretrained weights from weights path or download using url.
+ Args:
+ model (Module): The whole model of efficientnet.
+ model_name (str): Model name of efficientnet.
+ weights_path (None or str):
+ str: path to pretrained weights file on the local disk.
+ None: use pretrained weights downloaded from the Internet.
+ load_fc (bool): Whether to load pretrained weights for fc layer at the end of the model.
+ advprop (bool): Whether to load pretrained weights
+ trained with advprop (valid when weights_path is None).
+ """
+ if isinstance(weights_path, str):
+ state_dict = torch.load(weights_path, map_location=torch.device("cpu"))
+ else:
+ # AutoAugment or Advprop (different preprocessing)
+ url_map_ = url_map_advprop if advprop else url_map
+ state_dict = model_zoo.load_url(url_map_[model_name])
+
+ if load_fc:
+ ret = model.load_state_dict(state_dict, strict=False)
+ assert (
+ not ret.missing_keys
+ ), "Missing keys when loading pretrained weights: {}".format(ret.missing_keys)
+ else:
+ state_dict.pop("_fc.weight")
+ state_dict.pop("_fc.bias")
+ ret = model.load_state_dict(state_dict, strict=False)
+
+ # if len(ret.missing_keys):
+ # assert set(ret.missing_keys) == set(
+ # ['_fc.weight', '_fc.bias']), 'Missing keys when loading pretrained weights: {}'.format(ret.missing_keys)
+ assert (
+ not ret.unexpected_keys
+ ), "Missing keys when loading pretrained weights: {}".format(ret.unexpected_keys)
+
+ if verbose:
+ print("Loaded pretrained weights for {}".format(model_name))
diff --git a/clean/video/fakestormer/models/networks/backbones/resnet3d.py b/clean/video/fakestormer/models/networks/backbones/resnet3d.py
new file mode 100644
index 0000000000000000000000000000000000000000..7bb9055de832389eff045026729d1f0f152995e6
--- /dev/null
+++ b/clean/video/fakestormer/models/networks/backbones/resnet3d.py
@@ -0,0 +1,296 @@
+# -*- coding:utf-8 -*-
+import os
+import sys
+
+if not (os.getcwd()) in sys.path:
+ sys.path.append(os.getcwd())
+import math
+from functools import partial
+
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+
+from ...builder import BACKBONES
+from .base import BaseBackbone
+
+
+def get_inplanes():
+ return [64, 128, 256, 512]
+
+
+def conv3x3x3(in_planes, out_planes, stride=1):
+ return nn.Conv3d(
+ in_planes, out_planes, kernel_size=3, stride=stride, padding=1, bias=False
+ )
+
+
+def conv1x1x1(in_planes, out_planes, stride=1):
+ return nn.Conv3d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False)
+
+
+class BasicBlock(nn.Module):
+ expansion = 1
+
+ def __init__(self, in_planes, planes, stride=1, downsample=None):
+ super().__init__()
+
+ self.conv1 = conv3x3x3(in_planes, planes, stride)
+ self.bn1 = nn.BatchNorm3d(planes)
+ self.relu = nn.ReLU(inplace=True)
+ self.conv2 = conv3x3x3(planes, planes)
+ self.bn2 = nn.BatchNorm3d(planes)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x):
+ residual = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+
+ if self.downsample is not None:
+ residual = self.downsample(x)
+
+ out += residual
+ out = self.relu(out)
+
+ return out
+
+ @staticmethod
+ def __repr__():
+ return "BasicBlock"
+
+
+class Bottleneck(nn.Module):
+ expansion = 4
+
+ def __init__(self, in_planes, planes, stride=1, downsample=None):
+ super().__init__()
+
+ self.conv1 = conv1x1x1(in_planes, planes)
+ self.bn1 = nn.BatchNorm3d(planes)
+ self.conv2 = conv3x3x3(planes, planes, stride)
+ self.bn2 = nn.BatchNorm3d(planes)
+ self.conv3 = conv1x1x1(planes, planes * self.expansion)
+ self.bn3 = nn.BatchNorm3d(planes * self.expansion)
+ self.relu = nn.ReLU(inplace=True)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x):
+ residual = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+ out = self.relu(out)
+
+ out = self.conv3(out)
+ out = self.bn3(out)
+
+ if self.downsample is not None:
+ residual = self.downsample(x)
+
+ out += residual
+ out = self.relu(out)
+
+ return out
+
+ @staticmethod
+ def __repr__():
+ return "Bottleneck"
+
+
+@BACKBONES.register_module()
+class ResNet3D(BaseBackbone):
+ def __init__(
+ self,
+ block,
+ layers,
+ block_inplanes,
+ n_input_channels=3,
+ conv1_t_size=7,
+ conv1_t_stride=1,
+ no_max_pool=False,
+ shortcut_type="B",
+ widen_factor=1.0,
+ n_classes=400,
+ do_cls=False,
+ dropout_rate=0.25,
+ ):
+ super().__init__()
+
+ # Convert Cls name into Cls Object
+ if isinstance(block, str):
+ for bl in [BasicBlock, Bottleneck]:
+ if block == bl.__repr__():
+ block = bl
+
+ block_inplanes = [int(x * widen_factor) for x in block_inplanes]
+
+ self.in_planes = block_inplanes[0]
+ self.no_max_pool = no_max_pool
+
+ self.conv1 = nn.Conv3d(
+ n_input_channels,
+ self.in_planes,
+ kernel_size=(conv1_t_size, 7, 7),
+ stride=(conv1_t_stride, 2, 2),
+ padding=(conv1_t_size // 2, 3, 3),
+ bias=False,
+ )
+ self.bn1 = nn.BatchNorm3d(self.in_planes)
+ self.relu = nn.ReLU(inplace=True)
+ self.maxpool = nn.MaxPool3d(kernel_size=3, stride=2, padding=1)
+ self.layer1 = self._make_layer(
+ block, block_inplanes[0], layers[0], shortcut_type
+ )
+ self.drop_layer1 = nn.Dropout(dropout_rate)
+ self.layer2 = self._make_layer(
+ block, block_inplanes[1], layers[1], shortcut_type, stride=2
+ )
+ self.drop_layer2 = nn.Dropout(dropout_rate)
+ self.layer3 = self._make_layer(
+ block, block_inplanes[2], layers[2], shortcut_type, stride=2
+ )
+ self.drop_layer3 = nn.Dropout(dropout_rate)
+ self.layer4 = self._make_layer(
+ block, block_inplanes[3], layers[3], shortcut_type, stride=2
+ )
+ self.drop_layer4 = nn.Dropout(dropout_rate)
+
+ self.avgpool = nn.AdaptiveAvgPool3d((1, 1, 1))
+ self.do_cls = do_cls
+ if self.do_cls:
+ self.fc = nn.Linear(block_inplanes[3] * block.expansion, n_classes)
+
+ def _downsample_basic_block(self, x, planes, stride):
+ out = F.avg_pool3d(x, kernel_size=1, stride=stride)
+ zero_pads = torch.zeros(
+ out.size(0), planes - out.size(1), out.size(2), out.size(3), out.size(4)
+ )
+ if isinstance(out.data, torch.cuda.FloatTensor):
+ zero_pads = zero_pads.cuda()
+
+ out = torch.cat([out.data, zero_pads], dim=1)
+
+ return out
+
+ def _make_layer(self, block, planes, blocks, shortcut_type, stride=1):
+ downsample = None
+ if stride != 1 or self.in_planes != planes * block.expansion:
+ if shortcut_type == "A":
+ downsample = partial(
+ self._downsample_basic_block,
+ planes=planes * block.expansion,
+ stride=stride,
+ )
+ else:
+ downsample = nn.Sequential(
+ conv1x1x1(self.in_planes, planes * block.expansion, stride),
+ nn.BatchNorm3d(planes * block.expansion),
+ )
+
+ layers = []
+ layers.append(
+ block(
+ in_planes=self.in_planes,
+ planes=planes,
+ stride=stride,
+ downsample=downsample,
+ )
+ )
+ self.in_planes = planes * block.expansion
+ for i in range(1, blocks):
+ layers.append(block(self.in_planes, planes))
+
+ return nn.Sequential(*layers)
+
+ def forward(self, x):
+ outputs = []
+ x = self.conv1(x)
+ x = self.bn1(x)
+ x = self.relu(x)
+ if not self.no_max_pool:
+ x = self.maxpool(x)
+
+ x1 = self.layer1(x) # 256x16x56x56
+ x2 = self.layer2(x1) # 512x8x28x28
+ x3 = self.layer3(x2) # 1024x4x14x14
+ x4 = self.layer4(x3) # 2048x2x7x7
+
+ if self.do_cls:
+ x_avg = self.avgpool(x4)
+ x = x_avg.view(x_avg.size(0), -1).unsqueeze(1)
+ x = self.fc(x)
+
+ res = {}
+ res["embed"] = x4
+
+ x1 = self.drop_layer1(x1)
+ outputs.append(x1)
+ x2 = self.drop_layer2(x2)
+ outputs.append(x2)
+ x3 = self.drop_layer3(x3)
+ outputs.append(x3)
+ outputs.append(x4)
+ res["outputs"] = outputs
+
+ return res
+
+ def init_weights(self, pretrained=None):
+ if pretrained is not None:
+ super().init_weights(pretrained=pretrained)
+ else:
+ for m in self.modules():
+ if isinstance(m, nn.Conv3d):
+ nn.init.kaiming_normal_(
+ m.weight, mode="fan_out", nonlinearity="relu"
+ )
+ elif isinstance(m, nn.BatchNorm3d):
+ nn.init.constant_(m.weight, 1)
+ nn.init.constant_(m.bias, 0)
+
+
+def generate_model(model_depth, **kwargs):
+ assert model_depth in [10, 18, 34, 50, 101, 152, 200]
+
+ if model_depth == 10:
+ model = ResNet3D(BasicBlock, [1, 1, 1, 1], get_inplanes(), **kwargs)
+ elif model_depth == 18:
+ model = ResNet3D(BasicBlock, [2, 2, 2, 2], get_inplanes(), **kwargs)
+ elif model_depth == 34:
+ model = ResNet3D(BasicBlock, [3, 4, 6, 3], get_inplanes(), **kwargs)
+ elif model_depth == 50:
+ model = ResNet3D(Bottleneck, [3, 4, 6, 3], get_inplanes(), **kwargs)
+ elif model_depth == 101:
+ model = ResNet3D(Bottleneck, [3, 4, 23, 3], get_inplanes(), **kwargs)
+ elif model_depth == 152:
+ model = ResNet3D(Bottleneck, [3, 8, 36, 3], get_inplanes(), **kwargs)
+ elif model_depth == 200:
+ model = ResNet3D(Bottleneck, [3, 24, 36, 3], get_inplanes(), **kwargs)
+
+ return model
+
+
+if __name__ == "__main__":
+ cfg = {
+ "type": "ResNet3D",
+ "block": Bottleneck,
+ "layers": [3, 4, 6, 3],
+ "block_inplanes": [64, 128, 256, 512],
+ }
+ net = BACKBONES.build(cfg=cfg, default_args=cfg)
+ input = torch.rand(1, 3, 32, 224, 224)
+ res = net(input)
+ print(res["embed"].shape)
+ for i in range(len(res["outputs"])):
+ print(f"Layer {i+1}", res["outputs"][i].shape)
diff --git a/clean/video/fakestormer/models/networks/backbones/swin.py b/clean/video/fakestormer/models/networks/backbones/swin.py
new file mode 100644
index 0000000000000000000000000000000000000000..9f0d18cd6b593e99e3d39f684d74c9d83fb46ac9
--- /dev/null
+++ b/clean/video/fakestormer/models/networks/backbones/swin.py
@@ -0,0 +1,1151 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) OpenMMLab. All rights reserved.
+import math
+import os
+import sys
+from collections import OrderedDict
+from copy import deepcopy
+from typing import Sequence
+
+if not os.getcwd() in sys.path:
+ sys.path.append(os.getcwd())
+
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+import torch.utils.checkpoint as cp
+from einops import rearrange, reduce, repeat
+from logs.logger import get_root_logger
+from mmcv.cnn import (
+ build_conv_layer,
+ build_norm_layer,
+ constant_init,
+ trunc_normal_init,
+)
+from mmcv.cnn.bricks.transformer import FFN, build_dropout
+from mmcv.cnn.utils.weight_init import trunc_normal_
+from mmcv.runner import _load_checkpoint
+from mmcv.runner.base_module import BaseModule
+from mmcv.utils import to_2tuple
+from models.builder import BACKBONES
+from models.utils import swin_converter
+
+from .base import BaseBackbone
+
+
+class AdaptivePadding(nn.Module):
+ """Applies padding to input (if needed) so that input can get fully covered
+ by filter you specified. It support two modes "same" and "corner". The
+ "same" mode is same with "SAME" padding mode in TensorFlow, pad zero around
+ input. The "corner" mode would pad zero to bottom right.
+
+ Args:
+ kernel_size (int | tuple): Size of the kernel:
+ stride (int | tuple): Stride of the filter. Default: 1:
+ dilation (int | tuple): Spacing between kernel elements.
+ Default: 1
+ padding (str): Support "same" and "corner", "corner" mode
+ would pad zero to bottom right, and "same" mode would
+ pad zero around input. Default: "corner".
+ Example:
+ >>> kernel_size = 16
+ >>> stride = 16
+ >>> dilation = 1
+ >>> input = torch.rand(1, 1, 15, 17)
+ >>> adap_pad = AdaptivePadding(
+ >>> kernel_size=kernel_size,
+ >>> stride=stride,
+ >>> dilation=dilation,
+ >>> padding="corner")
+ >>> out = adap_pad(input)
+ >>> assert (out.shape[2], out.shape[3]) == (16, 32)
+ >>> input = torch.rand(1, 1, 16, 17)
+ >>> out = adap_pad(input)
+ >>> assert (out.shape[2], out.shape[3]) == (16, 32)
+ """
+
+ def __init__(self, kernel_size=1, stride=1, dilation=1, padding="corner"):
+
+ super(AdaptivePadding, self).__init__()
+
+ assert padding in ("same", "corner")
+
+ kernel_size = to_2tuple(kernel_size)
+ stride = to_2tuple(stride)
+ padding = to_2tuple(padding)
+ dilation = to_2tuple(dilation)
+
+ self.padding = padding
+ self.kernel_size = kernel_size
+ self.stride = stride
+ self.dilation = dilation
+
+ def get_pad_shape(self, input_shape):
+ input_h, input_w = input_shape
+ kernel_h, kernel_w = self.kernel_size
+ stride_h, stride_w = self.stride
+ output_h = math.ceil(input_h / stride_h)
+ output_w = math.ceil(input_w / stride_w)
+ pad_h = max(
+ (output_h - 1) * stride_h + (kernel_h - 1) * self.dilation[0] + 1 - input_h,
+ 0,
+ )
+ pad_w = max(
+ (output_w - 1) * stride_w + (kernel_w - 1) * self.dilation[1] + 1 - input_w,
+ 0,
+ )
+ return pad_h, pad_w
+
+ def forward(self, x):
+ pad_h, pad_w = self.get_pad_shape(x.size()[-2:])
+ if pad_h > 0 or pad_w > 0:
+ if self.padding == "corner":
+ x = F.pad(x, [0, pad_w, 0, pad_h])
+ elif self.padding == "same":
+ x = F.pad(
+ x, [pad_w // 2, pad_w - pad_w // 2, pad_h // 2, pad_h - pad_h // 2]
+ )
+ return x
+
+
+class PatchEmbed(BaseModule):
+ """Image to Patch Embedding.
+
+ We use a conv layer to implement PatchEmbed.
+
+ Args:
+ in_channels (int): The num of input channels. Default: 3
+ embed_dims (int): The dimensions of embedding. Default: 768
+ conv_type (str): The config dict for embedding
+ conv layer type selection. Default: "Conv2d.
+ kernel_size (int): The kernel_size of embedding conv. Default: 16.
+ stride (int): The slide stride of embedding conv.
+ Default: None (Would be set as `kernel_size`).
+ padding (int | tuple | string ): The padding length of
+ embedding conv. When it is a string, it means the mode
+ of adaptive padding, support "same" and "corner" now.
+ Default: "corner".
+ dilation (int): The dilation rate of embedding conv. Default: 1.
+ bias (bool): Bias of embed conv. Default: True.
+ norm_cfg (dict, optional): Config dict for normalization layer.
+ Default: None.
+ input_size (int | tuple | None): The size of input, which will be
+ used to calculate the out size. Only work when `dynamic_size`
+ is False. Default: None.
+ init_cfg (`mmcv.ConfigDict`, optional): The Config for initialization.
+ Default: None.
+ """
+
+ def __init__(
+ self,
+ in_channels=3,
+ embed_dims=768,
+ conv_type="Conv2d",
+ kernel_size=16,
+ stride=16,
+ padding="corner",
+ dilation=1,
+ bias=True,
+ norm_cfg=None,
+ input_size=None,
+ init_cfg=None,
+ ):
+ super(PatchEmbed, self).__init__(init_cfg=init_cfg)
+
+ self.embed_dims = embed_dims
+ if stride is None:
+ stride = kernel_size
+
+ kernel_size = to_2tuple(kernel_size)
+ stride = to_2tuple(stride)
+ dilation = to_2tuple(dilation)
+
+ if isinstance(padding, str):
+ self.adap_padding = AdaptivePadding(
+ kernel_size=kernel_size,
+ stride=stride,
+ dilation=dilation,
+ padding=padding,
+ )
+ # disable the padding of conv
+ padding = 0
+ else:
+ self.adap_padding = None
+ padding = to_2tuple(padding)
+
+ self.projection = build_conv_layer(
+ dict(type=conv_type),
+ in_channels=in_channels,
+ out_channels=embed_dims,
+ kernel_size=kernel_size,
+ stride=stride,
+ padding=padding,
+ dilation=dilation,
+ bias=bias,
+ )
+
+ if norm_cfg is not None:
+ self.norm = build_norm_layer(norm_cfg, embed_dims)[1]
+ else:
+ self.norm = None
+
+ if input_size:
+ input_size = to_2tuple(input_size)
+ # `init_out_size` would be used outside to
+ # calculate the num_patches
+ # when `use_abs_pos_embed` outside
+ self.init_input_size = input_size
+ if self.adap_padding:
+ pad_h, pad_w = self.adap_padding.get_pad_shape(input_size)
+ input_h, input_w = input_size
+ input_h = input_h + pad_h
+ input_w = input_w + pad_w
+ input_size = (input_h, input_w)
+
+ # https://pytorch.org/docs/stable/generated/torch.nn.Conv2d.html
+ h_out = (
+ input_size[0] + 2 * padding[0] - dilation[0] * (kernel_size[0] - 1) - 1
+ ) // stride[0] + 1
+ w_out = (
+ input_size[1] + 2 * padding[1] - dilation[1] * (kernel_size[1] - 1) - 1
+ ) // stride[1] + 1
+ self.init_out_size = (h_out, w_out)
+ else:
+ self.init_input_size = None
+ self.init_out_size = None
+
+ def forward(self, x):
+ """
+ Args:
+ x (Tensor): Has shape (B, C, H, W). In most case, C is 3.
+
+ Returns:
+ tuple: Contains merged results and its spatial shape.
+
+ - x (Tensor): Has shape (B, out_h * out_w, embed_dims)
+ - out_size (tuple[int]): Spatial shape of x, arrange as
+ (out_h, out_w).
+ """
+
+ if self.adap_padding:
+ x = self.adap_padding(x)
+
+ x = self.projection(x)
+ out_size = (x.shape[2], x.shape[3])
+ x = x.flatten(2).transpose(1, 2)
+ if self.norm is not None:
+ x = self.norm(x)
+ return x, out_size
+
+
+class PatchMerging(BaseModule):
+ """Merge patch feature map.
+
+ This layer groups feature map by kernel_size, and applies norm and linear
+ layers to the grouped feature map. Our implementation uses `nn.Unfold` to
+ merge patch, which is about 25% faster than original implementation.
+ Instead, we need to modify pretrained models for compatibility.
+
+ Args:
+ in_channels (int): The num of input channels.
+ to gets fully covered by filter and stride you specified..
+ Default: True.
+ out_channels (int): The num of output channels.
+ kernel_size (int | tuple, optional): the kernel size in the unfold
+ layer. Defaults to 2.
+ stride (int | tuple, optional): the stride of the sliding blocks in the
+ unfold layer. Default: None. (Would be set as `kernel_size`)
+ padding (int | tuple | string ): The padding length of
+ embedding conv. When it is a string, it means the mode
+ of adaptive padding, support "same" and "corner" now.
+ Default: "corner".
+ dilation (int | tuple, optional): dilation parameter in the unfold
+ layer. Default: 1.
+ bias (bool, optional): Whether to add bias in linear layer or not.
+ Defaults: False.
+ norm_cfg (dict, optional): Config dict for normalization layer.
+ Default: dict(type='LN').
+ init_cfg (dict, optional): The extra config for initialization.
+ Default: None.
+ """
+
+ def __init__(
+ self,
+ in_channels,
+ out_channels,
+ kernel_size=2,
+ stride=None,
+ padding="corner",
+ dilation=1,
+ bias=False,
+ norm_cfg=dict(type="LN"),
+ init_cfg=None,
+ ):
+ super().__init__(init_cfg=init_cfg)
+ self.in_channels = in_channels
+ self.out_channels = out_channels
+ if stride:
+ stride = stride
+ else:
+ stride = kernel_size
+
+ kernel_size = to_2tuple(kernel_size)
+ stride = to_2tuple(stride)
+ dilation = to_2tuple(dilation)
+
+ if isinstance(padding, str):
+ self.adap_padding = AdaptivePadding(
+ kernel_size=kernel_size,
+ stride=stride,
+ dilation=dilation,
+ padding=padding,
+ )
+ # disable the padding of unfold
+ padding = 0
+ else:
+ self.adap_padding = None
+
+ padding = to_2tuple(padding)
+ self.sampler = nn.Unfold(
+ kernel_size=kernel_size, dilation=dilation, padding=padding, stride=stride
+ )
+
+ sample_dim = kernel_size[0] * kernel_size[1] * in_channels
+
+ if norm_cfg is not None:
+ self.norm = build_norm_layer(norm_cfg, sample_dim)[1]
+ else:
+ self.norm = None
+
+ self.reduction = nn.Linear(sample_dim, out_channels, bias=bias)
+
+ def forward(self, x, input_size):
+ """
+ Args:
+ x (Tensor): Has shape (B, H*W, C_in).
+ input_size (tuple[int]): The spatial shape of x, arrange as (H, W).
+ Default: None.
+
+ Returns:
+ tuple: Contains merged results and its spatial shape.
+
+ - x (Tensor): Has shape (B, Merged_H * Merged_W, C_out)
+ - out_size (tuple[int]): Spatial shape of x, arrange as
+ (Merged_H, Merged_W).
+ """
+ B, L, C = x.shape
+ assert isinstance(input_size, Sequence), (
+ f"Expect " f"input_size is " f"`Sequence` " f"but get {input_size}"
+ )
+
+ H, W = input_size
+ assert L == H * W, "input feature has wrong size"
+
+ x = x.view(B, H, W, C).permute([0, 3, 1, 2]) # B, C, H, W
+ # Use nn.Unfold to merge patch. About 25% faster than original method,
+ # but need to modify pretrained model for compatibility
+
+ if self.adap_padding:
+ x = self.adap_padding(x)
+ H, W = x.shape[-2:]
+
+ x = self.sampler(x)
+ # if kernel_size=2 and stride=2, x should has shape (B, 4*C, H/2*W/2)
+
+ out_h = (
+ H
+ + 2 * self.sampler.padding[0]
+ - self.sampler.dilation[0] * (self.sampler.kernel_size[0] - 1)
+ - 1
+ ) // self.sampler.stride[0] + 1
+ out_w = (
+ W
+ + 2 * self.sampler.padding[1]
+ - self.sampler.dilation[1] * (self.sampler.kernel_size[1] - 1)
+ - 1
+ ) // self.sampler.stride[1] + 1
+
+ output_size = (out_h, out_w)
+ x = x.transpose(1, 2) # B, H/2*W/2, 4*C
+ x = self.norm(x) if self.norm else x
+ x = self.reduction(x)
+ return x, output_size
+
+
+class WindowMSA(nn.Module):
+ """Window based multi-head self-attention (W-MSA) module with relative
+ position bias.
+
+ Args:
+ embed_dims (int): Number of input channels.
+ num_heads (int): Number of attention heads.
+ window_size (tuple[int]): The height and width of the window.
+ qkv_bias (bool, optional): If True, add a learnable bias to q, k, v.
+ Default: True.
+ qk_scale (float | None, optional): Override default qk scale of
+ head_dim ** -0.5 if set. Default: None.
+ attn_drop_rate (float, optional): Dropout ratio of attention weight.
+ Default: 0.0
+ proj_drop_rate (float, optional): Dropout ratio of output. Default: 0.
+ """
+
+ def __init__(
+ self,
+ embed_dims,
+ num_heads,
+ window_size,
+ qkv_bias=True,
+ qk_scale=None,
+ attn_drop_rate=0.0,
+ proj_drop_rate=0.0,
+ ):
+
+ super().__init__()
+ self.embed_dims = embed_dims
+ self.window_size = window_size # Wh, Ww
+ self.num_heads = num_heads
+ head_embed_dims = embed_dims // num_heads
+ self.scale = qk_scale or head_embed_dims**-0.5
+
+ # define a parameter table of relative position bias
+ self.relative_position_bias_table = nn.Parameter(
+ torch.zeros((2 * window_size[0] - 1) * (2 * window_size[1] - 1), num_heads)
+ ) # 2*Wh-1 * 2*Ww-1, nH
+
+ # About 2x faster than original impl
+ Wh, Ww = self.window_size
+ rel_index_coords = self.double_step_seq(2 * Ww - 1, Wh, 1, Ww)
+ rel_position_index = rel_index_coords + rel_index_coords.T
+ rel_position_index = rel_position_index.flip(1).contiguous()
+ self.register_buffer("relative_position_index", rel_position_index)
+
+ self.qkv = nn.Linear(embed_dims, embed_dims * 3, bias=qkv_bias)
+ self.attn_drop = nn.Dropout(attn_drop_rate)
+ self.proj = nn.Linear(embed_dims, embed_dims)
+ self.proj_drop = nn.Dropout(proj_drop_rate)
+
+ self.softmax = nn.Softmax(dim=-1)
+
+ def init_weights(self):
+ trunc_normal_(self.relative_position_bias_table, std=0.02)
+
+ def forward(self, x, mask=None):
+ """
+ Args:
+
+ x (tensor): input features with shape of (num_windows*B, N, C)
+ mask (tensor | None, Optional): mask with shape of (num_windows,
+ Wh*Ww, Wh*Ww), value should be between (-inf, 0].
+ """
+ B, N, C = x.shape
+ qkv = (
+ self.qkv(x)
+ .reshape(B, N, 3, self.num_heads, C // self.num_heads)
+ .permute(2, 0, 3, 1, 4)
+ )
+ # make torchscript happy (cannot use tensor as tuple)
+ q, k, v = qkv[0], qkv[1], qkv[2]
+
+ q = q * self.scale
+ attn = q @ k.transpose(-2, -1)
+
+ relative_position_bias = self.relative_position_bias_table[
+ self.relative_position_index.view(-1)
+ ].view(
+ self.window_size[0] * self.window_size[1],
+ self.window_size[0] * self.window_size[1],
+ -1,
+ ) # Wh*Ww,Wh*Ww,nH
+ relative_position_bias = relative_position_bias.permute(
+ 2, 0, 1
+ ).contiguous() # nH, Wh*Ww, Wh*Ww
+ attn = attn + relative_position_bias.unsqueeze(0)
+
+ if mask is not None:
+ nW = mask.shape[0]
+ attn = attn.view(B // nW, nW, self.num_heads, N, N) + mask.unsqueeze(
+ 1
+ ).unsqueeze(0)
+ attn = attn.view(-1, self.num_heads, N, N)
+ attn = self.softmax(attn)
+
+ attn = self.attn_drop(attn)
+
+ x = (attn @ v).transpose(1, 2).reshape(B, N, C)
+ x = self.proj(x)
+ x = self.proj_drop(x)
+ return x
+
+ @staticmethod
+ def double_step_seq(step1, len1, step2, len2):
+ seq1 = torch.arange(0, step1 * len1, step1)
+ seq2 = torch.arange(0, step2 * len2, step2)
+ return (seq1[:, None] + seq2[None, :]).reshape(1, -1)
+
+
+class ShiftWindowMSA(nn.Module):
+ """Shifted Window Multihead Self-Attention Module.
+
+ Args:
+ embed_dims (int): Number of input channels.
+ num_heads (int): Number of attention heads.
+ window_size (int): The height and width of the window.
+ shift_size (int, optional): The shift step of each window towards
+ right-bottom. If zero, act as regular window-msa. Defaults to 0.
+ qkv_bias (bool, optional): If True, add a learnable bias to q, k, v.
+ Default: True
+ qk_scale (float | None, optional): Override default qk scale of
+ head_dim ** -0.5 if set. Defaults: None.
+ attn_drop_rate (float, optional): Dropout ratio of attention weight.
+ Defaults: 0.
+ proj_drop_rate (float, optional): Dropout ratio of output.
+ Defaults: 0.
+ dropout_layer (dict, optional): The dropout_layer used before output.
+ Defaults: dict(type='DropPath', drop_prob=0.).
+ """
+
+ def __init__(
+ self,
+ embed_dims,
+ num_heads,
+ window_size,
+ shift_size=0,
+ qkv_bias=True,
+ qk_scale=None,
+ attn_drop_rate=0,
+ proj_drop_rate=0,
+ dropout_layer=dict(type="DropPath", drop_prob=0.0),
+ ):
+ super().__init__()
+
+ self.window_size = window_size
+ self.shift_size = shift_size
+ assert 0 <= self.shift_size < self.window_size
+
+ self.w_msa = WindowMSA(
+ embed_dims=embed_dims,
+ num_heads=num_heads,
+ window_size=to_2tuple(window_size),
+ qkv_bias=qkv_bias,
+ qk_scale=qk_scale,
+ attn_drop_rate=attn_drop_rate,
+ proj_drop_rate=proj_drop_rate,
+ )
+
+ self.drop = build_dropout(dropout_layer)
+
+ def forward(self, query, hw_shape):
+ B, L, C = query.shape
+ H, W = hw_shape
+ assert L == H * W, "input feature has wrong size"
+ query = query.view(B, H, W, C)
+
+ # pad feature maps to multiples of window size
+ pad_r = (self.window_size - W % self.window_size) % self.window_size
+ pad_b = (self.window_size - H % self.window_size) % self.window_size
+ query = F.pad(query, (0, 0, 0, pad_r, 0, pad_b))
+ H_pad, W_pad = query.shape[1], query.shape[2]
+
+ # cyclic shift
+ if self.shift_size > 0:
+ shifted_query = torch.roll(
+ query, shifts=(-self.shift_size, -self.shift_size), dims=(1, 2)
+ )
+
+ # calculate attention mask for SW-MSA
+ img_mask = torch.zeros((1, H_pad, W_pad, 1), device=query.device)
+ h_slices = (
+ slice(0, -self.window_size),
+ slice(-self.window_size, -self.shift_size),
+ slice(-self.shift_size, None),
+ )
+ w_slices = (
+ slice(0, -self.window_size),
+ slice(-self.window_size, -self.shift_size),
+ slice(-self.shift_size, None),
+ )
+ cnt = 0
+ for h in h_slices:
+ for w in w_slices:
+ img_mask[:, h, w, :] = cnt
+ cnt += 1
+
+ # nW, window_size, window_size, 1
+ mask_windows = self.window_partition(img_mask)
+ mask_windows = mask_windows.view(-1, self.window_size * self.window_size)
+ attn_mask = mask_windows.unsqueeze(1) - mask_windows.unsqueeze(2)
+ attn_mask = attn_mask.masked_fill(
+ attn_mask != 0, float(-100.0)
+ ).masked_fill(attn_mask == 0, float(0.0))
+ else:
+ shifted_query = query
+ attn_mask = None
+
+ # nW*B, window_size, window_size, C
+ query_windows = self.window_partition(shifted_query)
+ # nW*B, window_size*window_size, C
+ query_windows = query_windows.view(-1, self.window_size**2, C)
+
+ # W-MSA/SW-MSA (nW*B, window_size*window_size, C)
+ attn_windows = self.w_msa(query_windows, mask=attn_mask)
+
+ # merge windows
+ attn_windows = attn_windows.view(-1, self.window_size, self.window_size, C)
+
+ # B H' W' C
+ shifted_x = self.window_reverse(attn_windows, H_pad, W_pad)
+ # reverse cyclic shift
+ if self.shift_size > 0:
+ x = torch.roll(
+ shifted_x, shifts=(self.shift_size, self.shift_size), dims=(1, 2)
+ )
+ else:
+ x = shifted_x
+
+ if pad_r > 0 or pad_b:
+ x = x[:, :H, :W, :].contiguous()
+
+ x = x.view(B, H * W, C)
+
+ x = self.drop(x)
+ return x
+
+ def window_reverse(self, windows, H, W):
+ """
+ Args:
+ windows: (num_windows*B, window_size, window_size, C)
+ H (int): Height of image
+ W (int): Width of image
+ Returns:
+ x: (B, H, W, C)
+ """
+ window_size = self.window_size
+ B = int(windows.shape[0] / (H * W / window_size / window_size))
+ x = windows.view(
+ B, H // window_size, W // window_size, window_size, window_size, -1
+ )
+ x = x.permute(0, 1, 3, 2, 4, 5).contiguous().view(B, H, W, -1)
+ return x
+
+ def window_partition(self, x):
+ """
+ Args:
+ x: (B, H, W, C)
+ Returns:
+ windows: (num_windows*B, window_size, window_size, C)
+ """
+ B, H, W, C = x.shape
+ window_size = self.window_size
+ x = x.view(B, H // window_size, window_size, W // window_size, window_size, C)
+ windows = x.permute(0, 1, 3, 2, 4, 5).contiguous()
+ windows = windows.view(-1, window_size, window_size, C)
+ return windows
+
+
+class SwinBlock(nn.Module):
+ """ "
+ Args:
+ embed_dims (int): The feature dimension.
+ num_heads (int): Parallel attention heads.
+ feedforward_channels (int): The hidden dimension for FFNs.
+ window_size (int, optional): The local window scale. Default: 7.
+ shift (bool, optional): whether to shift window or not. Default False.
+ qkv_bias (bool, optional): enable bias for qkv if True. Default: True.
+ qk_scale (float | None, optional): Override default qk scale of
+ head_dim ** -0.5 if set. Default: None.
+ drop_rate (float, optional): Dropout rate. Default: 0.
+ attn_drop_rate (float, optional): Attention dropout rate. Default: 0.
+ drop_path_rate (float, optional): Stochastic depth rate. Default: 0.
+ act_cfg (dict, optional): The config dict of activation function.
+ Default: dict(type='GELU').
+ norm_cfg (dict, optional): The config dict of normalization.
+ Default: dict(type='LN').
+ with_cp (bool, optional): Use checkpoint or not. Using checkpoint
+ will save some memory while slowing down the training speed.
+ Default: False.
+ """
+
+ def __init__(
+ self,
+ embed_dims,
+ num_heads,
+ feedforward_channels,
+ window_size=7,
+ shift=False,
+ qkv_bias=True,
+ qk_scale=None,
+ drop_rate=0.0,
+ attn_drop_rate=0.0,
+ drop_path_rate=0.0,
+ act_cfg=dict(type="GELU"),
+ norm_cfg=dict(type="LN"),
+ with_cp=False,
+ ):
+
+ super(SwinBlock, self).__init__()
+
+ self.with_cp = with_cp
+
+ self.norm1 = build_norm_layer(norm_cfg, embed_dims)[1]
+ self.attn = ShiftWindowMSA(
+ embed_dims=embed_dims,
+ num_heads=num_heads,
+ window_size=window_size,
+ shift_size=window_size // 2 if shift else 0,
+ qkv_bias=qkv_bias,
+ qk_scale=qk_scale,
+ attn_drop_rate=attn_drop_rate,
+ proj_drop_rate=drop_rate,
+ dropout_layer=dict(type="DropPath", drop_prob=drop_path_rate),
+ )
+
+ self.norm2 = build_norm_layer(norm_cfg, embed_dims)[1]
+ self.ffn = FFN(
+ embed_dims=embed_dims,
+ feedforward_channels=feedforward_channels,
+ num_fcs=2,
+ ffn_drop=drop_rate,
+ dropout_layer=dict(type="DropPath", drop_prob=drop_path_rate),
+ act_cfg=act_cfg,
+ add_identity=True,
+ init_cfg=None,
+ )
+
+ def forward(self, x, hw_shape):
+
+ def _inner_forward(x):
+ identity = x
+ x = self.norm1(x)
+ x = self.attn(x, hw_shape)
+
+ x = x + identity
+
+ identity = x
+ x = self.norm2(x)
+ x = self.ffn(x, identity=identity)
+
+ return x
+
+ if self.with_cp and x.requires_grad:
+ x = cp.checkpoint(_inner_forward, x)
+ else:
+ x = _inner_forward(x)
+
+ return x
+
+
+class SwinBlockSequence(nn.Module):
+ """Implements one stage in Swin Transformer.
+
+ Args:
+ embed_dims (int): The feature dimension.
+ num_heads (int): Parallel attention heads.
+ feedforward_channels (int): The hidden dimension for FFNs.
+ depth (int): The number of blocks in this stage.
+ window_size (int, optional): The local window scale. Default: 7.
+ qkv_bias (bool, optional): enable bias for qkv if True. Default: True.
+ qk_scale (float | None, optional): Override default qk scale of
+ head_dim ** -0.5 if set. Default: None.
+ drop_rate (float, optional): Dropout rate. Default: 0.
+ attn_drop_rate (float, optional): Attention dropout rate. Default: 0.
+ drop_path_rate (float | list[float], optional): Stochastic depth
+ rate. Default: 0.
+ downsample (nn.Module | None, optional): The downsample operation
+ module. Default: None.
+ act_cfg (dict, optional): The config dict of activation function.
+ Default: dict(type='GELU').
+ norm_cfg (dict, optional): The config dict of normalization.
+ Default: dict(type='LN').
+ with_cp (bool, optional): Use checkpoint or not. Using checkpoint
+ will save some memory while slowing down the training speed.
+ Default: False.
+ """
+
+ def __init__(
+ self,
+ embed_dims,
+ num_heads,
+ feedforward_channels,
+ depth,
+ window_size=7,
+ qkv_bias=True,
+ qk_scale=None,
+ drop_rate=0.0,
+ attn_drop_rate=0.0,
+ drop_path_rate=0.0,
+ downsample=None,
+ act_cfg=dict(type="GELU"),
+ norm_cfg=dict(type="LN"),
+ with_cp=False,
+ ):
+ super().__init__()
+
+ if isinstance(drop_path_rate, list):
+ drop_path_rates = drop_path_rate
+ assert len(drop_path_rates) == depth
+ else:
+ drop_path_rates = [deepcopy(drop_path_rate) for _ in range(depth)]
+
+ self.blocks = nn.ModuleList()
+ for i in range(depth):
+ block = SwinBlock(
+ embed_dims=embed_dims,
+ num_heads=num_heads,
+ feedforward_channels=feedforward_channels,
+ window_size=window_size,
+ shift=False if i % 2 == 0 else True,
+ qkv_bias=qkv_bias,
+ qk_scale=qk_scale,
+ drop_rate=drop_rate,
+ attn_drop_rate=attn_drop_rate,
+ drop_path_rate=drop_path_rates[i],
+ act_cfg=act_cfg,
+ norm_cfg=norm_cfg,
+ with_cp=with_cp,
+ )
+ self.blocks.append(block)
+
+ self.downsample = downsample
+
+ def forward(self, x, hw_shape):
+ for block in self.blocks:
+ x = block(x, hw_shape)
+
+ if self.downsample:
+ x_down, down_hw_shape = self.downsample(x, hw_shape)
+ return x_down, down_hw_shape, x, hw_shape
+ else:
+ return x, hw_shape, x, hw_shape
+
+
+@BACKBONES.register_module()
+class SwinTransformer(BaseBackbone):
+ """Swin Transformer
+ A PyTorch implement of : `Swin Transformer:
+ Hierarchical Vision Transformer using Shifted Windows` -
+ https://arxiv.org/abs/2103.14030
+
+ Inspiration from
+ https://github.com/microsoft/Swin-Transformer
+
+ Args:
+ pretrain_img_size (int | tuple[int]): The size of input image when
+ pretrain. Defaults: 224.
+ in_channels (int): The num of input channels.
+ Defaults: 3.
+ embed_dims (int): The feature dimension. Default: 96.
+ patch_size (int | tuple[int]): Patch size. Default: 4.
+ window_size (int): Window size. Default: 7.
+ mlp_ratio (int): Ratio of mlp hidden dim to embedding dim.
+ Default: 4.
+ depths (tuple[int]): Depths of each Swin Transformer stage.
+ Default: (2, 2, 6, 2).
+ num_heads (tuple[int]): Parallel attention heads of each Swin
+ Transformer stage. Default: (3, 6, 12, 24).
+ strides (tuple[int]): The patch merging or patch embedding stride of
+ each Swin Transformer stage. (In swin, we set kernel size equal to
+ stride.) Default: (4, 2, 2, 2).
+ out_indices (tuple[int]): Output from which stages.
+ Default: (0, 1, 2, 3).
+ qkv_bias (bool, optional): If True, add a learnable bias to query, key,
+ value. Default: True
+ qk_scale (float | None, optional): Override default qk scale of
+ head_dim ** -0.5 if set. Default: None.
+ patch_norm (bool): If add a norm layer for patch embed and patch
+ merging. Default: True.
+ drop_rate (float): Dropout rate. Defaults: 0.
+ attn_drop_rate (float): Attention dropout rate. Default: 0.
+ drop_path_rate (float): Stochastic depth rate. Defaults: 0.1.
+ use_abs_pos_embed (bool): If True, add absolute position embedding to
+ the patch embedding. Defaults: False.
+ act_cfg (dict): Config dict for activation layer.
+ Default: dict(type='LN').
+ norm_cfg (dict): Config dict for normalization layer at
+ output of backone. Defaults: dict(type='LN').
+ with_cp (bool, optional): Use checkpoint or not. Using checkpoint
+ will save some memory while slowing down the training speed.
+ Default: False.
+ pretrained (str, optional): model pretrained path. Default: None.
+ convert_weights (bool): The flag indicates whether the
+ pre-trained model is from the original repo. We may need
+ to convert some keys to make it compatible.
+ Default: False.
+ frozen_stages (int): Stages to be frozen (stop grad and set eval mode).
+ Default: -1 (-1 means not freezing any parameters).
+ """
+
+ def __init__(
+ self,
+ pretrain_img_size=224,
+ in_channels=3,
+ embed_dims=96,
+ patch_size=4,
+ window_size=7,
+ mlp_ratio=4,
+ depths=(2, 2, 6, 2),
+ num_heads=(3, 6, 12, 24),
+ strides=(4, 2, 2, 2),
+ out_indices=(0, 1, 2, 3),
+ qkv_bias=True,
+ qk_scale=None,
+ patch_norm=True,
+ drop_rate=0.0,
+ attn_drop_rate=0.0,
+ drop_path_rate=0.1,
+ use_abs_pos_embed=False,
+ act_cfg=dict(type="GELU"),
+ norm_cfg=dict(type="LN"),
+ with_cp=False,
+ convert_weights=False,
+ frozen_stages=-1,
+ pretrained=None,
+ ):
+ self.convert_weights = convert_weights
+ self.pretrained = pretrained
+ self.frozen_stages = frozen_stages
+ if isinstance(pretrain_img_size, int):
+ pretrain_img_size = to_2tuple(pretrain_img_size)
+ elif isinstance(pretrain_img_size, tuple):
+ if len(pretrain_img_size) == 1:
+ pretrain_img_size = to_2tuple(pretrain_img_size[0])
+ assert len(pretrain_img_size) == 2, (
+ f"The size of image should have length 1 or 2, "
+ f"but got {len(pretrain_img_size)}"
+ )
+
+ super(SwinTransformer, self).__init__()
+
+ num_layers = len(depths)
+ self.out_indices = out_indices
+ self.use_abs_pos_embed = use_abs_pos_embed
+
+ assert strides[0] == patch_size, "Use non-overlapping patch embed."
+
+ self.patch_embed = PatchEmbed(
+ in_channels=in_channels,
+ embed_dims=embed_dims,
+ conv_type="Conv2d",
+ kernel_size=patch_size,
+ stride=strides[0],
+ norm_cfg=norm_cfg if patch_norm else None,
+ init_cfg=None,
+ )
+
+ if self.use_abs_pos_embed:
+ patch_row = pretrain_img_size[0] // patch_size
+ patch_col = pretrain_img_size[1] // patch_size
+ num_patches = patch_row * patch_col
+ self.absolute_pos_embed = nn.Parameter(
+ torch.zeros((1, num_patches, embed_dims))
+ )
+
+ self.drop_after_pos = nn.Dropout(p=drop_rate)
+
+ # set stochastic depth decay rule
+ total_depth = sum(depths)
+ dpr = [x.item() for x in torch.linspace(0, drop_path_rate, total_depth)]
+
+ self.stages = nn.ModuleList()
+ in_channels = embed_dims
+ for i in range(num_layers):
+ if i < num_layers - 1:
+ downsample = PatchMerging(
+ in_channels=in_channels,
+ out_channels=2 * in_channels,
+ stride=strides[i + 1],
+ norm_cfg=norm_cfg if patch_norm else None,
+ init_cfg=None,
+ )
+ else:
+ downsample = None
+
+ stage = SwinBlockSequence(
+ embed_dims=in_channels,
+ num_heads=num_heads[i],
+ feedforward_channels=mlp_ratio * in_channels,
+ depth=depths[i],
+ window_size=window_size,
+ qkv_bias=qkv_bias,
+ qk_scale=qk_scale,
+ drop_rate=drop_rate,
+ attn_drop_rate=attn_drop_rate,
+ drop_path_rate=dpr[sum(depths[:i]) : sum(depths[: i + 1])],
+ downsample=downsample,
+ act_cfg=act_cfg,
+ norm_cfg=norm_cfg,
+ with_cp=with_cp,
+ )
+ self.stages.append(stage)
+ if downsample:
+ in_channels = downsample.out_channels
+
+ self.num_features = [int(embed_dims * 2**i) for i in range(num_layers)]
+ # Add a norm layer for each output
+ for i in out_indices:
+ layer = build_norm_layer(norm_cfg, self.num_features[i])[1]
+ layer_name = f"norm{i}"
+ self.add_module(layer_name, layer)
+
+ def train(self, mode=True):
+ """Convert the model into training mode while keep layers freezed."""
+ super(SwinTransformer, self).train(mode)
+ self._freeze_stages()
+
+ def _freeze_stages(self):
+ if self.frozen_stages >= 0:
+ self.patch_embed.eval()
+ for param in self.patch_embed.parameters():
+ param.requires_grad = False
+ if self.use_abs_pos_embed:
+ self.absolute_pos_embed.requires_grad = False
+ self.drop_after_pos.eval()
+
+ for i in range(1, self.frozen_stages + 1):
+
+ if (i - 1) in self.out_indices:
+ norm_layer = getattr(self, f"norm{i-1}")
+ norm_layer.eval()
+ for param in norm_layer.parameters():
+ param.requires_grad = False
+
+ m = self.stages[i - 1]
+ m.eval()
+ for param in m.parameters():
+ param.requires_grad = False
+
+ def init_weights(self, pretrained=None):
+ """Initialize the weights in backbone.
+
+ Args:
+ pretrained (str, optional): Path to pre-trained weights.
+ Defaults to None.
+ """
+ if isinstance(pretrained, str):
+ logger = get_root_logger()
+ ckpt = _load_checkpoint(pretrained, logger=None, map_location="cpu")
+ if "state_dict" in ckpt:
+ _state_dict = ckpt["state_dict"]
+ elif "model" in ckpt:
+ _state_dict = ckpt["model"]
+ else:
+ _state_dict = ckpt
+ if self.convert_weights:
+ # supported loading weight from original repo,
+ _state_dict = swin_converter(_state_dict)
+
+ state_dict = OrderedDict()
+ for k, v in _state_dict.items():
+ if k.startswith("backbone."):
+ state_dict[k[9:]] = v
+
+ # strip prefix of state_dict
+ if list(state_dict.keys())[0].startswith("module."):
+ state_dict = {k[7:]: v for k, v in state_dict.items()}
+
+ # reshape absolute position embedding
+ if state_dict.get("absolute_pos_embed") is not None:
+ absolute_pos_embed = state_dict["absolute_pos_embed"]
+ N1, L, C1 = absolute_pos_embed.size()
+ N2, C2, H, W = self.absolute_pos_embed.size()
+ if N1 != N2 or C1 != C2 or L != H * W:
+ logger.warning("Error in loading absolute_pos_embed, pass")
+ else:
+ state_dict["absolute_pos_embed"] = (
+ absolute_pos_embed.view(N2, H, W, C2)
+ .permute(0, 3, 1, 2)
+ .contiguous()
+ )
+
+ # interpolate position bias table if needed
+ relative_position_bias_table_keys = [
+ k for k in state_dict.keys() if "relative_position_bias_table" in k
+ ]
+ for table_key in relative_position_bias_table_keys:
+ table_pretrained = state_dict[table_key]
+ table_current = self.state_dict()[table_key]
+ L1, nH1 = table_pretrained.size()
+ L2, nH2 = table_current.size()
+ if nH1 != nH2:
+ logger.warning(f"Error in loading {table_key}, pass")
+ elif L1 != L2:
+ S1 = int(L1**0.5)
+ S2 = int(L2**0.5)
+ table_pretrained_resized = F.interpolate(
+ table_pretrained.permute(1, 0).reshape(1, nH1, S1, S1),
+ size=(S2, S2),
+ mode="bicubic",
+ )
+ state_dict[table_key] = (
+ table_pretrained_resized.view(nH2, L2)
+ .permute(1, 0)
+ .contiguous()
+ )
+
+ # load state_dict
+ self.load_state_dict(state_dict, False)
+ elif pretrained is None:
+ if self.use_abs_pos_embed:
+ trunc_normal_(self.absolute_pos_embed, std=0.02)
+ for m in self.modules():
+ if isinstance(m, nn.Linear):
+ trunc_normal_init(m, std=0.02, bias=0.0)
+ elif isinstance(m, nn.LayerNorm):
+ constant_init(m, 1.0)
+ else:
+ raise TypeError("pretrained must be a str or None")
+
+ def forward(self, x):
+ x, hw_shape = self.patch_embed(x)
+
+ if self.use_abs_pos_embed:
+ x = x + self.absolute_pos_embed
+ x = self.drop_after_pos(x)
+
+ outs = []
+ for i, stage in enumerate(self.stages):
+ x, hw_shape, out, out_hw_shape = stage(x, hw_shape)
+ if i in self.out_indices:
+ norm_layer = getattr(self, f"norm{i}")
+ out = norm_layer(out)
+ out = (
+ out.view(-1, *out_hw_shape, self.num_features[i])
+ .permute(0, 3, 1, 2)
+ .contiguous()
+ )
+ outs.append(out)
+
+ res = {}
+ B, C, Hp, Wp = outs[3].shape
+ res["cls"] = torch.mean(
+ rearrange(outs[3], "b c h w -> b c (h w)", h=Hp, w=Wp), -1, False
+ )
+ res["embed"] = outs[3]
+
+ return res
+
+
+if __name__ == "__main__":
+ model = SwinTransformer(
+ embed_dims=128,
+ depths=[2, 2, 18, 2],
+ num_heads=[4, 8, 16, 32],
+ window_size=7,
+ mlp_ratio=4,
+ qkv_bias=True,
+ qk_scale=None,
+ drop_rate=0.0,
+ attn_drop_rate=0.0,
+ drop_path_rate=0.3,
+ patch_norm=True,
+ out_indices=(0, 1, 2, 3),
+ with_cp=False,
+ convert_weights=True,
+ )
+ inputs = torch.randn(1, 3, 224, 224)
+ outputs = model(inputs)
+ pretrained_weights = "pretrained/swin_base_patch4_window7_224_22k.pth"
+ print(f"Loading pretrained from --- {pretrained_weights}")
+ model.init_weights(pretrained=pretrained_weights)
+
+ for i in range(len(outputs)):
+ print(f"Output length --- {len(outputs)}, Output shape --- {outputs[i].shape}")
diff --git a/clean/video/fakestormer/models/networks/backbones/swin3d.py b/clean/video/fakestormer/models/networks/backbones/swin3d.py
new file mode 100644
index 0000000000000000000000000000000000000000..70b56e2171f0955c4869dc718184b41a569355bb
--- /dev/null
+++ b/clean/video/fakestormer/models/networks/backbones/swin3d.py
@@ -0,0 +1,877 @@
+# -*- coding:utf-8 -*-
+import os
+import sys
+
+if not os.getcwd() in sys.path:
+ sys.path.append(os.getcwd())
+from functools import lru_cache, reduce
+from operator import mul
+
+import numpy as np
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+import torch.utils.checkpoint as checkpoint
+from einops import rearrange
+from logs.logger import get_root_logger
+from mmcv.cnn import build_norm_layer
+from mmcv.runner import _load_checkpoint as load_checkpoint
+from timm.models.layers import DropPath, trunc_normal_
+
+from ...builder import BACKBONES
+from .base import BaseBackbone
+
+
+class Mlp(nn.Module):
+ """Multilayer perceptron."""
+
+ def __init__(
+ self,
+ in_features,
+ hidden_features=None,
+ out_features=None,
+ act_layer=nn.GELU,
+ drop=0.0,
+ ):
+ super().__init__()
+ out_features = out_features or in_features
+ hidden_features = hidden_features or in_features
+ self.fc1 = nn.Linear(in_features, hidden_features)
+ self.act = act_layer()
+ self.fc2 = nn.Linear(hidden_features, out_features)
+ self.drop = nn.Dropout(drop)
+
+ def forward(self, x):
+ x = self.fc1(x)
+ x = self.act(x)
+ x = self.drop(x)
+ x = self.fc2(x)
+ x = self.drop(x)
+ return x
+
+
+def window_partition(x, window_size):
+ """
+ Args:
+ x: (B, D, H, W, C)
+ window_size (tuple[int]): window size
+
+ Returns:
+ windows: (B*num_windows, window_size*window_size, C)
+ """
+ B, D, H, W, C = x.shape
+ x = x.view(
+ B,
+ D // window_size[0],
+ window_size[0],
+ H // window_size[1],
+ window_size[1],
+ W // window_size[2],
+ window_size[2],
+ C,
+ )
+ windows = (
+ x.permute(0, 1, 3, 5, 2, 4, 6, 7)
+ .contiguous()
+ .view(-1, reduce(mul, window_size), C)
+ )
+ return windows
+
+
+def window_reverse(windows, window_size, B, D, H, W):
+ """
+ Args:
+ windows: (B*num_windows, window_size, window_size, C)
+ window_size (tuple[int]): Window size
+ H (int): Height of image
+ W (int): Width of image
+
+ Returns:
+ x: (B, D, H, W, C)
+ """
+ x = windows.view(
+ B,
+ D // window_size[0],
+ H // window_size[1],
+ W // window_size[2],
+ window_size[0],
+ window_size[1],
+ window_size[2],
+ -1,
+ )
+ x = x.permute(0, 1, 4, 2, 5, 3, 6, 7).contiguous().view(B, D, H, W, -1)
+ return x
+
+
+def get_window_size(x_size, window_size, shift_size=None):
+ use_window_size = list(window_size)
+ if shift_size is not None:
+ use_shift_size = list(shift_size)
+ for i in range(len(x_size)):
+ if x_size[i] <= window_size[i]:
+ use_window_size[i] = x_size[i]
+ if shift_size is not None:
+ use_shift_size[i] = 0
+
+ if shift_size is None:
+ return tuple(use_window_size)
+ else:
+ return tuple(use_window_size), tuple(use_shift_size)
+
+
+class WindowAttention3D(nn.Module):
+ """Window based multi-head self attention (W-MSA) module with relative position bias.
+ It supports both of shifted and non-shifted window.
+ Args:
+ dim (int): Number of input channels.
+ window_size (tuple[int]): The temporal length, height and width of the window.
+ num_heads (int): Number of attention heads.
+ qkv_bias (bool, optional): If True, add a learnable bias to query, key, value. Default: True
+ qk_scale (float | None, optional): Override default qk scale of head_dim ** -0.5 if set
+ attn_drop (float, optional): Dropout ratio of attention weight. Default: 0.0
+ proj_drop (float, optional): Dropout ratio of output. Default: 0.0
+ """
+
+ def __init__(
+ self,
+ dim,
+ window_size,
+ num_heads,
+ qkv_bias=False,
+ qk_scale=None,
+ attn_drop=0.0,
+ proj_drop=0.0,
+ ):
+
+ super().__init__()
+ self.dim = dim
+ self.window_size = window_size # Wd, Wh, Ww
+ self.num_heads = num_heads
+ head_dim = dim // num_heads
+ self.scale = qk_scale or head_dim**-0.5
+
+ # define a parameter table of relative position bias
+ self.relative_position_bias_table = nn.Parameter(
+ torch.zeros(
+ (2 * window_size[0] - 1)
+ * (2 * window_size[1] - 1)
+ * (2 * window_size[2] - 1),
+ num_heads,
+ )
+ ) # 2*Wd-1 * 2*Wh-1 * 2*Ww-1, nH
+
+ # get pair-wise relative position index for each token inside the window
+ coords_d = torch.arange(self.window_size[0])
+ coords_h = torch.arange(self.window_size[1])
+ coords_w = torch.arange(self.window_size[2])
+ coords = torch.stack(
+ torch.meshgrid(coords_d, coords_h, coords_w)
+ ) # 3, Wd, Wh, Ww
+ coords_flatten = torch.flatten(coords, 1) # 3, Wd*Wh*Ww
+ relative_coords = (
+ coords_flatten[:, :, None] - coords_flatten[:, None, :]
+ ) # 3, Wd*Wh*Ww, Wd*Wh*Ww
+ relative_coords = relative_coords.permute(
+ 1, 2, 0
+ ).contiguous() # Wd*Wh*Ww, Wd*Wh*Ww, 3
+ relative_coords[:, :, 0] += self.window_size[0] - 1 # shift to start from 0
+ relative_coords[:, :, 1] += self.window_size[1] - 1
+ relative_coords[:, :, 2] += self.window_size[2] - 1
+
+ relative_coords[:, :, 0] *= (2 * self.window_size[1] - 1) * (
+ 2 * self.window_size[2] - 1
+ )
+ relative_coords[:, :, 1] *= 2 * self.window_size[2] - 1
+ relative_position_index = relative_coords.sum(-1) # Wd*Wh*Ww, Wd*Wh*Ww
+ self.register_buffer("relative_position_index", relative_position_index)
+
+ self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)
+ self.attn_drop = nn.Dropout(attn_drop)
+ self.proj = nn.Linear(dim, dim)
+ self.proj_drop = nn.Dropout(proj_drop)
+
+ trunc_normal_(self.relative_position_bias_table, std=0.02)
+ self.softmax = nn.Softmax(dim=-1)
+
+ def forward(self, x, mask=None):
+ """Forward function.
+ Args:
+ x: input features with shape of (num_windows*B, N, C)
+ mask: (0/-inf) mask with shape of (num_windows, N, N) or None
+ """
+ B_, N, C = x.shape
+ qkv = (
+ self.qkv(x)
+ .reshape(B_, N, 3, self.num_heads, C // self.num_heads)
+ .permute(2, 0, 3, 1, 4)
+ )
+ q, k, v = qkv[0], qkv[1], qkv[2] # B_, nH, N, C
+
+ q = q * self.scale
+ attn = q @ k.transpose(-2, -1)
+
+ relative_position_bias = self.relative_position_bias_table[
+ self.relative_position_index[:N, :N].reshape(-1)
+ ].reshape(
+ N, N, -1
+ ) # Wd*Wh*Ww,Wd*Wh*Ww,nH
+ relative_position_bias = relative_position_bias.permute(
+ 2, 0, 1
+ ).contiguous() # nH, Wd*Wh*Ww, Wd*Wh*Ww
+ attn = attn + relative_position_bias.unsqueeze(0) # B_, nH, N, N
+
+ if mask is not None:
+ nW = mask.shape[0]
+ attn = attn.view(B_ // nW, nW, self.num_heads, N, N) + mask.unsqueeze(
+ 1
+ ).unsqueeze(0)
+ attn = attn.view(-1, self.num_heads, N, N)
+ attn = self.softmax(attn)
+ else:
+ attn = self.softmax(attn)
+
+ attn = self.attn_drop(attn)
+
+ x = (attn @ v).transpose(1, 2).reshape(B_, N, C)
+ x = self.proj(x)
+ x = self.proj_drop(x)
+ return x
+
+
+class SwinTransformerBlock3D(nn.Module):
+ """Swin Transformer Block.
+
+ Args:
+ dim (int): Number of input channels.
+ num_heads (int): Number of attention heads.
+ window_size (tuple[int]): Window size.
+ shift_size (tuple[int]): Shift size for SW-MSA.
+ mlp_ratio (float): Ratio of mlp hidden dim to embedding dim.
+ qkv_bias (bool, optional): If True, add a learnable bias to query, key, value. Default: True
+ qk_scale (float | None, optional): Override default qk scale of head_dim ** -0.5 if set.
+ drop (float, optional): Dropout rate. Default: 0.0
+ attn_drop (float, optional): Attention dropout rate. Default: 0.0
+ drop_path (float, optional): Stochastic depth rate. Default: 0.0
+ act_layer (nn.Module, optional): Activation layer. Default: nn.GELU
+ norm_layer (nn.Module, optional): Normalization layer. Default: nn.LayerNorm
+ """
+
+ def __init__(
+ self,
+ dim,
+ num_heads,
+ window_size=(2, 7, 7),
+ shift_size=(0, 0, 0),
+ mlp_ratio=4.0,
+ qkv_bias=True,
+ qk_scale=None,
+ drop=0.0,
+ attn_drop=0.0,
+ drop_path=0.0,
+ act_layer=nn.GELU,
+ norm_layer=nn.LayerNorm,
+ use_checkpoint=False,
+ ):
+ super().__init__()
+ self.dim = dim
+ self.num_heads = num_heads
+ self.window_size = window_size
+ self.shift_size = shift_size
+ self.mlp_ratio = mlp_ratio
+ self.use_checkpoint = use_checkpoint
+
+ assert (
+ 0 <= self.shift_size[0] < self.window_size[0]
+ ), "shift_size must in 0-window_size"
+ assert (
+ 0 <= self.shift_size[1] < self.window_size[1]
+ ), "shift_size must in 0-window_size"
+ assert (
+ 0 <= self.shift_size[2] < self.window_size[2]
+ ), "shift_size must in 0-window_size"
+
+ self.norm1 = norm_layer(dim)
+ self.attn = WindowAttention3D(
+ dim,
+ window_size=self.window_size,
+ num_heads=num_heads,
+ qkv_bias=qkv_bias,
+ qk_scale=qk_scale,
+ attn_drop=attn_drop,
+ proj_drop=drop,
+ )
+
+ self.drop_path = DropPath(drop_path) if drop_path > 0.0 else nn.Identity()
+ self.norm2 = norm_layer(dim)
+ mlp_hidden_dim = int(dim * mlp_ratio)
+ self.mlp = Mlp(
+ in_features=dim,
+ hidden_features=mlp_hidden_dim,
+ act_layer=act_layer,
+ drop=drop,
+ )
+
+ def forward_part1(self, x, mask_matrix):
+ B, D, H, W, C = x.shape
+ window_size, shift_size = get_window_size(
+ (D, H, W), self.window_size, self.shift_size
+ )
+
+ x = self.norm1(x)
+ # pad feature maps to multiples of window size
+ pad_l = pad_t = pad_d0 = 0
+ pad_d1 = (window_size[0] - D % window_size[0]) % window_size[0]
+ pad_b = (window_size[1] - H % window_size[1]) % window_size[1]
+ pad_r = (window_size[2] - W % window_size[2]) % window_size[2]
+ x = F.pad(x, (0, 0, pad_l, pad_r, pad_t, pad_b, pad_d0, pad_d1))
+ _, Dp, Hp, Wp, _ = x.shape
+ # cyclic shift
+ if any(i > 0 for i in shift_size):
+ shifted_x = torch.roll(
+ x,
+ shifts=(-shift_size[0], -shift_size[1], -shift_size[2]),
+ dims=(1, 2, 3),
+ )
+ attn_mask = mask_matrix
+ else:
+ shifted_x = x
+ attn_mask = None
+ # partition windows
+ x_windows = window_partition(shifted_x, window_size) # B*nW, Wd*Wh*Ww, C
+ # W-MSA/SW-MSA
+ attn_windows = self.attn(x_windows, mask=attn_mask) # B*nW, Wd*Wh*Ww, C
+ # merge windows
+ attn_windows = attn_windows.view(-1, *(window_size + (C,)))
+ shifted_x = window_reverse(
+ attn_windows, window_size, B, Dp, Hp, Wp
+ ) # B D' H' W' C
+ # reverse cyclic shift
+ if any(i > 0 for i in shift_size):
+ x = torch.roll(
+ shifted_x,
+ shifts=(shift_size[0], shift_size[1], shift_size[2]),
+ dims=(1, 2, 3),
+ )
+ else:
+ x = shifted_x
+
+ if pad_d1 > 0 or pad_r > 0 or pad_b > 0:
+ x = x[:, :D, :H, :W, :].contiguous()
+ return x
+
+ def forward_part2(self, x):
+ return self.drop_path(self.mlp(self.norm2(x)))
+
+ def forward(self, x, mask_matrix):
+ """Forward function.
+
+ Args:
+ x: Input feature, tensor size (B, D, H, W, C).
+ mask_matrix: Attention mask for cyclic shift.
+ """
+
+ shortcut = x
+ if self.use_checkpoint:
+ x = checkpoint.checkpoint(self.forward_part1, x, mask_matrix)
+ else:
+ x = self.forward_part1(x, mask_matrix)
+ x = shortcut + self.drop_path(x)
+
+ if self.use_checkpoint:
+ x = x + checkpoint.checkpoint(self.forward_part2, x)
+ else:
+ x = x + self.forward_part2(x)
+
+ return x
+
+
+class PatchMerging(nn.Module):
+ """Patch Merging Layer
+
+ Args:
+ dim (int): Number of input channels.
+ norm_layer (nn.Module, optional): Normalization layer. Default: nn.LayerNorm
+ """
+
+ def __init__(self, dim, norm_layer=nn.LayerNorm):
+ super().__init__()
+ self.dim = dim
+ self.reduction = nn.Linear(4 * dim, 2 * dim, bias=False)
+ self.norm = norm_layer(4 * dim)
+
+ def forward(self, x):
+ """Forward function.
+
+ Args:
+ x: Input feature, tensor size (B, D, H, W, C).
+ """
+ B, D, H, W, C = x.shape
+
+ # padding
+ pad_input = (H % 2 == 1) or (W % 2 == 1)
+ if pad_input:
+ x = F.pad(x, (0, 0, 0, W % 2, 0, H % 2))
+
+ x0 = x[:, :, 0::2, 0::2, :] # B D H/2 W/2 C
+ x1 = x[:, :, 1::2, 0::2, :] # B D H/2 W/2 C
+ x2 = x[:, :, 0::2, 1::2, :] # B D H/2 W/2 C
+ x3 = x[:, :, 1::2, 1::2, :] # B D H/2 W/2 C
+ x = torch.cat([x0, x1, x2, x3], -1) # B D H/2 W/2 4*C
+
+ x = self.norm(x)
+ x = self.reduction(x)
+
+ return x
+
+
+# cache each stage results
+@lru_cache()
+def compute_mask(D, H, W, window_size, shift_size, device):
+ img_mask = torch.zeros((1, D, H, W, 1), device=device) # 1 Dp Hp Wp 1
+ cnt = 0
+ for d in (
+ slice(-window_size[0]),
+ slice(-window_size[0], -shift_size[0]),
+ slice(-shift_size[0], None),
+ ):
+ for h in (
+ slice(-window_size[1]),
+ slice(-window_size[1], -shift_size[1]),
+ slice(-shift_size[1], None),
+ ):
+ for w in (
+ slice(-window_size[2]),
+ slice(-window_size[2], -shift_size[2]),
+ slice(-shift_size[2], None),
+ ):
+ img_mask[:, d, h, w, :] = cnt
+ cnt += 1
+ mask_windows = window_partition(img_mask, window_size) # nW, ws[0]*ws[1]*ws[2], 1
+ mask_windows = mask_windows.squeeze(-1) # nW, ws[0]*ws[1]*ws[2]
+ attn_mask = mask_windows.unsqueeze(1) - mask_windows.unsqueeze(2)
+ attn_mask = attn_mask.masked_fill(attn_mask != 0, float(-100.0)).masked_fill(
+ attn_mask == 0, float(0.0)
+ )
+ return attn_mask
+
+
+class BasicLayer(nn.Module):
+ """A basic Swin Transformer layer for one stage.
+
+ Args:
+ dim (int): Number of feature channels
+ depth (int): Depths of this stage.
+ num_heads (int): Number of attention head.
+ window_size (tuple[int]): Local window size. Default: (1,7,7).
+ mlp_ratio (float): Ratio of mlp hidden dim to embedding dim. Default: 4.
+ qkv_bias (bool, optional): If True, add a learnable bias to query, key, value. Default: True
+ qk_scale (float | None, optional): Override default qk scale of head_dim ** -0.5 if set.
+ drop (float, optional): Dropout rate. Default: 0.0
+ attn_drop (float, optional): Attention dropout rate. Default: 0.0
+ drop_path (float | tuple[float], optional): Stochastic depth rate. Default: 0.0
+ norm_layer (nn.Module, optional): Normalization layer. Default: nn.LayerNorm
+ downsample (nn.Module | None, optional): Downsample layer at the end of the layer. Default: None
+ """
+
+ def __init__(
+ self,
+ dim,
+ depth,
+ num_heads,
+ window_size=(1, 7, 7),
+ mlp_ratio=4.0,
+ qkv_bias=False,
+ qk_scale=None,
+ drop=0.0,
+ attn_drop=0.0,
+ drop_path=0.0,
+ norm_layer=nn.LayerNorm,
+ downsample=None,
+ use_checkpoint=False,
+ ):
+ super().__init__()
+ self.window_size = window_size
+ self.shift_size = tuple(i // 2 for i in window_size)
+ self.depth = depth
+ self.use_checkpoint = use_checkpoint
+
+ # build blocks
+ self.blocks = nn.ModuleList(
+ [
+ SwinTransformerBlock3D(
+ dim=dim,
+ num_heads=num_heads,
+ window_size=window_size,
+ shift_size=(0, 0, 0) if (i % 2 == 0) else self.shift_size,
+ mlp_ratio=mlp_ratio,
+ qkv_bias=qkv_bias,
+ qk_scale=qk_scale,
+ drop=drop,
+ attn_drop=attn_drop,
+ drop_path=(
+ drop_path[i] if isinstance(drop_path, list) else drop_path
+ ),
+ norm_layer=norm_layer,
+ use_checkpoint=use_checkpoint,
+ )
+ for i in range(depth)
+ ]
+ )
+
+ self.downsample = downsample
+ if self.downsample is not None:
+ self.downsample = downsample(dim=dim, norm_layer=norm_layer)
+
+ def forward(self, x):
+ """Forward function.
+
+ Args:
+ x: Input feature, tensor size (B, C, D, H, W).
+ """
+ # calculate attention mask for SW-MSA
+ B, C, D, H, W = x.shape
+ window_size, shift_size = get_window_size(
+ (D, H, W), self.window_size, self.shift_size
+ )
+ x = rearrange(x, "b c d h w -> b d h w c")
+ Dp = int(np.ceil(D / window_size[0])) * window_size[0]
+ Hp = int(np.ceil(H / window_size[1])) * window_size[1]
+ Wp = int(np.ceil(W / window_size[2])) * window_size[2]
+ attn_mask = compute_mask(Dp, Hp, Wp, window_size, shift_size, x.device)
+ for blk in self.blocks:
+ x = blk(x, attn_mask)
+ x = x.view(B, D, H, W, -1)
+
+ if self.downsample is not None:
+ x = self.downsample(x)
+ x = rearrange(x, "b d h w c -> b c d h w")
+ return x
+
+
+class PatchEmbed3D(nn.Module):
+ """Video to Patch Embedding.
+
+ Args:
+ patch_size (int): Patch token size. Default: (2,4,4).
+ in_chans (int): Number of input video channels. Default: 3.
+ embed_dim (int): Number of linear projection output channels. Default: 96.
+ norm_layer (nn.Module, optional): Normalization layer. Default: None
+ """
+
+ def __init__(self, patch_size=(2, 4, 4), in_chans=3, embed_dim=96, norm_layer=None):
+ super().__init__()
+ self.patch_size = patch_size
+
+ self.in_chans = in_chans
+ self.embed_dim = embed_dim
+
+ self.proj = nn.Conv3d(
+ in_chans, embed_dim, kernel_size=patch_size, stride=patch_size
+ )
+ if norm_layer is not None:
+ self.norm = norm_layer(embed_dim)
+ else:
+ self.norm = None
+
+ def forward(self, x):
+ """Forward function."""
+ # padding
+ _, _, D, H, W = x.size()
+ if W % self.patch_size[2] != 0:
+ x = F.pad(x, (0, self.patch_size[2] - W % self.patch_size[2]))
+ if H % self.patch_size[1] != 0:
+ x = F.pad(x, (0, 0, 0, self.patch_size[1] - H % self.patch_size[1]))
+ if D % self.patch_size[0] != 0:
+ x = F.pad(x, (0, 0, 0, 0, 0, self.patch_size[0] - D % self.patch_size[0]))
+
+ x = self.proj(x) # B C D Wh Ww
+ if self.norm is not None:
+ D, Wh, Ww = x.size(2), x.size(3), x.size(4)
+ x = x.flatten(2).transpose(1, 2)
+ x = self.norm(x)
+ x = x.transpose(1, 2).view(-1, self.embed_dim, D, Wh, Ww)
+
+ return x
+
+
+@BACKBONES.register_module()
+class SwinTransformer3D(BaseBackbone):
+ """Swin Transformer backbone.
+ A PyTorch impl of : `Swin Transformer: Hierarchical Vision Transformer using Shifted Windows` -
+ https://arxiv.org/pdf/2103.14030
+
+ Args:
+ patch_size (int | tuple(int)): Patch size. Default: (4,4,4).
+ in_chans (int): Number of input image channels. Default: 3.
+ embed_dim (int): Number of linear projection output channels. Default: 96.
+ depths (tuple[int]): Depths of each Swin Transformer stage.
+ num_heads (tuple[int]): Number of attention head of each stage.
+ window_size (int): Window size. Default: 7.
+ mlp_ratio (float): Ratio of mlp hidden dim to embedding dim. Default: 4.
+ qkv_bias (bool): If True, add a learnable bias to query, key, value. Default: Truee
+ qk_scale (float): Override default qk scale of head_dim ** -0.5 if set.
+ drop_rate (float): Dropout rate.
+ attn_drop_rate (float): Attention dropout rate. Default: 0.
+ drop_path_rate (float): Stochastic depth rate. Default: 0.2.
+ norm_layer: Normalization layer. Default: nn.LayerNorm.
+ patch_norm (bool): If True, add normalization after patch embedding. Default: False.
+ frozen_stages (int): Stages to be frozen (stop grad and set eval mode).
+ -1 means not freezing any parameters.
+ """
+
+ def __init__(
+ self,
+ pretrained=None,
+ pretrained2d=True,
+ patch_size=(4, 4, 4),
+ in_chans=3,
+ embed_dim=96,
+ depths=[2, 2, 6, 2],
+ num_heads=[3, 6, 12, 24],
+ window_size=(2, 7, 7),
+ out_indices=(0, 1, 2, 3),
+ mlp_ratio=4.0,
+ qkv_bias=True,
+ qk_scale=None,
+ drop_rate=0.0,
+ attn_drop_rate=0.0,
+ drop_path_rate=0.2,
+ norm_layer=nn.LayerNorm,
+ norm_cfg=dict(type="LN"),
+ patch_norm=False,
+ frozen_stages=-1,
+ use_checkpoint=False,
+ ):
+ super(SwinTransformer3D, self).__init__()
+
+ self.pretrained = pretrained
+ self.pretrained2d = pretrained2d
+ self.num_layers = len(depths)
+ self.embed_dim = embed_dim
+ self.patch_norm = patch_norm
+ self.frozen_stages = frozen_stages
+ self.window_size = window_size
+ self.patch_size = patch_size
+
+ # split image into non-overlapping patches
+ self.patch_embed = PatchEmbed3D(
+ patch_size=patch_size,
+ in_chans=in_chans,
+ embed_dim=embed_dim,
+ norm_layer=norm_layer if self.patch_norm else None,
+ )
+
+ self.pos_drop = nn.Dropout(p=drop_rate)
+
+ # stochastic depth
+ dpr = [
+ x.item() for x in torch.linspace(0, drop_path_rate, sum(depths))
+ ] # stochastic depth decay rule
+
+ # build layers
+ self.layers = nn.ModuleList()
+ for i_layer in range(self.num_layers):
+ layer = BasicLayer(
+ dim=int(embed_dim * 2**i_layer),
+ depth=depths[i_layer],
+ num_heads=num_heads[i_layer],
+ window_size=window_size,
+ mlp_ratio=mlp_ratio,
+ qkv_bias=qkv_bias,
+ qk_scale=qk_scale,
+ drop=drop_rate,
+ attn_drop=attn_drop_rate,
+ drop_path=dpr[sum(depths[:i_layer]) : sum(depths[: i_layer + 1])],
+ norm_layer=norm_layer,
+ downsample=PatchMerging if i_layer < self.num_layers - 1 else None,
+ use_checkpoint=use_checkpoint,
+ )
+ self.layers.append(layer)
+
+ self.num_features = [int(embed_dim * 2**i) for i in range(self.num_layers)]
+
+ # Add a norm layer for each output
+ for i in out_indices:
+ layer = build_norm_layer(norm_cfg, self.num_features[i])[1]
+ layer_name = f"norm{i}"
+ self.add_module(layer_name, layer)
+
+ def _freeze_stages(self):
+ if self.frozen_stages >= 0:
+ self.patch_embed.eval()
+ for param in self.patch_embed.parameters():
+ param.requires_grad = False
+
+ if self.frozen_stages >= 1:
+ self.pos_drop.eval()
+ for i in range(0, self.frozen_stages):
+ m = self.layers[i]
+ m.eval()
+ for param in m.parameters():
+ param.requires_grad = False
+
+ def inflate_weights(self, logger):
+ """Inflate the swin2d parameters to swin3d.
+
+ The differences between swin3d and swin2d mainly lie in an extra
+ axis. To utilize the pretrained parameters in 2d model,
+ the weight of swin2d models should be inflated to fit in the shapes of
+ the 3d counterpart.
+
+ Args:
+ logger (logging.Logger): The logger used to print
+ debugging infomation.
+ """
+ checkpoint = torch.load(self.pretrained, map_location="cpu")
+ state_dict = checkpoint["model"]
+
+ # delete relative_position_index since we always re-init it
+ relative_position_index_keys = [
+ k for k in state_dict.keys() if "relative_position_index" in k
+ ]
+ for k in relative_position_index_keys:
+ del state_dict[k]
+
+ # delete attn_mask since we always re-init it
+ attn_mask_keys = [k for k in state_dict.keys() if "attn_mask" in k]
+ for k in attn_mask_keys:
+ del state_dict[k]
+
+ state_dict["patch_embed.proj.weight"] = (
+ state_dict["patch_embed.proj.weight"]
+ .unsqueeze(2)
+ .repeat(1, 1, self.patch_size[0], 1, 1)
+ / self.patch_size[0]
+ )
+
+ # bicubic interpolate relative_position_bias_table if not match
+ relative_position_bias_table_keys = [
+ k for k in state_dict.keys() if "relative_position_bias_table" in k
+ ]
+ for k in relative_position_bias_table_keys:
+ relative_position_bias_table_pretrained = state_dict[k]
+ relative_position_bias_table_current = self.state_dict()[k]
+ L1, nH1 = relative_position_bias_table_pretrained.size()
+ L2, nH2 = relative_position_bias_table_current.size()
+ L2 = (2 * self.window_size[1] - 1) * (2 * self.window_size[2] - 1)
+ wd = self.window_size[0]
+ if nH1 != nH2:
+ logger.warning(f"Error in loading {k}, passing")
+ else:
+ if L1 != L2:
+ S1 = int(L1**0.5)
+ relative_position_bias_table_pretrained_resized = (
+ torch.nn.functional.interpolate(
+ relative_position_bias_table_pretrained.permute(1, 0).view(
+ 1, nH1, S1, S1
+ ),
+ size=(
+ 2 * self.window_size[1] - 1,
+ 2 * self.window_size[2] - 1,
+ ),
+ mode="bicubic",
+ )
+ )
+ relative_position_bias_table_pretrained = (
+ relative_position_bias_table_pretrained_resized.view(
+ nH2, L2
+ ).permute(1, 0)
+ )
+ state_dict[k] = relative_position_bias_table_pretrained.repeat(
+ 2 * wd - 1, 1
+ )
+
+ msg = self.load_state_dict(state_dict, strict=False)
+ logger.info(msg)
+ logger.info(f"=> loaded successfully '{self.pretrained}'")
+ del checkpoint
+ torch.cuda.empty_cache()
+
+ def init_weights(self, pretrained=None):
+ """Initialize the weights in backbone.
+
+ Args:
+ pretrained (str, optional): Path to pre-trained weights.
+ Defaults to None.
+ """
+
+ def _init_weights(m):
+ if isinstance(m, nn.Linear):
+ trunc_normal_(m.weight, std=0.02)
+ if isinstance(m, nn.Linear) and m.bias is not None:
+ nn.init.constant_(m.bias, 0)
+ elif isinstance(m, nn.LayerNorm):
+ nn.init.constant_(m.bias, 0)
+ nn.init.constant_(m.weight, 1.0)
+
+ if pretrained:
+ self.pretrained = pretrained
+ if isinstance(self.pretrained, str):
+ self.apply(_init_weights)
+ logger = get_root_logger()
+ logger.info(f"load model from: {self.pretrained}")
+
+ if self.pretrained2d:
+ # Inflate 2D model into 3D model.
+ self.inflate_weights(logger)
+ else:
+ # Directly load 3D model.
+ load_checkpoint(self, self.pretrained, strict=False, logger=logger)
+ elif self.pretrained is None:
+ self.apply(_init_weights)
+ else:
+ raise TypeError("pretrained must be a str or None")
+
+ def forward(self, x):
+ """Forward function."""
+ x = self.patch_embed(x)
+
+ x = self.pos_drop(x)
+
+ outputs = []
+ for i, layer in enumerate(self.layers):
+ x = layer(x.contiguous())
+ x = rearrange(x, "n c d h w -> n d h w c")
+ if i == len(self.layers) - 1:
+ norm_layer = getattr(self, f"norm{i}")
+ else:
+ norm_layer = getattr(self, f"norm{i+1}")
+ x = norm_layer(x)
+ x = rearrange(x, "n d h w c -> n c d h w")
+ outputs.append(x)
+
+ res = {}
+ res["embed"] = x
+ res["outputs"] = outputs
+
+ return res
+
+ def train(self, mode=True):
+ """Convert the model into training mode while keep layers freezed."""
+ super(SwinTransformer3D, self).train(mode)
+ self._freeze_stages()
+
+
+if __name__ == "__main__":
+ model = SwinTransformer3D(
+ embed_dim=128,
+ patch_size=(4, 4, 4),
+ depths=[2, 2, 18, 2],
+ num_heads=[4, 8, 16, 32],
+ window_size=(8, 7, 7),
+ mlp_ratio=4,
+ qkv_bias=True,
+ qk_scale=None,
+ drop_rate=0.0,
+ attn_drop_rate=0.0,
+ drop_path_rate=0.2,
+ patch_norm=True,
+ )
+ inputs = torch.randn(1, 3, 32, 224, 224)
+ outputs = model(inputs)
+ pretrained_weights = "pretrained/swin_base_patch4_window7_224_22k.pth"
+ print(f"Loading pretrained from --- {pretrained_weights}")
+ model.init_weights(pretrained=pretrained_weights)
+
+ for k, v in outputs.items():
+ print(f"Output length --- {len(outputs)}, Output shape --- {outputs[k].shape}")
diff --git a/clean/video/fakestormer/models/networks/backbones/vit.py b/clean/video/fakestormer/models/networks/backbones/vit.py
new file mode 100644
index 0000000000000000000000000000000000000000..40fa725b365eb93d5abf26143a722b2c051c831c
--- /dev/null
+++ b/clean/video/fakestormer/models/networks/backbones/vit.py
@@ -0,0 +1,1271 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) OpenMMLab. All rights reserved.
+import math
+from functools import partial
+from typing import Dict, Union
+
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+import torch.utils.checkpoint as checkpoint
+from einops import rearrange, reduce, repeat
+from models.builder import BACKBONES
+from timm.models.layers import drop_path, to_2tuple, trunc_normal_
+
+from ..common import BN3D_MOMENTUM
+from ..pose_efficientNet import EfficientNet
+from .base import BaseBackbone
+from .efficientNet import get_model_params
+
+
+def get_abs_pos(abs_pos, h, w, ori_h, ori_w, has_cls_token=True):
+ """
+ Calculate absolute positional embeddings. If needed, resize embeddings and remove cls_token
+ dimension for the original embeddings.
+ Args:
+ abs_pos (Tensor): absolute positional embeddings with (1, num_position, C).
+ has_cls_token (bool): If true, has 1 embedding in abs_pos for cls token.
+ hw (Tuple): size of input image tokens.
+
+ Returns:
+ Absolute positional embeddings after processing with shape (1, H, W, C)
+ """
+ cls_token = None
+ B, L, C = abs_pos.shape
+ if has_cls_token:
+ cls_token = abs_pos[:, 0:1]
+ abs_pos = abs_pos[:, 1:]
+
+ if ori_h != h or ori_w != w:
+ new_abs_pos = (
+ F.interpolate(
+ abs_pos.reshape(1, ori_h, ori_w, -1).permute(0, 3, 1, 2),
+ size=(h, w),
+ mode="bicubic",
+ align_corners=False,
+ )
+ .permute(0, 2, 3, 1)
+ .reshape(B, -1, C)
+ )
+
+ else:
+ new_abs_pos = abs_pos
+
+ if cls_token is not None:
+ new_abs_pos = torch.cat([cls_token, new_abs_pos], dim=1)
+ return new_abs_pos
+
+
+class DropPath(nn.Module):
+ """Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks)."""
+
+ def __init__(self, drop_prob=None):
+ super(DropPath, self).__init__()
+ self.drop_prob = drop_prob
+
+ def forward(self, x):
+ return drop_path(x, self.drop_prob, self.training)
+
+ def extra_repr(self):
+ return "p={}".format(self.drop_prob)
+
+
+class Mlp(nn.Module):
+ def __init__(
+ self,
+ in_features,
+ hidden_features=None,
+ out_features=None,
+ act_layer=nn.GELU,
+ drop=0.0,
+ ):
+ super().__init__()
+ out_features = out_features or in_features
+ hidden_features = hidden_features or in_features
+ self.fc1 = nn.Linear(in_features, hidden_features)
+ self.act = act_layer()
+ self.fc2 = nn.Linear(hidden_features, out_features)
+ self.drop = nn.Dropout(drop)
+
+ def forward(self, x):
+ x = self.fc1(x)
+ x = self.act(x)
+ x = self.fc2(x)
+ x = self.drop(x)
+ return x
+
+
+class Attention(nn.Module):
+ def __init__(
+ self,
+ dim,
+ num_heads=8,
+ qkv_bias=False,
+ qk_scale=None,
+ attn_drop=0.0,
+ proj_drop=0.0,
+ attn_head_dim=None,
+ att_dimension=None,
+ ):
+ super().__init__()
+ self.num_heads = num_heads
+ head_dim = dim // num_heads
+ self.dim = dim
+
+ if attn_head_dim is not None:
+ head_dim = attn_head_dim
+ all_head_dim = head_dim * self.num_heads
+
+ self.scale = qk_scale or head_dim**-0.5
+
+ self.qkv = nn.Linear(dim, all_head_dim * 3, bias=qkv_bias)
+
+ self.attn_drop = nn.Dropout(attn_drop)
+ self.proj = nn.Linear(all_head_dim, dim)
+ self.proj_drop = nn.Dropout(proj_drop)
+
+ self.attn_cam = None
+ self.attn = None
+ self.v = None
+ self.v_cam = None
+ self.attn_gradients = None
+
+ def get_attn(self):
+ return self.attn
+
+ def save_attn(self, attn):
+ self.attn = attn
+
+ def save_attn_cam(self, cam):
+ self.attn_cam = cam
+
+ def get_attn_cam(self):
+ return self.attn_cam
+
+ def get_v(self):
+ return self.v
+
+ def save_v(self, v):
+ self.v = v
+
+ def save_v_cam(self, cam):
+ self.v_cam = cam
+
+ def get_v_cam(self):
+ return self.v_cam
+
+ def save_attn_gradients(self, attn_gradients):
+ self.attn_gradients = attn_gradients
+
+ def get_attn_gradients(self):
+ return self.attn_gradients
+
+ def forward(self, x, b_size, **kwargs):
+ B, N, C = x.shape
+ # mask = None
+
+ # if 'maskout_pes' in kwargs.keys():
+ # mask = kwargs['maskout_pes']
+ # T = mask.shape[1]
+ # num_tokens = mask.shape[2]*mask.shape[3]
+
+ # if num_tokens == (N-1):
+ # mask = rearrange(mask, 'b t h w -> (b t) (h w)', b=b_size, t=T, h=mask.shape[2], w= mask.shape[3]).unsqueeze(1)
+ # mask = mask.unsqueeze(3)
+ # mask = mask.repeat(1, self.num_heads, 1, num_tokens+1)
+ # mask = torch.cat((torch.ones((b_size*T, self.num_heads, 1, num_tokens+1)).cuda(), mask), 2)
+ # else:
+ # mask = rearrange(mask, 'b t h w -> (b h w) t', b=b_size, t=T, h=mask.shape[2], w= mask.shape[3]).unsqueeze(1)
+ # mask = mask.unsqueeze(3)
+ # mask = mask.repeat(1, self.num_heads, 1, T+1)
+ # mask = torch.cat((torch.ones((b_size*num_tokens, self.num_heads, 1, T+1)).cuda(), mask), 2)
+
+ qkv = self.qkv(x)
+ qkv = qkv.reshape(B, N, 3, self.num_heads, -1).permute(
+ 2, 0, 3, 1, 4
+ ) # 3, B (BxT or BxN), H, N, C
+ q, k, v = (
+ qkv[0],
+ qkv[1],
+ qkv[2],
+ ) # make torchscript happy (cannot use tensor as tuple)
+
+ # self.save_v(v)
+
+ q = q * self.scale
+ attn = q @ k.transpose(-2, -1)
+
+ # if mask is not None:
+ # attn = attn.masked_fill(mask == 0, float("-1e20"))
+
+ attn = attn.softmax(dim=-1)
+ attn = self.attn_drop(attn)
+
+ # self.save_attn(attn)
+ # attn.register_hook(self.save_attn_gradients)
+
+ x = (attn @ v).transpose(1, 2).reshape(B, N, -1)
+ x = self.proj(x)
+ x = self.proj_drop(x)
+
+ return x
+
+
+class CrossAttention(nn.Module):
+ def __init__(
+ self,
+ dim,
+ num_heads=8,
+ qkv_bias=False,
+ qk_scale=None,
+ attn_drop=0.0,
+ proj_drop=0.0,
+ attn_head_dim=None,
+ att_dimension="spatial",
+ ):
+ """
+ Implementation for cross attention through dimension
+ """
+ super().__init__()
+ self.num_heads = num_heads
+ head_dim = dim // num_heads
+ self.dim = dim
+
+ if attn_head_dim is not None:
+ head_dim = attn_head_dim
+ all_head_dim = head_dim * self.num_heads
+
+ self.scale = qk_scale or head_dim**-0.5
+
+ self.qkv = nn.Linear(dim, all_head_dim * 3, bias=qkv_bias)
+
+ self.attn_drop = nn.Dropout(attn_drop)
+ self.proj = nn.Linear(all_head_dim, dim)
+ self.proj_drop = nn.Dropout(proj_drop)
+
+ assert att_dimension in ["spatial", "temporal"]
+ self.att_dimension = att_dimension
+
+ def forward(self, x, b_size):
+ B, N, C = (
+ x.shape
+ ) # N can be T or HW // P**2, B can be previous reshaped from self.batch_size * T|B
+ T = B // b_size
+
+ qkv = self.qkv(x)
+ qkv = qkv.reshape(b_size, T, N, 3, self.num_heads, -1).permute(3, 0, 4, 1, 2, 5)
+ q, k, v = (
+ qkv[0],
+ qkv[1],
+ qkv[2],
+ ) # make torchscript happy (cannot use tensor as tuple)
+
+ # Define the window
+ window = torch.tensor([-2, -1, 0, 1, 2]).cuda()
+
+ # Start computing locally cross self-attention
+ q_scale = q * self.scale
+
+ # Initialize attn weights
+ attn = torch.zeros((b_size, self.num_heads, T, N, N), dtype=torch.float).cuda()
+
+ if self.att_dimension == "spatial":
+ sqrt_N = int(math.sqrt(N))
+ for w in window:
+ i_indices = torch.arange(1, T).cuda()
+ j_indices = torch.arange(0, N).cuda()
+
+ i_valid = (i_indices + w >= 0) & (i_indices + w < T)
+ j_valid = (j_indices + sqrt_N * w >= 0) & (j_indices + sqrt_N * w < N)
+
+ i_indices = i_indices[i_valid]
+ j_indices = j_indices[j_valid]
+
+ attn[
+ :, :, torch.cat((torch.zeros(1, dtype=int).cuda(), i_indices + w))
+ ][:, :, :, j_indices][..., j_indices + sqrt_N * w] = q_scale[
+ :, :, torch.cat((torch.zeros(1, dtype=int).cuda(), i_indices))
+ ][
+ :, :, :, j_indices
+ ] @ k[
+ :, :, torch.cat((torch.zeros(1, dtype=int).cuda(), i_indices + w))
+ ][
+ :, :, :, j_indices + sqrt_N * w
+ ].transpose(
+ -2, -1
+ )
+ else:
+ sqrt_T = int(math.sqrt(T))
+
+ for w in window:
+ i_indices = torch.arange(0, T).cuda()
+ j_indices = torch.arange(1, N).cuda()
+
+ i_valid = (i_indices + sqrt_T * w >= 0) & (i_indices + sqrt_T * w < T)
+ j_valid = (j_indices + w >= 1) & (j_indices + w < N)
+
+ i_indices = i_indices[i_valid]
+ j_indices = j_indices[j_valid]
+
+ attn[:, :, i_indices + sqrt_T * w][
+ :, :, :, torch.cat((torch.zeros(1, dtype=int).cuda(), j_indices))
+ ][
+ ..., torch.cat((torch.zeros(1, dtype=int).cuda(), j_indices + w))
+ ] = q_scale[
+ :, :, i_indices
+ ][
+ :, :, :, torch.cat((torch.zeros(1, dtype=int).cuda(), j_indices))
+ ] @ k[
+ :, :, i_indices + sqrt_T * w
+ ][
+ :,
+ :,
+ :,
+ torch.cat((torch.zeros(1, dtype=int).cuda(), j_indices + w)),
+ ].transpose(
+ -2, -1
+ )
+
+ attn = attn.softmax(dim=-1)
+ attn = self.attn_drop(attn)
+
+ x = (attn @ v).transpose(1, 2).reshape(B, N, -1)
+ x = self.proj(x)
+ x = self.proj_drop(x)
+
+ return x
+
+
+class Block(nn.Module):
+ def __init__(
+ self,
+ dim,
+ num_heads,
+ mlp_ratio=4.0,
+ qkv_bias=False,
+ qk_scale=None,
+ drop=0.0,
+ attn_drop=0.0,
+ drop_path=0.0,
+ act_layer=nn.GELU,
+ norm_layer=nn.LayerNorm,
+ attn_head_dim=None,
+ ):
+ super().__init__()
+
+ self.norm1 = norm_layer(dim)
+ self.attn = Attention(
+ dim,
+ num_heads=num_heads,
+ qkv_bias=qkv_bias,
+ qk_scale=qk_scale,
+ attn_drop=attn_drop,
+ proj_drop=drop,
+ attn_head_dim=attn_head_dim,
+ )
+
+ # NOTE: drop path for stochastic depth, we shall see if this is better than dropout here
+ self.drop_path = DropPath(drop_path) if drop_path > 0.0 else nn.Identity()
+ self.norm2 = norm_layer(dim)
+ mlp_hidden_dim = int(dim * mlp_ratio)
+ self.mlp = Mlp(
+ in_features=dim,
+ hidden_features=mlp_hidden_dim,
+ act_layer=act_layer,
+ drop=drop,
+ )
+
+ def forward(self, x, b_size, **kwargs):
+ x = x + self.drop_path(self.attn(self.norm1(x), b_size))
+ x = x + self.drop_path(self.mlp(self.norm2(x)))
+ return x
+
+
+class Block2D(nn.Module):
+ def __init__(
+ self,
+ dim,
+ num_heads,
+ mlp_ratio=4.0,
+ qkv_bias=False,
+ qk_scale=None,
+ drop=0.0,
+ attn_drop=0.0,
+ drop_path=0.1,
+ act_layer=nn.GELU,
+ norm_layer=nn.LayerNorm,
+ attention_type="divided_space_time",
+ **kwargs,
+ ):
+ super().__init__()
+ self.attention_type = attention_type
+ assert attention_type in [
+ "divided_space_time",
+ "space_only",
+ "joint_space_time",
+ ]
+ self.register_token = kwargs.get("register_token")
+ self.temp_token = kwargs.get("temp_token")
+ self.return_s_cls_token = kwargs.get("return_s_cls_token") or False
+
+ self.norm1 = norm_layer(dim)
+ self.attn = Attention(
+ dim,
+ num_heads=num_heads,
+ qkv_bias=qkv_bias,
+ qk_scale=qk_scale,
+ attn_drop=attn_drop,
+ proj_drop=drop,
+ )
+
+ ## Temporal Attention Parameters
+ if self.attention_type == "divided_space_time":
+ self.temporal_norm1 = norm_layer(dim)
+ self.temporal_attn = Attention(
+ dim,
+ num_heads=num_heads,
+ qkv_bias=qkv_bias,
+ qk_scale=qk_scale,
+ attn_drop=attn_drop,
+ proj_drop=drop,
+ att_dimension="temporal",
+ )
+ self.temporal_fc = nn.Linear(dim, dim)
+
+ ## drop path
+ self.drop_path = DropPath(drop_path) if drop_path > 0.0 else nn.Identity()
+ self.norm2 = norm_layer(dim)
+ # self.norm3 = norm_layer(dim)
+ # self.norm4 = norm_layer(dim)
+ mlp_hidden_dim = int(dim * mlp_ratio)
+ self.mlp = Mlp(
+ in_features=dim,
+ hidden_features=mlp_hidden_dim,
+ act_layer=act_layer,
+ drop=drop,
+ )
+
+ def forward(self, x, B, T, W, **kwargs):
+ if self.temp_token:
+ num_spatial_tokens = (x.size(1) - 2) // T
+ else:
+ num_spatial_tokens = (x.size(1) - 1) // T
+ H = num_spatial_tokens // W
+
+ if self.attention_type in ["space_only", "joint_space_time"]:
+ x = x + self.drop_path(self.attn(self.norm1(x)))
+ x = x + self.drop_path(self.mlp(self.norm2(x)))
+ return x, None
+ elif self.attention_type == "divided_space_time":
+ # init class token
+ init_cls_token = x[:, 0, :].unsqueeze(1)
+ if self.temp_token:
+ init_temp_token = x[:, -1, :].unsqueeze(1)
+ # init_register_token = x[:, -1, :].unsqueeze(1)
+
+ ## Temporal
+ if self.temp_token:
+ t_cls_token = init_temp_token.repeat(1, num_spatial_tokens, 1)
+ else:
+ t_cls_token = init_cls_token.repeat(1, num_spatial_tokens, 1)
+ t_cls_token = rearrange(
+ t_cls_token, "b (h w) m -> (b h w) m", b=B, h=H, w=W
+ ).unsqueeze(1)
+
+ if self.temp_token:
+ xt = x[:, 1:-1, :]
+ else:
+ xt = x[:, 1:, :]
+
+ xt = rearrange(xt, "b (h w t) m -> (b h w) t m", b=B, h=H, w=W, t=T)
+ xt = torch.cat((xt, t_cls_token), 1)
+
+ res_temporal = self.drop_path(
+ self.temporal_attn(self.temporal_norm1(xt), b_size=B, **kwargs)
+ ) # Processing temporal att.
+ res_temporal = self.temporal_fc(res_temporal)
+ res_temporal, t_cls_token = res_temporal[:, :-1, :], res_temporal[:, -1, :]
+ res_temporal = rearrange(
+ res_temporal, "(b h w) t m -> b (h w t) m", b=B, h=H, w=W, t=T
+ )
+ t_cls_token = rearrange(
+ t_cls_token, "(b h w) m -> b (h w) m", b=B, h=H, w=W
+ )
+ # t_cls_token_avg = torch.mean(t_cls_token, 1, True) ## average for every temporal patch
+ xt = x[:, 1:-1, :] + res_temporal
+
+ ## Spatial
+ cls_token = init_cls_token.repeat(1, T, 1)
+ cls_token = rearrange(cls_token, "b t m -> (b t) m", b=B, t=T).unsqueeze(1)
+ # register_token = init_register_token.repeat(1, T, 1)
+ # register_token = rearrange(register_token, 'b t m -> (b t) m', b=B, t=T).unsqueeze(1)
+ xs = xt
+ xs = rearrange(xs, "b (h w t) m -> (b t) (h w) m", b=B, h=H, w=W, t=T)
+ xs = torch.cat((cls_token, xs), 1)
+ # xs = torch.cat((xs, register_token), 1)
+ res_spatial = self.drop_path(self.attn(self.norm1(xs), b_size=B, **kwargs))
+
+ ### Taking care of TEMP token
+ t_cls_token_avg = torch.mean(
+ t_cls_token, 1, True
+ ) ## average for every temporal patch
+
+ ### Taking care of CLS token
+ cls_token = res_spatial[:, 0, :]
+ cls_token = rearrange(cls_token, "(b t) m -> b t m", b=B, t=T)
+ cls_token_avg = torch.mean(cls_token, 1, True) ## averaging for every frame
+ # register_token = res_spatial[:, -1, :]
+ # register_token = rearrange(register_token, '(b t) m -> b t m', b=B, t=T)
+ # register_token_avg = torch.mean(register_token, 1, True) ## averaging for every frame
+
+ res_spatial = res_spatial[:, 1:, :]
+ res_spatial = rearrange(
+ res_spatial, "(b t) (h w) m -> b (h w t) m", b=B, h=H, w=W, t=T
+ )
+ res = res_spatial
+ x = xt
+
+ ## Mlp
+ # x = torch.cat((t_cls_token_avg, x), 1) + torch.cat((cls_token_avg, res), 1)
+ xt_ = torch.cat((init_cls_token, x), 1)
+ if self.temp_token:
+ xt_ = torch.cat((xt_, t_cls_token_avg), 1)
+ xs_ = torch.cat((cls_token_avg, res), 1)
+ if self.temp_token:
+ xs_ = torch.cat((xs_, init_temp_token), 1)
+ x = xt_ + xs_
+ x = x + self.drop_path(self.mlp(self.norm2(x)))
+
+ # Adding MLP for spatial_cls_token, ttemp_cls_token
+ # t_cls_token = self.drop_path(self.mlp(self.norm3(t_cls_token)))
+ # s_cls_token = self.drop_path(self.mlp(self.norm4(cls_token)))
+
+ if self.return_s_cls_token:
+ return x, cls_token, None
+ else:
+ return x, None, None
+
+
+class PatchEmbed(nn.Module):
+ """Image to Patch Embedding"""
+
+ def __init__(self, img_size=224, patch_size=16, in_chans=3, embed_dim=768, ratio=1):
+ super().__init__()
+ img_size = to_2tuple(img_size)
+ patch_size = to_2tuple(patch_size)
+ num_patches = (
+ (img_size[1] // patch_size[1]) * (img_size[0] // patch_size[0]) * (ratio**2)
+ )
+ self.patch_shape = (
+ int(img_size[0] // patch_size[0] * ratio),
+ int(img_size[1] // patch_size[1] * ratio),
+ )
+ self.origin_patch_shape = (
+ int(img_size[0] // patch_size[0]),
+ int(img_size[1] // patch_size[1]),
+ )
+ self.img_size = img_size
+ self.patch_size = patch_size
+ self.num_patches = num_patches
+
+ self.proj = nn.Conv2d(
+ in_chans,
+ embed_dim,
+ kernel_size=patch_size,
+ stride=(patch_size[0] // ratio),
+ padding=4 + 2 * (ratio // 2 - 1),
+ )
+
+ def forward(self, x, **kwargs):
+ B, C, H, W = x.shape
+ x = self.proj(x)
+ Hp, Wp = x.shape[2], x.shape[3]
+
+ x = x.flatten(2).transpose(1, 2)
+ return x, (Hp, Wp)
+
+
+class PatchEmbed3D(nn.Module):
+ """Images to Patch Embedding"""
+
+ def __init__(
+ self,
+ img_size=224,
+ patch_size=16,
+ in_chans=3,
+ embed_dim=768,
+ ratio=1,
+ low_level=False,
+ **override_params,
+ ):
+ super().__init__()
+ img_size = to_2tuple(img_size)
+ patch_size = to_2tuple(patch_size)
+ num_patches = (
+ (img_size[1] // patch_size[1]) * (img_size[0] // patch_size[0]) * (ratio**2)
+ )
+ self.patch_shape = (
+ int(img_size[0] // patch_size[0] * ratio),
+ int(img_size[1] // patch_size[1] * ratio),
+ )
+ self.origin_patch_shape = (
+ int(img_size[0] // patch_size[0]),
+ int(img_size[1] // patch_size[1]),
+ )
+ self.img_size = img_size
+ self.patch_size = patch_size
+ self.num_patches = num_patches
+ self.low_level = low_level
+
+ if not self.low_level:
+ self.proj = nn.Conv2d(
+ in_chans, embed_dim, kernel_size=patch_size, stride=patch_size
+ )
+ else:
+ model_name = "efficientnet-b4"
+ self.proj = EfficientNet.from_pretrained(
+ model_name, advprop=True, **override_params
+ )
+ self.fc = nn.Linear(160, embed_dim)
+
+ def forward(self, x):
+ B, C, T, H, W = x.shape
+ x = rearrange(x, "b c t h w -> (b t) c h w")
+
+ if not self.low_level:
+ x = self.proj(x)
+ else:
+ endpoints = self.proj.extract_endpoints(x)
+ x1 = endpoints["reduction_6"]
+ x2 = endpoints["reduction_5"]
+ x3 = endpoints["reduction_4"]
+ x4 = endpoints["reduction_3"]
+ x5 = endpoints["reduction_2"]
+ x = x3
+ x = x.permute(0, 2, 3, 1)
+ x = self.fc(x)
+ x = x.permute(0, 3, 1, 2)
+
+ Hp, Wp = x.shape[2], x.shape[3]
+ x = x.flatten(2).transpose(1, 2)
+ return x, T, (Hp, Wp)
+
+
+class HybridEmbed(nn.Module):
+ """CNN Feature Map Embedding
+ Extract feature map from CNN, flatten, project to embedding dim.
+ """
+
+ def __init__(
+ self, backbone, img_size=224, feature_size=None, in_chans=3, embed_dim=768
+ ):
+ super().__init__()
+ assert isinstance(backbone, nn.Module)
+ img_size = to_2tuple(img_size)
+ self.img_size = img_size
+ self.backbone = backbone
+ if feature_size is None:
+ with torch.no_grad():
+ training = backbone.training
+ if training:
+ backbone.eval()
+ o = self.backbone(torch.zeros(1, in_chans, img_size[0], img_size[1]))[
+ -1
+ ]
+ feature_size = o.shape[-2:]
+ feature_dim = o.shape[1]
+ backbone.train(training)
+ else:
+ feature_size = to_2tuple(feature_size)
+ feature_dim = self.backbone.feature_info.channels()[-1]
+ self.num_patches = feature_size[0] * feature_size[1]
+ self.proj = nn.Linear(feature_dim, embed_dim)
+
+ def forward(self, x):
+ x = self.backbone(x)[-1]
+ x = x.flatten(2).transpose(1, 2)
+ x = self.proj(x)
+ return x
+
+
+@BACKBONES.register_module()
+class ViT(BaseBackbone):
+ def __init__(
+ self,
+ img_size=224,
+ patch_size=16,
+ in_chans=3,
+ num_classes=80,
+ embed_dim=768,
+ depth=12,
+ num_heads=12,
+ mlp_ratio=4.0,
+ qkv_bias=False,
+ qk_scale=None,
+ drop_rate=0.0,
+ attn_drop_rate=0.0,
+ drop_path_rate=0.0,
+ hybrid_backbone=None,
+ norm_layer=None,
+ use_checkpoint=False,
+ frozen_stages=-1,
+ ratio=1,
+ last_norm=True,
+ class_token=True,
+ attention_type="space",
+ patch_padding="pad",
+ freeze_attn=False,
+ freeze_ffn=False,
+ **kwargs,
+ ):
+ # Protect mutable default arguments
+ super(ViT, self).__init__()
+ norm_layer = norm_layer or partial(nn.LayerNorm, eps=1e-6)
+ self.num_classes = num_classes
+ self.num_features = self.embed_dim = (
+ embed_dim # num_features for consistency with other models
+ )
+ self.frozen_stages = frozen_stages
+ self.use_checkpoint = use_checkpoint
+ self.patch_padding = patch_padding
+ self.freeze_attn = freeze_attn
+ self.freeze_ffn = freeze_ffn
+ self.depth = depth
+ self.attention_type = attention_type
+
+ if hybrid_backbone is not None:
+ self.patch_embed = HybridEmbed(
+ hybrid_backbone,
+ img_size=img_size,
+ in_chans=in_chans,
+ embed_dim=embed_dim,
+ )
+ else:
+ self.patch_embed = PatchEmbed(
+ img_size=img_size,
+ patch_size=patch_size,
+ in_chans=in_chans,
+ embed_dim=embed_dim,
+ ratio=ratio,
+ )
+ num_patches = self.patch_embed.num_patches
+
+ self.cls_token = (
+ nn.Parameter(torch.zeros(1, 1, embed_dim)) if class_token else None
+ )
+
+ # since the pretraining model has class token
+ self.pos_embed = nn.Parameter(torch.zeros(1, num_patches + 1, embed_dim))
+
+ dpr = [
+ x.item() for x in torch.linspace(0, drop_path_rate, depth)
+ ] # stochastic depth decay rule
+
+ self.blocks = nn.ModuleList(
+ [
+ Block(
+ dim=embed_dim,
+ num_heads=num_heads,
+ mlp_ratio=mlp_ratio,
+ qkv_bias=qkv_bias,
+ qk_scale=qk_scale,
+ drop=drop_rate,
+ attn_drop=attn_drop_rate,
+ drop_path=dpr[i],
+ norm_layer=norm_layer,
+ )
+ for i in range(depth)
+ ]
+ )
+
+ self.norm = norm_layer(embed_dim) if last_norm else nn.Identity()
+
+ if self.pos_embed is not None:
+ trunc_normal_(self.pos_embed, std=0.02)
+
+ self._freeze_stages()
+
+ def _freeze_stages(self):
+ """Freeze parameters."""
+ if self.frozen_stages >= 0:
+ self.patch_embed.eval()
+ for param in self.patch_embed.parameters():
+ param.requires_grad = False
+
+ for i in range(1, self.frozen_stages + 1):
+ m = self.blocks[i]
+ m.eval()
+ for param in m.parameters():
+ param.requires_grad = False
+
+ if self.freeze_attn:
+ for i in range(0, self.depth):
+ m = self.blocks[i]
+ m.attn.eval()
+ m.norm1.eval()
+ for param in m.attn.parameters():
+ param.requires_grad = False
+ for param in m.norm1.parameters():
+ param.requires_grad = False
+
+ if self.freeze_ffn:
+ self.pos_embed.requires_grad = False
+ self.patch_embed.eval()
+ for param in self.patch_embed.parameters():
+ param.requires_grad = False
+ for i in range(0, self.depth):
+ m = self.blocks[i]
+ m.mlp.eval()
+ m.norm2.eval()
+ for param in m.mlp.parameters():
+ param.requires_grad = False
+ for param in m.norm2.parameters():
+ param.requires_grad = False
+
+ def init_weights(self, pretrained=None):
+ """Initialize the weights in backbone.
+ Args:
+ pretrained (str, optional): Path to pre-trained weights.
+ Defaults to None.
+ """
+ super().init_weights(pretrained, patch_padding=self.patch_padding)
+
+ if pretrained is None:
+
+ def _init_weights(m):
+ if isinstance(m, nn.Linear):
+ trunc_normal_(m.weight, std=0.02)
+ if isinstance(m, nn.Linear) and m.bias is not None:
+ nn.init.constant_(m.bias, 0)
+ elif isinstance(m, nn.LayerNorm):
+ nn.init.constant_(m.bias, 0)
+ nn.init.constant_(m.weight, 1.0)
+
+ if self.cls_token is not None:
+ nn.init.normal_(self.cls_token, std=1e-6)
+
+ self.apply(_init_weights)
+
+ def get_num_layers(self):
+ return len(self.blocks)
+
+ @torch.jit.ignore
+ def no_weight_decay(self):
+ return {"pos_embed", "cls_token"}
+
+ def forward_features(self, x, **kwargs):
+ B, C, H, W = x.shape
+ x, (Hp, Wp) = self.patch_embed(x)
+
+ if self.cls_token is not None:
+ cls_token = self.cls_token.expand(x.shape[0], -1, -1)
+ x = torch.cat((cls_token, x), dim=1)
+
+ if self.pos_embed is not None:
+ # fit for multiple GPU training
+ # since the first element for pos embed (sin-cos manner) is zero, it will cause no difference
+ # x = x + self.pos_embed[:, 1:] + self.pos_embed[:, :1]
+ x = x + self.pos_embed
+
+ for blk in self.blocks:
+ if self.use_checkpoint:
+ x = checkpoint.checkpoint(blk, x)
+ else:
+ x = blk(x, B)
+
+ x = self.norm(x)
+ res = {}
+
+ if self.cls_token is not None:
+ x_cls = x[:, :1]
+ else:
+ x_cls = torch.mean(x[:, 1:], 1, False)
+ res["cls"] = x_cls
+
+ xp = x[:, 1:]
+ xp = xp.permute(0, 2, 1).reshape(B, -1, Hp, Wp).contiguous()
+ res["embed"] = xp
+
+ return res
+
+ def forward(self, x, **kwargs) -> Union[torch.tensor, Dict[str, torch.tensor]]:
+ x = self.forward_features(x, **kwargs)
+ return x
+
+ def train(self, mode=True):
+ """Convert the model into training mode."""
+ super().train(mode)
+ self._freeze_stages()
+
+
+@BACKBONES.register_module()
+class TimeViT(ViT):
+ def __init__(
+ self,
+ img_size=224,
+ patch_size=16,
+ in_chans=3,
+ num_classes=80,
+ embed_dim=768,
+ depth=12,
+ num_heads=12,
+ mlp_ratio=4,
+ qkv_bias=False,
+ qk_scale=None,
+ drop_rate=0,
+ attn_drop_rate=0,
+ drop_path_rate=0,
+ hybrid_backbone=None,
+ norm_layer=None,
+ use_checkpoint=False,
+ frozen_stages=-1,
+ ratio=1,
+ last_norm=True,
+ class_token=True,
+ attention_type="space_only",
+ patch_padding="pad",
+ freeze_attn=False,
+ freeze_ffn=False,
+ num_frames=4,
+ **kwargs,
+ ):
+ super().__init__(
+ img_size,
+ patch_size,
+ in_chans,
+ num_classes,
+ embed_dim,
+ depth,
+ num_heads,
+ mlp_ratio,
+ qkv_bias,
+ qk_scale,
+ drop_rate,
+ attn_drop_rate,
+ drop_path_rate,
+ hybrid_backbone,
+ norm_layer,
+ use_checkpoint,
+ frozen_stages,
+ ratio,
+ last_norm,
+ class_token,
+ attention_type,
+ patch_padding,
+ freeze_attn,
+ freeze_ffn,
+ **kwargs,
+ )
+
+ norm_layer = norm_layer or partial(nn.LayerNorm, eps=1e-6)
+ register_token = kwargs.get("register_token") or False
+ temp_token = kwargs.get("temp_token") or False
+ self.low_level_enhanced = kwargs.get("low_level_enhanced") or False
+ self.patch_size = patch_size
+
+ # Temporary
+ # self.patch_embed = PatchEmbed3D(
+ # img_size=img_size, patch_size=patch_size, in_chans=in_chans, embed_dim=embed_dim, ratio=ratio,
+ # low_level=True, include_top=False, include_hm_decoder=False)
+ self.patch_embed = PatchEmbed3D(
+ img_size=img_size,
+ patch_size=patch_size,
+ in_chans=in_chans,
+ embed_dim=embed_dim,
+ ratio=ratio,
+ )
+
+ self.register_token = (
+ nn.Parameter(torch.zeros(1, 1, embed_dim)) if register_token else None
+ )
+ self.temp_token = (
+ nn.Parameter(torch.zeros(1, 1, embed_dim)) if temp_token else None
+ )
+
+ if self.attention_type != "space_only":
+ if temp_token:
+ self.time_embed = nn.Parameter(
+ torch.zeros(1, num_frames + 1, embed_dim)
+ )
+ else:
+ self.time_embed = nn.Parameter(torch.zeros(1, num_frames, embed_dim))
+ self.time_drop = nn.Dropout(p=drop_rate)
+
+ self.norm_s_cls = norm_layer(embed_dim)
+ self.norm_t_cls = norm_layer(embed_dim)
+
+ dpr = [
+ x.item() for x in torch.linspace(0, drop_path_rate, depth)
+ ] # stochastic depth decay rule
+ self.blocks = nn.ModuleList(
+ [
+ Block2D(
+ dim=embed_dim,
+ num_heads=num_heads,
+ mlp_ratio=mlp_ratio,
+ qkv_bias=qkv_bias,
+ qk_scale=qk_scale,
+ drop=drop_rate,
+ attn_drop=attn_drop_rate,
+ drop_path=dpr[i],
+ norm_layer=norm_layer,
+ attention_type=self.attention_type,
+ temp_token=temp_token,
+ register_token=register_token,
+ return_s_cls_token=True,
+ )
+ for i in range(depth)
+ ]
+ )
+
+ if self.low_level_enhanced:
+ self.lowconv3d_0 = nn.Conv3d(
+ 3,
+ embed_dim // 16,
+ kernel_size=(3, 4, 4),
+ stride=(1, 4, 4),
+ padding=(1, 0, 0),
+ bias=False,
+ ) # B x 48 x 4 x 56 x 56
+ self.bn_low0 = nn.BatchNorm3d(embed_dim // 16, momentum=BN3D_MOMENTUM)
+ self.act_low0 = nn.GELU()
+ self.lowconv3d_01 = nn.Conv3d(
+ embed_dim // 16,
+ embed_dim // 4,
+ kernel_size=(3, 4, 4),
+ stride=(1, 4, 4),
+ padding=(1, 0, 0),
+ bias=False,
+ ) # B x 48 x 4 x 14 x 14
+ self.bn_low01 = nn.BatchNorm3d(embed_dim // 4, momentum=BN3D_MOMENTUM)
+ self.act_low01 = nn.GELU()
+ # self.lowmaxpool3d_0 = nn.MaxPool3d(kernel_size=(1, 4, 4), stride=(1, 4, 4), padding=0) # B x 48 x 4 x 14 x 14
+ self.lowfc_0 = nn.Linear(embed_dim // 4, embed_dim)
+
+ self.lowconv3d_1 = nn.Conv3d(
+ embed_dim // 16,
+ embed_dim // 4,
+ kernel_size=(3, 2, 2),
+ stride=(1, 2, 2),
+ padding=(1, 0, 0),
+ bias=False,
+ ) # B x 192 x 4 x 28 x 28
+ self.bn_low1 = nn.BatchNorm3d(embed_dim // 4, momentum=BN3D_MOMENTUM)
+ self.act_low1 = nn.GELU()
+ self.lowconv3d_11 = nn.Conv3d(
+ embed_dim // 4,
+ embed_dim,
+ kernel_size=(3, 2, 2),
+ stride=(1, 2, 2),
+ padding=(1, 0, 0),
+ bias=False,
+ ) # B x 192 x 4 x 14 x 14
+ self.bn_low11 = nn.BatchNorm3d(embed_dim, momentum=BN3D_MOMENTUM)
+ self.act_low11 = nn.GELU()
+ # self.lowmaxpool3d_1 = nn.MaxPool3d(kernel_size=(1,2,2), stride=(1,2,2), padding=0)
+ self.lowfc_1 = nn.Linear(embed_dim, embed_dim)
+
+ self.lowconv3d_2 = nn.Conv3d(
+ embed_dim // 4,
+ embed_dim,
+ kernel_size=(3, 2, 2),
+ stride=(1, 2, 2),
+ padding=(1, 0, 0),
+ bias=False,
+ ) # B x 768 x 4 x 14 x 14
+ self.bn_low2 = nn.BatchNorm3d(embed_dim, momentum=BN3D_MOMENTUM)
+ self.act_low2 = nn.GELU()
+ self.lowconv3d_21 = nn.Conv3d(
+ embed_dim,
+ embed_dim,
+ kernel_size=(3, 3, 3),
+ stride=(1, 1, 1),
+ padding=(1, 1, 1),
+ bias=False,
+ ) # B x 768 x 4 x 14 x 14
+ self.bn_low21 = nn.BatchNorm3d(embed_dim, momentum=BN3D_MOMENTUM)
+ self.act_low21 = nn.GELU()
+ # self.lowmaxpool3d_2 = nn.MaxPool3d(kernel_size=(1,1,1), stride=(1,1,1), padding=0)
+ self.lowfc_2 = nn.Linear(embed_dim, embed_dim)
+
+ self.lowconv3d_3 = nn.Conv3d(
+ embed_dim,
+ embed_dim,
+ kernel_size=(3, 1, 1),
+ stride=(1, 1, 1),
+ padding=(1, 0, 0),
+ bias=False,
+ ) # B x 768 x 4 x 14 x 14
+ self.bn_low3 = nn.BatchNorm3d(embed_dim, momentum=BN3D_MOMENTUM)
+ self.act_low3 = nn.GELU()
+ self.lowconv3d_31 = nn.Conv3d(
+ embed_dim,
+ embed_dim,
+ kernel_size=(3, 1, 1),
+ stride=(1, 1, 1),
+ padding=(1, 0, 0),
+ bias=False,
+ ) # B x 768 x 4 x 14 x 14
+ self.bn_low31 = nn.BatchNorm3d(embed_dim, momentum=BN3D_MOMENTUM)
+ self.act_low31 = nn.GELU()
+ # self.lowmaxpool3d_3 = nn.MaxPool3d(kernel_size=(1,1,1), stride=(1,1,1), padding=0)
+ self.lowfc_3 = nn.Linear(embed_dim, embed_dim)
+
+ def init_weights(self, pretrained=None):
+ super().init_weights(pretrained)
+
+ ## initialization of temporal attention weights
+ if self.attention_type == "divided_space_time":
+ print("Initializing weights for temporal FC...")
+ i = 0
+ for m in self.blocks.modules():
+ m_str = str(m)
+ if "Block" in m_str:
+ if i > 0:
+ nn.init.constant_(m.temporal_fc.weight, 0)
+ nn.init.constant_(m.temporal_fc.bias, 0)
+ i += 1
+
+ if self.temp_token is not None:
+ nn.init.normal_(self.temp_token, std=1e-6)
+
+ @torch.jit.ignore
+ def no_weight_decay(self):
+ return {"pos_embed", "cls_token", "time_embed"}
+
+ def forward_features(self, x, **kwargs):
+ B, C, T, H, W = x.shape
+
+ if self.low_level_enhanced:
+ x_low0 = self.lowconv3d_0(x)
+ x_low0 = self.bn_low0(x_low0)
+ x_low0 = self.act_low0(x_low0)
+ # x_low0_ = self.lowmaxpool3d_0(x_low0)
+ x_low0_ = self.act_low01(self.bn_low01(self.lowconv3d_01(x_low0)))
+ x_low0_ = x_low0_.flatten(2).transpose(1, 2)
+ x_low0_ = self.lowfc_0(x_low0_)
+ x_low0_ = rearrange(
+ x_low0_,
+ "b (t h w) m -> (b t) (h w) m",
+ b=B,
+ t=T,
+ h=H // self.patch_size,
+ w=W // self.patch_size,
+ )
+ x_low0_ = x_low0_.sigmoid()
+ x_prev = x_low0
+
+ x, T, (Hp, Wp) = self.patch_embed(x)
+
+ if self.low_level_enhanced:
+ x = x_low0_ * x
+
+ if self.cls_token is not None:
+ cls_token = self.cls_token.expand(x.shape[0], -1, -1)
+ x = torch.cat((cls_token, x), dim=1)
+
+ # if self.register_token is not None:
+ # register_token = self.register_token.expand(x.shape[0], -1, -1)
+ # x = torch.cat((x, register_token), dim=1)
+
+ if self.pos_embed is not None:
+ # fit for multiple GPU training
+ # since the first element for pos embed (sin-cos manner) is zero, it will cause no difference
+ # x = x + self.pos_embed[:, 1:] + self.pos_embed[:, :1]
+ if x.size(1) != self.pos_embed.size(1):
+ # Resizing the pos embeds in case they do not match the input at inference
+ pos_embed = self.pos_embed
+ cls_pos_embed = pos_embed[0, 0, :].unsqueeze(0).unsqueeze(1)
+ other_pos_embed = pos_embed[0, 1:, :].unsqueeze(0).transpose(1, 2)
+ P = int(other_pos_embed.size(2) ** 0.5)
+ H = x.size(1) // W
+ other_pos_embed = other_pos_embed.reshape(1, x.size(2), P, P)
+ new_pos_embed = F.interpolate(
+ other_pos_embed, size=(H, W), mode="nearest"
+ )
+ new_pos_embed = new_pos_embed.flatten(2)
+ new_pos_embed = new_pos_embed.transpose(1, 2)
+ new_pos_embed = torch.cat((cls_pos_embed, new_pos_embed), 1)
+ x = x + new_pos_embed
+ else:
+ x = x + self.pos_embed
+
+ ## Time Embeddings
+ if self.attention_type != "space_only":
+ cls_tokens = x[:B, 0, :].unsqueeze(1)
+ x = x[:, 1:]
+ x = rearrange(x, "(b t) n m -> (b n) t m", b=B, t=T)
+
+ if self.temp_token is not None:
+ temp_token = self.temp_token.expand(x.shape[0], -1, -1)
+ x = torch.cat((x, temp_token), dim=1)
+
+ ## Resizing time embeddings in case they don't match
+ if T != self.time_embed.size(1) and self.temp_token is None:
+ time_embed = self.time_embed.transpose(1, 2)
+ new_time_embed = F.interpolate(time_embed, size=(T), mode="nearest")
+ new_time_embed = new_time_embed.transpose(1, 2)
+ x = x + new_time_embed
+ else:
+ x = x + self.time_embed
+ x = self.time_drop(x)
+
+ temp_tokens = x[:B, 0, :].unsqueeze(1)
+ x = x[:, :-1]
+ x = rearrange(x, "(b n) t m -> b (n t) m", b=B, t=T)
+ x = torch.cat((cls_tokens, x), dim=1)
+ x = torch.cat((x, temp_tokens), dim=1)
+
+ for idx, blk in enumerate(self.blocks):
+ if self.use_checkpoint:
+ x = checkpoint.checkpoint(blk, x)
+ else:
+ x, s_cls_token, t_cls_token = blk(x, B, T, Wp, **kwargs)
+ if self.low_level_enhanced:
+ if (idx + 1) % 4 == 0:
+ x_low = self.__getattr__(f"lowconv3d_{(idx+1)//4}")(x_prev)
+ # x_low_ = self.__getattr__(f'lowmaxpool3d_{(idx+1)//4}')(x_low)
+ x_low = self.__getattr__(f"bn_low{(idx+1)//4}")(x_low)
+ x_low = self.__getattr__(f"act_low{(idx+1)//4}")(x_low)
+ x_low_ = self.__getattr__(f"lowconv3d_{(idx+1)//4}1")(x_low)
+ x_low_ = self.__getattr__(f"bn_low{(idx+1)//4}1")(x_low_)
+ x_low_ = self.__getattr__(f"act_low{(idx+1)//4}1")(x_low_)
+
+ x_low_ = x_low_.flatten(2).transpose(1, 2)
+ x_low_ = self.__getattr__(f"lowfc_{(idx+1)//4}")(x_low_)
+ x_low_ = x_low_.sigmoid()
+ x[:, 1:-1, :] = x[:, 1:-1, :].clone() * x_low_
+ x_prev = x_low
+
+ ### Predictions for space-only baseline
+ if self.attention_type == "space_only":
+ x = rearrange(x, "(b t) n m -> b t n m", b=B, t=T)
+ x = torch.mean(x, 1) # averaging predictions for every frame
+
+ x = self.norm(x)
+ res = {}
+
+ if self.temp_token is not None:
+ x_cls = x[:, -1:]
+ elif self.cls_token is not None:
+ x_cls = x[:, :1]
+ else:
+ x_cls = torch.mean(x[:, 1:-1], 1, False)
+ res["cls"] = x_cls
+
+ xp = x[:, 1:-1]
+ xp = xp.permute(0, 2, 1).reshape(B, -1, Hp, Wp).contiguous()
+
+ if self.attention_type != "space_only":
+ xp = rearrange(xp, "b (m t) h w -> b m t h w", b=B, t=T, h=Hp, w=Wp)
+ res["embed"] = xp
+
+ if s_cls_token is not None:
+ s_cls_token = self.norm_s_cls(s_cls_token)
+ res["s_cls_token"] = s_cls_token
+
+ if t_cls_token is not None:
+ t_cls_token = self.norm_t_cls(t_cls_token)
+ res["t_cls_token"] = t_cls_token
+
+ return res
diff --git a/clean/video/fakestormer/models/networks/backbones/xception.py b/clean/video/fakestormer/models/networks/backbones/xception.py
new file mode 100644
index 0000000000000000000000000000000000000000..aeb8e5fa5aae9c3f7cd18ca69c9e6db8139412ab
--- /dev/null
+++ b/clean/video/fakestormer/models/networks/backbones/xception.py
@@ -0,0 +1,253 @@
+# -*- coding: utf-8 -*-
+"""
+Creates an Xception Model as defined in:
+
+Francois Chollet
+Xception: Deep Learning with Depthwise Separable Convolutions
+https://arxiv.org/pdf/1610.02357.pdf
+
+This weights ported from the Keras implementation. Achieves the following performance on the validation set:
+
+Loss:0.9173 Prec@1:78.892 Prec@5:94.292
+
+REMEMBER to set your image size to 3x299x299 for both test and validation
+
+normalize = transforms.Normalize(mean=[0.5, 0.5, 0.5],
+ std=[0.5, 0.5, 0.5])
+
+The resize parameter of the validation transform should be 333, and make sure to center crop at 299x299
+"""
+
+import os
+import sys
+
+if not (os.getcwd()) in sys.path:
+ sys.path.append(os.getcwd())
+import math
+
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+import torch.utils.model_zoo as model_zoo
+from torch.nn import init
+
+from ...builder import MODELS
+from ..common import BN_MOMENTUM, conv_block
+
+model_urls = {
+ "xception": "https://www.dropbox.com/s/1hplpzet9d7dv29/xception-c0a72b38.pth.tar?dl=1"
+}
+
+
+class SeparableConv2d(nn.Module):
+ def __init__(
+ self,
+ in_channels,
+ out_channels,
+ kernel_size=1,
+ stride=1,
+ padding=0,
+ dilation=1,
+ bias=False,
+ ):
+ super(SeparableConv2d, self).__init__()
+
+ self.conv1 = nn.Conv2d(
+ in_channels,
+ in_channels,
+ kernel_size,
+ stride,
+ padding,
+ dilation,
+ groups=in_channels,
+ bias=bias,
+ )
+ self.pointwise = nn.Conv2d(in_channels, out_channels, 1, 1, 0, 1, 1, bias=bias)
+
+ def forward(self, x):
+ x = self.conv1(x)
+ x = self.pointwise(x)
+ return x
+
+
+class Block(nn.Module):
+ def __init__(
+ self,
+ in_filters,
+ out_filters,
+ reps,
+ strides=1,
+ start_with_relu=True,
+ grow_first=True,
+ ):
+ super(Block, self).__init__()
+
+ if out_filters != in_filters or strides != 1:
+ self.skip = nn.Conv2d(
+ in_filters, out_filters, 1, stride=strides, bias=False
+ )
+ self.skipbn = nn.BatchNorm2d(out_filters)
+ else:
+ self.skip = None
+
+ self.relu = nn.ReLU(inplace=True)
+ rep = []
+
+ filters = in_filters
+ if grow_first:
+ rep.append(self.relu)
+ rep.append(
+ SeparableConv2d(
+ in_filters, out_filters, 3, stride=1, padding=1, bias=False
+ )
+ )
+ rep.append(nn.BatchNorm2d(out_filters))
+ filters = out_filters
+
+ for i in range(reps - 1):
+ rep.append(self.relu)
+ rep.append(
+ SeparableConv2d(filters, filters, 3, stride=1, padding=1, bias=False)
+ )
+ rep.append(nn.BatchNorm2d(filters))
+
+ if not grow_first:
+ rep.append(self.relu)
+ rep.append(
+ SeparableConv2d(
+ in_filters, out_filters, 3, stride=1, padding=1, bias=False
+ )
+ )
+ rep.append(nn.BatchNorm2d(out_filters))
+
+ if not start_with_relu:
+ rep = rep[1:]
+ else:
+ rep[0] = nn.ReLU(inplace=False)
+
+ if strides != 1:
+ rep.append(nn.MaxPool2d(3, strides, 1))
+ self.rep = nn.Sequential(*rep)
+
+ def forward(self, inp):
+ x = self.rep(inp)
+
+ if self.skip is not None:
+ skip = self.skip(inp)
+ skip = self.skipbn(skip)
+ else:
+ skip = inp
+
+ x += skip
+ return x
+
+
+@MODELS.register_module()
+class Xception(nn.Module):
+ """
+ Xception optimized for the ImageNet dataset, as specified in
+ https://arxiv.org/pdf/1610.02357.pdf
+ """
+
+ def __init__(self, num_classes=1000, **kwargs):
+ """Constructor
+ Args:
+ num_classes: number of classes
+ """
+ super(Xception, self).__init__()
+
+ self.num_classes = num_classes
+
+ self.conv1 = nn.Conv2d(3, 32, 3, 2, 0, bias=False)
+ self.bn1 = nn.BatchNorm2d(32)
+ self.relu = nn.ReLU(inplace=True)
+
+ self.conv2 = nn.Conv2d(32, 64, 3, bias=False)
+ self.bn2 = nn.BatchNorm2d(64)
+ # do relu here
+
+ self.block1 = Block(64, 128, 2, 2, start_with_relu=False, grow_first=True)
+ self.block2 = Block(128, 256, 2, 2, start_with_relu=True, grow_first=True)
+ self.block3 = Block(256, 728, 2, 2, start_with_relu=True, grow_first=True)
+
+ self.block4 = Block(728, 728, 3, 1, start_with_relu=True, grow_first=True)
+ self.block5 = Block(728, 728, 3, 1, start_with_relu=True, grow_first=True)
+ self.block6 = Block(728, 728, 3, 1, start_with_relu=True, grow_first=True)
+ self.block7 = Block(728, 728, 3, 1, start_with_relu=True, grow_first=True)
+
+ self.block8 = Block(728, 728, 3, 1, start_with_relu=True, grow_first=True)
+ self.block9 = Block(728, 728, 3, 1, start_with_relu=True, grow_first=True)
+ self.block10 = Block(728, 728, 3, 1, start_with_relu=True, grow_first=True)
+ self.block11 = Block(728, 728, 3, 1, start_with_relu=True, grow_first=True)
+
+ self.block12 = Block(728, 1024, 2, 2, start_with_relu=True, grow_first=False)
+
+ self.conv3 = SeparableConv2d(1024, 1536, 3, 1, 1)
+ self.bn3 = nn.BatchNorm2d(1536)
+
+ # do relu here
+ self.conv4 = SeparableConv2d(1536, 2048, 3, 1, 1)
+ self.bn4 = nn.BatchNorm2d(2048)
+
+ # self.fc = nn.Linear(2048, num_classes)
+
+ def forward(self, x):
+ x = self.conv1(x)
+ x = self.bn1(x)
+ x = self.relu(x)
+
+ x = self.conv2(x)
+ x = self.bn2(x)
+ x = self.relu(x)
+
+ x = self.block1(x)
+ x = self.block2(x)
+ x = self.block3(x)
+ x = self.block4(x)
+ x = self.block5(x)
+ x = self.block6(x)
+ x = self.block7(x)
+ x = self.block8(x)
+ x = self.block9(x)
+ x = self.block10(x)
+ x = self.block11(x)
+ x = self.block12(x)
+
+ x = self.conv3(x)
+ x = self.bn3(x)
+ x = self.relu(x)
+
+ x = self.conv4(x)
+ x = self.bn4(x)
+ x = self.relu(x)
+
+ x = F.adaptive_avg_pool2d(x, (1, 1))
+ x = x.view(x.size(0), -1)
+ # x = self.fc(x)
+
+ res = {}
+ res["cls"] = x
+
+ return res
+
+ def init_weights(self, pretrained=False):
+ if not pretrained:
+ for m in self.modules():
+ if isinstance(m, nn.Conv2d):
+ n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
+ m.weight.data.normal_(0, math.sqrt(2.0 / n))
+ elif isinstance(m, nn.BatchNorm2d):
+ m.weight.data.fill_(1)
+ m.bias.data.zero_()
+ else:
+ state_dict = model_zoo.load_url(model_urls["xception"])
+ state_dict.pop("fc.weight")
+ state_dict.pop("fc.bias")
+ self.load_state_dict(state_dict, strict=False)
+
+
+if __name__ == "__main__":
+ net = Xception()
+ input = torch.rand((1, 3, 224, 224))
+ out = net(input)
+ print(out["cls"].shape)
diff --git a/clean/video/fakestormer/models/networks/common.py b/clean/video/fakestormer/models/networks/common.py
new file mode 100644
index 0000000000000000000000000000000000000000..4c694fc6bf6459d4e4211eeae68eb9cabb99858f
--- /dev/null
+++ b/clean/video/fakestormer/models/networks/common.py
@@ -0,0 +1,286 @@
+# -*- coding: utf-8 -*-
+import warnings
+
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+from mmcv.cnn import build_upsample_layer
+
+BN_MOMENTUM = 0.1
+BN3D_MOMENTUM = 0.05 # small for small batch size
+
+
+def point_wise_block(inplanes, outplanes):
+ return nn.Sequential(
+ nn.Conv2d(
+ in_channels=inplanes,
+ out_channels=outplanes,
+ kernel_size=1,
+ padding=0,
+ stride=1,
+ bias=False,
+ ),
+ nn.BatchNorm2d(outplanes, momentum=BN_MOMENTUM),
+ nn.ReLU(inplace=True),
+ )
+
+
+def conv_block(inplanes, outplanes, kernel_size, stride=1, padding=0):
+ return nn.Sequential(
+ nn.Conv2d(
+ in_channels=inplanes,
+ out_channels=outplanes,
+ kernel_size=kernel_size,
+ padding=padding,
+ stride=stride,
+ bias=False,
+ ),
+ nn.BatchNorm2d(outplanes, momentum=BN_MOMENTUM),
+ nn.ReLU(inplace=True),
+ )
+
+
+def conv3x3(in_planes, out_planes, stride=1):
+ """3x3 convolution with padding"""
+ return nn.Conv2d(
+ in_planes, out_planes, kernel_size=3, stride=stride, padding=1, bias=False
+ )
+
+
+def conv3d_block(
+ inplanes,
+ outplanes,
+ kernel_size=(3, 1, 1),
+ stride=(1, 1, 1),
+ padding=0,
+ bias=False,
+ inplace=False,
+ act=nn.GELU,
+):
+ """
+ General conv3d block for handling 3d feature maps
+ """
+ return nn.Sequential(
+ nn.Conv3d(
+ inplanes,
+ outplanes,
+ kernel_size=kernel_size,
+ stride=stride,
+ padding=padding,
+ bias=bias,
+ ),
+ nn.BatchNorm3d(outplanes, momentum=BN3D_MOMENTUM),
+ act(),
+ )
+
+
+def deconv3d_block(
+ inplanes,
+ outplanes,
+ kernel_size=(2, 4, 4),
+ stride=(2, 2, 2),
+ padding=(0, 1, 1),
+ bias=False,
+ inplace=False,
+ out_padding=(0, 1, 1),
+ act=None,
+):
+ """
+ General Transpose 3D Convolution for handling 3D feature maps
+ """
+ layers = []
+ layers.append(
+ build_upsample_layer(
+ dict(type="deconv3d"),
+ in_channels=inplanes,
+ out_channels=outplanes,
+ kernel_size=kernel_size,
+ stride=stride,
+ padding=padding,
+ output_padding=out_padding,
+ bias=bias,
+ )
+ )
+ layers.append(nn.BatchNorm3d(outplanes))
+
+ if act is not None:
+ layers.append(act())
+
+ return nn.Sequential(*layers)
+
+
+def resize(
+ input,
+ size=None,
+ scale_factor=None,
+ mode="nearest",
+ align_corners=None,
+ warning=True,
+):
+ if warning:
+ if size is not None and align_corners:
+ input_h, input_w = tuple(int(x) for x in input.shape[2:])
+ output_h, output_w = tuple(int(x) for x in size)
+ if output_h > input_h or output_w > output_h:
+ if (
+ (output_h > 1 and output_w > 1 and input_h > 1 and input_w > 1)
+ and (output_h - 1) % (input_h - 1)
+ and (output_w - 1) % (input_w - 1)
+ ):
+ warnings.warn(
+ f"When align_corners={align_corners}, "
+ "the output would more aligned if "
+ f"input size {(input_h, input_w)} is `x+1` and "
+ f"out size {(output_h, output_w)} is `nx+1`"
+ )
+ if isinstance(size, torch.Size):
+ size = tuple(int(x) for x in size)
+ return F.interpolate(input, size, scale_factor, mode, align_corners)
+
+
+class InceptionBlock(nn.Module):
+ def __init__(self, inplanes, outplanes, stride=1, pool_size=3):
+ self.inplanes = inplanes
+ self.outplanes = outplanes
+ self.stride = stride
+ self.pool_size = pool_size
+ super(InceptionBlock, self).__init__()
+
+ self.pw_block = point_wise_block(self.inplanes, self.outplanes // 4)
+ self.mp_layer = nn.MaxPool2d(
+ kernel_size=self.pool_size, stride=stride, padding=1
+ )
+ self.conv3_block = conv_block(
+ self.outplanes // 4, self.outplanes // 4, kernel_size=3, stride=1, padding=1
+ )
+ self.conv5_block = conv_block(
+ self.outplanes // 4, self.outplanes // 4, kernel_size=5, stride=1, padding=2
+ )
+
+ def forward(self, x):
+ x1 = self.pw_block(x)
+
+ x2 = self.pw_block(x)
+ x2 = self.conv3_block(x2)
+
+ x3 = self.pw_block(x)
+ x3 = self.conv5_block(x3)
+
+ x4 = self.mp_layer(x)
+ x4 = self.pw_block(x4)
+
+ x = torch.cat((x1, x2, x3, x4), dim=1)
+ return x
+
+
+class InceptionBlock3D(nn.Module):
+ def __init__(self, inplanes, outplanes, stride=1, pool_size=3):
+ self.inplanes = inplanes
+ self.outplanes = outplanes
+ self.stride = stride
+ self.pool_size = pool_size
+ super(InceptionBlock3D, self).__init__()
+
+ self.pw_block = conv3d_block(
+ self.inplanes,
+ self.outplanes // 4,
+ kernel_size=(1, 1, 1),
+ stride=(1, 1, 1),
+ act=nn.ReLU,
+ )
+ self.mp_layer = nn.MaxPool3d(
+ kernel_size=(self.pool_size, 1, 1), stride=stride, padding=(1, 0, 0)
+ )
+ self.conv3_block = conv3d_block(
+ self.outplanes // 4,
+ self.outplanes // 4,
+ kernel_size=(3, 1, 1),
+ stride=1,
+ padding=(1, 0, 0),
+ act=nn.ReLU,
+ )
+ self.conv5_block = conv3d_block(
+ self.outplanes // 4,
+ self.outplanes // 4,
+ kernel_size=(5, 1, 1),
+ stride=1,
+ padding=(2, 0, 0),
+ act=nn.ReLU,
+ )
+
+ def forward(self, x):
+ x1 = self.pw_block(x)
+
+ x2 = self.pw_block(x)
+ x2 = self.conv3_block(x2)
+
+ x3 = self.pw_block(x)
+ x3 = self.conv5_block(x3)
+
+ x4 = self.mp_layer(x)
+ x4 = self.pw_block(x4)
+
+ x = torch.cat((x1, x2, x3, x4), dim=1)
+ return x
+
+
+class SELayer(nn.Module):
+ def __init__(self, channel, reduction=16):
+ super(SELayer, self).__init__()
+ self.avg_pool = nn.AdaptiveAvgPool2d(1)
+ self.fc = nn.Sequential(
+ nn.Linear(channel, channel // reduction, bias=False),
+ nn.ReLU(inplace=True),
+ nn.Linear(channel // reduction, channel, bias=False),
+ nn.Sigmoid(),
+ )
+
+ def forward(self, x):
+ b, c, _, _ = x.size()
+ y = self.avg_pool(x).view(b, c)
+ y = self.fc(y).view(b, c, 1, 1)
+ return x * y.expand_as(x)
+
+
+class Texture_Enhance(nn.Module):
+ def __init__(self, num_features):
+ super().__init__()
+ # self.output_features=num_features
+ self.output_features = num_features * 4
+ self.output_features_d = num_features
+ self.conv0 = nn.Conv2d(num_features, num_features, 1)
+ self.conv1 = nn.Conv2d(num_features, num_features, 3, padding=1)
+ self.bn1 = nn.BatchNorm2d(num_features)
+ self.conv2 = nn.Conv2d(num_features * 2, num_features, 3, padding=1)
+ self.bn2 = nn.BatchNorm2d(2 * num_features)
+ self.conv3 = nn.Conv2d(num_features * 3, num_features, 3, padding=1)
+ self.bn3 = nn.BatchNorm2d(3 * num_features)
+ self.conv_last = nn.Conv2d(num_features * 4, num_features * 4, 1)
+ self.bn4 = nn.BatchNorm2d(4 * num_features)
+ self.bn_last = nn.BatchNorm2d(num_features * 4)
+
+ def forward(self, feature_maps, attention_maps=(1, 1)):
+ B, N, H, W = feature_maps.shape
+
+ if type(attention_maps) == tuple:
+ attention_size = (int(H * attention_maps[0]), int(W * attention_maps[1]))
+ else:
+ attention_size = (attention_maps.shape[2], attention_maps.shape[3])
+
+ feature_maps_d = F.adaptive_avg_pool2d(feature_maps, attention_size)
+ feature_maps = feature_maps - F.interpolate(
+ feature_maps_d,
+ (feature_maps.shape[2], feature_maps.shape[3]),
+ mode="nearest",
+ )
+ feature_maps0 = self.conv0(feature_maps)
+ feature_maps1 = self.conv1(F.relu(self.bn1(feature_maps0), inplace=True))
+ feature_maps1_ = torch.cat([feature_maps0, feature_maps1], dim=1)
+ feature_maps2 = self.conv2(F.relu(self.bn2(feature_maps1_), inplace=True))
+ feature_maps2_ = torch.cat([feature_maps1_, feature_maps2], dim=1)
+ feature_maps3 = self.conv3(F.relu(self.bn3(feature_maps2_), inplace=True))
+ feature_maps3_ = torch.cat([feature_maps2_, feature_maps3], dim=1)
+ feature_maps = self.bn_last(
+ self.conv_last(F.relu(self.bn4(feature_maps3_), inplace=True))
+ )
+ return feature_maps
diff --git a/clean/video/fakestormer/models/networks/detectors/__init__.py b/clean/video/fakestormer/models/networks/detectors/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..b4ae7526c86df36e6ffc0adb335e13975e53def0
--- /dev/null
+++ b/clean/video/fakestormer/models/networks/detectors/__init__.py
@@ -0,0 +1,5 @@
+# -*- coding:utf-8 -*-
+from .base import BaseDetector
+from .topdown import TopDownDetector
+
+__all__ = ["BaseDetector", "TopDownDetector"]
diff --git a/clean/video/fakestormer/models/networks/detectors/base.py b/clean/video/fakestormer/models/networks/detectors/base.py
new file mode 100644
index 0000000000000000000000000000000000000000..b22c4cb88eb959bf0c3b81811e9561b1a1b85a58
--- /dev/null
+++ b/clean/video/fakestormer/models/networks/detectors/base.py
@@ -0,0 +1,145 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) OpenMMLab. All rights reserved.
+import os
+import sys
+
+if not os.getcwd() in sys.path:
+ sys.path.append(os.getcwd())
+from abc import ABCMeta, abstractmethod
+from collections import OrderedDict
+from typing import Tuple, Union
+
+import torch
+import torch.distributed as dist
+import torch.nn as nn
+from models.builder import DETECTORS
+
+
+@DETECTORS.register_module()
+class BaseDetector(nn.Module, metaclass=ABCMeta):
+ """Base class for pose detectors.
+
+ All recognizers should subclass it.
+ All subclass should overwrite:
+ Methods:`forward_train`, supporting to forward when training.
+ Methods:`forward_test`, supporting to forward when testing.
+
+ Args:
+ backbone (dict): Backbone modules to extract feature.
+ head (dict): Head modules to give output.
+ train_cfg (dict): Config for training. Default: None.
+ test_cfg (dict): Config for testing. Default: None.
+ """
+
+ @abstractmethod
+ def forward_train(self, img, img_metas, **kwargs):
+ """Defines the computation performed at training."""
+
+ @abstractmethod
+ def forward_test(self, img, img_metas, **kwargs):
+ """Defines the computation performed at testing."""
+
+ @abstractmethod
+ def forward(self, img, img_metas, return_loss=True, **kwargs):
+ """Forward function."""
+
+ @staticmethod
+ def _parse_losses(losses):
+ """Parse the raw outputs (losses) of the network.
+
+ Args:
+ losses (dict): Raw output of the network, which usually contain
+ losses and other necessary information.
+
+ Returns:
+ tuple[Tensor, dict]: (loss, log_vars), loss is the loss tensor \
+ which may be a weighted sum of all losses, log_vars \
+ contains all the variables to be sent to the logger.
+ """
+ log_vars = OrderedDict()
+ for loss_name, loss_value in losses.items():
+ if isinstance(loss_value, torch.Tensor):
+ log_vars[loss_name] = loss_value.mean()
+ elif isinstance(loss_value, float):
+ log_vars[loss_name] = loss_value
+ elif isinstance(loss_value, list):
+ log_vars[loss_name] = sum(_loss.mean() for _loss in loss_value)
+ else:
+ raise TypeError(
+ f"{loss_name} is not a tensor or list of tensors or float"
+ )
+
+ loss = sum(_value for _key, _value in log_vars.items() if "loss" in _key)
+
+ log_vars["loss"] = loss
+ for loss_name, loss_value in log_vars.items():
+ # reduce loss when distributed training
+ if not isinstance(loss_value, float):
+ if dist.is_available() and dist.is_initialized():
+ loss_value = loss_value.data.clone()
+ dist.all_reduce(loss_value.div_(dist.get_world_size()))
+ log_vars[loss_name] = loss_value.item()
+ else:
+ log_vars[loss_name] = loss_value
+
+ return loss, log_vars
+
+ def train_step(self, data_batch, optimizer, **kwargs):
+ """The iteration step during training.
+
+ This method defines an iteration step during training, except for the
+ back propagation and optimizer updating, which are done in an optimizer
+ hook. Note that in some complicated cases or models, the whole process
+ including back propagation and optimizer updating is also defined in
+ this method, such as GAN.
+
+ Args:
+ data_batch (dict): The output of dataloader.
+ optimizer (:obj:`torch.optim.Optimizer` | dict): The optimizer of
+ runner is passed to ``train_step()``. This argument is unused
+ and reserved.
+
+ Returns:
+ dict: It should contain at least 3 keys: ``loss``, ``log_vars``,
+ ``num_samples``.
+ ``loss`` is a tensor for back propagation, which can be a
+ weighted sum of multiple losses.
+ ``log_vars`` contains all the variables to be sent to the
+ logger.
+ ``num_samples`` indicates the batch size (when the model is
+ DDP, it means the batch size on each GPU), which is used for
+ averaging the logs.
+ """
+ losses = self.forward(**data_batch)
+
+ loss, log_vars = self._parse_losses(losses)
+
+ outputs = dict(
+ loss=loss,
+ log_vars=log_vars,
+ num_samples=len(next(iter(data_batch.values()))),
+ )
+
+ return outputs
+
+ def val_step(self, data_batch, optimizer, **kwargs):
+ """The iteration step during validation.
+
+ This method shares the same signature as :func:`train_step`, but used
+ during val epochs. Note that the evaluation after training epochs is
+ not implemented with this method, but an evaluation hook.
+ """
+ results = self.forward(return_loss=False, **data_batch)
+
+ outputs = dict(results=results)
+
+ return outputs
+
+ # @abstractmethod
+ # def show_result(self, **kwargs):
+ # """Visualize the results."""
+ # raise NotImplementedError
+
+
+if __name__ == "__main__":
+ print(BaseDetector._version)
diff --git a/clean/video/fakestormer/models/networks/detectors/topdown.py b/clean/video/fakestormer/models/networks/detectors/topdown.py
new file mode 100644
index 0000000000000000000000000000000000000000..74f523d8c1b22d626d3f8909dc4ddd8a48fc50be
--- /dev/null
+++ b/clean/video/fakestormer/models/networks/detectors/topdown.py
@@ -0,0 +1,174 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) OpenMMLab. All rights reserved.
+import warnings
+
+import mmcv
+import numpy as np
+
+try:
+ from mmcv.runner import auto_fp16
+except:
+ raise ValueError("Please try to install mmcv==1.3.9")
+
+from ...builder import BACKBONES, DETECTORS, HEADS, NECKS
+from .base import BaseDetector
+
+
+@DETECTORS.register_module()
+class TopDownDetector(BaseDetector):
+ """Top-down pose detectors.
+
+ Args:
+ backbone (dict): Backbone modules to extract feature.
+ keypoint_head (dict): Keypoint head to process feature.
+ train_cfg (dict): Config for training. Default: None.
+ test_cfg (dict): Config for testing. Default: None.
+ pretrained (str): Path to the pretrained models.
+ loss_pose (None): Deprecated arguments. Please use
+ `loss_keypoint` for heads instead.
+ """
+
+ def __init__(
+ self,
+ backbone,
+ neck=None,
+ keypoint_head=None,
+ train_cfg=None,
+ test_cfg=None,
+ loss_pose=None,
+ **kwargs,
+ ):
+ super().__init__()
+ self.fp16_enabled = False
+
+ self.backbone = BACKBONES.build(backbone)
+
+ self.train_cfg = train_cfg
+ self.test_cfg = test_cfg
+
+ if neck is not None:
+ self.neck = NECKS.build(neck)
+
+ if keypoint_head is not None:
+ keypoint_head["train_cfg"] = train_cfg
+ keypoint_head["test_cfg"] = test_cfg
+
+ if "loss_keypoint" not in keypoint_head and loss_pose is not None:
+ warnings.warn(
+ "`loss_pose` for TopDown is deprecated, "
+ "use `loss_keypoint` for heads instead. See "
+ "https://github.com/open-mmlab/mmpose/pull/382"
+ " for more information.",
+ DeprecationWarning,
+ )
+ keypoint_head["loss_keypoint"] = loss_pose
+
+ self.keypoint_head = HEADS.build(keypoint_head)
+
+ @property
+ def with_neck(self):
+ """Check if has neck."""
+ return hasattr(self, "neck")
+
+ @property
+ def with_keypoint(self):
+ """Check if has keypoint_head."""
+ return hasattr(self, "keypoint_head")
+
+ def init_weights(self, pretrained=None):
+ """Weight initialization for model."""
+ self.backbone.init_weights(pretrained=pretrained)
+ if self.with_neck:
+ self.neck.init_weights()
+ if self.with_keypoint:
+ self.keypoint_head.init_weights()
+
+ def forward(self, img, **kwargs):
+ output = self.backbone(img, **kwargs)
+
+ if self.with_neck:
+ output = self.neck(output, **kwargs)
+
+ if self.with_keypoint:
+ output = self.keypoint_head(output, **kwargs)
+
+ return output
+
+ def forward_train(self, img, target, target_weight, img_metas, **kwargs):
+ """Defines the computation performed at every call when training."""
+ output = self.backbone(img)
+ if self.with_neck:
+ output = self.neck(output)
+ if self.with_keypoint:
+ output = self.keypoint_head(output)
+
+ # if return loss
+ losses = dict()
+ if self.with_keypoint:
+ keypoint_losses = self.keypoint_head.get_loss(output, target, target_weight)
+ losses.update(keypoint_losses)
+ keypoint_accuracy = self.keypoint_head.get_accuracy(
+ output, target, target_weight
+ )
+ losses.update(keypoint_accuracy)
+
+ return losses
+
+ def forward_test(self, img, img_metas, return_heatmap=False, **kwargs):
+ """Defines the computation performed at every call when testing."""
+ assert img.size(0) == len(img_metas)
+ batch_size, _, img_height, img_width = img.shape
+ if batch_size > 1:
+ assert "bbox_id" in img_metas[0]
+
+ result = {}
+
+ features = self.backbone(img)
+ if self.with_neck:
+ features = self.neck(features)
+ if self.with_keypoint:
+ output_heatmap = self.keypoint_head.inference_model(
+ features, flip_pairs=None
+ )
+
+ if self.test_cfg.get("flip_test", True):
+ img_flipped = img.flip(3)
+ features_flipped = self.backbone(img_flipped)
+ if self.with_neck:
+ features_flipped = self.neck(features_flipped)
+ if self.with_keypoint:
+ output_flipped_heatmap = self.keypoint_head.inference_model(
+ features_flipped, img_metas[0]["flip_pairs"]
+ )
+ output_heatmap = (output_heatmap + output_flipped_heatmap) * 0.5
+
+ if self.with_keypoint:
+ keypoint_result = self.keypoint_head.decode(
+ img_metas, output_heatmap, img_size=[img_width, img_height]
+ )
+ result.update(keypoint_result)
+
+ if not return_heatmap:
+ output_heatmap = None
+
+ result["output_heatmap"] = output_heatmap
+
+ return result
+
+ def forward_dummy(self, img):
+ """Used for computing network FLOPs.
+
+ See ``tools/get_flops.py``.
+
+ Args:
+ img (torch.Tensor): Input image.
+
+ Returns:
+ Tensor: Output heatmaps.
+ """
+ output = self.backbone(img)
+ if self.with_neck:
+ output = self.neck(output)
+ if self.with_keypoint:
+ output = self.keypoint_head(output)
+ return output
diff --git a/clean/video/fakestormer/models/networks/heads/__init__.py b/clean/video/fakestormer/models/networks/heads/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..d75583dbcccfdb02545e8181f9bc39cf7b71f34f
--- /dev/null
+++ b/clean/video/fakestormer/models/networks/heads/__init__.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+from .hm_base_head import TopdownHeatmapBaseHead
+from .hm_simple_head import TopdownHeatmapSimpleHead
+
+__all__ = ["TopdownHeatmapBaseHead", "TopdownHeatmapSimpleHead"]
diff --git a/clean/video/fakestormer/models/networks/heads/head_design.py b/clean/video/fakestormer/models/networks/heads/head_design.py
new file mode 100644
index 0000000000000000000000000000000000000000..2553470a89638b864507cdfac72271148a2ec06e
--- /dev/null
+++ b/clean/video/fakestormer/models/networks/heads/head_design.py
@@ -0,0 +1,225 @@
+# -*- coding: utf-8 -*-
+from typing import List, Optional, Tuple, Union
+
+import torch
+import torch.nn as nn
+
+from ..common import conv3d_block, conv_block
+
+
+class ClassificationHead(nn.Module):
+ def __init__(
+ self,
+ in_planes,
+ out_planes,
+ stages: Optional[List] = [],
+ return_prob: bool = False,
+ last_act: str = "sigmoid",
+ drop: float = 0.0,
+ **kwargs,
+ ):
+ """
+ General classification head
+
+ Args:
+ stages: indicate a list of outputs of hidden layers between in_planes and out_planes
+ """
+ super().__init__()
+ self.return_prob = return_prob
+ self.drop = drop
+ self.in_planes = in_planes
+ self.global_avg = kwargs.get("avg_pool") or False
+
+ if self.global_avg:
+ if kwargs.get("features") == "3D":
+ self.avg_pool = nn.AdaptiveAvgPool3d((1, 1, 1))
+ else:
+ self.avg_pool = nn.AdaptiveAvgPool3d((1, 1))
+
+ # Initialize layers
+ layers = []
+ for stage_plane in stages:
+ layers.append(nn.Linear(in_planes, stage_plane))
+ layers.append(nn.GELU())
+ layers.append(nn.Dropout(self.drop))
+ in_planes = stage_plane
+
+ self.fc1 = nn.Sequential(*layers) if len(layers) else nn.Identity()
+ self.fc_out = nn.Linear(self.in_planes, out_planes)
+
+ if last_act == "sigmoid":
+ self.act = nn.Sigmoid()
+ else:
+ self.act = nn.Softmax(dim=-1)
+
+ def forward(self, x) -> torch.tensor:
+ B = x.shape[0]
+
+ if self.global_avg:
+ num_channels = x.shape[1]
+ x = self.avg_pool(x).view(B, -1, num_channels)
+
+ assert self.in_planes == x.shape[-1]
+ x = self.fc1(x)
+
+ if x.ndim == 3:
+ x = x.reshape((B, -1))
+
+ x = self.fc_out(x)
+
+ if self.return_prob:
+ results = self.act(x)
+ else:
+ results = x
+
+ return results
+
+
+class RegressionHead(nn.Module):
+ def __init__(
+ self,
+ input_shape,
+ out_planes,
+ kernel_size,
+ padding,
+ conv_2direction=False,
+ extra=None,
+ **kwargs,
+ ):
+ """
+ General regression head for dense predictions like keypoints regression, etc
+
+ Args:
+ input_shape: [C, H, W]
+ conv_2direction: Specially design to compute derivative tx, ty from temporal tokens in video input. i.e. FakeSTormer
+ """
+ super().__init__()
+ self.conv_2direction = conv_2direction
+
+ conv_channels = input_shape[0]
+
+ layers = []
+ if extra is not None:
+ num_conv_layers = extra.get("num_conv_layers", 0)
+ num_conv_kernels = extra.get("num_conv_kernels", [1] * num_conv_layers)
+
+ for i in range(num_conv_layers):
+ layers.append(
+ conv_block(
+ inplanes=conv_channels,
+ outplanes=conv_channels,
+ kernel_size=kernel_size,
+ padding=padding,
+ )
+ )
+ self.before_proj = nn.Sequential(*layers) if len(layers) else nn.Identity()
+
+ if not conv_2direction:
+ self.proj = nn.Conv2d(
+ in_channels=input_shape[0],
+ out_channels=out_planes,
+ kernel_size=kernel_size,
+ padding=padding,
+ )
+ else:
+ self.d_tx = conv_block(
+ inplanes=input_shape[1],
+ outplanes=input_shape[1],
+ kernel_size=kernel_size,
+ padding=padding,
+ )
+
+ self.d_ty = conv_block(
+ inplanes=input_shape[2],
+ outplanes=input_shape[2],
+ kernel_size=kernel_size,
+ padding=padding,
+ )
+
+ self.proj = nn.Conv2d(
+ in_channels=int(input_shape[0] * 2),
+ out_channels=out_planes,
+ kernel_size=kernel_size,
+ padding=padding,
+ )
+
+ def forward(self, x):
+ assert x.ndim == 4
+ B, C, H, W = x.shape
+ x = self.before_proj(x)
+
+ if self.conv_2direction:
+ x_tx = self.d_tx(x.transpose(1, 2)).transpose(2, 1)
+ x_ty = self.d_ty(x.transpose(1, 3)).transpose(3, 1)
+ x = torch.cat((x_tx, x_ty), 1)
+ x = self.proj(x)
+
+ return x
+
+
+class TemporalRegressionHead(nn.Module):
+ def __init__(
+ self,
+ inplanes: int,
+ outplanes: int,
+ kernel_size: Union[int, Tuple] = (3, 1, 1),
+ stride: Union[int, Tuple] = (1, 1, 1),
+ padding: Union[int, Tuple] = (1, 0, 0),
+ extra: Optional[dict] = None,
+ act: nn.Module = nn.GELU,
+ **kwargs,
+ ):
+ super().__init__(**kwargs)
+ """
+ General head design for 3D feature maps
+ args:
+ inplanes: number of in channels
+ outplanes: number of out channels
+ extra: doing extra operation before predicting final outputs
+ """
+ layers = []
+ if extra is not None:
+ num_conv_layers = extra.get("num_conv_layers", 0)
+ num_conv_kernels = extra.get("num_conv_kernels", [1] * num_conv_layers)
+
+ for i in range(num_conv_layers):
+ layers.append(
+ conv3d_block(
+ inplanes=inplanes,
+ outplanes=inplanes,
+ kernel_size=kernel_size,
+ stride=stride,
+ padding=padding,
+ bias=True,
+ inplace=True,
+ act=act,
+ )
+ )
+ self.before_proj = nn.Sequential(*layers) if len(layers) else nn.Identity()
+ self.proj = nn.Sequential(
+ conv3d_block(
+ inplanes=inplanes,
+ outplanes=inplanes // 4,
+ stride=stride,
+ kernel_size=kernel_size,
+ padding=padding,
+ bias=True,
+ inplace=True,
+ act=act,
+ ),
+ nn.Conv3d(
+ inplanes // 4,
+ outplanes,
+ kernel_size=kernel_size,
+ stride=stride,
+ padding=padding,
+ bias=True,
+ ),
+ )
+
+ def forward(self, x):
+ assert x.ndim == 5
+
+ x = self.before_proj(x)
+ out = self.proj(x)
+ return out
diff --git a/clean/video/fakestormer/models/networks/heads/hm_base_head.py b/clean/video/fakestormer/models/networks/heads/hm_base_head.py
new file mode 100644
index 0000000000000000000000000000000000000000..6489d4f32097042ea0746403ddf48c938a1647fe
--- /dev/null
+++ b/clean/video/fakestormer/models/networks/heads/hm_base_head.py
@@ -0,0 +1,54 @@
+# Copyright (c) OpenMMLab. All rights reserved.
+# -*- coding: utf-8 -*-
+from abc import ABCMeta, abstractmethod
+
+import numpy as np
+import torch.nn as nn
+
+
+class TopdownHeatmapBaseHead(nn.Module):
+ """Base class for top-down heatmap heads.
+
+ All top-down heatmap heads should subclass it.
+ All subclass should overwrite:
+
+ Methods:`loss`, supporting to calculate loss.
+ Methods:`accuracy`, supporting to calculate accuracy.
+ Methods:`forward`, supporting to forward model.
+ Methods:`predict`, supporting to inference model.
+ """
+
+ __metaclass__ = ABCMeta
+
+ @abstractmethod
+ def loss(self, **kwargs):
+ """Gets the loss."""
+
+ @abstractmethod
+ def accuracy(self, **kwargs):
+ """Gets the accuracy."""
+
+ @abstractmethod
+ def forward(self, **kwargs):
+ """Forward function."""
+
+ @abstractmethod
+ def predict(self, **kwargs):
+ """Inference function."""
+
+ @staticmethod
+ def _get_deconv_cfg(deconv_kernel):
+ """Get configurations for deconv layers."""
+ if deconv_kernel == 4:
+ padding = 1
+ output_padding = 0
+ elif deconv_kernel == 3:
+ padding = 1
+ output_padding = 1
+ elif deconv_kernel == 2:
+ padding = 0
+ output_padding = 0
+ else:
+ raise ValueError(f"Not supported num_kernels ({deconv_kernel}).")
+
+ return deconv_kernel, padding, output_padding
diff --git a/clean/video/fakestormer/models/networks/heads/hm_simple_head.py b/clean/video/fakestormer/models/networks/heads/hm_simple_head.py
new file mode 100644
index 0000000000000000000000000000000000000000..c27c331e9e13a12d19e15561aebe50a45f90a4e7
--- /dev/null
+++ b/clean/video/fakestormer/models/networks/heads/hm_simple_head.py
@@ -0,0 +1,378 @@
+# Copyright (c) OpenMMLab. All rights reserved.
+# -*- coding: utf-8 -*-
+import os
+import sys
+from typing import Dict, Union
+
+if not os.getcwd() in sys.path:
+ sys.path.append(os.getcwd())
+
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+from einops import rearrange, reduce, repeat
+from losses import LOSSES, build_losses
+from mmcv.cnn import (
+ build_conv_layer,
+ build_norm_layer,
+ build_upsample_layer,
+ constant_init,
+ normal_init,
+)
+from models.builder import HEADS
+
+from ..common import BN_MOMENTUM, conv_block, resize
+from .head_design import ClassificationHead, RegressionHead, TemporalRegressionHead
+from .hm_base_head import TopdownHeatmapBaseHead
+
+
+@HEADS.register_module()
+class TopdownHeatmapSimpleHead(TopdownHeatmapBaseHead):
+ """Top-down heatmap simple head. paper ref: Bin Xiao et al. ``Simple
+ Baselines for Human Pose Estimation and Tracking``.
+
+ TopdownHeatmapSimpleHead is consisted of (>=0) number of deconv layers
+ and a simple conv2d layer.
+
+ Args:
+ in_channels (int): Number of input channels
+ out_channels (int): Number of output channels
+ num_deconv_layers (int): Number of deconv layers.
+ num_deconv_layers should >= 0. Note that 0 means
+ no deconv layers.
+ num_deconv_filters (list|tuple): Number of filters.
+ If num_deconv_layers > 0, the length of
+ num_deconv_kernels (list|tuple): Kernel sizes.
+ in_index (int|Sequence[int]): Input feature index. Default: 0
+ input_transform (str|None): Transformation type of input features.
+ Options: 'resize_concat', 'multiple_select', None.
+ Default: None.
+
+ - 'resize_concat': Multiple feature maps will be resized to the
+ same size as the first one and then concat together.
+ Usually used in FCN head of HRNet.
+ - 'multiple_select': Multiple feature maps will be bundle into
+ a list and passed into decode head.
+ - None: Only one select feature map is allowed.
+ align_corners (bool): align_corners argument of F.interpolate.
+ Default: False.
+ loss_keypoint (dict): Config for keypoint loss. Default: None.
+ """
+
+ def __init__(
+ self,
+ in_channels,
+ heads,
+ extra=None,
+ hm_size=[14, 14],
+ in_index=0,
+ input_transform=None,
+ align_corners=False,
+ loss_keypoint=None,
+ train_cfg=None,
+ test_cfg=None,
+ upsample=0,
+ conv_2direction=False,
+ use_temp_token=False,
+ features="2D",
+ act="GELU",
+ **kwargs,
+ ):
+ super().__init__()
+
+ self.in_channels = in_channels
+ self.loss = build_losses(loss_keypoint, LOSSES)
+ self.upsample = upsample
+ self.use_temp_token = use_temp_token
+
+ self.train_cfg = {} if train_cfg is None else train_cfg
+ self.test_cfg = {} if test_cfg is None else test_cfg
+ self.target_type = self.test_cfg.get("target_type", "GaussianHeatmap")
+
+ self._init_inputs(in_channels, in_index, input_transform)
+ self.in_index = in_index
+ self.align_corners = align_corners
+
+ assert (
+ isinstance(heads, dict) and heads is not None
+ ), "Head config can not be None!"
+ self.heads = heads
+
+ if extra is not None and not isinstance(extra, dict):
+ raise TypeError("extra should be dict or None.")
+
+ identity_final_layer = False
+ if extra is not None and "final_conv_kernel" in extra:
+ assert extra["final_conv_kernel"] in [0, 1, 3]
+ if extra["final_conv_kernel"] == 3:
+ padding = 1
+ elif extra["final_conv_kernel"] == 1:
+ padding = 0
+ else:
+ # 0 for Identity mapping.
+ identity_final_layer = True
+ kernel_size = extra["final_conv_kernel"]
+ else:
+ kernel_size = 1
+ padding = 0
+
+ final_layer = {}
+ if not identity_final_layer:
+ for head, out_channel in self.heads.items():
+ if head == "hm" or head == "cstency":
+ if features == "2D":
+ layer = RegressionHead(
+ input_shape=(self.in_channels, hm_size[0], hm_size[1]),
+ out_planes=out_channel,
+ kernel_size=kernel_size,
+ padding=padding,
+ extra=extra,
+ conv_2direction=conv_2direction,
+ )
+ elif features == "3D":
+ act_func = nn.GELU if act == "GELU" else nn.ReLU
+ layer = TemporalRegressionHead(
+ inplanes=self.in_channels,
+ outplanes=out_channel,
+ extra=extra,
+ act=act_func,
+ )
+ else:
+ raise ValueError(
+ "Only support 2D or 3D features, please check your feature dimension!"
+ )
+ final_layer[head] = layer
+ elif head == "cls":
+ layer = ClassificationHead(
+ in_planes=self.in_channels,
+ out_planes=out_channel,
+ return_prob=False,
+ last_act="sigmoid",
+ drop=0.2,
+ features=features,
+ avg_pool=kwargs.get("avg_pool"),
+ )
+ final_layer[head] = layer
+ elif head == "temp_loc":
+ layer = ClassificationHead(
+ in_planes=self.in_channels,
+ out_planes=out_channel,
+ stages=[self.in_channels // out_channel],
+ return_prob=False,
+ last_act="sigmoid",
+ drop=0.2,
+ )
+ final_layer[head] = layer
+ else:
+ final_layer["cls"] = nn.Identity()
+
+ for k, l in final_layer.items():
+ self.__setattr__(k, l)
+
+ def _init_inputs(self, in_channels, in_index, input_transform):
+ """Check and initialize input transforms.
+
+ The in_channels, in_index and input_transform must match.
+ Specifically, when input_transform is None, only single feature map
+ will be selected. So in_channels and in_index must be of type int.
+ When input_transform is not None, in_channels and in_index must be
+ list or tuple, with the same length.
+
+ Args:
+ in_channels (int|Sequence[int]): Input channels.
+ in_index (int|Sequence[int]): Input feature index.
+ input_transform (str|None): Transformation type of input features.
+ Options: 'resize_concat', 'multiple_select', None.
+
+ - 'resize_concat': Multiple feature maps will be resize to the
+ same size as first one and than concat together.
+ Usually used in FCN head of HRNet.
+ - 'multiple_select': Multiple feature maps will be bundle into
+ a list and passed into decode head.
+ - None: Only one select feature map is allowed.
+ """
+
+ if input_transform is not None:
+ assert input_transform in ["resize_concat", "multiple_select"]
+ self.input_transform = input_transform
+ self.in_index = in_index
+ if input_transform is not None:
+ assert isinstance(in_channels, (list, tuple))
+ assert isinstance(in_index, (list, tuple))
+ assert len(in_channels) == len(in_index)
+ if input_transform == "resize_concat":
+ self.in_channels = sum(in_channels)
+ else:
+ self.in_channels = in_channels
+ else:
+ assert isinstance(in_channels, int)
+ assert isinstance(in_index, int)
+ self.in_channels = in_channels
+
+ def _transform_inputs(self, inputs: Union[torch.tensor, Dict[str, torch.tensor]]):
+ """Transform inputs for decoder.
+
+ Args:
+ inputs (list[Tensor] | Tensor): multi-level img features.
+
+ Returns:
+ Tensor: The transformed inputs
+ """
+ additional_inputs = {}
+
+ if isinstance(inputs, dict):
+ # assert 'embed' in inputs.keys(), "Embed token must be present in the input dict key"
+ for k in inputs.keys():
+ if k != "embed":
+ additional_inputs[k] = inputs[k]
+ inputs = inputs["embed"] if "embed" in inputs.keys() else None
+
+ if not isinstance(inputs, list):
+ if not isinstance(inputs, list):
+ if self.upsample > 0:
+ inputs = resize(
+ input=F.relu(inputs),
+ scale_factor=self.upsample,
+ mode="bilinear",
+ align_corners=self.align_corners,
+ )
+ return inputs, additional_inputs
+
+ if self.input_transform == "resize_concat":
+ inputs = [inputs[i] for i in self.in_index]
+ upsampled_inputs = [
+ resize(
+ input=x,
+ size=inputs[0].shape[2:],
+ mode="bilinear",
+ align_corners=self.align_corners,
+ )
+ for x in inputs
+ ]
+ inputs = torch.cat(upsampled_inputs, dim=1)
+ elif self.input_transform == "multiple_select":
+ inputs = [inputs[i] for i in self.in_index]
+ else:
+ inputs = inputs[self.in_index]
+
+ return inputs, additional_inputs
+
+ def _make_deconv_layer(self, num_layers, num_filters, num_kernels):
+ """Make deconv layers."""
+ if num_layers != len(num_filters):
+ error_msg = (
+ f"num_layers({num_layers}) "
+ f"!= length of num_filters({len(num_filters)})"
+ )
+ raise ValueError(error_msg)
+ if num_layers != len(num_kernels):
+ error_msg = (
+ f"num_layers({num_layers}) "
+ f"!= length of num_kernels({len(num_kernels)})"
+ )
+ raise ValueError(error_msg)
+
+ layers = []
+ for i in range(num_layers):
+ kernel, padding, output_padding = self._get_deconv_cfg(num_kernels[i])
+
+ planes = num_filters[i]
+ layers.append(
+ build_upsample_layer(
+ dict(type="deconv"),
+ in_channels=self.in_channels,
+ out_channels=planes,
+ kernel_size=kernel,
+ stride=2,
+ padding=padding,
+ output_padding=output_padding,
+ bias=False,
+ )
+ )
+ layers.append(nn.BatchNorm2d(planes))
+ layers.append(nn.ReLU(inplace=True))
+ self.in_channels = planes
+
+ return nn.Sequential(*layers)
+
+ def init_weights(self):
+ """Initialize model weights."""
+ for head in self.heads.keys():
+ for m in self.__getattr__(head).modules():
+ if isinstance(m, nn.Conv2d):
+ normal_init(m, std=0.001, bias=0)
+ elif isinstance(m, nn.BatchNorm2d):
+ constant_init(m, 1)
+
+ def forward(self, x, **kwargs):
+ """Forward function.
+ The input is multiscale feature maps and the output is the heatmap without post processing
+ """
+ x_embed, additional_inputs = self._transform_inputs(x)
+ if "temp_loc" in self.heads.keys():
+ if not self.use_temp_token:
+ B, L, T, H, W = x_embed.shape
+ x_temp_loc = x_embed.reshape(B, T, L, -1)
+ x_temp_loc = torch.max(x_temp_loc, dim=3, keepdim=False)[0]
+ else:
+ x_temp_loc = additional_inputs["s_cls_token"]
+
+ x_outs = {}
+ # for head in self.heads.keys():
+ if "cls" in self.heads.keys():
+ assert hasattr(
+ self, "cls"
+ ), "There must be a Classification Head, please check the head design!"
+ if bool(additional_inputs) and "cls" in additional_inputs.keys():
+ x_outs["cls"] = self.__getattr__("cls")(additional_inputs["cls"])
+ else:
+ x_outs["cls"] = self.__getattr__("cls")(x_embed)
+
+ # for head in self.heads.keys():
+ if "temp_loc" in self.heads.keys():
+ assert hasattr(
+ self, "temp_loc"
+ ), "There must be a head for temporal localization, please check the head design!"
+ x_outs["temp_loc"] = self.__getattr__("temp_loc")(x_temp_loc)
+
+ if "hm" in self.heads.keys():
+ assert hasattr(
+ self, "hm"
+ ), "There must always be a Heatmap Head in the head!"
+ x_outs["hm"] = self.__getattr__("hm")(x_embed)
+
+ if "cstency" in self.heads.keys():
+ assert hasattr(
+ self, "cstency"
+ ), "There must always be a Consistency Head in the head!"
+ x_outs["cstency"] = self.__getattr__("cstency")(x_embed)
+
+ return [x_outs]
+
+ def get_loss(self, output, target, target_weight):
+ """Calculate top-down keypoint loss.
+
+ Note:
+ - batch_size: N
+ - num_keypoints: K
+ - heatmaps height: H
+ - heatmaps weight: W
+
+ Args:
+ output (torch.Tensor[N,K,H,W]): Output heatmaps.
+ target (torch.Tensor[N,K,H,W]): Target heatmaps.
+ target_weight (torch.Tensor[N,K,1]):
+ Weights across different joint types.
+ """
+
+ losses = dict()
+
+ assert not isinstance(self.loss, nn.Sequential)
+ assert target.dim() == 4 and target_weight.dim() == 3
+ losses["heatmap_loss"] = self.loss(output, target, target_weight)
+
+ return losses
+
+
+if __name__ == "__main__":
+ cfg = {}
diff --git a/clean/video/fakestormer/models/networks/mrsa_resnet.py b/clean/video/fakestormer/models/networks/mrsa_resnet.py
new file mode 100644
index 0000000000000000000000000000000000000000..38172a90c9faf9be5a10bc1d2adee9cc65a5c4af
--- /dev/null
+++ b/clean/video/fakestormer/models/networks/mrsa_resnet.py
@@ -0,0 +1,490 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import, division, print_function
+
+import math
+import os
+
+import torch
+import torch.nn as nn
+import torch.utils.model_zoo as model_zoo
+from torch.nn.modules.activation import ReLU
+from torch.nn.modules.batchnorm import BatchNorm2d
+from torch.nn.modules.pooling import MaxPool2d
+
+from ..builder import MODELS, build_model
+from .common import (
+ BN_MOMENTUM,
+ InceptionBlock,
+ conv_block,
+ point_wise_block,
+)
+
+model_urls = {
+ "resnet18": "https://download.pytorch.org/models/resnet18-5c106cde.pth",
+ "resnet34": "https://download.pytorch.org/models/resnet34-333f7ec4.pth",
+ "resnet50": "https://download.pytorch.org/models/resnet50-19c8e357.pth",
+ "resnet101": "https://download.pytorch.org/models/resnet101-5d3b4d8f.pth",
+ "resnet152": "https://download.pytorch.org/models/resnet152-b121ed2d.pth",
+}
+
+
+def conv3x3(in_planes, out_planes, stride=1):
+ """3x3 convolution with padding"""
+ return nn.Conv2d(
+ in_planes, out_planes, kernel_size=3, stride=stride, padding=1, bias=False
+ )
+
+
+class BasicBlock(nn.Module):
+ expansion = 1
+
+ def __init__(self, inplanes, planes, stride=1, downsample=None):
+ super(BasicBlock, self).__init__()
+ self.conv1 = conv3x3(inplanes, planes, stride)
+ self.bn1 = nn.BatchNorm2d(planes, momentum=BN_MOMENTUM)
+ self.relu = nn.ReLU(inplace=True)
+ self.conv2 = conv3x3(planes, planes)
+ self.bn2 = nn.BatchNorm2d(planes, momentum=BN_MOMENTUM)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x):
+ residual = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+
+ if self.downsample is not None:
+ residual = self.downsample(x)
+
+ out += residual
+ out = self.relu(out)
+
+ return out
+
+ @staticmethod
+ def __repr__():
+ return "BasicBlock"
+
+
+class Bottleneck(nn.Module):
+ expansion = 4
+
+ def __init__(self, inplanes, planes, stride=1, downsample=None):
+ super(Bottleneck, self).__init__()
+ self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False)
+ self.bn1 = nn.BatchNorm2d(planes, momentum=BN_MOMENTUM)
+ self.conv2 = nn.Conv2d(
+ planes, planes, kernel_size=3, stride=stride, padding=1, bias=False
+ )
+ self.bn2 = nn.BatchNorm2d(planes, momentum=BN_MOMENTUM)
+ self.conv3 = nn.Conv2d(
+ planes, planes * self.expansion, kernel_size=1, bias=False
+ )
+ self.bn3 = nn.BatchNorm2d(planes * self.expansion, momentum=BN_MOMENTUM)
+ self.relu = nn.ReLU(inplace=True)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x):
+ residual = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+ out = self.relu(out)
+
+ out = self.conv3(out)
+ out = self.bn3(out)
+
+ if self.downsample is not None:
+ residual = self.downsample(x)
+
+ out += residual
+ out = self.relu(out)
+
+ return out
+
+ @staticmethod
+ def __repr__():
+ return "Bottleneck"
+
+
+@MODELS.register_module()
+class PoseResNet(nn.Module):
+ def __init__(
+ self,
+ block,
+ layers,
+ heads,
+ head_conv,
+ dropout_prob,
+ fpn=False,
+ cls_based_hm=True,
+ use_c2=False,
+ **kwargs,
+ ):
+ self.inplanes = 64
+ self.deconv_with_bias = False
+ self.heads = heads
+ self.fpn = fpn
+ self.cls_based_hm = cls_based_hm
+ self.use_c2 = use_c2
+
+ # Convert Cls name into Cls Object
+ if isinstance(block, str):
+ for bl in [BasicBlock, Bottleneck]:
+ if block == bl.__repr__():
+ block = bl
+
+ for k, v in kwargs.items():
+ if v is None:
+ raise ValueError(
+ f"The {k} argument receive a None value, Please check!"
+ )
+ self.__setattr__(k, v)
+
+ super(PoseResNet, self).__init__()
+ self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, bias=False)
+ self.bn1 = nn.BatchNorm2d(64, momentum=BN_MOMENTUM)
+ self.relu = nn.ReLU(inplace=True)
+ self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
+ self.layer1 = self._make_layer(block, 64, layers[0])
+ self.layer2 = self._make_layer(block, 128, layers[1], stride=2)
+ self.layer3 = self._make_layer(block, 256, layers[2], stride=2)
+ self.layer4 = self._make_layer(block, 512, layers[3], stride=2)
+
+ # Custom dropout layer
+ self.dropout_layer = nn.Dropout(dropout_prob)
+
+ if self.fpn:
+ # Adding sidmoid layer
+ self.sigmoid_layer = nn.Sigmoid()
+
+ # Adding pointwise block
+ self.pw_block_1 = self._point_wise_block(2048, 1024)
+
+ # used for deconv layers
+ deconv_filters = [256, 128, 256] if self.fpn else [256, 256, 256]
+ self.deconv_layers = self._make_deconv_layer(
+ 3,
+ deconv_filters,
+ [4, 4, 4],
+ )
+
+ # Adding inception block
+ if self.fpn:
+ for idx, deconv_layer in enumerate(self.deconv_layers):
+ self.__setattr__(f"deconv_layer_{idx}", nn.Sequential(deconv_layer))
+ self.pw_block_2 = self._point_wise_block(512, 512)
+ if self.use_c2:
+ self.pw_block_3 = self._point_wise_block(512, 256)
+ self.pw_block_c3 = self._point_wise_block(1024, 256)
+ self.pw_block_c2 = self._point_wise_block(512, 128)
+ self.inception_block = InceptionBlock(256, 256, stride=1, pool_size=3)
+
+ for head in sorted(self.heads):
+ num_output = self.heads[head]
+ if head_conv > 0:
+ if head != "cls":
+ fc = nn.Sequential(
+ nn.Conv2d(256, head_conv, kernel_size=3, padding=1, bias=True),
+ nn.BatchNorm2d(head_conv),
+ nn.ReLU(inplace=True),
+ nn.Conv2d(
+ head_conv, num_output, kernel_size=1, stride=1, padding=0
+ ),
+ )
+ else:
+ if self.cls_based_hm:
+ fc = nn.Sequential(
+ nn.AdaptiveMaxPool2d(head_conv // 4),
+ nn.Flatten(),
+ nn.Linear(
+ num_output * ((head_conv // 4) ** 2),
+ head_conv,
+ bias=True,
+ ),
+ nn.BatchNorm1d(head_conv, momentum=BN_MOMENTUM),
+ nn.ReLU(inplace=True),
+ nn.Linear(head_conv, 1, bias=True),
+ nn.Sigmoid(),
+ )
+ else:
+ fc = nn.Sequential(
+ nn.Conv2d(
+ 256, head_conv, kernel_size=3, padding=1, bias=True
+ ),
+ nn.BatchNorm2d(head_conv, momentum=BN_MOMENTUM),
+ nn.ReLU(inplace=True),
+ # nn.Conv2d(head_conv, num_output, kernel_size=1,
+ # stride=1, padding=0, bias=True),
+ # nn.BatchNorm2d(num_output),
+ # nn.ReLU(inplace=True),
+ # nn.AdaptiveMaxPool2d(head_conv//4),
+ nn.AdaptiveAvgPool2d(1),
+ nn.Flatten(),
+ # nn.Linear((head_conv//4)**2, head_conv, bias=True),
+ # nn.BatchNorm1d(head_conv, momentum=BN_MOMENTUM),
+ # nn.ReLU(inplace=True),
+ nn.Linear(head_conv, 1, bias=True),
+ # nn.Sigmoid()
+ )
+ else:
+ fc = nn.Conv2d(
+ in_channels=256,
+ out_channels=num_output,
+ kernel_size=1,
+ stride=1,
+ padding=0,
+ )
+ self.__setattr__(head, fc)
+
+ def _point_wise_block(self, inplanes, outplanes):
+ self.inplanes = outplanes
+ module = point_wise_block(inplanes, outplanes)
+ return module
+
+ def _conv_block(self, inplanes, outplanes, kernel_size, stride=1):
+ self.inplanes = outplanes
+ module = conv_block(inplanes, outplanes, kernel_size=kernel_size, stride=stride)
+ return module
+
+ def _make_layer(self, block, planes, blocks, stride=1):
+ downsample = None
+ if stride != 1 or self.inplanes != planes * block.expansion:
+ downsample = nn.Sequential(
+ nn.Conv2d(
+ self.inplanes,
+ planes * block.expansion,
+ kernel_size=1,
+ stride=stride,
+ bias=False,
+ ),
+ nn.BatchNorm2d(planes * block.expansion, momentum=BN_MOMENTUM),
+ )
+
+ layers = []
+ layers.append(block(self.inplanes, planes, stride, downsample))
+ self.inplanes = planes * block.expansion
+ for i in range(1, blocks):
+ layers.append(block(self.inplanes, planes))
+
+ return nn.Sequential(*layers)
+
+ def _get_deconv_cfg(self, deconv_kernel, index):
+ if deconv_kernel == 4:
+ padding = 1
+ output_padding = 0
+ elif deconv_kernel == 3:
+ padding = 1
+ output_padding = 1
+ elif deconv_kernel == 2:
+ padding = 0
+ output_padding = 0
+
+ return deconv_kernel, padding, output_padding
+
+ def _make_deconv_layer(self, num_layers, num_filters, num_kernels):
+ assert num_layers == len(
+ num_filters
+ ), "ERROR: num_deconv_layers is different len(num_deconv_filters)"
+ assert num_layers == len(
+ num_kernels
+ ), "ERROR: num_deconv_layers is different len(num_deconv_filters)"
+
+ layers = []
+ for i in range(num_layers):
+ kernel, padding, output_padding = self._get_deconv_cfg(num_kernels[i], i)
+
+ planes = num_filters[i]
+ layers.append(
+ nn.Sequential(
+ nn.ConvTranspose2d(
+ in_channels=self.inplanes,
+ out_channels=planes,
+ kernel_size=kernel,
+ stride=2,
+ padding=padding,
+ output_padding=output_padding,
+ bias=self.deconv_with_bias,
+ ),
+ nn.BatchNorm2d(planes, momentum=BN_MOMENTUM),
+ )
+ )
+ if not self.fpn:
+ layers.append(nn.ReLU(inplace=True))
+
+ self.inplanes = planes if not self.fpn else planes * 2
+
+ if self.fpn:
+ return layers
+ else:
+ return nn.Sequential(*layers)
+
+ def forward(self, x):
+ x = self.conv1(x)
+ x = self.bn1(x)
+ x = self.relu(x)
+ x = self.maxpool(x)
+
+ x1 = self.layer1(x) # 256 x 64 x 64
+ x2 = self.layer2(x1) # 512 x 32 x 32
+ x3 = self.layer3(x2) # 1024 x 16 x 16
+ x4 = self.layer4(x3) # 2048 x 8 x 8
+
+ # Custom dropout layer
+ x = self.dropout_layer(x4) # B x 8 x 8 x 2048
+ x3 = self.dropout_layer(x3)
+ x2 = self.dropout_layer(x2)
+ x1 = self.dropout_layer(x1)
+
+ # Custom FPN
+ if self.fpn:
+ assert isinstance(
+ self.deconv_layers, list
+ ), "To custom FPN, decompose deconv layers as a list!"
+ x = self.pw_block_1(x) # B x 1024 x 8 x 8
+ x = self.deconv_layer_0(x) # B x 256 x 16 x 16
+ # x = self.relu(x) # B x 256 x 16 x 16
+
+ x_weighted = self.sigmoid_layer(x) # B x 256 x 16 x 16
+ x_inverse = torch.sub(1, x_weighted, alpha=1) # B x 256 x 16 x 16
+ x3 = self.pw_block_c3(x3) # B x 256 x 16 x 16
+ x3_ = torch.multiply(x3, x_inverse) # B x 256 x 16 x 16
+ x = torch.cat((x, x3_), dim=1) # B x 512 x 16 x 16
+
+ x = self.pw_block_2(x) # B x 512 x 16 x 16
+ x = self.deconv_layer_1(x) # B x 128 x 32 x 32
+ # x = self.relu(x) #B x 128 x 32 x 32
+
+ x_weighted = self.sigmoid_layer(x) # B x 128 x 32 x 32
+ x_inverse = torch.sub(1, x_weighted, alpha=1) # B x 128 x 32 x 32
+ x2 = self.pw_block_c2(x2)
+ x2_ = torch.multiply(x2, x_inverse) # B x 128 x 32 x 32
+ x = torch.cat((x, x2_), dim=1) # B x 256 x 32 x 32
+
+ x = self.inception_block(x) # B x 256 x 64 x 64
+ x = self.deconv_layer_2(x) # B x 256 x 64 x 64
+
+ if self.use_c2:
+ x_weighted = self.sigmoid_layer(x)
+ x_inverse = torch.sub(1, x_weighted, alpha=1)
+ x1_ = torch.multiply(x1, x_inverse)
+ x = torch.cat((x, x1_), dim=1)
+ x = self.pw_block_3(x)
+ else:
+ x = self.relu(x) # B x 256 x 64 x 64
+ else:
+ assert isinstance(
+ self.deconv_layers, nn.Module
+ ), "Deconv Layer must be nn Module to compute!"
+ x = self.deconv_layers(x)
+
+ ret = {}
+ x1_hm = None
+ for head in self.heads:
+ if self.cls_based_hm and head == "cls" and x1_hm is not None:
+ x = x1_hm
+ elif head == "hm":
+ x1_hm = x
+
+ ret[head] = self.__getattr__(head)(x)
+
+ return [ret]
+
+ def init_weights(self, pretrained=True, **kwargs):
+ num_layers = kwargs.get("num_layers")
+ if pretrained:
+ if self.fpn:
+ for bl in [self.pw_block_1, self.pw_block_2]:
+ for _, l in bl.named_parameters():
+ if isinstance(l, nn.Conv2d):
+ nn.init.normal_(l.weight, std=0.001)
+ nn.init.constant_(l.bias, 0)
+
+ for _, l in self.inception_block.named_parameters():
+ if isinstance(l, nn.Conv2d):
+ nn.init.normal_(l.weight, std=0.001)
+ nn.init.constant_(l.bias, 0)
+
+ # print('=> init resnet deconv weights from normal distribution')
+ if isinstance(self.deconv_layers, nn.Module):
+ for _, m in self.deconv_layers.named_modules():
+ if isinstance(m, nn.ConvTranspose2d):
+ # print('=> init {}.weight as normal(0, 0.001)'.format(name))
+ # print('=> init {}.bias as 0'.format(name))
+ nn.init.normal_(m.weight, std=0.001)
+ if self.deconv_with_bias:
+ nn.init.constant_(m.bias, 0)
+ elif isinstance(m, nn.BatchNorm2d):
+ # print('=> init {}.weight as 1'.format(name))
+ # print('=> init {}.bias as 0'.format(name))
+ nn.init.constant_(m.weight, 1)
+ nn.init.constant_(m.bias, 0)
+ else:
+ for layer in [
+ self.deconv_layer_0,
+ self.deconv_layer_1,
+ self.deconv_layer_2,
+ ]:
+ for _, m in layer.named_modules():
+ if isinstance(m, nn.ConvTranspose2d):
+ # print('=> init {}.weight as normal(0, 0.001)'.format(name))
+ # print('=> init {}.bias as 0'.format(name))
+ nn.init.normal_(m.weight, std=0.001)
+ if self.deconv_with_bias:
+ nn.init.constant_(m.bias, 0)
+ elif isinstance(m, nn.BatchNorm2d):
+ # print('=> init {}.weight as 1'.format(name))
+ # print('=> init {}.bias as 0'.format(name))
+ nn.init.constant_(m.weight, 1)
+ nn.init.constant_(m.bias, 0)
+
+ # print('=> init final conv weights from normal distribution')
+ for head in self.heads:
+ final_layer = self.__getattr__(head)
+ for i, m in enumerate(final_layer.modules()):
+ if isinstance(m, nn.Conv2d):
+ # nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
+ # print('=> init {}.weight as normal(0, 0.001)'.format(name))
+ # print('=> init {}.bias as 0'.format(name))
+ if m.weight.shape[0] == self.heads[head]:
+ if "hm" in head:
+ nn.init.constant_(m.bias, -2.19)
+ else:
+ nn.init.normal_(m.weight, std=0.001)
+ nn.init.constant_(m.bias, 0)
+ # if isinstance(m, nn.Linear):
+ # if m.weight.shape[0] == self.heads[head]:
+ # prior = 1/71
+ # nn.init.constant_(m.bias, -math.log((1-prior)/prior))
+ # else:
+ # nn.init.normal_(m.weight, std=0.001)
+ # nn.init.constant_(m.bias, 0)
+
+ # pretrained_state_dict = torch.load(pretrained)
+ url = model_urls["resnet{}".format(num_layers)]
+ pretrained_state_dict = model_zoo.load_url(url)
+ print("=> loading pretrained model {}".format(url))
+ self.load_state_dict(pretrained_state_dict, strict=False)
+ else:
+ print("=> imagenet pretrained model dose not exist")
+ print("=> please download it first")
+ raise ValueError("imagenet pretrained model does not exist")
+
+
+resnet_spec = {
+ 18: (BasicBlock, [2, 2, 2, 2]),
+ 34: (BasicBlock, [3, 4, 6, 3]),
+ 50: (Bottleneck, [3, 4, 6, 3]),
+ 101: (Bottleneck, [3, 4, 23, 3]),
+ 152: (Bottleneck, [3, 8, 36, 3]),
+}
diff --git a/clean/video/fakestormer/models/networks/necks/__init__.py b/clean/video/fakestormer/models/networks/necks/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..fd9cea73d48be2870de0d4fc54500d559133033d
--- /dev/null
+++ b/clean/video/fakestormer/models/networks/necks/__init__.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+from .efpn3D import EFPN3D
+
+__all__ = ["EFPN3D"]
diff --git a/clean/video/fakestormer/models/networks/necks/base.py b/clean/video/fakestormer/models/networks/necks/base.py
new file mode 100644
index 0000000000000000000000000000000000000000..e4aa3766502e681f3bce863dee33118f707178fc
--- /dev/null
+++ b/clean/video/fakestormer/models/networks/necks/base.py
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+from abc import ABCMeta, abstractmethod
+from typing import Dict
+
+import torch
+import torch.nn as nn
+
+
+class BaseNeck(nn.Module, metaclass=ABCMeta):
+ def __init__(self, **kwargs) -> None:
+ return super().__init__()
+
+ @abstractmethod
+ def forward(self, x: Dict[str, torch.tensor], **kwargs):
+ return NotImplemented
+
+ @abstractmethod
+ def preprocess_inputs(self, x: Dict[str, torch.tensor], **kwargs):
+ return NotImplemented
+
+ @abstractmethod
+ def init_weights(self, pretrained=None):
+ return NotImplemented
+
+ @staticmethod
+ def _get_deconv_cfg(deconv_kernel: int):
+ """Get configurations for deconv layers."""
+ if deconv_kernel == 4:
+ padding = 1
+ output_padding = 0
+ elif deconv_kernel == 3:
+ padding = 1
+ output_padding = 1
+ elif deconv_kernel in [1, 2]:
+ padding = 0
+ output_padding = 0
+ else:
+ raise ValueError(f"Not supported num_kernels ({deconv_kernel}).")
+
+ return deconv_kernel, padding, output_padding
diff --git a/clean/video/fakestormer/models/networks/necks/efpn3D.py b/clean/video/fakestormer/models/networks/necks/efpn3D.py
new file mode 100644
index 0000000000000000000000000000000000000000..0794dea46ce1928e0fe041fa23ed2514d83b51eb
--- /dev/null
+++ b/clean/video/fakestormer/models/networks/necks/efpn3D.py
@@ -0,0 +1,173 @@
+# -*- coding: utf-8 -*-
+from typing import Dict, List, Sequence
+
+import torch
+import torch.nn as nn
+from mmengine.model import xavier_init
+
+from ...builder import NECKS
+from ..common import InceptionBlock3D, conv3d_block, deconv3d_block
+from .base import BaseNeck
+
+
+@NECKS.register_module()
+class EFPN3D(BaseNeck):
+ def __init__(
+ self,
+ in_channels: int,
+ num_deconv_layers: int,
+ num_deconv_filters: Sequence[int],
+ num_deconv_kernels: Sequence[int],
+ num_deconv_strides: Sequence[int],
+ efpn: bool = True,
+ **kwargs,
+ ) -> None:
+ super().__init__(**kwargs)
+
+ self.in_channels = in_channels
+ self.efpn = efpn
+ self.num_deconv_layers = num_deconv_layers
+
+ if num_deconv_layers > 0:
+ self.deconv_layers = self._make_3ddeconv_layer(
+ num_deconv_filters[0],
+ num_deconv_layers,
+ num_deconv_filters,
+ num_deconv_kernels,
+ num_deconv_strides,
+ )
+ elif num_deconv_layers == 0:
+ self.deconv_layers = nn.Identity()
+ else:
+ raise ValueError(f"num_deconv_layers ({num_deconv_layers}) should >= 0.")
+
+ if self.efpn:
+ in_filter = self.in_channels
+ for idx, out_filter in enumerate(num_deconv_filters):
+ deconv_block = nn.Sequential(
+ conv3d_block(
+ inplanes=in_filter,
+ outplanes=out_filter,
+ kernel_size=(1, 1, 1),
+ stride=(1, 1, 1),
+ bias=False,
+ ),
+ self.deconv_layers[idx],
+ )
+ in_filter = out_filter * 2
+ self.__setattr__(f"deconv_block_{idx}", deconv_block)
+ self.inception_block3d = InceptionBlock3D(
+ inplanes=num_deconv_filters[-1],
+ outplanes=num_deconv_filters[-1],
+ stride=1,
+ pool_size=3,
+ )
+
+ def preprocess_inputs(self, x: Dict[str, torch.tensor], **kwargs):
+ assert "embed" in x.keys(), "The input dict must contain embedding features!"
+ inputs = x["embed"]
+ additional_inputs = {}
+
+ for k, v in x.items():
+ if k != "embed":
+ additional_inputs[k] = v
+
+ return inputs, additional_inputs
+
+ def _make_3ddeconv_layer(
+ self,
+ in_channels,
+ num_layers: int,
+ num_filters: List[int],
+ num_kernels: Sequence[int],
+ num_strides: Sequence[int],
+ ) -> list:
+ """Make deconv layers."""
+ if num_layers != len(num_filters):
+ error_msg = (
+ f"num_layers({num_layers}) "
+ f"!= length of num_filters({len(num_filters)})"
+ )
+ raise ValueError(error_msg)
+ if num_layers != len(num_kernels):
+ error_msg = (
+ f"num_layers({num_layers}) "
+ f"!= length of num_kernels({len(num_kernels)})"
+ )
+ raise ValueError(error_msg)
+
+ layers = []
+ in_planes = in_channels
+ for i in range(num_layers):
+ kernels = []
+ paddings = []
+ output_paddings = []
+
+ for j in range(len(num_kernels[i])):
+ kernel, padding, output_padding = self._get_deconv_cfg(
+ num_kernels[i][j]
+ )
+ kernels.append(kernel)
+ paddings.append(padding)
+ output_paddings.append(output_padding)
+
+ outplanes = num_filters[i]
+ layers.append(
+ deconv3d_block(
+ inplanes=in_planes,
+ outplanes=outplanes,
+ kernel_size=kernels,
+ stride=num_strides[i],
+ padding=paddings,
+ bias=False,
+ out_padding=output_paddings,
+ )
+ )
+
+ # This condition to match n_filters after convolution and optimize number of EFPN parameters
+ if self.efpn:
+ in_planes = (
+ num_filters[i + 1]
+ if (i + 1 < num_layers)
+ else num_filters[num_layers - 1]
+ )
+ else:
+ in_planes = outplanes
+
+ return layers
+
+ def forward(self, x: Dict[str, torch.tensor], **kwargs) -> dict:
+ inputs, additional_inputs = self.preprocess_inputs(x)
+ trapezoids = None
+ if "outputs" in additional_inputs.keys():
+ trapezoids = additional_inputs["outputs"]
+ # x2, x3, x4, x5 = trapezoids[0], trapezoids[1], trapezoids[2], trapezoids[3]
+
+ if not self.efpn:
+ x_embed = self.deconv_layers(inputs)
+ else:
+ assert (
+ "outputs" in additional_inputs.keys()
+ ), "EFPN requires multiscale feature outputs!"
+ x_embed = inputs
+ for i in range(self.num_deconv_layers):
+ x_embed = self.__getattr__(f"deconv_block_{i}")(x_embed)
+ if i < self.num_deconv_layers - 1:
+ x_weights = x_embed.sigmoid_()
+ x_inv = torch.sub(1, x_weights, alpha=1)
+ x_ = torch.multiply(
+ x_inv, trapezoids[self.num_deconv_layers - (i + 2)]
+ )
+ x_embed = torch.cat([x_embed, x_], dim=1)
+
+ # Last layer to capture multi-scale artifacts
+ x_embed = self.inception_block3d(x_embed)
+
+ res = {}
+ res["embed"] = x_embed
+
+ return res
+
+ def init_weights(self) -> None:
+ for layer in self.deconv_layers:
+ xavier_init(layer, distribution="uniform")
diff --git a/clean/video/fakestormer/models/networks/pose_efficientNet.py b/clean/video/fakestormer/models/networks/pose_efficientNet.py
new file mode 100644
index 0000000000000000000000000000000000000000..d6c3cf28fc7c1170289d3039330c4798b843198e
--- /dev/null
+++ b/clean/video/fakestormer/models/networks/pose_efficientNet.py
@@ -0,0 +1,978 @@
+# -*- coding: utf-8 -*-
+import math
+import os
+import sys
+
+if not os.getcwd() in sys.path:
+ sys.path.append(os.getcwd())
+
+import torch
+from torch import nn
+from torch.nn import functional as F
+from torch.utils import model_zoo
+
+from ..builder import MODELS, build_model
+from .backbones.efficientNet import (
+ MemoryEfficientSwish,
+ Swish,
+ calculate_output_image_size,
+ drop_connect,
+ efficientnet_params,
+ get_model_params,
+ get_same_padding_conv2d,
+ load_pretrained_weights,
+ round_filters,
+ round_repeats,
+ url_map,
+ url_map_advprop,
+)
+from .common import (
+ BN_MOMENTUM,
+ InceptionBlock,
+ SELayer,
+ Texture_Enhance,
+ conv_block,
+ point_wise_block,
+)
+
+VALID_MODELS = (
+ "efficientnet-b0",
+ "efficientnet-b1",
+ "efficientnet-b2",
+ "efficientnet-b3",
+ "efficientnet-b4",
+ "efficientnet-b5",
+ "efficientnet-b6",
+ "efficientnet-b7",
+ "efficientnet-b8",
+ # Support the construction of 'efficientnet-l2' without pretrained weights
+ "efficientnet-l2",
+)
+
+
+class MBConvBlock(nn.Module):
+ """Mobile Inverted Residual Bottleneck Block.
+ Args:
+ block_args (namedtuple): BlockArgs, defined in utils.py.
+ global_params (namedtuple): GlobalParam, defined in utils.py.
+ image_size (tuple or list): [image_height, image_width].
+ References:
+ [1] https://arxiv.org/abs/1704.04861 (MobileNet v1)
+ [2] https://arxiv.org/abs/1801.04381 (MobileNet v2)
+ [3] https://arxiv.org/abs/1905.02244 (MobileNet v3)
+ """
+
+ def __init__(self, block_args, global_params, image_size=None):
+ super().__init__()
+ self._block_args = block_args
+ self._bn_mom = (
+ 1 - global_params.batch_norm_momentum
+ ) # pytorch's difference from tensorflow
+ self._bn_eps = global_params.batch_norm_epsilon
+ self.has_se = (self._block_args.se_ratio is not None) and (
+ 0 < self._block_args.se_ratio <= 1
+ )
+ self.id_skip = (
+ block_args.id_skip
+ ) # whether to use skip connection and drop connect
+
+ # Expansion phase (Inverted Bottleneck)
+ inp = self._block_args.input_filters # number of input channels
+ oup = (
+ self._block_args.input_filters * self._block_args.expand_ratio
+ ) # number of output channels
+ if self._block_args.expand_ratio != 1:
+ Conv2d = get_same_padding_conv2d(image_size=image_size)
+ self._expand_conv = Conv2d(
+ in_channels=inp, out_channels=oup, kernel_size=1, bias=False
+ )
+ self._bn0 = nn.BatchNorm2d(
+ num_features=oup, momentum=self._bn_mom, eps=self._bn_eps
+ )
+ # image_size = calculate_output_image_size(image_size, 1) <-- this wouldn't modify image_size
+
+ # Depthwise convolution phase
+ k = self._block_args.kernel_size
+ s = self._block_args.stride
+ Conv2d = get_same_padding_conv2d(image_size=image_size)
+ self._depthwise_conv = Conv2d(
+ in_channels=oup,
+ out_channels=oup,
+ groups=oup, # groups makes it depthwise
+ kernel_size=k,
+ stride=s,
+ bias=False,
+ )
+ self._bn1 = nn.BatchNorm2d(
+ num_features=oup, momentum=self._bn_mom, eps=self._bn_eps
+ )
+ image_size = calculate_output_image_size(image_size, s)
+
+ # Squeeze and Excitation layer, if desired
+ if self.has_se:
+ Conv2d = get_same_padding_conv2d(image_size=(1, 1))
+ num_squeezed_channels = max(
+ 1, int(self._block_args.input_filters * self._block_args.se_ratio)
+ )
+ self._se_reduce = Conv2d(
+ in_channels=oup, out_channels=num_squeezed_channels, kernel_size=1
+ )
+ self._se_expand = Conv2d(
+ in_channels=num_squeezed_channels, out_channels=oup, kernel_size=1
+ )
+
+ # Pointwise convolution phase
+ final_oup = self._block_args.output_filters
+ Conv2d = get_same_padding_conv2d(image_size=image_size)
+ self._project_conv = Conv2d(
+ in_channels=oup, out_channels=final_oup, kernel_size=1, bias=False
+ )
+ self._bn2 = nn.BatchNorm2d(
+ num_features=final_oup, momentum=self._bn_mom, eps=self._bn_eps
+ )
+ self._swish = MemoryEfficientSwish()
+
+ def forward(self, inputs, drop_connect_rate=None):
+ """MBConvBlock's forward function.
+ Args:
+ inputs (tensor): Input tensor.
+ drop_connect_rate (bool): Drop connect rate (float, between 0 and 1).
+ Returns:
+ Output of this block after processing.
+ """
+
+ # Expansion and Depthwise Convolution
+ x = inputs
+ if self._block_args.expand_ratio != 1:
+ x = self._expand_conv(inputs)
+ x = self._bn0(x)
+ x = self._swish(x)
+
+ x = self._depthwise_conv(x)
+ x = self._bn1(x)
+ x = self._swish(x)
+
+ # Squeeze and Excitation
+ if self.has_se:
+ x_squeezed = F.adaptive_avg_pool2d(x, 1)
+ x_squeezed = self._se_reduce(x_squeezed)
+ x_squeezed = self._swish(x_squeezed)
+ x_squeezed = self._se_expand(x_squeezed)
+ x = torch.sigmoid(x_squeezed) * x
+
+ # Pointwise Convolution
+ x = self._project_conv(x)
+ x = self._bn2(x)
+
+ # Skip connection and drop connect
+ input_filters, output_filters = (
+ self._block_args.input_filters,
+ self._block_args.output_filters,
+ )
+ if (
+ self.id_skip
+ and self._block_args.stride == 1
+ and input_filters == output_filters
+ ):
+ # The combination of skip connection and drop connect brings about stochastic depth.
+ if drop_connect_rate:
+ x = drop_connect(x, p=drop_connect_rate, training=self.training)
+ x = x + inputs # skip connection
+ return x
+
+ def set_swish(self, memory_efficient=True):
+ """Sets swish function as memory efficient (for training) or standard (for export).
+ Args:
+ memory_efficient (bool): Whether to use memory-efficient version of swish.
+ """
+ self._swish = MemoryEfficientSwish() if memory_efficient else Swish()
+
+
+@MODELS.register_module()
+class EfficientNet(nn.Module):
+ """EfficientNet model.
+ Most easily loaded with the .from_name or .from_pretrained methods.
+ Args:
+ blocks_args (list[namedtuple]): A list of BlockArgs to construct blocks.
+ global_params (namedtuple): A set of GlobalParams shared between blocks.
+ References:
+ [1] https://arxiv.org/abs/1905.11946 (EfficientNet)
+ Example:
+ >>> import torch
+ >>> from efficientnet.model import EfficientNet
+ >>> inputs = torch.rand(1, 3, 224, 224)
+ >>> model = EfficientNet.from_pretrained('efficientnet-b0')
+ >>> model.eval()
+ >>> outputs = model(inputs)
+ """
+
+ def __init__(self, blocks_args=None, global_params=None):
+ super().__init__()
+ assert isinstance(blocks_args, list), "blocks_args should be a list"
+ assert len(blocks_args) > 0, "block args must be greater than 0"
+ self._global_params = global_params
+ self._blocks_args = blocks_args
+
+ # Batch norm parameters
+ bn_mom = 1 - self._global_params.batch_norm_momentum
+ bn_eps = self._global_params.batch_norm_epsilon
+
+ # Get stem static or dynamic convolution depending on image size
+ image_size = global_params.image_size
+ Conv2d = get_same_padding_conv2d(image_size=image_size)
+
+ # Stem
+ in_channels = 3 # rgb
+ out_channels = round_filters(
+ 32, self._global_params
+ ) # number of output channels
+ self._conv_stem = Conv2d(
+ in_channels, out_channels, kernel_size=3, stride=2, bias=False
+ )
+ self._bn0 = nn.BatchNorm2d(
+ num_features=out_channels, momentum=bn_mom, eps=bn_eps
+ )
+ image_size = calculate_output_image_size(image_size, 2)
+
+ # Build blocks
+ self._blocks = nn.ModuleList([])
+ for block_args in self._blocks_args:
+
+ # Update block input and output filters based on depth multiplier.
+ block_args = block_args._replace(
+ input_filters=round_filters(
+ block_args.input_filters, self._global_params
+ ),
+ output_filters=round_filters(
+ block_args.output_filters, self._global_params
+ ),
+ num_repeat=round_repeats(block_args.num_repeat, self._global_params),
+ )
+
+ # The first block needs to take care of stride and filter size increase.
+ self._blocks.append(
+ MBConvBlock(block_args, self._global_params, image_size=image_size)
+ )
+ image_size = calculate_output_image_size(image_size, block_args.stride)
+ if block_args.num_repeat > 1: # modify block_args to keep same output size
+ block_args = block_args._replace(
+ input_filters=block_args.output_filters, stride=1
+ )
+ for _ in range(block_args.num_repeat - 1):
+ self._blocks.append(
+ MBConvBlock(block_args, self._global_params, image_size=image_size)
+ )
+ # image_size = calculate_output_image_size(image_size, block_args.stride) # stride = 1
+
+ # Head
+ in_channels = block_args.output_filters # output of final block
+ out_channels = round_filters(1280, self._global_params)
+ Conv2d = get_same_padding_conv2d(image_size=image_size)
+ self._conv_head = Conv2d(in_channels, out_channels, kernel_size=1, bias=False)
+ self._bn1 = nn.BatchNorm2d(
+ num_features=out_channels, momentum=bn_mom, eps=bn_eps
+ )
+
+ # Final linear layer
+ self._avg_pooling = nn.AdaptiveAvgPool2d(1)
+ if self._global_params.include_top:
+ self._dropout = nn.Dropout(self._global_params.dropout_rate)
+ self._fc = nn.Linear(out_channels, self._global_params.num_classes)
+
+ # Heatmap Decoder Construction
+ if self._global_params.include_hm_decoder:
+ print("Constructing the heatmap Decoder!")
+ self.efpn = self._global_params.efpn
+ self.tfpn = self._global_params.tfpn
+
+ assert not (
+ self.efpn and self.tfpn
+ ), "Only one of E-FPN or FPN is intergrated!"
+
+ self.se_layer = self._global_params.se_layer
+ # self.hm_decoder_filters = [1792, 448, 160, 56] if self.fpn else [1792, 256, 256, 128]
+ self.hm_decoder_filters = [1792, 448, 160, 56]
+ num_kernels = [4, 4, 4, 4] if (self.efpn or self.tfpn) else [4, 4, 4]
+ self._dropout = nn.Dropout(self._global_params.dropout_rate)
+ self._sigmoid = nn.Sigmoid()
+ self._relu = nn.ReLU(inplace=True)
+ self._relu1 = nn.ReLU(inplace=False)
+ self.deconv_with_bias = False
+
+ # if self._global_params.use_c2:
+ # self.inception_block_4 = InceptionBlock(224, 224, stride=1, pool_size=3)
+ if self._global_params.use_c3:
+ self.inception_block = InceptionBlock(112, 112, stride=1, pool_size=3)
+ else:
+ self.inception_block = InceptionBlock(56, 56, stride=1, pool_size=3)
+
+ self.heads = self._global_params.heads
+ n_deconv = len(self.hm_decoder_filters)
+ self.fpn_layers = [
+ self._global_params.use_c51,
+ self._global_params.use_c4,
+ self._global_params.use_c3,
+ ]
+
+ if self.efpn or self.tfpn:
+ for idx in range(n_deconv):
+ in_decod_filters = self.hm_decoder_filters[idx]
+
+ if idx == 0:
+ out_decod_filters = self.hm_decoder_filters[idx + 1]
+ deconv = nn.Sequential(
+ conv_block(
+ in_decod_filters,
+ out_decod_filters,
+ (3, 3),
+ stride=1,
+ padding=1,
+ ),
+ )
+ else:
+ in_decod_filters = (
+ in_decod_filters * 2
+ if self.fpn_layers[idx - 1]
+ else in_decod_filters
+ )
+ kernel, padding, output_padding = self._get_deconv_cfg(
+ num_kernels[idx]
+ )
+
+ if idx + 1 < n_deconv:
+ out_decod_filters = self.hm_decoder_filters[idx + 1]
+ deconv = nn.Sequential(
+ conv_block(
+ in_decod_filters,
+ out_decod_filters,
+ (3, 3),
+ stride=1,
+ padding=1,
+ ),
+ nn.ConvTranspose2d(
+ in_channels=out_decod_filters,
+ out_channels=out_decod_filters,
+ kernel_size=kernel,
+ stride=2,
+ padding=padding,
+ output_padding=output_padding,
+ bias=self.deconv_with_bias,
+ ),
+ nn.BatchNorm2d(out_decod_filters, momentum=BN_MOMENTUM),
+ )
+ else:
+ out_decod_filters = in_decod_filters
+ deconv = nn.Sequential(
+ self.inception_block,
+ # conv_block(in_decod_filters, out_decod_filters, (3,3), stride=1, padding=1),
+ nn.ConvTranspose2d(
+ in_channels=out_decod_filters,
+ out_channels=out_decod_filters,
+ kernel_size=kernel,
+ stride=2,
+ padding=padding,
+ output_padding=output_padding,
+ bias=self.deconv_with_bias,
+ ),
+ nn.BatchNorm2d(out_decod_filters, momentum=BN_MOMENTUM),
+ )
+
+ # In case of using C2, this conv to apply to C2 features to get the same filters of the last deconv
+ if self._global_params.use_c2:
+ if self._global_params.norm_c2:
+ self.texture_enhance = Texture_Enhance(32)
+ # self.conv_c2 = point_wise_block(128, out_decod_filters)
+ self.conv_c2 = conv_block(
+ 128,
+ out_decod_filters,
+ (3, 3),
+ stride=1,
+ padding=1,
+ )
+ else:
+ self.conv_c2 = conv_block(
+ 32,
+ out_decod_filters,
+ (3, 3),
+ stride=1,
+ padding=1,
+ )
+ if self.se_layer:
+ se = SELayer(channel=out_decod_filters * 2)
+ self.__setattr__(f"se_layer_{idx+1}", se)
+
+ self.__setattr__(f"deconv_{idx+1}", deconv)
+ else:
+ self.deconv_layers = self._make_deconv_layer(
+ len(num_kernels),
+ self.hm_decoder_filters,
+ num_kernels,
+ )
+
+ for head, num_output in self.heads.items():
+ head_conv = int(self._global_params.head_conv)
+ num_output = int(num_output)
+ if self._global_params.use_c2:
+ assert (
+ self._global_params.efpn or self._global_params.tfpn
+ ), "FPN Design must be set active!"
+ assert (
+ self._global_params.use_c3
+ ), "C3 must be utilized for FPN intergration of C2"
+ in_head_filters = self.hm_decoder_filters[-1] * 4
+ elif self._global_params.use_c3:
+ in_head_filters = self.hm_decoder_filters[-1] * 2
+ else:
+ in_head_filters = self.hm_decoder_filters[-1]
+
+ if head_conv > 0:
+ if head != "cls":
+ fc = nn.Sequential(
+ nn.Conv2d(
+ in_head_filters,
+ head_conv,
+ kernel_size=3,
+ padding=1,
+ bias=True,
+ ),
+ nn.BatchNorm2d(head_conv),
+ nn.ReLU(inplace=True),
+ nn.Conv2d(
+ head_conv,
+ num_output,
+ kernel_size=1,
+ stride=1,
+ padding=0,
+ ),
+ )
+ else:
+ fc = nn.Sequential(
+ nn.Conv2d(
+ in_head_filters,
+ head_conv,
+ kernel_size=3,
+ padding=1,
+ bias=True,
+ ),
+ nn.BatchNorm2d(head_conv, momentum=BN_MOMENTUM),
+ nn.ReLU(inplace=True),
+ # nn.Conv2d(head_conv, num_output, kernel_size=1,
+ # stride=1, padding=0, bias=True),
+ # nn.BatchNorm2d(num_output),
+ # nn.ReLU(inplace=True),
+ # nn.AdaptiveMaxPool2d(head_conv//4),
+ nn.AdaptiveAvgPool2d(1),
+ nn.Flatten(),
+ # nn.Linear((head_conv//4)**2, head_conv, bias=True),
+ # nn.BatchNorm1d(head_conv, momentum=BN_MOMENTUM),
+ # nn.ReLU(inplace=True),
+ nn.Linear(head_conv, num_output, bias=True),
+ # nn.Sigmoid(),
+ # nn.Softmax(dim=-1)
+ )
+ else:
+ fc = nn.Conv2d(
+ in_channels=in_head_filters,
+ out_channels=num_output,
+ kernel_size=1,
+ stride=1,
+ padding=0,
+ )
+ self.__setattr__(head, fc)
+
+ # set activation to memory efficient swish by default
+ self._swish = MemoryEfficientSwish()
+
+ def _get_deconv_cfg(self, deconv_kernel):
+ if deconv_kernel == 4:
+ padding = 1
+ output_padding = 0
+ elif deconv_kernel == 3:
+ padding = 1
+ output_padding = 1
+ elif deconv_kernel == 2:
+ padding = 0
+ output_padding = 0
+
+ return deconv_kernel, padding, output_padding
+
+ def _make_deconv_layer(self, num_layers, num_filters, num_kernels):
+ assert num_layers == (
+ len(num_filters) - 1
+ ), "ERROR: num_deconv_layers is different len(num_deconv_filters)"
+ assert num_layers == len(
+ num_kernels
+ ), "ERROR: num_deconv_layers is different len(num_deconv_filters)"
+
+ layers = []
+ for i in range(num_layers):
+ kernel, padding, output_padding = self._get_deconv_cfg(num_kernels[i])
+
+ in_planes = num_filters[i]
+ out_planes = num_filters[i + 1]
+
+ layers.append(
+ nn.Sequential(
+ nn.ConvTranspose2d(
+ in_channels=in_planes,
+ out_channels=out_planes,
+ kernel_size=kernel,
+ stride=2,
+ padding=padding,
+ output_padding=output_padding,
+ bias=self.deconv_with_bias,
+ ),
+ nn.BatchNorm2d(out_planes, momentum=BN_MOMENTUM),
+ nn.ReLU(inplace=True),
+ )
+ )
+
+ return nn.Sequential(*layers)
+
+ def set_swish(self, memory_efficient=True):
+ """Sets swish function as memory efficient (for training) or standard (for export).
+ Args:
+ memory_efficient (bool): Whether to use memory-efficient version of swish.
+ """
+ self._swish = MemoryEfficientSwish() if memory_efficient else Swish()
+ for block in self._blocks:
+ block.set_swish(memory_efficient)
+
+ def extract_endpoints(self, inputs):
+ """Use convolution layer to extract features
+ from reduction levels i in [1, 2, 3, 4, 5].
+ Args:
+ inputs (tensor): Input tensor.
+ Returns:
+ Dictionary of last intermediate features
+ with reduction levels i in [1, 2, 3, 4, 5].
+ Example:
+ >>> import torch
+ >>> from efficientnet.model import EfficientNet
+ >>> inputs = torch.rand(1, 3, 224, 224)
+ >>> model = EfficientNet.from_pretrained('efficientnet-b0')
+ >>> endpoints = model.extract_endpoints(inputs)
+ >>> print(endpoints['reduction_1'].shape) # torch.Size([1, 16, 112, 112])
+ >>> print(endpoints['reduction_2'].shape) # torch.Size([1, 24, 56, 56])
+ >>> print(endpoints['reduction_3'].shape) # torch.Size([1, 40, 28, 28])
+ >>> print(endpoints['reduction_4'].shape) # torch.Size([1, 112, 14, 14])
+ >>> print(endpoints['reduction_5'].shape) # torch.Size([1, 320, 7, 7])
+ >>> print(endpoints['reduction_6'].shape) # torch.Size([1, 1280, 7, 7])
+ """
+ endpoints = dict()
+
+ # Stem
+ x = self._swish(self._bn0(self._conv_stem(inputs)))
+ prev_x = x
+
+ # Blocks
+ for idx, block in enumerate(self._blocks):
+ drop_connect_rate = self._global_params.drop_connect_rate
+ if drop_connect_rate:
+ drop_connect_rate *= float(idx) / len(
+ self._blocks
+ ) # scale drop connect_rate
+ x = block(x, drop_connect_rate=drop_connect_rate)
+ # print('Prev', prev_x.size())
+ # print('X', x.size())
+ if prev_x.size(2) > x.size(2):
+ endpoints["reduction_{}".format(len(endpoints) + 1)] = prev_x
+ elif idx == len(self._blocks) - 1:
+ endpoints["reduction_{}".format(len(endpoints) + 1)] = x
+ prev_x = x
+
+ # Head
+ x = self._swish(self._bn1(self._conv_head(x)))
+ endpoints["reduction_{}".format(len(endpoints) + 1)] = x
+
+ return endpoints
+
+ def extract_features(self, inputs):
+ """use convolution layer to extract feature .
+ Args:
+ inputs (tensor): Input tensor.
+ Returns:
+ Output of the final convolution
+ layer in the efficientnet model.
+ """
+ # Stem
+ x = self._swish(self._bn0(self._conv_stem(inputs)))
+
+ # Blocks
+ for idx, block in enumerate(self._blocks):
+ drop_connect_rate = self._global_params.drop_connect_rate
+ if drop_connect_rate:
+ drop_connect_rate *= float(idx) / len(
+ self._blocks
+ ) # scale drop connect_rate
+ x = block(x, drop_connect_rate=drop_connect_rate)
+
+ # Head
+ x = self._swish(self._bn1(self._conv_head(x)))
+
+ return x
+
+ def forward(self, inputs):
+ """EfficientNet's forward function.
+ Calls extract_features to extract features, applies final linear layer, and returns logits.
+ Args:
+ inputs (tensor): Input tensor.
+ Returns:
+ Output of this model after processing.
+ """
+ # Convolution layers
+ # x = self.extract_features(inputs)
+ endpoints = self.extract_endpoints(inputs)
+ x1 = endpoints["reduction_6"]
+ x2 = endpoints["reduction_5"]
+ x3 = endpoints["reduction_4"]
+ x4 = endpoints["reduction_3"]
+ x5 = endpoints["reduction_2"]
+ x = x1
+
+ if self._global_params.include_top:
+ # Pooling and final linear layer
+ x = self._avg_pooling(x)
+
+ x = x.flatten(start_dim=1)
+ x = self._dropout(x)
+ x = self._fc(x)
+ res = {}
+ res["cls"] = x
+
+ return res
+
+ if self._global_params.include_hm_decoder:
+ x1 = self._dropout(x1)
+ x2 = self._dropout(x2)
+ x3 = self._dropout(x3)
+ x4 = self._dropout(x4)
+
+ if self.efpn:
+ assert (
+ self._global_params.use_c51
+ ), "C51 must be utilized for FPN intergration"
+
+ x = self.__getattr__("deconv_1")(x1)
+
+ if self._global_params.use_c51:
+ x_weighted = self._sigmoid(x)
+ x_inv = torch.sub(1, x_weighted, alpha=1)
+ x2_ = torch.multiply(x_inv, x2)
+ x = torch.cat([x, x2_], dim=1)
+
+ if self.se_layer:
+ x = self.__getattr__("se_layer_1")(x)
+ else:
+ x = self._relu(x)
+
+ x = self.__getattr__("deconv_2")(x)
+
+ if self._global_params.use_c4:
+ x_weighted = self._sigmoid(x)
+ x_inv = torch.sub(1, x_weighted, alpha=1)
+ x3_ = torch.multiply(x_inv, x3)
+ x = torch.cat([x, x3_], dim=1)
+
+ if self.se_layer:
+ x = self.__getattr__("se_layer_2")(x)
+ else:
+ x = self._relu(x)
+
+ x = self.__getattr__("deconv_3")(x)
+
+ if self._global_params.use_c3:
+ assert (
+ self._global_params.use_c4
+ ), "C4 must be utilized for FPN intergration of C3"
+
+ x_weighted = self._sigmoid(x)
+ x_inv = torch.sub(1, x_weighted, alpha=1)
+ x4_ = torch.multiply(x_inv, x4)
+ x = torch.cat([x, x4_], dim=1)
+
+ if self.se_layer:
+ x = self.__getattr__("se_layer_3")(x)
+ else:
+ x = self._relu(x)
+
+ x = self.__getattr__("deconv_4")(x)
+
+ if not self._global_params.use_c2:
+ x = self._relu(x)
+ else:
+ assert (
+ self._global_params.use_c3
+ ), "C3 must be utilized for FPN intergration of C2"
+
+ x5 = self._dropout(x5)
+ if self._global_params.norm_c2:
+ x5_ = self.texture_enhance(x5, (16, 16))
+ x5_ = self.conv_c2(x5_)
+ else:
+ x5_ = self.conv_c2(x5)
+
+ x_weighted = self._sigmoid(x)
+ x_inv = torch.sub(1, x_weighted, alpha=1)
+ x5_ = torch.multiply(x_inv, x5_)
+ x = torch.cat([x, x5_], dim=1)
+
+ # # Adding multi receptive fields
+ # x = self.inception_block_4(x)
+
+ if self.se_layer:
+ x = self.__getattr__("se_layer_4")(x)
+ elif self.tfpn:
+ assert (
+ self._global_params.use_c51
+ ), "C51 must be utilized for FPN intergration"
+ x = self.__getattr__("deconv_1")(x1)
+ x = self._relu1(x)
+ x = torch.cat([x, x2], dim=1)
+
+ x = self.__getattr__("deconv_2")(x)
+ if not self._global_params.use_c4:
+ x = self._relu1(x)
+ else:
+ x = torch.cat([x, x3], dim=1)
+
+ x = self.__getattr__("deconv_3")(x)
+ if not self._global_params.use_c3:
+ x = self._relu1(x)
+ else:
+ assert (
+ self._global_params.use_c4
+ ), "C4 must be utilized for FPN intergration of C3"
+ x = torch.cat([x, x4], dim=1)
+
+ x = self.__getattr__("deconv_4")(x)
+ if not self._global_params.use_c2:
+ x = self._relu(x)
+ else:
+ assert (
+ self._global_params.use_c3
+ ), "C3 must be utilized for FPN intergration of C2"
+ x5 = self._dropout(x5)
+ x5 = self.conv_c2(x5)
+ x = self._relu1(x)
+ x = torch.cat([x, x5], dim=1)
+ else:
+ x = self.deconv_layers(x1)
+
+ ret = {}
+ for head in self.heads:
+ ret[head] = self.__getattr__(head)(x)
+
+ return [ret]
+
+ @classmethod
+ def from_name(cls, model_name, in_channels=3, **override_params):
+ """Create an efficientnet model according to name.
+ Args:
+ model_name (str): Name for efficientnet.
+ in_channels (int): Input data's channel number.
+ override_params (other key word params):
+ Params to override model's global_params.
+ Optional key:
+ 'width_coefficient', 'depth_coefficient',
+ 'image_size', 'dropout_rate',
+ 'num_classes', 'batch_norm_momentum',
+ 'batch_norm_epsilon', 'drop_connect_rate',
+ 'depth_divisor', 'min_depth'
+ Returns:
+ An efficientnet model.
+ """
+ cls._check_model_name_is_valid(model_name)
+ blocks_args, global_params = get_model_params(model_name, override_params)
+ model = cls(blocks_args, global_params)
+ model._change_in_channels(in_channels)
+ return model
+
+ @classmethod
+ def from_pretrained(
+ cls,
+ model_name,
+ weights_path=None,
+ advprop=False,
+ in_channels=3,
+ num_classes=1000,
+ **override_params,
+ ):
+ """Create an efficientnet model according to name.
+ Args:
+ model_name (str): Name for efficientnet.
+ weights_path (None or str):
+ str: path to pretrained weights file on the local disk.
+ None: use pretrained weights downloaded from the Internet.
+ advprop (bool):
+ Whether to load pretrained weights
+ trained with advprop (valid when weights_path is None).
+ in_channels (int): Input data's channel number.
+ num_classes (int):
+ Number of categories for classification.
+ It controls the output size for final linear layer.
+ override_params (other key word params):
+ Params to override model's global_params.
+ Optional key:
+ 'width_coefficient', 'depth_coefficient',
+ 'image_size', 'dropout_rate',
+ 'batch_norm_momentum',
+ 'batch_norm_epsilon', 'drop_connect_rate',
+ 'depth_divisor', 'min_depth'
+ Returns:
+ A pretrained efficientnet model.
+ """
+ model = cls.from_name(model_name, num_classes=num_classes, **override_params)
+ load_pretrained_weights(
+ model,
+ model_name,
+ weights_path=weights_path,
+ load_fc=((num_classes == 1000) and (model._global_params.include_top)),
+ advprop=advprop,
+ )
+ model._change_in_channels(in_channels)
+ return model
+
+ @classmethod
+ def get_image_size(cls, model_name):
+ """Get the input image size for a given efficientnet model.
+ Args:
+ model_name (str): Name for efficientnet.
+ Returns:
+ Input image size (resolution).
+ """
+ cls._check_model_name_is_valid(model_name)
+ _, _, res, _ = efficientnet_params(model_name)
+ return res
+
+ @classmethod
+ def _check_model_name_is_valid(cls, model_name):
+ """Validates model name.
+ Args:
+ model_name (str): Name for efficientnet.
+ Returns:
+ bool: Is a valid name or not.
+ """
+ if model_name not in VALID_MODELS:
+ raise ValueError("model_name should be one of: " + ", ".join(VALID_MODELS))
+
+ def _change_in_channels(self, in_channels):
+ """Adjust model's first convolution layer to in_channels, if in_channels not equals 3.
+ Args:
+ in_channels (int): Input data's channel number.
+ """
+ if in_channels != 3:
+ Conv2d = get_same_padding_conv2d(image_size=self._global_params.image_size)
+ out_channels = round_filters(32, self._global_params)
+ self._conv_stem = Conv2d(
+ in_channels, out_channels, kernel_size=3, stride=2, bias=False
+ )
+
+
+@MODELS.register_module()
+class PoseEfficientNet(EfficientNet):
+ def __init__(self, model_name, in_channels=3, **override_params):
+ self.model_name = model_name
+ self.in_channels = in_channels
+
+ # Initialize Parent Class
+ super()._check_model_name_is_valid(model_name)
+ blocks_args, global_params = get_model_params(model_name, override_params)
+ super().__init__(blocks_args, global_params)
+
+ @classmethod
+ def from_name(cls, model_name, in_channels, **override_params):
+ return NotImplemented
+
+ @classmethod
+ def from_pretrained(
+ cls,
+ model_name,
+ weights_path,
+ advprop,
+ in_channels,
+ num_classes,
+ **override_params,
+ ):
+ return NotImplemented
+
+ def _change_in_channels(self, in_channels):
+ return NotImplemented
+
+ def init_weights(self, pretrained=False, advprop=False, verbose=True):
+ if pretrained:
+ url_map_ = url_map_advprop if advprop else url_map
+ state_dict = model_zoo.load_url(url_map_[self.model_name])
+ state_dict.pop("_fc.weight")
+ state_dict.pop("_fc.bias")
+ self.load_state_dict(state_dict, strict=False)
+
+ # Initialize weights for Deconvolution Layer
+ if self._global_params.include_hm_decoder:
+ if self.efpn or self.tfpn:
+ deconv_layers = [
+ self.deconv_1,
+ self.deconv_2,
+ self.deconv_3,
+ self.deconv_4,
+ ]
+ else:
+ deconv_layers = self.deconv_layers
+
+ for layer in deconv_layers:
+ for _, m in layer.named_modules():
+ if isinstance(m, nn.ConvTranspose2d):
+ n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
+ m.weight.data.normal_(0, math.sqrt(2.0 / n))
+ if self.deconv_with_bias:
+ nn.init.constant_(m.bias, 0)
+ elif isinstance(m, nn.BatchNorm2d):
+ nn.init.constant_(m.weight, 1)
+ nn.init.constant_(m.bias, 0)
+
+ # Init head parameters
+ for head in self.heads:
+ final_layer = self.__getattr__(head)
+ for i, m in enumerate(final_layer.modules()):
+ if isinstance(m, nn.Conv2d):
+ if m.weight.shape[0] == self.heads[head]:
+ if "hm" in head:
+ nn.init.constant_(m.bias, -2.19)
+ else:
+ # nn.init.normal_(m.weight, std=0.001)
+ n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
+ m.weight.data.normal_(0, math.sqrt(2.0 / n))
+ nn.init.constant_(m.bias, 0)
+
+ self._change_in_channels(in_channels=self.in_channels)
+ if verbose:
+ print("Loaded pretrained weights for {}".format(self.model_name))
+
+
+if __name__ == "__main__":
+ cfg = dict(
+ type="PoseEfficientNet",
+ model_name="efficientnet-b4",
+ include_top=False,
+ include_hm_decoder=True,
+ head_conv=64,
+ heads={"hm": 1, "cls": 1, "cstency": 256},
+ use_c2=True,
+ )
+ model = build_model(cfg, MODELS)
+ model.init_weights(pretrained=True)
+ model.eval()
+ inputs = torch.rand((1, 3, 384, 384))
+
+ for i, (n, p) in enumerate(model.named_parameters()):
+ print(i, n)
+
+ # To show the whole pose EFN model outputs shape
+ x = model(inputs)[0]
+ for head in x.keys():
+ print(f"{head} shape is --- {x[head].shape}")
+
+ # To show the endpoints features shape
+ # endpoints = model.extract_endpoints(inputs)
+ # for k in endpoints.keys():
+ # print(endpoints[k].shape)
diff --git a/clean/video/fakestormer/models/networks/pose_hrnet.py b/clean/video/fakestormer/models/networks/pose_hrnet.py
new file mode 100644
index 0000000000000000000000000000000000000000..0c7f6bfc240320820f070a12e57687e30b608b9b
--- /dev/null
+++ b/clean/video/fakestormer/models/networks/pose_hrnet.py
@@ -0,0 +1,540 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import, division, print_function
+
+import logging
+import os
+import re
+
+import torch
+import torch.nn as nn
+
+from ..builder import MODELS
+from .common import BN_MOMENTUM, conv3x3
+
+
+class BasicBlock(nn.Module):
+ expansion = 1
+
+ def __init__(self, inplanes, planes, stride=1, downsample=None):
+ super(BasicBlock, self).__init__()
+ self.conv1 = conv3x3(inplanes, planes, stride)
+ self.bn1 = nn.BatchNorm2d(planes, momentum=BN_MOMENTUM)
+ self.relu = nn.ReLU(inplace=True)
+ self.conv2 = conv3x3(planes, planes)
+ self.bn2 = nn.BatchNorm2d(planes, momentum=BN_MOMENTUM)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x):
+ residual = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+
+ if self.downsample is not None:
+ residual = self.downsample(x)
+
+ out += residual
+ out = self.relu(out)
+
+ return out
+
+
+class Bottleneck(nn.Module):
+ expansion = 4
+
+ def __init__(self, inplanes, planes, stride=1, downsample=None):
+ super(Bottleneck, self).__init__()
+ self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False)
+ self.bn1 = nn.BatchNorm2d(planes, momentum=BN_MOMENTUM)
+ self.conv2 = nn.Conv2d(
+ planes, planes, kernel_size=3, stride=stride, padding=1, bias=False
+ )
+ self.bn2 = nn.BatchNorm2d(planes, momentum=BN_MOMENTUM)
+ self.conv3 = nn.Conv2d(
+ planes, planes * self.expansion, kernel_size=1, bias=False
+ )
+ self.bn3 = nn.BatchNorm2d(planes * self.expansion, momentum=BN_MOMENTUM)
+ self.relu = nn.ReLU(inplace=True)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x):
+ residual = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+ out = self.relu(out)
+
+ out = self.conv3(out)
+ out = self.bn3(out)
+
+ if self.downsample is not None:
+ residual = self.downsample(x)
+
+ out += residual
+ out = self.relu(out)
+
+ return out
+
+
+class HighResolutionModule(nn.Module):
+ def __init__(
+ self,
+ num_branches,
+ blocks,
+ num_blocks,
+ num_inchannels,
+ num_channels,
+ fuse_method,
+ multi_scale_output=True,
+ ):
+ super(HighResolutionModule, self).__init__()
+ self._check_branches(
+ num_branches, blocks, num_blocks, num_inchannels, num_channels
+ )
+
+ self.num_inchannels = num_inchannels
+ self.fuse_method = fuse_method
+ self.num_branches = num_branches
+
+ self.multi_scale_output = multi_scale_output
+
+ self.branches = self._make_branches(
+ num_branches, blocks, num_blocks, num_channels
+ )
+ self.fuse_layers = self._make_fuse_layers()
+ self.relu = nn.ReLU(True)
+
+ def _check_branches(
+ self, num_branches, blocks, num_blocks, num_inchannels, num_channels
+ ):
+ if num_branches != len(num_blocks):
+ error_msg = "NUM_BRANCHES({}) <> NUM_BLOCKS({})".format(
+ num_branches, len(num_blocks)
+ )
+ # logger.error(error_msg)
+ raise ValueError(error_msg)
+
+ if num_branches != len(num_channels):
+ error_msg = "NUM_BRANCHES({}) <> NUM_CHANNELS({})".format(
+ num_branches, len(num_channels)
+ )
+ # logger.error(error_msg)
+ raise ValueError(error_msg)
+
+ if num_branches != len(num_inchannels):
+ error_msg = "NUM_BRANCHES({}) <> NUM_INCHANNELS({})".format(
+ num_branches, len(num_inchannels)
+ )
+ # logger.error(error_msg)
+ raise ValueError(error_msg)
+
+ def _make_one_branch(self, branch_index, block, num_blocks, num_channels, stride=1):
+ downsample = None
+ if (
+ stride != 1
+ or self.num_inchannels[branch_index]
+ != num_channels[branch_index] * block.expansion
+ ):
+ downsample = nn.Sequential(
+ nn.Conv2d(
+ self.num_inchannels[branch_index],
+ num_channels[branch_index] * block.expansion,
+ kernel_size=1,
+ stride=stride,
+ bias=False,
+ ),
+ nn.BatchNorm2d(
+ num_channels[branch_index] * block.expansion, momentum=BN_MOMENTUM
+ ),
+ )
+
+ layers = []
+ layers.append(
+ block(
+ self.num_inchannels[branch_index],
+ num_channels[branch_index],
+ stride,
+ downsample,
+ )
+ )
+ self.num_inchannels[branch_index] = num_channels[branch_index] * block.expansion
+ for i in range(1, num_blocks[branch_index]):
+ layers.append(
+ block(self.num_inchannels[branch_index], num_channels[branch_index])
+ )
+
+ return nn.Sequential(*layers)
+
+ def _make_branches(self, num_branches, block, num_blocks, num_channels):
+ branches = []
+
+ for i in range(num_branches):
+ branches.append(self._make_one_branch(i, block, num_blocks, num_channels))
+
+ return nn.ModuleList(branches)
+
+ def _make_fuse_layers(self):
+ if self.num_branches == 1:
+ return None
+
+ num_branches = self.num_branches
+ num_inchannels = self.num_inchannels
+ fuse_layers = []
+ for i in range(num_branches if self.multi_scale_output else 1):
+ fuse_layer = []
+ for j in range(num_branches):
+ if j > i:
+ fuse_layer.append(
+ nn.Sequential(
+ nn.Conv2d(
+ num_inchannels[j],
+ num_inchannels[i],
+ 1,
+ 1,
+ 0,
+ bias=False,
+ ),
+ nn.BatchNorm2d(num_inchannels[i]),
+ nn.Upsample(scale_factor=2 ** (j - i), mode="nearest"),
+ )
+ )
+ elif j == i:
+ fuse_layer.append(None)
+ else:
+ conv3x3s = []
+ for k in range(i - j):
+ if k == i - j - 1:
+ num_outchannels_conv3x3 = num_inchannels[i]
+ conv3x3s.append(
+ nn.Sequential(
+ nn.Conv2d(
+ num_inchannels[j],
+ num_outchannels_conv3x3,
+ 3,
+ 2,
+ 1,
+ bias=False,
+ ),
+ nn.BatchNorm2d(num_outchannels_conv3x3),
+ )
+ )
+ else:
+ num_outchannels_conv3x3 = num_inchannels[j]
+ conv3x3s.append(
+ nn.Sequential(
+ nn.Conv2d(
+ num_inchannels[j],
+ num_outchannels_conv3x3,
+ 3,
+ 2,
+ 1,
+ bias=False,
+ ),
+ nn.BatchNorm2d(num_outchannels_conv3x3),
+ nn.ReLU(True),
+ )
+ )
+ fuse_layer.append(nn.Sequential(*conv3x3s))
+ fuse_layers.append(nn.ModuleList(fuse_layer))
+
+ return nn.ModuleList(fuse_layers)
+
+ def get_num_inchannels(self):
+ return self.num_inchannels
+
+ def forward(self, x):
+ if self.num_branches == 1:
+ return [self.branches[0](x[0])]
+
+ for i in range(self.num_branches):
+ x[i] = self.branches[i](x[i])
+
+ x_fuse = []
+
+ for i in range(len(self.fuse_layers)):
+ y = x[0] if i == 0 else self.fuse_layers[i][0](x[0])
+ for j in range(1, self.num_branches):
+ if i == j:
+ y = y + x[j]
+ else:
+ y = y + self.fuse_layers[i][j](x[j])
+ x_fuse.append(self.relu(y))
+
+ return x_fuse
+
+
+blocks_dict = {"BASIC": BasicBlock, "BOTTLENECK": Bottleneck}
+
+
+@MODELS.register_module()
+class PoseHighResolutionNet(nn.Module):
+ def __init__(self, cfg, **kwargs):
+ self.inplanes = 64
+ extra = cfg.MODEL.EXTRA
+ self.cls_based_hm = cfg.MODEL.cls_based_hm
+ self.heads = cfg.MODEL.heads
+ super(PoseHighResolutionNet, self).__init__()
+
+ # stem net
+ self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=2, padding=1, bias=False)
+ self.bn1 = nn.BatchNorm2d(64, momentum=BN_MOMENTUM)
+ self.conv2 = nn.Conv2d(64, 64, kernel_size=3, stride=2, padding=1, bias=False)
+ self.bn2 = nn.BatchNorm2d(64, momentum=BN_MOMENTUM)
+ self.relu = nn.ReLU(inplace=True)
+ self.layer1 = self._make_layer(Bottleneck, 64, 4)
+
+ self.stage2_cfg = cfg["MODEL"]["EXTRA"]["STAGE2"]
+ num_channels = self.stage2_cfg["NUM_CHANNELS"]
+ block = blocks_dict[self.stage2_cfg["BLOCK"]]
+ num_channels = [
+ num_channels[i] * block.expansion for i in range(len(num_channels))
+ ]
+ self.transition1 = self._make_transition_layer([256], num_channels)
+ self.stage2, pre_stage_channels = self._make_stage(
+ self.stage2_cfg, num_channels
+ )
+
+ self.stage3_cfg = cfg["MODEL"]["EXTRA"]["STAGE3"]
+ num_channels = self.stage3_cfg["NUM_CHANNELS"]
+ block = blocks_dict[self.stage3_cfg["BLOCK"]]
+ num_channels = [
+ num_channels[i] * block.expansion for i in range(len(num_channels))
+ ]
+ self.transition2 = self._make_transition_layer(pre_stage_channels, num_channels)
+ self.stage3, pre_stage_channels = self._make_stage(
+ self.stage3_cfg, num_channels
+ )
+
+ self.stage4_cfg = cfg["MODEL"]["EXTRA"]["STAGE4"]
+ num_channels = self.stage4_cfg["NUM_CHANNELS"]
+ block = blocks_dict[self.stage4_cfg["BLOCK"]]
+ num_channels = [
+ num_channels[i] * block.expansion for i in range(len(num_channels))
+ ]
+ self.transition3 = self._make_transition_layer(pre_stage_channels, num_channels)
+ self.stage4, pre_stage_channels = self._make_stage(
+ self.stage4_cfg, num_channels, multi_scale_output=False
+ )
+
+ self.final_layer = nn.Conv2d(
+ in_channels=pre_stage_channels[0],
+ out_channels=cfg.MODEL.NUM_JOINTS,
+ kernel_size=extra.FINAL_CONV_KERNEL,
+ stride=1,
+ padding=1 if extra.FINAL_CONV_KERNEL == 3 else 0,
+ )
+
+ self.final_layer_cls = nn.Sequential(
+ nn.BatchNorm2d(cfg.MODEL.NUM_JOINTS, momentum=BN_MOMENTUM),
+ nn.AdaptiveMaxPool2d(cfg.MODEL.HEATMAP_SIZE[0] // 4),
+ nn.Flatten(),
+ nn.Linear(
+ (cfg.MODEL.HEATMAP_SIZE[0] // 4) ** 2, cfg.MODEL.NUM_JOINTS, bias=True
+ ),
+ nn.Sigmoid(),
+ )
+
+ self.pretrained_layers = cfg["MODEL"]["EXTRA"]["PRETRAINED_LAYERS"]
+
+ def _make_transition_layer(self, num_channels_pre_layer, num_channels_cur_layer):
+ num_branches_cur = len(num_channels_cur_layer)
+ num_branches_pre = len(num_channels_pre_layer)
+
+ transition_layers = []
+ for i in range(num_branches_cur):
+ if i < num_branches_pre:
+ if num_channels_cur_layer[i] != num_channels_pre_layer[i]:
+ transition_layers.append(
+ nn.Sequential(
+ nn.Conv2d(
+ num_channels_pre_layer[i],
+ num_channels_cur_layer[i],
+ 3,
+ 1,
+ 1,
+ bias=False,
+ ),
+ nn.BatchNorm2d(num_channels_cur_layer[i]),
+ nn.ReLU(inplace=True),
+ )
+ )
+ else:
+ transition_layers.append(None)
+ else:
+ conv3x3s = []
+ for j in range(i + 1 - num_branches_pre):
+ inchannels = num_channels_pre_layer[-1]
+ outchannels = (
+ num_channels_cur_layer[i]
+ if j == i - num_branches_pre
+ else inchannels
+ )
+ conv3x3s.append(
+ nn.Sequential(
+ nn.Conv2d(inchannels, outchannels, 3, 2, 1, bias=False),
+ nn.BatchNorm2d(outchannels),
+ nn.ReLU(inplace=True),
+ )
+ )
+ transition_layers.append(nn.Sequential(*conv3x3s))
+
+ return nn.ModuleList(transition_layers)
+
+ def _make_layer(self, block, planes, blocks, stride=1):
+ downsample = None
+ if stride != 1 or self.inplanes != planes * block.expansion:
+ downsample = nn.Sequential(
+ nn.Conv2d(
+ self.inplanes,
+ planes * block.expansion,
+ kernel_size=1,
+ stride=stride,
+ bias=False,
+ ),
+ nn.BatchNorm2d(planes * block.expansion, momentum=BN_MOMENTUM),
+ )
+
+ layers = []
+ layers.append(block(self.inplanes, planes, stride, downsample))
+ self.inplanes = planes * block.expansion
+ for i in range(1, blocks):
+ layers.append(block(self.inplanes, planes))
+
+ return nn.Sequential(*layers)
+
+ def _make_stage(self, layer_config, num_inchannels, multi_scale_output=True):
+ num_modules = layer_config["NUM_MODULES"]
+ num_branches = layer_config["NUM_BRANCHES"]
+ num_blocks = layer_config["NUM_BLOCKS"]
+ num_channels = layer_config["NUM_CHANNELS"]
+ block = blocks_dict[layer_config["BLOCK"]]
+ fuse_method = layer_config["FUSE_METHOD"]
+
+ modules = []
+ for i in range(num_modules):
+ # multi_scale_output is only used last module
+ if not multi_scale_output and i == num_modules - 1:
+ reset_multi_scale_output = False
+ else:
+ reset_multi_scale_output = True
+
+ modules.append(
+ HighResolutionModule(
+ num_branches,
+ block,
+ num_blocks,
+ num_inchannels,
+ num_channels,
+ fuse_method,
+ reset_multi_scale_output,
+ )
+ )
+ num_inchannels = modules[-1].get_num_inchannels()
+
+ return nn.Sequential(*modules), num_inchannels
+
+ def forward(self, x):
+ x = self.conv1(x)
+ x = self.bn1(x)
+ x = self.relu(x)
+ x = self.conv2(x)
+ x = self.bn2(x)
+ x = self.relu(x)
+ x = self.layer1(x)
+
+ x_list = []
+ for i in range(self.stage2_cfg["NUM_BRANCHES"]):
+ if self.transition1[i] is not None:
+ x_list.append(self.transition1[i](x))
+ else:
+ x_list.append(x)
+ y_list = self.stage2(x_list)
+
+ x_list = []
+ for i in range(self.stage3_cfg["NUM_BRANCHES"]):
+ if self.transition2[i] is not None:
+ x_list.append(self.transition2[i](y_list[-1]))
+ else:
+ x_list.append(y_list[i])
+ y_list = self.stage3(x_list)
+
+ x_list = []
+ for i in range(self.stage4_cfg["NUM_BRANCHES"]):
+ if self.transition3[i] is not None:
+ x_list.append(self.transition3[i](y_list[-1]))
+ else:
+ x_list.append(y_list[i])
+ y_list = self.stage4(x_list)
+
+ x = self.final_layer(y_list[0])
+
+ ret = {}
+ for head in self.heads.keys():
+ if head == "hm":
+ ret[head] = x
+ else:
+ x1 = self.final_layer_cls(x)
+ ret[head] = x1
+ return [ret]
+
+ def init_weights(self, pretrained="", **kwargs):
+ for m in self.modules():
+ if isinstance(m, nn.Conv2d):
+ # nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
+ nn.init.normal_(m.weight, std=0.001)
+ for name, _ in m.named_parameters():
+ if name in ["bias"]:
+ nn.init.constant_(m.bias, 0)
+ elif isinstance(m, nn.BatchNorm2d):
+ nn.init.constant_(m.weight, 1)
+ nn.init.constant_(m.bias, 0)
+ elif isinstance(m, nn.ConvTranspose2d):
+ nn.init.normal_(m.weight, std=0.001)
+ for name, _ in m.named_parameters():
+ if name in ["bias"]:
+ nn.init.constant_(m.bias, 0)
+
+ if os.path.isfile(pretrained):
+ pretrained_state_dict = torch.load(
+ pretrained, map_location=torch.device("cpu")
+ )
+
+ need_init_state_dict = {}
+ for name, m in pretrained_state_dict.items():
+ if (
+ name.split(".")[0] in self.pretrained_layers
+ or self.pretrained_layers[0] == "*"
+ ):
+ need_init_state_dict[name] = m
+ self.load_state_dict(need_init_state_dict, strict=False)
+ elif pretrained:
+ raise ValueError("{} is not exist!".format(pretrained))
+
+
+def get_pose_net(cfg, is_train, **kwargs):
+ model = PoseHighResolutionNet(cfg, **kwargs)
+
+ if is_train and cfg.MODEL.INIT_WEIGHTS:
+ model.init_weights(cfg.MODEL.PRETRAINED)
+
+ return model
+
+
+if __name__ == "__main__":
+ from builder import build_model
+ from configs.get_config import load_config
+
+ cfg = load_config("configs/hrnet_sbi.yaml")
+
+ hrnet = build_model(cfg.MODEL, MODELS, default_args=dict(cfg=cfg))
+ print(hrnet)
diff --git a/clean/video/fakestormer/models/utils/__init__.py b/clean/video/fakestormer/models/utils/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..f469208ff760535cac619667e3c040138c84d20e
--- /dev/null
+++ b/clean/video/fakestormer/models/utils/__init__.py
@@ -0,0 +1,28 @@
+# -*- coding:utf-8 -*-
+from .check_and_update_config import check_and_update_config
+from .utils import (
+ freeze_backbone,
+ load_checkpoint,
+ load_model,
+ load_pretrained,
+ n_param_model,
+ preset_model,
+ save_model,
+ swin_converter,
+ unfreeze_backbone,
+)
+
+__all__ = [
+ "check_and_update_config",
+ "build_model",
+ "load_pretrained",
+ "freeze_backbone",
+ "resnet_spec",
+ "load_model",
+ "save_model",
+ "unfreeze_backbone",
+ "preset_model",
+ "load_checkpoint",
+ "n_param_model",
+ "swin_converter",
+]
diff --git a/clean/video/fakestormer/models/utils/check_and_update_config.py b/clean/video/fakestormer/models/utils/check_and_update_config.py
new file mode 100644
index 0000000000000000000000000000000000000000..7541a1bb8dc4a32ad4ae9f7f73ac498041e69a1a
--- /dev/null
+++ b/clean/video/fakestormer/models/utils/check_and_update_config.py
@@ -0,0 +1,262 @@
+# -*- coding:utf-8 -*-
+# Copyright (c) OpenMMLab. All rights reserved.
+from typing import Dict, Optional, Tuple, Union
+
+from mmengine.config import Config, ConfigDict
+from mmengine.dist import master_only
+from mmengine.logging import MMLogger
+
+ConfigType = Union[Config, ConfigDict]
+
+
+def process_input_transform(
+ input_transform: str,
+ head: Dict,
+ head_new: Dict,
+ head_deleted_dict: Dict,
+ head_append_dict: Dict,
+ neck_new: Dict,
+ input_index: Tuple[int],
+ align_corners: bool,
+) -> None:
+ """Process the input_transform field and update head and neck
+ dictionaries."""
+ if input_transform == "resize_concat":
+ in_channels = head_new.pop("in_channels")
+ head_deleted_dict["in_channels"] = str(in_channels)
+ in_channels = sum([in_channels[i] for i in input_index])
+ head_new["in_channels"] = in_channels
+ head_append_dict["in_channels"] = str(in_channels)
+
+ neck_new.update(
+ dict(
+ type="FeatureMapProcessor",
+ concat=True,
+ select_index=input_index,
+ )
+ )
+ if align_corners:
+ neck_new["align_corners"] = align_corners
+
+ elif input_transform == "select":
+ if input_index != (-1,):
+ neck_new.update(dict(type="FeatureMapProcessor", select_index=input_index))
+ if isinstance(head["in_channels"], tuple):
+ in_channels = head_new.pop("in_channels")
+ head_deleted_dict["in_channels"] = str(in_channels)
+ if isinstance(input_index, int):
+ in_channels = in_channels[input_index]
+ else:
+ in_channels = tuple([in_channels[i] for i in input_index])
+ head_new["in_channels"] = in_channels
+ head_append_dict["in_channels"] = str(in_channels)
+ if align_corners:
+ neck_new["align_corners"] = align_corners
+
+ else:
+ raise ValueError(
+ f"model.head get invalid value for argument "
+ f"input_transform: {input_transform}"
+ )
+
+
+def process_extra_field(
+ extra: Dict,
+ head_new: Dict,
+ head_deleted_dict: Dict,
+ head_append_dict: Dict,
+ neck_new: Dict,
+) -> None:
+ """Process the extra field and update head and neck dictionaries."""
+ head_deleted_dict["extra"] = "dict("
+ for key, value in extra.items():
+ head_deleted_dict["extra"] += f"{key}={value},"
+ head_deleted_dict["extra"] = head_deleted_dict["extra"][:-1] + ")"
+ if "final_conv_kernel" in extra:
+ kernel_size = extra["final_conv_kernel"]
+ if kernel_size > 1:
+ padding = kernel_size // 2
+ head_new["final_layer"] = dict(kernel_size=kernel_size, padding=padding)
+ head_append_dict["final_layer"] = (
+ f"dict(kernel_size={kernel_size}, " f"padding={padding})"
+ )
+ else:
+ head_new["final_layer"] = dict(kernel_size=kernel_size)
+ head_append_dict["final_layer"] = f"dict(kernel_size={kernel_size})"
+ if "upsample" in extra:
+ neck_new.update(
+ dict(
+ type="FeatureMapProcessor",
+ scale_factor=float(extra["upsample"]),
+ apply_relu=True,
+ )
+ )
+
+
+def process_has_final_layer(
+ has_final_layer: bool,
+ head_new: Dict,
+ head_deleted_dict: Dict,
+ head_append_dict: Dict,
+) -> None:
+ """Process the has_final_layer field and update the head dictionary."""
+ head_deleted_dict["has_final_layer"] = str(has_final_layer)
+ if not has_final_layer:
+ if "final_layer" not in head_new:
+ head_new["final_layer"] = None
+ head_append_dict["final_layer"] = "None"
+
+
+def check_and_update_config(
+ neck: Optional[ConfigType], head: ConfigType
+) -> Tuple[Optional[Dict], Dict]:
+ """Check and update the configuration of the head and neck components.
+ Args:
+ neck (Optional[ConfigType]): Configuration for the neck component.
+ head (ConfigType): Configuration for the head component.
+
+ Returns:
+ Tuple[Optional[Dict], Dict]: Updated configurations for the neck
+ and head components.
+ """
+ head_new, neck_new = head.copy(), neck.copy() if isinstance(neck, dict) else {}
+ head_deleted_dict, head_append_dict = {}, {}
+
+ if "input_transform" in head:
+ input_transform = head_new.pop("input_transform")
+ head_deleted_dict["input_transform"] = f"'{input_transform}'"
+ else:
+ input_transform = "select"
+
+ if "input_index" in head:
+ input_index = head_new.pop("input_index")
+ head_deleted_dict["input_index"] = str(input_index)
+ else:
+ input_index = (-1,)
+
+ if "align_corners" in head:
+ align_corners = head_new.pop("align_corners")
+ head_deleted_dict["align_corners"] = str(align_corners)
+ else:
+ align_corners = False
+
+ process_input_transform(
+ input_transform,
+ head,
+ head_new,
+ head_deleted_dict,
+ head_append_dict,
+ neck_new,
+ input_index,
+ align_corners,
+ )
+
+ if "extra" in head:
+ extra = head_new.pop("extra")
+ process_extra_field(
+ extra, head_new, head_deleted_dict, head_append_dict, neck_new
+ )
+
+ if "has_final_layer" in head:
+ has_final_layer = head_new.pop("has_final_layer")
+ process_has_final_layer(
+ has_final_layer, head_new, head_deleted_dict, head_append_dict
+ )
+
+ display_modifications(head_deleted_dict, head_append_dict, neck_new)
+
+ neck_new = neck_new if len(neck_new) else None
+ return neck_new, head_new
+
+
+@master_only
+def display_modifications(
+ head_deleted_dict: Dict, head_append_dict: Dict, neck: Dict
+) -> None:
+ """Display the modifications made to the head and neck configurations.
+
+ Args:
+ head_deleted_dict (Dict): Dictionary of deleted fields in the head.
+ head_append_dict (Dict): Dictionary of appended fields in the head.
+ neck (Dict): Updated neck configuration.
+ """
+ if len(head_deleted_dict) + len(head_append_dict) == 0:
+ return
+
+ old_model_info, new_model_info = build_model_info(
+ head_deleted_dict, head_append_dict, neck
+ )
+
+ total_info = (
+ "\nThe config you are using is outdated. "
+ "The following section of the config:\n```\n"
+ )
+ total_info += old_model_info
+ total_info += "```\nshould be updated to\n```\n"
+ total_info += new_model_info
+ total_info += (
+ "```\nFor more information, please refer to "
+ "https://mmpose.readthedocs.io/en/latest/"
+ "guide_to_framework.html#step3-model"
+ )
+
+ logger: MMLogger = MMLogger.get_current_instance()
+ logger.warning(total_info)
+
+
+def build_model_info(
+ head_deleted_dict: Dict, head_append_dict: Dict, neck: Dict
+) -> Tuple[str, str]:
+ """Build the old and new model information strings.
+ Args:
+ head_deleted_dict (Dict): Dictionary of deleted fields in the head.
+ head_append_dict (Dict): Dictionary of appended fields in the head.
+ neck (Dict): Updated neck configuration.
+
+ Returns:
+ Tuple[str, str]: Old and new model information strings.
+ """
+ old_head_info = build_head_info(head_deleted_dict)
+ new_head_info = build_head_info(head_append_dict)
+ neck_info = build_neck_info(neck)
+
+ old_model_info = "model=dict(\n" + " " * 4 + "...,\n" + old_head_info
+ new_model_info = "model=dict(\n" + " " * 4 + "...,\n" + neck_info + new_head_info
+
+ return old_model_info, new_model_info
+
+
+def build_head_info(head_dict: Dict) -> str:
+ """Build the head information string.
+
+ Args:
+ head_dict (Dict): Dictionary of fields in the head configuration.
+ Returns:
+ str: Head information string.
+ """
+ head_info = " " * 4 + "head=dict(\n"
+ for key, value in head_dict.items():
+ head_info += " " * 8 + f"{key}={value},\n"
+ head_info += " " * 8 + "...),\n"
+ return head_info
+
+
+def build_neck_info(neck: Dict) -> str:
+ """Build the neck information string.
+ Args:
+ neck (Dict): Updated neck configuration.
+
+ Returns:
+ str: Neck information string.
+ """
+ if len(neck) > 0:
+ neck = neck.copy()
+ neck_info = (
+ " " * 4 + "neck=dict(\n" + " " * 8 + f'type=\'{neck.pop("type")}\',\n'
+ )
+ for key, value in neck.items():
+ neck_info += " " * 8 + f"{key}={str(value)},\n"
+ neck_info += " " * 4 + "),\n"
+ else:
+ neck_info = ""
+ return neck_info
diff --git a/clean/video/fakestormer/models/utils/utils.py b/clean/video/fakestormer/models/utils/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..469f8e4c3403cccd8de8699eb4116cccbd13274a
--- /dev/null
+++ b/clean/video/fakestormer/models/utils/utils.py
@@ -0,0 +1,658 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import, division, print_function
+
+import copy
+import io
+import os
+import os.path as osp
+import pkgutil
+import re
+import warnings
+from collections import OrderedDict
+from importlib import import_module
+from tempfile import TemporaryDirectory
+
+import mmcv
+import torch
+import torch.nn as nn
+import torchvision
+from mmcv.parallel import is_module_wrapper
+from mmengine.dist import get_dist_info
+from mmengine.fileio import FileClient
+from mmengine.fileio import load as load_file
+from mmengine.utils import mkdir_or_exist
+from ptflops import get_model_complexity_info
+from torch.utils import model_zoo
+
+ENV_MMCV_HOME = "MMCV_HOME"
+ENV_XDG_CACHE_HOME = "XDG_CACHE_HOME"
+DEFAULT_CACHE_DIR = "~/.cache"
+
+
+layers_position = {
+ "PoseResNet_50": 158,
+ "PoseResNet_101": 311,
+ "PoseEfficientNet_B4": 415,
+}
+
+
+def m_flops(model, cfg):
+ if cfg.DATASET.DATA_TYPE != "video":
+ macs, params = get_model_complexity_info(
+ model,
+ (3, cfg.DATASET.IMAGE_SIZE[0], cfg.DATASET.IMAGE_SIZE[0]),
+ as_strings=True,
+ verbose=True,
+ )
+ else:
+ macs, params = get_model_complexity_info(
+ model,
+ (
+ 3,
+ cfg.DATASET.DATA.SAMPLES_PER_VIDEO.TRAIN,
+ cfg.DATASET.IMAGE_SIZE[0],
+ cfg.DATASET.IMAGE_SIZE[0],
+ ),
+ as_strings=True,
+ verbose=True,
+ )
+ print("{:<30} {:<8}".format("Computational complexity: ", macs))
+ print("{:<30} {:<8}".format("Number of parameters: ", params))
+
+
+def n_param_model(model):
+ print("Number of parameters", sum(p.numel() for p in model.parameters()))
+ print(
+ "Number of trainable parameters",
+ sum(p.numel() for p in model.parameters() if p.requires_grad),
+ )
+
+
+def preset_model(cfg, model, optimizer=None, scaler=None):
+ # Loading models from config, make sure the pretrained path correct to the model name
+ start_epoch = 0
+ if "pretrained" in cfg.TRAIN and os.path.isfile(cfg.TRAIN.pretrained):
+ model, optimizer, start_epoch, scaler = load_model(
+ model,
+ cfg.TRAIN.pretrained,
+ optimizer=optimizer,
+ scaler=scaler,
+ resume=cfg.TRAIN.resume,
+ lr=cfg.TRAIN.lr,
+ lr_step=cfg.TRAIN.lr_scheduler.milestones,
+ gamma=cfg.TRAIN.lr_scheduler.gamma,
+ )
+ else:
+ model.init_weights(**cfg.MODEL.INIT_WEIGHTS)
+ print("Loading model successfully -- {}".format(cfg.MODEL.type))
+
+ # Showing model FLOPS
+ m_flops(model, cfg)
+
+ # Freeze backbone if begin_epoch < warm up
+ if cfg.TRAIN.freeze_backbone and start_epoch < cfg.TRAIN.warm_up:
+ freeze_backbone(cfg.MODEL, model)
+
+ n_param_model(model)
+ return model, optimizer, start_epoch, scaler
+
+
+def load_pretrained(model, weight_path):
+ """
+ This function only care about state dict of model
+ For other modules such as optimizer, resume learning, please refer @load_model
+ """
+ state_dict = torch.load(weight_path, map_location=torch.device("cpu"))["state_dict"]
+ model.load_state_dict(state_dict, strict=True)
+ return model
+
+
+def freeze_backbone(cfg, model):
+ """
+ This func to freeze some specific layers to warm up the models
+ """
+ if hasattr(model, "backbone"):
+ backbone = model.backbone
+ for param in backbone.parameters():
+ param.requires_grad = False
+ else:
+ for i, (n, p) in enumerate(model.named_parameters()):
+ if i <= layers_position[f"{cfg.type}_{cfg.num_layers}"]:
+ p.requires_grad = False
+
+
+def unfreeze_backbone(model):
+ """
+ This func to unfreeze all model layers
+ """
+ for param in model.parameters():
+ if not param.requires_grad:
+ param.requires_grad = True
+
+
+def load_model(
+ model,
+ model_path,
+ optimizer=None,
+ scaler=None,
+ resume=False,
+ lr=None,
+ lr_step=None,
+ gamma=None,
+):
+ start_epoch = 0
+ checkpoint = torch.load(model_path, map_location=lambda storage, loc: storage)
+ print("loaded {}, epoch {}".format(model_path, checkpoint["epoch"]))
+ state_dict_ = checkpoint["state_dict"]
+ state_dict = {}
+
+ # convert data_parallal to model
+ for k in state_dict_:
+ if k.startswith("module") and not k.startswith("module_list"):
+ state_dict[k[7:]] = state_dict_[k]
+ else:
+ state_dict[k] = state_dict_[k]
+ model_state_dict = model.state_dict()
+
+ # check loaded parameters and created model parameters
+ msg = (
+ "If you see this, your model does not fully load the "
+ + "pre-trained weight. Please make sure "
+ + "you have correctly specified --arch xxx "
+ + "or set the correct --num_classes for your own dataset."
+ )
+ for k in state_dict:
+ if k in model_state_dict:
+ if state_dict[k].shape != model_state_dict[k].shape:
+ print(
+ "Skip loading parameter {}, required shape{}, "
+ "loaded shape{}. {}".format(
+ k, model_state_dict[k].shape, state_dict[k].shape, msg
+ )
+ )
+ state_dict[k] = model_state_dict[k]
+ else:
+ print("Drop parameter {}.".format(k) + msg)
+ for k in model_state_dict:
+ if not (k in state_dict):
+ print("No param {}.".format(k) + msg)
+ state_dict[k] = model_state_dict[k]
+ model.load_state_dict(state_dict, strict=False)
+
+ # resume optimizer parameters
+ if optimizer is not None and resume:
+ if "optimizer" in checkpoint:
+ optimizer.load_state_dict(checkpoint["optimizer"])
+ if "scaler" in checkpoint:
+ scaler.load_state_dict(checkpoint["scaler"])
+
+ start_epoch = checkpoint["epoch"] + 1
+ start_lr = lr
+ for step in lr_step:
+ if start_epoch >= step:
+ start_lr *= gamma
+ for param_group in optimizer.param_groups:
+ param_group["lr"] = start_lr
+ print("Resumed optimizer with start lr", start_lr)
+ else:
+ print("No optimizer parameters in checkpoint.")
+
+ return model, optimizer, start_epoch, scaler
+
+
+def save_model(path, epoch, model, optimizer=None, scaler=None):
+ if isinstance(model, torch.nn.DataParallel):
+ state_dict = model.module.state_dict()
+ else:
+ state_dict = model.state_dict()
+ data = {"epoch": epoch, "state_dict": state_dict}
+
+ if not (optimizer is None):
+ data["optimizer"] = optimizer.state_dict()
+
+ if not (scaler is None):
+ data["scaler"] = scaler.state_dict()
+
+ torch.save(data, path)
+
+
+def _get_mmcv_home():
+ mmcv_home = os.path.expanduser(
+ os.getenv(
+ ENV_MMCV_HOME,
+ os.path.join(os.getenv(ENV_XDG_CACHE_HOME, DEFAULT_CACHE_DIR), "mmcv"),
+ )
+ )
+
+ mkdir_or_exist(mmcv_home)
+ return mmcv_home
+
+
+def load_url_dist(url, model_dir=None, map_location="cpu"):
+ """In distributed setting, this function only download checkpoint at local
+ rank 0."""
+ rank, world_size = get_dist_info()
+ rank = int(os.environ.get("LOCAL_RANK", rank))
+ if rank == 0:
+ checkpoint = model_zoo.load_url(
+ url, model_dir=model_dir, map_location=map_location
+ )
+ if world_size > 1:
+ torch.distributed.barrier()
+ if rank > 0:
+ checkpoint = model_zoo.load_url(
+ url, model_dir=model_dir, map_location=map_location
+ )
+ return checkpoint
+
+
+def get_torchvision_models():
+ model_urls = dict()
+ for _, name, ispkg in pkgutil.walk_packages(torchvision.models.__path__):
+ if ispkg:
+ continue
+ _zoo = import_module(f"torchvision.models.{name}")
+ if hasattr(_zoo, "model_urls"):
+ _urls = getattr(_zoo, "model_urls")
+ model_urls.update(_urls)
+ return model_urls
+
+
+def get_external_models():
+ mmcv_home = _get_mmcv_home()
+ default_json_path = osp.join(mmcv.__path__[0], "model_zoo/open_mmlab.json")
+ default_urls = load_file(default_json_path)
+ assert isinstance(default_urls, dict)
+ external_json_path = osp.join(mmcv_home, "open_mmlab.json")
+ if osp.exists(external_json_path):
+ external_urls = load_file(external_json_path)
+ assert isinstance(external_urls, dict)
+ default_urls.update(external_urls)
+
+ return default_urls
+
+
+def get_deprecated_model_names():
+ deprecate_json_path = osp.join(mmcv.__path__[0], "model_zoo/deprecated.json")
+ deprecate_urls = load_file(deprecate_json_path)
+ assert isinstance(deprecate_urls, dict)
+
+ return deprecate_urls
+
+
+def get_mmcls_models():
+ mmcls_json_path = osp.join(mmcv.__path__[0], "model_zoo/mmcls.json")
+ mmcls_urls = load_file(mmcls_json_path)
+
+ return mmcls_urls
+
+
+def _process_mmcls_checkpoint(checkpoint):
+ state_dict = checkpoint["state_dict"]
+ new_state_dict = OrderedDict()
+ for k, v in state_dict.items():
+ if k.startswith("backbone."):
+ new_state_dict[k[9:]] = v
+ new_checkpoint = dict(state_dict=new_state_dict)
+
+ return new_checkpoint
+
+
+def load_pavimodel_dist(model_path, map_location=None):
+ """In distributed setting, this function only download checkpoint at local
+ rank 0."""
+ try:
+ from pavi import modelcloud
+ except ImportError:
+ raise ImportError("Please install pavi to load checkpoint from modelcloud.")
+ rank, world_size = get_dist_info()
+ rank = int(os.environ.get("LOCAL_RANK", rank))
+ if rank == 0:
+ model = modelcloud.get(model_path)
+ with TemporaryDirectory() as tmp_dir:
+ downloaded_file = osp.join(tmp_dir, model.name)
+ model.download(downloaded_file)
+ checkpoint = torch.load(downloaded_file, map_location=map_location)
+ if world_size > 1:
+ torch.distributed.barrier()
+ if rank > 0:
+ model = modelcloud.get(model_path)
+ with TemporaryDirectory() as tmp_dir:
+ downloaded_file = osp.join(tmp_dir, model.name)
+ model.download(downloaded_file)
+ checkpoint = torch.load(downloaded_file, map_location=map_location)
+ return checkpoint
+
+
+def load_fileclient_dist(filename, backend, map_location):
+ """In distributed setting, this function only download checkpoint at local
+ rank 0."""
+ rank, world_size = get_dist_info()
+ rank = int(os.environ.get("LOCAL_RANK", rank))
+ allowed_backends = ["ceph"]
+ if backend not in allowed_backends:
+ raise ValueError(f"Load from Backend {backend} is not supported.")
+ if rank == 0:
+ fileclient = FileClient(backend=backend)
+ buffer = io.BytesIO(fileclient.get(filename))
+ checkpoint = torch.load(buffer, map_location=map_location)
+ if world_size > 1:
+ torch.distributed.barrier()
+ if rank > 0:
+ fileclient = FileClient(backend=backend)
+ buffer = io.BytesIO(fileclient.get(filename))
+ checkpoint = torch.load(buffer, map_location=map_location)
+ return checkpoint
+
+
+def load_state_dict(module, state_dict, strict=False, logger=None):
+ """Load state_dict to a module.
+
+ This method is modified from :meth:`torch.nn.Module.load_state_dict`.
+ Default value for ``strict`` is set to ``False`` and the message for
+ param mismatch will be shown even if strict is False.
+
+ Args:
+ module (Module): Module that receives the state_dict.
+ state_dict (OrderedDict): Weights.
+ strict (bool): whether to strictly enforce that the keys
+ in :attr:`state_dict` match the keys returned by this module's
+ :meth:`~torch.nn.Module.state_dict` function. Default: ``False``.
+ logger (:obj:`logging.Logger`, optional): Logger to log the error
+ message. If not specified, print function will be used.
+ """
+ unexpected_keys = []
+ all_missing_keys = []
+ err_msg = []
+
+ metadata = getattr(state_dict, "_metadata", None)
+ state_dict = state_dict.copy()
+ if metadata is not None:
+ state_dict._metadata = metadata
+
+ # use _load_from_state_dict to enable checkpoint version control
+ def load(module, prefix=""):
+ # recursively check parallel module in case that the model has a
+ # complicated structure, e.g., nn.Module(nn.Module(DDP))
+ if is_module_wrapper(module):
+ module = module.module
+ local_metadata = {} if metadata is None else metadata.get(prefix[:-1], {})
+ module._load_from_state_dict(
+ state_dict,
+ prefix,
+ local_metadata,
+ True,
+ all_missing_keys,
+ unexpected_keys,
+ err_msg,
+ )
+ for name, child in module._modules.items():
+ if child is not None:
+ load(child, prefix + name + ".")
+
+ load(module)
+ load = None # break load->load reference cycle
+
+ # ignore "num_batches_tracked" of BN layers
+ missing_keys = [key for key in all_missing_keys if "num_batches_tracked" not in key]
+
+ if unexpected_keys:
+ err_msg.append(
+ "unexpected key in source " f'state_dict: {", ".join(unexpected_keys)}\n'
+ )
+ if missing_keys:
+ err_msg.append(
+ f'missing keys in source state_dict: {", ".join(missing_keys)}\n'
+ )
+
+ rank, _ = get_dist_info()
+ if len(err_msg) > 0 and rank == 0:
+ err_msg.insert(0, "The model and loaded state dict do not match exactly\n")
+ err_msg = "\n".join(err_msg)
+ if strict:
+ raise RuntimeError(err_msg)
+ elif logger is not None:
+ logger.warning(err_msg)
+ else:
+ print(err_msg)
+
+
+def _load_checkpoint(filename, map_location=None):
+ """Load checkpoint from somewhere (modelzoo, file, url).
+
+ Args:
+ filename (str): Accept local filepath, URL, ``torchvision://xxx``,
+ ``open-mmlab://xxx``. Please refer to ``docs/model_zoo.md`` for
+ details.
+ map_location (str | None): Same as :func:`torch.load`. Default: None.
+
+ Returns:
+ dict | OrderedDict: The loaded checkpoint. It can be either an
+ OrderedDict storing model weights or a dict containing other
+ information, which depends on the checkpoint.
+ """
+ if filename.startswith("modelzoo://"):
+ warnings.warn(
+ 'The URL scheme of "modelzoo://" is deprecated, please '
+ 'use "torchvision://" instead'
+ )
+ model_urls = get_torchvision_models()
+ model_name = filename[11:]
+ checkpoint = load_url_dist(model_urls[model_name])
+ elif filename.startswith("torchvision://"):
+ model_urls = get_torchvision_models()
+ model_name = filename[14:]
+ checkpoint = load_url_dist(model_urls[model_name])
+ elif filename.startswith("open-mmlab://"):
+ model_urls = get_external_models()
+ model_name = filename[13:]
+ deprecated_urls = get_deprecated_model_names()
+ if model_name in deprecated_urls:
+ warnings.warn(
+ f"open-mmlab://{model_name} is deprecated in favor "
+ f"of open-mmlab://{deprecated_urls[model_name]}"
+ )
+ model_name = deprecated_urls[model_name]
+ model_url = model_urls[model_name]
+ # check if is url
+ if model_url.startswith(("http://", "https://")):
+ checkpoint = load_url_dist(model_url)
+ else:
+ filename = osp.join(_get_mmcv_home(), model_url)
+ if not osp.isfile(filename):
+ raise IOError(f"{filename} is not a checkpoint file")
+ checkpoint = torch.load(filename, map_location=map_location)
+ elif filename.startswith("mmcls://"):
+ model_urls = get_mmcls_models()
+ model_name = filename[8:]
+ checkpoint = load_url_dist(model_urls[model_name])
+ checkpoint = _process_mmcls_checkpoint(checkpoint)
+ elif filename.startswith(("http://", "https://")):
+ checkpoint = load_url_dist(filename)
+ elif filename.startswith("pavi://"):
+ model_path = filename[7:]
+ checkpoint = load_pavimodel_dist(model_path, map_location=map_location)
+ elif filename.startswith("s3://"):
+ checkpoint = load_fileclient_dist(
+ filename, backend="ceph", map_location=map_location
+ )
+ else:
+ if not osp.isfile(filename):
+ raise IOError(f"{filename} is not a checkpoint file")
+ checkpoint = torch.load(filename, map_location=map_location)
+ return checkpoint
+
+
+def load_checkpoint(
+ model,
+ filename,
+ map_location="cpu",
+ strict=False,
+ logger=None,
+ patch_padding="pad",
+ part_features=None,
+):
+ """Load checkpoint from a file or URI.
+
+ Args:
+ model (Module): Module to load checkpoint.
+ filename (str): Accept local filepath, URL, ``torchvision://xxx``,
+ ``open-mmlab://xxx``. Please refer to ``docs/model_zoo.md`` for
+ details.
+ map_location (str): Same as :func:`torch.load`.
+ strict (bool): Whether to allow different params for the model and
+ checkpoint.
+ logger (:mod:`logging.Logger` or None): The logger for error message.
+ patch_padding (str): 'pad' or 'bilinear' or 'bicubic', used for interpolate patch embed from 14x14 to 16x16
+
+ Returns:
+ dict or OrderedDict: The loaded checkpoint.
+ """
+ checkpoint = _load_checkpoint(filename, map_location)
+ # OrderedDict is a subclass of dict
+ if not isinstance(checkpoint, dict):
+ raise RuntimeError(f"No state_dict found in checkpoint file {filename}")
+ # get state_dict from checkpoint
+ if "state_dict" in checkpoint:
+ state_dict = checkpoint["state_dict"]
+ elif "model" in checkpoint:
+ state_dict = checkpoint["model"]
+ elif "module" in checkpoint:
+ state_dict = checkpoint["module"]
+ else:
+ state_dict = checkpoint
+ # strip prefix of state_dict
+ if list(state_dict.keys())[0].startswith("module."):
+ state_dict = {k[7:]: v for k, v in state_dict.items()}
+
+ # for MoBY, load model of online branch
+ if sorted(list(state_dict.keys()))[0].startswith("encoder"):
+ state_dict = {
+ k.replace("encoder.", ""): v
+ for k, v in state_dict.items()
+ if k.startswith("encoder.")
+ }
+
+ rank, _ = get_dist_info()
+
+ layer_names = [name for name, param in model.named_parameters()]
+
+ if (
+ "patch_embed.proj.weight" in state_dict
+ and "patch_embed.proj._conv_stem.weight" not in layer_names
+ ):
+ proj_weight = state_dict["patch_embed.proj.weight"]
+ orig_size = proj_weight.shape[2:]
+ current_size = model.patch_embed.proj.weight.shape[2:]
+ padding_size = current_size[0] - orig_size[0]
+ padding_l = padding_size // 2
+ padding_r = padding_size - padding_l
+ if orig_size != current_size:
+ if "pad" in patch_padding:
+ proj_weight = torch.nn.functional.pad(
+ proj_weight, (padding_l, padding_r, padding_l, padding_r)
+ )
+ elif "bilinear" in patch_padding:
+ proj_weight = torch.nn.functional.interpolate(
+ proj_weight, size=current_size, mode="bilinear", align_corners=False
+ )
+ elif "bicubic" in patch_padding:
+ proj_weight = torch.nn.functional.interpolate(
+ proj_weight, size=current_size, mode="bicubic", align_corners=False
+ )
+ state_dict["patch_embed.proj.weight"] = proj_weight
+
+ if "pos_embed" in state_dict:
+ pos_embed_checkpoint = state_dict["pos_embed"]
+ # pos_embed_checkpoint = pos_embed_checkpoint[:, :-1, :]
+ embedding_size = pos_embed_checkpoint.shape[-1]
+ H, W = model.patch_embed.patch_shape
+ num_patches = model.patch_embed.num_patches
+ num_extra_tokens = model.pos_embed.shape[-2] - num_patches
+ # height (== width) for the checkpoint position embedding
+ orig_size = int((pos_embed_checkpoint.shape[-2] - num_extra_tokens) ** 0.5)
+ if rank == 0:
+ print(
+ "Position interpolate from %dx%d to %dx%d"
+ % (orig_size, orig_size, H, W)
+ )
+ extra_tokens = pos_embed_checkpoint[:, :num_extra_tokens]
+ # only the position tokens are interpolated
+ pos_tokens = pos_embed_checkpoint[:, num_extra_tokens:]
+ pos_tokens = pos_tokens.reshape(
+ -1, orig_size, orig_size, embedding_size
+ ).permute(0, 3, 1, 2)
+ pos_tokens = torch.nn.functional.interpolate(
+ pos_tokens, size=(H, W), mode="bicubic", align_corners=False
+ )
+ pos_tokens = pos_tokens.permute(0, 2, 3, 1).flatten(1, 2)
+ new_pos_embed = torch.cat((extra_tokens, pos_tokens), dim=1)
+ state_dict["pos_embed"] = new_pos_embed
+
+ new_state_dict = copy.deepcopy(state_dict)
+ if part_features is not None:
+ current_keys = list(model.state_dict().keys())
+ for key in current_keys:
+ if "mlp.experts" in key:
+ source_key = re.sub(r"experts.\d+.", "fc2.", key)
+ new_state_dict[key] = state_dict[source_key][-part_features:]
+ elif "fc2" in key:
+ new_state_dict[key] = state_dict[key][:-part_features]
+
+ # load state_dict
+ load_state_dict(model, new_state_dict, strict, logger)
+ return checkpoint
+
+
+def swin_converter(ckpt):
+
+ new_ckpt = OrderedDict()
+
+ def correct_unfold_reduction_order(x):
+ out_channel, in_channel = x.shape
+ x = x.reshape(out_channel, 4, in_channel // 4)
+ x = x[:, [0, 2, 1, 3], :].transpose(1, 2).reshape(out_channel, in_channel)
+ return x
+
+ def correct_unfold_norm_order(x):
+ in_channel = x.shape[0]
+ x = x.reshape(4, in_channel // 4)
+ x = x[[0, 2, 1, 3], :].transpose(0, 1).reshape(in_channel)
+ return x
+
+ for k, v in ckpt.items():
+ if k.startswith("head"):
+ continue
+ elif k.startswith("layers"):
+ new_v = v
+ if "attn." in k:
+ new_k = k.replace("attn.", "attn.w_msa.")
+ elif "mlp." in k:
+ if "mlp.fc1." in k:
+ new_k = k.replace("mlp.fc1.", "ffn.layers.0.0.")
+ elif "mlp.fc2." in k:
+ new_k = k.replace("mlp.fc2.", "ffn.layers.1.")
+ else:
+ new_k = k.replace("mlp.", "ffn.")
+ elif "downsample" in k:
+ new_k = k
+ if "reduction." in k:
+ new_v = correct_unfold_reduction_order(v)
+ elif "norm." in k:
+ new_v = correct_unfold_norm_order(v)
+ else:
+ new_k = k
+ new_k = new_k.replace("layers", "stages", 1)
+ elif k.startswith("patch_embed"):
+ new_v = v
+ if "proj" in k:
+ new_k = k.replace("proj", "projection")
+ else:
+ new_k = k
+ else:
+ new_v = v
+ new_k = k
+
+ new_ckpt["backbone." + new_k] = new_v
+
+ return new_ckpt
diff --git a/clean/video/fakestormer/package_utils/__init__.py b/clean/video/fakestormer/package_utils/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..40a96afc6ff09d58a702b76e3f7dd412fe975e26
--- /dev/null
+++ b/clean/video/fakestormer/package_utils/__init__.py
@@ -0,0 +1 @@
+# -*- coding: utf-8 -*-
diff --git a/clean/video/fakestormer/package_utils/_typing.py b/clean/video/fakestormer/package_utils/_typing.py
new file mode 100644
index 0000000000000000000000000000000000000000..37b26c25145f281bc23b6f98915deb58f886ffb1
--- /dev/null
+++ b/clean/video/fakestormer/package_utils/_typing.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+from typing import Dict, List, Optional, Tuple, Union
+
+from mmengine.config import ConfigDict
+from mmengine.structures import InstanceData, PixelData
+from torch import Tensor
+
+# Type hint of config data
+ConfigType = Union[ConfigDict, dict]
+OptConfigType = Optional[ConfigType]
+
+# Type hint of one or more config data
+MultiConfig = Union[ConfigType, List[ConfigType]]
+OptMultiConfig = Optional[MultiConfig]
+
+# Type hint of data samples
+InstanceList = List[InstanceData]
+PixelDataList = List[PixelData]
+Predictions = Union[InstanceList, Tuple[InstanceList, PixelDataList]]
+
+# Type hint of features
+Features = Union[Tuple[Tensor], List[Tuple[Tensor]], List[List[Tuple[Tensor]]]]
diff --git a/clean/video/fakestormer/package_utils/bi_online_generation.py b/clean/video/fakestormer/package_utils/bi_online_generation.py
new file mode 100644
index 0000000000000000000000000000000000000000..dfd4a95891008f049b77eced6edb96a21e710728
--- /dev/null
+++ b/clean/video/fakestormer/package_utils/bi_online_generation.py
@@ -0,0 +1,551 @@
+# -*- coding: utf-8 -*-
+import os
+import random
+import sys
+
+if os.getcwd() not in sys.path:
+ sys.path.insert(0, os.getcwd())
+
+import argparse
+import multiprocessing as mp
+import queue
+import time
+from threading import Thread
+
+import cv2
+import numpy as np
+from imgaug import augmenters as iaa
+from matplotlib import pyplot as plt
+from package_utils.deepfake_mask import random_get_hull
+from package_utils.utils import load_file, save_file
+from PIL import Image
+from skimage import io
+from skimage import transform as sktransform
+from tqdm import tqdm
+
+# from datasets.sbi.utils import gen_target
+
+IMAGE_H, IMAGE_W, IMAGE_CHANNEL = 256, 256, 3
+COMPRESSION = "c0"
+SPLIT = "train"
+DATA_TYPE = "frames"
+IMAGE_ROOT = f"/data/deepfake_cluster/datasets_df/FaceForensics++/{COMPRESSION}/"
+ANNO_FILE = "processed_data/train_faceforensics_processed.json"
+DEST_DIR = "FaceXRay"
+LABEL_FILE = "train_FF_FaceXRay.json"
+NUMBER_OF_PROCESS = 4
+BLENDING_TYPE = "BI"
+MARGIN = 20
+
+
+def args_parse(args=None):
+ args_parser = argparse.ArgumentParser("Blending Image Processing Hub...")
+ args_parser.add_argument("--task", "-t", help="Defining task!")
+ args_parser.add_argument("--anno_file", "-f", help="Pre annotation file!")
+ args_parser.add_argument("--fake_type", "-ft", help="Faketype to manipulation!")
+ args_parser.add_argument(
+ "--mp", "-m", help="Apply multiprocessing", action="store_true"
+ )
+ args = args_parser.parse_args(args)
+ return args
+
+
+def name_resolve(path):
+ if COMPRESSION == "c23":
+ name = os.path.splitext(os.path.basename(path))[0]
+ vid_id, frame_id = name.split("_")[0:2]
+ else:
+ name = path.split("/")
+ vid_id, frame_id = name[-2], os.path.splitext(name[-1])[0]
+ return vid_id, frame_id
+
+
+def gen_real_fimg_mask(img_path):
+ face_img = io.imread(img_path)
+ mask = np.zeros((face_img.shape[0], face_img.shape[1], 3))
+ mask = (mask * 255).astype(np.uint8)
+ return face_img, mask
+
+
+def total_euclidean_distance(a, b):
+ assert len(a.shape) == 2
+ return np.sum(np.linalg.norm(a - b, axis=1))
+
+
+def random_erode_dilate(mask, **kwargs):
+ ksize = kwargs.get("ksize")
+ rand_erode = kwargs.get("rand_erode") or random.random()
+
+ if rand_erode > 0.5:
+ if ksize is None:
+ ksize = random.randint(1, 21)
+ if ksize % 2 == 0:
+ ksize += 1
+ mask = np.array(mask).astype(np.uint8) * 255
+ kernel = np.ones((ksize, ksize), np.uint8)
+ mask = cv2.erode(mask, kernel, 1) / 255
+ else:
+ if ksize is None:
+ ksize = random.randint(1, 5)
+ if ksize % 2 == 0:
+ ksize += 1
+ mask = np.array(mask).astype(np.uint8) * 255
+ kernel = np.ones((ksize, ksize), np.uint8)
+ mask = cv2.dilate(mask, kernel, 1) / 255
+ return mask, ksize, rand_erode
+
+
+# borrow from https://github.com/MarekKowalski/FaceSwap
+def blendImages(src, dst, mask, featherAmount=0.2, **kwargs):
+ if kwargs.get("blend_ratio") is None:
+ blend_list = [0.25, 0.5, 0.75, 1, 1, 1]
+ blend_ratio = blend_list[np.random.randint(len(blend_list))]
+ else:
+ blend_ratio = kwargs.get("blend_ratio")
+
+ # mask = blend_ratio * mask # Applying a blending ratio from SBI to BI blending weights
+ maskIndices = np.where(mask != 0)
+
+ src_mask = np.ones_like(mask)
+ dst_mask = np.zeros_like(mask)
+
+ maskPts = np.hstack((maskIndices[1][:, np.newaxis], maskIndices[0][:, np.newaxis]))
+ faceSize = np.max(maskPts, axis=0) - np.min(maskPts, axis=0)
+ featherAmount = featherAmount * np.max(faceSize)
+
+ hull = cv2.convexHull(maskPts)
+ dists = np.zeros(maskPts.shape[0])
+
+ for i in range(maskPts.shape[0]):
+ dists[i] = cv2.pointPolygonTest(hull, (maskPts[i, 0], maskPts[i, 1]), True)
+
+ weights = np.clip(dists / featherAmount, 0, 1)
+
+ composedImg = np.copy(dst)
+ composedImg[maskIndices[0], maskIndices[1]] = (
+ weights[:, np.newaxis] * src[maskIndices[0], maskIndices[1]]
+ + (1 - weights[:, np.newaxis]) * dst[maskIndices[0], maskIndices[1]]
+ )
+
+ composedMask = np.copy(dst_mask)
+ composedMask[maskIndices[0], maskIndices[1]] = (
+ weights[:, np.newaxis] * src_mask[maskIndices[0], maskIndices[1]]
+ + (1 - weights[:, np.newaxis]) * dst_mask[maskIndices[0], maskIndices[1]]
+ )
+
+ blend_params = {"blend_ratio": blend_ratio}
+
+ return composedImg, composedMask, blend_params
+
+
+# borrow from https://github.com/MarekKowalski/FaceSwap
+def colorTransfer(src, dst, mask):
+ transferredDst = np.copy(dst)
+
+ maskIndices = np.where(mask != 0)
+
+ maskedSrc = src[maskIndices[0], maskIndices[1]].astype(np.int32)
+ maskedDst = dst[maskIndices[0], maskIndices[1]].astype(np.int32)
+
+ meanSrc = np.mean(maskedSrc, axis=0)
+ meanDst = np.mean(maskedDst, axis=0)
+
+ maskedDst = maskedDst - meanDst
+ maskedDst = maskedDst + meanSrc
+ maskedDst = np.clip(maskedDst, 0, 255)
+
+ transferredDst[maskIndices[0], maskIndices[1]] = maskedDst
+
+ return transferredDst
+
+
+class BIOnlineGeneration:
+ def __init__(
+ self, data_record, queue_size=1024, mlprocess=False, number=1, fake_type=None
+ ):
+ self.landmarks_record = {}
+ self.data_record = data_record["data"]
+ self.mlprocess = mlprocess
+ self.number = number
+ self.fake_type = fake_type
+
+ if self.fake_type is not None:
+ self.data_record = self._filter_data()
+ if not len(self.data_record):
+ raise ValueError("DataList can not be Empty!")
+
+ print(
+ f"You are generating data for --- {self.fake_type} --- {len(self.data_record)} images"
+ )
+
+ for item in self.data_record:
+ if "aligned_lms" in item.keys() and len(item["aligned_lms"]):
+ self.landmarks_record[item["image_path"]] = np.array(
+ item["aligned_lms"]
+ )
+ else:
+ self.landmarks_record[item["image_path"]] = np.array(item["orig_lms"])
+
+ # extract all frame from all video in the name of {videoid}_{frameid}
+ self.data_list = [item["image_path"] for item in self.data_record]
+ self.file_names = [item["file_name"] for item in self.data_record]
+
+ if COMPRESSION != "c23":
+ self.labels = [
+ item["image_path"].split("/")[-3] for item in self.data_record
+ ]
+ else:
+ self.labels = [
+ item["image_path"].split("/")[-2] for item in self.data_record
+ ]
+ self.vid_ids = [item["image_path"].split("/")[-2] for item in self.data_record]
+
+ # predefine mask distortion
+ self.distortion = iaa.Sequential([iaa.PiecewiseAffine(scale=(0.01, 0.15))])
+
+ self.result_queue = mp.Queue(maxsize=queue_size)
+ self.final_results = []
+
+ def register_task(self, target):
+ if self.mlprocess:
+ p = mp.Process(target=target, args=())
+ else:
+ p = Thread(target=target, args=())
+ return p
+
+ def start(self, p):
+ self.result_worker = p
+ self.result_worker.start()
+
+ def wait_n_put(self, item):
+ self.result_queue.put(item)
+
+ def wait_n_get(self):
+ return self.result_queue.get()
+
+ def count(self):
+ return self.result_queue.qsize()
+
+ def stop(self):
+ self.result_worker.join()
+
+ def running(self):
+ return not self.result_queue.empty()
+
+ def terminate(self):
+ self.result_worker.terminate()
+
+ def clear(self):
+ while not self.result_queue.empty():
+ self.result_queue.get()
+
+ def clear_sequences(self):
+ self.clear()
+
+ def get_results(self):
+ all_objs = []
+
+ while not self.final_results.empty():
+ all_objs.append(self.final_results.get())
+ return all_objs
+
+ def _filter_data(self):
+ assert self.fake_type is not None, "Fake type is require to filter data!"
+ assert self.fake_type in [
+ "Deepfakes",
+ "Face2Face",
+ "FaceSwap",
+ "NeuralTextures",
+ ]
+
+ self.data_record = [
+ item for item in self.data_record if item["fake_type"] == self.fake_type
+ ]
+ return self.data_record
+
+ def gen_one_datapoint(self, idx):
+ background_face_path = self.data_list[idx]
+ label = self.labels[idx]
+
+ # Choose Blending type
+ if BLENDING_TYPE != "SBI":
+ data_type = "real" if random.randint(0, 1) else "fake"
+ else:
+ data_type = "fake"
+
+ # Handle for the cases of blank landmarks, auto real if real label is real image, otherwise return
+ if not self.landmarks_record[background_face_path].any():
+ if not ("fake" == label):
+ data_type = "real"
+ else:
+ return None, None, None
+
+ if data_type == "fake":
+ if BLENDING_TYPE != "SBI":
+ face_img, mask = self.get_blended_face(
+ background_face_path, self.landmarks_record[background_face_path]
+ )
+ else:
+ face_img, mask, face_r, mask_r = gen_target(
+ os.path.join(IMAGE_ROOT, background_face_path),
+ self.landmarks_record[background_face_path],
+ margin=[MARGIN, MARGIN],
+ )
+ else:
+ face_img, mask = gen_real_fimg_mask(
+ os.path.join(IMAGE_ROOT, background_face_path)
+ )
+
+ face_img = face_img[MARGIN : IMAGE_H - MARGIN, MARGIN : IMAGE_W - MARGIN, :]
+ mask = mask[MARGIN : IMAGE_H - MARGIN, MARGIN : IMAGE_W - MARGIN, :]
+
+ return face_img, mask, data_type
+
+ def get_blended_face(self, background_face_path, background_landmark):
+ background_face = io.imread(os.path.join(IMAGE_ROOT, background_face_path))
+
+ foreground_face_path = self.search_similar_face(
+ background_landmark, background_face_path, get_best=True
+ )
+ foreground_face = io.imread(os.path.join(IMAGE_ROOT, foreground_face_path))
+
+ # down sample before blending
+ img_h, img_w = background_face.shape[:2]
+ aug_size = random.randint(img_h // 2, img_h)
+ background_landmark = background_landmark * (aug_size / img_h)
+
+ foreground_face = sktransform.resize(
+ foreground_face, (aug_size, aug_size), preserve_range=True
+ ).astype(np.uint8)
+ background_face = sktransform.resize(
+ background_face, (aug_size, aug_size), preserve_range=True
+ ).astype(np.uint8)
+
+ # get random type of initial blending mask
+ mask = random_get_hull(background_landmark, background_face)
+
+ # random deform mask
+ mask = self.distortion.augment_image(mask)
+ mask = random_erode_dilate(mask)
+
+ # filte empty mask after deformation
+ if np.sum(mask) == 0:
+ print(
+ f"There was an issue when doing blending with Image -- {background_face_path}"
+ )
+ print(f"Reverting by returning a real image and mask...")
+ face_img, mask = gen_real_fimg_mask(
+ os.path.join(IMAGE_ROOT, background_face_path)
+ )
+ return face_img, mask
+
+ # apply color transfer
+ foreground_face = colorTransfer(background_face, foreground_face, mask * 255)
+
+ # blend two face
+ blended_face, mask = blendImages(foreground_face, background_face, mask * 255)
+ blended_face = blended_face.astype(np.uint8)
+
+ # resize back to default resolution
+ blended_face = sktransform.resize(
+ blended_face, (img_h, img_w), preserve_range=True
+ ).astype(np.uint8)
+ mask = sktransform.resize(mask, (img_h, img_w), preserve_range=True)
+ mask = mask[:, :, 0:1]
+ mask = (1 - mask) * mask * 4
+ mask = np.repeat(mask, 3, 2)
+ mask = (mask * 255).astype(np.uint8)
+
+ # randomly downsample after BI pipeline
+ face_img = Image.fromarray(blended_face)
+ if random.randint(0, 1):
+ aug_size = random.randint(img_h // 4, img_h)
+ if random.randint(0, 1):
+ face_img = face_img.resize((aug_size, aug_size), Image.BILINEAR)
+ else:
+ face_img = face_img.resize((aug_size, aug_size), Image.NEAREST)
+ face_img = face_img.resize((img_h, img_w), Image.BILINEAR)
+ face_img = np.array(face_img)
+
+ # # random jpeg compression after BI pipeline
+ # if random.randint(0,1):
+ # quality = random.randint(60, 100)
+ # encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), quality]
+ # face_img_encode = cv2.imencode('.jpg', face_img, encode_param)[1]
+ # face_img = cv2.imdecode(face_img_encode, cv2.IMREAD_COLOR)
+
+ # # random flip
+ # if random.randint(0,1):
+ # face_img = np.flip(face_img,1)
+ # mask = np.flip(mask,1)
+
+ return face_img, mask
+
+ def search_similar_face(self, this_landmark, background_face_path, get_best=False):
+ vid_id, frame_id = name_resolve(background_face_path)
+ min_dist = 99999999
+
+ # random sample 5000 frame from all frams:
+ all_candidate_path = random.sample(self.data_list, k=10000)
+
+ # filter all frame that comes from the same video as background face
+ all_candidate_path = filter(
+ lambda k: name_resolve(k)[0] != vid_id, all_candidate_path
+ )
+ all_candidate_path = list(all_candidate_path)
+ candidate_distance_list = {}
+
+ # loop throungh all candidates frame to get best match
+ for candidate_path in all_candidate_path:
+ candidate_landmark = self.landmarks_record[candidate_path].astype(
+ np.float32
+ )
+
+ if not candidate_landmark.any():
+ continue
+
+ candidate_distance = total_euclidean_distance(
+ candidate_landmark, this_landmark
+ )
+ if candidate_distance < min_dist:
+ min_dist = candidate_distance
+ min_path = candidate_path
+ candidate_distance_list[candidate_path] = candidate_distance
+ if not get_best:
+ return candidate_distance_list
+ else:
+ return min_path
+
+ def search_similar_faces(self):
+ while True:
+ item = self.wait_n_get()
+ if item is None:
+ obj_list = self.final_results
+ data = {"data": obj_list}
+ save_file(
+ data, f"processed_data/{COMPRESSION}/dynamic_trainBI_FFv4.json"
+ )
+ return True
+ bg_path = item["image_path"]
+ if "aligned_lms" in item.keys() and len(item["aligned_lms"]):
+ f_lms = np.array(item["aligned_lms"])
+ else:
+ f_lms = np.array(item["orig_lms"])
+ best_match_paths = []
+
+ if f_lms.any():
+ candidate_list = self.search_similar_face(f_lms, bg_path)
+ best_match_paths = sorted(
+ candidate_list.items(), key=lambda x: x[1], reverse=False
+ )[: self.number]
+ best_match_paths = [it[0] for it in best_match_paths]
+ item["best_match"] = best_match_paths
+ self.final_results.append(item)
+
+
+if __name__ == "__main__":
+ if sys.argv[1:] is not None:
+ args = args_parse(sys.argv[1:])
+ else:
+ args = sys.argv[:-1]
+
+ task = args.task
+ anno_file = args.anno_file
+ mp_ = args.mp
+ fake_type = args.fake_type
+ assert len(anno_file), "Annotation file path can not be empty!"
+ assert os.access(
+ anno_file, os.R_OK
+ ), "Annotation file path must be valid to access!"
+
+ print("Starting to load processed data...")
+ start = time.time()
+ data_record = load_file(anno_file)
+ print("Loading time --- {}".format(time.time() - start))
+ ds = BIOnlineGeneration(data_record, mlprocess=mp_, number=30, fake_type=fake_type)
+ data = {}
+
+ assert task in ["save_blending", "search_similar_lms"]
+ if task == "save_blending":
+ all_object = []
+
+ for i in tqdm(range(len(ds.data_list))):
+ img, mask, label = ds.gen_one_datapoint(i)
+ if img is None and mask is None and label is None:
+ continue
+
+ if COMPRESSION == "c23":
+ image_path = os.path.join(
+ IMAGE_ROOT, DEST_DIR, "images", ds.file_names[i]
+ )
+ mask_path = os.path.join(
+ IMAGE_ROOT, DEST_DIR, "masks", ds.file_names[i]
+ )
+ else:
+ image_path = os.path.join(
+ IMAGE_ROOT,
+ SPLIT,
+ DATA_TYPE,
+ DEST_DIR,
+ "images",
+ f"{ds.vid_ids[i]}_{ds.file_names[i]}",
+ )
+ mask_path = os.path.join(
+ IMAGE_ROOT,
+ SPLIT,
+ DATA_TYPE,
+ DEST_DIR,
+ "masks",
+ f"{ds.vid_ids[i]}_{ds.file_names[i]}",
+ )
+
+ try:
+ mask_pil = Image.fromarray(mask)
+ mask_pil.save(mask_path)
+
+ image = Image.fromarray(img)
+ image.save(image_path)
+ except Exception as e:
+ print(e)
+ continue
+
+ all_object.append(
+ {
+ "id": i,
+ "image_path": image_path,
+ "mask_path": mask_path,
+ "label": label,
+ }
+ )
+ data["data"] = all_object
+ save_file(
+ data,
+ file_path=os.path.join(IMAGE_ROOT, SPLIT, DATA_TYPE, DEST_DIR, LABEL_FILE),
+ )
+ elif task == "search_similar_lms":
+ p = ds.register_task(ds.search_similar_faces)
+ ds.start(p)
+
+ try:
+ for i, item in enumerate(tqdm(ds.data_record, dynamic_ncols=True)):
+ ds.wait_n_put(item)
+ ds.wait_n_put(None)
+
+ while ds.running():
+ time.sleep(1)
+ print(
+ "===============> Rendering remaining "
+ + str(ds.count())
+ + " images in the queue...",
+ end="\r",
+ )
+ ds.stop()
+ except Exception as e:
+ print(repr(e))
+ print("There is an exception during process! Please check it")
+ except KeyboardInterrupt:
+ ds.terminate()
+ ds.clear_sequences()
+ exit(0)
+ else:
+ raise ValueError("This task {} is not supported at the moment!")
diff --git a/clean/video/fakestormer/package_utils/cam_vis.py b/clean/video/fakestormer/package_utils/cam_vis.py
new file mode 100644
index 0000000000000000000000000000000000000000..52c9b52a1fcd42051c2a0e2bd65883b91e5c853e
--- /dev/null
+++ b/clean/video/fakestormer/package_utils/cam_vis.py
@@ -0,0 +1,269 @@
+# -*-coding: utf-8 -*-
+import argparse
+import math
+import os
+import sys
+from copy import deepcopy
+
+if not os.getcwd() in sys.path:
+ sys.path.append(os.getcwd())
+
+from glob import glob
+
+import matplotlib.pyplot as plt
+import numpy as np
+import torch
+import torch.nn.functional as F
+from configs.get_config import load_config
+from image_utils import overlay_mask
+from logs.logger import Logger
+from models import MODELS, build_model
+from models.utils import load_pretrained
+from natsort import natsorted
+from PIL import Image
+from torchcam import methods
+from torchvision.transforms.functional import resize, to_pil_image
+from transform import final_transform
+
+
+def main():
+ argparser = argparse.ArgumentParser("Arguments for CAM visualization...")
+ argparser.add_argument("--cfg", help="Specify config to load", required=True)
+ argparser.add_argument(
+ "--target_layer",
+ "-t",
+ help="Specify layer names to visualize CAM",
+ required=False,
+ )
+ argparser.add_argument(
+ "--method", "-m", type=str, default="GradCAM", help="CAM method to use"
+ )
+ argparser.add_argument(
+ "--mode",
+ type=str,
+ choices=["image", "video"],
+ default="image",
+ help="Mode to visualize gradCAM",
+ )
+ argparser.add_argument(
+ "--image", "-i", help="Specify image to overlay CAM", required=False
+ )
+ argparser.add_argument(
+ "--video", "-v", help="Specify video to overlay CAM", required=False
+ )
+ argparser.add_argument(
+ "--savefig", type=str, default=None, help="Path to save figure"
+ )
+ argparser.add_argument(
+ "--rows", type=int, default=1, help="Number of rows for the layout"
+ )
+ argparser.add_argument(
+ "--class-idx", type=int, default=0, help="Index of the class to inspect"
+ )
+ argparser.add_argument(
+ "--alpha", type=float, default=0.5, help="Transparency of the heatmap"
+ )
+ argparser.add_argument("--cuda", action="store_true", help="Running CAM with cuda")
+ argparser.add_argument(
+ "--save_inverse", action="store_true", help="Saving the inverse of CAM"
+ )
+ args = argparser.parse_args()
+ print(args)
+
+ # Loading configs
+ cfg = load_config(args.cfg)
+
+ # Logger
+ logger = Logger(task="CAM_vis")
+
+ # Loading model based on the config
+ model = build_model(cfg.MODEL, MODELS).to(torch.float)
+ logger.info("Loading weight ... {}".format(cfg.TEST.pretrained))
+ model = load_pretrained(model, cfg.TEST.pretrained)
+
+ if args.cuda:
+ model = model.cuda()
+ model.eval()
+
+ # Freeze the model
+ for p in model.parameters():
+ p.requires_grad_(False)
+
+ # Loading image
+ img_list = []
+ if args.mode == "image":
+ assert os.path.exists(
+ args.image
+ ), "Image path must be valid, please check the path again!"
+ img = Image.open(args.image)
+ H, W = img.size
+ img = img.crop((0, 0, W - 0, H - 0))
+ img_list.append(img)
+ elif args.mode == "video":
+ assert os.path.exists(
+ args.video
+ ), "Video path must be valid, please check the path again!"
+ n_frames = cfg.DATASET.DATA.SAMPLES_PER_VIDEO.NUM_FRAMES
+ assert n_frames is not None, "Number of video frames can not be None!"
+ # Load first n_frames inside the video
+ img_paths = glob(f"{args.video}/*.png")
+ img_paths = natsorted(img_paths) # correct the order of image paths
+ img_paths = img_paths[:n_frames]
+ for img_path in img_paths:
+ img = Image.open(img_path)
+ H, W = img.size
+ img = img.crop((0, 0, W - 0, H - 0))
+ img_list.append(img)
+ else:
+ raise ValueError(
+ "We only support GradCAM for image or video mode at the moment!"
+ )
+
+ # Preprocess image
+ transform = final_transform(cfg.DATASET)
+ image_size = (cfg.DATASET.IMAGE_SIZE[0], cfg.DATASET.IMAGE_SIZE[1])
+
+ # Transform images
+ transformed_imgs = torch.tensor([])
+ for _i in img_list:
+ img_resize = _i.resize(image_size)
+ img_resize = np.array(img_resize) / 255
+ img_tensor = transform(img_resize).to(torch.float)
+ if args.cuda:
+ img_tensor = img_tensor.cuda()
+ img_tensor.requires_grad_(True)
+ transformed_imgs = torch.cat((transformed_imgs, img_tensor.unsqueeze(0)), 0)
+
+ # Hook the corresponding layer in the model
+ if isinstance(args.method, str):
+ cam_methods = args.method.split(",")
+ else:
+ cam_methods = [
+ "CAM",
+ "GradCAM",
+ "GradCAMpp",
+ "SmoothGradCAMpp",
+ "ScoreCAM",
+ "SSCAM",
+ "ISCAM",
+ "XGradCAM",
+ "LayerCAM",
+ ]
+ cam_extractors = [
+ methods.__dict__[name](
+ model, target_layer=args.target_layer, enable_hooks=False
+ )
+ for name in cam_methods
+ ]
+
+ if args.mode == "image":
+ num_rows = args.rows
+ num_cols = math.ceil((len(cam_extractors)) / num_rows) + 1
+ else:
+ num_cols = n_frames
+ num_rows = len(cam_extractors) + 1
+
+ _, axes = plt.subplots(num_rows, num_cols, figsize=(6, 4))
+ # Display input
+ for idx, _i in enumerate(img_list):
+ ax = axes[0][idx] if num_rows > 1 else axes[0] if num_cols > 1 else axes
+ ax.imshow(_i)
+ ax.set_title("Input", size=8)
+
+ for idx, extractor in zip(range(1, len(cam_extractors) + 1), cam_extractors):
+ extractor._hooks_enabled = True
+ model.zero_grad()
+ if args.mode == "image":
+ scores = model(transformed_imgs)[0]["cls"].sigmoid()
+ else:
+ transformed_imgs = transformed_imgs.transpose(0, 1).unsqueeze(0)
+ scores = (
+ model(transformed_imgs)[0]["hm"]
+ .sigmoid()
+ .view(1, -1)
+ .max(1, keepdim=True)
+ .values
+ )
+ # output, attn = model(transformed_imgs) # For visualizing the attn scores, will comeback later
+ # scores = output[0]['temp_loc'].sigmoid()
+ print("Classification Score -- {}".format(scores))
+
+ # Select the class index
+ class_idx = (
+ scores.squeeze(0).argmax().item()
+ if args.class_idx is None
+ else args.class_idx
+ )
+ # class_idx = img_idx
+
+ # Use the hooked data to compute activation map
+ activation_map = (
+ extractor(class_idx, scores)[0].to(torch.float).squeeze(0).cpu()
+ )
+ # activation_map = torch.cat((activation_map, torch.zeros(4)), 0)
+ # activation_map = F.adaptive_avg_pool1d(activation_map.unsqueeze(0), 196).squeeze(0)
+ # activation_map = activation_map[class_idx, 1:].reshape((14, 14))
+
+ # Clean data
+ extractor.remove_hooks()
+ extractor._hooks_enabled = False
+
+ for img_idx, i_ in enumerate(img_list):
+ # Convert it to PL image
+ # The indexing below means first image in batch
+ heatmap = to_pil_image(activation_map[img_idx].unsqueeze(0), mode="F")
+ # activation_map = attn[img_idx].mean(0)[0, 1:]
+ # activation_map = activation_map.reshape((14, 14)).detach()
+ # activation_map = (activation_map - activation_map.min()) / (activation_map.max() - activation_map.min())
+ # heatmap = to_pil_image(activation_map.unsqueeze(0), mode='F')
+
+ # Plot the result
+ result = overlay_mask(deepcopy(i_), heatmap, alpha=args.alpha)
+
+ ax = (
+ axes[idx][img_idx]
+ if num_rows > 1
+ else axes[idx] if num_cols > 1 else axes
+ )
+
+ ax.imshow(result)
+ ax.set_title(extractor.__class__.__name__, size=8)
+
+ # Compute the inverse heatmap
+ if args.save_inverse:
+ inverse_activation_map = torch.sub(
+ 1, activation_map[img_idx].unsqueeze(0)
+ )
+ inverse_heatmap = to_pil_image(inverse_activation_map, mode="F")
+ result_inverse = overlay_mask(
+ deepcopy(img), inverse_heatmap, alpha=args.alpha
+ )
+ ax = (
+ axes[idx][img_idx]
+ if args.rows > 1
+ else axes[idx] if num_cols > 1 else axes
+ )
+ ax.imshow(result_inverse)
+ ax.set_title(f"{extractor.__class__.__name__}_inverse", size=8)
+
+ # Clear axes
+ if num_cols > 1:
+ for _axes in axes:
+ if num_rows > 1:
+ for ax in _axes:
+ ax.axis("off")
+ else:
+ _axes.axis("off")
+
+ else:
+ axes.axis("off")
+
+ plt.tight_layout()
+ if args.savefig:
+ plt.savefig(
+ args.savefig, dpi=200, transparent=True, bbox_inches="tight", pad_inches=0
+ )
+
+
+if __name__ == "__main__":
+ main()
diff --git a/clean/video/fakestormer/package_utils/deepfake_mask.py b/clean/video/fakestormer/package_utils/deepfake_mask.py
new file mode 100644
index 0000000000000000000000000000000000000000..914376b2e72de3b82d01d9ae22ee9fbb00e1e145
--- /dev/null
+++ b/clean/video/fakestormer/package_utils/deepfake_mask.py
@@ -0,0 +1,303 @@
+# -*- coding: utf-8 -*-
+"""Masks functions for faceswap.py"""
+
+import inspect
+import logging
+import random
+import sys
+
+import cv2
+import numpy as np
+
+logger = logging.getLogger(__name__) # pylint: disable=invalid-name
+
+
+def get_available_masks():
+ """Return a list of the available masks for cli"""
+ masks = sorted(
+ [
+ name
+ for name, obj in inspect.getmembers(sys.modules[__name__])
+ if inspect.isclass(obj) and name != "Mask"
+ ]
+ )
+ masks.append("none")
+ logger.debug(masks)
+ return masks
+
+
+def get_default_mask():
+ """Set the default mask for cli"""
+ masks = get_available_masks()
+ default = "dfl_full"
+ default = default if default in masks else masks[0]
+ logger.debug(default)
+ return default
+
+
+class Mask:
+ """Parent class for masks
+ the output mask will be .mask
+ channels: 1, 3 or 4:
+ 1 - Returns a single channel mask
+ 3 - Returns a 3 channel mask
+ 4 - Returns the original image with the mask in the alpha channel"""
+
+ def __init__(self, landmarks, face, channels=4):
+ # logger.info("Initializing %s: (face_shape: %s, channels: %s, landmarks: %s)",
+ # self.__class__.__name__, face.shape, channels, landmarks)
+ self.landmarks = landmarks
+ self.face = face
+ self.channels = channels
+
+ mask = self.build_mask()
+ self.mask = self.merge_mask(mask)
+ # logger.info("Initialized %s", self.__class__.__name__)
+
+ def build_mask(self):
+ """Override to build the mask"""
+ raise NotImplementedError
+
+ def merge_mask(self, mask):
+ """Return the mask in requested shape"""
+ # logger.info("mask_shape: %s", mask.shape)
+ assert self.channels in (1, 3, 4), "Channels should be 1, 3 or 4"
+ assert (
+ mask.shape[2] == 1 and mask.ndim == 3
+ ), "Input mask be 3 dimensions with 1 channel"
+
+ if self.channels == 3:
+ retval = np.tile(mask, 3)
+ elif self.channels == 4:
+ retval = np.concatenate((self.face, mask), -1)
+ else:
+ retval = mask
+
+ # logger.info("Final mask shape: %s", retval.shape)
+ return retval
+
+
+class dfl_full(Mask): # pylint: disable=invalid-name
+ """DFL facial mask"""
+
+ def build_mask(self):
+ mask = np.zeros(self.face.shape[0:2] + (1,), dtype=np.float32)
+
+ nose_ridge = (self.landmarks[27:31], self.landmarks[33:34])
+ jaw = (
+ self.landmarks[0:17],
+ self.landmarks[48:68],
+ self.landmarks[0:1],
+ self.landmarks[8:9],
+ self.landmarks[16:17],
+ )
+ eyes = (
+ self.landmarks[17:27],
+ self.landmarks[0:1],
+ self.landmarks[27:28],
+ self.landmarks[16:17],
+ self.landmarks[33:34],
+ )
+ parts = [jaw, nose_ridge, eyes]
+
+ for item in parts:
+ merged = np.concatenate(item)
+ cv2.fillConvexPoly(
+ mask, cv2.convexHull(merged), 255.0
+ ) # pylint: disable=no-member
+ return mask
+
+
+class components(Mask): # pylint: disable=invalid-name
+ """Component model mask"""
+
+ def build_mask(self):
+ mask = np.zeros(self.face.shape[0:2] + (1,), dtype=np.float32)
+
+ r_jaw = (self.landmarks[0:9], self.landmarks[17:18])
+ l_jaw = (self.landmarks[8:17], self.landmarks[26:27])
+ r_cheek = (self.landmarks[17:20], self.landmarks[8:9])
+ l_cheek = (self.landmarks[24:27], self.landmarks[8:9])
+ nose_ridge = (
+ self.landmarks[19:25],
+ self.landmarks[8:9],
+ )
+ r_eye = (
+ self.landmarks[17:22],
+ self.landmarks[27:28],
+ self.landmarks[31:36],
+ self.landmarks[8:9],
+ )
+ l_eye = (
+ self.landmarks[22:27],
+ self.landmarks[27:28],
+ self.landmarks[31:36],
+ self.landmarks[8:9],
+ )
+ nose = (self.landmarks[27:31], self.landmarks[31:36])
+ parts = [r_jaw, l_jaw, r_cheek, l_cheek, nose_ridge, r_eye, l_eye, nose]
+
+ for item in parts:
+ merged = np.concatenate(item)
+ cv2.fillConvexPoly(
+ mask, cv2.convexHull(merged), 255.0
+ ) # pylint: disable=no-member
+ return mask
+
+
+class extended(Mask): # pylint: disable=invalid-name
+ """Extended mask
+ Based on components mask. Attempts to extend the eyebrow points up the forehead
+ """
+
+ def build_mask(self):
+ mask = np.zeros(self.face.shape[0:2] + (1,), dtype=np.float32)
+
+ landmarks = self.landmarks.copy()
+ # mid points between the side of face and eye point
+ ml_pnt = (landmarks[36] + landmarks[0]) // 2
+ mr_pnt = (landmarks[16] + landmarks[45]) // 2
+
+ # mid points between the mid points and eye
+ ql_pnt = (landmarks[36] + ml_pnt) // 2
+ qr_pnt = (landmarks[45] + mr_pnt) // 2
+
+ # Top of the eye arrays
+ bot_l = np.array(
+ (ql_pnt, landmarks[36], landmarks[37], landmarks[38], landmarks[39])
+ )
+ bot_r = np.array(
+ (landmarks[42], landmarks[43], landmarks[44], landmarks[45], qr_pnt)
+ )
+
+ # Eyebrow arrays
+ top_l = landmarks[17:22]
+ top_r = landmarks[22:27]
+
+ # Adjust eyebrow arrays
+ landmarks[17:22] = top_l + ((top_l - bot_l) // 2)
+ landmarks[22:27] = top_r + ((top_r - bot_r) // 2)
+
+ r_jaw = (landmarks[0:9], landmarks[17:18])
+ l_jaw = (landmarks[8:17], landmarks[26:27])
+ r_cheek = (landmarks[17:20], landmarks[8:9])
+ l_cheek = (landmarks[24:27], landmarks[8:9])
+ nose_ridge = (
+ landmarks[19:25],
+ landmarks[8:9],
+ )
+ r_eye = (landmarks[17:22], landmarks[27:28], landmarks[31:36], landmarks[8:9])
+ l_eye = (landmarks[22:27], landmarks[27:28], landmarks[31:36], landmarks[8:9])
+ nose = (landmarks[27:31], landmarks[31:36])
+ parts = [r_jaw, l_jaw, r_cheek, l_cheek, nose_ridge, r_eye, l_eye, nose]
+
+ for item in parts:
+ merged = np.concatenate(item)
+ cv2.fillConvexPoly(
+ mask, cv2.convexHull(merged), 255.0
+ ) # pylint: disable=no-member
+ return mask
+
+
+class facehull(Mask): # pylint: disable=invalid-name
+ """Basic face hull mask"""
+
+ def build_mask(self):
+ mask = np.zeros(self.face.shape[0:2] + (1,), dtype=np.float32)
+ hull = cv2.convexHull( # pylint: disable=no-member
+ np.array(self.landmarks).reshape((-1, 2))
+ )
+ cv2.fillConvexPoly(
+ mask, hull, 255.0, lineType=cv2.LINE_AA
+ ) # pylint: disable=no-member
+ return mask
+
+
+def random_get_hull(landmark, img1, hull_type=None):
+ if hull_type is None:
+ hull_type = random.choice([0, 1, 2, 3])
+
+ if hull_type == 0:
+ mask = dfl_full(landmarks=landmark.astype("int32"), face=img1, channels=3).mask
+ return mask / 255, hull_type
+ elif hull_type == 1:
+ mask = extended(landmarks=landmark.astype("int32"), face=img1, channels=3).mask
+ return mask / 255, hull_type
+ elif hull_type == 2:
+ mask = components(
+ landmarks=landmark.astype("int32"), face=img1, channels=3
+ ).mask
+ return mask / 255, hull_type
+ elif hull_type == 3:
+ mask = facehull(landmarks=landmark.astype("int32"), face=img1, channels=3).mask
+ return mask / 255, hull_type
+
+
+def dynamic_blend(source, target, mask, **kwargs):
+ mask_blured, size_h, size_w, kernel_1, kernel_2, sigma_rand = get_blend_mask(
+ mask, **kwargs
+ )
+
+ if kwargs.get("blend_ratio") is None:
+ blend_list = [0.25, 0.5, 0.75, 1, 1, 1]
+ blend_ratio = blend_list[np.random.randint(len(blend_list))]
+ else:
+ blend_ratio = kwargs.get("blend_ratio")
+
+ mask_blured_ = mask_blured * blend_ratio
+
+ img_blended = mask_blured_ * source + (1 - mask_blured_) * target
+
+ blend_params = {
+ "blend_ratio": blend_ratio,
+ "size_h": size_h,
+ "size_w": size_w,
+ "kernel_1": kernel_1,
+ "kernel_2": kernel_2,
+ "sigma_rand": sigma_rand,
+ }
+ return img_blended, mask_blured, blend_params
+
+
+def get_blend_mask(mask, **kwargs):
+ H, W = mask.shape
+
+ if kwargs.get("size_h") is None and kwargs.get("size_w") is None:
+ size_h = np.random.randint(H * 0.8, H / 0.8)
+ size_w = np.random.randint(W * 0.8, W / 0.8)
+ else:
+ size_h = kwargs.get("size_h")
+ size_w = kwargs.get("size_w")
+
+ mask = cv2.resize(mask, (size_w, size_h))
+
+ if kwargs.get("kernel_1") is None and kwargs.get("kernel_2") is None:
+ kernel_1 = random.randrange(5, 26, 2)
+ kernel_2 = random.randrange(5, 26, 2)
+ kernel_1 = (kernel_1, kernel_1)
+ kernel_2 = (kernel_2, kernel_2)
+ else:
+ kernel_1 = kwargs.get("kernel_1")
+ kernel_2 = kwargs.get("kernel_2")
+
+ mask_blured = cv2.GaussianBlur(mask, kernel_1, 0)
+ mask_blured = mask_blured / (mask_blured.max())
+ mask_blured[mask_blured < 1] = 0
+
+ if kwargs.get("sigma_rand") is None:
+ sigma_rand = np.random.randint(5, 46)
+ else:
+ sigma_rand = kwargs.get("sigma_rand")
+ mask_blured = cv2.GaussianBlur(mask_blured, kernel_2, sigma_rand)
+ mask_blured = mask_blured / (mask_blured.max())
+
+ mask_blured = cv2.resize(mask_blured, (W, H))
+
+ return (
+ mask_blured.reshape((mask_blured.shape + (1,))),
+ size_h,
+ size_w,
+ kernel_1,
+ kernel_2,
+ sigma_rand,
+ )
diff --git a/clean/video/fakestormer/package_utils/geo_landmarks_extraction.py b/clean/video/fakestormer/package_utils/geo_landmarks_extraction.py
new file mode 100644
index 0000000000000000000000000000000000000000..50ea211ad696c36fb969c0c36f3bf6022c5dd556
--- /dev/null
+++ b/clean/video/fakestormer/package_utils/geo_landmarks_extraction.py
@@ -0,0 +1,348 @@
+# -*- coding: utf-8 -*-
+import argparse
+import math
+import os
+import sys
+import time
+
+if not os.getcwd() in sys.path:
+ sys.path.append(os.getcwd())
+import random
+from glob import glob
+
+import cv2
+import dlib
+import numpy as np
+import simplejson as json
+from box import Box as edict
+from configs.get_config import load_config
+from imutils import face_utils
+from tqdm import tqdm
+from transform import affine_transform
+
+from utils import draw_landmarks
+
+
+class LandmarkUtility(object):
+ def __init__(self, cfg, load_imgs=False, **kwargs):
+ super().__init__()
+
+ assert "DATASET" in cfg, "Dataset can not be None!"
+ assert "ROOT" in cfg, "Image Directory need to be provided!"
+
+ if not isinstance(cfg, edict):
+ cfg = edict(cfg)
+
+ self.load_imgs = load_imgs
+ self.image_root = cfg.ROOT
+ self.image_suffix = cfg.IMAGE_SUFFIX or "jpg"
+ self.dataset = cfg.DATASET
+ self.split = cfg.SPLIT or "train"
+ self.data_type = cfg.DATA_TYPE or "images"
+ self.fol_label = cfg.LABEL or ["real"]
+ self.debug = cfg.DEBUG
+ self.fake_types = cfg.FAKETYPE
+ self.compression = cfg.COMPRESSION
+
+ if kwargs is not None:
+ for k, v in kwargs.items():
+ if v is None:
+ raise ValueError(f"{k}:{v} recieve a None value!")
+ self.__setattr__(k, v)
+
+ def __contain__(self, key):
+ return hasattr(self, key)
+
+ def _load_data(self):
+ img_paths = []
+ file_names = []
+
+ print(f"Loading data from dataset --- {self.dataset}")
+ if self.load_imgs:
+ img_paths, file_names = self._load_data_from_path()
+ else:
+ assert self.__contain__(
+ "file_path"
+ ), "Loading data from file need a file path"
+ img_paths, file_names = self._load_data_from_file(
+ self.__getattribute__("file_path")
+ )
+
+ assert (
+ len(img_paths) != 0
+ ), "Image paths have not been loaded! Please check image directory!"
+ assert (
+ len(file_names) != 0
+ ), "Image files have not been loaded! Please check image suffixes!"
+ return img_paths, file_names
+
+ def _load_data_from_path(self):
+ """
+ Currenly, Using Glob for loading file with regex
+ It might be changed for better performance in large datasets
+ """
+ assert os.path.exists(self.image_root), "Root path to dataset can not be None!"
+ data_type = self.data_type
+ fake_types = self.fake_types
+ img_paths = []
+
+ # Load image data for each type of fake techniques
+ for idx, ft in enumerate(fake_types):
+ data_dir = os.path.join(self.image_root, self.split, data_type, ft)
+ if not os.path.exists(data_dir):
+ raise ValueError("Data Directory can not be invalid!")
+
+ for sub_dir in os.listdir(data_dir):
+ sub_dir_path = os.path.join(data_dir, sub_dir)
+ img_paths_ = glob(f"{sub_dir_path}/*.{self.image_suffix}")
+
+ img_paths.extend(img_paths_)
+
+ print(
+ "{} image paths have been loaded from {}!".format(
+ len(img_paths), self.dataset
+ )
+ )
+ file_names = [ip.split("/")[-1] for ip in img_paths]
+
+ return img_paths, file_names
+
+ def _load_data_from_file(self, file_path):
+ """
+ Each extension will be treated with particular extension loader
+ """
+ filename, file_extension = os.path.splitext(file_path)
+ img_paths, file_names = [], []
+ if file_extension == ".json":
+ f = open(file_path)
+ data = json.load(f)
+ obj_data = data["data"]
+
+ for item in obj_data:
+ img_paths.append(item["image_path"])
+ file_names.append(item["file_name"])
+ return img_paths, file_names
+
+ def _img_obj(self, img_path, file_name, **kwargs):
+ img_path = img_path.replace(self.image_root, "")
+ obj = dict(image_path=img_path, file_name=file_name, **kwargs)
+ return obj
+
+ def _load_image(self, img_path):
+ image = cv2.imread(os.path.join(self.image_root, img_path))
+ return image
+
+ def _facial_landmark(self, image, detector, lm_predictor):
+ try:
+ gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
+ except:
+ gray = image
+
+ f_rect = detector(gray, 1)
+ if len(f_rect) > 0:
+ f_lms = lm_predictor(gray, f_rect[0])
+ f_lms = face_utils.shape_to_np(f_lms)
+ return f_lms
+ else:
+ return None
+
+ def _align_face(self, image, f_lms):
+ assert f_lms is not None, "Facial Landmarks can not be None!"
+ eyepoints = f_lms[39], f_lms[42]
+ le_x, le_y = eyepoints[0]
+ re_x, re_y = eyepoints[1]
+
+ angle = math.atan((le_y - re_y) / (le_x - re_x)) * (180 / math.pi)
+ origin_point = tuple(np.array(image.shape[1::-1]) / 2)
+
+ rot_mat = cv2.getRotationMatrix2D(origin_point, angle, 1.0)
+ rot_img = cv2.warpAffine(
+ image, rot_mat, image.shape[1::-1], flags=cv2.INTER_LINEAR
+ )
+
+ # Aligning face landmarks by the rotation matrix
+ rot_f_lms = None
+ if f_lms is not None:
+ rot_f_lms = np.empty_like(f_lms)
+ for i, p in enumerate(f_lms):
+ rot_f_lms[i] = affine_transform(p, rot_mat)
+
+ return rot_img, f_lms, rot_f_lms
+
+ def facial_landmarks(self, img_paths, detector, lm_predictor):
+ rot_imgs, f_lmses, rot_f_lmses = [], [], []
+
+ for i, ip in enumerate(tqdm(img_paths, dynamic_ncols=True)):
+ image = self._load_image(ip)
+
+ # Checking time processing for each item
+ s_t = time.time()
+ f_lms = None
+ try:
+ f_lms = self._facial_landmark(image, detector, lm_predictor)
+ if f_lms is None:
+ if self.debug:
+ cv2.imwrite(f"samples/exception_img_{i}.jpg", image)
+ print(f"Image {i}--{ip} did not find any landmarks!")
+ except Exception as e:
+ print(e)
+
+ if i == 1:
+ print(
+ "Landmark detection processing time ---- {}".format(
+ time.time() - s_t
+ )
+ )
+
+ if f_lms is not None:
+ rot_img, _f_lms, rot_f_lms = self._align_face(image, f_lms)
+ else:
+ rot_img, _f_lms, rot_f_lms = image, [], []
+ rot_imgs.append(rot_img)
+ f_lmses.append(_f_lms)
+ rot_f_lmses.append(rot_f_lms)
+
+ # Visualizing landmarks to test
+ if i < 10 and self.debug:
+ rot_img = draw_landmarks(rot_img, rot_f_lms)
+ cv2.imwrite(f"samples/test_{i}.jpg", rot_img)
+
+ if i % 100 == 0:
+ print(f"Landmarks have been detected for {i} images")
+ return rot_imgs, f_lmses, rot_f_lmses
+
+ def build_data(self, img_paths, file_names, **kwargs):
+ data = dict(data=[])
+
+ if "orig_lmses" in kwargs.keys():
+ if not bool(kwargs["orig_lmses"]):
+ raise ValueError("Original Landmarks cannot be None!")
+ else:
+ orig_lmses = kwargs["orig_lmses"]
+ assert len(orig_lmses) == len(
+ img_paths
+ ), "The length of images and landmarks is not compatible!"
+
+ if "aligned_lmses" in kwargs.keys():
+ if not bool(kwargs["aligned_lmses"]):
+ raise ValueError("Aligned Landmarks cannot be None!")
+ else:
+ aligned_lmses = kwargs["aligned_lmses"]
+ assert len(aligned_lmses) == len(
+ img_paths
+ ), "The length of images and aligned landmarks is not compatible!"
+
+ for i, (p, f) in enumerate(zip(img_paths, file_names)):
+ fake_type = (
+ p.split("/")[-2]
+ if self.fake_types != ["original"]
+ else self.fake_types[0]
+ )
+ img_obj = self._img_obj(p, f, id=i, fake_type=fake_type)
+
+ if "orig_lmses" in kwargs.keys():
+ img_obj["orig_lms"] = (
+ orig_lmses[i].tolist()
+ if isinstance(orig_lmses[i], np.ndarray)
+ else orig_lmses[i]
+ ) # To save to JSON
+ if "aligned_lmses" in kwargs.keys():
+ img_obj["aligned_lms"] = (
+ aligned_lmses[i].tolist()
+ if isinstance(aligned_lmses[i], np.ndarray)
+ else aligned_lmses[i]
+ ) # To save to JSON
+ data["data"].append(img_obj)
+ return data
+
+ def save2json(self, data, fn="faceforensics_processed.json"):
+ assert len(data), "Data can not be empty!"
+ target = "processed_data/{}".format(self.compression)
+ if not os.path.exists(target):
+ os.mkdir(target)
+ fp = os.path.join(target, fn)
+ with open(fp, "w") as f:
+ json.dump(data, f)
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description="Landmarks preprocessing!")
+ parser.add_argument("--config", help="Config file to proceed preprocessing")
+ parser.add_argument("--file_path", help="File to load processed data")
+ parser.add_argument(
+ "--extract_landmark", help="Use Dlib to extract landmarks", action="store_true"
+ )
+ parser.add_argument(
+ "--save_aligned", help="Save aligned images", action="store_true"
+ )
+ args = parser.parse_args()
+ print(args)
+
+ cfg = load_config(args.config)
+ extract_landmark = args.extract_landmark
+ save_aligned = args.save_aligned
+
+ kwargs = {}
+ if extract_landmark:
+ kwargs["extract_landmark"] = extract_landmark
+
+ # Initialize Landmark Utility instance
+ if args.file_path:
+ lm_ins = LandmarkUtility(
+ cfg.PREPROCESSING, load_imgs=False, file_path=args.file_path, **kwargs
+ )
+ else:
+ lm_ins = LandmarkUtility(cfg.PREPROCESSING, load_imgs=True, **kwargs)
+ img_paths, file_names = lm_ins._load_data()
+ print(f"{len(img_paths)} images have been loaded for processing!")
+
+ if extract_landmark:
+ assert (
+ cfg.PREPROCESSING.facial_lm_pretrained is not None
+ ), "Landmark pretrained can not be None!"
+ f_detector = dlib.get_frontal_face_detector()
+ f_lm_detector = dlib.shape_predictor(cfg.PREPROCESSING.facial_lm_pretrained)
+ rot_imgs, f_lmses, rot_f_lmses = lm_ins.facial_landmarks(
+ img_paths, f_detector, f_lm_detector
+ )
+
+ if save_aligned:
+ os.makedirs(
+ f"{lm_ins.image_root}{lm_ins.split}/{lm_ins.data_type}/aligned_{lm_ins.fake_types[0]}_{cfg.PREPROCESSING.N_LANDMARKS}",
+ exist_ok=True,
+ )
+ for i, img_p in enumerate(tqdm(img_paths, dynamic_ncols=True)):
+ rot_img = rot_imgs[i]
+ fn = file_names[i]
+ vid_id = img_p.split("/")[-2]
+ os.makedirs(
+ f"{lm_ins.image_root}{lm_ins.compression}/{lm_ins.split}/{lm_ins.data_type}/aligned_{lm_ins.fake_types[0]}_{cfg.PREPROCESSING.N_LANDMARKS}/{vid_id}",
+ exist_ok=True,
+ )
+
+ aligned_img_p = img_p.replace(
+ lm_ins.fake_types[0],
+ f"aligned_{lm_ins.fake_types[0]}_{cfg.PREPROCESSING.N_LANDMARKS}",
+ )
+ cv2.imwrite(os.path.join(lm_ins.image_root, aligned_img_p), rot_img)
+ img_paths[i] = aligned_img_p
+
+ print("All landmarks have been detected and stored in memory!")
+ print("Ready to save to file...")
+
+ if args.file_path is None:
+ if extract_landmark:
+ data = lm_ins.build_data(
+ img_paths, file_names, orig_lmses=f_lmses, aligned_lmses=rot_f_lmses
+ )
+ else:
+ data = lm_ins.build_data(img_paths, file_names)
+
+ try:
+ lm_ins.save2json(
+ data,
+ fn=f"{lm_ins.split}_{lm_ins.dataset}_{lm_ins.data_type}_{cfg.PREPROCESSING.N_LANDMARKS}.json",
+ )
+ except Exception as e:
+ print(e)
+ print("Processed Data has been saved successfully!")
diff --git a/clean/video/fakestormer/package_utils/image_augmentation.py b/clean/video/fakestormer/package_utils/image_augmentation.py
new file mode 100644
index 0000000000000000000000000000000000000000..1354db8602ce5a207d7417ca8f61eacb0229c4e1
--- /dev/null
+++ b/clean/video/fakestormer/package_utils/image_augmentation.py
@@ -0,0 +1,96 @@
+# -*- coding: utf-8 -*-
+import argparse
+import glob
+import os
+import random
+
+import numpy as np
+import torch
+from image_utils import (
+ block_wise,
+ color_contrast,
+ color_saturation,
+ gaussian_blur,
+ gaussian_noise_color,
+ jpeg_compression,
+ load_image,
+ video_compression,
+)
+from PIL import Image
+
+# DIST_LEVEL = 3
+
+
+def get_distortion_parameter(type, level):
+ param_dict = dict() # a dict of list
+ param_dict["CS"] = [0.4, 0.3, 0.2, 0.1, 0.0] # smaller, worse
+ param_dict["CC"] = [0.85, 0.725, 0.6, 0.475, 0.35] # smaller, worse
+ param_dict["BW"] = [16, 32, 48, 64, 80] # larger, worse
+ param_dict["GNC"] = [0.001, 0.002, 0.005, 0.01, 0.05] # larger, worse
+ param_dict["GB"] = [7, 9, 13, 17, 21] # larger, worse
+ param_dict["JPEG"] = [2, 3, 4, 5, 6] # larger, worse
+ param_dict["VC"] = [30, 32, 35, 38, 40] # larger, worse
+
+ # level starts from 1, list starts from 0
+ return param_dict[type][level - 1]
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+ parser.add_argument("-i", dest="path", type=str, default="")
+ parser.add_argument(
+ "-t",
+ dest="task",
+ choices=[
+ "noise",
+ "block",
+ "saturation",
+ "contrast",
+ "blur",
+ "pixel",
+ "compression",
+ ],
+ default="noise",
+ )
+ args = parser.parse_args()
+ # Setting device
+ device = torch.device("cuda")
+ dest = args.path + "_" + args.task + "_" + "random" + "/"
+
+ if not os.path.exists(dest):
+ os.makedirs(dest)
+
+ for dirpath, dirnames, filenames in os.walk(args.path):
+ possible_files = os.path.join(dirpath, "*.png")
+
+ for file in glob.glob(possible_files):
+ img = load_image(file)
+ dist_level = random.randint(1, 5)
+
+ if args.task == "noise":
+ params = get_distortion_parameter("GNC", dist_level)
+ img = gaussian_noise_color(img, params)
+ elif args.task == "block":
+ params = get_distortion_parameter("BW", dist_level)
+ img = block_wise(img, params)
+ elif args.task == "saturation":
+ params = get_distortion_parameter("CS", dist_level)
+ img = color_saturation(img, params)
+ elif args.task == "contrast":
+ params = get_distortion_parameter("CC", dist_level)
+ img = color_contrast(img, params)
+ elif args.task == "blur":
+ params = get_distortion_parameter("GB", dist_level)
+ img = gaussian_blur(img, params)
+ elif args.task == "pixel":
+ params = get_distortion_parameter("JPEG", dist_level)
+ img = jpeg_compression(img, params)
+ elif args.task == "compression":
+ params = get_distortion_parameter("VC", dist_level)
+ img = video_compression(img, params)
+ res = dest + file.split("/")[-2]
+
+ if not os.path.exists(res):
+ os.makedirs(res)
+ # print(dest+('/').join(file.split('/')[-2:]))
+ Image.fromarray(img).save(res + "/" + file.split("/")[-1])
diff --git a/clean/video/fakestormer/package_utils/image_utils.py b/clean/video/fakestormer/package_utils/image_utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..126d944f958e285e6c50cc84f98b2ef25a51c85e
--- /dev/null
+++ b/clean/video/fakestormer/package_utils/image_utils.py
@@ -0,0 +1,214 @@
+# -*- coding: utf-8 -*-
+import math
+import os
+import random
+
+import cv2
+import numpy as np
+from matplotlib import cm
+from PIL import Image
+
+
+def load_image(image_path):
+ """Loading image"""
+ img = Image.open(image_path)
+ # Fix bug RGBA
+ if img.mode != "RGB":
+ img = img.convert("RGB")
+ img = np.array(img)
+ return img
+
+
+def crop_by_margin(image, margin=[0, 0]):
+ """Cropping images by margins as a step of preprocessing"""
+ H, W = image.shape[:2]
+ margin_x, margin_y = margin
+ image = image[margin_y : H - margin_y, margin_x : W - margin_x, :]
+ return image
+
+
+def gaussian_radius(det_size, min_overlap=0.7):
+ """Calculating gaussian radius to compute std for Unnormalized Gaussian Mask"""
+ height, width = det_size
+
+ a1 = 1
+ b1 = height + width
+ c1 = width * height * (1 - min_overlap) / (1 + min_overlap)
+ sq1 = np.sqrt(b1**2 - 4 * a1 * c1)
+ r1 = (b1 + sq1) / 2
+
+ a2 = 4
+ b2 = 2 * (height + width)
+ c2 = (1 - min_overlap) * width * height
+ sq2 = np.sqrt(b2**2 - 4 * a2 * c2)
+ r2 = (b2 + sq2) / 2
+
+ a3 = 4 * min_overlap
+ b3 = -2 * min_overlap * (height + width)
+ c3 = (min_overlap - 1) * width * height
+ sq3 = np.sqrt(b3**2 - 4 * a3 * c3)
+ r3 = (b3 + sq3) / 2
+ return min(r1, r2, r3)
+
+
+def cal_mask_wh(p, mask):
+ """Adaptively calculating blending mask W, H at the most vulnerable points perspective"""
+ cy, cx = p
+ mask_h, mask_w = mask.shape
+ w = 0
+ h = 0
+
+ for i in [-1, 1]:
+ shift_y = 0
+ while (
+ (cy + shift_y > -mask_h)
+ and (cy + shift_y < mask_h)
+ and (mask[cy + shift_y, cx] > 128)
+ ):
+ w += 1
+ shift_y += i
+
+ shift_x = 0
+ while (
+ (cx + shift_x > -mask_w)
+ and (cx + shift_x < mask_w)
+ and (mask[cy, cx + shift_x] > 128)
+ ):
+ h += 1
+ shift_x += i
+
+ return w, h
+
+
+def overlay_mask(
+ img: Image.Image, mask: Image.Image, colormap: str = "jet", alpha: float = 0.7
+) -> Image.Image:
+ """Overlay a colormapped mask on a background image
+
+ >>> from PIL import Image
+ >>> import matplotlib.pyplot as plt
+ >>> from torchcam.utils import overlay_mask
+ >>> img = ...
+ >>> cam = ...
+ >>> overlay = overlay_mask(img, cam)
+
+ Args:
+ img: background image
+ mask: mask to be overlayed in grayscale
+ colormap: colormap to be applied on the mask
+ alpha: transparency of the background image
+
+ Returns:
+ overlayed image
+
+ Raises:
+ TypeError: when the arguments have invalid types
+ ValueError: when the alpha argument has an incorrect value
+ """
+
+ if not isinstance(img, Image.Image) or not isinstance(mask, Image.Image):
+ raise TypeError("img and mask arguments need to be PIL.Image")
+
+ if not isinstance(alpha, float) or alpha < 0 or alpha >= 1:
+ raise ValueError(
+ "alpha argument is expected to be of type float between 0 and 1"
+ )
+
+ cmap = cm.get_cmap(colormap)
+ # Resize mask and apply colormap
+ overlay = mask.resize(img.size, resample=Image.BICUBIC)
+ overlay = (255 * cmap(np.asarray(overlay) ** 1)[:, :, :3]).astype(np.uint8)
+ # Overlay the image with the mask
+ overlayed_img = Image.fromarray(
+ (alpha * np.asarray(img) + (1 - alpha) * overlay).astype(np.uint8)
+ )
+
+ return overlayed_img
+
+
+def bgr2ycbcr(img_bgr):
+ img_bgr = img_bgr.astype(np.float32)
+ img_ycrcb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2YCR_CB)
+ img_ycbcr = img_ycrcb[:, :, (0, 2, 1)].astype(np.float32)
+ # to [16/255, 235/255]
+ img_ycbcr[:, :, 0] = (img_ycbcr[:, :, 0] * (235 - 16) + 16) / 255.0
+ # to [16/255, 240/255]
+ img_ycbcr[:, :, 1:] = (img_ycbcr[:, :, 1:] * (240 - 16) + 16) / 255.0
+
+ return img_ycbcr
+
+
+def ycbcr2bgr(img_ycbcr):
+ img_ycbcr = img_ycbcr.astype(np.float32)
+ # to [0, 1]
+ img_ycbcr[:, :, 0] = (img_ycbcr[:, :, 0] * 255.0 - 16) / (235 - 16)
+ # to [0, 1]
+ img_ycbcr[:, :, 1:] = (img_ycbcr[:, :, 1:] * 255.0 - 16) / (240 - 16)
+ img_ycrcb = img_ycbcr[:, :, (0, 2, 1)].astype(np.float32)
+ img_bgr = cv2.cvtColor(img_ycrcb, cv2.COLOR_YCR_CB2BGR)
+
+ return img_bgr
+
+
+def gaussian_noise_color(img, param=None):
+ if param is None:
+ param = [0.001, 0.002, 0.005, 0.01, 0.05]
+ ycbcr = bgr2ycbcr(img) / 255
+ size_a = ycbcr.shape
+ b = (
+ ycbcr + math.sqrt(param) * np.random.randn(size_a[0], size_a[1], size_a[2])
+ ) * 255
+ b = ycbcr2bgr(b)
+ img = np.clip(b, 0, 255).astype(np.uint8)
+ return img
+
+
+def block_wise(img, param):
+ width = 8
+ block = np.ones((width, width, 3)).astype(int) * 128
+ param = min(img.shape[0], img.shape[1]) // 256 * param
+ for i in range(param):
+ r_w = random.randint(0, img.shape[1] - 1 - width)
+ r_h = random.randint(0, img.shape[0] - 1 - width)
+ img[r_h : r_h + width, r_w : r_w + width, :] = block
+
+ return img
+
+
+def color_saturation(img, param):
+ ycbcr = bgr2ycbcr(img)
+ ycbcr[:, :, 1] = 0.5 + (ycbcr[:, :, 1] - 0.5) * param
+ ycbcr[:, :, 2] = 0.5 + (ycbcr[:, :, 2] - 0.5) * param
+ img = ycbcr2bgr(ycbcr).astype(np.uint8)
+
+ return img
+
+
+def color_contrast(img, param):
+ img = img.astype(np.float32) * param
+ img = img.astype(np.uint8)
+
+ return img
+
+
+def gaussian_blur(img, param):
+ img = cv2.GaussianBlur(img, (param, param), param * 1.0 / 6)
+
+ return img
+
+
+def jpeg_compression(img, param):
+ h, w, _ = img.shape
+ s_h = h // param
+ s_w = w // param
+ img = cv2.resize(img, (s_w, s_h))
+ img = cv2.resize(img, (w, h))
+
+ return img
+
+
+def video_compression(vid_in, vid_out, param):
+ cmd = f"ffmpeg -i {vid_in} -crf {param} -y {vid_out}"
+ os.system(cmd)
+
+ return
diff --git a/clean/video/fakestormer/package_utils/images_crop.py b/clean/video/fakestormer/package_utils/images_crop.py
new file mode 100644
index 0000000000000000000000000000000000000000..e01e095d2d93e71972fee0231e8b9a447020e918
--- /dev/null
+++ b/clean/video/fakestormer/package_utils/images_crop.py
@@ -0,0 +1,444 @@
+# -*- coding: utf-8 -*-
+import argparse
+import csv
+import json
+import os
+import shutil
+from glob import glob
+
+import cv2
+import numpy as np
+import pandas as pd
+import torch
+from imutils import face_utils
+from retinaface.pre_trained_models import get_model
+from retinaface.utils import vis_annotations
+from sklearn.utils import shuffle
+from tqdm import tqdm
+
+ROOT = "/data/deepfake_cluster/datasets_df"
+SAVE_DIR = f"{ROOT}/FGN"
+IMAGE_H, IMAGE_W, IMAGE_C = 256, 256, 3
+PADDING = 0.25
+DATA_TYPE = "frames" # frames or videos
+
+
+def facecrop(
+ model,
+ org_path,
+ save_path,
+ period=1,
+ num_frames=10,
+ dataset="original",
+ label=None,
+ mask_path=None,
+ padding=PADDING,
+):
+ print(f"Processing video --- {org_path}")
+ cap_org = cv2.VideoCapture(org_path)
+ if mask_path is not None:
+ mask_cap = cv2.VideoCapture(mask_path)
+ croppedfaces = []
+ frame_count_org = int(cap_org.get(cv2.CAP_PROP_FRAME_COUNT))
+ print("N frame count --- ", frame_count_org)
+
+ if label is not None:
+ # Custom org_path for ForgeryNet
+ if dataset == "ForgeryNet":
+ org_path_ = org_path.split("/")
+ org_path = "/".join(org_path_[:7] + ["_".join(org_path_[8:])])
+ save_path_ = (
+ save_path
+ + f"/{DATA_TYPE}/{str(label)}/"
+ + os.path.basename(org_path).replace(".mp4", "/")
+ )
+ else:
+ save_path_ = (
+ save_path
+ + f"/{DATA_TYPE}/{dataset}/"
+ + os.path.basename(org_path).replace(".mp4", "/")
+ )
+ os.makedirs(save_path_, exist_ok=True)
+
+ if mask_path is not None:
+ save_mask_path_ = (
+ save_path
+ + f"/masks/{dataset}/"
+ + os.path.basename(mask_path).replace(".mp4", "/")
+ )
+ os.makedirs(save_mask_path_, exist_ok=True)
+
+ if DATA_TYPE == "frames":
+ frame_idxs = np.linspace(
+ 0, frame_count_org - 1, num_frames, endpoint=True, dtype=np.int64
+ )
+ else:
+ frame_idxs = range(0, num_frames)
+
+ for cnt_frame in range(frame_count_org):
+ image_path = save_path_ + str(cnt_frame).zfill(3) + ".png"
+ if os.path.isfile(image_path):
+ continue
+ if mask_path is not None:
+ mask_f_path = save_mask_path_ + str(cnt_frame).zfill(3) + ".png"
+ if os.path.isfile(mask_f_path):
+ continue
+
+ try:
+ ret_org, frame_org = cap_org.read()
+ if mask_path is not None:
+ ret_m_org, mask_org = mask_cap.read()
+ height, width = frame_org.shape[:-1]
+ if not ret_org:
+ tqdm.write(
+ "Frame read {} Error! : {}".format(
+ cnt_frame, os.path.basename(org_path)
+ )
+ )
+ continue
+
+ if cnt_frame not in frame_idxs:
+ continue
+
+ frame = cv2.cvtColor(frame_org, cv2.COLOR_BGR2RGB)
+ faces = model.predict_jsons(frame)
+ try:
+ if len(faces) == 0:
+ print(faces)
+ tqdm.write(
+ "No faces in {}:{}".format(
+ cnt_frame, os.path.basename(org_path)
+ )
+ )
+ continue
+
+ face_s_max = -1
+ landmarks = []
+ face_crop = None
+ score_max = -1
+ for face_idx in range(len(faces)):
+ x0, y0, x1, y1 = faces[face_idx]["bbox"]
+ # landmark = np.array([[x0,y0],[x1,y1]] + faces[face_idx]['landmarks'])
+ face_w = x1 - x0
+ face_h = y1 - y0
+ face_s = face_w * face_h
+ score = faces[face_idx]["score"]
+
+ if face_s > face_s_max and score > score_max:
+ f_c_x0 = max(0, x0 - int(face_w * padding))
+ f_c_x1 = min(width, x1 + int(face_w * padding))
+ f_c_y0 = max(0, y0 - int(face_h * padding))
+ f_c_y1 = min(height, y1 + int(face_h * padding))
+
+ face_crop = frame_org[f_c_y0:f_c_y1, f_c_x0:f_c_x1, :]
+ if mask_path is not None:
+ mask_crop = mask_org[f_c_y0:f_c_y1, f_c_x0:f_c_x1, :]
+ face_s_max = face_s
+ score_max = score
+ # size_list.append(face_s)
+ # # landmarks.append(landmark)
+ except Exception as e:
+ print(f"error in {cnt_frame}:{org_path}")
+ print(e)
+ continue
+ except Exception as e1:
+ print(e1)
+ continue
+
+ # landmarks=np.concatenate(landmarks).reshape((len(size_list),) + landmark.shape)
+ # landmarks=landmarks[np.argsort(np.array(size_list))[::-1]]
+
+ # land_path=save_path_+str(cnt_frame).zfill(3)
+ # land_path=land_path.replace('/frames','/retina')
+ # os.makedirs(os.path.dirname(land_path),exist_ok=True)
+ # np.save(land_path, landmarks)
+ # if not os.path.isfile(image_path):
+ face_crop = cv2.resize(
+ face_crop, (IMAGE_H, IMAGE_W), interpolation=cv2.INTER_LINEAR
+ )
+ cv2.imwrite(image_path, face_crop)
+
+ if mask_path is not None:
+ mask_crop = cv2.resize(
+ mask_crop, (IMAGE_H, IMAGE_W), interpolation=cv2.INTER_LINEAR
+ )
+ cv2.imwrite(mask_f_path, mask_crop)
+
+ cap_org.release()
+ return
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "-d",
+ dest="dataset",
+ choices=[
+ "FaceShifter",
+ "Face2Face",
+ "Deepfakes",
+ "FaceSwap",
+ "NeuralTextures",
+ "Original",
+ "Celeb-real",
+ "Celeb-synthesis",
+ "YouTube-real",
+ "DFDC",
+ "DFDCP",
+ "method_A",
+ "method_B",
+ "original_videos",
+ "DFo_source_videos",
+ "DFo_manipulated_videos",
+ "ForgeryNet",
+ ],
+ )
+ parser.add_argument("-c", dest="comp", choices=["raw", "c23", "c40"], default="raw")
+ parser.add_argument("-n", dest="num_frames", type=int, default=32)
+ parser.add_argument(
+ "-t", dest="task", choices=["train", "val", "test"], default="train"
+ )
+ parser.add_argument("--save_mask", "-sm", action="store_true")
+ parser.add_argument(
+ "--alloc_mem", "-a", help="Pre allocating GPU memory", action="store_true"
+ )
+ args = parser.parse_args()
+
+ # Allocate memory
+ if args.alloc_mem:
+ mem_all_tensors = torch.rand(60, 10000, 10000)
+ mem_all_tensors.to("cuda:0")
+
+ # Setting device
+ device = torch.device("cuda")
+
+ # Setting the dataset path based on the dataset name
+ if args.dataset == "Original":
+ dataset_path = (
+ "{}/FaceForensics++/original_download/original_sequences/youtube/".format(
+ ROOT
+ )
+ )
+ elif args.dataset == "DeepFakeDetection_original":
+ dataset_path = "/data/FaceForensics++/original_sequences/actors/{}/".format(
+ args.comp
+ )
+ elif args.dataset in [
+ "DeepFakeDetection",
+ "FaceShifter",
+ "Face2Face",
+ "Deepfakes",
+ "FaceSwap",
+ "NeuralTextures",
+ ]:
+ dataset_path = (
+ "{}/FaceForensics++/original_download/manipulated_sequences/{}/".format(
+ ROOT, args.dataset
+ )
+ )
+ elif args.dataset in ["Celeb-real", "Celeb-synthesis", "YouTube-real"]:
+ if "v1" in SAVE_DIR:
+ dataset_path = "{}/Celeb-DFv1/".format(ROOT)
+ else:
+ dataset_path = "{}/Celeb-DFv2/Celeb-DF-v2/".format(ROOT)
+ elif args.dataset in ["method_A", "method_B", "original_videos"]:
+ dataset_path = "{}/DFDCP/".format(ROOT)
+ elif args.dataset in ["DFDC"]:
+ dataset_path = "{}/DFDC/".format(ROOT)
+ elif args.dataset in ["DFo_source_videos", "DFo_manipulated_videos"]:
+ dataset_path = "{}/DeeperForensics/".format(ROOT)
+ elif args.dataset in ["ForgeryNet"]:
+ dataset_path = "{}/FGN/".format(ROOT)
+ else:
+ raise NotImplementedError
+
+ # Loading model
+ model = get_model("resnet50_2020-07-20", max_size=2048, device=device)
+ model.eval()
+
+ labels = []
+ if args.dataset in [
+ "Original",
+ "DeepFakeDetection",
+ "FaceShifter",
+ "Face2Face",
+ "Deepfakes",
+ "FaceSwap",
+ "NeuralTextures",
+ ]:
+ movies_path = os.path.join(dataset_path, args.comp, "videos/")
+ mask_mov_paths = os.path.join(dataset_path, "masks", "videos/")
+
+ # Annotation file for FF++
+ with open(f"{ROOT}/FaceForensics++/original_download/{args.task}.json") as f:
+ vid_ids = json.load(f)
+ elif args.dataset in ["Celeb-real", "Celeb-synthesis", "YouTube-real"]:
+ if "v1" in SAVE_DIR:
+ movies_path = dataset_path
+ else:
+ movies_path = os.path.join(dataset_path, args.dataset, "videos")
+
+ # Annotation file for Celeb-DF
+ with open(f"{dataset_path}List_of_{args.task}ing_videos.txt") as f:
+ vid_ids = pd.read_csv(f).values.reshape(-1)
+ elif args.dataset in ["DFDC"]:
+ movies_path = os.path.join(dataset_path, args.task, "download_videos")
+
+ # Annotation file for DFDC
+ with open(os.path.join(dataset_path, args.task, "labels.csv")) as f:
+ df = pd.read_csv(f)
+ # df['path'] = df['label'].astype(str) + '/' + df['filename']
+ vid_ids = df["filename"].values.reshape(-1)
+ labels = df["label"].values.reshape(-1)
+ elif args.dataset in ["DFo_source_videos", "DFo_manipulated_videos"]:
+ movies_path = dataset_path
+
+ with open(f"{dataset_path}lists/splits/{args.task}.txt") as f:
+ vid_ids = pd.read_csv(f).values.reshape(-1)
+
+ if args.dataset == "DFo_source_videos":
+ vid_ids = list(
+ set([vid_id.split("_")[1].split(".")[0] for vid_id in vid_ids])
+ )
+ elif args.dataset in ["ForgeryNet"]:
+ movies_path = os.path.join(dataset_path, args.task, "video")
+
+ # Annotation file for FGN
+ vid_ids = []
+ with open(
+ os.path.join(dataset_path, args.task, "video_list.txt"), encoding="utf-8"
+ ) as f:
+ df = csv.reader(f, delimiter="\n")
+
+ for idx, row in enumerate(df):
+ row_data = row[0].split(" ")
+ if int(row_data[-1]) in [0, 7]:
+ vid_ids.append(row_data[1])
+ label = (
+ f"fake_{args.task}"
+ if int(row_data[-1]) == 7
+ else f"real_{args.task}"
+ )
+ labels.append(label)
+ else:
+ movies_path = dataset_path
+
+ # Annotation file for DFDCP
+ with open(f"{ROOT}/DFDCP/dataset.json") as f:
+ movie_data = json.load(f)
+ vid_ids = []
+ for mv_id, item_data in movie_data.items():
+ if item_data["set"] == args.task:
+ vid_ids.append(mv_id)
+
+ movies_path_list = []
+ mask_mov_path_list = []
+ file_list = []
+ file_path = None
+ vid_id_count = {}
+
+ # Loading the list of specific video's names for an invidual task 'train/val/test
+ for i in range(len(vid_ids)):
+ if args.dataset == "Original":
+ file_list += vid_ids[i]
+ elif args.dataset in [
+ "Face2Face",
+ "Deepfakes",
+ "FaceSwap",
+ "NeuralTextures",
+ "FaceShifter",
+ ]:
+ file_list.append("_".join([vid_ids[i][0], vid_ids[i][1]]))
+ file_list.append("_".join([vid_ids[i][1], vid_ids[i][0]]))
+ elif args.dataset in ["method_A", "method_B", "original_videos"]:
+ if args.dataset in vid_ids[i]:
+ file_list.append(vid_ids[i])
+ elif args.dataset in ["DFDC", "ForgeryNet"]:
+ file_list.append(vid_ids[i])
+ elif args.dataset in ["DFo_source_videos", "DFo_manipulated_videos"]:
+ sub_dataset = args.dataset.replace("DFo_", "")
+ file_list_path = os.path.join(dataset_path, "lists", f"{sub_dataset}_lists")
+
+ if i == 0:
+ if sub_dataset == "source_videos":
+ file_path = f"{file_list_path}/{sub_dataset}_list.txt"
+ else:
+ file_path = f"{file_list_path}/{sub_dataset}_end_to_end_list.txt"
+ with open(file_path) as f:
+ full_file_list = pd.read_csv(f).values.reshape(-1)
+ full_file_list = shuffle(full_file_list, random_state=259)
+
+ for item in full_file_list:
+ if vid_ids[i] in vid_id_count.keys() and vid_id_count[vid_ids[i]] > 10:
+ break
+ if vid_ids[i] in item:
+ file_list.append(item)
+
+ if vid_ids[i] in vid_id_count.keys():
+ vid_id_count[vid_ids[i]] += 1
+ else:
+ vid_id_count[vid_ids[i]] = 1
+ else:
+ if args.dataset in vid_ids[i]:
+ file_list.append(vid_ids[i].split(" ")[-1])
+
+ # movies_path_list = sorted(glob(movies_path+'*.mp4'))
+ if args.dataset in [
+ "Original",
+ "DeepFakeDetection",
+ "FaceShifter",
+ "Face2Face",
+ "Deepfakes",
+ "FaceSwap",
+ "NeuralTextures",
+ ]:
+ [movies_path_list.append(movies_path + i + ".mp4") for i in file_list]
+ if args.save_mask:
+ [mask_mov_path_list.append(mask_mov_paths + i + ".mp4") for i in file_list]
+ else:
+ if "v2" in SAVE_DIR:
+ [
+ movies_path_list.append(os.path.join(movies_path, i.split("/")[-1]))
+ for i in file_list
+ ]
+ else:
+ [movies_path_list.append(os.path.join(movies_path, i)) for i in file_list]
+
+ print("{} : videos are exist in {}".format(len(movies_path_list), args.dataset))
+ n_sample = len(movies_path_list)
+ print(f"number of video samples -- {n_sample}")
+
+ # Defining the path to store the images
+ save_path = os.path.join(SAVE_DIR, args.task)
+ os.makedirs(save_path, exist_ok=True)
+
+ for i in tqdm(range(0, n_sample)):
+ # folder_path=movies_path_list[i].replace('videos/','frames/').replace('.mp4','/')
+ # if len(glob(folder_path.replace('/frames/','/retina/')+'*.npy')) < args.num_frames:
+ if len(labels):
+ facecrop(
+ model,
+ movies_path_list[i],
+ save_path=save_path,
+ num_frames=args.num_frames,
+ dataset=args.dataset,
+ label=labels[i],
+ )
+ else:
+ if not args.save_mask:
+ facecrop(
+ model,
+ movies_path_list[i],
+ save_path=save_path,
+ num_frames=args.num_frames,
+ dataset=args.dataset,
+ )
+ else:
+ facecrop(
+ model,
+ movies_path_list[i],
+ save_path=save_path,
+ num_frames=args.num_frames,
+ dataset=args.dataset,
+ mask_path=mask_mov_path_list[i],
+ )
diff --git a/clean/video/fakestormer/package_utils/metrics_based_preds.py b/clean/video/fakestormer/package_utils/metrics_based_preds.py
new file mode 100644
index 0000000000000000000000000000000000000000..a821c48a0d7ad367027efb4680c1c206ead6662c
--- /dev/null
+++ b/clean/video/fakestormer/package_utils/metrics_based_preds.py
@@ -0,0 +1,149 @@
+# -*- coding: utf-8 -*-
+import os
+import sys
+
+if not os.getcwd() in sys.path:
+ sys.path.insert(0, os.getcwd())
+import argparse
+
+import numpy as np
+import torch
+from lib.metrics import (
+ apply_cdf_transform,
+ bin_calculate_auc_ap_ar,
+ get_acc_mesure_func,
+)
+from scipy.stats import wasserstein_distance
+
+from utils import load_file
+
+
+def sigmoid(z):
+ return 1 / (1 + np.exp(-z))
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(
+ description="Reporting metrics based on saved predictions!"
+ )
+ parser.add_argument("--saved_preds", "-f", help="Path to saved prediction file")
+ parser.add_argument(
+ "--model_base",
+ "-m",
+ help="The input model is image-level or video-level",
+ default="image",
+ )
+ parser.add_argument(
+ "--metric_level",
+ "-ml",
+ help="Report metrics at image-level or video level",
+ default="image",
+ )
+ parser.add_argument(
+ "--apr",
+ help="Report average metrics instead of simple ones",
+ action="store_true",
+ )
+ args = parser.parse_args()
+
+ file = args.saved_preds
+ model_base = args.model_base
+ metric_level = args.metric_level
+ apr = args.apr
+ # Load data
+ data = load_file(file_path=file)
+
+ if "data" in data.keys():
+ data = data["data"]
+
+ total_preds = []
+ total_labels = []
+ neg_preds = []
+ pos_preds = []
+ vid_preds = {}
+ vid_labels = {}
+
+ if model_base == "image":
+ for ip in data.keys():
+ vid_id = os.path.dirname(ip)
+ pred = data[ip][0]
+ label = data[ip][1]
+
+ # Just append to total preds
+ total_preds.append(pred)
+ total_labels.append(label)
+
+ if vid_id in vid_preds.keys():
+ vid_preds[vid_id].append(pred)
+ else:
+ vid_preds[vid_id] = [pred]
+ vid_labels[vid_id] = [label]
+
+ if metric_level == "video":
+ total_preds = [
+ np.mean(vid_preds[k], keepdims=True) for k in vid_preds.keys()
+ ]
+ total_labels = [vid_labels[k] for k in vid_labels.keys()]
+ else:
+ for ip in data.keys():
+ vid_id = ip.split("/")[-1]
+ pred = [v for idx, v in enumerate(data[ip]) if idx % 2 == 0]
+ pred = [np.array(pred).mean()]
+ label = [data[ip][1]]
+
+ # Just append to total preds
+ total_preds.append(pred)
+ total_labels.append(label)
+
+ total_preds = sigmoid(np.array(total_preds))
+ total_labels = np.array(total_labels)
+
+ # Assigning predictions to neg/pos groups
+ neg_preds = total_preds[total_labels < 1].squeeze()
+ pos_preds = total_preds[total_labels == 1].squeeze()
+
+ # Computing metric section
+ acc_measure = get_acc_mesure_func("binary")
+ acc_ = acc_measure(total_preds, targets=None, labels=total_labels)
+ metrics = bin_calculate_auc_ap_ar(total_preds, total_labels, apr=apr)
+ best_thr = metrics["best_thr"]
+ thr_var = metrics["thr_var"]
+
+ if apr:
+ auc_, ap_, ar_, mf1_ = (
+ metrics["auc"],
+ metrics["ap"],
+ metrics["ar"],
+ metrics["mf1"],
+ )
+ print(
+ f"Current ACC, AUC, AP, AR, mF1, THR --- {acc_*100} -- {auc_*100} -- {ap_*100} -- {ar_*100} -- {mf1_*100} -- {best_thr}"
+ )
+ else:
+ bacc_, auc_, p_, r_, s_, f1_, eer_ = (
+ metrics["bacc"],
+ metrics["auc"],
+ metrics["p"],
+ metrics["r"],
+ metrics["s"],
+ metrics["f1"],
+ metrics["eer"],
+ )
+ print(
+ f"Current ACC, BACC, AUC, P, R, S, F1, EER, THR, THR_VAR -- {acc_*100} -- {bacc_*100} -- {auc_*100} -- {p_*100} -- {r_*100} -- {s_*100} -- {f1_*100} -- {eer_*100} -- {best_thr:.3f} -- {thr_var:.6f}"
+ )
+
+ # Computing Wasserstein distance
+ for cdf_type in ["empirical", "kde", "para", "quantile"]:
+ cdf1, cdf2 = apply_cdf_transform(
+ neg_data=neg_preds, pos_data=pos_preds, cdf_type=cdf_type
+ )
+
+ # Customize the calculation of quantile
+ if cdf_type != "quantile":
+ wd = wasserstein_distance(cdf1, cdf2)
+ else:
+ q = np.linspace(0, 1, min(len(neg_preds), len(pos_preds)))
+ wd = np.trapz(np.abs(cdf1 - cdf2), q)
+
+ print(f"Wasserstein Distance --- {cdf_type} --- {wd:.6f}")
diff --git a/clean/video/fakestormer/package_utils/misc.py b/clean/video/fakestormer/package_utils/misc.py
new file mode 100644
index 0000000000000000000000000000000000000000..2cf8addd71b82a0d60864af10a73536e2c4cf377
--- /dev/null
+++ b/clean/video/fakestormer/package_utils/misc.py
@@ -0,0 +1,74 @@
+# -*- coding:utf-8 -*-
+import torch
+from torch._six import inf
+
+
+class NativeScalerWithGradNormCount:
+ state_dict_key = "amp_scaler"
+
+ def __init__(self):
+ self._scaler = torch.cuda.amp.GradScaler()
+
+ def __call__(
+ self,
+ cfg,
+ loss,
+ optimizer,
+ clip_grad=None,
+ parameters=None,
+ create_graph=False,
+ update_grad=True,
+ step=0,
+ ):
+ self._scaler.scale(loss).backward(create_graph=create_graph)
+
+ if update_grad:
+ if clip_grad is not None:
+ assert parameters is not None
+ self._scaler.unscale_(
+ optimizer
+ ) # unscale the gradients of optimizer's assigned params in-place
+ norm = torch.nn.utils.clip_grad_norm_(parameters, clip_grad)
+ else:
+ self._scaler.unscale_(optimizer)
+ norm = get_grad_norm_(parameters)
+
+ if cfg.TRAIN.optimizer != "SAM":
+ self._scaler.step(optimizer)
+ else:
+ if step == 0:
+ optimizer.first_step(zero_grad=True)
+ else:
+ self._scaler = optimizer.second_step(
+ zero_grad=False, scaler=self._scaler
+ )
+ self._scaler.update()
+ else:
+ norm = None
+ return norm
+
+ def state_dict(self):
+ return self._scaler.state_dict()
+
+ def load_state_dict(self, state_dict):
+ self._scaler.load_state_dict(state_dict)
+
+
+def get_grad_norm_(parameters, norm_type: float = 2.0) -> torch.Tensor:
+ if isinstance(parameters, torch.Tensor):
+ parameters = [parameters]
+ parameters = [p for p in parameters if p.grad is not None]
+ norm_type = float(norm_type)
+ if len(parameters) == 0:
+ return torch.tensor(0.0)
+ device = parameters[0].grad.device
+ if norm_type == inf:
+ total_norm = max(p.grad.detach().abs().max().to(device) for p in parameters)
+ else:
+ total_norm = torch.norm(
+ torch.stack(
+ [torch.norm(p.grad.detach(), norm_type).to(device) for p in parameters]
+ ),
+ norm_type,
+ )
+ return total_norm
diff --git a/clean/video/fakestormer/package_utils/tensors.py b/clean/video/fakestormer/package_utils/tensors.py
new file mode 100644
index 0000000000000000000000000000000000000000..046344eca868ba6ee2da75bb6ef885ad1e728a91
--- /dev/null
+++ b/clean/video/fakestormer/package_utils/tensors.py
@@ -0,0 +1,93 @@
+# -*- coding:utf-8 -*-
+import cv2
+import numpy as np
+import torch
+import torch.nn.functional as F
+from PIL import Image
+
+
+def masked_inputs(
+ inputs: torch.tensor,
+ hm_preds: torch.tensor,
+ cfg: dict,
+ patch_size: int = 16,
+ prev_pos_mask: torch.tensor = None,
+ debug=False,
+ shot=0,
+ vid_ids=None,
+):
+ """
+ Masked out inputs given positions extracted from Heatmap_preds for multi-shot predictions.
+ args:
+ inputs of shape (B, 3, T, H, W)
+ hm of shape (B, 1, T, Hp, Wp) where Hp, Wp = H//patch_size, W//patch_size
+ """
+ # Prepare positions to mask
+ batch_size = inputs.shape[0]
+ Hp, Wp = hm_preds.shape[-2:]
+ H, W = inputs.shape[-2:]
+
+ hm_preds = hm_preds.reshape(batch_size, hm_preds.shape[1], hm_preds.shape[2], -1)
+ max_vals = hm_preds.max(axis=-1, keepdim=True)[0]
+ # pos_ = hm_preds.eq(max_vals).float()[:,:,0,:].unsqueeze(2).repeat(1,1,hm_preds.shape[2],1).unsqueeze(-1) #Take the first pos matrix
+ # pos_ = pos_.repeat(1,1,1,1,patch_size*patch_size).reshape(batch_size, pos_.shape[1], pos_.shape[2], H, W)
+ pos_ = (
+ hm_preds.eq(max_vals)
+ .float()
+ .reshape(batch_size, hm_preds.shape[1], hm_preds.shape[2], Hp, Wp)
+ )
+ pos_ = pos_[:, :, 1, :, :].unsqueeze(2).repeat(1, 1, hm_preds.shape[2], 1, 1)
+ pos_ = F.interpolate(pos_, size=(hm_preds.shape[2], H, W), mode="nearest")
+
+ # Prepare values to fill up
+ hard_vals = torch.zeros((1, 1, 1, 1, 3), dtype=torch.float)
+ mean = torch.as_tensor(cfg.TRANSFORM.normalize.mean)
+ std = torch.as_tensor(cfg.TRANSFORM.normalize.std)
+ normalized_vals = hard_vals.sub_(mean).div_(std).to(dtype=torch.float).cuda()
+
+ inputs_ = inputs.permute(0, 2, 3, 4, 1)
+ pos = pos_.permute(0, 2, 3, 4, 1)
+
+ if prev_pos_mask is not None:
+ pos = torch.logical_or(pos, prev_pos_mask).int()
+
+ outs = torch.where(pos.repeat(1, 1, 1, 1, 3).bool(), normalized_vals, inputs_)
+ inputs = outs.permute(0, 4, 1, 2, 3)
+
+ if debug:
+ if vid_ids is not None:
+ vis_input_tensor(inputs[0], file_name=f"test_{vid_ids[0]}_{shot+1}.png")
+ else:
+ vis_input_tensor(inputs[0], file_name=f"test_{shot+1}.png")
+
+ return inputs, pos
+
+
+def vis_input_tensor(tensor, file_name, normalize=True):
+ """
+ Visualize input tensor for debugging
+ args:
+ tensor of shape (3, H, W) or (3, T, H, W)
+ """
+ assert tensor.ndim in [3, 4]
+ H, W = tensor.shape[-2:]
+
+ if normalize:
+ tensor = tensor.clone()
+ min = float(tensor.min())
+ max = float(tensor.max())
+ tensor.add_(-min).div_(max - min + 1e-5)
+
+ if tensor.ndim == 4:
+ depth = tensor.shape[1]
+ inputs = tensor.mul(255).clamp(0, 255).byte().permute(1, 2, 3, 0).cpu().numpy()
+ else:
+ inputs = tensor.mul(255).clamp(0, 255).byte().permute(1, 2, 0).cpu().numpy()
+ depth = 1
+
+ grid_image = np.zeros((H, depth * W, 3), dtype=np.uint8)
+ for i in range(depth):
+ image = inputs[i]
+ grid_image[0:H, i * W : (i + 1) * W, :] = image
+
+ Image.fromarray(grid_image).save(file_name)
diff --git a/clean/video/fakestormer/package_utils/transform.py b/clean/video/fakestormer/package_utils/transform.py
new file mode 100644
index 0000000000000000000000000000000000000000..76b44718c4bb5e1a648ff578e6448817be11c87d
--- /dev/null
+++ b/clean/video/fakestormer/package_utils/transform.py
@@ -0,0 +1,167 @@
+# -*- coding: utf-8 -*-
+from copy import deepcopy
+
+import albumentations as alb
+import cv2
+import numpy as np
+from torchvision import transforms
+
+
+def get_dir(src_point, rot_rad):
+ sn, cs = np.sin(rot_rad), np.cos(rot_rad)
+
+ src_result = [0, 0]
+ src_result[0] = src_point[0] * cs - src_point[1] * sn
+ src_result[1] = src_point[0] * sn + src_point[1] * cs
+
+ return src_result
+
+
+def get_3rd_point(a, b):
+ direct = a - b
+ return b + np.array([-direct[1], direct[0]], dtype=np.float32)
+
+
+def get_affine_transform(
+ center,
+ scale,
+ rot,
+ output_size,
+ shift=np.array([0, 0], dtype=np.float32),
+ inv=0,
+ pixel_std=200,
+):
+ if not isinstance(scale, np.ndarray) and not isinstance(scale, list):
+ print(scale)
+ scale = np.array([scale, scale])
+
+ scale_tmp = scale * pixel_std
+ src_w = scale_tmp[0]
+ dst_w = output_size[0]
+ dst_h = output_size[1]
+
+ rot_rad = np.pi * rot / 180
+
+ src_dir = get_dir([0, (src_w - 1) * -0.5], rot_rad)
+ dst_dir = np.array([0, (dst_w - 1) * -0.5], np.float32)
+ src = np.zeros((3, 2), dtype=np.float32)
+ dst = np.zeros((3, 2), dtype=np.float32)
+ src[0, :] = center + scale_tmp * shift
+ src[1, :] = center + src_dir + scale_tmp * shift
+ dst[0, :] = [(dst_w - 1) * 0.5, (dst_h - 1) * 0.5]
+ dst[1, :] = np.array([(dst_w - 1) * 0.5, (dst_h - 1) * 0.5]) + dst_dir
+
+ src[2:, :] = get_3rd_point(src[0, :], src[1, :])
+ dst[2:, :] = get_3rd_point(dst[0, :], dst[1, :])
+
+ if inv:
+ trans = cv2.getAffineTransform(np.float32(dst), np.float32(src))
+ else:
+ trans = cv2.getAffineTransform(np.float32(src), np.float32(dst))
+
+ return trans
+
+
+def affine_transform(pt, t):
+ """
+ This function apply the affine transform to each point given by an affine matrix
+ """
+ new_pt = np.array([pt[0], pt[1], 1.0]).T
+ new_pt = np.dot(t, new_pt)
+ return new_pt[:2]
+
+
+def get_center_scale(shape, aspect_ratio, pixel_std=200):
+ h, w = shape[0], shape[1]
+ center = np.zeros((2), dtype=np.float32)
+ center[0] = (shape[1] - 1) / 2
+ center[1] = (shape[0] - 1) / 2
+
+ if w > h * aspect_ratio:
+ h = w * 1.0 / aspect_ratio
+ else:
+ w = h * 1.0 / aspect_ratio
+ scale = np.array([w * 1.0 / pixel_std, h * 1.0 / pixel_std], dtype=np.float32)
+
+ return center, scale
+
+
+def final_transform(_cfg):
+ return transforms.Compose(
+ [
+ transforms.ToTensor(),
+ transforms.Normalize(
+ mean=_cfg.TRANSFORM.normalize.mean,
+ std=_cfg.TRANSFORM.normalize.std,
+ ),
+ ]
+ )
+
+
+def randaffine(img, mask, index=0, data_type="image", **kwargs):
+ assert data_type in ["image", "video"]
+ assert mask.ndim == 2
+
+ if data_type == "image":
+ f = alb.Affine(
+ translate_percent={"x": (-0.03, 0.03), "y": (-0.015, 0.015)},
+ scale=[0.95, 1 / 0.95],
+ fit_output=False,
+ p=1,
+ )
+
+ g = alb.ElasticTransform(alpha=50, sigma=7, alpha_affine=0, p=1)
+ else:
+ f = alb.ReplayCompose(
+ [
+ alb.Affine(
+ translate_percent={"x": (-0.03, 0.03), "y": (-0.015, 0.015)},
+ scale=[0.95, 1 / 0.95],
+ fit_output=False,
+ p=1,
+ )
+ ],
+ p=1,
+ )
+
+ g = alb.ReplayCompose(
+ [alb.ElasticTransform(alpha=50, sigma=7, alpha_affine=0, p=1)], p=1
+ )
+
+ if index == 0 or data_type == "image":
+ data_f = f(image=img, mask=mask)
+ img = data_f["image"]
+ mask = data_f["mask"]
+
+ data_g = g(image=img, mask=mask)
+ mask = data_g["mask"]
+
+ if data_type == "image":
+ return img, mask, None
+ else:
+ f_replay_params = data_f["replay"]
+ g_replay_params = data_g["replay"]
+ return (
+ img,
+ mask,
+ {
+ "f_replay_params": f_replay_params,
+ "g_replay_params": g_replay_params,
+ },
+ )
+ else:
+ f_replay_params = kwargs.get("f_replay_params")
+ g_replay_params = kwargs.get("g_replay_params")
+ assert f_replay_params is not None and g_replay_params is not None
+
+ data_f = alb.ReplayCompose.replay(f_replay_params, image=img, mask=mask)
+ img = data_f["image"]
+ mask = data_f["mask"]
+
+ data_g = alb.ReplayCompose.replay(g_replay_params, image=img, mask=mask)
+ mask = data_g["mask"]
+ return (
+ img,
+ mask,
+ {"f_replay_params": f_replay_params, "g_replay_params": g_replay_params},
+ )
diff --git a/clean/video/fakestormer/package_utils/utils.py b/clean/video/fakestormer/package_utils/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..637ac9452b89aa6074fd6ea46ae11e3940a50870
--- /dev/null
+++ b/clean/video/fakestormer/package_utils/utils.py
@@ -0,0 +1,267 @@
+# -*- coding: utf-8 -*-
+import logging
+import os
+from copy import deepcopy
+
+import cv2
+import numpy as np
+import plotly.graph_objects as go
+import simplejson as json
+import torch
+from losses.losses import _sigmoid
+
+
+def file_extention(file_path):
+ f_name, f_extension = os.path.splitext(file_path)
+ return f_name, f_extension
+
+
+def make_dir(dir_path):
+ if not os.path.exists(dir_path):
+ os.mkdir(dir_path)
+
+
+def vis_heatmap(images, heatmaps, file_name, **kwargs):
+ temp_locs = kwargs.get("temp_loc_preds")
+
+ # hm_h, hm_w = heatmaps.shape[1:]
+ hm_h, hm_w = np.array(images[0]).shape[:2]
+
+ masked_image = np.zeros((hm_h, hm_w * heatmaps.shape[0], 3), dtype=np.uint8)
+
+ for i in range(heatmaps.shape[0]):
+ heatmap = heatmaps[i]
+ heatmap = np.clip(heatmap * 255, 0, 255).astype(np.uint8)
+ heatmap = np.squeeze(heatmap)
+
+ # heatmap_h = heatmap.shape[0]
+ # heatmap_w = heatmap.shape[1]
+
+ if isinstance(images, list):
+ # resized_image = cv2.resize(np.array(images[i]), (int(heatmap_h), int(heatmap_w)))
+ heatmap = cv2.resize(
+ heatmap, np.array(images[i]).shape[:2], interpolation=cv2.INTER_LINEAR
+ )
+ colored_heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)
+ masked_image[:, hm_w * i : hm_w * (i + 1), :] = (
+ colored_heatmap * 0.7 + np.array(images[i]) * 0.3
+ )
+ else:
+ # resized_image = cv2.resize(images, (int(heatmap_h), int(heatmap_w)))
+ heatmap = cv2.resize(
+ heatmap, images.shape[:2], interpolation=cv2.INTER_LINEAR
+ )
+ colored_heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)
+ masked_image[:, hm_w * i : hm_w * (i + 1), :] = (
+ colored_heatmap * 0.7 + images * 0.3
+ )
+
+ if temp_locs is not None:
+ font = cv2.FONT_HERSHEY_SIMPLEX
+ font_scale = 1
+ color = (255, 255, 255) # White color in BGR
+ thickness = 2
+ position = (20, 30)
+
+ temp_loc = temp_locs[i]
+ text = f"{temp_loc:.5f}"
+ cv2.putText(
+ masked_image[:, hm_w * i : hm_w * (i + 1), :],
+ text,
+ position,
+ font,
+ font_scale,
+ color,
+ thickness,
+ )
+ cv2.imwrite(file_name, masked_image)
+
+
+def vis_3d_heatmap(heatmap, file_name):
+ # Define the dimensions of the cuboid
+ z_dim, y_dim, x_dim = heatmap.shape
+
+ Z, Y, X = np.mgrid[:z_dim, :y_dim, :x_dim]
+
+ fig = go.Figure(
+ data=go.Volume(
+ x=X.flatten(),
+ y=Y.flatten(),
+ z=Z.flatten(),
+ value=heatmap.flatten(),
+ isomin=0.0,
+ isomax=0.999,
+ opacity=0.1,
+ surface_count=25,
+ )
+ )
+ fig.update_layout(
+ scene_xaxis_showticklabels=False,
+ scene_yaxis_showticklabels=False,
+ scene_zaxis_showticklabels=False,
+ )
+ fig.write_image(file_name)
+
+
+def save_batch_heatmaps(
+ batch_image, batch_heatmaps, file_name, normalize=True, batch_cls=None
+):
+ """
+ batch_image: [batch_size, channel, height, width]
+ batch_heatmaps: ['batch_size, num_joints, height, width]
+ batch_cls: ['batch_size, num_joints, 1]
+ file_name: saved file name
+ """
+ if normalize:
+ batch_image = batch_image.clone()
+ min = float(batch_image.min())
+ max = float(batch_image.max())
+
+ batch_image.add_(-min).div_(max - min + 1e-5)
+
+ batch_size = batch_heatmaps.size(0)
+ num_joints = batch_heatmaps.size(1)
+ heatmap_height = batch_heatmaps.size(2)
+ heatmap_width = batch_heatmaps.size(3)
+
+ grid_image = np.zeros(
+ (batch_size * heatmap_height, (num_joints + 1) * heatmap_width, 3),
+ dtype=np.uint8,
+ )
+
+ for i in range(batch_size):
+ if batch_image.dim() == 4:
+ image = (
+ batch_image[i]
+ .mul(255)
+ .clamp(0, 255)
+ .byte()
+ .permute(1, 2, 0)
+ .cpu()
+ .numpy()
+ )
+ else:
+ image = (
+ batch_image[i]
+ .mul(255)
+ .clamp(0, 255)
+ .byte()
+ .permute(1, 2, 3, 0)
+ .cpu()
+ .numpy()
+ )
+ heatmaps = batch_heatmaps[i].mul(255).clamp(0, 255).byte().cpu().numpy()
+
+ height_begin = heatmap_height * i
+ height_end = heatmap_height * (i + 1)
+ for j in range(num_joints):
+ if image.ndim == 4:
+ image = image[j, :, :, :]
+
+ resized_image = cv2.resize(image, (int(heatmap_width), int(heatmap_height)))
+
+ heatmap = heatmaps[j, :, :]
+ colored_heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)
+
+ if batch_cls is not None:
+ cls = batch_cls[i][j].detach().cpu().numpy()
+ colored_heatmap = cv2.putText(
+ colored_heatmap,
+ f"Cls Pred: {cls}",
+ (heatmap_width * (j + 1) - 15, 10),
+ cv2.FONT_HERSHEY_SIMPLEX,
+ 1,
+ 1,
+ cv2.LINE_AA,
+ )
+ masked_image = colored_heatmap * 0.7 + resized_image * 0.3
+
+ width_begin = heatmap_width * (j + 1)
+ width_end = heatmap_width * (j + 2)
+
+ grid_image[height_begin:height_end, width_begin:width_end, :] = masked_image
+
+ grid_image[height_begin:height_end, 0:heatmap_width, :] = resized_image
+ cv2.imwrite(file_name, grid_image)
+
+
+def debugging_panel(
+ debug_cfg,
+ batch_image,
+ batch_heatmaps_gt,
+ batch_heatmaps_pred,
+ idx,
+ normalize=True,
+ batch_cls_gt=None,
+ batch_cls_pred=None,
+ split="train",
+):
+ if debug_cfg.save_hm_gt:
+ save_batch_heatmaps(
+ batch_image,
+ batch_heatmaps_gt,
+ f"samples/{split}_debugs/hm_gt_{idx}.jpg",
+ normalize=normalize,
+ )
+
+ if debug_cfg.save_hm_pred:
+ batch_heatmaps_pred_ = _sigmoid(batch_heatmaps_pred.clone())
+ save_batch_heatmaps(
+ batch_image,
+ batch_heatmaps_pred_,
+ f"samples/{split}_debugs/hm_pred_{idx}.jpg",
+ normalize=normalize,
+ )
+
+
+def save_file(data, file_path):
+ f_name, f_extention = file_extention(file_path)
+
+ if f_extention == ".json":
+ with open(file_path, "w") as f:
+ json.dump(data, f)
+ print(f"Data has been saved to --- {file_path}")
+ else:
+ raise ValueError(f"{f_extention} is not supported now!")
+
+
+def load_file(file_path):
+ f_name, f_extention = file_extention(file_path)
+
+ if f_extention == ".json":
+ with open(file_path, "r") as f:
+ data = json.load(f)
+ print(f"Data has been loaded from --- {file_path}")
+ else:
+ raise ValueError(f"{f_extention} is not supported now!")
+
+ return data
+
+
+def draw_landmarks(image, landmarks):
+ """This function is to draw facial landmarks into transformed images"""
+ assert landmarks is not None, "Landmarks can not be None!"
+
+ img_cp = deepcopy(image)
+ landmarks = landmarks.astype(int)
+
+ for i, p in enumerate(landmarks):
+ img_cp = cv2.circle(img_cp, (p[0], p[1]), 2, (0, 255, 0), 1)
+
+ return img_cp
+
+
+def draw_most_vul_points(blended_mask):
+ """Detecting and Drawing the most vulnerable points for visualization purpose"""
+ b_mask_cp = deepcopy(blended_mask)
+ target_H, target_W, target_C = b_mask_cp.shape
+
+ max_val = b_mask_cp[..., 0].max()
+ max_val = max_val if max_val > 0 else 1
+
+ m_v_indices = np.where(b_mask_cp == max_val)
+
+ for j, i in zip(m_v_indices[0], m_v_indices[1]):
+ b_mask_cp[j, i] = (255, 0, 0)
+
+ return b_mask_cp
diff --git a/clean/video/fakestormer/register/misc.py b/clean/video/fakestormer/register/misc.py
new file mode 100644
index 0000000000000000000000000000000000000000..179c8a1bcbb078350cf84a3a170ab61fd174661d
--- /dev/null
+++ b/clean/video/fakestormer/register/misc.py
@@ -0,0 +1,359 @@
+# -*- coding: utf-8 -*-
+import collections.abc
+import functools
+import itertools
+import subprocess
+import warnings
+from collections import abc
+from importlib import import_module
+from inspect import getfullargspec
+from itertools import repeat
+
+
+# From PyTorch internals
+def _ntuple(n):
+
+ def parse(x):
+ if isinstance(x, collections.abc.Iterable):
+ return x
+ return tuple(repeat(x, n))
+
+ return parse
+
+
+to_1tuple = _ntuple(1)
+to_2tuple = _ntuple(2)
+to_3tuple = _ntuple(3)
+to_4tuple = _ntuple(4)
+to_ntuple = _ntuple
+
+
+def is_str(x):
+ """Whether the input is an string instance.
+ Note: This method is deprecated since python 2 is no longer supported.
+ """
+ return isinstance(x, str)
+
+
+def import_modules_from_strings(imports, allow_failed_imports=False):
+ """Import modules from the given list of strings.
+ Args:
+ imports (list | str | None): The given module names to be imported.
+ allow_failed_imports (bool): If True, the failed imports will return
+ None. Otherwise, an ImportError is raise. Default: False.
+ Returns:
+ list[module] | module | None: The imported modules.
+ Examples:
+ >>> osp, sys = import_modules_from_strings(
+ ... ['os.path', 'sys'])
+ >>> import os.path as osp_
+ >>> import sys as sys_
+ >>> assert osp == osp_
+ >>> assert sys == sys_
+ """
+ if not imports:
+ return
+ single_import = False
+ if isinstance(imports, str):
+ single_import = True
+ imports = [imports]
+ if not isinstance(imports, list):
+ raise TypeError(f"custom_imports must be a list but got type {type(imports)}")
+ imported = []
+ for imp in imports:
+ if not isinstance(imp, str):
+ raise TypeError(f"{imp} is of type {type(imp)} and cannot be imported.")
+ try:
+ imported_tmp = import_module(imp)
+ except ImportError:
+ if allow_failed_imports:
+ warnings.warn(f"{imp} failed to import and is ignored.", UserWarning)
+ imported_tmp = None
+ else:
+ raise ImportError
+ imported.append(imported_tmp)
+ if single_import:
+ imported = imported[0]
+ return imported
+
+
+def iter_cast(inputs, dst_type, return_type=None):
+ """Cast elements of an iterable object into some type.
+ Args:
+ inputs (Iterable): The input object.
+ dst_type (type): Destination type.
+ return_type (type, optional): If specified, the output object will be
+ converted to this type, otherwise an iterator.
+ Returns:
+ iterator or specified type: The converted object.
+ """
+ if not isinstance(inputs, abc.Iterable):
+ raise TypeError("inputs must be an iterable object")
+ if not isinstance(dst_type, type):
+ raise TypeError('"dst_type" must be a valid type')
+
+ out_iterable = map(dst_type, inputs)
+
+ if return_type is None:
+ return out_iterable
+ else:
+ return return_type(out_iterable)
+
+
+def list_cast(inputs, dst_type):
+ """Cast elements of an iterable object into a list of some type.
+ A partial method of :func:`iter_cast`.
+ """
+ return iter_cast(inputs, dst_type, return_type=list)
+
+
+def tuple_cast(inputs, dst_type):
+ """Cast elements of an iterable object into a tuple of some type.
+ A partial method of :func:`iter_cast`.
+ """
+ return iter_cast(inputs, dst_type, return_type=tuple)
+
+
+def is_seq_of(seq, expected_type, seq_type=None):
+ """Check whether it is a sequence of some type.
+ Args:
+ seq (Sequence): The sequence to be checked.
+ expected_type (type): Expected type of sequence items.
+ seq_type (type, optional): Expected sequence type.
+ Returns:
+ bool: Whether the sequence is valid.
+ """
+ if seq_type is None:
+ exp_seq_type = abc.Sequence
+ else:
+ assert isinstance(seq_type, type)
+ exp_seq_type = seq_type
+ if not isinstance(seq, exp_seq_type):
+ return False
+ for item in seq:
+ if not isinstance(item, expected_type):
+ return False
+ return True
+
+
+def is_list_of(seq, expected_type):
+ """Check whether it is a list of some type.
+ A partial method of :func:`is_seq_of`.
+ """
+ return is_seq_of(seq, expected_type, seq_type=list)
+
+
+def is_tuple_of(seq, expected_type):
+ """Check whether it is a tuple of some type.
+ A partial method of :func:`is_seq_of`.
+ """
+ return is_seq_of(seq, expected_type, seq_type=tuple)
+
+
+def slice_list(in_list, lens):
+ """Slice a list into several sub lists by a list of given length.
+ Args:
+ in_list (list): The list to be sliced.
+ lens(int or list): The expected length of each out list.
+ Returns:
+ list: A list of sliced list.
+ """
+ if isinstance(lens, int):
+ assert len(in_list) % lens == 0
+ lens = [lens] * int(len(in_list) / lens)
+ if not isinstance(lens, list):
+ raise TypeError('"indices" must be an integer or a list of integers')
+ elif sum(lens) != len(in_list):
+ raise ValueError(
+ "sum of lens and list length does not "
+ f"match: {sum(lens)} != {len(in_list)}"
+ )
+ out_list = []
+ idx = 0
+ for i in range(len(lens)):
+ out_list.append(in_list[idx : idx + lens[i]])
+ idx += lens[i]
+ return out_list
+
+
+def concat_list(in_list):
+ """Concatenate a list of list into a single list.
+ Args:
+ in_list (list): The list of list to be merged.
+ Returns:
+ list: The concatenated flat list.
+ """
+ return list(itertools.chain(*in_list))
+
+
+def check_prerequisites(
+ prerequisites,
+ checker,
+ msg_tmpl='Prerequisites "{}" are required in method "{}" but not '
+ "found, please install them first.",
+): # yapf: disable
+ """A decorator factory to check if prerequisites are satisfied.
+ Args:
+ prerequisites (str of list[str]): Prerequisites to be checked.
+ checker (callable): The checker method that returns True if a
+ prerequisite is meet, False otherwise.
+ msg_tmpl (str): The message template with two variables.
+ Returns:
+ decorator: A specific decorator.
+ """
+
+ def wrap(func):
+
+ @functools.wraps(func)
+ def wrapped_func(*args, **kwargs):
+ requirements = (
+ [prerequisites] if isinstance(prerequisites, str) else prerequisites
+ )
+ missing = []
+ for item in requirements:
+ if not checker(item):
+ missing.append(item)
+ if missing:
+ print(msg_tmpl.format(", ".join(missing), func.__name__))
+ raise RuntimeError("Prerequisites not meet.")
+ else:
+ return func(*args, **kwargs)
+
+ return wrapped_func
+
+ return wrap
+
+
+def _check_py_package(package):
+ try:
+ import_module(package)
+ except ImportError:
+ return False
+ else:
+ return True
+
+
+def _check_executable(cmd):
+ if subprocess.call(f"which {cmd}", shell=True) != 0:
+ return False
+ else:
+ return True
+
+
+def requires_package(prerequisites):
+ """A decorator to check if some python packages are installed.
+ Example:
+ >>> @requires_package('numpy')
+ >>> func(arg1, args):
+ >>> return numpy.zeros(1)
+ array([0.])
+ >>> @requires_package(['numpy', 'non_package'])
+ >>> func(arg1, args):
+ >>> return numpy.zeros(1)
+ ImportError
+ """
+ return check_prerequisites(prerequisites, checker=_check_py_package)
+
+
+def requires_executable(prerequisites):
+ """A decorator to check if some executable files are installed.
+ Example:
+ >>> @requires_executable('ffmpeg')
+ >>> func(arg1, args):
+ >>> print(1)
+ 1
+ """
+ return check_prerequisites(prerequisites, checker=_check_executable)
+
+
+def deprecated_api_warning(name_dict, cls_name=None):
+ """A decorator to check if some arguments are deprecate and try to replace
+ deprecate src_arg_name to dst_arg_name.
+ Args:
+ name_dict(dict):
+ key (str): Deprecate argument names.
+ val (str): Expected argument names.
+ Returns:
+ func: New function.
+ """
+
+ def api_warning_wrapper(old_func):
+
+ @functools.wraps(old_func)
+ def new_func(*args, **kwargs):
+ # get the arg spec of the decorated method
+ args_info = getfullargspec(old_func)
+ # get name of the function
+ func_name = old_func.__name__
+ if cls_name is not None:
+ func_name = f"{cls_name}.{func_name}"
+ if args:
+ arg_names = args_info.args[: len(args)]
+ for src_arg_name, dst_arg_name in name_dict.items():
+ if src_arg_name in arg_names:
+ warnings.warn(
+ f'"{src_arg_name}" is deprecated in '
+ f'`{func_name}`, please use "{dst_arg_name}" '
+ "instead",
+ DeprecationWarning,
+ )
+ arg_names[arg_names.index(src_arg_name)] = dst_arg_name
+ if kwargs:
+ for src_arg_name, dst_arg_name in name_dict.items():
+ if src_arg_name in kwargs:
+
+ assert dst_arg_name not in kwargs, (
+ f"The expected behavior is to replace "
+ f"the deprecated key `{src_arg_name}` to "
+ f"new key `{dst_arg_name}`, but got them "
+ f"in the arguments at the same time, which "
+ f"is confusing. `{src_arg_name} will be "
+ f"deprecated in the future, please "
+ f"use `{dst_arg_name}` instead."
+ )
+
+ warnings.warn(
+ f'"{src_arg_name}" is deprecated in '
+ f'`{func_name}`, please use "{dst_arg_name}" '
+ "instead",
+ DeprecationWarning,
+ )
+ kwargs[dst_arg_name] = kwargs.pop(src_arg_name)
+
+ # apply converted arguments to the decorated method
+ output = old_func(*args, **kwargs)
+ return output
+
+ return new_func
+
+ return api_warning_wrapper
+
+
+def is_method_overridden(method, base_class, derived_class):
+ """Check if a method of base class is overridden in derived class.
+ Args:
+ method (str): the method name to check.
+ base_class (type): the class of the base class.
+ derived_class (type | Any): the class or instance of the derived class.
+ """
+ assert isinstance(
+ base_class, type
+ ), "base_class doesn't accept instance, Please pass class instead."
+
+ if not isinstance(derived_class, type):
+ derived_class = derived_class.__class__
+
+ base_method = getattr(base_class, method)
+ derived_method = getattr(derived_class, method)
+ return derived_method != base_method
+
+
+def has_method(obj: object, method: str) -> bool:
+ """Check whether the object has a method.
+ Args:
+ method (str): The method name to check.
+ obj (object): The object to check.
+ Returns:
+ bool: True if the object has the method else False.
+ """
+ return hasattr(obj, method) and callable(getattr(obj, method))
diff --git a/clean/video/fakestormer/register/register.py b/clean/video/fakestormer/register/register.py
new file mode 100644
index 0000000000000000000000000000000000000000..e3d934f7309e3d3a22c3616804707a0e90cf2f9c
--- /dev/null
+++ b/clean/video/fakestormer/register/register.py
@@ -0,0 +1,323 @@
+# -*- coding: utf-8 -*-
+import inspect
+import warnings
+from functools import partial
+from typing import Any, Dict, Optional
+
+from .misc import deprecated_api_warning, is_seq_of
+
+
+def build_from_cfg(
+ cfg: Dict, registry: "Registry", default_args: Optional[Dict] = None
+) -> Any:
+ """Build a module from config dict when it is a class configuration, or
+ call a function from config dict when it is a function configuration.
+ Example:
+ >>> MODELS = Registry('models')
+ >>> @MODELS.register_module()
+ >>> class ResNet:
+ >>> pass
+ >>> resnet = build_from_cfg(dict(type='Resnet'), MODELS)
+ >>> # Returns an instantiated object
+ >>> @MODELS.register_module()
+ >>> def resnet50():
+ >>> pass
+ >>> resnet = build_from_cfg(dict(type='resnet50'), MODELS)
+ >>> # Return a result of the calling function
+ Args:
+ cfg (dict): Config dict. It should at least contain the key "type".
+ registry (:obj:`Registry`): The registry to search the type from.
+ default_args (dict, optional): Default initialization arguments.
+ Returns:
+ object: The constructed object.
+ """
+ if not isinstance(cfg, dict):
+ raise TypeError(f"cfg must be a dict, but got {type(cfg)}")
+ if "type" not in cfg:
+ if default_args is None or "type" not in default_args:
+ raise KeyError(
+ '`cfg` or `default_args` must contain the key "type", '
+ f"but got {cfg}\n{default_args}"
+ )
+ if not isinstance(registry, Registry):
+ raise TypeError(
+ "registry must be an mmcv.Registry object, " f"but got {type(registry)}"
+ )
+ if not (isinstance(default_args, dict) or default_args is None):
+ raise TypeError(
+ "default_args must be a dict or None, " f"but got {type(default_args)}"
+ )
+
+ args = cfg.copy()
+
+ if default_args is not None:
+ for name, value in default_args.items():
+ args.setdefault(name, value)
+
+ obj_type = args.pop("type")
+ if isinstance(obj_type, str):
+ obj_cls = registry.get(obj_type)
+ if obj_cls is None:
+ raise KeyError(f"{obj_type} is not in the {registry.name} registry")
+ elif inspect.isclass(obj_type) or inspect.isfunction(obj_type):
+ obj_cls = obj_type
+ else:
+ raise TypeError(f"type must be a str or valid type, but got {type(obj_type)}")
+ try:
+ return obj_cls(**args)
+ except Exception as e:
+ # Normal TypeError does not print class name.
+ raise type(e)(f"{obj_cls.__name__}: {e}")
+
+
+class Registry:
+ """A registry to map strings to classes or functions.
+ Registered object could be built from registry. Meanwhile, registered
+ functions could be called from registry.
+ Example:
+ >>> MODELS = Registry('models')
+ >>> @MODELS.register_module()
+ >>> class ResNet:
+ >>> pass
+ >>> resnet = MODELS.build(dict(type='ResNet'))
+ >>> @MODELS.register_module()
+ >>> def resnet50():
+ >>> pass
+ >>> resnet = MODELS.build(dict(type='resnet50'))
+ Please refer to
+ https://mmcv.readthedocs.io/en/latest/understand_mmcv/registry.html for
+ advanced usage.
+ Args:
+ name (str): Registry name.
+ build_func(func, optional): Build function to construct instance from
+ Registry, func:`build_from_cfg` is used if neither ``parent`` or
+ ``build_func`` is specified. If ``parent`` is specified and
+ ``build_func`` is not given, ``build_func`` will be inherited
+ from ``parent``. Default: None.
+ parent (Registry, optional): Parent registry. The class registered in
+ children registry could be built from parent. Default: None.
+ scope (str, optional): The scope of registry. It is the key to search
+ for children registry. If not specified, scope will be the name of
+ the package where class is defined, e.g. mmdet, mmcls, mmseg.
+ Default: None.
+ """
+
+ def __init__(self, name, build_func=None, parent=None, scope=None):
+ self._name = name
+ self._module_dict = dict()
+ self._children = dict()
+ self._scope = self.infer_scope() if scope is None else scope
+
+ # self.build_func will be set with the following priority:
+ # 1. build_func
+ # 2. parent.build_func
+ # 3. build_from_cfg
+ if build_func is None:
+ if parent is not None:
+ self.build_func = parent.build_func
+ else:
+ self.build_func = build_from_cfg
+ else:
+ self.build_func = build_func
+ if parent is not None:
+ assert isinstance(parent, Registry)
+ parent._add_children(self)
+ self.parent = parent
+ else:
+ self.parent = None
+
+ def __len__(self):
+ return len(self._module_dict)
+
+ def __contains__(self, key):
+ return self.get(key) is not None
+
+ def __repr__(self):
+ format_str = (
+ self.__class__.__name__ + f"(name={self._name}, "
+ f"items={self._module_dict})"
+ )
+ return format_str
+
+ @staticmethod
+ def infer_scope():
+ """Infer the scope of registry.
+ The name of the package where registry is defined will be returned.
+ Example:
+ >>> # in mmdet/models/backbone/resnet.py
+ >>> MODELS = Registry('models')
+ >>> @MODELS.register_module()
+ >>> class ResNet:
+ >>> pass
+ The scope of ``ResNet`` will be ``mmdet``.
+ Returns:
+ str: The inferred scope name.
+ """
+ # We access the caller using inspect.currentframe() instead of
+ # inspect.stack() for performance reasons. See details in PR #1844
+ frame = inspect.currentframe()
+ # get the frame where `infer_scope()` is called
+ infer_scope_caller = frame.f_back.f_back
+ filename = inspect.getmodule(infer_scope_caller).__name__
+ split_filename = filename.split(".")
+ return split_filename[0]
+
+ @staticmethod
+ def split_scope_key(key):
+ """Split scope and key.
+ The first scope will be split from key.
+ Examples:
+ >>> Registry.split_scope_key('mmdet.ResNet')
+ 'mmdet', 'ResNet'
+ >>> Registry.split_scope_key('ResNet')
+ None, 'ResNet'
+ Return:
+ tuple[str | None, str]: The former element is the first scope of
+ the key, which can be ``None``. The latter is the remaining key.
+ """
+ split_index = key.find(".")
+ if split_index != -1:
+ return key[:split_index], key[split_index + 1 :]
+ else:
+ return None, key
+
+ @property
+ def name(self):
+ return self._name
+
+ @property
+ def scope(self):
+ return self._scope
+
+ @property
+ def module_dict(self):
+ return self._module_dict
+
+ @property
+ def children(self):
+ return self._children
+
+ def get(self, key):
+ """Get the registry record.
+ Args:
+ key (str): The class name in string format.
+ Returns:
+ class: The corresponding class.
+ """
+ scope, real_key = self.split_scope_key(key)
+ if scope is None or scope == self._scope:
+ # get from self
+ if real_key in self._module_dict:
+ return self._module_dict[real_key]
+ else:
+ # get from self._children
+ if scope in self._children:
+ return self._children[scope].get(real_key)
+ else:
+ # goto root
+ parent = self.parent
+ while parent.parent is not None:
+ parent = parent.parent
+ return parent.get(key)
+
+ def build(self, *args, **kwargs):
+ return self.build_func(*args, **kwargs, registry=self)
+
+ def _add_children(self, registry):
+ """Add children for a registry.
+ The ``registry`` will be added as children based on its scope.
+ The parent registry could build objects from children registry.
+ Example:
+ >>> models = Registry('models')
+ >>> mmdet_models = Registry('models', parent=models)
+ >>> @mmdet_models.register_module()
+ >>> class ResNet:
+ >>> pass
+ >>> resnet = models.build(dict(type='mmdet.ResNet'))
+ """
+
+ assert isinstance(registry, Registry)
+ assert registry.scope is not None
+ assert (
+ registry.scope not in self.children
+ ), f"scope {registry.scope} exists in {self.name} registry"
+ self.children[registry.scope] = registry
+
+ @deprecated_api_warning(name_dict=dict(module_class="module"))
+ def _register_module(self, module, module_name=None, force=False):
+ if not inspect.isclass(module) and not inspect.isfunction(module):
+ raise TypeError(
+ "module must be a class or a function, " f"but got {type(module)}"
+ )
+
+ if module_name is None:
+ module_name = module.__name__
+ if isinstance(module_name, str):
+ module_name = [module_name]
+ for name in module_name:
+ if not force and name in self._module_dict:
+ raise KeyError(f"{name} is already registered " f"in {self.name}")
+ self._module_dict[name] = module
+
+ def deprecated_register_module(self, cls=None, force=False):
+ warnings.warn(
+ "The old API of register_module(module, force=False) "
+ "is deprecated and will be removed, please use the new API "
+ "register_module(name=None, force=False, module=None) instead.",
+ DeprecationWarning,
+ )
+ if cls is None:
+ return partial(self.deprecated_register_module, force=force)
+ self._register_module(cls, force=force)
+ return cls
+
+ def register_module(self, name=None, force=False, module=None):
+ """Register a module.
+ A record will be added to `self._module_dict`, whose key is the class
+ name or the specified name, and value is the class itself.
+ It can be used as a decorator or a normal function.
+ Example:
+ >>> backbones = Registry('backbone')
+ >>> @backbones.register_module()
+ >>> class ResNet:
+ >>> pass
+ >>> backbones = Registry('backbone')
+ >>> @backbones.register_module(name='mnet')
+ >>> class MobileNet:
+ >>> pass
+ >>> backbones = Registry('backbone')
+ >>> class ResNet:
+ >>> pass
+ >>> backbones.register_module(ResNet)
+ Args:
+ name (str | None): The module name to be registered. If not
+ specified, the class name will be used.
+ force (bool, optional): Whether to override an existing class with
+ the same name. Default: False.
+ module (type): Module class or function to be registered.
+ """
+ if not isinstance(force, bool):
+ raise TypeError(f"force must be a boolean, but got {type(force)}")
+ # NOTE: This is a walkaround to be compatible with the old api,
+ # while it may introduce unexpected bugs.
+ if isinstance(name, type):
+ return self.deprecated_register_module(name, force=force)
+
+ # raise the error ahead of time
+ if not (name is None or isinstance(name, str) or is_seq_of(name, str)):
+ raise TypeError(
+ "name must be either of None, an instance of str or a sequence"
+ f" of str, but got {type(name)}"
+ )
+
+ # use it as a normal method: x.register_module(module=SomeClass)
+ if module is not None:
+ self._register_module(module=module, module_name=name, force=force)
+ return module
+
+ # use it as a decorator: @x.register_module()
+ def _register(module):
+ self._register_module(module=module, module_name=name, force=force)
+ return module
+
+ return _register
diff --git a/clean/video/fakestormer/scripts/efn_sbi.sh b/clean/video/fakestormer/scripts/efn_sbi.sh
new file mode 100644
index 0000000000000000000000000000000000000000..4dabcee388cf55154799f3fe51a624df0fa62bbc
--- /dev/null
+++ b/clean/video/fakestormer/scripts/efn_sbi.sh
@@ -0,0 +1,3 @@
+#! /bin/bash
+
+CUDA_VISIBLE_DEVICES=0 python scripts/train.py --cfg configs/spatial/efn4_fpn_sbi_adv.yaml
diff --git a/clean/video/fakestormer/scripts/fakesformer_sbi.sh b/clean/video/fakestormer/scripts/fakesformer_sbi.sh
new file mode 100644
index 0000000000000000000000000000000000000000..fe62bbe2b49973e65e530eb01ddf04d9a21346e6
--- /dev/null
+++ b/clean/video/fakestormer/scripts/fakesformer_sbi.sh
@@ -0,0 +1,8 @@
+#! /bin/bash
+
+# CUDA_VISIBLE_DEVICES=0,1,2,3 python scripts/train.py --cfg configs/temporal/FakeSFormer_base_c23.yaml
+CUDA_VISIBLE_DEVICES=0,1,2,3 python scripts/train.py --cfg configs/temporal/FakeSFormer_base_c0.yaml
+# CUDA_VISIBLE_DEVICES=0,1,2,3 python scripts/train.py --cfg configs/temporal/FakeSFormer_base_c40.yaml
+# CUDA_VISIBLE_DEVICES=0,1,2,3 python scripts/train.py --cfg configs/temporal/FakeSFormer_large_c23.yaml
+# CUDA_VISIBLE_DEVICES=0,1,2,3 python scripts/train.py --cfg configs/temporal/FakeSwin3D_base_c23.yaml
+# CUDA_VISIBLE_DEVICES=0,1,2,3 python scripts/train.py --cfg configs/temporal/FakeSFormer_base_c23_224p8.yaml
diff --git a/clean/video/fakestormer/scripts/laanet_temporal.sh b/clean/video/fakestormer/scripts/laanet_temporal.sh
new file mode 100644
index 0000000000000000000000000000000000000000..a867e6f9c088b190c823ada306dd4c009a35b05f
--- /dev/null
+++ b/clean/video/fakestormer/scripts/laanet_temporal.sh
@@ -0,0 +1,5 @@
+#! /bin/bash
+
+CUDA_VISIBLE_DEVICES=0,1,2,3 python scripts/train.py --cfg configs/temporal/ResNet3D_EFPN3D_hm3D_c23.yaml
+# CUDA_VISIBLE_DEVICES=0,1,2,3 python scripts/train.py --cfg configs/temporal/FakeSwin3D_base_c23.yaml
+# CUDA_VISIBLE_DEVICES=0,1,2,3 python scripts/train.py --cfg configs/temporal/FakeSwin3D_base_c0.yaml
diff --git a/clean/video/fakestormer/scripts/swin_bi.sh b/clean/video/fakestormer/scripts/swin_bi.sh
new file mode 100644
index 0000000000000000000000000000000000000000..253b2ef1a09315cb71c8d31a8c7fc93c7ae72027
--- /dev/null
+++ b/clean/video/fakestormer/scripts/swin_bi.sh
@@ -0,0 +1,5 @@
+#! /bin/bash
+
+# CUDA_VISIBLE_DEVICES=0,1,2,3 python scripts/train.py --cfg configs/spatial/swin_sbi_base.yaml
+CUDA_VISIBLE_DEVICES=0 python scripts/train.py --cfg configs/spatial/swin_bi_small.yaml
+# CUDA_VISIBLE_DEVICES=0,1,2,3 python scripts/train.py --cfg configs/spatial/swin_sbi_tiny.yaml
diff --git a/clean/video/fakestormer/scripts/swin_sbi.sh b/clean/video/fakestormer/scripts/swin_sbi.sh
new file mode 100644
index 0000000000000000000000000000000000000000..96331da07787a28fb043536ef4aa09c3e8aa5bcf
--- /dev/null
+++ b/clean/video/fakestormer/scripts/swin_sbi.sh
@@ -0,0 +1,5 @@
+#! /bin/bash
+
+# CUDA_VISIBLE_DEVICES=0,1,2,3 python scripts/train.py --cfg configs/spatial/swin_sbi_base.yaml
+CUDA_VISIBLE_DEVICES=0,1,2,3 python scripts/train.py --cfg configs/spatial/swin_sbi_small.yaml
+# CUDA_VISIBLE_DEVICES=0,1,2,3 python scripts/train.py --cfg configs/spatial/swin_sbi_tiny.yaml
diff --git a/clean/video/fakestormer/scripts/test.py b/clean/video/fakestormer/scripts/test.py
new file mode 100644
index 0000000000000000000000000000000000000000..3bed76c022f1b0379e47c8d3c7cd6b54dafc2d41
--- /dev/null
+++ b/clean/video/fakestormer/scripts/test.py
@@ -0,0 +1,411 @@
+# -*- coding: utf-8 -*-
+import argparse
+import os
+import sys
+import time
+
+if not os.getcwd() in sys.path:
+ sys.path.append(os.getcwd())
+import math
+import random
+from glob import glob
+
+import cv2
+import numpy as np
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+from configs.get_config import load_config
+from datasets import DATASETS, build_dataset
+from lib.core_function import AverageMeter
+from lib.metrics import bin_calculate_auc_ap_ar, get_acc_mesure_func
+from logs.logger import LOG_DIR, Logger
+from losses.losses import _sigmoid
+from models import *
+from natsort import natsorted
+from package_utils.image_utils import crop_by_margin, load_image
+from package_utils.tensors import masked_inputs
+from package_utils.transform import (
+ final_transform,
+ get_affine_transform,
+ get_center_scale,
+)
+from package_utils.utils import save_file, vis_heatmap
+from PIL import Image
+from torch.utils.data import DataLoader
+from tqdm import tqdm
+
+
+def parse_args(args=None):
+ arg_parser = argparse.ArgumentParser("Processing testing...")
+ arg_parser.add_argument("--cfg", "-c", help="Config file", required=True)
+ arg_parser.add_argument(
+ "--image", "-i", type=str, help="Image for the single testing mode!"
+ )
+ arg_parser.add_argument(
+ "--video", "-v", type=str, help="Video for the single testing mode!"
+ )
+ args = arg_parser.parse_args(args)
+
+ return args
+
+
+if __name__ == "__main__":
+ if sys.argv[1:] is not None:
+ args = sys.argv[1:]
+ else:
+ args = sys.argv[:-1]
+ args = parse_args(args)
+
+ # Loading config file
+ cfg = load_config(args.cfg)
+ logger = Logger(task="testing")
+
+ # Seed
+ seed = cfg.SEED
+ random.seed(seed)
+ torch.manual_seed(seed)
+ np.random.seed(seed)
+ torch.cuda.manual_seed(seed)
+
+ task = cfg.TEST.subtask
+ flip_test = cfg.TEST.flip_test
+ logger.info("Flip Test is used --- {}".format(flip_test))
+
+ save_preds = cfg.TEST.save_preds
+ pred_file = cfg.TEST.pred_file
+
+ if task == "test_img":
+ assert (
+ args.image is not None
+ ), "Image can not be None with single image test mode!"
+ logger.info("Turning on single image test mode...")
+ if task == "test_vid":
+ assert (
+ args.video is not None
+ ), "Video can not be None with single video test mode!"
+ assert os.path.exists(
+ args.video
+ ), "Video path must be valid, please check the path again!"
+ logger.info("Turning on single video test mode...")
+ else:
+ logger.info("Turning on evaluation mode...")
+ if task == "eval" and cfg.DATASET.DATA.TEST.FROM_FILE:
+ assert (
+ cfg.DATASET.DATA.TEST.ANNO_FILE is not None
+ ), "Annotation file can not be None with evaluation test mode!"
+ assert len(
+ cfg.DATASET.DATA.TEST.ANNO_FILE
+ ), "Annotation file can not be empty with evaluation test mode!"
+ # assert os.access(cfg.DATASET.DATA.TEST.ANNO_FILE, os.R_OK), "Annotation file must be valid with evaluation test mode!"
+ device_count = torch.cuda.device_count()
+
+ # build and load/initiate pretrained model
+ model = build_model(cfg.MODEL, MODELS).to(torch.float)
+ logger.info("Loading weight ... {}".format(cfg.TEST.pretrained))
+ model = load_pretrained(model, cfg.TEST.pretrained)
+
+ if device_count >= 1:
+ model = nn.DataParallel(model, device_ids=cfg.TEST.gpus).cuda()
+ else:
+ model = model.cuda()
+
+ # Define essential variables
+ image = args.image
+ vid = args.video
+ test_file = cfg.TEST.test_file
+ video_level = cfg.TEST.video_level
+ aspect_ratio = cfg.DATASET.IMAGE_SIZE[1] * 1.0 / cfg.DATASET.IMAGE_SIZE[0]
+ pixel_std = 200
+ rot = 0
+ transforms = final_transform(cfg.DATASET)
+ metrics_base = cfg.METRICS_BASE
+ acc_measure = get_acc_mesure_func(metrics_base)
+ no_shot_preds = cfg.TEST.no_shot_preds or 1
+
+ model.eval()
+ if image is not None and task == "test_img":
+ img = load_image(image)
+ img = cv2.resize(img, (317, 317))
+ img = img[18 : (317 - 18), 18 : (317 - 18), :]
+ c, s = get_center_scale(img.shape[:2], aspect_ratio, pixel_std)
+ trans = get_affine_transform(c, s, rot, cfg.DATASET.IMAGE_SIZE)
+ input = cv2.warpAffine(
+ img,
+ trans,
+ (int(cfg.DATASET.IMAGE_SIZE[0]), int(cfg.DATASET.IMAGE_SIZE[1])),
+ flags=cv2.INTER_LINEAR,
+ )
+ with torch.no_grad():
+ st = time.time()
+ img_trans = transforms(input / 255).to(torch.float)
+ img_trans = torch.unsqueeze(img_trans, 0)
+ if device_count > 0:
+ img_trans = img_trans.cuda(non_blocking=True)
+
+ outputs = model(img_trans)
+ hm_outputs = outputs[0]["hm"]
+ cls_outputs = outputs[0]["cls"].sigmoid()
+ hm_preds = _sigmoid(hm_outputs).cpu().numpy()
+ if cfg.TEST.vis_hm:
+ print(f"Heatmap max value --- {hm_preds.max()}")
+ vis_heatmap(img, hm_preds[0], "output_pred.jpg")
+ label_pred = cls_outputs.cpu().numpy()
+ label = "Fake" if label_pred[0][-1] > cfg.TEST.threshold else "Real"
+ logger.info("Inferencing time --- {}".format(time.time() - st))
+ logger.info("{} --- {}".format(label, label_pred[0][-1]))
+ logger.info("-----------------***--------------------")
+ if vid is not None and task == "test_vid":
+ print(vid)
+ img_list = []
+ n_frames = cfg.DATASET.DATA.SAMPLES_PER_VIDEO.NUM_FRAMES
+ assert n_frames is not None, "Number of video frames can not be None!"
+ # Load first n_frames inside the video
+ img_paths = glob(f"{args.video}/*.png")
+ img_paths = natsorted(img_paths) # correct the order of image paths
+ img_paths = img_paths[:n_frames]
+ for img_path in img_paths:
+ img = Image.open(img_path)
+ H, W = img.size
+ img = img.crop((15, 15, W - 15, H - 15))
+ img_list.append(img)
+
+ # Transform images
+ transformed_imgs = torch.tensor([]).cuda()
+ for _i in img_list:
+ img_resize = _i.resize(
+ (int(cfg.DATASET.IMAGE_SIZE[0]), int(cfg.DATASET.IMAGE_SIZE[1]))
+ )
+ img_resize = np.array(img_resize) / 255
+ img_tensor = transforms(img_resize).to(torch.float)
+ if device_count > 0:
+ img_tensor = img_tensor.cuda(non_blocking=True)
+ transformed_imgs = torch.cat((transformed_imgs, img_tensor.unsqueeze(0)), 0)
+
+ with torch.no_grad():
+ st = time.time()
+ transformed_imgs = transformed_imgs.transpose(0, 1).unsqueeze(0)
+ outputs = model(transformed_imgs)
+
+ hm_outputs = outputs[0]["hm"]
+ cls_outputs = outputs[0]["cls"].sigmoid()
+ temp_loc_outputs = outputs[0]["temp_loc"].sigmoid()
+ temp_loc_preds = temp_loc_outputs.cpu().numpy()
+ hm_preds = _sigmoid(hm_outputs).cpu().numpy()
+
+ if cfg.TEST.vis_hm:
+ print(f"Heatmap max value --- {hm_preds.max()}")
+ print(f"Heatmap min value --- {hm_preds.min()}")
+ vis_heatmap(
+ img_list,
+ hm_preds[0],
+ "output_pred.jpg",
+ temp_loc_preds=temp_loc_preds[0],
+ )
+
+ label = "Fake" if temp_loc_preds[0][-1] > cfg.TEST.threshold else "Real"
+ logger.info("Inferencing time --- {}".format(time.time() - st))
+ logger.info("{} --- {}".format(label, temp_loc_preds[0]))
+ logger.info("-----------------***--------------------")
+ if task == "eval":
+ logger.info(f"Using metric-base {metrics_base} for evaluation!")
+ logger.info(f"Video level evaluation mode: {video_level}")
+ st = time.time()
+ test_dataset = build_dataset(
+ cfg.DATASET, DATASETS, default_args=dict(split="test", config=cfg.DATASET)
+ )
+ test_dataloader = DataLoader(
+ test_dataset,
+ batch_size=cfg.TRAIN.batch_size * len(cfg.TRAIN.gpus),
+ shuffle=True,
+ num_workers=cfg.DATASET.NUM_WORKERS,
+ )
+ logger.info("Dataset loading time --- {}".format(time.time() - st))
+
+ apr = cfg.TEST.apr
+ test_dataloader = tqdm(test_dataloader, dynamic_ncols=True)
+ with torch.no_grad():
+ # Make sure all tensors in same device
+ total_preds = torch.tensor([]).cuda().to(dtype=torch.float)
+ total_labels = torch.tensor([]).cuda().to(dtype=torch.float)
+ vid_preds = {}
+ vid_labels = {}
+
+ # Achieving frame-level predictions to save into file
+ pred_meta = {}
+
+ for b, (inputs, labels, meta) in enumerate(test_dataloader):
+ i_st = time.time()
+ prev_pos_mask = None
+ prev_hm_preds = None
+ b_vid_ids = [vid for vid in meta["vid_id"]]
+
+ if "img_path" in meta.keys():
+ b_data_paths = [ip for ip in meta["img_path"]]
+ elif "vid_path" in meta.keys():
+ b_data_paths = [ip for ip in meta["vid_path"]]
+ else:
+ if save_preds:
+ raise ValueError("There is no img or vid data for saving!")
+
+ if device_count > 0:
+ inputs = inputs.to(dtype=torch.float).cuda()
+ labels = labels.to(dtype=torch.float).cuda()
+
+ for i_shot in range(no_shot_preds): # multi-shot predictions
+ logger.info(f"Running the {i_shot} shot of predictions")
+ if i_shot > 0:
+ new_inputs, pos_mask = masked_inputs(
+ inputs=inputs,
+ hm_preds=prev_hm_preds,
+ prev_pos_mask=prev_pos_mask,
+ cfg=cfg.DATASET,
+ patch_size=16,
+ shot=i_shot,
+ debug=False,
+ vid_ids=b_vid_ids,
+ )
+ outputs = model(new_inputs)
+ prev_pos_mask = pos_mask
+ else:
+ outputs = model(inputs)
+
+ # Applying Flip test
+ if flip_test:
+ if inputs.dim() == 4:
+ outputs_1 = model(inputs.flip(dims=(3,)))
+ else:
+ outputs_1 = model(inputs.flip(dims=(4,)))
+
+ if isinstance(outputs, list):
+ outputs = outputs[0]
+ if flip_test:
+ outputs_1 = outputs_1[0]
+
+ # In case outputs contain a dict key
+ if isinstance(outputs, dict):
+ if flip_test:
+ hm_outputs = (
+ (outputs["hm"] + outputs_1["hm"]) / 2
+ if "hm" in outputs.keys()
+ else None
+ )
+ cls_outputs = (outputs["cls"] + outputs_1["cls"]) / 2
+ outputs_temp_loc = (
+ (outputs["temp_loc"] + outputs_1["temp_loc"]) / 2
+ if "temp_loc" in outputs.keys()
+ else None
+ )
+ else:
+ hm_outputs = (
+ outputs["hm"] if "hm" in outputs.keys() else None
+ )
+ cls_outputs = outputs["cls"]
+ outputs_temp_loc = (
+ outputs["temp_loc"]
+ if "temp_loc" in outputs.keys()
+ else None
+ )
+ prev_hm_preds = hm_outputs
+ logger.info("Inferencing time --- {}".format(time.time() - st))
+
+ # Grisping data item
+ for b_i in range(len(b_data_paths)):
+ if b_data_paths[b_i] not in pred_meta.keys():
+ pred_meta[b_data_paths[b_i]] = list(
+ (
+ cls_outputs[b_i].clone().detach().item(),
+ labels[b_i].clone().detach().item(),
+ )
+ )
+ else:
+ pred_meta[b_data_paths[b_i]].extend(
+ list(
+ (
+ cls_outputs[b_i].clone().detach().item(),
+ labels[b_i].clone().detach().item(),
+ )
+ )
+ )
+
+ if i_shot == (no_shot_preds - 1):
+ if not video_level:
+ total_preds = torch.cat((total_preds, cls_outputs), 0)
+ total_labels = torch.cat((total_labels, labels), 0)
+ else:
+ for idx, vid_id in enumerate(b_vid_ids):
+ if vid_id in vid_preds.keys():
+ vid_preds[vid_id] = torch.cat(
+ (
+ vid_preds[vid_id],
+ torch.unsqueeze(cls_outputs[idx], 0),
+ ),
+ 0,
+ )
+ else:
+ vid_preds[vid_id] = (
+ torch.unsqueeze(
+ cls_outputs[idx].clone().detach(), 0
+ )
+ .cuda()
+ .to(dtype=torch.float)
+ )
+ vid_labels[vid_id] = (
+ torch.unsqueeze(labels[idx].clone().detach(), 0)
+ .cuda()
+ .to(dtype=torch.float)
+ )
+
+ if video_level:
+ for k in vid_preds.keys():
+ total_preds = torch.cat(
+ (total_preds, torch.mean(vid_preds[k], 0, keepdim=True)), 0
+ )
+ total_labels = torch.cat((total_labels, vid_labels[k]), 0)
+
+ acc_ = acc_measure(
+ total_preds,
+ targets=None,
+ labels=total_labels,
+ threshold=cfg.TEST.threshold,
+ )
+ metrics = bin_calculate_auc_ap_ar(
+ total_preds,
+ total_labels,
+ metrics_base=metrics_base,
+ threshold=cfg.TEST.threshold,
+ apr=apr,
+ )
+ best_thr = metrics["best_thr"]
+
+ if apr:
+ auc_, ap_, ar_, mf1_ = (
+ metrics["auc"],
+ metrics["ap"],
+ metrics["ar"],
+ metrics["mf1"],
+ )
+
+ logger.info(
+ f"Current ACC, AUC, AP, AR, mF1, THR for {cfg.DATASET.DATA.TEST.FAKETYPE} --- {cfg.DATASET.DATA.TEST.LABEL_FOLDER} -- \
+ {acc_*100} -- {auc_*100} -- {ap_*100} -- {ar_*100} -- {mf1_*100} -- {best_thr}"
+ )
+ else:
+ bacc_, auc_, p_, r_, s_, f1_, eer_ = (
+ metrics["bacc"],
+ metrics["auc"],
+ metrics["p"],
+ metrics["r"],
+ metrics["s"],
+ metrics["f1"],
+ metrics["eer"],
+ )
+
+ logger.info(
+ f"Current ACC, BACC, AUC, P, R, S, F1, EER, THR for {cfg.DATASET.DATA.TEST.FAKETYPE} --- {cfg.DATASET.DATA.TEST.LABEL_FOLDER} -- \
+ {acc_*100} -- {bacc_*100} -- {auc_*100} -- {p_*100} -- {r_*100} -- {s_*100} -- {f1_*100} -- {eer_*100} -- {best_thr}"
+ )
+
+ if save_preds:
+ logger.info(f"Preditions will be saved into -- {pred_file}")
+ save_file(data=pred_meta, file_path=pred_file)
diff --git a/clean/video/fakestormer/scripts/test.sh b/clean/video/fakestormer/scripts/test.sh
new file mode 100644
index 0000000000000000000000000000000000000000..b6038464d4dd1b2463dd178e685e6c57a6dee906
--- /dev/null
+++ b/clean/video/fakestormer/scripts/test.sh
@@ -0,0 +1,10 @@
+#! /bin/bash
+
+# CUDA_VISIBLE_DEVICES=0,1,2,3 python scripts/test.py --cfg configs/temporal/bin_cls/ResNet3D_c23.yaml \
+# -i 447.png
+
+# CUDA_VISIBLE_DEVICES=0 python scripts/test.py --cfg configs/temporal/FakeSFormer_base_c23.yaml \
+# -v /data/deepfake_cluster/datasets_df/DFW/test/frames/fake_test/fake_98_187
+
+CUDA_VISIBLE_DEVICES=0 python scripts/test.py --cfg configs/spatial/xception_sbi.yaml \
+ -i 447.png
diff --git a/clean/video/fakestormer/scripts/test_bi.sh b/clean/video/fakestormer/scripts/test_bi.sh
new file mode 100644
index 0000000000000000000000000000000000000000..b9348cd6ceff0a95e2471e075877e4bd5ed5e049
--- /dev/null
+++ b/clean/video/fakestormer/scripts/test_bi.sh
@@ -0,0 +1,10 @@
+#! /bin/bash
+
+# CUDA_VISIBLE_DEVICES=0 python scripts/test.py --cfg configs/spatial/vit_bi_small.yaml \
+# -i /data/deepfake_cluster/datasets_df/FaceForensics++/c0/test/frames/Deepfakes/000_003/012.png
+
+# CUDA_VISIBLE_DEVICES=0 python scripts/test.py --cfg configs/spatial/swin_bi_small.yaml \
+# -i ~/data/FaceForensics++/c0/test/frames/NeuralTextures/035_036/000.png
+
+CUDA_VISIBLE_DEVICES=0 python scripts/test.py --cfg configs/spatial/efn4_fpn_hm_adv.yaml \
+ -i ~/data/FaceForensics++/c0/test/frames/NeuralTextures/035_036/000.png
diff --git a/clean/video/fakestormer/scripts/test_efn.sh b/clean/video/fakestormer/scripts/test_efn.sh
new file mode 100644
index 0000000000000000000000000000000000000000..3385c4b5532508a1c401c0f674ad2f2dba5811cc
--- /dev/null
+++ b/clean/video/fakestormer/scripts/test_efn.sh
@@ -0,0 +1,4 @@
+#! /bin/bash
+
+CUDA_VISIBLE_DEVICES=0 python scripts/test.py --cfg configs/spatial/efn4_fpn_hm_adv.yaml \
+ -i 447.png
diff --git a/clean/video/fakestormer/scripts/test_fakestormer.sh b/clean/video/fakestormer/scripts/test_fakestormer.sh
new file mode 100644
index 0000000000000000000000000000000000000000..d7ab6f1003261b9b307da6e1157bcfd606a88c50
--- /dev/null
+++ b/clean/video/fakestormer/scripts/test_fakestormer.sh
@@ -0,0 +1,10 @@
+#! /bin/bash
+
+# CUDA_VISIBLE_DEVICES=0,1,2,3 python scripts/test.py --cfg configs/temporal/FakeSFormer_base_c23.yaml \
+# -i samples/debugs/affine_f_2883.jpg
+
+# CUDA_VISIBLE_DEVICES=0,1,2,3 python scripts/test.py --cfg configs/temporal/FakeSFormer_base_c40.yaml \
+# -i samples/debugs/affine_f_2883.jpg
+
+CUDA_VISIBLE_DEVICES=0,1,2,3 python scripts/test.py --cfg configs/temporal/FakeSFormer_base_c0.yaml \
+ -i samples/debugs/affine_f_2883.jpg
diff --git a/clean/video/fakestormer/scripts/test_laanet_temporal.sh b/clean/video/fakestormer/scripts/test_laanet_temporal.sh
new file mode 100644
index 0000000000000000000000000000000000000000..f13d75df68c624335232c1d786f3ec8e607471fd
--- /dev/null
+++ b/clean/video/fakestormer/scripts/test_laanet_temporal.sh
@@ -0,0 +1,4 @@
+#! /bin/bash
+
+CUDA_VISIBLE_DEVICES=0,1,2,3 python scripts/test.py --cfg configs/temporal/FakeSwin3D_base_c23.yaml \
+ -i samples/debugs/affine_f_2883.jpg
diff --git a/clean/video/fakestormer/scripts/test_sbi.sh b/clean/video/fakestormer/scripts/test_sbi.sh
new file mode 100644
index 0000000000000000000000000000000000000000..de415980095ffcf1aa7e364376d3b387d416b74b
--- /dev/null
+++ b/clean/video/fakestormer/scripts/test_sbi.sh
@@ -0,0 +1,28 @@
+#! /bin/bash
+
+# CUDA_VISIBLE_DEVICES=0 python scripts/test.py --cfg configs/spatial/efn4_fpn_sbi_adv.yaml \
+# -i samples/debugs/affine_f_2883.jpg
+
+# CUDA_VISIBLE_DEVICES=0 python scripts/test.py --cfg configs/spatial/vit_sbi_base.yaml \
+# -i samples/debugs/affine_f_2883.jpg
+
+CUDA_VISIBLE_DEVICES=0 python scripts/test.py --cfg configs/spatial/vit_sbi_small.yaml \
+ -i /home/users/XXX/data/FaceForensics++/c0/test/frames/Deepfakes/000_003/000.png
+
+# CUDA_VISIBLE_DEVICES=0,1,2,3 python scripts/test.py --cfg configs/spatial/vit_sbi_large.yaml \
+# -i samples/debugs/affine_f_2883.jpg
+
+# CUDA_VISIBLE_DEVICES=0 python scripts/test.py --cfg configs/spatial/swin_sbi_base.yaml \
+# -i samples/debugs/affine_f_2883.jpg
+
+# CUDA_VISIBLE_DEVICES=0 python scripts/test.py --cfg configs/spatial/swin_sbi_small.yaml \
+# -i samples/debugs/affine_f_2883.jpg
+
+# CUDA_VISIBLE_DEVICES=0 python scripts/test.py --cfg configs/spatial/swin_bi_small.yaml \
+# -i samples/debugs/affine_f_2883.jpg
+
+# CUDA_VISIBLE_DEVICES=0,1,2,3 python scripts/test.py --cfg configs/spatial/swin_sbi_tiny.yaml \
+# -i samples/debugs/affine_f_2883.jpg
+
+# CUDA_VISIBLE_DEVICES=0,1,2,3 python scripts/test.py --cfg configs/temporal/FakeSFormer_base.yaml \
+# -i samples/debugs/affine_f_2883.jpg
diff --git a/clean/video/fakestormer/scripts/train.py b/clean/video/fakestormer/scripts/train.py
new file mode 100644
index 0000000000000000000000000000000000000000..0f994354bdd5139cf9d8a9f6b28dc153148f5736
--- /dev/null
+++ b/clean/video/fakestormer/scripts/train.py
@@ -0,0 +1,243 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
+import os
+import sys
+import time
+
+if os.getcwd() not in sys.path:
+ sys.path.append(os.getcwd())
+import argparse
+import random
+from datetime import datetime
+
+import numpy as np
+import torch
+import torch.nn as nn
+import torch.optim as optim
+from configs.get_config import load_config
+from datasets import *
+from lib.core_function import test, train, validate
+from lib.optimizers.sam import SAM
+from lib.scheduler.linear_decay import LinearDecayLR
+from logs.logger import LOG_DIR, Logger
+from losses import *
+from models import *
+from package_utils.misc import NativeScalerWithGradNormCount as NativeScaler
+from tensorboardX import SummaryWriter
+from torch.utils.data import DataLoader
+
+
+def args_parser(args=None):
+ parser = argparse.ArgumentParser("Training process...")
+ parser.add_argument("--cfg", help="Config file", required=True)
+ parser.add_argument(
+ "--alloc_mem", "-a", help="Pre allocating GPU memory", action="store_true"
+ )
+ return parser.parse_args(args)
+
+
+if __name__ == "__main__":
+ if len(sys.argv[1:]):
+ args = sys.argv[1:]
+ else:
+ args = None
+
+ args = args_parser(args)
+ cfg = load_config(args.cfg)
+ logger = Logger(task=f"training_{cfg.TASK}")
+
+ # Seed
+ seed = cfg.SEED
+ random.seed(seed)
+ torch.manual_seed(seed)
+ np.random.seed(seed)
+ torch.cuda.manual_seed(seed)
+
+ # Allocate memory
+ if args.alloc_mem:
+ mem_all_tensors = torch.rand(60, 10000, 10000)
+ mem_all_tensors.to("cuda:0")
+
+ # Configuing GPU devices
+ devices = torch.device("cpu")
+ torch.backends.cudnn.benchmark = False
+ torch.backends.cudnn.deterministic = True
+
+ if "gpus" in cfg.TRAIN.gpus and cfg.TRAIN.gpus is not None:
+ # Only support a single gpu for training now
+ devices = torch.device("cuda:1")
+ model = build_model(cfg.MODEL, MODELS).cuda()
+
+ # Loading Dataloader
+ start_loading = time.time()
+ val_dataset = build_dataset(
+ cfg.DATASET, DATASETS, default_args=dict(split="val", config=cfg.DATASET)
+ )
+ val_dataloader = DataLoader(
+ val_dataset,
+ batch_size=cfg.TRAIN.batch_size * len(cfg.TRAIN.gpus),
+ shuffle=False,
+ pin_memory=cfg.DATASET.PIN_MEMORY,
+ num_workers=cfg.DATASET.NUM_WORKERS,
+ worker_init_fn=val_dataset.train_worker_init_fn,
+ collate_fn=val_dataset.train_collate_fn,
+ )
+ logger.info(
+ "Loading val dataloader successfully! -- {}".format(time.time() - start_loading)
+ )
+
+ start_loading = time.time()
+ train_dataset = build_dataset(
+ cfg.DATASET, DATASETS, default_args=dict(split="train", config=cfg.DATASET)
+ )
+ train_dataloader = DataLoader(
+ train_dataset,
+ batch_size=cfg.TRAIN.batch_size * len(cfg.TRAIN.gpus),
+ shuffle=True,
+ pin_memory=cfg.DATASET.PIN_MEMORY,
+ num_workers=cfg.DATASET.NUM_WORKERS,
+ worker_init_fn=train_dataset.train_worker_init_fn,
+ collate_fn=train_dataset.train_collate_fn,
+ )
+ logger.info(
+ "Loading Train dataloader successfully! -- {}".format(
+ time.time() - start_loading
+ )
+ )
+
+ # Defining Loss function and Optimizer
+ critetion = build_losses(
+ cfg.TRAIN.loss, LOSSES, default_args=dict(cfg=cfg.TRAIN.loss)
+ ).cuda()
+
+ if cfg.TRAIN.use_amp:
+ eff_lr = (
+ cfg.TRAIN.lr
+ * cfg.TRAIN.accumulation_steps
+ * cfg.TRAIN.batch_size
+ * len(cfg.TRAIN.gpus)
+ / 64
+ ) # 16*4=64 as default, might change
+ else:
+ eff_lr = cfg.TRAIN.lr
+
+ if cfg.TRAIN.optimizer == "Adam":
+ optimizer = optim.Adam(model.parameters(), lr=eff_lr, weight_decay=1e-4)
+ elif cfg.TRAIN.optimizer == "AdamW":
+ optimizer = optim.AdamW(
+ model.parameters(), lr=eff_lr, betas=(0.9, 0.999), weight_decay=1e-4
+ )
+ elif cfg.TRAIN.optimizer == "SAM":
+ # optimizer = SAM(model.parameters(), optim.Adam, lr=cfg.TRAIN.lr, weight_decay=1e-4)
+ optimizer = SAM(
+ model.parameters(),
+ optim.Adam,
+ lr=eff_lr,
+ betas=(0.9, 0.995),
+ weight_decay=1e-4,
+ )
+ else:
+ optimizer = optim.SGD(
+ model.parameters(), lr=eff_lr, weight_decay=1e-5, momentum=0.9
+ )
+
+ # Defining scaler
+ scaler = NativeScaler() if cfg.TRAIN.use_amp else None
+
+ # Loading model
+ model, optimizer, start_epoch, scaler = preset_model(
+ cfg, model, optimizer=optimizer, scaler=scaler
+ )
+ if len(cfg.TRAIN.gpus) > 0:
+ model = nn.DataParallel(model, device_ids=cfg.TRAIN.gpus).cuda()
+ else:
+ model = model.cuda()
+
+ # Learning rate Scheduler
+ if cfg.TRAIN.lr_scheduler == "MultiStepLR":
+ lr_scheduler = optim.lr_scheduler.MultiStepLR(
+ optimizer, **cfg.TRAIN.lr_scheduler
+ )
+ else:
+ lr_scheduler = LinearDecayLR(
+ optimizer,
+ cfg.TRAIN.epochs,
+ cfg.TRAIN.epochs // cfg.TRAIN.start_decay,
+ last_epoch=cfg.TRAIN.begin_epoch,
+ booster=cfg.TRAIN.booster,
+ )
+
+ # Enabling tensorboard
+ writer = SummaryWriter(
+ ".tensorboard/{}_{}".format(datetime.today().strftime("%Y-%m-%d"), cfg.TASK)
+ )
+
+ trainIters = 0
+ valIters = 0
+ min_val_loss = 1e10
+ max_val_acc = 0
+ max_test_auc = 0
+ metrics_base = (
+ cfg.METRICS_BASE
+ ) # Combine heatmap + cls prediction to calculate accuracy
+
+ # Starting training process
+ logger.info("Starting training process...")
+ for epoch in range(start_epoch, cfg.TRAIN.epochs):
+ # Unfreezin backbone to update weights
+ if cfg.TRAIN.freeze_backbone and epoch == cfg.TRAIN.warm_up:
+ unfreeze_backbone(model)
+
+ np.random.seed(seed + epoch)
+ if epoch > 0 and cfg.DATA_RELOAD:
+ logger.info(f"Reloading data for epoch {epoch}...")
+ train_dataset._reload_data(epoch=epoch)
+ train_dataloader = DataLoader(
+ train_dataset,
+ batch_size=cfg.TRAIN.batch_size * len(cfg.TRAIN.gpus),
+ shuffle=True,
+ pin_memory=cfg.DATASET.PIN_MEMORY,
+ num_workers=cfg.DATASET.NUM_WORKERS,
+ worker_init_fn=train_dataset.train_worker_init_fn,
+ collate_fn=train_dataset.train_collate_fn,
+ )
+
+ loss_avg, acc_avg, trainIters = train(
+ cfg,
+ model,
+ critetion,
+ optimizer,
+ epoch,
+ train_dataloader,
+ logger,
+ writer,
+ devices,
+ trainIters,
+ metrics_base=metrics_base,
+ scaler=scaler,
+ )
+ if epoch % cfg.TRAIN.every_val_epochs == 0:
+ loss_val, acc_val, valIters = validate(
+ cfg,
+ model,
+ critetion,
+ epoch,
+ val_dataloader,
+ logger,
+ writer,
+ devices,
+ valIters,
+ metrics_base=metrics_base,
+ )
+
+ if acc_val.avg > max_val_acc:
+ # Saving checkpoint
+ ckp_path = os.path.join(
+ LOG_DIR, "{}_{}_model_best.pth".format(cfg.MODEL.type, cfg.TASK)
+ )
+ save_model(path=ckp_path, epoch=epoch, model=model, optimizer=optimizer)
+ min_val_loss = loss_val.avg
+ max_val_acc = acc_val.avg
+ logger.info(f"Saved best model at epoch --- {epoch}")
+ lr_scheduler.step()
diff --git a/clean/video/fakestormer/scripts/train.sh b/clean/video/fakestormer/scripts/train.sh
new file mode 100644
index 0000000000000000000000000000000000000000..e1aefaffa1f1fc9523dda6436fb6cff04dd84e2e
--- /dev/null
+++ b/clean/video/fakestormer/scripts/train.sh
@@ -0,0 +1,3 @@
+#! /bin/bash
+
+CUDA_VISIBLE_DEVICES=0,1,2,3 python scripts/train.py --cfg configs/temporal/bin_cls/ResNet3D_c23.yaml
diff --git a/clean/video/fakestormer/scripts/train_efn.sh b/clean/video/fakestormer/scripts/train_efn.sh
new file mode 100644
index 0000000000000000000000000000000000000000..aaa8961777e33d0129939acb502a566cbc6c8f47
--- /dev/null
+++ b/clean/video/fakestormer/scripts/train_efn.sh
@@ -0,0 +1,3 @@
+#! /bin/bash
+
+CUDA_VISIBLE_DEVICES=0 python scripts/train.py --cfg configs/spatial/binary_cls/efns/efn_4.yaml
diff --git a/clean/video/fakestormer/scripts/vit_bi.sh b/clean/video/fakestormer/scripts/vit_bi.sh
new file mode 100644
index 0000000000000000000000000000000000000000..aa674fa2bc529158db29e7c8475dff953c2c97a5
--- /dev/null
+++ b/clean/video/fakestormer/scripts/vit_bi.sh
@@ -0,0 +1,4 @@
+#! /bin/bash
+
+CUDA_VISIBLE_DEVICES=0,1,2,3 python scripts/train.py --cfg configs/spatial/vit_bi_small.yaml
+# CUDA_VISIBLE_DEVICES=0,1,2,3 python scripts/train.py --cfg configs/spatial/vit_sbi_large.yaml
diff --git a/clean/video/fakestormer/scripts/vit_sbi.sh b/clean/video/fakestormer/scripts/vit_sbi.sh
new file mode 100644
index 0000000000000000000000000000000000000000..2dccd0f9ef3cf1da14918a34afafbb2768431291
--- /dev/null
+++ b/clean/video/fakestormer/scripts/vit_sbi.sh
@@ -0,0 +1,5 @@
+#! /bin/bash
+
+CUDA_VISIBLE_DEVICES=0,1,2,3 python scripts/train.py --cfg configs/spatial/vit_sbi_small.yaml
+# CUDA_VISIBLE_DEVICES=0,1,2,3 python scripts/train.py --cfg configs/spatial/vit_sbi_base.yaml
+# CUDA_VISIBLE_DEVICES=0,1,2,3 python scripts/train.py --cfg configs/spatial/vit_sbi_large.yaml
diff --git a/clean/video/lipfd/.gitignore b/clean/video/lipfd/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..dd38aff5c46b6896f9d002d19dabd7b472e9fa6b
--- /dev/null
+++ b/clean/video/lipfd/.gitignore
@@ -0,0 +1,3 @@
+.DS_Store
+__pycache__
+.vscode/
diff --git a/clean/video/lipfd/README.md b/clean/video/lipfd/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..6148c630175fda0c4304a703d866bb895b228266
--- /dev/null
+++ b/clean/video/lipfd/README.md
@@ -0,0 +1,127 @@
+# [NeruIPS 2024] Lips Are Lying: Spotting the Temporal Inconsistency between Audio and Visual in Lip-syncing DeepFakes
+
+
+
+
+
+
+
+
+> **Abstract.** In recent years, DeepFake technology has achieved unprecedented success in high-quality video synthesis, but these methods also pose potential and severe security threats to humanity. DeepFake can be bifurcated into entertainment applications like face swapping and illicit uses such as lip-syncing fraud. However, lip-forgery videos, which neither change identity nor have discernible visual artifacts, present a formidable challenge to existing DeepFake detection methods. Our preliminary experiments have shown that the effectiveness of the existing methods often drastically decrease or even fail when tackling lip-syncing videos.
+> In this paper, for the first time, we propose a novel approach dedicated to lip-forgery identification that exploits the inconsistency between lip movements and audio signals. We also mimic human natural cognition by capturing subtle biological links between lips and head regions to boost accuracy. To better illustrate the effectiveness and advances of our proposed method, we create a high-quality LipSync dataset, AVLips, by employing the state-of-the-art lip generators. We hope this high-quality and diverse dataset could be well served the further research on this challenging and interesting field. Experimental results show that our approach gives an average accuracy of more than 95.3% in spotting lip-syncing videos, significantly outperforming the baselines. Extensive experiments demonstrate the capability to tackle deepfakes and the robustness in surviving diverse input transformations. Our method achieves an accuracy of up to 90.2% in real-world scenarios (e.g., WeChat video call) and shows its powerful capabilities in real scenario deployment.
+
+
+
+
+
+## 🔥 AVLips: A high-quality audio-visual dataset for LipSync detection
+
+To the best of our knowledge, the majority of public DeepFake datasets consist solely of videos or images, with no specialized one specifically dedicated to LipSync detection available. To fill this gap, we construct a high-quality **A**udio-**V**isual **Lip**-syncing Dataset, **AVLips**, which contains up to 340,000 audio-visual samples generated by several SOTA LipSync methods. The workflow is demonstrated below.
+
+**High quality.** We employed a combination of static MakeItTalk and dynamic Wav2Lip, TalkLip, SadTalker generation methods to simulate realistic lip movements. These methods are widely recognized as high-quality work, capable of generating high-resolution videos while ensuring accurate lip movements. We applied a noise reduction algorithm to all audio samples before synthesis to reduce irrelevant background noise, ensuring the models can focus on speech content.
+
+**Diversity.** Our dataset encompasses a wide range of scenarios, covering not only well-known public datasets but also real-world data. Our aim is for this collection to act as a catalyst for advancing real-time forgery detection. To better simulate the nuances of real-world conditions, we have employed six perturbation techniques — saturation, contrast, compression, Gaussian noise, Gaussian blur, and pixelation — at various degrees, thus ensuring the dataset's realism and practical relevance.
+
+**Download Link: [AVLips v1.0](https://drive.google.com/file/d/1fEiUo22GBSnWD7nfEwDW86Eiza-pOEJm/view?usp=share_link)**
+
+
+
+
+
+## :gear: Requirements
+
+~~~bash
+conda create -n LipFD python==3.10
+conda activate LipFD
+pip install -r requirements.txt
+~~~
+
+
+
+## :wrench: Dataset Preprocess
+
+**You can skip this section, if you only want to perform validation.**
+
+Download AVLips dataset and put it in the root directory.
+
+AVLips dataset folder structure.
+
+~~~
+AVLips
+├── 0_real
+│ ├── 0.mp4
+│ ...
+├── 1_fake
+│ ├── 0.mp4
+│ └── ...
+└── wav
+ ├── 0_real
+ │ ├── 0.wav
+ │ └── ...
+ └── 1_fake
+ ├── 0.wav
+ └── ...
+~~~
+
+Preprocess the dataset for training.
+
+~~~bash
+python preprocess.py
+~~~
+
+Preprocessed AVLips dataset folder structure.
+
+~~~bash
+datasets
+└── AVLips
+ ├── 0_real
+ │ ├── 0_0.png
+ │ └── ...
+ └── 1_fake
+ ├── 0_0.png
+ └── ...
+~~~
+
+The data sample is showed as follow, and **the fully processed dataset is approximately 60 GB.**
+
+
+
+
+
+## :tada: Validation
+
+- Download our [pertained weights](https://drive.google.com/file/d/1NPAcx0QS8N9v_9qUr-51jBaL9kGDT-cp/view?usp=share_link) and save it in to `checkpoints/ckpt.pth`.
+
+- Download [validation set](https://drive.google.com/file/d/1gZjzps5_rbr6CeBqBke8l2Gs8xXx_Ctb/view?usp=share_link) and extract it into `datasets/val`.
+
+~~~bash
+python validate.py --real_list_path ./datasets/val/0_real --fake_list_path ./datasets/val/1_fake --ckpt ./checkpoints/ckpt.pth
+~~~
+
+
+
+## :rocket: Train
+
+First, edit `--fake_list_path` and `--real_list_path` in `options/base_options.py`.
+
+Then, run `python train.py`.
+
+
+
+## :mailbox: Citation
+
+If you find this repo useful for your research, please consider citing our work:
+
+~~~
+@inproceedings{liu2024lips,
+ author = {Liu, Weifeng and She, Tianyi and Liu, Jiawei and Li, Boheng and Yao, Dongyu and Liang, Ziyou and Wang, Run},
+ booktitle = {Advances in Neural Information Processing Systems},
+ editor = {A. Globerson and L. Mackey and D. Belgrave and A. Fan and U. Paquet and J. Tomczak and C. Zhang},
+ pages = {91131--91155},
+ publisher = {Curran Associates, Inc.},
+ title = {Lips Are Lying: Spotting the Temporal Inconsistency between Audio and Visual in Lip-Syncing DeepFakes},
+ url = {https://proceedings.neurips.cc/paper_files/paper/2024/file/a5a5b0ff87c59172a13342d428b1e033-Paper-Conference.pdf},
+ volume = {37},
+ year = {2024}
+}
+~~~
\ No newline at end of file
diff --git a/clean/video/lipfd/SOURCE.md b/clean/video/lipfd/SOURCE.md
new file mode 100644
index 0000000000000000000000000000000000000000..3b752928a3588dcf3a5476f25b5453a74d4d56a2
--- /dev/null
+++ b/clean/video/lipfd/SOURCE.md
@@ -0,0 +1,17 @@
+# Source: video/lipfd
+
+| Field | Value |
+|---|---|
+| Upstream | **UNVERIFIED** -- provenance was lost when this code was vendored |
+| Paper | https://arxiv.org/abs/2401.15668 |
+| Commit SHA | **not recorded** -- the vendoring step did not preserve it |
+| Mirrored on | 2026-09-15 |
+| Upstream license | no license file present upstream (all rights reserved) |
+
+This is a **mirror**, stripped to the files needed for inference. The full
+untouched snapshot is at `archive/video__lipfd.tar.gz`.
+
+This code is the work of its original authors and is **not** covered by the
+DeepSafe project license. If you are an author and want this removed, open an
+issue on https://github.com/deepsafehq/deepsafe-bench and it will be taken down
+within 48 hours, no questions asked.
diff --git a/clean/video/lipfd/models/LipFD.py b/clean/video/lipfd/models/LipFD.py
new file mode 100644
index 0000000000000000000000000000000000000000..2a48dd37c66a28f1685b5a9940e63a7d6554e93f
--- /dev/null
+++ b/clean/video/lipfd/models/LipFD.py
@@ -0,0 +1,42 @@
+import torch
+import numpy as np
+import torch.nn as nn
+from .clip import clip
+from .region_awareness import get_backbone
+
+
+class LipFD(nn.Module):
+ def __init__(self, name, num_classes=1):
+ super(LipFD, self).__init__()
+
+ self.conv1 = nn.Conv2d(
+ 3, 3, kernel_size=5, stride=5
+ ) # (1120, 1120) -> (224, 224)
+ self.encoder, self.preprocess = clip.load(name, device="cpu")
+ self.backbone = get_backbone()
+
+ def forward(self, x, feature):
+ return self.backbone(x, feature)
+
+ def get_features(self, x):
+ x = self.conv1(x)
+ features = self.encoder.encode_image(x)
+ return features
+
+
+class RALoss(nn.Module):
+ def __init__(self):
+ super(RALoss, self).__init__()
+
+ def forward(self, alphas_max, alphas_org):
+ loss = 0.0
+ batch_size = alphas_org[0].shape[0]
+ for i in range(len(alphas_org)):
+ loss_wt = 0.0
+ for j in range(batch_size):
+ loss_wt += torch.Tensor([10]).to(alphas_max[i][j].device) / np.exp(
+ alphas_max[i][j] - alphas_org[i][j]
+ )
+ loss += loss_wt / batch_size
+ return loss
+
\ No newline at end of file
diff --git a/clean/video/lipfd/models/__init__.py b/clean/video/lipfd/models/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..3b31eb1cba9f53027652f30277634b017f7a6f68
--- /dev/null
+++ b/clean/video/lipfd/models/__init__.py
@@ -0,0 +1,28 @@
+from .clip_models import CLIPModel
+from .LipFD import LipFD, RALoss
+
+VALID_NAMES = [
+ "CLIP:ViT-B/32",
+ "CLIP:ViT-B/16",
+ "CLIP:ViT-L/14",
+]
+
+
+def get_model(name):
+ assert name in VALID_NAMES
+ if name.startswith("CLIP:"):
+ return CLIPModel(name[5:])
+ else:
+ assert False
+
+
+def build_model(transformer_name):
+ assert transformer_name in VALID_NAMES
+ if transformer_name.startswith("CLIP:"):
+ return LipFD(transformer_name[5:])
+ else:
+ assert False
+
+
+def get_loss():
+ return RALoss()
diff --git a/clean/video/lipfd/models/clip/__init__.py b/clean/video/lipfd/models/clip/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..dcc5619538c0f7c782508bdbd9587259d805e0d9
--- /dev/null
+++ b/clean/video/lipfd/models/clip/__init__.py
@@ -0,0 +1 @@
+from .clip import *
diff --git a/clean/video/lipfd/models/clip/bpe_simple_vocab_16e6.txt.gz b/clean/video/lipfd/models/clip/bpe_simple_vocab_16e6.txt.gz
new file mode 100644
index 0000000000000000000000000000000000000000..36a15856e00a06a9fbed8cdd34d2393fea4a3113
--- /dev/null
+++ b/clean/video/lipfd/models/clip/bpe_simple_vocab_16e6.txt.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:924691ac288e54409236115652ad4aa250f48203de50a9e4722a6ecd48d6804a
+size 1356917
diff --git a/clean/video/lipfd/models/clip/clip.py b/clean/video/lipfd/models/clip/clip.py
new file mode 100644
index 0000000000000000000000000000000000000000..257511e1d40c120e0d64a0f1562d44b2b8a40a17
--- /dev/null
+++ b/clean/video/lipfd/models/clip/clip.py
@@ -0,0 +1,237 @@
+import hashlib
+import os
+import urllib
+import warnings
+from typing import Any, Union, List
+from pkg_resources import packaging
+
+import torch
+from PIL import Image
+from torchvision.transforms import Compose, Resize, CenterCrop, ToTensor, Normalize
+from tqdm import tqdm
+
+from .model import build_model
+from .simple_tokenizer import SimpleTokenizer as _Tokenizer
+
+try:
+ from torchvision.transforms import InterpolationMode
+ BICUBIC = InterpolationMode.BICUBIC
+except ImportError:
+ BICUBIC = Image.BICUBIC
+
+
+if packaging.version.parse(torch.__version__) < packaging.version.parse("1.7.1"):
+ warnings.warn("PyTorch version 1.7.1 or higher is recommended")
+
+
+__all__ = ["available_models", "load", "tokenize"]
+_tokenizer = _Tokenizer()
+
+_MODELS = {
+ "RN50": "https://openaipublic.azureedge.net/clip/models/afeb0e10f9e5a86da6080e35cf09123aca3b358a0c3e3b6c78a7b63bc04b6762/RN50.pt",
+ "RN101": "https://openaipublic.azureedge.net/clip/models/8fa8567bab74a42d41c5915025a8e4538c3bdbe8804a470a72f30b0d94fab599/RN101.pt",
+ "RN50x4": "https://openaipublic.azureedge.net/clip/models/7e526bd135e493cef0776de27d5f42653e6b4c8bf9e0f653bb11773263205fdd/RN50x4.pt",
+ "RN50x16": "https://openaipublic.azureedge.net/clip/models/52378b407f34354e150460fe41077663dd5b39c54cd0bfd2b27167a4a06ec9aa/RN50x16.pt",
+ "RN50x64": "https://openaipublic.azureedge.net/clip/models/be1cfb55d75a9666199fb2206c106743da0f6468c9d327f3e0d0a543a9919d9c/RN50x64.pt",
+ "ViT-B/32": "https://openaipublic.azureedge.net/clip/models/40d365715913c9da98579312b702a82c18be219cc2a73407c4526f58eba950af/ViT-B-32.pt",
+ "ViT-B/16": "https://openaipublic.azureedge.net/clip/models/5806e77cd80f8b59890b7e101eabd078d9fb84e6937f9e85e4ecb61988df416f/ViT-B-16.pt",
+ "ViT-L/14": "https://openaipublic.azureedge.net/clip/models/b8cca3fd41ae0c99ba7e8951adf17d267cdb84cd88be6f7c2e0eca1737a03836/ViT-L-14.pt",
+ "ViT-L/14@336px": "https://openaipublic.azureedge.net/clip/models/3035c92b350959924f9f00213499208652fc7ea050643e8b385c2dac08641f02/ViT-L-14-336px.pt",
+}
+
+
+def _download(url: str, root: str):
+ os.makedirs(root, exist_ok=True)
+ filename = os.path.basename(url)
+
+ expected_sha256 = url.split("/")[-2]
+ download_target = os.path.join(root, filename)
+
+ if os.path.exists(download_target) and not os.path.isfile(download_target):
+ raise RuntimeError(f"{download_target} exists and is not a regular file")
+
+ if os.path.isfile(download_target):
+ if hashlib.sha256(open(download_target, "rb").read()).hexdigest() == expected_sha256:
+ return download_target
+ else:
+ warnings.warn(f"{download_target} exists, but the SHA256 checksum does not match; re-downloading the file")
+
+ with urllib.request.urlopen(url) as source, open(download_target, "wb") as output:
+ with tqdm(total=int(source.info().get("Content-Length")), ncols=80, unit='iB', unit_scale=True, unit_divisor=1024) as loop:
+ while True:
+ buffer = source.read(8192)
+ if not buffer:
+ break
+
+ output.write(buffer)
+ loop.update(len(buffer))
+
+ if hashlib.sha256(open(download_target, "rb").read()).hexdigest() != expected_sha256:
+ raise RuntimeError("Model has been downloaded but the SHA256 checksum does not not match")
+
+ return download_target
+
+
+def _convert_image_to_rgb(image):
+ return image.convert("RGB")
+
+
+def _transform(n_px):
+ return Compose([
+ Resize(n_px, interpolation=BICUBIC),
+ CenterCrop(n_px),
+ _convert_image_to_rgb,
+ ToTensor(),
+ Normalize((0.48145466, 0.4578275, 0.40821073), (0.26862954, 0.26130258, 0.27577711)),
+ ])
+
+
+def available_models() -> List[str]:
+ """Returns the names of available CLIP models"""
+ return list(_MODELS.keys())
+
+
+def load(name: str, device: Union[str, torch.device] = "cuda" if torch.cuda.is_available() else "cpu", jit: bool = False, download_root: str = None):
+ """Load a CLIP model
+
+ Parameters
+ ----------
+ name : str
+ A model name listed by `clip.available_models()`, or the path to a model checkpoint containing the state_dict
+
+ device : Union[str, torch.device]
+ The device to put the loaded model
+
+ jit : bool
+ Whether to load the optimized JIT model or more hackable non-JIT model (default).
+
+ download_root: str
+ path to download the model files; by default, it uses "~/.cache/clip"
+
+ Returns
+ -------
+ model : torch.nn.Module
+ The CLIP model
+
+ preprocess : Callable[[PIL.Image], torch.Tensor]
+ A torchvision transform that converts a PIL image into a tensor that the returned model can take as its input
+ """
+ if name in _MODELS:
+ model_path = _download(_MODELS[name], download_root or os.path.expanduser("~/.cache/clip"))
+ elif os.path.isfile(name):
+ model_path = name
+ else:
+ raise RuntimeError(f"Model {name} not found; available models = {available_models()}")
+
+ with open(model_path, 'rb') as opened_file:
+ try:
+ # loading JIT archive
+ model = torch.jit.load(opened_file, map_location=device if jit else "cpu").eval()
+ state_dict = None
+ except RuntimeError:
+ # loading saved state dict
+ if jit:
+ warnings.warn(f"File {model_path} is not a JIT archive. Loading as a state dict instead")
+ jit = False
+ state_dict = torch.load(opened_file, map_location="cpu")
+
+ if not jit:
+ model = build_model(state_dict or model.state_dict()).to(device)
+ if str(device) == "cpu":
+ model.float()
+ return model, _transform(model.visual.input_resolution)
+
+ # patch the device names
+ device_holder = torch.jit.trace(lambda: torch.ones([]).to(torch.device(device)), example_inputs=[])
+ device_node = [n for n in device_holder.graph.findAllNodes("prim::Constant") if "Device" in repr(n)][-1]
+
+ def patch_device(module):
+ try:
+ graphs = [module.graph] if hasattr(module, "graph") else []
+ except RuntimeError:
+ graphs = []
+
+ if hasattr(module, "forward1"):
+ graphs.append(module.forward1.graph)
+
+ for graph in graphs:
+ for node in graph.findAllNodes("prim::Constant"):
+ if "value" in node.attributeNames() and str(node["value"]).startswith("cuda"):
+ node.copyAttributes(device_node)
+
+ model.apply(patch_device)
+ patch_device(model.encode_image)
+ patch_device(model.encode_text)
+
+ # patch dtype to float32 on CPU
+ if str(device) == "cpu":
+ float_holder = torch.jit.trace(lambda: torch.ones([]).float(), example_inputs=[])
+ float_input = list(float_holder.graph.findNode("aten::to").inputs())[1]
+ float_node = float_input.node()
+
+ def patch_float(module):
+ try:
+ graphs = [module.graph] if hasattr(module, "graph") else []
+ except RuntimeError:
+ graphs = []
+
+ if hasattr(module, "forward1"):
+ graphs.append(module.forward1.graph)
+
+ for graph in graphs:
+ for node in graph.findAllNodes("aten::to"):
+ inputs = list(node.inputs())
+ for i in [1, 2]: # dtype can be the second or third argument to aten::to()
+ if inputs[i].node()["value"] == 5:
+ inputs[i].node().copyAttributes(float_node)
+
+ model.apply(patch_float)
+ patch_float(model.encode_image)
+ patch_float(model.encode_text)
+
+ model.float()
+
+ return model, _transform(model.input_resolution.item())
+
+
+def tokenize(texts: Union[str, List[str]], context_length: int = 77, truncate: bool = False) -> Union[torch.IntTensor, torch.LongTensor]:
+ """
+ Returns the tokenized representation of given input string(s)
+
+ Parameters
+ ----------
+ texts : Union[str, List[str]]
+ An input string or a list of input strings to tokenize
+
+ context_length : int
+ The context length to use; all CLIP models use 77 as the context length
+
+ truncate: bool
+ Whether to truncate the text in case its encoding is longer than the context length
+
+ Returns
+ -------
+ A two-dimensional tensor containing the resulting tokens, shape = [number of input strings, context_length].
+ We return LongTensor when torch version is <1.8.0, since older index_select requires indices to be long.
+ """
+ if isinstance(texts, str):
+ texts = [texts]
+
+ sot_token = _tokenizer.encoder["<|startoftext|>"]
+ eot_token = _tokenizer.encoder["<|endoftext|>"]
+ all_tokens = [[sot_token] + _tokenizer.encode(text) + [eot_token] for text in texts]
+ if packaging.version.parse(torch.__version__) < packaging.version.parse("1.8.0"):
+ result = torch.zeros(len(all_tokens), context_length, dtype=torch.long)
+ else:
+ result = torch.zeros(len(all_tokens), context_length, dtype=torch.int)
+
+ for i, tokens in enumerate(all_tokens):
+ if len(tokens) > context_length:
+ if truncate:
+ tokens = tokens[:context_length]
+ tokens[-1] = eot_token
+ else:
+ raise RuntimeError(f"Input {texts[i]} is too long for context length {context_length}")
+ result[i, :len(tokens)] = torch.tensor(tokens)
+
+ return result
diff --git a/clean/video/lipfd/models/clip/model.py b/clean/video/lipfd/models/clip/model.py
new file mode 100644
index 0000000000000000000000000000000000000000..c60bda69ab0d35af0b64517d32595d9c03f8721c
--- /dev/null
+++ b/clean/video/lipfd/models/clip/model.py
@@ -0,0 +1,452 @@
+from collections import OrderedDict
+from typing import Tuple, Union
+
+import numpy as np
+import torch
+import torch.nn.functional as F
+from torch import nn
+
+
+class Bottleneck(nn.Module):
+ expansion = 4
+
+ def __init__(self, inplanes, planes, stride=1):
+ super().__init__()
+
+ # all conv layers have stride 1. an avgpool is performed after the second convolution when stride > 1
+ self.conv1 = nn.Conv2d(inplanes, planes, 1, bias=False)
+ self.bn1 = nn.BatchNorm2d(planes)
+ self.relu1 = nn.ReLU(inplace=True)
+
+ self.conv2 = nn.Conv2d(planes, planes, 3, padding=1, bias=False)
+ self.bn2 = nn.BatchNorm2d(planes)
+ self.relu2 = nn.ReLU(inplace=True)
+
+ self.avgpool = nn.AvgPool2d(stride) if stride > 1 else nn.Identity()
+
+ self.conv3 = nn.Conv2d(planes, planes * self.expansion, 1, bias=False)
+ self.bn3 = nn.BatchNorm2d(planes * self.expansion)
+ self.relu3 = nn.ReLU(inplace=True)
+
+ self.downsample = None
+ self.stride = stride
+
+ if stride > 1 or inplanes != planes * Bottleneck.expansion:
+ # downsampling layer is prepended with an avgpool, and the subsequent convolution has stride 1
+ self.downsample = nn.Sequential(OrderedDict([
+ ("-1", nn.AvgPool2d(stride)),
+ ("0", nn.Conv2d(inplanes, planes * self.expansion, 1, stride=1, bias=False)),
+ ("1", nn.BatchNorm2d(planes * self.expansion))
+ ]))
+
+ def forward(self, x: torch.Tensor):
+ identity = x
+
+ out = self.relu1(self.bn1(self.conv1(x)))
+ out = self.relu2(self.bn2(self.conv2(out)))
+ out = self.avgpool(out)
+ out = self.bn3(self.conv3(out))
+
+ if self.downsample is not None:
+ identity = self.downsample(x)
+
+ out += identity
+ out = self.relu3(out)
+ return out
+
+
+class AttentionPool2d(nn.Module):
+ def __init__(self, spacial_dim: int, embed_dim: int, num_heads: int, output_dim: int = None):
+ super().__init__()
+ self.positional_embedding = nn.Parameter(torch.randn(spacial_dim ** 2 + 1, embed_dim) / embed_dim ** 0.5)
+ self.k_proj = nn.Linear(embed_dim, embed_dim)
+ self.q_proj = nn.Linear(embed_dim, embed_dim)
+ self.v_proj = nn.Linear(embed_dim, embed_dim)
+ self.c_proj = nn.Linear(embed_dim, output_dim or embed_dim)
+ self.num_heads = num_heads
+
+ def forward(self, x):
+ x = x.flatten(start_dim=2).permute(2, 0, 1) # NCHW -> (HW)NC
+ x = torch.cat([x.mean(dim=0, keepdim=True), x], dim=0) # (HW+1)NC
+ x = x + self.positional_embedding[:, None, :].to(x.dtype) # (HW+1)NC
+ x, _ = F.multi_head_attention_forward(
+ query=x[:1], key=x, value=x,
+ embed_dim_to_check=x.shape[-1],
+ num_heads=self.num_heads,
+ q_proj_weight=self.q_proj.weight,
+ k_proj_weight=self.k_proj.weight,
+ v_proj_weight=self.v_proj.weight,
+ in_proj_weight=None,
+ in_proj_bias=torch.cat([self.q_proj.bias, self.k_proj.bias, self.v_proj.bias]),
+ bias_k=None,
+ bias_v=None,
+ add_zero_attn=False,
+ dropout_p=0,
+ out_proj_weight=self.c_proj.weight,
+ out_proj_bias=self.c_proj.bias,
+ use_separate_proj_weight=True,
+ training=self.training,
+ need_weights=False
+ )
+ return x.squeeze(0)
+
+
+class ModifiedResNet(nn.Module):
+ """
+ A ResNet class that is similar to torchvision's but contains the following changes:
+ - There are now 3 "stem" convolutions as opposed to 1, with an average pool instead of a max pool.
+ - Performs anti-aliasing strided convolutions, where an avgpool is prepended to convolutions with stride > 1
+ - The final pooling layer is a QKV attention instead of an average pool
+ """
+
+ def __init__(self, layers, output_dim, heads, input_resolution=224, width=64):
+ super().__init__()
+ self.output_dim = output_dim
+ self.input_resolution = input_resolution
+
+ # the 3-layer stem
+ self.conv1 = nn.Conv2d(3, width // 2, kernel_size=3, stride=2, padding=1, bias=False)
+ self.bn1 = nn.BatchNorm2d(width // 2)
+ self.relu1 = nn.ReLU(inplace=True)
+ self.conv2 = nn.Conv2d(width // 2, width // 2, kernel_size=3, padding=1, bias=False)
+ self.bn2 = nn.BatchNorm2d(width // 2)
+ self.relu2 = nn.ReLU(inplace=True)
+ self.conv3 = nn.Conv2d(width // 2, width, kernel_size=3, padding=1, bias=False)
+ self.bn3 = nn.BatchNorm2d(width)
+ self.relu3 = nn.ReLU(inplace=True)
+ self.avgpool = nn.AvgPool2d(2)
+
+ # residual layers
+ self._inplanes = width # this is a *mutable* variable used during construction
+ self.layer1 = self._make_layer(width, layers[0])
+ self.layer2 = self._make_layer(width * 2, layers[1], stride=2)
+ self.layer3 = self._make_layer(width * 4, layers[2], stride=2)
+ self.layer4 = self._make_layer(width * 8, layers[3], stride=2)
+
+ embed_dim = width * 32 # the ResNet feature dimension
+ self.attnpool = AttentionPool2d(input_resolution // 32, embed_dim, heads, output_dim)
+
+ def _make_layer(self, planes, blocks, stride=1):
+ layers = [Bottleneck(self._inplanes, planes, stride)]
+
+ self._inplanes = planes * Bottleneck.expansion
+ for _ in range(1, blocks):
+ layers.append(Bottleneck(self._inplanes, planes))
+
+ return nn.Sequential(*layers)
+
+ def forward(self, x):
+ def stem(x):
+ x = self.relu1(self.bn1(self.conv1(x)))
+ x = self.relu2(self.bn2(self.conv2(x)))
+ x = self.relu3(self.bn3(self.conv3(x)))
+ x = self.avgpool(x)
+ return x
+
+ x = x.type(self.conv1.weight.dtype)
+ x = stem(x)
+ x = self.layer1(x)
+ x = self.layer2(x)
+ x = self.layer3(x)
+ x = self.layer4(x)
+ x = self.attnpool(x)
+
+ return x
+
+
+class LayerNorm(nn.LayerNorm):
+ """Subclass torch's LayerNorm to handle fp16."""
+
+ def forward(self, x: torch.Tensor):
+ orig_type = x.dtype
+ ret = super().forward(x.type(torch.float32))
+ return ret.type(orig_type)
+
+
+class QuickGELU(nn.Module):
+ def forward(self, x: torch.Tensor):
+ return x * torch.sigmoid(1.702 * x)
+
+
+class ResidualAttentionBlock(nn.Module):
+ def __init__(self, d_model: int, n_head: int, attn_mask: torch.Tensor = None):
+ super().__init__()
+
+ self.attn = nn.MultiheadAttention(d_model, n_head)
+ self.ln_1 = LayerNorm(d_model)
+ self.mlp = nn.Sequential(OrderedDict([
+ ("c_fc", nn.Linear(d_model, d_model * 4)),
+ ("gelu", QuickGELU()),
+ ("c_proj", nn.Linear(d_model * 4, d_model))
+ ]))
+ self.ln_2 = LayerNorm(d_model)
+ self.attn_mask = attn_mask
+
+ def attention(self, x: torch.Tensor):
+ self.attn_mask = self.attn_mask.to(dtype=x.dtype, device=x.device) if self.attn_mask is not None else None
+ return self.attn(x, x, x, need_weights=False, attn_mask=self.attn_mask)[0]
+
+ def forward(self, x: torch.Tensor):
+ x = x + self.attention(self.ln_1(x))
+ x = x + self.mlp(self.ln_2(x))
+ return x
+
+
+class Transformer(nn.Module):
+ def __init__(self, width: int, layers: int, heads: int, attn_mask: torch.Tensor = None):
+ super().__init__()
+ self.width = width
+ self.layers = layers
+ self.resblocks = nn.Sequential(*[ResidualAttentionBlock(width, heads, attn_mask) for _ in range(layers)])
+
+ def forward(self, x: torch.Tensor):
+ out = {}
+ for idx, layer in enumerate(self.resblocks.children()):
+ x = layer(x)
+ out['layer'+str(idx)] = x[0] # shape:LND. choose cls token feature
+ return out, x
+
+ # return self.resblocks(x) # This is the original code
+
+
+class VisionTransformer(nn.Module):
+ def __init__(self, input_resolution: int, patch_size: int, width: int, layers: int, heads: int, output_dim: int):
+ super().__init__()
+ self.input_resolution = input_resolution
+ self.output_dim = output_dim
+ self.conv1 = nn.Conv2d(in_channels=3, out_channels=width, kernel_size=patch_size, stride=patch_size, bias=False)
+
+ scale = width ** -0.5
+ self.class_embedding = nn.Parameter(scale * torch.randn(width))
+ self.positional_embedding = nn.Parameter(scale * torch.randn((input_resolution // patch_size) ** 2 + 1, width))
+ self.ln_pre = LayerNorm(width)
+
+ self.transformer = Transformer(width, layers, heads)
+
+ self.ln_post = LayerNorm(width)
+ self.proj = nn.Parameter(scale * torch.randn(width, output_dim))
+
+
+
+ def forward(self, x: torch.Tensor):
+ x = self.conv1(x) # shape = [*, width, grid, grid]
+ x = x.reshape(x.shape[0], x.shape[1], -1) # shape = [*, width, grid ** 2]
+ x = x.permute(0, 2, 1) # shape = [*, grid ** 2, width]
+ x = torch.cat([self.class_embedding.to(x.dtype) + torch.zeros(x.shape[0], 1, x.shape[-1], dtype=x.dtype, device=x.device), x], dim=1) # shape = [*, grid ** 2 + 1, width]
+ x = x + self.positional_embedding.to(x.dtype)
+ x = self.ln_pre(x)
+
+ x = x.permute(1, 0, 2) # NLD -> LND
+ out, x = self.transformer(x)
+ x = x.permute(1, 0, 2) # LND -> NLD
+
+ x = self.ln_post(x[:, 0, :])
+
+
+ out['before_projection'] = x
+
+ if self.proj is not None:
+ x = x @ self.proj
+ out['after_projection'] = x
+
+ # Return both intermediate features and final clip feature
+ # return out
+
+ # This only returns CLIP features
+ return x
+
+
+class CLIP(nn.Module):
+ def __init__(self,
+ embed_dim: int,
+ # vision
+ image_resolution: int,
+ vision_layers: Union[Tuple[int, int, int, int], int],
+ vision_width: int,
+ vision_patch_size: int,
+ # text
+ context_length: int,
+ vocab_size: int,
+ transformer_width: int,
+ transformer_heads: int,
+ transformer_layers: int
+ ):
+ super().__init__()
+
+ self.context_length = context_length
+
+ if isinstance(vision_layers, (tuple, list)):
+ vision_heads = vision_width * 32 // 64
+ self.visual = ModifiedResNet(
+ layers=vision_layers,
+ output_dim=embed_dim,
+ heads=vision_heads,
+ input_resolution=image_resolution,
+ width=vision_width
+ )
+ else:
+ vision_heads = vision_width // 64
+ self.visual = VisionTransformer(
+ input_resolution=image_resolution,
+ patch_size=vision_patch_size,
+ width=vision_width,
+ layers=vision_layers,
+ heads=vision_heads,
+ output_dim=embed_dim
+ )
+
+ self.transformer = Transformer(
+ width=transformer_width,
+ layers=transformer_layers,
+ heads=transformer_heads,
+ attn_mask=self.build_attention_mask()
+ )
+
+ self.vocab_size = vocab_size
+ self.token_embedding = nn.Embedding(vocab_size, transformer_width)
+ self.positional_embedding = nn.Parameter(torch.empty(self.context_length, transformer_width))
+ self.ln_final = LayerNorm(transformer_width)
+
+ self.text_projection = nn.Parameter(torch.empty(transformer_width, embed_dim))
+ self.logit_scale = nn.Parameter(torch.ones([]) * np.log(1 / 0.07))
+
+ self.initialize_parameters()
+
+ def initialize_parameters(self):
+ nn.init.normal_(self.token_embedding.weight, std=0.02)
+ nn.init.normal_(self.positional_embedding, std=0.01)
+
+ if isinstance(self.visual, ModifiedResNet):
+ if self.visual.attnpool is not None:
+ std = self.visual.attnpool.c_proj.in_features ** -0.5
+ nn.init.normal_(self.visual.attnpool.q_proj.weight, std=std)
+ nn.init.normal_(self.visual.attnpool.k_proj.weight, std=std)
+ nn.init.normal_(self.visual.attnpool.v_proj.weight, std=std)
+ nn.init.normal_(self.visual.attnpool.c_proj.weight, std=std)
+
+ for resnet_block in [self.visual.layer1, self.visual.layer2, self.visual.layer3, self.visual.layer4]:
+ for name, param in resnet_block.named_parameters():
+ if name.endswith("bn3.weight"):
+ nn.init.zeros_(param)
+
+ proj_std = (self.transformer.width ** -0.5) * ((2 * self.transformer.layers) ** -0.5)
+ attn_std = self.transformer.width ** -0.5
+ fc_std = (2 * self.transformer.width) ** -0.5
+ for block in self.transformer.resblocks:
+ nn.init.normal_(block.attn.in_proj_weight, std=attn_std)
+ nn.init.normal_(block.attn.out_proj.weight, std=proj_std)
+ nn.init.normal_(block.mlp.c_fc.weight, std=fc_std)
+ nn.init.normal_(block.mlp.c_proj.weight, std=proj_std)
+
+ if self.text_projection is not None:
+ nn.init.normal_(self.text_projection, std=self.transformer.width ** -0.5)
+
+ def build_attention_mask(self):
+ # lazily create causal attention mask, with full attention between the vision tokens
+ # pytorch uses additive attention mask; fill with -inf
+ mask = torch.empty(self.context_length, self.context_length)
+ mask.fill_(float("-inf"))
+ mask.triu_(1) # zero out the lower diagonal
+ return mask
+
+ @property
+ def dtype(self):
+ return self.visual.conv1.weight.dtype
+
+ def encode_image(self, image):
+ return self.visual(image.type(self.dtype))
+
+ def encode_text(self, text):
+ x = self.token_embedding(text).type(self.dtype) # [batch_size, n_ctx, d_model]
+
+ x = x + self.positional_embedding.type(self.dtype)
+ x = x.permute(1, 0, 2) # NLD -> LND
+ x = self.transformer(x)
+ x = x.permute(1, 0, 2) # LND -> NLD
+ x = self.ln_final(x).type(self.dtype)
+
+ # x.shape = [batch_size, n_ctx, transformer.width]
+ # take features from the eot embedding (eot_token is the highest number in each sequence)
+ x = x[torch.arange(x.shape[0]), text.argmax(dim=-1)] @ self.text_projection
+
+ return x
+
+ def forward(self, image, text):
+ image_features = self.encode_image(image)
+ text_features = self.encode_text(text)
+
+ # normalized features
+ image_features = image_features / image_features.norm(dim=1, keepdim=True)
+ text_features = text_features / text_features.norm(dim=1, keepdim=True)
+
+ # cosine similarity as logits
+ logit_scale = self.logit_scale.exp()
+ logits_per_image = logit_scale * image_features @ text_features.t()
+ logits_per_text = logits_per_image.t()
+
+ # shape = [global_batch_size, global_batch_size]
+ return logits_per_image, logits_per_text
+
+
+def convert_weights(model: nn.Module):
+ """Convert applicable model parameters to fp16"""
+
+ def _convert_weights_to_fp16(l):
+ if isinstance(l, (nn.Conv1d, nn.Conv2d, nn.Linear)):
+ l.weight.data = l.weight.data.half()
+ if l.bias is not None:
+ l.bias.data = l.bias.data.half()
+
+ if isinstance(l, nn.MultiheadAttention):
+ for attr in [*[f"{s}_proj_weight" for s in ["in", "q", "k", "v"]], "in_proj_bias", "bias_k", "bias_v"]:
+ tensor = getattr(l, attr)
+ if tensor is not None:
+ tensor.data = tensor.data.half()
+
+ for name in ["text_projection", "proj"]:
+ if hasattr(l, name):
+ attr = getattr(l, name)
+ if attr is not None:
+ attr.data = attr.data.half()
+
+ model.apply(_convert_weights_to_fp16)
+
+
+def build_model(state_dict: dict):
+ vit = "visual.proj" in state_dict
+
+ if vit:
+ vision_width = state_dict["visual.conv1.weight"].shape[0]
+ vision_layers = len([k for k in state_dict.keys() if k.startswith("visual.") and k.endswith(".attn.in_proj_weight")])
+ vision_patch_size = state_dict["visual.conv1.weight"].shape[-1]
+ grid_size = round((state_dict["visual.positional_embedding"].shape[0] - 1) ** 0.5)
+ image_resolution = vision_patch_size * grid_size
+ else:
+ counts: list = [len(set(k.split(".")[2] for k in state_dict if k.startswith(f"visual.layer{b}"))) for b in [1, 2, 3, 4]]
+ vision_layers = tuple(counts)
+ vision_width = state_dict["visual.layer1.0.conv1.weight"].shape[0]
+ output_width = round((state_dict["visual.attnpool.positional_embedding"].shape[0] - 1) ** 0.5)
+ vision_patch_size = None
+ assert output_width ** 2 + 1 == state_dict["visual.attnpool.positional_embedding"].shape[0]
+ image_resolution = output_width * 32
+
+ embed_dim = state_dict["text_projection"].shape[1]
+ context_length = state_dict["positional_embedding"].shape[0]
+ vocab_size = state_dict["token_embedding.weight"].shape[0]
+ transformer_width = state_dict["ln_final.weight"].shape[0]
+ transformer_heads = transformer_width // 64
+ transformer_layers = len(set(k.split(".")[2] for k in state_dict if k.startswith("transformer.resblocks")))
+
+ model = CLIP(
+ embed_dim,
+ image_resolution, vision_layers, vision_width, vision_patch_size,
+ context_length, vocab_size, transformer_width, transformer_heads, transformer_layers
+ )
+
+ for key in ["input_resolution", "context_length", "vocab_size"]:
+ if key in state_dict:
+ del state_dict[key]
+
+ convert_weights(model)
+ model.load_state_dict(state_dict)
+ return model.eval()
diff --git a/clean/video/lipfd/models/clip/simple_tokenizer.py b/clean/video/lipfd/models/clip/simple_tokenizer.py
new file mode 100644
index 0000000000000000000000000000000000000000..0a66286b7d5019c6e221932a813768038f839c91
--- /dev/null
+++ b/clean/video/lipfd/models/clip/simple_tokenizer.py
@@ -0,0 +1,132 @@
+import gzip
+import html
+import os
+from functools import lru_cache
+
+import ftfy
+import regex as re
+
+
+@lru_cache()
+def default_bpe():
+ return os.path.join(os.path.dirname(os.path.abspath(__file__)), "bpe_simple_vocab_16e6.txt.gz")
+
+
+@lru_cache()
+def bytes_to_unicode():
+ """
+ Returns list of utf-8 byte and a corresponding list of unicode strings.
+ The reversible bpe codes work on unicode strings.
+ This means you need a large # of unicode characters in your vocab if you want to avoid UNKs.
+ When you're at something like a 10B token dataset you end up needing around 5K for decent coverage.
+ This is a signficant percentage of your normal, say, 32K bpe vocab.
+ To avoid that, we want lookup tables between utf-8 bytes and unicode strings.
+ And avoids mapping to whitespace/control characters the bpe code barfs on.
+ """
+ bs = list(range(ord("!"), ord("~")+1))+list(range(ord("¡"), ord("¬")+1))+list(range(ord("®"), ord("ÿ")+1))
+ cs = bs[:]
+ n = 0
+ for b in range(2**8):
+ if b not in bs:
+ bs.append(b)
+ cs.append(2**8+n)
+ n += 1
+ cs = [chr(n) for n in cs]
+ return dict(zip(bs, cs))
+
+
+def get_pairs(word):
+ """Return set of symbol pairs in a word.
+ Word is represented as tuple of symbols (symbols being variable-length strings).
+ """
+ pairs = set()
+ prev_char = word[0]
+ for char in word[1:]:
+ pairs.add((prev_char, char))
+ prev_char = char
+ return pairs
+
+
+def basic_clean(text):
+ text = ftfy.fix_text(text)
+ text = html.unescape(html.unescape(text))
+ return text.strip()
+
+
+def whitespace_clean(text):
+ text = re.sub(r'\s+', ' ', text)
+ text = text.strip()
+ return text
+
+
+class SimpleTokenizer(object):
+ def __init__(self, bpe_path: str = default_bpe()):
+ self.byte_encoder = bytes_to_unicode()
+ self.byte_decoder = {v: k for k, v in self.byte_encoder.items()}
+ merges = gzip.open(bpe_path).read().decode("utf-8").split('\n')
+ merges = merges[1:49152-256-2+1]
+ merges = [tuple(merge.split()) for merge in merges]
+ vocab = list(bytes_to_unicode().values())
+ vocab = vocab + [v+'' for v in vocab]
+ for merge in merges:
+ vocab.append(''.join(merge))
+ vocab.extend(['<|startoftext|>', '<|endoftext|>'])
+ self.encoder = dict(zip(vocab, range(len(vocab))))
+ self.decoder = {v: k for k, v in self.encoder.items()}
+ self.bpe_ranks = dict(zip(merges, range(len(merges))))
+ self.cache = {'<|startoftext|>': '<|startoftext|>', '<|endoftext|>': '<|endoftext|>'}
+ self.pat = re.compile(r"""<\|startoftext\|>|<\|endoftext\|>|'s|'t|'re|'ve|'m|'ll|'d|[\p{L}]+|[\p{N}]|[^\s\p{L}\p{N}]+""", re.IGNORECASE)
+
+ def bpe(self, token):
+ if token in self.cache:
+ return self.cache[token]
+ word = tuple(token[:-1]) + ( token[-1] + '',)
+ pairs = get_pairs(word)
+
+ if not pairs:
+ return token+''
+
+ while True:
+ bigram = min(pairs, key = lambda pair: self.bpe_ranks.get(pair, float('inf')))
+ if bigram not in self.bpe_ranks:
+ break
+ first, second = bigram
+ new_word = []
+ i = 0
+ while i < len(word):
+ try:
+ j = word.index(first, i)
+ new_word.extend(word[i:j])
+ i = j
+ except:
+ new_word.extend(word[i:])
+ break
+
+ if word[i] == first and i < len(word)-1 and word[i+1] == second:
+ new_word.append(first+second)
+ i += 2
+ else:
+ new_word.append(word[i])
+ i += 1
+ new_word = tuple(new_word)
+ word = new_word
+ if len(word) == 1:
+ break
+ else:
+ pairs = get_pairs(word)
+ word = ' '.join(word)
+ self.cache[token] = word
+ return word
+
+ def encode(self, text):
+ bpe_tokens = []
+ text = whitespace_clean(basic_clean(text)).lower()
+ for token in re.findall(self.pat, text):
+ token = ''.join(self.byte_encoder[b] for b in token.encode('utf-8'))
+ bpe_tokens.extend(self.encoder[bpe_token] for bpe_token in self.bpe(token).split(' '))
+ return bpe_tokens
+
+ def decode(self, tokens):
+ text = ''.join([self.decoder[token] for token in tokens])
+ text = bytearray([self.byte_decoder[c] for c in text]).decode('utf-8', errors="replace").replace('', ' ')
+ return text
diff --git a/clean/video/lipfd/models/clip_models.py b/clean/video/lipfd/models/clip_models.py
new file mode 100644
index 0000000000000000000000000000000000000000..44de4db8ee4dd77690970fc76eb671b1b3a43882
--- /dev/null
+++ b/clean/video/lipfd/models/clip_models.py
@@ -0,0 +1,24 @@
+from .clip import clip
+from PIL import Image
+import torch.nn as nn
+
+
+CHANNELS = {
+ "RN50" : 1024,
+ "ViT-L/14" : 768
+}
+
+class CLIPModel(nn.Module):
+ def __init__(self, name, num_classes=1):
+ super(CLIPModel, self).__init__()
+
+ self.model, self.preprocess = clip.load(name, device="cpu") # self.preprecess will not be used during training, which is handled in Dataset class
+ self.fc = nn.Linear( CHANNELS[name], num_classes )
+
+
+ def forward(self, x, return_feature=False):
+ features = self.model.encode_image(x)
+ if return_feature:
+ return features
+ return self.fc(features)
+
diff --git a/clean/video/lipfd/models/region_awareness.py b/clean/video/lipfd/models/region_awareness.py
new file mode 100644
index 0000000000000000000000000000000000000000..dd9c2976ae60ba52bdd81ad92b78a15b04ab6c69
--- /dev/null
+++ b/clean/video/lipfd/models/region_awareness.py
@@ -0,0 +1,303 @@
+import torch
+from torch import Tensor
+import torch.nn as nn
+from typing import Type, Any, Callable, Union, List, Optional
+from torch.nn.functional import softmax
+
+try:
+ from torch.hub import load_state_dict_from_url
+except ImportError:
+ from torch.utils.model_zoo import load_url as load_state_dict_from_url
+
+model_urls = {
+ 'resnet18': 'https://download.pytorch.org/models/resnet18-f37072fd.pth',
+ 'resnet34': 'https://download.pytorch.org/models/resnet34-b627a593.pth',
+ 'resnet50': 'https://download.pytorch.org/models/resnet50-0676ba61.pth',
+ 'resnet101': 'https://download.pytorch.org/models/resnet101-63fe2227.pth',
+ 'resnet152': 'https://download.pytorch.org/models/resnet152-394f9c45.pth',
+ 'resnext50_32x4d': 'https://download.pytorch.org/models/resnext50_32x4d-7cdf4587.pth',
+ 'resnext101_32x8d': 'https://download.pytorch.org/models/resnext101_32x8d-8ba56ff5.pth',
+ 'wideget_backbone50_2': 'https://download.pytorch.org/models/wideget_backbone50_2-95faca4d.pth',
+ 'wideget_backbone101_2': 'https://download.pytorch.org/models/wideget_backbone101_2-32ee1156.pth',
+}
+
+
+def conv3x3(in_planes: int, out_planes: int, stride: int = 1, groups: int = 1, dilation: int = 1) -> nn.Conv2d:
+ """3x3 convolution with padding"""
+ return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,
+ padding=dilation, groups=groups, bias=False, dilation=dilation)
+
+
+def conv1x1(in_planes: int, out_planes: int, stride: int = 1) -> nn.Conv2d:
+ """1x1 convolution"""
+ return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False)
+
+
+class BasicBlock(nn.Module):
+ expansion: int = 1
+
+ def __init__(
+ self,
+ inplanes: int,
+ planes: int,
+ stride: int = 1,
+ downsample: Optional[nn.Module] = None,
+ groups: int = 1,
+ base_width: int = 64,
+ dilation: int = 1,
+ norm_layer: Optional[Callable[..., nn.Module]] = None
+ ) -> None:
+ super(BasicBlock, self).__init__()
+ if norm_layer is None:
+ norm_layer = nn.BatchNorm2d
+ if groups != 1 or base_width != 64:
+ raise ValueError('BasicBlock only supports groups=1 and base_width=64')
+ if dilation > 1:
+ raise NotImplementedError("Dilation > 1 not supported in BasicBlock")
+ # Both self.conv1 and self.downsample layers downsample the input when stride != 1
+ self.conv1 = conv3x3(inplanes, planes, stride)
+ self.bn1 = norm_layer(planes)
+ self.relu = nn.ReLU(inplace=True)
+ self.conv2 = conv3x3(planes, planes)
+ self.bn2 = norm_layer(planes)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x: Tensor) -> Tensor:
+ identity = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+
+ if self.downsample is not None:
+ identity = self.downsample(x)
+
+ out += identity
+ out = self.relu(out)
+
+ return out
+
+
+class Bottleneck(nn.Module):
+ expansion: int = 4
+
+ def __init__(
+ self,
+ inplanes: int,
+ planes: int,
+ stride: int = 1,
+ downsample: Optional[nn.Module] = None,
+ groups: int = 1,
+ base_width: int = 64,
+ dilation: int = 1,
+ norm_layer: Optional[Callable[..., nn.Module]] = None
+ ) -> None:
+ super(Bottleneck, self).__init__()
+ if norm_layer is None:
+ norm_layer = nn.BatchNorm2d
+ width = int(planes * (base_width / 64.)) * groups
+ # Both self.conv2 and self.downsample layers downsample the input when stride != 1
+ self.conv1 = conv1x1(inplanes, width)
+ self.bn1 = norm_layer(width)
+ self.conv2 = conv3x3(width, width, stride, groups, dilation)
+ self.bn2 = norm_layer(width)
+ self.conv3 = conv1x1(width, planes * self.expansion)
+ self.bn3 = norm_layer(planes * self.expansion)
+ self.relu = nn.ReLU(inplace=True)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x: Tensor) -> Tensor:
+ identity = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+ out = self.relu(out)
+
+ out = self.conv3(out)
+ out = self.bn3(out)
+
+ if self.downsample is not None:
+ identity = self.downsample(x)
+
+ out += identity
+ out = self.relu(out)
+
+ return out
+
+
+class ResNet(nn.Module):
+
+ def __init__(
+ self,
+ block: Type[Union[BasicBlock, Bottleneck]],
+ layers: List[int],
+ num_classes: int = 1000,
+ zero_init_residual: bool = False,
+ groups: int = 1,
+ width_per_group: int = 64,
+ replace_stride_with_dilation: Optional[List[bool]] = None,
+ norm_layer: Optional[Callable[..., nn.Module]] = None
+ ) -> None:
+ super(ResNet, self).__init__()
+ if norm_layer is None:
+ norm_layer = nn.BatchNorm2d
+ self._norm_layer = norm_layer
+
+ self.inplanes = 64
+ self.dilation = 1
+ if replace_stride_with_dilation is None:
+ # each element in the tuple indicates if we should replace
+ # the 2x2 stride with a dilated convolution instead
+ replace_stride_with_dilation = [False, False, False]
+ if len(replace_stride_with_dilation) != 3:
+ raise ValueError("replace_stride_with_dilation should be None "
+ "or a 3-element tuple, got {}".format(replace_stride_with_dilation))
+ self.groups = groups
+ self.base_width = width_per_group
+ self.conv1 = nn.Conv2d(3, self.inplanes, kernel_size=7, stride=2, padding=3,
+ bias=False)
+ self.bn1 = norm_layer(self.inplanes)
+ self.relu = nn.ReLU(inplace=True)
+ self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
+ self.layer1 = self._make_layer(block, 64, layers[0])
+ self.layer2 = self._make_layer(block, 128, layers[1], stride=2,
+ dilate=replace_stride_with_dilation[0])
+ self.layer3 = self._make_layer(block, 256, layers[2], stride=2,
+ dilate=replace_stride_with_dilation[1])
+ self.layer4 = self._make_layer(block, 512, layers[3], stride=2,
+ dilate=replace_stride_with_dilation[2])
+ self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
+ self.get_weight = nn.Sequential(
+ nn.Linear(512 * block.expansion + 768, 1), # TODO: 768 is the length of global feature
+ nn.Sigmoid()
+ )
+ self.fc = nn.Linear(512 * block.expansion + 768, 1)
+
+ for m in self.modules():
+ if isinstance(m, nn.Conv2d):
+ nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
+ elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
+ nn.init.constant_(m.weight, 1)
+ nn.init.constant_(m.bias, 0)
+
+ # Zero-initialize the last BN in each residual branch,
+ # so that the residual branch starts with zeros, and each residual block behaves like an identity.
+ # This improves the model by 0.2~0.3% according to https://arxiv.org/abs/1706.02677
+ if zero_init_residual:
+ for m in self.modules():
+ if isinstance(m, Bottleneck):
+ nn.init.constant_(m.bn3.weight, 0) # type: ignore[arg-type]
+ elif isinstance(m, BasicBlock):
+ nn.init.constant_(m.bn2.weight, 0) # type: ignore[arg-type]
+
+ def _make_layer(self, block: Type[Union[BasicBlock, Bottleneck]], planes: int, blocks: int,
+ stride: int = 1, dilate: bool = False) -> nn.Sequential:
+ norm_layer = self._norm_layer
+ downsample = None
+ previous_dilation = self.dilation
+ if dilate:
+ self.dilation *= stride
+ stride = 1
+ if stride != 1 or self.inplanes != planes * block.expansion:
+ downsample = nn.Sequential(
+ conv1x1(self.inplanes, planes * block.expansion, stride),
+ norm_layer(planes * block.expansion),
+ )
+
+ layers = []
+ layers.append(block(self.inplanes, planes, stride, downsample, self.groups,
+ self.base_width, previous_dilation, norm_layer))
+ self.inplanes = planes * block.expansion
+ for _ in range(1, blocks):
+ layers.append(block(self.inplanes, planes, groups=self.groups,
+ base_width=self.base_width, dilation=self.dilation,
+ norm_layer=norm_layer))
+
+ return nn.Sequential(*layers)
+
+ def _forward_impl(self, x, feature):
+ # The comment resolution is based on input size is 224*224 imagenet
+ # f.shape: (batch_size, 3, 224, 224), feature.shape: (batch_size, 768)
+ features, weights, parts, weights_org, weights_max = [list() for i in range(5)]
+ for i in range(len(x[0])):
+ features.clear()
+ weights.clear()
+ for j in range(len(x)):
+ f = x[j][i]
+ f = self.conv1(f)
+ f = self.bn1(f)
+ f = self.relu(f)
+ f = self.maxpool(f)
+ f = self.layer1(f)
+ f = self.layer2(f)
+ f = self.layer3(f)
+ f = self.layer4(f)
+ f = self.avgpool(f)
+ f = torch.flatten(f, 1)
+
+ # features.append(f)
+ features.append(torch.cat([f, feature], dim=1)) # concat regional feature with global feature
+ weights.append(self.get_weight(features[-1]))
+
+ features_stack = torch.stack(features, dim=2)
+ weights_stack = torch.stack(weights, dim=2)
+ weights_stack = softmax(weights_stack, dim=2)
+
+ weights_max.append(weights_stack[:, :, :len(x)].max(dim=2)[0])
+ weights_org.append(weights_stack[:, :, 0])
+ parts.append(features_stack.mul(weights_stack).sum(2).div(weights_stack.sum(2)))
+ parts_stack = torch.stack(parts, dim=0)
+ out = parts_stack.sum(0).div(parts_stack.shape[0])
+
+ pred_score = self.fc(out)
+
+ return pred_score, weights_max, weights_org
+
+ def forward(self, x, feature):
+ return self._forward_impl(x, feature)
+
+
+def _get_backbone(
+ arch: str,
+ block: Type[Union[BasicBlock, Bottleneck]],
+ layers: List[int],
+ pretrained: bool,
+ progress: bool,
+ **kwargs: Any
+) -> ResNet:
+ model = ResNet(block, layers, num_classes=1, **kwargs)
+ if pretrained:
+ state_dict = load_state_dict_from_url(model_urls[arch], progress=progress)
+ model.load_state_dict(state_dict)
+ return model
+
+
+def get_backbone(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> ResNet:
+ r"""ResNet-50 model from
+ `"Deep Residual Learning for Image Recognition" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return _get_backbone('resnet50', Bottleneck, [3, 4, 6, 3], pretrained, progress, **kwargs)
+
+
+if __name__ == '__main__':
+ model = get_backbone()
+ data = [[] for i in range(3)]
+ for i in range(3):
+ for j in range(5):
+ data[i].append(torch.rand((10, 3, 224, 224)))
+ feature = torch.rand((10, 768))
+ pred_score, weights_max, weights_org = model(data, feature)
+ pass
diff --git a/clean/video/lipfd/models/resnet.py b/clean/video/lipfd/models/resnet.py
new file mode 100644
index 0000000000000000000000000000000000000000..f1bc92c02bab14e7a12ee47b12c789e88694b1a5
--- /dev/null
+++ b/clean/video/lipfd/models/resnet.py
@@ -0,0 +1,336 @@
+import torch
+from torch import Tensor
+import torch.nn as nn
+from typing import Type, Any, Callable, Union, List, Optional
+
+try:
+ from torch.hub import load_state_dict_from_url
+except ImportError:
+ from torch.utils.model_zoo import load_url as load_state_dict_from_url
+
+
+model_urls = {
+ 'resnet18': 'https://download.pytorch.org/models/resnet18-f37072fd.pth',
+ 'resnet34': 'https://download.pytorch.org/models/resnet34-b627a593.pth',
+ 'resnet50': 'https://download.pytorch.org/models/resnet50-0676ba61.pth',
+ 'resnet101': 'https://download.pytorch.org/models/resnet101-63fe2227.pth',
+ 'resnet152': 'https://download.pytorch.org/models/resnet152-394f9c45.pth',
+ 'resnext50_32x4d': 'https://download.pytorch.org/models/resnext50_32x4d-7cdf4587.pth',
+ 'resnext101_32x8d': 'https://download.pytorch.org/models/resnext101_32x8d-8ba56ff5.pth',
+ 'wide_resnet50_2': 'https://download.pytorch.org/models/wide_resnet50_2-95faca4d.pth',
+ 'wide_resnet101_2': 'https://download.pytorch.org/models/wide_resnet101_2-32ee1156.pth',
+}
+
+
+
+
+def conv3x3(in_planes: int, out_planes: int, stride: int = 1, groups: int = 1, dilation: int = 1) -> nn.Conv2d:
+ """3x3 convolution with padding"""
+ return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,
+ padding=dilation, groups=groups, bias=False, dilation=dilation)
+
+
+def conv1x1(in_planes: int, out_planes: int, stride: int = 1) -> nn.Conv2d:
+ """1x1 convolution"""
+ return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False)
+
+
+class BasicBlock(nn.Module):
+ expansion: int = 1
+
+ def __init__(
+ self,
+ inplanes: int,
+ planes: int,
+ stride: int = 1,
+ downsample: Optional[nn.Module] = None,
+ groups: int = 1,
+ base_width: int = 64,
+ dilation: int = 1,
+ norm_layer: Optional[Callable[..., nn.Module]] = None
+ ) -> None:
+ super(BasicBlock, self).__init__()
+ if norm_layer is None:
+ norm_layer = nn.BatchNorm2d
+ if groups != 1 or base_width != 64:
+ raise ValueError('BasicBlock only supports groups=1 and base_width=64')
+ if dilation > 1:
+ raise NotImplementedError("Dilation > 1 not supported in BasicBlock")
+ # Both self.conv1 and self.downsample layers downsample the input when stride != 1
+ self.conv1 = conv3x3(inplanes, planes, stride)
+ self.bn1 = norm_layer(planes)
+ self.relu = nn.ReLU(inplace=True)
+ self.conv2 = conv3x3(planes, planes)
+ self.bn2 = norm_layer(planes)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x: Tensor) -> Tensor:
+ identity = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+
+ if self.downsample is not None:
+ identity = self.downsample(x)
+
+ out += identity
+ out = self.relu(out)
+
+ return out
+
+
+class Bottleneck(nn.Module):
+ # Bottleneck in torchvision places the stride for downsampling at 3x3 convolution(self.conv2)
+ # while original implementation places the stride at the first 1x1 convolution(self.conv1)
+ # according to "Deep residual learning for image recognition"https://arxiv.org/abs/1512.03385.
+ # This variant is also known as ResNet V1.5 and improves accuracy according to
+ # https://ngc.nvidia.com/catalog/model-scripts/nvidia:resnet_50_v1_5_for_pytorch.
+
+ expansion: int = 4
+
+ def __init__(
+ self,
+ inplanes: int,
+ planes: int,
+ stride: int = 1,
+ downsample: Optional[nn.Module] = None,
+ groups: int = 1,
+ base_width: int = 64,
+ dilation: int = 1,
+ norm_layer: Optional[Callable[..., nn.Module]] = None
+ ) -> None:
+ super(Bottleneck, self).__init__()
+ if norm_layer is None:
+ norm_layer = nn.BatchNorm2d
+ width = int(planes * (base_width / 64.)) * groups
+ # Both self.conv2 and self.downsample layers downsample the input when stride != 1
+ self.conv1 = conv1x1(inplanes, width)
+ self.bn1 = norm_layer(width)
+ self.conv2 = conv3x3(width, width, stride, groups, dilation)
+ self.bn2 = norm_layer(width)
+ self.conv3 = conv1x1(width, planes * self.expansion)
+ self.bn3 = norm_layer(planes * self.expansion)
+ self.relu = nn.ReLU(inplace=True)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x: Tensor) -> Tensor:
+ identity = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+ out = self.relu(out)
+
+ out = self.conv3(out)
+ out = self.bn3(out)
+
+ if self.downsample is not None:
+ identity = self.downsample(x)
+
+ out += identity
+ out = self.relu(out)
+
+ return out
+
+
+class ResNet(nn.Module):
+
+ def __init__(
+ self,
+ block: Type[Union[BasicBlock, Bottleneck]],
+ layers: List[int],
+ num_classes: int = 1000,
+ zero_init_residual: bool = False,
+ groups: int = 1,
+ width_per_group: int = 64,
+ replace_stride_with_dilation: Optional[List[bool]] = None,
+ norm_layer: Optional[Callable[..., nn.Module]] = None
+ ) -> None:
+ super(ResNet, self).__init__()
+ if norm_layer is None:
+ norm_layer = nn.BatchNorm2d
+ self._norm_layer = norm_layer
+
+ self.inplanes = 64
+ self.dilation = 1
+ if replace_stride_with_dilation is None:
+ # each element in the tuple indicates if we should replace
+ # the 2x2 stride with a dilated convolution instead
+ replace_stride_with_dilation = [False, False, False]
+ if len(replace_stride_with_dilation) != 3:
+ raise ValueError("replace_stride_with_dilation should be None "
+ "or a 3-element tuple, got {}".format(replace_stride_with_dilation))
+ self.groups = groups
+ self.base_width = width_per_group
+ self.conv1 = nn.Conv2d(3, self.inplanes, kernel_size=7, stride=2, padding=3,
+ bias=False)
+ self.bn1 = norm_layer(self.inplanes)
+ self.relu = nn.ReLU(inplace=True)
+ self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
+ self.layer1 = self._make_layer(block, 64, layers[0])
+ self.layer2 = self._make_layer(block, 128, layers[1], stride=2,
+ dilate=replace_stride_with_dilation[0])
+ self.layer3 = self._make_layer(block, 256, layers[2], stride=2,
+ dilate=replace_stride_with_dilation[1])
+ self.layer4 = self._make_layer(block, 512, layers[3], stride=2,
+ dilate=replace_stride_with_dilation[2])
+ self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
+ self.fc = nn.Linear(512 * block.expansion, num_classes)
+
+ for m in self.modules():
+ if isinstance(m, nn.Conv2d):
+ nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
+ elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
+ nn.init.constant_(m.weight, 1)
+ nn.init.constant_(m.bias, 0)
+
+ # Zero-initialize the last BN in each residual branch,
+ # so that the residual branch starts with zeros, and each residual block behaves like an identity.
+ # This improves the model by 0.2~0.3% according to https://arxiv.org/abs/1706.02677
+ if zero_init_residual:
+ for m in self.modules():
+ if isinstance(m, Bottleneck):
+ nn.init.constant_(m.bn3.weight, 0) # type: ignore[arg-type]
+ elif isinstance(m, BasicBlock):
+ nn.init.constant_(m.bn2.weight, 0) # type: ignore[arg-type]
+
+ def _make_layer(self, block: Type[Union[BasicBlock, Bottleneck]], planes: int, blocks: int,
+ stride: int = 1, dilate: bool = False) -> nn.Sequential:
+ norm_layer = self._norm_layer
+ downsample = None
+ previous_dilation = self.dilation
+ if dilate:
+ self.dilation *= stride
+ stride = 1
+ if stride != 1 or self.inplanes != planes * block.expansion:
+ downsample = nn.Sequential(
+ conv1x1(self.inplanes, planes * block.expansion, stride),
+ norm_layer(planes * block.expansion),
+ )
+
+ layers = []
+ layers.append(block(self.inplanes, planes, stride, downsample, self.groups,
+ self.base_width, previous_dilation, norm_layer))
+ self.inplanes = planes * block.expansion
+ for _ in range(1, blocks):
+ layers.append(block(self.inplanes, planes, groups=self.groups,
+ base_width=self.base_width, dilation=self.dilation,
+ norm_layer=norm_layer))
+
+ return nn.Sequential(*layers)
+
+ def _forward_impl(self, x):
+ # The comment resolution is based on input size is 224*224 imagenet
+ out = {}
+ x = self.conv1(x)
+ x = self.bn1(x)
+ x = self.relu(x)
+ x = self.maxpool(x)
+ out['f0'] = x # N*64*56*56
+
+ x = self.layer1(x)
+ out['f1'] = x # N*64*56*56
+
+ x = self.layer2(x)
+ out['f2'] = x # N*128*28*28
+
+ x = self.layer3(x)
+ out['f3'] = x # N*256*14*14
+
+ x = self.layer4(x)
+ out['f4'] = x # N*512*7*7
+
+ x = self.avgpool(x)
+ x = torch.flatten(x, 1)
+ out['penultimate'] = x # N*512
+
+ x = self.fc(x)
+ out['logits'] = x # N*1000
+
+ # return all features
+ return out
+
+ # return final classification result
+ # return x
+
+ def forward(self, x):
+ return self._forward_impl(x)
+
+
+def _resnet(
+ arch: str,
+ block: Type[Union[BasicBlock, Bottleneck]],
+ layers: List[int],
+ pretrained: bool,
+ progress: bool,
+ **kwargs: Any
+) -> ResNet:
+ model = ResNet(block, layers, **kwargs)
+ if pretrained:
+ state_dict = load_state_dict_from_url(model_urls[arch], progress=progress)
+ model.load_state_dict(state_dict)
+ return model
+
+
+def resnet18(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> ResNet:
+ r"""ResNet-18 model from
+ `"Deep Residual Learning for Image Recognition" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return _resnet('resnet18', BasicBlock, [2, 2, 2, 2], pretrained, progress, **kwargs)
+
+
+def resnet34(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> ResNet:
+ r"""ResNet-34 model from
+ `"Deep Residual Learning for Image Recognition" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return _resnet('resnet34', BasicBlock, [3, 4, 6, 3], pretrained, progress, **kwargs)
+
+
+def resnet50(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> ResNet:
+ r"""ResNet-50 model from
+ `"Deep Residual Learning for Image Recognition" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return _resnet('resnet50', Bottleneck, [3, 4, 6, 3], pretrained, progress, **kwargs)
+
+
+def resnet101(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> ResNet:
+ r"""ResNet-101 model from
+ `"Deep Residual Learning for Image Recognition" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return _resnet('resnet101', Bottleneck, [3, 4, 23, 3], pretrained, progress, **kwargs)
+
+
+def resnet152(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> ResNet:
+ r"""ResNet-152 model from
+ `"Deep Residual Learning for Image Recognition" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return _resnet('resnet152', Bottleneck, [3, 8, 36, 3], pretrained, progress, **kwargs)
diff --git a/clean/video/lipfd/models/vision_transformer.py b/clean/video/lipfd/models/vision_transformer.py
new file mode 100644
index 0000000000000000000000000000000000000000..618e9626ca43f1afdb3419e19be11f3a3048f81e
--- /dev/null
+++ b/clean/video/lipfd/models/vision_transformer.py
@@ -0,0 +1,481 @@
+import math
+from collections import OrderedDict
+from functools import partial
+from typing import Any, Callable, List, NamedTuple, Optional
+
+import torch
+import torch.nn as nn
+
+# from .._internally_replaced_utils import load_state_dict_from_url
+from .vision_transformer_misc import ConvNormActivation
+from .vision_transformer_utils import _log_api_usage_once
+
+try:
+ from torch.hub import load_state_dict_from_url
+except ImportError:
+ from torch.utils.model_zoo import load_url as load_state_dict_from_url
+
+# __all__ = [
+# "VisionTransformer",
+# "vit_b_16",
+# "vit_b_32",
+# "vit_l_16",
+# "vit_l_32",
+# ]
+
+model_urls = {
+ "vit_b_16": "https://download.pytorch.org/models/vit_b_16-c867db91.pth",
+ "vit_b_32": "https://download.pytorch.org/models/vit_b_32-d86f8d99.pth",
+ "vit_l_16": "https://download.pytorch.org/models/vit_l_16-852ce7e3.pth",
+ "vit_l_32": "https://download.pytorch.org/models/vit_l_32-c7638314.pth",
+}
+
+
+class ConvStemConfig(NamedTuple):
+ out_channels: int
+ kernel_size: int
+ stride: int
+ norm_layer: Callable[..., nn.Module] = nn.BatchNorm2d
+ activation_layer: Callable[..., nn.Module] = nn.ReLU
+
+
+class MLPBlock(nn.Sequential):
+ """Transformer MLP block."""
+
+ def __init__(self, in_dim: int, mlp_dim: int, dropout: float):
+ super().__init__()
+ self.linear_1 = nn.Linear(in_dim, mlp_dim)
+ self.act = nn.GELU()
+ self.dropout_1 = nn.Dropout(dropout)
+ self.linear_2 = nn.Linear(mlp_dim, in_dim)
+ self.dropout_2 = nn.Dropout(dropout)
+
+ nn.init.xavier_uniform_(self.linear_1.weight)
+ nn.init.xavier_uniform_(self.linear_2.weight)
+ nn.init.normal_(self.linear_1.bias, std=1e-6)
+ nn.init.normal_(self.linear_2.bias, std=1e-6)
+
+
+class EncoderBlock(nn.Module):
+ """Transformer encoder block."""
+
+ def __init__(
+ self,
+ num_heads: int,
+ hidden_dim: int,
+ mlp_dim: int,
+ dropout: float,
+ attention_dropout: float,
+ norm_layer: Callable[..., torch.nn.Module] = partial(nn.LayerNorm, eps=1e-6),
+ ):
+ super().__init__()
+ self.num_heads = num_heads
+
+ # Attention block
+ self.ln_1 = norm_layer(hidden_dim)
+ self.self_attention = nn.MultiheadAttention(hidden_dim, num_heads, dropout=attention_dropout, batch_first=True)
+ self.dropout = nn.Dropout(dropout)
+
+ # MLP block
+ self.ln_2 = norm_layer(hidden_dim)
+ self.mlp = MLPBlock(hidden_dim, mlp_dim, dropout)
+
+ def forward(self, input: torch.Tensor):
+ torch._assert(input.dim() == 3, f"Expected (seq_length, batch_size, hidden_dim) got {input.shape}")
+ x = self.ln_1(input)
+ x, _ = self.self_attention(query=x, key=x, value=x, need_weights=False)
+ x = self.dropout(x)
+ x = x + input
+
+ y = self.ln_2(x)
+ y = self.mlp(y)
+ return x + y
+
+
+class Encoder(nn.Module):
+ """Transformer Model Encoder for sequence to sequence translation."""
+
+ def __init__(
+ self,
+ seq_length: int,
+ num_layers: int,
+ num_heads: int,
+ hidden_dim: int,
+ mlp_dim: int,
+ dropout: float,
+ attention_dropout: float,
+ norm_layer: Callable[..., torch.nn.Module] = partial(nn.LayerNorm, eps=1e-6),
+ ):
+ super().__init__()
+ # Note that batch_size is on the first dim because
+ # we have batch_first=True in nn.MultiAttention() by default
+ self.pos_embedding = nn.Parameter(torch.empty(1, seq_length, hidden_dim).normal_(std=0.02)) # from BERT
+ self.dropout = nn.Dropout(dropout)
+ layers: OrderedDict[str, nn.Module] = OrderedDict()
+ for i in range(num_layers):
+ layers[f"encoder_layer_{i}"] = EncoderBlock(
+ num_heads,
+ hidden_dim,
+ mlp_dim,
+ dropout,
+ attention_dropout,
+ norm_layer,
+ )
+ self.layers = nn.Sequential(layers)
+ self.ln = norm_layer(hidden_dim)
+
+ def forward(self, input: torch.Tensor):
+ torch._assert(input.dim() == 3, f"Expected (batch_size, seq_length, hidden_dim) got {input.shape}")
+ input = input + self.pos_embedding
+ return self.ln(self.layers(self.dropout(input)))
+
+
+class VisionTransformer(nn.Module):
+ """Vision Transformer as per https://arxiv.org/abs/2010.11929."""
+
+ def __init__(
+ self,
+ image_size: int,
+ patch_size: int,
+ num_layers: int,
+ num_heads: int,
+ hidden_dim: int,
+ mlp_dim: int,
+ dropout: float = 0.0,
+ attention_dropout: float = 0.0,
+ num_classes: int = 1000,
+ representation_size: Optional[int] = None,
+ norm_layer: Callable[..., torch.nn.Module] = partial(nn.LayerNorm, eps=1e-6),
+ conv_stem_configs: Optional[List[ConvStemConfig]] = None,
+ ):
+ super().__init__()
+ _log_api_usage_once(self)
+ torch._assert(image_size % patch_size == 0, "Input shape indivisible by patch size!")
+ self.image_size = image_size
+ self.patch_size = patch_size
+ self.hidden_dim = hidden_dim
+ self.mlp_dim = mlp_dim
+ self.attention_dropout = attention_dropout
+ self.dropout = dropout
+ self.num_classes = num_classes
+ self.representation_size = representation_size
+ self.norm_layer = norm_layer
+
+ if conv_stem_configs is not None:
+ # As per https://arxiv.org/abs/2106.14881
+ seq_proj = nn.Sequential()
+ prev_channels = 3
+ for i, conv_stem_layer_config in enumerate(conv_stem_configs):
+ seq_proj.add_module(
+ f"conv_bn_relu_{i}",
+ ConvNormActivation(
+ in_channels=prev_channels,
+ out_channels=conv_stem_layer_config.out_channels,
+ kernel_size=conv_stem_layer_config.kernel_size,
+ stride=conv_stem_layer_config.stride,
+ norm_layer=conv_stem_layer_config.norm_layer,
+ activation_layer=conv_stem_layer_config.activation_layer,
+ ),
+ )
+ prev_channels = conv_stem_layer_config.out_channels
+ seq_proj.add_module(
+ "conv_last", nn.Conv2d(in_channels=prev_channels, out_channels=hidden_dim, kernel_size=1)
+ )
+ self.conv_proj: nn.Module = seq_proj
+ else:
+ self.conv_proj = nn.Conv2d(
+ in_channels=3, out_channels=hidden_dim, kernel_size=patch_size, stride=patch_size
+ )
+
+ seq_length = (image_size // patch_size) ** 2
+
+ # Add a class token
+ self.class_token = nn.Parameter(torch.zeros(1, 1, hidden_dim))
+ seq_length += 1
+
+ self.encoder = Encoder(
+ seq_length,
+ num_layers,
+ num_heads,
+ hidden_dim,
+ mlp_dim,
+ dropout,
+ attention_dropout,
+ norm_layer,
+ )
+ self.seq_length = seq_length
+
+ heads_layers: OrderedDict[str, nn.Module] = OrderedDict()
+ if representation_size is None:
+ heads_layers["head"] = nn.Linear(hidden_dim, num_classes)
+ else:
+ heads_layers["pre_logits"] = nn.Linear(hidden_dim, representation_size)
+ heads_layers["act"] = nn.Tanh()
+ heads_layers["head"] = nn.Linear(representation_size, num_classes)
+
+ self.heads = nn.Sequential(heads_layers)
+
+ if isinstance(self.conv_proj, nn.Conv2d):
+ # Init the patchify stem
+ fan_in = self.conv_proj.in_channels * self.conv_proj.kernel_size[0] * self.conv_proj.kernel_size[1]
+ nn.init.trunc_normal_(self.conv_proj.weight, std=math.sqrt(1 / fan_in))
+ if self.conv_proj.bias is not None:
+ nn.init.zeros_(self.conv_proj.bias)
+ elif self.conv_proj.conv_last is not None and isinstance(self.conv_proj.conv_last, nn.Conv2d):
+ # Init the last 1x1 conv of the conv stem
+ nn.init.normal_(
+ self.conv_proj.conv_last.weight, mean=0.0, std=math.sqrt(2.0 / self.conv_proj.conv_last.out_channels)
+ )
+ if self.conv_proj.conv_last.bias is not None:
+ nn.init.zeros_(self.conv_proj.conv_last.bias)
+
+ if hasattr(self.heads, "pre_logits") and isinstance(self.heads.pre_logits, nn.Linear):
+ fan_in = self.heads.pre_logits.in_features
+ nn.init.trunc_normal_(self.heads.pre_logits.weight, std=math.sqrt(1 / fan_in))
+ nn.init.zeros_(self.heads.pre_logits.bias)
+
+ if isinstance(self.heads.head, nn.Linear):
+ nn.init.zeros_(self.heads.head.weight)
+ nn.init.zeros_(self.heads.head.bias)
+
+ def _process_input(self, x: torch.Tensor) -> torch.Tensor:
+ n, c, h, w = x.shape
+ p = self.patch_size
+ torch._assert(h == self.image_size, "Wrong image height!")
+ torch._assert(w == self.image_size, "Wrong image width!")
+ n_h = h // p
+ n_w = w // p
+
+ # (n, c, h, w) -> (n, hidden_dim, n_h, n_w)
+ x = self.conv_proj(x)
+ # (n, hidden_dim, n_h, n_w) -> (n, hidden_dim, (n_h * n_w))
+ x = x.reshape(n, self.hidden_dim, n_h * n_w)
+
+ # (n, hidden_dim, (n_h * n_w)) -> (n, (n_h * n_w), hidden_dim)
+ # The self attention layer expects inputs in the format (N, S, E)
+ # where S is the source sequence length, N is the batch size, E is the
+ # embedding dimension
+ x = x.permute(0, 2, 1)
+
+ return x
+
+ def forward(self, x: torch.Tensor):
+ out = {}
+
+ # Reshape and permute the input tensor
+ x = self._process_input(x)
+ n = x.shape[0]
+
+ # Expand the class token to the full batch
+ batch_class_token = self.class_token.expand(n, -1, -1)
+ x = torch.cat([batch_class_token, x], dim=1)
+
+
+ x = self.encoder(x)
+ img_feature = x[:,1:]
+ H = W = int(self.image_size / self.patch_size)
+ out['f4'] = img_feature.view(n, H, W, self.hidden_dim).permute(0,3,1,2)
+
+ # Classifier "token" as used by standard language architectures
+ x = x[:, 0]
+ out['penultimate'] = x
+
+ x = self.heads(x) # I checked that for all pretrained ViT, this is just a fc
+ out['logits'] = x
+
+ return out
+
+
+def _vision_transformer(
+ arch: str,
+ patch_size: int,
+ num_layers: int,
+ num_heads: int,
+ hidden_dim: int,
+ mlp_dim: int,
+ pretrained: bool,
+ progress: bool,
+ **kwargs: Any,
+) -> VisionTransformer:
+ image_size = kwargs.pop("image_size", 224)
+
+ model = VisionTransformer(
+ image_size=image_size,
+ patch_size=patch_size,
+ num_layers=num_layers,
+ num_heads=num_heads,
+ hidden_dim=hidden_dim,
+ mlp_dim=mlp_dim,
+ **kwargs,
+ )
+
+ if pretrained:
+ if arch not in model_urls:
+ raise ValueError(f"No checkpoint is available for model type '{arch}'!")
+ state_dict = load_state_dict_from_url(model_urls[arch], progress=progress)
+ model.load_state_dict(state_dict)
+
+ return model
+
+
+def vit_b_16(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> VisionTransformer:
+ """
+ Constructs a vit_b_16 architecture from
+ `"An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return _vision_transformer(
+ arch="vit_b_16",
+ patch_size=16,
+ num_layers=12,
+ num_heads=12,
+ hidden_dim=768,
+ mlp_dim=3072,
+ pretrained=pretrained,
+ progress=progress,
+ **kwargs,
+ )
+
+
+def vit_b_32(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> VisionTransformer:
+ """
+ Constructs a vit_b_32 architecture from
+ `"An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return _vision_transformer(
+ arch="vit_b_32",
+ patch_size=32,
+ num_layers=12,
+ num_heads=12,
+ hidden_dim=768,
+ mlp_dim=3072,
+ pretrained=pretrained,
+ progress=progress,
+ **kwargs,
+ )
+
+
+def vit_l_16(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> VisionTransformer:
+ """
+ Constructs a vit_l_16 architecture from
+ `"An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return _vision_transformer(
+ arch="vit_l_16",
+ patch_size=16,
+ num_layers=24,
+ num_heads=16,
+ hidden_dim=1024,
+ mlp_dim=4096,
+ pretrained=pretrained,
+ progress=progress,
+ **kwargs,
+ )
+
+
+def vit_l_32(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> VisionTransformer:
+ """
+ Constructs a vit_l_32 architecture from
+ `"An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return _vision_transformer(
+ arch="vit_l_32",
+ patch_size=32,
+ num_layers=24,
+ num_heads=16,
+ hidden_dim=1024,
+ mlp_dim=4096,
+ pretrained=pretrained,
+ progress=progress,
+ **kwargs,
+ )
+
+
+def interpolate_embeddings(
+ image_size: int,
+ patch_size: int,
+ model_state: "OrderedDict[str, torch.Tensor]",
+ interpolation_mode: str = "bicubic",
+ reset_heads: bool = False,
+) -> "OrderedDict[str, torch.Tensor]":
+ """This function helps interpolating positional embeddings during checkpoint loading,
+ especially when you want to apply a pre-trained model on images with different resolution.
+
+ Args:
+ image_size (int): Image size of the new model.
+ patch_size (int): Patch size of the new model.
+ model_state (OrderedDict[str, torch.Tensor]): State dict of the pre-trained model.
+ interpolation_mode (str): The algorithm used for upsampling. Default: bicubic.
+ reset_heads (bool): If true, not copying the state of heads. Default: False.
+
+ Returns:
+ OrderedDict[str, torch.Tensor]: A state dict which can be loaded into the new model.
+ """
+ # Shape of pos_embedding is (1, seq_length, hidden_dim)
+ pos_embedding = model_state["encoder.pos_embedding"]
+ n, seq_length, hidden_dim = pos_embedding.shape
+ if n != 1:
+ raise ValueError(f"Unexpected position embedding shape: {pos_embedding.shape}")
+
+ new_seq_length = (image_size // patch_size) ** 2 + 1
+
+ # Need to interpolate the weights for the position embedding.
+ # We do this by reshaping the positions embeddings to a 2d grid, performing
+ # an interpolation in the (h, w) space and then reshaping back to a 1d grid.
+ if new_seq_length != seq_length:
+ # The class token embedding shouldn't be interpolated so we split it up.
+ seq_length -= 1
+ new_seq_length -= 1
+ pos_embedding_token = pos_embedding[:, :1, :]
+ pos_embedding_img = pos_embedding[:, 1:, :]
+
+ # (1, seq_length, hidden_dim) -> (1, hidden_dim, seq_length)
+ pos_embedding_img = pos_embedding_img.permute(0, 2, 1)
+ seq_length_1d = int(math.sqrt(seq_length))
+ torch._assert(seq_length_1d * seq_length_1d == seq_length, "seq_length is not a perfect square!")
+
+ # (1, hidden_dim, seq_length) -> (1, hidden_dim, seq_l_1d, seq_l_1d)
+ pos_embedding_img = pos_embedding_img.reshape(1, hidden_dim, seq_length_1d, seq_length_1d)
+ new_seq_length_1d = image_size // patch_size
+
+ # Perform interpolation.
+ # (1, hidden_dim, seq_l_1d, seq_l_1d) -> (1, hidden_dim, new_seq_l_1d, new_seq_l_1d)
+ new_pos_embedding_img = nn.functional.interpolate(
+ pos_embedding_img,
+ size=new_seq_length_1d,
+ mode=interpolation_mode,
+ align_corners=True,
+ )
+
+ # (1, hidden_dim, new_seq_l_1d, new_seq_l_1d) -> (1, hidden_dim, new_seq_length)
+ new_pos_embedding_img = new_pos_embedding_img.reshape(1, hidden_dim, new_seq_length)
+
+ # (1, hidden_dim, new_seq_length) -> (1, new_seq_length, hidden_dim)
+ new_pos_embedding_img = new_pos_embedding_img.permute(0, 2, 1)
+ new_pos_embedding = torch.cat([pos_embedding_token, new_pos_embedding_img], dim=1)
+
+ model_state["encoder.pos_embedding"] = new_pos_embedding
+
+ if reset_heads:
+ model_state_copy: "OrderedDict[str, torch.Tensor]" = OrderedDict()
+ for k, v in model_state.items():
+ if not k.startswith("heads"):
+ model_state_copy[k] = v
+ model_state = model_state_copy
+
+ return model_state
diff --git a/clean/video/lipfd/models/vision_transformer_misc.py b/clean/video/lipfd/models/vision_transformer_misc.py
new file mode 100644
index 0000000000000000000000000000000000000000..7915f036c00f0d9c57c176e621afc9f1e69dcb30
--- /dev/null
+++ b/clean/video/lipfd/models/vision_transformer_misc.py
@@ -0,0 +1,163 @@
+from typing import Callable, List, Optional
+
+import torch
+from torch import Tensor
+
+from .vision_transformer_utils import _log_api_usage_once
+
+
+interpolate = torch.nn.functional.interpolate
+
+
+# This is not in nn
+class FrozenBatchNorm2d(torch.nn.Module):
+ """
+ BatchNorm2d where the batch statistics and the affine parameters are fixed
+
+ Args:
+ num_features (int): Number of features ``C`` from an expected input of size ``(N, C, H, W)``
+ eps (float): a value added to the denominator for numerical stability. Default: 1e-5
+ """
+
+ def __init__(
+ self,
+ num_features: int,
+ eps: float = 1e-5,
+ ):
+ super().__init__()
+ _log_api_usage_once(self)
+ self.eps = eps
+ self.register_buffer("weight", torch.ones(num_features))
+ self.register_buffer("bias", torch.zeros(num_features))
+ self.register_buffer("running_mean", torch.zeros(num_features))
+ self.register_buffer("running_var", torch.ones(num_features))
+
+ def _load_from_state_dict(
+ self,
+ state_dict: dict,
+ prefix: str,
+ local_metadata: dict,
+ strict: bool,
+ missing_keys: List[str],
+ unexpected_keys: List[str],
+ error_msgs: List[str],
+ ):
+ num_batches_tracked_key = prefix + "num_batches_tracked"
+ if num_batches_tracked_key in state_dict:
+ del state_dict[num_batches_tracked_key]
+
+ super()._load_from_state_dict(
+ state_dict, prefix, local_metadata, strict, missing_keys, unexpected_keys, error_msgs
+ )
+
+ def forward(self, x: Tensor) -> Tensor:
+ # move reshapes to the beginning
+ # to make it fuser-friendly
+ w = self.weight.reshape(1, -1, 1, 1)
+ b = self.bias.reshape(1, -1, 1, 1)
+ rv = self.running_var.reshape(1, -1, 1, 1)
+ rm = self.running_mean.reshape(1, -1, 1, 1)
+ scale = w * (rv + self.eps).rsqrt()
+ bias = b - rm * scale
+ return x * scale + bias
+
+ def __repr__(self) -> str:
+ return f"{self.__class__.__name__}({self.weight.shape[0]}, eps={self.eps})"
+
+
+class ConvNormActivation(torch.nn.Sequential):
+ """
+ Configurable block used for Convolution-Normalzation-Activation blocks.
+
+ Args:
+ in_channels (int): Number of channels in the input image
+ out_channels (int): Number of channels produced by the Convolution-Normalzation-Activation block
+ kernel_size: (int, optional): Size of the convolving kernel. Default: 3
+ stride (int, optional): Stride of the convolution. Default: 1
+ padding (int, tuple or str, optional): Padding added to all four sides of the input. Default: None, in wich case it will calculated as ``padding = (kernel_size - 1) // 2 * dilation``
+ groups (int, optional): Number of blocked connections from input channels to output channels. Default: 1
+ norm_layer (Callable[..., torch.nn.Module], optional): Norm layer that will be stacked on top of the convolutiuon layer. If ``None`` this layer wont be used. Default: ``torch.nn.BatchNorm2d``
+ activation_layer (Callable[..., torch.nn.Module], optinal): Activation function which will be stacked on top of the normalization layer (if not None), otherwise on top of the conv layer. If ``None`` this layer wont be used. Default: ``torch.nn.ReLU``
+ dilation (int): Spacing between kernel elements. Default: 1
+ inplace (bool): Parameter for the activation layer, which can optionally do the operation in-place. Default ``True``
+ bias (bool, optional): Whether to use bias in the convolution layer. By default, biases are included if ``norm_layer is None``.
+
+ """
+
+ def __init__(
+ self,
+ in_channels: int,
+ out_channels: int,
+ kernel_size: int = 3,
+ stride: int = 1,
+ padding: Optional[int] = None,
+ groups: int = 1,
+ norm_layer: Optional[Callable[..., torch.nn.Module]] = torch.nn.BatchNorm2d,
+ activation_layer: Optional[Callable[..., torch.nn.Module]] = torch.nn.ReLU,
+ dilation: int = 1,
+ inplace: Optional[bool] = True,
+ bias: Optional[bool] = None,
+ ) -> None:
+ if padding is None:
+ padding = (kernel_size - 1) // 2 * dilation
+ if bias is None:
+ bias = norm_layer is None
+ layers = [
+ torch.nn.Conv2d(
+ in_channels,
+ out_channels,
+ kernel_size,
+ stride,
+ padding,
+ dilation=dilation,
+ groups=groups,
+ bias=bias,
+ )
+ ]
+ if norm_layer is not None:
+ layers.append(norm_layer(out_channels))
+ if activation_layer is not None:
+ params = {} if inplace is None else {"inplace": inplace}
+ layers.append(activation_layer(**params))
+ super().__init__(*layers)
+ _log_api_usage_once(self)
+ self.out_channels = out_channels
+
+
+class SqueezeExcitation(torch.nn.Module):
+ """
+ This block implements the Squeeze-and-Excitation block from https://arxiv.org/abs/1709.01507 (see Fig. 1).
+ Parameters ``activation``, and ``scale_activation`` correspond to ``delta`` and ``sigma`` in in eq. 3.
+
+ Args:
+ input_channels (int): Number of channels in the input image
+ squeeze_channels (int): Number of squeeze channels
+ activation (Callable[..., torch.nn.Module], optional): ``delta`` activation. Default: ``torch.nn.ReLU``
+ scale_activation (Callable[..., torch.nn.Module]): ``sigma`` activation. Default: ``torch.nn.Sigmoid``
+ """
+
+ def __init__(
+ self,
+ input_channels: int,
+ squeeze_channels: int,
+ activation: Callable[..., torch.nn.Module] = torch.nn.ReLU,
+ scale_activation: Callable[..., torch.nn.Module] = torch.nn.Sigmoid,
+ ) -> None:
+ super().__init__()
+ _log_api_usage_once(self)
+ self.avgpool = torch.nn.AdaptiveAvgPool2d(1)
+ self.fc1 = torch.nn.Conv2d(input_channels, squeeze_channels, 1)
+ self.fc2 = torch.nn.Conv2d(squeeze_channels, input_channels, 1)
+ self.activation = activation()
+ self.scale_activation = scale_activation()
+
+ def _scale(self, input: Tensor) -> Tensor:
+ scale = self.avgpool(input)
+ scale = self.fc1(scale)
+ scale = self.activation(scale)
+ scale = self.fc2(scale)
+ return self.scale_activation(scale)
+
+ def forward(self, input: Tensor) -> Tensor:
+ scale = self._scale(input)
+ return scale * input
diff --git a/clean/video/lipfd/models/vision_transformer_utils.py b/clean/video/lipfd/models/vision_transformer_utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..6d3293d103d0e186a1244e7cc0c6e3bde63d1df3
--- /dev/null
+++ b/clean/video/lipfd/models/vision_transformer_utils.py
@@ -0,0 +1,549 @@
+import math
+import pathlib
+import warnings
+from types import FunctionType
+from typing import Any, BinaryIO, List, Optional, Tuple, Union
+
+import numpy as np
+import torch
+from PIL import Image, ImageColor, ImageDraw, ImageFont
+
+__all__ = [
+ "make_grid",
+ "save_image",
+ "draw_bounding_boxes",
+ "draw_segmentation_masks",
+ "draw_keypoints",
+ "flow_to_image",
+]
+
+
+@torch.no_grad()
+def make_grid(
+ tensor: Union[torch.Tensor, List[torch.Tensor]],
+ nrow: int = 8,
+ padding: int = 2,
+ normalize: bool = False,
+ value_range: Optional[Tuple[int, int]] = None,
+ scale_each: bool = False,
+ pad_value: float = 0.0,
+ **kwargs,
+) -> torch.Tensor:
+ """
+ Make a grid of images.
+
+ Args:
+ tensor (Tensor or list): 4D mini-batch Tensor of shape (B x C x H x W)
+ or a list of images all of the same size.
+ nrow (int, optional): Number of images displayed in each row of the grid.
+ The final grid size is ``(B / nrow, nrow)``. Default: ``8``.
+ padding (int, optional): amount of padding. Default: ``2``.
+ normalize (bool, optional): If True, shift the image to the range (0, 1),
+ by the min and max values specified by ``value_range``. Default: ``False``.
+ value_range (tuple, optional): tuple (min, max) where min and max are numbers,
+ then these numbers are used to normalize the image. By default, min and max
+ are computed from the tensor.
+ range (tuple. optional):
+ .. warning::
+ This parameter was deprecated in ``0.12`` and will be removed in ``0.14``. Please use ``value_range``
+ instead.
+ scale_each (bool, optional): If ``True``, scale each image in the batch of
+ images separately rather than the (min, max) over all images. Default: ``False``.
+ pad_value (float, optional): Value for the padded pixels. Default: ``0``.
+
+ Returns:
+ grid (Tensor): the tensor containing grid of images.
+ """
+ if not torch.jit.is_scripting() and not torch.jit.is_tracing():
+ _log_api_usage_once(make_grid)
+ if not (torch.is_tensor(tensor) or (isinstance(tensor, list) and all(torch.is_tensor(t) for t in tensor))):
+ raise TypeError(f"tensor or list of tensors expected, got {type(tensor)}")
+
+ if "range" in kwargs.keys():
+ warnings.warn(
+ "The parameter 'range' is deprecated since 0.12 and will be removed in 0.14. "
+ "Please use 'value_range' instead."
+ )
+ value_range = kwargs["range"]
+
+ # if list of tensors, convert to a 4D mini-batch Tensor
+ if isinstance(tensor, list):
+ tensor = torch.stack(tensor, dim=0)
+
+ if tensor.dim() == 2: # single image H x W
+ tensor = tensor.unsqueeze(0)
+ if tensor.dim() == 3: # single image
+ if tensor.size(0) == 1: # if single-channel, convert to 3-channel
+ tensor = torch.cat((tensor, tensor, tensor), 0)
+ tensor = tensor.unsqueeze(0)
+
+ if tensor.dim() == 4 and tensor.size(1) == 1: # single-channel images
+ tensor = torch.cat((tensor, tensor, tensor), 1)
+
+ if normalize is True:
+ tensor = tensor.clone() # avoid modifying tensor in-place
+ if value_range is not None:
+ assert isinstance(
+ value_range, tuple
+ ), "value_range has to be a tuple (min, max) if specified. min and max are numbers"
+
+ def norm_ip(img, low, high):
+ img.clamp_(min=low, max=high)
+ img.sub_(low).div_(max(high - low, 1e-5))
+
+ def norm_range(t, value_range):
+ if value_range is not None:
+ norm_ip(t, value_range[0], value_range[1])
+ else:
+ norm_ip(t, float(t.min()), float(t.max()))
+
+ if scale_each is True:
+ for t in tensor: # loop over mini-batch dimension
+ norm_range(t, value_range)
+ else:
+ norm_range(tensor, value_range)
+
+ assert isinstance(tensor, torch.Tensor)
+ if tensor.size(0) == 1:
+ return tensor.squeeze(0)
+
+ # make the mini-batch of images into a grid
+ nmaps = tensor.size(0)
+ xmaps = min(nrow, nmaps)
+ ymaps = int(math.ceil(float(nmaps) / xmaps))
+ height, width = int(tensor.size(2) + padding), int(tensor.size(3) + padding)
+ num_channels = tensor.size(1)
+ grid = tensor.new_full((num_channels, height * ymaps + padding, width * xmaps + padding), pad_value)
+ k = 0
+ for y in range(ymaps):
+ for x in range(xmaps):
+ if k >= nmaps:
+ break
+ # Tensor.copy_() is a valid method but seems to be missing from the stubs
+ # https://pytorch.org/docs/stable/tensors.html#torch.Tensor.copy_
+ grid.narrow(1, y * height + padding, height - padding).narrow( # type: ignore[attr-defined]
+ 2, x * width + padding, width - padding
+ ).copy_(tensor[k])
+ k = k + 1
+ return grid
+
+
+@torch.no_grad()
+def save_image(
+ tensor: Union[torch.Tensor, List[torch.Tensor]],
+ fp: Union[str, pathlib.Path, BinaryIO],
+ format: Optional[str] = None,
+ **kwargs,
+) -> None:
+ """
+ Save a given Tensor into an image file.
+
+ Args:
+ tensor (Tensor or list): Image to be saved. If given a mini-batch tensor,
+ saves the tensor as a grid of images by calling ``make_grid``.
+ fp (string or file object): A filename or a file object
+ format(Optional): If omitted, the format to use is determined from the filename extension.
+ If a file object was used instead of a filename, this parameter should always be used.
+ **kwargs: Other arguments are documented in ``make_grid``.
+ """
+
+ if not torch.jit.is_scripting() and not torch.jit.is_tracing():
+ _log_api_usage_once(save_image)
+ grid = make_grid(tensor, **kwargs)
+ # Add 0.5 after unnormalizing to [0, 255] to round to nearest integer
+ ndarr = grid.mul(255).add_(0.5).clamp_(0, 255).permute(1, 2, 0).to("cpu", torch.uint8).numpy()
+ im = Image.fromarray(ndarr)
+ im.save(fp, format=format)
+
+
+@torch.no_grad()
+def draw_bounding_boxes(
+ image: torch.Tensor,
+ boxes: torch.Tensor,
+ labels: Optional[List[str]] = None,
+ colors: Optional[Union[List[Union[str, Tuple[int, int, int]]], str, Tuple[int, int, int]]] = None,
+ fill: Optional[bool] = False,
+ width: int = 1,
+ font: Optional[str] = None,
+ font_size: int = 10,
+) -> torch.Tensor:
+
+ """
+ Draws bounding boxes on given image.
+ The values of the input image should be uint8 between 0 and 255.
+ If fill is True, Resulting Tensor should be saved as PNG image.
+
+ Args:
+ image (Tensor): Tensor of shape (C x H x W) and dtype uint8.
+ boxes (Tensor): Tensor of size (N, 4) containing bounding boxes in (xmin, ymin, xmax, ymax) format. Note that
+ the boxes are absolute coordinates with respect to the image. In other words: `0 <= xmin < xmax < W` and
+ `0 <= ymin < ymax < H`.
+ labels (List[str]): List containing the labels of bounding boxes.
+ colors (color or list of colors, optional): List containing the colors
+ of the boxes or single color for all boxes. The color can be represented as
+ PIL strings e.g. "red" or "#FF00FF", or as RGB tuples e.g. ``(240, 10, 157)``.
+ By default, random colors are generated for boxes.
+ fill (bool): If `True` fills the bounding box with specified color.
+ width (int): Width of bounding box.
+ font (str): A filename containing a TrueType font. If the file is not found in this filename, the loader may
+ also search in other directories, such as the `fonts/` directory on Windows or `/Library/Fonts/`,
+ `/System/Library/Fonts/` and `~/Library/Fonts/` on macOS.
+ font_size (int): The requested font size in points.
+
+ Returns:
+ img (Tensor[C, H, W]): Image Tensor of dtype uint8 with bounding boxes plotted.
+ """
+
+ if not torch.jit.is_scripting() and not torch.jit.is_tracing():
+ _log_api_usage_once(draw_bounding_boxes)
+ if not isinstance(image, torch.Tensor):
+ raise TypeError(f"Tensor expected, got {type(image)}")
+ elif image.dtype != torch.uint8:
+ raise ValueError(f"Tensor uint8 expected, got {image.dtype}")
+ elif image.dim() != 3:
+ raise ValueError("Pass individual images, not batches")
+ elif image.size(0) not in {1, 3}:
+ raise ValueError("Only grayscale and RGB images are supported")
+
+ num_boxes = boxes.shape[0]
+
+ if labels is None:
+ labels: Union[List[str], List[None]] = [None] * num_boxes # type: ignore[no-redef]
+ elif len(labels) != num_boxes:
+ raise ValueError(
+ f"Number of boxes ({num_boxes}) and labels ({len(labels)}) mismatch. Please specify labels for each box."
+ )
+
+ if colors is None:
+ colors = _generate_color_palette(num_boxes)
+ elif isinstance(colors, list):
+ if len(colors) < num_boxes:
+ raise ValueError(f"Number of colors ({len(colors)}) is less than number of boxes ({num_boxes}). ")
+ else: # colors specifies a single color for all boxes
+ colors = [colors] * num_boxes
+
+ colors = [(ImageColor.getrgb(color) if isinstance(color, str) else color) for color in colors]
+
+ # Handle Grayscale images
+ if image.size(0) == 1:
+ image = torch.tile(image, (3, 1, 1))
+
+ ndarr = image.permute(1, 2, 0).cpu().numpy()
+ img_to_draw = Image.fromarray(ndarr)
+ img_boxes = boxes.to(torch.int64).tolist()
+
+ if fill:
+ draw = ImageDraw.Draw(img_to_draw, "RGBA")
+ else:
+ draw = ImageDraw.Draw(img_to_draw)
+
+ txt_font = ImageFont.load_default() if font is None else ImageFont.truetype(font=font, size=font_size)
+
+ for bbox, color, label in zip(img_boxes, colors, labels): # type: ignore[arg-type]
+ if fill:
+ fill_color = color + (100,)
+ draw.rectangle(bbox, width=width, outline=color, fill=fill_color)
+ else:
+ draw.rectangle(bbox, width=width, outline=color)
+
+ if label is not None:
+ margin = width + 1
+ draw.text((bbox[0] + margin, bbox[1] + margin), label, fill=color, font=txt_font)
+
+ return torch.from_numpy(np.array(img_to_draw)).permute(2, 0, 1).to(dtype=torch.uint8)
+
+
+@torch.no_grad()
+def draw_segmentation_masks(
+ image: torch.Tensor,
+ masks: torch.Tensor,
+ alpha: float = 0.8,
+ colors: Optional[Union[List[Union[str, Tuple[int, int, int]]], str, Tuple[int, int, int]]] = None,
+) -> torch.Tensor:
+
+ """
+ Draws segmentation masks on given RGB image.
+ The values of the input image should be uint8 between 0 and 255.
+
+ Args:
+ image (Tensor): Tensor of shape (3, H, W) and dtype uint8.
+ masks (Tensor): Tensor of shape (num_masks, H, W) or (H, W) and dtype bool.
+ alpha (float): Float number between 0 and 1 denoting the transparency of the masks.
+ 0 means full transparency, 1 means no transparency.
+ colors (color or list of colors, optional): List containing the colors
+ of the masks or single color for all masks. The color can be represented as
+ PIL strings e.g. "red" or "#FF00FF", or as RGB tuples e.g. ``(240, 10, 157)``.
+ By default, random colors are generated for each mask.
+
+ Returns:
+ img (Tensor[C, H, W]): Image Tensor, with segmentation masks drawn on top.
+ """
+
+ if not torch.jit.is_scripting() and not torch.jit.is_tracing():
+ _log_api_usage_once(draw_segmentation_masks)
+ if not isinstance(image, torch.Tensor):
+ raise TypeError(f"The image must be a tensor, got {type(image)}")
+ elif image.dtype != torch.uint8:
+ raise ValueError(f"The image dtype must be uint8, got {image.dtype}")
+ elif image.dim() != 3:
+ raise ValueError("Pass individual images, not batches")
+ elif image.size()[0] != 3:
+ raise ValueError("Pass an RGB image. Other Image formats are not supported")
+ if masks.ndim == 2:
+ masks = masks[None, :, :]
+ if masks.ndim != 3:
+ raise ValueError("masks must be of shape (H, W) or (batch_size, H, W)")
+ if masks.dtype != torch.bool:
+ raise ValueError(f"The masks must be of dtype bool. Got {masks.dtype}")
+ if masks.shape[-2:] != image.shape[-2:]:
+ raise ValueError("The image and the masks must have the same height and width")
+
+ num_masks = masks.size()[0]
+ if colors is not None and num_masks > len(colors):
+ raise ValueError(f"There are more masks ({num_masks}) than colors ({len(colors)})")
+
+ if colors is None:
+ colors = _generate_color_palette(num_masks)
+
+ if not isinstance(colors, list):
+ colors = [colors]
+ if not isinstance(colors[0], (tuple, str)):
+ raise ValueError("colors must be a tuple or a string, or a list thereof")
+ if isinstance(colors[0], tuple) and len(colors[0]) != 3:
+ raise ValueError("It seems that you passed a tuple of colors instead of a list of colors")
+
+ out_dtype = torch.uint8
+
+ colors_ = []
+ for color in colors:
+ if isinstance(color, str):
+ color = ImageColor.getrgb(color)
+ colors_.append(torch.tensor(color, dtype=out_dtype))
+
+ img_to_draw = image.detach().clone()
+ # TODO: There might be a way to vectorize this
+ for mask, color in zip(masks, colors_):
+ img_to_draw[:, mask] = color[:, None]
+
+ out = image * (1 - alpha) + img_to_draw * alpha
+ return out.to(out_dtype)
+
+
+@torch.no_grad()
+def draw_keypoints(
+ image: torch.Tensor,
+ keypoints: torch.Tensor,
+ connectivity: Optional[List[Tuple[int, int]]] = None,
+ colors: Optional[Union[str, Tuple[int, int, int]]] = None,
+ radius: int = 2,
+ width: int = 3,
+) -> torch.Tensor:
+
+ """
+ Draws Keypoints on given RGB image.
+ The values of the input image should be uint8 between 0 and 255.
+
+ Args:
+ image (Tensor): Tensor of shape (3, H, W) and dtype uint8.
+ keypoints (Tensor): Tensor of shape (num_instances, K, 2) the K keypoints location for each of the N instances,
+ in the format [x, y].
+ connectivity (List[Tuple[int, int]]]): A List of tuple where,
+ each tuple contains pair of keypoints to be connected.
+ colors (str, Tuple): The color can be represented as
+ PIL strings e.g. "red" or "#FF00FF", or as RGB tuples e.g. ``(240, 10, 157)``.
+ radius (int): Integer denoting radius of keypoint.
+ width (int): Integer denoting width of line connecting keypoints.
+
+ Returns:
+ img (Tensor[C, H, W]): Image Tensor of dtype uint8 with keypoints drawn.
+ """
+
+ if not torch.jit.is_scripting() and not torch.jit.is_tracing():
+ _log_api_usage_once(draw_keypoints)
+ if not isinstance(image, torch.Tensor):
+ raise TypeError(f"The image must be a tensor, got {type(image)}")
+ elif image.dtype != torch.uint8:
+ raise ValueError(f"The image dtype must be uint8, got {image.dtype}")
+ elif image.dim() != 3:
+ raise ValueError("Pass individual images, not batches")
+ elif image.size()[0] != 3:
+ raise ValueError("Pass an RGB image. Other Image formats are not supported")
+
+ if keypoints.ndim != 3:
+ raise ValueError("keypoints must be of shape (num_instances, K, 2)")
+
+ ndarr = image.permute(1, 2, 0).cpu().numpy()
+ img_to_draw = Image.fromarray(ndarr)
+ draw = ImageDraw.Draw(img_to_draw)
+ img_kpts = keypoints.to(torch.int64).tolist()
+
+ for kpt_id, kpt_inst in enumerate(img_kpts):
+ for inst_id, kpt in enumerate(kpt_inst):
+ x1 = kpt[0] - radius
+ x2 = kpt[0] + radius
+ y1 = kpt[1] - radius
+ y2 = kpt[1] + radius
+ draw.ellipse([x1, y1, x2, y2], fill=colors, outline=None, width=0)
+
+ if connectivity:
+ for connection in connectivity:
+ start_pt_x = kpt_inst[connection[0]][0]
+ start_pt_y = kpt_inst[connection[0]][1]
+
+ end_pt_x = kpt_inst[connection[1]][0]
+ end_pt_y = kpt_inst[connection[1]][1]
+
+ draw.line(
+ ((start_pt_x, start_pt_y), (end_pt_x, end_pt_y)),
+ width=width,
+ )
+
+ return torch.from_numpy(np.array(img_to_draw)).permute(2, 0, 1).to(dtype=torch.uint8)
+
+
+# Flow visualization code adapted from https://github.com/tomrunia/OpticalFlow_Visualization
+@torch.no_grad()
+def flow_to_image(flow: torch.Tensor) -> torch.Tensor:
+
+ """
+ Converts a flow to an RGB image.
+
+ Args:
+ flow (Tensor): Flow of shape (N, 2, H, W) or (2, H, W) and dtype torch.float.
+
+ Returns:
+ img (Tensor): Image Tensor of dtype uint8 where each color corresponds
+ to a given flow direction. Shape is (N, 3, H, W) or (3, H, W) depending on the input.
+ """
+
+ if flow.dtype != torch.float:
+ raise ValueError(f"Flow should be of dtype torch.float, got {flow.dtype}.")
+
+ orig_shape = flow.shape
+ if flow.ndim == 3:
+ flow = flow[None] # Add batch dim
+
+ if flow.ndim != 4 or flow.shape[1] != 2:
+ raise ValueError(f"Input flow should have shape (2, H, W) or (N, 2, H, W), got {orig_shape}.")
+
+ max_norm = torch.sum(flow ** 2, dim=1).sqrt().max()
+ epsilon = torch.finfo((flow).dtype).eps
+ normalized_flow = flow / (max_norm + epsilon)
+ img = _normalized_flow_to_image(normalized_flow)
+
+ if len(orig_shape) == 3:
+ img = img[0] # Remove batch dim
+ return img
+
+
+@torch.no_grad()
+def _normalized_flow_to_image(normalized_flow: torch.Tensor) -> torch.Tensor:
+
+ """
+ Converts a batch of normalized flow to an RGB image.
+
+ Args:
+ normalized_flow (torch.Tensor): Normalized flow tensor of shape (N, 2, H, W)
+ Returns:
+ img (Tensor(N, 3, H, W)): Flow visualization image of dtype uint8.
+ """
+
+ N, _, H, W = normalized_flow.shape
+ device = normalized_flow.device
+ flow_image = torch.zeros((N, 3, H, W), dtype=torch.uint8, device=device)
+ colorwheel = _make_colorwheel().to(device) # shape [55x3]
+ num_cols = colorwheel.shape[0]
+ norm = torch.sum(normalized_flow ** 2, dim=1).sqrt()
+ a = torch.atan2(-normalized_flow[:, 1, :, :], -normalized_flow[:, 0, :, :]) / torch.pi
+ fk = (a + 1) / 2 * (num_cols - 1)
+ k0 = torch.floor(fk).to(torch.long)
+ k1 = k0 + 1
+ k1[k1 == num_cols] = 0
+ f = fk - k0
+
+ for c in range(colorwheel.shape[1]):
+ tmp = colorwheel[:, c]
+ col0 = tmp[k0] / 255.0
+ col1 = tmp[k1] / 255.0
+ col = (1 - f) * col0 + f * col1
+ col = 1 - norm * (1 - col)
+ flow_image[:, c, :, :] = torch.floor(255 * col)
+ return flow_image
+
+
+def _make_colorwheel() -> torch.Tensor:
+ """
+ Generates a color wheel for optical flow visualization as presented in:
+ Baker et al. "A Database and Evaluation Methodology for Optical Flow" (ICCV, 2007)
+ URL: http://vision.middlebury.edu/flow/flowEval-iccv07.pdf.
+
+ Returns:
+ colorwheel (Tensor[55, 3]): Colorwheel Tensor.
+ """
+
+ RY = 15
+ YG = 6
+ GC = 4
+ CB = 11
+ BM = 13
+ MR = 6
+
+ ncols = RY + YG + GC + CB + BM + MR
+ colorwheel = torch.zeros((ncols, 3))
+ col = 0
+
+ # RY
+ colorwheel[0:RY, 0] = 255
+ colorwheel[0:RY, 1] = torch.floor(255 * torch.arange(0, RY) / RY)
+ col = col + RY
+ # YG
+ colorwheel[col : col + YG, 0] = 255 - torch.floor(255 * torch.arange(0, YG) / YG)
+ colorwheel[col : col + YG, 1] = 255
+ col = col + YG
+ # GC
+ colorwheel[col : col + GC, 1] = 255
+ colorwheel[col : col + GC, 2] = torch.floor(255 * torch.arange(0, GC) / GC)
+ col = col + GC
+ # CB
+ colorwheel[col : col + CB, 1] = 255 - torch.floor(255 * torch.arange(CB) / CB)
+ colorwheel[col : col + CB, 2] = 255
+ col = col + CB
+ # BM
+ colorwheel[col : col + BM, 2] = 255
+ colorwheel[col : col + BM, 0] = torch.floor(255 * torch.arange(0, BM) / BM)
+ col = col + BM
+ # MR
+ colorwheel[col : col + MR, 2] = 255 - torch.floor(255 * torch.arange(MR) / MR)
+ colorwheel[col : col + MR, 0] = 255
+ return colorwheel
+
+
+def _generate_color_palette(num_objects: int):
+ palette = torch.tensor([2 ** 25 - 1, 2 ** 15 - 1, 2 ** 21 - 1])
+ return [tuple((i * palette) % 255) for i in range(num_objects)]
+
+
+def _log_api_usage_once(obj: Any) -> None:
+
+ """
+ Logs API usage(module and name) within an organization.
+ In a large ecosystem, it's often useful to track the PyTorch and
+ TorchVision APIs usage. This API provides the similar functionality to the
+ logging module in the Python stdlib. It can be used for debugging purpose
+ to log which methods are used and by default it is inactive, unless the user
+ manually subscribes a logger via the `SetAPIUsageLogger method `_.
+ Please note it is triggered only once for the same API call within a process.
+ It does not collect any data from open-source users since it is no-op by default.
+ For more information, please refer to
+ * PyTorch note: https://pytorch.org/docs/stable/notes/large_scale_deployments.html#api-usage-logging;
+ * Logging policy: https://github.com/pytorch/vision/issues/5052;
+
+ Args:
+ obj (class instance or method): an object to extract info from.
+ """
+ if not obj.__module__.startswith("torchvision"):
+ return
+ name = obj.__class__.__name__
+ if isinstance(obj, FunctionType):
+ name = obj.__name__
+ torch._C._log_api_usage_once(f"{obj.__module__}.{name}")
diff --git a/clean/video/lipfd/options/base_options.py b/clean/video/lipfd/options/base_options.py
new file mode 100644
index 0000000000000000000000000000000000000000..6d5a8e8b0c95dd5c02b32548c5d616270f7cc9ad
--- /dev/null
+++ b/clean/video/lipfd/options/base_options.py
@@ -0,0 +1,97 @@
+import os
+import argparse
+import torch
+
+
+class BaseOptions:
+ def __init__(self):
+ self.initialized = False
+
+ def initialize(self, parser):
+ parser.add_argument("--arch", type=str, default="CLIP:ViT-L/14", help="see models/__init__.py")
+ parser.add_argument("--fix_backbone", default=False)
+ parser.add_argument("--fix_encoder", default=True)
+
+ parser.add_argument("--real_list_path", default="./datasets/val/0_real")
+ parser.add_argument("--fake_list_path", default="./datasets/val/1_fake")
+ parser.add_argument("--data_label", default="train", help="label to decide whether train or validation dataset",)
+
+ parser.add_argument( "--batch_size", type=int, default=10, help="input batch size")
+ parser.add_argument("--gpu_ids", type=str, default="1", help="gpu ids: e.g. 0 0,1,2, 0,2. use -1 for CPU",)
+ parser.add_argument("--name", type=str, default="experiment_name", help="name of the experiment. It decides where to store samples and models",)
+ parser.add_argument("--num_threads", default=0, type=int, help="# threads for loading data")
+ parser.add_argument("--checkpoints_dir", type=str, default="./checkpoints", help="models are saved here",)
+ parser.add_argument("--serial_batches",action="store_true",help="if true, takes images in order to make batches, otherwise takes them randomly",)
+ self.initialized = True
+ return parser
+
+ def gather_options(self):
+ # initialize parser with basic options
+ if not self.initialized:
+ parser = argparse.ArgumentParser(
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter
+ )
+ parser = self.initialize(parser)
+
+ # get the basic options
+ opt, _ = parser.parse_known_args()
+ self.parser = parser
+
+ return parser.parse_args()
+
+ def print_options(self, opt):
+ message = ""
+ message += "----------------- Options ---------------\n"
+ for k, v in sorted(vars(opt).items()):
+ comment = ""
+ default = self.parser.get_default(k)
+ if v != default:
+ comment = "\t[default: %s]" % str(default)
+ message += "{:>25}: {:<30}{}\n".format(str(k), str(v), comment)
+ message += "----------------- End -------------------"
+ print(message)
+
+ # save to the disk
+ expr_dir = os.path.join(opt.checkpoints_dir, opt.name)
+ os.makedirs(expr_dir, exist_ok=True)
+ # util.mkdirs(expr_dir)
+ file_name = os.path.join(expr_dir, "opt.txt")
+ with open(file_name, "wt") as opt_file:
+ opt_file.write(message)
+ opt_file.write("\n")
+
+ def parse(self, print_options=True):
+ opt = self.gather_options()
+ opt.isTrain = self.isTrain # train or test
+
+ # process opt.suffix
+ if opt.suffix:
+ suffix = ("_" + opt.suffix.format(**vars(opt))) if opt.suffix != "" else ""
+ opt.name = opt.name + suffix
+
+ if print_options:
+ self.print_options(opt)
+
+ # set gpu ids
+ str_ids = opt.gpu_ids.split(",")
+ opt.gpu_ids = []
+ for str_id in str_ids:
+ id = int(str_id)
+ if id >= 0:
+ opt.gpu_ids.append(id)
+ if len(opt.gpu_ids) > 0:
+ torch.cuda.set_device(opt.gpu_ids[0])
+
+ # additional
+ # opt.classes = opt.classes.split(',')
+ opt.rz_interp = opt.rz_interp.split(",")
+ opt.blur_sig = [float(s) for s in opt.blur_sig.split(",")]
+ opt.jpg_method = opt.jpg_method.split(",")
+ opt.jpg_qual = [int(s) for s in opt.jpg_qual.split(",")]
+ if len(opt.jpg_qual) == 2:
+ opt.jpg_qual = list(range(opt.jpg_qual[0], opt.jpg_qual[1] + 1))
+ elif len(opt.jpg_qual) > 2:
+ raise ValueError("Shouldn't have more than 2 values for --jpg_qual.")
+
+ self.opt = opt
+ return self.opt
diff --git a/clean/video/lipfd/options/test_options.py b/clean/video/lipfd/options/test_options.py
new file mode 100644
index 0000000000000000000000000000000000000000..a84885c6ad72d18a2959e240d5b9b74891778145
--- /dev/null
+++ b/clean/video/lipfd/options/test_options.py
@@ -0,0 +1,11 @@
+from .base_options import BaseOptions
+
+
+class TestOptions(BaseOptions):
+ def initialize(self, parser):
+ parser = BaseOptions.initialize(self, parser)
+ parser.add_argument('--model_path')
+ parser.add_argument('--eval', action='store_true', help='use eval mode during test time.')
+
+ self.isTrain = False
+ return parser
diff --git a/clean/video/lipfd/options/train_options.py b/clean/video/lipfd/options/train_options.py
new file mode 100644
index 0000000000000000000000000000000000000000..9e7fdf964cbc7ffab354b87c4cbd6f4caa234f23
--- /dev/null
+++ b/clean/video/lipfd/options/train_options.py
@@ -0,0 +1,20 @@
+from .base_options import BaseOptions
+
+
+class TrainOptions(BaseOptions):
+ def initialize(self, parser):
+ parser = BaseOptions.initialize(self, parser)
+ parser.add_argument('--optim', type=str, default='adam', help='optim to use [sgd, adam]')
+ parser.add_argument('--loss_freq', type=int, default=100, help='frequency of showing loss on tensorboard')
+ parser.add_argument('--save_epoch_freq', type=int, default=1,
+ help='frequency of saving checkpoints at the end of epochs')
+ parser.add_argument('--train_split', type=str, default='train', help='train, val, test, etc')
+ parser.add_argument('--val_split', type=str, default='val', help='train, val, test, etc')
+ parser.add_argument('--epoch', type=int, default=100, help='total epoches')
+ parser.add_argument('--beta1', type=float, default=0.9, help='momentum term of adam')
+ parser.add_argument('--lr', type=float, default=2e-9, help='initial learning rate for adam')
+ parser.add_argument('--pretrained_model', type=str, default='./checkpoints/experiment_name/model_epoch_29.pth', help='model will fine tune on it if fine-tune is True')
+ parser.add_argument('--fine-tune', type=bool, default=True)
+ self.isTrain = True
+
+ return parser
diff --git a/clean/video/lipfd/preprocess.py b/clean/video/lipfd/preprocess.py
new file mode 100644
index 0000000000000000000000000000000000000000..16fefbda6b1e32bfa6a26c71c82bc49d49ad59cc
--- /dev/null
+++ b/clean/video/lipfd/preprocess.py
@@ -0,0 +1,125 @@
+import os
+import cv2
+import numpy as np
+import librosa
+import matplotlib.pyplot as plt
+from tqdm import tqdm
+from librosa import feature as audio
+
+
+"""
+Structure of the AVLips dataset:
+AVLips
+├── 0_real
+├── 1_fake
+└── wav
+ ├── 0_real
+ └── 1_fake
+"""
+
+############ Custom parameter ##############
+N_EXTRACT = 10 # number of extracted images from video
+WINDOW_LEN = 5 # frames of each window
+MAX_SAMPLE = 100
+
+audio_root = "./AVLips/wav"
+video_root = "./AVLips"
+output_root = "./datasets/AVLips"
+############################################
+
+labels = [(0, "0_real"), (1, "1_fake")]
+
+def get_spectrogram(audio_file):
+ data, sr = librosa.load(audio_file)
+ mel = librosa.power_to_db(audio.melspectrogram(y=data, sr=sr), ref=np.min)
+ plt.imsave("./temp/mel.png", mel)
+
+
+def run():
+ i = 0
+ for label, dataset_name in labels:
+ if not os.path.exists(dataset_name):
+ os.makedirs(f"{output_root}/{dataset_name}", exist_ok=True)
+
+ if i == MAX_SAMPLE:
+ break
+ root = f"{video_root}/{dataset_name}"
+ video_list = os.listdir(root)
+ print(f"Handling {dataset_name}...")
+ for j in tqdm(range(len(video_list))):
+ v = video_list[j]
+ # load video
+ video_capture = cv2.VideoCapture(f"{root}/{v}")
+ fps = video_capture.get(cv2.CAP_PROP_FPS)
+ frame_count = int(video_capture.get(cv2.CAP_PROP_FRAME_COUNT))
+
+ # select 10 starting point from frames
+ frame_idx = np.linspace(
+ 0,
+ frame_count - WINDOW_LEN - 1,
+ N_EXTRACT,
+ endpoint=True,
+ dtype=np.uint8,
+ ).tolist()
+ frame_idx.sort()
+ # selected frames
+ frame_sequence = [
+ i for num in frame_idx for i in range(num, num + WINDOW_LEN)
+ ]
+ frame_list = []
+ current_frame = 0
+ while current_frame <= frame_sequence[-1]:
+ ret, frame = video_capture.read()
+ if not ret:
+ print(f"Error in reading frame {v}: {current_frame}")
+ break
+ if current_frame in frame_sequence:
+ frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
+ frame_list.append(cv2.resize(frame, (500, 500))) # to floating num
+ current_frame += 1
+ video_capture.release()
+
+ # load audio
+ name = v.split(".")[0]
+ a = f"{audio_root}/{dataset_name}/{name}.wav"
+
+ group = 0
+ get_spectrogram(a)
+ mel = plt.imread("./temp/mel.png") * 255 # load spectrogram (int)
+ mel = mel.astype(np.uint8)
+ mapping = mel.shape[1] / frame_count
+ for i in range(len(frame_list)):
+ idx = i % WINDOW_LEN
+ if idx == 0:
+ try:
+ begin = np.round(frame_sequence[i] * mapping)
+ end = np.round((frame_sequence[i] + WINDOW_LEN) * mapping)
+ sub_mel = cv2.resize(
+ (mel[:, int(begin) : int(end)]), (500 * WINDOW_LEN, 500)
+ )
+ x = np.concatenate(frame_list[i : i + WINDOW_LEN], axis=1)
+ # print(x.shape)
+ # print(sub_mel.shape)
+ x = np.concatenate((sub_mel[:, :, :3], x[:, :, :3]), axis=0)
+ # print(x.shape)
+ plt.imsave(
+ f"{output_root}/{dataset_name}/{name}_{group}.png", x
+ )
+ group = group + 1
+ except ValueError:
+ print(f"ValueError: {name}")
+ continue
+ # print(frame_sequence)
+ # print(frame_count)
+ # print(mel.shape[1])
+ # print(mapping)
+ # exit(0)
+ i += 1
+
+
+if __name__ == "__main__":
+ if not os.path.exists(output_root):
+ os.makedirs(output_root, exist_ok=True)
+ if not os.path.exists("./temp"):
+ os.makedirs("./temp", exist_ok=True)
+ run()
diff --git a/clean/video/lipfd/requirements.txt b/clean/video/lipfd/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6b3606abf823a0e93a1a9a6b008897952f7c2933
--- /dev/null
+++ b/clean/video/lipfd/requirements.txt
@@ -0,0 +1,10 @@
+ftfy==6.1.1
+librosa==0.10.1
+matplotlib==3.8.0
+numpy==1.25.2
+opencv-contrib-python==4.8.1.78
+opencv-python==4.8.1.78
+scikit-learn==1.3.1
+torch==2.1.0
+torchvision==0.16.0
+tqdm==4.66.1
\ No newline at end of file
diff --git a/clean/video/lipfd/train.py b/clean/video/lipfd/train.py
new file mode 100644
index 0000000000000000000000000000000000000000..67c258c2255511e990961bcc21b3a6ecb321165e
--- /dev/null
+++ b/clean/video/lipfd/train.py
@@ -0,0 +1,56 @@
+from validate import validate
+from data import create_dataloader
+from trainer.trainer import Trainer
+from options.train_options import TrainOptions
+
+
+def get_val_opt():
+ val_opt = TrainOptions().parse(print_options=False)
+ val_opt.isTrain = False
+ val_opt.data_label = "val"
+ val_opt.real_list_path = "./datasets/val/0_real"
+ val_opt.fake_list_path = "./datasets/val/1_fake"
+ return val_opt
+
+
+if __name__ == "__main__":
+ opt = TrainOptions().parse()
+ val_opt = get_val_opt()
+ model = Trainer(opt)
+
+ data_loader = create_dataloader(opt)
+ val_loader = create_dataloader(val_opt)
+
+ print("Length of data loader: %d" % (len(data_loader)))
+ print("Length of val loader: %d" % (len(val_loader)))
+
+ for epoch in range(opt.epoch):
+ model.train()
+ print("epoch: ", epoch + model.step_bias)
+ for i, (img, crops, label) in enumerate(data_loader):
+ model.total_steps += 1
+
+ model.set_input((img, crops, label))
+ model.forward()
+ loss = model.get_loss()
+
+ model.optimize_parameters()
+
+ if model.total_steps % opt.loss_freq == 0:
+ print(
+ "Train loss: {}\tstep: {}".format(
+ model.get_loss(), model.total_steps
+ )
+ )
+
+ if epoch % opt.save_epoch_freq == 0:
+ print("saving the model at the end of epoch %d" % (epoch + model.step_bias))
+ model.save_trainer("model_epoch_%s.pth" % (epoch + model.step_bias))
+
+ model.eval()
+ ap, fpr, fnr, acc = validate(model.model, val_loader, opt.gpu_ids)
+ print(
+ "(Val @ epoch {}) acc: {} ap: {} fpr: {} fnr: {}".format(
+ epoch + model.step_bias, acc, ap, fpr, fnr
+ )
+ )
diff --git a/clean/video/lipfd/trainer/trainer.py b/clean/video/lipfd/trainer/trainer.py
new file mode 100644
index 0000000000000000000000000000000000000000..0904c31d5ae0485afbbdcb023f43632822af9fc1
--- /dev/null
+++ b/clean/video/lipfd/trainer/trainer.py
@@ -0,0 +1,112 @@
+import os
+import torch
+import torch.nn as nn
+from models import build_model, get_loss
+
+
+class Trainer(nn.Module):
+ def __init__(self, opt):
+ self.opt = opt
+ self.total_steps = 0
+ self.save_dir = os.path.join(opt.checkpoints_dir, opt.name)
+ self.device = (
+ torch.device("cuda:{}".format(opt.gpu_ids[0]))
+ if opt.gpu_ids
+ else torch.device("cpu")
+ )
+ self.opt = opt
+ self.model = build_model(opt.arch)
+
+ self.step_bias = (
+ 0
+ if not opt.fine_tune
+ else int(opt.pretrained_model.split("_")[-1].split(".")[0]) + 1
+ )
+ if opt.fine_tune:
+ state_dict = torch.load(opt.pretrained_model, map_location="cpu")
+ self.model.load_state_dict(state_dict["model"])
+ self.total_steps = state_dict["total_steps"]
+ print(f"Model loaded @ {opt.pretrained_model.split('/')[-1]}")
+
+ if opt.fix_encoder:
+ params = []
+ for name, p in self.model.named_parameters():
+ if name.split(".")[0] in ["encoder"]:
+ p.requires_grad = False
+ else:
+ p.requires_grad = False
+ params = self.model.parameters()
+
+ if opt.optim == "adam":
+ self.optimizer = torch.optim.AdamW(
+ params,
+ lr=opt.lr,
+ betas=(opt.beta1, 0.999),
+ weight_decay=opt.weight_decay,
+ )
+ elif opt.optim == "sgd":
+ self.optimizer = torch.optim.SGD(
+ params, lr=opt.lr, momentum=0.0, weight_decay=opt.weight_decay
+ )
+ else:
+ raise ValueError("optim should be [adam, sgd]")
+
+ self.criterion = get_loss().to(self.device)
+ self.criterion1 = nn.CrossEntropyLoss()
+
+ self.model.to(opt.gpu_ids[0] if torch.cuda.is_available() else "cpu")
+
+ def adjust_learning_rate(self, min_lr=1e-8):
+ for param_group in self.optimizer.param_groups:
+ if param_group["lr"] < min_lr:
+ return False
+ param_group["lr"] /= 10.0
+ return True
+
+ def set_input(self, input):
+ self.input = input[0].to(self.device)
+ self.crops = [[t.to(self.device) for t in sublist] for sublist in input[1]]
+ self.label = input[2].to(self.device).float()
+
+ def forward(self):
+ self.get_features()
+ self.output, self.weights_max, self.weights_org = self.model.forward(
+ self.crops, self.features
+ )
+ self.output = self.output.view(-1)
+ self.loss = self.criterion(
+ self.weights_max, self.weights_org
+ ) + self.criterion1(self.output, self.label)
+
+ def get_loss(self):
+ loss = self.loss.data.tolist()
+ return loss[0] if isinstance(loss, type(list())) else loss
+
+ def optimize_parameters(self):
+ self.optimizer.zero_grad()
+ self.loss.backward()
+ self.optimizer.step()
+
+ def get_features(self):
+ self.features = self.model.get_features(self.input).to(
+ self.device
+ ) # shape: (batch_size
+
+ def eval(self):
+ self.model.eval()
+
+ def test(self):
+ with torch.no_grad():
+ self.forward()
+
+ def save_networks(self, save_filename):
+ save_path = os.path.join(self.save_dir, save_filename)
+
+ # serialize model and optimizer to dict
+ state_dict = {
+ "model": self.model.state_dict(),
+ "optimizer": self.optimizer.state_dict(),
+ "total_steps": self.total_steps,
+ }
+
+ torch.save(state_dict, save_path)
diff --git a/clean/video/lipfd/utils.py b/clean/video/lipfd/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..74a86346e96198ca2e6f15e18c664bcbcde11a77
--- /dev/null
+++ b/clean/video/lipfd/utils.py
@@ -0,0 +1,10 @@
+import os
+
+def get_list(path) -> list:
+ r"""Recursively read all files in root path"""
+ image_list = list()
+ for root, dirs, files in os.walk(path):
+ for f in files:
+ if f.split('.')[1] in ['png', 'jpg', 'jpeg']:
+ image_list.append(os.path.join(root, f))
+ return image_list
\ No newline at end of file
diff --git a/clean/video/lipfd/validate.py b/clean/video/lipfd/validate.py
new file mode 100644
index 0000000000000000000000000000000000000000..533c5c4724ebe826690034c6676620c8c87362a7
--- /dev/null
+++ b/clean/video/lipfd/validate.py
@@ -0,0 +1,63 @@
+import argparse
+import torch
+import numpy as np
+from data import AVLip
+import torch.utils.data
+from models import build_model
+from sklearn.metrics import average_precision_score, confusion_matrix, accuracy_score
+
+
+def validate(model, loader, gpu_id):
+ print("validating...")
+ device = torch.device(f"cuda:{gpu_id[0]}" if torch.cuda.is_available() else "cpu")
+ with torch.no_grad():
+ y_true, y_pred = [], []
+ for img, crops, label in loader:
+ img_tens = img.to(device)
+ crops_tens = [[t.to(device) for t in sublist] for sublist in crops]
+ features = model.get_features(img_tens).to(device)
+
+ y_pred.extend(model(crops_tens, features)[0].sigmoid().flatten().tolist())
+ y_true.extend(label.flatten().tolist())
+ y_true = np.array(y_true)
+ y_pred = np.where(np.array(y_pred) >= 0.5, 1, 0)
+
+ # Get AP
+ ap = average_precision_score(y_true, y_pred)
+ cm = confusion_matrix(y_true, y_pred)
+ tp, fn, fp, tn = cm.ravel()
+ fnr = fn / (fn + tp)
+ fpr = fp / (fp + tn)
+ acc = accuracy_score(y_true, y_pred)
+ return ap, fpr, fnr, acc
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+ parser.add_argument("--real_list_path", type=str, default="./datasets/val/0_real")
+ parser.add_argument("--fake_list_path", type=str, default="./datasets/val/1_fake")
+ parser.add_argument("--max_sample", type=int, default=1000, help="max number of validate samples")
+ parser.add_argument("--batch_size", type=int, default=10)
+ parser.add_argument("--data_label", type=str, default="val")
+ parser.add_argument("--arch", type=str, default="CLIP:ViT-L/14")
+ parser.add_argument("--ckpt", type=str, default="./checkpoints/ckpt.pth")
+ parser.add_argument("--gpu", type=int, default=0)
+
+ opt = parser.parse_args()
+
+ device = torch.device(f"cuda:{opt.gpu}" if torch.cuda.is_available() else "cpu")
+ print(f"Using cuda {opt.gpu} for inference.")
+
+ model = build_model(opt.arch)
+ state_dict = torch.load(opt.ckpt, map_location="cpu")
+ model.load_state_dict(state_dict["model"])
+ print("Model loaded.")
+ model.eval()
+ model.to(device)
+
+ dataset = AVLip(opt)
+ loader = data_loader = torch.utils.data.DataLoader(
+ dataset, batch_size=opt.batch_size, shuffle=True
+ )
+ ap, fpr, fnr, acc = validate(model, loader, gpu_id=[opt.gpu])
+ print(f"acc: {acc} ap: {ap} fpr: {fpr} fnr: {fnr}")
diff --git a/clean/video/mintime/.gitignore b/clean/video/mintime/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..b4e20e28c5225ee552094037026b2f68c317b699
--- /dev/null
+++ b/clean/video/mintime/.gitignore
@@ -0,0 +1,13 @@
+*/__pycache__
+*/support_files
+*/ouputs
+outputs
+preprocessing/data_preparation.py
+preprocessing/get_sizes_ranges.py
+__pycache__
+timesformer.py
+runs
+weights
+test_linear.py
+test_timesformer.py
+
diff --git a/clean/video/mintime/README.md b/clean/video/mintime/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..961c194356a5b659df75db8a4cd0d0e821dcc40f
--- /dev/null
+++ b/clean/video/mintime/README.md
@@ -0,0 +1,525 @@
+# MINTIME-DF Multi-Identity size-iNvariant TIMEsformer for Video Deepfake Detection
+
+
+
+# [Paper](https://ieeexplore.ieee.org/document/10547206)
+
+[](https://paperswithcode.com/sota/classification-on-forgerynet?p=mintime-multi-identity-size-invariant-video)
+
+## Motivations behind this study
+The continuing advancement of deepfake generation techniques and the increasingly credible results obtained through these, makes it increasingly urgent to develop new techniques to distinguish a manipulated video from a real one. This is, however, a far from simple task that introduces multiple challenges to be overcome, challenges that form the basis of this research work.
+- Generalization of the Deepfake concept : Deepfake generation methods tend to introduce specific anomalies within images and videos. Deepfake detection models often tend to learn to recognise these specific anomalies and are therefore ineffective in the real world when dealing with unseen manipulations. Our previous studies in this area suggest a greater capacity for generalisation by Vision Transformers than by Convolutional Neural Networks [Coccomini et al, 2022 ];
+- Ability to pick up both spatial and temporal anomalies within a video : Very often the anomalies that are searched for by deepfake detectors are exclusively spatial with frame-by-frame classifications. However, some important anomalies lie precisely in the variation of the face over time, which can be unnatural and thus allow a manipulated video to be identified;
+- Handling of multiple faces within the same video : A specific situation that can be exploited by an attacker to deceive a deepfake detection system is found in the case of videos or images with multiple faces (identities). An attacker could in fact decide to manipulate only one of the people in the video. However, if the detection is carried out en bloc for all the faces in the video, the negative contribution to the final prediction made by the fake faces could be 'masked' by the non-manipulated ones, thus deceiving the system.
+- Management of different face-frame area ratios : Typically in deepfake detection systems, the person's face is extracted from the video or image to be classified and before being given as input to a neural model it is rescaled to be uniform with all the others. This results in an important loss of information, namely the ratio of the area of the subject's face to the rest of the scene.
+
+To solve all these problems, we propose a Size-Invariant Multi-Identity Transformer-based architecture which exploits a novel form of Divided Space-Time attention.
+The new features, strengths and advantages introduced by our approach are as follows:
+- Ability of our model to capture both spatial and temporal anomalies in a deepfake video by jointly exploiting both a convolutional network and a variant of the Transformer namely the TimeSformer;
+- Ability to handle multi-identity cases effectively. In previous approaches, there is a tendency to ignore people who appear with a lower frequency in the video and to only analyze faces extracted from the most frequent identity. However, in the real world, this can result in a flaw that can be exploited by an attacker who might, for instance, deliberately decide to manipulate a face of an identity that appears for a smaller portion of the video than others and thus escape the deepfake detection algorithms. Our approach, through the introduction of several architectural innovations such as 'Adaptive Input Sequence Assignment', 'Temporal Positional Embedding' and 'Identity-based Attention Calculation', is able to handle any number of identities while remaining robust in terms of classification accuracy. The Adaptive Sequence Assignment approach is designed to construct the input sequence to the model coherently even in the presence of multiple identities. Temporal Positional Embedding is a modification to the classical positional embedding of Transformers that keeps tokens not only spatially but also temporally consistent in terms of the identities to which they belong. Finally, Identity-based Attention calculation is a particular way of calculating attention that we have developed so that the network first focuses separately on the different identities that occur in the video and then converges to a single CLS token that is influenced by and common to all of them. This CLS is finally used for the final video-level classification.
+- Ability to handle different face-frame area ratios through the introduction of 'Size Embedding'. Typically in deepfake detection systems, the person's face is extracted from the video or image to be classified and before being given as input to a neural model it is rescaled to be uniform with all the others. This results in an important loss of information, namely the ratio of the area of the subject's face to the rest of the scene. This may be reflected in missclassification with faces with a particular ratio being classified as fakes even though they are not.
+- Explainability of the results by analyzing the attention maps produced by the model. By looking at the attention values assigned by the model to the tokens associated with the individual faces as input, it is possible to obtain a more refined classification that is not only limited to saying whether or not the video is fake but also which of the multiple identities, if any, were manipulated and at what point in the video.
+- Near state-of-the-art results on ForgeryNet dataset.
+- Generalization capability on unseen deepfake generation methods demonstrated by analyzing the results obtained on approaches not considered in the training set obtaining or surpassing state-of-the-art accuracies on all setups.
+
+
+## Setup
+Clone the repository and move into it:
+
+```
+git clone https://github.com/davide-coccomini/MINTIME-Multi-Identity-size-iNvariant-TIMEsformer-for-Video-Deepfake-Detection.git
+
+cd MINTIME-Multi-Identity-size-iNvariant-TIMEsformer-for-Video-Deepfake-Detection
+```
+
+Setup Python environment using conda:
+
+```
+conda env create --file environment.yml
+conda activate deepfakes
+export PYTHONPATH=.
+```
+
+
+## Run Deepfake Detection on a video
+If you want to directly classify a video using pre-trained models, you can download the weights from the model zoo and use the following command:
+
+```
+python3 predict.py --video_path path/to/video.mp4 --model_weights path/to/model_weights --extractor_weights path/to/extractor_weights --config config/size_invariant_timesformer.yaml
+```
+
+The output video will be stored in the examples/preds folder:
+
+
+For purposes of explainability the attention maps on the various slots of the input sequence are also saved. These are used to discover, in the multi-identity case, which identity is fake in each frame.
+
+In the following example, the 16 slots are distributed between the two identities according to the number of available faces, the first 6 for identity 0 (the man), the second 6 for identity 1 (the woman). The remaining 4 slots are ignored as there are no additional faces to fill them.
+The attention values extracted from the various heads are combined considering the maximum values for each tokens. The tokens are then grouped according to the frame and identity they refer to, resulting in 16 attention values (of which 4 are null). The spatial and temporal attention is combined to obtain the final value via the average function. Finally, the softmax function is applied to emphasise the differences between the attention placed on one face rather than another.
+
+In this case, the attention in frame 20 of the second identity is particularly high, which indicates that there is an anomaly there.
+
+
+
+## Model ZOO
+
+To download the pre-trained models available click here .
+
+### Models comparison
+| Model | Identities | Accuracy | AUC |
+| --------------- | --------------- | --------------- | --------------- |
+| MINTIME-XC | 1 | 85.96 | 93.20 |
+| MINTIME-XC | 2 | 87.64 | 94.25 |
+| MINTIME-XC | 3 | 86.98 | 94.10 |
+| SlowFast R-50 Retrained | 1 | 82.59 | 90.86 |
+| SlowFast R-50 | 1 | 88.78 | 93.88 |
+| X3D-M | 1 | 87.93 | 93.75 |
+| MINTIME-EF | 1 | 81.92 | 90.13 |
+| MINTIME-EF | 2 | 82.28 | 90.45 |
+| MINTIME-EF | 3 | 82.05 | 90.28 |
+| EfficientNet-B0 + MLP | 1 | 65.33 | 71.42 |
+| EfficientNet-B0 + MLP | 2 | 67.03 | 71.05 |
+| EfficientNet-B0 + MLP | 3 | 66.89 | 70.92 |
+
+
+### Multi-Identity videos only
+Accuracy obtained from models on multi-identity videos only.
+
+| Model | Accuracy | AUC |
+| ---- | ---- | ---- |
+| MINTIME-XC | 86.68 | 94.12 |
+| MINTIME-EF | 81.21 | 89.56 |
+| SlowFast R-50 Retrained | 72.63 | 80.92 |
+| EfficientNet-B0 + MLP | 67.69 | 74.26 |
+
+
+### Per-class accuracy
+Accuracy obtained by the models on the various deepfake generation methods in the test set.
+| Model |Pristines | Method 1 | Method 2 | Method 3 | Method 4 | Method 5 | Method 6 | Method 7 | Method 8 | FPR |
+| --------------- | --------------- | --------------- | --------------- | --------------- | --------------- | --------------- | --------------- | --------------- | --------------- | --------------- |
+| MINTIME-XC | 88.15 | 79.94 | 84.64 | 82.17 | 84.05 | 77.59 | 85.37 | 92.03 | 79.91 | 14.06 |
+| MINTIME-EF | 85.84 | 70.05 | 69.75 | 74.55 | 82.05 | 78.14 | 79.59 | 91.49 | 77.03 | 14.16 |
+| SlowFast R-50 Retrained | 84.65 | 69.70 | 71.71 | 81.19 | 81.35 | 78.67 | 88.43 | 88.96 | 92.05 | 15.34 | 22.36 |
+| EfficientNet-B0 + MLP | 51.68 | 67.67 | 84.41 | 67.58 | 65.80 | 78.68 | 69.72 | 92.87 | 79.04 | 48.31 |
+
+
+### Size Embedding evaluation
+| Model | Identities| Accuracy | AUC |
+| --------------- | --------------- | --------------- | --------------- |
+| MINTIME-EF with size-embedding | 2 | 82.05 | 90.28 |
+| MINTIME-EF w/o size-embedding | 2 | 81.83 | 90.13 |
+| MINTIME-XC with size-embedding | 2 | 87.64 | 94.25 |
+| MINTIME-XC w/o size-embedding | 2 | 87.13 | 94.03 |
+
+
+
+### Cross-Forgery Analysis
+
+| | | ID-replaced | ID-remained | Identities |
+| --------------- | --------------- | --------------- | --------------- | --------------- |
+| | | Accuracy | Accuracy | |
+| X3D-M | ID-replaced | 87.92 | 55.25 | 1 |
+| | ID-remained | 55.93 | 88.85 | |
+| SlowFast | ID-replaced | 88.26 | 52.64 | 1 |
+| | ID-remained | 52.70 | 87.96 | |
+| MINTIME-XC | ID-replaced | 86.58 | 84.02 | 2 |
+| | ID-remained | 64.01 | 92.08 | |
+| MINTIME-EF | ID-replaced | 80.18 | 79.03 | 2 |
+| | ID-remained | 63.13 | 89.22 | |
+
+| | | ID-replaced | ID-remained | Identities |
+| --------------- | --------------- | --------------- | --------------- | --------------- |
+| | | AUC | AUC | |
+| X3D-M | ID-replaced | 92.91 | 65.59| 1 |
+| | ID-remained | 62.87 | 95.40| |
+| SlowFast | ID-replaced | 92.88 | 64.83| 1 |
+| | ID-remained | 61.50 | 95.47| |
+| MINTIME-XC | ID-replaced | 93.66 | 88.43| 2 |
+| | ID-remained | 68.53 | 97.26| |
+| MINTIME-EF | ID-replaced | 83.86 | 86.98| 2 |
+| | ID-remained | 66.26 | 95.02| |
+
+### Cross-Dataset Analysis
+| Model | Identities | AUC |
+| --------------- | --------------- | --------------- |
+| Face X-ray | 1 | 65.50 |
+| Patch-based | 1 | 65.60 |
+| DSP-FWA | 1 | 67.30 |
+| CSN | 1 | 68.10 |
+| Multi-Task | 1 | 68.10 |
+| CNN-GRU | 1 | 68.90 |
+| Xception | 1 | 70.90 |
+| CNN-aug | 1 | 72.10 |
+| LipForensics | 1 | 73.50 |
+| FTCN | 1 | 74.00 |
+| RealForensics | 1 | 75.90 |
+| MINTIME-EF | 2 | 68.57 |
+| MINTIME-XC | 2 | 77.92 |
+
+
+
+### Multi-Identity Approaches evaluation
+Considering only multi-identity videos
+
+| Model | Identities | Temporal Positional Embedding | Multi-Identity Attention | AUC |
+| --------------- | --------------- | --------------- | --------------- | --------------- |
+| MINTIME-XC | 2 | ✓ | ✓ | 94.12 |
+| MINTIME-XC | 2 | X | X | 93.29 |
+| MINTIME-XC | 3 | ✓ | ✓ | 93.32 |
+| MINTIME-XC | 3 | X | X | 90.57 |
+
+
+## Dataset
+In order to conduct our research, it was necessary to analyse the various datasets in circulation in order to identify the one with the following characteristics:
+- Containing a sufficient number of videos for effective training;
+- Presence of multi-faces videos;
+- Multiple face-frame area ratios present in the videos;
+- Large variety of subjects, scenes, perturbations, manipulation techniques.
+
+For these reasons, ForgeryNet was chosen as the dataset for our experiments. It is in fact characterised by a number of videos equal to 221,247 divided into 99,630 pristine videos and 121,617 manipulated ones with a frame rate between 20 and 30 FPS and variable duration.
+From an analysis conducted during our research, we identified the presence of 11,785 video multi-faces with a maximum of 23 faces per video. The face-frame area ratio also appears to be highly distributed with videos containing faces covering an area up to almost, in some rare cases, even 100% of the entire image.
+
+
+
+Furthermore, the EfficientNet B0 used as a patch extraction backbone was trained in our previous research work on the DFDC and FaceForensics++ datasets.
+
+The datasets can be downloaded at the following links:
+- ForgeryNet: https://yinanhe.github.io/projects/forgerynet.html#download
+- DFDC: https://dfdc.ai/
+- FaceForensics++: https://github.com/ondyari/FaceForensics/blob/master/dataset/
+
+
+## Preprocessing
+In order to use the proposed model, some preprocessing steps are required to convert the ForgeryNet into the desired format.
+
+In case you want to retrain the convolutional backbone patch extraction the preprocessing of DFDC and FaceForensics++ datasets, the procedure is described in this repository . Otherwise you can directly use the pretrained model as explained in the training section.
+
+### Face Detection and Extraction
+To perform deepfake detection it is necessary to first identify and extract faces from all the videos in the dataset.
+Detect the faces inside the videos:
+```
+cd preprocessing
+python3 detect_faces.py --data_path "path/to/videos"
+```
+
+The extracted boxes will be saved inside the "path/to/videos/boxes" folder.
+In order to get the best possible result, make sure that at least one face is identified in each video. If not, you can reduce the threshold values of the MTCNN on line 38 of face_detector.py and run the command again until at least one detection occurs.
+At the end of the execution of face_detector.py an error message will appear if the detector was unable to find faces inside some videos.
+
+If you want to manually check that at least one face has been identified in each video, make sure that the number of files in the "boxes" folder is equal to the number of videos. To count the files in the folder use:
+```
+cd path/to/videos/boxes
+ls | wc -l
+```
+
+Extract the detected faces obtaining the images:
+```
+python3 extract_crops.py --data_path "path/to/videos" --output_path "path/to/output"
+```
+
+Repeat detection and extraction for all the different parts of your dataset.
+
+After extracting all the faces from the videos in your dataset, organise the "dataset" folder as follows:
+```
+- ForgeryNet
+ - Training
+ - crops
+ - train_video_release
+ - 1
+ - video_name_0
+ 0_0.png
+ 1_0.png
+ 2_0.png
+ ...
+ N_0.png
+ ...
+ - video_name_K
+ 0_0.png
+ 1_0.png
+ 2_0.png
+ ...
+ M_0.png
+ ...
+ - 19
+ - video_name_0
+ 0_0.png
+ 1_0.png
+ 2_0.png
+ ...
+ S_0.png
+ ...
+ - video_name_Y
+ 0_0.png
+ 1_0.png
+ 2_0.png
+ ...
+ J_0.png
+ - Validation
+ - crops
+ - val_video_release
+ ...
+ ...
+ ...
+ ...
+ ...
+```
+
+We suggest to exploit the --output_path parameter when executing extract_crops.py to build the folders structure properly.
+
+
+### Split the Dataset
+Since the labels of the ForgeryNet test set were not made public at the time of the study, the Validation Set will be used as our Test Set while our Validation Set is obtained through a customised split on the distribution of the training set.
+The CSV files containing the videos belonging to each set are available in the "splits" folder, however, should you wish to redo the process of splitting the dataset, you can follow the steps below.
+```
+cd preprocessing
+python3 split_dataset.py --train_list_file path/to/training_list_file.txt --validation_list_file path/to/validation_list_file.txt
+```
+The script will analyse the distribution of deepfake generation methods in the training set and move the videos within three separate folders train, val and test accordingly inside the "faces" folder.
+
+
+
+
+The dataset at the end of this process will have the following structure:
+
+```
+- ForgeryNet
+ - faces
+ - train
+ - 1
+ - video_name_0
+ 0_0.png
+ 1_0.png
+ 2_0.png
+ ...
+ N_0.png
+ ...
+ - video_name_K
+ 0_0.png
+ 1_0.png
+ 2_0.png
+ ...
+ M_0.png
+ ...
+ - 19
+ - video_name_0
+ 0_0.png
+ 1_0.png
+ 2_0.png
+ ...
+ S_0.png
+ ...
+ - video_name_Y
+ 0_0.png
+ 1_0.png
+ 2_0.png
+ ...
+ J_0.png
+ - val
+ ...
+ ...
+ ...
+
+ - test
+ ...
+ ...
+ ...
+
+```
+
+This split was used only as an additional experimental field but all the reported results are obtained on the ForgeryNet Validation set.
+
+### Identity Clustering
+Having to manage multi-face videos and wanting to detect temporal and not just spatial anomalies, it is necessary to clustered the faces in each video on the basis of their similarity and maintaining the temporal order of their appearance in the frames. To do this, a clustering algorithm was developed that groups the faces extracted from the videos into sequences.
+
+To run the clustering split use the following commands:
+```
+cd preprocessing
+python3 cluster_faces.py --faces_path path/to/faces
+```
+
+The algorithm is structured as follows:
+- The features of each face are extracted via an InceptionResnetV1 pretrained on FaceNet;
+- The distance between each face and all faces identified in the video is calculated;
+- A graph is constructed with hard connection if the similarity is higher than the threshold;
+- Clusters are obtained based on the graph and small clusters are discarded;
+- The faces inside the clusters are temporally reordered;
+- The clusters are enumerated based on mean faces size during data loading.
+
+
+
+
+The following parameters can be changed as desired to achieve different clustering:
+- --similarity_threshold: Threshold used to discard faces with high distance value (default 0.8);
+- --valid_cluster_size_ratio: Valid cluster size percentage (default: 0.2)
+
+The dataset at the end of this process will have the following structure:
+```
+- ForgeryNet
+ - faces
+ - train
+ - 1
+ - video_name_0
+ - identity_0
+ 0_0.png
+ 1_0.png
+ 2_0.png
+ ...
+ D_0.png
+ ...
+ - identity_U
+ 0_0.png
+ 1_0.png
+ 2_0.png
+ ...
+ T_0.png
+ ...
+ - video_name_K
+ - identity_0
+ 0_0.png
+ 1_0.png
+ 2_0.png
+ ...
+ P_0.png
+ ...
+ - identity_X
+ 0_0.png
+ 1_0.png
+ 2_0.png
+ ...
+ R_0.png
+ ...
+ - 19
+ ...
+ ...
+ ...
+ - val
+ ...
+ ...
+ ...
+ ...
+
+ - test
+ ...
+ ...
+ ...
+ ...
+```
+
+## Training
+After transforming each video in the dataset into temporally and spatially coherent sequences, one can move on to the training phase of the model.
+
+To download the pretrained weights of the models you can run the following commands:
+```
+mkdir weights
+cd weights
+wget ...
+wget ...
+wget ...
+```
+
+
+If you are unable to use the previous urls you can download the weights from [Google Drive](https://drive.google.com/drive/folders/19bNOs8_rZ7LmPP3boDS3XvZcR1iryHR1?usp=sharing).
+
+
+The network is trained to perform pristine/fake binary classification. The features are extracted from a pertrained EfficientNet B0 and the training of the TimeSformer is also influenced by the presence of an additional embedding, namely the size embedding. It is calculated from the face-frame area ratio for each face of the video and concatenated to each token obtained from it.
+
+
+
+### Masking and Sampling
+The number of frames per video, and thus consecutive faces to be considered for classification, is set via the num-frames parameter in the configuration file. In the event that there are fewer faces in the considered identity than necessary, more empty ones are added and then a mask is used to drive the calculation of attention properly. In the case of longer sequences, however, uniform sampling is performed. Like a kind of data augmentation, this uniform sampling is performed by alternating various combinations of frames as shown in figure.
+
+
+
+
+### Adaptive Input Sequence Assignment
+To enable the model to handle multiple identities within one video, the number of available frames is divided among the identities of the video.
+The maximum number of identities per video is set via the max-identities parameter in the configuration file.
+
+The identities are reordered according to the size of the faces within them, and the most important identities are given a higher number of frames to be exploited in the input sequence, in order to give more importance to faces that cover a larger area and are therefore likely to be more relevant in the video, as opposed to smaller faces.
+
+
+
+In the event that an identity does not have enough faces to satisfy the number of slots allocated to it, the remaining slots are inherited by the next identity.
+
+
+
+### Temporal Coherent Positional Embedding
+Classical positional embedding was then evolved to ensure temporal consistency between frames as well as spatial consistency between tokens.
+Tokens are numbered in such a way that two faces, of different identities but belonging to the same frame, have the same numbering.
+Temporal coherence is maintained both locally by having an increasing numbering sequence as well as the frames from which the faces originate and globally by being generated on the basis of the global distribution of frames of all identities in the video.
+In this first example, the two sequences are of the same length and have the same frame numbering. Therefore, the tokens are also numbered in the same way.
+
+
+In example number two, however, although the two identities have the same number of faces, they are extracted from different frames. The numbering of the tokens therefore in this case, in addition to being generated by taking the sequentiality locally for each identity into account, is also assigned on the basis of the global distribution of frames.
+
+
+### Identity-based Attention Calculation
+For our TimeSformer we apply the version of attention that was most effective in the original paper, namely Divided Space-Time Attention. Attention is calculated spatially between all patches in the same frame, but is then also calculated between the corresponding patches in the next and previous frames using a moving window.
+
+
+
+As far as spatial attention is concerned, no further effort is required for this to be applied to our case.
+Not being interested in capturing the relationships between faces of different identities, the calculation of temporal attention in our case is carried out exclusively between faces belonging to the same identity.
+
+
+
+All faces, however, influence the CLS that is global and unique for all identities.
+In the animation below, it is shown how attention is calculated exclusively by tokens referring to identity 0 faces (green), ignoring those referring to identity 1 faces (red) and vice versa. While all refer to the global CLS.
+
+
+
+### Multi-Face Size-Invariant TimeSformer
+
+
+
+To run the training process use the following commands:
+```
+python3 train.py --config config/size_invariant_timesformer.yaml --model 1 --train_list_file path/to/training_list_file.txt --validation_list_file path/to/validation_list_file.txt --extractor_weights path/to/backbone_weights
+```
+
+The following parameters can be changed as desired to perform different training:
+- --num_epochs: Number of training epochs (default: 300);
+- --resume: Path to latest checkpoint (default: none);
+- --restore_epoch: Restart from the checkpoint's epoch if --resume option specified (default: False)
+- --freeze_backbone: Maintain the network freezed or train it (default: False);
+- --extractor_unfreeze_blocks: Number of blocks to train in the backbone (default: All);
+- --max_videos: Maximum number of videos to use for training (default: all);
+- --patience: How many epochs wait before stopping for validation loss not improving (default: 5);
+- --logger_name: Path to the folder for tensorboard logging (default: runs/train);
+
+
+### Baseline
+To validate the real effectiveness of the implementation choices made on the presented architecture, we also conducted some alternative architecture training. In particular, the simplest of the two consists of a freezed EfficientNet-B0 pre-trained on the DFDC and FaceForensics++ datasets but whose output features, instead of going into a Transformer as in the original architecture, are given as input directly to a simple MLP.
+
+
+The MLP performs frame-by-frame classification for each face of the video and the predictions are then averaged and evaluated against a fixed threshold.
+
+
+## Inference
+To run the evaluation process of a trained model on a test set, use the following command:
+```
+test.py --model_weights path/to/model --extractor_weights path/to/model --video_path path/to/videos --data_path path/to/faces --test_list_file path/to/test.csv --model model_type --config path/to/config
+```
+
+You can also use the option --save_attentions to save space, time and combined attention plots.
+
+
+## Additional Parameters
+In almost all the scripts the following parameters can be also customized:
+
+- --gpu_id: ID of GPU to use for processing or -1 to use multi-gpu only for the training (default: 0);
+- --workers: Number of data loader workers (default: 8);
+- --random_state: Random state number for reproducibility (default: 42)
+
+# Reference
+```
+@misc{https://doi.org/10.48550/arxiv.2211.10996,
+ doi = {10.48550/ARXIV.2211.10996},
+ url = {https://arxiv.org/abs/2211.10996},
+ author = {Coccomini, Davide Alessandro and Zilos, Giorgos Kordopatis and Amato, Giuseppe and Caldelli, Roberto and Falchi, Fabrizio and Papadopoulos, Symeon and Gennaro, Claudio},
+ keywords = {Computer Vision and Pattern Recognition (cs.CV), FOS: Computer and information sciences, FOS: Computer and information sciences},
+ title = {MINTIME: Multi-Identity Size-Invariant Video Deepfake Detection},
+ publisher = {arXiv},
+ year = {2022},
+ copyright = {arXiv.org perpetual, non-exclusive license}
+}
+```
diff --git a/clean/video/mintime/SOURCE.md b/clean/video/mintime/SOURCE.md
new file mode 100644
index 0000000000000000000000000000000000000000..3e5c4a5f5702917964544ad75a5c49bebafbe9f1
--- /dev/null
+++ b/clean/video/mintime/SOURCE.md
@@ -0,0 +1,17 @@
+# Source: video/mintime
+
+| Field | Value |
+|---|---|
+| Upstream | https://github.com/davide-coccomini/MINTIME-Multi-Identity-size-iNvariant-TIMEsformer-for-Video-Deepfake-Detection |
+| Paper | https://arxiv.org/abs/2206.13829 |
+| Commit SHA | **not recorded** -- the vendoring step did not preserve it |
+| Mirrored on | 2026-09-15 |
+| Upstream license | no license file present upstream (all rights reserved) |
+
+This is a **mirror**, stripped to the files needed for inference. The full
+untouched snapshot is at `archive/video__mintime.tar.gz`.
+
+This code is the work of its original authors and is **not** covered by the
+DeepSafe project license. If you are an author and want this removed, open an
+issue on https://github.com/deepsafehq/deepsafe-bench and it will be taken down
+within 48 hours, no questions asked.
diff --git a/clean/video/mintime/config/baseline.yaml b/clean/video/mintime/config/baseline.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..bdfa2a2cb0390aed327085782a31f59c8228f9a0
--- /dev/null
+++ b/clean/video/mintime/config/baseline.yaml
@@ -0,0 +1,21 @@
+training:
+ lr: 0.01
+ weight-decay: 0.0001
+ bs: 8
+ val_bs: 8
+ optimizer: 'SGD'
+ scheduler: 'cosinelr'
+ gamma: 0.1
+ step-size: 5
+ augmentation: 'max'
+
+test:
+ bs: 1
+
+model:
+ image-size: 224
+ num-classes: 1
+ dim: 1280
+ mlp-dim: 512
+ num-frames: 16
+ max-identities: 2
diff --git a/clean/video/mintime/config/convolutional_timesformer.yaml b/clean/video/mintime/config/convolutional_timesformer.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..19539b0677d14246ba70c1c9e6da2bd45c181ca9
--- /dev/null
+++ b/clean/video/mintime/config/convolutional_timesformer.yaml
@@ -0,0 +1,92 @@
+training:
+ lr: 0.01
+ weight-decay: 0.0001
+ bs: 1
+ val_bs: 1
+ scheduler: 'steplr'
+ gamma: 0.1
+ step-size: 15
+
+
+model:
+ image-size: 224
+ patch-size: 1
+ num-classes: 1
+ num-frames: 8
+ num-patches: 1280
+ dim: 256 #512
+ depth: 4 # 6
+ dim-head: 64
+ channels: 1280
+ heads: 6 # 8
+ emb-dim: 32
+ attn-dropout: 0.
+ ff-dropout: 0.
+ efficient-net-block: 20
+ rotary-emb: False
+ shift-tokens: False
+
+#model:
+# image-size: 224
+# patch-size: 14
+# num-classes: 1
+# num-frames: 16
+# num-patches: 112
+# dim: 512
+# depth: 6
+# dim-head: 64
+# channels: 3
+# heads: 8
+# emb-dim: 32
+# attn-dropout: 0.
+# ff-dropout: 0.
+# efficient-net-block: 9
+# rotary-emb: False
+# shift-tokens: False
+
+
+
+#model:
+# image-size: 224
+# patch-size: 7
+# num-classes: 1
+# num-frames: 8
+# num-patches: 1280
+# dim: 512
+# depth: 6
+# dim-head: 64
+# channels: 3
+# heads: 8
+# emb-dim: 32
+# attn-dropout: 0.
+# ff-dropout: 0.
+# efficient-net-block: 20
+# rotary-emb: False
+# shift-tokens: False
+
+
+#
+#torch.Size([64, 1280, 7, 7])
+#torch.Size([8, 10240, 1024])
+#
+
+
+#model:
+# image-size: 224
+# patch-size: 14
+# num-classes: 1
+# num-frames: 16
+# num-patches: 80
+# dim: 1024
+# depth: 6
+# dim-head: 64
+# channels: 3
+# heads: 16
+# emb-dim: 32
+# attn-dropout: 0.
+# ff-dropout: 0.
+# efficient-net-block: 6
+# rotary-emb: False
+# shift-tokens: False
+
+
diff --git a/clean/video/mintime/config/size_invariant_timesformer.yaml b/clean/video/mintime/config/size_invariant_timesformer.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..492c0e2fdbfe794f98b14d4981e310a8e60911b7
--- /dev/null
+++ b/clean/video/mintime/config/size_invariant_timesformer.yaml
@@ -0,0 +1,32 @@
+training:
+ lr: 0.01
+ weight-decay: 0.0001
+ bs: 8 #32
+ val_bs: 8 #32
+ optimizer: 'SGD'
+ scheduler: 'cosinelr'
+ gamma: 0.1
+ step-size: 5
+ augmentation: 'max' # min/max
+
+test:
+ bs: 1
+
+model:
+ image-size: 224
+ patch-size: 1
+ num-classes: 1
+ num-patches: 49
+ num-frames: 16
+ max-identities: 2
+ dim: 512
+ depth: 9 # 9 v2 3 v3
+ dim-head: 64
+ channels: 2048 # Xception: 2048 | EfficientNet: 1280
+ heads: 8
+ attn-dropout: 0.
+ ff-dropout: 0.
+ shift-tokens: False
+ enable-size-emb: True
+ enable-pos-emb: True
+ enable-identity-attention: True
diff --git a/clean/video/mintime/config/slowfast.yaml b/clean/video/mintime/config/slowfast.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..10e7d2474137faefe162b565a8121748bbb5a584
--- /dev/null
+++ b/clean/video/mintime/config/slowfast.yaml
@@ -0,0 +1,22 @@
+training:
+ lr: 0.001
+ weight-decay: 0.0001
+ bs: 32
+ val_bs: 32
+ optimizer: 'SGD'
+ scheduler: 'cosinelr'
+ gamma: 0.1
+ step-size: 5
+ augmentation: 'max' # min/max
+
+test:
+ bs: 32
+
+model:
+ image-size: 256
+ num-classes: 1
+ num-frames: 16
+ max-identities: 1
+ enable-size-emb: False
+ enable-pos-emb: False
+ enable-identity-attention: False
diff --git a/clean/video/mintime/cross-efficient-vit/configs/architecture.yaml b/clean/video/mintime/cross-efficient-vit/configs/architecture.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..1d9f3249c096d7f995046afe230955f0ea71ae4a
--- /dev/null
+++ b/clean/video/mintime/cross-efficient-vit/configs/architecture.yaml
@@ -0,0 +1,35 @@
+training:
+ lr: 0.01
+ weight-decay: 0.0000001
+ bs: 16
+ scheduler: 'steplr'
+ gamma: 0.1
+ step-size: 15
+ rebalancing-fake: 0.3
+ rebalancing-real: 1
+ frames-per-video: 30 # Equidistant frames
+
+model:
+ image-size: 224
+ num-classes: 1
+ depth: 4 # number of multi-scale encoding blocks
+ sm-dim: 192 # high res dimension
+ sm-patch-size: 7 # high res patch size (should be smaller than lg-patch-size)
+ sm-enc-depth: 2 # high res depth
+ sm-enc-dim-head: 64
+ sm-enc-heads: 8 # high res heads
+ sm-enc-mlp-dim: 2048 # high res feedforward dimension
+ lg-dim: 384 # low res dimension
+ lg-patch-size: 56 # low res patch size
+ lg-enc-depth: 3 # low res depth
+ lg-enc-dim-head: 64
+ lg-enc-heads: 8 # low res heads
+ lg-enc-mlp-dim: 2048 # low res feedforward dimensions
+ cross-attn-depth: 2 # cross attention rounds
+ cross-attn-dim-head: 64
+ cross-attn-heads: 8 # cross attention heads
+ lg-channels: 24
+ sm-channels: 1280
+ dropout: 0.15
+ emb-dropout: 0.15
+
\ No newline at end of file
diff --git a/clean/video/mintime/cross-efficient-vit/deepfakes_dataset.py b/clean/video/mintime/cross-efficient-vit/deepfakes_dataset.py
new file mode 100644
index 0000000000000000000000000000000000000000..778275638b2ed729235c5d5015f643309960142b
--- /dev/null
+++ b/clean/video/mintime/cross-efficient-vit/deepfakes_dataset.py
@@ -0,0 +1,67 @@
+import torch
+from torch.utils.data import DataLoader, TensorDataset, Dataset
+import cv2
+import numpy as np
+
+import uuid
+from albumentations import Compose, RandomBrightnessContrast, \
+ HorizontalFlip, FancyPCA, HueSaturationValue, OneOf, ToGray, \
+ ShiftScaleRotate, ImageCompression, PadIfNeeded, GaussNoise, GaussianBlur, Rotate
+
+from transforms.albu import IsotropicResize
+
+class DeepFakesDataset(Dataset):
+ def __init__(self, images, labels, image_size, mode = 'train'):
+ self.x = images
+ self.y = torch.from_numpy(labels)
+ self.image_size = image_size
+ self.mode = mode
+ self.n_samples = images.shape[0]
+
+ def create_train_transforms(self, size):
+ return Compose([
+ ImageCompression(quality_lower=60, quality_upper=100, p=0.2),
+ GaussNoise(p=0.3),
+ #GaussianBlur(blur_limit=3, p=0.05),
+ HorizontalFlip(),
+ OneOf([
+ IsotropicResize(max_side=size, interpolation_down=cv2.INTER_AREA, interpolation_up=cv2.INTER_CUBIC),
+ IsotropicResize(max_side=size, interpolation_down=cv2.INTER_AREA, interpolation_up=cv2.INTER_LINEAR),
+ IsotropicResize(max_side=size, interpolation_down=cv2.INTER_LINEAR, interpolation_up=cv2.INTER_LINEAR),
+ ], p=1),
+ PadIfNeeded(min_height=size, min_width=size, border_mode=cv2.BORDER_CONSTANT),
+ OneOf([RandomBrightnessContrast(), FancyPCA(), HueSaturationValue()], p=0.4),
+ ToGray(p=0.2),
+ ShiftScaleRotate(shift_limit=0.1, scale_limit=0.2, rotate_limit=5, border_mode=cv2.BORDER_CONSTANT, p=0.5),
+ ]
+ )
+
+ def create_val_transform(self, size):
+ return Compose([
+ IsotropicResize(max_side=size, interpolation_down=cv2.INTER_AREA, interpolation_up=cv2.INTER_CUBIC),
+ PadIfNeeded(min_height=size, min_width=size, border_mode=cv2.BORDER_CONSTANT),
+ ])
+
+ def __getitem__(self, index):
+ image = np.asarray(self.x[index])
+
+ if self.mode == 'train':
+ transform = self.create_train_transforms(self.image_size)
+ else:
+ transform = self.create_val_transform(self.image_size)
+
+ #unique = uuid.uuid4()
+ #cv2.imwrite("../dataset/augmented_frames/vit_augmentation/square_fda/"+str(unique)+"_"+str(index)+"_original.png", image)
+
+ image = transform(image=image)['image']
+
+ #cv2.imwrite("../dataset/augmented_frames/vit_augmentation/square_fda/"+str(unique)+"_"+str(index)+".png", image)
+
+ return torch.tensor(image).float(), self.y[index]
+
+
+
+ def __len__(self):
+ return self.n_samples
+
+
diff --git a/clean/video/mintime/cross-efficient-vit/efficient_net/LICENSE b/clean/video/mintime/cross-efficient-vit/efficient_net/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..d645695673349e3947e8e5ae42332d0ac3164cd7
--- /dev/null
+++ b/clean/video/mintime/cross-efficient-vit/efficient_net/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/clean/video/mintime/cross-efficient-vit/efficient_net/README.md b/clean/video/mintime/cross-efficient-vit/efficient_net/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..78f6fd41e7dd8d41c0064271849c65b0abbdd2d6
--- /dev/null
+++ b/clean/video/mintime/cross-efficient-vit/efficient_net/README.md
@@ -0,0 +1,269 @@
+# EfficientNet PyTorch
+
+### Quickstart
+
+Install with `pip install efficientnet_pytorch` and load a pretrained EfficientNet with:
+```python
+from efficientnet_pytorch import EfficientNet
+model = EfficientNet.from_pretrained('efficientnet-b0')
+```
+
+### Updates
+
+#### Update (April 2, 2021)
+
+The [EfficientNetV2 paper](https://arxiv.org/abs/2104.00298) has been released! I am working on implementing it as you read this :)
+
+About EfficientNetV2:
+> EfficientNetV2 is a new family of convolutional networks that have faster training speed and better parameter efficiency than previous models. To develop this family of models, we use a combination of training-aware neural architecture search and scaling, to jointly optimize training speed and parameter efficiency. The models were searched from the search space enriched with new ops such as Fused-MBConv.
+
+Here is a comparison:
+>
+
+
+#### Update (Aug 25, 2020)
+
+This update adds:
+ * A new `include_top` (default: `True`) option ([#208](https://github.com/lukemelas/EfficientNet-PyTorch/pull/208))
+ * Continuous testing with [sotabench](https://sotabench.com/)
+ * Code quality improvements and fixes ([#215](https://github.com/lukemelas/EfficientNet-PyTorch/pull/215) [#223](https://github.com/lukemelas/EfficientNet-PyTorch/pull/223))
+
+#### Update (May 14, 2020)
+
+This update adds comprehensive comments and documentation (thanks to @workingcoder).
+
+#### Update (January 23, 2020)
+
+This update adds a new category of pre-trained model based on adversarial training, called _advprop_. It is important to note that the preprocessing required for the advprop pretrained models is slightly different from normal ImageNet preprocessing. As a result, by default, advprop models are not used. To load a model with advprop, use:
+```python
+model = EfficientNet.from_pretrained("efficientnet-b0", advprop=True)
+```
+There is also a new, large `efficientnet-b8` pretrained model that is only available in advprop form. When using these models, replace ImageNet preprocessing code as follows:
+```python
+if advprop: # for models using advprop pretrained weights
+ normalize = transforms.Lambda(lambda img: img * 2.0 - 1.0)
+else:
+ normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406],
+ std=[0.229, 0.224, 0.225])
+```
+This update also addresses multiple other issues ([#115](https://github.com/lukemelas/EfficientNet-PyTorch/issues/115), [#128](https://github.com/lukemelas/EfficientNet-PyTorch/issues/128)).
+
+#### Update (October 15, 2019)
+
+This update allows you to choose whether to use a memory-efficient Swish activation. The memory-efficient version is chosen by default, but it cannot be used when exporting using PyTorch JIT. For this purpose, we have also included a standard (export-friendly) swish activation function. To switch to the export-friendly version, simply call `model.set_swish(memory_efficient=False)` after loading your desired model. This update addresses issues [#88](https://github.com/lukemelas/EfficientNet-PyTorch/pull/88) and [#89](https://github.com/lukemelas/EfficientNet-PyTorch/pull/89).
+
+#### Update (October 12, 2019)
+
+This update makes the Swish activation function more memory-efficient. It also addresses pull requests [#72](https://github.com/lukemelas/EfficientNet-PyTorch/pull/72), [#73](https://github.com/lukemelas/EfficientNet-PyTorch/pull/73), [#85](https://github.com/lukemelas/EfficientNet-PyTorch/pull/85), and [#86](https://github.com/lukemelas/EfficientNet-PyTorch/pull/86). Thanks to the authors of all the pull requests!
+
+#### Update (July 31, 2019)
+
+_Upgrade the pip package with_ `pip install --upgrade efficientnet-pytorch`
+
+The B6 and B7 models are now available. Additionally, _all_ pretrained models have been updated to use AutoAugment preprocessing, which translates to better performance across the board. Usage is the same as before:
+```python
+from efficientnet_pytorch import EfficientNet
+model = EfficientNet.from_pretrained('efficientnet-b7')
+```
+
+#### Update (June 29, 2019)
+
+This update adds easy model exporting ([#20](https://github.com/lukemelas/EfficientNet-PyTorch/issues/20)) and feature extraction ([#38](https://github.com/lukemelas/EfficientNet-PyTorch/issues/38)).
+
+ * [Example: Export to ONNX](#example-export)
+ * [Example: Extract features](#example-feature-extraction)
+ * Also: fixed a CUDA/CPU bug ([#32](https://github.com/lukemelas/EfficientNet-PyTorch/issues/32))
+
+It is also now incredibly simple to load a pretrained model with a new number of classes for transfer learning:
+```python
+model = EfficientNet.from_pretrained('efficientnet-b1', num_classes=23)
+```
+
+
+#### Update (June 23, 2019)
+
+The B4 and B5 models are now available. Their usage is identical to the other models:
+```python
+from efficientnet_pytorch import EfficientNet
+model = EfficientNet.from_pretrained('efficientnet-b4')
+```
+
+### Overview
+This repository contains an op-for-op PyTorch reimplementation of [EfficientNet](https://arxiv.org/abs/1905.11946), along with pre-trained models and examples.
+
+The goal of this implementation is to be simple, highly extensible, and easy to integrate into your own projects. This implementation is a work in progress -- new features are currently being implemented.
+
+At the moment, you can easily:
+ * Load pretrained EfficientNet models
+ * Use EfficientNet models for classification or feature extraction
+ * Evaluate EfficientNet models on ImageNet or your own images
+
+_Upcoming features_: In the next few days, you will be able to:
+ * Train new models from scratch on ImageNet with a simple command
+ * Quickly finetune an EfficientNet on your own dataset
+ * Export EfficientNet models for production
+
+### Table of contents
+1. [About EfficientNet](#about-efficientnet)
+2. [About EfficientNet-PyTorch](#about-efficientnet-pytorch)
+3. [Installation](#installation)
+4. [Usage](#usage)
+ * [Load pretrained models](#loading-pretrained-models)
+ * [Example: Classify](#example-classification)
+ * [Example: Extract features](#example-feature-extraction)
+ * [Example: Export to ONNX](#example-export)
+6. [Contributing](#contributing)
+
+### About EfficientNet
+
+If you're new to EfficientNets, here is an explanation straight from the official TensorFlow implementation:
+
+EfficientNets are a family of image classification models, which achieve state-of-the-art accuracy, yet being an order-of-magnitude smaller and faster than previous models. We develop EfficientNets based on AutoML and Compound Scaling. In particular, we first use [AutoML Mobile framework](https://ai.googleblog.com/2018/08/mnasnet-towards-automating-design-of.html) to develop a mobile-size baseline network, named as EfficientNet-B0; Then, we use the compound scaling method to scale up this baseline to obtain EfficientNet-B1 to B7.
+
+
+
+
+
+
+
+
+
+
+
+
+EfficientNets achieve state-of-the-art accuracy on ImageNet with an order of magnitude better efficiency:
+
+
+* In high-accuracy regime, our EfficientNet-B7 achieves state-of-the-art 84.4% top-1 / 97.1% top-5 accuracy on ImageNet with 66M parameters and 37B FLOPS, being 8.4x smaller and 6.1x faster on CPU inference than previous best [Gpipe](https://arxiv.org/abs/1811.06965).
+
+* In middle-accuracy regime, our EfficientNet-B1 is 7.6x smaller and 5.7x faster on CPU inference than [ResNet-152](https://arxiv.org/abs/1512.03385), with similar ImageNet accuracy.
+
+* Compared with the widely used [ResNet-50](https://arxiv.org/abs/1512.03385), our EfficientNet-B4 improves the top-1 accuracy from 76.3% of ResNet-50 to 82.6% (+6.3%), under similar FLOPS constraint.
+
+### About EfficientNet PyTorch
+
+EfficientNet PyTorch is a PyTorch re-implementation of EfficientNet. It is consistent with the [original TensorFlow implementation](https://github.com/tensorflow/tpu/tree/master/models/official/efficientnet), such that it is easy to load weights from a TensorFlow checkpoint. At the same time, we aim to make our PyTorch implementation as simple, flexible, and extensible as possible.
+
+If you have any feature requests or questions, feel free to leave them as GitHub issues!
+
+### Installation
+
+Install via pip:
+```bash
+pip install efficientnet_pytorch
+```
+
+Or install from source:
+```bash
+git clone https://github.com/lukemelas/EfficientNet-PyTorch
+cd EfficientNet-Pytorch
+pip install -e .
+```
+
+### Usage
+
+#### Loading pretrained models
+
+Load an EfficientNet:
+```python
+from efficientnet_pytorch import EfficientNet
+model = EfficientNet.from_name('efficientnet-b0')
+```
+
+Load a pretrained EfficientNet:
+```python
+from efficientnet_pytorch import EfficientNet
+model = EfficientNet.from_pretrained('efficientnet-b0')
+```
+
+Details about the models are below:
+
+| *Name* |*# Params*|*Top-1 Acc.*|*Pretrained?*|
+|:-----------------:|:--------:|:----------:|:-----------:|
+| `efficientnet-b0` | 5.3M | 76.3 | ✓ |
+| `efficientnet-b1` | 7.8M | 78.8 | ✓ |
+| `efficientnet-b2` | 9.2M | 79.8 | ✓ |
+| `efficientnet-b3` | 12M | 81.1 | ✓ |
+| `efficientnet-b4` | 19M | 82.6 | ✓ |
+| `efficientnet-b5` | 30M | 83.3 | ✓ |
+| `efficientnet-b6` | 43M | 84.0 | ✓ |
+| `efficientnet-b7` | 66M | 84.4 | ✓ |
+
+
+#### Example: Classification
+
+Below is a simple, complete example. It may also be found as a jupyter notebook in `examples/simple` or as a [Colab Notebook](https://colab.research.google.com/drive/1Jw28xZ1NJq4Cja4jLe6tJ6_F5lCzElb4).
+
+We assume that in your current directory, there is a `img.jpg` file and a `labels_map.txt` file (ImageNet class names). These are both included in `examples/simple`.
+
+```python
+import json
+from PIL import Image
+import torch
+from torchvision import transforms
+
+from efficientnet_pytorch import EfficientNet
+model = EfficientNet.from_pretrained('efficientnet-b0')
+
+# Preprocess image
+tfms = transforms.Compose([transforms.Resize(224), transforms.ToTensor(),
+ transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),])
+img = tfms(Image.open('img.jpg')).unsqueeze(0)
+print(img.shape) # torch.Size([1, 3, 224, 224])
+
+# Load ImageNet class names
+labels_map = json.load(open('labels_map.txt'))
+labels_map = [labels_map[str(i)] for i in range(1000)]
+
+# Classify
+model.eval()
+with torch.no_grad():
+ outputs = model(img)
+
+# Print predictions
+print('-----')
+for idx in torch.topk(outputs, k=5).indices.squeeze(0).tolist():
+ prob = torch.softmax(outputs, dim=1)[0, idx].item()
+ print('{label:<75} ({p:.2f}%)'.format(label=labels_map[idx], p=prob*100))
+```
+
+#### Example: Feature Extraction
+
+You can easily extract features with `model.extract_features`:
+```python
+from efficientnet_pytorch import EfficientNet
+model = EfficientNet.from_pretrained('efficientnet-b0')
+
+# ... image preprocessing as in the classification example ...
+print(img.shape) # torch.Size([1, 3, 224, 224])
+
+features = model.extract_features(img)
+print(features.shape) # torch.Size([1, 1280, 7, 7])
+```
+
+#### Example: Export to ONNX
+
+Exporting to ONNX for deploying to production is now simple:
+```python
+import torch
+from efficientnet_pytorch import EfficientNet
+
+model = EfficientNet.from_pretrained('efficientnet-b1')
+dummy_input = torch.randn(10, 3, 240, 240)
+
+model.set_swish(memory_efficient=False)
+torch.onnx.export(model, dummy_input, "test-b1.onnx", verbose=True)
+```
+
+[Here](https://colab.research.google.com/drive/1rOAEXeXHaA8uo3aG2YcFDHItlRJMV0VP) is a Colab example.
+
+
+#### ImageNet
+
+See `examples/imagenet` for details about evaluating on ImageNet.
+
+### Contributing
+
+If you find a bug, create a GitHub issue, or even better, submit a pull request. Similarly, if you have questions, simply post them as GitHub issues.
+
+I look forward to seeing what the community does with these models!
diff --git a/clean/video/mintime/cross-efficient-vit/efficient_net/efficientnet_pytorch/__init__.py b/clean/video/mintime/cross-efficient-vit/efficient_net/efficientnet_pytorch/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..2b529dfe3f61da71f7427fbeb7ab47710450d372
--- /dev/null
+++ b/clean/video/mintime/cross-efficient-vit/efficient_net/efficientnet_pytorch/__init__.py
@@ -0,0 +1,9 @@
+__version__ = "0.7.1"
+from .model import EfficientNet, VALID_MODELS
+from .utils import (
+ GlobalParams,
+ BlockArgs,
+ BlockDecoder,
+ efficientnet,
+ get_model_params,
+)
diff --git a/clean/video/mintime/cross-efficient-vit/efficient_net/efficientnet_pytorch/model.py b/clean/video/mintime/cross-efficient-vit/efficient_net/efficientnet_pytorch/model.py
new file mode 100644
index 0000000000000000000000000000000000000000..ccc0014468bf094160a6ad334c3fed44a8a0cf18
--- /dev/null
+++ b/clean/video/mintime/cross-efficient-vit/efficient_net/efficientnet_pytorch/model.py
@@ -0,0 +1,459 @@
+"""model.py - Model and module class for EfficientNet.
+ They are built to mirror those in the official TensorFlow implementation.
+"""
+
+# Author: lukemelas (github username)
+# Github repo: https://github.com/lukemelas/EfficientNet-PyTorch
+# With adjustments and added comments by workingcoder (github username).
+import numpy as np
+import torch
+from torch import nn
+from torch.nn import functional as F
+from .utils import (
+ round_filters,
+ round_repeats,
+ drop_connect,
+ get_same_padding_conv2d,
+ get_model_params,
+ efficientnet_params,
+ load_pretrained_weights,
+ Swish,
+ MemoryEfficientSwish,
+ calculate_output_image_size
+)
+
+
+VALID_MODELS = (
+ 'efficientnet-b0', 'efficientnet-b1', 'efficientnet-b2', 'efficientnet-b3',
+ 'efficientnet-b4', 'efficientnet-b5', 'efficientnet-b6', 'efficientnet-b7',
+ 'efficientnet-b8',
+
+ # Support the construction of 'efficientnet-l2' without pretrained weights
+ 'efficientnet-l2'
+)
+
+
+class MBConvBlock(nn.Module):
+ """Mobile Inverted Residual Bottleneck Block.
+
+ Args:
+ block_args (namedtuple): BlockArgs, defined in utils.py.
+ global_params (namedtuple): GlobalParam, defined in utils.py.
+ image_size (tuple or list): [image_height, image_width].
+
+ References:
+ [1] https://arxiv.org/abs/1704.04861 (MobileNet v1)
+ [2] https://arxiv.org/abs/1801.04381 (MobileNet v2)
+ [3] https://arxiv.org/abs/1905.02244 (MobileNet v3)
+ """
+
+ def __init__(self, block_args, global_params, image_size=None):
+ super().__init__()
+ self._block_args = block_args
+ self._bn_mom = 1 - global_params.batch_norm_momentum # pytorch's difference from tensorflow
+ self._bn_eps = global_params.batch_norm_epsilon
+ self.has_se = (self._block_args.se_ratio is not None) and (0 < self._block_args.se_ratio <= 1)
+ self.id_skip = block_args.id_skip # whether to use skip connection and drop connect
+
+ # Expansion phase (Inverted Bottleneck)
+ inp = self._block_args.input_filters # number of input channels
+ oup = self._block_args.input_filters * self._block_args.expand_ratio # number of output channels
+ if self._block_args.expand_ratio != 1:
+ Conv2d = get_same_padding_conv2d(image_size=image_size)
+ self._expand_conv = Conv2d(in_channels=inp, out_channels=oup, kernel_size=1, bias=False)
+ self._bn0 = nn.BatchNorm2d(num_features=oup, momentum=self._bn_mom, eps=self._bn_eps)
+ # image_size = calculate_output_image_size(image_size, 1) <-- this wouldn't modify image_size
+
+ # Depthwise convolution phase
+ k = self._block_args.kernel_size
+ s = self._block_args.stride
+ Conv2d = get_same_padding_conv2d(image_size=image_size)
+ self._depthwise_conv = Conv2d(
+ in_channels=oup, out_channels=oup, groups=oup, # groups makes it depthwise
+ kernel_size=k, stride=s, bias=False)
+ self._bn1 = nn.BatchNorm2d(num_features=oup, momentum=self._bn_mom, eps=self._bn_eps)
+ image_size = calculate_output_image_size(image_size, s)
+
+ # Squeeze and Excitation layer, if desired
+ if self.has_se:
+ Conv2d = get_same_padding_conv2d(image_size=(1, 1))
+ num_squeezed_channels = max(1, int(self._block_args.input_filters * self._block_args.se_ratio))
+ self._se_reduce = Conv2d(in_channels=oup, out_channels=num_squeezed_channels, kernel_size=1)
+ self._se_expand = Conv2d(in_channels=num_squeezed_channels, out_channels=oup, kernel_size=1)
+
+ # Pointwise convolution phase
+ final_oup = self._block_args.output_filters
+ Conv2d = get_same_padding_conv2d(image_size=image_size)
+ self._project_conv = Conv2d(in_channels=oup, out_channels=final_oup, kernel_size=1, bias=False)
+ self._bn2 = nn.BatchNorm2d(num_features=final_oup, momentum=self._bn_mom, eps=self._bn_eps)
+ self._swish = MemoryEfficientSwish()
+
+ def forward(self, inputs, drop_connect_rate=None):
+ """MBConvBlock's forward function.
+
+ Args:
+ inputs (tensor): Input tensor.
+ drop_connect_rate (bool): Drop connect rate (float, between 0 and 1).
+
+ Returns:
+ Output of this block after processing.
+ """
+
+ # Expansion and Depthwise Convolution
+ x = inputs
+ if self._block_args.expand_ratio != 1:
+ x = self._expand_conv(inputs)
+ x = self._bn0(x)
+ x = self._swish(x)
+
+ x = self._depthwise_conv(x)
+ x = self._bn1(x)
+ x = self._swish(x)
+
+ # Squeeze and Excitation
+ if self.has_se:
+ x_squeezed = F.adaptive_avg_pool2d(x, 1)
+ x_squeezed = self._se_reduce(x_squeezed)
+ x_squeezed = self._swish(x_squeezed)
+ x_squeezed = self._se_expand(x_squeezed)
+ x = torch.sigmoid(x_squeezed) * x
+
+ # Pointwise Convolution
+ x = self._project_conv(x)
+ x = self._bn2(x)
+
+ # Skip connection and drop connect
+ input_filters, output_filters = self._block_args.input_filters, self._block_args.output_filters
+ if self.id_skip and self._block_args.stride == 1 and input_filters == output_filters:
+ # The combination of skip connection and drop connect brings about stochastic depth.
+ if drop_connect_rate:
+ x = drop_connect(x, p=drop_connect_rate, training=self.training)
+ x = x + inputs # skip connection
+ return x
+
+ def set_swish(self, memory_efficient=True):
+ """Sets swish function as memory efficient (for training) or standard (for export).
+
+ Args:
+ memory_efficient (bool): Whether to use memory-efficient version of swish.
+ """
+ self._swish = MemoryEfficientSwish() if memory_efficient else Swish()
+
+
+class EfficientNet(nn.Module):
+ """EfficientNet model.
+ Most easily loaded with the .from_name or .from_pretrained methods.
+
+ Args:
+ blocks_args (list[namedtuple]): A list of BlockArgs to construct blocks.
+ global_params (namedtuple): A set of GlobalParams shared between blocks.
+
+ References:
+ [1] https://arxiv.org/abs/1905.11946 (EfficientNet)
+
+ Example:
+ >>> import torch
+ >>> from efficientnet.model import EfficientNet
+ >>> inputs = torch.rand(1, 3, 224, 224)
+ >>> model = EfficientNet.from_pretrained('efficientnet-b0')
+ >>> model.eval()
+ >>> outputs = model(inputs)
+ """
+
+ def __init__(self, blocks_args=None, global_params=None):
+ super().__init__()
+ assert isinstance(blocks_args, list), 'blocks_args should be a list'
+ assert len(blocks_args) > 0, 'block args must be greater than 0'
+ self._global_params = global_params
+ self._blocks_args = blocks_args
+
+ # Batch norm parameters
+ bn_mom = 1 - self._global_params.batch_norm_momentum
+ bn_eps = self._global_params.batch_norm_epsilon
+
+ # Get stem static or dynamic convolution depending on image size
+ image_size = global_params.image_size
+ Conv2d = get_same_padding_conv2d(image_size=image_size)
+
+ # Stem
+ in_channels = 3 # rgb
+ out_channels = round_filters(32, self._global_params) # number of output channels
+ self._conv_stem = Conv2d(in_channels, out_channels, kernel_size=3, stride=2, bias=False)
+ self._bn0 = nn.BatchNorm2d(num_features=out_channels, momentum=bn_mom, eps=bn_eps)
+ image_size = calculate_output_image_size(image_size, 2)
+
+ # Build blocks
+ self._blocks = nn.ModuleList([])
+ for block_args in self._blocks_args:
+
+ # Update block input and output filters based on depth multiplier.
+ block_args = block_args._replace(
+ input_filters=round_filters(block_args.input_filters, self._global_params),
+ output_filters=round_filters(block_args.output_filters, self._global_params),
+ num_repeat=round_repeats(block_args.num_repeat, self._global_params)
+ )
+
+ # The first block needs to take care of stride and filter size increase.
+ self._blocks.append(MBConvBlock(block_args, self._global_params, image_size=image_size))
+ image_size = calculate_output_image_size(image_size, block_args.stride)
+ if block_args.num_repeat > 1: # modify block_args to keep same output size
+ block_args = block_args._replace(input_filters=block_args.output_filters, stride=1)
+ for _ in range(block_args.num_repeat - 1):
+ self._blocks.append(MBConvBlock(block_args, self._global_params, image_size=image_size))
+ # image_size = calculate_output_image_size(image_size, block_args.stride) # stride = 1
+
+ # Head
+ in_channels = block_args.output_filters # output of final block
+ out_channels = round_filters(1280, self._global_params)
+ Conv2d = get_same_padding_conv2d(image_size=image_size)
+ self._conv_head = Conv2d(in_channels, out_channels, kernel_size=1, bias=False)
+ self._bn1 = nn.BatchNorm2d(num_features=out_channels, momentum=bn_mom, eps=bn_eps)
+
+ # Final linear layer
+ self._avg_pooling = nn.AdaptiveAvgPool2d(1)
+ if self._global_params.include_top:
+ self._dropout = nn.Dropout(self._global_params.dropout_rate)
+ self._fc = nn.Linear(out_channels, self._global_params.num_classes)
+
+ # set activation to memory efficient swish by default
+ self._swish = MemoryEfficientSwish()
+
+ def set_swish(self, memory_efficient=True):
+ """Sets swish function as memory efficient (for training) or standard (for export).
+
+ Args:
+ memory_efficient (bool): Whether to use memory-efficient version of swish.
+ """
+ self._swish = MemoryEfficientSwish() if memory_efficient else Swish()
+ for block in self._blocks:
+ block.set_swish(memory_efficient)
+
+ def extract_endpoints(self, inputs):
+ """Use convolution layer to extract features
+ from reduction levels i in [1, 2, 3, 4, 5].
+
+ Args:
+ inputs (tensor): Input tensor.
+
+ Returns:
+ Dictionary of last intermediate features
+ with reduction levels i in [1, 2, 3, 4, 5].
+ Example:
+ >>> import torch
+ >>> from efficientnet.model import EfficientNet
+ >>> inputs = torch.rand(1, 3, 224, 224)
+ >>> model = EfficientNet.from_pretrained('efficientnet-b0')
+ >>> endpoints = model.extract_endpoints(inputs)
+ >>> print(endpoints['reduction_1'].shape) # torch.Size([1, 16, 112, 112])
+ >>> print(endpoints['reduction_2'].shape) # torch.Size([1, 24, 56, 56])
+ >>> print(endpoints['reduction_3'].shape) # torch.Size([1, 40, 28, 28])
+ >>> print(endpoints['reduction_4'].shape) # torch.Size([1, 112, 14, 14])
+ >>> print(endpoints['reduction_5'].shape) # torch.Size([1, 320, 7, 7])
+ >>> print(endpoints['reduction_6'].shape) # torch.Size([1, 1280, 7, 7])
+ """
+ endpoints = dict()
+
+ # Stem
+ x = self._swish(self._bn0(self._conv_stem(inputs)))
+ prev_x = x
+
+ # Blocks
+ for idx, block in enumerate(self._blocks):
+ drop_connect_rate = self._global_params.drop_connect_rate
+ if drop_connect_rate:
+ drop_connect_rate *= float(idx) / len(self._blocks) # scale drop connect_rate
+ x = block(x, drop_connect_rate=drop_connect_rate)
+ if prev_x.size(2) > x.size(2):
+ endpoints['reduction_{}'.format(len(endpoints) + 1)] = prev_x
+ elif idx == len(self._blocks) - 1:
+ endpoints['reduction_{}'.format(len(endpoints) + 1)] = x
+ prev_x = x
+
+ # Head
+ x = self._swish(self._bn1(self._conv_head(x)))
+ endpoints['reduction_{}'.format(len(endpoints) + 1)] = x
+
+ return endpoints
+
+ def extract_features(self, inputs):
+ """use convolution layer to extract feature .
+
+ Args:
+ inputs (tensor): Input tensor.
+
+ Returns:
+ Output of the final convolution
+ layer in the efficientnet model.
+ """
+ # Stem
+ x = self._swish(self._bn0(self._conv_stem(inputs)))
+
+ # Blocks
+ for idx, block in enumerate(self._blocks):
+ drop_connect_rate = self._global_params.drop_connect_rate
+ if drop_connect_rate:
+ drop_connect_rate *= float(idx) / len(self._blocks) # scale drop connect_rate
+ x = block(x, drop_connect_rate=drop_connect_rate)
+
+ # Head
+ x = self._swish(self._bn1(self._conv_head(x)))
+
+ return x
+
+ def delete_blocks(self, limit):
+ '''
+ tmp_blocks = nn.ModuleList([])
+ for idx, block in enumerate(self._blocks):
+ if idx < limit:
+ tmp_blocks.append(self._blocks)
+
+ self._blocks = tmp_blocks
+ '''
+ self._blocks = self._blocks
+
+ def extract_features_at_block(self, inputs, selected_block):
+ """use convolution layer to extract feature .
+
+ Args:
+ inputs (tensor): Input tensor.
+
+ Returns:
+ Output of the final convolution
+ layer in the efficientnet model.
+ """
+ # Stem
+ x = self._swish(self._bn0(self._conv_stem(inputs)))
+
+ # Blocks
+ for idx, block in enumerate(self._blocks):
+ drop_connect_rate = self._global_params.drop_connect_rate
+ if drop_connect_rate:
+ drop_connect_rate *= float(idx) / len(self._blocks) # scale drop connect_rate
+ x = block(x, drop_connect_rate=drop_connect_rate)
+
+ if idx > selected_block:
+ break
+
+ # Head
+ if selected_block >= len(self._blocks):
+ x = self._swish(self._bn1(self._conv_head(x)))
+
+ return x
+
+ def forward(self, inputs):
+ """EfficientNet's forward function.
+ Calls extract_features to extract features, applies final linear layer, and returns logits.
+
+ Args:
+ inputs (tensor): Input tensor.
+
+ Returns:
+ Output of this model after processing.
+ """
+ # Convolution layers
+ x = self.extract_features(inputs)
+ # Pooling and final linear layer
+ x = self._avg_pooling(x)
+ if self._global_params.include_top:
+ x = x.flatten(start_dim=1)
+ x = self._dropout(x)
+ x = self._fc(x)
+ return x
+
+ @classmethod
+ def from_name(cls, model_name, in_channels=3, **override_params):
+ """Create an efficientnet model according to name.
+
+ Args:
+ model_name (str): Name for efficientnet.
+ in_channels (int): Input data's channel number.
+ override_params (other key word params):
+ Params to override model's global_params.
+ Optional key:
+ 'width_coefficient', 'depth_coefficient',
+ 'image_size', 'dropout_rate',
+ 'num_classes', 'batch_norm_momentum',
+ 'batch_norm_epsilon', 'drop_connect_rate',
+ 'depth_divisor', 'min_depth'
+
+ Returns:
+ An efficientnet model.
+ """
+ cls._check_model_name_is_valid(model_name)
+ blocks_args, global_params = get_model_params(model_name, override_params)
+ model = cls(blocks_args, global_params)
+ model._change_in_channels(in_channels)
+ return model
+
+ @classmethod
+ def from_pretrained(cls, model_name, weights_path=None, advprop=False,
+ in_channels=3, num_classes=1000, **override_params):
+ """Create an efficientnet model according to name.
+
+ Args:
+ model_name (str): Name for efficientnet.
+ weights_path (None or str):
+ str: path to pretrained weights file on the local disk.
+ None: use pretrained weights downloaded from the Internet.
+ advprop (bool):
+ Whether to load pretrained weights
+ trained with advprop (valid when weights_path is None).
+ in_channels (int): Input data's channel number.
+ num_classes (int):
+ Number of categories for classification.
+ It controls the output size for final linear layer.
+ override_params (other key word params):
+ Params to override model's global_params.
+ Optional key:
+ 'width_coefficient', 'depth_coefficient',
+ 'image_size', 'dropout_rate',
+ 'batch_norm_momentum',
+ 'batch_norm_epsilon', 'drop_connect_rate',
+ 'depth_divisor', 'min_depth'
+
+ Returns:
+ A pretrained efficientnet model.
+ """
+ model = cls.from_name(model_name, num_classes=num_classes, **override_params)
+ load_pretrained_weights(model, model_name, weights_path=weights_path,
+ load_fc=(num_classes == 1000), advprop=advprop)
+ model._change_in_channels(in_channels)
+ return model
+
+ @classmethod
+ def get_image_size(cls, model_name):
+ """Get the input image size for a given efficientnet model.
+
+ Args:
+ model_name (str): Name for efficientnet.
+
+ Returns:
+ Input image size (resolution).
+ """
+ cls._check_model_name_is_valid(model_name)
+ _, _, res, _ = efficientnet_params(model_name)
+ return res
+
+ @classmethod
+ def _check_model_name_is_valid(cls, model_name):
+ """Validates model name.
+
+ Args:
+ model_name (str): Name for efficientnet.
+
+ Returns:
+ bool: Is a valid name or not.
+ """
+ if model_name not in VALID_MODELS:
+ raise ValueError('model_name should be one of: ' + ', '.join(VALID_MODELS))
+
+ def _change_in_channels(self, in_channels):
+ """Adjust model's first convolution layer to in_channels, if in_channels not equals 3.
+
+ Args:
+ in_channels (int): Input data's channel number.
+ """
+ if in_channels != 3:
+ Conv2d = get_same_padding_conv2d(image_size=self._global_params.image_size)
+ out_channels = round_filters(32, self._global_params)
+ self._conv_stem = Conv2d(in_channels, out_channels, kernel_size=3, stride=2, bias=False)
diff --git a/clean/video/mintime/cross-efficient-vit/efficient_net/efficientnet_pytorch/utils.py b/clean/video/mintime/cross-efficient-vit/efficient_net/efficientnet_pytorch/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..826a62790920706d2c9f742fbe18386bf712ae4b
--- /dev/null
+++ b/clean/video/mintime/cross-efficient-vit/efficient_net/efficientnet_pytorch/utils.py
@@ -0,0 +1,616 @@
+"""utils.py - Helper functions for building the model and for loading model parameters.
+ These helper functions are built to mirror those in the official TensorFlow implementation.
+"""
+
+# Author: lukemelas (github username)
+# Github repo: https://github.com/lukemelas/EfficientNet-PyTorch
+# With adjustments and added comments by workingcoder (github username).
+
+import re
+import math
+import collections
+from functools import partial
+import torch
+from torch import nn
+from torch.nn import functional as F
+from torch.utils import model_zoo
+
+
+################################################################################
+# Help functions for model architecture
+################################################################################
+
+# GlobalParams and BlockArgs: Two namedtuples
+# Swish and MemoryEfficientSwish: Two implementations of the method
+# round_filters and round_repeats:
+# Functions to calculate params for scaling model width and depth ! ! !
+# get_width_and_height_from_size and calculate_output_image_size
+# drop_connect: A structural design
+# get_same_padding_conv2d:
+# Conv2dDynamicSamePadding
+# Conv2dStaticSamePadding
+# get_same_padding_maxPool2d:
+# MaxPool2dDynamicSamePadding
+# MaxPool2dStaticSamePadding
+# It's an additional function, not used in EfficientNet,
+# but can be used in other model (such as EfficientDet).
+
+# Parameters for the entire model (stem, all blocks, and head)
+GlobalParams = collections.namedtuple('GlobalParams', [
+ 'width_coefficient', 'depth_coefficient', 'image_size', 'dropout_rate',
+ 'num_classes', 'batch_norm_momentum', 'batch_norm_epsilon',
+ 'drop_connect_rate', 'depth_divisor', 'min_depth', 'include_top'])
+
+# Parameters for an individual model block
+BlockArgs = collections.namedtuple('BlockArgs', [
+ 'num_repeat', 'kernel_size', 'stride', 'expand_ratio',
+ 'input_filters', 'output_filters', 'se_ratio', 'id_skip'])
+
+# Set GlobalParams and BlockArgs's defaults
+GlobalParams.__new__.__defaults__ = (None,) * len(GlobalParams._fields)
+BlockArgs.__new__.__defaults__ = (None,) * len(BlockArgs._fields)
+
+# Swish activation function
+if hasattr(nn, 'SiLU'):
+ Swish = nn.SiLU
+else:
+ # For compatibility with old PyTorch versions
+ class Swish(nn.Module):
+ def forward(self, x):
+ return x * torch.sigmoid(x)
+
+
+# A memory-efficient implementation of Swish function
+class SwishImplementation(torch.autograd.Function):
+ @staticmethod
+ def forward(ctx, i):
+ result = i * torch.sigmoid(i)
+ ctx.save_for_backward(i)
+ return result
+
+ @staticmethod
+ def backward(ctx, grad_output):
+ i = ctx.saved_tensors[0]
+ sigmoid_i = torch.sigmoid(i)
+ return grad_output * (sigmoid_i * (1 + i * (1 - sigmoid_i)))
+
+
+class MemoryEfficientSwish(nn.Module):
+ def forward(self, x):
+ return SwishImplementation.apply(x)
+
+
+def round_filters(filters, global_params):
+ """Calculate and round number of filters based on width multiplier.
+ Use width_coefficient, depth_divisor and min_depth of global_params.
+
+ Args:
+ filters (int): Filters number to be calculated.
+ global_params (namedtuple): Global params of the model.
+
+ Returns:
+ new_filters: New filters number after calculating.
+ """
+ multiplier = global_params.width_coefficient
+ if not multiplier:
+ return filters
+ # TODO: modify the params names.
+ # maybe the names (width_divisor,min_width)
+ # are more suitable than (depth_divisor,min_depth).
+ divisor = global_params.depth_divisor
+ min_depth = global_params.min_depth
+ filters *= multiplier
+ min_depth = min_depth or divisor # pay attention to this line when using min_depth
+ # follow the formula transferred from official TensorFlow implementation
+ new_filters = max(min_depth, int(filters + divisor / 2) // divisor * divisor)
+ if new_filters < 0.9 * filters: # prevent rounding by more than 10%
+ new_filters += divisor
+ return int(new_filters)
+
+
+def round_repeats(repeats, global_params):
+ """Calculate module's repeat number of a block based on depth multiplier.
+ Use depth_coefficient of global_params.
+
+ Args:
+ repeats (int): num_repeat to be calculated.
+ global_params (namedtuple): Global params of the model.
+
+ Returns:
+ new repeat: New repeat number after calculating.
+ """
+ multiplier = global_params.depth_coefficient
+ if not multiplier:
+ return repeats
+ # follow the formula transferred from official TensorFlow implementation
+ return int(math.ceil(multiplier * repeats))
+
+
+def drop_connect(inputs, p, training):
+ """Drop connect.
+
+ Args:
+ input (tensor: BCWH): Input of this structure.
+ p (float: 0.0~1.0): Probability of drop connection.
+ training (bool): The running mode.
+
+ Returns:
+ output: Output after drop connection.
+ """
+ assert 0 <= p <= 1, 'p must be in range of [0,1]'
+
+ if not training:
+ return inputs
+
+ batch_size = inputs.shape[0]
+ keep_prob = 1 - p
+
+ # generate binary_tensor mask according to probability (p for 0, 1-p for 1)
+ random_tensor = keep_prob
+ random_tensor += torch.rand([batch_size, 1, 1, 1], dtype=inputs.dtype, device=inputs.device)
+ binary_tensor = torch.floor(random_tensor)
+
+ output = inputs / keep_prob * binary_tensor
+ return output
+
+
+def get_width_and_height_from_size(x):
+ """Obtain height and width from x.
+
+ Args:
+ x (int, tuple or list): Data size.
+
+ Returns:
+ size: A tuple or list (H,W).
+ """
+ if isinstance(x, int):
+ return x, x
+ if isinstance(x, list) or isinstance(x, tuple):
+ return x
+ else:
+ raise TypeError()
+
+
+def calculate_output_image_size(input_image_size, stride):
+ """Calculates the output image size when using Conv2dSamePadding with a stride.
+ Necessary for static padding. Thanks to mannatsingh for pointing this out.
+
+ Args:
+ input_image_size (int, tuple or list): Size of input image.
+ stride (int, tuple or list): Conv2d operation's stride.
+
+ Returns:
+ output_image_size: A list [H,W].
+ """
+ if input_image_size is None:
+ return None
+ image_height, image_width = get_width_and_height_from_size(input_image_size)
+ stride = stride if isinstance(stride, int) else stride[0]
+ image_height = int(math.ceil(image_height / stride))
+ image_width = int(math.ceil(image_width / stride))
+ return [image_height, image_width]
+
+
+# Note:
+# The following 'SamePadding' functions make output size equal ceil(input size/stride).
+# Only when stride equals 1, can the output size be the same as input size.
+# Don't be confused by their function names ! ! !
+
+def get_same_padding_conv2d(image_size=None):
+ """Chooses static padding if you have specified an image size, and dynamic padding otherwise.
+ Static padding is necessary for ONNX exporting of models.
+
+ Args:
+ image_size (int or tuple): Size of the image.
+
+ Returns:
+ Conv2dDynamicSamePadding or Conv2dStaticSamePadding.
+ """
+ if image_size is None:
+ return Conv2dDynamicSamePadding
+ else:
+ return partial(Conv2dStaticSamePadding, image_size=image_size)
+
+
+class Conv2dDynamicSamePadding(nn.Conv2d):
+ """2D Convolutions like TensorFlow, for a dynamic image size.
+ The padding is operated in forward function by calculating dynamically.
+ """
+
+ # Tips for 'SAME' mode padding.
+ # Given the following:
+ # i: width or height
+ # s: stride
+ # k: kernel size
+ # d: dilation
+ # p: padding
+ # Output after Conv2d:
+ # o = floor((i+p-((k-1)*d+1))/s+1)
+ # If o equals i, i = floor((i+p-((k-1)*d+1))/s+1),
+ # => p = (i-1)*s+((k-1)*d+1)-i
+
+ def __init__(self, in_channels, out_channels, kernel_size, stride=1, dilation=1, groups=1, bias=True):
+ super().__init__(in_channels, out_channels, kernel_size, stride, 0, dilation, groups, bias)
+ self.stride = self.stride if len(self.stride) == 2 else [self.stride[0]] * 2
+
+ def forward(self, x):
+ ih, iw = x.size()[-2:]
+ kh, kw = self.weight.size()[-2:]
+ sh, sw = self.stride
+ oh, ow = math.ceil(ih / sh), math.ceil(iw / sw) # change the output size according to stride ! ! !
+ pad_h = max((oh - 1) * self.stride[0] + (kh - 1) * self.dilation[0] + 1 - ih, 0)
+ pad_w = max((ow - 1) * self.stride[1] + (kw - 1) * self.dilation[1] + 1 - iw, 0)
+ if pad_h > 0 or pad_w > 0:
+ x = F.pad(x, [pad_w // 2, pad_w - pad_w // 2, pad_h // 2, pad_h - pad_h // 2])
+ return F.conv2d(x, self.weight, self.bias, self.stride, self.padding, self.dilation, self.groups)
+
+
+class Conv2dStaticSamePadding(nn.Conv2d):
+ """2D Convolutions like TensorFlow's 'SAME' mode, with the given input image size.
+ The padding mudule is calculated in construction function, then used in forward.
+ """
+
+ # With the same calculation as Conv2dDynamicSamePadding
+
+ def __init__(self, in_channels, out_channels, kernel_size, stride=1, image_size=None, **kwargs):
+ super().__init__(in_channels, out_channels, kernel_size, stride, **kwargs)
+ self.stride = self.stride if len(self.stride) == 2 else [self.stride[0]] * 2
+
+ # Calculate padding based on image size and save it
+ assert image_size is not None
+ ih, iw = (image_size, image_size) if isinstance(image_size, int) else image_size
+ kh, kw = self.weight.size()[-2:]
+ sh, sw = self.stride
+ oh, ow = math.ceil(ih / sh), math.ceil(iw / sw)
+ pad_h = max((oh - 1) * self.stride[0] + (kh - 1) * self.dilation[0] + 1 - ih, 0)
+ pad_w = max((ow - 1) * self.stride[1] + (kw - 1) * self.dilation[1] + 1 - iw, 0)
+ if pad_h > 0 or pad_w > 0:
+ self.static_padding = nn.ZeroPad2d((pad_w // 2, pad_w - pad_w // 2,
+ pad_h // 2, pad_h - pad_h // 2))
+ else:
+ self.static_padding = nn.Identity()
+
+ def forward(self, x):
+ x = self.static_padding(x)
+ x = F.conv2d(x, self.weight, self.bias, self.stride, self.padding, self.dilation, self.groups)
+ return x
+
+
+def get_same_padding_maxPool2d(image_size=None):
+ """Chooses static padding if you have specified an image size, and dynamic padding otherwise.
+ Static padding is necessary for ONNX exporting of models.
+
+ Args:
+ image_size (int or tuple): Size of the image.
+
+ Returns:
+ MaxPool2dDynamicSamePadding or MaxPool2dStaticSamePadding.
+ """
+ if image_size is None:
+ return MaxPool2dDynamicSamePadding
+ else:
+ return partial(MaxPool2dStaticSamePadding, image_size=image_size)
+
+
+class MaxPool2dDynamicSamePadding(nn.MaxPool2d):
+ """2D MaxPooling like TensorFlow's 'SAME' mode, with a dynamic image size.
+ The padding is operated in forward function by calculating dynamically.
+ """
+
+ def __init__(self, kernel_size, stride, padding=0, dilation=1, return_indices=False, ceil_mode=False):
+ super().__init__(kernel_size, stride, padding, dilation, return_indices, ceil_mode)
+ self.stride = [self.stride] * 2 if isinstance(self.stride, int) else self.stride
+ self.kernel_size = [self.kernel_size] * 2 if isinstance(self.kernel_size, int) else self.kernel_size
+ self.dilation = [self.dilation] * 2 if isinstance(self.dilation, int) else self.dilation
+
+ def forward(self, x):
+ ih, iw = x.size()[-2:]
+ kh, kw = self.kernel_size
+ sh, sw = self.stride
+ oh, ow = math.ceil(ih / sh), math.ceil(iw / sw)
+ pad_h = max((oh - 1) * self.stride[0] + (kh - 1) * self.dilation[0] + 1 - ih, 0)
+ pad_w = max((ow - 1) * self.stride[1] + (kw - 1) * self.dilation[1] + 1 - iw, 0)
+ if pad_h > 0 or pad_w > 0:
+ x = F.pad(x, [pad_w // 2, pad_w - pad_w // 2, pad_h // 2, pad_h - pad_h // 2])
+ return F.max_pool2d(x, self.kernel_size, self.stride, self.padding,
+ self.dilation, self.ceil_mode, self.return_indices)
+
+
+class MaxPool2dStaticSamePadding(nn.MaxPool2d):
+ """2D MaxPooling like TensorFlow's 'SAME' mode, with the given input image size.
+ The padding mudule is calculated in construction function, then used in forward.
+ """
+
+ def __init__(self, kernel_size, stride, image_size=None, **kwargs):
+ super().__init__(kernel_size, stride, **kwargs)
+ self.stride = [self.stride] * 2 if isinstance(self.stride, int) else self.stride
+ self.kernel_size = [self.kernel_size] * 2 if isinstance(self.kernel_size, int) else self.kernel_size
+ self.dilation = [self.dilation] * 2 if isinstance(self.dilation, int) else self.dilation
+
+ # Calculate padding based on image size and save it
+ assert image_size is not None
+ ih, iw = (image_size, image_size) if isinstance(image_size, int) else image_size
+ kh, kw = self.kernel_size
+ sh, sw = self.stride
+ oh, ow = math.ceil(ih / sh), math.ceil(iw / sw)
+ pad_h = max((oh - 1) * self.stride[0] + (kh - 1) * self.dilation[0] + 1 - ih, 0)
+ pad_w = max((ow - 1) * self.stride[1] + (kw - 1) * self.dilation[1] + 1 - iw, 0)
+ if pad_h > 0 or pad_w > 0:
+ self.static_padding = nn.ZeroPad2d((pad_w // 2, pad_w - pad_w // 2, pad_h // 2, pad_h - pad_h // 2))
+ else:
+ self.static_padding = nn.Identity()
+
+ def forward(self, x):
+ x = self.static_padding(x)
+ x = F.max_pool2d(x, self.kernel_size, self.stride, self.padding,
+ self.dilation, self.ceil_mode, self.return_indices)
+ return x
+
+
+################################################################################
+# Helper functions for loading model params
+################################################################################
+
+# BlockDecoder: A Class for encoding and decoding BlockArgs
+# efficientnet_params: A function to query compound coefficient
+# get_model_params and efficientnet:
+# Functions to get BlockArgs and GlobalParams for efficientnet
+# url_map and url_map_advprop: Dicts of url_map for pretrained weights
+# load_pretrained_weights: A function to load pretrained weights
+
+class BlockDecoder(object):
+ """Block Decoder for readability,
+ straight from the official TensorFlow repository.
+ """
+
+ @staticmethod
+ def _decode_block_string(block_string):
+ """Get a block through a string notation of arguments.
+
+ Args:
+ block_string (str): A string notation of arguments.
+ Examples: 'r1_k3_s11_e1_i32_o16_se0.25_noskip'.
+
+ Returns:
+ BlockArgs: The namedtuple defined at the top of this file.
+ """
+ assert isinstance(block_string, str)
+
+ ops = block_string.split('_')
+ options = {}
+ for op in ops:
+ splits = re.split(r'(\d.*)', op)
+ if len(splits) >= 2:
+ key, value = splits[:2]
+ options[key] = value
+
+ # Check stride
+ assert (('s' in options and len(options['s']) == 1) or
+ (len(options['s']) == 2 and options['s'][0] == options['s'][1]))
+
+ return BlockArgs(
+ num_repeat=int(options['r']),
+ kernel_size=int(options['k']),
+ stride=[int(options['s'][0])],
+ expand_ratio=int(options['e']),
+ input_filters=int(options['i']),
+ output_filters=int(options['o']),
+ se_ratio=float(options['se']) if 'se' in options else None,
+ id_skip=('noskip' not in block_string))
+
+ @staticmethod
+ def _encode_block_string(block):
+ """Encode a block to a string.
+
+ Args:
+ block (namedtuple): A BlockArgs type argument.
+
+ Returns:
+ block_string: A String form of BlockArgs.
+ """
+ args = [
+ 'r%d' % block.num_repeat,
+ 'k%d' % block.kernel_size,
+ 's%d%d' % (block.strides[0], block.strides[1]),
+ 'e%s' % block.expand_ratio,
+ 'i%d' % block.input_filters,
+ 'o%d' % block.output_filters
+ ]
+ if 0 < block.se_ratio <= 1:
+ args.append('se%s' % block.se_ratio)
+ if block.id_skip is False:
+ args.append('noskip')
+ return '_'.join(args)
+
+ @staticmethod
+ def decode(string_list):
+ """Decode a list of string notations to specify blocks inside the network.
+
+ Args:
+ string_list (list[str]): A list of strings, each string is a notation of block.
+
+ Returns:
+ blocks_args: A list of BlockArgs namedtuples of block args.
+ """
+ assert isinstance(string_list, list)
+ blocks_args = []
+ for block_string in string_list:
+ blocks_args.append(BlockDecoder._decode_block_string(block_string))
+ return blocks_args
+
+ @staticmethod
+ def encode(blocks_args):
+ """Encode a list of BlockArgs to a list of strings.
+
+ Args:
+ blocks_args (list[namedtuples]): A list of BlockArgs namedtuples of block args.
+
+ Returns:
+ block_strings: A list of strings, each string is a notation of block.
+ """
+ block_strings = []
+ for block in blocks_args:
+ block_strings.append(BlockDecoder._encode_block_string(block))
+ return block_strings
+
+
+def efficientnet_params(model_name):
+ """Map EfficientNet model name to parameter coefficients.
+
+ Args:
+ model_name (str): Model name to be queried.
+
+ Returns:
+ params_dict[model_name]: A (width,depth,res,dropout) tuple.
+ """
+ params_dict = {
+ # Coefficients: width,depth,res,dropout
+ 'efficientnet-b0': (1.0, 1.0, 224, 0.2),
+ 'efficientnet-b1': (1.0, 1.1, 240, 0.2),
+ 'efficientnet-b2': (1.1, 1.2, 260, 0.3),
+ 'efficientnet-b3': (1.2, 1.4, 300, 0.3),
+ 'efficientnet-b4': (1.4, 1.8, 380, 0.4),
+ 'efficientnet-b5': (1.6, 2.2, 456, 0.4),
+ 'efficientnet-b6': (1.8, 2.6, 528, 0.5),
+ 'efficientnet-b7': (2.0, 3.1, 600, 0.5),
+ 'efficientnet-b8': (2.2, 3.6, 672, 0.5),
+ 'efficientnet-l2': (4.3, 5.3, 800, 0.5),
+ }
+ return params_dict[model_name]
+
+
+def efficientnet(width_coefficient=None, depth_coefficient=None, image_size=None,
+ dropout_rate=0.2, drop_connect_rate=0.2, num_classes=1000, include_top=True):
+ """Create BlockArgs and GlobalParams for efficientnet model.
+
+ Args:
+ width_coefficient (float)
+ depth_coefficient (float)
+ image_size (int)
+ dropout_rate (float)
+ drop_connect_rate (float)
+ num_classes (int)
+
+ Meaning as the name suggests.
+
+ Returns:
+ blocks_args, global_params.
+ """
+
+ # Blocks args for the whole model(efficientnet-b0 by default)
+ # It will be modified in the construction of EfficientNet Class according to model
+ blocks_args = [
+ 'r1_k3_s11_e1_i32_o16_se0.25',
+ 'r2_k3_s22_e6_i16_o24_se0.25',
+ 'r2_k5_s22_e6_i24_o40_se0.25',
+ 'r3_k3_s22_e6_i40_o80_se0.25',
+ 'r3_k5_s11_e6_i80_o112_se0.25',
+ 'r4_k5_s22_e6_i112_o192_se0.25',
+ 'r1_k3_s11_e6_i192_o320_se0.25',
+ ]
+ blocks_args = BlockDecoder.decode(blocks_args)
+
+ global_params = GlobalParams(
+ width_coefficient=width_coefficient,
+ depth_coefficient=depth_coefficient,
+ image_size=image_size,
+ dropout_rate=dropout_rate,
+
+ num_classes=num_classes,
+ batch_norm_momentum=0.99,
+ batch_norm_epsilon=1e-3,
+ drop_connect_rate=drop_connect_rate,
+ depth_divisor=8,
+ min_depth=None,
+ include_top=include_top,
+ )
+
+ return blocks_args, global_params
+
+
+def get_model_params(model_name, override_params):
+ """Get the block args and global params for a given model name.
+
+ Args:
+ model_name (str): Model's name.
+ override_params (dict): A dict to modify global_params.
+
+ Returns:
+ blocks_args, global_params
+ """
+ if model_name.startswith('efficientnet'):
+ w, d, s, p = efficientnet_params(model_name)
+ # note: all models have drop connect rate = 0.2
+ blocks_args, global_params = efficientnet(
+ width_coefficient=w, depth_coefficient=d, dropout_rate=p, image_size=s)
+ else:
+ raise NotImplementedError('model name is not pre-defined: {}'.format(model_name))
+ if override_params:
+ # ValueError will be raised here if override_params has fields not included in global_params.
+ global_params = global_params._replace(**override_params)
+ return blocks_args, global_params
+
+
+# train with Standard methods
+# check more details in paper(EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks)
+url_map = {
+ 'efficientnet-b0': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b0-355c32eb.pth',
+ 'efficientnet-b1': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b1-f1951068.pth',
+ 'efficientnet-b2': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b2-8bb594d6.pth',
+ 'efficientnet-b3': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b3-5fb5a3c3.pth',
+ 'efficientnet-b4': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b4-6ed6700e.pth',
+ 'efficientnet-b5': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b5-b6417697.pth',
+ 'efficientnet-b6': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b6-c76e70fd.pth',
+ 'efficientnet-b7': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b7-dcc49843.pth',
+}
+
+# train with Adversarial Examples(AdvProp)
+# check more details in paper(Adversarial Examples Improve Image Recognition)
+url_map_advprop = {
+ 'efficientnet-b0': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b0-b64d5a18.pth',
+ 'efficientnet-b1': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b1-0f3ce85a.pth',
+ 'efficientnet-b2': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b2-6e9d97e5.pth',
+ 'efficientnet-b3': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b3-cdd7c0f4.pth',
+ 'efficientnet-b4': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b4-44fb3a87.pth',
+ 'efficientnet-b5': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b5-86493f6b.pth',
+ 'efficientnet-b6': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b6-ac80338e.pth',
+ 'efficientnet-b7': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b7-4652b6dd.pth',
+ 'efficientnet-b8': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b8-22a8fe65.pth',
+}
+
+# TODO: add the petrained weights url map of 'efficientnet-l2'
+
+
+def load_pretrained_weights(model, model_name, weights_path=None, load_fc=True, advprop=False, verbose=True):
+ """Loads pretrained weights from weights path or download using url.
+
+ Args:
+ model (Module): The whole model of efficientnet.
+ model_name (str): Model name of efficientnet.
+ weights_path (None or str):
+ str: path to pretrained weights file on the local disk.
+ None: use pretrained weights downloaded from the Internet.
+ load_fc (bool): Whether to load pretrained weights for fc layer at the end of the model.
+ advprop (bool): Whether to load pretrained weights
+ trained with advprop (valid when weights_path is None).
+ """
+ if isinstance(weights_path, str):
+ state_dict = torch.load(weights_path)
+ else:
+ # AutoAugment or Advprop (different preprocessing)
+ url_map_ = url_map_advprop if advprop else url_map
+ state_dict = model_zoo.load_url(url_map_[model_name])
+
+ if load_fc:
+ ret = model.load_state_dict(state_dict, strict=False)
+ assert not ret.missing_keys, 'Missing keys when loading pretrained weights: {}'.format(ret.missing_keys)
+ else:
+ state_dict.pop('_fc.weight')
+ state_dict.pop('_fc.bias')
+ ret = model.load_state_dict(state_dict, strict=False)
+ assert set(ret.missing_keys) == set(
+ ['_fc.weight', '_fc.bias']), 'Missing keys when loading pretrained weights: {}'.format(ret.missing_keys)
+ assert not ret.unexpected_keys, 'Missing keys when loading pretrained weights: {}'.format(ret.unexpected_keys)
+
+ if verbose:
+ print('Loaded pretrained weights for {}'.format(model_name))
diff --git a/clean/video/mintime/cross-efficient-vit/efficient_net/hubconf.py b/clean/video/mintime/cross-efficient-vit/efficient_net/hubconf.py
new file mode 100644
index 0000000000000000000000000000000000000000..dd0ea978cabcc7676bff4fcd18e7a0555eda98ab
--- /dev/null
+++ b/clean/video/mintime/cross-efficient-vit/efficient_net/hubconf.py
@@ -0,0 +1,43 @@
+from efficientnet_pytorch import EfficientNet as _EfficientNet
+
+dependencies = ['torch']
+
+
+def _create_model_fn(model_name):
+ def _model_fn(num_classes=1000, in_channels=3, pretrained='imagenet'):
+ """Create Efficient Net.
+
+ Described in detail here: https://arxiv.org/abs/1905.11946
+
+ Args:
+ num_classes (int, optional): Number of classes, default is 1000.
+ in_channels (int, optional): Number of input channels, default
+ is 3.
+ pretrained (str, optional): One of [None, 'imagenet', 'advprop']
+ If None, no pretrained model is loaded.
+ If 'imagenet', models trained on imagenet dataset are loaded.
+ If 'advprop', models trained using adversarial training called
+ advprop are loaded. It is important to note that the
+ preprocessing required for the advprop pretrained models is
+ slightly different from normal ImageNet preprocessing
+ """
+ model_name_ = model_name.replace('_', '-')
+ if pretrained is not None:
+ model = _EfficientNet.from_pretrained(
+ model_name=model_name_,
+ advprop=(pretrained == 'advprop'),
+ num_classes=num_classes,
+ in_channels=in_channels)
+ else:
+ model = _EfficientNet.from_name(
+ model_name=model_name_,
+ override_params={'num_classes': num_classes},
+ )
+ model._change_in_channels(in_channels)
+
+ return model
+
+ return _model_fn
+
+for model_name in ['efficientnet_b' + str(i) for i in range(9)]:
+ locals()[model_name] = _create_model_fn(model_name)
diff --git a/clean/video/mintime/cross-efficient-vit/efficient_net/logs b/clean/video/mintime/cross-efficient-vit/efficient_net/logs
new file mode 100644
index 0000000000000000000000000000000000000000..01c8dba67c1647ce3e8b10bfad8521f2e112ee67
--- /dev/null
+++ b/clean/video/mintime/cross-efficient-vit/efficient_net/logs
@@ -0,0 +1,46 @@
+Train images: 141230 Validation images: 8070
+__TRAINING STATS__
+Counter({1.0: 88531, 0.0: 52699})
+Weights 0.5952604172549728
+__VALIDATION STATS__
+Counter({0: 4198, 1: 3872})
+
+#0/300 loss:0.5136975361087457 accuracy:0.5732563902853501 val_loss:0.5364688427299703 val_accuracy:0.6002478314745973 val_0s:4678/4198 val_1s:3392/3872
+#1/300 loss:0.4748700084961793 accuracy:0.6409332294838207 val_loss:0.5375074183976265 val_accuracy:0.6192069392812887 val_0s:4395/4198 val_1s:3675/3872
+#2/300 loss:0.4591452846219224 accuracy:0.6621114494087659 val_loss:0.5839169139465875 val_accuracy:0.614002478314746 val_0s:2867/4198 val_1s:5203/3872
+#3/300 loss:0.4471282922684823 accuracy:0.6749203427033916 val_loss:0.5183086053412465 val_accuracy:0.628004956629492 val_0s:4636/4198 val_1s:3434/3872
+#4/300 loss:0.4380730671197989 accuracy:0.6847766055370672 val_loss:0.5090801186943618 val_accuracy:0.5711276332094176 val_0s:7007/4198 val_1s:1063/3872
+#5/300 loss:0.4327000849617695 accuracy:0.6904552857041705 val_loss:0.5188724035608308 val_accuracy:0.6338289962825279 val_0s:4449/4198 val_1s:3621/3872
+#6/300 loss:0.42427017841971437 accuracy:0.6993769029243079 val_loss:0.527833827893175 val_accuracy:0.6415117719950434 val_0s:4149/4198 val_1s:3921/3872
+#7/300 loss:0.4212744265080735 accuracy:0.7030163562982369 val_loss:0.5026112759643917 val_accuracy:0.6396530359355638 val_0s:5058/4198 val_1s:3012/3872
+#8/300 loss:0.4154885301614286 accuracy:0.7076683424201657 val_loss:0.5432640949554897 val_accuracy:0.6465923172242874 val_0s:4044/4198 val_1s:4026/3872
+#9/300 loss:0.4123908241291415 accuracy:0.710812150392976 val_loss:0.5210385756676557 val_accuracy:0.6503097893432466 val_0s:4164/4198 val_1s:3906/3872
+#10/300 loss:0.40723704333050326 accuracy:0.7136939743680522 val_loss:0.5589614243323435 val_accuracy:0.6472118959107807 val_0s:3179/4198 val_1s:4891/3872
+#11/300 loss:0.402232795242142 accuracy:0.7185654605961906 val_loss:0.5192581602373888 val_accuracy:0.6350681536555143 val_0s:4991/4198 val_1s:3079/3872
+#12/300 loss:0.39900764655904725 accuracy:0.7225235431565531 val_loss:0.5632047477744805 val_accuracy:0.6503097893432466 val_0s:3448/4198 val_1s:4622/3872
+#14/300 loss:0.5343504934649247 accuracy:0.7136664258322681 val_loss:0.9343544303797466 val_accuracy:0.57053852
+#15/300 loss:0.525838890370766 accuracy:0.7187906408047574 val_loss:0.8023291139240499 val_accuracy:0.614572332
+#16/300 loss:0.5172125900240065 accuracy:0.7257766909353638 val_loss:0.6720759493670888 val_accuracy:0.64656812
+#17/300 loss:0.5092864763937068 accuracy:0.7304396154059912 val_loss:0.679392405063291 val_accuracy:0.6568109820485745 val_0s:37742
+#18/300 loss:0.5029607895438754 accuracy:0.7338798421608403 val_loss:1.3394683544303796 val_accuracy:0.50200632
+#19/300 loss:0.49735662843424994 accuracy:0.7380870338464959 val_loss:0.8208860759493672 val_accuracy:0.5971482
+#20/300 loss:0.4908455588156868 accuracy:0.7425498805090869 val_loss:0.668025316455696 val_accuracy:0.640232312
+#21/300 loss:0.48448919711923205 accuracy:0.745934530095037 val_loss:0.8548101265822788 val_accuracy:0.586272439281943 val_0s:71562
+#22/300 loss:0.4819138436916507 accuracy:0.7464736286333574 val_loss:0.8362784810126573 val_accuracy:0.6214361140443506 val_0s:1512
+#23/300 loss:0.4766591090957589 accuracy:0.7510865336519758 val_loss:0.8313924050632903 val_accuracy:0.6175290390707497 val_0s:5592
+
+Train images: 324636 Validation images: 9470
+__TRAINING STATS__
+Counter({1.0: 184165, 0.0: 140471})
+Weights 0.7627453642114408
+__VALIDATION STATS__
+Counter({1: 5272, 0.0: 4198})
+
+
+#0/300 loss:0.577774820728925 accuracy:0.5991941743984032 val_loss:0.6628860759493668 val_accuracy:0.5971488912354804 val_0s:2313/4198 val_1s:7157/5272
+#1/300 loss:0.5315613218008431 accuracy:0.661925972473786 val_loss:0.6108101265822785 val_accuracy:0.5901795142555438 val_0s:3371/4198 val_1s:6099/5272
+#2/300 loss:0.5131625637613617 accuracy:0.6794471346369473 val_loss:0.6132911392405063 val_accuracy:0.5706441393875396 val_0s:6406/4198 val_1s:3064/5272
+#3/300 loss:0.49969690249131055 accuracy:0.6905796030015156 val_loss:0.5810126582278485 val_accuracy:0.6125659978880675 val_0s:5133/4198 val_1s:4337/5272
+#4/300 loss:0.4878531825238368 accuracy:0.7005754136941066 val_loss:0.5803544303797468 val_accuracy:0.6221752903907075 val_0s:4904/4198 val_1s:4566/5272
+#5/300 loss:0.47785761809713456 accuracy:0.7076171465887948 val_loss:0.599493670886076 val_accuracy:0.6082365364308342 val_0s:4704/4198 val_1s:4766/5272
+#6/300 loss:0.4679618540696333 accuracy:0.7164331743860817 val_loss:0.5943291139240504 val_accuracy:0.6158394931362197 val_0s:5984/4198 val_1s:3486/5272
\ No newline at end of file
diff --git a/clean/video/mintime/cross-efficient-vit/efficient_net/setup.py b/clean/video/mintime/cross-efficient-vit/efficient_net/setup.py
new file mode 100644
index 0000000000000000000000000000000000000000..eb8d95a136169d2178f6525965afac2ab2a824aa
--- /dev/null
+++ b/clean/video/mintime/cross-efficient-vit/efficient_net/setup.py
@@ -0,0 +1,123 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Note: To use the 'upload' functionality of this file, you must:
+# $ pipenv install twine --dev
+
+import io
+import os
+import sys
+from shutil import rmtree
+
+from setuptools import find_packages, setup, Command
+
+# Package meta-data.
+NAME = 'efficientnet_pytorch'
+DESCRIPTION = 'EfficientNet implemented in PyTorch.'
+URL = 'https://github.com/lukemelas/EfficientNet-PyTorch'
+EMAIL = 'lmelaskyriazi@college.harvard.edu'
+AUTHOR = 'Luke'
+REQUIRES_PYTHON = '>=3.5.0'
+VERSION = '0.7.1'
+
+# What packages are required for this module to be executed?
+REQUIRED = [
+ 'torch'
+]
+
+# What packages are optional?
+EXTRAS = {
+ # 'fancy feature': ['django'],
+}
+
+# The rest you shouldn't have to touch too much :)
+# ------------------------------------------------
+# Except, perhaps the License and Trove Classifiers!
+# If you do change the License, remember to change the Trove Classifier for that!
+
+here = os.path.abspath(os.path.dirname(__file__))
+
+# Import the README and use it as the long-description.
+# Note: this will only work if 'README.md' is present in your MANIFEST.in file!
+try:
+ with io.open(os.path.join(here, 'README.md'), encoding='utf-8') as f:
+ long_description = '\n' + f.read()
+except FileNotFoundError:
+ long_description = DESCRIPTION
+
+# Load the package's __version__.py module as a dictionary.
+about = {}
+if not VERSION:
+ project_slug = NAME.lower().replace("-", "_").replace(" ", "_")
+ with open(os.path.join(here, project_slug, '__version__.py')) as f:
+ exec(f.read(), about)
+else:
+ about['__version__'] = VERSION
+
+
+class UploadCommand(Command):
+ """Support setup.py upload."""
+
+ description = 'Build and publish the package.'
+ user_options = []
+
+ @staticmethod
+ def status(s):
+ """Prints things in bold."""
+ print('\033[1m{0}\033[0m'.format(s))
+
+ def initialize_options(self):
+ pass
+
+ def finalize_options(self):
+ pass
+
+ def run(self):
+ try:
+ self.status('Removing previous builds…')
+ rmtree(os.path.join(here, 'dist'))
+ except OSError:
+ pass
+
+ self.status('Building Source and Wheel (universal) distribution…')
+ os.system('{0} setup.py sdist bdist_wheel --universal'.format(sys.executable))
+
+ self.status('Uploading the package to PyPI via Twine…')
+ os.system('twine upload dist/*')
+
+ self.status('Pushing git tags…')
+ os.system('git tag v{0}'.format(about['__version__']))
+ os.system('git push --tags')
+
+ sys.exit()
+
+
+# Where the magic happens:
+setup(
+ name=NAME,
+ version=about['__version__'],
+ description=DESCRIPTION,
+ long_description=long_description,
+ long_description_content_type='text/markdown',
+ author=AUTHOR,
+ author_email=EMAIL,
+ python_requires=REQUIRES_PYTHON,
+ url=URL,
+ packages=find_packages(exclude=["tests", "*.tests", "*.tests.*", "tests.*"]),
+ # py_modules=['model'], # If your package is a single module, use this instead of 'packages'
+ install_requires=REQUIRED,
+ extras_require=EXTRAS,
+ include_package_data=True,
+ license='Apache',
+ classifiers=[
+ # Full list: https://pypi.python.org/pypi?%3Aaction=list_classifiers
+ 'License :: OSI Approved :: Apache Software License',
+ 'Programming Language :: Python',
+ 'Programming Language :: Python :: 3',
+ 'Programming Language :: Python :: 3.6',
+ ],
+ # $ setup.py publish support.
+ cmdclass={
+ 'upload': UploadCommand,
+ },
+)
diff --git a/clean/video/mintime/cross-efficient-vit/efficient_net/sotabench.py b/clean/video/mintime/cross-efficient-vit/efficient_net/sotabench.py
new file mode 100644
index 0000000000000000000000000000000000000000..67816ff301d8cae39dde534edf688eeb010320c8
--- /dev/null
+++ b/clean/video/mintime/cross-efficient-vit/efficient_net/sotabench.py
@@ -0,0 +1,71 @@
+import os
+import numpy as np
+import PIL
+import torch
+from torch.utils.data import DataLoader
+import torchvision.transforms as transforms
+from torchvision.datasets import ImageNet
+
+from efficientnet_pytorch import EfficientNet
+
+from sotabencheval.image_classification import ImageNetEvaluator
+from sotabencheval.utils import is_server
+
+if is_server():
+ DATA_ROOT = DATA_ROOT = os.environ.get('IMAGENET_DIR', './imagenet') # './.data/vision/imagenet'
+else: # local settings
+ DATA_ROOT = os.environ['IMAGENET_DIR']
+ assert bool(DATA_ROOT), 'please set IMAGENET_DIR environment variable'
+ print('Local data root: ', DATA_ROOT)
+
+model_name = 'EfficientNet-B5'
+model = EfficientNet.from_pretrained(model_name.lower())
+image_size = EfficientNet.get_image_size(model_name.lower())
+
+input_transform = transforms.Compose([
+ transforms.Resize(image_size, PIL.Image.BICUBIC),
+ transforms.CenterCrop(image_size),
+ transforms.ToTensor(),
+ transforms.Normalize(
+ mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
+])
+
+test_dataset = ImageNet(
+ DATA_ROOT,
+ split="val",
+ transform=input_transform,
+ target_transform=None,
+)
+
+test_loader = DataLoader(
+ test_dataset,
+ batch_size=128,
+ shuffle=False,
+ num_workers=4,
+ pin_memory=True,
+)
+
+model = model.cuda()
+model.eval()
+
+evaluator = ImageNetEvaluator(model_name=model_name,
+ paper_arxiv_id='1905.11946')
+
+def get_img_id(image_name):
+ return image_name.split('/')[-1].replace('.JPEG', '')
+
+with torch.no_grad():
+ for i, (input, target) in enumerate(test_loader):
+ input = input.to(device='cuda', non_blocking=True)
+ target = target.to(device='cuda', non_blocking=True)
+ output = model(input)
+ image_ids = [get_img_id(img[0]) for img in test_loader.dataset.imgs[i*test_loader.batch_size:(i+1)*test_loader.batch_size]]
+ evaluator.add(dict(zip(image_ids, list(output.cpu().numpy()))))
+ if evaluator.cache_exists:
+ break
+
+if not is_server():
+ print("Results:")
+ print(evaluator.get_results())
+
+evaluator.save()
diff --git a/clean/video/mintime/cross-efficient-vit/efficient_net/sotabench_setup.sh b/clean/video/mintime/cross-efficient-vit/efficient_net/sotabench_setup.sh
new file mode 100644
index 0000000000000000000000000000000000000000..e45bdeaebb0e1e9b27caa419b3a38623ffff5983
--- /dev/null
+++ b/clean/video/mintime/cross-efficient-vit/efficient_net/sotabench_setup.sh
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash -x
+source /workspace/venv/bin/activate
+PYTHON=${PYTHON:-"python"}
+$PYTHON -m pip install torch
+$PYTHON -m pip install torchvision
+$PYTHON -m pip install scipy
diff --git a/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/README.md b/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..9699aa807198df8a5b776fd35fce5052baaf6783
--- /dev/null
+++ b/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/README.md
@@ -0,0 +1,25 @@
+### TensorFlow to PyTorch Conversion
+
+This directory is used to convert TensorFlow weights to PyTorch. It was hacked together fairly quickly, so the code is not the most beautiful (just a warning!), but it does the job. I will be refactoring it soon.
+
+I should also emphasize that you do *not* need to run any of this code to load pretrained weights. Simply use `EfficientNet.from_pretrained(...)`.
+
+That being said, the main script here is `convert_to_tf/load_tf_weights.py`. In order to use it, you should first download the pretrained TensorFlow weights:
+ ```bash
+cd pretrained_tensorflow
+./download.sh efficientnet-b0
+cd ..
+```
+Then
+```bash
+mkdir -p pretrained_pytorch
+cd convert_tf_to_pt
+python load_tf_weights.py \
+ --model_name efficientnet-b0 \
+ --tf_checkpoint ../pretrained_tensorflow/efficientnet-b0/ \
+ --output_file ../pretrained_pytorch/efficientnet-b0.pth
+```
+
+
diff --git a/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/download.sh b/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/download.sh
new file mode 100644
index 0000000000000000000000000000000000000000..6405dbd93e4f54338b1c7874ef89926491742f38
--- /dev/null
+++ b/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/download.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+
+mkdir original_tf
+cd original_tf
+touch __init__.py
+wget https://raw.githubusercontent.com/tensorflow/tpu/master/models/official/efficientnet/efficientnet_builder.py
+wget https://raw.githubusercontent.com/tensorflow/tpu/master/models/official/efficientnet/efficientnet_model.py
+wget https://raw.githubusercontent.com/tensorflow/tpu/master/models/official/efficientnet/eval_ckpt_main.py
+wget https://raw.githubusercontent.com/tensorflow/tpu/master/models/official/efficientnet/utils.py
+wget https://raw.githubusercontent.com/tensorflow/tpu/master/models/official/efficientnet/preprocessing.py
+cd ..
+mkdir -p tmp
\ No newline at end of file
diff --git a/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/load_tf_weights.py b/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/load_tf_weights.py
new file mode 100644
index 0000000000000000000000000000000000000000..22e296e87558b521a3c60f8de3c4a8031743d1b4
--- /dev/null
+++ b/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/load_tf_weights.py
@@ -0,0 +1,174 @@
+import numpy as np
+import tensorflow as tf
+import torch
+
+tf.compat.v1.disable_v2_behavior()
+
+def load_param(checkpoint_file, conversion_table, model_name):
+ """
+ Load parameters according to conversion_table.
+
+ Args:
+ checkpoint_file (string): pretrained checkpoint model file in tensorflow
+ conversion_table (dict): { pytorch tensor in a model : checkpoint variable name }
+ """
+ for pyt_param, tf_param_name in conversion_table.items():
+ tf_param_name = str(model_name) + '/' + tf_param_name
+ tf_param = tf.train.load_variable(checkpoint_file, tf_param_name)
+ if 'conv' in tf_param_name and 'kernel' in tf_param_name:
+ tf_param = np.transpose(tf_param, (3, 2, 0, 1))
+ if 'depthwise' in tf_param_name:
+ tf_param = np.transpose(tf_param, (1, 0, 2, 3))
+ elif tf_param_name.endswith('kernel'): # for weight(kernel), we should do transpose
+ tf_param = np.transpose(tf_param)
+ assert pyt_param.size() == tf_param.shape, \
+ 'Dim Mismatch: %s vs %s ; %s' % (tuple(pyt_param.size()), tf_param.shape, tf_param_name)
+ pyt_param.data = torch.from_numpy(tf_param)
+
+
+def load_efficientnet(model, checkpoint_file, model_name):
+ """
+ Load PyTorch EfficientNet from TensorFlow checkpoint file
+ """
+
+ # This will store the enire conversion table
+ conversion_table = {}
+ merge = lambda dict1, dict2: {**dict1, **dict2}
+
+ # All the weights not in the conv blocks
+ conversion_table_for_weights_outside_blocks = {
+ model._conv_stem.weight: 'stem/conv2d/kernel', # [3, 3, 3, 32]),
+ model._bn0.bias: 'stem/tpu_batch_normalization/beta', # [32]),
+ model._bn0.weight: 'stem/tpu_batch_normalization/gamma', # [32]),
+ model._bn0.running_mean: 'stem/tpu_batch_normalization/moving_mean', # [32]),
+ model._bn0.running_var: 'stem/tpu_batch_normalization/moving_variance', # [32]),
+ model._conv_head.weight: 'head/conv2d/kernel', # [1, 1, 320, 1280]),
+ model._bn1.bias: 'head/tpu_batch_normalization/beta', # [1280]),
+ model._bn1.weight: 'head/tpu_batch_normalization/gamma', # [1280]),
+ model._bn1.running_mean: 'head/tpu_batch_normalization/moving_mean', # [32]),
+ model._bn1.running_var: 'head/tpu_batch_normalization/moving_variance', # [32]),
+ model._fc.bias: 'head/dense/bias', # [1000]),
+ model._fc.weight: 'head/dense/kernel', # [1280, 1000]),
+ }
+ conversion_table = merge(conversion_table, conversion_table_for_weights_outside_blocks)
+
+ # The first conv block is special because it does not have _expand_conv
+ conversion_table_for_first_block = {
+ model._blocks[0]._project_conv.weight: 'blocks_0/conv2d/kernel', # 1, 1, 32, 16]),
+ model._blocks[0]._depthwise_conv.weight: 'blocks_0/depthwise_conv2d/depthwise_kernel', # [3, 3, 32, 1]),
+ model._blocks[0]._se_reduce.bias: 'blocks_0/se/conv2d/bias', # , [8]),
+ model._blocks[0]._se_reduce.weight: 'blocks_0/se/conv2d/kernel', # , [1, 1, 32, 8]),
+ model._blocks[0]._se_expand.bias: 'blocks_0/se/conv2d_1/bias', # , [32]),
+ model._blocks[0]._se_expand.weight: 'blocks_0/se/conv2d_1/kernel', # , [1, 1, 8, 32]),
+ model._blocks[0]._bn1.bias: 'blocks_0/tpu_batch_normalization/beta', # [32]),
+ model._blocks[0]._bn1.weight: 'blocks_0/tpu_batch_normalization/gamma', # [32]),
+ model._blocks[0]._bn1.running_mean: 'blocks_0/tpu_batch_normalization/moving_mean',
+ model._blocks[0]._bn1.running_var: 'blocks_0/tpu_batch_normalization/moving_variance',
+ model._blocks[0]._bn2.bias: 'blocks_0/tpu_batch_normalization_1/beta', # [16]),
+ model._blocks[0]._bn2.weight: 'blocks_0/tpu_batch_normalization_1/gamma', # [16]),
+ model._blocks[0]._bn2.running_mean: 'blocks_0/tpu_batch_normalization_1/moving_mean',
+ model._blocks[0]._bn2.running_var: 'blocks_0/tpu_batch_normalization_1/moving_variance',
+ }
+ conversion_table = merge(conversion_table, conversion_table_for_first_block)
+
+ # Conv blocks
+ for i in range(len(model._blocks)):
+
+ is_first_block = '_expand_conv.weight' not in [n for n, p in model._blocks[i].named_parameters()]
+
+ if is_first_block:
+ conversion_table_block = {
+ model._blocks[i]._project_conv.weight: 'blocks_' + str(i) + '/conv2d/kernel', # 1, 1, 32, 16]),
+ model._blocks[i]._depthwise_conv.weight: 'blocks_' + str(i) + '/depthwise_conv2d/depthwise_kernel',
+ # [3, 3, 32, 1]),
+ model._blocks[i]._se_reduce.bias: 'blocks_' + str(i) + '/se/conv2d/bias', # , [8]),
+ model._blocks[i]._se_reduce.weight: 'blocks_' + str(i) + '/se/conv2d/kernel', # , [1, 1, 32, 8]),
+ model._blocks[i]._se_expand.bias: 'blocks_' + str(i) + '/se/conv2d_1/bias', # , [32]),
+ model._blocks[i]._se_expand.weight: 'blocks_' + str(i) + '/se/conv2d_1/kernel', # , [1, 1, 8, 32]),
+ model._blocks[i]._bn1.bias: 'blocks_' + str(i) + '/tpu_batch_normalization/beta', # [32]),
+ model._blocks[i]._bn1.weight: 'blocks_' + str(i) + '/tpu_batch_normalization/gamma', # [32]),
+ model._blocks[i]._bn1.running_mean: 'blocks_' + str(i) + '/tpu_batch_normalization/moving_mean',
+ model._blocks[i]._bn1.running_var: 'blocks_' + str(i) + '/tpu_batch_normalization/moving_variance',
+ model._blocks[i]._bn2.bias: 'blocks_' + str(i) + '/tpu_batch_normalization_1/beta', # [16]),
+ model._blocks[i]._bn2.weight: 'blocks_' + str(i) + '/tpu_batch_normalization_1/gamma', # [16]),
+ model._blocks[i]._bn2.running_mean: 'blocks_' + str(i) + '/tpu_batch_normalization_1/moving_mean',
+ model._blocks[i]._bn2.running_var: 'blocks_' + str(i) + '/tpu_batch_normalization_1/moving_variance',
+ }
+
+ else:
+ conversion_table_block = {
+ model._blocks[i]._expand_conv.weight: 'blocks_' + str(i) + '/conv2d/kernel',
+ model._blocks[i]._project_conv.weight: 'blocks_' + str(i) + '/conv2d_1/kernel',
+ model._blocks[i]._depthwise_conv.weight: 'blocks_' + str(i) + '/depthwise_conv2d/depthwise_kernel',
+ model._blocks[i]._se_reduce.bias: 'blocks_' + str(i) + '/se/conv2d/bias',
+ model._blocks[i]._se_reduce.weight: 'blocks_' + str(i) + '/se/conv2d/kernel',
+ model._blocks[i]._se_expand.bias: 'blocks_' + str(i) + '/se/conv2d_1/bias',
+ model._blocks[i]._se_expand.weight: 'blocks_' + str(i) + '/se/conv2d_1/kernel',
+ model._blocks[i]._bn0.bias: 'blocks_' + str(i) + '/tpu_batch_normalization/beta',
+ model._blocks[i]._bn0.weight: 'blocks_' + str(i) + '/tpu_batch_normalization/gamma',
+ model._blocks[i]._bn0.running_mean: 'blocks_' + str(i) + '/tpu_batch_normalization/moving_mean',
+ model._blocks[i]._bn0.running_var: 'blocks_' + str(i) + '/tpu_batch_normalization/moving_variance',
+ model._blocks[i]._bn1.bias: 'blocks_' + str(i) + '/tpu_batch_normalization_1/beta',
+ model._blocks[i]._bn1.weight: 'blocks_' + str(i) + '/tpu_batch_normalization_1/gamma',
+ model._blocks[i]._bn1.running_mean: 'blocks_' + str(i) + '/tpu_batch_normalization_1/moving_mean',
+ model._blocks[i]._bn1.running_var: 'blocks_' + str(i) + '/tpu_batch_normalization_1/moving_variance',
+ model._blocks[i]._bn2.bias: 'blocks_' + str(i) + '/tpu_batch_normalization_2/beta',
+ model._blocks[i]._bn2.weight: 'blocks_' + str(i) + '/tpu_batch_normalization_2/gamma',
+ model._blocks[i]._bn2.running_mean: 'blocks_' + str(i) + '/tpu_batch_normalization_2/moving_mean',
+ model._blocks[i]._bn2.running_var: 'blocks_' + str(i) + '/tpu_batch_normalization_2/moving_variance',
+ }
+
+ conversion_table = merge(conversion_table, conversion_table_block)
+
+ # Load TensorFlow parameters into PyTorch model
+ load_param(checkpoint_file, conversion_table, model_name)
+ return conversion_table
+
+
+def load_and_save_temporary_tensorflow_model(model_name, model_ckpt, example_img= '../../example/img.jpg'):
+ """ Loads and saves a TensorFlow model. """
+ image_files = [example_img]
+ eval_ckpt_driver = eval_ckpt_main.EvalCkptDriver(model_name)
+ with tf.Graph().as_default(), tf.compat.v1.Session() as sess:
+ images, labels = eval_ckpt_driver.build_dataset(image_files, [0] * len(image_files), False)
+ probs = eval_ckpt_driver.build_model(images, is_training=False)
+ sess.run(tf.compat.v1.global_variables_initializer())
+ print(model_ckpt)
+ eval_ckpt_driver.restore_model(sess, model_ckpt)
+ tf.compat.v1.train.Saver().save(sess, 'tmp/model.ckpt')
+
+
+if __name__ == '__main__':
+
+ import sys
+ import argparse
+
+ sys.path.append('original_tf')
+ import eval_ckpt_main
+
+ from efficientnet_pytorch import EfficientNet
+
+ parser = argparse.ArgumentParser(
+ description='Convert TF model to PyTorch model and save for easier future loading')
+ parser.add_argument('--model_name', type=str, default='efficientnet-b0',
+ help='efficientnet-b{N}, where N is an integer 0 <= N <= 8')
+ parser.add_argument('--tf_checkpoint', type=str, default='pretrained_tensorflow/efficientnet-b0/',
+ help='checkpoint file path')
+ parser.add_argument('--output_file', type=str, default='pretrained_pytorch/efficientnet-b0.pth',
+ help='output PyTorch model file name')
+ args = parser.parse_args()
+
+ # Build model
+ model = EfficientNet.from_name(args.model_name)
+
+ # Load and save temporary TensorFlow file due to TF nuances
+ print(args.tf_checkpoint)
+ load_and_save_temporary_tensorflow_model(args.model_name, args.tf_checkpoint)
+
+ # Load weights
+ load_efficientnet(model, 'tmp/model.ckpt', model_name=args.model_name)
+ print('Loaded TF checkpoint weights')
+
+ # Save PyTorch file
+ torch.save(model.state_dict(), args.output_file)
+ print('Saved model to', args.output_file)
diff --git a/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/load_tf_weights_tf1.py b/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/load_tf_weights_tf1.py
new file mode 100644
index 0000000000000000000000000000000000000000..0722a68389ae1a0d0827ad8635fae744e9d2dfe3
--- /dev/null
+++ b/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/load_tf_weights_tf1.py
@@ -0,0 +1,172 @@
+import numpy as np
+import tensorflow as tf
+import torch
+
+def load_param(checkpoint_file, conversion_table, model_name):
+ """
+ Load parameters according to conversion_table.
+
+ Args:
+ checkpoint_file (string): pretrained checkpoint model file in tensorflow
+ conversion_table (dict): { pytorch tensor in a model : checkpoint variable name }
+ """
+ for pyt_param, tf_param_name in conversion_table.items():
+ tf_param_name = str(model_name) + '/' + tf_param_name
+ tf_param = tf.train.load_variable(checkpoint_file, tf_param_name)
+ if 'conv' in tf_param_name and 'kernel' in tf_param_name:
+ tf_param = np.transpose(tf_param, (3, 2, 0, 1))
+ if 'depthwise' in tf_param_name:
+ tf_param = np.transpose(tf_param, (1, 0, 2, 3))
+ elif tf_param_name.endswith('kernel'): # for weight(kernel), we should do transpose
+ tf_param = np.transpose(tf_param)
+ assert pyt_param.size() == tf_param.shape, \
+ 'Dim Mismatch: %s vs %s ; %s' % (tuple(pyt_param.size()), tf_param.shape, tf_param_name)
+ pyt_param.data = torch.from_numpy(tf_param)
+
+
+def load_efficientnet(model, checkpoint_file, model_name):
+ """
+ Load PyTorch EfficientNet from TensorFlow checkpoint file
+ """
+
+ # This will store the enire conversion table
+ conversion_table = {}
+ merge = lambda dict1, dict2: {**dict1, **dict2}
+
+ # All the weights not in the conv blocks
+ conversion_table_for_weights_outside_blocks = {
+ model._conv_stem.weight: 'stem/conv2d/kernel', # [3, 3, 3, 32]),
+ model._bn0.bias: 'stem/tpu_batch_normalization/beta', # [32]),
+ model._bn0.weight: 'stem/tpu_batch_normalization/gamma', # [32]),
+ model._bn0.running_mean: 'stem/tpu_batch_normalization/moving_mean', # [32]),
+ model._bn0.running_var: 'stem/tpu_batch_normalization/moving_variance', # [32]),
+ model._conv_head.weight: 'head/conv2d/kernel', # [1, 1, 320, 1280]),
+ model._bn1.bias: 'head/tpu_batch_normalization/beta', # [1280]),
+ model._bn1.weight: 'head/tpu_batch_normalization/gamma', # [1280]),
+ model._bn1.running_mean: 'head/tpu_batch_normalization/moving_mean', # [32]),
+ model._bn1.running_var: 'head/tpu_batch_normalization/moving_variance', # [32]),
+ model._fc.bias: 'head/dense/bias', # [1000]),
+ model._fc.weight: 'head/dense/kernel', # [1280, 1000]),
+ }
+ conversion_table = merge(conversion_table, conversion_table_for_weights_outside_blocks)
+
+ # The first conv block is special because it does not have _expand_conv
+ conversion_table_for_first_block = {
+ model._blocks[0]._project_conv.weight: 'blocks_0/conv2d/kernel', # 1, 1, 32, 16]),
+ model._blocks[0]._depthwise_conv.weight: 'blocks_0/depthwise_conv2d/depthwise_kernel', # [3, 3, 32, 1]),
+ model._blocks[0]._se_reduce.bias: 'blocks_0/se/conv2d/bias', # , [8]),
+ model._blocks[0]._se_reduce.weight: 'blocks_0/se/conv2d/kernel', # , [1, 1, 32, 8]),
+ model._blocks[0]._se_expand.bias: 'blocks_0/se/conv2d_1/bias', # , [32]),
+ model._blocks[0]._se_expand.weight: 'blocks_0/se/conv2d_1/kernel', # , [1, 1, 8, 32]),
+ model._blocks[0]._bn1.bias: 'blocks_0/tpu_batch_normalization/beta', # [32]),
+ model._blocks[0]._bn1.weight: 'blocks_0/tpu_batch_normalization/gamma', # [32]),
+ model._blocks[0]._bn1.running_mean: 'blocks_0/tpu_batch_normalization/moving_mean',
+ model._blocks[0]._bn1.running_var: 'blocks_0/tpu_batch_normalization/moving_variance',
+ model._blocks[0]._bn2.bias: 'blocks_0/tpu_batch_normalization_1/beta', # [16]),
+ model._blocks[0]._bn2.weight: 'blocks_0/tpu_batch_normalization_1/gamma', # [16]),
+ model._blocks[0]._bn2.running_mean: 'blocks_0/tpu_batch_normalization_1/moving_mean',
+ model._blocks[0]._bn2.running_var: 'blocks_0/tpu_batch_normalization_1/moving_variance',
+ }
+ conversion_table = merge(conversion_table, conversion_table_for_first_block)
+
+ # Conv blocks
+ for i in range(len(model._blocks)):
+
+ is_first_block = '_expand_conv.weight' not in [n for n, p in model._blocks[i].named_parameters()]
+
+ if is_first_block:
+ conversion_table_block = {
+ model._blocks[i]._project_conv.weight: 'blocks_' + str(i) + '/conv2d/kernel', # 1, 1, 32, 16]),
+ model._blocks[i]._depthwise_conv.weight: 'blocks_' + str(i) + '/depthwise_conv2d/depthwise_kernel',
+ # [3, 3, 32, 1]),
+ model._blocks[i]._se_reduce.bias: 'blocks_' + str(i) + '/se/conv2d/bias', # , [8]),
+ model._blocks[i]._se_reduce.weight: 'blocks_' + str(i) + '/se/conv2d/kernel', # , [1, 1, 32, 8]),
+ model._blocks[i]._se_expand.bias: 'blocks_' + str(i) + '/se/conv2d_1/bias', # , [32]),
+ model._blocks[i]._se_expand.weight: 'blocks_' + str(i) + '/se/conv2d_1/kernel', # , [1, 1, 8, 32]),
+ model._blocks[i]._bn1.bias: 'blocks_' + str(i) + '/tpu_batch_normalization/beta', # [32]),
+ model._blocks[i]._bn1.weight: 'blocks_' + str(i) + '/tpu_batch_normalization/gamma', # [32]),
+ model._blocks[i]._bn1.running_mean: 'blocks_' + str(i) + '/tpu_batch_normalization/moving_mean',
+ model._blocks[i]._bn1.running_var: 'blocks_' + str(i) + '/tpu_batch_normalization/moving_variance',
+ model._blocks[i]._bn2.bias: 'blocks_' + str(i) + '/tpu_batch_normalization_1/beta', # [16]),
+ model._blocks[i]._bn2.weight: 'blocks_' + str(i) + '/tpu_batch_normalization_1/gamma', # [16]),
+ model._blocks[i]._bn2.running_mean: 'blocks_' + str(i) + '/tpu_batch_normalization_1/moving_mean',
+ model._blocks[i]._bn2.running_var: 'blocks_' + str(i) + '/tpu_batch_normalization_1/moving_variance',
+ }
+
+ else:
+ conversion_table_block = {
+ model._blocks[i]._expand_conv.weight: 'blocks_' + str(i) + '/conv2d/kernel',
+ model._blocks[i]._project_conv.weight: 'blocks_' + str(i) + '/conv2d_1/kernel',
+ model._blocks[i]._depthwise_conv.weight: 'blocks_' + str(i) + '/depthwise_conv2d/depthwise_kernel',
+ model._blocks[i]._se_reduce.bias: 'blocks_' + str(i) + '/se/conv2d/bias',
+ model._blocks[i]._se_reduce.weight: 'blocks_' + str(i) + '/se/conv2d/kernel',
+ model._blocks[i]._se_expand.bias: 'blocks_' + str(i) + '/se/conv2d_1/bias',
+ model._blocks[i]._se_expand.weight: 'blocks_' + str(i) + '/se/conv2d_1/kernel',
+ model._blocks[i]._bn0.bias: 'blocks_' + str(i) + '/tpu_batch_normalization/beta',
+ model._blocks[i]._bn0.weight: 'blocks_' + str(i) + '/tpu_batch_normalization/gamma',
+ model._blocks[i]._bn0.running_mean: 'blocks_' + str(i) + '/tpu_batch_normalization/moving_mean',
+ model._blocks[i]._bn0.running_var: 'blocks_' + str(i) + '/tpu_batch_normalization/moving_variance',
+ model._blocks[i]._bn1.bias: 'blocks_' + str(i) + '/tpu_batch_normalization_1/beta',
+ model._blocks[i]._bn1.weight: 'blocks_' + str(i) + '/tpu_batch_normalization_1/gamma',
+ model._blocks[i]._bn1.running_mean: 'blocks_' + str(i) + '/tpu_batch_normalization_1/moving_mean',
+ model._blocks[i]._bn1.running_var: 'blocks_' + str(i) + '/tpu_batch_normalization_1/moving_variance',
+ model._blocks[i]._bn2.bias: 'blocks_' + str(i) + '/tpu_batch_normalization_2/beta',
+ model._blocks[i]._bn2.weight: 'blocks_' + str(i) + '/tpu_batch_normalization_2/gamma',
+ model._blocks[i]._bn2.running_mean: 'blocks_' + str(i) + '/tpu_batch_normalization_2/moving_mean',
+ model._blocks[i]._bn2.running_var: 'blocks_' + str(i) + '/tpu_batch_normalization_2/moving_variance',
+ }
+
+ conversion_table = merge(conversion_table, conversion_table_block)
+
+ # Load TensorFlow parameters into PyTorch model
+ load_param(checkpoint_file, conversion_table, model_name)
+ return conversion_table
+
+
+def load_and_save_temporary_tensorflow_model(model_name, model_ckpt, example_img= '../../example/img.jpg'):
+ """ Loads and saves a TensorFlow model. """
+ image_files = [example_img]
+ eval_ckpt_driver = eval_ckpt_main.EvalCkptDriver(model_name)
+ with tf.Graph().as_default(), tf.Session() as sess:
+ images, labels = eval_ckpt_driver.build_dataset(image_files, [0] * len(image_files), False)
+ probs = eval_ckpt_driver.build_model(images, is_training=False)
+ sess.run(tf.global_variables_initializer())
+ print(model_ckpt)
+ eval_ckpt_driver.restore_model(sess, model_ckpt)
+ tf.train.Saver().save(sess, 'tmp/model.ckpt')
+
+
+if __name__ == '__main__':
+
+ import sys
+ import argparse
+
+ sys.path.append('original_tf')
+ import eval_ckpt_main
+
+ from efficientnet_pytorch import EfficientNet
+
+ parser = argparse.ArgumentParser(
+ description='Convert TF model to PyTorch model and save for easier future loading')
+ parser.add_argument('--model_name', type=str, default='efficientnet-b0',
+ help='efficientnet-b{N}, where N is an integer 0 <= N <= 8')
+ parser.add_argument('--tf_checkpoint', type=str, default='pretrained_tensorflow/efficientnet-b0/',
+ help='checkpoint file path')
+ parser.add_argument('--output_file', type=str, default='pretrained_pytorch/efficientnet-b0.pth',
+ help='output PyTorch model file name')
+ args = parser.parse_args()
+
+ # Build model
+ model = EfficientNet.from_name(args.model_name)
+
+ # Load and save temporary TensorFlow file due to TF nuances
+ print(args.tf_checkpoint)
+ load_and_save_temporary_tensorflow_model(args.model_name, args.tf_checkpoint)
+
+ # Load weights
+ load_efficientnet(model, 'tmp/model.ckpt', model_name=args.model_name)
+ print('Loaded TF checkpoint weights')
+
+ # Save PyTorch file
+ torch.save(model.state_dict(), args.output_file)
+ print('Saved model to', args.output_file)
diff --git a/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/original_tf/__init__.py b/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/original_tf/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/original_tf/efficientnet_builder.py b/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/original_tf/efficientnet_builder.py
new file mode 100644
index 0000000000000000000000000000000000000000..ff384b1126b8efc36e74c87e065976fedad21394
--- /dev/null
+++ b/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/original_tf/efficientnet_builder.py
@@ -0,0 +1,329 @@
+# Copyright 2019 The TensorFlow Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ==============================================================================
+"""Model Builder for EfficientNet."""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import functools
+import os
+import re
+from absl import logging
+import numpy as np
+import six
+import tensorflow.compat.v1 as tf
+
+import efficientnet_model
+import utils
+MEAN_RGB = [0.485 * 255, 0.456 * 255, 0.406 * 255]
+STDDEV_RGB = [0.229 * 255, 0.224 * 255, 0.225 * 255]
+
+
+def efficientnet_params(model_name):
+ """Get efficientnet params based on model name."""
+ params_dict = {
+ # (width_coefficient, depth_coefficient, resolution, dropout_rate)
+ 'efficientnet-b0': (1.0, 1.0, 224, 0.2),
+ 'efficientnet-b1': (1.0, 1.1, 240, 0.2),
+ 'efficientnet-b2': (1.1, 1.2, 260, 0.3),
+ 'efficientnet-b3': (1.2, 1.4, 300, 0.3),
+ 'efficientnet-b4': (1.4, 1.8, 380, 0.4),
+ 'efficientnet-b5': (1.6, 2.2, 456, 0.4),
+ 'efficientnet-b6': (1.8, 2.6, 528, 0.5),
+ 'efficientnet-b7': (2.0, 3.1, 600, 0.5),
+ 'efficientnet-b8': (2.2, 3.6, 672, 0.5),
+ 'efficientnet-l2': (4.3, 5.3, 800, 0.5),
+ }
+ return params_dict[model_name]
+
+
+class BlockDecoder(object):
+ """Block Decoder for readability."""
+
+ def _decode_block_string(self, block_string):
+ """Gets a block through a string notation of arguments."""
+ if six.PY2:
+ assert isinstance(block_string, (str, unicode))
+ else:
+ assert isinstance(block_string, str)
+ ops = block_string.split('_')
+ options = {}
+ for op in ops:
+ splits = re.split(r'(\d.*)', op)
+ if len(splits) >= 2:
+ key, value = splits[:2]
+ options[key] = value
+
+ if 's' not in options or len(options['s']) != 2:
+ raise ValueError('Strides options should be a pair of integers.')
+
+ return efficientnet_model.BlockArgs(
+ kernel_size=int(options['k']),
+ num_repeat=int(options['r']),
+ input_filters=int(options['i']),
+ output_filters=int(options['o']),
+ expand_ratio=int(options['e']),
+ id_skip=('noskip' not in block_string),
+ se_ratio=float(options['se']) if 'se' in options else None,
+ strides=[int(options['s'][0]),
+ int(options['s'][1])],
+ conv_type=int(options['c']) if 'c' in options else 0,
+ fused_conv=int(options['f']) if 'f' in options else 0,
+ super_pixel=int(options['p']) if 'p' in options else 0,
+ condconv=('cc' in block_string))
+
+ def _encode_block_string(self, block):
+ """Encodes a block to a string."""
+ args = [
+ 'r%d' % block.num_repeat,
+ 'k%d' % block.kernel_size,
+ 's%d%d' % (block.strides[0], block.strides[1]),
+ 'e%s' % block.expand_ratio,
+ 'i%d' % block.input_filters,
+ 'o%d' % block.output_filters,
+ 'c%d' % block.conv_type,
+ 'f%d' % block.fused_conv,
+ 'p%d' % block.super_pixel,
+ ]
+ if block.se_ratio > 0 and block.se_ratio <= 1:
+ args.append('se%s' % block.se_ratio)
+ if block.id_skip is False: # pylint: disable=g-bool-id-comparison
+ args.append('noskip')
+ if block.condconv:
+ args.append('cc')
+ return '_'.join(args)
+
+ def decode(self, string_list):
+ """Decodes a list of string notations to specify blocks inside the network.
+
+ Args:
+ string_list: a list of strings, each string is a notation of block.
+
+ Returns:
+ A list of namedtuples to represent blocks arguments.
+ """
+ assert isinstance(string_list, list)
+ blocks_args = []
+ for block_string in string_list:
+ blocks_args.append(self._decode_block_string(block_string))
+ return blocks_args
+
+ def encode(self, blocks_args):
+ """Encodes a list of Blocks to a list of strings.
+
+ Args:
+ blocks_args: A list of namedtuples to represent blocks arguments.
+ Returns:
+ a list of strings, each string is a notation of block.
+ """
+ block_strings = []
+ for block in blocks_args:
+ block_strings.append(self._encode_block_string(block))
+ return block_strings
+
+
+def swish(features, use_native=True, use_hard=False):
+ """Computes the Swish activation function.
+
+ We provide three alternnatives:
+ - Native tf.nn.swish, use less memory during training than composable swish.
+ - Quantization friendly hard swish.
+ - A composable swish, equivalant to tf.nn.swish, but more general for
+ finetuning and TF-Hub.
+
+ Args:
+ features: A `Tensor` representing preactivation values.
+ use_native: Whether to use the native swish from tf.nn that uses a custom
+ gradient to reduce memory usage, or to use customized swish that uses
+ default TensorFlow gradient computation.
+ use_hard: Whether to use quantization-friendly hard swish.
+
+ Returns:
+ The activation value.
+ """
+ if use_native and use_hard:
+ raise ValueError('Cannot specify both use_native and use_hard.')
+
+ if use_native:
+ return tf.nn.swish(features)
+
+ if use_hard:
+ return features * tf.nn.relu6(features + np.float32(3)) * (1. / 6.)
+
+ features = tf.convert_to_tensor(features, name='features')
+ return features * tf.nn.sigmoid(features)
+
+
+_DEFAULT_BLOCKS_ARGS = [
+ 'r1_k3_s11_e1_i32_o16_se0.25', 'r2_k3_s22_e6_i16_o24_se0.25',
+ 'r2_k5_s22_e6_i24_o40_se0.25', 'r3_k3_s22_e6_i40_o80_se0.25',
+ 'r3_k5_s11_e6_i80_o112_se0.25', 'r4_k5_s22_e6_i112_o192_se0.25',
+ 'r1_k3_s11_e6_i192_o320_se0.25',
+]
+
+
+def efficientnet(width_coefficient=None,
+ depth_coefficient=None,
+ dropout_rate=0.2,
+ survival_prob=0.8):
+ """Creates a efficientnet model."""
+ global_params = efficientnet_model.GlobalParams(
+ blocks_args=_DEFAULT_BLOCKS_ARGS,
+ batch_norm_momentum=0.99,
+ batch_norm_epsilon=1e-3,
+ dropout_rate=dropout_rate,
+ survival_prob=survival_prob,
+ data_format='channels_last',
+ num_classes=1000,
+ width_coefficient=width_coefficient,
+ depth_coefficient=depth_coefficient,
+ depth_divisor=8,
+ min_depth=None,
+ relu_fn=tf.nn.swish,
+ # The default is TPU-specific batch norm.
+ # The alternative is tf.layers.BatchNormalization.
+ batch_norm=utils.TpuBatchNormalization, # TPU-specific requirement.
+ use_se=True,
+ clip_projection_output=False)
+ return global_params
+
+
+def get_model_params(model_name, override_params):
+ """Get the block args and global params for a given model."""
+ if model_name.startswith('efficientnet'):
+ width_coefficient, depth_coefficient, _, dropout_rate = (
+ efficientnet_params(model_name))
+ global_params = efficientnet(
+ width_coefficient, depth_coefficient, dropout_rate)
+ else:
+ raise NotImplementedError('model name is not pre-defined: %s' % model_name)
+
+ if override_params:
+ # ValueError will be raised here if override_params has fields not included
+ # in global_params.
+ global_params = global_params._replace(**override_params)
+
+ decoder = BlockDecoder()
+ blocks_args = decoder.decode(global_params.blocks_args)
+
+ logging.info('global_params= %s', global_params)
+ return blocks_args, global_params
+
+
+def build_model(images,
+ model_name,
+ training,
+ override_params=None,
+ model_dir=None,
+ fine_tuning=False,
+ features_only=False,
+ pooled_features_only=False):
+ """A helper functiion to creates a model and returns predicted logits.
+
+ Args:
+ images: input images tensor.
+ model_name: string, the predefined model name.
+ training: boolean, whether the model is constructed for training.
+ override_params: A dictionary of params for overriding. Fields must exist in
+ efficientnet_model.GlobalParams.
+ model_dir: string, optional model dir for saving configs.
+ fine_tuning: boolean, whether the model is used for finetuning.
+ features_only: build the base feature network only (excluding final
+ 1x1 conv layer, global pooling, dropout and fc head).
+ pooled_features_only: build the base network for features extraction (after
+ 1x1 conv layer and global pooling, but before dropout and fc head).
+
+ Returns:
+ logits: the logits tensor of classes.
+ endpoints: the endpoints for each layer.
+
+ Raises:
+ When model_name specified an undefined model, raises NotImplementedError.
+ When override_params has invalid fields, raises ValueError.
+ """
+ assert isinstance(images, tf.Tensor)
+ assert not (features_only and pooled_features_only)
+
+ # For backward compatibility.
+ if override_params and override_params.get('drop_connect_rate', None):
+ override_params['survival_prob'] = 1 - override_params['drop_connect_rate']
+
+ if not training or fine_tuning:
+ if not override_params:
+ override_params = {}
+ override_params['batch_norm'] = utils.BatchNormalization
+ if fine_tuning:
+ override_params['relu_fn'] = functools.partial(swish, use_native=False)
+ blocks_args, global_params = get_model_params(model_name, override_params)
+
+ if model_dir:
+ param_file = os.path.join(model_dir, 'model_params.txt')
+ if not tf.gfile.Exists(param_file):
+ if not tf.gfile.Exists(model_dir):
+ tf.gfile.MakeDirs(model_dir)
+ with tf.gfile.GFile(param_file, 'w') as f:
+ logging.info('writing to %s', param_file)
+ f.write('model_name= %s\n\n' % model_name)
+ f.write('global_params= %s\n\n' % str(global_params))
+ f.write('blocks_args= %s\n\n' % str(blocks_args))
+
+ with tf.variable_scope(model_name):
+ model = efficientnet_model.Model(blocks_args, global_params)
+ outputs = model(
+ images,
+ training=training,
+ features_only=features_only,
+ pooled_features_only=pooled_features_only)
+ if features_only:
+ outputs = tf.identity(outputs, 'features')
+ elif pooled_features_only:
+ outputs = tf.identity(outputs, 'pooled_features')
+ else:
+ outputs = tf.identity(outputs, 'logits')
+ return outputs, model.endpoints
+
+
+def build_model_base(images, model_name, training, override_params=None):
+ """A helper functiion to create a base model and return global_pool.
+
+ Args:
+ images: input images tensor.
+ model_name: string, the predefined model name.
+ training: boolean, whether the model is constructed for training.
+ override_params: A dictionary of params for overriding. Fields must exist in
+ efficientnet_model.GlobalParams.
+
+ Returns:
+ features: global pool features.
+ endpoints: the endpoints for each layer.
+
+ Raises:
+ When model_name specified an undefined model, raises NotImplementedError.
+ When override_params has invalid fields, raises ValueError.
+ """
+ assert isinstance(images, tf.Tensor)
+ # For backward compatibility.
+ if override_params and override_params.get('drop_connect_rate', None):
+ override_params['survival_prob'] = 1 - override_params['drop_connect_rate']
+
+ blocks_args, global_params = get_model_params(model_name, override_params)
+
+ with tf.variable_scope(model_name):
+ model = efficientnet_model.Model(blocks_args, global_params)
+ features = model(images, training=training, features_only=True)
+
+ features = tf.identity(features, 'features')
+ return features, model.endpoints
diff --git a/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/original_tf/efficientnet_model.py b/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/original_tf/efficientnet_model.py
new file mode 100644
index 0000000000000000000000000000000000000000..6bc827e1e0de4ced8192f8e1920ff44afdbb0e93
--- /dev/null
+++ b/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/original_tf/efficientnet_model.py
@@ -0,0 +1,713 @@
+# Copyright 2019 The TensorFlow Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ==============================================================================
+"""Contains definitions for EfficientNet model.
+
+[1] Mingxing Tan, Quoc V. Le
+ EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks.
+ ICML'19, https://arxiv.org/abs/1905.11946
+"""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import collections
+import functools
+import math
+
+from absl import logging
+import numpy as np
+import six
+from six.moves import xrange
+import tensorflow.compat.v1 as tf
+
+import utils
+# from condconv import condconv_layers
+
+GlobalParams = collections.namedtuple('GlobalParams', [
+ 'batch_norm_momentum', 'batch_norm_epsilon', 'dropout_rate', 'data_format',
+ 'num_classes', 'width_coefficient', 'depth_coefficient', 'depth_divisor',
+ 'min_depth', 'survival_prob', 'relu_fn', 'batch_norm', 'use_se',
+ 'local_pooling', 'condconv_num_experts', 'clip_projection_output',
+ 'blocks_args'
+])
+GlobalParams.__new__.__defaults__ = (None,) * len(GlobalParams._fields)
+
+BlockArgs = collections.namedtuple('BlockArgs', [
+ 'kernel_size', 'num_repeat', 'input_filters', 'output_filters',
+ 'expand_ratio', 'id_skip', 'strides', 'se_ratio', 'conv_type', 'fused_conv',
+ 'super_pixel', 'condconv'
+])
+# defaults will be a public argument for namedtuple in Python 3.7
+# https://docs.python.org/3/library/collections.html#collections.namedtuple
+BlockArgs.__new__.__defaults__ = (None,) * len(BlockArgs._fields)
+
+
+def conv_kernel_initializer(shape, dtype=None, partition_info=None):
+ """Initialization for convolutional kernels.
+
+ The main difference with tf.variance_scaling_initializer is that
+ tf.variance_scaling_initializer uses a truncated normal with an uncorrected
+ standard deviation, whereas here we use a normal distribution. Similarly,
+ tf.initializers.variance_scaling uses a truncated normal with
+ a corrected standard deviation.
+
+ Args:
+ shape: shape of variable
+ dtype: dtype of variable
+ partition_info: unused
+
+ Returns:
+ an initialization for the variable
+ """
+ del partition_info
+ kernel_height, kernel_width, _, out_filters = shape
+ fan_out = int(kernel_height * kernel_width * out_filters)
+ return tf.random_normal(
+ shape, mean=0.0, stddev=np.sqrt(2.0 / fan_out), dtype=dtype)
+
+
+def dense_kernel_initializer(shape, dtype=None, partition_info=None):
+ """Initialization for dense kernels.
+
+ This initialization is equal to
+ tf.variance_scaling_initializer(scale=1.0/3.0, mode='fan_out',
+ distribution='uniform').
+ It is written out explicitly here for clarity.
+
+ Args:
+ shape: shape of variable
+ dtype: dtype of variable
+ partition_info: unused
+
+ Returns:
+ an initialization for the variable
+ """
+ del partition_info
+ init_range = 1.0 / np.sqrt(shape[1])
+ return tf.random_uniform(shape, -init_range, init_range, dtype=dtype)
+
+
+def superpixel_kernel_initializer(shape, dtype='float32', partition_info=None):
+ """Initializes superpixel kernels.
+
+ This is inspired by space-to-depth transformation that is mathematically
+ equivalent before and after the transformation. But we do the space-to-depth
+ via a convolution. Moreover, we make the layer trainable instead of direct
+ transform, we can initialization it this way so that the model can learn not
+ to do anything but keep it mathematically equivalent, when improving
+ performance.
+
+
+ Args:
+ shape: shape of variable
+ dtype: dtype of variable
+ partition_info: unused
+
+ Returns:
+ an initialization for the variable
+ """
+ del partition_info
+ # use input depth to make superpixel kernel.
+ depth = shape[-2]
+ filters = np.zeros([2, 2, depth, 4 * depth], dtype=dtype)
+ i = np.arange(2)
+ j = np.arange(2)
+ k = np.arange(depth)
+ mesh = np.array(np.meshgrid(i, j, k)).T.reshape(-1, 3).T
+ filters[
+ mesh[0],
+ mesh[1],
+ mesh[2],
+ 4 * mesh[2] + 2 * mesh[0] + mesh[1]] = 1
+ return filters
+
+
+def round_filters(filters, global_params):
+ """Round number of filters based on depth multiplier."""
+ orig_f = filters
+ multiplier = global_params.width_coefficient
+ divisor = global_params.depth_divisor
+ min_depth = global_params.min_depth
+ if not multiplier:
+ return filters
+
+ filters *= multiplier
+ min_depth = min_depth or divisor
+ new_filters = max(min_depth, int(filters + divisor / 2) // divisor * divisor)
+ # Make sure that round down does not go down by more than 10%.
+ if new_filters < 0.9 * filters:
+ new_filters += divisor
+ logging.info('round_filter input=%s output=%s', orig_f, new_filters)
+ return int(new_filters)
+
+
+def round_repeats(repeats, global_params):
+ """Round number of filters based on depth multiplier."""
+ multiplier = global_params.depth_coefficient
+ if not multiplier:
+ return repeats
+ return int(math.ceil(multiplier * repeats))
+
+
+class MBConvBlock(tf.keras.layers.Layer):
+ """A class of MBConv: Mobile Inverted Residual Bottleneck.
+
+ Attributes:
+ endpoints: dict. A list of internal tensors.
+ """
+
+ def __init__(self, block_args, global_params):
+ """Initializes a MBConv block.
+
+ Args:
+ block_args: BlockArgs, arguments to create a Block.
+ global_params: GlobalParams, a set of global parameters.
+ """
+ super(MBConvBlock, self).__init__()
+ self._block_args = block_args
+ self._batch_norm_momentum = global_params.batch_norm_momentum
+ self._batch_norm_epsilon = global_params.batch_norm_epsilon
+ self._batch_norm = global_params.batch_norm
+ self._condconv_num_experts = global_params.condconv_num_experts
+ self._data_format = global_params.data_format
+ if self._data_format == 'channels_first':
+ self._channel_axis = 1
+ self._spatial_dims = [2, 3]
+ else:
+ self._channel_axis = -1
+ self._spatial_dims = [1, 2]
+
+ self._relu_fn = global_params.relu_fn or tf.nn.swish
+ self._has_se = (
+ global_params.use_se and self._block_args.se_ratio is not None and
+ 0 < self._block_args.se_ratio <= 1)
+
+ self._clip_projection_output = global_params.clip_projection_output
+
+ self.endpoints = None
+
+ self.conv_cls = tf.layers.Conv2D
+ self.depthwise_conv_cls = utils.DepthwiseConv2D
+ if self._block_args.condconv:
+ self.conv_cls = functools.partial(
+ condconv_layers.CondConv2D, num_experts=self._condconv_num_experts)
+ self.depthwise_conv_cls = functools.partial(
+ condconv_layers.DepthwiseCondConv2D,
+ num_experts=self._condconv_num_experts)
+
+ # Builds the block accordings to arguments.
+ self._build()
+
+ def block_args(self):
+ return self._block_args
+
+ def _build(self):
+ """Builds block according to the arguments."""
+ if self._block_args.super_pixel == 1:
+ self._superpixel = tf.layers.Conv2D(
+ self._block_args.input_filters,
+ kernel_size=[2, 2],
+ strides=[2, 2],
+ kernel_initializer=conv_kernel_initializer,
+ padding='same',
+ data_format=self._data_format,
+ use_bias=False)
+ self._bnsp = self._batch_norm(
+ axis=self._channel_axis,
+ momentum=self._batch_norm_momentum,
+ epsilon=self._batch_norm_epsilon)
+
+ if self._block_args.condconv:
+ # Add the example-dependent routing function
+ self._avg_pooling = tf.keras.layers.GlobalAveragePooling2D(
+ data_format=self._data_format)
+ self._routing_fn = tf.layers.Dense(
+ self._condconv_num_experts, activation=tf.nn.sigmoid)
+
+ filters = self._block_args.input_filters * self._block_args.expand_ratio
+ kernel_size = self._block_args.kernel_size
+
+ # Fused expansion phase. Called if using fused convolutions.
+ self._fused_conv = self.conv_cls(
+ filters=filters,
+ kernel_size=[kernel_size, kernel_size],
+ strides=self._block_args.strides,
+ kernel_initializer=conv_kernel_initializer,
+ padding='same',
+ data_format=self._data_format,
+ use_bias=False)
+
+ # Expansion phase. Called if not using fused convolutions and expansion
+ # phase is necessary.
+ self._expand_conv = self.conv_cls(
+ filters=filters,
+ kernel_size=[1, 1],
+ strides=[1, 1],
+ kernel_initializer=conv_kernel_initializer,
+ padding='same',
+ data_format=self._data_format,
+ use_bias=False)
+ self._bn0 = self._batch_norm(
+ axis=self._channel_axis,
+ momentum=self._batch_norm_momentum,
+ epsilon=self._batch_norm_epsilon)
+
+ # Depth-wise convolution phase. Called if not using fused convolutions.
+ self._depthwise_conv = self.depthwise_conv_cls(
+ kernel_size=[kernel_size, kernel_size],
+ strides=self._block_args.strides,
+ depthwise_initializer=conv_kernel_initializer,
+ padding='same',
+ data_format=self._data_format,
+ use_bias=False)
+
+ self._bn1 = self._batch_norm(
+ axis=self._channel_axis,
+ momentum=self._batch_norm_momentum,
+ epsilon=self._batch_norm_epsilon)
+
+ if self._has_se:
+ num_reduced_filters = max(
+ 1, int(self._block_args.input_filters * self._block_args.se_ratio))
+ # Squeeze and Excitation layer.
+ self._se_reduce = tf.layers.Conv2D(
+ num_reduced_filters,
+ kernel_size=[1, 1],
+ strides=[1, 1],
+ kernel_initializer=conv_kernel_initializer,
+ padding='same',
+ data_format=self._data_format,
+ use_bias=True)
+ self._se_expand = tf.layers.Conv2D(
+ filters,
+ kernel_size=[1, 1],
+ strides=[1, 1],
+ kernel_initializer=conv_kernel_initializer,
+ padding='same',
+ data_format=self._data_format,
+ use_bias=True)
+
+ # Output phase.
+ filters = self._block_args.output_filters
+ self._project_conv = self.conv_cls(
+ filters=filters,
+ kernel_size=[1, 1],
+ strides=[1, 1],
+ kernel_initializer=conv_kernel_initializer,
+ padding='same',
+ data_format=self._data_format,
+ use_bias=False)
+ self._bn2 = self._batch_norm(
+ axis=self._channel_axis,
+ momentum=self._batch_norm_momentum,
+ epsilon=self._batch_norm_epsilon)
+
+ def _call_se(self, input_tensor):
+ """Call Squeeze and Excitation layer.
+
+ Args:
+ input_tensor: Tensor, a single input tensor for Squeeze/Excitation layer.
+
+ Returns:
+ A output tensor, which should have the same shape as input.
+ """
+ se_tensor = tf.reduce_mean(input_tensor, self._spatial_dims, keepdims=True)
+ se_tensor = self._se_expand(self._relu_fn(self._se_reduce(se_tensor)))
+ logging.info('Built Squeeze and Excitation with tensor shape: %s',
+ (se_tensor.shape))
+ return tf.sigmoid(se_tensor) * input_tensor
+
+ def call(self, inputs, training=True, survival_prob=None):
+ """Implementation of call().
+
+ Args:
+ inputs: the inputs tensor.
+ training: boolean, whether the model is constructed for training.
+ survival_prob: float, between 0 to 1, drop connect rate.
+
+ Returns:
+ A output tensor.
+ """
+ logging.info('Block input: %s shape: %s', inputs.name, inputs.shape)
+ logging.info('Block input depth: %s output depth: %s',
+ self._block_args.input_filters,
+ self._block_args.output_filters)
+
+ x = inputs
+
+ fused_conv_fn = self._fused_conv
+ expand_conv_fn = self._expand_conv
+ depthwise_conv_fn = self._depthwise_conv
+ project_conv_fn = self._project_conv
+
+ if self._block_args.condconv:
+ pooled_inputs = self._avg_pooling(inputs)
+ routing_weights = self._routing_fn(pooled_inputs)
+ # Capture routing weights as additional input to CondConv layers
+ fused_conv_fn = functools.partial(
+ self._fused_conv, routing_weights=routing_weights)
+ expand_conv_fn = functools.partial(
+ self._expand_conv, routing_weights=routing_weights)
+ depthwise_conv_fn = functools.partial(
+ self._depthwise_conv, routing_weights=routing_weights)
+ project_conv_fn = functools.partial(
+ self._project_conv, routing_weights=routing_weights)
+
+ # creates conv 2x2 kernel
+ if self._block_args.super_pixel == 1:
+ with tf.variable_scope('super_pixel'):
+ x = self._relu_fn(
+ self._bnsp(self._superpixel(x), training=training))
+ logging.info(
+ 'Block start with SuperPixel: %s shape: %s', x.name, x.shape)
+
+ if self._block_args.fused_conv:
+ # If use fused mbconv, skip expansion and use regular conv.
+ x = self._relu_fn(self._bn1(fused_conv_fn(x), training=training))
+ logging.info('Conv2D: %s shape: %s', x.name, x.shape)
+ else:
+ # Otherwise, first apply expansion and then apply depthwise conv.
+ if self._block_args.expand_ratio != 1:
+ x = self._relu_fn(self._bn0(expand_conv_fn(x), training=training))
+ logging.info('Expand: %s shape: %s', x.name, x.shape)
+
+ x = self._relu_fn(self._bn1(depthwise_conv_fn(x), training=training))
+ logging.info('DWConv: %s shape: %s', x.name, x.shape)
+
+ if self._has_se:
+ with tf.variable_scope('se'):
+ x = self._call_se(x)
+
+ self.endpoints = {'expansion_output': x}
+
+ x = self._bn2(project_conv_fn(x), training=training)
+ # Add identity so that quantization-aware training can insert quantization
+ # ops correctly.
+ x = tf.identity(x)
+ if self._clip_projection_output:
+ x = tf.clip_by_value(x, -6, 6)
+ if self._block_args.id_skip:
+ if all(
+ s == 1 for s in self._block_args.strides
+ ) and self._block_args.input_filters == self._block_args.output_filters:
+ # Apply only if skip connection presents.
+ if survival_prob:
+ x = utils.drop_connect(x, training, survival_prob)
+ x = tf.add(x, inputs)
+ logging.info('Project: %s shape: %s', x.name, x.shape)
+ return x
+
+
+class MBConvBlockWithoutDepthwise(MBConvBlock):
+ """MBConv-like block without depthwise convolution and squeeze-and-excite."""
+
+ def _build(self):
+ """Builds block according to the arguments."""
+ filters = self._block_args.input_filters * self._block_args.expand_ratio
+ if self._block_args.expand_ratio != 1:
+ # Expansion phase:
+ self._expand_conv = tf.layers.Conv2D(
+ filters,
+ kernel_size=[3, 3],
+ strides=[1, 1],
+ kernel_initializer=conv_kernel_initializer,
+ padding='same',
+ use_bias=False)
+ self._bn0 = self._batch_norm(
+ axis=self._channel_axis,
+ momentum=self._batch_norm_momentum,
+ epsilon=self._batch_norm_epsilon)
+
+ # Output phase:
+ filters = self._block_args.output_filters
+ self._project_conv = tf.layers.Conv2D(
+ filters,
+ kernel_size=[1, 1],
+ strides=self._block_args.strides,
+ kernel_initializer=conv_kernel_initializer,
+ padding='same',
+ use_bias=False)
+ self._bn1 = self._batch_norm(
+ axis=self._channel_axis,
+ momentum=self._batch_norm_momentum,
+ epsilon=self._batch_norm_epsilon)
+
+ def call(self, inputs, training=True, survival_prob=None):
+ """Implementation of call().
+
+ Args:
+ inputs: the inputs tensor.
+ training: boolean, whether the model is constructed for training.
+ survival_prob: float, between 0 to 1, drop connect rate.
+
+ Returns:
+ A output tensor.
+ """
+ logging.info('Block input: %s shape: %s', inputs.name, inputs.shape)
+ if self._block_args.expand_ratio != 1:
+ x = self._relu_fn(self._bn0(self._expand_conv(inputs), training=training))
+ else:
+ x = inputs
+ logging.info('Expand: %s shape: %s', x.name, x.shape)
+
+ self.endpoints = {'expansion_output': x}
+
+ x = self._bn1(self._project_conv(x), training=training)
+ # Add identity so that quantization-aware training can insert quantization
+ # ops correctly.
+ x = tf.identity(x)
+ if self._clip_projection_output:
+ x = tf.clip_by_value(x, -6, 6)
+
+ if self._block_args.id_skip:
+ if all(
+ s == 1 for s in self._block_args.strides
+ ) and self._block_args.input_filters == self._block_args.output_filters:
+ # Apply only if skip connection presents.
+ if survival_prob:
+ x = utils.drop_connect(x, training, survival_prob)
+ x = tf.add(x, inputs)
+ logging.info('Project: %s shape: %s', x.name, x.shape)
+ return x
+
+
+class Model(tf.keras.Model):
+ """A class implements tf.keras.Model for MNAS-like model.
+
+ Reference: https://arxiv.org/abs/1807.11626
+ """
+
+ def __init__(self, blocks_args=None, global_params=None):
+ """Initializes an `Model` instance.
+
+ Args:
+ blocks_args: A list of BlockArgs to construct block modules.
+ global_params: GlobalParams, a set of global parameters.
+
+ Raises:
+ ValueError: when blocks_args is not specified as a list.
+ """
+ super(Model, self).__init__()
+ if not isinstance(blocks_args, list):
+ raise ValueError('blocks_args should be a list.')
+ self._global_params = global_params
+ self._blocks_args = blocks_args
+ self._relu_fn = global_params.relu_fn or tf.nn.swish
+ self._batch_norm = global_params.batch_norm
+
+ self.endpoints = None
+
+ self._build()
+
+ def _get_conv_block(self, conv_type):
+ conv_block_map = {0: MBConvBlock, 1: MBConvBlockWithoutDepthwise}
+ return conv_block_map[conv_type]
+
+ def _build(self):
+ """Builds a model."""
+ self._blocks = []
+ batch_norm_momentum = self._global_params.batch_norm_momentum
+ batch_norm_epsilon = self._global_params.batch_norm_epsilon
+ if self._global_params.data_format == 'channels_first':
+ channel_axis = 1
+ self._spatial_dims = [2, 3]
+ else:
+ channel_axis = -1
+ self._spatial_dims = [1, 2]
+
+ # Stem part.
+ self._conv_stem = tf.layers.Conv2D(
+ filters=round_filters(32, self._global_params),
+ kernel_size=[3, 3],
+ strides=[2, 2],
+ kernel_initializer=conv_kernel_initializer,
+ padding='same',
+ data_format=self._global_params.data_format,
+ use_bias=False)
+ self._bn0 = self._batch_norm(
+ axis=channel_axis,
+ momentum=batch_norm_momentum,
+ epsilon=batch_norm_epsilon)
+
+ # Builds blocks.
+ for block_args in self._blocks_args:
+ assert block_args.num_repeat > 0
+ assert block_args.super_pixel in [0, 1, 2]
+ # Update block input and output filters based on depth multiplier.
+ input_filters = round_filters(block_args.input_filters,
+ self._global_params)
+ output_filters = round_filters(block_args.output_filters,
+ self._global_params)
+ kernel_size = block_args.kernel_size
+ block_args = block_args._replace(
+ input_filters=input_filters,
+ output_filters=output_filters,
+ num_repeat=round_repeats(block_args.num_repeat, self._global_params))
+
+ # The first block needs to take care of stride and filter size increase.
+ conv_block = self._get_conv_block(block_args.conv_type)
+ if not block_args.super_pixel: # no super_pixel at all
+ self._blocks.append(conv_block(block_args, self._global_params))
+ else:
+ # if superpixel, adjust filters, kernels, and strides.
+ depth_factor = int(4 / block_args.strides[0] / block_args.strides[1])
+ block_args = block_args._replace(
+ input_filters=block_args.input_filters * depth_factor,
+ output_filters=block_args.output_filters * depth_factor,
+ kernel_size=((block_args.kernel_size + 1) // 2 if depth_factor > 1
+ else block_args.kernel_size))
+ # if the first block has stride-2 and super_pixel trandformation
+ if (block_args.strides[0] == 2 and block_args.strides[1] == 2):
+ block_args = block_args._replace(strides=[1, 1])
+ self._blocks.append(conv_block(block_args, self._global_params))
+ block_args = block_args._replace( # sp stops at stride-2
+ super_pixel=0,
+ input_filters=input_filters,
+ output_filters=output_filters,
+ kernel_size=kernel_size)
+ elif block_args.super_pixel == 1:
+ self._blocks.append(conv_block(block_args, self._global_params))
+ block_args = block_args._replace(super_pixel=2)
+ else:
+ self._blocks.append(conv_block(block_args, self._global_params))
+ if block_args.num_repeat > 1: # rest of blocks with the same block_arg
+ # pylint: disable=protected-access
+ block_args = block_args._replace(
+ input_filters=block_args.output_filters, strides=[1, 1])
+ # pylint: enable=protected-access
+ for _ in xrange(block_args.num_repeat - 1):
+ self._blocks.append(conv_block(block_args, self._global_params))
+
+ # Head part.
+ self._conv_head = tf.layers.Conv2D(
+ filters=round_filters(1280, self._global_params),
+ kernel_size=[1, 1],
+ strides=[1, 1],
+ kernel_initializer=conv_kernel_initializer,
+ padding='same',
+ use_bias=False)
+ self._bn1 = self._batch_norm(
+ axis=channel_axis,
+ momentum=batch_norm_momentum,
+ epsilon=batch_norm_epsilon)
+
+ self._avg_pooling = tf.keras.layers.GlobalAveragePooling2D(
+ data_format=self._global_params.data_format)
+ if self._global_params.num_classes:
+ self._fc = tf.layers.Dense(
+ self._global_params.num_classes,
+ kernel_initializer=dense_kernel_initializer)
+ else:
+ self._fc = None
+
+ if self._global_params.dropout_rate > 0:
+ self._dropout = tf.keras.layers.Dropout(self._global_params.dropout_rate)
+ else:
+ self._dropout = None
+
+ def call(self,
+ inputs,
+ training=True,
+ features_only=None,
+ pooled_features_only=False):
+ """Implementation of call().
+
+ Args:
+ inputs: input tensors.
+ training: boolean, whether the model is constructed for training.
+ features_only: build the base feature network only.
+ pooled_features_only: build the base network for features extraction
+ (after 1x1 conv layer and global pooling, but before dropout and fc
+ head).
+
+ Returns:
+ output tensors.
+ """
+ outputs = None
+ self.endpoints = {}
+ reduction_idx = 0
+ # Calls Stem layers
+ with tf.variable_scope('stem'):
+ outputs = self._relu_fn(
+ self._bn0(self._conv_stem(inputs), training=training))
+ logging.info('Built stem layers with output shape: %s', outputs.shape)
+ self.endpoints['stem'] = outputs
+
+ # Calls blocks.
+ for idx, block in enumerate(self._blocks):
+ is_reduction = False # reduction flag for blocks after the stem layer
+ # If the first block has super-pixel (space-to-depth) layer, then stem is
+ # the first reduction point.
+ if (block.block_args().super_pixel == 1 and idx == 0):
+ reduction_idx += 1
+ self.endpoints['reduction_%s' % reduction_idx] = outputs
+
+ elif ((idx == len(self._blocks) - 1) or
+ self._blocks[idx + 1].block_args().strides[0] > 1):
+ is_reduction = True
+ reduction_idx += 1
+
+ with tf.variable_scope('blocks_%s' % idx):
+ survival_prob = self._global_params.survival_prob
+ if survival_prob:
+ drop_rate = 1.0 - survival_prob
+ survival_prob = 1.0 - drop_rate * float(idx) / len(self._blocks)
+ logging.info('block_%s survival_prob: %s', idx, survival_prob)
+ outputs = block.call(
+ outputs, training=training, survival_prob=survival_prob)
+ self.endpoints['block_%s' % idx] = outputs
+ if is_reduction:
+ self.endpoints['reduction_%s' % reduction_idx] = outputs
+ if block.endpoints:
+ for k, v in six.iteritems(block.endpoints):
+ self.endpoints['block_%s/%s' % (idx, k)] = v
+ if is_reduction:
+ self.endpoints['reduction_%s/%s' % (reduction_idx, k)] = v
+ self.endpoints['features'] = outputs
+
+ if not features_only:
+ # Calls final layers and returns logits.
+ with tf.variable_scope('head'):
+ outputs = self._relu_fn(
+ self._bn1(self._conv_head(outputs), training=training))
+ self.endpoints['head_1x1'] = outputs
+
+ if self._global_params.local_pooling:
+ shape = outputs.get_shape().as_list()
+ kernel_size = [
+ 1, shape[self._spatial_dims[0]], shape[self._spatial_dims[1]], 1]
+ outputs = tf.nn.avg_pool(
+ outputs, ksize=kernel_size, strides=[1, 1, 1, 1], padding='VALID')
+ self.endpoints['pooled_features'] = outputs
+ if not pooled_features_only:
+ if self._dropout:
+ outputs = self._dropout(outputs, training=training)
+ self.endpoints['global_pool'] = outputs
+ if self._fc:
+ outputs = tf.squeeze(outputs, self._spatial_dims)
+ outputs = self._fc(outputs)
+ self.endpoints['head'] = outputs
+ else:
+ outputs = self._avg_pooling(outputs)
+ self.endpoints['pooled_features'] = outputs
+ if not pooled_features_only:
+ if self._dropout:
+ outputs = self._dropout(outputs, training=training)
+ self.endpoints['global_pool'] = outputs
+ if self._fc:
+ outputs = self._fc(outputs)
+ self.endpoints['head'] = outputs
+ return outputs
diff --git a/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/original_tf/eval_ckpt_main.py b/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/original_tf/eval_ckpt_main.py
new file mode 100644
index 0000000000000000000000000000000000000000..5993c323b3a8340fd0914ef56bf2a75cda5723d6
--- /dev/null
+++ b/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/original_tf/eval_ckpt_main.py
@@ -0,0 +1,225 @@
+# Copyright 2019 The TensorFlow Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ==============================================================================
+"""Eval checkpoint driver.
+
+This is an example evaluation script for users to understand the EfficientNet
+model checkpoints on CPU. To serve EfficientNet, please consider to export a
+`SavedModel` from checkpoints and use tf-serving to serve.
+"""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import json
+import sys
+from absl import app
+from absl import flags
+import numpy as np
+import tensorflow as tf
+
+
+import efficientnet_builder
+import preprocessing
+
+
+tf.compat.v1.disable_v2_behavior()
+
+flags.DEFINE_string('model_name', 'efficientnet-b0', 'Model name to eval.')
+flags.DEFINE_string('runmode', 'examples', 'Running mode: examples or imagenet')
+flags.DEFINE_string('imagenet_eval_glob', None,
+ 'Imagenet eval image glob, '
+ 'such as /imagenet/ILSVRC2012*.JPEG')
+flags.DEFINE_string('imagenet_eval_label', None,
+ 'Imagenet eval label file path, '
+ 'such as /imagenet/ILSVRC2012_validation_ground_truth.txt')
+flags.DEFINE_string('ckpt_dir', '/tmp/ckpt/', 'Checkpoint folders')
+flags.DEFINE_string('example_img', '/tmp/panda.jpg',
+ 'Filepath for a single example image.')
+flags.DEFINE_string('labels_map_file', '/tmp/labels_map.txt',
+ 'Labels map from label id to its meaning.')
+flags.DEFINE_integer('num_images', 5000,
+ 'Number of images to eval. Use -1 to eval all images.')
+FLAGS = flags.FLAGS
+
+MEAN_RGB = [0.485 * 255, 0.456 * 255, 0.406 * 255]
+STDDEV_RGB = [0.229 * 255, 0.224 * 255, 0.225 * 255]
+
+
+class EvalCkptDriver(object):
+ """A driver for running eval inference.
+
+ Attributes:
+ model_name: str. Model name to eval.
+ batch_size: int. Eval batch size.
+ num_classes: int. Number of classes, default to 1000 for ImageNet.
+ image_size: int. Input image size, determined by model name.
+ """
+
+ def __init__(self, model_name='efficientnet-b0', batch_size=1):
+ """Initialize internal variables."""
+ self.model_name = model_name
+ self.batch_size = batch_size
+ self.num_classes = 1000
+ # Model Scaling parameters
+ _, _, self.image_size, _ = efficientnet_builder.efficientnet_params(
+ model_name)
+
+ def restore_model(self, sess, ckpt_dir):
+ """Restore variables from checkpoint dir."""
+ checkpoint = tf.train.latest_checkpoint(ckpt_dir)
+ ema = tf.train.ExponentialMovingAverage(decay=0.9999)
+ ema_vars = tf.compat.v1.trainable_variables() + tf.compat.v1.get_collection('moving_vars')
+ for v in tf.compat.v1.global_variables():
+ if 'moving_mean' in v.name or 'moving_variance' in v.name:
+ ema_vars.append(v)
+ ema_vars = list(set(ema_vars))
+ var_dict = ema.variables_to_restore(ema_vars)
+ saver = tf.compat.v1.train.Saver(var_dict, max_to_keep=1)
+ saver.restore(sess, checkpoint)
+
+ def build_model(self, features, is_training):
+ """Build model with input features."""
+ features -= tf.constant(MEAN_RGB, shape=[1, 1, 3], dtype=features.dtype)
+ features /= tf.constant(STDDEV_RGB, shape=[1, 1, 3], dtype=features.dtype)
+ logits, _ = efficientnet_builder.build_model(
+ features, self.model_name, is_training)
+ probs = tf.nn.softmax(logits)
+ probs = tf.squeeze(probs)
+ return probs
+
+ def build_dataset(self, filenames, labels, is_training):
+ """Build input dataset."""
+ filenames = tf.constant(filenames)
+ labels = tf.constant(labels)
+
+ dataset = tf.compat.v1.data.Dataset.from_tensor_slices((filenames, labels))
+
+ def _parse_function(filename, label):
+ image_string = tf.io.read_file(filename)
+ image_decoded = preprocessing.preprocess_image(
+ image_string, is_training, self.image_size)
+ image = tf.cast(image_decoded, tf.float32)
+ return image, label
+
+ dataset = dataset.map(_parse_function)
+ dataset = dataset.batch(self.batch_size)
+
+ iterator = dataset.make_one_shot_iterator()
+ #iterator = iter(dataset)
+ images, labels = iterator.get_next()
+ return images, labels
+
+ def run_inference(self, ckpt_dir, image_files, labels):
+ """Build and run inference on the target images and labels."""
+ with tf.Graph().as_default(), tf.Session() as sess:
+ images, labels = self.build_dataset(image_files, labels, False)
+ probs = self.build_model(images, is_training=False)
+
+ sess.run(tf.global_variables_initializer())
+ self.restore_model(sess, ckpt_dir)
+
+ prediction_idx = []
+ prediction_prob = []
+ for _ in range(len(image_files) // self.batch_size):
+ out_probs = sess.run(probs)
+ idx = np.argsort(out_probs)[::-1]
+ prediction_idx.append(idx[:5])
+ prediction_prob.append([out_probs[pid] for pid in idx[:5]])
+
+ # Return the top 5 predictions (idx and prob) for each image.
+ return prediction_idx, prediction_prob
+
+
+def eval_example_images(model_name, ckpt_dir, image_files, labels_map_file):
+ """Eval a list of example images.
+
+ Args:
+ model_name: str. The name of model to eval.
+ ckpt_dir: str. Checkpoint directory path.
+ image_files: List[str]. A list of image file paths.
+ labels_map_file: str. The labels map file path.
+
+ Returns:
+ A tuple (pred_idx, and pred_prob), where pred_idx is the top 5 prediction
+ index and pred_prob is the top 5 prediction probability.
+ """
+ eval_ckpt_driver = EvalCkptDriver(model_name)
+ classes = json.loads(tf.gfile.Open(labels_map_file).read())
+ pred_idx, pred_prob = eval_ckpt_driver.run_inference(
+ ckpt_dir, image_files, [0] * len(image_files))
+ for i in range(len(image_files)):
+ print('predicted class for image {}: '.format(image_files[i]))
+ for j, idx in enumerate(pred_idx[i]):
+ print(' -> top_{} ({:4.2f}%): {} '.format(
+ j, pred_prob[i][j] * 100, classes[str(idx)]))
+ return pred_idx, pred_prob
+
+
+def eval_imagenet(model_name,
+ ckpt_dir,
+ imagenet_eval_glob,
+ imagenet_eval_label,
+ num_images):
+ """Eval ImageNet images and report top1/top5 accuracy.
+
+ Args:
+ model_name: str. The name of model to eval.
+ ckpt_dir: str. Checkpoint directory path.
+ imagenet_eval_glob: str. File path glob for all eval images.
+ imagenet_eval_label: str. File path for eval label.
+ num_images: int. Number of images to eval: -1 means eval the whole dataset.
+
+ Returns:
+ A tuple (top1, top5) for top1 and top5 accuracy.
+ """
+ eval_ckpt_driver = EvalCkptDriver(model_name)
+ imagenet_val_labels = [int(i) for i in tf.gfile.GFile(imagenet_eval_label)]
+ imagenet_filenames = sorted(tf.gfile.Glob(imagenet_eval_glob))
+ if num_images < 0:
+ num_images = len(imagenet_filenames)
+ image_files = imagenet_filenames[:num_images]
+ labels = imagenet_val_labels[:num_images]
+
+ pred_idx, _ = eval_ckpt_driver.run_inference(ckpt_dir, image_files, labels)
+ top1_cnt, top5_cnt = 0.0, 0.0
+ for i, label in enumerate(labels):
+ top1_cnt += label in pred_idx[i][:1]
+ top5_cnt += label in pred_idx[i][:5]
+ if i % 100 == 0:
+ print('Step {}: top1_acc = {:4.2f}% top5_acc = {:4.2f}%'.format(
+ i, 100 * top1_cnt / (i + 1), 100 * top5_cnt / (i + 1)))
+ sys.stdout.flush()
+ top1, top5 = 100 * top1_cnt / num_images, 100 * top5_cnt / num_images
+ print('Final: top1_acc = {:4.2f}% top5_acc = {:4.2f}%'.format(top1, top5))
+ return top1, top5
+
+
+def main(unused_argv):
+ tf.logging.set_verbosity(tf.logging.ERROR)
+ if FLAGS.runmode == 'examples':
+ # Run inference for an example image.
+ eval_example_images(FLAGS.model_name, FLAGS.ckpt_dir, [FLAGS.example_img],
+ FLAGS.labels_map_file)
+ elif FLAGS.runmode == 'imagenet':
+ # Run inference for imagenet.
+ eval_imagenet(FLAGS.model_name, FLAGS.ckpt_dir, FLAGS.imagenet_eval_glob,
+ FLAGS.imagenet_eval_label, FLAGS.num_images)
+ else:
+ print('must specify runmode: examples or imagenet')
+
+
+if __name__ == '__main__':
+ app.run(main)
diff --git a/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/original_tf/eval_ckpt_main_tf1.py b/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/original_tf/eval_ckpt_main_tf1.py
new file mode 100644
index 0000000000000000000000000000000000000000..e869d4ee767f3444e9872a023da00730a95cd4ad
--- /dev/null
+++ b/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/original_tf/eval_ckpt_main_tf1.py
@@ -0,0 +1,221 @@
+# Copyright 2019 The TensorFlow Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ==============================================================================
+"""Eval checkpoint driver.
+
+This is an example evaluation script for users to understand the EfficientNet
+model checkpoints on CPU. To serve EfficientNet, please consider to export a
+`SavedModel` from checkpoints and use tf-serving to serve.
+"""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import json
+import sys
+from absl import app
+from absl import flags
+import numpy as np
+import tensorflow as tf
+
+
+import efficientnet_builder
+import preprocessing
+
+
+flags.DEFINE_string('model_name', 'efficientnet-b0', 'Model name to eval.')
+flags.DEFINE_string('runmode', 'examples', 'Running mode: examples or imagenet')
+flags.DEFINE_string('imagenet_eval_glob', None,
+ 'Imagenet eval image glob, '
+ 'such as /imagenet/ILSVRC2012*.JPEG')
+flags.DEFINE_string('imagenet_eval_label', None,
+ 'Imagenet eval label file path, '
+ 'such as /imagenet/ILSVRC2012_validation_ground_truth.txt')
+flags.DEFINE_string('ckpt_dir', '/tmp/ckpt/', 'Checkpoint folders')
+flags.DEFINE_string('example_img', '/tmp/panda.jpg',
+ 'Filepath for a single example image.')
+flags.DEFINE_string('labels_map_file', '/tmp/labels_map.txt',
+ 'Labels map from label id to its meaning.')
+flags.DEFINE_integer('num_images', 5000,
+ 'Number of images to eval. Use -1 to eval all images.')
+FLAGS = flags.FLAGS
+
+MEAN_RGB = [0.485 * 255, 0.456 * 255, 0.406 * 255]
+STDDEV_RGB = [0.229 * 255, 0.224 * 255, 0.225 * 255]
+
+
+class EvalCkptDriver(object):
+ """A driver for running eval inference.
+
+ Attributes:
+ model_name: str. Model name to eval.
+ batch_size: int. Eval batch size.
+ num_classes: int. Number of classes, default to 1000 for ImageNet.
+ image_size: int. Input image size, determined by model name.
+ """
+
+ def __init__(self, model_name='efficientnet-b0', batch_size=1):
+ """Initialize internal variables."""
+ self.model_name = model_name
+ self.batch_size = batch_size
+ self.num_classes = 1000
+ # Model Scaling parameters
+ _, _, self.image_size, _ = efficientnet_builder.efficientnet_params(
+ model_name)
+
+ def restore_model(self, sess, ckpt_dir):
+ """Restore variables from checkpoint dir."""
+ checkpoint = tf.train.latest_checkpoint(ckpt_dir)
+ ema = tf.train.ExponentialMovingAverage(decay=0.9999)
+ ema_vars = tf.trainable_variables() + tf.get_collection('moving_vars')
+ for v in tf.global_variables():
+ if 'moving_mean' in v.name or 'moving_variance' in v.name:
+ ema_vars.append(v)
+ ema_vars = list(set(ema_vars))
+ var_dict = ema.variables_to_restore(ema_vars)
+ saver = tf.train.Saver(var_dict, max_to_keep=1)
+ saver.restore(sess, checkpoint)
+
+ def build_model(self, features, is_training):
+ """Build model with input features."""
+ features -= tf.constant(MEAN_RGB, shape=[1, 1, 3], dtype=features.dtype)
+ features /= tf.constant(STDDEV_RGB, shape=[1, 1, 3], dtype=features.dtype)
+ logits, _ = efficientnet_builder.build_model(
+ features, self.model_name, is_training)
+ probs = tf.nn.softmax(logits)
+ probs = tf.squeeze(probs)
+ return probs
+
+ def build_dataset(self, filenames, labels, is_training):
+ """Build input dataset."""
+ filenames = tf.constant(filenames)
+ labels = tf.constant(labels)
+ dataset = tf.data.Dataset.from_tensor_slices((filenames, labels))
+
+ def _parse_function(filename, label):
+ image_string = tf.read_file(filename)
+ image_decoded = preprocessing.preprocess_image(
+ image_string, is_training, self.image_size)
+ image = tf.cast(image_decoded, tf.float32)
+ return image, label
+
+ dataset = dataset.map(_parse_function)
+ dataset = dataset.batch(self.batch_size)
+
+ iterator = dataset.make_one_shot_iterator()
+ images, labels = iterator.get_next()
+ return images, labels
+
+ def run_inference(self, ckpt_dir, image_files, labels):
+ """Build and run inference on the target images and labels."""
+ with tf.Graph().as_default(), tf.Session() as sess:
+ images, labels = self.build_dataset(image_files, labels, False)
+ probs = self.build_model(images, is_training=False)
+
+ sess.run(tf.global_variables_initializer())
+ self.restore_model(sess, ckpt_dir)
+
+ prediction_idx = []
+ prediction_prob = []
+ for _ in range(len(image_files) // self.batch_size):
+ out_probs = sess.run(probs)
+ idx = np.argsort(out_probs)[::-1]
+ prediction_idx.append(idx[:5])
+ prediction_prob.append([out_probs[pid] for pid in idx[:5]])
+
+ # Return the top 5 predictions (idx and prob) for each image.
+ return prediction_idx, prediction_prob
+
+
+def eval_example_images(model_name, ckpt_dir, image_files, labels_map_file):
+ """Eval a list of example images.
+
+ Args:
+ model_name: str. The name of model to eval.
+ ckpt_dir: str. Checkpoint directory path.
+ image_files: List[str]. A list of image file paths.
+ labels_map_file: str. The labels map file path.
+
+ Returns:
+ A tuple (pred_idx, and pred_prob), where pred_idx is the top 5 prediction
+ index and pred_prob is the top 5 prediction probability.
+ """
+ eval_ckpt_driver = EvalCkptDriver(model_name)
+ classes = json.loads(tf.gfile.Open(labels_map_file).read())
+ pred_idx, pred_prob = eval_ckpt_driver.run_inference(
+ ckpt_dir, image_files, [0] * len(image_files))
+ for i in range(len(image_files)):
+ print('predicted class for image {}: '.format(image_files[i]))
+ for j, idx in enumerate(pred_idx[i]):
+ print(' -> top_{} ({:4.2f}%): {} '.format(
+ j, pred_prob[i][j] * 100, classes[str(idx)]))
+ return pred_idx, pred_prob
+
+
+def eval_imagenet(model_name,
+ ckpt_dir,
+ imagenet_eval_glob,
+ imagenet_eval_label,
+ num_images):
+ """Eval ImageNet images and report top1/top5 accuracy.
+
+ Args:
+ model_name: str. The name of model to eval.
+ ckpt_dir: str. Checkpoint directory path.
+ imagenet_eval_glob: str. File path glob for all eval images.
+ imagenet_eval_label: str. File path for eval label.
+ num_images: int. Number of images to eval: -1 means eval the whole dataset.
+
+ Returns:
+ A tuple (top1, top5) for top1 and top5 accuracy.
+ """
+ eval_ckpt_driver = EvalCkptDriver(model_name)
+ imagenet_val_labels = [int(i) for i in tf.gfile.GFile(imagenet_eval_label)]
+ imagenet_filenames = sorted(tf.gfile.Glob(imagenet_eval_glob))
+ if num_images < 0:
+ num_images = len(imagenet_filenames)
+ image_files = imagenet_filenames[:num_images]
+ labels = imagenet_val_labels[:num_images]
+
+ pred_idx, _ = eval_ckpt_driver.run_inference(ckpt_dir, image_files, labels)
+ top1_cnt, top5_cnt = 0.0, 0.0
+ for i, label in enumerate(labels):
+ top1_cnt += label in pred_idx[i][:1]
+ top5_cnt += label in pred_idx[i][:5]
+ if i % 100 == 0:
+ print('Step {}: top1_acc = {:4.2f}% top5_acc = {:4.2f}%'.format(
+ i, 100 * top1_cnt / (i + 1), 100 * top5_cnt / (i + 1)))
+ sys.stdout.flush()
+ top1, top5 = 100 * top1_cnt / num_images, 100 * top5_cnt / num_images
+ print('Final: top1_acc = {:4.2f}% top5_acc = {:4.2f}%'.format(top1, top5))
+ return top1, top5
+
+
+def main(unused_argv):
+ tf.logging.set_verbosity(tf.logging.ERROR)
+ if FLAGS.runmode == 'examples':
+ # Run inference for an example image.
+ eval_example_images(FLAGS.model_name, FLAGS.ckpt_dir, [FLAGS.example_img],
+ FLAGS.labels_map_file)
+ elif FLAGS.runmode == 'imagenet':
+ # Run inference for imagenet.
+ eval_imagenet(FLAGS.model_name, FLAGS.ckpt_dir, FLAGS.imagenet_eval_glob,
+ FLAGS.imagenet_eval_label, FLAGS.num_images)
+ else:
+ print('must specify runmode: examples or imagenet')
+
+
+if __name__ == '__main__':
+ app.run(main)
diff --git a/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/original_tf/preprocessing.py b/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/original_tf/preprocessing.py
new file mode 100644
index 0000000000000000000000000000000000000000..e7af8ab625d40d9581ed47db3517feab74fe380d
--- /dev/null
+++ b/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/original_tf/preprocessing.py
@@ -0,0 +1,241 @@
+# Copyright 2019 The TensorFlow Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ==============================================================================
+"""ImageNet preprocessing."""
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+from absl import logging
+
+import tensorflow.compat.v1 as tf
+
+
+IMAGE_SIZE = 224
+CROP_PADDING = 32
+
+
+def distorted_bounding_box_crop(image_bytes,
+ bbox,
+ min_object_covered=0.1,
+ aspect_ratio_range=(0.75, 1.33),
+ area_range=(0.05, 1.0),
+ max_attempts=100,
+ scope=None):
+ """Generates cropped_image using one of the bboxes randomly distorted.
+
+ See `tf.image.sample_distorted_bounding_box` for more documentation.
+
+ Args:
+ image_bytes: `Tensor` of binary image data.
+ bbox: `Tensor` of bounding boxes arranged `[1, num_boxes, coords]`
+ where each coordinate is [0, 1) and the coordinates are arranged
+ as `[ymin, xmin, ymax, xmax]`. If num_boxes is 0 then use the whole
+ image.
+ min_object_covered: An optional `float`. Defaults to `0.1`. The cropped
+ area of the image must contain at least this fraction of any bounding
+ box supplied.
+ aspect_ratio_range: An optional list of `float`s. The cropped area of the
+ image must have an aspect ratio = width / height within this range.
+ area_range: An optional list of `float`s. The cropped area of the image
+ must contain a fraction of the supplied image within in this range.
+ max_attempts: An optional `int`. Number of attempts at generating a cropped
+ region of the image of the specified constraints. After `max_attempts`
+ failures, return the entire image.
+ scope: Optional `str` for name scope.
+ Returns:
+ cropped image `Tensor`
+ """
+ with tf.name_scope(scope, 'distorted_bounding_box_crop', [image_bytes, bbox]):
+ shape = tf.image.extract_jpeg_shape(image_bytes)
+ sample_distorted_bounding_box = tf.image.sample_distorted_bounding_box(
+ shape,
+ bounding_boxes=bbox,
+ min_object_covered=min_object_covered,
+ aspect_ratio_range=aspect_ratio_range,
+ area_range=area_range,
+ max_attempts=max_attempts,
+ use_image_if_no_bounding_boxes=True)
+ bbox_begin, bbox_size, _ = sample_distorted_bounding_box
+
+ # Crop the image to the specified bounding box.
+ offset_y, offset_x, _ = tf.unstack(bbox_begin)
+ target_height, target_width, _ = tf.unstack(bbox_size)
+ crop_window = tf.stack([offset_y, offset_x, target_height, target_width])
+ image = tf.image.decode_and_crop_jpeg(image_bytes, crop_window, channels=3)
+
+ return image
+
+
+def _at_least_x_are_equal(a, b, x):
+ """At least `x` of `a` and `b` `Tensors` are equal."""
+ match = tf.equal(a, b)
+ match = tf.cast(match, tf.int32)
+ return tf.greater_equal(tf.reduce_sum(match), x)
+
+
+def _decode_and_random_crop(image_bytes, image_size):
+ """Make a random crop of image_size."""
+ bbox = tf.constant([0.0, 0.0, 1.0, 1.0], dtype=tf.float32, shape=[1, 1, 4])
+ image = distorted_bounding_box_crop(
+ image_bytes,
+ bbox,
+ min_object_covered=0.1,
+ aspect_ratio_range=(3. / 4, 4. / 3.),
+ area_range=(0.08, 1.0),
+ max_attempts=10,
+ scope=None)
+ original_shape = tf.image.extract_jpeg_shape(image_bytes)
+ bad = _at_least_x_are_equal(original_shape, tf.shape(image), 3)
+
+ image = tf.cond(
+ bad,
+ lambda: _decode_and_center_crop(image_bytes, image_size),
+ lambda: tf.image.resize_bicubic([image], # pylint: disable=g-long-lambda
+ [image_size, image_size])[0])
+
+ return image
+
+
+def _decode_and_center_crop(image_bytes, image_size):
+ """Crops to center of image with padding then scales image_size."""
+ shape = tf.image.extract_jpeg_shape(image_bytes)
+ image_height = shape[0]
+ image_width = shape[1]
+
+ padded_center_crop_size = tf.cast(
+ ((image_size / (image_size + CROP_PADDING)) *
+ tf.cast(tf.minimum(image_height, image_width), tf.float32)),
+ tf.int32)
+
+ offset_height = ((image_height - padded_center_crop_size) + 1) // 2
+ offset_width = ((image_width - padded_center_crop_size) + 1) // 2
+ crop_window = tf.stack([offset_height, offset_width,
+ padded_center_crop_size, padded_center_crop_size])
+ image = tf.image.decode_and_crop_jpeg(image_bytes, crop_window, channels=3)
+ image = tf.image.resize_bicubic([image], [image_size, image_size])[0]
+ return image
+
+
+def _flip(image):
+ """Random horizontal image flip."""
+ image = tf.image.random_flip_left_right(image)
+ return image
+
+
+def preprocess_for_train(image_bytes, use_bfloat16, image_size=IMAGE_SIZE,
+ augment_name=None,
+ randaug_num_layers=None, randaug_magnitude=None):
+ """Preprocesses the given image for evaluation.
+
+ Args:
+ image_bytes: `Tensor` representing an image binary of arbitrary size.
+ use_bfloat16: `bool` for whether to use bfloat16.
+ image_size: image size.
+ augment_name: `string` that is the name of the augmentation method
+ to apply to the image. `autoaugment` if AutoAugment is to be used or
+ `randaugment` if RandAugment is to be used. If the value is `None` no
+ augmentation method will be applied applied. See autoaugment.py for more
+ details.
+ randaug_num_layers: 'int', if RandAug is used, what should the number of
+ layers be. See autoaugment.py for detailed description.
+ randaug_magnitude: 'int', if RandAug is used, what should the magnitude
+ be. See autoaugment.py for detailed description.
+
+ Returns:
+ A preprocessed image `Tensor`.
+ """
+ image = _decode_and_random_crop(image_bytes, image_size)
+ image = _flip(image)
+ image = tf.reshape(image, [image_size, image_size, 3])
+
+ image = tf.image.convert_image_dtype(
+ image, dtype=tf.bfloat16 if use_bfloat16 else tf.float32)
+
+ if augment_name:
+ try:
+ import autoaugment # pylint: disable=g-import-not-at-top
+ except ImportError as e:
+ logging.exception('Autoaugment is not supported in TF 2.x.')
+ raise e
+
+ logging.info('Apply AutoAugment policy %s', augment_name)
+ input_image_type = image.dtype
+ image = tf.clip_by_value(image, 0.0, 255.0)
+ image = tf.cast(image, dtype=tf.uint8)
+
+ if augment_name == 'autoaugment':
+ logging.info('Apply AutoAugment policy %s', augment_name)
+ image = autoaugment.distort_image_with_autoaugment(image, 'v0')
+ elif augment_name == 'randaugment':
+ image = autoaugment.distort_image_with_randaugment(
+ image, randaug_num_layers, randaug_magnitude)
+ else:
+ raise ValueError('Invalid value for augment_name: %s' % (augment_name))
+
+ image = tf.cast(image, dtype=input_image_type)
+ return image
+
+
+def preprocess_for_eval(image_bytes, use_bfloat16, image_size=IMAGE_SIZE):
+ """Preprocesses the given image for evaluation.
+
+ Args:
+ image_bytes: `Tensor` representing an image binary of arbitrary size.
+ use_bfloat16: `bool` for whether to use bfloat16.
+ image_size: image size.
+
+ Returns:
+ A preprocessed image `Tensor`.
+ """
+ image = _decode_and_center_crop(image_bytes, image_size)
+ image = tf.reshape(image, [image_size, image_size, 3])
+ image = tf.image.convert_image_dtype(
+ image, dtype=tf.bfloat16 if use_bfloat16 else tf.float32)
+ return image
+
+
+def preprocess_image(image_bytes,
+ is_training=False,
+ use_bfloat16=False,
+ image_size=IMAGE_SIZE,
+ augment_name=None,
+ randaug_num_layers=None,
+ randaug_magnitude=None):
+ """Preprocesses the given image.
+
+ Args:
+ image_bytes: `Tensor` representing an image binary of arbitrary size.
+ is_training: `bool` for whether the preprocessing is for training.
+ use_bfloat16: `bool` for whether to use bfloat16.
+ image_size: image size.
+ augment_name: `string` that is the name of the augmentation method
+ to apply to the image. `autoaugment` if AutoAugment is to be used or
+ `randaugment` if RandAugment is to be used. If the value is `None` no
+ augmentation method will be applied applied. See autoaugment.py for more
+ details.
+ randaug_num_layers: 'int', if RandAug is used, what should the number of
+ layers be. See autoaugment.py for detailed description.
+ randaug_magnitude: 'int', if RandAug is used, what should the magnitude
+ be. See autoaugment.py for detailed description.
+
+ Returns:
+ A preprocessed image `Tensor` with value range of [0, 255].
+ """
+ if is_training:
+ return preprocess_for_train(
+ image_bytes, use_bfloat16, image_size, augment_name,
+ randaug_num_layers, randaug_magnitude)
+ else:
+ return preprocess_for_eval(image_bytes, use_bfloat16, image_size)
diff --git a/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/original_tf/utils.py b/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/original_tf/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..61782ea3c45d7588dd909061e6c319272d803915
--- /dev/null
+++ b/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/original_tf/utils.py
@@ -0,0 +1,405 @@
+# Copyright 2019 The TensorFlow Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ==============================================================================
+"""Model utilities."""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import json
+import os
+import sys
+
+from absl import logging
+import numpy as np
+import tensorflow.compat.v1 as tf
+
+from tensorflow.python.tpu import tpu_function # pylint:disable=g-direct-tensorflow-import
+
+
+def build_learning_rate(initial_lr,
+ global_step,
+ steps_per_epoch=None,
+ lr_decay_type='exponential',
+ decay_factor=0.97,
+ decay_epochs=2.4,
+ total_steps=None,
+ warmup_epochs=5):
+ """Build learning rate."""
+ if lr_decay_type == 'exponential':
+ assert steps_per_epoch is not None
+ decay_steps = steps_per_epoch * decay_epochs
+ lr = tf.train.exponential_decay(
+ initial_lr, global_step, decay_steps, decay_factor, staircase=True)
+ elif lr_decay_type == 'cosine':
+ assert total_steps is not None
+ lr = 0.5 * initial_lr * (
+ 1 + tf.cos(np.pi * tf.cast(global_step, tf.float32) / total_steps))
+ elif lr_decay_type == 'constant':
+ lr = initial_lr
+ else:
+ assert False, 'Unknown lr_decay_type : %s' % lr_decay_type
+
+ if warmup_epochs:
+ logging.info('Learning rate warmup_epochs: %d', warmup_epochs)
+ warmup_steps = int(warmup_epochs * steps_per_epoch)
+ warmup_lr = (
+ initial_lr * tf.cast(global_step, tf.float32) / tf.cast(
+ warmup_steps, tf.float32))
+ lr = tf.cond(global_step < warmup_steps, lambda: warmup_lr, lambda: lr)
+
+ return lr
+
+
+def build_optimizer(learning_rate,
+ optimizer_name='rmsprop',
+ decay=0.9,
+ epsilon=0.001,
+ momentum=0.9):
+ """Build optimizer."""
+ if optimizer_name == 'sgd':
+ logging.info('Using SGD optimizer')
+ optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
+ elif optimizer_name == 'momentum':
+ logging.info('Using Momentum optimizer')
+ optimizer = tf.train.MomentumOptimizer(
+ learning_rate=learning_rate, momentum=momentum)
+ elif optimizer_name == 'rmsprop':
+ logging.info('Using RMSProp optimizer')
+ optimizer = tf.train.RMSPropOptimizer(learning_rate, decay, momentum,
+ epsilon)
+ else:
+ logging.fatal('Unknown optimizer: %s', optimizer_name)
+
+ return optimizer
+
+
+class TpuBatchNormalization(tf.layers.BatchNormalization):
+ # class TpuBatchNormalization(tf.layers.BatchNormalization):
+ """Cross replica batch normalization."""
+
+ def __init__(self, fused=False, **kwargs):
+ if fused in (True, None):
+ raise ValueError('TpuBatchNormalization does not support fused=True.')
+ super(TpuBatchNormalization, self).__init__(fused=fused, **kwargs)
+
+ def _cross_replica_average(self, t, num_shards_per_group):
+ """Calculates the average value of input tensor across TPU replicas."""
+ num_shards = tpu_function.get_tpu_context().number_of_shards
+ group_assignment = None
+ if num_shards_per_group > 1:
+ if num_shards % num_shards_per_group != 0:
+ raise ValueError('num_shards: %d mod shards_per_group: %d, should be 0'
+ % (num_shards, num_shards_per_group))
+ num_groups = num_shards // num_shards_per_group
+ group_assignment = [[
+ x for x in range(num_shards) if x // num_shards_per_group == y
+ ] for y in range(num_groups)]
+ return tf.tpu.cross_replica_sum(t, group_assignment) / tf.cast(
+ num_shards_per_group, t.dtype)
+
+ def _moments(self, inputs, reduction_axes, keep_dims):
+ """Compute the mean and variance: it overrides the original _moments."""
+ shard_mean, shard_variance = super(TpuBatchNormalization, self)._moments(
+ inputs, reduction_axes, keep_dims=keep_dims)
+
+ num_shards = tpu_function.get_tpu_context().number_of_shards or 1
+ if num_shards <= 8: # Skip cross_replica for 2x2 or smaller slices.
+ num_shards_per_group = 1
+ else:
+ num_shards_per_group = max(8, num_shards // 8)
+ logging.info('TpuBatchNormalization with num_shards_per_group %s',
+ num_shards_per_group)
+ if num_shards_per_group > 1:
+ # Compute variance using: Var[X]= E[X^2] - E[X]^2.
+ shard_square_of_mean = tf.math.square(shard_mean)
+ shard_mean_of_square = shard_variance + shard_square_of_mean
+ group_mean = self._cross_replica_average(
+ shard_mean, num_shards_per_group)
+ group_mean_of_square = self._cross_replica_average(
+ shard_mean_of_square, num_shards_per_group)
+ group_variance = group_mean_of_square - tf.math.square(group_mean)
+ return (group_mean, group_variance)
+ else:
+ return (shard_mean, shard_variance)
+
+
+class BatchNormalization(tf.layers.BatchNormalization):
+ """Fixed default name of BatchNormalization to match TpuBatchNormalization."""
+
+ def __init__(self, name='tpu_batch_normalization', **kwargs):
+ super(BatchNormalization, self).__init__(name=name, **kwargs)
+
+
+def drop_connect(inputs, is_training, survival_prob):
+ """Drop the entire conv with given survival probability."""
+ # "Deep Networks with Stochastic Depth", https://arxiv.org/pdf/1603.09382.pdf
+ if not is_training:
+ return inputs
+
+ # Compute tensor.
+ batch_size = tf.shape(inputs)[0]
+ random_tensor = survival_prob
+ random_tensor += tf.random_uniform([batch_size, 1, 1, 1], dtype=inputs.dtype)
+ binary_tensor = tf.floor(random_tensor)
+ # Unlike conventional way that multiply survival_prob at test time, here we
+ # divide survival_prob at training time, such that no addition compute is
+ # needed at test time.
+ output = tf.div(inputs, survival_prob) * binary_tensor
+ return output
+
+
+def archive_ckpt(ckpt_eval, ckpt_objective, ckpt_path):
+ """Archive a checkpoint if the metric is better."""
+ ckpt_dir, ckpt_name = os.path.split(ckpt_path)
+
+ saved_objective_path = os.path.join(ckpt_dir, 'best_objective.txt')
+ saved_objective = float('-inf')
+ if tf.gfile.Exists(saved_objective_path):
+ with tf.gfile.GFile(saved_objective_path, 'r') as f:
+ saved_objective = float(f.read())
+ if saved_objective > ckpt_objective:
+ logging.info('Ckpt %s is worse than %s', ckpt_objective, saved_objective)
+ return False
+
+ filenames = tf.gfile.Glob(ckpt_path + '.*')
+ if filenames is None:
+ logging.info('No files to copy for checkpoint %s', ckpt_path)
+ return False
+
+ # Clear the old folder.
+ dst_dir = os.path.join(ckpt_dir, 'archive')
+ if tf.gfile.Exists(dst_dir):
+ tf.gfile.DeleteRecursively(dst_dir)
+ tf.gfile.MakeDirs(dst_dir)
+
+ # Write checkpoints.
+ for f in filenames:
+ dest = os.path.join(dst_dir, os.path.basename(f))
+ tf.gfile.Copy(f, dest, overwrite=True)
+ ckpt_state = tf.train.generate_checkpoint_state_proto(
+ dst_dir,
+ model_checkpoint_path=ckpt_name,
+ all_model_checkpoint_paths=[ckpt_name])
+ with tf.gfile.GFile(os.path.join(dst_dir, 'checkpoint'), 'w') as f:
+ f.write(str(ckpt_state))
+ with tf.gfile.GFile(os.path.join(dst_dir, 'best_eval.txt'), 'w') as f:
+ f.write('%s' % ckpt_eval)
+
+ # Update the best objective.
+ with tf.gfile.GFile(saved_objective_path, 'w') as f:
+ f.write('%f' % ckpt_objective)
+
+ logging.info('Copying checkpoint %s to %s', ckpt_path, dst_dir)
+ return True
+
+
+def get_ema_vars():
+ """Get all exponential moving average (ema) variables."""
+ ema_vars = tf.trainable_variables() + tf.get_collection('moving_vars')
+ for v in tf.global_variables():
+ # We maintain mva for batch norm moving mean and variance as well.
+ if 'moving_mean' in v.name or 'moving_variance' in v.name:
+ ema_vars.append(v)
+ return list(set(ema_vars))
+
+
+class DepthwiseConv2D(tf.keras.layers.DepthwiseConv2D, tf.layers.Layer):
+ """Wrap keras DepthwiseConv2D to tf.layers."""
+
+ pass
+
+
+class EvalCkptDriver(object):
+ """A driver for running eval inference.
+
+ Attributes:
+ model_name: str. Model name to eval.
+ batch_size: int. Eval batch size.
+ image_size: int. Input image size, determined by model name.
+ num_classes: int. Number of classes, default to 1000 for ImageNet.
+ include_background_label: whether to include extra background label.
+ """
+
+ def __init__(self,
+ model_name,
+ batch_size=1,
+ image_size=224,
+ num_classes=1000,
+ include_background_label=False):
+ """Initialize internal variables."""
+ self.model_name = model_name
+ self.batch_size = batch_size
+ self.num_classes = num_classes
+ self.include_background_label = include_background_label
+ self.image_size = image_size
+
+ def restore_model(self, sess, ckpt_dir, enable_ema=True, export_ckpt=None):
+ """Restore variables from checkpoint dir."""
+ sess.run(tf.global_variables_initializer())
+ checkpoint = tf.train.latest_checkpoint(ckpt_dir)
+ if enable_ema:
+ ema = tf.train.ExponentialMovingAverage(decay=0.0)
+ ema_vars = get_ema_vars()
+ var_dict = ema.variables_to_restore(ema_vars)
+ ema_assign_op = ema.apply(ema_vars)
+ else:
+ var_dict = get_ema_vars()
+ ema_assign_op = None
+
+ tf.train.get_or_create_global_step()
+ sess.run(tf.global_variables_initializer())
+ saver = tf.train.Saver(var_dict, max_to_keep=1)
+ saver.restore(sess, checkpoint)
+
+ if export_ckpt:
+ if ema_assign_op is not None:
+ sess.run(ema_assign_op)
+ saver = tf.train.Saver(max_to_keep=1, save_relative_paths=True)
+ saver.save(sess, export_ckpt)
+
+ def build_model(self, features, is_training):
+ """Build model with input features."""
+ del features, is_training
+ raise ValueError('Must be implemented by subclasses.')
+
+ def get_preprocess_fn(self):
+ raise ValueError('Must be implemented by subclsses.')
+
+ def build_dataset(self, filenames, labels, is_training):
+ """Build input dataset."""
+ batch_drop_remainder = False
+ if 'condconv' in self.model_name and not is_training:
+ # CondConv layers can only be called with known batch dimension. Thus, we
+ # must drop all remaining examples that do not make up one full batch.
+ # To ensure all examples are evaluated, use a batch size that evenly
+ # divides the number of files.
+ batch_drop_remainder = True
+ num_files = len(filenames)
+ if num_files % self.batch_size != 0:
+ tf.logging.warn('Remaining examples in last batch are not being '
+ 'evaluated.')
+ filenames = tf.constant(filenames)
+ labels = tf.constant(labels)
+ dataset = tf.data.Dataset.from_tensor_slices((filenames, labels))
+
+ def _parse_function(filename, label):
+ image_string = tf.read_file(filename)
+ preprocess_fn = self.get_preprocess_fn()
+ image_decoded = preprocess_fn(
+ image_string, is_training, image_size=self.image_size)
+ image = tf.cast(image_decoded, tf.float32)
+ return image, label
+
+ dataset = dataset.map(_parse_function)
+ dataset = dataset.batch(self.batch_size,
+ drop_remainder=batch_drop_remainder)
+
+ iterator = dataset.make_one_shot_iterator()
+ images, labels = iterator.get_next()
+ return images, labels
+
+ def run_inference(self,
+ ckpt_dir,
+ image_files,
+ labels,
+ enable_ema=True,
+ export_ckpt=None):
+ """Build and run inference on the target images and labels."""
+ label_offset = 1 if self.include_background_label else 0
+ with tf.Graph().as_default(), tf.Session() as sess:
+ images, labels = self.build_dataset(image_files, labels, False)
+ probs = self.build_model(images, is_training=False)
+ if isinstance(probs, tuple):
+ probs = probs[0]
+
+ self.restore_model(sess, ckpt_dir, enable_ema, export_ckpt)
+
+ prediction_idx = []
+ prediction_prob = []
+ for _ in range(len(image_files) // self.batch_size):
+ out_probs = sess.run(probs)
+ idx = np.argsort(out_probs)[::-1]
+ prediction_idx.append(idx[:5] - label_offset)
+ prediction_prob.append([out_probs[pid] for pid in idx[:5]])
+
+ # Return the top 5 predictions (idx and prob) for each image.
+ return prediction_idx, prediction_prob
+
+ def eval_example_images(self,
+ ckpt_dir,
+ image_files,
+ labels_map_file,
+ enable_ema=True,
+ export_ckpt=None):
+ """Eval a list of example images.
+
+ Args:
+ ckpt_dir: str. Checkpoint directory path.
+ image_files: List[str]. A list of image file paths.
+ labels_map_file: str. The labels map file path.
+ enable_ema: enable expotential moving average.
+ export_ckpt: export ckpt folder.
+
+ Returns:
+ A tuple (pred_idx, and pred_prob), where pred_idx is the top 5 prediction
+ index and pred_prob is the top 5 prediction probability.
+ """
+ classes = json.loads(tf.gfile.Open(labels_map_file).read())
+ pred_idx, pred_prob = self.run_inference(
+ ckpt_dir, image_files, [0] * len(image_files), enable_ema, export_ckpt)
+ for i in range(len(image_files)):
+ print('predicted class for image {}: '.format(image_files[i]))
+ for j, idx in enumerate(pred_idx[i]):
+ print(' -> top_{} ({:4.2f}%): {} '.format(j, pred_prob[i][j] * 100,
+ classes[str(idx)]))
+ return pred_idx, pred_prob
+
+ def eval_imagenet(self, ckpt_dir, imagenet_eval_glob,
+ imagenet_eval_label, num_images, enable_ema, export_ckpt):
+ """Eval ImageNet images and report top1/top5 accuracy.
+
+ Args:
+ ckpt_dir: str. Checkpoint directory path.
+ imagenet_eval_glob: str. File path glob for all eval images.
+ imagenet_eval_label: str. File path for eval label.
+ num_images: int. Number of images to eval: -1 means eval the whole
+ dataset.
+ enable_ema: enable expotential moving average.
+ export_ckpt: export checkpoint folder.
+
+ Returns:
+ A tuple (top1, top5) for top1 and top5 accuracy.
+ """
+ imagenet_val_labels = [int(i) for i in tf.gfile.GFile(imagenet_eval_label)]
+ imagenet_filenames = sorted(tf.gfile.Glob(imagenet_eval_glob))
+ if num_images < 0:
+ num_images = len(imagenet_filenames)
+ image_files = imagenet_filenames[:num_images]
+ labels = imagenet_val_labels[:num_images]
+
+ pred_idx, _ = self.run_inference(
+ ckpt_dir, image_files, labels, enable_ema, export_ckpt)
+ top1_cnt, top5_cnt = 0.0, 0.0
+ for i, label in enumerate(labels):
+ top1_cnt += label in pred_idx[i][:1]
+ top5_cnt += label in pred_idx[i][:5]
+ if i % 100 == 0:
+ print('Step {}: top1_acc = {:4.2f}% top5_acc = {:4.2f}%'.format(
+ i, 100 * top1_cnt / (i + 1), 100 * top5_cnt / (i + 1)))
+ sys.stdout.flush()
+ top1, top5 = 100 * top1_cnt / num_images, 100 * top5_cnt / num_images
+ print('Final: top1_acc = {:4.2f}% top5_acc = {:4.2f}%'.format(top1, top5))
+ return top1, top5
diff --git a/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/rename.sh b/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/rename.sh
new file mode 100644
index 0000000000000000000000000000000000000000..aa791139895b14ae1ffe00098cc55c56dfeca0fd
--- /dev/null
+++ b/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/rename.sh
@@ -0,0 +1,5 @@
+for i in 0 1 2 3 4 5 6 7 8
+do
+ X=$(sha256sum efficientnet-b${i}.pth | head -c 8)
+ mv efficientnet-b${i}.pth efficientnet-b${i}-${X}.pth
+done
diff --git a/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/run.sh b/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/run.sh
new file mode 100644
index 0000000000000000000000000000000000000000..f80d5f5d9b879ce98d180672c5abcb3dd9e569b9
--- /dev/null
+++ b/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/convert_tf_to_pt/run.sh
@@ -0,0 +1,17 @@
+python ../convert_tf_to_pt/load_tf_weights.py --model_name efficientnet-b0 --tf_checkpoint ../pretrained_tensorflow/efficientnet-b0/ --output_file ../pretrained_pytorch/efficientnet-b0.pth
+
+# python ../convert_tf_to_pt/load_tf_weights.py --model_name efficientnet-b1 --tf_checkpoint ../pretrained_tensorflow/efficientnet-b1/ --output_file ../pretrained_pytorch/efficientnet-b1.pth
+
+# python ../convert_tf_to_pt/load_tf_weights.py --model_name efficientnet-b2 --tf_checkpoint ../pretrained_tensorflow/efficientnet-b2/ --output_file ../pretrained_pytorch/efficientnet-b2.pth
+
+# python ../convert_tf_to_pt/load_tf_weights.py --model_name efficientnet-b3 --tf_checkpoint ../pretrained_tensorflow/efficientnet-b3/ --output_file ../pretrained_pytorch/efficientnet-b3.pth
+
+# python ../convert_tf_to_pt/load_tf_weights.py --model_name efficientnet-b4 --tf_checkpoint ../pretrained_tensorflow/efficientnet-b4/ --output_file ../pretrained_pytorch/efficientnet-b4.pth
+
+# python ../convert_tf_to_pt/load_tf_weights.py --model_name efficientnet-b5 --tf_checkpoint ../pretrained_tensorflow/efficientnet-b5/ --output_file ../pretrained_pytorch/efficientnet-b5.pth
+
+# python ../convert_tf_to_pt/load_tf_weights.py --model_name efficientnet-b6 --tf_checkpoint ../pretrained_tensorflow/efficientnet-b6/ --output_file ../pretrained_pytorch/efficientnet-b6.pth
+
+# python ../convert_tf_to_pt/load_tf_weights.py --model_name efficientnet-b7 --tf_checkpoint ../pretrained_tensorflow/efficientnet-b7/ --output_file ../pretrained_pytorch/efficientnet-b7.pth
+
+# python ../convert_tf_to_pt/load_tf_weights.py --model_name efficientnet-b8 --tf_checkpoint ../pretrained_tensorflow/efficientnet-b8/ --output_file ../pretrained_pytorch/efficientnet-b8.pth
diff --git a/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/pretrained_tensorflow/download.sh b/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/pretrained_tensorflow/download.sh
new file mode 100644
index 0000000000000000000000000000000000000000..ba7d7befa85af7390b5626d23a6278636dbcdeb5
--- /dev/null
+++ b/clean/video/mintime/cross-efficient-vit/efficient_net/tf_to_pytorch/pretrained_tensorflow/download.sh
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+
+
+# This script accepts a single command-line argument, which specifies which model to download.
+# Only the b0, b1, b2, and b3 models have been released, so your command must be one of them.
+
+# For example, to download efficientnet-b0, run:
+# ./download.sh efficientnet-b0
+# And to download efficientnet-b3, run:
+# ./download.sh efficientnet-b3
+
+MODEL=$1
+wget https://storage.googleapis.com/cloud-tpu-checkpoints/efficientnet/advprop/${MODEL}.tar.gz
+tar xvf ${MODEL}.tar.gz
+rm ${MODEL}.tar.gz
diff --git a/clean/video/mintime/cross-efficient-vit/test.py b/clean/video/mintime/cross-efficient-vit/test.py
new file mode 100644
index 0000000000000000000000000000000000000000..7f425df879e34657955973895b525dc160cccc86
--- /dev/null
+++ b/clean/video/mintime/cross-efficient-vit/test.py
@@ -0,0 +1,300 @@
+import matplotlib.pyplot as plt
+from sklearn import metrics
+from sklearn.metrics import auc
+from sklearn.metrics import accuracy_score
+from sklearn.metrics import f1_score
+
+import os
+import cv2
+import numpy as np
+import torch
+from torch import nn, einsum
+from sklearn.metrics import plot_confusion_matrix
+
+from utils import get_method, check_correct, resize, shuffle_dataset, get_n_params
+import torch.nn as nn
+import torch.nn.functional as F
+from functools import partial
+from cross_efficient_vit import CrossEfficientViT
+from utils import transform_frame
+import glob
+from os import cpu_count
+import json
+from multiprocessing.pool import Pool
+from progress.bar import Bar
+import pandas as pd
+from tqdm import tqdm
+from multiprocessing import Manager
+from utils import custom_round, custom_video_round
+from albumentations import Compose, RandomBrightnessContrast, \
+ HorizontalFlip, FancyPCA, HueSaturationValue, OneOf, ToGray, \
+ ShiftScaleRotate, ImageCompression, PadIfNeeded, GaussNoise, GaussianBlur, Rotate
+from transforms.albu import IsotropicResize
+import yaml
+import argparse
+
+#########################
+####### CONSTANTS #######
+#########################
+
+MODELS_DIR = "models"
+BASE_DIR = "../../deep_fakes"
+DATA_DIR = os.path.join(BASE_DIR, "dataset")
+TEST_DIR = os.path.join(DATA_DIR, "test_set")
+OUTPUT_DIR = os.path.join(MODELS_DIR, "tests")
+
+TEST_LABELS_PATH = os.path.join(BASE_DIR, "dataset/dfdc_test_labels.csv")
+
+#########################
+####### UTILITIES #######
+#########################
+
+def save_confusion_matrix(confusion_matrix):
+ fig, ax = plt.subplots()
+ im = ax.imshow(confusion_matrix, cmap="Blues")
+
+ threshold = im.norm(confusion_matrix.max())/2.
+ textcolors=("black", "white")
+
+ ax.set_xticks(np.arange(2))
+ ax.set_yticks(np.arange(2))
+ ax.set_xticklabels(["original", "fake"])
+ ax.set_yticklabels(["original", "fake"])
+
+ ax.tick_params(top=True, bottom=False, labeltop=True, labelbottom=False)
+
+ for i in range(2):
+ for j in range(2):
+ text = ax.text(j, i, confusion_matrix[i, j], ha="center", va="center",
+ fontsize=12, color=textcolors[int(im.norm(confusion_matrix[i, j]) > threshold)])
+
+ fig.tight_layout()
+ plt.savefig(os.path.join(OUTPUT_DIR, "confusion.jpg"))
+
+
+def save_roc_curves(correct_labels, preds, model_name, accuracy, loss, f1):
+ plt.figure(1)
+ plt.plot([0, 1], [0, 1], 'k--')
+
+ fpr, tpr, th = metrics.roc_curve(correct_labels, preds)
+
+ model_auc = auc(fpr, tpr)
+
+
+ plt.plot(fpr, tpr, label="Model_"+ model_name + ' (area = {:.3f})'.format(model_auc))
+
+ plt.xlabel('False positive rate')
+ plt.ylabel('True positive rate')
+ plt.title('ROC curve')
+ plt.legend(loc='best')
+ plt.savefig(os.path.join(OUTPUT_DIR, model_name + "_" + opt.dataset + "_acc" + str(accuracy*100) + "_loss"+str(loss)+"_f1"+str(f1)+".jpg"))
+ plt.clf()
+
+
+def read_frames(video_path, videos):
+
+ # Get the video label based on dataset selected
+ method = get_method(video_path, DATA_DIR)
+ if "Original" in video_path:
+ label = 0.
+ elif method == "DFDC":
+ test_df = pd.DataFrame(pd.read_csv(TEST_LABELS_PATH))
+ video_folder_name = os.path.basename(video_path)
+ video_key = video_folder_name + ".mp4"
+ label = test_df.loc[test_df['filename'] == video_key]['label'].values[0]
+ else:
+ label = 1.
+
+
+ # Calculate the interval to extract the frames
+ frames_number = len(os.listdir(video_path))
+ frames_interval = int(frames_number / opt.frames_per_video)
+ frames_paths = os.listdir(video_path)
+ frames_paths_dict = {}
+
+ # Group the faces with the same index, reduce probabiity to skip some faces in the same video
+
+ for path in frames_paths:
+ for i in range(0,3): # Consider up to 3 faces per video
+ if "_" + str(i) in path:
+ if i not in frames_paths_dict.keys():
+ frames_paths_dict[i] = [path]
+ else:
+ frames_paths_dict[i].append(path)
+
+ # Select only the frames at a certain interval
+ if frames_interval > 0:
+ for key in frames_paths_dict.keys():
+ if len(frames_paths_dict) > frames_interval:
+ frames_paths_dict[key] = frames_paths_dict[key][::frames_interval]
+
+ frames_paths_dict[key] = frames_paths_dict[key][:opt.frames_per_video]
+
+ # Select N frames from the collected ones
+ video = {}
+ for key in frames_paths_dict.keys():
+ for index, frame_image in enumerate(frames_paths_dict[key]):
+ transform = create_base_transform(config['model']['image-size'])
+ image = transform(image=cv2.imread(os.path.join(video_path, frame_image)))['image']
+ if len(image) > 0:
+ if key in video:
+ video[key].append(image)
+ else:
+ video[key] = [image]
+ videos.append((video, label, video_path))
+
+
+def create_base_transform(size):
+ return Compose([
+ IsotropicResize(max_side=size, interpolation_down=cv2.INTER_AREA, interpolation_up=cv2.INTER_CUBIC),
+ PadIfNeeded(min_height=size, min_width=size, border_mode=cv2.BORDER_CONSTANT),
+ ])
+
+#########################
+####### MODEL #######
+#########################
+
+
+# Main body
+if __name__ == "__main__":
+
+ parser = argparse.ArgumentParser()
+
+ parser.add_argument('--workers', default=10, type=int,
+ help='Number of data loader workers.')
+ parser.add_argument('--model_path', default='', type=str, metavar='PATH',
+ help='Path to model checkpoint (default: none).')
+ parser.add_argument('--dataset', type=str, default='DFDC',
+ help="Which dataset to use (Deepfakes|Face2Face|FaceShifter|FaceSwap|NeuralTextures|DFDC)")
+ parser.add_argument('--max_videos', type=int, default=-1,
+ help="Maximum number of videos to use for training (default: all).")
+ parser.add_argument('--config', type=str,
+ help="Which configuration to use. See into 'config' folder.")
+ parser.add_argument('--efficient_net', type=int, default=0,
+ help="Which EfficientNet version to use (0 or 7, default: 0)")
+ parser.add_argument('--frames_per_video', type=int, default=30,
+ help="How many equidistant frames for each video (default: 30)")
+ parser.add_argument('--batch_size', type=int, default=32,
+ help="Batch size (default: 32)")
+
+ opt = parser.parse_args()
+ print(opt)
+
+ with open(opt.config, 'r') as ymlfile:
+ config = yaml.safe_load(ymlfile)
+
+
+ if os.path.exists(opt.model_path):
+ model = CrossEfficientViT(config=config)
+ model.load_state_dict(torch.load(opt.model_path))
+ model.eval()
+ model = model.cuda()
+ else:
+ print("No model found.")
+ exit()
+
+ model_name = os.path.basename(opt.model_path)
+
+
+ #########################
+ ####### EXECUTION #######
+ #########################
+
+
+ OUTPUT_DIR = os.path.join(OUTPUT_DIR, opt.dataset)
+
+ if not os.path.exists(OUTPUT_DIR):
+ os.makedirs(OUTPUT_DIR)
+
+
+
+ NUM_CLASSES = 1
+ preds = []
+
+ mgr = Manager()
+ paths = []
+ videos = mgr.list()
+
+ if opt.dataset != "DFDC":
+ folders = ["Original", opt.dataset]
+ else:
+ folders = [opt.dataset]
+
+ # Read all videos paths
+ for folder in folders:
+ method_folder = os.path.join(TEST_DIR, folder)
+ for index, video_folder in enumerate(os.listdir(method_folder)):
+ paths.append(os.path.join(method_folder, video_folder))
+
+ # Read faces
+ with Pool(processes=cpu_count()-1) as p:
+ with tqdm(total=len(paths)) as pbar:
+ for v in p.imap_unordered(partial(read_frames, videos=videos),paths):
+ pbar.update()
+
+ video_names = np.asarray([row[2] for row in videos])
+ correct_test_labels = np.asarray([row[1] for row in videos])
+ videos = np.asarray([row[0] for row in videos])
+ preds = []
+
+
+ # Perform prediction
+ bar = Bar('Predicting', max=len(videos))
+
+ f = open(opt.dataset + "_" + model_name + "_labels.txt", "w+")
+ for index, video in enumerate(videos):
+ video_faces_preds = []
+ video_name = video_names[index]
+ f.write(video_name)
+ for key in video:
+ faces_preds = []
+ video_faces = video[key]
+ for i in range(0, len(video_faces), opt.batch_size):
+ faces = video_faces[i:i+opt.batch_size]
+ faces = torch.tensor(np.asarray(faces))
+ if faces.shape[0] == 0:
+ continue
+ faces = np.transpose(faces, (0, 3, 1, 2))
+ faces = faces.cuda().float()
+
+ pred = model(faces)
+
+ scaled_pred = []
+ for idx, p in enumerate(pred):
+ scaled_pred.append(torch.sigmoid(p))
+ faces_preds.extend(scaled_pred)
+
+ current_faces_pred = sum(faces_preds)/len(faces_preds)
+ face_pred = current_faces_pred.cpu().detach().numpy()[0]
+ f.write(" " + str(face_pred))
+ video_faces_preds.append(face_pred)
+ bar.next()
+ if len(video_faces_preds) > 1:
+ video_pred = custom_video_round(video_faces_preds)
+ else:
+ video_pred = video_faces_preds[0]
+ preds.append([video_pred])
+
+ f.write(" --> " + str(video_pred) + "(CORRECT: " + str(correct_test_labels[index]) + ")" +"\n")
+
+ f.close()
+ bar.finish()
+
+
+ #########################
+ ####### METRICS #######
+ #########################
+
+ loss_fn = torch.nn.BCEWithLogitsLoss()
+ tensor_labels = torch.tensor([[float(label)] for label in correct_test_labels])
+ tensor_preds = torch.tensor(preds)
+
+
+ loss = loss_fn(tensor_preds, tensor_labels).numpy()
+
+ #accuracy = accuracy_score(np.asarray(preds).round(), correct_test_labels) # Classic way
+ accuracy = accuracy_score(custom_round(np.asarray(preds)), correct_test_labels) # Custom way
+ f1 = f1_score(correct_test_labels, custom_round(np.asarray(preds)))
+ print(model_name, "Test Accuracy:", accuracy, "Loss:", loss, "F1", f1)
+ save_roc_curves(correct_test_labels, preds, model_name, accuracy, loss, f1)
+ save_confusion_matrix(metrics.confusion_matrix(correct_test_labels,custom_round(np.asarray(preds))))
diff --git a/clean/video/mintime/cross-efficient-vit/train.py b/clean/video/mintime/cross-efficient-vit/train.py
new file mode 100644
index 0000000000000000000000000000000000000000..bc0b6b0f1687f7a80029fac0cfba1832161387ec
--- /dev/null
+++ b/clean/video/mintime/cross-efficient-vit/train.py
@@ -0,0 +1,322 @@
+import torch
+from torch.utils.data import DataLoader, TensorDataset, Dataset
+from einops import rearrange, repeat
+from torch import nn, einsum
+import torch.nn as nn
+import torch.nn.functional as F
+from random import random, randint, choice
+from vit_pytorch import ViT
+import numpy as np
+import os
+import json
+from multiprocessing.pool import Pool
+from functools import partial
+from multiprocessing import Manager
+from progress.bar import ChargingBar
+from cross_efficient_vit import CrossEfficientViT
+import uuid
+from torch.utils.data import DataLoader, TensorDataset, Dataset
+from sklearn.metrics import accuracy_score
+import cv2
+from transforms.albu import IsotropicResize
+import glob
+import pandas as pd
+from tqdm import tqdm
+from utils import get_method, check_correct, resize, shuffle_dataset, get_n_params
+from sklearn.utils.class_weight import compute_class_weight
+from torch.optim import lr_scheduler
+import collections
+from deepfakes_dataset import DeepFakesDataset
+import math
+import yaml
+import argparse
+
+BASE_DIR = '../../deep_fakes/'
+DATA_DIR = os.path.join(BASE_DIR, "dataset")
+TRAINING_DIR = os.path.join(DATA_DIR, "training_set")
+VALIDATION_DIR = os.path.join(DATA_DIR, "validation_set")
+TEST_DIR = os.path.join(DATA_DIR, "test_set")
+MODELS_PATH = "models"
+METADATA_PATH = os.path.join(BASE_DIR, "data/metadata") # Folder containing all training metadata for DFDC dataset
+VALIDATION_LABELS_PATH = os.path.join(DATA_DIR, "dfdc_val_labels.csv")
+
+
+def read_frames(video_path, train_dataset, validation_dataset):
+
+ # Get the video label based on dataset selected
+ method = get_method(video_path, DATA_DIR)
+ if TRAINING_DIR in video_path:
+ if "Original" in video_path:
+ label = 0.
+ elif "DFDC" in video_path:
+ for json_path in glob.glob(os.path.join(METADATA_PATH, "*.json")):
+ with open(json_path, "r") as f:
+ metadata = json.load(f)
+ video_folder_name = os.path.basename(video_path)
+ video_key = video_folder_name + ".mp4"
+ if video_key in metadata.keys():
+ item = metadata[video_key]
+ label = item.get("label", None)
+ if label == "FAKE":
+ label = 1.
+ else:
+ label = 0.
+ break
+ else:
+ label = None
+ else:
+ label = 1.
+ if label == None:
+ print("NOT FOUND", video_path)
+ else:
+ if "Original" in video_path:
+ label = 0.
+ elif "DFDC" in video_path:
+ val_df = pd.DataFrame(pd.read_csv(VALIDATION_LABELS_PATH))
+ video_folder_name = os.path.basename(video_path)
+ video_key = video_folder_name + ".mp4"
+ label = val_df.loc[val_df['filename'] == video_key]['label'].values[0]
+ else:
+ label = 1.
+
+ # Calculate the interval to extract the frames
+ frames_number = len(os.listdir(video_path))
+ if label == 0:
+ min_video_frames = max(int(config['training']['frames-per-video'] * config['training']['rebalancing-real']),1) # Compensate unbalancing
+ else:
+ min_video_frames = max(int(config['training']['frames-per-video'] * config['training']['rebalancing-fake']),1)
+
+
+
+ if VALIDATION_DIR in video_path:
+ min_video_frames = int(max(min_video_frames/8, 2))
+ frames_interval = int(frames_number / min_video_frames)
+ frames_paths = os.listdir(video_path)
+ frames_paths_dict = {}
+
+ # Group the faces with the same index, reduce probabiity to skip some faces in the same video
+ for path in frames_paths:
+ for i in range(0,1):
+ if "_" + str(i) in path:
+ if i not in frames_paths_dict.keys():
+ frames_paths_dict[i] = [path]
+ else:
+ frames_paths_dict[i].append(path)
+ # Select only the frames at a certain interval
+ if frames_interval > 0:
+ for key in frames_paths_dict.keys():
+ if len(frames_paths_dict) > frames_interval:
+ frames_paths_dict[key] = frames_paths_dict[key][::frames_interval]
+
+ frames_paths_dict[key] = frames_paths_dict[key][:min_video_frames]
+ # Select N frames from the collected ones
+ for key in frames_paths_dict.keys():
+ for index, frame_image in enumerate(frames_paths_dict[key]):
+ #image = transform(np.asarray(cv2.imread(os.path.join(video_path, frame_image))))
+ image = cv2.imread(os.path.join(video_path, frame_image))
+ if image is not None:
+ if TRAINING_DIR in video_path:
+ train_dataset.append((image, label))
+ else:
+ validation_dataset.append((image, label))
+
+# Main body
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--num_epochs', default=300, type=int,
+ help='Number of training epochs.')
+ parser.add_argument('--workers', default=10, type=int,
+ help='Number of data loader workers.')
+ parser.add_argument('--resume', default='', type=str, metavar='PATH',
+ help='Path to latest checkpoint (default: none).')
+ parser.add_argument('--dataset', type=str, default='All',
+ help="Which dataset to use (Deepfakes|Face2Face|FaceShifter|FaceSwap|NeuralTextures|All)")
+ parser.add_argument('--max_videos', type=int, default=-1,
+ help="Maximum number of videos to use for training (default: all).")
+ parser.add_argument('--config', type=str,
+ help="Which configuration to use. See into 'config' folder.")
+ parser.add_argument('--efficient_net', type=int, default=0,
+ help="Which EfficientNet version to use (0 or 7, default: 0)")
+ parser.add_argument('--patience', type=int, default=5,
+ help="How many epochs wait before stopping for validation loss not improving.")
+
+ opt = parser.parse_args()
+ print(opt)
+
+ with open(opt.config, 'r') as ymlfile:
+ config = yaml.safe_load(ymlfile)
+
+ model = CrossEfficientViT(config=config)
+ model.train()
+
+ optimizer = torch.optim.SGD(model.parameters(), lr=config['training']['lr'], weight_decay=config['training']['weight-decay'])
+ scheduler = lr_scheduler.StepLR(optimizer, step_size=config['training']['step-size'], gamma=config['training']['gamma'])
+ starting_epoch = 0
+ if os.path.exists(opt.resume):
+ model.load_state_dict(torch.load(opt.resume))
+ starting_epoch = int(opt.resume.split("checkpoint")[1].split("_")[0]) + 1
+ else:
+ print("No checkpoint loaded.")
+
+
+ print("Model Parameters:", get_n_params(model))
+
+ #READ DATASET
+ if opt.dataset != "All":
+ folders = ["Original", opt.dataset]
+ else:
+ folders = ["Original", "DFDC", "Deepfakes", "Face2Face", "FaceShifter", "FaceSwap", "NeuralTextures"]
+
+ sets = [TRAINING_DIR, VALIDATION_DIR]
+
+ paths = []
+ for dataset in sets:
+ for folder in folders:
+ subfolder = os.path.join(dataset, folder)
+ for index, video_folder_name in enumerate(os.listdir(subfolder)):
+ if index == opt.max_videos:
+ break
+ if os.path.isdir(os.path.join(subfolder, video_folder_name)):
+ paths.append(os.path.join(subfolder, video_folder_name))
+
+
+ mgr = Manager()
+ train_dataset = mgr.list()
+ validation_dataset = mgr.list()
+
+ with Pool(processes=10) as p:
+ with tqdm(total=len(paths)) as pbar:
+ for v in p.imap_unordered(partial(read_frames, train_dataset=train_dataset, validation_dataset=validation_dataset),paths):
+ pbar.update()
+ train_samples = len(train_dataset)
+ train_dataset = shuffle_dataset(train_dataset)
+ validation_samples = len(validation_dataset)
+ validation_dataset = shuffle_dataset(validation_dataset)
+
+ # Print some useful statistics
+ print("Train images:", len(train_dataset), "Validation images:", len(validation_dataset))
+ print("__TRAINING STATS__")
+ train_counters = collections.Counter(image[1] for image in train_dataset)
+ print(train_counters)
+
+ class_weights = train_counters[0] / train_counters[1]
+ print("Weights", class_weights)
+
+ print("__VALIDATION STATS__")
+ val_counters = collections.Counter(image[1] for image in validation_dataset)
+ print(val_counters)
+ print("___________________")
+
+ loss_fn = torch.nn.BCEWithLogitsLoss(pos_weight=torch.tensor([class_weights]))
+
+ # Create the data loaders
+ validation_labels = np.asarray([row[1] for row in validation_dataset])
+ labels = np.asarray([row[1] for row in train_dataset])
+
+ train_dataset = DeepFakesDataset(np.asarray([row[0] for row in train_dataset]), labels, config['model']['image-size'])
+ dl = torch.utils.data.DataLoader(train_dataset, batch_size=config['training']['bs'], shuffle=True, sampler=None,
+ batch_sampler=None, num_workers=opt.workers, collate_fn=None,
+ pin_memory=False, drop_last=False, timeout=0,
+ worker_init_fn=None, prefetch_factor=2,
+ persistent_workers=False)
+ del train_dataset
+
+ validation_dataset = DeepFakesDataset(np.asarray([row[0] for row in validation_dataset]), validation_labels, config['model']['image-size'], mode='validation')
+ val_dl = torch.utils.data.DataLoader(validation_dataset, batch_size=config['training']['bs'], shuffle=True, sampler=None,
+ batch_sampler=None, num_workers=opt.workers, collate_fn=None,
+ pin_memory=False, drop_last=False, timeout=0,
+ worker_init_fn=None, prefetch_factor=2,
+ persistent_workers=False)
+ del validation_dataset
+
+
+ model = model.cuda()
+ counter = 0
+ not_improved_loss = 0
+ previous_loss = math.inf
+ for t in range(starting_epoch, opt.num_epochs + 1):
+ if not_improved_loss == opt.patience:
+ break
+ counter = 0
+
+ total_loss = 0
+ total_val_loss = 0
+
+ bar = ChargingBar('EPOCH #' + str(t), max=(len(dl)*config['training']['bs'])+len(val_dl))
+ train_correct = 0
+ positive = 0
+ negative = 0
+ for index, (images, labels) in enumerate(dl):
+ images = np.transpose(images, (0, 3, 1, 2))
+ labels = labels.unsqueeze(1)
+ images = images.cuda()
+
+ y_pred = model(images)
+ y_pred = y_pred.cpu()
+ loss = loss_fn(y_pred, labels)
+
+ corrects, positive_class, negative_class = check_correct(y_pred, labels)
+ train_correct += corrects
+ positive += positive_class
+ negative += negative_class
+ optimizer.zero_grad()
+
+ loss.backward()
+
+ optimizer.step()
+ counter += 1
+ total_loss += round(loss.item(), 2)
+ for i in range(config['training']['bs']):
+ bar.next()
+
+
+ if index%1200 == 0:
+ print("\nLoss: ", total_loss/counter, "Accuracy: ",train_correct/(counter*config['training']['bs']) ,"Train 0s: ", negative, "Train 1s:", positive)
+
+
+ val_counter = 0
+ val_correct = 0
+ val_positive = 0
+ val_negative = 0
+
+ train_correct /= train_samples
+ total_loss /= counter
+ for index, (val_images, val_labels) in enumerate(val_dl):
+
+ val_images = np.transpose(val_images, (0, 3, 1, 2))
+
+ val_images = val_images.cuda()
+ val_labels = val_labels.unsqueeze(1)
+ val_pred = model(val_images)
+ val_pred = val_pred.cpu()
+ val_loss = loss_fn(val_pred, val_labels)
+ total_val_loss += round(val_loss.item(), 2)
+ corrects, positive_class, negative_class = check_correct(val_pred, val_labels)
+ val_correct += corrects
+ val_positive += positive_class
+ val_negative += negative_class
+ val_counter += 1
+ bar.next()
+
+ scheduler.step()
+ bar.finish()
+
+
+ total_val_loss /= val_counter
+ val_correct /= validation_samples
+ if previous_loss <= total_val_loss:
+ print("Validation loss did not improved")
+ not_improved_loss += 1
+ else:
+ not_improved_loss = 0
+
+ previous_loss = total_val_loss
+ print("#" + str(t) + "/" + str(opt.num_epochs) + " loss:" +
+ str(total_loss) + " accuracy:" + str(train_correct) +" val_loss:" + str(total_val_loss) + " val_accuracy:" + str(val_correct) + " val_0s:" + str(val_negative) + "/" + str(np.count_nonzero(validation_labels == 0)) + " val_1s:" + str(val_positive) + "/" + str(np.count_nonzero(validation_labels == 1)))
+
+
+ if not os.path.exists(MODELS_PATH):
+ os.makedirs(MODELS_PATH)
+ torch.save(model.state_dict(), os.path.join(MODELS_PATH, "efficientnet_checkpoint" + str(t) + "_" + opt.dataset))
+
+
diff --git a/clean/video/mintime/cross-efficient-vit/transforms/albu.py b/clean/video/mintime/cross-efficient-vit/transforms/albu.py
new file mode 100644
index 0000000000000000000000000000000000000000..e08dc172ccd2db6a858ae9395699e45854f47212
--- /dev/null
+++ b/clean/video/mintime/cross-efficient-vit/transforms/albu.py
@@ -0,0 +1,102 @@
+import random
+
+import cv2
+import numpy as np
+from albumentations import DualTransform, ImageOnlyTransform
+from albumentations.augmentations.functional import crop
+
+
+def isotropically_resize_image(img, size, interpolation_down=cv2.INTER_AREA, interpolation_up=cv2.INTER_CUBIC):
+ h, w = img.shape[:2]
+
+ if max(w, h) == size:
+ return img
+ if w > h:
+ scale = size / w
+ h = h * scale
+ w = size
+ else:
+ scale = size / h
+ w = w * scale
+ h = size
+ interpolation = interpolation_up if scale > 1 else interpolation_down
+
+ img = img.astype('uint8')
+ resized = cv2.resize(img, (int(w), int(h)), interpolation=interpolation)
+ return resized
+
+
+class IsotropicResize(DualTransform):
+ def __init__(self, max_side, interpolation_down=cv2.INTER_AREA, interpolation_up=cv2.INTER_CUBIC,
+ always_apply=False, p=1):
+ super(IsotropicResize, self).__init__(always_apply, p)
+ self.max_side = max_side
+ self.interpolation_down = interpolation_down
+ self.interpolation_up = interpolation_up
+
+ def apply(self, img, interpolation_down=cv2.INTER_AREA, interpolation_up=cv2.INTER_CUBIC, **params):
+ return isotropically_resize_image(img, size=self.max_side, interpolation_down=interpolation_down,
+ interpolation_up=interpolation_up)
+
+ def apply_to_mask(self, img, **params):
+ return self.apply(img, interpolation_down=cv2.INTER_NEAREST, interpolation_up=cv2.INTER_NEAREST, **params)
+
+ def get_transform_init_args_names(self):
+ return ("max_side", "interpolation_down", "interpolation_up")
+
+
+class Resize4xAndBack(ImageOnlyTransform):
+ def __init__(self, always_apply=False, p=0.5):
+ super(Resize4xAndBack, self).__init__(always_apply, p)
+
+ def apply(self, img, **params):
+ h, w = img.shape[:2]
+ scale = random.choice([2, 4])
+ img = cv2.resize(img, (w // scale, h // scale), interpolation=cv2.INTER_AREA)
+ img = cv2.resize(img, (w, h),
+ interpolation=random.choice([cv2.INTER_CUBIC, cv2.INTER_LINEAR, cv2.INTER_NEAREST]))
+ return img
+
+
+class RandomSizedCropNonEmptyMaskIfExists(DualTransform):
+
+ def __init__(self, min_max_height, w2h_ratio=[0.7, 1.3], always_apply=False, p=0.5):
+ super(RandomSizedCropNonEmptyMaskIfExists, self).__init__(always_apply, p)
+
+ self.min_max_height = min_max_height
+ self.w2h_ratio = w2h_ratio
+
+ def apply(self, img, x_min=0, x_max=0, y_min=0, y_max=0, **params):
+ cropped = crop(img, x_min, y_min, x_max, y_max)
+ return cropped
+
+ @property
+ def targets_as_params(self):
+ return ["mask"]
+
+ def get_params_dependent_on_targets(self, params):
+ mask = params["mask"]
+ mask_height, mask_width = mask.shape[:2]
+ crop_height = int(mask_height * random.uniform(self.min_max_height[0], self.min_max_height[1]))
+ w2h_ratio = random.uniform(*self.w2h_ratio)
+ crop_width = min(int(crop_height * w2h_ratio), mask_width - 1)
+ if mask.sum() == 0:
+ x_min = random.randint(0, mask_width - crop_width + 1)
+ y_min = random.randint(0, mask_height - crop_height + 1)
+ else:
+ mask = mask.sum(axis=-1) if mask.ndim == 3 else mask
+ non_zero_yx = np.argwhere(mask)
+ y, x = random.choice(non_zero_yx)
+ x_min = x - random.randint(0, crop_width - 1)
+ y_min = y - random.randint(0, crop_height - 1)
+ x_min = np.clip(x_min, 0, mask_width - crop_width)
+ y_min = np.clip(y_min, 0, mask_height - crop_height)
+
+ x_max = x_min + crop_height
+ y_max = y_min + crop_width
+ y_max = min(mask_height, y_max)
+ x_max = min(mask_width, x_max)
+ return {"x_min": x_min, "x_max": x_max, "y_min": y_min, "y_max": y_max}
+
+ def get_transform_init_args_names(self):
+ return "min_max_height", "height", "width", "w2h_ratio"
\ No newline at end of file
diff --git a/clean/video/mintime/cross-efficient-vit/utils.py b/clean/video/mintime/cross-efficient-vit/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..9f56891cb03ac324cab38ae76978275d9d51ba9e
--- /dev/null
+++ b/clean/video/mintime/cross-efficient-vit/utils.py
@@ -0,0 +1,85 @@
+import cv2
+from albumentations import Compose, PadIfNeeded
+from transforms.albu import IsotropicResize
+import numpy as np
+import os
+import cv2
+import torch
+from statistics import mean
+def transform_frame(image, image_size):
+ transform_pipeline = Compose([
+ IsotropicResize(max_side=image_size, interpolation_down=cv2.INTER_LINEAR, interpolation_up=cv2.INTER_LINEAR),
+ PadIfNeeded(min_height=image_size, min_width=image_size, border_mode=cv2.BORDER_REPLICATE)
+ ]
+ )
+ return transform_pipeline(image=image)['image']
+
+
+def resize(image, image_size):
+ try:
+ return cv2.resize(image, dsize=(image_size, image_size))
+ except:
+ return []
+
+def custom_round(values):
+ result = []
+ for value in values:
+ if value > 0.6:
+ result.append(1)
+ else:
+ result.append(0)
+ return np.asarray(result)
+
+
+
+def get_method(video, data_path):
+ methods = os.listdir(os.path.join(data_path, "manipulated_sequences"))
+ methods.extend(os.listdir(os.path.join(data_path, "original_sequences")))
+ methods.append("DFDC")
+ methods.append("Original")
+ selected_method = ""
+ for method in methods:
+ if method in video:
+ selected_method = method
+ break
+ return selected_method
+
+def shuffle_dataset(dataset):
+ import random
+ random.seed(4)
+ random.shuffle(dataset)
+ return dataset
+
+
+def get_n_params(model):
+ pp=0
+ for p in list(model.parameters()):
+ nn=1
+ for s in list(p.size()):
+ nn = nn*s
+ pp += nn
+ return pp
+
+def check_correct(preds, labels):
+ preds = preds.cpu()
+ labels = labels.cpu()
+ preds = [np.asarray(torch.sigmoid(pred).detach().numpy()).round() for pred in preds]
+
+ correct = 0
+ positive_class = 0
+ negative_class = 0
+ for i in range(len(labels)):
+ pred = int(preds[i])
+ if labels[i] == pred:
+ correct += 1
+ if pred == 1:
+ positive_class += 1
+ else:
+ negative_class += 1
+ return correct, positive_class, negative_class
+
+def custom_video_round(preds):
+ for pred_value in preds:
+ if pred_value > 0.55:
+ return pred_value
+ return mean(preds)
diff --git a/clean/video/mintime/deepfakes_dataset.py b/clean/video/mintime/deepfakes_dataset.py
new file mode 100644
index 0000000000000000000000000000000000000000..210afac364f93648610d4976c38e6a1758c2d88e
--- /dev/null
+++ b/clean/video/mintime/deepfakes_dataset.py
@@ -0,0 +1,345 @@
+# DeepFakesDataset class used for data loading
+# In this step the identities are also refined and organized in order to fit into the available number of frames per video.
+# The data augmentation is also applied to each face extracted from the video and several embeddings and masks are generated:
+# 1. The Size Embedding, responsible to induct the information about face-frame area ratio of each face to the model.
+# 2. The Temporal Positional Embedding, responsible to maintain a coherent spatial and temporal positional information of the input tokens
+# 3. The Mask, responsible to make the model ignore the "empty faces" added to fill wholes in the input sequence, if occur
+# 4. The Identity Mask, used to tell the model each face to which identity it corresponds
+
+import torch
+from torch.utils.data import DataLoader, TensorDataset, Dataset
+import cv2
+import random
+import numpy as np
+from datetime import datetime
+import os
+import magic
+from albumentations import Cutout, CoarseDropout, RandomGamma, MedianBlur, ToSepia, RandomShadow, MultiplicativeNoise, RandomSunFlare, GlassBlur, RandomBrightness, MotionBlur, RandomRain, RGBShift, RandomFog, RandomContrast, Downscale, InvertImg, RandomContrast, ColorJitter, Compose, RandomBrightnessContrast, CLAHE, ISONoise, JpegCompression, HorizontalFlip, FancyPCA, HueSaturationValue, OneOf, ToGray, ShiftScaleRotate, ImageCompression, PadIfNeeded, GaussNoise, GaussianBlur, Rotate, Normalize, Resize
+from PIL import Image
+from transforms.albu import IsotropicResize
+from concurrent.futures import ThreadPoolExecutor
+from os import cpu_count
+import re
+import cv2
+from itertools import compress
+from statistics import mean
+
+
+ORIGINAL_VIDEOS_PATH = {"train": "../datasets/ForgeryNet/Training/video/train_video_release", "val": "../datasets/ForgeryNet/Training/video/train_video_release", "test": "../datasets/ForgeryNet/Validation/video/val_video_release"}
+MODES = ["train", "val", "test"]
+RANGE_SIZE = 5
+SIZE_EMB_DICT = [(1+i*RANGE_SIZE, (i+1)*RANGE_SIZE) if i != 0 else (0, RANGE_SIZE) for i in range(20)]
+
+class DeepFakesDataset(Dataset):
+ def __init__(self, videos_paths, labels, data_path, video_path, image_size, augmentation = None, multiclass_labels = None, save_attention_plots = False, mode = 'train', model = 0, num_frames = 8, max_identities = 3, num_patches=49, enable_identity_attention = True, identities_ordering = 0):
+ self.x = videos_paths
+ self.y = labels
+ self.multiclass_labels = multiclass_labels
+ self.save_attention_plots = save_attention_plots
+ self.data_path = data_path
+ self.video_path = video_path
+ self.image_size = image_size
+ if mode not in MODES:
+ raise Exception("Invalid dataloader mode.")
+ self.mode = mode
+ self.n_samples = len(videos_paths)
+ self.num_frames = num_frames
+ self.num_patches = num_patches
+ self.max_identities = max_identities
+ self.augmentation = augmentation
+ self.max_faces_per_identity = {1: [num_frames],
+ 2: [int(num_frames/2), int(num_frames/2)],
+ 3: [int(num_frames/3), int(num_frames/3), int(num_frames/4)],
+ 4: [int(num_frames/3), int(num_frames/3), int(num_frames/8), int(num_frames/8)]}
+ self.enable_identity_attention = enable_identity_attention
+ self.identities_ordering = identities_ordering
+
+ def create_train_transforms(self, size, additional_targets, augmentation):
+ if augmentation == "min":
+ return Compose([
+ OneOf([
+ IsotropicResize(max_side=size, interpolation_down=cv2.INTER_AREA, interpolation_up=cv2.INTER_CUBIC),
+ IsotropicResize(max_side=size, interpolation_down=cv2.INTER_AREA, interpolation_up=cv2.INTER_LINEAR),
+ IsotropicResize(max_side=size, interpolation_down=cv2.INTER_LINEAR, interpolation_up=cv2.INTER_LINEAR),
+ ], p=1),
+ PadIfNeeded(min_height=size, min_width=size, border_mode=cv2.BORDER_CONSTANT),
+ Resize(height=size, width=size),
+ ImageCompression(quality_lower=60, quality_upper=100, p=0.2),
+ GaussNoise(p=0.3),
+ GaussianBlur(blur_limit=3, p=0.05),
+ HorizontalFlip(),
+ OneOf([RandomBrightnessContrast(), FancyPCA(), HueSaturationValue()], p=0.4),
+ ToGray(p=0.2),
+ ShiftScaleRotate(shift_limit=0.1, scale_limit=0.2, rotate_limit=5, border_mode=cv2.BORDER_CONSTANT, p=0.5),
+ ], additional_targets = additional_targets
+ )
+ else:
+ return Compose([
+ OneOf([
+ IsotropicResize(max_side=size, interpolation_down=cv2.INTER_AREA, interpolation_up=cv2.INTER_CUBIC),
+ IsotropicResize(max_side=size, interpolation_down=cv2.INTER_AREA, interpolation_up=cv2.INTER_LINEAR),
+ IsotropicResize(max_side=size, interpolation_down=cv2.INTER_LINEAR, interpolation_up=cv2.INTER_LINEAR),
+ ], p=1),
+ PadIfNeeded(min_height=size, min_width=size, border_mode=cv2.BORDER_CONSTANT),
+ Resize(height=size, width=size),
+ ImageCompression(quality_lower=60, quality_upper=100, p=0.2),
+ OneOf([GaussianBlur(blur_limit=3), MedianBlur(), GlassBlur(), MotionBlur()], p=0.1),
+ OneOf([HorizontalFlip(), InvertImg()], p=0.5),
+ OneOf([RandomBrightnessContrast(), RandomContrast(), RandomBrightness(), FancyPCA(), HueSaturationValue()], p=0.5),
+ OneOf([RGBShift(), ColorJitter()], p=0.1),
+ OneOf([MultiplicativeNoise(), ISONoise(), GaussNoise()], p=0.3),
+ OneOf([Cutout(), CoarseDropout()], p=0.1),
+ OneOf([RandomFog(), RandomRain(), RandomSunFlare()], p=0.02),
+ RandomShadow(p=0.05),
+ RandomGamma(p=0.1),
+ CLAHE(p=0.05),
+ ToGray(p=0.2),
+ ToSepia(p=0.05),
+ ShiftScaleRotate(shift_limit=0.1, scale_limit=0.2, rotate_limit=5, border_mode=cv2.BORDER_CONSTANT, p=0.5),
+ ], additional_targets = additional_targets
+ )
+
+ def create_val_transform(self, size, additional_targets):
+ return Compose([
+ IsotropicResize(max_side=size, interpolation_down=cv2.INTER_AREA, interpolation_up=cv2.INTER_CUBIC),
+ PadIfNeeded(min_height=size, min_width=size, border_mode=cv2.BORDER_CONSTANT),
+ Resize(height=size, width=size)
+ ], additional_targets = additional_targets
+ )
+
+ # Input the identity path and return a row with path, size and number of faces available
+ def get_identity_information(self, identity):
+ faces = [os.path.join(identity, face) for face in os.listdir(identity)]
+ try:
+ mean_side = mean([int(re.search('(\d+) x (\d+)', magic.from_file(face)).groups()[0]) for face in faces])
+ except:
+ mean_side = 0
+
+ number_of_faces = len(faces)
+ return [identity, mean_side, number_of_faces]
+
+
+ # Returns the identities, size-based sorted, with the number of faces for each identity to be readed
+ def get_sorted_identities(self, video_path):
+ identities = [os.path.join(video_path, identity) for identity in os.listdir(video_path)]
+ sorted_identities = []
+ discarded_faces = []
+ for identity in identities:
+ if not os.path.isdir(identity): # The faces are not inside an identity folder but we save them to fill temporal wholes in identities if occurs
+ discarded_faces.append(identity)
+ continue
+
+ # Sort faces based on temporal order
+ sorted_identities.append(self.get_identity_information(identity))
+
+
+ # If no faces have been found, use the discarded faces
+ if len(sorted_identities) == 0:
+ sorted_identities.append(self.get_identity_information(os.path.dirname(discarded_faces[0])))
+ discarded_faces = []
+
+ # Sort identities
+ if self.identities_ordering == 0: # Based on faces size
+ sorted_identities = sorted(sorted_identities, key=lambda x:x[1], reverse=True)
+ elif self.identities_ordering == 1: # Based on identities length
+ sorted_identities = sorted(sorted_identities, key=lambda x:x[2], reverse=True)
+ else: # Random shuffle
+ random.shuffle(sorted_identities)
+
+ if len(sorted_identities) > self.max_identities:
+ sorted_identities = sorted_identities[:self.max_identities]
+
+ # Adjust the identities list faces number
+ identities_number = len(sorted_identities)
+ available_additional_faces = []
+ if identities_number > 1:
+ max_faces_per_identity = self.max_faces_per_identity[identities_number]
+ for i in range(identities_number):
+ if sorted_identities[i][2] < max_faces_per_identity[i] and i < identities_number - 1:
+ sorted_identities[i+1][2] += max_faces_per_identity[i] - sorted_identities[i][2]
+ available_additional_faces.append(0)
+ elif sorted_identities[i][2] > max_faces_per_identity[i]:
+ available_additional_faces.append(sorted_identities[i][2] - max_faces_per_identity[i])
+ sorted_identities[i][2] = max_faces_per_identity[i]
+ else:
+ available_additional_faces.append(0)
+
+ else: # If only one identity is in the video, all the frames are assigned to this identity
+ sorted_identities[0][2] = self.num_frames
+ available_additional_faces.append(0)
+
+ # Check if we found enough faces to fullfill the input sequence, otherwise go back and add some faces from previous identities
+ input_sequence_length = sum(faces for _, _, faces in sorted_identities)
+ if input_sequence_length < self.num_frames:
+ for i in range(identities_number):
+ needed_faces = self.num_frames - input_sequence_length
+ if available_additional_faces[i] > 0:
+ added_faces = min(available_additional_faces[i], needed_faces)
+ sorted_identities[i][2] += added_faces
+ input_sequence_length += added_faces
+ if input_sequence_length == self.num_frames:
+ break
+ # If not enough faces have been found, add some "dummy" images in the last identity
+ if input_sequence_length < self.num_frames:
+ needed_faces = self.num_frames - input_sequence_length
+ sorted_identities[-1][2] += needed_faces
+ input_sequence_length += needed_faces
+
+ return sorted_identities, discarded_faces
+
+
+ def __getitem__(self, index):
+ video_path = self.x[index]
+ video_path = os.path.join(self.data_path, video_path)
+ if self.mode not in video_path:
+ for mode in MODES:
+ if mode in video_path:
+ self.mode = mode
+ break
+
+ video_id = video_path.split(self.mode + os.path.sep)[1]
+
+ original_video_path = os.path.join(self.video_path, self.mode, video_id)
+ if ".mp4" not in original_video_path:
+ original_video_path += ".mp4"
+ if not os.path.exists(original_video_path) and self.mode == "val":
+ original_video_path = os.path.join(self.video_path, "train", video_id)
+
+
+
+ if not os.path.exists(original_video_path):
+ raise Exception("Invalid video path for video.", original_video_path)
+
+
+ identities, discarded_faces = self.get_sorted_identities(video_path)
+
+ mask = []
+ last_range_end = 0
+ sequence = []
+ size_embeddings = []
+
+ images_frames = []
+ for identity_index, identity in enumerate(identities):
+ identity_path = identity[0]
+ max_faces = identity[2]
+ identity_faces = [os.path.join(identity_path, face) for face in os.listdir(identity_path)]
+
+ # If no faces were considered for a frame during clustering, probably it is inside the discarded faces
+ if identity_index == 0 and len(discarded_faces) > 0:
+ frames = [int(os.path.basename(image_path).split("_")[0]) for image_path in identity_faces]
+ discarded_frames = [int(os.path.basename(image_path).split("_")[0]) for image_path in discarded_faces]
+ missing_frames = list(set(discarded_frames) - set(frames))
+ missing_faces = [discarded_faces[discarded_frames.index(missing_frame)] for missing_frame in missing_frames]
+
+ if len(missing_faces) > 0:
+ identity_faces = identity_faces + missing_faces # Add the missing faces to the identity
+
+ identity_faces = np.asarray(sorted(identity_faces, key=lambda x:int(os.path.basename(x).split("_")[0])))
+
+ # Select uniformly the frames in an alternate way
+ if len(identity_faces) > max_faces:
+ if index % 2:
+ idx = np.round(np.linspace(0, len(identity_faces) - 2, max_faces)).astype(int)
+ else:
+ idx = np.round(np.linspace(1, len(identity_faces) - 1, max_faces)).astype(int)
+
+ identity_faces = identity_faces[idx]
+
+ # Read all images files
+ identity_images = []
+ capture = cv2.VideoCapture(original_video_path)
+ width = capture.get(3)
+ height = capture.get(4)
+ video_area = width*height/2
+ identity_size_embeddings = []
+ for image_index, image_path in enumerate(identity_faces):
+ # Read face image
+ image = cv2.imread(image_path)
+
+ # Get face-frame area ratio for size embedding
+ face_area = image.shape[0] * image.shape[1] / 2
+ ratio = int(face_area * 100 / video_area)
+ side_ranges = list(map(lambda a_: ratio in range(a_[0], a_[1] + 1), SIZE_EMB_DICT))
+ identity_size_embeddings.append(np.where(side_ranges)[0][0]+1)
+
+ # Read the frame number associated with the image in order to generate the correct temporal-positional embedding
+ frame = int(os.path.basename(image_path).split("_")[0])
+ images_frames.append(frame)
+
+ # Append the image to the list of readed images
+ identity_images.append(image)
+
+
+ # If the readed faces are less than max_faces we need to add empty images and generate the mask
+ if len(identity_images) < max_faces:
+ diff = max_faces - len(identity_size_embeddings)
+ identity_size_embeddings = np.concatenate((identity_size_embeddings, np.zeros(diff)))
+ identity_images.extend([np.zeros((self.image_size, self.image_size, 3), dtype=np.uint8) for i in range(diff)])
+ try:
+ images_frames.extend([max(images_frames) for i in range(diff)])
+ except:
+ print("Error", original_video_path)
+ images_frames.extend([0 for i in range(diff)])
+
+ if self.enable_identity_attention and len(identity_images) < max_faces: # Calculate attention only between faces of the same identity
+ mask.extend([1 if i < max_faces - diff else 0 for i in range(max_faces)])
+ else: # Otherwise all the faces are valid
+ mask.extend([1 for i in range(max_faces)])
+
+ # Compose the size_embedding and sequence list
+ size_embeddings.extend(identity_size_embeddings)
+ sequence.extend(identity_images)
+
+ # Transform the images for data augmentation, the same transformation is applied to all the faces in the same video
+ additional_targets_keys = ["image" + str(i) for i in range(self.num_frames)]
+ additional_targets_values = ["image" for i in range(self.num_frames)]
+ additional_targets = dict(zip(additional_targets_keys, additional_targets_values))
+
+ if self.mode == 'train':
+ transform = self.create_train_transforms(self.image_size, additional_targets, self.augmentation)
+ else:
+ transform = self.create_val_transform(self.image_size, additional_targets)
+
+ if len(sequence) == 8:
+ transformed_images = transform(image=sequence[0], image1=sequence[1], image2=sequence[2], image3=sequence[3], image4=sequence[4], image5=sequence[5], image6=sequence[6], image7=sequence[7])
+ elif len(sequence) == 16:
+ transformed_images = transform(image=sequence[0], image1=sequence[1], image2=sequence[2], image3=sequence[3], image4=sequence[4], image5=sequence[5], image6=sequence[6], image7=sequence[7], image8=sequence[8], image9=sequence[9], image10=sequence[10], image11=sequence[11], image12=sequence[12], image13=sequence[13], image14=sequence[14], image15=sequence[15])
+ elif len(sequence) == 32:
+ transformed_images = transform(image=sequence[0], image1=sequence[1], image2=sequence[2], image3=sequence[3], image4=sequence[4], image5=sequence[5], image6=sequence[6], image7=sequence[7], image8=sequence[8], image9=sequence[9], image10=sequence[10], image11=sequence[11], image12=sequence[12], image13=sequence[13], image14=sequence[14], image15=sequence[15], image16=sequence[16], image17=sequence[17], image18=sequence[18], image19=sequence[19], image20=sequence[20], image21=sequence[21], image22=sequence[22], image23=sequence[23], image24=sequence[24], image25=sequence[25], image26=sequence[26], image27=sequence[27], image28=sequence[28], image29=sequence[29], image30=sequence[30], image31=sequence[31])
+ else:
+ raise Exception("Invalid number of frames.")
+
+ sequence = [transformed_images[key] for key in transformed_images]
+
+ # Generate the identities_mask telling to the model which faces attend to an identity and which to another one
+ identities_mask = []
+ last_range_end = 0
+ for identity_index in range(len(identities)):
+ identity_mask = [True if i >= last_range_end and i < last_range_end + identities[identity_index][2] else False for i in range(0, self.num_frames)]
+ for k in range(identities[identity_index][2]):
+ identities_mask.append(identity_mask)
+ last_range_end += identities[identity_index][2]
+
+ # Generate coherent temporal-positional embedding
+ images_frames_positions = {k: v+1 for v, k in enumerate(sorted(set(images_frames)))}
+ frame_positions = [images_frames_positions[frame] for frame in images_frames]
+ if self.num_patches is not None:
+ positions = [[i+1 for i in range(((frame_position-1)*self.num_patches), self.num_patches*(frame_position))] for frame_position in frame_positions]
+ positions = sum(positions, []) # Merge the lists
+ positions.insert(0,0) # Add CLS
+ tokens_per_identity = [(os.path.basename(identities[i][0]), identities[i][2]*self.num_patches + identities[i-1][2]*self.num_patches) if i > 0 else (os.path.basename(identities[i][0]), identities[i][2]*self.num_patches) for i in range(len(identities))]
+ else:
+ positions = []
+ tokens_per_identity = []
+
+ if self.save_attention_plots == False:
+ tokens_per_identity = []
+
+ if self.multiclass_labels == None:
+ return torch.tensor(sequence).float(), torch.tensor(size_embeddings).int(), torch.tensor(mask).bool(), torch.tensor(identities_mask).bool(), torch.tensor(positions), self.y[index]
+ else:
+ return torch.tensor(sequence).float(), torch.tensor(size_embeddings).int(), torch.tensor(mask).bool(), torch.tensor(identities_mask).bool(), torch.tensor(positions), tokens_per_identity, self.y[index], self.multiclass_labels[index], video_id.replace("/", "_")
+
+
+ def __len__(self):
+ return self.n_samples
diff --git a/clean/video/mintime/environment.yml b/clean/video/mintime/environment.yml
new file mode 100644
index 0000000000000000000000000000000000000000..7dce5868115488ae7b3a8f4feae1fa68e0d53712
--- /dev/null
+++ b/clean/video/mintime/environment.yml
@@ -0,0 +1,76 @@
+name: mintime
+channels:
+ - defaults
+dependencies:
+ - _libgcc_mutex=0.1=main
+ - _openmp_mutex=5.1=1_gnu
+ - ca-certificates=2022.10.11=h06a4308_0
+ - certifi=2022.9.24=py38h06a4308_0
+ - ld_impl_linux-64=2.38=h1181459_1
+ - libffi=3.4.2=h6a678d5_6
+ - libgcc-ng=11.2.0=h1234567_1
+ - libgomp=11.2.0=h1234567_1
+ - libstdcxx-ng=11.2.0=h1234567_1
+ - ncurses=6.3=h5eee18b_3
+ - openssl=1.1.1s=h7f8727e_0
+ - pip=22.3.1=py38h06a4308_0
+ - python=3.8.15=h7a1cb2a_2
+ - readline=8.2=h5eee18b_0
+ - setuptools=65.5.0=py38h06a4308_0
+ - sqlite=3.40.0=h5082296_0
+ - tk=8.6.12=h1ccaba5_0
+ - wheel=0.37.1=pyhd3eb1b0_0
+ - xz=5.2.8=h5eee18b_0
+ - zlib=1.2.13=h5eee18b_0
+ - pip:
+ - albumentations==0.5.2
+ - av==10.0.0
+ - charset-normalizer==2.1.1
+ - contourpy==1.0.6
+ - cycler==0.11.0
+ - efficientnet-pytorch==0.7.1
+ - einops==0.6.0
+ - facenet-pytorch==2.5.2
+ - fonttools==4.38.0
+ - fvcore==0.1.5.post20221213
+ - idna==3.4
+ - imageio==2.22.4
+ - imgaug==0.4.0
+ - iopath==0.1.10
+ - joblib==1.2.0
+ - kiwisolver==1.4.4
+ - matplotlib==3.6.2
+ - networkx==2.8.8
+ - numpy==1.23.5
+ - opencv-python==4.6.0.66
+ - opencv-python-headless==4.6.0.66
+ - packaging==22.0
+ - parameterized==0.8.1
+ - pillow==9.3.0
+ - portalocker==2.6.0
+ - pyparsing==3.0.9
+ - python-dateutil==2.8.2
+ - pytorchvideo==0.1.5
+ - pywavelets==1.4.1
+ - pyyaml==6.0
+ - qudida==0.0.4
+ - requests==2.28.1
+ - scikit-image==0.19.3
+ - scikit-learn==1.2.0
+ - scipy==1.9.3
+ - shapely==2.0.0
+ - six==1.16.0
+ - tabulate==0.9.0
+ - termcolor==2.1.1
+ - threadpoolctl==3.1.0
+ - tifffile==2022.10.10
+ - torch==1.9.0+cu111
+ - torchaudio==0.9.0
+ - torchsummary==1.5.1
+ - torchvision==0.10.0+cu111
+ - tqdm==4.64.1
+ - typing-extensions==4.4.0
+ - urllib3==1.26.13
+ - yacs==0.1.8
+prefix: /home/coccomini/anaconda3/envs/mintime
+
diff --git a/clean/video/mintime/get_multi_identity_videos.py b/clean/video/mintime/get_multi_identity_videos.py
new file mode 100644
index 0000000000000000000000000000000000000000..eb813072a17fc14779356dff566ef33a39e097e9
--- /dev/null
+++ b/clean/video/mintime/get_multi_identity_videos.py
@@ -0,0 +1,31 @@
+import os
+import pandas as pd
+
+DATA_CSV = "../../datasets/dfdc_test_preview/test_videos_preview_labels.csv"
+DATA_PATH = "../../datasets/dfdc_test_preview/faces"
+
+
+col_names = ["video", "label"]
+df_test = pd.read_csv(DATA_CSV, sep=' ', names=col_names)
+
+indexes_to_drop = []
+for index, row in df_test.iterrows():
+ folders = os.listdir(os.path.join(DATA_PATH, row['video']))
+ if len(folders) < 2:
+ indexes_to_drop.append(index)
+ else:
+ counter = 0
+ for folder in folders:
+ if os.path.isdir(os.path.join(DATA_PATH, row['video'], folder)):
+ counter += 1
+ if counter < 2:
+ indexes_to_drop.append(index)
+
+df_test.drop(df_test.index[indexes_to_drop], inplace=True)
+
+
+df_test.to_csv("../../datasets/dfdc_test_preview/multi_identity_videos.csv")
+
+print(len(df_test))
+
+
diff --git a/clean/video/mintime/model.txt b/clean/video/mintime/model.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a8cb7936075b59c9bf3a2b09d4775de25c52f6c2
--- /dev/null
+++ b/clean/video/mintime/model.txt
@@ -0,0 +1,12 @@
+Namespace(config='config/slowfast.yaml', data_path='../../datasets/ForgeryNet/faces', deepfake_methods=None, extractor_model=0, extractor_unfreeze_blocks=-1, extractor_weights='ImageNet', freeze_backbone=False, gpu_id=-1, logger_name='runs/train/slowfast', max_videos=-1, model=2, models_output_path='outputs/models/slowfast', num_epochs=30, patience=5, random_state=42, restore_epoch=False, resume='', train_list_file='../../datasets/ForgeryNet/faces/train_and_val.csv', validation_list_file='../../datasets/ForgeryNet/faces/test.csv', video_path='../../datasets/ForgeryNet/videos', workers=10)
+Loaded pretrained weights for efficientnet-b0
+Train videos: 163909 Validation videos: 14495
+__TRAINING STATS__
+Counter({1: 90211, 0: 73698})
+Weights 0.8169513695669043
+__VALIDATION STATS__
+Counter({1: 8147, 0: 6348})
+___________________
+No checkpoint loaded for the model.
+
+Loss: 0.59 Accuracy: 0.75 Train 0s: 4 Train 1s: 4 Expected Time: 09:05:27.583136
diff --git a/clean/video/mintime/models/baseline.py b/clean/video/mintime/models/baseline.py
new file mode 100644
index 0000000000000000000000000000000000000000..9eedc0f0bec4d2e1458621d2fc4698385c62622a
--- /dev/null
+++ b/clean/video/mintime/models/baseline.py
@@ -0,0 +1,37 @@
+import torch
+from torch import nn
+from einops import rearrange
+from efficientnet_pytorch import EfficientNet
+import cv2
+import re
+import numpy as np
+from torch import einsum
+from random import randint
+
+import timm
+
+from torchsummary import summary
+
+class Baseline(nn.Module):
+ def __init__(self, config):
+ super().__init__()
+
+ self.dim = config['model']['dim']
+ self.mlp_dim = config['model']['mlp-dim']
+
+ self.num_classes = config['model']['num-classes']
+
+ self._avg_pooling = nn.AdaptiveAvgPool2d(1)
+ self.mlp_head = nn.Sequential(
+ nn.Linear(self.dim, self.mlp_dim),
+ nn.Linear(self.mlp_dim, self.num_classes)
+ )
+
+ for index, (name, param) in enumerate(self.mlp_head.named_parameters()):
+ param.requires_grad = True
+
+
+ def forward(self, x, mask=None): # (B x C x H x W)
+ x = self._avg_pooling(x)
+ x = x.flatten(start_dim=1)
+ return self.mlp_head(x)
diff --git a/clean/video/mintime/models/convolutional_timesformer_base.py b/clean/video/mintime/models/convolutional_timesformer_base.py
new file mode 100644
index 0000000000000000000000000000000000000000..030408080c480ca1b0d35b074fcef8fc5cfad7a6
--- /dev/null
+++ b/clean/video/mintime/models/convolutional_timesformer_base.py
@@ -0,0 +1,240 @@
+import torch
+from torch import nn, einsum
+import torch.nn.functional as F
+from einops import rearrange, repeat
+
+from models.efficientnet.efficientnet_pytorch import EfficientNet
+
+
+# helpers
+def exists(val):
+ return val is not None
+
+# classes
+
+class PreNorm(nn.Module):
+ def __init__(self, dim, fn):
+ super().__init__()
+ self.fn = fn
+ self.norm = nn.LayerNorm(dim)
+
+ def forward(self, x, *args, **kwargs):
+ x = self.norm(x)
+ return self.fn(x, *args, **kwargs)
+
+# time token shift
+
+def shift(t, amt):
+ if amt is 0:
+ return t
+ return F.pad(t, (0, 0, 0, 0, amt, -amt))
+
+class PreTokenShift(nn.Module):
+ def __init__(self, frames, fn):
+ super().__init__()
+ self.frames = frames
+ self.fn = fn
+
+ def forward(self, x, *args, **kwargs):
+ f, dim = self.frames, x.shape[-1]
+ cls_x, x = x[:, :1], x[:, 1:]
+ x = rearrange(x, 'b (f n) d -> b f n d', f = f)
+
+ # shift along time frame before and after
+
+ dim_chunk = (dim // 3)
+ chunks = x.split(dim_chunk, dim = -1)
+ chunks_to_shift, rest = chunks[:3], chunks[3:]
+ shifted_chunks = tuple(map(lambda args: shift(*args), zip(chunks_to_shift, (-1, 0, 1))))
+ x = torch.cat((*shifted_chunks, *rest), dim = -1)
+
+ x = rearrange(x, 'b f n d -> b (f n) d')
+ x = torch.cat((cls_x, x), dim = 1)
+ return self.fn(x, *args, **kwargs)
+
+# feedforward
+
+class GEGLU(nn.Module):
+ def forward(self, x):
+ x, gates = x.chunk(2, dim = -1)
+ return x * F.gelu(gates)
+
+class FeedForward(nn.Module):
+ def __init__(self, dim, mult = 4, dropout = 0.):
+ super().__init__()
+ self.net = nn.Sequential(
+ nn.Linear(dim, dim * mult * 2),
+ GEGLU(),
+ nn.Dropout(dropout),
+ nn.Linear(dim * mult, dim)
+ )
+
+ def forward(self, x):
+ return self.net(x)
+
+# attention
+
+def attn(q, k, v, mask = None):
+ sim = einsum('b i d, b j d -> b i j', q, k)
+ if exists(mask):
+ max_neg_value = -torch.finfo(sim.dtype).max
+ sim.masked_fill_(~mask, max_neg_value)
+ attn = sim.softmax(dim = -1)
+ out = einsum('b i j, b j d -> b i d', attn, v)
+ return out
+
+class Attention(nn.Module):
+ def __init__(
+ self,
+ dim,
+ dim_head = 64,
+ heads = 8,
+ dropout = 0.
+ ):
+ super().__init__()
+ self.heads = heads
+ self.scale = dim_head ** -0.5
+ inner_dim = dim_head * heads
+
+ self.to_qkv = nn.Linear(dim, inner_dim * 3, bias = False)
+ self.to_out = nn.Sequential(
+ nn.Linear(inner_dim, dim),
+ nn.Dropout(dropout)
+ )
+
+ def forward(self, x, einops_from, einops_to, mask = None, cls_mask = None, rot_emb = None, **einops_dims):
+ h = self.heads
+ q, k, v = self.to_qkv(x).chunk(3, dim = -1)
+ q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> (b h) n d', h = h), (q, k, v))
+
+ q = q * self.scale
+
+ # splice out classification token at index 1
+ (cls_q, q_), (cls_k, k_), (cls_v, v_) = map(lambda t: (t[:, :1], t[:, 1:]), (q, k, v))
+
+ # let classification token attend to key / values of all patches across time and space
+ cls_out = attn(cls_q, k, v, mask = cls_mask)
+ # rearrange across time or space
+ q_, k_, v_ = map(lambda t: rearrange(t, f'{einops_from} -> {einops_to}', **einops_dims), (q_, k_, v_))
+
+ # expand cls token keys and values across time or space and concat
+ r = q_.shape[0] // cls_k.shape[0]
+ cls_k, cls_v = map(lambda t: repeat(t, 'b () d -> (b r) () d', r = r), (cls_k, cls_v))
+
+ k_ = torch.cat((cls_k, k_), dim = 1)
+ v_ = torch.cat((cls_v, v_), dim = 1)
+
+ # attention
+ out = attn(q_, k_, v_, mask = mask)
+
+ # merge back time or space
+ out = rearrange(out, f'{einops_to} -> {einops_from}', **einops_dims)
+
+ # concat back the cls token
+ out = torch.cat((cls_out, out), dim = 1)
+
+ # merge back the heads
+ out = rearrange(out, '(b h) n d -> b n (h d)', h = h)
+
+ # combine heads out
+ return self.to_out(out)
+
+# main classes
+
+class ConvolutionalTimeSformer(nn.Module):
+ def __init__(
+ self,
+ *,
+ config
+ ):
+
+ super().__init__()
+ self.dim = config['model']['dim']
+ self.num_frames = config['model']['num-frames']
+ self.num_patches = config['model']['num-patches']
+ self.image_size = config['model']['image-size']
+ self.num_classes = config['model']['num-classes']
+ self.patch_size = config['model']['patch-size']
+ self.channels = config['model']['channels']
+ self.depth = config['model']['depth']
+ self.heads = config['model']['heads']
+ self.dim_head = config['model']['dim-head']
+ self.attn_dropout = config['model']['attn-dropout']
+ self.ff_dropout = config['model']['ff-dropout']
+ self.shift_tokens = config['model']['shift-tokens']
+ self.efficient_net_block = config['model']['efficient-net-block']
+ self.efficient_net = EfficientNet.from_pretrained('efficientnet-b0')
+
+
+ for m in self.efficient_net.modules():
+ m.requires_grad = False
+ self.efficient_net.eval()
+
+
+ num_positions = self.num_frames * self.num_patches
+ patch_dim = self.patch_size ** 2
+
+
+
+ self.to_patch_embedding = nn.Linear(patch_dim, self.dim)
+ self.cls_token = nn.Parameter(torch.randn(1, self.dim))
+
+ self.pos_emb = nn.Embedding(num_positions + 1, self.dim)
+ self.size_emb = nn.Embedding(num_positions + 1, self.dim)
+
+
+ self.layers = nn.ModuleList([])
+ for _ in range(self.depth):
+ ff = FeedForward(self.dim, dropout = self.ff_dropout)
+ time_attn = Attention(self.dim, dim_head = self.dim_head, heads = self.heads, dropout = self.attn_dropout)
+ spatial_attn = Attention(self.dim, dim_head = self.dim_head, heads = self.heads, dropout = self.attn_dropout)
+ if self.shift_tokens:
+ time_attn, spatial_attn, ff = map(lambda t: PreTokenShift(num_frames, t), (time_attn, spatial_attn, ff))
+
+ time_attn, spatial_attn, ff = map(lambda t: PreNorm(self.dim, t), (time_attn, spatial_attn, ff))
+
+ self.layers.append(nn.ModuleList([time_attn, spatial_attn, ff]))
+
+ self.to_out = nn.Sequential(
+ nn.LayerNorm(self.dim),
+ nn.Linear(self.dim, self.num_classes)
+ )
+
+ def forward(self, x, mask = None, size_embedding = None):
+ b, f, h, w, _, *_, device, p = *x.shape, x.device, self.patch_size
+ hp, wp = (h // p), (w // p)
+ n = hp * wp
+
+ x = rearrange(x, 'b f h w c -> (b f) c h w')
+ x = self.efficient_net.extract_features_at_block(x, self.efficient_net_block)
+ x = rearrange(x, '(b f) c h w -> b f c h w', b = b, f = f)
+ x = rearrange(x, 'b f c h w -> b (f c) (h w)')
+ tokens = self.to_patch_embedding(x)
+
+ # add cls token
+ cls_token = repeat(self.cls_token, 'n d -> b n d', b = b)
+ x = torch.cat((cls_token, tokens), dim = 1)
+ # positional embedding
+ x += self.pos_emb(torch.arange(x.shape[1], device = device))
+
+ # size embedding
+ size_embedding = repeat(size_embedding, 'b f -> p b f', p=self.num_patches)
+ size_embedding = rearrange(size_embedding, 'p b f -> (p b f)')
+ size_embedding = torch.cat((torch.tensor([0]), size_embedding), dim = 0)
+ size_embedding = size_embedding.to(device)
+ x += self.size_emb(size_embedding)
+
+ # calculate masking for uneven number of frames
+
+ frame_mask = None
+ cls_attn_mask = None
+
+ # time and space attention
+
+ for (time_attn, spatial_attn, ff) in self.layers:
+ x = time_attn(x, 'b (f n) d', '(b n) f d', n = n, mask = frame_mask, cls_mask = cls_attn_mask) + x
+ x = spatial_attn(x, 'b (f n) d', '(b f) n d', f = f, cls_mask = cls_attn_mask) + x
+ x = ff(x) + x
+
+ cls_token = x[:, 0]
+ return self.to_out(cls_token)
diff --git a/clean/video/mintime/models/efficientnet/.gitignore b/clean/video/mintime/models/efficientnet/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..138cf12f29857624fbd24308bc8ab334419082d8
--- /dev/null
+++ b/clean/video/mintime/models/efficientnet/.gitignore
@@ -0,0 +1,127 @@
+# Custom
+tmp
+*.pkl
+
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# pyenv
+.python-version
+
+# celery beat schedule file
+celerybeat-schedule
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.DS_STORE
+
+# PyCharm
+.idea*
+*.xml
+
+# Custom
+tensorflow/
+example/test*
+*.pth*
+examples/imagenet/data/
+!examples/imagenet/data/README.md
+tmp
+tf_to_pytorch/pretrained_tensorflow
+!tf_to_pytorch/pretrained_tensorflow/download.sh
+examples/imagenet/run.sh
+
+
+
diff --git a/clean/video/mintime/models/efficientnet/LICENSE b/clean/video/mintime/models/efficientnet/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..d645695673349e3947e8e5ae42332d0ac3164cd7
--- /dev/null
+++ b/clean/video/mintime/models/efficientnet/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/clean/video/mintime/models/efficientnet/README.md b/clean/video/mintime/models/efficientnet/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..78f6fd41e7dd8d41c0064271849c65b0abbdd2d6
--- /dev/null
+++ b/clean/video/mintime/models/efficientnet/README.md
@@ -0,0 +1,269 @@
+# EfficientNet PyTorch
+
+### Quickstart
+
+Install with `pip install efficientnet_pytorch` and load a pretrained EfficientNet with:
+```python
+from efficientnet_pytorch import EfficientNet
+model = EfficientNet.from_pretrained('efficientnet-b0')
+```
+
+### Updates
+
+#### Update (April 2, 2021)
+
+The [EfficientNetV2 paper](https://arxiv.org/abs/2104.00298) has been released! I am working on implementing it as you read this :)
+
+About EfficientNetV2:
+> EfficientNetV2 is a new family of convolutional networks that have faster training speed and better parameter efficiency than previous models. To develop this family of models, we use a combination of training-aware neural architecture search and scaling, to jointly optimize training speed and parameter efficiency. The models were searched from the search space enriched with new ops such as Fused-MBConv.
+
+Here is a comparison:
+>
+
+
+#### Update (Aug 25, 2020)
+
+This update adds:
+ * A new `include_top` (default: `True`) option ([#208](https://github.com/lukemelas/EfficientNet-PyTorch/pull/208))
+ * Continuous testing with [sotabench](https://sotabench.com/)
+ * Code quality improvements and fixes ([#215](https://github.com/lukemelas/EfficientNet-PyTorch/pull/215) [#223](https://github.com/lukemelas/EfficientNet-PyTorch/pull/223))
+
+#### Update (May 14, 2020)
+
+This update adds comprehensive comments and documentation (thanks to @workingcoder).
+
+#### Update (January 23, 2020)
+
+This update adds a new category of pre-trained model based on adversarial training, called _advprop_. It is important to note that the preprocessing required for the advprop pretrained models is slightly different from normal ImageNet preprocessing. As a result, by default, advprop models are not used. To load a model with advprop, use:
+```python
+model = EfficientNet.from_pretrained("efficientnet-b0", advprop=True)
+```
+There is also a new, large `efficientnet-b8` pretrained model that is only available in advprop form. When using these models, replace ImageNet preprocessing code as follows:
+```python
+if advprop: # for models using advprop pretrained weights
+ normalize = transforms.Lambda(lambda img: img * 2.0 - 1.0)
+else:
+ normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406],
+ std=[0.229, 0.224, 0.225])
+```
+This update also addresses multiple other issues ([#115](https://github.com/lukemelas/EfficientNet-PyTorch/issues/115), [#128](https://github.com/lukemelas/EfficientNet-PyTorch/issues/128)).
+
+#### Update (October 15, 2019)
+
+This update allows you to choose whether to use a memory-efficient Swish activation. The memory-efficient version is chosen by default, but it cannot be used when exporting using PyTorch JIT. For this purpose, we have also included a standard (export-friendly) swish activation function. To switch to the export-friendly version, simply call `model.set_swish(memory_efficient=False)` after loading your desired model. This update addresses issues [#88](https://github.com/lukemelas/EfficientNet-PyTorch/pull/88) and [#89](https://github.com/lukemelas/EfficientNet-PyTorch/pull/89).
+
+#### Update (October 12, 2019)
+
+This update makes the Swish activation function more memory-efficient. It also addresses pull requests [#72](https://github.com/lukemelas/EfficientNet-PyTorch/pull/72), [#73](https://github.com/lukemelas/EfficientNet-PyTorch/pull/73), [#85](https://github.com/lukemelas/EfficientNet-PyTorch/pull/85), and [#86](https://github.com/lukemelas/EfficientNet-PyTorch/pull/86). Thanks to the authors of all the pull requests!
+
+#### Update (July 31, 2019)
+
+_Upgrade the pip package with_ `pip install --upgrade efficientnet-pytorch`
+
+The B6 and B7 models are now available. Additionally, _all_ pretrained models have been updated to use AutoAugment preprocessing, which translates to better performance across the board. Usage is the same as before:
+```python
+from efficientnet_pytorch import EfficientNet
+model = EfficientNet.from_pretrained('efficientnet-b7')
+```
+
+#### Update (June 29, 2019)
+
+This update adds easy model exporting ([#20](https://github.com/lukemelas/EfficientNet-PyTorch/issues/20)) and feature extraction ([#38](https://github.com/lukemelas/EfficientNet-PyTorch/issues/38)).
+
+ * [Example: Export to ONNX](#example-export)
+ * [Example: Extract features](#example-feature-extraction)
+ * Also: fixed a CUDA/CPU bug ([#32](https://github.com/lukemelas/EfficientNet-PyTorch/issues/32))
+
+It is also now incredibly simple to load a pretrained model with a new number of classes for transfer learning:
+```python
+model = EfficientNet.from_pretrained('efficientnet-b1', num_classes=23)
+```
+
+
+#### Update (June 23, 2019)
+
+The B4 and B5 models are now available. Their usage is identical to the other models:
+```python
+from efficientnet_pytorch import EfficientNet
+model = EfficientNet.from_pretrained('efficientnet-b4')
+```
+
+### Overview
+This repository contains an op-for-op PyTorch reimplementation of [EfficientNet](https://arxiv.org/abs/1905.11946), along with pre-trained models and examples.
+
+The goal of this implementation is to be simple, highly extensible, and easy to integrate into your own projects. This implementation is a work in progress -- new features are currently being implemented.
+
+At the moment, you can easily:
+ * Load pretrained EfficientNet models
+ * Use EfficientNet models for classification or feature extraction
+ * Evaluate EfficientNet models on ImageNet or your own images
+
+_Upcoming features_: In the next few days, you will be able to:
+ * Train new models from scratch on ImageNet with a simple command
+ * Quickly finetune an EfficientNet on your own dataset
+ * Export EfficientNet models for production
+
+### Table of contents
+1. [About EfficientNet](#about-efficientnet)
+2. [About EfficientNet-PyTorch](#about-efficientnet-pytorch)
+3. [Installation](#installation)
+4. [Usage](#usage)
+ * [Load pretrained models](#loading-pretrained-models)
+ * [Example: Classify](#example-classification)
+ * [Example: Extract features](#example-feature-extraction)
+ * [Example: Export to ONNX](#example-export)
+6. [Contributing](#contributing)
+
+### About EfficientNet
+
+If you're new to EfficientNets, here is an explanation straight from the official TensorFlow implementation:
+
+EfficientNets are a family of image classification models, which achieve state-of-the-art accuracy, yet being an order-of-magnitude smaller and faster than previous models. We develop EfficientNets based on AutoML and Compound Scaling. In particular, we first use [AutoML Mobile framework](https://ai.googleblog.com/2018/08/mnasnet-towards-automating-design-of.html) to develop a mobile-size baseline network, named as EfficientNet-B0; Then, we use the compound scaling method to scale up this baseline to obtain EfficientNet-B1 to B7.
+
+
+
+
+
+
+
+
+
+
+
+
+EfficientNets achieve state-of-the-art accuracy on ImageNet with an order of magnitude better efficiency:
+
+
+* In high-accuracy regime, our EfficientNet-B7 achieves state-of-the-art 84.4% top-1 / 97.1% top-5 accuracy on ImageNet with 66M parameters and 37B FLOPS, being 8.4x smaller and 6.1x faster on CPU inference than previous best [Gpipe](https://arxiv.org/abs/1811.06965).
+
+* In middle-accuracy regime, our EfficientNet-B1 is 7.6x smaller and 5.7x faster on CPU inference than [ResNet-152](https://arxiv.org/abs/1512.03385), with similar ImageNet accuracy.
+
+* Compared with the widely used [ResNet-50](https://arxiv.org/abs/1512.03385), our EfficientNet-B4 improves the top-1 accuracy from 76.3% of ResNet-50 to 82.6% (+6.3%), under similar FLOPS constraint.
+
+### About EfficientNet PyTorch
+
+EfficientNet PyTorch is a PyTorch re-implementation of EfficientNet. It is consistent with the [original TensorFlow implementation](https://github.com/tensorflow/tpu/tree/master/models/official/efficientnet), such that it is easy to load weights from a TensorFlow checkpoint. At the same time, we aim to make our PyTorch implementation as simple, flexible, and extensible as possible.
+
+If you have any feature requests or questions, feel free to leave them as GitHub issues!
+
+### Installation
+
+Install via pip:
+```bash
+pip install efficientnet_pytorch
+```
+
+Or install from source:
+```bash
+git clone https://github.com/lukemelas/EfficientNet-PyTorch
+cd EfficientNet-Pytorch
+pip install -e .
+```
+
+### Usage
+
+#### Loading pretrained models
+
+Load an EfficientNet:
+```python
+from efficientnet_pytorch import EfficientNet
+model = EfficientNet.from_name('efficientnet-b0')
+```
+
+Load a pretrained EfficientNet:
+```python
+from efficientnet_pytorch import EfficientNet
+model = EfficientNet.from_pretrained('efficientnet-b0')
+```
+
+Details about the models are below:
+
+| *Name* |*# Params*|*Top-1 Acc.*|*Pretrained?*|
+|:-----------------:|:--------:|:----------:|:-----------:|
+| `efficientnet-b0` | 5.3M | 76.3 | ✓ |
+| `efficientnet-b1` | 7.8M | 78.8 | ✓ |
+| `efficientnet-b2` | 9.2M | 79.8 | ✓ |
+| `efficientnet-b3` | 12M | 81.1 | ✓ |
+| `efficientnet-b4` | 19M | 82.6 | ✓ |
+| `efficientnet-b5` | 30M | 83.3 | ✓ |
+| `efficientnet-b6` | 43M | 84.0 | ✓ |
+| `efficientnet-b7` | 66M | 84.4 | ✓ |
+
+
+#### Example: Classification
+
+Below is a simple, complete example. It may also be found as a jupyter notebook in `examples/simple` or as a [Colab Notebook](https://colab.research.google.com/drive/1Jw28xZ1NJq4Cja4jLe6tJ6_F5lCzElb4).
+
+We assume that in your current directory, there is a `img.jpg` file and a `labels_map.txt` file (ImageNet class names). These are both included in `examples/simple`.
+
+```python
+import json
+from PIL import Image
+import torch
+from torchvision import transforms
+
+from efficientnet_pytorch import EfficientNet
+model = EfficientNet.from_pretrained('efficientnet-b0')
+
+# Preprocess image
+tfms = transforms.Compose([transforms.Resize(224), transforms.ToTensor(),
+ transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),])
+img = tfms(Image.open('img.jpg')).unsqueeze(0)
+print(img.shape) # torch.Size([1, 3, 224, 224])
+
+# Load ImageNet class names
+labels_map = json.load(open('labels_map.txt'))
+labels_map = [labels_map[str(i)] for i in range(1000)]
+
+# Classify
+model.eval()
+with torch.no_grad():
+ outputs = model(img)
+
+# Print predictions
+print('-----')
+for idx in torch.topk(outputs, k=5).indices.squeeze(0).tolist():
+ prob = torch.softmax(outputs, dim=1)[0, idx].item()
+ print('{label:<75} ({p:.2f}%)'.format(label=labels_map[idx], p=prob*100))
+```
+
+#### Example: Feature Extraction
+
+You can easily extract features with `model.extract_features`:
+```python
+from efficientnet_pytorch import EfficientNet
+model = EfficientNet.from_pretrained('efficientnet-b0')
+
+# ... image preprocessing as in the classification example ...
+print(img.shape) # torch.Size([1, 3, 224, 224])
+
+features = model.extract_features(img)
+print(features.shape) # torch.Size([1, 1280, 7, 7])
+```
+
+#### Example: Export to ONNX
+
+Exporting to ONNX for deploying to production is now simple:
+```python
+import torch
+from efficientnet_pytorch import EfficientNet
+
+model = EfficientNet.from_pretrained('efficientnet-b1')
+dummy_input = torch.randn(10, 3, 240, 240)
+
+model.set_swish(memory_efficient=False)
+torch.onnx.export(model, dummy_input, "test-b1.onnx", verbose=True)
+```
+
+[Here](https://colab.research.google.com/drive/1rOAEXeXHaA8uo3aG2YcFDHItlRJMV0VP) is a Colab example.
+
+
+#### ImageNet
+
+See `examples/imagenet` for details about evaluating on ImageNet.
+
+### Contributing
+
+If you find a bug, create a GitHub issue, or even better, submit a pull request. Similarly, if you have questions, simply post them as GitHub issues.
+
+I look forward to seeing what the community does with these models!
diff --git a/clean/video/mintime/models/efficientnet/efficientnet_pytorch/__init__.py b/clean/video/mintime/models/efficientnet/efficientnet_pytorch/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..2b529dfe3f61da71f7427fbeb7ab47710450d372
--- /dev/null
+++ b/clean/video/mintime/models/efficientnet/efficientnet_pytorch/__init__.py
@@ -0,0 +1,9 @@
+__version__ = "0.7.1"
+from .model import EfficientNet, VALID_MODELS
+from .utils import (
+ GlobalParams,
+ BlockArgs,
+ BlockDecoder,
+ efficientnet,
+ get_model_params,
+)
diff --git a/clean/video/mintime/models/efficientnet/efficientnet_pytorch/model.py b/clean/video/mintime/models/efficientnet/efficientnet_pytorch/model.py
new file mode 100644
index 0000000000000000000000000000000000000000..807b639da01671e0d96e227c61c2ad51f8f14000
--- /dev/null
+++ b/clean/video/mintime/models/efficientnet/efficientnet_pytorch/model.py
@@ -0,0 +1,444 @@
+"""model.py - Model and module class for EfficientNet.
+ They are built to mirror those in the official TensorFlow implementation.
+"""
+
+# Author: lukemelas (github username)
+# Github repo: https://github.com/lukemelas/EfficientNet-PyTorch
+# With adjustments and added comments by workingcoder (github username).
+import numpy as np
+import torch
+from torch import nn
+from torch.nn import functional as F
+from .utils import (
+ round_filters,
+ round_repeats,
+ drop_connect,
+ get_same_padding_conv2d,
+ get_model_params,
+ efficientnet_params,
+ load_pretrained_weights,
+ Swish,
+ MemoryEfficientSwish,
+ calculate_output_image_size
+)
+
+
+VALID_MODELS = (
+ 'efficientnet-b0', 'efficientnet-b1', 'efficientnet-b2', 'efficientnet-b3',
+ 'efficientnet-b4', 'efficientnet-b5', 'efficientnet-b6', 'efficientnet-b7',
+ 'efficientnet-b8',
+
+ # Support the construction of 'efficientnet-l2' without pretrained weights
+ 'efficientnet-l2'
+)
+
+
+class MBConvBlock(nn.Module):
+ """Mobile Inverted Residual Bottleneck Block.
+ Args:
+ block_args (namedtuple): BlockArgs, defined in utils.py.
+ global_params (namedtuple): GlobalParam, defined in utils.py.
+ image_size (tuple or list): [image_height, image_width].
+ References:
+ [1] https://arxiv.org/abs/1704.04861 (MobileNet v1)
+ [2] https://arxiv.org/abs/1801.04381 (MobileNet v2)
+ [3] https://arxiv.org/abs/1905.02244 (MobileNet v3)
+ """
+
+ def __init__(self, block_args, global_params, image_size=None):
+ super().__init__()
+ self._block_args = block_args
+ self._bn_mom = 1 - global_params.batch_norm_momentum # pytorch's difference from tensorflow
+ self._bn_eps = global_params.batch_norm_epsilon
+ self.has_se = (self._block_args.se_ratio is not None) and (0 < self._block_args.se_ratio <= 1)
+ self.id_skip = block_args.id_skip # whether to use skip connection and drop connect
+
+ # Expansion phase (Inverted Bottleneck)
+ inp = self._block_args.input_filters # number of input channels
+ oup = self._block_args.input_filters * self._block_args.expand_ratio # number of output channels
+ if self._block_args.expand_ratio != 1:
+ Conv2d = get_same_padding_conv2d(image_size=image_size)
+ self._expand_conv = Conv2d(in_channels=inp, out_channels=oup, kernel_size=1, bias=False)
+ self._bn0 = nn.BatchNorm2d(num_features=oup, momentum=self._bn_mom, eps=self._bn_eps)
+ # image_size = calculate_output_image_size(image_size, 1) <-- this wouldn't modify image_size
+
+ # Depthwise convolution phase
+ k = self._block_args.kernel_size
+ s = self._block_args.stride
+ Conv2d = get_same_padding_conv2d(image_size=image_size)
+ self._depthwise_conv = Conv2d(
+ in_channels=oup, out_channels=oup, groups=oup, # groups makes it depthwise
+ kernel_size=k, stride=s, bias=False)
+ self._bn1 = nn.BatchNorm2d(num_features=oup, momentum=self._bn_mom, eps=self._bn_eps)
+ image_size = calculate_output_image_size(image_size, s)
+
+ # Squeeze and Excitation layer, if desired
+ if self.has_se:
+ Conv2d = get_same_padding_conv2d(image_size=(1, 1))
+ num_squeezed_channels = max(1, int(self._block_args.input_filters * self._block_args.se_ratio))
+ self._se_reduce = Conv2d(in_channels=oup, out_channels=num_squeezed_channels, kernel_size=1)
+ self._se_expand = Conv2d(in_channels=num_squeezed_channels, out_channels=oup, kernel_size=1)
+
+ # Pointwise convolution phase
+ final_oup = self._block_args.output_filters
+ Conv2d = get_same_padding_conv2d(image_size=image_size)
+ self._project_conv = Conv2d(in_channels=oup, out_channels=final_oup, kernel_size=1, bias=False)
+ self._bn2 = nn.BatchNorm2d(num_features=final_oup, momentum=self._bn_mom, eps=self._bn_eps)
+ self._swish = MemoryEfficientSwish()
+
+ def forward(self, inputs, drop_connect_rate=None):
+ """MBConvBlock's forward function.
+ Args:
+ inputs (tensor): Input tensor.
+ drop_connect_rate (bool): Drop connect rate (float, between 0 and 1).
+ Returns:
+ Output of this block after processing.
+ """
+
+ # Expansion and Depthwise Convolution
+ x = inputs
+ if self._block_args.expand_ratio != 1:
+ x = self._expand_conv(inputs)
+ x = self._bn0(x)
+ x = self._swish(x)
+
+ x = self._depthwise_conv(x)
+ x = self._bn1(x)
+ x = self._swish(x)
+
+ # Squeeze and Excitation
+ if self.has_se:
+ x_squeezed = F.adaptive_avg_pool2d(x, 1)
+ x_squeezed = self._se_reduce(x_squeezed)
+ x_squeezed = self._swish(x_squeezed)
+ x_squeezed = self._se_expand(x_squeezed)
+ x = torch.sigmoid(x_squeezed) * x
+
+ # Pointwise Convolution
+ x = self._project_conv(x)
+ x = self._bn2(x)
+
+ # Skip connection and drop connect
+ input_filters, output_filters = self._block_args.input_filters, self._block_args.output_filters
+ if self.id_skip and self._block_args.stride == 1 and input_filters == output_filters:
+ # The combination of skip connection and drop connect brings about stochastic depth.
+ if drop_connect_rate:
+ x = drop_connect(x, p=drop_connect_rate, training=self.training)
+ x = x + inputs # skip connection
+ return x
+
+ def set_swish(self, memory_efficient=True):
+ """Sets swish function as memory efficient (for training) or standard (for export).
+ Args:
+ memory_efficient (bool): Whether to use memory-efficient version of swish.
+ """
+ self._swish = MemoryEfficientSwish() if memory_efficient else Swish()
+
+
+class EfficientNet(nn.Module):
+ """EfficientNet model.
+ Most easily loaded with the .from_name or .from_pretrained methods.
+ Args:
+ blocks_args (list[namedtuple]): A list of BlockArgs to construct blocks.
+ global_params (namedtuple): A set of GlobalParams shared between blocks.
+ References:
+ [1] https://arxiv.org/abs/1905.11946 (EfficientNet)
+ Example:
+ >>> import torch
+ >>> from efficientnet.model import EfficientNet
+ >>> inputs = torch.rand(1, 3, 224, 224)
+ >>> model = EfficientNet.from_pretrained('efficientnet-b0')
+ >>> model.eval()
+ >>> outputs = model(inputs)
+ """
+
+ def __init__(self, blocks_args=None, global_params=None):
+ super().__init__()
+ assert isinstance(blocks_args, list), 'blocks_args should be a list'
+ assert len(blocks_args) > 0, 'block args must be greater than 0'
+ self._global_params = global_params
+ self._blocks_args = blocks_args
+
+ # Batch norm parameters
+ bn_mom = 1 - self._global_params.batch_norm_momentum
+ bn_eps = self._global_params.batch_norm_epsilon
+
+ # Get stem static or dynamic convolution depending on image size
+ image_size = global_params.image_size
+ Conv2d = get_same_padding_conv2d(image_size=image_size)
+
+ # Stem
+ in_channels = 3 # rgb
+ out_channels = round_filters(32, self._global_params) # number of output channels
+ self._conv_stem = Conv2d(in_channels, out_channels, kernel_size=3, stride=2, bias=False)
+ self._bn0 = nn.BatchNorm2d(num_features=out_channels, momentum=bn_mom, eps=bn_eps)
+ image_size = calculate_output_image_size(image_size, 2)
+
+ # Build blocks
+ self._blocks = nn.ModuleList([])
+ for block_args in self._blocks_args:
+
+ # Update block input and output filters based on depth multiplier.
+ block_args = block_args._replace(
+ input_filters=round_filters(block_args.input_filters, self._global_params),
+ output_filters=round_filters(block_args.output_filters, self._global_params),
+ num_repeat=round_repeats(block_args.num_repeat, self._global_params)
+ )
+
+ # The first block needs to take care of stride and filter size increase.
+ self._blocks.append(MBConvBlock(block_args, self._global_params, image_size=image_size))
+ image_size = calculate_output_image_size(image_size, block_args.stride)
+ if block_args.num_repeat > 1: # modify block_args to keep same output size
+ block_args = block_args._replace(input_filters=block_args.output_filters, stride=1)
+ for _ in range(block_args.num_repeat - 1):
+ self._blocks.append(MBConvBlock(block_args, self._global_params, image_size=image_size))
+ # image_size = calculate_output_image_size(image_size, block_args.stride) # stride = 1
+
+ # Head
+ in_channels = block_args.output_filters # output of final block
+ out_channels = round_filters(1280, self._global_params)
+ Conv2d = get_same_padding_conv2d(image_size=image_size)
+ self._conv_head = Conv2d(in_channels, out_channels, kernel_size=1, bias=False)
+ self._bn1 = nn.BatchNorm2d(num_features=out_channels, momentum=bn_mom, eps=bn_eps)
+
+ # Final linear layer
+ self._avg_pooling = nn.AdaptiveAvgPool2d(1)
+ if self._global_params.include_top:
+ self._dropout = nn.Dropout(self._global_params.dropout_rate)
+ self._fc = nn.Linear(out_channels, self._global_params.num_classes)
+
+ # set activation to memory efficient swish by default
+ self._swish = MemoryEfficientSwish()
+
+ def set_swish(self, memory_efficient=True):
+ """Sets swish function as memory efficient (for training) or standard (for export).
+ Args:
+ memory_efficient (bool): Whether to use memory-efficient version of swish.
+ """
+ self._swish = MemoryEfficientSwish() if memory_efficient else Swish()
+ for block in self._blocks:
+ block.set_swish(memory_efficient)
+
+ def extract_endpoints(self, inputs):
+ """Use convolution layer to extract features
+ from reduction levels i in [1, 2, 3, 4, 5].
+ Args:
+ inputs (tensor): Input tensor.
+ Returns:
+ Dictionary of last intermediate features
+ with reduction levels i in [1, 2, 3, 4, 5].
+ Example:
+ >>> import torch
+ >>> from efficientnet.model import EfficientNet
+ >>> inputs = torch.rand(1, 3, 224, 224)
+ >>> model = EfficientNet.from_pretrained('efficientnet-b0')
+ >>> endpoints = model.extract_endpoints(inputs)
+ >>> print(endpoints['reduction_1'].shape) # torch.Size([1, 16, 112, 112])
+ >>> print(endpoints['reduction_2'].shape) # torch.Size([1, 24, 56, 56])
+ >>> print(endpoints['reduction_3'].shape) # torch.Size([1, 40, 28, 28])
+ >>> print(endpoints['reduction_4'].shape) # torch.Size([1, 112, 14, 14])
+ >>> print(endpoints['reduction_5'].shape) # torch.Size([1, 320, 7, 7])
+ >>> print(endpoints['reduction_6'].shape) # torch.Size([1, 1280, 7, 7])
+ """
+ endpoints = dict()
+
+ # Stem
+ x = self._swish(self._bn0(self._conv_stem(inputs)))
+ prev_x = x
+
+ # Blocks
+ for idx, block in enumerate(self._blocks):
+ drop_connect_rate = self._global_params.drop_connect_rate
+ if drop_connect_rate:
+ drop_connect_rate *= float(idx) / len(self._blocks) # scale drop connect_rate
+ x = block(x, drop_connect_rate=drop_connect_rate)
+ if prev_x.size(2) > x.size(2):
+ endpoints['reduction_{}'.format(len(endpoints) + 1)] = prev_x
+ elif idx == len(self._blocks) - 1:
+ endpoints['reduction_{}'.format(len(endpoints) + 1)] = x
+ prev_x = x
+
+ # Head
+ x = self._swish(self._bn1(self._conv_head(x)))
+ endpoints['reduction_{}'.format(len(endpoints) + 1)] = x
+
+ return endpoints
+
+ def forward(self, inputs):
+ """use convolution layer to extract feature .
+ Args:
+ inputs (tensor): Input tensor.
+ Returns:
+ Output of the final convolution
+ layer in the efficientnet model.
+ """
+ # Stem
+ x = self._swish(self._bn0(self._conv_stem(inputs)))
+
+ # Blocks
+ for idx, block in enumerate(self._blocks):
+ drop_connect_rate = self._global_params.drop_connect_rate
+ if drop_connect_rate:
+ drop_connect_rate *= float(idx) / len(self._blocks) # scale drop connect_rate
+ x = block(x, drop_connect_rate=drop_connect_rate)
+
+ # Head
+ x = self._swish(self._bn1(self._conv_head(x)))
+
+ return x
+
+ def delete_blocks(self, limit):
+ '''
+ tmp_blocks = nn.ModuleList([])
+ for idx, block in enumerate(self._blocks):
+ if idx < limit:
+ tmp_blocks.append(self._blocks)
+
+ self._blocks = tmp_blocks
+ '''
+ self._blocks = self._blocks
+
+ def extract_features_at_block(self, inputs, selected_block):
+ """use convolution layer to extract feature .
+ Args:
+ inputs (tensor): Input tensor.
+ Returns:
+ Output of the final convolution
+ layer in the efficientnet model.
+ """
+ # Stem
+ x = self._swish(self._bn0(self._conv_stem(inputs)))
+
+ # Blocks
+ for idx, block in enumerate(self._blocks):
+ drop_connect_rate = self._global_params.drop_connect_rate
+ if drop_connect_rate:
+ drop_connect_rate *= float(idx) / len(self._blocks) # scale drop connect_rate
+ x = block(x, drop_connect_rate=drop_connect_rate)
+ if idx > selected_block:
+ break
+
+ # Head
+ if selected_block >= len(self._blocks):
+ x = self._swish(self._bn1(self._conv_head(x)))
+
+ return x
+
+ def predict(self, inputs):
+ """EfficientNet's forward function.
+ Calls extract_features to extract features, applies final linear layer, and returns logits.
+ Args:
+ inputs (tensor): Input tensor.
+ Returns:
+ Output of this model after processing.
+ """
+ # Convolution layers
+ x = self.extract_features(inputs)
+ # Pooling and final linear layer
+ x = self._avg_pooling(x)
+ if self._global_params.include_top:
+ x = x.flatten(start_dim=1)
+ x = self._dropout(x)
+ x = self._fc(x)
+ return x
+
+ @classmethod
+ def from_name(cls, model_name, in_channels=3, **override_params):
+ """Create an efficientnet model according to name.
+ Args:
+ model_name (str): Name for efficientnet.
+ in_channels (int): Input data's channel number.
+ override_params (other key word params):
+ Params to override model's global_params.
+ Optional key:
+ 'width_coefficient', 'depth_coefficient',
+ 'image_size', 'dropout_rate',
+ 'num_classes', 'batch_norm_momentum',
+ 'batch_norm_epsilon', 'drop_connect_rate',
+ 'depth_divisor', 'min_depth'
+ Returns:
+ An efficientnet model.
+ """
+ cls._check_model_name_is_valid(model_name)
+ blocks_args, global_params = get_model_params(model_name, override_params)
+ model = cls(blocks_args, global_params)
+ model._change_in_channels(in_channels)
+ return model
+
+ def load_matching_state_dict(self, state_dict):
+
+ for name, param in state_dict.items():
+ if "efficient_net" in name:
+ name = name.split("efficient_net.")[1]
+
+ if name not in self.state_dict():
+ continue
+ if isinstance(param, torch.nn.parameter.Parameter):
+ param = param.data
+ self.state_dict()[name].copy_(param)
+
+ @classmethod
+ def from_pretrained(cls, model_name, weights_path=None, advprop=False,
+ in_channels=3, num_classes=1000, **override_params):
+ """Create an efficientnet model according to name.
+ Args:
+ model_name (str): Name for efficientnet.
+ weights_path (None or str):
+ str: path to pretrained weights file on the local disk.
+ None: use pretrained weights downloaded from the Internet.
+ advprop (bool):
+ Whether to load pretrained weights
+ trained with advprop (valid when weights_path is None).
+ in_channels (int): Input data's channel number.
+ num_classes (int):
+ Number of categories for classification.
+ It controls the output size for final linear layer.
+ override_params (other key word params):
+ Params to override model's global_params.
+ Optional key:
+ 'width_coefficient', 'depth_coefficient',
+ 'image_size', 'dropout_rate',
+ 'batch_norm_momentum',
+ 'batch_norm_epsilon', 'drop_connect_rate',
+ 'depth_divisor', 'min_depth'
+ Returns:
+ A pretrained efficientnet model.
+ """
+ model = cls.from_name(model_name, num_classes=num_classes, **override_params)
+ load_pretrained_weights(model, model_name, weights_path=weights_path,
+ load_fc=(num_classes == 1000), advprop=advprop)
+ model._change_in_channels(in_channels)
+ return model
+
+ @classmethod
+ def get_image_size(cls, model_name):
+ """Get the input image size for a given efficientnet model.
+ Args:
+ model_name (str): Name for efficientnet.
+ Returns:
+ Input image size (resolution).
+ """
+ cls._check_model_name_is_valid(model_name)
+ _, _, res, _ = efficientnet_params(model_name)
+ return res
+
+ @classmethod
+ def _check_model_name_is_valid(cls, model_name):
+ """Validates model name.
+ Args:
+ model_name (str): Name for efficientnet.
+ Returns:
+ bool: Is a valid name or not.
+ """
+ if model_name not in VALID_MODELS:
+ raise ValueError('model_name should be one of: ' + ', '.join(VALID_MODELS))
+
+ def _change_in_channels(self, in_channels):
+ """Adjust model's first convolution layer to in_channels, if in_channels not equals 3.
+ Args:
+ in_channels (int): Input data's channel number.
+ """
+ if in_channels != 3:
+ Conv2d = get_same_padding_conv2d(image_size=self._global_params.image_size)
+ out_channels = round_filters(32, self._global_params)
+ self._conv_stem = Conv2d(in_channels, out_channels, kernel_size=3, stride=2, bias=False)
\ No newline at end of file
diff --git a/clean/video/mintime/models/efficientnet/efficientnet_pytorch/utils.py b/clean/video/mintime/models/efficientnet/efficientnet_pytorch/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..826a62790920706d2c9f742fbe18386bf712ae4b
--- /dev/null
+++ b/clean/video/mintime/models/efficientnet/efficientnet_pytorch/utils.py
@@ -0,0 +1,616 @@
+"""utils.py - Helper functions for building the model and for loading model parameters.
+ These helper functions are built to mirror those in the official TensorFlow implementation.
+"""
+
+# Author: lukemelas (github username)
+# Github repo: https://github.com/lukemelas/EfficientNet-PyTorch
+# With adjustments and added comments by workingcoder (github username).
+
+import re
+import math
+import collections
+from functools import partial
+import torch
+from torch import nn
+from torch.nn import functional as F
+from torch.utils import model_zoo
+
+
+################################################################################
+# Help functions for model architecture
+################################################################################
+
+# GlobalParams and BlockArgs: Two namedtuples
+# Swish and MemoryEfficientSwish: Two implementations of the method
+# round_filters and round_repeats:
+# Functions to calculate params for scaling model width and depth ! ! !
+# get_width_and_height_from_size and calculate_output_image_size
+# drop_connect: A structural design
+# get_same_padding_conv2d:
+# Conv2dDynamicSamePadding
+# Conv2dStaticSamePadding
+# get_same_padding_maxPool2d:
+# MaxPool2dDynamicSamePadding
+# MaxPool2dStaticSamePadding
+# It's an additional function, not used in EfficientNet,
+# but can be used in other model (such as EfficientDet).
+
+# Parameters for the entire model (stem, all blocks, and head)
+GlobalParams = collections.namedtuple('GlobalParams', [
+ 'width_coefficient', 'depth_coefficient', 'image_size', 'dropout_rate',
+ 'num_classes', 'batch_norm_momentum', 'batch_norm_epsilon',
+ 'drop_connect_rate', 'depth_divisor', 'min_depth', 'include_top'])
+
+# Parameters for an individual model block
+BlockArgs = collections.namedtuple('BlockArgs', [
+ 'num_repeat', 'kernel_size', 'stride', 'expand_ratio',
+ 'input_filters', 'output_filters', 'se_ratio', 'id_skip'])
+
+# Set GlobalParams and BlockArgs's defaults
+GlobalParams.__new__.__defaults__ = (None,) * len(GlobalParams._fields)
+BlockArgs.__new__.__defaults__ = (None,) * len(BlockArgs._fields)
+
+# Swish activation function
+if hasattr(nn, 'SiLU'):
+ Swish = nn.SiLU
+else:
+ # For compatibility with old PyTorch versions
+ class Swish(nn.Module):
+ def forward(self, x):
+ return x * torch.sigmoid(x)
+
+
+# A memory-efficient implementation of Swish function
+class SwishImplementation(torch.autograd.Function):
+ @staticmethod
+ def forward(ctx, i):
+ result = i * torch.sigmoid(i)
+ ctx.save_for_backward(i)
+ return result
+
+ @staticmethod
+ def backward(ctx, grad_output):
+ i = ctx.saved_tensors[0]
+ sigmoid_i = torch.sigmoid(i)
+ return grad_output * (sigmoid_i * (1 + i * (1 - sigmoid_i)))
+
+
+class MemoryEfficientSwish(nn.Module):
+ def forward(self, x):
+ return SwishImplementation.apply(x)
+
+
+def round_filters(filters, global_params):
+ """Calculate and round number of filters based on width multiplier.
+ Use width_coefficient, depth_divisor and min_depth of global_params.
+
+ Args:
+ filters (int): Filters number to be calculated.
+ global_params (namedtuple): Global params of the model.
+
+ Returns:
+ new_filters: New filters number after calculating.
+ """
+ multiplier = global_params.width_coefficient
+ if not multiplier:
+ return filters
+ # TODO: modify the params names.
+ # maybe the names (width_divisor,min_width)
+ # are more suitable than (depth_divisor,min_depth).
+ divisor = global_params.depth_divisor
+ min_depth = global_params.min_depth
+ filters *= multiplier
+ min_depth = min_depth or divisor # pay attention to this line when using min_depth
+ # follow the formula transferred from official TensorFlow implementation
+ new_filters = max(min_depth, int(filters + divisor / 2) // divisor * divisor)
+ if new_filters < 0.9 * filters: # prevent rounding by more than 10%
+ new_filters += divisor
+ return int(new_filters)
+
+
+def round_repeats(repeats, global_params):
+ """Calculate module's repeat number of a block based on depth multiplier.
+ Use depth_coefficient of global_params.
+
+ Args:
+ repeats (int): num_repeat to be calculated.
+ global_params (namedtuple): Global params of the model.
+
+ Returns:
+ new repeat: New repeat number after calculating.
+ """
+ multiplier = global_params.depth_coefficient
+ if not multiplier:
+ return repeats
+ # follow the formula transferred from official TensorFlow implementation
+ return int(math.ceil(multiplier * repeats))
+
+
+def drop_connect(inputs, p, training):
+ """Drop connect.
+
+ Args:
+ input (tensor: BCWH): Input of this structure.
+ p (float: 0.0~1.0): Probability of drop connection.
+ training (bool): The running mode.
+
+ Returns:
+ output: Output after drop connection.
+ """
+ assert 0 <= p <= 1, 'p must be in range of [0,1]'
+
+ if not training:
+ return inputs
+
+ batch_size = inputs.shape[0]
+ keep_prob = 1 - p
+
+ # generate binary_tensor mask according to probability (p for 0, 1-p for 1)
+ random_tensor = keep_prob
+ random_tensor += torch.rand([batch_size, 1, 1, 1], dtype=inputs.dtype, device=inputs.device)
+ binary_tensor = torch.floor(random_tensor)
+
+ output = inputs / keep_prob * binary_tensor
+ return output
+
+
+def get_width_and_height_from_size(x):
+ """Obtain height and width from x.
+
+ Args:
+ x (int, tuple or list): Data size.
+
+ Returns:
+ size: A tuple or list (H,W).
+ """
+ if isinstance(x, int):
+ return x, x
+ if isinstance(x, list) or isinstance(x, tuple):
+ return x
+ else:
+ raise TypeError()
+
+
+def calculate_output_image_size(input_image_size, stride):
+ """Calculates the output image size when using Conv2dSamePadding with a stride.
+ Necessary for static padding. Thanks to mannatsingh for pointing this out.
+
+ Args:
+ input_image_size (int, tuple or list): Size of input image.
+ stride (int, tuple or list): Conv2d operation's stride.
+
+ Returns:
+ output_image_size: A list [H,W].
+ """
+ if input_image_size is None:
+ return None
+ image_height, image_width = get_width_and_height_from_size(input_image_size)
+ stride = stride if isinstance(stride, int) else stride[0]
+ image_height = int(math.ceil(image_height / stride))
+ image_width = int(math.ceil(image_width / stride))
+ return [image_height, image_width]
+
+
+# Note:
+# The following 'SamePadding' functions make output size equal ceil(input size/stride).
+# Only when stride equals 1, can the output size be the same as input size.
+# Don't be confused by their function names ! ! !
+
+def get_same_padding_conv2d(image_size=None):
+ """Chooses static padding if you have specified an image size, and dynamic padding otherwise.
+ Static padding is necessary for ONNX exporting of models.
+
+ Args:
+ image_size (int or tuple): Size of the image.
+
+ Returns:
+ Conv2dDynamicSamePadding or Conv2dStaticSamePadding.
+ """
+ if image_size is None:
+ return Conv2dDynamicSamePadding
+ else:
+ return partial(Conv2dStaticSamePadding, image_size=image_size)
+
+
+class Conv2dDynamicSamePadding(nn.Conv2d):
+ """2D Convolutions like TensorFlow, for a dynamic image size.
+ The padding is operated in forward function by calculating dynamically.
+ """
+
+ # Tips for 'SAME' mode padding.
+ # Given the following:
+ # i: width or height
+ # s: stride
+ # k: kernel size
+ # d: dilation
+ # p: padding
+ # Output after Conv2d:
+ # o = floor((i+p-((k-1)*d+1))/s+1)
+ # If o equals i, i = floor((i+p-((k-1)*d+1))/s+1),
+ # => p = (i-1)*s+((k-1)*d+1)-i
+
+ def __init__(self, in_channels, out_channels, kernel_size, stride=1, dilation=1, groups=1, bias=True):
+ super().__init__(in_channels, out_channels, kernel_size, stride, 0, dilation, groups, bias)
+ self.stride = self.stride if len(self.stride) == 2 else [self.stride[0]] * 2
+
+ def forward(self, x):
+ ih, iw = x.size()[-2:]
+ kh, kw = self.weight.size()[-2:]
+ sh, sw = self.stride
+ oh, ow = math.ceil(ih / sh), math.ceil(iw / sw) # change the output size according to stride ! ! !
+ pad_h = max((oh - 1) * self.stride[0] + (kh - 1) * self.dilation[0] + 1 - ih, 0)
+ pad_w = max((ow - 1) * self.stride[1] + (kw - 1) * self.dilation[1] + 1 - iw, 0)
+ if pad_h > 0 or pad_w > 0:
+ x = F.pad(x, [pad_w // 2, pad_w - pad_w // 2, pad_h // 2, pad_h - pad_h // 2])
+ return F.conv2d(x, self.weight, self.bias, self.stride, self.padding, self.dilation, self.groups)
+
+
+class Conv2dStaticSamePadding(nn.Conv2d):
+ """2D Convolutions like TensorFlow's 'SAME' mode, with the given input image size.
+ The padding mudule is calculated in construction function, then used in forward.
+ """
+
+ # With the same calculation as Conv2dDynamicSamePadding
+
+ def __init__(self, in_channels, out_channels, kernel_size, stride=1, image_size=None, **kwargs):
+ super().__init__(in_channels, out_channels, kernel_size, stride, **kwargs)
+ self.stride = self.stride if len(self.stride) == 2 else [self.stride[0]] * 2
+
+ # Calculate padding based on image size and save it
+ assert image_size is not None
+ ih, iw = (image_size, image_size) if isinstance(image_size, int) else image_size
+ kh, kw = self.weight.size()[-2:]
+ sh, sw = self.stride
+ oh, ow = math.ceil(ih / sh), math.ceil(iw / sw)
+ pad_h = max((oh - 1) * self.stride[0] + (kh - 1) * self.dilation[0] + 1 - ih, 0)
+ pad_w = max((ow - 1) * self.stride[1] + (kw - 1) * self.dilation[1] + 1 - iw, 0)
+ if pad_h > 0 or pad_w > 0:
+ self.static_padding = nn.ZeroPad2d((pad_w // 2, pad_w - pad_w // 2,
+ pad_h // 2, pad_h - pad_h // 2))
+ else:
+ self.static_padding = nn.Identity()
+
+ def forward(self, x):
+ x = self.static_padding(x)
+ x = F.conv2d(x, self.weight, self.bias, self.stride, self.padding, self.dilation, self.groups)
+ return x
+
+
+def get_same_padding_maxPool2d(image_size=None):
+ """Chooses static padding if you have specified an image size, and dynamic padding otherwise.
+ Static padding is necessary for ONNX exporting of models.
+
+ Args:
+ image_size (int or tuple): Size of the image.
+
+ Returns:
+ MaxPool2dDynamicSamePadding or MaxPool2dStaticSamePadding.
+ """
+ if image_size is None:
+ return MaxPool2dDynamicSamePadding
+ else:
+ return partial(MaxPool2dStaticSamePadding, image_size=image_size)
+
+
+class MaxPool2dDynamicSamePadding(nn.MaxPool2d):
+ """2D MaxPooling like TensorFlow's 'SAME' mode, with a dynamic image size.
+ The padding is operated in forward function by calculating dynamically.
+ """
+
+ def __init__(self, kernel_size, stride, padding=0, dilation=1, return_indices=False, ceil_mode=False):
+ super().__init__(kernel_size, stride, padding, dilation, return_indices, ceil_mode)
+ self.stride = [self.stride] * 2 if isinstance(self.stride, int) else self.stride
+ self.kernel_size = [self.kernel_size] * 2 if isinstance(self.kernel_size, int) else self.kernel_size
+ self.dilation = [self.dilation] * 2 if isinstance(self.dilation, int) else self.dilation
+
+ def forward(self, x):
+ ih, iw = x.size()[-2:]
+ kh, kw = self.kernel_size
+ sh, sw = self.stride
+ oh, ow = math.ceil(ih / sh), math.ceil(iw / sw)
+ pad_h = max((oh - 1) * self.stride[0] + (kh - 1) * self.dilation[0] + 1 - ih, 0)
+ pad_w = max((ow - 1) * self.stride[1] + (kw - 1) * self.dilation[1] + 1 - iw, 0)
+ if pad_h > 0 or pad_w > 0:
+ x = F.pad(x, [pad_w // 2, pad_w - pad_w // 2, pad_h // 2, pad_h - pad_h // 2])
+ return F.max_pool2d(x, self.kernel_size, self.stride, self.padding,
+ self.dilation, self.ceil_mode, self.return_indices)
+
+
+class MaxPool2dStaticSamePadding(nn.MaxPool2d):
+ """2D MaxPooling like TensorFlow's 'SAME' mode, with the given input image size.
+ The padding mudule is calculated in construction function, then used in forward.
+ """
+
+ def __init__(self, kernel_size, stride, image_size=None, **kwargs):
+ super().__init__(kernel_size, stride, **kwargs)
+ self.stride = [self.stride] * 2 if isinstance(self.stride, int) else self.stride
+ self.kernel_size = [self.kernel_size] * 2 if isinstance(self.kernel_size, int) else self.kernel_size
+ self.dilation = [self.dilation] * 2 if isinstance(self.dilation, int) else self.dilation
+
+ # Calculate padding based on image size and save it
+ assert image_size is not None
+ ih, iw = (image_size, image_size) if isinstance(image_size, int) else image_size
+ kh, kw = self.kernel_size
+ sh, sw = self.stride
+ oh, ow = math.ceil(ih / sh), math.ceil(iw / sw)
+ pad_h = max((oh - 1) * self.stride[0] + (kh - 1) * self.dilation[0] + 1 - ih, 0)
+ pad_w = max((ow - 1) * self.stride[1] + (kw - 1) * self.dilation[1] + 1 - iw, 0)
+ if pad_h > 0 or pad_w > 0:
+ self.static_padding = nn.ZeroPad2d((pad_w // 2, pad_w - pad_w // 2, pad_h // 2, pad_h - pad_h // 2))
+ else:
+ self.static_padding = nn.Identity()
+
+ def forward(self, x):
+ x = self.static_padding(x)
+ x = F.max_pool2d(x, self.kernel_size, self.stride, self.padding,
+ self.dilation, self.ceil_mode, self.return_indices)
+ return x
+
+
+################################################################################
+# Helper functions for loading model params
+################################################################################
+
+# BlockDecoder: A Class for encoding and decoding BlockArgs
+# efficientnet_params: A function to query compound coefficient
+# get_model_params and efficientnet:
+# Functions to get BlockArgs and GlobalParams for efficientnet
+# url_map and url_map_advprop: Dicts of url_map for pretrained weights
+# load_pretrained_weights: A function to load pretrained weights
+
+class BlockDecoder(object):
+ """Block Decoder for readability,
+ straight from the official TensorFlow repository.
+ """
+
+ @staticmethod
+ def _decode_block_string(block_string):
+ """Get a block through a string notation of arguments.
+
+ Args:
+ block_string (str): A string notation of arguments.
+ Examples: 'r1_k3_s11_e1_i32_o16_se0.25_noskip'.
+
+ Returns:
+ BlockArgs: The namedtuple defined at the top of this file.
+ """
+ assert isinstance(block_string, str)
+
+ ops = block_string.split('_')
+ options = {}
+ for op in ops:
+ splits = re.split(r'(\d.*)', op)
+ if len(splits) >= 2:
+ key, value = splits[:2]
+ options[key] = value
+
+ # Check stride
+ assert (('s' in options and len(options['s']) == 1) or
+ (len(options['s']) == 2 and options['s'][0] == options['s'][1]))
+
+ return BlockArgs(
+ num_repeat=int(options['r']),
+ kernel_size=int(options['k']),
+ stride=[int(options['s'][0])],
+ expand_ratio=int(options['e']),
+ input_filters=int(options['i']),
+ output_filters=int(options['o']),
+ se_ratio=float(options['se']) if 'se' in options else None,
+ id_skip=('noskip' not in block_string))
+
+ @staticmethod
+ def _encode_block_string(block):
+ """Encode a block to a string.
+
+ Args:
+ block (namedtuple): A BlockArgs type argument.
+
+ Returns:
+ block_string: A String form of BlockArgs.
+ """
+ args = [
+ 'r%d' % block.num_repeat,
+ 'k%d' % block.kernel_size,
+ 's%d%d' % (block.strides[0], block.strides[1]),
+ 'e%s' % block.expand_ratio,
+ 'i%d' % block.input_filters,
+ 'o%d' % block.output_filters
+ ]
+ if 0 < block.se_ratio <= 1:
+ args.append('se%s' % block.se_ratio)
+ if block.id_skip is False:
+ args.append('noskip')
+ return '_'.join(args)
+
+ @staticmethod
+ def decode(string_list):
+ """Decode a list of string notations to specify blocks inside the network.
+
+ Args:
+ string_list (list[str]): A list of strings, each string is a notation of block.
+
+ Returns:
+ blocks_args: A list of BlockArgs namedtuples of block args.
+ """
+ assert isinstance(string_list, list)
+ blocks_args = []
+ for block_string in string_list:
+ blocks_args.append(BlockDecoder._decode_block_string(block_string))
+ return blocks_args
+
+ @staticmethod
+ def encode(blocks_args):
+ """Encode a list of BlockArgs to a list of strings.
+
+ Args:
+ blocks_args (list[namedtuples]): A list of BlockArgs namedtuples of block args.
+
+ Returns:
+ block_strings: A list of strings, each string is a notation of block.
+ """
+ block_strings = []
+ for block in blocks_args:
+ block_strings.append(BlockDecoder._encode_block_string(block))
+ return block_strings
+
+
+def efficientnet_params(model_name):
+ """Map EfficientNet model name to parameter coefficients.
+
+ Args:
+ model_name (str): Model name to be queried.
+
+ Returns:
+ params_dict[model_name]: A (width,depth,res,dropout) tuple.
+ """
+ params_dict = {
+ # Coefficients: width,depth,res,dropout
+ 'efficientnet-b0': (1.0, 1.0, 224, 0.2),
+ 'efficientnet-b1': (1.0, 1.1, 240, 0.2),
+ 'efficientnet-b2': (1.1, 1.2, 260, 0.3),
+ 'efficientnet-b3': (1.2, 1.4, 300, 0.3),
+ 'efficientnet-b4': (1.4, 1.8, 380, 0.4),
+ 'efficientnet-b5': (1.6, 2.2, 456, 0.4),
+ 'efficientnet-b6': (1.8, 2.6, 528, 0.5),
+ 'efficientnet-b7': (2.0, 3.1, 600, 0.5),
+ 'efficientnet-b8': (2.2, 3.6, 672, 0.5),
+ 'efficientnet-l2': (4.3, 5.3, 800, 0.5),
+ }
+ return params_dict[model_name]
+
+
+def efficientnet(width_coefficient=None, depth_coefficient=None, image_size=None,
+ dropout_rate=0.2, drop_connect_rate=0.2, num_classes=1000, include_top=True):
+ """Create BlockArgs and GlobalParams for efficientnet model.
+
+ Args:
+ width_coefficient (float)
+ depth_coefficient (float)
+ image_size (int)
+ dropout_rate (float)
+ drop_connect_rate (float)
+ num_classes (int)
+
+ Meaning as the name suggests.
+
+ Returns:
+ blocks_args, global_params.
+ """
+
+ # Blocks args for the whole model(efficientnet-b0 by default)
+ # It will be modified in the construction of EfficientNet Class according to model
+ blocks_args = [
+ 'r1_k3_s11_e1_i32_o16_se0.25',
+ 'r2_k3_s22_e6_i16_o24_se0.25',
+ 'r2_k5_s22_e6_i24_o40_se0.25',
+ 'r3_k3_s22_e6_i40_o80_se0.25',
+ 'r3_k5_s11_e6_i80_o112_se0.25',
+ 'r4_k5_s22_e6_i112_o192_se0.25',
+ 'r1_k3_s11_e6_i192_o320_se0.25',
+ ]
+ blocks_args = BlockDecoder.decode(blocks_args)
+
+ global_params = GlobalParams(
+ width_coefficient=width_coefficient,
+ depth_coefficient=depth_coefficient,
+ image_size=image_size,
+ dropout_rate=dropout_rate,
+
+ num_classes=num_classes,
+ batch_norm_momentum=0.99,
+ batch_norm_epsilon=1e-3,
+ drop_connect_rate=drop_connect_rate,
+ depth_divisor=8,
+ min_depth=None,
+ include_top=include_top,
+ )
+
+ return blocks_args, global_params
+
+
+def get_model_params(model_name, override_params):
+ """Get the block args and global params for a given model name.
+
+ Args:
+ model_name (str): Model's name.
+ override_params (dict): A dict to modify global_params.
+
+ Returns:
+ blocks_args, global_params
+ """
+ if model_name.startswith('efficientnet'):
+ w, d, s, p = efficientnet_params(model_name)
+ # note: all models have drop connect rate = 0.2
+ blocks_args, global_params = efficientnet(
+ width_coefficient=w, depth_coefficient=d, dropout_rate=p, image_size=s)
+ else:
+ raise NotImplementedError('model name is not pre-defined: {}'.format(model_name))
+ if override_params:
+ # ValueError will be raised here if override_params has fields not included in global_params.
+ global_params = global_params._replace(**override_params)
+ return blocks_args, global_params
+
+
+# train with Standard methods
+# check more details in paper(EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks)
+url_map = {
+ 'efficientnet-b0': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b0-355c32eb.pth',
+ 'efficientnet-b1': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b1-f1951068.pth',
+ 'efficientnet-b2': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b2-8bb594d6.pth',
+ 'efficientnet-b3': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b3-5fb5a3c3.pth',
+ 'efficientnet-b4': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b4-6ed6700e.pth',
+ 'efficientnet-b5': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b5-b6417697.pth',
+ 'efficientnet-b6': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b6-c76e70fd.pth',
+ 'efficientnet-b7': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b7-dcc49843.pth',
+}
+
+# train with Adversarial Examples(AdvProp)
+# check more details in paper(Adversarial Examples Improve Image Recognition)
+url_map_advprop = {
+ 'efficientnet-b0': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b0-b64d5a18.pth',
+ 'efficientnet-b1': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b1-0f3ce85a.pth',
+ 'efficientnet-b2': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b2-6e9d97e5.pth',
+ 'efficientnet-b3': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b3-cdd7c0f4.pth',
+ 'efficientnet-b4': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b4-44fb3a87.pth',
+ 'efficientnet-b5': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b5-86493f6b.pth',
+ 'efficientnet-b6': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b6-ac80338e.pth',
+ 'efficientnet-b7': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b7-4652b6dd.pth',
+ 'efficientnet-b8': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b8-22a8fe65.pth',
+}
+
+# TODO: add the petrained weights url map of 'efficientnet-l2'
+
+
+def load_pretrained_weights(model, model_name, weights_path=None, load_fc=True, advprop=False, verbose=True):
+ """Loads pretrained weights from weights path or download using url.
+
+ Args:
+ model (Module): The whole model of efficientnet.
+ model_name (str): Model name of efficientnet.
+ weights_path (None or str):
+ str: path to pretrained weights file on the local disk.
+ None: use pretrained weights downloaded from the Internet.
+ load_fc (bool): Whether to load pretrained weights for fc layer at the end of the model.
+ advprop (bool): Whether to load pretrained weights
+ trained with advprop (valid when weights_path is None).
+ """
+ if isinstance(weights_path, str):
+ state_dict = torch.load(weights_path)
+ else:
+ # AutoAugment or Advprop (different preprocessing)
+ url_map_ = url_map_advprop if advprop else url_map
+ state_dict = model_zoo.load_url(url_map_[model_name])
+
+ if load_fc:
+ ret = model.load_state_dict(state_dict, strict=False)
+ assert not ret.missing_keys, 'Missing keys when loading pretrained weights: {}'.format(ret.missing_keys)
+ else:
+ state_dict.pop('_fc.weight')
+ state_dict.pop('_fc.bias')
+ ret = model.load_state_dict(state_dict, strict=False)
+ assert set(ret.missing_keys) == set(
+ ['_fc.weight', '_fc.bias']), 'Missing keys when loading pretrained weights: {}'.format(ret.missing_keys)
+ assert not ret.unexpected_keys, 'Missing keys when loading pretrained weights: {}'.format(ret.unexpected_keys)
+
+ if verbose:
+ print('Loaded pretrained weights for {}'.format(model_name))
diff --git a/clean/video/mintime/models/efficientnet/hubconf.py b/clean/video/mintime/models/efficientnet/hubconf.py
new file mode 100644
index 0000000000000000000000000000000000000000..dd0ea978cabcc7676bff4fcd18e7a0555eda98ab
--- /dev/null
+++ b/clean/video/mintime/models/efficientnet/hubconf.py
@@ -0,0 +1,43 @@
+from efficientnet_pytorch import EfficientNet as _EfficientNet
+
+dependencies = ['torch']
+
+
+def _create_model_fn(model_name):
+ def _model_fn(num_classes=1000, in_channels=3, pretrained='imagenet'):
+ """Create Efficient Net.
+
+ Described in detail here: https://arxiv.org/abs/1905.11946
+
+ Args:
+ num_classes (int, optional): Number of classes, default is 1000.
+ in_channels (int, optional): Number of input channels, default
+ is 3.
+ pretrained (str, optional): One of [None, 'imagenet', 'advprop']
+ If None, no pretrained model is loaded.
+ If 'imagenet', models trained on imagenet dataset are loaded.
+ If 'advprop', models trained using adversarial training called
+ advprop are loaded. It is important to note that the
+ preprocessing required for the advprop pretrained models is
+ slightly different from normal ImageNet preprocessing
+ """
+ model_name_ = model_name.replace('_', '-')
+ if pretrained is not None:
+ model = _EfficientNet.from_pretrained(
+ model_name=model_name_,
+ advprop=(pretrained == 'advprop'),
+ num_classes=num_classes,
+ in_channels=in_channels)
+ else:
+ model = _EfficientNet.from_name(
+ model_name=model_name_,
+ override_params={'num_classes': num_classes},
+ )
+ model._change_in_channels(in_channels)
+
+ return model
+
+ return _model_fn
+
+for model_name in ['efficientnet_b' + str(i) for i in range(9)]:
+ locals()[model_name] = _create_model_fn(model_name)
diff --git a/clean/video/mintime/models/efficientnet/setup.py b/clean/video/mintime/models/efficientnet/setup.py
new file mode 100644
index 0000000000000000000000000000000000000000..eb8d95a136169d2178f6525965afac2ab2a824aa
--- /dev/null
+++ b/clean/video/mintime/models/efficientnet/setup.py
@@ -0,0 +1,123 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Note: To use the 'upload' functionality of this file, you must:
+# $ pipenv install twine --dev
+
+import io
+import os
+import sys
+from shutil import rmtree
+
+from setuptools import find_packages, setup, Command
+
+# Package meta-data.
+NAME = 'efficientnet_pytorch'
+DESCRIPTION = 'EfficientNet implemented in PyTorch.'
+URL = 'https://github.com/lukemelas/EfficientNet-PyTorch'
+EMAIL = 'lmelaskyriazi@college.harvard.edu'
+AUTHOR = 'Luke'
+REQUIRES_PYTHON = '>=3.5.0'
+VERSION = '0.7.1'
+
+# What packages are required for this module to be executed?
+REQUIRED = [
+ 'torch'
+]
+
+# What packages are optional?
+EXTRAS = {
+ # 'fancy feature': ['django'],
+}
+
+# The rest you shouldn't have to touch too much :)
+# ------------------------------------------------
+# Except, perhaps the License and Trove Classifiers!
+# If you do change the License, remember to change the Trove Classifier for that!
+
+here = os.path.abspath(os.path.dirname(__file__))
+
+# Import the README and use it as the long-description.
+# Note: this will only work if 'README.md' is present in your MANIFEST.in file!
+try:
+ with io.open(os.path.join(here, 'README.md'), encoding='utf-8') as f:
+ long_description = '\n' + f.read()
+except FileNotFoundError:
+ long_description = DESCRIPTION
+
+# Load the package's __version__.py module as a dictionary.
+about = {}
+if not VERSION:
+ project_slug = NAME.lower().replace("-", "_").replace(" ", "_")
+ with open(os.path.join(here, project_slug, '__version__.py')) as f:
+ exec(f.read(), about)
+else:
+ about['__version__'] = VERSION
+
+
+class UploadCommand(Command):
+ """Support setup.py upload."""
+
+ description = 'Build and publish the package.'
+ user_options = []
+
+ @staticmethod
+ def status(s):
+ """Prints things in bold."""
+ print('\033[1m{0}\033[0m'.format(s))
+
+ def initialize_options(self):
+ pass
+
+ def finalize_options(self):
+ pass
+
+ def run(self):
+ try:
+ self.status('Removing previous builds…')
+ rmtree(os.path.join(here, 'dist'))
+ except OSError:
+ pass
+
+ self.status('Building Source and Wheel (universal) distribution…')
+ os.system('{0} setup.py sdist bdist_wheel --universal'.format(sys.executable))
+
+ self.status('Uploading the package to PyPI via Twine…')
+ os.system('twine upload dist/*')
+
+ self.status('Pushing git tags…')
+ os.system('git tag v{0}'.format(about['__version__']))
+ os.system('git push --tags')
+
+ sys.exit()
+
+
+# Where the magic happens:
+setup(
+ name=NAME,
+ version=about['__version__'],
+ description=DESCRIPTION,
+ long_description=long_description,
+ long_description_content_type='text/markdown',
+ author=AUTHOR,
+ author_email=EMAIL,
+ python_requires=REQUIRES_PYTHON,
+ url=URL,
+ packages=find_packages(exclude=["tests", "*.tests", "*.tests.*", "tests.*"]),
+ # py_modules=['model'], # If your package is a single module, use this instead of 'packages'
+ install_requires=REQUIRED,
+ extras_require=EXTRAS,
+ include_package_data=True,
+ license='Apache',
+ classifiers=[
+ # Full list: https://pypi.python.org/pypi?%3Aaction=list_classifiers
+ 'License :: OSI Approved :: Apache Software License',
+ 'Programming Language :: Python',
+ 'Programming Language :: Python :: 3',
+ 'Programming Language :: Python :: 3.6',
+ ],
+ # $ setup.py publish support.
+ cmdclass={
+ 'upload': UploadCommand,
+ },
+)
diff --git a/clean/video/mintime/models/efficientnet/sotabench.py b/clean/video/mintime/models/efficientnet/sotabench.py
new file mode 100644
index 0000000000000000000000000000000000000000..67816ff301d8cae39dde534edf688eeb010320c8
--- /dev/null
+++ b/clean/video/mintime/models/efficientnet/sotabench.py
@@ -0,0 +1,71 @@
+import os
+import numpy as np
+import PIL
+import torch
+from torch.utils.data import DataLoader
+import torchvision.transforms as transforms
+from torchvision.datasets import ImageNet
+
+from efficientnet_pytorch import EfficientNet
+
+from sotabencheval.image_classification import ImageNetEvaluator
+from sotabencheval.utils import is_server
+
+if is_server():
+ DATA_ROOT = DATA_ROOT = os.environ.get('IMAGENET_DIR', './imagenet') # './.data/vision/imagenet'
+else: # local settings
+ DATA_ROOT = os.environ['IMAGENET_DIR']
+ assert bool(DATA_ROOT), 'please set IMAGENET_DIR environment variable'
+ print('Local data root: ', DATA_ROOT)
+
+model_name = 'EfficientNet-B5'
+model = EfficientNet.from_pretrained(model_name.lower())
+image_size = EfficientNet.get_image_size(model_name.lower())
+
+input_transform = transforms.Compose([
+ transforms.Resize(image_size, PIL.Image.BICUBIC),
+ transforms.CenterCrop(image_size),
+ transforms.ToTensor(),
+ transforms.Normalize(
+ mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
+])
+
+test_dataset = ImageNet(
+ DATA_ROOT,
+ split="val",
+ transform=input_transform,
+ target_transform=None,
+)
+
+test_loader = DataLoader(
+ test_dataset,
+ batch_size=128,
+ shuffle=False,
+ num_workers=4,
+ pin_memory=True,
+)
+
+model = model.cuda()
+model.eval()
+
+evaluator = ImageNetEvaluator(model_name=model_name,
+ paper_arxiv_id='1905.11946')
+
+def get_img_id(image_name):
+ return image_name.split('/')[-1].replace('.JPEG', '')
+
+with torch.no_grad():
+ for i, (input, target) in enumerate(test_loader):
+ input = input.to(device='cuda', non_blocking=True)
+ target = target.to(device='cuda', non_blocking=True)
+ output = model(input)
+ image_ids = [get_img_id(img[0]) for img in test_loader.dataset.imgs[i*test_loader.batch_size:(i+1)*test_loader.batch_size]]
+ evaluator.add(dict(zip(image_ids, list(output.cpu().numpy()))))
+ if evaluator.cache_exists:
+ break
+
+if not is_server():
+ print("Results:")
+ print(evaluator.get_results())
+
+evaluator.save()
diff --git a/clean/video/mintime/models/efficientnet/sotabench_setup.sh b/clean/video/mintime/models/efficientnet/sotabench_setup.sh
new file mode 100644
index 0000000000000000000000000000000000000000..e45bdeaebb0e1e9b27caa419b3a38623ffff5983
--- /dev/null
+++ b/clean/video/mintime/models/efficientnet/sotabench_setup.sh
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash -x
+source /workspace/venv/bin/activate
+PYTHON=${PYTHON:-"python"}
+$PYTHON -m pip install torch
+$PYTHON -m pip install torchvision
+$PYTHON -m pip install scipy
diff --git a/clean/video/mintime/models/efficientnet/tf_to_pytorch/README.md b/clean/video/mintime/models/efficientnet/tf_to_pytorch/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..9699aa807198df8a5b776fd35fce5052baaf6783
--- /dev/null
+++ b/clean/video/mintime/models/efficientnet/tf_to_pytorch/README.md
@@ -0,0 +1,25 @@
+### TensorFlow to PyTorch Conversion
+
+This directory is used to convert TensorFlow weights to PyTorch. It was hacked together fairly quickly, so the code is not the most beautiful (just a warning!), but it does the job. I will be refactoring it soon.
+
+I should also emphasize that you do *not* need to run any of this code to load pretrained weights. Simply use `EfficientNet.from_pretrained(...)`.
+
+That being said, the main script here is `convert_to_tf/load_tf_weights.py`. In order to use it, you should first download the pretrained TensorFlow weights:
+ ```bash
+cd pretrained_tensorflow
+./download.sh efficientnet-b0
+cd ..
+```
+Then
+```bash
+mkdir -p pretrained_pytorch
+cd convert_tf_to_pt
+python load_tf_weights.py \
+ --model_name efficientnet-b0 \
+ --tf_checkpoint ../pretrained_tensorflow/efficientnet-b0/ \
+ --output_file ../pretrained_pytorch/efficientnet-b0.pth
+```
+
+
diff --git a/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/download.sh b/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/download.sh
new file mode 100644
index 0000000000000000000000000000000000000000..6405dbd93e4f54338b1c7874ef89926491742f38
--- /dev/null
+++ b/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/download.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+
+mkdir original_tf
+cd original_tf
+touch __init__.py
+wget https://raw.githubusercontent.com/tensorflow/tpu/master/models/official/efficientnet/efficientnet_builder.py
+wget https://raw.githubusercontent.com/tensorflow/tpu/master/models/official/efficientnet/efficientnet_model.py
+wget https://raw.githubusercontent.com/tensorflow/tpu/master/models/official/efficientnet/eval_ckpt_main.py
+wget https://raw.githubusercontent.com/tensorflow/tpu/master/models/official/efficientnet/utils.py
+wget https://raw.githubusercontent.com/tensorflow/tpu/master/models/official/efficientnet/preprocessing.py
+cd ..
+mkdir -p tmp
\ No newline at end of file
diff --git a/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/load_tf_weights.py b/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/load_tf_weights.py
new file mode 100644
index 0000000000000000000000000000000000000000..22e296e87558b521a3c60f8de3c4a8031743d1b4
--- /dev/null
+++ b/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/load_tf_weights.py
@@ -0,0 +1,174 @@
+import numpy as np
+import tensorflow as tf
+import torch
+
+tf.compat.v1.disable_v2_behavior()
+
+def load_param(checkpoint_file, conversion_table, model_name):
+ """
+ Load parameters according to conversion_table.
+
+ Args:
+ checkpoint_file (string): pretrained checkpoint model file in tensorflow
+ conversion_table (dict): { pytorch tensor in a model : checkpoint variable name }
+ """
+ for pyt_param, tf_param_name in conversion_table.items():
+ tf_param_name = str(model_name) + '/' + tf_param_name
+ tf_param = tf.train.load_variable(checkpoint_file, tf_param_name)
+ if 'conv' in tf_param_name and 'kernel' in tf_param_name:
+ tf_param = np.transpose(tf_param, (3, 2, 0, 1))
+ if 'depthwise' in tf_param_name:
+ tf_param = np.transpose(tf_param, (1, 0, 2, 3))
+ elif tf_param_name.endswith('kernel'): # for weight(kernel), we should do transpose
+ tf_param = np.transpose(tf_param)
+ assert pyt_param.size() == tf_param.shape, \
+ 'Dim Mismatch: %s vs %s ; %s' % (tuple(pyt_param.size()), tf_param.shape, tf_param_name)
+ pyt_param.data = torch.from_numpy(tf_param)
+
+
+def load_efficientnet(model, checkpoint_file, model_name):
+ """
+ Load PyTorch EfficientNet from TensorFlow checkpoint file
+ """
+
+ # This will store the enire conversion table
+ conversion_table = {}
+ merge = lambda dict1, dict2: {**dict1, **dict2}
+
+ # All the weights not in the conv blocks
+ conversion_table_for_weights_outside_blocks = {
+ model._conv_stem.weight: 'stem/conv2d/kernel', # [3, 3, 3, 32]),
+ model._bn0.bias: 'stem/tpu_batch_normalization/beta', # [32]),
+ model._bn0.weight: 'stem/tpu_batch_normalization/gamma', # [32]),
+ model._bn0.running_mean: 'stem/tpu_batch_normalization/moving_mean', # [32]),
+ model._bn0.running_var: 'stem/tpu_batch_normalization/moving_variance', # [32]),
+ model._conv_head.weight: 'head/conv2d/kernel', # [1, 1, 320, 1280]),
+ model._bn1.bias: 'head/tpu_batch_normalization/beta', # [1280]),
+ model._bn1.weight: 'head/tpu_batch_normalization/gamma', # [1280]),
+ model._bn1.running_mean: 'head/tpu_batch_normalization/moving_mean', # [32]),
+ model._bn1.running_var: 'head/tpu_batch_normalization/moving_variance', # [32]),
+ model._fc.bias: 'head/dense/bias', # [1000]),
+ model._fc.weight: 'head/dense/kernel', # [1280, 1000]),
+ }
+ conversion_table = merge(conversion_table, conversion_table_for_weights_outside_blocks)
+
+ # The first conv block is special because it does not have _expand_conv
+ conversion_table_for_first_block = {
+ model._blocks[0]._project_conv.weight: 'blocks_0/conv2d/kernel', # 1, 1, 32, 16]),
+ model._blocks[0]._depthwise_conv.weight: 'blocks_0/depthwise_conv2d/depthwise_kernel', # [3, 3, 32, 1]),
+ model._blocks[0]._se_reduce.bias: 'blocks_0/se/conv2d/bias', # , [8]),
+ model._blocks[0]._se_reduce.weight: 'blocks_0/se/conv2d/kernel', # , [1, 1, 32, 8]),
+ model._blocks[0]._se_expand.bias: 'blocks_0/se/conv2d_1/bias', # , [32]),
+ model._blocks[0]._se_expand.weight: 'blocks_0/se/conv2d_1/kernel', # , [1, 1, 8, 32]),
+ model._blocks[0]._bn1.bias: 'blocks_0/tpu_batch_normalization/beta', # [32]),
+ model._blocks[0]._bn1.weight: 'blocks_0/tpu_batch_normalization/gamma', # [32]),
+ model._blocks[0]._bn1.running_mean: 'blocks_0/tpu_batch_normalization/moving_mean',
+ model._blocks[0]._bn1.running_var: 'blocks_0/tpu_batch_normalization/moving_variance',
+ model._blocks[0]._bn2.bias: 'blocks_0/tpu_batch_normalization_1/beta', # [16]),
+ model._blocks[0]._bn2.weight: 'blocks_0/tpu_batch_normalization_1/gamma', # [16]),
+ model._blocks[0]._bn2.running_mean: 'blocks_0/tpu_batch_normalization_1/moving_mean',
+ model._blocks[0]._bn2.running_var: 'blocks_0/tpu_batch_normalization_1/moving_variance',
+ }
+ conversion_table = merge(conversion_table, conversion_table_for_first_block)
+
+ # Conv blocks
+ for i in range(len(model._blocks)):
+
+ is_first_block = '_expand_conv.weight' not in [n for n, p in model._blocks[i].named_parameters()]
+
+ if is_first_block:
+ conversion_table_block = {
+ model._blocks[i]._project_conv.weight: 'blocks_' + str(i) + '/conv2d/kernel', # 1, 1, 32, 16]),
+ model._blocks[i]._depthwise_conv.weight: 'blocks_' + str(i) + '/depthwise_conv2d/depthwise_kernel',
+ # [3, 3, 32, 1]),
+ model._blocks[i]._se_reduce.bias: 'blocks_' + str(i) + '/se/conv2d/bias', # , [8]),
+ model._blocks[i]._se_reduce.weight: 'blocks_' + str(i) + '/se/conv2d/kernel', # , [1, 1, 32, 8]),
+ model._blocks[i]._se_expand.bias: 'blocks_' + str(i) + '/se/conv2d_1/bias', # , [32]),
+ model._blocks[i]._se_expand.weight: 'blocks_' + str(i) + '/se/conv2d_1/kernel', # , [1, 1, 8, 32]),
+ model._blocks[i]._bn1.bias: 'blocks_' + str(i) + '/tpu_batch_normalization/beta', # [32]),
+ model._blocks[i]._bn1.weight: 'blocks_' + str(i) + '/tpu_batch_normalization/gamma', # [32]),
+ model._blocks[i]._bn1.running_mean: 'blocks_' + str(i) + '/tpu_batch_normalization/moving_mean',
+ model._blocks[i]._bn1.running_var: 'blocks_' + str(i) + '/tpu_batch_normalization/moving_variance',
+ model._blocks[i]._bn2.bias: 'blocks_' + str(i) + '/tpu_batch_normalization_1/beta', # [16]),
+ model._blocks[i]._bn2.weight: 'blocks_' + str(i) + '/tpu_batch_normalization_1/gamma', # [16]),
+ model._blocks[i]._bn2.running_mean: 'blocks_' + str(i) + '/tpu_batch_normalization_1/moving_mean',
+ model._blocks[i]._bn2.running_var: 'blocks_' + str(i) + '/tpu_batch_normalization_1/moving_variance',
+ }
+
+ else:
+ conversion_table_block = {
+ model._blocks[i]._expand_conv.weight: 'blocks_' + str(i) + '/conv2d/kernel',
+ model._blocks[i]._project_conv.weight: 'blocks_' + str(i) + '/conv2d_1/kernel',
+ model._blocks[i]._depthwise_conv.weight: 'blocks_' + str(i) + '/depthwise_conv2d/depthwise_kernel',
+ model._blocks[i]._se_reduce.bias: 'blocks_' + str(i) + '/se/conv2d/bias',
+ model._blocks[i]._se_reduce.weight: 'blocks_' + str(i) + '/se/conv2d/kernel',
+ model._blocks[i]._se_expand.bias: 'blocks_' + str(i) + '/se/conv2d_1/bias',
+ model._blocks[i]._se_expand.weight: 'blocks_' + str(i) + '/se/conv2d_1/kernel',
+ model._blocks[i]._bn0.bias: 'blocks_' + str(i) + '/tpu_batch_normalization/beta',
+ model._blocks[i]._bn0.weight: 'blocks_' + str(i) + '/tpu_batch_normalization/gamma',
+ model._blocks[i]._bn0.running_mean: 'blocks_' + str(i) + '/tpu_batch_normalization/moving_mean',
+ model._blocks[i]._bn0.running_var: 'blocks_' + str(i) + '/tpu_batch_normalization/moving_variance',
+ model._blocks[i]._bn1.bias: 'blocks_' + str(i) + '/tpu_batch_normalization_1/beta',
+ model._blocks[i]._bn1.weight: 'blocks_' + str(i) + '/tpu_batch_normalization_1/gamma',
+ model._blocks[i]._bn1.running_mean: 'blocks_' + str(i) + '/tpu_batch_normalization_1/moving_mean',
+ model._blocks[i]._bn1.running_var: 'blocks_' + str(i) + '/tpu_batch_normalization_1/moving_variance',
+ model._blocks[i]._bn2.bias: 'blocks_' + str(i) + '/tpu_batch_normalization_2/beta',
+ model._blocks[i]._bn2.weight: 'blocks_' + str(i) + '/tpu_batch_normalization_2/gamma',
+ model._blocks[i]._bn2.running_mean: 'blocks_' + str(i) + '/tpu_batch_normalization_2/moving_mean',
+ model._blocks[i]._bn2.running_var: 'blocks_' + str(i) + '/tpu_batch_normalization_2/moving_variance',
+ }
+
+ conversion_table = merge(conversion_table, conversion_table_block)
+
+ # Load TensorFlow parameters into PyTorch model
+ load_param(checkpoint_file, conversion_table, model_name)
+ return conversion_table
+
+
+def load_and_save_temporary_tensorflow_model(model_name, model_ckpt, example_img= '../../example/img.jpg'):
+ """ Loads and saves a TensorFlow model. """
+ image_files = [example_img]
+ eval_ckpt_driver = eval_ckpt_main.EvalCkptDriver(model_name)
+ with tf.Graph().as_default(), tf.compat.v1.Session() as sess:
+ images, labels = eval_ckpt_driver.build_dataset(image_files, [0] * len(image_files), False)
+ probs = eval_ckpt_driver.build_model(images, is_training=False)
+ sess.run(tf.compat.v1.global_variables_initializer())
+ print(model_ckpt)
+ eval_ckpt_driver.restore_model(sess, model_ckpt)
+ tf.compat.v1.train.Saver().save(sess, 'tmp/model.ckpt')
+
+
+if __name__ == '__main__':
+
+ import sys
+ import argparse
+
+ sys.path.append('original_tf')
+ import eval_ckpt_main
+
+ from efficientnet_pytorch import EfficientNet
+
+ parser = argparse.ArgumentParser(
+ description='Convert TF model to PyTorch model and save for easier future loading')
+ parser.add_argument('--model_name', type=str, default='efficientnet-b0',
+ help='efficientnet-b{N}, where N is an integer 0 <= N <= 8')
+ parser.add_argument('--tf_checkpoint', type=str, default='pretrained_tensorflow/efficientnet-b0/',
+ help='checkpoint file path')
+ parser.add_argument('--output_file', type=str, default='pretrained_pytorch/efficientnet-b0.pth',
+ help='output PyTorch model file name')
+ args = parser.parse_args()
+
+ # Build model
+ model = EfficientNet.from_name(args.model_name)
+
+ # Load and save temporary TensorFlow file due to TF nuances
+ print(args.tf_checkpoint)
+ load_and_save_temporary_tensorflow_model(args.model_name, args.tf_checkpoint)
+
+ # Load weights
+ load_efficientnet(model, 'tmp/model.ckpt', model_name=args.model_name)
+ print('Loaded TF checkpoint weights')
+
+ # Save PyTorch file
+ torch.save(model.state_dict(), args.output_file)
+ print('Saved model to', args.output_file)
diff --git a/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/load_tf_weights_tf1.py b/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/load_tf_weights_tf1.py
new file mode 100644
index 0000000000000000000000000000000000000000..0722a68389ae1a0d0827ad8635fae744e9d2dfe3
--- /dev/null
+++ b/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/load_tf_weights_tf1.py
@@ -0,0 +1,172 @@
+import numpy as np
+import tensorflow as tf
+import torch
+
+def load_param(checkpoint_file, conversion_table, model_name):
+ """
+ Load parameters according to conversion_table.
+
+ Args:
+ checkpoint_file (string): pretrained checkpoint model file in tensorflow
+ conversion_table (dict): { pytorch tensor in a model : checkpoint variable name }
+ """
+ for pyt_param, tf_param_name in conversion_table.items():
+ tf_param_name = str(model_name) + '/' + tf_param_name
+ tf_param = tf.train.load_variable(checkpoint_file, tf_param_name)
+ if 'conv' in tf_param_name and 'kernel' in tf_param_name:
+ tf_param = np.transpose(tf_param, (3, 2, 0, 1))
+ if 'depthwise' in tf_param_name:
+ tf_param = np.transpose(tf_param, (1, 0, 2, 3))
+ elif tf_param_name.endswith('kernel'): # for weight(kernel), we should do transpose
+ tf_param = np.transpose(tf_param)
+ assert pyt_param.size() == tf_param.shape, \
+ 'Dim Mismatch: %s vs %s ; %s' % (tuple(pyt_param.size()), tf_param.shape, tf_param_name)
+ pyt_param.data = torch.from_numpy(tf_param)
+
+
+def load_efficientnet(model, checkpoint_file, model_name):
+ """
+ Load PyTorch EfficientNet from TensorFlow checkpoint file
+ """
+
+ # This will store the enire conversion table
+ conversion_table = {}
+ merge = lambda dict1, dict2: {**dict1, **dict2}
+
+ # All the weights not in the conv blocks
+ conversion_table_for_weights_outside_blocks = {
+ model._conv_stem.weight: 'stem/conv2d/kernel', # [3, 3, 3, 32]),
+ model._bn0.bias: 'stem/tpu_batch_normalization/beta', # [32]),
+ model._bn0.weight: 'stem/tpu_batch_normalization/gamma', # [32]),
+ model._bn0.running_mean: 'stem/tpu_batch_normalization/moving_mean', # [32]),
+ model._bn0.running_var: 'stem/tpu_batch_normalization/moving_variance', # [32]),
+ model._conv_head.weight: 'head/conv2d/kernel', # [1, 1, 320, 1280]),
+ model._bn1.bias: 'head/tpu_batch_normalization/beta', # [1280]),
+ model._bn1.weight: 'head/tpu_batch_normalization/gamma', # [1280]),
+ model._bn1.running_mean: 'head/tpu_batch_normalization/moving_mean', # [32]),
+ model._bn1.running_var: 'head/tpu_batch_normalization/moving_variance', # [32]),
+ model._fc.bias: 'head/dense/bias', # [1000]),
+ model._fc.weight: 'head/dense/kernel', # [1280, 1000]),
+ }
+ conversion_table = merge(conversion_table, conversion_table_for_weights_outside_blocks)
+
+ # The first conv block is special because it does not have _expand_conv
+ conversion_table_for_first_block = {
+ model._blocks[0]._project_conv.weight: 'blocks_0/conv2d/kernel', # 1, 1, 32, 16]),
+ model._blocks[0]._depthwise_conv.weight: 'blocks_0/depthwise_conv2d/depthwise_kernel', # [3, 3, 32, 1]),
+ model._blocks[0]._se_reduce.bias: 'blocks_0/se/conv2d/bias', # , [8]),
+ model._blocks[0]._se_reduce.weight: 'blocks_0/se/conv2d/kernel', # , [1, 1, 32, 8]),
+ model._blocks[0]._se_expand.bias: 'blocks_0/se/conv2d_1/bias', # , [32]),
+ model._blocks[0]._se_expand.weight: 'blocks_0/se/conv2d_1/kernel', # , [1, 1, 8, 32]),
+ model._blocks[0]._bn1.bias: 'blocks_0/tpu_batch_normalization/beta', # [32]),
+ model._blocks[0]._bn1.weight: 'blocks_0/tpu_batch_normalization/gamma', # [32]),
+ model._blocks[0]._bn1.running_mean: 'blocks_0/tpu_batch_normalization/moving_mean',
+ model._blocks[0]._bn1.running_var: 'blocks_0/tpu_batch_normalization/moving_variance',
+ model._blocks[0]._bn2.bias: 'blocks_0/tpu_batch_normalization_1/beta', # [16]),
+ model._blocks[0]._bn2.weight: 'blocks_0/tpu_batch_normalization_1/gamma', # [16]),
+ model._blocks[0]._bn2.running_mean: 'blocks_0/tpu_batch_normalization_1/moving_mean',
+ model._blocks[0]._bn2.running_var: 'blocks_0/tpu_batch_normalization_1/moving_variance',
+ }
+ conversion_table = merge(conversion_table, conversion_table_for_first_block)
+
+ # Conv blocks
+ for i in range(len(model._blocks)):
+
+ is_first_block = '_expand_conv.weight' not in [n for n, p in model._blocks[i].named_parameters()]
+
+ if is_first_block:
+ conversion_table_block = {
+ model._blocks[i]._project_conv.weight: 'blocks_' + str(i) + '/conv2d/kernel', # 1, 1, 32, 16]),
+ model._blocks[i]._depthwise_conv.weight: 'blocks_' + str(i) + '/depthwise_conv2d/depthwise_kernel',
+ # [3, 3, 32, 1]),
+ model._blocks[i]._se_reduce.bias: 'blocks_' + str(i) + '/se/conv2d/bias', # , [8]),
+ model._blocks[i]._se_reduce.weight: 'blocks_' + str(i) + '/se/conv2d/kernel', # , [1, 1, 32, 8]),
+ model._blocks[i]._se_expand.bias: 'blocks_' + str(i) + '/se/conv2d_1/bias', # , [32]),
+ model._blocks[i]._se_expand.weight: 'blocks_' + str(i) + '/se/conv2d_1/kernel', # , [1, 1, 8, 32]),
+ model._blocks[i]._bn1.bias: 'blocks_' + str(i) + '/tpu_batch_normalization/beta', # [32]),
+ model._blocks[i]._bn1.weight: 'blocks_' + str(i) + '/tpu_batch_normalization/gamma', # [32]),
+ model._blocks[i]._bn1.running_mean: 'blocks_' + str(i) + '/tpu_batch_normalization/moving_mean',
+ model._blocks[i]._bn1.running_var: 'blocks_' + str(i) + '/tpu_batch_normalization/moving_variance',
+ model._blocks[i]._bn2.bias: 'blocks_' + str(i) + '/tpu_batch_normalization_1/beta', # [16]),
+ model._blocks[i]._bn2.weight: 'blocks_' + str(i) + '/tpu_batch_normalization_1/gamma', # [16]),
+ model._blocks[i]._bn2.running_mean: 'blocks_' + str(i) + '/tpu_batch_normalization_1/moving_mean',
+ model._blocks[i]._bn2.running_var: 'blocks_' + str(i) + '/tpu_batch_normalization_1/moving_variance',
+ }
+
+ else:
+ conversion_table_block = {
+ model._blocks[i]._expand_conv.weight: 'blocks_' + str(i) + '/conv2d/kernel',
+ model._blocks[i]._project_conv.weight: 'blocks_' + str(i) + '/conv2d_1/kernel',
+ model._blocks[i]._depthwise_conv.weight: 'blocks_' + str(i) + '/depthwise_conv2d/depthwise_kernel',
+ model._blocks[i]._se_reduce.bias: 'blocks_' + str(i) + '/se/conv2d/bias',
+ model._blocks[i]._se_reduce.weight: 'blocks_' + str(i) + '/se/conv2d/kernel',
+ model._blocks[i]._se_expand.bias: 'blocks_' + str(i) + '/se/conv2d_1/bias',
+ model._blocks[i]._se_expand.weight: 'blocks_' + str(i) + '/se/conv2d_1/kernel',
+ model._blocks[i]._bn0.bias: 'blocks_' + str(i) + '/tpu_batch_normalization/beta',
+ model._blocks[i]._bn0.weight: 'blocks_' + str(i) + '/tpu_batch_normalization/gamma',
+ model._blocks[i]._bn0.running_mean: 'blocks_' + str(i) + '/tpu_batch_normalization/moving_mean',
+ model._blocks[i]._bn0.running_var: 'blocks_' + str(i) + '/tpu_batch_normalization/moving_variance',
+ model._blocks[i]._bn1.bias: 'blocks_' + str(i) + '/tpu_batch_normalization_1/beta',
+ model._blocks[i]._bn1.weight: 'blocks_' + str(i) + '/tpu_batch_normalization_1/gamma',
+ model._blocks[i]._bn1.running_mean: 'blocks_' + str(i) + '/tpu_batch_normalization_1/moving_mean',
+ model._blocks[i]._bn1.running_var: 'blocks_' + str(i) + '/tpu_batch_normalization_1/moving_variance',
+ model._blocks[i]._bn2.bias: 'blocks_' + str(i) + '/tpu_batch_normalization_2/beta',
+ model._blocks[i]._bn2.weight: 'blocks_' + str(i) + '/tpu_batch_normalization_2/gamma',
+ model._blocks[i]._bn2.running_mean: 'blocks_' + str(i) + '/tpu_batch_normalization_2/moving_mean',
+ model._blocks[i]._bn2.running_var: 'blocks_' + str(i) + '/tpu_batch_normalization_2/moving_variance',
+ }
+
+ conversion_table = merge(conversion_table, conversion_table_block)
+
+ # Load TensorFlow parameters into PyTorch model
+ load_param(checkpoint_file, conversion_table, model_name)
+ return conversion_table
+
+
+def load_and_save_temporary_tensorflow_model(model_name, model_ckpt, example_img= '../../example/img.jpg'):
+ """ Loads and saves a TensorFlow model. """
+ image_files = [example_img]
+ eval_ckpt_driver = eval_ckpt_main.EvalCkptDriver(model_name)
+ with tf.Graph().as_default(), tf.Session() as sess:
+ images, labels = eval_ckpt_driver.build_dataset(image_files, [0] * len(image_files), False)
+ probs = eval_ckpt_driver.build_model(images, is_training=False)
+ sess.run(tf.global_variables_initializer())
+ print(model_ckpt)
+ eval_ckpt_driver.restore_model(sess, model_ckpt)
+ tf.train.Saver().save(sess, 'tmp/model.ckpt')
+
+
+if __name__ == '__main__':
+
+ import sys
+ import argparse
+
+ sys.path.append('original_tf')
+ import eval_ckpt_main
+
+ from efficientnet_pytorch import EfficientNet
+
+ parser = argparse.ArgumentParser(
+ description='Convert TF model to PyTorch model and save for easier future loading')
+ parser.add_argument('--model_name', type=str, default='efficientnet-b0',
+ help='efficientnet-b{N}, where N is an integer 0 <= N <= 8')
+ parser.add_argument('--tf_checkpoint', type=str, default='pretrained_tensorflow/efficientnet-b0/',
+ help='checkpoint file path')
+ parser.add_argument('--output_file', type=str, default='pretrained_pytorch/efficientnet-b0.pth',
+ help='output PyTorch model file name')
+ args = parser.parse_args()
+
+ # Build model
+ model = EfficientNet.from_name(args.model_name)
+
+ # Load and save temporary TensorFlow file due to TF nuances
+ print(args.tf_checkpoint)
+ load_and_save_temporary_tensorflow_model(args.model_name, args.tf_checkpoint)
+
+ # Load weights
+ load_efficientnet(model, 'tmp/model.ckpt', model_name=args.model_name)
+ print('Loaded TF checkpoint weights')
+
+ # Save PyTorch file
+ torch.save(model.state_dict(), args.output_file)
+ print('Saved model to', args.output_file)
diff --git a/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/original_tf/__init__.py b/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/original_tf/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/original_tf/efficientnet_builder.py b/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/original_tf/efficientnet_builder.py
new file mode 100644
index 0000000000000000000000000000000000000000..ff384b1126b8efc36e74c87e065976fedad21394
--- /dev/null
+++ b/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/original_tf/efficientnet_builder.py
@@ -0,0 +1,329 @@
+# Copyright 2019 The TensorFlow Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ==============================================================================
+"""Model Builder for EfficientNet."""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import functools
+import os
+import re
+from absl import logging
+import numpy as np
+import six
+import tensorflow.compat.v1 as tf
+
+import efficientnet_model
+import utils
+MEAN_RGB = [0.485 * 255, 0.456 * 255, 0.406 * 255]
+STDDEV_RGB = [0.229 * 255, 0.224 * 255, 0.225 * 255]
+
+
+def efficientnet_params(model_name):
+ """Get efficientnet params based on model name."""
+ params_dict = {
+ # (width_coefficient, depth_coefficient, resolution, dropout_rate)
+ 'efficientnet-b0': (1.0, 1.0, 224, 0.2),
+ 'efficientnet-b1': (1.0, 1.1, 240, 0.2),
+ 'efficientnet-b2': (1.1, 1.2, 260, 0.3),
+ 'efficientnet-b3': (1.2, 1.4, 300, 0.3),
+ 'efficientnet-b4': (1.4, 1.8, 380, 0.4),
+ 'efficientnet-b5': (1.6, 2.2, 456, 0.4),
+ 'efficientnet-b6': (1.8, 2.6, 528, 0.5),
+ 'efficientnet-b7': (2.0, 3.1, 600, 0.5),
+ 'efficientnet-b8': (2.2, 3.6, 672, 0.5),
+ 'efficientnet-l2': (4.3, 5.3, 800, 0.5),
+ }
+ return params_dict[model_name]
+
+
+class BlockDecoder(object):
+ """Block Decoder for readability."""
+
+ def _decode_block_string(self, block_string):
+ """Gets a block through a string notation of arguments."""
+ if six.PY2:
+ assert isinstance(block_string, (str, unicode))
+ else:
+ assert isinstance(block_string, str)
+ ops = block_string.split('_')
+ options = {}
+ for op in ops:
+ splits = re.split(r'(\d.*)', op)
+ if len(splits) >= 2:
+ key, value = splits[:2]
+ options[key] = value
+
+ if 's' not in options or len(options['s']) != 2:
+ raise ValueError('Strides options should be a pair of integers.')
+
+ return efficientnet_model.BlockArgs(
+ kernel_size=int(options['k']),
+ num_repeat=int(options['r']),
+ input_filters=int(options['i']),
+ output_filters=int(options['o']),
+ expand_ratio=int(options['e']),
+ id_skip=('noskip' not in block_string),
+ se_ratio=float(options['se']) if 'se' in options else None,
+ strides=[int(options['s'][0]),
+ int(options['s'][1])],
+ conv_type=int(options['c']) if 'c' in options else 0,
+ fused_conv=int(options['f']) if 'f' in options else 0,
+ super_pixel=int(options['p']) if 'p' in options else 0,
+ condconv=('cc' in block_string))
+
+ def _encode_block_string(self, block):
+ """Encodes a block to a string."""
+ args = [
+ 'r%d' % block.num_repeat,
+ 'k%d' % block.kernel_size,
+ 's%d%d' % (block.strides[0], block.strides[1]),
+ 'e%s' % block.expand_ratio,
+ 'i%d' % block.input_filters,
+ 'o%d' % block.output_filters,
+ 'c%d' % block.conv_type,
+ 'f%d' % block.fused_conv,
+ 'p%d' % block.super_pixel,
+ ]
+ if block.se_ratio > 0 and block.se_ratio <= 1:
+ args.append('se%s' % block.se_ratio)
+ if block.id_skip is False: # pylint: disable=g-bool-id-comparison
+ args.append('noskip')
+ if block.condconv:
+ args.append('cc')
+ return '_'.join(args)
+
+ def decode(self, string_list):
+ """Decodes a list of string notations to specify blocks inside the network.
+
+ Args:
+ string_list: a list of strings, each string is a notation of block.
+
+ Returns:
+ A list of namedtuples to represent blocks arguments.
+ """
+ assert isinstance(string_list, list)
+ blocks_args = []
+ for block_string in string_list:
+ blocks_args.append(self._decode_block_string(block_string))
+ return blocks_args
+
+ def encode(self, blocks_args):
+ """Encodes a list of Blocks to a list of strings.
+
+ Args:
+ blocks_args: A list of namedtuples to represent blocks arguments.
+ Returns:
+ a list of strings, each string is a notation of block.
+ """
+ block_strings = []
+ for block in blocks_args:
+ block_strings.append(self._encode_block_string(block))
+ return block_strings
+
+
+def swish(features, use_native=True, use_hard=False):
+ """Computes the Swish activation function.
+
+ We provide three alternnatives:
+ - Native tf.nn.swish, use less memory during training than composable swish.
+ - Quantization friendly hard swish.
+ - A composable swish, equivalant to tf.nn.swish, but more general for
+ finetuning and TF-Hub.
+
+ Args:
+ features: A `Tensor` representing preactivation values.
+ use_native: Whether to use the native swish from tf.nn that uses a custom
+ gradient to reduce memory usage, or to use customized swish that uses
+ default TensorFlow gradient computation.
+ use_hard: Whether to use quantization-friendly hard swish.
+
+ Returns:
+ The activation value.
+ """
+ if use_native and use_hard:
+ raise ValueError('Cannot specify both use_native and use_hard.')
+
+ if use_native:
+ return tf.nn.swish(features)
+
+ if use_hard:
+ return features * tf.nn.relu6(features + np.float32(3)) * (1. / 6.)
+
+ features = tf.convert_to_tensor(features, name='features')
+ return features * tf.nn.sigmoid(features)
+
+
+_DEFAULT_BLOCKS_ARGS = [
+ 'r1_k3_s11_e1_i32_o16_se0.25', 'r2_k3_s22_e6_i16_o24_se0.25',
+ 'r2_k5_s22_e6_i24_o40_se0.25', 'r3_k3_s22_e6_i40_o80_se0.25',
+ 'r3_k5_s11_e6_i80_o112_se0.25', 'r4_k5_s22_e6_i112_o192_se0.25',
+ 'r1_k3_s11_e6_i192_o320_se0.25',
+]
+
+
+def efficientnet(width_coefficient=None,
+ depth_coefficient=None,
+ dropout_rate=0.2,
+ survival_prob=0.8):
+ """Creates a efficientnet model."""
+ global_params = efficientnet_model.GlobalParams(
+ blocks_args=_DEFAULT_BLOCKS_ARGS,
+ batch_norm_momentum=0.99,
+ batch_norm_epsilon=1e-3,
+ dropout_rate=dropout_rate,
+ survival_prob=survival_prob,
+ data_format='channels_last',
+ num_classes=1000,
+ width_coefficient=width_coefficient,
+ depth_coefficient=depth_coefficient,
+ depth_divisor=8,
+ min_depth=None,
+ relu_fn=tf.nn.swish,
+ # The default is TPU-specific batch norm.
+ # The alternative is tf.layers.BatchNormalization.
+ batch_norm=utils.TpuBatchNormalization, # TPU-specific requirement.
+ use_se=True,
+ clip_projection_output=False)
+ return global_params
+
+
+def get_model_params(model_name, override_params):
+ """Get the block args and global params for a given model."""
+ if model_name.startswith('efficientnet'):
+ width_coefficient, depth_coefficient, _, dropout_rate = (
+ efficientnet_params(model_name))
+ global_params = efficientnet(
+ width_coefficient, depth_coefficient, dropout_rate)
+ else:
+ raise NotImplementedError('model name is not pre-defined: %s' % model_name)
+
+ if override_params:
+ # ValueError will be raised here if override_params has fields not included
+ # in global_params.
+ global_params = global_params._replace(**override_params)
+
+ decoder = BlockDecoder()
+ blocks_args = decoder.decode(global_params.blocks_args)
+
+ logging.info('global_params= %s', global_params)
+ return blocks_args, global_params
+
+
+def build_model(images,
+ model_name,
+ training,
+ override_params=None,
+ model_dir=None,
+ fine_tuning=False,
+ features_only=False,
+ pooled_features_only=False):
+ """A helper functiion to creates a model and returns predicted logits.
+
+ Args:
+ images: input images tensor.
+ model_name: string, the predefined model name.
+ training: boolean, whether the model is constructed for training.
+ override_params: A dictionary of params for overriding. Fields must exist in
+ efficientnet_model.GlobalParams.
+ model_dir: string, optional model dir for saving configs.
+ fine_tuning: boolean, whether the model is used for finetuning.
+ features_only: build the base feature network only (excluding final
+ 1x1 conv layer, global pooling, dropout and fc head).
+ pooled_features_only: build the base network for features extraction (after
+ 1x1 conv layer and global pooling, but before dropout and fc head).
+
+ Returns:
+ logits: the logits tensor of classes.
+ endpoints: the endpoints for each layer.
+
+ Raises:
+ When model_name specified an undefined model, raises NotImplementedError.
+ When override_params has invalid fields, raises ValueError.
+ """
+ assert isinstance(images, tf.Tensor)
+ assert not (features_only and pooled_features_only)
+
+ # For backward compatibility.
+ if override_params and override_params.get('drop_connect_rate', None):
+ override_params['survival_prob'] = 1 - override_params['drop_connect_rate']
+
+ if not training or fine_tuning:
+ if not override_params:
+ override_params = {}
+ override_params['batch_norm'] = utils.BatchNormalization
+ if fine_tuning:
+ override_params['relu_fn'] = functools.partial(swish, use_native=False)
+ blocks_args, global_params = get_model_params(model_name, override_params)
+
+ if model_dir:
+ param_file = os.path.join(model_dir, 'model_params.txt')
+ if not tf.gfile.Exists(param_file):
+ if not tf.gfile.Exists(model_dir):
+ tf.gfile.MakeDirs(model_dir)
+ with tf.gfile.GFile(param_file, 'w') as f:
+ logging.info('writing to %s', param_file)
+ f.write('model_name= %s\n\n' % model_name)
+ f.write('global_params= %s\n\n' % str(global_params))
+ f.write('blocks_args= %s\n\n' % str(blocks_args))
+
+ with tf.variable_scope(model_name):
+ model = efficientnet_model.Model(blocks_args, global_params)
+ outputs = model(
+ images,
+ training=training,
+ features_only=features_only,
+ pooled_features_only=pooled_features_only)
+ if features_only:
+ outputs = tf.identity(outputs, 'features')
+ elif pooled_features_only:
+ outputs = tf.identity(outputs, 'pooled_features')
+ else:
+ outputs = tf.identity(outputs, 'logits')
+ return outputs, model.endpoints
+
+
+def build_model_base(images, model_name, training, override_params=None):
+ """A helper functiion to create a base model and return global_pool.
+
+ Args:
+ images: input images tensor.
+ model_name: string, the predefined model name.
+ training: boolean, whether the model is constructed for training.
+ override_params: A dictionary of params for overriding. Fields must exist in
+ efficientnet_model.GlobalParams.
+
+ Returns:
+ features: global pool features.
+ endpoints: the endpoints for each layer.
+
+ Raises:
+ When model_name specified an undefined model, raises NotImplementedError.
+ When override_params has invalid fields, raises ValueError.
+ """
+ assert isinstance(images, tf.Tensor)
+ # For backward compatibility.
+ if override_params and override_params.get('drop_connect_rate', None):
+ override_params['survival_prob'] = 1 - override_params['drop_connect_rate']
+
+ blocks_args, global_params = get_model_params(model_name, override_params)
+
+ with tf.variable_scope(model_name):
+ model = efficientnet_model.Model(blocks_args, global_params)
+ features = model(images, training=training, features_only=True)
+
+ features = tf.identity(features, 'features')
+ return features, model.endpoints
diff --git a/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/original_tf/efficientnet_model.py b/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/original_tf/efficientnet_model.py
new file mode 100644
index 0000000000000000000000000000000000000000..6bc827e1e0de4ced8192f8e1920ff44afdbb0e93
--- /dev/null
+++ b/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/original_tf/efficientnet_model.py
@@ -0,0 +1,713 @@
+# Copyright 2019 The TensorFlow Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ==============================================================================
+"""Contains definitions for EfficientNet model.
+
+[1] Mingxing Tan, Quoc V. Le
+ EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks.
+ ICML'19, https://arxiv.org/abs/1905.11946
+"""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import collections
+import functools
+import math
+
+from absl import logging
+import numpy as np
+import six
+from six.moves import xrange
+import tensorflow.compat.v1 as tf
+
+import utils
+# from condconv import condconv_layers
+
+GlobalParams = collections.namedtuple('GlobalParams', [
+ 'batch_norm_momentum', 'batch_norm_epsilon', 'dropout_rate', 'data_format',
+ 'num_classes', 'width_coefficient', 'depth_coefficient', 'depth_divisor',
+ 'min_depth', 'survival_prob', 'relu_fn', 'batch_norm', 'use_se',
+ 'local_pooling', 'condconv_num_experts', 'clip_projection_output',
+ 'blocks_args'
+])
+GlobalParams.__new__.__defaults__ = (None,) * len(GlobalParams._fields)
+
+BlockArgs = collections.namedtuple('BlockArgs', [
+ 'kernel_size', 'num_repeat', 'input_filters', 'output_filters',
+ 'expand_ratio', 'id_skip', 'strides', 'se_ratio', 'conv_type', 'fused_conv',
+ 'super_pixel', 'condconv'
+])
+# defaults will be a public argument for namedtuple in Python 3.7
+# https://docs.python.org/3/library/collections.html#collections.namedtuple
+BlockArgs.__new__.__defaults__ = (None,) * len(BlockArgs._fields)
+
+
+def conv_kernel_initializer(shape, dtype=None, partition_info=None):
+ """Initialization for convolutional kernels.
+
+ The main difference with tf.variance_scaling_initializer is that
+ tf.variance_scaling_initializer uses a truncated normal with an uncorrected
+ standard deviation, whereas here we use a normal distribution. Similarly,
+ tf.initializers.variance_scaling uses a truncated normal with
+ a corrected standard deviation.
+
+ Args:
+ shape: shape of variable
+ dtype: dtype of variable
+ partition_info: unused
+
+ Returns:
+ an initialization for the variable
+ """
+ del partition_info
+ kernel_height, kernel_width, _, out_filters = shape
+ fan_out = int(kernel_height * kernel_width * out_filters)
+ return tf.random_normal(
+ shape, mean=0.0, stddev=np.sqrt(2.0 / fan_out), dtype=dtype)
+
+
+def dense_kernel_initializer(shape, dtype=None, partition_info=None):
+ """Initialization for dense kernels.
+
+ This initialization is equal to
+ tf.variance_scaling_initializer(scale=1.0/3.0, mode='fan_out',
+ distribution='uniform').
+ It is written out explicitly here for clarity.
+
+ Args:
+ shape: shape of variable
+ dtype: dtype of variable
+ partition_info: unused
+
+ Returns:
+ an initialization for the variable
+ """
+ del partition_info
+ init_range = 1.0 / np.sqrt(shape[1])
+ return tf.random_uniform(shape, -init_range, init_range, dtype=dtype)
+
+
+def superpixel_kernel_initializer(shape, dtype='float32', partition_info=None):
+ """Initializes superpixel kernels.
+
+ This is inspired by space-to-depth transformation that is mathematically
+ equivalent before and after the transformation. But we do the space-to-depth
+ via a convolution. Moreover, we make the layer trainable instead of direct
+ transform, we can initialization it this way so that the model can learn not
+ to do anything but keep it mathematically equivalent, when improving
+ performance.
+
+
+ Args:
+ shape: shape of variable
+ dtype: dtype of variable
+ partition_info: unused
+
+ Returns:
+ an initialization for the variable
+ """
+ del partition_info
+ # use input depth to make superpixel kernel.
+ depth = shape[-2]
+ filters = np.zeros([2, 2, depth, 4 * depth], dtype=dtype)
+ i = np.arange(2)
+ j = np.arange(2)
+ k = np.arange(depth)
+ mesh = np.array(np.meshgrid(i, j, k)).T.reshape(-1, 3).T
+ filters[
+ mesh[0],
+ mesh[1],
+ mesh[2],
+ 4 * mesh[2] + 2 * mesh[0] + mesh[1]] = 1
+ return filters
+
+
+def round_filters(filters, global_params):
+ """Round number of filters based on depth multiplier."""
+ orig_f = filters
+ multiplier = global_params.width_coefficient
+ divisor = global_params.depth_divisor
+ min_depth = global_params.min_depth
+ if not multiplier:
+ return filters
+
+ filters *= multiplier
+ min_depth = min_depth or divisor
+ new_filters = max(min_depth, int(filters + divisor / 2) // divisor * divisor)
+ # Make sure that round down does not go down by more than 10%.
+ if new_filters < 0.9 * filters:
+ new_filters += divisor
+ logging.info('round_filter input=%s output=%s', orig_f, new_filters)
+ return int(new_filters)
+
+
+def round_repeats(repeats, global_params):
+ """Round number of filters based on depth multiplier."""
+ multiplier = global_params.depth_coefficient
+ if not multiplier:
+ return repeats
+ return int(math.ceil(multiplier * repeats))
+
+
+class MBConvBlock(tf.keras.layers.Layer):
+ """A class of MBConv: Mobile Inverted Residual Bottleneck.
+
+ Attributes:
+ endpoints: dict. A list of internal tensors.
+ """
+
+ def __init__(self, block_args, global_params):
+ """Initializes a MBConv block.
+
+ Args:
+ block_args: BlockArgs, arguments to create a Block.
+ global_params: GlobalParams, a set of global parameters.
+ """
+ super(MBConvBlock, self).__init__()
+ self._block_args = block_args
+ self._batch_norm_momentum = global_params.batch_norm_momentum
+ self._batch_norm_epsilon = global_params.batch_norm_epsilon
+ self._batch_norm = global_params.batch_norm
+ self._condconv_num_experts = global_params.condconv_num_experts
+ self._data_format = global_params.data_format
+ if self._data_format == 'channels_first':
+ self._channel_axis = 1
+ self._spatial_dims = [2, 3]
+ else:
+ self._channel_axis = -1
+ self._spatial_dims = [1, 2]
+
+ self._relu_fn = global_params.relu_fn or tf.nn.swish
+ self._has_se = (
+ global_params.use_se and self._block_args.se_ratio is not None and
+ 0 < self._block_args.se_ratio <= 1)
+
+ self._clip_projection_output = global_params.clip_projection_output
+
+ self.endpoints = None
+
+ self.conv_cls = tf.layers.Conv2D
+ self.depthwise_conv_cls = utils.DepthwiseConv2D
+ if self._block_args.condconv:
+ self.conv_cls = functools.partial(
+ condconv_layers.CondConv2D, num_experts=self._condconv_num_experts)
+ self.depthwise_conv_cls = functools.partial(
+ condconv_layers.DepthwiseCondConv2D,
+ num_experts=self._condconv_num_experts)
+
+ # Builds the block accordings to arguments.
+ self._build()
+
+ def block_args(self):
+ return self._block_args
+
+ def _build(self):
+ """Builds block according to the arguments."""
+ if self._block_args.super_pixel == 1:
+ self._superpixel = tf.layers.Conv2D(
+ self._block_args.input_filters,
+ kernel_size=[2, 2],
+ strides=[2, 2],
+ kernel_initializer=conv_kernel_initializer,
+ padding='same',
+ data_format=self._data_format,
+ use_bias=False)
+ self._bnsp = self._batch_norm(
+ axis=self._channel_axis,
+ momentum=self._batch_norm_momentum,
+ epsilon=self._batch_norm_epsilon)
+
+ if self._block_args.condconv:
+ # Add the example-dependent routing function
+ self._avg_pooling = tf.keras.layers.GlobalAveragePooling2D(
+ data_format=self._data_format)
+ self._routing_fn = tf.layers.Dense(
+ self._condconv_num_experts, activation=tf.nn.sigmoid)
+
+ filters = self._block_args.input_filters * self._block_args.expand_ratio
+ kernel_size = self._block_args.kernel_size
+
+ # Fused expansion phase. Called if using fused convolutions.
+ self._fused_conv = self.conv_cls(
+ filters=filters,
+ kernel_size=[kernel_size, kernel_size],
+ strides=self._block_args.strides,
+ kernel_initializer=conv_kernel_initializer,
+ padding='same',
+ data_format=self._data_format,
+ use_bias=False)
+
+ # Expansion phase. Called if not using fused convolutions and expansion
+ # phase is necessary.
+ self._expand_conv = self.conv_cls(
+ filters=filters,
+ kernel_size=[1, 1],
+ strides=[1, 1],
+ kernel_initializer=conv_kernel_initializer,
+ padding='same',
+ data_format=self._data_format,
+ use_bias=False)
+ self._bn0 = self._batch_norm(
+ axis=self._channel_axis,
+ momentum=self._batch_norm_momentum,
+ epsilon=self._batch_norm_epsilon)
+
+ # Depth-wise convolution phase. Called if not using fused convolutions.
+ self._depthwise_conv = self.depthwise_conv_cls(
+ kernel_size=[kernel_size, kernel_size],
+ strides=self._block_args.strides,
+ depthwise_initializer=conv_kernel_initializer,
+ padding='same',
+ data_format=self._data_format,
+ use_bias=False)
+
+ self._bn1 = self._batch_norm(
+ axis=self._channel_axis,
+ momentum=self._batch_norm_momentum,
+ epsilon=self._batch_norm_epsilon)
+
+ if self._has_se:
+ num_reduced_filters = max(
+ 1, int(self._block_args.input_filters * self._block_args.se_ratio))
+ # Squeeze and Excitation layer.
+ self._se_reduce = tf.layers.Conv2D(
+ num_reduced_filters,
+ kernel_size=[1, 1],
+ strides=[1, 1],
+ kernel_initializer=conv_kernel_initializer,
+ padding='same',
+ data_format=self._data_format,
+ use_bias=True)
+ self._se_expand = tf.layers.Conv2D(
+ filters,
+ kernel_size=[1, 1],
+ strides=[1, 1],
+ kernel_initializer=conv_kernel_initializer,
+ padding='same',
+ data_format=self._data_format,
+ use_bias=True)
+
+ # Output phase.
+ filters = self._block_args.output_filters
+ self._project_conv = self.conv_cls(
+ filters=filters,
+ kernel_size=[1, 1],
+ strides=[1, 1],
+ kernel_initializer=conv_kernel_initializer,
+ padding='same',
+ data_format=self._data_format,
+ use_bias=False)
+ self._bn2 = self._batch_norm(
+ axis=self._channel_axis,
+ momentum=self._batch_norm_momentum,
+ epsilon=self._batch_norm_epsilon)
+
+ def _call_se(self, input_tensor):
+ """Call Squeeze and Excitation layer.
+
+ Args:
+ input_tensor: Tensor, a single input tensor for Squeeze/Excitation layer.
+
+ Returns:
+ A output tensor, which should have the same shape as input.
+ """
+ se_tensor = tf.reduce_mean(input_tensor, self._spatial_dims, keepdims=True)
+ se_tensor = self._se_expand(self._relu_fn(self._se_reduce(se_tensor)))
+ logging.info('Built Squeeze and Excitation with tensor shape: %s',
+ (se_tensor.shape))
+ return tf.sigmoid(se_tensor) * input_tensor
+
+ def call(self, inputs, training=True, survival_prob=None):
+ """Implementation of call().
+
+ Args:
+ inputs: the inputs tensor.
+ training: boolean, whether the model is constructed for training.
+ survival_prob: float, between 0 to 1, drop connect rate.
+
+ Returns:
+ A output tensor.
+ """
+ logging.info('Block input: %s shape: %s', inputs.name, inputs.shape)
+ logging.info('Block input depth: %s output depth: %s',
+ self._block_args.input_filters,
+ self._block_args.output_filters)
+
+ x = inputs
+
+ fused_conv_fn = self._fused_conv
+ expand_conv_fn = self._expand_conv
+ depthwise_conv_fn = self._depthwise_conv
+ project_conv_fn = self._project_conv
+
+ if self._block_args.condconv:
+ pooled_inputs = self._avg_pooling(inputs)
+ routing_weights = self._routing_fn(pooled_inputs)
+ # Capture routing weights as additional input to CondConv layers
+ fused_conv_fn = functools.partial(
+ self._fused_conv, routing_weights=routing_weights)
+ expand_conv_fn = functools.partial(
+ self._expand_conv, routing_weights=routing_weights)
+ depthwise_conv_fn = functools.partial(
+ self._depthwise_conv, routing_weights=routing_weights)
+ project_conv_fn = functools.partial(
+ self._project_conv, routing_weights=routing_weights)
+
+ # creates conv 2x2 kernel
+ if self._block_args.super_pixel == 1:
+ with tf.variable_scope('super_pixel'):
+ x = self._relu_fn(
+ self._bnsp(self._superpixel(x), training=training))
+ logging.info(
+ 'Block start with SuperPixel: %s shape: %s', x.name, x.shape)
+
+ if self._block_args.fused_conv:
+ # If use fused mbconv, skip expansion and use regular conv.
+ x = self._relu_fn(self._bn1(fused_conv_fn(x), training=training))
+ logging.info('Conv2D: %s shape: %s', x.name, x.shape)
+ else:
+ # Otherwise, first apply expansion and then apply depthwise conv.
+ if self._block_args.expand_ratio != 1:
+ x = self._relu_fn(self._bn0(expand_conv_fn(x), training=training))
+ logging.info('Expand: %s shape: %s', x.name, x.shape)
+
+ x = self._relu_fn(self._bn1(depthwise_conv_fn(x), training=training))
+ logging.info('DWConv: %s shape: %s', x.name, x.shape)
+
+ if self._has_se:
+ with tf.variable_scope('se'):
+ x = self._call_se(x)
+
+ self.endpoints = {'expansion_output': x}
+
+ x = self._bn2(project_conv_fn(x), training=training)
+ # Add identity so that quantization-aware training can insert quantization
+ # ops correctly.
+ x = tf.identity(x)
+ if self._clip_projection_output:
+ x = tf.clip_by_value(x, -6, 6)
+ if self._block_args.id_skip:
+ if all(
+ s == 1 for s in self._block_args.strides
+ ) and self._block_args.input_filters == self._block_args.output_filters:
+ # Apply only if skip connection presents.
+ if survival_prob:
+ x = utils.drop_connect(x, training, survival_prob)
+ x = tf.add(x, inputs)
+ logging.info('Project: %s shape: %s', x.name, x.shape)
+ return x
+
+
+class MBConvBlockWithoutDepthwise(MBConvBlock):
+ """MBConv-like block without depthwise convolution and squeeze-and-excite."""
+
+ def _build(self):
+ """Builds block according to the arguments."""
+ filters = self._block_args.input_filters * self._block_args.expand_ratio
+ if self._block_args.expand_ratio != 1:
+ # Expansion phase:
+ self._expand_conv = tf.layers.Conv2D(
+ filters,
+ kernel_size=[3, 3],
+ strides=[1, 1],
+ kernel_initializer=conv_kernel_initializer,
+ padding='same',
+ use_bias=False)
+ self._bn0 = self._batch_norm(
+ axis=self._channel_axis,
+ momentum=self._batch_norm_momentum,
+ epsilon=self._batch_norm_epsilon)
+
+ # Output phase:
+ filters = self._block_args.output_filters
+ self._project_conv = tf.layers.Conv2D(
+ filters,
+ kernel_size=[1, 1],
+ strides=self._block_args.strides,
+ kernel_initializer=conv_kernel_initializer,
+ padding='same',
+ use_bias=False)
+ self._bn1 = self._batch_norm(
+ axis=self._channel_axis,
+ momentum=self._batch_norm_momentum,
+ epsilon=self._batch_norm_epsilon)
+
+ def call(self, inputs, training=True, survival_prob=None):
+ """Implementation of call().
+
+ Args:
+ inputs: the inputs tensor.
+ training: boolean, whether the model is constructed for training.
+ survival_prob: float, between 0 to 1, drop connect rate.
+
+ Returns:
+ A output tensor.
+ """
+ logging.info('Block input: %s shape: %s', inputs.name, inputs.shape)
+ if self._block_args.expand_ratio != 1:
+ x = self._relu_fn(self._bn0(self._expand_conv(inputs), training=training))
+ else:
+ x = inputs
+ logging.info('Expand: %s shape: %s', x.name, x.shape)
+
+ self.endpoints = {'expansion_output': x}
+
+ x = self._bn1(self._project_conv(x), training=training)
+ # Add identity so that quantization-aware training can insert quantization
+ # ops correctly.
+ x = tf.identity(x)
+ if self._clip_projection_output:
+ x = tf.clip_by_value(x, -6, 6)
+
+ if self._block_args.id_skip:
+ if all(
+ s == 1 for s in self._block_args.strides
+ ) and self._block_args.input_filters == self._block_args.output_filters:
+ # Apply only if skip connection presents.
+ if survival_prob:
+ x = utils.drop_connect(x, training, survival_prob)
+ x = tf.add(x, inputs)
+ logging.info('Project: %s shape: %s', x.name, x.shape)
+ return x
+
+
+class Model(tf.keras.Model):
+ """A class implements tf.keras.Model for MNAS-like model.
+
+ Reference: https://arxiv.org/abs/1807.11626
+ """
+
+ def __init__(self, blocks_args=None, global_params=None):
+ """Initializes an `Model` instance.
+
+ Args:
+ blocks_args: A list of BlockArgs to construct block modules.
+ global_params: GlobalParams, a set of global parameters.
+
+ Raises:
+ ValueError: when blocks_args is not specified as a list.
+ """
+ super(Model, self).__init__()
+ if not isinstance(blocks_args, list):
+ raise ValueError('blocks_args should be a list.')
+ self._global_params = global_params
+ self._blocks_args = blocks_args
+ self._relu_fn = global_params.relu_fn or tf.nn.swish
+ self._batch_norm = global_params.batch_norm
+
+ self.endpoints = None
+
+ self._build()
+
+ def _get_conv_block(self, conv_type):
+ conv_block_map = {0: MBConvBlock, 1: MBConvBlockWithoutDepthwise}
+ return conv_block_map[conv_type]
+
+ def _build(self):
+ """Builds a model."""
+ self._blocks = []
+ batch_norm_momentum = self._global_params.batch_norm_momentum
+ batch_norm_epsilon = self._global_params.batch_norm_epsilon
+ if self._global_params.data_format == 'channels_first':
+ channel_axis = 1
+ self._spatial_dims = [2, 3]
+ else:
+ channel_axis = -1
+ self._spatial_dims = [1, 2]
+
+ # Stem part.
+ self._conv_stem = tf.layers.Conv2D(
+ filters=round_filters(32, self._global_params),
+ kernel_size=[3, 3],
+ strides=[2, 2],
+ kernel_initializer=conv_kernel_initializer,
+ padding='same',
+ data_format=self._global_params.data_format,
+ use_bias=False)
+ self._bn0 = self._batch_norm(
+ axis=channel_axis,
+ momentum=batch_norm_momentum,
+ epsilon=batch_norm_epsilon)
+
+ # Builds blocks.
+ for block_args in self._blocks_args:
+ assert block_args.num_repeat > 0
+ assert block_args.super_pixel in [0, 1, 2]
+ # Update block input and output filters based on depth multiplier.
+ input_filters = round_filters(block_args.input_filters,
+ self._global_params)
+ output_filters = round_filters(block_args.output_filters,
+ self._global_params)
+ kernel_size = block_args.kernel_size
+ block_args = block_args._replace(
+ input_filters=input_filters,
+ output_filters=output_filters,
+ num_repeat=round_repeats(block_args.num_repeat, self._global_params))
+
+ # The first block needs to take care of stride and filter size increase.
+ conv_block = self._get_conv_block(block_args.conv_type)
+ if not block_args.super_pixel: # no super_pixel at all
+ self._blocks.append(conv_block(block_args, self._global_params))
+ else:
+ # if superpixel, adjust filters, kernels, and strides.
+ depth_factor = int(4 / block_args.strides[0] / block_args.strides[1])
+ block_args = block_args._replace(
+ input_filters=block_args.input_filters * depth_factor,
+ output_filters=block_args.output_filters * depth_factor,
+ kernel_size=((block_args.kernel_size + 1) // 2 if depth_factor > 1
+ else block_args.kernel_size))
+ # if the first block has stride-2 and super_pixel trandformation
+ if (block_args.strides[0] == 2 and block_args.strides[1] == 2):
+ block_args = block_args._replace(strides=[1, 1])
+ self._blocks.append(conv_block(block_args, self._global_params))
+ block_args = block_args._replace( # sp stops at stride-2
+ super_pixel=0,
+ input_filters=input_filters,
+ output_filters=output_filters,
+ kernel_size=kernel_size)
+ elif block_args.super_pixel == 1:
+ self._blocks.append(conv_block(block_args, self._global_params))
+ block_args = block_args._replace(super_pixel=2)
+ else:
+ self._blocks.append(conv_block(block_args, self._global_params))
+ if block_args.num_repeat > 1: # rest of blocks with the same block_arg
+ # pylint: disable=protected-access
+ block_args = block_args._replace(
+ input_filters=block_args.output_filters, strides=[1, 1])
+ # pylint: enable=protected-access
+ for _ in xrange(block_args.num_repeat - 1):
+ self._blocks.append(conv_block(block_args, self._global_params))
+
+ # Head part.
+ self._conv_head = tf.layers.Conv2D(
+ filters=round_filters(1280, self._global_params),
+ kernel_size=[1, 1],
+ strides=[1, 1],
+ kernel_initializer=conv_kernel_initializer,
+ padding='same',
+ use_bias=False)
+ self._bn1 = self._batch_norm(
+ axis=channel_axis,
+ momentum=batch_norm_momentum,
+ epsilon=batch_norm_epsilon)
+
+ self._avg_pooling = tf.keras.layers.GlobalAveragePooling2D(
+ data_format=self._global_params.data_format)
+ if self._global_params.num_classes:
+ self._fc = tf.layers.Dense(
+ self._global_params.num_classes,
+ kernel_initializer=dense_kernel_initializer)
+ else:
+ self._fc = None
+
+ if self._global_params.dropout_rate > 0:
+ self._dropout = tf.keras.layers.Dropout(self._global_params.dropout_rate)
+ else:
+ self._dropout = None
+
+ def call(self,
+ inputs,
+ training=True,
+ features_only=None,
+ pooled_features_only=False):
+ """Implementation of call().
+
+ Args:
+ inputs: input tensors.
+ training: boolean, whether the model is constructed for training.
+ features_only: build the base feature network only.
+ pooled_features_only: build the base network for features extraction
+ (after 1x1 conv layer and global pooling, but before dropout and fc
+ head).
+
+ Returns:
+ output tensors.
+ """
+ outputs = None
+ self.endpoints = {}
+ reduction_idx = 0
+ # Calls Stem layers
+ with tf.variable_scope('stem'):
+ outputs = self._relu_fn(
+ self._bn0(self._conv_stem(inputs), training=training))
+ logging.info('Built stem layers with output shape: %s', outputs.shape)
+ self.endpoints['stem'] = outputs
+
+ # Calls blocks.
+ for idx, block in enumerate(self._blocks):
+ is_reduction = False # reduction flag for blocks after the stem layer
+ # If the first block has super-pixel (space-to-depth) layer, then stem is
+ # the first reduction point.
+ if (block.block_args().super_pixel == 1 and idx == 0):
+ reduction_idx += 1
+ self.endpoints['reduction_%s' % reduction_idx] = outputs
+
+ elif ((idx == len(self._blocks) - 1) or
+ self._blocks[idx + 1].block_args().strides[0] > 1):
+ is_reduction = True
+ reduction_idx += 1
+
+ with tf.variable_scope('blocks_%s' % idx):
+ survival_prob = self._global_params.survival_prob
+ if survival_prob:
+ drop_rate = 1.0 - survival_prob
+ survival_prob = 1.0 - drop_rate * float(idx) / len(self._blocks)
+ logging.info('block_%s survival_prob: %s', idx, survival_prob)
+ outputs = block.call(
+ outputs, training=training, survival_prob=survival_prob)
+ self.endpoints['block_%s' % idx] = outputs
+ if is_reduction:
+ self.endpoints['reduction_%s' % reduction_idx] = outputs
+ if block.endpoints:
+ for k, v in six.iteritems(block.endpoints):
+ self.endpoints['block_%s/%s' % (idx, k)] = v
+ if is_reduction:
+ self.endpoints['reduction_%s/%s' % (reduction_idx, k)] = v
+ self.endpoints['features'] = outputs
+
+ if not features_only:
+ # Calls final layers and returns logits.
+ with tf.variable_scope('head'):
+ outputs = self._relu_fn(
+ self._bn1(self._conv_head(outputs), training=training))
+ self.endpoints['head_1x1'] = outputs
+
+ if self._global_params.local_pooling:
+ shape = outputs.get_shape().as_list()
+ kernel_size = [
+ 1, shape[self._spatial_dims[0]], shape[self._spatial_dims[1]], 1]
+ outputs = tf.nn.avg_pool(
+ outputs, ksize=kernel_size, strides=[1, 1, 1, 1], padding='VALID')
+ self.endpoints['pooled_features'] = outputs
+ if not pooled_features_only:
+ if self._dropout:
+ outputs = self._dropout(outputs, training=training)
+ self.endpoints['global_pool'] = outputs
+ if self._fc:
+ outputs = tf.squeeze(outputs, self._spatial_dims)
+ outputs = self._fc(outputs)
+ self.endpoints['head'] = outputs
+ else:
+ outputs = self._avg_pooling(outputs)
+ self.endpoints['pooled_features'] = outputs
+ if not pooled_features_only:
+ if self._dropout:
+ outputs = self._dropout(outputs, training=training)
+ self.endpoints['global_pool'] = outputs
+ if self._fc:
+ outputs = self._fc(outputs)
+ self.endpoints['head'] = outputs
+ return outputs
diff --git a/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/original_tf/eval_ckpt_main.py b/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/original_tf/eval_ckpt_main.py
new file mode 100644
index 0000000000000000000000000000000000000000..5993c323b3a8340fd0914ef56bf2a75cda5723d6
--- /dev/null
+++ b/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/original_tf/eval_ckpt_main.py
@@ -0,0 +1,225 @@
+# Copyright 2019 The TensorFlow Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ==============================================================================
+"""Eval checkpoint driver.
+
+This is an example evaluation script for users to understand the EfficientNet
+model checkpoints on CPU. To serve EfficientNet, please consider to export a
+`SavedModel` from checkpoints and use tf-serving to serve.
+"""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import json
+import sys
+from absl import app
+from absl import flags
+import numpy as np
+import tensorflow as tf
+
+
+import efficientnet_builder
+import preprocessing
+
+
+tf.compat.v1.disable_v2_behavior()
+
+flags.DEFINE_string('model_name', 'efficientnet-b0', 'Model name to eval.')
+flags.DEFINE_string('runmode', 'examples', 'Running mode: examples or imagenet')
+flags.DEFINE_string('imagenet_eval_glob', None,
+ 'Imagenet eval image glob, '
+ 'such as /imagenet/ILSVRC2012*.JPEG')
+flags.DEFINE_string('imagenet_eval_label', None,
+ 'Imagenet eval label file path, '
+ 'such as /imagenet/ILSVRC2012_validation_ground_truth.txt')
+flags.DEFINE_string('ckpt_dir', '/tmp/ckpt/', 'Checkpoint folders')
+flags.DEFINE_string('example_img', '/tmp/panda.jpg',
+ 'Filepath for a single example image.')
+flags.DEFINE_string('labels_map_file', '/tmp/labels_map.txt',
+ 'Labels map from label id to its meaning.')
+flags.DEFINE_integer('num_images', 5000,
+ 'Number of images to eval. Use -1 to eval all images.')
+FLAGS = flags.FLAGS
+
+MEAN_RGB = [0.485 * 255, 0.456 * 255, 0.406 * 255]
+STDDEV_RGB = [0.229 * 255, 0.224 * 255, 0.225 * 255]
+
+
+class EvalCkptDriver(object):
+ """A driver for running eval inference.
+
+ Attributes:
+ model_name: str. Model name to eval.
+ batch_size: int. Eval batch size.
+ num_classes: int. Number of classes, default to 1000 for ImageNet.
+ image_size: int. Input image size, determined by model name.
+ """
+
+ def __init__(self, model_name='efficientnet-b0', batch_size=1):
+ """Initialize internal variables."""
+ self.model_name = model_name
+ self.batch_size = batch_size
+ self.num_classes = 1000
+ # Model Scaling parameters
+ _, _, self.image_size, _ = efficientnet_builder.efficientnet_params(
+ model_name)
+
+ def restore_model(self, sess, ckpt_dir):
+ """Restore variables from checkpoint dir."""
+ checkpoint = tf.train.latest_checkpoint(ckpt_dir)
+ ema = tf.train.ExponentialMovingAverage(decay=0.9999)
+ ema_vars = tf.compat.v1.trainable_variables() + tf.compat.v1.get_collection('moving_vars')
+ for v in tf.compat.v1.global_variables():
+ if 'moving_mean' in v.name or 'moving_variance' in v.name:
+ ema_vars.append(v)
+ ema_vars = list(set(ema_vars))
+ var_dict = ema.variables_to_restore(ema_vars)
+ saver = tf.compat.v1.train.Saver(var_dict, max_to_keep=1)
+ saver.restore(sess, checkpoint)
+
+ def build_model(self, features, is_training):
+ """Build model with input features."""
+ features -= tf.constant(MEAN_RGB, shape=[1, 1, 3], dtype=features.dtype)
+ features /= tf.constant(STDDEV_RGB, shape=[1, 1, 3], dtype=features.dtype)
+ logits, _ = efficientnet_builder.build_model(
+ features, self.model_name, is_training)
+ probs = tf.nn.softmax(logits)
+ probs = tf.squeeze(probs)
+ return probs
+
+ def build_dataset(self, filenames, labels, is_training):
+ """Build input dataset."""
+ filenames = tf.constant(filenames)
+ labels = tf.constant(labels)
+
+ dataset = tf.compat.v1.data.Dataset.from_tensor_slices((filenames, labels))
+
+ def _parse_function(filename, label):
+ image_string = tf.io.read_file(filename)
+ image_decoded = preprocessing.preprocess_image(
+ image_string, is_training, self.image_size)
+ image = tf.cast(image_decoded, tf.float32)
+ return image, label
+
+ dataset = dataset.map(_parse_function)
+ dataset = dataset.batch(self.batch_size)
+
+ iterator = dataset.make_one_shot_iterator()
+ #iterator = iter(dataset)
+ images, labels = iterator.get_next()
+ return images, labels
+
+ def run_inference(self, ckpt_dir, image_files, labels):
+ """Build and run inference on the target images and labels."""
+ with tf.Graph().as_default(), tf.Session() as sess:
+ images, labels = self.build_dataset(image_files, labels, False)
+ probs = self.build_model(images, is_training=False)
+
+ sess.run(tf.global_variables_initializer())
+ self.restore_model(sess, ckpt_dir)
+
+ prediction_idx = []
+ prediction_prob = []
+ for _ in range(len(image_files) // self.batch_size):
+ out_probs = sess.run(probs)
+ idx = np.argsort(out_probs)[::-1]
+ prediction_idx.append(idx[:5])
+ prediction_prob.append([out_probs[pid] for pid in idx[:5]])
+
+ # Return the top 5 predictions (idx and prob) for each image.
+ return prediction_idx, prediction_prob
+
+
+def eval_example_images(model_name, ckpt_dir, image_files, labels_map_file):
+ """Eval a list of example images.
+
+ Args:
+ model_name: str. The name of model to eval.
+ ckpt_dir: str. Checkpoint directory path.
+ image_files: List[str]. A list of image file paths.
+ labels_map_file: str. The labels map file path.
+
+ Returns:
+ A tuple (pred_idx, and pred_prob), where pred_idx is the top 5 prediction
+ index and pred_prob is the top 5 prediction probability.
+ """
+ eval_ckpt_driver = EvalCkptDriver(model_name)
+ classes = json.loads(tf.gfile.Open(labels_map_file).read())
+ pred_idx, pred_prob = eval_ckpt_driver.run_inference(
+ ckpt_dir, image_files, [0] * len(image_files))
+ for i in range(len(image_files)):
+ print('predicted class for image {}: '.format(image_files[i]))
+ for j, idx in enumerate(pred_idx[i]):
+ print(' -> top_{} ({:4.2f}%): {} '.format(
+ j, pred_prob[i][j] * 100, classes[str(idx)]))
+ return pred_idx, pred_prob
+
+
+def eval_imagenet(model_name,
+ ckpt_dir,
+ imagenet_eval_glob,
+ imagenet_eval_label,
+ num_images):
+ """Eval ImageNet images and report top1/top5 accuracy.
+
+ Args:
+ model_name: str. The name of model to eval.
+ ckpt_dir: str. Checkpoint directory path.
+ imagenet_eval_glob: str. File path glob for all eval images.
+ imagenet_eval_label: str. File path for eval label.
+ num_images: int. Number of images to eval: -1 means eval the whole dataset.
+
+ Returns:
+ A tuple (top1, top5) for top1 and top5 accuracy.
+ """
+ eval_ckpt_driver = EvalCkptDriver(model_name)
+ imagenet_val_labels = [int(i) for i in tf.gfile.GFile(imagenet_eval_label)]
+ imagenet_filenames = sorted(tf.gfile.Glob(imagenet_eval_glob))
+ if num_images < 0:
+ num_images = len(imagenet_filenames)
+ image_files = imagenet_filenames[:num_images]
+ labels = imagenet_val_labels[:num_images]
+
+ pred_idx, _ = eval_ckpt_driver.run_inference(ckpt_dir, image_files, labels)
+ top1_cnt, top5_cnt = 0.0, 0.0
+ for i, label in enumerate(labels):
+ top1_cnt += label in pred_idx[i][:1]
+ top5_cnt += label in pred_idx[i][:5]
+ if i % 100 == 0:
+ print('Step {}: top1_acc = {:4.2f}% top5_acc = {:4.2f}%'.format(
+ i, 100 * top1_cnt / (i + 1), 100 * top5_cnt / (i + 1)))
+ sys.stdout.flush()
+ top1, top5 = 100 * top1_cnt / num_images, 100 * top5_cnt / num_images
+ print('Final: top1_acc = {:4.2f}% top5_acc = {:4.2f}%'.format(top1, top5))
+ return top1, top5
+
+
+def main(unused_argv):
+ tf.logging.set_verbosity(tf.logging.ERROR)
+ if FLAGS.runmode == 'examples':
+ # Run inference for an example image.
+ eval_example_images(FLAGS.model_name, FLAGS.ckpt_dir, [FLAGS.example_img],
+ FLAGS.labels_map_file)
+ elif FLAGS.runmode == 'imagenet':
+ # Run inference for imagenet.
+ eval_imagenet(FLAGS.model_name, FLAGS.ckpt_dir, FLAGS.imagenet_eval_glob,
+ FLAGS.imagenet_eval_label, FLAGS.num_images)
+ else:
+ print('must specify runmode: examples or imagenet')
+
+
+if __name__ == '__main__':
+ app.run(main)
diff --git a/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/original_tf/eval_ckpt_main_tf1.py b/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/original_tf/eval_ckpt_main_tf1.py
new file mode 100644
index 0000000000000000000000000000000000000000..e869d4ee767f3444e9872a023da00730a95cd4ad
--- /dev/null
+++ b/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/original_tf/eval_ckpt_main_tf1.py
@@ -0,0 +1,221 @@
+# Copyright 2019 The TensorFlow Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ==============================================================================
+"""Eval checkpoint driver.
+
+This is an example evaluation script for users to understand the EfficientNet
+model checkpoints on CPU. To serve EfficientNet, please consider to export a
+`SavedModel` from checkpoints and use tf-serving to serve.
+"""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import json
+import sys
+from absl import app
+from absl import flags
+import numpy as np
+import tensorflow as tf
+
+
+import efficientnet_builder
+import preprocessing
+
+
+flags.DEFINE_string('model_name', 'efficientnet-b0', 'Model name to eval.')
+flags.DEFINE_string('runmode', 'examples', 'Running mode: examples or imagenet')
+flags.DEFINE_string('imagenet_eval_glob', None,
+ 'Imagenet eval image glob, '
+ 'such as /imagenet/ILSVRC2012*.JPEG')
+flags.DEFINE_string('imagenet_eval_label', None,
+ 'Imagenet eval label file path, '
+ 'such as /imagenet/ILSVRC2012_validation_ground_truth.txt')
+flags.DEFINE_string('ckpt_dir', '/tmp/ckpt/', 'Checkpoint folders')
+flags.DEFINE_string('example_img', '/tmp/panda.jpg',
+ 'Filepath for a single example image.')
+flags.DEFINE_string('labels_map_file', '/tmp/labels_map.txt',
+ 'Labels map from label id to its meaning.')
+flags.DEFINE_integer('num_images', 5000,
+ 'Number of images to eval. Use -1 to eval all images.')
+FLAGS = flags.FLAGS
+
+MEAN_RGB = [0.485 * 255, 0.456 * 255, 0.406 * 255]
+STDDEV_RGB = [0.229 * 255, 0.224 * 255, 0.225 * 255]
+
+
+class EvalCkptDriver(object):
+ """A driver for running eval inference.
+
+ Attributes:
+ model_name: str. Model name to eval.
+ batch_size: int. Eval batch size.
+ num_classes: int. Number of classes, default to 1000 for ImageNet.
+ image_size: int. Input image size, determined by model name.
+ """
+
+ def __init__(self, model_name='efficientnet-b0', batch_size=1):
+ """Initialize internal variables."""
+ self.model_name = model_name
+ self.batch_size = batch_size
+ self.num_classes = 1000
+ # Model Scaling parameters
+ _, _, self.image_size, _ = efficientnet_builder.efficientnet_params(
+ model_name)
+
+ def restore_model(self, sess, ckpt_dir):
+ """Restore variables from checkpoint dir."""
+ checkpoint = tf.train.latest_checkpoint(ckpt_dir)
+ ema = tf.train.ExponentialMovingAverage(decay=0.9999)
+ ema_vars = tf.trainable_variables() + tf.get_collection('moving_vars')
+ for v in tf.global_variables():
+ if 'moving_mean' in v.name or 'moving_variance' in v.name:
+ ema_vars.append(v)
+ ema_vars = list(set(ema_vars))
+ var_dict = ema.variables_to_restore(ema_vars)
+ saver = tf.train.Saver(var_dict, max_to_keep=1)
+ saver.restore(sess, checkpoint)
+
+ def build_model(self, features, is_training):
+ """Build model with input features."""
+ features -= tf.constant(MEAN_RGB, shape=[1, 1, 3], dtype=features.dtype)
+ features /= tf.constant(STDDEV_RGB, shape=[1, 1, 3], dtype=features.dtype)
+ logits, _ = efficientnet_builder.build_model(
+ features, self.model_name, is_training)
+ probs = tf.nn.softmax(logits)
+ probs = tf.squeeze(probs)
+ return probs
+
+ def build_dataset(self, filenames, labels, is_training):
+ """Build input dataset."""
+ filenames = tf.constant(filenames)
+ labels = tf.constant(labels)
+ dataset = tf.data.Dataset.from_tensor_slices((filenames, labels))
+
+ def _parse_function(filename, label):
+ image_string = tf.read_file(filename)
+ image_decoded = preprocessing.preprocess_image(
+ image_string, is_training, self.image_size)
+ image = tf.cast(image_decoded, tf.float32)
+ return image, label
+
+ dataset = dataset.map(_parse_function)
+ dataset = dataset.batch(self.batch_size)
+
+ iterator = dataset.make_one_shot_iterator()
+ images, labels = iterator.get_next()
+ return images, labels
+
+ def run_inference(self, ckpt_dir, image_files, labels):
+ """Build and run inference on the target images and labels."""
+ with tf.Graph().as_default(), tf.Session() as sess:
+ images, labels = self.build_dataset(image_files, labels, False)
+ probs = self.build_model(images, is_training=False)
+
+ sess.run(tf.global_variables_initializer())
+ self.restore_model(sess, ckpt_dir)
+
+ prediction_idx = []
+ prediction_prob = []
+ for _ in range(len(image_files) // self.batch_size):
+ out_probs = sess.run(probs)
+ idx = np.argsort(out_probs)[::-1]
+ prediction_idx.append(idx[:5])
+ prediction_prob.append([out_probs[pid] for pid in idx[:5]])
+
+ # Return the top 5 predictions (idx and prob) for each image.
+ return prediction_idx, prediction_prob
+
+
+def eval_example_images(model_name, ckpt_dir, image_files, labels_map_file):
+ """Eval a list of example images.
+
+ Args:
+ model_name: str. The name of model to eval.
+ ckpt_dir: str. Checkpoint directory path.
+ image_files: List[str]. A list of image file paths.
+ labels_map_file: str. The labels map file path.
+
+ Returns:
+ A tuple (pred_idx, and pred_prob), where pred_idx is the top 5 prediction
+ index and pred_prob is the top 5 prediction probability.
+ """
+ eval_ckpt_driver = EvalCkptDriver(model_name)
+ classes = json.loads(tf.gfile.Open(labels_map_file).read())
+ pred_idx, pred_prob = eval_ckpt_driver.run_inference(
+ ckpt_dir, image_files, [0] * len(image_files))
+ for i in range(len(image_files)):
+ print('predicted class for image {}: '.format(image_files[i]))
+ for j, idx in enumerate(pred_idx[i]):
+ print(' -> top_{} ({:4.2f}%): {} '.format(
+ j, pred_prob[i][j] * 100, classes[str(idx)]))
+ return pred_idx, pred_prob
+
+
+def eval_imagenet(model_name,
+ ckpt_dir,
+ imagenet_eval_glob,
+ imagenet_eval_label,
+ num_images):
+ """Eval ImageNet images and report top1/top5 accuracy.
+
+ Args:
+ model_name: str. The name of model to eval.
+ ckpt_dir: str. Checkpoint directory path.
+ imagenet_eval_glob: str. File path glob for all eval images.
+ imagenet_eval_label: str. File path for eval label.
+ num_images: int. Number of images to eval: -1 means eval the whole dataset.
+
+ Returns:
+ A tuple (top1, top5) for top1 and top5 accuracy.
+ """
+ eval_ckpt_driver = EvalCkptDriver(model_name)
+ imagenet_val_labels = [int(i) for i in tf.gfile.GFile(imagenet_eval_label)]
+ imagenet_filenames = sorted(tf.gfile.Glob(imagenet_eval_glob))
+ if num_images < 0:
+ num_images = len(imagenet_filenames)
+ image_files = imagenet_filenames[:num_images]
+ labels = imagenet_val_labels[:num_images]
+
+ pred_idx, _ = eval_ckpt_driver.run_inference(ckpt_dir, image_files, labels)
+ top1_cnt, top5_cnt = 0.0, 0.0
+ for i, label in enumerate(labels):
+ top1_cnt += label in pred_idx[i][:1]
+ top5_cnt += label in pred_idx[i][:5]
+ if i % 100 == 0:
+ print('Step {}: top1_acc = {:4.2f}% top5_acc = {:4.2f}%'.format(
+ i, 100 * top1_cnt / (i + 1), 100 * top5_cnt / (i + 1)))
+ sys.stdout.flush()
+ top1, top5 = 100 * top1_cnt / num_images, 100 * top5_cnt / num_images
+ print('Final: top1_acc = {:4.2f}% top5_acc = {:4.2f}%'.format(top1, top5))
+ return top1, top5
+
+
+def main(unused_argv):
+ tf.logging.set_verbosity(tf.logging.ERROR)
+ if FLAGS.runmode == 'examples':
+ # Run inference for an example image.
+ eval_example_images(FLAGS.model_name, FLAGS.ckpt_dir, [FLAGS.example_img],
+ FLAGS.labels_map_file)
+ elif FLAGS.runmode == 'imagenet':
+ # Run inference for imagenet.
+ eval_imagenet(FLAGS.model_name, FLAGS.ckpt_dir, FLAGS.imagenet_eval_glob,
+ FLAGS.imagenet_eval_label, FLAGS.num_images)
+ else:
+ print('must specify runmode: examples or imagenet')
+
+
+if __name__ == '__main__':
+ app.run(main)
diff --git a/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/original_tf/preprocessing.py b/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/original_tf/preprocessing.py
new file mode 100644
index 0000000000000000000000000000000000000000..e7af8ab625d40d9581ed47db3517feab74fe380d
--- /dev/null
+++ b/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/original_tf/preprocessing.py
@@ -0,0 +1,241 @@
+# Copyright 2019 The TensorFlow Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ==============================================================================
+"""ImageNet preprocessing."""
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+from absl import logging
+
+import tensorflow.compat.v1 as tf
+
+
+IMAGE_SIZE = 224
+CROP_PADDING = 32
+
+
+def distorted_bounding_box_crop(image_bytes,
+ bbox,
+ min_object_covered=0.1,
+ aspect_ratio_range=(0.75, 1.33),
+ area_range=(0.05, 1.0),
+ max_attempts=100,
+ scope=None):
+ """Generates cropped_image using one of the bboxes randomly distorted.
+
+ See `tf.image.sample_distorted_bounding_box` for more documentation.
+
+ Args:
+ image_bytes: `Tensor` of binary image data.
+ bbox: `Tensor` of bounding boxes arranged `[1, num_boxes, coords]`
+ where each coordinate is [0, 1) and the coordinates are arranged
+ as `[ymin, xmin, ymax, xmax]`. If num_boxes is 0 then use the whole
+ image.
+ min_object_covered: An optional `float`. Defaults to `0.1`. The cropped
+ area of the image must contain at least this fraction of any bounding
+ box supplied.
+ aspect_ratio_range: An optional list of `float`s. The cropped area of the
+ image must have an aspect ratio = width / height within this range.
+ area_range: An optional list of `float`s. The cropped area of the image
+ must contain a fraction of the supplied image within in this range.
+ max_attempts: An optional `int`. Number of attempts at generating a cropped
+ region of the image of the specified constraints. After `max_attempts`
+ failures, return the entire image.
+ scope: Optional `str` for name scope.
+ Returns:
+ cropped image `Tensor`
+ """
+ with tf.name_scope(scope, 'distorted_bounding_box_crop', [image_bytes, bbox]):
+ shape = tf.image.extract_jpeg_shape(image_bytes)
+ sample_distorted_bounding_box = tf.image.sample_distorted_bounding_box(
+ shape,
+ bounding_boxes=bbox,
+ min_object_covered=min_object_covered,
+ aspect_ratio_range=aspect_ratio_range,
+ area_range=area_range,
+ max_attempts=max_attempts,
+ use_image_if_no_bounding_boxes=True)
+ bbox_begin, bbox_size, _ = sample_distorted_bounding_box
+
+ # Crop the image to the specified bounding box.
+ offset_y, offset_x, _ = tf.unstack(bbox_begin)
+ target_height, target_width, _ = tf.unstack(bbox_size)
+ crop_window = tf.stack([offset_y, offset_x, target_height, target_width])
+ image = tf.image.decode_and_crop_jpeg(image_bytes, crop_window, channels=3)
+
+ return image
+
+
+def _at_least_x_are_equal(a, b, x):
+ """At least `x` of `a` and `b` `Tensors` are equal."""
+ match = tf.equal(a, b)
+ match = tf.cast(match, tf.int32)
+ return tf.greater_equal(tf.reduce_sum(match), x)
+
+
+def _decode_and_random_crop(image_bytes, image_size):
+ """Make a random crop of image_size."""
+ bbox = tf.constant([0.0, 0.0, 1.0, 1.0], dtype=tf.float32, shape=[1, 1, 4])
+ image = distorted_bounding_box_crop(
+ image_bytes,
+ bbox,
+ min_object_covered=0.1,
+ aspect_ratio_range=(3. / 4, 4. / 3.),
+ area_range=(0.08, 1.0),
+ max_attempts=10,
+ scope=None)
+ original_shape = tf.image.extract_jpeg_shape(image_bytes)
+ bad = _at_least_x_are_equal(original_shape, tf.shape(image), 3)
+
+ image = tf.cond(
+ bad,
+ lambda: _decode_and_center_crop(image_bytes, image_size),
+ lambda: tf.image.resize_bicubic([image], # pylint: disable=g-long-lambda
+ [image_size, image_size])[0])
+
+ return image
+
+
+def _decode_and_center_crop(image_bytes, image_size):
+ """Crops to center of image with padding then scales image_size."""
+ shape = tf.image.extract_jpeg_shape(image_bytes)
+ image_height = shape[0]
+ image_width = shape[1]
+
+ padded_center_crop_size = tf.cast(
+ ((image_size / (image_size + CROP_PADDING)) *
+ tf.cast(tf.minimum(image_height, image_width), tf.float32)),
+ tf.int32)
+
+ offset_height = ((image_height - padded_center_crop_size) + 1) // 2
+ offset_width = ((image_width - padded_center_crop_size) + 1) // 2
+ crop_window = tf.stack([offset_height, offset_width,
+ padded_center_crop_size, padded_center_crop_size])
+ image = tf.image.decode_and_crop_jpeg(image_bytes, crop_window, channels=3)
+ image = tf.image.resize_bicubic([image], [image_size, image_size])[0]
+ return image
+
+
+def _flip(image):
+ """Random horizontal image flip."""
+ image = tf.image.random_flip_left_right(image)
+ return image
+
+
+def preprocess_for_train(image_bytes, use_bfloat16, image_size=IMAGE_SIZE,
+ augment_name=None,
+ randaug_num_layers=None, randaug_magnitude=None):
+ """Preprocesses the given image for evaluation.
+
+ Args:
+ image_bytes: `Tensor` representing an image binary of arbitrary size.
+ use_bfloat16: `bool` for whether to use bfloat16.
+ image_size: image size.
+ augment_name: `string` that is the name of the augmentation method
+ to apply to the image. `autoaugment` if AutoAugment is to be used or
+ `randaugment` if RandAugment is to be used. If the value is `None` no
+ augmentation method will be applied applied. See autoaugment.py for more
+ details.
+ randaug_num_layers: 'int', if RandAug is used, what should the number of
+ layers be. See autoaugment.py for detailed description.
+ randaug_magnitude: 'int', if RandAug is used, what should the magnitude
+ be. See autoaugment.py for detailed description.
+
+ Returns:
+ A preprocessed image `Tensor`.
+ """
+ image = _decode_and_random_crop(image_bytes, image_size)
+ image = _flip(image)
+ image = tf.reshape(image, [image_size, image_size, 3])
+
+ image = tf.image.convert_image_dtype(
+ image, dtype=tf.bfloat16 if use_bfloat16 else tf.float32)
+
+ if augment_name:
+ try:
+ import autoaugment # pylint: disable=g-import-not-at-top
+ except ImportError as e:
+ logging.exception('Autoaugment is not supported in TF 2.x.')
+ raise e
+
+ logging.info('Apply AutoAugment policy %s', augment_name)
+ input_image_type = image.dtype
+ image = tf.clip_by_value(image, 0.0, 255.0)
+ image = tf.cast(image, dtype=tf.uint8)
+
+ if augment_name == 'autoaugment':
+ logging.info('Apply AutoAugment policy %s', augment_name)
+ image = autoaugment.distort_image_with_autoaugment(image, 'v0')
+ elif augment_name == 'randaugment':
+ image = autoaugment.distort_image_with_randaugment(
+ image, randaug_num_layers, randaug_magnitude)
+ else:
+ raise ValueError('Invalid value for augment_name: %s' % (augment_name))
+
+ image = tf.cast(image, dtype=input_image_type)
+ return image
+
+
+def preprocess_for_eval(image_bytes, use_bfloat16, image_size=IMAGE_SIZE):
+ """Preprocesses the given image for evaluation.
+
+ Args:
+ image_bytes: `Tensor` representing an image binary of arbitrary size.
+ use_bfloat16: `bool` for whether to use bfloat16.
+ image_size: image size.
+
+ Returns:
+ A preprocessed image `Tensor`.
+ """
+ image = _decode_and_center_crop(image_bytes, image_size)
+ image = tf.reshape(image, [image_size, image_size, 3])
+ image = tf.image.convert_image_dtype(
+ image, dtype=tf.bfloat16 if use_bfloat16 else tf.float32)
+ return image
+
+
+def preprocess_image(image_bytes,
+ is_training=False,
+ use_bfloat16=False,
+ image_size=IMAGE_SIZE,
+ augment_name=None,
+ randaug_num_layers=None,
+ randaug_magnitude=None):
+ """Preprocesses the given image.
+
+ Args:
+ image_bytes: `Tensor` representing an image binary of arbitrary size.
+ is_training: `bool` for whether the preprocessing is for training.
+ use_bfloat16: `bool` for whether to use bfloat16.
+ image_size: image size.
+ augment_name: `string` that is the name of the augmentation method
+ to apply to the image. `autoaugment` if AutoAugment is to be used or
+ `randaugment` if RandAugment is to be used. If the value is `None` no
+ augmentation method will be applied applied. See autoaugment.py for more
+ details.
+ randaug_num_layers: 'int', if RandAug is used, what should the number of
+ layers be. See autoaugment.py for detailed description.
+ randaug_magnitude: 'int', if RandAug is used, what should the magnitude
+ be. See autoaugment.py for detailed description.
+
+ Returns:
+ A preprocessed image `Tensor` with value range of [0, 255].
+ """
+ if is_training:
+ return preprocess_for_train(
+ image_bytes, use_bfloat16, image_size, augment_name,
+ randaug_num_layers, randaug_magnitude)
+ else:
+ return preprocess_for_eval(image_bytes, use_bfloat16, image_size)
diff --git a/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/original_tf/utils.py b/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/original_tf/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..61782ea3c45d7588dd909061e6c319272d803915
--- /dev/null
+++ b/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/original_tf/utils.py
@@ -0,0 +1,405 @@
+# Copyright 2019 The TensorFlow Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ==============================================================================
+"""Model utilities."""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import json
+import os
+import sys
+
+from absl import logging
+import numpy as np
+import tensorflow.compat.v1 as tf
+
+from tensorflow.python.tpu import tpu_function # pylint:disable=g-direct-tensorflow-import
+
+
+def build_learning_rate(initial_lr,
+ global_step,
+ steps_per_epoch=None,
+ lr_decay_type='exponential',
+ decay_factor=0.97,
+ decay_epochs=2.4,
+ total_steps=None,
+ warmup_epochs=5):
+ """Build learning rate."""
+ if lr_decay_type == 'exponential':
+ assert steps_per_epoch is not None
+ decay_steps = steps_per_epoch * decay_epochs
+ lr = tf.train.exponential_decay(
+ initial_lr, global_step, decay_steps, decay_factor, staircase=True)
+ elif lr_decay_type == 'cosine':
+ assert total_steps is not None
+ lr = 0.5 * initial_lr * (
+ 1 + tf.cos(np.pi * tf.cast(global_step, tf.float32) / total_steps))
+ elif lr_decay_type == 'constant':
+ lr = initial_lr
+ else:
+ assert False, 'Unknown lr_decay_type : %s' % lr_decay_type
+
+ if warmup_epochs:
+ logging.info('Learning rate warmup_epochs: %d', warmup_epochs)
+ warmup_steps = int(warmup_epochs * steps_per_epoch)
+ warmup_lr = (
+ initial_lr * tf.cast(global_step, tf.float32) / tf.cast(
+ warmup_steps, tf.float32))
+ lr = tf.cond(global_step < warmup_steps, lambda: warmup_lr, lambda: lr)
+
+ return lr
+
+
+def build_optimizer(learning_rate,
+ optimizer_name='rmsprop',
+ decay=0.9,
+ epsilon=0.001,
+ momentum=0.9):
+ """Build optimizer."""
+ if optimizer_name == 'sgd':
+ logging.info('Using SGD optimizer')
+ optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
+ elif optimizer_name == 'momentum':
+ logging.info('Using Momentum optimizer')
+ optimizer = tf.train.MomentumOptimizer(
+ learning_rate=learning_rate, momentum=momentum)
+ elif optimizer_name == 'rmsprop':
+ logging.info('Using RMSProp optimizer')
+ optimizer = tf.train.RMSPropOptimizer(learning_rate, decay, momentum,
+ epsilon)
+ else:
+ logging.fatal('Unknown optimizer: %s', optimizer_name)
+
+ return optimizer
+
+
+class TpuBatchNormalization(tf.layers.BatchNormalization):
+ # class TpuBatchNormalization(tf.layers.BatchNormalization):
+ """Cross replica batch normalization."""
+
+ def __init__(self, fused=False, **kwargs):
+ if fused in (True, None):
+ raise ValueError('TpuBatchNormalization does not support fused=True.')
+ super(TpuBatchNormalization, self).__init__(fused=fused, **kwargs)
+
+ def _cross_replica_average(self, t, num_shards_per_group):
+ """Calculates the average value of input tensor across TPU replicas."""
+ num_shards = tpu_function.get_tpu_context().number_of_shards
+ group_assignment = None
+ if num_shards_per_group > 1:
+ if num_shards % num_shards_per_group != 0:
+ raise ValueError('num_shards: %d mod shards_per_group: %d, should be 0'
+ % (num_shards, num_shards_per_group))
+ num_groups = num_shards // num_shards_per_group
+ group_assignment = [[
+ x for x in range(num_shards) if x // num_shards_per_group == y
+ ] for y in range(num_groups)]
+ return tf.tpu.cross_replica_sum(t, group_assignment) / tf.cast(
+ num_shards_per_group, t.dtype)
+
+ def _moments(self, inputs, reduction_axes, keep_dims):
+ """Compute the mean and variance: it overrides the original _moments."""
+ shard_mean, shard_variance = super(TpuBatchNormalization, self)._moments(
+ inputs, reduction_axes, keep_dims=keep_dims)
+
+ num_shards = tpu_function.get_tpu_context().number_of_shards or 1
+ if num_shards <= 8: # Skip cross_replica for 2x2 or smaller slices.
+ num_shards_per_group = 1
+ else:
+ num_shards_per_group = max(8, num_shards // 8)
+ logging.info('TpuBatchNormalization with num_shards_per_group %s',
+ num_shards_per_group)
+ if num_shards_per_group > 1:
+ # Compute variance using: Var[X]= E[X^2] - E[X]^2.
+ shard_square_of_mean = tf.math.square(shard_mean)
+ shard_mean_of_square = shard_variance + shard_square_of_mean
+ group_mean = self._cross_replica_average(
+ shard_mean, num_shards_per_group)
+ group_mean_of_square = self._cross_replica_average(
+ shard_mean_of_square, num_shards_per_group)
+ group_variance = group_mean_of_square - tf.math.square(group_mean)
+ return (group_mean, group_variance)
+ else:
+ return (shard_mean, shard_variance)
+
+
+class BatchNormalization(tf.layers.BatchNormalization):
+ """Fixed default name of BatchNormalization to match TpuBatchNormalization."""
+
+ def __init__(self, name='tpu_batch_normalization', **kwargs):
+ super(BatchNormalization, self).__init__(name=name, **kwargs)
+
+
+def drop_connect(inputs, is_training, survival_prob):
+ """Drop the entire conv with given survival probability."""
+ # "Deep Networks with Stochastic Depth", https://arxiv.org/pdf/1603.09382.pdf
+ if not is_training:
+ return inputs
+
+ # Compute tensor.
+ batch_size = tf.shape(inputs)[0]
+ random_tensor = survival_prob
+ random_tensor += tf.random_uniform([batch_size, 1, 1, 1], dtype=inputs.dtype)
+ binary_tensor = tf.floor(random_tensor)
+ # Unlike conventional way that multiply survival_prob at test time, here we
+ # divide survival_prob at training time, such that no addition compute is
+ # needed at test time.
+ output = tf.div(inputs, survival_prob) * binary_tensor
+ return output
+
+
+def archive_ckpt(ckpt_eval, ckpt_objective, ckpt_path):
+ """Archive a checkpoint if the metric is better."""
+ ckpt_dir, ckpt_name = os.path.split(ckpt_path)
+
+ saved_objective_path = os.path.join(ckpt_dir, 'best_objective.txt')
+ saved_objective = float('-inf')
+ if tf.gfile.Exists(saved_objective_path):
+ with tf.gfile.GFile(saved_objective_path, 'r') as f:
+ saved_objective = float(f.read())
+ if saved_objective > ckpt_objective:
+ logging.info('Ckpt %s is worse than %s', ckpt_objective, saved_objective)
+ return False
+
+ filenames = tf.gfile.Glob(ckpt_path + '.*')
+ if filenames is None:
+ logging.info('No files to copy for checkpoint %s', ckpt_path)
+ return False
+
+ # Clear the old folder.
+ dst_dir = os.path.join(ckpt_dir, 'archive')
+ if tf.gfile.Exists(dst_dir):
+ tf.gfile.DeleteRecursively(dst_dir)
+ tf.gfile.MakeDirs(dst_dir)
+
+ # Write checkpoints.
+ for f in filenames:
+ dest = os.path.join(dst_dir, os.path.basename(f))
+ tf.gfile.Copy(f, dest, overwrite=True)
+ ckpt_state = tf.train.generate_checkpoint_state_proto(
+ dst_dir,
+ model_checkpoint_path=ckpt_name,
+ all_model_checkpoint_paths=[ckpt_name])
+ with tf.gfile.GFile(os.path.join(dst_dir, 'checkpoint'), 'w') as f:
+ f.write(str(ckpt_state))
+ with tf.gfile.GFile(os.path.join(dst_dir, 'best_eval.txt'), 'w') as f:
+ f.write('%s' % ckpt_eval)
+
+ # Update the best objective.
+ with tf.gfile.GFile(saved_objective_path, 'w') as f:
+ f.write('%f' % ckpt_objective)
+
+ logging.info('Copying checkpoint %s to %s', ckpt_path, dst_dir)
+ return True
+
+
+def get_ema_vars():
+ """Get all exponential moving average (ema) variables."""
+ ema_vars = tf.trainable_variables() + tf.get_collection('moving_vars')
+ for v in tf.global_variables():
+ # We maintain mva for batch norm moving mean and variance as well.
+ if 'moving_mean' in v.name or 'moving_variance' in v.name:
+ ema_vars.append(v)
+ return list(set(ema_vars))
+
+
+class DepthwiseConv2D(tf.keras.layers.DepthwiseConv2D, tf.layers.Layer):
+ """Wrap keras DepthwiseConv2D to tf.layers."""
+
+ pass
+
+
+class EvalCkptDriver(object):
+ """A driver for running eval inference.
+
+ Attributes:
+ model_name: str. Model name to eval.
+ batch_size: int. Eval batch size.
+ image_size: int. Input image size, determined by model name.
+ num_classes: int. Number of classes, default to 1000 for ImageNet.
+ include_background_label: whether to include extra background label.
+ """
+
+ def __init__(self,
+ model_name,
+ batch_size=1,
+ image_size=224,
+ num_classes=1000,
+ include_background_label=False):
+ """Initialize internal variables."""
+ self.model_name = model_name
+ self.batch_size = batch_size
+ self.num_classes = num_classes
+ self.include_background_label = include_background_label
+ self.image_size = image_size
+
+ def restore_model(self, sess, ckpt_dir, enable_ema=True, export_ckpt=None):
+ """Restore variables from checkpoint dir."""
+ sess.run(tf.global_variables_initializer())
+ checkpoint = tf.train.latest_checkpoint(ckpt_dir)
+ if enable_ema:
+ ema = tf.train.ExponentialMovingAverage(decay=0.0)
+ ema_vars = get_ema_vars()
+ var_dict = ema.variables_to_restore(ema_vars)
+ ema_assign_op = ema.apply(ema_vars)
+ else:
+ var_dict = get_ema_vars()
+ ema_assign_op = None
+
+ tf.train.get_or_create_global_step()
+ sess.run(tf.global_variables_initializer())
+ saver = tf.train.Saver(var_dict, max_to_keep=1)
+ saver.restore(sess, checkpoint)
+
+ if export_ckpt:
+ if ema_assign_op is not None:
+ sess.run(ema_assign_op)
+ saver = tf.train.Saver(max_to_keep=1, save_relative_paths=True)
+ saver.save(sess, export_ckpt)
+
+ def build_model(self, features, is_training):
+ """Build model with input features."""
+ del features, is_training
+ raise ValueError('Must be implemented by subclasses.')
+
+ def get_preprocess_fn(self):
+ raise ValueError('Must be implemented by subclsses.')
+
+ def build_dataset(self, filenames, labels, is_training):
+ """Build input dataset."""
+ batch_drop_remainder = False
+ if 'condconv' in self.model_name and not is_training:
+ # CondConv layers can only be called with known batch dimension. Thus, we
+ # must drop all remaining examples that do not make up one full batch.
+ # To ensure all examples are evaluated, use a batch size that evenly
+ # divides the number of files.
+ batch_drop_remainder = True
+ num_files = len(filenames)
+ if num_files % self.batch_size != 0:
+ tf.logging.warn('Remaining examples in last batch are not being '
+ 'evaluated.')
+ filenames = tf.constant(filenames)
+ labels = tf.constant(labels)
+ dataset = tf.data.Dataset.from_tensor_slices((filenames, labels))
+
+ def _parse_function(filename, label):
+ image_string = tf.read_file(filename)
+ preprocess_fn = self.get_preprocess_fn()
+ image_decoded = preprocess_fn(
+ image_string, is_training, image_size=self.image_size)
+ image = tf.cast(image_decoded, tf.float32)
+ return image, label
+
+ dataset = dataset.map(_parse_function)
+ dataset = dataset.batch(self.batch_size,
+ drop_remainder=batch_drop_remainder)
+
+ iterator = dataset.make_one_shot_iterator()
+ images, labels = iterator.get_next()
+ return images, labels
+
+ def run_inference(self,
+ ckpt_dir,
+ image_files,
+ labels,
+ enable_ema=True,
+ export_ckpt=None):
+ """Build and run inference on the target images and labels."""
+ label_offset = 1 if self.include_background_label else 0
+ with tf.Graph().as_default(), tf.Session() as sess:
+ images, labels = self.build_dataset(image_files, labels, False)
+ probs = self.build_model(images, is_training=False)
+ if isinstance(probs, tuple):
+ probs = probs[0]
+
+ self.restore_model(sess, ckpt_dir, enable_ema, export_ckpt)
+
+ prediction_idx = []
+ prediction_prob = []
+ for _ in range(len(image_files) // self.batch_size):
+ out_probs = sess.run(probs)
+ idx = np.argsort(out_probs)[::-1]
+ prediction_idx.append(idx[:5] - label_offset)
+ prediction_prob.append([out_probs[pid] for pid in idx[:5]])
+
+ # Return the top 5 predictions (idx and prob) for each image.
+ return prediction_idx, prediction_prob
+
+ def eval_example_images(self,
+ ckpt_dir,
+ image_files,
+ labels_map_file,
+ enable_ema=True,
+ export_ckpt=None):
+ """Eval a list of example images.
+
+ Args:
+ ckpt_dir: str. Checkpoint directory path.
+ image_files: List[str]. A list of image file paths.
+ labels_map_file: str. The labels map file path.
+ enable_ema: enable expotential moving average.
+ export_ckpt: export ckpt folder.
+
+ Returns:
+ A tuple (pred_idx, and pred_prob), where pred_idx is the top 5 prediction
+ index and pred_prob is the top 5 prediction probability.
+ """
+ classes = json.loads(tf.gfile.Open(labels_map_file).read())
+ pred_idx, pred_prob = self.run_inference(
+ ckpt_dir, image_files, [0] * len(image_files), enable_ema, export_ckpt)
+ for i in range(len(image_files)):
+ print('predicted class for image {}: '.format(image_files[i]))
+ for j, idx in enumerate(pred_idx[i]):
+ print(' -> top_{} ({:4.2f}%): {} '.format(j, pred_prob[i][j] * 100,
+ classes[str(idx)]))
+ return pred_idx, pred_prob
+
+ def eval_imagenet(self, ckpt_dir, imagenet_eval_glob,
+ imagenet_eval_label, num_images, enable_ema, export_ckpt):
+ """Eval ImageNet images and report top1/top5 accuracy.
+
+ Args:
+ ckpt_dir: str. Checkpoint directory path.
+ imagenet_eval_glob: str. File path glob for all eval images.
+ imagenet_eval_label: str. File path for eval label.
+ num_images: int. Number of images to eval: -1 means eval the whole
+ dataset.
+ enable_ema: enable expotential moving average.
+ export_ckpt: export checkpoint folder.
+
+ Returns:
+ A tuple (top1, top5) for top1 and top5 accuracy.
+ """
+ imagenet_val_labels = [int(i) for i in tf.gfile.GFile(imagenet_eval_label)]
+ imagenet_filenames = sorted(tf.gfile.Glob(imagenet_eval_glob))
+ if num_images < 0:
+ num_images = len(imagenet_filenames)
+ image_files = imagenet_filenames[:num_images]
+ labels = imagenet_val_labels[:num_images]
+
+ pred_idx, _ = self.run_inference(
+ ckpt_dir, image_files, labels, enable_ema, export_ckpt)
+ top1_cnt, top5_cnt = 0.0, 0.0
+ for i, label in enumerate(labels):
+ top1_cnt += label in pred_idx[i][:1]
+ top5_cnt += label in pred_idx[i][:5]
+ if i % 100 == 0:
+ print('Step {}: top1_acc = {:4.2f}% top5_acc = {:4.2f}%'.format(
+ i, 100 * top1_cnt / (i + 1), 100 * top5_cnt / (i + 1)))
+ sys.stdout.flush()
+ top1, top5 = 100 * top1_cnt / num_images, 100 * top5_cnt / num_images
+ print('Final: top1_acc = {:4.2f}% top5_acc = {:4.2f}%'.format(top1, top5))
+ return top1, top5
diff --git a/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/rename.sh b/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/rename.sh
new file mode 100644
index 0000000000000000000000000000000000000000..aa791139895b14ae1ffe00098cc55c56dfeca0fd
--- /dev/null
+++ b/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/rename.sh
@@ -0,0 +1,5 @@
+for i in 0 1 2 3 4 5 6 7 8
+do
+ X=$(sha256sum efficientnet-b${i}.pth | head -c 8)
+ mv efficientnet-b${i}.pth efficientnet-b${i}-${X}.pth
+done
diff --git a/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/run.sh b/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/run.sh
new file mode 100644
index 0000000000000000000000000000000000000000..f80d5f5d9b879ce98d180672c5abcb3dd9e569b9
--- /dev/null
+++ b/clean/video/mintime/models/efficientnet/tf_to_pytorch/convert_tf_to_pt/run.sh
@@ -0,0 +1,17 @@
+python ../convert_tf_to_pt/load_tf_weights.py --model_name efficientnet-b0 --tf_checkpoint ../pretrained_tensorflow/efficientnet-b0/ --output_file ../pretrained_pytorch/efficientnet-b0.pth
+
+# python ../convert_tf_to_pt/load_tf_weights.py --model_name efficientnet-b1 --tf_checkpoint ../pretrained_tensorflow/efficientnet-b1/ --output_file ../pretrained_pytorch/efficientnet-b1.pth
+
+# python ../convert_tf_to_pt/load_tf_weights.py --model_name efficientnet-b2 --tf_checkpoint ../pretrained_tensorflow/efficientnet-b2/ --output_file ../pretrained_pytorch/efficientnet-b2.pth
+
+# python ../convert_tf_to_pt/load_tf_weights.py --model_name efficientnet-b3 --tf_checkpoint ../pretrained_tensorflow/efficientnet-b3/ --output_file ../pretrained_pytorch/efficientnet-b3.pth
+
+# python ../convert_tf_to_pt/load_tf_weights.py --model_name efficientnet-b4 --tf_checkpoint ../pretrained_tensorflow/efficientnet-b4/ --output_file ../pretrained_pytorch/efficientnet-b4.pth
+
+# python ../convert_tf_to_pt/load_tf_weights.py --model_name efficientnet-b5 --tf_checkpoint ../pretrained_tensorflow/efficientnet-b5/ --output_file ../pretrained_pytorch/efficientnet-b5.pth
+
+# python ../convert_tf_to_pt/load_tf_weights.py --model_name efficientnet-b6 --tf_checkpoint ../pretrained_tensorflow/efficientnet-b6/ --output_file ../pretrained_pytorch/efficientnet-b6.pth
+
+# python ../convert_tf_to_pt/load_tf_weights.py --model_name efficientnet-b7 --tf_checkpoint ../pretrained_tensorflow/efficientnet-b7/ --output_file ../pretrained_pytorch/efficientnet-b7.pth
+
+# python ../convert_tf_to_pt/load_tf_weights.py --model_name efficientnet-b8 --tf_checkpoint ../pretrained_tensorflow/efficientnet-b8/ --output_file ../pretrained_pytorch/efficientnet-b8.pth
diff --git a/clean/video/mintime/models/size_invariant_timesformer.py b/clean/video/mintime/models/size_invariant_timesformer.py
new file mode 100644
index 0000000000000000000000000000000000000000..67f405858d9c8ef1b09003bd969a176068c35140
--- /dev/null
+++ b/clean/video/mintime/models/size_invariant_timesformer.py
@@ -0,0 +1,276 @@
+import torch
+from torch import nn, einsum
+import torch.nn.functional as F
+from einops import rearrange, repeat
+from statistics import mean
+from models.efficientnet.efficientnet_pytorch import EfficientNet
+from torch.nn.init import trunc_normal_
+import cv2
+import numpy as np
+from random import random
+
+
+# helpers
+def exists(val):
+ return val is not None
+
+# classes
+class PreNorm(nn.Module):
+ def __init__(self, dim, fn):
+ super().__init__()
+ self.fn = fn
+ self.norm = nn.LayerNorm(dim)
+
+ def forward(self, x, *args, **kwargs):
+ x = self.norm(x)
+ return self.fn(x, *args, **kwargs)
+
+# time token shift
+
+def shift(t, amt):
+ if amt is 0:
+ return t
+ return F.pad(t, (0, 0, 0, 0, amt, -amt))
+
+class PreTokenShift(nn.Module):
+ def __init__(self, frames, fn):
+ super().__init__()
+ self.frames = frames
+ self.fn = fn
+
+ def forward(self, x, *args, **kwargs):
+ f, dim = self.frames, x.shape[-1]
+ cls_x, x = x[:, :1], x[:, 1:]
+ x = rearrange(x, 'b (f n) d -> b f n d', f = f)
+
+ # shift along time frame before and after
+
+ dim_chunk = (dim // 3)
+ chunks = x.split(dim_chunk, dim = -1)
+ chunks_to_shift, rest = chunks[:3], chunks[3:]
+ shifted_chunks = tuple(map(lambda args: shift(*args), zip(chunks_to_shift, (-1, 0, 1))))
+ x = torch.cat((*shifted_chunks, *rest), dim = -1)
+
+ x = rearrange(x, 'b f n d -> b (f n) d')
+ x = torch.cat((cls_x, x), dim = 1)
+ return self.fn(x, *args, **kwargs)
+
+# feedforward
+
+class GEGLU(nn.Module):
+ def forward(self, x):
+ x, gates = x.chunk(2, dim = -1)
+ return x * F.gelu(gates)
+
+class FeedForward(nn.Module):
+ def __init__(self, dim, mult = 4, dropout = 0.):
+ super().__init__()
+ self.net = nn.Sequential(
+ nn.Linear(dim, dim * mult * 2),
+ GEGLU(),
+ nn.Dropout(dropout),
+ nn.Linear(dim * mult, dim)
+ )
+
+ def forward(self, x):
+ return self.net(x)
+
+# attention
+
+def attn(q, k, v, mask = None):
+ sim = einsum('b i d, b j d -> b i j', q, k)
+ if exists(mask):
+ max_neg_value = -torch.finfo(sim.dtype).max
+ sim.masked_fill_(~mask, max_neg_value)
+ attn = sim.softmax(dim = -1)
+ out = einsum('b i j, b j d -> b i d', attn, v)
+ return out, attn
+
+class Attention(nn.Module):
+ def __init__(
+ self,
+ dim,
+ dim_head = 64,
+ heads = 8,
+ dropout = 0.,
+ ):
+ super().__init__()
+ self.heads = heads
+ self.scale = dim_head ** -0.5
+ inner_dim = dim_head * heads
+
+ self.to_qkv = nn.Linear(dim, inner_dim * 3, bias = False)
+ self.to_out = nn.Sequential(
+ nn.Linear(inner_dim, dim),
+ nn.Dropout(dropout)
+ )
+
+
+ def forward(self, x, einops_from, einops_to, mask = None, cls_mask = None, identities_mask = None, rot_emb = None, **einops_dims):
+ h = self.heads
+ q, k, v = self.to_qkv(x).chunk(3, dim = -1)
+ q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> (b h) n d', h = h), (q, k, v))
+
+ q = q * self.scale
+
+ # splice out classification token at index 1
+ (cls_q, q_), (cls_k, k_), (cls_v, v_) = map(lambda t: (t[:, :1], t[:, 1:]), (q, k, v))
+
+ # let classification token attend to key / values of all patches across time and space
+ cls_out, cls_attentions = attn(cls_q, k, v, mask = cls_mask)
+ # rearrange across time or space
+ q_, k_, v_ = map(lambda t: rearrange(t, f'{einops_from} -> {einops_to}', **einops_dims), (q_, k_, v_))
+
+ # expand cls token keys and values across time or space and concat
+ r = q_.shape[0] // cls_k.shape[0]
+ cls_k, cls_v = map(lambda t: repeat(t, 'b () d -> (b r) () d', r = r), (cls_k, cls_v))
+
+ k_ = torch.cat((cls_k, k_), dim = 1)
+ v_ = torch.cat((cls_v, v_), dim = 1)
+
+ # attention
+ out, attentions = attn(q_, k_, v_, mask = mask)
+
+ # merge back time or space
+ out = rearrange(out, f'{einops_to} -> {einops_from}', **einops_dims)
+
+ # concat back the cls token
+ out = torch.cat((cls_out, out), dim = 1)
+
+ # merge back the heads
+ out = rearrange(out, '(b h) n d -> b n (h d)', h = h)
+
+ # combine heads out
+ return self.to_out(out), cls_attentions
+
+
+class SizeInvariantTimeSformer(nn.Module):
+ def __init__(
+ self,
+ *,
+ config,
+ require_attention = False
+ ):
+
+ super().__init__()
+ self.dim = config['model']['dim']
+ self.num_frames = config['model']['num-frames']
+ self.max_identities = config['model']['max-identities']
+ self.image_size = config['model']['image-size']
+ self.num_classes = config['model']['num-classes']
+ self.patch_size = config['model']['patch-size']
+ self.num_patches = config['model']['num-patches']
+ self.channels = config['model']['channels']
+ self.depth = config['model']['depth']
+ self.heads = config['model']['heads']
+ self.dim_head = config['model']['dim-head']
+ self.attn_dropout = config['model']['attn-dropout']
+ self.ff_dropout = config['model']['ff-dropout']
+ self.shift_tokens = config['model']['shift-tokens']
+ self.enable_size_emb = config['model']['enable-size-emb']
+ self.enable_pos_emb = config['model']['enable-pos-emb']
+ self.require_attention = require_attention
+
+ num_positions = self.num_frames * self.channels
+ self.to_patch_embedding = nn.Linear(self.channels , self.dim)
+ self.cls_token = nn.Parameter(torch.randn(1, self.dim))
+
+ self.pos_emb = nn.Embedding(num_positions + 1, self.dim)
+ if self.enable_size_emb:
+ self.size_emb = nn.Embedding(num_positions + 1, self.dim)
+
+
+ self.layers = nn.ModuleList([])
+ for _ in range(self.depth):
+ ff = FeedForward(self.dim, dropout = self.ff_dropout)
+ time_attn = Attention(self.dim, dim_head = self.dim_head, heads = self.heads, dropout = self.attn_dropout)
+ spatial_attn = Attention(self.dim, dim_head = self.dim_head, heads = self.heads, dropout = self.attn_dropout)
+ if self.shift_tokens:
+ time_attn, spatial_attn, ff = map(lambda t: PreTokenShift(num_frames, t), (time_attn, spatial_attn, ff))
+
+
+ time_attn, spatial_attn, ff = map(lambda t: PreNorm(self.dim, t), (time_attn, spatial_attn, ff))
+ self.layers.append(nn.ModuleList([time_attn, spatial_attn, ff]))
+
+ self.to_out = nn.Sequential(
+ nn.LayerNorm(self.dim),
+ nn.Linear(self.dim, self.num_classes)
+ )
+
+ # Initialization
+ trunc_normal_(self.pos_emb.weight, std=.02)
+ trunc_normal_(self.cls_token, std=.02)
+ if self.enable_size_emb:
+ trunc_normal_(self.size_emb.weight, std=.02)
+ self.apply(self._init_weights)
+
+ def _init_weights(self, m):
+ if isinstance(m, nn.Linear):
+ trunc_normal_(m.weight, std=.02)
+ if isinstance(m, nn.Linear) and m.bias is not None:
+ nn.init.constant_(m.bias, 0)
+ elif isinstance(m, nn.LayerNorm):
+ nn.init.constant_(m.bias, 0)
+ nn.init.constant_(m.weight, 1.0)
+
+ @torch.jit.ignore
+ def no_weight_decay(self):
+ if self.enable_size_emb:
+ return {'pos_emb', 'cls_token', 'size_emb'}
+ else:
+ return {'pos_emb', 'cls_token'}
+
+
+ def forward(self, x, mask = None, identities_mask = None, size_embedding = None, positions = None):
+ b, f, c, h, w, *_, device = *x.shape, x.device
+ n = h * w
+ x = rearrange(x, 'b f c h w -> b (f h w) c') # B x F*P*P x C
+ tokens = self.to_patch_embedding(x) # B x 8*7*7 x dim
+
+ # Add cls token
+ cls_token = repeat(self.cls_token, 'n d -> b n d', b = b)
+ x = torch.cat((cls_token, tokens), dim = 1)
+
+ # Positional
+ if self.enable_pos_emb:
+ x += self.pos_emb(positions)
+ else:
+ x += (self.pos_emb(torch.arange(x.shape[1]).to(device)))
+
+ # Size embedding
+ if self.enable_size_emb:
+ size_embedding = repeat(size_embedding, 'b f -> b f p', p=self.num_patches) # B x 8 x 49
+ size_embedding = rearrange(size_embedding, 'b f p -> b (f p)')
+ cls_token = torch.Tensor([0]*b).unsqueeze(-1).to(device)
+ size_embedding = size_embedding.to(device)
+ size_embedding = torch.cat((cls_token, size_embedding), dim = 1)
+ size_embedding = size_embedding.to(device).int()
+ x += self.size_emb(size_embedding)
+
+
+ # Frame mask
+ frame_mask = repeat(mask, 'b f1 -> b f2 f1', f2 = self.num_frames)
+ frame_mask = torch.logical_and(frame_mask, identities_mask)
+ frame_mask = F.pad(frame_mask, (1, 0), value= True)
+ frame_mask = repeat(frame_mask, 'b f1 f2 -> (b h n) f1 f2', n = n, h = self.heads)
+
+
+ # CLS mask
+ cls_attn_mask = repeat(mask, 'b f -> (b h) () (f n)', n = n, h = self.heads)
+ cls_attn_mask = F.pad(cls_attn_mask, (1, 0), value = True)
+
+ # Time and space attention
+ for (time_attn, spatial_attn, ff) in self.layers:
+ y, time_attention = time_attn(x, 'b (f n) d', '(b n) f d', n = n, mask = frame_mask, cls_mask = cls_attn_mask)
+ x = x + y
+ y, space_attention = spatial_attn(x, 'b (f n) d', '(b f) n d', f = f, cls_mask = cls_attn_mask)
+ x = x + y
+ x = ff(x) + x
+
+ cls_token = x[:, 0]
+ attentions = [space_attention, time_attention]
+
+ if self.require_attention:
+ return self.to_out(cls_token), attentions
+ else:
+ return self.to_out(cls_token)
diff --git a/clean/video/mintime/models/utils.py b/clean/video/mintime/models/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..48b261a31f5a596900efdc613920d3ef1f3c85d3
--- /dev/null
+++ b/clean/video/mintime/models/utils.py
@@ -0,0 +1,62 @@
+from math import log, pi
+import torch
+from torch import nn, einsum
+import torch.nn.functional as F
+from einops import rearrange, repeat
+
+def rotate_every_two(x):
+ x = rearrange(x, '... (d j) -> ... d j', j = 2)
+ x1, x2 = x.unbind(dim = -1)
+ x = torch.stack((-x2, x1), dim = -1)
+ return rearrange(x, '... d j -> ... (d j)')
+
+def apply_rot_emb(q, k, rot_emb):
+ sin, cos = rot_emb
+ rot_dim = sin.shape[-1]
+ (q, q_pass), (k, k_pass) = map(lambda t: (t[..., :rot_dim], t[..., rot_dim:]), (q, k))
+ q, k = map(lambda t: t * cos + rotate_every_two(t) * sin, (q, k))
+ q, k = map(lambda t: torch.cat(t, dim = -1), ((q, q_pass), (k, k_pass)))
+ return q, k
+
+class AxialRotaryEmbedding(nn.Module):
+ def __init__(self, dim, max_freq = 10):
+ super().__init__()
+ self.dim = dim
+ scales = torch.logspace(0., log(max_freq / 2) / log(2), self.dim // 4, base = 2)
+ self.register_buffer('scales', scales)
+
+ def forward(self, h, w, device):
+ scales = rearrange(self.scales, '... -> () ...')
+ scales = scales.to(device)
+
+ h_seq = torch.linspace(-1., 1., steps = h, device = device)
+ h_seq = h_seq.unsqueeze(-1)
+
+ w_seq = torch.linspace(-1., 1., steps = w, device = device)
+ w_seq = w_seq.unsqueeze(-1)
+
+ h_seq = h_seq * scales * pi
+ w_seq = w_seq * scales * pi
+
+ x_sinu = repeat(h_seq, 'i d -> i j d', j = w)
+ y_sinu = repeat(w_seq, 'j d -> i j d', i = h)
+
+ sin = torch.cat((x_sinu.sin(), y_sinu.sin()), dim = -1)
+ cos = torch.cat((x_sinu.cos(), y_sinu.cos()), dim = -1)
+
+ sin, cos = map(lambda t: rearrange(t, 'i j d -> (i j) d'), (sin, cos))
+ sin, cos = map(lambda t: repeat(t, 'n d -> () n (d j)', j = 2), (sin, cos))
+ return sin, cos
+
+class RotaryEmbedding(nn.Module):
+ def __init__(self, dim):
+ super().__init__()
+ inv_freqs = 1. / (10000 ** (torch.arange(0, dim, 2).float() / dim))
+ self.register_buffer('inv_freqs', inv_freqs)
+
+ def forward(self, n, device):
+ seq = torch.arange(n, device = device)
+ freqs = einsum('i, j -> i j', seq, self.inv_freqs)
+ freqs = torch.cat((freqs, freqs), dim = -1)
+ freqs = rearrange(freqs, 'n d -> () n d')
+ return freqs.sin(), freqs.cos()
\ No newline at end of file
diff --git a/clean/video/mintime/models/xception.py b/clean/video/mintime/models/xception.py
new file mode 100644
index 0000000000000000000000000000000000000000..e3ae1de438a55c44021e25c939af8a6420e2ffd9
--- /dev/null
+++ b/clean/video/mintime/models/xception.py
@@ -0,0 +1,272 @@
+# ------------------------------------------------------------------------------
+# Copyright (c) SenseTime
+# Written by Joey Fang (fangzheng@sensetime.com)
+# ------------------------------------------------------------------------------
+
+import math
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+import torch.utils.model_zoo as model_zoo
+from torch.nn import init
+
+__all__ = ['xception']
+
+
+BN = None
+class SeparableConv2d(nn.Module):
+ def __init__(self,in_channels,out_channels,kernel_size=1,stride=1,padding=0,dilation=1,bias=False):
+ super(SeparableConv2d,self).__init__()
+
+ self.conv1 = nn.Conv2d(in_channels,in_channels,kernel_size,stride,padding,dilation,groups=in_channels,bias=bias)
+ self.pointwise = nn.Conv2d(in_channels,out_channels,1,1,0,1,1,bias=bias)
+
+ def forward(self,x):
+ x = self.conv1(x)
+ x = self.pointwise(x)
+ return x
+
+
+class Block(nn.Module):
+ def __init__(self,in_filters,out_filters,reps,strides=1,start_with_relu=True,grow_first=True):
+ super(Block, self).__init__()
+
+ if out_filters != in_filters or strides!=1:
+ self.skip = nn.Conv2d(in_filters,out_filters,1,stride=strides, bias=False)
+ self.skipbn = BN(out_filters)
+ else:
+ self.skip=None
+
+ self.relu = nn.ReLU(inplace=True)
+ rep=[]
+
+ filters=in_filters
+ if grow_first:
+ rep.append(self.relu)
+ rep.append(SeparableConv2d(in_filters,out_filters,3,stride=1,padding=1,bias=False))
+ rep.append(BN(out_filters))
+ filters = out_filters
+
+ for i in range(reps-1):
+ rep.append(self.relu)
+ rep.append(SeparableConv2d(filters,filters,3,stride=1,padding=1,bias=False))
+ rep.append(BN(filters))
+
+ if not grow_first:
+ rep.append(self.relu)
+ rep.append(SeparableConv2d(in_filters,out_filters,3,stride=1,padding=1,bias=False))
+ rep.append(BN(out_filters))
+
+ if not start_with_relu:
+ rep = rep[1:]
+ else:
+ rep[0] = nn.ReLU(inplace=False)
+
+ if strides != 1:
+ rep.append(nn.MaxPool2d(3,strides,1))
+ self.rep = nn.Sequential(*rep)
+
+ def forward(self,inp):
+ x = self.rep(inp)
+
+ if self.skip is not None:
+ skip = self.skip(inp)
+ skip = self.skipbn(skip)
+ else:
+ skip = inp
+
+ x+=skip
+ return x
+
+
+class Xception(nn.Module):
+ """
+ Xception optimized for the ImageNet dataset, as specified in
+ https://arxiv.org/pdf/1610.02357.pdf
+ """
+ def __init__(self, in_channels = 3, num_classes=1000, bn_group_size=1,
+ bn_group=None, bn_sync_stats=True,feature_visible=False,
+ dropout=0, return_feature_idx=None, bypass_last_bn=False, **kwargs):
+ """ Constructor
+ Args:
+ num_classes: number of classes
+ """
+ global BN
+
+ BN = nn.BatchNorm2d
+
+ bypass_bn_weight_list = []
+ self.inplanes = 64
+
+ super(Xception, self).__init__()
+ self.num_classes = num_classes
+ self.return_feature_idx = return_feature_idx
+ self.feature_visible = feature_visible
+
+ self.conv1 = nn.Conv2d(in_channels, 32, 3,2, 0, bias=False)
+ self.bn1 = BN(32)
+ self.relu = nn.ReLU(inplace=True)
+
+ self.conv2 = nn.Conv2d(32,64,3,bias=False)
+ self.bn2 = BN(64)
+ #do relu here
+
+ self.block1=Block(64,128,2,2,start_with_relu=False,grow_first=True)
+ self.block2=Block(128,256,2,2,start_with_relu=True,grow_first=True)
+ self.block3=Block(256,728,2,2,start_with_relu=True,grow_first=True)
+
+ self.block4=Block(728,728,3,1,start_with_relu=True,grow_first=True)
+ self.block5=Block(728,728,3,1,start_with_relu=True,grow_first=True)
+ self.block6=Block(728,728,3,1,start_with_relu=True,grow_first=True)
+ self.block7=Block(728,728,3,1,start_with_relu=True,grow_first=True)
+
+ self.block8=Block(728,728,3,1,start_with_relu=True,grow_first=True)
+ self.block9=Block(728,728,3,1,start_with_relu=True,grow_first=True)
+ self.block10=Block(728,728,3,1,start_with_relu=True,grow_first=True)
+ self.block11=Block(728,728,3,1,start_with_relu=True,grow_first=True)
+
+ self.block12=Block(728,1024,2,2,start_with_relu=True,grow_first=False)
+
+ self.conv3 = SeparableConv2d(1024,1536,3,1,1)
+ self.bn3 = BN(1536)
+
+ #do relu here
+ self.conv4 = SeparableConv2d(1536,2048,3,1,1)
+ self.bn4 = BN(2048)
+
+ self.fc = nn.Linear(2048, num_classes)
+ self.drop = None
+ if dropout > 0:
+ self.drop = nn.Dropout(p=dropout)
+
+ for m in self.modules():
+ if isinstance(m, nn.Conv2d):
+ n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
+ m.weight.data.normal_(0, math.sqrt(2. / n))
+ elif (isinstance(m, torch.nn.SyncBatchNorm)
+ or isinstance(m, nn.BatchNorm2d)):
+ m.weight.data.fill_(1)
+ m.bias.data.zero_()
+
+ if bypass_last_bn:
+ for param in bypass_bn_weight_list:
+ param.data.zero_()
+ print('bypass {} bn.weight in BottleneckBlocks'.format(len(bypass_bn_weight_list)))
+
+ def att_feature(self, feature):
+ sum_feature = F.relu(torch.sum(feature, dim=1))
+ sum_feature = sum_feature / (torch.max(sum_feature)+ 1e-9)
+ return sum_feature
+
+ def features(self, input):
+ features = []
+ x = self.conv1(input)
+ x = self.bn1(x)
+ x = self.relu(x)
+
+ x = self.conv2(x)
+ x = self.bn2(x)
+ x = self.relu(x)
+ features.append(x)
+
+ x_b1 = self.block1(x)
+ features.append(x_b1)
+ x_b2 = self.block2(x_b1)
+ features.append(x_b2)
+ x_b3 = self.block3(x_b2)
+ features.append(x_b3)
+ x_b4 = self.block4(x_b3)
+ features.append(x_b4)
+ x_b5 = self.block5(x_b4)
+ features.append(x_b5)
+ x_b6 = self.block6(x_b5)
+ features.append(x_b6)
+ x_b7 = self.block7(x_b6)
+ features.append(x_b7)
+ x_b8 = self.block8(x_b7)
+ features.append(x_b8)
+ x_b9 = self.block9(x_b8)
+ features.append(x_b9)
+ x_b10 = self.block10(x_b9)
+ features.append(x_b10)
+ x_b11 = self.block11(x_b10)
+ features.append(x_b11)
+ x_b12 = self.block12(x_b11)
+ features.append(x_b12)
+
+ x = self.conv3(x_b12)
+ x = self.bn3(x)
+ x = self.relu(x)
+
+ x = self.conv4(x)
+ x = self.bn4(x)
+ return x, features
+
+ def logits(self, features):
+ x = self.relu(features)
+
+ x = F.adaptive_avg_pool2d(x, (1, 1))
+ x = x.view(x.size(0), -1)
+ if self.drop is not None:
+ x = self.drop(x)
+ out = self.fc(x)
+ return out, x
+
+ def forward(self, input):
+ x, features = self.features(input)
+ return x
+ '''
+ logit, embedding = self.logits(x)
+ features.append(embedding)
+ selected_feature = None
+ if self.return_feature_idx is not None:
+ selected_feature = [features[i] for i in self.return_feature_idx]
+ if self.feature_visible:
+ selected_feature = [self.att_feature(feature) for feature in selected_feature]
+ return logit, selected_feature
+ else:
+ return logit
+ '''
+
+def get_model_size(model):
+ result = 0
+ for key,value in model.state_dict().items():
+ s = 1
+ for item in value.size():
+ s *= item
+ result += s
+ print(key)
+ result *= 4
+ return result
+
+def xception(pretrain_path=None, **kwargs):
+ model = Xception(**kwargs)
+ if pretrain_path != None:
+ state_dict = torch.load(pretrain_path)
+ if 'state_dict' in state_dict.keys():
+ state_dict = torch.load(pretrain_path)
+
+ '''
+ for name, weights in state_dict.items():
+ if 'pointwise' in name:
+ print("test")
+ state_dict[name] = weights.unsqueeze(-1).unsqueeze(-1)
+ '''
+ own_state = model.state_dict()
+
+ for name, param in state_dict.items():
+ name = name.replace("module.", "")
+ if name in own_state:
+ if isinstance(param, torch.nn.Parameter):
+ # backwards compatibility for serialized parameters
+ param = param.data
+ try:
+ own_state[name].copy_(param)
+ except:
+ print('While copying the parameter named {}, '
+ 'whose dimensions in the model are {} and '
+ 'whose dimensions in the checkpoint are {}.'
+ .format(name, own_state[name].size(), param.size()))
+
+ print("Features Extractor checkpoint loaded.")
+ return model
diff --git a/clean/video/mintime/predict.py b/clean/video/mintime/predict.py
new file mode 100644
index 0000000000000000000000000000000000000000..85c65e1c3dacbcfe9ab9c2a89ceb622cd9dde967
--- /dev/null
+++ b/clean/video/mintime/predict.py
@@ -0,0 +1,563 @@
+
+import argparse
+import cv2
+import numpy as np
+import yaml
+import random
+
+from typing import Type
+import preprocessing.face_detector as face_detector
+from preprocessing.face_detector import VideoDataset, VideoFaceDetector
+from torch.utils.data.dataloader import DataLoader
+
+from PIL import Image
+
+import torch
+from preprocessing.utils import preprocess_images, _generate_connected_components
+from facenet_pytorch import InceptionResnetV1, fixed_image_standardization
+
+from statistics import mean
+
+from albumentations import Compose, RandomBrightnessContrast, HorizontalFlip, FancyPCA, HueSaturationValue, OneOf, ToGray, ShiftScaleRotate, ImageCompression, PadIfNeeded, GaussNoise, GaussianBlur, Rotate, Normalize, Resize
+from transforms.albu import IsotropicResize
+
+from models.size_invariant_timesformer import SizeInvariantTimeSformer
+from models.efficientnet.efficientnet_pytorch import EfficientNet
+from models.baseline import Baseline
+import os
+from einops import rearrange
+from utils import aggregate_attentions, draw_border, save_attention_plots
+from models.xception import xception
+
+
+
+RANGE_SIZE = 5
+SIZE_EMB_DICT = [(1+i*RANGE_SIZE, (i+1)*RANGE_SIZE) if i != 0 else (0, RANGE_SIZE) for i in range(20)]
+
+def detect_faces(video_path, detector_cls: Type[VideoFaceDetector], opt):
+ # Init the face detector
+ detector = face_detector.__dict__[detector_cls](device=opt.gpu_id)
+
+ # Read the video and its information
+ dataset = VideoDataset([video_path])
+ loader = DataLoader(dataset, shuffle=False, num_workers=opt.workers, batch_size=1, collate_fn=lambda x: x)
+
+ # Detect the faces
+ for item in loader:
+ bboxes = {}
+ video, indices, fps, frames = item[0]
+ bboxes.update({i : b for i, b in zip(indices, detector._detect_faces(frames))})
+ found_faces = False
+ for key in bboxes:
+ if type(bboxes[key]) == list:
+ found_faces = True
+ break
+
+ if not found_faces:
+ raise Exception("No faces found.")
+
+ return bboxes
+
+def extract_crops(video_path, bboxes_dict):
+
+ # Read video frames
+ frames = []
+
+ capture = cv2.VideoCapture(video_path)
+ frames_num = int(capture.get(cv2.CAP_PROP_FRAME_COUNT))
+ fps = int(capture.get(5))
+
+ for i in range(frames_num):
+ capture.grab()
+ success, frame = capture.retrieve()
+ if not success:
+ continue
+ frames.append(frame)
+
+ # Extract the faces crops
+ explored_indexes = []
+ crops = []
+
+ for i in range(0, len(frames), fps):
+ while str(i) not in bboxes_dict:
+ if i == frames_num - 1:
+ i -= 1
+ if i in explored_indexes:
+ break
+ else:
+ explored_indexes.append(i)
+
+ frame = frames[i]
+ index = i
+ limit = i + fps - 1
+ keys = [int(x) for x in list(bboxes_dict.keys())]
+
+ while index < limit:
+ index += 1
+ if index in keys and bboxes_dict[index] is not None:
+ break
+ if index == limit:
+ continue
+
+ bboxes = bboxes_dict[index]
+ for bbox in bboxes:
+ xmin, ymin, xmax, ymax = [int(b * 2) for b in bbox]
+ w = xmax - xmin
+ h = ymax - ymin
+
+ # Add some padding to catch background too
+ p_h = h // 3
+ p_w = w // 3
+
+ crop_h = (ymax + p_h) - max(ymin - p_h, 0)
+ crop_w = (xmax + p_w) - max(xmin - p_w, 0)
+
+ # Make the image square
+ if crop_h > crop_w:
+ p_h -= int(((crop_h - crop_w)/2))
+ else:
+ p_w -= int(((crop_w - crop_h)/2))
+
+ # Extract the face from the frame
+ crop = frame[max(ymin - p_h, 0):ymax + p_h, max(xmin - p_w, 0):xmax + p_w]
+
+ # Check if out of bound and correct
+ h, w = crop.shape[:2]
+ if h > w:
+ diff = int((h - w)/2)
+ if diff > 0:
+ crop = crop[diff:-diff,:]
+ else:
+ crop = crop[1:,:]
+ elif h < w:
+ diff = int((w - h)/2)
+ if diff > 0:
+ crop = crop[:,diff:-diff]
+ else:
+ crop = crop[:,:-1]
+
+ # Add the extracted face to the list
+ crops.append((i, Image.fromarray(crop), bbox))
+
+ return crops
+
+def cluster_faces(crops, valid_cluster_size_ratio = 0.20, similarity_threshold = 0.45):
+
+ # Convert crops to PIL images
+ crops_images = [row[1] for row in crops]
+
+ # Extract the embeddings
+ embeddings_extractor = InceptionResnetV1(pretrained='vggface2').eval().to(device)
+ faces = [preprocess_images(face) for face in crops_images]
+ faces = np.stack([np.uint8(face) for face in faces])
+ faces = torch.as_tensor(faces)
+ faces = faces.permute(0, 3, 1, 2).float()
+ faces = fixed_image_standardization(faces)
+ face_recognition_input = faces.cuda()
+ embeddings = []
+ embeddings = embeddings_extractor(face_recognition_input).detach().cpu().numpy()
+
+ # Clustering
+ valid_cluster_size = int(len(faces) * valid_cluster_size_ratio)
+ similarities = np.dot(np.array(embeddings), np.array(embeddings).T)
+
+ components = _generate_connected_components(
+ similarities, similarity_threshold=similarity_threshold
+ )
+ components = [sorted(component) for component in components]
+
+ clustered_faces = {}
+ for identity_index, component in enumerate(components):
+ for index, face_index in enumerate(component):
+ component[index] = crops[face_index]
+
+ clustered_faces[identity_index] = component
+
+ return clustered_faces
+
+def get_identity_information(identity, faces):
+ mean_side = mean([row[1].size[0] for row in faces])
+ number_of_faces = len(faces)
+ return [identity, mean_side, number_of_faces, faces]
+
+def get_sorted_identities(identities, discarded_faces, max_identities = 2, num_frames = 16):
+ sorted_identities = []
+ discarded_faces = []
+ for identity in identities:
+ sorted_identities.append(get_identity_information(identity, identities[identity]))
+
+ '''
+ # If no faces have been found, use the discarded faces
+ if len(sorted_identities) == 0:
+ sorted_identities.append(self.get_identity_information(identities))
+ discarded_faces = []
+ '''
+
+ # Sort identities based on faces size
+ sorted_identities = sorted(sorted_identities, key=lambda x:x[1], reverse=True)
+
+ if len(sorted_identities) > max_identities:
+ sorted_identities = sorted_identities[:max_identities]
+
+ # Adjust the identities list faces number
+ identities_number = len(sorted_identities)
+ available_additional_faces = []
+ if identities_number > 1:
+ max_faces_per_identity = {1: [num_frames],
+ 2: [int(num_frames/2), int(num_frames/2)],
+ 3: [int(num_frames/3), int(num_frames/3), int(num_frames/4)],
+ 4: [int(num_frames/3), int(num_frames/3), int(num_frames/8), int(num_frames/8)]}
+
+ max_faces_per_identity = max_faces_per_identity[identities_number]
+ for i in range(identities_number):
+ if sorted_identities[i][2] < max_faces_per_identity[i] and i < identities_number - 1:
+ sorted_identities[i+1][2] += max_faces_per_identity[i] - sorted_identities[i][2]
+ available_additional_faces.append(0)
+ elif sorted_identities[i][2] > max_faces_per_identity[i]:
+ available_additional_faces.append(sorted_identities[i][2] - max_faces_per_identity[i])
+ sorted_identities[i][2] = max_faces_per_identity[i]
+ else:
+ available_additional_faces.append(0)
+
+ else: # If only one identity is in the video, all the frames are assigned to this identity
+ sorted_identities[0][2] = num_frames
+ available_additional_faces.append(0)
+
+
+ # Check if we found enough faces to fullfill the input sequence, otherwise go back and add some faces from previous identities
+ input_sequence_length = sum(faces_number for _, _, faces_number, _ in sorted_identities)
+ if input_sequence_length < num_frames:
+ for i in range(identities_number):
+ needed_faces = num_frames - input_sequence_length
+ if available_additional_faces[i] > 0:
+ added_faces = min(available_additional_faces[i], needed_faces)
+ sorted_identities[i][2] += added_faces
+ input_sequence_length += added_faces
+ if input_sequence_length == num_frames:
+ break
+ # If not enough faces have been found, add some "dummy" images in the last identity
+ if input_sequence_length < num_frames:
+ needed_faces = num_frames - input_sequence_length
+ sorted_identities[-1][2] += needed_faces
+ input_sequence_length += needed_faces
+
+ return sorted_identities, discarded_faces
+
+def create_val_transform(size, additional_targets):
+ return Compose([
+ IsotropicResize(max_side=size, interpolation_down=cv2.INTER_AREA, interpolation_up=cv2.INTER_CUBIC),
+ PadIfNeeded(min_height=size, min_width=size, border_mode=cv2.BORDER_CONSTANT),
+ Resize(height=size, width=size)
+ ], additional_targets = additional_targets
+ )
+
+def generate_masks(video_path, identities, discarded_faces, num_frames, image_size, num_patches):
+ mask = []
+ last_range_end = 0
+ sequence = []
+ size_embeddings = []
+
+ images_frames = []
+ for identity_index, identity in enumerate(identities):
+ max_faces = identity[2]
+ identity_images = identity[3]
+ '''
+ # If no faces were considered for a frame during clustering, probably it is inside the discarded faces
+ if identity_index == 0 and len(discarded_faces) > 0:
+ frames = [int(os.path.basename(image_path).split("_")[0]) for image_path in identity_faces]
+ discarded_frames = [int(os.path.basename(image_path).split("_")[0]) for image_path in discarded_faces]
+ missing_frames = list(set(discarded_frames) - set(frames))
+ missing_faces = [discarded_faces[discarded_frames.index(missing_frame)] for missing_frame in missing_frames]
+
+ if len(missing_faces) > 0:
+ identity_faces = identity_faces + missing_faces # Add the missing faces to the identity
+ '''
+
+
+ # Select uniformly the frames in an alternate way
+ if len(identity_images) > max_faces:
+ idx = np.round(np.linspace(0, len(identity_images) - 2, max_faces)).astype(int)
+ identity_images = np.asarray(identity_images)[idx]
+
+ images_frames.extend(identity_image[0] for identity_image in identity_images)
+ identity_images = [identity_image[1] for identity_image in identity_images]
+
+ # Generate size embeddings
+ capture = cv2.VideoCapture(video_path)
+ width = capture.get(3)
+ height = capture.get(4)
+ video_area = width*height/2
+ identity_size_embeddings = []
+
+ for image_index, image in enumerate(identity_images):
+ # Get face-frame area ratio for size embedding
+ face_area = image.size[0] * image.size[1]
+ ratio = int(face_area * 100 / video_area)
+ side_ranges = list(map(lambda a_: ratio in range(a_[0], a_[1] + 1), SIZE_EMB_DICT))
+ identity_size_embeddings.append(np.where(side_ranges)[0][0]+1)
+
+
+ # If the readed faces are less than max_faces we need to add empty images and generate the mask
+ if len(identity_images) < max_faces:
+ diff = max_faces - len(identity_size_embeddings)
+ identity_size_embeddings = np.concatenate((identity_size_embeddings, np.zeros(diff)))
+ identity_images.extend([np.zeros((image_size, image_size, 3), dtype=np.uint8) for i in range(diff)])
+ mask.extend([1 if i < max_faces - diff else 0 for i in range(max_faces)])
+ images_frames.extend([max(images_frames) for i in range(diff)])
+ else: # Otherwise all the faces are valid
+ mask.extend([1 for i in range(max_faces)])
+
+ # Compose the size_embedding and sequence list
+ size_embeddings.extend(identity_size_embeddings)
+ sequence.extend(identity_images)
+
+ # Transform the images, the same transformation is applied to all the faces in the same video
+ sequence = [np.asarray(image) for image in sequence]
+ additional_targets_keys = ["image" + str(i) for i in range(num_frames)]
+ additional_targets_values = ["image" for i in range(num_frames)]
+ additional_targets = dict(zip(additional_targets_keys, additional_targets_values))
+
+
+ transform = create_val_transform(image_size, additional_targets)
+ if len(sequence) == 8:
+ transformed_images = transform(image=sequence[0], image1=sequence[1], image2=sequence[2], image3=sequence[3], image4=sequence[4], image5=sequence[5], image6=sequence[6], image7=sequence[7])
+ elif len(sequence) == 16:
+ transformed_images = transform(image=sequence[0], image1=sequence[1], image2=sequence[2], image3=sequence[3], image4=sequence[4], image5=sequence[5], image6=sequence[6], image7=sequence[7], image8=sequence[8], image9=sequence[9], image10=sequence[10], image11=sequence[11], image12=sequence[12], image13=sequence[13], image14=sequence[14], image15=sequence[15])
+ else:
+ raise Exception("Invalid number of frames.")
+
+ sequence = [transformed_images[key] for key in transformed_images]
+
+ # Generate the identities_mask telling to the model which faces attend to an identity and which to another one
+ identities_mask = []
+ last_range_end = 0
+ for identity_index in range(len(identities)):
+ identity_mask = [True if i >= last_range_end and i < last_range_end + identities[identity_index][2] else False for i in range(0, num_frames)]
+ for k in range(identities[identity_index][2]):
+ identities_mask.append(identity_mask)
+ last_range_end += identities[identity_index][2]
+
+ # Generate coherent temporal-positional embedding
+ images_frames_positions = {k: v+1 for v, k in enumerate(sorted(set(images_frames)))}
+ frame_positions = [images_frames_positions[frame] for frame in images_frames]
+ if num_patches != None:
+ positions = [[i+1 for i in range(((frame_position-1)*num_patches), num_patches*(frame_position))] for frame_position in frame_positions]
+ positions = sum(positions, []) # Merge the lists
+ positions.insert(0,0) # Add CLS
+ else:
+ positions = []
+
+ tokens_per_identity = [(identities[i][0], identities[i][2]*num_patches + identities[i-1][2]*num_patches) if i > 0 else (identities[i][0], identities[i][2]*num_patches) for i in range(len(identities))]
+
+ return torch.tensor([sequence]).float(), torch.tensor([size_embeddings]).int(), torch.tensor([mask]).bool(), torch.tensor([identities_mask]).bool(), torch.tensor([positions]), tokens_per_identity
+
+
+def predict(video_path, clustered_faces, config, opt, discarded_faces = None):
+
+ # Load required weights for feature extractor
+ if opt.extractor_model == 0: # EfficientNet-B0
+ if opt.extractor_weights.lower() == 'imagenet':
+ features_extractor = EfficientNet.from_pretrained('efficientnet-b0')
+ else:
+ features_extractor = EfficientNet.from_name('efficientnet-b0')
+ features_extractor.load_matching_state_dict(torch.load(opt.extractor_weights, map_location=torch.device('cpu')))
+ print("Custom features extractor weights loaded.")
+ else: # XceptionNet
+ if opt.extractor_weights.lower() == 'pretrained':
+ features_extractor = xception(num_classes=1, pretrain_path="weights/ckpt_iter.pth.tar")
+ else:
+ features_extractor = xception(num_classes=1, pretrain_path=opt.extractor_weights)
+
+
+
+ # Init the model
+ model = SizeInvariantTimeSformer(config=config, require_attention=True)
+ num_patches = config['model']['num-patches']
+
+
+ features_extractor = torch.nn.DataParallel(features_extractor)
+ model = torch.nn.DataParallel(model)
+
+ # Move into GPU
+ features_extractor = features_extractor.to(device)
+ model = model.to(device)
+ features_extractor.eval()
+ model.eval()
+
+ if os.path.exists(opt.model_weights):
+ model.load_state_dict(torch.load(opt.model_weights))
+ else:
+ raise Exception("No checkpoint loaded for the model.")
+
+ identities, discarded_faces = get_sorted_identities(clustered_faces, discarded_faces)
+ videos, size_embeddings, mask, identities_mask, positions, tokens_per_identity = generate_masks(video_path, identities, discarded_faces, config["model"]["num-frames"], config["model"]["image-size"], config["model"]["num-patches"])
+ b, f, h, w, c = videos.shape
+ videos = videos.to(device)
+ identities_mask = identities_mask.to(device)
+ mask = mask.to(device)
+ positions = positions.to(device)
+
+
+ with torch.no_grad():
+ video = rearrange(videos, "b f h w c -> (b f) c h w")
+ features = features_extractor(video)
+
+ features = rearrange(features, '(b f) c h w -> b f c h w', b = b, f = f)
+ test_pred, attentions = model(features, mask=mask, size_embedding=size_embeddings, identities_mask=identities_mask, positions=positions)
+
+ identity_names = [row[0] for row in tokens_per_identity]
+ frames_per_identity = [int(row[1] / config["model"]["num-patches"]) for row in tokens_per_identity]
+
+ if opt.save_attentions:
+ aggregated_attentions, identity_attentions = aggregate_attentions(attentions, config['model']['heads'], config['model']['num-frames'], frames_per_identity)
+ save_attention_plots(aggregated_attentions, identity_names, frames_per_identity, config['model']['num-frames'], os.path.basename(video_path))
+ else:
+ identity_attentions = []
+ aggregated_attentions = []
+ return torch.sigmoid(test_pred[0]).item(), identity_attentions, aggregated_attentions, identities, frames_per_identity
+
+def get_identities_bboxes(identities):
+ identities_bboxes = {}
+ for row in identities:
+ identity = row[3]
+ for face in identity:
+ frame = face[0]
+ if frame in identities_bboxes:
+ identities_bboxes[frame].append(face[2])
+ else:
+ identities_bboxes[frame] = [face[2]]
+ return identities_bboxes
+
+
+def generate_output_video(video_path, pred, identity_attentions, aggregated_attentions, identities, frames_per_identity):
+
+ identities_bboxes = get_identities_bboxes(identities)
+ available_frames_keys = [frame for frame in identities_bboxes]
+
+ cap = cv2.VideoCapture(video_path)
+ width = cap.get(3)
+ height = cap.get(4)
+ fps = int(cap.get(5))
+ fourcc = hex(int(cap.get(cv2.CAP_PROP_FOURCC)))
+ output = cv2.VideoWriter("examples/preds/"+str(os.path.basename(video_path).replace(".mp4", ".avi")), cv2.VideoWriter_fourcc("X", "V", "I", "D"), fps, (int(width), int(height)))
+ frame_index = 0
+ while True:
+ ret, frame = cap.read()
+ if ret:
+ nearest_frame_index = min(available_frames_keys, key=lambda x:abs(x - frame_index))
+ if nearest_frame_index - frame_index > fps:
+ continue
+
+ bbox = identities_bboxes[nearest_frame_index]
+
+ for identity_index, identity_bbox in enumerate(bbox):
+
+ xmin, ymin, xmax, ymax = [int(b * 2) for b in identity_bbox]
+ if pred > 0.5:
+ red = 255 * identity_attentions[identity_index]
+ green = 255 - red
+
+ if red > green:
+ text = 'Fake ' + str(round(pred*100,2)) + "%"
+ else:
+ text = 'Pristine'
+ else:
+ green = int(255 * (1 - pred))
+ red = 255 - green
+ text = 'Pristine ' + str(round((1-pred)*100,2)) + "%"
+
+ color = (0, green, red)
+ frame = draw_border(frame, (xmin,ymin), (xmax,ymax), color, 2, 10, 20)
+ cv2.putText(frame, text, (xmin, ymin - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, color, 2)
+
+ output.write(frame)
+ else:
+ break
+
+ frame_index += 1
+ output.release()
+ cap.release()
+
+
+
+
+if __name__ == "__main__":
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--video_path', type=str,
+ help='Path to the video file')
+ parser.add_argument("--detector_type", help="type of the detector", default="FacenetDetector",
+ choices=["FacenetDetector"])
+ parser.add_argument('--random_state', default=42, type=int,
+ help='Random state value')
+ parser.add_argument('--gpu_id', default=0, type=int,
+ help='ID of GPU to be used')
+ parser.add_argument('--workers', default=1, type=int,
+ help='Number of data loader workers.')
+ parser.add_argument('--config', type=str,
+ help="Which configuration to use. See into 'config' folder.")
+ parser.add_argument('--model_weights', type=str,
+ help='Model weights.')
+ parser.add_argument('--extractor_model', type=int, default=0,
+ help="Which model use for features extraction (0: EfficientNet; 1: XceptionNet).")
+ parser.add_argument('--extractor_weights', default='ImageNet', type=str,
+ help='Path to extractor weights or "imagenet".')
+ parser.add_argument('--output_type', default=0, type=int,
+ help='Specify which type of output is requested (0: Prediction; 1: Video)".')
+ parser.add_argument('--save_attentions', default=False, action="store_true",
+ help='Save attentions plots.')
+
+ opt = parser.parse_args()
+ print(opt)
+
+ os.environ["CUDA_VISIBLE_DEVICES"] = "0,1"
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
+ with open(opt.config, 'r') as ymlfile:
+ config = yaml.safe_load(ymlfile)
+
+ # Check for integrity
+ if config['model']['num-frames'] != 8 and config['model']['num-frames'] != 16:
+ raise Exception("Invalid number of frames.")
+
+ if not os.path.exists(opt.video_path):
+ raise Exception("Invalid video path.")
+
+
+ # Setup CUDA settings
+ torch.cuda.set_device(opt.gpu_id)
+ torch.backends.cudnn.deterministic = True
+ random.seed(opt.random_state)
+ torch.manual_seed(opt.random_state)
+ torch.cuda.manual_seed(opt.random_state)
+ np.random.seed(opt.random_state)
+
+
+ print("Detecting faces...")
+ bboxes_dict = detect_faces(opt.video_path, opt.detector_type, opt)
+ print("Face detection completed.")
+
+
+ print("Cropping faces from the video...")
+ crops = extract_crops(opt.video_path, bboxes_dict)
+ print("Faces cropping completed.")
+
+ '''
+ for j, crop in enumerate(crops):
+ cv2.imwrite("outputs/faces/face_{}.png".format(j), np.asarray(crop[1]))
+ '''
+
+ print("Clustering faces...")
+ clustered_faces = cluster_faces(crops)
+ print("Faces clustering completed.")
+
+
+ print("Searching for fakes in the video...")
+ pred, identity_attentions, aggregated_attentions, identities, frames_per_identity = predict(opt.video_path, clustered_faces, config, opt)
+ if pred > 0.5:
+ print("The video is fake ("+str(round(pred*100,2)) + "%), showing video result...")
+ else:
+ print("The video is pristine ("+str(round((1-pred)*100,2)) + "%), showing video result...")
+ if opt.output_type == 0:
+ print("Prediction", pred)
+ else:
+ generate_output_video(opt.video_path, pred, identity_attentions, aggregated_attentions, identities, frames_per_identity)
diff --git a/clean/video/mintime/preprocessing/cluster_faces.py b/clean/video/mintime/preprocessing/cluster_faces.py
new file mode 100644
index 0000000000000000000000000000000000000000..78d0b0395f53a3f39042c11261ab1f8c594d0721
--- /dev/null
+++ b/clean/video/mintime/preprocessing/cluster_faces.py
@@ -0,0 +1,120 @@
+# Since several subjects can be found within a video, it is necessary to cluster them into groups based on similarity.
+# This operation is carried out in the following code with additional attention to maintaining the temporal coherence of faces.
+# The extracted faces are reorganised into consecutive sequences of similar faces so as to be more suitable for network processing.
+
+
+import argparse
+import os
+import glob
+import torch
+import numpy as np
+import pandas as pd
+import shutil
+from functools import partial
+from multiprocessing.pool import Pool
+from numpy.linalg import norm
+from PIL import Image
+from torchvision import transforms
+from facenet_pytorch import InceptionResnetV1, fixed_image_standardization
+from collections import OrderedDict
+from sklearn.cluster import KMeans
+from torch.utils.data.dataloader import DataLoader
+from progress.bar import ChargingBar
+from utils import preprocess_images, _generate_connected_components
+
+seed = 42
+def move_files(face_paths):
+ src_path, dst_path = face_paths
+ os.makedirs(os.path.dirname(dst_path), exist_ok=True)
+ shutil.move(src_path, dst_path)
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--faces_path', default="../../datasets/ForgeryNet/faces", type=str,
+ help='Path of folder containing train/val/test with extracted cropped faces to be clustered.')
+ parser.add_argument('--gpu_id', default=0, type=int,
+ help='ID of GPU to be used.')
+ parser.add_argument('--similarity_threshold', default=0.45, type=float,
+ help='Threshold to discard faces with high distance.')
+ parser.add_argument('--valid_cluster_size_ratio', default=0.20, type=int,
+ help='Valid cluster size ratio.')
+ parser.add_argument('--workers', default=40, type=int,
+ help='Number of data loader workers.')
+
+ opt = parser.parse_args()
+ print(opt)
+
+ # Get all the paths of the videos to be clustered
+ for dataset in os.listdir(opt.faces_path):
+ dataset_path = os.path.join(opt.faces_path, dataset)
+ if not os.path.isdir(dataset_path):
+ continue
+
+ print()
+ print("Clustering videos in ", dataset_path)
+ set_paths = glob.glob(f'{dataset_path}/*/**/*.mp4', recursive=True)
+
+ excluded_videos = []
+ for path in set_paths:
+ if os.path.exists(os.path.join(path, "0")):
+ excluded_videos.append(path)
+
+ set_paths = [video_path for video_path in set_paths if video_path not in excluded_videos]
+ print("Excluded already clustered videos: ", len(excluded_videos))
+
+ # For each video in each set, perform faces clustering
+ bar = ChargingBar('Clustered videos', max=(len(set_paths)))
+ for path in set_paths:
+ # Read all faces, load them into a dictionary
+ faces_files = [face_file for face_file in os.listdir(path) if not os.path.isdir(os.path.join(path, face_file))]
+ faces_files = sorted(faces_files, key=lambda x:(int(x.split("_")[0]), int(os.path.splitext(x)[0].split("_")[1])))
+ mapping = {}
+ faces = []
+
+ for index, face_file in enumerate(faces_files):
+ face_path = os.path.join(path, face_file)
+ frame_number = int(os.path.splitext(face_file)[0].split("_")[0])
+ face = Image.open(face_path)
+ faces.append(face)
+ mapping[index] = face_path
+
+
+
+ # Extract the embeddings
+ embeddings_extractor = InceptionResnetV1(pretrained='vggface2').eval().to(opt.gpu_id)
+ faces = [preprocess_images(face) for face in faces]
+ faces = np.stack([np.uint8(face) for face in faces])
+ faces = torch.as_tensor(faces)
+ faces = faces.permute(0, 3, 1, 2).float()
+ faces = fixed_image_standardization(faces)
+ face_recognition_input = faces.cuda()
+ embeddings = []
+ embeddings = embeddings_extractor(face_recognition_input).detach().cpu().numpy()
+
+ # Clustering
+ valid_cluster_size = int(len(mapping) * opt.valid_cluster_size_ratio)
+ similarities = np.dot(np.array(embeddings), np.array(embeddings).T)
+
+ components = _generate_connected_components(
+ similarities, similarity_threshold=opt.similarity_threshold
+ )
+ components = [sorted(component) for component in components]
+
+ mapped_components = []
+ for identity_index, component in enumerate(components):
+ for index in component:
+ src_path = mapping[index]
+ folder_path = os.path.dirname(src_path)
+ file_name = os.path.basename(src_path)
+ dst_path = os.path.join(folder_path, str(identity_index), file_name)
+ mapped_components.append((src_path, dst_path))
+
+
+ # Organize the clusters inside the folder
+ with Pool(processes=opt.workers) as p:
+ for v in p.imap_unordered(move_files, mapped_components):
+ continue
+
+ bar.next()
+
+ print()
diff --git a/clean/video/mintime/preprocessing/common.csv b/clean/video/mintime/preprocessing/common.csv
new file mode 100644
index 0000000000000000000000000000000000000000..70957974f44ba967d43cab1d480364080ada0323
--- /dev/null
+++ b/clean/video/mintime/preprocessing/common.csv
@@ -0,0 +1,401 @@
+name,label_y
+aassnaulhq,1
+aayfryxljh,0
+acazlolrpz,1
+adohdulfwb,0
+ahjnxtiamx,1
+ajiyrjfyzp,0
+aktnlyqpah,1
+alrtntfxtd,1
+aomqqjipcp,1
+apedduehoy,0
+apvzjkvnwn,0
+aqrsylrzgi,1
+axfhbpkdlc,1
+ayipraspbn,0
+bcbqxhziqz,0
+bcvheslzrq,1
+bdshuoldwx,1
+bfdopzvxbi,0
+bfjsthfhbd,0
+bjyaxvggle,1
+bkcyglmfci,0
+bktkwbcawi,1
+bkuzquigyt,0
+blnmxntbey,0
+blszgmxkvu,0
+bnuwxhfahw,0
+bofrwgeyjo,1
+btdxnajogv,0
+bvpeerislp,0
+bwdmzwhdnw,1
+bzvzpwrabw,1
+cekarydqba,0
+cekwtyxdoo,1
+cjkctqqakb,1
+cnpanmywno,0
+cnxccbjlct,1
+coqwgzpbhx,1
+cosghhimnd,0
+coujjnypba,1
+cqhwesrciw,1
+cqxxumarvp,0
+csnkohqxdv,1
+cxsvvnxpyz,0
+czfqlbcfpa,0
+dcqodpzomd,1
+ddtbarpcgo,0
+demuhxssgl,1
+didzujjhtg,0
+dkuqbduxev,1
+dmmvuaikkv,0
+dnmowthjcj,0
+doniqevxeg,0
+dozjwhnedd,1
+dpevefkefv,0
+dpmgoiwhuf,0
+dsnxgrfdmd,0
+dtozwcapoa,0
+dvkdfhrpph,1
+dvtpwatuja,0
+dvwpvqdflx,0
+dxfdovivlw,0
+dxgnpnowgk,0
+dyjklprkoc,1
+dzkyxbbqkr,0
+dzojiwfvba,0
+ecumyiowzs,1
+eisofhptvk,1
+ekboxwrwuv,1
+ekelfsnqof,0
+ekvwecwltj,0
+elackxuccp,0
+eppyqpgewp,0
+eqslzbqfea,1
+eryjktdexi,1
+esjdyghhog,1
+esmqxszybs,1
+espkiocpxq,1
+etdliwticv,1
+evysmtpnrf,0
+eyguqfmgzh,0
+eywdmustbb,1
+famlupsgqm,1
+fddmkqjwsh,1
+fjrueenjyp,1
+fjxovgmwnm,0
+fmhiujydwo,0
+fmvvmcbdrw,1
+fneqiqpqvs,0
+fnxgqcvlsd,1
+fopjiyxiqd,0
+fpevfidstw,0
+fqgypsunzr,1
+frqfsucgao,0
+fsdrwikhge,1
+fwykevubzy,0
+fxuxxtryjn,1
+fzvpbrzssi,0
+gahgyuwzbu,0
+gbnzicjyhz,1
+gccnvdoknm,1
+gcdtglsoqj,0
+gfcycflhbo,1
+gfdjzwnpyp,1
+gfgcwxkbjd,0
+ggdpclfcgk,1
+ggzjfrirjh,0
+ghnpsltzyn,1
+gkutjglghz,1
+gochxzemmq,0
+gpsxfxrjrr,0
+gqnaxievjx,1
+gunamloolc,1
+halvwiltfs,1
+hbufmvbium,0
+hcanfkwivl,1
+hclsparpth,1
+hefisnapds,1
+heiyoojifp,0
+hevcclcklc,0
+hfsvqabzfq,1
+hicjuubiau,0
+hierggamuo,0
+hitfycdavv,1
+hnfwagcxdf,1
+honxqdilvv,1
+hqzwudvhih,1
+hsbljbsgxr,1
+hsbwhlolsn,0
+hszwwswewp,0
+htzbnroagi,0
+huvlwkxoxm,1
+hweshqpfwe,1
+hxwtsaydal,1
+hyjqolupxn,1
+hzoiotcykp,1
+hzssdinxec,1
+ibxfxggtqh,1
+icbsahlivv,1
+igpvrfjdzc,0
+ihglzxzroo,0
+iksxzpqxzi,0
+ilqwcbprqa,0
+imdmhwkkni,1
+iorbtaarte,0
+ipkpxvwroe,1
+ipvwtgdlre,1
+irqzdokcws,0
+itfsvvmslp,1
+iznnzjvaxc,1
+jawgcggquk,0
+jhczqfefgw,1
+jiavqbrkyk,0
+jiswxuqzyz,0
+jquevmhdvc,1
+jsbpkpxwew,1
+jsysgmycsx,1
+jyfvaequfg,0
+jyoxdvxpza,0
+jytrvwlewz,0
+jzmzdispyo,0
+kcjvhgvhpt,1
+keioymnobc,0
+kezwvsxxzj,0
+khpipxnsvx,1
+kmcdjxmnoa,1
+kmqkiihrmj,1
+knxltsvzyu,0
+kowiwvrjht,1
+kqlvggiqee,0
+kvmpmhdxly,0
+kwfdyqofzw,0
+lbfqksftuo,1
+lbigytrrtr,0
+lebzjtusnr,1
+lhvjzhjxdp,1
+ljauauuyka,0
+ljouzjaqqe,0
+llplvmcvbl,0
+lmdyicksrv,1
+lnhkjhyhvw,0
+lnjkpdviqb,0
+lpgxwdgnio,0
+lpkgabskbw,1
+lujvyveojc,0
+lyoslorecs,1
+mdfndlljvt,1
+mkmgcxaztt,0
+mkzaekkvej,0
+mllzkpgatp,1
+mnowxangqx,1
+mnzabbkpmt,0
+mohiqoogpb,0
+mszblrdprw,1
+mwnibuujwz,0
+mwwploizlj,0
+mxahsihabr,1
+mxlipjhmqk,0
+ncmpqwmnzb,0
+ncoeewrdlo,1
+ndikguxzek,1
+nikynwcvuh,1
+njzshtfmcw,1
+nkhzxomani,1
+novarhxpbj,0
+nplviymzlg,1
+nswtvttxre,0
+nthpnwylxo,0
+nwvloufjty,1
+nwvsbmyndn,0
+nxgzmgzkfv,1
+nxnmkytwze,0
+nxzgekegsp,1
+nycmyuzpml,0
+nymodlmxni,0
+oaguiggjyv,0
+ocgdbrgmtq,0
+oefukgnvel,0
+oelqpetgwj,1
+ojsxxkalat,1
+okgelildpc,1
+omphqltjdd,0
+ooafcxxfrs,0
+oocincvedt,0
+oojxonbgow,0
+opvqdabdap,1
+orekjthsef,1
+orixbcfvdz,1
+ouaowjmigq,0
+owaogcehvc,1
+oyqgwjdwaj,1
+oysopgovhu,1
+papagllumt,0
+pcoxcmtroa,0
+pcyswtgick,1
+pdswwyyntw,0
+pdufsewrec,0
+petmyhjclt,1
+phjvutxpoi,0
+pqdeutauqc,0
+pqthmvwonf,1
+prhmixykhr,1
+prwsfljdjo,0
+psesikjaxx,0
+ptbfnkajyi,1
+ptbnewtvon,1
+pxcfrszlgi,0
+pxjkzvqomp,0
+qarqtkvgby,0
+qcbkztamqc,1
+qclpbcbgeq,0
+qdqdsaiitt,1
+qhkzlnzruj,0
+qhsehzgxqj,1
+qlqhjcshpk,1
+qlvsqdroqo,1
+qooxnxqqjb,0
+qqnlrngaft,0
+qsjiypnjwi,1
+qswlzfgcgj,0
+qxyrtwozyw,1
+qyyhuvqmyf,1
+rcecrgeotc,1
+rcjfxxhcal,1
+rerpivllud,1
+rfjuhbnlro,1
+rfwxcinshk,1
+rklawjhbpv,1
+rktrpsdlci,0
+rmlzgerevr,0
+rmufsuogzn,0
+rnfcjxynfa,1
+rrrfjhugvb,1
+rtpbawlmxr,1
+ruhtnngrqv,0
+rukyxomwcx,0
+rvvpazsffd,1
+rxdoimqble,0
+ryxaqpfubf,1
+scbdenmaed,1
+scrbqgpvzz,1
+sfsayjgzrh,0
+shnsajrsow,1
+siebfpwuhu,0
+sjinmmbipg,1
+sjkfxrlxxs,1
+sjwywglgym,1
+sktpeppbkc,1
+sngjsueuhs,1
+snlyjbnpgw,1
+sodvtfqbpf,0
+sqixhnilfm,1
+srfefmyjvt,0
+sufvvwmbha,1
+swsaoktwgi,1
+sylnrepacf,0
+syuxttuyhm,1
+syxobtuucp,0
+sznkemeqro,0
+tejfudfgpq,0
+temeqbmzxu,1
+temjefwaas,1
+tgawasvbbr,0
+tjuihawuqm,1
+tjywwgftmv,1
+toinozytsp,1
+tvhjcfnqtg,1
+txmnoyiyte,1
+txnmkabufs,0
+tyjpjpglgx,0
+tynfsthodx,1
+ucthmsajay,0
+udxqbhgvvx,1
+uhakqelqri,1
+uhrqlmlclw,0
+uoccaiathd,1
+upmgtackuf,0
+uqvxjfpwdo,1
+usqqvxcjmg,1
+uubgqnvfdl,1
+uvrzaczrbx,0
+uxuvkrjhws,0
+vajkicalux,0
+vbcgoyxsvn,1
+vdtsbqidjb,1
+vhbbwdflyh,1
+viteugozpv,0
+vizerpsvbz,0
+vjljdfopjg,1
+vmxfwxgdei,0
+vnlzxqwthl,0
+voawxrmqyl,1
+vokrpfjpeb,0
+vssmlqoiti,0
+vtunvalyji,0
+vurjckblge,1
+vvfszaosiv,0
+vwxednhlwz,1
+wadvzjhwtw,0
+waucvvmtkq,0
+wclvkepakb,0
+wcqvzujamg,0
+wcssbghcpc,1
+wcvsqnplsk,1
+wfzjxzhdkj,0
+wixbuuzygv,0
+wjhpisoeaj,0
+wmoqzxddkb,0
+wndursivcx,1
+wnlubukrki,1
+wqysrieiqu,0
+wvgviwnwob,1
+wynotylpnm,0
+xcruhaccxc,0
+xdezcezszc,0
+xhtppuyqdr,1
+xitgdpzbxv,1
+xjvxtuakyd,1
+xljemofssi,1
+xmkwsnuzyq,0
+xphdfgmfmz,1
+xrtvqhdibb,1
+xugmhbetrw,0
+xxzefxwyku,0
+yarpxfqejd,1
+yaxgpxhavq,1
+ybbrkacebd,0
+yhjlnisfel,0
+yhylappzid,0
+yietrwuncf,0
+yiykshcbaz,0
+yljecirelf,0
+yllztsrwjw,1
+ylxwcwhjjd,0
+yoyhmxtrys,1
+ypbtpunjvm,0
+yqhouqakbx,1
+yronlutbgm,0
+ystdtnetgj,0
+ytddugrwph,1
+ytopzxrswu,1
+ywauoonmlr,0
+ywxpquomgt,0
+yxadevzohx,1
+yxirnfyijn,1
+yxvmusxvcz,0
+yzuestxcbq,1
+zbgssotnjm,0
+zcxcmneefk,1
+zfobicuigx,0
+zfrrixsimm,0
+zgbhzkditd,1
+zgjosltkie,1
+ziipxxchai,0
+zmxeiipnqb,0
+ztyuiqrhdk,0
+ztyvglkcsf,0
+zuwwbbusgl,0
+zxacihctqp,0
+zyufpqvpyu,1
+zzmgnglanj,0
diff --git a/clean/video/mintime/preprocessing/count_multi_identities.py b/clean/video/mintime/preprocessing/count_multi_identities.py
new file mode 100644
index 0000000000000000000000000000000000000000..6e76b72d51042a51ce38a24935061ac989f521c5
--- /dev/null
+++ b/clean/video/mintime/preprocessing/count_multi_identities.py
@@ -0,0 +1,72 @@
+import os
+from collections import Counter
+import pandas as pd
+import matplotlib.pyplot as plt
+
+CSV_PATH_TRAIN = "../../../datasets/ForgeryNet/faces/train_and_val.csv"
+
+CSV_PATH_TEST = "../../../datasets/ForgeryNet/faces/test.csv"
+DATA_PATH = "../../../datasets/ForgeryNet/faces/"
+
+col_names = ["video", "label", "8_cls"]
+
+df_train = pd.read_csv(CSV_PATH_TRAIN, sep=' ', names=col_names)
+
+df_test = pd.read_csv(CSV_PATH_TEST, sep=' ', names=col_names)
+counters_train_test = []
+for df in [df_train, df_test]:
+ indexes_to_drop = []
+ for index, row in df.iterrows():
+ video_path = os.path.join(DATA_PATH, row["video"])
+ if not os.path.exists(video_path) or len(os.listdir(video_path)) == 0:
+ indexes_to_drop.append(index)
+ df.drop(df.index[indexes_to_drop], inplace=True)
+
+
+ identities_numbers = []
+ for row in df.iterrows():
+ video_path = os.path.join(DATA_PATH, row[1]["video"])
+ identities = len(os.listdir(video_path))
+ identities_numbers.append(identities)
+
+ counters = Counter(identities_numbers)
+ counters_train_test.append(counters)
+
+
+total_identities_train = sum(counters_train_test[0].values())
+total_identities_test = sum(counters_train_test[1].values())
+
+collapsed_train_count = sum(count for num_identities, count in counters_train_test[0].items() if num_identities >= 4)
+collapsed_test_count = sum(count for num_identities, count in counters_train_test[1].items() if num_identities >= 4)
+
+counters_train_test[0][4] = collapsed_train_count
+counters_train_test[1][4] = collapsed_test_count
+
+data = {
+ 'Number of identities': list(range(1, 4)) + ['4+'],
+ 'Train': [counters_train_test[0][i] for i in range(1, 4)] + [counters_train_test[0][4]],
+ 'Test': [counters_train_test[1][i] for i in range(1, 4)] + [counters_train_test[1][4]]
+}
+
+df_plot = pd.DataFrame(data)
+
+df_plot['Number of identities'] = df_plot['Number of identities'].apply(lambda x: '4+' if x == 4 else str(x))
+
+plt.figure(figsize=(8, 6))
+bar_width = 0.35
+opacity = 0.8
+
+plt.bar(df_plot.index, df_plot['Train'], bar_width, alpha=opacity, color='b', label='Train')
+plt.bar([x + bar_width for x in df_plot.index], df_plot['Test'], bar_width, alpha=opacity, color='g', label='Test')
+
+plt.xlabel('Number of identities')
+plt.ylabel('Number of videos')
+plt.title('Number of videos by number of identities (Train and Test)')
+plt.xticks([r + bar_width/2 for r in range(len(df_plot))], df_plot['Number of identities'])
+plt.legend()
+
+output_path = "../outputs/plots/forgerynet_multiidentity_videos.png"
+os.makedirs(os.path.dirname(output_path), exist_ok=True)
+plt.savefig(output_path)
+
+print(counters_train_test)
\ No newline at end of file
diff --git a/clean/video/mintime/preprocessing/detect_faces.py b/clean/video/mintime/preprocessing/detect_faces.py
new file mode 100644
index 0000000000000000000000000000000000000000..c975111b47204b7b6bfe65c657ed8c859b39b5b4
--- /dev/null
+++ b/clean/video/mintime/preprocessing/detect_faces.py
@@ -0,0 +1,115 @@
+# The videos are given as input to the network for training and inference in the form of sequences of faces extracted from the frames.
+# Faces are detected using a MTCNN in order to extract one per second. In the case of multiple faces within the same frame, all faces are extracted.
+
+import argparse
+import json
+import os
+import numpy as np
+from typing import Type
+
+from torch.utils.data.dataloader import DataLoader
+from tqdm import tqdm
+import pandas as pd
+import face_detector
+from face_detector import VideoDataset, VideoFaceDetector
+import argparse
+
+
+def process_videos(videos, detector_cls: Type[VideoFaceDetector], opt):
+
+ detector = face_detector.__dict__[detector_cls](device=opt.gpu_id)
+
+ dataset = VideoDataset(videos)
+ loader = DataLoader(dataset, shuffle=False, num_workers=opt.workers, batch_size=1, collate_fn=lambda x: x)
+
+ missed_videos = [] # Used to print videos with no detected faces
+
+ # For each video in the dataset, detect faces
+ for item in tqdm(loader):
+ result = {}
+ video, indices, fps, frames = item[0]
+ id = video.split(opt.data_path)[-1]
+ out_dir = opt.output_path + id
+ out_dir = out_dir.replace("video.mp4", '')
+
+ # Skip already detected videos to improve speed
+ if os.path.exists(out_dir) and "video.json" in os.listdir(out_dir):
+ continue
+
+ if fps == 0:
+ print("Zero fps video", video)
+ continue
+
+
+ result.update({i : b for i, b in zip(indices, detector._detect_faces(frames))})
+
+ # Save faces as json dictionary into output folder
+ os.makedirs(out_dir, exist_ok=True)
+
+ with open(os.path.join(out_dir, "video.json"), "w") as f:
+ json.dump(result, f)
+
+ # Check if some faces have been detected
+ found_faces = False
+ for key in result:
+ if type(result[key]) == list:
+ found_faces = True
+ break
+
+ if not found_faces:
+ print("Faces not found", video)
+ missed_videos.append(video)
+
+ # Display the missed videos
+ if len(missed_videos) > 0:
+ print("The detector did not find faces inside the following videos:")
+ print(missed_videos)
+ print(len(missed_videos))
+ print("We suggest to re-run the code decreasing the detector threshold.")
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--list_file', default="../../datasets/ForgeryNet/Validation/video_list.txt", type=str,
+ help='Video List txt file path)')
+ parser.add_argument('--data_path', type=str,
+ help='Data directory', default='../../datasets/ForgeryNet/Validation/video')
+ parser.add_argument('--output_path', type=str,
+ help='Output directory', default='../../datasets/ForgeryNet/Validation/boxes')
+ parser.add_argument("--detector_type", help="type of the detector", default="FacenetDetector",
+ choices=["FacenetDetector"])
+ parser.add_argument('--gpu_id', default=0, type=int,
+ help='ID of GPU to be used')
+ parser.add_argument('--workers', default=40, type=int,
+ help='Number of data loader workers.')
+
+ opt = parser.parse_args()
+ print(opt)
+
+
+ # Read videos paths from which the user wants to detect faces
+ with open(opt.list_file, 'r') as temp_f:
+ col_count = [ len(l.split(" ")) for l in temp_f.readlines() ]
+
+ column_names = [i for i in range(0, max(col_count))]
+ df = pd.read_csv(opt.list_file, sep=' ', names=column_names)
+ videos_paths = df.values.tolist()
+ videos_paths = list(dict.fromkeys([os.path.join(opt.data_path, os.path.dirname(row[1].split(" ")[0]), "video.mp4") for row in videos_paths]))
+
+ # Ignore already extracted videos to improve speed
+ excluded_videos = []
+ for path in videos_paths:
+ id = path.split(opt.data_path)[-1]
+ out_dir = opt.output_path + id
+ out_dir = out_dir.replace("video.mp4", '')
+ if os.path.exists(out_dir) and "video.json" in os.listdir(out_dir):
+ excluded_videos.append(path)
+
+ videos_paths = [video_path for video_path in videos_paths if video_path not in excluded_videos]
+ print("Excluded videos:", len(excluded_videos))
+
+ # Start face detection
+ process_videos(videos_paths, opt.detector_type, opt)
+
+if __name__ == "__main__":
+ main()
diff --git a/clean/video/mintime/preprocessing/extract_crops.py b/clean/video/mintime/preprocessing/extract_crops.py
new file mode 100644
index 0000000000000000000000000000000000000000..336bc44006bea33b37608e02693d50b5919087ec
--- /dev/null
+++ b/clean/video/mintime/preprocessing/extract_crops.py
@@ -0,0 +1,159 @@
+# Following face detection, the json files containing the coordinates framing the faces identified by the MTCNN must be converted into images.
+
+import argparse
+import json
+import os
+from os import cpu_count
+from pathlib import Path
+from collections import OrderedDict
+
+import pandas as pd
+os.environ["MKL_NUM_THREADS"] = "1"
+os.environ["NUMEXPR_NUM_THREADS"] = "1"
+os.environ["OMP_NUM_THREADS"] = "1"
+from functools import partial
+from glob import glob
+from multiprocessing.pool import Pool
+
+import cv2
+
+cv2.ocl.setUseOpenCL(False)
+cv2.setNumThreads(0)
+from tqdm import tqdm
+
+def extract_video(video, data_path):
+ # Composes the path where the coordinates of the detected faces were saved
+ bboxes_path = data_path + "/boxes_better/" + video.split("video/")[-1].split(".")[0] + ".json"
+ if not os.path.exists(bboxes_path) or not os.path.exists(video):
+ print(bboxes_path, "not found\n")
+ return
+
+ # Load the json dictionary and the corresponding video
+ with open(bboxes_path, "r") as bbox_f:
+ bboxes_dict = json.load(bbox_f)
+ capture = cv2.VideoCapture(video)
+ frames_num = int(capture.get(cv2.CAP_PROP_FRAME_COUNT))
+ fps = int(capture.get(5))
+
+
+ # For each frame, save the detected faces into files
+ frames = []
+ for i in range(frames_num):
+ capture.grab()
+ success, frame = capture.retrieve()
+ if not success:
+ continue
+ frames.append(frame)
+
+ explored_indexes = []
+
+ for i in range(0, len(frames), fps):
+ while str(i) not in bboxes_dict:
+ if i == frames_num - 1:
+ i -= 1
+ if i in explored_indexes:
+ break
+ else:
+ explored_indexes.append(i)
+
+ frame = frames[i]
+ id = os.path.splitext(os.path.basename(video))[0]
+ crops = []
+ index = i
+ limit = i + fps - 1
+ keys = [int(x) for x in list(bboxes_dict.keys())]
+
+ while index < limit:
+ index += 1
+ if index in keys and bboxes_dict[str(index)] is not None:
+ break
+ if index == limit:
+ continue
+
+ bboxes = bboxes_dict[str(index)]
+
+ for bbox in bboxes:
+ xmin, ymin, xmax, ymax = [int(b * 2) for b in bbox]
+ w = xmax - xmin
+ h = ymax - ymin
+
+ # Add some padding to catch background too
+ p_h = h // 3
+ p_w = w // 3
+
+ crop_h = (ymax + p_h) - max(ymin - p_h, 0)
+ crop_w = (xmax + p_w) - max(xmin - p_w, 0)
+
+ # Make the image square
+ if crop_h > crop_w:
+ p_h -= int(((crop_h - crop_w)/2))
+ else:
+ p_w -= int(((crop_w - crop_h)/2))
+
+ # Extract the face from the frame
+ crop = frame[max(ymin - p_h, 0):ymax + p_h, max(xmin - p_w, 0):xmax + p_w]
+
+ # Check if out of bound and correct
+ h, w = crop.shape[:2]
+ if h > w:
+ diff = int((h - w)/2)
+ if diff > 0:
+ crop = crop[diff:-diff,:]
+ else:
+ crop = crop[1:,:]
+ elif h < w:
+ diff = int((w - h)/2)
+ if diff > 0:
+ crop = crop[:,diff:-diff]
+ else:
+ crop = crop[:,:-1]
+
+
+ # Add the extracted face to the list
+ crops.append(crop)
+
+ # Save the extracted faces into files
+ tmp = video.split("release")[1]
+ out_dir = opt.output_path + tmp
+ os.makedirs(out_dir, exist_ok=True)
+ for j, crop in enumerate(crops):
+ try:
+ cv2.imwrite(os.path.join(out_dir, "{}_{}.png".format(i, j)), crop)
+ except:
+ print("Error writing image")
+
+
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--list_file', default="../../datasets/ForgeryNet/Training/video_list.txt", type=str,
+ help='Images List txt file path)')
+ parser.add_argument('--data_path', default='../../datasets/ForgeryNet/Training', type=str,
+ help='Videos directory')
+ parser.add_argument('--output_path', default='../../datasets/ForgeryNet/Training/faces_fix/crops_fix', type=str,
+ help='Output directory')
+ parser.add_argument('--gpu_id', default=0, type=int,
+ help='ID of GPU to be used')
+ parser.add_argument('--workers', default=40, type=int,
+ help='Number of data loader workers.')
+
+ opt = parser.parse_args()
+ print(opt)
+
+ # Read the dataset
+ with open(opt.list_file, 'r') as temp_f:
+ col_count = [ len(l.split(" ")) for l in temp_f.readlines() ]
+ column_names = [i for i in range(0, max(col_count))]
+ os.makedirs(opt.output_path, exist_ok=True)
+ df = pd.read_csv(opt.list_file, sep=' ', names=column_names)
+ videos_paths = df.values.tolist()
+ videos_paths = list(dict.fromkeys([os.path.join(opt.data_path, "video", os.path.dirname(row[1].split(" ")[0]), "video.mp4") for row in videos_paths]))
+
+ # Start face extraction
+ with Pool(processes=opt.workers) as p:
+ with tqdm(total=len(videos_paths)) as pbar:
+ for v in p.imap_unordered(partial(extract_video, data_path=opt.data_path), videos_paths):
+ pbar.update()
+
+
\ No newline at end of file
diff --git a/clean/video/mintime/preprocessing/extract_features.py b/clean/video/mintime/preprocessing/extract_features.py
new file mode 100644
index 0000000000000000000000000000000000000000..e526b2b2a2060426caa2180ef2863c3a5011038d
--- /dev/null
+++ b/clean/video/mintime/preprocessing/extract_features.py
@@ -0,0 +1,75 @@
+# It is possible to decide to extract features from previously detected face images in advance. This is done via an EfficientNet B0 and is useful if you are using the convolutional
+# backbone freezed architecture.
+# ATTENTION: The features take up a lot of disk space and it may therefore be unavoidable to have to extract them in the training phase as the images are loaded from the data loader.
+
+from utils import get_paths
+from tqdm import tqdm
+from efficientnet_pytorch import EfficientNet
+from faces_dataset import FacesDataset
+from torch.utils.data.dataloader import DataLoader
+import argparse
+import os
+import pickle
+import torch
+from progress.bar import ChargingBar
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--data_path', default='', type=str,
+ help='Faces images directory')
+ parser.add_argument('--support_files_path', default='support_files', type=str,
+ help='Path to save support files')
+ parser.add_argument('--gpu_id', default=0, type=int,
+ help='ID of GPU to be used')
+ parser.add_argument('--workers', default=40, type=int,
+ help='Number of data loader workers.')
+ parser.add_argument('--batch_size', default=48, type=int,
+ help='Batch size.')
+ parser.add_argument('--output_path', default='', type=str,
+ help='Features output directory')
+
+
+ opt = parser.parse_args()
+ print(opt)
+
+ # Reading or saving the file containing previously saved paths to improve speed in the case of multiple executions.
+ print("Searching for faces...")
+ list_file_path = os.path.join(opt.support_files_path, "faces.txt")
+ if os.path.exists(list_file_path):
+ with open(list_file_path, 'rb') as fp:
+ paths = pickle.load(fp)
+ print("Backup file found, loaded", len(paths), "faces.")
+ else:
+ paths = get_paths(opt.data_path)
+ with open(list_file_path, 'wb') as fp:
+ pickle.dump(paths, fp)
+ print(len(paths), "faces found.")
+
+ # Read faces and prepare them for extraction
+ dataset = FacesDataset(paths, output_dir = opt.output_path)
+ dl = torch.utils.data.DataLoader(dataset, batch_size=opt.batch_size, sampler=None,
+ batch_sampler=None, num_workers=opt.workers, collate_fn=None,
+ pin_memory=False, drop_last=False, timeout=0,
+ worker_init_fn=None, prefetch_factor=2,
+ persistent_workers=False)
+
+ # Load the pretrained convolutional backbone
+ model = EfficientNet.from_pretrained('efficientnet-b0')
+ model = model.cuda(device=opt.gpu_id)
+
+
+ # Extract the features and save them into disk
+ bar = ChargingBar('Extracted: ', max=(len(dl)))
+ os.makedirs(opt.output_path, exist_ok=True)
+ for index, (faces, output_paths) in enumerate(dl):
+ faces = faces.cuda(device=opt.gpu_id)
+ features = model.extract_features(faces)
+
+ for i in range(len(faces)):
+ os.makedirs(os.path.dirname(output_paths[i]), exist_ok = True)
+ torch.save(features[i], output_paths[i])
+
+ bar.next()
+
+
diff --git a/clean/video/mintime/preprocessing/face_detector.py b/clean/video/mintime/preprocessing/face_detector.py
new file mode 100644
index 0000000000000000000000000000000000000000..18c809a9f10be2c09f66c8cbdd29609d95af8bb9
--- /dev/null
+++ b/clean/video/mintime/preprocessing/face_detector.py
@@ -0,0 +1,83 @@
+# File containing classes used for face detection.
+
+import os
+os.environ["MKL_NUM_THREADS"] = "1"
+os.environ["NUMEXPR_NUM_THREADS"] = "1"
+os.environ["OMP_NUM_THREADS"] = "1"
+
+from abc import ABC, abstractmethod
+from collections import OrderedDict
+from typing import List
+
+
+import cv2
+cv2.ocl.setUseOpenCL(False)
+cv2.setNumThreads(0)
+
+from PIL import Image
+from facenet_pytorch.models.mtcnn import MTCNN
+from torch.utils.data import Dataset
+
+
+class VideoFaceDetector(ABC):
+
+ def __init__(self, **kwargs) -> None:
+ super().__init__()
+
+ @property
+ @abstractmethod
+ def _batch_size(self) -> int:
+ pass
+
+ @abstractmethod
+ def _detect_faces(self, frames) -> List:
+ pass
+
+
+# Class implementing the MTCNN performing face detection
+class FacenetDetector(VideoFaceDetector):
+
+ def __init__(self, device="cuda:0") -> None:
+ super().__init__()
+ self.detector = MTCNN(
+ device=device,
+ thresholds=[0.85, 0.95, 0.95],
+ margin=0,
+ )
+
+ def _detect_faces(self, frames) -> List:
+ batch_boxes, *_ = self.detector.detect(frames, landmarks=False)
+ if batch_boxes is None:
+ return []
+ return [b.tolist() if b is not None else None for b in batch_boxes]
+
+ @property
+ def _batch_size(self):
+ return 32
+
+# Class for managing videos on which to perform face detection. The video is divided into frames when returned by getitem().
+class VideoDataset(Dataset):
+
+ def __init__(self, videos) -> None:
+ super().__init__()
+ self.videos = videos
+
+ def __getitem__(self, index: int):
+ video = self.videos[index]
+ capture = cv2.VideoCapture(video)
+ frames_num = int(capture.get(cv2.CAP_PROP_FRAME_COUNT))
+ fps = int(capture.get(5))
+ frames = OrderedDict()
+ for i in range(frames_num):
+ capture.grab()
+ success, frame = capture.retrieve()
+ if not success:
+ continue
+ frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
+ frame = Image.fromarray(frame)
+ frame = frame.resize(size=[s // 2 for s in frame.size])
+ frames[i] = frame
+ return video, list(frames.keys()), fps, list(frames.values())
+
+ def __len__(self) -> int:
+ return len(self.videos)
diff --git a/clean/video/mintime/preprocessing/faces_dataset.py b/clean/video/mintime/preprocessing/faces_dataset.py
new file mode 100644
index 0000000000000000000000000000000000000000..6c7eb71c24e5217b2548ad8bf7812fdf9d70ae55
--- /dev/null
+++ b/clean/video/mintime/preprocessing/faces_dataset.py
@@ -0,0 +1,29 @@
+# Class used in extract_features.py file
+
+from torch.utils.data import Dataset
+from PIL import Image
+import torch
+from torchvision import transforms
+import os
+import cv2
+class FacesDataset(Dataset):
+
+ def __init__(self, faces, output_dir) -> None:
+ super().__init__()
+ self.faces = faces
+ self.output_dir = output_dir
+
+ def __getitem__(self, index: int):
+ # Preprocess the image as required by EfficientNet
+ face_path = self.faces[index]
+ tfms = transforms.Compose([transforms.Resize((224,224)), transforms.ToTensor(),
+ transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),])
+ img = tfms(Image.open(face_path))
+
+ # Compose the output path
+ output_path = self.output_dir + face_path.split("faces")[1] + ".pt"
+
+ return img, output_path
+
+ def __len__(self) -> int:
+ return len(self.faces)
diff --git a/clean/video/mintime/preprocessing/merge_csv.py b/clean/video/mintime/preprocessing/merge_csv.py
new file mode 100644
index 0000000000000000000000000000000000000000..37bed21b3be42e46156502a6f912897cc91df9fb
--- /dev/null
+++ b/clean/video/mintime/preprocessing/merge_csv.py
@@ -0,0 +1,11 @@
+import pandas as pd
+
+
+df1 = pd.read_csv("../../../datasets/dfdc_test_preview/test_videos_preview_labels.csv", sep=' ', names=["name", "label"])
+df2 = pd.read_csv("preview.csv", sep=' ', usecols=["name", "label"])
+
+
+df3 = df1.merge(df2, on=["name"])
+
+df3 = df3.drop(["label_x"], axis=1)
+df3.to_csv("common.csv", index=False)
\ No newline at end of file
diff --git a/clean/video/mintime/preprocessing/preview.csv b/clean/video/mintime/preprocessing/preview.csv
new file mode 100644
index 0000000000000000000000000000000000000000..0b0b5c9c0d1514ecb1486d54a4bfa792f474b6c2
--- /dev/null
+++ b/clean/video/mintime/preprocessing/preview.csv
@@ -0,0 +1,119147 @@
+name label frames set
+aaagqkcdis 1 300 val
+aaaoqepxnf 1 300 val
+aaapwqhxli 0 300 train
+aaavbjopeq 1 300 train
+aaavflklag 1 300 train
+aabdnomlru 1 300 test
+aabdogagch 1 300 train
+aabgnwnqba 1 300 train
+aabjfjbpir 1 301 train
+aabkwhhgwv 1 300 train
+aabmgfhcgg 1 300 train
+aabqcugcpc 0 300 val
+aabqyygbaa 0 300 val
+aabunyewgi 1 300 train
+aabuyfvwrh 1 241 train
+aabyjxwqyo 1 300 train
+aaccnjbbxw 1 300 train
+aacehwwzol 1 300 train
+aacfuwiwjw 0 300 val
+aachjwmgcr 1 294 train
+aacmrrcpmr 1 300 train
+aacporghzp 1 299 train
+aacweweyzz 1 300 train
+aacwokkodz 1 300 train
+aadlvezwah 1 300 train
+aadqbokerz 1 300 train
+aadtvsyvzg 1 300 train
+aadubxfxhr 1 300 train
+aadvqhdtxl 1 300 train
+aaedrqeumd 1 300 train
+aaeflzzhvy 1 300 train
+aaeoalihgj 1 300 train
+aaerwkkcfy 1 300 train
+aaeucwtkdx 1 300 val
+aaewstdhzp 1 300 val
+aafcgzwvmy 1 300 train
+aaferzprat 0 301 train
+aafezqchru 1 300 val
+aafiblayhl 1 299 train
+aafkeenkqm 1 300 train
+aafnerhbrs 1 300 train
+aafuphyhpt 1 300 train
+aagfhgtpmv 1 300 train
+aaghqpewzx 1 300 train
+aagkcljeci 1 300 train
+aaglhulpyq 1 300 train
+aagnpclvlz 1 302 train
+aagondskwl 1 300 train
+aagpxhuqpp 1 300 train
+aagsmskgyw 1 300 train
+aagumdmtjk 0 300 train
+aagundkpoh 1 300 train
+aagvhbxgmc 1 300 train
+aahdwkciqw 1 300 train
+aahgdqgozs 1 300 train
+aahkgsltxw 1 300 train
+aahncigwte 0 125 val
+aahntrlswm 1 300 train
+aahslbfkop 1 300 val
+aahsnkchkz 1 300 train
+aahzjreawd 1 300 train
+aaiqegjkrj 1 300 train
+aaiqsitvnd 1 300 train
+aaivbtdyjn 0 300 val
+aaixesxaoj 1 300 train
+aajhbrxhzm 1 300 val
+aajnpdqnlz 1 300 train
+aajrvbynqc 0 300 train
+aajrzgorsm 1 300 train
+aajsqyyjni 0 300 train
+aajtsolpjq 1 301 val
+aajxdztmpb 0 300 train
+aakbpusmxs 1 300 val
+aakdoghgcp 1 300 train
+aakjdfqwnu 1 300 train
+aakjukgjme 1 300 train
+aakkdgsmvl 1 300 val
+aakkhbgnjp 1 300 train
+aaknzywids 1 300 train
+aakrdapxha 1 300 train
+aakxolbwgg 1 300 train
+aakzzdrumy 1 300 train
+aalhdlexwx 1 300 train
+aalkxecnzm 1 300 train
+aalolkuhxb 1 299 val
+aalovlbqts 1 300 train
+aalqaiyuxt 1 300 train
+aamjfukxwp 0 300 train
+aamjpjqkhc 1 300 val
+aamrbolklk 1 298 train
+aamvplpjbw 1 300 val
+aanfrlpkui 1 300 train
+aanhoksyeq 1 300 train
+aannvfgmek 1 301 train
+aansscoqsl 1 300 train
+aanvfngndg 0 300 train
+aanzliuzft 1 300 val
+aanzlvzywt 1 300 train
+aaoecyszps 1 300 train
+aaonlmxhne 1 300 train
+aaooydetsr 1 300 train
+aaoyvnkeyo 1 300 train
+aapauvxnsf 1 300 train
+aapievvnuu 0 300 train
+aapjptyetv 1 300 train
+aapnvogymq 1 300 train
+aapqbyzjws 1 301 train
+aaprcuxsdb 1 241 train
+aaqadjweuz 1 301 val
+aaqaifqrwn 1 300 test
+aaqdkpivxv 1 298 train
+aaqnqubunq 1 300 train
+aaragvjucp 0 300 train
+aarrrzwibf 1 300 train
+aarsgjbafv 1 300 train
+aarsmohwrt 1 300 val
+aarvjowgvd 1 300 train
+aarxilbppj 0 300 train
+aasjtiyjip 1 300 train
+aasobppfwe 1 300 val
+aaspwgdcxx 1 300 train
+aasrzgbdpp 0 300 train
+aassnaulhq 1 299 test
+aaszqdbdtk 1 300 train
+aatfilvfmc 1 300 val
+aatfxhkzqx 1 300 val
+aatgqvvrta 1 300 train
+aatlprhwxl 0 300 train
+aatntbvzum 0 298 train
+aatstfrpio 1 300 train
+aattrykxcr 1 300 train
+aatzuimcwr 1 300 train
+aauevvfyan 1 300 train
+aauffntidi 1 300 train
+aaugopnsow 1 299 train
+aauhqwwncp 1 300 train
+aaujbbfhqu 1 300 test
+aaunepkrsm 1 298 train
+aaunkxgnup 1 300 train
+aaupbhxkoy 1 300 val
+aauzlyqkbj 1 300 train
+aavmhcnxxx 1 298 train
+aavnkpdeaw 1 300 train
+aavoyypnkf 1 298 train
+aavqiqgbzl 1 300 val
+aavuzodiub 1 300 train
+aavvshwqnn 1 300 train
+aavwzojdei 1 300 val
+aavyetamvt 1 300 test
+aawddjkkoz 0 300 val
+aawdgpkfhg 1 300 train
+aawguqttmk 1 300 train
+aawhvztjdt 1 300 val
+aawkmrlilr 1 300 train
+aawukagukx 1 300 train
+aawvkuxypy 0 239 train
+aawwkinixp 1 300 val
+aaxgcsyjyj 1 300 val
+aaxrduwhbi 1 301 train
+aaxzsfqvxv 1 301 val
+aayfryxljh 0 300 test
+aayggxmbke 1 300 val
+aayplaymtt 1 300 train
+aayrffkzxn 0 300 val
+aaytftgoxe 1 300 val
+aayuqaacef 1 300 train
+aayyqrkmow 1 300 val
+aayzrphjgr 1 301 train
+aazbmyxkzg 1 300 train
+aazeuxonse 1 300 train
+aazgvznwmw 1 299 train
+aazjhvpvzn 1 300 train
+aazkzzkbns 1 300 train
+aazqkwibxi 0 300 train
+aazsugjvjk 1 300 train
+abacmovtxb 1 300 train
+abahildqna 1 300 train
+abaodketae 1 300 train
+abarnvbtwb 0 300 train
+abbaqpqgjb 1 300 train
+abbazlhmhz 1 301 val
+abbgqbrdiz 0 300 train
+abbgvafufg 1 300 train
+abbhzhtjru 1 300 train
+abbniyapop 1 300 train
+abcclxtnil 1 300 train
+abcgccgxgq 0 301 train
+abcggjpuqg 1 300 train
+abclkoobgo 1 300 val
+abcrqrbwih 1 300 train
+abcwetphux 1 300 train
+abddemeing 1 300 val
+abdgairkrk 1 300 train
+abdhebzuzt 1 300 val
+abdkzxmzaq 1 300 train
+abdqmdklio 1 300 train
+abdxzlhagb 1 299 train
+abebnhqyzv 1 299 val
+abeibpdqhj 1 300 train
+abeknwzbhx 1 300 train
+abemqhiuki 1 300 train
+abepvlivgr 0 300 train
+abeusommao 1 300 train
+abevkjwulb 1 300 train
+abfcpgmncf 1 300 val
+abfgzgtmdc 1 300 train
+abfhqnwiaz 1 300 train
+abfnyenqdw 0 300 train
+abftzhzfrf 1 300 val
+abfvpzjkwr 1 299 val
+abfwqxqcim 1 300 train
+abfwsuaplk 1 300 val
+abfzzvfkrx 1 300 train
+abganitbvj 1 300 train
+abgjveinnv 1 300 train
+abgmiyhtth 1 300 train
+abgnegvcdm 0 300 val
+abgrdkbhch 1 300 train
+abgsujyria 1 300 train
+abgunexqlc 1 241 train
+abgzebtpyw 1 300 train
+abhdaoikio 1 300 train
+abhggqdift 1 300 val
+abhgyltuqg 1 300 train
+abhlupreiy 1 300 train
+abhqmggsqu 1 241 train
+abhssqzhxu 0 300 val
+abhzleejiv 1 300 train
+abiihwztdo 0 300 train
+abimtvgydq 1 298 train
+abingyvkus 1 298 val
+abinsthlog 1 300 train
+abiodyryai 1 297 val
+abiotberut 1 300 train
+abiyemtwhw 1 300 train
+abjeigrfib 1 301 train
+abjguhkhki 1 298 train
+abjgxazkfk 1 300 test
+abjhsmfczh 1 300 train
+abjkxgezpu 1 300 train
+abjpggtrck 1 301 train
+abjqjcvhwe 0 300 train
+abjrrrufhj 1 300 val
+abjsiiiydj 1 301 val
+abjsubjall 1 300 train
+abjvfvhtnp 1 241 train
+abjvvojmai 1 300 train
+abjykkteik 1 300 train
+abjzzqcwhq 1 300 train
+abkclntljz 0 300 val
+abkepzubca 1 300 train
+abkjuustxy 1 300 train
+abkkrgodfb 1 300 train
+abklmthkbg 0 300 train
+abknwyuqen 1 300 train
+abktvzahwq 1 300 val
+abkwmaixbf 1 300 train
+abkxlatant 1 300 train
+abkyekgdzs 1 300 train
+abkytgczmm 1 300 train
+ablakozzyi 1 300 train
+abldbnaqrk 0 300 val
+ablltmlqya 1 300 val
+ablxzjygfz 1 298 train
+ablzgowmwo 0 300 train
+ablzpwqhcc 1 300 val
+abmcjolywn 0 300 train
+abmdetdeok 1 300 train
+abmfaeqrzx 1 301 train
+abmjszfycr 0 300 train
+abmnkljiny 1 300 train
+abmpdeflqj 1 300 val
+abmtcpjxdi 1 301 val
+abndpnacql 0 300 train
+abnkezfgga 1 300 val
+abnlecswxf 1 300 train
+abnnlixoap 0 300 val
+abnrftezxy 1 300 train
+abnrklaglv 1 301 train
+abnrkomjlr 1 300 train
+abnxwtqpya 1 300 train
+abofeumbvv 1 300 train
+abooilmuow 1 301 train
+abozmriuej 0 300 train
+abpanedvow 0 300 train
+abpibxailk 0 300 val
+abplofmgwg 0 300 train
+abpqikbcpj 1 300 train
+abpwapkxel 0 302 train
+abpynckiti 1 300 val
+abqixolobn 1 300 train
+abqqjjoabz 1 300 val
+abqvchodwu 1 300 train
+abqwwspghj 1 300 train
+abreamitah 1 300 train
+abrfkdizen 0 300 train
+abrnvjbjwb 1 300 train
+abroglvegl 1 298 val
+abrtpedhex 1 300 val
+abrvrktwyp 1 299 train
+abrwlzdhnc 1 300 train
+abrzoxzceh 1 300 val
+absbzgzmsf 1 300 train
+abshlmrtvt 0 300 train
+absrjvblaj 1 300 val
+abssilrpat 1 300 train
+abssjquwjy 1 300 train
+absujvyrdm 0 300 train
+absytkidsf 1 300 train
+abszlbwsaz 1 300 train
+abtdxltqyc 1 300 val
+abterabwrj 1 300 val
+abteztchqz 1 167 train
+abtrcaikve 0 300 train
+abtwfjsdra 1 300 train
+abubfimllc 0 300 train
+abvbbhojqz 1 300 train
+abvgbvoxco 1 300 val
+abviavonpo 0 300 train
+abvmydmmpd 1 300 train
+abvpqidzxi 0 242 train
+abvptajbyb 1 300 train
+abwadcxlmj 1 300 train
+abwbwxdssk 1 300 train
+abwijcvcbe 1 300 train
+abwkycibpi 1 298 train
+abwlafapkf 1 300 val
+abwndgzvkq 1 300 train
+abwvxlfyvh 1 301 train
+abwzrtrwic 1 300 train
+abxeyfzocf 1 300 train
+abxpidbrnq 1 300 train
+abxqiozuzu 1 300 train
+abxqxkuktx 1 300 train
+abxrjzzetq 0 236 train
+abxtkdjyru 1 299 test
+abxxxaobry 1 300 val
+abydcbpvfl 1 300 train
+abyewytpxo 1 300 train
+abygnkrrix 1 300 train
+abyhogcrwu 1 300 train
+abyjfijbjk 1 300 train
+abymaaihkj 1 300 train
+abyrwifdfe 0 300 train
+abysizqmso 1 300 train
+abzamapbpi 1 300 train
+abzbwiyubn 1 300 train
+abzcmncrxu 1 300 train
+abzdscofnz 1 300 train
+abzdxpmmdb 0 300 val
+abzelcbnya 1 301 train
+abzkaeazro 1 300 train
+abzkauwmbl 0 300 train
+acagallncj 1 300 test
+acajitpqte 1 301 train
+acanmekatk 1 300 train
+acazlolrpz 1 300 test
+acbjldcqka 1 300 train
+acbkbblbaj 0 300 val
+acbnunfplf 1 300 train
+acboheogok 1 300 train
+acbolztzli 1 300 val
+acbqitgkie 1 300 train
+acbqyhyrfb 1 300 train
+acbtslwclk 1 301 train
+acbvpkcgqo 1 300 train
+acbztojjhi 1 300 train
+accfhmtiuj 1 301 val
+accfrqkrni 1 301 train
+acckjqyxad 1 300 train
+accnrseufh 0 300 val
+accuranbpc 1 300 test
+acdcqpnwcv 1 300 val
+acdeidkyvv 1 300 train
+acdichcibo 0 300 train
+acdinqwqvn 0 300 train
+acdkfksyev 1 300 test
+acdlfavijf 1 300 train
+acdsdxwpcv 0 300 train
+acdsgpjcpz 0 300 train
+acdycejvma 1 300 val
+acdzvbtfpo 1 300 train
+acefbeffbr 0 300 train
+acegbdlwrl 1 300 train
+acegtkwxxv 1 301 val
+acekdubprv 1 300 train
+acekgkqgdg 1 300 train
+acekqocukw 1 300 train
+acerazhyvo 1 300 val
+acesusftoa 0 300 train
+acfaxepklq 1 300 train
+acffugkzgj 1 300 train
+acfkbngapy 1 297 train
+acfnqjgsgj 1 300 train
+acfontkfbh 0 300 train
+acfpjpwulr 1 300 train
+acfwxwjowu 1 300 train
+acgdmcpqoe 1 300 train
+acgfnrikwu 1 300 train
+acgnyiipuz 1 300 train
+acgousjnbk 0 297 train
+acguxjvmju 0 300 train
+acgwaylwzk 0 300 val
+acgwstvole 1 300 val
+acgyspwyqr 1 301 train
+acgyszkuel 1 300 train
+acgywoqfbr 1 300 train
+acgzblwsgw 0 300 train
+achakioceb 1 300 train
+achcojqaas 1 300 train
+achdeirhym 1 300 test
+achejkrwas 1 300 train
+achekamhkd 1 300 train
+achofoxrpx 1 241 train
+achowwyozf 1 300 train
+achylfkuww 0 300 train
+achzehztxs 1 300 train
+acidsbcssr 1 300 val
+aciecilrsg 1 300 val
+acifjvzvpm 1 300 train
+acihfhsary 1 300 train
+acijttdakc 1 298 train
+aciojxqswi 1 300 train
+acirmhvmqj 1 300 train
+acitwmzozm 1 300 train
+aciukwyoli 1 300 train
+aciwtsxaxa 1 300 val
+aciykyosuy 1 300 train
+aciymzujzb 1 300 train
+acjajsfopu 1 300 train
+acjjzzvzvg 1 241 train
+acjronkyus 1 300 train
+acjwdlpzob 1 300 val
+acjwolqjgw 1 300 train
+acjxjweexj 1 300 train
+ackdbivzat 1 298 train
+acksouhbrc 1 300 train
+ackurqduho 1 300 val
+ackyrwxeew 1 300 train
+aclbgqullo 1 300 train
+acldlsznmw 1 300 train
+acldzthtdb 1 300 train
+acledardkp 1 300 train
+acljemtpdq 1 300 val
+acljesxipy 1 299 val
+acljgkyckk 1 300 val
+aclrropsvm 1 300 train
+aclwcilmvu 1 300 train
+acmbupnrjx 1 300 train
+acmclypsqv 1 300 val
+acmhexsysx 0 301 train
+acmooughzq 1 301 train
+acmprtiljv 1 300 train
+acnjextatt 1 300 val
+acnneviedl 0 301 train
+acnxphmsks 1 302 val
+acocfksxwg 1 300 val
+acoddicury 1 300 train
+acojangjjl 1 300 train
+acokjaojew 0 301 train
+acolsfrwgj 0 300 train
+acomtivxdw 1 300 train
+acottxtsbq 0 300 train
+acovzzymlu 1 300 val
+acozboebwm 0 300 train
+acpaumltcm 1 300 train
+acpcmicltl 1 300 train
+acpdtcpguj 1 300 val
+acpiobctdt 1 300 train
+acpmgqemao 1 300 val
+acpqdpskin 1 300 train
+acpsfrntrv 1 300 train
+acpswnmcyt 1 299 val
+acptlizllc 1 300 val
+acpvctzdde 1 300 train
+acqaoymwjb 1 300 val
+acqawykwfs 1 300 train
+acqfdwsrhi 1 300 train
+acqihnyhih 1 300 train
+acqpwmuogz 1 300 train
+acquouyxco 1 300 train
+acrbohqcuv 0 300 train
+acrfgqyqom 0 300 train
+acrfuqupxt 1 302 train
+acrlghmrkp 0 300 train
+acrmlmgeog 1 300 train
+acrmtzeojb 1 300 train
+acrmwhpkcd 0 300 train
+acrnjclnuw 1 300 train
+acrpacryoy 1 300 train
+acrrbsroel 1 298 train
+acrxkexoqu 1 300 train
+acryukkddn 1 300 test
+acscknxbjl 0 300 val
+acsfdxosrq 1 300 val
+acsgqmpdez 1 300 train
+acsiidpvei 0 300 train
+acsnnvnvhy 1 300 train
+acsooctzwo 1 300 val
+acstbmvpcr 1 300 train
+acsvpqbdfk 1 300 train
+actccpgzdm 1 300 val
+actccqfmac 1 300 train
+actjhhywdl 1 302 train
+actlcrgiug 0 301 val
+actodakupb 1 298 train
+acubjjdopy 0 300 train
+acugesknfp 1 300 val
+acuhmmgmtx 0 300 train
+acukjpjxen 1 300 train
+aculncmpqz 1 300 train
+acuplpopso 1 300 val
+acuqtxhvhc 0 300 train
+acvfwpmvrw 1 300 train
+acvmhbulie 1 300 train
+acvojaahxa 1 300 train
+acvpuukcwl 0 300 val
+acvsdjaqqq 1 300 train
+acwbuvznwf 1 300 train
+acwcgmdxhl 1 300 train
+acwctvmnlq 0 300 train
+acwegmlcgs 1 300 val
+acwgeumyoy 0 300 train
+acwrjqrixb 1 300 train
+acwsfbvhdr 1 300 train
+acwyzobqer 1 300 train
+acxcqyqlwx 1 300 val
+acxnxvbsxk 1 300 train
+acxullwnzh 1 300 train
+acxwigylke 1 298 train
+acxwjqncgh 0 300 train
+acydhcvpnx 0 300 val
+acyjzyuamp 0 300 train
+acymbipdjl 1 300 train
+acysbfbfnz 1 300 train
+acyvmvapdl 1 296 val
+acyvqflqkv 0 300 train
+acyybfjpmd 1 300 train
+acyyvmziij 1 300 train
+acyywefdgd 1 300 train
+aczigtxrgf 1 299 val
+aczjkkdxtd 1 300 train
+aczlzylqpq 1 300 train
+aczofflgti 1 298 train
+aczqjdvoge 0 300 train
+aczrgyricp 1 300 train
+aczrqatleo 1 300 val
+aczsrttjzb 1 300 val
+aczzgyjlrh 1 300 val
+adaebgmnfr 1 300 train
+adaghsyfjw 1 300 train
+adalaxvwfv 1 300 train
+adamtvkcrt 1 300 train
+adanpmvyxk 1 301 train
+adaodkocvq 0 300 train
+adaoqecjet 1 300 train
+adarbftbnt 1 300 train
+adawqznrjo 1 300 train
+adbavqbqsj 1 300 val
+adblmfjbta 1 300 train
+adbniaqshh 1 298 train
+adbovbqdts 1 300 train
+adbrvcotdu 1 300 train
+adbrzekmbf 1 300 train
+adbseuwqjt 1 300 train
+adbtmcrziy 1 300 train
+adbxbaprel 1 300 train
+adbzrcfwga 1 300 train
+adcahlmkdo 1 299 train
+adcbeqixvb 1 300 val
+adcejihrnp 1 300 train
+adchpydhaz 0 300 train
+adchsrubwe 1 300 train
+adciglvoob 0 300 train
+adckadazdl 1 300 train
+adcnvlhawy 1 300 train
+adcomakgmc 1 300 train
+adcxgttehe 0 301 train
+adcywtvtty 1 300 val
+addeinoouo 1 300 train
+addewzbsic 1 300 val
+addkktdymg 1 241 train
+addknoverp 0 300 train
+addmkzupjn 1 300 train
+addsdoqtzo 1 300 train
+addtbwjyjw 0 300 val
+addvsjaeho 1 300 train
+addygiubph 1 300 val
+addyjceutz 1 300 train
+adechdkvaj 1 300 train
+adedomkndn 1 300 train
+adetbwujux 1 300 train
+adezhpkskf 1 300 train
+adfdenhxsm 1 300 train
+adffjkqxhu 1 300 train
+adfgonrqvw 1 301 train
+adfteyuomy 1 241 train
+adftmlvzfs 1 300 test
+adfufsvmcl 1 300 train
+adfzvplbky 1 301 train
+adgbonsihj 1 301 train
+adgeevfgsm 1 300 train
+adgpcfwhtf 1 300 train
+adgsdutoer 1 300 train
+adguixzqmu 1 300 val
+adgveaibmt 0 300 train
+adgwkmcvre 1 300 train
+adgwpnyltr 1 300 train
+adgybhytzs 1 300 train
+adhbvpbwpr 1 300 train
+adhdziprml 1 288 train
+adhfwchxwe 1 300 val
+adhksutmhs 1 300 train
+adhmuoxxhp 1 300 train
+adhsbajydo 1 300 train
+adhwaysrfz 1 300 train
+adhwkmcxpl 1 298 val
+adhwnjtpky 1 241 train
+adhxgdbqlr 1 300 train
+adieleznea 1 298 train
+adiitvebli 1 300 train
+adilspamjj 1 300 val
+adioaqyble 1 301 train
+aditupkylq 1 301 val
+adjeohbzmp 1 300 train
+adjkuzwzvx 1 300 val
+adjwiqxrfp 1 300 train
+adjynjeyrp 1 300 val
+adjzxczied 1 300 train
+adkbiscuoo 0 300 train
+adkbzciieb 1 300 train
+adkmserist 0 300 train
+adkmwvnowf 0 300 train
+adkvpprwcz 1 300 val
+adkymkuove 0 300 val
+adlbyccevz 1 300 train
+adlecsyrxv 1 300 train
+adlpogpncr 1 300 train
+adlrcdmybm 0 300 train
+adltvboxxd 1 300 train
+adlucxlfvr 1 241 train
+adlwbrcqkw 1 300 train
+admbuyewyx 1 300 train
+admgstssgd 1 297 train
+admnsknntz 1 300 val
+admtxtpqza 1 300 val
+admukpsohs 1 301 train
+admyveomqu 1 298 train
+adneakturu 1 300 train
+adnhkwloas 1 301 train
+adnlomirjs 1 300 train
+adnnnmoqek 1 300 train
+adnuzwuhcb 1 300 train
+adnwcpiofc 1 301 train
+adnwmyfaek 1 300 val
+adoegocfid 1 299 train
+adohdulfwb 0 300 test
+adohikbdaz 1 300 train
+adokcuwvpm 1 249 train
+adovxmilsk 1 300 val
+adozueqxqh 1 300 val
+adpaakulte 1 301 train
+adpdecrehl 1 300 train
+adplentlpv 1 300 train
+adpobgciet 1 241 train
+adprabxmos 1 300 train
+adprkekziz 1 300 train
+adptnnwyum 0 300 train
+adpuazsbqv 1 300 train
+adpxdcydgq 1 300 train
+adpxjjknbc 1 300 train
+adqetuqkxh 1 300 val
+adqftoxbjl 0 301 train
+adqgbsyomi 0 300 train
+adqirczghu 1 300 train
+adqyqmibof 1 300 val
+adrcjenxlz 1 300 train
+adrhmbnmof 1 300 train
+adrkthanlb 0 300 train
+adrkztwtyy 1 288 train
+adrnjafcnh 0 300 val
+adrqlckutl 1 301 train
+adrxofhuxi 1 300 train
+adsxpxgjlp 1 300 train
+adsxwxeibr 1 300 val
+adtavmdgvg 0 300 train
+adtcjhkibb 1 300 train
+adtftvevja 1 300 train
+adthviqaig 0 300 train
+adtloiudep 1 300 train
+adtlrixcxe 1 300 val
+adtovspidj 1 300 train
+adtvlinjvb 1 300 train
+adubzfvswf 1 300 train
+aducalsrif 0 300 train
+adueiwhbql 1 300 val
+adugeltfwz 1 300 val
+adukaourac 1 300 val
+adurlibudg 1 300 val
+advhlnfwag 1 301 train
+advqisfjvd 1 301 train
+advyjmiozx 1 300 train
+advzryyfkn 0 300 val
+adwbthsgqb 1 299 test
+adwdhdssrh 0 300 train
+adwhyklevu 1 300 val
+adwjhlqver 0 300 train
+adwrokpofy 0 300 val
+adwtqjusqx 1 300 val
+adwujlygpp 0 300 train
+adxbfqfvry 1 299 val
+adxeuzvvzb 0 300 train
+adxkyxkepg 1 300 val
+adxnttcbku 1 300 train
+adxqqhgqnb 1 300 train
+adxsoladps 1 298 train
+adxtihgjrs 1 300 train
+adxvxfsbhw 1 300 val
+adybvfykyw 1 300 train
+adybwllgkj 1 301 val
+adyfconmdy 1 300 train
+adyhhmmvxb 1 300 train
+adyiotxxxu 1 300 train
+adylbeequz 1 300 train
+adylpmghhr 1 300 train
+adylsrnsan 1 300 train
+adywyvayvj 1 300 val
+adzcyjtpet 1 300 train
+adzogkbmuo 1 300 train
+adzpdfkzaj 1 300 train
+adzxmqarac 1 301 train
+adzxumycjn 1 300 train
+adzzdafqok 1 300 train
+aeaalcklkf 1 300 train
+aeafanmfvt 1 300 train
+aeahutrvaj 1 300 train
+aeamguivpq 0 300 train
+aeapxhoeli 1 300 train
+aearhnatoj 1 301 val
+aebafchtks 1 300 train
+aebaxxepmo 1 300 train
+aebenljufi 1 300 train
+aebgvmafzx 1 300 train
+aebhowazav 1 300 train
+aebjlsefci 1 298 train
+aebkhtsigw 0 300 val
+aebrgxdalw 1 300 train
+aebybbzzdp 1 300 train
+aecaowvcvo 1 300 train
+aeccicjqmy 1 300 val
+aecehlesrj 1 300 train
+aecilvlrmt 0 299 train
+aeciwinhhl 1 300 train
+aeclidpgbb 1 300 train
+aecmpgzdbs 1 300 train
+aeconjpzxx 1 300 val
+aectxtnhws 1 300 train
+aecunwnmcw 0 300 train
+aedbcwxsud 1 300 val
+aedbjztjwz 1 300 train
+aedcdpbyhq 1 300 train
+aednqykqfh 1 300 train
+aedxxcqpqk 1 301 val
+aeectgudlh 1 300 val
+aeeesixhlh 1 300 train
+aeeigakagw 1 300 train
+aeeigmpocb 0 300 train
+aeejcrifmn 1 300 train
+aeejycxkwb 1 300 train
+aeendqqdkv 1 300 train
+aeepmwyhkk 1 300 train
+aeetrnfoir 0 147 train
+aeeuubqure 1 300 val
+aefblqbblo 1 300 val
+aefcnrszdv 1 240 train
+aefjjvlmfe 1 300 val
+aefkeswufw 1 300 train
+aefpqqxvbe 1 300 val
+aefsxxkosk 1 300 train
+aeftglfxkv 0 300 train
+aefxispfct 1 300 train
+aegchddxjh 1 300 train
+aegeiboeus 1 300 train
+aegmpmgpje 1 300 train
+aegvtnwqoe 1 300 val
+aegwmawqov 1 300 val
+aegzgdzwhx 1 298 train
+aehavkoosa 1 300 val
+aehqeompff 1 300 train
+aehruoendm 0 300 train
+aehsmecopx 1 300 train
+aeiagzdnun 1 300 train
+aeibxrjmej 1 300 train
+aeicdssqro 1 300 train
+aeiljgujcj 1 301 train
+aeinolstjf 0 300 train
+aeiziaaxua 1 300 val
+aejgdsuoqg 1 300 val
+aejhwrtzel 1 300 val
+aejlbaxwrb 0 300 train
+aejnircxtk 1 300 train
+aejqcnyktk 1 300 train
+aejroilouc 1 300 test
+aejtmxrtxs 1 300 train
+aejvkfbtxs 1 300 test
+aejxzhccak 1 300 train
+aejywkgnar 1 301 train
+aekbcfwbwg 1 300 train
+aekcmnblby 1 300 test
+aekibaeyku 1 300 val
+aekmkwtlis 1 300 train
+aekosfipob 1 300 train
+aekrohihxa 1 300 train
+aekvkkmfqi 1 301 train
+aelcnlgdez 1 255 train
+aeldazmimi 1 300 train
+aelegvxesy 1 300 train
+aelfnikyqj 0 300 train
+aelsditult 1 298 train
+aelsfznuqw 1 299 val
+aelvskvush 1 300 val
+aelybbzizk 1 300 train
+aelzhcnwgf 1 300 train
+aemdhhvdbm 1 301 val
+aemfpfwron 1 300 train
+aemjdivfqf 1 300 train
+aemldzfofe 1 300 train
+aempoxlxod 1 301 train
+aemtbjgkfl 1 300 train
+aemursmjjc 1 300 train
+aemuyscfmg 1 300 train
+aemywfagkq 0 300 train
+aenbgyszpv 1 300 train
+aenbulmxjs 0 300 train
+aencvflgzz 1 300 val
+aendggysgf 1 300 train
+aenfqtmksu 1 300 train
+aenrudespm 1 300 train
+aentwuqfmv 1 300 train
+aeoeeroavr 1 300 train
+aeofbjgjgb 1 300 val
+aeolxtsnfc 0 300 train
+aeoogtyzpd 1 300 train
+aeovzefbpr 1 299 val
+aeoxlkxmyj 0 300 val
+aepbnctjuv 1 300 val
+aepfidmamk 1 300 train
+aephjahtms 1 300 train
+aepixllcqi 1 300 val
+aeplbqxnge 1 300 train
+aeplkbgkub 1 300 train
+aepnnpkscx 1 301 train
+aepuluzrdy 0 300 train
+aeqdxmdwrd 1 300 train
+aeqengxxrg 0 301 val
+aeqfnecrcb 1 301 val
+aeqpxjlbwu 1 300 test
+aeqrctqwxt 1 300 train
+aeqslfyyih 1 300 train
+aeqwhzfyzg 0 300 train
+aerabkktdg 1 300 train
+aerhtwlqzx 1 300 train
+aerihvkxyj 1 301 val
+aerkmsxipq 1 300 train
+aernxhvxss 1 301 train
+aerpisvqwx 1 300 train
+aerwisykdl 0 299 val
+aerzetktyh 0 300 train
+aesdmkwcja 1 300 val
+aesicqmigv 1 296 val
+aesqljtwep 1 300 train
+aesxbmbwce 1 300 train
+aetbhpddib 1 301 val
+aetbyrujti 1 300 train
+aetcdsmpld 1 301 train
+aetdhiqpaf 1 300 train
+aetpnobkcv 1 300 train
+aettqgevhz 1 300 train
+aetucrlshk 1 298 val
+aeudhfvcvk 1 299 test
+aeujbvkafe 1 300 val
+aeusdpiftd 1 301 val
+aeuxknmacb 1 241 train
+aeuyruleqo 1 296 val
+aeuzjqawlf 1 301 val
+aeuznaywzs 1 300 train
+aevavjcuqq 1 301 train
+aevbmlbayq 0 300 train
+aevfqnzeuu 1 300 train
+aeviyhvand 1 300 train
+aevjgnxdei 1 300 train
+aevmvtdssq 1 300 train
+aevpdbbxoh 1 300 train
+aevqxxxhno 1 300 train
+aevrfsexku 1 300 train
+aevvibtfva 1 300 train
+aevxvajusj 0 300 train
+aewaxxdbjk 1 300 train
+aewhkicghc 1 300 val
+aewkzkqmqj 1 300 train
+aewplvpush 1 300 val
+aewpytojhs 0 300 train
+aewsbofgwl 0 300 train
+aewyjymfdv 1 297 val
+aewzjcqpaq 1 300 val
+aexfaanqvz 1 296 train
+aexhjlyxko 1 300 train
+aexkdsocpo 1 300 val
+aexrhjvlfa 1 300 train
+aexunyfjsl 1 300 val
+aexvjvqmsj 1 300 train
+aexwgcmvef 0 300 train
+aeybidzwoe 0 300 train
+aeydatwurh 1 300 val
+aeydtyokjq 1 300 train
+aeykoomsoa 0 298 train
+aeyprmocjo 1 300 train
+aeysrmfmht 0 300 train
+aeytxfwmjh 1 300 train
+aeyvvhevxe 1 300 train
+aezagrnzdz 0 300 train
+aezcgyslac 1 300 train
+aezgmksjlx 1 300 train
+aeziwslgvt 1 300 train
+aezndieatk 1 300 train
+aezujunliw 1 300 train
+aezvgaqjpf 1 241 train
+aezyekjqvb 1 300 train
+aezyoffjsd 1 300 train
+aezyquwuci 1 300 val
+afadqgujvi 1 300 train
+afaduxukbd 0 300 train
+afagmjswbt 1 300 val
+afagoqmhsb 1 300 train
+afakjxsove 1 300 train
+afanttpmut 1 300 val
+afatmolcby 1 300 train
+afaxsgqksm 1 300 train
+afbgivckik 0 300 val
+afbhfqnswr 1 301 val
+afbjhgoqcz 1 300 val
+afbpbhunsi 1 300 train
+afbscszraw 1 300 train
+afbwxsnsjv 0 300 train
+afbxszoeml 1 300 val
+afcbxoxdmz 1 300 val
+afceemtoue 1 300 train
+afceqneqfr 1 300 train
+afcfvexdoj 0 300 train
+afchfngwuj 0 300 train
+afcicxheuj 1 300 train
+afcldghkid 1 300 train
+afcwvndury 0 300 train
+afcxyiwatf 1 301 val
+afdblocyhi 1 300 val
+afdcbqqjgz 1 300 train
+afemctlakq 1 300 val
+afemjrgmyk 0 300 train
+afeqcmrcww 1 300 train
+afetvyxndy 1 300 train
+afexcmhzxn 1 300 train
+afezjurpyw 1 300 train
+affyecftqy 0 301 train
+affymoposl 1 300 train
+affyuivhqt 0 300 val
+afgeaslihg 1 300 train
+afghvrnxni 1 300 train
+afgmszwvvg 1 301 train
+afgplxczaq 0 300 train
+afgvjnqstv 0 300 train
+afgynkcgrs 1 300 train
+afhbouinds 1 300 train
+afhoaqaddf 1 300 val
+afhxxvslsv 1 300 train
+aficsrypiz 1 239 train
+afigzzlags 1 300 train
+afilktvfxg 1 301 train
+afilyikdgg 1 300 train
+afixxjdxef 1 300 train
+afjcibuemx 1 300 val
+afjhezcxar 1 300 val
+afjhgapojs 1 300 train
+afjiqyggtd 1 300 train
+afjmjzmdkp 0 300 train
+afkddezfkx 1 300 train
+afkdviidui 1 300 train
+afkfjviffj 1 300 train
+afkfweamui 1 300 test
+afkufwvefm 1 300 train
+afkwttdfff 1 300 train
+afkyiunrcp 1 300 val
+aflonsoyfh 1 300 train
+aflspexpuy 1 300 train
+aflyrowbiw 0 300 train
+aflyunuroo 1 300 train
+aflzwnkfqp 1 300 train
+afmhdngiib 0 301 train
+afmopoanwn 1 300 val
+afmxcjlzbq 1 299 train
+afmxymkjmu 1 300 train
+afmxyqnnle 1 300 train
+afnbrsikom 0 300 train
+afncpysbqu 1 99 train
+afndtsydmt 1 300 train
+afnfgunwvj 1 300 train
+afngwmjuuy 1 240 train
+afnhmtuuva 1 300 train
+afnkxiexxj 1 300 train
+afnwtbqjoe 0 300 val
+afnxnrrqsj 1 300 val
+afnzlmwxjr 1 300 train
+afodzmqylg 1 300 val
+afoebgprva 1 300 train
+afolgdwiix 1 300 val
+afoovlsmtx 0 300 train
+afoqnvmfza 1 300 train
+afouwfpdkd 1 300 train
+afovojcvgh 1 300 train
+afpjojmsxq 1 300 train
+afpkqtshaf 1 300 train
+afplylzzji 1 300 train
+afposymfjh 1 300 val
+afpqokzmev 1 300 train
+afqatecrhd 1 299 val
+afqaubpglg 1 300 train
+afqbbzjetx 1 300 train
+afqfrfdowg 1 299 test
+afqhjqevie 0 300 val
+afqobtsxpk 1 300 train
+afqpwplnfm 1 300 train
+afqtpkzppe 1 300 val
+afrarzddbh 1 300 val
+afrdmyapxj 1 300 train
+afrdnpridi 1 301 val
+afrgmowivl 1 300 train
+afrhfiziqx 1 301 train
+afrwahmczi 1 300 train
+afrwgxjdqz 1 300 val
+afscljojpo 1 301 train
+afslhsyvcg 1 300 train
+afsljlgvcm 1 300 val
+afsokxukic 1 300 train
+afsrjsoyyn 1 300 train
+afstvgkgcn 1 300 val
+afsudznjfa 1 300 train
+aftbvueeid 1 300 train
+aftigtgxdj 1 301 train
+aftqqmiysd 0 300 train
+afttgbsiqt 1 300 train
+afttsjskam 1 298 train
+afuafjgwcz 1 300 val
+afuahfjtdh 0 300 val
+afugtpbwml 0 300 train
+afuooedkej 1 300 train
+afuskeckyt 0 301 train
+afuumscrle 0 301 val
+afuvfbnutt 1 300 train
+afuwpzydbg 1 300 train
+afvahljafh 1 300 train
+afvbadakux 1 300 train
+afvbnsjcyu 1 301 train
+afvdmlwwyr 1 300 test
+afvefokzbu 1 241 train
+afvldbcclm 1 239 val
+afvlrevses 1 300 train
+afvufvldvx 1 299 val
+afvwwfbjhn 1 300 train
+afvzgjwiue 1 300 train
+afwadscyfu 1 300 val
+afwakzqdin 1 300 train
+afwapwjzha 0 300 train
+afwdweiwla 1 300 train
+afwnbrjjpz 1 300 train
+afwrywjodm 1 300 val
+afwxvdwyuc 1 300 train
+afwxwlxfbc 1 298 train
+afwzbrfqbs 1 300 train
+afwzhwbutk 0 300 train
+afxafafvae 1 296 val
+afxatgswor 0 300 train
+afxjvtvfkb 1 300 val
+afxksdrgnc 0 300 train
+afxtastwkm 0 300 train
+afxuuxmywr 1 300 train
+afyatncsun 1 300 train
+afygfggngz 1 299 val
+afynesbqqg 1 301 train
+afyywbpmoh 1 300 train
+afzahsqjgi 1 300 train
+afzalzwwsr 1 300 train
+afzcqkgcgl 1 301 train
+afzglsuwio 0 300 train
+afztrudtkd 1 300 train
+afzumybalb 1 300 train
+afzxoznquw 1 301 train
+agaecoeisr 1 300 train
+agapxbbgnu 1 300 train
+agaqxbgman 0 300 val
+agatrlvpov 1 300 val
+agaxevrqio 0 301 train
+agayctninz 1 300 train
+agazcxsnes 0 300 train
+agbavyxjhd 0 300 train
+agbcymftvq 1 300 train
+agbfymrrhv 1 300 train
+agbgwqacac 0 300 train
+agbkftuluk 1 300 val
+agblhurdrh 1 300 train
+agbpetxkrk 1 300 val
+agcdaizeff 1 300 train
+agcmwyvauk 0 300 train
+agcoyyzeju 0 300 train
+agcxmqfjos 1 300 val
+agcymsmqhj 1 300 train
+agdevdgwsm 0 300 train
+agdgtimgdl 1 300 train
+agdivudslh 1 300 val
+agdizmxpmy 1 300 train
+agdkmztvby 1 300 train
+agdmjlttjy 1 300 train
+agdqtpimwr 1 300 train
+agdqwwrorz 1 241 train
+agdtcltibk 1 301 val
+agdvzcriwo 1 300 train
+agdxsawgeu 0 300 train
+agefbqufao 1 300 train
+agelbmkcdx 1 301 train
+ageronljbq 1 300 train
+agetriarxi 1 300 train
+agfivzlsgp 1 300 train
+agftvgduvu 1 300 train
+agfwadzxld 1 300 train
+agfyfocump 1 300 train
+agfzapmdwv 1 300 train
+aggbmxhrgs 0 300 train
+aggepsqvqg 0 301 val
+aggganpwec 1 300 val
+aggiycwmvz 1 300 train
+aggpkjygfy 1 300 train
+aggutjkaoz 0 300 val
+aggwnlepuy 1 301 train
+aghcwdjoye 1 300 train
+aghejhqnru 1 300 train
+aghgphfvfe 1 300 train
+aghjtpfofw 1 300 train
+aghlanmigg 1 300 train
+aghqistaok 1 300 train
+aghsirqfno 1 300 train
+aghvhjzesz 1 300 train
+aghvylrrfp 1 300 train
+agiddwueyy 0 301 train
+agigxglzjk 1 300 train
+agikkrfetn 1 300 train
+agilfnldve 1 241 train
+agiwssahrz 1 300 train
+agjaeoqtez 1 300 val
+agjbagvosr 1 300 train
+agjbahosfa 1 300 train
+agjfrevfeu 1 300 val
+agjhckhukv 1 300 val
+agjtsqujbq 0 300 train
+agjtuglktq 1 300 train
+agjxddzjbn 1 300 train
+agjxpidzyu 1 299 val
+agjxxuumuk 1 300 train
+agkkktssvy 1 300 train
+agkkrpggrh 1 301 train
+agklhwhjog 1 300 val
+agkmxixxts 0 300 train
+agkpbfcpiv 1 300 train
+agktbbxwla 1 300 train
+agkuzeyvkl 1 241 train
+agkvcuntqw 1 300 train
+agkxvmtyfj 0 301 train
+agkziowtjo 1 300 train
+aglalfjfer 1 300 train
+agldheqnhf 1 300 val
+aglogtnjvs 0 300 train
+aglqdsqmim 1 300 train
+aglwqifqwf 1 301 train
+agmnmsiywb 1 300 train
+agmsqaprtg 1 300 val
+agmurwijnw 0 300 train
+agnhfoufjd 1 300 train
+agnhllzynr 0 300 val
+agnhouokqg 1 300 train
+agnsnklhny 1 300 train
+agnvcwmsli 0 300 val
+agofgfcuuv 1 301 train
+agomxvsluh 1 300 train
+agorzaxkul 1 300 val
+agotmizucf 1 300 train
+agougdutjy 0 300 train
+agoxwwvpiv 1 301 train
+agpaqovbup 1 300 val
+agplffthuy 1 299 test
+agplobkyci 0 300 train
+agpvkgrgyj 1 300 train
+agpzzhhprs 1 300 train
+agqickzelv 1 300 val
+agqncsarzb 0 300 val
+agqphdxmwt 1 300 train
+agqqdoeswy 1 300 train
+agqzyglsup 1 300 test
+agraudgvee 1 300 train
+agrdrmjtrq 0 300 train
+agrfxefnih 1 300 train
+agrkmxywnc 1 298 train
+agrmhtjdlk 0 300 train
+agrqzohqhx 1 300 train
+agrvzckdbj 1 298 train
+agrzahazcy 0 300 val
+agrzhzapku 1 300 train
+agsbrbnbfh 1 300 val
+agscxjuzvp 1 300 train
+agsjaljtfp 1 300 train
+agsjjtssht 1 300 train
+agsnfupaiw 1 300 train
+agsotutjdj 1 300 train
+agsrndgxzi 1 300 train
+agsrndrnjg 1 300 train
+agstrotlwr 1 301 train
+agsvesfhlc 1 300 train
+agswjtuhss 1 300 val
+agswocdgzj 1 300 train
+agtfkordde 1 300 train
+agtgnkxfhg 1 269 train
+agtgoythda 1 300 train
+agtioqicwp 1 99 train
+agtjsmsgxj 1 300 train
+agtozfbnvo 1 300 val
+agtqrhfvty 1 300 train
+agttormoky 1 297 train
+agtumquthr 1 300 train
+agtvzogidd 1 300 train
+agtwxptvyu 1 298 train
+agtxxhgqyw 1 300 train
+agtyuglxan 1 300 val
+agultmegkn 1 298 val
+aguruxyozv 1 300 train
+aguvisboqr 1 300 train
+aguwbmeuzu 0 300 train
+aguxjvffln 0 300 val
+aguxpzvexp 1 300 val
+agvfchxufj 0 301 train
+agvggvwpgw 1 300 val
+agvgmjuzru 1 300 train
+agvncgirex 1 300 train
+agvqqmsyvo 1 300 train
+agvtpygfdc 0 300 val
+agvtumzugg 0 270 train
+agwbnwpmdr 1 300 train
+agwbtwcwwq 1 300 train
+agwcegyvuy 1 300 train
+agwgyxvxjp 1 300 train
+agwjizbwzg 1 300 val
+agwonnvtov 1 300 val
+agwrmbdcom 1 300 train
+agwswijsqz 1 300 train
+agwtdbsape 1 300 train
+agwtvukqyx 1 300 train
+agxplbynwg 1 300 train
+agxptfaavu 1 300 train
+agxqtmywcf 0 300 train
+agxuqnnjsb 1 300 train
+agyawnxlmv 1 300 train
+agycsxhdjp 1 300 train
+agygngjgse 0 300 val
+agykjehfsf 1 300 val
+agyozdhdga 0 300 train
+agyrefuzye 1 300 val
+agyvsqfpcd 1 300 train
+agzfylehqn 1 300 train
+agziimvuqi 1 300 test
+agzkdngoop 1 300 train
+agzpasxmwv 1 300 train
+ahaewflcaf 1 300 train
+ahalqtfixi 1 300 train
+ahanoygyei 0 300 train
+ahaopbalyf 1 300 train
+ahauixjqjp 1 300 val
+ahayccwqkh 0 298 train
+ahbdzvywry 1 300 val
+ahbfnhuner 1 300 train
+ahbgvauzmm 1 300 val
+ahbjzjoucp 1 300 train
+ahbnjrtnwc 1 300 val
+ahbrmguujk 1 300 train
+ahbroumuqx 1 301 train
+ahbweevwpv 1 300 train
+ahcbiribgn 1 300 test
+ahccavvrcc 1 300 val
+ahccdihrje 1 300 train
+ahclqgbbty 1 300 train
+ahcptgydid 1 300 train
+ahcuvkqvsh 1 300 train
+ahcxtenjgp 1 300 train
+ahczosvxjq 1 300 train
+ahdbuwqxit 1 300 train
+ahdegpidyf 0 300 train
+ahdhhhiila 1 300 train
+ahdhrrzejm 1 300 train
+ahdizndylm 1 300 val
+ahdjlkjoiy 1 300 train
+ahdlptchip 1 300 train
+ahdvqprptb 1 300 val
+ahencqpiin 1 300 train
+aheocfkxjx 1 299 test
+aheoeiyzds 1 300 train
+ahepenxrrd 1 300 train
+ahesnzswur 0 300 train
+ahfazfbntc 1 300 train
+ahfmgtflry 1 298 train
+ahfndeqsed 1 300 val
+ahfpbtfydo 1 300 train
+ahfpwhmsok 1 300 train
+ahfqcbiwuy 1 300 train
+ahfqnhrmbd 1 300 val
+ahftrfxija 1 300 train
+ahfvehrmse 0 300 train
+ahfvmgltlg 1 300 train
+ahhciegkde 1 300 val
+ahhdprhoww 1 300 test
+ahhelrolkm 1 300 train
+ahhgiituzu 1 300 train
+ahhjoedhbf 1 300 train
+ahhvwmilvv 1 300 train
+ahhwcjandn 1 301 train
+ahibdgjstv 1 300 train
+ahidherfqr 1 300 val
+ahihejgaoi 1 300 train
+ahiinegyte 1 298 train
+ahinnadnzp 1 300 val
+ahjankljtz 1 300 train
+ahjeixrwwo 1 300 val
+ahjgsdsldx 1 300 train
+ahjnugetia 1 300 train
+ahjnxtiamx 1 300 test
+ahjthipwks 1 300 train
+ahkbgzabfg 1 300 train
+ahkcchuwqq 1 300 train
+ahkibiituu 0 300 train
+ahkmridxqn 1 300 test
+ahksrawlnz 1 600 train
+ahleretiea 1 300 val
+ahlilvgbjd 1 300 val
+ahlkrjkpvd 1 300 train
+ahlvxupazj 1 300 train
+ahlzkwgzan 1 301 train
+ahmcwvbeus 0 300 train
+ahmsvvakhn 1 240 val
+ahmtarbkeg 0 300 train
+ahmtzpethi 1 300 test
+ahnbazrjlj 1 300 train
+ahngpfavrr 0 299 val
+ahnhwpxegb 1 300 train
+ahnohhcpqg 1 300 val
+ahnsqjtrce 1 300 train
+ahofrimoni 1 300 train
+ahohjltigz 1 300 train
+aholwinrku 1 298 train
+ahoofqneve 1 241 train
+ahoqopgaey 1 300 train
+ahorlqgstq 0 300 train
+ahosxsezvx 1 301 val
+ahovbbmyls 0 300 train
+ahovtectej 1 301 train
+ahoyonpatk 1 300 train
+ahoyxuiikx 0 300 train
+ahpaydsovz 1 300 train
+ahpnrwwibe 0 301 train
+ahpomwuuqc 1 300 train
+ahptnosmvj 1 301 train
+ahpvzeetyy 1 300 train
+ahqaspvikq 1 300 val
+ahqausishe 1 300 train
+ahqbzhlgfd 1 300 train
+ahqgxlxnwq 1 300 train
+ahqmrttyeq 0 300 val
+ahqoyfwmbj 1 300 train
+ahqqqilsxt 0 300 train
+ahqwgdsqjn 0 300 val
+ahqwhhmpbn 1 301 train
+ahrfivqfhq 1 301 train
+ahrigbsxpt 1 300 train
+ahrqzxkppw 0 300 train
+ahrroblasu 1 300 train
+ahrwawtzzg 1 301 train
+ahsabqozjt 1 298 train
+ahsczfpqqw 1 300 val
+ahsdvvcjjo 1 300 train
+ahsnuvkzcp 1 300 val
+ahsogiihuz 0 301 train
+ahsqadzghy 1 300 train
+ahssjssyen 1 241 train
+ahsuwsrgrw 0 300 train
+ahtaeeesuo 0 300 train
+ahthfectji 1 241 train
+ahtkuwkjvc 1 300 train
+ahtoprtppg 1 300 train
+ahtqfxuxya 1 300 train
+ahtrvxiaky 1 300 train
+ahtuimxddu 1 300 train
+ahuaopqhtl 1 249 train
+ahuhnviqom 1 300 train
+ahujkugdci 1 300 val
+ahukuoipxb 1 300 train
+ahumqtvbug 0 300 val
+ahunqpenmk 1 300 val
+ahuynjystq 1 300 train
+ahvaayggcf 0 300 train
+ahvatznenl 1 301 train
+ahvnjazgls 1 300 train
+ahvqekzvzf 0 300 train
+ahvroxnbbr 1 300 train
+ahvyeeaweq 1 296 train
+ahvztuxoyw 1 300 train
+ahwduszjzf 1 241 train
+ahwhvnfqhj 1 241 train
+ahwnelkxdg 1 300 train
+ahwoqcizcp 1 300 train
+ahwyeumiuv 1 300 train
+ahxeohagtn 1 300 train
+ahxhzvzgrb 1 300 train
+ahxiodzlfq 1 298 train
+ahxjlznfwx 1 301 train
+ahxmhugdvi 1 300 train
+ahxmjmqsgx 1 300 val
+ahxnjolsip 1 300 train
+ahxspfdyny 1 300 val
+ahxwvdyowy 1 300 train
+ahyakuhocp 1 300 train
+ahycbdxsmi 0 300 val
+ahyhvmgxfn 0 300 train
+ahyopyzjnc 1 300 train
+ahypssdaef 1 300 train
+ahytipibgx 1 298 train
+ahzeyrmulw 1 300 train
+ahzfqirfkx 0 300 train
+ahzidpmemk 1 300 val
+ahzphhzvkj 0 300 train
+ahzsimvscu 1 300 train
+ahztdracba 0 300 val
+ahzuhugjto 0 300 train
+aiakxmxgdl 1 300 val
+aiaplmnzaz 1 300 train
+aiaqzkpvlf 1 240 train
+aiauzuibuq 1 300 train
+aiaxrvlchq 1 300 train
+aiaxyavqce 1 136 train
+aibcynuhkv 1 300 val
+aibfastlwt 0 300 train
+aibiqkczez 1 300 train
+aibiskwzkj 1 300 train
+aibnhrfwae 1 300 train
+aibolzviqm 1 300 train
+aibqozcqvy 1 300 train
+aibtlxfhqi 1 300 val
+aibwsfyvov 1 297 train
+aibxtmpppt 1 300 train
+aibyxmwvfw 1 300 train
+aicblqhpby 1 301 train
+aicezwkwgl 1 300 train
+aiclznskrl 0 300 val
+aicovlahym 1 241 train
+aicvhawriu 1 300 train
+aidjfsfgjc 1 300 train
+aidnmtgwlv 1 300 train
+aidocisbby 0 300 train
+aidosztwoi 1 300 train
+aidtdqafdq 1 300 train
+aiedovfeob 1 300 val
+aiegstqzno 1 300 train
+aiehtsizbs 0 300 train
+aieprwfqzp 1 300 train
+aieqhlrbev 0 300 train
+aieztoondm 1 300 val
+aifkdzbaoh 1 300 train
+aifsxulphe 1 300 train
+aifuqnayux 0 301 train
+aigfuneurk 0 301 train
+aigiiemnfz 1 300 val
+aigncbayvh 1 300 train
+aigpvcechi 0 300 val
+aigrhrowsj 1 301 train
+aigufxcoyu 1 300 train
+aigvwkmsmp 1 300 train
+aihfeivawc 1 269 train
+aihgwxorxq 1 300 train
+aihnytdica 1 300 train
+aihvsjluzl 1 300 train
+aiibawuqtp 1 300 train
+aiidydwsim 1 236 train
+aiihfyykkb 1 300 train
+aiintrmpaq 1 300 val
+aiiqqfaihm 1 300 train
+aiismkiywk 1 300 train
+aijdqpqexk 1 300 train
+aijegkeygj 1 300 val
+aijlttdlrj 1 300 val
+aijmlfesyw 0 300 train
+aijxucsclo 1 300 train
+aikcsvtwxj 0 300 train
+aikmehbtbm 0 300 val
+aiknwokflv 0 300 train
+aildcyhkso 1 300 train
+ailhqhhqtl 1 300 train
+ailmasxkxb 0 300 val
+ailwalkorh 1 300 train
+ailyhemgyh 1 301 train
+aimkjacvip 1 300 val
+aimsrnwtvo 1 300 train
+aimusoodfa 1 300 train
+aimvdfybka 1 300 train
+aimzesksew 1 300 test
+ainvaeqxez 1 300 val
+ainwxnaqlo 1 300 train
+aiodnwhjvu 1 301 val
+aiohyupybq 1 300 val
+aioixdvbzg 1 300 train
+aiojrozfyt 1 299 train
+aiolqtfgui 1 301 train
+aiovfueakc 0 300 train
+aiovoszqsn 0 300 train
+aiovtwpvfy 1 300 train
+aioxedgymv 1 297 train
+aipchbpyjo 1 299 train
+aipfdnwpoo 1 300 train
+aiphtedvul 1 300 train
+aipkhjqodg 1 300 val
+aipmicjriy 0 300 val
+aipyyuyypd 0 300 val
+aiqilfmklp 1 300 train
+aiqjrdcrzi 1 300 train
+airioqpngh 1 300 train
+airjvvwwbc 1 300 train
+airktntzqp 1 300 train
+airnsbszvn 1 300 train
+airohvpnga 1 300 train
+aisdsiyxvh 1 300 train
+aiseiufjsz 1 300 val
+aisjmesfqi 1 300 train
+aismvzujjr 1 301 val
+aisncatiyp 1 300 train
+aisumjkudv 1 300 train
+aitakbuqnz 1 300 train
+aitdmcambv 1 300 train
+aitfcfdpjs 0 300 train
+aithjjsyax 1 300 train
+aitisdvlut 1 301 train
+aitoprvlda 1 300 val
+aitoysnomk 0 300 train
+aitvdkyvtd 1 300 train
+aiucrzbces 1 300 train
+aiugvovqhw 1 297 train
+aiuimrebtg 1 300 test
+aiuoeqfcka 1 300 train
+aiupnpzgkp 0 300 train
+aiuutdsmpd 1 300 train
+aiuvaldnqj 1 300 val
+aiuydkbjok 1 300 train
+aivhvskkgc 1 300 train
+aivqjujqqd 1 300 train
+aivslmwqcd 1 301 train
+aivucpvfus 0 300 train
+aivxgeymaa 1 300 train
+aivycazeqs 1 269 train
+aiwksstbri 0 300 val
+aiwoabwgca 1 300 train
+aiwvljvnzz 1 241 train
+aixcbptqob 1 99 train
+aixiawohqn 1 299 val
+aixkdvqcem 1 241 train
+aixowzqxlu 1 300 train
+aiydnuoloc 1 301 train
+aiyicetcoo 1 300 train
+aiymomktet 1 300 val
+aiyqaylifg 1 300 train
+aiyvrupckg 0 300 train
+aiyvsxcnlz 1 300 train
+aiyxcubozy 1 300 train
+aizcowqwmg 1 300 train
+aizcvzaxcj 0 300 train
+aizcylpyoq 1 300 train
+aizdhhesnq 0 300 train
+aizythrjcu 1 300 train
+ajacacjktb 1 300 val
+ajacmuqpht 1 300 train
+ajafdvgcyj 1 241 train
+ajajvcjnlm 1 300 train
+ajalgtjhgp 1 300 train
+ajazlwhecq 1 300 train
+ajazyuaoef 1 300 val
+ajazzycoqz 1 300 val
+ajbfgffvfe 1 300 train
+ajbfsfwphp 1 300 train
+ajblihrqat 1 301 val
+ajbmmkwnzf 0 300 val
+ajbqnhtzhp 1 300 train
+ajbtpylnqr 1 300 train
+ajbxbxcrdo 0 300 train
+ajcgqfzbef 1 300 val
+ajcihkwhrv 1 241 train
+ajconjiwey 0 300 train
+ajcxyezjol 1 300 train
+ajdegythla 1 301 val
+ajdfnozbhq 1 300 val
+ajdtonmypr 1 300 train
+ajecqizcgt 1 300 train
+ajeegjgyzk 1 300 test
+ajeeslbztj 1 300 train
+ajegzusfqo 1 300 train
+ajehhdwutm 0 300 val
+ajflstmejh 1 300 train
+ajfsxtjyfw 1 300 train
+ajftljwgif 1 300 train
+ajfvjdkxlc 1 298 train
+ajgilbyczx 1 302 val
+ajgmeutnsx 1 300 train
+ajgqualrbi 1 299 train
+ajgukoojpg 1 300 train
+ajgyzbzctg 1 298 train
+ajhezglysr 1 300 train
+ajhffyqnfd 1 300 train
+ajhijalfco 1 300 train
+ajhirhemzi 1 301 train
+ajhmvnssbb 0 300 train
+ajhwgcegtm 1 300 train
+ajiaxscidx 1 300 train
+ajicammobe 1 300 train
+ajicrhwzdw 1 300 train
+ajigkzdkjk 1 298 val
+ajijqswcwv 1 301 val
+ajiljtvzao 0 300 train
+ajintjubct 1 300 train
+ajitbbkjao 1 300 val
+ajiwnpctlh 1 300 train
+ajiyjjalau 1 300 train
+ajiyrjfyzp 0 300 test
+ajizwftxwx 0 300 val
+ajjhhfkoks 1 300 train
+ajjkcbrith 1 300 train
+ajjnueuzlr 1 300 train
+ajkdcjnonp 0 300 train
+ajkfvjrqkh 1 300 train
+ajkomyegdp 1 300 train
+ajkrquvpzn 1 300 val
+ajkrtxwaxf 0 300 train
+ajliunxmwr 1 300 train
+ajljaaphzr 0 300 train
+ajlmtakpmt 1 300 train
+ajlwskvcvo 1 300 val
+ajmeruuzzc 1 300 train
+ajmmfbufil 1 300 train
+ajmqaudgnl 1 300 train
+ajmrksuirh 1 300 val
+ajmtlbipdg 1 300 val
+ajmuljcfkb 1 299 test
+ajmvszeaho 1 300 train
+ajmzpbtjqg 1 300 val
+ajnaarnfdw 1 300 train
+ajnbiohajd 1 300 train
+ajnchhutru 1 300 train
+ajnjrhcgff 0 300 train
+ajnqudtjxe 1 300 train
+ajnsgdlbjk 1 300 train
+ajnysrreuv 1 300 train
+ajnzuiktuo 1 300 val
+ajoogzihog 1 300 train
+ajoqxfuxhi 1 300 train
+ajovkrmjye 1 300 test
+ajowqizwjl 1 299 train
+ajozokmfyd 1 300 train
+ajpasdpkqz 1 302 train
+ajpdmrbnyu 1 300 train
+ajpexmkxej 1 300 val
+ajplbzrmld 0 300 train
+ajpleysqnb 1 300 train
+ajpozojbso 1 300 val
+ajpwtcvoqm 1 300 train
+ajpzditips 1 300 train
+ajqiospyrh 1 300 train
+ajqmtwoocc 1 300 test
+ajqmwoxmjj 1 300 train
+ajqmzuokjb 1 301 train
+ajqqjqkpsr 1 300 val
+ajqslcypsw 0 300 train
+ajqtcvxfad 1 300 train
+ajquhoecmv 1 300 train
+ajqwsgiisn 1 300 train
+ajqykbxhji 1 300 train
+ajrhthktnq 1 300 train
+ajrixmamla 1 300 train
+ajrsotccej 1 298 train
+ajrtkchido 1 299 val
+ajrznbbamg 1 300 train
+ajsijmviwk 1 300 val
+ajsqdnclya 1 300 train
+ajsxndifnu 1 300 train
+ajtbogddxv 1 300 val
+ajtdopmorw 1 300 train
+ajtgkeqmiz 1 300 train
+ajtmgsaocm 1 300 train
+ajtuiopeww 1 300 train
+ajtygxrewl 1 300 val
+ajtziexlkt 1 300 val
+ajuczobjuj 1 300 val
+ajueabvifh 1 300 val
+ajufzvuybv 1 298 val
+ajuqldphwa 0 300 train
+ajusgabgcr 0 300 train
+ajvkjkmhlw 1 299 val
+ajvsdinxzu 1 300 val
+ajvtuefnpi 0 300 train
+ajwajjzhvk 1 300 train
+ajwbewcmwi 0 300 train
+ajwcjycvgr 1 300 val
+ajwegyagtv 1 300 train
+ajwegzsjwr 1 300 train
+ajwfztlkxy 1 300 train
+ajwiijfltt 1 300 train
+ajwpjhrbcv 1 300 train
+ajwqejboet 1 300 train
+ajwwrwdadl 1 300 train
+ajwydwvzvb 1 300 train
+ajxcpxpmof 1 300 val
+ajxcsiiqzw 1 300 val
+ajxfwvzifj 1 239 train
+ajxivketbf 1 300 val
+ajxkpwjgsy 1 300 train
+ajxkvlpgov 1 300 train
+ajxlbvrsni 1 300 train
+ajxmlhcsqa 1 300 train
+ajxmoyqvmj 1 300 train
+ajxpaiqcee 1 300 test
+ajxqmncunn 1 300 train
+ajxuotftix 1 302 val
+ajxzupgmgo 1 300 train
+ajybacpqmc 1 300 train
+ajyexgaimz 1 300 train
+ajygfujjfi 1 300 train
+ajykfwtjeo 1 300 train
+ajyuvxspvx 1 300 train
+ajywrgjetn 1 300 val
+ajywwurjut 1 300 train
+ajyxoxplth 1 300 train
+ajzgxtpvyt 1 300 train
+ajzpdgtigi 1 300 train
+ajzpuemmbg 0 300 train
+ajzretbhgz 1 300 val
+ajzzikvfrj 1 300 train
+akaaoybeeq 1 300 train
+akadwmzzrf 1 300 train
+akalyasdmg 1 300 train
+akaqyxcfep 1 300 val
+akatfxowma 1 298 train
+akaxdmtnod 1 300 train
+akbezffrjx 1 300 train
+akbfafjjyu 1 300 train
+akbkrvrvbs 1 300 train
+akblhteskx 1 300 train
+akbqkjuopj 0 300 train
+akbrklrvhi 1 300 val
+akbwmwqalx 1 300 train
+akbydmnnzd 1 300 train
+akbyzqlris 0 300 train
+akcebajhgd 1 167 train
+akcgfndbvj 1 292 train
+akcijmdkaq 0 241 train
+akcjgnmrfr 1 300 val
+akcmmulzka 1 298 train
+akcnfhxoqh 1 300 train
+akcnpwdjjk 1 300 train
+akcogqlmdd 1 300 train
+akcouuuvpk 0 300 train
+akcwqsnjln 1 240 train
+akcxufnmsr 0 300 train
+akczfbzxye 1 300 train
+akdaowzvvw 0 300 train
+akddowubef 0 300 train
+akdmaezgts 1 300 train
+akdqrdkelr 1 301 train
+akdvkdoyoh 0 300 train
+akefewcntz 1 301 train
+akehbkfpqj 1 297 train
+akeiilpxlx 1 301 train
+akeixdinzr 1 298 train
+akeuqfkrka 1 299 train
+akfjqoantp 1 299 test
+akfostnsgl 1 300 val
+akfoywoqmc 1 300 train
+akfrnoqubc 1 300 val
+akfzfrevcc 1 300 train
+akgiqpwmsv 1 300 train
+akgjhfddug 1 300 train
+akgueokfzl 1 300 train
+akgyesyqkt 1 300 train
+akgyyniqoz 1 300 train
+akhbnmzfce 1 300 train
+akhernogch 1 300 train
+akhfhjgnnv 0 300 train
+akhpyauffl 1 300 train
+akhtxuzreh 1 300 val
+akhuxyqwmb 1 300 train
+akhzndtglc 1 300 train
+akhzyysbyu 1 300 val
+akibmagvog 0 300 val
+akibrounof 1 300 train
+akidxubbcs 1 300 train
+akifdlpibt 1 300 train
+akihstbduv 1 300 train
+akijggepdx 1 300 train
+akitvhevpq 1 300 val
+akjahgkjds 1 300 val
+akjimeoiox 1 300 train
+akjkqsvfzl 1 241 train
+akjmozwnne 1 297 train
+akjumsnpsh 1 300 train
+akjvglpobj 1 300 test
+akkewboafl 1 300 val
+akknskjakh 1 300 train
+akktehfoui 0 301 train
+aklaysonru 1 300 train
+aklmjbjdfq 1 300 train
+akloiiogtc 1 300 train
+aklqzsddfl 1 300 train
+akluvruemz 1 300 train
+aklyvmtbnz 1 300 test
+akmcyevhhf 1 300 train
+akmjvyaxsq 1 300 train
+akmkangqbj 0 300 val
+akmkcxguii 0 300 train
+akmletxfbg 1 300 train
+akmmrizujh 1 300 val
+akmomqwdkg 1 300 train
+akmteetttx 1 300 train
+akmvjzulkz 1 300 train
+akmwivcaly 1 301 train
+aknbdpmgua 1 300 train
+aknblktwhg 1 300 train
+akndeedthv 1 300 val
+akndzxxbai 1 300 train
+aknfvmmkud 1 300 val
+aknlecnjwg 1 300 val
+aknmpoonls 1 300 train
+aknnjyuypy 1 300 train
+aknpmbdksv 1 300 val
+aknrpivxgd 1 300 train
+aknxxagvws 1 300 val
+aknynjmtzb 1 300 train
+akobwqjdqj 1 300 train
+akobxwitbe 0 300 val
+akomkhnosr 1 300 train
+akopuxryho 1 300 train
+akorjvmomz 1 298 train
+akotrfasyc 1 300 train
+akpbyalynb 1 300 train
+akpfvadijp 1 299 val
+akphckavlg 1 300 train
+akpuczgfpk 1 300 test
+akqeamjweg 1 300 train
+akqfgtkqjg 1 300 train
+akqfwqfyck 0 300 train
+akqjhilhtc 1 300 train
+akqtiabugz 1 301 train
+akqynhsfkg 1 300 train
+akrabxcbds 1 300 train
+akrebrefnz 1 300 val
+akrnfldhwy 1 299 val
+akrubjfzzc 0 300 train
+akrwodsyak 1 300 train
+akrwxwwfxw 1 300 train
+akrxrxzvxj 1 300 train
+aksavcfrlk 1 300 train
+aksbjqjcix 1 300 train
+aksipjcmaq 1 300 val
+akskvkssnn 1 300 train
+aksopgeldv 1 301 train
+akstjxliak 1 300 train
+aktagpgviq 1 300 train
+aktakhpugu 1 300 train
+aktdcwdclx 0 300 train
+aktgcyeqeo 0 300 train
+aktiyxayvr 1 300 train
+aktnlyqpah 1 300 test
+aktpkfrkkg 0 300 train
+aktskznnbx 1 300 train
+aktsnujuse 1 300 train
+aktxqigpwt 1 300 val
+akulaikjcg 1 300 train
+akulddirwt 1 300 val
+akupygwxyv 1 300 val
+akvcrttvvo 0 300 train
+akvcvafqwk 1 300 train
+akverwmrdo 1 300 train
+akvifawmqe 1 300 train
+akviyudhhp 1 300 train
+akvmwkdyuv 1 300 train
+akvmwrdseh 1 300 train
+akvpkmrzio 1 300 val
+akvsnzgqrx 1 300 val
+akvvjehikt 1 301 train
+akvvvtlenq 1 300 train
+akvzwvjgxq 1 301 train
+akwavzdiob 1 300 train
+akwjimvvzy 1 300 train
+akwjxjxkjd 1 300 train
+akwmftpuka 1 300 train
+akwudkiamz 1 299 train
+akwzvrzbim 1 300 train
+akxenuzgtp 1 300 train
+akxfepmjje 1 300 val
+akxmjcxhmp 0 300 train
+akxomzlrls 0 300 train
+akxoopqjqz 1 300 train
+akxtsuinpj 0 300 train
+akxvfiuusn 1 300 val
+akxweafppi 1 300 train
+akxztlfsks 1 300 train
+akygxijmgx 1 300 train
+akyhfvfflu 1 300 train
+akyivewdnl 0 300 train
+akyjotmrcu 1 300 train
+akyqowgmwt 1 300 train
+akysuraini 0 300 val
+akyuzdjjvj 1 300 train
+akzaetsbkv 1 300 val
+akzbnazxtz 1 300 train
+akzctljlag 1 300 train
+akzoyfpvfd 1 300 val
+akzqviukav 1 300 train
+alabtogcpi 1 301 train
+aladcziidp 1 298 train
+alahbtxgpb 0 300 train
+alahtpnvyo 1 300 train
+alaijyygdv 1 298 train
+alapuhmete 1 300 val
+alaqopxmhw 1 300 train
+alaxwpwdyb 1 300 train
+albkkvdesw 1 300 val
+albmkgvkhm 1 300 train
+albpcygegi 0 300 train
+albqnixkfe 0 300 train
+alcamnydvt 0 300 val
+alceyaduzi 1 300 train
+alckeawtjp 1 300 val
+alclpnubdd 1 300 train
+alcueoqbnp 1 241 train
+alcvtmyczk 1 300 val
+alcwerhhpu 1 300 train
+alcymltoqb 1 300 train
+aldclwldxn 1 300 val
+alddoocxqo 1 300 train
+aldekovjjt 0 300 train
+aldfjcjeti 0 300 train
+aldiaifkrb 1 300 train
+aldnupmnka 1 300 train
+aldtqwchhe 0 300 val
+aldwkhyqvn 1 300 train
+aldxnorbdp 1 300 train
+alebgijlzb 1 298 train
+aledbhfcdp 1 301 train
+aledotxnmz 1 300 train
+alegsddzzn 1 300 val
+aleiiisdzv 1 300 train
+aleqxjlkzx 1 300 train
+alevzwjovd 1 300 train
+alewdsjvbk 1 301 train
+alexkuuatd 1 302 train
+aleyluvjcv 1 301 train
+aleynhequh 1 300 train
+alezaywuxv 1 300 train
+alfaeujjto 1 300 train
+alfidaevix 1 299 val
+alfjkgcvle 0 300 train
+alfoimlaul 1 300 train
+alfynijsqy 1 300 train
+algcxuxkge 1 300 train
+algkqmxdkj 1 300 train
+algqbygmhk 0 300 val
+algxwpvyde 1 301 train
+alhbidqnrt 1 300 train
+alhckpgigz 1 300 train
+alhqaurncj 1 300 test
+alhqvmlmfm 1 300 val
+alhsvhumdw 1 300 train
+alidbnaydf 1 300 val
+alidfjtwvg 1 300 test
+aligpjcnat 1 300 train
+alihirtwnd 1 300 train
+aliiokxvrj 1 300 train
+aliseomfxz 1 300 train
+aliygnpssy 1 301 val
+aljaxpxbld 1 300 train
+aljcpkltxd 1 300 train
+aljjmeqszq 1 300 train
+aljlvuoosb 1 300 train
+aljukgvthe 1 300 train
+aljxuvmhhy 0 300 train
+aljyahbmje 1 300 train
+aljzaalpym 0 298 val
+alkeuibdtl 0 300 train
+alkhjykzhv 1 300 val
+alkjffcgxb 1 300 val
+alkomvbvah 1 299 test
+alkrmvtqvy 0 300 train
+allbpxjonx 1 300 train
+allbviznsb 0 300 val
+allirrddty 1 300 train
+allzkplefm 1 300 train
+almduxqxkm 0 298 train
+almnilnfyu 0 300 train
+almydpsrum 1 301 train
+almydrosfd 1 300 train
+almyyibgay 0 300 train
+almzobgdyx 1 300 train
+alnfbhzqzr 1 300 val
+alninxcyhg 1 300 train
+alnjvuhzqg 1 300 train
+alnkzqihau 1 300 test
+alnrqrhpru 0 300 train
+alntfrtccp 1 300 train
+alnutckewi 1 292 val
+alnwhmtbub 1 301 train
+alpfdoaihj 1 292 val
+alpffqwsvr 1 300 val
+alpjodptvs 1 300 train
+alpkghdgrv 1 300 test
+alpmztosny 0 301 train
+alqayvaatm 1 300 train
+alqbgeothz 1 300 train
+alqfxbtmlq 1 300 train
+alqiqhnrza 1 300 test
+alqqvruble 1 300 train
+alqywpzmrv 1 300 train
+alrelaahti 1 300 train
+alrhjkhxmn 1 300 train
+alrhucxcnv 0 300 train
+alrhzpzlqt 1 300 train
+alrjjpkdwb 0 269 train
+alrmawyknb 1 298 train
+alrogmblmz 1 300 val
+alrtipudhw 1 300 train
+alrtntfxtd 1 300 test
+alrwmcleus 1 300 train
+alrygoogve 1 300 val
+alrzkjspjq 1 300 train
+alseiqnfnc 1 300 train
+alsxbgfkjb 1 300 train
+alszazjckx 1 301 val
+altdwlxfcx 1 240 train
+altfvrpmxe 1 300 val
+altjczdlke 0 300 train
+altmlofkol 1 300 train
+altqelkpqj 1 301 train
+altsldzvrj 1 300 train
+altttvjaxx 1 301 train
+altziddtxi 1 300 train
+alumxqbzxq 1 300 val
+alunjceitn 1 300 train
+alunlwxvze 1 300 train
+alunmxhkda 1 300 train
+aluuzmuqui 1 300 val
+alvbydoswv 1 300 train
+alveuecehk 1 300 train
+alvfitjuip 1 300 train
+alvgwypubw 1 300 train
+alvhfkvgbf 1 300 train
+alvqhgaeeu 1 300 train
+alvtwidqgx 1 300 train
+alvtzfofgl 1 302 val
+alvymawvku 1 300 train
+alwawapjwq 1 300 train
+alwucscsaa 1 300 val
+alwygsjrlx 1 301 val
+alxffdisev 1 299 test
+alxhjctmkg 1 300 train
+alxiptcihe 0 300 val
+alxodlppci 1 300 val
+alxpnosgtc 1 300 train
+alxqyjhmzd 0 300 train
+alxwnuxjay 1 300 train
+alxycxkrsn 1 255 train
+alxyuchmzs 1 300 train
+alxzfebwcx 1 300 train
+alybjlhtmt 1 300 train
+alydrjsvkp 1 300 train
+alygipvchi 1 300 train
+alynbvvaar 1 300 val
+alypwytrnl 0 300 train
+alysxtkgdg 1 300 train
+alytallqyo 1 300 train
+alyxaywfsy 1 300 train
+alyxfsgfab 1 300 train
+alzajhomle 1 300 train
+alzbizkswy 0 300 train
+alzoglbicl 1 300 train
+alzqhxzuoe 1 300 val
+alzrreiirg 1 300 train
+alzsiirjyn 0 300 train
+alzstbwuva 1 300 train
+alztvbchpc 1 300 val
+alzzepufil 1 300 train
+amaafjqfpi 1 300 val
+amaivqofda 1 300 train
+amapzzdqse 1 300 train
+amazjgvfbg 1 300 val
+ambabjrwbt 1 300 val
+ambfrhxhxr 1 301 train
+ambipnlmhm 0 300 train
+ambmklrhtt 1 300 train
+ambqrofozt 1 241 train
+ambzbconcm 1 300 val
+amcdrvwwfg 1 300 train
+amcdtdvtsy 1 300 train
+amckcjeoee 1 300 train
+amcocxjkel 1 300 val
+amcqsjsxqh 1 299 train
+amczvybpav 1 299 test
+amdflcvyaf 1 300 train
+amdkokqlfq 1 300 train
+amdkufnsyw 0 300 train
+amdlrymezn 1 300 train
+amdnvezdcv 1 300 train
+amdoecgegz 1 300 train
+amdomkmlov 1 300 val
+amdrqfyqgr 1 300 train
+amdsocyvfq 1 300 train
+amdtapdkzk 1 300 val
+amdtcpqcjf 1 300 train
+amdwgzzsfb 0 300 train
+amecqqixzs 1 300 train
+ameddrsrnu 1 301 val
+amedqjisns 1 301 val
+amewrciygw 1 300 train
+amexfpxjzt 1 300 val
+amfchgtqzz 1 300 train
+amfdaqjcyv 0 300 val
+amflyomuqj 0 300 train
+amfwnbxwoe 0 300 val
+amgcpdpnjh 1 300 train
+amgcrtdght 1 241 train
+amgdymqkkk 1 301 train
+amgffqquxp 1 300 train
+amggfklief 1 300 train
+amgmmshjzb 1 240 train
+amgskfqrbv 1 300 train
+amgvrxpnsj 1 300 train
+amgwepdksz 1 300 train
+amgwvgswlu 1 300 train
+amhaovcmkc 0 300 train
+amhcxuibrs 1 300 val
+amhgvetood 1 300 val
+amhjubjncc 1 301 train
+amhtkqfdjy 0 300 train
+amiirbmexw 1 300 train
+amioukxobk 1 297 train
+amiqkliwtf 1 300 train
+amirbxjvjn 0 300 train
+amirwsdztp 1 300 train
+amivrvwesd 1 300 train
+amjcqpuper 1 300 train
+amjewwiciv 1 300 train
+amjockwral 1 300 train
+amkaqehlum 0 300 train
+amkfnazvpm 1 298 train
+amkhfybfxf 1 300 train
+amkqhexhou 1 300 test
+amkrhiojmr 1 301 val
+amkrlocunq 1 298 train
+amkvbktnmb 0 300 train
+amlczlfmph 1 300 train
+amljqllcwj 0 300 train
+amlkmjcbsg 1 301 train
+amllysholf 1 301 val
+amluexcfvi 1 300 test
+amlxclbtvg 1 300 train
+amlxxdddxe 1 300 train
+ammcdfkxfl 1 300 train
+ammfmzaied 1 300 train
+ammjmqtbdo 0 300 train
+ammkabwonw 1 301 val
+ammkzaigsj 1 300 train
+ammowfdpae 1 300 test
+ammrscubkm 1 300 train
+ammsbhroun 1 300 train
+amnewwygcj 0 300 train
+amnlztdajc 0 300 train
+amnnindvzc 1 301 train
+amnquvnmaz 1 300 val
+amnwdrjcsc 0 301 train
+amnwvwrzaa 1 300 train
+amnwvylsvo 1 300 train
+amnzjdtmtg 0 300 train
+amobcvwkgm 1 300 train
+amocgevapl 1 300 train
+amoklvhphe 1 300 val
+amooumaljz 1 300 val
+amowujxmzc 1 300 train
+amoyritjif 1 83 train
+ampejireoy 0 300 train
+ampfdjosot 0 300 train
+ampiisxhzf 1 300 train
+ampkadeccx 1 300 train
+amplczvnhf 1 301 train
+amptorfnua 1 300 val
+ampuawncsg 0 300 train
+ampulwpzat 0 299 train
+ampwuteugc 1 300 train
+ampyystebb 1 300 val
+ampzchmgvj 1 299 val
+amqaearxwx 1 300 val
+amqvxdixtf 0 300 train
+amqzejrrfp 1 288 train
+amrncajpkv 1 298 train
+amrryjxojv 1 241 train
+amsayptvlg 1 249 train
+amsgshcdrt 1 300 train
+amskocwiil 1 300 train
+amslrtushh 1 99 train
+amsqbtaqxr 1 300 train
+amsrzsvcij 1 300 train
+amssxswwxf 1 300 train
+amswidgjne 1 300 train
+amtgdnicfd 0 300 val
+amtgkepkbz 1 300 train
+amtlkbydwn 1 301 val
+amuazeqiyx 1 300 train
+amuimlumpi 1 300 train
+amujoiikax 1 300 train
+amukqwhssg 1 300 train
+amumyipktv 1 300 train
+amusfjcxxf 1 300 train
+amusnzgrcw 1 300 train
+amuwroyteu 1 300 train
+amuxmdthkv 1 300 train
+amvaxwoezt 1 300 train
+amvhbsiwou 1 241 train
+amvnlxbjdl 0 300 train
+amvqosiiin 1 300 val
+amvskovhei 1 300 train
+amvvmpoytv 1 300 val
+amvwelsift 1 298 train
+amvydakvli 1 300 val
+amwipjlkbo 1 300 train
+amwjdtnprx 1 299 test
+amwmnvuftj 1 300 train
+amwqklteuh 1 300 train
+amxeybwksq 1 301 train
+amxtgpskys 1 300 train
+amxuvbrmfj 1 300 train
+amxyapzweu 1 300 val
+amxydsazqr 1 300 train
+amynzwwqab 1 300 train
+amytmwaidt 1 300 train
+amzfqufrpe 0 300 train
+amziikrisc 1 300 val
+amzisjppsy 0 300 train
+amzjseksco 1 300 train
+amzkbxslyy 1 300 train
+amzlsaeqee 1 300 train
+amzrqwbvqq 1 300 train
+amztmezqgh 1 296 train
+amzwdwizqu 1 303 train
+amzwfotmig 1 300 train
+anaagxljms 1 300 train
+anabrzfjqr 1 297 val
+anabubgrud 1 270 train
+anaohxgahc 1 300 train
+anaplgkyjr 0 300 train
+anaykjgpmk 1 301 train
+anayzmxgnp 1 300 train
+anbirbqecs 1 300 val
+anbkhkungt 1 300 train
+anbnrrbyac 1 301 train
+anbqevfkhz 1 300 train
+anbqncdiej 1 300 val
+anbswjhddl 1 299 test
+anbtdrguum 1 301 val
+anbteaeopm 1 300 train
+ancqcufdpe 1 300 train
+ancueyumhc 1 300 val
+andaxzscny 1 300 train
+andbprkaoz 1 300 train
+andcosjluf 1 300 train
+andilxvwob 1 300 val
+andlgdcxdr 1 298 train
+andnipfbgy 0 300 train
+andtikykcc 1 301 train
+andzbwhpem 1 300 train
+aneclqfpbt 1 300 train
+aneiwfhzlo 1 300 train
+anewicpmkd 1 300 val
+anfioxzeci 1 300 train
+anfktfudqe 1 300 val
+anfoyjmwoz 1 299 val
+anfupdhmyr 1 300 train
+anfwfhudlp 1 300 train
+angajnjmxi 1 300 train
+angerpqrqg 1 300 train
+anglrrmdnf 1 300 val
+angokkehzt 1 300 train
+angqjpzdts 1 301 train
+angsnihzxk 1 300 train
+angygvuwwn 1 300 train
+angykfhbxq 0 300 train
+angzvssnlr 1 300 train
+anhfrtswmh 1 241 train
+anibubncor 1 300 val
+anicocfvge 1 300 val
+anidyjcrxw 1 302 train
+aniescivbi 0 300 train
+anijjqtfth 1 288 train
+anijlxqwza 1 300 train
+anikhdvdzo 0 300 val
+anitiqaike 1 300 train
+anjajlmrio 1 300 train
+anjcivvdyd 1 300 train
+anjgxkikea 1 300 val
+anjjzyvvlq 1 300 train
+anjlmqmuaj 1 300 train
+anjlxbnxpo 1 300 train
+anjvkhdrua 1 300 train
+anjzjprypc 1 300 val
+anjzzdyhno 0 300 train
+ankeipmksk 1 300 train
+ankjbrbtlc 0 300 train
+ankjkezbvp 1 300 train
+ankkfzsaoz 1 300 val
+anklylpjpm 1 299 test
+ankmajjnml 1 300 val
+ankmhqwytc 1 300 train
+ankndwoptl 1 300 train
+ankuuhvmou 1 300 train
+ankybccavg 1 300 train
+ankyspxepw 1 300 val
+anldmbjxxt 1 300 train
+anlikuimks 1 300 train
+anlpfbokfn 1 300 train
+anlrtolnqx 1 298 val
+anlrxdxsel 1 300 val
+anmgkhxucm 1 300 val
+anmmkrlmyo 1 298 train
+anmonywvkk 1 300 train
+anmqqumghf 1 300 val
+anmvjylile 1 300 train
+anmzhupzpa 1 299 val
+anmzsfpcog 1 300 train
+annaogdkfj 1 300 train
+annbzfzydr 1 300 val
+anndvqgoko 0 300 train
+annedquvkt 1 300 train
+annjwjgecd 1 300 train
+annkrurnzl 1 300 train
+annmtetkqa 0 300 val
+annrepersn 1 300 val
+annsmfhdgk 0 300 train
+annxqhdget 1 300 train
+anodbxmpne 0 301 train
+anoehnostw 1 300 train
+anokulqnvk 1 300 val
+anoqhafhck 1 300 val
+anorupqpeo 1 300 test
+anpfejqjdv 1 300 train
+anpmcremfh 1 300 train
+anpptpyvxe 1 300 train
+anprtlsfhl 1 300 train
+anpuvshzoo 0 300 train
+anqblwkoca 1 300 train
+anragapsxa 1 300 val
+anrbakxalf 0 300 train
+anrcuqghaj 1 300 train
+anrerutgdg 1 300 val
+anrglokmco 1 300 train
+anrgplirit 1 300 train
+anrjzhvztj 1 298 train
+anrlivgkfq 1 300 train
+anrmtvgmjo 0 300 train
+ansbricyzg 1 301 val
+ansbtntiqu 1 300 test
+ansipdckmu 1 301 train
+ansisdzvof 1 300 train
+ansoiwvrqm 1 300 train
+ansvozgmlt 1 300 train
+ansztvbavn 1 300 val
+antctpaqje 1 300 val
+antlihmfhm 1 300 train
+antlqjchwn 0 300 train
+antppuznjo 0 300 train
+antpydooxs 1 300 train
+antryhqazg 1 300 train
+antzbewqab 1 300 train
+anuccdjfab 1 298 train
+anukjnkojh 0 300 train
+anukptetbd 1 241 train
+anunyoghdg 1 300 train
+anuwikwvow 1 300 train
+anuzdiqqnq 1 300 test
+anvbwbcwiq 1 300 val
+anvcjtwiwr 1 298 train
+anvdxkymap 1 298 train
+anvjqfsmcr 1 300 train
+anvlfhrwpv 1 300 train
+anvoqxldcw 1 300 train
+anvpnzrtjj 1 300 train
+anvwvdqpvx 1 300 train
+anvyvvwwga 1 300 train
+anvzovvyug 1 300 train
+anwbliivax 1 300 train
+anwdknkpod 1 300 train
+anwecotwou 0 300 train
+anwgwhqtif 0 300 train
+anwjjhmbqt 0 300 train
+anwjldncaz 1 300 val
+anwktisyiw 1 298 train
+anwlwxwgeu 1 300 train
+anwmviccyx 1 300 train
+anwoglxucl 1 300 train
+anwrkkclze 1 300 train
+anwtfblvbr 1 300 train
+anwxwllvfg 1 300 train
+anxbbarnzx 1 300 train
+anxbywwrkc 1 300 train
+anxeqgmacn 1 300 val
+anxfbbowrq 1 298 train
+anxfnwkhfa 1 300 train
+anxhzsdtlq 0 300 train
+anxteqfazk 1 300 val
+anxvyqrknq 0 300 train
+anxzivnfhd 1 300 train
+anyaaehmeo 1 249 train
+anyazgcfjn 1 298 train
+anycsvryvs 0 300 train
+anydimkkek 1 300 train
+anyeaafmht 1 300 train
+anyhkuudjx 1 300 train
+anyndrbpju 1 300 val
+anyqmaqcrm 1 298 train
+anytvmbxsa 1 300 train
+anzbihnxvv 1 298 train
+anzenqcwqo 0 300 train
+anzeymmqaa 1 300 train
+anznjoyqhx 1 300 val
+anznojhdjf 0 300 val
+anzofmtmuv 1 300 train
+anzukkbyvj 1 300 train
+anzvpnfizi 1 300 val
+anzwccijbl 1 300 train
+anzwilyepx 1 298 val
+anzylmbqgi 1 300 test
+anzzvkouxv 1 300 train
+anzzyvnoqk 0 300 train
+aoabmfspkv 0 300 train
+aoahphnoed 1 300 train
+aoaigusywb 1 300 train
+aoallgteyc 1 300 test
+aoamhavbyb 1 300 train
+aoaqpznmgn 1 300 train
+aoayayeqji 1 300 test
+aobitdtyus 1 297 val
+aobjpeeevc 1 300 train
+aobkcgrtpc 1 300 train
+aobqaxxpom 0 300 train
+aobtgscxxu 1 300 train
+aobvgofepj 1 300 train
+aobzfbmpop 1 300 train
+aockokzwyb 1 300 train
+aoclawrydd 1 299 val
+aocmypzdsw 0 300 train
+aodczfleto 0 300 val
+aodgtudnun 1 298 val
+aodheokfzn 1 300 train
+aodijlfnur 1 300 train
+aodjxpwsng 1 300 train
+aodljytxgs 1 300 val
+aodpwamaqd 1 300 train
+aodqhsxdgk 1 300 train
+aodqmfpuhg 0 241 train
+aodrcrvodk 1 301 train
+aodscsqoyc 0 300 train
+aodwixxwxl 1 300 val
+aoegtmsbnc 1 300 train
+aoenoacoqc 1 300 train
+aoeoxkueop 1 147 train
+aoepmomsuc 1 300 train
+aoeqicimca 1 300 train
+aoerwwhwwt 1 300 train
+aoerxokasa 1 300 train
+aoeuvrhatp 0 300 train
+aoevmbkult 0 300 train
+aofijxylul 1 300 train
+aofjdfbvsf 1 300 train
+aofpyyamme 0 300 train
+aofqqeiisz 1 300 train
+aofrdmqnya 1 300 train
+aofuhtnouj 1 300 train
+aofwudrvjp 1 300 train
+aogedidtxq 1 300 train
+aogehznslq 0 300 train
+aogeoiljkt 1 300 train
+aogfdkxaco 1 300 train
+aogfeuvjji 1 300 train
+aoghrxfjyg 1 300 train
+aogsgxgjij 1 300 train
+aogwcxcdcv 1 300 val
+aogzzemcnc 0 300 val
+aoheasapsh 1 300 train
+aohefebobr 1 300 train
+aohpayeuus 1 301 train
+aohtixcgqk 1 300 train
+aohxiyjceo 1 300 train
+aoiejhrhmt 1 300 train
+aoifhudyzh 1 300 train
+aoigsecafe 1 300 train
+aoisgtrmgh 1 300 train
+aojaayykzy 0 300 train
+aojabqhgsp 0 300 val
+aojlfcewvk 1 300 train
+aojnhartqb 0 300 train
+aokalwxzig 1 300 train
+aokaxzbxfz 1 301 train
+aokdhxatmf 0 300 train
+aokgqgryat 0 300 train
+aokhuioyqh 1 300 val
+aokhvkoynm 1 300 val
+aokrlamaci 0 300 train
+aokxvqadsx 0 300 test
+aokzecrsqk 1 300 train
+aokzigplme 1 300 train
+aolbdipqql 1 300 train
+aolggfbtcq 1 300 val
+aolhuwcdwv 1 300 train
+aoljvrxdyb 1 300 val
+aolojigpmv 0 300 train
+aolttdkcxv 1 299 train
+aolvemvlnz 1 241 train
+aolxazqxjm 1 300 train
+aomdezxgzc 1 300 train
+aomhbqppxn 1 300 train
+aomilychlk 1 299 train
+aomkpavswk 1 300 train
+aomnodsnlh 1 300 train
+aomowspatw 1 300 train
+aomqqjipcp 1 299 test
+aomsgdgpxh 1 300 train
+aomsunroqu 1 300 val
+aomuwheldb 1 300 train
+aonaupzilc 1 300 val
+aonccmcgrh 1 300 val
+aonfdzjsem 1 300 train
+aonggfzbxc 1 301 val
+aonnkacpmr 1 300 train
+aonprngsys 1 300 train
+aonrwsdqqn 1 297 train
+aoobxuqbla 1 300 train
+aopfmwmlrp 1 298 train
+aopgandqma 1 241 train
+aopirydans 1 300 train
+aopmnxolci 1 300 train
+aopnftmaex 0 300 train
+aopvrfrydo 1 300 val
+aoqbcjoqjh 0 300 train
+aoqkifqtit 1 300 train
+aoqscfomec 1 300 train
+aoqzxlwvmi 0 300 train
+aordhrhhun 1 301 val
+aorhjnequr 1 300 val
+aorivlamxj 1 300 val
+aorjvbyxhw 1 300 train
+aorwnetwso 1 300 train
+aosaxorzoe 1 300 train
+aosburdumj 1 300 val
+aosbztrrkw 1 300 train
+aosizimfzi 1 300 train
+aoslehqsra 1 301 val
+aosmlwbjrc 1 300 train
+aosnzkbllm 1 300 test
+aosonazrhc 1 300 train
+aosovymqjf 0 300 train
+aoszdeayes 1 300 train
+aotqqslzby 1 300 train
+aououvkimi 1 301 train
+aourvgckjw 1 300 val
+aouzlroqzt 1 300 train
+aovbctixqc 0 300 train
+aovdrmcokm 1 300 train
+aovipufpkc 1 298 train
+aovjmdvxfj 0 300 val
+aovjyvaqrp 1 300 train
+aovmgbaadn 1 300 val
+aovnhgjhpe 1 300 train
+aovrlwlzpr 0 300 train
+aovruftlxk 0 300 train
+aovskzsqqy 1 300 train
+aovxvsgkmm 1 300 train
+aowfzwayqs 1 300 val
+aowiffcqxa 1 300 val
+aowpwesmxa 1 301 val
+aowxewvrei 1 300 val
+aoxcttbsju 1 300 train
+aoxdrgewie 1 300 train
+aoxjbzqjey 1 300 train
+aoxjeneofv 1 300 train
+aoxklyybdv 1 300 train
+aoxltdxgll 1 300 train
+aoybdbmisp 1 300 train
+aoydavjcbz 0 300 train
+aoydktojny 1 300 test
+aoyiirhvef 1 300 train
+aoykobzmld 0 300 train
+aoyoopetdx 1 300 train
+aoyvghuegg 1 300 train
+aoyxjtoqhg 0 300 train
+aozinftsyr 1 300 train
+aozjqlpvob 1 300 val
+aozliqzela 1 300 train
+aozrrvrbpa 1 300 train
+aozvkebfza 1 300 train
+apahohbfek 1 300 test
+apanophovl 1 301 train
+apansjedym 0 300 train
+apaoqcfyml 1 300 train
+apasrbjbwu 1 300 train
+apatcsqejh 1 300 train
+apaubiovvf 1 302 train
+apauourorl 1 269 train
+apavbchjbq 0 300 train
+apavbvmxrb 1 301 val
+apaxorirnn 1 300 train
+apbidtmyvm 1 300 train
+apbjpqiswq 1 300 train
+apbshbhgvi 1 298 train
+apbtqpxkpt 0 298 train
+apbuihspri 1 300 val
+apbvarwxli 0 300 val
+apcbgfhlos 0 298 train
+apccpwzdpc 1 300 train
+apcjdaqzwa 1 300 val
+apcntjhkdg 1 300 train
+apcqyakznt 1 302 train
+apcrjhkztt 1 300 val
+apcwcrklwh 0 301 train
+apdddkutje 1 300 train
+apddumqkmt 0 300 train
+apdfykbltf 1 301 train
+apdiebssyz 1 298 train
+apdiifzjbg 1 300 val
+apdjhhsfnd 0 300 train
+apdkicnuoo 1 300 train
+apdmamltet 1 301 train
+apdowqkvix 1 300 train
+apdyhzvvtm 1 300 train
+apedduehoy 0 300 test
+apeeelwdlp 1 300 train
+apeftlgrqg 0 300 train
+apejxbkiwr 1 300 train
+apfajdzoym 1 300 train
+apfcpcyonw 1 300 train
+apfcvqlcxh 1 300 val
+apfdcxttpz 0 300 train
+apfgnkqiks 1 300 val
+apfkqaeruh 1 300 train
+apfowundmc 0 297 train
+apfpxxeynw 1 300 train
+apfribzdle 1 300 train
+apfwbpnetp 1 136 train
+apfwukzcvd 1 300 train
+apfxpspodv 1 298 train
+apgbfczjzd 1 300 train
+apgbzciuhr 1 300 train
+apgcndzthg 1 302 train
+apgjqzkoma 1 300 train
+apgncdjuzj 1 301 val
+apgnyspnps 1 300 train
+apgogdhmzd 0 300 train
+apgqgxqcbh 1 300 val
+apgqqohtno 1 300 train
+apgwlpvvwt 1 300 train
+apgxbcqpko 1 300 train
+apgzndtbsz 1 300 train
+aphbjcscfn 0 300 train
+aphkfbthpz 0 300 train
+aphwcjltag 1 300 train
+apifduvjkm 0 300 val
+apifhdspiu 1 300 train
+apihcvvotj 0 300 train
+apikmyjdkq 1 300 train
+apipdqlref 1 300 train
+apipmssjnl 1 300 train
+apirqsqrlz 1 301 val
+apitkovnzh 0 297 train
+apjapqdjiz 1 300 val
+apjeecbaep 1 298 val
+apjktzsawg 1 300 train
+apjovfzzft 1 300 train
+apjycnnpfi 0 300 train
+apkjagmcvz 1 298 train
+aplfgrenfv 1 300 train
+aplpvrtvce 1 300 train
+aplropqehb 1 300 train
+aplurzejra 1 300 train
+apmfozguat 1 298 train
+apmklfemrw 1 297 train
+apmolxkrhv 1 300 val
+apmowtywei 1 300 train
+apmoyovxid 0 300 train
+apmytvgnaj 1 300 train
+apmzxocjio 1 300 val
+apnaakewce 1 241 train
+apnbrekjfa 1 300 train
+apnccudltb 1 300 train
+apnluiftyn 1 300 train
+apnocyhfhv 1 300 train
+apnoooowog 1 300 train
+apnwnfjyfy 1 300 train
+apnywjnnii 1 300 train
+apobfcukea 0 301 train
+apofytyhxk 1 300 train
+apogckdfrz 1 300 train
+apojgziubj 1 300 train
+apowswlyzi 1 300 train
+appnpveszq 1 300 train
+appqklflsu 1 301 train
+appvffejyy 0 300 train
+appxeagkwm 0 300 train
+appyopevdd 1 300 train
+apraruuhhu 1 300 train
+aprcmkybrl 1 301 train
+apregrciyy 1 300 train
+aprggysaph 1 300 train
+aprgtqcqda 1 300 train
+aprjugtgdv 1 296 train
+aprkqcworu 1 300 train
+aprnseeewu 1 240 val
+aprqxvgtgg 1 300 train
+aprrfrmjmn 1 300 train
+aprtfacuwr 1 300 val
+aprylcdijv 1 300 train
+apsctogzhy 1 269 train
+apscureryf 1 298 train
+apscwnwndu 1 301 train
+apsjgjohkd 1 300 train
+apslrfwtwa 1 300 train
+apslynneqq 1 300 train
+apssnaoipi 0 300 train
+apswbbedxn 1 300 train
+apsylyknjy 1 300 train
+aptjgrmarh 1 300 train
+aptqllaawb 1 241 train
+apttmhpmps 0 300 val
+apufeoakpj 1 300 val
+apulnkmpfw 1 300 train
+apunyeesae 1 300 train
+apurdoxoea 1 300 train
+aputskujlt 1 300 train
+apvdpwusfq 1 299 train
+apvhgeulvy 1 300 train
+apviayggyq 1 300 train
+apvjguamcy 1 297 train
+apvktqqhcq 1 300 train
+apvmchmcbm 1 300 train
+apvrmkvqza 1 300 train
+apvtngotvd 1 300 train
+apvuoexpux 1 298 train
+apvzeefhog 1 300 train
+apvzjkvnwn 0 300 test
+apwdamyjbw 1 300 val
+apwkowqngy 1 300 train
+apwlboftdx 1 300 train
+apxabvufkh 1 300 train
+apxadyoyum 1 300 val
+apxcatgxts 1 300 train
+apxgvdrjkv 1 300 val
+apxmimownx 1 300 train
+apxrqexuvg 1 300 train
+apycffuwrg 1 300 val
+apynffhluo 1 300 train
+apyqfiouvw 0 300 train
+apyrdjelvu 1 300 val
+apyxwaxfps 1 300 val
+apyzikguhs 1 300 train
+apzcbdmlux 0 300 train
+apzckowxpy 1 300 test
+apzlacqgnz 1 300 train
+apzltxnnfe 1 300 train
+apzoewmtdf 1 300 train
+apzrphtzys 0 300 train
+apztusvlxo 1 83 train
+aqakglyrht 1 300 train
+aqaoadlzlh 1 300 train
+aqaqgzihfa 1 300 train
+aqbcsxrsjx 0 239 train
+aqbjrrxuys 0 300 train
+aqbkbgwgrd 1 300 val
+aqcajigjfm 1 300 train
+aqcbfjaqaw 1 300 train
+aqceybxdso 1 300 train
+aqcmloehdh 1 300 train
+aqcmtcybpq 1 300 train
+aqcmzudorm 1 300 train
+aqcqygyoae 1 300 test
+aqdbtqggew 1 299 test
+aqdcrtujap 1 297 train
+aqdgarsevm 0 300 train
+aqdkgdinvb 1 301 train
+aqdnmfsdaw 1 300 train
+aqdybczyag 1 300 train
+aqediprrpp 1 300 train
+aqeecyhmzd 1 300 val
+aqegtqxxdj 1 300 val
+aqejlaudtq 1 299 test
+aqemytasjc 1 297 train
+aqeukjoshi 1 300 train
+aqfeqkckjs 1 300 train
+aqfhydprgp 1 301 train
+aqfimhexfc 1 300 train
+aqfjgahafl 0 300 train
+aqfknwdsjr 1 300 train
+aqfnbkwyct 1 301 train
+aqfnfsbqft 0 300 train
+aqfqabvgdz 1 300 train
+aqfrvqkwrm 1 301 train
+aqfytexxbl 0 300 train
+aqgackolpd 1 300 train
+aqgbewikxk 1 300 train
+aqgblamujg 1 300 train
+aqgbmtoekh 1 300 val
+aqgjounhqv 0 300 train
+aqgkloqxld 1 300 train
+aqgocqgpqp 1 299 val
+aqgwyuaijx 1 300 train
+aqhaqkqbsn 1 300 train
+aqhbszcpal 1 300 train
+aqhlpyacll 0 300 train
+aqijshghnp 1 300 train
+aqipkezofh 1 300 train
+aqirevafst 1 300 train
+aqiwuvxump 1 298 train
+aqixjqhycr 1 300 train
+aqixnwknzx 1 300 train
+aqjjfkydvf 1 300 val
+aqjpwskcci 1 300 train
+aqjtpksesv 0 300 train
+aqjvidhoof 1 300 train
+aqjvubdrum 1 300 train
+aqjwkkbklt 0 299 val
+aqjyeirrlv 1 300 val
+aqjzqcfosw 1 300 train
+aqkbphifub 1 300 train
+aqkvqvmxta 1 300 train
+aqkxylfqqc 1 300 train
+aqlfwgrjbg 1 300 train
+aqlwusgzbf 0 300 val
+aqmaowgukh 1 300 train
+aqmbbmicfa 1 300 val
+aqmcwutiej 1 300 train
+aqmdamzkzw 1 300 train
+aqmdrnrunl 1 300 train
+aqmwdyjfwp 1 298 val
+aqmwurythp 1 300 train
+aqmxsdujjy 1 300 val
+aqmydibivi 0 300 train
+aqmzquqqzi 0 300 train
+aqnfrdbsia 1 300 train
+aqnmhettxn 0 300 train
+aqnrvwmqbt 1 300 train
+aqnufuvgiq 0 301 val
+aqnycyaehg 1 300 train
+aqoaolvbwr 0 300 val
+aqoeyjsnzr 1 300 val
+aqogxmeouy 1 241 train
+aqohpjvfhd 1 300 train
+aqoiohqcbj 1 300 train
+aqoisweguz 1 300 train
+aqooxilfzc 1 300 train
+aqozyybzlr 0 300 val
+aqpcbawfuc 1 300 train
+aqpfnbapix 1 301 train
+aqpgiwkfuc 1 300 val
+aqpjdjnvky 0 300 train
+aqpkscpngc 1 300 train
+aqpnvjhuzw 1 300 train
+aqpqvoempp 1 300 train
+aqqaabjicv 0 300 val
+aqqcoedhcc 1 301 train
+aqqijubtsr 1 300 train
+aqqkokuaar 1 300 train
+aqqnrypxni 1 300 train
+aqquulzxpp 1 300 train
+aqrejgepnk 1 298 train
+aqrliqhxsg 0 300 train
+aqrlsoytmq 0 300 train
+aqrodorsgz 1 299 test
+aqrrlckvdc 1 300 train
+aqrsylrzgi 1 299 test
+aqrzuafttg 1 300 train
+aqsbgbnidp 1 300 train
+aqsfifolvi 1 300 val
+aqsgzoxyok 0 300 train
+aqshzvyucn 0 300 train
+aqsjhodxqh 0 300 train
+aqsnonrndh 0 300 train
+aqsoyqygky 0 300 train
+aqsrbioktt 1 300 train
+aqsvjezuyq 1 300 train
+aqszhxrxbr 0 300 train
+aqtavzvdbv 1 300 train
+aqtilihxfl 1 300 train
+aqtpexaamb 1 300 train
+aqtqirjyam 1 298 train
+aqtrrqlrpt 1 300 train
+aqtvsxelrj 1 300 test
+aqtwaoeacu 1 300 train
+aqtypfezoi 0 300 val
+aqtzwfnnyo 1 288 train
+aquablfftp 1 241 train
+aqubhmutxz 1 300 train
+aqufcpfqnd 1 300 val
+aqugzakufj 1 300 train
+aqujarjclk 1 300 train
+aqujbitkrd 1 300 train
+aquooykzmc 0 300 train
+aqupehtqiv 1 300 train
+aqvaysmpzk 0 300 val
+aqviuapbyq 1 300 train
+aqvjwcnmgn 1 300 val
+aqvmhgbuhy 1 300 train
+aqvowsdlld 1 300 test
+aqvpagjeub 1 299 val
+aqvpggzkmz 1 300 val
+aqvpyzhbbt 1 249 train
+aqvqaqtkll 1 300 train
+aqvsciajos 1 300 train
+aqvykkximk 1 300 train
+aqvywunszy 1 300 train
+aqwdwiatyk 1 300 train
+aqwfpoewqb 1 300 val
+aqwfxoqtqu 1 300 train
+aqwiiugduy 1 300 train
+aqwjzvgeil 1 300 train
+aqwrjomvmp 1 300 train
+aqwveuizkr 1 300 train
+aqwvusskie 1 301 train
+aqwyabxema 1 298 train
+aqwziiggkr 0 300 train
+aqwzxjooxl 1 300 train
+aqxbpnwoyu 1 300 train
+aqxdxumyia 1 300 val
+aqxfsfafus 0 300 train
+aqxjysinmy 1 300 train
+aqxqtiahts 1 301 train
+aqxsrqecfh 1 300 train
+aqxvhhbtib 1 301 train
+aqybwsiyfy 1 300 train
+aqyemwessu 1 300 train
+aqymrqseqg 0 300 train
+aqyqaqjvkr 1 300 train
+aqyvunegbf 0 301 train
+aqywnbekqk 1 300 val
+aqzbhxohjk 0 300 val
+aqzbjebvhu 1 300 train
+aqzgpmlynd 1 300 train
+aqzkiwfvlv 0 300 train
+aqzssoizgs 1 300 train
+aqzuimqyjq 1 300 val
+aqzwjwqwuq 1 300 train
+araastjfym 1 300 train
+arafzhoqil 1 300 val
+aralaxkuwf 1 300 train
+aramdcfxhn 1 300 train
+araoplrpeb 1 300 test
+arasptnvme 1 300 train
+arawwqrgxr 1 300 val
+arbeiwacbk 1 300 train
+arbezwqjhr 1 300 train
+arbljycfpx 1 300 val
+arbtkzqayi 1 300 train
+arccwzfwkm 0 300 train
+arcdokvebk 1 300 train
+arcigchzav 1 300 train
+arciuacdpu 1 298 train
+arcrbzosjg 0 300 train
+arcviozhqq 1 300 test
+arddblqgxh 1 300 val
+ardfibzljb 0 300 train
+ardijxbxdm 0 300 train
+ardkbqszob 1 300 train
+ardklpwgds 1 300 val
+ardmfelhgw 1 300 test
+ardnhgxcuo 1 302 train
+ardqnhfkoj 1 300 train
+ardrvtazjs 1 300 val
+ardthlteap 1 300 train
+arebkvnjtb 1 300 train
+areepskxqp 1 241 train
+arefghfwhj 1 300 train
+arelembybp 1 300 val
+aretpmdutp 0 300 train
+aretvijthh 0 300 train
+arfdnjtlop 1 300 train
+arflgfcnkg 1 300 train
+arflkzattc 0 300 train
+arfpvtvavs 1 300 train
+arfqjhbpax 1 300 train
+arfsazswhs 1 301 train
+arfxxftkqg 1 299 val
+argcsfhvjf 1 300 train
+argfibbhsp 1 300 train
+argpgzyddc 1 300 train
+argpsumnze 1 297 train
+argxbsvrps 1 300 train
+argyuhgbqe 1 300 train
+arhbstyqkw 1 300 train
+arhcwdubjd 1 300 val
+arhmeydaqw 1 300 val
+arhxaejjgk 1 300 train
+ariavigzqu 1 300 train
+aribmktfkv 1 298 train
+arijyrjuzh 1 300 train
+arilrepvkj 1 299 train
+arimuztful 1 300 train
+aripxkdlsd 1 300 val
+ariulacfco 1 300 train
+arixtqglae 1 300 train
+arjcsmmjpv 1 300 train
+arjcxlitoh 1 301 val
+arjdbfrxvu 1 300 train
+arjhugbkjr 1 300 train
+arjihnnsxp 1 300 train
+arjmsfmkym 0 300 train
+arjnjhghyf 1 300 train
+arjnujicfx 0 303 train
+arjvscherh 1 300 train
+arklczdqet 1 300 train
+arkqqrfpjo 1 300 val
+arkqrbjzld 0 300 train
+arkroixhey 1 300 train
+arkrzyznbq 1 300 train
+arkvqylmce 1 300 train
+arkwqyuthh 1 299 test
+arlklajpvk 1 300 train
+arlmiizoob 1 300 train
+arlrwszmpn 1 300 train
+arlzgugbkk 1 297 val
+armqtpynhg 1 298 train
+armthxafvt 0 300 train
+armtkdutdu 1 300 train
+arnnszgmpi 1 300 train
+arnoeknrix 1 300 train
+arnshkdhmt 1 300 train
+arntckxfpg 0 300 train
+arnthfucnd 0 300 train
+arnxqwlhhy 1 300 train
+arnynohkiq 1 300 val
+arofnyavwi 1 300 train
+arojiamzpp 1 299 val
+arokxduvue 1 301 train
+arounjxhhv 1 300 train
+arovnvjxul 1 300 train
+arovusxbcb 0 300 train
+arowpzepzu 1 300 train
+aroyludddl 1 300 train
+arpbjgtacu 1 300 train
+arpjjrnpzm 1 298 train
+arpkmdcyta 1 300 train
+arpsbojfxl 1 300 train
+arptkxoscn 1 300 train
+arpwfxieay 1 300 train
+arpxdfjgbt 0 300 train
+arpyzvkyiq 0 300 val
+arpzrvoylz 1 288 train
+arqabxorin 1 300 train
+arqadmwicu 0 300 train
+arqbrqbjtt 1 300 train
+arqemexeyx 0 301 train
+arqhhrzzfe 1 300 train
+arqigrccnb 1 300 train
+arqkautnud 1 300 train
+arqkfspbhv 0 300 train
+arqpibyiyi 1 301 train
+arqptejqws 1 300 train
+arqszxotbq 0 301 train
+arrfbwpasm 1 300 val
+arrflbwjau 1 300 val
+arrhsnjqku 1 300 train
+arrkzndcbq 1 300 train
+arrneakknr 1 300 train
+arrpqqfiah 0 300 train
+arrprgeura 0 300 val
+arruqttjtu 1 300 train
+arruxldloh 1 300 train
+arrzllscnu 0 300 train
+arrznciaei 1 300 train
+arsayfybpz 0 300 val
+arsbrmfwca 1 269 train
+arsipsjhax 0 299 train
+arskgfjbig 1 300 val
+arstrttqeg 1 300 train
+arsyutncba 1 300 train
+artdpdmeri 1 300 val
+artetnatdf 1 300 train
+artjzhpafa 1 300 val
+artlvuoedl 1 300 train
+artsjrhgij 1 300 val
+artyhhqalj 1 300 train
+arudlrbjsm 1 241 train
+aruemevgtm 1 300 train
+arulsxwzmq 1 241 train
+aruvraefdk 1 300 train
+aruwupqwsc 1 301 train
+aruygoonys 1 300 val
+aruyyclubn 1 300 train
+arvdebtahl 1 300 train
+arvezfgabn 1 300 train
+arvfczthxq 1 300 train
+arvqhnzltg 1 299 test
+arvqnhhwpm 0 300 train
+arvurmcgjs 1 300 train
+arwbaligay 1 300 val
+arwefyghir 0 300 val
+arwiyweadv 0 300 train
+arwkolrdin 1 300 train
+arwmbhzknm 1 300 train
+arwsjwopqe 1 300 val
+arwwmwdpiv 0 300 val
+arwyjgnvlp 1 300 test
+arxaabhesq 0 300 train
+arxiighiuw 1 300 train
+arxmclcemw 1 301 train
+arxngsfysd 1 297 val
+arxqijpbgi 1 300 train
+arxrdpyjhl 1 301 val
+arxtdzaufb 1 300 train
+arxzngjuww 1 300 train
+aryatiqkux 1 300 train
+arybwdkvrm 0 300 train
+aryesdeggf 1 300 train
+aryvgrjzan 0 300 train
+aryxrnnlsr 1 300 train
+aryycfonig 1 300 train
+arzbiiwkrp 0 300 train
+arzcgyecpy 1 300 val
+arzenjyyrm 0 241 train
+arzibochtu 1 300 train
+arziusrlal 1 296 val
+arzmfjryua 1 300 train
+arzxjcyupl 1 241 train
+arzxyrstcs 1 300 train
+asaatlgelc 1 301 train
+asabhwhxbh 1 300 train
+asaflbucjt 1 300 val
+asagdvyxlw 1 300 train
+asahxwzgiu 1 300 train
+asanbqerkb 1 300 train
+asarlqgmqi 1 301 train
+asaulgpiaj 1 300 train
+asaxgevnnp 0 300 train
+asaznagkeg 0 298 train
+asbgigamjm 1 300 train
+asbjfajcxl 1 300 train
+asbrrnbkbn 1 300 train
+asbsihbpvo 1 300 val
+asbutjisyx 1 300 val
+asbuybriyp 1 301 val
+ascnybkrhp 1 300 train
+ascqxdkrgh 1 300 val
+ascrpmppub 1 300 train
+ascrreyhfq 1 300 train
+asctnimvnx 1 300 train
+ascxludrhp 0 300 train
+asddammewq 1 300 train
+asdfeigenc 1 239 train
+asdinxfscu 1 300 train
+asdkayohsb 1 300 train
+asdlmqyuzz 1 302 train
+asdobemvhs 1 300 train
+asdpeebotb 1 300 train
+asdvrcdjoo 1 300 val
+asdwfaumck 1 300 train
+asdzplbhnm 1 300 test
+asebjkxyih 0 301 train
+asegzhcfvb 1 300 train
+asehefjcrx 1 300 train
+asetdhavnb 1 300 train
+asethuqknh 1 301 val
+asewdghwiy 0 300 train
+asewluvyef 1 300 train
+aseytmtsra 1 300 train
+asezorxmhf 0 300 val
+asfdlwrfhj 1 300 train
+asfhofohez 1 300 train
+asfmbofesp 1 300 train
+asfmcylpjv 1 301 val
+asfonhwhzd 1 300 val
+asfqfdvrjj 0 300 val
+asgfrovmom 0 300 train
+asgqrqtsuh 1 300 val
+asgsjbpgdn 1 300 val
+asgzesadhh 1 300 train
+asherfekge 1 300 train
+ashhlwfobv 1 300 train
+ashldjotfg 1 297 val
+ashnmocbih 1 300 train
+ashqrawqub 1 300 train
+ashuwsyjoy 1 300 train
+ashwnofkdi 1 300 train
+asiduvhsif 1 300 train
+asifdtncje 1 241 train
+asiowlirap 1 300 train
+asiuftijhs 1 300 val
+asiwswrgnh 1 300 train
+asiwzzmvey 1 300 val
+asjcdsuxqc 1 241 train
+asjegdijws 1 300 val
+asjeirtlwd 0 300 train
+asjekccfmc 1 300 train
+asjfyybwlx 1 300 train
+asjmvwjkga 1 300 train
+asjqgzcxjm 1 300 train
+asjvplzvqm 1 300 train
+asjwojmbtw 1 300 train
+asjxofxzbd 1 300 train
+asjzklsxgb 1 300 train
+askalizlde 1 300 train
+askbwhvcty 1 239 train
+askcfxbyhu 0 300 train
+askdfuvymj 1 298 val
+askhsshduz 0 300 train
+askiedemhz 1 240 train
+askjqjaeot 1 300 train
+askqkmvjdc 1 300 train
+askydwekiz 1 300 train
+aslagfljgq 1 300 train
+aslioexcfy 1 300 val
+aslizdtstq 1 300 val
+aslkgbcvyw 1 300 val
+aslmihlqts 1 300 train
+aslokfrsbj 1 300 val
+aslrunhhyl 0 300 train
+aslsvlvpth 1 300 train
+aslwfdrdsz 1 300 val
+aslxmgtptv 1 300 train
+aslxzwzntx 1 300 val
+asmbxylneu 1 300 train
+asmpfjfzif 1 300 train
+asmqnysvsj 1 301 train
+asmtmczggz 1 300 train
+asmturwvvg 1 300 train
+asmvgulrof 1 300 train
+asmyxvvkwr 1 300 train
+asngnptgeu 1 300 train
+asnhojocyk 1 300 train
+asnkbzwmtw 1 300 train
+asnnogwqkh 1 299 train
+asnpsowhyj 1 299 test
+asntcqtqkq 1 300 val
+asokwizksz 1 300 train
+asopsoelan 0 300 train
+asownnwcfl 0 300 train
+aspaowlgbo 1 300 val
+aspctnzdzu 0 300 train
+aspddascnt 1 300 train
+aspfqudnfm 0 300 train
+aspfugtmow 1 300 val
+aspjhkusgd 1 300 train
+aspqeufuad 1 300 train
+asprauawhs 1 298 train
+aspszzzkju 1 300 train
+asptbsmjte 1 302 train
+aspxnmdiku 1 300 test
+aspxqtipuv 1 300 train
+aspymrzpyt 1 241 train
+asqqmgvssv 1 300 train
+asquqxqfgt 1 300 train
+asrcllzyav 1 300 train
+asrdxfgoax 0 300 train
+asrhlkuzpq 1 301 train
+asrlczgebm 1 300 train
+asrolirrqe 1 300 train
+asrqbwjtvi 1 300 val
+asrqdjylvs 1 300 train
+assetebyvu 1 300 train
+assiabpavb 1 300 train
+assmgrbnns 1 300 train
+assnxglavo 1 299 test
+asswuixayc 1 300 train
+astlmmrlwl 1 300 train
+astmemhkkb 1 300 train
+astmniufbz 1 300 train
+astngczbtb 1 300 train
+astsglvnfu 1 300 train
+astycpcvjv 1 300 train
+asuexsbatl 0 300 train
+asunvzmjhu 1 300 train
+asupryfzyn 0 300 train
+asurzsoimd 1 298 train
+asusdwxyxp 1 300 train
+asutuywxrs 1 300 val
+asuvyfogir 1 300 val
+asvcrfdpnq 1 300 train
+asvekpymtt 1 300 val
+asvellxbhg 1 300 val
+asverchuam 0 300 train
+asvheijspx 0 300 train
+asvmheclag 1 298 train
+asvroyjehl 1 299 val
+asvsrnhyfx 1 300 train
+asvuutypvz 1 300 train
+asvzmbozcs 1 300 train
+asweglrfni 1 300 val
+aswennsiif 1 300 train
+aswiwviosx 1 147 train
+aswtglynif 1 300 train
+aswtmjxxsm 1 298 train
+aswtwwuiva 1 300 train
+asxhhsants 1 300 test
+asxhprdsfg 1 300 train
+asxjtqbpxq 1 300 val
+asxsyglald 1 300 train
+asyjnjjldz 1 300 train
+asyngyvjas 1 300 train
+asysavfqhi 0 300 train
+asytpbwdda 1 300 train
+asyvhuglhs 1 300 val
+aszdwxqtnb 0 239 val
+asznwwwgvg 0 300 train
+aszpchzkyg 1 301 train
+aszpjdkvys 1 300 val
+aszsocbkpa 1 300 train
+aszxwfzccf 1 300 val
+atabwvdlhh 1 300 train
+atafcwjaia 1 300 train
+atahzrvlsa 1 300 train
+ataqqdebsl 1 300 train
+ataucpprds 1 300 val
+ataulynpgd 1 301 train
+ataynkhdcf 1 300 train
+atbqpfymgi 1 300 val
+atbtdfphqv 1 299 train
+atbtsntowb 1 241 train
+atbxcasnkc 1 300 train
+atbxybzopa 1 300 val
+atcejmlcmn 0 300 train
+atcfypvdpu 1 300 train
+atcgkelqhu 1 300 train
+atchftsngx 1 300 train
+atcmqkpppw 1 300 train
+atcnenknyb 1 241 train
+atcvqucrzf 0 301 train
+atcvvcoejg 0 300 train
+atdfyhldqf 1 300 val
+atdhxneulh 1 300 train
+atdipvfetm 1 300 train
+atdtoujvdc 1 300 train
+atdwnhxgoe 1 300 train
+atedadvxfr 1 296 train
+atedpzfvyf 0 300 train
+ateeagebpq 1 300 train
+ateioktfar 1 300 val
+atewgdjqdl 1 300 val
+atfajfiodw 0 300 train
+atfajwqeit 1 300 val
+atfbrkmkll 1 300 train
+atfibypwpp 1 300 train
+atfkzatsfs 1 301 train
+atfmpitctk 1 300 val
+atfocoqgmu 1 300 train
+atfsetbxac 1 300 train
+atfsgedmws 1 298 train
+atfuphvjft 1 300 val
+atfvfghcom 1 300 train
+atgawbaspu 1 300 train
+atgfhmgkjo 1 300 train
+atggnbknaq 1 300 val
+atglxemkyw 1 300 train
+atgnxbxemp 1 300 train
+atgqynwifn 1 300 val
+atgtcxokbl 1 300 train
+atgtohzdhg 1 300 val
+athaasdqvu 1 300 train
+athblvjkub 1 300 train
+athgcxtboz 1 300 train
+athgskkizr 1 299 val
+athhoigcyr 0 300 train
+athhvgvtxe 1 300 train
+athlwavnyb 1 300 train
+athqmimdaj 1 300 train
+athwwvrhcv 1 300 train
+athyhkghgu 1 300 train
+atidvosipb 1 300 train
+atigpbfytt 1 300 train
+atijhccfre 1 300 train
+atisizneup 1 300 test
+atixaudngu 0 300 val
+atjcjxdqhp 1 298 val
+atjrilmghp 1 300 train
+atjvhhidya 1 300 val
+atkbwsuekf 1 300 train
+atkdbqlpri 0 300 train
+atkdltyyen 0 300 train
+atkpyhjbyv 1 300 train
+atkqtbbbeq 0 300 train
+atksribkip 1 300 train
+atkvnzjywz 1 300 val
+atlgndqoer 1 301 train
+atlgptyibs 0 300 train
+atlinzpgiq 1 301 train
+atlndbikhv 1 300 test
+atloxhcthr 1 300 train
+atlqijvnzs 1 241 train
+atlrsxtful 1 300 val
+atmalptsdf 1 167 train
+atmckdctch 1 300 train
+atmhcvvjfs 1 299 train
+atmjyaldyf 1 300 train
+atmnxwqrsz 1 300 val
+atmpbrgsmp 1 300 train
+atmqdcgwaj 1 300 train
+atncneuejc 1 147 train
+atndkfaexa 1 300 train
+atndvsfdfz 1 300 train
+atneaiuxap 1 300 val
+atngszfenm 0 300 train
+atnlkyhyfc 1 300 train
+atnmhtfbyx 1 300 train
+atntkkmyft 1 300 val
+atnwteurcw 1 300 val
+atnzcsviod 1 301 val
+atoasmpvfo 1 301 train
+atocmpynlp 1 300 train
+atoeqixpui 1 300 train
+atoguadykn 1 300 train
+atokvbzcel 1 300 train
+atomsspjbl 1 241 train
+atophdvemg 1 300 test
+atorvfmqtw 1 301 train
+atosiqqljt 1 300 val
+atougzisvw 1 300 train
+atowsdbqcx 1 300 train
+atowzetfps 1 300 train
+atpakmzodn 1 300 train
+atpavsukgc 1 300 train
+atpcpjmeqn 1 300 train
+atpngxfnhr 1 300 test
+atpnhuzwfx 1 300 train
+atprqjklpx 1 300 train
+atptcqosxk 1 300 train
+atpthnobxr 1 300 train
+atpwddsewz 1 300 train
+atpwgkaeet 1 300 train
+atqiwttwse 1 300 train
+atqjxefbhr 1 297 train
+atqogajciq 1 300 val
+atqtjhcjok 1 300 train
+atqvygnuin 1 300 train
+atqzgwwnml 1 300 train
+atrcstuvme 1 300 train
+atrelvkevy 0 300 train
+atrewimowk 0 300 train
+atrfdylqcc 1 300 train
+atrhuxbwwv 1 301 val
+atrkuzsdlc 1 301 train
+atrmrdhzrk 1 299 test
+atrssikhoy 0 300 train
+atrteuctxr 1 300 test
+atsaksrayk 1 300 train
+atskafotrj 1 241 train
+atsoxhthal 1 300 train
+atsqpfujai 1 300 train
+atsvznzksa 1 300 train
+atsxbvdqfb 0 300 train
+attddpplub 1 300 train
+attmnksdst 1 300 train
+attuckvdne 1 300 val
+attyvvugmr 1 300 val
+atubdulawq 0 300 train
+atubuiqpqo 1 299 val
+atuchlkujx 1 298 train
+atuelqlopo 1 300 train
+atuevnkgvs 1 302 val
+atuizbpwqu 1 300 train
+atuvrbyqor 1 299 val
+atuweqcvfa 1 300 val
+atuydgvxda 1 300 train
+atuzsraaul 0 300 train
+atvazqibly 1 300 val
+atvkhsmnpt 1 300 train
+atvlqqlhwk 1 300 train
+atvmxvwyns 0 300 train
+atvnqtubdj 1 300 train
+atvowzcvwd 1 300 val
+atvucyyltw 1 300 val
+atvyoietle 1 300 train
+atwdcowelh 1 300 train
+atwjgmhfzb 1 300 train
+atwlvegbed 1 301 val
+atwmgvaauf 1 300 train
+atwqjgynix 0 300 train
+atwvfkjmzj 1 300 train
+atwxhnhtjr 1 301 train
+atwzoszrue 1 300 train
+atxaywwsys 1 300 train
+atxjcnhfij 1 300 val
+atxnomscvq 1 300 train
+atxoertfts 1 300 train
+atxomakpou 1 300 train
+atxqpfxtad 1 301 val
+atxqvvrthu 1 300 val
+atxtpvdiqh 1 300 train
+atxvxouljq 1 300 train
+atxwpmqdjg 1 297 train
+atxxrvpedy 1 300 train
+atydjyhqsv 1 300 train
+atyinggtpp 1 239 train
+atyljnwunq 1 300 val
+atymuugcbc 1 300 train
+atynlqfnoa 0 300 train
+atyntldecu 1 300 train
+atyslhetzg 1 300 train
+atyvepvewm 1 300 train
+atywhotyfi 1 300 train
+atyxikdsqe 1 300 train
+atzbzdzkep 1 300 train
+atzdjguknk 0 300 val
+atzdorfpoo 0 300 val
+atzdznmder 1 300 train
+atzlmdedzg 1 300 val
+atznrnsmsi 1 299 val
+atznsntfra 1 300 train
+atzrmdkzfm 1 301 val
+atzsmxhbyd 1 300 train
+atzvxcgfmy 1 300 train
+atzwrsivnb 1 300 test
+auabdnhegy 1 300 train
+auaeqnxoqu 1 300 val
+auaicanxpp 1 300 train
+auapkhjjlb 1 300 train
+auaqihmsmu 0 300 train
+auaudezume 1 300 train
+aubmaydoyk 1 300 train
+aubopmoghu 0 300 train
+aubpextrzn 0 300 train
+aubuzedwnr 1 300 train
+aubwdivikf 0 300 train
+aucdquhxmk 0 301 val
+aucfkadwgs 1 300 train
+aucjnglfvy 1 241 train
+aucmvckzax 1 300 train
+aucskzirmd 1 300 train
+aucunewmkp 1 300 train
+audcaumiyk 1 300 train
+audiqndpnh 1 300 train
+audmymhyqq 1 300 train
+audooqjxxn 0 300 train
+audopnpcyd 0 300 train
+aueslnuoxx 1 300 val
+aufcgglxtv 1 300 test
+aufmsmnoye 1 300 train
+aufnlnndwk 1 300 train
+aufphhubty 1 300 train
+aufudlkirv 1 300 train
+aufuqdncad 1 300 train
+augfkhqkbv 1 300 train
+augnkililg 0 300 train
+augowetyej 1 300 test
+augtsuxpzc 1 300 train
+augwmbhmkq 1 300 train
+augwyjvlqa 1 300 test
+auhahnwdcp 1 300 train
+auhelqsolf 1 300 val
+auhhhfprkw 1 300 train
+auhiwypzvd 1 300 train
+auhlumkfdg 1 300 train
+auhqxlvztv 1 300 train
+auhrezixau 1 300 val
+auhwmwgwrt 1 300 train
+auhyylivrx 1 300 train
+auihlryzbt 1 300 train
+auikdbtptv 0 300 val
+auilwijuvo 0 300 val
+auiyaoncks 0 300 train
+aujfbgxila 1 300 train
+aujiyxfffk 1 300 val
+aujjenqxyl 1 297 train
+aujjjfkloi 1 300 train
+aujnmzqaae 1 300 train
+aujoxrpddn 0 300 train
+aujpmgpzaj 1 300 train
+aujqnutgrt 0 300 train
+aujrpwwjtq 1 300 train
+aujxjbehuz 1 296 train
+aukacmqeru 1 300 train
+aukauaaqwt 0 300 train
+aukfaxetvr 1 300 val
+aukmfldgcb 1 300 val
+aukxwgyuov 1 300 train
+aukznkpjqe 1 300 train
+aukzxswprz 1 300 train
+aulahnnest 1 300 train
+aulcidxczq 1 300 val
+auldikrfnu 1 300 train
+aulhgrnrmf 1 300 val
+aulhlbsxzq 1 300 train
+aulmrfdiyo 1 300 train
+aultpoxkdl 1 300 train
+aulykluogb 1 300 train
+aumcclscze 1 300 train
+aumdtjrpoq 1 300 train
+aumgbezciw 1 300 train
+aumhehkisj 1 300 val
+aummcyaedy 1 300 train
+aumndplfqk 1 240 val
+aumnwnognw 1 300 val
+aumokcjpko 1 298 train
+aumrbclbbc 1 300 val
+aumsysgpsf 0 300 train
+aumyahypue 1 300 train
+aunbxjislr 1 300 train
+aungqwwvev 1 298 val
+aunokqsmrt 0 299 val
+aunqfjmfqp 1 299 test
+aunsxsgprx 0 300 train
+aunzmczjot 1 300 train
+auobavdvej 1 99 train
+auoervelwm 0 300 test
+auoigmvbxt 1 299 train
+auoiwspjju 1 300 train
+auoojxnyap 1 300 train
+auopyykbbo 1 300 val
+aupelgqcor 1 300 train
+auphqsoduh 1 300 train
+auprjrkwqd 1 300 val
+aupsxowdcp 1 300 train
+aupuivyhay 1 301 val
+aupunxljjw 0 300 train
+aupwvhmmzg 0 300 train
+auqgkzaacb 0 241 train
+auqgxmpfls 1 300 train
+auqlledwxt 0 300 train
+auqocxhare 1 301 val
+auqodugkft 1 299 train
+auqqcffvnq 0 300 train
+auquqlmsts 1 300 test
+aurcpsxlqm 1 300 test
+aurdxcfzlq 1 300 val
+aureohnlim 1 300 train
+aurgcztzed 1 300 train
+aurgosqhcy 1 298 val
+aurhwgydst 1 298 train
+aurpwezfec 1 298 train
+aurveuxybo 1 300 train
+aurylporij 1 300 train
+aurzklcfsd 1 300 train
+ausqwaaujs 1 300 train
+auszbyqcem 0 300 train
+autarxwghk 1 301 val
+auticcvqlx 1 300 train
+autisbexzb 1 300 train
+autrzwpvav 0 300 train
+auttzzzosj 1 300 train
+autwdwydhy 1 300 train
+auubycdueq 0 300 val
+auucuhztow 1 300 train
+auufojyawu 1 300 train
+auunxrgrox 1 300 train
+auurrcbcul 1 300 train
+auutsafigm 1 300 train
+auuxrdogjl 1 300 val
+auvbpfyttf 1 299 val
+auvfbzsngs 1 300 val
+auvfkpejdn 1 300 train
+auvihbwrop 1 300 train
+auviwvqttx 1 300 train
+auvmvpiwxe 1 300 train
+auvprruuly 1 300 train
+auwljofebi 0 300 train
+auwoeoemgo 1 301 train
+auwraeneuz 1 301 val
+auwtchbkmh 1 237 train
+auwxgkkipp 1 301 train
+auxnjvttgs 1 301 train
+auxtpaboto 1 300 train
+auxxqwvfkc 1 300 val
+auydsalswy 1 298 train
+auykxzlgzj 1 300 train
+auyndsjryc 1 301 val
+auyootefrt 1 300 train
+auyrrevsns 1 300 train
+auysreeedq 1 301 train
+auyyexggvm 1 300 train
+auyzbzzqpt 1 241 train
+auzdasaabf 1 300 train
+auzfmgvfgf 1 300 train
+auzjtdvbao 1 300 train
+auzmsdnnhm 1 300 val
+auzofkvxmb 1 300 train
+auzoiwvcym 1 300 val
+auzqswbczw 1 300 train
+auzyknaopn 1 300 val
+avabskjphz 1 300 val
+avadsjxbjq 1 300 val
+avaideasjj 1 300 train
+avajqvytck 1 300 train
+avaqhfpexl 1 300 train
+avbgtxduxw 1 300 train
+avbmqxnmlj 1 300 train
+avbnltvmfx 1 300 val
+avbsswfveh 1 300 val
+avcccznrft 1 299 val
+avcfbvlltt 1 300 val
+avcftqodfe 1 300 train
+avcgrlsnwu 1 300 train
+avcgzaxcxj 1 300 train
+avcihsaenf 1 300 val
+avcnyamvrb 1 300 train
+avcohlhxjr 0 300 train
+avcoxxzayv 0 300 train
+avcyoqrqbg 1 301 train
+avczvisstl 1 300 val
+avczzdxwns 1 300 val
+avdbjlhnef 1 300 train
+avdcsqqkin 1 300 train
+avdfyvawxu 0 302 train
+avdickhxmm 1 300 train
+avdqdbekdg 1 300 train
+avdqmosfow 1 300 val
+avdvlgnqnm 1 300 val
+avdvrthswq 1 300 train
+avdvtlhcot 0 300 train
+avdwxsegib 0 300 train
+avebrhzvyp 1 300 train
+avefgngkal 1 300 train
+avenlmlmtn 1 300 val
+avernyjbxv 1 300 val
+aveybbfgtb 1 298 train
+avfehpwoit 1 301 val
+avferwcvnt 1 300 train
+avfhsplmya 1 300 val
+avfitoutyn 1 300 train
+avfoukjslp 1 300 train
+avfvieoaih 1 241 train
+avfvsddibv 1 300 train
+avfxgetfyn 1 300 train
+avgekvunas 1 300 train
+avgerywsmv 1 300 val
+avgfqtedcd 1 300 train
+avgfywmqlr 1 300 train
+avgiuextiz 1 300 train
+avgrquoicj 1 300 train
+avgtoksnru 1 300 train
+avgxjomocx 1 300 val
+avhdquzuwf 0 300 train
+avhldaimyf 1 300 val
+avhnnjtuqw 1 299 test
+avhogqrbfr 1 299 train
+avhyjwzrdp 1 300 val
+avibnnhwhp 1 300 train
+avibtgzoux 0 300 val
+aviojqkwmg 1 300 train
+avjauiqsjy 0 301 train
+avjcmifvyz 1 300 train
+avjgupazfa 1 300 train
+avjisfzhex 1 300 train
+avjkwuusto 0 300 val
+avjlhxlhbi 1 300 train
+avjoadrpkd 1 301 train
+avjqdkzjdx 1 300 train
+avjsnsinzy 1 300 train
+avjvhhmnxr 1 298 val
+avjwhrqbwl 1 299 train
+avjzekwelm 1 300 val
+avkcnnxjmt 1 300 train
+avkelzfynk 1 300 train
+avkeqerpsc 0 300 train
+avkjzckdjp 1 300 train
+avkofrewmx 1 300 val
+avkoyhjdcy 1 300 train
+avktbnnfct 1 300 train
+avlbihahvk 1 301 train
+avlcvrdnno 1 300 train
+avlfjeuozz 1 300 test
+avliofdydx 1 300 train
+avlmfkyfzg 1 300 val
+avlmlshqjh 1 299 test
+avmainezlp 1 300 val
+avmbrtpdoa 1 300 train
+avmedxjrro 1 300 train
+avmemmaaor 1 300 train
+avmgyrjqzy 1 300 val
+avmjormvsx 0 300 train
+avmrqfwizg 1 167 train
+avmrxnncfv 1 300 train
+avmtuoxxer 1 300 train
+avmyfsapcs 1 300 train
+avnqldseev 1 300 val
+avnqydkqjj 1 300 train
+avnxwfdjca 1 300 train
+avoajvzwjz 1 300 val
+avocsaizhx 1 300 train
+avonxlveeb 1 300 train
+avoqheikrk 1 300 test
+avotaeqmvc 1 300 train
+avovhmumnp 1 300 train
+avowpehija 1 300 val
+avowqomohu 1 300 train
+avoznljmeq 1 297 train
+avozobkkmm 1 300 val
+avpfewqqbu 1 300 train
+avphttmbpx 0 300 val
+avpjlmaddb 1 300 val
+avpmcgjckj 0 300 train
+avptoyibqd 1 297 train
+avpuemhqni 0 300 train
+avpuwxsjxc 0 300 train
+avpxiwwfwa 1 300 train
+avpxuvplbn 0 300 val
+avqccojucs 1 300 train
+avqctbjgpr 0 301 train
+avqjwllsvv 0 300 val
+avqmdqnxbs 1 300 val
+avqxrnfzpd 1 300 train
+avqznmlvzs 1 300 val
+avrdqcxtgo 1 301 train
+avrjnwyavl 1 300 train
+avrkhkuggo 1 300 val
+avrpxdjfyw 1 298 train
+avrtgzyqjl 1 300 train
+avrwxtyoqg 1 300 train
+avrxdvoabt 1 300 train
+avseaqfbeq 1 300 train
+avshmkgrwm 1 300 val
+avsirfayle 1 301 train
+avsmkgfxso 1 300 val
+avssvvsdhz 1 300 train
+avsuotpjte 1 300 train
+avsuqiquiq 1 300 train
+avsuwuptec 1 300 val
+avsyycwhhq 1 300 val
+avtdwylihb 1 301 train
+avteqdmbob 0 300 train
+avtfoeadnt 1 300 train
+avtfrnaplf 1 300 val
+avtnmkkymk 1 300 val
+avtsotbmxb 1 300 train
+avttogwbyz 0 300 train
+avtycwsgyb 1 300 train
+avubtwxvrc 1 300 train
+avucqbunoa 1 300 train
+avudszzvcp 1 302 train
+avuemvxxcf 0 300 train
+avuhqqndox 1 292 val
+avujxrubzm 0 300 train
+avujziraao 1 300 train
+avuodshygp 1 300 train
+avuujqflxz 0 300 train
+avvdgsennp 1 300 train
+avvijgjqre 0 300 train
+avvioujqyo 1 300 train
+avvkokmaae 1 300 val
+avvmcxfdup 1 300 val
+avvmidgbai 1 300 train
+avvmvlzkug 1 301 train
+avvpwmvcuy 1 300 train
+avvswvvoxp 1 300 val
+avvyicotkk 1 300 train
+avwabkfjnx 1 300 train
+avwddhpjxw 1 300 train
+avwezsgvml 1 300 train
+avwfnudcag 1 300 train
+avwhgwufdz 1 300 train
+avwqlepobv 1 300 train
+avwwbtbtqr 1 300 val
+avwyvjwuqf 1 300 train
+avxatzklnf 1 300 train
+avxgvoxwsy 1 300 val
+avxkxnaxfa 1 300 train
+avxmdlcfnb 1 300 train
+avxtaltkzj 1 300 train
+avxvnpjfmp 1 300 train
+avxxlusnod 1 300 train
+avywawptfc 1 300 train
+avyxflippj 1 300 train
+avzfguclaf 1 300 train
+avzhpakvbe 1 298 train
+avzhpmaugt 1 300 train
+avzjnxfbge 1 300 train
+avzmrjrmdd 1 298 train
+avznxuwvbx 1 300 test
+awaiqpayyx 0 300 val
+awaodxwyqd 1 298 train
+awavcnfxzj 1 300 train
+awawmbfyof 1 300 train
+awbalzombg 0 300 val
+awbjetawnf 1 300 train
+awbsiclhpo 1 300 train
+awbwkdsdkh 1 301 val
+awcftwahcl 1 300 train
+awcinqyptd 1 300 val
+awciwaoxbg 0 300 train
+awckrpgrza 1 297 train
+awclenxahv 0 300 train
+awderxpojn 1 300 train
+awdrgjsmdm 1 300 train
+aweiaivpvs 1 300 train
+awelafarav 1 300 val
+aweoiozyrk 1 300 val
+awerihgcpz 1 300 train
+aweyorxpto 1 300 train
+awfddrmdst 1 299 test
+awfdmxsbnj 1 300 train
+awfghdfcmz 1 300 train
+awfhtuiccr 1 300 train
+awfjdqqygu 1 300 test
+awfjjiienh 1 300 train
+awfkuosrud 1 302 val
+awfrfnpdas 1 300 val
+awfskxlfij 1 300 train
+awfteelgmx 1 300 train
+awfttazckk 1 300 train
+awfubwmtlh 1 300 val
+awgczyqngx 1 298 train
+awgdlcpsot 1 300 train
+awgigljrgi 1 300 train
+awgkrpxukk 1 300 train
+awglcxxkdp 1 300 train
+awgnijixvk 1 300 test
+awgsrlznew 1 300 train
+awhggyzodc 1 300 val
+awhmfnnjih 1 300 train
+awhupovbao 1 300 train
+awibecpxci 1 300 train
+awifeyjgpb 1 300 train
+awigucdtpo 1 300 train
+awigxxbbpb 1 300 test
+awihhtzuen 0 300 train
+awijekjkiu 1 300 val
+awiomwmrkv 1 298 train
+awiusprppe 1 300 val
+awiyvmgflq 1 300 train
+awiyzfdvkn 0 300 train
+awjaqhlcqu 1 300 train
+awjdqsthvc 1 300 val
+awjdxxtdpa 1 300 train
+awjizuuwtg 0 241 train
+awjkypdefk 1 240 train
+awjptrwzzo 1 300 train
+awjtdulzbz 1 300 train
+awjuastgdw 1 300 train
+awjywmwplp 1 299 test
+awkbynykry 1 300 train
+awkknginsz 1 300 train
+awkkwnyswq 1 300 val
+awkothxqwq 1 300 train
+awksqngwsw 1 300 train
+awktopskpn 1 300 train
+awkvatcshx 0 300 train
+awkxwqfint 1 300 val
+awkzxzryod 1 241 train
+awldflynbc 1 300 train
+awlhmcqaan 1 297 train
+awliruqjkd 1 300 train
+awlmfcjhxf 1 300 val
+awlpqlmfbd 0 301 train
+awlqktdjoa 1 300 train
+awlskxaayc 1 300 val
+awlxbashns 1 297 val
+awmatnckri 1 241 train
+awmeoatyyy 1 296 val
+awmhafhfof 1 300 train
+awmhinzfsf 1 298 train
+awmhjhkkrs 1 300 train
+awmhslwaed 0 300 train
+awmvrsdttc 1 300 val
+awmydrvoez 1 300 train
+awmzssxngn 1 300 val
+awnfpubqmo 1 300 test
+awnhnhbbxm 1 300 test
+awnirdhpua 1 296 train
+awnjymbwza 0 300 train
+awnocmzbhi 1 301 val
+awnorqobve 1 300 val
+awnwkrqibf 1 300 train
+awnwneljqx 1 301 train
+awobjvjdwg 1 301 val
+awoeujcxvp 1 300 train
+awommqxhgm 0 300 train
+awomvlcenj 1 300 train
+awpauyheez 1 300 train
+awpdbtfgbj 1 300 train
+awpixmkmzv 1 241 val
+awpnjkemhd 1 300 train
+awpoavcoiw 0 300 train
+awqhdmmuvx 1 300 train
+awqlgqazkz 0 241 train
+awqxxphxbf 1 300 train
+awqzsxwubw 1 298 train
+awrazctokk 1 300 train
+awrjjgpfok 1 300 val
+awrnfjkwxr 1 300 train
+awrvggbava 1 300 train
+awrxrznakh 0 300 train
+awsceniain 0 300 val
+awsjaessrp 1 300 train
+awstgmezgy 1 300 train
+awswgbzdsh 1 300 train
+awsylzjvft 1 300 train
+awsyzabifm 1 301 train
+awsznciprw 0 300 val
+awtnxljuij 1 300 val
+awtomwfgsw 1 300 train
+awtovqtwpx 1 298 train
+awtrjchfyi 0 300 train
+awttpcynpo 1 300 train
+awtuzutzcg 1 300 train
+awtvzkchmb 0 300 val
+awtwvcthes 1 300 train
+awtxmrgbtv 1 300 train
+awuejsplvk 1 300 train
+awufmdbtmh 1 300 val
+awukslzjra 1 300 train
+awuwcwcmry 1 300 train
+awuxsqvaez 1 300 train
+awvbaakabm 1 300 train
+awvjqlhrmf 1 301 train
+awvnopdojm 0 300 train
+awvpdblicz 1 299 train
+awvpnrmvuf 1 300 train
+awvzwnorqc 1 300 train
+awwdrhjncq 1 300 val
+awwdzrzixb 1 300 train
+awwexvkmil 0 301 train
+awwlbkyice 1 300 val
+awwwhgaqfy 1 300 train
+awwycszotu 1 300 val
+awxbgxeldd 1 300 train
+awxjcnfcrw 1 300 train
+awxoipyrhc 1 298 train
+awxyltpwea 1 299 train
+awxzireppb 1 300 train
+awyccgauib 1 300 train
+awykspojnf 1 300 train
+awymlsdwiq 1 300 train
+awynklddka 1 301 train
+awypqsjdfg 1 300 train
+awyqkbkxub 0 300 val
+awyzsmccyp 1 300 train
+awzgjaqzyu 1 301 train
+awzjpnfkwz 1 300 train
+awzkdpxorv 1 300 train
+awzngrgwjw 0 301 train
+awzspxvaxv 0 300 val
+awzxxaxccz 1 300 train
+axacqvzcem 1 300 train
+axaetvbwns 1 300 train
+axakrhimzr 1 300 train
+axanpcosjc 1 298 train
+axatawveci 1 300 train
+axazpptbwz 1 300 train
+axbadtrvjp 1 300 val
+axbahffclw 1 300 val
+axbffpjqpj 1 299 train
+axbnwqundg 1 300 train
+axbnxjivlr 1 301 train
+axbocmkdix 1 300 train
+axbondvizf 0 300 val
+axbpgirutr 0 300 train
+axbpveqqqg 1 301 train
+axbvacitpc 1 300 train
+axbvoepbdc 1 300 test
+axbwohvwap 1 300 train
+axcasmwtjb 1 241 train
+axcjfghdur 1 300 train
+axcjlihbfp 1 300 train
+axclxmvyxx 1 300 train
+axcmfbugxm 1 300 val
+axcrlohqmz 0 300 train
+axctwetafz 1 301 train
+axcwjuvwyu 1 300 train
+axcxcpuvob 1 300 train
+axcyprvxsm 1 300 val
+axczxisdtb 1 300 train
+axdalxpkuo 1 298 train
+axdepsfowg 0 300 train
+axdfevfyte 1 300 train
+axdgwkhocr 1 300 train
+axdhmvtxnp 1 300 train
+axdkyemcps 1 300 train
+axdtpoftlh 1 300 train
+axdvnynpjj 1 300 test
+axefavvhcm 1 300 train
+axefpthxba 1 300 train
+axefxbvfyn 1 299 test
+axegmnrwcx 1 300 val
+axekxrofuz 1 300 val
+axeskcyfyw 1 300 train
+axeweryrur 1 300 train
+axfbizxbhd 1 300 val
+axfekcjvqk 1 300 val
+axfenneicj 0 300 train
+axffqdpfvc 1 300 train
+axfgowzinn 1 300 val
+axfhbpkdlc 1 300 test
+axfjqgpksd 1 300 train
+axflcedbst 1 300 train
+axfmazvuro 1 300 val
+axfquovbya 0 300 train
+axfqvtdpqn 1 300 train
+axfvkaxgpa 1 300 train
+axfwkvygnt 1 300 train
+axfwtbbwyu 1 300 train
+axfzvnwvmk 1 300 train
+axgaidrsri 1 301 val
+axgcqvgavl 1 300 train
+axghhvvlxv 1 300 train
+axgjecgvwm 1 300 train
+axgkbpxjvr 1 299 test
+axgxikfija 1 300 train
+axgzydgksr 0 300 train
+axhbwhtjeo 1 300 val
+axhcrttfvh 1 300 train
+axhjmenqsy 1 300 val
+axhkvlkqrx 1 300 train
+axhoziggtl 1 300 train
+axhqevrfxx 1 300 train
+axidwwmhvb 1 300 val
+axietspzae 1 300 train
+axihbxiqnf 1 300 val
+axiltxiyse 1 300 train
+axiqquouhw 0 300 train
+axizacykmi 1 300 train
+axizfntigl 1 301 train
+axjbcvrvje 1 299 test
+axjkknsbsd 1 300 train
+axjxsymyhw 1 300 train
+axjxujtbsr 1 300 train
+axkbdkcony 1 300 train
+axkbqzdxdb 1 301 val
+axkbrlwjrk 1 300 train
+axkkwzttha 1 301 train
+axklfzdbme 1 300 val
+axkneqqnso 1 300 train
+axkuywcuzt 1 300 train
+axlawxrhzi 1 300 train
+axlbzcbfzt 1 300 train
+axldhrkyls 1 298 train
+axliahbtym 1 300 val
+axlmxrgbiw 1 300 train
+axlsscylar 0 300 train
+axlyhqiljm 1 300 train
+axlyjxjgva 1 300 train
+axlzaoxpcs 1 300 val
+axmfwwuair 1 300 train
+axmhmxlked 1 300 train
+axmnbbewaz 0 300 train
+axmwuiabtk 1 300 train
+axnkkwaotc 1 300 val
+axnpeqmffl 0 300 train
+axnpuuknzw 0 300 train
+axnqdchhfo 1 300 train
+axnrnlbyvi 1 300 val
+axnsynfgqo 1 300 train
+axntxmycwd 0 300 train
+axntzvpfmh 1 300 train
+axnvexznps 1 301 train
+axnyzytgws 1 297 train
+axnzqhlhrn 1 300 val
+axnztobmfv 0 300 train
+axochbfyam 1 300 train
+axodysvnia 1 300 train
+axojprftsy 1 300 val
+axolimmsqr 0 300 train
+axoohecyzz 1 300 train
+axopbbxwzr 1 239 train
+axoygtekut 1 298 train
+axoynijrvs 0 300 val
+axpanprprj 1 300 train
+axpbionmss 1 300 val
+axpbrjhfqf 1 300 train
+axppnromyo 1 302 val
+axpwfeomqt 1 300 train
+axqbmiijno 1 147 train
+axqdnsitzx 1 288 train
+axqgrorxfl 1 300 train
+axqjoetave 0 300 train
+axqkzfboii 1 300 val
+axqmwxjlrg 1 300 val
+axqoxnsewc 0 300 train
+axqsgizzhg 1 300 train
+axqtnlxfzl 1 300 train
+axrhhjkgdl 1 300 train
+axrhxmniem 0 300 train
+axrhyqpdte 1 301 val
+axriuvwgcm 1 300 train
+axrjayzfma 1 298 val
+axrjmjewtw 0 300 val
+axrnokhrnk 0 300 val
+axrrqhwegr 1 300 train
+axrsphinge 1 300 train
+axrvohycln 0 301 train
+axsbbxqsyz 1 300 val
+axsgyeohxb 1 301 train
+axtfaxnnir 1 300 train
+axtfxdqvfk 1 240 train
+axtgwlebim 1 241 train
+axtibgcxgd 1 300 val
+axtqkczcjf 1 300 train
+axtszmzvat 1 300 val
+axttznnysz 1 300 train
+axtvwbsvcg 1 300 train
+axtxpkejwb 1 300 train
+axtyynoxdk 1 301 train
+axuacbannl 1 300 train
+axudxwpjpq 0 300 train
+axugkibxrv 1 298 train
+axulmlkufx 0 300 train
+axurdgcngb 1 300 train
+axutpjywuu 0 300 train
+axuymyxukm 0 300 train
+axvafppqre 1 300 train
+axvchzyjrv 1 300 val
+axvnqxxuex 1 300 train
+axvpzavqyf 1 300 val
+axvvrrujab 0 300 train
+axvzfkzeyb 1 300 train
+axwcwygmkc 1 300 train
+axwgcsyphv 1 300 train
+axwovszumc 1 300 train
+axwpdgxruj 1 300 val
+axwvfkdsaq 1 300 train
+axxekmavjm 1 300 train
+axxldpmbat 1 300 val
+axxngrhfpi 1 300 train
+axxnwcxatg 1 300 train
+axxojjcuzi 1 300 train
+axxvqwvryi 1 300 train
+axxxmqnvlo 1 300 train
+axybfzwjou 1 300 train
+axyczuqmyl 1 300 train
+axyorvscnv 1 300 train
+axytlrpjux 1 301 train
+axytnkxxhd 1 300 train
+axyzsqhnts 1 300 test
+axyzunnpvp 1 301 train
+axzbzdlact 1 299 train
+axzjovaktp 1 300 val
+axzmqrxpxn 1 300 train
+axzxmjrvvi 1 300 train
+ayadravncu 1 300 train
+ayaflkovlc 1 300 train
+ayaklbufdz 1 300 train
+ayaquhexqz 1 299 val
+aybgrrbgef 1 300 train
+aybgtakzhf 1 300 train
+aybgughjxh 0 300 train
+aybhjzvgsz 1 300 train
+aybkiznleo 1 300 train
+ayblwczytf 0 300 train
+aybozriclz 1 301 train
+aybqoonlol 1 300 train
+aybtugbqxp 1 300 train
+aybumesmpk 0 300 train
+aybxejnqxn 1 300 train
+aycfpzxxxm 1 302 train
+aycgmkmvue 1 302 val
+aycgxsaqgi 0 300 train
+aycjerwghk 0 300 val
+ayclhmjajg 1 300 train
+aycpumeoth 1 300 train
+aycrceahnh 1 300 train
+aycutytbxb 1 300 train
+ayddjwnpmh 0 300 train
+aydhuyhqvh 1 300 train
+aydiylfrlh 1 300 val
+aydsqcndsp 1 300 train
+aydxjkfuhk 1 300 train
+aydxtmgdge 0 300 train
+ayehybcbfv 1 300 train
+ayemywhbcy 1 300 train
+ayeuasvmue 1 300 val
+ayewksqvyd 1 300 train
+ayeytpezft 1 300 train
+ayfahboitj 1 300 train
+ayfauyvasg 1 300 train
+ayffajxdql 0 300 train
+ayfffpzztv 1 300 train
+ayfjanopir 1 300 train
+ayfohzyelj 0 298 train
+ayfsfcgwva 1 300 train
+ayftadnbcp 1 301 val
+ayfwibcxei 1 300 train
+ayghiketsd 1 299 train
+ayghjyhjpa 1 300 train
+aygjjgvdvq 1 300 train
+aygsanilyf 1 300 train
+aygxtngztt 1 300 val
+aygyitljoi 1 300 val
+ayhabcqsat 1 300 val
+ayhblsodaz 1 300 train
+ayhhqjvchn 0 300 train
+ayhhyfamhc 1 300 val
+ayhljgasce 1 300 train
+ayhpqqcjuw 1 300 train
+ayhqsngfgm 1 301 train
+ayijzcgmxu 1 300 train
+ayimaqgxep 1 300 train
+ayipraspbn 0 300 test
+ayiqatefmh 1 300 val
+ayisknqtin 1 300 train
+ayiyiznwnr 1 300 val
+ayiyopsoth 1 249 train
+ayjhlfmumi 1 301 val
+ayjiviupgu 1 300 train
+ayjmbpjill 1 301 train
+ayjpsdziav 1 300 train
+ayjxtgelxi 1 300 train
+ayjybhypib 1 300 train
+aykawoglaw 1 300 val
+aykbmlifdu 1 241 train
+aykdfgqrpc 1 300 val
+aykigadhgq 1 301 train
+aykkbovtgl 0 300 train
+ayknzzaztw 1 300 train
+ayksynxvmv 1 300 train
+aykxdbrocq 1 298 train
+aykytsanpx 1 300 train
+aylbqemnhc 1 300 val
+ayldgxapih 1 300 train
+ayldhxkwyd 1 300 train
+ayleocznjp 1 300 train
+aylgpnilrj 1 300 train
+aylqthgnhe 1 300 test
+aylsmqpdwb 1 297 train
+aylzurqmmr 1 300 train
+aymlynzeni 1 300 test
+aymwgrmlbt 0 241 train
+ayneiahymh 1 300 train
+aynqsaxgiu 1 301 train
+ayntzgwakd 0 298 train
+aynvjgamgi 1 300 train
+ayodjtwutr 1 300 train
+ayojccmuqk 1 300 train
+ayoyqfyvxb 1 300 train
+ayozpzxgrg 1 300 train
+aypdhnyecs 1 300 train
+aypdqjxzmu 1 298 train
+aypgpcgzzo 1 300 train
+ayphanzbpm 1 300 train
+aypkfdynul 1 300 val
+aypletsgxc 0 301 train
+aypljgeqag 0 300 train
+aypsslvabz 1 300 val
+aypwdoupiz 1 300 train
+ayqetwwwjn 1 300 train
+ayqpuidfos 1 302 train
+ayqpyomdan 1 301 train
+ayququayvl 1 300 train
+ayqvfdhslr 1 300 train
+ayqvfldwuf 1 241 train
+ayqwlnyqgn 1 300 train
+ayqywtrjhl 1 300 train
+ayregwfkuy 1 300 train
+ayrpqmbxwj 1 300 train
+ayruusetwt 1 300 val
+ayrwjwllmx 0 300 train
+ayserurddl 0 298 train
+aysrnwnhii 1 300 train
+aystoolvlj 1 300 train
+aystpwgtnd 1 300 train
+aysxspqqdm 1 300 val
+aytalckkea 1 300 train
+aytewqzkgb 1 300 train
+aytfwjmtkk 1 299 val
+aytgqggvzu 1 301 val
+aytjdeldie 1 300 train
+aytsnlflqn 1 300 train
+aytxhvqmzu 1 300 train
+aytxkbrpck 1 300 train
+aytzyidmgs 0 300 train
+ayumdlbgzg 1 301 train
+ayumrsumla 1 300 val
+ayuocwmzpm 1 300 train
+ayvcvqamlo 1 300 train
+ayvkjimrki 1 300 train
+ayvmipjkqy 0 300 train
+ayvmlkbabt 1 300 val
+ayvmqddutg 1 300 train
+ayvnhxqifb 0 300 train
+ayvqgytitn 1 300 train
+ayvrrldwmy 1 300 val
+ayvydsmdys 1 300 train
+ayvyqvvayo 1 300 train
+aywjjzeuce 1 300 train
+aywpnsdemq 1 300 train
+aywpqylxdm 0 298 train
+aywteojccm 1 300 train
+aywtqiwded 1 300 train
+aywwbfnvhk 1 300 train
+aywxjblnvr 1 301 val
+aywxvqlvdz 1 300 val
+aywzfaodrz 1 300 val
+ayxmdjekaw 1 300 train
+ayxpdzgpui 0 300 train
+ayxrucvgge 1 300 train
+ayxuxnxwxa 1 241 train
+ayxvnsyvan 1 300 train
+ayxwdgwkol 1 300 train
+ayxwdvdmvn 0 300 val
+ayxwzqufmq 1 300 train
+ayxzbyifsf 1 300 val
+ayyrltarjz 0 300 train
+ayystmhbip 0 300 train
+ayyuycuyxl 1 300 val
+ayyvovoqpq 0 300 train
+ayywxduatc 1 300 train
+ayyyllijgt 1 300 train
+ayyzuoklel 1 300 train
+ayyzyhqvav 1 300 train
+ayzcatqxaj 1 301 train
+ayzcjwfbsn 0 300 train
+ayzfvixjmw 1 300 train
+ayzherlveu 1 300 train
+ayzppalsno 1 300 train
+ayzrnuffie 1 300 val
+azaahiwadu 0 300 val
+azacigrcit 1 299 val
+azadhrzhkf 1 300 train
+azagqawgaz 1 300 train
+azajvevgky 0 300 train
+azarzgywrq 1 300 train
+azavwxxxtn 1 300 val
+azaxkawwtm 1 240 train
+azbcbbisho 1 300 train
+azbfqpllmy 0 300 train
+azbmyuxayo 1 300 train
+azbofvuffd 1 300 train
+azbokmbobc 1 298 train
+azbvekzerb 1 300 train
+azbwsupibi 1 300 train
+azcbnczesb 0 300 train
+azcdenjart 0 300 val
+azcdexfolm 1 300 train
+azcdoycnpg 1 300 train
+azclcszcyq 1 300 train
+azcmabpjmr 1 300 train
+azcsqgyuzb 1 300 val
+azcvdctoii 0 300 train
+azdazfdlkv 1 299 val
+azdgvgbgdv 0 300 train
+azdnpcxhcx 1 300 train
+azdqkgvdbd 0 301 val
+azdqpyvtjf 0 300 train
+azducmbckk 1 300 train
+azduhthfhk 1 300 train
+azdwparxng 1 300 train
+azdyflvmmq 1 300 train
+azefstphot 0 300 train
+azegisuvcp 1 300 train
+azenhytrlc 1 300 val
+azeqliwnpc 1 300 train
+azerbqkngz 1 300 train
+azetzzismz 1 300 train
+azexbcjrxd 1 300 train
+azeytvxpbx 1 300 val
+azeznwraac 1 300 train
+azfdkjyiwz 1 300 train
+azfyeyuhww 0 300 val
+azfzdshcgn 1 300 train
+azgafrrntz 1 300 val
+azgfidhvmw 1 300 val
+azgkuomhkg 1 300 train
+azgnidjfzl 1 300 train
+azgqldxpqu 1 300 train
+azgrvcvhzf 1 301 train
+azgvkbgvjm 1 300 train
+azhbacpvhg 0 300 train
+azhextpsam 1 300 train
+azhgwqmtmy 0 300 train
+azhhoprzju 1 300 train
+azhpzylusc 1 300 train
+azhrvjvptq 1 300 train
+azhrynejrl 0 300 val
+azhvaumkgs 1 300 val
+azioayhcyv 1 300 train
+aziqclhmxa 0 300 train
+azisixgksy 1 300 train
+azitblavhk 0 300 train
+azivnorcbt 1 134 val
+azivxiykdi 1 300 train
+azizygldzb 1 300 train
+azjeanuzpe 1 300 train
+azjihuumrm 0 300 train
+azjileknta 0 301 train
+azjpqungtq 1 300 train
+azjxbjmsie 0 302 train
+azkcxlucst 1 300 val
+azkdupbivt 0 300 train
+azkhkminwu 1 167 train
+azkieigjvj 1 300 train
+azkjdigcrp 1 300 train
+azkvvuwiww 1 298 val
+azlegxsowo 1 300 train
+azlfodrdst 1 300 val
+azloskdmkl 1 300 test
+azlvwkdzji 1 300 val
+azlwgfnjpi 1 300 train
+azlybpzqln 0 300 val
+azmbudlmve 1 300 train
+azmheosoed 0 300 train
+azmirctgyh 1 300 train
+azmjullweh 1 298 train
+azmtgtivlm 1 300 val
+azmthyazex 1 300 train
+azmwqsoiyv 1 301 train
+azngbletdu 1 300 val
+aznhsktnlr 1 297 train
+aznpvuajaw 1 300 train
+aznqgghqge 1 300 train
+aznsswvnxo 0 300 train
+aznwlklyey 0 300 val
+aznyksihgl 1 300 train
+azobkfldrm 1 300 train
+azojfxotad 1 300 val
+azojgtsfqf 1 270 train
+azoszehsys 1 300 train
+azoujagkmd 1 300 train
+azoususkmj 1 300 train
+azozbmaple 1 300 train
+azpamhpoyy 1 300 train
+azpfikprtm 1 300 train
+azpfwcynmx 1 300 train
+azpgkhnbfq 1 300 train
+azpgkljhij 1 300 train
+azphckonyb 0 300 val
+azphlhhnqa 1 300 train
+azppkqhqpi 1 300 train
+azppuasxcf 1 241 train
+azprgjfpgz 1 300 train
+azpsfbwwce 1 300 train
+azpuxunqyo 1 300 train
+azqbopqket 1 300 train
+azqiqdmeif 1 241 train
+azqmhafddn 1 300 train
+azqmircfhx 1 300 train
+azqmtcjxbk 1 300 train
+azquntslyh 1 301 val
+azqvligwls 1 300 train
+azqycoiiuk 1 300 train
+azrbqpomdw 1 300 train
+azrdwmzpqb 1 300 train
+azrgvcrdom 1 300 val
+azrlezxzsq 1 300 train
+azrltfcgki 1 300 train
+azrnasfxsw 1 300 test
+azropyxcjl 1 300 train
+azrovzeecz 0 300 train
+azrqwansbe 1 297 val
+azrrpztvte 1 300 val
+azrwvcpzti 1 300 val
+azrxxsypbj 0 300 val
+azryihdhqe 1 300 val
+azrzdpvkjw 1 300 val
+azscxdpgwk 1 300 train
+azseubmxrc 1 300 train
+azsizuhdse 0 300 train
+azsmewqghg 1 300 train
+azsongfrbo 1 300 train
+azsppdfpdu 0 240 val
+azsrjonuae 1 301 train
+azstxtuuqs 1 300 train
+aztadaceye 1 302 val
+aztfzimxkr 1 300 train
+aztohekkjp 1 300 train
+aztpfrbojy 1 300 train
+aztvcczene 1 300 val
+azueydkjun 1 300 train
+azuheondug 1 300 train
+azulfosmdg 1 300 train
+azuoanakpi 1 300 train
+azuqfvasfq 1 300 train
+azuqfvstge 1 300 train
+azuvbfzeae 1 298 train
+azuyrjszeg 1 300 train
+azvkbgaeoq 1 299 train
+azvnmgesce 1 300 train
+azvpvieiaj 1 300 test
+azvtsxkidq 0 300 train
+azvuadmhnf 0 301 train
+azvwhtagug 1 300 val
+azvxorjlrm 1 300 train
+azweykdwkk 1 300 val
+azwhlgfdpt 1 300 train
+azwqdbfqrd 0 300 train
+azwsqmaxmf 1 300 train
+azwtbicguj 1 300 train
+azwusfxjmb 1 300 val
+azwwrvjyyp 1 300 train
+azwxpyysde 1 300 train
+azxasdagie 1 300 train
+azxcqazqbs 1 241 train
+azxheumhku 1 300 train
+azxilcbqro 1 298 train
+azxmesrgbz 1 300 train
+azxmphhunl 0 300 train
+azxsyvaurb 1 299 val
+azxxenkicg 1 300 train
+azxzqxskzm 0 300 train
+azydlgxdym 1 300 train
+azyiizhjpc 1 300 train
+azylugxlnm 1 300 train
+azyluukyhz 0 300 train
+azylwizjmc 1 300 train
+azyqrdeoew 0 300 train
+azytehaonn 1 301 train
+azytxdovkn 1 300 train
+azyuiunvmg 1 300 train
+azzgrltpvu 1 300 train
+azzhmmoycu 0 300 val
+azzhropiql 1 300 train
+azzldkhpzk 1 300 train
+azzpwoedpk 1 300 train
+azzumsrvli 1 300 train
+azzxjriydb 1 300 train
+baaapdmpob 1 300 train
+baajwwebva 1 300 train
+baapjchyrg 1 300 train
+baarzfneac 1 300 train
+babekszsfg 1 299 train
+babhuyhduk 1 300 train
+babihtuujy 1 300 train
+babiibjqdc 1 300 train
+babjudnaqd 1 297 train
+babnfhxgfj 1 300 train
+babywbbwpx 1 300 train
+babzibbuuh 1 300 train
+bacaqitswp 1 300 train
+bacbsuewui 1 241 train
+bacndmsxqj 1 300 val
+bacnffbyky 1 300 train
+bacpnbcdaz 1 300 train
+bacrdkbsdk 1 298 train
+bacrfnbhvo 1 300 train
+bactcvwhqk 1 300 train
+badfzsekpa 1 300 train
+badkwlcjqx 1 300 train
+badwlnskwz 0 300 val
+baeajscskm 1 300 val
+baehmngomx 1 301 val
+baekvryyob 1 301 val
+baeoscgqoe 1 300 val
+bafhgiizip 1 300 train
+bafievwatz 1 300 train
+bafktkorci 0 300 train
+bafmfdwiej 1 300 train
+bafqqiaphh 0 300 train
+bagbacpxjk 1 300 train
+bagkrkxqcp 0 300 val
+bagkzlffuh 1 299 val
+bagmoeqyny 0 300 val
+bagotfeeki 1 300 train
+bagssbeokq 1 300 val
+bagzgohqjw 1 297 val
+bahdhnhycu 1 300 train
+bahdpoesir 1 300 train
+baheacsakw 1 300 train
+bahgibkjek 1 300 train
+bahpguunin 1 301 train
+bahsfbqxur 1 300 train
+bahwryithf 1 300 train
+baiefifser 1 300 train
+baixgpvwme 1 300 train
+baiyzipjbr 1 300 test
+bajfrpmupx 1 300 train
+bajlbtvhxf 1 300 train
+bajmqwxtxp 1 300 val
+bajoyrzwaa 1 299 train
+bajuhwyats 0 300 train
+bakkmiossx 1 300 train
+baklbjkzeq 1 241 train
+bakqyqhplh 1 300 train
+baktdytfjl 1 300 train
+bakuscluwn 1 300 test
+balbpgldho 1 300 val
+balgcurscn 1 300 train
+balgkhiurl 1 299 train
+balnmmarhv 1 301 train
+balpoltqvn 0 300 train
+baluvjaejs 0 300 train
+balwrahloa 1 300 train
+balxpjnzmm 1 300 train
+balxxkjlti 1 301 train
+balzcwwtpn 1 300 val
+bamddalkqb 0 240 train
+bamdyzznzg 1 298 val
+bamgpgbjtg 1 300 train
+bamgphbnub 0 300 train
+bamjrophaj 1 300 val
+bammhpbvqs 1 301 val
+bamtobqvtx 1 300 val
+bamubhhzdq 0 297 val
+bamuxfygeg 1 300 train
+bamvzqzroe 1 300 train
+banbcqfqmw 1 300 train
+bandnkwfej 1 300 train
+bangumygkm 1 300 train
+banjrnjzhb 1 300 train
+banknncuqo 1 300 train
+banvwdrhmc 0 300 train
+baogegrjtz 1 300 val
+baokkeqdxp 1 301 val
+baolpdzfsz 1 300 train
+baonabxsuj 1 300 val
+baonduohkn 1 300 train
+baoscylnfr 1 301 train
+baosvoxjxg 1 300 train
+baoszfmdlj 1 300 train
+baovivatgs 1 302 train
+baoyaflncn 1 300 train
+baphsbkpbz 0 300 val
+bapilhmhyc 1 300 val
+bapixmyzsy 1 301 val
+bapoghwlde 1 300 val
+bapyuafrxo 1 300 train
+baqeedculf 1 300 train
+baqledjaon 1 300 train
+baqoxzzalh 1 300 val
+baqsyainyu 1 300 val
+baqzozplgs 1 300 train
+barbcborgl 0 300 val
+bardworeop 1 300 train
+barfpcdpxe 1 300 train
+barmlxxrpt 0 300 train
+barozfunpn 1 300 train
+basgtuwbmh 1 300 train
+basjckrjdf 1 300 test
+basonwkpvy 1 300 val
+basxuzmctc 1 300 val
+bateuibxti 1 299 test
+batfgxokwg 1 300 val
+batgqxfifq 1 300 val
+batxxxccby 1 300 train
+baufmlwgtz 0 300 val
+baulkposcy 1 301 train
+baummvrmhl 1 300 train
+bautxrrlxf 1 300 train
+bauutjqiow 1 296 train
+bauxpvwpza 1 300 train
+bauyxacgfk 1 300 val
+bavaszoflz 1 300 train
+bavhucvtaq 1 300 train
+bavrdqilfs 1 300 train
+bavuczkuwv 1 300 train
+bavxkvnvua 1 255 train
+bawhghlfoi 1 300 train
+bawxauqnqk 1 298 train
+baxalwsuyl 0 300 val
+baxdvqglnu 1 300 train
+baxefshuvs 0 300 train
+baxhgxfwcm 1 301 train
+baxkmsihqv 0 300 val
+baxpshhrhc 0 300 train
+baxxugbqvn 0 300 train
+bayetfizox 1 300 train
+bayfgfsreo 1 300 train
+bayuahaydv 1 300 train
+bazehalfin 1 300 train
+bazuuilpib 1 300 train
+bazxcobmhk 1 300 train
+bbaeewtqei 1 300 train
+bbagpnnxnv 1 300 train
+bbahoyncjd 0 300 val
+bbbatqblyk 0 300 train
+bbbfwdexan 1 300 train
+bbbkqdlsyu 1 301 train
+bbbmfffsad 1 300 train
+bbbqniokoa 1 241 train
+bbbyrusiwe 1 300 train
+bbcghjqixf 1 301 train
+bbcibscbkq 1 300 train
+bbciiyrhoe 1 300 train
+bbcjkyhhuy 0 300 train
+bbclqpeapk 1 300 train
+bbcpbivknv 1 300 train
+bbcqhccwzk 1 298 train
+bbcuwadkaf 1 297 val
+bbdeidcmgb 1 300 train
+bbdhfyocmp 1 300 val
+bbdudcrakk 1 300 train
+bbduhazzmb 1 300 train
+bbdwfeznwk 1 300 train
+bbdyimyzbp 1 300 val
+bbdyjfklmg 1 300 train
+bbdymgviqv 1 300 val
+bbdzssjeen 1 300 train
+bbejqmiyvh 1 300 train
+bbenehhaze 1 300 train
+bbenggeukt 1 300 train
+bbeouqcdzs 1 300 train
+bbeyhbquql 1 300 val
+bbeyrxgxhw 1 300 train
+bbeywofslk 1 300 train
+bbfbvvnaak 1 300 train
+bbfewvawtu 1 300 train
+bbfflhbtsd 1 300 train
+bbfpygrvoa 1 300 val
+bbftdqokkt 1 300 train
+bbfwbwtqut 1 300 train
+bbfwlhanjw 1 300 train
+bbfxmlheds 1 300 train
+bbfzunyiaj 1 300 train
+bbgalsnffj 1 300 train
+bbgkukkicj 1 300 train
+bbgmchpnqd 1 300 train
+bbgsjyxpev 0 301 train
+bbgtrsseht 1 301 val
+bbhbhduxxq 1 300 train
+bbhjnxbdco 1 300 val
+bbhkszzsei 1 299 test
+bbhlolixfd 1 300 train
+bbhnngnuig 1 300 val
+bbhpvrmbse 1 300 train
+bbhrzugxmn 1 300 train
+bbhtcdzmgf 1 300 train
+bbhtdfuqxq 1 300 train
+bbhvpyzmiv 1 300 train
+bbhweyyufc 1 300 train
+bbhwlztebz 1 300 train
+bbioetewnc 1 300 train
+bbirmntrbi 1 300 train
+bbisgqelmk 1 300 val
+bbivjcyvcv 1 300 train
+bbjlbfgvke 1 300 train
+bbjqbowaaq 1 300 train
+bbjqqoqhmj 1 300 train
+bbjtivfdzq 1 300 train
+bbjtxcqkns 1 300 train
+bbjzfeubzw 1 300 val
+bbkatcxqpi 1 300 train
+bbkbbgrlzo 1 300 train
+bbkejegwft 0 300 train
+bbkprckncv 1 300 val
+bbkpsxyjvs 1 300 train
+bbkuwgusib 1 300 train
+bbkwwrlwpb 0 300 val
+bblcipnywx 1 299 val
+bblditzyqm 1 300 val
+bblhefvcya 1 300 train
+bbllfwgcir 1 300 train
+bbltbwkpzh 1 300 train
+bblxzqpbgm 1 300 train
+bbmagsmxrb 1 300 val
+bbmbkvcjze 1 300 train
+bbmozugqvj 1 300 val
+bbmstrmoaf 1 300 train
+bbmswifdvz 1 301 val
+bbmtfdyqsx 1 300 train
+bbmxeiukxe 1 300 train
+bbmzhxtcld 1 300 train
+bbnesewcot 1 300 val
+bbnpuynemf 1 300 train
+bbnusepqeh 0 300 val
+bbodlbylou 1 300 train
+bbodxnyhja 1 298 train
+bbofbtcbbf 1 300 train
+bbokqqvbdh 1 300 train
+bbolcqktfd 1 300 train
+bbomhhqbhk 1 300 val
+bbpgqdpija 1 300 val
+bbphjbqwae 1 300 train
+bbpjgsfveo 1 300 train
+bbpvyecxtd 1 300 train
+bbqauldhba 1 300 train
+bbqimlfqjw 1 300 train
+bbqlpkudxs 1 300 val
+bbqoigycue 1 298 train
+bbqosygkdg 1 300 train
+bbqvecgqxl 1 300 val
+bbrmcjbeqe 1 300 train
+bbrqnzlnyj 1 300 train
+bbrrplranq 1 301 val
+bbryxrqfcb 1 300 val
+bbsabvrpih 0 300 train
+bbssbtknlc 0 300 train
+bbtypvevoj 1 298 train
+bbuebaojot 1 300 test
+bbukdseshg 1 298 val
+bbuwxnpgvd 1 300 train
+bbuyagtrip 1 300 val
+bbvdfsuiki 1 300 train
+bbvgxeczei 1 300 train
+bbvjnnlrzm 1 300 train
+bbvouhpoys 1 300 train
+bbvycfumal 1 300 train
+bbvztvutfb 1 301 val
+bbwbopxbrv 1 299 test
+bbwckmtrao 0 300 train
+bbweboygsv 1 297 val
+bbwffycqmr 1 300 train
+bbwljkvsyt 1 297 train
+bbwndtahps 1 300 train
+bbwnmgecdf 1 300 val
+bbwqyoeski 0 300 val
+bbwrqfawrj 0 300 train
+bbwwbsccdf 1 300 train
+bbxqtnztyy 1 300 train
+bbxuciztza 1 300 train
+bbxxwijhxf 1 301 train
+bbyapzzbbp 1 300 train
+bbygubzrfk 1 300 train
+bbyheffqbo 0 300 train
+bbynajqcsf 1 300 train
+bbyosyhxzo 1 300 test
+bbyukepsyl 1 300 train
+bbyzlvgllp 1 300 val
+bbzatzlgpo 1 298 train
+bbzdjgrlvl 1 300 train
+bbzhbjylhl 1 300 train
+bbzmjgssik 1 300 train
+bbzxzoelqt 1 300 train
+bcagxtfenv 1 300 train
+bcahujpzri 0 300 train
+bcajvxttuv 0 241 train
+bcakmcwgit 1 300 train
+bcaswgbknh 0 300 train
+bcavrprfct 1 299 test
+bcawixfkln 1 300 train
+bcawximqto 1 300 train
+bcaxndbaki 1 300 train
+bcazkgzdop 0 300 train
+bcbaodgold 0 300 val
+bcbketsrwt 1 300 train
+bcblmplxod 1 300 train
+bcbohexwow 1 300 val
+bcbqxhziqz 0 299 test
+bcbrtcqtpt 0 300 train
+bcbrujsqxo 0 300 val
+bcbvgnidic 1 300 train
+bcbychjgfz 1 300 train
+bccaioaudk 1 300 train
+bccswlodnb 1 300 train
+bcdmlsqzbn 0 300 train
+bcdmnkzrqa 1 300 train
+bcdvykigus 0 300 train
+bcdytgumpn 1 300 train
+bceloyolhy 1 300 train
+bcemixwldi 1 300 train
+bcenttyeoc 1 300 train
+bceqyqwshk 1 300 train
+bcerevqzyr 1 300 train
+bcewwggmxu 1 300 train
+bcffyhvxcc 1 300 train
+bcfjomnjuw 1 300 train
+bcftegygrr 1 300 val
+bcfytrfgrp 1 300 train
+bcfzwkyukw 1 300 val
+bcgbvtfira 1 301 val
+bcgcdkjivz 1 300 train
+bcgdrxhjvd 1 300 train
+bcgievnwef 1 300 train
+bcgiywxzwi 1 300 val
+bcgjlsupne 0 300 train
+bcgjugkehl 1 300 train
+bcgnzohdlw 1 300 train
+bcgyyqgweu 1 300 train
+bcgzfrxbbz 0 300 train
+bchbiiqvnv 1 300 train
+bchidnmojc 1 300 train
+bchnbulevv 1 300 train
+bchqetfkok 1 300 val
+bchtuggmvh 1 300 train
+bcihtlgaqa 1 300 train
+bciijuybgq 0 300 train
+bcijqbastj 1 300 train
+bcipimmnmv 1 300 train
+bcipnhosil 0 300 val
+bcisypwgtf 1 241 train
+bcitfzbsnt 1 300 train
+bciuzbjoxq 1 299 test
+bcixruopcf 1 300 train
+bciypstymi 0 300 train
+bcjknckrtn 1 301 train
+bcjteassyd 0 300 train
+bcjuiazvil 1 241 train
+bcjuppebns 1 300 train
+bckalnjoyq 1 300 train
+bckdhmhdjk 1 300 train
+bckjlnaiun 1 300 train
+bckjuzbabv 0 300 train
+bckkuicgde 1 300 val
+bckorfknun 1 300 train
+bckqoiisbl 1 300 val
+bcktcgzhom 1 300 train
+bcktnbnnyv 1 300 val
+bckuzhtwyt 1 241 train
+bclifiizok 1 300 val
+bclnjhoqol 1 301 train
+bclowkiysp 1 299 train
+bclypwksbx 1 300 train
+bclzhymvmh 1 301 train
+bcmaaekzcm 1 300 train
+bcmfmmqgxc 1 300 train
+bcmkqueihh 1 300 val
+bcmkvzaoob 1 298 train
+bcmmomiuel 1 300 train
+bcmrkgjtdq 1 300 train
+bcmrwummzs 1 300 val
+bcnlcmrwks 1 300 train
+bcnoxdblgr 1 300 val
+bcoltrgajd 1 300 train
+bconsoupfq 1 300 train
+bcoorvngcn 1 300 val
+bcorltkxuf 0 300 train
+bcownucjtw 1 300 train
+bcoydxioxf 1 300 train
+bcpeexlkgq 1 300 train
+bcpfilxzop 1 300 train
+bcplxdpxss 1 300 val
+bcpnyacygj 1 300 val
+bcpqedpunw 0 300 train
+bcpsomlspv 0 241 train
+bcpvgwrxug 1 298 train
+bcpythngcj 1 300 train
+bcqbbilybx 1 300 train
+bcqbhshtgd 1 300 val
+bcqeebkqwp 1 300 train
+bcqgoxqhjc 1 147 train
+bcqielfoji 1 300 train
+bcqjzpgpbq 1 300 val
+bcqptrgmdt 1 300 train
+bcqqfmthwk 1 300 train
+bcqrunnwhl 1 297 val
+bcqzbksorh 1 300 train
+bcrajtjljy 1 301 train
+bcrcdkrgiv 1 300 train
+bcrhsbxuwu 1 241 train
+bcrnkbcppk 0 300 train
+bcrsadrqyz 0 300 val
+bcsfbiaujp 1 288 train
+bcsoaztfle 1 288 train
+bcsvkbjzwk 1 300 train
+bcsyzakipb 1 300 train
+bctcynauwa 1 301 train
+bctfgewcrt 1 298 train
+bctfkknjhy 1 300 val
+bctmdmfgza 1 297 val
+bctvsmddgq 1 300 train
+bctwtzhnje 1 300 val
+bcudplyevq 1 300 train
+bcujkpycpa 1 300 train
+bculuffwko 1 300 train
+bcunaygofh 1 300 train
+bcunmpqmwf 1 299 test
+bcuouavgkc 1 300 train
+bcutrzfodh 1 300 train
+bcuyvoqfms 1 298 train
+bcvcyvgowt 1 300 train
+bcvezeyggp 1 300 train
+bcvfczypjo 0 300 train
+bcvheslzrq 1 300 test
+bcvisrvzak 1 299 train
+bcvtvufngy 1 300 val
+bcvvewtfhx 1 301 train
+bcvwmegucr 1 300 val
+bcvzgovntj 1 241 train
+bcwhokjvfn 1 300 train
+bcwlrunlii 1 300 train
+bcwnlclhjh 1 300 train
+bcwpmauyhg 0 300 train
+bcwtjzsutw 0 300 val
+bcwwvilvbd 1 300 val
+bcwzqojgvx 1 298 val
+bcwzrffayj 1 300 train
+bcxbqjtedq 1 300 val
+bcxgxzusit 1 300 test
+bcxojybwjj 1 300 train
+bcxqltxxvd 1 300 val
+bcxxsfztlh 1 300 val
+bcycmmnpnf 1 300 train
+bcyzudcxcw 1 300 train
+bczguerkpm 1 300 train
+bdaehxfzbk 1 300 train
+bdaeuugdop 1 288 train
+bdahtcivcd 1 300 train
+bdamapnuof 1 300 train
+bdazqodumh 1 300 train
+bdbfpoumql 1 300 train
+bdbhekrrwo 1 300 train
+bdbmpsyevy 1 300 train
+bdbofdzikv 1 83 train
+bdbqrjjyak 1 300 val
+bdbryopkaa 1 300 train
+bdcaqfdoew 0 300 val
+bdcbrzfphv 1 300 train
+bdccqdncyo 1 300 train
+bdchfgyrzo 1 300 train
+bdcjyjvxsb 1 300 train
+bdcnzxibfz 1 300 train
+bdcvtxwdob 1 300 train
+bddbwurxar 1 300 train
+bddcuhbniy 1 301 train
+bdddojeyaz 1 300 train
+bdddopafjm 1 292 train
+bddgoatygz 1 300 train
+bddjdhzfze 0 300 train
+bddpvihkew 1 300 train
+bddycfotsn 1 298 train
+bdeniywtnn 1 300 val
+bdeouczrwb 1 300 train
+bdfdzayszz 1 300 train
+bdfswhbxlh 1 300 train
+bdftdpohva 1 300 train
+bdfzfjykst 0 300 train
+bdgcinijzt 1 299 test
+bdgipnyobr 1 300 train
+bdgmavlwan 1 300 train
+bdgspwardg 1 301 train
+bdgwwzxwll 1 300 train
+bdhbzwfiov 1 300 test
+bdhcxanaqy 1 300 train
+bdhhjzdatz 1 300 val
+bdhnxeeitg 1 300 train
+bdhoxfotli 1 300 val
+bdhtlpuywf 0 300 train
+bdhuoyfzuz 0 300 train
+bdhyqryoil 1 300 train
+bdicysuijs 1 300 train
+bdinoddvte 1 300 train
+bdiointpxx 1 300 train
+bdiooanzvc 1 301 train
+bdirxvjxlc 1 300 train
+bdiswjfefc 1 300 train
+bdivrfxtqv 1 300 val
+bdjbmmhlxe 0 300 train
+bdjhgodhko 0 300 train
+bdjifayiiu 1 300 train
+bdjxzbtadn 1 301 train
+bdkazhizye 1 301 train
+bdkdruulfj 0 300 train
+bdkgwjldke 1 300 val
+bdkhvnvvjj 1 300 train
+bdkihilpyw 1 241 train
+bdkjxdndjn 1 300 val
+bdkvriwfvy 1 300 train
+bdkwkatfzc 1 240 train
+bdkxovndlh 1 300 train
+bdlchpfqtb 1 300 val
+bdlgnrxrvd 1 300 train
+bdlvyppgtw 1 300 train
+bdlzynmlar 1 301 train
+bdmcnjipbq 1 300 train
+bdmhjkrxoj 1 300 train
+bdmjcelmcs 1 300 train
+bdmjqtymxg 1 300 train
+bdmmskzdar 1 300 train
+bdmvjkonon 1 300 train
+bdnaqemxmr 0 300 train
+bdnesbbphy 0 300 train
+bdnfczrxey 0 300 train
+bdnixtboql 1 300 train
+bdnlupllhk 0 300 val
+bdnoxibdvz 1 300 val
+bdnwuzgaew 1 298 train
+bdoadbahhf 1 300 train
+bdocvgclcs 1 300 train
+bdofjezrfi 0 300 val
+bdohxzepdl 0 300 val
+bdoribeoya 1 301 val
+bdotfompqj 1 300 train
+bdotoahnef 1 300 train
+bdpabmlzds 1 300 train
+bdpbctfndi 1 99 train
+bdpdzumsry 1 300 train
+bdpmicugbp 1 300 train
+bdppaexvrj 1 300 train
+bdptiuagpz 1 300 train
+bdpwzkrofr 1 299 test
+bdpxgwpdop 1 300 train
+bdqdarvhiv 0 300 train
+bdqffmwxqh 1 300 val
+bdqgzfgayh 1 299 val
+bdqgzjoamp 1 300 train
+bdqjtvrizk 1 300 train
+bdqmhkoehe 1 300 val
+bdqrqgwytw 0 301 train
+bdqrsasbda 1 299 train
+bdqshjkpxd 1 300 test
+bdqvamryhc 1 301 train
+bdrvacwwat 1 240 train
+bdrvwexsfj 1 300 train
+bdrwkfvjlm 0 301 train
+bdrwmmtyly 1 301 val
+bdrwwvxlek 1 300 train
+bdsdikqgtb 1 300 val
+bdsdjxvatu 1 300 val
+bdseiiwavo 1 297 train
+bdshamihxz 1 300 val
+bdshuoldwx 1 299 test
+bdsktfgzbz 1 299 val
+bdsopgtlmq 1 167 train
+bdsqflnetv 0 300 train
+bdstpdunks 1 300 train
+bdsxxaamze 1 300 train
+bdsyetykew 0 300 val
+bdsyzwsrzw 1 300 train
+bdtdtlhyha 1 300 train
+bdtioreslo 1 300 train
+bdtnxarnwm 1 300 train
+bdtwicokdu 1 300 train
+bdtybsixoz 1 302 val
+bduaqrlxea 1 300 train
+bduhuslewa 0 300 train
+bduthmcqmv 1 300 train
+bdvaxjdbft 1 300 train
+bdvlqubgig 0 300 train
+bdvqwpqmag 1 299 test
+bdvuqjupnd 1 300 train
+bdvzrmjuoe 0 300 val
+bdwacwjnnu 1 300 train
+bdwcnpsruv 1 300 train
+bdweezvxfc 1 300 train
+bdwjbzyorj 1 300 train
+bdwpyrudti 0 300 train
+bdwtgwbfkj 0 300 train
+bdxcfvbniu 0 300 train
+bdxfuszcwx 1 300 val
+bdxlkzmnyt 1 300 train
+bdxludmnux 1 300 train
+bdxuhamuqx 1 300 train
+bdyghmwvxu 1 300 val
+bdynuzrqbt 1 300 train
+bdypohxfxs 1 300 train
+bdyrlwexay 1 300 train
+bdyuwvpelk 1 300 train
+bdyxoqkyko 1 300 train
+bdyxxmudkt 1 301 train
+bdzcwwdfit 1 297 train
+bdzgchaaxp 0 300 val
+bdzprapxma 1 300 val
+bdztumelho 1 300 train
+bdzytcvbdt 1 300 train
+bdzzjqqekr 1 301 train
+beactrbhub 1 300 test
+beafisbhdv 1 300 train
+bealtzpnlk 0 300 train
+bearfhicjd 1 298 train
+bearkodqxk 1 300 test
+beasxridov 1 300 train
+beavrxvmqx 1 300 train
+beaweqchrq 1 240 train
+bebdmemovj 0 300 train
+bebfstfcgp 1 300 train
+bebmjrpvos 1 300 val
+bebngjmghz 1 300 train
+bebnleywrr 1 301 train
+beborlpxuy 1 300 train
+beboztfcme 0 298 train
+bebrgwqbot 1 300 train
+bebsbklxgz 0 301 train
+bebuhxbiym 1 300 train
+becctvxykt 1 298 train
+becfjonwfu 1 300 val
+becimdnxwc 0 300 train
+becjjdnvpn 1 300 train
+beclytxiol 1 299 test
+becmtivmwm 0 300 train
+becoatlxqm 1 300 train
+becqadbtkb 1 300 train
+becrsvtafz 1 300 train
+becuavants 1 298 val
+becyhoonnm 0 300 train
+bedebkalii 1 300 val
+bedepmgvzy 1 300 train
+bedgiweloz 1 300 train
+bednaxvzbt 1 241 train
+bedugmnxov 1 288 train
+bedwpfaghf 1 300 train
+beebrqboob 1 300 train
+beebxwvqli 1 300 train
+beeehdcwso 0 300 train
+beeelfonyn 1 300 train
+beefhzclcw 1 300 train
+beegfitfyr 0 300 train
+beemayhwxc 1 300 val
+befdggddui 1 300 val
+befkxqjbox 1 300 test
+beflbtfydl 0 300 train
+beghrisqya 0 300 train
+begigijiiq 0 300 train
+begolhmsru 1 241 train
+begozxasac 1 300 train
+begsvayjvq 1 300 train
+begxnxtome 1 301 val
+begyynegyx 1 300 train
+behdsfoxnk 0 300 train
+behhgrhkmc 1 300 train
+behkealmti 1 300 train
+behlbelncd 1 300 train
+beicdocurn 1 300 train
+beiqvcoxym 1 300 train
+beivsoemaa 1 300 val
+bejaewmooz 0 300 val
+bejblmnabd 0 300 train
+bejhvclboh 0 300 train
+bejrxclqgh 1 300 train
+bejyjklqkv 1 300 train
+bejyovndin 1 300 train
+bekamukelt 1 298 train
+bekfuiifpr 1 300 train
+bekilotbxu 1 300 train
+bekmufolps 1 300 train
+bekuilzxxn 1 298 val
+bekvvpeolr 1 300 train
+belewgtmbs 0 300 train
+belhsfgafi 1 300 train
+belqgihdjp 1 300 val
+beltfmbgvb 1 300 val
+beltsyfcmh 1 301 val
+belwinawhy 1 300 train
+bemegycftg 1 300 train
+bemfujaktg 1 300 train
+bemkbovwsz 1 300 val
+bemmydljot 1 298 train
+bemqbwgxxs 0 300 train
+bemrvkpmbw 0 300 train
+bemtodhzoz 0 300 train
+bemzjclvgu 1 302 train
+benkzrmryl 1 300 train
+benlmmdcnf 1 300 train
+benmsfzfaz 1 300 train
+bennfkianl 1 300 val
+benxwujzwl 1 300 train
+benyrkbvzv 1 300 val
+benzxvtapn 1 300 train
+beocsyoqed 1 300 val
+beoeofnqpa 0 300 train
+beoftnkaok 1 301 train
+beonlzcydr 1 300 train
+beoobdybbw 1 300 val
+beoohhpboz 1 299 train
+beosdmoipb 1 300 val
+beotixrzpw 1 300 train
+beoudnupot 1 298 train
+bepdicbepv 1 300 train
+bepfmkgqcw 1 302 train
+bepqosfgtm 1 300 train
+beprdsgeep 1 300 val
+bepvyljmsw 0 300 train
+bepysrlpzr 0 300 train
+beqbaxvahc 1 300 train
+beqbcfymww 1 300 train
+beqcgqmqkf 1 300 train
+beqffgbdaf 0 300 train
+beqkwtlvux 1 300 train
+beqqpddhfq 1 300 train
+berbcixvjc 1 300 train
+berhtdrcya 0 300 train
+beridjgqtm 1 300 train
+bermjyfulo 1 300 train
+bernwheesw 1 300 train
+berrastjdv 1 300 train
+bersbtebdv 0 300 train
+besaakdbin 1 300 val
+besbeekiaz 1 300 train
+beshruwzkt 1 300 val
+besjqehhps 1 300 val
+besjxzxhqy 1 301 train
+besxmxaefx 1 300 train
+betdiwiwql 0 300 train
+bethubglgn 0 300 train
+bethzdptir 1 300 train
+betpyxtdba 1 300 train
+betuzngwpt 1 300 train
+betxlrlfsv 1 300 train
+betxmldjqa 1 300 train
+betzeachui 1 300 train
+betzkoibel 1 300 train
+beueokqiuo 0 241 train
+beunhwksjw 1 300 val
+beuqejurhq 1 300 train
+beutkgdtcb 1 300 train
+beuuuidoiq 1 296 train
+beuzicnshd 0 241 train
+bevaljphpp 1 301 val
+bevbgiztdc 1 300 train
+bevijjvici 1 241 train
+bevjclbhuo 0 300 train
+bevoadncox 1 300 train
+bevpwootah 1 300 train
+bevrsulvkt 1 239 train
+bevspulfsl 1 300 train
+bevtlaxijd 1 300 train
+bevvboclnc 1 300 train
+bevvdbvruf 1 300 train
+bewbohouqa 1 299 val
+bewdlknhhi 0 300 train
+bewobhaofv 0 300 train
+bewruzjlng 0 300 train
+bewwwxnzbk 1 300 train
+bexggkibht 1 300 train
+bexirkzrhv 1 300 train
+bexljqnnqg 1 300 val
+bexltdjzun 1 300 train
+bexxqeohiv 1 300 val
+bexyrzykzu 1 300 train
+bexzlindzv 1 300 val
+beyebyhrph 0 300 train
+beyegcvfkr 1 300 val
+beyhcwgavh 1 300 train
+beypnhydse 1 300 train
+beyrhsvlrt 1 300 test
+beysxgrqkk 1 301 train
+beyxfbmgrw 1 300 train
+beyxpliwsy 1 300 train
+bezccrfklu 1 300 train
+bezlbssete 1 300 train
+bezxyrovyz 1 300 train
+bfajqsxjis 1 301 train
+bfajruognp 0 300 train
+bfajryuvdg 1 300 train
+bfapvakyen 1 300 train
+bfauslmpjh 1 302 train
+bfawveelwz 1 300 train
+bfaxajoxti 1 300 train
+bfbpgqcfwi 1 300 val
+bfcdbaevbj 1 300 val
+bfcejaynie 0 300 train
+bfcmnlwsiq 1 241 train
+bfcmxcvwps 1 167 train
+bfcptqxlvw 1 300 train
+bfcsnjkhza 1 300 train
+bfcuoaihns 0 300 train
+bfcvdqwvwb 1 300 train
+bfcyypufaf 0 302 train
+bfdbfbfzcz 1 300 train
+bfdbybhxvr 1 300 train
+bfdfkbmkva 1 300 train
+bfdgzjrnck 1 300 train
+bfdieyuhkl 0 300 val
+bfdixupnnt 1 300 train
+bfdlyfihvy 1 300 val
+bfdnlyosad 0 299 train
+bfdogcazue 1 300 train
+bfdopzvxbi 0 300 test
+bfdxhnfacf 1 300 train
+bfecraawwz 1 300 train
+bfeewgzrbr 1 300 val
+bfefohyaqy 1 300 train
+bfegqqytki 1 288 train
+bfevrsgehw 1 300 train
+bfevvflqsy 1 300 train
+bfexklkiyj 1 300 train
+bfeycvkedq 1 300 train
+bffavsfxqi 1 241 train
+bffeslonih 1 301 train
+bffjkyuqvb 1 300 train
+bffkfspkvz 0 300 val
+bffozowhov 1 300 train
+bffrdavndf 1 300 train
+bffrlzfhkc 1 300 val
+bffrotkdcu 1 300 train
+bffuderusr 1 300 train
+bffufthwtk 1 300 train
+bffvmcfeyu 1 300 train
+bffwsjxghk 0 300 train
+bfgcgkfrde 0 300 train
+bfgfvcofvn 1 300 train
+bfgkbvemcr 0 300 train
+bfgrxafoef 1 300 train
+bfgsibgras 1 300 train
+bfgykgohpy 1 301 train
+bfgzqxwhti 1 300 train
+bfhgudaysl 1 299 train
+bfhjmxlrja 0 300 train
+bfhkzqdwbx 1 300 train
+bfhrtnnwmi 1 300 train
+bfhtddaoqy 1 300 train
+bfhvcmnkmz 1 300 train
+bfibrgtvjc 1 300 test
+bfifbfziqw 1 299 train
+bfiimlamny 1 300 train
+bfikaojgbu 1 301 train
+bfitiqnegg 1 300 val
+bfitywlemf 1 300 train
+bfiuowgwfu 1 300 val
+bfiztrjizr 0 300 val
+bfjajtyjzt 1 300 train
+bfjdshvayr 1 300 val
+bfjeavwnoi 0 300 train
+bfjfdlrkgt 1 301 val
+bfjnphaqfz 1 300 train
+bfjsthfhbd 0 300 test
+bfjwtlumpn 1 300 train
+bfjzxatdrc 1 300 val
+bfkfrtmiub 1 300 train
+bfklxuaity 1 300 train
+bfkmmtobhs 1 300 val
+bfkndtkpqn 1 300 train
+bfktkdugru 1 300 test
+bfkzrgovsv 0 300 train
+bflarmyzne 1 300 train
+bflfstbixw 1 300 val
+bflhdbgkkb 1 300 train
+bflhvfizhu 1 300 train
+bfliazfiyf 1 300 train
+bfljjbavig 1 300 train
+bfllocpabl 1 302 val
+bflnrgqguc 1 99 train
+bflrmwntvn 1 300 train
+bflrnxrmfb 1 300 train
+bflrohpklz 1 300 train
+bfluunemxz 1 300 val
+bflvmtnyyb 1 300 train
+bfmebxfyax 1 300 train
+bfmkqqxlgq 1 301 train
+bfmogqdknz 1 298 train
+bfmoopvnho 0 300 train
+bfmvjimrqn 1 299 test
+bfnavigkkm 1 300 train
+bfnbhaitpo 0 300 train
+bfnbolopux 1 300 train
+bfncwtolzs 1 300 train
+bfnockrztt 1 300 train
+bfnossqoxp 0 300 val
+bfnoyyfneh 1 300 train
+bfnqjiamdr 1 301 train
+bfnrgcfmdp 1 300 train
+bfoaqbobup 1 300 val
+bfodvgkqbg 1 300 train
+bfoerwzxjl 1 301 val
+bfofpyvvnt 0 300 val
+bfoktrnuxj 1 300 train
+bfokutsmfl 1 300 train
+bfoozhcgse 1 300 train
+bfowhabcyv 1 300 train
+bfpeepmhhb 0 300 train
+bfpgosmnqv 1 300 train
+bfpqojyrkp 1 299 val
+bfpqsiancp 1 300 val
+bfpukwgayc 1 300 val
+bfpwkwfwvq 1 300 val
+bfpzbmminl 1 300 train
+bfqgcgygsw 0 300 val
+bfqgftdadt 1 143 train
+bfqjqairog 1 300 train
+bfqlqydtam 0 300 train
+bfqmshszcu 1 249 train
+bfqumzcsvu 1 300 train
+bfqyovgynr 1 300 val
+bfrbtmnllp 1 300 train
+bfrdlnqald 1 300 train
+bfrhbglqus 1 300 train
+bfrpbogxps 1 298 train
+bfrtyndaac 0 300 train
+bfrwghgtrn 1 300 train
+bfsbhdzvfd 1 288 train
+bfsjasmdpd 1 298 val
+bfsnakisid 1 300 train
+bftaroylmh 1 237 train
+bftezzwmcr 1 300 train
+bftgduqoct 1 241 train
+bftgerkvls 1 300 train
+bftknghhed 1 300 val
+bftmxmxywu 1 300 val
+bftqgyprmz 1 300 val
+bftrhnojyt 1 236 train
+bftztxnheg 1 300 test
+bfukrxvndm 1 300 val
+bfupvodqkz 0 300 train
+bfutthnppf 1 300 train
+bfvecorcjd 1 300 train
+bfveicsuwq 1 300 val
+bfvgpmmiex 0 300 train
+bfvqrltnpc 1 300 val
+bfvsdasdkq 1 300 train
+bfwgingqsv 1 300 val
+bfwmhauynh 1 298 train
+bfwrkaogup 1 300 val
+bfwsibszqq 1 300 train
+bfwuqtejgm 1 300 train
+bfwwampoar 1 300 val
+bfwwrlwopy 1 300 train
+bfwxsurxjv 1 240 val
+bfwygztkfb 1 301 train
+bfwynqcxiz 1 240 train
+bfxeijwtbl 0 300 train
+bfxevozqyq 1 300 val
+bfxqzalgdj 1 300 val
+bfxvqyifpe 1 300 train
+bfyhfmdztn 1 300 train
+bfymzjjfkm 0 300 val
+bfynhjklyo 1 300 val
+bfywfjjots 1 300 val
+bfyxwqsyhd 1 300 val
+bfzkkcltvf 1 300 train
+bfzlaauaqy 1 300 train
+bfzvzyidrj 1 300 train
+bfzxyyxzoi 1 300 val
+bfzylgxdsh 1 300 train
+bgaafmocsn 1 300 train
+bgabrlwmjz 1 300 train
+bgacxwakmz 1 300 val
+bgaogsjehq 1 300 train
+bgatyjdowa 1 300 val
+bgaylepgml 1 300 train
+bgbcqsopdw 1 300 train
+bgbkbvdjnd 1 300 train
+bgbkogrfys 0 300 val
+bgbompfabg 1 300 train
+bgbpheojle 0 300 train
+bgbuqmmaqe 1 300 train
+bgbykpybnp 1 300 train
+bgcdzljbvs 1 300 train
+bgcectalof 1 300 val
+bgcfsiswtj 1 300 train
+bgcolixxne 1 300 val
+bgcphugrob 0 269 train
+bgcuvhbfkz 1 300 val
+bgcvbayfhn 0 300 val
+bgcxzjipkn 1 300 val
+bgddhwgtgk 1 300 train
+bgdehyzokn 1 300 train
+bgdhmiplel 1 296 train
+bgdokxsepy 1 300 train
+bgduhdhubv 1 298 val
+bgeacsngmi 0 300 train
+bgebfcoxuz 1 300 train
+bgebgmkxyc 0 241 train
+bgeeccvcjv 1 241 train
+bgenhtsnnp 1 300 val
+bgexonjbpn 1 300 train
+bgffrxwrms 1 300 train
+bgfjmcfzev 0 300 train
+bgftflstam 0 300 train
+bgghsleghu 1 300 val
+bgghtzmkcf 1 300 train
+bggikytkou 1 301 train
+bggisaihct 1 301 train
+bggsurpgpr 1 300 train
+bghcevlhjf 1 300 train
+bghgqeswsj 1 299 train
+bghkkhglyk 1 301 val
+bghmhuxxyr 0 301 val
+bghphrsfxf 1 300 train
+bghpxawcnb 0 300 train
+bghscpvrbt 1 300 val
+bghvplwlhc 1 300 train
+bgicufggmb 1 300 train
+bgihlcqcik 1 300 train
+bgihvznzbf 1 300 train
+bgikmnyvlh 1 300 train
+bgilmjxago 1 300 train
+bgilydppiv 1 300 train
+bgisxylcbw 1 300 val
+bgiukncdoc 1 300 train
+bgjcqrvoyb 1 300 train
+bgjghivhji 0 300 train
+bgjuqdjnss 1 300 train
+bgjyidaspl 1 300 val
+bgkjyalpix 0 300 train
+bgkmfxsqxd 1 300 val
+bgkmgallha 1 300 train
+bgkoodawio 1 300 val
+bgkspwrqlr 1 300 train
+bgkwhempmn 1 301 train
+bgkysyqffh 1 299 train
+bglchyhsuf 1 300 train
+bglhztchfd 1 301 train
+bglklkiayu 1 300 val
+bglqkukirr 1 302 train
+bglsrppmtk 0 298 train
+bgmaztzqse 1 300 train
+bgmhuxmtou 1 300 train
+bgmlfjiheo 1 300 train
+bgmlwsoamc 1 300 train
+bgmnilhgac 1 241 train
+bgmofsdxst 1 300 val
+bgmoxzfllh 1 302 train
+bgmsbthrmj 1 300 train
+bgmtdhbzny 1 301 train
+bgmzzxkwdz 0 301 train
+bgneigofxm 1 300 val
+bgnlimiiff 1 301 train
+bgnnnhzncc 1 300 train
+bgnobjzsva 1 301 val
+bgnwsxocup 1 297 train
+bgnxqmdjxq 1 300 train
+bgnxtocxqo 1 300 train
+bgohzkqrss 1 300 val
+bgoiditweq 1 300 train
+bgoiwkpmml 1 300 train
+bgolzgiqxg 1 301 val
+bgoqngtleo 1 300 val
+bgpdudgyab 1 300 val
+bgpdzlrluk 1 301 train
+bgpgoxfouy 1 300 val
+bgphlvduwf 1 301 train
+bgpmkktrss 1 300 val
+bgpnbmjuqq 1 300 train
+bgpniillwo 1 300 train
+bgpnirgwsl 1 300 train
+bgpobwqwmr 1 300 train
+bgpoldvzrh 0 299 train
+bgpsjixtwm 1 301 val
+bgpwqfqnbi 1 300 train
+bgpzkygcea 1 300 val
+bgpzxthrqp 1 300 train
+bgqeqhunsq 1 301 val
+bgqgtxbaxx 1 300 train
+bgqhldvsgc 0 300 train
+bgqnopotbe 0 300 train
+bgqqtjfgsv 1 300 train
+bgquoxhevh 0 300 train
+bgqvaldacu 1 298 train
+bgqxhvcncy 0 300 val
+bgrazuzabd 1 300 val
+bgrdfeoydq 1 241 train
+bgrhnabzur 1 300 train
+bgrkttmsxd 1 300 train
+bgrradjndh 1 300 train
+bgshhomcpq 1 300 val
+bgslobeeyd 1 300 train
+bgslonazqf 1 300 train
+bgsluarwyl 0 300 val
+bgsokbksmw 0 300 train
+bgsqoctomw 1 300 train
+bgsrdqcqjx 1 300 train
+bgsrgxerbk 1 299 val
+bgssgjrhxi 1 300 train
+bgssriyozb 1 300 train
+bgstlvtorb 1 300 val
+bgswtwkxvc 1 300 val
+bgsyvyclgh 1 298 train
+bgtdimeznz 1 300 train
+bgtgxubqmy 1 300 test
+bgthumekak 0 300 val
+bgtiikryvg 1 300 train
+bgtjwkpzec 0 300 train
+bgtmncrsyj 1 300 train
+bgtptuhstj 1 301 val
+bgtridlkdi 1 300 val
+bgtvaxxqom 1 301 train
+bgtvsmksqq 0 300 train
+bgtvzcgmvk 1 300 train
+bgtzweckzk 1 300 train
+bgulsntdfd 1 300 train
+bgulswwjgs 1 300 train
+bguwlyazau 1 300 train
+bguxmfaihe 0 300 train
+bgvbeqrgtc 1 300 train
+bgvbfxvamo 1 300 train
+bgvhtpzknn 0 300 train
+bgvjswnndb 1 298 val
+bgvjvvuvgb 1 300 val
+bgvknboeyq 1 300 train
+bgvojycuju 1 300 train
+bgvuxeubtf 1 300 val
+bgvwgianhf 1 300 train
+bgvxznyhqg 1 300 train
+bgwcfsaacz 1 300 train
+bgwesydxhq 1 300 train
+bgwhydslda 1 300 train
+bgwlaabsnl 1 300 train
+bgwmechesv 1 299 train
+bgwmmujlmc 0 300 train
+bgwmmwgmgk 1 300 train
+bgxdeluogh 0 300 train
+bgxdumpvrv 1 301 train
+bgxftrukbr 1 300 train
+bgxjabrhbg 1 300 train
+bgxlldsfmx 1 300 train
+bgxmruicge 1 301 train
+bgxpmpwcyg 0 300 train
+bgxqvmjgbm 1 300 train
+bgxvfdqcgg 0 300 train
+bgxvtdyush 1 300 val
+bgxxyytpnf 1 300 train
+bgyaqospgo 1 300 test
+bgycggxsky 0 300 val
+bgyfrdkbsj 0 300 train
+bgyimohqak 1 300 train
+bgymmjkbec 1 300 train
+bgyqwxcrsm 1 300 train
+bgyreqkyzf 1 300 train
+bgyrspukmk 1 300 train
+bgyzvpllxi 1 298 train
+bgzcvwoboe 1 300 train
+bgzejupjsn 1 301 train
+bhaaboftbc 1 300 train
+bhaaitemak 1 301 train
+bhacfzlqov 1 300 val
+bhahkwkxor 1 300 train
+bhasetirqb 1 300 train
+bhbakfaqvk 1 300 val
+bhbbqmdjkv 1 300 test
+bhbbrbqcgp 1 300 train
+bhbcuzpogd 0 300 train
+bhbdbhcqlh 0 300 train
+bhbdugnurr 1 300 train
+bhbkalayvx 1 300 train
+bhbnvkiwti 1 300 val
+bhbzzmnpht 1 300 train
+bhcaxpyavd 1 300 val
+bhcbgpnkpd 1 300 train
+bhcdshvqor 1 300 val
+bhchlbmzrc 1 300 train
+bhchuiowho 1 301 train
+bhcivkoeto 0 300 train
+bhcpsexpir 1 300 train
+bhcytcdxeb 1 300 train
+bhdckalrgx 1 300 val
+bhdekznjrb 0 300 train
+bhdorwlgel 1 240 train
+bhdrdqfehh 1 300 train
+bhduhrsxak 1 300 val
+bhebbvkawn 1 301 val
+bhepzisvro 1 300 val
+bhetenlzsp 1 300 test
+bheujthifr 1 300 train
+bhffrlwbrx 1 300 val
+bhfihhudau 1 300 train
+bhfpmvpmyw 1 300 train
+bhfxttitcb 1 299 test
+bhgjhzlage 0 241 train
+bhguavqyfj 0 300 train
+bhgxmwbuzr 0 300 train
+bhgxwxvrks 1 301 train
+bhhdgzyimt 1 300 train
+bhhjopuypx 1 300 train
+bhhkyewexj 1 300 train
+bhhlpxdugp 1 300 train
+bhhmhvvwvd 1 301 train
+bhhmxcerkg 1 300 train
+bhhwqrmvgt 1 300 train
+bhhyypufqy 1 241 train
+bhidtfximd 1 300 test
+bhidxblmbv 1 300 train
+bhieufgnnf 1 300 val
+bhifvlgump 0 300 train
+bhiicjomwj 1 300 train
+bhinkhmewt 1 300 val
+bhiprtqyon 1 299 train
+bhirvndalc 1 300 train
+bhiuelvdgr 1 300 train
+bhjbjznqko 1 300 val
+bhjdhrylae 1 300 val
+bhjmnscriw 1 300 val
+bhjmyjcayb 0 300 train
+bhjqmlqvch 1 301 train
+bhjscxpzjg 1 302 train
+bhjwfpvcvq 1 300 train
+bhkfrmjlpv 1 300 train
+bhkjrexduj 1 300 train
+bhknvnxxnw 1 298 val
+bhkpkcxaqu 1 300 train
+bhkvkncawg 1 240 train
+bhlelcjvoq 0 300 train
+bhlharrhys 1 300 train
+bhlibcqirb 1 300 train
+bhliuvpgub 1 300 val
+bhlnbwopiw 1 300 train
+bhlxxeqtlk 1 300 train
+bhlyasmjqj 0 300 train
+bhmeqebvvc 1 300 train
+bhmfpkjsbz 1 300 val
+bhmnjbwzuh 1 300 train
+bhmufiyfjs 1 300 val
+bhmwkkxunf 1 300 train
+bhneimyaiz 1 300 val
+bhnlaxgvrf 1 300 train
+bhnlhiioij 1 300 train
+bhnlujskfu 1 301 train
+bhnnjjpgzk 1 300 train
+bhnphupuza 1 300 train
+bhnxgzigwg 1 300 train
+bhnzlhkajv 1 300 train
+bhoanxucio 1 298 train
+bhoklfxbmz 1 300 train
+bhowwrobya 1 300 train
+bhpajnpmeo 1 300 train
+bhpcqftpdm 1 300 train
+bhpddjewrv 0 300 train
+bhpddnqauc 0 300 train
+bhpepgttmi 1 300 train
+bhpgxnitwb 1 300 train
+bhpiiawcrz 1 300 train
+bhpwpydzpo 1 300 train
+bhqardaoba 1 298 train
+bhqcqwcise 0 301 train
+bhqdtqspji 1 300 train
+bhqiisfkui 1 300 train
+bhqteplzxp 1 300 train
+bhqtkitcvk 1 300 train
+bhrpiyqspc 1 300 train
+bhrzhsebbm 1 300 train
+bhsbxnalvq 1 300 train
+bhsklnhjrj 1 300 train
+bhsluedavd 1 300 train
+bhsmpxgdia 1 241 train
+bhtoegtzyi 1 300 train
+bhtoxwgarp 1 300 val
+bhtpbkfwdd 1 300 val
+bhtpnsaigv 1 299 val
+bhtrchmzkq 1 300 train
+bhtrhmtfvu 1 300 train
+bhtrjjtato 1 300 train
+bhtwyqgbeg 1 300 val
+bhtzxqutab 1 300 train
+bhumkuzoeo 1 241 train
+bhuxqlizqw 1 298 train
+bhuyzxvohl 1 300 train
+bhvadkcgfm 1 300 train
+bhvgnyuybi 1 300 train
+bhvnfaylpk 1 300 test
+bhvrdxzcco 1 300 train
+bhvssfromy 0 300 train
+bhwdqztgmq 1 300 train
+bhwevhjvwx 0 300 train
+bhwiblpyub 1 300 train
+bhwlgymgxk 1 300 train
+bhwnrkrlxk 1 300 train
+bhwomacivv 1 300 val
+bhwrpwervy 1 300 val
+bhwujfazqy 1 300 train
+bhwwzofqvo 1 300 train
+bhwydehfex 1 298 train
+bhxcinrqmc 1 300 train
+bhxgeompsl 0 300 train
+bhxiufgdxa 1 300 train
+bhxocyygxb 1 300 train
+bhxtomcnqv 1 300 val
+bhxvkeygvv 1 300 test
+bhybofqflj 1 300 train
+bhybspbwwa 0 300 val
+bhyftkjnxb 1 300 train
+bhykihwhkv 1 300 train
+bhysvzstxz 1 300 train
+bhyzjrwkvk 1 295 train
+bhzfcdzqar 1 300 train
+bhzhtdtuvz 1 241 train
+bhzhzvadnn 1 167 train
+bhzkyouhao 1 300 train
+bhzmcktrkb 1 300 train
+bhzoipaxsp 1 300 train
+bhzosxdmyt 1 300 train
+bhzrapafro 1 300 train
+bhzwgteaic 1 300 train
+bhzxjhcwgj 1 300 train
+bhzyjsztok 1 300 train
+bhzyyqtqei 1 300 train
+biaalpexjt 1 300 train
+biabyexhff 0 300 val
+biactglfwl 1 300 train
+biadezsblv 1 300 val
+biamfehslm 1 241 train
+biatmogsbv 1 300 test
+bibjgxjhuv 0 300 train
+bibngtstif 1 241 train
+biborxaekt 0 300 train
+bibpelmopy 1 300 train
+bibszgugnx 1 300 train
+bicaybbcfg 0 300 train
+biccegbekb 1 298 train
+bicenrlrcf 1 300 val
+bicexletbj 1 300 train
+bicizvojrg 1 300 train
+bickzzulsq 1 241 train
+bicnsxyooy 1 300 train
+bictntmeob 1 300 train
+bicyhiobff 0 300 val
+bidadvzxgm 1 299 val
+bidfiduqsr 1 300 train
+bidlydtbkf 1 300 train
+bidognfjqs 1 300 train
+bidulzdkec 1 300 train
+biebcflser 1 300 train
+biecivdxsy 1 300 train
+biecvobxdt 1 300 train
+biedigqtiw 1 300 train
+biefjlethf 0 300 train
+bieojeixtf 1 300 train
+biergxlxmd 1 300 train
+biesrefymb 1 300 train
+bieuiqiqwj 0 298 val
+bifaizxtsc 0 300 train
+bifeiowfeu 1 300 train
+bifeuhwdfj 0 301 train
+bifnyjkhek 1 301 val
+bifohxzhwe 1 300 train
+bifqebyysh 1 300 train
+bigagjdpdt 1 300 train
+bigbqhgvof 1 300 train
+bigcuppwcf 1 300 train
+bigelmprhp 1 300 train
+bighjkdqxa 1 300 train
+bigruojxrp 0 300 train
+bigwzvlzhb 0 300 train
+bihdarejma 0 300 val
+bihhlazttc 0 300 train
+bihkgddzdo 1 255 train
+bihlajjbnl 1 300 test
+bihqnanaoq 1 300 train
+biibogyrpt 1 300 train
+biicqbqajx 1 300 train
+biihbnwecq 1 300 train
+bijcbfrxyc 1 300 train
+bijcrevctl 0 300 train
+bijmjhpvgg 0 300 train
+bijnzrftzz 1 300 train
+bijpqxgyug 0 300 train
+bijsoecgyp 1 300 train
+bijvvsgumf 1 300 train
+bijzpkoaja 1 300 train
+bikapsyjfg 1 300 val
+bikehwjuzk 1 300 train
+bikrimaoum 0 300 val
+biksijpktj 0 300 train
+bikymqckfq 1 300 train
+biljtwvytw 1 300 val
+bilmscjhgl 1 300 train
+bilnggbxgu 0 300 train
+bilsagmnhr 1 300 train
+bilwtjqxak 1 300 train
+bilylzpjwj 0 300 train
+bimbdboxdb 1 300 train
+bimmohdxvc 1 300 train
+bimmxgieic 1 300 train
+bimpdnrgxw 1 300 train
+bimrevkxcc 1 300 train
+bimroumchp 1 300 train
+bimslulfed 1 300 train
+bimzrbzktf 1 294 train
+binbaztlye 1 300 train
+binjbtuzkr 1 300 train
+binmffjjvl 1 298 train
+binnsdnqfe 1 300 train
+binribybof 1 300 test
+binrkjcwxe 1 300 val
+binymyngeo 0 300 train
+bioaextmva 1 300 train
+biolbvjlzx 0 300 train
+biopqmyucz 1 300 val
+biotwaakin 0 300 train
+biotzvraxy 0 300 train
+biowbdsrne 1 300 train
+bipeokitdv 1 300 train
+bipkwdckrk 1 300 train
+biplfrodhb 1 300 train
+bippiycqws 1 300 val
+biqgaxvjyy 1 300 train
+biqvbrfdyj 1 300 train
+biqvdjgtrv 1 300 train
+biqxviyfdo 1 300 val
+birclphnsf 1 300 train
+bireyekpmd 1 240 train
+birhdtntif 1 300 train
+birhfcgkot 1 300 train
+birjnwdpbg 1 300 train
+birkvvqnmh 0 300 val
+birmbtezni 1 300 test
+birnqzxcga 1 300 val
+birqcqcbxc 1 300 val
+birwckbwcr 1 300 val
+bisdcbeipo 1 300 train
+bisevvlcfm 1 300 train
+bisfdlcbva 1 300 train
+bisjawdsao 0 300 train
+bisoehzztd 1 241 train
+bispzrzegu 1 298 train
+bisyqoikns 0 300 val
+bisyrvqxvg 1 300 train
+bitgmpsjko 0 301 train
+bithritjse 1 300 test
+bitjeasukl 1 300 train
+bitlskxuct 1 300 val
+bitticunoc 1 300 train
+bittnmrwww 1 300 val
+bittxslmgp 1 299 test
+bitwvzgcqt 1 300 train
+biujwiagmx 1 300 val
+biuqixndfy 1 300 train
+biuwqkhfhr 0 300 train
+bivdbsqzbq 1 300 train
+bivfenlysj 1 300 train
+bivgdpypxh 1 300 train
+bivlawbbmm 1 300 train
+bivqumlojf 1 300 train
+bivvdqhxdn 1 300 train
+bivyxqxxpd 1 300 val
+bivzhsmrqo 0 300 train
+biwccgiiju 1 300 val
+biwcfxtdhv 1 300 train
+biwwxgrzbg 1 300 val
+biwyesbtwm 1 300 train
+bixdmyhkzw 1 300 val
+bixdutvmll 1 300 val
+bixfmpvnvo 1 298 val
+bixiepitjl 1 300 train
+bixkaqexme 1 300 train
+bixlobzsqp 1 300 train
+bixmpzfdzm 1 300 val
+bixqxnpkhk 1 239 train
+bixvunsrsj 0 300 train
+bixzmysorx 1 300 train
+biyachxhdr 1 300 val
+biybyydljp 1 300 val
+biyeiljrgv 1 300 train
+biyldyzclj 0 300 train
+biymscessf 1 300 val
+biyoqhwnty 1 300 train
+biytppyjul 0 301 train
+biyummatiu 1 300 val
+biyxcjcfhy 1 300 val
+bizbjxafzr 1 300 train
+bizbyemakm 1 300 train
+bizfweqpeq 1 300 train
+bizmlxjfss 1 301 val
+bizncwtlyd 0 300 train
+biznftbygo 1 300 train
+bizohehlgw 1 300 train
+bizwruyydm 1 300 train
+bjaarkxzjx 1 300 train
+bjacjzisbq 1 300 train
+bjaejffikm 1 300 test
+bjafccymsg 1 300 train
+bjakmyuoks 0 301 train
+bjakrtrvaj 1 300 train
+bjapnbgbyf 1 300 val
+bjasjnihuu 1 300 train
+bjatoelbvi 1 240 train
+bjaubcuqcl 1 297 train
+bjbmfygeyw 1 297 train
+bjbmxdthaa 1 300 train
+bjbsjsmobz 1 301 train
+bjburndhjf 1 300 train
+bjbuztpwar 1 300 val
+bjccpuwafd 1 298 val
+bjcefkabza 1 302 train
+bjcesbmllx 1 300 test
+bjchvsgqlc 1 300 train
+bjddsnsuqc 0 300 val
+bjdnvdiorc 1 300 train
+bjdtgkmvza 0 301 train
+bjeefxivfz 1 300 train
+bjeiutsvuz 1 299 val
+bjejfciavt 1 300 val
+bjekntlern 1 147 train
+bjellznrlc 1 300 train
+bjeocyuknw 1 300 val
+bjeskyiyhr 1 302 train
+bjevfmiohj 1 301 train
+bjewyvdkbc 1 300 train
+bjfbzhlzyk 1 300 train
+bjfepqbjey 0 299 val
+bjfezkbmni 1 300 train
+bjfkpuziuk 1 300 val
+bjforfzjqi 1 300 train
+bjgoaahirz 0 300 train
+bjgobiieru 1 300 train
+bjgqahnwit 1 298 train
+bjgqvuvzlc 1 300 train
+bjgtmmetrx 1 301 val
+bjgxevnjiu 0 300 val
+bjgyhqslox 1 300 train
+bjhftvzdoz 0 300 train
+bjhglfghge 1 300 train
+bjhieizrjq 1 300 train
+bjhlloopdo 1 300 test
+bjhmudziab 1 300 train
+bjhqmrwcga 1 241 train
+bjhqszctit 0 300 train
+bjhrnoxued 1 300 train
+bjhwjlzczo 1 300 val
+bjhxjfenwo 1 300 train
+bjifxxuftr 1 300 train
+bjihincwwb 1 300 val
+bjiiauuweh 1 301 train
+bjiprdwujx 1 301 val
+bjisqhfqvg 1 300 train
+bjizwsyhld 0 300 train
+bjjaloefag 0 300 val
+bjjbqirbvj 1 300 train
+bjjbwsqjir 1 300 train
+bjjczrcrlh 1 300 train
+bjjdzidkac 1 300 train
+bjjnvcgjml 1 300 test
+bjjoujprzo 1 300 val
+bjjwtgyepm 1 300 val
+bjkdnhyjoj 1 241 train
+bjkeaghdtd 1 300 train
+bjkemytibi 1 300 train
+bjkjjutppv 1 300 train
+bjkjlklfcj 0 300 train
+bjkkkzmdfh 0 300 train
+bjklrivzii 1 300 val
+bjklzldhna 1 300 train
+bjkmjilrxp 1 300 train
+bjkwxobemt 1 300 train
+bjkyoanxnt 1 301 val
+bjkyoompwi 1 300 train
+bjkyqskytm 1 300 val
+bjkzojznqa 1 300 train
+bjlfeovcwd 1 300 train
+bjllfiganv 1 300 train
+bjlmreemtq 1 300 train
+bjlmsiosjt 1 300 train
+bjltstxtml 1 300 train
+bjlutfvxxi 1 300 train
+bjlvrndjen 1 300 val
+bjlwgiuuxv 0 242 train
+bjlxerjzbl 1 298 train
+bjlxpejqcy 0 300 train
+bjmaxtqiwq 1 300 train
+bjmhknfumi 1 300 train
+bjmrxuabhe 1 300 train
+bjmtxysdjo 1 300 train
+bjmupmludt 1 301 train
+bjmveqttsq 1 300 train
+bjmxelrutm 1 297 train
+bjnabumhcn 1 300 train
+bjnamnskxo 1 240 train
+bjndjajeer 1 300 train
+bjndjvhrkt 1 300 val
+bjniczmumi 1 300 val
+bjnjsiypnv 1 300 train
+bjnleiepgs 1 300 train
+bjnmhhoayf 1 299 train
+bjnnhvjoio 1 300 train
+bjntawnzmv 1 300 train
+bjnvgindid 1 300 val
+bjoaczaqqz 1 300 train
+bjoayaupwb 1 301 train
+bjodrjkfxc 1 300 val
+bjohsfdcuw 0 299 train
+bjorqgprft 1 300 train
+bjorshdgjo 1 300 test
+bjoskdfhuh 1 298 train
+bjovqnilks 0 300 train
+bjovrhougg 0 300 train
+bjpdfzhars 1 301 train
+bjpgamcrux 1 300 val
+bjpimfdtds 0 300 train
+bjpnibwoid 0 241 train
+bjqhmybwko 0 146 train
+bjqjyplccn 1 300 val
+bjqlsgajhc 1 300 train
+bjqmdsvxxa 1 300 train
+bjqqudbued 1 300 train
+bjqqzablga 0 300 train
+bjqsyskiyq 1 300 train
+bjrddhjkuq 1 300 train
+bjrszdkxmo 1 300 train
+bjrwwyslue 1 300 train
+bjrxqkpzhc 1 301 train
+bjsjjfeozt 1 300 val
+bjsmaqefoi 1 300 train
+bjszzfmchp 0 301 train
+bjtbmyfoyq 0 300 train
+bjtdbxvwfp 1 241 train
+bjteexlicx 1 300 train
+bjtefjcnqi 1 300 train
+bjtgipnmzu 1 300 train
+bjtrrrunms 0 300 train
+bjtsofpzve 1 300 train
+bjtwbltzbs 1 300 train
+bjtwbtndwk 1 300 val
+bjudloxvel 1 300 train
+bjuhnomrsu 1 299 test
+bjumlmeblq 0 300 train
+bjuopzolvj 1 300 train
+bjuwpszfiu 1 300 train
+bjvhivxkel 1 300 train
+bjvhklwyom 0 300 train
+bjvhkyxnjj 1 300 val
+bjvmyyhuza 1 300 train
+bjvqduwhtf 1 301 val
+bjvudhgvtj 0 301 train
+bjwcqzymmj 1 300 train
+bjwctylvmy 1 300 train
+bjwlkdnbgw 1 300 train
+bjwlufdvbc 1 300 train
+bjwuuedtla 0 300 val
+bjwvvwewcc 1 241 train
+bjwyeppvze 1 300 train
+bjxasekfcx 1 300 test
+bjxaxxdlfy 1 300 val
+bjxetpxoxg 1 301 train
+bjxghgoctz 1 300 train
+bjxjtqaqbf 1 300 val
+bjxmsrkhyf 1 241 train
+bjxunedutq 1 300 train
+bjxxsvwlzm 1 241 train
+bjxzcaifpw 1 300 val
+bjyadretip 0 300 train
+bjyaxvggle 1 299 test
+bjyfwqezqa 1 300 train
+bjylmnvggi 1 241 train
+bjymnnukqs 1 300 train
+bjyrgzmssb 1 298 train
+bjytxyelfw 1 109 train
+bjzboctmut 1 300 train
+bjzdxvsuvu 0 300 train
+bjzhcjjnwg 1 300 train
+bjzhclfwhq 1 300 train
+bjzhehwofu 0 300 train
+bjzkahdzig 0 300 val
+bjzlxpnwvr 1 300 train
+bjzqcztwlb 1 300 train
+bjzsbmkaam 1 300 train
+bkadhwwkwf 0 300 train
+bkadxgxipz 1 300 train
+bkaedejhcn 1 300 train
+bkahsatkrs 0 300 train
+bkalogzjos 1 300 train
+bkamlqslms 0 300 train
+bkaorhnbdq 1 300 train
+bkbadpwpwa 0 241 train
+bkbdgknxwr 1 300 train
+bkbflitext 0 300 train
+bkbnfigppd 1 300 train
+bkbokyebco 0 300 val
+bkbqftidrf 1 300 train
+bkbupkvksa 1 241 train
+bkchtwvnis 1 300 train
+bkcpgomkyy 1 300 val
+bkcqlavtab 1 300 train
+bkcyglmfci 0 300 test
+bkcztuqxbp 1 300 test
+bkdjwhyojy 1 300 train
+bkdodfwcqn 1 300 val
+bkdoivfsmh 1 298 train
+bkdrqfiqje 1 300 train
+bkdtympvxj 0 300 train
+bkdtyrkvgb 1 302 train
+bkebahschk 1 301 val
+bkebkkwzmf 1 300 val
+bkeczatxrk 1 300 train
+bkeebzfzir 1 300 train
+bkemapctax 1 297 train
+bkepefbfdf 0 300 val
+bkeshmxpen 1 300 train
+bkewppansb 0 300 train
+bkfdxymegl 1 300 train
+bkffyluwrx 1 300 val
+bkfgexlytc 1 300 train
+bkfiyurjkt 1 300 train
+bkfkiejtle 1 300 train
+bkfuglkfcd 1 300 train
+bkfvakwdnw 1 300 train
+bkfzdspzxe 1 300 train
+bkgfyqtuil 1 300 val
+bkgiowakdi 1 300 val
+bkgogbetsk 1 300 train
+bkgpolyuke 1 300 val
+bkhclbvdis 1 300 train
+bkhkouzfsl 1 297 train
+bkhqsithvj 1 301 train
+bkhxxkuilh 0 300 train
+bkianoydkj 0 300 train
+bkidieecdg 0 300 val
+bkijuyvthb 1 269 train
+bkiklcpkhs 1 300 val
+bkiktnngpt 1 298 train
+bkimeogrre 1 300 train
+bkindczhfw 1 241 val
+bkiogelrvu 1 300 val
+bkitjnimap 1 300 val
+bkivxaxfdv 1 300 train
+bkixloqwgr 1 300 train
+bkizohuxts 1 300 train
+bkjhfcvsig 0 301 train
+bkjmekrsip 1 300 train
+bkjmniowpc 0 240 train
+bkjqhzjyti 1 300 train
+bkjxcbphsp 1 300 train
+bkkctwfiag 1 300 train
+bkkdcgdoya 1 297 val
+bkkkindqvf 1 300 train
+bkkkwbhjyk 1 301 val
+bkknadbdyb 0 300 train
+bkkxuqeifu 1 300 test
+bklltfdtkn 1 300 train
+bkmdzhfzfh 1 300 train
+bkmhlmjvtr 1 300 train
+bkmncclkhd 1 300 train
+bkmrcuzvek 1 300 train
+bkmtxhrlsl 1 300 test
+bkmyreelcs 1 300 train
+bkmzjbrzhj 1 300 train
+bknczlsdia 1 300 train
+bkniynymlp 1 298 train
+bknjyvqoec 1 300 test
+bknpfnzlou 0 300 train
+bknyfridoa 1 300 train
+bkoeppigdz 1 300 train
+bkohmmgqcl 1 300 val
+bkojtypnkn 1 300 train
+bkosrjadfi 1 300 train
+bkovlwjwee 1 300 train
+bkpbfylrvx 1 300 train
+bkpbqshzmo 1 298 train
+bkpcqdadda 1 300 train
+bkpfnekcxh 1 300 train
+bkpolfeixc 1 300 train
+bkppzqmzdp 0 300 train
+bkprvplltu 1 300 train
+bkpscxaetl 0 300 val
+bkpubzzmft 1 300 train
+bkpxwokxtu 0 300 train
+bkqaildbep 1 300 train
+bkqfiglzhd 1 300 train
+bkqgvkwjcn 0 300 val
+bkqzowsehk 1 300 train
+bkqzqgnzmw 1 300 train
+bkrluluooo 1 298 train
+bkrpegilqc 1 300 val
+bkrpxyjars 1 300 train
+bkrthuclue 1 301 train
+bksfwwiwdj 1 300 train
+bksgspsokf 0 300 train
+bksiatrvlp 0 300 val
+bksoskogan 1 300 train
+bksqssshtl 0 300 train
+bksuxzffpn 1 300 train
+bksvsnwtoi 1 300 train
+bksydsubui 1 300 train
+bksygsejzk 1 300 val
+bkszyohkda 1 300 train
+bktcgtnzzh 0 300 train
+bktibnjveq 0 301 train
+bktkwbcawi 1 300 test
+bktrcdwbjx 1 300 train
+bktxvguxuy 1 300 train
+bkunvstyyq 1 300 train
+bkuoqwyjor 0 300 train
+bkuqynjuod 1 300 val
+bkuxvlsyax 1 300 val
+bkuzquigyt 0 299 test
+bkvetcojbt 1 300 train
+bkvgqvngep 1 300 train
+bkvjolvmhd 1 300 train
+bkvliqzkba 1 300 train
+bkvmpillpt 1 300 train
+bkvpggjaod 1 300 train
+bkvujfissu 1 300 train
+bkwedwckhv 1 300 train
+bkwicglevl 0 300 val
+bkwiqcrzca 1 300 train
+bkwljktgnj 1 300 train
+bkwpeforul 1 300 train
+bkwqojntbf 1 299 test
+bkwxhglwct 1 300 train
+bkxgxhbkcf 1 300 train
+bkxkjlcwkh 1 300 train
+bkxqjiqabv 1 300 train
+bkxxbtsvkz 1 300 test
+bkycjjxlti 1 300 train
+bkyelekjqs 1 302 train
+bkyhyjacht 1 300 train
+bkymqahmft 1 300 train
+bkyoodlpvw 1 300 train
+bkyqaqhdra 1 300 train
+bkytciqsgd 0 300 train
+bkyvkuvvij 1 300 train
+bkywyprmxz 1 300 train
+bkyzinwdfz 1 300 train
+bkzabjxnpm 1 300 train
+bkzbiriopd 1 300 train
+bkzcioseyf 1 300 train
+bkzdqjuovy 1 300 val
+bkzjlbokrx 1 300 train
+bkzqarlyhs 1 300 train
+bkzrsfcrcr 1 300 test
+bkzwxbysjl 1 300 val
+bkzxepcbee 1 300 val
+bkzztamepr 1 300 train
+blacgtwnol 1 300 train
+blajhhistl 1 300 val
+blapzzrmja 1 300 val
+blatnvxlhu 0 300 train
+blbbfvpctz 1 300 val
+blbcnohsup 1 300 val
+blbghnbwmt 0 300 val
+blboswgcsn 1 300 train
+blbqigirdr 1 300 train
+blbsewntsg 0 300 train
+blbtxevriv 1 300 val
+blbvdywnbk 0 301 train
+blbxgidsbn 1 301 train
+blcmfoqkyh 1 288 train
+blcpogyffx 1 300 train
+blcqmwhzwr 0 300 train
+blcqzztrvu 0 300 val
+bldeizqycp 1 300 test
+bldglrgkgy 1 241 train
+bldjbwbxcm 1 300 train
+bldkavegsb 1 300 train
+bldqetfopy 1 237 train
+bldvboovyj 1 300 train
+blebfqndml 1 297 train
+blehjybifk 0 300 train
+blemhkciot 0 300 train
+bleowhekvn 0 300 train
+blepmtsdvs 1 300 train
+bleyyfdcaw 1 300 train
+blfdfsedii 1 300 train
+blfdwlumfv 1 300 train
+blfiakiqsz 1 300 val
+blfmarosnw 1 300 val
+blfmnzmqyt 1 300 val
+blfnjgizaj 1 302 train
+blfportlxc 1 300 val
+blfqpzvoqt 1 300 train
+blfwchaqbd 1 298 train
+blfwnbitgb 1 300 train
+blfzhuobde 1 301 train
+blgguvlyac 1 297 train
+blggyzbach 1 300 train
+blghqsyyfx 1 300 train
+blgompxjca 1 300 val
+blgqypzjuv 1 300 train
+blguiieqvl 1 300 train
+blhfraazak 1 300 train
+blhgbioprk 1 241 train
+blhhutqvsw 1 300 train
+blhwqtogil 1 300 train
+blhxipfcro 1 300 train
+blifukgmvg 1 297 train
+bliugfusvu 0 300 train
+blixeyzezn 1 300 train
+bljafwdkgk 1 300 train
+bljimxqnrp 0 300 val
+bljjbfslfx 1 300 train
+bljlskjwsg 1 300 train
+bljmpoqajf 1 300 train
+bljpdykszf 0 300 val
+bljrzamplz 1 300 val
+bljzsvsuuk 1 300 train
+blkbkvcffn 0 300 test
+blklnegyki 1 300 test
+blkxyqpgry 1 300 train
+blkytrglsm 1 300 train
+bllhfrgbza 0 300 val
+bllwucqezv 1 300 val
+bllxjkvgbx 1 300 train
+bllzezsiip 1 300 train
+blmhnptamf 1 300 train
+blmofumugf 1 300 train
+blmqnkxzae 1 300 train
+blmshuqtot 1 241 train
+blmuodoxei 1 300 train
+blmuqktchd 1 300 train
+blmuzhjygg 0 301 train
+blnbnokiuq 1 301 train
+blncrpznaa 1 299 val
+blnmxntbey 0 300 test
+blnnqgjuck 1 301 train
+blnoubxzwr 1 250 train
+blnvojesru 1 241 train
+blomkvafap 1 300 train
+blpboxhdvz 1 241 train
+blpcbbdpud 1 288 train
+blpchvmhxx 1 300 train
+blpftgoedo 1 301 train
+blphnebfgt 1 301 train
+blplivuqcr 1 300 train
+blppqzkjlq 1 300 val
+blprrfobos 1 300 train
+blpsprzbrp 1 300 val
+blpwdaadsm 1 300 train
+blpweqniph 0 301 train
+blqcmqslyk 1 300 train
+blqcrgfrko 1 300 train
+blqddxvutv 1 301 train
+blqdjztxsw 1 300 train
+blqgpxokwq 0 136 train
+blqhvxglyz 1 300 train
+blqmbehvam 1 300 val
+blqocnwung 1 300 train
+blqozrtxtm 1 300 val
+blqrkgjsun 1 300 train
+blqswyjgff 1 300 train
+blqwrzztiy 1 300 val
+blrlqshxsk 1 300 train
+blrolvknsm 1 297 train
+blruhiftcw 1 301 train
+blryzyqfan 1 299 val
+blsflyuyof 1 300 train
+blsfputbrz 1 300 train
+blsgycrkog 0 300 val
+blsmnfekjb 0 300 train
+blsubpozyk 0 300 train
+blswnkmgtn 1 241 train
+blszgmxkvu 0 300 test
+blszrprdrv 1 300 val
+bltbwbihal 1 300 train
+bltedjvtlj 1 300 train
+bltfgsdelz 1 300 val
+bltgxotaiv 0 300 val
+bltidtsxen 1 302 train
+bltoponeel 1 300 val
+bltrrevthi 0 300 train
+bltsfxhpce 1 300 train
+bltxzeoijl 1 300 train
+bluxihkxcz 1 300 train
+blvbtkgrra 1 299 train
+blvdapjxzz 1 300 train
+blvdxvadvd 1 300 train
+blvgczhxyu 1 300 train
+blvlaqkhov 1 300 train
+blvpaewknn 1 300 train
+blvqcbuele 1 300 train
+blvuhoedza 0 300 train
+blvxytpjqz 1 300 val
+blwfcizbrl 0 300 train
+blwvnvsbmz 1 300 test
+blwzwwzntm 1 300 train
+blxabkodvi 1 300 train
+blxeeqwycp 1 300 train
+blxfkpvtov 1 300 train
+blxlwncdej 1 300 train
+blxpqkkret 1 301 val
+blxtweqoax 1 300 val
+blyaioymsr 1 297 train
+blyaymhdil 1 300 train
+blybhmrnrd 1 300 train
+blycgpiikp 0 300 train
+blydmtfwwk 1 300 train
+blyfmnqkfl 1 300 train
+blyimyjwcl 0 300 val
+blykqbluyb 1 300 val
+blynxptkya 1 300 train
+blynypczbp 1 300 train
+blyoxkhsdl 0 300 train
+blyqngenhe 1 300 train
+blyvubsbod 1 300 train
+blyzlljblm 1 300 train
+blzabhgaim 1 296 train
+blzcuynlhq 1 300 train
+blzespzdkl 1 300 train
+blzgjrjsvy 0 300 val
+blziolhzdx 1 300 train
+blzjhbplij 1 300 train
+blzkqiyuuj 1 300 train
+blzkuhvnvp 1 300 train
+blzmqourro 1 300 train
+blzsfimppr 1 300 train
+blzskoyaav 1 300 train
+blzxynijom 1 300 train
+blzydqdfem 1 300 train
+bmablqorlk 1 300 train
+bmacjazhyt 1 300 val
+bmahmggjbd 1 301 train
+bmalihrewa 1 300 val
+bmaocruisg 1 300 val
+bmauuakxcx 1 301 train
+bmauyodcax 1 300 val
+bmbbkwmxqj 1 300 train
+bmbdnuohqv 1 300 val
+bmbhcmbfor 1 300 train
+bmbokniazt 1 300 train
+bmbuowgrhm 1 300 train
+bmcawdehgz 1 300 val
+bmcmlejpik 1 300 train
+bmcpsjkjqv 1 300 train
+bmdbtuehxi 0 300 train
+bmdgvyiveu 1 300 val
+bmdiaytrcm 0 300 train
+bmdkuleseg 0 300 train
+bmdmviwavq 1 300 train
+bmdrytwxjp 1 300 train
+bmdseigcra 1 301 val
+bmdwhzgita 0 300 train
+bmehkyanbj 1 300 train
+bmejcmawty 1 300 train
+bmejcpnvvs 1 300 train
+bmejygajwg 1 300 train
+bmelmdgsjo 0 300 val
+bmepdrvkyy 1 300 train
+bmewfssalv 1 300 val
+bmfdkynrny 1 300 val
+bmffrysoii 1 299 test
+bmfftnywnw 1 298 val
+bmfjkmwieq 1 300 train
+bmfkkzheii 1 300 test
+bmfrfuiucc 1 300 train
+bmfuosxwoc 1 300 train
+bmgcyjggxe 1 297 train
+bmgdyawjfu 1 301 train
+bmgfvlxwed 1 300 val
+bmgidxpirq 1 83 train
+bmgjjwxmhi 1 300 train
+bmgmlkikqi 0 300 train
+bmgnopxcdf 1 300 train
+bmgptqpfdt 0 300 train
+bmgsqeuaqf 1 300 train
+bmgxoyykup 1 300 train
+bmgyolkiyj 1 300 val
+bmgzsdbmxd 1 300 train
+bmhcbivwvf 1 300 train
+bmhghysucl 1 300 test
+bmhjwjlzet 1 301 train
+bmhoxgozft 0 300 train
+bmhujsbnxk 1 300 train
+bmhvktyiwp 1 300 train
+bmhyzbtedz 1 300 train
+bmhztsvskg 1 299 val
+bmhzvjkoeb 1 300 train
+bmijukkheo 1 300 train
+bmimrgglnb 1 300 train
+bmioepcpsx 1 300 train
+bmiofvaobi 0 300 train
+bmiryozzvx 0 300 train
+bmixrenyil 1 300 train
+bmjambpihn 1 300 train
+bmjbamtqwn 0 300 val
+bmjcwrvfpv 1 298 train
+bmjgasheub 1 300 train
+bmjjhpgnra 1 241 train
+bmjmjmbglm 1 300 train
+bmjnecqxpr 1 300 val
+bmjqfxjpcd 1 301 val
+bmjvqaefiw 1 300 train
+bmjwoqldhv 1 300 test
+bmjzrlszhi 0 300 train
+bmkglbhaiz 1 300 train
+bmkgprgspf 0 300 train
+bmkimqkzlh 1 300 train
+bmkirvqnkq 1 300 train
+bmkkcdbfda 1 300 train
+bmknljaccn 1 300 val
+bmkqvrbwal 1 300 val
+bmkrojdzfi 1 300 train
+bmkvdjplky 1 301 val
+bmkzenlrkm 1 301 train
+bmlesleubu 1 300 val
+bmlfosmjsb 1 301 train
+bmlfuxhzck 1 300 val
+bmljrhlhta 0 300 val
+bmlkelpjmp 1 300 train
+bmlngcskzn 1 300 train
+bmlnzuebwq 1 300 train
+bmlovaheks 1 301 train
+bmlvcbcmig 1 299 train
+bmlzrrbryg 1 300 val
+bmmcqezsqf 1 300 val
+bmmdgzgqyb 1 300 train
+bmmgvyxgtd 1 300 train
+bmmorpkrlu 1 300 val
+bmmyqhhwnw 1 300 train
+bmnolajvus 1 300 val
+bmnpqrwnex 0 300 train
+bmnrvnrmup 1 300 train
+bmodvgktsq 1 300 train
+bmokmikufp 1 300 train
+bmonhalney 1 298 train
+bmorukofvf 1 300 train
+bmowylfixf 1 241 train
+bmpdoyqwrp 1 300 train
+bmpgdxzwpt 1 300 val
+bmpixzqpmw 1 300 val
+bmpqechbsl 1 301 val
+bmprytqwwp 0 300 train
+bmptztmobh 1 300 val
+bmpuhzsicr 1 300 train
+bmpxgjgryj 1 300 train
+bmqekrgmmh 1 300 train
+bmqiypaqla 1 300 train
+bmqjjdkysw 1 300 train
+bmqmaknmam 1 300 train
+bmqouoakyf 1 300 train
+bmqqgioruy 1 298 train
+bmqqlhwcbq 1 300 train
+bmqqmckpbv 1 300 train
+bmqxraeqaw 1 300 train
+bmrffzpeqi 1 300 train
+bmrfnpgter 1 300 train
+bmrogzgbqw 1 300 test
+bmrvbaqddk 1 301 train
+bmrwcqrpyp 0 297 train
+bmrzypslcn 1 300 train
+bmskphjibo 1 300 train
+bmsoarcvmn 1 299 test
+bmspwayqbn 1 299 val
+bmsrrkjlaj 1 300 train
+bmsvbgqlqo 1 300 val
+bmsxkitovr 1 300 train
+bmsylxxkly 1 300 train
+bmszzdboqq 1 300 train
+bmtacubhig 1 300 train
+bmtatdezlv 1 300 train
+bmtbxkjkjq 0 300 train
+bmthsmwnsd 1 300 train
+bmthtafiuf 1 301 val
+bmtlpmxujc 1 300 train
+bmtnmgydah 0 300 val
+bmtrpwqkii 1 300 train
+bmtvkrvubb 1 300 train
+bmubodkwtx 0 300 train
+bmugrleytv 1 300 train
+bmuppienyb 1 300 train
+bmuuutcuba 1 300 train
+bmuynsdqhz 1 300 val
+bmvjqkjtnf 1 300 train
+bmvksrmqmv 1 300 train
+bmvkssoxvv 1 300 train
+bmvmfmlsna 1 240 val
+bmvsutcqxe 1 300 val
+bmvuyydzmd 1 300 train
+bmvvcdbhpc 1 300 train
+bmwacwpmqf 1 299 val
+bmwecdywmg 1 300 val
+bmwftpdgmk 1 300 val
+bmwmwjwluk 1 302 train
+bmwuxmhtcc 1 300 val
+bmwwownzvl 1 300 train
+bmwzgdjddp 1 300 train
+bmxgauvkbj 1 300 train
+bmxolpnlxu 0 298 val
+bmxxeugfpg 1 300 val
+bmydmlvxro 1 240 train
+bmydqokovk 1 300 train
+bmyjdoslrp 1 300 val
+bmzdfyogfw 1 300 train
+bmzkjqilog 1 300 train
+bmzsbavkaw 1 300 val
+bmzsvaimta 1 300 train
+bmzywathcq 0 300 train
+bmzzkjvqpa 1 300 train
+bnaisutopz 1 300 train
+bnakxfpbyt 0 300 train
+bnanycsmiw 0 300 train
+bnaqqefxll 1 299 val
+bnazswlmqw 1 300 train
+bnbfkhafjz 1 300 val
+bnbflzcvwf 1 300 train
+bnbfzyjbdo 1 300 train
+bnbovmdeot 0 300 train
+bnbpburtrc 0 300 val
+bnbueocaql 1 300 val
+bnbuonyoje 1 300 train
+bnbuqimfbn 1 300 val
+bnbvwywbci 1 300 train
+bnbxarxyqk 1 300 train
+bncgmrljgp 1 300 train
+bncqtvlcee 1 300 train
+bncxsmfjor 1 300 train
+bndazrmdkj 1 300 train
+bndciminct 1 300 test
+bndcitxnyh 1 300 train
+bndejeyqpb 1 301 val
+bndfldavtx 1 300 train
+bndhfeofzp 1 300 train
+bndisdunhz 1 300 train
+bndkaaqewo 1 300 train
+bndnqwlgez 1 300 train
+bndpmddyur 1 300 train
+bndybcqhfr 1 300 train
+bnelvlleic 1 300 train
+bneqwtomed 1 296 val
+bneuvofkbh 1 300 train
+bnevqylmpw 1 300 train
+bnexllrfsq 1 300 train
+bneyyrkeut 1 300 val
+bnfhgczmrn 1 301 train
+bnflosxiea 1 300 train
+bnfnnswiwd 1 299 val
+bnfofjyvlf 1 300 train
+bnfqcshwdx 0 300 train
+bnfrdywzvv 1 300 train
+bnfrgecebo 1 300 train
+bnftsifsdl 1 300 train
+bnfxegkque 0 241 val
+bnfxesdwqu 1 300 train
+bngbpbgguy 0 302 train
+bngimidubc 0 300 train
+bngnnwbtqa 1 301 val
+bngpjglyqu 1 300 train
+bngpswdemp 1 300 train
+bnhejkbtyq 0 300 val
+bnhjdjlszu 1 300 train
+bnhqhwqcqm 1 300 train
+bnhusicjao 1 300 train
+bnhzgxxodm 1 300 train
+bnifctbafh 1 300 train
+bnifrkeqrt 1 300 train
+bnigglnguz 1 300 train
+bnimtitnnc 0 300 train
+bnioxftiwh 1 301 val
+bnipkpqevp 1 300 train
+bnirjkrhpf 1 300 val
+bnisslwezp 1 300 train
+bnityfpill 1 300 val
+bnitzihcqs 1 300 train
+bnivhzpecz 1 241 train
+bnivwnbzbx 1 300 train
+bnizotcovs 1 300 val
+bnjcdrfuov 1 300 train
+bnjdaskseq 1 300 train
+bnjnsrammj 1 299 train
+bnjpnkqoyh 1 300 val
+bnjpqypcmg 1 300 val
+bnjzsmvuot 1 301 train
+bnkfxvfszq 1 301 train
+bnkheclavc 0 300 val
+bnkhvsgilj 1 300 train
+bnkjftqxbh 1 300 train
+bnkmyawjld 1 300 train
+bnknqangbc 1 300 val
+bnkpyfsvhy 0 300 val
+bnktoisqiy 1 300 train
+bnkvdoujfy 1 301 train
+bnkxfblspr 1 300 train
+bnlaajzsxt 1 300 train
+bnldaxdhwf 1 300 train
+bnlhnkfkrg 1 300 train
+bnlhyawkzi 1 300 train
+bnlqmpwwok 1 301 val
+bnlqpmwotj 1 299 train
+bnlqzjegan 1 300 train
+bnltjnkatm 0 300 train
+bnlufsupvf 1 298 val
+bnmcytpazm 1 292 train
+bnmhlmrefd 1 298 train
+bnmkwtjris 1 300 train
+bnmtqdhxig 1 300 train
+bnmwcuhcsd 0 300 val
+bnmxzioxft 1 300 train
+bnmyoujtpb 1 300 train
+bnnbfpcvlr 1 300 train
+bnnbywoosz 0 300 val
+bnndjmrpuk 1 300 test
+bnnpurjrvu 1 300 train
+bnnurttetv 1 300 val
+bnoenthkmd 1 300 train
+bnoguraavi 1 300 train
+bnolprqrms 1 240 val
+bnosklttlt 1 301 val
+bnoyahpspd 1 300 val
+bnpkjsorco 0 300 val
+bnpsclwvrp 1 300 train
+bnqbbrzria 1 300 val
+bnqcycuufi 1 300 val
+bnqruwyerr 1 300 train
+bnqswltvxj 1 300 train
+bnravrfoli 1 300 train
+bnrhpswktc 1 300 train
+bnrinrrsle 1 300 train
+bnriwtwfof 0 300 val
+bnrmoejozc 1 300 train
+bnroljkhvu 1 300 train
+bnrqbeadrg 1 300 val
+bnrvmjfihd 1 300 train
+bnrzysbtiw 1 301 train
+bnssiugvik 1 300 train
+bnsxuqhoei 0 300 train
+bnsyxqrgae 1 300 train
+bntdjyzsvo 1 300 train
+bntffimwve 1 302 val
+bnthgqolpp 1 300 train
+bnthvgevmy 1 300 train
+bntlodcfeg 1 300 train
+bntlxllqcr 1 300 train
+bntmdzsges 1 300 val
+bntpzmfavf 1 300 val
+bnturekhnz 1 299 val
+bntzctsxro 1 300 train
+bnudobzshb 1 300 train
+bnutziujwg 0 300 train
+bnuwxhfahw 0 299 test
+bnvosbprwt 1 300 train
+bnvpafalfu 1 300 train
+bnvtgmfunt 1 300 train
+bnwchtmiku 1 241 train
+bnwetzchfg 1 300 train
+bnwfyxjhth 1 300 train
+bnwgnvnreu 1 300 val
+bnwkhfneqp 0 300 train
+bnwlsejuna 1 300 test
+bnwnqigtxx 0 300 train
+bnwpzorrtc 1 300 train
+bnwqrhwjmp 1 300 train
+bnwxqegocz 1 300 train
+bnwzkftbix 1 300 val
+bnxhmolmlc 1 300 train
+bnxispqojs 1 300 train
+bnxmbphnnn 0 300 train
+bnxmvkrbhm 1 300 train
+bnxqmregwp 1 300 train
+bnxuzwyftq 1 300 train
+bnyiorehpm 1 300 train
+bnyiryeqxf 1 300 train
+bnynincvkz 1 298 val
+bnywsgghdq 1 241 train
+bnyzlzdwhd 1 300 train
+bnzgbnlhao 1 300 train
+bnzlmqqdyh 1 300 train
+bnzouputpd 1 300 val
+bnzufuewgo 1 300 val
+boagmphucy 1 300 train
+boaitvufer 1 300 train
+boaluuroop 1 300 val
+boamzvextx 1 298 train
+boattrzsqp 1 299 val
+boatuniakm 1 300 val
+boaubpdrvk 0 300 train
+bobdujxvmd 1 236 train
+bobihhgccf 1 300 test
+bobqcudtvq 1 300 train
+bobulcobhw 1 300 train
+bobuotmbyj 0 300 train
+bocdttfbsu 1 300 val
+bocgzhhbwv 1 300 val
+bockklctcz 1 300 val
+bocqwtnpvy 1 300 train
+bocrnmsejn 1 300 train
+bodcstdytd 1 300 val
+bododgoost 1 300 train
+bodsawledj 1 300 val
+boduivptnu 1 300 train
+bodulwuuhr 1 300 train
+bodvhackdj 1 300 val
+bodvudzeek 1 300 train
+bodzohkepk 1 300 val
+boeetvtloe 1 300 train
+boepzadatv 1 300 train
+boeqmjdwcj 0 300 train
+bofdhlwiof 1 300 val
+bofeeihrug 1 300 train
+bofeuivknt 1 300 train
+boffgepsfl 1 300 train
+bofgeerrrz 1 300 train
+bofkynhwex 1 300 train
+bofmetrgfm 1 300 val
+bofobfsabm 1 300 train
+boforjdzba 1 302 train
+bofqajtwve 1 300 train
+bofqrylfpr 1 300 test
+bofrwgeyjo 1 300 test
+bofrxgpdnb 1 300 val
+bofuzcvssf 1 300 train
+bofweizbhv 1 300 train
+bofwjwilkx 1 300 train
+bofxxkkdjl 1 300 train
+bogcoldwxa 0 300 val
+bogdanhvot 1 300 train
+bogekgnwin 1 300 train
+bogjubshbr 1 301 train
+bogmhrcibi 1 300 val
+bogpwahmwx 1 300 train
+bohdrbkdgk 1 300 train
+bohiqwsnez 0 301 train
+bohqidbmls 1 300 train
+bohrgpvebk 1 300 train
+bohwfyympd 1 300 train
+bohxccdcoo 1 301 train
+boiaofxiwp 1 300 train
+boiexvxboc 1 300 train
+boigglmnof 1 300 train
+boigxsawwj 1 298 train
+boimwwwcvb 1 300 train
+boioyxhfch 1 300 val
+boiqmmzslz 1 300 train
+boirbbzkvt 1 300 train
+bojahordjs 1 300 train
+bojeaxbyqw 0 300 train
+bojhoipcwj 0 300 train
+bojpmzyjzd 0 300 val
+bojrkqyjdk 1 300 train
+bokclrtqyi 1 300 val
+bokfrfzqyt 1 300 train
+bokwfrmeyv 1 298 train
+bokxxrpbqk 1 300 train
+bolccjllpc 1 300 train
+bolcjxqleh 1 301 train
+bolcohfmnd 1 300 train
+bolnmdxqiy 1 300 train
+bolnqgimhd 1 300 train
+bolpdamwfo 0 300 val
+boltwhhpxg 0 300 train
+bolxsckgnj 1 302 val
+bomcfegdpt 1 300 train
+bomfzgzrgu 1 298 train
+bomifrddkv 1 300 train
+bomsohzrou 1 300 train
+bomwubhrhy 1 300 train
+bonanummuk 1 300 train
+bonatvjrzc 1 300 train
+bondpozhiq 0 300 val
+boniihghzg 0 300 train
+bonkafyzur 1 300 train
+bonmcuwuqu 1 300 train
+bonmtpvlao 0 300 train
+bonwkgdpzx 0 300 train
+bonxixslro 1 255 train
+booanrqetg 1 300 train
+boobpetndu 0 299 val
+booejmgaqh 0 300 train
+boofqjynws 0 300 train
+boolcgesju 1 301 train
+boolpinsvs 1 300 train
+boopvichfi 0 300 train
+boovltmuwi 1 300 train
+bopfhrjolx 1 300 train
+bopjzdsmxy 1 298 val
+bopqhhalml 1 300 train
+boprewpbmp 1 300 train
+bopzdqqfqi 1 300 train
+boqihigtcw 1 300 val
+boqiyveflk 1 300 val
+boqpxyzcyc 1 300 train
+boqqtmwtle 1 301 val
+boqsqyfdhw 1 300 train
+borbtrwyhb 0 300 train
+bordcikifg 1 300 train
+bordikedal 1 300 train
+boreeeujiu 1 300 train
+bornwbiawr 1 300 train
+bortbfnubx 1 300 train
+borupglecp 1 300 train
+boruwivyxw 1 301 train
+borvrzlpon 1 300 train
+borwxlaoje 1 300 val
+borxehbaea 1 300 val
+bosbcjeizu 1 300 train
+bosclfijdo 1 300 train
+bospdntyrt 1 300 train
+bosqlnwalb 1 301 val
+bosqveawob 1 300 train
+bostfdnanu 1 300 train
+bosutusbke 1 300 val
+bosxyhludp 1 300 train
+bosyrbubtq 1 300 val
+botezfxrtv 1 300 train
+bothyprepo 1 300 train
+botlpnmjmt 1 301 train
+botlvrjcxy 1 300 train
+botmrxmhgu 1 300 val
+botmynyrbc 1 300 train
+bototlyqgs 0 300 val
+botswdcyee 1 300 test
+botytorwcf 1 298 val
+botzphvmyi 1 300 train
+boufcmguqp 1 300 train
+bouhmflnng 1 300 train
+boulgxcbqd 1 300 val
+boulpmuket 1 300 train
+boumootsed 0 300 val
+bourlmzsio 1 300 train
+bovbpcdzjp 1 300 train
+bovdcqwtbf 1 300 val
+boviyasobx 1 300 train
+bovulcoicx 0 300 val
+bowapfosea 0 300 train
+bowapsnlpk 1 300 train
+bowgnwjhqe 1 300 train
+bowjhilvfm 1 300 val
+bowlewsdoc 1 300 train
+bowlimhoul 1 300 train
+bowlklfabb 1 301 val
+bowsazznoh 1 300 train
+bowvhjcpsj 1 301 train
+boxalsxdzk 0 298 train
+boxcfpxfqg 0 300 train
+boxfawgnyw 0 301 val
+boxfdbfgsn 1 300 train
+boxffpjcxp 1 302 train
+boxgkdhzuh 1 300 train
+boxhgyguis 1 300 train
+boxrpxjcrv 1 300 train
+boxrvwsmho 1 300 train
+boxtpeqnnl 0 300 val
+boydzhuebj 1 241 train
+boyebftepb 1 300 train
+boyjqinioh 1 300 train
+boyqijigvx 1 301 val
+boyribbmyg 0 300 train
+boytcyrjwc 1 300 val
+boyvpmwkhd 1 300 val
+bozetkdhoi 1 300 train
+bozhmxsghc 1 300 train
+bozkbbydju 1 301 train
+bozmjzlwxr 1 300 train
+bozwzdwwic 1 298 train
+bpadffygrq 1 300 train
+bpadmpcmre 1 300 train
+bpapbctoao 0 300 train
+bpapdifduo 1 300 train
+bparszhscy 1 300 train
+bpartnwakp 1 299 test
+bpasruchcy 1 300 val
+bpauyhxnlj 1 300 train
+bpayrzuqkf 1 300 train
+bpbapwtwfa 1 300 train
+bpbbiubvoj 1 300 train
+bpbbjegsoa 1 300 train
+bpbkgyajts 1 300 train
+bpbqjruhkj 1 300 val
+bpbtijbhih 1 300 train
+bpbtxqytty 1 300 val
+bpbykjbyvp 1 300 train
+bpcairsgal 1 300 train
+bpcimjvhlu 1 299 test
+bpcmfykufo 1 300 train
+bpcngaazlg 1 300 val
+bpcwkfqtuo 1 300 val
+bpcxuqcivd 1 300 train
+bpdakeatsq 1 300 val
+bpdbfbqnkl 1 300 train
+bpdbowwxxq 1 300 train
+bpdbtzzuhy 1 300 train
+bpdvahiqem 0 300 train
+bpdvlyaupp 1 300 train
+bpdwkgpwah 0 300 train
+bpdwvutnkb 1 300 val
+bpdzodtokw 1 300 train
+bpeciyicig 1 300 train
+bpeemkcxad 0 300 train
+bpeykzhmgl 1 301 train
+bpezkefwro 1 298 train
+bpfoshcgbd 1 300 train
+bpfsnzublf 1 300 train
+bpfuxaekce 1 301 train
+bpfwbwtihj 1 300 val
+bpgclzzckb 1 300 train
+bpgekujqux 1 300 train
+bpgfhqmwkv 1 300 val
+bpggmrcdbr 0 300 train
+bpginhkvxq 1 300 train
+bpguesjrfa 1 300 test
+bpgzfbcuzn 1 300 train
+bphailefxg 1 299 val
+bphdpclagl 1 301 train
+bphdxnykou 1 239 train
+bphizcvcao 0 300 train
+bphkjrfmdf 1 300 train
+bphndjivob 1 300 train
+bphnfjxagq 1 300 train
+bphuuuhabb 1 300 train
+bpiaonpbju 1 300 train
+bpieoyctzo 0 300 train
+bpihwagtnt 1 300 train
+bpijdklhxj 1 300 train
+bpikmdncgi 1 300 train
+bpilkoviwk 1 300 val
+bpisbvizga 1 300 train
+bpitlcilin 1 301 val
+bpiuysyyuj 1 300 train
+bpivyqpbqn 0 300 val
+bpjdzzrejd 1 300 train
+bpjkimtqtz 1 300 train
+bpjtvwbzjn 1 300 train
+bpjvkhzgbm 1 300 train
+bpjvxxvxvn 1 300 val
+bpjwhlzkst 0 300 train
+bpkfgwqvjk 1 300 train
+bpkgdlopkm 1 300 val
+bpkklvxqfc 0 300 train
+bpkoaykilj 0 300 train
+bpkouwxdjn 1 300 train
+bpkpvrqduq 0 300 train
+bpkqpbfzkt 1 301 train
+bpktkblxjg 0 300 train
+bplgsunoju 1 301 val
+bplholcbjb 1 298 train
+bplreismgo 1 300 train
+bplulofcjk 1 300 val
+bplwjxrjfx 1 300 train
+bplydqnrps 1 300 train
+bpmchuqyme 1 300 train
+bpmhcavmle 1 300 train
+bpmimcjgmi 1 300 train
+bpmonwznmw 1 300 train
+bpmqlfquqd 1 241 train
+bpmrjzllyx 1 300 train
+bpmsyvyfao 1 300 train
+bpnaomehzk 1 300 train
+bpnaqrvhgw 1 300 train
+bpncjwzygq 1 300 train
+bpnexhvqmc 1 300 train
+bpnphpiibh 0 236 train
+bpnvhgdepc 1 297 val
+bpoekpidxd 0 300 train
+bpofwnsxhr 1 300 val
+bpogbhuwvd 1 300 test
+bpokhtyism 1 300 train
+bpokxakofx 1 300 train
+bpolvgzrqa 1 300 train
+bpoteqryto 1 300 train
+bpoyxbmgau 1 300 train
+bpozerhrla 1 300 val
+bpphufmsrn 1 300 train
+bpppnleeud 1 300 train
+bpppzfcuuw 1 300 val
+bppqpsrvjt 0 300 val
+bppsslmqpn 1 300 val
+bpptwacmjs 1 302 train
+bppvnnfsbu 1 167 train
+bppvyenwri 1 300 train
+bppzgjwfbi 1 300 train
+bpqehbeuly 1 600 train
+bpqkdefbia 0 300 train
+bpqmetsjik 1 300 val
+bpqnqpdrvq 1 300 train
+bpqreecowu 1 300 train
+bpqrwvichd 1 299 train
+bpqtyarnjh 1 300 val
+bpqxgmtxli 1 300 train
+bpqydkfgbs 1 300 train
+bpqyqcsacu 0 300 train
+bprbdtrsyz 1 300 val
+bprcupujiv 1 300 train
+bprfcqhhmh 1 298 train
+bprlmhgqcu 1 300 train
+bprmtindge 1 300 train
+bprpcwfras 1 298 train
+bprsgsinkl 1 300 val
+bprvlpfpgf 1 300 train
+bprwodjaev 1 301 train
+bpscetatri 1 300 train
+bpsepuymho 1 303 train
+bpsjlpirye 0 300 train
+bpsjqgpszt 1 300 train
+bpsjvrrvpa 1 298 train
+bpsofjvwqw 0 300 train
+bpsqrrutff 1 300 train
+bpsstiiuzp 1 300 train
+bptawjltne 0 300 train
+bptbbrigni 1 300 train
+bptdwbwqtp 1 300 train
+bpteuesxca 1 300 train
+bptfyhbxkh 1 300 train
+bptgakrcvv 0 300 train
+bptgdgggmw 1 300 train
+bptmbaffim 0 300 train
+bptrjazhbd 1 300 val
+bptrqltmsx 1 300 train
+bptskppffr 1 297 train
+bpttffvedn 1 297 train
+bptuspvmzq 1 300 train
+bpuaoihwyh 1 300 train
+bpueeygkdb 1 300 train
+bpuejvlclc 1 300 train
+bpuhrkvgyj 0 300 train
+bpujsteojc 0 300 train
+bpumlievda 1 300 train
+bpunvjnbxu 1 300 train
+bpurhuhrkx 1 300 train
+bpurwdafcq 1 241 train
+bpuxykqwke 1 298 train
+bpuztimwat 0 300 train
+bpuzvrjihz 1 241 train
+bpuzyxwbiw 1 300 train
+bpvcqqrgbq 1 300 train
+bpveyyjlav 1 300 train
+bpvezemyqa 1 300 val
+bpvicneatq 0 300 val
+bpvimgtvqr 0 300 train
+bpvjdhkspw 1 300 train
+bpvmtzmxpa 1 300 train
+bpvrltfiuf 1 300 train
+bpwcajlxav 1 301 val
+bpwcctcgfi 1 300 val
+bpwgnoqnls 1 300 val
+bpwgtgahcv 1 296 val
+bpwiiargkq 1 237 train
+bpwjoacfxu 0 300 train
+bpwlxljeqi 1 300 train
+bpwmopyyox 1 300 train
+bpwrdvhnmx 1 300 val
+bpwucdibhz 1 300 train
+bpwudenryg 1 300 test
+bpwynspgkx 0 300 val
+bpwzipqtxf 1 300 train
+bpxbsogyih 1 300 val
+bpxckdzddv 1 300 train
+bpxitgkwkm 1 300 train
+bpxkkcpurm 1 300 train
+bpxnubsfkp 1 300 train
+bpxrgfkjbd 1 300 val
+bpxsrwrgvo 0 300 train
+bpxxmxuvuy 0 300 train
+bpxylsijdh 1 301 train
+bpxymugmnd 1 300 train
+bpyaeymxvx 1 300 train
+bpydczlvql 1 301 train
+bpyjsrjcro 0 300 train
+bpykroksyw 1 300 val
+bpylmgxfqt 1 300 train
+bpyybvvnnx 1 301 train
+bpzfalcypz 1 241 train
+bpzllnrxpz 1 300 val
+bpzmcgorle 1 300 val
+bpzpradokb 1 300 train
+bpzrvxwcdw 1 300 train
+bpzskkbywi 1 300 val
+bpzwkisxdq 1 301 train
+bpzxipkgvk 0 300 train
+bpzxuaoqyt 0 300 train
+bpzzvzbtvl 1 300 val
+bqaazokwgn 1 300 train
+bqaknqwcyg 1 300 train
+bqamrsyvnf 1 300 test
+bqapqldnbj 1 300 train
+bqawxbnlnp 1 301 train
+bqbaucwxvo 1 301 train
+bqbazvieah 1 241 train
+bqbevcobok 1 300 train
+bqbnuvouqp 0 300 train
+bqbtcvytxf 1 300 train
+bqcfdbdtvu 0 300 train
+bqckuzlrar 0 301 val
+bqctsjyrnn 1 300 train
+bqcwckuzax 1 300 train
+bqcwxmwszy 1 300 train
+bqcysevbwg 1 298 val
+bqdaqfinwz 1 300 val
+bqdatpidkt 1 300 train
+bqddiaxzhj 0 300 val
+bqdgeuxypv 1 300 val
+bqdhnaeihb 0 299 train
+bqdjzqhcft 1 300 train
+bqdonuyjry 1 300 train
+bqdpxnfcsu 1 300 train
+bqdqdxmoui 0 300 train
+bqdrhathha 1 300 train
+bqdsdhohtm 1 298 train
+bqdtcwkxmk 1 300 train
+bqdwopiwjc 1 300 train
+bqdwxaaiom 1 300 train
+bqefygjsnx 1 300 test
+bqeiblbxtl 1 300 train
+bqembdwwnd 1 300 train
+bqeqdwugwm 1 300 val
+bqerbkbkba 1 300 train
+bqexkiylpo 1 300 train
+bqexsfjguv 1 300 train
+bqfbhkinte 0 300 train
+bqfnqqxyoo 1 298 train
+bqfuqvtgux 0 300 train
+bqfyfhzjxk 1 300 train
+bqgcnlkcmv 1 301 val
+bqggazjfbt 1 240 train
+bqgreinner 1 300 val
+bqgtmfagak 1 300 train
+bqgwnuocdo 1 300 train
+bqhcjuivwg 1 300 train
+bqhemgndnm 1 300 val
+bqhkgtptfc 1 300 train
+bqhmyqnhev 1 298 train
+bqhnwhikid 1 300 train
+bqhoruyguq 1 300 train
+bqhpbchtjr 1 299 val
+bqhtpqmmqp 1 300 train
+bqhuqxrncx 1 300 train
+bqhzazlywa 1 300 train
+bqiamgofca 1 300 train
+bqibcqpnqi 1 300 train
+bqibrgyyfn 1 300 train
+bqierwdzet 1 300 val
+bqigqcheps 0 300 train
+bqiivuyign 1 296 train
+bqiknntqjb 1 297 train
+bqipgqbxuu 1 300 train
+bqitfztbmf 1 300 train
+bqiyhktjsa 1 300 train
+bqiztwtgcu 0 300 train
+bqjaliddvr 1 301 train
+bqjekhchdu 1 301 train
+bqjhlweyyl 1 300 train
+bqjmnairer 1 300 train
+bqjokxjmur 0 300 train
+bqjrhuuwsf 1 300 train
+bqjuahxbtp 0 300 val
+bqjudquukz 1 300 val
+bqjvcxxtho 1 300 val
+bqjwectfoj 1 300 train
+bqkabvwndz 1 300 val
+bqkcbecxvc 1 300 val
+bqkcuexgba 1 300 train
+bqkdbcqjvb 1 300 train
+bqkjjzotyp 1 300 train
+bqkjvmuhkq 1 300 val
+bqkmlqpaqw 1 300 train
+bqkrgdfmjk 1 301 train
+bqkvyejoel 1 300 train
+bqlbvmpxqe 1 300 train
+bqlgllqdco 0 300 val
+bqlgvoexky 1 300 val
+bqljfirjtb 1 300 train
+bqlkwfkqbx 1 240 train
+bqlzpuxbrl 1 300 train
+bqmanbtedb 1 300 train
+bqmbdlgufw 1 301 val
+bqmdjsdegp 0 300 train
+bqmqwdsrsk 1 300 train
+bqmsfnzudu 1 299 train
+bqnkjutgfo 1 300 train
+bqnnwenews 1 300 train
+bqnrrwlhoa 1 300 train
+bqnwpojdfk 1 300 train
+bqnymlsayl 1 300 train
+bqnzpbppur 0 300 val
+bqofmblzfe 1 298 val
+bqogivlqei 0 300 train
+bqogzulufl 1 300 train
+bqokvgyvbc 1 300 train
+bqoqedoppu 1 300 train
+bqouowbtrc 1 300 train
+bqouzypnln 1 300 val
+bqoxkjjlcc 1 298 train
+bqpiaibadq 1 299 train
+bqplpvwekb 1 300 train
+bqpmahicpp 1 298 train
+bqpnzxepcz 1 300 train
+bqprogzerf 1 300 train
+bqprzvsqfd 1 300 val
+bqpueovmwa 0 300 train
+bqpwmmesgq 0 300 train
+bqpyatbfsb 1 300 train
+bqpzzgbvjz 1 300 train
+bqqaetrjss 1 298 val
+bqqmdklucx 1 300 train
+bqqmwptktz 1 300 train
+bqqnhlcjwm 1 300 train
+bqqpbzjgup 1 300 train
+bqqpqklcta 1 300 train
+bqraxecmjq 1 300 train
+bqrcgzqhnm 1 300 val
+bqreaktkan 1 300 train
+bqrhsggyfz 1 300 train
+bqrmazghsj 1 300 train
+bqrohsgyux 1 300 train
+bqrqgidhyk 1 300 train
+bqrqsamrah 1 300 train
+bqrtvrlann 1 300 train
+bqruljgfil 0 300 train
+bqrwevyzov 1 300 train
+bqsgbqtdct 1 300 val
+bqsgkcshnr 1 300 train
+bqsodelzkw 1 300 val
+bqsrmckjrm 0 300 train
+bqsrwyygcb 1 300 train
+bqstyqrqpk 1 300 train
+bqsxxzyzyu 1 300 val
+bqtfntlnum 0 300 train
+bqtleesmzc 0 300 train
+bqtnaozkjr 0 300 train
+bqtterqjyn 1 301 train
+bqtuuwzdtr 1 300 train
+bqtwvmatah 1 300 val
+bqtxylbmhe 1 300 train
+bquajsvklg 1 301 train
+bquiqmqbor 1 298 train
+bquixjwgjq 1 300 train
+bqumyoprdn 1 300 val
+bquonljvjy 1 300 train
+bquwvbrgfm 1 298 train
+bquybimorp 0 300 train
+bqvhlqlrba 1 300 test
+bqvoaiurbg 1 240 train
+bqvwjrwtvs 1 300 train
+bqwdvtkafu 1 301 train
+bqwuxpgqnk 1 301 train
+bqwvfqlprg 1 300 train
+bqwwkjlmgv 1 300 train
+bqwwxglqcv 1 298 val
+bqwzynnsst 1 300 train
+bqxafndwgr 1 241 train
+bqxejanadt 1 300 train
+bqxfmskjdz 1 300 train
+bqxxjdrlhv 1 300 train
+bqyawguxnm 1 300 val
+bqyckibuee 1 300 train
+bqydwaxekh 1 300 train
+bqygxyhzzl 1 300 train
+bqylqctsxk 1 300 train
+bqyngxqxct 0 300 train
+bqyrbupdex 1 301 train
+bqysooqqdw 1 300 train
+bqyswmtesa 1 300 train
+bqyvjfmtxk 1 300 train
+bqyybmnxmk 1 301 train
+bqzlymwvak 1 297 val
+bqzmgkfxho 1 300 train
+bqzqcnytto 1 300 train
+bqzsitzzze 1 241 train
+bqzvpucnoz 0 300 train
+bqzxvddxhv 1 300 val
+bqzyamzyfb 1 241 train
+braakxlqhr 1 300 train
+brabohxhes 1 300 train
+brafehfdef 1 300 train
+brakjxmeoy 1 300 train
+brakusjkza 0 300 val
+brarsdswho 1 300 train
+brbajvtovp 1 300 train
+brbcvfndkb 1 300 train
+brbjuopcko 1 300 val
+brbkdjhodw 1 300 train
+brcwfkskbu 1 300 train
+brdgxmzyer 1 300 val
+brdivlkikp 0 300 train
+brdkwozbwk 1 300 train
+brdlencarq 1 300 train
+brdqnpyymu 1 300 train
+brdrapqoos 1 300 val
+brdrhtpwut 1 301 train
+brdsxrolik 1 298 train
+brdtgbokzj 1 300 train
+brduxzmmca 0 300 train
+brdymbhmhn 1 300 train
+bredrtjqhi 1 300 train
+brehocipmz 1 300 train
+brejilxlpx 0 300 train
+brerfovadr 1 300 train
+breyjhknsa 1 300 val
+brfdijfgph 0 300 train
+brfdnuzzwi 1 300 val
+brfhgnvpvu 1 300 train
+brfisiknjr 1 300 train
+brfjxrbezo 0 301 train
+brftztqwxi 1 299 test
+brfwaxtfov 1 302 train
+brfzvumdyc 1 300 train
+brgcqjtlie 1 300 train
+brgdbelisj 1 300 train
+brginvruka 1 300 train
+brgmdrsuld 1 300 train
+brgnsmjnde 1 301 train
+brgqcocycc 1 298 train
+brgyfpiahs 0 300 train
+brhalypwoo 1 300 train
+brhhehdcsa 0 300 train
+brhkdbpjpv 1 299 train
+brhlyhehrq 1 300 train
+brhpxdxbcy 1 300 val
+brieynzztz 1 301 train
+brihlutndc 1 300 test
+briiqgrhsv 1 300 val
+brimyzwzdx 1 301 train
+brinacubmg 0 301 train
+briquegqph 1 300 train
+brirqrndwc 0 300 train
+brisaxviqo 1 301 train
+briujhlomc 0 302 train
+briushizfu 1 300 train
+brjeffhbzl 1 300 train
+brjgfdmuha 1 300 train
+brjhlfkapw 1 300 train
+brjvozjthm 1 300 train
+brjzgbsmye 1 300 val
+brksqjugjp 1 300 train
+brlbfrwlxc 1 300 val
+brlfypwhcj 1 300 train
+brlgldrllv 1 301 train
+brljbkqojj 1 300 train
+brlkkskcpw 1 300 train
+brllfylzgs 1 300 train
+brlraaempq 0 300 val
+brnclqrplz 1 300 train
+brnfoxrlfy 0 300 val
+brnmynbswu 1 300 train
+brnpejbjwh 0 300 train
+brnqhplixg 1 300 train
+brnrjjaoax 1 300 train
+brnucgxfmt 1 300 val
+brodhrtljb 0 300 train
+brokmubtek 1 300 train
+brpegrpuhx 1 300 train
+brpeicyhrl 1 300 val
+brpgchpere 1 300 train
+brpgearflr 1 300 train
+brpkkgdggv 1 300 test
+brpkpuuncm 1 300 train
+brpowziqei 1 300 train
+brpyycqyiw 1 300 train
+brqcongpqi 0 241 train
+brqcvpnvvt 1 300 train
+brqdzotqzx 1 298 val
+brqefywkfn 1 300 train
+brqkpzprld 1 300 train
+brqmvsxeaz 0 300 train
+brqpanquyn 1 300 train
+brqpnrcufe 1 300 train
+brqqhvmbiv 0 300 train
+brraezrejv 0 300 train
+brrbwodviq 1 300 val
+brrdxgrikt 1 300 train
+brrgojqquo 0 300 train
+brrsjdxmln 1 300 train
+brrspejlrg 1 241 train
+brrzqrgfcf 1 300 val
+brsdjjdfcd 1 300 train
+brsjbddase 1 300 train
+brskypiqwa 1 300 train
+brspmlldvm 1 300 train
+brsqxzfeyl 1 300 train
+brsruvuols 1 300 train
+brthpcihdg 1 300 train
+brtujopkby 1 300 test
+brtvlphcwy 1 300 train
+brtvxkbjgb 1 300 train
+brtwfaprks 1 300 train
+brtxipjzxx 1 300 train
+bruayouvht 1 300 train
+brujrbhnsp 1 300 train
+brukfvnunx 1 300 train
+brupgajmqh 1 300 val
+brurluwgmb 0 301 train
+brutqynawb 1 300 train
+bruuugwvqy 1 300 train
+brvjlapnpa 1 300 train
+brvndbrrzl 1 300 train
+brvnvecdnm 0 300 val
+brvqixoblx 1 300 train
+brvqtabyxj 1 300 train
+brvsnraikz 1 300 train
+brvvrselpv 1 300 train
+brvwkvyqef 1 297 train
+brvxrubfio 1 300 train
+brvyquicjc 1 300 train
+brvzlewxse 1 301 val
+brwnebfnea 0 241 train
+brwrlczjvi 0 300 train
+brwxskkygk 1 301 val
+brxjwopuzg 1 300 train
+brxksmkyrv 1 301 val
+brxnhacofm 1 300 train
+brxswajyjy 1 300 val
+brxuxcgifd 1 299 val
+brybbmsfbz 1 300 train
+brydrdnlln 1 300 train
+bryjhlfvuv 1 300 train
+brytlwyeis 1 300 train
+brytuyzbsp 1 300 val
+bryusijbzk 1 300 train
+bryxfrlkul 0 300 train
+brzdjfpndf 1 241 train
+brzfxbzteo 1 300 val
+brzhadgdbo 1 300 train
+brzhdnagey 1 300 train
+brztlyyauu 1 300 train
+brzvtuamta 1 300 val
+brzwrlifji 1 300 train
+bsabeilplr 1 300 val
+bsadzbixub 1 300 val
+bsairngrxq 1 300 val
+bsalymlxbf 1 300 val
+bsarexshsm 1 299 test
+bsasrtgagk 1 302 train
+bsaxncmxzz 1 300 train
+bsbeopblkx 1 300 val
+bsbnaftjxd 1 300 train
+bsbpkuphfu 1 302 train
+bsbpxvkcxj 1 300 train
+bsbvmbuudg 1 300 train
+bsbyvsgodg 1 299 test
+bsbztddlfe 0 300 train
+bsckuhakfc 1 300 train
+bsctqevgne 1 301 train
+bscvtmdkle 0 300 train
+bsdelhlyfi 1 300 train
+bsdeqywpgo 1 300 train
+bsdfkmlkwc 1 301 train
+bsdhxityss 1 300 train
+bsdwnkwzya 1 300 train
+bsdxszzuoz 1 300 train
+bsdyiglgaw 0 300 val
+bsdyjymwcg 1 300 train
+bseaalaspv 1 241 train
+bseamdrpbj 1 300 train
+bsedzrojkw 1 300 train
+bseexxfifs 1 300 train
+bseqngknsh 1 298 train
+bserejknun 1 300 train
+bsevwuoabp 1 300 train
+bsfaoypybt 1 300 val
+bsfgmptjvf 1 300 train
+bsfguxegoj 0 300 val
+bsfmwclnqy 1 300 train
+bsfylnbgww 1 300 train
+bsfzugrovq 1 300 train
+bsggqpqhqm 0 300 train
+bsghddlheb 1 300 train
+bsgontfxue 1 299 val
+bshahlewfg 0 300 train
+bshbncamhk 1 300 train
+bshbugoyua 1 288 train
+bshezooygm 1 300 train
+bshmwbzewf 1 301 train
+bshrczdaaq 1 300 train
+bshsjmxhii 1 300 train
+bshuxtpqks 1 300 val
+bshvtgcqnu 1 300 val
+bshwsknqwm 1 300 val
+bshxgvkdoe 1 300 val
+bsifdjkipn 1 300 train
+bsiftwkbhu 0 300 train
+bsihvtnbbd 1 269 train
+bsijbywcuc 1 300 val
+bsimeittcm 0 300 train
+bsipuogpmm 1 298 train
+bsipwfdphz 0 300 train
+bsissxcigs 1 301 train
+bsiyyhceog 1 300 train
+bsjdjscnec 1 292 train
+bsjezfsydc 0 296 val
+bsjmrddppa 1 300 train
+bsjsqcyyat 1 300 train
+bsjubsobtp 1 296 train
+bsjucwhlrj 0 300 val
+bsjxpacdow 1 300 train
+bskakfwghd 0 300 val
+bskbnuotjw 1 301 val
+bskboeadhh 0 300 train
+bskpyfkxpt 1 300 val
+bskrcrgnpu 1 300 train
+bskwbhoenl 0 300 train
+bslhiabmve 1 300 train
+bsljqykhwa 1 300 train
+bslqxmastf 1 300 train
+bslrftpuil 1 300 train
+bslvoeizbx 1 299 train
+bsmjyfctpp 1 241 train
+bsmnmuyakc 1 300 train
+bsmqhfbiau 1 300 train
+bsnkefbpyl 1 301 train
+bsnodtboti 1 300 train
+bsnqmtobit 1 300 train
+bsnrcykrki 0 300 train
+bsnsresrqj 0 300 val
+bsnugtneym 1 300 train
+bsnweoiova 1 300 train
+bsnxoayogp 1 300 train
+bsocqapnce 1 300 train
+bsojiruzej 1 300 train
+bsoliazwrw 1 298 train
+bsorbbpkdb 1 300 train
+bsovvblcxg 0 300 train
+bspcyahzeb 1 300 val
+bspjsikjnv 1 299 train
+bsplcozagn 1 300 train
+bsprlfyyyc 1 193 train
+bspvtixfud 1 300 train
+bspwelmoiu 1 300 train
+bsqaehcxmo 1 299 train
+bsqbjujjwx 1 300 val
+bsqgziaylx 1 300 train
+bsqnzpidrn 1 300 train
+bsqvhrfnry 1 300 train
+bsrjbcgtbn 0 300 val
+bsrjirhzqk 1 300 train
+bsrsspbbnf 1 300 val
+bsrvrzenjo 1 300 val
+bsrwincazk 1 300 train
+bssakhqkjg 0 300 train
+bssfqydpps 0 300 train
+bssfubhffo 1 300 val
+bssgfnaqow 1 298 val
+bsshkhbuzf 1 300 train
+bsslblmznk 1 300 train
+bssmemwqkp 1 300 train
+bsspfyrpnw 1 300 train
+bstbbiefie 1 300 train
+bstcnjqpwp 1 300 train
+bstetrqars 1 300 train
+bstqwhzjbq 0 300 train
+bstqzsknhe 0 300 train
+bstrajsndp 1 300 train
+bsttzosatq 1 300 train
+bsuebllrri 1 300 train
+bsuhgbshgt 1 241 train
+bsujqrtvla 1 300 train
+bsuplrkjtj 1 300 train
+bsuqanofuh 1 297 train
+bsutyosbsx 0 300 val
+bsuwzyhubl 1 300 val
+bsvhwfagxu 1 301 train
+bsvmqlmucm 1 300 train
+bsvwcilhko 1 300 train
+bsvwmqamfn 1 298 val
+bswcgixolx 0 301 train
+bsweemufbk 1 300 train
+bswmkbounl 0 302 train
+bswmxwhjml 1 300 train
+bswmymhtgq 1 300 train
+bswniyvcng 0 300 train
+bswoxmwklo 1 300 train
+bswrobxrrf 1 241 train
+bswzrlzckw 1 300 train
+bsxdhuuczi 1 300 train
+bsxewdhhaf 1 301 train
+bsxikakpoo 1 300 train
+bsxirggilb 1 300 val
+bsxpgkrxim 0 300 train
+bsxuicplux 1 301 train
+bsxuigrkhw 1 300 test
+bsxvcxceca 0 300 train
+bsxznrgkpz 1 241 train
+bsybhvudsq 1 300 train
+bsyeupjlxh 1 300 train
+bsyfztbcjb 1 300 train
+bsyilberhz 0 288 train
+bsyvuzsydi 1 300 val
+bszazaqmdn 1 298 train
+bszeuwuqzv 1 300 train
+bszgsnlink 1 300 train
+bszrnwrqcq 0 300 train
+bszswtwrra 0 300 train
+bszvlysebs 1 300 train
+bszybpoibo 0 300 train
+bszzvytfvr 0 300 train
+btaidzkrks 1 300 train
+btanrlpgrm 1 300 train
+btaobqocgt 0 300 train
+btaonipbve 1 300 val
+btaotmxdpu 1 300 train
+btasosiwtd 1 300 train
+btasrybbjp 1 300 train
+btatuyvjcz 1 299 train
+btaxjrlnmj 1 300 train
+btayrbgjxm 1 300 train
+btbagxtphm 0 300 train
+btbepogvyl 1 300 val
+btbfrzgcqo 1 300 val
+btblynpcuu 1 300 train
+btbtmvypjx 1 300 val
+btbvjzjlqz 1 300 train
+btcaqtjdjz 1 300 val
+btcbzekdto 1 240 train
+btcezppbsv 1 300 train
+btclqnwhrs 1 300 train
+btcrnbwagj 1 301 train
+btcuttrcxi 0 300 train
+btcytckhfx 1 298 val
+btdafakibt 1 300 train
+btdiyxibce 0 300 train
+btdjfsvmvz 1 300 val
+btdlkmhtfz 1 300 val
+btdnewmtrq 1 298 train
+btdqgmtqry 1 298 train
+btdxnajogv 0 300 test
+btdxroldqb 1 300 train
+bteafrnibw 0 300 train
+bteaoilopu 1 301 val
+btepqqdyrq 1 240 val
+bteskoapty 1 300 train
+btexelaydt 1 300 train
+btfeympfrf 1 299 test
+btfsgaxvym 1 299 test
+btgclwcmdv 1 300 val
+btggyjectf 1 300 train
+btgjzdszxd 1 300 train
+btglxmjpxn 1 300 val
+btgotbktnq 1 300 train
+btgpmxokzm 1 298 train
+btgqgkdwaf 1 300 train
+btgxrrldio 0 300 train
+btgxrvmrwy 1 300 train
+btgzigifjb 1 300 val
+bthhobpzyq 0 300 train
+bthkrdubbz 1 301 train
+bthqdyjlfw 1 300 val
+bthweewuqp 0 300 train
+bthztedsuv 1 300 train
+btieonhidz 0 300 train
+btieyruzwf 1 300 train
+btighkhfss 1 302 train
+btinmklnyn 1 300 train
+btirbpdxwb 1 300 train
+btiwatmwqq 1 300 train
+btiysiskpf 1 300 train
+btiznanugc 1 300 train
+btizoxwqwp 1 300 test
+btizzvkqij 1 300 val
+btjckbczmb 1 300 train
+btjixzlpao 1 300 train
+btjlfpzbdu 1 300 train
+btjooqbucg 1 299 train
+btjwbtsgln 1 300 train
+btjzirvujj 1 300 train
+btkbqjbpye 1 301 train
+btkbucqnkp 1 300 train
+btkesmtixy 1 297 val
+btkhzjaqho 1 300 train
+btkixixznd 1 300 val
+btknugoagq 1 300 train
+btkqjzxhbk 1 300 train
+btkwpzfjbu 1 300 train
+btlfyxivqz 1 300 train
+btlklhcrzt 1 300 val
+btlmahwnmq 1 300 train
+btlnvoiykr 0 300 val
+btlojvpizg 1 300 train
+btlpuzghpr 0 300 train
+btlqqvfuck 1 300 train
+btlxmzfhup 1 300 train
+btlxobdodr 1 300 val
+btlxrnkrja 1 300 val
+btmcuzeapy 1 300 val
+btmhnidnpq 1 300 train
+btmsngnqhv 1 300 train
+btmstjvczd 1 241 train
+btmugjmgmu 1 300 train
+btmwchvxxo 1 300 train
+btmzqsbqoh 1 300 train
+btmztqmmgb 1 300 train
+btnbabtddl 1 300 train
+btnolnefoi 0 300 train
+btnpmgzbvh 1 297 train
+btnrjiboxc 1 300 train
+btnwgrtgsv 1 300 train
+btnxcinzyi 1 300 val
+btodwmstfj 1 300 test
+btogwbvgdd 1 300 train
+btohlidmru 1 300 train
+btootkmwxu 1 300 train
+btovwozcsm 0 241 train
+btozdqscxv 1 300 train
+btozxiwphj 1 300 train
+btpaxvxwid 0 300 train
+btpetotxac 1 300 train
+btpfafkyyx 1 300 train
+btpiahrzcc 1 301 train
+btpkpovlba 0 300 train
+btprcgwwiu 1 236 train
+btpsqnldul 1 301 train
+btpyolbxtq 1 300 train
+btpzgbnlzn 0 300 val
+btqedjcqpt 1 300 train
+btqfyzguwg 1 300 train
+btqgwrjgwn 1 300 train
+btqktbhalb 1 300 val
+btqmbxcpsc 1 299 test
+btqqucipfc 1 300 train
+btrnnpruie 1 300 train
+btrtwbssow 1 300 train
+btrzghvcoy 1 300 train
+btsbqigrcq 0 300 val
+btsrawjyyo 1 300 train
+btsyjxkhsz 1 300 val
+bttdwvsioz 1 300 val
+btthcvhtbn 0 300 train
+bttjrhkjec 1 300 train
+bttkvdunwu 1 300 train
+bttpbjbxio 1 300 train
+btufmkbsmt 1 300 val
+btugbdzrnx 1 302 train
+btugrnoton 1 300 train
+btuilumhlk 1 300 val
+btuivreuqv 0 300 train
+btunqpphxn 0 300 train
+btunxncpjh 1 300 train
+bturisblmo 1 300 val
+btvabyfyct 1 300 val
+btvfejqhvm 1 298 train
+btvfmagwff 1 300 train
+btvmjiulnh 1 300 train
+btvxpbzdth 1 300 val
+btvzdlravc 1 300 train
+btweniisjp 1 300 train
+btwlwpcqpc 0 300 train
+btwyaugquo 1 300 train
+btxbhzzeim 1 300 val
+btxdrbdnpu 1 300 val
+btxgjsonxg 0 300 train
+btxjufhiaz 1 300 train
+btxlttbpkj 1 300 train
+btxlyyywwo 0 300 train
+btxrqvixnh 1 300 val
+btxusvfopn 1 300 train
+btydshktss 1 300 train
+btyfnqjhhm 1 300 train
+btyhdzhpvg 1 301 val
+btylobgyqk 1 300 train
+btypbhkzns 1 298 train
+btyqcbvpmp 1 300 train
+btyxvpjgcc 1 300 test
+btzdobfdib 1 300 train
+btzmrbjvay 1 300 train
+btznklglil 1 300 train
+btzqiokysa 1 300 train
+btzrnskuas 1 301 train
+btzrvmskue 1 300 train
+btzxsegllg 1 300 train
+btzyhavygb 1 300 train
+buabafojmo 1 241 train
+buadafzmbv 1 300 train
+buahvxqetu 1 300 train
+buavuaumij 1 300 train
+buayleceyc 1 300 train
+buazfjnzud 1 300 val
+bubbmjnmge 1 300 train
+bubjotismp 1 300 train
+bubkdbpjze 1 300 train
+bubxtvtutc 1 300 train
+bucatqvrrb 1 300 train
+bucdtamdfj 1 300 train
+bucoykgnou 1 300 train
+bucsokxbxr 0 301 train
+buctvoahji 1 300 train
+bucyxkdorm 1 241 train
+budabfnbql 1 300 train
+budaogjsut 1 300 train
+budsnjjxgl 1 299 train
+budxidfpka 1 300 val
+budxlbakyt 1 300 val
+buebohuobd 1 300 train
+buedjxrowy 0 300 val
+buefgtjncu 1 298 train
+buejhiahpy 1 300 train
+buekvfriwt 1 300 train
+buellpgdem 1 300 train
+buemqdmdwu 1 300 train
+buesukpgjd 0 241 train
+buetglnwvn 1 301 train
+buetnnfjqk 1 300 train
+buevdyrebw 1 300 train
+buewbjrjan 1 300 train
+buezutuhse 1 300 train
+bufechrihn 1 300 val
+bufihmkmfb 1 300 train
+bufktfyxtx 1 300 train
+bufndeiogn 1 300 train
+bufnvvnjiq 0 300 val
+bufrlvvuuu 0 300 train
+bufvpnusnx 1 300 train
+bufvvgvocm 1 300 val
+bufwbibdil 1 300 train
+bufwdtjsqq 1 300 train
+bufwekvezk 1 300 train
+bufydtkvxt 0 301 train
+bugaehhdlh 1 300 train
+bugaupvytx 1 300 train
+bugiwrwsfe 1 299 test
+bugxjsgwly 1 300 train
+bugxrvvgxj 0 300 train
+bugymqgirs 1 300 train
+buhcfgpuyk 1 300 train
+buhfpfqwnq 1 300 train
+buhiqfnqdw 1 300 val
+buhkwwyhmz 1 300 train
+buhqsrexai 1 300 train
+buhshnytys 1 300 train
+buhvwnaupu 1 300 val
+buhyokzkfx 1 300 train
+buiepzoyns 1 241 train
+buijfanqgj 1 300 test
+buipioytio 1 300 train
+buiqozfdfl 1 300 train
+buitfbvjro 1 300 train
+buiymunszl 1 300 train
+bujbpickcu 0 300 train
+bujcaxkrus 1 301 val
+bujdofzyyo 1 300 val
+bujfknruqx 1 300 val
+bujfvpizen 1 300 train
+bujfwowzml 1 302 train
+bujurekuaj 1 300 train
+bujwhunklh 1 300 train
+bujwlvyzkr 1 241 train
+bujyjkoxay 1 300 train
+bukdnrigys 1 300 val
+bukegrztbb 1 300 train
+bukhphgdyf 1 300 train
+buklnvarnx 1 300 train
+bukofdgxss 0 300 val
+bukrdolgaa 1 300 train
+bukrebcogf 1 300 val
+buksjavbec 0 300 train
+buktacsuax 1 300 train
+bukujzbexf 1 300 train
+bukvgbjddg 1 300 train
+bukwbjjdfm 1 300 train
+bulbfxxnzi 1 300 train
+buldirtpop 1 300 val
+bulkxhhknf 0 300 train
+bulmuhdpit 1 300 train
+bulowhgmrv 1 300 train
+bulpwfdiyl 1 300 train
+buluyyeszy 1 300 train
+bulvhtzaho 1 300 train
+bulvxgdlen 1 301 val
+bumaqmtzww 1 300 train
+bumbhuxpsb 1 298 train
+bumbxglchn 1 302 train
+bummyhnvwg 1 300 train
+bumsvfobjo 1 300 train
+bumwxmjfuz 1 300 train
+bumzkmncht 1 300 train
+bungaibitn 1 300 train
+bungnuqlye 0 300 train
+bunkputpqj 1 300 val
+bunqceeubj 1 300 train
+bunqneptba 0 300 train
+bunrneizgv 1 300 val
+buobaexigp 1 300 train
+buobjdgrnb 1 298 train
+buopqdpctq 0 300 train
+buottofqbp 1 239 train
+buovtlnzaz 1 300 train
+bupcliysfg 1 300 train
+bupevkfbpl 1 300 val
+bupexalpur 1 300 val
+buphywxmpz 1 300 train
+bupoarxobl 0 300 train
+buqdzgvzwx 1 241 train
+buqfbklybo 1 300 train
+buqjtkguuj 1 300 train
+buquceghsg 0 300 train
+buratlofzz 1 299 test
+burfhpfzwq 1 300 train
+burfxzoidv 1 301 val
+burglzjysn 1 300 test
+burmrmvkps 1 300 train
+burrttotog 1 300 train
+burxiwcpka 1 300 train
+busedsjyyy 1 300 train
+busqltixoy 1 301 train
+busutccrmc 1 300 train
+butcbdayfp 0 300 train
+butcqmdolz 0 300 val
+butkrmwxvd 1 300 val
+buttwssduj 1 300 train
+butydlltnu 1 300 train
+buuhhffxjt 1 300 train
+buuxmgfpny 1 300 train
+buuxutwofy 1 300 train
+buuznrwqwk 1 300 val
+buvbzstnuu 1 300 train
+buvhewxyxu 0 300 val
+buviahassp 1 300 train
+buvqtyoodn 1 300 val
+buwcfsbutz 1 300 train
+buwcowbrux 1 300 train
+buwcrmjdob 0 300 val
+buwlbeygpx 1 300 train
+buwsoahbql 1 300 val
+buwtezqrum 0 300 train
+buwvltmwfx 1 300 train
+buxigmcefw 1 300 train
+buxipbfbir 1 300 train
+buxkibosvm 1 300 train
+buxmjdnowq 1 300 train
+buxrvoggov 1 300 val
+buyjzpcgjw 1 297 train
+buyniyufbw 1 300 train
+buynrnqdoq 0 146 train
+buyvsvqvve 1 300 train
+buyvxbrqsc 1 300 train
+buywrbgfqy 0 300 train
+buyxgjifoh 1 300 val
+buzdtxdyid 1 300 test
+buzkrvzzlp 1 300 train
+buzktzndej 1 300 train
+buzlryubkx 1 300 val
+buzmtpwndq 1 300 train
+buznnntmnf 0 300 train
+buzqmuifod 1 300 train
+buzrvpriaz 1 300 train
+buzzvnnfkp 1 300 train
+bvaajzstgj 1 300 train
+bvaakzpfin 1 300 train
+bvaasrpdwi 1 300 train
+bvaffyvyjy 1 300 test
+bvagqyahki 1 300 train
+bvahacnzcf 1 300 val
+bvajqlmjnj 1 302 train
+bvaqaejmxv 1 300 val
+bvaujcjgih 1 300 train
+bvavrwigvx 1 300 train
+bvawamrser 1 300 train
+bvayavcphd 1 300 train
+bvayvrdpvp 1 300 train
+bvazvhiwji 1 300 train
+bvbekshaej 1 300 train
+bvbgrnnbsi 0 300 val
+bvbkmfvscw 1 300 train
+bvbnqnfmed 0 300 train
+bvbpmmiuoo 1 301 train
+bvbrngubgv 1 301 train
+bvbvhamqgd 1 298 train
+bvbxaenure 1 300 train
+bvbzyugjum 1 299 train
+bvccvjstvk 1 300 train
+bvcfduhsmp 1 300 train
+bvcgjefely 1 300 train
+bvchleajgn 1 301 train
+bvciamccyx 1 301 val
+bvcifkhbsr 1 300 train
+bvcmtwdive 1 300 train
+bvdkuotfnw 1 100 train
+bvdllgwnle 1 300 train
+bvdncdyxls 1 167 train
+bvdoltmmat 1 298 train
+bvdsccikao 1 300 val
+bvdsrnjtmn 0 301 train
+bvdtoxlnzp 1 300 train
+bvefyxjvqr 1 299 val
+bvejtrjahj 1 300 train
+bvekwhumry 1 299 test
+bverzqsqzn 1 300 train
+bvevsezfho 1 300 val
+bvfhvgdlnl 1 300 train
+bvfivlvvho 1 300 train
+bvfiynbqar 0 300 train
+bvflkesiug 0 300 train
+bvfnfsllna 0 301 train
+bvfpihoszq 1 297 train
+bvfqnxdqhw 1 300 train
+bvfxnmejnh 1 83 train
+bvgkmaupxn 0 300 val
+bvgkpjzhyn 1 298 train
+bvgrnjruko 1 300 train
+bvgwelbeof 1 300 train
+bvhfkpfyma 1 300 train
+bvhjnkhfml 1 300 val
+bvhmwphflz 1 300 train
+bvhqmyzqow 1 300 train
+bvhtcinegi 1 300 train
+bvhzopqkek 1 301 train
+bvibhzfhla 1 301 train
+bvicupuoqd 1 300 val
+bvienyqobe 1 300 train
+bvigkozalf 1 300 train
+bvimbeuchl 1 300 train
+bvixniyivj 1 300 train
+bvixqdtskk 1 300 train
+bviychitvv 1 300 train
+bvjdckijtv 1 300 train
+bvjdrocsro 1 300 train
+bvjebyqext 1 300 val
+bvjjrsdevv 1 300 val
+bvjqejuwtq 1 300 train
+bvjribybbl 1 300 train
+bvjvvndycq 1 300 train
+bvjvzesjjb 1 300 train
+bvjxtzewxo 1 300 train
+bvkfgeyaif 1 300 train
+bvkgmmcdxr 1 300 train
+bvkhyhzlre 1 300 train
+bvknfkehmq 1 300 train
+bvkscwjnrm 1 301 train
+bvkvhbitpp 1 300 val
+bvlarutxhl 0 300 train
+bvldfxzbgn 1 300 train
+bvlehtmqzn 0 300 train
+bvlkezasly 0 300 train
+bvllqnjzpy 1 300 val
+bvmarkafwe 1 300 val
+bvmdvwimmh 1 300 train
+bvmplbmqde 1 301 train
+bvmwqfbzur 1 298 train
+bvnapwoxqy 1 300 train
+bvnbkivoue 0 300 val
+bvndgybqfm 0 300 val
+bvnegesmxf 1 300 train
+bvnkvragwd 1 300 val
+bvnnzznzbi 1 300 train
+bvnqquehff 1 300 val
+bvnxqymzml 1 300 train
+bvohzhseoi 1 300 val
+bvonaznhpm 1 300 train
+bvopxpvhns 0 300 train
+bvoxyumctv 1 300 train
+bvpeerislp 0 299 test
+bvpfmkzeoi 1 300 train
+bvpqatdnyb 1 301 train
+bvpxwjlkkg 1 300 train
+bvqachgtwq 1 300 val
+bvqhfltctv 1 300 train
+bvqmbsvzfv 1 300 train
+bvqogultwl 1 300 train
+bvqpqvqaql 1 300 train
+bvquaufoey 1 300 train
+bvqvuhzzrq 1 300 train
+bvqxexttog 1 300 val
+bvrgsnsqql 1 300 val
+bvrgzscrwb 1 302 train
+bvrhhphtqv 1 300 train
+bvrhroydzw 1 300 train
+bvriycmcmp 1 300 val
+bvrmcqqgsp 1 300 train
+bvrozdlgrt 1 300 val
+bvrtaisfyr 1 300 train
+bvrxamwgcl 1 300 train
+bvrxyvtefw 1 300 train
+bvsnnjncmr 1 300 train
+bvsnqubtjc 0 300 train
+bvsoruxrea 1 298 train
+bvstgibbuo 1 300 train
+bvszoquzra 1 300 train
+bvszwamatk 1 300 train
+bvtdgrscfl 1 239 train
+bvtltnsjdy 1 83 train
+bvtscpmrlo 1 300 train
+bvufynfwom 1 296 train
+bvugfvbvno 1 300 train
+bvujlvvord 1 300 train
+bvuqrihkzd 1 300 train
+bvvbtgcwxk 1 300 train
+bvvioigqgs 1 300 train
+bvvlsicddb 1 300 train
+bvvqdjtowu 1 300 val
+bvvtplzwnt 0 300 train
+bvvuvwwpdw 1 300 train
+bvvybuutza 1 300 train
+bvwddbsvyb 1 300 train
+bvwilxrtif 1 298 train
+bvwksxjqtz 1 301 train
+bvwrnhxpqm 0 300 train
+bvwsprcjha 1 300 train
+bvxdpugtaf 1 302 train
+bvxgwnzdtg 1 300 train
+bvxtphxeku 1 300 train
+bvxxbmxjun 0 300 train
+bvyfekcshf 1 300 train
+bvyhnzgnjn 1 296 train
+bvyifjvvvq 1 300 train
+bvyldcywdh 1 298 train
+bvylomlyys 1 300 train
+bvymibgbsb 1 300 train
+bvypqxlkwq 1 300 train
+bvyvehqlnr 1 300 train
+bvyvzmnjwd 1 300 train
+bvzecoohzv 1 298 train
+bvzjkezkms 1 300 train
+bvzqruqijr 1 300 train
+bvzrlehshl 1 300 val
+bvzxdqpuzz 1 300 train
+bwaaxmpsmt 1 241 train
+bwabxrljfa 1 300 val
+bwabycoxai 1 298 train
+bwabyvtbyt 1 300 val
+bwadizhfgh 1 299 val
+bwaeskbdin 1 300 train
+bwaesrrdhr 1 241 train
+bwagweehvu 1 300 train
+bwahtlquns 1 300 train
+bwahxotfwz 1 300 train
+bwanrifpvc 1 298 val
+bwaorjqqwn 1 136 train
+bwappvfuol 1 300 train
+bwavhbqlew 1 297 train
+bwavwszqqa 0 300 train
+bwavzwevgr 1 300 train
+bwbgomtfhd 0 300 train
+bwbnjvsbcd 1 300 val
+bwbptvsuyr 0 300 train
+bwbtakdffv 1 143 train
+bwbzczjett 1 300 train
+bwcajtxluy 1 241 train
+bwcewwkedb 1 300 train
+bwchqtzzaq 1 300 train
+bwckcuufrs 1 300 train
+bwcvdarlrw 1 301 train
+bwcvtnpagf 1 298 train
+bwcwykvswt 1 301 train
+bwdagcnaix 0 296 train
+bwdcagaquo 1 300 train
+bwddspodaz 1 300 train
+bwditoozfz 1 300 train
+bwdmzwhdnw 1 300 test
+bwdpqyohuv 1 300 train
+bwdwnpyzbo 1 300 train
+bweczofkze 1 300 train
+bwedkrczpa 1 300 train
+bwedvpmotz 0 300 train
+bweepvlxli 1 299 val
+bweezhfpzp 1 300 train
+bwehhwkqio 1 300 val
+bweqhxlrrm 1 300 train
+bwetgseinq 1 300 train
+bwetzcoeor 1 300 train
+bwfgyssmlt 1 300 train
+bwfliathdg 1 301 train
+bwfljfamuu 1 300 val
+bwflusfvxg 1 300 train
+bwfoqrlrtz 1 300 val
+bwfuaxqmkt 1 300 train
+bwfulxdqjx 1 300 train
+bwfveznubc 1 300 train
+bwfwvdydyb 0 300 train
+bwgdnuptyi 1 300 train
+bwgfsespvf 1 298 train
+bwgsdyeptx 1 300 train
+bwhdmdqwba 0 301 train
+bwhfhcxxno 1 300 train
+bwhhkkwyrg 1 301 val
+bwhktckfjz 1 300 train
+bwhlgysghg 0 300 train
+bwhogljbze 1 300 train
+bwhxpexqsw 1 300 train
+bwibhtuldm 0 300 val
+bwidycpzpc 1 298 train
+bwigwpvbvn 1 300 val
+bwioafgsxg 1 300 train
+bwioxwmzmk 1 300 val
+bwipwzzxxu 0 300 train
+bwiqfmngml 1 300 train
+bwitpcpzcd 1 300 train
+bwiyygfbrz 0 300 train
+bwjjcravyb 1 300 train
+bwjnozfjrk 1 300 train
+bwjpicfmef 1 300 train
+bwjqcwhpfr 1 300 test
+bwjtdldunt 1 300 val
+bwjwxpxepr 1 300 val
+bwjxdrrgdn 1 300 train
+bwjzwayrkk 1 300 train
+bwkawtpdzy 1 300 train
+bwkddsdoqj 1 299 test
+bwkjzpzamn 1 300 train
+bwkmelwrit 1 298 train
+bwkvqzypli 1 300 train
+bwkwepbuvn 1 300 val
+bwkxgwbjhk 1 300 train
+bwkyuxjxxn 1 300 train
+bwlffzgmgp 1 300 train
+bwlrxzhaew 1 300 train
+bwlswdbfwv 0 241 train
+bwltaglnxn 1 300 train
+bwlxucgxro 1 300 test
+bwmauwledl 1 300 train
+bwmbbmtsfi 1 300 train
+bwmbcejdwb 1 300 train
+bwmfqkbmzx 1 300 val
+bwmgadcxfv 1 300 val
+bwmhmjdpbh 1 300 val
+bwmnobzril 1 300 train
+bwmqlgmzln 0 300 train
+bwmuqmisgx 1 300 train
+bwmyegjvoy 1 301 val
+bwmyzwofld 1 300 val
+bwnjmxuftf 1 300 train
+bwntewnmzx 1 300 train
+bwnugdtpui 1 300 val
+bwnwtomuus 1 301 train
+bwnxrxvjmb 1 300 train
+bwnxxypcuv 1 300 train
+bwocxfcknz 1 300 train
+bwoekgtvne 0 300 train
+bwojxfowiw 1 300 val
+bwopxuzykt 0 300 train
+bwpfzrtkvk 1 300 test
+bwpqrbtvdq 0 300 train
+bwpuxeqbso 1 300 train
+bwqbndignx 1 300 train
+bwqfjaxyjb 1 300 train
+bwqfwesgqk 1 300 train
+bwqjzgibcu 1 240 train
+bwqklxwhbd 1 301 train
+bwqugkcdhb 1 300 train
+bwquverbcd 1 300 train
+bwrdkiirsu 1 300 train
+bwressutay 1 300 train
+bwrlcrrlec 1 300 val
+bwrtykzswp 1 300 val
+bwrvwiwdbd 1 300 train
+bwrwssyltx 1 300 train
+bwryylpbof 0 300 train
+bwsekuehyo 1 300 train
+bwsfcdhbiw 1 300 val
+bwsfkrigda 1 301 train
+bwshqkblkm 1 300 train
+bwspwiymvk 1 300 test
+bwsytelwkm 1 300 test
+bwtbedxpxf 0 300 train
+bwtdwmcahh 1 300 val
+bwtfpriivh 1 300 train
+bwtgujxyhs 1 300 val
+bwtqavonmj 1 300 train
+bwtqnmbnbg 1 300 train
+bwtrfztpko 1 301 train
+bwtuvbsgfa 0 300 train
+bwtyeeplxj 0 300 train
+bwtywzusnc 1 300 train
+bwufrgxqoa 1 300 train
+bwukshdgpi 1 300 train
+bwuqlrwryv 1 300 train
+bwuqunogsd 1 300 train
+bwuvkociif 1 300 train
+bwuwstvsbw 1 300 train
+bwuxmtgmbv 1 300 train
+bwvbpzxyhp 1 290 train
+bwvmskoriy 0 300 train
+bwvrjppxlg 1 300 val
+bwvwdcbeol 1 300 train
+bwvxqmolob 1 300 val
+bwvzxzumop 1 300 train
+bwwazyhjav 1 301 train
+bwwcmftycf 1 300 train
+bwwdvjtzzp 1 300 train
+bwwhbelftf 1 237 train
+bwwnvrhzti 1 300 val
+bwwxahlxhr 1 300 train
+bwwxcxbqlq 1 300 train
+bwwyjtmnga 1 300 train
+bwwynencjv 1 300 train
+bwxafzjmgd 1 300 train
+bwxcxqmuyo 1 300 train
+bwxfakgakt 1 301 train
+bwxkwixtng 1 300 train
+bwxkyqwwcb 1 300 train
+bwxpsmsefj 1 300 train
+bwxsttjaxr 1 241 train
+bwxwlgbkal 1 300 train
+bwxwuttmul 1 300 train
+bwxxgqzihu 1 300 val
+bwxxqywljk 1 300 train
+bwykciwlwm 1 300 val
+bwykxtqvqo 1 301 val
+bwyqzvoqfw 1 300 train
+bwyvrcczte 1 301 train
+bwywgggeen 1 300 train
+bwywukcbwc 0 300 train
+bwyxdrzifm 1 300 val
+bwzchlyhcs 1 300 train
+bwzihweiem 1 300 train
+bwzpknlhhm 1 300 train
+bxajwykzqi 1 239 train
+bxaopaeshm 1 300 train
+bxapnpzklc 1 300 train
+bxarhcjufa 1 302 train
+bxbamhdtve 1 300 val
+bxbdzeloqp 1 300 train
+bxbfpzbkwl 1 300 train
+bxbhncwilh 1 300 train
+bxbuhetbxk 1 300 train
+bxbzpsnpbz 1 301 val
+bxcjzglhez 1 300 val
+bxcmqokvfk 1 300 train
+bxcorukbgi 1 298 train
+bxctqseswc 1 300 train
+bxctteujhv 1 300 val
+bxdabefxrj 1 299 train
+bxdbbvlsgg 1 300 train
+bxdbfogqbx 1 240 train
+bxdbivvrgj 1 299 val
+bxdhawuldp 1 300 train
+bxdhnnffvw 1 300 test
+bxdhtwymtv 1 300 train
+bxdvtzwciu 1 300 train
+bxdyjejzht 1 300 val
+bxebtlgbde 1 300 train
+bxedvimbqc 1 300 val
+bxefyimnqr 0 301 train
+bxejcionpa 1 300 train
+bxejobxcfz 1 300 val
+bxeomrckmg 1 301 val
+bxeprijnls 1 300 train
+bxexekqtcx 1 300 train
+bxeyjgwycq 1 300 train
+bxfkujjfez 1 300 train
+bxfneytcmm 1 300 val
+bxfnvvwjvc 1 300 train
+bxfwcyjvoc 1 301 train
+bxfwiuvafo 1 300 train
+bxfxykencc 1 241 train
+bxgbpdjgjv 1 300 test
+bxgesmkqrs 1 300 train
+bxgkydnxzv 0 300 train
+bxguvcttlt 1 300 train
+bxgwfbnzjp 1 300 val
+bxgxbipxxu 1 300 train
+bxgyxslimt 1 300 val
+bxhbxqgenk 1 300 train
+bxhgmfwpay 1 241 train
+bxhhongyce 1 300 train
+bxhitlorpq 1 241 train
+bxhksbnvvr 1 300 train
+bxhwuhfplb 1 300 train
+bxhyaulwtg 0 300 train
+bxihocgdku 0 300 train
+bxiuubszss 1 298 val
+bxiwtntoxf 1 301 train
+bxjeivqzjl 1 300 val
+bxjwspywsy 1 300 train
+bxkalrcdyx 1 300 train
+bxkevliysj 1 300 train
+bxkugtuzbx 0 300 val
+bxkvcjrywe 1 298 train
+bxldffbnsq 1 300 train
+bxlgkrahxg 1 301 train
+bxlhwmsfmt 1 301 train
+bxlixjwyrh 1 301 train
+bxlrbtzsvb 1 300 train
+bxlubhtvgm 1 300 train
+bxlyvithhr 1 300 train
+bxmlvyjhkm 0 299 train
+bxmowqlonf 1 297 train
+bxmvceoquu 0 300 train
+bxnfoseqvh 1 300 train
+bxnheaevzx 1 300 train
+bxnlryijhn 1 300 train
+bxnnamknve 1 300 train
+bxnnbryvwj 1 300 val
+bxnsimvjlv 1 300 train
+bxnwhbnjnp 1 300 train
+bxnzbjlgsx 1 301 train
+bxoctcdwgm 1 300 train
+bxoerjwing 1 300 train
+bxoevjjrya 1 300 train
+bxooifrfzo 1 300 val
+bxoqjcxxtk 1 300 train
+bxoykchsnk 1 299 train
+bxpcejafgx 1 300 train
+bxpglfjtcw 1 300 train
+bxpmmqgwdi 1 241 train
+bxpshvpljo 1 300 val
+bxptafpclo 1 300 train
+bxpxxsimjw 1 300 train
+bxqbcrxmgv 1 300 train
+bxqbpgkvfc 1 300 train
+bxqenxqvqi 1 300 val
+bxqercyauk 1 300 train
+bxqgvzamnx 0 300 train
+bxqmegfrni 1 300 train
+bxqmfgdlul 0 300 val
+bxqobapdzz 1 300 train
+bxqtrqyoqz 1 300 train
+bxqvffwfpd 1 300 train
+bxqwzqvtym 1 300 train
+bxqyjhikaj 1 300 train
+bxrefgauoq 1 300 train
+bxrgwxbhdt 1 300 train
+bxriwqpced 1 300 val
+bxrlaehmdg 1 300 train
+bxrlhupflv 1 240 train
+bxrongfgss 1 300 train
+bxrpqqvpfk 0 300 train
+bxrqolkezc 0 300 train
+bxrvoggdzi 1 300 train
+bxrxrggcnq 1 300 val
+bxsdnqizii 0 300 train
+bxswfhqcbc 0 300 train
+bxswpxalxm 1 300 train
+bxtaeanoyr 1 300 val
+bxtayevhbw 1 300 val
+bxtilcdxcx 1 240 train
+bxtlknuwkz 1 300 val
+bxttfmrdwr 0 300 train
+bxtxxxylhv 0 300 train
+bxujrixvnt 1 300 train
+bxumrqyphe 1 300 train
+bxuwznajtd 0 300 train
+bxvgrfojxm 1 298 train
+bxvloxsftn 0 300 train
+bxwagpxkmn 1 300 train
+bxwcsktmqw 1 300 train
+bxwfplauus 0 300 train
+bxwfxlvwpc 1 301 val
+bxwiflrowu 0 300 train
+bxwroajqua 1 300 train
+bxwswwesmk 1 301 train
+bxwuujgitg 1 300 train
+bxwwiwawbf 1 300 train
+bxxovxktqn 1 300 train
+bxxtccmbll 0 300 train
+bxxucoyrxf 1 300 val
+bxxyaufivh 1 147 train
+bxxyngjaoe 1 300 train
+bxxynjbyth 0 300 train
+bxxzymksik 1 300 train
+bxybhzadmx 0 300 train
+bxyhekvjiz 0 300 train
+bxyivgdcjz 1 301 train
+bxylmmtuwp 1 300 train
+bxyqedrfhz 1 300 train
+bxytmmfuvy 1 300 train
+bxzakyopjf 0 300 train
+bxzbhaiipr 1 300 train
+bxzjlrolfa 1 301 train
+bxzsqcfbjs 1 300 train
+bxzzexsjrl 1 302 train
+bxzzmbhwiu 1 300 train
+byaagkudca 0 300 train
+byaazdkgxo 1 300 train
+byadtrtxjq 1 300 train
+byahwgvhmf 0 300 val
+byaihidnns 1 300 train
+byajlgbxeb 1 300 train
+byavookkdu 1 300 val
+byaxuivhkl 0 300 train
+bybafebasv 0 300 train
+bybazuaxcd 1 300 train
+bybdriuzpt 1 300 train
+bybjnuvivn 1 300 val
+bybkpqmroe 1 300 val
+byblufwinv 1 300 val
+bybudefjsm 1 300 val
+bycahicdry 1 300 train
+bycbfeqofn 1 300 train
+bycdekauwy 1 300 train
+bycgsexgfc 1 300 train
+bycktzkuax 1 300 train
+bycqmnyqlt 1 300 val
+bycwjagbgy 1 301 train
+bycyalhlxv 1 300 val
+bydaidkpdp 1 300 train
+bydbcnqmyu 1 300 train
+bydbnonjwm 1 298 train
+bydpmsvhgd 1 300 train
+bydtnhfnyp 1 299 test
+byeisklyzt 1 300 train
+byemhhkenz 1 300 train
+byersrwsxu 1 301 val
+byfappkcff 1 300 train
+byfbiiyofy 1 300 val
+byfbrumcav 1 300 train
+byfcuclddy 1 300 val
+byfdhsjrkt 1 300 val
+byfenovjnf 1 300 train
+byfkwavped 1 300 val
+byfsbwnfgd 1 297 train
+byfuwjseuh 1 300 train
+bygbpfunju 0 300 train
+bygcjtxpzt 1 300 val
+bygddausiy 1 298 train
+bygextwxvc 1 300 train
+bygfmueyqb 1 300 train
+bygliesdxg 1 300 train
+bygmwmgzne 1 300 train
+bygtwucggu 1 300 train
+bygvmhzviq 1 301 val
+bygzwygloo 1 301 val
+byhcnbxbhc 1 300 train
+byhdgtfqrf 1 300 train
+byhfdzwppd 1 300 val
+byhnpxstqf 1 300 val
+byhrwehemb 0 300 train
+byhwdadqiz 1 300 val
+byichlxusl 1 300 train
+byifmfitsq 1 300 val
+byiiwussrx 1 269 train
+byijojkdba 1 298 train
+byiminimdm 1 300 train
+byipklfpep 0 300 train
+byiqfuoxfa 1 300 train
+byisrktdny 1 300 train
+byivdbmffg 1 300 train
+byizvwpqyx 1 300 train
+byjoihgsaq 1 300 train
+byjtjbuafp 1 301 train
+byjuufxrwl 1 300 train
+bykbyvzxog 1 300 train
+bykcwiczkr 0 300 val
+bykgnyykta 1 300 test
+bykjvweucb 1 300 train
+bykrypvyry 1 301 train
+bykuvjnkuf 1 300 train
+byldztfret 0 300 val
+bylffbests 1 300 train
+bylhbevqxy 1 300 train
+bylkmqbkkz 1 298 train
+bylogugnoj 1 300 train
+byloqytsws 1 300 test
+bylpobinsn 1 300 train
+bylxcfxqaf 1 300 train
+bylzbhgcal 1 300 train
+bymdnvzzvf 0 300 train
+bymiurlofm 1 300 train
+bymyhfqxns 1 300 val
+bynawljfed 1 147 train
+bynbpbjiwp 1 300 train
+bynggtiynv 1 300 train
+bynghiuoeh 1 299 train
+bynhsjcmfk 1 299 train
+bynjfympwi 1 300 val
+bynwaqcgnj 1 300 val
+bynwgxcpev 1 300 train
+bynyqmbonf 1 300 train
+byocokuicb 1 300 train
+byofjwgexm 1 300 train
+byofowlkki 1 300 train
+byolipgkkb 1 300 val
+byonsznecm 1 300 train
+byorayoofg 1 300 train
+byorlgkvai 1 300 val
+bypaqdwvlv 1 298 val
+bypcshpzue 0 300 train
+bypharnzvh 1 301 val
+byplrzvcgn 1 300 val
+bypnfnyrcl 1 300 val
+byprtayfed 1 300 train
+byprvddfxd 1 300 train
+bypsujbwls 1 300 train
+bypxnsuvaz 1 300 train
+byqcedsfap 1 300 train
+byqiopgklz 1 298 train
+byqugsmtxr 0 298 train
+byqvbitrlo 1 300 train
+byqvxfrtcw 1 240 val
+byqzyxifza 1 300 train
+byrbgeowil 1 300 train
+byrciauesi 1 300 train
+byrclwttja 1 300 train
+byrexxlpyj 1 147 train
+byrflccwdf 1 300 val
+byridjpwox 1 300 val
+byrjdpnkhz 0 300 train
+byrjpznuar 1 300 val
+byrzacjmjl 1 299 test
+byscxspxah 1 300 train
+bysdksedja 1 300 train
+bysmshsqpv 0 300 train
+bysnjpwrxs 1 300 train
+bysnlubywf 0 300 train
+bysogztscg 1 301 train
+bysromjvhc 1 241 train
+byszkjxwfh 1 300 val
+bytfrsxnwi 1 300 test
+bytiwsyfjr 1 300 train
+bytkymllqv 1 300 train
+bytliiuqij 0 300 val
+bytmknqtol 0 300 train
+bytncpzoqp 1 300 val
+bytpazjfhg 1 300 train
+bytzlcfmqy 1 300 val
+byubcjfkzu 1 300 val
+byunigvnay 1 300 train
+byupnsucvu 1 300 train
+byuqfzuwuh 1 301 val
+byusjuglvw 1 300 train
+byuyjtloht 1 300 train
+byuzgbyyrs 0 300 train
+byvezwafcl 1 301 val
+byvgilzydb 1 300 train
+byvglwkkoc 1 300 val
+byvnucyqov 1 300 train
+byvsfehvwc 1 300 val
+byvsfvznnn 1 300 train
+byvvodjkyx 0 300 train
+byvvtbefus 1 300 train
+bywhzpdgyz 1 300 train
+bywkfvypwj 1 300 train
+bywkwmtghl 1 301 train
+bywkznbyha 1 300 train
+bywosxcnwm 1 300 train
+bywsnzefxm 1 300 train
+byxasxlnqy 1 300 train
+byxbsuazip 1 300 train
+byxgtvarwn 1 300 train
+byxkpgcpzq 1 300 train
+byxuznmdfc 1 300 train
+byyfiqctdb 1 300 train
+byygypllwx 0 300 train
+byymvbttdc 1 301 val
+byyqectxqa 1 300 train
+byyttdzjen 0 300 val
+byyttvzbds 1 300 train
+byyyvzsaet 1 298 train
+byzboucruq 1 300 train
+byzdqbsjhs 1 300 train
+byzhqvspaz 0 300 train
+byzkrasazx 1 300 train
+byzmklwjro 0 300 train
+byzmxujeng 1 300 val
+byzphsqxzj 1 300 train
+byzqulbpmw 1 136 train
+byzsrsnsva 1 300 train
+byzvrxxlfn 1 300 train
+bzaauejtrm 1 300 train
+bzacdgllfn 1 300 train
+bzadvtcrbc 1 300 val
+bzagvgsgrf 1 300 train
+bzaqomdlim 0 300 train
+bzarzqgixt 1 300 train
+bzatlueaeu 1 300 train
+bzaukiurar 1 296 val
+bzbgfksqiq 0 300 train
+bzbmbnulzr 1 300 train
+bzbmowfkgs 1 300 train
+bzbtqgbrdl 1 300 train
+bzbvxuhvmj 1 300 train
+bzbvyrxzki 1 300 train
+bzclepvjkd 1 300 train
+bzcllqzvps 1 300 train
+bzcolqetwd 0 301 train
+bzcuildyyg 1 300 train
+bzcytcuhwh 1 300 val
+bzdhpjxqbp 1 300 train
+bzdktdzcpd 1 300 train
+bzdljqrsrr 1 300 train
+bzdowajxug 1 298 train
+bzdqwaacml 1 300 val
+bzdsgfhstw 1 301 train
+bzdywpajvr 0 300 train
+bzdztgsroy 0 300 train
+bzecksiwyd 1 300 train
+bzenjqbqag 1 300 train
+bzeovupukx 1 300 train
+bzexfqueet 1 300 val
+bzfhkpsthh 0 300 train
+bzflnbzosv 1 301 train
+bzfmmrqswa 1 298 train
+bzfmtqkuqn 1 300 train
+bzfuboxbjj 1 300 train
+bzfwuhytjx 0 300 train
+bzgactssoc 1 240 val
+bzgakeprpd 1 301 val
+bzgbexteux 1 300 train
+bzgntpuroz 1 298 train
+bzgsljmnmh 0 300 train
+bzhchxiwlf 1 300 train
+bzhksoaxbm 1 296 val
+bzhlcrxtyp 0 300 val
+bzhupudxee 0 300 val
+bzhvcqciis 1 301 val
+bzhvpxtkks 1 299 train
+bzhvtbfwdp 1 299 train
+bzhxqsgtyb 1 300 train
+bzichlknun 1 300 val
+bziekeavpv 1 297 val
+bzifuhigbw 1 300 train
+bziiryxwqb 1 300 train
+bziluffqhf 1 300 train
+bzipuxdfxu 1 300 train
+bzisviigbj 1 300 train
+bziyaparip 1 298 train
+bzizbjayot 1 300 train
+bzjihidtqo 0 300 train
+bzjsskmivr 1 300 train
+bzkcxleaos 0 300 train
+bzkdheimcx 1 300 val
+bzkgdqauwi 1 300 train
+bzkhwwwncm 1 300 train
+bzktkihnst 1 300 train
+bzkwftgenj 0 300 train
+bzkyhbjpbz 0 300 train
+bzlkxplojm 0 300 train
+bzmdrafeex 1 300 train
+bzmkdtmpch 1 300 val
+bzmkkccnkt 1 300 val
+bzmrzdjdfi 1 300 val
+bzmtrewkvz 1 300 train
+bzmucsxecs 1 300 train
+bzmvnbpgbz 1 300 val
+bznhaeanyi 1 300 train
+bznkogdxxi 1 300 test
+bznqlkvooi 1 300 train
+bznvpsqshz 0 300 train
+bznzcvjciy 1 300 train
+bzoazndgum 1 300 train
+bzobkqewtt 1 300 train
+bzoceqaseu 0 300 train
+bzogdhmnks 1 300 train
+bzohuudija 1 300 train
+bzokutzzkp 0 301 train
+bzonnzpmxa 1 300 train
+bzophvlfug 1 300 val
+bzovglavil 1 147 train
+bzpakhiczx 1 300 train
+bzprpvomfu 1 300 val
+bzpwwyrklf 1 300 train
+bzpyicwhcr 1 300 train
+bzqemivbgx 1 300 train
+bzqfrfmgzb 1 300 val
+bzqjhgpwef 1 298 train
+bzqkplrsnt 1 300 train
+bzqnpeicqh 1 300 val
+bzqsqecznf 1 300 train
+bzqsxmvxny 0 300 train
+bzqzktvzdn 1 299 test
+bzriviqbdr 1 300 train
+bzrizmbvgg 1 300 train
+bzrtpdlgmw 1 298 train
+bzruluulpm 1 300 train
+bzsdvoxjzz 1 300 train
+bzsfphmrxp 1 300 train
+bzsgsgytzb 1 300 val
+bzsnkjzneg 1 300 train
+bzsubopmrv 1 299 val
+bzswtcvvak 1 300 train
+bzswxzdiha 1 300 train
+bzsxifhdeq 1 300 train
+bzsxxqcyny 1 300 train
+bztdemptfg 1 300 test
+bztifpciva 1 300 train
+bztufjtujr 1 300 train
+bztuwilieg 1 300 train
+bzuszivgau 1 298 train
+bzuugbxlax 1 301 train
+bzvhtmpwbd 0 300 val
+bzvhvonbdu 0 300 train
+bzvkhvjaeo 1 300 val
+bzvlmeobfl 0 300 val
+bzvrgyjiuv 0 300 val
+bzvzpwrabw 1 300 test
+bzwajzslne 1 300 train
+bzwdrjjoiq 1 300 train
+bzwdvkgang 1 300 train
+bzwicfdrmu 1 300 train
+bzwjfgxdtt 0 300 val
+bzwkqogtyp 1 300 train
+bzwpeggkkr 1 300 train
+bzwtxeifuu 1 300 train
+bzxauvpscl 1 300 test
+bzxefrmihn 1 300 train
+bzxesmhumc 1 300 train
+bzxgrvhkiz 1 300 train
+bzxltcvyfu 1 300 train
+bzxrgnjxkx 1 300 val
+bzxyxbegoa 1 300 train
+bzyawroeif 1 300 test
+bzybxsrwxk 0 300 val
+bzymycufbd 1 300 train
+bzyojadoof 1 300 train
+bzypdvmjsf 1 300 train
+bzyrduvuqb 1 300 train
+bzythlfnhq 0 300 train
+bzyznixpio 0 300 train
+bzzbuvtrbq 0 300 train
+bzzcuuntfd 0 300 val
+bzzidlidde 1 301 val
+bzzovdtlpc 1 300 train
+bzzoylchma 1 298 train
+bzztsrsbwp 1 300 train
+bzzvxykyza 1 300 train
+caaackoecr 0 300 train
+caadsylcvz 1 300 val
+caaiwhbfwt 1 300 train
+caanukzrlh 1 302 train
+caatzjujmz 1 301 train
+caazxiiwzj 0 300 train
+cabhgzgpba 0 300 val
+cabjaiwamo 1 300 train
+cabseyquzo 1 300 train
+cabuhwkols 1 300 train
+cabvgwttll 1 300 train
+cabyiyjsxu 1 298 train
+cacaalogqa 1 300 train
+cacdswmrdp 0 300 train
+cacelrnvtt 1 300 val
+cacijczweb 1 300 train
+cacjezputw 1 300 train
+cacmgzyvyc 1 300 train
+caczudtlmw 1 300 train
+cadbalqwdd 0 300 train
+cadunqdqla 1 300 train
+caedadzzml 0 298 val
+caehfiqwkj 1 300 train
+caelizujev 1 300 train
+caemhpqbcd 1 299 train
+caernzpupa 1 300 train
+caesvcojqk 1 300 train
+caewyiwjvi 1 300 train
+caeyzwnpor 1 300 train
+cafdjsyupv 1 300 train
+cafmijjmoo 1 301 val
+cafsyijwpm 1 300 train
+caghftnarw 1 300 train
+cagiejwets 1 300 train
+cagkewgxcy 0 300 train
+cagkthsztk 1 300 val
+caglqvchdf 1 300 train
+cagoqwiopu 1 300 train
+cagtrwvmbf 1 300 train
+cagyovhtxp 1 300 val
+cahbpophdl 1 300 train
+cahhitfisu 1 300 train
+cahkacdgge 1 299 val
+cahtimcmlt 1 300 train
+cahwjeuszl 1 300 train
+cahwufnocx 1 302 train
+cahxxqxnto 1 300 train
+caiarjdpna 1 300 val
+caiawngylm 1 300 train
+caifxvsozs 0 300 train
+caikegrhfs 0 300 train
+caikthrakl 1 300 train
+cairgxleup 1 300 train
+caiunsnquf 1 300 train
+cajdcwtfui 1 296 train
+cajhyqynvq 1 300 train
+cajtodmmwx 1 300 train
+cajxctvlfj 1 300 train
+cakngmoakn 1 299 val
+caknjehogz 0 300 train
+cakvxxbzeg 1 300 train
+calgsvuncg 1 300 train
+calhtslbzf 1 300 test
+caljwhewpb 1 300 train
+callycoxbs 1 300 train
+calmewskjn 0 300 train
+calnloxfdm 1 300 val
+calqcklglq 1 300 train
+calwihtnjm 1 301 train
+calxueftte 1 300 train
+cambmhacur 1 301 train
+camjjcxnhk 1 300 train
+campcpgvlt 1 300 val
+canfhzwjyw 1 600 train
+canjrymigo 1 300 train
+canozerlob 1 300 train
+canptnddwm 1 300 train
+canzjpemnu 1 300 val
+caoabtjtyo 1 299 test
+caocfxbmjj 1 296 val
+caodevnstn 0 300 val
+caohlfazlx 1 300 val
+caolfufjvz 1 241 train
+caorcsgvsr 1 301 train
+caoxrvrous 1 240 train
+caozxiewds 1 300 train
+caperzzilq 1 300 train
+caphzofvrj 0 300 train
+caplninunw 1 300 train
+capsnbjwcz 1 300 train
+capxzwjsau 1 300 val
+caqbrkogkb 1 300 train
+caqcavomfk 0 300 train
+caqderfjql 1 301 train
+caqeuxhrdd 0 298 train
+caqiydrttj 1 300 train
+caqmcpipgz 0 300 train
+caqnknxgkb 1 301 train
+caqrutmoif 0 300 train
+caqwaugebu 1 300 train
+caqxtnrihi 1 300 train
+caqzqnpblx 1 300 val
+caretdrtec 0 300 train
+carqvcydoc 1 300 train
+carukmrjjo 1 241 train
+carulfalep 1 300 train
+carvrcfwwu 1 300 train
+casgtukpjx 1 300 train
+casnrbkwix 1 240 val
+casqbydkuv 1 300 train
+casqxjtmqh 1 300 train
+casvoqphmo 1 297 train
+caswnhgrxj 1 300 val
+catcjvrkoj 1 300 train
+catdhymrfz 0 300 train
+cathvygbkb 1 300 train
+catiovsmas 1 300 train
+cattfpuwme 1 300 val
+catwfsejfc 1 300 val
+catzvoailc 0 301 train
+caufgvqfsq 1 300 train
+caunvnarjg 1 300 val
+caunxhctes 1 300 train
+cauthxezhw 1 300 train
+cavecoxbzx 1 301 val
+cavfrfgzjk 1 300 train
+caviaggnam 1 300 train
+cavrlgtxhb 1 301 train
+cavudpefre 1 300 train
+cavuvyojnx 1 300 train
+cavvofhzgz 1 300 val
+cavwtpmmbr 0 300 train
+cavzfykhew 1 300 train
+cawedwneci 1 300 train
+cawfumepka 1 300 train
+cawpdvymcp 0 300 train
+cawyskypay 1 300 train
+caxdhwpyww 1 300 train
+caxihpdatp 1 301 train
+caxijxuzqk 0 300 train
+caxsyphmru 1 300 train
+caybmgfzgr 1 300 train
+caybvafaow 0 300 train
+caycdqrxlu 1 300 train
+caydsjdmfw 1 300 train
+caygzclxfm 1 300 train
+cayiasylxk 1 298 train
+cayjarbgsx 1 301 train
+cayliwbhpq 1 302 train
+caypwrfwar 1 300 train
+cazbojkyjz 1 300 train
+cazdiesnim 0 300 train
+cazdzhfmcn 1 300 train
+cazhchqjke 1 300 train
+cazmeaxiob 1 300 train
+caznfplucs 0 300 train
+caznppaeek 0 300 train
+cazuewqhvv 1 300 train
+cazuqtjfrn 1 300 train
+cbaetxcmkf 1 300 train
+cbanufeqzb 1 300 val
+cbaqbnugrn 1 302 train
+cbaubihobq 0 300 train
+cbbfjyhlxk 1 300 train
+cbbibzcoih 1 300 train
+cbbkxznyfe 1 300 train
+cbbmihedlz 0 300 train
+cbbndlfjds 1 300 train
+cbbndovxtb 1 300 train
+cbbugjbzwq 0 300 train
+cbbxnpvyqy 1 300 train
+cbccesmyto 0 300 train
+cbceueruqz 1 300 val
+cbcjilnpfa 1 300 train
+cbcjuhdped 1 300 train
+cbcpjcrjjd 1 300 val
+cbcqaaytvh 1 241 val
+cbcqcbezwv 1 298 val
+cbcvopctom 1 300 train
+cbcwdtsyqk 0 300 train
+cbdewpgqmx 1 300 val
+cbdfttbdog 1 300 train
+cbdkwabria 1 300 train
+cbdnonogrk 0 300 train
+cbdquwkipe 0 300 val
+cbdsqeqqgw 1 300 train
+cbdugpbwjz 1 300 train
+cbebeaznzy 0 300 train
+cbejoxikrt 1 143 train
+cbergyymhr 1 300 train
+cberkdkyfm 0 300 train
+cbesxvslls 1 300 val
+cbevuigodd 1 300 val
+cbeyfiklbe 1 300 val
+cbezijagez 1 300 train
+cbfbxgvcpd 1 300 train
+cbfdjiaktu 1 302 train
+cbfdwmtuoy 0 300 train
+cbffzyuzmb 0 300 train
+cbfumyluwq 1 300 train
+cbfvfsetoj 1 300 train
+cbfvkzmyus 1 300 val
+cbfyrdxxun 0 300 train
+cbfzxbwhdh 1 300 train
+cbgcawerse 1 300 train
+cbgcrtddef 1 300 train
+cbgerjhdzy 0 300 train
+cbgihaqmiw 1 300 train
+cbgoguzirl 1 300 train
+cbgryoyvkt 0 300 train
+cbgtsbwxzi 1 301 val
+cbhfjqmwes 1 288 train
+cbhfymetoq 1 241 train
+cbhqylgtxg 1 300 train
+cbhyxgmokb 1 299 val
+cbieewabwp 1 300 train
+cbipyxvxad 0 300 train
+cbiqnvszuw 1 300 train
+cbirndxuli 1 301 train
+cbivilebbl 0 300 train
+cbiwgiqwxy 0 300 val
+cbjaesxmsv 1 297 train
+cbjahwlunn 1 241 val
+cbjazcafdf 1 300 train
+cbjubgvsss 1 300 val
+cbjztcfamt 0 300 train
+cbkaohrtkz 1 300 train
+cbkojiiyes 1 300 train
+cbkpffismt 1 136 train
+cbkppzjtqf 0 300 train
+cbkqrlaiyi 1 300 train
+cbkuuhtttt 1 300 train
+cbkwcykfex 1 241 train
+cblampgkhz 1 300 train
+cblbgfevcq 1 300 train
+cblbjqelkz 1 300 train
+cblcntsvln 0 300 train
+cbldxobgrw 1 300 train
+cbllfkbaqw 1 300 train
+cblpsynptz 1 300 train
+cblquvzvyl 1 300 train
+cblrlhlyee 1 292 train
+cbltdtxglo 1 300 train
+cbltsezlmg 1 301 val
+cbmhbmwxgc 1 241 train
+cbmpoqjfxc 1 300 train
+cbnbjuhfmo 1 301 train
+cbncqbleug 1 300 train
+cbngdfjmvw 1 300 val
+cbntmghmkn 1 300 train
+cbnyssjaho 1 300 train
+cbobasgydd 0 300 train
+cbobaygolx 0 298 train
+cbodwzdvno 1 300 train
+cboefaupik 1 136 train
+cbogxxmfnd 1 301 train
+cboknvsylb 1 300 train
+cborltcwhi 1 300 train
+cbosqnfypp 1 300 train
+cboymxepfb 1 241 train
+cboztpdgxt 0 300 train
+cbpaoachhz 1 300 val
+cbpjvmtmzx 1 300 train
+cbpqvedsgn 1 249 train
+cbpxzyvtyg 1 300 train
+cbqalqxhox 1 300 train
+cbqchlkdkk 0 301 train
+cbqdpfnktj 0 300 train
+cbqfgqronr 1 301 train
+cbqgyvlyyh 1 300 train
+cbqhrrvval 1 300 val
+cbqpzcljcu 1 301 train
+cbqteothjv 1 300 train
+cbrasisybv 1 300 val
+cbrlmpovtt 1 300 train
+cbrmhrdwlj 1 300 val
+cbrsebfupa 1 300 train
+cbrsenwybp 1 302 train
+cbrtlnospy 1 300 train
+cbrvdbvnea 0 300 train
+cbsbhvlvvi 0 300 train
+cbscshksfb 1 300 train
+cbsefmnkpy 0 300 val
+cbshqltflk 1 300 val
+cbsskjhefa 1 300 train
+cbsvrcxknz 1 300 train
+cbtcwfzudb 1 300 test
+cbtfztsttf 1 300 train
+cbtgceekxe 0 300 train
+cbtisqyamt 1 300 train
+cbtjqmtrpr 1 300 train
+cbtxhyzfbh 1 300 train
+cbtzxanzcj 0 300 train
+cbueuqdcth 1 300 train
+cbukvshrzm 1 299 val
+cbulmphxfg 1 301 train
+cbvjpslxyj 0 300 val
+cbvqvlydjm 1 300 train
+cbvrnjdqwc 1 300 val
+cbvzweiuag 1 300 train
+cbwdcfclfp 0 300 train
+cbwsdexwwm 1 300 train
+cbwypxmrib 0 300 val
+cbxaeqakvz 0 300 train
+cbxatxykwx 1 300 train
+cbxbnwfjxx 1 300 train
+cbxfqpvoxs 1 299 train
+cbxlwnkrpz 1 300 train
+cbxnbbttif 1 300 train
+cbxnupmtix 1 300 train
+cbxphbzrvy 1 300 train
+cbxtulzkxr 1 300 train
+cbxvjlttcp 0 298 train
+cbxvvgybsy 1 302 val
+cbxwcgzlna 1 300 val
+cbxyzwaoal 1 300 train
+cbybbxuusl 1 300 test
+cbycmesndu 1 301 train
+cbycvmlndk 1 300 train
+cbyjikvunk 1 300 val
+cbytidzegv 1 298 train
+cbywmlmeds 1 300 train
+cbyzmqkbcl 1 300 train
+cbzdfewrhy 1 300 val
+cbzktvqkbi 1 300 val
+cbzkudiqez 1 301 train
+cbzwrelxyx 1 300 train
+cbzxmkfgle 1 300 train
+cbzxrzhjrr 1 300 train
+cbzxykepbl 1 300 test
+ccaequtltd 1 300 test
+ccafjjfqid 0 300 train
+ccaihvldle 1 301 train
+ccaiyxmdut 1 300 train
+ccakgpvupa 1 300 val
+ccbfcnkwxa 1 300 test
+ccbfmuqlkj 1 300 val
+ccbmthpups 1 300 train
+ccbnlgdfjs 1 300 train
+ccbnmrjdki 1 301 val
+ccboyxnmtw 1 301 train
+ccbsknxdyc 1 301 train
+ccbtjcyvll 1 302 train
+ccbueybaxw 1 300 val
+ccbyngtagf 1 300 val
+cccanpxgzl 1 300 train
+cccdagmmxu 1 300 train
+cccdhhehej 1 301 train
+ccceyyczpw 1 241 train
+cccfhnzslg 1 301 val
+cccjldvlys 1 300 train
+cccngsdrvy 1 300 val
+cccpckvjiw 1 297 train
+cccrkhfgou 1 300 val
+cccukmzqxt 1 300 val
+cccvfncjid 1 300 train
+cccwbhcnwe 0 300 train
+ccczyufvjn 0 300 train
+ccdaqfjqft 0 300 train
+ccdgiezfdv 1 300 train
+ccdhupjnbm 1 300 val
+ccdidtvycw 1 300 train
+ccdjtibahz 0 298 val
+ccdlnpaaki 1 300 train
+ccdnuxdctx 1 300 val
+ccdpnwqbal 1 300 train
+ccdpvedhkd 1 302 train
+ccdpvwhgkz 1 300 train
+ccdtwvjhfs 1 300 train
+ccdxkfjwdc 1 300 train
+ccdxpgcufs 1 300 train
+ccecjmxflb 1 300 val
+cceclbhgej 1 300 train
+cceknmswyn 0 300 train
+ccelupzkxk 1 300 val
+ccenahyrpb 1 300 val
+ccendejomy 0 300 train
+cceqjxezdw 1 300 train
+ccesiweode 1 300 train
+ccevbixrwu 0 300 val
+cceypzfrqp 1 301 train
+ccfbthohle 1 301 train
+ccfhogoqpm 1 300 val
+ccfldnjmul 1 241 train
+ccfloicpbc 1 300 train
+ccfnwlffqs 1 301 train
+ccfoszqabv 0 300 train
+ccftfhdfnn 1 300 train
+ccfvwveyfl 1 301 train
+ccfxxnyhxq 1 300 val
+ccfyxpgstu 1 300 train
+ccgbfmogzq 1 301 train
+ccgbzvaicj 0 300 train
+ccggjgnzws 1 300 train
+ccggqzuotg 1 300 train
+ccgiwpbnmm 1 300 train
+ccgkrhncpi 1 300 train
+ccgmeohvnu 1 300 train
+ccgmtlhdjp 1 300 train
+ccgmvconex 0 300 train
+ccgviopwhw 1 300 train
+ccgwnltpgd 1 300 val
+ccgwvqribx 1 301 train
+cchbkkgxts 0 300 train
+cchevvfwpu 1 300 val
+cchfwuzqmn 1 300 val
+cchjntpryf 1 241 train
+cchjuvkwhi 1 300 train
+cchjzlcplu 1 300 train
+cchtzaxgfv 1 300 train
+cchxcjviax 1 288 train
+cciabaezvr 1 300 train
+ccihgtfigm 1 300 train
+ccihqwushq 1 300 val
+ccipcmxaef 1 300 val
+ccirkpwvgi 1 300 train
+ccirvmdunv 1 300 train
+cciyrmayki 1 298 val
+ccjbwowrzr 1 300 train
+ccjdqupbqr 0 300 train
+ccjiwxnihq 1 300 test
+ccjlsquofg 1 300 val
+ccjorzzmdo 1 300 train
+ccjosurvwg 1 300 train
+ccjrrkbxjg 1 302 val
+ccjvbdyqoo 1 300 train
+ccjwpkwdtx 1 300 train
+cckkbjvmam 1 300 train
+ccklqblvtn 1 300 train
+cckotenyxx 1 300 train
+cckpjnllin 1 301 val
+cckzuzizjm 1 300 train
+cckzwbefwm 1 300 train
+cclfjbjsrt 1 300 train
+cclgimqbnu 0 300 val
+cclkwtadow 1 296 val
+ccllaslwfw 1 300 train
+ccltkhgugi 1 300 val
+cclusswnlb 1 300 train
+ccluxkxxsk 1 297 train
+ccmebntrrn 1 300 train
+ccmfdjqzil 1 241 train
+ccmonzqfrz 1 300 train
+ccmovtuglt 1 300 test
+ccmpbioauu 1 300 train
+ccnbdqeetl 1 300 train
+ccnmwmmoaq 1 300 train
+ccnmxgjron 1 300 train
+ccnojigtzv 1 300 train
+ccnpgajwjk 1 301 train
+ccnqawnlny 1 300 val
+ccnscxftah 1 125 train
+ccofxnqrqb 1 301 train
+ccopaenmsc 1 300 train
+ccovdguwcz 1 300 train
+ccoxmlqpdz 1 300 train
+ccpaeuelug 1 300 train
+ccpisbkrgy 1 300 train
+ccpkjeveme 1 300 val
+ccpnakarci 1 300 train
+ccpudlfmer 1 269 train
+ccpuxjxyjg 0 300 val
+ccpwkvdjir 0 301 train
+ccpwvuudgy 0 300 train
+ccpxfwqifj 0 300 train
+ccpydpqsam 1 300 train
+ccpziunxfb 0 301 train
+ccpzqqemva 1 300 train
+ccqfiwztca 1 300 train
+ccqibzllgr 1 300 val
+ccqrbbudlr 1 300 val
+ccqrqgitnf 1 300 val
+ccqspukmcr 1 300 train
+ccqvrbikis 0 300 train
+ccqzmknavj 1 241 train
+ccrfseojcq 1 302 train
+ccrgfndhem 1 300 val
+ccrrlidqnp 1 300 test
+ccrtvyylwu 1 300 train
+ccsgbkccgk 1 300 train
+ccsogyuwic 1 298 train
+ccsohxdeyz 1 300 val
+ccsphoifkq 1 301 train
+ccszmiuugn 1 300 val
+cctbuvslem 1 300 val
+ccteennqhv 1 300 train
+cctfcnzync 1 300 train
+cctlobrnxo 1 301 val
+cctpcnsfka 0 300 val
+cctrhqvein 1 299 test
+cctvrbjdhv 1 300 train
+cctwlwjkoi 1 301 val
+cctzssgnxc 1 300 train
+ccufwwpkrc 1 300 val
+ccugrsepny 1 300 train
+ccukxgjsfw 1 300 train
+ccuomzztyu 1 300 val
+ccuptgcaex 1 300 train
+ccutrujdcs 1 300 train
+ccvcpipyti 1 300 train
+ccverippkg 1 241 train
+ccvgsjbwmz 1 300 train
+ccviaegiyr 1 300 val
+ccvjotcfrf 1 302 train
+ccwabydkuh 1 300 train
+ccwcbkxwjk 1 300 train
+ccxbzqmxfv 1 300 train
+ccxlvnbljr 1 300 val
+ccxqrysmxj 1 300 train
+ccxtpaqpsc 1 302 train
+ccxtzzixyv 1 300 train
+ccxztylkhl 1 300 val
+ccyfmsxuyc 0 300 train
+ccypfmufed 1 300 train
+ccyphmrxrf 1 300 train
+ccytwlyrkk 1 300 train
+ccyykriupf 1 300 train
+ccyymgragw 1 300 train
+ccyywzfvii 0 300 train
+ccyzerjybx 1 301 train
+cczcxkrrnj 0 300 val
+cczdxtweqv 0 300 train
+cczexzhuou 1 300 train
+ccziopimrm 1 300 train
+cczirkefmi 0 250 train
+cczisiwrmd 1 300 train
+ccznkddrub 1 300 train
+cczqhzqwob 1 300 val
+cczxmsfutp 1 301 train
+cczxmvgfzr 0 300 train
+cdabwflrxr 1 300 train
+cdadymfdql 1 239 train
+cdairnevmw 1 300 val
+cdawcfbriw 1 300 val
+cdawymhaak 1 134 val
+cdaxixbosp 1 300 train
+cdbikdbkrx 1 300 train
+cdbjpehdnv 1 301 train
+cdbjreoznw 1 300 val
+cdbmqliycy 1 300 val
+cdbsbdymzd 1 300 train
+cdbxbpmcmb 1 300 train
+cdcaedaavn 1 297 train
+cdcdoqbdmi 1 300 test
+cdcklwxsim 1 301 train
+cdcqutthrw 1 300 val
+cdczfrwudb 1 300 train
+cddassmrmv 1 301 val
+cddckmwrdc 1 300 train
+cddghncyfn 1 300 train
+cddlrdnjwu 1 300 train
+cddlvnkhzo 1 298 train
+cddqkogvva 0 300 train
+cddwbrlhie 1 300 train
+cddykxfiii 1 300 train
+cdeaowkeoh 1 300 train
+cdeesuuuqz 0 300 val
+cdelzdhqpc 1 300 train
+cdenhadzhi 1 300 train
+cdfbhqgada 1 300 val
+cdffygfgcz 0 300 train
+cdfjurcrvj 1 300 train
+cdfskesera 1 300 train
+cdfusvptie 1 300 train
+cdfvyezjis 1 300 val
+cdgayaitnv 1 300 train
+cdgkvqzqhi 1 300 val
+cdgmukyuig 1 300 train
+cdgopashmv 1 300 val
+cdgrttukjn 0 300 val
+cdgsptpqet 0 300 train
+cdgtonmgap 1 299 val
+cdgulhthen 1 300 train
+cdgveexocr 0 300 val
+cdgyduwbeg 1 300 train
+cdhdwtdbpe 0 300 train
+cdhiogrmhb 0 301 train
+cdhklxmaal 1 299 val
+cdhqahmfqo 0 299 val
+cdhvtnirns 0 300 val
+cdibsjhmzb 0 300 train
+cdifwxoclh 1 300 train
+cdighgiscm 0 300 train
+cdigrftghi 1 300 val
+cdigwcjxac 1 300 train
+cdiiaflact 0 301 train
+cdiskfchsj 1 300 train
+cdiwhirjmi 1 301 train
+cdjbgjbctw 1 300 val
+cdjglvxapn 1 300 train
+cdjisxdgbq 1 300 train
+cdjpkuaovh 1 300 train
+cdjrzwitvh 1 301 train
+cdjyfrrlht 1 300 train
+cdkariruvd 1 301 val
+cdketmfmnm 0 300 val
+cdkgkspxwg 1 301 train
+cdkhhpdwic 1 300 val
+cdklbtyres 1 300 train
+cdklueukql 1 300 train
+cdkmzuoeqi 1 300 test
+cdkniwszmf 1 300 train
+cdksourjbv 1 297 train
+cdkujluuwl 1 249 train
+cdlcrcmzac 1 300 train
+cdlfiqilqq 1 300 train
+cdlusurrps 1 300 train
+cdmpemitjx 1 300 train
+cdmrdkhxyu 1 300 train
+cdmwcoqgsq 1 239 val
+cdmzcuuzce 1 300 val
+cdnhtrhbjn 1 300 val
+cdnizjybej 1 300 train
+cdnookrehk 1 300 train
+cdnzwnhxle 1 300 train
+cdocbhuhuy 1 300 train
+cdofxtzbmp 0 300 train
+cdokbrpgwr 1 300 train
+cdokbxxevk 1 300 train
+cdolzmgbod 1 300 train
+cdomdwytdp 1 300 train
+cdomjqtkuj 1 300 train
+cdopdljvgt 1 301 train
+cdosaiyoln 1 300 train
+cdotyfvxop 1 249 train
+cdoxoegwjc 0 300 train
+cdphgkcdmk 1 300 train
+cdphtzqrvp 1 300 train
+cdpndxgclc 1 300 train
+cdpnnebwfa 0 300 train
+cdpnvyypuy 0 300 train
+cdpukyvqpm 1 300 train
+cdpwyinhbm 0 300 train
+cdqepjjnai 0 301 train
+cdqeseepyo 1 300 val
+cdqizfltet 0 301 train
+cdqjqhgahi 1 300 train
+cdqprcsdsw 1 299 val
+cdrbcnpwnh 1 301 val
+cdrdflgopu 0 300 train
+cdrhefkzxo 1 300 train
+cdrktlivps 1 300 train
+cdrxdvdxwt 0 300 val
+cdrxshwham 1 300 train
+cdsefvjgtb 1 300 train
+cdslfmsvir 1 300 train
+cdspzxitmn 1 300 train
+cdsusghebc 1 300 train
+cdtakhdhdb 0 300 train
+cdtczqsfdc 1 300 train
+cdtdknvaix 1 300 train
+cdtgayygwn 0 300 train
+cdtphtnyyq 1 300 train
+cdtptxybyv 1 300 val
+cdtvurrrzb 1 300 train
+cdubvdkuby 1 300 train
+cdubynoclz 0 300 val
+cduirlfffk 1 301 train
+cduovsffmz 1 300 train
+cduswmgwku 1 300 train
+cdutdcaovc 1 300 train
+cduujihlvh 0 239 train
+cduxnbnejb 1 300 train
+cdvaxysmlw 1 300 train
+cdvjaazomt 1 300 train
+cdvlkckrxw 1 241 train
+cdvpltaglw 1 300 train
+cdvrqtfkug 1 300 train
+cdvtnptyvw 1 300 train
+cdvwcmkcdz 1 300 test
+cdwbxofixe 1 300 train
+cdwhpwvmls 1 300 train
+cdwhtpnuia 0 300 train
+cdwoinhglz 1 300 train
+cdwtzresja 1 300 val
+cdwxurdymt 1 300 train
+cdwzqgyqan 1 300 train
+cdwzuorlcs 1 300 train
+cdxktalois 1 301 val
+cdxlycxonl 1 300 val
+cdxowomrhk 0 300 train
+cdxqkqbttv 1 300 train
+cdxtgnafht 1 300 train
+cdxvsdpkio 1 300 train
+cdxwjbqwxu 1 297 train
+cdxwmzxudd 1 299 test
+cdxxenjwam 0 300 train
+cdxykuskua 1 298 train
+cdyakrxkia 1 300 train
+cdyaoprhrr 1 298 train
+cdyclvewaw 1 300 train
+cdynaiiotj 0 300 train
+cdyoiiuszk 1 301 train
+cdyotmvujc 1 300 test
+cdypvrvhpo 1 297 train
+cdyurhtvls 1 301 val
+cdyxbkszli 1 300 train
+cdyyocuphu 1 300 train
+cdzculzlad 1 300 train
+cdzindcaxu 1 300 train
+cdzjzjavcc 1 300 train
+cdzlhktatq 1 299 val
+cdzoetjdwq 1 300 val
+cdzriaborp 1 300 val
+cdzxeitqld 1 300 train
+ceadsrbcgf 1 300 val
+ceajcbpjfv 1 300 train
+ceajctiezl 1 300 train
+ceaogebsum 0 300 train
+ceatuikimd 0 300 train
+ceatybwxtm 1 300 val
+ceawlspnrl 1 298 train
+cebaebkxgf 1 300 train
+cebbgoldtx 1 300 train
+cebcmahlap 1 300 train
+cebdylhogm 1 300 train
+cebjakkosg 0 294 train
+cebpfewlbd 1 300 val
+cebrdwhvrs 0 300 train
+cebtmwttvu 1 300 train
+cebtyutbtn 1 300 train
+cecasinijm 1 298 train
+cecnbbobxn 1 300 train
+cecpaaawmc 1 300 train
+cecqflguyc 0 300 train
+cecrftrnlv 0 300 val
+cedilmtdmi 1 300 train
+cedirxbpod 1 300 train
+cedizgstid 0 300 train
+cedlqcxazg 1 300 train
+cedneyiutj 1 300 train
+cedpwjjnsc 1 300 train
+cedpyannqf 0 300 train
+cedpzscejx 1 300 train
+cedqestobv 1 300 train
+cedxarwgrw 0 300 train
+cedydlkhff 1 300 train
+ceebmgekpz 1 300 train
+ceefexwvtq 1 300 val
+ceeggdnwek 1 300 train
+ceelmfvdxi 1 83 train
+ceeodwphfb 1 300 val
+ceeutxgbzd 1 300 train
+ceevrhgzgu 1 300 val
+ceezfxqjrt 1 300 train
+cefbtqikej 0 300 train
+ceffvfqkyb 1 300 train
+cefkifmdkd 0 300 train
+cefolmrrlx 0 300 train
+cefpmcqwex 1 300 test
+cefqtwwdir 1 300 train
+cefwujawid 0 300 train
+cefxvhvuut 0 300 val
+cefzoeryat 0 300 val
+cegdayfefc 1 300 val
+ceggnrfcyg 1 298 train
+cegiemvlnt 1 300 train
+cegsvyxjif 1 300 train
+cehchwzpfe 1 300 train
+cehhbxagyt 1 300 train
+cehsieoarf 1 300 train
+cehtpjzpes 1 300 train
+cehujdhefw 1 300 train
+ceiaeqrsvl 1 300 train
+ceilrsexla 1 300 train
+ceirhouonh 1 300 train
+ceivqzvpeo 1 300 train
+ceiwazlque 0 300 train
+ceiwfjitzl 1 300 train
+cejcybcemu 1 301 train
+cejgpvadjj 1 241 train
+cejimtkdoq 0 300 train
+cejkpwcump 0 300 train
+cejyavlbey 1 300 val
+cekarydqba 0 300 test
+ceketlqsrm 1 300 train
+cekobsslkp 1 300 val
+cekuytiohq 1 300 train
+cekwtyxdoo 1 300 test
+cekxlwtceh 1 300 train
+cekyywktkj 1 300 train
+celahlsamd 1 300 train
+celecxxjjg 1 300 train
+celeqvfvik 1 300 train
+celpgkvgpb 1 300 train
+celrjxpmyu 1 300 train
+celvdajmek 1 241 train
+celyntkwbj 1 300 train
+cembklhtbh 1 300 train
+cemfqurihd 1 300 train
+cemftmsxis 1 300 test
+cemickbskt 1 300 train
+cemkckfnfn 0 300 train
+cemmbbijve 0 300 train
+cempkdywzt 1 301 val
+cemtyyxdti 1 300 train
+cendwvgnbk 0 300 train
+cenjnnpwnw 1 300 train
+cenmgmzjqp 1 301 train
+cenobxuilf 0 300 train
+cenvrovfzg 1 300 train
+ceobbmkvnp 0 300 train
+ceokdkdvgb 1 298 train
+ceonbxkjyu 1 300 train
+ceotvqfajr 1 300 train
+ceouhoqqsl 1 300 train
+ceouuotloy 1 300 val
+ceoxljnjva 1 301 val
+ceoyuhoxof 1 269 train
+ceozkcbvfe 1 300 train
+cepfmtlfli 1 300 train
+ceplrpumog 1 300 train
+cepocekyvc 1 300 train
+cepoollqua 1 300 val
+cepqcoseaj 0 299 train
+cepqgcoxuk 1 300 val
+cepsnuvlqu 1 300 val
+ceptxjrpwr 1 300 train
+cepxysienc 1 300 train
+cepysbjwjf 1 301 val
+ceqmqgzewb 1 300 train
+ceqohdbyfi 1 300 train
+ceqsvfimvc 0 300 train
+ceqvstfsou 1 300 train
+cerdtgydan 0 300 train
+cerlkkynsx 1 300 val
+cernghexve 1 300 val
+cerpjszyua 1 300 val
+cerwqpmouj 1 300 test
+cerwxjqsmv 1 300 val
+cesgmngaco 1 300 train
+cesiuumrwj 1 300 train
+cesyydepjw 0 301 train
+cetjuevdbj 1 300 train
+cetnkjijcl 1 300 train
+cettndmvzl 1 300 train
+cetvgcrlka 1 300 val
+ceufzuzydq 1 300 train
+ceugcydpgb 1 300 train
+ceuicumdmo 0 300 train
+ceuokdpayk 1 300 val
+ceuurxiiyl 1 300 val
+ceuvcoplbs 1 300 train
+cevazvkhyr 1 300 train
+cevjhyggpt 1 300 train
+cevklgckyx 1 301 train
+cevktnkdup 1 300 test
+cevontacue 1 299 val
+cevriyliqv 1 300 train
+cevrqoqrpm 1 300 val
+cewalfidka 1 300 train
+cewbjmqyic 1 300 val
+cewgpzdrsc 1 300 train
+cewhmeoiee 1 300 val
+cexamjkjcm 1 300 train
+cexlfcumbe 1 300 train
+cexmizogbp 0 300 val
+cexrhgoikd 1 300 val
+cexuvicrju 1 300 val
+cexvtilqfn 1 300 train
+cexwxxnbvw 1 300 train
+ceyddawxjd 0 300 train
+ceyewzqnup 1 300 train
+ceygiieeyf 1 300 train
+ceyissnjuv 1 299 val
+ceykhsossc 1 300 train
+ceymbecxnj 1 300 train
+ceyqgamdwu 1 300 train
+ceyrgvfoji 1 300 train
+ceytlyjqne 1 300 train
+ceytwnnhzo 1 300 train
+ceyvswmikv 1 300 train
+cezihuwtca 1 300 train
+cezmhermsf 0 298 val
+cezwuwctrd 1 300 val
+cfabkxvery 1 300 train
+cfabwrwoha 1 288 train
+cfaelcvldo 0 300 train
+cfaqberteo 1 300 train
+cfaqbobudg 0 301 train
+cfaxqoasjl 0 300 val
+cfayaairkq 0 300 train
+cfbbwgwjql 1 300 train
+cfbglnuldf 1 241 train
+cfbjoudmqt 1 301 train
+cfbzrgtbmw 1 300 train
+cfcabmkqne 0 300 train
+cfcfuagkem 1 298 train
+cfcjjaembf 1 300 val
+cfcrgdvupt 1 301 train
+cfculsebms 1 298 val
+cfdjclyayo 1 300 val
+cfdlomqjkk 1 300 train
+cfdlyhelif 1 300 train
+cfeccumoiy 1 300 train
+cfeelpwldf 1 300 train
+cfegjchptu 1 300 train
+cfepgwphfx 1 300 train
+cferslmfwh 1 300 train
+cfevopgevc 1 298 train
+cfewfbbgxj 1 300 train
+cfeykevqdx 1 299 train
+cffffbcywc 1 300 train
+cfffuoldct 1 300 train
+cffiamlmxj 1 301 train
+cffiwsldyw 0 300 train
+cffobunthq 1 300 train
+cffpcdxoyt 1 300 train
+cffxvkvmcv 0 300 train
+cffxwvvhwi 1 300 train
+cfgbdycxuu 1 300 train
+cfgcngmdjn 1 300 val
+cfgdhhqzve 1 300 train
+cfgicodjdw 1 300 train
+cfgotyucqv 0 300 train
+cfgvdxxrwb 1 300 train
+cfhejdmemu 1 300 test
+cfhoqpdzqb 1 299 train
+cfhzziagsz 1 300 train
+cfidjdctmv 1 300 train
+cfiettrfhi 1 298 train
+cfijmnlmjz 1 300 train
+cfiojavprq 1 300 train
+cfipijcfwt 1 300 train
+cfirkbroma 1 300 val
+cfisckebel 1 300 train
+cfiujbglvp 0 300 train
+cfiwfrygll 1 300 train
+cfiwjsjltu 1 300 train
+cfizxbetpa 1 300 val
+cfjfplnbrd 1 300 train
+cfjfyptzwn 1 300 train
+cfjiphqcrh 1 300 val
+cfjvctusjp 1 300 train
+cfjxolemtz 1 300 val
+cfjyyllolw 1 300 train
+cfjzltenvn 1 300 train
+cfkbnqpbpm 1 300 train
+cfkgmegmcj 1 300 train
+cfkgtvgkkp 1 300 train
+cfkjxylprk 1 300 train
+cfkkbsnihy 0 300 train
+cfkliqmphy 1 299 train
+cfkmjqcpcd 1 298 train
+cfkodaajhv 1 300 train
+cfkreeduua 1 300 train
+cfkzktbfex 1 299 train
+cflajhyjwz 1 300 train
+cflchrsucl 0 300 train
+cflkdvzmms 0 300 train
+cflkoqmenk 0 300 train
+cflpvgemyh 1 300 train
+cflsquvdoh 0 300 train
+cflwigoquj 1 300 train
+cfmapbvctw 1 300 test
+cfmgwnnyri 0 300 train
+cfmhlrtsaf 1 300 val
+cfmiliboth 1 300 train
+cfmjwmqgjd 1 300 train
+cfmnirsgxs 0 300 train
+cfmqcqhevu 1 300 train
+cfmskgcrrm 1 300 train
+cfmvycbhlt 0 300 train
+cfmxdisump 1 300 val
+cfmxhruvov 0 300 train
+cfmzfzamfj 0 300 train
+cfnbltpvbr 1 300 train
+cfnlqhqhvp 1 300 val
+cfnmdyofmf 1 300 train
+cfnzczoyfj 1 297 val
+cfogjeundg 1 300 train
+cfolpcshqw 1 300 train
+cfozboeyaq 1 300 train
+cfpblexucf 1 300 train
+cfpkbsiiqh 1 288 train
+cfpmeadviw 1 241 train
+cfpmhnphqc 1 301 train
+cfpqsnersj 1 297 val
+cfpwugwvjj 1 300 val
+cfpydwmroe 1 298 train
+cfqmnjcuwa 0 300 train
+cfqnmpqyrv 1 300 train
+cfqqubdzde 1 300 train
+cfqsorfkvn 0 300 train
+cfrdfuunan 1 300 train
+cfrfkujfnc 1 300 val
+cfryhrtbkr 1 300 train
+cfsbzeyhpl 1 299 val
+cfsdvzrckg 1 300 val
+cfsfbdykgk 1 300 train
+cfsiesdgir 1 300 train
+cfsizphblx 1 298 train
+cfskcbujka 1 300 train
+cfsyfosxzt 1 300 train
+cftaeufnmp 1 300 train
+cftcjrimex 1 300 train
+cftfpsgzil 0 300 train
+cftgswmtpj 1 300 val
+cftlnhvkjm 1 300 train
+cftnkjbpdm 1 300 val
+cftsqzumda 1 300 val
+cfuhpgulbg 1 301 train
+cfuilgjref 0 300 train
+cfujweharl 1 300 train
+cfuobgamvs 1 300 val
+cfuwvsrylm 1 300 train
+cfuygkozye 1 301 val
+cfvdlhypmw 1 298 train
+cfvdrawtgq 0 300 train
+cfvhbaeoqo 1 301 train
+cfvjbyroyb 1 301 train
+cfvufeifby 1 301 val
+cfvyxxmlxc 1 301 val
+cfwcupbujp 1 300 val
+cfwdlimdjk 1 300 train
+cfwdrwuwob 1 300 val
+cfwdxymuoi 1 300 train
+cfwjbgktyl 1 300 val
+cfwjfzjdby 1 300 val
+cfwjpthcpu 1 300 train
+cfwkaldfpp 1 300 train
+cfwkrubysq 1 300 train
+cfwnullxwk 1 300 val
+cfwrdzxogc 1 300 train
+cfwsamzybv 1 300 train
+cfwwarmizt 1 300 train
+cfwxrlwkmn 1 300 train
+cfwxvqnufi 1 300 train
+cfxdzvscqb 1 297 train
+cfxjehunde 1 300 train
+cfxkpiweqt 0 300 train
+cfxlelpedd 1 300 train
+cfxpebxswd 1 300 train
+cfxrrjyzpy 0 300 val
+cfxydeuwvv 1 300 train
+cfxypsulos 1 300 train
+cfyayetydv 1 300 test
+cfybijtodh 1 241 train
+cfybmuezmr 1 300 train
+cfybxlixvs 1 300 train
+cfycdpkjrt 1 300 val
+cfyduhpbps 1 300 train
+cfygpieygr 0 300 train
+cfzfhvyrsr 1 300 train
+cfzlvcaqpx 1 300 val
+cfzmudiwif 1 300 train
+cfzqbcxlrb 1 300 train
+cfzvxoblqa 1 300 train
+cgabkxobjh 0 300 train
+cgabuugavo 1 300 val
+cgacynuzzc 0 300 train
+cgahwkstnv 1 298 train
+cgakuqkotg 1 300 train
+cgaoujuasi 1 300 train
+cgauqjrqrb 0 300 train
+cgawstgxms 1 301 train
+cgbcoyyuhn 1 300 train
+cgbfmokzmf 1 300 train
+cgbjqkpxvc 0 300 val
+cgbjtfbljp 1 300 train
+cgblcaialw 1 300 val
+cgblwwmgbt 1 298 train
+cgbmnbeazo 1 299 val
+cgbykzkgdg 1 300 train
+cgcbgrlwes 1 300 train
+cgcdmklkqs 1 300 train
+cgcfrcephg 1 299 val
+cgcmdddbch 1 300 train
+cgctbyuvrj 1 300 train
+cgdixdaaql 1 296 val
+cgdjovwtdt 1 300 train
+cgdkmiumuz 1 300 train
+cgdpimxyqd 1 300 train
+cgdrbrnhma 1 300 train
+cgdrflfmom 1 300 train
+cgdrgdldtn 1 300 train
+cgdsaxqmvo 1 300 val
+cgdsxnytwc 0 300 train
+cgebtadovo 1 300 train
+cgecltlpyr 1 301 train
+cgefriykjw 0 300 train
+cgejubwayd 1 300 train
+cgeotrsgsf 1 300 train
+cgeppykufl 1 300 train
+cgeqvmziil 1 288 train
+cgetledlxm 1 300 train
+cgexfmjnpg 1 300 train
+cgexssnjrq 0 300 train
+cgezcspxjq 1 300 train
+cgfcquqwvt 1 300 train
+cgfedkyktr 1 300 train
+cgffujtzjr 1 300 train
+cggasyxlxc 1 301 val
+cggcwvrkui 1 300 val
+cggdptapsj 0 300 train
+cgggxqptwu 1 240 train
+cggngboudt 1 300 val
+cggytekpwz 1 300 train
+cggzjocxdk 0 300 train
+cgheccdlif 0 300 train
+cghklgzlau 1 300 train
+cghmcisqjh 0 300 train
+cgifdoaosl 1 300 train
+cgigqncgru 1 300 test
+cgiptmhzdu 0 300 train
+cgirwxsied 1 300 train
+cgivjahnel 1 300 train
+cgjemtnfvh 0 300 train
+cgjerdrzst 1 300 val
+cgjgaddbbw 1 300 test
+cgjmjdenqi 0 300 train
+cgjqegcfvz 1 300 train
+cgjrchabmn 1 300 train
+cgkdygkheu 1 300 train
+cgkkwecgjq 1 300 train
+cgknbbrsta 1 236 train
+cgkorxrqlv 1 300 test
+cgksdoyyxv 1 300 train
+cgkuwkbpsx 1 301 train
+cgkxdyvdhx 1 241 train
+cgkxuecqhl 1 300 train
+cglbqmhgwp 0 300 train
+cglkmwjxda 1 300 train
+cgllfnjsyn 1 300 val
+cglmqqcxvf 1 298 train
+cglpyitrzw 1 300 train
+cglpzcmgeo 0 300 train
+cglveitybx 1 299 test
+cglvjkplnc 1 300 train
+cglxirfaey 1 300 train
+cglzoiprgl 1 300 train
+cgmcrovuwg 0 300 train
+cgmrbwbsmr 1 300 train
+cgmyiexmbk 1 300 train
+cgmzwxzaly 1 297 train
+cgnerxknwl 1 241 train
+cgngubpkgn 0 300 train
+cgnhytdbnt 1 300 test
+cgntouozbs 1 300 train
+cgntrolwgj 1 300 train
+cgoetwkxmc 1 300 train
+cgoidghttq 1 300 val
+cgomfzqjeu 1 300 train
+cgoqhidgvq 0 300 train
+cgoswbxvtr 1 300 train
+cgoymvzolm 1 300 train
+cgpeqihkht 1 300 val
+cgpffvhusn 1 300 train
+cgpkeptxex 1 300 train
+cgpoltonnr 1 300 train
+cgpzyljbod 1 300 train
+cgqdlttkop 1 300 val
+cgqkyamfzl 1 300 test
+cgqmayqnhz 0 300 train
+cgqnxavvus 1 300 train
+cgqolgmapv 0 300 train
+cgqwecutyn 1 300 train
+cgrgytpdjg 1 300 train
+cgrpueglup 1 241 train
+cgrqqpzjzd 1 300 train
+cgsfbxlndd 1 300 train
+cgshwqygpt 1 300 train
+cgsoqafcfn 0 300 train
+cgsqfmhssz 1 300 val
+cgswtobqsw 1 300 train
+cgsytxotwz 0 300 train
+cgszoidfbf 1 302 train
+cgtazaiapf 1 301 train
+cgtfmnnfrw 1 300 val
+cgtijpxnsr 1 297 train
+cgtlxussed 0 300 train
+cgttnbybei 1 300 train
+cgttzpagqf 1 300 train
+cguelfepci 1 300 train
+cguelxskll 1 300 train
+cgugkrbayf 1 300 train
+cgugynfdtp 1 300 val
+cgumdsscsh 1 300 train
+cguokithze 1 297 val
+cguosbcyvw 1 300 train
+cguqnbnfut 0 300 train
+cguqyteyvf 1 300 train
+cguutwjisr 1 300 train
+cguwnxrdgl 1 300 train
+cgvbczvvuu 1 300 train
+cgvcgyvgsl 1 300 val
+cgvchfgrdl 1 300 train
+cgvdhhwhyz 1 300 train
+cgvdjymlig 1 300 train
+cgvffsrefc 0 300 train
+cgvgfncfzs 1 300 train
+cgvherbgnc 1 300 train
+cgvnxghqbl 1 300 train
+cgvpzbdvlh 0 300 val
+cgvraedjau 1 300 train
+cgvrgibpfo 1 300 train
+cgvriuepvn 1 300 train
+cgvvzebxfr 1 300 train
+cgvwhhfpha 1 300 train
+cgvxnadtdm 1 300 val
+cgwdrfwtyz 1 301 train
+cgwobrroyy 1 300 train
+cgwpvvdxak 1 301 train
+cgwvqrdikf 1 300 val
+cgwwzjscib 1 300 train
+cgxbvngoek 1 300 train
+cgxdlfptsa 1 300 train
+cgxgswovuv 1 301 val
+cgxmbsazyu 0 300 train
+cgxpjplcke 1 300 train
+cgxruwoaqc 1 300 train
+cgxskyzsqr 0 300 train
+cgxsxdllit 1 300 train
+cgxvgsgzco 0 300 train
+cgxyezxteb 1 300 train
+cgybdmhuhr 1 300 train
+cgybelhqkk 1 300 train
+cgybkddawq 1 300 val
+cgyficbwoe 1 300 val
+cgyfrcpcqi 1 300 val
+cgyfydvyyx 1 300 val
+cgygktvkyp 1 300 train
+cgyglkqfut 1 300 train
+cgymikrafx 1 300 train
+cgyxvcrjwh 1 300 train
+cgzacljiaw 1 300 val
+cgzbyaeizg 1 300 train
+cgzehrnpvv 1 299 val
+cgzffezhdl 1 298 train
+cgzlzfmhlf 1 300 val
+cgzmrsixqq 1 301 train
+cgzrfjjorz 0 300 val
+cgzwteqzur 1 300 train
+cgzxxjamqy 1 300 train
+cgzypqyewg 1 299 train
+chaintznsk 1 301 train
+chajgyysle 1 300 train
+charqggrmj 1 300 train
+chawydbolv 1 240 train
+chayhcvqtm 1 300 train
+chayotcuqs 1 300 val
+chbblgaxes 1 300 train
+chbjetguwl 1 300 train
+chbmstljzm 1 300 train
+chbnpgnnzu 1 241 train
+chboxkquas 1 300 val
+chbzgddmss 0 300 train
+chcdlbscoh 1 296 train
+chcyiyddnp 1 300 train
+chdawmzbci 1 300 val
+chdbbbghqw 1 300 val
+chdblklxdv 1 300 val
+chdbnyxful 0 300 train
+chdbpzgrpy 0 300 train
+chdjlglrkb 1 300 train
+chdqmrhqhp 1 292 train
+chdvhlhaiq 1 300 train
+chdwmbuyle 1 300 train
+chdzgklkye 1 300 val
+cheduihlur 1 300 val
+chefoakwbw 1 301 val
+chehvhrqyg 1 300 val
+chemgftzds 1 301 train
+chfeodetsk 1 300 val
+chfkrpvgnz 0 300 val
+chfnibwist 1 300 train
+chfonbvkxq 1 300 train
+chfoqmydit 1 300 train
+chfuqvtudi 1 300 train
+chfwdnscpg 1 300 train
+chgdwwwgrq 1 300 train
+chgitbsnso 0 300 train
+chgkcdtkhw 0 300 train
+chgqmwtbyf 1 300 train
+chgrtvydwz 1 301 train
+chgsduqlxy 0 300 train
+chguivtcfs 1 300 train
+chgxpfjkpv 1 300 train
+chhcmabekn 1 300 train
+chhdhwehot 1 300 val
+chhfxazpav 1 300 train
+chhjdmutms 1 300 test
+chhokpsxpp 1 299 val
+chhosgdqat 1 300 train
+chhqtdxurz 0 300 val
+chhzoxcvhl 1 300 val
+chibbtchnd 0 300 val
+chiglwzltk 1 300 train
+chihfjebdp 1 300 test
+chiklcbxdv 1 300 train
+chincnahom 1 300 train
+chinjpmavc 1 298 train
+chipvomngq 0 301 train
+chiqwpdyus 1 301 val
+chiyetcxfu 1 300 val
+chjatzdqcl 0 300 train
+chjdlrpstf 1 298 train
+chjhbsexls 0 301 train
+chjihagstc 1 300 train
+chjlruvglf 1 300 val
+chjpflakmt 1 300 train
+chkinrmflh 1 300 train
+chkknbagbw 1 300 val
+chkwjaamct 1 300 train
+chkwkxujis 1 239 val
+chkyctpgjr 1 300 val
+chlambrojg 0 300 train
+chlamzmwaq 1 300 train
+chllblqjmf 0 300 train
+chlpysdlgh 1 301 train
+chlrkevtxa 1 300 train
+chlshvbday 1 300 train
+chluvlflyi 1 300 train
+chmcianbdf 1 300 train
+chmczktwtj 1 301 val
+chmfvuliah 1 298 val
+chmgkgvsyp 1 300 val
+chmhthssjg 1 301 val
+chmjkdgtyx 1 300 train
+chmoaszycy 1 298 train
+chmomgbvyf 1 300 train
+chmpderfqz 0 300 train
+chmspsrlhf 1 300 train
+chmuqybxeh 0 300 train
+chmwoofpir 1 300 train
+chmzenrmrr 1 300 train
+chnbexdyhq 0 300 val
+chnejmuaqs 1 300 train
+chnhlsjyxb 1 300 train
+chnkxknmbq 1 300 train
+chnlzyfsrd 1 298 train
+chodspgwep 1 300 train
+choeiyioig 0 300 val
+choesqfxfo 1 241 train
+chohzofpsz 0 300 train
+chombbeegs 1 300 val
+choosfntwb 1 300 train
+choscqlfdf 0 300 train
+chowsoaunb 1 300 train
+chpbcakjbs 1 300 train
+chpclaevzg 1 298 train
+chpcotzlpx 1 300 train
+chpfpccdas 1 240 train
+chpmfdtdtr 1 300 train
+chppuauksa 0 300 train
+chpqftmhpr 0 301 train
+chprhivkyt 1 300 train
+chpthcjkev 1 300 train
+chptpypuzz 1 300 val
+chqfxmkwdq 1 300 val
+chqgstqgyz 1 301 train
+chqleyudul 1 300 train
+chqosjqjus 0 300 train
+chqqxfuuzi 0 300 train
+chqzqmzwcc 1 300 train
+chraacdwpc 1 301 train
+chrcjzpnwj 1 300 val
+chrdqhtiuy 1 299 val
+chrdwywujo 1 300 train
+chrfkvqkmg 1 301 val
+chrlezqnqx 1 300 train
+chrofcxwnx 1 300 val
+chrzfcjtaw 1 300 train
+chsaunaybu 1 300 train
+chsnltvoyi 1 298 train
+chssdjrbvf 1 300 train
+chsyitbssl 1 167 train
+chtapglbcj 0 300 train
+chtgkrlbek 1 300 train
+chtkbsvigk 1 300 train
+chtkeceelk 0 300 train
+chtslmxyax 1 301 train
+chtwxyxhzs 1 300 val
+chtznynuhs 1 300 val
+chtzzfgfmd 1 298 train
+chucelrrkq 1 301 train
+chudhiiygb 0 300 train
+chueohkgtn 0 300 train
+chuiqnmuwo 1 300 train
+chujiurbqs 1 300 train
+chukujgyvi 0 300 train
+chupatlkxc 1 300 train
+chupyqxggc 1 300 train
+chuqdswyhh 1 300 train
+chuqenxwqf 1 300 val
+chvbgfwkdf 1 300 train
+chvdngtuyf 1 300 val
+chveuigxsx 1 300 train
+chvexqsjua 1 300 val
+chvgivvrka 1 300 train
+chviwxsfhg 0 300 train
+chvkyinkpv 1 300 train
+chvqemtirf 1 300 train
+chvrpqgrqk 1 300 train
+chvwneqdcy 1 300 train
+chwfrnpqbp 1 241 train
+chwmwqiisa 1 300 train
+chwoehjcpv 0 297 train
+chwqafjhkr 0 300 train
+chwsmwoswx 1 300 train
+chwyohkzjl 1 300 train
+chxbbhvgjh 1 301 train
+chxgwiaujv 1 300 val
+chxrkprguh 1 300 train
+chxwkxbseo 1 300 val
+chxystuxux 1 300 train
+chyajgtevi 1 241 train
+chyfmhbvbi 0 300 train
+chygufblpo 1 300 train
+chynrgunat 1 300 train
+chyravncdv 1 300 train
+chyrhcdqdq 1 300 train
+chywubxsch 1 300 val
+chyxqupfqy 1 300 train
+chyxwpspjr 1 241 train
+chyzdgxfyy 1 300 train
+chzbutmizx 0 301 train
+chzieimrwu 1 298 train
+chzpclvkvg 1 300 train
+chzqptmqxv 1 300 test
+chztitsylg 0 300 train
+chzxlddmjo 1 300 val
+ciacypsucq 1 300 train
+ciafebevxq 1 300 train
+ciaigyqhyn 1 300 train
+ciajjlkqpo 0 300 train
+ciapioravh 1 240 train
+ciarewcddo 0 300 train
+ciausjbpff 1 300 val
+ciaxcxtxix 1 299 test
+cibafsjemx 1 300 train
+cibbapmuqu 1 300 train
+cibbxdajot 0 300 val
+cibcukuvsm 0 300 train
+cibhriqswz 1 300 train
+cibkroqtxz 1 300 val
+cibunztqcw 1 300 train
+cibyknwzog 0 302 train
+cicffpiskp 0 300 train
+cicgeotuuw 1 301 train
+cicrewulkf 1 300 train
+cicsmbwjqk 0 300 train
+cidafzafml 0 300 train
+cidhdrfcbe 1 300 train
+cidljzeutw 1 300 train
+cidnakbkjh 1 301 val
+cidsyadfjq 1 298 train
+cidujokplp 1 300 train
+cidwtqwsph 1 298 train
+cidzkctwby 1 241 train
+cieecwrewu 0 300 train
+ciefijkrbm 1 300 val
+ciefyjrzjv 0 300 val
+cieilnowsw 1 269 train
+cielkjozhs 1 298 val
+ciepqxjamz 1 300 train
+ciewuhazfw 1 300 train
+cifgpytmgs 1 302 train
+cifhvelrvx 1 300 train
+ciflxrbqrz 1 300 train
+cifmpumyyf 1 300 train
+cifnvcwbpt 1 300 train
+cifsgbnvrx 0 300 val
+cifshfsxfi 0 300 train
+cifvbemfhi 1 300 train
+cifzyndxio 1 300 train
+cigchlqmkp 1 300 train
+cigeitrnlc 1 300 train
+cigihfwjrv 1 300 train
+cigpagtbpw 0 300 train
+cigrglaemt 0 300 train
+cigurttoax 1 301 train
+cigvtuehdm 1 300 train
+cigxlofbkn 1 300 train
+cihbvwgicn 1 300 train
+cihmqcnoxg 1 300 val
+cihngsoxwh 1 300 val
+cihqsivbtq 1 300 train
+cihsavnyej 1 300 train
+cihurvzgbh 1 300 train
+ciigqisggi 0 300 train
+ciijjqsrto 0 300 train
+ciinpuraxg 1 300 val
+ciirikadrb 1 300 train
+ciiwkaloqz 1 300 val
+ciiysyltft 1 301 train
+cijqgyeubp 1 300 train
+cikdwogtyh 1 300 train
+cikfwkiwfl 1 300 train
+cikgroaccw 0 300 train
+cikhubpqxy 1 300 train
+cikibrhzja 0 300 train
+cikqezajwn 1 299 val
+cikuqkpxhu 1 300 val
+cikxqgxbuw 1 300 train
+cikzzjbxzy 0 300 train
+cilicvyqlx 1 300 train
+cilkzhgiew 0 300 train
+cilnawgeah 1 300 train
+cilnlmkzqz 1 300 val
+ciloryludb 1 299 train
+cilqmlflfn 0 300 train
+ciluwvyjbk 1 300 train
+cilvojejoo 1 299 val
+cimfjgnans 1 300 train
+cimhlmxioy 1 300 train
+ciminikxsj 1 300 train
+cimlotvwxy 1 300 train
+cimmfsbkyt 1 300 train
+cimmouewvu 1 302 val
+cimqxfwyjd 1 300 val
+cimrydhtlj 1 300 train
+cinapniybz 1 300 train
+cingpunobd 1 301 train
+cingrlrgov 1 300 val
+ciniwjlhit 1 300 train
+cinjqeodep 1 300 val
+cinkoaquto 1 300 train
+cinldhtdjg 1 301 val
+cinqetiide 1 298 train
+cinrseylyp 1 300 train
+cintoxpsgf 1 300 train
+cinygkllvv 1 300 train
+cinzgdxdlb 1 300 train
+cinzmdxhvb 1 301 train
+ciofvmjkdw 1 300 val
+cioizeilvz 1 241 train
+cioqvqngku 0 300 val
+cipapjvezp 1 300 train
+cipbjqtdfa 1 300 train
+ciphtizqbs 1 300 train
+cipjezpcti 1 300 train
+cipoosirjn 1 300 val
+cipouvzzmf 1 300 train
+ciqabmwajp 0 300 train
+ciqbxmvphz 1 300 train
+ciqgwitsga 0 300 val
+ciqrfryzfr 1 300 val
+ciqrvmazdq 1 300 train
+ciqtrvvokw 1 300 train
+ciqufkablq 1 300 train
+ciqvtdnkbm 1 300 train
+ciqvyagagj 1 300 train
+cirdjnapnt 1 298 train
+cirfufkjuz 1 302 train
+cirylhflqm 1 300 train
+cisanwqtaq 1 300 train
+cisatzdpcs 0 300 train
+cisfilzzrp 1 300 val
+cishdivhvc 1 300 train
+cisjhhdtuh 1 300 train
+cismesuomc 1 300 train
+cisrxltwyh 0 300 val
+cisyhndlli 1 300 train
+citbozlhxs 1 300 train
+cithuwasbk 1 300 val
+citihgzfkw 1 300 train
+citkfepusj 0 300 train
+citmuhlmzw 1 300 val
+citnmpozjl 1 300 test
+citotkokpc 1 300 train
+citpcmlvpy 1 298 train
+citzcbhlbk 1 300 train
+ciufbwnbko 1 300 train
+ciukdmedgg 1 301 val
+ciuleprkzd 1 288 train
+ciuwvrkjpy 1 300 train
+civfnvmgog 1 300 train
+civfqrceau 0 300 train
+civhhqpvio 0 300 train
+civhmvnyzk 1 300 train
+civwwkhjkh 0 300 train
+civzmohmef 1 241 train
+ciwilqlkxj 1 249 train
+ciwjicrvua 1 300 train
+ciwrhnigzx 1 300 train
+ciwubuzgxw 1 300 train
+ciwzwmlyxz 1 300 train
+cixdftcnrs 0 300 train
+cixfcdtjav 1 300 train
+cixobvpgwk 1 300 train
+cixshbsmix 1 300 val
+cixsixnfgv 1 300 train
+cixsuhxaot 1 300 train
+cixupjraoc 1 299 test
+ciyefcfzvu 1 300 val
+ciyoudyhly 0 300 train
+ciypszaqje 1 300 train
+ciyqhbpbry 0 300 train
+ciytftuwfp 1 299 val
+ciyuzmbqho 1 300 val
+ciyvpljyvt 0 300 val
+cizaubppze 1 300 val
+cizbjdhppw 1 300 train
+cizkoevvax 1 300 train
+cizlkenljw 0 300 train
+cizlladvwf 1 300 train
+cizxmeztny 1 300 train
+cjadoedyhk 1 300 train
+cjaiskhrsh 0 300 train
+cjaqstlzkb 1 300 val
+cjaukgjtpf 1 301 train
+cjaulsvavp 1 300 train
+cjazrigwbq 1 300 train
+cjbcbkhtni 1 300 train
+cjbcfmrlnr 1 301 val
+cjbejshqep 1 300 train
+cjbktshabd 0 300 train
+cjbmmgsrpn 1 299 val
+cjbpdztczy 1 300 train
+cjbsfxtjfm 1 300 train
+cjbvcmycmn 1 300 train
+cjchrkgftq 1 300 val
+cjcneqgjba 1 300 train
+cjdiezyedv 1 300 train
+cjdlmicngi 0 300 train
+cjdxubpzdc 1 301 val
+cjepbmtrkm 1 300 train
+cjetyhnwpr 1 300 train
+cjewhpksgj 0 300 train
+cjfcqpeycp 1 296 val
+cjfevmgvkn 1 300 train
+cjfnkuulch 1 300 train
+cjfwxrtjdc 1 299 val
+cjfxvoqehy 1 300 train
+cjgdqgwdzs 1 301 train
+cjgiebpjph 1 300 train
+cjgktnbbyw 0 300 train
+cjgmkgfhnr 1 300 train
+cjgmkstamu 0 300 train
+cjgnahdeaq 1 298 train
+cjgozeokwu 1 300 train
+cjgtljowod 1 301 val
+cjguwyhjnd 1 300 val
+cjhagibtap 0 300 train
+cjhfhvibgw 1 301 train
+cjhflcxdas 1 300 train
+cjhudarkzv 1 300 train
+cjhwsuzeuz 1 300 test
+cjhxvbbxsq 1 301 train
+cjiefktauf 0 300 train
+cjifazyuei 1 300 train
+cjimwughot 1 300 val
+cjiorwurwj 1 296 train
+cjiqewimqq 1 301 train
+cjiwsviedd 0 300 train
+cjiwxfwcit 0 300 train
+cjjboszaln 0 299 train
+cjjbxpnyja 0 300 train
+cjjfcqwmoe 1 300 train
+cjjjchakav 1 301 val
+cjjkfuqaee 1 300 train
+cjjqfcnmlr 1 298 val
+cjkctgykua 1 239 train
+cjkctqqakb 1 300 test
+cjksrgccue 1 300 train
+cjkttgcyxr 1 300 train
+cjlcuujmqy 1 298 train
+cjldjpzxzb 1 300 train
+cjldpugnxb 1 300 train
+cjleqqezkb 1 300 val
+cjljrdwijq 1 300 train
+cjluxhjvcb 1 300 train
+cjlvqedqee 1 300 val
+cjlwdftbbi 1 300 val
+cjlzscornn 1 300 train
+cjmfuasyog 1 300 train
+cjmgsjuivb 0 300 train
+cjmihebpcf 1 300 val
+cjmkgrsply 1 300 train
+cjmrxryakv 1 300 train
+cjmzyaylfj 1 300 train
+cjnbqelczp 1 301 train
+cjndatpdcy 1 300 val
+cjndhcclqi 1 300 test
+cjnfiihawm 1 300 train
+cjnhvphsxx 1 300 train
+cjnvjglffp 1 300 train
+cjnvqfxigi 1 300 train
+cjogxmrksh 1 300 train
+cjoonkoypi 1 300 val
+cjorckqkcn 1 300 train
+cjoszlysnr 1 300 train
+cjoxtbrenc 1 300 train
+cjoykobwyh 1 300 test
+cjoysehjtm 1 300 train
+cjpdbowxbt 1 300 train
+cjpfsoagsm 1 300 train
+cjpjfnxqbv 1 300 train
+cjpjjjnsgz 1 300 train
+cjpmietvsx 1 301 train
+cjptajsjfh 1 300 val
+cjpxmdbpqg 1 300 train
+cjqapwcpnt 1 300 train
+cjqflkvlzi 1 300 train
+cjqjmelvvr 1 300 train
+cjqqchxchr 1 300 val
+cjqtqrceib 1 300 train
+cjqtwktjff 1 297 train
+cjqvoprhav 0 300 train
+cjqyfqrjqa 1 300 train
+cjrabgzvsh 1 300 train
+cjrcsxqacy 0 300 train
+cjrgcavfsr 1 300 train
+cjricjqzwh 1 300 train
+cjrlzvsljn 1 300 train
+cjrmmjonai 1 300 train
+cjrtufpftt 1 300 train
+cjrvjuofvu 1 300 train
+cjrxquwhtp 1 300 train
+cjrzklaqjt 1 300 val
+cjsfppvdok 1 301 train
+cjsopoykvh 1 147 train
+cjstktscwm 0 300 train
+cjstqmiyud 1 300 train
+cjswfcckwt 1 300 train
+cjszxarsni 1 240 val
+cjszyxkpjo 1 299 val
+cjtdvfiwui 1 300 train
+cjtgnshdpj 1 300 train
+cjtnjjfqhx 1 300 train
+cjtonigzdf 0 300 val
+cjtxaowmed 1 300 val
+cjufmdfmtt 1 301 val
+cjuixvhexh 1 300 train
+cjuqcwkxkz 1 300 train
+cjuxuxwrqs 1 300 val
+cjuyjjiizm 1 300 train
+cjvauezybx 0 300 train
+cjvawexidx 1 300 train
+cjvhlubajs 1 301 train
+cjvtjwtkwh 1 300 train
+cjwbrvxbgb 1 300 val
+cjweempvsx 0 300 val
+cjwlhfibcr 1 300 val
+cjwpszyzar 1 300 train
+cjwyfughav 0 300 train
+cjwzotwnnx 1 300 val
+cjxbcxpbqi 1 300 test
+cjxcvdiaxj 1 300 train
+cjxqxerjer 1 300 train
+cjxshjppnd 1 300 train
+cjxsykqkji 1 300 train
+cjxxaawstb 1 300 train
+cjxypalpdm 0 300 train
+cjyfixhxir 1 300 train
+cjygiefuis 0 300 val
+cjyjbineij 0 301 train
+cjykugiciu 1 299 val
+cjyojxmrox 1 300 train
+cjyqqdurec 0 300 train
+cjzaphxcwi 1 300 train
+cjzarnrphr 1 299 train
+cjzfkfvfwv 1 300 train
+cjzqilwtnu 1 241 train
+ckadtcipgr 0 299 train
+ckagxkhshh 1 298 val
+ckajsauqkc 1 300 train
+ckalxlnkde 1 300 val
+ckanpcmjlp 1 300 train
+ckbdjpflsu 0 269 train
+ckbdwedgmc 1 300 train
+ckbgzsboxk 1 300 train
+ckbhtdwogw 1 300 train
+ckbiaaxzgq 1 300 train
+ckbjmzxwtn 1 240 train
+ckcfglcegb 1 300 train
+ckckwmbraq 1 300 train
+ckcpehympi 1 300 train
+ckcryklgzw 1 300 train
+ckcsmgxnbr 1 300 train
+ckdamfrafe 0 300 train
+ckddyprqjv 1 300 val
+ckdgxkevmq 1 300 train
+ckdzicuiio 1 241 val
+ckeaqpvbig 0 300 val
+ckechbyzit 1 300 train
+ckecqbcsun 1 300 train
+ckedkayawm 1 300 train
+ckemvkadqt 1 301 train
+ckerqaywsw 1 300 val
+ckesjfigst 0 298 train
+ckeuvnxric 1 299 test
+ckevvlpdug 1 300 train
+ckewjamoaq 1 300 train
+ckfebhnfoz 1 300 train
+ckfiljcejo 1 300 val
+ckfiodyxbq 1 299 train
+ckfmwmksam 1 300 train
+ckfmzqeesw 1 300 train
+ckfqqhpbph 1 300 test
+ckgabgjnca 0 300 train
+ckgephtoiw 1 298 val
+ckghblozpf 1 300 train
+ckgkmmgevx 1 300 train
+ckgpztnbvc 1 300 test
+ckgrpklzyd 0 300 train
+ckgsjlswpm 1 302 train
+ckgtfnhxaw 1 300 train
+ckgujmerme 1 300 val
+ckhiqguxzt 1 300 train
+ckhjteceto 1 300 train
+ckhqbkkswv 1 300 train
+ckhsoxhlzf 1 300 train
+ckibeahxva 1 300 train
+ckibjfxqmc 1 300 train
+ckifejvobq 1 300 train
+ckiovbrsdf 1 300 train
+ckizqymonj 1 298 train
+ckjaibzfxa 0 300 train
+ckjbatzrki 1 300 train
+ckjctlogrm 1 300 train
+ckjhxoovci 1 300 train
+ckjpnsrkue 1 300 train
+ckjrknofko 1 300 train
+ckjwlieplo 1 300 train
+ckkcbibrkd 1 300 train
+ckkcdaqwkh 1 298 train
+ckkfdwiuts 1 300 val
+ckkfgrkhhk 1 298 train
+ckkhekfajw 1 300 val
+ckkkrkbowi 1 300 train
+ckkoubxkhs 1 300 train
+ckkuyewywx 0 300 train
+ckkyjknfqa 1 300 train
+cklixvdsso 0 300 train
+ckljphoora 1 300 train
+cklnijebia 1 300 train
+ckluehuzkr 1 300 val
+cklzmflbbg 1 300 train
+ckmahvimru 1 300 train
+ckmfrpsefq 1 300 train
+ckmhekxnxl 1 300 val
+ckmjeilxpy 1 300 train
+ckmjyotvce 1 300 val
+ckmqcjdxjz 1 301 val
+ckmutjwucm 1 300 train
+ckmzjikxyh 1 300 train
+cknndxlewf 1 300 train
+cknnsatjfq 1 301 train
+cknqoxgbru 1 300 train
+cknrrsbgai 1 300 train
+cknsqnkrgl 1 300 train
+cknyxaqouy 1 300 train
+ckogtjkhzt 1 300 val
+ckohvkyxwn 1 300 train
+ckojmkevtr 1 300 train
+ckokvqjebx 1 300 val
+ckoletpkpg 0 241 train
+ckolojkyqz 1 300 val
+ckosdlezzl 1 300 train
+ckouqolnll 1 300 val
+ckoutmnbqu 0 300 train
+ckoznaxcps 1 298 train
+ckpbllwlnj 1 298 val
+ckphdgvojq 1 300 val
+ckpicwimrk 1 300 train
+ckpkmybeox 1 300 train
+ckplnalgsx 1 300 val
+ckpqmqcbms 1 300 val
+ckprfomigj 1 300 train
+ckpugedtun 1 300 train
+ckpzdejlzb 1 300 train
+ckqfqernbf 0 300 val
+ckqhkgtmyz 1 300 val
+ckqkyikoru 1 300 train
+ckqllubykn 0 300 train
+ckqpzpsnku 1 300 train
+ckqyovvugg 1 300 val
+ckracakohx 1 255 train
+ckradivqua 0 240 train
+ckrafhjqpz 0 297 val
+ckreyvmlgz 1 300 train
+ckrivkqvra 1 300 train
+ckronlxbzr 1 300 train
+ckroyyhczi 0 300 train
+ckrylxwhzi 1 300 val
+ckryufxbja 1 300 train
+cksanfsjhc 1 300 train
+cksfcfaegh 1 300 train
+cksjhegwyq 1 300 train
+ckskyotfdx 1 300 test
+ckslhjdcdj 1 299 val
+cksxlgdxuh 1 300 train
+cktdrtexub 1 300 train
+cktffqfrwn 1 301 train
+ckthxgccxn 1 300 train
+cktinnxtdq 1 300 train
+cktnvixgub 1 300 train
+cktraanpyu 1 300 train
+cktsyobheu 1 300 train
+cktulounod 1 300 test
+cktxxlcnom 1 300 train
+ckubrpacib 1 300 train
+ckufxtrfvd 1 301 train
+ckuklkwpkk 1 300 train
+ckumbevdrg 1 300 val
+ckuqkzmkyd 1 301 train
+ckutryryek 1 296 train
+ckuvjbzeja 1 241 train
+ckuyocuenw 1 300 train
+ckvdzozaer 1 300 val
+ckvouwzjwb 1 300 train
+ckvpbtltck 1 300 val
+ckvvxwulvk 1 300 train
+ckwdmymgfn 1 299 test
+ckwezmqqou 0 300 val
+ckwjydkaqg 1 300 train
+ckwojtcrvl 1 301 val
+ckwteckxaq 1 300 train
+ckwtyczdct 1 300 train
+ckxdllxivn 1 300 train
+ckxeznxxop 1 300 train
+ckxfnwnamq 0 300 val
+ckxnddjutf 1 300 train
+ckxqlsmryi 1 300 train
+ckxqxlsfeb 1 300 train
+ckxxsiljkr 0 300 train
+ckxxswspou 1 241 train
+ckydirciav 1 300 train
+ckydqwehyb 1 300 train
+ckyjqneema 1 299 val
+ckykucmaki 1 300 val
+ckyrztbaes 1 300 val
+ckytrhkaov 1 300 val
+ckyxpaqyac 1 300 train
+ckzbebnkfe 0 300 train
+ckzqxbvyqc 1 298 train
+ckzxmjrjvi 1 300 train
+ckzxryfjqo 1 300 train
+ckzxyuvowt 1 301 val
+claefujajm 1 300 train
+clalhtjkxe 1 300 train
+claloechcd 1 300 train
+clapgiqixn 1 301 train
+claqxlmjzz 1 299 train
+clawfcpnop 1 300 val
+clbjxuzftc 1 300 val
+clboiievyv 1 300 train
+clbppmwlbt 1 300 train
+clbtzyujqq 1 300 train
+clbvlczmey 1 301 train
+clbvotyixd 1 300 train
+clbwrjvpvk 1 300 train
+clbwuespnm 1 300 train
+clbyiyqits 0 300 val
+clbzbwytku 1 300 train
+clcajbnclq 1 300 train
+clccdvmmlv 1 302 train
+clcdbvvcrw 1 299 val
+clcgxszbnc 1 300 val
+clcjjbtmnm 0 298 train
+clcoudnsew 1 301 train
+clcvkgznjv 1 300 train
+clcwqjmvjd 1 239 val
+clcxdmbhxf 0 300 train
+clcyaiybyu 1 300 train
+cldcraffvt 1 300 train
+cldeqzisqv 1 300 val
+cldionzwzs 1 300 train
+cldosvtrea 0 300 train
+cldtjjykbj 1 300 train
+cldzxfpbkj 1 300 train
+cleiuzqvfv 1 300 train
+clekngdqxa 1 300 val
+clekumvwbf 0 300 val
+clercaqzmo 1 300 train
+clfauhmhcu 1 249 train
+clfckkmyvi 1 297 train
+clfgoqymlx 1 300 train
+clfhvtfnki 1 300 train
+clfkbhcgpj 1 300 val
+clflarcjlk 0 300 train
+clgeofdgrn 1 300 train
+clggcywupp 1 300 train
+clgkfocjve 0 300 train
+clgpmpxpxa 1 300 test
+clgtwmxbce 1 300 train
+clgwqczzza 1 300 train
+clhbomitfz 1 300 train
+clheiwbykm 1 300 train
+clhvpxpett 1 300 train
+clhxgbngzs 1 300 train
+clidemnydd 1 300 train
+clidutpabx 1 300 train
+clihsshdkq 1 300 train
+cliiprrcqk 1 301 train
+cliyfreqlz 1 300 train
+cljaovquzv 1 300 train
+cljbuyqbtk 1 300 train
+cljoncoqsk 0 300 train
+cljrrajwkj 1 300 train
+cljzmgwrva 1 300 train
+cljzmyuity 1 298 val
+clkgvdosxe 1 300 train
+clkhxtnxgm 1 300 val
+clkkwuxtkr 1 300 val
+clkrvlifja 1 300 val
+clkxgilfnl 0 300 val
+clkxjpokwa 1 300 train
+cllolfaunj 1 300 val
+cllpbyfczw 1 300 train
+cllsklblbu 1 301 train
+cllsvjohur 1 300 train
+clltaxoqos 1 300 train
+clmdutckle 1 300 val
+clmgkufday 1 300 train
+clmobaseag 1 300 train
+clmousfsnd 1 300 train
+clmtssvjaf 1 300 val
+clndjmjqbg 1 300 train
+clneutumat 1 302 train
+clnfbkylpp 1 300 train
+clnnqtjnld 1 300 train
+clnrmyghce 0 241 train
+clnugjmcva 1 300 train
+clnyyjtoce 1 240 train
+clomphlxce 1 300 train
+clotbjjrhl 1 298 train
+clotzdefxi 1 300 train
+cloxeokbne 1 300 train
+cloymwmsgb 1 299 val
+clpacpvsex 1 299 val
+clpanbecvs 1 300 train
+clpfdaynyl 1 300 train
+clpfovlxsy 1 300 train
+clpgwvlksy 1 301 train
+clplmehzka 1 300 train
+clpqepktwx 1 300 val
+clpvgmopjx 1 300 test
+clpxcisatq 0 300 train
+clpxpaeugz 1 301 train
+clqnsjqdpj 1 240 train
+clqufrsfxn 0 300 train
+clqzgrxrqy 1 298 train
+clqzvqrzwy 1 300 val
+clrdxzhlzn 1 299 test
+clrlpomyhr 1 300 train
+clrxigzbqr 1 300 train
+clrycekyst 0 300 train
+clsavohaye 1 300 train
+clscdexzde 1 300 train
+clsegmkrlh 1 300 train
+clskneivay 1 300 test
+clsqjqfqax 0 300 train
+clssjlgtkp 1 100 train
+clsuuljblu 1 296 val
+cltcgfkyrb 1 300 train
+cltfjmoqls 1 300 train
+cltivdolgi 1 300 train
+cltocmrmvu 1 300 train
+cltpibyvfx 1 300 train
+cltqdfqggg 1 300 train
+cltzentanu 1 300 train
+cluedbizkn 1 296 train
+clvbctyrsn 0 300 train
+clvddrgsab 1 300 train
+clvhyorkei 1 300 val
+clvklaeolq 1 300 train
+clvotgcjfe 1 300 val
+clvqvejlen 1 300 train
+clvrktxikr 1 300 train
+clvsjjnmxf 1 300 train
+clvsknptqj 0 300 train
+clvtrdioyp 1 296 val
+clvzmwiouq 0 301 val
+clwesdkstk 1 300 train
+clwgevlick 1 301 train
+clwhicktkw 1 300 train
+clwkkqwozj 1 300 train
+clwvkyuyqv 0 300 train
+clwyxxydld 1 298 val
+clwzfndgmf 0 300 train
+clxgzkdgta 0 300 train
+clxkihahpw 1 300 train
+clxlaisyrq 1 300 train
+clxohgaxby 0 300 train
+clxpxwgljm 1 300 train
+clybewdcgg 1 300 train
+clyiowxjxl 1 300 train
+clykvdevmb 0 300 val
+clyolrxzxs 1 299 train
+clyqtuwwub 1 301 train
+clyqxccszs 0 300 train
+clyysioglx 1 300 train
+clzcvdsuyp 1 300 train
+clzdeecpqt 1 300 train
+clzkcmoyhb 1 300 test
+clzmxxvlxs 1 300 train
+clzoosrlpp 1 300 train
+clzoubpxjg 1 300 train
+clzpppwfop 1 300 train
+clzpxvnaui 1 300 train
+clzsqkrvga 1 300 train
+clzvzcagxf 1 300 val
+clzwhpvfpe 1 241 val
+clzyhellbw 1 300 val
+clzyspsagz 1 298 train
+cmabtadwke 1 300 val
+cmaeplipsz 1 300 train
+cmaislyngh 1 300 train
+cmbagdmdtj 1 300 train
+cmbbrojtmm 1 300 train
+cmbcebohin 1 300 val
+cmbeyrzhvr 1 300 train
+cmbkignhjt 1 300 train
+cmbkzxueyi 1 300 train
+cmbloezomc 1 300 train
+cmbnbbuwcx 1 300 train
+cmbqehtmns 1 301 val
+cmbqibehhb 1 300 val
+cmbrlniexh 0 300 val
+cmbvmibdcr 1 300 val
+cmbzllswnl 0 300 train
+cmcgahdcmo 1 300 val
+cmchigmmtb 1 241 train
+cmcimjoliw 1 300 train
+cmdfrlzaou 1 299 test
+cmdgmeoloz 1 300 train
+cmdivumlkb 1 300 train
+cmdjfxeaap 1 300 train
+cmdnbivizp 1 300 train
+cmdvyowigi 1 300 val
+cmebjfuvfg 1 300 train
+cmebrzpwbo 1 300 train
+cmeciucico 1 301 train
+cmeiymxsrx 0 300 train
+cmenostbsi 1 300 val
+cmewuiizwx 1 299 val
+cmffdywyev 1 298 train
+cmffxgsunl 1 300 train
+cmfjolppux 1 300 train
+cmfldpsgig 1 300 val
+cmflgsaurh 1 300 train
+cmfrrykswu 1 302 train
+cmfvltcddo 0 300 train
+cmgktfejct 1 301 train
+cmgmhevsmr 1 301 train
+cmgotitvig 0 300 train
+cmgpkcqhwt 1 300 train
+cmgswxmvlv 1 300 val
+cmgxxmjbhr 1 300 train
+cmgybxlatl 1 300 train
+cmhdodlwik 1 300 train
+cmhfwbgfrv 1 300 train
+cmhjyeryaa 1 300 train
+cmhmrfjfna 1 299 train
+cmhsqjyhlg 1 300 train
+cmhyvnxuve 1 300 train
+cmibddnytf 1 300 val
+cmieiniplg 1 300 train
+cmilzubuwg 1 300 val
+cmiprzppvu 1 298 train
+cmirvugxlv 1 301 train
+cmjbogupmh 1 298 val
+cmjggvepqx 1 300 train
+cmjgsimibl 1 300 train
+cmjhohqldj 1 300 train
+cmjiaqgbuv 1 300 train
+cmjklhpdsw 1 300 train
+cmjvkiyrmg 0 300 train
+cmkcljpcsp 1 300 train
+cmkfxauicj 1 300 val
+cmkigulnas 1 300 train
+cmkrejkvea 1 300 train
+cmkzyzytqr 1 301 train
+cmlbhlhsdm 1 147 train
+cmleyapewy 0 300 train
+cmliuimutv 1 300 test
+cmlkxrufqw 1 300 train
+cmlmcdbwtg 1 300 train
+cmlrisjfim 1 300 train
+cmlubaczdt 1 300 train
+cmlvgoiwvz 1 300 train
+cmmifuinbl 1 301 train
+cmmlvopjbt 1 300 train
+cmmoeaeftx 1 300 test
+cmmoemwtce 1 298 train
+cmmqqqkpri 1 300 train
+cmmschvpal 1 300 train
+cmndgoaepe 1 300 train
+cmnnfymbez 1 300 val
+cmnoqaneou 1 298 train
+cmnpzanmsd 1 298 train
+cmnqnxtkhn 1 300 val
+cmnsepputh 1 300 train
+cmnubbdpnt 1 300 train
+cmoeewkbqv 1 301 train
+cmoizyxqcc 1 300 test
+cmojwrcgkx 1 300 val
+cmoonoypaj 1 300 train
+cmooxodlff 1 300 train
+cmoqimrics 1 301 val
+cmoqplbifs 1 300 train
+cmoskyzgrs 0 300 train
+cmoxqnhqdq 1 300 val
+cmoydflohs 1 300 train
+cmpbjkjtks 1 300 train
+cmpeoqifai 1 300 val
+cmpfjuwyud 1 300 train
+cmpkopoabr 1 300 train
+cmplvsxspz 1 300 train
+cmpmbimess 1 300 val
+cmpnnbdogx 1 300 train
+cmpozkuian 1 301 val
+cmpptnjisz 1 300 train
+cmpspkmedk 1 300 train
+cmptloljte 0 300 train
+cmpzwzrfsp 1 298 train
+cmqegbgirh 1 300 train
+cmqfdirmpu 0 300 train
+cmqfqmivto 0 300 train
+cmqjgyponj 1 300 train
+cmqjpitmyj 1 300 train
+cmqrkqlqck 1 300 train
+cmqryxvrjs 1 241 train
+cmqtagbxou 1 300 train
+cmqwzqehdv 1 299 val
+cmreaehfwr 1 300 train
+cmrfcmxoee 1 298 val
+cmrjxxmtef 0 300 train
+cmrqmtdawr 1 300 train
+cmrwhmiolw 1 300 train
+cmrwjnqpon 0 300 val
+cmsfecvsiz 1 300 train
+cmsgfgmofg 1 299 test
+cmshgnsghq 1 240 train
+cmshwdpbjn 1 300 train
+cmskrcosbs 1 300 train
+cmspdykufp 1 300 train
+cmssuctcdv 1 300 train
+cmsvynguda 1 300 train
+cmthxxcfie 1 300 train
+cmtmamcdte 1 300 train
+cmtnchtoqz 1 300 train
+cmtppftktc 1 300 train
+cmtwutvqch 1 300 train
+cmtxhuzakl 1 143 train
+cmtxuweesh 1 300 train
+cmtygbdohw 1 302 train
+cmuhgymbnl 1 300 train
+cmuidddbpj 1 300 train
+cmuzrrlaiy 1 301 train
+cmvdkibrsb 1 300 train
+cmveqobtaf 0 300 val
+cmvguitoba 1 300 train
+cmvncstbkx 1 300 train
+cmvnrjllux 1 300 train
+cmvterrdsl 1 300 train
+cmvwxakhgc 1 300 val
+cmvymfbmlb 1 300 test
+cmwbktrvdu 1 301 val
+cmwfhmyqzm 0 300 val
+cmwggappmh 1 300 val
+cmwjtsaukx 1 301 train
+cmwkhvxthg 1 300 val
+cmwmcvvmlx 1 301 val
+cmwnysjtww 1 300 train
+cmwozbaxwb 1 300 train
+cmwqaulwau 1 300 test
+cmwxpmbuea 1 300 train
+cmxbukanvn 1 300 val
+cmxcfkrjiv 1 300 train
+cmxckeiagl 1 300 val
+cmxeyjxras 0 300 train
+cmxkckfafd 1 300 train
+cmxnhlhpjv 1 300 train
+cmxooumvba 1 299 test
+cmxpchregf 1 300 val
+cmxtwpabsw 1 300 val
+cmxtxfhqxi 1 300 train
+cmxzobnpcz 1 300 train
+cmyahcrgiv 1 300 train
+cmybfubapj 1 300 val
+cmydgfodof 1 300 train
+cmyhcrqfnl 1 300 train
+cmyiicmdpj 1 300 train
+cmyqxqrdkq 1 300 val
+cmyrwbuxek 1 300 val
+cmyvjmgldk 0 300 val
+cmzcojwcbn 1 300 train
+cmzeicaooh 1 300 train
+cmzgqumtko 1 300 train
+cmzpzaevel 1 300 val
+cmzsehkpnj 1 300 val
+cmzvlrfqsq 1 300 train
+cmzxputgcr 1 300 train
+cmzztzglmh 1 298 train
+cnabiivwwt 1 300 train
+cnahwlfafy 1 300 train
+cnaifxmdlx 1 300 train
+cnajogtazm 1 300 train
+cnakptxcfx 1 300 train
+cnaodqzsny 1 300 train
+cnavndhbdb 1 300 train
+cnaxfhqakf 1 300 train
+cnazdwrfur 1 300 train
+cnbgfhcdkl 1 299 val
+cnbhotdrub 1 300 val
+cnbjnlfeft 1 300 train
+cnbkrmhwjc 1 300 train
+cnbpshabzc 1 300 train
+cnbpzdeuzs 1 301 train
+cnbtegsjlx 1 300 val
+cnbxddelwb 1 299 test
+cncditjduh 1 300 train
+cncmotjhsc 1 296 train
+cncobrsrrb 1 300 val
+cndfsgcjhv 1 300 val
+cndpomgvxd 1 301 train
+cndtykayuj 0 300 val
+cnedrutuoj 1 300 train
+cnefwbcagz 1 301 train
+cneoslxrqp 1 300 train
+cneqrafhqp 1 300 train
+cnequaglft 1 300 train
+cnfceaaqyl 1 300 train
+cnfcgevkdy 1 300 train
+cnfcweqfvl 1 300 train
+cnfgyoqoja 0 300 train
+cnfidfeyln 1 300 train
+cnfjejhxuy 1 301 val
+cngclcygxh 1 300 train
+cnglddzyhs 1 300 train
+cngogfretb 1 269 train
+cngppjgnav 1 300 train
+cngrcqfmef 1 300 train
+cnguoshwca 1 300 val
+cngwikbryl 1 300 val
+cngypocnyc 1 298 val
+cngzljeedg 1 300 train
+cnhauwlvza 1 300 val
+cnhcjnjtvc 0 300 val
+cnhmgesyff 1 300 train
+cnhmhmnjzt 1 301 train
+cnhpwzknts 1 300 train
+cnhuzleszm 1 299 val
+cnicolmysx 1 300 train
+cniguenkpg 1 300 train
+cnigvwpbnp 0 300 val
+cnilkgvfei 1 300 train
+cniqcqqkpc 1 300 train
+cnitdhksts 1 300 val
+cnitpzzwkc 1 300 train
+cniuvcmuwp 1 301 train
+cnizkimkhj 1 300 train
+cnjhnysnft 1 300 train
+cnjiycuopd 1 300 train
+cnjkvuxvxz 1 300 train
+cnjlvpzfrg 1 300 train
+cnjssbpoun 1 300 train
+cnjzvuvdrg 1 296 val
+cnkagalbom 1 298 train
+cnkbkvykej 1 300 train
+cnkgfsvgpa 1 300 train
+cnkiievkcs 1 300 train
+cnklpvtzdv 1 300 train
+cnktwklcrb 1 300 val
+cnkwxuysgk 0 300 val
+cnlboybtqk 1 300 train
+cnlovaecgh 1 300 train
+cnlttcfsvu 0 300 val
+cnlypryluk 1 299 train
+cnmdpskbjv 1 298 train
+cnmdwvuecr 1 300 val
+cnmfybsdbz 1 301 train
+cnmhsqkovv 1 298 train
+cnmiiuubmx 1 300 train
+cnmjfcypzg 0 300 train
+cnmrwmzssw 1 300 val
+cnnoztbpyy 1 298 train
+cnnrlpqzzt 1 300 train
+cnnuglakib 1 301 val
+cnnullkglj 1 300 train
+cnnxvazzze 1 300 train
+cnnyovajio 1 300 val
+cnoasvesez 0 300 train
+cnobbyyzoq 1 300 train
+cnowlqxdbx 1 300 val
+cnpanmywno 0 299 test
+cnpasnybly 1 300 train
+cnpelqnahn 1 300 train
+cnplpnqrfn 1 300 train
+cnpwoqxjps 1 300 train
+cnqaogqexa 1 299 val
+cnqqljnnuc 1 300 test
+cnqqzkrgmh 1 300 train
+cnqrnrzzll 1 300 train
+cnqsdkwzmn 1 300 train
+cnqvsvshlv 1 300 train
+cnqwgagcgy 0 300 train
+cnrodkfuay 0 300 train
+cnroesqwki 0 300 train
+cnrofrairp 1 300 train
+cnrpluzcpw 0 300 train
+cnrqyitpqs 0 300 val
+cnsmgjuxbi 1 300 train
+cnsnofuoiq 1 300 train
+cnspvaxxfr 1 301 train
+cntdawrowp 1 300 train
+cntgysycel 1 300 train
+cntncbmgmi 0 300 train
+cntorkscyt 1 300 train
+cntvbpqykw 1 300 train
+cntwvadfii 1 300 train
+cnuhhfeikg 1 300 train
+cnuhjcswso 1 300 train
+cnukeekhca 1 298 train
+cnumpytbpm 1 300 train
+cnuvbfpaek 1 300 train
+cnuvmpbnje 1 241 train
+cnvbvrcyaa 1 300 train
+cnvbzwmwyx 0 300 train
+cnvdpkxlgy 0 300 val
+cnvhlcuyjq 1 300 train
+cnvkcqtdbw 1 300 train
+cnvkzbnefj 1 300 train
+cnvpcernca 1 299 test
+cnvquynriz 0 300 train
+cnvskvokjr 1 300 train
+cnvuwedyis 1 300 train
+cnwcbgzrbg 1 300 train
+cnwfngmrog 1 300 train
+cnwhmioyeg 1 298 train
+cnwiicuofh 1 300 train
+cnwlrvzura 1 300 train
+cnwryfbhjs 1 300 train
+cnwumgmtoc 1 300 train
+cnxccbjlct 1 300 test
+cnxzgurkld 0 300 train
+cnycctrbyt 1 300 train
+cnyfrwkiyl 1 300 train
+cnyfzszjoh 0 300 train
+cnymesatee 1 301 val
+cnypegdqth 0 300 train
+cnypgecspy 1 301 train
+cnyphduocz 1 300 train
+cnzfgqsbnq 1 300 train
+cnzlqibzwf 1 300 train
+cnztaiaphu 1 300 train
+cnzxvjdwbw 1 301 train
+coaaaeqsta 1 300 train
+coacrsvrnl 1 300 train
+coadfnerlk 1 300 train
+coahfvujdv 1 300 train
+coahxknxuy 1 300 train
+coamtllvrf 1 300 train
+coatfjiush 1 300 train
+coawjwyyjo 1 300 train
+coayfxnsgw 1 300 val
+coayxlvxyu 1 300 train
+cobcvmzdph 1 300 train
+cobiwoqcbv 1 299 val
+cobjrlugvp 0 300 train
+cobnmkgjiu 1 300 train
+cobowalzix 0 300 train
+cobrcdtekr 1 300 train
+cobtsztpyg 1 297 train
+cobxovtdmw 1 300 train
+cocaotafob 1 300 val
+coclzlvacz 1 300 train
+coclznjhtm 1 299 train
+cocrpazpna 1 300 train
+cocxlcbtfz 1 300 train
+codgmogbzc 1 300 train
+codllgchjp 1 299 test
+codrzmxemd 0 300 val
+codthnumyq 0 300 train
+codvgpqpaa 1 300 train
+codynbclja 1 300 train
+coedpbayuc 1 301 train
+coegoetjpm 1 300 train
+coenczwdxq 1 301 train
+coenupqwgt 0 300 train
+coeofrqblu 1 300 val
+coeuxzclkm 0 300 val
+coevwwztuk 1 255 train
+cofagrkybh 1 300 train
+cofjvqjkcj 1 300 train
+cofsgceysf 1 300 train
+cofsuwbpti 1 300 train
+cofwjxpmcl 1 300 train
+cofxbtbnsf 0 300 train
+cofxgrlrpb 1 300 train
+cogcbbxpsn 1 301 train
+cogcrwzvdb 1 300 train
+cogcvbbjcm 1 300 test
+cogdchtkek 1 298 train
+cogefdzykg 1 240 train
+cogkntngde 1 301 train
+cogvxntstc 1 300 train
+cogwlfktmv 1 297 train
+cogxmahduk 1 299 test
+cogywizzkb 0 300 train
+cohgnhsldi 1 300 train
+cohkwaxnvw 1 299 test
+cohlqbfxzu 1 300 train
+cohnfjjaas 1 300 train
+cohyafsjaf 1 300 val
+coiaetywjj 1 300 train
+coibcixpqp 1 300 train
+coijxsppdw 1 300 val
+coikhtewmt 1 300 train
+coilvztxsl 0 300 train
+coiqibotbv 1 300 train
+coiymemlxe 1 300 val
+cojdjqdmua 1 241 train
+cojfnbtfkr 0 300 train
+cojfzsbdkf 0 300 train
+cojkkldalk 0 300 val
+cojqpjeibd 1 300 train
+cojthhfywz 1 300 train
+cojtqauazp 0 300 train
+cojznwlzoi 1 300 train
+cokcdaizvg 1 300 train
+cokftyhjmk 1 300 val
+coklegowbt 1 300 train
+coklfjtcyt 0 300 train
+cokojygoiq 1 300 train
+coktlalzeg 1 300 train
+colqfkwuyq 1 301 val
+colvnutibe 1 300 train
+colylxvjmu 1 300 train
+colzynxyxj 1 300 train
+combksqhno 1 300 val
+comgldjhwm 1 300 train
+comlodmqnt 0 300 train
+commemfsua 0 269 train
+comoufohza 1 300 train
+comoxqrfup 1 300 train
+comqkwjrft 0 299 val
+concvocmmz 0 300 train
+condbpyazo 1 300 train
+congkparoh 1 300 val
+connsjyvsl 1 300 train
+conodqbmpe 1 300 train
+contphjzyg 1 300 train
+convbaiiiu 1 300 train
+convzgmiqk 1 300 train
+cooarrfjoi 1 300 train
+coopfllocl 1 300 train
+copcucgbif 1 300 train
+cophefpjri 1 300 train
+copinsyiiz 1 300 val
+copiodpxtl 1 300 val
+copowfosob 0 300 train
+coptuddcwd 1 300 val
+copybkdfji 1 300 train
+coqatretvx 1 300 train
+coqrcakmmx 0 301 train
+coqwgzpbhx 1 299 test
+coqybzqqgb 1 298 val
+coralbgmjk 1 300 train
+corcplqpxs 1 298 train
+corhwewwda 1 300 train
+corqagqytp 1 300 train
+corsygyivy 1 241 train
+corudnbzlm 1 300 train
+corvccyssr 1 300 train
+corvjpcyuf 1 300 train
+corxcnlslj 1 300 train
+corznpbttm 1 300 train
+corzuofzie 1 300 val
+cosdfmtfwa 0 300 train
+cosfoqobzo 0 300 train
+cosghhimnd 0 299 test
+cospepjvas 1 300 train
+cossfdblib 1 297 train
+cossnrydpl 1 300 train
+cotcpetxls 1 300 train
+cotdljjfei 1 301 train
+coteoeomqu 1 300 train
+cotgxtgqse 1 300 train
+cotriwoyvq 1 300 val
+cotsihcdmg 0 300 val
+cotubmgefn 1 300 train
+cotvgdnkbo 1 297 train
+cotvlcroov 1 241 train
+cotxffvovx 1 299 train
+couachazlq 0 300 train
+coubxyuvrm 0 300 val
+coujjnypba 1 300 test
+coujzlfkke 1 298 train
+coulkppulq 1 300 val
+couoovfwtb 1 299 val
+courgddfev 1 300 train
+coushmhsij 1 600 train
+couyrcwviy 1 300 train
+covdcysmbi 1 300 train
+covhwtdspw 1 300 train
+covnmughjo 1 300 val
+covqctlmpu 1 300 val
+cowcehymay 1 298 train
+cowjeoqoxc 1 300 val
+cowmhzmvyg 1 300 train
+cowwzodpkz 0 300 train
+cowxzlygfo 1 100 train
+cowxzrtdcx 1 300 val
+coxemxwyzy 1 300 train
+coxkwvnpvu 1 300 train
+coxssmkqbu 1 300 train
+coxwlrjeyw 1 298 train
+coyhkbkmrm 1 298 val
+coyjgtrxhb 1 300 train
+coymcqztbj 1 300 train
+coytfhjqcr 1 300 val
+coyvlrgimg 1 300 val
+coyzppokcj 1 300 val
+coyzuzluob 0 300 val
+cozcfuwxip 1 300 train
+cozgtibuda 0 300 train
+cozhgscyij 1 301 train
+cozlsbzlsh 0 300 train
+coznguzsuq 0 300 train
+cozslsoswi 0 300 train
+cozxtycxag 0 300 train
+cozyxkfkqp 1 300 train
+cpacgxipon 1 300 train
+cpaeucefro 1 136 train
+cpaqcfnlih 1 300 train
+cpbbbpewsb 1 300 train
+cpbqwwhrxq 0 300 train
+cpbrauhlcl 1 300 train
+cpbvnkznpc 1 300 train
+cpcecgauub 1 300 train
+cpcfmvdnlh 1 300 val
+cpcgexznuc 1 300 train
+cpcmcqbboj 1 300 train
+cpcnyqoevu 0 300 train
+cpcrcezxqo 0 300 train
+cpctmtsgme 1 300 train
+cpctqroarq 1 300 val
+cpcuvixqbn 1 300 train
+cpcuxqcgzp 1 300 train
+cpdecknbqp 1 300 train
+cpdlcyrbum 1 300 train
+cpdlqhbvux 1 300 train
+cpdtroihpl 1 301 train
+cpdvvwvuxb 1 300 train
+cpdwlliqpj 1 300 val
+cpeajrjkoa 0 300 train
+cpecpwjvtl 1 298 train
+cpecqrnxkn 1 300 val
+cpeehyyazr 0 300 train
+cpefzmckiq 1 300 val
+cpegivsezt 1 300 val
+cpegwviavn 1 300 train
+cpeixodiyg 0 300 train
+cpekxlmlwa 1 300 train
+cpelglathd 1 300 train
+cpeucaxrny 1 300 train
+cpezrspnjr 1 299 train
+cpfbbhkuus 1 298 train
+cpfomgxkvd 1 300 val
+cpfwywwknx 1 298 train
+cpfwzeszbn 1 300 train
+cpgayhckef 1 300 train
+cpgewtslab 1 301 train
+cpgksamyev 1 300 train
+cpgmeuhbtk 1 300 train
+cpgrwxmkxw 1 300 train
+cpgtztewxf 1 300 val
+cpgzwqlszu 1 300 val
+cphfdjkgmq 0 300 val
+cphgymzdqs 1 300 train
+cphhxmdzgg 1 300 train
+cphnpwcmkx 1 300 train
+cphnsdosco 1 298 train
+cphokrjsqo 0 300 train
+cphtzishek 1 241 train
+cphwzddoiy 1 300 train
+cpieheiujg 1 300 train
+cpihokcdyk 0 300 val
+cpijvkgxvy 1 300 train
+cpikbgotus 0 300 train
+cpiknuswli 1 300 train
+cpipsblwsv 0 300 train
+cpixrjvxjn 1 300 train
+cpiztwrcqk 0 300 train
+cpjiflbqbo 0 300 train
+cpjjvyskbm 1 300 train
+cpjxareypw 0 300 train
+cpjyrivahb 1 300 train
+cpkahsazdl 1 292 val
+cpkbrjijpt 1 300 train
+cpkeyidusc 0 239 train
+cpkpfdwfmb 0 300 val
+cpkyabfzlc 1 300 train
+cplbyzaslf 1 298 train
+cpleiewmzv 1 300 val
+cplhunmfvv 0 236 train
+cplkdbfpxj 1 300 val
+cplqsrsnyr 1 300 train
+cplxouetis 1 300 val
+cpmawzfuyu 1 300 val
+cpmfiaiqsq 1 300 val
+cpmgnsrogr 1 300 train
+cpmqxchnmg 1 300 train
+cpmqyjjzpk 1 300 train
+cpmridjxbc 0 300 train
+cpmswmgiqr 1 301 train
+cpmvsuixwn 0 300 train
+cpnbbykfds 1 300 train
+cpnlmkmmdh 1 300 train
+cpnompjulg 1 300 val
+cpnpmgzqvv 1 300 train
+cpoqoqmxct 1 300 val
+cpowyojoit 1 600 train
+cpoyanxkdb 1 300 test
+cpoybfqsno 1 300 train
+cppaigkyae 1 300 train
+cppblldqit 0 300 train
+cppdvdejkc 0 298 train
+cppjlsrmoe 1 300 train
+cpplszmkmd 1 301 val
+cppztnbtvs 1 300 train
+cpqaiqrblo 1 300 train
+cpqdbunxcq 1 300 train
+cpqgdzvakx 1 300 train
+cpqygdahym 1 300 train
+cprbwwlbhz 1 300 train
+cprbzixvdu 1 300 train
+cprdevfjyw 1 300 val
+cprdwtsorp 1 300 train
+cprhtltsjp 0 300 train
+cprktvyrlw 1 301 val
+cprmmgasmm 1 300 train
+cprsviqowo 1 300 train
+cpsjmhhzye 1 301 train
+cpskfrurfq 1 300 train
+cpsmnqhsck 0 300 train
+cpsqfqaztq 1 300 val
+cpsqhltyrz 1 298 train
+cpsttjlkme 1 300 train
+cpszgjiwdh 1 300 train
+cptdjxaxtq 1 300 train
+cptemwefma 1 300 train
+cpthaklgku 1 299 val
+cpthtjqwjg 1 300 train
+cptolstjjp 1 302 train
+cpubwmcllz 1 300 train
+cpucjmfawf 0 300 train
+cpujuvwaed 1 300 train
+cpuqxxfjzq 1 300 train
+cpuuoyqige 1 300 train
+cpuwahasdg 1 301 val
+cpvbjfhbph 0 300 train
+cpvhgylffq 0 300 train
+cpvlmfudwa 1 300 train
+cpvnfjfmni 1 300 train
+cpvnpvcvzo 1 300 train
+cpvwreivtv 0 300 train
+cpvxeupcjb 1 300 train
+cpwbmlyzjd 0 300 train
+cpwfwaurge 1 300 train
+cpwgofevvo 1 300 train
+cpwjaveeeq 1 300 test
+cpwmxjfltv 1 241 train
+cpwovkauzj 0 300 train
+cpwwwqvyyl 1 300 train
+cpwxkbdths 1 298 train
+cpwxruldkk 1 300 val
+cpwyqbacrt 1 300 train
+cpxbnzuafp 0 300 train
+cpxdooypve 1 241 train
+cpxedkyytp 1 300 train
+cpxkrtypkz 1 300 train
+cpxlfotfyz 1 300 train
+cpxlmsatst 1 300 train
+cpxxhaiexb 1 300 train
+cpxxliovme 1 300 val
+cpxxtmviit 1 299 train
+cpxzktdxsi 1 299 val
+cpybodhbkn 1 300 train
+cpycvtmtuo 0 300 train
+cpylltovhq 0 300 train
+cpynfxglzc 1 300 train
+cpyqtpzmtr 1 300 train
+cpyuoaqeyi 0 300 val
+cpzazvweaq 1 300 val
+cpzbttbllo 1 301 val
+cpzncpzzwa 0 300 train
+cpzrjqnffi 1 299 test
+cpzyxoqgnd 1 300 train
+cqabbbsxeq 1 301 train
+cqacexiqmy 1 301 val
+cqadfjmclr 1 299 train
+cqahjlxssx 1 300 val
+cqamutjreg 1 300 train
+cqawkwzcfy 0 296 train
+cqazhnkjrt 1 300 train
+cqbfayfpqx 0 300 val
+cqbglsbujj 1 301 val
+cqbhgsmffd 1 300 test
+cqbjqtmqvj 1 300 train
+cqbnjiyzay 1 300 val
+cqbodtkxiw 1 300 train
+cqbtboxqzb 1 300 train
+cqbxgessxh 0 300 train
+cqclibqbwz 0 300 train
+cqcqgggpml 1 300 train
+cqcvtiijro 1 300 val
+cqdgetigaq 1 300 train
+cqdgydgsxe 1 300 train
+cqdkvkmzgl 1 300 train
+cqdnnweluw 1 300 train
+cqdpononmq 1 300 train
+cqdxzxirqw 1 300 train
+cqdyheoqhn 1 300 train
+cqdytnllfm 0 300 train
+cqdzakzakn 1 300 train
+cqdzgskztu 1 300 val
+cqdzkfrdxl 0 300 val
+cqeaaihvfr 1 300 val
+cqeekdnkpa 1 301 val
+cqegquwdda 1 300 train
+cqehhxyhto 1 300 train
+cqehppvict 1 299 train
+cqemqttubw 1 300 train
+cqeqirfagb 1 300 train
+cqerqirksv 0 301 val
+cqeuyhnqft 1 300 val
+cqevoiruai 1 298 train
+cqewayywpg 0 300 train
+cqewfqnawl 1 300 train
+cqezovtiya 1 301 train
+cqfapooeqz 1 300 train
+cqfcupulef 1 300 train
+cqfugiqupm 1 300 train
+cqfxfcrdrg 1 300 train
+cqfxgyotpv 0 300 train
+cqfzfuxvyw 0 300 train
+cqgdtrywmy 1 300 train
+cqgfbxpkuj 0 300 train
+cqgihowwhl 1 300 val
+cqgjvtnhir 1 300 val
+cqgosurwtp 1 300 train
+cqgqrhjwqh 1 300 val
+cqgsacster 1 300 train
+cqgtfwgxcw 1 300 val
+cqgttxrorj 1 300 train
+cqgvmjtidv 1 300 train
+cqgyemjnsl 1 301 train
+cqgzckbimc 1 300 train
+cqhdzpuogz 1 301 train
+cqhmucnpaf 1 300 val
+cqhngvpgyi 1 300 train
+cqhsrnvpvo 1 300 train
+cqhvizekqo 1 300 train
+cqhwesrciw 1 300 test
+cqhxhikvgp 1 300 train
+cqidzzgjjr 1 300 train
+cqiedhyzom 1 300 train
+cqiedyggnb 1 300 train
+cqiktzymdu 0 300 train
+cqinqrcvse 1 300 train
+cqiqryrhox 1 300 train
+cqiscqrtlw 1 300 train
+cqiyijvrcj 1 300 train
+cqjirpfwmj 1 300 val
+cqjiuvuori 1 300 train
+cqjoqhigvz 1 300 val
+cqjpvlbjiy 1 241 train
+cqkarxqzxx 0 300 val
+cqkfihwvvr 1 300 train
+cqkftuhhza 1 300 train
+cqklyqnfer 1 300 train
+cqkomlfzpo 1 298 train
+cqkpqekzcw 1 297 train
+cqkskvnktc 1 301 val
+cqksooccmu 1 300 train
+cqkwtgecwf 0 300 train
+cqlarprtdy 0 301 val
+cqljnmuloq 1 300 train
+cqlwckvaeb 1 300 train
+cqmhxvdkuo 1 300 train
+cqmmgxqjtf 1 300 train
+cqmpldiwzv 1 300 val
+cqmwyzpikk 1 300 train
+cqmywmtbsi 1 300 train
+cqnbbdltgq 1 300 train
+cqnbolqdhe 1 300 train
+cqntibhkbq 0 300 train
+cqnutosgsm 1 300 train
+cqnwfpglna 1 302 train
+cqodkyhimq 1 300 train
+cqogueyphy 1 300 train
+cqogutfwhh 1 300 train
+cqojknfuus 1 300 train
+cqomufbzpp 1 300 test
+cqoqshvwuy 1 300 train
+cqoqzojnzo 1 300 train
+cqorwncvhl 1 300 train
+cqosugshyr 1 300 val
+cqpbrcmqmd 0 300 train
+cqpdqjzgcs 1 300 test
+cqpjedhvoz 0 300 train
+cqpoanrjak 1 300 train
+cqpxanikyo 1 300 train
+cqpyzqtnqt 1 301 train
+cqqapjnjkx 1 300 train
+cqqatvxerx 1 300 val
+cqqbbmvfid 1 300 train
+cqqbmmqnda 1 300 train
+cqqcrpuail 0 300 train
+cqqgbnaknv 1 300 val
+cqqokqqoks 1 301 train
+cqqvqkryoe 1 300 train
+cqriqodldx 1 300 val
+cqrjepnrii 1 300 val
+cqroxivqio 1 300 train
+cqrskwiqng 1 300 train
+cqrxhsuqqq 1 300 train
+cqsaiextgs 0 300 train
+cqsgfwcots 1 300 train
+cqshmiarqg 1 300 train
+cqsixjxbxo 1 300 val
+cqskjazxwc 1 300 train
+cqsmuftgep 1 300 train
+cqsslhhood 1 301 val
+cqsyxoqcds 0 300 val
+cqtaofqvtl 1 300 train
+cqthqbsuyv 1 300 train
+cqtikmpave 1 300 train
+cqtjxkuwrv 1 300 test
+cqtlzarcss 1 300 train
+cqtozexihz 1 300 train
+cqttsbnsag 1 300 train
+cqtwjlhsgl 1 300 train
+cqtwqdzswc 1 300 val
+cqtxrekabh 1 300 test
+cqudzzwtlo 1 300 train
+cquhouhgoc 1 300 train
+cqukylpdhr 1 300 train
+cquniinedp 1 300 train
+cqunquafan 1 300 val
+cquqakbnso 1 300 train
+cquwxluokz 1 300 train
+cquygcocfz 1 298 val
+cquynbyczd 1 301 train
+cqvancueff 1 300 train
+cqvbejdreo 1 302 train
+cqvdbcugwg 1 300 train
+cqvektkbtn 1 300 train
+cqvglgkzui 1 300 train
+cqvgopmkna 1 300 val
+cqvmcswepa 1 299 test
+cqvndapzgg 1 300 train
+cqvoycciww 1 297 val
+cqvrufiicc 0 300 train
+cqvugayosg 0 300 train
+cqwipjgzlo 1 301 train
+cqwmesauep 0 300 train
+cqwpquwxid 1 300 train
+cqwprtijzp 1 300 train
+cqwsblloon 1 300 train
+cqwvtaauzd 0 299 train
+cqxchwnkov 0 300 train
+cqxddddvro 1 298 train
+cqxfndecan 1 300 train
+cqxgajyaon 1 301 train
+cqxkntoiqh 1 300 val
+cqxkqqscrm 1 300 train
+cqxqzzfrox 1 300 train
+cqxwlkmiel 0 300 train
+cqxwnhupme 1 300 val
+cqxwwyreqe 1 301 train
+cqxxumarvp 0 299 test
+cqxylbgxnc 0 300 val
+cqybfihzfe 1 301 train
+cqyjdmmncl 1 300 train
+cqyjopioik 1 300 train
+cqyndkxmum 1 300 train
+cqynoztleq 1 299 test
+cqyowzdfdd 1 300 train
+cqyugsdrcu 1 300 train
+cqyvauumlt 1 300 train
+cqyvyvppyi 1 300 train
+cqzbohnyip 1 300 val
+cqzcdwnhtg 1 300 train
+cqzkjylvwz 1 300 train
+cqzpbfqghe 1 300 train
+cqzpcuukhp 1 296 val
+cqzylfwbkq 1 300 val
+cracconkyr 0 109 train
+cracusggal 1 300 test
+crakbxvcyh 1 300 train
+craslvtlfq 1 300 train
+crawadrnaa 1 300 train
+crbcrxqftw 1 300 train
+crbeedzivm 1 300 train
+crbegopwgs 1 300 train
+crbieeifzf 1 300 train
+crbijnlhbx 0 300 train
+crbjylbwlc 1 300 train
+crbrgeviwa 1 300 train
+crbrxpiqvz 1 300 train
+crbspiybxp 1 300 train
+crbxbmyldj 1 241 train
+crcbryuqhz 1 300 train
+crcgmnaxvs 1 300 val
+crcnhvsixi 0 300 train
+crcrqrsyik 1 300 val
+crctktvhej 1 300 train
+crcwhjdwhy 0 300 train
+crcyrotboj 1 301 train
+crczcrffvo 1 300 train
+crdblihodv 1 300 train
+crdcnjqflx 1 300 train
+crdcqpxoen 1 300 train
+crdehzludu 1 300 train
+crdhketdoh 0 300 val
+crdongatjy 1 301 train
+crdsuotgfl 1 300 train
+crdtvzbluw 1 136 train
+crdwshvwjn 1 300 val
+crdyfgsduz 1 301 val
+crdyibxnar 1 298 train
+crecahperw 1 300 train
+crehkldrkf 1 300 val
+crejnrpfwu 1 300 train
+crekemdxff 1 300 train
+crekmuotuk 1 300 val
+creldqlbzr 1 301 train
+crenxvvkwy 1 300 train
+creplotjfu 0 300 train
+crervajrku 1 297 train
+crevnrhhxu 1 300 train
+creyvvrxcf 0 300 train
+crezycjqyk 0 300 train
+crfargrltm 1 300 train
+crfflxuedy 1 300 val
+crflaflooj 1 300 val
+crflouimpt 1 300 train
+crfmxlbnbd 1 302 train
+crfnqdprte 0 300 train
+crfolhbuzh 1 300 train
+crfrgvezut 1 300 train
+crftazrgju 1 300 train
+crfwqlljtp 0 300 train
+crfyvirnma 1 300 train
+crgcccsirc 0 300 train
+crgcrqxqjw 0 300 train
+crgedimfpc 1 300 val
+crgeyrdfxk 1 300 train
+crggfpfpjz 1 300 train
+crgoxxvpxp 1 298 train
+crgwevtkgf 1 300 train
+crgwncwwns 1 300 train
+crhelcitmz 1 299 test
+crhglqfttf 1 300 train
+crhjwwgtef 1 301 train
+crhkipauyk 0 300 train
+crhlyjcycv 1 300 train
+crhqpootot 1 300 train
+crilhpdoez 1 300 val
+crimgzxour 0 300 val
+crisotkdmh 1 300 train
+crisypahfv 1 297 train
+critntktnq 1 300 train
+criwntgqwh 1 300 train
+criztkfuem 1 300 train
+crjaxyhanq 1 298 train
+crjjkpskgu 1 300 train
+crjlenlhek 1 300 train
+crjvhcpwis 0 300 train
+crjzbblhog 1 300 train
+crkcsrelev 1 300 train
+crkjzvzyzb 1 300 train
+crkmmnhiam 1 300 val
+crktehraph 1 300 train
+crkzinirbp 1 300 train
+crlbsvunnh 1 300 train
+crlbzncobq 1 300 train
+crlftkllsd 0 300 val
+crlgomenvb 1 300 val
+crllsfqiul 1 300 train
+crlollqxtq 1 300 train
+crlphqtqnq 1 300 train
+crlxjpnyrt 1 300 train
+crlzwoiasj 1 300 train
+crmkkgqahl 1 300 val
+crmlpdbazp 1 298 train
+crmobgizwo 0 300 train
+crmwccddrb 1 300 train
+crnbqgwbmt 0 300 train
+crnfdbnpjz 1 300 train
+crnhcygnjj 1 300 train
+crnjzofvaf 1 300 train
+crnkpgykgj 1 300 val
+crnnkjvdmt 1 300 train
+crnpivmygd 1 300 train
+crnwdznwcx 1 300 val
+croamzzqdr 1 299 train
+crocgecwna 1 302 val
+croehqngdb 1 300 val
+crooqcjlqc 0 300 train
+croqkpakht 1 300 val
+crotumbywg 1 300 train
+crowjypbvu 1 300 train
+crpixkdmav 1 300 train
+crplxxbnkm 1 300 train
+crpmgqavlf 1 300 train
+crpmskycub 1 300 train
+crprqezmgn 1 300 train
+crqclprxcp 1 298 train
+crqhicfshq 0 300 train
+crqkqjncyz 1 301 val
+crqltosafm 0 300 train
+crqoxbkkpl 1 300 train
+crqrncjcaz 1 300 train
+crqsiyuufg 1 300 train
+crqybwddzz 1 300 train
+crqzfjravf 1 300 train
+crrcreusag 1 300 train
+crrihgnehr 0 300 val
+crrokkivdw 1 300 train
+crrthxtrth 1 300 train
+crrygtvdxd 1 300 train
+crsdkuimiu 1 300 train
+crsfsmblkf 1 298 train
+crsqboyipf 1 300 val
+crsvyhlvko 1 300 train
+crtfokolyw 1 300 train
+crtprwbbpd 1 300 val
+crtqgmicas 1 300 train
+crtsgpkzmv 1 300 val
+crtvtlmchf 1 300 train
+crtwajokau 0 300 train
+crtxxkfztp 1 300 train
+cruaalheal 1 300 train
+crubhecwnk 0 300 train
+cruebsmlgr 1 241 train
+cruhcatywp 1 300 train
+cruiyqzoso 1 298 train
+crumzbcdoq 1 300 train
+cruozikpmv 1 300 train
+cruwjlxxzf 1 300 train
+cruxhaxsmq 1 300 val
+crvepxiplb 0 300 train
+crverjdkhk 0 300 train
+crvipdssks 1 240 train
+crvjayqqcl 1 300 train
+crvjjrszvm 1 298 val
+crvlwgvhjz 1 300 val
+crvmhykxki 1 300 train
+crvnokpuao 1 300 val
+crvotfojeq 1 300 train
+crvtmfzxzb 1 249 train
+crvvtpydtx 1 300 train
+crwkoeoxfi 1 300 train
+crwwligkoi 1 300 train
+crwzrpozbv 1 300 test
+crwzuxqezo 1 300 train
+crxccbeifk 1 300 val
+crxgozdcne 1 300 train
+crxnkfunvm 0 300 train
+crxtvlwpgc 0 300 train
+crxwhnfbmh 1 288 train
+cryjdayyxa 1 147 train
+cryqrsysbf 1 300 train
+crysdcscnb 1 300 train
+crytsyqpyl 1 300 train
+cryvfnpiau 1 300 val
+cryxhnrndp 1 300 train
+cryywaxnpt 0 300 train
+crzcbhurrh 1 300 train
+crzfebnfgb 1 300 train
+crzrsezocr 1 301 train
+crzvmqszan 0 300 train
+crzzbqlhfj 1 301 train
+crzzzxzvtw 1 300 train
+csaatbqsnp 1 300 train
+csadfusqab 1 300 val
+csadypzubx 1 297 val
+csafktzcrs 1 301 val
+csagttjlqt 0 300 train
+csahmhbavq 1 300 val
+csailoihev 1 301 train
+csakctnwak 1 300 train
+csaozhathc 1 300 val
+csauiuajcs 0 300 val
+csbbphqcev 1 300 train
+csbdcisqnu 1 300 train
+csbhsossva 1 300 train
+csbmiqaidp 1 300 val
+csbrqfiyvu 1 300 train
+csbxhupmhx 1 297 val
+csbyorodad 1 300 train
+csbzqhunqw 0 300 train
+cscdlfidfj 1 300 train
+cscflgmxlj 1 300 train
+csclnicuyn 1 300 train
+cscqiumunp 1 300 val
+cscwdukujx 1 300 train
+cscxobonmr 1 300 train
+csdbdvxyhl 1 300 train
+csdcnwbwiu 1 300 train
+csdikrzaqt 1 300 train
+csdjsonmcd 1 299 train
+csdkogcust 1 302 train
+csdlxtagim 0 300 train
+csdnzizgfn 0 300 val
+csdqvhefzs 1 298 train
+csdrnqjwev 0 300 train
+csdrwieihk 1 300 train
+csdxalpqcl 1 300 train
+csdzjehwbf 1 300 train
+csecveltnm 0 300 train
+csefroivib 1 300 val
+cseqwtcwdl 1 300 train
+cseriybaqt 1 300 train
+csetzcnezn 1 301 train
+csfakyszws 1 300 val
+csfixqpjhw 1 300 val
+csflmeggme 0 300 train
+csflwluoeb 1 300 test
+csfoaeqqdu 0 300 train
+csfpwkztlf 1 241 train
+csfrcupvbf 1 300 train
+csfsskknsh 1 300 train
+csfssvnwsp 1 300 train
+csfwgdpzym 0 300 train
+csfwrgnbwo 1 300 val
+csgcwyaazy 1 300 train
+csglxknfgx 1 301 val
+csgnemklmq 1 300 train
+csgouotlcg 1 301 val
+csgshstnuy 1 300 train
+csguabnacy 0 300 train
+cshdgzvfpe 1 299 train
+cshhakbofs 0 300 val
+cshjgwysrw 1 300 val
+cshlbvfpzi 1 300 test
+cshovthaal 1 300 train
+cshpzaoovu 1 300 val
+cshxowxrfl 1 300 train
+csikbraapk 1 300 train
+csikkbsnia 1 300 val
+csjaggwdtq 1 300 train
+csjcuzkwey 1 300 train
+csjeiievqq 1 300 train
+csjlqqwkpc 1 301 val
+csjpfrogyp 0 300 val
+csjxenszpy 1 300 train
+csjzskxwyx 1 300 train
+cskhcvqucf 1 301 train
+cskmvswfov 1 300 train
+cskoqodepp 1 300 train
+cskoyeyxmy 1 299 train
+cskupggovl 1 300 train
+cslceaskvo 1 300 train
+cslfapvyjv 0 300 train
+cslmdbmlzk 0 300 train
+cslsbufmpu 1 300 val
+cslsqptoiw 1 300 train
+csluwepgfa 0 300 train
+csmdwlcoir 1 300 train
+csmezlywcs 0 300 train
+csmiexvtfh 1 300 train
+csmpwjogik 0 300 train
+csmrqvgsrk 1 300 train
+csmsrngjrm 1 300 train
+csmvoigpmo 1 300 val
+csmzzyvsbc 1 300 val
+csnbiwlwuz 1 300 train
+csncdloguh 0 300 train
+csndqogsku 1 300 train
+csnkohqxdv 1 300 test
+csnzuyltso 1 241 train
+csnzwhunir 1 300 train
+csofafwrts 1 300 val
+csollwjhrx 1 300 train
+csomiogcwu 0 300 val
+csonnyogpm 1 241 train
+csoqeobiql 1 300 train
+csoxekulpu 1 301 train
+csozifgqcx 1 300 train
+csozphfidv 1 300 train
+cspadzkkxy 1 300 train
+cspbxdvhzz 1 300 train
+cspgdomapy 1 300 val
+cspghufxlx 1 146 train
+csplgefkgx 0 300 train
+cspnpyohxu 1 300 train
+cspsgyxwqt 1 300 val
+cspsmrguki 1 300 val
+csptavjdwb 1 301 train
+csptvrxfap 1 300 train
+cspxwzuccg 1 300 val
+csqbebvoxt 0 300 train
+csqlmewefk 0 300 train
+csqlvstupt 0 300 train
+csqojsqtgn 1 300 test
+csqsdmrctj 0 300 val
+csqsxsjrnp 1 300 train
+csqtrlumkz 1 270 train
+csqxvlpvcs 1 298 train
+csrabfvevi 1 301 train
+csraeqynwd 1 300 train
+csremuoyna 1 300 train
+csribdbvgz 1 300 val
+csrmrbugag 1 300 train
+csroceqkkd 1 300 val
+csrqbscgxz 1 269 train
+csrqlmzjph 1 300 train
+csrqsdfkjt 0 300 train
+csrsxklgle 1 300 train
+csrtdeeouw 1 300 train
+csrwkiwgyk 1 298 train
+csrymqydbk 1 300 train
+csrytcnozp 1 299 val
+csrzijbfda 1 300 train
+cssoselqjy 1 300 val
+csspmkdmmt 1 300 val
+csspxfqcqn 1 301 val
+cssuukpkgx 1 301 train
+csswoyakjk 0 300 train
+cstenlkbwi 1 301 val
+cstfqsxyhp 1 300 val
+cstkcclhdc 1 300 train
+cstotimkgj 1 249 train
+cstxbaiqez 1 300 train
+cstzexdcbw 1 300 train
+csuaztyjjt 1 300 train
+csuovrlqzc 1 300 train
+csuwuruutx 1 302 train
+csvfaepgno 1 298 val
+csvflnmkvh 1 300 train
+csvggiwfey 1 300 train
+csvhhhydcr 1 300 train
+csvqixkrdb 1 300 val
+csvrqzkixi 1 300 train
+csvsolnwge 1 300 train
+csvxxjkbzk 1 300 train
+cswajdmqyx 1 300 train
+cswdtvtgji 1 300 train
+cswhwudpzk 0 300 train
+cswrbxyikk 1 300 train
+cswvrrtrfi 1 300 train
+csxboewxgs 1 300 val
+csxdicxppc 1 300 train
+csxdoljtqj 1 300 val
+csximsmssp 1 301 train
+csxjcoesqt 1 300 train
+csxjoirhtw 1 300 train
+csxksuzkhm 1 300 train
+csxlsassml 1 300 train
+csxtydbgui 1 300 val
+csxvxmydax 1 301 train
+csxymovdqx 1 300 train
+csykmzdltv 1 300 train
+csyltbzcrg 1 300 train
+csymemdxjs 1 300 train
+csyomqphqw 1 298 val
+csyqjauqfy 1 269 train
+csysmpozdj 1 300 train
+csyxkdhsbx 1 300 val
+cszbrjxedc 1 300 val
+cszbvpyxnr 1 300 train
+cszdcuibjt 1 300 train
+cszljdkkka 0 143 train
+cszqqaesif 0 300 train
+cszvjqvmed 1 300 train
+cszwqsnohf 1 300 train
+ctadkykzlw 1 301 val
+ctapiptgpv 1 300 val
+ctarrlrgdy 1 300 train
+ctauriijrf 0 300 val
+ctavqrrmgv 1 300 val
+ctawiyhhzf 0 300 train
+ctbbtipivz 1 300 train
+ctbfeowfgb 1 300 train
+ctbkqbmiqi 1 300 train
+ctbonxvats 0 300 train
+ctbvbustlx 0 300 val
+ctbvhwpvhy 1 300 train
+ctbyrzowrp 0 300 train
+ctbzbowgqc 0 300 train
+ctcbdczxpy 1 300 train
+ctcchuseai 0 300 train
+ctccuizjur 1 300 val
+ctcemwjmix 1 300 train
+ctcgtaikxd 0 300 train
+ctchthbojs 1 300 val
+ctchulwwxm 1 300 train
+ctckdmusun 1 298 train
+ctclbnlclm 0 300 train
+ctcozenfll 0 300 val
+ctcrsbudxa 1 300 train
+ctcyblximu 1 300 train
+ctcyppxshb 1 300 val
+ctdacastkt 1 300 train
+ctdcinkmey 1 300 train
+ctdetnpcny 1 300 train
+ctdwkvfsmp 1 300 train
+ctdwtfcjei 0 300 train
+ctdzrkqorp 1 300 train
+cteeuqbldm 1 300 train
+cteglwofrc 1 300 train
+cteolgekjy 1 300 val
+cteqcijtgc 1 300 train
+cteqlloxwu 0 300 train
+cteungyauw 1 300 train
+ctexjdufex 1 300 train
+ctexslclai 1 300 train
+cteyfbetls 1 300 train
+ctfbubbycb 1 300 val
+ctfegjuydq 1 300 train
+ctfjmtuzcl 1 298 val
+ctfkxfffzx 1 301 train
+ctfmwebpxh 0 300 val
+ctfvpczuea 0 300 train
+ctfvpxcjzi 1 301 train
+ctgembpbzd 1 300 train
+ctgemvhxvs 1 301 val
+ctgjxphbeq 1 301 val
+ctgkfkxzxl 1 300 train
+ctgmrsprck 1 300 val
+ctgradkbzn 1 300 train
+cthdnahrkh 1 300 train
+cthdrbnhpo 1 300 test
+cthhppkbgd 1 300 val
+cthyolvdif 0 300 train
+ctibxwjesk 0 300 val
+ctidqluhtj 1 300 train
+ctijnwbuck 1 300 train
+ctikqrsitj 1 300 train
+ctiotdxchs 1 300 train
+ctiqjvitci 1 300 train
+ctiwcrperj 1 241 train
+ctixivmvsr 1 300 train
+ctiyalwbsv 1 300 train
+ctjcgwtgwk 0 300 train
+ctjcicttwr 1 300 train
+ctjepwqiul 1 300 train
+ctjewcqxee 1 300 train
+ctjfbgkfxs 0 300 val
+ctjgedzulo 1 300 train
+ctjgmxfaxe 1 241 train
+ctjhewezxh 1 297 train
+ctjmpefwnx 1 300 train
+ctjotjkeci 1 300 train
+ctjqfwivhb 1 300 train
+ctjuwaprck 1 300 train
+ctkopczrhm 1 300 train
+ctkqqyvgtc 1 300 train
+ctkwuprdsl 0 300 train
+ctkxnmuukh 1 300 train
+ctljczbeej 1 300 train
+ctljtcfgqs 1 300 train
+ctlmkrjmut 1 300 val
+ctlpvgkloc 1 298 val
+ctlqptsltq 0 300 train
+ctlwouvozz 1 300 train
+ctmaffxlnx 0 300 train
+ctmepjcdge 1 300 train
+ctmjenhkqg 1 300 train
+ctmjywsvkj 1 300 train
+ctmqwwpdnc 1 300 train
+ctmwfvnugu 1 300 val
+ctmzprtrhs 1 300 train
+ctnbxsceln 1 300 val
+ctnneaxztc 0 300 train
+ctnubxcpbn 0 297 train
+ctnupbsabf 1 300 train
+ctnyuikpfa 1 300 train
+ctoeplyxsc 1 300 train
+ctojcitnpn 0 300 train
+ctojzygjwi 1 300 val
+ctonskhkea 1 300 train
+ctooqkhtgp 1 300 val
+ctopurgfgx 1 300 val
+ctouemisne 1 300 train
+ctowvrmazl 1 300 train
+ctozwusfxb 1 300 train
+ctpaahkfdc 1 300 train
+ctpexqamtx 1 300 val
+ctpmigxzom 0 300 train
+ctppzltiid 1 301 val
+ctpqeykqdp 1 300 train
+ctpxuueebz 1 300 train
+ctpypmzfnl 0 301 train
+ctpzxfjbmt 1 300 train
+ctqfuwijvm 1 300 train
+ctqhjlnwxl 1 300 train
+ctqjnsvrvk 1 300 train
+ctqmijtxxy 1 300 val
+ctqmvgzvfa 1 299 val
+ctrengqlqk 1 300 train
+ctrmymuzvr 1 300 train
+ctrodwqvjx 1 300 train
+ctrrdpagov 0 300 train
+ctryulifmt 0 300 train
+ctrzahihvb 1 300 train
+ctsahczkhr 1 299 test
+ctsdittcdz 1 300 train
+ctsdqbskzi 1 300 val
+ctsjalmkpx 1 300 train
+ctsoiluvvz 1 300 train
+ctsuyxoevp 1 300 train
+ctsxxraruc 1 300 test
+ctsykmidnc 1 300 train
+cttbevkbhr 1 300 train
+cttbiujgiv 1 300 train
+cttgsafhrw 1 296 train
+cttodcvhiy 1 300 train
+cttqtsjvgn 1 300 train
+cttzqgsyct 1 300 val
+ctubflixxv 0 300 train
+ctugqnflud 1 301 val
+ctuiwtvhui 0 300 train
+ctulbaeifx 1 300 val
+ctulsxsjwx 1 300 test
+ctusyabydj 0 300 train
+ctuucnrbna 0 300 train
+ctvczyezqe 1 301 val
+ctvgzogjqz 1 241 train
+ctvjqagwnz 1 300 train
+ctvnkjdxoz 1 301 train
+ctvpfuwanq 1 301 train
+ctvquiqqnz 1 300 train
+ctvqzjxefr 1 300 train
+ctvrdvsvlm 1 300 train
+ctwbitwsih 1 301 train
+ctweyxhekp 1 298 train
+ctwljxvbdp 1 300 train
+ctwqyniuuk 1 300 test
+ctwvhdkmkx 1 241 train
+ctwvwcnfeb 1 300 train
+ctwvxixozj 1 300 train
+ctwyfomddo 1 300 test
+ctwygmbzpa 1 300 train
+ctwzaiyrgx 1 300 train
+ctxhjpebsl 1 300 train
+ctxixjuldj 1 300 train
+ctxiytgmay 1 300 train
+ctxlrubjof 1 298 train
+ctxngpxdth 1 300 train
+ctyczggqkf 1 300 train
+ctyhaquawh 1 300 train
+ctykzejpnp 1 300 train
+ctymspciqq 1 300 train
+ctypbqmehx 1 300 train
+ctzanofqzd 1 300 train
+ctzbyjteri 1 302 train
+ctzextgily 1 300 train
+ctzgjaqrpl 1 301 train
+ctzgudcdyu 1 300 test
+ctzhkqmynl 1 300 val
+ctzidpuxqo 1 300 train
+ctzknhuffj 0 300 train
+ctzmavwror 1 300 train
+ctzvhowbhr 1 300 train
+ctzxbwwnlu 1 300 val
+ctzzytwvpi 1 300 train
+cuabanvwfg 1 300 train
+cuafoggwku 0 301 train
+cuajkvkgch 1 300 train
+cualykjhoa 1 300 val
+cuaqzwwuzw 1 241 train
+cuarybjtqu 1 300 val
+cuasffmqqt 1 300 train
+cuattwrevd 1 300 train
+cubbwhqsio 1 300 train
+cubcugxjks 1 300 train
+cubernsric 1 300 train
+cubidebbwb 1 300 train
+cubiijddyv 1 300 val
+cubovymgid 1 300 train
+cubpzovrle 1 300 train
+cubudyesmd 1 300 train
+cubuvjbojg 1 300 train
+cubwixjevd 1 300 test
+cubyoldoos 1 300 train
+cucaawfemy 1 300 train
+cucnhxbrrz 0 300 train
+cucoscmpjy 1 300 train
+cucungdfoq 0 300 val
+cudbbhoegh 1 300 val
+cudelemkpw 1 300 val
+cudjeshfcw 1 300 val
+cudqwytasr 1 300 train
+cuecowubeb 0 300 train
+cueivytkwb 1 300 train
+cueoszcxam 1 300 train
+cueoweauma 1 300 train
+cuerkhzuum 1 301 val
+cuewtjauyi 1 300 train
+cuexiuoenr 1 301 train
+cuexwqperb 1 298 train
+cufgfduips 1 300 train
+cufipbigrt 0 301 train
+cufjeqvuga 1 300 val
+cufkgegbum 1 300 train
+cufoyytpgj 1 292 train
+cufpjxwbjt 1 300 train
+cufrprkuzl 1 300 train
+cufsbvfjen 1 300 train
+cufwpbfhwc 1 300 train
+cufxqiuwrd 1 300 train
+cufzoprzgd 1 288 train
+cugbtwdurl 1 300 train
+cugflmdnrp 1 296 train
+cugifqjqto 0 300 train
+cugqzibkas 1 300 test
+cugtrhruer 0 300 train
+cugumlyhiu 0 300 val
+cugvaxsbsv 1 299 train
+cuhbaquctx 1 300 val
+cuhbygmfxd 1 299 val
+cuhbynkdzu 0 300 train
+cuhkutstac 1 300 train
+cuhrutgvft 1 300 train
+cuhsftbffu 1 300 val
+cuhzbsemgs 1 249 train
+cuiaboltvn 1 300 val
+cuibixkynh 1 300 train
+cuinqgwczx 1 300 train
+cuixxqmpmy 0 300 val
+cujdbikros 1 300 val
+cujjqochhs 1 300 train
+cujqbmziws 1 301 train
+cujsfckgxq 1 300 val
+cujtepcume 1 300 train
+cujuflgqqa 1 300 val
+cukadnrzpo 1 241 train
+cukbbewtmd 1 301 train
+cukbenxlgc 1 300 train
+cukbwjepmi 0 300 val
+cukedccddh 1 300 train
+cukgevrxhx 1 300 train
+cukkuyqxpq 0 300 train
+cukqowdaey 1 300 train
+cukwoecmmq 1 300 train
+cukyihsryf 1 300 train
+cukylghuco 1 300 train
+culaevxduf 1 300 test
+culbrdouta 1 301 train
+culhdxfqgd 1 301 val
+culqnykaue 1 300 train
+cumgkxsjgz 1 300 train
+cumhonvwlg 1 300 train
+cummgzdxft 1 300 train
+cumrfsvpri 0 300 train
+cumumecvxk 1 300 test
+cumwizfkcg 1 300 train
+cumwqtxgvl 1 241 train
+cumyymgndh 1 300 train
+cumzpeesnp 0 300 train
+cunannjawe 1 300 train
+cunaxhiert 0 300 train
+cundwodhjt 1 300 train
+cungjkdvaz 1 300 train
+cunjrhvdbq 1 300 train
+cunobtbzwj 0 300 train
+cunzjagprk 1 300 val
+cuobzceakk 1 300 train
+cuodohfdmi 1 300 train
+cuohqkgmse 1 300 train
+cuokygelal 1 300 val
+cuoqvtqick 1 301 val
+cuovokblws 1 300 train
+cuovwgibgk 1 300 train
+cuphoipnua 0 300 train
+cuphpxqdmp 1 298 train
+cupjhxmqsy 1 298 train
+cupmtmedsc 1 300 val
+cupqbscadr 1 300 train
+cupryrokhg 1 300 val
+cupujkcxwr 1 300 train
+cuqlpntsgm 1 300 val
+cuqmhymyxk 0 299 train
+cuqpcymavt 0 300 train
+cuqqeghuun 1 300 train
+cuqqpbqwhk 1 301 train
+curiduxvja 0 300 train
+curoyzlzbr 1 300 val
+curpwogllm 1 300 train
+curyxptmtx 1 300 train
+cusdxxdwmg 1 300 train
+cuseazykjy 0 300 train
+cusgxexhdx 0 300 train
+cushsityvj 1 288 train
+cusjldwbcr 1 300 train
+cuslsmkwpx 1 300 train
+cusnretedj 1 300 val
+cuswxeekym 0 300 train
+cutabgeoaf 1 300 val
+cutdjzeeip 1 300 train
+cutfpzdonm 1 299 test
+cutlbamnpn 1 300 val
+cuudfoogee 1 300 val
+cuuqwcxelc 1 300 train
+cuurkqqikr 1 300 val
+cuurmzcffe 1 300 train
+cuursqkpxc 1 297 train
+cuuspjotwf 1 300 train
+cuuuohldur 1 300 train
+cuuvswxxek 1 301 train
+cuuxqetxmb 0 299 train
+cuuyarnbhw 1 300 train
+cuvcxavplw 1 299 val
+cuvcxsqpjy 1 298 train
+cuvihcqjej 1 300 train
+cuvqifjkse 1 301 val
+cuvqoorsek 1 300 val
+cuvrlyyniy 1 300 train
+cuvxaostpt 0 300 train
+cuwdlchgat 1 300 train
+cuwfpfcjxu 1 300 train
+cuwkygiyim 0 301 train
+cuwnhkgiyb 1 300 val
+cuwoemoaai 1 241 train
+cuxaxdgtkr 1 300 train
+cuxfcbvaeu 1 298 train
+cuxhekncql 1 300 train
+cuxlufcotk 1 300 train
+cuxqfnwzus 1 300 train
+cuxzeadqfe 1 299 test
+cuycsnvhfq 1 300 train
+cuydmmzcuw 1 240 train
+cuyffriuzk 1 300 train
+cuyigebxzv 1 300 train
+cuyjleqjxg 1 300 train
+cuymgblwvu 0 300 train
+cuypznsdlz 1 300 train
+cuzahyamgn 0 300 train
+cuzbvoqeff 1 300 train
+cuzhfhjkjr 1 300 train
+cuzjbltmkl 1 300 train
+cuzrgrbvil 1 300 train
+cvaaaorptd 0 300 val
+cvaeexwlkk 1 300 train
+cvaivlbscu 1 298 train
+cvaksbpssm 1 300 train
+cvalhpwzbz 0 300 train
+cvallwyhed 1 300 train
+cvbckybaaq 1 300 test
+cvbdvzttpx 1 300 val
+cvbebdokcr 1 300 train
+cvbjxpwoie 1 300 train
+cvboojbsxa 1 300 test
+cvbubcwkkl 0 300 train
+cvbwemuxtq 1 300 train
+cvcgyphqfh 1 297 train
+cvcopelvcd 1 300 train
+cvcsmrjjbi 1 300 train
+cvcznehtwl 1 300 train
+cvdbiprhhl 1 298 train
+cvdggytjdh 1 302 train
+cvdjdgynzg 1 300 val
+cvdpjordgi 1 300 train
+cvdqhdcfde 1 300 val
+cvdrqqbwdl 1 300 train
+cvdrzlkwdf 1 300 test
+cvdswtxdem 1 300 train
+cvdyksxctx 1 300 val
+cveehypkla 1 300 val
+cvenjrgnrr 1 300 train
+cvepfgpobe 1 300 train
+cvepliorgw 1 300 val
+cveqgferbf 0 300 train
+cvesotrbwj 1 300 train
+cvfbxmteyv 1 300 train
+cvfinyvmrn 1 300 val
+cvgadcyxnu 1 300 train
+cvgakfkxig 1 300 val
+cvgbmvjnds 1 300 train
+cvgfzoyatn 1 301 train
+cvgiosreoa 1 300 val
+cvgmejzwsz 1 300 train
+cvhgdhteev 1 300 val
+cvhgoabtml 1 300 train
+cvhjvlbdda 0 300 train
+cvhmdigame 1 300 train
+cvhzgkoclh 1 300 train
+cvibusznso 0 300 val
+cvickaqyxn 1 300 train
+cvicohmags 0 300 train
+cviefnfhrl 1 300 train
+cviikqvflj 1 300 val
+cvikqxzwck 1 298 train
+cvinbbepzq 1 300 train
+cvinvujvdy 1 300 train
+cvisuksqzu 1 300 train
+cvixicyuon 1 300 train
+cviyjsusie 1 300 train
+cvjcxhzjqq 1 300 train
+cvjdlmbhls 1 300 train
+cvjtaxyhed 1 301 train
+cvkazpvuyc 1 300 train
+cvkgwufxld 1 300 train
+cvkrbnidon 1 300 train
+cvkszgigiy 1 300 val
+cvkwgcizxe 0 300 train
+cvkwhmnpzq 1 300 train
+cvlcfsokzv 0 300 train
+cvldzfmhga 1 300 val
+cvlfhscumw 1 146 train
+cvlmosigys 1 300 train
+cvlvajbjqp 1 300 train
+cvlwabuioe 1 300 train
+cvmcvcqpgn 1 300 test
+cvmdiubnln 1 300 train
+cvmerrznwg 1 300 train
+cvmlvxkrau 1 300 train
+cvmmtklgst 1 300 train
+cvmnkyhzki 1 300 train
+cvmofrwdcz 0 300 train
+cvnfjpkgyi 1 299 test
+cvnkbrpjuo 1 301 train
+cvnnqebwcz 1 300 val
+cvnusiwohr 1 300 train
+cvnvkjcftg 1 300 train
+cvnvsbejdk 1 300 train
+cvoewuchtt 1 300 val
+cvoikrdglc 1 300 train
+cvooazmfdb 1 298 train
+cvortzphbc 1 300 train
+cvorwgcpua 1 300 train
+cvotzhernt 0 300 train
+cvousgnasq 1 300 val
+cvovxjmzsl 1 300 train
+cvoxjflaxg 0 300 train
+cvpacvtoyc 1 300 train
+cvpdwkpfse 0 241 train
+cvpiuunjwy 1 300 train
+cvpqdmxddu 1 300 train
+cvpughwdeq 1 300 train
+cvpytkuqyd 1 300 train
+cvqbppiabu 1 300 train
+cvqgcudntd 1 301 train
+cvqgrezhur 1 300 train
+cvqljfkotv 1 301 train
+cvqlmslhdv 1 300 test
+cvqrchlzhm 1 300 train
+cvqyddpcxj 1 300 test
+cvrfrostae 1 300 train
+cvrkocprnk 1 299 test
+cvrmozrlwk 1 300 train
+cvrnjfmzup 1 300 train
+cvrnlbvpge 1 300 train
+cvrtjvwvqg 1 300 val
+cvrzdywcth 1 300 train
+cvsftmwnnh 1 300 train
+cvsgadpvbl 1 300 val
+cvshiqpncn 1 296 train
+cvsobewhsk 1 300 train
+cvsvyuueoh 1 300 train
+cvtaccskvb 1 299 val
+cvtklxtdrd 1 300 train
+cvtkpllefe 1 300 val
+cvtnowxgtq 1 300 train
+cvtogeuiqd 1 300 train
+cvtqumcpbk 1 300 train
+cvtwlzgzne 0 300 train
+cvtzzjrlfa 1 300 train
+cvudcnjhvn 1 300 train
+cvuiocbcbz 0 300 val
+cvupsfszqb 1 301 val
+cvvabkmusu 1 300 train
+cvvllhnbhj 1 301 train
+cvvmoaolqa 1 300 train
+cvvnebbktm 1 300 train
+cvvsqajlmx 1 300 train
+cvvtpdnajw 1 300 train
+cvvwitgutr 1 241 train
+cvvwrjubjv 1 300 train
+cvwbvedicl 1 300 train
+cvwfocfmpb 1 300 train
+cvwfrzxcai 1 300 train
+cvwiidwcnq 1 301 val
+cvwqofmaef 0 300 train
+cvxgpdelgy 1 236 train
+cvxnllaicc 1 300 train
+cvxphzedsu 1 300 train
+cvxuswbzmq 1 300 train
+cvxyomzrnm 1 301 train
+cvycgtwfsi 1 300 test
+cvyenririk 0 300 train
+cvyeznxkct 1 300 train
+cvyrfhetrx 1 300 train
+cvysaafunu 1 301 train
+cvywcvnytv 1 300 train
+cvzjglautx 1 298 train
+cvzlyfuumu 1 301 train
+cvznehgagq 0 300 val
+cvznwxifib 0 300 val
+cvzsiudpyx 1 300 train
+cvzvadwoje 1 300 train
+cvzybqmrvo 1 300 val
+cwaayxldci 0 300 train
+cwalqxbyff 1 300 train
+cwaoshhenk 0 301 train
+cwasnpqxck 1 300 train
+cwayeqkjto 1 298 val
+cwbacdwrzo 1 300 train
+cwbaihpjtx 1 299 train
+cwbgztanym 0 300 train
+cwbincavby 1 300 train
+cwbiwilgdb 1 300 val
+cwbloesipb 1 300 train
+cwbphcwonh 1 300 train
+cwbsotburz 1 300 val
+cwbubjzysv 0 300 train
+cwbwhsjrbz 1 301 train
+cwbzorvwcl 1 300 val
+cwcbnewdpg 1 300 train
+cwccvrqqzt 1 300 train
+cwcdlmovnm 1 300 train
+cwchwtkjze 0 300 train
+cwcqigdglq 1 300 train
+cwcspgnrzc 1 294 train
+cwcvkwidcc 0 300 val
+cwcwgibsgo 0 300 val
+cwczkeupnm 1 301 train
+cwdkfjctcp 1 241 train
+cwdtfxgvnt 1 240 train
+cwdvlhursc 0 300 train
+cwdzbjmsrj 1 300 val
+cwdzddbqyi 1 136 train
+cwebumhuqk 1 300 val
+cwekeyycuh 1 301 train
+cwenrpnned 1 300 train
+cweqsnfrui 1 298 train
+cwetvtzeyf 1 300 test
+cwfkstvwpn 1 298 train
+cwfzfanecy 1 300 train
+cwgaspxoqu 1 300 val
+cwgibuqvwm 1 300 train
+cwgnnijunv 1 300 train
+cwgymbeyiw 1 298 train
+cwgzvqsagc 1 299 train
+cwhcdcleaz 1 300 train
+cwhgkieoho 1 300 train
+cwhibklyle 1 300 val
+cwhitukhlh 1 300 train
+cwhlbndlvw 1 300 train
+cwhmodncwy 1 300 train
+cwhocpcoqq 1 300 train
+cwhoszpfek 1 300 test
+cwhowibuxc 1 300 val
+cwhoxcazbc 1 300 train
+cwhratjytu 1 301 train
+cwhrrvgeku 1 300 train
+cwhvshlzzh 1 300 val
+cwimepqnxq 1 300 train
+cwinesfmug 1 300 train
+cwiomypnvs 1 146 train
+cwirfjdlvs 0 300 train
+cwivuugapq 1 300 val
+cwixfnvhmn 1 300 train
+cwjcakwokd 1 300 train
+cwjgcmytqc 1 300 train
+cwjguxtovt 0 300 train
+cwjkdlzrvb 1 299 test
+cwjmbddibt 0 300 train
+cwjovizmhq 1 300 val
+cwjqtcdmoe 1 136 train
+cwjtawpefj 1 300 test
+cwjvrpudbb 1 300 train
+cwjxpgbggq 1 300 train
+cwkbonbiec 0 300 val
+cwkdtzgdil 1 300 val
+cwkiapvkwg 1 300 val
+cwkiiyezzg 1 300 train
+cwklpmzxtx 1 300 val
+cwksfhbpcg 1 300 train
+cwktquxciy 1 300 train
+cwkugnjqzg 1 300 train
+cwlbyjitfv 1 300 val
+cwldadomaz 1 241 train
+cwlkfmhlox 1 300 train
+cwlkguuphy 1 300 train
+cwlkqoxzee 1 300 train
+cwlqpuwuoj 1 300 train
+cwltsdyued 1 300 train
+cwlvjyebuo 1 300 val
+cwlwyjtxnc 1 241 train
+cwlxxhemsd 1 300 train
+cwmahupvmg 1 300 val
+cwmidyiqvl 1 300 train
+cwmistjkvh 1 298 train
+cwmjhyvfcv 1 300 train
+cwmqvgihtt 0 300 val
+cwmrhkeqsm 1 300 train
+cwmudgctnj 1 301 val
+cwmwbryhqx 1 300 train
+cwnagpgres 1 300 val
+cwnctviabv 1 298 train
+cwnfjafmch 1 300 train
+cwnnhwqhpu 1 300 train
+cwnnmxatsd 1 300 train
+cwnqtcmnqv 1 300 train
+cwnqyfuggv 1 300 train
+cwnryzcrjc 1 298 train
+cwogqcalwa 1 300 val
+cwoiryhauz 1 300 train
+cwoizcysto 1 300 train
+cwojtdtcux 1 300 train
+cwonpsyuuz 1 301 train
+cwooqusgus 0 300 train
+cwosvnnasn 1 300 test
+cwouamlqii 1 300 train
+cwovrcucqo 0 300 val
+cwowctozwu 1 298 train
+cwpderbche 1 300 val
+cwpfmgwxlp 1 300 train
+cwpvwlflwa 1 301 val
+cwqadggicq 1 300 train
+cwqauxqvfw 1 298 val
+cwqdzlcbed 0 300 train
+cwqexpwysg 1 300 val
+cwqhzuhjol 0 300 val
+cwqiiminqn 1 300 train
+cwqislqtti 1 300 train
+cwqkrogbtu 1 300 val
+cwqlvzefpg 1 300 train
+cwqrtetesu 1 300 train
+cwqwhvjaul 1 300 train
+cwqycdjevy 1 300 test
+cwrjhzvshd 1 300 train
+cwrmgbzjeu 1 288 train
+cwrnhrrace 1 300 train
+cwroxejnus 0 300 train
+cwrphgbftq 0 300 train
+cwrqxcvglq 1 300 train
+cwrrixbeqb 1 300 train
+cwrtiydlln 1 300 train
+cwrtvtyanu 1 300 train
+cwrtwrjdpa 1 300 train
+cwrtyzndpx 1 300 train
+cwruaywtvb 0 301 train
+cwryohvdpy 1 300 train
+cwsbspfzck 1 300 train
+cwsdeasldr 1 300 train
+cwsdjdhwoz 1 300 train
+cwsgfhdizj 1 300 train
+cwsjhkiaml 1 300 val
+cwsktcqrzf 0 300 val
+cwspfeiklq 1 298 train
+cwsrozctrk 1 300 train
+cwstdobzfg 1 301 train
+cwswucjieo 1 300 val
+cwszhupzre 1 300 train
+cwtgddlhby 0 300 train
+cwthksdnco 0 300 train
+cwtmswdzww 1 300 train
+cwtnlfwhbz 1 298 val
+cwtntnrylj 1 300 train
+cwtqzovbba 1 300 train
+cwtsuxyhea 1 300 train
+cwtulyzetd 1 300 val
+cwtxqxuvlc 1 300 train
+cwtzbmfpeu 1 300 train
+cwuacihcap 1 300 val
+cwulcnedat 1 300 val
+cwuoawokkl 0 300 train
+cwupoiihky 1 300 train
+cwuuhvqzis 0 300 val
+cwuukeotgn 1 300 train
+cwvhqngngm 1 300 train
+cwvpcctjgs 1 300 test
+cwvpjumhbg 1 300 train
+cwvtgzizxw 1 300 train
+cwvvrbcchf 1 300 train
+cwwandrkus 1 300 train
+cwwcdndhmr 1 299 val
+cwwgsnejua 1 300 train
+cwwnlfahfx 1 300 train
+cwwqaazswi 1 300 train
+cwwsiywfnu 1 300 train
+cwwtxcfwmp 1 300 train
+cwxgqkgvoy 1 300 train
+cwxjlssagj 1 300 test
+cwxlgfvtdq 1 300 train
+cwxrlwltie 0 300 train
+cwxtpmonhy 1 300 train
+cwyanmlhdx 1 300 train
+cwydjcuxap 1 300 val
+cwyefuyzhg 1 300 train
+cwykfzwimc 1 299 test
+cwyslgvsmr 1 300 train
+cwywmteqst 0 300 train
+cwzdoxtpms 1 241 train
+cwzepohbwu 0 300 train
+cwzfrnoskg 1 300 train
+cwzgdnkite 1 300 train
+cwzpgqpfum 0 300 train
+cwzsutjiqz 1 300 train
+cwzwtiocml 0 300 train
+cwzykvwllv 1 300 val
+cwzyzxjmfh 1 300 train
+cwzzqzmblh 1 300 train
+cxacbzdokf 0 300 train
+cxajnkqjkq 0 300 val
+cxajobdgrv 1 300 train
+cxatnnpeyo 1 300 train
+cxauncwtkj 1 300 val
+cxawfgajcs 1 300 train
+cxazqtfzta 0 300 train
+cxbimcvejo 1 301 train
+cxbnpcvoqt 1 300 train
+cxbsalbmst 1 300 train
+cxbsdhpnxa 1 298 train
+cxbuowwwsr 1 299 val
+cxccagkrpt 1 299 test
+cxccizaied 1 300 train
+cxceihvdhv 0 300 train
+cxcesxkunc 1 300 train
+cxciisvynh 0 300 train
+cxcksiutzl 1 297 train
+cxcopmaqcx 1 300 train
+cxcqexahml 0 300 val
+cxcsostsxq 0 300 train
+cxcvzcsrqf 1 300 train
+cxcwnazxzm 1 300 train
+cxdibrhrwz 1 300 val
+cxdlxvgysz 1 300 train
+cxdynolmbt 1 301 val
+cxdzqfuaox 1 300 val
+cxeifiayyp 0 300 train
+cxenptrtzm 1 300 test
+cxeopypcfd 1 300 train
+cxepagsvia 1 300 train
+cxepyrdckc 1 300 val
+cxeuodcmqd 0 125 train
+cxevdilqjh 1 300 train
+cxeyiytudt 1 300 train
+cxeziknbpr 1 300 train
+cxfbhgmuyu 0 300 train
+cxfdvfuchw 1 300 train
+cxffcxlroh 0 300 train
+cxfoxdvbpk 1 300 train
+cxfujlvsuw 1 300 train
+cxfwyfjrfn 1 300 val
+cxfyrqbrji 1 300 train
+cxgaacxbmp 1 300 train
+cxgdlbmeqy 1 300 train
+cxgdmvuxjc 1 300 val
+cxgieqcozm 1 300 test
+cxgjbrhcha 1 301 val
+cxgrlduslk 1 300 train
+cxgsjamupo 1 300 test
+cxguvyaque 0 300 train
+cxgxkxbaby 1 297 train
+cxgzkuvkas 0 300 train
+cxhcdctspt 1 300 train
+cxhdtpciaj 1 300 train
+cxheontgxv 1 300 train
+cxhjjxergt 0 300 val
+cxhmbvwqxm 1 300 train
+cxhwxwlkvz 1 300 train
+cxhymkbrxw 1 300 train
+cxieibifyj 1 300 train
+cxiephiblg 1 300 train
+cxieujkazw 1 300 train
+cxigoqsdoo 1 300 val
+cxiitnbzie 1 299 test
+cxilsssnoj 1 301 train
+cxinyndrfj 1 300 train
+cxippkanpn 1 300 train
+cxiurodzsg 1 300 train
+cxjiyyhcvg 1 300 train
+cxjpzucdse 1 300 train
+cxjsxgirny 1 300 train
+cxjtjcinqt 1 300 test
+cxjumzfmqd 0 300 train
+cxjwmxsgjv 1 300 train
+cxksaamntc 1 300 train
+cxkvryrnso 0 300 train
+cxkymqpwuq 1 300 train
+cxlkfsyfvb 0 300 train
+cxlpvfoxdt 1 300 val
+cxmqothqql 1 300 train
+cxmriavskm 1 301 train
+cxmublbrkr 1 241 train
+cxmvedvusk 1 300 train
+cxnfmwwqfo 1 300 val
+cxngkbtdek 0 300 train
+cxngwglwnw 1 300 train
+cxnimvhbzy 1 301 train
+cxnoxemydo 1 300 val
+cxnrivifkn 1 240 train
+cxnspvjknt 1 300 train
+cxnzffnsjg 1 300 train
+cxobtfqqqo 0 298 train
+cxoepethos 0 301 train
+cxogiwyldp 1 300 train
+cxohfdhkkq 1 300 train
+cxojlakmoj 1 300 train
+cxomjjsezz 1 300 train
+cxopoojmmo 1 300 train
+cxowqrykxl 1 240 train
+cxoxqdwvin 1 299 val
+cxpcimyhpr 1 301 train
+cxpfmenkit 1 300 train
+cxpgmdalzn 1 300 train
+cxplnduxka 1 300 train
+cxpmdgntdl 1 300 train
+cxpqbcsqls 1 297 train
+cxptpzqfnf 0 300 train
+cxqdoqwgsp 1 300 train
+cxqhrnxgvd 1 300 train
+cxqmnbdhiy 1 240 train
+cxqnhvqxbg 0 300 train
+cxqucbhale 1 300 test
+cxrfacemmq 1 300 train
+cxrjwrbklx 1 300 val
+cxrmbappkf 1 301 train
+cxrncthuby 0 300 train
+cxroabhzxu 1 300 train
+cxrooetoay 1 300 train
+cxrqxqwtyt 0 300 train
+cxrqyltnuu 1 300 train
+cxrstzfsuy 0 301 train
+cxruvknvha 1 300 train
+cxsbcuvhju 1 300 train
+cxsbpegjlu 1 300 val
+cxsekvffny 1 300 train
+cxsjgqvmxj 1 300 train
+cxsjnptter 1 300 train
+cxsnzkabaa 1 300 train
+cxsqjzyauw 1 300 test
+cxsuojnuiq 0 300 val
+cxsvvnxpyz 0 299 test
+cxsxwxcstd 1 300 val
+cxszdyotss 1 300 train
+cxthlqeseq 1 300 train
+cxtodzawmj 1 300 train
+cxttmymlbn 1 300 train
+cxuidgtpqr 0 300 val
+cxuvzmrisu 1 300 val
+cxuzbxfwst 1 298 val
+cxvanghqkq 1 301 train
+cxvayntesu 0 300 train
+cxvbureeyj 1 300 train
+cxvctggwxi 0 301 train
+cxvgbzsijg 1 300 train
+cxvgeiybme 1 300 train
+cxvggoszkn 1 300 train
+cxvkgrbaku 1 300 test
+cxvqurbsev 1 300 train
+cxvrqqflti 1 300 train
+cxvutzpduu 1 301 train
+cxvwreuyuz 0 300 train
+cxwbwgjrde 1 298 val
+cxwcpgspni 0 300 train
+cxwfakmhui 1 300 train
+cxwsadeunl 1 300 train
+cxwvzubmaw 0 300 val
+cxwybafzyu 1 301 train
+cxxbfiqvco 1 301 train
+cxxbqjxsou 1 300 val
+cxxgfpikji 0 300 train
+cxxhhwykme 1 300 train
+cxxnoalpiy 1 300 val
+cxxtimzveh 1 300 train
+cxxussejmm 0 300 train
+cxxysuhrnz 1 300 train
+cxxyvegmxm 1 300 train
+cxybpbtpih 1 241 train
+cxygklpkbx 0 300 train
+cxyizzufss 1 300 train
+cxypzjpwqj 1 300 val
+cxyqglsyyx 1 300 train
+cxyvoffxcv 1 300 train
+cxzdbwctfx 0 300 train
+cxzqexgpeu 1 299 test
+cyafkadnnw 0 300 train
+cyahnwhorz 1 300 val
+cyaovhndrs 1 300 train
+cyavflusgb 0 300 train
+cyavimfiex 0 300 train
+cyawtchfiw 1 297 val
+cybascnbiy 1 300 train
+cybetknayd 1 167 train
+cybfrdydog 1 300 train
+cybibvhets 1 300 train
+cybnhobdyh 1 300 test
+cyboodqqyr 1 300 train
+cybrggleiy 1 300 val
+cybvkcmdgl 0 300 train
+cybxslqllm 1 300 train
+cybzehicku 1 300 train
+cycacemkmt 1 300 train
+cycaqgcens 1 299 train
+cyckgyxtxi 0 300 train
+cyclgfjdrv 1 300 train
+cycxdkwndh 1 300 val
+cycxugfybm 1 300 val
+cydgyibjmo 1 300 train
+cydlbpmnry 1 300 train
+cydneakcyh 1 300 train
+cydsglobim 1 300 train
+cyedbeujok 1 299 test
+cyeiqwpyxo 0 300 train
+cyeksdhnip 1 300 train
+cyemvmpwrv 1 300 val
+cyenuxstkq 1 240 val
+cyepzwbesk 1 298 train
+cyersjafjt 1 300 train
+cyfaiicytj 1 136 train
+cyfaimpqvv 0 300 val
+cyfephdyrb 0 300 train
+cyfgzhxmdo 1 300 train
+cyfjdftqxg 1 300 train
+cyflmpzuuf 1 300 val
+cyfpuudecp 1 301 val
+cyfxpvkhrz 1 300 train
+cyfzuxyvyr 1 300 train
+cygblzsrwn 1 300 test
+cyghqovbkt 1 301 val
+cyghxccnsn 1 301 train
+cygixvotoj 1 300 test
+cyglumtcmz 0 300 train
+cygncccjph 0 300 train
+cygpehczfp 1 301 val
+cygpladtgs 1 300 train
+cyhbctxlnu 1 241 train
+cyhdbixykk 1 301 val
+cyhefjhsko 1 300 train
+cyhfxxipmu 1 297 train
+cyhkfxrhdn 1 300 val
+cyhmklcvkd 0 300 train
+cyhpyggvsq 1 300 train
+cyhrewnywq 1 300 val
+cyhvptketc 1 300 train
+cyhxxnezbo 1 300 test
+cyifdylbln 1 300 test
+cyikctpzqw 1 300 train
+cyikdthgod 1 300 train
+cyizrdptbs 1 300 train
+cyjcfkdjgp 1 300 val
+cyjixxrrrg 1 300 train
+cyjrkyjicz 1 300 val
+cyjrsnjizj 1 300 train
+cyjwrqofkr 1 300 val
+cyjyvzhkvt 1 300 val
+cykdqoymho 0 300 train
+cykedihqwv 1 300 val
+cykylxfjrb 1 300 train
+cyligssaqu 1 300 train
+cylqyhypql 1 300 train
+cymacnqyqw 1 300 val
+cymfpsjhjl 0 300 val
+cymfsdestn 0 300 train
+cymktmzosb 1 300 train
+cymnyrefsk 0 300 val
+cymymrhzgd 1 300 train
+cymyxynhcn 0 301 val
+cynbzxibda 1 300 val
+cynckdnzjh 1 299 test
+cyngrezphf 0 300 train
+cynoshpsem 1 300 train
+cynqzgnnkd 1 300 train
+cynreeeaye 1 300 train
+cynrqvpahp 1 300 train
+cynzudaqbx 1 298 val
+cyokqrzbol 1 300 val
+cyomcqpgmy 1 300 val
+cypbysjsua 1 300 train
+cypejmkvjc 1 300 train
+cypekpzfaz 1 300 train
+cyprmcxiid 1 300 train
+cypzvknuqh 1 300 train
+cypzxddmmk 1 300 train
+cyqbrpmrny 1 241 train
+cyqefzwdah 1 300 train
+cyqhavcobz 1 300 train
+cyqhlojnof 1 298 train
+cyqhzdxgrk 1 300 train
+cyqnqhfzsc 1 300 train
+cyqqtpkazm 1 300 train
+cyqrdjfqfp 1 300 train
+cyqsfqlbgp 1 300 train
+cyrifbgfno 1 302 train
+cyrmhszohp 1 301 train
+cyrnxncxif 1 300 train
+cyrrsspkeo 1 301 train
+cysbdohfha 1 300 train
+cysdphxwpv 1 300 val
+cysgiryugk 1 301 train
+cyslxyayir 1 240 train
+cytahjbxuk 1 301 train
+cytbcqxqmw 1 300 train
+cytdctacrw 1 300 val
+cythdgxpdi 1 300 test
+cytofsratb 1 300 val
+cyttisxxpd 1 300 train
+cytyzunfyn 1 269 train
+cyucijsqiw 1 300 train
+cyudfgcsbh 1 300 train
+cyupfqaehu 0 300 train
+cyuruwsjim 0 300 train
+cyvbeyvgbd 1 300 train
+cyvjigpbao 1 300 val
+cyvlcvmahj 1 300 val
+cyvnlbgqlh 1 300 train
+cyvovfharx 0 299 val
+cyvprkxzrf 1 300 train
+cyvrbnzomt 1 300 train
+cyvskgjcul 1 300 train
+cyvwarfocs 1 300 train
+cyvxriituc 1 241 train
+cywebjaezn 0 300 train
+cywlgvimms 1 300 val
+cywmmmxoyo 1 300 train
+cywnpwjupc 1 300 val
+cywzevdlxx 1 300 train
+cyxbkmwpyx 1 298 train
+cyxbncihpu 1 300 train
+cyxdgyisae 1 601 train
+cyxfegxaea 1 300 train
+cyxhaypqzs 1 300 train
+cyxhjuflrs 0 300 train
+cyxlcuyznd 0 300 train
+cyxqisnnee 1 297 train
+cyxsqawcsa 1 300 train
+cyxtasgppy 0 100 train
+cyxtigbszj 1 300 val
+cyxzkgsafw 1 300 val
+cyyldcqvqm 1 300 train
+cyymubrszw 1 300 train
+cyyqtralcn 1 300 train
+cyyvngscuu 1 300 train
+cyywjpwwdn 1 300 val
+cyyzslyglb 1 300 val
+cyzaecgzji 1 300 train
+cyzgavhyiv 0 300 val
+cyzhcxqbjg 0 300 val
+cyzuxgsgck 0 300 train
+czahyawkrq 1 300 train
+czapmddgnk 1 298 train
+czaqetolzt 1 300 train
+czardhuxbx 1 297 train
+czbcuxtart 1 301 val
+czbftoatqg 1 300 train
+czbksjzuaf 1 300 train
+czbmmitjls 1 300 val
+czboylujng 1 300 val
+czbsjdjmlq 1 300 train
+czbskzaaqg 0 300 train
+czcbegjurf 0 300 val
+czccznyfzs 1 300 train
+czclbcysuz 1 146 train
+czcsdmfyob 1 300 train
+czcvkufpdc 1 300 train
+czcwkietro 1 300 train
+czdchuhbfe 1 300 val
+czdcpksprl 1 299 train
+czddwifbwy 1 300 train
+czdipdvsft 0 300 train
+czdubpyolw 1 300 train
+czdzdbowto 1 300 train
+czempsilib 1 300 val
+czemufjhkl 1 298 train
+czeuftputf 1 300 train
+czffoviacf 1 300 train
+czfkkmhzoq 0 300 val
+czflcuyztw 1 300 train
+czflfcldpm 1 301 train
+czfojqdolv 0 300 train
+czfqlbcfpa 0 300 test
+czfqnzyfur 0 300 train
+czftcuzylj 1 300 train
+czfunozvwp 1 300 train
+czfvgsiezr 1 300 train
+czgewsenmz 1 300 val
+czgnyrrkuq 0 300 train
+czgphdxhta 1 300 train
+czgvmggrfc 1 300 train
+czgzxzzvfg 1 300 train
+czhddzphpn 1 300 train
+czhifxynwd 1 298 train
+czhkwernpi 0 300 val
+czhopjqtns 1 301 train
+czhpevswau 1 300 train
+czhtyqkczd 1 300 train
+czhziqffhw 1 300 val
+cziakqpmbn 0 300 train
+czifmcopho 1 300 test
+czigoxgwnf 1 300 val
+czimafmarx 1 300 train
+cziolaybgn 1 300 train
+czirapruub 1 300 train
+czissdodwl 1 300 val
+cziwcuwazd 1 300 val
+czixqjgyck 0 300 train
+czjeannjmi 1 299 test
+czjelgcbvz 1 300 train
+czjjlhcdaf 1 300 val
+czjkgcwhch 1 300 val
+czjkzmczlh 0 300 val
+czjmqasuys 1 300 train
+czjsdnoofc 0 300 train
+czjxkqbhmy 1 299 val
+czjyavzouv 1 300 train
+czjyzdtvvy 1 299 val
+czjzzcliuy 1 300 train
+czkdanyadc 1 300 train
+czkgavlmdr 1 300 train
+czkivkpinf 1 300 train
+czkmptcbfr 1 300 train
+czkmyugpwf 1 301 val
+czkwwkzpyx 1 301 train
+czlanpxaoq 1 300 train
+czldstijav 1 300 train
+czlfmczgfs 0 300 val
+czlrpgposa 0 300 train
+czmaawxltt 1 300 train
+czmfjgnxol 1 300 train
+czmgxivkqs 1 301 val
+czmjdcggyj 1 300 train
+czmmoyfilz 1 300 train
+czmnowpqyt 1 300 train
+czmpwctfaq 1 300 train
+czmqpxrqoh 1 300 train
+czmzfmooww 1 300 train
+cznjawmxyl 1 301 val
+cznlffvegs 1 300 train
+cznnnhetaz 1 300 val
+cznpmsfgpl 0 300 val
+czntadmkzj 1 300 train
+cznweqvrog 1 300 train
+cznwglxzxz 0 300 train
+czobhnafne 1 300 train
+czofdbsogt 1 300 train
+czofuhtjvw 1 300 train
+czogiwtyog 1 300 train
+czohmhdutz 1 298 train
+czohxbxgys 1 300 train
+czoldluihi 1 300 train
+czoscgdxbn 1 300 train
+czpatfihwa 1 300 train
+czpdfuloey 1 298 train
+czpfqlacbh 1 300 train
+czpgezpcrt 1 300 train
+czphqoxnof 1 300 train
+czplamsktr 1 302 train
+czpldgbegb 1 147 train
+czpnuvxosz 0 300 train
+czprwjjpzn 1 300 train
+czpxmsaxhn 1 300 val
+czqipipsok 1 300 train
+czqkvxukyv 1 300 train
+czqrqaztxb 1 300 train
+czqsbhaceo 1 300 train
+czquwucvls 1 300 train
+czrhylrxtc 0 300 train
+czrnayusig 1 300 val
+czrxxgerwk 1 300 train
+czsbnyuesp 1 300 train
+czspkzxynw 1 300 train
+czstlfgskg 1 300 train
+czstpmzduw 1 300 val
+czszluoora 0 300 train
+cztdpjebyh 1 298 train
+cztefzwluj 1 300 train
+cztfpjhfys 1 300 train
+cztistfloh 1 300 val
+cztqkbxnzr 1 300 train
+cztynvlpbm 1 300 train
+cztznffeuo 1 292 val
+czugwbbiox 1 299 val
+czukaggegr 1 300 train
+czultdnbqu 1 300 train
+czunwwovdy 1 298 train
+czupmkgroe 1 300 test
+czuxbovyvl 1 300 val
+czuxyunbjo 1 300 val
+czvafigkpt 0 300 train
+czvbhotyrf 1 301 val
+czvfrmjyan 1 300 train
+czvkzoewhw 1 301 train
+czvmfivyve 0 300 train
+czvtpopqok 1 300 train
+czvumppkey 1 301 val
+czvutoolrz 1 300 train
+czvwaeigfa 0 300 train
+czwadatfjm 1 301 train
+czxafoeluc 1 300 test
+czxmwgqqmi 1 300 train
+czxpalimji 1 300 train
+czxrzglsjk 1 300 train
+czxtlccmnm 1 300 train
+czxtraxsnt 1 300 train
+czxuxqxdzr 1 300 val
+czxxhvjxsa 1 300 val
+czxxysoefd 1 300 train
+czybtgfjtm 1 241 train
+czygbspvwr 0 300 train
+czygnxlbjc 1 300 val
+czyhqhvccy 1 300 train
+czyjcdszlf 1 299 val
+czylfgmknr 1 300 val
+czyllxdlzo 1 300 train
+czysurxwoe 1 298 train
+czywvnuoug 1 300 train
+czyxcidvyj 1 300 val
+czzayswdcg 1 300 train
+czzduqtmqo 1 300 train
+czzdxpfnka 0 300 train
+czzesconay 1 300 train
+czzfgvkhah 0 300 train
+czzlswyteo 0 300 train
+czzohqhadp 1 300 train
+czzxobrnex 1 300 train
+dabecadkih 1 300 train
+dabeehedda 1 300 val
+dabgyrgsmq 1 300 train
+dabimeamvb 1 300 train
+dablyhkffy 1 300 train
+dabnshuwun 1 296 train
+dabysiasvf 1 300 test
+dacgatcwfl 1 300 train
+dacipjinby 1 300 train
+dacohqtmvn 1 300 train
+dacqkzjhfr 1 300 val
+dacshzltqa 1 300 train
+dacyqhdgrj 1 299 val
+dadafcvbky 1 300 train
+dadkezptce 1 300 train
+dadmmuxvjh 0 300 train
+dadnicxjee 0 300 train
+dadoqbxlso 1 300 train
+dadqhcqwha 1 300 train
+dadrotzwag 0 302 val
+daduxgwpjz 1 300 test
+daefglozdd 1 300 train
+daegjgzstj 1 300 val
+daerkhgscz 1 300 train
+dafdjjhbrb 1 300 train
+dafhnjbgjp 0 300 train
+dafhtipaml 1 300 train
+dafjliglyi 1 300 train
+daflehvuam 1 298 train
+dafoovhzso 1 300 train
+dafuedwdqt 1 301 val
+dafueythua 1 298 val
+dagcolpmki 0 300 train
+dagcrdgape 0 300 train
+dagerloolt 1 300 train
+daghsascso 1 300 val
+daglulphmn 1 300 train
+dagmnvkeeg 1 300 train
+dagnyzbyvf 1 300 train
+dagrpdryhv 1 300 train
+dagsbmrjhr 1 300 val
+dagtaiqtnd 1 300 train
+dagwuewlzy 1 300 train
+dahejbzujr 1 300 train
+dahkagbobu 1 300 train
+dahofvxbbz 1 301 train
+dahvuijxob 1 300 test
+dahznkybpw 1 300 train
+daibixbdvx 1 301 val
+daicstpaco 1 300 train
+daijlfwakh 1 300 train
+daijvfsosr 1 300 val
+dailocwlfc 1 300 train
+daimottkty 0 300 train
+daisdfsvkt 1 300 val
+daityhferh 1 300 train
+daiubqdjif 0 300 train
+daiwuxoium 1 300 val
+dajcyskjxs 1 300 train
+dajebuxaez 0 300 train
+dajjnrpswk 1 300 train
+dajlkmlvch 1 300 train
+dajsbyjrbs 1 300 train
+dakgcjvwgg 1 300 train
+dakiztgtnw 0 300 train
+dakqqwnrmp 0 300 train
+dakqwktlbi 1 300 train
+dakrqpseiv 1 299 test
+dalisyltit 1 300 train
+dalkdjprwa 1 300 train
+dalqfujoxh 0 300 train
+dalwecbssl 1 300 val
+dalxcpgfym 1 300 train
+dalxmwioel 1 241 train
+dalynxygrs 1 300 train
+damibfwqrr 0 300 train
+damjizgilg 0 300 train
+dampwkeytg 1 300 train
+damwvewpft 1 300 train
+danafqnhho 1 300 train
+danmrifulj 1 300 train
+danqvbizlv 1 300 train
+danseoxojf 1 300 train
+danuecrfoy 1 300 train
+danuqeqxlm 1 300 train
+danxziqhbj 1 300 val
+danyfkofxk 1 302 train
+daoacyzjae 1 300 val
+daofusvhpl 1 300 train
+daojzrtlbh 1 300 train
+daoqftnvgp 1 300 val
+daoqwwqpcg 0 300 val
+daorjdldgu 1 300 val
+daouufwjtv 1 300 train
+dapjphrfxq 0 300 train
+dapjwqisok 1 300 train
+dapqtunldr 1 300 train
+dapvpkfack 0 300 train
+dapwsnoxqw 1 240 train
+dapzxxsgem 1 300 train
+daqbetniep 1 300 train
+daqcstrqmx 1 300 train
+daqrcgbagj 1 300 train
+darajozjnx 1 300 train
+dardkjawbf 0 241 train
+dargqdtmnl 1 300 train
+darkklfgys 1 300 train
+darmzdfpoa 1 300 val
+dartmctkpz 1 300 train
+darvppdimr 1 300 train
+darxemfscl 0 300 train
+darxqfiash 0 300 train
+darydguzqn 1 300 train
+dasbqgiifj 1 298 train
+dasefuclrs 0 300 train
+daseneexra 1 299 test
+dasikdoalw 1 300 train
+dasivprjjm 0 300 train
+dasjndgvcs 0 300 train
+dasleascbq 1 300 val
+dasoffaihl 0 297 train
+dasporeovg 1 300 train
+dasprsensp 0 300 train
+dasyfhyvuq 1 300 train
+dateawnngx 0 300 val
+dathymnzrv 1 300 val
+datjrwctmd 1 300 test
+datorbycfg 1 300 train
+datqxgequa 0 300 val
+dattpmhfah 1 300 train
+datufutidv 1 300 train
+dauiheqtqt 1 300 train
+daukofinwi 1 300 train
+dauucfdgdv 1 300 train
+dauutgcujv 1 300 train
+dauvhtvqmh 1 300 train
+dauwchljha 1 300 train
+dauxpmkozg 1 298 val
+dauxqdsrta 1 300 train
+dauyrkvtvs 1 300 train
+davcjqoiiy 1 300 train
+davcxjonum 1 300 train
+davgyuxjno 0 300 train
+davhbwinyn 1 300 train
+davnvgifis 1 300 train
+davocwwzhg 1 300 train
+davpwsqkog 1 300 train
+davuhslhgt 1 300 train
+dawbmzgdjh 1 300 train
+dawbwwhull 1 300 train
+dawmxkceki 0 300 train
+dawquhngxn 1 300 train
+dawqzqldie 1 300 train
+dawrkiubdf 1 300 train
+dawsozqnoy 1 300 val
+dawvwziiyk 1 300 train
+daxdoayhtl 1 300 train
+daxjeiwvvx 0 300 val
+daxkdccqcp 1 300 train
+daxppvplei 0 300 train
+daygtjhalq 1 300 train
+daylggxlif 1 300 train
+dayogkgfka 1 300 train
+dayoypylcf 1 299 train
+dayznamdkh 1 300 train
+dazcqddmah 0 300 train
+dazekytmqr 1 300 train
+dazellwbsl 1 300 train
+dazfhyptug 1 300 val
+dazgcqiafb 1 300 train
+dazjrqdnag 0 300 train
+dazmitzpls 1 300 train
+dazseswwpp 1 301 train
+dazzyilpxg 1 300 train
+dbacftwcpq 1 300 train
+dbahlxpfkm 1 300 train
+dbajaaprln 1 300 train
+dbakbevirv 1 300 train
+dbalijphes 1 297 train
+dbasmnyuci 1 300 val
+dbauiiupef 1 301 train
+dbbbhusgnt 1 300 train
+dbbefxhmfk 1 300 train
+dbbinpmwbb 1 300 train
+dbbkgaiunn 1 300 train
+dbbkqclmfv 1 300 train
+dbblgjrtga 0 300 train
+dbbsfrqnoh 1 300 val
+dbburzyxvt 1 301 train
+dbbvpyzdsv 0 300 train
+dbcarhpzep 1 300 train
+dbcawspopu 1 298 train
+dbcfhbbqww 0 300 val
+dbckbkktch 0 300 train
+dbclzwjvvx 1 300 val
+dbcqrixpgh 1 241 train
+dbdlybcefl 1 241 train
+dbdoggoocx 1 300 train
+dbdtzjphfb 1 300 val
+dbeglcyepd 1 298 train
+dbeouqereh 1 300 train
+dbeqcrkmlo 1 300 train
+dbesjvrcqb 0 300 train
+dbeuvemlya 1 300 train
+dbexdostck 1 300 train
+dbfcxecuru 1 298 train
+dbffefhwek 1 300 train
+dbffhqmctl 1 300 train
+dbfgelmnzr 1 300 val
+dbflmwzlud 1 300 train
+dbftndapfi 1 300 train
+dbfwjejfnz 1 301 train
+dbgcausyti 1 300 train
+dbgdvoqjrs 1 300 train
+dbgknmtfbf 1 300 train
+dbglpvkptp 1 298 train
+dbglzdviqh 1 300 train
+dbgqaweaal 1 300 train
+dbgvpwesbv 0 300 train
+dbgztzhbhb 1 300 test
+dbhehpfump 0 300 train
+dbhoxkblzx 1 300 train
+dbhprzhroy 0 300 train
+dbhrpizyeq 1 298 train
+dbhrswenun 0 300 train
+dbhthsgych 1 300 test
+dbhtzqhwcx 1 300 train
+dbibfbldnn 1 301 val
+dbicyhpvxm 1 301 train
+dbidscxvqs 1 300 train
+dbilyhnwll 1 301 val
+dbinjrmthj 1 301 train
+dbiuxvqhrt 1 300 train
+dbiwlmeneq 1 300 train
+dbixwxtuxs 0 300 val
+dbjeddgjgs 0 301 train
+dbjmhpklbv 0 300 train
+dbkbabxjgt 1 300 train
+dbkfqjstbm 1 298 train
+dbkfuamuim 1 299 val
+dbkltefslw 1 298 train
+dbkmmswqfg 0 300 train
+dbkmxwlytr 1 300 train
+dbkrfxlell 1 167 train
+dbkuejstgi 1 288 train
+dbkximjyaw 1 300 val
+dblcsugamc 1 300 val
+dblhswzedj 1 300 train
+dbljbbyeos 0 300 train
+dbljnexmlf 1 300 train
+dblnpkvwko 1 300 train
+dblppjxdvi 1 301 train
+dblsgankdl 0 300 val
+dbltocewnq 1 300 train
+dblwnifome 1 300 train
+dbmamolath 1 300 train
+dbmaspujld 1 301 train
+dbmbkijkmk 0 300 train
+dbmfjfcljy 1 300 train
+dbmipjhejr 1 301 val
+dbmlazkbll 1 300 val
+dbmpfxwtfw 1 301 train
+dbmrufysdj 1 300 val
+dbmyeixpdn 0 300 train
+dbmzriiqft 1 300 train
+dbndymgwsg 1 300 train
+dbnfpcbizh 1 300 train
+dbnggnoozm 1 300 train
+dbnrpkiwjx 0 300 train
+dbnrsbcrvk 1 301 train
+dbnuyzbgky 1 300 val
+dbnygxtwek 0 300 train
+dbobbvqmkr 1 300 val
+dbogzmnzlt 1 300 val
+dbohjwmfwt 1 300 train
+dbolcqemhu 0 300 train
+dbolphrfma 1 300 train
+dboosnvpgs 1 300 train
+dboxtiehng 1 300 train
+dbpcjeeaui 0 300 train
+dbpepqnran 1 300 train
+dbpfluwfxy 1 300 train
+dbpfptzhiw 0 301 train
+dbpiskidse 1 300 val
+dbpronrkvv 1 301 val
+dbpwyvzccc 1 300 val
+dbpzdrpogs 1 300 val
+dbqbbonwjt 1 300 train
+dbqbwrcvjk 0 300 train
+dbqcfvuugb 1 300 val
+dbqrktaaub 1 300 train
+dbqtnfwwle 1 300 val
+dbqyiobgnx 1 300 train
+dbrepbwbuu 1 300 val
+dbrnckvpjv 1 300 train
+dbroyfteer 1 300 train
+dbrpqjttey 1 300 train
+dbrzclhznh 1 300 test
+dbsfikupsn 1 300 val
+dbsiwsvkxw 1 300 train
+dbskpnukgs 0 300 val
+dbsldpxnfg 1 300 train
+dbsnsrfjxk 1 297 val
+dbspmvaemh 1 300 val
+dbspznfdki 1 300 val
+dbsstdvakf 1 300 train
+dbsxlxitgm 0 300 train
+dbszgdavst 1 298 train
+dbtbbhakdv 0 300 train
+dbthqamhyz 1 301 train
+dbtjnvpphe 1 300 train
+dbtjptphuk 1 300 train
+dbunpvsjbz 1 300 train
+dbvdymdpym 0 300 train
+dbvjdiyqrb 1 300 train
+dbvjpkvypm 1 300 val
+dbvpoprhmr 1 300 train
+dbvqfdormn 0 300 train
+dbvvehcocv 1 300 train
+dbvvrcivid 1 300 train
+dbwanmiovy 0 298 val
+dbwdpplwxu 1 301 train
+dbwehqaxyy 1 300 train
+dbwjlbxxda 1 300 train
+dbwuuksfoc 1 300 train
+dbwydfwtip 1 300 train
+dbxbvwmpzp 1 301 train
+dbxckqbbur 1 300 val
+dbxdzbnlfv 1 300 train
+dbxkxnlycs 1 300 train
+dbxpzfbhsn 1 300 train
+dbxqfrnasj 1 300 train
+dbxtfthhxt 1 300 train
+dbxtzfnhyv 1 300 val
+dbxyvaxzot 1 300 val
+dbyavdtnns 0 300 train
+dbyfoksnlh 1 300 test
+dbyhjoeslx 1 300 train
+dbyordqnut 1 300 train
+dbyprbtyll 1 300 val
+dbyyuizpvr 1 300 train
+dbzasrcpdu 0 300 train
+dbzcqmxzaj 1 300 train
+dbzcscekab 1 300 train
+dbzfhmrcrs 1 300 train
+dbzkcskatw 1 300 train
+dbzpcjntve 1 300 train
+dbzpqxlahq 1 299 test
+dbzuyftsme 1 300 train
+dcadwqahtn 1 300 train
+dcadxbcfng 0 300 train
+dcajgtdjdx 1 300 train
+dcalkgdneh 1 300 train
+dcamvmuors 1 300 train
+dcaqvdswge 1 300 train
+dcaswgmsxn 1 301 train
+dcawsogoet 1 300 train
+dcaysfatsp 1 300 train
+dcazaskuka 1 300 train
+dcbbeqmvuk 1 300 train
+dcbbqkltgg 0 300 train
+dcbgsnvfyk 1 269 train
+dcbuzzqnof 1 300 train
+dcbwwlrhtv 0 300 train
+dcbydzoxnb 0 249 train
+dccgpwoegm 1 298 train
+dccruidyaq 0 298 train
+dccuznsyal 1 300 train
+dcddcsmeyi 0 300 train
+dcdddicjmm 1 300 train
+dcdfljnxtj 1 298 train
+dcdmzumqzk 1 300 val
+dcdsnuolnc 1 300 train
+dcdvcottcd 1 300 train
+dcdvxhndxf 1 300 train
+dcedujbcpo 1 300 val
+dcegdxkdkd 0 300 train
+dcekkkxnfx 1 300 train
+dcekxwervb 1 300 train
+dcetttpuqm 1 301 train
+dceycqcznl 1 300 train
+dcffkjgahn 1 300 train
+dcfodaqazt 0 300 train
+dcfuwvayco 1 300 train
+dcgaqywrfn 1 300 train
+dcgcrywopp 1 300 train
+dcgfdtskdk 1 300 train
+dcgnumdfoq 1 300 train
+dcgtandnko 1 300 train
+dcgtvkbmyf 0 302 train
+dcgzckukcv 1 300 train
+dchhvxkhxi 1 300 val
+dchllyatbq 1 300 train
+dciaaibvhx 1 300 train
+dcijmgmkjm 1 300 val
+dciydwvcfy 1 303 train
+dcjbughszt 1 300 val
+dcjfueishg 1 300 train
+dcjmcaxcxz 1 300 train
+dcjmidqxdc 1 301 val
+dcjmwckfgf 0 300 train
+dcjnlrvwko 0 300 train
+dcjnpgzcbi 1 300 train
+dcjpplfvok 1 299 test
+dcjpvhhexf 1 300 val
+dcjvqpgjgd 1 301 train
+dcjymntuui 1 300 train
+dcjyqozkhc 0 300 val
+dcklqywyhe 0 300 train
+dcknjksahd 0 300 val
+dcknupvcpo 1 300 train
+dckpfvpion 1 300 val
+dckwrwjrzb 1 300 val
+dckygrkwnr 1 300 train
+dclkdurmln 1 301 train
+dclvkjelsd 1 297 train
+dclvqwcysa 1 300 train
+dclxdycljw 1 300 val
+dcmammspzg 1 300 train
+dcmghkuuwz 1 300 val
+dcmitrlcbk 0 300 train
+dcmolptgrh 1 300 train
+dcmshtwawr 1 301 train
+dcmwnhbreb 0 301 val
+dcnegjsubk 1 299 test
+dcnkbfkwzp 1 301 train
+dcnltnfeeg 1 300 val
+dcnlykkbbx 1 300 train
+dcnmoepllz 1 300 train
+dcnppezxya 1 147 train
+dcnqtgonsk 1 301 train
+dcnuhmzpeu 0 300 train
+dcoawjaurg 1 301 train
+dcoieqrjhf 1 300 train
+dcoyfnrpsm 1 300 train
+dcoyqacqmo 1 300 train
+dcpbjtmfca 1 298 train
+dcpgtzfulm 1 300 train
+dcpmipuapc 0 300 train
+dcpnedehxa 0 300 train
+dcpsbavokb 1 300 train
+dcpscajolo 1 300 train
+dcptbihiel 1 300 train
+dcpvkyyurp 0 300 train
+dcqdtsgrif 1 300 train
+dcqhhkwztm 1 300 train
+dcqjlozdwm 1 299 train
+dcqknjslcm 1 300 train
+dcqodpzomd 1 300 test
+dcqxjyahds 1 300 train
+dcrbdsltes 1 298 train
+dcrefaartv 0 302 val
+dcreovcynv 0 300 train
+dcrjbnkhwu 1 300 train
+dcrkfowrrh 0 300 train
+dcrqssumut 1 300 val
+dcrsugpfcv 1 300 train
+dcseifpvtf 0 300 train
+dcsikgcygf 1 300 val
+dcskqkepft 1 300 train
+dcsuccbsei 1 300 train
+dcsurmyeij 1 300 train
+dcsxzweyxl 1 300 train
+dcszjczlpo 1 300 train
+dctbnichwl 1 300 train
+dctbsgvebr 1 300 train
+dctlyoecwq 1 300 train
+dctnujryty 1 300 train
+dctrwkqupd 1 296 train
+dctsqbktdd 1 300 train
+dctszztpxd 1 300 train
+dctxmwkzct 1 300 train
+dctxqygasy 1 300 train
+dctyzjipfr 1 300 train
+dctzysxaey 1 300 train
+dcuiiorugd 1 300 train
+dcujufwtaa 1 301 train
+dcuspptsov 1 300 val
+dcuuucdbsv 1 300 train
+dcvdlptqqo 1 301 val
+dcveredmux 1 300 train
+dcvifxtzwd 1 298 val
+dcvklmigsh 0 300 train
+dcvnpbelyb 1 300 train
+dcvnuptiko 1 300 train
+dcvswxkcat 1 300 val
+dcvvmkvpna 1 299 test
+dcwcdhskvh 1 300 train
+dcwdiuhdsf 0 300 val
+dcwevdiicr 1 300 train
+dcwkheoips 1 300 train
+dcwklweqsd 1 300 train
+dcwnkxrsgg 1 300 test
+dcwokudqws 0 300 train
+dcwvwuzooj 1 301 train
+dcxaxpmbgz 1 288 train
+dcxdrzwppb 1 300 train
+dcxozcclel 0 300 train
+dcxqbxontt 1 297 train
+dcxrxffknw 1 300 train
+dcyizhgzmd 1 300 train
+dcykyujhay 1 300 train
+dcymikeysr 1 298 train
+dcypbtproo 1 300 train
+dczbizydwu 1 300 train
+dczfgnqnsr 1 300 train
+dczllhqjjs 1 300 train
+dczlxpspyt 1 300 train
+dczmsjrwlc 1 300 train
+dcztdakmjg 1 300 train
+dczxxkstmj 1 300 train
+ddadaongzn 1 300 val
+ddaesgonsi 1 300 train
+ddafrtsryt 1 239 train
+ddagxidupk 1 300 train
+ddagyhwnwm 1 300 train
+ddagzbeazt 1 300 train
+ddanabbzkp 1 298 train
+ddaxeymmmn 1 300 train
+ddaxhzxzaq 0 300 train
+ddbhhoxaib 1 300 train
+ddbitfxjcv 1 300 train
+ddbiylzzqx 1 300 val
+ddblowwfcm 1 300 train
+ddbpfxzqrl 1 301 train
+ddbyhorsay 1 300 train
+ddcfzufmyd 1 299 test
+ddcmgidgxo 1 300 train
+ddcnqpyrmh 1 301 train
+ddcugdxkpj 1 299 train
+ddcwvtzzno 1 300 train
+ddcymnyysf 1 300 val
+dddjbmpchd 1 300 train
+dddxunglkp 1 300 train
+ddepeddixj 0 298 train
+ddeurbvioq 1 240 train
+ddewfzykyp 1 300 train
+ddfghtmonn 1 301 val
+ddfgkbawlc 1 300 train
+ddflhcrqow 1 300 train
+ddfqkcxrnx 1 300 train
+ddfrexfnhg 0 300 val
+ddfscdlncl 1 300 train
+ddfuttyflp 1 298 train
+ddfvzudfly 1 301 val
+ddgdbctyif 1 300 train
+ddgepruoow 1 300 train
+ddggrkisbn 0 300 val
+ddghapcesx 1 300 train
+ddgkivevug 1 301 train
+ddgubuafql 1 300 train
+ddgworhapa 1 239 train
+ddgyqoxsir 1 300 train
+ddhfabwpuz 1 300 train
+ddhhuhyoes 1 300 train
+ddhijrstzr 0 298 train
+ddhonehdzt 1 300 val
+ddhsykhyod 1 300 train
+ddhwmadatq 1 300 train
+ddibmwpiuk 1 300 train
+ddidvzmvjs 1 300 train
+ddieekaouu 1 300 val
+ddiekairss 1 296 train
+ddifvixwxx 1 300 train
+ddiofpvrkb 1 300 train
+ddirdservp 1 300 val
+ddizdslzfv 1 300 val
+ddjewnoazz 1 300 train
+ddjfjzmdkk 1 300 val
+ddjggcasdw 1 300 train
+ddjllgeomh 0 300 val
+ddjpztlbqq 1 301 train
+ddjsufdebq 1 300 train
+ddjvprldej 1 300 train
+ddjzmyabyu 1 300 val
+ddkazdnczb 1 300 val
+ddkbgdbmud 1 300 test
+ddkcxrncmq 1 301 train
+ddkjmumjgf 1 300 train
+ddkkljdgom 1 300 train
+ddktcurcsw 1 302 train
+ddktgjqvti 1 300 train
+ddkuilhous 1 299 test
+ddlingzysy 1 300 val
+ddlmpybsht 1 300 train
+ddlsasmgig 1 300 train
+ddlssksupe 1 300 train
+ddlsxsesbx 1 300 train
+ddltueqqqj 1 300 train
+ddlutqlzwv 1 298 train
+ddmwhccwzc 0 300 train
+ddmwokwixc 0 300 train
+ddmyqzmsuy 1 241 train
+ddnbpgouzr 1 300 train
+ddndewezea 1 300 train
+ddnfrgolit 1 300 train
+ddnhftubpz 1 300 train
+ddnishdmey 1 300 train
+ddnqcocqpq 1 301 train
+ddntgfnuet 1 300 train
+ddnthwdvwg 0 300 train
+ddnticyxmd 0 300 train
+ddnuwwtiss 1 300 train
+ddoanziqhj 1 300 train
+ddofbnkgot 1 300 val
+ddofbzcdbb 1 300 train
+ddofigfqtp 1 300 train
+ddogfurugq 1 300 val
+ddohdmifkp 1 300 val
+ddoiyjsqua 1 300 val
+ddoxblqugp 1 298 val
+ddpghcfrmg 1 300 val
+ddpkbmwrra 0 300 train
+ddpngojvzy 1 300 val
+ddppcudrad 1 300 train
+ddpvuimigj 1 300 train
+ddqayybsuq 1 300 train
+ddqccgmtka 1 300 train
+ddqgdrpvkm 0 300 train
+ddqnhxudty 1 300 train
+ddqsbryhvd 0 300 train
+ddqsjrfrhx 0 300 val
+ddqtdcasgi 1 300 val
+ddqtkrkmjn 1 300 test
+ddqugjopgv 1 301 val
+ddqvftebrt 0 300 val
+ddqybqgnkl 0 300 train
+ddrcabjbza 0 300 val
+ddrjnwlugg 0 300 train
+ddrkfvsttq 0 300 train
+ddrkrlgrou 1 297 train
+ddrpctikvm 1 300 train
+ddrrbntbuu 0 300 train
+ddrtwbrvvq 1 300 train
+ddrxykcwxm 0 300 train
+ddryljorfm 1 300 train
+ddsanrrtve 0 300 train
+ddshhjsygw 1 300 train
+ddsmrsokkt 0 300 train
+ddsnbavtfo 1 298 train
+ddsqqjrjax 1 298 val
+ddsqtnxyif 1 298 train
+ddssybhovi 0 300 train
+ddstgqzzbx 1 300 val
+ddsylmermi 1 300 train
+ddtbarpcgo 0 300 test
+ddteixybzf 1 300 train
+ddtgcdxlfj 1 300 train
+ddtrknyeno 1 300 val
+ddtuholdfz 1 300 val
+ddtxbzgbho 1 300 train
+dduarbnfwc 0 300 train
+ddugdzuqno 1 301 train
+dduhylpjry 1 300 train
+dduidrhkvv 0 300 train
+dduwbsrnmv 1 300 val
+ddvbvfrnwi 1 300 val
+ddvbwjmtxo 1 300 train
+ddveckflgo 1 300 val
+ddveunwfbw 1 300 val
+ddvgpsclyx 1 301 train
+ddvgrczjno 1 300 train
+ddvknwrapr 0 300 train
+ddvpmqqrlj 1 300 train
+ddvpppjciq 1 300 train
+ddvqkgpblf 1 300 train
+ddvstiwcwt 1 167 train
+ddvwdvwcla 1 301 train
+ddvxmmcqic 1 300 train
+ddwepnuyti 1 300 train
+ddwfpwxejt 1 300 train
+ddwvccamne 1 298 train
+ddwzmhupav 1 300 train
+ddxfhdumcy 0 300 train
+ddxmucvrgg 1 300 train
+ddxydequdc 1 300 train
+ddyipigvqe 1 300 train
+ddyjlbiqyr 1 300 train
+ddylopxpuw 1 300 train
+ddyrkertzf 0 300 train
+ddyvqawoiq 1 300 train
+ddywtlbyzo 1 300 val
+ddzblueuzp 1 303 train
+ddzdqyzdhc 0 300 train
+ddzfbpeogt 1 299 train
+ddzfcscdat 1 300 val
+ddzivswqxk 1 300 train
+ddzksqfpsr 1 300 train
+ddzmdulwdn 0 301 train
+ddzqqwkcie 1 300 train
+ddzredpzlo 1 301 val
+ddzsbynofq 1 300 val
+ddzvxazexy 1 300 train
+deaftjdyqy 1 240 train
+deagrwoqak 1 300 train
+deajjxedru 1 300 train
+deaptvudks 1 300 train
+deatliunyn 0 301 train
+deatlyizmz 1 300 train
+deaxrkmkbh 1 240 train
+debaivdfyo 1 300 val
+debffbfzqh 1 300 train
+debfikcmdv 0 300 train
+debkrrmywb 0 300 train
+debllamlvm 1 300 train
+deblvxptel 1 300 val
+debszcijvd 1 300 val
+debzyjrpxm 1 300 train
+decjmafhav 1 301 val
+deckvbmgtn 0 300 val
+decnwudhiu 1 300 train
+decpkffsla 1 300 train
+decpocsuhd 0 300 train
+deczfkdrhz 1 300 val
+dedaztepmu 1 299 test
+dedcjjcizg 1 300 train
+dedfmnngpk 1 300 train
+dedqiwxjck 1 300 val
+dedswiphjs 1 299 val
+dedyedsjrf 1 300 train
+deeanfuurl 1 300 train
+deecutkywj 0 300 train
+deeihusbku 0 300 train
+deejejuzcu 1 300 train
+deelglqrcf 1 301 train
+deeqmpacic 1 300 train
+deesewpczx 1 302 train
+deewyvrlzo 1 300 train
+deeyvzmgaw 1 300 train
+defeqlyysh 0 300 val
+defeyoyaik 1 301 train
+deffxrnftl 1 300 train
+defludtqav 1 300 train
+defolmxezz 1 300 val
+defoxhdwiy 1 300 train
+defpjacbqr 1 300 val
+defrnleigv 0 301 val
+defvdrrahn 0 300 train
+defxubrwdp 1 299 test
+degaiqcgjz 1 301 train
+degaufnpix 1 300 train
+degdaofolf 1 300 train
+degghmtwuw 1 300 train
+deglzarhyx 0 300 train
+degpbqvcay 1 300 train
+degqguwzgp 0 300 train
+degriaqieh 1 300 train
+degrpcsful 1 300 train
+degyedntzd 1 300 train
+dehaljckyt 1 300 val
+dehfkvsfak 0 300 train
+dehhyjdoal 1 300 train
+dehkunamqr 1 300 train
+dehwqyosfb 0 301 train
+dehzzsmhmo 1 300 train
+deifhsplng 1 300 train
+deijviwkda 1 298 train
+deiwnqacsh 1 300 train
+deiywoufiy 1 300 train
+dejewgjkro 1 300 val
+dejewxlwmm 1 300 train
+dejhvbgbwx 1 300 val
+dejpclclqi 1 300 train
+dejrbttkhl 1 300 val
+dejsuiselh 1 300 train
+dejvqycmoj 1 300 train
+dekbonvvou 1 300 train
+dekduqdfdu 1 300 train
+dekimxwgdg 1 300 train
+dekkxfgplf 1 300 test
+dekubmzctv 0 300 train
+dekwsquppl 1 300 train
+delawebgzl 1 302 train
+delnylpyhp 1 300 train
+delpasdocb 1 300 train
+delpuzjsvd 1 300 train
+delpzztvsh 1 300 train
+delyrslnsy 1 301 train
+delzhijefz 1 297 train
+demhikwrxs 1 300 train
+demnwvojit 1 300 val
+demrymmoyx 1 143 train
+demuhxssgl 1 300 test
+demwnpptmb 1 300 train
+dencrrvllu 0 300 train
+denenuzuxo 1 300 val
+denfgnnjtm 1 300 train
+denfyldpva 1 300 val
+denujrssjb 1 300 train
+denvrbrfex 1 300 val
+denztufsjq 1 300 train
+deodklomyv 1 298 train
+deoexpsdqf 0 299 val
+deogcslvgj 1 299 val
+deoisxtlgy 1 301 train
+deokroxvyd 1 300 train
+deonabexby 1 300 train
+deoofblanl 1 298 train
+deovlpriuk 1 298 train
+deoxkcqbel 0 300 val
+depawydyuh 1 300 train
+depcrcqwai 1 300 train
+depliffrko 1 300 train
+depsivyouu 1 300 train
+depwiwjaya 1 300 val
+deqdvahbhg 1 300 train
+deqjbfxtgj 1 300 train
+deqxaihxuz 0 300 train
+deqxdmfrfy 1 240 val
+deqyhpazkq 1 300 train
+derdlanzhv 1 300 train
+derdywipzq 1 300 train
+derekimscj 1 300 val
+derfsbbisk 1 300 train
+derkcaxbhk 1 300 train
+dermivvylo 1 300 train
+dermobcmbu 1 301 train
+deroigfoxd 1 300 train
+derpbinucl 1 300 train
+derzmqksvz 1 300 val
+deslnszgpy 0 300 train
+desmutgemu 1 301 train
+desxyekycw 1 300 train
+detkcsskhe 1 300 train
+detsnvjgrp 0 300 train
+detuirvogn 1 300 train
+detvabrxiy 1 300 val
+detwoqyuci 1 300 train
+detykgqgco 1 300 train
+deuacldebm 1 300 val
+deulvodsky 1 300 train
+deuqmhwoco 0 300 val
+deurycxhpp 1 300 train
+deuxwgvqsu 1 300 train
+devctmnwkj 1 300 train
+devefnvbbj 1 300 train
+devjzldunl 1 300 val
+devkehhkrk 0 300 train
+devkqhjvjr 0 300 val
+devrzvmzrp 1 300 train
+dewcfwtkzc 1 298 train
+dewgobbsfq 1 300 train
+dewgotwlkr 1 300 train
+dewhpxurks 1 300 val
+dewntsgucs 0 298 train
+dewoyrlvjp 1 300 val
+dewwkfbakz 1 300 train
+dexiaeuqha 1 300 train
+dexibjhmeo 1 300 val
+dexkltjdnr 1 301 val
+dexltvvrzu 1 300 train
+dexmozizsn 1 300 train
+dexnpbncta 1 300 train
+dexrcvoajh 1 300 train
+dexuumghyb 1 300 train
+deyancnbyf 1 298 train
+deycvgkrre 0 300 val
+deyfgggwzx 0 300 train
+deylwmxabw 1 300 train
+deymyrzssl 0 300 train
+deynbvzkus 0 300 train
+deynzimvqz 0 298 val
+deyoqcfjcm 1 300 val
+deyspzcmit 1 300 train
+deyvsvafuy 0 300 train
+deywhkarol 1 300 train
+deywskbzkt 1 240 val
+deyyistcrd 1 300 train
+deyzglmlwj 0 300 train
+dezelspotq 1 300 val
+dezhjrsqvt 1 300 train
+dezokbfywn 1 300 val
+dezuxwdjih 1 300 train
+dezuyiezqi 1 301 train
+dezveepgbs 1 300 val
+dezvqtncth 1 300 train
+dfaeqriiwz 1 300 val
+dfafrrltdi 1 300 val
+dfarlbhxsu 1 300 train
+dfaslvpqyj 0 300 train
+dfaunkljam 1 300 train
+dfaxihmsqo 1 300 val
+dfayvpnfkw 0 300 train
+dfbcwghugs 1 300 train
+dfbgkamcnd 0 300 train
+dfbpceeaox 1 300 train
+dfcijxtotm 1 300 train
+dfcnrutriw 1 300 train
+dfcoszgyow 1 300 train
+dfcoyuhhex 1 300 test
+dfcschesei 1 300 train
+dfcyksflhk 1 301 train
+dfdxotpqfo 1 300 train
+dfdxszcpru 1 300 train
+dfeehevbus 0 300 val
+dfehgjswwd 1 300 val
+dfehszipdg 1 297 train
+dfejiindbl 1 300 train
+dfekmhmmgp 1 300 val
+dfembozird 0 300 train
+dferzfqkbu 1 298 train
+dfezkstnzg 1 301 val
+dffdtlsjuv 1 241 train
+dffkcrccsj 1 300 train
+dffmijyodr 1 300 train
+dffmvpqblv 1 300 train
+dffoepnujh 1 300 train
+dffqaqezvn 1 299 train
+dffscprcuu 1 241 train
+dffsnfrocs 1 300 train
+dfftuzgohr 1 300 train
+dffurdkguy 0 300 val
+dffwjugyxq 0 300 train
+dffwjuqsye 0 241 train
+dfgeezzdjt 1 300 train
+dfggmughpl 1 300 train
+dfgihdrqqu 1 300 test
+dfgjncxkio 1 241 train
+dfgldgtgxt 1 300 train
+dfgmdzwtdj 1 300 train
+dfgpojcubw 0 300 val
+dfgwglcyiz 1 241 train
+dfgxmbooui 1 300 train
+dfgzhzlnpa 1 300 train
+dfgzozyfau 1 300 train
+dfhijhjvbb 1 301 train
+dfhnxcowcn 0 300 train
+dfhofezdps 1 300 train
+dfhpeakbjm 1 240 train
+dfhthnhzrb 1 300 test
+dfhvynnars 1 300 train
+dfhzmusawi 1 300 val
+dfikcuaudf 1 298 train
+dfilebaipe 1 300 train
+dfisypclnv 1 300 train
+dfiwbwdvci 1 300 train
+dfizleqjyx 1 300 train
+dfjeslbxar 1 300 train
+dfjnlgoctu 0 301 train
+dfjueqzmfx 0 300 val
+dfkaekrnfr 1 300 val
+dfkatdijen 0 300 train
+dfkeosenua 1 299 test
+dfkjcoltmo 1 300 train
+dfkkldwxjs 1 300 train
+dfkqciwcxx 1 300 train
+dfkqgmlyqe 0 300 train
+dflaajejvw 0 300 train
+dflerefwqj 1 300 train
+dfllzqcyug 1 241 train
+dflmmskmaf 1 302 train
+dflmvwxvtf 1 300 train
+dflntkllui 1 300 val
+dflpzscccs 0 300 train
+dflpzzixje 1 300 test
+dflsctrwct 1 300 train
+dflspovqos 0 300 train
+dflswfhkwq 1 301 train
+dfltwxmthv 1 300 train
+dfltyhtruf 1 301 train
+dfmgpurley 1 300 val
+dfmpogdasz 1 300 train
+dfmrkjvbst 1 300 val
+dfncyispfc 1 300 train
+dfndzltvde 1 300 train
+dfnnriurvc 0 300 train
+dfnxqfwtxy 1 300 train
+dfoiyuirbj 1 300 val
+dfolhoqttw 1 301 train
+dfonlrreiv 1 300 val
+dfonxmosjd 1 241 train
+dfootuddqt 1 300 train
+dfowvjboav 1 300 val
+dfozukdjfj 1 300 train
+dfpajgzhxq 1 300 val
+dfpecjsbdi 1 241 train
+dfpizimddw 1 300 val
+dfpmkyzpca 1 300 train
+dfpmmnvaop 1 300 train
+dfpmwknxkp 1 300 train
+dfpvvtcbot 1 300 train
+dfpwwyaomf 1 300 train
+dfpwzhovnb 1 300 val
+dfpwzvfypv 1 300 train
+dfpylfgkka 1 300 train
+dfpyystabi 0 300 train
+dfqmbirtlt 1 300 val
+dfqqluqcxg 1 300 val
+dfqskgadcw 1 300 train
+dfqvxwgmyl 1 300 train
+dfqwasrdvq 0 301 train
+dfqzmxyvqw 0 300 train
+dfrblpzrfs 1 300 train
+dfrhdjwfpz 1 300 val
+dfrkufxfpc 1 300 train
+dfrkuqmrwf 1 300 train
+dfrlloclqh 1 300 train
+dfrngtsauk 1 300 train
+dfrqbgrydf 1 300 val
+dfrubjbopu 1 300 val
+dfrvhvpgda 1 300 train
+dfrvucpydi 1 300 train
+dfrwroiwdl 1 300 val
+dfrxcsrixu 1 300 train
+dfsasnyktn 1 300 train
+dfsddgovoo 1 300 val
+dfsgzankji 1 300 train
+dfshmoospr 1 300 val
+dfskrsqsqy 1 300 val
+dfslbkcxbj 0 300 val
+dfsqpecwog 1 300 train
+dfsudwuyki 1 300 val
+dftdzfqfot 1 300 train
+dftkdhjqvs 1 300 val
+dftlgtbhag 1 301 train
+dftlkexgak 1 298 train
+dftnwbytug 1 300 val
+dftswlnrfz 0 300 train
+dftyisuemv 1 300 train
+dfueewmwus 1 300 train
+dfufvvtqov 1 300 train
+dfujjfsabh 1 136 train
+dfujkgpzvc 1 299 train
+dfujkuzelh 1 300 train
+dfulockbbz 1 300 train
+dfuzkscbci 1 301 train
+dfvesskkhm 1 300 train
+dfvfkozxkx 1 300 train
+dfvnusznlr 0 300 train
+dfvrwzrpsp 1 300 train
+dfvrytdmoe 1 301 train
+dfvsvzeqeg 0 300 train
+dfvudaojxn 1 299 test
+dfvwkacxqe 1 300 train
+dfwachzzkr 1 300 train
+dfwnnzegsy 1 300 train
+dfwobilokm 1 300 train
+dfwpffnzkm 1 300 train
+dfwqdiyhmg 1 241 train
+dfwtdceztx 1 300 train
+dfwyvfclce 1 300 train
+dfxerhzvfm 0 300 train
+dfxiluowgr 1 136 train
+dfxnkdsvup 1 300 val
+dfxsugmlsw 1 300 val
+dfxtesniah 1 300 train
+dfxwtmsttt 1 300 train
+dfxybzrqeo 0 300 train
+dfxyitekai 1 301 val
+dfyackeosi 1 600 train
+dfykdvchet 1 297 train
+dfynybcnzh 1 300 test
+dfyrcfoplq 1 300 train
+dfzgnwsdcd 1 300 train
+dfztooaqxj 1 299 val
+dfzupullbn 1 241 train
+dfzwlayvoj 1 300 train
+dfzzznxuah 0 300 train
+dgabaumtaa 1 296 val
+dgagpzefwb 1 300 train
+dgagwsjkqk 0 288 train
+dgaihddirb 0 300 train
+dgandltzfp 1 288 train
+dgavmmishw 1 300 val
+dgaytezioz 1 300 train
+dgbagxswlx 1 300 val
+dgbayljaxu 0 300 val
+dgbeekairq 0 300 train
+dgbqnwuqlf 1 300 train
+dgbszzkmyr 1 300 train
+dgbxioynxc 1 300 train
+dgccevhofy 1 300 train
+dgccquxszf 1 300 train
+dgcdkewejs 1 300 train
+dgcjustqps 1 300 train
+dgclsrcjap 1 300 train
+dgcrrnrjyl 1 300 train
+dgctyuitth 1 300 train
+dgcuscqlkd 0 300 train
+dgcyaajqwm 1 300 train
+dgcynprkrb 1 300 train
+dgdalswdyp 1 300 train
+dgdaodyusj 1 300 train
+dgdfjpumzd 1 300 val
+dgdhzkpvra 1 299 test
+dgdnfijnft 0 300 train
+dgdrihvkxl 1 300 train
+dgdswrdogt 1 301 train
+dgduopxzwm 1 300 val
+dgdvunsamx 1 300 train
+dgdxidiauq 1 300 train
+dgdzidzpoe 1 300 train
+dgebmcisuo 1 300 train
+dgekatgucu 1 301 train
+dgekpaxrfp 0 300 train
+dgencqcxmp 1 300 train
+dgerrnwvxl 0 300 train
+dgezbtjinh 1 300 train
+dgfesudnft 1 300 train
+dgfktoueqa 1 241 train
+dgfohexhun 1 300 train
+dgfrhycttb 1 240 train
+dgftkfwzwu 0 300 train
+dgfuertkjp 1 300 train
+dgfwvxrbni 1 300 val
+dgfxvmrcxi 1 300 train
+dgfzbkxnbj 1 300 train
+dggacvfsst 1 300 train
+dgggkeswzb 1 300 val
+dggtzvlmqq 1 298 train
+dggybitydu 1 241 train
+dggzfnnmwf 1 300 train
+dggzimgtrq 1 300 train
+dghbpnphef 0 300 train
+dgheawmllp 1 241 train
+dghebukypk 0 300 train
+dghhdvdzrb 1 300 test
+dghikbblsr 1 300 train
+dghlnlzoks 1 300 train
+dghszgdefi 1 300 train
+dghuodhtqi 1 300 train
+dgizmspftn 1 300 train
+dgjkiowcbq 1 300 train
+dgjkrmurmx 1 300 train
+dgjlourgsw 1 300 train
+dgjmstvnpd 1 300 train
+dgjoxokksm 1 300 train
+dgjrhmivzs 0 300 val
+dgjssccxhx 1 300 train
+dgjuuohkmr 1 300 train
+dgjxfzhrzg 1 300 train
+dgkbqwatne 1 298 train
+dgkdcvnhrr 1 300 train
+dgkemudauo 0 300 val
+dgkngkneyf 1 302 train
+dgknxqazvi 1 300 val
+dgksuydlsr 1 300 train
+dgkvlmjlef 1 300 val
+dgkyrayvtd 1 300 train
+dglaksqwvt 1 300 val
+dgljlvecjo 0 300 val
+dglnsoibqk 1 300 train
+dglvilfaao 1 300 train
+dgmbgofdwy 1 300 train
+dgmcoflrox 1 300 train
+dgmerbxfzu 1 300 train
+dgmevclvzy 1 300 train
+dgmrzbgprb 0 300 val
+dgmsbcpyon 1 300 train
+dgmsyauuvv 1 300 test
+dgmtcvsyxr 1 300 train
+dgmujgivqu 1 300 train
+dgmxfixurf 1 300 train
+dgmzjbwhdm 1 300 train
+dgnijohvsx 1 300 train
+dgnnjvelxv 1 300 train
+dgnroisrup 1 300 train
+dgnrrgbuck 1 300 train
+dgnrrzbdki 0 301 train
+dgnuzsynvv 1 300 train
+dgnzzvfujo 0 300 train
+dgoamvqzki 0 300 train
+dgohtipgij 1 300 train
+dgooxrrhmr 0 300 train
+dgoxeqshvy 1 300 val
+dgpbfhiyio 1 241 train
+dgpexgsngq 1 300 train
+dgpljbxkcx 1 301 train
+dgprxstdgj 1 300 val
+dgpvbdmebj 1 300 train
+dgpzwfwrst 1 241 train
+dgqexrmrke 1 300 train
+dgqifelufo 1 300 train
+dgqnmehbqy 0 300 train
+dgqrwzakcu 1 300 train
+dgradxydnt 1 300 train
+dgrfyyirxt 1 241 train
+dgrmcxvcok 1 300 train
+dgroyiupvw 1 300 val
+dgrsfhioaj 1 300 train
+dgrtnkjmbe 1 301 train
+dgrwhlqosh 0 300 train
+dgrwshcepu 1 300 train
+dgrzbruftl 1 300 val
+dgscebukdo 0 240 train
+dgscvfecqs 1 299 val
+dgsfaepnum 1 300 train
+dgsqlajbme 1 299 val
+dgstkakoiv 1 300 train
+dgsvgrqoku 1 300 train
+dgszotyamt 0 300 train
+dgtdgrzifi 0 300 train
+dgtexcjtec 1 298 train
+dgtltvrqzw 0 300 train
+dgtvvjejli 0 300 val
+dgtvxduqxb 1 300 train
+dgubmmyddl 1 299 test
+dguhzoobev 1 300 train
+dguibctgnw 1 300 train
+dguimpsjmb 1 300 train
+dguncbljmw 0 300 train
+dguvdjysqo 1 300 train
+dguvxabzeg 1 236 train
+dguwaorjmx 1 300 val
+dgvdkmixwf 1 300 train
+dgvhkhmohz 0 300 val
+dgvjvwlahu 1 300 train
+dgvqefslkw 1 300 train
+dgvspplhfu 1 300 val
+dgvzqahycq 1 301 val
+dgwbulfhpq 1 300 train
+dgwebivakv 1 300 train
+dgwexsksra 1 300 val
+dgwhrhufly 1 300 val
+dgwrkbdoop 1 300 val
+dgwrvlikca 1 288 train
+dgxnlutmcl 0 300 train
+dgxnmgikej 1 300 train
+dgxpjtddfz 1 300 val
+dgxrqjdomn 1 300 train
+dgxwkzjeuh 1 300 train
+dgyeaodnzw 1 300 test
+dgyidaeucw 1 300 train
+dgypllsgsz 1 297 train
+dgyqnulynq 1 300 train
+dgytnkpzjs 1 300 train
+dgzajzyzum 0 301 train
+dgzklxjmix 1 300 train
+dgzrkiuhre 1 300 train
+dgzykttzzi 1 302 train
+dhacxelphg 1 300 val
+dhafiubuuv 0 300 train
+dhahwzhaoj 1 300 val
+dhankauxvn 1 300 train
+dharoobkdi 1 300 train
+dhattexrpi 1 300 val
+dhazowlcun 1 296 train
+dhbbkwlagj 1 300 val
+dhbbvqylfl 1 300 train
+dhbcezmxtw 1 300 train
+dhbcxyzgez 1 300 train
+dhbixobmeu 1 300 train
+dhbnxpdkof 1 300 train
+dhbwcahdsw 1 301 train
+dhbwrtvcwd 1 300 train
+dhbzkpirjq 1 300 train
+dhcfvvwvid 1 300 val
+dhcfwllrda 1 300 val
+dhcndnuwta 0 300 train
+dhcpmedqqw 0 300 train
+dhcqtevbkp 1 300 train
+dhcrpdqqlv 1 300 train
+dhcselezer 1 300 train
+dhctavhoja 1 300 val
+dhcvupxnrj 0 300 train
+dhcxcgtcpd 1 300 val
+dhcxperxqr 1 300 train
+dhcxruhxqm 1 300 train
+dhcxwjaesx 1 300 val
+dhcyqigcio 1 300 val
+dhdarygjio 1 300 train
+dhdbsecfsy 1 300 train
+dhdcevbzns 1 301 train
+dhdivhuwly 1 300 val
+dhdklhwrdj 1 300 val
+dhdmzidhht 1 300 val
+dhdqerelzc 1 300 val
+dhdtvnuglu 1 300 train
+dhdykwypbc 1 300 train
+dheefpgewg 1 299 val
+dheglvyxoz 1 300 train
+dhepzaoilf 1 300 val
+dhetuxjmnz 1 300 train
+dhevettufk 1 298 train
+dheynhtlps 1 300 train
+dhfcwchsir 1 300 train
+dhfeyosllj 0 300 train
+dhfinawlcy 1 300 train
+dhfkobxjwq 0 300 train
+dhfkryfspz 1 300 train
+dhflewbzbo 1 300 train
+dhfqnebqii 1 300 train
+dhfxzbuooo 1 241 train
+dhfynueypt 1 300 train
+dhgizzwrma 1 300 val
+dhgsmhlvva 1 300 val
+dhgsupycod 1 300 train
+dhgvsdotga 0 300 val
+dhgvvblxsu 0 300 val
+dhgzhxqirc 1 297 train
+dhhaporerz 1 301 train
+dhhfhcetsw 1 298 train
+dhhpaftgnd 1 300 train
+dhhtxynlby 0 300 train
+dhibgljpai 0 300 val
+dhifxkzcep 1 300 train
+dhihyuwpnh 1 300 train
+dhiiiwxtof 1 300 val
+dhikrifybo 1 300 val
+dhinaqxuuj 1 300 train
+dhisuendkq 1 300 train
+dhiszxchum 1 300 train
+dhitvkvral 1 300 train
+dhjcpzikle 1 300 train
+dhjdrgnrux 1 300 train
+dhjdstrbci 1 300 train
+dhjfpbanzk 1 298 val
+dhjkbdtpui 0 300 train
+dhjlbgiryl 1 300 val
+dhjmgdgkte 0 300 train
+dhjmzhrcav 1 300 train
+dhjnjkzuhq 0 300 train
+dhjreaoqpt 1 241 train
+dhjromtynd 1 300 train
+dhjtthuama 0 300 train
+dhjzyijhmm 0 300 train
+dhkcjwmviv 1 300 train
+dhkdjqwfhy 1 300 train
+dhkdlpxcbg 1 241 train
+dhkebfmrvu 0 300 train
+dhkqhrzkjo 1 301 val
+dhksnbiajq 1 300 train
+dhkwmjxwrn 1 300 train
+dhkwqxhujb 1 300 train
+dhlciyougq 1 300 train
+dhlibjhsri 1 301 train
+dhllwvavwx 1 300 train
+dhlnvxhtkj 1 300 train
+dhlpxgiilz 1 300 train
+dhlqlnupll 1 299 val
+dhlvedasty 1 298 train
+dhmbxpyvef 1 298 train
+dhmdcnvkbf 1 300 val
+dhmgfhlwzp 1 300 train
+dhmovshgex 1 300 train
+dhmqkfyqfu 1 300 train
+dhmqqvxntl 1 300 train
+dhmqtqggfb 1 300 train
+dhnbifolrc 1 300 train
+dhnocdtaqi 1 300 train
+dhnoqbblkm 1 300 train
+dhnpzlonzy 1 301 val
+dhnwvbcbnt 1 300 train
+dhoazaplgg 1 300 train
+dhobwtvijp 1 300 val
+dhogryadgy 1 300 val
+dholiupxyb 1 300 train
+dhomzpvtvj 1 300 train
+dhoqdkxnjt 1 300 train
+dhoqofwoxa 1 300 train
+dhorwydqmq 1 300 train
+dhosaybyih 1 300 train
+dhosilznxc 1 300 train
+dhoylnnsjr 1 297 train
+dhpbcfmalj 1 241 train
+dhpimkizlj 1 300 train
+dhpjfcwifb 1 300 train
+dhpmnokwfn 1 300 val
+dhprkfvrph 1 301 train
+dhprsxhlmn 1 301 train
+dhpsvaichc 1 300 val
+dhpwpbwqgc 1 301 val
+dhpxicqwzj 1 300 train
+dhpxrvdtkf 1 300 val
+dhqahhxvvs 0 300 train
+dhqqsbvxnl 1 300 train
+dhqvmfljrm 1 300 val
+dhryootdox 1 300 train
+dhryyolqbz 1 301 train
+dhrzxytixv 1 300 train
+dhsoohbbeb 1 300 train
+dhsoozhsoz 0 300 train
+dhspjmstbw 1 241 train
+dhstieibgq 1 300 train
+dhsvhffmmv 1 300 train
+dhsyqoquhs 1 298 train
+dhtcqaghxp 1 300 train
+dhteikxugk 0 300 val
+dhtfrptgwk 0 300 train
+dhtmhszncm 1 300 val
+dhtnlcuwwr 1 300 val
+dhtooynzzt 0 300 train
+dhtshmwlil 1 298 train
+dhtthatcww 0 300 train
+dhttlyoyhy 0 300 train
+dhtucqcqyc 1 300 train
+dhtvwqnqhm 1 241 train
+dhtwmsnrfb 1 300 train
+dhtwqllwch 0 298 train
+dhuglwfjwe 1 300 val
+dhujlrhlmc 1 300 train
+dhuvjvzqkz 1 300 val
+dhuvrjnggi 1 300 train
+dhuwisxryd 1 301 val
+dhuyuomvwv 0 301 train
+dhvakcuotf 1 300 train
+dhvhfxtqsw 1 300 train
+dhvibkkpax 1 300 train
+dhvmvczfhs 1 300 train
+dhvnzywyuf 1 250 train
+dhvojcmjnl 1 300 train
+dhvptyqhvg 1 300 train
+dhvtqqczev 1 300 val
+dhvxgjudyq 1 241 train
+dhweakfwyf 1 300 train
+dhwgibjqcm 0 297 train
+dhwmxiwkpw 1 300 val
+dhwsdumcee 1 300 test
+dhwvoebdjs 0 300 train
+dhwxqtgvoh 1 300 train
+dhxbntcvuc 0 300 val
+dhxctgyoqj 0 300 train
+dhxfrumvhh 1 300 train
+dhxmdqifot 1 300 train
+dhxrauqahg 1 300 train
+dhyevnqzak 1 300 train
+dhyskxqqkh 0 300 val
+dhyudevaol 1 300 train
+dhyybsrvwc 1 300 test
+dhyywwatda 1 300 train
+dhyzacnust 0 300 train
+dhzbdddomc 1 300 train
+dhzbzdwpcb 1 241 train
+dhzitkpnzx 1 300 train
+dhziybfuzk 1 301 val
+dhzmyolony 1 300 train
+dhzriznpjm 0 300 train
+diacloondv 1 300 train
+diagymsuhz 0 300 train
+diajihdtxa 1 300 val
+diajywffym 1 298 val
+dianuqbtho 1 300 train
+diaofnwlzs 1 300 train
+diaybfbnyc 1 301 train
+dibbkvwvoz 1 241 train
+dibdxgfyhd 1 300 train
+dibecibgso 1 300 train
+diberbfuum 1 240 train
+dibfzyynnf 1 300 train
+dibgdfklfh 1 241 train
+diblancvvk 1 300 train
+dibojbgexk 1 300 train
+dibrsdfptr 1 300 train
+dibuenxyfs 1 300 val
+dibwmyrpql 1 300 val
+dicbrgbutm 0 301 train
+dicdynesul 1 300 train
+dicfjxkgdb 1 300 train
+dicihlatwe 1 299 train
+dicjrvkjkw 0 300 train
+dicjvzaqyu 1 300 train
+dicsbspmdx 1 300 train
+dicvhmhhkg 1 301 train
+didjmaqpri 0 300 train
+didoywruyf 1 300 train
+didpqxskqw 0 298 val
+diduhnkheh 1 300 val
+didwlikulu 1 298 train
+didzujjhtg 0 300 test
+dieeubojvf 1 300 val
+diegrsidvu 1 300 val
+dieoechqok 1 298 train
+difaiqrpfu 1 300 val
+diffiazjjc 1 300 train
+diffnyuujk 1 298 train
+difjncqlff 0 300 train
+difjzyvozs 1 300 train
+difkouazrx 1 300 train
+diflfmvvpd 1 300 train
+diftwenggi 1 300 val
+digadpqbnq 0 300 train
+digbhpjocu 1 300 train
+diggduzsju 0 300 train
+dignydiols 1 300 train
+digodfuebj 1 300 train
+digvzzvyoe 1 300 val
+dihfbuguwe 1 300 train
+dihikfoowv 1 300 train
+dihitefqqa 1 299 train
+dihkifnikf 1 300 val
+dihltgtngr 1 300 train
+dihonregrl 1 300 train
+dihrobqfqz 1 300 train
+dihuyqyqps 0 300 val
+dihvecbwqc 1 300 train
+diiaolozpg 1 298 train
+diiuleqqgw 1 300 train
+diiznqknyh 1 300 val
+dijbnarhjk 0 300 train
+dijcpkqozj 1 300 train
+dijkaqwdja 1 300 val
+dijkbxqbtk 1 300 train
+dijkublluh 1 300 train
+dikjzdxxoa 1 300 train
+dikmwvppsb 1 300 train
+dikxglsnjb 0 300 val
+dikzljabcv 1 299 test
+dilexcbrjg 1 300 train
+dilfhyevdv 1 300 test
+dilfieqeyf 1 300 train
+dilfumvxqx 1 193 train
+dilqewlpmm 1 300 val
+diluxytget 1 300 train
+dilvamjaoj 1 300 train
+dilyraxdba 1 300 val
+dilzlejgic 1 300 train
+dimebwoajr 1 300 train
+dimeesrcmt 1 300 train
+dimiflrvgt 1 300 train
+dimizkqjfg 1 299 test
+dimkaxvksg 1 298 train
+dimlufgfja 1 300 train
+dimqkapwkw 1 300 train
+dimtezjmej 1 300 val
+dimusbjwxz 1 301 train
+dimxnfalvi 1 300 train
+dimzkihwpf 1 300 train
+dinrvqfpbi 0 302 train
+dinsbywbwl 0 300 train
+dinstxlajj 0 300 val
+dinswqpjsj 1 300 train
+dinukxjoce 0 300 val
+diocfoujvj 0 300 train
+dioegmuega 1 300 train
+diokmtvbvi 1 300 val
+diomeixhrg 1 300 train
+diopkeyxjz 1 300 val
+diopnptloj 1 300 val
+diopzaywor 1 300 train
+dioryfhfnn 1 300 train
+dioueusgrg 0 300 train
+dioxvkiwze 1 300 train
+diozrmqahq 1 250 train
+dipartetxi 1 240 train
+diphwhjcki 1 300 train
+dipkaieufh 1 300 train
+dipppokfel 1 300 val
+dipryfocll 1 300 val
+dipshxxebt 0 301 train
+dipsiuexxw 1 300 train
+dipswgfslu 1 299 val
+diptkcsvwb 1 300 train
+dipubiicum 1 300 train
+dipytjuprx 0 300 val
+diqqbcmidu 1 300 val
+diqraixiov 1 300 train
+dirbeupmwp 1 300 train
+direzlbdwo 1 300 train
+dirfuosarj 1 300 train
+dirivcdncx 1 300 train
+dirjtkcxaa 1 300 train
+dirmzyzqdc 1 300 train
+dirppabgwa 1 241 train
+dirulwdekh 1 300 val
+disbytpxhu 1 300 val
+disgdyizyu 1 300 train
+diskzkrrph 0 300 train
+disldvkasb 1 300 train
+disowjqgzc 1 300 train
+dissdcomdy 0 300 train
+disvnwrryr 0 300 train
+ditdcwjuik 1 300 train
+ditgggwqru 1 300 train
+ditgnohyeb 1 300 train
+ditgqvducp 0 300 train
+ditutizgrn 0 300 val
+ditygkvzml 1 300 train
+diuaptgufo 1 300 train
+diubkvruls 1 300 train
+diufxiirow 1 300 train
+diuhjlbgyi 1 300 train
+diuncaymhb 1 300 train
+diuoilvnvc 1 300 train
+diurmwqyer 0 300 train
+diuzlanscs 1 300 train
+diuzrpqjli 1 300 train
+divgvhztzk 1 300 train
+divhdosugi 1 300 train
+divvynaett 1 300 val
+diwhviwhgb 1 300 val
+diwiirjriq 0 301 train
+diwpgiikqw 1 300 train
+diwtzkfgpy 1 300 train
+diwuivuapl 1 300 train
+diwvlxzagw 1 301 train
+dixfznfyvg 0 300 val
+dixordmuzk 1 300 train
+dixsykufcf 1 300 train
+dixwhywudj 1 300 train
+diybhygcnh 1 300 train
+diybxapfbw 1 300 train
+diycjnntjf 0 300 train
+diydigppng 0 300 val
+diyktzofpg 1 300 train
+diymeordny 1 299 train
+diyokbalej 1 300 train
+diysftqqth 1 300 train
+dizdbidtor 1 300 val
+dizlbwkjjz 1 600 train
+dizocuazsa 1 300 val
+dizqlkthxv 1 300 train
+dizqwymrqj 1 300 train
+dizsnojczx 1 300 train
+diztudbgym 1 301 train
+djabgmttqg 1 300 val
+djagudgftt 1 301 train
+djapnntzvz 1 300 train
+djaxftnzkp 1 241 train
+djbfwqsvsb 1 241 train
+djbimbpwbg 0 300 train
+djbmrrjelb 1 300 train
+djbvbxioph 1 298 train
+djbvcsdbvc 1 300 val
+djbvorgtrq 0 300 train
+djbwgogtqo 1 301 train
+djbwlpybbr 1 300 train
+djbxnuqltp 1 300 train
+djchjxxndc 1 300 train
+djckwbjble 1 300 train
+djcokxuvqa 1 300 train
+djcuqtgccw 1 300 train
+djcwyyddya 1 300 train
+djdacdsbhz 1 241 train
+djdawhgbsk 1 300 train
+djdduzrkuh 1 300 train
+djdjaytlgk 1 300 val
+djdnxuqlbu 1 300 train
+djeichwqqe 1 300 train
+djelvxvyhb 1 300 train
+djewdrjaos 1 300 train
+djfxrzqitg 1 300 val
+djgbahezbh 1 300 val
+djgnqtpsls 1 300 train
+djgpowvmgj 1 300 train
+djgspuaqqp 1 300 val
+djgwmnjpes 1 300 train
+djhhnixfyi 0 300 train
+djhncpdcmo 1 300 train
+djhnisnmzs 1 300 train
+djibvjxokb 1 300 train
+djicfxwsff 1 300 val
+djicllbwff 1 300 train
+djikebdqdz 1 300 train
+djillmkele 1 300 train
+djiunqrpsb 0 298 train
+djivyntdpi 1 300 train
+djixyfrtbj 1 300 train
+djiypdbbfy 1 298 train
+djiysgzgpe 1 300 train
+djjafmdtxy 1 300 train
+djjdcnhlma 1 300 train
+djjdzsivvi 1 136 train
+djjgzhluss 0 299 test
+djjhidxwnx 1 300 train
+djjmyzkmsb 1 300 train
+djjtcotfqy 1 300 train
+djjtwjtymj 1 300 val
+djjveruyrx 1 300 train
+djjxkihpff 1 300 train
+djkheikoaj 1 298 train
+djkpbjrscp 1 300 train
+djksbwkzgg 1 300 val
+djkvxejnqm 1 300 train
+djkwstalvv 0 300 train
+djkzdbcfgb 1 300 val
+djlbwxsyud 1 300 train
+djlcalumnp 1 296 train
+djlgjbpuvk 1 300 train
+djlgnbnsle 1 300 train
+djlkkqmjkk 0 300 train
+djlpswbquk 1 241 train
+djlubjyhsj 0 300 train
+djmhmlpcrw 1 300 val
+djmijumxks 1 301 train
+djmkebnjsm 1 298 train
+djmluqgtqy 1 300 val
+djmormcyqu 0 300 train
+djmwdamqbh 1 298 train
+djmxwgcvur 0 300 train
+djmyetudka 0 300 train
+djmypxnzdp 1 300 train
+djnamxdumg 1 300 train
+djnbpintmy 1 300 train
+djncmccgpw 0 300 train
+djndkfmukp 1 301 val
+djneavvwdl 1 240 val
+djnjgsplgc 1 300 train
+djnratbpzx 1 300 train
+djnvjoilak 1 300 train
+djodnxisaa 0 300 train
+djoftlruau 0 300 train
+djogdzsrue 1 298 train
+djossucaoj 1 300 train
+djotkztepz 1 300 train
+djozjfcnwk 1 300 val
+djpakbpuym 1 300 train
+djpdyujvsf 1 300 train
+djphxzgkco 0 300 train
+djpjfgtxun 1 297 train
+djpqpucnni 1 300 train
+djprkltmkl 1 241 train
+djpxnbwxlj 1 300 train
+djqdxvbqlq 0 300 train
+djrfxolqxm 1 300 train
+djrirkhcuc 1 300 val
+djrlljilyk 1 300 train
+djrsjqtvry 1 300 val
+djrsxgienu 1 300 train
+djslhfgccm 1 300 train
+djtqvnnfyt 1 300 train
+djtsenhnhz 0 300 train
+djttvzkrat 1 301 train
+djtxjdqkhn 1 300 train
+djuegbrrwn 0 301 val
+djuglraptc 1 300 train
+djuglubovi 1 300 train
+djumgpchrn 1 300 train
+djurladqta 1 300 train
+djutslakvn 1 300 test
+djvbsnsiah 0 300 val
+djvnxbdhqg 1 300 train
+djvriiujey 1 301 train
+djvtbgwdcc 1 300 train
+djvustcyne 1 300 train
+djvutyvaio 1 300 train
+djvygkqnxw 1 300 train
+djvzkebwmq 1 301 train
+djwcqyqznx 1 300 train
+djwelrujhe 1 300 val
+djwshghuug 1 300 train
+djwtvksqup 1 300 train
+djxcmobexd 1 300 train
+djxdyjopjd 0 300 train
+djxjsfvxpf 1 300 val
+djxkovbayh 1 300 train
+djxlhgkyeg 0 298 train
+djxogftlxw 1 300 val
+djxtvdtmxx 1 300 val
+djxueugyoq 0 300 train
+djxwaiyzug 1 300 train
+djxwanozbb 1 300 train
+djxzdbgkcb 1 300 train
+djxzmbwtxh 1 300 train
+djyablngsv 1 298 train
+djycdroxqm 1 302 train
+djylanzkqq 1 300 train
+djynqeqhud 1 300 val
+djyrqupdes 1 300 train
+djytodyczi 1 136 train
+djywyeltzk 1 300 train
+djzdpqlzfe 1 300 train
+djzgiwbecd 1 147 train
+djzhafvcfh 1 300 train
+djzjzfzmel 1 300 train
+djzpxvypfp 1 300 train
+djzuwvejzr 1 300 train
+djzvnazioq 1 300 val
+djzyraaict 1 300 train
+dkabzvvurq 1 300 train
+dkadyyxwru 0 300 train
+dkaklaptww 1 300 train
+dkamfisevo 1 301 val
+dkayifawyz 1 300 train
+dkbhjjbmxj 1 300 train
+dkbjdbsfai 1 300 val
+dkbmrryekj 1 300 val
+dkbpvlmyhq 1 83 train
+dkbquepvwi 1 300 val
+dkbuvyatlu 1 300 train
+dkbxybibnh 1 300 val
+dkcdwhimur 1 301 train
+dkcffbwxex 1 100 train
+dkcieespqf 1 299 train
+dkdczdrfet 1 301 train
+dkdepkoqkz 1 300 train
+dkdwrocolx 1 241 train
+dkdwxmtpuo 1 300 train
+dkdxutvheq 1 167 train
+dkecafbtqe 1 300 train
+dkecoglfmz 1 300 val
+dkefhelpiw 1 300 val
+dkegmyzfmk 1 300 train
+dkeguzynhx 1 300 train
+dkeisysdhq 1 300 train
+dkemxsjleq 1 300 train
+dkenctaoes 1 300 test
+dkeontafvh 1 300 train
+dketpabwga 0 300 train
+dkeywucgch 1 300 train
+dkfwxzaabn 1 300 train
+dkfyvfjcpr 0 300 val
+dkgcdwzgyg 1 300 train
+dkgifcguyf 1 300 train
+dkglneowqx 1 300 train
+dkgmpgblsg 1 300 val
+dkgmpwbqde 0 300 train
+dkgrbxnchr 1 236 train
+dkgxdyqukq 1 300 train
+dkgxnghmhd 1 300 train
+dkgxsuavjw 1 300 train
+dkgxzcoogd 1 300 train
+dkhcbutgbr 1 300 train
+dkhdxcsjsk 1 300 train
+dkhiasuavk 1 300 train
+dkhlttuvmx 1 300 train
+dkhnnrhrbp 1 300 train
+dkhqkaagax 1 298 train
+dkhqtgxcwl 1 300 val
+dkicrqucgy 1 300 val
+dkiepbgzww 0 300 train
+dkihkgntwj 1 300 train
+dkiiqijowz 0 300 train
+dkionpuooh 0 300 train
+dkisuimzar 1 300 train
+dkjbpakqzz 1 300 train
+dkjbvvybxj 0 300 train
+dkjcqvvtbs 1 298 train
+dkjgufeexo 1 300 train
+dkjpdevbhw 1 300 train
+dkjpnomaek 1 300 train
+dkjxtelpyg 0 300 train
+dkkcehclxb 1 300 train
+dkkhttadsa 1 300 train
+dkknwsvdgo 1 300 train
+dkkqtmyitk 1 300 train
+dkkstelqip 1 298 train
+dkkvcedpkn 0 300 train
+dklboxskwf 1 297 train
+dkldmpfbzv 0 300 val
+dklhbdtcgz 1 300 val
+dklkqoaewo 1 297 train
+dklmzyvjpr 1 300 train
+dklnixwbsm 1 300 val
+dklogrdyuw 1 300 train
+dkloqbtpvq 1 300 train
+dklpvblwpi 1 300 val
+dklrmxxxbg 1 299 val
+dklyohebjb 1 300 train
+dkmesyoxlp 1 300 train
+dkmjzshlid 1 300 val
+dkmvbsyuqx 1 300 train
+dkmyaphiqy 0 300 train
+dkmybfdiif 1 300 val
+dkmyethaxs 0 300 train
+dkmymeoyyy 1 241 train
+dknnokrira 1 300 train
+dkntaifhkt 0 300 train
+dkntkrmlzb 1 300 val
+dknttybmxm 1 241 train
+dknuxhrkjd 1 300 train
+dknvuhubkf 1 241 train
+dkobxivwmn 0 300 train
+dkofkxrhng 1 300 train
+dkojxwpvza 1 300 test
+dkormeyalv 1 298 train
+dkovkjfxwp 1 300 train
+dkozrbjxgo 0 300 train
+dkpegbxels 1 300 train
+dkphahwdrr 1 300 test
+dkpktsratf 1 300 train
+dkpomvbzfh 1 300 train
+dkppjpbuul 1 300 train
+dkpptjnocr 1 300 train
+dkpvmylcug 1 300 train
+dkpyqdwlnp 1 300 train
+dkqbuhxzbn 1 300 train
+dkqgphgzgf 1 300 val
+dkqitkradr 0 300 train
+dkqwmjuvky 1 300 test
+dkqzxeudzp 1 300 train
+dkqzymfxoa 1 300 train
+dkrbsnfodn 1 300 val
+dkrbtzkvnu 1 300 val
+dkregyjasx 1 300 train
+dkrgbzdtot 1 300 train
+dkrgfpeoft 1 299 val
+dkrjqyfgxb 1 300 train
+dkrknynayu 1 300 train
+dkrljzjwhv 1 300 train
+dkrmpyuopv 1 300 val
+dkrvorliqc 1 300 train
+dkrvyhjerb 0 300 train
+dkscekqovq 1 300 train
+dksitwzgcb 1 299 test
+dksuvwpvpb 1 300 train
+dkszaydwxj 1 300 train
+dkszwvfwxb 1 300 test
+dktderbnzg 1 300 train
+dktpniyvec 1 300 test
+dktuqozmst 1 300 train
+dktvjujnqu 0 300 train
+dktwmkgcrz 1 300 train
+dktwpdpgqs 1 300 train
+dktyccouxk 1 300 train
+dktywrlqgu 1 300 train
+dkuayagnmc 0 300 train
+dkuekmvqoy 1 300 train
+dkuezmicux 1 300 train
+dkugeqviqc 1 301 train
+dkuinmlpya 1 300 train
+dkuotqaois 1 298 train
+dkuqbduxev 1 299 test
+dkuuejqoss 1 300 train
+dkuvktiywb 1 300 val
+dkvbdmljkx 1 298 train
+dkvedxqgma 1 300 train
+dkvjyzylod 1 300 train
+dkvpjzyzxb 1 301 train
+dkvtqnqtoe 1 300 train
+dkvxzocpnx 1 300 train
+dkwcabgddi 1 300 val
+dkwhpqqqaf 1 300 train
+dkwjpcktel 1 300 train
+dkwjwbwgey 1 300 train
+dkwqlxestq 1 300 val
+dkwvrllpyw 1 300 train
+dkwylvczij 1 301 train
+dkxbvpgztu 1 300 train
+dkxermeyac 1 300 train
+dkxgpxbuuy 0 300 train
+dkxirsrsxe 1 300 val
+dkxnxxfnlf 1 300 val
+dkxoetnbtq 1 301 val
+dkxpudymjc 1 300 train
+dkxsrhspqf 0 300 val
+dkxttrzfuj 1 300 train
+dkxvaivjvu 1 300 train
+dkxyfdytbs 0 300 train
+dkyavhnmte 1 298 train
+dkyboeoika 1 300 val
+dkyiumiwwa 1 300 train
+dkyodzomms 1 300 train
+dkyxezptsu 1 300 train
+dkyztnifza 1 300 train
+dkzdguggob 1 300 train
+dkzeuuyydv 1 300 train
+dkzinomdzy 1 298 train
+dkztuuoshv 1 300 train
+dkzvdrzcnr 0 300 train
+dkzvhtkenl 1 300 train
+dkzvoxskbu 0 300 train
+dlabmdtxzx 1 300 train
+dlafhoqylr 1 298 train
+dlaibvrubs 1 300 train
+dlalkoiknc 1 300 train
+dlalzhjmbs 1 300 train
+dlandpsogt 1 300 train
+dlawwdzkpq 1 301 train
+dlazwrjveu 1 300 train
+dlbjulbwea 1 300 train
+dlbxnfthal 1 300 train
+dlcbmdkbxz 1 300 train
+dlccyuailb 1 300 train
+dlckdleyaj 1 300 train
+dlcxmytdht 0 303 train
+dlcygyhvit 1 300 train
+dlcyhjqdnx 1 301 train
+dldaiqtavj 1 300 val
+dldqhbmebe 1 300 train
+dldqqfksyo 1 300 train
+dlealirddu 1 241 train
+dlebjfujap 1 300 val
+dledljarkv 1 301 train
+dleeobecxq 0 300 val
+dlekrblqwh 1 300 train
+dlekvfkuum 1 300 val
+dlelgvsnae 0 300 train
+dletmwhegv 1 300 train
+dleybnbuli 1 300 train
+dlezhlbjtu 1 300 train
+dlfiwkeohj 1 300 val
+dlfjgxzokr 0 300 train
+dlfpswdhxj 1 301 train
+dlftdxouov 1 300 val
+dlfubjxywg 1 300 train
+dlfuxshert 1 300 test
+dlfyulzzzg 1 300 train
+dlgcycscay 1 300 train
+dlgdmbvxux 0 300 train
+dlgdrwttie 1 300 val
+dlgjkofxgn 1 300 val
+dlgrgmkmpa 1 300 val
+dlhbkziruq 1 300 val
+dlhdsvrnzb 1 300 train
+dlhfzmukfy 1 300 train
+dlhibcsuow 1 300 val
+dlhnapxhem 1 300 train
+dlhxjopbmh 1 297 train
+dlhzfvfgzh 1 300 train
+dliajpqpqd 1 298 train
+dliapdgfsg 0 300 train
+dlildirhub 1 300 train
+dlitymspeh 0 300 val
+dliyzirjpg 1 300 train
+dljbvhseze 1 300 train
+dljegkgcan 1 300 train
+dljlvmwhvy 1 301 val
+dljvfmkkpo 1 302 train
+dlkifxjpem 1 301 train
+dlkjimbdzz 0 301 train
+dlkkuolvdk 1 300 train
+dlknkizxrw 1 300 train
+dlkrgjuion 1 302 train
+dllbhbekzq 1 301 val
+dllbihqseo 1 301 train
+dllkubdbbd 1 300 train
+dlllcetqbw 1 300 train
+dllsdwuguy 1 300 val
+dlmbhowqxi 1 300 train
+dlmfukhdrj 0 300 train
+dlmgyhgvlp 1 300 val
+dlmiesrmus 1 298 train
+dlmsssszbk 1 300 train
+dlmvgbbueg 1 299 train
+dlmxaewmvu 1 240 train
+dlndwdwdus 1 301 train
+dlnfsqpfcd 1 241 train
+dlnjkyisav 0 300 val
+dlnjrfpijz 1 300 train
+dlnlmwpeim 0 299 val
+dlnpkmiytm 1 298 train
+dlnprrpsmp 1 300 val
+dlnuhhvidb 0 300 train
+dlnxsfbljv 1 300 train
+dlocdopjks 1 300 train
+dlofrcvqon 1 300 train
+dlogguklox 1 300 train
+dlohmggfrd 1 300 train
+dlormpqeif 1 300 train
+dlounjvdro 1 300 train
+dlpaibcwsy 1 300 test
+dlpbbtzxpb 1 298 train
+dlpcktczyw 1 300 train
+dlpczexqmx 1 300 val
+dlpebwsuxg 1 300 train
+dlpirjuvwi 1 301 train
+dlpnmuttlc 1 300 train
+dlpoieqvfb 0 300 train
+dlpvnxljzj 1 300 train
+dlpwjhrpte 1 300 train
+dlqhpqmmdo 1 298 train
+dlqlsfshcb 1 301 train
+dlqnvkhamn 1 298 train
+dlqouiqfue 1 300 train
+dlqpqyyuqa 0 300 train
+dlqqieidqo 1 241 train
+dlrcprykef 1 300 test
+dlrfpvskey 1 300 train
+dlrooyspqx 1 300 train
+dlrsbscitn 1 300 train
+dlsdmdraln 1 300 train
+dlsfpstkyc 1 301 train
+dlshgknsmq 1 300 train
+dlsjlzhdhq 1 300 train
+dlsmnasyop 1 300 train
+dlsozadwpv 1 301 train
+dlsyzwsswg 1 300 train
+dlszenqhfh 1 301 val
+dlszoejyjb 0 300 train
+dltcxwwyur 1 299 train
+dltgqtawem 1 300 train
+dlthzbremc 1 300 train
+dltoduaeaj 1 300 train
+dltpcveooo 1 300 train
+dluaxfukbh 1 300 val
+dlueqbzqcr 1 301 val
+dlufcxywgr 1 300 train
+dluimsdhnk 1 301 val
+dluknggcwk 1 300 train
+dlumllgytg 1 298 val
+dlunuacjdp 1 300 train
+dluqlzodmm 1 300 train
+dlusyyhtkp 1 300 train
+dlutdhjhil 1 300 train
+dlutncnhce 1 300 train
+dluvgfzvdm 1 298 val
+dlvnemluto 1 300 train
+dlvutmncux 1 298 train
+dlvuwljayy 1 300 train
+dlvvnxsmyt 1 300 train
+dlvxejwbzc 1 299 val
+dlwczwqwer 1 300 train
+dlwieyjybu 1 300 train
+dlwmbadytf 1 300 train
+dlwnorskhy 1 300 train
+dlwsmydcez 1 300 val
+dlxbkrdozc 1 301 train
+dlxltrvfmf 1 300 train
+dlxqdncwsh 1 300 val
+dlxrbkclme 1 300 val
+dlxvbfdfny 1 299 test
+dlxzvkrwkw 0 300 train
+dlyaicbqly 0 300 val
+dlybulufda 1 300 test
+dlyjdhxkrg 1 300 train
+dlyjnyshxu 1 300 train
+dlykfuvmvi 1 300 val
+dlykyjfanz 1 299 test
+dlyolaisdz 0 300 train
+dlyolvvvxs 1 300 train
+dlypiobnna 1 300 val
+dlyquphdcc 1 300 train
+dlyrqlgvcd 1 300 train
+dlyuvbycaf 0 300 train
+dlyxngqflj 1 301 train
+dlzcradrsq 1 301 val
+dlzdyyzzav 1 300 train
+dlzgfcuqmr 1 300 val
+dlzptoehia 1 300 train
+dmabuhmyel 0 300 train
+dmacbstebm 1 300 train
+dmadqljrab 0 300 train
+dmafzlffwj 1 300 train
+dmagghegra 1 300 val
+dmaijbeylk 1 300 train
+dmanrluert 1 300 val
+dmapgveuyw 1 300 val
+dmaqwzrgkr 1 300 train
+dmavufuqqy 1 300 val
+dmawbjbiua 1 300 train
+dmaxnzeyak 1 301 val
+dmbdlhkmmy 1 300 train
+dmbhjotdud 1 300 train
+dmbsofuonu 1 300 train
+dmbtnshrxm 1 300 train
+dmbwijgszl 1 300 train
+dmcaboiwzd 1 300 train
+dmcaggggkm 1 300 train
+dmchxgiecw 1 300 train
+dmcnsuwsin 1 300 train
+dmcoprtasg 1 300 train
+dmcoyrrlbl 1 300 train
+dmcvlfcjfq 0 300 train
+dmczblhcdt 1 300 train
+dmddngkhes 1 300 val
+dmddxqzfgv 1 241 train
+dmdfeqjmpe 1 300 train
+dmdgfhqhnb 1 300 train
+dmdhwpgbtx 1 301 val
+dmdlomfigx 1 300 train
+dmdseiicjy 1 300 train
+dmdskkrzbc 1 300 train
+dmdsqhprqw 1 300 train
+dmduprrrmo 1 300 val
+dmdxvemtwk 1 300 train
+dmeabvsmmv 1 300 train
+dmebceoylu 1 300 train
+dmecajzxbx 1 300 train
+dmegwsvycz 0 300 train
+dmehxjzdmv 0 300 train
+dmelcppgzc 1 300 train
+dmepwdmccf 1 300 train
+dmewkotpkc 1 298 train
+dmfaqzikrh 1 300 train
+dmfavqmkab 1 300 train
+dmfaxuiwtx 1 300 train
+dmfbovabjd 1 300 val
+dmfednlroq 0 300 val
+dmfehdckry 1 300 train
+dmffmleqcu 1 300 train
+dmffyzgacu 1 300 train
+dmfkfwoeck 1 300 train
+dmfqkkdznx 0 300 train
+dmfqzqdvzp 0 300 train
+dmfvucvzaz 1 300 train
+dmfwkudogi 1 298 val
+dmfysraiiw 1 300 train
+dmgafmocjl 0 300 train
+dmgjhisfnt 1 300 train
+dmglxkgztg 1 300 val
+dmgooiimwk 1 301 train
+dmgqebtztr 1 240 train
+dmgshaefup 1 300 train
+dmhfnqvxnn 0 249 train
+dmhfssknop 1 300 train
+dmhsizbghm 1 300 train
+dmicabusaq 0 298 val
+dmiiejxcjt 1 301 train
+dmirhwrgrn 1 299 val
+dmirtsrziw 1 300 train
+dmirvrfrmu 1 300 train
+dmisapphyk 1 300 train
+dmitvectsn 0 300 train
+dmitzbstzi 0 300 train
+dmjfjrhnpg 1 300 train
+dmjoqbsuei 1 300 train
+dmjosocqkk 1 298 train
+dmjozwexzt 1 300 train
+dmkcvmdmoa 1 302 train
+dmkjvscdeb 1 300 train
+dmkunvmasn 1 300 train
+dmkyqxbryo 1 300 train
+dmlagmugqs 0 300 val
+dmlcieoidq 1 300 train
+dmlhemyrzi 1 300 train
+dmlivhmsng 1 300 val
+dmllscpmpp 1 300 train
+dmloghrqpa 1 300 val
+dmlxckjzqe 1 300 val
+dmmdfzagvm 1 300 train
+dmmuakrefq 0 300 train
+dmmvcdxqdf 1 300 train
+dmmvuaikkv 0 300 test
+dmncqbxnqx 1 300 train
+dmncsnzmsa 1 300 train
+dmndsesdsu 1 300 train
+dmneorhwcl 1 300 train
+dmniibimgn 1 300 train
+dmnurdpswv 1 300 train
+dmnybhfwmq 1 300 train
+dmoctfubep 1 301 train
+dmofpnicbm 1 300 train
+dmojakcdxx 1 300 train
+dmojmqfpum 1 300 train
+dmokusotwn 1 300 train
+dmomurmnec 1 300 train
+dmonugzxlo 1 300 train
+dmouivbjkm 1 300 train
+dmovryfvuu 0 301 train
+dmovwthrda 1 300 train
+dmoxkaeico 1 300 train
+dmoyfrklmr 1 300 val
+dmpacchzdi 0 301 train
+dmpdwoqnae 0 300 val
+dmpeqobntf 1 300 train
+dmpfxquzrt 1 300 train
+dmphhphtam 0 300 train
+dmpitetrcj 1 300 train
+dmpixxdphy 1 300 val
+dmpltevlxb 1 300 train
+dmpmeqiafv 1 300 test
+dmpvbeyuqb 0 299 val
+dmqjmpuosu 1 300 train
+dmqucqdxsa 1 300 train
+dmqwuutqun 0 300 train
+dmqydcvmyy 1 300 train
+dmqzbafcfn 1 301 train
+dmraadymhi 1 300 train
+dmrpezpjbz 1 300 train
+dmrrjilqgw 1 300 train
+dmrujnuzme 1 300 val
+dmsbpidqka 0 300 train
+dmsjoitbsh 1 300 val
+dmskuexabl 0 300 train
+dmspiciqdb 1 300 train
+dmspqijafg 1 301 train
+dmtiqmuczr 1 299 train
+dmtjqgbezd 0 300 train
+dmtsxclujy 0 299 train
+dmtwohxhgt 1 298 train
+dmtzpjvfhz 1 300 val
+dmubrkqxvd 0 300 train
+dmueaxtkcm 1 300 train
+dmuhzrcbfa 0 300 train
+dmujirwhrl 1 296 val
+dmulgzyxhb 1 300 train
+dmuovykqam 1 300 train
+dmupfdcvca 0 299 val
+dmurhipwia 1 300 train
+dmuuiayoqv 1 300 train
+dmvaerdrfi 1 300 train
+dmvalkjehr 1 299 test
+dmvcaldnnd 1 300 train
+dmvcpbknnl 1 299 val
+dmvflcclof 0 301 train
+dmviwgcyoo 1 300 train
+dmvjnawoob 1 300 train
+dmvnzlhpgm 1 300 train
+dmvpndjgky 1 300 train
+dmvrobtdon 1 300 train
+dmvzryjzbe 1 300 train
+dmwctqmxjt 1 299 train
+dmwmhxvlfq 0 300 train
+dmwrmxwctp 1 300 train
+dmxawpehkh 1 300 train
+dmxcrspnga 1 300 val
+dmxdbdjjlx 1 300 train
+dmxinfvegm 1 300 train
+dmxjlskdid 1 300 val
+dmxrickror 1 301 train
+dmxtgritbe 1 299 val
+dmxwithiff 1 300 train
+dmxwrjusxm 1 300 train
+dmyaexuqpr 1 299 test
+dmykzzflrk 1 300 val
+dmyojxbjac 1 300 train
+dmyrdvcubh 1 300 train
+dmysxqhhkd 1 300 train
+dmytcpilbn 1 301 train
+dmyydmewnv 1 300 train
+dmyyvzpjjg 1 300 train
+dmzblkdwkv 0 298 train
+dmzbzcjsrg 1 300 train
+dmzfhikjjo 1 300 train
+dmzfqeunkp 1 269 train
+dmzllitzih 1 301 train
+dmzrorvosy 1 300 train
+dmzupwmxjo 1 300 train
+dmzvddfasl 1 300 val
+dmzyfcvisd 0 300 val
+dnakbmafvh 1 300 train
+dnaoszqxag 1 300 train
+dnargmsmdp 1 300 train
+dnarvuxikn 1 300 train
+dnavpslhmy 1 300 train
+dnbfywraiv 1 300 train
+dnbgijcsux 1 300 train
+dnbnqzidxy 1 300 train
+dncoebkxpv 1 300 train
+dncrxghnzv 1 300 val
+dndanmuscq 1 300 train
+dndkqnciqg 1 300 train
+dndpcusmgh 1 300 train
+dndpfhgmlx 1 300 train
+dndurwfpfx 1 300 train
+dndvdfwmme 1 298 train
+dnebeevzpl 1 300 train
+dnebyzfvzt 1 300 val
+dnecilutfg 0 300 train
+dnediuiaxy 1 300 train
+dneghxhqsr 1 300 train
+dneleizoxr 1 300 val
+dnepnrozau 1 300 train
+dnexlwbcxq 1 300 train
+dnfahbzaso 1 301 train
+dnfbyrzhcd 0 300 val
+dnfcolcnti 1 300 train
+dnfeattxrj 1 241 train
+dnfgmxwsya 1 300 train
+dnfgnczzsv 1 300 val
+dnfiiyjqrp 1 300 train
+dnfkbndbyu 1 301 train
+dnfnxwbsoi 0 301 train
+dnfpebppiq 1 300 val
+dnfvyzhnfh 1 300 train
+dnfwbrgude 1 300 train
+dnfwikkuzy 1 301 val
+dnggmfefgr 1 300 train
+dngjwhptgl 1 300 val
+dnglqxxhet 1 300 train
+dngtoszjnq 1 300 test
+dngvaozylo 1 300 train
+dngwozfwzc 0 300 val
+dnhaskulaj 1 300 train
+dnhavqrzzy 1 300 test
+dnhdqryijq 1 300 train
+dnhgsywgkk 1 301 val
+dnhhjzvbkh 0 300 train
+dnhijyqzac 0 300 train
+dnhlbpayyl 1 301 val
+dnhlwyzwtx 0 300 train
+dnhotbpzzg 1 300 train
+dnhpnvkcgg 0 300 train
+dnhrhanrko 0 300 val
+dnhsllnrnv 1 299 train
+dnhtodemdj 1 241 train
+dnhukpuvpu 1 299 val
+dnhvalzvrt 1 300 train
+dnibqijexs 1 300 train
+dniemnknoe 1 300 train
+dnigdffplp 1 300 train
+dnihlqpfgp 1 300 train
+dnijmsuvkw 1 300 val
+dniqrablyi 1 300 train
+dnirzrdpcv 1 300 train
+dnitqucxqk 1 300 train
+dniuvmzefk 1 300 val
+dnivqoazsj 1 300 train
+dnjfgytdik 1 298 train
+dnjjjmdbos 1 301 train
+dnjlbgljyf 1 300 val
+dnjuncschk 1 298 train
+dnknqbdveu 1 300 train
+dnksorsbcm 1 300 train
+dnkyxprnak 1 301 val
+dnkzwngwpf 1 290 train
+dnlahnvtqk 1 300 train
+dnlckoyatl 1 241 train
+dnldfqdbtz 1 301 train
+dnlghyhgfj 0 300 train
+dnlknpyxpb 1 300 train
+dnlqdcchcz 1 300 train
+dnlshtnedx 1 300 train
+dnlutroxpg 1 299 val
+dnlxklfacs 1 300 train
+dnmbdkyxdu 1 300 train
+dnmcncqkmc 1 270 train
+dnmgjhucsj 1 300 train
+dnmhntrzck 1 300 train
+dnmjiyjodh 0 300 train
+dnmmadauqi 1 297 val
+dnmowthjcj 0 300 test
+dnmpnubwvr 1 301 train
+dnmwkvqpey 1 300 train
+dnnagoloqb 1 300 train
+dnncgzntsk 0 300 val
+dnnqfvdmmd 1 300 train
+dnnvqoyckz 1 300 train
+dnoccqrtoa 1 300 val
+dnocqlgupe 0 300 train
+dnofupbivz 1 300 train
+dnoimqvpmr 1 300 val
+dnomkfoccj 0 300 train
+dnonhfcjly 1 300 train
+dnonvgmeyp 1 300 train
+dnpophoqao 1 300 train
+dnpsruulvw 1 300 val
+dnpugxwblh 0 300 val
+dnqmxlztsc 1 300 train
+dnqnopitea 1 300 val
+dnqnpoozlk 1 241 train
+dnqobuqalm 1 300 train
+dnqrsjllbn 1 300 val
+dnquugxkdd 1 301 train
+dnqzawqirl 1 300 train
+dnratobdph 1 300 train
+dnrewgaafp 1 241 train
+dnrjdywjfe 0 300 train
+dnrkgzrzfo 1 300 train
+dnrnfypstq 1 301 train
+dnrojrvdrw 1 300 train
+dnrpknwija 1 300 val
+dnrqehggwv 1 300 val
+dnrsykxfty 1 300 train
+dnrtqvvxbn 0 300 train
+dnrttdylqa 1 301 train
+dnrydtpjus 1 300 train
+dnsbzdjxsv 1 299 train
+dnscnhmmcf 1 300 train
+dnsflgnpvm 1 300 train
+dnsloadbnj 1 300 train
+dnsntuccbs 1 298 train
+dnsokgitxl 1 301 train
+dnsucvukoa 1 300 train
+dnswxamjjt 0 300 val
+dntajpwava 1 301 train
+dntgzwqitj 1 300 train
+dntihcoxuv 0 300 train
+dntjlmjpwy 1 300 train
+dntkzzzcdh 1 300 train
+dntrbkorwb 1 255 train
+dntvoisebj 1 241 train
+dntzhkxgsb 0 300 train
+dnublilpww 1 300 train
+dnudxitpqj 1 300 train
+dnuejnupba 1 300 train
+dnueovapgb 1 298 train
+dnugrjawlu 1 300 train
+dnulrpyfuc 1 300 train
+dnuponkdfa 1 300 train
+dnvabpqnxg 1 300 train
+dnvedqxvcb 1 298 train
+dnvkjrkqbn 1 300 train
+dnvmoabipt 1 301 train
+dnvrbqxhqz 1 300 train
+dnvrzekhov 1 300 val
+dnvtqaalwe 0 300 train
+dnvtzzshdn 1 300 train
+dnvxraeele 1 301 train
+dnvystgwyo 1 300 test
+dnwambsaat 1 300 train
+dnwfukbbcn 1 300 train
+dnwhoboviz 1 300 train
+dnwkkrblcw 0 300 val
+dnwkqvsdtm 1 300 train
+dnwmnttyfe 1 300 train
+dnwohsnyob 0 300 train
+dnwpesywuh 1 300 val
+dnwxaxuycx 1 301 train
+dnwxtoktds 0 300 train
+dnwxvwwlah 1 300 val
+dnxdioczln 1 292 val
+dnxpsqsuil 1 300 train
+dnyctpfgzw 1 300 train
+dnydftpgky 1 300 train
+dnydntpsxb 1 300 train
+dnyitmhhrs 0 300 val
+dnyvfblxpm 1 300 train
+dnywvdsosx 1 297 val
+dnzntxvurw 1 300 val
+doadvmmbxa 1 300 val
+doagslzeae 1 300 val
+doaisfmawr 1 300 train
+doakqmxxzv 1 299 val
+doaldjpsgv 1 298 train
+doalobnktb 1 299 train
+doalrnxyew 1 300 train
+doanjploai 1 300 train
+doaspsgipf 1 301 train
+doazeldxul 1 300 train
+doblwjidzf 1 300 train
+dobmkyconz 1 300 train
+dobniqrlak 0 300 train
+doboalxzro 1 300 train
+dobwpmxxvi 1 300 val
+dobxxgyzwu 1 300 train
+dobyrqmayi 0 300 train
+dobzieuwxn 1 300 val
+docchtqdao 1 299 val
+docuahlbto 1 300 train
+dodfndjpmz 1 300 val
+dodfzufutw 1 300 val
+dodkrhonrn 1 300 train
+dodrguajhf 1 300 train
+dodurbokmz 1 300 train
+dodwessgpl 1 300 val
+dodxnceoup 1 300 train
+doebcumxik 1 300 val
+doeeuppytb 1 300 train
+doegnmrokq 1 300 val
+doeijjugxc 1 300 train
+doejawfgnh 1 301 train
+doemehunwj 1 300 train
+doenbaqrnu 1 292 val
+doesctevfp 1 300 train
+doeuqrqbmr 1 299 test
+doevunlyyt 1 302 val
+doewhdhrdk 1 300 train
+dofcqhsrhb 1 301 val
+dofcvzsqno 1 300 val
+dofevevzhw 0 300 train
+doffbmajbk 1 300 train
+doflmqmoba 1 300 train
+dofnheuvhu 0 300 val
+dofnhnvaxq 0 300 train
+dofuliykpv 0 300 train
+dofusvhnib 1 300 train
+dofuttfapq 1 240 train
+dofxakipma 1 300 train
+dogdekomvf 1 300 val
+dogeflmobs 0 300 train
+dogenbgabh 0 300 val
+doggrkigkp 1 300 train
+dogibysjkl 1 300 train
+dogotzkdiw 0 300 train
+dogyedeobq 1 300 val
+dohbueaisb 0 300 train
+doheugxdet 0 300 train
+dohidzgzqj 1 300 train
+dohoyaxwsb 1 300 train
+dohqoffamf 1 300 train
+dohrhnryln 1 300 val
+dohuhkcebr 0 300 train
+dohxwgpugw 1 300 val
+dohyajgpym 0 300 val
+doieimouer 0 300 train
+doiljuhamq 1 300 test
+doilpljcoj 1 300 val
+doilqiprwr 1 300 train
+doiwcojvgj 1 300 train
+doiwjltgpc 1 300 train
+doixgrmkib 0 302 train
+dojaxngjak 1 300 train
+dojiveigog 0 300 train
+dojnabaoug 1 298 train
+dojorsyreo 1 300 train
+dojtnxqdrq 1 300 train
+dokclgqjgu 1 300 train
+doksubaxju 1 241 train
+dokufsogvh 0 300 train
+dokwdsjpky 1 241 train
+dolgepsqdl 1 298 val
+dolgjagncn 1 300 val
+dolkpkhsnp 1 249 train
+dolldwzcmg 1 300 train
+dolxsahxwn 1 300 val
+dolynaukae 1 300 test
+domdfrvzol 0 300 train
+domhbvrfyc 1 300 val
+domhnipkeh 0 300 train
+domlgntwvg 1 300 train
+domsajovzs 0 300 train
+domzpupdnm 1 300 train
+dondnshrhl 1 301 val
+doniqevxeg 0 300 test
+donlceyfem 1 300 train
+donrqywxxu 1 301 train
+dontjoarqe 1 300 train
+dontwxbnza 1 299 val
+donxqcyuiw 1 298 train
+donzzpwvcz 1 300 train
+doocsurzzi 1 300 val
+dooklnzike 1 300 val
+dootttqtvv 1 300 test
+doovpeutgl 1 301 train
+doowkwavvj 1 300 train
+dopcfoclfq 1 300 train
+dopcoxsotn 0 300 train
+dopphjahir 1 300 train
+doprgfnryn 1 300 train
+doprsfvjxz 1 301 val
+dopszhdhgr 1 300 train
+doptetuggv 0 300 train
+dopulvkqip 1 301 train
+dopxldqkao 1 302 train
+dopyarkmwh 1 300 train
+doqiitaizz 1 302 train
+doqkuqoqlj 1 300 val
+doqrblvpxr 0 300 train
+dorerwjhvj 1 299 test
+dorgwfxgrc 1 300 train
+dorkzruqpe 1 301 train
+dorqiyjsod 1 300 train
+dortpogjfp 1 298 train
+doruflroku 1 300 train
+dorwcbfmzu 1 301 train
+dosdrthwyv 1 300 train
+dosezavwhq 1 300 train
+dosjwmjzrx 1 300 train
+dosmbazarb 1 240 val
+dosnxvkzgf 1 300 train
+dosoafcydc 1 300 train
+dostcqonsd 1 300 train
+dostozbsco 0 300 val
+dosvlktrae 1 300 train
+dosvmrkqws 0 300 train
+dosxnpwvhk 0 301 train
+dosycnfjgb 1 147 train
+dotcqkywul 1 298 train
+dotnqbskng 0 300 val
+dottjvwxqm 1 300 val
+douhtkotpu 1 300 train
+doujpiwzkc 1 300 train
+doulkankti 1 302 train
+doulpzhrvz 1 300 val
+dousbnlwam 0 300 train
+douuspmzao 1 300 train
+dovbqeieek 0 300 val
+dovdrtvmbx 0 301 train
+doveoojfbg 1 300 train
+dovonxgzrn 1 300 train
+dovorvqcgi 1 300 train
+dovqhphfgy 1 300 train
+dovrnmwucz 1 300 train
+dovwkrokru 1 300 train
+dovwvzocwl 1 300 train
+dovxgqhsst 1 298 train
+dovzpopzop 1 301 train
+dowcqibizd 1 300 train
+dowjbnujnf 1 300 train
+dowlmdskun 1 300 train
+downwsebge 1 300 val
+dowopnjsjm 0 300 train
+dowpslozxr 1 299 train
+dowybibeqv 1 300 train
+doxeyanlla 1 300 train
+doxmeuhnpt 1 300 train
+doxxwkyeyy 1 300 train
+doycefznlf 1 298 train
+doydmpebcj 1 300 train
+doyfynweis 1 300 train
+doyimainin 1 300 train
+doyllvberx 1 300 val
+doyxphntti 1 300 train
+dozbdewilw 0 303 train
+dozdjdnsrl 0 300 train
+dozfsckcsr 1 300 train
+dozjwhnedd 1 299 test
+dozrpobgop 1 300 train
+dozsfriylc 1 300 train
+dozswzstib 1 300 val
+dozyddhild 1 298 train
+dozzypcnjm 1 300 val
+dpacxirzme 1 300 train
+dpalrcaliw 1 300 train
+dpamitiitr 1 300 train
+dpamqgszdc 1 300 train
+dpapdldidi 1 298 val
+dpaqaxgzon 1 302 train
+dpawhrkwba 1 297 train
+dpaxfhgmyr 1 241 train
+dpbleikabh 1 300 train
+dpbobkmnup 1 241 train
+dpbojjwctj 1 300 train
+dpbuogncla 1 297 train
+dpbzxxwaxo 0 240 val
+dpcahzyjmo 1 300 train
+dpcbuydqaz 1 300 train
+dpcjmehsby 1 300 train
+dpcjtfkcgc 1 300 train
+dpcnkzulmt 0 301 val
+dpcsinlpgj 0 300 train
+dpcxlbefqa 1 300 val
+dpdeszoxlp 0 300 train
+dpdjjmqwqn 0 300 val
+dpdnxtforx 1 240 train
+dpdpkevreu 1 300 train
+dpdqwygcrc 1 299 test
+dpeehtnctk 0 300 val
+dpegbdzijf 0 300 train
+dpegwtsswh 1 300 train
+dpekatbxlr 1 300 val
+dpesoimjjo 1 300 train
+dpetoqdajw 1 300 train
+dpevefkefv 0 300 test
+dpevhliuec 0 300 train
+dpevppxaaz 1 300 train
+dpextyywdr 1 300 val
+dpfdxyzenz 0 300 train
+dpfjhklovx 1 300 train
+dpfnuntgwh 1 300 train
+dpfswsxknq 1 300 train
+dpfuqzdtrs 1 300 train
+dpfygjvurs 1 300 train
+dpfzykxteg 1 299 val
+dpgaegossz 1 300 train
+dpgejlhueq 0 300 train
+dpgjudbvus 0 300 train
+dpglsmiqwm 0 300 val
+dpgxrxlmqj 1 300 train
+dpgznlwvpx 0 300 train
+dphivdjboy 1 300 train
+dphliwleqr 1 301 val
+dphpvmgpbp 1 300 train
+dphqaflxdo 1 300 val
+dphqkybvto 1 300 train
+dphtzcswiu 1 300 train
+dpiaqritba 0 300 train
+dpigbbkerv 1 300 train
+dpihmcmpfq 1 241 train
+dpihwwnser 1 300 train
+dpilxkugfs 0 300 train
+dpioueayis 1 300 train
+dpirglafro 1 300 train
+dpiynoeiwp 1 300 val
+dpjfwtafke 1 300 test
+dpjghtzvko 1 295 train
+dpjvdjeduu 0 300 train
+dpjzcvczif 0 300 train
+dpkbgifccb 1 300 train
+dpkbvkgfwq 1 300 train
+dpkmuaoqnx 1 300 train
+dpkpwadajp 1 298 train
+dpkpxmsfeo 1 298 val
+dpkucbpexr 0 300 train
+dpkztjklge 1 301 train
+dplanawaxh 1 300 val
+dplbsilieg 1 240 train
+dpldrcqfdx 1 300 train
+dplfintlwc 0 300 train
+dplgcnkzqp 0 300 val
+dplgqdumdb 1 300 train
+dplskcpqne 1 239 val
+dpmbiymdxs 1 300 train
+dpmejozova 1 300 train
+dpmfmgxxde 1 300 test
+dpmgoiwhuf 0 300 test
+dpmiopituf 1 299 test
+dpmkyykfqz 1 300 train
+dpmngbibio 1 299 test
+dpmpadzhia 1 300 val
+dpmzclizkp 1 300 train
+dpncsuyamf 1 301 train
+dpnjuvteew 1 300 train
+dpnniykoeq 1 300 val
+dpnnwjdspi 1 300 train
+dpoguapjty 1 300 train
+dpohqhypgu 1 298 train
+dpoisudctx 1 300 train
+dpojtssjpq 1 241 train
+dpooyxagkj 1 300 train
+dposxfhbxc 1 300 train
+dpouqllztj 1 300 val
+dpowxaunrz 1 298 val
+dppcnmhlcn 0 300 train
+dppenikefd 0 300 train
+dppippjamp 1 300 train
+dppixhsszo 1 300 train
+dpporahttc 1 300 train
+dppuqrqrac 1 301 val
+dppurncpia 0 300 train
+dppvuetjhi 1 301 train
+dpqagasfcv 1 300 train
+dpqjxftbdt 1 300 val
+dpqkszhqix 1 302 train
+dpqmzbhasn 1 300 train
+dpqocpjswu 1 300 train
+dpqsftyfai 1 300 val
+dpqspsnfls 1 300 train
+dpquvbkgoh 1 301 train
+dpqwdiooad 1 300 train
+dpqxzvyccv 1 300 val
+dpqzvppssn 1 301 val
+dprdiqgydx 1 249 train
+dprehbfgwi 1 300 train
+dpronsafgg 1 301 train
+dprtqyvvca 0 300 train
+dpsfbgwbvr 1 302 train
+dpsfsvflio 1 300 train
+dpsijhzcpg 1 300 train
+dpskoxcgds 1 240 train
+dpsnbyivjq 1 300 train
+dpswvtluiz 0 300 train
+dptbnjnkdg 1 300 train
+dptrzdvwpg 1 300 train
+dptteokefd 1 301 train
+dptzndiouk 1 300 val
+dpuaqtdhjk 1 300 train
+dpucwvhywf 1 300 train
+dpugwumfok 1 300 val
+dpuirizhbk 0 300 val
+dpumavoiti 1 300 train
+dpuucddzsr 1 300 val
+dpuzevsqec 1 300 train
+dpvaigjftr 0 300 train
+dpvcebzgqr 1 300 train
+dpvdihysra 1 300 train
+dpvligsdzp 1 300 train
+dpvmizbjmm 1 300 train
+dpvsjorvsd 1 300 val
+dpvyupznif 0 300 train
+dpwncfttqu 1 301 val
+dpwpjeyyqc 1 300 train
+dpwqbngytx 1 300 train
+dpwxclnvav 1 300 train
+dpwyrhpzhl 1 297 val
+dpxdbdtyxg 1 300 val
+dpxjxfjxaj 1 300 train
+dpxqemmfjz 1 300 train
+dpxuofgnjb 1 300 train
+dpyckjuxij 1 300 train
+dpyfmngnlk 1 300 train
+dpygtovvqe 1 301 train
+dpyiqmkeot 1 300 train
+dpyjlbgxhv 0 300 train
+dpynqhdyal 1 300 train
+dpyoikmbdj 1 300 train
+dpyujeqnrz 1 300 train
+dpyxedhwxc 1 300 train
+dpzayxcsok 1 300 train
+dpzcvwfekf 1 301 val
+dpzpbjufmy 1 300 train
+dpzqzfnzrs 1 241 train
+dpzsgxhecn 0 300 train
+dqabyjwzwt 1 300 train
+dqajgtbnlo 1 300 train
+dqalrysjkr 1 301 train
+dqavjmidxr 0 300 train
+dqavzxxqht 1 300 train
+dqaxedcslj 1 300 val
+dqaxvrskvd 1 298 train
+dqbgdbtdij 1 300 train
+dqbhuexjiv 1 302 val
+dqbilrqozl 1 300 train
+dqblrylonj 1 300 train
+dqbqfocqrz 1 301 val
+dqbtjsrrkj 1 300 val
+dqcamrpobq 1 300 test
+dqchmjpkwp 0 300 train
+dqcjkyfugk 1 300 train
+dqcktkancu 1 300 val
+dqckzndxbh 1 300 train
+dqcmdwbrvr 1 300 train
+dqcmqcmmba 1 300 train
+dqcqaciyjp 1 300 train
+dqcqapwfmm 0 300 train
+dqcrdjlcta 1 300 train
+dqdiarmuzs 1 300 train
+dqdjvfvgjz 1 301 train
+dqdkidemfy 1 241 train
+dqdkwqoxvg 1 300 val
+dqdsprifmt 0 300 val
+dqdvipvrmr 1 300 train
+dqdwtzouhv 1 300 train
+dqecxlcpiz 0 300 train
+dqeexnwfso 1 300 train
+dqegihknfk 1 300 train
+dqeklvvgyj 1 300 val
+dqekrtqvql 1 300 train
+dqeofiabtc 1 300 val
+dqevbrjxzm 1 300 train
+dqewbdwssv 1 299 train
+dqfgwejsvm 0 300 train
+dqfjjwowmp 0 300 val
+dqfkandnht 1 300 train
+dqfqgkoyax 1 300 train
+dqfvhvptda 1 300 train
+dqfvllhffq 0 301 val
+dqfxietbgm 1 297 val
+dqfzodtstf 1 300 val
+dqggmbpnwj 1 241 train
+dqghwyhlav 0 300 val
+dqgjsmzcel 1 299 train
+dqgrcibkko 0 300 train
+dqguihiqmu 1 300 train
+dqhiorhxrr 1 300 train
+dqhriynnec 1 300 train
+dqibpplzly 0 300 train
+dqidxhktvn 0 300 train
+dqidxrvhud 1 300 train
+dqiifdpfnd 1 300 train
+dqiqzqnpwu 1 300 train
+dqisjtyguv 1 300 train
+dqitmcvzpw 1 300 train
+dqivnrmzjs 1 300 train
+dqiwloufxc 1 300 train
+dqiwnvwslz 1 300 train
+dqixmpzlug 0 300 train
+dqjdgpdomr 1 301 train
+dqjdhjdrpe 0 301 train
+dqjimfodxg 1 300 val
+dqjvzwlpfb 1 300 train
+dqkagghvhq 1 301 val
+dqkefsgzeb 1 300 train
+dqkiytivrm 1 300 train
+dqkpfpxrkb 1 300 train
+dqkxdzxkuw 0 300 train
+dqkxyqswlf 1 300 train
+dqkzidnkct 1 300 train
+dqlboemuef 1 301 val
+dqlehcyynm 1 298 train
+dqlevdzjlh 1 298 train
+dqlmffnywx 1 300 test
+dqltfusznk 1 300 train
+dqlwqlyvyd 0 300 train
+dqmjowpuxk 0 300 val
+dqmkthhjbx 1 300 train
+dqmldqorqa 1 300 train
+dqmlelzmkk 1 300 train
+dqmmcbbvzh 1 300 train
+dqmptbhnvo 1 300 train
+dqmrfhgpql 1 300 train
+dqmrsxmias 1 300 val
+dqmswcqdwn 1 300 val
+dqmzigbgvd 1 302 train
+dqnimegdrl 1 300 train
+dqnoljoqri 1 300 train
+dqnrmokzze 1 300 train
+dqnrnkyhww 1 300 train
+dqnvplfkrm 1 296 val
+dqnxfjcqob 1 300 train
+dqnyszdong 1 300 train
+dqnyunfrzx 1 300 train
+dqombsgufg 1 300 train
+dqomowdkuy 1 300 train
+dqotlpeixt 1 300 val
+dqovdnkhtb 0 300 train
+dqpfrzvfjg 1 300 train
+dqpivvafbb 0 301 train
+dqpjkpgvts 1 300 train
+dqpjothchf 1 300 train
+dqppcbikrv 1 300 train
+dqppxmoqdl 1 300 train
+dqqeyuatkw 1 300 train
+dqqfwuzuon 1 300 train
+dqqgfwcmrn 1 300 train
+dqqkipigmq 1 300 train
+dqqpdgcjpb 1 300 val
+dqqtjcryjv 1 300 train
+dqquvfnfir 0 300 train
+dqqwmmwlbg 1 300 test
+dqqyckzdyu 1 300 train
+dqqzkftrov 1 300 train
+dqqzonyfus 1 300 train
+dqribgabap 1 300 train
+dqribxkdoc 1 297 val
+dqrqqgrqwv 1 301 val
+dqrsukajna 1 300 train
+dqsbmlbioa 1 300 train
+dqsdcbmoyo 0 301 train
+dqsdsiszmt 1 300 train
+dqseyefxus 1 300 train
+dqsjrwfcim 1 242 train
+dqsrsoxcck 1 298 train
+dqstwncfrt 1 300 val
+dqswpjoepo 1 300 train
+dqtcyvqtzh 1 300 train
+dqtdiofbat 1 302 train
+dqtdwwptpl 1 300 train
+dqteoymnhu 1 288 train
+dqthpbczpo 1 300 val
+dqtpqkfxfd 0 300 train
+dqtprojnpg 1 300 train
+dquaaefepx 1 300 train
+dqubkheruj 1 300 val
+dquebqjckm 1 300 val
+dquxguciif 1 300 train
+dqvaqzderz 1 297 train
+dqvdamgdpw 1 300 val
+dqvdrlvzhd 1 299 train
+dqvgubgovp 1 300 val
+dqvigmswec 1 300 train
+dqvmmssikk 1 300 train
+dqvwzfhnbo 1 300 train
+dqwaqerwma 1 300 train
+dqwiommqgl 1 300 train
+dqwivnescd 1 300 train
+dqwliuxich 0 301 train
+dqwnndyoti 1 300 train
+dqwovdpalr 1 99 train
+dqwstprwis 1 300 train
+dqwzmbwhzo 0 300 train
+dqwzxhtucd 1 300 train
+dqxhrlrcvz 1 300 train
+dqxlmhcqao 1 300 train
+dqxojjjwdp 1 241 train
+dqxprtqlxy 1 300 train
+dqxqfyxrpn 1 301 train
+dqxqmexekn 1 100 train
+dqxwrxwjcu 1 300 train
+dqxxoscein 1 300 train
+dqycocughj 1 298 train
+dqyjucdnhx 1 298 train
+dqylsglxgr 1 300 train
+dqypurwdyr 0 300 train
+dqyrxoyxcy 1 300 train
+dqyzrfjjae 1 300 train
+dqzapzhrzg 1 300 train
+dqzkvnpvpn 1 300 train
+dqzreruvje 1 300 train
+dqztatxlqb 1 300 val
+dqztuvpjhe 1 301 train
+drahlnwilf 1 300 train
+dralbstugr 1 300 val
+drapfnscij 1 300 train
+drapovnkch 1 300 train
+drbacjdatw 1 299 test
+drbeyrkvgr 0 300 val
+drbnyexjsp 1 300 train
+drbqpaasvz 1 300 train
+drbwsykxua 1 300 train
+drcbdxvlit 1 301 train
+drcbersvnq 1 300 train
+drcnexexcc 1 300 train
+drcnwccwku 1 297 train
+drcoqmmrpf 0 290 train
+drcpswlwdt 1 300 train
+drcqsbknij 1 299 train
+drcrsyofgj 0 300 train
+drcwxqtwgx 1 301 train
+drcyabprvt 0 300 train
+drdebschfk 1 300 val
+drdfmbgowv 1 300 train
+drdfoowoub 1 300 val
+drdiibkluw 1 298 train
+drdsqscsro 1 300 val
+dreaibtijx 1 300 train
+dreamznfsd 1 300 train
+drecofpdwv 1 300 train
+drehopjdry 1 300 train
+dreiuqfayx 1 300 train
+dresjrvhhj 1 300 train
+dretamidot 1 300 val
+dreupyxqpi 1 300 train
+drevlhzdrj 1 301 val
+drffprhwll 1 300 train
+drfhclwdqw 1 300 train
+drfjdwyjba 1 300 train
+drfjrlqbhj 0 300 train
+drfxxsoqpu 0 300 train
+drgjzlxzxj 1 300 train
+drgpaonezb 1 300 train
+drgvbpjdea 1 300 train
+drgvtllewu 1 300 train
+drheirwjbb 1 300 train
+drhsyogfpq 1 300 train
+drhulcdtbf 1 300 train
+drhxufodxo 1 300 train
+drieyseoev 1 300 val
+drifjooxkc 1 300 train
+drifljlgzm 1 300 train
+drjaegjgvo 1 300 val
+drjbrauwqt 0 300 train
+drjdwfbmod 0 300 train
+drjjyrznum 1 300 train
+drjkkdbcvc 0 241 train
+drjlhykuso 1 300 train
+drjlymljha 1 300 train
+drjmagfuss 1 300 train
+drjmigyisb 1 300 train
+drjnvbiqbu 1 300 train
+drjqnsqfsk 1 300 train
+drjwafunon 1 300 val
+drkcvgubrx 1 300 train
+drkdtigcja 0 300 train
+drkgblxscz 1 300 train
+drkgogkpqi 1 299 test
+drkisthaav 1 300 train
+drkkxpmdaw 1 300 train
+drksycorsl 1 300 val
+drlbzmlsuh 1 300 train
+drliykwqcc 0 300 val
+drljglyski 1 300 val
+drlkcilgmc 1 300 test
+drlnvwvvuw 0 300 train
+drlqhfctxh 1 300 train
+drlrszhcjy 1 300 train
+drlxqvoqaj 1 240 train
+drmenmvnil 1 300 train
+drmtumqfus 1 300 train
+drmtvuyoam 1 300 test
+drmtykanjz 1 300 val
+drnexrxoks 1 300 train
+drnjesnfcs 1 300 val
+drnkxvgtae 1 300 train
+drnwsctnuh 0 300 train
+drnyxcdxmj 1 300 val
+drnzxzuzlu 1 300 train
+droeyvdhbo 1 300 train
+droflgpbgt 1 300 train
+drojjsajtb 1 300 train
+drooaxkvib 1 300 test
+drorvehrld 1 300 train
+drotauchvw 0 300 train
+drouplvofs 1 239 val
+drozeobdwc 1 300 train
+drpqbtfjsr 1 300 train
+drprkdfycv 0 300 val
+drpstylchq 0 300 val
+drpsvvxxco 1 300 train
+drqbnsabva 1 300 val
+drqcntgrhf 1 299 test
+drqkbppazx 1 300 val
+drqspoygux 1 300 train
+drqtyzvhdd 1 300 train
+drqyduthnk 1 300 train
+drrcckzpnm 1 300 train
+drrdcrrsxn 0 300 train
+drrfshifmg 0 300 train
+drrfzphjid 1 301 train
+drrmdksoxw 1 300 train
+drrntajiyp 1 300 train
+drrpntzyos 1 300 train
+drrqevuold 1 298 val
+drruhxvuck 1 300 train
+drrvqwuubn 1 301 train
+drsakwyvqv 1 300 train
+drscxohoqw 1 300 val
+drsdhsiame 1 300 train
+drsehggeqj 1 300 train
+drsfrhpdgk 0 300 train
+drsgxhctvz 1 300 val
+drsgygzgya 1 300 val
+drskirfsgn 1 300 train
+drskwcmmeb 1 298 train
+drsqpxhfeq 1 300 train
+drsvtbkrdr 0 300 train
+drswdgjhrb 1 300 train
+drsxpffkvv 1 300 train
+drsxvvffwq 1 300 train
+drtbksnpol 1 300 train
+drtcebdmsd 1 300 train
+drtcokiusq 1 301 val
+drtffcayak 0 300 train
+drthoxlzfr 1 300 train
+drtjfukgsw 1 300 train
+drtkdzumxn 1 300 train
+drtoduffnw 0 300 val
+drtrtbgwmc 1 300 train
+drtulzvrde 0 300 train
+drtyzjzaxz 0 300 train
+druapjtxgu 1 300 train
+druieafzyv 1 300 train
+drunryhskx 1 300 train
+druokiksrn 1 300 train
+druqwoyjnx 1 301 val
+druthecyrd 1 300 train
+drvmufcudd 1 300 train
+drvnhlsvfj 1 297 train
+drvodtwine 1 300 train
+drvtnhzkyw 1 300 train
+drvtugrrjx 1 300 val
+drvuffopkp 1 300 train
+drvvsxnxke 1 298 train
+drwgfucrnz 1 300 val
+drwiutntjf 1 300 val
+drwmfvxesn 1 300 val
+drwrgupnpd 1 300 train
+drwzbuwdwo 1 300 train
+drxadjcdek 1 300 train
+drxdmrwgmc 1 300 val
+drxfbynzji 1 300 train
+drxfjitbio 1 300 train
+drxkxlcmto 0 300 val
+drxrehfgoa 1 300 val
+drxswkgtst 0 300 train
+drxvhmrfmo 1 300 train
+drxvirslgf 1 300 train
+drxvwffypa 0 301 train
+drxxemqdmt 1 300 val
+drxzulpsoz 1 300 train
+drygthdmxs 1 300 train
+dryhqdbmut 0 300 train
+drykptqtsm 1 302 val
+drytosluag 0 300 train
+drywmgvslp 0 300 val
+dryzxpabpa 1 300 train
+drzcqgmcxd 1 300 train
+drzdwwvbew 1 300 train
+drznplrdda 1 300 train
+drzwkomakf 1 300 train
+dsaimnkbgj 1 300 train
+dsakhvhfle 1 300 train
+dsapaavrie 1 301 val
+dsaqimdnjb 1 300 train
+dsaxwwtgtx 1 125 val
+dsbfpcrbvk 1 298 val
+dsbmnhkxdh 1 301 val
+dsbrnbihpn 1 300 test
+dsbuzyerau 0 300 train
+dsbvhyjfor 1 300 train
+dsbxijjxxn 1 300 train
+dsbzijxulb 0 300 train
+dscaevrvqa 1 300 train
+dsccgxhtud 1 300 train
+dscgrauvgh 1 300 train
+dscijfgpba 1 300 train
+dsckjrlpky 1 300 val
+dscprfjses 0 300 train
+dscrbxbbjv 1 300 train
+dscwpjefsv 1 300 train
+dsdgxlsvab 1 300 train
+dsdjacgwbg 1 300 train
+dsdkmkhcaf 1 300 train
+dsdoseflas 1 300 train
+dsdsmfrmdw 1 300 train
+dsdswrtyyl 1 300 train
+dsduejlbqc 1 300 train
+dsdupbfnvp 1 301 train
+dsdvutucic 1 300 train
+dsealbmwme 1 300 train
+dsecpwiktk 1 300 train
+dseirpxyvn 1 300 train
+dseloorrok 1 301 val
+dsertupxsw 1 299 test
+dseuedlgff 1 300 train
+dsevsetatr 1 300 train
+dsfbtblodu 0 300 train
+dsfebkcuru 1 300 train
+dsfefmocjy 1 300 train
+dsffcnbmya 1 300 val
+dsfhozjjuh 1 300 train
+dsfjdogysp 1 299 test
+dsfosjtnho 1 300 train
+dsgbczgstu 1 300 train
+dsgcxpawfd 1 301 train
+dsgheclofa 0 99 train
+dsgimzmcjo 0 300 train
+dsgpbgsrdm 1 300 train
+dsgsnhzgmg 1 300 val
+dsgswagtvp 1 300 test
+dsgsyhsfgw 1 300 train
+dsgtewvysr 1 300 val
+dsgwsmscmh 0 300 train
+dshfmaequh 1 300 train
+dshgmpqmxa 0 300 train
+dshhxylazk 0 300 train
+dshipbzylt 1 300 train
+dshmevxpdb 1 300 train
+dshoywjgap 1 300 val
+dshzlfpsdh 1 300 train
+dsicaqgnpp 0 300 train
+dsiirbwwyt 1 300 train
+dsilxejbkg 1 302 train
+dsimdyvceg 1 300 train
+dsiqhmzjcq 1 302 val
+dsirzbqhvc 0 300 train
+dsjbknkujw 0 300 train
+dsjcxcmfgp 1 296 val
+dsjekitetb 1 301 train
+dsjelqqcbe 1 300 train
+dsjgzzscvg 1 300 train
+dsjoheyazh 1 300 val
+dsjowrbvno 1 299 val
+dsjswaaiiv 1 300 val
+dskacvwxsw 1 300 train
+dskavhjysn 1 300 val
+dskdhcxutl 1 302 val
+dskfqergbt 0 300 train
+dskhcyjnqw 1 300 train
+dskmqeboxb 1 300 train
+dskocecfym 1 300 train
+dskzamsvtn 1 300 train
+dslbhvbfmh 1 300 train
+dslhnkgodw 1 300 train
+dslifinjkj 1 300 train
+dslpjueuhn 1 300 train
+dslqptqxdw 1 300 train
+dsluqyohov 0 300 val
+dsmcmczelz 1 300 train
+dsmdkytbzr 1 300 train
+dsmdylqcjr 1 300 train
+dsmgcmdqxy 1 300 train
+dsmjvycfmg 1 300 train
+dsmlabbgkb 1 300 train
+dsmqdgresm 0 300 val
+dsnaecbell 1 300 val
+dsnclpfpet 1 298 train
+dsndhujjjb 1 300 train
+dsnerafcqv 1 300 train
+dsnfqciqly 1 301 train
+dsnfyenwjx 1 300 train
+dsnjyvnspt 1 300 train
+dsnnxyfctp 1 295 train
+dsnvzccwcm 0 300 train
+dsnxgrfdmd 0 300 test
+dsopfynioo 1 300 train
+dsorchofyr 1 300 val
+dsorrzsbsr 1 300 train
+dspahjiktq 1 300 train
+dspdtacmun 0 300 train
+dspezmgkkj 1 300 train
+dspngapans 1 300 train
+dspnjwfpes 1 300 train
+dsppvlvcom 1 300 train
+dsqixnximj 0 300 val
+dsqoagpfgc 1 300 train
+dsqqdjbiwd 1 300 train
+dsquisttjd 1 300 train
+dsqxrkgmnr 1 300 train
+dsralytzln 1 300 train
+dsrbcbwmjx 1 300 train
+dsrdkwnuvd 1 270 train
+dsrioilqfo 1 300 train
+dsrjljnjgw 1 288 train
+dsrllxoeos 1 299 train
+dsrmkfilyg 1 300 train
+dsrmzmrvxa 1 300 train
+dsrytiitih 1 300 train
+dsrzbcgrlu 1 301 val
+dsrzvvzwmq 1 300 train
+dssbtqzpek 1 300 train
+dsshsqhwyq 0 300 val
+dssjgsuapw 1 300 train
+dssvefhjok 1 300 test
+dssxlicmbl 1 300 val
+dstdqjxotm 1 300 train
+dstibundsx 0 301 train
+dstvkvrglm 1 301 train
+dstzgzpqwj 1 300 train
+dsubvafgyh 0 300 train
+dsudlzmehv 1 300 train
+dsuibvingt 1 300 val
+dsupupjiet 1 300 val
+dsuswszpue 1 240 train
+dsuxbnyyax 1 300 train
+dsveelyrgf 0 300 val
+dsvfvahxjb 1 300 train
+dsviaijduj 1 300 train
+dsvibdylng 1 300 val
+dsviippitl 1 300 train
+dsvopuhqiz 1 300 test
+dsvrtkjwvz 0 300 train
+dsvrysxyqw 0 300 train
+dsvwtcrvwv 1 300 train
+dsvxgfzwdj 1 300 train
+dsvzltsbyq 1 300 train
+dswaxbhfgs 1 300 train
+dswbwjbmyk 1 300 train
+dswhjyjrrs 1 240 train
+dswvtfyjhv 1 300 val
+dsxbuabcuj 1 300 train
+dsxhbtiraa 1 300 train
+dsxjsuqnsk 1 300 train
+dsxmlpgpdd 1 300 val
+dsxmpdwjjq 0 300 train
+dsxvketzmt 1 269 train
+dsxxrzxusd 1 301 val
+dsyapihokr 1 300 train
+dsyljupsqw 1 300 train
+dsypvnksuc 0 300 train
+dsypzyhrdt 1 298 train
+dsywxyckwy 1 300 train
+dsyxpluggm 1 300 train
+dsyygpukxp 1 300 val
+dsyyxhywiy 1 301 train
+dszfkngghv 1 301 train
+dszizxvkqp 1 300 train
+dsznmzroir 1 300 train
+dszocsfvpr 1 300 train
+dszoxhhige 1 300 train
+dszvnzsffp 1 300 val
+dszyfycaxl 1 300 train
+dtacifxdzu 1 298 train
+dtaddbilvb 1 300 train
+dtakxfpczr 1 297 val
+dtasngsqpl 1 300 train
+dtaznbiheh 1 300 train
+dtbgjdtujf 1 300 train
+dtbidzludn 1 300 train
+dtbilnqlqx 1 299 val
+dtbisxheij 1 300 train
+dtbnoimzzl 1 300 train
+dtbpmdqvao 1 300 train
+dtbqyxbxjj 1 292 val
+dtbtodgule 1 300 train
+dtbvywokwy 1 300 val
+dtcemctlvr 1 241 train
+dtcjjbfosp 1 299 test
+dtcpeyippm 1 300 train
+dtcseuijtb 1 300 train
+dtctoaxksk 0 300 train
+dtdeapijco 1 300 train
+dtdfjxyubu 1 300 train
+dtdlzuofte 1 300 train
+dtehebhwis 1 300 val
+dtehuznchv 1 302 val
+dteiklzbtq 1 300 train
+dtelsfwyem 1 300 train
+dteshahzfp 1 300 train
+dtfbixfayh 1 300 val
+dtfcgnsdtd 1 300 train
+dtfgsvfmjq 1 301 train
+dtfjzvikwk 1 300 val
+dtfmymslpx 1 301 val
+dtfqimruhk 1 300 train
+dtfqodmape 0 300 train
+dtfrslgpwj 0 300 train
+dtfyluocuh 1 300 val
+dtfzsnhdju 1 301 val
+dtgbonxukc 0 300 train
+dtgejbdshy 1 300 val
+dtgixxordp 1 300 train
+dtgkqpfxgd 0 300 train
+dtgsmqzvqx 1 300 train
+dtgyycbylg 0 300 train
+dthbysjgfg 0 300 train
+dthectkigu 1 301 train
+dthequmukv 1 300 train
+dthgskgnxk 1 300 val
+dthqfutqsw 1 300 val
+dthsbwohjb 1 300 train
+dthuejanym 1 300 train
+dthvdezqws 1 300 train
+dtidkfvnnw 1 300 train
+dtiizzehgj 1 300 train
+dtijcohbrd 0 300 val
+dtiqogndtf 1 300 train
+dtissoiefc 1 300 train
+dtivssiisl 1 300 train
+dtjamuiyiu 1 300 val
+dtjcrfmraj 1 301 train
+dtjcyzgdts 1 300 test
+dtjmxcrwfd 1 301 val
+dtjnasdyyy 1 300 train
+dtjxsdvkov 1 300 train
+dtkhzjnuzy 1 300 val
+dtkobljzgr 1 300 train
+dtkpagbdmv 1 300 train
+dtktpgtuhu 1 300 train
+dtkvzwnvmm 0 300 train
+dtkypvrrgo 1 300 val
+dtlfxguvoi 1 302 train
+dtllszqumv 1 300 train
+dtllvnmwdh 1 300 train
+dtlmcejxrz 1 298 train
+dtlrlpemur 0 300 train
+dtlylnsrns 1 300 train
+dtmboydqqu 1 300 train
+dtmjmmhrzi 1 300 train
+dtmlspmqqp 1 300 val
+dtmqbsbmtx 1 300 train
+dtmyiszoad 1 300 train
+dtnbfjtoou 1 300 train
+dtndkhtznj 1 300 train
+dtngwlnmhu 1 300 train
+dtnibazvrf 1 300 train
+dtnxkwhloi 1 300 train
+dtobxangxt 0 300 train
+dtocdfbwca 1 300 train
+dtoebncawk 1 300 val
+dtoskysokn 1 300 val
+dtovjfinca 1 300 train
+dtozwcapoa 0 300 test
+dtpdsicgjm 0 299 train
+dtpfkyylpi 1 300 train
+dtpiigaajq 0 300 train
+dtpqmdmuos 1 300 train
+dtpubdfoap 1 300 train
+dtpuxzeuln 1 300 train
+dtqfqfddgh 0 300 train
+dtqgehoxjl 1 300 train
+dtqhcyijmd 1 300 train
+dtqhijoxgk 1 300 train
+dtqwarztao 1 300 train
+dtrasqdgid 1 300 train
+dtrbfbkahv 1 300 train
+dtrmgwnmrf 1 300 train
+dtrpvcrbyk 1 300 test
+dtrylmmfku 1 300 train
+dtsdluvgmg 1 300 test
+dtsemuqyot 1 301 train
+dtskukyggw 1 301 train
+dtsoxfqjtr 1 300 train
+dtspboofrz 1 300 train
+dtspghozbj 1 300 train
+dtsrvspqhm 1 300 train
+dtssdnhgiw 0 300 train
+dtsuvuapzw 0 300 train
+dtsxksuely 1 300 train
+dtszxpzrwh 1 300 val
+dtteldyuvf 1 300 train
+dttgbugxbe 1 300 train
+dttgdywaeq 1 300 train
+dttgowapsc 1 288 train
+dttgumikuo 1 300 val
+dttktgjcsq 0 300 val
+dttndlgcse 1 300 val
+dttppayggl 1 300 val
+dttuwhqhhl 1 301 train
+dttzqimroz 1 300 train
+dtuatfaetk 1 300 train
+dtuhfrjfcm 1 300 train
+dtujcdomxh 1 300 train
+dtusmifhor 1 300 val
+dtutjoeohz 1 300 train
+dtuwyvosek 0 300 train
+dtvcchgysl 1 300 val
+dtvfowwvki 1 300 train
+dtviszogbx 1 300 val
+dtvlwkzhwb 0 300 train
+dtvmqghkxl 1 300 train
+dtvpmvtxkt 1 300 train
+dtvsntuctq 1 300 train
+dtvxaotydy 0 298 train
+dtvylqtivq 1 300 val
+dtvzkziood 1 300 train
+dtwbmdgqsl 1 300 val
+dtwmkvalrf 1 300 train
+dtwpaytccy 1 300 train
+dtwppzipeo 1 301 val
+dtwxxkuvox 1 300 test
+dtwyrdfwjv 1 300 train
+dtwzjhoizi 1 300 test
+dtxcbjoupb 1 301 train
+dtxlvowwgh 1 300 train
+dtxyaacbwp 1 296 train
+dtxzchwimo 1 300 train
+dtybbstrow 0 300 train
+dtyfvhyphl 1 300 train
+dtyldbfwif 1 300 train
+dtylzjvdic 1 300 train
+dtymieprub 1 297 val
+dtyrynyvjq 1 297 val
+dtyxicmtwr 1 300 train
+dtzcznnnri 1 300 train
+dtzeayzalt 1 300 train
+dtzemgzhhl 1 300 train
+dtzhqlxpjz 0 300 train
+dtzlalimdl 0 300 train
+dtzuqoiieq 1 300 train
+dtzuwxopos 0 300 train
+dtzxmoukfk 1 296 train
+duagkimymq 1 301 train
+dubapdrelq 1 300 train
+dubcbdxrjw 1 300 train
+dubdchmosb 1 300 train
+dubfjsvnbr 1 300 train
+dubiroskqn 1 300 train
+dubtztpxwi 1 300 val
+dubwdwysxp 1 300 train
+ducbhngngg 0 300 train
+duccbrpddx 1 300 train
+ducfbvlcvp 1 301 train
+ducgnuyrft 1 300 train
+ducinsaroq 1 300 train
+duciovvndy 1 300 val
+duckaycmww 0 300 train
+ducnlshemx 1 300 train
+ducopengue 0 298 train
+ducopsdoto 1 300 train
+ducoxfxphm 1 300 train
+ducrzdylfi 1 296 train
+ducxlmluel 1 301 train
+duczhwighk 1 300 test
+dudffwylgp 1 300 train
+dudihuykfb 1 298 train
+dudkzqczwl 1 300 val
+dudwffxjrv 1 301 train
+dueamqvxnu 1 300 train
+dueetmggnr 1 300 train
+duekvkfzff 1 300 val
+dufjujmnjb 1 300 train
+dufldddpbl 1 298 train
+dufrlympsb 1 300 val
+dufwqldemv 1 300 train
+dufyebdgxc 1 600 train
+dugeewlcoh 1 301 train
+dugetsyeex 1 300 train
+dughzjlote 1 297 train
+dugqhdwduy 1 300 train
+dugxnvunhp 1 300 train
+duharfxvlx 1 300 train
+duhcgqzgic 0 300 train
+duhdbrtcdk 1 300 train
+duheoojtee 1 300 train
+duhgeoovha 1 300 train
+duhilxsfwa 1 300 train
+duhludvllm 1 298 val
+duhsukogap 0 300 val
+duhsvhutbd 1 300 train
+duhwpyufwp 1 300 val
+duiswsmlth 1 300 train
+duiuwyxdal 1 301 train
+dujcilrfww 1 300 val
+dujkoqilcm 0 300 val
+dujodwlmny 1 300 train
+dujqekxrvp 1 300 train
+dujywkpuns 1 300 train
+dujzywxmiy 1 300 train
+dukhziauyt 1 300 train
+dukwfxjqyj 1 300 train
+dukwxvlmkq 1 300 train
+dukyihrdhb 1 301 train
+dukyxdeypr 1 298 train
+dulanfulol 1 300 train
+dulbjxpshd 1 300 train
+dulcrynlhw 1 300 train
+duleismfxw 1 600 train
+duleldhtno 1 241 train
+dulerniows 1 241 train
+dulfkikovu 1 300 train
+dullbimwjp 1 300 train
+dulqhllfov 1 300 val
+dulrkjgjvr 1 300 train
+dultiznosk 0 300 train
+dulurmlisg 1 300 val
+dulwygcxuq 1 300 train
+dulxiwngbb 1 301 val
+dulzxaolus 1 300 train
+dumckbvsnf 0 300 train
+dumisvtyyl 1 300 train
+dumjlfiuqp 1 300 train
+dumpellzes 1 298 val
+dunalebmpa 0 300 train
+dunfgnvgmr 1 300 train
+dunoyrraik 1 300 train
+dunpragkfp 1 300 val
+dunvjxibnr 1 300 train
+dunvnvhbat 1 301 train
+duoazqwwlz 1 300 train
+duobjznslt 1 300 train
+duoehftfgy 1 300 train
+duoisftrbn 1 300 val
+duolxuirhf 1 300 val
+duorbxnaew 1 300 train
+duosdjqhxr 1 300 train
+duotlfwqlx 1 300 train
+duowkaxqfz 1 300 train
+dupaawsoge 1 300 train
+dupipltdex 1 300 train
+duplfegshv 1 300 val
+duplyxsudb 0 300 val
+dupozoprbh 1 300 train
+duppkqessg 1 300 train
+dupqqiguui 1 300 train
+dupsnteozu 0 300 train
+dupstaizio 1 300 train
+dupzjvwgeb 1 300 train
+duqeevntgr 1 300 train
+duqeiqjeww 1 300 train
+duqfwmozqw 1 300 train
+duqiruqllb 1 300 train
+duqjkvgqqa 1 301 val
+duqjwtuahk 1 300 train
+duqmkkkoxl 1 300 train
+duqnldogpg 1 300 train
+duqzgngijc 1 300 train
+durclovmni 1 300 train
+dureftqvsh 1 300 train
+duresenabz 1 301 train
+durfmbnqez 1 300 train
+durhdaqfup 1 300 train
+durhuhszcj 1 300 train
+durjpbmxnt 1 300 train
+duruzkjocq 1 296 train
+durwcqjclm 1 296 train
+durzvonsdp 1 300 val
+dusbhhockt 0 301 train
+duscqyzztx 1 301 val
+dusdbgswfw 1 300 train
+dusdpfycnq 1 300 train
+dusdqweuov 1 300 train
+dusgmzotvh 1 297 train
+dusgrtwjfs 1 302 val
+dushvzcaok 1 300 val
+duskgxxgha 1 300 train
+duskhvzdze 1 300 train
+dusxokcbgq 1 300 train
+dutcaatdbk 0 300 train
+dutdnjgeud 0 241 train
+dutgklvxqr 1 300 train
+dutksjiaxm 1 241 train
+dutmmtplyf 1 301 train
+dutqjjpqfu 1 300 train
+dutxfomimk 1 300 val
+duuciiycws 1 299 val
+duuefmfzfq 1 300 train
+duufrtgxtq 0 300 train
+duufwshqyc 0 300 train
+duurzmppfk 1 301 train
+duutgvwvhj 1 300 train
+duuzobnkdu 1 300 train
+duvccfpaeh 1 300 train
+duvevfzcjn 1 300 train
+duvffhbhlr 1 300 train
+duvihajlvv 1 241 train
+duvlanzhnn 1 300 train
+duvpgpnedc 1 300 train
+duvpnwhshk 0 300 train
+duvwguwidc 1 300 train
+duvwmyocim 1 300 train
+duvyaxbzvp 1 300 train
+duwmzggdvd 1 300 train
+duwwgciptr 0 301 train
+duxdwoczmu 1 301 val
+duxebrvpko 1 300 val
+duxfmbyddi 1 300 train
+duxhvftnpq 1 300 val
+duxjjywsah 1 300 train
+duxntmbppy 1 300 val
+duxzbcagqz 1 300 train
+duyaxwfact 0 300 train
+duycddgtrl 0 300 train
+duycukxwfx 1 300 train
+duyisbzujq 1 300 train
+duymakvytr 1 300 train
+duypdwrwxl 1 300 train
+duyssckgzs 1 300 train
+duywhnombt 1 300 val
+duzhyctuln 1 300 val
+duzkhddrdu 1 302 train
+duzmotcwss 1 300 train
+duzovahuvi 1 300 train
+duzpgwrxnt 1 300 val
+duzueyonao 1 300 train
+duzuusuajr 1 300 train
+duzwclbzui 1 300 train
+dvaeejmney 1 300 train
+dvafzkkehz 0 300 train
+dvaihgaira 1 300 train
+dvajdynpdh 1 301 train
+dvakowbgbt 1 300 train
+dvalwsjxcv 1 300 train
+dvamhcbjap 1 299 val
+dvaorftkeq 1 300 train
+dvaxrkkxtg 1 300 train
+dvazfntepg 1 300 val
+dvbbnrkvdy 1 300 train
+dvbboychog 1 300 train
+dvbcptngiv 1 301 train
+dvbjwudatn 1 300 train
+dvbohsuknn 1 241 train
+dvbqnsdicb 1 300 val
+dvbsanctxr 1 300 train
+dvcioruqyy 1 300 train
+dvclvkchod 0 300 train
+dvcoxufzek 1 300 train
+dvcsapbvyr 1 300 train
+dvcslzbvnm 0 300 train
+dvcxlgxswj 1 300 train
+dvdbzcoirs 1 300 val
+dvdesejgct 1 300 val
+dvdetyfrop 1 300 train
+dvdfbcrhxj 1 299 train
+dvdgwbcsdo 1 300 train
+dvdiqmebgv 1 300 train
+dvdngabyzr 1 300 train
+dvdtizyhyb 1 300 train
+dvduupuoqx 1 300 test
+dvdwbwsztw 1 301 train
+dvdxtnnnmp 1 300 train
+dvdzvxciac 1 301 train
+dvecbxagzd 1 241 train
+dveiawavsq 1 301 train
+dvelhhpkvo 1 300 train
+dvemrolrwy 1 300 val
+dvemvxnmmc 1 300 val
+dvenhhshvj 0 300 train
+dvenkxynov 1 300 train
+dvfctcxrqg 1 300 train
+dvffqcoehs 1 300 val
+dvfggelian 1 300 val
+dvfgoeuinm 1 300 train
+dvfgpyfltj 1 300 val
+dvfmhaqocl 1 300 train
+dvfymgsmmd 1 241 train
+dvgbdxchzh 1 300 train
+dvgeqilcbb 1 300 val
+dvgknaqnpq 1 300 train
+dvglijlzdi 1 301 train
+dvgnnrwqne 1 300 train
+dvgrxlhsry 0 300 train
+dvgtnbiaoo 1 300 train
+dvguthxhux 1 300 val
+dvgvdygwwy 1 300 train
+dvhelaijts 1 300 train
+dvhfrlpanf 1 300 train
+dvhfsbzxbi 1 300 train
+dvhjpqxivo 1 300 train
+dvhqffxuud 1 300 val
+dvhvthlgpo 1 300 train
+dvidirtwll 1 300 train
+dvidnauyrz 1 300 train
+dvieslcdff 0 301 train
+dvihzrkglc 1 298 train
+dvinxyskoc 1 300 train
+dviplwhgui 1 300 train
+dviudfholf 1 300 train
+dvjdrhfogf 0 300 train
+dvjwublkvq 0 300 train
+dvjyhnbojh 1 300 train
+dvjzmpccug 1 300 val
+dvkbsvwkrg 1 300 train
+dvkdfhrpph 1 299 test
+dvkicveiag 1 300 train
+dvkjztmcqn 0 300 train
+dvkkzhfrfw 1 300 train
+dvkrhlndow 0 300 train
+dvkxchfqbv 0 300 train
+dvlfqigkgr 1 300 train
+dvlnrmlxjo 1 300 train
+dvlxcwzizt 1 300 train
+dvlzmksoyf 1 300 train
+dvmllfuicr 0 300 train
+dvmmryecpe 1 300 train
+dvmvkmynha 1 300 train
+dvncxecafe 1 300 train
+dvnfbddxux 1 300 val
+dvnfwudmwz 1 300 train
+dvnlnfgvak 1 300 train
+dvnqjpwfvn 1 300 train
+dvnyljoxnk 0 300 val
+dvoeuynrmu 1 300 train
+dvokziuunu 1 300 train
+dvoogowijs 1 300 train
+dvpcfmcsml 1 302 train
+dvpdxxkkng 1 299 train
+dvpfvrshkw 1 300 val
+dvpkqdigjh 1 300 val
+dvpmuwkhpl 0 300 train
+dvpzwtsznt 1 300 val
+dvqclmxwgd 1 300 train
+dvqlllaudx 0 301 train
+dvqndekiat 1 300 train
+dvqohhwjou 1 300 train
+dvqquqynkt 1 299 train
+dvqrlxuuve 1 300 train
+dvqthddptg 1 300 train
+dvrfstmwlw 1 297 train
+dvriktjvyz 1 300 train
+dvrnrzlqdo 1 300 test
+dvrpcwpawq 1 300 train
+dvrtxqtutf 1 298 val
+dvruoqbxnd 1 300 train
+dvsbugujph 1 300 train
+dvseunekna 1 300 val
+dvslakpmqw 1 300 train
+dvslrgviss 1 300 test
+dvsvpiqaad 1 300 train
+dvswqnlwgy 0 300 train
+dvsxaantho 1 301 train
+dvtddhxlcy 1 300 train
+dvtecviott 1 300 train
+dvtfjdkanq 0 300 train
+dvtggedfgf 1 300 train
+dvthcyqrco 1 300 train
+dvthlumvkk 1 300 train
+dvthzsxwnb 1 300 train
+dvtiaiezhe 1 300 train
+dvtilpgwyi 1 300 train
+dvtoritqxq 1 300 train
+dvtpwatuja 0 299 test
+dvtqmjsjpt 1 300 train
+dvtzvkcrku 0 300 train
+dvuftytmvn 0 300 train
+dvuhqhgapq 1 299 val
+dvumqqhoac 1 300 train
+dvusgcaaji 1 300 train
+dvuzmbxmjc 1 300 train
+dvuzmqrykm 1 300 train
+dvvaingisq 1 300 train
+dvvbvnobcx 1 300 train
+dvvekopjjj 1 300 val
+dvvffgunte 1 300 train
+dvvglvssak 1 300 train
+dvvpborgqi 1 300 train
+dvvqzaxqgw 1 300 val
+dvvrufajch 1 300 train
+dvvrzubojt 1 300 train
+dvvzdortuz 1 299 val
+dvwgdmetyv 1 300 train
+dvwhlcpaem 1 301 train
+dvwogkdvxn 1 300 train
+dvwpvqdflx 0 299 test
+dvwqhuqevo 1 298 train
+dvwvrtmrlf 1 300 val
+dvwwnypymn 1 300 train
+dvxfkzhmwq 1 298 train
+dvxslderub 1 298 train
+dvxuczskar 1 297 train
+dvxuddeetj 1 300 train
+dvxudjqkck 1 302 train
+dvxvpfxhas 1 300 train
+dvxwteqbti 1 300 train
+dvxwyliemn 0 300 train
+dvybyygisy 1 300 train
+dvyetljzhk 1 300 train
+dvyixgckvo 1 300 train
+dvykguonft 1 300 train
+dvyqrhoejs 1 300 train
+dvyuxkyvws 1 301 train
+dvyvppiqcp 1 300 train
+dvyzijxwpk 1 300 train
+dvzazyccgb 0 300 train
+dvzbpciyvq 1 300 train
+dvzikrvoam 1 300 train
+dvzlyikrcy 1 300 train
+dvzmolgimy 1 300 train
+dvzosejlfd 1 300 train
+dvzsntqstp 1 300 train
+dvzugrydvc 1 300 train
+dvzujgxlbr 0 300 train
+dvzwkvoefx 0 300 train
+dvzxmhkzti 1 300 train
+dvzzbsykab 1 301 train
+dvzzqivayg 0 300 val
+dwafbxmzlp 1 300 train
+dwardtgkwh 1 299 test
+dwatrclquo 1 300 train
+dwbiteoown 1 300 train
+dwbnvmlubl 1 300 val
+dwbowdmluw 1 300 val
+dwbqyobupb 1 300 train
+dwbrniefrh 1 300 train
+dwburmdnah 1 300 train
+dwbvutixof 1 300 train
+dwbyetbebi 0 300 train
+dwceebuwka 1 241 train
+dwcfnxwmfy 1 301 val
+dwcmicccsa 1 301 val
+dwcrgbyfak 1 300 val
+dwczogpery 1 300 val
+dwdktihpbm 1 300 train
+dwdsqjvuch 1 300 val
+dwdutnvemt 0 300 val
+dwdyoukiht 0 300 train
+dwdzrrvikm 1 300 train
+dwediigjit 1 300 train
+dwehmdegct 0 300 train
+dwekhhrxtv 1 297 train
+dwepeiwahc 1 300 train
+dweqqukuhk 1 300 test
+dwetzaxcec 1 299 val
+dwevzywdea 1 301 train
+dwezonukuz 1 300 train
+dwfcwugamo 1 300 train
+dwfkkajpey 1 300 val
+dwfmboanbv 1 301 train
+dwftqyotqh 1 301 train
+dwfwzvngmw 1 300 train
+dwgbqxlqzh 1 300 train
+dwgfrzahmr 1 299 val
+dwglpajork 1 300 train
+dwgtadvcwe 1 300 train
+dwgugqfrbx 1 300 train
+dwgxfiassm 1 300 val
+dwgxhzgvfl 1 301 train
+dwhewktqds 1 300 val
+dwhlwvplsz 0 300 train
+dwhobkntoq 1 299 val
+dwhogxjjva 1 302 train
+dwhpcwefvj 1 300 train
+dwhrslidcc 1 300 train
+dwhrtnaivl 1 301 val
+dwhuzwkgzp 1 300 val
+dwiegnxonz 1 300 train
+dwifzagwyl 1 300 val
+dwikmjmppn 1 136 train
+dwikyzrhxv 1 300 train
+dwimhjnmxv 1 301 train
+dwioiavflq 1 300 train
+dwirzryifn 1 297 train
+dwiuqkkzlo 1 300 train
+dwiwqkewpk 1 300 train
+dwjhuqjqdc 1 300 train
+dwjmwxgqtg 1 300 train
+dwjnjqkpzk 1 298 train
+dwjqiionzx 1 300 train
+dwjuwdjbnt 1 301 val
+dwkkqhxclz 1 300 test
+dwkmwwyvpj 0 300 train
+dwlaeboecy 1 298 train
+dwldadwkuq 1 300 val
+dwlgovxgwq 1 241 train
+dwlhmiwzsr 1 300 val
+dwlizgknzq 1 300 train
+dwlkmhbkrq 1 300 val
+dwlrlopgxr 1 300 train
+dwlxlcnhxu 1 301 train
+dwlyuilqwp 1 241 train
+dwmdolplwr 0 300 train
+dwmmadcvcv 1 300 train
+dwmqumqnjz 1 300 train
+dwmqyjrdud 1 300 train
+dwmsebyypl 0 301 train
+dwmuulwqpt 1 300 train
+dwmvqowcwl 0 299 train
+dwmylyqcai 1 300 train
+dwnblhsnoz 1 300 val
+dwnhdzuydq 1 299 test
+dwnjghnnvx 1 300 train
+dwnjpdqryv 1 300 train
+dwnofqzcss 1 300 train
+dwnuedgsbk 1 300 train
+dwnuveeret 1 300 train
+dwnuvfvgwf 1 300 train
+dwohjxbajs 1 300 train
+dwoiiugjic 1 241 train
+dwolumdlvo 1 300 train
+dwosvwqovy 0 300 train
+dwosyiggty 1 300 train
+dwotcppcgf 1 300 train
+dwowalvgfk 1 300 train
+dwpbdbpodw 1 300 train
+dwpdeehrwt 1 296 val
+dwpdozdvcx 1 300 train
+dwpjyidlfg 1 300 train
+dwpntnsiab 1 300 train
+dwpoopdkmp 0 300 train
+dwpqnoeyhp 1 298 val
+dwpurwnovd 0 300 train
+dwqbukyujc 1 300 train
+dwqdffwgzk 1 300 train
+dwqdhjlgvm 1 300 train
+dwqdqamaax 1 300 train
+dwqhiwmswx 1 300 train
+dwqhlieqey 1 300 train
+dwqnoceslb 1 300 train
+dwqoxeaejv 1 300 val
+dwrafdaquz 0 300 train
+dwrdqpjidd 0 300 train
+dwrguqzmpl 1 300 train
+dwrjyffuzp 0 300 train
+dwrleiwqtb 0 300 train
+dwrpxabjqt 1 241 train
+dwruwqicke 1 300 train
+dwrvthsffp 1 300 train
+dwrzjaqdrn 1 300 val
+dwsbuqxcbh 0 300 train
+dwscasabov 1 300 val
+dwsfreppjd 0 300 train
+dwsjwktmxj 1 298 train
+dwsmrozlbe 1 300 train
+dwsvklqtbt 0 300 train
+dwtbnrjoid 1 300 train
+dwtesjybhd 0 301 train
+dwthrmasmj 1 302 train
+dwtmueoqyf 1 300 train
+dwtpwrcnxm 1 300 val
+dwtvdylfms 1 301 val
+dwulcgctyu 1 300 train
+dwuuehrtfw 1 300 train
+dwuwkbiwdr 1 300 train
+dwuyuvtbcs 0 298 train
+dwvbumrmgo 1 300 train
+dwvcyqnrfc 1 300 train
+dwvhonewys 1 300 val
+dwvmoomhzo 1 300 train
+dwvozvlsna 1 300 train
+dwvqttyelz 1 300 val
+dwvxdhbgiu 1 300 val
+dwvxvbxioc 1 300 train
+dwvxwfoiet 1 300 train
+dwwcereael 1 241 train
+dwwninqprc 1 300 train
+dwwqjbadjc 1 300 train
+dwwsypbeok 1 300 train
+dwwvcerhyn 1 299 train
+dwwytkheyx 1 300 train
+dwxbothlyp 0 300 train
+dwxdhsacsk 1 300 val
+dwxkuqpikh 1 300 train
+dwxphntupz 0 300 train
+dwxpqefjub 1 240 train
+dwxteujjnv 1 301 train
+dwxtyzznbo 1 301 train
+dwxvxxyzgg 1 302 train
+dwxzgolduz 1 300 train
+dwyaezgzaa 1 300 val
+dwydctgjoi 1 300 train
+dwydykqtls 1 300 train
+dwyhwmuvkp 1 300 train
+dwyjfycrio 1 300 val
+dwyknfducy 1 298 train
+dwynqbgsue 1 300 train
+dwynwbyabp 1 300 train
+dwyqnukmve 1 300 train
+dwysxigtfp 1 300 train
+dwzaobyubw 1 300 train
+dwzejmhgex 1 300 val
+dwzfkpasbo 1 300 train
+dwzimdqfbg 1 300 train
+dwzrqovlzp 1 300 train
+dwzwbvyzsp 1 300 train
+dxabwtdvfh 0 300 val
+dxadhuiiyd 1 300 train
+dxafqwleke 1 300 train
+dxajdivfve 1 300 train
+dxaqhkvyeb 0 300 train
+dxaqipdvyw 1 300 train
+dxbadsmdle 1 297 val
+dxbboqrbif 1 300 train
+dxbdmugyxi 1 300 train
+dxbmssavus 1 301 val
+dxbnekvefy 1 301 train
+dxbqjxrhin 0 300 train
+dxbrjrefpe 1 300 val
+dxbsakroda 1 298 train
+dxbuljsuxq 1 300 train
+dxbvfgzokp 1 240 train
+dxcbnkgqep 1 300 train
+dxcdoqatqe 1 301 train
+dxclxjwslp 1 301 train
+dxcpfkxqzm 1 300 val
+dxcrhtiydx 1 298 train
+dxcwgceyom 1 300 val
+dxdansstna 0 300 train
+dxdbcytdid 1 300 train
+dxdboiwhoo 0 300 train
+dxddocqqho 0 300 train
+dxdjhfsrto 1 300 train
+dxdlgjufhm 1 298 train
+dxdlugvuta 1 300 train
+dxdlvylnnn 1 255 train
+dxdpvonbiy 1 300 train
+dxdsmhjlxz 1 300 train
+dxdtcwvnsf 1 301 train
+dxdtqocxjd 1 301 train
+dxdytmqtmx 1 300 train
+dxdzrfikon 1 300 test
+dxeajcrwqg 1 300 val
+dxebretfjb 0 300 train
+dxemcmxlan 1 300 train
+dxepehnhgm 0 300 train
+dxexoyuqqf 1 300 train
+dxfbdwuckx 1 300 val
+dxfdovivlw 0 300 test
+dxfjnbqegr 1 300 train
+dxfqibfleh 1 300 val
+dxgcfjarii 1 300 train
+dxgewerqli 1 299 test
+dxggzrzcpf 0 300 val
+dxgnpnowgk 0 300 test
+dxgotgmdnr 1 300 train
+dxgqpzshfu 0 300 val
+dxhacwtgxn 1 300 test
+dxhdxabssc 1 301 train
+dxhenltavi 1 300 train
+dxhgfdqpdv 1 300 train
+dxhgyiunie 1 300 train
+dxhleituhz 1 300 train
+dxhspdihsz 1 300 train
+dxicnnoilh 1 241 train
+dxieksfyad 1 300 val
+dxizvbkadb 1 300 train
+dxjahepfze 1 300 train
+dxjhcwurnv 1 301 train
+dxjkwqkpoy 0 300 val
+dxkeetpqey 1 300 train
+dxkeqytawm 1 300 train
+dxkqxgumzp 1 300 train
+dxlepkqbeh 1 300 train
+dxlfedxafu 0 300 train
+dxliakhips 0 300 val
+dxlpyszdqi 0 300 val
+dxlpzbiajj 0 297 val
+dxlwiomalq 1 300 train
+dxlytaxhoe 1 300 train
+dxmcnxzrkc 0 301 train
+dxmfvcqbeo 1 300 train
+dxmijrrmbx 1 299 test
+dxmjmeekyn 1 297 train
+dxmlvgcrfu 1 300 train
+dxmowzwvxr 1 300 train
+dxmqsnzlbh 0 300 train
+dxmtotjlpy 1 300 train
+dxnbssaubh 0 300 train
+dxnlgmvmfc 1 300 train
+dxnoupjelu 1 300 val
+dxnvgqxmka 1 300 train
+dxnvidamni 1 300 train
+dxnyhptrkz 1 299 train
+dxoktjhmat 1 300 train
+dxolvgldzh 1 300 val
+dxomhothmb 0 300 val
+dxopfluwmw 0 300 train
+dxotkftrcj 1 301 train
+dxotrxbcza 1 300 train
+dxpcynpokl 1 300 train
+dxphidlxoz 1 300 train
+dxphlwcvan 1 300 train
+dxpiiwpret 1 300 val
+dxpqnkmhby 1 300 train
+dxpzolbzgh 0 300 train
+dxqcqmfmsh 1 300 train
+dxqfbfaepi 1 300 train
+dxqhwtxwat 0 300 val
+dxqpxgnbuy 1 300 train
+dxqrotahdg 1 300 train
+dxqzynzstw 1 301 val
+dxraevezxe 1 300 train
+dxrekgwshq 1 300 train
+dxrkuldqkx 1 300 train
+dxrqdhegop 1 300 test
+dxrtkemajv 1 301 train
+dxrtunuxjb 1 300 train
+dxryfkvzyf 1 300 train
+dxsawmfpfr 1 300 val
+dxshnrsvcn 1 300 train
+dxsjmrnlgt 1 300 train
+dxsmbtnlqs 1 300 train
+dxsnbbfvau 1 298 train
+dxspscojoj 1 300 val
+dxswqlriar 1 300 train
+dxsxmemway 1 300 train
+dxtahhcouj 1 300 val
+dxtelyvrfd 1 300 val
+dxtkwribah 1 298 val
+dxttlqpkhh 0 300 train
+dxtwqloamo 1 300 val
+dxtztpodxl 1 300 train
+dxtzxqglyg 1 300 train
+dxuenwsoet 1 300 train
+dxufplmrlm 1 300 val
+dxuliowugt 1 300 train
+dxuplhwvig 1 300 train
+dxuppenqky 1 240 train
+dxurmhqxwy 1 300 train
+dxuxkyqhof 0 300 train
+dxvapecbvc 1 300 val
+dxvcwfziyx 1 300 train
+dxvddjmexe 1 300 train
+dxvgdftehj 1 300 train
+dxvmnsxrrv 1 301 train
+dxvpdvmcjp 1 300 train
+dxvuwkqimv 0 300 train
+dxwevhvjhm 1 300 train
+dxwizawmim 1 300 train
+dxwkixitat 1 300 train
+dxwopfbqun 1 300 train
+dxwvavgnsr 0 300 train
+dxxrzvnetn 1 301 train
+dxxxefjrdg 1 300 train
+dxyakiyigf 1 300 train
+dxydqtnkgi 1 300 train
+dxygfcclgu 1 300 val
+dxyhmyrxrr 1 298 train
+dxyhygfcry 1 300 train
+dxykhefnal 1 300 train
+dxykzwnuoj 0 300 train
+dxymrazgdv 1 300 val
+dxynhvcwrh 1 300 val
+dxyscyrjgu 1 298 train
+dxyvzmpqgp 1 300 train
+dxyxalbuty 1 300 train
+dxzccjuqnz 0 241 train
+dxzfmwayan 0 300 train
+dxzfynmsis 1 300 train
+dxzgokytcd 0 300 train
+dxzitnlvqg 1 300 train
+dxzlcobcos 1 300 train
+dxzscteuyd 1 300 train
+dxzuueaush 1 300 train
+dxzyaovkks 1 300 train
+dyabsuwjpo 1 300 val
+dyaerjijja 1 300 val
+dyanizlneu 1 301 train
+dyaxisxukj 1 300 train
+dybcnokooq 1 100 train
+dybfpqertz 1 300 train
+dybftpanwm 1 301 train
+dycaoznyxq 1 301 train
+dycdufdjnf 1 299 val
+dycetgrdtx 0 300 train
+dycmubnkqs 1 300 train
+dycqaiefqc 1 302 train
+dycsnodlkx 1 300 train
+dycxvvosfn 1 300 val
+dydfvqqufi 0 300 train
+dydgxalbvq 1 300 val
+dydlkguthz 1 300 train
+dydtmhlkhl 1 300 val
+dydxojzqvc 1 300 train
+dyesrdnfia 1 300 val
+dyeztclfvf 1 300 val
+dyfdshoysi 1 300 train
+dyfgrcslaw 1 302 train
+dyfiizgexn 0 300 train
+dyfndegyow 1 300 train
+dyftroxrlv 1 300 train
+dyfyicyqoc 1 301 train
+dyfyxbbkyl 0 301 train
+dygdyijkli 1 298 train
+dyggbogcao 1 300 train
+dygglqlujl 1 299 test
+dygjctawfl 1 300 train
+dygowyeveo 1 300 train
+dygqkwggyf 1 300 train
+dygrvmhzsb 0 300 train
+dygsjlcqut 1 300 val
+dygtwamvce 1 300 train
+dygvvksupx 1 300 train
+dyhatkzikn 1 300 train
+dyhbgjmqff 1 300 train
+dyhcyaozmv 1 300 train
+dyhegporuf 1 300 train
+dyhgpfadsd 1 300 val
+dyhmwdcbsl 0 300 val
+dyhnlrkhki 1 300 train
+dyhntnsmkd 1 301 val
+dyhqlqnkdl 1 301 train
+dyifxrijyv 1 300 val
+dyihxvpdkk 1 300 train
+dyiixvqmjt 1 301 val
+dyilsajcvs 1 300 train
+dyioiacfyw 1 300 train
+dyitupcvjm 1 241 train
+dyiulogsqs 1 301 train
+dyivrafsux 1 300 val
+dyjdjspzew 1 298 train
+dyjfkbskab 1 300 test
+dyjgbbvocn 1 300 train
+dyjilzokmy 1 300 train
+dyjklprkoc 1 300 test
+dyjosvrgxy 1 301 train
+dyjtfbqrmt 1 300 train
+dykdovyrzi 1 239 train
+dykhpkyxsq 1 300 train
+dykjyitsbn 1 300 train
+dykljokhdg 0 300 train
+dykyivrvxo 1 300 train
+dylfraworx 1 300 train
+dylgbuxnpy 0 300 train
+dylkvpccwb 1 300 train
+dylmbeyjub 0 300 train
+dylpnjoqjb 1 300 train
+dymbelijah 1 299 test
+dymblxfjlj 1 300 val
+dymccsnduc 1 300 train
+dymfianyot 1 301 train
+dymnwzerlb 1 300 train
+dymulfowor 1 300 train
+dymuwnxxuc 1 300 train
+dymxcnijsb 1 300 train
+dynapptfga 1 300 train
+dyndlgrzak 1 300 train
+dynenqzqfe 1 301 train
+dynkwlbhop 1 300 train
+dynkwuikss 1 300 train
+dynmsxtbup 1 300 train
+dyocqhemds 1 300 train
+dyocrnsuuo 1 301 train
+dyoenqbezb 1 298 train
+dyokztqbey 1 301 val
+dyolakhvvw 0 300 train
+dyoobcxpxe 1 300 train
+dyosfmifna 1 300 train
+dyoskkopze 1 300 train
+dyosradcyd 1 300 train
+dyotjlcnhf 1 300 train
+dyowjilyiv 1 300 train
+dypesfpwyi 1 300 val
+dypetrfpio 1 300 train
+dypjkknirz 0 298 train
+dypncubgem 1 300 train
+dyprovhtkx 1 300 val
+dyprswzlcf 1 299 train
+dypyuejyev 0 300 train
+dypyvrxpvs 1 300 train
+dypzaguael 1 300 train
+dypzlziecx 1 300 val
+dyqeddqknx 1 301 train
+dyqggzcpxc 1 300 train
+dyqhomjvap 0 300 train
+dyqmhvcsbr 1 241 train
+dyqorzmjbc 1 300 train
+dyqpeliimv 1 300 train
+dyqraywxwq 1 300 train
+dyqxksgrqq 1 300 train
+dyrcppjudh 1 300 train
+dyrgnpkgmc 0 300 train
+dyrioijzef 1 300 train
+dyrparmuyd 1 300 train
+dyrpdgfucs 1 300 val
+dyrqeiyoqt 1 300 train
+dyrqzossla 1 301 train
+dyrskzsbvj 1 300 train
+dyrsrqsspu 1 301 train
+dysayreyzb 1 300 train
+dysijtsjkv 1 300 train
+dysizbnenh 1 300 train
+dysjipkwuz 1 301 train
+dyslulaxmu 0 300 train
+dysqgsohru 1 299 test
+dyssggqavj 1 300 train
+dystbicdrt 1 301 val
+dystevlhwp 1 299 train
+dytatnzqic 1 300 train
+dytbiqhhzf 1 300 val
+dythhiiokb 0 300 train
+dytpllwlko 1 300 val
+dyuavxunox 1 300 train
+dyudbbgcgj 1 300 train
+dyuebhxulp 1 300 val
+dyuirqtols 1 300 train
+dyukishyle 1 300 train
+dyulsjviud 1 300 train
+dyuoeeubqr 1 300 val
+dyuxqtrhxj 1 300 train
+dyuykxjdyd 1 300 val
+dyvexiwgdf 0 300 train
+dyvoikduac 0 301 train
+dyvozbrdte 1 300 val
+dyvudcaipy 1 300 train
+dyvvxwyrau 1 301 train
+dywdrkkyvy 1 299 train
+dywegzqyel 0 300 train
+dywfozyczf 1 300 train
+dywkdfclzy 1 300 val
+dywozyxkiy 1 300 train
+dywronddes 1 300 test
+dywrvfnhme 1 300 train
+dywryacbba 1 300 train
+dywsegvtvy 1 300 train
+dywsgmqpbp 0 300 train
+dywxefvgfi 1 300 test
+dyxbmpetbl 1 300 train
+dyxdggbmgk 1 300 val
+dyxetbwkgf 0 300 train
+dyxhwddplw 1 300 train
+dyxkpgpugl 1 300 train
+dyxmvodnfp 1 300 train
+dyxnxclbhg 1 300 train
+dyxrjcadtt 0 300 train
+dyxzpjsrom 0 300 train
+dyyarhqoie 1 301 train
+dyycxcfjhs 1 300 train
+dyyemtaizw 1 300 train
+dyyeqxvdct 1 300 val
+dyysdftqyd 1 300 val
+dyzfijaqsv 1 300 train
+dyzgapdmtk 1 300 train
+dyzgupxtij 1 301 train
+dyziovfxes 1 300 train
+dyzjiomjcd 1 300 train
+dyzkwqexox 1 300 train
+dyzlcakqty 0 300 train
+dyzlonzlxt 0 300 train
+dyzlyeclbs 1 300 train
+dyzmvojocj 1 300 train
+dyzowrafjy 1 300 train
+dyzrwzetse 1 300 train
+dyzvemjqpw 1 300 train
+dzaaqgupfn 1 298 train
+dzakrufkag 1 300 train
+dzaollfqxv 1 300 train
+dzaqkzjwfe 1 300 val
+dzaqzpuhdo 1 300 val
+dzarqiebzh 1 300 val
+dzatgmnqzj 1 299 train
+dzauhngzwk 1 300 train
+dzaxrputrs 1 299 train
+dzbgolojvf 0 300 train
+dzbptdqivh 1 300 train
+dzbqxrrxgx 1 300 train
+dzbrrnxrlj 1 300 val
+dzbsaplpbs 1 300 train
+dzbtmzyupz 1 300 train
+dzbtoxlwnc 1 300 train
+dzbtozxlwb 1 300 train
+dzcdamilyz 1 300 train
+dzcnbpcndg 1 301 train
+dzczyujerh 1 300 train
+dzdbunuaag 1 299 test
+dzddfezpon 1 300 train
+dzdiqfvapz 1 300 train
+dzeatonfds 1 300 val
+dzeczhacap 1 300 train
+dzekkugqlc 1 301 train
+dzelmotnxm 1 300 train
+dzemyvvctu 1 300 val
+dzeqnzgwae 1 300 train
+dzereelrhe 1 300 train
+dzerihccix 1 300 train
+dzezotgbhf 1 300 val
+dzezzlmtrb 1 300 train
+dzfavttdga 1 300 train
+dzffetljax 1 300 val
+dzfkwxvmhc 1 288 train
+dzfqjqccuz 1 300 val
+dzfysxngqu 1 300 train
+dzgajtndul 1 241 train
+dzgdrirujh 1 300 train
+dzgfihepxl 1 300 train
+dzgfolcvpq 1 301 train
+dzgfxjhife 1 300 val
+dzgqeodbeh 1 300 val
+dzgxaeplnl 1 300 val
+dzhethcpbw 0 300 train
+dzhgfitdlb 1 300 train
+dzhjxalykq 1 300 val
+dzhkiyfivt 0 300 train
+dzhrlgdhbu 1 300 train
+dzhrumagfs 1 300 train
+dzhrxcqhax 1 300 train
+dzhsjhxrfv 0 300 train
+dzhugeqyah 1 300 train
+dzhumksrow 1 300 train
+dzhvblathg 1 301 train
+dziapjyyep 1 300 train
+dzibnoxuyy 1 301 val
+dzieklokdr 1 300 train
+dzigzulwio 1 300 train
+dziiojrtkv 1 300 train
+dzimvwqasw 1 300 train
+dziomdvusw 1 300 train
+dzipvqsmpi 1 300 train
+dzirlqbwbh 1 300 train
+dzixignzrh 0 300 val
+dzjfftmkee 0 300 train
+dzjgfpssjx 1 300 train
+dzjiczigjr 1 300 train
+dzjikkybip 1 300 train
+dzjjtpjtum 1 300 train
+dzjlwxgbyc 1 298 train
+dzjpxmzgqu 1 300 train
+dzjsckzcmq 1 300 train
+dzjswiqnmm 1 300 test
+dzjswxpstl 1 300 val
+dzjzsbobdm 1 300 train
+dzkelwouxi 1 300 train
+dzkfjraptq 1 300 train
+dzkyxbbqkr 0 300 test
+dzlajpdppz 0 300 train
+dzlblcmrqc 1 299 test
+dzlkulrplo 1 300 train
+dzlnrbwdda 1 300 train
+dzlovvyyvl 1 300 train
+dzlpfpszyv 1 300 train
+dzlrdixjgv 1 301 train
+dzluexijkb 1 300 train
+dzlvydjnkp 1 300 train
+dzmdabeasy 1 300 train
+dzmeejhrpz 0 300 train
+dzmiebgfrr 1 301 train
+dzmjdnpvsc 0 300 train
+dzmklkehbv 1 300 val
+dzmynqyozi 0 300 train
+dznchaiaqh 0 300 train
+dzngxjxwjy 1 300 train
+dznjykynmf 1 300 train
+dznofrvkfp 1 300 train
+dznonnujmx 1 239 train
+dznsvkxdrs 1 300 val
+dznvouzzwl 1 300 train
+dzochfswby 0 300 val
+dzoespidyr 0 300 train
+dzojiwfvba 0 300 test
+dzowjphhzo 1 300 train
+dzpftjovem 1 241 train
+dzpiyxspwh 1 147 train
+dzpokpqpxr 1 300 test
+dzprrfdsmi 1 300 train
+dzptrcpemh 1 300 train
+dzpychqarm 0 300 train
+dzqegetlbl 1 300 train
+dzqgkilpso 1 300 train
+dzqirdgvts 0 300 val
+dzqirzkwon 0 300 train
+dzqjzlcgsm 1 269 train
+dzqnkdwrph 1 300 train
+dzqrjsoaiq 1 301 val
+dzqvkueslt 1 299 val
+dzqwgqcxgb 1 300 train
+dzqwgqewhu 1 300 train
+dzqworubhq 1 300 train
+dzrajnnfly 1 301 val
+dzrfembxvh 1 300 train
+dzrgflxexs 0 300 val
+dzrhmljhqr 1 301 train
+dzrjhrbppm 1 300 train
+dzrrklwrgn 0 299 train
+dzrtfcvmxm 0 300 train
+dzsahoadbg 1 300 train
+dzsbwuvwhm 1 300 train
+dzsfpjguev 0 300 train
+dzsgbnotgw 1 300 train
+dzshbwcwyu 1 299 test
+dzskoafoai 1 300 train
+dzslxmhkjj 0 300 train
+dzstrtwvix 1 300 train
+dzsuxocyja 1 300 train
+dzsyoehyuv 1 300 train
+dzszxdjkfc 1 300 val
+dztfgwfowu 1 300 val
+dztivnzyod 1 300 train
+dztnjpqcwj 1 300 train
+dztucuwgpi 1 300 train
+dztuhkucrj 1 300 train
+dztvaulyqr 1 300 val
+dztvfdabkn 1 146 train
+dztvxrzuta 1 299 val
+dztwnoiwit 1 300 train
+dzudprvlso 1 296 train
+dzuliuxzcj 1 300 train
+dzumdajyot 0 301 train
+dzunnkqxwk 1 300 train
+dzunurmjac 1 300 train
+dzuqsmzxbr 1 300 train
+dzuqydykva 1 299 val
+dzutxqywjo 1 300 train
+dzuufmvuxn 0 300 train
+dzuxxgokdh 1 300 train
+dzuyvasvct 1 241 train
+dzvaykngjf 1 300 train
+dzvbcsvjpx 1 298 train
+dzvijsbblm 0 300 train
+dzvnmcdpjl 1 300 train
+dzvtosyezr 1 300 train
+dzvxnkvwon 1 300 train
+dzvyfiarrq 1 300 train
+dzwjzqfbtg 1 300 val
+dzwkjohixg 1 300 val
+dzwkmcwkwl 1 300 train
+dzwleiudsk 1 300 test
+dzxiokxmzp 0 300 train
+dzxiwecdvq 1 300 train
+dzxqjtzzjp 1 300 train
+dzxqrbsowj 1 301 train
+dzxrtnnmlc 1 300 train
+dzxsudpvwm 1 300 train
+dzxtgayaos 1 300 val
+dzxujqzfqc 1 297 train
+dzxyryiwvc 0 300 train
+dzyawpcord 1 300 val
+dzyayxyzbx 1 300 train
+dzymzqavcd 1 302 val
+dzyrczavxf 1 300 val
+dzytlzjmvt 1 300 train
+dzyuwjkjui 0 300 train
+dzywbvexqk 1 300 train
+dzyzpdnurd 1 300 train
+dzzacniwka 1 300 train
+dzzbigqcpf 1 300 train
+dzzcfvkgth 0 299 train
+dzzevfhzgv 1 300 val
+dzzinekulq 1 300 train
+dzzqmjyrzi 1 300 train
+dzztxvsixn 1 300 train
+eaaelnilal 0 300 train
+eaakpmkvvp 1 300 train
+eaaksafhqq 1 300 train
+eaamzvbgnw 1 300 train
+eaapbktdnv 1 300 train
+eaapzkypip 1 300 train
+eaatxeoeeu 1 300 train
+eaaysmdwlq 1 300 train
+eabaekshvs 0 300 train
+eabedsqyyu 1 300 train
+eabghyltka 1 300 val
+eabjipvech 1 300 test
+eaboxmgote 1 288 train
+eabucrvsij 0 300 val
+eabyiybnkn 0 300 train
+eabzzdgsfx 1 300 train
+eacjsuqenz 0 300 train
+eacsjvcmlp 1 300 train
+eacxmpguml 1 300 val
+eadaevhzal 1 300 train
+eadaszpjuj 0 300 train
+eadfkyulrk 1 300 val
+eadirncnsr 1 300 train
+eadolnlbix 1 300 val
+eadunjmjwk 1 300 train
+eaeaysrowp 1 301 train
+eaedyunofo 1 302 train
+eaehumgyox 1 300 train
+eaekowvqkh 1 300 train
+eaeulwiese 1 301 train
+eaevlthzlv 1 300 train
+eaewlbhlxk 1 300 train
+eafavjmdow 1 301 val
+eafgqrkhlc 0 300 train
+eafptmmzpn 0 300 train
+eafvwvolnz 1 300 val
+eafwtyslpe 1 300 train
+eagawpusdy 1 300 train
+eagiowqlut 1 300 train
+eagofaifqi 1 300 val
+eagqabbzku 0 300 train
+eagqnsbiyh 1 241 train
+eagrizoiyl 1 300 train
+eagvrawvlk 1 300 train
+eagzlzukzh 1 300 train
+eagzrwdomn 1 300 train
+eahfxxbwtf 1 300 val
+eahgjoumll 1 300 train
+eahhbyqhgj 1 300 train
+eahlqmfvtj 1 300 train
+eahmseribf 1 300 train
+eahoycmeem 1 299 train
+eahsqrwwum 1 300 train
+eahsxehlri 1 300 train
+eahthbqnbe 1 300 train
+eahvhdfruw 0 300 val
+eaigdemyfo 0 241 train
+eaikuhffkj 1 300 val
+eairfbaswz 1 300 val
+eajgfnbvsq 1 300 val
+eajlrktemq 1 300 train
+eajqbwrfye 1 298 train
+eajqduyhcm 1 300 train
+eajtsffbsf 1 300 train
+eajucugllb 1 300 train
+eajucwhxrd 1 300 train
+eajuvhrqfr 1 300 val
+eajyzvoldu 1 300 val
+eakcqdpvqh 0 297 train
+eakdiizgyl 1 300 train
+eakkjrcceq 1 300 val
+eaknukltqk 1 300 train
+eakouqtamo 1 301 train
+eakrsghbip 0 300 train
+eakyrzutmx 1 300 train
+eakzedasol 0 301 train
+ealfplhqdz 1 300 val
+ealguqfocu 1 300 train
+ealngzauwe 1 300 train
+ealnqgxkml 1 300 train
+ealtwtwcbq 1 300 train
+ealulizawd 1 300 test
+ealupsrfoh 1 300 val
+ealvekafep 1 300 train
+ealzrkfkvs 0 300 train
+eamafzemde 0 300 train
+eamdbluhqf 1 300 train
+eamixkghtw 1 136 train
+eamrgdchjd 1 300 train
+eamrrztkth 1 300 train
+eamrsjonro 1 300 train
+eamzkxxtyi 1 300 train
+eamztfdvar 1 300 train
+eanjomskin 1 300 train
+eanpsjwtjm 1 300 val
+eanriatjbj 1 301 train
+eanspddxov 1 301 train
+eanubsjnbk 1 300 train
+eanvyvphfw 1 300 train
+eaobwivwzb 1 299 train
+eaodavfsgj 1 300 train
+eaohfhprhc 1 300 train
+eaolaqoahr 0 300 train
+eaortrqjnv 1 300 train
+eaozkblmif 1 298 train
+eappwiyrnd 0 300 train
+eaqfgjytez 1 300 train
+eaqkwhzfwr 1 300 train
+eaqkzccyga 1 301 train
+eaqpooegza 1 300 train
+eaqqrmewhd 0 300 train
+eaquarsawu 1 300 train
+eaqxklixlu 0 301 train
+earcinbicd 0 300 train
+eargjkwkjv 1 300 val
+earglhdosu 1 300 train
+eargzslqfq 1 300 val
+earmovzoce 1 300 val
+earndmttfj 1 300 train
+earrhxgtwp 0 300 train
+earvpccijm 1 302 train
+earwwwxica 1 300 train
+earyrbmojv 1 300 train
+easamiahht 1 300 val
+easdczlojt 1 300 train
+easdkteqig 1 300 train
+easfqanzlg 1 301 train
+eatiatqptv 1 300 val
+eatiuwqqwf 1 146 train
+eatjcstfnq 1 298 train
+eatqiqtytv 1 300 val
+eatqqovdlh 1 299 val
+eauhakbohz 1 300 test
+eaujamlrfj 1 300 train
+eaupixxtjv 1 300 train
+eauzbdfdsx 1 300 train
+eavapuimmt 0 301 train
+eaveotxisi 1 300 train
+eavufxkqps 1 300 train
+eavvwidqco 1 300 train
+eavwghkobe 1 300 train
+eaweencjhp 1 241 train
+eawewfnuvx 0 300 train
+eawgevdqke 1 300 train
+eawjjaiqqc 1 301 val
+eawmkkxrkz 1 297 train
+eawmtjadch 1 297 train
+eawmxkambo 0 300 val
+eawqvpdcze 1 300 train
+eawwblntbt 1 241 train
+eawyztoxbb 0 300 train
+eaxdyuetrk 1 300 train
+eaxkilqqgu 0 300 train
+eaxmcrkbtm 0 300 train
+eaxmnqtquf 1 300 train
+eaxtktogbc 0 300 val
+eaydqjivcs 1 300 val
+eayfrsvqsk 0 300 train
+eaygibsmca 1 241 train
+eayqjrrqce 1 288 train
+eayzufzneh 1 300 train
+eazbaqodcy 1 298 train
+eazhkerxkw 1 301 val
+eazkicaoye 1 300 test
+eazsywdpgh 1 300 train
+eaztlyeegn 1 301 train
+eaztsjkpxo 1 301 val
+eaztsmksng 1 300 train
+eazuxemota 1 300 val
+ebaaoffjez 1 300 train
+ebaeervdea 1 301 train
+ebafpavapo 1 301 train
+ebaggobefz 1 299 train
+ebagtzwylp 0 300 train
+ebahevofla 0 300 train
+ebakrsmaqv 1 300 val
+ebaneftpfp 1 300 train
+ebaopkgfpx 1 300 train
+ebauhnngna 1 298 val
+ebavidcenm 1 300 train
+ebbdatnxfr 1 300 train
+ebbszssvhj 1 300 train
+ebbvlrvabj 1 300 val
+ebcfeeeokx 0 300 train
+ebchwmwayp 1 300 train
+ebcogwdmdf 0 300 train
+ebcoilpbjo 0 300 train
+ebcrealkaj 1 300 train
+ebcuslqgql 1 300 val
+ebcviipxzp 1 300 train
+ebczzbenwe 1 134 train
+ebdblblfiy 1 299 train
+ebdeippuqf 1 300 train
+ebdfapkiyf 1 300 train
+ebdimfrmaz 1 300 train
+ebdlffrebe 1 300 train
+ebdlkpyehs 1 300 train
+ebdpceuqsy 1 300 train
+ebdtpdzptc 1 300 val
+ebdysevkut 1 300 train
+ebeaounzou 1 300 train
+ebeaywqydn 1 300 val
+ebebgmtlcu 1 300 train
+ebedrtozak 1 300 val
+ebejzdkxll 0 300 train
+ebeknhudxq 1 300 train
+ebenjegtdw 1 300 train
+ebenvuuxld 0 300 train
+ebetwpftfm 1 301 val
+ebevzcuydw 1 300 train
+ebezansurq 0 300 train
+ebfapqiklf 1 300 train
+ebfasahlma 1 300 train
+ebffuhuesn 1 136 train
+ebfqwugmjo 1 300 train
+ebfzzxgswf 1 300 train
+ebgdzfwmlm 1 300 train
+ebgfcbkgmc 1 300 train
+ebgmolbmjs 1 300 train
+ebguokagfp 1 300 train
+ebgwpuuiet 1 300 val
+ebgxudzwqm 1 300 val
+ebhcifgskz 0 300 train
+ebhimgkrjz 1 300 train
+ebhmsikovp 1 300 val
+ebhocdvthd 1 301 val
+ebhwiimkbl 1 298 train
+ebhzhkizzd 1 300 train
+ebivjdieda 1 300 val
+ebizjhbujg 1 299 train
+ebjcqjslzz 1 300 val
+ebjdkllijf 1 300 train
+ebjdmhnula 1 300 train
+ebjflxoidl 1 300 train
+ebjloshjfk 1 300 train
+ebkatwvaqr 0 300 train
+ebkcxeqyab 1 300 train
+ebkgmakwhy 0 300 train
+ebkklhrlgh 1 300 val
+ebkovtksah 1 300 train
+ebkowxhori 0 300 val
+ebktdzzjjt 1 298 train
+ebkuhscfdy 1 300 val
+ebkzdtebmn 1 300 train
+ebkzwjgjhq 1 300 train
+eblqksfzzd 1 297 val
+eblrskkhle 0 300 train
+ebluzeutae 1 300 train
+eblxsklbah 1 300 train
+eblzoeldgf 1 300 train
+ebmgcemgbu 1 302 val
+ebmintmsej 1 300 train
+ebmkpusppg 1 300 train
+ebmnymgbgm 1 300 train
+ebmotsujrb 1 300 train
+ebmqlzcihi 1 300 val
+ebndcklvsn 1 300 train
+ebnerkxicg 1 301 val
+ebnkmcrkmp 1 300 train
+ebnlvzkonj 1 300 train
+ebnmfiduev 1 300 train
+ebnswzlvrn 1 300 train
+ebnxrhxxdt 0 300 val
+ebofoaidos 0 300 train
+ebonugqvvy 1 300 train
+ebopmkcizs 1 300 train
+eboqtnoxkv 0 300 train
+ebosfjhxjv 1 300 val
+ebosgrhdhy 1 300 train
+ebouxgards 1 240 train
+ebpcpykogz 0 296 train
+ebpeiurmir 1 300 train
+ebppbyuyhc 1 302 train
+ebpxbudvzv 1 299 test
+ebpyicqwue 1 300 train
+ebqceovwpd 0 300 train
+ebqhfutsih 1 300 train
+ebqoqarrqh 1 300 train
+ebqzawwggb 1 300 val
+ebreyymxvq 1 300 train
+ebritkxdkz 1 298 train
+ebrqdazrsn 1 300 val
+ebrqqkgqnw 1 299 test
+ebrsglqviz 1 301 train
+ebrtmonrma 1 300 train
+ebruxirvwv 1 300 train
+ebrvrilohg 1 300 train
+ebsprndmew 1 300 train
+ebssfwplww 1 300 val
+ebsusunsoo 1 300 val
+ebsvuoccfd 1 300 val
+ebtgcelpdh 1 300 train
+ebtkdczsdq 1 300 train
+ebtmzfqfdt 1 300 train
+ebtnolrmuu 1 298 train
+ebubrjyqns 1 300 val
+ebubysoxsl 1 300 train
+ebuebnxpdq 0 300 train
+ebuejzauxq 0 300 train
+ebuiraiusk 1 300 train
+ebukatsryj 0 300 train
+ebuspmwinh 1 300 train
+ebuthbfhyn 1 300 train
+ebvanagxbt 1 300 train
+ebvezhagrw 1 299 val
+ebvmlmfspr 1 300 train
+ebvnljnrtk 1 298 train
+ebvtprlgyz 0 300 train
+ebvvelqptf 1 300 train
+ebwfhpgflm 0 300 val
+ebwgzmehdo 1 298 train
+ebwirtdlkj 1 300 train
+ebwjtjcspx 1 300 train
+ebwtzueget 1 300 train
+ebwvoufqvr 1 299 val
+ebwwhdprfb 1 301 val
+ebxeniwdgc 0 300 train
+ebxibuuior 1 300 val
+ebxnhqeaab 0 300 train
+ebxopxoftt 1 300 train
+ebxrckrvig 1 300 val
+ebxruufffq 0 300 train
+ebxuhcrcsw 1 301 train
+ebxvxrayde 1 300 train
+ebxyllfnrk 0 300 val
+ebydkhkocs 1 240 val
+ebydtebztb 1 300 train
+ebyhzsyxbe 1 300 val
+ebyjfupubp 1 300 train
+ebymoslfbe 1 300 train
+ebywfrmhtd 1 300 train
+ebyyimdpyq 1 300 val
+ebyzltjpio 1 300 train
+ebzjvbdmcb 1 300 train
+ebzsbvkutx 1 300 train
+ebzspprfny 1 300 train
+ebzsqgfpgh 1 300 test
+ebzxcrbzxb 1 300 train
+ecaetyjowd 1 300 train
+ecafszsdek 1 300 val
+ecahafxewo 1 300 train
+ecaokdxkyd 1 300 train
+ecaoqmcbzo 1 300 train
+ecapgjqeqe 1 300 train
+ecatbfciue 1 300 train
+ecaztssenr 1 269 train
+ecbdlzgwnb 0 300 train
+ecbdylimvv 1 302 val
+ecblkidyfd 0 301 train
+ecblmrgwqa 1 300 val
+ecbrdquqjw 1 299 val
+ecbyigsmki 1 298 train
+eccejkqjha 1 300 train
+ecchngslsy 0 300 train
+ecciahmjyw 1 300 train
+eccpdfpjel 0 300 val
+eccwcbxwkd 1 300 train
+eccwrliesa 1 299 train
+ecdgxqhelh 1 300 train
+ecdilzfkkl 1 301 train
+ecdmvsbwqi 1 300 val
+ecdrgdcntl 1 300 train
+ecdvbjqjzc 1 300 train
+ecdvjgbxko 1 300 train
+ececuhyxce 1 300 train
+eceeqbggko 1 300 train
+ecehrqxntu 0 301 train
+ecelngerjo 1 300 train
+ecelwhkmdj 1 301 train
+ecemscsrgg 1 300 train
+ecemumkhki 0 300 train
+eceoujbjts 1 299 test
+ecephunsas 0 300 val
+ecepjwtain 1 300 train
+eceqlqfuyt 1 299 train
+ecetgjzzxa 1 300 train
+eceyvbrdyq 0 300 train
+ecfahncafd 1 300 train
+ecfcmnyxzr 1 300 train
+ecfhgekaxs 1 301 val
+ecfltbjoqj 1 300 train
+ecfrafyddr 1 300 train
+ecftnkdiaf 1 300 train
+ecfvkaewto 1 300 train
+ecfydhcubl 1 300 train
+ecgasoiagm 1 300 val
+ecgfsrobbr 1 300 train
+ecgpjltjoi 0 300 train
+ecgvpejkiz 1 300 train
+ecgxyeitnb 1 300 train
+echdilwfig 1 300 test
+echfgpirum 1 300 val
+echgmuftdh 0 300 train
+echgyzthwo 1 300 train
+echiwtcepm 1 300 val
+echurwqdgu 0 300 train
+eciaaifomk 1 301 val
+eciawhfnli 1 241 train
+ecibulzlxj 0 300 train
+ecilroerik 1 301 val
+eciqmzhjpv 1 300 train
+ecispyzqqy 1 301 train
+eciwkxuihs 1 300 train
+eciygjkaco 0 300 val
+ecjjzukqpy 1 300 test
+ecjoabovik 1 300 train
+ecjozlfeec 1 300 train
+ecjvnpqqhw 1 300 train
+ecjzrnrbdm 1 301 train
+eckarqzmwa 1 300 train
+eckgwjepzp 1 300 train
+eckhsharba 0 298 train
+eckloytegm 1 300 val
+eckmiopfpa 1 301 val
+eckpsuekqw 1 297 train
+eckqlnpbjc 0 300 train
+ecktwohmhf 0 300 train
+eckvhdusax 0 300 train
+eckwxkgvov 1 300 train
+eckzvdwhpo 1 300 train
+eclbfxrelo 1 300 train
+eclmwgvast 1 300 train
+eclnhayuzs 1 300 train
+eclnowceyi 1 300 train
+eclpgjjies 1 300 train
+eclxonfxph 0 300 train
+ecmeyklynx 1 300 train
+ecmqlztklx 1 300 train
+ecndenhhar 1 300 train
+ecnhovxzfr 1 300 train
+ecnihjlfyt 1 300 train
+ecnjoogewp 0 300 train
+ecnmwevrxo 1 300 train
+ecnpwevklo 1 300 val
+ecnuekyfvy 0 300 train
+ecnveamelz 1 300 train
+ecnymtxkje 1 300 train
+ecnzdhwgpi 1 300 val
+ecolfbruyi 1 300 train
+ecooazclij 1 300 val
+ecozbsimsz 1 300 train
+ecpcmwowel 1 301 val
+ecpcukyzsu 1 300 train
+ecpebsnnjc 1 300 val
+ecpenpslvu 1 300 val
+ecpiawvxqa 1 300 train
+ecpldziywn 1 300 train
+ecploqnumu 1 300 train
+ecpoizyscr 0 300 train
+ecptxiqiqp 1 300 train
+ecpucsrwvb 0 300 val
+ecqawxcied 1 300 train
+ecqdyvucxr 1 300 train
+ecqfzguvwy 0 300 train
+ecqiuhmijo 1 301 train
+ecqjxsqqss 1 301 train
+ecqkcffgur 1 300 train
+ecqpbhajkx 1 300 val
+ecqpebjrvo 1 300 train
+ecqulzqtgl 1 300 train
+ecqzntbaqf 1 300 train
+ecrfunevaq 1 300 train
+ecrpzeuebj 1 300 train
+ecrskxqpav 1 300 val
+ecrtyidcrf 0 300 val
+ecsaiortsl 0 240 val
+ecsbuzreow 1 300 train
+ecscbclfaa 1 300 train
+ecsjgdocyg 1 300 val
+ecsjyvknwr 1 300 train
+ecsnnvmapj 1 300 train
+ecsthpibzf 1 299 val
+ectccevjdi 1 300 val
+ectceantef 0 300 train
+ecternqfam 1 300 val
+ectfovhloh 1 298 train
+ectsztyumi 1 300 train
+ecudvgsqtg 1 300 val
+ecujsjhscd 0 300 train
+eculwfsisv 1 300 train
+ecumyiowzs 1 299 test
+ecuqjdbvxb 1 301 val
+ecutcsdroz 1 300 train
+ecuvtoltue 1 300 train
+ecuyjkrxsh 1 300 train
+ecveihaltc 1 300 train
+ecvgmmausm 1 300 train
+ecvmcszigb 1 300 train
+ecvmsxuhyh 1 300 train
+ecvxkykmvx 1 300 train
+ecwaxgutkc 1 300 train
+ecwihculqd 0 300 train
+ecwkhsqzmu 0 300 train
+ecwmsjcmfo 1 300 train
+ecwpnhqoji 1 300 train
+ecwqbmxmci 1 300 val
+ecwvwwbcks 1 240 train
+ecxdkuoeyh 1 241 train
+ecxlhoizxw 1 300 train
+ecxpywhqcl 1 300 train
+ecxywgqcig 1 300 train
+ecxzwatjkp 1 300 train
+ecydbcaucn 1 300 train
+ecyhhwgqjg 1 297 train
+ecynynmmqc 1 300 train
+eczcpjxzwv 0 301 train
+eczejwdufy 0 300 train
+eczgxkofnq 1 300 train
+eczkjtiyda 1 300 train
+eczoeypdon 1 300 val
+eczoulhdgj 1 300 train
+eczrdidouk 1 300 train
+eczrseixwq 1 300 train
+eczyaosjdw 1 300 train
+eczyfvuyar 1 292 val
+edabmiuwgo 1 300 val
+edabyclzaq 1 300 val
+edaixxkrhl 1 300 train
+edanjkaglb 1 300 val
+edavfjsjzw 0 300 train
+edavtoeiaz 1 300 train
+edbarpohfu 1 300 train
+edbbvqusfo 1 301 train
+edbnhesvjl 1 301 train
+edbpulmoms 0 300 train
+edbvkqmchr 1 240 train
+edbzjnlluo 1 302 train
+edbzkdecmf 1 300 train
+edbzvbusjl 0 300 train
+edcfsauyck 0 300 train
+edcfsbfmgq 1 300 train
+edcmihwqte 1 301 train
+edcmufkmfj 1 300 train
+edcnreebpl 1 300 train
+edcpubzfyh 0 300 val
+edcshxtedg 1 300 train
+edcuaolvxj 1 300 train
+edddrcdisq 1 300 train
+eddeoggvwd 1 300 train
+eddfbqjngn 1 300 train
+eddhqplbbu 1 300 train
+eddocxyxea 1 300 train
+eddpavstag 1 300 train
+eddqbbzglr 1 300 train
+edehcgwmjh 1 300 train
+edemmtmucu 1 300 train
+edeswiwtiy 0 300 train
+edevpyuazf 0 300 train
+edfgmedgcw 1 300 train
+edflgfgttc 0 300 train
+edfmwxmirk 1 300 train
+edfnrrtvdn 1 300 train
+edgetzirqr 1 300 train
+edggkddtuv 0 241 train
+edggzblxzn 1 300 train
+edghvpdkdo 1 300 train
+edghxugaar 1 300 train
+edgruppmkq 1 300 train
+edgtolrkuk 0 241 train
+edgvzjmegm 1 300 train
+edgznrmukf 1 300 train
+edheaxeika 1 300 train
+edhxeguahw 1 300 train
+edhygwpogy 1 300 train
+edhzaowwqu 1 300 train
+edihjkoutx 1 300 train
+edipqtcxwb 1 300 train
+edixsialsl 1 300 train
+edizgmdmgt 0 300 train
+edjdplatqy 1 300 test
+edjfbhwszx 1 300 train
+edjhsiympc 0 301 train
+edjpcuaeoi 1 300 train
+edjpmkmqqf 0 300 train
+edjsytrrth 1 300 val
+edjwguukpi 1 300 train
+edjycjxyyn 1 300 train
+edjysbcefn 0 300 train
+edkdrisuig 1 301 train
+edkfnoqfsk 1 300 train
+edkgfulflr 1 298 train
+edkoiqvrsh 1 300 train
+edlbptdzgh 1 300 val
+edldghszvx 0 300 train
+edljnwnywc 1 300 train
+edlqvwpgbg 1 300 train
+edlsockxzy 1 300 train
+edlswsvlxc 1 300 val
+edlvcobgyu 1 300 train
+edlvzpquzr 1 300 val
+edlzuklmzp 1 300 train
+edmeouzxdg 1 300 val
+edmiitrplj 1 300 train
+edmmhxrwls 1 300 train
+edmpqmyqzc 1 300 train
+edmrdlwfbp 1 300 val
+edmtrwmxkl 1 300 train
+edmuqomdea 1 300 val
+edmuvmtcde 1 300 train
+edmvpoaniw 1 300 val
+edmwkcbltz 1 300 train
+edmxswvrpy 1 298 train
+ednakzreoi 1 300 train
+edniskuoda 1 300 train
+ednjxskkrq 1 300 train
+ednmcryfis 1 300 train
+edntyxboxd 1 239 train
+ednucjfqso 1 300 train
+ednvnkmnze 1 239 train
+ednwmipeqg 1 300 train
+ednxpkgmqz 1 300 train
+edoaeudzsq 1 300 train
+edodholdem 1 300 train
+edommikmmi 1 300 val
+edoncwqstd 1 300 train
+edoneuwjjh 0 300 train
+edonifbtms 1 302 train
+edoovwrjwc 0 300 val
+edopoapqqc 1 297 train
+edosobmtzq 0 300 train
+edovkrceaj 1 300 train
+edovmwavuw 1 300 train
+edoxxahron 1 300 train
+edoyiewjlb 1 300 val
+edpbqnwtho 1 300 train
+edpffjbmai 1 300 train
+edpgkratsh 1 300 train
+edphailgtd 1 300 train
+edphtavcep 0 300 train
+edpjgsunfy 1 300 val
+edpplzvuyt 0 300 val
+edpuiwxgvi 1 300 train
+edpuvbmtma 1 240 val
+edpxwlarmk 1 99 train
+edqhdckynd 1 300 train
+edqkgcokbg 1 300 train
+edqpmwkqov 1 300 train
+edquqwggla 1 300 val
+edqzxkqpsk 1 300 train
+edrmgejsbk 1 300 train
+edrmjajich 1 300 train
+edrszsylkf 0 300 train
+edrxlfynvl 1 300 train
+edryvpqidj 1 300 val
+edscpejjej 1 300 val
+edsjrpcbqk 1 300 val
+edsnricakl 1 300 train
+edspezanem 1 300 train
+edsrnhlody 1 300 train
+edsrzuxmna 1 300 val
+edswamyrbb 1 300 val
+edsxkhhcmd 1 300 train
+edszrezley 1 300 val
+edtccalvgr 1 300 train
+edteomnawz 0 300 val
+edtkmpkjnh 1 301 train
+edtpirebkl 1 300 train
+educnopmxl 0 300 val
+edudlkyelu 1 299 test
+eduebqhpua 1 300 train
+edueoohlhy 1 300 train
+edugqvrwhn 0 300 train
+edujhukcnh 1 300 train
+edujkduqgi 1 240 train
+edukarxbph 1 300 train
+edukbnrdyq 1 300 train
+eduorgiuji 1 300 train
+eduxitjqlq 1 300 train
+eduxlfqxhg 1 300 val
+edvaveetbi 0 300 train
+edvegifxop 1 300 train
+edvgguggat 1 147 train
+edvgsefgph 1 241 train
+edvjqxbppi 0 300 train
+edvlekdczt 1 301 train
+edvmejcjhe 1 300 train
+edvooqzakj 1 301 train
+edvrbvjvzf 1 300 train
+edvsrpoqyg 1 300 test
+edvtkbpxxi 1 300 train
+edvtyrosef 1 300 val
+edvyiiycqu 0 300 train
+edvyxmzpoy 1 300 train
+edwbjpderw 1 300 train
+edweilpuxf 1 300 train
+edwmmaidud 0 300 train
+edwqmdnhyq 1 300 val
+edwqoonrkm 1 300 train
+edxmterncv 0 300 train
+edxnyohbss 1 300 val
+edxucnxbld 1 300 train
+edybkoaxzp 1 300 train
+edyfklgxcg 1 300 train
+edylmobkop 1 300 train
+edyncaijwx 0 300 train
+edynogjene 0 300 train
+edywwjquvz 1 300 train
+edzgjmnyul 1 300 train
+edzkoxpomb 1 300 train
+edzpqqevtb 1 301 train
+edzsttaqss 1 301 train
+edzuirorfg 0 300 train
+edzxnrvabc 1 241 val
+eeaegnbros 1 300 val
+eeajrcwkjq 1 300 train
+eeaorbezrt 1 300 train
+eeaowdnspv 1 300 train
+eeaumdyeyu 1 300 val
+eeayaqmanz 1 300 train
+eebmdnyjhf 1 300 train
+eebmtqwvqq 1 300 train
+eebrkicpry 1 300 train
+eebserckhh 1 300 train
+eebsinngza 1 241 train
+eebtzyoqyd 0 300 train
+eebysksbls 1 300 val
+eecepngvqz 1 298 train
+eecjlreedm 1 300 train
+eecjpuwzfp 1 300 train
+eecjupixac 1 301 val
+eectmahvrw 1 300 train
+eecvubghfz 1 301 train
+eedbxggago 1 300 train
+eedeexqyxg 1 298 train
+eedghgksif 0 300 train
+eedgkctjzh 0 300 val
+eedqpctook 1 241 train
+eedrlxtqbe 0 300 train
+eedwazoljh 1 300 val
+eedwyzhipo 1 300 train
+eeeaorttvg 0 300 val
+eeedajhatk 1 301 val
+eeeepxupkq 1 301 train
+eeekohpfpm 1 300 train
+eeemkqbcjz 1 300 train
+eeendmhkkm 1 299 test
+eeerpjthmb 1 300 train
+eeetcyeeyl 1 302 train
+eeeuihqdtu 1 300 val
+eeeurclykg 1 300 train
+eeeuyarirv 1 300 train
+eeeuzozcdc 1 300 train
+eeevqpmusf 1 300 train
+eeexurxfne 1 300 train
+eeeyhhrkky 1 301 train
+eeeyxlsxys 0 300 train
+eefejwnqso 1 300 train
+eefeqlzxnz 1 300 train
+eefjhklvnt 1 300 val
+eefolqhehe 1 301 train
+eefvalcpvd 1 300 train
+eefziuudfy 1 300 val
+eefzpdrrji 1 300 test
+eegdvwikhz 1 301 val
+eegenfikbt 1 241 train
+eegeqglget 1 300 train
+eeggpudlqb 1 300 train
+eeghdjervn 1 298 train
+eegkohxuzb 1 297 train
+eegmumuemt 1 300 train
+eegnbkemau 1 300 train
+eegrkbmpqw 0 300 train
+eegzqcqtrm 1 300 train
+eehgcdgiok 0 300 train
+eehljtnybv 1 300 train
+eehmfwoqrp 1 300 train
+eehrknynfg 0 300 train
+eehuqngkfz 1 301 train
+eehvawzjgy 1 299 test
+eeiabruiqj 1 300 train
+eeiaqkzsxi 0 300 train
+eeigpdutpu 1 300 val
+eeimpqlmmu 1 300 train
+eeiqmuxzxk 1 300 train
+eeixunjdkp 1 300 train
+eejdelozuo 1 300 train
+eejepiavgr 1 300 train
+eejgkudwwg 1 300 train
+eejhtxbvqs 1 298 train
+eejkfqcfzb 1 300 train
+eejlnggyjj 0 300 train
+eejnusvlxl 1 300 train
+eejphearhs 1 300 train
+eejsansfwg 1 300 val
+eejsmcmiwp 1 300 train
+eejswgycjc 1 300 train
+eejzuckqqk 0 300 train
+eekextuzpv 1 300 train
+eekfppyltt 0 300 train
+eekftvuvcl 1 300 train
+eekifrwqhw 1 300 train
+eekjyzjxyx 1 300 train
+eekozbeafq 1 300 train
+eelaraased 1 241 train
+eelbzbcbtz 1 300 train
+eeldlakiax 1 300 val
+eeldudssre 0 300 train
+eelegoxjwv 1 300 train
+eelgidejif 1 300 train
+eelgnwuftv 1 300 train
+eelmkpomil 1 300 train
+eelwdpafyr 0 300 train
+eelyrdflzy 1 300 val
+eemhauxoon 1 300 train
+eempfhjvbl 1 136 train
+eempsqftgk 1 241 train
+eencgyhphy 1 300 train
+eenmkbzwie 1 300 train
+eenursprfr 0 300 val
+eenvmpihlw 1 300 train
+eenzjiaonh 1 298 train
+eeohcepxjm 1 300 train
+eeoibqzlsn 0 300 train
+eeoiyuexop 1 301 val
+eeoocnftja 1 300 train
+eeoudoxwvy 1 300 train
+eeowbtdjld 1 300 val
+eepctzeyfj 1 300 train
+eepezmygaq 1 300 train
+eephmartuo 1 300 train
+eeplnfjawz 1 298 train
+eeplsokidd 1 300 train
+eepogoslrw 1 300 train
+eepqrmtrdk 1 300 val
+eepqzrqyvg 1 300 train
+eepubbscmz 1 300 val
+eeqfqxwenp 1 300 train
+eeqhlygayp 1 300 train
+eeqmaiiwnx 1 300 train
+eeqnbbafzq 1 300 train
+eeqolwqbrz 1 300 train
+eeqtqmhxhc 1 239 train
+eeqxajletz 1 300 train
+eeqxlsczov 1 300 train
+eeqxmjwbhi 1 301 train
+eeqywdjklq 1 249 train
+eerbsimaoy 1 300 train
+eerdaigypv 1 300 train
+eerhmzaebh 0 300 test
+eeriyvjsek 1 301 train
+eerksicnlb 0 300 train
+eerlpkvyoe 1 300 val
+eerytoiriw 1 300 train
+eerzkchzes 1 300 train
+eescbdtoom 1 300 train
+eesfbidqme 1 300 train
+eesijpscve 1 300 val
+eetakjhfpa 1 300 train
+eeticefxfy 1 296 train
+eetigtaciw 0 300 train
+eettnaxgcz 1 300 train
+eeubskpxct 1 300 val
+eeuekpiwkh 0 300 train
+eeuesbytld 1 300 train
+eeufkcoyxh 1 300 train
+eeuhwigdaq 1 300 val
+eeuifzvhrd 1 300 train
+eeuihevxnp 1 298 val
+eeuoyqlhav 0 300 val
+eeuwqbtjfu 1 300 val
+eeviuzlfep 1 300 val
+eevmlqhdlq 1 301 val
+eevoyzaxdu 0 300 train
+eevqjlqsze 1 300 train
+eevqzfycse 1 300 train
+eevtminqmf 0 300 val
+eevyugldiw 1 300 test
+eewaqxuxhe 1 300 val
+eewdjolhyx 1 301 val
+eewldeutuw 1 300 train
+eewlybcbhd 1 300 train
+eewmsudhdh 1 300 val
+eewsngeqfs 1 300 train
+eewysqrcjf 1 300 train
+eexcywfrgo 1 299 train
+eexezlsjtr 1 300 train
+eexkzgqygl 1 297 train
+eexqilyakb 1 300 train
+eexvwbiwtk 0 300 val
+eexwytsgqy 1 300 test
+eexxvmpggy 1 299 train
+eeyhxisdfh 1 300 train
+eeyiwiccrp 1 300 train
+eeympgyzqq 1 300 train
+eeyoadgncr 1 298 val
+eeyomeqcox 1 300 train
+eeyrbkikrn 1 300 train
+eeysqqfhmd 1 300 train
+eeyvnarnjk 0 300 train
+eeyynsvput 0 300 train
+eezednepcp 0 301 val
+eezmfnvxxt 1 300 train
+eezvdezfmk 1 241 train
+efafhdmuoh 1 298 train
+efagybpxsa 1 299 val
+efaiqwiifj 0 300 train
+efakoetljk 1 300 val
+efapytglsw 1 300 train
+efaqphwrbp 1 300 train
+efatpchndx 1 300 train
+efavvsoaaa 1 300 train
+efazuieysm 0 300 train
+efbfhuxssy 1 301 train
+efbibsmgpw 0 300 train
+efbkgcgnnk 1 300 train
+efblbrmxmo 1 300 train
+efbmvocbli 1 300 train
+efbnfluhyj 1 300 train
+efbnulqveo 0 300 train
+efbsmnanjr 1 300 train
+efbwpzryhw 0 300 train
+efbyrychuz 1 300 train
+efcbhtwcid 1 300 val
+efcdxjwwih 1 300 train
+efcexvmafw 1 298 train
+efciphfqmh 0 300 train
+efclidoyxb 1 300 train
+efcoqvfsor 1 300 train
+efdclayinw 1 300 train
+efdidhtpfe 1 300 train
+efdiqgqeka 1 300 test
+efdiwgnruf 1 300 val
+efdkuyhtwk 1 301 val
+efdkxeccdb 1 301 train
+efdrhtxknl 1 300 val
+efdtgxwvqz 1 300 train
+efdvvlnzre 1 300 val
+efdyrflcpg 1 300 train
+efdzfglkij 1 301 train
+efefzyesss 1 300 train
+efegfjphrk 1 300 train
+efejzzlrzf 1 300 val
+efekpstvwa 1 300 train
+efeksfusfk 1 288 train
+efelqzmraz 1 300 train
+efelurriyk 1 300 train
+efeodzzrap 1 300 val
+eferfasxqg 1 300 train
+efeshzcjpb 1 300 train
+efewacqeov 0 300 train
+efexumqepp 1 300 train
+efezbuuywa 1 300 train
+effavbfvay 1 300 train
+effbozsxwq 0 300 train
+effdaakkfi 1 302 val
+effgbuweip 1 300 train
+effzuiqxof 1 300 train
+efgbikipop 1 300 train
+efghsdmasb 1 300 train
+efghtoxzvr 1 300 train
+efgqtwalbf 1 300 val
+efgqvhbfqj 1 300 train
+efgsgzdtqk 0 300 train
+efgtkqtbgi 1 300 train
+efgvfqstmy 1 249 train
+efgvueaxxb 1 300 train
+efgxwnhdkg 1 300 train
+efhbwwulqb 1 301 train
+efheepqyek 1 300 train
+efhkwuvvaa 1 299 val
+efhpkoezxm 1 300 train
+efhvfcxjgl 1 300 train
+efhxffocsi 1 300 train
+efhzelzdrq 1 300 val
+efianwppfc 1 300 train
+eficoxxbuo 1 300 train
+efifcvxhrj 1 300 train
+efifkfdwsb 1 300 train
+efinthqyej 1 300 train
+efipryhtum 1 300 train
+efityeiwol 1 300 train
+efjgycrwfm 0 300 train
+efjpwlxrna 1 300 val
+efjsowsghk 1 300 train
+efjtzmmzrw 0 300 train
+efjwcpgxdh 1 241 train
+efjwwuxkwk 1 300 val
+efkafgubac 1 300 val
+efkceiaman 1 300 train
+efkgduniwg 1 300 train
+efkhzzvwae 1 300 train
+efkmolgbwm 1 300 train
+efktbhpilh 1 300 test
+efktkdkcmi 0 300 train
+efktschtcb 1 300 val
+efkzktkwib 0 300 train
+eflgczcfbn 1 292 val
+eflhlqmvek 0 300 train
+eflkohgemk 1 300 val
+eflszerajt 1 300 val
+efltqxolqu 1 300 val
+efmefgbbmk 1 300 train
+efmkwlqfip 1 300 train
+efmlcnltqk 1 297 train
+efmnwgoyrj 1 300 train
+efmpbqiqwp 0 300 val
+efmsxlltcc 1 300 test
+efmtxmmbfk 0 300 train
+efmwrzibgb 1 300 val
+efmygjljqk 1 300 train
+efnhvieljj 0 300 train
+efnjaehgha 0 300 train
+efnkrsjatw 1 300 val
+efnvjluzuk 1 300 val
+efobouzjft 1 300 train
+efoepnvsts 1 300 train
+efoidbhppd 1 300 train
+efoiowmcxr 1 302 val
+efosnegbxc 1 300 train
+efovkozvvn 1 300 val
+efpaxjwljv 1 300 val
+efpcfzhbpe 0 300 train
+efplrldzjr 1 300 train
+efpphckcoi 1 300 train
+efpwzhmwot 1 300 train
+efqcwnyqdu 1 300 train
+efqfomvqac 1 300 train
+efqhfcoyla 1 300 train
+efqidahvcx 1 241 train
+efrairxdnm 1 300 train
+efrdbafwek 1 300 train
+efrmclojib 1 300 val
+efrsirqypc 1 301 train
+efrvcykret 1 300 train
+efrxdmajmo 0 300 train
+efsctplmax 1 300 train
+efsjmhfaee 1 300 train
+efspcwthbh 1 300 train
+efsrpkmmir 1 299 val
+efstpwwzpb 0 301 train
+efsukarxtn 1 300 train
+efsxfbsiah 0 300 val
+efsxjcnhde 1 300 train
+efsxoprojd 1 301 train
+eftdhqdlpm 0 300 val
+eftgkvaolu 1 300 train
+eftlgmpiaw 1 300 val
+eftmygtdqe 0 300 train
+eftsoaodey 1 83 train
+efttfxdapw 1 300 train
+efudijaxql 1 300 train
+efudwfbimj 0 302 val
+efufmaxost 1 300 train
+efurhupnmd 0 300 val
+efuwlafayn 1 300 train
+efuzqmxhww 1 300 test
+efvdbkpjkj 1 300 val
+efvgkwyndm 1 300 train
+efvinhpbvv 1 297 train
+efvivrzkxk 1 301 train
+efvsfftuqr 1 300 train
+efvskmshjy 1 300 train
+efvwmeyfmp 1 300 train
+efwctulsjy 1 300 train
+efwfsixgtg 1 300 train
+efwfxwwlbw 0 300 train
+efwgjxvxtd 1 300 train
+efwicykjoh 1 300 train
+efwjqzgfnh 1 300 val
+efwonrvqvy 1 300 train
+efwpkrmymk 1 300 train
+efwvynstiq 1 300 train
+efxbkgszyu 1 300 train
+efxfqjeiyx 1 269 train
+efxkpdxsjs 1 300 train
+efyafdmuwy 1 300 train
+efydxghsro 1 300 train
+efyeuidsum 1 300 train
+efyphrhpsw 1 300 train
+efyvmzqltw 1 300 train
+efyxjqvife 1 301 val
+efzotvfgsh 1 300 train
+efzpuiidej 1 298 train
+efzqlpbdfm 0 300 train
+efzuagfooh 1 300 val
+egagtyxwzl 1 300 train
+egamepwdao 1 300 train
+egaomrgpvf 1 300 val
+egbbcxcuqy 1 300 train
+egbgzhqgwd 1 300 train
+egbkdnafdv 1 300 train
+egbllgwolp 1 300 train
+egbraautld 1 301 train
+egbxumstdp 1 147 train
+egcasqzjep 1 300 train
+egcaufhmql 1 300 train
+egcbrmnnxy 1 300 train
+egcggwtorf 0 300 train
+egchvltqhp 1 300 train
+egcizcdwjn 1 300 train
+egcliesbel 1 300 train
+egclqvbnus 1 300 train
+egcnwhidnx 1 300 train
+egcovnwlvk 1 300 train
+egcugeafxw 1 300 val
+egcuyhyvsm 0 300 val
+egcypeckff 1 300 train
+egdccoieoe 1 241 train
+egdhgkhcwo 1 300 train
+egdklvgpna 0 300 val
+egdsycypqd 1 302 val
+egeazrsikj 1 300 train
+egedxqsldk 1 300 train
+egeoefoqfi 1 300 train
+egeomopbmn 0 300 train
+egeubcpncv 1 300 val
+egevbbvbao 0 300 train
+egewjfugot 1 300 train
+egewtjimtb 1 300 val
+egexebmgjn 1 300 train
+egeyqhrepq 1 298 val
+egfnxjndxw 1 300 val
+egfscjuldp 1 300 train
+egfsdciomi 1 298 val
+egfspresvk 0 300 val
+egfuigjmtu 1 300 train
+egfyngguuj 1 300 train
+eggbjzxnmg 0 300 train
+eggcbcoedw 1 300 val
+eggcyhcqyg 1 300 train
+eggguurzxm 1 300 train
+egghreippu 0 300 train
+egghxjjmfg 0 300 train
+eggkjyonil 1 301 train
+eggloxdfmw 1 300 train
+egglwffeoh 1 300 val
+eggovkhgzv 1 301 train
+egguywfami 1 300 val
+eggzqfbjti 1 300 train
+eghbponxfi 1 300 train
+eghcnsaqxg 1 300 train
+eghfdunoxv 1 300 train
+eghhfgzxme 1 301 train
+eghhkfyvub 1 298 train
+eghjdoktvi 1 301 val
+eghloowibn 1 300 train
+eghtpxasxj 1 300 val
+eghvuzdbpi 1 301 train
+egidjdstrw 1 298 train
+egidkvnqlz 1 300 train
+egisulhdfa 1 300 val
+egiwkclyov 1 300 train
+egjaackanr 1 300 val
+egjrqbcgym 1 301 train
+egjuhkwdbf 1 300 val
+egjwyrjipy 1 300 train
+egkabdaxla 1 298 val
+egkaufznwj 0 300 train
+egkddnuimv 1 300 train
+egkqlmafpr 1 300 train
+egkwbrsnbl 1 300 train
+egkzkygmol 1 300 val
+egkzonvoze 1 300 train
+eglbpmqqbu 1 300 train
+eglhjecykb 1 300 val
+eglifouwvd 1 300 train
+eglmnhfbop 1 300 train
+eglnibqjaw 1 300 val
+eglxlqogub 1 300 train
+eglymosdch 1 300 train
+egmawhhfxz 1 300 val
+egmfodhqrc 0 300 train
+egmhohtjpu 1 300 train
+egmjtxwlxq 1 298 train
+egmmrvopga 0 300 train
+egmpwlgksc 1 299 train
+egmweglpxm 1 300 train
+egngozmkht 1 300 train
+egnotwcxjh 1 300 val
+egnqyvikah 1 300 train
+egnwccuxvw 1 300 train
+egnzyfpyzj 1 300 val
+egofsshnwd 1 300 train
+egolarylow 1 301 train
+egolbmkdql 1 300 train
+egomtvwwam 1 300 train
+egoxlpllxp 0 300 train
+egoxvspxpt 1 300 train
+egpoquwuzu 1 300 train
+egppeylgqv 1 300 train
+egpvnriqsj 1 300 train
+egqfaebbxc 1 300 train
+egqkdzwaxb 1 300 train
+egqoennnkj 1 300 val
+egqszphwcg 1 300 val
+egqugnqibo 1 300 train
+egrhqadvti 1 300 val
+egrjayncbz 1 300 train
+egrktyzwsi 1 300 train
+egrpjvuozo 1 300 train
+egrqlxkpno 1 300 train
+egrrujwgsm 0 300 train
+egrtychdmx 1 300 train
+egrvkcxuuq 1 300 val
+egrydmhptw 1 299 train
+egrygbrykh 1 300 train
+egsaglisze 1 300 train
+egsbawlylz 1 240 train
+egsbilbdyb 1 300 val
+egscejrtnp 1 300 train
+egscoezvho 1 300 test
+egshgiwyhy 1 300 train
+egsnwjttut 1 300 train
+egsosnvkcw 1 300 val
+egsssbbxba 1 300 train
+egsxemfpsx 1 300 train
+egtrjvgggy 1 300 train
+egtudazaxw 0 300 train
+egtxdxsgxa 1 300 train
+egtyjqxnik 1 300 train
+egtyqeijek 1 300 train
+egubcolndw 1 300 train
+egudtwimqd 1 240 train
+egugkoamjm 1 300 train
+egulmgdddz 1 299 test
+eguqjwflyk 1 298 train
+egusftvcqp 1 241 train
+egvdzdcshe 1 300 val
+egvfazotxc 1 301 val
+egvkxaaams 1 300 train
+egvnnoaqss 1 300 train
+egvnshhsod 0 300 train
+egvolptnbm 1 300 train
+egvtogliqb 1 300 train
+egvwgnhzgo 1 300 train
+egwapsifcv 1 300 train
+egwcrporui 1 300 train
+egwektrfea 1 299 val
+egwlxvswjr 1 300 val
+egwnfutaes 1 241 train
+egwodjebum 1 300 train
+egwohwxzxa 1 300 val
+egwugrneww 1 300 train
+egwyvhmynr 1 300 test
+egwzzhemvk 1 301 train
+egxbehzmza 0 300 train
+egxdgjsilw 1 300 train
+egxuqchbas 1 300 train
+egydpqaqrc 1 300 train
+egyemqrvna 0 300 val
+egykjflrjp 0 239 train
+egymkdavul 1 601 train
+egyogbgocw 1 300 train
+egyvikphfi 1 300 train
+egyxkzfdec 1 300 train
+egyyajhxxk 1 300 val
+egyyygqsah 1 300 train
+egzdspgmem 1 300 train
+egzfaoiuwo 0 300 train
+egzimzpfcs 1 300 train
+egzkwyqirh 0 300 train
+egzpkatcuu 1 300 train
+egzsoxdoag 1 300 train
+egztpetrgt 1 300 train
+egzuajyaqg 1 299 train
+egzwvowoll 1 300 train
+egzxuzyqnc 0 300 train
+egzymbqkdk 1 296 train
+egzyxqihni 0 298 train
+egzyzkccxi 0 300 train
+ehalrbynuz 1 300 train
+ehanjytlnn 1 300 train
+eharakfchp 1 300 train
+ehbkztvcup 1 300 val
+ehbmjfgrfc 0 301 train
+ehbnclaukr 1 300 train
+ehbqymthjl 1 300 train
+ehbujerrtd 1 300 test
+ehcbtioqtu 1 300 test
+ehccixxzoe 0 300 train
+ehccxkudjh 1 300 train
+ehcezdniyx 0 300 train
+ehcfeogadx 0 300 train
+ehcrtspwao 1 241 train
+ehdcylhhpm 1 300 val
+ehddpxwcnw 1 300 train
+ehddydqurb 1 300 val
+ehdhktcffz 1 300 train
+ehdikivxij 1 298 train
+ehdkmxgtxh 1 300 train
+ehdyzxlyra 1 300 train
+ehdzakapuz 1 300 train
+ehetlufgmx 0 300 train
+eheuapnenp 1 300 train
+eheutlaxrs 1 241 train
+ehevsxtecd 1 300 train
+ehexpzhdjn 1 300 val
+eheykkgmjt 1 300 val
+ehffttxoty 1 300 train
+ehfiekigla 1 300 train
+ehfmarmsvo 1 300 test
+ehfordcuzn 1 300 val
+ehfrnagsqf 0 300 train
+ehftosntej 1 300 train
+ehfxdpqzyd 0 300 val
+ehfxdzkoiy 1 300 train
+ehfxohnspa 1 300 train
+ehfyngvztc 1 300 train
+ehgdzhkdvo 0 300 train
+ehgebgisym 1 300 val
+ehghmpjdta 0 300 val
+ehglixdkng 1 300 train
+ehgnwomhxb 1 299 val
+ehgpscsvsm 1 298 train
+ehgqdpyewx 0 300 val
+ehgxmfxyyg 1 297 val
+ehhctgbaoo 0 300 train
+ehhdhytqns 1 300 val
+ehhhjbfsyd 1 300 train
+ehhjdvadcq 1 300 train
+ehieahnhte 1 300 train
+ehiwlsfbbi 1 241 train
+ehiyauqubp 1 297 train
+ehjjbktrfs 1 298 val
+ehjkdsbmcm 1 300 train
+ehjkvtgdkm 1 300 train
+ehjnrkppbm 1 300 val
+ehjzkjisrx 1 301 train
+ehkfhndcxe 1 301 train
+ehkhjxtdzp 1 300 train
+ehkieeghqv 0 300 train
+ehkjdctavq 1 300 test
+ehkynxgilr 1 301 val
+ehlesppxfw 1 300 val
+ehlhxncasy 1 300 train
+ehloeocbky 1 300 train
+ehlvevmbxz 1 301 train
+ehlzgsgrgm 1 300 train
+ehmlnfjniv 1 300 train
+ehmqwkdulq 1 300 train
+ehmqzjshbm 1 300 train
+ehmtrgjafl 1 300 train
+ehmvilvlvj 0 300 train
+ehmxtsynns 1 300 train
+ehnadojbix 1 300 train
+ehnkivreie 1 300 val
+ehnuidfhdu 1 298 train
+ehnurjujoc 1 301 val
+ehnvjqosux 1 300 train
+ehobliprdk 0 300 train
+ehobuslnal 0 300 val
+ehobxyylop 1 300 val
+ehockowsde 1 300 train
+ehodfjcnbc 1 301 train
+ehoemabgmp 1 301 val
+ehoeuoufwu 1 300 val
+ehoiajkgyp 1 301 val
+ehojxfiaap 1 300 train
+ehovqehcia 1 300 train
+ehpgayhiso 1 300 train
+ehpqtlflru 1 300 train
+ehprcizkpq 1 300 train
+ehpsvsmndp 1 301 train
+ehptzgpilt 1 300 train
+ehpvmvxbkk 1 300 train
+ehpwmtyvwm 0 300 train
+ehpzjoeixx 1 297 train
+ehqbyettan 0 300 train
+ehqdmysloe 1 301 train
+ehqfpnfynf 1 300 train
+ehqihqvjos 1 299 test
+ehqvqhsutl 1 301 val
+ehqwygtfsp 1 300 train
+ehqydnqxph 1 240 val
+ehqyvztebg 1 300 train
+ehrbdspppd 1 300 train
+ehrihcwppi 0 300 train
+ehrnoovzhq 1 300 train
+ehroayenhj 0 300 val
+ehrorehijn 1 298 train
+ehrpxcekyy 1 300 train
+ehrrreprkw 1 300 train
+ehrsmbkjtb 1 297 train
+ehrtdalgon 1 299 test
+ehrvldbien 1 300 train
+ehskchyvya 0 300 val
+ehssudncod 1 300 val
+ehsxbdyiog 1 300 train
+ehtbcrzwed 1 300 train
+ehtbiqorco 1 300 train
+ehtdtkmmli 0 300 train
+ehtdvrunlh 1 300 val
+ehthgupumf 1 300 test
+ehtkcisdcw 1 300 train
+ehtmhdbslm 0 300 val
+ehtvcnlsfl 1 300 train
+ehtzerphxf 1 296 train
+ehuazwrzbn 1 299 test
+ehubzcyblo 1 300 train
+ehudnzecnx 1 300 train
+ehuhioxwkk 1 298 train
+ehuhoftycr 1 300 train
+ehukntokuk 1 300 train
+ehumahschx 1 300 val
+ehuqhfdwmi 1 300 val
+ehuwbscwhw 1 300 train
+ehuwusqcgf 1 300 train
+ehuynjtdav 1 300 train
+ehuytoctru 1 300 val
+ehvdzmzoiq 1 300 val
+ehvhopfden 1 300 train
+ehvjruzsyj 1 300 train
+ehvpjyhqrg 1 300 train
+ehvvslnvry 1 300 train
+ehwcyxmtmb 1 301 train
+ehwhbqciyf 1 300 train
+ehwheaeegg 0 300 train
+ehwjfenbgu 1 300 train
+ehwoohpulw 1 300 train
+ehwplguwps 1 300 train
+ehwqcsduyw 1 298 train
+ehwxlndsmd 1 300 train
+ehxbhbvrew 1 300 train
+ehxxmfftom 0 300 train
+ehxxnbbgbf 1 300 train
+ehxywkaozo 1 300 train
+ehxzrvgvtx 1 300 train
+ehybveurpz 1 300 train
+ehyfxxxftq 1 300 train
+ehypjoufkk 1 300 train
+ehytkbagyq 1 300 train
+ehyvaxnvja 1 300 train
+ehzdxohyqb 1 300 train
+ehzfwxkwhd 1 300 val
+ehzjkbkwps 0 300 train
+ehzqipzfma 1 300 train
+ehzsvkcjuo 1 301 train
+ehztvhixpt 1 300 train
+eiacyfdkat 1 300 train
+eiahuhzvcx 1 300 train
+eiakhsfjxc 1 241 train
+eiarkrzjub 1 300 train
+eiatoypqys 1 300 train
+eiavukmbqd 0 300 val
+eiayatksud 1 299 test
+eibcsmcirp 1 300 train
+eibcvggmsf 1 300 train
+eibdzfaaif 1 297 val
+eibeoodnpu 1 300 train
+eiblikazji 1 300 train
+eibvbudwaa 1 300 train
+eibvvpheen 1 300 val
+eibwnqrgcz 1 301 train
+eicabwrsjp 1 300 val
+eicanaeuha 0 300 train
+eiciutahwn 1 300 train
+eiclimddwo 1 300 train
+eicljcllqv 1 147 train
+eicngtwvoh 0 300 train
+eiczxyyqbi 1 300 val
+eidbgwganx 1 298 train
+eidjkkcbhy 1 300 val
+eidlfhngvi 1 301 val
+eidprxiitt 1 301 train
+eidrmsvilp 1 300 train
+eiduajoefc 1 300 train
+eiduiphlgm 1 300 train
+eidwbuxuaf 1 300 train
+eidwmykvut 1 301 train
+eieeqxhsqk 0 300 train
+eieidbvula 1 300 train
+eiejvxtsaj 1 300 train
+eiewfmymhx 1 300 train
+eifdjwcjnq 1 300 train
+eifikirvoo 1 300 val
+eiflffikuj 1 300 train
+eifretwgfd 0 300 val
+eifrztnuki 1 298 val
+eifujvlrzd 1 300 train
+eifwjwcqkj 1 300 train
+eigrmzgems 1 301 train
+eigrxcetcn 0 301 val
+eigybmsmoj 1 298 train
+eiheiceuxo 0 300 train
+eihfonpsfc 1 300 train
+eihnptbcya 1 300 train
+eihtvotdpv 1 300 train
+eihucwigue 1 300 train
+eihuncenpr 1 300 train
+eihxhddeou 1 300 train
+eihygqtdkc 0 300 train
+eiicmuoagl 1 301 train
+eiidlcmtzl 1 297 val
+eiigievbjx 1 298 val
+eiiiqhiphs 1 298 train
+eiiizbbmop 1 300 train
+eiismzeitf 0 300 train
+eiitvcurxz 1 300 train
+eiiwtmkobc 0 300 train
+eiixwxgauo 1 299 test
+eiixxwaydk 1 300 train
+eiiyumhoit 1 300 val
+eiizkzbdxd 1 300 val
+eijbjnpqua 1 300 train
+eijccqrkkx 1 300 train
+eijchtxdae 1 300 train
+eijcykinhu 1 300 train
+eijnbogsok 1 300 train
+eijokhuyst 1 299 val
+eijspnbyow 1 300 train
+eijsyonzeq 0 300 train
+eijuqrgaqp 0 300 train
+eijwkjkjtm 1 300 val
+eijycsdien 1 300 train
+eikalyqiab 0 300 train
+eikgmiykos 1 300 val
+eikgoxbhht 0 300 train
+eikinwdezq 1 300 train
+eikjcrnmxc 1 300 train
+eiklavlmtk 1 300 train
+eikqvabflm 1 300 val
+eiksdtapzc 1 300 train
+eilcvcovqh 1 300 train
+eilfbdisof 1 300 test
+eilgzjgukh 1 298 train
+eilnuuihdg 1 300 val
+eilrokmzgb 1 301 val
+eilvfdkkia 0 300 train
+eilxyvmvvn 1 300 train
+eimfjqslgi 1 300 val
+eimjakthpp 0 300 train
+eimnrimtws 1 300 train
+eimtbmjnkn 1 99 train
+eimxfiaoof 1 300 val
+eimytuzirn 1 300 val
+einaekqeof 1 300 train
+einayzeaml 1 300 train
+eindiyyyec 1 300 train
+einkcqgdlf 0 300 train
+einrfjcmve 1 300 train
+einuilwwyq 1 300 train
+einzffdldz 1 300 train
+einzjxuova 1 300 train
+einzzdyxps 1 300 val
+eiofpijvxq 0 300 val
+eiohhevint 1 300 val
+eiojlambcg 1 300 train
+eiozvdohir 1 300 train
+eipgrasgik 1 300 train
+eipiymqgqw 1 301 train
+eiplaepcgp 0 300 val
+eipleqsbuv 1 300 train
+eiptnbybdk 1 300 val
+eipwxqahgp 0 298 train
+eipyxvfhkf 1 301 train
+eipzvbpuuu 1 300 train
+eiqffyyzic 1 300 val
+eiqghdwqgv 1 301 val
+eiqgvbnuab 1 297 train
+eiqjqnjdpj 1 300 val
+eiqkjgmjzj 1 240 val
+eiqkzdpmun 1 300 train
+eiqmgdkhcf 1 300 val
+eiquzbvykr 0 300 val
+eirdcphzpl 1 301 train
+eirfrbcken 0 300 train
+eirhvynauf 1 300 train
+eiriyukqqy 1 300 train
+eirliiyuik 1 300 train
+eirljobptb 1 301 train
+eirndiltfu 1 300 train
+eirqkmkeaz 0 300 train
+eirrhmppfo 0 300 train
+eirsybiywa 0 300 train
+eirwennutv 0 299 train
+eisblogzaf 1 297 train
+eisfawsyep 0 300 val
+eisgeotlay 1 300 train
+eishoprydk 1 300 train
+eisofhptvk 1 300 test
+eisovtqbfw 0 300 train
+eissivrblt 1 297 train
+eissylsysf 1 300 train
+eistnigkih 1 300 train
+eiswjtfxrj 1 300 train
+eitcwqmdmn 1 300 train
+eitdwgzbtn 0 300 train
+eitfpxnzwo 0 300 train
+eitgoswemc 0 300 train
+eitjlgatsq 1 300 val
+eitozbsduc 1 249 train
+eitsfyraad 1 300 train
+eittgdpvxg 1 301 val
+eitvkszvas 1 300 train
+eitzzrryrp 1 300 train
+eiuciedrvr 1 299 val
+eiujlbxnup 1 300 train
+eiumscwqwk 1 300 train
+eiuqpbsxvv 1 300 train
+eivccpdecn 1 300 train
+eivcumeuxu 1 300 train
+eivjdwffiz 1 300 train
+eivjfbudaj 1 300 train
+eivndiizwr 0 300 train
+eivtckqcmk 1 300 train
+eivxffliio 1 300 train
+eiwamqjboa 1 300 val
+eiweqgwnuk 1 296 train
+eiwmeoupft 1 300 val
+eiwopxzjfn 1 300 train
+eiwtggvtfp 0 300 test
+eiwtwfrnuv 1 300 train
+eiwwftakrx 0 300 train
+eixapfhlww 1 302 val
+eixgvemqnk 1 300 train
+eixhwihtgm 1 300 val
+eixmixznml 1 300 train
+eixntxxxcl 1 301 train
+eixseyxxxg 1 300 val
+eixvbkmqcd 1 298 train
+eixwxvxbbn 1 300 train
+eixzzhrgrd 1 300 train
+eiybtckzyc 0 300 train
+eiyesuqlwu 1 300 train
+eiygtsqxco 0 300 train
+eiyhctwtne 1 300 val
+eiyjrjgvih 0 300 train
+eiymcxgfjq 1 300 train
+eiymzaejwi 1 300 val
+eiyozfeewp 1 301 train
+eiyqnbwwha 1 298 train
+eizaajwktd 1 300 train
+eizdnwhclo 1 300 train
+eizeoqgggt 0 300 train
+eizepspxbh 1 300 val
+eizlariprr 1 300 val
+eizltoybnh 1 300 val
+eiztbwmaoj 1 300 train
+ejaerplihp 1 300 train
+ejagjdpovw 1 300 test
+ejakkbxnjp 1 300 train
+ejarlcecxs 1 300 train
+ejavbqmxlf 0 300 val
+ejawborsyb 1 300 train
+ejaydbdptx 1 300 train
+ejazmqwgdz 1 300 train
+ejazprqjzr 0 300 train
+ejbiggdtke 1 300 train
+ejbksktrpr 1 300 train
+ejbqyeonlo 1 298 train
+ejcglpcihz 1 300 train
+ejcmwdstej 0 301 train
+ejcqfsdlmu 1 300 val
+ejcrgctrqn 1 300 train
+ejcsfyytxh 1 300 train
+ejcuzwsyqa 1 301 train
+ejcwolfsvd 1 299 train
+ejcythhjap 1 300 train
+ejdavxgdsf 0 300 val
+ejdoadetmz 1 298 val
+ejdscdudfg 1 300 train
+ejdshfsqoh 1 601 train
+ejdsoxslkh 0 300 train
+ejduevqyce 0 300 train
+ejdzmllxak 1 300 train
+ejeccsomxe 1 298 train
+ejelabznep 1 300 train
+ejelxgmstc 1 300 val
+ejemhaucbz 1 300 val
+ejeonfogfi 1 300 train
+ejeucyrpbn 1 300 train
+ejevdfyyzw 1 300 train
+ejevqgvhgh 1 300 train
+ejevzyhdgc 0 300 train
+ejewrmwvbs 1 300 train
+ejexhshvos 1 240 train
+ejfepmcjkw 0 300 val
+ejfeuavmib 1 241 train
+ejfgtkqojm 1 300 train
+ejfpanyjai 0 300 train
+ejfpkbojld 1 300 train
+ejfqzyxrqc 1 300 train
+ejgnnocwwf 1 300 train
+ejgukcmwdk 1 300 train
+ejgwxdlttz 1 300 train
+ejhdsgpokp 1 300 train
+ejhhdlzpjg 1 300 test
+ejhhokmvpe 0 300 test
+ejhhriogdr 1 300 train
+ejhuwtbcxs 0 300 train
+ejhwqbpqyc 0 300 train
+ejhwtgzisd 1 300 train
+ejhxgasndv 0 300 train
+ejhxybcqdm 1 300 val
+ejiegvzplj 1 300 train
+ejigyjwxjg 1 300 train
+ejihadjcos 1 300 train
+ejihiqyvtf 0 300 train
+ejihsojcdj 1 300 val
+ejiiajyjbg 1 300 train
+ejiiapzrwx 1 300 val
+ejijwbwnkv 1 300 train
+ejilmxtdpq 1 239 val
+ejimmefewo 1 301 train
+ejivdcrlnv 1 300 train
+ejjaujkfzd 1 300 train
+ejjqgpvjme 0 301 train
+ejjsygqfvx 1 300 val
+ejkculpisl 0 301 train
+ejkfisntul 1 300 train
+ejkhlexowa 1 300 val
+ejkiprtgkr 0 300 val
+ejkjohjxag 0 300 train
+ejkjrdkwci 1 300 train
+ejklzppjqd 1 300 train
+ejkmfyvlwa 1 300 train
+ejkqesyvam 1 300 train
+ejldxbgeiz 1 300 train
+ejlfhduotr 1 299 val
+ejlgkshnrx 0 300 train
+ejlhdbfxoh 1 300 train
+ejllqmhnyt 0 300 train
+ejmicbsvfd 1 300 train
+ejmigxjzbe 1 241 train
+ejmmjzxuon 1 300 train
+ejmpycnatt 0 300 train
+ejmydgmrdg 1 300 train
+ejncblwuej 1 300 train
+ejndsbhroo 1 301 train
+ejngbwdvhz 1 300 val
+ejnleiwyex 0 298 val
+ejnnsfbten 1 300 train
+ejnpiehuuk 1 302 train
+ejnqmijsao 1 300 train
+ejnqyivbip 1 300 train
+ejnrxekehh 0 300 train
+ejnweymqnb 1 301 val
+ejnyidceim 1 300 train
+ejobauwpjq 1 300 train
+ejobyyzner 1 300 train
+ejonxeysvw 1 300 train
+ejowjjdmpx 1 301 val
+ejpftkbwln 1 300 train
+ejppyfltkv 1 300 train
+ejpqtzhujv 1 300 train
+ejpywzaser 1 298 train
+ejqjernodu 0 300 train
+ejqkcermdx 1 300 train
+ejqpntdilx 1 300 train
+ejqrxvtucr 1 301 train
+ejqwhsghph 1 298 train
+ejqxbwyzzz 1 300 train
+ejrbdkjhhn 1 300 val
+ejrifbklfi 1 300 train
+ejrmxbztrm 1 300 val
+ejrxgrkuup 1 300 train
+ejrywhucyy 1 300 train
+ejscvurdzw 1 300 train
+ejsdvcnvlu 1 300 val
+ejsjrolrac 0 241 train
+ejsnehnaqo 1 300 val
+ejsnniudtz 1 300 train
+ejspskddqq 1 300 train
+ejtimuprkr 0 300 train
+ejtnfisxja 1 298 train
+ejtoceqagd 1 300 train
+ejtondldnk 1 300 train
+ejtsclbupv 1 300 train
+ejufyjjskz 1 298 train
+ejughyndqp 1 300 train
+ejutmzspws 0 300 train
+ejutmzzjbr 1 300 val
+ejuvtxqvos 1 241 train
+ejuxvtyizf 0 300 val
+ejuzcomijk 1 300 train
+ejvcakuclp 0 301 train
+ejvekgctfu 1 300 val
+ejvhpsisii 1 300 train
+ejvpuctmyr 1 300 train
+ejvqokvvkb 1 300 train
+ejvqorwbol 1 299 val
+ejvqsahfcz 1 300 train
+ejvrhxvkdr 1 300 train
+ejvutjytwt 1 300 train
+ejvxsbmohv 1 300 train
+ejvzniiwbq 0 300 train
+ejwakfgtqd 1 300 val
+ejwbqtyosm 1 300 val
+ejwezefhoh 1 300 train
+ejwkklumeg 0 300 train
+ejwoswykff 1 300 val
+ejwuepnoaq 1 300 train
+ejwvqbeyef 1 300 val
+ejwwivhszc 1 300 train
+ejwxolkwsr 0 300 train
+ejxftftwgd 1 300 val
+ejxniublbo 1 300 train
+ejxnykesiu 1 298 train
+ejxrhjfhak 1 300 train
+ejxtahzrdt 1 298 train
+ejxuhqvdjf 1 301 train
+ejybewlkze 1 300 train
+ejybueyurf 1 301 train
+ejyhzcuytn 1 300 train
+ejykbxakod 1 298 train
+ejykvtkwpt 1 300 val
+ejymqfawpz 1 300 val
+ejynkzrazc 1 300 val
+ejyoybicax 1 300 train
+ejyripvmvw 1 300 train
+ejyrrekbxm 1 300 train
+ejzfffaalw 1 300 train
+ejzkecngzf 1 300 train
+ejzkucglgm 1 300 val
+ejzlvkqmre 1 302 train
+ejzrvimtcm 0 301 train
+ejzsbwphhx 0 300 train
+ekadmectsi 1 299 val
+ekakbndktf 1 300 train
+ekakeosslm 1 300 train
+ekalngzvwx 1 300 test
+ekalorldiz 1 302 train
+ekawrabqie 1 300 train
+ekbcrbtmmc 0 300 train
+ekbeqygtrq 0 301 train
+ekbfkfxzlf 1 300 val
+ekbhrdvecs 1 300 val
+ekbittwxlq 1 300 train
+ekblnquxhq 0 301 train
+ekbntmuqhj 0 300 train
+ekbnytgwbc 1 300 train
+ekboxwrwuv 1 300 test
+ekbqwgwevm 1 300 train
+ekbtkvtfsf 1 301 val
+ekbylzhjgp 0 300 train
+ekbywoogqt 0 300 train
+ekcgrysqam 1 300 val
+ekcrtigpab 0 300 train
+ekcztejffy 0 300 train
+ekdepvhwxk 1 300 val
+ekdgndagyc 1 300 val
+ekdwhbdeoz 1 300 train
+ekdytdjsax 1 300 train
+ekebuxrige 1 300 val
+ekectxegkf 1 300 train
+ekedvskayy 1 299 test
+ekelfsnqof 0 299 test
+ekelpjsrmk 1 300 train
+ekensuxkkt 1 300 train
+ekexblgylm 0 300 train
+ekfgmkfmyc 1 300 train
+ekfhchiqqi 1 298 train
+ekfhckgwbe 1 300 train
+ekfhzmnshw 1 300 val
+ekfiewirjs 1 299 test
+ekfjpswjug 1 300 train
+ekfknmwrev 1 300 train
+ekfxpqjhnh 0 300 train
+ekfyyfaqvs 1 299 train
+ekgccotacg 1 300 train
+ekgjfxtdhb 1 300 train
+ekgojnyvby 1 300 train
+ekgsevvfvl 1 298 train
+ekhacizpah 1 300 train
+ekhdkjhtbp 1 300 train
+ekhdunpxzs 1 300 val
+ekhdzmeygp 1 300 train
+ekhjgthkoc 1 300 train
+ekhmchjymb 1 300 val
+ekhoumwula 1 299 val
+ekhqsatjuo 1 300 train
+ekhuvtncnw 1 300 train
+ekhzwrppgy 1 300 val
+ekidiquivf 1 300 train
+ekihpvgnpk 1 300 test
+ekihtgdsmh 1 301 train
+ekihvvriqm 1 300 train
+ekiibefvfu 1 300 train
+ekinylkxkt 1 300 val
+ekipbfbtoo 0 300 train
+ekirfaopmj 1 240 train
+ekizgabilm 1 300 train
+ekjbtuucpz 1 300 train
+ekjdrsnykb 1 301 train
+ekjezbdyxw 1 300 train
+ekjgzumgtq 1 300 train
+ekjhvhjzzf 1 300 train
+ekjifbzrfr 1 300 train
+ekjlgkljvv 1 147 train
+ekkdjkirzq 1 300 train
+ekkgzrewrv 1 300 train
+ekkhbqmqey 0 300 train
+ekkheaisuo 1 300 test
+ekkileqfsd 1 301 train
+ekkksdqgzl 1 300 train
+ekkkuvrqso 1 300 train
+ekknjayiwh 1 301 train
+ekksyifkkq 1 300 val
+ekkufyfcon 0 300 train
+ekldiuludx 1 301 train
+eklgbwceyi 1 300 train
+ekllfrfgss 1 300 train
+ekllmudlwi 1 300 train
+eklmkbktzs 1 300 train
+eklmqoycqb 1 300 train
+ekloeswyfg 1 300 train
+eklrwpezsg 1 300 train
+eklsiuzyiy 1 300 train
+eklsrnkwog 0 300 val
+eklwtgksmx 0 300 train
+eklxfbjuzd 1 300 train
+ekmbotgxyr 0 300 train
+ekmdbjwyed 1 300 val
+ekmjbxovtj 0 298 train
+ekmmgdvdhe 1 300 val
+ekmpricrrr 1 300 val
+ekmtvguisa 1 300 train
+ekmwbuaedp 1 300 train
+eknbohtoom 1 300 val
+ekndpgswqg 1 300 train
+ekndxpycvw 1 300 train
+ekneyurwol 1 301 val
+eknkigbcqn 1 300 train
+eknonpmtkx 1 300 val
+eknoxdhyot 1 300 test
+ekobvgbiiu 1 300 train
+ekogldesoy 1 301 train
+ekolzsqdzj 0 301 train
+ekonqkcioi 0 300 val
+ekoyxvfxwi 1 300 train
+ekozfobxxw 1 300 train
+ekpaipmwuo 1 300 train
+ekppovddnl 1 300 train
+ekpsyicagq 1 300 train
+ekptveunoa 1 255 train
+ekqajwwwan 1 300 train
+ekqdsvtjhj 1 300 train
+ekqeeqfzeo 1 300 train
+ekqseqvcrg 1 302 train
+ekqtlhsclp 0 300 train
+ekquarsplg 1 300 train
+ekreepcbid 0 300 val
+ekrmmejjdg 1 300 train
+ekrooluwcl 1 300 train
+ekroqoupno 1 301 val
+ekrovnzbih 1 300 val
+ekrxefxule 1 300 train
+ekrxyzlqgm 0 300 train
+eksafeazce 1 301 train
+ekselgajdc 0 300 train
+eksknyjyne 1 300 val
+eksqjwuqwj 1 300 train
+ekstzhenwb 0 299 train
+eksuofducd 1 300 val
+eksxxvalyg 1 300 train
+ektblhodgo 1 300 train
+ektbqfsjoq 1 300 train
+ektcauseus 0 300 train
+ekteinubfk 1 300 train
+ektpcycwsa 1 300 train
+ektqvjydep 0 301 train
+ektqvnzoyv 1 300 train
+ektrtuwidv 1 300 train
+ekttckyxbq 1 300 val
+ektuojlbkf 1 300 train
+ektwmkryvm 1 300 train
+ektwvznjhj 1 300 train
+ektzudxnen 1 300 train
+ekuiikgthu 1 300 train
+ekujbtlave 1 298 train
+ekukrapvob 1 300 train
+ekunwvpbzd 1 301 train
+ekusbammok 0 300 train
+ekutbiitqk 0 300 train
+ekuuexugkg 1 300 train
+ekuxaoahyi 1 300 train
+ekuzikscyt 1 300 val
+ekvapshklb 1 302 val
+ekvhyeycpr 0 300 train
+ekvkuodrul 1 300 train
+ekvpxmpfkw 1 236 train
+ekvvevzkyu 0 300 train
+ekvwecwltj 0 300 test
+ekvwqojmnz 1 300 train
+ekwczkvszi 1 300 train
+ekwfirmggp 0 300 val
+ekwglpkqms 1 301 train
+ekwhsbcxdd 1 300 train
+ekwibgshxq 1 300 val
+ekwidzkjjg 0 300 train
+ekwjzeptsb 1 300 val
+ekwkobkttt 1 300 train
+ekwltvkkzl 0 300 train
+ekwrfvhvos 1 300 train
+ekwtnrwrjz 1 300 val
+ekxcxwkety 1 300 train
+ekxiidkjpq 1 300 train
+ekxjfqulyc 1 300 train
+ekxowxtdfj 1 300 train
+ekxsduhvwh 0 300 train
+ekxskbftxk 1 301 train
+ekxsotfdup 1 299 train
+ekxxlzflnb 1 300 train
+ekydnznbkd 1 300 train
+ekylgudynp 0 301 val
+ekyqfnbgrm 1 300 train
+ekyufhvdif 1 300 train
+ekyycsaoqv 0 300 train
+ekyztqhbui 1 300 train
+ekzceykbjr 1 300 val
+ekzfjqzrnp 1 302 train
+ekzgrobucr 1 300 train
+ekziyatdew 1 300 train
+ekzlovqjbv 1 300 val
+ekzltdwpjj 1 300 test
+ekzlzfmhoo 0 300 val
+ekzojdwvzr 1 300 train
+ekzqkbdypn 1 300 train
+ekzrprxyby 1 300 train
+ekzsevwpij 1 300 train
+ekzuhbtnqf 1 136 train
+ekzwasnkky 1 300 val
+ekzykyotlh 1 300 train
+elackxuccp 0 300 test
+elaioyfyph 1 300 train
+elanrpoupa 1 300 train
+elansccbki 1 300 train
+elasnzhboy 1 300 train
+elaxwnjzsf 1 300 train
+elbcgmkdrw 0 300 train
+elbcslsoee 1 300 train
+elbelnfogt 1 300 train
+elbmamfwvw 1 299 train
+elbmrziana 1 300 train
+elboymgolh 1 300 train
+elbphjqewz 1 298 train
+elbqkcpape 1 300 train
+elbxfchnpt 1 300 train
+elcnndreoc 1 300 train
+elcolhrlnp 1 300 train
+elcvqegksy 0 300 train
+eldfrkuxtd 1 300 train
+eldmdaljmu 1 300 train
+eldndygyuj 1 300 train
+eldrdewglb 0 300 train
+eldukoggsh 1 301 train
+eldwicktbn 1 302 train
+eldzyxvqan 1 300 val
+eleccezzfk 1 300 train
+elecnxwagy 1 300 train
+elecwywqiy 1 300 val
+elefkzmxey 0 300 train
+elepzolpfv 1 300 train
+elernullyn 1 300 train
+elevnwxenh 1 300 train
+eleyeeybqi 0 300 train
+elfbhthwde 1 300 train
+elffrhwrxr 1 300 train
+elfhorlmgg 1 300 train
+elflocpvcv 1 241 train
+elflojhycc 1 300 train
+elforujjyi 1 300 train
+elfqgfzyid 1 300 train
+elginszwtk 1 300 train
+elgkqyaeis 1 300 train
+elgmuqvusu 1 300 val
+elgsweyjfb 1 300 test
+elgxyyjrja 1 300 val
+elhcggavzf 1 300 train
+elhfrjljib 1 301 train
+elhiudovby 1 300 train
+elhkbzgjoj 1 300 train
+eliazncrwl 0 300 train
+elibzwmjie 0 300 train
+elikgbssgh 1 300 val
+elimogcqmt 1 300 train
+elinrhmuzg 1 300 train
+elipbhkriy 1 301 train
+elisexkmmz 1 300 train
+eliskmcgkh 1 298 train
+eliusgdvno 1 300 train
+eliwtrcdsc 1 300 train
+eljbbqzpcz 0 296 train
+eljmbnbcgo 1 300 train
+eljtgmcpfw 1 300 train
+eljuwtunzi 1 298 train
+eljvhsixvx 0 300 train
+eljyfxrymd 0 298 train
+eljyokhuyz 1 300 train
+eljzpanwfo 1 300 train
+elkbjpwigu 1 300 train
+elkbpremoh 1 300 train
+elkbquerfn 1 241 train
+elkewgkesd 1 241 train
+elktntxczt 1 298 train
+elkvwoacwh 1 300 train
+ellavthztb 0 300 train
+ellerbzgmz 1 300 val
+ellfaiwiyl 1 298 train
+ellibnfrxj 1 300 train
+elljrxzeau 1 300 train
+ellrwhvtbt 1 300 train
+ellvxntech 1 300 train
+ellywooqeg 1 300 train
+elmtszrkyg 1 300 train
+elnadljsko 1 300 train
+elnhyybyxd 1 300 train
+elnmbaafbs 0 298 val
+elnqrfpkqf 1 300 train
+elnqrnvdfg 1 300 val
+elocxgidli 1 300 val
+eloczbirrl 1 300 val
+elojiwzswt 1 300 train
+elojrxvohh 1 300 train
+elokkmrzrt 1 300 train
+elondavtxd 1 300 train
+eloruxrfxu 1 297 train
+elovfrblwp 1 300 train
+elpbwhuahb 1 300 train
+elpffqstqw 1 300 train
+elpfwuypbp 1 300 train
+elpfxfpmsl 1 300 train
+elpoqmgtcc 1 300 train
+elpptcyabc 1 300 train
+elpxrseijw 1 300 test
+elqbcociee 1 300 val
+elqbvncdpe 1 300 train
+elqiuckdls 1 300 train
+elqkrqiruk 1 301 train
+elqndspvrh 1 300 val
+elquyujked 1 300 train
+elqwccskbx 1 300 val
+elqwqccmot 1 300 train
+elrascpukp 1 300 train
+elrkacifos 1 300 train
+elrmpzdppn 1 300 val
+elroocuuei 1 300 train
+elrqhmztpc 1 301 train
+elrrryqpkv 1 300 train
+elscuighwc 1 300 train
+elshlokneb 1 300 train
+elsmkmfkuk 1 300 val
+elsmxhryaf 1 300 train
+elsniaacef 1 300 train
+elsomsyjct 0 300 train
+elstdtdqvy 0 300 train
+elstidjkkr 1 298 train
+elstrzeazv 1 300 val
+elsvnmrlue 0 300 train
+elswiqsyby 1 300 val
+elsxqxzbtk 0 300 train
+elszzxitgv 1 300 train
+eltdfmwgji 1 300 train
+eltegvmovm 1 300 train
+eltffanmrz 0 298 train
+eltjhrlbnu 0 299 train
+eltklzymmv 1 301 train
+eltotlxqoq 0 300 val
+eltuxrwcgh 1 301 val
+elubhywzzv 1 300 train
+eluhuvocwr 1 300 train
+eluisbadpw 1 300 val
+elujuuvdib 1 301 train
+eluwjoxfav 1 300 train
+elvdfqptjk 1 300 val
+elvduffofs 0 300 val
+elvjwbwpfj 1 300 train
+elvorjwdut 1 300 train
+elvvackpjh 1 300 train
+elvvtvpllm 1 301 train
+elvwyqspgu 1 301 train
+elvyeqpinx 1 300 train
+elwbzzkzse 1 300 train
+elwdoyaytg 1 300 train
+elwdztqnot 1 300 train
+elwkarapml 1 300 val
+elwodtjxbz 1 300 train
+elwsmanmkc 1 300 val
+elxbkhrbis 1 241 train
+elxelcwfkc 0 241 train
+elxflqcpgp 1 300 val
+elxfyfhwix 1 300 train
+elxhrfxiqr 0 300 train
+elxiilxvjw 1 300 train
+elxjzumvfd 1 300 train
+elxlnjzmzi 0 300 train
+elxpmshmuh 1 300 train
+elxpszfnvu 1 300 val
+elxtsedbxu 1 300 train
+elxvgshykr 1 300 train
+elxxsfuyhl 1 300 train
+elycqdvvxf 1 300 train
+elydzuduof 1 300 train
+elynykyrab 1 300 train
+elyogghqnr 0 300 train
+elyosecnfp 1 301 train
+elyoskeeju 1 300 val
+elyuapcyhc 1 300 train
+elyvkuldpz 1 300 test
+elyxhiymjl 1 300 train
+elyyepyjrz 0 300 train
+elzagvsdjt 1 300 train
+elzkhvqobv 1 300 train
+elzknnwtud 1 300 val
+elztneithk 1 300 train
+elztrnjyjz 1 300 train
+elzyaxzkbw 0 300 train
+emaahepmij 0 300 train
+emaalmsonj 1 300 train
+emajfshvdl 1 300 train
+emajtqhmwe 1 301 train
+emamioiuac 1 300 val
+emarvplekl 1 301 train
+emazlhouiw 1 300 val
+embcmvxhau 1 298 train
+embhtiswqh 1 300 train
+embjjaybmt 1 302 train
+embmaestpq 1 300 test
+embmyescyc 1 300 val
+embmzonwof 1 299 train
+embsmlaezn 1 300 train
+embuivkmpn 1 300 train
+embutxzbzh 1 300 train
+embxvesuyh 1 298 train
+emcgulgjos 1 300 val
+emcmmemork 1 301 val
+emcwrkuqag 1 300 train
+emcyktgdhq 1 300 train
+emczecnjxm 1 300 val
+emdjnitovk 1 300 train
+emdoggnrga 1 300 val
+emdtsuztrq 1 300 train
+emduoxrhib 1 300 train
+emecmfeykx 1 300 val
+emedkscdtu 1 300 val
+emekhemxvg 1 300 train
+ememzafmmx 1 300 train
+emetppzwqp 0 300 train
+emexwanqpg 1 300 train
+emfbhytfhc 1 300 train
+emffqrjhyk 0 300 train
+emfhcuoqdw 1 300 train
+emfkryqdmk 1 300 test
+emflfadjyb 0 300 val
+emflshuwqj 1 300 train
+emfpiridro 1 300 train
+emfzmpxvfa 1 300 train
+emgchlmhmd 1 300 train
+emgciwmtuj 0 300 train
+emgdjqirov 1 300 train
+emgdobptvi 1 300 train
+emgjphonqb 1 300 train
+emgknogezh 1 300 train
+emgktyjjur 1 300 train
+emgwaijgbx 1 300 train
+emgwzmokvm 1 300 train
+emheyikbvt 1 300 val
+emhfdagxes 1 300 train
+emhhmttage 1 300 train
+emhiqhssxk 1 298 train
+emhqqohdiw 1 300 train
+emhviuiexz 1 300 train
+emhwtvqqpx 1 300 train
+emicavxonz 1 300 train
+emimxqipug 1 300 train
+eminffolcr 1 297 train
+emiowrbnqn 1 301 train
+emipsxscir 0 300 train
+emivuuvmnv 1 300 train
+emiyuzydgw 0 300 train
+emjblzziyi 1 300 val
+emjbwiruky 1 300 train
+emjfwbvhrz 1 300 val
+emjhfbddtx 1 300 train
+emjklvrxqt 1 300 train
+emjobuscyu 1 300 train
+emjrvrkdsj 1 300 val
+emjtexvqxo 1 300 train
+emjurnjsns 1 300 train
+emjuzmdnmm 1 300 train
+emjvnrdior 1 300 val
+emkchkayfs 1 300 train
+emkgcytwii 1 298 train
+emkzigwhnz 1 300 train
+emlbkquaok 0 300 train
+emlgazbzmp 0 300 train
+emltgvwzjp 1 298 val
+emluajmkqr 1 300 train
+emlvtyvrgf 1 300 train
+emlxggiohl 1 300 train
+emlxorhbwc 1 300 train
+emmddtvyal 1 300 train
+emmeyjrckj 1 300 train
+emmhvthugd 1 300 train
+emmigqfpia 1 300 train
+emmompdpbp 1 300 train
+emmpcdiywg 1 300 val
+emmygleyft 0 300 train
+emmzfsmqfb 1 300 val
+emmzuggyoe 1 301 val
+emnckphvgs 1 300 train
+emndbgwowk 1 301 train
+emnjzyegcc 1 300 val
+emnmnrdrik 1 241 train
+emnsqtwrxf 1 300 train
+emnttneegx 1 300 val
+emnxjfdqyg 1 300 train
+emocjwfcqr 1 601 train
+emognsfjum 1 300 val
+emopnhdcuv 1 300 train
+emouqgcvda 1 300 train
+emovqdktou 1 298 train
+emoytolqau 1 300 train
+empibqxyvt 1 302 val
+empmmkmgxy 1 300 train
+empqsoulhv 1 300 val
+emptxvueom 1 300 train
+empyeoanvv 1 300 train
+empzrudgsg 1 300 train
+emqbqqhubc 1 300 train
+emqeprwwpi 1 299 test
+emqidgfxdh 1 300 train
+emqiwrsihy 0 300 train
+emqrzuchea 1 300 train
+emquxxfffy 0 300 train
+emqwvillhl 1 301 train
+emrcntxdgx 1 300 train
+emrdfyhgoo 1 300 train
+emrerqftel 1 300 train
+emrhtomwpy 0 301 train
+emrkenkhja 1 301 train
+emrmblrrtm 1 300 val
+emrrusjpbr 1 300 train
+emrsqvjawa 0 300 train
+emruzzbtpp 1 300 train
+emsfwzohii 1 241 train
+emsnbjdsve 1 300 val
+emstbyvehc 1 300 train
+emthoarbdj 0 300 train
+emtqhgpbkk 1 300 train
+emtyalvhip 0 301 train
+emudayhivl 0 300 val
+emudwmtiku 1 300 val
+emuhunitbj 1 300 train
+emunkvnrqv 1 296 train
+emusyxkytu 0 295 train
+emuyfonjla 1 300 train
+emuzlotcnx 1 300 val
+emvefvjhxs 1 300 train
+emvercnruk 1 300 val
+emvfaleomu 1 300 train
+emvikmmndn 1 300 train
+emvkqakzft 1 300 train
+emvnbthflm 1 300 train
+emvqyocmkt 1 298 train
+emvryijqlx 1 300 train
+emvyjelukj 1 300 train
+emwbovxems 1 299 test
+emwftcfjxv 1 300 train
+emwwxngstk 1 300 val
+emwyadgcpz 1 240 train
+emxknhlufj 1 300 val
+emxqsgqtdz 0 300 val
+emydsxueew 1 296 train
+emyeynycew 1 300 train
+emyieqewtf 1 300 train
+emyujgrtam 1 300 val
+emyuupedpf 1 300 train
+emyxhllxsy 1 300 train
+emzbasnefg 1 300 train
+emzhjvmihq 1 300 train
+emzpwwqnbu 1 300 val
+emzvhjgvil 1 300 train
+emzwwlvpvh 1 300 train
+emzwyzrsvj 1 300 train
+emzxydfgar 1 300 train
+emzyxfqrfl 1 300 train
+enabebfifv 1 300 train
+enaloxrkbq 1 300 train
+enaupjigsj 1 300 train
+enavmziqtm 1 296 val
+enaxhazpcf 1 300 train
+enaxrhpjpb 1 300 train
+enbfepbwau 1 300 train
+enbftbywkk 1 298 train
+enbseyltvw 1 300 train
+enbwseqhsd 0 300 train
+enclclienu 1 300 train
+encmazdvub 1 300 train
+encpspxssi 0 300 train
+encvnokybd 0 300 train
+encyyfekai 1 300 train
+endblutfop 0 300 train
+endiuktcod 1 298 val
+endltzlqpl 1 241 train
+endpgnuvfs 1 300 train
+endsusndeu 0 300 train
+endtzsxgao 1 300 train
+endyepvcxe 1 299 test
+enegjdbjre 1 300 train
+eneknlfodw 1 300 train
+eneofiltbk 1 300 test
+enerzluejw 1 300 test
+enexnymsbr 1 300 train
+enextjoooy 1 300 train
+enfcptkktm 1 300 val
+enfdiglvvt 1 300 train
+enfmynwlvz 1 300 train
+enftrdvduu 1 300 train
+engekpwzjb 1 300 train
+engiedokre 1 300 train
+engkpbwcgq 1 298 val
+engpmuueot 1 301 train
+engqomxtpa 1 300 val
+engrfolawd 1 301 train
+engrtptveb 1 300 val
+engsdrpgyb 1 301 val
+engsjjoxfe 0 300 train
+engswoxwys 1 300 train
+engwynjyqs 1 300 train
+engymfxqme 1 300 val
+enhckzdzis 1 300 train
+enhioxigpa 1 300 train
+enhiqdvfpu 1 300 test
+enhlolcwtf 1 300 train
+enhmogbtli 1 300 train
+enhnmsqyqj 1 300 train
+enhqfydjvr 1 300 val
+enhrmlgvnt 1 300 val
+enhxubddhk 1 300 train
+enhydgxlso 1 300 val
+enibjhsgje 1 255 train
+eniecqyisj 1 300 train
+enipqkwzqx 1 300 val
+eniqwmdvvn 1 300 val
+eniwlqcrrd 1 300 train
+eniwursspz 1 300 val
+enizxofene 1 300 train
+enjaxrsqfw 0 241 train
+enjcgntrbu 1 301 train
+enjdgcalpl 1 300 train
+enjggxpoii 1 300 val
+enjjddkvps 1 300 train
+enjlezwnxf 1 300 train
+enjoifswtz 1 298 train
+enjpvpmbpb 1 298 train
+enjtywvrzf 1 300 train
+enjuhqktov 1 300 train
+enjxtyoedl 1 300 val
+enjzkucxsd 0 300 train
+enkdvexnxi 1 300 val
+enkpwtwwnf 0 300 train
+enkpxzkvni 1 300 train
+enkselqiwh 0 300 train
+enktszvgww 1 300 train
+enlbqlghpj 1 301 train
+enlcwhijah 1 300 train
+enljrpodub 1 299 test
+enllemybiz 0 300 train
+enlolpbgqi 1 300 train
+enlyxqyizx 1 300 train
+enmdaytcuc 1 300 train
+enmghvssjk 1 300 train
+enmgplmpni 1 300 train
+enmhynnovp 1 298 train
+enmowffmak 1 300 train
+enmqxixglr 1 300 train
+enmwbulzea 1 300 train
+enmxdwpxmd 1 300 val
+ennbagdwpz 1 300 train
+ennbmnoygj 0 300 train
+enneoqmjbk 0 300 train
+ennggwgewg 1 300 train
+ennkjirvtk 1 300 train
+ennsaswngw 1 300 train
+ennyxnvovn 1 300 train
+enoamrhpzo 1 297 train
+enoeecjnwh 0 300 train
+enoouxpgmj 1 300 train
+enovdmrsnb 1 300 val
+enpbjzqfyf 1 300 train
+enpdzuwrqu 1 300 train
+enphibvjne 1 300 train
+enpjmahsgj 1 300 train
+enpnclhmik 1 299 test
+enpqwqmztj 1 300 train
+enpryzieyc 0 300 train
+enpshnkugu 1 300 train
+enqgituzjh 1 300 train
+enqkphrtpi 1 300 train
+enqojjephh 1 300 train
+enqpiztubw 1 300 val
+enqrycfnua 1 300 train
+enqxmaplyw 1 300 train
+enqxsifggs 1 300 test
+enrayuqalt 1 300 val
+enrdidiwpy 1 298 val
+enrmqqoawf 1 298 train
+enrrlpgbeg 1 299 test
+enrsnustsu 1 300 train
+ensjhocuzm 1 300 val
+ensqjokdse 0 300 train
+ensqprppfp 1 300 train
+ensyyivobf 1 300 train
+entdaiqrgf 1 300 val
+entdyegoud 0 241 train
+enteeozxvw 1 300 val
+entpculrml 1 301 train
+enujhgtndo 1 301 train
+enuvbqyode 1 300 train
+envfwgonkw 1 300 train
+envgqunrmz 1 302 train
+envlovlvqo 1 300 train
+envlpcyqsu 1 300 train
+envmivjahd 1 300 train
+envzcooavo 1 302 train
+enwcnhoqfe 1 301 val
+enwdngjood 1 300 train
+enwhstvrpt 1 300 train
+enwkimmigr 1 300 train
+enwmbzjdiz 1 300 train
+enwsrtwsnm 1 300 train
+enxazpptrf 1 300 train
+enxciuqvdw 1 300 train
+enxjtwmtrl 1 300 train
+enxmvehfvn 1 300 train
+enxqnminak 1 300 train
+enxrusfqzc 1 300 test
+enxutgkcds 1 241 train
+enxxwptxzh 1 300 train
+enxymmghot 1 296 val
+enybsjbxeu 1 300 train
+enyfsmfgvb 1 300 train
+enyfzkpdeq 0 300 train
+enyhaxfqre 1 300 train
+enyhgljqwr 1 83 train
+enyufxmbdi 1 249 train
+enywrmpiib 1 300 train
+enyytoyguq 1 300 train
+enzhejuswm 1 300 train
+enzilllhyd 1 300 train
+enzkklzjau 0 300 val
+enzlliylet 1 300 val
+enzngcerxy 1 300 train
+enznkxtllv 1 300 train
+enzsbbnwyz 1 300 train
+eoajaazlzj 1 300 train
+eoajyopeaw 1 300 train
+eoavcmopsy 1 300 test
+eoaviddrkc 1 300 train
+eobectkniq 0 300 train
+eobgizjnst 1 300 val
+eobjdumcjj 0 300 train
+eobjzcvdjc 1 300 train
+eobqmockmb 1 300 train
+eobruprfir 1 300 train
+eobtpresst 1 299 test
+eobtqxsraj 1 300 train
+eobukbnqjy 1 300 train
+eobwpnjgld 1 300 train
+eobyorukwr 1 300 train
+eobzcbhoca 1 300 val
+eoclcdruis 1 300 train
+eocqzwmtxp 0 300 train
+eoczrgfnfc 1 240 train
+eoczvkvxer 1 300 train
+eodcnfydil 0 300 train
+eodeiyybfk 1 300 train
+eodnvnckpb 0 300 train
+eodrioissz 1 300 train
+eoecyagmwn 1 300 train
+eoeoxehgqf 0 300 train
+eoeqlzcawa 1 240 val
+eoetruoced 1 300 train
+eoeuffsrbp 1 300 val
+eoewqcpbgt 1 300 train
+eoextlfkjh 1 300 train
+eofajrswbe 1 300 train
+eofbparhow 1 300 val
+eofloyspbg 0 300 train
+eofmndfjhx 1 300 train
+eofrafoaox 1 300 train
+eofwbtrsrw 0 300 val
+eogoxcbumn 1 300 train
+eogtafeebh 1 300 train
+eogtykbjzo 1 288 train
+eohfpmdetv 1 300 val
+eohifcejnd 1 300 train
+eohtohplmt 1 300 train
+eohuccjlgv 1 300 train
+eohwdmwtvb 1 300 train
+eoighdabxr 0 300 train
+eoihdczbsu 1 302 train
+eoihgbylxs 1 300 val
+eoiivyirku 1 299 val
+eoijiohjqy 1 300 train
+eoiphherjq 1 300 train
+eoirehvyxx 1 298 train
+eojbgopmdq 1 301 train
+eojdxfwvpl 0 300 val
+eojiijwanp 1 300 train
+eojlafatzp 1 301 train
+eojnrocwyu 1 300 train
+eojslldtza 1 299 test
+eojtfnpgbb 0 298 train
+eojzwgqhez 1 300 train
+eokcarfull 1 300 val
+eokjvotqys 1 300 val
+eokkrwmqai 1 300 val
+eokrjqnxwx 1 300 train
+eokzbwqpqm 1 300 train
+eolawwagii 0 300 val
+eolhmkhbzw 1 300 val
+eoljscsixt 1 300 train
+eolkgahjpc 0 300 train
+eolnkehgza 1 300 val
+eomckefhqz 1 300 train
+eomjtauudo 1 300 train
+eomkkrghqx 1 301 train
+eomqauazvs 1 301 train
+eomsdkukdd 1 300 train
+eomsfwykap 0 300 train
+eomywmlzyj 1 300 train
+eomzovujcy 1 300 val
+eonaotadhk 1 300 val
+eoncbtiopu 1 300 train
+eongwsmtbz 1 255 train
+eonhxfxydd 1 300 val
+eonmbpgcvr 1 300 val
+eonmclkdvc 1 300 train
+eonrnkuznw 1 300 train
+eonxnugdvo 0 300 val
+eooelwcdjy 1 300 train
+eoohrrbolh 1 300 train
+eookpnqhvf 1 301 train
+eoolybdaxo 1 301 train
+eoooocwauk 1 300 val
+eoorgqcdxi 1 300 test
+eooubrhmjb 1 300 train
+eoourklmjk 0 300 train
+eoovtabijc 1 300 train
+eoovzxhxps 1 300 train
+eooxdrbbrk 1 300 train
+eoozrcwxbv 1 301 train
+eopbwmailq 1 300 train
+eopcdsfkzm 0 300 train
+eopcxgdhmb 1 302 train
+eopfkbpvyr 1 300 train
+eopiwusyzw 0 300 train
+eopsexsidw 1 301 val
+eopvllblxh 0 300 train
+eoqehommte 1 300 train
+eoqzlimaxf 1 300 train
+eorfnapwtw 1 300 train
+eorjkovqdc 1 300 train
+eorlkzlhod 0 300 train
+eornwqtqsm 1 300 train
+eorosxkrht 1 300 test
+eorpfyvlok 0 300 train
+eorvyulwtf 1 300 train
+eorzuoawzo 1 300 train
+eoshdeycui 1 300 train
+eoshntcipd 1 299 test
+eosotoxzsv 1 300 train
+eotfviincu 1 300 train
+eotmblattz 1 300 train
+eotmotbqmh 1 300 train
+eotmtjvvny 1 300 train
+eotomosxbv 1 300 train
+eotrjtjauj 1 300 val
+eoturwwthi 1 300 train
+eotxapyhnr 1 300 train
+eouapvsygi 1 300 train
+eoubcmiqyt 1 300 train
+eoudgdkclq 1 301 train
+eouepjhqci 1 300 train
+eougitcxzy 1 300 train
+eoumymmygd 1 300 train
+eovdolozvs 1 300 train
+eovhwbsopw 0 300 train
+eovnbckyyh 0 300 val
+eovtghjjfi 1 300 train
+eowcuvqbyg 1 300 train
+eoweizjbnu 1 300 train
+eowifjqhnb 1 300 train
+eowpsoipfd 1 300 train
+eowsoapzuj 1 300 test
+eowunvvtkl 1 300 train
+eowyildduz 0 300 val
+eowyyfwgsi 1 300 train
+eowzrmhxjf 1 300 train
+eowzujrqgy 1 300 train
+eoxcfhtroc 1 300 train
+eoxdgayiyo 1 300 train
+eoxepsqewm 1 300 train
+eoxfrltwte 0 300 train
+eoxfxdocyx 1 300 train
+eoxgoqyoow 1 300 val
+eoxmjrjlyz 1 300 train
+eoxriajitk 1 300 val
+eoybutteqg 1 298 train
+eoykglvxvm 1 300 train
+eoyncdyjdm 0 300 train
+eoynlharxe 1 300 train
+eoypxpiwjr 1 300 train
+eoyryysbhd 0 300 val
+eoyxiiglgt 1 301 train
+eoyzkmpjem 1 300 train
+eozcbgtdmo 1 300 train
+eozfnrgmbc 1 300 train
+eozgdcdfzo 1 300 train
+eozpgpsgpt 1 300 train
+eozqffxrla 1 300 train
+eozvttotyw 1 300 train
+eozvydjgaq 1 300 train
+epadwwdiqg 1 300 train
+epahnxebfa 1 301 val
+epaxyxcldg 1 298 train
+epazxfxhqq 1 300 train
+epbajxjgjd 1 300 val
+epbfjtqriw 1 301 val
+epbhocgjxi 1 300 train
+epbihgdktz 1 301 train
+epbkfxmcnq 1 300 train
+epbuconkxk 1 300 train
+epbybxkzae 1 300 train
+epchzigjfn 1 299 train
+epcifhnrnh 1 300 train
+epctsuhlgk 1 300 train
+epctzprswe 1 300 train
+epcusefpzr 1 300 test
+epczikxgho 1 300 train
+epdexoxaub 1 300 train
+epdncpntwx 0 300 train
+epdxozwhic 1 300 train
+epeegcxwcp 1 300 val
+epefspyufn 1 300 train
+epeiodtait 1 299 test
+epeobaazob 1 300 train
+epetovyqho 1 300 train
+epeusndmyd 1 300 train
+epeyujjlhn 1 300 test
+epezasvfty 1 300 val
+epezdgjeji 1 300 train
+epfeounjus 1 300 train
+epftvaqpsh 1 300 train
+epftyyvcqv 1 300 train
+epgfqrvwlr 0 301 train
+epgnqkhgsn 0 249 train
+epgokhdfyh 1 300 train
+epgpnifmwk 1 300 train
+epgwtbcrmp 1 241 train
+ephapgzlze 1 301 train
+ephapmedel 1 300 train
+ephaxkeopi 0 300 train
+ephfaqivvr 1 300 train
+ephnqagghe 1 300 val
+epiaqyayih 1 300 val
+epibqprxop 1 302 train
+epinsihsxf 0 300 val
+epivofunvc 1 300 val
+epivyawujt 1 298 train
+epixbdehvv 1 300 train
+epjborbgzq 0 300 train
+epjhqzeweb 1 300 val
+epjkmysvmn 1 300 val
+epjledfltd 1 300 train
+epjonxsmwh 1 296 train
+epjstuklzg 1 300 train
+epkgoovkxa 1 297 train
+epkmvescaj 1 300 train
+epktjbgnju 1 300 val
+eplfenxzio 1 300 val
+eplhtqodvf 1 300 train
+eplyjorrms 1 300 val
+epmbxnbhjk 0 301 val
+epmehiyhap 1 298 train
+epmhatobwp 0 300 train
+epmjvvfqnb 0 300 val
+epmkeaolkz 0 300 train
+epmqdmuemt 1 300 train
+epmvowtywz 1 300 val
+epmvxwjeda 1 300 train
+epmxgfxpsl 1 300 train
+epniwtmldw 1 302 train
+epnucnkogg 1 300 train
+epnwuvxzxw 1 300 train
+epnzmghgbt 1 301 train
+epoblnewbi 1 300 train
+epohielxsd 1 300 train
+epolenvfxl 1 300 train
+epphrlkqhp 0 300 val
+eppmwpntfi 1 300 test
+eppozcvlub 1 299 test
+epptpbihho 1 300 train
+eppwozgkpb 1 300 train
+eppyqpgewp 0 300 test
+eppywcdkcs 1 300 val
+epqaqvwesc 1 301 train
+epqjwfuruc 0 300 train
+epqksomnzt 0 301 val
+eprdgmcksq 1 300 train
+eprggxqgeb 1 300 val
+eprhdfsljo 1 300 train
+eprpywvwyw 0 300 train
+eprqxyniem 1 300 train
+eprulpdosy 1 302 train
+eprwxzoonh 0 300 train
+eprybmbpba 1 300 train
+epsguwpsbn 1 300 val
+epsjyqmuvw 1 300 val
+epsmfofeiu 1 300 val
+epsrffjokm 1 300 train
+epssdfmtjy 1 300 train
+epsyssvibg 1 300 val
+eptaiqegrr 1 300 train
+eptivcmfdt 1 300 train
+eptkaiqjyn 1 241 train
+epttxrbjrx 1 300 train
+eptuxzhzob 1 300 train
+eptxbexmra 0 300 val
+epuzqxggwu 1 300 train
+epvatldhpl 1 300 train
+epvemsjnie 1 301 train
+epvlnimmpd 1 298 val
+epvmisawli 1 300 train
+epvnrjtjsi 1 300 train
+epvtxqaadn 1 301 val
+epvxmalyxo 1 301 val
+epvxplwobq 1 300 train
+epwbqspolv 1 241 train
+epwbrtgupr 1 300 train
+epwesrdmpt 1 300 test
+epwmpwkxio 1 300 train
+epwnsbctud 0 300 val
+epwqkhisif 1 300 train
+epwrieccui 1 300 train
+epwspldhvx 1 300 train
+epwvkmbqze 1 300 train
+epwvvqsutn 0 300 train
+epwzmprgol 1 300 train
+epxbakfukt 1 300 val
+epxcmrrwwi 1 300 train
+epxfjlzjot 1 299 train
+epxotdneee 1 300 train
+epxpeanhzq 1 300 val
+epxubxovhy 1 300 train
+epxwangnvl 1 300 train
+epxxazhprp 0 297 train
+epxynvljqm 1 300 train
+epxzxbchmd 1 298 val
+epyfkqlnhk 1 300 train
+epyihxcvhe 0 300 train
+epymrzuqhm 1 300 val
+epymyyiblu 1 300 train
+epypviwfrs 1 297 train
+epyxfkhovo 1 300 val
+epzlfxuozx 0 300 train
+epznxyujvz 1 300 train
+epztzhrvra 1 300 train
+epzweipokn 1 298 train
+eqaafexycc 1 300 train
+eqabuehals 0 300 train
+eqafrizkve 1 301 train
+eqahzafnym 1 300 train
+eqakbrnwmd 1 300 test
+eqakmmwngj 1 300 train
+eqamptvplr 1 300 train
+eqaqgiolzr 0 298 train
+eqazpgpocj 1 298 train
+eqbhmqbwak 1 300 train
+eqbksplsqc 1 300 train
+eqboxsomoz 1 300 train
+eqbpoylbjf 1 299 val
+eqbrjtdmox 1 300 train
+eqbscfnyaa 1 300 train
+eqbyeipxqh 1 299 val
+eqcfspzshf 1 300 train
+eqchtjasnw 1 300 train
+eqclriamjt 1 301 train
+eqctbhzwuu 1 302 train
+eqcwbrpuqt 0 300 train
+eqcwfzjhfi 0 300 train
+eqdevfaapb 0 300 train
+eqdhbelkdl 1 300 val
+eqdktbbdtx 0 300 val
+eqdrormigj 1 300 train
+eqdzjjlgfx 1 300 train
+eqehiqwgqh 1 300 train
+eqemoxvlgt 1 301 train
+eqesqqzkni 1 300 train
+eqevbnhrai 0 300 val
+eqexoaofvw 1 300 val
+eqfdvgejgf 1 298 val
+eqffckkduj 1 300 train
+eqflqvqxou 1 300 train
+eqfmghrlxk 1 300 train
+eqftvfwfhk 1 242 train
+eqgipviesf 0 300 train
+eqgixnzctg 1 300 train
+eqgxsmgnvz 1 300 val
+eqgxunncgh 1 300 val
+eqgyesnbdo 1 298 val
+eqhbtcenbv 1 301 val
+eqhdvrvfxp 1 300 val
+eqheddgayq 1 300 train
+eqhjyhhtcb 1 301 val
+eqhltmstho 1 300 train
+eqhovlsomi 1 300 train
+eqhpdwysuw 0 300 train
+eqhqvcyfri 1 300 train
+eqhzqnnzmg 1 300 val
+eqiccxqnjb 1 300 train
+eqihmtsyvp 0 300 val
+eqihscbsti 0 300 train
+eqilhfaxqn 1 300 train
+eqitwdggyk 1 300 train
+eqjfsyfohu 1 300 train
+eqjgvglazw 1 300 train
+eqjiagoygx 0 300 train
+eqjkjfdbch 1 300 val
+eqjnmduqpe 1 300 train
+eqjscdagiv 1 300 train
+eqjyrvpfmz 1 300 train
+eqkegfxmur 0 300 train
+eqkhtuippf 1 300 train
+eqklxbzhmu 1 300 train
+eqkmcistey 0 300 val
+eqknkjnvea 1 300 val
+eqknvxglks 1 300 train
+eqkodjrjyz 1 300 train
+eqkqpgsquv 1 298 val
+eqkticrtvs 1 300 test
+eqkybjnuea 0 300 train
+eqkymdlspg 1 300 val
+eqldgiizmy 0 301 train
+eqldobtdic 1 300 train
+eqlhnwfxze 0 300 train
+eqliqjdput 1 300 train
+eqlnukzxxz 1 301 train
+eqlrifcnys 1 298 train
+eqlxpvxtvo 1 300 train
+eqlygriwog 1 300 train
+eqmbljqgyr 1 301 train
+eqmiruoozl 1 300 val
+eqmklliuvv 0 300 train
+eqmmiddpir 1 300 train
+eqmokglwxl 1 300 val
+eqmqbtfnwq 1 298 train
+eqmqwvtxpu 0 300 train
+eqmrmdwnyo 0 300 val
+eqmxbrgkdd 1 300 val
+eqngodbndt 1 300 train
+eqnkhoddav 1 298 train
+eqnmiwvxow 1 300 train
+eqnoqyfquo 0 300 train
+eqnqdhgskm 1 300 train
+eqnrhfnypx 1 300 train
+eqntokofqi 1 296 train
+eqnyjdtfxs 0 300 train
+eqoccqvvtu 0 300 train
+eqocvyioam 1 300 train
+eqodrxvlvy 1 300 train
+eqoknwfyci 0 300 train
+eqolqrnvrl 1 300 train
+eqoqopmgix 0 99 train
+eqoymbglbj 1 300 train
+eqpakjgyae 1 300 test
+eqpbudnwga 1 300 train
+eqpeiboklv 1 269 train
+eqpfwyapqg 1 241 train
+eqpkecgzpu 1 300 train
+eqpmhxxgzu 1 300 train
+eqpnxxliki 1 300 train
+eqponboyow 1 300 val
+eqprqayech 1 300 val
+eqptblfnwc 1 300 val
+eqpyroujfd 1 300 val
+eqpzfibqnp 1 300 train
+eqqeopnjvg 0 300 train
+eqqgvvnnjt 1 300 train
+eqqkryvzcu 1 300 train
+eqqmxgktvw 1 300 train
+eqqrggcmrx 1 300 train
+eqqyjmmtkb 1 300 val
+eqqzrmrire 1 301 val
+eqrachdzog 1 302 val
+eqrjhjzpyg 1 300 train
+eqrnqttedw 1 300 train
+eqrqiddmsp 0 301 train
+eqrrsmbhcm 1 300 test
+eqrygudlpp 1 300 val
+eqsdsagofc 1 300 test
+eqsgqcskkz 0 300 train
+eqslzbqfea 1 300 test
+eqsmwnadad 1 300 train
+eqsnaqrnmz 1 299 test
+eqsntricik 1 300 train
+eqspqyyoca 1 301 train
+eqstliqzef 0 300 val
+eqsushzdrm 1 300 train
+eqszckrudp 1 300 train
+eqszovemao 1 300 train
+eqtbglmcok 1 300 val
+eqtgcgvfxh 1 300 train
+eqthrboxeu 1 300 val
+eqtnwfjxgu 1 300 train
+eqtnypkqul 1 300 train
+eqtqxycvsf 1 300 train
+eqtvtmtgqi 1 300 train
+eqtwkqxolz 0 300 train
+equhphjiwi 1 301 train
+equjwgtema 1 300 train
+equqrmutdj 1 300 val
+equrlxlnst 1 300 train
+equvuhnfmu 1 300 train
+equyucexox 1 300 train
+equzoxiqta 0 300 val
+eqvlynzttm 1 299 train
+eqvqxeygvb 1 300 train
+eqvuywnbbl 1 300 train
+eqvuznuwsa 1 300 train
+eqvvyyvbar 1 300 train
+eqvyydpvxo 1 300 train
+eqvzvbzbtc 1 300 train
+eqwdkfkdpy 1 300 train
+eqwemzqlip 1 241 train
+eqwfruhvfj 1 300 val
+eqwjrvlrbd 1 300 train
+eqwkbdxtyk 1 300 train
+eqwnzogntx 1 300 train
+eqwugufafk 1 300 val
+eqwyfykqkz 0 300 val
+eqxeeaexda 1 300 train
+eqxgjmftio 1 300 train
+eqxjoraple 1 300 train
+eqxlbewrge 0 300 val
+eqxlmvzzyl 1 300 train
+eqxmeoystj 1 300 val
+eqxqgckeaa 1 300 train
+eqxqlfglra 1 300 val
+eqxrhqscte 1 300 train
+eqxvuwzyke 1 300 train
+eqxxtaqwfr 0 300 train
+eqxzucmcjg 1 300 train
+eqybpicyji 1 300 train
+eqygnldapf 1 300 train
+eqyjvkultg 1 300 train
+eqylhwkaoy 1 300 val
+eqywsaajro 1 298 train
+eqzbjcldzm 1 301 train
+eqzbptsabh 1 301 train
+eqzbvhruho 0 300 train
+eqzefvdxhy 1 298 train
+eqzhmbwvip 1 300 train
+eqzhzhvfuk 1 300 train
+eqzizahfxi 1 300 train
+eqzkukaerp 1 300 train
+eqzqwjmzmu 1 300 train
+eqzsejevjm 1 300 train
+eqztafqimw 1 300 train
+eqzuwjgant 1 298 val
+eragtyavhp 1 300 val
+erajgfvrht 1 301 val
+eralrexepy 1 300 train
+eralssljje 0 300 train
+eranxucjrc 1 300 train
+eraodsamyd 1 299 train
+eraprqybnh 1 299 train
+erathgtbsm 1 300 train
+erawxndoay 1 300 train
+erazdrftwy 1 300 train
+erbcdnkjqv 1 300 train
+erbfxwbqic 1 300 test
+erbgcpjuzj 1 300 test
+erbkuqxdue 1 300 val
+erbkvpzedt 1 300 train
+erbnvtidau 1 300 train
+erbohkvmhv 1 301 train
+erbqtjngvc 0 300 train
+erbusacxsz 1 300 train
+erbxczqpfj 1 300 train
+ercdeofpex 1 300 train
+ercgpntrbr 0 300 train
+ercmkkecic 1 298 train
+ercqmajdid 1 299 test
+ercvulggxk 1 299 test
+ercvvpuoqo 1 301 train
+ercwrjsmxx 1 300 train
+erdciikvep 0 300 val
+erdhjyjduk 0 300 train
+erdifqqhyf 1 300 train
+erdklmfxmo 1 300 val
+erdlswrxdt 1 300 train
+erdnvzsdvb 1 300 train
+erdozpufuh 1 299 test
+erdulktysn 1 300 train
+erdxtwlfbz 1 297 train
+erdzftogpr 1 300 train
+ereczvtcsx 1 300 train
+eredlckdyf 1 300 train
+eredrhvjxe 1 300 val
+erefetbhjq 1 300 train
+eregzipklo 1 300 train
+eretemkxyp 1 600 train
+eretmsrysr 1 300 train
+erfjrsvubh 0 300 train
+erflqkzqua 1 297 train
+erfmmfcjdg 1 300 val
+erfnfjcghd 1 300 val
+erfvciteqx 1 301 val
+erggnnfmou 1 300 train
+erhbvayumk 1 299 train
+erhqztizqn 1 300 train
+eriblluuxr 1 239 train
+eridbtnenr 1 298 train
+eriidarzax 1 300 val
+eriilfqkbb 1 297 train
+eriitqowxv 1 300 train
+erinmxmrfx 1 300 train
+eripcbawtb 1 300 val
+eriqwbobly 1 300 train
+erivvzrclv 1 300 train
+eriwsrvpmv 1 301 train
+erjicwmyro 0 300 train
+erjohaltah 1 300 val
+erjpgbkeif 1 300 train
+erjpqvxpxs 1 300 train
+erjwrksgsu 0 300 train
+erkapejfvk 1 300 train
+erkgddivgm 1 298 train
+erkhcpirmc 1 298 train
+erkkufavja 1 300 train
+erkllhrjkt 1 300 train
+erlaoteozv 0 300 val
+erlfvbahxg 1 301 train
+erlhaegtba 1 301 train
+erluerwkwn 1 300 train
+erlvuvjsjf 0 300 train
+ermjohydmm 1 300 train
+ermnqsqory 1 300 train
+erneefwnvq 1 300 val
+ernfzaruwz 1 300 test
+erodeehozy 1 300 train
+eronefamtp 1 300 train
+eroofabioe 1 300 train
+eropxrspka 1 300 train
+erorbvkikv 1 299 val
+erotdfkdnr 1 300 train
+erotfcrebp 1 300 train
+erouztjybk 1 300 train
+eroykhssqp 1 301 val
+erozcmepjb 1 300 train
+erpaijomxg 1 300 train
+erpjijxsjq 1 296 val
+erpnwzoren 0 300 train
+erqcnwkbdw 1 300 val
+erqesciwji 0 300 val
+erqgqacbqe 1 300 train
+erqmvvcphv 1 300 train
+erqradovpa 0 300 train
+errihciscb 1 300 val
+errjlsyicx 1 300 train
+errksyckwl 1 301 train
+errmvmgrme 0 300 train
+errocgcham 1 300 train
+errowohaej 1 300 val
+errpayarzr 1 300 train
+errsybjnsi 1 300 train
+ersmlekxac 1 300 val
+erspuknctn 0 300 val
+erttiebmnu 1 236 train
+ertzslidqb 1 298 val
+erudqctwfx 1 300 train
+erufbzxadr 0 298 train
+erugoqgosb 1 300 train
+erujqhdqsu 1 300 train
+erutikzkfr 1 300 train
+eruzuardbd 1 300 train
+ervbowufgu 1 300 train
+ervdifhhwj 1 300 train
+ervfdioksl 0 300 train
+ervfsynekw 1 300 train
+ervrhrvfej 1 298 train
+ervxfukcgz 1 300 train
+ervxqzbncr 1 300 train
+erwncbdfxa 1 298 val
+erwxlgmlyu 1 300 train
+erxjhlepfe 1 300 train
+erxlsxdfwi 1 300 train
+erxslhffam 1 300 train
+erybgioyfo 1 300 train
+erygqryaay 1 300 train
+eryipdpinw 1 300 train
+eryjktdexi 1 299 test
+erykzkoxtp 1 300 train
+erzfabwflz 1 299 test
+erzrjdtlqv 1 300 train
+erzyucrekk 1 300 val
+erzzhffzvu 0 300 train
+erzzpfakdl 1 300 train
+esaboezwps 1 300 train
+esabpidjmb 1 292 train
+esacncvhun 1 300 train
+esadgdzrry 1 300 val
+esaeysmuud 1 300 val
+esafwdvuby 1 300 train
+esamseoyej 1 300 train
+esamyuedji 1 300 train
+esarxzzvkx 0 300 train
+esauvcogbi 1 300 train
+esbafwoifh 1 297 train
+esbaoauizq 0 300 train
+esbbxlmhhe 1 296 val
+esbjdjcmhd 1 300 train
+esbjhebefl 1 300 train
+escdjejujn 1 300 train
+escfavemij 1 300 train
+escgwtehtk 0 300 train
+eschwpqksb 1 300 train
+esckbnkkvb 1 300 train
+escowvoxet 1 300 val
+escqvfsxap 1 300 train
+esctaaylif 1 301 train
+escubycnrb 1 300 train
+escwmsthiz 0 300 train
+escwylyxap 1 300 test
+esdeajcfxn 1 300 train
+esdmcqxzjh 1 300 train
+esdmehlyhe 0 300 train
+esdscwuuqp 1 300 train
+esdwknhgvs 1 300 train
+esdysjlmku 1 297 val
+esefhskmul 1 300 train
+esejytdary 1 300 train
+eseluytuzh 0 300 val
+eseqomravm 0 299 train
+eserzmylpd 1 300 train
+esetqcaaxy 1 147 train
+esfewlgfuw 0 300 train
+esfgpjuvwm 1 300 val
+esfjjalvtf 1 300 val
+esfkusoapx 1 300 train
+esfqmozfto 1 300 train
+esftzobyyg 0 300 val
+esfzbjqzxj 1 300 train
+esgeiwzavk 1 300 train
+esgeqtjmyn 1 300 train
+esgftaficx 1 300 train
+esgqftxfky 1 300 train
+esgsbocyxt 1 300 train
+eshbpqddmx 1 300 train
+eshcmegogv 0 300 train
+eshesftdmp 1 300 train
+eshnfkwrdv 1 300 train
+eshpfyqxev 1 241 train
+eshpypfpwg 1 299 val
+eshthpimvh 1 300 val
+eshtvbrsld 1 300 train
+eshvuuwqwp 1 300 val
+eshylhwvej 1 300 val
+esibskwqwn 1 300 train
+esidrivnfh 1 300 train
+esijwoctuo 1 300 val
+esiotbeupd 1 136 train
+esiqygmzhl 1 300 train
+esixjxfsms 1 301 train
+esiynxkabe 1 301 train
+esiyzsjmfq 1 269 train
+esjdyghhog 1 300 test
+esjeepgsbm 0 300 train
+esjfanmvpw 0 300 train
+esjnbixlal 1 300 test
+esjnbowbxh 0 300 val
+esjrjzrfeg 0 300 val
+esjskfryfp 1 300 val
+eskccltjll 1 297 val
+eskcrottyh 1 300 train
+eskdvubsyo 1 300 train
+eskfexdxrr 1 301 train
+eskgxjnagp 0 300 train
+eskhoguunr 1 300 train
+eskixrcqzg 1 301 val
+eskluhxdrc 1 301 train
+eskoxzusde 1 300 train
+eskrzejqxk 1 300 train
+eslcazibhu 1 300 train
+eslcjjrvmo 1 300 train
+eslgzuvzya 1 300 val
+eslhebdhyn 1 300 train
+eslibwktlt 0 300 train
+eslqnemuwd 0 300 train
+eslwqsqxuo 1 300 train
+esmfndqmkz 0 300 val
+esmggmwfkm 1 298 train
+esmhdtnhjx 1 300 train
+esmjycftqj 0 300 val
+esmoaiurwt 1 300 train
+esmqulnsef 1 300 train
+esmqxszybs 1 300 test
+esmtytqobh 0 300 val
+esnfpqwxtt 1 300 train
+esngcvacjf 1 300 train
+esnicmcruo 1 300 train
+esnkwjhpcr 1 300 train
+esnntzzajv 1 298 train
+esnqklpomp 1 300 train
+esnsafyapy 1 302 train
+esnswujfhi 1 300 train
+esnwthikca 1 300 train
+esnxwconnv 1 301 train
+esnzqdwpbc 1 300 train
+esobntxlad 0 300 train
+esofzgiqdx 1 302 train
+esohcrpcsz 1 300 train
+esoidwhxwo 1 300 test
+esouzsaubb 1 300 train
+esozpojnmo 0 300 val
+espaodgzxa 1 300 train
+espbwaalta 1 300 train
+espjrijyqa 1 297 val
+espkgxnlfw 1 300 train
+espkiocpxq 1 300 test
+espkkzobwi 0 301 train
+espnsvthvu 1 300 train
+esppzyuocz 1 300 train
+espsovooyn 1 300 train
+esptghvvhu 1 300 train
+espvgdoaem 1 300 train
+espzwjfxvi 1 300 train
+esqapmjzwm 0 300 train
+esqheclrfw 1 300 train
+esqlozyxwo 0 300 train
+esqqatspvz 0 300 train
+esqqrzgtzo 1 300 train
+esqvrydrim 1 301 train
+esqvscxctu 0 300 val
+esqzjinuih 1 300 train
+esrdhvmqvp 1 300 train
+esrkewmeqt 0 300 train
+esrlprirvx 1 300 train
+esrmebhaow 1 300 train
+esrukfrnpx 1 300 val
+esrxmtadkt 1 300 train
+essbuwkggo 1 300 train
+essddktnhl 1 300 train
+essiclzurj 1 300 val
+essmnizpod 1 300 train
+estbfwwxjy 1 300 train
+esthcpamfa 1 300 val
+estkogwhdn 1 298 train
+estmcfrokq 1 300 train
+estmhtrqks 1 300 train
+estswpuhyl 1 300 train
+estwtsbkge 1 300 train
+estygoobsr 1 300 val
+estykblkaw 1 300 train
+esubotylje 1 298 train
+esujvwtwvq 1 300 train
+esuweuifts 1 300 val
+esuyjbnkvx 0 300 train
+esvfbnxbfk 1 300 train
+esvhogkdzs 1 300 test
+esvikpjuiv 1 300 train
+esvjsjvzul 1 300 train
+eswczrhegu 1 301 train
+eswhdoxkyi 1 300 val
+eswjxjblzy 1 136 train
+eswnonvyqk 1 300 train
+eswsjbajnw 0 300 val
+eswtjfnqir 1 300 train
+eswtpeqexa 1 300 train
+eswtqddqlb 1 300 train
+eswtvvkqvn 1 300 test
+eswxwxovtu 1 300 train
+eswzqomvye 0 300 train
+esxmqritho 1 300 train
+esxpvuqdlu 1 297 train
+esxqgermfl 1 300 train
+esxrvsgpvb 1 300 train
+esxygefppr 1 300 train
+esydswnyko 0 300 train
+esydumgise 1 300 train
+esyfakyccm 1 300 train
+esyhwdfnxs 1 300 train
+esynjdisgg 1 300 train
+esyrimvzsa 1 300 train
+eszdsvehly 1 300 train
+eszdvpxjwx 1 241 train
+eszivwjcls 1 300 train
+eszjbqahzh 1 299 test
+esznerjdma 1 300 train
+eszrckbsto 1 300 train
+eszrcywcgd 1 298 val
+esztkevzfj 1 300 train
+etaaaibzns 1 300 val
+etacemolnz 1 300 train
+etaegzedpg 1 300 val
+etagpnouis 1 300 train
+etaqsagfgn 1 301 val
+etawendpkv 1 300 train
+etaxwwpsls 0 300 train
+etbcgrtnft 1 298 train
+etbealbbou 1 300 val
+etbklocgdm 1 300 train
+etbwgmeusp 1 298 val
+etbwplmxmk 0 300 train
+etccauwpqj 1 300 val
+etclzdpmpz 1 300 train
+etcnelygqm 1 300 val
+etcvrzyacw 1 300 train
+etcvvqevun 1 300 train
+etdcqxabww 1 300 train
+etdglmsyin 0 300 train
+etdiyaufib 1 300 train
+etdkolnufl 0 300 train
+etdliwticv 1 300 test
+etdmhqtodf 1 241 train
+etdxfawnai 1 301 train
+etejaapnxh 1 300 train
+etejejcvbo 1 301 val
+etemzfgvac 1 300 val
+etenhykapk 1 300 train
+eterxlklwi 1 300 val
+etewvhbnzs 1 300 train
+etfeuobadu 1 300 train
+etfmsyqdmw 0 300 train
+etfmtolikj 1 300 train
+etfpaxveba 0 300 train
+etfqrclmio 1 300 train
+etfyvfbnbm 1 300 train
+etgczdcvvk 1 299 val
+etgmmymetr 1 300 train
+etgnudemya 1 300 train
+etgnykrkkp 1 300 train
+etgotupzvn 0 300 train
+etgrqvtfwt 1 300 train
+etgsqpfauk 1 301 val
+ethbvtvahp 1 300 train
+ethdazlnnc 1 300 train
+etheswuzvz 0 301 train
+ethiruvhfg 1 300 train
+ethkiptljh 0 300 train
+etiihqouos 0 300 train
+etinaehykw 0 300 train
+etinyifrcj 1 300 train
+etioprbaww 1 300 train
+etirykgbfz 1 300 val
+etisprvjae 1 300 train
+etjctgagcl 1 300 train
+etjfaospvf 1 300 val
+etjfudufax 1 298 train
+etjhvuvyqj 1 300 train
+etjonsboxi 0 301 train
+etjrxypnra 1 300 train
+etjsvyhepr 1 300 train
+etjupcirhj 1 300 train
+etjvzeatqo 0 300 train
+etkgpkqglx 1 300 val
+etkmawxvet 1 299 test
+etkmoudyxt 1 300 train
+etktbymzhx 1 300 train
+etkuwzefva 1 300 train
+etkwneghea 1 300 val
+etkxpolkef 0 300 val
+etlavwxvxy 1 300 val
+etlcqqqrzv 1 300 train
+etlizkhcko 1 298 val
+etljjzxsfm 1 300 val
+etloepycew 1 300 train
+etlpvrbugw 0 300 train
+etlroolqer 0 300 train
+etltdsoubb 1 300 train
+etmbeepygr 1 298 val
+etmcbpjofk 1 300 val
+etmcruaihe 1 300 train
+etmfxxhpcd 1 300 train
+etmjgrudsp 1 300 train
+etmlcqihzs 1 299 val
+etmowcpnhj 1 300 train
+etmpigursu 1 300 train
+etmqrribab 1 300 train
+etmsvuymep 1 300 train
+etmtlobhjl 1 300 val
+etmtpkrxpa 1 300 train
+etndujkuoe 1 300 val
+etnpnfyxuh 1 300 val
+etnricjray 1 300 train
+etnveteuau 1 300 val
+etnvuldqwy 1 300 train
+etnydnrmvb 1 300 train
+etodejdqoj 1 300 train
+etoezdmbjh 1 301 train
+etofetloij 0 300 train
+etohcvnzbj 1 300 train
+etonldfohq 1 301 train
+etoxnbkdan 1 301 train
+etphkpokgh 1 300 train
+etpketrlnd 1 300 train
+etpwjvibdn 1 300 train
+etpxujofec 1 300 train
+etqefqwfem 1 300 val
+etqegkhtlt 1 300 val
+etqeifhttt 1 300 train
+etqekytcma 1 298 train
+etqfezywrc 1 241 train
+etqifsnyki 1 300 train
+etqopucvsa 1 300 train
+etqtqvoofo 1 300 train
+etqulfbomt 1 300 train
+etqyrutfok 1 299 test
+etqziedrbv 0 300 train
+etrbofjhyj 1 300 train
+etrcxfmenu 1 301 val
+etrdptdued 0 300 val
+etrlealthf 1 301 val
+etrprgjbna 1 300 train
+etryveojbc 1 297 train
+etsdnraxgf 1 297 val
+etsfedmwmq 1 298 train
+etsmiepmfs 1 241 train
+etsobifmgk 1 300 val
+etspyajinh 1 301 train
+etspyurooo 1 300 train
+etsusouibh 1 300 train
+etsvhdjyhg 1 300 val
+etswgogitb 1 300 train
+etswuqmyhz 1 300 val
+etswywimft 1 300 val
+ettgpcicqn 0 300 train
+etthnhuidk 1 300 train
+ettliojswb 1 299 test
+ettmoluwyi 0 300 train
+ettolxlpdx 1 300 train
+ettthorxxv 1 300 train
+etttsckqzg 1 300 train
+etuhfvfswk 0 300 train
+etuhwwigem 1 300 val
+etuiyfidqe 1 300 train
+etujbcqbaf 1 300 train
+etussslnws 1 300 train
+etuwobljgk 1 298 val
+etuwxcszcm 1 300 train
+etuyyfpvpz 1 300 train
+etuzieieim 1 300 train
+etuzvpxbod 1 300 train
+etvagcrift 1 300 train
+etvbtqeegd 1 300 train
+etvcdyryxq 1 300 train
+etvmuiutxj 1 300 train
+etvneeiqel 1 300 train
+etvnftwxgr 1 300 train
+etwaxilsdd 1 298 train
+etwejymoqt 0 300 train
+etwgmmiyfl 1 300 train
+etwiwsfgjs 1 300 val
+etwpngxyoo 1 300 train
+etwuvriiws 1 300 train
+etxenjfnaf 1 300 val
+etxknonwli 1 300 val
+etxmshgclx 1 299 test
+etxzgzjwfp 1 300 train
+etxzltpejb 1 300 train
+etychryvty 1 300 test
+etygjbrhzn 1 300 train
+etymlovigx 1 300 train
+etyoqebcio 1 300 val
+etytgluvqg 1 300 train
+etyuxfcnho 0 300 train
+etyysejqhe 1 300 train
+etyyuclunv 1 300 train
+etyywbhrfz 0 300 train
+etyziqzyyr 1 298 train
+etyzplnbru 1 300 train
+etzhgrrviq 1 298 train
+etziqrkyya 1 300 val
+etzoioohut 0 301 train
+etzzmkanzi 1 300 train
+euacgxiohd 0 301 train
+euarbrmuzs 1 300 val
+euaugumzog 0 300 val
+euavixhbsq 1 300 train
+euavjxseoz 1 300 test
+euayomvtle 0 300 train
+eubcovafds 1 302 val
+eubgacitww 1 300 val
+eubjjvbxss 0 300 train
+eublqrvqzf 1 300 val
+eubmnrgbgu 1 298 train
+eubmxnqfrf 1 300 val
+eubpfonvdx 1 301 train
+eubuplmxrk 0 300 train
+eubvmjhspp 1 300 val
+eubzpsdqei 0 301 train
+eucbajvqbe 1 241 train
+euclhezhps 1 300 train
+euclrufrag 1 300 train
+eucqwbtjfu 1 300 train
+euczosymyk 1 300 train
+eudeqjhdfd 0 300 train
+eudetwrgts 1 301 val
+eudmlkbsll 1 300 train
+eudnfziddg 1 300 train
+eudnjqzhac 1 300 train
+eudqyrnjoo 1 300 train
+euegygpzez 0 300 train
+euenttouyr 1 300 train
+euephwnbfo 1 300 train
+euerllhiwr 1 300 train
+euesfaiujx 1 300 train
+euettuhfwk 1 300 val
+euevtellaq 1 300 train
+euewcgckvm 1 300 train
+euewfgjtrf 1 300 train
+euexgfxdel 1 300 train
+eufezjhacr 1 298 val
+euffkttktu 1 298 train
+eufjuiauuq 0 300 train
+eufntetucv 1 301 train
+eufqgqcszg 1 300 train
+eufuvsebix 1 300 train
+eufxalbxbb 1 300 train
+eufxjsolyv 1 301 train
+eugcprxhvd 1 300 test
+eughjmhnwg 1 300 train
+eugizkqdla 1 300 train
+eugjbxtszt 1 300 val
+eugmwsetxd 1 299 test
+eugntjlwqf 1 300 train
+eugohzjnzn 1 300 val
+eugpvwbpiz 1 300 train
+eugrnytjec 1 300 train
+eugskecitn 1 241 train
+eugszzdbxy 1 300 train
+eugucyqvce 1 300 train
+eugvdewtpb 1 300 train
+eugyujwnza 1 299 val
+euhabhqloj 1 298 train
+euhduijesf 1 300 train
+euhfncixdc 0 300 train
+euhfpjfbrt 1 300 train
+euhnopdghl 1 300 train
+euhtswzxyz 0 300 train
+euhtwrrldq 0 300 val
+euibbukhvy 1 300 val
+euictoiuma 1 299 test
+euidgxgpff 0 300 train
+euihqhjkul 1 300 train
+euiiarygve 1 300 train
+euijrempvm 0 300 train
+euilhfyjkj 1 300 train
+euilltgsrq 1 300 train
+euioixajuw 1 300 train
+euiqtmvnja 1 302 val
+euizkgoxog 1 301 train
+eujaqrcjgc 1 300 val
+eujarkvmsd 1 300 train
+eujsvdhrdm 1 300 val
+eujveruhyr 1 300 train
+eujvhvrzyj 1 300 train
+eujzsbivpj 1 300 train
+eukbmcdsbq 1 300 train
+eukcwbotrv 0 300 train
+eukebgiccw 1 300 train
+eukpkxbgcw 1 300 train
+eukutnkwkh 1 300 train
+eukvucdetx 1 300 train
+eukxkhumll 0 300 train
+eukyyxopvt 1 300 train
+euldcdaobo 0 300 train
+eulfnzrojr 1 300 val
+eulkqybopx 1 300 train
+eulmapihck 1 300 train
+eulslskxei 1 300 train
+euludczkni 1 300 train
+eulxbczasr 1 300 train
+eumezsjkur 1 300 train
+eumfzayvdz 1 300 train
+eumizltjon 1 297 train
+eumlufqcfn 1 300 train
+eummhwqrcd 1 300 train
+eummwjqbpd 1 300 train
+eumqvwtksc 1 300 train
+eundchcedg 1 300 train
+eunmknftuv 1 298 train
+eunmohsjhe 1 241 train
+eunnmzcojr 1 300 train
+eunsttomkc 1 300 train
+euobuvvxhc 1 300 train
+euopwhixuv 0 300 val
+euoudlinep 0 241 train
+euovhdcpim 1 300 train
+eupbthgsbs 1 300 train
+eupepgixho 1 300 test
+eupisnxhsb 1 299 test
+eupvhqwmpe 1 300 train
+eupwpdxbqm 1 288 train
+euqeauccmw 1 300 train
+euqfagpckg 1 300 train
+euqgbqurns 1 301 train
+euqnrfcvnd 1 241 train
+euqpvnyxrb 0 300 train
+euqtwhhwwr 1 299 val
+euqujvlnnb 1 300 train
+euqwejvncu 0 300 train
+eurcogcewe 1 300 val
+eurfdjzxng 1 300 train
+eurhttghny 1 300 test
+eurjsnbbug 1 300 train
+eurnsychmr 1 300 train
+eurpcvhazx 1 300 train
+eurtdahlrz 1 300 val
+eurwocrxgj 1 300 train
+eurzqqifpl 1 300 train
+eusahtoays 1 302 train
+eusbnwxcah 1 300 train
+eushohxtpt 1 300 train
+eushtbqdjk 1 241 train
+eusshevuiy 1 300 train
+eussutnjhy 1 300 train
+eusuehokbv 1 300 train
+eusvkbaogc 1 300 train
+eusxhfybrd 1 300 train
+euszkwoqeq 1 300 val
+eutaedkkmc 1 297 train
+eutayddgov 0 300 train
+eutcmnwsum 1 241 train
+eutgwsszqf 1 300 train
+euthwchlci 1 300 train
+eutlgwrkih 1 300 val
+euttnardyg 1 300 train
+eutvitygbh 1 300 train
+euubbgaubd 1 300 train
+euueadilsp 1 300 train
+euunyizmtc 1 300 train
+euurmiutnv 1 300 train
+euuwzjplib 1 300 train
+euvdoiaokh 1 301 val
+euvhbpgluc 1 302 train
+euvpbsvwif 1 300 val
+euvtqhdptn 1 300 train
+euvxrcqcpt 1 300 train
+euwlescdpt 0 300 train
+euwrayzkvf 1 300 val
+euwtvrqjog 1 300 train
+euwwjjjbsa 1 300 train
+euwzjauqgi 0 300 train
+euxcelftrj 1 300 test
+euxlncjaip 1 300 train
+euxmgykyip 1 300 val
+euxofyxagh 1 300 train
+euxpunysza 1 269 train
+euxuxpvomo 1 300 val
+euydqohhqn 1 300 train
+euylxrfdrk 1 298 train
+euynucvzjq 1 300 val
+euyugdpidp 1 300 val
+euyuojpjbx 1 300 val
+euyynvauyv 0 300 train
+euzbeoqyyd 1 300 train
+euzekaecvr 1 300 train
+euzemejyah 1 300 train
+euzkckmjbm 1 300 train
+euzlhdnsid 1 300 train
+euzlhrwolz 1 300 val
+euzmxtuswh 1 301 train
+euzqwnlgkk 0 301 train
+euzrhamais 0 299 train
+euzswuawca 1 300 val
+evafvwxarh 1 300 train
+evanozbfoa 1 300 val
+evaqaeuhro 0 300 val
+evatniqhlm 1 300 val
+evauagoyun 1 300 train
+evaxlxcwgp 0 300 val
+evbcnhjvvt 1 300 train
+evbgxgbupt 1 300 train
+evblkrxmto 1 299 test
+evbndvudug 1 269 train
+evbnyntpnd 1 300 train
+evbqwvvsdi 1 300 train
+evctyqapap 1 300 train
+evcufdsehk 1 300 train
+evcuyvdcoz 1 301 val
+evcvnfldgv 1 300 train
+evdarxrenf 1 300 train
+evdjvyzrxd 1 297 train
+evdlnfysfg 1 298 train
+evdxodqhso 1 302 train
+evecwbqsfu 1 300 train
+evejryaoag 1 300 train
+evelnossix 0 300 train
+eveosulcbn 1 300 train
+evetzgnhxj 1 300 train
+eveumzukvk 0 300 train
+eveuugilki 0 300 train
+evfepuimjg 1 300 train
+evfmcoeebg 1 300 val
+evfwfkjxli 1 300 train
+evfwgmxgrj 1 300 train
+evfwhdnals 1 300 train
+evfymmywdn 1 300 train
+evfzpitpgc 1 300 train
+evgccmcmkn 1 300 train
+evgdrmajqt 1 300 train
+evgejrtvay 1 300 test
+evghzsgtxc 1 300 train
+evgqgkfptg 1 300 val
+evgqsxqmwi 1 240 val
+evgsgtzsmq 1 300 val
+evgwwdmcxa 1 300 train
+evgzjtwveg 1 300 train
+evhcmambkp 1 300 train
+evhjkghtmq 1 300 train
+evhpaxklkc 1 301 train
+evhpwknrdu 1 300 val
+evhtpeyqsc 1 300 train
+evhwvefsle 0 300 train
+evhykxalmi 1 300 train
+evibqvhyjc 1 298 train
+evidskkybl 1 300 train
+evihvzkysp 1 300 train
+eviqjqhqni 1 300 train
+eviqugvhte 0 99 train
+evirgbpwbl 1 300 train
+evirwnkqms 0 300 train
+evitrbujbq 1 300 train
+eviwwcskgc 1 300 train
+evjgxegspv 1 300 val
+evjhkjeqys 1 300 val
+evjkrjrged 0 300 val
+evjlrttcki 1 300 train
+evjumxcwur 1 300 train
+evjwbpbubo 1 301 train
+evkagcffdi 0 300 train
+evkevitmfx 1 300 train
+evkkjgvprd 1 300 val
+evkmmqbdgq 0 301 train
+evkmrhlwak 1 300 train
+evknxifuyp 1 300 train
+evlfjbyegt 1 300 val
+evlkhfbyaa 1 300 train
+evlohmpajz 1 300 train
+evmcvkhort 1 300 val
+evmgcjcsnm 1 241 train
+evmgtesofz 1 300 train
+evmmsjwyqj 0 300 train
+evmrcinjdq 1 300 train
+evmrudfvbf 1 300 train
+evmujzsypj 1 300 train
+evmvevujtc 1 300 train
+evmxjxoahl 1 300 train
+evnbhowkba 1 300 val
+evnbpdndlu 0 301 val
+evnclxelyx 1 300 train
+evnfjvobno 1 300 train
+evnllqxqbi 1 300 train
+evnpfradix 1 300 train
+evnwptizdh 0 300 val
+evnzxbnlti 1 298 val
+evoiapzwne 1 300 train
+evoieivlzm 1 300 train
+evojufsbso 1 301 train
+evoolgcqip 0 300 train
+evoxksjmtv 1 300 train
+evoyvlktol 1 300 train
+evpbbjssuo 0 300 train
+evpbiqfqqv 1 300 val
+evpcvomshc 1 241 train
+evpdgbdvkm 1 300 train
+evpmcvhcpz 1 300 train
+evpnxfhmnu 1 300 train
+evppthjsbd 1 300 train
+evptgknypl 1 300 val
+evpuikalfe 1 300 train
+evpvyvqybg 0 300 train
+evpxmftwyw 1 300 train
+evpynkvpzb 1 301 train
+evpzeohkrq 1 298 train
+evpzhcdpvk 1 300 train
+evpzowaulh 1 300 train
+evpzypwfxg 0 300 train
+evqelgbjbq 1 301 train
+evqfdqvvks 1 300 train
+evqiukuqff 1 300 train
+evqocfaybd 1 300 train
+evqpfithgd 1 300 train
+evqpppnrfs 1 300 train
+evqqkbfnff 0 300 train
+evqumrxyfs 1 300 train
+evqxazxbnh 1 300 train
+evrgcrznre 0 300 train
+evrnsnwpjd 1 301 train
+evrpdowggo 1 300 train
+evrxbzvqbj 0 300 train
+evsbufgkbn 1 300 train
+evsgkrvptx 1 300 train
+evsmwusbox 1 300 train
+evsokhsekc 1 300 train
+evsrwoifxu 1 300 train
+evtejfbbal 0 300 train
+evtizpbsrt 1 300 train
+evtqlcanne 1 300 train
+evttikralx 1 300 train
+evtwpssjhk 1 300 train
+evtxiaxexc 0 300 val
+evtzmeblgw 1 300 train
+evudgjgkkk 1 300 val
+evukegvdwh 1 300 val
+evukpdfsas 1 301 train
+evupxzzoxz 0 300 train
+evutrhbglp 0 300 train
+evuyarrqcb 1 300 val
+evuyqnwzgm 1 300 train
+evvacwqxzb 1 300 val
+evvbmiusjr 1 300 train
+evvcmlzliv 0 300 val
+evviuewjod 1 300 val
+evvotowfkw 1 300 train
+evvpasudrd 1 300 train
+evvqlsuerd 1 299 test
+evvrdztpmi 1 300 train
+evwcrawhto 1 300 train
+evwgkntebg 1 300 train
+evwijiahjz 1 300 train
+evwtcjhytk 1 300 train
+evwtxpowgd 1 300 train
+evwveuowav 1 300 train
+evwwcybbol 1 301 train
+evwyllcgxp 1 300 train
+evwyqhqahv 1 300 val
+evxcpabxnq 1 298 val
+evxpjmlixq 1 300 train
+evxtqswetb 1 300 val
+evxyexlrgp 1 301 train
+evyccyiixt 1 300 train
+evyjwdkuhu 1 300 train
+evynetxtig 1 296 val
+evypufjvtr 0 300 train
+evyqbkbsiv 1 300 train
+evyqfdjexh 0 300 train
+evysmtpnrf 0 300 test
+evyvummwke 1 300 train
+evyyxzgnmo 1 296 train
+evzeawuuvf 1 300 val
+evzfyaeqey 1 300 train
+evziryftvx 1 301 train
+evzmijhthq 0 300 train
+evzwnwrjgz 1 300 test
+ewalytdxho 1 300 val
+ewapjbcfuv 1 300 val
+ewavdsgjyf 1 300 train
+ewavtkrxbb 1 241 train
+ewaxowzmna 1 300 train
+ewbgvlunzf 1 300 train
+ewbgymjvos 1 300 train
+ewboiokegt 1 300 train
+ewbpzlfdgk 0 300 val
+ewbtyfjswh 1 300 val
+ewcarvojld 1 300 val
+ewccqwkhpc 1 300 val
+ewceeinrel 1 300 train
+ewcfslabwh 1 300 train
+ewcgydtfjp 1 300 train
+ewchmfogip 1 300 train
+ewcjerkrwq 0 300 train
+ewclupknhn 1 300 train
+ewcyhjucor 1 300 val
+ewdcazacrh 0 300 train
+ewdeufyoic 1 300 train
+ewdjkplgei 1 300 train
+ewdncxleyj 1 299 train
+ewdonszwnn 1 300 train
+ewdpatntaf 1 300 train
+ewdtalygox 1 300 train
+ewdubecsnk 1 301 train
+ewdvbsuihy 1 300 train
+eweezufaky 1 300 train
+ewehqnfmvr 1 300 train
+eweidnvatl 1 300 train
+ewenqgkepv 1 300 train
+eweohmorwm 1 300 train
+ewepgwxnbc 0 300 train
+ewerbsencj 1 300 train
+ewfgypoisb 1 300 val
+ewfnvcuvnn 1 300 train
+ewfpsvyffv 1 300 val
+ewglmznvxe 1 300 train
+ewgoylxwgv 1 300 train
+ewgqzawytw 1 300 train
+ewgsqtuvqu 1 300 val
+ewgwgsftfq 1 300 train
+ewgyrkfkmq 1 300 train
+ewhdbhzmlr 0 300 train
+ewhdymgjmo 1 301 val
+ewhpvcwxyg 1 300 val
+ewhtjwbuqy 1 300 train
+ewhwdzukev 1 300 train
+ewhwxhjogw 1 300 train
+ewhxngtnia 1 300 train
+ewimhhuovr 1 300 train
+ewivyisjtm 1 300 train
+ewixzuqwga 1 300 train
+ewiyhypsgq 1 300 train
+ewjajgrcjl 1 300 val
+ewjopkuafz 1 298 train
+ewjrqhcwbn 1 300 val
+ewjwkmevus 1 301 train
+ewkakfpqmw 0 300 train
+ewkdvemmff 1 300 train
+ewknjjmzqb 1 300 test
+ewkqjdhvvo 1 301 train
+ewkwgpdrhv 1 300 train
+ewlfdytbhz 1 241 val
+ewlhdpdrtq 1 300 train
+ewlojhipnw 1 300 train
+ewlyehxfzb 1 300 val
+ewmcrdjktd 1 300 val
+ewmdybkcda 1 300 train
+ewmhqidvlq 1 300 train
+ewmhzluvgm 1 300 train
+ewmmoghilb 1 300 train
+ewmppwynnf 1 300 train
+ewmqqpfgjm 0 300 train
+ewmtcmxyjd 1 301 train
+ewmunvvtxg 1 301 val
+ewnbfdjecq 1 300 train
+ewncpbhvvx 1 300 train
+ewnftxjwci 1 300 val
+ewnjeqojwg 1 300 train
+ewnlkyprvh 1 300 train
+ewnoyoiotj 1 300 train
+ewnxcyojwp 1 297 val
+ewoczpvuuc 0 300 train
+ewoefcghuy 1 300 train
+ewokvfyjsz 1 300 train
+ewomeimiqz 0 300 train
+ewoxyqlsrh 1 300 train
+ewpgxynkyb 1 300 train
+ewpjjhprmj 1 300 train
+ewpkerhxfb 1 299 val
+ewpkflkuah 0 300 val
+ewpkgsitss 1 300 train
+ewpofkrxae 0 240 train
+ewppdjmscl 1 300 train
+ewppusxdih 0 300 train
+ewpvbvbnxy 1 292 val
+ewpykkacyo 1 300 train
+ewqazqdrmg 1 300 train
+ewqbigarao 1 301 train
+ewqffplnea 1 300 train
+ewqlqvleil 1 299 val
+ewqpsoyfes 1 300 train
+ewqrfiisqe 0 300 train
+ewqrjskhlh 1 300 train
+ewregmzonc 1 299 test
+ewreissupj 1 300 train
+ewrgbguien 1 300 val
+ewrgbnztgs 1 301 train
+ewrlrkjock 0 300 train
+ewrnmphzzi 1 300 val
+ewrozspbny 1 300 train
+ewrpdzlzkb 1 300 train
+ewrrpxobje 1 300 train
+ewrsolskmf 1 300 train
+ewrtxhsahr 1 300 train
+ewrxgyqgzz 1 300 train
+ewrxohkehk 1 300 val
+ewsdluigpt 1 300 test
+ewsnlacgxj 1 300 train
+ewtcglcfsm 1 300 train
+ewtfuvmpps 0 298 val
+ewttmsywwz 1 300 val
+ewtygmmlsd 1 300 test
+ewuddtkwxf 0 300 val
+ewuhuebngm 0 300 train
+ewuibihtuo 0 300 val
+ewurxuyrwv 1 300 val
+ewvcoskmnu 1 300 train
+ewvdytcajf 0 300 train
+ewvelymojn 0 300 val
+ewvsvyatbp 1 300 val
+ewwhlscuha 1 301 train
+ewwkfljrua 1 300 train
+ewwvllyjdr 1 300 train
+ewxcjogzhk 1 300 train
+ewxddjqzml 0 300 train
+ewxlmjtfwq 1 300 val
+ewxmmeyqtl 1 300 train
+ewyeaqhmfe 1 300 train
+ewyghebhvl 1 300 val
+ewygzrrcft 1 300 train
+ewynxmyodj 1 300 val
+ewysmnpdkm 1 300 train
+ewyzdxbich 0 300 train
+ewzslkongs 1 300 train
+ewzvqdqchc 1 301 train
+ewzyngqedc 1 300 val
+ewzyrgbxtk 1 300 train
+ewzythzlez 1 300 train
+exactiudfy 1 300 train
+exalixapsg 1 300 val
+exanjjxzre 1 300 train
+exapkjzlcc 1 300 train
+exapoobbmo 1 300 val
+exatrzuvgq 1 300 train
+exbachoyoo 1 300 val
+exbbqbpljs 1 300 train
+exbcottrza 1 300 val
+exbcpxkyuv 1 300 train
+exbggebksr 1 300 train
+exbrvchpgv 1 298 train
+exbxfmqqpx 1 299 train
+excbecqxzk 1 300 train
+excdqgwwuy 0 300 train
+exchwpjvgr 1 300 train
+excifevbsh 1 300 val
+excjgrhggx 1 241 train
+excmyfrwzp 1 300 train
+exconiqian 0 300 train
+excorurywi 1 300 train
+exctrfukdb 1 300 train
+excumhymko 1 299 train
+excvgksgda 1 300 train
+excvtyvuto 1 300 train
+excyzzigtp 1 298 train
+exdaebbqwg 0 301 train
+exdarcvuci 1 300 train
+exddoxwyel 1 300 train
+exdiqsgncd 0 300 train
+exdmnregfr 1 300 train
+exdvnmtaeq 1 299 train
+exdvpvycrd 1 300 val
+exdxpotzrw 1 300 train
+exeamsvwes 1 300 train
+exebnwjiao 1 300 val
+exegqniiaj 1 300 train
+exehikjona 1 300 train
+exelrplurw 1 300 train
+exetyzhsyc 1 300 train
+exewzykbsv 1 300 train
+exfbtfriwb 1 300 train
+exfgcpqoyy 1 301 train
+exfpnvnfwa 0 300 val
+exfpupyhhl 0 300 train
+exfugxlaic 1 300 val
+exgauztqla 0 300 train
+exgboibseg 1 300 train
+exgbqfgaoj 1 300 train
+exgcskiest 1 300 train
+exggwnyfiz 1 300 train
+exgkuxgeup 1 300 train
+exglrgczti 1 300 val
+exgmypzisd 1 300 train
+exgtchfkbs 1 300 train
+exgtoejemq 0 300 train
+exguxglksl 1 300 train
+exhfrwrwiq 1 255 train
+exhfwnjwrh 1 300 val
+exhhgxhedf 1 300 train
+exhizvutjm 1 300 train
+exhkvwrvks 1 300 train
+exhofobrlg 1 300 train
+exhqbptkqy 1 300 train
+exhqvcivyb 1 300 train
+exhsvztrjf 1 300 train
+exhwpkwgjr 1 300 train
+exhzzxwghl 1 300 train
+exiabvuzmo 1 300 train
+exifnhfkzs 1 300 train
+exikkzaesy 0 300 train
+exilgnvbhf 1 300 train
+exioersgps 1 300 val
+exipptdkki 1 300 train
+exjfejwdmk 1 300 val
+exjhqhkiiq 1 300 train
+exjhxchdsg 1 241 train
+exjmbshhkl 1 300 train
+exjmfjwuvn 1 300 train
+exjmtejyxo 1 300 train
+exjnpsilrw 1 300 train
+exjpkzvand 1 301 train
+exjspovhor 1 300 train
+exjuhrvmkd 1 300 train
+exjuupytug 1 300 train
+exkbsurshn 0 300 train
+exkchgggai 1 301 train
+exkflgswfx 1 300 train
+exklctvfty 1 298 train
+exkoqwpzpl 1 300 val
+exlbmtpqbt 1 300 train
+exlmepcdps 1 300 val
+exlqfdvhaf 1 301 val
+exlxuggisv 1 298 train
+exlymefpqh 1 300 train
+exlyzcphfm 1 300 val
+exmuhuamql 1 300 train
+exnfrnkgco 1 300 val
+exngsbdjkg 1 300 train
+exnictzxtl 1 300 val
+exnouagpnh 1 301 train
+exnqtksnsd 1 300 train
+exntculcjo 1 300 train
+exnvnrzqjf 1 300 val
+exnvpnwloi 1 300 val
+exnwunjolo 0 300 train
+exnxhajmic 1 300 train
+exnxonosso 1 300 train
+exobpiroru 1 300 val
+exoejlyrxw 1 300 train
+exoijhzndo 1 301 train
+exoiljxgnb 1 300 train
+exoiygftnt 1 300 val
+exosimokky 1 300 val
+exotjouiuv 1 300 train
+exouxhurex 0 300 val
+expbhhdplc 1 300 val
+exprsetrwv 1 300 train
+expwjnqnny 1 300 train
+expxuxqhrm 1 300 train
+exqaaevevx 1 300 val
+exqfnbnwll 1 300 val
+exqoaqcbga 1 300 train
+exqxqktuzi 1 300 train
+exrdfjblnj 1 300 train
+exrlkypabt 1 300 train
+exrosljwid 1 300 train
+exruieyion 1 300 train
+exryowrpso 0 300 train
+exsbgixhir 1 300 val
+exsclanyjg 1 300 train
+exseruhiuk 0 300 test
+exsjbkldxf 1 298 train
+exsrsllqdk 0 300 train
+exsteszbhp 1 269 train
+exsuygvela 1 300 train
+exsvptiatk 1 300 train
+extbidooov 0 299 val
+extfjvooaw 1 300 train
+extgpbsbsb 0 300 train
+exthjwvrla 1 300 train
+extihvlsxg 0 300 train
+extlvvqoef 1 300 train
+extmbbwsdy 0 300 val
+extnqzbhco 1 300 train
+extomzpuqq 1 300 train
+extpwopzkx 1 300 train
+extthfnusg 1 300 train
+extvdesumz 1 300 train
+exufspgvfx 1 300 train
+exugxrmaah 1 300 train
+exukprbcuu 1 300 val
+exullzlbif 1 300 train
+exumphhxwa 1 300 train
+exunhdbwmp 1 300 val
+exuqawztwn 1 300 train
+exurdvqjej 1 240 train
+exuuxtxiur 1 301 val
+exuwywbqik 1 300 val
+exuxoisxyl 1 300 train
+exvapekqxv 1 301 train
+exvbiowzyn 1 300 train
+exvdklllgp 1 300 train
+exvjqgfhuo 1 146 train
+exvnsbkqpy 1 300 val
+exvwmgobwc 1 300 val
+exwbhaviyy 1 300 train
+exwbzleeek 0 300 train
+exwebcophp 1 301 train
+exwjftbmrt 1 300 val
+exwjynivjo 0 300 train
+exwkcuqyhs 1 300 train
+exwreeeour 1 301 train
+exwvsbyknd 1 300 train
+exwwkhjkbw 1 300 train
+exwwmdzioh 1 300 train
+exwyzmylhy 1 300 train
+exwzqdxddt 1 300 train
+exxdugnweb 0 300 train
+exxfhkgnvx 1 300 train
+exxmdbzkyr 1 301 train
+exxnwcwkge 1 300 val
+exxqlfpnbz 0 300 test
+exxutccavg 1 300 train
+exybacigpe 1 301 train
+exybmorhyk 1 301 train
+exybyhqsag 1 300 train
+exynuryqhz 0 299 train
+exyxizknpa 1 300 train
+exzaaebioh 1 300 train
+exzhvkjabr 1 301 train
+exzkbgzgib 1 300 train
+exzlkzguxl 1 300 train
+exzuisvrpr 1 241 train
+exzzhzcvjo 1 300 val
+eyacdtciqm 1 300 train
+eyacmcjknj 1 300 val
+eyahtukize 1 300 train
+eyamnjolnp 0 300 train
+eyanizeghw 1 300 train
+eyaseuvaal 1 300 train
+eybccxcxrn 1 300 val
+eybcdhehha 1 300 train
+eybdavkfzg 1 300 train
+eybhytmswk 1 300 val
+eybhzkzvhd 1 239 train
+eybjavzmoy 1 300 train
+eybluknonz 0 300 train
+eybmslynad 1 300 train
+eybvalvwfq 1 300 val
+eybvpbhezl 1 300 train
+eybweytsbt 0 241 val
+eycacodtjk 1 300 train
+eycdlgettr 1 300 train
+eycfnmrhdt 1 300 train
+eycnpnvqed 1 288 train
+eycwvdpqbo 1 300 train
+eydebflvug 1 300 train
+eydggntgwm 1 300 train
+eydgzjbwvz 1 300 train
+eydjhucgly 1 300 train
+eydltbrgfj 1 300 val
+eydmpkgqeq 1 300 train
+eydxjimncv 0 300 train
+eyeavddsza 1 300 train
+eyebiidzte 1 300 train
+eyeboujggi 1 300 val
+eyednyojwx 1 300 train
+eyeeizenid 0 300 train
+eyekesnzuh 0 300 train
+eyeksssuvg 1 301 train
+eyemqvadrv 1 300 train
+eyeqnbqamj 1 298 train
+eyeqydhtte 1 300 train
+eyetgxfimp 1 300 train
+eyevwdohgf 1 300 train
+eyfedhzase 1 297 train
+eyffoapcce 1 300 val
+eyfjvaboam 1 298 val
+eyfliddvar 1 299 train
+eyfpgyabpk 1 300 train
+eyfqtmmjhg 1 300 train
+eyfuyzgghr 1 300 val
+eygcphespr 1 300 train
+eygcpssvws 1 300 train
+eyggyzewzb 1 300 val
+eygjbnzgmt 1 300 train
+eygocervrz 1 301 train
+eyguqfmgzh 0 300 test
+eyguyqoyml 1 300 train
+eygwtqpnue 1 300 train
+eyhgjtcdvh 1 300 train
+eyhhnebwcs 0 300 train
+eyhixwoapu 1 300 val
+eyhizewvlt 1 300 test
+eyhjqwikza 0 300 train
+eyhlrrcvea 1 300 train
+eyhlvkamkb 1 300 train
+eyhphpspew 1 300 train
+eyhsrybgro 0 300 train
+eyhsyonaxb 1 300 train
+eyhzhvvmkl 1 300 train
+eyiahkxsvc 0 300 train
+eyiakymhoz 1 241 train
+eyiciuhrvv 1 298 val
+eyirdehevf 1 300 train
+eyitbxcakn 0 300 train
+eyivatspar 1 300 train
+eyixkzppxc 1 301 train
+eyjejjgdyd 1 300 val
+eyjiippprl 0 300 train
+eyjiwmclao 1 300 train
+eyjpughmmi 1 300 train
+eyjtvcfdbo 1 300 val
+eykayfqngu 1 300 train
+eykgdojbbf 1 300 train
+eykgzdbvpe 0 300 train
+eykkthrnoy 0 300 test
+eylfklsjwo 1 300 val
+eylmytvbqt 1 300 train
+eyltmgzqal 1 300 train
+eylwvdgbcy 0 300 train
+eymbhwikgh 1 300 train
+eymdkdeudq 1 300 val
+eymkppycqq 1 301 train
+eymmvgrtsx 1 300 val
+eynboqrsnk 1 300 train
+eyndhzzodk 1 300 train
+eyndltjeoh 1 300 train
+eyntanjavy 1 300 val
+eynvbesfsi 1 300 train
+eynxajczkd 0 299 test
+eynzqgzqwc 1 300 train
+eyobwrpppe 0 300 train
+eyoitfsnhl 1 301 train
+eyoweyxyiv 1 301 val
+eypevytikz 1 300 train
+eypfraqxmc 1 300 test
+eypjnqccva 1 300 val
+eypoacrmcv 1 300 train
+eypqcwmvfd 1 298 train
+eypudhbdbp 1 99 train
+eypzcikkrb 0 300 train
+eyqjufadve 1 300 train
+eyqnayljgq 1 300 train
+eyqwkxoiya 1 300 train
+eyrdrnlpdu 1 300 val
+eyrljxqrjz 1 300 train
+eyrnirnrcn 1 300 train
+eyrphmtciv 1 300 train
+eyrqcdwlee 0 300 train
+eyrvyndpjs 1 300 train
+eyrwzznfov 1 300 train
+eysacgyjvx 1 300 train
+eysalhhefi 1 300 train
+eyscmmobpw 0 300 val
+eyserqjwlg 1 300 train
+eysfaqsokt 1 300 train
+eysijcirnw 0 300 train
+eysueyvzry 1 301 train
+eysvudwmjk 1 300 train
+eyswgigekf 1 300 val
+eytatcgpkg 1 300 train
+eytntqdzqp 1 300 train
+eyubsoufwk 1 300 train
+eyudklhxjj 1 300 val
+eyujrtghok 1 300 train
+eyulbxiwne 1 300 train
+eyumihfcck 0 300 train
+eyusbqspuh 1 300 train
+eyvjbgibfm 1 300 train
+eyvsgkwrkj 0 300 train
+eyvwkwpqba 1 241 train
+eywamnfgsr 0 300 val
+eywdmustbb 1 300 test
+eywkptzdvl 1 300 val
+eywqtttzxd 1 301 train
+eywrvybdvp 1 300 train
+eywtrllazw 1 300 train
+eywxpimyad 0 300 train
+eywyirgzon 1 300 train
+eyxbxeyukj 1 300 train
+eyxgfavxld 1 298 train
+eyxhkexasm 1 299 val
+eyxivepgri 1 300 train
+eyxjlhkadh 1 300 train
+eyxjvtskkd 1 300 train
+eyxkxjzyci 1 300 val
+eyxkycclyx 1 300 val
+eyxmouvody 0 300 train
+eyxnjbodxy 1 300 train
+eyxrxayemu 0 300 val
+eyxtmbdynz 1 300 train
+eyxuzvrwik 1 300 train
+eyxvndtjxm 1 300 train
+eyyafuqxuj 1 300 val
+eyybmdcloy 1 300 val
+eyyebthppe 1 300 train
+eyyigsrqff 1 300 test
+eyyknluydp 1 300 train
+eyywfiialh 0 300 val
+eyzalirywb 1 298 train
+eyzewpjtzp 1 300 train
+eyzgwzegwv 1 300 val
+eyzgzdgtyn 1 300 train
+eyzmtkklvc 1 300 val
+eyzrnbvgkn 1 300 train
+eyzrwpudox 0 300 train
+eyzudnrcnp 1 300 train
+eyzzwyjyfz 1 300 train
+ezaajaswoe 0 300 train
+ezaaqjpswx 0 300 train
+ezabcrihco 1 300 train
+ezabjvevlu 1 300 train
+ezabudfqms 0 300 train
+ezadehoecy 1 301 train
+ezajsnknkc 0 300 train
+ezanlofvuw 0 300 train
+ezavxvivqy 1 300 val
+ezbbgipdfn 0 300 train
+ezbcopeybv 0 300 train
+ezbdhcawda 1 300 val
+ezbfsanxnk 1 300 train
+ezbojukhxs 0 300 train
+ezbvvongzk 0 300 test
+ezbwkhycbe 1 300 train
+ezbyfrzjqx 1 299 test
+ezckbwmnvc 1 300 train
+ezckgtsqzk 1 299 train
+ezcpxwleel 0 300 train
+ezcqzucpcr 1 300 train
+ezczrzbsgq 1 300 train
+ezddinqpqf 1 300 val
+ezdhkuoydl 1 300 train
+ezdrxsnicg 1 298 train
+ezdzzsxvab 1 300 train
+ezegjkfrad 1 300 train
+ezehdjvwvy 1 300 train
+ezeknttgkv 1 300 train
+ezevmuxtwu 1 298 train
+ezfarchrcg 0 300 train
+ezfjywtlpn 1 300 val
+ezfmobxvil 1 300 train
+ezfomrgwam 1 300 train
+ezfonqdiqe 1 300 train
+ezfrcspzxw 0 300 val
+ezgevynkof 1 146 train
+ezgjzcywfe 1 300 val
+ezgmjmlssa 1 300 val
+ezgruvwexl 0 300 train
+ezgusylcyf 0 301 train
+ezgxxzmyyq 1 300 train
+ezhgsdifpb 1 300 train
+ezhncxjtjw 0 300 train
+ezhnuaiazw 1 300 train
+ezhnymmhht 1 300 train
+ezhwueehlt 1 301 train
+ezipjzeffl 1 301 train
+ezjfyxslqt 1 300 train
+ezjpqczmeg 1 297 train
+ezjqyugalp 1 300 train
+ezjxunqfkn 0 300 train
+ezjzbtktdp 1 300 train
+ezkdbplvgc 1 300 train
+ezkhhudbyn 1 301 train
+ezkidfosnl 1 300 train
+ezkjedjlcf 0 300 train
+ezkprcfhuo 1 300 train
+ezktdxxahe 1 300 val
+ezkunpqrzh 1 300 train
+ezkxbqxbam 0 300 val
+ezkyiounzg 1 300 train
+ezlehpbfya 1 125 val
+ezlekovezp 1 300 train
+ezljdafkkh 1 300 train
+ezllcntwvv 0 300 train
+ezlpviyboj 1 300 train
+ezlsmflifv 1 300 train
+ezltfgktsa 1 300 val
+ezmbjytutg 1 300 train
+ezmdnojhuc 1 297 train
+ezmfkgbadc 1 300 train
+ezmfsviyuc 1 299 test
+ezmhgyjwqt 1 300 train
+ezmjanosfv 1 298 train
+ezmlngrlvg 1 300 val
+ezmvbsgogx 0 300 train
+eznazoptjg 1 300 val
+eznfhmennm 0 300 train
+eznrzwebix 1 300 train
+eznsavfnav 1 300 val
+ezocuommzp 0 300 train
+ezogongwfo 1 300 val
+ezolzuxyio 0 300 train
+ezoogxmkvq 1 241 train
+ezouqnopwi 1 300 train
+ezozhammnh 1 301 train
+ezpaloghzj 1 300 train
+ezpgbzhejw 1 300 train
+ezpialoqyh 1 300 val
+ezpizkjycp 1 300 train
+ezpnggyxtz 1 298 train
+ezpsqjytug 1 300 train
+ezpulhyrqd 1 300 val
+ezpuvfxzir 1 241 train
+ezqoboflbm 1 300 train
+ezqscppooh 1 300 train
+ezrfihipbi 1 300 train
+ezrgemzvju 0 300 train
+ezrlpsoczz 1 300 train
+ezrsfdsuzr 1 300 train
+ezsbqfrcfa 1 300 train
+ezsdqantct 1 301 val
+ezsfifpetq 1 300 train
+ezshcaeksv 1 300 test
+ezszzxfrnq 1 300 train
+eztgdxslyf 1 300 train
+eztkfvorxo 1 300 train
+eztmajnsww 1 300 train
+eztofjdvsk 1 300 val
+eztwadaxde 0 300 train
+eztycfwfpz 1 299 train
+ezuckynksv 1 241 train
+ezufneaopl 1 300 train
+ezuftudsoa 0 301 train
+ezukmjfkvk 1 240 val
+ezupajzwdl 1 300 train
+ezupovqlhq 1 300 train
+ezuybqdieq 1 300 train
+ezuyqnjbwb 0 300 val
+ezuywsbnot 1 300 val
+ezvetrxlyz 1 301 val
+ezvigiskgn 1 300 train
+ezvpacuegj 0 301 train
+ezvqjcunnf 1 300 train
+ezvsimvagj 1 300 train
+ezvxqunobu 0 302 val
+ezwbapbpgw 1 300 train
+ezwdgnnhpm 1 300 train
+ezwftndahz 1 300 train
+ezwgqwfpyb 1 301 train
+ezwhkfivwc 0 300 val
+ezwjisband 1 300 train
+ezwqacetdx 1 300 train
+ezwswnpxgw 1 300 train
+ezwvaxplvk 1 300 train
+ezwzpfbrbc 1 300 train
+ezxbjoamxn 1 300 train
+ezxfbqmcko 1 300 train
+ezxfriiglr 1 300 train
+ezxjmgjnyz 1 300 val
+ezxkqqqeqn 1 300 train
+ezxmwlkdpq 1 300 train
+ezxnapocrl 1 300 train
+ezxnuipsgv 0 300 val
+ezxoxejssq 1 300 train
+ezxqjislaz 1 300 train
+ezxtrbzwhy 1 300 train
+ezxxzybbmb 0 301 train
+ezygtbroex 1 299 test
+ezyjpzfnxs 1 300 train
+ezymytowow 1 300 val
+ezynsuipwe 0 300 train
+ezynyiyewj 1 299 test
+ezyttpijys 1 300 train
+ezyvtrufqa 1 300 train
+ezyvyqvjxv 1 298 train
+ezyxytrayc 1 300 train
+ezzdvvpsrf 1 298 train
+ezzfdnllnp 1 300 val
+ezzsovfefo 1 300 train
+ezzxtovqvz 1 300 train
+faaafavxjo 0 300 train
+faaezphusq 1 300 train
+faahcrxltm 1 300 val
+faalgsowou 1 300 train
+faaqmjvali 0 300 train
+faawhwkykm 1 300 val
+fabbbvrkoi 1 300 val
+fabfbolhsn 0 300 train
+fabkhaooks 1 300 train
+fabnzwzwjd 1 300 train
+fabohkfgls 1 300 train
+fabpyzwktz 1 300 train
+fabtrqmrnl 1 300 train
+faccdcgtov 1 300 train
+facfirssno 1 300 train
+fachvpmjpg 1 300 train
+facimhnjmp 1 300 val
+facjaxvaym 1 300 train
+fackiyrkuz 1 300 train
+factpeezlu 1 300 train
+fadcaxaafk 0 300 train
+fadljknvrx 1 300 val
+fadvmubkho 1 300 train
+faekcbqpjn 1 298 train
+faelhvqael 1 299 test
+faemrxtwui 1 300 train
+faeofakexb 1 298 val
+faerpdjach 1 298 train
+faeusxtffd 1 300 test
+faevxxupes 0 300 val
+faeyfjgska 1 300 train
+fafcskrdck 0 300 val
+fafcvcvjlb 0 300 train
+fafelguets 0 300 val
+fafihcaagb 1 300 train
+faflnbhjej 1 300 train
+fafoyorfuc 1 241 train
+fafwmepiyo 1 301 val
+fagdrfcvcf 1 300 val
+faghliyxaa 1 300 train
+fagirlfirv 1 300 train
+fagnwmedog 0 300 train
+fagrxzclau 0 300 train
+fagshunkcm 1 300 train
+fahafldpeb 1 300 val
+fahbidqhcx 1 298 train
+fahbllbagg 1 300 val
+fahevlhtcx 1 300 train
+fahnvsfiwj 1 300 val
+fahpamrpfy 1 298 train
+fahrejqccb 1 300 test
+fahsdxdkqd 0 299 train
+fahvfuqcgm 1 300 train
+fahykeifgz 1 300 train
+faicwfivhj 1 300 train
+faiekhdqyj 1 300 train
+faikkamrdw 1 300 train
+faiovubukn 1 300 train
+fajzlernli 1 300 train
+fakbxbxxjy 0 300 train
+fakcmcbsax 1 299 test
+fakfkpzenm 0 300 train
+fakhglygte 1 300 train
+fakiuygxwr 1 300 train
+faklcbjoln 1 300 train
+fakojkvxrs 1 300 train
+fakpmrnicc 1 300 val
+fakquybnpz 1 300 train
+faksjwyfvd 1 300 val
+faksztjsrs 1 299 test
+faktmhmtpb 1 300 test
+fakuegymft 1 300 train
+fakxwnyyql 1 300 val
+fakycyhozw 1 300 train
+faldrzrfbs 1 300 train
+falfxrjier 1 300 train
+falmtukzra 0 300 train
+falquxjgcs 1 300 train
+falturjtfd 1 300 train
+falukrvbhd 1 300 train
+famavifufv 0 300 train
+famcnvqqjv 1 300 train
+fameihlzjs 1 300 train
+faminorqkh 1 300 train
+famlupsgqm 1 299 test
+fammwnwkzf 1 301 train
+fampmuboxd 1 298 train
+famvrdotln 1 300 test
+famywizotu 1 300 train
+fancmuflyb 1 300 train
+fandwknulr 1 300 train
+fanejhouma 0 300 val
+fangjhyrzp 0 300 train
+fanibwbmoq 0 300 train
+fanitsglzw 1 300 train
+fanoszyrtu 1 300 train
+fanyxvplqo 1 300 train
+faorqeihgj 1 300 val
+faotvkexqf 1 300 val
+faozenvekq 1 300 train
+fapaemphqa 1 300 val
+fapagysonw 1 299 train
+fapazklyby 1 300 train
+fapgixhfen 1 300 train
+faphmeklyl 1 300 train
+fapkfiroqk 0 300 train
+fapkgynpfm 1 301 val
+fapkhkflmj 1 300 val
+faplmdxkih 1 301 train
+fapmcxyhqb 1 299 test
+fapqblvnqm 1 298 train
+fapupenfkl 0 300 val
+faqdzzhdfy 0 300 val
+faqiazrleg 1 300 train
+faqniwwbxq 1 300 train
+faqrazwymc 0 300 train
+faqwyeyoov 1 300 train
+faqxpylsmo 1 301 train
+farcrqxsmy 1 300 train
+fardukltij 1 300 train
+fargvrswxy 1 300 val
+farkayufbk 1 300 train
+farmqijdbu 1 300 val
+farnifosze 1 301 train
+farrazrwmt 0 301 val
+farryjtkwj 1 300 train
+fartqjaomm 0 300 train
+farwsuljug 1 300 train
+farwsvxszh 1 300 val
+fascxfrbis 1 300 train
+fasdqgldov 1 300 train
+fashimyayn 1 300 train
+faslgdifiu 0 300 train
+faspiqgzpe 1 301 val
+fasqzvoqts 1 300 train
+fassenuwad 1 300 train
+fastqxetbh 1 300 train
+fasuaiwqpu 1 300 train
+fasyguwpmg 1 300 train
+faszsqdqgn 1 300 val
+fatdwdeqxo 1 296 val
+fatmrkisny 1 300 train
+fatnoezenh 1 300 train
+fatuzsieeq 1 300 train
+fauflvnbwe 1 300 train
+fauqtiiztx 1 300 train
+fauqucwxfy 1 300 val
+fauqvwjfbq 1 300 train
+fauriemkfh 1 300 train
+faurwndulk 1 300 train
+fauuqsuqba 1 300 val
+fauvmbfyay 1 300 train
+favdukodsi 1 300 train
+favgnxwjss 1 300 train
+favgzqwrxr 1 300 train
+favhbthoqd 1 300 train
+favklanlaa 1 300 train
+favpbouums 1 300 train
+favrjgshqi 0 300 train
+favwudatxe 1 300 train
+favxtlylhy 1 300 train
+favydhlbyj 1 300 train
+faweophskp 1 300 val
+fawexlolyw 1 300 train
+fawjkzmzru 1 300 val
+fawmsvelfp 1 301 train
+fawunmoagt 0 300 train
+fawuvanlzn 1 300 train
+fawvzkfqud 1 301 val
+fawxgykmwi 0 300 val
+fawxhslsws 1 300 train
+faxcktvqyx 1 300 train
+faxcxrdkvg 1 301 val
+faxfqltkyl 0 299 train
+faxpraxrgg 1 300 train
+fayehgbfon 1 300 train
+fayetmfgru 1 300 train
+faygjfrrcq 0 300 train
+faypwmtdre 1 301 train
+fayuakomer 1 300 train
+fayxrjrdiy 1 300 train
+fazkvrvuzb 0 300 train
+fazmpvrveo 1 300 val
+fazmumfdzy 1 300 val
+fazoeausgp 1 300 train
+fazsermqum 1 300 train
+fazvawknmy 1 300 train
+fazxlgrnot 1 300 train
+fbahdmxoed 0 300 train
+fbajsjwfpe 1 300 train
+fbakjsnwxw 1 300 train
+fbamquqxcp 1 300 train
+fbaowuyagg 1 301 train
+fbapkhasfm 0 300 val
+fbapokghgg 1 300 val
+fbauuanxsc 1 300 train
+fbbautdoxl 1 300 train
+fbbeavdmkg 1 298 train
+fbbhafddsv 1 300 train
+fbbhzabvxd 1 300 train
+fbbjoslxdy 1 241 train
+fbbmsckgkj 1 300 train
+fbbozgloqv 1 300 val
+fbbpclizuw 1 300 test
+fbbsooyrla 1 301 train
+fbbtlcjktz 1 300 train
+fbbzakoayb 1 301 val
+fbbznhqnqv 1 300 val
+fbbzqxewah 1 300 train
+fbcdrnxhcx 0 300 train
+fbceopxnsg 1 300 train
+fbcewqjjmd 1 298 train
+fbchvvfwdo 1 300 train
+fbcoiidqdd 1 300 train
+fbcoqrklhy 0 300 train
+fbcqbodjsl 1 300 train
+fbcsuhiwzl 1 300 val
+fbctblabfx 1 300 train
+fbcuuaaxht 1 300 train
+fbdhbgrbok 1 300 train
+fbdorsyrek 1 300 val
+fbdtonudir 1 300 train
+fbdxdwvlyo 1 300 val
+fbdxjscbzc 1 300 train
+fbdyzabvvo 1 300 train
+fbdzfxddvk 1 300 train
+fbearagryu 0 300 val
+fbebxxmltk 1 300 train
+fbecriyqzn 1 300 val
+fbenvdzzqa 1 239 val
+fbeqqyemsi 1 300 train
+fbfdfnfyak 1 300 train
+fbfekhaqzz 1 298 train
+fbffimwgfz 1 300 train
+fbflejhfpn 1 300 train
+fbfnlcqjjp 0 300 train
+fbfnpeldsc 1 300 train
+fbfqbyappj 1 300 train
+fbfxiwunri 1 300 train
+fbfxmcwltv 1 300 train
+fbgcnpdpnx 1 301 train
+fbgenqpkml 1 300 train
+fbgfjwjrzl 1 300 test
+fbgkohkzot 1 300 train
+fbgoflbkwh 1 300 val
+fbgqxuhxuh 1 300 val
+fbgsueqwxv 1 301 train
+fbhopsqopt 1 298 train
+fbhtlcpupl 1 298 train
+fbhtujxyid 0 300 train
+fbhubzyijg 1 300 train
+fbibpnbjox 1 300 train
+fbibslklnz 1 300 train
+fbibtubooo 1 300 val
+fbicfztldi 0 300 val
+fbifigmjzk 1 300 train
+fbjdjgthyh 1 300 train
+fbjhccxgyk 1 300 val
+fbjnzbfwht 1 300 train
+fbjooyptdx 1 300 train
+fbjrcftzrn 1 302 train
+fbjvfhavhj 1 300 train
+fbkepsruif 1 301 train
+fbkfmzjyey 1 300 train
+fbkmcokyez 1 300 val
+fbkpnjqfik 0 300 train
+fbkrqpavor 1 300 train
+fbkuudyidd 1 300 train
+fbkwkupxuj 1 300 train
+fbkygfkzyc 1 300 train
+fbkzwjcuxm 1 300 train
+fblcxngbtt 1 300 train
+fblimgipds 1 300 train
+fblnluweun 1 300 train
+fblnmqspuk 1 300 val
+fblpslxkmm 0 300 train
+fblpvqwcev 1 300 train
+fblquxtnmf 1 300 train
+fblueumsov 1 300 train
+fblvemeaej 1 300 train
+fblxrrmshm 1 301 train
+fblyakialo 1 300 train
+fblzgeagoh 1 300 val
+fbmbhjzgie 0 300 train
+fbmgagtuok 1 298 train
+fbmgyohfba 1 301 train
+fbmkxtuxdp 1 241 train
+fbmvpgheih 1 298 train
+fbmvygkkkt 0 301 train
+fbnbxidkju 1 301 train
+fbnenzaroc 1 300 train
+fbnnthkegg 1 299 test
+fbnrgkqszs 1 300 train
+fbnspyoplp 1 300 train
+fbnveezzal 1 300 train
+fboldtukcp 1 299 test
+fborahodiq 1 300 train
+fbosopvlqz 1 300 train
+fbowvghdfk 1 241 train
+fboxwyhacn 1 301 val
+fbpdookvah 1 300 val
+fbpebbuslu 1 300 train
+fbpgbovvxj 1 300 val
+fbplhwdvuy 1 300 train
+fbpmpbqcxf 1 300 val
+fbpnwtilgt 1 300 train
+fbpsnyylei 1 300 train
+fbpvuumpfi 1 300 val
+fbqbkecquv 1 300 train
+fbqfpbsukz 1 300 val
+fbqivaozzf 0 300 train
+fbqjnnllgg 1 300 train
+fbqjyxiwgc 0 300 train
+fbqmpjccpr 1 300 train
+fbqnobjdip 1 300 train
+fbqrdsclny 0 300 train
+fbqwjykwzq 1 300 train
+fbqwomdehr 1 300 train
+fbqzjrziud 0 298 train
+fbrbvpcwms 1 300 val
+fbrhorisro 1 299 test
+fbrnfldzje 1 300 train
+fbrnkwsgrh 0 300 train
+fbrnzgbdpp 1 298 val
+fbrofxhjxf 0 300 train
+fbrqjqnwza 1 300 train
+fbrvapcfwg 1 241 train
+fbrykfxtwn 0 300 train
+fbsldmczss 1 300 train
+fbslmgbypq 0 300 train
+fbsttogvjx 1 300 val
+fbswlqshag 1 300 train
+fbsxrqasbn 1 300 val
+fbtesfdoym 1 302 train
+fbtgrsrrjd 1 300 train
+fbtgsjghee 1 300 val
+fbtrkpxuql 1 300 train
+fbtskywfjv 1 298 val
+fbuewievpd 1 300 train
+fbujdvlmgh 1 300 train
+fbujpbnkys 1 300 train
+fbuqknpnpx 0 300 train
+fbutyqvklp 1 300 val
+fbvpggjebl 1 300 train
+fbvsoozixq 1 300 train
+fbvvheoquw 0 300 train
+fbwamgqruq 1 300 train
+fbwfpmbwin 1 300 val
+fbwgwhlimc 1 300 train
+fbwmqvjttx 1 300 val
+fbwmqzhghn 1 300 val
+fbwqyckgwc 1 300 train
+fbxaamoucp 1 300 train
+fbxgytacoa 1 300 train
+fbxlqxlcqa 1 300 val
+fbxnmuhsum 0 300 train
+fbxpssbrqp 1 300 train
+fbxsmxkslz 1 300 train
+fbxycbrpnd 1 300 val
+fbxzlwejjw 1 300 train
+fbybejwonv 1 300 train
+fbycgvmaaq 0 300 train
+fbydtaqhbr 1 300 train
+fbyetasxrt 1 300 train
+fbygkhmiev 1 300 train
+fbyicumqml 1 298 val
+fbykdbonvn 1 300 train
+fbylaezydp 1 300 train
+fbyqfeausr 1 300 val
+fbyvelgjbg 1 300 train
+fbyxcxtpsw 0 300 train
+fbzamdxgjw 1 300 train
+fbzaptcqjy 1 298 train
+fbzclcxmxh 1 300 train
+fbznxvewma 1 300 train
+fbzpezjuac 1 300 train
+fbzsiuxipz 1 297 train
+fbzvbtnwuo 1 300 train
+fbzvnwpxfg 1 300 train
+fbzyimzylr 1 300 test
+fbzztilvpn 0 300 train
+fcaadsjjdt 1 300 val
+fcacovhtqc 1 300 train
+fcagoxvfam 1 300 train
+fcaigwoatg 1 300 train
+fcaolwaaly 1 288 train
+fcawschzhs 1 300 train
+fcbcugpyqb 1 300 train
+fcbgbioqqc 1 300 train
+fcbgcmzvgo 1 167 train
+fcbgvoyrrr 1 301 val
+fcbnmtrpqo 1 300 train
+fcbrsmceku 1 300 train
+fcbwiaddld 1 300 train
+fcbyocpvdq 1 297 val
+fcbzbbywul 1 300 train
+fccckpnmdn 1 299 val
+fccfjczqgy 1 300 train
+fccjcpxyew 1 300 train
+fcckanhaqo 1 300 train
+fccofumcjd 1 300 train
+fcczfousea 1 300 val
+fcdbfpikjx 1 300 train
+fcdlkuwhgc 0 300 train
+fcdndpddtw 1 299 test
+fcdocjxnug 1 300 train
+fcdocliqlm 1 300 train
+fcdrjqqxyt 1 300 train
+fcdrtksewi 1 298 train
+fcduluogax 1 300 train
+fcduuskckq 1 300 train
+fcdwmtqhzb 1 299 test
+fcdwzdqasp 1 300 val
+fceaefbruz 1 300 train
+fcefhlbnwe 1 300 train
+fceobmlgdo 1 301 train
+fceptuklfo 1 300 train
+fcevnejpix 1 292 train
+fcevppjtel 0 300 train
+fcevrzjfga 1 301 val
+fcewkvlkcl 1 298 train
+fcfeysnrax 1 288 train
+fcfjmblrmj 0 300 train
+fcfuyeauun 1 300 val
+fcfwzjbllp 0 300 train
+fcfxpmvpoq 1 300 train
+fcfzhkvqqr 1 301 val
+fcfzruaoum 1 297 train
+fcgdkbrhob 1 300 train
+fcgdrvwpgy 1 300 val
+fcgidbpuod 1 298 train
+fcgqfebndj 1 298 val
+fcgsaskflq 0 300 train
+fcgttspyiy 1 300 val
+fcgvvxpnyi 1 300 train
+fcgyfjftdx 1 300 train
+fcgyywhfwn 1 300 train
+fcgzegqfhu 1 300 train
+fchawobtti 0 300 train
+fchfxbjlmu 1 300 train
+fchhwtwkve 1 301 val
+fchipwcorl 1 299 val
+fchjvswlgv 1 241 train
+fchlrzdlwd 1 300 train
+fchpilzgfl 0 300 train
+fchswmskuw 1 300 train
+fchulhsiot 1 300 train
+fchyqiaoeo 1 301 train
+fcilbpaazn 1 300 train
+fcirooygfa 1 298 train
+fciyutvfpy 1 300 train
+fcjcpqsqdl 1 300 train
+fcjehpxwlo 1 300 train
+fcjepqgfts 1 300 train
+fcjgetycim 1 300 train
+fcjossnylc 0 300 train
+fcjrqmqheq 1 300 train
+fcjujaxmot 1 300 val
+fcjujjnmze 0 300 train
+fckedzldka 1 300 train
+fckfmeondr 1 301 val
+fckhrlmdps 1 300 train
+fckrovmlsc 1 300 test
+fckxaqjbxk 1 300 test
+fckyqnljcw 1 300 train
+fclalhzuqn 1 300 train
+fclarssgkh 1 300 train
+fclbpdxgxz 1 300 train
+fclfsmueha 0 298 train
+fclghwxfyv 0 300 val
+fcliwhvitf 1 300 val
+fcljxxkszr 1 288 train
+fclnkaotuf 0 300 val
+fclnvgwhqj 0 300 val
+fclpgzvmly 1 300 train
+fclzoebmof 1 300 train
+fcmbekeioj 0 301 val
+fcmdzspgeh 1 300 train
+fcmedjqlgr 1 300 train
+fcmexsbxbl 1 300 train
+fcmgqxpbqd 1 300 train
+fcmkwqjgcf 0 300 train
+fcmukpflxo 1 300 train
+fcmvdopkgg 1 300 train
+fcmymgffth 1 300 train
+fcnfgrkpes 1 300 train
+fcniblddhn 0 301 train
+fcnjtawqvj 1 300 train
+fcnosnknhr 1 300 train
+fcnrttrfjd 1 300 train
+fcnvslbvkp 1 300 train
+fcobxpplyh 1 300 train
+fcocsuznuz 1 300 train
+fcoldanlue 1 300 train
+fcoosmczka 1 300 train
+fcoqyyvcti 1 299 val
+fcowmxflnx 1 300 train
+fcpclqvwdg 1 300 val
+fcpjjajbrs 1 300 train
+fcqfismapb 1 300 val
+fcqgzoqwnq 0 300 train
+fcqkakrkkt 1 300 val
+fcqoeufwso 0 300 train
+fcqojlmizi 0 300 val
+fcqotwdluv 1 300 val
+fcraobpsak 1 300 train
+fcrhnotouh 0 300 train
+fcrlgyekpl 1 300 train
+fcroeeiwbw 0 300 val
+fcrtopoper 1 300 train
+fcrwgettrv 1 300 train
+fcrxcdkkov 1 300 train
+fcryjdfhxr 1 303 train
+fcsepdmclv 1 300 val
+fcsldkukwf 1 299 train
+fcstaiungc 1 300 train
+fctkybwdqr 1 300 train
+fctplmadle 1 300 val
+fctpzcfrmj 1 300 train
+fctupjcqsd 1 300 train
+fctxslfxsw 1 300 train
+fctxyczvjr 1 300 train
+fctygtzbzq 1 300 train
+fctyywfhmh 1 300 val
+fcubvqwhzp 1 302 val
+fcujmrcwbl 1 299 test
+fcukkebcyx 1 300 val
+fcumybzljl 1 300 val
+fcussypxwn 1 300 val
+fcutdxywbw 1 300 train
+fcvalghdjp 1 300 train
+fcvcuxtryi 1 301 train
+fcviwujukb 1 300 train
+fcvrahqypw 1 300 train
+fcvzlzfufb 0 300 train
+fcwarehzgq 1 300 train
+fcwbweeosj 1 300 train
+fcwgjggqub 1 300 train
+fcwisgaaro 1 300 train
+fcwrhhfado 1 300 train
+fcwyjzxkmh 1 300 train
+fcwytrceol 1 298 train
+fcxentjmzf 0 300 train
+fcxharlrvl 1 300 train
+fcxvfkofed 1 300 train
+fcxwsymvhc 0 300 train
+fcyedxtdbz 1 301 train
+fcyhcmbvis 1 300 val
+fcylgaelfy 0 301 val
+fcymzjbwrl 1 300 val
+fcyqqaxuig 1 300 train
+fcytwslmhe 1 300 train
+fcyzsnnext 1 300 train
+fczdtpcgmo 1 300 train
+fczgcqffgg 1 300 train
+fczgjceyjq 0 301 val
+fczhbwfxuw 1 300 train
+fczmlponul 0 300 train
+fczrttsakk 0 300 train
+fczsyqgorg 1 300 train
+fczvffyrza 1 300 train
+fczvijpxim 1 300 train
+fczvlbhexk 1 300 train
+fdaalnmkoa 1 300 train
+fdabxzcain 1 300 train
+fdadegpuar 1 300 train
+fdadpyzrgm 1 300 test
+fdahznhdjf 0 300 train
+fdaotijrwl 1 300 train
+fdapjswpio 0 300 train
+fdatpcccjf 1 300 val
+fdaxsptshk 1 300 train
+fdazieinpw 1 300 train
+fdbctkufii 1 300 train
+fdbmplikfr 1 301 train
+fdbmvivkyk 1 298 train
+fdbuudgvxk 1 300 train
+fdcleekthx 0 300 train
+fdcttsvjwf 0 300 train
+fdcvshmfkh 1 300 val
+fdcwmgxxed 1 300 train
+fdczuwyugc 1 300 train
+fddawzxdkg 0 301 val
+fdddiyrnzi 1 300 train
+fddjyuntaw 1 300 train
+fddmkqjwsh 1 299 test
+fddrxswphy 1 298 val
+fdegsncecf 1 300 val
+fdehcexxls 1 300 train
+fdetglsgfm 1 297 val
+fdezrogbya 1 300 train
+fdfcclojex 1 300 val
+fdfegcnvaj 1 300 train
+fdfetybveh 1 300 train
+fdffsphdrs 1 300 train
+fdfjurhwvi 1 300 train
+fdfjzuptcp 1 300 val
+fdfkccudyt 1 299 val
+fdfkgybqpx 1 300 train
+fdfncdwcsp 1 300 train
+fdfppcyhkc 0 300 train
+fdfqdxxpkc 1 300 train
+fdfqweaety 1 300 val
+fdfsgjhzlc 1 300 val
+fdfstbxbjh 1 300 train
+fdfvdggoft 1 301 val
+fdfyrgbtln 0 300 val
+fdgbgxddbt 0 300 val
+fdgfkiwfqe 1 300 train
+fdgjxunkbg 1 300 train
+fdgotycxcs 1 300 train
+fdgyspoimg 1 300 train
+fdhcjnyhec 1 299 test
+fdhmvpdhmg 1 299 train
+fdhorbtgca 1 300 train
+fdhqqrvhzl 1 300 train
+fdiaydvtjh 0 300 val
+fdibsyxhwu 1 300 train
+fdicjoommm 1 300 train
+fdiiiafqra 1 300 val
+fdikickhgw 1 300 train
+fdipsrizhu 0 300 train
+fdirkafogc 1 300 train
+fdisgqcvpz 1 300 train
+fdiwpxbqcz 1 300 train
+fdjbeckyom 1 297 train
+fdjgqumnut 0 300 train
+fdjiqfnirg 1 300 train
+fdjpuhkkln 1 300 train
+fdjwbrgbty 0 300 train
+fdkbgtnlbe 1 300 val
+fdkbmfdohh 1 299 test
+fdkdgocuvg 1 300 val
+fdkhmdbohv 0 300 val
+fdknmtrfjm 1 300 train
+fdkswhrnvc 0 300 train
+fdktkvlziu 1 300 train
+fdkvragrfd 1 300 val
+fdkxiecbtm 1 298 train
+fdkywoylxe 1 300 train
+fdlbdqhogg 1 300 val
+fdlcvmsniy 1 300 train
+fdlgwivmdw 1 300 train
+fdljwgcbvb 1 301 train
+fdlkxokcbp 1 300 train
+fdlrrbroar 0 300 val
+fdlxbqbjxm 1 300 train
+fdlxgbecze 1 143 train
+fdmfxcherk 1 300 train
+fdmkdahhwb 1 300 train
+fdmrglkfwv 0 300 train
+fdmroaidaj 1 300 train
+fdmsyypemb 0 300 train
+fdnhekmnpo 1 300 train
+fdnjuwypav 1 300 train
+fdnqcgfvvc 1 240 train
+fdnrhgictd 1 300 train
+fdnvmmoobs 1 300 train
+fdoepayshg 1 300 train
+fdofzggxpm 1 300 train
+fdogmnyird 1 300 train
+fdojxrqymz 1 300 val
+fdooucyjuw 1 300 train
+fdoxhvqlcu 1 301 train
+fdozjrmuve 1 301 train
+fdpifawluk 1 300 train
+fdpisghkmd 0 300 test
+fdpkflecgj 1 300 train
+fdpkzvpxwx 1 300 train
+fdpmnucvqi 1 300 train
+fdppujxagz 1 300 train
+fdpwifnlrq 0 300 train
+fdpwwnnysy 1 300 val
+fdpwzxcfip 1 300 train
+fdpylgdwgw 1 300 train
+fdqafjiqtn 1 300 test
+fdqbhbyrwb 1 300 val
+fdqfqujbqh 1 241 train
+fdqgmsavmb 1 300 train
+fdqimaerdp 1 300 train
+fdqqpxjizi 0 300 train
+fdqqzjrcqb 1 300 test
+fdqufblmbe 1 300 train
+fdqvegjsrd 1 300 train
+fdqzjdfeca 1 300 train
+fdrcqxzpmc 1 301 train
+fdrdjuthgu 1 300 train
+fdrexwzmkw 1 300 train
+fdrgvkzfmg 1 300 val
+fdrizqnsqt 1 300 train
+fdrkrjsmog 1 300 train
+fdroxpavml 1 300 train
+fdrqxbnbft 1 292 val
+fdrrchsbbc 0 298 train
+fdrskvltor 1 300 train
+fdrxzssujf 0 300 val
+fdrypswqbu 1 300 train
+fdsjhzdhxn 0 298 train
+fdsmdjjhrs 1 299 val
+fdstzkwgrw 1 300 train
+fdsvmrrfjd 1 300 train
+fdszggpuih 1 300 val
+fdtgsfrfdq 1 249 train
+fdtmtbbbab 0 300 train
+fdtynawrpy 0 300 train
+fdubcqyphb 0 300 train
+fdueszucxw 1 300 train
+fduexmmqer 1 300 train
+fdugrxkvap 1 300 train
+fduhwlydlg 0 300 val
+fdumtjobph 1 300 train
+fduqklszee 0 302 train
+fduqoqqsuk 1 301 val
+fdurwujpok 1 300 train
+fduzwmyecl 1 300 train
+fdvaeieddq 1 300 train
+fdvbsmpmge 0 300 train
+fdvcwbsuru 1 300 val
+fdvgiqipzx 1 301 train
+fdwarafeig 1 299 train
+fdwasprcjd 1 300 train
+fdwghvaliw 1 300 train
+fdwjjxvxlu 0 300 train
+fdwkvtbvxz 1 300 train
+fdwswcptlx 1 300 train
+fdwtuppdmr 1 300 train
+fdxeaxhnxh 1 300 train
+fdxnlcyvcl 1 300 train
+fdxogdfyjx 1 300 train
+fdxszaqwde 1 300 train
+fdxvlxsuxv 1 300 train
+fdybrzvqak 1 298 train
+fdygrcsbnx 1 300 val
+fdyzixbbni 1 300 test
+fdzbfjfptb 0 300 val
+fdzbpqfcwl 1 300 train
+fdzexbsksd 0 300 train
+fdzgqqpqua 1 300 train
+fdziwiuoer 1 300 val
+fdzpamgmee 1 300 val
+fdzrcjpewd 1 300 test
+fdzrqygbuc 1 300 val
+fdzwvbtrwl 0 300 train
+fealxekjms 1 298 train
+feaqnlczwc 1 300 train
+feaqorbkar 1 299 test
+feavavojfn 1 241 train
+feayjwkppw 1 300 val
+feazhvejib 1 301 train
+febszsogxt 0 300 train
+febvxdmywc 1 300 train
+febzvsibjn 1 300 train
+fecaapkwdm 1 300 test
+feccjjbhbf 1 300 val
+feclrivjqi 1 300 train
+fecnpaovgx 1 302 train
+fecomunsht 1 300 train
+fecrkedono 1 300 train
+feculiepto 1 300 train
+fecysfujzk 0 300 train
+fedagjfkfa 1 300 train
+fedbbtejfu 1 300 train
+fedcdqtboz 1 300 test
+fedciltgry 0 300 val
+fedelidbyz 1 300 train
+fedenklvlr 1 300 val
+fedgbjseqo 1 296 train
+fedhtuplyv 0 300 val
+fednyefrrm 1 300 train
+fedwunxqdb 1 300 train
+feeaepqihl 0 301 val
+feejfxvlfs 1 300 val
+feelawyelb 1 300 train
+feerhqvmfs 1 300 train
+feeyruwecl 1 300 train
+feezgloowv 1 300 train
+feezoheuju 1 301 val
+feezzruhzh 1 300 train
+feffcgjgww 1 300 test
+feftucmlwa 1 300 train
+fefyerbfpi 1 301 val
+fefytxclbx 1 300 train
+fefzhybovf 1 300 val
+fegfqcpnlw 1 300 val
+fegsghuyhw 1 300 train
+fegzxtygou 1 298 train
+fehfopvrxj 1 301 train
+fehsidvxnq 1 300 train
+fehvqagskg 1 299 val
+fehyoxtiwl 1 299 test
+feicjilwfi 0 300 train
+feidnmwzqw 1 302 train
+feihhdwmcu 0 300 train
+feiiyklsup 1 241 train
+feikotbhhf 0 301 train
+fejacnpjzo 1 300 train
+fejbmkfnpu 1 300 train
+fejjwuoosa 0 300 val
+fejoztpznc 1 300 train
+fekazhlpdr 1 300 train
+fekbyyzjxi 1 300 train
+fekcdrwojq 1 300 train
+fekdyrzfda 1 301 train
+fekecdkzfx 1 300 train
+fekfqkxcmg 1 300 train
+fekgecddba 0 300 train
+feklsyhydc 1 300 train
+fektpafggz 1 300 train
+fekttfvyio 1 300 train
+fekufemysq 1 300 train
+felvphspwq 1 300 train
+felyhnwexr 1 300 val
+felyqpstsc 1 298 train
+femcbddhuq 1 300 train
+femcomojjl 1 300 train
+femoixxyrz 1 297 train
+femsamhngx 1 297 train
+femslxrqzs 1 300 train
+femupkjzdk 1 300 train
+fenkagfgpz 1 300 train
+fenlzanzsu 1 300 val
+fenqbpkwak 1 300 train
+fenvutkjgf 1 300 train
+feobxzcjml 1 240 train
+feocfndoxy 1 300 train
+feogyoaehk 1 299 train
+feomtvzchx 1 241 train
+feotkojcfj 1 300 train
+feotzeicse 1 300 train
+feouerxuhk 0 300 train
+feouzuufou 1 296 val
+fepcaxmpzk 1 300 train
+fepdwndilf 1 300 train
+fepdyrzwrb 1 300 val
+fepebtknzw 1 298 train
+fepjgkpkva 1 300 val
+fepjnikgvu 0 300 train
+fepjqbsqbk 1 299 test
+fepulzanem 0 300 train
+fepvekjmzw 1 300 val
+fepwisakid 1 300 train
+fepzrvdwje 1 300 train
+feqbzkgihs 0 300 val
+feqerpjhzu 1 300 train
+feqiitiriq 0 300 train
+feqioexjfh 1 99 train
+feqkuzrsja 1 300 train
+feqrqoxiwy 1 300 test
+feqwbyzkht 1 300 train
+feqzsacurr 1 300 train
+ferahsccuy 1 300 train
+fergstpssp 0 300 val
+fermszanqp 1 300 train
+fernwnthuy 1 299 test
+ferpvpdpqs 1 300 train
+fersuzuomu 1 300 train
+ferxzqugjl 1 300 train
+ferymajfia 0 300 train
+fesdfuymuj 1 300 val
+fesdunrsvf 1 300 train
+fesdxiprfd 1 300 val
+fesgdepvwo 1 298 train
+feshilyojm 1 300 train
+fespscbeum 1 300 val
+fessafbqix 1 300 train
+fesszmyykv 1 301 train
+fetaleltae 1 300 train
+fetflabxwm 1 298 train
+fetgpaxuds 1 300 train
+fetqgkizdf 1 300 train
+fetxwjfque 0 300 train
+feuawxyxue 1 300 train
+feubajatmw 0 300 val
+feufaateyo 1 300 train
+feuocwugny 1 300 train
+feurfvmagm 1 300 test
+feutlocdqr 0 300 train
+fevcorrrsa 1 300 train
+feveknbdid 1 300 train
+fevfjccfdv 1 300 train
+feviauguip 1 300 val
+fevomtfshn 0 300 train
+fevtwebqul 1 301 val
+fevurxrrgf 1 300 val
+fewafzzrbb 1 296 val
+fewcljwqkr 0 298 train
+fewcmpwboi 1 300 train
+fewczsiiye 0 301 train
+fewjjgfokg 1 300 train
+fewlcdldng 1 298 train
+fewmhwpftb 0 300 train
+fewszivjon 1 288 train
+fewtbzmmds 1 300 train
+fewvptnlit 1 300 train
+fexafazetd 1 300 val
+fexeboarpp 0 297 train
+fexhvxfiwe 0 300 train
+fexnjmnpoe 1 301 val
+fexocqurcj 1 300 val
+fexpbwredb 1 300 train
+fexpgzacof 1 300 val
+fexsdiriwq 1 301 train
+feydlezwac 1 301 train
+feyilafcbb 1 301 train
+feyoxrvpac 1 301 train
+feywtwtfxr 1 301 val
+fezasvqvsw 1 300 val
+fezbpbvueh 1 300 train
+fezdsrxjuz 1 300 train
+fezfsagvyo 1 300 train
+fezlujuape 1 300 train
+fezpininqy 1 300 val
+fezttluhlf 0 300 train
+fezufqrfpe 1 300 train
+fezxipxwsm 1 300 val
+fezxstjlma 1 300 val
+ffadtqptvw 1 300 train
+ffahlazvmr 1 301 train
+ffamowhlkw 1 300 val
+ffarxjfoal 0 300 train
+ffavdzrmll 1 300 train
+ffavgedkwj 0 300 val
+ffawqkehyb 0 300 val
+ffazxjhwuu 1 301 train
+ffbbbjollg 1 300 val
+ffbcijzdmh 0 300 val
+ffbcwbelsp 1 300 train
+ffbigogpwb 1 300 val
+ffbjlbsudv 1 300 train
+ffbjvdsvto 1 300 train
+ffblorryhi 1 300 train
+ffbssqtpax 1 298 val
+ffbtjneard 0 300 val
+ffbwehugnp 0 300 val
+ffbyxpvsxl 1 300 train
+ffcommhoby 0 300 train
+ffcsioenoe 1 300 val
+ffcwhpnpuw 0 298 train
+ffcxldacyr 1 300 train
+ffczscfkkp 1 301 train
+ffdbabjuix 1 300 val
+ffdcsucfqr 1 240 train
+ffdgyalqxu 1 300 train
+ffecukoyrm 1 300 train
+ffeimzbwnc 1 300 train
+ffeletkydk 1 300 train
+ffeniwxbrt 1 300 train
+ffentyuxzw 1 301 train
+ffeoprynzm 1 301 val
+fferdgkhoh 1 300 train
+fferofffwo 1 300 train
+ffesfxsctu 1 300 train
+ffeteuoqbr 1 300 train
+ffetooseic 1 300 train
+ffeuakygvq 1 300 train
+ffevfcjxva 0 300 val
+fffabxflxz 1 300 train
+fffmstphjp 1 300 val
+fffpfnlwbp 1 300 train
+fffpksykni 1 300 train
+fffpvrhlse 1 300 train
+ffftvvszis 1 299 train
+fffxdvvrgh 0 300 train
+ffgbsunyjw 1 299 train
+ffgjubpsrv 1 298 train
+ffgpwcfvgi 0 300 train
+ffhdgsvsmb 1 300 val
+ffhiapqvzp 1 301 train
+ffhlqnapse 0 301 train
+ffhmmkkmic 1 300 val
+ffhteustqc 1 300 train
+ffhtgvhmzm 1 300 train
+ffhxffomjj 1 298 train
+ffhxvrcxjp 1 300 train
+ffhylwubca 1 300 train
+ffhzeodora 1 300 val
+ffidvaqcfh 1 300 val
+ffikhwxjgm 1 300 train
+ffipepamkk 1 300 train
+ffjdqkgdns 1 300 train
+ffjfdttbzi 1 300 train
+ffjkphlvym 1 300 train
+ffjrlcvmkg 1 300 train
+ffjxmnlppd 1 300 train
+ffjyigbvyj 1 300 train
+ffjyjsdzcx 1 300 train
+ffkaazomkg 1 300 train
+ffkhritile 1 301 train
+ffksuvspdv 1 300 train
+fflfnwokgs 0 300 val
+fflgzydmzd 0 300 train
+fflhlodwnf 1 300 train
+fflibjqolx 1 300 train
+ffliykeruq 1 300 train
+fflogokxxw 1 300 train
+ffloxijuta 0 300 val
+fflspkgjah 1 300 train
+fflvxiuumu 1 300 train
+fflxzfsxzt 1 297 val
+ffmjcwyzij 1 300 val
+ffmlwfcddc 1 300 train
+ffmpcikyaf 1 300 train
+ffmtwqvngl 1 300 train
+ffmyqpdqdb 1 301 train
+ffnaeknjds 1 300 train
+ffnalfhrkl 1 300 train
+ffnbguuvjo 1 300 train
+ffoawjvtvw 1 300 train
+ffoccujyxz 0 300 train
+ffoiobfljf 1 300 train
+ffojvbklfn 1 300 train
+ffolstniaz 1 299 test
+ffotrmvefk 1 300 val
+ffowqiihtn 1 300 val
+ffowuinxte 1 300 val
+ffpdrftlkq 1 300 train
+ffpmxeaahd 1 300 train
+ffptftxttg 1 300 train
+ffpuiuntmp 1 300 train
+ffpwtqfazl 1 300 train
+ffpxoabdgt 1 300 val
+ffqajwukgi 1 300 train
+ffqawznfgz 1 300 train
+ffqdjelclt 1 298 train
+ffqfbvsmkq 1 300 train
+ffqgeykztf 1 298 train
+ffqgsmxvuq 1 300 train
+ffqjujayjr 1 300 train
+ffqmsqrogh 1 300 val
+ffqmymuzyk 1 301 train
+ffqrjoxaxr 1 300 train
+ffqtwsnbjy 1 301 train
+ffqxkomedp 1 300 train
+ffqyvkfady 1 299 val
+ffqztpmqht 0 300 val
+ffrnrbjbzn 0 300 train
+ffscvgescz 1 300 val
+ffsfxbzlwg 0 301 train
+ffsofssjon 1 300 train
+fftbwviyhe 1 300 train
+fftbxfybmf 1 300 val
+fftdqxvpku 1 300 train
+fftfdezrnh 1 300 train
+fftvnmijiv 1 300 train
+fftvqwdmrl 1 300 train
+ffuadtmics 1 300 train
+ffuegayswn 1 300 val
+ffuhlmaxue 1 300 train
+ffulcrvbzg 1 300 train
+ffuniyofza 1 300 train
+ffurgacnqg 1 300 train
+ffvcpukfvb 0 298 train
+ffvgdqjkjb 1 300 test
+ffvgzbyivt 1 300 val
+ffvoqimwmv 1 300 val
+ffvqburvck 1 300 train
+ffvwladfuh 1 300 train
+ffvyaaolvh 1 300 train
+ffwmtxznqn 0 300 val
+ffwpiwqnmf 1 300 train
+ffwqdplgdo 1 300 val
+ffwtqvpsmy 1 301 val
+ffwtxjjwla 1 300 train
+ffwwiszvdg 1 300 train
+ffxanujlwz 1 300 train
+ffxhjizxae 1 300 train
+ffxiutfknw 0 300 train
+ffxvbwbxbp 1 300 train
+ffycdoligw 0 300 train
+ffydzmwyqd 1 300 train
+ffyecxkezb 1 300 train
+ffygnvpvtv 1 300 val
+ffyybaoayj 1 300 train
+ffzcmxlwfs 1 300 train
+ffzcuzxqhz 1 300 train
+ffzeueddpx 1 300 val
+ffztqatacr 1 300 train
+ffzuiawyzm 1 300 train
+ffzyswbaxs 1 300 test
+fgaaxwisyh 1 301 train
+fgabcmasqg 1 300 train
+fgabpxldcq 0 300 train
+fgacgxvlpw 1 300 val
+fgahummvmc 1 300 train
+fgaisnmcyb 1 299 val
+fgakmywupb 1 300 train
+fgasybrtob 0 300 train
+fgaztzxuix 1 300 train
+fgbecskwle 1 300 train
+fgbkbzsxbl 0 300 train
+fgbopxbkam 1 300 test
+fgbppgaruc 1 300 train
+fgcazspzuy 1 300 train
+fgcplwjkwj 1 300 train
+fgcrbinglk 1 300 train
+fgcubmfsqg 1 300 train
+fgcvmubbzp 1 300 train
+fgcxqtibav 0 300 val
+fgcxvhaghq 1 236 train
+fgdcrhhiuq 1 300 val
+fgdhdoqpsf 0 300 train
+fgdiwobasc 1 300 train
+fgdixviiuv 1 300 train
+fgdjprdake 1 300 val
+fgdnwlonbb 1 300 train
+fgdpgztcaw 1 300 train
+fgdriqscyw 1 300 train
+fgdxafrqnv 1 300 train
+fgdyrazuhe 1 300 val
+fgeepyrgsa 1 300 train
+fgejwajwcw 1 300 train
+fgeuhffsss 1 301 train
+fgevjuicdf 1 300 train
+fgexjqzsti 1 300 train
+fgffbvnvxp 1 300 val
+fgfjzwtkcr 1 300 train
+fgfvppjfqp 1 300 train
+fgfyrfyqay 0 300 train
+fggnisskhq 1 300 train
+fggtptqdux 0 300 train
+fggvitjdji 1 300 val
+fggvulrylm 1 300 train
+fggyeqctuq 1 300 train
+fghajiuvet 1 300 train
+fghsaovswi 1 300 train
+fghxjmjfll 1 298 train
+fgicfmosym 1 300 train
+fgidtzzkai 1 241 train
+fgijnlhzhb 1 241 train
+fgirrgiuzr 1 300 val
+fgisnqmnbo 1 300 train
+fgjenewzsg 1 300 train
+fgjrfoujnu 1 300 train
+fgjrzfdagt 1 288 train
+fgjvgzuqgs 1 300 train
+fgkdqdbhvs 1 301 train
+fgkkhtjosp 1 300 val
+fgkmkmyksz 1 300 train
+fgkpembbpv 0 300 train
+fglewmddcn 0 300 test
+fglfkwlujv 0 300 val
+fglguggmiy 0 300 val
+fglhdubwcx 1 301 train
+fgliksrdtq 1 300 train
+fglnopfcok 1 300 train
+fglrfaszey 1 300 train
+fglvqbbayj 1 300 val
+fgmbxfqoze 0 300 train
+fgmdwcinnh 1 300 train
+fgmqrobblg 0 300 val
+fgmvhqzppo 1 300 train
+fgmvujbjhf 1 300 val
+fgmxzkzxhr 1 300 train
+fgncxmkchi 1 300 train
+fgnfghzzas 1 300 val
+fgnkzpemeh 0 300 train
+fgnmillpcj 1 300 val
+fgnnpqhxrw 1 300 train
+fgnofuaqga 1 300 train
+fgnpzadtfr 1 301 val
+fgnqqvtadb 1 300 train
+fgnqrrlhkp 1 300 train
+fgnzyumqrp 1 298 train
+fgoarsegvt 1 300 train
+fgobmbcami 0 300 val
+fgophendij 1 300 train
+fgoriveyxg 1 300 val
+fgoxamoelu 1 300 val
+fgpcrccxqp 1 300 train
+fgpfxeovsh 0 300 train
+fgpjczpejr 1 300 val
+fgplkrwnhb 1 300 train
+fgpomttfog 1 136 train
+fgpozagjpl 1 300 train
+fgqggvltzv 1 298 train
+fgqmmehmev 1 300 train
+fgqpfxmlir 1 300 train
+fgqwibrpov 1 301 val
+fgrahniqqd 1 300 test
+fgrbojptfu 1 300 train
+fgrfpbvrkv 1 300 train
+fgrgyxhmzk 1 300 val
+fgrhiqjubm 1 301 val
+fgrhwcmitk 1 300 train
+fgrikchqsu 1 300 val
+fgrnwqhoan 1 302 val
+fgrxdtkqod 1 300 val
+fgrxodoqcr 0 300 val
+fgsjbkxyjk 1 300 train
+fgskskhusk 0 300 val
+fgsmxpynej 1 300 train
+fgsnybuaan 1 300 train
+fgsqfprawu 1 300 val
+fgstwpulgx 1 300 train
+fgsulgqrgk 1 300 val
+fgsvnldzdx 1 300 train
+fgtdbexjtp 1 300 train
+fgtggqkggf 1 301 val
+fgtlivalil 1 300 train
+fgtpeerbfc 1 300 train
+fgtpkjnclo 1 300 train
+fguaqrbrpb 1 299 train
+fgueschpvr 1 300 train
+fguilxszjy 0 300 train
+fgukbdlwga 1 300 train
+fgulametef 1 300 train
+fgutlhwbua 1 300 train
+fgvcymtolf 1 300 val
+fgvfeubemr 1 300 train
+fgvimhagof 1 300 train
+fgvolxxsnq 1 300 val
+fgvpqpxkot 1 300 train
+fgvrxztroo 1 300 val
+fgvsewxvus 1 301 train
+fgvvgcdflc 1 300 train
+fgwhvbmraa 1 300 train
+fgwiypyxom 1 299 test
+fgwnqpoakk 1 300 train
+fgwovturvz 1 296 train
+fgwsgolela 1 299 val
+fgwujwtmcx 1 300 train
+fgwuliztyh 1 300 train
+fgwvkypthm 1 300 train
+fgwxkmbrfn 1 300 val
+fgxifjoeab 1 300 train
+fgxigrpxjt 1 300 train
+fgxiiptgcn 1 300 train
+fgxotqcyqh 0 300 train
+fgxpkasbaq 0 300 train
+fgxxqsfbcv 1 300 train
+fgycqbfjdl 1 300 train
+fgydlejwbw 1 300 train
+fgyjlqhugm 1 300 val
+fgyjsfkyid 1 300 val
+fgynouuarj 1 300 train
+fgyohrsldo 1 300 train
+fgyrmqarez 0 300 train
+fgysdsfehq 0 301 train
+fgysfjixxh 1 300 train
+fgzmioqabq 1 241 train
+fgzrkfwnpt 0 300 train
+fgzztxdlak 0 300 train
+fhaacoinwb 1 300 train
+fhaadtewmf 1 300 train
+fhaejqkxto 1 300 train
+fhafkpfjwi 1 300 val
+fhagtcekiy 0 300 train
+fhaiimbhdg 1 300 val
+fhaiqjsxxr 1 300 train
+fhajjbenap 1 300 train
+fhajwvmxlg 1 300 train
+fhamtzmywi 1 300 train
+fhaoftrpul 0 300 val
+fhaupqvsnl 1 300 train
+fhbajybgmi 1 300 train
+fhbfkmutjb 0 300 train
+fhblcnczdj 1 300 train
+fhbqnhqlwn 1 301 train
+fhbslciqdm 1 300 train
+fhbtqhyqmv 1 298 train
+fhcgufunfz 1 300 train
+fhcicxjlyr 1 300 train
+fhcmxyftgw 1 300 val
+fhcncljvrv 1 300 train
+fhcootmxdq 1 300 test
+fhcrdaknpq 1 300 train
+fhcuwezfpy 1 298 train
+fhczoolmco 1 300 train
+fhdgktivrg 0 300 train
+fhdgqukkso 1 300 train
+fhdhluissq 1 300 train
+fhdkuglmzo 1 300 val
+fhdpasazzp 1 300 val
+fheautpznj 1 300 val
+fhebochzzo 1 302 train
+fhecllzeps 1 300 val
+fheejoaovv 1 300 train
+fhefrzdhpj 1 301 train
+fhefzlqiha 1 300 train
+fheoxoneeu 1 298 val
+fhetmbyobx 0 300 train
+fhfbxttwfh 0 300 train
+fhfcleoirs 1 300 train
+fhfclibybo 1 299 val
+fhfgnhjxcm 1 298 train
+fhfifgkean 1 300 train
+fhfnixrhws 1 299 test
+fhfunjspkf 1 300 val
+fhfwalqltr 0 300 train
+fhggpjcxxp 1 300 train
+fhghkgbnsh 1 301 val
+fhghkqdkhe 0 300 train
+fhgnmqzfca 1 300 test
+fhgrxmqqul 1 302 train
+fhgyeiuvmg 1 299 train
+fhhbltcnyj 1 300 train
+fhhfrrvulf 1 300 train
+fhhgvvydre 1 300 train
+fhhlzspwur 1 300 train
+fhhnrpwkki 1 300 train
+fhhohseher 1 300 train
+fhhortycpg 1 300 train
+fhhpgvcqoh 0 241 train
+fhhtztucxq 1 299 val
+fhhyuaqztb 0 300 train
+fhiblpemsd 0 300 train
+fhigdlcnhw 1 300 train
+fhigwcnxhr 1 299 val
+fhijwlldwo 1 300 train
+fhimbeijci 0 300 train
+fhinmahqfi 1 300 train
+fhioksfycd 0 300 train
+fhiueodgxt 0 300 train
+fhjhvdgmcq 0 300 test
+fhjifxzzxt 1 301 train
+fhkbdhtirb 1 300 train
+fhkecjxtim 0 300 train
+fhkickwefi 1 241 train
+fhknqsokhi 1 300 val
+fhldjotxko 1 300 val
+fhlffeyxol 0 300 train
+fhlfuquyhr 1 300 train
+fhlwgpcnqp 1 300 train
+fhlxhkrpyt 1 300 train
+fhlztdauvt 1 300 train
+fhmjuyomqf 0 300 train
+fhmokzktal 1 300 train
+fhmstcpajb 1 300 train
+fhmzdntaqj 0 300 train
+fhmzwtuqbn 1 292 val
+fhncucaend 0 300 train
+fhncznvida 0 298 train
+fhnlwgjnlq 0 300 train
+fhnmdognis 1 300 train
+fhnrjrrfab 1 300 train
+fhntnyzoai 1 300 val
+fhoabmmeqb 0 301 val
+fhocwzeryw 1 300 train
+fhodnvppkz 1 300 train
+fhohurryun 1 300 val
+fhojnkawkq 1 300 val
+fhonpnpnls 0 300 val
+fhoteytxtb 0 300 train
+fhowmnvvge 1 300 train
+fhoxdkhopo 1 300 train
+fhpfjjbfbi 1 300 train
+fhpjeivdvm 1 300 train
+fhpqzqvruo 1 300 train
+fhpwdjbmow 1 167 train
+fhqiimesrc 1 300 train
+fhqycclsvg 1 300 val
+fhqycspasd 1 300 train
+fhqzwrgfmb 1 299 train
+fhrjtrxpsv 1 300 train
+fhrlkfrofk 1 300 train
+fhrqmneeqh 0 300 train
+fhrsqtuohm 0 300 train
+fhryafekve 1 300 train
+fhsckyuezm 0 300 train
+fhsdkuguju 1 300 val
+fhsdyqtcja 1 300 test
+fhsmosbesh 1 300 train
+fhsopezelx 0 300 train
+fhsqiidxjf 1 300 train
+fhssdtkmjy 1 300 train
+fhsyriemev 1 300 train
+fhsysgdpub 1 300 train
+fhtamkylht 1 300 val
+fhtcxgzjvr 1 300 val
+fhteiiigaz 1 300 train
+fhtkoootlq 1 300 train
+fhtmnfeqft 1 300 test
+fhtvrunsve 1 300 train
+fhtzzfysws 1 300 train
+fhucacmmfg 1 300 train
+fhufodtrbc 1 300 train
+fhuhlfnzoj 1 298 train
+fhutckjulr 1 300 train
+fhvaxbjqjw 1 300 train
+fhvdrjeeve 1 300 train
+fhvhfqrqhr 1 300 train
+fhvnuwsfdr 1 300 train
+fhvrvjiuxh 1 300 train
+fhvsnnxmjf 1 296 val
+fhwgrarnid 1 300 train
+fhwhkenywq 1 300 val
+fhwsilhhyd 1 300 train
+fhwujfakld 1 300 train
+fhxbkasmhh 1 300 train
+fhxboeaqpj 1 300 train
+fhxfrtvpvh 1 300 val
+fhxnsnpbjl 1 300 train
+fhxomiwsov 1 300 train
+fhxptowtss 1 300 train
+fhxxopxzni 1 300 train
+fhxzowzofb 0 300 val
+fhyczuygmr 1 300 train
+fhygbxcuvm 1 300 train
+fhyjokdowm 1 301 train
+fhykpqmvhi 1 301 train
+fhyllnfxfq 1 300 train
+fhymxcvtyv 1 300 train
+fhysmcypsf 1 300 train
+fhzdeeqxsm 1 300 train
+fhzdtfiqrh 1 300 test
+fhzegfdzpu 1 300 train
+fhzfwzuedd 1 300 train
+fhznwvrkwz 1 301 train
+fhzpmudsrj 1 300 train
+fhzpyswnqz 1 300 val
+fhzqbegfpg 1 300 train
+fhzqmyagac 1 300 train
+fhzrcxflmt 1 298 train
+fhzxwyxlnl 1 300 val
+fiacsiugzt 0 300 train
+fiafgkdufg 1 300 train
+fiajjhnckb 1 241 train
+fiakreyjbg 1 300 train
+fiaoioqikt 1 300 train
+fiaqcebcjy 1 240 val
+fiaqecjvxv 0 300 train
+fiavrtgzkk 1 300 train
+fiayeurvwb 1 300 train
+fibctjkhly 0 300 train
+fibhmdonmj 1 300 train
+fiblrjzqaq 1 300 train
+fibpwdkctq 1 300 val
+fibsfsivxr 1 300 train
+ficfcsdezh 0 300 train
+ficmlfzbul 1 300 val
+fictfesjrr 1 297 train
+ficudqzpxc 1 300 train
+ficywnedgy 1 300 train
+fidfazmovh 1 300 train
+fidfnekxpy 0 300 train
+fidgumueec 1 300 train
+fidgzwismf 1 301 train
+fiedmhtawp 1 300 train
+fiedwlcwyn 1 300 train
+fieeljsghy 1 241 train
+fiekqbztfe 1 288 train
+fiencvqrps 1 295 train
+fienqibwhi 1 302 train
+fieohlhzwp 0 300 train
+fiepgbvlrb 1 300 val
+fierqjpuef 1 99 train
+fiesmfagyt 1 300 train
+fiewcigwkv 1 300 train
+fifcusswoz 0 298 train
+fifiolrugh 1 300 train
+fifjoqsfan 1 301 val
+fifnuzkjgg 1 300 train
+fifpruwhjx 1 302 val
+fiftvucvue 1 300 train
+fifuixxokg 1 300 train
+figflgncsf 1 300 train
+figfxyhild 1 300 val
+figsmtmzse 0 300 train
+figuqpbovb 1 300 train
+figxvsdmsb 1 300 train
+figxxtupnw 1 300 val
+fihhemujnh 1 300 train
+fihimnflou 1 296 train
+fihjnhcwth 1 300 train
+fihjohiaiz 1 300 train
+fihjujrmpf 0 300 val
+fihnnkimzz 1 300 train
+fihvltkgzk 1 300 train
+fihylwnlms 1 300 train
+fiiiybmtbm 1 300 train
+fiijbfltwu 1 301 val
+fiinousxrm 1 300 train
+fiiqfocsvl 1 301 train
+fiiulonszn 1 241 train
+fiiwjcnzff 0 300 train
+fiiwmeedpe 0 300 train
+fiiwwzyefv 1 300 train
+fiiytbrbyp 1 300 train
+fijjvsbmlr 1 300 train
+fijlkwbugp 1 300 train
+fikdowhlpf 1 300 val
+fikgknbjzv 1 300 train
+fikqucsnyv 1 300 train
+filaxhxfnu 1 300 train
+fileffkzou 1 300 train
+filipcuviz 1 300 train
+filmckkgiz 1 300 val
+filmmsbgum 1 300 val
+filtihcuha 1 300 train
+filtoyoekj 1 300 train
+filuudleua 0 300 val
+filwepxjlv 1 300 val
+fimaxivyjo 0 300 train
+fimdeakoow 1 300 train
+fimhhyetym 0 300 val
+fimmookvqv 1 300 train
+fimociqhzk 1 300 train
+fimwzpujhe 1 300 train
+finajvgncq 0 300 train
+finbctuswt 1 300 train
+findfddbfr 1 301 train
+finhqimpzj 1 300 train
+finnjqnztr 1 300 train
+fintjppenq 1 300 train
+finwkpyfus 1 300 val
+finxnswaul 0 300 val
+fiobdzvedn 1 240 train
+fiobjlznms 1 300 train
+fiobpjuuzw 1 300 test
+fiohqhsbwz 1 300 train
+fioosmzdkq 1 241 train
+fiosbwtuyg 1 300 train
+fiowpegcdv 1 300 val
+fipanlabdz 0 300 train
+fipenzvrxb 0 300 train
+fipjqrgwmm 1 300 train
+fipwnqgonh 0 300 train
+fipybppzlr 1 300 val
+fiqgkrpvyr 1 300 train
+fiqgnthvfg 1 300 val
+fiqhctxfus 1 299 test
+fiqjmthegx 1 300 train
+fiqsmzuggy 1 300 val
+fiqtdygepo 1 292 val
+fiquxglbtj 0 300 val
+fiqvyucwzn 1 300 train
+fiqzgirirh 1 300 train
+fiqzxgsiow 1 301 val
+firbngucmx 0 300 train
+firczmxodx 1 300 train
+firgfjlrjk 1 300 train
+firkihyytz 1 300 train
+firlsjvtup 0 300 val
+firmqihsxd 1 300 train
+firovdoeuw 1 300 train
+firsgehlex 1 300 train
+firvybweog 1 300 train
+fisacwgrlp 1 300 train
+fiseahkwgc 0 300 train
+fisicodugi 1 301 val
+fiskmunura 1 301 train
+fisyxjvtre 1 300 train
+fitaiauqbr 1 300 train
+fitdcyepci 0 300 train
+fitgoopjfu 1 300 train
+fitkdqesny 1 300 train
+fitnascevt 1 300 train
+fitrowlltn 1 300 train
+fitssbqkue 1 300 val
+fiuclusoxo 1 301 train
+fiudjyxouo 1 296 train
+fiueppyyql 1 300 train
+fiuiofecgh 1 300 train
+fiuqnaqgbm 1 300 train
+fiuqxaanye 1 300 val
+fiurqjrbkx 1 297 val
+fiuuxnrkuz 1 241 train
+fiuvyfekwq 1 300 train
+fiuydkbyxu 1 300 train
+fivbdypogr 1 300 train
+fivchgvchx 1 300 train
+fivdmorlbt 0 300 train
+fivjzpjtfs 1 302 train
+fivlogttny 1 301 train
+fivwyuyndg 0 300 train
+fivxypdofz 1 300 val
+fiwdddcccw 1 300 train
+fiwjgwsfkr 1 300 val
+fiwtqakyhi 0 301 train
+fiwxoxxqay 1 299 val
+fiwxyfsijh 1 299 train
+fiwyozbblu 1 300 val
+fixatljgfz 1 300 train
+fixdxyvzkx 1 301 train
+fixeuqycrq 1 302 train
+fixfxbzahu 1 300 train
+fixirllgzk 1 300 train
+fixjrewibn 1 300 train
+fixpligwzl 1 300 val
+fixqngooli 1 300 val
+fixxfpyyny 0 300 train
+fixywcpkjr 1 300 train
+fiybjuhogl 1 300 train
+fiyhcmxjst 1 300 train
+fizfrdlxrd 1 300 train
+fizjpvkvsk 1 300 train
+fizjrtkrbk 0 241 train
+fizlfxkrsp 1 300 train
+fizlnxpjpn 0 300 train
+fiznpgcnxg 1 300 train
+fiztvpnszw 1 300 train
+fjabrelevm 1 300 train
+fjacfmuvhh 0 298 train
+fjafecudrk 1 300 train
+fjafyicjlw 1 300 test
+fjagaxlbpd 1 300 train
+fjaifztfmv 1 298 train
+fjajnnmytp 1 299 train
+fjammjljws 1 300 train
+fjaomdpqkk 0 300 val
+fjarqdvuea 1 300 train
+fjatdgwaux 1 300 train
+fjawcgdzkj 1 300 val
+fjaxqoxlkt 1 300 train
+fjbdczndhq 1 300 train
+fjbfbanlyx 1 300 val
+fjbputqtrr 1 300 train
+fjbshkvnnd 1 300 val
+fjccoyatzx 1 300 train
+fjcdvgffec 1 300 train
+fjcfsxcbbb 1 300 val
+fjcfyxtkyu 1 300 train
+fjckdlvxqn 1 300 test
+fjcodkulop 1 300 train
+fjcoszukly 1 300 train
+fjctwymmnn 0 241 train
+fjcyoixqau 1 300 train
+fjdbygjzfi 1 300 train
+fjdgazeuqw 1 300 train
+fjdiijzfsw 1 269 train
+fjdjdtzfdt 1 297 train
+fjdkxakecv 1 300 train
+fjdsoxkkwo 1 300 train
+fjdulbehpx 1 300 val
+fjdunxauji 0 241 train
+fjdvhqckev 1 300 train
+fjdykbckzi 0 300 train
+fjeapgsnsz 1 298 train
+fjebxgfrls 1 300 train
+fjecguljgd 1 300 train
+fjeddnhvmh 1 300 train
+fjehekjobc 1 300 train
+fjejdkbdvo 1 300 val
+fjeondysmq 1 240 train
+fjfbxkqlju 1 300 train
+fjfchiabde 1 301 train
+fjffrliobe 0 300 train
+fjfhibljxu 1 300 train
+fjfngtoihc 1 299 test
+fjfvsdxxkh 1 299 test
+fjgddxjqhb 1 300 train
+fjgncibwbl 1 300 train
+fjgqkvmlyn 1 300 train
+fjgqrphojl 0 300 train
+fjguqfldav 1 300 train
+fjgxnqduai 1 301 train
+fjhappnjbd 1 300 train
+fjhgaunrgr 0 300 train
+fjhjtwijnb 1 300 train
+fjhlhoifdh 1 300 val
+fjhydagkns 1 300 val
+fjifjlwazd 1 300 train
+fjihrjusdx 0 300 train
+fjikfukeeu 1 300 train
+fjiokipniq 1 300 val
+fjitaycehq 1 300 val
+fjiykmlwqs 1 298 val
+fjjhbclmle 1 300 train
+fjjhdupqdv 1 301 val
+fjjjwcibmv 1 300 train
+fjjnuaejee 1 300 train
+fjjocymjmz 0 300 train
+fjjubtwttp 1 300 train
+fjjvhpfmuh 1 300 train
+fjkbiwdyus 1 300 train
+fjkfqlwhwe 1 300 train
+fjkgcykspg 1 300 train
+fjklrvzpic 1 300 train
+fjkmfzajnx 1 249 train
+fjknzezzpg 1 288 train
+fjkuwtmvin 1 300 train
+fjkvqgovws 1 300 train
+fjkyexyswf 1 300 train
+fjlwkmkdfg 1 300 train
+fjlyaizcwc 0 300 train
+fjmbzlsdux 1 300 train
+fjmdbzibnq 0 300 train
+fjmnfblycb 1 300 train
+fjmrwoczej 1 300 train
+fjmzotvgtt 1 300 train
+fjncnvgpad 1 300 val
+fjnepgselg 1 298 train
+fjnetcxhnu 1 300 train
+fjnhqjvhwm 1 300 train
+fjnmmdglsh 1 301 train
+fjnoqfxzxf 0 300 train
+fjnupufknt 1 300 train
+fjnvsgejnv 0 300 val
+fjnxgddurc 1 300 train
+fjocodmxee 1 300 train
+fjoiggbvqt 1 300 train
+fjooquxwsa 1 297 val
+fjozlghihm 1 300 train
+fjpoqomzvd 1 300 train
+fjptcjjdve 1 300 train
+fjpxgxlhwt 1 300 val
+fjpxousjik 1 300 train
+fjqbcbyjtk 1 240 train
+fjqcdvkbjc 1 300 val
+fjqdnfkriu 1 300 train
+fjqlswitcb 1 300 train
+fjqlxxnabb 1 301 val
+fjqmjlbmad 1 300 train
+fjqtmpofjl 1 300 train
+fjqzlccxlq 1 300 train
+fjrbquaicw 0 300 train
+fjrcjisybg 1 300 train
+fjrcmhfpyz 1 300 train
+fjrkojeyvu 1 300 train
+fjrleuhnha 1 300 train
+fjrmptshrs 1 300 train
+fjrovfpsmq 1 300 train
+fjrueenjyp 1 300 test
+fjsbsydeai 0 300 val
+fjsjxottge 1 300 train
+fjslqjylww 1 299 train
+fjsstymmlz 0 300 val
+fjsuelxaqo 1 300 val
+fjszwtqjwj 1 300 train
+fjtbfmzrsn 1 300 train
+fjtbnvcpzk 1 300 train
+fjteinuizg 1 300 train
+fjtgipzeyf 0 300 val
+fjtopvzdcm 0 300 train
+fjtpdlgjet 1 300 train
+fjtzbqmpcr 1 300 train
+fjuatujczy 1 300 train
+fjubmqudgd 0 193 train
+fjuqmwrdmi 0 300 train
+fjuuookbpi 1 300 train
+fjuuzlqhdb 1 298 val
+fjuwritlvw 1 300 train
+fjuwxqapzb 0 300 train
+fjvriqokla 1 299 val
+fjwahrdeqo 0 300 train
+fjwcfziazx 1 298 val
+fjwfpdibhh 0 300 val
+fjxgxbwkfa 1 300 train
+fjxjzeuxco 1 300 val
+fjxovgmwnm 0 300 test
+fjxqdwzyle 1 300 train
+fjxwwpcgcu 1 300 train
+fjxynzqzxc 1 300 train
+fjyegbtzcb 1 300 train
+fjyfpynkta 1 300 train
+fjyqdlthcg 1 300 train
+fjysbwrxoc 0 300 train
+fjzbfexbjr 1 300 train
+fjzficggmo 1 299 val
+fjzpibfehj 1 298 train
+fjzrvkleur 1 300 val
+fjzubtympu 1 300 train
+fjzxgznzti 1 301 train
+fjzxygdweh 1 300 train
+fkaesoakje 1 300 train
+fkafbuieux 1 300 train
+fkalwfarxz 1 300 train
+fkanprepej 1 300 val
+fkarxowzuf 0 300 train
+fkatqttepa 0 300 train
+fkazlahbrz 1 300 train
+fkbeddwmpx 1 300 train
+fkberdxeqy 1 300 train
+fkbjregizy 1 298 train
+fkbloovrix 1 300 val
+fkbowkvwrl 0 300 train
+fkbrpnuxyl 1 300 train
+fkbtgogfko 1 297 val
+fkbwlrvpdy 1 300 val
+fkbysojhdy 1 297 train
+fkcdupzlhj 1 300 train
+fkcfdmlmzz 0 300 train
+fkcfxwkqpo 1 300 train
+fkcgxxbyge 0 300 train
+fkciyccmiy 1 300 train
+fkcrjzxukk 1 300 train
+fkcrvlpwnq 0 300 train
+fkcvweykwa 1 300 train
+fkdaybrfed 1 300 train
+fkdfmcfqqw 1 301 train
+fkdghyvcvc 1 299 train
+fkdjmbfxdq 0 300 train
+fkdlulvxdh 0 300 val
+fkdmipkufb 1 300 train
+fkdqwmkhrr 1 301 train
+fkdwhlkzqo 1 298 train
+fkdzdzmguj 1 300 val
+fkeawkcnbx 1 300 train
+fkebsdemzh 1 300 train
+fkeccxaeit 1 301 train
+fkedzsjnll 1 300 train
+fkeepspvps 0 300 train
+fkeictfhfp 1 300 train
+fkekjiwsyv 1 300 train
+fkessgvekm 1 300 train
+fkeyfhlhfu 1 302 train
+fkezgemgyj 1 301 train
+fkezygjoqi 1 136 train
+fkfbpxjsgk 1 300 train
+fkfkjujqjg 1 301 val
+fkflfsklrg 0 300 train
+fkfqwwralq 0 300 train
+fkfvbdqmbr 0 300 train
+fkfxnvftvc 0 300 val
+fkgbrpubep 1 300 val
+fkgdbngipj 1 300 train
+fkgheptmfg 1 300 train
+fkgibqzujd 1 300 train
+fkgpuczwkt 1 300 val
+fkgsobxabp 1 299 train
+fkhbjljluw 0 301 train
+fkhdiygyqf 1 300 train
+fkhfejtjpd 1 300 train
+fkhfgdebui 0 300 train
+fkhiyzyndh 0 300 train
+fkhlxtjenk 1 300 train
+fkhmutejpi 1 300 train
+fkhqdtprji 1 300 train
+fkianuhuko 1 300 train
+fkidsixtkn 0 300 train
+fkiejjiydk 1 301 train
+fkikwosmhx 1 301 train
+fkipjvtayq 1 300 train
+fkisosebej 0 241 train
+fkiuwyyzjt 1 299 test
+fkixyxxavp 1 300 train
+fkiztawrtv 1 300 train
+fkjchfyclo 0 300 val
+fkjegdwqur 0 300 train
+fkjiodygxa 1 241 train
+fkkjsqywrq 1 269 train
+fkkkfalzza 1 302 train
+fkkmxwjkxb 1 300 train
+fkksbgaibl 1 300 train
+fkkwlndxme 1 300 val
+fkkykgobzs 1 300 train
+fklditvesf 1 297 val
+fkleqilapg 1 300 val
+fklereoibg 1 300 train
+fklhvpdzpz 1 300 train
+fklmgqcgrs 1 300 train
+fklyibsgua 1 300 train
+fklzzxioez 0 300 val
+fkmalnfjee 0 300 train
+fkmhznucev 1 301 val
+fkmiygeekr 1 300 train
+fkmjfvjqru 1 300 train
+fkmlmkogkq 1 300 train
+fkmphbvzgx 1 241 train
+fkmuvtuuhs 1 300 train
+fkmuwkagxl 1 300 train
+fkmvxejhvf 1 299 val
+fkmxqizsjr 1 300 train
+fknafzvndp 1 300 train
+fknauejbfh 0 301 train
+fknbxhdhna 1 300 val
+fkneqpynjf 1 300 train
+fkneuizzgi 1 300 train
+fknfzuxfmy 1 300 train
+fknggynsab 1 300 train
+fknhmjdimp 1 300 train
+fknkcobmix 1 300 train
+fknnakjgzg 1 300 train
+fknonbqgdm 1 300 train
+fknrpthfcv 1 300 train
+fkodkltttc 1 300 train
+fkojclpsdn 1 300 train
+fkolrzqrge 1 300 train
+fkomzmoqzb 1 300 train
+fkosrukqml 1 300 val
+fkougtewkt 1 300 val
+fkpcwebkya 1 300 train
+fkpjlgnzsm 1 300 train
+fkpjpyhtax 0 300 val
+fkptjqeuhu 1 300 val
+fkqagjuckk 0 300 val
+fkqbsedarm 1 300 train
+fkqhgokyxc 0 300 train
+fkqkfpxdgv 1 300 val
+fkqkixrhhn 1 300 train
+fkqlqzyjvb 1 300 train
+fkqptfouqw 0 300 train
+fkquaxogko 0 300 val
+fkqzkrmfto 1 300 train
+fkqzwnytyl 1 300 train
+fkrkfbbdfu 1 300 train
+fkrmyvxocc 1 300 train
+fkrnlwqsmm 1 300 val
+fkrpswcbyj 1 300 train
+fkrpuyjzbt 1 300 val
+fksbgzstce 0 300 train
+fkscvnrjkt 1 300 val
+fkseutlgmb 0 300 train
+fksgiigank 1 300 train
+fksksiyyty 0 300 train
+fkssfkbrkp 1 300 train
+fksuepmjfx 1 299 test
+fksxywotbh 1 300 train
+fksypzmavv 1 300 train
+fktasshecy 1 300 train
+fktdsqigxq 1 299 train
+fktidqvkou 1 300 train
+fktpkdihfh 1 300 train
+fktxniwzxe 1 300 val
+fktzmvlqpf 1 300 test
+fkuaeezkvc 1 300 train
+fkuervobsc 1 300 train
+fkujbfnief 1 300 train
+fkukyvanom 1 300 train
+fkuprjwxou 1 300 val
+fkurevobjp 1 300 train
+fkvdbgnsrf 0 300 train
+fkvkicttid 1 300 train
+fkwadedwfe 1 299 test
+fkwgafcjit 1 301 train
+fkwgnwgfkj 1 300 train
+fkwkmhqqhu 1 241 val
+fkwpvrnoda 1 300 train
+fkwsqelktq 1 300 train
+fkwucbqnot 1 299 test
+fkxdhrpbkf 1 298 train
+fkxemhhdyx 1 300 train
+fkxfhrjsmx 1 301 train
+fkxgrokggj 1 300 train
+fkxkcftaza 1 300 train
+fkxomsatzv 1 300 train
+fkxppjofdq 1 300 val
+fkxruylypw 1 300 train
+fkycrmrcsr 1 236 train
+fkyhglxxlk 0 300 train
+fkyjucdrhs 0 300 train
+fkyrrigzpt 0 300 train
+fkytehbasw 1 300 train
+fkywnulhhf 1 300 train
+fkyyquhoge 1 301 val
+fkzarhkmyp 0 300 train
+fkzbezsnid 1 300 train
+fkzcnakyvd 1 300 val
+fkzggoiekp 1 300 train
+fkzmdpmcbc 1 300 train
+flafkjfgik 1 300 train
+flaiajndsl 1 300 train
+flammdszzo 1 300 train
+flanwtvuul 1 300 train
+flaucqmcjg 1 300 val
+flawetuacb 1 301 train
+flbcqpdqae 1 300 train
+flbgxrzowr 1 300 train
+flbkpwhllr 0 300 train
+flbrdxytmn 1 300 train
+flbrvohbvv 0 300 train
+flbuoulzvu 1 300 train
+flbxvsolki 1 300 train
+flcanezyoy 1 300 train
+flcayajedj 1 300 train
+flcdzqcocl 1 298 train
+flchnybldg 1 300 train
+flciegtafk 0 300 train
+fldipftzcj 1 296 train
+fldpkataqk 0 300 val
+fldqgrwguz 1 300 train
+fldzwyxkyh 0 301 val
+flehurzpbi 1 298 val
+flekxcxqcz 1 300 train
+flelrnmyyb 1 300 train
+flelyuqpxl 1 300 train
+fleoawtvif 1 300 val
+flewnfmwqy 1 300 train
+flfclkknni 1 298 val
+flfdxtiiku 1 300 val
+flfrcaoluu 1 299 test
+flfzeqkhnk 1 300 train
+flfzlkjocf 0 300 train
+flgayhvdok 1 300 test
+flgdpgiuyo 1 300 train
+flgeyrvktn 1 300 train
+flgfhzgiwt 0 300 val
+flghpxtrvv 1 300 train
+flgvkdijui 1 300 train
+flgztszejx 1 241 train
+flhamanjdh 1 300 val
+flhbuwzapo 1 300 train
+flhdsqdkib 1 300 val
+flhdswdwka 0 300 train
+flhgpumdbh 1 300 train
+flhsohvnzx 1 300 val
+flhvldseej 1 300 train
+flhvxcuoux 1 300 train
+flhzurjzwa 1 300 train
+fliashcclk 0 300 train
+flidcqnxoa 1 301 train
+fliewwrjck 1 300 val
+flilazlokf 1 300 test
+flimtbdsoo 1 300 train
+flinzslzrw 1 300 train
+flisgstglb 1 300 val
+fliyvtgbru 1 300 val
+flizrnhjsh 1 300 val
+fljabxsdxl 0 300 train
+fljgktbrif 0 301 train
+fljjrisqoy 1 300 test
+fljlpfzbrx 1 300 train
+fljsyrnaev 1 300 train
+fljtrmcohq 1 300 train
+fljxgxnpku 1 301 val
+fljyoqhgcp 1 300 train
+flkbecxzej 1 300 val
+flkcbvanpt 1 300 val
+flkhxqidll 1 300 train
+flkmdghpzy 1 296 val
+flkrcpcxzj 0 300 val
+flkrkykavq 1 300 train
+flkslbrgee 1 300 train
+flktoxtmkm 1 300 train
+flkyfvztfn 1 300 train
+flkyoehsyh 1 300 train
+fllccgwlhc 0 300 val
+flldsxhkvp 1 300 train
+fllkhvqdtf 1 300 val
+fllkzgyhka 1 300 train
+fllljbscbk 1 300 train
+fllljvuqqa 1 300 train
+fllqmxglug 0 300 train
+fllrawwclt 1 240 train
+fllrrugytq 0 301 train
+flmaakudnr 1 300 val
+flmcckqccv 1 147 train
+flmdswijrq 1 300 train
+flmewpbxmc 1 300 train
+flmkaifcqm 1 301 train
+flmlfkhdxa 1 301 train
+flmtzaicyi 1 299 val
+flmvfafkgu 1 300 train
+flmzohztyr 1 301 train
+flndbxfdta 1 299 test
+flnhfqfhsk 1 300 train
+flnotizmfa 1 300 train
+flnprphysg 0 300 train
+flnpuftppy 1 301 train
+flnyajzhsn 1 300 train
+flnyxtghwk 1 300 train
+flnzivmbsg 1 300 train
+floigrrodm 1 300 val
+flokdsxbgy 0 300 train
+flollgxopn 0 300 train
+flomkvxbkm 1 300 train
+floopyyydb 1 236 train
+floukjwtsj 1 300 train
+floxovbpvo 1 300 train
+flpaebsyzf 1 300 train
+flpdcbxkxl 1 294 train
+flplwlvpqh 1 300 train
+flptzlzjov 1 300 val
+flpyarefbo 1 300 train
+flqeiqdoza 1 300 train
+flqgmnetsg 0 300 train
+flqpovrciu 1 300 train
+flqrcolcyv 1 300 train
+flqsqzhdzg 1 301 train
+flqsssfnvp 1 301 val
+flqtblrvbb 1 299 train
+flqthiodqa 1 300 train
+flqusvanls 1 300 train
+flqwmxveir 1 300 train
+flqzqhgfiy 1 300 train
+flreajpcaa 1 300 train
+flrrarosuj 1 298 train
+flrrvkkxxf 1 300 train
+flrucvbppu 1 300 train
+flsaluyvws 1 300 train
+flsapfrhaz 1 241 train
+flscnlygsf 1 300 train
+flsdqvosqh 0 300 train
+flshczqpvt 1 302 train
+flsishllsn 1 301 val
+flsjziutgl 1 300 train
+flsomjtymw 1 300 train
+flsrhzzazq 1 300 train
+flstswwpvm 1 300 val
+fltabnehuo 1 300 train
+fltaubcdoo 1 300 train
+fltaysfwct 0 300 train
+fltdzcggwj 1 300 val
+fltimsxlfq 1 300 train
+fltpouphzs 1 300 val
+fltwqzypjm 1 300 train
+fluhfizuxc 0 300 val
+fluhrncpuv 1 300 train
+flumifdoxb 1 300 train
+flupgzcotk 1 300 train
+fluvmfflqo 0 300 val
+flvarrfpdw 1 300 train
+flvbxmtoml 1 300 train
+flvclhndvy 1 300 train
+flvgffvrxx 1 299 train
+flvggpxyxa 1 300 train
+flvnspbdet 0 300 val
+flvntcpujg 1 300 val
+flvpxpofbf 1 300 val
+flvwbdkpjz 1 296 val
+flvyfswjls 0 300 train
+flwelakahc 1 301 train
+flwkpdnhna 1 300 train
+flwmfioqdz 1 300 val
+flwszzinwf 1 300 train
+flwwerunhc 1 298 train
+flwyxwkbut 1 300 train
+flxhyvalil 1 300 train
+flxkagsdek 0 301 val
+flxnqxxpku 1 300 train
+flxogucnoo 0 300 train
+flxolcoioq 0 300 train
+flxsxcgfkz 1 300 train
+flxuyzbglj 1 300 train
+flyapytwzl 1 300 val
+flycpukhem 1 299 test
+flyfushrwr 1 300 train
+flyiuycbzk 1 300 train
+flymwrrjzm 1 300 train
+flyngabqxk 0 300 train
+flynvldesl 1 300 train
+flyuhvlaef 0 300 val
+flzflmkcyj 1 300 train
+flzfmyemkr 0 300 train
+flzgswyggs 1 299 test
+flzljstmnt 1 300 train
+flzlyrexie 1 300 train
+flznaipoft 1 300 val
+flzuymaupb 1 300 train
+flzwoieezm 1 300 train
+flzzatdnub 1 299 test
+fmaaowxqpw 0 300 train
+fmabovdbdw 1 300 train
+fmabtnteqd 0 300 train
+fmaeghtspv 0 300 train
+fmaprfsayl 1 300 val
+fmauvgencv 1 300 train
+fmbbkxntmr 1 300 train
+fmbbuabmed 1 300 train
+fmbcendnnh 1 300 train
+fmbdffmife 1 300 train
+fmbjulvbsy 1 300 train
+fmblegzmiu 1 300 val
+fmbltvunyt 1 300 val
+fmbmlagoiq 1 300 train
+fmbtaztqve 1 300 val
+fmbwltkgiw 1 300 train
+fmbwvvqblt 1 300 train
+fmbymqdysk 1 301 val
+fmbzbsmhux 1 300 train
+fmchohvhsr 1 300 train
+fmckabbhfv 1 300 val
+fmclyipaog 1 300 val
+fmcqevzmhb 1 298 train
+fmcrhaisxl 1 300 train
+fmcuffkedk 1 300 train
+fmcvyarlbm 1 300 train
+fmcwxcyaii 0 300 train
+fmcxagkyby 1 300 val
+fmcxhcdapk 1 300 train
+fmdhqnkvyo 1 300 val
+fmdlqkvbhy 1 300 train
+fmdmxnazhc 1 300 train
+fmdzinswpj 1 300 train
+fmdzjijatj 1 300 train
+fmegtxqovc 1 300 train
+fmeifvqtlt 1 302 train
+fmekywunkx 0 300 train
+fmelqkqitj 1 240 train
+fmemykshyq 0 301 train
+fmeptfderu 1 300 test
+fmexhqiekb 1 300 train
+fmfazqqfvk 0 300 train
+fmfbfntqlt 1 299 val
+fmfcgqfgtk 1 300 val
+fmfhevvcpq 1 300 train
+fmfkqmafin 1 300 train
+fmfzjxbgrk 1 300 train
+fmggpqngxa 1 300 train
+fmgldnjfiy 1 301 train
+fmgloiqwnn 0 300 train
+fmgmjuhcnj 0 300 val
+fmgtdrcvlx 1 300 train
+fmguyggvxv 1 301 train
+fmgwilfxpi 1 300 train
+fmhazobreq 1 300 train
+fmhdgrbcwg 1 300 train
+fmhiujydwo 0 299 test
+fmhlsehffj 1 300 train
+fmhpmqhyxu 1 300 train
+fmhulqdldk 1 300 train
+fmhvovidjv 1 301 train
+fmhytvqaaf 0 300 train
+fmiciisiqe 1 300 train
+fmigueccqp 1 241 train
+fmihtgohid 1 300 val
+fminppiauw 1 300 train
+fmivjsxwrh 0 300 train
+fmixyiojaq 1 302 train
+fmjbmpdgyo 1 300 train
+fmjbthfrrj 1 300 train
+fmjjymqsqv 1 300 val
+fmjmfgynph 1 300 train
+fmjocrmuqq 1 300 train
+fmjtcrdfmm 1 300 train
+fmjwgaxonw 1 300 train
+fmkaglsfox 1 300 val
+fmkbvsztfc 1 300 train
+fmkgoxapzt 1 300 val
+fmkhuajvzv 1 298 train
+fmklixparn 1 300 train
+fmknozijfs 1 300 train
+fmkusgfdux 0 300 val
+fmldeiihya 1 300 test
+fmljdvhwtj 0 301 train
+fmlrikvqcc 1 300 train
+fmlulwbxog 1 300 train
+fmlxlhepst 1 300 val
+fmmiwdulyz 1 300 train
+fmmwrjbman 1 300 val
+fmnfjlbsob 1 301 train
+fmnhbcghcx 1 300 train
+fmnigmlbmo 0 300 train
+fmnkrgqkbh 1 300 train
+fmnlxoiiue 1 300 val
+fmnoizjfxv 1 300 train
+fmnpsjdxov 1 301 train
+fmnzbwtjep 1 300 val
+fmoebkyejl 1 300 val
+fmomtapqbp 1 300 val
+fmorhnqepu 1 300 train
+fmosxaojqp 1 300 train
+fmowoztmdg 1 300 train
+fmoywdmssi 1 300 val
+fmpfytylbs 0 300 train
+fmpigpxfbw 0 300 train
+fmplybyyxg 1 300 val
+fmpppuvpjw 1 300 train
+fmprksrncj 0 300 train
+fmpyaucqrt 1 298 train
+fmqalahnjw 0 300 train
+fmqeetdhyv 1 300 train
+fmqihbcfhs 0 301 train
+fmqkezfpmb 1 300 train
+fmqkvssmuh 1 300 val
+fmqmruhhmz 1 300 train
+fmquvnpfnw 1 300 train
+fmqvbaxnse 1 300 train
+fmrthqcprn 1 300 train
+fmryvphrtb 1 300 val
+fmrzjlkiql 0 300 train
+fmsbtnxulk 1 300 val
+fmsdqktnlz 1 300 train
+fmsgdzjzty 1 300 train
+fmsrtebgmj 1 300 train
+fmsscfpyla 1 300 train
+fmstmvsghc 1 300 train
+fmsxomanga 0 300 train
+fmsxwtarwd 0 300 train
+fmteuebzfk 1 300 train
+fmtgjesjzx 1 300 train
+fmtivxomgv 1 300 train
+fmtjplzasl 1 298 train
+fmtlbuuriy 1 300 train
+fmtlgkmrfw 1 300 val
+fmtryaszxl 1 299 test
+fmukomcpfd 1 301 train
+fmuleeyhxj 0 300 train
+fmuncwjpej 1 300 train
+fmurvmizzi 1 300 train
+fmutbqbnsk 0 300 val
+fmuubpbqde 1 300 train
+fmuvopvoif 1 300 train
+fmvcabnbtz 1 300 train
+fmvdkhucsz 1 300 train
+fmvoukfedu 1 300 val
+fmvpyahacc 1 300 train
+fmvvmcbdrw 1 300 test
+fmvwfjjvgy 1 300 val
+fmwbtpllbn 1 300 train
+fmwegswtzj 1 300 train
+fmwepphhxh 1 300 val
+fmwgxwsydg 1 241 train
+fmwmqitpkw 1 300 train
+fmxawwhlub 0 300 train
+fmxdhyldpx 0 301 train
+fmxesahfet 1 300 train
+fmxhsxokpq 1 298 train
+fmxkeawabv 1 301 train
+fmyalalwjh 1 300 val
+fmyehmzinn 0 300 train
+fmyexsznly 1 298 train
+fmygqulimu 1 300 train
+fmyisvlyyf 1 301 train
+fmyjgxeudl 1 300 val
+fmyueqgtar 1 300 train
+fmywbrgrde 1 300 train
+fmyzvdduwd 1 300 train
+fmzdbsviul 1 300 train
+fmzmwupomf 1 300 train
+fmztdticln 0 300 val
+fmzufgwlyj 1 300 train
+fmzxptgzut 1 300 train
+fnaajvgmwt 0 300 train
+fnaamfbakz 1 300 train
+fnabvqqhwq 1 300 val
+fnaofvckvy 1 300 train
+fnapjgrqwt 1 299 test
+fnashzpuhh 1 300 train
+fnassvbmfl 0 300 train
+fnatyslrgf 1 300 train
+fnazspfnbs 1 300 train
+fnbaeljuyt 1 299 test
+fnbekoafga 1 241 train
+fnbjsxarfd 1 300 train
+fnbkonffjh 1 300 val
+fnbtldnhvk 1 300 val
+fnbwfrgbam 1 300 val
+fnbyoyzfvk 1 288 train
+fncbcqsqof 1 300 train
+fnccgwlapt 1 300 train
+fnccrsrchl 1 301 val
+fncenesahd 1 300 train
+fnchjaowdq 1 299 test
+fnchyvajny 1 300 train
+fncnobpzzx 1 300 train
+fncnrwyyqz 1 300 train
+fncqkxkuow 1 300 val
+fncvzofotd 1 300 train
+fncxxdmkfx 1 300 val
+fncypiszkf 0 300 train
+fndhijmzqg 0 300 val
+fndhlkfrcr 1 300 train
+fndhoywbty 1 300 train
+fndnlvxbyw 1 300 train
+fndqsgotxx 1 300 train
+fndtctqlaj 1 147 train
+fndwkidiyc 1 301 train
+fndxnctihv 1 300 train
+fndzidbkay 1 298 train
+fneatzvrsv 0 299 train
+fnegaaozcp 1 299 test
+fnejwhwdee 1 300 val
+fnejwlvvsg 1 300 train
+fneqiqpqvs 0 299 test
+fnfgazrfxe 1 300 train
+fnfgtxzmjh 1 300 train
+fnfijljlly 1 301 train
+fnfjxjfrtn 1 300 train
+fnfrwdxyoy 1 301 train
+fnfrxtvkmg 1 300 train
+fnftfqvvxe 1 300 val
+fnfxwilegs 1 300 train
+fnfzaiueia 1 300 val
+fnfzeexlaw 1 300 val
+fngjzyzohx 1 300 val
+fngpizitlu 1 241 train
+fngppyjakg 1 300 val
+fnhamwxrdt 1 301 val
+fnhklprtus 1 300 val
+fnhnqhmicp 1 299 train
+fnhtrjggdb 0 300 val
+fnhvmlysxv 1 300 train
+fnhyfjsnop 1 301 train
+fnicwoxeln 0 300 train
+fnidqmgfpi 1 300 train
+fnifgsgxmb 1 300 train
+fniijvwwow 0 300 train
+fnitoittmt 0 300 train
+fniwtkekbc 1 300 train
+fniznxhmyg 1 299 val
+fnjbfxdvms 1 300 train
+fnjfhetrwh 1 300 train
+fnjivgipmq 1 300 train
+fnjmbozylf 1 300 train
+fnjmqjwpez 1 300 val
+fnjnoeuqmn 1 300 train
+fnjowdvyke 1 300 train
+fnjpujwyfp 1 300 train
+fnjslfddlh 1 167 train
+fnjtrjjppf 1 300 train
+fnkdkfajak 0 300 train
+fnkkqtouoz 1 300 test
+fnklaaafpi 1 300 train
+fnkmpmouas 1 300 train
+fnkscusoao 1 300 train
+fnldwdbwlk 0 300 train
+fnlejrhfgp 1 300 train
+fnlepxxlip 1 300 val
+fnlevpvyii 1 300 train
+fnlovrlbjw 0 300 train
+fnlpdmjmta 1 300 train
+fnlqhlbltj 0 241 train
+fnlrcjaauq 1 299 train
+fnlvikrytu 1 300 val
+fnlvpucikn 1 300 train
+fnlyouwxau 1 300 val
+fnlzgmvxwg 1 136 train
+fnmiqhvxqt 1 300 train
+fnmqhhzoao 1 300 train
+fnmtbntlyi 1 300 train
+fnmtjgjqxe 0 300 train
+fnmxxderxt 1 298 train
+fnmxxskuhk 1 300 train
+fnmyrbkppr 1 298 train
+fnnahethgq 1 300 train
+fnnajcwcvc 1 300 train
+fnnvkkppqg 1 241 train
+fnodhipplo 1 300 val
+fnoeqfxkth 1 300 val
+fnomsecrln 1 300 train
+fnoqzmthex 1 300 train
+fnoujjkvnu 1 300 train
+fnpbmfxslw 1 300 train
+fnpczerfna 1 300 train
+fnpicpgrjj 1 300 train
+fnpqckskwh 1 300 train
+fnprhpkkyw 1 300 train
+fnpterildn 1 300 train
+fnqbsizwsv 1 300 train
+fnqnxfjvdt 1 298 train
+fnqonxkhpm 1 237 train
+fnqrydakgc 0 300 train
+fnqsdhkoxo 1 300 train
+fnrfbyocre 1 301 train
+fnrivllmnr 1 300 train
+fnriyvznar 1 292 val
+fnrznlracp 1 300 val
+fnsfnsuqhi 1 300 train
+fnslimfagb 0 300 test
+fntaqkkvtu 1 300 train
+fntbthvvfj 1 300 train
+fntclsgbep 1 300 train
+fntioxlffj 1 301 train
+fntomcusok 1 300 train
+fntpvkeksp 0 300 train
+fntrideeyb 1 300 train
+fntskqfxxf 0 300 train
+fntwhjewdn 1 297 train
+fntzrlplbr 1 300 train
+fnubnafvdu 1 300 val
+fnudskjmbt 0 300 train
+fnudsphmnk 1 300 train
+fnutlphems 0 300 train
+fnuvyoyomw 0 300 train
+fnuwioyupw 1 300 train
+fnuxdwxumz 1 297 train
+fnvblpsfen 1 301 val
+fnvpzsivsc 1 300 val
+fnvrpfpgzy 1 300 val
+fnvtiaemmw 1 300 val
+fnvyoclbos 1 300 train
+fnwadlstxu 1 300 train
+fnwkskwmff 1 300 train
+fnwnfnrbte 0 300 train
+fnwnvvfymp 1 300 train
+fnwqxqecnm 1 301 train
+fnwtkyadab 1 300 val
+fnwvqdprhw 1 300 train
+fnwyrqcgip 1 300 train
+fnwzluuksk 1 300 train
+fnxgmlfqpc 1 300 val
+fnxgqcvlsd 1 299 test
+fnxhrwzcmj 1 301 train
+fnxinzjzfb 1 240 train
+fnxlgapxgx 1 300 train
+fnxmqrygbm 0 300 train
+fnxtmuhkxt 1 298 train
+fnyfttoppw 0 300 train
+fnyrvnfegv 1 300 test
+fnzcyxfbxj 1 240 train
+fnzepfmqlb 1 300 val
+fnzevnxabe 1 300 train
+fnzexbbltq 1 300 train
+fnzmlwhhdd 1 300 train
+fnzozvyxsq 0 301 train
+fnzvphudej 1 300 test
+foaccrhqhv 1 300 train
+foaqnaqvjz 1 300 train
+foaszwqboi 1 300 test
+foatowedvz 0 298 train
+foaybpqnrq 1 300 train
+fobezgnkjj 1 300 train
+fobfcnhvhg 1 300 train
+fobjtzmehz 1 301 train
+fobnkiglkm 1 300 val
+fobqcvegfr 1 300 train
+fobuloidrt 1 300 train
+fobxxpujgt 1 300 train
+focpkzmizk 0 300 train
+focrvumxxg 1 300 test
+fodalblhcd 1 300 val
+fodeqpuzbv 1 300 train
+fodhjwybqm 1 300 train
+fodlygqrcx 1 300 train
+fodmzjauvz 0 300 train
+fodpdbzkpi 1 300 train
+foduvthzgm 0 300 train
+foeepalwlt 0 300 train
+foehcvikeg 1 300 train
+foehqvfucz 0 300 train
+foeozkvwii 1 300 train
+foeqclgypj 1 300 train
+foeqdpisxf 0 298 train
+foerxneyvu 1 300 train
+foescmhzgq 0 300 train
+foeuncnvnd 1 298 train
+foevravwbd 1 301 train
+fofcdycshg 1 300 train
+foflklwpsw 0 300 val
+fofqxuuryw 1 300 train
+foftbpkdev 1 300 test
+foftkffmwy 1 301 train
+fogcgggrxz 1 300 train
+fogdskvher 1 300 train
+fogeedjzrv 1 301 train
+foggejxjea 1 300 train
+fogkarnumo 0 300 val
+fogmyovwjt 1 300 val
+fogrzoxrch 1 301 train
+fogumwdbqc 1 301 train
+foguogczvs 1 241 train
+fogvuxsrmh 0 300 train
+fogxcacauq 0 300 train
+fogzkcgwzv 1 250 train
+fohesjrenj 1 300 train
+fohgifymhw 1 300 train
+fohmhzhhuc 0 300 train
+fohnwahvbr 1 300 train
+foibohwkqb 1 300 train
+foiczxqruw 1 300 train
+foifvnloxa 1 300 train
+foioktmbsk 1 300 train
+foishnxozg 0 300 train
+foityehgno 1 301 val
+foiuifhdhs 1 300 train
+fojbikmxjv 1 301 train
+fojhncadwb 0 300 val
+fojjdrqzkz 1 300 train
+fojmiqejht 1 299 train
+fojncnzzrs 1 300 train
+fojnvcjdaw 1 300 train
+fojooiajqv 1 300 train
+fojswhagff 0 300 train
+fojuchzjmb 1 300 train
+fokbqgxrdf 0 300 train
+fokjbuazgr 1 300 test
+fokniecgnk 1 300 val
+foknrqirmu 1 300 train
+fokqgsgsku 1 300 train
+fokuimoqkh 1 300 train
+fokzwocift 0 300 train
+folanrdfbq 0 300 train
+foligrwxod 1 300 train
+folildqyrn 1 298 train
+folnravvyf 1 300 train
+folnwowegb 1 301 val
+folvmimysf 1 300 val
+folvmlxzwp 1 300 train
+folxcvvtgq 1 300 train
+folxzxcxvy 1 300 train
+fomaiyrtin 1 299 val
+fomccdufil 1 300 train
+fomfhfyzxg 1 241 train
+fomfmkfbqv 1 300 train
+fomgviyohz 1 300 train
+fomhmpfeki 1 301 train
+fomibzjdbk 1 300 val
+fomsttpqnm 0 300 train
+fomvnxyrbn 1 300 val
+fomwhtxjzi 1 300 train
+fomyxzfuxd 0 300 train
+foncmjwcrn 1 300 train
+fonfhgffun 1 300 train
+fongivuyxd 0 300 train
+fongjhcwvu 1 302 val
+fonhmzoqsm 1 301 val
+fonoxshdww 1 300 train
+fonrexmbzz 1 300 test
+fonsehhusi 1 300 train
+fonylxwxef 1 300 train
+fooapdswnu 0 300 train
+foodomqkvq 0 300 train
+foohyhbmhe 1 300 test
+fophlxjwol 1 300 train
+fopjiyxiqd 0 300 test
+fopmdkqszn 1 301 train
+foptkvfuhs 1 300 train
+foptlvvakb 1 300 val
+foqbbihjzc 1 300 val
+foqdvfuvjc 1 301 train
+foqfrkuztm 1 299 train
+foqwmiwrdt 1 300 train
+foqxjtpxgf 0 300 train
+foqygpxnfq 1 301 val
+foqzjzxdrf 0 300 train
+forohbufpd 0 300 train
+forqbzjgjc 1 300 val
+forrseurea 1 300 train
+fortjanwmb 0 300 train
+foryjijpae 1 300 train
+forysduuws 1 300 train
+foscnvozob 1 300 train
+fosovipqkg 1 300 val
+fosqibnubd 1 300 train
+fossjefhwn 1 299 train
+fotdwuwgsq 1 300 train
+fotgmeorfp 1 300 train
+fotqbosccv 1 300 train
+fotqmxytlc 1 300 val
+fotvxamhxh 1 300 train
+fotzbujcxy 1 300 val
+fouajbowhz 1 241 train
+fouopijxwe 1 300 val
+fouottflrl 1 301 train
+fouucrowag 1 300 train
+fovfjgkzml 1 300 train
+fovjiefdrf 1 300 train
+fovnnzstmd 1 300 train
+fovtsuhkyh 1 300 train
+fovwyyyxhr 1 300 train
+fowjmhkbeh 1 300 train
+fowpmphaya 1 300 train
+fowsqtlwmo 1 300 train
+foxdqteooy 1 300 train
+foxjgyoumr 1 299 val
+foxmetfmht 1 300 val
+foxpjxasnv 1 300 train
+foxsabkaxa 0 302 train
+foxwczjakn 1 300 train
+foxwqacjjw 1 300 train
+foxycuvwjt 0 301 train
+foycsccyvb 1 300 train
+foydsyjzhp 1 301 train
+foyhauzvch 1 300 train
+foyhraedej 1 300 train
+foyievjaad 1 300 train
+foymknprbl 1 300 train
+foynwjsqeh 0 300 train
+foyskhgqdp 1 300 val
+fozajwrjvs 1 300 train
+fozjpxdehp 1 300 train
+fozpvjlfuo 1 300 train
+fozqgvubje 1 300 train
+fpaagvbyjp 1 298 train
+fpafdiehsl 1 300 train
+fpagjjvmho 1 300 train
+fpakfdhuqh 1 298 train
+fpamtxbdvu 1 300 train
+fpapndwupg 1 300 train
+fpawgawyqs 1 299 train
+fpaykqshpa 0 300 train
+fpbcmfberh 1 299 val
+fpbiwajwdo 1 300 train
+fpbjlolmcw 1 300 train
+fpbljvtjqf 1 300 train
+fpcczjppoz 0 301 train
+fpcepeefho 1 125 val
+fpckfenbbw 1 241 train
+fpcncmwzxf 1 300 test
+fpcotrphmr 0 300 train
+fpcqawomzz 0 300 train
+fpczgzjodg 1 300 train
+fpdbfvcrqd 1 300 train
+fpdjahzghj 1 301 train
+fpdlpbqjjs 1 300 train
+fpdqbytvmk 1 300 val
+fpdrjkgwnz 0 301 train
+fpeadurrwp 1 300 train
+fpegftnojt 1 300 train
+fpeghxkepx 1 300 train
+fpeiwavbvl 1 241 train
+fpelumatcz 1 300 train
+fpespmbbmh 0 300 train
+fpetccfbzb 1 298 train
+fpeudmvcbu 1 300 val
+fpevfidstw 0 299 test
+fpfedexwil 1 300 val
+fpfefuixuc 1 300 train
+fpfljuvbxj 1 83 train
+fpfqjqyrum 1 300 val
+fpfwzjdhrd 1 300 train
+fpgacmtdsi 1 300 train
+fpgbqmqesb 1 300 train
+fpgkfpevfj 1 300 train
+fpgmlnpyys 0 300 train
+fpgnbvzycs 0 300 val
+fpgpjtbydy 1 300 val
+fpgrwgojgm 1 300 train
+fpgswkfxyp 1 301 train
+fpgzavhexk 1 300 train
+fphsgphdcd 1 299 test
+fphuxwdtpy 1 300 val
+fphuzkxqit 1 300 val
+fpigjwxsjw 1 300 train
+fpikfgbxdz 1 300 val
+fpiltwqkcz 0 300 train
+fpiowljlrq 1 300 val
+fpiuydztwi 1 294 train
+fpiybwcszz 1 299 train
+fpjczdegjy 1 300 val
+fpjdwqsmri 0 299 train
+fpjemqymbe 1 300 train
+fpjnqkzewj 1 300 val
+fpjpwidpwm 1 297 train
+fpkbiiwpdu 1 300 train
+fpkjadqsaf 1 300 val
+fpkmkpkhiy 1 300 train
+fpkrkluigq 1 300 train
+fpksnudhhm 1 300 train
+fplamcgcci 0 300 train
+fplbjxvolk 1 300 train
+fplgwzikps 0 300 train
+fpliemtlco 1 300 train
+fplilgkdcc 1 300 train
+fpliptrbxx 1 300 val
+fpljuwubiv 1 300 train
+fplknsyqiz 0 300 train
+fplkqksnhk 1 239 train
+fplloskddq 1 300 train
+fplpwwgmfq 1 300 train
+fplziwbigq 1 300 train
+fpmabinhtm 0 300 train
+fpmacwpaqr 0 301 train
+fpmarcqjfr 0 300 train
+fpmgdktbyh 0 300 train
+fpmgiqaija 1 300 val
+fpmhkroqof 1 301 train
+fpmkrioqgi 1 300 train
+fpmpqbwmba 1 300 train
+fpmsgjyqwd 1 300 train
+fpmvwcxbfy 1 300 train
+fpmzgkezho 0 301 train
+fpnccssfmc 1 301 train
+fpnfwgeeuj 1 300 val
+fpnhbgiuej 0 292 val
+fpnhdbfleu 1 300 train
+fpnkgqslzz 1 300 train
+fpnkzegrps 1 300 train
+fpnpifwtok 1 300 train
+fpnqkovisx 1 300 test
+fpnrqskakv 1 300 train
+fpoavhcmxt 1 301 val
+fpobacwdrp 1 300 train
+fpodzuuebt 0 300 train
+fpofcntgpe 1 300 train
+fpoinoxtsh 0 300 train
+fpoixaowgf 1 300 train
+fposdoyraa 1 300 train
+fpoykttcqn 1 300 train
+fpozzmbcol 1 298 train
+fppeqvwevz 1 300 train
+fppiaflmuq 1 300 train
+fppkprrydv 1 300 train
+fpplhodtfr 1 298 train
+fpplivvwri 1 300 train
+fppmxmbxou 1 300 train
+fpprjnmrzq 1 301 train
+fpprngktoo 1 301 train
+fppzwruckp 1 298 train
+fpqcsldjwl 0 300 train
+fpqcxcbiqr 0 302 train
+fpqhqpiiqq 0 300 train
+fpqjludbwi 0 300 train
+fpqjqoeeij 1 300 train
+fpqovzxuwc 1 136 train
+fpqpaobnvf 1 301 val
+fpqqgjapqc 1 300 train
+fpqrtbbcpv 0 300 val
+fpqvnzqqls 0 300 train
+fpqxvycwoc 1 301 train
+fprgwxrvts 1 300 train
+fprlzalyrz 1 300 train
+fprnaorizo 1 300 train
+fpscxiutxe 1 300 train
+fpsfhhczne 1 300 train
+fpshkzmddp 1 300 train
+fpsiscyfyw 1 301 train
+fpskkbpdxo 1 300 train
+fpsrbiuoxh 1 300 train
+fpstmifqnu 0 300 train
+fptanamdqf 1 300 train
+fptewxnuyt 1 300 val
+fptorfkyuz 1 298 val
+fptqmjcpuo 0 300 train
+fptqqzpqbj 0 300 train
+fpttjztuay 1 300 val
+fptwpxadrf 0 300 train
+fptwrlwvyd 1 300 train
+fpuaeblskk 1 298 val
+fpucrrdnki 1 300 train
+fpucwtjbuy 1 300 train
+fpujvkgzpp 1 298 train
+fpusxzzrgw 1 241 train
+fpuzhfsgus 1 300 train
+fpvduejzcw 0 300 train
+fpvijzphos 1 300 train
+fpvjqmcyjy 0 300 train
+fpvlbcugwu 1 241 train
+fpvomrhkia 1 300 val
+fpvrmlddve 1 300 train
+fpvurjklwt 1 300 val
+fpvxhcasse 1 300 train
+fpvyuijbzo 0 300 val
+fpwgkerlun 1 300 train
+fpwkaaaahk 1 300 train
+fpwtdlbnte 1 300 val
+fpwwutjtty 1 300 val
+fpwxlhamap 1 300 train
+fpxaquvzgr 1 299 val
+fpxdigsvwv 1 301 train
+fpxedsnmfh 1 300 train
+fpxeunxkfj 1 300 train
+fpxfndaaml 1 300 val
+fpxjzinwky 1 300 train
+fpxnhbcoob 1 298 train
+fpxoorpqkv 1 300 train
+fpxqlwbeib 1 300 train
+fpyflralta 1 300 train
+fpyfzjyybt 1 300 train
+fpynidpwoa 0 300 train
+fpyqdbklly 0 300 train
+fpywvyvuut 1 297 val
+fpyybnkagb 0 300 train
+fpyyllhcnf 1 300 train
+fpzgpmoxcm 1 300 train
+fpzjippyki 1 300 train
+fpzlthygvg 1 300 train
+fpzpgbugxm 1 300 val
+fpzyggmqzp 1 300 train
+fpzznseyxj 0 300 train
+fqabcvxdtp 1 300 train
+fqadxvyblp 1 300 train
+fqagmuruwt 1 300 train
+fqancsqjxq 0 300 train
+fqauipezfi 1 300 train
+fqavpfgmua 1 300 train
+fqawgxhhqh 1 240 train
+fqbcwugwon 1 300 train
+fqberdmiui 1 300 val
+fqbffwfxlx 1 301 val
+fqbndyrupa 0 300 train
+fqbqsyubzm 1 300 train
+fqbrybeztb 1 300 train
+fqbtknguje 0 300 train
+fqbuthoeqg 1 301 train
+fqbzpfodlz 1 300 train
+fqcehiuynd 1 300 val
+fqcfzpuctk 1 300 train
+fqcifwcdsv 1 300 train
+fqcjzgcmey 1 300 val
+fqcowbvyjv 1 241 train
+fqctevsjsm 1 297 train
+fqdddnovfa 0 300 train
+fqdklzzkfj 0 301 train
+fqdmghiwtb 1 300 val
+fqdmxafkhq 1 300 train
+fqdpdlbnif 1 297 train
+fqdtknurwf 1 300 train
+fqdzaubvhs 1 300 train
+fqdziaezmb 0 300 train
+fqecackmla 1 300 val
+fqeebgwwfs 0 300 train
+fqeilecqej 0 300 train
+fqepjykfru 1 300 train
+fqetglngae 1 300 train
+fqeunoxwux 0 300 val
+fqeytkksjm 1 300 val
+fqezvnpypl 1 300 val
+fqfdqnkssk 1 300 val
+fqfgrpunnu 1 300 train
+fqfhwmtasl 1 300 train
+fqfqvviylk 1 300 train
+fqfsugddkr 1 300 train
+fqgabqotrd 1 300 train
+fqghtycztv 1 300 val
+fqgirixvip 1 300 train
+fqgkpaxdgj 1 300 val
+fqgoixfwxl 1 301 val
+fqgpkjsdjx 1 301 train
+fqgrvqtutd 1 300 val
+fqgtfcbyam 1 300 val
+fqgypsunzr 1 300 test
+fqhajzskrc 1 298 train
+fqhbmravfr 1 300 train
+fqhdjrbivm 1 299 val
+fqhivmkvvu 1 300 train
+fqhodbgbti 1 300 train
+fqhovztzbp 1 300 train
+fqiatkiapa 1 300 train
+fqigzisvbj 1 300 val
+fqiteoiyda 0 300 val
+fqixbvpton 1 300 train
+fqjbeyxeph 1 300 train
+fqjbooptlq 0 300 val
+fqjcltzipj 1 300 train
+fqjdyomacd 0 300 train
+fqjicqoasu 1 300 train
+fqjiyckgrj 1 300 train
+fqjrreaffk 1 300 val
+fqjrylvphp 1 300 test
+fqkaaaagkw 0 300 train
+fqkagmnzxq 1 298 val
+fqkbexvmce 1 300 val
+fqkcmpivdv 0 300 train
+fqkhinwwqy 0 300 train
+fqkhvmugbw 1 298 train
+fqkmpojcsi 1 300 train
+fqkoiicqub 1 300 train
+fqkqitsumc 1 300 test
+fqkrsoeuvq 1 300 train
+fqktrpqfto 1 300 train
+fqlbrfbiyz 1 300 val
+fqldcvddga 1 300 train
+fqldtuhspe 1 300 train
+fqlkzgkpnx 1 241 train
+fqlmhrmeem 1 300 train
+fqlnrcaquj 1 302 train
+fqlrqjhxjq 0 300 train
+fqlsgciyvu 1 301 val
+fqlvbvgdgn 1 300 train
+fqlyrjczen 1 300 train
+fqmagqatec 1 300 val
+fqmfvshgns 1 300 test
+fqmvlxcxmr 1 300 train
+fqmwhnpduz 1 300 val
+fqngkpzdyv 1 300 train
+fqngozhtfk 1 300 train
+fqnibqdfly 1 300 train
+fqntqmhfmo 1 240 train
+fqnvpbvfmf 0 299 train
+fqodshqpzx 1 300 train
+fqovtlzwkd 1 300 train
+fqoykxbioc 1 240 train
+fqpifvxwyx 1 301 val
+fqpkocazgv 1 301 train
+fqpmvwdxaw 1 300 val
+fqpphcbruh 0 300 train
+fqppzqacjf 1 299 train
+fqpuryhmnj 0 300 train
+fqqaoqbtpe 1 300 train
+fqqngtbisq 1 298 train
+fqqqmfvanh 1 300 train
+fqqrhjuptg 0 299 train
+fqqtlglsqp 1 300 train
+fqrchdojtb 1 300 train
+fqreloltdd 1 300 train
+fqrrmbzntu 1 296 val
+fqruijjpfk 1 300 val
+fqrzmuzvjl 1 300 train
+fqsakjdayc 1 300 test
+fqshrduofz 1 300 val
+fqsymmbpna 1 301 train
+fqtabogrwi 1 300 val
+fqtadktqxr 1 300 train
+fqtcommobo 1 300 train
+fqteplotsl 1 300 train
+fqtmagxifh 1 296 val
+fqtmqiqhtr 1 300 train
+fqtpsfcmjr 1 300 train
+fqtytrgrwz 1 300 train
+fqucmyckfr 1 298 train
+fqucuqkvid 1 300 train
+fquechyqjk 1 300 train
+fqugcxgamo 1 300 val
+fqumxjnljo 1 300 train
+fqunnanewj 1 300 train
+fquuxhgrkx 1 300 train
+fquyddvpto 1 300 val
+fqvaalcdae 0 300 train
+fqvdqipioh 0 300 train
+fqvhvowiyr 1 288 train
+fqvoenhdod 1 300 train
+fqvqhihjol 1 296 val
+fqvriaaihu 0 300 train
+fqwdkzlwvg 1 300 val
+fqweeualqa 0 300 train
+fqwnbarpgv 1 300 train
+fqwplcsspu 1 300 train
+fqwtjskrec 1 300 val
+fqwtplcjfl 1 300 train
+fqwzflygtt 1 300 train
+fqwzsygxmq 1 300 train
+fqxionszxk 1 299 val
+fqxkglialr 1 300 train
+fqxlphzpsr 1 300 train
+fqxpgflfpc 1 240 val
+fqxvsftafp 1 300 train
+fqyaunvagr 1 300 train
+fqydrrndqc 1 300 val
+fqyfkbiipw 1 298 train
+fqygsfvmhu 0 300 val
+fqyldrcuot 1 300 train
+fqywdzsfjk 1 300 train
+fqyxxemqyb 1 300 val
+fqzdfduvlp 1 301 train
+fqzjvsposn 0 300 train
+fqzqnzzqwe 1 300 train
+fqzrykvrmo 1 300 train
+fqzygyfzzx 0 302 train
+fradpsybuj 0 300 train
+fragcvirlc 1 300 train
+fragqhpdjo 1 300 train
+fragyohcvq 1 241 train
+frakdhccek 1 300 train
+fralkdacto 1 300 train
+fraqjvnoxk 0 300 train
+frasadkwee 1 300 train
+fratowhttl 0 300 val
+fraweqonht 1 300 train
+frbajvvbwe 1 300 val
+frbdbkxaim 0 300 train
+frbhfojsry 0 300 train
+frbjsddtei 0 300 train
+frbnktgfor 1 300 train
+frbpaxqayg 1 300 train
+frbvunhkmz 1 299 val
+frcbgvuthg 1 300 train
+frcbosicyq 1 301 val
+frcflhqjqw 1 300 train
+frcirqezzm 0 292 train
+frcluhsyzk 1 300 val
+frcnojoyjq 1 300 train
+frcorwepoo 1 300 train
+frcplqrpgo 1 300 train
+frcsdlkxws 1 300 train
+frcwiruhjs 1 300 train
+frcwnwudln 1 300 train
+frcxhewrbi 1 301 val
+frczmdfzza 0 301 train
+frdfzynegz 1 288 train
+frdhhppcpm 1 300 train
+frdiruneji 0 301 train
+frdpasyrom 1 300 train
+frdxmfdplx 1 300 train
+frehtgxiln 0 300 train
+frekgugezt 1 300 train
+freqivezwh 1 300 train
+frexrurafj 1 236 train
+frfahhmjwh 1 300 train
+frfbygbsyx 1 241 train
+frfjmachtj 1 301 train
+frfllvgtlg 0 300 val
+frflyqooor 1 300 train
+frfojrpxhl 1 300 train
+frfyygjcvv 1 300 val
+frgbhpkdyf 1 300 val
+frgcvppgzj 1 300 val
+frgdpgbfmh 1 300 train
+frgejoibtz 1 300 train
+frgpuaoouz 1 300 val
+frgqpotejh 1 300 train
+frgwtziugg 1 301 val
+frgxlmbecr 1 299 val
+frgzynfdxp 0 300 val
+frhpqtmdjq 1 300 train
+frhrlmkbit 1 300 train
+frhupambad 0 300 train
+frhuxhpzvv 1 300 train
+frhvxmjavk 1 301 train
+frhxvdnwxj 1 300 train
+frieewiioj 1 300 train
+fripkdcelh 1 298 val
+frirdbhggm 1 300 val
+frirfsdmoi 1 300 train
+frjbrjdbmz 1 300 train
+frjkjlcfon 0 300 train
+frjllotrxj 0 300 train
+frkaigebav 1 300 train
+frkhhpwfjr 1 300 train
+frkiuejngv 0 300 train
+frklcckcqk 1 301 train
+frkobdmxpr 1 300 train
+frkoosiypx 1 301 val
+frkptuaxpz 1 241 train
+frkpueocbe 1 300 train
+frkrjhrwgh 0 301 train
+frkscpjusi 1 298 train
+frksxzccfm 1 301 train
+frktsiyzpp 1 301 train
+frkytkjxmh 0 300 train
+frlfdvwqdu 1 300 train
+frlqwnbkjo 1 300 train
+frlscamohf 1 300 train
+frlsxhdntt 1 300 train
+frltisynpx 1 297 train
+frluzuvywh 1 300 train
+frlzzsjamb 1 300 train
+frmfjousux 1 300 train
+frmgoftnkl 1 300 train
+frmkxglmuc 0 241 train
+frmrtwfbmc 1 300 train
+frmzkdhkzw 1 300 test
+frnegvplzk 1 300 train
+frnfvrofek 1 300 train
+frnjrzflhs 1 240 train
+frnrfcdaub 1 300 train
+frnxbpoasg 1 300 val
+frnxgmjnre 1 300 train
+frnypypslr 1 302 train
+fromclsodq 1 300 train
+frompgpzhp 1 300 train
+fronojwbgp 1 300 train
+frotgcqrde 1 300 train
+frousigghf 1 300 train
+frovxkqksr 1 300 train
+frovyktnsd 1 300 val
+frowxiaclv 1 301 train
+froyxkngvk 1 241 train
+frpefqshmo 1 300 train
+frpemaftwx 1 300 train
+frpexffkhf 1 300 train
+frpkynwuus 1 300 train
+frplqcissc 1 300 train
+frpmgxhppd 1 300 train
+frpqgmanuf 1 300 train
+frprbewzjq 1 300 val
+frqbuskapk 1 301 train
+frqejhoztf 1 300 train
+frqfsucgao 0 299 test
+frqhofmoob 1 300 test
+frqijjzpxl 1 300 train
+frqkzhyuzj 1 298 train
+frqopoojws 1 300 val
+frqrlcfuno 1 300 train
+frquqjldty 1 300 train
+frrebqdqvj 1 300 train
+frrhyudilh 1 300 val
+frriqgcdcu 1 300 train
+frrkzgjapb 0 300 train
+frrqtjofwm 1 300 train
+frruapayul 1 300 train
+frrukoihvj 1 300 val
+frrxceukpd 1 300 train
+frsjawvaoq 1 300 val
+frsomiwlbf 1 301 val
+frsuharvbo 1 300 train
+frtcdhlsmj 0 300 train
+frtgdbzcxw 1 300 train
+frthyifvlh 1 300 train
+frtktczcdf 1 300 val
+frtokkkhku 1 300 train
+fruavxnszz 1 298 train
+frugzwmsby 1 299 val
+frulgtwydy 1 300 train
+fruloxkpyy 1 300 train
+fruoaaefvp 1 249 train
+fruopjdxju 1 300 train
+fruukszcjn 1 269 train
+frvciqvzsc 0 241 train
+frvcncumpb 1 300 train
+frvdcftraa 1 300 train
+frvlugclaf 1 236 train
+frvtnsalmk 1 300 train
+frvtopklmu 1 300 train
+frvwbxtxka 1 300 train
+frvydrcjks 1 301 val
+frwaglvrxo 1 300 train
+frwaupnxab 1 300 train
+frwbewtgds 1 300 train
+frwbpshvyi 0 300 train
+frwgsmwayz 1 301 val
+frwhjxinqn 1 300 train
+frwivvbysq 1 301 train
+frwpjswdnr 0 300 train
+frwqozyjem 1 298 train
+frwzzishwb 1 300 train
+frxceyfttc 1 300 val
+frxgujmriv 1 300 train
+frxmydygsm 1 300 train
+frxrlvhtig 1 300 train
+frycvmzrez 1 300 train
+frydbcippq 1 300 val
+fryipulczz 1 300 train
+fryjurazkm 1 300 train
+frykkgbxnp 1 300 train
+fryqvgqkgt 1 300 train
+fryskdgsfd 1 301 train
+fryxefczja 0 300 train
+frzcjhetav 1 300 train
+frzdxnidkr 1 300 train
+frzdxvsxly 0 300 train
+frzdydxhkz 1 300 train
+frzefbsgmo 0 300 train
+frzhkrdtqe 1 298 train
+frzpbywpnx 1 300 val
+frzrswqycd 0 300 train
+frzzwpzmqb 1 300 val
+fsaakkrvdh 1 300 train
+fsaemuwjfg 1 301 train
+fsafpwxvpd 1 300 train
+fsalfwmdao 1 300 train
+fsalrjsyzm 1 300 train
+fsaokdigqp 0 300 train
+fsaoocmdgt 1 300 train
+fsaoxxjdjd 1 298 train
+fsapcdzxcq 1 301 train
+fsaronfupy 0 300 test
+fsbabrxhqy 1 300 train
+fsbdgbsgbj 1 300 train
+fsbeqkcuul 1 300 train
+fsbevcmphh 1 300 train
+fsbgawqwgt 1 300 train
+fsbjrmyfdv 1 300 test
+fsbtznktag 1 300 train
+fsbxvpalcp 1 300 train
+fschxggrzu 1 300 train
+fscltsbhqm 1 301 train
+fscpqzivoj 1 300 train
+fscscwadog 1 301 val
+fsctdcxuqp 1 300 train
+fscyfygpyk 0 300 train
+fsddurduvd 1 298 train
+fsdeegievg 0 300 train
+fsdeyqdans 1 300 train
+fsdgpysupr 1 300 train
+fsdonarqki 0 300 val
+fsdoseabco 1 300 train
+fsdplhynds 1 300 train
+fsdqterpek 1 300 train
+fsdrhxyoek 0 300 train
+fsdrwikhge 1 300 test
+fsdspdoysn 1 300 train
+fsdvwurxul 1 300 val
+fsdvzvkevg 1 300 train
+fsdwhsrecs 1 300 train
+fsdzaamgvj 1 300 train
+fsdzwjnxgo 1 300 train
+fseamiushb 0 300 val
+fseikzintc 1 300 train
+fseopnryum 1 300 val
+fsepjiwjrt 1 300 train
+fsfjlwwsen 0 300 train
+fsfnueduvi 1 301 train
+fsfqcetyyb 1 298 train
+fsgfvduaxq 1 241 train
+fsgghwymiv 0 300 train
+fsggkbhuin 1 301 train
+fsghozvjzf 0 300 train
+fsgtawehdn 0 300 train
+fsgzgzpglb 1 300 train
+fshjzdqdog 1 300 train
+fshjzksghf 1 240 train
+fshohylmpq 1 300 train
+fshsvxhuzj 0 300 val
+fshykjkois 1 301 train
+fshyuruqyd 1 299 val
+fsifmmgnrv 0 300 val
+fsisgbssxe 1 300 train
+fsiunpwpqx 1 300 val
+fsizfpqyjj 0 300 val
+fsizmovxoc 1 239 train
+fsjccjuqwf 1 299 train
+fsjdegkzxn 1 300 val
+fsjldslmvv 1 300 train
+fsjlheqxbo 1 300 val
+fsjmwhewmm 1 300 train
+fsjobllsfc 1 300 train
+fsjtihxnza 1 300 train
+fsjwjzqsjg 1 136 train
+fsjxsewmig 1 300 train
+fsjzwubwic 1 300 val
+fskesctxrw 1 300 train
+fskjykudzw 0 300 train
+fsknwfrczt 1 298 val
+fsksmyzjbv 1 300 val
+fsktkgbrkx 1 300 train
+fsldzkimln 1 300 train
+fslfwiqeau 1 300 train
+fslolunawz 1 300 train
+fslpatvxqx 1 298 train
+fsludojvyq 1 300 train
+fslwjnzjfy 1 300 train
+fsmdmzoimw 0 301 train
+fsmhgajswf 0 300 train
+fsmhupspqn 1 300 train
+fsmmgnjhhi 1 300 train
+fsmvlxaapa 1 300 val
+fsmwiiyuno 0 300 train
+fsmwlfevvp 1 300 train
+fsmxujzmop 1 298 train
+fsnbfdzbhq 1 300 train
+fsnewdhhqe 1 301 val
+fsnexexcka 1 300 train
+fsnirpvats 0 300 train
+fsnjjqgeto 1 300 val
+fsnliqatbu 1 300 train
+fsnppkmcwm 1 300 train
+fsnrdxtzde 0 300 val
+fsnstyxisv 1 300 train
+fsnxhikrhl 1 300 train
+fsoallmiov 1 300 train
+fsoanljfmx 0 300 train
+fsofonchgl 1 300 train
+fsogcoukrw 1 300 train
+fsoicnmyke 1 301 train
+fsomcxpfsm 1 298 train
+fsotugbzaw 1 298 train
+fsouqkhmkp 1 300 train
+fsovsygdmn 1 241 train
+fsowcwypwz 1 300 val
+fspoetivgb 1 300 train
+fspqoeuomc 1 300 train
+fspqzszoog 1 300 train
+fsptihfykw 0 300 train
+fsqagugbzm 1 300 train
+fsqbokdmjc 0 300 val
+fsqmcodtiu 1 300 train
+fsqpfckyho 1 300 train
+fsqrvwvnho 1 300 train
+fsqteuqfqj 0 300 val
+fsrbiisvsl 1 301 train
+fsrqsqzzcv 1 300 train
+fsrrqxkqob 1 300 train
+fssfgtoucb 1 300 train
+fssfmkvkci 0 241 train
+fssgvipbhk 1 300 train
+fssmgiceik 1 298 train
+fssmndjcbn 1 300 train
+fstcwyymfy 1 300 val
+fstiklyphm 1 301 val
+fstjulvkst 1 300 train
+fstlhgszjq 1 300 train
+fstnndabuo 1 300 val
+fstyvjsqpm 1 300 train
+fsubfwqlfb 1 301 train
+fsuetbnklu 1 300 train
+fsupcippjc 1 300 train
+fsuuqoiuqk 1 300 train
+fsuvsvtdmg 1 300 val
+fsveplitwe 1 301 val
+fsvftwyvrk 1 300 train
+fsvkitiidu 0 241 train
+fsvmxcelxe 1 300 train
+fsvnhagxec 1 300 train
+fsvnrnvmfa 0 300 train
+fsvpkugfxi 0 301 train
+fsvpzakdvz 1 300 train
+fsvqzxyvxz 1 300 train
+fswfiespcl 1 300 train
+fswjeuiwks 1 300 train
+fswszwicfw 1 300 test
+fswwddokin 1 300 train
+fsxdzxyhqh 0 300 train
+fsxedvalgi 1 300 train
+fsxhzufpmy 0 300 train
+fsxjbjvymh 0 300 train
+fsxjpxakzo 1 300 train
+fsxnypyfyh 1 300 train
+fsxpbqfgub 1 300 train
+fsxqjdqbpw 1 300 train
+fsxtwhuszx 0 300 val
+fsxwkitotg 1 288 train
+fsxwyhjxgo 0 300 train
+fsydpomvvc 1 300 val
+fsyebzdcoa 0 301 train
+fsymtbbuev 1 298 train
+fsyvsdxagh 1 300 train
+fsywibkykv 0 300 val
+fszcqehjmw 1 300 train
+fszehmumqx 0 300 train
+fszexmwczt 0 239 val
+fszkztzjyl 1 300 val
+fszmzrzoud 1 298 train
+fsznbbsqvl 1 300 train
+fszstnqlle 0 300 train
+fszvumhbji 1 300 train
+fszzvlkhcz 1 299 val
+ftabdmxjkr 1 301 train
+ftaehmyacq 1 241 train
+ftaeibmzmt 0 300 train
+ftafdstxyu 1 300 train
+ftafvawnwv 1 300 train
+ftaqnrjnrz 1 300 train
+ftbdfmekir 1 300 train
+ftbopgfqsv 1 300 train
+ftbqgzadge 0 300 train
+ftbsncpcok 1 301 train
+ftbzhsrrqu 1 300 val
+ftcaryvrcq 1 300 train
+ftcduclzsf 1 300 train
+ftcfcmqnif 1 300 train
+ftcmxybxox 1 300 train
+ftcvwsykza 1 302 train
+ftcxyxeovu 0 300 train
+ftddiwtuzv 1 300 train
+ftdeyptkxa 1 300 val
+ftdgzakuxw 1 301 val
+ftdhdltxkx 1 300 train
+ftdjicutax 1 300 train
+ftdkhyvwxf 1 298 train
+ftdwptruub 1 298 train
+ftegoykalc 1 299 val
+fteiwujfus 1 298 train
+ftejebdiac 1 300 val
+fteqkjqeji 1 300 train
+ftetrossxz 1 300 train
+ftevfqdpmq 1 300 train
+ftfemkjnot 0 300 train
+ftfiiokrpe 1 300 val
+ftfiuxqnrq 1 300 train
+ftfjpzqcrn 1 300 train
+ftfnypwddf 1 300 train
+ftfsuunqay 0 300 train
+ftfvgqdqxw 1 300 train
+ftfvleofjx 1 301 val
+ftgfedcldy 1 300 val
+ftggcbqwpw 1 299 test
+ftgjzaoiaw 1 300 train
+ftgsxxqcuc 1 298 train
+ftgufnqcvg 1 300 train
+ftgxeeihuv 1 300 train
+ftgzrawqsd 1 300 train
+fthbksnfqm 1 300 train
+fthiiicbhl 1 300 val
+fthjpbuvhq 1 300 val
+fthxjhxzyl 1 298 val
+fthzcibwic 1 300 val
+fthzfgtnqy 1 300 train
+ftigwkkobr 1 300 train
+ftiubtjxdj 1 300 train
+ftiwtpgobs 1 300 train
+ftjbpmvcdq 1 300 train
+ftjgwgjdam 1 300 train
+ftjhsfykor 1 300 train
+ftjknepqls 1 300 train
+ftjlacrvwu 0 300 train
+ftjmklmrft 0 300 train
+ftjnvrdurg 1 298 val
+ftjqarnhtf 1 300 train
+ftkqtvfvvq 1 300 train
+ftkskvfeth 1 300 val
+ftkxdmaemk 1 301 train
+ftlalxtaht 1 301 train
+ftlatniuwx 1 241 train
+ftlbjqrvag 1 300 train
+ftlefdarud 0 300 train
+ftlfdigxjf 1 300 val
+ftlrcdcpjm 1 300 train
+ftltvfacxy 1 300 train
+ftlvczbdme 1 300 val
+ftlxdbinct 1 300 train
+ftlzvcyswr 1 300 train
+ftmcjwndiy 1 300 val
+ftmdkroplr 1 300 train
+ftmffafmbv 1 300 train
+ftmktfgvsd 1 301 train
+ftmtazzunk 1 249 train
+ftmvnewzyw 1 298 train
+ftmvqcinzq 0 301 train
+ftmzruofrb 1 300 train
+ftnadelrct 1 300 train
+ftnbjgcrdu 1 300 train
+ftnkmsrrqs 1 241 train
+ftnmqzkxve 1 300 train
+ftnpfcabka 1 300 train
+ftnteolhjr 1 301 train
+ftnyqhpara 1 300 train
+ftoadqqgak 1 300 train
+ftoaxcbtgn 1 298 train
+ftodljaoyq 1 300 train
+ftoecttrok 1 300 train
+ftoflgzwen 1 300 train
+ftomejyowz 1 298 train
+ftoqbarusn 1 300 train
+ftovfrgjon 1 300 val
+ftowheytwl 1 300 train
+ftpadowrdf 1 301 train
+ftpdiarmjx 1 300 train
+ftphtwzhkm 1 300 train
+ftpmibhbec 1 300 train
+ftpppcihhj 1 300 train
+ftpvdgrrvw 1 299 train
+ftqayorcmg 1 300 val
+ftqbqyrxma 1 300 train
+ftqcbdfevj 1 99 train
+ftqeyugual 1 301 train
+ftqgelzioh 1 302 train
+ftqkikwzkv 0 300 val
+ftqvvdajzt 1 300 train
+ftrdtiyvre 1 300 train
+ftrduerstj 1 297 train
+ftrjuxfinz 1 300 train
+ftrlmthmgw 1 300 val
+ftrmsaqods 1 300 train
+ftrozqmxlo 1 298 train
+ftrqdvnqxn 1 301 train
+ftrrajufkv 1 300 val
+ftrucvkebp 1 300 train
+ftrvqvielv 1 300 test
+ftrxdvzqhm 1 300 train
+ftsarrwghx 1 300 train
+ftsgwzxvcm 1 300 train
+ftshdmikvn 1 300 train
+ftsinjrjap 1 300 train
+ftsojzoxtv 1 300 train
+ftsuphblcw 1 300 train
+ftsutcupto 1 300 train
+fttesiqzki 1 300 val
+fttjepcvuy 1 300 val
+fttngvxjpq 1 300 train
+fttwtnbitf 0 300 train
+ftuchkvmtr 0 300 train
+ftugybfwuw 0 300 train
+ftuhvimneu 1 300 train
+ftulgaascq 1 300 train
+ftumoftfoa 1 300 train
+ftusfcvkic 1 300 val
+ftuuhmjvkm 1 300 train
+ftvhrutnur 1 300 val
+ftvkmjuuhd 1 300 train
+ftvoqzhtdr 1 300 train
+ftwbzwydud 1 300 train
+ftwhwusbct 1 300 train
+ftwkdcwsvc 1 300 val
+ftwkncuvyx 1 300 train
+ftwnachzbd 1 300 val
+ftwtfucugq 1 300 train
+ftwvlcivib 1 300 train
+ftxavczbvi 0 300 train
+ftxbuvmkzx 1 300 train
+ftxiykiokf 1 300 train
+ftxkyhpuyp 0 300 train
+ftxogbjujn 0 300 train
+ftxqeraryj 0 300 val
+ftxsafydra 1 241 val
+ftxsiqlwtu 1 300 train
+ftxtkaolsk 1 300 train
+ftyclxgnbp 1 300 train
+ftyfkxsxux 1 300 train
+ftygrioyli 1 300 train
+ftylolqzmd 1 299 test
+ftypjcynnk 1 300 train
+ftysdaiuxo 1 300 train
+ftysjladzz 0 300 train
+ftyxisyzxr 1 301 train
+ftzqxzwwur 1 241 train
+ftzqywawya 1 302 val
+ftzunbbopg 1 298 train
+ftzwhmsoht 1 300 train
+fuaaqjtyao 1 300 train
+fuafqjlhnh 1 300 train
+fuagrqknja 1 300 train
+fuaiefbxdv 1 300 train
+fuajmaivsx 1 300 train
+fuakjlnfem 0 300 train
+fuanewhvas 1 300 train
+fubfrgjuyt 0 300 train
+fubgavgwzr 1 300 train
+fubgtlfeeu 1 300 train
+fubimsjlec 0 300 train
+fubkziydef 1 300 val
+fubmyjkozi 0 300 train
+fubpaitfyi 1 300 train
+fubppvheag 1 300 train
+fubvyuvals 1 300 train
+fubxvizayl 1 300 train
+fuchihvzbt 1 300 train
+fucmgfnrso 1 299 val
+fucolxblxh 1 298 train
+fucqsuxstj 1 300 val
+fucyuqalxk 1 300 val
+fudabqtwtm 1 241 train
+fudctgiqtg 0 300 train
+fudlahnhxv 0 300 val
+fudmwydqup 0 300 train
+fudosbrkez 1 300 train
+fudzlwacws 1 300 val
+fuegzrizzn 0 300 val
+fueiqjfgoq 1 300 val
+fuejnktipj 1 300 train
+fuenwqfltz 1 300 train
+fuerdujnmm 1 301 train
+fuetewygpz 0 300 train
+fueuybjpqu 1 300 val
+fueyzfuplo 1 301 train
+fuezskmgkr 1 300 val
+fufahuzvqr 1 300 train
+fufcmupzen 0 300 test
+fufoogofzn 1 300 train
+fufvpovlre 1 301 train
+fufyiqnsqe 1 300 train
+fufyqqbepn 1 300 train
+fugfrvucid 1 301 val
+fugkmklkbx 1 300 train
+fuguahashf 1 300 train
+fugwsyncsa 1 300 val
+fugzbjmcsc 1 300 train
+fuhmexegmf 1 300 train
+fuiakztlie 1 300 val
+fuicggxsws 1 298 train
+fuicllzvcq 1 241 train
+fuicodhcgx 0 300 train
+fuiglusbnl 1 300 test
+fuihgnbntk 1 300 train
+fuiidnbyjj 1 298 train
+fuilvipjlk 1 300 train
+fuiohinhvm 1 300 train
+fuipgsxhml 1 300 train
+fuiqfutwni 1 136 train
+fuixycdfqu 1 301 train
+fuizhjkpfk 0 300 train
+fuizudadhv 1 300 train
+fujdymvfcz 1 300 val
+fujpgqrihk 0 300 train
+fujsgbgiho 0 300 train
+fujubslwsy 1 300 train
+fujulinofp 1 300 train
+fujvppauoz 1 300 train
+fujwbsqeaf 1 300 train
+fujwhlwlff 1 300 train
+fukbmvopmk 1 300 train
+fukhunlqmn 1 300 train
+fukjiykwxz 1 300 train
+fukwgkjxfx 1 300 train
+fukwwdnwkd 1 300 train
+fuldvqjnam 1 298 val
+fuldvurmus 1 300 train
+fulesnfmfy 1 300 train
+fulhdmrsve 1 297 train
+fuljlvpbef 1 300 train
+fullzinjvc 1 300 train
+fuluvycjnw 1 300 train
+fumkkynirm 1 300 train
+fumoatfgzs 1 297 train
+fumrvdrkhg 1 301 train
+fumtejbdie 0 300 val
+fumuumjpud 0 300 train
+fumuxndmpv 1 300 val
+fumvmiowtu 1 300 train
+fumyyqfash 1 300 val
+fumzyeunxp 1 300 train
+funlmeoodq 1 300 val
+funrqunkvv 1 300 val
+fuobmswltj 0 302 val
+fuodxwoanw 0 300 train
+fuojhffxqu 1 300 train
+fuolxbpwez 1 300 train
+fuoqsmmzcg 1 300 train
+fuoswlrdgj 1 300 train
+fuovrtafbg 1 300 train
+fuoxnwqwbn 1 296 train
+fupbjsydcj 0 300 train
+fupbzybwis 1 300 train
+fupcovvieq 1 300 train
+fupcyuhxkg 1 300 val
+fupjjvvmbu 1 300 train
+fupolywzms 1 300 val
+fupqlxrnid 1 297 train
+fupsscbipe 1 297 train
+fupzijzyeq 1 300 train
+fuqcxthotp 1 300 val
+fuqflmbxwh 1 300 test
+fuqgzmlfcx 1 300 test
+fuqkpvcxar 1 299 train
+furlafpbfx 0 300 train
+furmkbqxwv 1 300 train
+furnrbtkwn 1 300 train
+furokqojrv 0 300 train
+furpmukdbk 1 300 train
+furshtzpdx 1 300 train
+furtuxzyvp 1 300 train
+furupdnvsg 1 249 train
+furvgnwfln 1 300 test
+furxbypblg 1 300 val
+fusfpcpsox 1 300 train
+fusgwmpjfh 1 300 val
+fuskfxelvv 1 300 train
+fusrkgmrrk 1 300 train
+fusssgbaol 1 300 train
+fustqzqkkh 1 300 val
+fusxlaflim 1 300 train
+fuszzvvpbm 1 300 train
+futjtwjsgt 1 241 train
+futjxzsyvs 1 300 val
+futvcippdx 1 300 train
+futvcsygxt 1 300 train
+futwxbhyls 1 300 train
+futwxyhbfw 1 300 train
+futzbsmkgx 1 300 train
+fuufdnajjh 1 300 train
+fuuhqqvxhl 1 300 val
+fuukjffnvl 1 301 val
+fuusqwogjb 1 300 train
+fuusxfhmrc 0 300 train
+fuuvolwkvh 1 300 train
+fuuwjkjelj 1 300 train
+fuuzeqfknj 1 301 train
+fuvccncrwv 1 298 train
+fuvegkfobf 1 300 val
+fuverqzkxh 1 300 train
+fuvgtepofn 1 300 train
+fuvipoqtbl 1 239 train
+fuvniycycu 1 300 train
+fuvpxblqpv 1 300 val
+fuvrijlvov 1 301 train
+fuvsguxqfp 1 300 train
+fuvwlbfhcx 1 300 val
+fuvwtyjmlf 1 300 train
+fuwevjkmdp 0 300 train
+fuwnsvsglc 1 300 train
+fuwwnuxbgt 1 300 train
+fuxekjiniq 1 301 train
+fuxgucedwt 1 300 train
+fuxlgnyujv 1 300 val
+fuxorhqbgl 0 300 val
+fuxqrqojwj 1 300 val
+fuxwsmbtjl 1 300 train
+fuyecqpvar 1 300 train
+fuykcvxujp 1 300 train
+fuykodbata 1 300 train
+fuymdjiuzq 1 300 train
+fuynepjfgw 1 300 train
+fuyoetrkqh 1 300 train
+fuypoadobu 1 300 train
+fuyvcjmibg 1 300 train
+fuywworttr 1 300 train
+fuyyqlseah 1 300 val
+fuzdxjsqvp 1 300 test
+fuzgtljhff 1 300 val
+fuzonzhbwt 1 240 train
+fuzrbxbkji 1 300 train
+fuzzllsbtg 1 99 train
+fvadvtklen 1 300 train
+fvaezfnuox 1 300 val
+fvajvzdnac 1 300 train
+fvaphxsbiz 1 299 train
+fvavuiptrw 1 300 train
+fvbaiihqpz 1 300 val
+fvbmglxvnu 1 298 train
+fvbqrkdvmz 1 300 train
+fvbtehwpgw 1 300 train
+fvcbxmxuiz 1 300 train
+fvccajstsd 0 300 train
+fvcgyoubiz 1 300 train
+fvchcrryfk 1 300 val
+fvcnftvtjv 0 300 train
+fvcqerfgfa 0 300 train
+fvcrfzzfnm 1 300 val
+fvcutuyffd 1 300 train
+fvcvweshvg 1 300 train
+fvcxtymazh 0 300 val
+fvczlbbhwk 1 300 val
+fvderxktfb 1 300 train
+fvdhqemlxe 1 300 train
+fvdkgreggl 1 298 train
+fvdnowmivl 1 300 train
+fveetlvabu 1 300 train
+fvenbssvyo 1 301 train
+fvennkzjbp 1 300 val
+fvesgpxalv 1 241 train
+fvetpuaxtk 1 301 val
+fveuakkpcy 1 300 val
+fvfcrmjkrx 0 300 train
+fvfesunwrg 1 300 train
+fvfqgkvjqx 1 300 train
+fvfwdvzqsm 1 300 train
+fvfxaxdiim 1 300 val
+fvfxffmuue 1 301 train
+fvfzksrsbd 0 300 train
+fvgimbewza 1 300 train
+fvgsbqodny 0 300 val
+fvgynhwepy 1 300 train
+fvgzwzgbkh 1 300 train
+fvhcsmkpvc 1 300 test
+fvhedunuub 0 300 train
+fvhelqvjmw 0 300 train
+fvhfqqhgll 1 300 val
+fvhhdftwcf 1 298 val
+fvhluagxrx 1 300 val
+fvhqajmsbe 1 301 train
+fvhvwkavlj 1 301 val
+fvhwprdodn 0 300 train
+fvilwijnwc 1 300 val
+fviqzhbyfd 1 300 train
+fvisaxkeaf 1 300 train
+fvivzhyahn 0 300 train
+fvjafyibdz 0 300 train
+fvjbvehmtl 1 300 train
+fvjgauvoqz 0 300 val
+fvjgyvowtw 1 301 train
+fvjkjpbujg 1 300 train
+fvjprteokk 1 300 train
+fvjutpueqx 1 300 train
+fvjzahyafa 1 300 train
+fvkengbdud 0 300 train
+fvklluniug 1 147 train
+fvkokcpfox 1 300 train
+fvkwkrdqgy 1 300 train
+fvkxjzkhib 0 300 train
+fvlajylxog 1 300 train
+fvlddnbwyd 1 301 val
+fvlfbjtljl 1 300 train
+fvlfqqwcgc 1 300 train
+fvllcbmwoo 1 300 train
+fvlmjzkqyy 1 300 train
+fvlrujrzre 0 300 train
+fvlujjqkdv 1 300 train
+fvlutprvjv 1 300 train
+fvlxhoaldp 0 300 train
+fvmavsuvlg 1 300 train
+fvmgomeatk 1 300 val
+fvmhipsebc 0 300 train
+fvmjwpalll 1 298 train
+fvmkxepnkp 1 300 val
+fvmtnwkoab 1 299 test
+fvmzeeukal 1 300 val
+fvmzqfflwe 1 300 train
+fvnfyukhpd 1 300 train
+fvnxxhzfqk 1 301 train
+fvockwqdri 1 298 val
+fvojjtkkdy 0 300 train
+fvooutibrd 1 300 val
+fvoramuyla 1 301 train
+fvorzqpgps 1 300 train
+fvouuqxulb 1 301 train
+fvpbfxcigp 0 300 train
+fvphehmebp 1 300 val
+fvpizkiiik 1 298 train
+fvprwqavma 1 300 train
+fvpvksioqx 1 300 train
+fvpvqvrnln 1 298 train
+fvpxbrdkpm 1 300 train
+fvqdfifffn 1 300 train
+fvqdvkejsu 1 301 val
+fvqgnobwab 1 300 test
+fvqgofievn 0 300 train
+fvqjlfufip 1 300 train
+fvqlbpgahd 0 300 val
+fvqtndbfoi 1 300 train
+fvqusseugh 1 300 train
+fvqywcoyck 1 300 train
+fvrenvmlyz 1 300 train
+fvrhhxqcmh 1 300 train
+fvrjlugmiw 1 300 val
+fvrngotufj 1 301 train
+fvroouzbry 1 300 val
+fvropcbpyq 1 300 train
+fvrvitnxqc 1 298 train
+fvrxvzfjxq 1 300 train
+fvscjrdxcd 1 300 train
+fvsnqgxrpb 1 300 train
+fvstcximqs 1 300 val
+fvsyzeycyv 1 300 train
+fvtbqagizw 1 300 val
+fvtdxqdsmv 1 300 train
+fvtgafkqys 0 301 train
+fvtgwatpwz 1 301 val
+fvtinjiwqm 1 300 train
+fvtjedjgsr 1 299 val
+fvtmnbjvyl 0 300 train
+fvudxsypdc 1 300 train
+fvufsmerkn 1 300 train
+fvugsjlvkw 1 300 train
+fvutcmepck 1 300 val
+fvuwsbciqk 0 300 train
+fvuwtdqdpe 1 301 train
+fvuxmhaowa 1 300 train
+fvuzptqoba 0 300 train
+fvvfdtnuey 1 300 train
+fvvjfvonqk 1 300 train
+fvvuzjbsqe 1 300 train
+fvvzvoommr 1 300 val
+fvwdwoqrxl 1 300 train
+fvwfayarlg 1 300 val
+fvwhpsrmwx 0 300 train
+fvwizfzopw 1 300 train
+fvwjqnwzdl 0 300 train
+fvwnppgyso 1 300 train
+fvwojbteqk 0 300 train
+fvwqdwzrcc 1 300 train
+fvwvjwtpec 1 300 train
+fvwwvkanpc 0 300 val
+fvxbwpzdyw 1 298 train
+fvxnemkmim 1 300 train
+fvxoirrpou 0 300 train
+fvxsvdyowa 1 300 train
+fvxwaazoiy 1 300 train
+fvxwpnmash 1 300 train
+fvxyegqlzr 1 300 train
+fvxzklsiux 1 300 train
+fvydbtyobg 1 300 train
+fvygagxyuk 1 300 train
+fvyopmtfmu 1 300 train
+fvypjpigxo 0 299 train
+fvyqxyrvjj 1 300 train
+fvyuztddwy 1 300 train
+fvyxjclxph 0 300 train
+fvzbrdgbzd 1 300 train
+fvzbredojh 1 300 train
+fvzfpquoxe 1 300 train
+fvznsdnabi 1 300 train
+fvzpgvbhys 1 292 val
+fvzuxliloe 1 241 train
+fvzwfxnerd 1 300 train
+fwaacpjrbi 1 300 train
+fwadhgncoa 1 300 train
+fwaxkocbeq 1 300 train
+fwaxvytpuw 1 300 train
+fwbekchfyd 1 300 train
+fwbjwypggt 1 300 val
+fwbkkigixs 1 300 train
+fwboxgwtlw 1 300 val
+fwbumhpamo 1 300 train
+fwbvksfidm 1 300 val
+fwbyrxyuyo 0 300 train
+fwcaaxpujv 0 300 train
+fwcflvujrp 1 300 val
+fwcftlpbwz 1 300 train
+fwcgtjuqgl 1 300 train
+fwciyecawr 1 300 train
+fwcsbrbbpr 1 300 val
+fwcupeteho 1 300 train
+fwczdfgprc 1 300 val
+fwdemvztva 1 300 val
+fwdoyacnai 0 301 val
+fwdtzzumqo 1 300 train
+fwdygshwtg 1 300 train
+fwecflqdjr 1 301 train
+fweczpgmok 0 237 train
+fweczwhjec 1 300 train
+fweejkryos 1 301 train
+fwefriokvv 1 300 train
+fwefyenxqk 1 241 train
+fwekcrqdak 0 300 val
+fwekhphoqr 1 300 train
+fwerqbukmq 1 300 train
+fwesgkefnw 1 300 val
+fweukjhlsg 1 300 train
+fwezlxinox 1 300 train
+fwfeduktjq 1 300 val
+fwfjzavjtz 1 300 train
+fwfswsxrcs 1 300 train
+fwgrdvshjo 0 300 val
+fwgromxnyj 1 300 train
+fwgsbstxfl 1 300 train
+fwgyckdxip 1 300 train
+fwheahaubn 1 300 train
+fwhelpsero 1 298 train
+fwhguersxb 1 300 train
+fwhnurlbyc 1 300 val
+fwhulipufw 1 300 val
+fwhybkmfty 1 300 train
+fwifdmqqjc 1 299 val
+fwijcyzosq 1 300 train
+fwijgixvsb 1 300 train
+fwikyoafxf 1 300 val
+fwimqamfst 1 300 train
+fwiostswhx 1 300 train
+fwipdcerra 0 300 train
+fwisndrpzm 0 300 val
+fwispntihd 1 300 train
+fwiugdqrwq 1 300 val
+fwixkckupe 1 298 train
+fwiyjcfwta 0 300 train
+fwiytijijg 1 300 train
+fwjfbaqaux 0 300 train
+fwjhcmqmgk 1 300 val
+fwjhcqlmfd 1 300 train
+fwjkjwelbt 1 300 train
+fwjncwwjdj 1 300 train
+fwjrgshqfj 1 302 train
+fwjrzhcina 1 300 train
+fwjsbmxkua 1 300 train
+fwjsjpgeua 0 300 train
+fwjtjsjqua 1 301 val
+fwkheapnsn 1 300 train
+fwkhjpcewv 1 301 train
+fwksvucglh 0 300 train
+fwkyxvdmff 1 300 train
+fwlakxjtip 1 301 train
+fwlkeewswy 1 300 train
+fwlzcpuuor 1 300 val
+fwmcduwcik 1 300 train
+fwmemtykfn 1 300 train
+fwmkzwfhvg 1 300 train
+fwmmofclor 1 300 train
+fwmqkcegsf 0 300 train
+fwmqyespvd 0 300 train
+fwmtqugwmc 1 300 test
+fwmvesrwou 1 300 train
+fwnetqcuit 1 300 train
+fwngrtvaee 0 300 train
+fwngwlcgva 0 300 train
+fwnirsyhwe 1 300 val
+fwnopaiuah 1 300 train
+fwnoxicsrx 1 300 train
+fwnvcplyby 1 241 train
+fwobjlcuko 1 300 train
+fwoclhwwjg 0 83 train
+fwopacxcxn 1 300 train
+fworafijyr 1 300 train
+fworxtuhyu 1 241 train
+fwosbfrsnu 1 300 train
+fwosuimbgb 1 300 train
+fwotrbpicb 1 301 val
+fwovqngwcu 1 300 train
+fwoxsbbkae 1 301 train
+fwpadpugqn 1 300 train
+fwpdcxkiqd 1 300 val
+fwpgeqpsoj 1 300 train
+fwpjhlonzg 1 300 train
+fwpmduoyot 1 301 val
+fwpoqmoihm 0 300 train
+fwpoxuktzn 1 300 train
+fwpwyxfmnw 0 300 train
+fwpzsfynpj 1 300 train
+fwqfbrlbbt 1 300 train
+fwqfzyxydh 1 300 train
+fwqglazuqh 1 241 train
+fwqgrgdfyc 1 300 train
+fwqjqstizc 1 300 train
+fwqmlsllgd 1 300 val
+fwraxwqaql 1 300 train
+fwrcfaglhz 0 300 train
+fwrdompbhm 1 300 train
+fwrpbsdywt 1 300 train
+fwrqqahezp 1 300 train
+fwrsclmglu 1 300 train
+fwrvxpcliu 0 300 train
+fwsbbpbexg 1 300 test
+fwsehsenea 1 300 train
+fwsfhblpie 1 300 val
+fwsibemzym 1 300 train
+fwsisrymhk 1 300 val
+fwslpihtpn 1 296 val
+fwsodequbf 1 300 train
+fwsoweflrs 1 300 val
+fwsrwpveom 1 300 train
+fwsshajbiq 0 299 train
+fwsvkjqyjr 1 300 train
+fwsvofuanz 1 300 val
+fwsykovroj 1 300 val
+fwsypadiom 0 300 val
+fwtcoqcqpa 1 300 train
+fwtdbskaqb 1 300 train
+fwtdhczlcq 1 300 train
+fwteknuomi 1 241 train
+fwtfiussmt 1 241 train
+fwtfmublxh 1 300 train
+fwtiviemce 1 300 train
+fwtmmkthxf 1 300 train
+fwtpnwjdkk 1 300 train
+fwtuvpkplj 0 300 train
+fwuaplnkla 1 300 train
+fwubboptri 1 300 train
+fwubtsygyk 1 300 train
+fwuhiaxtsm 1 300 val
+fwumfbmnwl 1 300 train
+fwuyplmkwg 1 300 train
+fwvaatwezp 1 300 val
+fwvownpkyp 1 300 train
+fwvvlvrenb 1 300 train
+fwvvppxhyg 1 300 train
+fwvxlivshl 1 300 train
+fwvxtssltw 1 300 train
+fwwbgwpsno 1 300 train
+fwwijwumcg 1 147 train
+fwwitihjch 0 300 train
+fwwmvfzczo 1 300 train
+fwwqqnaaka 1 241 train
+fwwrfsbqtq 1 300 train
+fwwrivmuqh 1 300 train
+fwwshmwtwq 1 301 val
+fwwtdnlnex 1 300 train
+fwwtsybelu 1 300 train
+fwwuctxzhv 1 300 train
+fwwuehpted 1 300 train
+fwwvytmqhi 1 300 train
+fwxaazwpxq 1 300 val
+fwxdstvspc 1 301 train
+fwxhfodvfm 1 300 train
+fwxkqbtuoi 1 300 train
+fwxmpjnyhc 1 300 train
+fwxrivasxe 1 298 train
+fwxumlhoma 1 299 val
+fwyfmbynyh 1 300 train
+fwygfeabor 1 297 train
+fwykevubzy 0 299 test
+fwynhpgaot 1 300 train
+fwyusptfjh 1 300 train
+fwyyhdgopb 1 300 train
+fwyztbmgeq 1 300 train
+fwzjdbzqbc 0 302 train
+fwzjqrqrnr 1 300 train
+fwzjvfcdji 0 300 train
+fwzucjkolj 1 300 train
+fwzucsmqgm 1 300 train
+fxaeljvkce 1 300 train
+fxakmcwnut 1 300 train
+fxaqkyjxcz 1 300 train
+fxaspjlsdt 1 300 val
+fxavmshodu 1 300 train
+fxawojripx 1 300 train
+fxaybijwnv 1 300 train
+fxazwvarlr 1 300 train
+fxbetgsvaa 1 300 train
+fxbfdkvhno 1 300 train
+fxbfnwdaqs 1 300 train
+fxbkyhkoyk 1 300 train
+fxbpshgzdw 1 300 train
+fxbrhdqhki 1 300 train
+fxbtekplno 1 300 train
+fxbtivvrpv 1 300 train
+fxchyvdxfo 1 300 train
+fxcmfcqroh 1 300 val
+fxcwjpvilf 1 300 train
+fxdfodrjte 0 300 train
+fxdfuxjvuh 1 300 train
+fxdkiqsvtt 1 300 train
+fxdvdnevdv 1 301 train
+fxeenvjrgc 1 300 train
+fxeqexfnbm 0 301 train
+fxeqxwrilk 1 300 train
+fxerdccmev 1 300 train
+fxesowzguc 1 300 val
+fxesqgpvhq 1 300 val
+fxeuoygimr 0 300 val
+fxevwqstoi 1 300 train
+fxezehmdkw 1 300 train
+fxezpuoxxf 1 300 train
+fxfahurhlr 1 301 train
+fxfvxqmmox 1 300 val
+fxfxrgntdt 1 300 train
+fxfxtrrkeq 0 300 train
+fxfzhprfja 1 300 train
+fxgelobnzq 1 298 val
+fxghgkfaut 1 301 train
+fxgpfayrlw 1 300 train
+fxgpgffbkt 1 300 train
+fxgufwzmzl 0 297 train
+fxgvfgrjgf 1 300 train
+fxgxlvpqrj 0 300 train
+fxhineuptm 1 241 train
+fxhqouysjy 1 300 val
+fxhszqhneq 1 300 train
+fxhvawzjfn 1 300 train
+fxiagzltmj 1 300 val
+fxiavfnacj 1 300 val
+fxicjknipj 1 300 train
+fxigvqxmay 1 300 train
+fxirbbepzn 1 300 train
+fxiwoibzty 0 300 train
+fxiyoqkyho 1 300 train
+fxjdrtulmg 1 288 train
+fxjnmtqool 1 300 train
+fxjxsksnqh 1 300 train
+fxkfgakclm 1 300 train
+fxkusvjtij 0 300 train
+fxkyhwtvrh 1 300 val
+fxlagyqpfc 1 300 train
+fxlauxuqfw 1 240 train
+fxlbozuoas 1 300 train
+fxlebirsll 1 300 train
+fxlenxiszk 0 300 train
+fxlfeiluwf 1 300 train
+fxlgoimahx 1 300 train
+fxlizjitcq 1 300 val
+fxlljvuomj 1 300 train
+fxlpqgyjfn 1 300 train
+fxlvygobod 1 300 train
+fxlxckvteg 1 300 train
+fxmbclilqj 1 300 train
+fxmermngmn 0 300 val
+fxmtcmxmzu 1 300 train
+fxmtkvitfw 0 300 val
+fxmyfnkjtl 1 300 val
+fxneiguopi 1 300 train
+fxnktbnhpr 1 300 train
+fxnlsfrytb 0 300 train
+fxocxqcnay 1 301 train
+fxokprzsjo 1 300 train
+fxolsjefko 1 300 train
+fxorstudip 1 300 train
+fxotsnhqks 1 300 train
+fxpeeqlkur 1 300 train
+fxpfpqmxcc 1 297 val
+fxpjhpdfzd 0 241 train
+fxpkitbegs 1 300 train
+fxpukmeiau 1 300 train
+fxpxrbdoyw 1 300 train
+fxqbaxxocf 0 300 train
+fxqbstfrtp 1 241 train
+fxqbtvmyaw 0 300 train
+fxqfqbploo 0 302 train
+fxqovlruio 1 300 train
+fxrbnpzkgi 0 299 train
+fxrbqdvfgc 1 300 train
+fxredodlkl 1 300 test
+fxrnjgfxyf 1 300 train
+fxrsfyyrgf 1 298 train
+fxrtkfzqcm 1 300 test
+fxrzuqcmiu 1 300 train
+fxsbsnwjfv 1 300 train
+fxscbubgdi 1 298 train
+fxseedosdt 1 300 train
+fxsiohgbap 1 301 train
+fxsjaglrba 1 300 train
+fxskypezvv 1 300 train
+fxsmedjfyp 1 300 train
+fxspxyuxpj 1 300 train
+fxsscbdili 0 300 train
+fxssrvhqmg 0 300 train
+fxsuzurfry 0 300 train
+fxszvpqldu 1 300 train
+fxtbtfmuew 1 300 train
+fxtcsxnupb 1 300 train
+fxtehfcuqe 0 300 train
+fxthuiowrx 1 300 train
+fxtncaxweu 1 300 train
+fxtrbrdcgo 0 300 train
+fxtzifovvc 0 299 train
+fxuauryvjn 1 300 train
+fxufqmljyy 1 300 train
+fxuhvgqkzy 1 300 train
+fxukgctrpd 1 298 train
+fxuokdxumd 1 300 train
+fxuxxtryjn 1 300 test
+fxvenacwft 1 294 train
+fxvghvomvg 1 300 val
+fxvlqjnjot 1 300 train
+fxvmhzhdxg 1 300 train
+fxvmngxirv 1 300 train
+fxvpthwshj 1 300 train
+fxvszitcnp 1 300 train
+fxvvifwvir 1 299 test
+fxwkgytdmo 1 301 val
+fxwnatanfs 1 300 val
+fxwptihnhr 1 300 val
+fxwvalgqaw 1 300 train
+fxxfiycemw 1 301 train
+fxxijdnbuy 1 300 train
+fxxpxoqoxp 0 300 train
+fxxtgbehdx 1 300 train
+fxxtltwcjv 1 300 train
+fxxuoebumn 1 300 train
+fxxzlfowle 1 300 train
+fxxzsqsemk 1 300 val
+fxyejryuta 1 300 train
+fxyiffuchm 1 300 train
+fxyocnnutg 1 300 train
+fxytmtdqnr 1 240 val
+fxytzqjljc 0 300 train
+fxyywidtrd 1 300 train
+fxyzxptcwb 0 300 train
+fxzabbjwbm 1 300 train
+fxzarxrrsq 1 300 train
+fxzfhxreys 1 300 train
+fxzfnwecwj 1 270 train
+fxzgjfujab 1 298 val
+fxzkbpwkto 1 300 train
+fxznkkueak 1 300 train
+fxztfonplr 1 300 train
+fxzwxldrvm 1 300 train
+fyadnomkax 1 300 train
+fyahzmskqq 0 300 val
+fyambrpmta 1 300 train
+fyarprngkd 1 300 val
+fyauzlegoc 1 300 train
+fybdhsvwjf 0 300 train
+fybfybjntb 1 300 train
+fybiztpnrc 0 300 val
+fybktcihci 1 240 train
+fybkxkgstv 1 300 test
+fybnhflvem 1 300 train
+fybtfyeeik 1 299 train
+fyburfddfd 1 301 train
+fyckocjgug 1 300 val
+fyckzjbarl 1 300 train
+fycsurqxah 1 297 train
+fycswstcos 1 300 train
+fycwtfwtdg 1 300 train
+fycyqnecsw 1 300 train
+fyddbrlyxh 1 300 train
+fydgavpooz 1 300 train
+fydhhlvjsj 1 300 test
+fydhrzyaef 1 300 val
+fydocxxmtg 1 300 train
+fydopdphla 1 300 train
+fydpoutqrt 1 300 train
+fydznpzfbo 1 300 val
+fyecpmkswr 1 300 train
+fyeffurojh 1 300 train
+fyegscnjvq 0 300 train
+fyejbwqmtw 1 300 val
+fyekwzbgyp 0 300 train
+fyetbdryma 1 300 train
+fyeurevirp 1 301 train
+fyewovfowx 1 300 train
+fyexuozvdb 1 300 train
+fyeyontcpr 1 300 train
+fyfbfguymt 1 298 train
+fyfbfwxpro 1 300 train
+fyfbkaruio 1 300 train
+fyfbkzthko 1 300 test
+fyfdxrzzga 1 240 val
+fyfkvairus 1 298 train
+fyfrdcccgk 1 298 val
+fyfrzxdwut 1 300 train
+fyfwsuzsge 0 300 train
+fygavznouh 1 302 val
+fygbkgbpwt 1 300 train
+fyghclmjqm 1 300 val
+fygjjfdcei 1 302 train
+fygviyzcjm 0 300 train
+fygvxppfvs 1 301 train
+fygxczhbsf 0 300 train
+fygydtboxr 0 301 train
+fyhehvirph 1 300 train
+fyhelwzkbd 0 300 train
+fyhjptbshw 0 300 train
+fyhpcyepmd 0 300 train
+fyhstggzjn 1 300 train
+fyhtjlxqdz 1 300 val
+fyiablknys 1 300 train
+fyihsitmmr 1 301 train
+fyiitssavx 0 300 train
+fyimoltnjm 0 301 train
+fyiokitoih 1 300 train
+fyixpghfae 1 300 train
+fyiymoftcx 1 299 test
+fyjgbylvlv 1 300 val
+fyjlkwrccv 1 300 train
+fyjpuucugl 1 300 train
+fyjqkzoqqc 0 300 train
+fyjsagezto 1 300 train
+fykblvrxon 1 299 val
+fykckdlwst 1 300 train
+fykhddltpb 1 300 train
+fykxqskzpk 1 300 train
+fylgnqtoam 1 300 train
+fyljdrthcq 1 300 val
+fylqtteoxp 0 300 train
+fyluohueyn 1 300 val
+fymagspffs 1 299 test
+fymbnorwmg 1 300 val
+fymcjvluax 1 300 train
+fymclhzqir 0 300 train
+fymicbjirh 1 299 val
+fymnzxcztj 1 300 train
+fymoarzsvd 1 299 val
+fymrkaulvl 1 300 train
+fymttpklni 1 300 train
+fymwjqqxaq 0 300 train
+fymzuitsys 0 300 train
+fynfkcgwri 0 300 train
+fynjpjpckl 0 300 train
+fynkcazgiz 0 300 val
+fynmkresaj 1 300 train
+fynuifvdva 1 300 train
+fynwgopwky 1 300 val
+fyobexyiro 1 300 val
+fyobobkkyx 1 300 val
+fyohbexunc 1 298 train
+fyokgvhoft 1 300 train
+fyooghuagw 1 300 train
+fyoxlzdchq 1 300 train
+fyphnavgxw 1 300 val
+fypipkbohl 1 300 test
+fypjghxrtd 1 301 train
+fypnwsajkt 1 300 train
+fypooqjxtx 1 300 train
+fyptlmfnog 1 300 train
+fyptulmddg 1 300 train
+fypxeollqw 1 300 train
+fyqewhljmv 1 300 train
+fyqfiffdpt 1 300 train
+fyqgmobizs 1 300 train
+fyqiaczkju 1 300 train
+fyqmdxiwdw 0 300 train
+fyqrrroisp 1 300 train
+fyqulfkhkg 1 300 train
+fyquunjfvb 1 301 val
+fyqyindnzs 1 300 train
+fyrckgsqvg 1 300 test
+fyrfjqzzpp 1 300 train
+fyrirkmosq 1 301 train
+fyrmkfymla 1 300 train
+fyrrvnknol 1 297 train
+fyscbnykgz 1 300 train
+fysehbyyjp 1 300 train
+fysmewdbqv 1 300 train
+fyswelbcdk 1 300 train
+fysyrqfguw 0 300 train
+fyszkugfxk 1 300 train
+fytefhkrtz 1 300 test
+fytexlqltu 1 300 val
+fytklttxuh 1 301 val
+fytxleslqt 1 299 test
+fyugbcukab 1 300 train
+fyuhwlsnwe 1 300 train
+fyuimnkemv 1 299 val
+fyuobqsptd 0 300 train
+fyusfacglo 1 300 val
+fyuswizrrw 0 300 val
+fyvahvegpp 1 300 train
+fyvesqrbuq 1 300 train
+fyvhatbjgc 0 300 train
+fyvofreefq 1 300 train
+fyvqniings 0 300 train
+fywawinkrw 1 300 train
+fywgfyhijp 1 241 train
+fywidktvsx 1 300 train
+fywilnmnje 1 300 val
+fywirfhzkd 1 298 train
+fywlytfnrh 1 300 train
+fywnltfutu 1 300 train
+fywtonlvda 1 300 train
+fywvtiicud 1 136 train
+fywzlzauxp 1 300 train
+fyxfffdvcg 1 300 train
+fyxjtgyezb 1 300 val
+fyxkkfdlyu 1 300 train
+fyxlqstwew 1 300 val
+fyxqbkzrkp 1 300 val
+fyxsuujljd 1 301 val
+fyxtkgmbup 0 300 train
+fyydlyaiya 1 300 train
+fyygfkcsqq 1 299 test
+fyygtwpvcc 0 242 train
+fyyjiloinb 1 300 train
+fyyplyyknz 1 300 val
+fyyverjkhn 1 300 train
+fyywteffui 1 300 train
+fyyybigduf 1 300 val
+fyyyoslpgo 0 299 train
+fyzlunqyrr 1 298 train
+fyzngynciq 0 300 train
+fyzowxqnol 1 300 train
+fyzskvkeqz 1 300 train
+fyzskwzjyd 1 300 train
+fzagllwdlb 1 300 val
+fzagsvjfne 1 300 train
+fzaiprecki 1 300 train
+fzamdqeljh 1 300 train
+fzaowpidqx 1 300 train
+fzbavlznym 1 300 train
+fzbdgzzopl 1 300 train
+fzbftmubit 1 300 train
+fzbinnlwkr 1 298 train
+fzbjwqdewk 1 300 train
+fzbmnnggje 0 300 train
+fzbphbxsza 1 300 train
+fzbtcjvjto 1 300 train
+fzbvqgrnkb 0 300 val
+fzbymmdkac 1 300 train
+fzbzmxlnue 0 300 train
+fzcahngime 1 297 train
+fzcfiyagld 1 300 train
+fzcilmlyij 1 300 train
+fzcjoeedev 1 300 train
+fzcteknomv 1 300 val
+fzcwlyhwyl 1 300 train
+fzcwtnaypl 1 300 train
+fzczwgdgwo 0 300 train
+fzczxqogem 1 300 val
+fzdfmijguq 0 300 val
+fzdftpedtk 1 301 train
+fzdkapejcq 1 300 train
+fzdkwbyuun 1 241 train
+fzdpzjenfq 0 300 val
+fzdwvvaqwg 0 300 train
+fzefoamcyz 1 300 train
+fzegrgsdky 0 298 train
+fzeigeqheu 1 300 train
+fzeitxrsnl 1 300 val
+fzeivjmput 0 300 train
+fzejmrhnzc 0 300 train
+fzeshnjege 1 300 train
+fzexdbqunl 1 301 val
+fzfeepnhca 1 300 train
+fzfhqfxnqb 1 300 val
+fzfizdqdzm 1 301 train
+fzfxglsjxr 1 301 train
+fzgcnzttkp 1 300 train
+fzgisyxqhy 1 300 val
+fzgjuskzae 1 300 train
+fzgktgqmdo 1 301 train
+fzgrzcjibn 1 300 val
+fzgxhqhttq 1 298 val
+fzgzvjzthk 1 300 train
+fzhapkipgk 1 300 train
+fzhlbtvapt 1 301 train
+fzhqmhtpug 1 301 train
+fzhsecnarn 1 300 train
+fzhsptnpbo 1 300 train
+fzhwasxjoo 1 300 train
+fzilrduycj 1 300 train
+fzilzrlrwu 1 300 train
+fzimbqtqss 1 300 val
+fzinbnljge 1 300 val
+fzisppudiw 1 300 train
+fziunnjfsj 1 300 val
+fzivosvuhl 1 302 train
+fzjagortdj 1 300 train
+fzjavaiyst 1 300 train
+fzjbinsrhx 1 300 train
+fzjgfthfer 1 300 train
+fzjitiknmg 1 300 train
+fzjnlvcelc 0 300 val
+fzjpfrlqbv 1 300 train
+fzjvdhvfhp 0 300 train
+fzkbcgpzis 1 300 train
+fzkgywjeeg 1 300 train
+fzkjhuifsb 1 300 train
+fzkzqwoghs 1 300 test
+fzlccdcgoj 1 241 train
+fzliozbuku 1 300 train
+fzllykvswe 1 300 train
+fzlmjhrjcu 1 300 train
+fzlncvobmc 1 297 train
+fzlsrdupas 1 300 train
+fzmmpujffb 1 300 train
+fzmnxvmtgh 0 300 test
+fzmwaqgrgm 1 300 val
+fzmxmncmup 0 300 val
+fznauvpcbn 1 302 train
+fznggswiag 1 298 train
+fznubemmhy 0 300 train
+fzoblaoiel 1 300 val
+fzoevqhrnz 1 300 train
+fzojvrpzhr 1 300 train
+fzordfssax 1 300 train
+fzorigtezp 1 300 train
+fzoszfqzfp 1 299 test
+fzottwanxs 0 300 train
+fzoxphygqe 1 300 train
+fzpafgyzvf 1 300 train
+fzpafwcsyj 0 300 train
+fzpcybutzy 1 300 val
+fzpdtqlchu 1 300 val
+fzphvypszf 1 301 train
+fzpjvskqwu 1 300 train
+fzprmlfevn 1 300 train
+fzqftvlmhz 1 300 train
+fzqhufhqfw 1 299 train
+fzqktfwkvu 1 298 train
+fzqnoyzhbm 1 300 test
+fzqrpeyetj 1 300 train
+fzqvwbsuze 1 300 train
+fzqwtngedu 1 300 train
+fzraggegkz 1 296 train
+fzrvjobsbt 1 300 train
+fzrxqbxrcy 1 300 train
+fzsozxkaoy 1 300 train
+fzsxcxkyjc 1 300 val
+fztnpmcexo 1 300 train
+fztpqmvlzp 0 300 val
+fztqkuewsf 1 300 val
+fztuhkkqnq 1 300 train
+fztyblwncr 1 300 train
+fzudxbwqte 1 300 train
+fzufshgeef 1 301 val
+fzufuzbgra 1 300 train
+fzurflflwv 1 300 train
+fzuthmtxud 1 300 train
+fzuxokfzaj 1 300 train
+fzuzbvzmsl 1 300 train
+fzvgnurlku 1 300 train
+fzvhplfjna 1 300 train
+fzvjfunfow 1 300 train
+fzvkuhgspa 0 300 val
+fzvpbrzssi 0 300 test
+fzvtipksxg 1 300 val
+fzvvtefkzf 1 300 val
+fzvxmpoikx 1 302 train
+fzvypfixcq 1 301 train
+fzwlnoiayp 1 300 train
+fzwnnccurn 1 300 train
+fzwqilbejm 1 301 train
+fzwwyblkli 1 300 train
+fzxbfzymhw 1 300 val
+fzxbvrjjhr 1 300 train
+fzxdlkuffg 0 249 train
+fzxnownxcz 1 300 train
+fzxpnjqmvk 0 300 train
+fzxqojwfse 1 300 val
+fzxrxhcwou 1 299 test
+fzxsggojyo 1 300 train
+fzxxkgoxhh 0 300 train
+fzyjplvkaf 1 301 train
+fzykmseklr 0 300 train
+fzyofnsblt 0 300 val
+fzyxfklyly 1 300 train
+fzyynkxrsu 0 300 train
+fzzcphdacz 1 300 train
+fzzjacougf 0 302 train
+fzzkhjbfpv 1 300 train
+fzznhjogqj 1 241 train
+fzzpipgoyl 1 300 train
+gaadspfsbw 1 300 train
+gaadxzmtfe 1 300 train
+gaamgahqze 1 300 val
+gaavzrymkc 1 300 train
+gaawsfwapc 1 300 train
+gabckzxoia 1 300 test
+gabievjorc 1 300 train
+gabjldcpoa 1 300 train
+gabjvcgjcg 1 299 test
+gabobgiccn 0 300 train
+gabriqswhu 0 300 val
+gabrzovxka 0 300 train
+gabvrvxcqc 0 300 train
+gacaonleme 1 300 train
+gacoaflpbo 1 300 train
+gacqwlypoz 1 300 train
+gacsxansvv 1 300 train
+gacszprqsr 1 300 train
+gadawfzvzh 1 300 train
+gaddgupclv 1 300 train
+gadfzjezgh 1 300 train
+gadmusygle 1 300 train
+gaevpwvusi 1 300 train
+gaexiccooi 1 302 train
+gaexxsybom 0 300 train
+gaezfjhckb 1 297 train
+gafagqaasp 1 300 train
+gaffodreks 1 300 train
+gafhgtscun 1 300 train
+gafhwdmidq 1 299 val
+gafigkpugr 0 300 val
+gafyfetmls 1 300 train
+gaggwjdwmn 1 300 train
+gagilukzul 1 241 train
+gagjgsailf 1 300 train
+gagkjwxaba 1 300 train
+gagvvmypob 1 300 train
+gahazqsucd 1 300 train
+gahgyuwzbu 0 299 test
+gahlgzjgbq 1 301 val
+gahlzfbmst 1 300 train
+gahmjgyizr 1 301 train
+gahnzfllyk 0 300 train
+gahqickpnq 1 300 train
+gahsvrgskg 1 300 train
+gahucpdonh 0 236 train
+gahyycstsi 1 300 train
+gaidetzmvz 0 300 train
+gaigzcfjzm 1 298 val
+gaiirjtvdb 0 300 train
+gaijqzszzr 1 300 train
+gaikqtxfjh 1 300 train
+gaitsfuizp 1 300 train
+gaixauyujn 1 300 val
+gajagctzzq 1 301 train
+gajfhbiakn 0 300 train
+gajiicluak 0 300 val
+gajmilwswj 0 300 train
+gajwkuimrh 1 300 train
+gajyxyuikf 1 300 train
+gajzmjfzmn 1 300 train
+gakehrooju 1 300 val
+gakgqztklr 0 300 train
+gaklwqvekk 1 300 train
+gakmbwszuz 1 300 train
+gakqrhzerw 1 301 train
+gakrxuhtfw 0 300 val
+gakukcytox 1 300 train
+gakytaaqxx 1 300 train
+galckcdeka 0 301 val
+galexkbrbv 1 300 train
+galfvidlmw 1 300 train
+galgziizsu 1 300 val
+galhckdqab 1 300 train
+galotgnfcq 1 300 train
+galoznycwp 1 300 train
+galsstznjd 1 299 test
+gambjldvlc 1 300 train
+gamdxmmfyy 1 300 train
+gamljulduh 1 300 val
+gamxligiwu 1 300 train
+ganccjaxxy 1 300 train
+ganenzsqyh 1 300 train
+ganhyrbocg 1 300 val
+gankhhhvla 1 300 train
+ganmnaujcq 1 300 train
+ganotnsspf 1 300 train
+ganrnhxvxw 1 300 val
+ganrtkkzil 1 300 train
+ganwpujrlq 1 302 train
+gaoddyxyfx 1 301 train
+gaofaacklg 1 299 test
+gaogtgroyr 1 300 val
+gaohttwiqx 1 301 val
+gaoiunanqg 1 300 val
+gaokbdmmmx 1 297 val
+gaoplfrfzu 1 300 train
+gaoryxnpuq 1 300 train
+gaozfnsrob 1 300 test
+gapdcwkfge 1 300 train
+gapqcxdinz 1 300 train
+gaptsqkaks 0 300 train
+gapumrsswx 1 300 val
+gapvetxxhl 0 300 train
+gaqskhtayt 1 301 train
+gaqudepjtw 0 300 train
+garlekfuzl 1 300 val
+garsckfzzk 1 300 train
+gartoatdqq 0 300 train
+garunulzzv 1 300 train
+garxffqklk 1 301 train
+garygrmuie 1 300 train
+garyozboal 1 300 train
+gasanqzioj 1 300 train
+gasawaljil 1 300 val
+gasbzeweme 0 300 val
+gasdqayvgc 0 239 val
+gashzkzmhq 1 300 train
+gasmofwqkp 1 300 train
+gaspumvtcs 1 300 train
+gastwpcdis 1 300 train
+gasvvkgzrr 1 300 train
+gasytaacsj 0 300 train
+gatgerfsjl 1 300 train
+gatnvnkjcw 0 300 train
+gattgtrwfa 1 300 train
+gattkmwqkz 1 300 train
+gattojytcb 1 241 train
+gatubxqouv 1 300 train
+gatycdcrtz 1 300 train
+gatywbscxn 1 300 train
+gatzlkmhqt 0 300 train
+gauasgbohq 1 300 test
+gaudqiligp 1 300 train
+gauhhhgvlk 1 300 val
+gaulesojbm 1 300 train
+gauuanvzsg 1 300 val
+gauuoevrnw 1 300 val
+gavbhjeufo 1 301 train
+gavevlsumb 0 300 train
+gavqnsbism 1 300 train
+gavqxvguhg 1 99 train
+gavqzzofqv 1 300 train
+gavrxdccvf 0 300 train
+gawakklefk 1 300 train
+gawbagazjl 0 298 train
+gawmelaiir 0 300 val
+gawomdobfg 1 300 train
+gawvjppxps 1 300 train
+gawvprhoth 1 300 train
+gawxncjdra 1 300 train
+gaxbjjqwfg 0 300 train
+gaxdvpuwju 0 300 train
+gaxroakdxd 1 300 train
+gaxvondfff 0 300 train
+gaxvqelpjf 1 241 val
+gaxvuetshr 1 300 train
+gayflwtmiv 1 300 train
+gayflzqctp 1 300 train
+gaypzhbkhd 1 300 train
+gayuuphqnh 1 300 train
+gayypjkwsg 1 300 train
+gazevuoahc 1 300 train
+gazirwytip 1 300 train
+gazjczvgew 1 300 train
+gazockikpd 1 300 train
+gazppqoeeq 1 298 train
+gazrgzbnzj 1 298 train
+gbacnojrmk 1 300 train
+gbajitryvv 1 301 train
+gbakewijef 1 298 val
+gbambjdbwq 1 300 train
+gbasowlzzy 1 300 train
+gbasqpxnww 1 298 train
+gbatfzbsjs 1 300 val
+gbawfojktc 0 300 train
+gbawgsnlgk 1 300 train
+gbawhsplpi 1 300 train
+gbbevfnfiq 1 300 train
+gbbhyicorv 0 300 train
+gbbiggebsw 1 300 train
+gbbkbmzpfl 0 299 val
+gbbohjwpnf 1 300 train
+gbboicfsdc 1 300 train
+gbbozmumxh 1 300 train
+gbbvgyokaz 1 300 train
+gbbvknwnph 1 300 train
+gbbyyfnreq 1 300 train
+gbccaaauat 1 300 train
+gbcjmtrhap 0 300 train
+gbctzhqtoe 1 300 train
+gbdazgniqc 1 300 train
+gbdfukfadr 1 300 train
+gbdiuhtvoy 1 300 train
+gbdjftsiqy 1 300 val
+gbdkebpcnc 1 300 train
+gbeldfqhsa 1 297 val
+gbensgskzr 0 300 train
+gbeqpnpwbm 0 300 train
+gbfaeroziw 1 302 train
+gbfbzuobtq 0 300 train
+gbfdzigwic 1 300 test
+gbfgwfrntb 1 300 train
+gbfhqkesql 1 300 train
+gbflagqcrg 0 300 train
+gbfqxrepqh 1 300 train
+gbfrhqtrut 1 300 val
+gbfrvlkbjv 1 300 train
+gbfshanude 1 301 val
+gbggjsdvjy 1 300 train
+gbghfjiume 1 300 train
+gbgqhufked 1 300 train
+gbgtzspdnv 1 300 test
+gbgusytpaz 1 301 val
+gbgzkigxjs 1 300 train
+gbhaewrojh 0 300 val
+gbhorztstf 1 298 train
+gbhrjiprks 1 300 train
+gbhruilniq 1 300 train
+gbidpzftta 0 300 train
+gbifwixlyi 0 301 train
+gbihejpxav 1 300 val
+gbihqnvsfa 0 300 train
+gbinyqapyk 1 300 train
+gbitckruvd 1 300 train
+gbjnngfbgw 1 301 train
+gbjsdyfmfa 1 301 train
+gbjsspptkl 1 300 val
+gbjwlaakct 1 300 train
+gbjxesicxu 1 300 train
+gbjyygymvk 1 300 val
+gbjzelewgn 1 300 train
+gbkfqgwafb 0 300 train
+gbkondzlfo 1 241 train
+gblcfivkkf 1 297 val
+gblclehusp 1 300 train
+gblgydddmq 1 300 train
+gblhevskhn 0 300 train
+gblwufwnbn 1 298 train
+gblxhrlxpr 1 300 val
+gbmjucczkl 1 300 train
+gbmkrzagpj 1 300 train
+gbmkwegeuj 0 300 train
+gbmlaazukv 1 300 val
+gbmnhqjytp 1 300 train
+gbmpdloaka 0 300 train
+gbmvyaytyn 1 300 train
+gbmxoyltlk 1 300 train
+gbnjqvxvzj 1 299 test
+gbnorhivne 1 301 train
+gbnqiddbus 0 301 train
+gbnqxhrzbi 1 300 val
+gbnyobilza 1 300 train
+gbnyqnnctw 1 300 train
+gbnzicjyhz 1 300 test
+gboffnixjn 1 239 train
+gboitkzsid 1 240 train
+gboqgdhkap 1 300 train
+gborbywvto 1 298 val
+gborudkxrf 0 300 train
+gboyvifuol 0 300 train
+gbpmdjsewd 1 298 train
+gbpvvooxhc 1 300 train
+gbpxqnjpko 1 269 train
+gbpymmkcbw 0 300 train
+gbqgarpyeh 1 300 train
+gbqkjbbshd 1 301 val
+gbqmtnsweh 0 300 train
+gbqnsqtzuf 0 300 train
+gbqotrytdb 0 300 val
+gbqrgajyca 0 300 train
+gbqrlhbtcx 1 300 val
+gbqtbmsmuy 1 300 val
+gbqycjqsqz 1 296 train
+gbrbvzzrbe 1 300 train
+gbrksustev 1 300 train
+gbrlxnzobr 1 301 train
+gbruxhoggj 1 300 val
+gbsiogtker 1 300 train
+gbslqyilvy 1 300 train
+gbslsnhhnx 1 300 train
+gbsmeiukqs 1 300 train
+gbtbgbqvuk 1 300 val
+gbtdlkjjwq 1 301 train
+gbteygceoo 1 300 val
+gbtibbevhd 1 300 train
+gbtmpohxoz 1 300 train
+gbtpsutbyn 1 269 train
+gbtrosxofe 1 300 train
+gbtyfypgab 1 300 val
+gbucvnddms 1 300 train
+gbudtlkooq 1 300 train
+gbujdhkwqg 1 300 train
+gbujloqzbk 1 300 train
+gbujnafhit 1 300 train
+gbuktdlcfz 1 300 train
+gbumfjxtdl 1 300 train
+gbuwwrezyx 1 241 train
+gbuzbvmmas 1 300 train
+gbvllwqbjl 0 300 train
+gbvpnqitbh 1 300 val
+gbvravevjt 0 300 train
+gbvzatnfvs 1 300 train
+gbwbyxszjl 0 300 val
+gbwgcufjav 1 301 train
+gbwgeareuf 1 300 train
+gbwgfjfwax 1 300 test
+gbwhyroefx 1 300 train
+gbwnfkaypl 1 300 train
+gbwxmandwi 1 300 train
+gbxdsvjcwo 1 300 val
+gbxjqabfkd 1 300 train
+gbxpizgirx 1 300 train
+gbxrzwsjjb 1 300 train
+gbybaunlwy 1 300 train
+gbycljawnz 1 300 train
+gbycqpxnhp 1 300 train
+gbyecrdgsf 0 300 train
+gbyttktwdg 1 300 test
+gbyufieidl 1 300 train
+gbzaitshmc 1 300 train
+gbzcutzxal 1 299 test
+gbzlqysnqv 1 300 train
+gbzlywtsdf 1 300 train
+gbzwrgdqto 1 300 val
+gcasyvymsk 1 300 train
+gcbczishez 1 298 train
+gcbjkxvhdf 1 300 train
+gcbjrbpuvy 0 300 val
+gcbkjyyiog 1 300 val
+gcblaqhikw 1 300 train
+gcbpjyjhpy 0 301 val
+gcbqwwtagh 1 299 val
+gcbyurxhbz 1 300 train
+gccadfefkb 0 300 train
+gcccgzpqfy 0 300 train
+gccddsbvpg 1 300 train
+gccebfimda 1 298 val
+gcchijqccj 1 300 val
+gcckmhlhfr 1 300 train
+gcclmpcwyr 1 301 train
+gccmafuwry 1 300 train
+gccnvdoknm 1 300 test
+gccrfcsgmx 1 300 train
+gccrjjpclx 1 241 train
+gccrvaoqvf 1 300 train
+gccwdwkdmb 1 300 train
+gccwwlyugi 1 300 val
+gccxepblfi 1 300 train
+gcdavsiegr 1 301 val
+gcddjditsb 1 300 train
+gcdjgrkwgh 1 300 train
+gcdlnnkzqr 1 300 train
+gcdmpgbszn 0 300 train
+gcdnxoinnm 1 300 train
+gcdqvrudks 1 300 train
+gcdtgcvyaj 1 300 val
+gcdtglsoqj 0 300 test
+gcdumxcpcg 1 300 train
+gcdyhjklzf 0 300 train
+gcefgwbdae 1 300 train
+gcegdamzda 1 300 train
+gcegrfdmlx 1 300 train
+gceguumpmu 1 300 train
+gcehhgvgft 1 167 train
+gceonicwzj 1 300 train
+gcepiamlbq 1 301 train
+gcepmukbgr 1 300 train
+gcerrazrsi 1 300 train
+gceyxaqgcz 1 300 train
+gcfitworgi 1 300 train
+gcfmmojlal 1 300 train
+gcfmnnxfil 1 300 train
+gcfoeinqbo 0 300 train
+gcfpxweapn 1 298 train
+gcgkoyodpx 0 301 train
+gcgnszddxg 1 300 val
+gcgtklypxv 1 300 train
+gcgvhckocl 0 300 train
+gchahtbjqd 1 301 train
+gchmnketsx 1 300 train
+gchrmpaqsn 1 300 train
+gchrsyioec 1 300 train
+gchvopfgcc 1 301 train
+gchvouptky 0 241 train
+gchzfflazb 1 301 train
+gcibwutsiq 1 300 train
+gcidegwthx 1 299 test
+gcimeyglpp 1 300 val
+gciucuuaou 1 300 train
+gciuoskkao 1 300 val
+gcivsrnfir 1 300 val
+gciwcltclm 0 300 train
+gcjahnvfrs 1 296 val
+gcjdhznbsc 0 300 train
+gcjdzzmibd 1 300 train
+gcjhaarqoi 0 300 train
+gcjjhkhwgr 1 300 train
+gcjmhwainp 1 300 val
+gcjmubsxtr 0 301 train
+gcjtyaqiwo 0 300 val
+gcjyccqiap 1 300 train
+gckbkqedod 1 298 train
+gckdxfrstd 1 299 test
+gckearzogi 1 300 train
+gckeefyxlu 1 300 val
+gckfzomoxu 1 300 val
+gckhgltbqw 1 300 train
+gckjflncdf 1 297 train
+gcknephknj 0 300 train
+gckpbkchdf 1 300 train
+gckregynpo 0 300 train
+gckufzoobd 0 300 train
+gckxxedcpi 1 301 val
+gclbtfzlaa 1 298 train
+gcldoijzio 1 300 val
+gclldsynbo 1 300 val
+gclwtkvmpq 1 300 train
+gcmdueikrg 1 300 train
+gcmdyoifok 1 300 train
+gcmetbviyj 1 300 train
+gcmhtnytnz 1 300 train
+gcmmtuoupw 1 300 val
+gcmognqwgz 1 240 val
+gcmrvtseyk 0 300 train
+gcmzcpuxdj 1 300 val
+gcnbfzgtnd 1 301 val
+gcnhqdxwqd 1 300 test
+gcnjwgjzae 0 300 train
+gcnrfmisda 1 300 train
+gcoacfcupw 1 300 train
+gcoelenjwy 1 300 train
+gcoeniltbg 0 300 train
+gcogydupqa 1 300 train
+gcohsfodxw 0 300 train
+gcojtjjglp 1 300 train
+gcoowkrfnv 1 300 train
+gcopbpasbm 1 301 train
+gcossjikmb 1 301 train
+gcovtngxla 1 136 train
+gcoyyxhxrw 1 300 train
+gcpbzbcmtc 1 300 train
+gcpddqcnyv 1 300 train
+gcphojsohr 1 300 test
+gcpjokmohj 0 300 train
+gcpumdtqbw 1 83 train
+gcpwisspwy 1 300 train
+gcpxhxtepn 0 301 train
+gcqgmqbcgn 1 300 train
+gcqksygrxg 0 240 train
+gcqpxoaczg 0 300 train
+gcqvmlmwui 1 300 train
+gcrdaqsyyu 1 300 val
+gcrgogpnqc 1 270 train
+gcrjszftca 1 301 train
+gcrsaesnjg 1 300 train
+gcrtuzrpih 1 300 train
+gcrvkrkxhg 1 300 train
+gcsfhgurxa 1 301 train
+gcsmgypxlb 0 300 train
+gcsmugeeus 1 300 train
+gcswhfouhz 0 300 train
+gcsyrmbjbf 1 298 train
+gcszcifzgc 1 300 val
+gcszqqslwn 1 300 train
+gctfpscwsd 1 300 train
+gcthdpvkqi 1 300 train
+gctqacnjyy 1 299 test
+gctqdocldq 1 300 val
+gctuvgzhbp 1 300 train
+gctxzlzcjz 1 300 val
+gctyynjruz 0 300 train
+gcumbzfgna 1 301 train
+gcunfgbmwp 1 300 val
+gcuowvdvhc 1 300 train
+gcusybknis 1 300 train
+gcuynrkxkh 1 294 train
+gcvahzjlbf 1 300 train
+gcvdxwvflj 1 300 val
+gcvgotmwer 1 300 train
+gcvubsplpv 1 300 train
+gcvwnekzdr 1 300 train
+gcvygxlxuh 1 241 train
+gcwcvduria 1 300 train
+gcwfgohdet 1 300 train
+gcwgedgnhj 1 300 train
+gcwgwrssmo 0 300 train
+gcwitsaxkv 1 300 val
+gcwjactfir 1 300 train
+gcwqrpelfi 1 300 train
+gcwuhlegud 0 300 train
+gcwvzhkrsu 1 300 val
+gcxexbsvot 0 300 train
+gcxsawaszs 1 300 val
+gcxwdkhxxs 1 300 train
+gcxwoablgs 1 298 val
+gcxwqrqudn 1 300 train
+gcyddrltjp 0 301 train
+gcyecnxtht 0 301 val
+gcyekbytms 0 300 train
+gcygtpbycz 1 300 val
+gcyhpylbbm 1 300 train
+gcyltgbrhb 0 299 train
+gcymjilcah 0 300 val
+gcywlndrrv 1 300 train
+gczepcsdfi 0 300 train
+gczhhclrwj 1 300 train
+gczidzghyp 1 298 train
+gczieafvpe 1 300 test
+gczmxzlzrs 1 300 val
+gcznisyuby 1 300 train
+gczrefownz 1 300 train
+gczufodzsi 1 300 train
+gczunjhxvv 1 300 train
+gdaaslzklh 0 300 train
+gdacuzdwsg 1 300 val
+gdaeedgzhc 1 300 train
+gdasaxhkwl 1 300 train
+gdattqtxmz 1 301 val
+gdavsauheg 0 300 val
+gdbcuttvqa 0 300 train
+gdbsyzybzq 1 301 train
+gdcazcwxle 1 300 train
+gdcfgdykhi 1 300 train
+gdcgedilke 1 300 train
+gdckrojffr 1 297 train
+gdcypjiwbo 1 300 train
+gddbrecqpe 1 298 train
+gdddrdqpuj 1 300 train
+gddgbvubhq 1 300 train
+gddlmdiirt 1 300 train
+gddlntsueq 1 300 train
+gddluyivyr 1 300 train
+gddtghkyjl 1 300 train
+gdedpfhbjs 1 300 train
+gdegxhncrl 1 300 train
+gdeljipddf 0 300 train
+gdelvmkpkp 1 300 train
+gdeymeoxcz 1 300 val
+gdezlfgevn 1 299 test
+gdffzrpnib 1 300 train
+gdflqpvyob 1 288 train
+gdfluugkze 1 249 train
+gdfsdtyiwv 1 300 train
+gdfvpxlrza 0 300 val
+gdfwwoeyke 0 300 train
+gdfyzwykty 0 300 train
+gdgakhttkz 1 301 train
+gdglyvqwxw 1 300 train
+gdgnnztkuj 1 301 train
+gdgokuraof 1 301 train
+gdgpzjifrc 1 298 train
+gdheecsagz 1 300 train
+gdhfelehbr 1 300 train
+gdhhyvkxea 0 300 train
+gdhjptskze 1 301 train
+gdhkrmssve 1 300 train
+gdhkzovxet 1 298 train
+gdhlrzpxxr 1 300 train
+gdholdjgur 1 300 train
+gdhpjklbol 1 300 train
+gdhplcajxw 0 300 train
+gdhtrbgmql 0 300 train
+gdimzmymbl 0 300 train
+gdirkuovmm 1 300 train
+gdisoknouo 1 296 train
+gdjavdzijx 1 300 val
+gdjcfraspf 1 300 train
+gdjkdcytlo 1 300 train
+gdjkfapyqu 1 300 train
+gdjpaoqewn 1 300 train
+gdjqajazmi 0 300 val
+gdjubugymo 1 300 train
+gdjxuwtafd 1 298 train
+gdkaedaqzo 1 300 train
+gdkbcjwshu 1 300 val
+gdkgoiufno 1 300 train
+gdkjvyugdm 1 300 train
+gdkoskvfkm 1 300 val
+gdkqgovbbu 1 300 train
+gdksctrmpk 1 300 train
+gdktohgfss 0 298 train
+gdkxsuwhtb 0 240 val
+gdkxxsjhhw 1 300 train
+gdlctdrxzs 0 300 val
+gdlgasdpzp 1 300 train
+gdlksqdiqj 1 301 train
+gdlmljpqio 0 300 train
+gdlowgeiee 0 300 train
+gdlqvwxnws 1 300 train
+gdlrmypfha 1 300 train
+gdltygmodd 1 300 train
+gdmaakgxfx 1 300 train
+gdmdyaghgf 1 300 train
+gdmhwwkmbe 1 300 train
+gdmiqdlpji 1 297 train
+gdmnnlgnpz 1 300 val
+gdmwdicgxq 0 300 train
+gdnazxhqfl 1 300 train
+gdnbcgtfay 1 300 train
+gdnfwtcnwj 1 300 train
+gdnkmubddj 1 300 val
+gdnkrokzpv 1 300 train
+gdnnieahty 1 300 train
+gdnshovdhv 1 300 val
+gdnvuhoxbi 1 300 train
+gdnwijvryh 1 300 train
+gdnzszmpjw 1 298 val
+gdofpzayvy 1 300 train
+gdohinwlun 1 300 train
+gdolzaiiih 1 300 train
+gdphxrxfpi 1 300 train
+gdpiltbyzo 1 300 train
+gdpklemybz 1 300 test
+gdpmiofjlc 1 300 train
+gdpqdtqgqs 1 300 train
+gdprdkyqtl 1 301 train
+gdpxgankmr 1 299 test
+gdpzfqbcbz 1 300 val
+gdqjbathwu 1 300 val
+gdqmfxpbtb 1 300 train
+gdqnsfgxko 0 300 train
+gdqocjhptd 1 300 train
+gdqrrpoqrg 1 300 train
+gdqudeabmc 0 300 train
+gdqvoevdtr 0 300 train
+gdqyhlzhyr 1 300 train
+gdrlutsiai 1 300 train
+gdrnynsdlj 1 300 test
+gdrqrlryeu 1 300 train
+gdrvklhatm 1 301 train
+gdrwzhtjlt 1 300 train
+gdryltaywl 1 301 train
+gdsabnjxjd 1 297 train
+gdsfgpyukl 1 300 train
+gdskjdylwz 1 300 train
+gdsnrhxjzk 1 300 train
+gdspfwhoxr 1 300 train
+gdswpwhmqz 1 300 train
+gdtiezvtgt 1 300 val
+gdtkovtsci 1 300 train
+gdtktxbggz 1 240 train
+gdtoccvupx 1 300 train
+gdtprxxigc 1 300 train
+gdtqsgckrm 1 300 val
+gdtqvcbmvp 1 300 train
+gdtsrugtyb 1 300 train
+gdudzbliss 1 300 train
+gduevksmhk 0 300 train
+gduytrhnvn 0 300 train
+gduzikqfgp 1 300 test
+gdvelhvhst 1 300 val
+gdvjbmownz 1 300 train
+gdvkbjcfbc 1 300 train
+gdvlhfxtbo 1 300 train
+gdvnljutuu 1 300 val
+gdvpcrrdlr 1 300 train
+gdvsoxwtlt 1 300 train
+gdvullcchl 1 300 train
+gdvwtuewdh 1 300 train
+gdvwygyfml 1 300 val
+gdvxumgvlx 1 301 val
+gdwbzayezx 1 136 train
+gdweubaodc 1 301 train
+gdwewinnpp 1 300 train
+gdwhuedwfo 1 300 val
+gdwjwgbyse 1 300 val
+gdwrferueh 1 300 train
+gdwsbknrdo 1 300 train
+gdwsgktixc 1 300 train
+gdwwzmiawg 1 300 val
+gdxdtlktvj 1 300 train
+gdxdurvkza 1 300 train
+gdxfsjkjci 1 300 val
+gdxgkevwkz 0 300 val
+gdxiahzyjr 1 300 train
+gdxiixwkxg 1 300 train
+gdxlfksrme 1 300 train
+gdxmaogsip 1 300 train
+gdxmwsnbmy 1 300 train
+gdxpotpoqt 1 300 train
+gdxtazndzk 1 300 val
+gdxtmbpkkh 1 300 train
+gdxvehfjas 1 300 train
+gdxxsnwnex 1 300 val
+gdxyudtqdl 1 300 train
+gdyaocjsoz 1 300 train
+gdyaozopiw 1 300 train
+gdybiahjog 1 300 train
+gdyfwudbwf 1 300 val
+gdygdvuyum 1 300 val
+gdygzrpynl 0 300 train
+gdyihbkgxp 0 300 val
+gdyijzprfv 1 300 train
+gdylvqgbdb 1 300 train
+gdyuqzmlpu 1 298 train
+gdyzyumwxi 0 300 train
+gdzgfakofw 1 298 train
+gdzgwzpopb 1 300 val
+gdziywsbpe 1 99 train
+gdzkgknauw 1 300 val
+gdzrhdyrib 0 300 val
+gdzrlvdfsw 0 300 train
+gdzsgsqbwi 1 300 train
+gdztqbjsjo 1 301 val
+gdztqqkbkg 0 300 val
+gdzuruahmi 1 300 train
+gdzwldhidi 1 297 train
+geaaanfxvt 1 300 train
+geaatldliq 1 300 train
+geacphwnra 1 300 train
+gealjblkxd 1 301 val
+geaoqcfkxr 0 300 train
+geaozduazv 0 300 train
+geatjsiejy 1 300 train
+geavdfgiir 1 241 train
+gebfeffinf 0 300 train
+gebpnpejld 0 300 train
+gebskbzmyz 1 300 train
+gebvnmmopr 1 240 train
+gebytwcsne 1 300 train
+gebzckmubg 1 300 train
+gecbjvllqd 1 301 train
+gecbtwrsqh 1 300 train
+gecdkhexge 0 300 train
+gechrjyeee 1 300 train
+gecjgfcbtn 1 300 train
+geckcgefnu 0 300 train
+geclsfdhgz 1 300 val
+gecntpiksy 1 300 train
+gecocamjwz 1 300 train
+gecrjewspu 1 300 test
+gecvxkpagm 1 300 train
+gedejjlvpw 0 300 train
+gedoblgvpy 1 300 train
+gedqjzkcjt 1 299 train
+geeawkwmgv 1 300 train
+geenabbona 1 300 val
+geesluddxj 1 300 val
+geesordzji 1 300 train
+geewtjkxwj 1 300 train
+geexmtdwck 1 300 train
+geezlngqgg 1 301 val
+geezrhjaml 0 300 val
+gefalexxdg 0 300 train
+gefeqgozld 1 300 train
+gefkyqelsf 1 300 train
+gefpmzknts 1 300 train
+gefugazrua 0 300 train
+gefuzwybfz 1 300 train
+gefwxtpjiz 0 300 train
+gefzxebncs 1 300 test
+gegbvljuyx 1 300 train
+gegckiepxa 1 300 train
+geglgdrsgp 1 299 train
+gegxhfofzt 1 300 val
+gehkxaeknz 1 300 train
+gehrtmigii 1 300 train
+gehxhshryc 1 300 train
+geidasluuh 1 300 train
+geiirsaioc 1 300 val
+geijlambge 1 301 val
+geiqigidrb 1 300 train
+gejavamxdm 1 300 train
+gejdzyjezj 1 300 val
+gejhnvzcyc 1 241 train
+gejkozphwo 1 300 train
+gejlmadrzd 1 300 train
+gejowmlplg 1 301 val
+gejqzubfqk 1 300 train
+gekfaqwxix 0 300 val
+gekhmedtbr 1 300 val
+gekjoaxhub 1 300 train
+geknowufwz 1 300 test
+gekorsskqq 1 300 train
+gekutrnohm 1 300 train
+gelawavgpw 0 300 train
+gelayxdawo 1 300 train
+geldghroix 1 300 train
+gelipfukix 1 300 train
+geloovcowz 1 301 train
+geltelsozh 1 300 train
+geluvzaxzh 1 301 train
+gemayympnw 1 299 train
+gemgyquzeu 1 300 val
+gemhcgmmev 1 300 train
+gemheimuxv 1 301 train
+gemhsfkaiu 1 300 train
+gemkhcfaka 1 300 train
+gemozjtrip 1 300 train
+gemprmgqjx 1 300 train
+gemrsgtjae 0 300 val
+gemrvqslyk 1 300 val
+gemusoofds 1 299 val
+gemwaiueno 1 300 train
+gengeeoata 1 300 val
+genkcfqsjr 1 300 train
+genmiorbeh 1 301 train
+genrhxayoj 1 300 val
+gensnfjyhm 1 300 train
+gentxvtxcw 1 300 train
+geoecvcbqf 1 300 train
+geohwppdhj 1 300 val
+geomldqoob 1 300 train
+geoocjiigk 1 300 train
+geoynczpxt 1 294 train
+geoypwfwon 0 300 train
+geozatjpcp 0 300 train
+geozjfzdlk 1 300 train
+gepgmfbdwq 1 300 train
+gepinqymub 1 300 train
+gepjrpyfpa 1 300 train
+geplejeqjr 1 300 train
+geplyqwtgx 1 300 train
+gepmsfvfrm 0 300 train
+gepsogoopi 1 300 train
+gepynjpkym 1 300 val
+gepzcywmsx 1 300 test
+geqageknla 1 300 val
+geqdqxzshg 1 300 train
+geqhoykuxf 1 300 train
+geqhqcceyz 1 301 val
+geqvxrljyg 1 167 train
+geqwbnmtbm 1 300 val
+geqyxpidke 0 300 train
+gerhijzwvq 1 299 train
+gerhnzbiag 1 300 val
+gerhwzrkhn 1 255 train
+gernycxeyx 1 300 train
+gerukdvpvk 1 300 train
+gervmbobtm 1 300 val
+gerwprlefx 1 300 train
+gesodyndok 0 297 train
+gesoljhdhx 1 300 val
+gesomtbrxl 0 300 train
+gesptqwxhe 1 300 train
+gestruivhx 1 300 train
+gesyxrfvmj 1 300 train
+geszhvgoch 1 301 train
+getdyhdytd 0 300 train
+getllmoacf 1 300 test
+getmctvhmd 1 300 test
+getnigqbls 1 299 train
+getnufqfhq 1 300 val
+getuajcsmb 1 300 test
+geturetbpy 0 300 train
+geuajeozuv 0 300 train
+geubguaunf 1 300 train
+geudtfadvo 1 300 train
+geuhmpknvu 1 300 val
+geujbzxsdd 1 300 train
+geulcwvfuy 1 300 train
+geuludgtjj 1 300 val
+gevbsktxjk 0 299 val
+gevjcllmjf 1 300 train
+gevjymsmpn 1 300 train
+gevnnuekkx 1 300 train
+gevpatgkzp 1 300 train
+gevppryqwp 1 300 train
+gevqmdrmbs 1 300 train
+gevypmzgnb 1 300 train
+gevzrlqdxd 1 300 train
+gewgfntbmn 0 300 train
+gewldlfuuq 1 300 train
+gewlpehuqr 0 300 train
+gewosinxix 1 300 val
+gewpvmacgn 1 300 train
+gexespncwo 1 301 train
+gexfmyynda 0 300 val
+gexhvhwfuc 1 300 train
+gexjksyqnd 1 300 train
+gexjlfsfnr 1 300 train
+gexkmvzsqi 0 300 train
+gexppmrhxd 0 300 train
+gexxbcqunx 1 300 train
+geyfnxroex 1 300 train
+geyhsxjtcc 1 301 val
+geypcumpig 1 300 train
+geywccqnyg 1 296 val
+gezgtvfajs 1 300 train
+gezoakwzsv 1 300 train
+gezwdkrytm 1 300 val
+gezzarnoxs 1 300 train
+gfaaqjndbr 1 300 train
+gfacqibhjv 1 298 train
+gfahvpuqzm 1 300 val
+gfaiddlczr 1 298 train
+gfajlcmxvi 1 298 val
+gfajujzoly 1 300 train
+gfaokyqycj 1 300 test
+gfaqxtsezr 1 300 train
+gfasbtjond 1 300 train
+gfassegacw 1 300 train
+gfbgpiahif 1 300 train
+gfbhoscsnl 1 241 train
+gfbkgrbbfo 1 300 val
+gfblmjoqek 1 300 train
+gfcetgkvvp 1 300 train
+gfcqnfqnkh 1 300 train
+gfcsmeihpb 1 300 train
+gfcspejcib 0 300 val
+gfcxgrmuuf 1 300 train
+gfcycflhbo 1 300 test
+gfcyeobsrl 1 300 train
+gfddktmssm 1 300 train
+gfdenskfme 0 300 train
+gfdjtbhgud 1 300 train
+gfdjzwnpyp 1 300 test
+gfdnbcqexq 1 301 train
+gfdocnszxc 1 299 test
+gfdosoqxif 1 300 train
+gfdtqxnqah 1 300 train
+gfdwncgbcm 1 300 train
+gfdyoyjuxy 1 300 train
+gfecefiqwl 1 300 val
+gfegqlgssw 1 300 train
+gfehstjqdf 0 300 val
+gfeowclwxh 1 297 train
+gfeoygbnrw 1 300 train
+gfeysgojjj 1 300 val
+gffdbqnikt 1 300 train
+gffenophsd 1 300 train
+gfffgtnndr 0 300 train
+gfflbrpncg 1 300 train
+gffszagmvi 1 300 train
+gfgbzngutc 1 300 train
+gfgcwxkbjd 0 300 test
+gfggmwdeor 1 301 train
+gfgkkmkmlf 1 301 train
+gfhazyivif 1 300 train
+gfhjnvkwsp 0 300 train
+gfhkekkrqo 1 300 train
+gfhlpjacbp 1 297 train
+gfhrlnlmja 1 300 train
+gfibmtvmko 1 300 train
+gfihjbqgvy 1 300 train
+gfikyugpkq 0 300 train
+gfimfnbobc 1 300 train
+gfimwggatf 1 300 train
+gfizjidffn 1 300 train
+gfjfprrqlc 1 300 train
+gfjqirgmlo 0 300 val
+gfjtkzoama 1 300 train
+gfjxhbqkva 1 300 val
+gfkbdgzcwp 1 300 train
+gfkdvulbfo 1 300 test
+gfknuehpse 0 300 val
+gfknvvudwk 1 300 test
+gfknxjnoyo 1 300 train
+gfkoxbfiwr 1 300 train
+gfksrieyhs 1 300 train
+gfkyliwlni 1 301 val
+gfkyxnoyhy 1 300 val
+gflaofider 0 300 train
+gflhlvhqyl 0 300 train
+gfljehkmmu 1 300 train
+gfloefwszv 1 300 train
+gflpvwmxnp 1 300 train
+gfluyuhrwh 1 300 train
+gfmcshmvmw 1 300 train
+gfmeutlfzy 1 300 train
+gfmpiplnhe 0 300 train
+gfmqlukrho 1 300 train
+gfmtfdcecc 1 300 train
+gfnbbumvmb 1 300 train
+gfncmhgdio 1 300 test
+gfngporvaq 1 300 train
+gfnjzkjhkb 1 300 train
+gfnluvggfr 1 300 train
+gfnogmttzx 0 300 train
+gfnolbzyzb 1 300 train
+gfntxelhke 1 300 train
+gfnxzjcmsi 1 301 train
+gfnyxvxkjn 1 300 train
+gfoalmzxns 1 298 val
+gfoatmznbh 1 300 train
+gfoozygynw 1 300 test
+gfoxjnwdfy 1 300 train
+gfpasurfnl 1 300 train
+gfpjefyext 0 300 train
+gfpkrucyku 1 300 val
+gfpluqxhri 1 298 train
+gfpmnpqezr 1 300 val
+gfpnrxnpfl 1 300 train
+gfpozoswxm 1 300 train
+gfpqtrphql 0 300 val
+gfpuzizann 1 300 train
+gfqaqqwrne 1 300 train
+gfqaynzbve 0 300 train
+gfqchyflkn 1 300 train
+gfqfhekwks 1 301 val
+gfqglolpbf 1 297 train
+gfqgmpkohd 1 300 train
+gfqrxpjovp 1 300 train
+gfqtcgrchy 1 300 train
+gfqzxjhxrh 0 300 train
+gfrksvjiru 1 300 train
+gfrpokslat 1 300 train
+gfrqcbyfzu 0 300 train
+gfrraqliuv 1 300 train
+gfrugjuusa 1 300 train
+gfruxwvrun 1 300 train
+gfryibbugx 0 300 train
+gfrziaznmk 0 300 train
+gfrzzjzbix 1 300 train
+gfsbxfszdq 1 300 train
+gfsfubmefw 1 300 train
+gfsognaxis 1 300 train
+gfsoiepxno 1 300 test
+gfsoodajup 1 300 train
+gfsqwdiuca 1 239 train
+gfsxrnrsmh 1 300 val
+gftdzhtvuc 1 300 test
+gftfgyjtad 1 300 val
+gftjxemklb 0 300 val
+gftkrnewfv 1 299 test
+gftnimdbet 1 300 train
+gftwbbuetj 1 300 val
+gftyncfpyv 1 300 train
+gfuxpqxlka 1 301 train
+gfuygpilca 1 300 train
+gfvalvcupm 1 300 val
+gfvfxjsbzk 1 300 train
+gfvntlfocz 1 300 train
+gfvqybxcrk 1 300 test
+gfvscfsgcz 1 300 train
+gfvubnkpwg 1 300 train
+gfvvtsfyqw 1 300 train
+gfvwixsfok 1 300 train
+gfvxeotdoq 1 300 train
+gfwcyqhfhd 1 300 train
+gfwdfljehv 1 301 val
+gfwgmmwylo 1 300 train
+gfwkutmilw 1 302 val
+gfwkvaxemc 1 300 val
+gfwooeihwn 1 298 train
+gfwuebiijb 1 300 train
+gfwypxolgv 1 300 val
+gfxanupdkr 1 300 train
+gfxfgqgeda 1 300 train
+gfxgutbdbg 1 300 train
+gfxjvuslgu 0 301 val
+gfxkhsgbwm 0 300 val
+gfxlmbnrnn 0 300 train
+gfxnuidfgl 0 300 train
+gfxppzkkjz 1 298 val
+gfxrszkghe 1 300 train
+gfxugcttnb 1 300 train
+gfxvabsczy 1 300 train
+gfxvkyrlgw 1 300 train
+gfxvycuaaf 1 301 val
+gfxxiesepp 1 300 train
+gfxylnastd 1 300 train
+gfybtjkgux 1 300 train
+gfyddgpncx 1 298 train
+gfyhbcbqkf 1 300 val
+gfykmuxjwi 1 300 val
+gfylkbyaub 1 300 train
+gfymlmionj 1 300 val
+gfymynrsrp 0 300 train
+gfyrsyoruy 1 300 train
+gfytrevkup 1 299 train
+gfyvxymwne 1 300 val
+gfzhgkonqc 1 300 train
+gfzleovdnl 1 300 train
+gfzlmfzshm 1 241 train
+gfzpimkdtk 0 300 train
+gfztiqsgak 1 301 train
+gfzumblluu 1 300 train
+ggagtqivwl 1 300 train
+ggaodfzuoq 1 298 train
+ggaqeypwsc 1 300 train
+ggaqhnyqeh 1 300 train
+ggartvwnks 1 300 val
+ggauoquwzr 1 300 train
+ggbutwtdet 1 300 val
+ggbxcxlmpa 0 300 train
+ggcamrhgog 1 300 train
+ggcebvaqzv 0 300 val
+ggczqvwflj 1 300 train
+ggczqzzmzf 0 300 train
+ggdddxaxdg 1 300 train
+ggdettjwbn 1 300 train
+ggdicgpeis 0 300 train
+ggdlbywogq 1 300 val
+ggdlojhunz 0 300 train
+ggdpclfcgk 1 300 test
+ggdpjgafmp 1 300 test
+ggdqutlsto 1 301 train
+ggdtngvavm 1 300 train
+ggdusgedpj 1 300 train
+ggdvqcueyq 1 300 val
+ggedetbntc 1 298 train
+ggeeikpgel 1 301 val
+ggeiapygvj 1 301 train
+ggetxayhxf 1 300 train
+ggexwlqpfb 1 301 val
+ggeznaevle 0 300 train
+ggezryqyox 1 99 train
+ggfbfcjhts 1 300 train
+ggfffumvgm 1 300 train
+ggfjeqqkve 1 300 train
+ggfookethx 1 300 val
+ggfpgxixvp 1 300 train
+ggfrauhqox 1 300 train
+ggfumkidhc 1 300 train
+ggfxkaqbvz 1 300 train
+gggefkrjgw 0 300 train
+ggggxxuijb 0 300 train
+gggprdifcs 1 300 train
+gggulbfxxa 1 300 train
+gggwezjwxm 1 300 val
+gggxkzqtvh 0 301 train
+gggzwojfid 1 300 val
+gghfyqgkho 1 300 val
+gghgnshuys 1 300 train
+gghhmtxnle 0 300 train
+gghimiqmte 0 300 train
+gghjoyllyg 1 298 val
+gghmemueoc 1 300 train
+gghzrlsfiw 1 301 val
+ggidelgrej 1 601 train
+ggidptmvad 1 241 train
+ggiheutqqm 1 241 train
+ggikzpyiuh 1 300 train
+ggiofuenqc 1 300 val
+ggipmoifjz 0 300 train
+ggiqapvqqb 1 300 val
+ggirmwcnvt 1 300 train
+ggixlxkzqj 1 300 val
+ggjareyaqd 1 300 val
+ggjcqyuelz 1 300 train
+ggjcrroblk 0 300 train
+ggjhlchtkr 1 300 val
+ggjoiareel 1 300 val
+ggjotynsyj 1 300 train
+ggjweeongm 1 300 train
+ggkanvgvud 1 300 train
+ggkkhkxnyd 0 300 val
+ggknbwmbci 1 239 train
+ggkpameyuq 1 300 train
+ggkqxiafij 1 300 train
+gglgculrjf 1 300 train
+gglmogiyph 1 300 train
+gglpvgilzq 1 300 train
+ggltfenzwo 0 300 train
+gglukbwbin 1 300 train
+gglwyvfkjn 1 300 val
+gglylxdvoh 1 300 train
+ggmcepsdne 1 300 train
+ggmwrkxbwx 1 300 train
+ggndifbnjj 1 300 train
+ggnhvrlapb 1 300 train
+ggnirqyiwl 1 300 train
+ggnjejeroj 1 300 val
+ggnkmvyrts 1 300 train
+ggnopmtuuw 1 300 val
+ggnpdozstl 1 100 train
+ggnvttttrk 1 300 train
+ggnxllgjnk 1 241 train
+ggnyicrmrd 1 300 val
+ggodqsjxiy 1 300 train
+ggoiotxooh 1 300 train
+ggoodqnnlx 0 300 train
+ggoqgxhzri 0 299 val
+ggotdfscvn 1 300 train
+ggovduycmx 1 300 train
+ggpatqrzyk 1 299 train
+ggpcjkbsug 1 300 train
+ggpfchdgjx 1 300 train
+ggprhtkjyo 1 300 train
+ggptivzlzs 1 298 train
+ggpuxwhpri 0 300 train
+ggpxsyidcv 0 300 val
+ggqmajrlid 1 300 train
+ggqmwmunyd 0 300 train
+ggqqdwkqns 1 301 val
+ggqqpnyxlw 1 300 train
+ggqugxetdb 1 298 val
+ggqyzrsoys 0 300 train
+ggrahjjegi 1 298 train
+ggrcbforax 1 300 train
+ggrckhjhdq 1 301 val
+ggrjernpmp 1 300 val
+ggrmgkmvkt 1 300 train
+ggrmihpsqs 1 300 train
+ggrsoflwyw 1 300 val
+ggrtkttlxv 1 301 train
+ggrxjcllnh 0 300 train
+ggrxjfxdxm 1 300 test
+ggrxvrbnyo 1 300 train
+ggryyavspl 0 300 train
+ggsaqsblvu 1 300 train
+ggsdoijlrj 1 300 train
+ggsdtwymbi 0 300 train
+ggsffylodm 0 300 train
+ggspsadinj 1 299 train
+ggstpfcoet 1 298 train
+ggsxziisgs 1 300 train
+ggszlsmtzr 1 300 train
+ggtkryypyq 1 300 train
+ggtnceondd 1 300 val
+ggtodztkbr 1 300 val
+ggtskzavxn 1 300 train
+ggtwbjkxic 0 300 train
+ggubnctfmv 1 300 train
+ggueyqbwdc 1 300 val
+gguhazxafh 1 300 train
+gguienkjpv 1 300 train
+gguoyfaict 1 300 train
+gguwkagcjj 0 300 train
+ggvckdofhr 1 300 train
+ggvesetbsq 1 300 val
+ggwbywpkyf 1 300 train
+ggwflckbkv 1 300 val
+ggwhsuyvrb 1 292 train
+ggwmjfhixc 1 300 val
+ggwxcsfecd 1 300 train
+ggxeqmluxk 1 300 train
+ggxnoktlbx 1 300 train
+ggxrftsibq 1 300 train
+ggxtqzicfv 1 300 train
+ggxvpmqrar 0 298 train
+ggyaqmukyz 1 300 val
+ggyogngves 1 300 val
+ggysrtzwya 1 300 val
+ggyxpodbxd 0 300 val
+ggyywqwgfa 1 300 train
+ggyzxaauyn 1 300 val
+ggzcegccry 1 300 train
+ggzdsgkynq 1 300 train
+ggzevzsphw 1 300 train
+ggzjfrirjh 0 300 test
+ggzjjvtbla 1 301 train
+ggzkujqned 1 300 train
+ggznlcjsce 0 300 val
+ggztcrvmpq 1 300 train
+ggztixcdmk 1 300 val
+ghaaghrpfp 1 300 train
+ghacquqxvk 1 300 train
+ghaflaudsh 1 300 train
+ghakpjzgzi 0 300 train
+ghanyvkhnw 0 300 train
+gharjdksox 1 300 train
+ghatbspdri 1 300 val
+ghaztjdokh 1 300 val
+ghbbxgxefw 0 300 train
+ghbdaxbuqo 1 300 train
+ghbdaznixj 1 300 train
+ghbdsirsbi 1 241 train
+ghbfpexnaf 1 300 train
+ghblebwnfv 1 300 train
+ghbmrhqloy 1 300 train
+ghbqrfvxyy 1 300 train
+ghbspecnbo 1 301 val
+ghbuegqmde 1 300 train
+ghcaleoimk 1 300 train
+ghccalazpw 1 300 train
+ghccycttqk 0 300 train
+ghcdldcwjo 0 300 train
+ghcekqgunn 1 300 train
+ghckjmudob 1 300 train
+ghcmrdcqdf 1 300 train
+ghcohywjmj 1 300 train
+ghcpiykyjr 1 300 train
+ghctpbhdmc 1 299 train
+ghcudkoxwm 1 300 train
+ghcyuftdul 1 300 train
+ghdfnhqbvc 1 300 train
+ghdhszxmtz 1 300 train
+ghdicklvxv 1 299 test
+ghdiqahfhm 1 300 train
+ghdjdbxsar 1 300 train
+ghdjltrbdf 0 300 val
+ghdnkrcswu 1 301 train
+ghdpzteruc 0 300 val
+ghducagiqq 1 300 train
+ghdzkyckfg 1 300 train
+ghecwonhbq 1 300 train
+ghejgqfcqo 1 300 train
+ghemhaebio 0 300 train
+gheosvymay 1 300 val
+gheozjcomi 0 301 train
+gheuivvcfb 1 300 val
+ghevcqpcur 0 300 train
+ghevcrdmyq 1 300 val
+ghewxwkovt 1 298 train
+ghfnznqrvh 0 300 train
+ghfplztvht 1 300 train
+ghfsdbbxsx 1 300 train
+ghfsyhxlpe 0 302 train
+ghfttccnuc 1 300 val
+ghftvokhfs 1 300 train
+ghfxstqdcg 1 300 train
+ghgamwwpbp 1 300 train
+ghgdaoqfpk 1 300 train
+ghgeryirlf 0 300 train
+ghggqtxadl 1 300 train
+ghgjvqykys 1 300 val
+ghgkkxaarr 0 300 val
+ghgomrssja 1 300 train
+ghgpmlurvy 1 300 train
+ghgqgeogeq 1 300 train
+ghgvboxnnx 0 300 train
+ghgvpehrpa 1 301 val
+ghgzkkxlzk 1 249 train
+ghhgflrjpe 1 300 train
+ghhgukmjbw 0 300 train
+ghhkuajlex 1 300 train
+ghhlgtzlqk 1 300 train
+ghhmymwxom 1 300 val
+ghhqnjnzjr 1 300 train
+ghhusaytrg 1 300 train
+ghhzuigsjj 1 300 train
+ghiftcsrvp 1 298 val
+ghikdlhgxy 1 300 val
+ghilwywnfc 1 241 train
+ghivncurcy 1 300 train
+ghiyahnnns 1 147 train
+ghjbabxvsz 1 300 train
+ghjellrvet 1 300 test
+ghjgyogfmw 1 300 val
+ghjmxjwjak 1 300 val
+ghkgoxibpn 1 300 train
+ghkjkvbqpx 1 300 val
+ghkneplejt 1 300 train
+ghlanypjyl 1 300 train
+ghlcvcejtq 1 300 train
+ghloqxiowq 1 300 train
+ghlsgkhffa 1 300 train
+ghmansehag 1 300 val
+ghmbtusjrn 1 300 train
+ghmcmskckw 1 300 train
+ghmdirbfiz 1 300 train
+ghmjkotnvs 1 240 val
+ghmmihldqh 0 237 train
+ghmuxnsxpg 1 300 train
+ghncfauixn 1 300 test
+ghndqyhsuw 1 300 train
+ghnfaxufct 1 300 train
+ghnkqqegld 1 300 train
+ghnmjlwvlz 0 300 train
+ghnnpvzrdq 1 297 train
+ghnorxskyg 1 300 train
+ghnpsltzyn 1 299 test
+ghnrfluepy 1 300 train
+ghnyfsuudy 0 300 train
+ghocibrroi 0 300 train
+ghofdqlnjz 0 300 train
+ghonxsanvu 1 301 train
+ghpebcfeua 0 300 train
+ghphekvkbz 1 301 train
+ghpmajvcsk 1 299 val
+ghpnfodcij 0 300 train
+ghptdzpuae 0 300 train
+ghpwbvqmur 1 300 train
+ghpybzyahf 1 299 train
+ghpzlzqjdt 1 300 train
+ghpztgufxc 1 297 train
+ghqalspmvk 1 300 train
+ghqcuwnvwu 1 300 train
+ghqepbcmgb 1 300 train
+ghqghysxuj 1 300 train
+ghqgyzbcdb 1 301 train
+ghqrlhpfrj 1 300 train
+ghquawtnge 1 300 val
+ghrcmocyhe 1 300 train
+ghrfkqaybt 1 300 val
+ghrncawfze 1 300 train
+ghroxiulze 1 300 train
+ghrspbvgpl 1 301 train
+ghrsshxpft 1 300 train
+ghrtrdpihj 1 300 train
+ghsdcolcub 1 301 train
+ghsfbvgpeu 1 300 train
+ghsrimvdxg 1 300 train
+ghsvaypraa 0 300 train
+ghtcyyganj 1 300 val
+ghtdqnqrao 1 300 val
+ghtfslplgo 1 298 train
+ghthkhieam 1 300 train
+ghtidwbjzm 0 302 val
+ghtngvjjyb 0 300 train
+ghtvherfda 1 301 val
+ghtzjwvato 1 300 train
+ghudxtepmp 1 300 train
+ghufymcgox 1 300 train
+ghujdkstry 0 300 train
+ghurwsplvw 0 300 train
+ghutxxwjrs 0 300 train
+ghuxwstlxu 1 300 train
+ghvemfqfjw 1 300 train
+ghvgnmbbgt 1 299 val
+ghvgyhoazl 1 300 train
+ghvoszafzz 1 300 train
+ghvrhygweg 1 301 train
+ghvrphnvod 1 300 train
+ghvwhybdoo 1 300 train
+ghwdlytvcp 0 300 train
+ghwfbvheob 0 300 train
+ghwirftxfd 1 300 val
+ghwlogkoic 1 300 train
+ghwrtcenkm 1 300 train
+ghwvzxxsol 1 300 train
+ghxbpouprn 1 298 train
+ghxkoghced 1 300 val
+ghxqlgxlak 1 300 train
+ghxtavbzwn 1 300 train
+ghxwaxtmch 1 300 train
+ghxzsygiou 1 300 train
+ghxzvovygq 1 300 val
+ghydpthmab 1 300 train
+ghyhtphxvd 1 300 train
+ghyocdqirx 1 300 train
+ghyqfwpdsy 0 300 train
+ghyrcgfuyu 1 300 train
+ghysqipxsg 0 300 train
+ghytanpsjl 1 300 train
+ghyxplmidg 0 300 train
+ghzdopwyiu 1 300 train
+ghzjrgvpgs 1 300 train
+ghzkozfife 1 300 train
+ghzlnfxcai 1 298 train
+ghzndbmaxd 1 300 train
+ghzsgegzmj 1 300 train
+ghzsvoqrqo 1 298 train
+ghzziybqbl 1 300 train
+gianjluesv 1 301 train
+giatedowhb 1 300 train
+giaxcllaww 1 300 train
+giccvzegww 1 241 train
+gicfnusnlu 1 300 train
+gickejlshd 1 300 train
+giconfoumy 1 299 val
+gicqpeyqxs 1 301 train
+gicxfrpaqr 1 147 train
+gidecugryj 1 300 train
+gidgefyeda 1 300 train
+gidlgctluk 1 299 train
+gidndqlhrj 1 300 train
+gidsqloxud 1 300 train
+gidxwntcpc 1 300 train
+gidzmerohb 1 300 train
+giebymunak 1 300 train
+gieenhizuv 1 300 train
+gieeufulqu 1 300 val
+gieeuqyemn 1 300 train
+gieizdhveg 1 300 train
+giejrvilhz 1 300 train
+giejwugzgw 0 300 train
+giekchmuor 1 300 train
+gielahnxqm 1 300 train
+gienxrngas 1 300 train
+giezcerlnl 1 301 train
+gifhctjtdd 1 300 train
+gifhnfuehc 1 300 train
+gifuxzdctf 1 300 train
+gigedpsomq 1 300 val
+gigfwgojui 0 300 train
+gigkljbtnw 1 300 train
+giglesjcgp 1 300 train
+gigndbyvbq 0 300 val
+gigpsuvprx 1 300 train
+gigwslaimd 0 300 train
+gihchuwvgk 1 300 train
+gihcxpfpxm 0 300 train
+gihexgwuyu 1 300 train
+gihkwuicag 1 295 train
+gihrtdehll 1 300 train
+gihvlmnkrk 1 300 train
+gihwqgflcb 0 301 val
+gihwsybrtq 1 300 train
+giibefqnop 0 300 train
+giifcztofo 1 300 train
+giifpbniet 0 300 train
+giifsokhhn 1 300 train
+giipqtomid 0 300 val
+giiqkndkqd 1 300 train
+giiunfhqki 1 300 train
+giivbedwpe 1 298 train
+giivxwonhm 1 300 val
+giiyrvgxow 1 300 train
+gijeixtykp 1 300 test
+gijhikberv 1 300 train
+gijhwzgrae 1 300 train
+gijoffsifw 1 300 val
+gijpcntrct 1 300 train
+gijsxmpjlg 1 300 train
+gijxbirvek 1 300 train
+gijybounnm 1 300 train
+gikewntjco 1 300 train
+gikmxcttwc 0 300 train
+gikpagtynb 1 300 val
+gikpoavimq 1 300 train
+giktkmgmhk 1 300 train
+giktmstzmd 1 300 train
+gikvkmkzzq 1 300 train
+gikvlbvbxp 1 298 val
+gikvndheth 1 300 train
+gikxuiegss 1 300 val
+gikyszehvz 1 300 train
+gilasrzvld 1 239 val
+gilecbqoai 1 299 train
+gillhgnfvf 0 300 val
+gilrccufxa 1 299 train
+giltcfzgll 1 300 train
+giluddfepf 1 300 train
+gilvyncglg 1 301 train
+gilzdnbpep 1 300 val
+gimbpphhrr 1 241 train
+gimfdwnnpj 1 300 train
+gimicsnzcw 1 300 train
+gimlsvemvh 1 301 train
+gimnmsjgtd 1 298 train
+gimqjixlbw 1 300 val
+gimvvkhqyi 1 300 val
+gimwbgvvom 1 300 train
+gimzgukfzj 1 300 train
+gingvkhmlk 1 300 train
+ginncihbhq 1 300 train
+ginsggyqvz 1 298 train
+gintrwsusw 1 300 train
+giodglqpmb 1 300 train
+gioezbvhxf 1 300 train
+giogibymva 1 300 val
+gioiwjsmlm 1 299 train
+giolodnzfy 1 300 train
+giolphechf 1 300 train
+giookzwddi 1 300 train
+giotmdtgyr 1 300 train
+giovidjytb 1 288 train
+gipbyjfxfp 0 300 train
+gipcvghjiy 1 300 train
+gipfkeghvn 1 300 train
+gippiwzoqp 1 300 test
+giptaunzou 0 300 train
+gipxxepkvv 1 298 train
+giqifsjjxl 1 241 train
+giqiwbgyta 1 250 train
+giqjuakuhp 1 300 train
+giqkvwisoa 0 300 val
+giqkxpmivw 1 296 val
+giqncczwue 0 300 val
+giqpgpcnaz 1 300 train
+giqrgbebdx 1 239 val
+giqtpvcsxq 1 300 train
+giraumitbx 1 300 val
+girddcvdqx 1 300 train
+girdmnxgdk 1 300 val
+girdwtjwsr 0 300 train
+girejtgmau 1 300 train
+girfitjjsl 1 300 train
+girghalxfh 1 300 train
+girkmwcvwi 1 300 train
+girmrmiima 1 301 train
+girnnjpjdi 1 300 train
+girqoxcmtq 1 300 train
+girzvnxxos 0 301 train
+gisbgacysy 1 300 train
+gisdkkmmzv 1 300 train
+gisfmijhfw 1 300 train
+gislefqaqw 1 300 val
+gislivuscz 0 300 train
+gistqrdixw 0 300 train
+gisyqwestz 0 300 train
+giszjpgpmy 1 296 train
+gitefceugq 1 300 train
+githmjsfmx 1 300 train
+gitiljsfye 1 300 train
+gitiqxqezk 0 300 train
+gitkrmxuyy 1 300 train
+gitkzyghyd 1 301 val
+gitzqrhmqk 1 300 val
+giukznfuwl 1 300 train
+giulbigphi 1 301 val
+giunujatma 1 300 train
+giuuovfuot 1 300 train
+giuymhlbyo 1 300 train
+givefnvwzm 1 298 train
+givncjvgwa 1 300 train
+giwdadrdqn 1 300 val
+giwdwlrvny 1 300 train
+giwjazktru 1 300 train
+giwobcepvb 0 300 train
+giwqsildya 1 300 train
+giwqysnrlo 1 300 train
+giwvqjhljm 1 296 val
+giwwoaeuzi 1 300 train
+giwwrlbsjc 1 299 train
+giwyisyggg 1 300 train
+gixdxjcfoo 1 300 train
+gixhvsbvai 1 300 val
+gixreeumkk 0 300 train
+gixwixhbbm 1 269 train
+gixyykcasv 0 300 val
+gixzxhsyca 0 301 train
+giyaskmmnz 1 298 train
+giychaqfyt 1 298 train
+giyfxltkwm 1 301 train
+giymbyjqgv 1 300 train
+giyorutrsk 1 300 train
+giyqwoixhf 1 300 train
+giyrmesary 1 300 train
+giyzvhswtk 1 299 test
+gizcfcimtn 1 300 train
+gizdnpoyar 1 300 val
+gizglcxnyj 1 300 train
+gizhkoazgo 1 300 train
+giziheudgy 1 300 train
+gizxuxfblo 0 300 train
+gizzgtdvkh 0 300 train
+gjadwclfiq 0 300 train
+gjajilhbik 1 300 train
+gjakvggxai 1 300 val
+gjanedngde 0 300 train
+gjaqtwlpbc 1 241 train
+gjargkjnrm 1 300 train
+gjarvidhvr 0 300 train
+gjasrapdle 0 300 val
+gjawiqxpca 1 300 train
+gjbcpsqzhi 1 241 train
+gjbjkzexqr 1 300 train
+gjblcbiffo 1 300 val
+gjbqdxmeio 1 300 val
+gjbzshswtg 1 300 val
+gjcbovtuii 1 300 val
+gjcfofeizi 0 300 val
+gjcsowzglh 1 300 train
+gjcvhdeciv 1 300 val
+gjcxtgehsr 1 300 train
+gjczflelao 1 300 train
+gjddgibaqi 0 300 val
+gjdencqooc 1 241 train
+gjdkrqtaze 1 300 train
+gjdpqgyxec 1 300 val
+gjdscgzxmd 1 300 train
+gjdsnrjfcb 1 300 val
+gjdydmipbr 1 300 train
+gjelwuzmza 1 300 train
+gjemceigsr 1 301 train
+gjervzutuq 1 300 val
+gjewehvqaz 1 300 train
+gjfalsooax 1 300 val
+gjfkjtpnks 0 300 train
+gjfmfiivsi 1 300 train
+gjgbtyjcgk 1 300 train
+gjgcvkyuia 1 300 train
+gjgessyjcd 1 300 train
+gjgoygdfbg 1 298 train
+gjgqtllwqz 0 300 train
+gjgrdqbvgi 1 300 val
+gjhbbofhty 1 300 train
+gjhfzhwbhs 0 300 train
+gjhtfuirui 1 300 train
+gjihqrthob 1 300 train
+gjilzybdqq 1 302 train
+gjiwengygm 1 300 train
+gjiziopvis 1 300 test
+gjjaralgjc 1 300 train
+gjjcavqoql 1 300 train
+gjjfnlhmid 1 300 train
+gjjhjqlxuz 1 300 train
+gjjkfoedrj 1 300 train
+gjjpzsgigh 1 300 test
+gjjthwadta 0 300 train
+gjjvdnsuwx 0 300 val
+gjjxjtgugw 1 300 train
+gjkcibkkni 1 300 train
+gjkltyiztd 0 300 train
+gjkwoywtup 1 299 train
+gjkxiicoti 0 300 train
+gjleolwbwr 1 300 train
+gjlgmhbijf 1 298 train
+gjlkjqjydy 1 300 train
+gjllmtwpfe 1 300 train
+gjlmodbnve 1 300 train
+gjlrssvqkt 1 300 test
+gjltbcfqyt 1 300 train
+gjltgyqgtj 1 300 train
+gjlwmegnzg 1 301 train
+gjlybpbmjp 0 300 train
+gjmcfoklto 0 300 train
+gjmexxpisv 1 299 train
+gjmpseimsk 1 300 train
+gjmurvxuiz 0 300 train
+gjnbeezbbl 1 300 train
+gjnjhayuee 1 300 train
+gjnokchhap 1 300 train
+gjntzhnptv 1 300 val
+gjnuepqpjj 1 300 val
+gjogakckau 1 301 train
+gjosxszgnt 1 300 train
+gjoyzwhzlt 1 300 train
+gjpaiqwkpq 1 300 train
+gjpgknrsoo 1 300 train
+gjpgsfjwpf 1 300 train
+gjppvbicme 1 300 train
+gjpqfgxtfy 1 300 train
+gjprzaslhz 1 300 train
+gjpwfjpqvn 1 300 train
+gjpwgikkrw 1 300 train
+gjqfdaygww 1 300 train
+gjqgalcnku 1 300 val
+gjqmuceibb 1 300 val
+gjqsogruom 1 241 train
+gjrddhgogi 1 300 train
+gjrhxmdgih 1 300 train
+gjrkpbhyvs 1 300 train
+gjrozufnaj 0 300 train
+gjrpsnkhie 1 301 train
+gjrrbutmqx 1 249 train
+gjrvzvuvty 1 300 train
+gjrykiltfr 1 300 train
+gjsaonfgqo 1 300 train
+gjsbrpjioy 1 300 train
+gjsegbhdyf 1 301 train
+gjsfvahwuh 1 300 val
+gjshfuzqtc 1 300 train
+gjsirkzrwe 1 300 val
+gjspakhxem 1 300 train
+gjszqpngyq 1 299 test
+gjtctcytbn 1 300 train
+gjteaavapx 1 300 val
+gjtfzpmyxd 1 301 val
+gjthassixk 1 300 train
+gjtjgfhfut 1 300 train
+gjtjluifwf 1 300 train
+gjtlexrvrj 1 295 train
+gjtmyodkes 1 300 train
+gjtnmhndmx 0 300 val
+gjtsqbtrvy 1 300 val
+gjtvijfxck 0 297 val
+gjtxrhhbiu 1 300 train
+gjuxgvgktl 1 300 train
+gjvbyzpnaz 1 294 train
+gjvgtyndzw 1 298 train
+gjvhyjlskk 1 300 train
+gjvhzdnmnb 0 300 train
+gjvjnmoabk 1 300 train
+gjvnkbteme 0 300 train
+gjvqsomuyl 1 300 train
+gjvwjhesgg 0 300 val
+gjvyamemgm 1 298 train
+gjwflvsjtj 1 300 train
+gjwgmqislt 1 300 val
+gjwjxdnaip 1 300 train
+gjwkbkyvjg 1 300 train
+gjwolfjlrj 1 297 val
+gjwoohigbk 1 300 train
+gjwpzvzfgd 1 300 train
+gjxbkmhegg 1 300 train
+gjxbuydeyq 1 300 train
+gjxdidoupr 1 300 train
+gjxeaguiyi 1 300 val
+gjxfowkaeo 1 300 test
+gjxivvbqva 1 300 val
+gjxnrwjxwe 0 300 val
+gjxntxspxv 1 300 val
+gjxrpvuphb 0 300 train
+gjxtmevndn 1 300 train
+gjxujhvkyc 0 300 val
+gjxznmarpw 1 300 val
+gjyayfqknz 1 300 val
+gjydlhcrtn 0 300 train
+gjygvvuiir 1 300 train
+gjyhbfapen 1 300 val
+gjykivrdye 1 300 train
+gjylqsqjiu 1 300 train
+gjypopglvi 0 300 train
+gjysuxxmgd 0 300 val
+gjyuryvlhe 1 300 train
+gjyvblufxy 1 300 val
+gjywiceybn 0 300 train
+gjywwmnvsu 1 297 val
+gjyxjhuniu 1 300 train
+gjzcbloxmj 1 300 val
+gjzdquoeml 1 300 train
+gjzdusvnja 0 300 val
+gjznaoxbmv 1 300 train
+gjzvaypsfk 0 300 train
+gjzzflzknu 1 300 train
+gkabcyoumn 1 301 val
+gkajumkvor 1 300 train
+gkaocherbx 1 300 train
+gkaplrydxx 1 241 train
+gkatpxxcgt 1 300 train
+gkawtrgmnn 1 300 val
+gkbbduugeh 1 298 train
+gkbbngtnfk 1 300 train
+gkbfxjlhju 1 301 train
+gkbiiuwvjd 1 300 train
+gkbmuqhfti 0 298 val
+gkbtbrpmto 0 300 train
+gkbxpshmjy 1 300 train
+gkbxschdbo 1 300 train
+gkcqhdxxne 1 301 train
+gkcvudlqfs 1 300 train
+gkcxanrlpp 1 300 train
+gkczvtdnzz 1 301 val
+gkdfuoelbe 1 300 train
+gkdwiqavma 1 301 train
+gkeamhtzwn 1 300 train
+gkeauaufmz 1 300 val
+gkekyifqsv 1 300 train
+gkeltqtvwx 1 302 val
+gkettsbsrh 0 300 val
+gkeubyechu 1 300 train
+gkfdimxqzk 1 300 train
+gkfgdzcbxf 0 298 val
+gkfijcojhc 1 300 train
+gkfkltdbwk 1 300 train
+gkfnbyclxy 1 299 val
+gkfpevwyvc 1 300 train
+gkfqqdebfa 1 300 train
+gkfthbiszj 1 300 train
+gkftwfvdyt 1 300 train
+gkgbyqkfys 1 300 val
+gkgcnwteoh 1 300 train
+gkgcyvzjbd 1 300 train
+gkgjsqjywz 1 300 train
+gkgjuapwbq 1 300 train
+gkgntvsszv 0 300 train
+gkgsafweei 1 301 train
+gkgujlcazc 1 298 val
+gkgvdjcemx 1 300 train
+gkgyfndrxx 1 300 train
+gkgyuginbd 0 300 train
+gkhgmuqxxz 1 300 train
+gkhhcxjshu 0 300 train
+gkhqjvrmut 1 300 train
+gkhtjvypym 1 298 train
+gkhwrqguzw 1 300 train
+gkicllwmyb 1 300 test
+gkiiuqgrfq 1 300 val
+gkijftelpw 1 300 train
+gkijjgjxhl 1 300 val
+gkijkojxnc 1 300 train
+gkirrvqbxb 1 300 train
+gkitkfybav 1 300 train
+gkjgjqyyff 0 300 train
+gkjjaeqwmh 1 297 train
+gkjuhtkeau 0 301 train
+gkjunbvrdy 1 300 train
+gkjxowuika 1 299 train
+gkkgrhkdhb 1 241 train
+gkkjefhuzz 1 300 train
+gkknsyqbnz 1 300 train
+gkkpesmtic 1 300 train
+gkkqdhhlxi 0 300 train
+gkkqkljdgc 1 300 train
+gkkvunsoec 1 300 train
+gklbyicmvd 1 300 train
+gklemgduvi 1 300 train
+gklgmkleza 1 297 val
+gkliugsrne 1 300 val
+gklqigqroq 1 300 train
+gkltbysazj 1 300 train
+gkluonblmp 1 300 train
+gklxjvzirw 1 300 val
+gklxpixbpo 1 300 train
+gklybkjkek 1 300 val
+gklyuqfmqj 1 300 val
+gklyuueqqo 0 298 train
+gkmnozivru 1 300 train
+gkmsvnxwto 0 300 train
+gkmzggwtvb 1 300 train
+gknjjgdmer 1 300 train
+gknjpknzce 1 301 train
+gknjpydgfj 1 300 train
+gknntwuwab 1 300 train
+gknoryqggc 1 300 train
+gknrewulox 0 300 val
+gknufblsxx 0 300 train
+gknysalxjp 1 300 val
+gknyztlxxl 1 299 test
+gkoaqihhfd 1 300 val
+gkodbjonry 1 300 train
+gkoepduvxg 1 300 train
+gkofdnbgfp 1 300 train
+gkohfnywjc 1 300 train
+gkokllbuwd 1 300 train
+gkoxyhfssm 1 300 train
+gkozhhmcja 1 300 val
+gkpixynjfr 1 300 train
+gkpkktrzjb 1 298 train
+gkppazyosa 1 300 train
+gkptqixrkk 1 300 train
+gkpymgsocz 1 300 train
+gkqaexphlq 1 300 train
+gkqbdncwxs 1 300 val
+gkqckeiibc 0 300 train
+gkqitjodaa 1 300 test
+gkqjsjnohc 1 300 train
+gkqoskbqfl 1 300 test
+gkqqhnfaub 1 300 train
+gkqupfviiq 1 300 train
+gkqzhnqfxo 1 299 val
+gkrcgkujsn 1 300 train
+gkrecyncze 1 300 train
+gkrnqmhunf 1 241 train
+gkrwoygvjd 0 300 train
+gksddhdlez 1 300 val
+gksexlknii 1 147 train
+gkshbbetyg 0 300 train
+gksijxwvyf 0 300 train
+gksipiyczq 1 300 train
+gkssxnazeg 1 301 train
+gksuasmfoo 1 300 train
+gksvfvolyn 0 300 train
+gkswlyaxfv 1 300 train
+gktacrffcf 1 300 train
+gktdnuwcse 1 300 train
+gktdwopuvv 1 300 train
+gktgthkugb 0 300 train
+gktgvxffns 1 300 train
+gktjowiuqe 0 300 train
+gktsfdyitl 1 300 train
+gkttkuzpsf 1 300 train
+gkuafgtsvo 1 300 val
+gkuntfxqrr 1 300 train
+gkusdnnvha 1 300 train
+gkutjglghz 1 299 test
+gkuvfmjgce 1 300 train
+gkvahnmizd 1 300 train
+gkvhqhwwkv 1 299 val
+gkvibqzryk 1 300 train
+gkvqqdvqxh 1 300 train
+gkvqvfkspq 1 269 train
+gkvydkllyn 1 300 val
+gkvzwenjyo 1 300 train
+gkwbasizwd 1 300 train
+gkwigusybt 0 300 val
+gkwkwzulbx 0 300 train
+gkwmalrvcj 1 300 train
+gkwzytngjh 1 300 val
+gkxgqtjokl 1 300 test
+gkxirdxzbp 1 300 train
+gkxlnuvjgb 0 241 train
+gkxtsljexu 1 300 train
+gkykoytfix 1 241 train
+gkyprzeezm 1 300 train
+gkyszngwwt 1 300 train
+gkyturuqoo 0 300 train
+gkywixmdxk 0 300 val
+gkyxdknkzh 1 292 train
+gkyyhkskrp 1 300 train
+gkzfwvyupu 1 300 train
+gkzjxsqyrb 0 300 train
+glaaknvdml 1 300 train
+gladktygyb 1 300 train
+glakxckeif 1 300 train
+glaljfzfpz 1 300 train
+glamnffbfe 0 300 train
+glaqiakepr 1 300 train
+glbiuhsrpz 1 298 train
+glbjtxmsqn 1 300 val
+glbriatpsy 1 300 train
+glbwohdqpw 1 300 train
+glcbbeaxyv 1 300 val
+glccesvsed 1 300 train
+glcifkjjkd 1 300 train
+glcvrmeduk 1 300 val
+glcyddulzh 1 300 train
+glczoxommv 1 300 train
+gldbvarkge 1 301 train
+gldgaflubx 1 300 train
+gldlvkplzy 1 300 test
+gldoxkpezc 1 300 train
+gldpafckwo 0 300 train
+glduibccuz 1 300 train
+gldxyhytub 0 300 train
+gldyjcsxkf 1 300 train
+gldzguwfao 1 300 val
+gldzqnyvsf 1 300 val
+glefulamyk 0 300 train
+gleijkfzhr 1 300 train
+glelsrgfhc 0 300 train
+glelzwgywx 1 300 val
+gleoswxbhs 0 300 train
+glepfknonq 1 300 train
+glesxeslfn 1 300 val
+gletajtyci 1 300 train
+glfevgzdts 1 300 train
+glffvvktkp 1 300 train
+glfgwynmjt 1 300 train
+glfjllgfcg 1 300 train
+glfmswucsj 1 300 train
+glfpofywyz 1 300 train
+glfpzagcui 1 299 train
+glfqknlvmt 1 300 train
+glftxxrecl 1 300 val
+glfwraejch 1 300 train
+glfxhduvfw 1 300 val
+glgabqzauy 1 300 train
+glghscbqzn 1 300 train
+glgpfbebcx 1 300 train
+glgtvkvauu 0 300 train
+glgwbjcmzf 1 300 val
+glhkukotwt 1 300 val
+glhlmbhwbl 1 301 train
+glhuodmfic 1 300 train
+glhyxtaeeb 1 300 train
+glirfepckh 1 300 train
+glitjxdsfr 0 300 train
+glivuoahbz 1 241 train
+gljhmvavqj 1 299 train
+gljinzhrsf 1 300 train
+gljktftydv 1 301 val
+gljlsjpzyk 1 300 val
+gljmmuqpvx 1 300 train
+gljngltwko 1 300 train
+gljnirqiqq 1 300 val
+gljombycln 1 300 train
+gljqwinsfi 1 300 train
+glkbrtaulh 1 300 train
+glkdsbtlgk 1 300 train
+glkgaerynm 1 300 val
+glkjoaosvi 1 300 train
+glkkigoeqc 1 301 train
+glklbmhyzf 1 300 train
+glktymezzc 0 300 train
+glkxmkeskl 1 300 train
+glkyzecdax 1 300 train
+gllcwjrhch 1 300 train
+gllczllsbr 1 300 val
+gllddnvpzj 1 300 train
+gllgjxzopi 1 300 val
+gllgprhsmc 1 241 train
+gllhtvfcrv 1 300 val
+gllirotfep 1 300 val
+gllmnlshoz 1 300 val
+gllocjtngh 1 301 train
+gllrzaamts 1 300 train
+gllxlhvsul 1 300 train
+glmhnzlqdf 1 301 val
+glmkwwraac 1 300 train
+glmrbpxpjs 0 300 train
+glmxszmvdc 1 300 train
+glmzbfrvbl 1 300 train
+glndegrweg 1 301 train
+glngbyepfw 1 300 train
+glosfeubpr 1 300 train
+glowbfyhko 1 300 train
+gloxelyhst 1 300 val
+glpgfalqwn 1 300 train
+glpzhvswup 1 300 train
+glpzlkxzsm 1 300 test
+glqbxttlol 1 241 train
+glqevjqzdc 1 300 val
+glqkwwcqcc 1 300 train
+glqlnidrzf 1 249 train
+glqriykjsl 1 301 train
+glqroypvfk 1 300 train
+glqrxwwpsg 1 300 val
+glqxarhiyy 0 300 train
+glqxuugwsj 1 300 train
+glqzoncdoa 1 300 val
+glrkhgqmap 1 300 train
+glrmqblnzq 1 300 train
+glrxpfnhxx 1 300 train
+glsgrjerme 1 300 train
+glshmsgdyw 0 300 train
+glsmblqnoq 1 300 train
+glsvewykpx 1 300 train
+gltiyiysmn 1 300 train
+gltlfltmia 1 300 train
+gltmxojooo 1 300 train
+gltpndcohp 1 242 train
+gltqqbpzvw 1 300 train
+gltqydksgm 1 300 train
+glttzneqaz 1 300 train
+gltyysegqr 1 300 val
+gluehynqep 0 300 train
+glugygrchb 1 301 train
+glujvdhxmq 1 301 train
+glulltqodv 1 298 train
+gluqpszsgi 1 301 train
+gluuftugei 1 301 val
+gluzohzfhp 1 300 train
+glvazcagtb 1 300 val
+glvdukqcbn 1 300 train
+glviwluzaj 1 301 train
+glvkhhypqd 1 301 train
+glvoqorkrv 1 301 train
+glwcmuudzc 0 300 train
+glwdynujsy 1 300 train
+glwhmuuebm 1 300 train
+glwjrjujgy 1 300 train
+glwlomfblb 1 300 test
+glwlzersek 0 300 train
+glwnakzkru 1 298 train
+glwqttmmwj 1 300 train
+glxcikgjwd 1 300 train
+glxfafqbcf 0 300 train
+glxfpjrhgp 1 300 val
+glxfxykybb 1 300 val
+glxhiyxyup 1 299 test
+glxrhibhol 0 298 val
+glxxogdths 1 300 train
+glyaqkpxgh 1 300 train
+glybskgdcu 0 300 train
+glyttztdmw 0 300 train
+glzduncndi 1 300 val
+glzgcpyqwy 1 300 train
+glzhlycqjq 1 300 val
+glzkqcjcpe 1 300 train
+glzthbjhnj 1 300 train
+glzvljduyb 1 300 train
+glzwsxpwuh 0 300 val
+glzyfkswzc 1 300 val
+glzyifzrql 1 300 train
+gmaaiuugnr 1 300 train
+gmaghrdamw 1 300 test
+gmagxtkedz 1 300 train
+gmailgyenl 1 300 val
+gmanmdsqyz 1 294 train
+gmarqjywjh 0 300 train
+gmbckelbzp 0 300 train
+gmbcnicart 0 300 train
+gmbecsekgn 1 300 train
+gmbjdmpmnh 1 300 train
+gmbquvqqug 1 300 train
+gmbrpbouck 0 300 val
+gmbvzutxre 1 300 val
+gmbxnusbkh 1 241 train
+gmcdkyfnni 1 300 train
+gmchknuzqb 1 300 val
+gmcpavifht 1 300 train
+gmcpfpkflw 1 301 train
+gmctmgmyob 1 300 test
+gmcvyrferj 1 300 train
+gmcyexuefh 1 300 train
+gmdaxsmoou 1 300 train
+gmdbtfctmt 1 300 train
+gmdoyjvcnu 1 300 test
+gmdrzdxsfh 1 300 test
+gmdsssnwda 1 300 train
+gmduiwbari 1 300 val
+gmecgxzori 1 300 train
+gmeokgnnmc 1 300 val
+gmepmwcgwg 0 300 train
+gmetsemqqn 1 301 train
+gmevafymsj 0 147 train
+gmexapgebg 1 300 train
+gmezwlnjqh 1 300 train
+gmfharjwig 1 300 train
+gmfipthbyw 1 300 train
+gmflfitjvh 0 300 val
+gmfoegsoft 1 300 train
+gmfomzcsgg 1 300 train
+gmfowavzuz 0 300 train
+gmfwrrmxwg 0 300 train
+gmgbarmfmg 1 300 val
+gmgdzrsbqq 1 241 train
+gmgefmcnur 0 300 val
+gmgvznalxs 1 300 train
+gmgyplntat 1 300 val
+gmgzufywqd 1 300 train
+gmhbgvobqy 1 300 val
+gmhedxdazx 1 300 train
+gmhmyvumlw 1 241 train
+gmhosclfho 1 300 train
+gmhppivyji 0 300 train
+gmhrdcpuvj 0 300 train
+gmhrvpxpus 0 300 train
+gmhtuubbqm 1 300 train
+gmibtribcc 1 300 val
+gmihbscmwq 0 300 train
+gmiijemmrr 1 300 val
+gmijyrbuvj 1 300 train
+gmimvysuub 1 300 val
+gmiqmllhpx 1 300 train
+gmjccfnmjz 1 300 val
+gmjdbyqspe 0 300 train
+gmjfroqyus 1 300 train
+gmjkxvhymr 1 300 train
+gmjvhtzazt 1 300 val
+gmkbrmltbo 1 300 val
+gmkdeklqkd 1 300 train
+gmkfzogjlj 0 300 train
+gmkizdmpfr 1 300 train
+gmkuswweko 0 300 train
+gmlnhdlnhk 1 300 val
+gmlnjuzjbu 1 298 train
+gmlnotxixn 0 300 train
+gmlnztbggi 1 301 train
+gmlomcyfap 1 292 val
+gmlpactizy 1 300 train
+gmlqsrwrrj 1 300 train
+gmlsawyjgk 1 300 train
+gmlzadzbag 1 301 val
+gmmhjyxtsv 1 300 train
+gmmnwixnvo 1 300 train
+gmmzkdhnbd 0 300 train
+gmmzlqhlzr 1 300 train
+gmnjjxcadp 1 241 train
+gmnkmtnlyw 1 300 train
+gmnlhbvmxk 1 300 train
+gmnsugyzmo 1 301 val
+gmnuoezkbf 0 300 train
+gmobmhkilb 1 298 train
+gmofyywabx 1 300 train
+gmomookarj 1 300 train
+gmonrufvyu 1 300 train
+gmonvwaujc 1 300 test
+gmoqnbdmdr 1 300 train
+gmormxdytr 1 300 val
+gmoterthqw 1 300 train
+gmoxkmamfb 1 301 val
+gmpjmpsjvq 1 300 train
+gmpkwgcnza 1 301 val
+gmplfairyd 1 300 train
+gmpokuotku 1 292 val
+gmpqlncatc 1 300 val
+gmpwfcomcl 1 301 val
+gmpxhzzeso 1 300 train
+gmqkqddygw 1 300 train
+gmqlnajrdc 1 300 train
+gmqmyvyqvm 0 300 train
+gmqqqmpksa 1 302 train
+gmquwgwvtc 1 300 train
+gmqxjkndgs 1 241 train
+gmqymvszgk 1 300 train
+gmrduwzcdg 1 300 train
+gmrjnaeerk 1 300 train
+gmrjrvdgos 1 300 train
+gmrpufmznq 1 300 val
+gmruvuxnwp 1 241 train
+gmrxvmvrzt 0 134 train
+gmsdevqexx 1 300 train
+gmsoirgziy 1 300 train
+gmsukalbwi 1 300 train
+gmsusvebnz 1 300 train
+gmsvraarut 1 300 train
+gmtgqwumjb 1 300 train
+gmtmhojbjf 1 300 train
+gmtndklvsc 1 302 train
+gmtnuqkwql 1 298 train
+gmtvecxqrw 1 302 train
+gmtvtolefj 1 300 train
+gmtxinzlmb 1 241 train
+gmtxkpliex 1 300 val
+gmtztejgry 1 300 train
+gmuagvvcen 1 300 train
+gmutjqhliq 1 300 val
+gmutlcetxb 1 300 train
+gmuvoiyrwo 1 300 val
+gmuzmoovkc 1 300 train
+gmvebzkncg 1 299 val
+gmvhepetjs 1 300 train
+gmvhzhndbc 1 255 train
+gmvpkfnjfl 1 300 train
+gmvzcaublc 1 300 train
+gmwbwhcdko 1 300 test
+gmwdvwyajs 1 300 val
+gmwfaocbil 1 240 train
+gmwgynxgpa 1 300 train
+gmwhynivzx 1 300 train
+gmwopipxqu 1 302 train
+gmwrrcgvmi 1 301 val
+gmwtcnpozk 1 299 val
+gmwztswmdy 1 300 train
+gmwzurwyxh 1 300 train
+gmxbebmauy 1 300 train
+gmxipmhakj 1 300 val
+gmxjlfuwpv 1 300 train
+gmxkxhruic 1 300 train
+gmxltwezbh 1 300 val
+gmxrwhogku 1 300 train
+gmxxdslvif 0 300 train
+gmyancpayq 1 300 train
+gmyehejryd 1 299 train
+gmyidmmfrj 1 300 train
+gmynszfycz 1 300 train
+gmyozlpfkh 0 300 train
+gmyulbcyri 1 300 val
+gmyvfdvwau 1 300 val
+gmzjbwdqcs 1 299 val
+gmzkpcetns 1 300 val
+gmzqugdlcp 0 300 train
+gmzzfzvyvx 1 300 train
+gnabjjaova 0 300 train
+gnaczvlztt 1 300 val
+gnatjshncl 1 241 train
+gnatyjlibe 0 300 train
+gnaxqnicxj 1 300 val
+gnbaqomlin 1 300 train
+gnbfgbfqdw 1 298 val
+gnbjmbjicv 1 300 train
+gnbncjbclm 0 300 train
+gnbuzqstcf 1 300 train
+gnceqdwaub 1 241 train
+gnceqfbheo 1 300 train
+gncfjnpreo 0 300 train
+gnchosmeuf 1 300 train
+gncnxvdgzz 1 302 train
+gncpxzkcca 0 300 train
+gncqepevhu 0 300 train
+gncxqiqagr 0 300 train
+gndabcmmfb 1 300 train
+gndcymmzzu 1 301 train
+gndfvyczqq 1 300 train
+gndgbqhvpx 1 300 val
+gndpkritse 1 300 val
+gndusfksku 1 250 train
+gndwcgzwct 0 301 train
+gndwznamgn 1 301 train
+gndxqxjyli 0 300 train
+gnedjegvun 1 300 train
+gneeoltznu 0 300 train
+gnehbqolrz 1 302 train
+gnenhkljcl 1 298 val
+gneqjyguxm 1 240 val
+gnerepjzus 1 300 train
+gneufaypol 0 300 train
+gneufjmjne 1 300 train
+gnfhzyixsx 1 301 train
+gnfllocoww 1 301 val
+gngbromgln 1 300 train
+gngcfdcffo 1 300 val
+gngeeiqrfc 1 298 train
+gngeqyrkfo 1 299 test
+gnghsiaxkc 1 300 train
+gngzrgtxik 0 300 val
+gnhbhyrkmf 1 300 val
+gnhbtnojfp 0 300 val
+gnhjsregoh 1 300 train
+gnhlropodn 1 300 train
+gnhowvgdvg 1 300 train
+gnhptuzmfn 1 300 train
+gnhtfpgxpn 1 300 val
+gnhvvzuhgp 1 240 val
+gnhzduwqbr 1 300 train
+gnicwhvkmz 1 300 train
+gniidtmqst 1 300 train
+gnilipnyjj 1 300 train
+gniziafbtj 1 288 train
+gnjaobughh 0 300 train
+gnjavhtgdp 1 300 train
+gnjdwbhvdc 1 300 val
+gnjhrmfemm 1 300 train
+gnjidhgpma 1 301 train
+gnjykoepmg 1 300 val
+gnjzotznfq 1 292 train
+gnkfbipbko 0 300 train
+gnkisezhjo 1 300 train
+gnkjzkxbfs 1 300 val
+gnkkmrmlme 1 300 train
+gnkmpcefzl 1 300 train
+gnkorwgvuy 1 300 train
+gnktnqnipj 1 300 train
+gnkytgskjl 0 300 train
+gnkzcrbfjm 1 300 train
+gnldziwmer 1 300 val
+gnlinjiobp 1 298 val
+gnlkthxfjf 0 300 train
+gnlqorqfev 0 300 train
+gnlumlkzqk 1 300 train
+gnlvnyrpfq 1 300 test
+gnlwynwxhd 1 300 train
+gnlxmgjjof 1 300 train
+gnlxtuygei 1 241 train
+gnlycjwkmg 1 300 train
+gnmaduangt 1 300 train
+gnmemxauqz 1 300 train
+gnmemylccj 1 300 train
+gnmhfxfsgh 1 300 train
+gnmkwiahyd 1 300 train
+gnmmhlbzge 0 300 test
+gnmqhwitkb 1 300 train
+gnnbtnjqto 1 300 test
+gnnjzekjpx 1 301 train
+gnnmufbiva 1 300 val
+gnnmuhkxyy 1 300 train
+gnnuktzwwy 1 300 train
+gnnuovoywm 1 300 train
+gnnyscxrzi 1 300 train
+gnojflkwhm 1 298 train
+gnondqabyn 1 300 train
+gnoqqplafe 1 299 test
+gnosbljutd 1 300 train
+gnotkzirme 1 300 train
+gnouwtefpd 0 240 train
+gnoxqfwkxb 1 300 train
+gnpaehuyie 1 300 test
+gnpdpalgaw 1 300 train
+gnpiohcjho 1 300 train
+gnpitlpfpw 1 300 train
+gnpllptuer 1 240 val
+gnpzknyuih 1 301 train
+gnpznpliys 1 300 val
+gnqmvtflkw 1 300 train
+gnqobbqrns 1 300 train
+gnqojufshp 0 239 val
+gnqtwcrwju 1 300 val
+gnquanigrd 0 300 train
+gnqzqyjwrj 1 300 train
+gnrbhysdok 0 300 train
+gnrdilopke 1 241 train
+gnrgjaxhtl 1 300 train
+gnrmekmgpu 1 300 train
+gnrokcdvve 1 269 train
+gnrtpkbene 1 300 train
+gnrwdaogqh 0 301 train
+gnrwnpmurn 1 300 train
+gnryvymosi 1 300 val
+gnscpdsanw 1 301 val
+gnsjdzdcyk 1 300 train
+gnslcjmktc 0 302 val
+gnslnjrgnx 1 300 test
+gnsmmehuhb 1 300 train
+gnsvylaarh 1 300 train
+gntcafcubh 1 300 train
+gntviyxvhb 1 300 train
+gntwhdgazh 0 300 val
+gnuavsxjhr 1 298 val
+gnuczwpoxa 1 300 train
+gnukxvimny 1 301 val
+gnulzsscvk 1 300 train
+gnuupysstr 1 300 train
+gnuwmbfrox 1 300 train
+gnuxpxxuon 1 300 train
+gnvamzvbpb 0 300 train
+gnvgrskdwd 1 300 train
+gnvihtukcz 1 300 train
+gnvkxplgww 0 300 val
+gnvvpnwfck 0 300 train
+gnwaflnrkw 1 300 train
+gnwcjacyph 1 300 train
+gnwdpoubyo 1 300 train
+gnwlfmrngq 1 300 train
+gnwqvktwib 1 300 train
+gnwstnficr 1 300 train
+gnwyqouhfd 1 301 train
+gnxbxpksai 0 300 train
+gnxemcmisb 1 300 val
+gnxgiwcknq 1 300 test
+gnxgzmbcdr 0 300 train
+gnxlbuwucy 1 300 test
+gnxskixxcm 1 300 train
+gnxzaxgllk 1 300 train
+gnxzrhdgeg 1 300 train
+gnycafppzz 1 300 train
+gnyecttszz 1 301 train
+gnygsziikw 1 300 train
+gnyiqcwnkt 1 300 train
+gnykansqlk 0 294 train
+gnylqbevnf 1 300 train
+gnyobtyjls 1 300 train
+gnyqkorxmh 1 300 train
+gnyqluuenf 1 300 val
+gnyspcpbhd 0 300 train
+gnytcpethj 1 300 val
+gnytikpmnm 0 300 train
+gnzapjfnhr 1 300 val
+gnzawhgnjf 0 300 train
+gnzozfkipj 1 241 train
+gnzwqtcupx 1 296 val
+gnzxhnndci 1 300 train
+goaguxqpdo 1 300 train
+goakjsojgk 1 300 val
+goaocmpuye 1 300 train
+goardbrdyd 1 300 train
+goasjrcftu 1 300 train
+gobnezgnaw 1 300 val
+gobnlkjrhk 1 300 train
+gobvfbczxj 1 300 train
+gobvnzkjaf 1 300 train
+gobwzxxslw 1 298 train
+gobzlemppm 1 300 val
+gocbkevlvb 1 300 val
+gochxzemmq 0 300 test
+gocibcpiyu 1 300 train
+goclebfgcj 1 300 train
+gocmcxvpsn 1 300 val
+gocqhmthdw 1 301 val
+gocrdvihos 0 300 train
+gocuchujbg 1 241 train
+gocuxhyybk 1 300 train
+godcuwkobs 1 300 train
+goddwzjrwt 1 300 train
+godkoqdpky 1 300 train
+godkzecvxg 0 300 train
+godmopteom 1 300 val
+godpfnlizl 1 300 val
+godzbfzsri 1 300 train
+godzfxciyw 1 300 train
+goecylbbks 1 300 test
+goegdmmyxk 0 300 train
+goeivdgdzc 1 300 val
+goekzadjqz 1 300 train
+goemtjevdw 1 300 train
+goenfduqug 0 300 train
+goeomnbuee 1 300 train
+goetaanbkq 1 300 val
+goevvjhxer 1 300 val
+gofbphjonb 0 300 train
+gofcvoyogl 0 300 train
+gofdngllac 1 300 train
+goflrbkvdh 1 300 train
+gofqhmrhtg 1 300 train
+gofwmkvxix 0 300 train
+gofybzkrli 1 300 train
+gogbvdqtoa 1 300 train
+gogdodtvfw 1 298 train
+gogiqvfoag 1 301 train
+gogmiwqkcm 1 300 train
+gogntctftc 1 300 val
+gogqihhrvj 1 300 val
+gogueewnnt 1 300 train
+gogybqjoqi 1 300 val
+gohsbddbhu 1 300 test
+gohsytuzei 1 241 val
+gohxysgjzw 1 300 train
+gohzxhoazl 1 300 val
+goicfjmmqd 1 300 train
+goidqtxjeq 1 300 train
+goitgrpdhe 1 298 train
+goixghkrth 1 298 train
+goiyhxbylg 1 299 test
+gojijlvdfn 1 300 train
+gojrmpwuns 1 300 train
+gojtqqxkca 1 300 train
+gojumtrpud 0 300 train
+gokbzxgwdr 1 300 train
+gokfrurvmy 1 300 train
+gokrnqfydg 1 300 val
+gokscpmmxj 1 300 val
+goksepviwp 1 300 train
+gokswltifh 1 298 train
+goktxzixxx 1 300 train
+gokvbpxind 1 300 train
+gokwvhzsgc 0 300 val
+golajpxixu 1 300 val
+golcejjalb 0 300 train
+golmvrouze 1 298 train
+goltqpoduh 1 300 train
+goludwyjbq 1 300 train
+golysrbdyn 0 300 train
+gomiwcnvrk 1 301 train
+gomjwlutwd 1 300 train
+gomlnmufvc 1 300 val
+gommeywkvt 1 300 train
+gomqkftobw 1 300 val
+gomtogkuli 1 300 train
+gomvkuhwxv 1 300 train
+gomwfvijiv 0 300 train
+gomxkjifiu 1 300 train
+gonamxyjrp 1 300 test
+gonbtrzhlw 1 300 val
+gondltewba 1 300 val
+gonilmxjfg 0 300 train
+gonkwpeqkk 1 300 train
+gookxtipaz 1 300 train
+goolpwftkw 1 300 val
+gopaetevnq 1 298 train
+gopahkgezx 1 300 train
+gopbzglrzb 0 300 val
+gophykfcuv 1 300 train
+gopoxulzbz 0 300 train
+goppdjjssf 1 300 train
+gopykvbaxq 0 300 train
+gopyrlxczk 1 300 train
+goqderzmlr 1 300 val
+goqdzibgdz 1 301 train
+goqggsgnyb 1 269 train
+goqgljchwh 1 300 val
+goqhafgwgx 1 288 train
+goqhyebxyl 1 300 train
+goqjqsgari 1 300 train
+goqnmgzgwk 1 300 train
+goqnmudces 0 300 train
+goqpmmcgdv 1 300 train
+goqsvyoseh 1 300 train
+goqwvuyzpy 1 300 train
+gorfpmhzlk 0 300 train
+gorgcirpdd 1 301 train
+gorjggzvop 1 300 train
+gorrghkrjt 0 300 train
+gorrgjpxbk 1 298 train
+gortorhgtt 0 300 train
+gosayzsetb 1 300 train
+gosbomznhy 1 300 train
+gosdbxyxfd 1 300 train
+gosjaaazhp 1 300 train
+goskpsabpp 1 300 val
+goslgrsaer 0 300 train
+gossjayscb 1 301 train
+goswookxqc 0 300 train
+gosyohgxii 1 296 val
+gotattltdg 1 300 train
+gotblyicoj 1 300 train
+gotdchglhk 1 300 train
+gothhacfff 0 300 train
+gotilrinkh 1 300 train
+gotowctiri 1 300 train
+gotrjagwjv 1 297 train
+gotvgckpns 0 300 val
+gouhiusnqj 1 298 train
+gouqgigfec 1 300 train
+goussttfgt 1 300 test
+gouxvhsmgr 1 300 train
+gouzvhlvki 1 300 val
+govciveiko 1 300 train
+govjvzfbcj 1 300 train
+govoedqwdv 0 300 train
+govqfsszza 1 301 train
+govwgycgfx 0 300 train
+gowbhijvth 1 298 train
+gowckbhuer 1 300 train
+goweljhmfa 1 300 train
+gowkpdogel 1 300 train
+gowmotenup 0 300 train
+gowrtdfbvq 1 300 train
+gowtkwqkqd 1 300 train
+gowtyjhref 1 300 train
+gowucbfrin 1 301 val
+gowuwxfudf 1 297 train
+gowvikqjbx 1 300 train
+gowystmbab 0 300 train
+goxbkycgkg 1 300 val
+goxkxrugwy 0 300 val
+goxqhztutu 1 300 train
+goxvdflnas 1 269 train
+goybpueemz 1 241 train
+goyentrszm 1 300 train
+goyfxbztgl 1 300 train
+goygmtiefx 0 300 train
+goypgwghaw 0 300 val
+goyqbxelji 1 300 train
+goyqvoaotb 1 301 train
+goyrhrvden 1 300 test
+gozbrlxguv 1 300 test
+gozguevcji 1 300 train
+gozlvmmrbg 1 300 train
+gozrlvanth 1 300 train
+gozsesxenh 1 300 train
+gozxmqwtzi 1 241 train
+gozymnihsb 1 300 train
+gpajaarmxh 1 300 train
+gpalfmianp 1 300 test
+gpamavvtlc 1 301 train
+gpanuhpdmf 1 300 train
+gpaqoqegbn 0 300 train
+gparfpojzt 1 300 train
+gpaxzckick 0 300 val
+gpaztkgvkz 1 300 train
+gpbevocdvn 1 300 train
+gpbfezznuc 1 300 train
+gpbngfqtno 1 300 train
+gpboeffyoh 1 300 train
+gpbozxaeok 1 300 train
+gpbsmhnhil 1 302 train
+gpbvwddzij 1 300 val
+gpbwpjgngy 1 300 train
+gpbxboeiuo 1 300 train
+gpccuqyywa 1 300 train
+gpcdvhfoqj 1 300 val
+gpcgqwatwv 1 300 train
+gpclcokcfx 1 300 train
+gpcqjarchp 1 300 train
+gpctpannwt 1 300 train
+gpcwattrnd 0 301 train
+gpdcdaivqe 1 300 train
+gpdhmwfxnn 1 300 train
+gpdkzpulfs 1 300 val
+gpdtoamvkz 0 300 train
+gpdytnzydn 1 300 train
+gpeefwttrv 1 298 train
+gpegjnzdfz 1 300 train
+gpekphsqjh 1 298 train
+gpenoneeqf 0 300 train
+gpeoerrgaj 1 300 train
+gpevrsbgim 1 300 train
+gpexqhcedq 1 300 train
+gpfcxpuweq 1 300 train
+gpfundyrla 1 301 train
+gpfyzppxlu 1 300 val
+gpgbkevjrb 0 300 train
+gpgcmhsuqn 0 300 train
+gpgdzkgmtj 1 298 train
+gpgnvggiye 1 300 train
+gpgtncumzj 1 300 train
+gpgtsauwaw 1 300 train
+gpgubeivem 0 300 train
+gpguueiape 0 300 val
+gpgvlccaqa 1 301 val
+gphbmcacvo 1 300 train
+gphdyisiot 0 300 val
+gphegnhvqj 0 300 train
+gphgxhyvni 1 298 train
+gphkkpxrjr 1 300 train
+gphqtxgbgq 1 300 val
+gphrluouye 1 300 train
+gphvpcqwlf 0 300 train
+gphwbbbjnb 1 300 train
+gphwegipfu 1 300 train
+gphwezuwrb 1 300 train
+gpieyudqze 1 300 train
+gpihfsayjl 1 301 train
+gpihvxshbj 0 300 train
+gpipuocgfq 1 300 train
+gpizdsqvsr 0 300 train
+gpjejsdmni 1 300 train
+gpjfundste 1 300 train
+gpjhljtyoq 1 300 test
+gpjnjxdgrg 1 300 train
+gpjolgxvvk 1 300 train
+gpjwbkelnm 1 300 train
+gpjyutpeib 1 300 val
+gpkqzknsvj 1 300 val
+gpkresscry 1 300 val
+gpktopynlp 1 300 test
+gpktstikwh 1 300 train
+gplcznqznv 0 300 train
+gpldedgawp 1 301 train
+gplfvateud 1 299 val
+gplgurohus 0 300 train
+gplljeejvd 1 297 val
+gplnqwprix 1 298 train
+gplurzlrhb 1 300 train
+gplyturbmn 0 298 train
+gpmpmtgjfu 1 241 train
+gpmqqgifmr 0 300 train
+gpnaqdqwqn 1 300 train
+gpnczubuhf 1 301 val
+gpnduxocsz 1 300 train
+gpnjruepgy 1 300 val
+gpnkdexant 0 300 train
+gpnnxqxwze 1 300 val
+gpnsczhiso 1 300 train
+gpoafdkduw 1 298 val
+gpobhiixsp 0 300 val
+gpobttqxoe 1 298 train
+gpocepkdkg 1 300 train
+gpofafwvpn 1 300 val
+gpolwqideg 1 300 train
+gpornvqtvz 1 241 train
+gpoummlawi 1 300 train
+gpoxpmuozt 1 298 train
+gppcoesosf 1 300 val
+gppdwdgfil 1 300 train
+gppinocwlh 0 300 train
+gppmpydfqi 1 300 val
+gpppeeizae 1 300 train
+gppptutxxe 0 300 train
+gppsgbqjhr 1 300 train
+gppvbusobq 0 300 val
+gppwxisrdc 1 300 train
+gpqbskhnny 1 297 train
+gpqdprdnmp 0 300 train
+gpqdrkflpo 1 300 test
+gpqfrhzlgl 1 301 train
+gpqgrnrjsy 1 300 train
+gpqjxmovkf 1 241 train
+gpqlfejyna 1 300 train
+gpqnqhklpg 1 300 train
+gpqsrmwewd 1 300 train
+gpqvcwoenr 1 300 train
+gprestnwyx 1 300 val
+gprjqigplu 1 300 val
+gprlsdgoge 1 300 train
+gprmemqqif 1 300 train
+gprqgmleal 1 300 train
+gprvjgqraz 1 300 train
+gprwzinlpd 0 300 train
+gprxiuplev 1 300 train
+gprxkpwbfp 1 296 train
+gprxsfwfkc 1 300 train
+gpsaobjisl 1 300 val
+gpskwigkxd 1 300 test
+gpslxrzlfw 1 300 train
+gpsqelalbp 0 300 train
+gpsqoaxgnc 1 300 train
+gpsqqpfkdy 1 300 train
+gpssfyvjja 1 300 train
+gpswfiyivm 0 300 train
+gpsxfxrjrr 0 300 test
+gpsytbhcmb 1 300 train
+gptcvmbcqo 1 300 train
+gpthondchd 0 300 train
+gptrgbtqem 1 300 train
+gptyizpwgm 1 301 val
+gpuciydhjt 0 300 train
+gpucsnaeun 1 300 train
+gpucxckuts 1 300 train
+gpurfeajeg 0 300 train
+gpuspwfxfl 1 300 train
+gpuvjjknrl 1 300 train
+gpuwiicfxo 1 300 train
+gpuycezsfz 1 300 train
+gpvellvmyj 1 300 train
+gpvoqhfyee 1 300 val
+gpvrkdoweb 1 301 val
+gpvwsfexwp 1 300 train
+gpvwvsquzc 1 300 train
+gpwbnbavne 1 300 train
+gpwjtjnhqx 0 300 train
+gpwllvbhtm 1 300 train
+gpwnogboea 1 300 train
+gpwnvzdflz 1 298 train
+gpwufippaw 1 300 train
+gpwxhiieaz 1 300 train
+gpwzcdqrwb 1 300 train
+gpxbzuuekd 1 300 val
+gpxhpmlqsx 1 298 train
+gpxkxqrujx 0 300 train
+gpxtwpeski 0 300 train
+gpxvprqlnh 1 300 train
+gpxxornbiu 1 300 train
+gpxzcqxeea 1 298 train
+gpyetootnv 1 300 train
+gpzflkluau 1 300 train
+gpzfnoxodh 1 300 val
+gpzgbvvehv 0 300 train
+gpzlnnljhn 0 300 train
+gpzscexozl 1 300 val
+gpzvmkrzgp 0 300 train
+gpzwvdkuie 1 300 test
+gpzygjplrt 1 300 val
+gpzyphbuiq 1 300 train
+gqacyfqyfk 1 300 train
+gqaisclrxt 1 288 train
+gqajznuljm 1 300 val
+gqaloythtf 1 300 train
+gqanvgwuqk 1 298 train
+gqaoszjmne 1 300 train
+gqaouycewd 1 300 train
+gqappgolvn 1 300 train
+gqatosifpz 0 300 train
+gqauayeamb 0 300 train
+gqavyegpot 1 299 val
+gqaybjiybn 1 300 train
+gqbelxwffi 0 300 train
+gqbfotorcg 1 300 train
+gqbgikpjrq 1 300 val
+gqbqhdfuid 1 301 val
+gqbraaobou 1 300 train
+gqbrjkjice 1 300 train
+gqbtzlzkkb 1 300 train
+gqbvisffvd 1 300 val
+gqbzlzztkw 1 300 train
+gqcruneneb 1 301 train
+gqcshgpfvo 1 300 val
+gqcyqapcxh 0 300 train
+gqdahxdfxi 1 300 train
+gqdbkcbowq 1 300 train
+gqdcfaicrl 1 300 train
+gqdovnjjsh 1 303 train
+gqduotrzbx 1 300 train
+gqdvdfbkka 1 300 train
+gqdxsmqscz 1 300 train
+gqdyxxemfl 1 300 train
+gqeapnhtur 1 300 val
+gqedujxevy 0 300 train
+gqeemfybkh 0 300 val
+gqelfevant 1 300 train
+gqemulfzdr 0 300 train
+gqeoacaoas 0 300 train
+gqexbjfyjp 1 301 train
+gqeynbcxkt 1 300 train
+gqezbbmijn 0 300 train
+gqfqalokpc 1 301 train
+gqfuauvhvg 1 300 val
+gqgatqipah 1 300 val
+gqgedgnyra 1 300 val
+gqgedzswmf 1 300 val
+gqgijxslhs 1 300 train
+gqgtmhrmxe 0 300 train
+gqhczrgntd 1 300 train
+gqheyyzjyf 1 302 train
+gqhggniyqk 1 300 train
+gqhmedrcky 1 300 train
+gqikxmwgcc 1 301 train
+gqiluosbff 1 300 train
+gqimawahvr 1 300 train
+gqinsedysp 1 300 train
+gqipinkpdv 0 298 train
+gqitdpngnb 1 301 train
+gqiwjxefzm 1 300 train
+gqixdoekgx 1 300 train
+gqjfstcckz 1 298 train
+gqjohkcjww 0 300 train
+gqjqldpdzd 1 301 train
+gqjzuiijmh 0 300 train
+gqkajbhkof 1 300 train
+gqkdipntkr 1 301 val
+gqkefasweq 1 269 train
+gqkelizhxu 1 300 train
+gqkhnexdjf 1 300 val
+gqkirskvna 1 241 train
+gqklfoxqbg 1 300 val
+gqkmnpuiqf 0 300 train
+gqksacbfsy 1 300 train
+gqkwwgnuaz 1 300 train
+gqlajpyklv 0 300 train
+gqlfqtmmxn 1 300 train
+gqllfhscvv 1 300 train
+gqlowjvcxh 1 239 val
+gqlpwihuku 1 300 train
+gqlqikaara 1 300 train
+gqlvahrghg 1 83 train
+gqmdicvbtk 1 300 train
+gqmjolwxnb 1 300 train
+gqmkuyvpdv 1 300 val
+gqmmrskwba 0 300 train
+gqnaxievjx 1 300 test
+gqndefmvai 1 300 train
+gqnjzeehxf 1 300 train
+gqnkarjtmh 1 300 test
+gqnpffuryh 1 300 train
+gqnudphymq 1 300 train
+gqnwgfbkzu 1 300 val
+gqnxkiqhws 1 300 train
+gqnylcoyuu 1 300 train
+gqnzmlmtho 0 300 train
+gqnzocbvpg 1 300 train
+gqobzkvpep 1 300 train
+gqofkxplaa 1 300 train
+gqohgvwgiy 1 300 train
+gqonceccpe 1 300 val
+gqonjnqkqs 0 300 train
+gqooyqcmpv 1 299 train
+gqopkqbkfc 1 300 train
+gqormdaoxq 1 299 train
+gqoxcajxyf 1 301 train
+gqpayiddqv 1 300 train
+gqpbgirzpc 0 300 train
+gqpfrrhnyd 1 300 train
+gqpjtmozqb 1 300 train
+gqpkmbussn 1 300 train
+gqpmcwawlo 1 300 train
+gqpoyshdte 1 300 train
+gqprifzrrz 1 300 val
+gqpshjihle 1 300 val
+gqpwluptgw 1 300 train
+gqqfldhxcp 1 300 train
+gqqhhrsqge 1 300 val
+gqqishrojf 1 301 val
+gqqlsltepq 1 300 val
+gqqngalilz 1 301 train
+gqqwhprmmg 1 300 train
+gqqwyepgsv 1 300 train
+gqrawigxvq 1 300 train
+gqriktodch 1 300 train
+gqrnojuenr 1 300 train
+gqrsljhqke 0 301 train
+gqrtzmyrsn 1 300 val
+gqrwddkzts 1 300 train
+gqrwiwbomo 1 300 val
+gqsbvsitzw 1 297 train
+gqscmcmcup 1 300 val
+gqsczmyvlj 1 300 train
+gqsekflpar 1 300 val
+gqsmiqnwgr 1 300 train
+gqsmnrflrq 1 300 train
+gqsokvhypx 1 298 train
+gqsxjxtdew 1 300 val
+gqsxnpltxr 1 300 train
+gqsxrancdn 1 300 train
+gqtifuvefc 1 300 val
+gqtmtpyvka 1 300 train
+gqtmxgffkx 1 300 train
+gqtshkahib 1 300 val
+gqtueigwgr 1 298 train
+gqtuvbqpsq 1 300 train
+gqtztlohkv 1 300 val
+gqubsjszxz 1 300 train
+gqudngulue 1 301 train
+gqugaumrhz 0 300 train
+gqugqvylsu 1 300 train
+gqulwuqdcx 1 300 train
+gqunaaidgi 1 301 val
+gqvaukdpwf 1 300 train
+gqvfgybels 1 300 train
+gqvgiwotnv 1 300 train
+gqvhfslswt 1 300 train
+gqvkpcrwos 1 300 train
+gqvssnodlz 1 300 val
+gqvwimfpsc 1 301 train
+gqvxiqyivr 1 301 train
+gqwbadaocx 1 301 val
+gqwdkieboo 1 300 train
+gqwgdjqnmj 1 300 train
+gqwhktgtuw 1 241 train
+gqwieprwei 1 301 train
+gqwiuklnoy 1 300 train
+gqwzejndyw 1 300 train
+gqxbllvyaj 1 240 train
+gqxeqogchh 1 300 train
+gqxlxuohui 0 300 train
+gqxmkawnqx 0 300 train
+gqxmqvuuhe 1 300 train
+gqxmvibpbl 0 300 train
+gqxqqodwql 1 300 train
+gqyaosmxcl 1 300 train
+gqydkbnsxs 1 300 train
+gqyfcdcilv 1 300 val
+gqyhsojmrv 1 300 val
+gqyrggbsdy 1 300 train
+gqyvmperza 0 300 train
+gqywgfeoei 1 300 train
+gqyywwwvcx 1 300 val
+gqzeunnauo 1 300 train
+gqzfzqemdg 1 300 train
+gqzgsjhuem 1 300 train
+gqzjxydnyo 1 297 val
+gqzltruesu 1 300 train
+gqzluogxga 1 300 train
+gqzmitvnil 1 136 train
+gqzpstkfoy 1 300 train
+gqzvxlnszl 1 300 train
+gqzxhqutkd 1 300 train
+graaqioxxg 0 300 train
+gracjceakp 1 299 val
+gractsujxy 1 301 train
+graeboivzm 1 300 train
+grafmobcfm 1 298 train
+grapbctchn 0 300 train
+grarsfuifu 1 300 train
+gratgukhkl 1 300 test
+graytfvzpa 1 300 train
+grbifxvzjg 1 298 train
+grblswgisv 1 300 train
+grbmegaawd 1 300 train
+grboghbade 1 300 train
+grbowkuwti 1 300 val
+grbrpuqdat 1 300 val
+grbtiztwoy 0 300 train
+grbtvvjvhz 0 300 train
+grcebccgmn 1 300 train
+grcfvyyzvp 1 300 train
+grckidrcno 0 300 train
+grcpbwevdk 1 241 train
+grcqovdzaf 1 300 train
+grcqwetjrz 1 300 train
+grcrqhjtkp 1 301 train
+grcsdeaphd 0 300 train
+grctbctcxb 0 300 val
+grddyeptoh 1 299 train
+grddzuexmx 1 300 train
+grdfjgrjnf 0 300 train
+grdfngecmz 1 300 train
+grdiwcdubs 1 300 val
+grdqmwyyqg 1 300 train
+grdtnaccqb 0 300 train
+grdxtnrpzd 1 300 train
+grecsttjzq 1 300 train
+greejvtkkn 1 300 test
+grettujxfz 0 300 train
+gretwjgofc 1 300 val
+greufebyia 1 300 train
+grezcjcqqg 0 300 train
+grezgxjrht 1 300 val
+grfoipnkgi 1 300 train
+grfowyucmy 1 300 train
+grfqumsqpi 1 300 train
+grfybshldj 1 296 val
+grfyucshef 1 300 val
+grfzbumcdf 1 300 train
+grgilsopwm 1 300 train
+grgjgpyter 1 301 train
+grgofxtgsw 1 300 train
+grgoqekefq 1 300 train
+grgrcvteet 0 300 train
+grgrltauvv 0 300 train
+grgtcqgenk 1 300 val
+grgtvtggta 1 300 train
+grgwugperc 1 300 val
+grgykxxgeu 1 240 train
+grgytdeghx 1 300 train
+grgzrryeox 1 300 train
+grhesifgsa 1 241 train
+grhhufbiiw 1 300 train
+grhlwyjebw 1 300 train
+grhovatoev 1 300 train
+grhwwdydnq 1 300 train
+gridemwoqr 1 300 val
+grielfiuwt 1 300 train
+griezugicu 1 302 train
+grifwanjzn 1 300 train
+grihfvadlq 1 300 train
+griiuxromb 1 301 train
+grinzhyeqo 1 300 train
+gritsajzwy 0 300 val
+grixzoygha 1 300 train
+grjfjxejwz 1 300 val
+grjiavvozo 1 300 train
+grjidrxmqq 1 300 train
+grjjvjlxrs 1 300 train
+grjkryhwao 1 300 train
+grjlkuvjdb 1 300 train
+grjmbvjmtr 1 300 train
+grkbrqkdus 1 300 train
+grkbxhjahv 0 300 val
+grkhvzlchv 1 300 train
+grkiznikxb 1 300 train
+grknxfpkqz 1 300 train
+grkspqjqfs 1 300 train
+grkwnbzlcm 1 300 train
+grlefilwpq 1 300 train
+grlgdwgglp 1 300 train
+grlnstjrut 0 300 val
+grlpjauvzq 1 300 train
+grmizxkvuo 1 301 train
+grmlwkwdcl 1 300 train
+grmwnqgnpw 1 136 train
+grncxndcog 1 300 val
+grnedaoddk 1 300 train
+grnfxcmguq 1 300 val
+grnsntrond 1 300 val
+grnycmbdfu 0 300 train
+grocyqfblm 1 300 train
+grohyodjvy 1 300 train
+groirfzzwb 1 300 train
+groylurwmw 0 300 train
+grpbirvlde 1 300 train
+grphplbpan 1 300 train
+grpiilvmlr 1 300 train
+grpnmlendo 1 300 train
+grptteifsw 1 300 train
+grptyztvqt 1 300 train
+grqcqiznao 1 300 val
+grqdeuyjno 1 300 train
+grqejnjmoc 1 300 train
+grqheonmvl 1 300 train
+grqktxocux 1 301 val
+grqyyhfexr 1 300 test
+grqzqaiojz 1 300 val
+grrcbcryus 0 300 train
+grregntfio 1 300 train
+grrhzkybgd 1 300 train
+grrkfgooxa 1 300 val
+grrlszlktd 1 299 val
+grrvordknv 0 300 val
+grrzxzptay 1 300 train
+grsetinrhl 1 300 train
+grsifcsops 1 300 train
+grslroerqw 1 300 train
+grspujctun 1 300 val
+grsslqidak 1 300 train
+grtjcqdseq 1 240 train
+grtyfxhthr 1 300 train
+gruarwuebb 1 300 train
+grucmllkwm 1 299 val
+gruesokdvj 1 300 train
+grugcuwdkq 0 300 val
+gruiiadqrh 1 299 test
+grujgngcze 1 300 train
+grukqjezms 1 300 val
+gruqhmtsbu 1 300 train
+gruwgoaxac 1 300 train
+gruyhwrioj 0 300 val
+grvbmrztgg 1 300 val
+grvhcvezyd 1 300 train
+grvhhgvawu 1 241 train
+grvmsatgiz 1 300 train
+grvoaxggnz 1 300 train
+grvwhehnbv 1 300 train
+grvzlxhhzm 1 300 val
+grwcxofqrx 1 300 train
+grwgwiyrzy 1 300 train
+grwxgtvlob 1 301 train
+grwxkxtlbh 0 300 train
+grwzfjxrsy 1 300 val
+grxabtecyy 0 300 train
+grxcrntvky 1 301 train
+grxlphstql 1 300 train
+grxuygwcnx 1 300 train
+grxvilvsmd 1 300 train
+grxyzxlhzg 1 300 test
+grybcghwff 1 300 train
+gryesvnbgk 1 300 train
+gryjehjtpz 1 300 train
+grytgghxuz 1 299 train
+grytywjexd 1 301 val
+grzfncynvs 1 300 train
+grzgtbnqtk 1 300 val
+grzjfjyagv 1 300 train
+grzlpkoinj 1 300 train
+grzmxmpuiw 1 301 train
+grznenhqyo 1 300 train
+grzocblpqu 1 300 train
+grzozxrpgq 1 300 val
+grzszchajr 0 300 test
+gsaajflfpz 1 300 val
+gsamcdsvpu 1 300 val
+gsauowgqhs 1 300 val
+gsbbmqcase 1 300 train
+gsbburugoy 1 300 train
+gsbkmfcgnl 1 300 train
+gsbxsxaqeu 1 300 train
+gsciaepqnd 0 300 train
+gscodekatw 1 301 train
+gscpkxfvjr 1 300 val
+gscvirqpcy 1 297 train
+gscxabvysz 1 298 train
+gsdebkyxjy 0 301 train
+gsdeqqxsra 1 100 train
+gsdeuffxuz 0 300 val
+gsdewmtdpg 1 298 train
+gsdltpcrsq 1 269 train
+gsdxqkdkzu 1 300 test
+gsedznpphd 1 300 train
+gsenjveoeq 1 300 val
+gseqcukgdx 0 300 train
+gsexzmolrc 1 301 val
+gsezfytakx 1 300 train
+gsfgxbtoxy 1 300 train
+gsfjdfoysf 0 300 train
+gsflrfcrpc 1 300 train
+gsfpoymzsh 1 300 train
+gsfxyauttk 1 300 train
+gsgadmzchv 1 300 train
+gsgglgjlgm 1 300 train
+gsgngkyufq 1 300 train
+gsgtnqfpah 1 300 train
+gshgerkqui 1 300 train
+gshgzmqfid 0 300 train
+gshimbjwia 1 300 val
+gshruegrcb 1 299 test
+gshthoorsz 1 288 train
+gshwiztljb 1 300 train
+gshxuywgcd 1 300 val
+gsicqdrjmc 1 300 train
+gsicwhxxve 1 302 train
+gsihxwkhlf 1 301 train
+gsinaddbyd 1 300 train
+gsiowgsubl 1 300 train
+gsipbhgetz 1 300 train
+gsiqvsowby 1 300 train
+gsiwrbbkbv 1 300 train
+gsizyyynov 1 300 train
+gsjcvsoaqe 1 300 train
+gsjiurlbjn 1 300 train
+gsjjowtppl 1 300 train
+gsjmdtzrqf 1 300 val
+gsjrpqfcjy 1 300 train
+gsjtmupmyn 1 300 train
+gsjvxclchn 1 300 train
+gsjwkyeglz 0 300 train
+gsjyadmdqs 1 300 val
+gsjyltddag 1 299 val
+gskbplfbpi 1 300 train
+gskhaxrvap 1 300 train
+gskneuzeua 1 300 train
+gsknqfbbvp 1 300 train
+gskpbozfvh 1 300 train
+gsksqztqhe 1 300 train
+gsktfiyqvz 1 300 train
+gskthuripr 0 300 train
+gskuuecuwg 0 300 train
+gslactuklm 1 298 train
+gslfkyqwin 1 300 train
+gsliwxxviz 1 300 train
+gslkbdbmzw 1 300 val
+gslnlehkyz 1 298 val
+gslpymwmzb 1 300 train
+gslwphugdw 1 300 train
+gslxvsxnpf 1 300 train
+gslywbdujy 1 99 train
+gsmcvnjygr 1 300 train
+gsmdxqdxdz 1 300 train
+gsmjiqtfnu 1 300 train
+gsmppiotsb 1 300 test
+gsmthyaulw 1 300 val
+gsmuzwzzhd 1 300 train
+gsndjtzfdg 1 300 val
+gsnhcgheoc 1 300 train
+gsnkjyqwps 1 300 train
+gsnqvvauxc 1 300 train
+gsnvswjkxm 1 300 train
+gsnxgcjdtm 1 300 val
+gsoksqynrd 1 300 train
+gsolecscbm 0 300 train
+gsomzkioxq 1 300 train
+gsonsxkoib 1 300 train
+gsotgdkwdi 0 300 train
+gsoustqnhm 0 300 train
+gspajggizf 1 298 train
+gspcdmvvoj 1 300 train
+gspfcsepcy 1 99 train
+gspkzaeqxi 1 300 train
+gspmrngxra 1 300 train
+gspojjvuyn 1 300 train
+gspptumlth 0 300 train
+gspxydfbup 1 241 train
+gspxymurun 1 300 train
+gspzmhpmgk 1 300 val
+gsqcanxotk 1 240 train
+gsqepibeqs 1 300 train
+gsqewoxbzm 1 300 train
+gsqigetvzm 1 298 train
+gsqjxejxuo 1 300 train
+gsrejchefp 1 301 train
+gsreldxplc 1 300 train
+gsrewrdkmg 1 300 train
+gsrncsgqcg 1 300 train
+gsrpruxeky 0 300 train
+gsrqbimmlr 1 300 train
+gsrtyhfpce 1 300 train
+gsrvfdzmsq 0 300 train
+gssebutvff 0 300 train
+gsshxchgqv 0 299 test
+gsslanrtsq 1 300 train
+gstbuvuets 1 300 train
+gstdfliahk 1 300 val
+gstflwfliv 1 300 train
+gstltcptwz 1 300 val
+gstqnjyteo 1 300 train
+gstyhbnxwx 0 300 train
+gsuaxyusvk 1 300 train
+gsubvcfqsu 1 299 val
+gsufmjyjfd 0 300 val
+gsupwijhxx 1 240 val
+gsurjeebwz 1 300 train
+gsuuxdtlsp 1 300 train
+gsvbqfdmzq 1 300 val
+gsvhbvufvu 1 300 train
+gsviktqtsj 1 300 train
+gsvlvvaliu 1 301 train
+gsvnccxuzy 1 300 val
+gsvvtbcxik 1 300 val
+gsvxsozxbv 1 300 train
+gswetskbvb 1 300 train
+gswfskmdnd 1 301 val
+gswgzcqiav 1 300 train
+gswihgkujl 1 300 train
+gswplrzgrl 1 300 train
+gswszvoojm 1 299 test
+gswwmzzjhl 1 300 train
+gsxfhwihop 1 300 val
+gsxfyhudip 1 300 train
+gsxhrxrxyp 0 300 train
+gsxlolioxh 0 300 train
+gsxmjjhtft 0 300 val
+gsycrgkyew 1 300 train
+gsyfeboidl 1 301 train
+gsyjiiflyp 1 301 train
+gsyluazbir 1 300 train
+gsyluyxncf 1 300 val
+gsymziortr 1 300 train
+gsypkgezer 1 300 train
+gsyttxitgj 1 300 val
+gsyuqlpdac 1 300 train
+gsyywcclqp 1 300 val
+gszezmtvth 1 300 train
+gszgqnuzox 1 300 train
+gszhahvdfa 1 300 val
+gszkgixytj 1 300 train
+gszkkhehvi 1 301 train
+gszytodwnu 1 300 train
+gtadhnwicu 1 241 val
+gtakjbzpjr 0 300 train
+gtawaprccv 1 300 train
+gtazbanxdk 1 302 train
+gtbdaoxsdx 1 300 train
+gtbjejzsaf 0 300 train
+gtbjyhvpjl 1 300 train
+gtbmmjlyes 1 300 train
+gtbulzataa 0 300 train
+gtbzjhcfry 0 300 train
+gtcclzcagp 1 300 train
+gtciihctcl 1 301 val
+gtclpbinzh 1 300 train
+gtcqcdmdtb 1 301 train
+gtcqlfgves 1 301 train
+gtcvkofcmi 1 300 train
+gtdauewqci 1 300 train
+gtdbrdsrao 1 300 val
+gtdjfweoyr 1 300 test
+gtdjltklox 1 300 train
+gtdkzkofox 0 300 val
+gtdlbubycy 1 300 train
+gteegjifpn 1 300 train
+gtehnsuwpf 1 300 train
+gteirzrqgj 1 300 train
+gtempuluqe 0 301 train
+gtewnheslp 1 298 train
+gteyoegtwz 1 300 val
+gtfalmavrm 1 300 train
+gtfdzhhreu 1 300 train
+gtfeptcxic 1 300 val
+gtfeygqlgd 1 300 val
+gtfjzwhpuh 1 300 train
+gtfpkooeab 1 300 train
+gtfqrajodf 1 300 train
+gtftaekbye 1 240 train
+gtftthpycv 0 300 train
+gtfwmnswmg 0 300 train
+gtfwzfrxml 1 300 test
+gtfydughgx 1 300 train
+gtgaqkzmtz 1 241 train
+gtgekhxhwf 1 298 train
+gtgjhateos 1 300 train
+gtgkunfyms 1 300 val
+gtglqdxsbl 1 300 train
+gtgmxqvkwh 1 300 train
+gtgnhgzrye 0 300 train
+gtgnsdblos 1 300 train
+gtgqxspgjl 0 300 train
+gtgtsreuso 1 300 train
+gtgukbzahg 1 300 train
+gthcuihaxs 0 300 train
+gthgmboyet 1 300 train
+gthptdgtgx 1 300 train
+gthvvygfcj 1 300 train
+gtibxfvlrv 1 300 train
+gtijvhuhxw 1 300 val
+gtinxlhder 1 300 test
+gtiyrmrily 1 300 train
+gtjichhfwd 1 300 train
+gtjlcqrjxl 0 300 train
+gtjqkjjkbv 1 300 train
+gtjsmzvnfp 0 300 train
+gtjzctrcva 1 300 train
+gtkbmwycli 1 300 train
+gtkcjpdyda 1 300 train
+gtkdnbowjr 1 300 val
+gtkjgrkufy 1 300 train
+gtkmzgfdrl 0 300 train
+gtkrvhnjuz 1 300 train
+gtksiofiwm 1 300 val
+gtkwflqyat 0 290 train
+gtkwzqzcpf 1 300 train
+gtkygihtwl 1 300 val
+gtlavcfzqn 1 300 train
+gtlldwduek 1 300 train
+gtlqonbaur 1 300 train
+gtlszjzqaa 0 300 train
+gtlxzmznjl 1 301 train
+gtmhoqvsud 1 241 train
+gtmuyeicwd 1 300 train
+gtnefxzobl 1 300 train
+gtnobsfmmg 1 300 train
+gtnpatlnxp 1 300 train
+gtnpqevfqh 0 300 train
+gtnprsrvpc 1 300 train
+gtnriwuckg 1 301 train
+gtnyjahhmp 1 300 train
+gtoahfhdcu 1 300 train
+gtoenaoylf 1 300 train
+gtohtrqukn 1 300 train
+gtolbxsyzd 1 300 train
+gtomdumcwa 1 300 train
+gtopzxctxx 1 300 val
+gtoravwwrm 1 301 train
+gtotdtzxqz 1 300 train
+gtouadtfni 0 300 train
+gtoxgbepyx 1 300 train
+gtpajvnljq 0 300 train
+gtpbqogpif 1 300 train
+gtpbsniqon 0 300 val
+gtpcxrisuc 1 301 train
+gtpdnjqqws 1 300 train
+gtplxcgfys 1 300 train
+gtpocctdjv 1 299 val
+gtpxsirrch 0 300 train
+gtpyvlmabx 1 300 train
+gtqqtxgvox 1 300 test
+gtqraqbdxd 1 300 train
+gtqxflvavu 1 300 val
+gtrfjghdfx 1 300 train
+gtrndgtyqk 1 300 train
+gtrricaool 1 300 train
+gtrymxgptc 1 300 val
+gtryzrhzak 1 241 train
+gtsdtzhhtx 1 300 train
+gtsgruydpw 1 298 val
+gtsodxtlcl 0 298 train
+gtsusawepa 0 300 train
+gtsyozritx 1 300 train
+gtszxkkphy 1 300 train
+gttcfnpbnd 1 300 train
+gttjnebniq 1 300 train
+gttlcyeqjz 1 300 train
+gttlvhvjnr 1 300 train
+gttowpjtkl 1 300 train
+gttpffsvcw 1 298 train
+gttpwaovxb 1 300 train
+gttqggvfav 1 300 val
+gtujhceory 0 300 train
+gtultxwvqb 1 300 train
+gtuqedcuci 1 300 val
+gtuqynohfh 1 300 train
+gtvfiromcp 1 300 val
+gtvmvlycjc 1 301 train
+gtvomesekf 1 300 train
+gtvpdavabd 1 300 train
+gtvszqcyiu 0 300 train
+gtwfuuoyfo 1 300 val
+gtwgpgmxay 1 300 train
+gtwgyqlshj 1 302 train
+gtwmzolkhl 1 300 val
+gtwspzfcve 1 300 train
+gtwvsrdhdx 1 300 val
+gtwxiblkwz 1 300 train
+gtxprkivjy 0 300 train
+gtxpsfblyr 1 300 train
+gtxwviqphc 1 300 train
+gtxzguuouj 1 300 train
+gtyiiwgavr 1 298 train
+gtyngehltp 1 300 train
+gtyqjlhoas 1 300 train
+gtytdibwzo 1 300 train
+gtyunvyxal 0 300 train
+gtyvtbojpp 0 300 train
+gtzexfiujg 0 300 val
+gtzklhcjrb 1 300 val
+gtzpaxhoow 1 300 train
+guaenetucl 1 300 train
+guahhqdsyq 1 300 train
+guairfomyk 1 300 train
+guamkilhnt 1 300 train
+guatsfkqxn 1 300 train
+guaxhtxrlh 1 300 val
+guaxsdkngw 1 299 train
+guazsvosbe 1 300 train
+gubdkujsvg 1 300 val
+gubgciotgd 1 300 train
+gubgsfgcxg 1 300 train
+gublhyldxn 1 300 train
+gubsttfwnz 1 300 train
+gubwqazrpm 1 300 val
+gubywfpyhc 1 300 train
+guclsnyxvq 1 300 train
+gucmoqsjbz 1 300 train
+gucsgoyqes 1 300 train
+gucsyifbhx 1 299 train
+guczjrrjpt 1 300 train
+gudbaucusm 1 300 train
+gudedkpnie 1 300 test
+gudkpeguyq 1 297 train
+gudniqrnda 1 300 train
+gudnqcenha 0 300 train
+gudsqoyieo 1 300 train
+guduwhfqep 0 301 train
+gudwgfmmbq 1 301 train
+gudwzyzpol 1 302 train
+gueccdqigw 1 300 train
+guecziuobg 0 300 train
+guemdthavy 0 300 val
+gueoxgxpcy 1 301 train
+guerwoutas 1 300 train
+gueuxgisxo 0 300 train
+guevmaxztv 1 300 train
+guezpomtrv 1 300 train
+gufbyiznnf 0 300 train
+guffckbvby 1 300 train
+gufhvkutxh 1 136 train
+gufwnzmwli 1 300 val
+gugbtjmajr 1 300 train
+gugeiukesq 1 300 train
+gugfkgmtaf 1 301 train
+gugjpfnriv 0 300 train
+gugsvvuqzo 1 300 train
+gugxmnqcuz 1 300 train
+gugzqgltfd 1 300 train
+gugzqhjpka 1 300 val
+guhbdgmemt 1 300 train
+guhqwecykl 0 300 val
+guhrzvyqtz 1 300 train
+guhysklzbd 0 300 train
+guibfddplh 1 300 train
+guikinmnpm 1 300 train
+guipdaxnix 1 300 train
+guipnszqow 0 300 val
+guiqkjvudb 1 300 val
+guitgvirdt 1 300 train
+guiupvmbnj 0 300 train
+gujfbfpajx 1 240 train
+gujfmnwfsg 1 300 train
+gujkjbursj 1 300 train
+gujknxshww 1 300 train
+gujltqnimc 1 300 train
+gujnhuvarb 1 300 test
+gujtefpala 1 298 train
+gujuuvyxyt 1 300 train
+gujzyphkky 1 300 train
+gukasdlgbw 1 300 train
+gukbgsqpxt 1 300 train
+gukkdligzb 0 300 val
+gukpcfwkuo 1 300 train
+gulcdszfwd 1 300 train
+gulevllfxt 0 300 train
+guligiuqch 1 300 train
+gullqzkwez 1 300 val
+gulpcxaxhc 0 300 train
+gulyhrjbrn 1 300 train
+gulyhvchld 1 300 train
+gumakltsve 1 300 train
+gumbljalou 1 300 train
+gumcnhxhju 1 300 train
+gumgtfoblf 1 300 train
+gumgvhycum 1 300 test
+gumibfxigf 0 300 train
+gumisvjiaf 1 300 train
+gumjimknrf 1 300 train
+gumtanuzts 1 300 train
+gumuvrnmnw 1 300 val
+gunamloolc 1 299 test
+gunjdvluqr 1 300 train
+gunqoeunxj 1 300 train
+gunswjvcre 1 300 train
+gunumpmomk 1 298 train
+gunuuztaxd 0 300 train
+gunvgbbxht 1 300 train
+guoproqwnf 1 301 train
+guorqioozw 1 300 train
+guotalmatn 1 298 train
+guoubqfpam 1 300 train
+guougkebbc 1 301 train
+guoxrfrcjl 1 300 train
+gupfxsxboj 0 300 train
+guplchrlzb 1 300 train
+gupmonxwdm 1 300 train
+gupnzjvird 1 300 val
+gupsnsulzg 1 300 train
+gupsrlgheh 1 300 val
+gupsvszzkb 0 300 train
+gupwexfkmw 0 300 train
+gupyznzzsg 1 300 train
+guqayoypew 1 300 test
+guqsjffedj 1 301 train
+guqykzfgpo 1 298 val
+guqzikoyyv 1 300 train
+gurdreuxlv 0 300 train
+gureoksscs 1 300 train
+gurgzgaapw 1 300 train
+gurkxerekr 0 300 val
+gurtlckxhh 1 301 train
+gurzpxkvrb 1 300 val
+guscfdprgd 1 300 val
+gusiqxfrzw 1 300 train
+gusmunifrj 1 300 val
+gusnkhexha 1 300 train
+gusujwfozv 1 300 val
+guswdimgwr 1 301 val
+gusxdctnuq 0 300 val
+gutbdexyid 1 300 train
+guthddbqij 1 300 val
+guthmdaova 1 296 train
+guthpzsxmr 1 300 val
+guthxhrqln 1 300 train
+gutjstyrxk 1 298 train
+gutmvovhsj 1 300 train
+gutujxzrwz 1 300 train
+gutukjzyfq 1 300 train
+guuaoviovo 1 300 train
+guuevcvywx 1 300 val
+guuexzajyg 1 300 train
+guuhedkomg 1 300 train
+guukoblftf 1 300 train
+guunxrhwrd 1 300 train
+guupwbnbzc 0 298 train
+guuuqkgzoo 1 240 train
+guvcexkwdz 1 300 train
+guvkmwfxew 1 300 train
+guvnquoajy 1 300 train
+guvprjxopl 1 301 val
+guvptbqgrj 1 300 train
+guvqpztgwf 1 300 train
+guvtadxsbd 0 300 train
+guvylgejhy 1 300 val
+guvzjrzqyh 1 300 train
+guwffsajwn 1 298 train
+guwjunbxjx 0 300 train
+guwmrgcgrb 1 299 test
+guwmumtpzh 1 300 val
+guwntixeec 1 300 train
+guwqwhnpzx 1 300 train
+guwqzsoqjd 0 300 train
+guxewrqhfb 1 300 train
+guxmojzlbj 1 300 train
+guxqzghrat 1 300 train
+guxuhehldu 0 300 train
+guxuxfeekl 1 300 train
+guxwanumvz 1 301 train
+guxzdbakef 1 300 train
+guycctasoq 1 300 train
+guymqchfwo 1 300 train
+guyppejziz 1 300 val
+guytsqxffo 1 300 train
+guyunvsdsx 0 300 val
+guyytkpebp 1 300 train
+guzbduenyt 1 302 train
+guzfeoeybw 1 300 val
+guzjutrpju 1 300 val
+guzkiukrgs 1 300 train
+guznvfxqtj 1 300 train
+guzzizvlka 1 300 train
+guzzjgmmkx 1 298 val
+gvaepednwe 1 300 train
+gvakjgsafd 0 300 train
+gvammmuqbk 1 300 train
+gvanlxrmxf 1 300 train
+gvasarkpfh 0 300 val
+gvasdexmhe 1 300 train
+gvavfwxkhm 1 300 train
+gvbbploter 1 298 train
+gvbbunnuat 1 300 train
+gvbcwuyaot 1 300 test
+gvbhzwgszk 1 300 val
+gvbrxjqgaz 1 300 val
+gvbwohzsui 1 239 val
+gvcexhmzgf 1 300 train
+gvchkcbjss 1 300 train
+gvckxlrkmh 1 299 train
+gvcmjpbcvd 1 300 val
+gvcqqdwswv 1 136 train
+gvcrwbnzpa 1 300 train
+gvcvgscwwp 1 300 train
+gvcwrbcqdd 1 300 val
+gvcwutdnxc 0 300 val
+gvcycjpyda 1 300 train
+gvczsjkuan 1 300 test
+gvdddfgpuv 1 300 train
+gvdjbnxmhw 1 300 train
+gvdlijoszh 1 300 train
+gvdqdduzkm 1 300 train
+gvdqnwqaia 1 300 train
+gvdzbvkrlf 1 300 train
+gveeswbyyt 1 300 train
+gvehwkpgfv 1 301 train
+gvejaseods 1 300 val
+gvekjxzsik 1 300 train
+gvekoglrgx 1 300 train
+gvelqlpjlg 1 300 train
+gverizloak 1 300 train
+gvexaanjol 1 241 train
+gveyigisjo 1 300 train
+gvfblfpwca 1 301 train
+gvffzcwdrf 0 300 val
+gvfhcvqmbu 1 298 train
+gvfmiauwfl 1 300 train
+gvfusfgxev 1 301 val
+gvfvpjomcj 1 300 val
+gvfzgmwgzn 1 300 val
+gvgajrzeed 1 167 train
+gvgiwbkaiu 1 300 train
+gvgkvfjchj 1 298 train
+gvgmiadpiw 1 299 train
+gvgndzazvc 1 300 val
+gvgsugqfrg 1 300 train
+gvgwkrqtid 1 300 train
+gvgxwfdoif 1 300 train
+gvgzzgiqng 1 300 train
+gvhelarjwu 1 300 train
+gvhnlizrst 1 301 val
+gvhvwnyqhp 1 300 train
+gvibkwutuu 1 300 train
+gvicncmstz 0 300 train
+gvigkxojrw 1 300 train
+gvihoaswnr 1 300 train
+gvimuvqicd 1 300 val
+gvinntguhu 1 300 train
+gviozcjywl 1 302 train
+gviqewwufy 0 300 train
+gvirmwwkby 1 300 val
+gvisnrzibp 1 300 train
+gvizslvthj 1 300 train
+gvjeldetmv 1 300 val
+gvjesqmidg 1 300 train
+gvjkpdmvcg 1 300 train
+gvjmebnzzt 1 300 train
+gvjmqqijof 1 300 train
+gvjnpsvvfm 1 298 train
+gvjqcspjqk 1 249 train
+gvjszxsaku 1 300 train
+gvjwggknjf 1 300 val
+gvjxdqdjif 1 300 train
+gvkguejifk 1 300 train
+gvkgxyutkg 0 300 train
+gvkkeczzhe 1 300 train
+gvklsdqvnf 1 300 train
+gvkrkvbocw 1 300 train
+gvkshqoaoc 1 300 train
+gvktgluynt 1 300 train
+gvktmuazoz 0 296 train
+gvkwjftsoz 1 300 train
+gvkxompcdm 1 300 val
+gvlagxnnyh 1 300 train
+gvlatpvbvl 1 300 train
+gvlbvgcgdy 1 300 train
+gvlczlcpmq 0 300 train
+gvleesmgxz 1 300 test
+gvlegsuxrg 1 300 train
+gvlnsvbyrd 1 300 train
+gvlraqlweh 1 300 test
+gvlsustfbo 1 300 train
+gvlswvktmc 1 301 train
+gvlvrhgndw 0 300 train
+gvlxpgoijy 1 301 val
+gvlzenjwxb 1 300 val
+gvmdxsphgr 1 300 train
+gvmfxvenfz 1 300 train
+gvmmfnzgbq 1 300 train
+gvmuanyslh 1 300 train
+gvmvhplfbh 1 300 train
+gvnamnxrky 1 300 train
+gvncyqyfef 1 300 val
+gvnebnzirc 1 301 train
+gvnikaiiur 1 300 train
+gvnjgfmlvx 1 300 train
+gvnujrxrzp 1 300 train
+gvnxvqitrc 1 296 val
+gvnzcagmxk 1 300 val
+gvofgqumty 0 300 train
+gvokuxhsbf 1 300 train
+gvonpgtonn 1 300 train
+gvoovcgcbs 1 300 train
+gvooygdutl 1 300 train
+gvoppdyhiw 1 300 train
+gvoysenthe 1 298 train
+gvpaetxlip 1 300 train
+gvpbfubycd 1 300 train
+gvpmjmxhzj 1 300 train
+gvpmmduxua 1 300 val
+gvpoijxknl 0 300 train
+gvpqgtsuyh 0 300 val
+gvprksvuns 1 300 train
+gvprrsuzgh 1 298 train
+gvpsdogkiu 1 298 train
+gvqayoquux 0 300 train
+gvqnyftnqr 0 300 val
+gvqpuklsdk 1 300 train
+gvqqrneklk 1 300 train
+gvqrhpadpx 1 300 val
+gvqtcevzuo 1 300 train
+gvqtciuapu 0 300 train
+gvqtnedfso 1 300 train
+gvqyepcntc 1 300 train
+gvrndkdbwg 1 298 train
+gvrsulnkqu 0 300 train
+gvrtvflyup 0 300 val
+gvrznjpirs 1 300 train
+gvsabhrfxt 1 300 val
+gvscaplsah 1 241 train
+gvsfkkpktb 1 300 val
+gvskxuepjw 1 300 train
+gvsnifvwiu 1 298 train
+gvsnktlqne 1 300 train
+gvsriirkvl 1 300 val
+gvsvbfoktc 1 300 train
+gvswyialmf 1 300 train
+gvtdhlwptd 1 298 train
+gvtgdfoxah 1 300 train
+gvtgivqlhc 1 300 val
+gvttgmblkt 1 300 train
+gvtwqpxqvh 1 300 train
+gvtwuzglpk 1 300 train
+gvtyefwwiw 1 297 train
+gvtyfuisjr 1 300 train
+gvtyvjfbqz 1 300 val
+gvtzyqkwix 1 298 train
+gvucrwhjdq 0 300 train
+gvugievkqg 1 300 train
+gvuknosmbn 1 300 train
+gvulrwphov 1 299 test
+gvuvdhzcqu 0 300 val
+gvuwhthlkb 1 301 val
+gvvfwdlauq 1 300 train
+gvvhegkoiz 1 300 train
+gvvorfbmne 1 300 train
+gvvqkgjmqd 0 300 train
+gvvtqekgnn 1 300 train
+gvvyrsydsk 1 300 train
+gvwgmadlws 1 300 train
+gvwibyfmby 1 300 train
+gvwkwkosow 0 300 train
+gvwohpgpyu 1 300 val
+gvwqberjhs 0 300 train
+gvwqlnccyb 1 300 train
+gvwsbshbuz 1 300 train
+gvwsgyexpl 0 300 val
+gvwtxgpfer 1 300 train
+gvwvorbuto 1 300 train
+gvxatmhmev 1 300 val
+gvxbesmujd 1 300 val
+gvxefdkyrb 1 300 train
+gvxermtjav 0 300 train
+gvxevjcnud 1 298 train
+gvxiqjjkab 1 299 test
+gvxubmogmp 0 300 train
+gvxxuwvfmx 1 300 train
+gvxykreesx 1 298 train
+gvycszbsqv 0 300 val
+gvyjskpsbn 1 300 train
+gvymuzptfo 1 300 train
+gvythshkdh 1 300 train
+gvyvbdlfap 1 300 train
+gvyytljpjs 0 300 train
+gvyzmvvvst 1 300 train
+gvzckydbin 1 300 train
+gvzhautbsl 0 300 train
+gvzmdghcdc 1 300 val
+gvzpnjrjdr 0 300 val
+gvzquyojht 0 300 train
+gvztvkzyar 1 300 train
+gvzualusso 1 300 train
+gwadlivyoy 1 300 val
+gwaoeruqxm 1 300 train
+gwaoipkunh 1 298 val
+gwaomozuko 1 300 train
+gwasythsfn 1 300 train
+gwauxumrmi 1 300 train
+gwaxqwlsww 1 300 train
+gwazpgohym 1 300 val
+gwbfvbqtwl 1 241 train
+gwblqipaxf 1 241 train
+gwbqirmhfs 1 300 val
+gwbtfherju 1 301 train
+gwcackkeyx 1 300 train
+gwcgpeyreu 1 240 train
+gwclchhqqu 1 300 train
+gwcngswmpj 1 300 train
+gwcrqnusun 1 300 train
+gwcszwubdj 1 300 train
+gwcuabvasm 1 300 train
+gwczqlszfp 1 300 train
+gwdgaxgtbf 0 300 train
+gwdijepfcg 1 300 train
+gwdnovbrja 0 301 val
+gwdqpqwzmt 1 300 train
+gwduldervr 1 299 train
+gwdvwhimpp 1 300 train
+gweajahowj 1 300 val
+gwefvpvsyh 1 300 train
+gwehlksuia 1 300 train
+gwepblsbdi 1 298 train
+gweqqjwlxg 0 300 train
+gwfemtpzik 1 241 train
+gwfemwjrjx 1 300 train
+gwfgzoxmox 1 300 train
+gwfkzbprgu 1 301 val
+gwfllcwyof 1 300 val
+gwflolvfpp 1 300 train
+gwfnjzzqju 1 300 train
+gwfplwjvqk 1 300 train
+gwfykhtnqd 1 302 train
+gwfzxvjjaw 1 300 val
+gwgqpoaben 0 300 train
+gwgqwraxua 1 298 train
+gwgzlfioeo 1 300 train
+gwhblymftp 1 300 train
+gwhdmjsjlp 1 300 train
+gwhetnxtmd 0 300 val
+gwhfrfguef 1 300 val
+gwhhwvbidr 1 300 val
+gwhirvvovr 0 300 val
+gwhjicgbzl 1 300 train
+gwhzrvwcky 1 300 train
+gwiamzhwlp 1 298 train
+gwiftoatuw 0 300 train
+gwihhlwtiq 0 300 val
+gwipngyeaz 1 300 train
+gwirozzovl 1 300 train
+gwivoycgzb 1 300 train
+gwivrmiros 1 300 train
+gwixomgafk 0 300 val
+gwjbumkoil 1 299 val
+gwjdhuarrb 1 300 train
+gwjdnxefon 0 300 val
+gwjgjuzzsp 1 300 train
+gwjhwktqmz 1 300 train
+gwjvucdwox 1 300 train
+gwjvzveyuq 1 298 train
+gwjygmdcca 1 300 train
+gwkglimpve 1 300 train
+gwkiyavxnq 1 300 train
+gwkrdjivto 1 301 train
+gwkspxiopk 1 300 train
+gwkujlufjr 1 300 train
+gwkxazzmmr 0 300 train
+gwldjrjahk 1 300 train
+gwlhmtkofu 1 300 train
+gwljmnlisu 1 300 train
+gwlkwkdpov 1 300 train
+gwltoqjbfk 1 300 train
+gwmbvteaor 1 300 train
+gwmlawcreb 0 298 train
+gwmnorecss 1 300 val
+gwmnrkbdsq 1 241 train
+gwmnzgwapx 0 300 train
+gwmolehgvj 1 300 train
+gwmpjvzjug 1 300 train
+gwnaxtndii 1 300 train
+gwnbsmavrp 1 300 train
+gwnobwxcrc 1 300 train
+gwnrgnjxlq 1 241 train
+gwnuczonkk 0 300 train
+gwnwppscuf 1 300 train
+gwnxqtenem 1 301 train
+gwoetgongv 1 300 val
+gwohmzhrpk 1 300 train
+gwokxqgiyr 1 300 train
+gwomyjtwvv 1 300 val
+gwooqsmvwy 1 300 train
+gwopdxzwhy 1 301 train
+gwopodktyx 1 300 train
+gwoqohzfgp 0 298 train
+gwowaxepoy 1 300 val
+gwozhhsfdb 1 300 train
+gwpanglzbd 1 300 train
+gwpdxinfbc 1 300 train
+gwpgbowzye 0 241 train
+gwphcrttwz 1 300 val
+gwponardoa 1 300 train
+gwpyjfjctj 1 300 train
+gwpztsfcix 1 297 train
+gwqaqnnhyn 1 300 val
+gwqdrapybq 0 300 train
+gwqhmpeumj 1 296 train
+gwqirctmea 1 300 train
+gwqkhobeyv 1 300 val
+gwqplejvnt 1 300 train
+gwqpmnobaq 1 300 train
+gwraedckcg 1 300 train
+gwrloogbta 1 300 train
+gwrnbskgml 1 300 train
+gwrsfgxprq 0 300 train
+gwrtgkqfql 1 300 train
+gwrvpajipu 1 300 train
+gwrwmuxoty 1 300 train
+gwrzjyvkct 1 300 val
+gwscxngizr 1 300 val
+gwsmeakcic 1 300 val
+gwswhkexsl 1 300 train
+gwsygunrfd 1 300 val
+gwsyumegbv 1 300 train
+gwtdydogdb 1 300 test
+gwtqrjjdfy 1 300 train
+gwtsqhwpjw 1 300 train
+gwtxwtvsss 1 300 val
+gwtzqfraxf 1 301 val
+gwuaqafgzt 1 300 train
+gwuhkbddjd 1 300 val
+gwukwbscxn 1 300 train
+gwuvxanihp 0 300 train
+gwuyimsylt 0 300 val
+gwvdqrkuux 0 300 train
+gwvidjjpek 1 300 train
+gwvoacgtde 1 300 train
+gwvqcnifto 1 300 val
+gwvssgmgmh 0 300 train
+gwvwbbfckb 0 300 val
+gwvzkmdwey 1 300 val
+gwwazyoqms 1 300 train
+gwwqciwoqs 0 300 train
+gwwtpriqcy 1 299 test
+gwwzddwvov 1 300 train
+gwxegwtsaj 1 299 test
+gwxlzwccif 1 300 train
+gwxotldolu 1 300 val
+gwxtrqsaew 0 300 train
+gwxvwumuva 1 300 train
+gwycefxenh 1 300 train
+gwydgdzgvq 1 296 train
+gwydnqcjfv 1 300 train
+gwydplyioc 0 300 train
+gwymeedakp 1 300 train
+gwymndbhen 1 300 train
+gwyoyccafj 1 300 train
+gwypcwesyg 0 299 train
+gwyvzkvvld 0 300 train
+gwzavddryz 1 300 train
+gwzawzndsp 1 300 train
+gwzbuelxct 1 300 train
+gwzeubnydg 0 300 val
+gwzfugbidx 1 300 test
+gwzttezkpv 0 300 val
+gxafhatuxj 1 300 val
+gxagxjdhoe 1 300 train
+gxahsvasub 1 300 train
+gxarkezoin 1 300 train
+gxaxnlxlbg 1 300 train
+gxbdbjjeup 1 300 train
+gxbkcxyfjm 0 300 train
+gxblelyihv 1 300 val
+gxbrybjgmn 1 300 train
+gxbzqwldsp 1 300 train
+gxcakcrndd 1 300 val
+gxcjhsmuqc 1 297 train
+gxcoafghbo 1 300 val
+gxcoglmcjy 1 300 train
+gxcyjadqpe 1 300 train
+gxdauznilj 0 300 train
+gxdbjmerhb 1 300 train
+gxdimngwgr 1 300 val
+gxdnihgbib 1 300 train
+gxdqhookvo 1 300 train
+gxdwfjrkyn 0 300 train
+gxdzpuxjlg 1 300 train
+gxeexnwuua 1 300 train
+gxeknmhrwx 1 300 val
+gxekqzllls 0 300 train
+gxembgiarp 0 300 train
+gxemcrngus 1 300 train
+gxeogmuaiz 1 300 train
+gxeokzxuzn 0 300 train
+gxeumhwsux 1 298 train
+gxexltzdzl 1 300 train
+gxfaiqipcw 1 241 train
+gxfbtusigy 1 300 val
+gxfcjjtiit 0 300 train
+gxfrxcxgdf 1 300 train
+gxfuwrikbz 1 300 train
+gxfyvxdibc 1 300 train
+gxgaikozer 0 300 train
+gxgebeeulk 1 300 train
+gxgglolowb 1 300 train
+gxgnvuufdj 1 300 val
+gxgqgnniro 1 300 val
+gxgseukasu 1 300 train
+gxgvbmqzxn 1 300 train
+gxgwpmrcjs 1 300 train
+gxgxsrftqs 0 300 train
+gxgytyxovs 1 300 train
+gxgywzyycz 1 300 val
+gxhcmcdstc 1 301 val
+gxhcuxulhi 0 300 train
+gxhigzfqiq 1 300 train
+gxhkzichcb 1 300 train
+gxhmwktmgg 0 300 train
+gxhphiheet 0 300 train
+gxhssdgnrm 1 300 train
+gxhvvbazur 1 241 val
+gxhxcqltpk 1 300 val
+gxhyhwxmfs 1 300 train
+gxhyukxwgx 1 300 train
+gxhzqfiqni 1 300 train
+gxijetxugw 1 300 train
+gxikrajfoi 1 302 train
+gxioqoexyb 1 300 train
+gxirgivmtq 1 301 val
+gxixautknf 1 301 train
+gxixmivsuh 1 301 train
+gxiynseggz 0 300 train
+gxjgbovfvm 1 300 val
+gxjhbocsui 1 300 val
+gxjlopeyls 1 300 train
+gxjmrlupje 1 300 train
+gxjpfshbzy 1 300 train
+gxkjqcicyt 1 300 train
+gxkkyzahaj 1 240 train
+gxkohasmfj 1 300 train
+gxlgmnmbqk 1 300 train
+gxlqqayjkx 1 300 train
+gxmiszefsm 1 241 train
+gxnfkuujyv 0 300 train
+gxngmfmgoh 1 298 train
+gxnjamrtcf 1 300 train
+gxnjgokfrs 1 299 test
+gxnmiqvuky 0 301 train
+gxnnxnyklc 1 300 train
+gxnpgaquti 1 300 test
+gxohwflxvs 1 300 train
+gxonqiyzpk 1 300 val
+gxoqqilnel 1 300 train
+gxorpagqfn 1 300 train
+gxotbbzdqi 1 300 train
+gxoudzukfe 1 300 val
+gxoutxuksj 1 300 train
+gxoywjwgfe 1 300 val
+gxpenheogd 1 241 train
+gxpiowhqnw 1 300 train
+gxpohzcamw 1 300 train
+gxpqqrwqab 1 300 train
+gxpteclppy 0 300 train
+gxpuqjdzcu 1 146 train
+gxqhacfxaf 1 299 val
+gxqqhcxqux 1 300 train
+gxqzavbulk 0 300 train
+gxramsjxvg 1 300 train
+gxrdpwklmt 1 300 val
+gxrgmigzwn 1 300 train
+gxriengaro 0 297 train
+gxrjozfsaa 1 300 val
+gxrocwxkyy 1 300 val
+gxrofltkjn 0 300 train
+gxrqxnlvfe 1 300 train
+gxrswiehai 1 300 train
+gxrtesajns 0 299 train
+gxrtyxmkbj 1 301 train
+gxsbbcjuzh 0 300 train
+gxsfmaqauz 1 300 train
+gxskukcgnu 1 300 train
+gxsxeldvpl 1 300 val
+gxtcwagrya 1 300 val
+gxtkixenvj 0 300 train
+gxtkpbexrm 0 299 val
+gxtlvahove 1 300 train
+gxtphaaujn 1 297 train
+gxtutdbkfu 1 300 train
+gxuetvjkho 1 300 train
+gxuncqgppg 1 299 val
+gxuqqvvvpw 1 300 val
+gxusbybkgj 0 300 train
+gxuyzvutwf 1 298 val
+gxvbypqozt 0 300 train
+gxvhxyghku 0 300 train
+gxvifszntd 1 300 train
+gxvpdlmwna 1 300 train
+gxvpgclcho 1 300 train
+gxvqpfiulb 1 301 val
+gxvvbqclib 1 300 train
+gxvvqphvls 1 300 train
+gxvyapjrqs 1 300 train
+gxvyijevam 1 300 train
+gxwfabcord 1 300 train
+gxwhcgcnfr 1 300 train
+gxwibvaesd 1 300 train
+gxwmwjmyxr 1 300 train
+gxwsebonze 1 300 train
+gxwwpnlcxy 1 300 train
+gxxcarolcc 1 300 train
+gxxjvyghem 0 300 train
+gxxlbjuyza 0 300 val
+gxyeiteetm 1 300 train
+gxyqwraipn 1 300 train
+gxytgtbrld 1 300 train
+gxyvvdtswi 0 300 val
+gxzdueambi 1 300 test
+gxzlnrtbfe 1 300 val
+gxzmlpuxgz 1 300 train
+gxzmtungxc 1 300 train
+gxzzpoqvsh 1 301 train
+gyainwhgmf 1 300 train
+gyaiywhloc 1 301 train
+gyalzphjgt 1 241 train
+gyamabedgl 1 298 train
+gyapfffpvd 1 300 train
+gyaqwfujgg 1 299 val
+gyarwewnap 1 300 train
+gyattlblqh 1 301 train
+gyaxfbagnj 1 300 train
+gybjvchwoy 1 300 train
+gyboafwxwx 1 300 train
+gyboojigst 1 299 train
+gybqsrrwhc 1 300 train
+gybxdkdrpg 1 300 train
+gycbnhkicd 1 300 train
+gycbzrnrjf 1 300 train
+gyccrjplmo 1 300 val
+gyckbbatpt 1 300 train
+gycmhpbghv 1 288 train
+gycrbqqnje 1 300 val
+gycrnobqpp 0 300 train
+gycsdchxjv 0 300 train
+gycuzhhkpm 1 300 train
+gydaqrxshh 1 300 train
+gydgdqiduz 0 300 val
+gydiqiazti 1 300 train
+gydjwwwbno 1 300 train
+gydphqcsjz 1 300 train
+gydvsfdigh 1 300 train
+gydzgrthnw 1 301 val
+gyeaqcnxhx 1 300 train
+gyegjupbal 1 300 val
+gyeshxcfzm 1 300 train
+gyexknytsf 1 300 val
+gyezotejdl 0 300 val
+gyfeijcrwl 1 300 train
+gyfejplagr 1 302 train
+gyfoeuuwfr 1 300 train
+gyfqnutjyv 0 300 train
+gyfvycxfie 1 300 train
+gygcwtvdwz 1 300 train
+gyghugsmoh 1 300 train
+gygjqhfdvw 1 300 train
+gyglbbksfo 1 300 train
+gygnkpqxlp 1 300 train
+gygpptbdmp 1 300 train
+gygzemzgnf 1 300 train
+gyheqxrzpw 1 300 train
+gyhnrcmqpw 1 301 train
+gyhsfhbrtb 1 300 train
+gyibxtkqsu 1 300 train
+gyieiooddh 1 300 train
+gyigwifmde 0 300 val
+gyihcfbtqv 1 300 train
+gyiknkigjg 1 299 test
+gyilexcdfs 1 300 train
+gyismzbpat 1 300 train
+gyiustrwjv 1 300 train
+gyjdebcqrc 1 300 train
+gyjinrsxmr 1 300 train
+gyjsfnrebs 0 300 train
+gyjwdezhhy 1 300 train
+gyjxuppxad 1 300 train
+gykfuhwoaa 1 300 train
+gykfytcehm 1 298 val
+gykhpbgjvt 0 300 train
+gyknyxbcak 1 300 train
+gykodvavds 1 301 train
+gyksbhfprp 1 300 train
+gyktewxcsb 0 300 train
+gykvshoqvk 1 300 val
+gykxckcbyp 1 300 train
+gykyqruqkl 1 301 train
+gykzntrrbw 1 300 train
+gylbwgagfy 1 300 val
+gylcfcozce 0 300 val
+gylfnakizg 1 300 train
+gylhcczatl 1 300 val
+gylhgjymhf 1 298 val
+gyliqzgsuy 1 300 train
+gyllmdpgqz 1 300 train
+gyllupwjhs 1 300 val
+gylntzvolo 1 300 train
+gyluavwkij 0 300 train
+gylwlxqeer 1 300 train
+gymeckipqs 1 300 train
+gynpswzfos 1 300 train
+gynxsnzxit 1 301 val
+gyohjhqfmo 1 301 train
+gyojqqhflv 1 300 val
+gyokfwvgfk 0 301 train
+gyooimftle 1 301 val
+gyosmhohba 1 300 train
+gyosvoeamf 1 300 test
+gyouyaqhrz 0 300 train
+gypapuqdrx 0 300 train
+gypdfcqxao 1 300 train
+gypihejvbg 1 300 train
+gyppjmvypq 0 300 train
+gypqakzmrh 1 300 train
+gyptvyzbmk 1 300 train
+gyqjsymrvp 1 301 train
+gyqnfcdsge 1 301 train
+gyqnqhrtov 1 300 train
+gyqrbcitjb 1 300 train
+gyqrfxwjsf 1 300 val
+gyrdgpiygb 1 300 test
+gyrfwembgm 1 300 train
+gyriqqplxe 1 301 train
+gyrjkxbzfq 1 300 train
+gyrmgxlclo 1 300 train
+gyrmisvhlu 1 298 val
+gyrtordvwo 1 300 train
+gyrvbuxipr 1 300 train
+gyrwjitwhy 0 300 train
+gysaynthma 1 300 train
+gyskeqpyrj 1 240 train
+gysnhwqcmo 1 300 train
+gysnrxvhbn 1 300 train
+gysskuqdty 1 300 train
+gysupwvqhg 1 300 train
+gyswbocgpr 1 300 train
+gyswfzrmtd 1 240 val
+gytabbiasl 1 300 train
+gytbfpvkdv 1 298 val
+gytbkscrih 1 300 train
+gytegrqmrx 0 300 train
+gytgaaobsu 1 298 train
+gytjcguvml 1 300 val
+gytjcjvzxy 1 300 train
+gytqgluldt 0 298 train
+gytyaaladl 0 300 val
+gytyimgugz 1 300 train
+gytzbdhbww 1 300 train
+gytzzsfpxt 1 300 train
+gyudsgygya 1 300 train
+gyvdcrkyya 1 300 val
+gyvhfrhmhq 1 241 train
+gyvnqdhijo 1 300 train
+gyvolulghr 1 300 train
+gyvtwpzxbt 1 300 train
+gywcvsgmda 1 301 train
+gywcwslbhv 1 300 train
+gywgtlnovu 1 300 train
+gywkkzzoxq 0 299 train
+gywncszoog 1 300 train
+gywuzlodjr 1 300 train
+gywzlsqofn 1 300 train
+gywzngahoq 1 300 train
+gyxarnjzuc 1 300 val
+gyxeyzdwqf 1 300 test
+gyxfhyhagv 0 300 train
+gyxkyadmge 1 301 train
+gyxkzwnniw 1 300 train
+gyxlbygywk 0 300 train
+gyxtdltnoe 1 300 train
+gyypfzqxdc 1 300 train
+gyzixtmfen 1 299 val
+gyzjkvowqm 1 300 train
+gyzksucobq 1 300 train
+gyzplkphqa 1 300 train
+gzabjmglim 0 301 train
+gzacwawsuj 1 300 train
+gzaenvicht 1 300 train
+gzagvzwhhk 0 300 train
+gzalabksqk 1 300 train
+gzalkterqk 1 300 val
+gzaminhcri 1 300 val
+gzapmclgal 1 300 train
+gzaulpjuzb 1 300 train
+gzaxpcyrfs 1 298 train
+gzbagbdubm 0 299 train
+gzbepripts 1 300 train
+gzbfvvfevm 1 300 train
+gzbfzvyoqj 1 301 train
+gzbihntdbr 1 300 train
+gzbldmzycg 1 300 val
+gzblthunsd 1 300 train
+gzbpscjnvu 1 301 train
+gzbqorfjvc 1 300 train
+gzbuerncnl 1 300 train
+gzchkngvmx 1 300 train
+gzcieglwpm 1 301 val
+gzcjqhpqcp 1 288 train
+gzcqegoojz 1 300 train
+gzcqqabobe 1 300 train
+gzcsmtvrjv 1 300 train
+gzcuhiyvpo 0 300 train
+gzcuzkriku 1 300 val
+gzcwiguldz 1 300 train
+gzdeexgkwp 1 300 train
+gzdmaijwqq 1 302 val
+gzdmqiwkym 1 301 train
+gzdnifamxx 1 300 train
+gzdsestvja 1 300 train
+gzdslayhbo 1 300 train
+gzeakpgpun 1 300 train
+gzeidtyzub 0 300 train
+gzekgwdykm 1 298 train
+gzelwhnhbd 1 300 train
+gzeobetaac 1 300 train
+gzesfubacw 0 298 train
+gzezqvyuqj 1 300 val
+gzfhbsmkol 1 300 train
+gzfhwxgcxd 0 300 train
+gzfkpecqls 1 299 test
+gzflzoaadh 1 302 val
+gzfovnvluq 1 300 train
+gzfpunodyf 1 300 train
+gzfqezffrf 1 300 train
+gzfsgkohxy 1 300 train
+gzfucmvdsr 1 300 train
+gzfxxpqxvv 0 300 train
+gzgdgxwrjr 1 301 val
+gzgnmaxmxa 1 300 train
+gzgybfezly 1 298 val
+gzhcrxdqfv 1 300 test
+gzhkzspdvz 1 300 train
+gzhrzwsoha 1 300 train
+gzhxxfhpyx 1 300 train
+gziafukmkm 0 300 train
+gzialwlrmz 1 300 train
+gzibbaiwzl 1 298 train
+gzidgkmhzx 1 300 train
+gziftojyva 1 300 train
+gzihnqhkyn 1 300 val
+gziinptxup 0 300 train
+gzikqotwbl 1 300 train
+gzimxxskar 1 299 val
+gzinevflni 1 300 val
+gzioqzzsxq 1 300 train
+gzipxojewn 1 300 train
+gzixibzfdy 1 300 train
+gzjindhmkc 1 300 val
+gzjjdhmdff 1 300 train
+gzjlzygnac 1 300 train
+gzjphqbump 0 300 train
+gzjshcnkkg 1 300 train
+gzjzykoccl 1 300 val
+gzkcvmcnrq 1 300 train
+gzkggvloao 1 300 test
+gzklathjwo 1 298 train
+gzkxhufydr 1 300 val
+gzlatpceji 1 300 train
+gzlbvmboxm 1 300 train
+gzldpnysau 1 300 val
+gzlgpafpax 1 300 train
+gzlpgmwkih 1 300 train
+gzmazkegsv 1 300 train
+gzmcqnjgeh 1 300 train
+gzmcyoosih 1 301 val
+gzmijtpsxp 1 300 train
+gzmostmzdt 1 300 train
+gzmsocbmkz 0 300 train
+gznlbpdnxa 1 300 train
+gznmaualbr 1 300 val
+gznmonxiom 1 301 train
+gznphyupii 1 300 train
+gznswdsljq 1 301 val
+gzofefepbu 1 300 train
+gzohxjtbfd 1 300 train
+gzompgclwa 0 300 train
+gzpnyzoroy 1 300 train
+gzppmtghbx 1 300 train
+gzptosqztf 1 300 train
+gzptoulkhi 1 300 val
+gzpvonnbpm 1 298 train
+gzpyniwjiv 0 300 train
+gzpzmkyxey 1 300 train
+gzquromtns 1 300 train
+gzqyililkj 1 300 train
+gzqywnmwvp 1 300 train
+gzraxjxdiv 1 300 train
+gzrdiemlgb 1 300 train
+gzrfjlvvqu 1 300 train
+gzrgipegjc 1 299 train
+gzrswfalvp 1 300 train
+gzsgxalkve 1 300 train
+gzshocjyzm 1 298 train
+gzshsetbxk 1 300 val
+gzskgynxsa 1 300 train
+gzsppugoek 1 300 test
+gzsqbybrmz 1 300 train
+gzszyxolow 1 300 train
+gztamvyoxr 1 300 train
+gztdsonqlf 1 300 train
+gztffgsxpt 0 300 val
+gztkobhylv 1 300 train
+gztqmkbekw 1 298 val
+gzueauqyjw 1 300 train
+gzugkajudr 1 300 val
+gzukcthgqg 0 300 train
+gzutyeitxk 0 300 train
+gzuwgmrmmo 1 300 train
+gzvjnkkgka 1 300 train
+gzvkcocqqq 1 301 train
+gzvnqrchml 1 300 train
+gzvqxxjglz 1 300 train
+gzvsihgvyu 0 300 train
+gzvyjyvdoy 1 300 train
+gzwaaewbai 1 300 train
+gzwemmhhhp 1 300 train
+gzwnyxdwtg 1 300 val
+gzwpdcyauj 1 300 train
+gzwthckmpd 1 300 train
+gzwwstvxkb 0 300 train
+gzwzxbtkpd 1 300 train
+gzxcjotndi 1 301 train
+gzxlzukrbn 1 301 val
+gzxnoptair 1 241 train
+gzxtqsjyqm 0 300 train
+gzxyjojicr 1 300 train
+gzydkfronh 1 300 train
+gzykhcoocu 1 300 train
+gzypdzxoas 1 300 train
+gzyphxbstz 0 300 train
+gzyzadxidl 1 301 train
+gzyzdcbuuv 0 300 train
+gzyzqxvocf 0 300 train
+gzzbfuxtzw 1 300 train
+gzzprsbent 1 302 train
+gzzrnhzkgz 1 301 val
+gzzuyuhaxi 1 300 train
+gzzvhopbqc 0 300 train
+haaekhexdq 1 300 train
+haaeliryfq 1 300 val
+haaktoickz 1 300 train
+haawpbcezf 1 300 val
+habbjoltqj 1 300 train
+habfqfrmjz 1 300 train
+habhcfsjme 0 300 train
+habiwpyvhu 0 300 train
+habmnrhapf 1 300 train
+habrnpkdbr 1 300 train
+habvynwsvv 1 300 train
+habwdcfhyp 0 300 train
+habybzgzxe 1 300 train
+hacbengagg 1 301 train
+hacbovovtk 1 241 train
+hackaumfil 1 300 train
+hacljvzijs 1 300 train
+hacmylbdrz 1 300 train
+hacqoekmkh 1 301 val
+hacvvrprry 1 301 train
+hacwzuqisj 1 300 train
+hacyuvstiu 1 300 train
+hadghhszzt 1 300 train
+hadngdumar 1 300 val
+hadssbtpsu 1 300 train
+haefkdmngn 1 302 val
+haeppdsnmr 1 300 val
+haesrhzukc 1 300 train
+haewukajaa 1 300 train
+haexnflzek 1 300 train
+hafdykqojm 1 300 train
+haffddmiyo 1 300 train
+hafobcwarm 1 300 train
+hafojkdniz 1 300 train
+hafpdtmeyl 1 300 train
+haftqapupu 0 300 train
+hafxsbsgly 1 300 train
+hafyhwakbu 1 301 train
+hafylusmeq 1 300 train
+hagcthpbpt 1 300 train
+hagdzrycyf 1 300 train
+haghkzidok 1 298 train
+hagilazhui 1 241 train
+hagjjjetdi 1 300 train
+haguzfgnlh 1 301 val
+hagwpqirru 0 300 train
+hagyozibor 1 300 train
+hahestbqoj 1 301 train
+hahfniezou 1 300 train
+hahicwynee 1 300 train
+hahqaxikvp 1 300 train
+hahscfxgom 1 300 val
+haiaqyfavh 1 300 train
+haiejrdivd 0 301 train
+haiijdlgqq 1 298 val
+haipbksquw 1 300 train
+haiqfcbqnn 1 241 train
+hajgwuytzh 0 296 val
+hajkizpxpz 1 300 train
+hajmqkklsy 1 300 train
+hajqanaaga 1 301 train
+hajxecjbuv 1 300 train
+hajxqevxmn 0 300 train
+hajyzvmisg 0 300 train
+hakfzgbjpc 0 300 train
+hakgdmsskq 0 300 train
+hakjqehtys 1 249 train
+haknpmhigp 0 300 train
+hakpntaqiz 1 300 train
+hakqvgwstx 1 167 train
+hakymuoufx 1 288 train
+hakypmoszz 1 300 train
+halfgqdacz 1 300 train
+halighnerc 1 300 train
+halqwjayrq 1 300 train
+halurquqxa 1 300 train
+halvwiltfs 1 300 test
+halzpcdduw 1 300 train
+hametyyejx 1 300 train
+hamgcygfht 1 300 train
+hamhvdntaj 1 300 train
+hamngtsokt 1 300 val
+hamouznkvj 1 147 train
+hampmwjvaj 0 300 train
+hamrpvfacp 1 299 train
+hamspgttwp 1 300 train
+hamtalbegf 1 300 train
+hamvkvohgz 1 300 train
+hancwqusah 1 300 val
+hanhtorgbm 0 300 train
+haniartizy 1 300 val
+hanjhjrvjv 0 300 val
+hannqgvztl 0 300 val
+hantvgwnkv 1 300 val
+hanwcqhltp 1 300 val
+hanxfngtel 1 301 train
+haoadbkzvu 0 300 val
+haodfvlrnx 1 300 val
+haofroidxy 1 300 train
+haohmaekck 1 300 val
+haonmijjij 1 301 train
+haoogauyzr 1 300 train
+haovxavffj 1 301 train
+haowhariso 1 300 train
+haoyozsejp 1 300 train
+hapbnzkyau 1 300 train
+hapjmshqxw 1 300 train
+hapmctqqgt 1 300 train
+haqaytczcr 1 300 train
+haqeduqxqn 1 300 train
+haqfqjdcup 1 300 val
+haqfqkkehf 1 300 train
+haqhhmprto 0 300 train
+hardcvxzxu 1 300 train
+harqidprqa 1 300 train
+haryjhgpnd 1 300 train
+hasaagrlkg 1 300 train
+hasaeibrjl 1 300 train
+hasdjygtqz 1 240 val
+hasjjkoygr 1 300 test
+haskpmxggv 1 300 train
+haslpfcwqj 1 300 train
+hasnlpwbbs 1 300 train
+haspvmtfkl 1 300 train
+hasuplglfm 1 300 train
+hasyzyhtnw 0 300 train
+haszgwfsna 0 300 train
+hatcgszybe 1 300 train
+hatesldbvu 1 300 train
+hatgzjzzbs 1 300 train
+hatztthpbh 1 300 train
+hauadbuadc 1 302 val
+hauatxqcid 1 300 train
+haugisnjmf 1 300 val
+haukphfysc 0 300 val
+hauswuhngn 1 300 train
+hauymbirfa 1 300 train
+havbyqsvyj 1 300 train
+havkhxvxfw 1 300 train
+havlqxqnno 0 300 train
+havozkvldh 1 300 val
+hawfsumehu 1 300 train
+hawgoyppoc 1 300 train
+hawifsawjr 1 300 val
+hawmuailyl 1 300 train
+hawpexvrwr 1 300 train
+hawpzjlxju 1 300 train
+hawrbvowsv 1 300 train
+hawtpqabpl 1 300 train
+hawwatyexw 1 300 train
+haxnhfvqvs 1 300 test
+haxyslfudu 1 300 train
+hayezxgmxk 1 300 train
+haygjemvdw 1 300 train
+haygvkpruq 1 300 train
+hayjbgpama 1 300 train
+haylwukukd 1 301 train
+haynxbbpwq 1 300 train
+hayorjmjob 1 300 train
+haytdcoenz 1 300 train
+hazbvrlncf 1 300 train
+hazcvdjzyf 0 302 val
+hazesofgff 1 300 train
+hazhbmmcla 1 300 train
+hazjdfjyjk 1 300 train
+hazsgohnbv 1 300 train
+hazsnizlii 0 300 train
+hazzrwdokn 1 301 train
+hbadgjnkgu 1 300 val
+hbaejewdii 1 299 test
+hbaimlsevz 1 300 train
+hbajmhveui 1 298 train
+hbaqpukzah 1 300 val
+hbaqzvhluo 1 300 val
+hbarvxzmkk 0 298 val
+hbasabynwp 1 300 train
+hbaxiwzjnh 1 300 train
+hbbfwphnnr 0 300 train
+hbbnbemsln 0 300 train
+hbbqldnatj 1 300 train
+hbbtpvqvrf 1 300 val
+hbcasaspdr 0 300 val
+hbcbtqmbuf 1 300 train
+hbcefyimzz 1 99 train
+hbcmorypjy 1 300 train
+hbcuusrvqf 1 300 train
+hbcwfxlgya 1 300 train
+hbcwivrppi 1 300 train
+hbcybumjli 1 300 train
+hbdefybmtv 1 300 train
+hbdemoelnk 1 300 train
+hbdhvxcuye 1 300 train
+hbdkqzyutc 1 300 train
+hbdoyfcesz 1 300 val
+hbdvioqhoj 1 297 val
+hbdvyzpqny 1 300 train
+hbdwumljsj 1 300 train
+hbebkyeksu 1 300 train
+hbegynotjs 1 300 val
+hbemtpvlsj 1 300 train
+hbesbzgajw 1 300 train
+hbewmwqrgt 1 297 train
+hbeywtnfgq 1 300 val
+hbezwxsuqk 1 300 val
+hbfabhtqsd 1 299 val
+hbfartiyik 1 300 train
+hbfmoimzkb 1 300 train
+hbfojotjge 1 298 train
+hbgbxnhwum 1 301 train
+hbgdnkkbvi 0 300 train
+hbgecswxpg 1 302 train
+hbghwfwpot 1 300 train
+hbgjemecrs 1 300 train
+hbgkrlnsmt 1 300 train
+hbgmgdlkdd 1 300 val
+hbgmydgbyh 0 240 train
+hbgpipxncf 1 300 train
+hbhbmwoamq 1 300 train
+hbhnsldfzo 1 299 test
+hbhvilmwhk 1 300 train
+hbhxlxtxca 1 300 train
+hbhzbihfpp 1 300 train
+hbieaiwrdm 1 300 train
+hbiexmdpcm 1 300 train
+hbikqfcnyg 1 300 train
+hbiumvwkcy 1 300 train
+hbiuohewjf 1 301 train
+hbjihpazwq 1 298 val
+hbjiozieej 0 300 train
+hbjlscnzjt 1 299 train
+hbjsvkuhlh 1 300 train
+hbjsvnfxfi 1 300 train
+hbjurkhwac 1 300 train
+hbjzuexpwy 1 300 train
+hbkdbcivno 1 300 train
+hbkkbnjewp 1 298 train
+hbkrshiixl 1 297 train
+hbkutvzpna 1 300 train
+hblkonvlyq 1 300 val
+hblkrcljsv 1 300 train
+hbllwtwewh 1 300 train
+hblqwhprwy 0 300 train
+hblrxxtzvr 1 300 train
+hblrzbblln 1 240 train
+hblxigrvhs 1 300 train
+hbmumtptii 1 300 test
+hbmvxgonmq 0 300 train
+hbnfbppnym 0 300 val
+hbnnovfcln 1 300 train
+hbnpxohbzc 1 300 train
+hbnwrzcfiy 1 299 test
+hboblcqivb 0 300 train
+hbocezyrug 1 300 val
+hbocidcxhm 0 300 train
+hbodgbvcbl 1 300 train
+hbojegbwll 1 300 val
+hbokvgcceo 0 300 train
+hbomggunmo 1 300 val
+hbonbijddw 1 300 train
+hbonmpugwk 1 300 train
+hbosgmreeb 1 300 train
+hbotpzjkuc 0 300 val
+hbouaoczxa 1 300 val
+hbouszlqcx 1 300 train
+hbouvodtjy 0 300 train
+hbowjxnmbi 1 300 train
+hbozjjcafn 1 300 train
+hbpaovdthn 1 300 train
+hbpnvvuloc 1 300 test
+hbpqcltvra 1 300 train
+hbpqrgayhg 1 300 val
+hbpuinlogb 1 300 train
+hbqewgmkjj 1 300 train
+hbqezcluve 0 300 train
+hbqhyjamvh 1 300 train
+hbqkyibaeg 0 300 train
+hbqncanmxj 1 300 train
+hbqrffvwjf 1 300 train
+hbrbghphfj 1 300 train
+hbrbtikhcr 0 300 train
+hbrfvlbtqy 1 300 train
+hbrgosouxx 1 300 train
+hbrgvmrtnn 0 300 train
+hbrgwpfyhj 1 300 train
+hbrkehqfqm 1 300 train
+hbrlzaayso 1 300 train
+hbrsqxprmc 1 300 train
+hbrxbtyhhh 1 255 train
+hbrxrguoxc 1 300 train
+hbrydefnkh 1 300 train
+hbsayxqlve 1 300 train
+hbsebsehoh 1 300 train
+hbsethzlwg 1 300 train
+hbshbjypem 1 300 val
+hbsqbqzxbg 1 301 val
+hbsshshruy 1 300 train
+hbsuttldcd 1 136 train
+hbtcuqhwyy 1 300 test
+hbtcxdfwus 0 300 train
+hbtiyusigb 1 300 train
+hbtjfidysw 1 300 train
+hbtmtojhdn 1 300 train
+hbtqtfedky 0 302 train
+hbtudwefdr 1 300 train
+hbuaewloov 1 300 train
+hbufmvbium 0 299 test
+hbuhgubbss 1 300 train
+hbupszodkb 0 300 train
+hbuvmgbgzz 1 300 train
+hbveyaictx 0 300 train
+hbvifikdnj 1 300 train
+hbvjzqiqzz 0 300 train
+hbvojjwcvy 1 300 train
+hbvrjxapdv 1 300 train
+hbvtmivszk 1 300 train
+hbvvaxorwq 1 300 train
+hbvzvvykvz 1 301 train
+hbwbgobxow 1 300 train
+hbwgebdwgy 0 301 val
+hbwlpylywv 1 300 train
+hbwqgvwgic 1 300 train
+hbwtshzufg 1 300 train
+hbxcjlmqbk 1 300 train
+hbxeabadwd 1 300 train
+hbxjzfiell 1 300 val
+hbxmgcyaqi 1 300 train
+hbxqkxulgp 1 299 test
+hbxqzasgok 0 300 train
+hbxrcbxxvi 1 301 train
+hbyaseauom 0 300 train
+hbyeewaaxa 1 297 train
+hbyfedtgnt 0 300 train
+hbygbuvpft 1 300 train
+hbyikfsffc 0 300 train
+hbymerzqjq 1 300 train
+hbyxzwnifl 1 300 val
+hbzehecsma 1 300 train
+hbzgjlccot 1 302 train
+hbzrqtrzap 1 288 train
+hcagwjvlwr 1 300 val
+hcahfnrzao 1 300 train
+hcanfkwivl 1 300 test
+hcaqzhouzh 1 300 train
+hcavnzdmag 1 300 train
+hcawzoysam 1 300 train
+hcbatjbcey 1 240 train
+hcbetseuar 1 300 train
+hcbezutlsl 1 300 train
+hcbktkbpzb 1 300 train
+hcbubsilqz 1 301 train
+hcbvqqozcj 1 300 train
+hcbzssleke 1 300 train
+hcccsffmhf 1 299 train
+hccggmndqd 1 300 train
+hccjwyfptj 1 301 train
+hccoyhfnsf 1 242 train
+hccujersgb 1 242 train
+hccurssbpg 1 300 train
+hccviksznb 1 300 train
+hccvzjiemg 1 300 train
+hcdgpbztdu 1 300 train
+hcdrcpsffi 1 300 train
+hcdyegkqzt 1 301 train
+hceatcueei 1 300 train
+hcehbgfyvq 1 300 train
+hceplvorif 1 300 train
+hceqiwibjn 1 299 train
+hcexgcrkcr 1 300 train
+hceywoylku 1 300 train
+hcfawwyjqs 1 300 val
+hcfdtnccwj 1 300 val
+hcfftuhdqp 1 300 train
+hcfgcvkyks 1 300 train
+hcfslhcexi 1 300 val
+hcftvdovys 1 300 train
+hcftxmcucc 1 300 train
+hcfxbqzctv 1 300 val
+hcfyfqwnth 1 300 val
+hcfytnfcbe 1 301 train
+hcfzlwolqr 1 300 val
+hcgcvhxani 1 300 train
+hcgjlbnvpr 0 300 val
+hcgkxcaytp 1 147 train
+hcgnyhyizb 1 300 val
+hcgugahpaj 1 300 train
+hcgutowhpm 0 300 val
+hcgxrugwko 1 300 train
+hcgzrgtuno 1 109 train
+hchiymmdqm 0 300 train
+hchkegdttm 1 288 train
+hchktsapup 1 300 train
+hchmmchvlb 1 300 train
+hchpwjgudx 0 300 train
+hchuzarchg 0 300 val
+hcicddwmeq 1 300 train
+hcicdpjhip 1 300 train
+hcidadpnmp 1 300 val
+hcifzdoayp 1 301 train
+hciickghzu 1 300 train
+hciiufvnai 1 300 train
+hcijkjqnpr 1 288 train
+hcipwlvena 1 300 val
+hciqagkhwb 1 300 val
+hciqrddhaj 0 300 val
+hcirwncxmn 1 300 train
+hcisqnohby 1 300 train
+hcitbutbap 1 300 val
+hcitzdxjsy 0 300 train
+hciujjwwnw 1 300 train
+hcivgterfv 1 298 val
+hciwewlauj 0 300 train
+hcjavzyeaz 1 300 val
+hcjcnfrfsu 0 300 train
+hcjgkouldx 1 300 val
+hcjjlfgxpt 0 301 train
+hcjkrcvvnd 1 300 train
+hcjtwiqfzu 1 300 train
+hckcqdqodd 0 300 train
+hcknrtiscw 1 300 val
+hckorjqpvy 1 301 val
+hcldywnfpq 1 300 train
+hclibzbbyy 1 301 val
+hclsparpth 1 300 test
+hclxvewcys 1 300 train
+hcmecceshb 0 300 val
+hcmfxucsvn 1 300 val
+hcmilthzzq 1 299 train
+hcmjjhoxug 1 300 train
+hcmjofkwlu 1 300 train
+hcmkqafvnz 1 300 val
+hcmvukgybv 1 300 train
+hcmyribizm 1 299 train
+hcmyrtdkgr 1 300 val
+hcnbxepois 0 300 train
+hcncztsnxg 1 300 train
+hcnkuzygbp 1 300 train
+hcnmwecybu 1 298 train
+hcnqndljfc 1 300 val
+hcnunlgtsr 1 300 val
+hcnvjrbwyb 0 300 train
+hcnwzwrare 1 300 train
+hcnyexqclz 1 300 train
+hcnywpnupa 1 301 train
+hcocbvbpxp 0 300 train
+hcoluipcdj 1 300 train
+hconjfouel 1 300 val
+hcppplfpbo 1 300 val
+hcpqrjgaqt 1 300 train
+hcprdjhcel 1 300 train
+hcpvybqaea 1 300 train
+hcpxaobnjr 0 300 val
+hcpzvrriwh 1 167 train
+hcqdwzkasd 1 300 train
+hcqilphicl 1 300 train
+hcqoxjwhws 1 300 train
+hcqpikgnil 1 300 val
+hcqxrwzgxt 1 300 test
+hcqyszppuv 1 300 train
+hcrbjaityh 1 300 train
+hcrcldyvak 0 300 train
+hcrearmdur 1 300 train
+hcrhxbweul 1 300 val
+hcrofqqxkj 1 300 val
+hcrqgttdrc 1 299 test
+hcrqxnvfyt 1 300 train
+hcrsxhxvdo 0 249 train
+hcsescdotm 1 300 train
+hcsfisyeit 1 300 val
+hcsfkirlgq 1 300 train
+hcspsjaudj 1 300 train
+hcsrezaldx 0 300 train
+hcswybumab 0 300 train
+hcsynxlfev 1 300 train
+hcszriejpd 0 300 val
+hctattwbik 1 300 train
+hctcyjfssz 1 300 train
+hctekvdfll 1 147 train
+hctzqiwncj 1 300 train
+hcujjpgxaa 1 300 val
+hculgfktdg 1 300 train
+hcutlqoddc 1 300 train
+hcutshgtvx 1 99 train
+hcuvbcrgmo 1 297 train
+hcuvwubcnx 1 300 val
+hcuyafxyrq 1 99 train
+hcuzcmywxv 1 300 train
+hcvdpnhqsa 1 300 train
+hcvejcngud 1 300 val
+hcvgqdkqbf 1 300 train
+hcvmxhfmzu 1 300 train
+hcvwpivvvq 1 300 train
+hcvyqdptrg 1 300 train
+hcwbxzkkwm 1 300 train
+hcwdezcsdm 1 300 val
+hcwghmdequ 0 300 train
+hcwhwpwcrv 1 300 train
+hcwiusyvox 1 300 train
+hcwjcpotfa 1 300 train
+hcwlqsoonr 1 300 train
+hcwvygnspm 1 300 train
+hcwzguzfem 0 300 train
+hcxcomepos 1 300 train
+hcxdmfwsus 1 300 val
+hcxeunezjk 1 300 val
+hcxhtxqzio 1 300 train
+hcxthekeyt 1 300 val
+hcxvlezrox 1 300 val
+hcxwnmoncd 1 300 train
+hcxyoaxfin 1 300 train
+hcxzxuvedy 1 300 train
+hcyeodttbp 1 300 train
+hcyhcyfnzo 1 300 train
+hcyjgawxnt 1 300 val
+hcyprruzpu 1 300 train
+hcyqdktfiv 1 301 val
+hcyyjbngyp 1 300 train
+hcyzbzdwtd 1 300 train
+hczetyrtga 1 300 train
+hczfyxtxnw 1 300 train
+hcziircupz 1 300 train
+hczlutekvc 1 301 train
+hcznycmxsa 1 300 train
+hczoakrfld 1 300 train
+hdafjidtpa 1 300 train
+hdafnsbdrm 1 300 val
+hdagvnsdsp 0 300 train
+hdaleijded 0 300 train
+hdapddfvgg 1 298 train
+hdatsxiyhg 1 300 val
+hdauuytvhx 0 300 train
+hdavvtqjrp 1 300 train
+hdbbppsmhp 1 300 train
+hdbbqxydca 1 240 train
+hdbejalgtx 0 239 train
+hdbeqxzrbb 1 300 train
+hdbfsqjlos 1 300 train
+hdbrtnarsy 1 300 train
+hdbtjetuql 1 236 train
+hdcdmjhoca 1 300 train
+hdcjnvgazz 1 300 train
+hdckmfvpof 0 241 train
+hdckzcdbxi 0 300 val
+hdclgrggjs 1 300 val
+hdcljwvnts 1 300 train
+hdctzklouz 1 301 train
+hdcuuefuzh 1 300 train
+hdcvgcubmd 1 300 train
+hdcxhrlafa 1 300 train
+hdddfrvqws 1 300 train
+hddgrmdzta 0 300 train
+hddmcdudyt 1 301 val
+hddminxrhw 0 300 train
+hddmqsggjz 1 300 val
+hddnnhtjuu 1 300 train
+hddoaufndn 0 300 train
+hddogudevl 1 301 train
+hddohuycnv 1 300 train
+hddsgyvbem 1 301 train
+hddvofqapm 0 300 train
+hddvrtxffc 1 300 train
+hdeeloejda 0 300 train
+hdejlbwnnn 1 300 val
+hdekiddmbr 1 300 train
+hdelaheqtt 1 300 train
+hdeubzuwrt 1 300 train
+hdewinvrfs 1 300 train
+hdfdvkeiyt 1 300 val
+hdffrdocqk 1 300 val
+hdfheqvqwf 1 300 val
+hdfhmlsrzn 0 300 train
+hdfogbjqxm 0 300 train
+hdfqqxyiab 1 300 train
+hdfrdajxrx 1 300 train
+hdfspxlxfs 0 300 val
+hdfutmzzey 1 300 val
+hdgffsmrtd 1 300 val
+hdgfgvcoqk 1 300 val
+hdgwynwsyh 1 300 train
+hdgxltgqpn 1 300 train
+hdhelrqzci 1 300 train
+hdhjxqwagu 1 300 train
+hdhktpnxtk 1 300 train
+hdhnhfedou 1 299 train
+hdhntzlsdw 0 300 train
+hdhosyjdqa 1 300 train
+hdhtgaybjy 1 300 train
+hdhulzbggh 1 300 train
+hdhuqvdfij 1 300 train
+hdhurbyciy 0 300 train
+hdhzgvwlxl 1 300 train
+hdidvxfppi 1 300 train
+hdidxyrtrc 1 300 val
+hdihqnshlv 1 300 train
+hdikatntvf 1 300 train
+hdjbbigtmb 1 300 val
+hdjcgcfjzo 1 300 train
+hdjdmhrcle 1 300 train
+hdjnyrgvrk 1 300 train
+hdjscdwotm 1 300 train
+hdjtzbdmww 1 300 train
+hdjvowbkbe 0 300 train
+hdjvuuxpxx 1 300 train
+hdkikzynek 1 300 train
+hdknqpbxiw 1 301 train
+hdksxgszke 1 300 train
+hdkwxvnwbp 0 300 train
+hdlbxynbfx 1 300 val
+hdlcufarcs 1 300 train
+hdldtpqqrt 1 300 val
+hdlewnlnud 1 300 train
+hdlpnaruhz 1 300 val
+hdlpvdfpte 1 300 val
+hdmbygaois 1 300 val
+hdmcjrfdtf 1 300 train
+hdmcmgszjt 1 300 train
+hdmfqqovdq 1 300 train
+hdmhhcixqb 1 300 test
+hdmqltaiuh 1 300 val
+hdmrtvpplw 1 300 train
+hdmsorkzxc 0 300 train
+hdncsvzjjk 1 300 val
+hdnlkddxfh 1 300 train
+hdnszxqazb 1 300 train
+hdnvrfulgc 1 300 val
+hdnxtcjnps 1 300 val
+hdoemwbabf 1 300 train
+hdoggxlynf 1 241 train
+hdonvukllz 1 300 train
+hdoyjaobhg 0 301 train
+hdoyopjuki 1 300 train
+hdpcjxkzbh 1 300 val
+hdpdbzczpy 1 300 train
+hdpfwcfigq 1 300 val
+hdpkdyuvok 1 302 val
+hdplrrdvqu 0 300 train
+hdppxwxqoa 0 300 train
+hdqbwxlacj 1 300 val
+hdqcxgrpqu 1 241 train
+hdqkhgdjph 1 300 val
+hdquimbepn 0 300 train
+hdrcfbhylq 1 300 train
+hdrhwqbytu 0 299 train
+hdrowikbif 1 300 train
+hdryxquzff 1 298 train
+hdrzvxuttp 1 300 val
+hdsayhknek 1 300 train
+hdsbvyxutk 0 300 val
+hdslivusdj 1 300 val
+hdsmxpwkyq 1 299 test
+hdspbihgjg 1 300 train
+hdspwamgxh 1 300 train
+hdtciyztlf 1 302 train
+hdtqiagzqb 1 300 val
+hdtrzbdmqq 1 300 train
+hdtslvvftc 0 300 train
+hdtsuizcti 1 300 train
+hdtszhudws 0 300 val
+hdtwkrbvyu 1 300 train
+hdtydsrgaa 1 300 train
+hduhgvczlj 1 300 train
+hdunuumyxa 0 300 val
+hduwcwwkcf 1 298 train
+hdvazdbvbo 0 300 val
+hdvpqmklwf 1 300 train
+hdvptdxmgm 1 300 train
+hdvrxlrnyk 1 300 train
+hdvtfmhvye 1 300 train
+hdvtxocbhv 1 300 train
+hdwfocdqns 1 298 train
+hdwmdpucdl 0 300 train
+hdwmxmdqot 0 300 train
+hdwoycdamb 1 298 train
+hdwtamqvky 1 300 train
+hdxfvvlpet 1 300 train
+hdxmzyltpy 1 300 train
+hdxnmpknle 0 300 train
+hdxooxkisr 1 300 train
+hdxsaishbv 1 300 train
+hdxzneektz 1 300 train
+hdyoiejnwl 0 300 train
+hdyootaira 0 300 train
+hdypzazeks 1 300 train
+hdysfhsyox 1 300 train
+hdytjaiglk 1 300 test
+hdyvindkjk 1 300 train
+hdzckzbjcm 1 300 train
+hdzeqfjbmz 1 300 train
+hdzmnswthw 1 300 val
+hdzmqtxbyt 1 300 train
+hdzqldgerz 1 300 train
+hdzsyotwqn 1 298 train
+hdzvtqbpqs 1 300 train
+hdzygqltzu 1 300 train
+heacpjqtmu 0 300 val
+heaieeghsv 0 300 train
+heaiiveqxh 1 301 train
+healmdjdqb 1 300 val
+heaouuhopi 1 300 train
+heapwnqjpm 1 300 train
+heaqqlytsc 0 300 val
+heasusflsk 1 300 train
+heautdpxxo 1 300 val
+heaxbmchys 1 300 train
+hebctgmncr 1 300 train
+hebddxiwci 1 300 train
+hebovtdlph 1 300 train
+hebrlxvfeo 1 300 train
+hebupquivx 1 300 train
+hebyxnalwy 1 300 train
+heccnjugpk 1 300 train
+hecerpfjsy 1 300 train
+hecfssiezj 1 298 train
+hecglkrexr 1 300 train
+hechdrfgkj 0 300 train
+hechzxqtfo 1 300 train
+heciplciap 1 300 train
+hecofwjiux 1 300 train
+hectzcuzdv 1 300 test
+hecutpzkqq 1 147 train
+hecxeqclmd 1 302 val
+hecxxkaprp 0 300 train
+hedeftegwd 1 300 train
+hedetzyqpu 0 300 train
+hedgftlcsk 1 300 train
+hedjpbgyga 0 300 train
+hednhtslzy 1 300 train
+hedvoqehaw 1 301 train
+heebdhemin 1 300 val
+heebllzbis 1 292 train
+heefaguqig 1 300 train
+heefgehjrr 1 300 train
+heeijdolfh 1 300 train
+heejybmjai 1 301 val
+heeocelknr 1 298 val
+heesnutqtm 1 301 train
+heexadftse 0 300 train
+hefiqrcmen 1 300 train
+hefiremjyf 0 300 train
+hefisnapds 1 300 test
+hefixtvspc 1 300 train
+hefsqjlddk 0 300 train
+hegbcqtazt 0 300 val
+hegffcpclm 1 300 train
+heghvxkyuk 1 299 train
+hegomtnjrv 1 299 val
+hegrwugnct 1 300 train
+hegttdfqre 1 300 train
+hegucmrlfl 1 300 train
+hegzxuozed 1 241 train
+hehagntoqy 1 240 val
+hehongqcto 0 300 train
+hehuookjud 1 300 train
+hehvrrzobq 1 300 train
+hehyfgefhh 0 300 val
+heigpmxyvw 1 300 val
+heilsevfcc 0 300 val
+heiqasolyw 1 300 train
+heitflxfhr 1 300 val
+heiurmawgr 0 300 train
+heiuytczzb 1 300 train
+heiviflgdb 1 300 train
+heiyoojifp 0 300 test
+hejfyockqf 1 300 train
+hejkmqgnng 0 300 val
+hejmoxglbw 0 300 train
+hejrazflbv 1 298 train
+hejrrynxfk 1 300 train
+hejudaxgji 1 301 val
+hejxoqaotk 0 300 train
+hekeqdfuyw 1 300 train
+hekhubztvd 1 300 val
+hekwkvdvyq 1 300 train
+helaqdgadz 1 300 train
+heldbzescf 0 300 train
+helfijkvvi 1 300 train
+helijvwmfx 1 300 train
+hellvacoev 1 300 val
+heltevgekc 1 300 val
+helumjtmik 0 300 train
+helwkdpqaf 1 301 train
+helywhtbcs 0 300 train
+hemfmurxhi 1 300 val
+hemhefvkum 1 300 train
+hemhhjgnld 1 300 train
+hendtstcai 1 296 val
+henggajptu 1 300 val
+hennoccnfl 1 300 train
+henpwcjutg 1 300 train
+hensjerwnl 0 300 train
+heoufzaddn 0 300 val
+heoxpyffcw 1 300 val
+hephnbihfc 0 300 train
+hepjjlvper 0 300 val
+heppupfnws 1 300 val
+heprffercd 0 300 train
+hepvgksmbb 1 300 train
+hepwwhzjhb 1 300 train
+hercreciym 1 300 train
+herfsxfrgo 1 300 train
+hermxlfqqk 1 300 train
+hernaepzvf 1 300 train
+herpauxedu 1 300 train
+herufumizv 0 299 val
+hervmuonhn 1 300 train
+herwmvoobn 1 300 train
+herzzxcsxk 1 300 val
+hescdbqwnk 1 300 train
+hescfkmoxe 1 298 train
+heshbcgrqc 1 301 val
+heslyipegn 0 300 val
+hesqgxgjch 0 300 val
+hesrlgwvbu 1 301 train
+hesruaznni 1 100 train
+hestjtubtl 1 300 val
+hesuqfhiku 1 300 train
+hesywytmbd 1 300 train
+heszotticv 1 300 val
+hetclsgiwz 1 300 val
+hetcpovklp 1 300 train
+hetjuegtsl 1 300 train
+hetlhhxtlb 1 300 train
+hetxvghqhn 1 300 train
+heucqmxtdd 1 300 val
+heugpdolzi 1 300 train
+heuhfeqqws 1 300 train
+heunroklfh 1 300 val
+heunzildxt 1 300 train
+heurdiogcw 1 300 train
+heuucpaygz 1 300 val
+hevajonyvj 1 300 train
+hevcclcklc 0 300 test
+hevgjlambb 1 300 val
+hevkhkdleb 1 300 train
+hevmzzyfep 1 300 train
+hevnqqfelb 1 300 train
+hevoctdzwj 1 300 train
+hevrtabipp 1 300 train
+hevvqisebr 1 300 train
+hewakydaia 1 300 train
+hewcwxclsp 0 300 train
+hewezvtiud 1 300 train
+hewhitnasz 1 300 train
+hewhnzjqbd 1 298 train
+hewlieyzlv 1 300 val
+hewyozvcjs 1 300 train
+hexprqhila 1 300 val
+hexxuigzdl 1 300 train
+hexyjykhvk 0 300 val
+heyeimsmbc 1 300 val
+heyhatzzxk 1 300 val
+heyixtkolz 0 300 train
+heymqwtnns 1 295 train
+heymtqsonn 1 300 train
+heyuhmcyfe 1 300 val
+heyumuvdyv 1 300 train
+heyzjzitot 1 300 train
+hezbrjjjba 1 299 val
+hezlwdnkue 1 300 train
+hezmcecine 1 300 train
+hezqkhggsd 1 299 test
+hezvknnrgk 1 300 train
+hezwtipaij 1 300 val
+hfabdideab 1 298 train
+hfaeavzzqc 1 301 val
+hfafmazgcg 1 300 train
+hfahxntsvj 1 300 train
+hfbcczwgiu 1 300 train
+hfbcxofuag 0 300 val
+hfbdofelkr 1 300 train
+hfbhapgfuy 1 301 val
+hfbhfeevlg 1 300 train
+hfbiuujvqg 1 300 train
+hfblnovkno 0 300 train
+hfbonjhrcj 0 301 train
+hfbpsswwll 0 300 train
+hfbqxpfhqu 1 300 train
+hfbylajzuq 1 300 train
+hfcahbxojg 1 298 train
+hfcbsslplq 1 300 train
+hfcedpllzw 1 300 train
+hfcezskxnq 1 300 train
+hfckgibxms 1 301 train
+hfckgxxhle 1 300 train
+hfcojjgcdl 1 300 train
+hfcotpbszq 1 300 train
+hfcqhwdbcc 0 301 train
+hfcvllmsvl 1 300 train
+hfcxlucrbj 0 300 train
+hfcywlzvwc 1 300 train
+hfdbgfzuiu 0 300 train
+hfddlncpdz 1 300 train
+hfdhsfizrd 1 300 train
+hfdkskwrwk 1 300 val
+hfdlriqcir 1 300 train
+hfdpapyngn 1 300 train
+hfdpfdymne 1 301 train
+hfdqlrmahm 1 300 train
+hfdzpxkkve 1 299 train
+hfeacozznh 1 300 test
+hfedtplyys 1 299 test
+hfeqmmhfgn 1 300 train
+hferbtucpb 1 297 train
+hferdapvuh 1 300 val
+hffemnxolq 1 300 val
+hffexausji 1 300 train
+hffircryfk 1 300 train
+hffkrqxlyv 1 300 train
+hfflsxqsqi 1 300 val
+hffnagxquq 1 300 train
+hffpiwqxns 1 300 train
+hffpurrqwv 1 300 train
+hffqkokckx 0 237 train
+hffraywwao 1 240 train
+hffrrckuui 1 300 train
+hffsgjyaxy 1 300 val
+hfftaiguiv 1 300 train
+hffztvbkox 1 301 train
+hfgbcfgqbm 1 300 train
+hfgcpeoeyp 1 300 train
+hfgczdzbix 0 300 train
+hfglpfwooo 1 300 train
+hfhbnfpumi 1 300 train
+hfhgtkuaxr 1 298 train
+hfhgysacyf 0 300 val
+hfhhuycfum 1 300 train
+hfhpcrajfb 1 300 train
+hfhuzaukrl 1 300 train
+hfhvimgnkc 1 300 val
+hfhzijlgyu 1 241 train
+hfidatzhik 1 300 val
+hfietcbhko 1 298 train
+hfiizhatus 0 299 val
+hfikkcfxbp 1 300 train
+hfimvbpmhp 1 300 train
+hfiobuccsm 1 300 train
+hfirqzsicr 1 300 train
+hfiruntglp 1 300 val
+hfisbdelui 1 300 val
+hfiuhfcgkx 1 300 train
+hfiyocolqc 1 300 train
+hfizjciwwe 1 300 train
+hfiznnueou 1 300 train
+hfjcusxmqr 0 300 val
+hfjczthrqm 1 301 train
+hfjetiudor 1 300 val
+hfjkowddbc 1 300 val
+hfjnotbatc 1 300 train
+hfjoxmvhmu 1 136 train
+hfjqqibivh 1 300 train
+hfkarniexj 1 300 val
+hfkdhayuie 1 241 train
+hfkjmucqvy 1 300 train
+hfkllixxkr 0 300 train
+hfknnzyqzh 1 300 train
+hfknsdqrht 1 300 val
+hfknxfrupb 1 300 train
+hfkrrficft 0 300 train
+hfkssjwgsy 1 300 train
+hfkstolikf 1 300 train
+hfkwogkzid 1 239 val
+hflevhjyro 1 300 val
+hflfcwvmtb 1 300 train
+hflgjyfyus 1 300 train
+hflgowqwtt 1 300 train
+hflhhnqajt 1 300 test
+hflnotbagi 1 300 train
+hfltwgkohs 1 300 train
+hflzbzsfjq 1 300 val
+hflzcvraei 1 300 train
+hfmgqguilx 1 300 test
+hfmhfqcqfb 1 300 train
+hfmicjxnyl 1 300 train
+hfmkgwhsqo 1 300 train
+hfmwxyjott 1 300 train
+hfmycbfmln 1 300 train
+hfmzgwlroe 1 300 train
+hfncmvdoli 1 255 train
+hfncqnulgt 1 297 train
+hfnlmhbyqt 1 301 val
+hfnorozmmr 1 300 train
+hfnptlkzlk 0 300 train
+hfnrljsphk 1 300 val
+hfnrzvkjfq 0 300 val
+hfnsqlqkcx 1 300 val
+hfnvhvpjlu 1 240 val
+hfocfhpdtw 1 300 train
+hfoewuxnhu 1 300 train
+hfoioyeobe 0 300 val
+hfoleykkho 0 300 train
+hfolszbhzm 1 300 train
+hforhrolvu 1 298 train
+hfotuauhls 1 300 train
+hfovmuenhe 0 300 train
+hfpakcvudu 0 300 train
+hfpcityjtq 1 300 train
+hfpxpwhdkn 1 301 train
+hfqekodths 1 300 val
+hfqpyvxasx 1 300 train
+hfqvgavken 1 300 train
+hfrhckvepy 0 240 train
+hfrhtjungx 1 301 train
+hfriuxfleb 1 300 train
+hfrjayeltj 1 300 val
+hfrlfyisor 1 298 val
+hfrtnrlcxd 0 300 train
+hfsadwxfxh 1 300 train
+hfsdsrwthf 1 300 val
+hfsfnobwbb 1 301 train
+hfsmvibnwo 1 300 val
+hfspenqmpw 1 300 train
+hfsrhxxnih 1 300 train
+hfsvqabzfq 1 299 test
+hfsywbcrav 0 300 train
+hftisowewt 1 300 train
+hftiwsbmaj 1 300 train
+hftjyfuqcs 1 299 val
+hftkxvybot 1 300 val
+hftninrtod 1 300 train
+hftxxlnsbp 1 300 val
+hftypnppjr 0 300 train
+hftzcfchvo 1 301 train
+hfuhmcwrhn 1 300 train
+hfurjnbjvj 1 300 train
+hfuumbpivg 1 300 train
+hfvexodpht 1 300 val
+hfvohwcvfc 0 300 train
+hfvufgteyr 1 300 train
+hfvwchizdz 0 300 val
+hfvxhtuore 0 300 train
+hfvxpofxfr 1 300 test
+hfwgxhmznd 1 301 train
+hfwpqpplrm 1 300 train
+hfwwineuwd 1 300 train
+hfwzpytvpn 0 301 train
+hfxgbbeapi 1 299 train
+hfxhgmcsvf 1 300 train
+hfxmqrzdrp 0 300 train
+hfxnnbwcve 1 300 train
+hfxvdmtsum 1 300 train
+hfxvecyvmj 1 300 train
+hfxwupsztp 0 300 train
+hfxxdsgruh 0 300 val
+hfyfhpdlcd 1 240 train
+hfygefzhwd 1 300 train
+hfytfbmaxh 1 300 train
+hfyyntijry 1 300 train
+hfyytxckgf 1 301 val
+hfyzlbfdxd 0 300 val
+hfzazxtkzc 1 300 val
+hfzbajanit 0 300 train
+hfzjosjrgl 0 300 train
+hfzjrtvrtz 1 300 train
+hfzkljkstq 0 300 train
+hfzvkjapfp 1 300 train
+hgadfwdhce 1 241 train
+hgaenyddem 1 302 train
+hgahioydam 1 300 val
+hgahuohxbq 1 301 train
+hgakqixokz 1 298 val
+hgamueohsn 1 300 train
+hgapkkpvdb 1 300 val
+hgashsetkv 1 300 val
+hgatxssojx 1 300 val
+hgbdjfkrpe 1 300 train
+hgboevycdj 1 300 train
+hgbosjbwer 1 298 train
+hgbpjatady 1 301 val
+hgbqlfyici 1 300 val
+hgbumfkmoy 1 300 train
+hgbvseybjl 1 300 train
+hgbvxogyuv 0 300 train
+hgcbwsvmxh 1 300 train
+hgcevzagah 1 298 val
+hgcjhnidtm 0 300 train
+hgcnubousl 0 300 train
+hgcqdpagpw 0 301 val
+hgcwjxxcle 1 300 val
+hgczbfguss 1 300 train
+hgdhviipip 1 301 train
+hgdjrqzwff 0 300 train
+hgdkjejnki 1 300 val
+hgdlkeugdz 1 300 train
+hgdswzlbuq 0 300 train
+hgdyqykqgk 0 300 val
+hgeakabscm 1 300 train
+hgecfatxte 0 300 train
+hgecqreqto 1 300 train
+hgedoaokjl 1 300 val
+hgeeqivyjy 1 300 train
+hgeesybdln 0 300 train
+hgefzguctw 1 300 train
+hgekgodpjs 1 300 train
+hgenhqxwyf 1 300 train
+hgenpbzqca 1 300 val
+hgeobyqjjw 1 300 train
+hgeqhrugyi 1 300 train
+hgfcupavaj 1 300 test
+hgfgxgkali 1 300 val
+hgfndnebzz 1 300 train
+hgfpjkaots 1 300 val
+hgfqaejpff 1 300 train
+hgfqmoimul 1 300 val
+hgfqxlgeuc 1 300 train
+hgfxjjgtbx 1 301 train
+hggcaivvje 1 298 train
+hggjjcihyv 1 300 train
+hggjxgcidq 1 300 train
+hggormbiyl 1 300 train
+hggrfjrrly 0 300 train
+hggrpayswy 1 300 train
+hggxfpgfju 1 297 val
+hggxjnhnst 1 300 train
+hghugynpuj 1 241 train
+hgifslzouy 1 300 train
+hgihvxrhkh 1 300 val
+hgimnvvfup 1 300 train
+hgipczryrr 1 300 train
+hgiwlepbte 0 300 train
+hgixraeaye 1 300 val
+hgjbnfsyid 1 300 train
+hgjdosshpt 1 300 test
+hgjheddlde 1 300 train
+hgjkkddwjy 1 300 train
+hgjktnnetg 1 300 train
+hgjkzsoxbj 1 300 val
+hgjswpbmmu 1 300 val
+hgjwyphxkx 1 298 train
+hgkbhaztur 0 300 train
+hgkfryxybj 1 300 train
+hgkiymguuo 1 300 train
+hgkokdqkcx 1 300 val
+hgkplddfqa 0 240 train
+hgkrvykhla 1 300 train
+hgkwddemea 1 301 train
+hgkwxprdxu 1 299 train
+hglaodpyup 1 300 val
+hgldvicfxk 0 300 train
+hglhooqzej 1 300 val
+hglklkxzxg 1 300 train
+hglmacuujk 1 300 train
+hgmckehjft 1 300 train
+hgmclqrimg 1 300 val
+hgmkpwbzwl 1 298 train
+hgmnnbtuyw 1 300 train
+hgmpsbvzkx 0 300 train
+hgndjhgrlr 1 300 train
+hgnensqrzu 1 300 val
+hgnyujjwsa 1 300 train
+hgohzfpguz 1 300 val
+hgomkdxenn 0 297 val
+hgoryqulng 1 298 train
+hgoscxtunq 1 300 train
+hgoupsqnig 1 300 train
+hgowimjmwy 1 300 train
+hgozghlrty 1 302 val
+hgpbgnofoj 1 300 train
+hgpdhtgbot 1 241 train
+hgpesbprdw 0 300 val
+hgpzvlbmga 1 300 val
+hgqcjhbdse 1 300 val
+hgqeprjgid 1 300 val
+hgqerdoyfn 1 300 val
+hgqfoasyla 1 300 train
+hgqkaddtkt 1 300 train
+hgqmjmxhiw 1 300 train
+hgqmrwnyiy 1 298 train
+hgqpzhkoua 0 300 train
+hgqqwuqrlm 0 300 val
+hgqqxcrajb 1 300 train
+hgqrrbegzn 1 300 train
+hgqteutmie 1 300 val
+hgrcwbznom 1 300 val
+hgrflzdqwx 1 300 train
+hgrmznqdzx 1 300 train
+hgrppcvjyx 1 300 train
+hgrutgamco 1 300 train
+hgrwxmexyo 1 300 train
+hgscojqwyp 1 300 train
+hgslssdkky 1 300 test
+hgsntvpycd 0 300 train
+hgsvltiixn 0 300 val
+hgtirzyckj 1 298 train
+hgtszljanw 0 300 train
+hgtvslqxzf 1 300 val
+hgtvuwhztq 1 300 train
+hgtyeogjtm 0 300 train
+hgtzfzuujo 0 300 train
+hgubfvlxta 0 300 train
+hguhdutrby 1 300 train
+hguygahizr 1 300 train
+hgvdttjcgk 1 300 train
+hgvfhqfbuz 1 300 train
+hgvhpdipcv 1 300 train
+hgviytsamb 1 300 val
+hgvlupzwxy 1 300 train
+hgvtnzfcvs 1 300 train
+hgwsskiudd 1 300 train
+hgwxucfgbe 0 300 train
+hgwycgnapl 1 300 train
+hgwzdxfynt 1 300 train
+hgxaxykble 1 300 train
+hgxhlwyqhr 1 300 train
+hgxicygqxd 1 300 train
+hgxtgjstga 0 300 train
+hgxzrnepdy 1 301 val
+hgyiqroihk 1 299 val
+hgyjtixhyn 1 300 val
+hgyovfcxxl 1 300 train
+hgyupsezoh 1 300 train
+hgyvcmpddj 0 300 train
+hgyzedfdiq 1 100 train
+hgzbuouxaa 1 300 train
+hgzdpnqzvb 1 298 val
+hgzfyettbv 1 300 test
+hgzgtxzgeg 1 300 train
+hgzihzctao 1 300 train
+hgziojxtan 1 300 train
+hgzjftrbbv 1 300 val
+hgzmovwegj 1 299 val
+hgztdvmlmk 1 300 train
+hgzwakwfuu 1 300 train
+hgzzpepxkv 1 300 train
+hhaeiaweqa 1 298 train
+hhaqwjgett 1 300 train
+hhasrtjxod 1 99 train
+hhayopshwo 1 301 train
+hhbdmwkuzk 1 300 train
+hhbgwwujib 1 301 val
+hhbpmbnalf 0 249 train
+hhbtwatokr 1 300 train
+hhbwkivspg 1 300 train
+hhbxalifov 1 300 train
+hhcapkusnr 1 300 train
+hhcbkchtyk 1 301 train
+hhcbzkonea 1 300 val
+hhcgteklqv 1 300 val
+hhckrgehwt 0 300 train
+hhcpcamiwk 1 300 train
+hhcvwyuwfv 1 300 train
+hhdblnxhtj 0 300 train
+hhddxuhorq 1 300 val
+hhdffhudyd 1 300 train
+hhdpnhrnsp 1 300 train
+hhdtuilvnd 1 241 train
+hhduhfpgdg 1 300 val
+hhdxjkkbow 1 300 train
+hhdzofpfgu 0 300 train
+hheboixbgi 1 300 val
+hhefhuwkzo 1 300 train
+hhegjycqca 1 300 val
+hhegrmxsbp 1 300 train
+hhfcshhpse 1 300 train
+hhffjlrrms 1 300 train
+hhfhnyojlh 1 300 train
+hhflpjeagw 0 300 train
+hhfodksgjq 1 300 val
+hhfplwerbg 1 300 train
+hhfspoontw 1 300 val
+hhftunckhq 1 300 train
+hhgarggtgl 1 300 train
+hhgjldiswr 1 300 train
+hhgkixhctm 1 300 train
+hhhmlzfugc 1 300 train
+hhhrbherkq 1 300 train
+hhhrdnwzdw 1 300 train
+hhhrjgexse 1 300 train
+hhhvnhhqsc 0 299 test
+hhhwdbxlej 1 300 train
+hhhwvintrc 1 301 train
+hhhzwfinsc 1 300 train
+hhickstlnn 1 299 test
+hhipsqszlg 1 300 train
+hhitzafuoo 1 300 train
+hhiznfrxun 1 301 train
+hhjavsocdd 1 300 train
+hhjfirelwd 1 300 train
+hhjnfwezhr 1 300 train
+hhjttwtfko 1 83 train
+hhkglrisef 1 300 train
+hhkhtvnkro 1 300 train
+hhkknxmlbt 1 300 train
+hhknykrtkc 1 300 train
+hhkozfijcn 1 300 val
+hhkzdvqnzf 1 300 train
+hhlgrzjdif 1 300 train
+hhlhuawhhe 1 300 train
+hhlntqrako 1 300 train
+hhlpoxvufn 1 300 train
+hhlvtppefz 1 300 train
+hhmaliilfn 1 241 train
+hhmemqpsld 1 300 train
+hhmfgcsxml 1 300 train
+hhmflhhbih 1 298 train
+hhmkgrhhsd 1 300 train
+hhmmgbgsdx 1 300 train
+hhmoxuqvqh 1 300 train
+hhmsbuyugf 1 300 train
+hhmwtkzgph 1 300 train
+hhncbukwdc 1 300 train
+hhnebfdzoy 1 301 train
+hhnfxlfhjp 1 300 train
+hhnjnfxgol 1 300 train
+hhnkpxifid 1 300 val
+hhnqmzylpd 1 300 train
+hhnsijyqzj 1 301 train
+hhoaqazixk 1 299 test
+hhoccqhaaq 1 300 train
+hhohejcksh 1 300 train
+hhoogutbxk 1 300 val
+hhoprtsazr 1 300 train
+hhozjscusk 1 300 train
+hhpadzxihg 1 300 train
+hhpdksvajj 1 300 train
+hhpeahpxxr 1 300 train
+hhpernrkrq 1 300 train
+hhphifkstv 1 300 train
+hhpivlybuf 1 300 train
+hhpjxgzncu 1 296 val
+hhpmuiybqn 1 300 val
+hhpnppeydl 1 300 train
+hhppjrafli 1 298 train
+hhpvctiryk 1 300 train
+hhpwufkffq 1 298 train
+hhpzfnaplk 1 300 train
+hhqbuxjimf 1 300 train
+hhqcircgmf 0 241 train
+hhqdbswteb 1 146 train
+hhqejeszki 0 300 train
+hhqipubnxj 1 300 train
+hhqlwyqvpn 1 300 train
+hhqpulohfs 0 300 train
+hhqtdepsyl 1 299 val
+hhrckavmqd 1 300 val
+hhrdfvgzik 1 300 train
+hhreitayaa 1 298 val
+hhrfguhlkg 1 300 train
+hhrkbnbtru 1 300 train
+hhrnaekwyc 1 300 train
+hhroycqneq 1 300 train
+hhrpdtqzxd 0 300 train
+hhrsabtkcz 1 297 train
+hhrvceqxhp 1 300 train
+hhsaujqkqo 1 300 train
+hhsnwtmpjm 1 300 train
+hhspdqobsd 1 300 train
+hhspsdqxgr 1 300 train
+hhssvhbrdw 1 300 val
+hhssxmsbog 0 300 val
+hhsyuwxrod 1 300 train
+hhtbkctsyj 1 300 train
+hhtggweimd 1 300 train
+hhtgjbgexx 1 300 val
+hhtgzqcmvk 1 298 train
+hhthsvysvu 1 301 train
+hhtjvgfqbz 1 300 train
+hhtnxlvfxd 1 300 train
+hhtvrlfich 1 300 train
+hhtxwyjqcc 1 300 train
+hhtywtqslk 1 300 train
+hhuakzfttr 0 300 train
+hhujcljzhk 1 300 train
+hhunmrbhyc 1 300 train
+hhuqodnvgi 0 300 val
+hhuwygcgzu 1 300 train
+hhvayvionx 1 301 train
+hhvcvjyrne 1 300 train
+hhvdokacxp 1 300 val
+hhvfywtomx 1 300 train
+hhviyvxoiw 1 300 train
+hhvkinanov 1 298 train
+hhvqljhxtm 1 300 val
+hhvtegwynm 1 300 train
+hhvuhtweqi 1 300 train
+hhvwphjxgk 1 300 train
+hhvxuxcwix 1 298 train
+hhwjhyntbf 1 300 train
+hhwjtdtyml 1 300 val
+hhwrbezwxr 1 300 train
+hhwwxylstd 1 300 train
+hhwyxajcrv 1 300 train
+hhxaxylkgv 1 300 test
+hhxewetqoi 1 301 train
+hhxgnzqfxb 0 300 train
+hhxhbuqlma 1 300 val
+hhxithuian 1 300 val
+hhxjvqkvkc 1 300 val
+hhxmofezyo 1 300 train
+hhxxuyjfpl 1 297 val
+hhxzqjmbyy 0 300 train
+hhxzvnfdij 0 300 val
+hhydadbbkf 1 241 train
+hhydivgbmr 1 300 train
+hhydqxywzf 1 300 train
+hhyfgoaewt 1 298 train
+hhykgtgdqo 1 300 train
+hhykrwtxxp 1 300 train
+hhynlsztug 1 300 train
+hhyroaqtts 1 300 val
+hhyuqudlfw 1 300 test
+hhyxnwbuxm 1 300 train
+hhyxweyjlt 1 300 test
+hhyykgozwv 1 300 train
+hhzazvkmrp 1 300 val
+hhzbewsckp 1 300 train
+hhzcnhwahb 0 300 train
+hhzhvvifat 1 300 train
+hhzlddfggp 1 300 train
+hhzprfzlcj 1 300 val
+hhzrcenmhf 1 301 train
+hhzxwtlaem 1 300 train
+hhzyiyibhq 1 300 train
+hiaafvgomz 1 300 train
+hiadoidirz 0 300 train
+hiafeqjgjt 1 300 train
+hiakcuwbax 1 300 train
+hialjaayty 1 301 train
+hialtjzmnx 1 300 train
+hialyxosji 1 300 train
+hiarnpazuc 1 300 train
+hiawcsrodk 0 300 train
+hiawdembtp 1 300 train
+hiawhianik 1 300 train
+hiazpbumlr 1 300 val
+hibeeihgvi 1 300 train
+hibkmwmyum 1 301 train
+hibkqhlvgq 1 300 val
+hibmzlzbpy 1 300 val
+hibnixfhse 1 298 train
+hibuxwaddu 1 300 train
+hibvfrsyll 1 269 train
+hicbwuyaxv 1 300 train
+hicfjkwtrn 1 300 train
+hicjuubiau 0 300 test
+hiclqqebky 1 299 train
+hicmrdeajp 1 301 train
+hicndczldu 0 300 val
+hicsmswlbp 1 300 train
+hicufnotrn 1 300 val
+hicusehiwu 1 300 train
+hicycmkrce 1 300 train
+hidonazxtm 1 300 train
+hidqgpyybf 1 300 train
+hidvvmamhc 1 300 train
+hidwnstahw 1 300 train
+hidyzcdexh 1 300 train
+hiedwjfocm 1 300 train
+hiedwjvflb 1 300 train
+hieglogxvn 1 300 val
+hiegvpduql 1 300 val
+hiegyvdmko 1 300 train
+hielcvtmau 1 300 train
+hierggamuo 0 300 test
+hierkgwjhc 1 300 train
+hieuizimzp 1 292 train
+hieuynrdvg 1 300 train
+hifcwvflfd 0 300 train
+hifjgphzjc 1 300 train
+hifnhxcvdq 1 300 val
+hifoqnnega 1 301 train
+hifqzumuts 1 300 train
+hifsfyjqia 1 294 train
+hifwyvpwsz 1 300 train
+higdmcpfpw 1 300 train
+higdyzywdv 1 300 train
+higgbplmgy 1 300 train
+highgzadlr 1 298 train
+hignlfrpcv 1 300 train
+hignttjkad 0 301 val
+higosqerza 1 300 val
+higpdbpxam 1 300 train
+higtamnayu 1 300 train
+higuaocckl 1 300 train
+hihcrogmkv 1 300 train
+hiheymtqvi 1 301 train
+hihllafeup 1 300 test
+hihtiqtluv 1 300 train
+hiictcyiid 0 300 val
+hiifkngikj 1 300 train
+hiiotutgqb 1 301 val
+hiiqeoftgd 1 300 train
+hiivirhwur 1 300 train
+hiixalzbpk 0 301 train
+hiiyhfqeia 1 300 train
+hiiyszsgjy 1 300 val
+hijcqcvayr 1 299 val
+hijflohfrw 1 300 train
+hijmepskvj 0 300 train
+hijoaaoakn 1 300 train
+hijxqxczhe 1 300 train
+hikcnlrkvz 1 300 val
+hikjkaojdy 0 300 train
+hikkniplzo 1 301 val
+hikpfgptsn 1 240 train
+hikqsclcfb 1 298 train
+hilfoftyjg 1 300 train
+hilfujwfey 1 300 train
+hilgegfcjv 1 300 train
+hiljjqxwck 1 300 train
+hilmuaqgdw 1 300 test
+hilnnupliw 1 300 train
+hilryzxzij 1 300 train
+hilymcchve 1 300 val
+himagzwcnu 0 300 train
+himcbzmmhg 1 300 train
+himctcvjeg 1 300 train
+himvveuxmq 1 240 train
+himwfthfma 1 300 train
+hinocozqaq 1 300 train
+hinogxnrhx 0 300 train
+hinqgwjlgl 1 300 val
+hinrxateqp 1 300 train
+hinumiavxq 1 300 train
+hinytblltt 1 300 val
+hioffslzjp 0 300 train
+hiokkbarew 0 300 train
+hiolnpycko 1 301 val
+hiomsxhzhi 1 300 train
+hiomtfcwkb 1 300 train
+hioopeggcn 1 300 val
+hioqqktyzq 1 300 train
+hiouewskhh 1 300 train
+hiouqcdiye 0 300 train
+hiovfvadlg 1 300 train
+hipcyptyvv 1 300 train
+hipedsudqh 0 300 train
+hipksamgsi 1 300 val
+hipmbblwpl 1 300 train
+hipmdbjqhp 1 298 train
+hipqsqzlms 1 300 train
+hipsfncqwd 1 297 train
+hipskflepq 1 300 train
+hipzzheqlg 1 300 train
+hiqabqrwdh 1 300 val
+hiqhyvruxx 1 297 train
+hiqotkmjll 1 241 train
+hiqphvdpfi 1 300 train
+hiqtvgljbl 1 300 val
+hiqwxhjyca 1 300 train
+hirazyxbau 1 300 val
+hirhitmzio 1 300 test
+hirpijibhp 1 299 val
+hirzwspuzp 0 300 train
+hisbunqdch 1 300 train
+hischbhubz 1 300 train
+hiseipdlrd 1 300 train
+hisfrixnbu 1 167 train
+hisfsngehu 1 300 train
+hiskggmgtr 1 298 train
+hislcternr 1 300 val
+hisqqfkdbd 1 300 train
+hisuybzdjb 1 300 train
+hitfycdavv 1 300 test
+hitjkrjdbm 1 300 train
+hitvddsmkj 1 300 train
+hiubzkclmx 1 299 val
+hiudppjazt 1 301 train
+hiurpjclkt 1 300 train
+hiuvwmhppi 1 300 train
+hiuybvwqac 0 300 train
+hivasyhmvq 1 300 train
+hivbemfwkf 1 300 train
+hivcjnzkcv 1 297 train
+hivditnruq 1 300 train
+hiveudkbss 1 301 val
+hivfeiutsx 1 300 train
+hivnldfvyl 0 300 test
+hivqoasard 1 300 train
+hivrbyfree 1 269 train
+hivtukryen 1 300 train
+hivywjxnjz 1 300 train
+hiwfnsyvzr 1 300 train
+hiwlemcybx 1 300 train
+hiwlkmphat 1 300 train
+hiwmwaraiy 1 300 train
+hiwzkfvzaa 1 301 train
+hiwzrfkinp 1 300 val
+hixamsqeov 1 300 train
+hixdloourp 0 300 train
+hixfwsjtnz 1 300 train
+hixfzxlhcp 1 300 train
+hixhdumvxf 1 300 train
+hixifnjzba 1 300 train
+hixrtrhxmi 1 300 train
+hixunokdof 1 300 train
+hiybfvqqwj 1 300 train
+hiycpfipxc 1 300 train
+hiyergvepo 1 300 train
+hiyfjubisi 1 300 val
+hiyivgrvoi 1 300 train
+hiyonmnvsh 1 147 train
+hiywlfevvc 1 300 train
+hizgjrsljt 1 300 train
+hizjbjpjls 0 301 train
+hizltbedia 1 300 val
+hizygxelaj 1 300 val
+hjaalijmbg 1 300 train
+hjaasqlfzy 1 300 val
+hjagxgkfhb 1 299 train
+hjalygospu 1 300 train
+hjbisxrdbp 1 300 train
+hjbjznxisw 1 300 train
+hjblygobtf 1 300 train
+hjboqskwsk 1 300 train
+hjbowaahtl 1 300 train
+hjbqqjjxhg 1 300 train
+hjbqvosmtv 1 300 val
+hjbwztyuch 1 300 train
+hjbzbnxylc 1 300 train
+hjcaedgzbt 1 300 train
+hjcdjhhlzo 1 300 train
+hjcdkvjgoj 1 300 train
+hjclsojsrp 0 300 train
+hjcnzxixdw 0 300 train
+hjcqvpjvfe 1 300 val
+hjcvnjpnrd 1 300 train
+hjcwpfrsww 1 302 train
+hjcwtelvys 1 300 train
+hjdbpzbkot 1 300 train
+hjddjiqcpb 1 300 test
+hjddyeycod 1 300 val
+hjdkaabfzj 1 300 train
+hjdxncztav 1 237 train
+hjdzbiinwm 1 300 train
+hjefxesbtl 1 300 train
+hjelxxaavf 1 299 test
+hjemlpvsee 0 300 train
+hjereknbvv 1 300 val
+hjeryzzvbg 1 300 train
+hjetcvesie 1 298 train
+hjevypwbpn 1 300 train
+hjexqyglvy 0 300 train
+hjexrxrwwq 0 299 val
+hjezlaklbj 1 299 val
+hjfbpeglsg 1 300 val
+hjffkbkdvp 0 300 train
+hjfpqhqgqx 1 300 train
+hjfvahalpq 0 300 train
+hjfvvhlmbg 1 300 train
+hjfvwlqmeg 0 300 val
+hjfyfukkzm 1 300 val
+hjgedtfatx 1 301 val
+hjgkhkwead 1 300 train
+hjgkmbstin 0 300 val
+hjgqgiawqy 1 300 train
+hjgtdyuovr 1 300 train
+hjgxryckbx 1 299 val
+hjhdhumvod 0 300 test
+hjhdoxubte 1 300 val
+hjhhculjsi 1 300 train
+hjhncymvti 1 300 train
+hjhnptlwbm 1 302 train
+hjhxtcacvv 0 300 train
+hjicrdytkp 1 300 train
+hjidcpwszl 1 299 train
+hjielzdstj 1 300 train
+hjieycglah 1 300 train
+hjiixnernu 0 300 train
+hjiqvfiodc 1 300 test
+hjiweecxmn 0 300 train
+hjiwmybauf 0 300 train
+hjiymqsjsb 1 300 train
+hjjccpoiwf 1 239 train
+hjjdjcrrtv 1 300 train
+hjjdxqkcpb 1 300 train
+hjjfubyvhk 0 300 val
+hjjlgffdnj 1 300 val
+hjjlobakpe 1 300 test
+hjjqxkbsay 1 300 train
+hjjsuvothd 0 300 train
+hjkcrbpbmq 1 300 train
+hjkhxtorry 1 300 train
+hjkjedkacq 1 300 train
+hjkjfmklob 1 300 train
+hjkjyelizt 0 300 val
+hjkojzpklh 1 300 train
+hjlbfmyuri 1 300 train
+hjlbgudjqv 1 300 train
+hjledymcmc 1 300 train
+hjlgfrsktl 1 300 train
+hjliawiffu 1 301 train
+hjlljxipgd 1 300 train
+hjlmanfced 1 300 train
+hjlqfygamf 1 297 train
+hjlzopctcs 0 300 train
+hjmcnndmri 1 300 val
+hjmeygvyqc 1 300 train
+hjmmmwusjx 1 300 train
+hjmvsvxvpd 1 241 train
+hjmxpjgpol 1 301 train
+hjmzgzvabq 1 298 train
+hjnhwpnuwm 1 300 train
+hjnjbftosk 1 300 train
+hjnjdfefku 1 300 train
+hjnjfrebfb 0 300 train
+hjnjxvnwxf 1 300 train
+hjnudxlavk 0 300 train
+hjnzztyqdk 1 300 train
+hjoetslmwu 0 300 train
+hjogpdlxaj 1 300 train
+hjopgwlojg 1 296 train
+hjowcxnmqb 1 300 val
+hjozctjvfv 1 300 val
+hjpliztbqh 1 300 val
+hjpofokerg 0 300 train
+hjprgsiagd 1 300 val
+hjprpohtdb 1 300 val
+hjpsvhdncw 1 300 train
+hjpvcmgjzu 1 301 train
+hjpxttqjyq 1 300 train
+hjqhxyndit 0 300 train
+hjqnmwsldh 1 300 train
+hjqpqlcgeu 1 300 val
+hjqwdpoasa 1 300 train
+hjrjtrohcu 1 300 train
+hjrjxodeab 1 300 train
+hjrksktoxs 0 300 train
+hjrkzsbpvt 0 298 train
+hjrlzjkygb 1 300 train
+hjrsnrhlkf 1 298 train
+hjrzjrssrl 1 300 val
+hjskhdglby 1 300 val
+hjskixepdo 1 300 train
+hjsmjwiewi 1 301 val
+hjsnigzjjw 0 300 train
+hjstmtrqjn 1 300 train
+hjsvoblumx 1 300 val
+hjsxwgarvq 1 298 train
+hjtauqmpqo 1 300 val
+hjtnxkeduu 1 300 train
+hjucokbvcp 1 300 train
+hjuepwgxqm 1 300 train
+hjurtqndkf 1 300 train
+hjutmftzmw 1 300 train
+hjvcqegzxz 1 300 train
+hjvdrvoimr 0 300 train
+hjvflarrrq 1 300 train
+hjvlbeqnst 1 300 val
+hjvppggzeg 1 302 train
+hjvtndlzlk 1 300 val
+hjvtsmmgwo 1 300 train
+hjvybgigpv 1 300 train
+hjwhpdkwyw 1 300 train
+hjwpgiqkhk 1 300 train
+hjwpkcidey 1 300 train
+hjwrsmevkz 1 300 train
+hjwtgverag 1 300 train
+hjwvmxufos 1 241 train
+hjwvstouna 1 297 train
+hjwvyafzhh 0 300 train
+hjxckindzx 1 300 test
+hjxeekdmab 1 300 test
+hjxqgzyafl 1 300 train
+hjxratydnx 0 300 train
+hjxrkescnx 1 300 train
+hjxvdbnndw 1 300 train
+hjxvyufxan 1 300 train
+hjyahpffcf 1 300 train
+hjyayxvedh 1 298 train
+hjybminefo 1 300 train
+hjyffvdgvf 1 300 train
+hjyiwrwmgn 1 300 train
+hjykhqbhtu 0 300 train
+hjykqlxjea 1 300 train
+hjzfrmzzfl 0 300 train
+hjzhzsdxpi 0 300 train
+hjziepuyhs 1 300 train
+hjzwbsmiam 0 298 train
+hjzwlyxeld 1 241 train
+hjzyasauwr 1 298 val
+hjzzykkcib 1 300 train
+hkamalqdze 1 300 train
+hkapaswvkx 1 300 train
+hkatomhgph 1 300 train
+hkavnmycnp 1 300 train
+hkawzvmxbl 1 300 val
+hkbfkszcyr 1 300 train
+hkbkvhcynv 0 300 train
+hkbvijpfcs 1 300 train
+hkbwsmbmpo 1 300 train
+hkbzevoctr 1 300 train
+hkcapfpydt 1 300 train
+hkcfqjqbut 1 300 val
+hkcgyokttk 1 300 train
+hkchbdmzjx 1 300 train
+hkcivlniee 1 300 train
+hkcmwgdksh 1 300 train
+hkcsqzlqfy 0 300 train
+hkcttuzlkd 1 300 val
+hkcunzfeal 1 300 val
+hkcurgetvc 1 300 train
+hkdmxpmewr 0 300 train
+hkdpyhtqxm 0 300 train
+hkdsamgzom 1 300 val
+hkecflwqpr 1 300 train
+hkeigtkzne 1 300 train
+hkekdhftak 1 300 train
+hkelbjsbth 1 300 train
+hkelfxsxyo 1 300 val
+hkeodxizla 1 301 train
+hkepgyupzr 1 300 train
+hkeymqohio 1 300 val
+hkfagixfez 1 300 train
+hkfajoookb 1 300 train
+hkfecpjiua 1 300 train
+hkfksnrbtm 1 298 train
+hkfkwisdxl 1 300 train
+hkfqxwfhiv 1 300 train
+hkfyfuhtsw 1 300 train
+hkggfwvkgu 1 300 train
+hkgkrycmmp 1 299 val
+hkgldamgcb 1 300 test
+hkglxceyvi 1 300 train
+hkgmyuvikr 1 300 train
+hkhkaewcvi 1 300 train
+hkhleykexb 1 300 test
+hkhmcpecpe 1 300 train
+hkhnyrecyk 1 300 train
+hkhojwescl 1 300 train
+hkhpdjckkx 1 300 train
+hkhqzmphyg 1 300 train
+hkhutqidrk 1 300 test
+hkhwabstxp 1 300 train
+hkhwdgsqji 1 297 train
+hkiapcszqi 0 300 train
+hkigowcdwd 1 300 train
+hkimmsmxii 1 300 train
+hkioxyhxya 1 300 train
+hkipuscuok 1 300 val
+hkisbnuknx 1 241 train
+hkisgdxmqe 1 300 train
+hkittssyzx 1 300 train
+hkjejjxonb 0 300 val
+hkjnztvsmk 0 300 val
+hkjrdicmmb 1 301 train
+hkjujvvehn 1 300 train
+hkjuujzoll 1 300 train
+hkkacghtyf 1 300 train
+hkkaoobiwq 1 300 train
+hkkhpsczqq 1 300 train
+hkkjpsnyoj 1 300 train
+hkklgujolw 1 300 train
+hkkwrrrrei 1 300 train
+hkkxwqzewl 1 298 train
+hklckgfsis 1 301 train
+hkljzykenf 1 300 train
+hklmidvppb 1 300 val
+hklnylpqrg 1 300 train
+hklwformks 1 300 val
+hklyydiyzp 1 300 val
+hkmapmksbu 0 301 train
+hkmbmyqymq 1 300 train
+hkmbyeuyig 1 300 train
+hkmilhpalb 1 300 train
+hkmleshuuf 1 300 train
+hkmoxnzqtq 1 300 train
+hkmqimmklr 1 300 train
+hkmrzwsgxl 1 300 train
+hkmsartjds 1 300 train
+hkmznpevrk 0 300 val
+hknhhtjfiz 1 297 train
+hknkkpwstj 1 300 train
+hknucpztup 0 300 train
+hknxehfdxt 1 300 train
+hkoaodpwcd 1 300 train
+hkoasochve 1 300 train
+hkobpyburj 0 300 val
+hkohlhnywc 0 300 train
+hkosvtczoy 0 300 train
+hkotcvuwyu 1 300 train
+hkovtdjpmu 1 301 train
+hkoxvelxxh 0 301 train
+hkpbwybtfw 1 300 train
+hkplvhwibp 0 300 train
+hkpnddtbel 1 300 train
+hkpsxworpo 0 300 train
+hkptymbsmx 1 300 train
+hkpuddqpvi 1 300 val
+hkpyvgmstw 1 300 train
+hkqcobduba 1 299 test
+hkqeadfqlc 1 301 train
+hkqeqfzdqw 1 300 val
+hkqfrxwftj 0 300 train
+hkqhntryfr 1 299 train
+hkqivnrpco 0 300 train
+hkqjdfrizw 1 300 val
+hkqopvybph 1 299 val
+hkqqubdspz 1 241 train
+hkrevcuaha 1 301 train
+hkrhoronxv 0 300 train
+hkrithzmkt 1 301 train
+hkrkkhinzs 1 300 train
+hkroqhedpr 0 300 train
+hkrtxvxgru 1 300 train
+hkrwmakjzh 1 300 val
+hksbfcpnax 0 300 train
+hkscfgzwyo 1 300 train
+hksgumovdu 1 298 train
+hksigskmcb 1 301 val
+hksnuwrrdz 1 300 train
+hksptlvbwr 0 300 train
+hkssffmqxw 1 300 train
+hksvvztkmw 1 300 train
+hksyjesdls 1 300 val
+hktegfngvy 1 300 train
+hkthfcssqp 1 300 train
+hktjkboajy 1 300 train
+hktkbmoydh 0 301 val
+hktmreohka 1 300 train
+hkttgskhex 1 300 val
+hkucesxnwg 1 300 val
+hkudmkrrvu 1 300 train
+hkudxpnjqa 1 300 train
+hkugtbeoqd 1 298 val
+hkumfawvey 1 300 train
+hkupworbqb 1 300 train
+hkutirleav 1 301 train
+hkuvixymut 1 300 train
+hkvcbcfulf 1 300 test
+hkvfyeacje 0 300 train
+hkvmtvsxem 1 300 val
+hkvpmzvour 1 300 train
+hkvquoymch 1 300 val
+hkvsvxxade 0 300 train
+hkvtscjvbg 1 300 train
+hkvxmsajbx 0 300 train
+hkwdkixksd 1 300 val
+hkwlwjdilx 1 301 train
+hkwmewfrew 1 301 train
+hkxbtyuutg 1 300 train
+hkxfkwihoy 0 300 train
+hkxlcqghjx 1 300 train
+hkxmdncgcy 1 300 train
+hkxmpuxhmm 1 300 train
+hkxoqlmhsq 1 299 test
+hkxvcdnquz 1 300 train
+hkxvdxooip 1 300 val
+hkygybryma 1 300 train
+hkyoqklcwu 1 300 train
+hkysfjqufq 1 300 val
+hkyviotvry 1 300 train
+hkyyjahxww 1 300 val
+hkzksamqnn 1 300 val
+hkzmlkdyik 1 300 train
+hkznpfbsei 1 300 val
+hkzsmfxygm 1 300 train
+hkzudioyub 1 301 val
+hkzuumhfrx 0 300 train
+hkzwbmxpyy 1 300 train
+hkzxsmpuld 1 300 train
+hkzygoodvp 1 300 train
+hlaesqhvrc 1 300 train
+hlafyytmmy 1 300 train
+hlakzcsffm 1 300 train
+hlawtszbsz 1 301 train
+hlbfwnpuef 1 298 train
+hlbgxxptwj 1 300 train
+hlbhxqaqjn 1 300 train
+hlbrbkvyhr 1 301 val
+hlbsufashr 1 300 val
+hlbyzsyuai 0 300 train
+hlcpwfwcyw 0 300 train
+hlcqjuwpsd 0 300 train
+hlddiefmgi 1 300 train
+hldgcimxip 1 241 train
+hldhchyhfg 1 300 test
+hldlxricij 1 300 val
+hldocxtodo 1 300 train
+hldpdnapqh 1 300 train
+hldqervcxy 0 300 train
+hldvaqrqfs 1 300 train
+hldxlluycu 1 300 train
+hldycaemxz 0 300 train
+hlebvxyfpk 1 300 train
+hleiiwcdwb 1 300 val
+hlemgltaor 1 300 train
+hletmfwutr 0 300 train
+hleuuebxea 1 298 train
+hlevqpdeyf 1 300 train
+hlewwfiwzk 0 300 train
+hlfeuituyk 1 241 train
+hlfnawfryx 1 240 val
+hlfposscre 1 300 train
+hlfqnidxtz 1 300 train
+hlfsgqznjb 1 300 train
+hlfwsfhjps 1 300 train
+hlfxamywlw 1 300 train
+hlgakplxso 1 300 val
+hlgbviwvka 1 300 val
+hlgekivsbq 1 300 train
+hlgfewunel 0 300 train
+hlgggjzmdi 1 300 train
+hlgicjaytp 1 299 val
+hlgjnuwvqu 0 300 train
+hlgkqylzrh 0 300 train
+hlglukfuyt 1 300 train
+hlgqgnispc 1 240 train
+hlgranjocy 1 241 val
+hlhaljdyga 1 300 val
+hlhjulceyx 1 300 train
+hlhjxdezxs 1 298 train
+hlhncbtsgq 1 300 train
+hlhoclqaeb 0 300 train
+hlhqtyqnqd 1 300 train
+hlhxlmjzez 1 294 train
+hlhzincbxl 1 300 train
+hlimcopqeo 1 300 train
+hlixxcgxnm 1 300 train
+hliyrlaubq 1 300 val
+hlizdoqzzl 1 241 train
+hljaokocyv 1 301 train
+hljbrosgou 1 300 train
+hljeggtufj 1 300 train
+hljiksfqfy 1 300 train
+hljmtyrbca 1 300 train
+hljqdqbofb 1 297 train
+hlkawfzzer 1 301 val
+hlkjfdyohp 1 300 val
+hlklbhaxdu 1 300 train
+hlkupyhesf 1 300 train
+hllbaopvae 1 300 train
+hlleiadoqj 1 300 val
+hllioqvqbq 1 300 train
+hllnkjvbhj 1 300 train
+hllpsujmiy 1 299 test
+hllqxosieo 1 300 train
+hlmhrkcemk 1 299 test
+hlmuqqguqw 1 300 train
+hlmyjjalcc 1 300 train
+hlnbprigmc 1 296 val
+hlnuvejoum 1 300 train
+hlofgdjifc 1 300 train
+hloqhpuxpw 1 300 val
+hlovscdksv 1 300 train
+hloxaccskb 1 241 train
+hloxpvfccm 1 300 train
+hlpbbbvlii 1 300 train
+hlpbtldomw 1 301 train
+hlpcuxawav 1 300 train
+hlpjpdrait 1 300 train
+hlpmodihnx 1 300 train
+hlpnwsuurc 1 301 train
+hlpqhhingk 0 302 train
+hlpqxodqpz 1 300 train
+hlpvgvhabg 1 300 train
+hlpwdvlnso 1 300 train
+hlpzfvivln 1 300 val
+hlqbwyefzd 1 300 train
+hlqswzdcsa 1 300 train
+hlqvmahzco 0 300 train
+hlqychjycc 0 300 train
+hlrcsqraqd 0 300 train
+hlrdlactxw 1 300 val
+hlrdlbupbd 1 300 train
+hlrejsubcx 1 298 val
+hlritbsszg 1 300 train
+hlrkhyizhd 1 300 val
+hlrlbzwfxa 1 300 train
+hlrlzybjrq 0 300 train
+hlrohbqvwv 1 300 train
+hlrpuubewi 1 300 train
+hlrvtugehi 1 300 val
+hlsbacxpca 1 298 val
+hlsklnclxn 1 241 train
+hlskpzircb 1 300 train
+hlsmdadyrs 1 300 train
+hlsrphdgcn 0 300 train
+hlsubhyoea 0 300 train
+hlswbvjmvc 1 300 train
+hlswmuqlmh 1 300 train
+hltccvujhf 1 300 train
+hltcgeumqw 1 300 train
+hlteumzjis 0 300 train
+hltqxlbmyl 1 300 train
+hltxqhuaru 1 241 train
+hlugfdnwth 1 300 train
+hluubyhoub 1 300 train
+hluutfbsig 1 300 train
+hluxanoxct 0 300 train
+hluygfpyjs 1 300 train
+hluynpkvgv 1 147 train
+hluzffysqf 1 300 val
+hlviixtwan 1 298 val
+hlvoawddac 1 300 val
+hlvqeedsbs 0 300 train
+hlvzdttqrz 1 300 train
+hlwitavnnd 0 300 val
+hlwrpkmlqx 1 241 train
+hlwtkznzaf 1 300 train
+hlxahlliov 1 300 val
+hlxcalgltw 1 300 train
+hlxdakqrmy 1 300 train
+hlxgwlqtde 0 300 train
+hlxpjpydlh 1 300 train
+hlxpllstdk 1 300 train
+hlxuvpsboc 1 300 train
+hlxvxvmryc 1 300 train
+hlxzhipvix 1 300 train
+hlyecpkaox 0 300 train
+hlyovmttnx 1 300 val
+hlytebulax 1 300 val
+hlzkuryxas 1 300 val
+hlzmodrnqc 1 300 train
+hlzmydxvvf 1 300 train
+hlzoqpgonr 1 300 train
+hlzsuyfssv 0 300 train
+hlzwqrkwkh 1 300 val
+hlzztkliyx 1 300 train
+hmaacoiafs 1 300 train
+hmadnxwzlo 1 300 train
+hmaiksgpyg 0 300 train
+hmajsjwmbc 1 300 val
+hmaowtplvd 1 241 train
+hmapkolrje 1 300 train
+hmaqkbuzns 1 300 train
+hmasykrqcq 1 300 val
+hmavoxgvor 1 300 train
+hmaykuedhm 0 300 val
+hmbdrjvmet 1 300 val
+hmbkdaflod 1 300 train
+hmbkwnntwe 1 300 train
+hmbpajsqhd 1 300 train
+hmbqwylrbi 1 300 train
+hmbwkcpzoh 1 300 val
+hmbxhbhknk 1 300 train
+hmcbclrgdu 1 300 train
+hmcdjqncsm 1 298 train
+hmchpmvdke 0 300 val
+hmchxsdorm 1 300 train
+hmclltmwut 1 300 val
+hmcpdlychm 1 298 train
+hmcqkbwxcg 1 241 train
+hmcqmxvatx 1 300 train
+hmcrgowzym 1 298 val
+hmcsusahss 1 300 val
+hmdbpmyhyp 0 300 val
+hmdnaffyws 1 300 train
+hmdppelxqt 1 301 train
+hmdsakkrte 1 301 val
+hmebpidawf 1 300 train
+hmedexplpk 1 300 train
+hmeklosqcn 1 300 val
+hmeozrftdm 1 300 train
+hmeqdctbdn 1 301 train
+hmevwbvvlh 0 300 train
+hmfcptrods 0 301 train
+hmfcvfkagy 1 300 train
+hmffzlngeu 1 300 val
+hmflxdeemj 1 300 train
+hmfriybrck 1 300 train
+hmfrtgexuj 0 300 train
+hmfskvugyq 1 300 val
+hmfzymqjdc 1 296 train
+hmgxdnxjsi 1 300 test
+hmhdycyuen 1 300 train
+hmhhykezqj 1 300 train
+hmhnfzfrro 1 300 train
+hmhsnocunb 1 300 train
+hmiefslmfs 1 300 train
+hmiilegozp 1 300 val
+hmiimuepzd 1 300 train
+hmikxpbuuk 0 300 val
+hmikzgosnp 1 167 train
+hmileqwjrg 1 300 train
+hmilnaetwf 1 300 val
+hmireevxbd 1 300 val
+hmiugidcyk 1 300 train
+hmiwpufbgr 1 300 train
+hmiylncrva 1 239 train
+hmjhzrwjcn 1 300 test
+hmjiojxgwm 1 299 test
+hmjwnjzfvb 1 300 train
+hmjxstsabt 0 301 train
+hmjzcsmtvn 1 300 train
+hmjzgvkbky 0 300 train
+hmketbzdmc 1 300 train
+hmkfdyxodj 1 300 train
+hmklvgxrga 1 300 val
+hmkphhcxhw 1 239 train
+hmktpowvrd 1 300 train
+hmlghvqigt 1 300 val
+hmlmbiqrzp 1 300 train
+hmlpfddvjl 1 300 train
+hmlwklcqfo 1 300 val
+hmlwkqnxio 1 300 train
+hmlxrwowtc 1 300 val
+hmlyeduqbg 1 300 train
+hmlzhwjfsz 0 300 train
+hmmbzbwmdx 0 300 train
+hmmgmekvtn 1 300 val
+hmmmalrvnk 0 300 train
+hmmpibwcha 1 300 val
+hmmvpqabgv 1 301 val
+hmmwitiyry 0 300 train
+hmmwmhrujk 1 300 train
+hmmwraekvt 1 300 train
+hmnauiwovh 1 300 train
+hmnkjimojl 0 300 val
+hmnspetjoc 0 300 val
+hmnujxresc 1 300 train
+hmnwbyjgea 1 300 train
+hmobzqtbaq 1 300 train
+hmofiqjzxe 0 300 train
+hmoglbgvzh 1 300 train
+hmotahfiyh 1 300 train
+hmpbhblarx 0 300 train
+hmpcuhrope 1 300 train
+hmpczzivtb 1 300 train
+hmpjwavtwe 1 300 train
+hmpmzhsjga 1 300 train
+hmprmylinu 0 300 val
+hmprulvonq 1 300 train
+hmpsbxzglp 0 300 train
+hmptzswdcx 0 300 train
+hmpwloaqki 1 300 val
+hmqcnrnldb 1 300 train
+hmqfswcxtu 0 300 train
+hmqimwrphz 1 298 train
+hmqjbxgsne 1 300 train
+hmqjhkqkte 1 297 train
+hmqjkqbbnk 1 300 val
+hmqopxdcel 1 300 train
+hmqtrjauvf 1 300 train
+hmqvkvgdop 1 300 train
+hmraehcaoo 1 300 train
+hmrccvrljj 1 300 train
+hmrgcvzdnd 1 297 train
+hmrklxjhqw 1 301 val
+hmrnsjzewt 0 300 val
+hmrnzlidph 0 300 val
+hmrqnkxows 1 300 val
+hmrthkkvam 1 301 val
+hmsewtnful 1 300 train
+hmsicyqzyc 1 300 train
+hmskksqouh 1 300 train
+hmsktsqhzg 1 146 train
+hmsmkwzusz 1 300 train
+hmsnfaalmw 1 301 train
+hmsqmhihij 0 301 val
+hmsupjpzvl 1 300 train
+hmsziotfgx 1 298 train
+hmtdxgytwc 1 300 train
+hmtedwdlcc 0 300 train
+hmtfhypvgb 1 298 val
+hmtkeeibrj 1 300 train
+hmtkfywnsi 1 300 train
+hmtnmhepjz 0 300 val
+hmtnmrntlj 1 300 train
+hmtoqsdvss 1 300 train
+hmtpkixhjb 1 300 train
+hmtslfgekh 1 300 train
+hmtsucvrdz 1 300 train
+hmtujwwvqq 1 301 train
+hmugoovuhr 0 300 train
+hmuihokvdo 1 300 train
+hmulruizbo 1 300 train
+hmuptgngjr 1 300 train
+hmurwmhvsz 0 300 train
+hmuurfnobk 0 300 train
+hmuxqdecfs 1 300 val
+hmuzmajfhl 1 300 train
+hmvdorfdzk 1 299 test
+hmvgfxisyi 1 300 train
+hmvgwczosq 1 300 train
+hmvvvgxuxr 1 300 train
+hmvwpvnyco 0 300 train
+hmvxepafig 0 300 train
+hmwcwtutbx 1 300 train
+hmwhewernb 1 301 val
+hmwwiarhru 1 298 train
+hmxdowkesn 0 300 train
+hmxdwxydsk 1 300 train
+hmxedaacts 0 300 val
+hmxflzmzym 1 301 train
+hmxgriljqp 1 300 train
+hmxihwteht 0 299 test
+hmxlvyrksk 1 301 train
+hmxoepobvn 1 300 train
+hmxqnguyij 0 300 train
+hmxycstsos 0 300 train
+hmyccfpvbu 1 300 train
+hmyfpwbsxu 0 300 train
+hmyfqyxclx 1 300 val
+hmyveahjjb 1 300 train
+hmywawbhvc 0 300 train
+hmyycavgpq 1 300 val
+hmzbcelono 1 300 train
+hmzclmiplx 1 300 train
+hmzcuszpok 1 300 train
+hmzdwqrkjc 1 300 train
+hmzdzozfsc 1 300 train
+hmzfdocias 1 300 train
+hmzkijkhtc 1 300 val
+hmzpkrjqxh 1 300 train
+hmzpljfpnb 1 300 train
+hmzvjbaszs 1 300 train
+hmzxaazrml 1 146 train
+hnabdirocn 1 300 train
+hnabxlxbqa 1 300 val
+hnaivhcfep 1 300 train
+hnalbeaqjq 1 300 train
+hnalkvbcim 1 300 test
+hnambobzhb 0 300 val
+hnasypiyqs 1 300 train
+hnatfdifug 1 300 train
+hnbbjkbmiw 1 300 val
+hnbcpblynn 1 300 train
+hnbdwwuwno 1 301 train
+hnbkclvcgu 1 301 val
+hnbswzykku 0 249 train
+hncakxzmou 1 300 train
+hncezwpgbr 1 300 train
+hncklxqdgl 1 300 train
+hncvqppfad 1 300 val
+hndagiuhjr 1 241 train
+hndlhsvgnj 1 300 train
+hndorpodxe 1 300 train
+hndqmqibjx 1 300 val
+hndtvhozhq 1 300 train
+hnduasoexh 1 300 val
+hndweyuwrf 0 300 val
+hndzrlolxt 0 193 train
+hneddxqnnh 1 300 train
+hnelauuwfr 1 300 train
+hnelbkvbxf 1 300 val
+hnemetktvp 1 300 train
+hnetpruzii 1 301 train
+hneuizgmgb 1 301 train
+hnewpzhihy 1 300 train
+hnfcfstqnw 1 300 train
+hnfdqoykoh 1 300 train
+hnfdytoptb 0 300 train
+hnffbqzypq 1 300 val
+hnfqmsgvch 1 300 train
+hnfqnasdnm 1 300 train
+hnfrkiscbw 1 300 train
+hnfssbkumw 1 299 test
+hnftarorsu 1 300 val
+hnfvpoglen 1 300 train
+hnfwagcxdf 1 300 test
+hnfxjodihv 0 300 train
+hnfzprkodk 1 300 train
+hngbppnrys 1 300 train
+hngdzzjxfo 1 298 train
+hnglazpqtw 0 300 train
+hngmdcwliy 1 300 train
+hngsxhckgd 1 300 val
+hngultovqd 1 298 train
+hnguvzdjpe 1 300 train
+hngzsmpvva 1 300 train
+hnhafxatut 1 300 val
+hnhatjsfjx 1 298 val
+hnhcndqeiw 0 300 train
+hnhiefywmi 1 300 train
+hnhixwrjbs 1 300 train
+hnhqvejrqu 1 300 train
+hnhrxcfqsy 1 300 val
+hnhrxxirht 1 300 train
+hnigwpbkno 1 300 train
+hnigzmskoe 1 300 val
+hninriimhd 1 300 train
+hnitnjujrv 1 300 test
+hniydbeakm 1 300 val
+hniyrjepdi 1 300 train
+hnjepxzttj 1 300 train
+hnjgqaaicx 1 300 train
+hnjoobqywj 1 301 train
+hnjrwyxdih 1 300 val
+hnjtfdetqs 1 300 train
+hnjvdnygjm 1 300 train
+hnjyvlhonp 0 300 train
+hnjzbriysa 1 300 train
+hnkeolkhks 1 300 train
+hnklecpcwf 1 300 val
+hnksomofpc 1 300 train
+hnlbblarxn 1 298 train
+hnlidywipq 1 300 train
+hnlnxorlvu 1 300 train
+hnlouepgqd 1 300 val
+hnlpmvyanu 1 300 val
+hnlxdctrny 1 301 train
+hnmdzsqwwi 1 300 train
+hnmefdzxxf 1 300 train
+hnmfjrcayp 1 300 train
+hnmjyvxxhg 1 300 train
+hnmpqyteqf 0 300 train
+hnmuflayuv 1 300 train
+hnndmlzjdr 1 298 val
+hnnhablrww 1 300 train
+hnnjmlnatx 0 300 train
+hnnlcrqfpf 0 300 train
+hnnqdccjsk 1 300 val
+hnnungjzfv 1 300 train
+hnnzadcdos 1 300 val
+hnobywmhub 1 300 train
+hnoiaqwstl 1 300 train
+hnokdeltbj 0 300 train
+hnonyvtuvx 1 300 train
+hnopstcqoi 1 300 train
+hnotlpuwul 1 300 train
+hnpbrviibl 1 300 train
+hnpemjjcuq 1 300 train
+hnpfbsmarx 1 300 train
+hnpiflaohv 1 300 train
+hnpjlqwpos 1 300 train
+hnpqzfeeiy 1 241 train
+hnpxfwmrxc 1 300 train
+hnqjwijpdp 1 300 train
+hnqkejilda 1 300 train
+hnqocyfmyk 1 301 val
+hnqqfjpioa 1 300 train
+hnqrrljqei 1 300 train
+hnqxotcevk 1 300 train
+hnrejhehka 1 300 test
+hnrhowuevf 0 300 train
+hnrjqavaaf 1 300 val
+hnrlrzohns 1 300 train
+hnrnvcrrof 1 301 train
+hnroixknbp 1 300 train
+hnruvjllbs 1 300 train
+hnrwhlepir 1 300 train
+hnrzuoqnkz 1 300 train
+hnsbuiizov 1 301 train
+hnselekxwv 0 300 val
+hnsgjiicgo 1 300 train
+hnshdsglrh 1 300 val
+hnsvivwubi 1 300 train
+hnsvwqpsxc 1 300 train
+hnswfdiygr 1 301 train
+hntguogkqd 0 299 train
+hntlvltpwo 1 301 train
+hntnemhdnv 1 300 train
+hntoqabvxy 1 300 train
+hntxhvjdxy 1 300 train
+hnuudbriou 1 300 val
+hnuxytmfdm 1 136 train
+hnuyyagmlz 1 296 train
+hnvecxayzc 1 300 train
+hnvroxltnl 1 300 train
+hnwayorldx 1 300 val
+hnwljrzjaz 1 300 val
+hnwvdtjqvc 1 301 train
+hnwwmhenfg 1 300 val
+hnxbtipvwc 1 298 train
+hnxdqowyqc 0 300 train
+hnxetiknbh 1 300 train
+hnxhwfttpy 1 300 train
+hnxiwdurri 1 300 train
+hnxkqrffjx 1 300 test
+hnxxnufuyv 1 240 train
+hnxxyqtnsp 0 300 train
+hnyarndzix 1 300 train
+hnycbbsjfi 1 300 val
+hnyfifefzg 1 300 val
+hnyfyegvrt 1 300 train
+hnygkbmyyg 1 300 val
+hnyhlhysau 0 300 train
+hnyhxyrahc 1 300 train
+hnyqrdidah 1 299 train
+hnywpozkhx 1 301 train
+hnzawxxwkh 1 300 train
+hnzdkvwmoz 1 302 train
+hnzqqwinxl 1 300 train
+hnzwkgxedf 1 300 train
+hnzymonnsh 0 300 train
+hoabestbvo 1 300 train
+hoadpgmeyi 1 301 val
+hoafmkwlaw 1 300 train
+hoaljnurvt 1 300 train
+hoanieaxry 1 301 train
+hoanyyfizm 1 298 val
+hoavhqskuy 1 300 val
+hoaweiathp 1 300 train
+hobarhnsyk 1 300 train
+hobblmkges 0 300 train
+hobgetzpea 1 241 train
+hobkbuaklr 1 300 train
+hobmpusszb 1 300 train
+hobqnnblkq 1 298 train
+hobsbfscbx 1 300 train
+hobsqgcawk 1 300 val
+hobxawtira 1 300 val
+hocglwmzhr 0 300 train
+hocjijxcug 1 300 train
+hockjwzduq 1 300 train
+hockpcxwvz 1 298 train
+hocojytmjf 1 300 train
+hocuhwhgji 1 300 train
+hocwzucogk 1 300 train
+hodbwfrray 1 300 train
+hoddanjgqp 0 300 val
+hodglukdub 1 300 train
+hodhfycfrm 1 300 train
+hodncgmzxb 0 300 train
+hodohjlzxg 1 300 val
+hodrszynaa 1 301 train
+hodzowguky 1 300 train
+hoebaacbjo 1 300 train
+hoebvdovuj 1 300 train
+hoelpuopfi 1 299 val
+hoevrgmybf 1 300 train
+hoeweunzhs 1 300 val
+hofhiufhfd 1 300 train
+hofjmnefza 0 249 train
+hofkhjxisd 1 300 train
+hoflsgfncq 1 298 train
+hofmzswtrc 1 300 train
+hofqokfyvd 1 300 train
+hofrbunxng 0 300 train
+hofupsxkai 0 300 train
+hofyjuklgx 1 300 train
+hofykjflsd 1 300 train
+hofyuwtrcy 1 300 train
+hogdlxksdh 1 300 train
+hogifuhffm 1 300 train
+hogilbrbej 0 300 val
+hogmvuuhhl 1 296 train
+hogqreuhfm 0 300 train
+hogyprobqu 1 300 train
+hogzkraxgq 1 300 train
+hohaulnmrm 1 300 train
+hohdtppeag 1 300 train
+hohicuwqdn 1 300 train
+hohkrwopdg 1 300 train
+hohrvrekpk 0 300 val
+hoidoqstpn 1 300 val
+hoifswpbsd 1 300 train
+hoihutnvty 1 300 train
+hoihzcvsgv 1 300 val
+hoiotrbvkm 1 299 train
+hoitqyycbu 1 300 train
+hoiydjcgkj 1 300 train
+hojasgegod 0 300 val
+hojbefkzhz 0 300 train
+hojcyybnwm 0 300 train
+hojfceejsf 1 300 val
+hojheagjuw 1 300 train
+hojjeasdok 1 300 train
+hojjnezarv 1 300 train
+hojlqyugwx 1 300 train
+hojwlxlzox 0 300 val
+hokbnmcntx 1 298 train
+hokbnnrkho 1 300 train
+hokbxluozv 1 300 train
+hokodwrnpw 1 300 train
+hokqxqones 1 300 train
+hokugesscb 1 300 val
+hokyhymcgv 1 300 train
+holcsnrsao 1 301 train
+holdvutgiz 1 300 train
+holfzxlrzl 1 300 train
+holgduewud 1 300 train
+holjfoqmdj 1 300 train
+hollmfvplq 1 298 train
+holnqykchl 1 300 val
+holpragenm 1 300 train
+holssaffbm 1 300 train
+holvywcnrd 1 298 train
+hombhxahfr 1 299 val
+hombtiaspp 1 300 train
+homepvwcgh 1 301 train
+homewkmtmn 1 300 val
+homnphwgav 1 301 val
+homwfsdunz 1 300 train
+honhlvedjb 1 300 val
+honlaxtvxq 1 300 train
+honsdpgunl 1 300 train
+hontnrmcxp 1 300 val
+honxqdilvv 1 299 test
+hoocqprani 1 300 train
+hoocwxghxl 1 300 val
+hoopxglgxr 1 300 val
+hooqcfyouy 1 300 train
+hoowldzhce 1 300 train
+hooxqfrqjc 1 300 train
+hooznljahx 1 300 val
+hopheufrwa 1 300 train
+hoplzfvtid 1 300 train
+hopnfebmck 1 298 train
+hopqndxlso 1 300 train
+hopuugykpb 1 300 train
+hopvuricti 1 300 train
+hopyexztjg 1 299 train
+hoqjyfyjbw 1 300 train
+hoqmkzxzym 0 300 train
+hoqnjghgam 1 240 train
+hoqyirekjb 1 298 train
+horbklyyni 0 300 train
+horcjsxnin 1 300 val
+hordcggzmi 1 300 train
+hormvlveov 1 300 train
+horqmicjnu 1 300 train
+horrhnsuea 1 300 train
+horteymmvg 1 300 train
+horutnradk 1 300 test
+horzgzunkm 1 300 train
+horzzciczp 1 300 val
+hosebsbdix 1 300 val
+hosqfqqgee 1 300 train
+hosvnsayez 1 300 val
+hoswwrgbsb 1 300 val
+hotafxfzxc 1 300 train
+hotcatfjfd 1 300 train
+hotipyqqyl 1 300 train
+hotvnhsufy 1 300 train
+hotzlbthky 1 299 train
+houbvfwmrd 1 300 train
+houceixjki 1 301 train
+houdacvthz 1 300 train
+houfasepzn 1 241 train
+hounkknlbz 1 300 train
+hournhdfpq 1 300 train
+housbahgev 1 300 train
+houuhunipr 1 300 train
+houvnaqqbi 1 241 train
+houyfiwdyw 1 300 train
+houyzbhcjx 1 300 train
+houzjcicgk 1 300 train
+houzrrfbqg 1 300 test
+hovmulvwpz 1 300 test
+hovqwmunjh 1 300 train
+hovxifufxf 1 241 train
+hovxzlmjji 1 300 train
+hovynzkrlh 1 300 train
+howewzbdom 1 300 train
+howhygmfvg 1 300 val
+howishwmtc 1 302 val
+howmcsjnjb 1 300 train
+howoyjlciu 1 300 train
+howqmjjpoz 0 301 train
+howruupkxw 1 300 train
+howwlhmavm 1 300 train
+howwsaboik 1 300 train
+hoxbqrkykv 1 300 train
+hoxdbhxpqf 1 298 train
+hoxemyczix 1 300 train
+hoxjfrsbye 1 300 test
+hoxpeauwjk 1 300 train
+hoxrefyboh 1 300 val
+hoyfruihtw 1 300 val
+hoyiqnfwcc 1 300 train
+hoykxrljpv 1 300 val
+hoyudeuckw 1 300 train
+hoyulwhdfo 1 300 val
+hoywsbopjw 1 300 train
+hozblujqic 0 298 train
+hozciksznp 1 300 train
+hozcwxyrrz 0 300 train
+hozwfqophr 1 300 val
+hozyutxylm 1 299 test
+hpabomixmu 1 300 train
+hpafzeavqo 1 300 train
+hpajdruryi 0 300 val
+hpatesrpuu 1 300 train
+hpawkfcnrr 1 300 val
+hpaydhckpf 1 301 train
+hpbbdahlnv 1 298 train
+hpbhnyewff 1 300 train
+hpbjyhlqku 1 300 train
+hpbmczvuam 1 288 train
+hpbqsdmrgz 1 300 train
+hpbqzowfao 1 300 train
+hpbrsjknez 1 300 val
+hpbyldngth 1 300 train
+hpcfvgdlwi 1 300 train
+hpcgekliru 1 300 train
+hpchpnvawf 1 300 train
+hpcivouyku 0 300 train
+hpcnfqzlto 1 300 train
+hpcnmxtomj 1 300 train
+hpcuqrtslu 1 300 train
+hpcywxkdqw 1 300 train
+hpdavfaacr 1 298 train
+hpddnqjkfm 1 300 train
+hpdetbrchg 1 136 train
+hpdlkcnpbf 1 300 train
+hpdnhefbll 0 300 train
+hpdnxefseu 0 301 val
+hpdprqsiny 1 301 train
+hpdvbpcgww 1 299 train
+hpdvnwiado 1 300 train
+hpeotrqggp 0 300 train
+hpepttbpqu 0 300 train
+hpetjipexz 1 300 train
+hpeyakpjiu 0 300 train
+hpfbsnuwwi 1 300 train
+hpfrfbheli 1 300 train
+hpftfizsyi 1 300 train
+hpfxfxcedh 1 300 train
+hpgcddcvke 1 300 train
+hpgkeqihrs 1 300 train
+hpgoulaolm 1 241 train
+hpgteigvcc 0 300 train
+hpgyfsynif 1 300 train
+hphakyvkmy 1 300 train
+hphaokkuxd 1 300 train
+hphgvxgldu 1 300 train
+hphhaymlah 1 300 train
+hphistdqhu 1 300 val
+hphiyksrth 1 300 val
+hphnkvblhf 1 300 train
+hphrzocvcs 1 300 train
+hphwoahxjg 1 300 train
+hphwokudib 1 300 train
+hphxgttbro 1 300 train
+hphzexqnuf 1 300 train
+hpibvkqmvh 1 300 val
+hpierzntfi 1 300 train
+hpieuicpyu 1 241 train
+hpigtmlwqy 1 300 val
+hpikqtfxzs 1 300 val
+hpiojbofht 1 300 train
+hpiquqarde 1 301 train
+hpirlwniwe 1 300 train
+hpitubsrqo 1 300 train
+hpjbafyejx 1 300 val
+hpjcrnqxyo 1 300 train
+hpjecyfqrx 0 300 train
+hpjfaujhhy 1 300 val
+hpjlsodvji 1 300 train
+hpjqwnzqey 1 300 train
+hpkrhhxscl 1 255 train
+hpkslfadsn 1 298 train
+hpkvnqbnyt 1 300 train
+hpkvsuvwbk 1 288 train
+hplemlikjw 0 300 train
+hplffsplnv 1 300 val
+hplllsmoyg 1 300 val
+hplnnfomzi 1 300 train
+hplxobozah 1 300 train
+hplxtssgnz 0 300 val
+hpmdmmgrch 1 300 train
+hpmezdkuki 1 302 train
+hpmjkvjcuw 1 301 val
+hpmlabxnio 1 300 train
+hpmvunemnz 1 300 train
+hpneudadtf 1 300 val
+hpnevpakvy 1 241 train
+hpnffvmkbl 1 241 train
+hpnfxwzvpc 1 300 train
+hpngzbiuje 1 300 train
+hpnhewmrqv 1 300 train
+hpnhftyxnr 0 300 train
+hpnicxbgrn 1 300 train
+hpnkbdrjsz 1 300 train
+hpnpppxrcj 1 300 val
+hpnxrufval 1 300 train
+hpofuqlnpr 0 300 train
+hpoithtzux 1 241 train
+hpomliuqdc 1 300 val
+hpomzutmfq 1 300 test
+hponjexdhn 1 300 train
+hpopwapqxv 1 300 train
+hpoqxrddlx 0 300 train
+hpotsxzxbx 1 300 train
+hpowxfzqkl 1 300 train
+hppeihmuec 1 300 train
+hppiwnhbax 1 295 train
+hppjwivarm 1 300 train
+hppkohwkwb 1 300 val
+hppnxpnkui 1 300 train
+hppthldonb 1 300 train
+hppwmqphfq 1 300 train
+hpqgkultrg 1 301 train
+hpqieaydio 1 300 train
+hpqlwuwerw 1 300 train
+hpqmelyasc 1 300 train
+hpqoteqpbr 1 300 val
+hpqrriuxcy 1 300 train
+hprhjudtot 0 300 train
+hprjimqfvg 0 300 train
+hprmoefdab 1 300 val
+hprpnytpgv 1 298 val
+hprstleikc 1 299 test
+hprzotbjtj 0 300 train
+hpsjrqgyon 1 300 train
+hpskrtuawv 0 300 train
+hpssndpjfi 1 300 train
+hpssvcvihl 1 300 train
+hpsvdyikxk 1 241 train
+hpsvytifzs 1 300 train
+hptbcitxji 1 300 train
+hptftpwwar 1 300 train
+hptnztntml 1 300 train
+hptpfttftf 1 300 train
+hptqbnarbv 0 298 train
+hptydqkdpp 1 300 train
+hpuislawan 1 301 val
+hpulxkoirm 1 300 train
+hpumfhgpxr 0 301 train
+hpumupvcpx 1 300 train
+hpurahupjh 0 300 train
+hpvahqsfvd 1 300 train
+hpvaolfwdj 1 301 train
+hpvbvcxipt 1 300 train
+hpvjldbcnx 1 298 train
+hpvoiuirnt 1 300 train
+hpvpqejzle 0 301 train
+hpvtmohvma 1 300 train
+hpvtzjjykw 0 300 val
+hpwbfbwiio 0 300 train
+hpwcvxgtnk 1 301 train
+hpwdlgshqg 1 300 test
+hpwmxshndg 1 300 train
+hpwoqumlaw 0 300 train
+hpxexmjorz 1 300 train
+hpxikhknts 1 300 train
+hpxkitfcxm 0 300 train
+hpxsnuodkh 1 300 train
+hpxykzhgtf 0 301 train
+hpyctzepzn 1 300 train
+hpydwmizew 1 298 val
+hpyhoykdwo 0 300 train
+hpylizxkzq 1 300 train
+hpypqkybny 1 300 train
+hpysazqobm 1 269 train
+hpyxxlyutp 1 300 val
+hpzfjjfhbq 1 300 val
+hpzjszrqqz 0 300 train
+hpzqubfjom 1 300 train
+hpzwxyqpht 1 301 train
+hpzztgqqbl 1 300 train
+hqacfyyvqa 1 300 train
+hqagqcxicm 1 300 train
+hqamrvlvfj 1 298 val
+hqaogapyog 1 300 train
+hqaqgvuwdx 1 300 train
+hqasskuudt 1 300 train
+hqbcowwydf 1 302 val
+hqbgbuxksq 1 300 train
+hqbjsdfses 1 300 train
+hqbnsuhxou 1 298 val
+hqbokimony 1 300 train
+hqbwqqwxgl 1 300 train
+hqbyhofrot 0 300 train
+hqccrpbmhr 1 297 train
+hqcdljodok 0 300 train
+hqcdzmwcig 0 300 val
+hqcfsyvjly 1 300 train
+hqcgyayuwb 1 300 train
+hqcieyxrgs 1 300 train
+hqcnaesvmg 1 300 train
+hqcrauawma 1 300 test
+hqcsditimx 1 300 train
+hqcveqsrsb 1 300 train
+hqcwnryzvl 0 300 train
+hqczhhssie 1 300 train
+hqdfmlonnd 1 300 train
+hqdnnmxlwi 0 299 val
+hqdobqhsyz 1 301 train
+hqdpqxvekq 1 300 train
+hqeaptsnho 0 300 train
+hqebuosggp 1 300 train
+hqedsnenno 0 300 train
+hqeevyeknb 1 300 train
+hqeldyhmpu 1 300 train
+hqeqmvombq 1 300 val
+hqergxqdir 1 300 val
+hqeseklsdo 1 300 train
+hqeukcqkgg 1 300 train
+hqevjqiglq 1 300 val
+hqfgyilxka 1 300 train
+hqftstuxzs 1 300 val
+hqfwnwyulv 0 300 val
+hqfxruqynj 1 300 train
+hqgbifpkry 1 300 train
+hqgervpkkf 0 300 train
+hqgkfmfruw 1 300 train
+hqglvjyrwg 1 300 val
+hqgmjzfksp 1 249 train
+hqgndlnyvu 0 300 train
+hqgoqmozpm 1 300 train
+hqhaqjvpds 1 299 test
+hqhgxcutir 1 300 val
+hqhktnvikh 1 300 train
+hqhxonkyov 1 300 train
+hqiebmrvou 1 300 train
+hqionfqgsu 1 300 train
+hqisqfxerz 0 300 train
+hqixijrrjd 1 300 train
+hqizhctvex 1 300 train
+hqjdqjiyfc 1 292 train
+hqjebznrdz 1 300 train
+hqjeynxsru 1 300 train
+hqjhztoikb 1 300 train
+hqjuvsqmpv 1 300 train
+hqkotzqcfg 1 300 train
+hqkpapumoa 1 300 train
+hqktcihspg 0 300 val
+hqkvihgtbr 1 300 train
+hqldzgqqpg 1 300 train
+hqlflsfbog 1 300 train
+hqlfvevxfl 1 300 train
+hqlmhjsbgj 1 300 train
+hqlqsqqher 1 300 train
+hqlshhraad 1 300 train
+hqlzcmdrbx 1 300 train
+hqmcbwrplp 0 301 train
+hqmcwejpnq 1 300 train
+hqmdfcphsg 0 300 train
+hqmtuxmucg 1 300 val
+hqmuwcrdoz 1 301 val
+hqmuzlctgd 1 300 train
+hqmvbuwhwa 0 300 train
+hqmzdcwjnn 1 300 train
+hqnfmvrjlo 1 300 train
+hqnfmydsju 1 300 train
+hqnkjfyhri 1 300 train
+hqnoemaqsd 1 299 val
+hqnoeymikr 0 300 train
+hqnsjkkpjc 1 300 train
+hqnwdzttpm 0 300 train
+hqnzmyfqmh 1 300 train
+hqojzwsdmb 0 300 train
+hqompqlkft 1 300 val
+hqosycfrjf 1 300 train
+hqpbyqbuzt 1 298 train
+hqpebsloec 0 300 train
+hqpjmwyygq 0 239 train
+hqpntlbcte 1 300 val
+hqpoytlyel 1 300 val
+hqpqwfnjwz 1 300 train
+hqqbunesff 1 249 train
+hqqkhnvgtc 0 300 train
+hqqmtxvbjj 0 300 train
+hqqnsbetzv 1 300 val
+hqqwhvfrkt 1 241 train
+hqqyxdqxum 1 300 val
+hqrekufrrj 1 300 train
+hqrfmujsgn 1 300 train
+hqrobjsjvn 1 300 train
+hqrrpdijqb 1 300 train
+hqsjtzjnod 1 240 val
+hqsrildiwm 1 300 train
+hqsuovcrlk 1 300 train
+hqtahhbjsl 1 300 train
+hqtepxaeqx 0 300 train
+hqtgiyuuep 1 300 val
+hqtjafdzow 1 301 val
+hqtkzmrgew 1 300 train
+hqtmojujlv 1 300 train
+hqtqyhomru 1 300 train
+hqtvgiwtce 0 241 val
+hqucoizzbg 1 300 test
+hqurikfcie 1 301 val
+hquxvwnigf 0 300 val
+hquzkyfpbn 1 300 train
+hqvchagnjd 1 300 train
+hqvesvhmnh 1 300 train
+hqvgizzpmy 1 300 train
+hqvhlivsas 0 300 train
+hqvkabpedg 1 300 test
+hqvxahnrnw 1 301 val
+hqwbgchtpp 1 300 val
+hqwfxfcohn 1 300 train
+hqwhpdgort 1 300 train
+hqwjsjtkru 1 300 train
+hqwpjzpjha 1 300 train
+hqwruoqmnu 1 300 train
+hqwsaneqlu 1 300 train
+hqwtbwjnul 1 300 train
+hqwtiqdfan 1 300 val
+hqwxigyxie 1 300 train
+hqwxwmvopn 1 300 train
+hqxfenmiis 1 300 test
+hqxhkfkzyv 1 300 train
+hqxivsfbwb 1 300 train
+hqxlyxhjin 0 300 train
+hqxmdzdegz 1 300 val
+hqxniwuzth 1 300 train
+hqxpzbyijx 0 299 val
+hqxtmetifv 1 300 train
+hqxvlboamz 0 300 train
+hqytjkkmus 1 300 train
+hqyvmzekuy 0 300 train
+hqzbfloszg 0 300 train
+hqzfihmxne 1 300 train
+hqzljwdfwm 0 300 val
+hqzmuisipr 1 300 train
+hqzoizppqb 1 300 train
+hqzuuxfnhx 0 300 train
+hqzvjivapc 1 300 train
+hqzvtootih 1 300 val
+hqzwudvhih 1 300 test
+hraerfknlm 1 241 train
+hramviadsc 1 300 train
+hramvxdwvj 1 300 train
+hraokltron 1 300 train
+hrasgwarml 1 300 train
+hraulhmagz 1 300 train
+hravesxbng 1 300 val
+hraxiiyfvg 1 300 train
+hrbbfgntax 1 300 train
+hrbdfaglwt 1 300 val
+hrbdgunsvk 1 300 train
+hrbjfjgnjg 1 241 train
+hrbjhlvwtw 1 240 train
+hrbkraauwx 1 300 test
+hrblxtujgx 0 300 train
+hrbrjdctgm 1 301 train
+hrbslndovp 1 300 train
+hrbvugekdv 1 300 train
+hrbwvtjwat 1 300 train
+hrbxywlyyt 1 300 train
+hrbzuyezxg 1 300 train
+hrcciawbyh 1 300 train
+hrcfjojxqq 1 300 train
+hrcggrngog 1 300 train
+hrchgwivyy 1 298 train
+hrchuhybuy 1 300 train
+hrcmsestby 0 300 train
+hrcsvfktcz 1 300 train
+hrdcdjtarc 1 241 train
+hrddukmlxq 1 300 train
+hrdezifdym 1 300 train
+hrdlenccwv 1 300 train
+hreamploeb 0 300 train
+hregmxhpzr 1 300 val
+hrehhvcwjv 1 300 train
+hrejwcseqb 1 249 train
+hrepdeiczh 1 300 train
+hrercnxqcv 0 300 train
+hrestpwqha 0 300 train
+hrettxkjco 1 300 train
+hrfesnigjd 1 300 test
+hrffhnpvrj 1 300 train
+hrfjbsruvh 1 301 train
+hrfkjdtzww 1 302 val
+hrflalczag 0 300 train
+hrfplvcrnp 1 300 train
+hrfrsqpiqx 1 300 val
+hrfweylnua 1 300 train
+hrfxajrltl 1 301 train
+hrfxlkjgjk 1 300 train
+hrgbntllei 1 300 train
+hrgdcdpgow 0 301 train
+hrgqhsmdaa 1 300 train
+hrgrffxxzj 1 300 val
+hrgrwwujcy 1 300 train
+hrgwhymjpq 1 300 val
+hrgyceempk 1 300 train
+hrhpwttotn 1 300 train
+hrhsdsowvo 0 300 train
+hrhsedoyer 1 300 train
+hrhvngykur 1 300 train
+hrhxpqjpui 1 300 train
+hrhzoupjzq 1 300 train
+hrifyziwgp 0 300 train
+hriguptneu 1 147 train
+hrigwyzdtm 1 300 train
+hriitpxjtk 1 300 train
+hrijhsruwx 1 300 train
+hrikcfaehb 1 300 val
+hrilefvfga 0 300 train
+hrimlwvzjd 1 300 train
+hriucrwdmf 1 300 train
+hriultflyg 0 300 val
+hrizczebyb 1 300 train
+hrjaahazzq 1 300 val
+hrjbpqbhup 1 241 train
+hrjielxetg 1 300 val
+hrjiflwsrx 1 300 train
+hrjjbjfdxl 1 241 val
+hrjkgzpcgc 1 302 val
+hrjphyuizh 1 300 train
+hrjpktdppp 1 300 train
+hrjsswqbbe 1 298 train
+hrkfjaxlhs 1 300 val
+hrkgvxumkl 1 167 train
+hrkikllkqt 1 300 train
+hrkquvytxp 1 300 train
+hrkrdfhmdr 1 300 train
+hrkutevfpo 1 300 val
+hrkvhduqqm 1 300 train
+hrkwaqpljg 0 300 train
+hrkwsnfbfp 1 300 train
+hrlbvanxwv 0 300 train
+hrlcoalhiu 1 300 train
+hrlimoipax 1 300 val
+hrllilgtzi 1 301 train
+hrlronsnht 1 300 train
+hrlrtaouty 1 300 train
+hrlshhoiko 1 300 train
+hrlsiyxqdx 1 300 train
+hrlttulqpm 1 300 train
+hrlxrztqsy 1 300 train
+hrlyersjrh 1 300 train
+hrlzudzpyp 1 300 train
+hrmbmwjebp 1 301 val
+hrmdzvymgt 1 300 train
+hrmnmrfgsx 1 298 train
+hrmqefifhs 0 300 train
+hrmqirsrgx 1 297 val
+hrmsmamtam 1 300 val
+hrmurgfzoi 0 300 train
+hrmyyyqqfv 1 300 val
+hrnajamccr 1 301 train
+hrncvumttq 1 300 train
+hrnfnbtaci 1 300 train
+hrnhdjwymh 1 301 val
+hrnliocrtl 0 300 train
+hrnllwhaay 1 301 train
+hrnrjdfoqh 1 300 train
+hrnuyxgzxf 1 300 val
+hrnwutsecy 1 241 train
+hrochgaosv 0 301 train
+hrofeelxvp 1 300 train
+hroqcpapmy 0 301 train
+hrotywgvnz 1 300 train
+hrovzkcyjw 1 300 test
+hrozdlulou 1 300 train
+hrpcxptrfj 1 297 train
+hrpdutntqq 1 242 train
+hrpffqsxiv 1 301 train
+hrpxcjzzhj 1 300 train
+hrpxiqilkc 1 300 val
+hrqewbulqa 1 300 train
+hrqjludceq 1 300 train
+hrqqeibfnm 1 300 train
+hrqrswvkww 1 300 train
+hrqrusbfhn 1 300 train
+hrqwqzptjj 1 300 val
+hrrajpwwfo 1 300 train
+hrrkieofej 1 300 val
+hrrrvetfgu 1 300 train
+hrrwofyxnz 1 300 train
+hrrwxfsyzg 1 300 train
+hrrzfjpuak 1 300 train
+hrsdmqnrgy 1 300 train
+hrshyeoquj 1 300 val
+hrsiwoxehy 1 300 train
+hrsmancvnq 1 298 train
+hrtarlzjqi 0 300 val
+hrthfgffnf 1 300 train
+hrthfhjrdd 1 300 train
+hrtkxhuwou 1 298 train
+hrtmclnwyq 0 301 train
+hrtmnxmadf 1 300 train
+hrtmpxqumh 1 300 train
+hrtmwztfzc 1 299 val
+hrtnmkgjin 1 300 val
+hrtruotrdu 1 300 train
+hrtvdjgrqc 1 300 train
+hrtyepnllz 1 300 train
+hrucxshlym 1 167 train
+hruiuuxxzc 0 300 train
+hrujtazwda 1 300 train
+hrumbmmwuf 1 300 train
+hrundztjfb 1 301 train
+hrupkssvds 1 297 train
+hruugiyirx 1 301 train
+hruydvrvqu 1 241 train
+hrvdmmjpwn 1 300 train
+hrvikpomtz 1 300 train
+hrviseedju 1 300 train
+hrvliizvgg 1 300 train
+hrvqywpiev 1 300 train
+hrvqzjmsxh 0 300 train
+hrvsdlljgn 1 300 train
+hrvsehxmts 1 300 val
+hrvwkydokj 0 300 train
+hrvyuyjwuv 1 300 train
+hrwbotqljp 1 301 val
+hrwgtkdgvh 1 300 train
+hrwldzzaco 1 300 train
+hrwnzlqruf 0 240 train
+hrwurpjerz 1 300 train
+hrwvkpmght 1 300 val
+hrxcnewegb 1 300 train
+hrxijsbgns 1 300 train
+hrxletgstq 1 300 val
+hrxqwqdrfd 1 300 train
+hrxximpcnf 1 300 train
+hrydrvbapt 1 300 val
+hryenfjmcn 1 241 train
+hryhqvkupl 1 300 train
+hryigjhtfg 1 300 train
+hrykzjlhva 1 301 train
+hrymuwlegh 0 300 train
+hrzbzfnfbj 1 299 val
+hrzdmyjfxh 1 300 val
+hrzdrybpdy 1 300 train
+hrzkvdbqlc 1 300 val
+hrzmpehsmo 1 298 train
+hrznynemfj 0 300 train
+hrzskpirud 1 300 train
+hrztbthajc 1 300 train
+hrzupygjiw 1 300 train
+hrzzgwasev 1 300 val
+hsaafwdtoj 0 300 train
+hsaaknzxhg 1 300 train
+hsagxqxhni 1 299 val
+hsasnblsta 1 300 train
+hsasxgmixy 1 240 train
+hsazdtrvux 1 300 train
+hsbgwiqzcg 1 300 train
+hsbijaigkz 1 301 train
+hsbiqbtyrq 1 299 test
+hsbljbsgxr 1 300 test
+hsbmlcuxyx 1 300 train
+hsbrwaeaah 1 300 test
+hsbwhlolsn 0 300 test
+hsbyrkadik 0 300 train
+hsbzndebrl 1 300 val
+hscahixejc 1 300 train
+hscinccfcp 1 300 train
+hscmhcxyqy 1 301 train
+hscxbknlsx 1 301 val
+hsdaufxvau 1 300 train
+hsdisorwhm 1 300 train
+hsdkcxignr 1 300 train
+hsdmktfzqx 1 301 train
+hsdofynpsa 1 299 train
+hsdyfidrxi 1 300 train
+hsedwxvljr 1 300 train
+hselhjjdwg 1 301 train
+hseotizotm 1 299 train
+hseqckyspj 1 300 train
+hsevzcqesy 1 300 train
+hsezyyxsfb 1 300 train
+hsfbyxbkmn 1 300 train
+hsfcfszgxb 1 296 train
+hsfchihmld 1 300 train
+hsfdtzhuno 1 300 train
+hsfedqonem 1 300 train
+hsffsyqlbl 1 301 train
+hsfkitehzn 1 300 train
+hsfoaxnqrd 0 301 train
+hsfogiipgs 0 300 train
+hsfqxlalgy 1 241 train
+hsfrlqoezc 1 300 train
+hsfutddtzn 1 300 train
+hsfuxglebv 1 300 train
+hsgmhqmqpn 1 300 train
+hsgxsbefrb 1 300 val
+hsgxtybabo 1 300 val
+hshapbcail 0 300 train
+hshawzwjkd 1 300 train
+hshlhtycxr 1 300 train
+hsholijlwo 1 300 train
+hshpnnxnyh 0 299 train
+hshpxlugwv 1 300 val
+hsibptqojw 0 300 train
+hsibzyswrs 1 300 train
+hsifzzppiu 1 300 train
+hsiigsygsc 1 300 train
+hsijefjiop 1 301 val
+hsijsvfjao 1 300 test
+hsilbuzpcn 0 300 train
+hsinbtskpx 1 300 val
+hsirdisoaf 0 241 train
+hsitpzjrmu 1 300 train
+hsivixcmnn 1 300 train
+hsiwbtszfc 0 300 val
+hsiwwzqvcd 1 300 train
+hsixqfdxqo 1 299 val
+hsiyzxpvqm 1 300 val
+hsjgvlndct 1 300 val
+hsjgxbvyqh 1 300 train
+hsjmisocpl 1 300 val
+hsjmpnlbas 0 300 train
+hsjukoflzf 1 300 val
+hsjzcuaors 1 300 val
+hskdauftwr 1 300 train
+hskevjjlzp 1 300 train
+hsklltivuk 1 299 train
+hskneimxnc 1 241 train
+hsknnlbswy 1 300 val
+hsktvjqwjh 1 300 val
+hskutsnicn 1 300 val
+hskxjddedq 1 300 val
+hskzjifsqo 1 300 train
+hslbemfams 1 300 train
+hslcjyberm 1 300 train
+hsldeiwlgm 1 300 train
+hslhjzwdzu 1 300 train
+hsllgbjitl 1 241 train
+hsllwtgadk 1 300 test
+hslupphtel 0 300 val
+hslyybugvf 1 298 train
+hsmggsiwax 1 300 val
+hsmnqtwuxv 1 300 train
+hsnbqojgis 1 301 train
+hsnctayncx 1 300 train
+hsniwapxih 1 300 train
+hsnmcigjjx 0 300 train
+hsnrffajbh 1 302 train
+hsnssaimgt 1 300 train
+hsnxxqwooq 1 301 train
+hsnyaujcts 1 300 train
+hsnzpsqxgk 1 300 val
+hsnzvojifx 0 300 train
+hsnzxixbll 1 300 train
+hsodphpjra 1 300 train
+hsoduwbwzm 1 300 train
+hsofkojctt 1 301 train
+hsokjuzfzq 1 300 val
+hsokresccb 1 300 train
+hsomnykwkb 1 300 train
+hsosrxlnzk 1 300 test
+hsoxbifzxi 1 300 val
+hsoybkvkrv 1 300 train
+hsoyzdytzb 0 300 val
+hsozhrplut 1 300 val
+hspbdjkzpf 0 300 train
+hspdmdjzod 1 300 test
+hspnfycerq 1 300 train
+hsprvfdvnq 1 300 train
+hspwrgaqys 1 300 train
+hspxkpdvdb 1 301 train
+hspzwzsccz 1 300 val
+hsqckqbicz 1 300 train
+hsqcvbedvl 1 300 train
+hsqdhntniv 1 300 train
+hsqdyrqiup 1 298 train
+hsqjaeuioz 1 241 train
+hsqkxapixk 0 300 train
+hsqopvxuyn 1 300 train
+hsqskhzmmc 1 299 train
+hsrijrunud 1 300 train
+hsrjpbooab 0 300 train
+hsrkevltqb 0 300 train
+hsrmbntnjw 1 300 train
+hsrqdsatqm 0 300 val
+hsrvahwnuw 1 300 train
+hsrvqfoaoy 1 300 train
+hsrwyhvcca 1 300 train
+hssbxyyudp 1 300 train
+hssfbfhkrg 1 300 train
+hssqqtntch 1 300 train
+hssyqheqho 1 300 val
+hstdygmlas 1 241 train
+hstinnjoqd 1 300 train
+hstipirujl 1 300 val
+hstnnnybob 0 300 train
+hstqyyjcyr 1 300 val
+hsttbgiybi 1 302 train
+hstvglyexy 1 300 train
+hstwgdzeba 1 299 train
+hstzunypun 1 300 train
+hsubmoizkf 0 300 train
+hsuflzddio 1 300 train
+hsufyncmvi 1 300 train
+hsugpxcjll 1 300 val
+hsunnwljgf 0 300 train
+hsvbimzuza 1 300 val
+hsvcukeefb 0 300 train
+hsvcyrhekj 1 301 train
+hsverfwbdy 0 300 val
+hsvjituyll 0 300 train
+hsvjjlultc 1 300 train
+hsvkvsxvsn 1 298 train
+hsvprwptki 1 300 train
+hsvtlrvoxl 1 300 train
+hsvzmghwrt 1 300 train
+hswgjnccsw 1 300 train
+hswjruahsc 1 241 train
+hswkrsvplh 1 300 train
+hsxgcnebky 1 300 val
+hsxhkffniw 1 301 train
+hsxoflrgtr 1 301 train
+hsxopdkcqn 0 300 train
+hsxpijbeji 1 300 train
+hsxrmrcaqh 1 300 test
+hsxugnjgjf 1 300 train
+hsyhgsrkqx 1 300 val
+hsyimwqmbg 1 300 train
+hsyjbopvdt 1 300 test
+hsypbkqnbk 1 143 train
+hsypgwsufp 1 301 train
+hsyvnjesxg 0 300 train
+hsywtgmbel 0 300 train
+hszesmmtxb 1 300 train
+hszghhzxas 1 300 val
+hszilbwsnx 1 300 train
+hszitlusxg 0 300 train
+hszkzproql 1 300 train
+hszpqkfsqb 1 300 train
+hszwwswewp 0 300 test
+hszxdjvyva 1 300 train
+hszyfhrdex 1 301 train
+hszyxcktnw 1 300 train
+htaciepzsy 1 300 train
+htaevbtzyq 0 301 train
+htafhiaztf 1 300 val
+htafmrgqej 1 300 val
+htajkoiyrr 0 300 val
+htaszoajhi 1 300 train
+htawfkucux 1 301 train
+htazdxshbo 1 300 train
+htbdweduob 1 300 train
+htcekgodhi 1 300 train
+htcergdpsj 1 300 train
+htcfcuwpsq 1 300 train
+htctvmxuut 1 298 train
+htcvejjghr 0 300 train
+htdbgatkbk 1 300 train
+htdbovnnfa 1 302 val
+htddezfxqh 1 300 train
+htddpavgen 1 300 train
+htdgulfxcl 1 301 train
+htdjeigyqw 1 298 train
+htdkbuepzw 1 300 train
+htdrkahwxu 1 300 train
+htdxbghbeg 1 300 train
+htdxthdsqw 1 249 train
+htecfndsrs 1 300 train
+htehelicgu 1 300 val
+htekfrsraw 1 300 train
+htelcjopzv 1 298 train
+hteouiubpz 1 300 train
+htetkwbhxn 1 301 val
+htexdzffsg 1 300 train
+htfcxeytvn 1 300 train
+htfsbfzwag 1 300 train
+htfsutxhtr 1 300 train
+htftegewhf 1 241 train
+htgdctnhec 1 300 train
+htgihstpbi 1 300 train
+htgkmsdzug 1 300 train
+htgnkivppc 0 300 train
+htgrssmdhi 1 300 train
+htgyfaawpd 0 300 train
+htgzwfyfrd 1 300 train
+hthcwyrlzb 1 300 train
+hthfejgwdy 1 300 val
+hthuorhwdn 1 300 test
+hthvckddty 1 300 train
+htiayvblns 1 298 train
+htieblsoln 1 300 train
+htifdungjh 1 300 val
+htifjggvrw 1 297 train
+htigwwgwkf 1 300 train
+htihljzvnf 1 300 train
+htiihimjnm 1 300 train
+htiiwicntu 0 302 train
+htixfnxfgt 1 300 train
+htizjegqpn 1 301 train
+htjhljtkxg 1 301 val
+htjhybnluy 0 300 train
+htjinzfcvc 1 300 train
+htjjirhvmb 0 300 train
+htjphcjbzg 0 300 train
+htkelwcies 1 300 train
+htkolkotxx 1 298 train
+htkszkediw 0 300 train
+htkvsdhotn 1 300 train
+htlabzauno 0 300 train
+htlaeanqej 1 300 train
+htlcviofbb 1 300 train
+htljbnzazk 1 300 val
+htljcljxyt 1 301 train
+htlwicryvo 1 300 train
+htlxcpesej 1 300 train
+htlytxvrxf 1 300 val
+htlzupthxc 1 300 train
+htmbvvmjig 1 300 val
+htmebockku 1 300 train
+htmgplqmlr 1 301 train
+htmmpihuxm 1 300 train
+htmqemvoqv 1 300 val
+htmqmjdfnb 1 300 train
+htnbqxsgmo 1 299 test
+htnjcermzy 1 300 train
+htnrqhmiqf 1 298 train
+htnvllkbej 0 300 train
+htofmqfrjk 1 300 train
+htogozkrax 1 302 train
+htohhxlfnl 1 300 train
+htoliupuhc 0 300 val
+htoothlges 1 300 train
+htoowvsdeh 1 301 train
+htorvhbcae 1 300 test
+htoyvdszos 1 300 val
+htpasilnpo 1 300 train
+htpazaviko 1 300 train
+htpqogltzb 1 300 train
+htpynjivdq 1 300 train
+htqfkjzpuv 1 300 train
+htqfzcytzu 1 300 train
+htqhjgthaa 1 298 train
+htqhzfwsmb 0 300 train
+htqjikasqa 1 300 train
+htqmwqohyq 1 301 train
+htqtvkygxi 0 300 train
+htqvbtsnrv 1 300 train
+htrfewqkrr 0 300 val
+htrfpzpiso 1 300 train
+htripisfqx 0 300 train
+htrjvroqvz 1 300 train
+htrkeemhkr 0 298 val
+htrmbppvvr 1 300 train
+htrnhdlzmp 1 298 train
+htrststslc 1 300 train
+htrvdkeosw 0 300 train
+htrvmgqlfi 0 300 train
+htrwxzllri 1 300 val
+htryyzhwvq 1 300 val
+htsafdfdav 0 300 train
+htshwkgqxz 1 299 test
+htsicgwcfb 1 300 test
+htsicwzxie 0 300 train
+htskueymzg 1 300 train
+htsmbosehr 1 300 train
+htsobsnpou 1 300 train
+htsoxdzdba 1 301 train
+htspgwogfa 1 300 train
+htsviqkpig 1 300 train
+htswfrgtdb 1 300 train
+httbasaevn 1 299 test
+httfjttwph 1 300 val
+httftywuok 0 300 train
+httlbbzers 1 294 train
+httluulakd 0 300 train
+htulyjcizm 1 300 train
+htutazcyqu 1 299 train
+htuvyvkovk 1 300 train
+htuxozplwj 0 300 train
+htuyhgpchq 1 300 train
+htvbzxbpmd 1 300 train
+htvgahmueb 1 300 train
+htvjcvsnkw 1 301 val
+htvowcxseo 1 249 train
+htvpaolyrq 1 300 train
+htwegmqgqo 1 298 train
+htwfgdztjj 1 299 train
+htwjhwmjum 1 300 train
+htwkhbxggy 0 300 train
+htwojuqojq 1 301 val
+htwrdfuipf 1 300 train
+htwxqemmfu 1 300 val
+htxayuikry 1 300 train
+htxbgvgatd 1 300 train
+htxbylillt 1 300 val
+htxcqpofub 1 300 train
+htxrveybse 1 300 train
+htyilrgshp 1 300 train
+htyitlyejv 1 300 train
+htyotuhbcc 1 241 train
+htyzbxdetd 1 300 train
+htzbnroagi 0 300 test
+htzcbpevhf 1 300 train
+htzhbeamrs 1 300 train
+htzhuekdqu 1 300 train
+htzjmoufai 1 300 train
+htzsauetyi 1 301 val
+htztzgkfzv 0 300 train
+huaacrmvkw 1 300 train
+huakttluoz 1 299 val
+huaqkbikyr 1 300 train
+huarxlwpki 1 300 train
+hubdpuywlj 1 300 train
+hubowsjila 1 300 train
+hubqivdhne 1 300 train
+hubsbjmmwe 0 300 train
+hubtebvzdp 1 301 train
+hubuiiwdtn 1 300 train
+hucdvvlvtx 1 297 val
+hucmdlcmdg 1 300 train
+hucmkfktfa 1 300 train
+hucqrumioa 0 300 val
+huctliifce 1 300 val
+hucyaeufqq 1 300 val
+huczrcdasm 0 301 val
+hudbucksba 1 300 train
+hudmutditr 1 300 train
+hudokvubyv 1 300 train
+hudrinvcyt 1 300 train
+hudxulcbuk 1 300 train
+huecalgvcz 0 300 train
+huecqgjncq 1 300 train
+hueermflbp 1 300 train
+huehkodwjb 1 300 train
+hueziwjubp 1 300 train
+hufdhsnfkl 1 300 test
+hufjrmsvdt 1 300 val
+hufkhirswz 1 300 train
+hufloxjssp 1 300 train
+hufmsorauj 1 300 val
+hufnwjsrry 1 300 train
+hufrooewfp 1 300 train
+hufshaglij 0 300 val
+hufyuzjiqm 1 300 train
+hufywdzltd 1 300 train
+hugafjqxql 1 300 train
+hugbzjpphk 1 300 train
+hugcokpuks 0 301 train
+hughpmydui 1 300 train
+huglgatpjc 1 300 train
+hugopxwqks 1 300 train
+hugqprznix 1 300 train
+hugwkuprvy 1 300 val
+huhgawkazc 1 300 train
+huhwegsrhh 1 300 train
+huhxclvymi 1 300 train
+huhxwuihzm 1 300 train
+huhzgargtz 1 300 val
+huhzyknoqo 1 300 val
+huilclfbeo 1 241 train
+huilufzozs 0 300 train
+huiqdkxjuu 0 300 train
+huirsgmbxy 1 300 train
+huiydckiil 1 298 train
+hujddswvon 1 300 train
+hujfimxiqi 1 301 train
+hujkogevzs 1 300 train
+hujliesifc 1 300 val
+hujmromlkd 1 300 train
+hujnpmnccn 1 300 train
+hujqhjtxub 0 300 train
+hujtdohszu 1 300 train
+hujxdgarto 0 300 train
+hukcsnotdh 0 300 train
+hukhzzntwr 1 300 train
+hukqcbfyac 1 301 val
+hukttnllxr 1 300 val
+hukzodijmp 1 300 train
+hulaxwolns 1 300 val
+huldrslrzm 1 300 val
+hulfidzhmi 1 300 train
+hulmljcvnq 1 300 val
+hultmvgwuw 1 300 val
+humawcyddv 1 300 test
+humbrhuzib 1 299 val
+humjligfru 1 300 train
+hunpbscjol 0 300 train
+huntakrfzp 1 300 train
+huoaqoftqs 1 300 train
+huoctrfnxd 1 300 train
+huodbvioih 1 300 train
+huofjvzwhq 1 300 train
+huofsuikoh 1 300 train
+huohybpcej 1 300 train
+huontkxnwo 0 300 train
+huooilisxl 1 300 train
+huoueercpo 1 300 val
+huoutrlske 1 300 train
+huouxztjql 1 301 train
+huowmqotqo 0 300 val
+huowsesgyq 0 301 train
+hupbgcxpua 1 298 train
+huptbsadro 1 300 train
+huqakotbhk 1 300 train
+huqivatfln 1 300 train
+huqiyangsh 1 300 train
+huqwqfreju 0 300 train
+huqzdmjffm 1 301 train
+hurcutcxpb 1 300 test
+hurkbqomnl 1 300 val
+hurkpwpped 1 298 train
+hurlxdpsxl 1 300 train
+hursubdtvz 0 300 train
+hurvjbckrw 1 300 train
+hurylpugkq 1 300 train
+hurysmfmyk 1 300 val
+husdjoozno 1 300 train
+huseuftnbp 1 300 train
+husjiayjyg 1 300 train
+husohxnjmx 0 300 train
+huspcwuyuw 1 300 train
+husqkubqdp 1 300 val
+husskehtel 0 300 train
+huswpbjznr 1 300 train
+husyyhazww 1 300 train
+hutgcooycl 1 300 val
+hutlisfmkg 1 288 train
+hutptbtqce 1 300 val
+huttcrbevu 1 300 val
+hutztepdmq 1 300 test
+huucvrfcfm 1 300 train
+huuebfmqec 1 300 train
+huuguibhfq 1 299 test
+huunzskqhw 1 241 train
+huuupjzrru 1 300 train
+huvaxatous 1 301 val
+huvdiotphl 1 301 train
+huvgomcylt 1 301 train
+huvhqnpmqi 1 298 train
+huvlwkxoxm 1 299 test
+huvmpblgyw 1 300 train
+huvtkwaxfw 1 300 train
+huwetbwqtr 1 300 val
+huwfwwjxyz 1 300 train
+huwkcjiwsh 1 300 train
+huwnwjdhgy 1 300 train
+huwwdxvmdt 1 300 train
+huwwwnseqa 1 300 train
+huwyndrnfv 0 300 train
+huxbvygywp 1 301 train
+huxgkyluod 1 300 train
+huydwoggco 1 300 train
+huyhgvpxrh 1 300 train
+huyikpryex 1 300 train
+huylufxiwc 1 300 val
+huyniwuhqe 1 300 val
+huypfznxby 1 300 train
+huypjdisot 0 300 train
+huyrbnasiv 1 300 train
+huzaqiagsc 1 300 train
+huzbsdifgi 1 300 val
+huzehsqvkj 1 300 train
+huziaxyqrn 1 300 train
+huzmagmeaq 1 301 train
+huzmujbsnn 1 300 val
+huznbaakma 1 300 test
+huzpmegfxj 1 300 train
+huzryvwrfa 0 300 train
+huztmpuepl 1 255 train
+huzxqvskyv 1 300 train
+hvacequemz 1 300 train
+hvahfziabq 1 300 train
+hvajujwuez 1 300 train
+hvalvoklqf 1 300 train
+hvalxdyjdz 1 300 train
+hvasszicyv 1 300 train
+hvaxdtxhot 1 300 val
+hvayvsrcxg 1 300 train
+hvbawyfkhi 1 300 train
+hvbbizddfc 0 300 train
+hvbfbdqdin 1 300 train
+hvbjxkgwnj 1 300 train
+hvbmcbeoed 1 300 val
+hvbncqsyez 1 300 train
+hvbnkquhzl 1 301 train
+hvbnoppmsd 1 300 train
+hvclykinmg 1 300 train
+hvcrcfujni 1 300 train
+hvcrijmhlj 1 300 train
+hvcsvvgrjf 1 300 train
+hvcxqgiwfe 1 300 val
+hvdamhdnvs 1 298 train
+hvddxkjpgm 1 300 train
+hvdfepipit 1 298 train
+hvdftuozuk 1 300 train
+hvdkiikndg 0 300 train
+hvdoehnjwf 1 298 train
+hvdpvcwgmc 1 300 train
+hvdvaeewcs 1 241 train
+hvdzfiymqx 1 300 train
+hvefzshjxl 1 83 train
+hvehlbocza 1 300 val
+hveicxbnbb 1 300 train
+hveiymonlx 0 301 train
+hvesrsnrtl 1 300 train
+hvevyvwnvf 1 300 train
+hvewlnratj 1 300 train
+hvexbfyvzy 0 300 train
+hvfgnmjmvl 0 300 train
+hvfjmgljxq 1 298 train
+hvfqvfqapt 1 300 train
+hvfuvjqdrv 1 300 train
+hvgisfbzqn 1 300 train
+hvgokdtdla 1 300 train
+hvgvjintyv 1 300 train
+hvgwvloonr 1 300 train
+hvhbmncfac 1 301 train
+hvhcavmfnp 1 300 train
+hvhduzbzjw 1 301 train
+hvhmhheuwm 1 301 train
+hvhpbvufmd 1 241 train
+hvhrlowtzh 1 299 val
+hvhwqugoxu 1 300 train
+hvierltlmq 0 300 train
+hvifqweyxx 1 300 train
+hviqqtqgll 1 300 train
+hvizhucxwb 1 300 train
+hvizpibrvb 0 300 train
+hvjbloelaj 1 300 val
+hvjkwcpqxi 1 300 train
+hvjmzqujjd 1 300 val
+hvjqbrktfn 1 300 train
+hvjqitobbi 1 300 train
+hvjxqjjucv 1 300 train
+hvkcuhyedq 1 300 train
+hvkmqifunx 1 299 val
+hvkramhcmx 1 301 train
+hvkuzvtulc 1 300 train
+hvkwauqizl 0 300 train
+hvkwnouqnx 1 300 train
+hvkwqeaczn 1 300 train
+hvkwthwurb 1 300 train
+hvlffssemo 1 300 train
+hvlgjwfnrp 0 300 val
+hvlibyiuqn 1 300 train
+hvljrxrybz 1 300 train
+hvlqewtbbf 1 300 test
+hvltyzhgkk 0 298 val
+hvlwyjgnxb 1 300 val
+hvmbirnoyr 1 300 train
+hvmcslpaeu 0 125 val
+hvmeswenxv 1 300 val
+hvmllpuucc 1 300 val
+hvmnipolza 1 300 train
+hvmpghzrwc 1 299 test
+hvmzimtrdq 1 300 test
+hvngotpack 1 300 val
+hvnhuymltm 0 300 train
+hvnoosojzi 1 300 train
+hvnpkshbdt 1 300 train
+hvntivbqxx 1 300 train
+hvnwmcupjm 0 300 train
+hvnzcewcvn 1 300 train
+hvnzdsvkpa 1 300 train
+hvojagkpwu 1 300 val
+hvopzymymu 0 300 val
+hvoqbqkjct 1 300 train
+hvpdrefmgp 1 300 train
+hvplvgwjzt 0 299 train
+hvpmnfpruw 1 300 train
+hvpmxjsjus 1 298 train
+hvqbywtguq 0 300 train
+hvqcxprjni 1 300 train
+hvqfhieetb 1 300 test
+hvqfyaxyfj 1 300 train
+hvqkdxqdoz 0 300 train
+hvqmkyrggf 0 300 val
+hvqogmonqi 1 300 train
+hvqyqdksse 1 300 train
+hvrbzohjij 1 300 train
+hvrfcrstef 1 300 val
+hvrgycaimh 1 300 train
+hvrimcezcx 1 300 train
+hvrkqpjkkr 1 298 train
+hvrogfypmt 1 300 train
+hvrosyxjgu 1 300 train
+hvrqacacno 1 300 train
+hvrtqxcgue 1 300 train
+hvrxpqeajh 1 300 train
+hvsbcrovbh 1 300 val
+hvshaelzle 1 300 val
+hvshykjvwt 0 300 train
+hvsoudzqfb 1 300 train
+hvsrsmixku 0 301 val
+hvsrsstpkd 1 300 train
+hvsrydchnd 1 300 val
+hvswiniaqh 1 300 train
+hvtlrmtbdd 0 300 train
+hvtsyiuvcn 1 300 val
+hvtuxtpnrm 1 300 train
+hvtwdrgecq 1 99 train
+hvtwtohuor 1 300 train
+hvtxdhpuca 0 300 train
+hvuhsugadn 1 300 val
+hvuwlxvfrj 1 302 train
+hvuxhtdbqf 1 300 train
+hvvcnzkkoo 1 300 val
+hvvearwuya 1 300 train
+hvvemhbopa 1 300 train
+hvvohsysmz 1 301 train
+hvwftkrfnx 1 300 train
+hvwgiotrdg 0 300 train
+hvwhxjmzwo 1 297 val
+hvwhzywmoo 1 296 train
+hvwikhejpy 1 300 train
+hvwjusgspd 1 300 train
+hvwvlssmck 1 300 train
+hvwvmzjplp 1 299 test
+hvxbzwetvm 1 300 val
+hvxjasnvvm 1 300 val
+hvxjjbvcwj 1 300 train
+hvxlokkbzn 0 300 val
+hvxmvczeqx 1 300 train
+hvxowxojnn 1 300 val
+hvxpmiyzpl 1 300 train
+hvxrsfgvyi 1 300 train
+hvxwzlacgc 1 300 val
+hvybuiicjz 1 300 val
+hvycxkeirv 1 300 train
+hvyevrpeyc 0 300 train
+hvyhhgtkpb 1 300 train
+hvykqvaizw 1 300 train
+hvylbewzaa 1 300 train
+hvyounzkku 1 300 train
+hvywucdzbt 1 300 val
+hvzajwcacs 1 300 train
+hvzaljnunu 1 300 train
+hvzboteugl 1 301 train
+hvzbxqeisd 1 300 train
+hvzgxiwlwk 1 300 train
+hvznknkjvq 1 300 train
+hvzoeiqyqe 1 300 train
+hvzthfduhp 1 300 train
+hwafeitigg 0 300 val
+hwaghurvci 1 300 train
+hwanpwgjob 1 299 test
+hwapuqrvfb 1 300 train
+hwaslzerct 1 300 train
+hwaxcxpfxl 0 300 val
+hwaxeetxfy 1 298 train
+hwaznlylcp 1 300 train
+hwaztbnqic 0 300 val
+hwbamkeoqd 1 300 val
+hwbcdlwjoc 1 300 train
+hwbjpxfjcc 1 301 train
+hwbnghhfsz 1 298 train
+hwbnnzmcos 1 300 train
+hwborqafnv 1 300 train
+hwbqxawuhk 1 301 val
+hwbupatirc 1 300 train
+hwcadwarqe 1 298 train
+hwckmbvupn 1 300 train
+hwcnsgqzld 1 300 test
+hwcpigcjqz 1 298 train
+hwcpjaebpn 1 300 train
+hwcplmkglv 1 300 train
+hwcrgnzkyv 1 296 train
+hwcrhxtsps 1 300 train
+hwcxmkbfnh 1 300 train
+hwdclpevyd 0 300 train
+hwdhqsdxvu 1 300 val
+hwdhtsbgbd 0 300 train
+hwdlruplpx 0 300 train
+hwdrfenilf 1 300 test
+hwdtbuwkdt 1 300 val
+hwdusdxcsj 1 300 train
+hwebhgutkf 1 300 train
+hwebmdbypc 1 298 val
+hwebzjktum 1 300 val
+hweedlhhgu 1 301 train
+hwepjtfgdu 1 300 val
+hweshqpfwe 1 299 test
+hwffjtznrd 1 300 train
+hwfgwmuuby 1 300 train
+hwfjnngetb 1 298 train
+hwfnbfscmk 1 300 train
+hwfpdkxckq 1 300 train
+hwfpjrkevf 1 300 val
+hwfvcvfixd 1 300 train
+hwfvxqqadm 1 300 train
+hwgbkoswda 1 300 train
+hwgcxllypa 1 300 train
+hwgdtucbck 1 242 train
+hwgfkwzkgx 1 299 val
+hwgiyjqlmw 1 301 train
+hwgocohpcc 1 301 train
+hwgqgirdyc 1 299 train
+hwgvcwpzod 0 300 train
+hwgyszfbcc 1 300 train
+hwhisnljug 1 300 train
+hwhjseuxws 1 301 train
+hwhkqfqcme 1 301 val
+hwhqtnxdsd 0 300 train
+hwhroraoho 1 300 train
+hwhyxsfdac 1 300 train
+hwibtynenh 1 300 train
+hwikaqewiq 1 147 train
+hwikdqslop 1 300 train
+hwipsjeujj 1 288 train
+hwirhirkne 0 300 train
+hwixlgkbjk 1 298 train
+hwixlpyhpe 1 300 train
+hwjehqzikx 1 300 train
+hwjferthaq 1 301 val
+hwjfhkzrtm 1 300 train
+hwjikyfwlm 0 300 val
+hwjkdmwrce 1 300 train
+hwjkxkreht 1 300 train
+hwjlcdwuyq 0 300 train
+hwjqfepxmx 0 300 train
+hwjwlaitvb 1 300 val
+hwjyutuyee 1 300 train
+hwkcwhwgix 1 300 train
+hwkkhcwflx 1 300 train
+hwklwhlahc 1 300 train
+hwkohghpbg 1 300 val
+hwkplisvwe 1 300 train
+hwkvktpown 1 300 val
+hwletaajjm 0 300 train
+hwlguhxffo 1 299 train
+hwlizlhzjj 0 299 train
+hwlkfpodnl 1 300 val
+hwlpwwhgmq 1 300 train
+hwlstynhqa 1 300 train
+hwltoeeilr 1 300 val
+hwlwjbtrzq 1 301 train
+hwmbdrmueb 1 300 train
+hwmeqvocvl 1 300 train
+hwmittznsy 1 300 train
+hwmmfqsxjm 1 300 val
+hwmnvvlubg 1 300 val
+hwmotqkotc 1 298 train
+hwmpwaennr 1 300 train
+hwmqannjgh 1 300 train
+hwmwyhtoqf 1 300 train
+hwmxbzyukd 0 300 train
+hwmybqyceh 1 300 train
+hwnanpkeja 1 300 train
+hwnavovbnf 1 300 val
+hwncvqjgkz 1 300 train
+hwngbjfiit 1 300 train
+hwnixjcyum 0 300 train
+hwnjtjicpg 1 300 train
+hwnkfzaidm 1 300 train
+hwnmkmvzfo 1 300 train
+hwnxvgfkjj 1 298 train
+hwocmokpis 1 301 train
+hwofkxxmyw 0 300 val
+hwojndppmu 1 298 train
+hwosevumoe 0 300 train
+hwotptaaxc 1 300 train
+hwoxyvspab 1 299 train
+hwpjnhtgcz 1 300 train
+hwpkcfgqbk 1 300 train
+hwplegxife 1 300 train
+hwpminyase 1 300 train
+hwppmcjfby 1 300 train
+hwqatepsyz 1 300 test
+hwqjcjpxcj 1 301 train
+hwqkgqmrkj 1 300 train
+hwqmdqroas 1 300 train
+hwqnigucxn 1 300 train
+hwqukcelrx 1 300 train
+hwqworxmut 1 300 train
+hwqyesugdf 1 300 train
+hwrgbbswlw 1 300 train
+hwrszcocvq 1 300 val
+hwryksrowe 1 300 train
+hwsdbanwth 1 300 train
+hwsgjnslze 0 301 train
+hwsneitzms 0 300 train
+hwsnetsqja 1 240 val
+hwsnwtlwdw 1 300 val
+hwspklkjol 1 301 train
+hwspkutmjr 1 300 train
+hwsqxlbtgc 0 300 val
+hwssfxdbbv 1 300 train
+hwszxmhues 1 300 train
+hwtblpicrm 1 300 train
+hwtbygihfd 1 300 train
+hwtgwmfxyz 1 300 train
+hwtjiitwwe 1 300 train
+hwtnalvalq 1 300 train
+hwtnwtczts 1 300 train
+hwtrzrxkyg 1 300 train
+hwtupajxgl 1 300 train
+hwtzyhdztg 1 301 train
+hwuavdwztw 1 300 train
+hwufwjdaai 1 300 train
+hwujekvhzx 0 300 train
+hwuksjmpvu 1 300 train
+hwuosegups 1 300 train
+hwupzqblgo 1 300 train
+hwutftrpog 1 298 train
+hwuwqbesox 1 300 train
+hwuxekhvmb 1 300 train
+hwvojrzppr 1 300 train
+hwwazyhcss 1 300 val
+hwweeeqkll 1 300 train
+hwwgutdbcg 1 299 val
+hwwirlqjuh 1 300 train
+hwwmhwkdhb 1 300 train
+hwwmwwteag 1 300 val
+hwwvfiufic 1 300 train
+hwwxhtdlpv 1 300 train
+hwxamzrdaw 0 300 train
+hwxfocncgq 1 300 val
+hwxfrashko 1 300 train
+hwxljxqzsg 1 300 train
+hwxmkvonpv 1 298 train
+hwxninlffv 1 300 val
+hwxquijekn 1 300 train
+hwxtdslpqu 1 300 train
+hwxudyevzb 1 300 train
+hwyguzgmzq 1 300 train
+hwygwlbyev 1 300 train
+hwyhleldui 0 300 val
+hwykkcvafb 1 300 train
+hwylcvyuxp 0 300 train
+hwypebukel 1 300 train
+hwyuwbnszo 1 301 train
+hwyvbtuvoe 1 300 train
+hwyxvsdfkw 1 300 train
+hwzgzczzei 1 292 train
+hwznudbaan 1 300 train
+hwzqeodegs 0 300 train
+hwzswotvpc 1 300 train
+hwzvkbairy 1 300 train
+hxadmqihjf 1 300 train
+hxaggobmxu 1 301 train
+hxahnhbnrz 0 300 train
+hxajptmitv 1 300 train
+hxamrqjjwm 0 300 train
+hxamxpcqwh 1 300 train
+hxaqmnvrpv 1 297 train
+hxarxkddri 1 300 val
+hxatwclonw 1 300 val
+hxbhaudsor 1 300 val
+hxbklovyme 1 300 train
+hxbtxphmom 1 300 train
+hxburehncr 1 300 val
+hxbxfxyrsn 1 300 train
+hxcazozhqo 0 300 train
+hxcdmlbbfj 1 300 train
+hxcejljpta 1 300 train
+hxcmjpjgul 1 300 train
+hxcusgkfvy 1 300 val
+hxcxlparkz 1 300 train
+hxdazpagbv 1 300 train
+hxdczonuvi 1 300 val
+hxddpnvklf 1 300 train
+hxdggdclkc 1 300 test
+hxdktprbdm 1 300 train
+hxdmqncidx 0 300 train
+hxdovenkiu 1 301 val
+hxdwnxdlfn 1 300 train
+hxebjpamjl 1 299 test
+hxeiexrdrq 1 300 val
+hxenojahiu 1 298 train
+hxeoyyprkh 1 300 val
+hxesfgcqgu 0 300 train
+hxestavvje 1 300 train
+hxeufhxyeb 1 300 train
+hxewjezhlo 1 300 train
+hxfbxeudpd 1 300 train
+hxfcpyxovk 1 300 train
+hxfnbqzjas 1 300 train
+hxfoblypgu 0 300 val
+hxfqltenqh 0 301 train
+hxfspqumyf 0 300 val
+hxfsvapfvk 1 300 train
+hxftyaqumq 1 300 train
+hxfyzpnwgd 1 300 train
+hxgaaatora 1 301 train
+hxgamtaldj 1 300 train
+hxgcefsums 1 300 train
+hxghoyrqnv 0 302 train
+hxgksvlkpw 1 300 train
+hxglgkkwwr 1 301 val
+hxgmozlftr 1 300 train
+hxgqkqtcwy 1 300 train
+hxgunwwczp 1 299 val
+hxgvckxrzo 1 301 train
+hxhietagta 1 301 train
+hxhkbqrvbc 1 300 val
+hxhpvravqj 1 300 val
+hxhqqdtdeg 1 300 train
+hxiboyszmp 1 298 train
+hxijwdmltd 1 300 train
+hximypqplj 1 300 train
+hxioqgxsrx 1 300 val
+hxipakgdqj 1 300 train
+hxixbghgxj 1 300 train
+hxiysfxcfj 1 300 train
+hxiznixypa 1 300 train
+hxjfcgpcgc 1 301 train
+hxjojmcmvb 0 300 train
+hxjtvdfgsq 1 300 train
+hxjwywtwmb 1 300 train
+hxkbvntxub 1 300 train
+hxkewzrwjo 1 300 val
+hxkqibwvoq 1 300 train
+hxlfrcdwqh 1 300 train
+hxlftemwwg 1 300 train
+hxlhdlfypc 1 300 train
+hxlmrfuklu 1 301 train
+hxlornwuct 1 300 train
+hxlrqvdokn 0 300 train
+hxmbrkjxvz 1 298 train
+hxmgitnzsb 1 300 train
+hxmwbpwwlv 0 300 train
+hxmxgwqxtv 1 300 train
+hxnedyumwi 1 300 val
+hxnkaxuabq 0 300 val
+hxnmphbcdz 1 300 train
+hxnqkxqtps 1 301 val
+hxnsftkdkg 1 300 train
+hxnvptlgcu 1 300 train
+hxofsiydpl 1 300 train
+hxorjqfecw 0 300 train
+hxotyaburr 1 300 train
+hxoxbuurut 1 300 train
+hxoxcbjoyu 1 300 train
+hxperjvebs 1 300 train
+hxpkxzoseq 1 300 train
+hxptodkldl 1 298 train
+hxpvedmdej 0 300 train
+hxqerdrvpb 1 300 train
+hxqkgjannv 1 300 train
+hxqolncuso 1 300 train
+hxqqnbdlaj 1 300 train
+hxqsvmeovs 1 300 train
+hxquvldued 0 300 train
+hxqwmqlver 1 301 train
+hxqzlyumcg 1 300 val
+hxrckqklrs 1 300 train
+hxrduudydx 1 300 train
+hxrlyivxvh 1 300 train
+hxrpakcytg 1 300 val
+hxrruqinnh 1 300 val
+hxrsputvso 1 300 train
+hxrxsmlmfg 1 300 train
+hxrylbfueu 1 300 train
+hxrzxtizic 1 300 train
+hxsnyyrgwo 1 300 val
+hxsoasfjjw 1 300 val
+hxsuisonbd 1 299 test
+hxtbjnymee 1 300 train
+hxtdygilhn 1 299 test
+hxtnpcdaum 1 300 train
+hxtrlysibt 0 300 train
+hxtryetzjf 0 300 val
+hxtxahjitb 1 300 val
+hxuakqdpin 1 300 val
+hxualhnacg 1 300 val
+hxuegrmiyl 1 301 train
+hxuhotkfuf 0 300 val
+hxuijnzfvw 1 300 train
+hxuklgnuhr 1 300 test
+hxulclhueu 1 300 train
+hxupravjmo 1 298 train
+hxuqmzzofo 1 300 train
+hxurijguyl 1 300 val
+hxutvmudyl 1 300 train
+hxuxgbgkem 1 300 train
+hxvqvnqwwb 1 300 train
+hxwhmvkhjy 1 296 train
+hxwlnodvuq 1 300 train
+hxwmoxkqsw 1 300 val
+hxwpxdlxli 1 300 train
+hxwqxxgarw 1 300 val
+hxwtsaydal 1 300 test
+hxwuxgrlvd 1 300 train
+hxwzblwhdi 1 300 train
+hxxcapoekv 1 300 train
+hxxcsuzjqx 1 300 train
+hxxigqqkkh 1 298 train
+hxxjbpqqxm 0 300 train
+hxxjoiyqqv 0 300 train
+hxxofqrrue 1 300 val
+hxxulzaweo 1 300 train
+hxyhoufgrm 1 300 train
+hxyjzvavtf 1 298 train
+hxypfqptoe 1 299 train
+hxysdgxzkf 1 300 val
+hxyvwylxuv 1 241 train
+hxywqhgdyw 1 298 train
+hxywvspdgi 1 300 train
+hxzczdbibf 0 300 train
+hxzftbkedt 1 300 train
+hxzhvrhlfs 0 300 train
+hxzrcnpxgc 1 300 train
+hxzroxxgku 1 300 train
+hxzxevdgds 1 300 train
+hyaaaahdvu 1 300 train
+hyaabcnwum 1 300 train
+hyacxfznfc 1 300 train
+hyadctzndk 1 300 train
+hyaejsntoh 1 300 train
+hyafqbzgin 0 300 val
+hyafqmjxaw 1 300 train
+hyaicsqrnu 1 300 train
+hyaiiedtds 0 300 train
+hyalywahqn 1 300 train
+hyamgqummb 1 300 train
+hyaoeiownm 1 300 train
+hyappmoicg 1 300 train
+hyauobpnrp 1 300 train
+hybbdegxvk 1 300 train
+hybjfytvwo 0 300 train
+hybjprdxoh 1 301 val
+hybjzdrttb 1 301 train
+hybocopfwt 0 300 val
+hybopwbigm 1 300 val
+hybvuhzfbd 1 300 train
+hybyghawhg 0 300 val
+hyccvqwurc 1 300 train
+hycdczdeby 1 300 train
+hycihhjjzq 1 300 train
+hycnfiwquc 1 300 train
+hycuregsmv 1 300 train
+hycvcywqid 1 300 train
+hycweezicc 1 241 train
+hycxhvuwnl 1 298 train
+hycxwtokhl 1 300 val
+hydlrfzhjs 0 300 train
+hydyelbqjl 1 301 train
+hydytyakzr 1 269 train
+hyefliglvt 1 300 train
+hyeotskpuk 1 300 train
+hyeppmhceo 1 300 train
+hyesgtzimm 1 300 train
+hyetimeyst 1 300 val
+hyetubeika 1 301 train
+hyexlyouqy 1 300 val
+hyfazmeacv 1 300 val
+hyfdmkfuyr 1 300 val
+hyfhezuhgh 1 300 train
+hyfljfjzqc 0 300 train
+hyfqoshdyz 1 300 val
+hygawiggdh 1 301 train
+hygeirbptu 1 301 train
+hygximjjnw 1 300 train
+hygythymkx 1 300 train
+hyhczxthrs 0 302 train
+hyheeyffxt 1 300 train
+hyhfqvyfsj 1 300 train
+hyhhstwjlc 0 300 train
+hyhjfdxqxy 0 300 train
+hyhluclhuy 1 302 train
+hyhntnfids 1 239 val
+hyhoeteudn 0 300 train
+hyhohlppvg 1 300 train
+hyiasqivcp 1 300 train
+hyihnzrlex 1 300 val
+hyiigyjbmd 1 300 train
+hyimplklmb 1 299 train
+hyisqrjnki 1 300 val
+hyizhsdahl 0 300 train
+hyjbsteleq 1 300 train
+hyjedkriqd 0 300 train
+hyjgfchlnr 1 288 train
+hyjmitpidr 1 300 val
+hyjmkdgxsa 1 300 train
+hyjqolupxn 1 300 test
+hyjuqxwhqm 1 297 train
+hyjwstohbs 1 298 train
+hykhlwchzt 1 300 train
+hyklczpocv 0 301 val
+hykoiqkbcv 0 300 train
+hykupxvaxj 1 300 train
+hykuyowagg 1 298 train
+hykwehvlji 1 300 train
+hylafdnuym 1 300 train
+hylcelylvd 1 300 train
+hylhabqxpy 0 300 train
+hyliepneal 1 301 train
+hylimfhykk 1 300 train
+hylmyxkwlh 1 300 train
+hylnohbbxl 1 298 val
+hylqmhztng 1 300 train
+hylqrqzrpx 1 300 val
+hylvpzoqpn 1 301 train
+hylwcsnthh 1 301 val
+hylwhwrylr 0 300 train
+hylzxlfyus 0 300 train
+hymahjaygt 1 300 val
+hymjbylhfd 1 300 train
+hymmhbbrhq 0 300 val
+hymqlcdqoa 1 298 train
+hymsjxkymd 1 300 train
+hymsuxbjzk 0 300 train
+hymwuaomiw 0 300 train
+hymzlzvlel 1 300 train
+hynagulpwz 1 300 train
+hynowuipao 1 300 val
+hyobhrteab 1 302 train
+hyocoomhzc 1 300 train
+hyoesmcweq 0 300 val
+hyomyjkodg 1 300 train
+hyorsobehy 1 300 train
+hyowybfrwg 1 301 train
+hypfsxpgbj 1 300 train
+hyplsbyobm 1 300 train
+hypozprqhm 1 299 val
+hyqbbmapvb 0 300 train
+hyqhqaosfl 0 300 train
+hyqkslwjkp 1 241 train
+hyqnbsrinc 1 300 train
+hyqomxgzrg 1 300 train
+hyqpaqnmpv 1 301 train
+hyqszrnkhz 0 300 val
+hyqxxshotc 0 300 val
+hyreyuokmf 1 300 train
+hyrfzhhgre 1 300 train
+hyrhddtayk 0 300 train
+hyrnfmanrm 1 300 val
+hyrufbafyc 1 300 train
+hyrufgigck 0 300 train
+hyrugmqhbc 1 300 train
+hyrukzufoy 0 300 val
+hyrxbwbabi 1 299 train
+hyrxucfjxc 1 300 train
+hyrzbinpsc 1 300 val
+hysbryfimx 1 300 train
+hyseabpjdt 1 300 train
+hyslgvtpfg 1 300 train
+hysmzkqsdl 0 300 train
+hysppsmhpl 1 301 train
+hytbqnvoqk 1 300 train
+hytcfohlkv 1 300 train
+hytdcdixlv 1 300 train
+hytkciqjko 1 300 train
+hytlmwbunx 1 300 train
+hyttoovsnk 0 300 train
+hytvxdgwth 1 300 train
+hytzleqzdw 1 300 train
+hyucuncoci 1 301 val
+hyuipchisa 0 300 train
+hyukhkwhtn 0 300 train
+hyukhxrjsp 1 300 train
+hyumhlxnqs 1 300 train
+hyuqqlteky 1 300 val
+hyuunmfnxk 1 300 val
+hyvbliiing 1 298 train
+hyvdeycnfy 1 300 train
+hyvdtasvvc 1 300 train
+hyvshlngvm 1 300 train
+hyvynxmsfd 0 300 val
+hywhmkmlxt 1 301 train
+hywieulrhl 1 300 train
+hywkqvcsdh 1 299 train
+hyxbgxnsvz 0 300 train
+hyxfugmowu 1 300 train
+hyxisixfaf 1 300 train
+hyxtavuhga 1 300 val
+hyxwqqhbtb 1 300 train
+hyyeacnney 1 300 train
+hyylxcyelg 0 301 train
+hyytnerzru 1 300 train
+hyytqwxhei 1 300 val
+hyzeitilgy 1 300 val
+hyzjslobpp 1 300 train
+hyzlklnpvv 1 300 train
+hyzoxkmcdr 1 300 train
+hyzrzrmpab 1 300 val
+hyzsjvzznt 1 300 train
+hyzulcglvv 1 301 train
+hzacynzkcu 1 300 train
+hzamveydwi 1 299 train
+hzaslzhlkx 0 300 train
+hzbaohyuer 1 298 val
+hzbgxulnxz 1 300 train
+hzblrhnitq 1 300 train
+hzbqvxidoa 0 300 train
+hzbsbaxhyb 1 300 val
+hzbuabrbvf 0 300 train
+hzbvainuxg 1 300 val
+hzbydejarq 1 300 train
+hzbyrwhuao 1 297 train
+hzcbfuzbus 1 300 train
+hzcuauheoy 1 300 train
+hzcxcpeeqo 1 300 train
+hzddssvylu 1 300 train
+hzdjhzclma 1 300 train
+hzdkasgymo 1 300 train
+hzdlpbgapx 1 240 train
+hzdqbraqnt 1 301 val
+hzdrsuebsu 1 300 train
+hzdxymoiyl 1 300 train
+hzeanfiuqe 1 241 train
+hzeaubwgis 0 300 train
+hzeavpvgjf 1 300 train
+hzekfdzgki 1 300 train
+hzeknxbgrp 1 300 val
+hzelevuaaj 1 300 val
+hzenyppzrf 1 300 val
+hzeqgckwyg 1 300 train
+hzessrlmik 1 300 train
+hzfamqikcs 1 300 train
+hzfceovkix 1 301 val
+hzfotylcxo 1 297 train
+hzfozlzdnz 0 301 train
+hzfsobmyqx 1 300 val
+hzfymkaibp 1 300 train
+hzfymxkkbj 1 300 train
+hzgdcosrcx 1 300 train
+hzgtrzyuld 1 300 train
+hzgxbdmeaf 1 300 val
+hzhjhnaabg 1 298 train
+hzhlyfzngf 1 301 train
+hzhpfomgqf 1 300 train
+hzhpgrzqxz 1 300 train
+hzhpkfynsu 1 300 train
+hzhqjbrmui 1 300 train
+hzhqwtkwwq 1 300 train
+hzhuilctfp 1 300 val
+hzhvexzokl 0 300 train
+hzhwgieazk 1 300 train
+hzhzdnbwnr 1 300 train
+hzicpspcan 1 300 train
+hzicugvreh 1 300 train
+hzidewmuub 1 300 train
+hzinugqapj 1 299 train
+hziwzozche 1 298 train
+hzizltbggv 1 300 val
+hzizolqfbh 1 300 train
+hzjffznowa 1 299 val
+hzjmslmkue 1 300 train
+hzjocpqdjd 1 300 train
+hzjoljnatn 1 300 train
+hzjpgjgtar 0 300 train
+hzjtnwptry 1 300 val
+hzjunvkstz 1 300 train
+hzkixhuppm 0 300 train
+hzkpbreqrt 0 301 train
+hzkpyvitkj 1 300 train
+hzkrcmfmkq 0 299 train
+hzkxlsfxbk 0 300 train
+hzkyojocmm 0 300 val
+hzkzlxqnpv 0 300 val
+hzlfdbtbau 0 300 train
+hzlfpkujvr 1 300 train
+hzlitwzkhf 1 300 train
+hzmellkdvz 1 300 train
+hzmhezkxsf 1 300 train
+hzmluaqjcf 1 301 train
+hzmppzxsuy 1 300 test
+hzmsqetqmn 1 300 val
+hzmsvsidas 1 300 train
+hznaljgdzc 0 300 train
+hznfbjfbgw 1 300 train
+hznhjtsqfh 1 299 train
+hznmrjbckp 1 301 train
+hznsgfmfvj 1 300 train
+hznwyqvsjj 1 300 train
+hznxfdjjsa 1 288 train
+hznxtpvnbv 1 300 train
+hzoajqujew 1 300 val
+hzoccorwwg 1 301 val
+hzodvanwcl 1 301 train
+hzogjayovj 0 300 train
+hzohyyrfdj 1 300 val
+hzoiotcykp 1 300 test
+hzojxxuvop 1 300 val
+hzonqlwzzo 1 296 val
+hzoqergxyh 1 300 train
+hzorbwpaey 1 301 train
+hzoyngiaoz 1 300 val
+hzozmgrukv 1 300 val
+hzpeccyres 1 298 train
+hzpezehigs 1 300 train
+hzpfuyhudl 1 300 train
+hzphpwrwic 1 300 val
+hzpjegobrw 1 300 train
+hzqboibbui 1 300 val
+hzqfvgcqiy 0 300 train
+hzqsniwvsj 1 300 train
+hzqwopfnzl 1 300 train
+hzqykxkjic 1 300 train
+hzrlcndrek 1 300 train
+hzrnxusemq 1 300 val
+hzrwabllda 1 300 train
+hzsatqfihy 0 300 train
+hzskhvqeic 1 300 train
+hzsngctjjq 1 298 val
+hzsparxotj 1 300 train
+hzssdinxec 1 300 test
+hzssesksot 1 300 train
+hzssvhwqty 0 300 train
+hzstrkmhvx 1 300 train
+hzsywornrw 1 299 test
+hztbmcwvxl 1 301 train
+hztckasqpy 1 300 train
+hztewxsvwg 1 300 train
+hztfhwglfn 1 300 val
+hztmimcqsu 1 300 train
+hztyomjumu 0 300 val
+hzugqqsvis 1 300 train
+hzupnzedyd 1 300 train
+hzuwunbsks 1 300 train
+hzuyakazoo 0 300 val
+hzvfnkeuhu 1 300 train
+hzvgozpwze 1 300 train
+hzvhzagzls 1 299 val
+hzvsjhvepm 1 300 train
+hzvtmmdbpv 0 300 train
+hzvvncuzey 1 300 val
+hzwegdkpck 0 300 train
+hzwhewelss 1 239 train
+hzwjgtixvp 1 300 train
+hzwjtxxfun 1 255 train
+hzwqattqej 0 300 val
+hzwrahniyx 0 300 train
+hzxaoosnan 1 301 train
+hzxcrumscx 1 299 train
+hzxfmhbpbv 1 300 train
+hzxgumuycx 1 301 train
+hzxnganwgx 1 300 train
+hzxroynfwb 1 300 train
+hzxufkpwhg 0 300 train
+hzxvydnvih 1 300 train
+hzxwksyuxx 1 300 val
+hzxzeuuwac 1 300 train
+hzyftaezmh 1 300 train
+hzyuhfiqcy 1 300 train
+iaaabqpbie 1 300 train
+iaaecuquha 0 300 train
+iaahwpvbhk 1 300 val
+iaansycndc 1 300 train
+iaaqknnxmj 1 300 train
+iaasdaamvq 1 300 train
+iaawixugwg 1 300 train
+iabjytkeka 0 300 train
+iabnclmlsz 1 300 val
+iabrckrzzb 1 300 train
+iacewlsjgz 0 300 train
+iacgdwlrrc 1 300 train
+iacjnvkbol 1 300 train
+iackjaqvnz 1 300 train
+iaclxlpevl 1 300 train
+iacqbjhhyi 1 300 val
+iadaxbfggh 0 300 train
+iaddncrasy 1 300 train
+iadglutuip 1 300 train
+iadhtmfonc 1 300 train
+iadswupprp 1 298 train
+iadveqkaoy 1 292 val
+iadvveeoyo 1 300 train
+iadyctdpxp 1 300 val
+iaejfprwxv 0 300 train
+iaeoilngdv 0 300 train
+iaeoyoywza 1 300 train
+iaephhhsbp 0 298 train
+iaffxzbsat 0 300 train
+iaflbyrlfl 1 296 train
+iafpekejto 1 300 train
+iafpjbzekz 1 300 train
+iafpwuoyjq 1 301 train
+iafvtrwdna 1 300 test
+iafvzgpbix 1 300 test
+iafxqimtct 1 300 val
+iafzdcaapx 1 298 train
+iagberxnov 1 299 train
+iagbnelfbk 0 300 train
+iagfwljuyl 1 300 val
+iaggyguueu 0 300 train
+iagkfqsiqf 1 300 test
+iagnuurzlu 1 301 train
+iagptjlsoa 1 300 train
+iagsuyrhfv 1 300 train
+iagtuzbrax 1 300 train
+iagwkiuhax 1 300 val
+iagyfexdei 0 302 train
+iagylbvkog 1 300 train
+iagypwuotd 1 300 train
+iagzvgntwj 1 300 train
+iahfubiqha 1 300 train
+iahkeegnay 0 300 train
+iahorleaqb 1 298 train
+iahqztseln 0 300 train
+iahrwamgdp 1 300 train
+iahumkrqom 1 300 train
+iahwnrxmnk 1 300 train
+iahzcxmuck 0 300 train
+iaiayhbnds 0 300 val
+iaijyzzsja 1 300 train
+iaimfjlqgf 1 300 train
+iaionsbhss 1 299 train
+iaitvjkkxp 1 300 train
+iaiyrdizoh 1 300 train
+iajbkukqgu 1 301 val
+iajblozgtx 1 300 train
+iajftegrgj 1 301 train
+iajhxwfhqr 0 300 train
+iajlynqgnf 0 300 train
+iajmjtkkvl 0 300 train
+iakdvjfpwd 1 300 train
+iakjjcavlp 0 300 val
+iakkfkedts 0 300 train
+iaklhigjuj 1 300 train
+iaknaxuuhv 1 300 train
+iakovzidoj 1 300 train
+iakpptsfov 1 300 train
+iakxukygxf 0 300 val
+iakzfiumwi 1 299 train
+iakzgqqova 0 300 train
+ialahsnskn 1 300 train
+ialfzgmsvc 0 300 train
+ialifkmkeh 1 300 val
+iallgurddp 1 241 train
+ialtfvckyv 0 300 val
+ialuhnxoos 1 298 train
+ialzehbegd 0 300 train
+iamcivocsm 1 301 val
+iamozluybw 1 300 val
+iamteyjapm 1 298 val
+iancuamjfd 1 300 train
+ianegceftx 1 300 train
+ianhunltdj 1 300 train
+iankaueair 1 298 train
+ianmsgoocr 1 300 train
+iannnhnrdb 1 300 train
+ianrpeopjz 1 300 train
+ianvpsluga 1 300 train
+ianyazeqng 1 300 train
+iaocprcxtx 1 300 train
+iaodvxkpdk 1 300 val
+iaofhfmkvk 1 300 train
+iaoiksgreo 1 300 train
+iaorknwzjd 1 300 train
+iaoudvakbo 1 300 train
+iaoyzghkwa 0 300 train
+iapdcuzrtj 1 300 train
+iapghlpwjv 1 300 train
+iapkqojtfb 1 300 train
+iapmgvknfw 1 300 train
+iapmvphvxe 1 300 val
+iaptsnuuys 1 298 train
+iapyznpzgw 1 300 train
+iaqjkrucsa 1 301 train
+iaqkrrfwtm 1 299 train
+iaqqtrfkqn 1 297 train
+iaqtariies 0 300 train
+iaquzvpkgp 1 300 test
+iaravzciev 1 300 train
+iarazqtgjq 1 300 train
+iarcbwygtn 1 300 val
+iargdxuhac 1 300 train
+iargmvychb 1 300 val
+iarhtpfnbt 1 300 train
+iarkaikbkj 1 300 val
+iarkkhmyta 0 300 train
+iarobzzslu 0 241 train
+iarowhjwvl 0 300 train
+iaroxkofsz 1 300 train
+iasfjbowcb 1 300 val
+iasfksuaeb 1 300 train
+iasglgcgvz 1 300 train
+iasikptdwp 1 300 train
+iasqxzcofm 1 300 train
+iasuzxlpka 1 300 train
+iasxagvyyu 1 300 train
+iaszgoofuw 1 299 train
+iatcmpblht 1 298 train
+iatcvvxyeb 1 300 val
+iatekyewbx 1 300 train
+iatemnmwgz 1 300 train
+iatevqworc 1 300 val
+iatfbnhdel 1 298 val
+iathiiapiz 1 300 train
+iathxcownj 1 300 train
+iatjzvpzyy 1 300 train
+iatqmqjpdv 0 300 val
+iaucqvmdrg 1 300 train
+iauojwbkom 1 300 val
+iauozvcqxh 1 300 val
+iauqigiuch 1 301 train
+iausqxyaeo 1 300 train
+iauytvnhuf 1 300 train
+iavbvjrrjz 1 301 val
+iavdmgtydi 1 300 val
+iavhnevvde 1 300 train
+iavkdhtxku 1 300 train
+iavrfieowo 0 300 train
+iavrplwusj 0 300 train
+iavsrylowa 1 300 train
+iavtounefu 1 300 train
+iavwmqbaro 1 300 val
+iavxqeuuxa 0 298 val
+iawbfkdlat 1 300 val
+iawjzttxsa 1 300 train
+iawuqgarrh 1 240 val
+iawyhyvobd 0 300 val
+iawznwqrdb 1 241 train
+iaxfvkvwjp 1 300 val
+iaxhdplsjw 1 298 train
+iaxpznfgmx 1 300 train
+iaxsybxxrv 1 300 val
+iaxyjbryga 1 300 train
+iayalzmyvk 1 300 train
+iayfpyjuzl 0 300 train
+iayhuvbhya 1 300 train
+iayjhljdau 1 300 val
+iazfgosbgc 1 300 train
+iazhlddcpk 1 299 train
+iazktilafz 1 300 train
+iazmzxbwdk 1 300 train
+iazovjywij 1 300 test
+iazykudofy 1 300 val
+ibabkcslyi 1 300 train
+ibaoyixdmz 1 300 train
+ibaqxmubws 1 300 val
+ibatmmissu 1 300 train
+ibbcanpfpz 1 300 train
+ibbirvhxzf 1 300 train
+ibbvnkvvsx 1 301 train
+ibcmlunspy 0 300 train
+ibcmyzqrdn 0 300 train
+ibcnsmcfuj 1 300 val
+ibcoeemozu 0 300 train
+ibcqtraqym 1 300 train
+ibcrkohdrk 1 300 train
+ibcrytnkrr 1 300 train
+ibcvfazmsv 1 300 train
+ibcwijeodg 1 300 train
+ibcwqvjymz 1 300 train
+ibcxjvamtn 1 300 train
+ibczcjjlvs 1 301 train
+ibdaotbwap 1 300 train
+ibdcakioxs 1 300 train
+ibdekcqggc 1 300 val
+ibdeoiczoh 0 300 train
+ibdfmkcwxt 1 300 train
+ibdfwpubeq 1 300 val
+ibdixmwoyj 1 301 val
+ibdiyczlnf 1 300 train
+ibdjhlazgn 0 300 train
+ibdnlvrnvu 1 300 train
+ibdzrojhyl 1 300 val
+ibealpglid 1 301 train
+ibebxwclro 0 300 train
+ibefaxnqrj 1 300 train
+ibelgqucrk 1 300 val
+ibepqwrbvw 0 300 train
+ibeqsemwnq 1 300 train
+ibetzqqqul 1 300 val
+ibevodwfxg 1 301 train
+ibexrhxcnw 1 300 val
+ibfcxpsvaf 1 601 train
+ibfeetvoeg 1 300 train
+ibgmhjenxr 1 300 train
+ibgocbdxva 1 300 val
+ibgqcgwvku 1 301 train
+ibgrtmlmjk 0 301 val
+ibgwhlmymw 1 300 train
+ibgylexamz 0 300 train
+ibhbrgrnoi 1 300 train
+ibhfdqywst 1 300 val
+ibhhifhsba 1 300 train
+ibhiqntxjp 1 300 train
+ibhodehdzb 1 300 train
+ibhoivgoml 0 300 train
+ibhrbcboav 1 300 val
+ibhsflcjjr 1 300 train
+ibietyxlgw 1 241 train
+ibitakjzzn 1 300 train
+ibjajvfulo 0 300 train
+ibjkcuwfby 1 300 train
+ibjkueqtba 1 300 val
+ibjkzbpqhd 1 300 train
+ibjnblqlwb 1 300 train
+ibjnrzfngk 1 300 train
+ibjomudxdp 1 300 test
+ibjqcwchjo 1 300 train
+ibjwnqjulv 0 300 train
+ibkcnqqixc 0 301 train
+ibketgjuop 1 300 train
+ibkgonjbjz 0 299 train
+ibkqfxklrx 1 300 train
+ibksoedegv 0 300 train
+ibksxmdtbp 1 300 train
+iblfjaagwo 1 300 train
+iblhdbsurm 1 300 train
+iblijbremh 1 300 train
+ibllwydbxg 1 300 val
+iblofvipyk 1 300 train
+iblqxqdpfr 1 300 train
+iblrdnkcny 0 300 train
+iblwldnsko 0 300 train
+ibmbevjtck 0 300 train
+ibmbkfiexb 1 300 val
+ibmehtjscb 1 300 val
+ibmjazedun 1 300 val
+ibmnuatjyz 1 300 train
+ibmslcqmtc 1 300 train
+ibmxdxchvr 1 300 train
+ibmzjtploj 1 300 val
+ibnbfsmufo 1 300 val
+ibndvrpnfi 1 300 train
+ibnlgrbkqi 1 301 train
+ibnukwwjas 1 300 val
+iboeemjjnq 1 300 train
+ibopxidexc 1 300 train
+iboqzcaknp 0 300 train
+ibovjyekgk 1 300 val
+ibovujmtce 1 300 train
+iboykxeyiq 1 300 train
+ibpcyzcvpb 1 300 train
+ibpejqhjlq 1 300 train
+ibpkdtdqyp 1 300 train
+ibpkhvbton 1 300 val
+ibpmaawlyo 1 300 train
+ibpsrkqhlj 1 300 train
+ibpwmmicvh 1 300 train
+ibqexozihp 1 300 train
+ibqleaiagu 1 300 train
+ibqlsszovy 1 236 train
+ibqmomrlro 1 300 train
+ibqoxklbrh 0 300 train
+ibqqieqbyb 0 301 train
+ibrdkgckhc 0 300 train
+ibrryzgmfy 1 300 val
+ibryrelmff 1 300 train
+ibsetvtuom 1 300 train
+ibseuodsgc 1 296 train
+ibsjfqtooa 1 300 train
+ibsoralizj 1 300 train
+ibsprpdevi 1 298 train
+ibstzifuum 1 300 val
+ibtbfelplt 1 300 train
+ibtfwzovjy 0 300 train
+ibtmkgmfyq 1 300 train
+ibtneynlmr 1 300 train
+ibtnnneitz 1 300 train
+ibubtwqoil 1 301 train
+ibuivkqsyk 1 300 val
+ibuklythlr 1 301 train
+ibulltsbfd 0 300 val
+ibumwtxpsd 1 300 train
+ibusijathj 1 300 train
+ibuxecwfti 1 300 val
+ibuykxywnu 1 300 train
+ibvahevpwk 1 300 train
+ibvftomeks 0 300 train
+ibvgqmxwiz 1 300 train
+ibvilvxmmo 1 300 train
+ibvomadohg 1 300 train
+ibvouhuzak 0 300 train
+ibvpnzmgkh 1 300 train
+ibvumqguch 0 300 val
+ibvyapyort 0 300 train
+ibvzfnhbej 0 300 val
+ibweyptfjz 0 301 train
+ibwpmofvsr 0 300 train
+ibwqsxftfl 1 300 train
+ibwttyoraj 1 300 train
+ibwwurwjgs 1 300 train
+ibwwzqlvuk 1 241 train
+ibxaeqkkkf 1 300 train
+ibxesqtwof 1 300 val
+ibxfjfyxna 1 300 val
+ibxfxggtqh 1 300 test
+ibxjbinwhk 0 300 train
+ibxjlzrugr 1 301 train
+ibxkammjrt 1 300 train
+ibxkhtrmdq 1 300 train
+ibxmhkmxpx 1 300 train
+ibxmrjdmpm 0 300 train
+ibxolsgkru 1 300 train
+ibxqjsvqcl 1 300 train
+ibxroxfckg 1 300 train
+ibxryzsosu 0 300 train
+ibxyizjjut 0 300 train
+ibxzhlqijg 1 300 val
+ibybdjmmps 1 300 train
+ibyevudtta 1 300 val
+ibyfsskmnp 1 300 train
+ibygpqzyhp 1 300 val
+ibyibyqywj 1 300 train
+ibylnpjwsj 1 300 train
+ibyqlgyljn 1 300 train
+ibyvsdbywn 0 300 train
+ibywkegbbb 1 300 train
+ibyxrzafun 1 301 train
+ibyzegnqfe 1 300 train
+ibzafiyhyp 1 300 train
+ibzdgsiuzy 1 300 train
+ibzgacltls 1 300 val
+ibzihaeowg 1 300 train
+ibzmmaruzq 1 300 val
+icaeqxcbgp 0 300 train
+icakoqnaxa 1 300 train
+icapqzqcuo 1 300 train
+icaqfgyfue 1 300 train
+icarbwqejo 1 300 train
+icasbucwjj 1 298 train
+icascjuftz 1 300 train
+icbfzqoass 1 296 val
+icbggbmffh 1 300 val
+icbqfvgfsm 1 300 train
+icbrhcdfmo 1 300 train
+icbsahlivv 1 299 test
+icbtygxnbe 1 300 train
+icbylspzoe 1 299 val
+icbzbcwlgf 0 300 val
+iccdyopdma 1 300 train
+icchgkkrrm 1 300 val
+iccrsavqor 0 300 train
+icctbkjedq 1 300 train
+iccxpcvwlm 1 300 train
+icdcwewcxd 1 300 train
+icdiczmfqs 0 300 train
+icdjfhsvke 1 300 train
+icdjimtvle 1 300 train
+icdmwvicft 1 300 train
+icdpbucptd 0 300 train
+icdqhnmpsk 1 292 train
+icdqsehkjx 1 300 train
+icdsruusmp 1 301 train
+icdurrnilp 0 302 train
+icdxqthvir 1 300 train
+icdzrrflaj 1 300 train
+icehuykzkb 1 300 train
+icejsilpcj 1 300 train
+icekuiwngx 1 300 train
+icexgxjsbx 1 300 train
+iceyxwxjof 0 296 train
+iceyyvssxc 1 300 val
+icfcbwhnii 1 300 val
+icfdwpsusg 0 300 val
+icffpvvtnu 0 301 train
+icfgdgdzzu 1 301 train
+icfhrsjvcf 1 302 val
+icflgdqzzp 1 300 train
+icfmofparh 1 240 train
+icfwwwhlnr 1 298 train
+icfyibcstp 1 300 train
+icgacnyaff 1 294 train
+icgapcxria 1 301 train
+icgbcmjljl 1 300 val
+icgbddywmb 1 300 train
+icgdbzodmc 0 300 train
+icgiegvinq 1 300 train
+icgrbktjov 1 300 train
+icgwvijfsj 1 300 train
+icgxytmtaj 0 300 train
+icgykjefji 0 300 train
+ichbahfgrd 1 300 train
+ichbbqrzzf 1 300 val
+ichdjrsaby 1 300 train
+ichitgncxm 1 296 train
+ichkpdzqrb 1 300 train
+ichxrumvty 1 300 train
+icihgqgzjv 0 300 train
+icihmyxnps 1 300 train
+iciitcmmro 1 300 train
+icimijhkiy 1 300 train
+iciosjtmde 1 300 train
+iciucnxpfs 1 300 train
+iciwnqedvi 1 300 train
+icixsudnsj 1 299 val
+icjctmnbbk 1 300 train
+icjdgqaegf 0 300 val
+icjdxrzrwp 0 300 train
+icjgaupncb 1 300 val
+icjguyixom 1 300 train
+icjhsaoqdx 1 300 train
+icjrpokysq 1 300 train
+icjszfwhpo 1 300 train
+ickaowvree 1 300 train
+ickgmyiabp 1 300 train
+icklgrlvqs 1 299 test
+ickokxqfnq 1 300 train
+ickseczowy 1 300 train
+icldjdfoii 1 300 val
+icleltrgvr 1 300 train
+icletkvmhy 1 300 train
+iclluvbprk 1 300 train
+icloodhsss 1 300 train
+iclrzgdndu 1 301 train
+iclsboagyo 1 300 train
+icltgnaluy 1 300 train
+icltmulsdu 0 300 train
+icluqlnjrc 1 300 val
+iclvcqwdte 1 300 train
+icmbotystx 1 300 train
+icmikfktcb 0 300 train
+icmsprtfro 1 301 train
+icmtbqlctp 1 300 train
+icmxogeeta 1 241 train
+icndiproml 1 301 train
+icnessjxcq 0 300 train
+icnfldgphx 1 297 train
+icnlkcpjzg 1 300 train
+icnlrtbomm 1 300 val
+icnpurvfnv 0 300 train
+icnrizpsic 0 300 train
+icnsjvyovf 1 300 train
+icnxlpkqck 1 300 val
+icoexulwur 1 300 train
+icogfaodkh 1 300 train
+icogniotec 1 300 train
+icokcjzyjm 1 300 train
+icoqtpzktv 1 300 train
+icovknaajw 1 300 train
+icpfefkzpy 1 300 train
+icpiywnasj 1 300 train
+icpjgmharj 1 300 train
+icpriujqbv 0 300 train
+icqcqcpgkx 1 300 train
+icqmqztbry 0 300 train
+icqpohatfy 1 300 train
+icqulbkcpl 1 300 train
+icqveacfdo 1 301 train
+icqvlexdsf 0 300 train
+icqwawpakt 1 300 val
+icrgmcvxwy 1 300 train
+icrlpxducm 1 300 val
+icrsnwcjec 0 300 val
+icrvorrnel 1 300 val
+icsdvfdvix 1 300 train
+icsjsstcfv 1 300 train
+icsnwphskc 1 300 train
+icsohhlvhk 1 300 train
+icsqbukkrp 1 300 train
+icsqflacid 1 300 train
+icsqwhmeou 1 300 train
+icsxletuwy 1 300 val
+icsyoswwvq 1 300 train
+ictbbbprgl 1 300 train
+ictedxrvpq 0 300 train
+ictiftibcz 1 300 train
+ictitxopnk 1 300 val
+ictnvgvaem 0 300 val
+ictomxicqv 1 301 train
+ictrscipdx 1 300 train
+ictsrbvpyw 0 300 val
+ictulnhznj 1 300 train
+icuolbvyqu 1 300 train
+icvbhynbui 1 301 train
+icvbwnjins 0 300 train
+icvdmuralp 1 300 train
+icvevwmnut 1 300 val
+icvkkfipvb 1 300 train
+icvnffvwrx 1 300 train
+icvplkpbci 1 300 val
+icvvyxfezw 1 301 train
+icwciqzrid 1 301 train
+icwlmhflzf 1 297 train
+icwqxqfmqt 1 300 train
+icwvaztkdk 1 300 train
+icwvmmmlpy 0 301 train
+icwxpzhoww 1 298 val
+icwzexprfv 1 300 train
+icwzhiyekf 1 301 val
+icxcbaziyx 1 300 train
+icxgcdnugn 1 300 train
+icxhnmftoq 1 301 train
+icxiqspnie 1 301 train
+icxllszfib 1 300 train
+icxmuaiwvq 1 301 train
+icxnnoqyng 0 300 val
+icxvnigqza 0 300 train
+icybqyznrg 1 300 train
+icyjsunwgr 1 301 train
+icynhabozg 1 300 train
+icyttnhbcb 1 300 train
+icyxkygchy 1 300 train
+iczglouguh 0 300 train
+icziwndesh 1 300 train
+iczjgbjeyu 1 300 train
+iczkbkwwuu 1 300 train
+iczlgqaqpg 1 300 val
+idadbkxpji 1 300 train
+idaqwmmsnm 1 299 test
+idarvroilu 1 300 train
+idawtjiblc 1 300 val
+idazugefys 1 298 train
+idbaeatils 0 300 train
+idbhrszccl 1 300 train
+idblbloesr 1 300 train
+idbljuvduk 1 300 train
+idbrvettfr 1 301 train
+idbvfynrkg 1 300 train
+idbyqyjxer 1 300 train
+idcbaqpqwx 1 300 train
+idcenbzluw 1 300 train
+idclldpxxv 1 300 train
+idcqccajdb 1 301 train
+idctovmfvq 1 300 train
+idcxezkhbt 1 300 val
+idczcwsfqq 1 301 val
+idczhqbbqz 1 300 test
+idczrxmicy 1 300 train
+iddcjxsgyq 1 300 train
+iddcpvsvnq 1 300 train
+iddikdeeib 0 300 train
+iddjmuszko 0 300 train
+iddusvxjjk 1 301 train
+idduvzcspg 1 300 val
+ideirgtvwo 1 300 train
+idelcgqdok 1 300 val
+idevihnoiu 0 300 val
+idewmjjcor 1 292 val
+idexzksgyj 1 298 train
+idfcmepusm 1 300 val
+idffgkfuuu 1 300 train
+idffyndchl 1 300 val
+idfllgrmpc 1 300 train
+idfnodkdkz 1 300 test
+idfpkfirul 1 300 train
+idfslgsler 0 300 train
+idftxnczgl 1 298 train
+idfvqexswv 0 300 val
+idgfghhwes 0 300 train
+idgfprlyln 1 301 train
+idglftyrjq 1 300 train
+idgqkqlmag 1 300 val
+idgviegmai 1 300 train
+idgyfmeiob 1 300 train
+idhbtlqlax 1 300 train
+idhcuvcqnh 1 301 val
+idhduicoip 1 241 train
+idhendubfm 1 300 train
+idhivuqobl 1 270 train
+idhqpwmptv 1 300 train
+idhucumgad 1 300 train
+idhxsxrljg 1 300 train
+idifdkemcz 1 300 train
+idiidmqade 1 300 val
+idilptyute 1 297 val
+idiqxarzla 1 300 train
+idirqwitxd 1 300 train
+idiwtqoqel 1 300 train
+idiyvdnxst 1 300 train
+idizmfmiol 1 300 train
+idjaubvnms 0 300 train
+idjfodzoiq 1 300 train
+idjfydctho 1 241 train
+idjhhtjvig 1 300 val
+idjoasuopo 1 301 val
+idjpsicisf 0 300 train
+idkctowzoy 1 300 train
+idkhtendeo 1 300 train
+idkipswees 1 300 train
+idklchvhxp 0 300 train
+idklujzcjs 0 300 train
+idkmnqlcks 1 300 val
+idkmrrvwiz 1 299 train
+idkoajsxoz 0 300 train
+idkxtkllsm 1 300 train
+idkypjamom 0 300 val
+idkzvhnvog 1 241 train
+idldvhbbql 1 300 val
+idlndijmeb 1 298 train
+idlvayiwru 1 300 val
+idlzlmvvkm 1 299 test
+idmhtacfpp 1 300 train
+idmnnnlngf 1 301 val
+idmpttjjmt 1 300 train
+idmruoiylw 1 300 test
+idmusofjij 1 300 train
+idmwainfhx 1 300 train
+idnbymuzkb 1 300 train
+idndashdrs 1 300 train
+idnftykcsj 1 300 val
+idnkieqgec 1 297 train
+idnrnqaocs 0 300 val
+idnrtnswqk 1 300 train
+idntbmggek 1 300 train
+idnvievros 1 299 test
+idnyhzssgv 1 300 train
+idnzdgufeh 1 301 train
+idoatnofsg 1 300 val
+idonwrbigy 0 300 train
+idpeiedymw 1 300 train
+idpnmsyoio 1 300 train
+idpqahuphg 1 300 train
+idpryxethg 1 300 train
+idpsbzpwbm 1 300 train
+idpsuuycxx 1 300 train
+idpvziaviy 1 300 val
+idpyzjmfvr 1 300 train
+idqeytsgfw 1 288 train
+idqfpxmkbz 1 301 train
+idqgctgfgm 1 300 train
+idqmbfhtod 1 300 train
+idqvimshpb 1 300 train
+idqwbfknso 1 300 train
+idqwolxjql 1 300 test
+idqxefeyno 0 298 train
+idqzaxczdq 1 300 train
+idrbsowlyz 1 300 train
+idrfcnqkmy 1 300 train
+idrglfzdxz 0 241 train
+idrkckayqw 1 298 train
+idrrtaxsxh 1 300 train
+idrwpdzaxg 1 300 val
+idrywygpod 1 83 train
+idrzntgmqv 1 300 val
+idslmbefgu 1 301 val
+idsrgxzhuj 1 300 train
+idsupeszcp 1 300 test
+idswtwyaat 0 300 train
+idtfzwduqc 0 300 train
+idthtttdin 1 300 train
+idtjidropp 1 300 val
+idtrxsvbqs 0 300 train
+idttmskbxp 1 297 train
+idtulckubw 1 300 train
+idubfbiavu 1 301 train
+idublnimkg 1 300 train
+iducyiaicz 1 300 val
+iduepcuwnx 1 300 train
+iduilholve 1 300 val
+idukbchmao 1 300 train
+idumxqtpaq 1 300 train
+idutnrjbmh 1 300 train
+iduxskpipi 1 241 train
+idvckqxhku 1 300 train
+idvdwmuiyg 1 300 train
+idvswwcxmm 1 300 train
+idvupxipcj 0 300 train
+idvystcrfi 1 300 train
+idwazgztax 1 299 test
+idwfebyhtp 1 296 val
+idwhtnofel 0 300 train
+idwlctaaov 0 300 train
+idwlmuiqcf 1 300 train
+idwymigirr 1 300 train
+idwzfxlvlp 0 300 val
+idwzwpxlhh 1 300 train
+idxefzqfoo 1 300 train
+idxnwvjsdq 1 300 train
+idxosdxjfx 1 300 val
+idxqdzkedj 1 300 val
+idxwsvjpwm 0 300 val
+idxzijbhuc 1 300 train
+idyaoorqlq 0 300 train
+idyeuzauml 1 136 train
+idylibifnz 1 300 train
+idymraczvi 1 300 train
+idytgtwoyw 1 300 val
+idywvgefns 1 300 train
+idyyusqmuy 1 300 train
+idzanlyoov 1 300 train
+idzhptqifq 1 300 val
+idznoeuphj 1 301 train
+idzntwkkjy 1 301 val
+idzvwaehek 1 301 val
+idzzeprsoz 1 300 train
+ieablenuwf 1 300 val
+ieahdkebjr 1 301 train
+ieahgrikbf 1 300 train
+ieammjzuzr 1 300 train
+ieapfzneul 1 300 train
+ieayruqaum 1 300 train
+ieazrjhstb 1 300 train
+ieazyslhjp 0 300 train
+iebavodfbm 1 269 train
+iebcraoxba 1 300 val
+ieblmcegmk 1 300 val
+ieblyetiob 1 300 val
+iebmggvffj 1 300 train
+iebnuxnbcl 0 300 train
+iebvvschnq 1 300 val
+iebytestod 1 300 train
+iebzyjcevc 1 301 val
+ieccgftoog 1 300 train
+ieceooufst 1 300 train
+iecnnndmih 1 301 train
+iecrcnfrvy 1 300 val
+iectbvzxxv 1 300 train
+iedayonitd 1 300 val
+iedcosijll 1 300 train
+iedohrjaip 1 300 val
+iedoxqgjib 1 300 train
+iedsgxqfuz 0 299 test
+iedwllcovh 1 301 train
+iedwvcfbbv 0 300 val
+ieeabyyskz 1 240 train
+ieediducjd 1 300 val
+ieespskvba 1 300 train
+ieetcpdorf 1 301 train
+iefcdlggjt 1 300 val
+iefejwjgxv 1 300 train
+ieffklubvw 1 300 train
+iefmnvgukg 1 300 train
+iefmojjwhd 0 300 train
+iefyuoxhji 0 300 train
+iegajauwmj 1 300 train
+ieghrgrzcg 1 300 train
+iegjuatobt 1 300 train
+ieglnjrfev 1 300 train
+iegsfsmgqv 1 241 train
+iegunvihwt 1 300 train
+iegwbqnlxa 0 300 val
+iegzhaqbvj 1 300 test
+iehacprdli 1 300 train
+iehcphzizv 1 241 train
+iehkdzljsv 0 300 train
+iehprbxpfz 1 300 val
+iehqacttmo 1 298 train
+iehxbxjfvp 1 300 train
+ieijedcdgu 1 300 train
+ieilvwoguv 1 300 train
+ieixopuznp 0 300 train
+ieiyrvycnc 1 300 train
+ieizukaqus 1 300 train
+iejbsxdytl 1 299 train
+iejjwfhzbk 0 300 train
+iejlhussqv 1 241 train
+iejlkkxdvn 1 300 train
+iejmyjinfc 0 300 train
+iejsjlmsbf 1 301 train
+iejsmvmbrj 1 300 train
+iejtbpalis 1 300 train
+iejtesnfvm 1 300 train
+iejyeyzjrr 1 300 train
+iekjkjksds 1 300 val
+iekkobafvz 1 300 train
+iekpcgggfb 1 300 train
+iekpiwuhua 1 300 train
+iekvsfjhya 1 300 train
+iekysyefpt 1 300 train
+ielcijipyr 1 300 train
+ielgismpza 0 300 train
+ielhjxmxuy 1 300 train
+ieljnverzu 1 300 train
+iellyzphms 1 300 train
+ielojrzbhe 1 300 train
+ielonfxgew 0 300 train
+ielpecwrvy 1 300 train
+ielrrtwsdr 1 300 test
+ielsbxknis 1 300 train
+ielwvvgavv 1 300 train
+ielyhphrla 1 300 val
+iempjnzdef 1 300 train
+iemrsgdmpy 1 300 val
+iencorrqjy 1 300 train
+ieniyhcxoj 1 300 train
+ienkuvllaf 0 300 train
+ienlpkmwzd 1 300 train
+ienmumzvce 1 301 train
+ienpqtctso 1 300 val
+ienuvfvnsf 1 300 train
+ienvvxcruh 1 300 val
+ienxwdghsn 0 300 val
+ienzeobaus 0 300 train
+ienzfrlnku 0 300 train
+ieoardezfz 1 300 train
+ieoemhvohi 1 300 train
+ieoervpooz 0 300 train
+ieogyyjueb 1 300 train
+ieoixnltne 1 299 test
+ieojkfxvfb 1 300 train
+ieojvnabjg 1 300 val
+ieopsubbkk 1 300 train
+ieoznfhwtd 1 300 train
+iepbnynwrk 1 300 train
+iepfpszzex 1 300 train
+iepiicsldm 1 300 val
+iepiwuwmja 1 299 test
+ieplvzbyvl 0 301 train
+ieprixgtqw 1 300 train
+ieqeevedrz 1 299 train
+ieqilqdtny 1 300 train
+ieqpatxbvq 1 300 val
+ieqqabcgry 1 300 train
+ieqqivjdek 1 299 test
+ieqqxuxbej 1 300 val
+ieqrzhbkfi 1 300 train
+ieqsmnbncd 1 300 train
+ieqtuasijl 0 300 train
+ieqvxyxqaf 1 301 train
+ierdtqxaqx 1 300 train
+ierdzmlgsj 0 300 train
+iereerqidh 1 298 train
+ierioclrpn 1 299 train
+ierqhmpksk 1 300 train
+ierqmjhgkw 1 300 val
+iesabjceyq 1 300 val
+iesftahqon 1 300 train
+iesgtcmomr 1 300 val
+iesqelxvxo 1 300 train
+iestfugmyu 1 300 train
+iesxfvntdp 1 300 train
+ietaguzsww 1 300 train
+ietekwwhoc 0 300 train
+ietmndyxyc 1 300 train
+ietpvbfmax 1 300 train
+iettbjibcl 1 240 train
+ietunqyaar 1 301 train
+ieucjuzjqq 1 300 train
+ieuoinyxmt 1 300 train
+ieushlhwpk 1 300 train
+ieuxohfweg 0 300 train
+ievaopemwn 1 300 train
+ievevzdypl 1 300 train
+ievfqngfzm 1 300 train
+ievfrmztyv 0 300 train
+ievilxkyna 1 300 val
+ievitkoqhn 1 300 train
+ievjqsivjx 0 300 train
+ievkliwull 1 300 train
+ievmqxpxzk 0 300 train
+ievsgicwyn 0 300 train
+ievwfvefpb 1 300 train
+iewanjcqyo 1 300 train
+iewewjstku 1 300 val
+iewggzdtmd 0 300 val
+iewhuybkzt 1 300 train
+iewlnbyxcr 1 300 train
+iewnksavpn 1 300 train
+iewqewoiwq 1 298 val
+iewrgvhrtf 1 300 train
+iewsamehyy 0 300 train
+iewsnpnwhl 1 292 train
+iewsqvmcog 1 300 train
+iewubyuawz 1 300 train
+iexakuabku 1 300 train
+iexpazbvkj 1 300 train
+iexrwqdnmk 1 300 train
+ieyaeossbx 1 300 train
+ieyagiuvte 1 300 train
+ieyauptfnj 1 300 train
+ieybduadtn 1 300 train
+ieybeoxyyd 1 300 train
+ieycdlrlet 1 301 val
+ieycmlnprv 0 300 train
+ieygvtnomj 1 300 val
+ieysmiicva 1 300 train
+ieyywncjfj 0 300 train
+iezaeaizzp 0 300 train
+iezlgezozt 0 300 val
+iezorintbr 0 300 train
+iezssqzkuw 0 300 train
+iezygupcbz 1 300 train
+ifacwdryng 1 300 train
+ifadtbdsnu 1 300 train
+ifafihagaj 1 300 train
+ifaiwvujdz 1 300 train
+ifapujuykj 1 300 train
+ifasoqslzi 1 300 train
+ifaumaxagx 1 300 train
+ifbaleejqi 0 300 train
+ifbdbogiqn 0 300 train
+ifbexrjqyl 1 300 train
+ifbfpcfynf 1 300 train
+ifbftteujv 0 300 train
+ifbmgslpux 1 300 train
+ifbnqnateq 1 300 train
+ifbrrxlvmt 1 300 train
+ifbztnkfwj 1 288 train
+ifcpipovtg 1 300 train
+ifcrqqezrg 1 241 train
+ifcrwgusmj 1 301 val
+ifcvgledqx 1 300 train
+ifcvzptkiu 1 300 val
+ifcyqviwvw 1 298 train
+ifddwpwwpq 1 300 train
+ifdftgnlas 1 300 train
+ifdiyylyow 1 300 train
+ifdjqzzuxp 1 300 val
+ifdpnvioqy 1 300 train
+ifdrempraq 1 300 val
+ifdrrziryf 1 300 val
+ifdxdslmat 0 300 train
+ifdycojmja 0 300 train
+ifdygkyqgh 0 300 train
+ifdzmbmabw 1 300 train
+ifeiovrcyz 0 300 train
+ifetxjrqft 1 300 train
+ifezphpbcj 1 298 train
+ifflukdium 0 300 train
+iffnhuakcp 1 300 train
+iffowzafje 1 300 train
+ifftaefxao 1 240 train
+iffuwrmanv 1 300 train
+iffvaaswwj 1 300 test
+iffvbezmro 1 298 val
+ifgdjorcxi 1 301 train
+ifgfihjgvi 1 298 train
+ifggshtynd 1 300 train
+ifgjbescbh 0 300 train
+ifgjbjeuvj 1 300 train
+ifgqdbuvuc 0 300 train
+ifgwfyulwo 0 298 train
+ifhbhjltyz 1 300 val
+ifhcessuxq 1 298 train
+ifhkiyyjtc 1 300 val
+ifhlmoycii 1 300 train
+ifhnjsmiro 1 300 train
+ifhqyebjdc 1 300 val
+ifhrdtbdnv 1 300 val
+ifhvjsfyca 1 300 train
+ifhwfgfdba 1 300 train
+ifhzofjkuh 1 300 train
+ifiabzpicn 0 300 train
+ifiidnukqv 1 300 train
+ifipnaujoy 1 300 train
+ifiuufdctp 1 299 test
+ifiwoyqjnx 1 300 train
+ifjdbblonn 1 300 train
+ifjkbdsjpx 1 300 val
+ifjktxxiln 0 300 train
+ifjlzsacbn 1 300 train
+ifjqwcoaqa 1 300 test
+ifjsiierar 1 300 train
+ifjuyhbiec 1 300 train
+ifjxjinmwm 1 300 train
+ifjzcxxvcd 1 300 test
+ifkgrayoeg 1 300 train
+ifkqknsmuo 1 300 train
+ifksnroxss 1 300 train
+ifkvgrmpdk 1 300 train
+ifkwsnfmpd 0 300 train
+iflmprxhjy 1 249 train
+iflpspqqjz 1 301 train
+iflpvynkne 1 301 val
+ifltvewlpa 1 300 train
+iflyyhqrzf 1 300 val
+ifmdgmqptp 1 299 val
+ifmengvgvb 1 300 train
+ifmowsvnxs 0 299 val
+ifmrjsbzht 1 301 train
+ifmyagxpqa 1 301 train
+ifnazmmtyl 1 300 train
+ifnbtqawcy 1 300 train
+ifncshryta 1 300 train
+ifnkczaksz 0 300 val
+ifnlytasas 0 301 train
+ifnmmnfljt 1 301 val
+ifnsbiqfdf 1 300 train
+ifnzwzzcdv 1 300 train
+ifoesojzgd 1 301 train
+ifoffhdbdg 1 300 train
+ifojjefnhb 1 300 train
+ifougnqcfr 1 300 train
+ifoybtorlj 1 298 train
+ifphnynsrr 1 99 train
+ifphvhbmen 1 300 train
+ifpjowvtgo 1 301 train
+ifpnkdloos 1 300 train
+ifpqeojocz 1 300 train
+ifpqwaqwfe 1 300 train
+ifqeqimruk 1 300 train
+ifqghnlhth 1 300 val
+ifqnnxzpry 1 301 train
+ifqutlnbab 1 298 train
+ifquukmxxm 0 300 train
+ifqxbqbwlo 1 300 train
+ifqzxlsfje 1 300 train
+ifraezsjlu 1 300 val
+ifragtmmgj 1 300 train
+ifrbyuodmk 1 300 train
+ifrgshsycv 1 300 train
+ifrkkqxjzy 1 298 train
+ifrlhqmmzx 0 300 train
+ifrnmbhjuu 1 300 train
+ifrosnoslp 1 301 train
+ifrqxgcxve 0 300 train
+ifrrvrmgeq 1 300 train
+ifrxcbqamt 1 300 train
+ifsaqemimf 1 300 val
+ifsfkwyfgr 1 300 train
+ifshcvruhn 1 255 train
+ifshdexuoy 1 300 train
+ifshurmbgc 1 300 val
+ifsiyraxsg 1 300 val
+ifsqlqkvvg 1 300 train
+ifstpkkgsy 1 300 train
+ifsukcvnch 1 300 train
+ifszmxuemy 1 300 train
+iftayphwhc 1 300 train
+iftfvinsgj 1 300 train
+ifthrazggb 1 300 train
+iftluclqfd 1 300 val
+iftqakgrmy 1 302 train
+iftqrenhau 1 300 val
+iftscryovw 1 300 train
+iftslncsev 1 300 train
+iftxrnyzrt 1 300 train
+ifuaobfrhn 1 298 train
+ifubyoaifk 0 301 train
+ifumzpbnhu 1 298 train
+ifvalqursn 1 299 val
+ifvatcgnvq 0 300 train
+ifvatczxio 1 300 val
+ifvbwbcnyj 0 300 val
+ifvpemzpuf 0 300 val
+ifvsoxuelf 1 300 train
+ifvypkuwuk 0 239 train
+ifvzkfsrpo 1 300 train
+ifvzptquzk 0 300 train
+ifwhspkofn 1 300 train
+ifwkpaxoye 0 300 val
+ifwldihtfm 1 300 train
+ifwqhranos 1 300 train
+ifwummoaip 1 300 train
+ifwvcawxgc 1 297 train
+ifwygqldix 0 300 val
+ifxaojtzqg 0 300 val
+ifxkdcpuog 1 299 test
+ifxuwpceiw 1 300 val
+ifygltkojr 0 300 train
+ifygvxkccr 1 300 train
+ifyklgdvmf 1 300 train
+ifymmduofn 1 300 train
+ifypxgoczv 1 302 val
+ifyvrzecye 1 300 test
+ifyvybixew 1 300 train
+ifzmdtudrp 1 301 train
+ifzspsyvsu 1 300 val
+ifzyirixfu 1 300 train
+igaeqcswip 1 300 val
+igakfbescp 1 300 train
+igamqtygjm 1 298 train
+igaobtaeuk 0 300 train
+igaxwcwfgy 1 300 train
+igazotsmka 1 300 train
+igbhevulbb 1 300 train
+igbmamgbwl 0 299 train
+igbnijdvai 1 300 train
+igbvqmetfq 1 300 train
+igbxxjlcsp 1 300 train
+igbyejqxve 1 300 val
+igbypcqmah 1 302 train
+igciggxbzg 1 300 val
+igcpecxbxu 1 300 train
+igcqzxjezw 0 300 train
+igcudxsabk 1 300 train
+igdifobvny 1 300 train
+igdiwismie 1 241 train
+igdskqhcmo 0 300 val
+igeazbecmj 1 300 train
+igedkulsvc 1 300 train
+igehogroie 1 300 train
+igekiersqy 1 300 val
+igerfsbjcv 1 300 train
+igettdttpz 1 300 val
+igexnlxhrp 1 300 train
+igfgmxfqse 1 300 train
+igfhuqfvsk 1 300 val
+igfjejwdeg 1 300 train
+igfjmkzges 1 300 val
+igfswqsudw 1 298 train
+iggaslwzex 1 167 train
+iggfjxzsbf 1 300 train
+iggixplyqf 0 300 train
+iggmrxafha 1 300 train
+iggojuqqng 1 300 train
+igguzxdchx 1 300 train
+iggzpvhqpl 1 300 train
+ighgptshjh 0 300 train
+ighlqjimfj 1 300 train
+ighneujxpi 1 300 val
+ighsijifvf 1 300 test
+ighxwusvdb 1 301 train
+igibhnxmmr 1 300 train
+igicnvszpy 1 300 val
+igicvxhpvq 1 300 train
+igidlhoyij 1 301 val
+igidrdyhky 0 300 val
+igigqwkkkj 1 300 train
+igiqjkzwbj 0 300 train
+igiujiwiec 0 300 train
+igivaftugx 1 300 train
+igiyjzpykw 1 300 train
+igjcwfmodt 1 298 train
+igjgkdnwbc 1 300 train
+igjrrkzmzz 1 300 val
+igkdnzsmuf 1 301 train
+igkeauszro 1 300 train
+igkghtbwgx 1 301 train
+igkhzfxvlv 1 300 train
+igkjcqwxff 1 300 train
+igleuxrkap 1 298 train
+igloenuzfl 1 300 train
+igltmsiggb 1 240 val
+iglunokepd 1 300 train
+igmbrvoxmp 1 300 train
+igmfdrzryo 1 300 train
+igndyvsvjz 1 300 train
+igniolzkcc 1 300 train
+ignjgucwqo 0 300 val
+ignnnnpang 0 300 train
+ignosnyrgj 1 300 train
+igocixtthf 1 297 train
+igoeltjwna 1 300 val
+igoscayqzz 1 300 val
+igouepvsij 1 300 val
+igoyiwldew 1 300 train
+igozdkozho 1 301 train
+igpcdxrhrd 1 301 train
+igpdruufbl 1 300 train
+igpesqdreb 1 300 train
+igpfjjxaxp 1 299 val
+igpgpxsxfi 1 301 train
+igpqypvhtg 1 300 train
+igptebbdgv 1 300 train
+igpuctdnhm 1 300 train
+igpuihnakd 1 300 val
+igpvrfjdzc 0 299 test
+igpxeffiiu 1 300 train
+igqawcjvbk 1 300 train
+igqhapdxrm 1 299 test
+igqpidbghc 1 300 train
+igqshywzhc 0 298 train
+igqtehovnx 1 300 train
+igqwnabiwl 1 241 train
+igradrodip 1 298 train
+igrjzpduve 1 297 train
+igrnnwcife 1 301 train
+igrnumdddg 1 300 val
+igskvdqdgq 1 300 train
+igsqiwufse 0 300 train
+igsqrhwzro 1 297 val
+igsyoakgod 1 300 val
+igszgtyaou 1 300 train
+igtgmuljlt 1 300 train
+igtjepwcml 1 300 train
+igtkcmspif 1 300 train
+igtlxyhmeu 1 300 train
+igtwtegocc 1 300 train
+igublytzpc 1 300 train
+igukuxrfcz 1 300 train
+iguljqodgq 1 301 val
+igupcloczi 1 298 train
+igvdzwvuxd 1 288 train
+igvgrelnok 1 300 train
+igvhwcjqqi 1 300 train
+igvmbppqiw 1 300 train
+igvrhmiggl 1 298 train
+igvtidvimh 1 300 train
+igvvtooxem 1 300 train
+igvyqqqxfj 1 300 train
+igwapcnsbb 0 301 val
+igwefbugnu 1 300 val
+igwekiidbq 1 239 train
+igwkzixatk 1 300 val
+igwlxdtgix 1 299 val
+igwuwvvjkv 1 300 val
+igwxjnfnos 1 300 val
+igwyftdshr 1 300 val
+igxcdfatrf 1 300 train
+igxhbcppwe 1 300 train
+igxhynhfsr 0 300 val
+igxmbizkqv 1 300 train
+igxwlwbnrl 0 300 train
+igydssgspa 0 300 train
+igyligfzip 1 300 train
+igyqbulunh 1 300 val
+igyvpymyki 1 299 train
+igyzbftnok 1 300 train
+igzduylpgp 1 300 val
+igzkmrnosn 1 300 train
+igznljkiez 1 300 train
+igzpjjcsua 1 300 train
+igztjgndud 0 301 train
+igzvunospk 0 300 train
+igzwbvyuzg 1 300 train
+ihaazqkfjd 1 300 train
+ihaczkbpvu 1 300 train
+ihaenwsjeg 1 300 train
+ihahebszkv 1 300 train
+ihaqcaeveo 1 300 train
+ihatzthuqw 1 300 train
+ihaucvkxnl 1 298 val
+ihaunqoenk 1 300 train
+ihauvmnevo 0 300 train
+ihavtmmcuc 1 300 train
+ihazqithac 1 300 train
+ihbcurfhqs 1 269 train
+ihbfgwdrto 1 298 train
+ihbhxsccyx 1 298 val
+ihbkkxqfue 1 299 val
+ihbtgqksjv 1 300 train
+ihbypjleeu 1 300 train
+ihcbivdfpb 1 300 train
+ihceabkzlk 1 300 train
+ihcgbzhszd 1 300 val
+ihckldqxzj 1 300 test
+ihclsykxlf 1 300 train
+ihcnyhddua 1 300 train
+ihcovexchv 1 300 train
+ihcxgmbubo 1 300 val
+ihdcditvcy 1 300 train
+ihdgrfnndy 1 300 train
+ihdgrsfcuz 1 300 train
+ihdopxhysr 1 300 train
+ihdpulmsbe 1 300 train
+ihdspfgwip 1 300 val
+ihdxulftot 1 300 val
+ihehfxwait 1 297 val
+ihexuaymou 1 301 train
+ihfemhgyyk 1 300 train
+ihfhpmvczt 0 300 train
+ihfiepuxlx 1 300 train
+ihflbuvazj 1 300 train
+ihfnxgddyj 1 300 train
+ihfrdmvbnw 1 300 train
+ihfrmdxlid 0 300 train
+ihgazewlbd 0 300 val
+ihgdgxsgps 1 300 val
+ihgfajpexm 1 300 train
+ihgfevczof 1 300 val
+ihgfhgjslx 1 300 train
+ihgguaghrw 0 300 train
+ihgiilzahj 1 300 train
+ihgisfmogy 1 300 train
+ihgiutlmbw 1 300 train
+ihgkxfqczm 0 300 train
+ihglzxzroo 0 300 test
+ihgnzjlmyd 0 300 train
+ihgvbkognw 1 300 train
+ihhaaurrmn 0 300 val
+ihhgledxgx 1 300 train
+ihhhahojql 1 300 train
+ihhqcdmpwa 0 300 val
+ihhrbvapzc 1 300 train
+ihhvzvasol 1 300 train
+ihhwpdsrvf 1 300 train
+ihhxwgtysm 1 300 val
+ihiazvglvn 0 300 train
+ihihvlytpy 1 300 train
+ihiixjkxlg 1 300 train
+ihiqiyyivf 1 300 train
+ihisvritca 1 300 train
+ihjbaofslw 1 300 train
+ihjcfidpow 1 300 train
+ihjcmhvqkl 1 299 test
+ihjiysecxt 0 300 train
+ihjozehfzn 1 300 train
+ihjtihwars 0 301 train
+ihjtmuxuom 1 300 val
+ihjyplgmqx 1 301 val
+ihkcjetbrc 0 300 train
+ihkenvytso 1 300 train
+ihkfvodztj 1 300 train
+ihklglsqss 1 301 train
+ihknrbxosz 0 300 train
+ihkumazszf 1 298 train
+ihkykrmigi 0 300 val
+ihlaujdmyx 1 300 train
+ihlbiaygvz 1 301 train
+ihlqfwaodz 1 300 train
+ihlwqfxdwa 1 300 train
+ihlwuzlhii 1 300 train
+ihlyskgfzv 1 300 val
+ihmdsgwsox 1 298 train
+ihmmwjfyqf 1 300 train
+ihmwekcjlb 1 300 train
+ihmwpaixuk 1 300 train
+ihmxghyfkb 0 300 train
+ihnbqgfynp 1 300 train
+ihnchuctxv 1 301 train
+ihnelbxnxa 1 300 train
+ihnheluyok 1 296 train
+ihnhxathkq 1 300 test
+ihnjwwvpbz 0 300 train
+ihnmbvgfqn 1 300 train
+ihnpipyyqj 0 300 train
+ihnykgbpuz 1 300 val
+ihnytebfcy 0 300 train
+ihobqbaibc 1 301 train
+ihocczjmdk 1 300 val
+ihofasmhmv 1 300 train
+ihohnncinv 1 300 train
+ihopudnlnl 1 301 train
+ihouqetsic 1 301 val
+ihpewuxqzb 0 300 train
+ihpgxaytlq 1 300 train
+ihpmuhivyg 1 301 train
+ihpqqcfzxy 1 241 train
+ihpscljcdw 1 300 train
+ihpswurxan 1 300 val
+ihptjcufwo 0 300 train
+ihqdkxuxzx 1 300 train
+ihqlnijfiw 1 300 train
+ihqurgivsl 1 300 val
+ihrdbdpbes 1 300 train
+ihritenrlk 1 300 train
+ihrjvevuce 1 300 test
+ihrnxtvkqr 1 300 train
+ihrvzwzbab 0 300 train
+ihrydqwojs 1 298 train
+ihsaatknnw 0 300 train
+ihshfqljic 1 300 train
+ihshihvwkk 1 302 val
+ihsjupntno 1 300 train
+ihskyixonz 1 300 train
+ihsokbmjbc 1 300 val
+ihspovngfo 0 300 train
+ihsqpjlenp 1 300 train
+ihsrhmwlre 1 300 val
+ihstncrcwa 1 300 train
+ihsxctybgk 1 300 train
+ihszkmcwvw 0 300 val
+ihtfdzsyrc 1 300 train
+ihtpucakzy 1 300 val
+ihtrtctmuf 1 300 train
+ihtsucyrjz 1 300 train
+ihtzbryflc 1 300 train
+ihubnfhyuw 1 300 train
+ihufkhecjg 1 300 train
+ihugfangyt 1 300 train
+ihugqcryfn 1 300 train
+ihujulanle 1 300 val
+ihuowoqsgg 1 298 train
+ihuxghezoa 1 300 train
+ihwgpktjiq 1 300 val
+ihwtxwoijm 1 301 val
+ihwuefyndk 1 300 val
+ihwwpkzcdn 0 300 val
+ihxgskwgvn 1 300 train
+ihxgwrlkaw 1 300 train
+ihxxnnbqha 1 300 train
+ihydjjcioo 1 300 train
+ihygpajlxm 1 300 train
+ihyjemlobn 1 297 train
+ihywkcualp 1 300 train
+ihzankgvyy 1 241 train
+ihzfgviusj 1 300 val
+ihzrsqmrxi 1 301 train
+iiabmdvcpj 1 300 train
+iiadtgzeqr 1 300 train
+iiaoukzipu 0 300 val
+iiapzhuidn 1 299 test
+iiauspoepq 1 300 train
+iiawcmhcqv 1 300 train
+iiawmjvzsd 1 300 train
+iibdamwadw 0 300 train
+iibdkbwupq 0 300 train
+iibfhdltcd 1 300 train
+iibjmruirz 1 300 train
+iibolawmoq 1 300 train
+iibsbkbegu 1 296 train
+iicdhzsfpc 1 301 train
+iichbiatyw 1 300 train
+iiclkuiexg 1 299 val
+iicmtlqqga 1 299 val
+iicreugtei 1 300 train
+iicsqtglye 1 300 train
+iicsvrikit 1 300 train
+iicvlxjayc 1 300 val
+iidakislxz 1 300 train
+iidbhoxlpr 0 300 train
+iidlzxipln 1 300 val
+iidoeyujak 1 300 train
+iidqfmfquu 0 300 val
+iidsevbnrs 0 301 train
+iidsldpnqe 1 301 train
+iidspecvyy 1 300 train
+iidsxctcam 1 300 train
+iiduzwvlrm 1 300 train
+iidxfdoplp 1 300 train
+iiefdnlzps 1 300 train
+iieoqptzec 0 300 train
+iierwkxthz 1 300 train
+iiesesoyxp 1 300 val
+iieshmvxxu 1 300 val
+iieygeizqt 0 300 train
+iifhvyebnc 1 300 train
+iifmxancxp 1 147 train
+iifpjbejaf 1 300 val
+iiftbxaamb 0 300 val
+iifumipimm 1 300 train
+iifvlgpdrg 1 300 train
+iifxnhoexx 1 297 train
+iifysqmwaj 1 300 train
+iigcoabzxw 1 300 train
+iiggbgfpsz 1 300 train
+iigmtlgees 1 300 train
+iigxexfqtv 1 300 train
+iigyhshrwe 1 300 val
+iihmevdzdw 1 298 train
+iihqpphuyy 1 300 train
+iihsdrajtc 1 300 train
+iihshrrbhs 1 300 train
+iihsomcgkj 1 299 val
+iiikdojinc 1 298 train
+iiiycdclun 1 300 train
+iiiylmxggs 1 300 train
+iijhrhgtos 1 300 train
+iijljhugfo 1 299 test
+iijnlmvfco 1 300 train
+iijnzbjyls 1 297 val
+iijosrnjho 1 300 val
+iijyezwuua 0 300 train
+iijypkhgyw 1 300 train
+iijzkqhnte 1 302 train
+iikdjnrllm 1 300 train
+iikehqxcrh 1 300 train
+iikmmjanew 1 297 train
+iikukekdol 1 300 train
+iikwjyrptu 1 297 train
+iikxnaedah 1 299 test
+iilearmcqg 1 300 train
+iilenvtqqu 1 300 val
+iilormraws 1 300 train
+iilrffkxoh 1 239 train
+iilsbfjzcs 1 300 train
+iiltwtgbby 1 300 train
+iilvxqnapt 1 300 train
+iilwgwtjlz 1 300 train
+iilxfvdyrq 1 300 train
+iilzyabbzl 1 300 train
+iimisgnmhb 1 300 train
+iimnvjpgoy 1 300 test
+iimtveeaeg 1 298 train
+iimwnevkeo 1 300 val
+iinevbpmcf 1 300 train
+iinudvalec 0 300 train
+iinyfxufxx 1 300 train
+iiogpegogr 1 300 train
+iioiaeqxcj 1 300 train
+iioipkorta 0 300 train
+iiojneutjz 1 301 train
+iioktoferc 0 300 val
+iiomvouemm 0 300 train
+iioobrdcbd 1 300 val
+iiotbjmkwm 1 298 train
+iioyrvzajo 0 300 train
+iipackcsoi 1 300 train
+iipdrmqqeq 0 300 train
+iipgclzryu 1 300 train
+iipgvwxepz 1 255 train
+iipkfcrmxn 1 300 train
+iiplpskmyq 1 299 val
+iipnaebawa 1 300 train
+iipnhxfxmp 1 300 train
+iiposhrtta 1 300 val
+iipypfugov 1 300 train
+iiqctlfpwp 1 300 val
+iiqgxwhkpd 1 300 train
+iiqvaksbky 1 300 val
+iirbdiyxrv 1 300 train
+iirzaktroz 1 300 train
+iissqmllct 1 300 val
+iisszfdrxx 1 300 train
+iiswiymvix 1 300 val
+iitcambovg 0 300 train
+iitccrleri 1 300 train
+iitjnyiukz 1 300 val
+iitkiiwmyx 1 300 train
+iitlzsowmw 1 300 train
+iitrkvtwae 1 300 val
+iituredjwx 1 300 train
+iitxiemvmx 1 300 train
+iiubmqamod 1 300 train
+iiuelnfzze 1 300 train
+iiulvjrkyv 1 300 train
+iiumieewxp 1 300 train
+iiupjenuwg 1 301 val
+iiuqymzjbp 0 300 val
+iiutsjexdl 1 302 train
+iiuvvcefth 1 300 train
+iiuxgysiec 1 300 train
+iivadqebol 1 300 train
+iivlsxmqra 1 300 train
+iivourzsfd 1 300 train
+iivpdtsjfc 1 300 train
+iivrgiqnjk 1 300 train
+iivwdmxdjd 0 300 train
+iivwkmoazr 1 300 train
+iivzxgqmwu 1 301 train
+iiwffwiyrg 1 300 train
+iiwilssrhb 0 300 train
+iiwlglequh 0 300 train
+iiwlitxnjv 1 300 train
+iiwofjbuyu 0 300 train
+iixchmxmnj 1 300 val
+iixmhsmehf 1 300 train
+iixopkmtbg 1 300 val
+iixyjcgzpw 1 300 train
+iixzlljwgb 1 300 train
+iiyaenysle 1 300 val
+iiydbikvss 1 300 train
+iiyfpjuqaf 1 300 train
+iiyqzhrkjb 1 300 train
+iiytgmceis 1 300 train
+iiytxczbiw 1 301 val
+iiyyqzftqq 1 299 train
+iiyywrzelp 1 300 train
+iizdcloziq 1 300 train
+iizmsifdpo 1 300 train
+iizsiofbik 0 300 val
+iizsrcugyd 1 300 val
+ijapbtaeju 1 300 train
+ijatjjgjhr 1 300 train
+ijazwgmpzh 1 241 train
+ijbbtmsgoj 1 167 train
+ijbkyrrgbu 1 300 train
+ijblnijmpp 1 298 train
+ijbreydpiq 1 300 val
+ijbrgmzpwo 1 300 val
+ijbtvhvhra 1 301 train
+ijbzzdlehf 1 300 train
+ijcbbewhwx 1 298 train
+ijchkulser 1 300 val
+ijcndpghrg 1 300 train
+ijcnfssqqj 1 300 train
+ijcoqidfyx 1 300 train
+ijcyeitjgy 0 300 val
+ijdjymfroo 0 300 train
+ijdqrngqsz 1 300 val
+ijdvawulhr 1 300 train
+ijdwrjrzme 1 300 train
+ijdxufetrw 1 300 train
+ijdxvnmyih 1 241 train
+ijdydipjws 1 300 train
+ijdzcjujrw 1 300 train
+ijeadznqzb 1 300 train
+ijeavgbanz 1 300 train
+ijecctqkpp 1 300 train
+ijecofxshj 1 302 train
+ijecyudlvs 1 300 train
+ijehzkozkp 1 300 test
+ijeijsupvx 1 300 val
+ijekimunpj 0 300 train
+ijeklknrdb 1 269 train
+ijeocdiijx 1 300 train
+ijeqomctsa 0 300 train
+ijevdhbymv 0 300 train
+ijfdusmbtk 1 300 val
+ijfurmuiih 1 300 val
+ijgborufon 1 300 train
+ijgcwhjkua 1 300 test
+ijgfowotbt 1 300 train
+ijgmcbwkjy 1 300 val
+ijgmqdbiww 1 301 val
+ijgnftkova 1 300 train
+ijgwwoupzf 0 300 train
+ijgzafdtqj 1 300 train
+ijhhztmidr 0 299 val
+ijiagbpwae 1 300 val
+ijicgtvikq 1 300 train
+ijidvibaqx 1 300 train
+ijiubvcsfk 1 301 train
+ijizltikkv 0 300 train
+ijjhzjhgve 1 300 train
+ijjnmqocav 1 300 val
+ijjxdsdkad 1 300 train
+ijjxgqmbfv 0 300 train
+ijjybatadp 1 300 train
+ijkkfawper 1 300 train
+ijkkhohiym 0 297 train
+ijkmnnlncj 1 300 train
+ijkswoield 0 300 train
+ijkuayfihm 1 300 train
+ijkwihnmld 1 300 train
+ijlaqnxjxt 1 300 train
+ijldxcqdtx 1 300 train
+ijlexpkluo 1 300 val
+ijlhhcoqml 1 300 train
+ijllngdkab 1 300 train
+ijlmzpbxth 1 300 train
+ijlrlsnsna 1 300 train
+ijlrvenhzk 1 300 train
+ijlyhbzvmg 1 300 val
+ijmkrmkauq 1 300 train
+ijmrwtiwvs 1 300 train
+ijncnebnuc 1 300 train
+ijnelkbuxm 1 300 train
+ijnfpkuhcm 0 300 val
+ijnkazaysb 1 300 train
+ijnlvfbgww 1 300 train
+ijnnixcnbz 1 300 train
+ijnoswozyy 1 300 train
+ijnqxlbhef 1 240 val
+ijnrqgiwvr 0 300 train
+ijnxsqppbb 1 298 val
+ijoakcedfe 1 300 val
+ijodvsnceb 1 296 val
+ijoejejcxl 0 300 train
+ijoflemgjq 1 300 train
+ijohxveeyp 1 297 train
+ijokbqmizz 1 301 train
+ijokcwewbs 0 300 train
+ijolctatjy 0 300 train
+ijolglnlhv 1 300 val
+ijolohlrbz 1 300 train
+ijopbigkhb 1 300 train
+ijpcelqdco 1 300 train
+ijpdgsydfx 1 300 train
+ijpgtptdge 1 300 test
+ijphkwnzba 1 300 train
+ijpiwerelj 1 300 train
+ijpnvvtakw 0 300 train
+ijpopdwbfd 1 300 train
+ijptjuwypg 1 300 train
+ijptktlyfr 0 300 train
+ijpxswghyk 1 300 train
+ijqihvinvq 1 241 train
+ijqpebqhwk 1 300 train
+ijqqgxjyzm 1 300 train
+ijqqrilphg 1 300 val
+ijqrvbpesp 1 300 train
+ijqvofcxuj 1 300 train
+ijqxtqvteg 1 300 train
+ijrcsnykcm 1 300 val
+ijrdhyuflu 0 300 train
+ijrlchjobl 1 300 val
+ijsldsuegi 1 300 train
+ijspqwgovc 1 300 val
+ijsuhngezc 1 300 train
+ijtcijsdch 1 288 train
+ijthkzsvdb 1 300 train
+ijtnzgvdpu 1 300 train
+ijttkzkvrk 1 300 train
+ijtujnhybj 1 300 train
+ijtuvanpki 1 300 train
+ijuaypjdjt 1 300 train
+ijubfznyue 1 300 train
+ijudojmrwt 1 300 train
+ijueytglor 1 300 train
+ijugdatjqh 1 300 val
+ijuhqdarza 1 300 val
+ijuhwltjyu 1 300 train
+ijulzuuplt 0 300 train
+ijupxdmyah 1 300 train
+ijuritvvvm 1 300 train
+ijuxicarhu 0 300 val
+ijvicicjwi 1 300 train
+ijvjxstyxn 1 301 train
+ijvkvmcpjp 1 300 train
+ijvlstcjsa 1 299 test
+ijvlxcfbhg 1 300 train
+ijvprklcmz 0 300 train
+ijvqpzanqe 1 300 train
+ijvrruppbz 1 300 train
+ijvshpufpa 1 300 train
+ijvwgmpoiy 1 300 train
+ijwlyqapnq 1 300 train
+ijwmhwupga 1 300 train
+ijwrpomqbb 1 300 train
+ijwwtiaydk 1 300 train
+ijxbyfwxse 0 300 train
+ijxfehyrhx 1 300 train
+ijxfkwzwrt 1 298 train
+ijxjjxtrsi 1 300 train
+ijxlgqqryi 0 300 train
+ijxoweqtxd 1 300 train
+ijxsawdvrz 1 300 train
+ijxtrwyjcm 1 300 train
+ijxugwjfok 1 300 val
+ijxvacjkcd 1 298 train
+ijxytxjpdq 1 300 val
+ijykzqouhx 1 300 val
+ijylmcjnys 1 299 val
+ijymhnxqjo 1 301 val
+ijzagyxghd 0 300 train
+ijzbqfymei 1 300 train
+ijzokipecn 1 300 train
+ijzqcxttbm 1 300 train
+ijzqskpdwt 1 300 train
+ijzsmdzced 1 300 train
+ikacknizqm 1 300 train
+ikaevqrstt 1 300 train
+ikafitvkwe 1 300 val
+ikaguhjtav 0 300 train
+ikahcvxmil 1 300 train
+ikavesminb 1 300 train
+ikbkruhzjl 1 300 val
+ikbwuigstb 1 301 train
+ikbwwbuhtg 1 298 train
+ikcdfwrftx 1 300 train
+ikcfxjwycf 1 300 train
+ikchbvrynn 1 300 train
+ikchunmihb 1 300 val
+ikckzwmdbr 1 300 train
+ikcpaaosur 1 300 train
+ikcxvepgks 0 300 train
+ikdjxgtpbt 1 300 train
+ikdpkieeqa 1 300 train
+ikdwzwxlgb 1 300 train
+ikeauaolws 1 300 train
+ikebjpfwok 1 241 val
+ikebomnsiq 0 300 train
+ikenynnzpi 1 301 train
+ikescldngs 1 300 val
+iketyctlsn 1 300 train
+ikezifzakr 1 300 train
+ikfcoxhsil 1 300 train
+ikfdrinras 1 300 train
+ikfhdjkmvz 0 300 val
+ikfjkeorkn 1 300 val
+ikfqwtfoyp 1 300 val
+ikfugyrtps 1 300 train
+ikfukzmrfb 1 136 train
+ikfvsnkarn 1 300 val
+ikfwhdqsgf 1 300 val
+ikfyoclumy 1 300 train
+ikgbbgwvjd 1 301 train
+ikgfhqmjnp 1 300 train
+ikgilgckkh 1 300 train
+ikgjtpvogh 1 300 train
+ikgoxgxkad 1 301 train
+ikgrgrxlvd 1 300 train
+ikgtpzlknn 1 300 train
+ikgxqbhmlv 1 300 train
+ikgxrpgikl 1 300 train
+ikgygoqdtu 1 301 val
+ikgzvuuznw 1 300 train
+ikhbolmhlp 1 300 train
+ikhgkfjbcy 0 300 train
+ikhgnbpjfk 1 297 train
+ikhhbpasuu 1 300 train
+ikhlmfaaev 1 300 train
+ikhmxowypw 1 300 train
+ikipwnlsnz 1 300 train
+ikishtowqt 1 300 train
+ikitsnjidv 1 300 train
+ikitygcbai 1 300 train
+ikiyenmfkm 1 300 train
+ikjbviykgs 1 300 train
+ikjlhrwzeo 1 300 test
+ikjnhwvtjb 1 300 train
+ikjribvcvj 1 300 train
+ikjtezfwus 1 300 train
+ikjvjeyova 1 301 train
+ikkcpnumft 1 241 train
+ikkhswmbmy 1 300 train
+ikkivspaft 0 300 train
+ikklplqeua 1 300 train
+ikknftnhnt 1 241 train
+ikkpygqiej 1 300 val
+ikkrgmcgxy 1 300 train
+ikkrwksgqk 1 300 val
+ikkukkqnoe 1 300 train
+iklirjixwf 1 300 train
+iklpucdfhr 1 300 train
+iklstyjfln 1 300 val
+iklzagpncp 1 300 train
+iklzfeueid 0 300 train
+ikmcboqjaz 1 301 val
+ikmoewqjta 1 298 train
+ikmqoljlad 1 300 train
+ikmsdmynbf 0 300 train
+ikmvzfogro 1 300 val
+iknaoncdob 1 300 train
+iknczpgabi 1 300 train
+ikndrsefac 0 300 train
+iknfqmugud 1 300 train
+iknhcerwfy 1 298 val
+iknjxxdlqm 1 301 train
+iknpverima 1 300 train
+iknssqgwmh 1 300 train
+ikoejngade 1 300 train
+ikoghnlhzc 1 300 train
+ikohxqtzhd 1 301 train
+ikojicyzvk 1 300 train
+ikokogfuzz 0 300 train
+ikoofyncxh 1 300 train
+ikoqjcdupk 0 300 train
+ikosynolad 1 300 train
+ikowbbxmlq 0 300 train
+ikpcfupfxb 1 300 train
+ikpouwpezv 1 300 val
+ikpozyocom 0 300 val
+ikpqevbkka 1 300 train
+ikpsyeypvd 1 297 val
+ikpyxzpiiv 1 300 test
+ikqbzrbwqh 1 300 train
+ikqebyugwj 1 300 val
+ikqkuyagbl 1 300 val
+ikqlryipli 1 300 train
+ikqovcqwqc 1 300 val
+ikqwulydob 1 300 train
+ikqxkmcfqh 1 300 train
+ikqymawnzl 1 300 train
+ikrblkqqcf 1 300 train
+ikrenhfmpq 1 300 val
+ikrhjeyoaa 1 241 train
+ikrifisjpm 1 300 train
+ikrkzaikdp 1 300 train
+ikschsvken 1 300 train
+iksdzvxrny 0 300 train
+iksgczilqj 1 300 train
+ikskvijggr 1 300 train
+iksntpazti 1 300 train
+ikspwznybb 1 300 train
+iksqygcnyj 1 300 val
+iksrupkidh 1 240 train
+ikssyqwtzq 0 301 val
+iksxzpqxzi 0 300 test
+iktfyxproe 1 300 val
+ikthkudeeo 1 299 test
+iktlzujalm 1 300 train
+iktrajicum 1 300 train
+iktwckbykj 1 299 train
+iktxfmdvtj 1 300 train
+ikuebqamni 1 300 train
+ikufpmogey 1 300 train
+ikurcepiqq 1 300 train
+ikusaklssf 1 301 val
+ikuxlngkzx 1 300 val
+ikuyatfgpk 0 300 train
+ikvkymvsuf 1 249 train
+ikvlzzpcbs 1 300 val
+ikvpszrfds 1 300 train
+ikvqopdfxm 1 300 train
+ikwlskwwyf 1 167 train
+ikwnyzpuea 1 300 train
+ikwqqlzzgh 1 301 train
+ikwtpiotja 1 300 train
+ikwyovlbpt 1 300 val
+ikxfjdwavu 1 301 train
+ikxhnaekof 1 300 train
+ikxhxzrica 1 300 val
+ikxiykfqdm 1 300 val
+ikxlxtlocs 1 298 train
+ikxtxxqonn 1 300 val
+ikyetixxef 1 300 val
+ikyeufgtlv 1 301 val
+ikyghoorjg 1 297 train
+ikyigvxavs 1 300 val
+ikykohofor 0 301 train
+ikykpkiymo 1 300 val
+ikyonftely 1 300 train
+ikzdbeeuwm 1 300 train
+ikzgszvxjl 1 300 train
+ikzobpnltg 1 300 train
+ikzoqrjaql 0 300 train
+ikzslayeei 0 300 train
+ilaacqlbcj 1 300 val
+iladqczmtm 1 300 train
+ilagmgypta 1 300 train
+ilakpawtbg 1 99 train
+ilaqozkyzp 1 241 train
+ilawvksiqi 1 301 train
+ilawvuwlse 1 300 train
+ilbcdkpkgh 0 300 train
+ilbdtfrsyi 1 300 train
+ilbgnioxio 0 300 train
+ilbiowpxag 1 300 train
+ilbovzthdc 0 301 train
+ilbrpcilgt 1 300 train
+ilbskswiae 1 300 val
+ilbykqrzps 1 300 train
+ilbzdmwnuv 1 300 train
+ilbzxkssci 1 300 train
+ilbzxwvfaq 0 300 train
+ilcbzdryem 1 249 train
+ilcewfduax 1 300 val
+ilcgjevjdc 1 147 train
+ilcgpzbzei 1 300 val
+ilclduxpsc 1 300 train
+ilcljbbzvq 1 297 train
+ilcncpafqo 0 300 val
+ilcphuyvrm 1 300 val
+ilcpkujaxn 1 241 train
+ilcsjmqbph 1 300 train
+ilcsznbvvu 1 300 train
+ilcvpnxftv 1 240 train
+ilcvuasffg 1 300 val
+ilcxskqhce 1 300 val
+ildnnpsayt 1 300 train
+ildymgduvu 1 299 test
+iledgzpxpf 1 300 train
+ilefzzpsik 1 300 train
+ilepaltolc 1 296 val
+ilfbhfdfai 1 300 train
+ilfdoyxlxr 1 300 train
+ilflslfgbn 1 300 test
+ilfrynyhef 1 300 train
+ilgpwvcxuq 1 300 train
+ilgrivpzfn 1 300 train
+ilhfbhuojk 0 300 train
+ilhnupngyk 1 300 train
+ilhyftifdz 1 300 train
+ilictmnqzf 1 300 train
+ilihwixpwc 1 300 train
+ilijyjnnde 0 300 train
+ilitiwfhsm 1 240 train
+ilitvuovjv 1 300 train
+ilitxgdabb 1 300 train
+iliwmonzgd 1 300 train
+iljbvsfiqt 1 300 train
+iljclsrotz 1 300 train
+iljdwnyteo 1 300 train
+iljntmugut 0 300 train
+iljopcgqtx 1 300 val
+iljvsojzzv 1 300 train
+iljxxtnxnb 1 300 train
+iljygdtztx 1 300 val
+ilkbvphctp 0 300 train
+ilkhtkopoq 0 300 train
+ilkuxqamua 1 300 val
+ilkzwzcrnh 1 300 val
+illdqjpszw 1 301 train
+illicuncku 0 300 train
+illjeenptm 0 301 train
+illjlyargm 1 294 train
+illxinqoez 1 300 train
+illxvvfiux 1 300 train
+ilmhnmfrux 1 300 train
+ilmmqjhaxy 1 300 train
+ilmqhapntw 1 298 train
+ilmqjfferi 1 300 train
+ilmrykckie 0 300 train
+ilmssrcmcm 0 300 train
+ilnbtsmfxw 1 300 train
+ilndcatvse 1 300 val
+ilnofmqzqe 0 300 train
+ilnsunnigz 1 300 train
+ilnvjuhsgh 1 300 train
+ilnxfpkirv 1 301 train
+ilnzuwvrsx 1 301 val
+iloepwbylm 1 239 train
+ilolislpjl 1 298 train
+iloqoarohp 0 300 val
+ilowgdacjj 1 300 train
+iloxmuwjpn 1 300 train
+ilpciqezyx 1 300 train
+ilpjraxjrc 1 300 train
+ilqbsmbylx 1 300 train
+ilqckieial 1 300 train
+ilqjnammst 1 300 val
+ilqkdhzwhh 1 300 train
+ilqlwbcyru 1 296 val
+ilquablxfh 1 300 train
+ilqwcbprqa 0 300 test
+ilqzdkyxti 1 298 train
+ilroifbpoq 1 300 train
+ilrqvcmvno 1 300 train
+ilrtuzmlua 1 300 train
+ilrvlrlkzu 1 300 train
+ilsiaqqane 1 301 train
+ilsntfrbrm 1 299 test
+ilspsflusm 1 300 train
+ilthkuqkih 1 300 train
+iltklvhlph 1 300 val
+iltszsufdi 1 300 train
+iltvdlztnh 1 300 train
+ilubksbtrs 1 300 train
+iluetsnbln 1 300 train
+iluitobthi 1 299 test
+ilutuvrivm 0 300 train
+iluxtdzasg 1 300 train
+iluysybcda 1 300 train
+ilvcghrcpt 1 300 train
+ilvmccdkzz 1 300 train
+ilvmgbpdga 1 300 train
+ilvmgunkie 0 300 val
+ilvnosnbxx 1 300 train
+ilvrlztoac 1 300 val
+ilvrzgvmhk 1 300 train
+ilvwzfluvs 1 300 train
+ilwecgcnwg 1 300 train
+ilwhlwlpgg 1 240 train
+ilwhnhiuds 1 300 train
+ilwwucmcze 1 300 train
+ilwxdcdstv 1 300 train
+ilwyybfuem 1 300 train
+ilxaolkkpb 1 300 test
+ilxlssjsrw 1 300 train
+ilxmktuups 1 300 train
+ilxnkpkyqj 0 300 train
+ilxpiywxyz 1 299 test
+ilxszbrras 1 300 train
+ilxtrejpxr 1 300 train
+ilxyhurnfu 1 300 val
+ilxyxdwxau 1 300 train
+ilyizpbdcl 1 300 train
+ilyrjpxeri 1 300 train
+ilyytexbev 0 300 train
+ilzhgraxpl 0 301 train
+ilzjepbyvq 1 301 train
+ilzjtlnoti 1 300 train
+ilzkmsechg 1 300 val
+ilzmflrnfq 1 300 val
+ilzqbskjjc 1 301 train
+imabxdexel 1 300 train
+imamkvpuhk 1 302 train
+imaqnshnfg 1 300 val
+imasufvwky 1 300 train
+imavfyqmvf 0 300 train
+imbhofyohf 0 299 train
+imbitycmfj 0 300 train
+imblbudkuk 1 300 train
+imbmlaeedc 1 300 train
+imbpeffied 1 300 train
+imbvmoestu 1 300 val
+imbwaliztd 1 300 val
+imbxoalbyu 1 300 train
+imbxxuipbi 1 241 train
+imcctslcgz 1 300 train
+imchoihbif 1 300 train
+imcmewblak 1 300 train
+imcmkwrvjf 0 300 val
+imcmphfsiz 1 300 train
+imczlqiicr 1 300 train
+imddvbhbpp 1 300 val
+imddwqfjmh 1 300 train
+imdjyynfry 1 300 val
+imdlfldnzh 1 296 train
+imdmhwkkni 1 300 test
+imdomcppat 1 300 val
+imdrtivkbw 1 300 train
+imdtvkomro 0 300 train
+imdvkzrlqg 1 302 train
+imehwufcox 1 300 train
+imekboagmn 1 300 train
+imelmfenoa 1 300 train
+imewumwqos 1 300 train
+imfatmxgxk 1 300 train
+imfcdepsrs 1 300 test
+imfkjxkqeh 1 300 train
+imftqaihxk 1 300 train
+imfydqnbdk 1 300 train
+imgfgyffga 1 300 val
+imgnvcjijv 1 300 val
+imgsbkytzy 1 300 train
+imgythodrm 0 301 train
+imhfmahuyu 1 300 val
+imhlojtnut 0 300 train
+imicatmqrf 0 300 train
+imieptfgsd 1 300 train
+imijeuifwl 1 300 train
+imitqivtlf 1 300 train
+imiwzsamzz 1 300 val
+imjfunevrp 0 300 train
+imjkqycpxy 1 300 val
+imjksxhpcm 1 255 train
+imjoieseuw 1 300 train
+imjrgszzcb 1 300 train
+imjvwheucs 1 300 train
+imjwqgzhai 1 300 train
+imjzmhiiuq 1 301 val
+imkbiemabm 1 301 train
+imkduomghz 1 300 val
+imkjcsdzkc 1 300 val
+imkrflgdrt 1 300 val
+imkrswmxeg 1 300 train
+imkrunyvib 1 300 train
+imkxcrifgn 1 300 train
+imkznybgcz 1 300 val
+imleeeqlhj 0 240 train
+imlfgbdpuj 0 241 train
+imljocdrfl 1 300 train
+imljyimrcs 1 300 train
+imllqoruag 1 255 train
+imlrjluidi 1 300 train
+imlsdgidgv 1 300 train
+imlsyhhwsb 1 300 train
+imlvyknzmu 1 300 val
+imlzskfxkf 1 300 train
+immfucqwhc 1 300 train
+immgxnnixy 1 300 val
+immhqqjbug 1 300 train
+immsyyzjjq 1 301 train
+immxgtbwsb 0 300 train
+immxtbujua 1 300 train
+imndctighq 1 299 val
+imndwwlfui 1 300 val
+imnhgitwer 0 300 train
+imnimaiuzj 1 300 train
+imnwrkejef 1 300 val
+imnyrjolno 0 300 train
+imnzannmcr 0 300 train
+imofwcmiht 1 300 train
+imotkfjzmz 1 240 train
+impdmlidjl 1 241 train
+impdpmbtks 1 300 train
+impgtprsqz 1 300 val
+impwkaeywx 1 300 train
+impxxyurql 0 300 train
+imqaxqoxku 1 300 train
+imqdjxgogr 1 298 train
+imqeslimbd 1 300 train
+imqovhmjea 1 300 train
+imqvdshzvd 1 298 train
+imqyuprwbb 1 300 train
+imrbxfrdoe 0 300 train
+imrcqdtgfj 1 298 train
+imrhynwmbm 1 297 train
+imrkgzauaa 1 300 train
+imrksxmclv 1 300 train
+imrlhajrpy 1 241 train
+imrnyoybow 1 300 train
+imrprfgqaj 0 300 val
+imrqjuaiix 1 300 train
+imrqvihgef 1 241 train
+imrtqcecim 1 300 train
+imrwjylmkd 1 300 train
+imrxsvorhl 1 300 train
+imsacxixmv 0 300 train
+imsfcsgabz 1 300 val
+imsssnmbdh 1 300 train
+imtcegbouk 1 300 train
+imtdwomkok 1 300 train
+imtjpvdoil 1 300 train
+imtkdzkypf 0 300 train
+imtmwlmlpf 1 300 train
+imtqhldxwh 0 300 train
+imtskvelgx 1 300 train
+imtxzghzev 1 300 val
+imuadrqqeq 1 300 train
+imubjhmvca 1 300 train
+imuelslarq 1 300 train
+imuifxhtpx 1 300 test
+imunhfzepl 1 300 train
+imuxybwcaq 1 300 train
+imvbxbuhbp 1 300 test
+imvcyiurwe 1 300 train
+imvekuisxh 1 300 val
+imvkjcocgb 1 300 train
+imvljxvuta 1 300 train
+imvmeagwqu 1 300 train
+imvptioztm 0 300 train
+imvrshlser 1 300 val
+imvtkbbdgx 1 300 train
+imvygxuvoc 0 300 train
+imwccvidud 0 300 train
+imwrhaxipv 1 300 train
+imwtonmaac 1 300 train
+imwugsuclz 1 300 val
+imwxooampn 0 300 train
+imxclqmepu 0 300 train
+imxjyoomdb 1 300 train
+imxwnvwnwm 1 300 val
+imxzpqdacr 1 300 train
+imycfiyabj 1 300 train
+imyxeippti 1 300 train
+imzbwkuyrp 1 300 train
+imzgjqnefb 1 302 train
+imzjrqqohz 1 300 val
+imzntehmul 1 300 train
+imzofsrbne 1 298 train
+imzpiqvcnt 1 301 train
+imzpztemle 0 301 train
+imzqmbfugn 0 300 train
+imzuxqzjfy 1 301 val
+imzyvtgzng 1 300 train
+imzzprbmjt 1 300 train
+inacpvwijz 1 300 train
+inaegnmolg 1 300 train
+inahbqltbz 1 300 train
+inaziagfks 1 300 train
+inazucxqwp 1 300 train
+inbbyulhvi 1 300 train
+inbkxxjlvs 1 300 train
+inbngwptcq 1 300 train
+inbpxfegeq 1 301 train
+inbreubvej 1 300 train
+inbtxveqxx 0 300 train
+inbxdaipwx 1 241 train
+inbygpzdds 1 300 train
+inbykqedho 1 300 train
+incavslche 1 300 train
+incjzplcas 1 300 train
+incntknemt 1 300 train
+incwjyqmnr 1 300 train
+indhegsbew 1 300 val
+indjhijlne 1 300 train
+indjkegkrh 1 299 test
+indoiqhinq 0 300 train
+indpmjtgbg 1 300 train
+indujzhckh 1 300 train
+indunhbset 1 300 train
+indvfeemhp 1 300 train
+indxcmhxac 1 300 train
+inelcrkike 0 300 train
+inelwzcgih 1 300 train
+inemzkdvkp 1 302 val
+ineolokmqv 1 300 train
+ineriwbkom 0 300 train
+inesnaprwm 1 300 train
+infejzfghd 1 301 train
+infeotylrv 1 300 train
+infktzjqjf 1 300 val
+infnnslrwc 1 300 train
+infqarzfqf 1 300 train
+infuizswzf 1 300 val
+infvyhmoiu 1 300 val
+infwsvmogx 1 300 val
+ingbgiktpv 0 300 train
+ingbljxmtb 1 301 val
+ingbvhtzhs 1 300 val
+ingdpgpzso 1 300 train
+inglifhicn 1 298 val
+ingljnyuhv 1 300 train
+ingtbpvean 1 300 train
+ingywwbqyj 1 300 train
+inhdjqusao 1 300 train
+inhgwrzvnu 1 300 train
+inhhnmbumo 1 300 train
+inhkkezkhu 1 301 val
+inhobwkrgo 0 300 train
+inhwftsrga 1 301 val
+inidddgtbx 1 300 train
+inidoxpeji 1 300 train
+inimyjcere 1 300 train
+inirakibnb 1 300 val
+iniunlnbxq 1 300 train
+iniyhknsde 1 302 train
+iniyzlhckx 1 300 train
+injaswpjgj 1 300 val
+injcjmrtyq 0 300 val
+injepvztjq 0 300 train
+injmftmbii 1 300 train
+injosxqgxb 1 300 train
+injpbivosc 1 300 train
+injrbbdyor 1 300 train
+injwbiynxe 1 300 train
+inkhvrrrxc 1 240 train
+inkqxytzyu 0 300 train
+inkvlhzprb 1 300 train
+inkxsksvfs 1 300 train
+inkxxqwrzi 1 300 val
+inlaxnqier 0 300 val
+inlffmoxpe 0 300 train
+inlolpxukt 1 300 train
+inlulnqgjf 1 300 val
+inlurljyft 1 300 train
+inluuhjteb 0 300 train
+inlxicysby 0 300 train
+inmfczqyrh 1 300 train
+inmfjthhci 0 300 val
+inmmctcqam 1 301 train
+inmnzzgnop 1 300 train
+inmqhfujch 0 300 train
+inmwakldeq 1 302 train
+innaeobksi 1 300 train
+innafzyoeq 0 300 train
+inneixkosf 0 300 train
+innekexcog 1 300 train
+innfhbljwv 1 300 train
+innnxjnjzg 0 300 train
+innoflkfcx 1 300 train
+inntpctwlu 1 300 val
+inntvbzhhz 0 298 train
+innwilygih 0 298 val
+inobonhufr 1 300 val
+inocfgtpyx 1 300 val
+inoekwduag 0 300 train
+inoiadjgym 1 300 val
+inoiowakav 0 300 train
+inoknwbrzl 1 302 train
+inorgluytn 1 300 val
+inoujepcty 1 300 val
+inpdbngrai 1 300 train
+inpiiokedd 0 298 train
+inplaontrb 1 299 train
+inptsqeimo 1 300 val
+inpyubrqgk 1 300 train
+inqeczqphc 1 300 train
+inqspshazx 1 300 val
+inqutjlcig 1 300 train
+inqzzkerdt 1 300 train
+inraaqfdik 1 302 train
+inreuldnic 0 300 val
+inrgjckdhl 1 301 train
+inrkmarkbw 1 300 val
+inrodxmtmz 1 300 train
+inromowfjl 1 300 train
+inrtevolac 1 300 train
+inryigxeuq 1 299 val
+insaitlrup 1 300 train
+insbnbhqxw 1 299 train
+inscrqakxp 1 300 train
+inshqgypap 1 300 val
+insnamzdii 0 300 train
+inspmkixlc 1 300 train
+inssowioup 0 300 train
+intaxqjkpa 1 300 train
+intbjzmqjb 1 300 train
+intdikbydt 1 300 train
+intgifgoei 1 298 train
+intjehdtxz 1 299 val
+intjrgoddn 1 300 train
+inttuqkvbl 1 300 train
+intvelmsah 1 300 train
+inuntgvmfo 1 300 train
+inuroqwmwr 1 300 val
+inusdrqzhz 1 300 train
+invdiiotkx 0 300 train
+invewpqigy 1 300 train
+invftgiqmf 1 300 val
+invgswjxql 1 300 train
+invphykbjo 0 300 val
+invykqpihq 1 301 train
+inwaznexiv 1 301 train
+inweoetzvh 1 301 train
+inwiunnxmr 1 300 test
+inwjmrkgid 1 300 val
+inwncrbasw 1 300 train
+inwvkwgbae 1 300 train
+inwxkyqmvm 0 300 train
+inwzklmdfv 1 300 train
+inxdbjiqun 0 300 train
+inxftbkcqq 1 300 test
+inxsfqysmb 1 300 train
+inxvgjgrrq 0 300 train
+inxwsysntf 1 300 train
+inxytnffpi 1 300 val
+inycevlxpp 1 300 val
+inyghuvekb 1 300 train
+inyhbidemg 1 300 train
+inyhiitiqt 0 300 train
+inyhmnubqq 1 300 train
+inyptqqeru 0 300 train
+inytmlhyrm 1 300 train
+inyzwblrvn 1 300 train
+inzgulrorj 0 300 train
+inzhijvyev 1 300 train
+inzlbdwkpz 1 300 val
+inzlvwlpks 1 300 train
+inzlwmtulv 1 300 train
+inzqoiwoae 1 300 train
+inzrlbgtul 1 300 test
+inztcghfvo 0 300 train
+inzwsvpsah 1 300 test
+inzystwyud 1 301 train
+ioabsxkrvu 0 300 val
+ioafctqohg 1 269 train
+ioagaknzxx 1 167 train
+ioajvwjkbn 1 300 val
+ioakowtmul 1 300 train
+ioasajmdzf 1 300 val
+ioatsvnnur 0 300 val
+ioawppxuxf 0 300 train
+ioaxbkdyea 1 300 train
+iobexjisxq 1 300 train
+iobfmxwakb 1 300 train
+iobnxqtkgg 1 300 val
+iobunwzuda 0 300 val
+iobvxlnbwn 0 300 train
+iobxbrimou 1 300 train
+iocbhpfbso 1 300 val
+iocecnmdzm 1 300 train
+iocjgjemeb 1 300 test
+ioconbamkx 1 300 train
+iocpymnnba 0 300 train
+iocstgmnkp 1 300 train
+iocvcalewi 1 300 train
+iocwywwedi 1 300 train
+iodccitsyt 1 300 val
+ioddadfqdf 1 300 train
+iodhnjvlby 1 300 train
+iodibdwzeh 1 300 train
+iodkhhuixd 1 298 train
+iodkwujahf 0 300 train
+iodlgyzcsj 1 300 train
+iodlnqsuzm 1 300 train
+iodvtuacfh 1 300 train
+iodwjkqblp 1 300 val
+iodxbnqlsd 1 300 val
+iodxwskxmp 1 300 val
+iodykticnh 0 300 train
+ioeggkpjpv 1 241 train
+ioeiuvnnea 1 300 train
+ioenlnghvz 1 300 train
+ioephjampr 1 300 train
+iofakbvbis 0 300 val
+iofcqfflsx 1 300 train
+iofnzcsfzb 1 300 train
+iofoynuaqe 0 300 train
+iofvhfkugm 1 300 val
+iofxdadhjp 1 300 train
+iofyzcmfzn 1 300 train
+ioghjkwzgj 1 300 train
+ioghtcqpws 0 301 val
+iogkhwjqsg 1 300 train
+iogpvrelcc 1 300 val
+iogqyamcnr 1 300 train
+iogrkojxwc 1 300 train
+iogwwljjzs 1 300 train
+iohbhuwztq 1 300 train
+iohdbhydzx 1 300 train
+iohenqlegu 1 300 val
+iohgusmdwv 1 301 train
+iohmidrrqq 1 300 train
+iohpkzeoqv 1 296 val
+iohuzwvefi 0 301 train
+ioibyufhmd 1 300 train
+ioiixdtwnb 1 300 val
+ioijmbftxg 1 301 train
+ioiqejhmtf 1 296 train
+ioitqcvyuk 0 300 train
+ioiuywspyh 1 300 train
+ioiwzbafjy 1 300 train
+iojdmuyccj 1 299 val
+iojhndegmj 0 300 train
+iojmxrzvxe 1 300 val
+iojrefzdlz 1 300 train
+iojwofhnwj 1 300 val
+iokehbsbni 1 300 train
+iokhkqmhgw 1 300 train
+iokiuqvept 1 300 train
+iokqzthjft 1 300 train
+ioksdjdlwf 0 300 train
+iokxwxptiz 1 294 train
+iolcskuitk 1 297 train
+iolewuiamx 1 300 train
+iolgfhdhwl 1 300 train
+iolggovffj 1 300 train
+iolhfuzywn 0 300 train
+iolnrlkuou 1 301 train
+iolxctpvjw 1 300 train
+iolzdxcdlv 1 300 train
+iomeepgxuc 1 300 val
+iomhrpdypg 1 300 train
+iomixyprpe 1 300 val
+iomrpnpqyn 0 300 train
+iomwswsmzr 1 300 train
+iomxmfsdim 0 300 train
+iondvzqjbe 0 300 train
+ionjkxysgw 0 300 train
+ionmsllaxk 1 300 val
+ionnyalzrj 1 300 train
+ionpldbxqj 1 300 val
+iontvvcfzc 1 300 val
+iooavikatq 1 300 train
+iooczipycv 1 300 val
+ioolqahamw 1 300 test
+ioolxkxehd 1 300 train
+ioopqynust 1 301 val
+ioopziywwb 0 302 train
+iootzzehig 1 300 train
+iopaywxzcj 0 239 train
+iophbjompx 1 300 train
+iophwenimv 1 300 train
+iopprxmdrl 1 300 val
+iopuzbpmuy 1 300 val
+ioqacgyrwh 0 301 train
+ioqsgldfpc 1 300 train
+iorbtaarte 0 300 test
+iorelxckyf 1 298 train
+iorflqhzwd 1 300 train
+iorhxrlbuy 1 300 train
+iorisovmxr 1 300 test
+iorjrlpnfj 1 300 val
+iorlcxibbb 1 300 train
+iormenbpxv 0 300 train
+iorpzvnxai 1 300 train
+iorrnxiyyo 1 300 test
+iorrylopzn 1 300 train
+iorsjvmyib 1 300 train
+iorsunvbyy 1 298 train
+ioruwzdrhe 0 300 train
+iosdqvewkt 1 301 train
+iosfhlelkz 1 300 train
+iosfkthgtj 1 300 train
+iosheiybrn 1 300 train
+iosljkpvnt 1 300 train
+iosnfmelus 1 300 test
+iostcayhox 1 300 train
+iosvcobakp 1 300 train
+iotdvbrdkj 0 300 val
+ioterlulny 1 301 val
+iothpbzfcg 1 300 train
+iotiicpogb 1 300 train
+iotikwpoyv 1 300 train
+iotljxkhvm 1 300 train
+iotvvdegmx 1 301 train
+iotwxkwswd 1 300 train
+iouczsufhs 1 300 train
+iougvrixla 1 300 train
+ioujtlguyo 0 300 train
+ioumhcdmbd 1 300 train
+ioumwfvogk 1 300 train
+ioupchhadz 1 300 train
+iouptolpal 1 300 train
+iourrcefei 1 300 train
+iouugpzbkk 1 300 train
+iouymhtfaw 1 300 train
+iouyqtrcxe 1 300 val
+iouzgtlkul 1 241 train
+iouzqpjvrm 1 300 val
+iovaicrqwx 0 300 val
+iovaodyezs 1 300 val
+ioveedzanu 1 302 train
+iovjcaptmz 0 300 val
+iovkjpgpva 1 301 train
+iovncdznue 1 300 train
+iovndfczkm 1 298 train
+iovrwuyfyy 1 298 train
+iovtgtimjc 1 301 val
+iovubdzhoh 1 298 val
+iovwbhibas 1 300 train
+iovwepqsrz 1 300 val
+iovwnxhyns 0 300 train
+iovykwzdjv 0 300 train
+iovyuzcrsy 1 300 train
+iovzovzfgc 1 241 train
+iowaqjdoxq 1 300 val
+iowiacgesi 1 301 train
+iowiznmnnd 1 300 val
+iownzvcdqv 1 300 train
+iowuapuwjr 1 300 train
+iowysiowwy 1 297 train
+ioxkqfokjj 1 300 train
+ioxoankfxd 1 300 train
+ioxqaejrhq 1 300 train
+ioxqvriziv 1 300 train
+ioxqwxbnhu 1 298 train
+ioxuwhhvge 0 298 train
+ioxvbxicwx 1 300 train
+ioybbttazq 1 300 train
+ioyetmvwyk 1 300 train
+ioyizgxnmo 1 300 train
+ioykzunylo 1 300 train
+ioyudnyavy 1 300 train
+ioyuxjqdrt 0 300 train
+ioywetfnyb 0 300 val
+ioyymihitf 1 300 train
+iozhmdxllt 1 300 train
+iozmtepcjz 1 301 val
+ioznlapftt 1 300 train
+iozoxnbnae 1 300 train
+ioztkmjhbg 1 300 train
+iozztujesd 1 300 train
+ipakfzcdvv 1 300 train
+ipamxpknjh 1 300 train
+ipaqrjidab 1 300 train
+ipbdzgqssd 0 300 train
+ipbhlhadsy 1 300 train
+ipbjdcieix 1 300 train
+ipblyaohlp 1 301 train
+ipbqhrfply 1 300 train
+ipbqxvryms 1 297 train
+ipbunnjfbm 0 300 train
+ipbyairara 1 300 val
+ipceevmvfn 1 300 train
+ipckigpivk 1 300 train
+ipcosodfbo 1 300 val
+ipcpkkjdeb 1 301 val
+ipdbmwlfml 1 300 train
+ipddmnkswh 1 300 train
+ipdebdvqtc 1 300 val
+ipdjzhfths 1 300 train
+ipdnavunpx 0 300 train
+ipdvelopxz 1 300 train
+ipdvhtudnz 1 300 train
+ipdzfnlidh 1 300 train
+ipecmeuibp 1 240 train
+ipehaqtcgz 1 300 train
+ipemtttinh 1 300 train
+ipenghibrw 1 300 train
+ipepalibrz 1 300 val
+ipescrcxli 1 300 train
+ipetzkwdir 1 300 train
+ipeujcomet 1 300 test
+ipewbhfpen 0 300 train
+ipfbkyfhlv 1 300 train
+ipffiwpnpn 1 300 train
+ipfkiydwqq 1 300 train
+ipfkxzbarx 1 300 train
+ipflfpnkmh 1 300 train
+ipfpbylbwc 1 302 train
+ipfpsswiiw 1 300 train
+ipfqjfqfkn 1 300 val
+ipfvrgbjrm 1 300 train
+ipfymkbexs 1 300 train
+ipgikzjqty 0 301 train
+ipgmmdtpvb 1 300 train
+ipguckbegp 1 300 train
+iphmozjvef 1 300 train
+iphmuypnxl 0 298 train
+iphoxkieyc 0 300 train
+iphspqugeu 1 300 train
+iphzhcoahy 1 298 val
+ipibsjqofq 1 300 train
+ipijpsawpc 0 300 train
+ipijvlwetn 1 300 train
+ipiqsbnuux 0 300 train
+ipiqzekfkc 1 300 train
+ipisbnwavn 1 300 train
+ipisvmpxfd 0 300 train
+ipiwxfaxgn 1 299 train
+ipjbvkupug 1 298 val
+ipjdmgxxrd 1 297 train
+ipjdsflfcd 1 300 train
+ipjfbgagrj 1 301 train
+ipjivmsrdi 1 300 train
+ipjjcmuira 1 301 train
+ipjjgqdfcg 0 300 train
+ipjmvcgdhw 1 300 val
+ipjonswcfn 0 300 val
+ipjvzjdfja 1 300 train
+ipjyqcbvyl 1 300 train
+ipkcgogvxm 1 300 train
+ipkjiduclj 1 300 train
+ipkkhwgnok 1 300 train
+ipklchignw 1 298 val
+ipknjeuhyx 1 300 train
+ipkpxvwroe 1 300 test
+ipkrhqanqp 1 300 train
+ipkuhxqmyx 1 300 val
+ipkyxmxjiz 1 301 train
+iplbpvezof 1 300 train
+iplfwctspt 1 298 val
+iplgviptfg 1 300 test
+iplhyqiary 1 300 train
+iplptdkuih 1 300 train
+iplrrxmwgt 1 300 train
+ipmaldzjwp 1 300 train
+ipmhrvxkrb 1 300 val
+ipmqfvmqcf 1 300 train
+ipmwgbmbjb 1 300 val
+ipnahkyzem 1 300 train
+ipnbamklnj 0 300 train
+ipnkpesmhd 1 301 train
+ipnlfqlqcc 1 298 train
+ipnlndiupb 1 300 train
+ipnolrawqj 1 301 train
+ipnuvehtbk 1 300 train
+ipnxcxbofs 1 300 train
+ipogquizmd 1 300 train
+ipokrzvhah 1 300 train
+ipolpruzgf 0 300 train
+ipopeacpus 1 300 train
+ipouzwmwit 1 300 val
+ipowmecrzs 0 300 val
+ippbxefskg 1 300 train
+ippdksnvxw 1 300 val
+ippfrlcmdo 1 300 train
+ippnanamvr 0 300 val
+ipppoirbiy 0 300 val
+ipprkorglm 1 298 train
+ipqawcymqh 1 300 train
+ipqcfnivsy 1 300 train
+ipqczngolu 1 241 train
+ipqistxtpz 1 300 train
+ipqkumytiv 1 300 train
+ipqrxfuqgd 1 300 train
+ipqupfeioc 1 300 val
+iprelosufd 0 301 train
+ipriwqdeci 0 300 train
+iprmrrxtle 0 300 train
+iprofmwjpa 1 301 train
+iprrhqrxvd 1 298 train
+iprudfcwdb 0 300 train
+iprvpwboni 1 301 train
+ipryudzonr 0 300 val
+iprzgkjisv 1 300 val
+ipsbxiaxme 1 300 train
+ipsczjlent 1 300 train
+ipsplisdwh 1 300 train
+ipsqwydoob 1 300 val
+iptenipepy 1 300 train
+iptndwhwjz 1 300 val
+iptyeiuiwr 1 300 train
+ipudumrvde 0 300 train
+ipujpicjxw 0 300 train
+ipuniglqkv 1 300 train
+ipuxlomcqk 1 300 train
+ipvdvnzxmh 1 300 train
+ipvhfryoxj 1 300 train
+ipvjznvcjj 0 300 train
+ipvkilztsq 1 300 val
+ipvkozalyn 1 300 train
+ipvrhowqzf 1 298 train
+ipvtjixuqg 1 300 train
+ipvurtxdld 1 300 train
+ipvwtgdlre 1 299 test
+ipvzfekfwu 0 300 train
+ipwafisikd 0 300 train
+ipwgfsrsyn 1 300 train
+ipwgilocco 1 300 val
+ipwisogbru 1 297 train
+ipwjfhtnmz 1 301 val
+ipwqihnyol 1 300 train
+ipwroeubye 1 300 train
+ipwtqallyo 1 299 test
+ipxjjryovj 1 300 train
+ipxktsqwmw 1 299 train
+ipxkxfgeuz 1 298 train
+ipxqeofmby 1 300 val
+ipxsymswgp 1 300 train
+ipxvvnscml 1 300 train
+ipyqkokery 1 300 train
+ipysfppvox 1 300 train
+ipywaoscpa 1 300 train
+ipyzcqognn 0 300 train
+ipzfknmvdr 1 600 train
+ipzntfgcbe 1 300 train
+ipzrldinfx 1 239 train
+ipzwmxtfrl 1 300 train
+iqafvrphec 1 300 val
+iqahjxovvu 1 300 train
+iqapgukwmc 1 300 train
+iqapiwnsmu 1 300 train
+iqayiurwtv 1 300 train
+iqaylplffo 1 301 train
+iqbavyrfyl 0 300 train
+iqbbhffuzi 1 301 val
+iqbitqhmax 1 255 train
+iqbiubquwk 1 300 train
+iqbonigbsw 1 298 train
+iqbowezbud 1 300 val
+iqbrblvxvk 1 300 train
+iqbrkqgoje 1 300 train
+iqbrvsqmsc 1 300 train
+iqbxtedpfl 1 301 val
+iqbxvhzmim 1 301 train
+iqbxycpzru 0 300 train
+iqbzjoweap 1 299 test
+iqcgvkabeg 1 300 train
+iqclpotodm 1 300 train
+iqcrbrzzrn 1 300 train
+iqcskvpkuz 1 300 train
+iqcvtsxryj 1 300 train
+iqczmlmmzx 1 300 train
+iqczwyywit 1 300 train
+iqdqqzhnfs 1 300 train
+iqdtdnkcff 1 300 train
+iqdxlygogh 0 300 train
+iqebgcigjj 1 300 train
+iqedbspdto 1 300 train
+iqefaeoeij 0 300 train
+iqehocsylf 1 300 train
+iqejqjawox 1 300 train
+iqeneddttw 1 300 train
+iqeprlbngc 1 300 train
+iqeskcfbqm 1 300 train
+iqezpeuzhz 1 300 train
+iqfisfoptm 0 300 train
+iqflylhqvh 1 300 train
+iqfrtunuqq 1 300 train
+iqfsgocljr 1 300 train
+iqfwtkamgi 1 300 train
+iqfxqwqtpe 1 300 val
+iqgadqmpqb 1 300 train
+iqgbjjyyge 1 300 train
+iqgcofuajv 1 300 train
+iqgfxqewgi 0 300 train
+iqgiirciwn 1 300 train
+iqgilxproe 1 241 train
+iqgmjgjrsy 1 300 train
+iqgrebkqto 1 300 train
+iqgrzqqlhy 0 300 train
+iqgvagxdrg 1 298 train
+iqgxpctdvo 1 299 train
+iqhazmimer 1 300 val
+iqhhmhmfjd 1 301 train
+iqhivuhyax 1 300 train
+iqhjifcniy 1 300 train
+iqhllschqx 1 300 train
+iqhpjrotso 1 300 train
+iqhvvdkndu 0 300 train
+iqifzxqlqo 1 301 val
+iqigcfmdmy 0 300 train
+iqigctdqhj 1 300 train
+iqigcvwgji 1 300 train
+iqikyrhldk 1 300 train
+iqiudfgimd 1 300 train
+iqjeozgryv 0 300 val
+iqjffnydwu 1 300 train
+iqjntoiidb 1 299 test
+iqjosshlgo 1 300 val
+iqjrxdzowd 1 302 train
+iqjtsrlatk 1 300 train
+iqjzxqooem 1 300 train
+iqkdtvdhhy 1 300 train
+iqkertesgx 1 300 train
+iqkhdjjxes 1 300 val
+iqkhnngquf 1 300 val
+iqkkhxoudo 1 300 train
+iqklsrgdjj 1 299 val
+iqkmwmrstl 1 300 train
+iqknxvurxt 1 300 train
+iqlbivxagm 1 300 train
+iqlcvxtmvr 1 300 train
+iqlheybaqw 1 300 train
+iqlhosbqro 1 300 val
+iqllublvez 1 300 val
+iqlmoluucd 1 300 train
+iqlnkvxslo 1 300 train
+iqlpoumvoy 1 241 train
+iqlydlfxsn 1 300 train
+iqlyjgkbrf 1 298 train
+iqlypuzupc 1 298 train
+iqmaenrypb 1 298 val
+iqmgafjzkp 0 300 val
+iqmgbwcenp 1 301 val
+iqmipjshrc 1 300 val
+iqmjemfchp 1 300 val
+iqmkwrcyqs 1 300 train
+iqmloztrck 1 300 train
+iqmnjobdob 1 300 train
+iqmrwmuowt 1 292 train
+iqmsjrspvp 1 301 val
+iqmvdrhndp 1 300 train
+iqmvrahukb 1 300 val
+iqmwiatvqg 1 300 val
+iqmwzjyksk 1 300 val
+iqnbkusoup 1 300 val
+iqndppeoav 1 300 train
+iqnjflxbjz 1 241 train
+iqnkribxkk 1 300 train
+iqntgsdimp 1 300 train
+iqnvkkewxi 0 300 train
+iqoeuzalkd 1 300 train
+iqoguhfzlj 1 300 train
+iqokmoltrr 0 300 train
+iqopoamixz 1 300 train
+iqoqctfmec 1 241 train
+iqovzvsvkn 1 300 train
+iqpauxrmqa 1 300 train
+iqpavczptd 1 300 val
+iqpckowwia 0 300 val
+iqpcsxzxci 1 300 train
+iqpekmaxgn 1 300 train
+iqpgamxbtt 1 300 val
+iqpifizagt 1 300 train
+iqprtphahc 1 300 train
+iqptikhiak 1 301 val
+iqqbkfscte 1 300 train
+iqqckuassu 0 300 train
+iqqejyggsm 1 298 train
+iqqihawllx 0 300 train
+iqqutdwnya 1 300 train
+iqrafkqzwz 1 300 val
+iqragpsbvg 1 300 val
+iqrbtffyox 1 300 val
+iqrgkuetsl 1 300 train
+iqrgwnfkga 1 301 train
+iqrixqebob 0 300 train
+iqrjuczuxb 1 300 train
+iqrkbsiuql 1 298 train
+iqrppejtwk 0 300 train
+iqrqhrixfp 1 300 val
+iqruxnyhfx 0 300 train
+iqrzppimhu 1 300 train
+iqsceqxotz 1 300 val
+iqsfvftycm 1 300 train
+iqsnklbmtv 1 300 train
+iqsufzqxlt 1 300 val
+iqsxnucxvo 1 300 train
+iqtebusqwh 1 300 train
+iqtlsawhqe 1 300 val
+iqtmskvmhw 1 300 train
+iqtojehgyl 0 300 train
+iqttukcyth 1 300 train
+iqtutmwfui 1 300 train
+iqtyytiicl 1 298 train
+iqubmhnfvq 1 300 train
+iqueupwckw 1 300 train
+iquhufkwjb 1 300 train
+iqukofwxuo 1 298 train
+iqupvubgpm 1 300 train
+iqurlbdywx 1 300 val
+iquxmnsbsg 1 300 train
+iqveahxmir 1 146 train
+iqvfopywpa 1 300 train
+iqvjhwaith 1 241 train
+iqvkbrbikt 1 300 train
+iqvnqsjhvo 1 300 train
+iqvopopbsr 1 300 train
+iqvucokjmf 0 300 train
+iqvvykallr 1 298 val
+iqvwppnoyc 1 298 train
+iqvwuckgkb 1 301 val
+iqvxawitga 1 300 train
+iqwlhkekpi 0 300 train
+iqwqdhdeco 1 300 train
+iqwvzsizfk 0 300 train
+iqxebazshx 1 300 train
+iqxgcmdbgq 0 300 train
+iqxkenmlnj 1 300 train
+iqxoxvkxbe 0 300 train
+iqyegfhuzr 1 300 val
+iqyenueqqd 1 300 train
+iqyflpepap 1 300 val
+iqygikiopj 1 301 train
+iqygwedtaf 1 300 val
+iqygzjmnpv 0 300 train
+iqylhfxyjm 1 300 train
+iqytnszjzg 1 302 train
+iqyzgnhgxt 1 300 train
+iqzaghrmke 1 300 train
+iqzgrscbcu 1 300 train
+iqzhjtoooh 1 300 train
+iqzidqnjru 1 300 train
+iqzjzifjuj 1 300 train
+iqzolthqdz 1 297 val
+iqzoqolccf 0 300 train
+iqztejoljo 1 300 train
+iqztfmomng 1 300 train
+iraeybzebd 1 300 train
+iragwxtzhe 1 300 train
+irahmepbqx 1 241 train
+iramathzcf 0 300 train
+iraqiguwzo 1 300 val
+irbixkoiqa 1 300 val
+irbizraspf 1 300 train
+irbmsvytsj 1 300 train
+irbpxgovsr 1 300 train
+irbrcmywek 1 300 train
+irbuixhcdk 1 300 train
+irbwxygqmw 1 300 train
+irbyfpqxhh 1 300 val
+irbzbjifpc 1 300 val
+ircdznwjbc 1 298 train
+irchtoqkzy 1 300 val
+irchzvigec 1 241 train
+ircjfntqit 1 300 train
+ircmvzkosl 1 300 train
+ircosowvze 1 300 train
+ircsmgmpxv 1 300 train
+ircwajsosw 1 302 train
+ircydspglx 1 300 train
+irczlsrzjp 1 300 train
+irddfguovg 1 300 val
+irddxofanc 1 300 train
+irdgkhvigm 1 301 train
+irdptfgpbb 0 300 train
+irdpurucmt 0 300 val
+irdrzxhiin 1 300 train
+irdvfgizvd 1 300 train
+irdvzkphza 1 300 train
+irdwvrawqk 1 300 train
+irdywayooz 1 300 train
+irdzxtwifh 1 301 val
+irebuxgkwa 1 300 train
+iredotbulx 1 300 test
+irenrgtxix 1 300 train
+irerylmdmc 0 300 train
+iresqbfced 1 300 train
+irexjenpki 1 300 val
+ireymetjjh 0 300 val
+irfhrdweqh 1 300 train
+irfjbqscfl 1 300 train
+irfjupnsiq 1 300 train
+irftbeawzx 1 300 train
+irftxtbitj 1 300 train
+irfuitcbqf 1 300 val
+irgceawdsw 1 300 val
+irgflfnrkf 1 300 train
+irgfnlmksm 1 300 train
+irgpledmve 0 300 train
+irgsarzzlq 1 300 train
+irgvyejdfp 1 300 val
+irgxbyjbgu 1 301 train
+irgxysozjn 1 300 train
+irhemohuaj 1 300 train
+irhlokwbsm 1 300 train
+irhrqtvtgh 1 300 val
+irhspphnzz 1 300 train
+irhthgpkcx 1 300 train
+irhtyxmpri 1 300 val
+irhuesaenu 0 300 train
+irhvksasls 1 300 train
+irhyfeekdz 1 300 val
+iriadhnmyy 1 300 train
+irihhcabrv 1 300 train
+irijruhkdu 1 300 train
+iripapzncy 1 300 train
+irivcxhvrf 0 300 train
+irixdjtwpp 1 300 val
+irjbrwpqqd 1 300 train
+irjbukzjqt 0 300 train
+irjcjvedbw 1 301 train
+irjcquleuq 1 298 train
+irjequwudq 1 300 train
+irjhgojodp 1 300 train
+irjppgbdrr 0 303 train
+irjsumzeie 1 300 train
+irjxqznjfr 1 300 train
+irjywrjaqj 1 300 val
+irkhpbpwkp 1 299 val
+irknbykoow 1 300 train
+irkoxdyxgd 1 300 train
+irkrdbjkkv 0 300 train
+irkrikaons 1 300 train
+irkrldfmeg 1 300 train
+irkzgutang 1 300 train
+irlauykigp 1 298 train
+irlgidcrvj 1 300 test
+irlirvbphb 1 300 train
+irlisfshaq 1 300 train
+irllssqurg 1 300 val
+irlpnzqgrt 1 300 val
+irlqofwvmf 0 300 train
+irmbmznryg 1 300 train
+irmdgkpcgn 1 300 train
+irmimyuumh 1 300 train
+irmkoxrfni 1 300 train
+irmovzxqhw 1 300 train
+irmpbhnlrc 1 300 train
+irnbobloeg 0 300 train
+irnbxnqqzh 1 300 val
+irnctqemlo 1 300 val
+irnejrdgex 1 300 train
+irnflhiciu 1 300 test
+irnfmcgvrf 1 99 train
+irnfnmfxtq 0 300 train
+irnsrjoymh 1 300 train
+irnveqlhio 1 300 train
+irnxtdqahj 1 300 train
+irorfgbnem 1 300 train
+iroszqzgeb 1 300 train
+iroyrldewp 0 300 train
+irpleglwzn 1 300 train
+irpvjndavi 1 300 train
+irqifzfaut 0 298 train
+irqmnljizu 1 301 train
+irqzdokcws 0 300 test
+irrabetdyo 1 300 train
+irriroabtu 0 300 val
+irrmczxsly 1 300 val
+irrupftbpj 1 300 val
+irrvmjbowk 0 300 train
+irsakqrxbp 1 240 train
+irsbnnwdrn 0 301 val
+irskrrghuf 0 300 train
+irslbryzin 0 300 train
+irsrloocbi 1 300 train
+irswdclxag 1 300 train
+irtjjofhwa 1 300 val
+irtnypbxas 1 300 val
+irtrgajtwq 1 301 train
+irtyyuhhqy 1 300 train
+irufgcupir 1 300 train
+irugtoxdrz 1 300 val
+iruhgcdiww 1 300 train
+irukgvcdsl 0 300 train
+irukyuwbfb 1 301 train
+irumthqbgv 1 300 train
+irurxjcnqr 1 300 train
+irvjozgtkm 0 300 val
+irvmkbgvav 1 300 train
+irvpbmilew 1 300 train
+irvvuayhjl 1 300 train
+irvwwgpili 1 300 train
+irvwxpbxmr 1 300 train
+irwayimilk 0 300 train
+irwcschyys 1 300 train
+irwdsnsayj 1 300 train
+irwmnuixiy 1 300 train
+irwzuzlkkv 1 298 train
+irxaomucof 1 300 train
+irxfiqsbuj 0 300 train
+irxfjkpekn 1 300 train
+irxlynojzv 1 300 val
+irxmbmceev 1 301 val
+irxopvqznc 1 300 train
+irxpxqjhgw 0 300 train
+irxrvprqqi 1 300 train
+irxsooisor 1 300 train
+irxxdkyufd 1 300 train
+iryjkosyla 0 300 train
+iryqzwiwzh 0 300 train
+irythuasnk 1 300 val
+iryuwfmpbs 1 300 train
+irzbrxikle 1 302 val
+irzucyyixu 1 302 train
+irzyfqzvci 1 300 val
+isaagzqmtv 1 300 train
+isaginujnt 1 300 train
+isarllsdus 1 300 val
+isaruzcdxp 0 300 train
+isauernzll 1 300 train
+isauzsfgny 1 301 val
+isbaammqru 1 300 train
+isbkpxdqug 1 301 train
+isbkuptipx 0 300 train
+isbmgabjat 1 301 train
+isbpywzztg 1 300 train
+isbxtrfebv 1 300 val
+iscbfzqeyn 1 300 train
+iscvsysnhn 1 300 train
+iscwebnkbs 1 299 train
+iscyvmbhzs 1 300 train
+isdacfltyy 1 300 val
+isddandzca 0 300 train
+isdffajhii 1 300 train
+isdklqbdnf 1 300 val
+isdmsccxor 1 300 train
+isdsmlahqs 1 300 train
+isdsycqxnl 1 301 train
+isdtdgwlbi 1 300 train
+isebnqykad 0 300 train
+isecyxsxyu 1 300 train
+isefonafme 1 300 val
+isehasvkwy 1 300 train
+isejamimam 1 299 train
+isenrfjdku 1 300 train
+isersflgtc 1 300 train
+isesajuxxf 1 300 train
+iseykvossv 1 300 train
+isfagiiubj 1 300 train
+isfkcvmzbm 1 300 val
+isflxbtkda 1 300 train
+isfroznvha 1 300 train
+isfrxiomlx 1 300 train
+isgjlgucub 1 300 test
+isgmhzcnsn 0 300 train
+isgoeqoedr 1 300 val
+isguyxrtmf 1 300 val
+isgwavrxss 1 300 train
+ishebkpkyb 0 300 train
+isheghsxoo 1 299 train
+ishidrdsli 1 300 train
+ishlsmenwo 1 300 train
+ishsjqqijm 1 300 train
+ishtafyqwc 1 300 train
+ishwxahqhu 1 300 train
+ishxwlmakg 1 300 train
+isijlzptfp 1 300 train
+isimeplgmv 1 300 val
+isioerhlkz 1 301 val
+isiourhpot 1 300 test
+isiqchtxth 1 300 train
+isiubqzuzc 1 300 val
+isivftrbgz 1 300 train
+isixfyxvcp 1 300 train
+isjcjsmrmb 1 300 train
+isjgsrgnih 1 300 train
+isjkwjmypw 1 300 val
+isjlagxruy 1 300 train
+isjmufwbzv 0 300 train
+isjoudmnfj 1 301 train
+isjpiupegl 1 300 val
+isjvgthpyu 1 300 train
+iskadyoizu 0 300 train
+iskbjiyaij 1 300 train
+iskhivysqb 1 300 train
+iskkrfzdsv 1 299 val
+isknscqsjx 1 300 train
+iskoncqsdx 1 300 train
+iskqdueuxr 1 300 train
+iskujjudud 1 300 test
+iskwriuust 1 300 train
+iskyizphhl 1 300 train
+islmqjginb 1 300 val
+islnawtqzq 1 300 val
+islzgwudql 1 300 train
+ismbrkpmot 1 297 train
+ismoihrwjs 0 300 train
+ismsbuctwg 1 298 train
+isnbkhofol 0 300 train
+isnglkewdf 1 297 val
+isngrcptlx 0 300 train
+isnmxovfca 0 300 train
+isnqmehvoo 1 300 test
+isodmebypf 1 300 train
+isofcfjiar 1 301 val
+isoiooeznt 1 300 train
+isojisdxne 1 300 train
+isossxthze 0 297 train
+isototjlvu 1 300 train
+isouhqxtlq 1 301 train
+isoxfyhcuu 1 299 test
+ispcnlshcv 1 300 train
+ispeyrhmus 1 300 train
+ispgaapbpn 0 301 train
+ispldrgdra 1 298 train
+ispnjqelfe 0 300 train
+ispnoggyyl 0 300 train
+isprimskfu 1 300 train
+ispsuckbtw 1 301 train
+isqboqrfaq 1 300 val
+isqggenqwp 1 300 train
+isqgyyphys 1 300 train
+isqslqcirj 1 299 val
+isqyfxebiv 1 300 train
+isqzqvreov 1 300 train
+isrcbycggz 1 300 train
+isrneibtsq 0 300 train
+isrofdyiir 1 300 val
+isrscgbrbn 1 301 train
+isrtayaexy 1 300 train
+isrxenruzx 1 300 val
+issauoyrxi 1 300 train
+isshcjsmlj 1 301 train
+isshhwpulw 1 300 train
+issjgiimvq 1 300 train
+issqprjjnf 1 300 train
+isssebqvfn 1 300 train
+issxhgljkz 0 301 train
+istaazovyg 1 300 train
+istduykqup 1 300 train
+istgsllxyq 1 300 val
+istkzsdbjr 1 298 train
+istlvvylqy 1 300 val
+istqcxpzte 1 300 train
+istqherlzh 1 240 train
+isttlabolu 1 300 val
+istuilvoyz 1 300 val
+istuybqeyj 1 301 train
+istxuttxko 1 300 train
+isuhdvajec 1 300 train
+isukkjxaoo 1 300 train
+isuohdwdzx 0 298 train
+isuuywkjkp 1 300 val
+isuvafxtcw 1 300 train
+isuyxkqttj 1 300 train
+isvpmjjhwn 1 300 train
+isvqeoksng 1 300 train
+isvssecxnx 1 300 train
+isvxdpgxtx 0 300 train
+iswbynqcos 1 300 train
+iswcnayxde 1 300 train
+iswgwrwtzr 1 300 train
+iswkwzeooi 1 300 train
+iswltzdnfb 1 300 train
+iswoxfhubj 1 300 val
+isxdbhzurn 1 300 train
+isxekfofqe 1 300 train
+isxgygflrm 1 300 val
+isxwolikhj 0 300 train
+isxwueescp 1 300 train
+isxxybhuls 0 300 train
+isxywrrfwy 1 300 train
+isxzmbfwaz 1 300 val
+isybaoppkb 1 300 val
+isycysmhwg 1 301 train
+isyewdvxzt 1 300 train
+isyewygrzc 1 300 train
+isyglougjg 1 300 train
+isyhwfndmq 1 300 val
+isykvabvwa 1 300 train
+isynlxyina 1 241 train
+isyopaltci 1 300 train
+isysrgzwyg 1 300 train
+isyucpkqoa 1 300 train
+isywvoylfh 1 300 val
+iszeimyxug 1 300 train
+iszkahefzx 1 301 val
+iszopdcfmo 1 300 train
+iszptuqyzd 1 300 train
+iszroepqfc 1 299 train
+isztxlbjoe 1 300 train
+itacgsmnkq 1 300 train
+itadbziowf 1 300 train
+itadnlyssk 1 300 train
+itafhkmmpz 1 300 train
+itajgcgrsh 1 300 train
+itamvvgdpp 1 300 train
+itavxrsafk 1 147 train
+itbffwejmb 1 300 train
+itbsjttkkw 1 300 train
+itbuijqzki 1 300 train
+itbyxocfni 1 300 train
+itcoifcyrj 1 300 val
+itcxiqksqa 1 300 train
+itcyxigyog 1 300 train
+itdrpdhlby 1 300 train
+itdsiqxqet 1 300 train
+itdtgsvezx 1 300 train
+itdywxjknn 1 300 train
+iteirjxdte 1 300 train
+itelpprqsg 1 300 train
+iteouetozb 1 300 val
+itewavapjq 1 298 train
+itfdmygyre 1 300 train
+itfdsbukvb 1 300 train
+itfeokfnfp 1 300 train
+itfjqqzvfv 1 300 train
+itfljkhhmr 1 300 val
+itfnxotnge 1 300 train
+itfojnmvrv 1 300 train
+itfsvvmslp 1 300 test
+itfuzvtjtd 0 300 train
+itfzfpuilx 0 300 train
+itgpilzvay 0 300 train
+itgprdayac 1 300 train
+itgqbpccfo 1 300 train
+itgrehnkwm 1 300 val
+itgrgobbrq 1 300 train
+itgsznsdae 0 300 train
+itgxonniuq 1 300 val
+ithbdkdyaf 0 300 train
+ithbrmtqrx 1 300 val
+ithdqtcbey 1 301 train
+ithfazbwdk 1 300 val
+ithgrbjokr 0 300 train
+ithkydrkkp 1 300 train
+ithomhorcn 1 241 train
+ithpejaqrb 1 300 train
+ithvpxrvce 1 300 val
+iticnbeoyk 1 300 train
+itilxichgh 1 300 train
+itiptpqxpj 1 300 val
+itiusshmzo 1 300 train
+itiycsafaf 1 300 val
+itjnrsyhwt 1 300 train
+itjpxbskre 1 300 train
+itjtqjzbvf 1 301 val
+itjvdkfcyg 1 240 train
+itjxzhfilr 1 300 val
+itkcwxextx 1 300 train
+itkfiidxuu 1 300 train
+itksvqoses 1 300 train
+itksyonvbk 1 300 train
+itkuihvrnk 1 300 train
+itkvfvmgma 1 300 train
+itkvlisljd 1 296 train
+itkxalewmn 1 300 val
+itlwgvaxiv 1 300 val
+itlyziddxi 1 302 train
+itlzoywfbv 1 298 val
+itmayxiyne 1 301 train
+itmjxopkey 1 300 train
+itmkomrbnh 1 301 train
+itmktywsgh 1 300 train
+itmnwcrluu 0 300 train
+itmomecdvu 1 300 train
+itmwamwnte 0 300 train
+itmwoyxbas 0 300 train
+itmxitlbra 1 300 val
+itmyhgtdoc 1 300 train
+itnawjbxos 1 300 train
+itndexqskc 0 300 train
+itndhezahp 1 300 train
+itnkworuoe 1 301 train
+itnsqldumr 0 302 train
+itnumzdchb 0 300 train
+itnzpgnwoj 1 301 val
+itofwrunec 1 300 train
+itoiaabhko 0 300 train
+itousmyoly 1 300 train
+itpamrybdz 1 249 train
+itpaqvfwpg 1 300 train
+itpauysdvo 1 299 test
+itpezzyjji 0 300 train
+itphqifkuj 1 300 train
+itpkvblciq 1 300 train
+itpnqnnjyp 1 240 train
+itqaifumxp 1 300 train
+itqbhtwydq 1 299 val
+itqdvqnosv 1 300 val
+itqhlrleio 1 300 train
+itqmwnvajl 1 300 train
+itqqhgysnw 1 300 train
+itqrednqlc 1 300 train
+itqvpbqndx 0 300 train
+itqxwigfum 1 300 train
+itqzggjcsk 1 297 train
+itranaleig 0 300 train
+itrmskkndi 1 300 train
+itrowqigua 1 300 train
+itrpygajdw 1 300 train
+itrqtffjkw 1 300 train
+itrsdfydjh 1 300 train
+itrsojyzkf 1 301 train
+itrwytnqso 1 301 train
+itrxgzjewc 1 300 train
+itsaeqzveb 1 300 train
+itsamkzzry 1 301 train
+itsbakgpmq 1 301 val
+itsbfwzyde 1 298 train
+itsbtrrelv 1 300 val
+itsdfbblvf 1 300 val
+itsdlwdqje 1 300 val
+itsdmmtdxg 0 300 train
+itsedwdjys 1 300 train
+itsfsjiruj 1 300 val
+itslkazuvg 1 300 val
+itsndnelco 1 300 train
+itspwcifre 1 300 val
+itsqfzciit 1 300 train
+itsuieiwve 0 300 train
+itsvcpfjwk 1 301 train
+itsvfzdxkt 1 300 train
+ittbydmgld 1 301 val
+ittcgjzqey 1 298 train
+ittgsduukq 1 300 train
+ittjxxipyr 1 143 train
+ittkkelgtf 1 300 train
+ittomivioa 0 300 val
+ittsmuhyhv 1 300 val
+itttfditsj 1 300 train
+ittzgzsjhw 0 300 train
+itucafenye 1 300 val
+itugyowaov 1 300 train
+ituykzzbqq 1 299 test
+itvrchmorf 1 300 val
+itvvlxykiq 1 300 train
+itwegcsfqa 1 300 train
+itwlluclqd 1 301 train
+itwohyrdcb 1 300 train
+itwsemifnj 1 300 train
+itwsvyywjd 1 300 val
+itwurfhiir 1 301 val
+itwvssoevj 1 300 test
+itxawnlbch 1 300 val
+itxiztqzug 1 300 train
+itxofirjoe 1 298 train
+itxziqmodj 1 300 train
+ityddwrgfc 1 300 train
+ityhxnekzo 1 241 train
+itymdrkyyf 1 269 train
+itymhyirqb 1 300 train
+ityqjjucub 1 300 val
+ityxklqcim 1 300 train
+ityyiblsin 1 300 train
+ityzrffbmh 1 300 train
+itzcjhwakv 0 300 train
+itzjjwxysp 1 300 val
+itzmdwutdu 0 300 train
+itzmizklti 1 300 val
+iuabdbjwmn 1 300 train
+iuaeaadyxj 1 300 train
+iuajssgktv 1 600 train
+iuaqkvagza 1 300 train
+iuatfdhkya 0 300 train
+iubklilvdl 0 300 train
+iubyasowgv 1 300 train
+iucnaynimg 1 300 train
+iucnlyadlt 0 300 train
+iucopuupvn 1 301 train
+iuctpajxnn 1 300 val
+iuctxvtxkp 1 300 train
+iucumqpjla 1 300 train
+iucwphzxcc 1 300 train
+iucyscfqbx 1 300 train
+iucytcqxfu 1 300 train
+iudajnmtun 1 300 train
+iudfnpahid 0 300 train
+iudhzblmjr 1 301 train
+iudizvnuzf 1 241 train
+iudlawgsry 1 301 train
+iudlsefikg 0 300 train
+iudofkwscw 1 300 val
+iudusgluxo 1 299 val
+iudybadbqa 1 299 val
+iuechicdtb 1 300 train
+iueelzuywc 0 300 train
+iueeqwaykq 0 300 train
+iuemgewmxy 0 300 train
+iueofqnitn 1 300 val
+iueptmqaoi 0 300 train
+iueqbedolx 1 300 train
+iuesigifbt 1 300 train
+iuetdsczpf 0 297 train
+iueuagxpgd 1 300 train
+iuewyxarwm 1 300 train
+iufakulumj 1 300 val
+iufanilvlv 1 300 train
+iufcklqere 1 300 val
+iufjcxwyop 0 300 train
+iufkkbseyb 0 300 train
+iufnehfelh 1 300 val
+iufotyxgzb 0 300 train
+iufrqaiymv 0 300 train
+iufybuadlw 1 300 train
+iufywdcdyv 0 300 train
+iugbhcsosl 1 300 train
+iugbolecsc 1 301 train
+iugfvftdni 1 300 train
+iugjhewraz 1 302 train
+iugkoznqpz 1 300 val
+iugngutfcl 1 300 val
+iugnhllekl 1 301 val
+iugnysiwao 1 300 test
+iugyekhggd 1 300 test
+iuhebpwcrz 1 300 train
+iuhjpblryw 0 300 train
+iuhskztdjv 1 300 train
+iuhtbwdkrm 1 301 train
+iuhtqnzofi 1 300 val
+iuhvgoxmai 0 300 train
+iuhvvwxdce 1 300 train
+iuhwngikbq 1 300 train
+iuikozlzvg 1 300 train
+iuitpjhoii 1 300 train
+iuituywyxn 1 300 train
+iuiztqsndk 0 300 val
+iujmjwcefm 1 300 val
+iujnlpzwuq 1 301 train
+iujukgehcc 1 300 train
+iujvgedoas 1 300 val
+iujykckrmc 1 300 train
+iujzeobjfc 1 300 train
+iukkdgxnwj 1 300 train
+iuklmebuvk 1 300 train
+iukphmvuja 1 300 train
+iukwdhtsut 0 300 train
+iukwdzlrej 1 301 train
+iulafnjvng 1 300 train
+iulhnuhwee 1 300 train
+iulmqrlzdx 1 300 train
+iulnkyslop 1 300 train
+iulznyoyxc 1 301 val
+iumfpnosuq 0 300 val
+iumfuatkkz 0 301 val
+iumgxayhhj 1 300 train
+iumjgktarc 1 300 val
+iumkcwloxz 1 301 train
+iumkhjndst 1 300 val
+iumkovybhg 1 300 train
+iumodmtdbo 1 300 train
+iumwwnyouo 1 300 train
+iumybqkbzt 0 300 train
+iumyyonxqk 0 300 train
+iunbsnaqek 1 300 val
+iunffdvbto 1 300 train
+iunhzsuvfd 0 300 val
+iunjqmgoht 1 301 val
+iunpzphxxr 1 300 train
+iunuekyvob 1 300 train
+iuoaacarhc 1 300 val
+iuodusfmrr 1 300 val
+iuoegscrup 1 300 train
+iuoembbpmf 1 300 val
+iuoexaphps 1 300 train
+iuovlbhebm 1 300 train
+iuphngdpvq 1 300 train
+iupngkdauv 1 301 train
+iupxhybuyo 1 300 train
+iuqgintxoy 1 300 train
+iuqjoilxex 1 300 val
+iuqjoofoxa 1 300 train
+iuqozhqifr 1 301 train
+iurcwpfqhk 1 297 train
+iurginwgyu 1 300 train
+iuriawcxjb 1 300 train
+iurmztyqed 1 300 val
+iuroftzmsb 1 297 train
+iuromphqkq 0 300 train
+iusachxgqy 1 300 train
+iusawyxkvl 1 300 train
+iusdjdawih 1 300 val
+iusedzcqjx 1 300 train
+iuskkwagyl 1 146 train
+iuskvcflzy 1 300 train
+iuslenlqix 1 301 train
+iusqeamevp 1 300 val
+iusrxcrxcq 1 300 train
+iusujbffkw 1 300 train
+iutavmoowt 1 300 train
+iutbofrcvr 1 300 train
+iutieugpqx 0 300 val
+iutigfoqgc 1 300 train
+iutmmxwgah 1 300 train
+iutnbyldij 1 300 train
+iutnjuuxfp 0 300 train
+iutqppzovu 0 300 train
+iutqwymdxs 1 300 train
+iuttprjxhf 1 300 train
+iutwrfjdoo 1 300 train
+iuujqumhwm 1 300 train
+iuukqiavbb 1 300 train
+iuuqljzmnt 1 300 train
+iuuurlqitq 1 300 train
+iuvelrnuap 1 300 train
+iuvfvfzxeh 1 300 test
+iuvhrgckrt 0 300 train
+iuvjcrqkde 1 300 train
+iuvkcwcqbb 1 300 train
+iuvmqxrwtv 1 255 train
+iuvqlgmcif 1 300 train
+iuvuhjcihe 1 300 train
+iuwaqvkcma 1 300 train
+iuwcaynult 1 300 train
+iuwewqitvl 1 300 val
+iuwfkchvpc 1 300 train
+iuwgvbwcmp 1 300 train
+iuwlwinbdr 1 300 train
+iuwnccabob 1 300 test
+iuwqcvrhol 1 300 train
+iuwxzmxsuy 1 300 train
+iuxhfhneom 1 300 train
+iuxnmhwhsy 1 300 val
+iuxolavxoa 1 300 train
+iuxopnkzzc 1 300 train
+iuxoymwrrb 1 298 train
+iuxpinrkvu 1 300 train
+iuxpmnchdi 1 300 train
+iuxrgbfhtg 1 300 train
+iuxuegzrfo 1 300 train
+iuygdohjfs 1 269 train
+iuyjlzekhb 1 300 train
+iuyocwnopv 1 300 train
+iuyqicdyhr 0 300 train
+iuzdfwsefw 0 300 train
+iuzmgtwygk 1 300 train
+iuzojewjil 1 300 train
+iuzspdkchy 1 300 train
+iuztcdgtwf 1 300 test
+iuzynnhumg 1 300 val
+iuzzbmiabi 1 300 train
+ivafmyvsyo 1 300 val
+ivalavjixg 1 299 train
+ivaokxkyrk 1 300 train
+ivapjffhns 1 300 train
+ivapkuwryf 1 301 train
+ivarngiehh 1 300 train
+ivatauaxiq 1 300 val
+ivayrcadni 1 298 train
+ivbelgwrff 1 298 train
+ivbhzehkeh 1 300 train
+ivbjhczihl 1 298 train
+ivbphwwgrm 1 298 train
+ivbryilmzq 1 300 val
+ivbsetowvs 1 300 val
+ivbshqrxnt 1 300 train
+ivbxxtpabf 1 300 train
+ivbymzghfw 1 300 train
+ivbyvtqgzd 1 300 val
+ivcmywoktn 1 298 train
+ivcnirotcz 1 300 train
+ivcplgdqxh 1 298 train
+ivctdtckcn 0 298 train
+ivczqfnnxf 1 300 val
+ivdafszmmu 1 300 train
+ivdcahzjgz 1 240 train
+ivdewyemli 1 300 train
+ivdlxktqvk 1 300 test
+ivdoqanbyx 1 300 train
+ivdttuugex 1 301 train
+ivdvjowhmz 1 300 val
+ivdwcrytmz 1 300 val
+iveayulvxn 1 300 val
+ivedywwuer 1 300 train
+ivekyikbaq 1 300 train
+ivemkyrsnz 0 301 train
+iverfkizcj 1 300 val
+iverjmtcbg 0 300 train
+ivewsghxmf 1 301 val
+ivewzkxtuu 1 301 train
+ivexyynvqc 0 300 train
+ivezetwtxh 1 300 val
+ivfffebkow 1 300 train
+ivffzghmer 1 300 train
+ivfhdtwchv 1 300 train
+ivfizuthsm 1 300 train
+ivfrhdfujz 1 300 train
+ivfwhnosla 1 300 train
+ivfzkvqnkf 1 301 train
+ivfzsxtezl 1 300 test
+ivgaqlclhh 1 301 train
+ivgbyeslaz 0 300 train
+ivgdizvqjo 1 300 train
+ivgotbhcdh 0 601 train
+ivgtihyige 1 300 val
+ivgunqqypz 1 300 train
+ivgvjfdrbd 1 300 train
+ivgzaqcrjd 1 300 train
+ivgzvtqlyo 1 300 val
+ivhipksdtl 1 298 val
+ivhjdaqbrb 1 300 train
+ivhkxdvvgc 1 300 train
+ivhmetlooq 1 300 train
+ivhoraojgc 1 300 train
+ivhowmrwtd 1 300 val
+ivhpnfzkyc 1 300 train
+ivhvroiinq 1 300 val
+ivhyxzrfbf 1 300 train
+iviehnmhbk 1 300 train
+ivilahinci 1 300 train
+ivimbysdew 1 300 train
+ivimsdjcts 1 300 train
+ivindnrfyd 1 300 train
+iviqpdassm 1 300 val
+ivjblhgexx 1 300 val
+ivjjcmroey 1 300 train
+ivjjkajmlr 1 300 train
+ivjtlnpnhu 1 300 train
+ivjzfgjjmd 1 300 train
+ivkdoukoga 1 300 train
+ivkqrtukxb 1 300 train
+ivkqzsjsjz 1 241 train
+ivkrzgwlst 1 239 train
+ivkspkgpqj 1 300 train
+ivkvgtaekc 1 300 train
+ivkvvdfcdr 1 300 train
+ivkysrakmr 0 300 train
+ivlblicoqn 1 300 train
+ivleolirfd 1 300 train
+ivlfunutyu 1 300 train
+ivlfzvxusb 1 300 train
+ivliztuflk 1 300 val
+ivlkmfidoj 1 300 val
+ivlrwjxjko 1 300 train
+ivlxblgscs 1 300 train
+ivlxfbnoph 1 300 train
+ivlxgbadrs 0 300 train
+ivlxyjtbza 0 300 val
+ivmnlzrcpl 1 300 train
+ivngdkjxcj 1 300 train
+ivngiaholz 1 300 val
+ivnnyzpgkg 1 300 val
+ivnnzevjef 1 300 train
+ivnpfhiqkp 1 300 train
+ivnygxopre 1 299 train
+ivnzfkinhf 1 300 train
+ivoawfikbr 1 240 val
+ivocyntvbi 1 300 train
+ivofslwmml 1 300 val
+ivohixhfpe 1 300 test
+ivojdfsuih 1 300 train
+ivomizmlrw 1 237 train
+ivouhbdxse 1 300 train
+ivpekwveja 1 301 train
+ivpkbglhpo 1 300 train
+ivppedrozi 1 300 train
+ivpqdcully 0 300 train
+ivpufxwmth 1 300 train
+ivpzbkhkwv 1 297 train
+ivqjeeckuh 1 300 train
+ivqnynhrsk 1 300 train
+ivrgztqnvy 1 300 train
+ivrmpnijrq 0 300 train
+ivrpwqfdob 1 300 train
+ivrrtkfqyf 1 300 train
+ivrvvevexb 1 301 train
+ivseovsjux 0 300 train
+ivsiqtezao 0 300 val
+ivskwrnctj 0 300 train
+ivssyazqtr 0 300 train
+ivtbbwejej 1 300 test
+ivtckciojb 1 300 train
+ivtfgwfjfm 1 301 val
+ivtgygzijt 1 300 test
+ivthivgszr 1 300 train
+ivtlhlvgvf 1 300 train
+ivtoydpxpa 1 300 train
+ivtrqiaksx 0 300 train
+ivuceegsjg 1 300 train
+ivunoezyes 1 300 train
+ivuosqqpff 1 300 train
+ivuvppfhap 0 300 train
+ivuxnysacw 1 300 train
+ivuxvfquuw 1 300 train
+ivvalhpfdc 1 300 val
+ivvgwbhjee 1 300 val
+ivvirnajot 1 241 train
+ivxbutvlwk 1 300 train
+ivxeahfygq 1 300 train
+ivxhxfpwus 1 300 train
+ivxjccekbd 1 300 train
+ivxkzvtvab 0 300 train
+ivxlflmxje 0 300 train
+ivxmpricda 1 300 train
+ivxnxyszuu 1 300 train
+ivxzpdxnqh 0 300 train
+ivycgtcofx 1 298 train
+ivycucyhwq 1 300 train
+ivygifypet 1 300 train
+ivyhocaxul 1 300 train
+ivymumjmop 1 300 val
+ivyoykfjmq 1 299 val
+ivyqegqqev 1 241 train
+ivyvnvwzgj 0 300 train
+ivywzqwzjw 1 300 train
+ivyyfovazh 1 300 train
+ivzeuhdezn 1 298 train
+ivzevsvsgw 1 300 train
+ivzjtofsec 1 300 train
+ivzplpgbew 1 300 train
+ivzpsahjfw 1 300 train
+ivztwacdsm 1 300 train
+iwaikfiivj 1 300 train
+iwandsrlhu 1 301 train
+iwanjxbuqq 0 301 train
+iwatktqcfd 1 300 test
+iwbanublex 1 300 train
+iwbdixywrr 1 300 train
+iwbfunkmbn 1 300 train
+iwbmnvxovh 1 300 train
+iwbmupsdyk 1 300 train
+iwbruyugvs 1 300 train
+iwbsozjcfr 1 300 train
+iwbsxnzpmc 1 300 val
+iwbueuhpqr 0 300 train
+iwbxiqptrw 1 300 val
+iwbxuuyfnt 1 300 train
+iwcckkoakx 1 300 train
+iwceuiykdi 1 300 val
+iwcfxyoimw 1 300 train
+iwchehjyva 1 298 train
+iwckkslbpn 1 300 train
+iwclmdjwvc 1 300 val
+iwclpynllp 1 300 train
+iwclxocvzl 1 300 train
+iwcndhervv 1 300 train
+iwcqjeyplg 1 300 train
+iwcsessxkj 1 301 val
+iwcvvwvnes 1 300 train
+iwdgrrmoql 1 300 val
+iwdgvmwcnj 1 298 train
+iwdittzleo 1 241 train
+iwdlariprk 1 300 val
+iwdlwoqcvo 1 300 val
+iwdobbtokl 1 300 train
+iwdtcgikbl 1 241 train
+iwdvdzvhwn 1 300 train
+iwehwbsaob 1 241 train
+iweobhwprt 0 300 val
+iwepytttef 1 300 train
+iweqlomgcw 1 300 train
+iweugtdrpv 0 300 train
+iwexvgaccr 1 300 train
+iwezcnpomx 1 300 train
+iwfaehfbza 1 300 train
+iwffazkchq 1 300 train
+iwfmdqekmb 0 300 val
+iwfmgnjhoz 1 300 train
+iwfqatwnfa 0 300 train
+iwfrjkhocp 1 300 train
+iwfsoklsgg 1 300 val
+iwfuqlozsg 1 300 train
+iwfxiijzfc 1 300 train
+iwfyukyyzj 1 301 train
+iwgchcxyfo 0 300 train
+iwghlsqpqv 1 300 train
+iwgkbvmbjk 0 300 train
+iwgkqycihd 1 300 val
+iwgmvicass 1 300 train
+iwgsrvmyqo 0 298 train
+iwgxzgiwju 0 300 train
+iwgzfwanql 1 300 train
+iwhcsbnwhs 1 241 train
+iwhjscvlfg 1 300 train
+iwhkezibhf 1 300 train
+iwhkixmsvc 0 300 train
+iwhqfmxbfl 1 300 train
+iwhrsvsqcs 1 299 test
+iwhtvrxvcp 1 300 val
+iwhuqugcum 1 300 train
+iwhzhemnul 0 300 train
+iwicbrflbu 1 300 train
+iwihhsanwh 1 300 train
+iwijctcvfn 1 300 train
+iwilmsrdku 1 300 val
+iwiseiuuyj 1 300 train
+iwitbkehiq 1 300 train
+iwiwgryovk 0 301 val
+iwixgytgkz 1 300 train
+iwjadqnimm 1 301 train
+iwjbhusflh 1 300 train
+iwjhauqknu 1 299 train
+iwjiayxady 1 300 train
+iwjixagmqy 1 300 train
+iwjvhmsdzk 1 301 train
+iwjwrijomv 1 241 train
+iwkdyefcry 0 300 train
+iwkkadozkq 0 300 train
+iwkufhbniy 1 300 train
+iwkwpivdty 1 300 train
+iwkxwerlbo 1 301 val
+iwladlmomt 1 300 val
+iwlcgjhuyz 1 300 train
+iwljtmarck 1 300 train
+iwlltncupu 1 300 val
+iwlqewbjeo 1 300 train
+iwlqskbrsm 0 300 train
+iwlughnueg 0 300 train
+iwmafsriju 1 300 val
+iwmfrcloix 1 301 train
+iwmivlhxhp 1 300 val
+iwmqnnvhic 0 300 train
+iwmucqtpoe 1 300 train
+iwmxjgcpzb 0 300 train
+iwnfvkmktq 0 300 train
+iwnioeuyng 1 298 train
+iwnlrowpnb 1 300 val
+iwnwcdanvb 1 300 train
+iwnzvpjumj 1 300 train
+iwobeeggzu 1 298 train
+iwowncaggr 1 300 train
+iwozkvydbl 1 300 train
+iwpbhkkjcb 1 300 train
+iwpodrfkag 1 99 train
+iwpxgoejax 1 300 train
+iwpziyiqpw 1 298 train
+iwqcdlurfz 0 300 train
+iwqfvxbbuc 1 301 train
+iwqgkmzzun 1 301 train
+iwqsvoozfx 1 300 val
+iwquimjrjn 0 300 train
+iwquwreibp 1 300 val
+iwqwiezecx 1 300 train
+iwrclnpqoc 0 300 val
+iwrgyqlark 1 298 train
+iwrhhiwljg 1 300 train
+iwrilndybk 1 300 val
+iwrkkcfcob 0 300 train
+iwrrevsbjf 1 302 train
+iwrwdtvmiw 1 301 train
+iwrwoyyllo 1 300 train
+iwsdnbajql 1 300 train
+iwsmufejze 0 298 train
+iwsnnzijjd 1 300 train
+iwswdyproy 1 300 train
+iwswulwtjp 1 300 test
+iwtdxrijbu 1 300 val
+iwthiaarpj 0 302 train
+iwtjdkrtgx 1 299 test
+iwtjnrbcbb 1 300 test
+iwtrhnpwnb 1 300 train
+iwtthhjhkj 1 300 train
+iwtttiqeco 1 300 val
+iwtvtdrpxj 1 298 train
+iwudvirawn 1 300 train
+iwugxfdupu 1 298 train
+iwunoavlgg 1 300 train
+iwviwwoqkf 1 300 train
+iwvsdvisvr 1 300 train
+iwvuqzddrq 0 300 train
+iwvynfufaq 1 300 train
+iwwbhjwter 1 300 train
+iwwlgekywx 1 241 train
+iwwnwnxboi 1 300 val
+iwwogruzra 1 300 train
+iwwokmqulg 0 300 train
+iwwqxjoxfp 0 300 val
+iwwtsekifc 1 300 val
+iwwvnksime 1 300 train
+iwwvqklxxx 1 294 train
+iwwwgbxelv 1 300 train
+iwwxozjyfc 1 236 train
+iwxagxemvz 1 300 train
+iwxjlxfpjo 1 302 train
+iwxlbaklmr 1 300 train
+iwxnelgmei 1 300 train
+iwxnjsfqkw 1 300 train
+iwxzxemnjl 1 300 train
+iwyhczsuec 1 300 train
+iwylhrgafb 1 297 val
+iwyqgclcgz 0 300 train
+iwytmhnrad 1 301 val
+iwyurlgxiq 1 301 train
+iwzbgmtsuh 0 300 train
+iwzcwngwut 1 300 train
+iwzdhmltrk 1 300 train
+iwznmctsoz 1 300 train
+iwzqtwchox 1 300 train
+iwzsxvdymu 0 300 train
+iwzubyvdqm 1 300 train
+iwzxofazow 1 302 train
+iwzxyrgxxx 1 300 train
+ixaapzynwh 1 300 train
+ixayucyyzl 1 301 train
+ixbbqxbrci 1 300 train
+ixbcqacrfk 1 300 train
+ixbcwrwrqc 1 300 train
+ixbezghtef 1 300 train
+ixbgenntvc 1 300 train
+ixbpaubkas 1 300 train
+ixbqctqtmy 1 300 val
+ixbshqefra 1 300 train
+ixcfobbwix 1 300 train
+ixcguszlsk 1 300 train
+ixcojemain 0 300 train
+ixcrtusrfi 1 300 train
+ixcsuxxhzj 1 300 train
+ixcurorujz 1 300 train
+ixdfadaxpz 1 300 train
+ixdkdofqme 1 300 train
+ixdllrcaga 1 300 train
+ixdpdwwjvr 1 300 train
+ixdqyufswh 1 300 train
+ixdqzokpen 1 300 train
+ixdtdhlotp 1 298 train
+ixduztskzg 0 300 val
+ixebkxuxts 1 300 train
+ixedxyrbrm 0 300 train
+ixegidgqza 1 300 train
+ixemvyowey 1 299 train
+ixeruzpjcu 1 301 train
+ixesiknxjz 1 300 train
+ixevumyicd 1 147 train
+ixewjgjdwm 1 300 train
+ixfbuqnneo 1 300 train
+ixfdzrarsa 1 300 train
+ixflpgvzfz 1 300 train
+ixfnrwlnmg 0 300 val
+ixfsiofjto 1 300 train
+ixfzjmdhnu 1 300 train
+ixgbeiekdr 1 300 train
+ixgdnokplk 1 300 train
+ixggoemcbu 1 241 train
+ixgkclxbss 1 300 train
+ixgmwbaxry 1 300 train
+ixgntggktf 1 300 val
+ixgnuenpvc 1 300 val
+ixgvxtkmwt 1 300 train
+ixgwqqnyaz 1 298 train
+ixgxcbsbdi 1 300 train
+ixgycxoate 0 300 train
+ixhcaizjjt 1 300 train
+ixhmtubtle 1 300 train
+ixhrrzmjlu 1 300 val
+ixhsmdorum 1 300 train
+ixhywssact 1 300 val
+ixictbbahy 1 300 train
+ixictcnnwq 1 300 train
+ixiemiordj 0 300 train
+ixihznhwqr 1 300 val
+iximgngyzc 1 300 train
+ixjhxwgcrt 0 300 train
+ixjimragxn 0 300 train
+ixjiweevau 1 300 train
+ixjnwybyvy 1 300 train
+ixjqcqqxps 1 300 train
+ixjuzwvdhm 1 300 train
+ixjxyevfst 1 300 train
+ixkcpdkyjf 1 300 train
+ixkentujcx 0 300 train
+ixkhmqxidu 1 300 train
+ixlipbxbyl 0 300 train
+ixlpgpwyoa 1 300 val
+ixlsqtanjc 1 300 train
+ixlxyycryn 0 255 train
+ixlzpzmnam 1 300 train
+ixmfqrxlbg 1 300 train
+ixmiqvgych 0 300 train
+ixmkyvkxxd 1 300 train
+ixmsvefemy 1 295 train
+ixmtjukguq 1 299 val
+ixmvwmgewb 1 300 train
+ixmwbpwyxh 1 300 train
+ixmwxjoqke 1 300 train
+ixnauxdhos 1 300 train
+ixnfuudpie 1 300 val
+ixoislwzgd 1 301 train
+ixollenxsr 1 300 train
+ixollhdshi 1 298 train
+ixongfpxov 1 300 train
+ixornaprjq 1 300 train
+ixoywiwxzr 1 300 train
+ixpigphiko 1 300 train
+ixplzwjivh 0 300 train
+ixpnroqvjr 1 300 val
+ixprvoyimc 1 300 train
+ixpyfvubru 1 300 train
+ixpztpmojx 1 300 train
+ixqaiwtldi 0 300 train
+ixqfvxjtsr 1 300 val
+ixqviavpyf 1 300 train
+ixrcxoztho 1 300 train
+ixrdlekndo 1 300 val
+ixrfmndhuk 0 300 val
+ixrgrvwexn 1 300 train
+ixrhhmndnz 1 300 train
+ixrjfnfwtj 1 300 train
+ixrjksakie 1 300 val
+ixrpqifkvp 1 300 val
+ixrshvjpui 1 299 train
+ixryrhnkbw 1 300 train
+ixsabuaykm 1 300 train
+ixsazdvgcm 1 300 train
+ixsdmejgkz 1 300 train
+ixsdzcyojt 1 300 val
+ixsldkjafq 1 300 train
+ixsotcyrvg 1 300 train
+ixssfgwbjz 1 300 val
+ixsxvmyyrl 1 300 val
+ixtcnlykwb 0 300 train
+ixthjlkjan 1 300 train
+ixtlsepobo 1 300 val
+ixtnoobpji 1 300 train
+ixtoatenid 1 300 train
+ixtukgbkmv 1 300 train
+ixtuyddxxz 1 300 train
+ixtviipixx 1 302 train
+ixtxubdqou 1 300 train
+ixtydssmam 1 300 train
+ixubfnlkns 1 300 train
+ixubiangdx 1 301 val
+ixucbymhsh 1 300 train
+ixuijcqeee 1 300 train
+ixulbtzucv 1 301 train
+ixuouyigxa 0 300 train
+ixuuwiejti 1 300 val
+ixuvnlwtrp 1 300 train
+ixuyfvogbq 1 300 train
+ixuyhlwlos 1 300 train
+ixvezzeprm 1 300 train
+ixvhklaxky 1 300 train
+ixvimsnwks 1 300 train
+ixvjnszxch 1 300 train
+ixvjylnpra 1 300 train
+ixvkhbcuyq 0 300 train
+ixvtglvnsf 1 299 val
+ixvvgevgry 1 300 train
+ixvztrxchg 1 300 val
+ixvzxlfksx 0 300 train
+ixwgepyscn 1 300 train
+ixwidlyahz 0 300 train
+ixwjksvtxv 0 300 train
+ixwqvljird 0 300 train
+ixwvqvtoem 0 300 val
+ixwygokwus 1 300 train
+ixwyhhjuxz 1 298 train
+ixwykebrtz 0 300 train
+ixxbgcyhim 1 300 train
+ixxcpbrymg 0 300 val
+ixxdimpjkn 1 300 train
+ixxeciwpoi 1 300 train
+ixxetzflme 1 300 train
+ixxfvhodlp 0 300 val
+ixxiivyqrm 1 300 train
+ixxjxilvck 1 167 train
+ixxlsuarvt 1 300 val
+ixxwqexyhb 1 300 val
+ixxzlngwug 0 300 train
+ixycmrnyks 1 300 train
+ixydhrhngh 1 300 train
+ixyitjhpex 1 300 train
+ixykmnbwxc 1 300 train
+ixypadrkvg 1 300 val
+ixypsvvkfv 0 300 val
+ixyqhidlcv 1 300 val
+ixyqxcokrs 0 300 train
+ixyseycyke 1 300 train
+ixytmqplqt 1 300 val
+ixytzdgbfl 1 300 train
+ixyvxquetw 1 300 train
+ixzdchdqtq 1 300 train
+ixzgpnpflt 1 300 val
+ixzizubepc 1 300 train
+ixzkhxrmka 0 300 train
+ixzlxnfxni 1 300 train
+ixzqrvknnl 1 300 train
+ixzsayotaj 1 300 train
+ixzuccwwqs 0 300 val
+ixzxcuyjch 1 300 train
+ixzzfbjiwu 1 300 train
+iyaaatxftx 1 300 train
+iyathksdmx 1 300 train
+iyaxgpepqr 1 300 val
+iybcwvsnru 1 300 train
+iybddhsnea 1 300 train
+iybeenycdm 1 301 val
+iybjcyrvmw 1 300 train
+iybnyabglv 1 300 val
+iybodcrcnc 1 292 train
+iybrmlqrzb 1 300 train
+iybuwdyjkm 1 300 train
+iycbbmjief 1 300 train
+iyciyppmkq 1 300 train
+iycqbycozc 1 300 train
+iycsdduxwl 0 300 train
+iycstoqedl 1 300 train
+iycyzocmqx 1 300 train
+iydeqktuql 0 300 train
+iydildurwm 1 298 train
+iydssphcep 1 300 train
+iydummdsoa 0 300 train
+iydyvuvtuy 0 300 train
+iydzizaopo 1 240 val
+iyeddobgmq 1 300 train
+iyefnuagav 0 300 train
+iyegjhsbci 1 299 test
+iyegstbilg 1 301 train
+iyehyealyz 1 300 train
+iyejoxsoqz 1 299 val
+iyerbpbkeq 1 300 train
+iyevlxhraf 1 300 val
+iyewtthlmb 0 300 train
+iyfdxpvkgk 0 300 train
+iyffzyahfp 1 300 train
+iyfrjjoark 1 298 train
+iyfrztvsvx 1 300 train
+iygbhjkhpm 1 301 train
+iyggeywivg 1 300 train
+iygpfnjqvr 1 300 train
+iygqtvkrwf 1 300 test
+iyhbsrkotv 0 300 train
+iyheosista 1 300 train
+iyhiufnrbd 1 300 train
+iyhkhsdhma 1 300 test
+iyhnhawndk 1 300 train
+iyhqemstti 1 298 train
+iyhqfygtwo 1 300 train
+iyhtjahyzx 1 300 train
+iyhxchufch 1 147 train
+iyhzzwoqmi 1 300 test
+iyibppyrtj 0 300 train
+iyilruqfhe 1 300 test
+iyiojarsht 1 269 train
+iyixmjjyrl 1 240 val
+iyjofxppna 1 300 train
+iyjomyaytf 1 301 train
+iyjrqkkeof 1 300 train
+iyjscyomzv 1 300 val
+iyjybwielm 1 297 train
+iyjzxaumul 1 300 train
+iykatwvtlo 1 300 val
+iykfgshgqv 1 300 train
+iykhzfzgkt 1 300 train
+iykkomxaja 1 300 train
+iykperybpb 1 300 val
+iylgchjrja 1 296 train
+iylhyypegc 1 298 train
+iylnbnwfhc 1 298 train
+iylqacirzy 0 300 train
+iylujmtolb 1 300 train
+iylwgfyswr 1 296 val
+iymdqozovu 1 300 train
+iymjtfuisq 1 300 train
+iymkenagsp 1 300 train
+iymlemdldn 1 300 train
+iymsvbtlnp 1 300 train
+iymztkafxg 1 300 val
+iynaefjhwh 1 300 train
+iynqjtimwc 0 300 train
+iyntaojwbw 1 300 val
+iynuflmhau 1 300 val
+iynxqdizck 1 300 train
+iyobxgtsvz 1 240 val
+iyorkuftee 1 301 train
+iypcvtchfy 1 300 train
+iypdhkbqsi 1 300 val
+iypftmauon 1 300 train
+iypidkveup 0 300 val
+iypivgjahx 1 300 train
+iypkckoqsb 1 301 train
+iypqoktthd 1 300 val
+iyprthentu 1 300 val
+iyqfuituhp 0 300 train
+iyqoewtjvb 1 299 test
+iyqqepdkyt 1 300 train
+iyqtnfuije 1 300 train
+iyquxriyqd 1 300 train
+iyqvfgcykc 1 300 train
+iyqykojidr 1 300 train
+iyrafvzjnf 0 299 val
+iyrjdwjjkl 1 300 train
+iyrmltyelm 1 300 train
+iyromnkalp 1 300 train
+iyrsthhhwi 1 300 train
+iyrwuqutbn 1 300 train
+iysiitdxjf 1 301 train
+iyskmztwew 1 300 train
+iysohojmyd 1 300 train
+iysqricdpb 1 300 train
+iysvczmsms 0 300 train
+iyswglziib 1 300 test
+iytdsjcwxy 0 300 train
+iytkbgunzn 1 300 val
+iytkbyahir 1 299 val
+iytnvfizkp 1 300 train
+iytyilgihs 0 300 val
+iytyxfdmmf 1 300 val
+iyufxamuiu 0 300 train
+iyuioatcdu 1 300 train
+iyujjjntxk 0 300 train
+iyujymppjg 1 300 train
+iyuntioqrn 1 298 val
+iyutbbgjql 0 300 val
+iyuwjjxyoq 1 300 train
+iyuxnpeeau 1 301 val
+iyvaghvhjl 1 269 train
+iyvcndziss 0 299 val
+iyvevfvuxx 1 300 train
+iyvhbdodpj 1 300 train
+iyvivvcthl 0 300 train
+iyvoafuqjf 1 300 train
+iyvqluqwzn 1 300 train
+iyvtqyxizu 1 300 val
+iyvytmjwkb 1 300 train
+iywgtvcdky 1 300 train
+iywhpaeciv 1 300 train
+iywhwkgzmq 1 300 train
+iywrddavxt 1 300 val
+iywtjwpeks 1 300 val
+iywuavxnpx 1 300 train
+iywxsqsrsm 1 300 val
+iyxasoplip 1 241 train
+iyxelmxpfx 0 300 train
+iyxjdvhoil 1 298 train
+iyxlkaysef 1 300 val
+iyxlkqezdk 1 241 train
+iyxotzadnl 1 301 val
+iyxrjrtive 1 300 train
+iyxutmglzj 1 300 val
+iyxwamcojv 1 300 train
+iyyiwbfpmm 1 300 train
+iyyjkzkels 1 300 train
+iyykmqanju 1 300 val
+iyyohfehur 0 302 train
+iyzcmtlqds 1 300 val
+iyzfltopuo 1 300 train
+iyzhvnlukr 1 300 train
+iyzhzhzpfg 1 300 train
+iyzjjvenmu 1 300 train
+iyzrahjpvo 0 300 train
+iyzruylmxa 1 300 train
+iyzsnjmfud 1 300 train
+iyzsxihtuk 1 300 val
+iyzvsvstsw 1 300 train
+iyzztikssi 1 300 val
+izafpzgupv 1 300 train
+izafuvvwwi 1 300 train
+izagkzgfuu 1 300 train
+izalokbyee 1 300 train
+izamzkbrbc 0 300 train
+izanyxbfrw 0 300 train
+izaoqssyvw 1 300 train
+izappfzldr 1 300 train
+izarampnzh 1 300 train
+izbbmenvrw 0 300 train
+izbioilrax 1 300 train
+izbjpwxumi 1 300 train
+izbkpxuwmf 1 300 train
+izbusfehir 1 300 train
+izbxdkbfdk 1 300 val
+izcddnkexo 1 300 val
+izcgakoubh 1 300 train
+izcpnmmhfa 1 300 val
+izcqycnyfd 1 300 train
+izcsobojgp 1 300 train
+izcuhdldnf 1 300 train
+izcvwswosq 1 301 train
+izcwceqqta 1 300 train
+izcxebhtfp 1 300 train
+izdckejfmp 1 300 train
+izddtrmijp 1 300 train
+izdxyflgdq 1 300 train
+izdxztnzpd 1 301 train
+izdzcdlrpo 1 300 train
+izehgbrreh 1 300 train
+izehsqyemw 1 302 val
+izevfbcjot 0 300 train
+izfdfyundf 1 300 train
+izfdlnfxre 1 241 train
+izfojgcokb 1 300 val
+izfuelnxbj 1 298 val
+izfvpthhcy 1 300 train
+izfyedvxhd 1 300 train
+izfyghageu 1 300 train
+izgghxbita 1 300 train
+izglbuaqkt 1 300 test
+izgldriffe 1 300 train
+izgnxrjqfv 1 300 val
+izgonpyfws 1 300 val
+izgumqcxhi 0 300 val
+izgutpnsre 1 300 train
+izgxpoccwo 1 298 val
+izgxrlqbqk 1 300 train
+izhchgzacx 0 300 val
+izhdphrmlw 1 300 train
+izhfjncnut 1 300 val
+izhfkxysto 1 300 test
+izhgevkhba 1 301 train
+izhhxphjwc 1 300 train
+izhnyenoej 0 300 train
+izieomaoko 1 300 val
+izihkrhcep 1 300 test
+iziuqwsoef 1 300 train
+izjajzyszt 1 300 train
+izjbunivhp 0 300 train
+izjqhjrhhk 1 300 train
+izjtzkimun 1 300 train
+izjuqrgzvi 0 300 val
+izjvqhjokl 1 300 val
+izjwgdprmx 1 300 train
+izjwmhunbk 1 300 train
+izkahexkec 1 301 train
+izkavempcf 1 300 train
+izkdaeizpj 1 300 train
+izkfhrildi 1 255 train
+izkikcclfv 1 300 train
+izkqquaqpw 1 300 val
+izkrdjbtol 1 301 train
+izkvecvmid 0 241 train
+izkypnzjhl 1 299 val
+izlhutihbf 1 300 train
+izlpwhzkuj 1 300 train
+izlseforxg 1 300 train
+izlwmdahee 1 300 val
+izlxfessti 0 300 train
+izlzwaqpsw 1 300 train
+izmfhoosyi 0 300 train
+izmghxdror 1 241 train
+izmgmtfewh 1 298 val
+izmwdwobln 1 300 train
+izmysihgff 1 300 train
+iznamzoera 1 301 train
+izndkibdms 1 241 train
+iznnzjvaxc 1 300 test
+iznuwuxnqc 0 300 train
+iznvkuthdk 1 300 val
+izoadkuikp 1 300 train
+izoaxogfnm 1 296 train
+izobhqblin 1 300 train
+izocoaixub 0 301 train
+izorkovxra 1 300 train
+izoslstyhe 0 300 val
+izouuuswwx 1 300 train
+izovcfviko 1 300 train
+izovpqwurs 1 300 train
+izowmeknso 1 300 train
+izoywnwvzc 0 300 train
+izozkczrrt 1 300 train
+izpddhxmhw 1 300 train
+izpedkituy 1 300 train
+izpffscumm 1 300 train
+izpmmxftek 1 301 train
+izpncyqwqu 1 300 train
+izpsvafqia 0 298 train
+izqbaeadoh 1 241 train
+izqbpyxmkz 1 300 val
+izqkhizehl 1 300 train
+izqloinjwk 1 300 test
+izqrrvwvjx 1 288 train
+izqvablmsn 1 302 train
+izqyarmakg 1 300 train
+izqyismnhp 0 300 train
+izqyxfvxrj 1 300 train
+izrevxyfet 1 300 test
+izrjasmngs 1 300 val
+izrmjvjyxi 0 300 train
+izrpcodhek 1 300 train
+izrukhmjfx 1 300 train
+izruqmbare 1 299 test
+izrxqbhkca 1 300 train
+izsejcmijs 1 300 train
+izsfxgnupd 1 300 val
+izsgrmtpto 1 300 train
+izsiyppwbp 1 299 val
+izsjxixdlr 1 300 train
+izsoaexxfj 1 300 train
+izsvnupcib 1 300 train
+izswtrtsma 1 301 train
+izswxtsqsy 1 301 train
+izswzcgmjq 1 300 train
+izsycjuamo 1 300 train
+iztglppzcn 1 136 train
+iztjlguijq 1 300 val
+iztohpzqod 1 300 train
+iztpttlskz 1 300 train
+iztqglthhr 1 300 train
+iztvnzwxds 1 300 train
+izufhxeuve 1 300 train
+izujskjynu 1 300 train
+izumbgfuxt 0 300 val
+izunrhzmhr 1 300 val
+izurqowaxf 1 300 val
+izushcrwhm 1 300 val
+izusocmfvb 1 300 train
+izuwizilgv 0 300 val
+izvipgybix 1 300 train
+izvjrkbhia 1 300 val
+izvnhvfkuw 1 300 train
+izvqobjehj 1 300 train
+izvyqwatsi 1 300 train
+izwffjjktn 1 300 train
+izwhktnyob 1 300 val
+izwollgcyv 0 300 val
+izwsybqjfz 1 300 val
+izxamzwrlu 1 300 train
+izxbcyulyt 1 300 train
+izxbypthyy 1 300 val
+izxdwtnvty 1 300 train
+izxhmhmlbq 1 300 val
+izxkpunalz 1 300 train
+izxszyftmg 1 300 train
+izybzjtoof 1 300 train
+izycdfyeik 0 300 train
+izyogmxmoz 1 300 train
+izyqqybmcq 1 299 val
+izyrzamcqj 1 300 val
+izyzwlbigy 1 300 val
+izzdktvqus 1 300 train
+izzdvwmzfe 1 300 train
+izziawbvxp 1 300 train
+izzizxvfaw 0 301 train
+izzjbktyjr 1 300 train
+izzlvfvkwi 1 300 val
+izzmvbiras 1 300 val
+izzrixoftl 1 302 val
+jaaaeokdkk 0 300 val
+jaaeovgdwa 1 300 train
+jaamdmxvmv 1 300 train
+jaarawxvwo 1 301 train
+jaaxdtwwdu 1 300 val
+jabfulxofx 1 300 train
+jaboefdhdh 0 300 val
+jabtbsqorr 1 300 train
+jabvlngldw 1 300 val
+jabxlooafa 1 300 train
+jacagpxpnq 1 300 val
+jacaspbgbf 0 300 train
+jacbysukfi 1 300 train
+jacmgbjhwo 0 300 train
+jacnpawlsf 1 300 train
+jacvxyeeqa 1 300 val
+jacwfnxssb 1 300 train
+jadmgxjhgb 1 298 train
+jadochbnrm 1 300 train
+jadqakeaoc 1 255 train
+jadzdegptj 1 300 val
+jaeeeffypa 1 241 train
+jaeqgvkwlm 1 300 train
+jaeslmfgab 1 300 train
+jaetnqgktl 0 300 train
+jafpzzlqse 1 300 val
+jafxhlcyqk 1 300 train
+jafxiptxew 1 300 train
+jafxkrazzh 1 300 train
+jafxtknnoa 1 300 val
+jafxzaqcao 1 300 train
+jafyjjmunj 0 300 train
+jagdgrhofw 0 300 val
+jagdzowdri 1 300 val
+jagflalxhl 1 300 train
+jaggofaiiq 1 300 train
+jagjtcxlfw 0 300 train
+jaglmbxatl 1 300 train
+jagmqcvuip 0 300 train
+jagrhoufaz 1 301 train
+jagrkfsdvk 1 298 train
+jahklnwscj 1 300 train
+jahlcvdwdm 0 300 val
+jahnsytkoh 1 236 train
+jahvexosbx 1 300 val
+jahvruaepm 1 301 val
+jahxyaswnk 1 300 train
+jailgizmln 1 300 val
+jaimulhywo 1 301 val
+jaiojqyufy 1 300 val
+jaisoicsqy 1 300 train
+jajbmqewfy 0 300 val
+jajbvprceb 1 300 train
+jajcagivqc 0 300 val
+jajdogxcbu 1 300 train
+jajhldnera 1 300 train
+jajjzvhlou 1 300 train
+jajnvnkynl 1 300 train
+jajqrgefaq 1 302 train
+jakcnyuwei 1 241 train
+jakezhdgbr 0 300 val
+jakfremigr 1 300 val
+jakhyxdkmw 1 300 val
+jakjfxcjqx 1 300 val
+jakregbmuf 1 300 test
+jakvghoayo 1 300 train
+jakwmemyjj 1 300 train
+jalaaubeqb 0 300 train
+jalbvevoxn 1 300 val
+jalgnyqtzl 1 300 train
+jalifcidnp 1 300 train
+jalmxdivsh 1 300 train
+jalndfixun 1 300 val
+jalnhtrofg 1 301 train
+jalovmxcgk 1 300 train
+jalqfjsxyr 1 300 train
+jalutuvgew 1 300 train
+jalzdjkegw 1 300 train
+jamcoysvvp 1 241 train
+jamhxdptam 0 300 train
+jamurssefx 0 300 val
+janawzwgip 1 300 train
+janghqcnuj 1 300 train
+jankpqqcqv 1 300 train
+jannamlrje 1 300 train
+janpjkrxky 1 300 train
+janqvnnppy 1 300 train
+jantqsgklo 1 300 train
+janwsbiojw 1 300 train
+jaocplqkcu 1 300 train
+jaogotncwj 1 300 test
+jaomwewhxt 1 300 train
+jaoqvbrxep 1 240 train
+jaorgbqruh 1 300 train
+jaoyqdyzvg 0 300 train
+japautsabs 1 300 train
+japeipnfla 1 300 val
+japffgogpn 1 300 test
+japkrtsdkj 1 300 train
+japoasbnio 1 301 train
+japswojfhl 1 300 train
+jaqavnyaii 1 300 train
+jaqgccovpn 1 300 train
+jaqkoaifol 1 300 train
+jaqsjlohgm 1 300 train
+jaqyamaloo 1 300 val
+jarcxupfvu 1 300 train
+jarebgmdyf 0 300 val
+jaruexfgky 1 300 train
+jarwzyjqnz 0 300 val
+jarxjojthr 1 298 train
+jarzvyhgve 1 300 train
+jasbmxgopi 1 300 train
+jascajixzv 1 300 train
+jaskustatr 1 301 train
+jasopzrspq 0 301 val
+jasshduqgh 1 300 train
+jatpyqmdhn 0 300 train
+jatsybxwsc 1 300 val
+jattojjsod 1 298 train
+jatuhhpdfa 1 300 train
+jatvfulyhg 1 300 train
+jatyvfltqg 1 300 val
+jaukelrqch 1 300 val
+jauolugbsh 1 300 val
+jaurdjnhfi 1 300 train
+jaurxwocly 1 300 test
+jauwdvlpxf 1 298 train
+jauwhqjzkh 1 300 train
+jauzyxbadm 1 300 train
+javaidijkz 1 300 val
+javcctidsr 0 300 val
+javdjdbfhf 1 300 train
+javetmajgc 1 300 train
+javncjzkjt 1 300 train
+javooplidl 1 300 train
+javrpuxtba 1 300 train
+javssxlatd 1 300 train
+javtkzuykv 1 300 val
+javtxnogey 0 300 train
+javxtwhvub 1 300 train
+javyvwvmhd 0 300 train
+jawewhiexm 1 300 train
+jawgcggquk 0 300 test
+jawhvtiqhs 1 301 train
+jawjzasauu 0 300 train
+jawsndcpuu 1 300 val
+jawulqeyzr 1 300 train
+jawwlbojon 0 300 train
+jawycktkcs 1 300 train
+jaxslvzthe 1 300 test
+jaxssdkeyg 1 300 train
+jaxsvzilcr 1 300 train
+jaxuhzqcyh 1 300 train
+jaybwbgfwm 1 300 train
+jaygpadugs 0 300 train
+jaymexergk 1 300 train
+jaynqmloow 1 300 train
+jayvasghae 1 300 train
+jayybrfpgr 1 301 train
+jazatgwree 0 300 train
+jazbpflrcx 1 300 train
+jazdzntcfc 1 301 train
+jazhgxildx 1 300 train
+jazjmmugqf 0 300 train
+jazmkphsnn 1 300 train
+jazrfmgzpy 0 300 val
+jazvabvrgi 1 300 train
+jazyoeydzn 1 300 train
+jazzmscrid 1 300 train
+jbaahohsns 0 300 train
+jbahcovspa 1 300 val
+jbajkblyko 1 300 train
+jbamkplzqj 0 300 val
+jbamrunjok 0 300 train
+jbamxjgfob 0 300 val
+jbaqarlltp 0 300 train
+jbaqreckyf 1 300 train
+jbarktisos 1 300 train
+jbatiwjmzh 1 300 train
+jbaxqvfhwm 0 300 train
+jbayzbfxsg 1 301 train
+jbbiykbcvn 1 298 train
+jbblippolx 1 300 train
+jbbndsfnqu 1 300 train
+jbbpssuahy 1 300 train
+jbbysdmnwr 1 301 train
+jbbzntphpu 1 300 train
+jbcesucwqv 1 300 train
+jbcjypxbli 1 299 train
+jbcmcalago 0 300 train
+jbcnsmlysc 0 300 val
+jbcuiqstif 1 300 train
+jbcvkodrvy 1 300 train
+jbdabmdbsf 0 300 train
+jbdbsfhzbu 1 300 train
+jbdkulvsti 1 301 train
+jbdmfjnsup 0 300 train
+jbdqevfnlz 1 300 train
+jbdqpkuyac 1 300 train
+jbdtwoxdiy 1 301 val
+jbebjrmqiu 1 300 val
+jbebqobxeb 1 300 train
+jbencltszf 1 300 train
+jbepwyoziw 1 300 train
+jbfgwihmda 1 300 train
+jbfmmltyex 1 301 val
+jbfrizzpin 1 300 train
+jbfspnzoms 1 300 train
+jbfubgwmwk 0 300 train
+jbfxfoycfx 1 298 train
+jbgdikwbwr 0 300 train
+jbgivjvgrm 1 300 train
+jbgklqgife 0 298 train
+jbgxmoyvla 1 300 val
+jbgzlpdlbb 1 300 train
+jbhjpjdhyj 1 300 train
+jbhosduyyq 1 300 train
+jbhoztwgjm 0 300 train
+jbhvifiujz 1 300 train
+jbifcgrgvi 1 300 val
+jbinfqztea 1 300 train
+jbiradvsio 1 300 train
+jbisxdillp 1 300 train
+jbiypdwofh 1 300 val
+jbizmaukak 1 299 train
+jbjxyruohr 1 298 train
+jbkaewamsx 1 300 train
+jbkfwaayuk 1 300 train
+jbkkwmfsrt 1 300 train
+jbkrxgnynh 1 300 train
+jbkwnjatua 1 300 train
+jbkwryfipw 1 300 train
+jbkxqrqbcy 1 300 val
+jblfvzevdi 1 300 train
+jblfxtijks 1 241 train
+jblibhnsch 0 300 train
+jblifxkahd 1 300 train
+jblkcfejih 1 300 train
+jblltdygfy 0 300 train
+jbmdzelkry 1 300 train
+jbmemsdbvf 1 300 train
+jbmialddyd 0 300 val
+jbmojwnatp 1 241 train
+jbmqnvgtjx 1 300 val
+jbmvqndxbr 1 300 train
+jbnakrsscz 1 300 val
+jbnfdkrgdv 1 301 train
+jbnndprobn 1 240 train
+jbobnmshak 1 300 train
+jbocbmvqhh 1 300 val
+jboofnpgas 1 298 train
+jboxtjvlti 1 301 train
+jbpajntban 1 300 train
+jbpchknvbd 1 300 val
+jbpiwtilqx 1 301 val
+jbplfhqoib 1 300 train
+jbplnqxfbw 1 300 train
+jbpmiawgfq 1 300 val
+jbptmfdsjb 0 300 train
+jbpuqmomvc 1 300 train
+jbpvhfqyop 1 300 train
+jbpxyyacyj 0 300 train
+jbqfifmaka 1 300 train
+jbqksfnqsd 1 300 train
+jbqlmhgkjz 1 300 train
+jbqqqhuiir 0 300 train
+jbqtknxkrk 1 300 train
+jbrjeujfmw 0 300 train
+jbroqppyxm 0 299 val
+jbrowwiggh 1 300 val
+jbrymjgske 1 300 train
+jbsalzfqtl 1 300 train
+jbsjntstgx 1 300 train
+jbsrlijaij 1 300 train
+jbsucpzcug 1 300 train
+jbswxonozv 1 300 train
+jbtayvbjbv 1 300 train
+jbtgmyiuuh 1 300 train
+jbtkucyaxo 1 302 val
+jbtkxuziwn 1 300 train
+jbtowkighm 1 301 train
+jbtuvaqltg 1 300 train
+jbtwknjuph 1 300 train
+jbtxgmgqke 1 301 train
+jbucifddgs 1 300 train
+jbujtwjhtp 1 298 train
+jbukxhshfm 1 298 val
+jbuomylolg 1 300 train
+jbutqxloiw 1 300 train
+jbuuyywlgd 1 300 train
+jbuzltkpdw 0 300 train
+jbvevkivmt 1 300 train
+jbvktadzia 0 300 train
+jbvqnbkpoo 1 300 train
+jbvvmronya 1 300 train
+jbvwtnekeh 1 300 train
+jbvykcutef 0 300 train
+jbwbmokqht 1 300 train
+jbwehkdxhh 0 300 train
+jbwfkkdeep 1 300 train
+jbwjwzxjym 1 300 train
+jbwtbfbdko 1 300 train
+jbwtvoixgc 1 300 test
+jbwtytjdyj 1 300 train
+jbwuzhtfkf 1 299 val
+jbwvahbmfb 1 300 train
+jbwxzxaxen 1 269 train
+jbwzrlpevt 1 300 train
+jbxefcizew 0 300 train
+jbxhwlyojx 1 300 train
+jbxiszwoms 1 300 train
+jbxjqnwwhv 1 300 train
+jbxjvkdnci 1 300 test
+jbxlivgkll 1 300 test
+jbxljgmylw 1 300 train
+jbxnogwwow 1 300 train
+jbxsnmibxr 0 300 val
+jbxtzfymea 1 300 val
+jbxviammiv 1 300 test
+jbxvxjeklv 1 300 train
+jbxwxfwncq 1 300 train
+jbxxhxcoyh 1 300 train
+jbyabeoivw 1 300 train
+jbydmvaxfy 1 300 train
+jbygrnhroe 1 240 val
+jbygwljdyy 1 300 train
+jbyrlqskuw 1 300 train
+jbysofevrm 1 300 train
+jbyyrjbptv 1 300 train
+jbyzfrmrdh 0 300 train
+jbzixvffsf 1 241 train
+jbzljgjwrd 1 297 train
+jbzprcchjw 1 300 train
+jbzqjborfw 1 300 train
+jbzxmsdlna 0 300 train
+jbzzcjbtgk 1 300 train
+jcaavicbyk 0 300 train
+jcaedmoznm 1 301 train
+jcaentwavr 1 300 train
+jcafibbcdx 1 300 train
+jcahmchbgr 1 300 train
+jcaoljdnpm 1 300 train
+jcayovyzfd 1 301 train
+jcbagegbne 1 300 train
+jcbbrqaaaq 0 301 train
+jcbcsxbmkh 1 300 train
+jcbljxsnkq 1 300 train
+jcbrkrekbh 1 300 train
+jcbsycrkok 1 298 train
+jcbtrooxiv 1 300 train
+jcbzbjbips 1 300 train
+jcbzvzcxzt 1 300 train
+jccdosuaei 0 300 train
+jccgenmqao 1 292 train
+jcckrtvvmw 1 300 train
+jcckxvchoa 1 300 train
+jccnimztzl 1 300 train
+jccofuwqrp 1 300 train
+jccvzepxjn 1 300 test
+jccywqqkjl 1 298 train
+jcdanlldbh 1 300 train
+jcdijgtyre 1 300 train
+jcdjulohcc 1 300 train
+jcdjuwmzmt 1 300 train
+jcdkghupzo 1 298 train
+jcdkxrhcbf 1 300 val
+jcdsliebdg 0 300 train
+jcdtguywds 1 300 train
+jcdurgmxca 0 302 train
+jcdwcvhiic 0 298 train
+jcedsiexnp 0 300 train
+jceejhpnip 1 300 train
+jceevetrcm 1 300 train
+jcefyfthzl 1 298 train
+jcemhurxla 1 300 train
+jcenhhtpvh 0 300 train
+jcerhinbrx 1 300 train
+jcerzhbwdy 1 300 train
+jcfbsuwqkj 1 300 train
+jcfhijtioh 1 299 test
+jcfhtypqnv 0 300 train
+jcfibndigv 1 300 val
+jcfisfexkt 1 300 val
+jcfkavlnzt 1 300 train
+jcfmmamehu 1 300 val
+jcfqjjkefm 1 298 train
+jcfthjznna 0 300 train
+jcfwpohvoz 1 300 train
+jcfwrugpmb 1 167 train
+jcgacibgnr 1 301 train
+jcgbrpoxte 1 300 val
+jcgchkagdy 1 300 train
+jcgeaadwxt 1 300 train
+jcggxsyyph 1 298 train
+jcghecaiay 1 298 train
+jcglqjqhan 1 300 train
+jcgndflmvj 1 300 train
+jcgnmpdepm 1 300 train
+jcgsirqzdc 0 300 train
+jcgztikjdy 0 300 train
+jchcwdajtk 1 301 train
+jchjdqfaax 1 300 train
+jchjosbfkw 1 300 val
+jchkxmtoue 1 300 train
+jchrcyfvjs 1 301 val
+jchribimkb 1 241 train
+jchsrvcboi 0 300 train
+jchwzgkjbn 1 300 train
+jchzhrmmuk 1 300 train
+jcijaylltt 1 300 train
+jcipnwiowk 1 300 val
+jciprwszay 1 300 train
+jcirgymcmp 0 240 train
+jcitcoyrxu 1 300 train
+jciuoqhwjh 1 300 train
+jcivepxxrw 1 300 val
+jcivzlayyl 1 300 train
+jciwjcyipa 0 300 train
+jcjbdrluyb 1 300 train
+jcjbfjuidx 1 300 train
+jcjfxveqvr 1 300 train
+jcjiwnltwv 1 300 train
+jcjjlldkww 0 300 val
+jcjkirwykv 0 300 train
+jcjkpwbhso 1 299 val
+jcjlwgqlfv 1 300 train
+jcjmoczpjf 1 600 train
+jcjsormaiu 1 300 val
+jcjupckwwo 1 300 val
+jcjvaypgbq 0 302 train
+jcjzfcpzvb 1 300 train
+jckqosfotj 1 297 train
+jcladjsvks 1 300 train
+jclarzoktw 0 300 train
+jclgkjtmfp 1 300 train
+jclhggdqwj 1 300 train
+jclibaoujn 1 300 train
+jcljktilez 1 301 train
+jclmtomedt 1 300 val
+jclqtgycyd 0 300 val
+jclshaiflo 0 300 train
+jcmgbahven 0 301 train
+jcmphslawp 1 300 val
+jcmrarqwsh 1 298 train
+jcnfyxmfmq 1 300 train
+jcnlpjdvyo 1 300 train
+jcnrejctwf 1 300 train
+jcnreztvlt 1 300 train
+jcnxfbqyte 1 300 train
+jcoahdlpkf 1 300 train
+jcockzcwdj 1 300 train
+jcoybssfob 1 288 train
+jcozyqetvv 1 300 train
+jcpcvrmtwj 1 300 train
+jcphznnovl 1 288 train
+jcpimqracm 1 300 train
+jcpjfycbmu 1 300 train
+jcprzlmnwn 1 300 train
+jcqbscxfsg 1 299 train
+jcqdpvjpph 0 300 val
+jcqjhgsoxr 1 300 val
+jcqlnytgil 1 300 train
+jcqvkaalyg 1 299 test
+jcqxwbgvbl 1 300 val
+jcqzsldrcf 0 300 train
+jcraqzsjjo 1 300 train
+jcrctdpftr 1 297 train
+jcrhvauwts 1 300 train
+jcrkcqxbku 1 300 train
+jcrpwhrpyk 1 300 train
+jcrwcsvigb 1 300 train
+jcsetstuio 1 241 train
+jcsfrkqvyt 1 300 train
+jcsiirvdlf 1 300 train
+jcskpkzxjc 1 298 val
+jcspnpityc 1 300 train
+jcsqblnqum 1 300 test
+jcsqrhfgso 0 300 train
+jcszuniisy 1 300 train
+jctahcrbkh 1 299 test
+jctkcqmbnq 1 300 val
+jctldanhhv 1 300 train
+jcujpwphjt 0 300 train
+jcumdiiqmk 1 300 train
+jcurjqcjnr 1 83 train
+jcutsvnbky 1 300 train
+jcvcaymvjf 1 300 train
+jcvclxcgnc 1 300 train
+jcvihxcuyc 0 300 train
+jcvjqsmjwe 1 300 train
+jcvpaacckj 0 300 train
+jcvwdhbjrf 1 300 train
+jcvysccwcc 1 300 val
+jcwkemycdm 0 300 val
+jcwliusjbw 1 300 train
+jcxbeoxfip 1 300 train
+jcxbfeqqqq 1 300 train
+jcxgveehec 0 300 train
+jcxjjnulen 1 300 train
+jcxmtgszae 1 301 val
+jcxwhrrxda 1 300 val
+jcxxlefmpq 1 300 train
+jcxxspkyth 1 300 val
+jcyfzyfnjs 0 300 train
+jcyitrgvtz 1 300 test
+jcyjjoxplz 1 302 train
+jcyrdzxlmy 0 300 train
+jcyrgdqlyi 0 300 train
+jcyrzhtvdz 1 300 train
+jcysauvvkv 1 301 train
+jcywwljhni 1 300 val
+jcyydwxkor 1 300 train
+jcyyimwkus 1 298 train
+jczbwyrqfs 1 300 val
+jczcxapadt 1 300 train
+jczeajciwx 1 301 val
+jczfvlnooy 1 300 train
+jczhxeqapk 1 300 train
+jczkbwttrd 1 300 train
+jcznskrrjx 1 300 train
+jczsfvlaeh 1 300 train
+jczvjwojia 1 300 train
+jczxdtodnk 1 300 train
+jczyfovfhy 1 300 val
+jdahycturj 1 300 train
+jdaojwkjpp 1 300 val
+jdarnrszrw 0 300 train
+jdbjvdjykg 1 300 val
+jdbobakgly 1 300 train
+jdbptqebpo 1 300 train
+jdbwqjtdqp 1 300 train
+jdbztnbnif 0 298 train
+jdcdwqqesr 1 300 train
+jdcoheaygf 1 300 train
+jdcrojuukw 1 300 train
+jdcvgrtoux 1 300 train
+jdcwoqqeir 1 241 train
+jddarfvccu 1 294 train
+jddezqiwqm 1 300 val
+jddffgsfed 1 300 val
+jddhnvfeeh 1 300 train
+jddmbonyaa 1 300 train
+jddpcvodwa 1 300 train
+jddvglluxs 0 300 train
+jddwsnjopj 1 300 train
+jdeekjdfxh 1 300 train
+jdellqtucc 1 300 train
+jdemymqhnq 1 300 train
+jdfaxqtpjk 1 300 test
+jdfciycixq 1 300 train
+jdffbokydq 1 300 train
+jdfpldqjcv 1 300 train
+jdftwygyac 1 301 train
+jdfuhwyyif 0 300 train
+jdfytlbevt 1 300 train
+jdgawxtkmk 1 241 train
+jdghgrdwrr 0 300 train
+jdghzokiyn 1 300 train
+jdgkxhzgwe 1 300 train
+jdgoozcdzv 1 300 val
+jdgqcagwgq 0 300 train
+jdgqsictvt 1 300 val
+jdgrhihslk 0 300 train
+jdgtakoqwu 1 300 train
+jdgzbsjnri 1 300 train
+jdhcpscpnd 1 300 val
+jdhdagckts 1 300 val
+jdhfrxodqe 1 300 train
+jdhnfmufuz 1 301 train
+jdhrcmproz 1 300 train
+jdhrlhmndn 0 300 train
+jdhrvdlgio 1 300 train
+jdhtihlnoi 1 300 train
+jdhujewgmf 1 301 train
+jdhxlmqgij 1 300 train
+jdhxvexhay 1 302 train
+jdhxyyrdit 1 300 val
+jdibnhafli 1 300 train
+jdicavkqya 1 300 val
+jdidbppntn 1 300 train
+jdidklvond 1 300 val
+jdigyueanp 0 300 train
+jdiklnwriz 1 302 val
+jdirunzeah 1 300 train
+jdiywmsukg 1 300 val
+jdjdnrufji 1 300 train
+jdjrnjpapv 1 300 val
+jdjwlbcmzu 1 300 train
+jdkceovlzn 1 300 train
+jdkdqqlxag 0 300 train
+jdkfivxebr 1 300 val
+jdkhmsqneu 1 300 train
+jdkhocvaql 0 300 train
+jdkiztrola 1 298 train
+jdkvgcjxje 1 300 test
+jdkwtlpyio 1 298 train
+jdkzebpryv 1 300 val
+jdkzylguud 0 300 train
+jdldxklaqc 1 300 train
+jdlfqkppgz 1 301 val
+jdlkzubuqu 1 300 train
+jdlqmnhuix 1 300 train
+jdltbwexuy 1 300 train
+jdlugfubgd 1 300 train
+jdlunrupzn 1 300 train
+jdlwbkikfu 1 300 train
+jdmjewwlwc 1 300 train
+jdmjkmtgkt 1 301 train
+jdmrnyamcq 1 300 train
+jdmuadvwfj 1 298 train
+jdndjlxhab 1 300 train
+jdngtplonp 1 300 train
+jdnihunlwu 1 300 train
+jdniqpvmdr 0 300 val
+jdnizohssx 1 134 val
+jdnmcwygbv 0 300 val
+jdnwqgdcgd 0 300 train
+jdnzdjgipn 1 300 val
+jdoekxclgz 0 300 train
+jdonvxwnzw 1 300 train
+jdoynevvri 1 300 train
+jdpbksdxmd 0 300 train
+jdpgqqlwtx 1 300 train
+jdpjubjovv 1 300 val
+jdpoqewunc 1 300 train
+jdprngxdwz 1 300 train
+jdpxqzvlyv 1 300 val
+jdqagmvjic 1 300 train
+jdqfrlmpfi 1 300 train
+jdqlltlnew 0 300 train
+jdqoffbjur 1 300 val
+jdqqgguezm 1 300 train
+jdqwhvbsbe 0 300 train
+jdrbddyfgw 1 300 train
+jdrewsxujt 1 300 train
+jdrhhmyvrk 0 300 train
+jdrhwiuwtd 1 300 val
+jdrkrpobmg 1 300 train
+jdrlqvwpwn 1 300 train
+jdrrxwlmfe 1 300 train
+jdruzblgzt 1 300 train
+jdrwscppus 1 300 train
+jdrzjgvsag 0 298 train
+jdrzuflzbu 0 298 train
+jdsbzjdcdv 1 300 train
+jdsganedqh 1 300 train
+jdsgwxuyin 0 300 train
+jdsjnbdpti 1 296 train
+jdsjzzgzlf 1 300 train
+jdskdykrct 1 299 test
+jdsqboubqm 1 300 train
+jdsurjvxxq 1 300 val
+jdszbmohug 1 300 train
+jdtkzobksf 0 300 train
+jdtlmfhvel 1 298 train
+jdtlqvfwut 0 300 train
+jdtoregira 0 300 val
+jdtqfrszwm 1 240 train
+jdtuslifje 1 300 train
+jdtvasjggb 1 301 train
+jdtxkroifj 1 301 val
+jdubbvfswz 0 300 train
+jdueipntuo 1 301 train
+jduhzatmnf 0 300 train
+jduilfrsta 1 298 train
+jdujogycws 1 300 train
+jdumxqfzop 1 300 train
+jduphrgqqw 1 300 train
+jduvvjoejn 1 300 train
+jduzrspspr 1 299 train
+jdvdeobprm 1 300 train
+jdvkcoqlys 1 301 train
+jdvssumjzv 1 300 train
+jdvtkpjubr 1 300 val
+jdvwbbwqed 0 300 train
+jdvzqjihud 0 300 train
+jdwkwnlgkk 1 300 train
+jdwubpkquk 1 300 train
+jdwymabbbx 0 300 train
+jdwywxvxgf 1 300 train
+jdxfxyljjw 1 300 train
+jdxgiuqkzh 1 300 train
+jdxgvdgoir 1 300 train
+jdxjgytlva 1 300 train
+jdxnotoadb 0 300 train
+jdxojmzvdn 0 300 train
+jdxulhdoyv 1 300 train
+jdxvbzwshp 1 300 train
+jdxylhjgft 1 300 train
+jdyhvrsier 1 300 train
+jdyjdkuknq 1 300 train
+jdymowzncw 1 301 train
+jdynzksrau 1 300 train
+jdyqsuybsd 1 300 train
+jdyrbxmpsc 1 300 train
+jdyrecrjtv 1 300 val
+jdzdbpqsjm 1 300 train
+jdzdlgkfiz 1 300 val
+jdzgjbqksy 1 300 test
+jdzkmwbdyu 1 300 train
+jdzkvhchja 1 301 train
+jdzkykqgsx 0 300 train
+jdzqptropt 1 300 train
+jdztasqled 1 299 val
+jdzuhquobd 1 147 train
+jdzzgkvlgp 1 300 train
+jeabpshdmp 1 300 train
+jeajtmnxpj 1 300 train
+jeakupfepe 1 300 train
+jeaovjrwbh 1 300 val
+jeaquifmqr 1 297 train
+jeaupgnxll 1 300 val
+jeavzltvzv 1 300 val
+jeaydhrzqc 1 300 train
+jebfboxyyt 1 301 train
+jebfdcgkyk 1 300 train
+jebipymfgn 1 300 val
+jeblbsmlij 1 300 test
+jebskmgkhy 1 300 train
+jebtchddux 1 300 train
+jebtnygbte 0 300 val
+jebwesgcko 1 300 train
+jebziyowsd 1 300 train
+jecaspvwdx 0 300 val
+jecaylfurj 1 301 train
+jeckydypxe 1 300 train
+jeclduagbh 0 300 train
+jecnyqdnit 1 300 train
+jecphujqqk 1 300 val
+jecploouyl 1 300 train
+jecqoldsmp 1 297 train
+jecsgtcsaf 1 300 val
+jecucaanpp 1 301 train
+jecyqtgbnb 0 300 train
+jedoneccwd 1 300 train
+jedoyrtmpc 1 300 train
+jedufjsqzl 0 300 train
+jeeaasrdwy 1 301 val
+jeeetboyqz 1 300 train
+jeeinabjqq 1 300 train
+jeejkkargi 1 300 train
+jeelittiwf 1 300 val
+jeemocjotx 1 297 train
+jeeopvvzzh 0 301 train
+jeexcirluy 1 300 val
+jefecqmmbd 0 300 train
+jefuwxesbw 1 300 train
+jefweckgnl 1 301 train
+jefzechyiu 1 300 train
+jegaokdbdb 0 300 val
+jegdxhxnfe 1 300 train
+jegfyndudz 1 300 train
+jeghuhpdwi 1 300 train
+jegqwgnmql 1 300 test
+jehcrpdezx 1 300 train
+jehihkigxw 1 300 train
+jehmjvcccg 1 300 val
+jehqqelrpx 1 300 train
+jehwdtszrt 1 300 train
+jeierullea 1 300 val
+jeifvfftpl 1 300 train
+jeipufjffh 1 301 val
+jeisruklyb 1 300 train
+jeittyrcui 1 300 train
+jeivlervlc 1 239 val
+jeizgwneir 1 300 train
+jejdgssoat 1 300 val
+jejhkrsjrw 1 300 val
+jejhxtozrh 1 300 train
+jejjcsijvc 1 300 val
+jejjxhajij 1 300 train
+jejocgtpyx 1 300 train
+jejppsekfq 1 300 train
+jejypxqtrv 1 301 train
+jejzjwuumk 1 300 train
+jekdpxipmi 1 300 train
+jekledrxqw 1 300 train
+jekodoebus 0 300 train
+jekqutvzpb 0 300 train
+jekvoetlsu 1 241 train
+jekxnohueu 1 302 val
+jekygpznjo 1 300 val
+jekyhkswtp 1 193 train
+jelegykytj 1 301 train
+jelmzelvoj 1 300 train
+jelpmzcvzz 1 300 test
+jelwdnqdxk 1 300 train
+jelzjknnet 1 300 train
+jemmcluaff 1 300 train
+jemrrgssqn 1 300 train
+jemtsdjgxq 1 298 train
+jemwfzbkqc 0 300 train
+jendkcelzh 1 300 train
+jeniyeuohf 1 300 val
+jenjkegnjn 1 300 train
+jenwovyzez 1 301 train
+jeoafxjcaa 1 300 train
+jeoanqwwfx 1 300 train
+jeoatgbtmh 1 300 train
+jeofrozgqs 1 300 train
+jeogqnpnrr 1 298 train
+jeokwpavxm 1 300 train
+jeosukfzow 1 300 test
+jeouiqhagh 1 300 train
+jepavgmbmf 1 300 val
+jepguaulgf 0 300 train
+jepjsuhddh 1 300 train
+jeplbgorta 1 300 train
+jeprokqshs 1 300 val
+jeptbdagbt 1 300 train
+jeqavwmktg 1 300 train
+jeqblglebh 1 300 train
+jeqeclziwh 1 300 val
+jeqhsihhgm 1 300 val
+jeqibfcqoy 1 300 train
+jeqjbotqsn 1 300 train
+jeqmtltkwb 1 300 val
+jeqpnjqhsc 1 288 train
+jeqxukpock 1 301 train
+jerdficrrp 0 300 val
+jerhryuwgo 1 300 val
+jerlmkdkxp 1 300 train
+jerscnojfq 1 240 val
+jersqypdbt 1 298 train
+jerzgxxano 1 300 train
+jescniiznk 0 300 train
+jeshtjowtx 1 300 val
+jesjtnfuhe 1 300 train
+jeskbusgja 0 300 train
+jesnczpmly 1 300 train
+jesstfspwv 1 300 train
+jesvpeuvkv 1 300 train
+jeswozogcb 1 300 train
+jesxydcwae 1 301 train
+jetbbieuzs 1 300 train
+jetbpvzhzi 1 300 train
+jetnuhkjwy 0 300 train
+jetrpilbzt 1 300 train
+jetugcmdfk 1 299 val
+jetuwscipg 1 298 val
+jetvxgotuz 0 300 train
+jetyjwflrf 0 300 train
+jetyrkqaif 1 300 train
+jeucjzfnkv 1 301 train
+jeujfvgrnh 0 300 train
+jeunztbgqk 0 300 train
+jeurdxpfnt 0 300 train
+jeuvnqstmj 1 300 val
+jeuybgsqre 0 300 train
+jevtocgbcd 0 300 train
+jevtstncoj 1 300 val
+jewawswhvd 1 300 train
+jewhgesjay 0 300 train
+jewhpnzwkc 1 300 train
+jewkbeztdl 1 300 train
+jewmklzjhc 0 300 val
+jewowokzmj 1 300 train
+jewxpncdcp 0 300 val
+jexjxmbuwo 1 300 train
+jexkwqljok 1 300 val
+jexttqprhw 1 300 train
+jexuhsfnox 1 302 val
+jexvqmufit 1 300 train
+jeyeioajbs 1 300 train
+jeyeqgtdzj 1 300 train
+jeyvgixnkm 0 300 train
+jezchlgqer 1 300 train
+jezdhobejc 1 300 train
+jezgsvsqjp 1 300 train
+jezmqbtfss 1 300 train
+jezvgslgik 1 300 val
+jezxpnfxbo 1 300 val
+jfaifjoolx 1 300 train
+jfajjjihnq 1 300 train
+jfakgkzfez 1 300 train
+jfarfiijed 1 300 train
+jfarjhhlsc 1 300 val
+jfaujojdsj 1 300 val
+jfavahiiib 1 300 train
+jfayfmnxke 1 300 train
+jfayzgziay 1 300 train
+jfbcefsgtw 1 300 train
+jfbcuppbux 0 301 val
+jfbdksvkgn 1 300 train
+jfbdqoiofz 1 297 val
+jfbeifrbty 1 300 train
+jfbeqfotli 1 300 test
+jfbiuazgwb 1 300 train
+jfbljslbfc 1 300 train
+jfbnkogfbq 0 300 train
+jfbottnlel 1 300 val
+jfbqhuavob 1 300 train
+jfbwytvbwa 1 300 train
+jfbyzayxvi 1 300 train
+jfcbizbpiq 1 300 train
+jfcglbovmo 1 300 train
+jfcimzbqag 1 300 train
+jfckjoceqc 1 300 val
+jfclkecjoj 0 300 val
+jfcnyinasq 1 300 train
+jfcrowripg 1 300 train
+jfcsumiude 1 300 train
+jfcwqpuqxg 1 300 test
+jfcxsltrtq 1 300 train
+jfczxmooec 1 300 train
+jfddnzbgra 1 299 train
+jfddvprhzr 1 300 train
+jfdifxyycg 1 300 train
+jfdjwujeka 1 298 train
+jfdlksvxii 1 300 train
+jfdowopymy 1 300 train
+jfdpdvqrly 1 300 train
+jfdtqjbsvv 1 300 val
+jfdujlungr 0 300 train
+jfdzfaatju 1 300 val
+jfecpdvglu 1 300 val
+jfeepwized 1 300 train
+jfehxzplvy 1 300 val
+jfepsctkoh 1 300 train
+jfepznjnhf 1 300 train
+jfexfhpiom 1 300 val
+jffclvscpj 1 300 val
+jffcyrahxs 1 300 val
+jfffqmhuwb 1 298 train
+jffjarszar 1 300 val
+jffrjoefsw 1 298 train
+jfftcgpmou 1 300 train
+jfgbiuryyp 1 300 train
+jfgbjjghxz 1 300 train
+jfgchvcaud 1 300 train
+jfgdfmmekk 1 300 train
+jfggaheccf 1 300 train
+jfghpzveqs 1 300 train
+jfgidfrxqn 1 300 test
+jfgjmrvqve 1 300 train
+jfglfhocla 1 300 train
+jfgmrhizml 0 300 train
+jfgpljdjph 1 300 val
+jfgthbfidq 0 300 train
+jfguzsqnlv 1 301 train
+jfgyrpuqig 1 300 val
+jfgyytfdfd 1 300 train
+jfhazzusgt 0 300 val
+jfhcyymhwz 1 300 train
+jfhjyflcnz 1 300 train
+jfhtynnkrt 1 300 train
+jfhujpvkay 1 299 val
+jfiaviauck 0 300 train
+jfighqzpzm 1 300 train
+jfiglglxvn 1 300 train
+jfihvhrjyr 1 301 train
+jfiiefyxyn 1 300 train
+jfiihcpiyh 1 300 train
+jfinjeuoqb 0 300 val
+jfiqnujzis 1 300 train
+jfiysrbhjy 1 300 train
+jfjberuxhh 1 300 train
+jfjevcdrgg 0 298 train
+jfjfffzcrn 1 300 train
+jfjrlqtoyb 1 300 train
+jfjshyeukc 1 300 train
+jfjudabiii 1 299 val
+jfjuftvhqw 1 298 train
+jfjvyslvjc 1 301 train
+jfjwutmlhp 1 300 train
+jfjyjkuwae 1 300 train
+jfkfyjpzcd 1 300 train
+jfkjfpowdh 1 300 train
+jfkrcsuslj 1 300 train
+jfkstihilh 0 300 train
+jfktrewzkh 1 300 train
+jfkvjlyfsk 1 300 train
+jfkwkohdoc 0 300 train
+jfkzdpzwao 1 300 train
+jfkzebfyhd 1 300 train
+jfkzqqvovj 1 300 train
+jflcdopyom 1 241 train
+jfldyyitxb 0 300 train
+jflohkbmxn 1 300 train
+jflysftryf 1 300 train
+jfmaqowfwv 1 299 test
+jfmbffomax 1 300 train
+jfmchvdonq 1 300 test
+jfmecdkdgf 1 300 val
+jfmkpjnvgb 1 300 train
+jfmkucncfb 1 300 val
+jfmmvfpudw 1 300 test
+jfmqjuqapd 1 301 train
+jfmuzpcoxt 1 300 train
+jfmvrhoxwh 1 300 train
+jfmwcojlml 1 300 train
+jfnbwcwnrh 1 300 train
+jfniqyqcnj 1 300 val
+jfnshutkal 1 300 train
+jfnthahjpc 1 300 train
+jfnucwnoby 0 300 train
+jfnuwvhhzm 1 300 train
+jfnyjxupxm 1 300 train
+jfnzfcxjcj 1 300 train
+jfodsknfql 1 300 val
+jfogmqqqwk 1 300 train
+jfolvgnfee 1 255 train
+jfooqrefta 1 297 train
+jfopmvjwuj 1 300 train
+jfoqcidgbl 1 300 train
+jfosiwxjmd 1 241 train
+jfoywilhat 1 300 train
+jfozdfoycz 1 300 train
+jfpbjjhzoh 1 300 val
+jfpedtdmbo 0 300 train
+jfpglxltpd 1 300 train
+jfpigbucue 1 300 train
+jfpnohzknd 1 300 train
+jfpwczbybt 1 299 train
+jfpwydtaye 1 300 val
+jfqjypvbop 1 300 train
+jfqladzfeb 1 241 train
+jfqmsklemx 1 300 val
+jfqnctxtuy 1 300 train
+jfqxuopeol 1 300 train
+jfrahkrzbx 1 300 train
+jfrcjjfmqo 1 300 val
+jfrfcnodxt 0 300 train
+jfrkmgldsg 0 300 train
+jfrtugaqht 1 300 train
+jfrueisgic 0 270 train
+jfrvwmuorp 1 300 val
+jfshfucnsl 1 300 train
+jfsnazcbxd 0 300 train
+jfsnqbgrdw 1 300 train
+jfsutpsimt 1 300 train
+jfszfqkyem 1 300 train
+jftkyrtekx 1 300 train
+jftqyptpnb 1 300 train
+jftrbnijmt 1 300 train
+jftslzalsj 1 300 train
+jftwcyvkvc 1 241 train
+jfubmfrtxr 1 300 train
+jfuezzawyk 1 300 train
+jfukvmrirl 1 300 train
+jfunocattx 1 300 train
+jfuqtakysf 1 300 train
+jfuucsoeeb 1 300 train
+jfuxqvfucv 0 299 val
+jfuypqgyxv 1 300 train
+jfvfqxaeyh 1 300 train
+jfvgibibcm 1 300 train
+jfvhokkzmq 0 300 train
+jfvioypbfg 1 300 train
+jfvjlzgkgx 0 300 train
+jfvmphfxaz 1 300 train
+jfvnwpcjrm 1 300 train
+jfvsrcfame 1 300 test
+jfvwafmdxm 1 300 train
+jfwbtzpwds 1 300 train
+jfwhxrlnrm 0 300 val
+jfwjaeoizs 1 300 train
+jfwkcuhqxi 1 301 train
+jfwxyzuhiy 1 300 train
+jfxhwvpyjs 0 300 val
+jfxiyrvtvk 1 301 train
+jfxjsqlupt 1 300 train
+jfxroglrst 1 300 train
+jfxvohewqu 0 300 val
+jfxyegpyfe 1 301 train
+jfxzbxjbac 1 300 val
+jfybskdfvq 1 300 train
+jfyeadetdx 1 300 val
+jfyqefjwqh 1 298 train
+jfytzvfygd 1 300 train
+jfyumqwrdw 1 300 train
+jfywcnmzut 1 300 train
+jfyzfnawgt 1 297 train
+jfzilrwtrn 1 300 train
+jfzjnmnare 0 300 train
+jfzlnqyraa 1 300 train
+jfzsbvmvil 1 300 train
+jgaejvfomy 1 300 train
+jgasqbyrbo 1 300 train
+jgattisyur 0 300 val
+jgaurqhtri 1 300 train
+jgbbakaqtc 1 300 train
+jgbbldvxim 1 300 train
+jgbdfsjvuj 1 300 train
+jgbjkukyyp 1 300 train
+jgbpkhafrm 1 300 train
+jgbpmnqoxl 1 300 test
+jgbwcvxarh 1 300 train
+jgcexuawcp 0 300 train
+jgcsktyhif 1 300 val
+jgctemodlk 1 297 train
+jgcykhzlwv 1 300 train
+jgdbaqpiog 1 301 train
+jgdexanjjk 1 300 train
+jgdhbqffry 0 300 val
+jgdjmiibjf 1 300 train
+jgdqcnykgf 1 301 train
+jgdqirjslx 1 300 val
+jgdrcvviil 0 300 test
+jgdshpoygh 1 300 train
+jgdtfopkqx 1 300 val
+jgdyhdnsva 0 300 train
+jgdynnqhui 1 302 val
+jgdzqmqalr 1 300 train
+jgegsztyti 1 300 train
+jgehfzchud 1 298 train
+jgeiwlrjwk 1 299 test
+jgenynfvmw 0 300 train
+jgetoqsuou 1 300 train
+jgfdjejxcx 1 300 val
+jgfgpxoraf 1 241 train
+jgfirmaztx 1 300 val
+jgfmyvsidd 1 300 train
+jgfpmasqnf 1 300 train
+jgfpubdbyh 1 300 val
+jgfqalzwqh 1 300 train
+jgftxcnnca 1 300 train
+jgfvckriik 1 301 train
+jgfvexwjix 1 300 train
+jgfyeshyrg 1 300 train
+jggavlevbd 1 301 val
+jggkwuvgwa 1 300 train
+jggovedevi 1 300 train
+jggrlvifyl 1 300 train
+jggxcrioho 1 300 train
+jggxilgdef 1 300 train
+jghdytpumr 0 300 train
+jghfrsibsy 1 300 train
+jghitsalsd 1 300 train
+jghjmgaipt 1 249 train
+jghzdkuzyy 1 300 train
+jgidbsavtz 1 300 test
+jgihhmuvpi 0 300 train
+jgijuusdev 1 300 train
+jgishqyglv 1 300 val
+jgjascdgnz 1 300 train
+jgjatlapxn 1 300 train
+jgjctxasju 1 300 train
+jgjedubejh 0 300 train
+jgjfgqwhuu 1 296 train
+jgjllbodby 0 301 val
+jgjqatboag 1 300 test
+jgkmoxkxmg 1 300 train
+jgkpgyfhkf 1 300 train
+jgkrmffxys 1 301 train
+jgkzgdxozk 1 300 train
+jglbxlgwvj 0 300 val
+jglflyakou 1 300 train
+jglhlccrhl 1 300 train
+jglironpiv 1 300 train
+jglmjblhxm 0 300 train
+jglnqzxiop 1 300 train
+jglooveumk 1 299 test
+jglrfawgpc 1 300 train
+jglritnjfh 1 300 train
+jglubjbhnu 1 300 val
+jglvgjadnn 1 300 train
+jgmehcszoc 1 300 train
+jgmkfxuiqo 1 301 val
+jgmlazvbtk 0 300 train
+jgmtynuyqc 1 300 train
+jgmxaxbjfb 1 300 train
+jgnacfspue 1 300 train
+jgneecgjym 1 300 train
+jgnfjzqngy 1 300 val
+jgnpgycufc 1 300 train
+jgnrpluikf 1 288 train
+jgnrwvzdiz 1 300 train
+jgnurwfutc 1 300 val
+jgnxfufiwz 1 300 train
+jgoaylwwcn 1 300 train
+jgoplvdxdz 1 300 train
+jgpcebnhcz 1 300 train
+jgpdevhsqp 1 300 train
+jgpehjkuvu 1 298 train
+jgpkntwotd 1 298 train
+jgpsgbqyop 1 300 train
+jgpxmqxazp 1 299 test
+jgqectjgta 1 241 train
+jgqemdtqsq 1 301 val
+jgqmhhojzo 1 298 train
+jgqsgiclfp 1 300 train
+jgqxfqflft 1 298 train
+jgqztwdofx 1 300 val
+jgrdzsjsqn 0 300 train
+jgrehpbivm 1 299 val
+jgrrayzssl 1 300 train
+jgrtmjmqmj 1 300 val
+jgrtpfnlks 0 300 train
+jgrznynobk 1 300 train
+jgsdoaxfgj 1 300 train
+jgsemsamng 1 300 train
+jgseqihdbs 1 300 train
+jgsvseuwld 1 241 train
+jgtfjkcdfy 1 300 train
+jgtimrprjo 1 300 train
+jgtjjltjtg 1 300 train
+jgtjqmsajp 0 300 train
+jgtmaektcr 1 300 val
+jgtnfihyha 1 300 train
+jgtnkwltxd 1 300 val
+jgtnwbmofm 1 300 val
+jgtzjmttnu 1 300 train
+jgudqdkfmv 0 300 train
+jgujkodmlr 1 300 train
+jguknmconu 1 300 train
+jgumxadkch 1 300 train
+jguwkpmpao 0 300 train
+jguztwqvow 1 300 train
+jgvbjktqff 1 298 train
+jgvjmtlvek 0 300 train
+jgvpahijuh 1 300 train
+jgvpzcwozz 1 300 train
+jgvqoasjoi 0 300 val
+jgvxopxppa 0 300 train
+jgwifximhk 1 300 train
+jgwlvjbzjy 1 300 train
+jgwmeuaiyk 1 300 train
+jgwmoaiepq 0 300 train
+jgwnsuhilq 1 299 test
+jgwpzwxfta 1 300 train
+jgwrcygoql 1 301 val
+jgwuktnwgg 1 300 train
+jgwvgzjaeh 1 300 train
+jgwzyyfrxj 1 300 train
+jgxccifcgz 1 300 train
+jgxfifwlmx 1 300 train
+jgxjosrmlr 0 300 val
+jgxmuqhjhy 1 299 val
+jgxqfjpxfv 1 300 train
+jgybxxtltz 1 300 test
+jgyefdpcga 1 300 train
+jgyggwcoyi 1 300 train
+jgyyolcuep 1 300 val
+jgzhasocpu 1 298 train
+jgzhtvmvwm 1 300 train
+jgzhzetaqy 0 300 train
+jgztkbadbf 1 300 train
+jgztvwnpez 1 300 val
+jgzuidmelw 1 300 train
+jgzvkvmpro 1 300 train
+jgzvxebper 1 300 train
+jgzwhkcrcc 1 300 test
+jhactuqgwa 1 300 train
+jhajwlaakq 1 300 train
+jhamstcxmf 1 300 train
+jhasfeplgl 1 300 train
+jhbbaueqva 1 300 train
+jhbgeoravd 1 299 train
+jhbmyltlce 1 300 train
+jhbpkmnesn 1 241 train
+jhbsmjcjhp 1 300 train
+jhbxzwfzly 1 300 train
+jhccvzwonn 1 300 train
+jhchearscf 1 300 train
+jhcnxlxdol 1 300 train
+jhctyebusd 0 300 train
+jhcxyejyef 1 300 val
+jhcynxkhku 1 300 train
+jhczqfefgw 1 300 test
+jhczqojdwx 1 300 train
+jhdhlxruqo 0 300 train
+jhdjjywifr 1 301 train
+jhdklkpruv 1 300 val
+jhdrxeelhb 1 300 train
+jhecetyfym 0 300 train
+jhegswpvdq 0 300 train
+jhehlerhmd 1 301 train
+jheilvdkdl 1 300 train
+jhekdjfehl 1 300 train
+jheknxtwzo 1 301 train
+jhelknsabm 1 300 train
+jhetgmikln 1 300 test
+jhevyvqqyp 1 300 train
+jhewbevyph 1 298 train
+jhextjvyqj 1 301 val
+jheytzqien 1 300 train
+jhfgjykwon 1 300 val
+jhfnhpcpzy 1 300 train
+jhfnvrxdow 1 297 val
+jhfquaeasu 1 300 train
+jhfwwrljql 1 300 val
+jhfykjblun 1 300 train
+jhgcmcbnck 1 301 train
+jhghidziij 0 300 train
+jhgjvcuujf 0 300 train
+jhglcodeyo 1 300 train
+jhgmnakqpy 1 240 train
+jhhecxbbkw 1 300 train
+jhhlagbfkl 1 300 train
+jhiajzqwhw 1 298 train
+jhibrhprsb 1 300 val
+jhigeycavr 1 241 train
+jhihpqpkmb 1 300 train
+jhiiwjnzba 1 300 val
+jhijukrldh 1 300 train
+jhiktmavev 1 300 train
+jhiqhamnve 1 300 train
+jhirbpuvho 1 300 val
+jhispjezcs 1 300 train
+jhiulnahbl 1 300 train
+jhixkklllq 1 300 train
+jhjbedmgba 1 301 train
+jhjdkfctdg 1 300 val
+jhjfkifdgx 1 299 val
+jhjghxwhep 1 300 test
+jhjjvdmrcz 1 300 val
+jhjjzicjvi 1 300 train
+jhjpidynpx 0 300 train
+jhjplwemul 1 300 train
+jhjsqgswlt 1 300 train
+jhjwhhtilw 1 297 val
+jhjyafbjqo 0 300 train
+jhkaevqfog 1 241 train
+jhkdzxgiig 1 300 train
+jhkptnikbb 1 300 train
+jhksgresva 1 300 val
+jhkudfsaoi 1 300 val
+jhllkvpaae 1 300 val
+jhlnhoqcdb 1 269 train
+jhlnjlkvej 0 301 train
+jhloraczby 1 300 val
+jhlvjsnwpz 1 298 train
+jhlwgeyuoi 1 300 train
+jhlzkvzsrh 0 300 train
+jhmbwwrrac 1 300 train
+jhmliugwqq 0 300 train
+jhmrrzriad 1 298 train
+jhnaxwgasd 1 299 test
+jhneddzztv 1 300 train
+jhnhfuyfno 1 300 train
+jhnjkjvwgd 1 300 train
+jhnrzqlhxk 1 300 train
+jhntvxshiw 1 300 val
+jhnxzkogcg 1 300 val
+jhoafbyhax 0 300 train
+jhomaktgzy 1 134 train
+jhomwnydeg 1 300 val
+jhonpnpoue 1 300 train
+jhouhfsljj 1 301 val
+jhovmotrex 1 300 train
+jhowlvsuzw 1 300 train
+jhphbvyjsb 1 300 train
+jhpkbwstpw 1 300 test
+jhpouexeaw 1 300 train
+jhpteycmyf 1 300 train
+jhptltfuug 1 300 train
+jhpudjmclc 1 300 train
+jhpuechetx 1 300 train
+jhpuqavmpf 1 298 train
+jhpwkjoouj 1 241 train
+jhqblgyoum 1 300 train
+jhqhjybjdk 1 300 train
+jhqlzbqgnp 1 300 val
+jhqmerdjhq 1 300 train
+jhqyslavqq 0 300 val
+jhqyslqgps 1 300 val
+jhrbtapxwo 1 300 val
+jhrewrkujb 1 300 val
+jhrgjpcpbi 0 300 train
+jhrhjelywq 1 300 train
+jhrihxbrtp 1 300 train
+jhroxjxobw 1 300 train
+jhrydzhdkh 1 298 val
+jhryjowivx 1 300 train
+jhsayjbgva 1 300 train
+jhsdczgxic 0 300 train
+jhshxnfxnb 1 300 train
+jhsohpyhki 1 300 train
+jhspiyddlk 1 298 train
+jhspjfwghh 1 300 val
+jhszstpvpf 1 300 train
+jhtafcntss 0 300 train
+jhtejtlmpo 1 300 train
+jhtphsligx 1 300 train
+jhttzsdeke 1 300 train
+jhtuwflmnm 1 300 train
+jhtyzvbhkx 1 300 train
+jhucouutjg 1 300 val
+jhugffruzt 1 300 train
+jhugtokabb 1 300 train
+jhumldyaxq 1 300 train
+jhunmskdxo 1 300 train
+jhutqwxnyz 1 300 train
+jhuzawsahl 0 300 train
+jhvgzyuosr 1 300 train
+jhvmeghzri 1 300 train
+jhvmsuocuf 1 300 train
+jhvqipsmss 1 300 train
+jhvvkiwfwq 1 300 test
+jhvxwpjkms 1 300 train
+jhvxzteeei 0 300 val
+jhweajgahu 1 300 train
+jhwfbfwlul 1 299 train
+jhwlpyoxnk 1 301 train
+jhxatjqafb 1 300 train
+jhxdmdvprp 1 300 val
+jhxhrlcfbh 1 300 train
+jhxifbrgwu 1 300 train
+jhxmmetnfa 1 299 train
+jhxqukpbcs 1 300 train
+jhxwycmkbl 1 300 train
+jhxxzptgan 1 300 train
+jhxyfmsrrm 1 298 train
+jhyfxihnws 0 300 train
+jhylzkolmg 1 300 train
+jhyqkbiydn 0 300 train
+jhyrglgwqj 0 298 train
+jhysrfalxs 1 300 train
+jhyvbmsxwp 1 300 train
+jhyvxtuhlb 1 300 val
+jhzbwezmcs 1 300 train
+jhzdaoscwv 1 300 val
+jhzhjplvzn 0 300 train
+jhzjdozpiy 1 301 val
+jhzmgdsuqe 1 300 train
+jhzozsurac 0 300 val
+jhztphnhit 0 300 train
+jhzvqkivtu 1 298 train
+jhzximmeyt 1 300 train
+jhzxlgbetm 1 240 val
+jiaixqijtv 1 300 val
+jiajoalqzh 0 300 val
+jiallftwct 1 300 train
+jiaqdnqluv 1 300 train
+jiavqbrkyk 0 300 test
+jibawajgsh 1 300 train
+jibbjwufbf 1 269 train
+jibcwhgpup 0 300 train
+jibhugdfbs 1 300 train
+jibkzdatek 0 300 train
+jiblxijzgp 1 300 train
+jibmmlkkfo 1 300 train
+jibpgthvrn 1 300 val
+jibqkhgqww 1 300 train
+jibxryehyp 1 300 val
+jicbvkjjdq 1 301 val
+jicebollua 1 300 train
+jichqsnkxx 1 302 val
+jickjfbicd 0 301 train
+jicmvwnfde 1 300 val
+jicspspkbz 0 300 val
+jicsxmypxm 1 300 val
+jicxtmjduw 1 300 train
+jiczofiqnw 0 300 val
+jidavnfzmf 1 300 val
+jidbemztpa 0 300 train
+jidbgjqkur 1 300 train
+jidbmqevbi 0 300 train
+jiddesrgoi 1 300 train
+jidhnvtrpf 1 300 train
+jidjicpeqj 1 300 train
+jidjvpzwbg 1 300 val
+jidkzoagws 0 300 train
+jidosktebk 1 300 test
+jidtpybyfm 1 300 train
+jidtuhidog 1 300 train
+jiecdabeaq 1 300 val
+jieeajumtx 1 300 train
+jiejvvjhzh 1 300 train
+jiemwyondu 1 300 train
+jierwcacbo 1 301 val
+jietpvmhij 1 300 train
+jieuqpyvnm 1 300 train
+jiexuinezh 0 300 train
+jieyxqsecs 1 300 val
+jifboiffmf 1 300 train
+jifceqalmp 1 300 train
+jifgoxdldc 1 300 train
+jifhsxvdyw 1 300 val
+jifjcvtqar 0 300 val
+jifkbgreko 1 300 val
+jifnrzuwwd 1 240 train
+jifrtsgmlr 1 300 val
+jifvfnhfpn 1 300 train
+jifvgbtlkv 1 300 train
+jifwnjycks 1 300 val
+jifxwxpnsa 1 300 train
+jifzrwiyxt 0 300 train
+jigfxwduiw 1 300 train
+jigproqgns 0 300 train
+jigssihghr 1 300 train
+jigtcgxbro 1 300 train
+jigtkjrbot 1 298 val
+jihajeoivn 1 300 train
+jihbfmnsci 1 300 train
+jihhseagvg 1 300 train
+jihmnpdxoi 0 300 val
+jihpgmechw 0 300 val
+jihpjftjpt 1 300 train
+jihtpjpiox 1 300 test
+jihznxveun 1 300 train
+jiierqjyrb 1 302 train
+jiisquwdyu 1 300 train
+jiivsvouxw 0 300 train
+jiiwgqnekq 1 241 train
+jijkfdwixj 1 301 train
+jijmphxrqd 1 300 train
+jijnndhell 1 300 train
+jijpyzxkfw 1 300 train
+jijydihvum 1 300 val
+jijyuxiqpl 1 300 train
+jijzextciy 1 300 train
+jijzieywty 0 300 train
+jijzjqbooq 1 300 train
+jikbcxxzsp 1 300 val
+jikcoeqasq 1 300 train
+jiklttzoht 1 298 train
+jikoqjgviv 1 300 train
+jiksdkgocr 1 300 train
+jikswtkmeg 1 300 train
+jikxjegvbn 1 300 train
+jikxmvntlu 1 296 train
+jikxnnhscb 1 300 train
+jikzlboymo 1 300 val
+jilapojult 1 300 train
+jilarwvlxm 1 300 train
+jilbcjahbv 1 300 train
+jilfwcuyrp 0 300 train
+jilhrmunzr 0 300 train
+jiljbcpjzh 1 300 val
+jillyqtact 0 300 val
+jilpenulal 1 300 train
+jilquoitml 0 300 val
+jilrvmzjfe 1 299 test
+jilscygdbw 1 240 train
+jiltjygimx 1 300 train
+jiltpzdfwg 1 300 train
+jimftpswex 1 302 train
+jimhylsoyt 1 300 train
+jimjnofwih 1 300 train
+jimmxgiwpl 0 300 train
+jimqjwaqle 1 301 val
+jimyddcjzl 1 300 train
+jinawwgxls 0 300 val
+jinbhnxsfk 1 300 train
+jincloewtg 1 300 train
+jindwbbvya 1 300 train
+jinomojicv 1 300 test
+jintynmhzu 1 300 train
+jinubpzyth 1 300 train
+jinzlsofla 1 300 train
+jinzqwrtos 1 300 train
+jiomduynyg 1 300 train
+jioqrlrmxl 0 301 train
+jioxevwjwu 0 300 train
+jipfjtgrqv 1 300 train
+jiphhyvxez 1 300 val
+jiphzqtbam 1 300 train
+jipjequbqf 1 299 val
+jipnxxxsog 1 300 train
+jipojvbnri 1 300 train
+jiprjbmojq 1 300 train
+jiptqojggg 1 300 train
+jiqaiaurvp 1 299 val
+jiqhuhqtdf 0 300 train
+jiqmkebhue 1 300 val
+jiqnlxpoul 1 300 train
+jiqnrbobep 1 288 train
+jiqnruiajw 1 300 train
+jiqqjkqbgw 1 298 train
+jiqswtmzff 0 300 train
+jircykzwxu 1 300 train
+jirgnrwzsv 1 300 train
+jirjygmovt 1 300 val
+jirknefhky 1 300 train
+jirmulechj 1 300 test
+jirqiqyyfb 1 300 train
+jirupuxxvt 1 300 train
+jirzotxeun 1 300 train
+jiscdcyxnp 1 300 train
+jiscrkliic 0 300 train
+jisdydociz 1 302 train
+jisglbrdnb 1 300 train
+jislcvfnzf 0 300 train
+jiswxuqzyz 0 300 test
+jisynpcyxq 1 300 train
+jiszokmppd 1 300 train
+jiszxbqhcq 0 300 train
+jitbvgevrw 1 300 train
+jitcnijcij 1 300 train
+jitfmnmitq 0 300 val
+jitmtcwlsi 1 300 train
+jitpbcqjbq 1 300 train
+jitsafnzkt 1 300 train
+jiubdawybj 1 300 val
+jiufjajnvq 1 300 train
+jiufrxsvkl 1 300 train
+jiufsgbtlu 1 300 train
+jiugbwylsj 0 300 train
+jiujpemdwt 1 300 val
+jiupdoxnpg 1 300 val
+jiupoqvptp 1 300 train
+jiuqjdqytr 0 300 train
+jiusgiscfl 1 300 train
+jiutglcbhf 1 300 train
+jivfvgfken 1 300 train
+jivjhcomtm 1 300 train
+jivmrkqgen 1 300 train
+jivriunvyi 1 300 train
+jivtuckmxg 1 300 val
+jivvpnwwcm 1 300 train
+jivwekgjqr 0 300 train
+jivwoiqeyj 0 300 train
+jivwrppbsq 1 298 train
+jiwdqhoxvo 1 300 train
+jiwlonxohi 0 300 train
+jiwmkmdphy 1 300 train
+jiwvgbcmle 1 300 train
+jiwwcqggnm 1 300 train
+jiwwwkcyln 1 301 train
+jiwxdekjug 1 298 train
+jixddzligx 1 301 train
+jixempvkxy 1 300 train
+jixfcrcbiz 1 300 train
+jixjhrdtnq 1 300 train
+jixkbxjpkn 1 300 val
+jixmwjqphy 1 301 train
+jixtdgoybl 1 300 val
+jixtlyitnn 1 300 train
+jixwxbpoge 1 299 train
+jixxboonlz 1 300 train
+jiyaskebfc 0 301 train
+jiyiwjazle 1 301 train
+jiyjnwhzfi 1 300 val
+jiyjoygikx 1 300 val
+jiylosgavl 0 300 train
+jiynwlziwv 1 300 train
+jiyujgqtav 1 300 train
+jizadreaeq 1 300 train
+jizgeonxnm 1 300 train
+jizjbfjdhz 0 300 train
+jizkpwewde 1 300 train
+jiznrsypus 0 300 train
+jizpiknqaf 0 300 train
+jiztppgqlc 1 300 train
+jiztyoorkh 1 300 train
+jjagjqcejw 1 300 train
+jjagqcwnhs 1 300 train
+jjamkukusv 0 300 train
+jjatiqwprk 1 300 train
+jjaucqyrvr 1 300 train
+jjayrhvawc 1 301 train
+jjaznboikk 1 300 train
+jjazumstsu 1 300 train
+jjbhtojerm 1 300 train
+jjbjacivnw 1 300 train
+jjbkfwofik 1 301 val
+jjbnzycnjx 1 300 train
+jjbouzhars 1 300 train
+jjbpxzevzl 1 300 train
+jjbsjkipgr 1 300 train
+jjbsvvgusx 1 300 train
+jjbzodbprk 1 99 train
+jjcctencjm 1 300 train
+jjcfllgaje 1 241 train
+jjcgurocqb 1 300 train
+jjcjgwgict 1 300 train
+jjcjyopdij 1 300 train
+jjdpjztgcz 1 300 train
+jjdwfpoarm 1 300 train
+jjdwscmboo 1 300 val
+jjearciskp 1 300 val
+jjeaszmkza 0 300 train
+jjeecyzmzo 1 300 val
+jjegzfkwua 1 300 train
+jjehhjfztg 1 300 train
+jjenwbabmy 1 298 train
+jjeptliazl 1 300 val
+jjewbavpac 1 300 val
+jjezndjfmx 1 297 train
+jjfijcfgsl 1 300 val
+jjfllwjxdy 1 300 train
+jjfpjqyfur 0 300 val
+jjftgqekza 1 300 train
+jjgcpugjwy 0 300 val
+jjgmrisgku 0 300 val
+jjgplzzjbw 0 300 train
+jjgqdqwcmq 1 300 train
+jjgtlwcvcd 1 300 train
+jjguwagxur 1 300 test
+jjhjxpaigu 1 300 train
+jjhkbwwqrc 1 300 train
+jjhllibvha 1 300 train
+jjhpptdzjz 1 300 train
+jjhsftlvgu 1 300 train
+jjhxmoubcn 1 300 val
+jjiffpwjyy 0 300 train
+jjimhynmzu 1 300 train
+jjimqgbjgu 1 300 train
+jjinifopsq 1 300 val
+jjiniiqbdk 1 300 train
+jjioflapll 1 300 train
+jjisxhettl 1 300 train
+jjiyiossrk 1 300 train
+jjizylneqz 1 300 train
+jjjnodvoug 1 300 train
+jjjvcommmt 1 300 train
+jjjwutyyjg 1 300 train
+jjjxdrrspz 1 300 train
+jjjxkwlwsb 1 300 train
+jjkcbglvia 1 300 train
+jjkfvegcnx 0 300 val
+jjkmqbixix 1 300 val
+jjknzmuovx 1 300 val
+jjkpklrqdm 0 300 train
+jjkvkkqwrb 1 300 train
+jjlbxnlccv 1 300 val
+jjldfdsiwn 0 300 train
+jjlmszzaqi 1 300 val
+jjlnktpwqk 1 300 val
+jjlrpcdplq 1 300 val
+jjlsdxbgmu 1 300 train
+jjmamjucww 1 301 train
+jjmawrccwf 1 297 train
+jjmdaqtyco 1 300 val
+jjmkolruut 1 300 train
+jjmlvhvlhf 1 300 train
+jjmmmqumtj 0 300 train
+jjmoksdmdg 0 300 train
+jjmqywydoa 1 300 train
+jjmtderoby 1 300 val
+jjmthqeecu 0 300 val
+jjnbwmrdaq 1 301 train
+jjneiobzca 0 300 train
+jjneuahmex 1 300 train
+jjnjujutyi 1 300 train
+jjnsbnzpzf 1 300 val
+jjnuzyutky 1 292 val
+jjnzvsibrs 1 299 train
+jjoikbsxhw 1 300 train
+jjokcipras 1 298 train
+jjootlipum 1 300 val
+jjotwykhqr 1 301 val
+jjpaedfneo 1 300 val
+jjpfwbfeqp 0 300 val
+jjpjogwxzx 1 300 train
+jjpkqalxlh 1 300 train
+jjpmepegli 1 299 val
+jjppplpwfs 1 298 train
+jjprdmkbak 1 300 train
+jjptkvyxhv 0 301 train
+jjpuafddqd 1 301 train
+jjpvymtfyz 1 300 train
+jjpwoemuiw 1 300 train
+jjpxjuttbz 1 300 train
+jjqadtkapo 1 299 train
+jjqcxownbu 1 241 train
+jjqenuqypg 1 298 train
+jjqfisjkki 1 300 train
+jjqmlkkoss 1 300 train
+jjqnzkpwyw 1 300 val
+jjqwvrjcdw 1 300 train
+jjrerovpht 1 300 train
+jjrglhvdbd 1 300 train
+jjribuiepi 1 298 train
+jjrkvkivfj 1 300 train
+jjrnsyiihl 1 299 val
+jjroxzmmzg 1 300 train
+jjrytxhibf 1 300 val
+jjsabsbbmi 1 300 train
+jjsrxyyrhe 0 300 train
+jjsuqhcmyw 1 300 train
+jjsxqhxjgs 1 300 train
+jjtavehbjc 1 300 train
+jjtdsqzwbt 1 299 val
+jjtgqihnkq 1 300 train
+jjtsvqpani 1 300 val
+jjucpwlsyb 1 300 train
+jjucwgygvo 1 300 train
+jjudidnuwp 1 300 train
+jjufjipkit 0 300 train
+jjuipjbvhv 1 300 train
+jjujflvfcr 1 300 train
+jjunpqfsfy 1 300 train
+jjusjkovfy 1 300 test
+jjvbmupmmw 1 300 train
+jjvghtthcl 1 300 train
+jjvktahwpv 1 299 train
+jjvudnlvge 1 301 train
+jjvvyfomho 1 300 train
+jjvxeeawfq 1 300 val
+jjvydbntsq 1 301 val
+jjwcyfrqzl 1 300 val
+jjwktpgwyl 1 300 train
+jjwmlwajjz 1 300 val
+jjxblhpdox 1 300 train
+jjxcruldox 1 300 train
+jjxdqizecj 1 241 train
+jjxidcxytj 1 300 val
+jjxifawupt 0 301 train
+jjxjswkjbm 1 300 val
+jjxrerphsn 1 241 train
+jjxrkvkmft 1 300 train
+jjxtnswcvv 0 300 train
+jjxtumenxk 0 300 train
+jjxvmeedik 0 300 train
+jjxwsknwdx 0 300 train
+jjxxatdfcx 1 300 train
+jjxyytiqmz 1 300 train
+jjxzidyitl 1 300 test
+jjyaisgtip 1 300 train
+jjyaysmngn 1 297 train
+jjycletzyl 0 300 train
+jjyfvzxwwx 0 300 train
+jjyjsxcgvt 1 300 val
+jjykaarsdc 1 300 train
+jjylebqgmf 1 300 train
+jjyrmbentx 1 301 train
+jjywhxspst 1 301 val
+jjzcgncujw 1 300 train
+jjzecoytux 1 300 val
+jjzhotwzlf 1 300 train
+jjzmoetecd 0 300 train
+jjzpwcociv 0 300 train
+jjzveabagf 0 300 train
+jjzvfvkqau 1 300 train
+jjzvwdlibv 1 300 train
+jjzzbsslun 1 300 train
+jjzzuodenm 0 292 val
+jkadnvoqhk 0 300 train
+jkahmhnpub 1 241 train
+jkaihkrfoc 1 300 train
+jkajqpwiay 1 300 train
+jkaxqpkyus 1 300 train
+jkbgzyirhf 1 300 val
+jkbizdxjfc 1 300 val
+jkbpywovva 1 300 train
+jkbqvpskqd 1 300 train
+jkcechtgho 0 300 train
+jkcjgwysvs 1 300 train
+jkcjtokpwd 1 300 train
+jkcpbcpnft 1 300 train
+jkcpgrzvdc 1 299 val
+jkcrlgetfu 1 300 train
+jkcvdterse 1 300 train
+jkcvwuhrxy 1 300 train
+jkdbnjogks 1 300 val
+jkdbrcakmj 1 300 train
+jkddywriuf 0 300 train
+jkdehoarcj 0 298 train
+jkdgogmlqu 1 300 train
+jkdovnmcyr 1 300 train
+jkdqqtokrj 1 300 train
+jkdxvhjxdg 1 300 train
+jkebjqkdee 0 300 train
+jkekbhvtkr 1 300 val
+jkeophrouw 1 302 train
+jkepeduxea 1 300 train
+jkepraleck 0 300 train
+jkerwpnymv 1 300 train
+jkeseloldg 1 300 train
+jketxnhnmx 1 300 train
+jkeubyegov 0 300 val
+jkewzshsmz 1 300 train
+jkezosrcnt 1 300 train
+jkffazsfos 1 300 train
+jkfiafozee 1 301 train
+jkfmcyyspe 0 300 val
+jkfmldabrv 1 300 train
+jkfoehpdnd 1 300 test
+jkfucthbhs 1 241 train
+jkfukzcjxd 1 300 val
+jkgaspfiql 1 298 train
+jkgbnwzqek 1 300 train
+jkgbucpzki 0 301 train
+jkgevzgjby 1 300 val
+jkgfjawvag 1 300 train
+jkgoacwovv 1 300 train
+jkgoimbcrr 1 300 train
+jkgsimowhk 1 300 train
+jkhauakgrv 1 300 train
+jkhbxhmhtf 1 300 val
+jkhfnbdhfg 1 300 train
+jkhkctamec 1 299 train
+jkhmlbmwdz 1 300 train
+jkhmzttnqg 1 300 train
+jkhndcqgco 1 300 train
+jkhpazkinl 1 300 train
+jkhsuxvoys 0 300 val
+jkhugkoqdz 1 300 train
+jkhukelids 1 300 train
+jkhwzrzqsr 1 299 train
+jkicnpuhvx 0 300 train
+jkiglwobpf 1 300 train
+jkikpvupfb 1 300 train
+jkilwczcdi 1 300 train
+jkinsiyvnh 1 300 train
+jkiplzurbb 1 300 val
+jkirjzqhns 1 300 train
+jkjahwrghe 1 300 train
+jkjdqtzfat 1 300 val
+jkjfuxmreo 1 297 val
+jkjkyilofc 1 300 val
+jkjmdmjbix 1 300 train
+jkjmqhmprd 1 300 train
+jkjubzukst 1 300 train
+jkjvxgxdjy 0 300 train
+jkkdglnjhw 1 300 train
+jkkmutevux 1 300 train
+jkkruvsexa 1 300 train
+jkktmfmaqy 1 300 train
+jkkunmjtak 1 300 train
+jklfudkrxk 1 297 train
+jklgmuitrh 1 300 train
+jklhtwxnqr 1 300 train
+jklovbfvcl 1 300 val
+jklyzyoipl 1 300 train
+jkmadqmnwh 1 300 train
+jkmdbrsqdr 1 301 val
+jkmftqkxht 1 300 train
+jkmhvprjrl 1 300 val
+jkmxxujmwo 1 300 train
+jkmzsyiwdr 1 300 train
+jknlvsdlhi 1 300 val
+jknqixlovb 1 300 val
+jkntlgmvaz 1 300 val
+jknutfonoa 1 241 train
+jknxugrurs 1 300 train
+jkojzwquct 1 300 train
+jkolxnejeh 1 300 train
+jkonwkrhqp 0 300 train
+jkoowdsgbe 1 300 train
+jkorkmwvfk 1 300 train
+jkosxzvyac 1 300 train
+jkotycuxpc 1 300 val
+jkpaoevvmh 1 301 train
+jkpbalqoca 1 302 train
+jkpgjofomw 1 300 val
+jkpquolhfq 1 300 train
+jkqdweauub 1 300 train
+jkqivqkrnc 1 300 test
+jkqnndlvsu 1 297 train
+jkquqsonfp 1 300 train
+jkqvidhxwz 0 300 train
+jkrbsekajk 0 300 train
+jkrdcoeyzx 1 300 val
+jkrdfmmtbz 1 301 val
+jkrenpwvvj 1 300 train
+jkrijhnlco 1 300 train
+jkrnphmznp 1 300 train
+jkrqjgwiof 1 301 val
+jkrqpgxdux 1 300 train
+jksdgjxuws 1 300 val
+jksiosbgqr 1 300 train
+jkskujrxbz 1 237 train
+jksqkdgclz 1 300 train
+jktsnofxgb 1 300 val
+jktvlfcpom 0 300 train
+jkudzrtiho 1 300 train
+jkuiljgllp 1 300 train
+jkunrfifvq 0 300 train
+jkuphupxyg 1 300 val
+jkusgrhdfy 1 300 train
+jkvcevfwio 1 299 val
+jkvdlvfznj 1 300 train
+jkveodwvoi 1 300 val
+jkvhhqmgys 1 300 train
+jkvlkqerux 1 300 train
+jkvquwguiq 1 300 train
+jkvzfbnzzt 0 301 val
+jkwcmcdbmi 1 300 train
+jkwcqbzdjp 1 300 val
+jkwcyjtivh 1 300 train
+jkweqswkmp 1 300 train
+jkwgfikcjw 1 300 val
+jkwhwsfzdz 1 301 train
+jkwpppugfm 0 300 val
+jkxdmesbvb 1 236 train
+jkxfexovpf 1 300 val
+jkxgzzrmnp 1 300 train
+jkxjvuioek 1 300 test
+jkxmrbzwau 1 300 val
+jkxowfeuei 1 300 train
+jkxqgxayto 1 300 train
+jkxrjgnksq 0 300 val
+jkxrpeqqdt 1 300 train
+jkxwrvgzpr 1 300 train
+jkxxwfycsj 0 300 val
+jkxyqsppke 1 300 train
+jkxytjgrlj 0 300 train
+jkyarpmxxv 1 300 train
+jkyatwnjxk 1 299 train
+jkydygqjuv 1 300 train
+jkyhbpicmv 1 300 val
+jkyizkpqxe 1 300 train
+jkynbulcid 1 298 train
+jkyoiziybn 1 300 val
+jkytqzmemu 1 300 train
+jkywubufbk 1 300 train
+jkyzronjcg 1 300 train
+jkzbfceoyo 1 298 train
+jkzdcscyxn 1 300 train
+jkzesnfmzc 1 300 train
+jkzfwaqzan 1 300 train
+jkzguoxgrp 1 300 train
+jkzhvvuylq 1 300 train
+jkzjtazxdp 1 300 train
+jkzqqhkytp 1 300 train
+jkzqutzket 1 300 train
+jkzwhlbftx 1 300 train
+jlajrofwyb 1 300 train
+jlakbruuxj 1 300 train
+jlasazooyj 1 300 train
+jlasrdmshz 1 300 train
+jlawarjbur 1 301 train
+jlaxroimtj 1 300 train
+jlaybxewgv 1 300 train
+jlbbptnfea 0 300 val
+jlbcbzbacz 0 300 train
+jlbntfvurf 0 300 train
+jlbphssexk 1 300 val
+jlbpjgbioa 1 300 train
+jlbtiajtlt 1 299 train
+jlbtukzmyh 1 300 train
+jlbtvqmfux 0 300 train
+jlcfapsbqz 1 300 train
+jlciqrwohp 1 301 train
+jlckrvhipl 1 300 train
+jldbmxqgft 1 300 train
+jlddvpzbqy 1 300 train
+jldkmbxccu 0 300 train
+jldmrwcmbn 1 300 train
+jldtskgusg 1 300 train
+jldxdiewbx 1 300 train
+jldyhvttqs 1 298 train
+jleecnqvlk 1 300 val
+jlejcehosw 1 300 train
+jlekihrhsg 1 300 train
+jlewawbqfo 1 300 train
+jlewhjxkiy 1 300 train
+jlezgmooih 1 300 train
+jlfadvmypa 1 300 val
+jlfbbdaykv 1 300 train
+jlfgxphhzt 1 300 val
+jlfipzbuxq 1 300 train
+jlfltjblid 1 296 val
+jlflzghftl 0 300 val
+jlfmzjkqdu 1 300 val
+jlfoxayiao 1 301 train
+jlfrfbcxyr 1 300 val
+jlfxdrisls 1 297 train
+jlfxenznos 1 300 val
+jlfxmldeeu 1 300 train
+jlgclwjdfy 1 300 val
+jlgdbwkstg 1 300 train
+jlgkzspzlp 1 300 train
+jlglwdojut 1 300 train
+jlguomaojq 1 300 train
+jlhahahiqr 1 241 train
+jlhjzrjfue 1 300 train
+jlhmcnajch 1 300 train
+jlhoqozcxb 0 300 train
+jlhpdrzxci 1 298 val
+jlhsqzadgp 1 300 train
+jlhuzeuopl 1 300 train
+jliekxdrtd 1 300 train
+jliiylbwpj 1 300 train
+jlijsupauf 1 300 train
+jlixlzgucm 1 300 train
+jliyplgfng 1 300 train
+jlizymitsl 1 300 train
+jljcnywhao 1 300 train
+jljgjmdovb 0 300 train
+jljhvmfoog 1 300 train
+jljpdojupu 0 300 train
+jljtzoplew 1 300 train
+jljwzilvze 1 300 val
+jljzdmmudi 1 300 train
+jlkaeiwhnl 1 300 train
+jlkfvkwmsf 1 300 train
+jlkqtifdru 1 300 train
+jlkxbmyodc 1 300 train
+jlkzypbjmv 1 300 train
+jllgksrwas 1 300 train
+jllkmkgzzo 1 300 train
+jlluezfnyr 1 300 test
+jlluoqdjqg 1 298 train
+jllvvffsek 0 300 val
+jlmhgkjyix 1 301 train
+jlmlxnalsb 1 300 train
+jlmmslbing 1 300 train
+jlmqjvtale 1 300 train
+jlmslmodjv 1 297 train
+jlmxgiwjrj 1 301 train
+jlmyzhhbdl 1 300 train
+jlnatrmsqw 0 300 train
+jlnauymcwu 1 300 val
+jlnkflvelk 1 300 train
+jlnlvwfows 1 300 val
+jlnsjehljf 1 302 train
+jlnwlnqrxt 1 300 train
+jlnwpxksdp 0 300 train
+jlnxftxesx 1 300 val
+jloacgyeqy 1 300 train
+jloanvopeo 1 300 test
+jloctarpah 0 300 train
+jlomryzlcu 0 300 train
+jlopwajaju 0 300 train
+jloraupuel 1 300 train
+jlormbsgiu 1 300 train
+jlouwovpic 1 300 train
+jlpacklord 1 241 train
+jlpdigyqvw 1 300 train
+jlpkekykyz 1 300 val
+jlplxmbawp 1 300 val
+jlpowwswuu 1 300 val
+jlpqzjladg 1 300 train
+jlpsvagyxu 1 300 train
+jlptkfupjy 1 300 train
+jlpyxikuqa 1 300 train
+jlpzyrhwik 0 300 train
+jlqarzddeg 1 300 train
+jlqdqzvyth 1 300 train
+jlqfjykhee 1 136 train
+jlqfryhwpj 0 300 train
+jlqhlhxwaz 1 300 train
+jlqijydxwb 1 300 train
+jlqknicbuv 1 241 train
+jlqtxuyefy 0 300 train
+jlqubodbnt 1 300 train
+jlqubumdwq 1 300 train
+jlqudxkdvc 1 300 train
+jlqykrjsdi 1 300 val
+jlqzoxqvgh 1 300 train
+jlrakhfgjh 0 300 train
+jlrbtqwhug 1 300 train
+jlrfsmrkrq 1 300 train
+jlricrfmss 0 300 train
+jlritrohgw 1 300 train
+jlriwaayvn 0 300 train
+jlrolyrbyf 1 298 train
+jlrqwehqzh 1 300 train
+jlrrmdznai 1 300 train
+jlrvlsdgll 1 300 train
+jlrwmehbwx 1 300 train
+jlrztjivsw 1 300 train
+jlsgkkeryu 0 300 train
+jlskmeevxr 1 300 train
+jlsmicekzq 1 300 train
+jlsveomjrx 1 300 val
+jlsxptpzhx 1 302 train
+jlsylbojlt 0 300 train
+jlszsmbpze 0 301 train
+jltbsrpksq 1 300 train
+jlthrnkzof 1 300 train
+jltiodskcw 1 300 train
+jltlsrrwxs 1 300 train
+jltluebzse 1 300 train
+jltrqfzlnr 1 300 train
+jltudfiwwr 1 300 train
+jltwuigjnp 1 300 train
+jlubhwwhht 1 300 train
+jlugkqeqbl 1 302 train
+jlukgxaxjk 1 241 train
+jlunuxqucj 1 300 train
+jlussdnmfm 1 300 train
+jluxdyftpa 1 300 train
+jlvdajgmbr 0 300 train
+jlvhbotqzi 0 300 train
+jlviguadhz 1 300 val
+jlvmdehdvf 1 300 train
+jlvnsjgyhz 1 300 test
+jlvqrgqhpw 0 300 val
+jlvviiiadl 1 300 train
+jlvxmssvwi 1 300 train
+jlvyaxhixs 1 300 train
+jlwazimcui 0 300 train
+jlwephekug 1 300 val
+jlwfjenaim 1 299 train
+jlwihfzyxa 1 300 train
+jlwrjxfwdi 1 300 train
+jlwshdrqfu 1 300 train
+jlwuuthbpc 1 300 train
+jlwvlbetbj 1 300 train
+jlxglqxpls 1 300 train
+jlxhfphwpw 1 300 train
+jlxiyagdjo 1 300 train
+jlxjuksqeh 1 300 train
+jlxmzhtkwm 0 300 train
+jlxnfqocew 1 300 train
+jlxnzxtopm 0 301 train
+jlxpoalwya 1 300 train
+jlxutyzemo 0 300 train
+jlxwpqksnr 1 300 test
+jlxyabssbi 1 300 val
+jlxyqwlemt 0 300 train
+jlxytgcoeg 1 300 train
+jlxzndudaj 1 300 train
+jlygbysuom 1 300 val
+jlylaxhoor 1 300 train
+jlytuhqydw 1 300 val
+jlyvkuefwd 0 300 train
+jlyvtlcajx 1 300 train
+jlyzvlehhm 1 300 train
+jlzbyxqgiw 1 300 train
+jlzckbmrbw 0 300 train
+jlzelzmyin 0 300 val
+jlzlqfqitl 1 300 train
+jlzsvkfsdl 1 300 train
+jlzvrbeeyl 1 300 train
+jlzxvuxojs 0 300 train
+jmabzncswd 1 300 val
+jmajxvlurd 0 300 val
+jmaogvrnrf 1 301 train
+jmaspvlwfl 1 300 train
+jmaszdwnkz 1 300 val
+jmaylyisgz 0 300 train
+jmazwjebsu 1 300 train
+jmbhdpayug 1 300 train
+jmbmszhvdb 1 300 train
+jmbyprxmfn 0 300 val
+jmcqwwcuxp 1 300 val
+jmcryhnksj 1 300 test
+jmcskbrwae 1 300 train
+jmctsixbhk 1 300 train
+jmculodxsw 0 298 val
+jmcuroppjz 0 300 val
+jmddxhehsb 1 300 train
+jmdjmbkcyx 1 300 train
+jmdnsflxij 1 300 train
+jmdylhjyzf 0 300 train
+jmdztfcyhm 1 300 train
+jmeuqgyxhl 1 300 train
+jmeytxbzvf 1 300 train
+jmfetisosr 1 300 train
+jmfgkwgyym 1 300 train
+jmfiehgkcn 1 300 val
+jmfjkqyyej 1 300 train
+jmfrlvnlbm 1 300 val
+jmfwryxneg 1 136 train
+jmghqvqgxv 1 300 val
+jmgozrnbir 1 300 val
+jmgqflginv 1 300 train
+jmguakcwsy 1 300 train
+jmhqbsgzrg 1 300 test
+jmhrhlyixg 1 300 train
+jmhttsbgcs 1 298 train
+jmhyfazbda 1 300 train
+jmiemyzsnl 1 300 train
+jmigkewchc 1 300 train
+jmiguhbkkm 0 300 train
+jmimlbvoae 1 300 val
+jmizwhvejg 1 300 train
+jmjbbucqgf 1 300 train
+jmjcqrggsw 1 300 train
+jmjgnikdsu 1 300 train
+jmjqmpwtof 1 300 train
+jmjuobsfid 1 300 val
+jmkjrabiak 1 300 test
+jmkkbkvbjo 0 300 train
+jmkkzjwnst 1 299 test
+jmkmzlvpnw 1 300 train
+jmkqtjuuqu 1 300 test
+jmkvjigwzf 1 300 train
+jmkwbchkqk 1 300 train
+jmlbdvbvih 1 300 train
+jmlbltpnwg 1 300 val
+jmldzfyqus 1 300 val
+jmlehcqpgt 1 241 train
+jmlidzqpao 1 300 train
+jmluyrxtfn 1 300 train
+jmmecntohl 1 300 train
+jmmhppwkfg 0 300 val
+jmmjuligfj 1 299 train
+jmmrrmjjhc 0 300 train
+jmnfoppajo 1 300 val
+jmnhpetvgd 1 300 train
+jmnqqbwkso 0 300 train
+jmnrofiulx 1 300 val
+jmnshhykla 1 298 train
+jmnvmkxwga 1 300 train
+jmnxijabzi 0 298 val
+jmnyavrtau 0 300 train
+jmodyiocdx 0 300 train
+jmoeaquinn 1 300 train
+jmoltzkhax 1 300 test
+jmomruqjnf 1 298 train
+jmoqelikic 1 300 train
+jmoxeyiywo 1 300 train
+jmpndzdwxf 1 300 train
+jmpnxczwnl 1 300 train
+jmporfhink 1 300 train
+jmpqzlmmpr 1 300 train
+jmpttwtdbs 1 300 val
+jmpumaauyh 1 300 val
+jmpwdyskda 1 300 val
+jmpwlstems 1 300 train
+jmpybygqon 1 300 train
+jmqfvvidtt 1 300 val
+jmqhdonewc 1 300 val
+jmqjcocxnp 0 300 train
+jmqjzrdenu 1 241 train
+jmqmljznhv 0 300 val
+jmqpsimwcd 1 300 train
+jmqsajveob 1 301 train
+jmqsfzvcou 1 300 train
+jmqstgejrs 1 300 train
+jmqtstyuvv 1 300 train
+jmqzaqrguk 1 300 train
+jmqzarhtfb 1 300 train
+jmraknlykt 0 146 train
+jmrbvhwiih 1 300 val
+jmrckepvbo 1 300 train
+jmrdtweydv 1 300 train
+jmrfbhqnqk 0 300 train
+jmrirhlfot 1 298 train
+jmrvbsnsiv 1 300 val
+jmrvmcqarx 1 300 train
+jmscasqqke 1 300 val
+jmscipgnyr 1 300 train
+jmshwmfhqi 1 300 train
+jmsitrdbom 1 241 train
+jmsmwzstfx 1 300 val
+jmszcikkjx 1 301 val
+jmszrburbe 1 300 train
+jmtbneszao 1 298 train
+jmtcuherzv 0 300 train
+jmtenczcpl 1 241 train
+jmteqvfilc 1 300 train
+jmtexdptfy 1 300 train
+jmtftbmazs 1 297 val
+jmtspvpecy 1 299 test
+jmubocmowh 1 300 train
+jmufrwawsm 0 300 train
+jmuogdrpib 1 300 train
+jmuwcxvbur 0 300 train
+jmuwdtisfd 1 301 val
+jmuweancoz 1 300 val
+jmvdcpojlg 1 300 val
+jmvmumowjq 1 300 train
+jmvmztomdw 0 300 val
+jmvngkhazd 1 300 val
+jmvnvichuk 1 249 train
+jmvnxexych 1 300 train
+jmvtoywwic 1 300 train
+jmwbojmijo 1 301 train
+jmwrfurpcp 1 300 test
+jmwywdfwnz 1 300 train
+jmxbizzywt 0 300 train
+jmxdbxjqzu 0 300 train
+jmxkiuxzvg 1 300 train
+jmxrcvakrr 0 300 train
+jmxwyhcabc 0 297 train
+jmxyqnvaew 1 241 train
+jmykcrqrnf 1 300 train
+jmyusjdbgo 1 301 train
+jmywsenyzt 1 300 val
+jmzkawfzqt 0 300 train
+jmzqvioqnp 1 297 train
+jmzuwsricv 1 300 train
+jmzxyyvxzv 1 300 train
+jmzypzvqsv 1 300 val
+jnaftxxutz 1 300 train
+jnafwjebjb 1 300 train
+jnairglkux 0 300 train
+jnalvclkjn 1 300 train
+jnaocvkjhc 0 300 val
+jnaoxtdzzs 1 300 train
+jnariwnatr 1 300 train
+jnassgopcp 1 300 train
+jnattqmjpa 1 300 val
+jnawytlxjn 1 300 train
+jnbbbxihbh 1 300 val
+jnbljsloup 1 301 train
+jnbmeyznts 1 300 train
+jnbsbkrauq 1 300 train
+jnbvbbened 0 300 train
+jnbvdxghaa 1 300 train
+jncdlfnhnf 1 297 val
+jncghwmmpf 0 241 train
+jncnyigscz 0 300 train
+jncnzarlsm 1 299 test
+jncrjhqvhx 1 300 val
+jnctoqoufb 1 300 train
+jncuaosxat 1 300 val
+jncvyfymit 1 300 train
+jndbzlbubz 1 300 train
+jnddcpkepm 0 300 train
+jndflyjywp 1 300 train
+jndhbnidca 0 300 train
+jndkdjrifd 1 300 train
+jndobzgjpi 1 300 train
+jndpsjskep 1 300 val
+jndupaumax 1 300 train
+jnechttqqc 0 300 val
+jneckvehyk 1 300 train
+jnekajvlcj 1 300 val
+jnelvrznwv 1 298 train
+jnerlwkgav 1 300 val
+jnfaxmlowe 1 300 val
+jnfbpwwxsr 1 300 val
+jnfnwuvutq 1 300 val
+jnfsppjcmo 1 300 train
+jnftouyunl 1 301 train
+jnfuqvhdii 0 300 val
+jnfzspjgzo 1 300 train
+jngdqydaal 0 300 train
+jngzmnnulf 1 300 train
+jnhagsvcib 1 299 train
+jnhhbquwkt 1 241 train
+jnhoochgtb 1 300 val
+jniamiezfj 1 300 train
+jnianhnlvr 0 300 train
+jnifcpyxho 1 300 train
+jninyixxqv 1 300 train
+jniytngcmy 0 300 train
+jnjaakvezg 1 300 val
+jnjbrknefd 1 298 train
+jnjrqmwgbu 1 300 train
+jnjszosdox 1 299 train
+jnjvuwglre 1 239 val
+jnjzwcogsw 1 300 train
+jnkdtmwlje 0 300 train
+jnkhbwptut 1 300 train
+jnkhjctvpq 1 249 train
+jnkiecpeve 1 300 val
+jnklpeolur 1 300 train
+jnkowcbdaf 1 301 train
+jnkrugdqzl 1 300 val
+jnlevanrpd 1 301 train
+jnlfhlzhub 1 300 train
+jnlfystmzs 1 300 train
+jnlhnmmpwk 0 300 val
+jnlibuuyfd 1 296 val
+jnllrvdkzt 1 300 val
+jnlmwmgfok 1 300 val
+jnlsblkssg 1 300 train
+jnltojrecm 1 300 val
+jnmglqfqah 1 300 train
+jnmpqwqtkc 1 300 train
+jnmvgqkrli 1 300 train
+jnmygfglwb 1 300 train
+jnmyqccicf 1 297 val
+jnnfkmuxie 1 300 train
+jnnjfilmrg 1 300 train
+jnnlofcqty 1 300 train
+jnnotoakjb 0 300 val
+jnnsgzdxtn 1 300 val
+jnnvmukoff 1 300 val
+jnnwcesqop 1 300 train
+jnocmrgime 1 300 train
+jnodakrcxi 1 300 val
+jnoeawijqg 1 300 train
+jnohdbrmnw 1 300 train
+jnohdhinec 0 300 train
+jnohxdgsjl 0 300 train
+jnopzrsezp 1 300 train
+jnotdgzpgj 0 300 train
+jnoyqpoxnn 0 300 train
+jnpffdcskg 1 300 train
+jnpfknbyus 1 300 val
+jnphuclors 1 300 train
+jnpjekjcos 1 300 val
+jnppybytup 0 300 train
+jnpwfoiddz 1 300 train
+jnpxqoeqmw 1 300 train
+jnqakjilnm 1 300 train
+jnqaqroaar 1 300 train
+jnqbcdbylz 1 300 train
+jnqbxiqhfw 1 300 train
+jnqepyndcm 1 300 train
+jnqgbeifos 1 300 train
+jnqjchroea 1 300 train
+jnqkzajabc 0 300 train
+jnqmcyshrf 1 300 train
+jnqovqcklb 1 300 train
+jnqvvbpcjn 1 300 train
+jnrbjcsxlz 0 300 train
+jnrgqzlvvr 1 300 train
+jnrgyehakj 0 300 train
+jnrkscmcgq 1 300 train
+jnrkxzsxms 1 300 train
+jnrpnonrqz 1 300 val
+jnrqzhzoml 1 300 train
+jnrttvcdxc 1 300 val
+jnrtzfzpqa 1 300 train
+jnruqyivyf 1 300 train
+jnrxewzqfp 1 300 train
+jnsjlslwuk 0 300 train
+jnsoobuvhp 1 298 train
+jnspbsyajz 1 300 val
+jnszxfdvdu 1 300 train
+jntavfzozt 0 300 train
+jntdjktqrv 1 300 train
+jntiomfhcr 1 298 train
+jntlukilia 0 300 train
+jntpviiziw 1 300 train
+jntsnqioce 1 300 train
+jnuijmxmig 1 300 val
+jnupqyqvhh 1 300 val
+jnuptiqqbe 1 300 train
+jnurtdpytl 1 300 val
+jnuttlzubz 1 241 train
+jnuvtvgjsc 1 298 train
+jnuwxldmly 1 300 train
+jnuyiheucs 1 240 train
+jnuyjeddta 1 301 val
+jnuymijlnb 0 300 train
+jnuzssvtrw 1 300 train
+jnvxvwnocs 0 300 train
+jnvycbkaph 0 301 train
+jnwacqpmgg 1 300 val
+jnwgtwdhxe 1 300 train
+jnwkxntkrk 1 300 val
+jnwtewydtl 0 300 train
+jnxhbqhzyl 1 300 val
+jnxjbucuwr 1 300 train
+jnxlymnqfm 1 300 train
+jnxmqudjbd 1 298 train
+jnxninjsir 0 300 train
+jnxqztdgyp 1 300 train
+jnxuezglcb 1 299 val
+jnxyfopyfq 0 300 val
+jnxyuvovtp 1 300 train
+jnxzkhdshg 1 301 train
+jnxzkzidtd 1 300 train
+jnyadkoijo 1 300 val
+jnyjqfawai 1 300 train
+jnylusceha 0 300 train
+jnyrjjagxb 1 300 train
+jnywudxcur 1 300 val
+jnyyaaclpu 1 241 train
+jnyyisemqq 1 300 train
+jnyyurkrbj 1 240 val
+jnyzknibwm 1 300 val
+jnzcbujlfw 0 300 train
+jnzcnqilgl 1 300 train
+jnzhqeyysi 1 300 train
+jnzhwkdkfi 1 300 train
+jnzkrknexy 1 300 val
+jnzliazdkx 1 298 val
+jnzrylcsiy 1 300 train
+jnzthvpxhs 1 300 val
+jnztiadssn 1 300 train
+jnzwbsushx 1 300 train
+joadtqvfwc 0 300 train
+joaohtlqqt 1 241 train
+joarxdehel 1 300 train
+joavzrzgqo 1 300 val
+jobdmtmujc 1 300 val
+jobfupqyjp 1 240 train
+jobjurhuvr 1 300 train
+jobvtomjyt 1 301 train
+jobymkxheb 1 299 train
+joccfilapv 1 300 train
+jocctgmazm 1 240 train
+jocjbgbfqo 1 299 test
+jocksapjca 1 300 train
+jocmseacvk 1 300 val
+jodgnayrqr 1 296 train
+jodmpxamjm 0 300 train
+jodpxdnajh 1 300 train
+jodrgvovds 1 300 train
+joduxqwjds 0 300 val
+joeagxxbbn 0 300 train
+joeawzrtzn 1 300 train
+joecbkgtsi 0 300 val
+joecxmxjyn 1 300 train
+joefnqfnzy 0 300 train
+joefoenszf 0 300 train
+joeifeskbs 0 300 train
+joeiukomrp 0 300 train
+joeouidgjq 1 300 val
+joepunxrzr 1 300 train
+joerzhqnzc 1 300 train
+joevjtjgzn 1 300 train
+joewkbdkib 1 300 train
+joewtskcve 1 300 train
+joezmuxfzt 1 300 train
+jofbydmmpp 0 300 train
+jofdgymoeb 1 301 train
+jofkmrngjg 1 300 train
+joflcavmns 1 297 train
+jofrmhzjyg 1 300 train
+jofujclkfb 1 300 val
+jofvevjwim 1 300 train
+jofvycopyj 1 300 val
+jofyekzfzd 1 300 train
+joghmjwscd 1 300 val
+joghrrlhve 0 300 val
+joghzaznjg 0 300 train
+jogihuryca 1 300 train
+jogiqlbcrp 1 300 train
+jogkhwcrmg 1 300 train
+jogzeegepu 1 300 train
+johpgxjpdm 0 300 train
+johuaietaz 0 300 train
+johuwrcurd 1 300 train
+joiansblwv 1 300 train
+joitywalua 1 300 val
+joivxhqnxo 1 300 val
+joiwhobtqq 1 300 val
+joiwtshxir 1 300 train
+joixwmfizg 1 300 train
+jojbvmgyeh 1 300 train
+jojsscizlb 1 300 val
+jojvfctndk 1 99 train
+jokealrign 1 300 train
+jokemukffb 0 300 val
+jokhldryiw 1 300 train
+jokhonzxiw 1 300 train
+jokljefhzw 1 300 val
+jokpcshyuc 0 300 val
+jokpgieozn 1 300 train
+jokskvrmmm 1 300 train
+jokumtsegd 1 300 train
+jokvmkpegb 1 300 train
+jokvzuiivx 1 300 train
+jokxnelnfn 1 300 train
+jolegllgnk 1 300 train
+jolmlanwhp 1 300 train
+jolrloqajj 1 300 train
+jolrxzvwji 1 300 val
+jolrzhwbbv 1 300 val
+jolvkbhszw 1 300 val
+jomfjkvwnx 0 300 train
+jomnognvrf 1 300 train
+jomvcqqars 0 300 train
+jomwcbwhjk 1 300 train
+jonioihqji 0 300 train
+jonjhjpwzw 1 300 train
+jonnrxawsy 1 300 val
+jonqjioucp 1 300 train
+jonrxepdxk 1 300 train
+jonthtgogn 1 300 train
+jonwcdhxwk 1 301 val
+jonyhxktri 1 300 train
+joomwgjfao 1 300 train
+joooyxhqxq 1 300 train
+joouypmnuc 1 300 train
+jooxuprezs 1 300 train
+jopktpwppc 1 300 train
+jopmojtysl 1 300 train
+jopqwzkdtc 1 298 train
+jopzicdocl 1 300 train
+joqcupcigh 1 300 train
+joqdmptvzn 1 300 train
+joqmewcaqv 0 300 val
+joqovzhazn 1 300 train
+jorcpebhea 1 300 val
+jordseoase 1 300 val
+joresvocdj 1 300 train
+joretjymbs 1 300 train
+jorezqxvud 1 300 train
+jorfifqxhq 1 300 test
+jorfxyiizk 0 300 train
+jorfzfcqbl 1 301 train
+jorghlmkzr 1 300 train
+jorkcmumxh 1 300 train
+jorqbynumf 1 300 val
+jorvatqgzc 1 300 train
+jorwbhypws 1 300 train
+jorxecnkfh 1 301 val
+jorxoesoqa 1 300 train
+jorytevubi 1 301 train
+josazobdcb 1 300 train
+josdikixtm 1 301 train
+joshukhbpp 1 300 train
+josvdlktes 1 300 train
+jotfdmronq 1 300 train
+jotgmumnig 1 298 train
+jotosdekah 0 300 train
+jotpkcabub 1 300 train
+jotrtxqekz 1 300 train
+jotuktkehu 1 300 train
+jotvywsnym 1 300 train
+jotywkyuvo 1 300 train
+joulcxhyjv 1 300 val
+joulmzeqvy 1 300 train
+joumiubwat 1 301 train
+jouqqaafig 1 300 train
+jouuwvnaig 1 298 train
+jouzjsxkns 1 300 train
+jovaaaryaf 1 301 train
+jovauydjvz 1 300 val
+jovcwgatlt 0 300 train
+jovfjkwibx 1 300 train
+jovlorawmz 1 269 train
+jovlwtkpyn 1 300 train
+jovohczybs 1 300 train
+jovpcvvlvw 1 300 train
+jovqqmdngq 1 301 train
+jovqtearzg 1 300 val
+jovrnujurf 1 300 train
+jovrzaqluh 0 300 train
+jovwjoypwf 1 300 val
+jowcsetjnr 0 300 train
+jowjancoht 1 300 train
+jowwhogqzr 0 300 train
+jowxvukjyo 1 300 test
+jowyxdfykv 1 300 train
+jowyxevmgi 1 302 train
+joxayzkkny 1 300 train
+joxdqiidul 1 300 train
+joxggjiwoj 1 297 train
+joxhszkkjj 1 300 train
+joxiekwyhw 0 241 train
+joxrifzbzk 1 300 val
+joxrxwqzec 1 299 test
+joyqdiarmf 1 297 val
+joywacizgw 0 300 train
+jozbyjakln 1 300 train
+jozdpkfbxt 1 300 train
+jozfaxodnx 0 300 train
+jozgrowdss 1 300 val
+jozivrywzt 1 300 train
+jozlbultic 1 300 train
+jozlysmacz 1 299 val
+jozmldrwgz 1 301 train
+jozqagajbm 1 300 val
+jozrxxdyia 1 300 train
+jozyjdehxi 1 301 val
+jpaaavcygy 0 300 train
+jpafxndgfr 1 300 train
+jpagxhejyn 1 300 train
+jpaiyivxzh 1 296 val
+jpaohjsxbm 1 299 val
+jpatduagju 1 300 train
+jpayfytkhk 1 300 train
+jpazwswbjj 0 300 train
+jpbiidmceu 1 241 train
+jpbodrqgec 1 300 train
+jpbrwtkkxk 1 300 train
+jpbsnyitmv 1 300 train
+jpbwbkobnp 1 300 train
+jpccbvwvtm 1 300 train
+jpcumydkej 1 300 train
+jpczzidqqk 1 300 val
+jpdeqadibf 1 300 train
+jpdfiwuxil 1 300 train
+jpdgijasir 1 300 train
+jpdmejzwuv 1 300 train
+jpdramsluc 1 300 train
+jpdyndogbm 1 300 train
+jpedssnjbi 1 300 train
+jpehvirzib 1 300 train
+jpenumshnn 1 300 val
+jpfaiudvgd 1 300 val
+jpfbmiwzhx 1 301 val
+jpffaybgks 1 298 val
+jpflxfzvgo 1 300 val
+jpfrsdaebg 1 300 train
+jpfvcuymbs 1 300 train
+jpfvktyhki 1 300 train
+jpfwpaygze 1 300 val
+jpfycrnhpt 1 300 train
+jpfzokwegi 1 300 val
+jpgcajdzti 1 300 val
+jpgejzqzxc 1 300 train
+jpgfkwofyy 1 300 train
+jpggwgjgtz 1 300 val
+jpghekbgdy 0 300 val
+jpghmrxfvu 1 300 train
+jpgkbrytxq 1 300 train
+jpgxqlwxgj 1 300 val
+jpgxvefxgz 1 300 train
+jphdtidaxt 1 300 train
+jpheyemqik 0 300 train
+jphjxklkju 1 300 train
+jphmkhpoeb 1 300 test
+jphmsrnsao 1 300 train
+jphnztcebg 1 300 train
+jphofajnku 1 300 val
+jphpdrgnqz 1 300 val
+jphpxiiqfd 1 300 train
+jphugrtghy 1 300 train
+jphvpypiwr 1 300 train
+jphwfngeux 0 300 train
+jphyzgenfe 1 300 train
+jpiejubkdq 1 300 val
+jpihwuiifn 1 300 train
+jpiougaimx 1 300 val
+jpisfbtjcc 1 300 train
+jpjehzhiin 1 300 train
+jpjidbpxhf 0 300 train
+jpjmnzilmz 1 300 val
+jpjqgocyka 0 301 train
+jpjyidxamh 1 300 train
+jpjyldcxnl 0 300 val
+jpketfftcq 1 300 val
+jpkeysifbw 1 300 train
+jpkmpxrpto 1 301 train
+jpkoxyoqos 1 300 val
+jpksczecfa 0 300 train
+jpkzbwgjtd 0 300 train
+jplaesabpj 0 300 train
+jplaghquiq 1 300 train
+jplbbczwuy 1 300 train
+jplepofmsa 1 300 train
+jpljwdfhof 1 300 train
+jplmbopjnv 1 300 train
+jplqtoziaz 1 300 train
+jplutjjkru 1 300 train
+jpmbnyxyav 1 301 train
+jpmfdkkahk 1 302 train
+jpmqvhzmku 1 300 train
+jpmsbstxyu 1 299 train
+jpmwcrtvuw 1 300 val
+jpnbjuksdk 1 300 train
+jpndpzugdy 0 300 train
+jpnkvgflma 1 300 train
+jpnlrqjucb 1 300 val
+jpnothtwkv 0 300 train
+jpnpccqamf 1 300 val
+jpnvbfcekk 1 300 train
+jpnvuqkdvw 1 301 train
+jpocpmgvmv 1 300 train
+jpocyckzny 1 299 val
+jpoeypwvcn 1 300 train
+jpokudqdeh 1 300 train
+jpoumqyecu 1 300 train
+jpowjlrgcu 1 300 val
+jppersggch 1 300 train
+jppfrqoztr 1 300 train
+jppjmazcbc 0 300 val
+jppjmqqfeb 1 300 train
+jppkkudheq 1 300 train
+jppstvntfb 1 299 val
+jppuqzlevo 1 300 train
+jppzzcldui 1 300 test
+jpqjumbvnd 1 300 train
+jpqkitujil 1 300 train
+jpqqlzshti 0 300 train
+jpqtchiwuz 1 300 train
+jpqtnujtvl 0 300 val
+jpquwcujcd 0 300 train
+jpqzxbmrbc 0 300 train
+jprhvuildq 1 300 train
+jprsmiybem 0 300 train
+jprtolusrq 1 300 train
+jprvmckshg 0 300 val
+jprwurdarq 1 301 train
+jprzyhqvis 1 300 val
+jpsjxxvrsq 1 300 train
+jpsktrbyxi 1 300 train
+jpsmggkazz 1 300 train
+jpsomjqcpw 1 301 train
+jpsqzmhcnw 1 300 train
+jptmcbyjop 0 300 train
+jptnaxsxuq 1 301 train
+jptqtosioi 1 300 train
+jptujxaoxs 0 300 val
+jptxjzbrva 1 300 val
+jptxrikuxw 1 300 train
+jptxsmuwid 1 300 train
+jptzoxorxm 1 300 train
+jpuaeekbgd 0 300 train
+jpubhlickt 1 300 train
+jpucqnqusu 1 300 train
+jpuiehmocj 1 300 train
+jpulobvxeo 1 300 train
+jpumncqgcd 1 300 train
+jpuqnwtjvn 1 301 train
+jpuuoorxff 1 301 train
+jpuzlsmpqx 1 240 train
+jpvjjpesyi 1 300 train
+jpvkoxrueh 0 299 val
+jpvleeoqex 1 300 train
+jpvmtmecnx 1 302 train
+jpvnwlrjde 0 300 train
+jpvutogayr 1 300 train
+jpvzilkqvz 1 300 val
+jpwdmjuuev 0 300 train
+jpwekhucij 1 300 train
+jpwhbstmcd 1 300 val
+jpwhjfnbao 1 302 train
+jpwkwtlsby 1 300 train
+jpwlevtbas 1 300 val
+jpwykgqklz 0 300 train
+jpxbkxyrss 0 300 train
+jpxbpzuzjr 1 300 train
+jpxcjjccwt 1 300 train
+jpxeyxjego 0 300 val
+jpxgifdzyb 1 300 train
+jpxgrnctcc 0 300 train
+jpxjpvpypl 1 300 train
+jpxkshkspx 1 300 train
+jpxljdwkgb 1 300 train
+jpxmbjtlsq 0 300 train
+jpxmlyueru 1 300 train
+jpxprefynp 1 297 train
+jpxrvemllw 0 300 train
+jpxwbkodtu 1 300 train
+jpycfzroue 1 300 train
+jpyovsnfga 1 300 val
+jpyppltqju 1 300 train
+jpyrtewkev 1 301 val
+jpyvtzfzmu 1 300 train
+jpyxjcndwd 1 300 val
+jpyzkctoqa 1 300 train
+jpzepsaejm 1 300 val
+jpzgloptum 1 300 train
+jpzihbfwif 1 299 val
+jpzkhpexle 1 300 train
+jpzmwcnutj 1 300 train
+jpzscqcjvz 1 301 train
+jqacsyczuc 1 300 train
+jqahakmukd 1 300 train
+jqajhrcgwo 1 301 train
+jqaqbzewsu 1 143 train
+jqarsowuiq 1 300 val
+jqasusdlor 0 300 train
+jqasvzhzsx 0 300 train
+jqaylxoyjy 1 300 train
+jqbljzbear 1 300 train
+jqbueogosr 0 300 train
+jqbvoejupl 1 300 val
+jqbynrrpsx 0 300 train
+jqcfzqfmuo 1 300 train
+jqcgckphhm 1 300 train
+jqcjoeyzob 1 300 train
+jqcmfgxaeb 1 300 train
+jqcorwhzvt 0 300 train
+jqcpikryji 1 300 train
+jqcpzouxvk 1 300 train
+jqcqlmyrwk 1 300 val
+jqcqvzqcci 1 300 train
+jqcxwxeyng 0 300 train
+jqdieyzjvv 1 300 train
+jqdmjirujb 1 300 train
+jqduafrenc 1 300 train
+jqdvcosowb 1 300 train
+jqdxklmzfb 1 300 train
+jqedfvszwq 1 300 train
+jqeelxclio 1 300 train
+jqefbxpkvh 1 300 val
+jqegwogudh 1 301 val
+jqekqalssy 0 300 val
+jqekzibtwn 0 300 val
+jqeofsgjoa 1 300 val
+jqepglgamm 1 300 train
+jqequofros 1 299 test
+jqevhjodad 1 300 train
+jqfeszpvvb 1 300 train
+jqffbjwxre 1 299 test
+jqflbegyzp 1 300 train
+jqfnkkjjea 0 300 train
+jqftxwoqxo 1 301 val
+jqganwvigq 1 301 train
+jqgcbrsfmy 1 300 train
+jqgiabjdum 0 300 train
+jqgljhssyf 1 300 train
+jqgyjgdsjs 1 300 train
+jqhrwzwmxi 1 300 train
+jqhsfrduxs 1 301 train
+jqiayxomia 0 300 val
+jqijxcgwuu 0 300 val
+jqiloqnssu 1 300 train
+jqipvvsisb 1 300 train
+jqiqoivywh 1 300 train
+jqiyrrspsj 0 300 val
+jqjfgalnfp 1 300 train
+jqjfpkuckf 1 300 train
+jqjjxtlsxx 1 300 train
+jqjrxtxkei 1 300 train
+jqjsppxryq 0 300 val
+jqjuptdlbr 1 301 train
+jqjuqbwqvc 1 301 val
+jqjvdlytuy 1 300 train
+jqjvoniyxg 1 300 val
+jqkjbfvnxj 1 300 train
+jqkjgkjyws 1 300 train
+jqknrtzeab 1 237 train
+jqkslygusy 0 300 val
+jqkudhapwn 1 300 train
+jqkuyuotbb 1 240 val
+jqkzcdhvaf 0 300 train
+jqkzvipdcr 1 300 train
+jqldhrtwjc 1 300 train
+jqlnvlckjz 1 300 val
+jqlqjnpuog 1 300 train
+jqlqrobxiy 1 300 val
+jqlsethxvz 1 300 test
+jqltalmabm 1 301 val
+jqltenhqht 0 300 train
+jqmimsdrly 1 300 train
+jqmpshwlgy 1 300 train
+jqnagxzdlr 1 300 val
+jqnatdphlg 1 301 train
+jqnebbpshx 1 300 train
+jqngaupjhv 1 301 val
+jqnlikkyhe 1 300 train
+jqnselxbyu 1 298 train
+jqnuuzvvao 1 301 val
+jqocbvfwpp 1 300 train
+jqodmblkbb 1 298 train
+jqomvjjjxk 1 300 train
+jqonoafaum 1 300 train
+jqowiajepd 1 300 train
+jqoyqrzwnf 1 300 train
+jqpklmmkkv 0 300 val
+jqpoqqthyk 1 300 train
+jqptisjaat 1 300 train
+jqpunbpyea 1 300 train
+jqqbnrvzkp 1 300 train
+jqqcojuucy 1 300 val
+jqqjrvdqoi 1 300 val
+jqqpgsorcl 0 300 train
+jqqvlvgkyv 1 300 train
+jqqyyymwpm 1 300 val
+jqrcaawsoe 0 300 val
+jqrfqyjkqg 1 300 train
+jqrfrqykue 0 300 train
+jqrhbfryac 0 300 train
+jqrnnbprqi 1 299 val
+jqrppowjim 1 300 train
+jqrwusgwbf 1 301 val
+jqsgoahtrn 1 300 val
+jqsiqphbrt 1 300 train
+jqsmrsyiqn 1 300 val
+jqtjqtszyg 1 298 val
+jqtkdncbbj 1 300 train
+jqtprqbqzf 1 300 train
+jqtxwhdknt 1 300 train
+jqtyrtchdu 1 300 train
+jquecpbxdl 1 300 train
+jquevmhdvc 1 300 test
+jquhzmlsfs 1 300 val
+jqupaehzqi 1 300 train
+jquqnmdhpz 1 301 train
+jquwvjqhmp 1 300 train
+jquxgyjljl 1 300 train
+jqvbozufvl 1 300 train
+jqvcwyzhlh 1 301 train
+jqvedzkrxw 1 300 val
+jqvgoobdft 1 300 train
+jqvrpzjgvu 1 300 train
+jqvvlcurkn 1 300 train
+jqvwczirpa 1 301 train
+jqwdzyuttc 1 300 train
+jqwgktspum 1 297 train
+jqwpcouicf 1 300 val
+jqwqnmxstp 1 300 train
+jqwvcxcjjf 1 300 train
+jqwvvaqpao 1 300 train
+jqwwdvnwam 1 301 val
+jqwycsurda 1 300 train
+jqwyltvldg 1 300 train
+jqwypxfbns 0 300 train
+jqwyuelqsx 1 297 train
+jqxfscpibb 0 300 train
+jqxlxngjcl 1 300 val
+jqxwaaqvhu 1 300 train
+jqygrschbg 1 300 train
+jqyiwooilh 1 300 train
+jqypqwufdv 1 300 test
+jqyqezyutr 1 300 train
+jqzdswrlif 1 298 val
+jqzehqddis 1 300 train
+jqzmyutuml 1 300 train
+jqzmzfqpcq 1 300 train
+jqznabqbes 1 301 train
+jqzpfigaxh 1 300 val
+jqzpssmrex 1 300 train
+jqzuuicgbm 1 300 train
+jqzzrthpnt 1 299 train
+jrabjapswc 1 300 val
+jrabtkjqwn 0 300 train
+jradfrmhvb 1 301 train
+jraehbxfgj 0 300 train
+jraejjhhhy 1 301 train
+jraihbnpib 0 300 val
+jrakqbwquo 1 300 train
+jranrlmuyk 1 300 test
+jraodnkhkw 1 301 train
+jratxzmvan 1 300 train
+jraujypbkw 1 300 train
+jrbnxvgdva 1 300 train
+jrbpgglpyk 1 300 train
+jrbthdeypd 0 300 train
+jrbvssypfd 1 300 train
+jrbyllhhti 1 298 train
+jrcbxevnrf 1 300 train
+jrckfdokwl 1 300 train
+jrckljmonu 1 300 train
+jrcnquaako 1 300 train
+jrcntuijra 1 300 train
+jrctkjsnwv 1 298 train
+jrcxjyuddj 1 301 val
+jrcyjnygdg 1 300 train
+jrdacodkky 1 300 val
+jrdaowgknr 0 300 train
+jrdkewnpng 1 301 train
+jrdnwottjy 1 301 train
+jrdsdnlvzp 1 300 train
+jrdspknouk 1 300 val
+jrdvozukfo 1 300 train
+jregqlpriq 1 241 train
+jrejskikgi 1 299 test
+jrelmwwawy 0 300 train
+jrentcffjc 1 300 train
+jrewpuztaa 1 300 train
+jreyohhagp 1 300 train
+jrfaaszfqd 0 300 train
+jrfaqilmkz 1 300 train
+jrffhrahla 1 300 train
+jrffyhvmuu 1 297 val
+jrfheofiuu 1 299 train
+jrfhfwbafd 1 300 val
+jrfpswbcjm 1 300 train
+jrfurxxsvw 1 298 train
+jrfwvztbed 1 300 train
+jrfysqxoyv 0 300 train
+jrfzwcudmu 1 300 train
+jrganooivc 1 300 train
+jrgbxzjwsm 1 300 train
+jrgfabamaa 1 300 test
+jrgixfqrvf 1 300 train
+jrgkbiayur 1 300 train
+jrgmmtmafq 0 300 train
+jrgrxmzjhv 1 300 train
+jrgyxvsmgq 1 300 val
+jrgzhmsiox 1 300 train
+jrhhgcvctg 0 236 train
+jrhqfmpslk 1 300 train
+jrhrxgmnvj 1 300 train
+jrhyosneuf 1 297 train
+jribcxrada 1 300 train
+jrikdpwrfr 0 300 train
+jrivhpodsx 1 300 val
+jrjbjggsot 1 300 train
+jrjcmzjmfk 1 300 train
+jrjiclklya 1 241 train
+jrjklmnkfd 1 299 train
+jrjlmyygsa 1 300 train
+jrjotygsxf 1 300 train
+jrjqgahsey 1 298 train
+jrjrmrjlqb 1 300 train
+jrjrwgixgv 1 300 val
+jrjturuuzm 1 300 val
+jrjutcqvfb 1 300 train
+jrjvzpjldk 1 300 train
+jrjxehotww 1 300 train
+jrkdzpijpb 1 136 train
+jrkhwltlsb 0 301 train
+jrkvtfizbr 1 300 train
+jrkxlsjkro 1 300 train
+jrlelcahry 1 300 train
+jrlepsymil 0 300 train
+jrlixknfvq 1 298 train
+jrlkwlrmpw 1 300 val
+jrlncrfwcj 0 300 train
+jrlodkmngy 1 300 train
+jrlrxfzece 1 300 train
+jrltgiaqfy 1 300 val
+jrlvnimusz 1 301 train
+jrmdnwgdfi 1 300 train
+jrmgqzgcmj 1 300 val
+jrmgyjggtu 1 301 val
+jrmipgegog 0 301 val
+jrmnxfguwh 1 300 train
+jrmpjrxfgj 1 300 train
+jrmpxxbikm 1 300 train
+jrmqsinefn 0 300 train
+jrmrihegbn 1 300 train
+jrmwzcmjum 1 300 train
+jrmxtiyweq 1 300 train
+jrneaksjvj 1 300 val
+jrngrhmgor 1 300 train
+jrniosjjyy 1 300 train
+jrnjsuiakv 1 300 train
+jrnklhsqet 0 300 train
+jrnmspakke 1 300 train
+jrnreznqes 1 300 val
+jrofpjxnob 1 300 train
+jrofvutpmh 1 300 val
+jromfdsxtu 1 300 train
+jroutjpyfa 1 300 val
+jroxehuxll 1 300 train
+jroxppirqe 0 300 val
+jrpccjhcth 1 300 train
+jrpeqcrsax 1 300 val
+jrpgxjfigi 1 300 train
+jrphozmnov 0 300 val
+jrpkyoteas 0 300 val
+jrplzddhna 1 300 train
+jrpurlcwgr 1 300 train
+jrqvrjdthp 1 300 train
+jrqzhijhik 1 300 train
+jrrbiltviz 1 299 train
+jrreiborhf 1 301 train
+jrreztguln 1 300 train
+jrrhsbwjph 1 301 train
+jrrqmrsybi 1 240 train
+jrrslkdiaf 0 300 train
+jrrwdwqjdg 0 300 train
+jrrzmtqwdg 0 300 train
+jrscolnmdf 1 300 train
+jrsdfyvfig 1 300 train
+jrsgxwetfc 1 298 train
+jrsknzrssp 1 299 train
+jrsobvasqd 1 300 train
+jrstleapwn 0 300 train
+jrstztoybc 1 300 train
+jrtadvzeby 1 300 train
+jrtcxweqxe 1 300 val
+jrtghqlzxk 0 300 train
+jrtglzlijz 1 300 test
+jrtgsrmvfu 0 300 val
+jrtkfzvedu 1 300 train
+jrtoqjcqmn 1 240 train
+jrucimypwg 1 300 train
+jruczqfsaj 1 300 train
+jrujgfwvgd 1 298 val
+jrujqurhms 1 241 train
+jrukadlpxc 1 299 train
+jruqdkdnnz 1 301 train
+jrurwegwmd 1 300 train
+jrusnaaffv 1 300 val
+jrutdyjyks 1 300 train
+jrutmxkokw 1 301 val
+jruuybbckw 1 299 train
+jruxzqarwf 1 239 train
+jrvfuggowd 1 300 train
+jrvhkuroor 1 298 train
+jrviwokzrg 1 300 train
+jrvjswdnbj 1 300 train
+jrvkvaband 1 301 val
+jrvncjucma 1 300 train
+jrvpdkwduj 1 301 train
+jrvtaxyblu 1 301 train
+jrwcbgckvl 1 300 train
+jrwgmfdfsf 1 300 train
+jrwibaohlk 1 300 train
+jrwjdkoouq 1 299 test
+jrwlxmtayw 1 300 train
+jrwqouwlzc 1 300 train
+jrwxbewzym 0 300 train
+jrxdmvhsth 1 300 train
+jrxfhvcuuz 1 300 train
+jrxmcmigoq 1 300 train
+jrxmyjotcc 1 300 train
+jrxvchrgwp 1 300 train
+jrxvfumorv 1 300 val
+jryaixqoqw 1 300 val
+jryauhyvbe 1 298 train
+jryhteeoxh 1 300 train
+jrymyxtjqo 1 300 train
+jryowjdxxf 1 300 train
+jryrqyiont 1 300 train
+jrysyfoedn 1 300 train
+jryzaxwhjq 0 300 train
+jrzblhctey 1 301 val
+jrzgbkqffg 1 300 train
+jrzhapjcjs 1 301 train
+jrzibpjody 1 300 train
+jrzjifqtpt 1 300 train
+jrzkszvxsu 1 300 train
+jrzmfauynu 1 302 train
+jrzmnqcxmm 1 300 train
+jrznwtjskk 1 240 train
+jrzphugdyd 1 301 train
+jrzqddawnn 0 300 train
+jrzsengxux 0 301 train
+jrzwabkkvh 1 302 val
+jsabxwsgid 1 300 val
+jsafxjkszn 1 300 train
+jsalpxumob 0 300 val
+jsanjrgufc 1 300 train
+jsaoosmkqe 1 300 train
+jsaqcymkis 1 300 train
+jsasjuhurv 1 300 train
+jsaxugyuqt 1 299 test
+jsayncjtgn 0 300 train
+jsazvwbrpo 1 300 train
+jsbbesskzz 1 300 train
+jsbgiqlqhc 1 300 train
+jsbhkmrppe 1 300 train
+jsbitxrabi 1 300 train
+jsblexmmvw 0 301 train
+jsbpkpxwew 1 300 test
+jsbrememgc 1 300 train
+jsbsfornwi 1 300 val
+jsbzthxqwn 1 300 train
+jscfmmbgmv 1 300 train
+jscgwsatat 1 300 train
+jscprixdqn 1 300 train
+jscqgaevuz 1 300 train
+jsctgsinhg 1 300 val
+jscycckibw 1 300 train
+jsdcfhtyyr 1 300 val
+jsddeswcrn 0 300 train
+jsddlzollu 1 300 train
+jsdonkriyw 1 239 train
+jsdqmvrxez 1 300 train
+jsdzbyubvl 1 300 train
+jsdzhlsgbl 1 300 train
+jsdzsukqyw 1 300 val
+jsecestmul 1 300 train
+jseklzygum 1 301 train
+jsenbolqlq 1 300 val
+jseqkdiakn 1 300 train
+jseujyrgvb 1 300 train
+jsexlelkyg 1 300 val
+jsfajipqks 1 300 train
+jsficotskd 1 296 train
+jsfsjjgahm 1 241 train
+jsfudvzjhb 1 299 train
+jsfybjkoaz 1 300 val
+jsgexbapus 1 300 train
+jsgeyozwvx 1 241 train
+jsggfsbraz 1 300 train
+jsgivepvkt 1 300 train
+jsgqmclzdj 1 300 train
+jsgrlczusb 1 300 train
+jsgruvxkuk 0 300 train
+jshdgdhbek 0 300 train
+jshkqnynbh 1 300 train
+jshlzwhsgf 1 301 train
+jshvrulehi 1 300 val
+jsijpxmjir 1 300 train
+jsiknrqthx 1 300 train
+jsimfxqjqv 0 300 train
+jsinfemeeb 1 301 val
+jsiphcaqos 1 300 train
+jsirfifkwz 1 300 train
+jsithnrvsv 1 300 train
+jsizgqsaxp 1 300 train
+jsjbfknigi 1 297 train
+jsjkrckbep 1 300 val
+jsjlxjzlid 1 300 train
+jsjuuscwnp 1 300 train
+jskayjpwbx 1 300 val
+jskbflneit 1 300 train
+jskczbnmrl 1 300 val
+jskiwfcfkv 1 300 train
+jskjkebmgf 1 300 train
+jskmofmijr 1 300 train
+jskqsjbzfd 0 300 train
+jskreyryta 1 300 val
+jsksmezfth 1 300 test
+jskucbqyhl 1 300 train
+jskwkrdoxm 0 300 val
+jslbcvcsdd 1 300 train
+jslmibhdmy 1 300 train
+jslmxxogon 1 241 train
+jsmfsvpcze 1 298 train
+jsmglmlgrz 1 300 train
+jsmhjaduqt 1 300 train
+jsmlfwdmht 1 300 val
+jsmohpxtcr 1 300 train
+jsmpyzdmtj 1 300 val
+jsndyfrafa 1 300 train
+jsnejuyavq 1 300 train
+jsnghlpxpu 0 300 train
+jsnkotxoua 1 300 test
+jsnmepapdc 1 300 train
+jsnmjmoykw 1 300 train
+jsnooolihm 1 300 train
+jsnrkyovgc 1 300 train
+jsoggjrgjg 1 300 train
+jsohjnstkt 1 300 train
+jsoimzdksr 1 300 val
+jsojgpoaib 1 300 train
+jsokbkwqso 1 300 train
+jsoouhmwsb 1 300 train
+jsowetfslh 1 300 train
+jsowtzdepc 0 300 train
+jspfhbecif 1 300 train
+jsprhkyuwc 1 300 train
+jsptcbajsc 1 302 train
+jspxmuypkq 0 300 train
+jsqbjbydgp 1 300 val
+jsqfoxnffa 1 300 train
+jsqfvmhgoz 1 301 train
+jsqtbnxnpb 1 300 train
+jsqwrghyep 1 300 train
+jsqxxxeqfw 1 300 train
+jsqzdospiv 1 300 train
+jsrblmdhky 1 300 train
+jsrckrdopv 1 300 train
+jsrezsxyro 1 300 val
+jsrgcgsqll 1 300 train
+jsrhoymggn 1 300 train
+jsrkxevvnm 1 241 train
+jsrlfyjhzg 1 302 train
+jsrmwevsmp 1 300 test
+jsruumuhra 1 300 train
+jsruxnmhbz 1 300 val
+jsrzgpqyjy 1 300 val
+jssctdgngb 1 300 train
+jsshbuhrel 1 300 train
+jsslinonsc 1 300 train
+jssvebigdw 1 300 train
+jssvhybdxi 1 300 train
+jstfqtqxsd 1 300 val
+jstkxkjxmo 1 299 train
+jstlavjwmf 1 294 train
+jstmyejtty 1 300 train
+jstwvimaml 1 300 test
+jstxaddoee 0 301 train
+jsugobkfqg 1 300 train
+jsuhwchxdu 1 300 train
+jsujujzxqn 1 300 train
+jsuobaeskq 1 300 val
+jsvolvdaxo 1 300 train
+jsvpxppned 1 300 train
+jsvqjggeqz 1 300 val
+jsvqjkmpzu 1 299 val
+jsvwpbsddr 1 300 train
+jsvxrjvyuj 1 300 test
+jsvzushqrs 1 300 train
+jswfvewzrz 1 292 val
+jswhgnskzt 0 300 train
+jswifckvow 1 300 train
+jswlnqjfyu 1 241 train
+jswpkmgbqk 1 300 train
+jswsssnhzq 0 300 val
+jswunuyhcq 0 300 train
+jswuqkcikl 0 300 train
+jswwviwhdt 1 300 train
+jsxcadchkl 0 301 train
+jsxdkjdoqs 1 300 train
+jsxfcybqpn 0 300 train
+jsxfuhvvcu 1 300 val
+jsxgbxobzi 1 300 val
+jsxgilblfw 1 300 val
+jsxhjvxmah 1 300 train
+jsxjcgojly 1 298 train
+jsxmwrxjdo 1 301 val
+jsxqmxtmgu 1 300 test
+jsxqyreyps 1 300 train
+jsxvmbpwen 1 300 train
+jsxytifcwp 1 300 train
+jsyceusvro 1 300 train
+jsydtyxubs 0 300 train
+jsyffvsrjt 1 300 val
+jsyhejuznh 0 300 train
+jsyinaqlaf 1 301 train
+jsyisypskd 1 300 train
+jsyjstecqw 1 301 train
+jsyqkuekxc 1 300 train
+jsysgmycsx 1 300 test
+jsytdoqkoh 1 300 train
+jsyvjrorrc 0 299 val
+jsyyatuoox 1 300 val
+jsyzohwhta 1 300 train
+jszcnqtpjm 0 300 val
+jszdwwjajd 1 300 train
+jszeqvgngi 1 300 train
+jszncmcrgx 1 300 train
+jszyfkcsvb 1 300 train
+jszyyhamrh 0 300 train
+jtafajtmpv 0 300 train
+jtairnyezr 1 301 train
+jtaqzshggo 1 300 train
+jtarojcuko 1 300 train
+jtataeqtgt 0 300 train
+jtatjkutwx 0 300 train
+jtazbdmcqi 1 299 test
+jtbdyxjnnv 1 300 train
+jtbnxquvmb 0 300 train
+jtbqjkgfnk 1 300 train
+jtbslmtffu 1 300 train
+jtbvdjpotw 1 300 train
+jtbxxtflgn 1 300 train
+jtcczuggnh 1 301 val
+jtcdnrwmwn 0 300 train
+jtcfpzwbkf 1 300 train
+jtcgemhutj 1 300 val
+jtcibopcdr 1 300 train
+jtcmogdwka 1 298 train
+jtcmpbmcgm 1 300 train
+jtcnvejifk 1 300 train
+jtcplqzvaf 1 300 train
+jtcsjwncak 1 300 train
+jtcsllillq 1 301 train
+jtctmvotlp 1 300 val
+jtcuhmncrg 1 300 train
+jtcwyiywmy 1 300 train
+jtddriehmx 1 300 train
+jtdkxmqnwn 1 300 train
+jtdngjvgwq 1 300 train
+jtduaxahlv 0 300 train
+jtdvenwmkx 1 300 train
+jtdvlkvnjv 1 299 train
+jtdwcnmhmz 1 300 val
+jtdycuybti 1 300 test
+jteiccmuyn 1 300 train
+jteqilvdec 1 300 train
+jtfcivmkts 1 300 test
+jtffnatnxj 1 300 train
+jtfhglskyq 1 300 train
+jtfjpcldhi 1 300 train
+jtfjygauws 1 299 test
+jtfklrpqhv 1 300 train
+jtfrlnkyoz 1 300 train
+jtfxmxcghb 0 240 train
+jtfzcvlfxi 1 300 train
+jtgesoyiiy 1 300 train
+jtgfbxkgkj 0 300 train
+jtgfoscjjd 1 300 train
+jtgfvokvea 1 300 train
+jtgjiokssd 1 300 val
+jtgletnzly 1 300 val
+jtglgbwqxg 1 300 train
+jtgmxlpnja 1 241 train
+jtgpcqqwqi 1 300 train
+jtgujpmdff 0 300 train
+jtguzdzxod 1 300 train
+jtheaunoie 1 300 val
+jthegfowct 1 300 train
+jthhzxnrwj 1 300 train
+jthjtdmodv 0 300 train
+jthldhxvfu 1 300 train
+jthoqcewkf 1 301 train
+jthssgnbze 0 300 train
+jththiweee 1 288 train
+jthxoyeoij 1 300 train
+jthxydasmt 1 300 train
+jtibfxbjpo 1 300 train
+jtihnfftgo 1 301 val
+jtiideprrg 1 300 train
+jtilgqqkab 1 300 val
+jtiryyphwj 0 300 train
+jtivmdidrb 1 300 val
+jtizjapuss 1 300 train
+jtjejchhfw 1 300 train
+jtjeyowlxq 0 300 train
+jtjjgbmfdd 1 288 train
+jtjqdwdpjn 1 300 train
+jtjxfjaamb 1 298 train
+jtjxulrmvv 1 300 train
+jtketdamsj 1 300 val
+jtkfbvfxst 1 300 train
+jtkimbeegy 1 301 train
+jtkjxwyvpu 0 300 train
+jtkkxssxge 1 301 train
+jtkoizauow 1 300 train
+jtkqjeenlp 1 300 val
+jtkqkovbid 1 300 train
+jtkslktcjw 1 300 val
+jtkyoulizr 0 300 val
+jtlbeqgmmn 1 300 val
+jtlbtasmvt 1 300 val
+jtlcfpgpim 1 300 train
+jtlhnksetc 1 300 train
+jtlhwwxrtr 0 301 train
+jtlirhcqir 1 300 train
+jtlsugcter 1 300 val
+jtlujteklr 1 300 train
+jtlvaogjmv 0 300 val
+jtlwxmwvuw 1 300 train
+jtmaersduo 1 300 train
+jtmbjpgrww 1 300 train
+jtmjzepxmy 1 300 train
+jtmntnyppf 1 300 train
+jtmsdyckqs 0 300 train
+jtmsnqqvpc 1 300 train
+jtmvghgdru 1 301 val
+jtmyingtsc 1 300 train
+jtnkppoigi 0 300 val
+jtnqntwshv 1 300 test
+jtnxprlqpj 1 300 train
+jtnyvsvczz 1 300 train
+jtoesjaejy 1 300 train
+jtohddoqan 1 300 val
+jtohkanmcb 1 300 train
+jtokbfkuve 1 300 train
+jtopketwmv 1 300 train
+jtoqkohokh 1 300 val
+jtpaxywixp 1 300 train
+jtpbjnrcgj 1 300 train
+jtpgojfros 1 300 val
+jtpgyefpjh 1 300 train
+jtpjvsnwjc 0 300 train
+jtpkhkdafc 1 300 train
+jtplbbgtup 1 300 train
+jtpmcpcbsn 1 300 val
+jtpupxzgoa 1 300 test
+jtpxeylqez 1 300 train
+jtqaughydm 1 300 train
+jtqdhomsan 1 300 val
+jtqglpdlzp 1 300 val
+jtqnyjpmoq 1 300 val
+jtqoahhdyw 1 300 train
+jtqrujchxw 1 300 train
+jtqstsniyh 1 300 val
+jtqsywdslx 1 300 train
+jtqvverdvh 1 298 train
+jtrbieopvk 1 300 test
+jtrbuywjdy 1 300 train
+jtrkocnwhv 1 300 train
+jtrlcqcamr 1 300 val
+jtroatfmaw 1 241 train
+jtrreaszdg 1 300 train
+jtrsfqiowp 0 300 val
+jtryvnerhg 1 301 val
+jtsfgtxnhi 1 300 val
+jtsftmvtcf 0 300 train
+jtsiisuilu 1 300 train
+jtswehvreq 1 300 train
+jttbenjinn 1 300 val
+jtteetuqtt 1 300 train
+jttfeamlei 1 300 val
+jttgsevqku 1 300 train
+jtthbxcbqd 1 300 train
+jttpgvrqep 1 301 train
+jttzqzzikd 1 300 train
+jtuiddncpo 1 300 test
+jtuiyjajhw 1 300 train
+jtukwxfwew 1 300 train
+jtupvfukkx 1 300 val
+jtusjqeiqz 0 300 train
+jtuuajwtiq 1 300 train
+jtuvrttuwy 1 300 train
+jtvbtwmfgr 1 300 train
+jtvccolpru 1 300 train
+jtvcxbfuks 1 300 val
+jtveiglyxh 1 300 train
+jtvkqxsugc 1 300 val
+jtvlkfcrxj 0 300 val
+jtvopxfptd 1 300 val
+jtvrpogeil 1 300 val
+jtvvmhqhbp 1 300 train
+jtvznbwmem 1 300 val
+jtwarujkxb 1 300 train
+jtwehmfurs 1 300 val
+jtwhxlisxi 1 300 train
+jtwjkzjgut 1 300 train
+jtwpwdqmxz 0 300 val
+jtwqwmqfrh 1 300 val
+jtwwxgmyvt 1 300 val
+jtxwpkbnem 1 300 train
+jtxwpqhbyy 0 300 train
+jtynaugsru 1 300 train
+jtyrcldkrn 1 300 train
+jtyutxhuhm 0 299 train
+jtyvngdrkr 1 300 val
+jtzekkwofj 1 300 train
+jtzgjwxifi 1 301 train
+jtzhpcaxpo 1 301 val
+jtzjxkcbtg 1 300 test
+jtzmffmroy 1 300 val
+jtzrqorpbq 1 299 val
+jtzuvuqqxk 1 300 train
+jtzveqmnnr 1 300 train
+juaelozfre 1 300 val
+juahjpqxhg 1 300 train
+juaqsqaphv 1 300 train
+juavnhcgyl 0 300 train
+jubbkhuhgc 1 241 train
+jubcvtyanz 1 301 train
+jubdthsrzc 1 300 train
+jubdudqyem 0 300 train
+jubgiuyhtj 0 300 val
+jubhnrzjnt 1 298 val
+jubibhoyio 1 300 val
+jubprlhlfr 1 300 train
+jucamxomcy 1 300 train
+jucbwpzqmj 1 300 train
+jucdkyvttm 1 300 train
+juceivmtzs 1 300 train
+jucsqxtxyy 1 302 train
+jucvgjwoep 1 300 train
+jucvtcykma 1 300 val
+jucwjcziwo 1 300 train
+judbandmix 1 300 train
+judijcrqow 1 300 train
+judmcwbhws 1 300 train
+judmuxsrvn 1 300 train
+judnahasmd 1 300 train
+judokbfarj 1 300 train
+judsnxbvol 1 300 train
+judthfhzix 0 300 train
+judvmmvwll 1 300 train
+judwwzqwrs 1 300 val
+judztawuje 1 300 train
+juedmdxjdo 1 300 val
+jueeritxcp 1 300 train
+juenjlzrap 1 300 train
+jueuqezaoz 1 300 val
+juewofufos 1 300 train
+jufcwymcjl 0 300 train
+jufcykpvra 1 300 train
+jufnzwhpcl 1 300 train
+jufqbtclow 0 300 train
+jufsyamrqw 1 300 train
+jufzjqtqux 1 300 train
+jugcjdsxmc 1 300 train
+jugposzkgy 0 300 train
+jugxnpjyak 1 300 train
+juhdvgqdfe 1 300 train
+juhisrjwbo 1 300 train
+juhpgqxkwl 0 300 val
+juhsvucksu 0 300 val
+juhyvpvkwb 1 301 train
+juigeuwbxn 1 300 train
+juinndbyjk 1 299 val
+juiuzrtxnb 1 300 train
+juivahptle 1 300 train
+juivasplmg 1 300 train
+juiybnkuxc 1 300 train
+jujbjgqshr 1 300 train
+jujfgbmoph 1 300 train
+jujpqsrgll 0 300 train
+jujuzhqrdz 0 300 val
+jukcjryufw 1 241 train
+jukdrlxfna 1 300 val
+jukejxtrju 1 300 train
+jukglapcgp 0 298 train
+jukuwuqiik 1 300 train
+jukxslmvnt 1 300 train
+jukyazaybn 1 300 train
+jukyfuxrka 1 300 val
+julcvauylz 1 301 train
+julfellhdf 0 300 train
+julfioglcy 1 301 train
+julfknzrsp 1 299 val
+juljusrhxc 1 300 val
+julkwjicct 1 300 train
+julnynlqul 1 300 train
+jumbhmwmwt 0 300 train
+jumllfuvgm 1 299 val
+jumqsbxlwc 1 298 val
+junccaygsb 1 300 train
+jungoardsy 1 301 train
+juniypxmlh 1 300 train
+junllgghcq 0 299 val
+junmjuoplm 1 83 train
+junospzshm 1 300 train
+junsbfgbnv 1 300 val
+junsqfquxf 1 301 train
+junsqswjoc 0 300 val
+junvgpndop 1 300 train
+junwffcypn 1 300 train
+junyrlainl 1 300 train
+junzqfxzxj 1 300 train
+junzzlnlfw 1 300 train
+juoerlgkpf 1 299 val
+juojkwweft 1 300 train
+juoldquzwp 1 300 train
+juoyxhclkj 1 269 train
+juoztokndk 1 300 train
+juozwnwlzq 1 300 train
+jupblreoup 1 301 train
+jupepuhajs 1 300 val
+jupfdupshw 1 300 val
+jupixnzmad 1 300 train
+juprmlognj 1 300 train
+jupshqfhqz 1 300 train
+jupsrcyjeg 1 300 train
+juqgdaxcej 0 300 val
+juqhqrfoit 1 301 val
+juqplwkgxu 0 300 train
+juqqzliyrk 1 300 train
+jurapnzpdt 1 298 train
+juravllygo 1 301 train
+jurpmhcmis 1 300 val
+jursobqsvf 1 300 train
+jurtcmuywj 1 300 train
+jurumobmww 1 300 train
+juryperlig 0 300 val
+jurznbpwvc 1 300 train
+jurzyggpgq 0 300 train
+jusankjagd 1 300 train
+jusibutifg 1 300 train
+juslzvahqm 1 300 train
+jusmragukx 0 300 train
+juspfcwdxi 0 300 train
+jusvaqqpde 1 300 train
+juswhonnji 1 300 train
+jutaplgsnv 0 292 train
+jutcgztwyc 1 300 train
+jutekeanye 1 300 train
+jutghbcklw 1 301 train
+jutkyeczir 0 300 train
+jutnkmqtxy 0 298 train
+jutpohkisi 1 300 train
+jutxvpmwdz 1 300 val
+juubmonefn 1 298 train
+juudbscpul 1 300 train
+juugrqdhai 1 300 train
+juunpbzdaz 1 299 train
+juuxucpukk 0 300 train
+juuzhvhejm 1 300 train
+juvcsunngk 1 300 val
+juvfdsrodw 0 300 train
+juvkgfopbn 1 300 train
+juvnnolwbw 0 300 train
+juvomhxzgt 1 300 train
+juvsjbjoft 1 300 train
+juwiksnlqv 1 301 train
+juwlfcebod 1 299 test
+juwmdknrki 1 299 val
+juwmifvwmj 1 300 val
+juwogsjffl 1 300 train
+juwqgeddwt 1 300 train
+juwwebygny 1 300 train
+juwyxocpqf 1 300 train
+juxfpelqqj 1 300 train
+juxnfngdxg 1 300 train
+juxqmadugp 1 300 train
+juxsomndll 1 298 train
+juxsppleru 1 298 val
+juxswrseor 1 300 train
+juxtasggsh 1 301 train
+juxtnwfsjh 1 300 train
+juxwemqaoo 0 300 train
+juyadpcdzu 1 300 train
+juybcnkfle 1 300 val
+juydzuzjzb 1 300 train
+juyijcudeb 1 300 train
+juyrpurftp 0 300 train
+juysldanin 1 300 train
+juyweuyrcu 1 300 train
+juyzxfaydw 1 167 train
+juzarfnkgs 1 301 train
+juzdhkxpkp 1 300 train
+juzetmgaoc 0 300 train
+juzhmqbiwn 1 300 train
+juzjaxsbhh 1 300 train
+juzjntqofi 1 300 test
+juzjpblenq 1 300 train
+juzjsciuyy 1 300 train
+juzlxiuwdg 1 300 train
+juzryqckqi 0 300 val
+juztyfwzts 1 300 train
+juzxutctdx 1 300 train
+jvadnjprqn 1 300 test
+jvatbrmbty 1 300 train
+jvathupada 1 300 train
+jvaxbzaavd 1 300 train
+jvbiqqkinr 1 300 train
+jvbkzkkkcg 1 300 train
+jvcerwsnlb 1 300 train
+jvciyfgyux 1 300 train
+jvckgfmuxm 1 249 train
+jvcqwdekjd 1 300 train
+jvcrvrazmm 1 297 val
+jvcvwiugzi 1 301 train
+jvcxmwktsf 1 300 train
+jvdaoipduc 1 300 train
+jvdxgtentr 1 300 val
+jvdxkwmbxz 1 300 train
+jvdypckvki 1 300 train
+jvebpyiget 1 300 train
+jvefeqbzwe 1 300 train
+jvejhcxrpk 1 300 val
+jvekouiosl 1 300 train
+jveqsndvuv 1 300 train
+jverkxqlvk 1 300 train
+jveskbrbnb 1 300 train
+jveubdamoh 1 300 train
+jvevfxpezm 1 300 train
+jvexewmxzf 1 300 val
+jvezijjrcf 1 300 val
+jveztsgbrn 1 302 train
+jvfguqnbpx 1 300 train
+jvfhbqvixc 1 300 train
+jvfkdqiwug 1 300 train
+jvfmgrpknj 0 298 train
+jvfpcokomj 1 300 train
+jvfsalaiqa 1 300 train
+jvfuujkick 1 300 train
+jvfvolwxep 1 301 train
+jvgbdimxet 1 300 val
+jvgbggnvuh 1 299 train
+jvgeqnmwmz 1 300 train
+jvgiztupzp 1 300 train
+jvgnfkybgv 1 300 train
+jvgpkmbudt 1 300 train
+jvgrsfohjf 1 300 train
+jvgwcmnpdf 1 300 train
+jvhfzjtzww 1 300 train
+jvhidzdcec 1 300 train
+jvhmnsksbf 1 299 test
+jvhoaraznu 1 301 train
+jvhpmluxhp 1 241 train
+jvhtufavvu 0 300 train
+jvihmimqca 0 300 train
+jvioejzfxk 1 300 train
+jviyrkkmfi 1 300 train
+jvjkddqwem 1 300 train
+jvjqhogbjh 1 300 train
+jvjrveqgky 1 298 train
+jvjstqodrq 1 300 val
+jvkjkrdeok 0 241 train
+jvksqlpuae 1 301 train
+jvkzxerjub 1 300 train
+jvlmwvzpak 1 300 test
+jvlpvtlmxy 1 300 val
+jvltbfzcox 1 301 train
+jvlvkijuwa 1 300 train
+jvlzvgcfft 1 301 train
+jvlzwnbblv 1 298 train
+jvmdzcrakg 0 300 train
+jvmhslmnrn 0 301 train
+jvmimpgivr 0 301 train
+jvmjjaljep 1 300 val
+jvmmgcirbk 1 300 train
+jvmvhvrpyn 1 300 train
+jvnadcrout 1 300 train
+jvngdavyfw 1 300 train
+jvnokzmvje 1 300 train
+jvoccwojhu 1 300 train
+jvoejpzdfq 0 300 val
+jvojjjhmvh 1 300 val
+jvolaeiszk 1 300 train
+jvomudwqga 1 300 train
+jvoqlyayrn 1 299 train
+jvoqzzvbmu 1 300 train
+jvoudxgubz 1 301 val
+jvoyeatnah 1 299 train
+jvozxoqwly 1 300 train
+jvpfpyqkdl 1 300 train
+jvphdpptqv 1 300 train
+jvpivxomab 1 300 train
+jvppjxymwn 1 300 train
+jvppzoiiss 1 300 train
+jvptmgmmff 1 300 train
+jvpwjupnxs 1 300 train
+jvpzkubqfj 1 301 train
+jvpzztmoiw 1 300 train
+jvqcgarxwl 1 300 train
+jvqcvinqvt 1 300 train
+jvqgbzeuai 1 300 val
+jvqjnnuuiu 1 301 val
+jvqvwasuic 1 300 train
+jvrcpqbzcu 1 300 train
+jvrllqztml 1 300 val
+jvrtqrtulh 1 300 train
+jvrwshxjmr 1 300 train
+jvscpktkpv 1 300 train
+jvsngcdomj 0 300 train
+jvsnshykcf 1 300 train
+jvsofogtub 1 300 val
+jvsyayposo 1 300 train
+jvtelsocxh 1 236 train
+jvtgwixooc 0 300 train
+jvtjxreizj 0 300 val
+jvtrffcjuh 0 300 val
+jvtttgwsha 1 300 train
+jvtziksdfh 1 300 train
+jvudvsujtq 0 300 train
+jvuvxjexte 1 300 val
+jvuwoayfca 1 300 train
+jvuwsnvypv 0 300 train
+jvuxjmomty 1 300 val
+jvuyijxuas 1 300 train
+jvvdmdoetp 1 300 val
+jvvlwjmfyn 1 300 val
+jvvrmwpbdq 1 300 train
+jvvzvgtoqb 1 300 val
+jvwhwtvuxt 0 303 train
+jvwmqzqsnh 1 300 train
+jvwmsmgzzq 1 299 val
+jvwylnhwhx 0 300 train
+jvwywiexxx 1 300 train
+jvxeafimrp 1 298 train
+jvxheknnqd 1 300 train
+jvxjddpdkh 1 300 train
+jvxjzbyori 1 83 train
+jvxljxahww 1 300 val
+jvxlwcmwed 1 300 train
+jvxneutjqq 1 300 val
+jvxnkbmrvd 1 300 train
+jvxticvhgh 1 300 train
+jvxuntcgom 1 300 val
+jvybbvcdoc 1 298 train
+jvybholngu 1 300 val
+jvyfzizdvi 1 300 val
+jvynjragij 1 301 train
+jvyohfbofm 1 300 train
+jvysoqvize 0 301 val
+jvyyumogsy 1 300 train
+jvyzfqklxl 1 301 train
+jvzakxfpyy 1 300 train
+jvzdpyonga 1 300 train
+jvzmzgqtrk 1 300 train
+jvzniqqhhr 1 300 train
+jvzrxzzpci 1 300 val
+jvztqhabhg 1 300 train
+jvzugoakqs 1 300 train
+jvzvsqomru 1 300 train
+jvzvugshel 1 300 val
+jvzxmntucw 1 300 train
+jwalykqnyp 1 240 train
+jwamhisrvs 1 300 train
+jwaoofecwt 1 300 val
+jwapisopww 1 301 train
+jwaqydcpzq 1 300 train
+jwavordtzd 1 300 val
+jwawdnmnid 0 300 train
+jwawvhfgzy 1 240 train
+jwaxanlhde 1 300 train
+jwbkfbbcrr 1 300 train
+jwblarntfg 1 300 train
+jwbsicnbyc 0 300 train
+jwbsjpudpl 1 301 train
+jwcbwrlvuh 1 300 val
+jwccbzribj 1 300 train
+jwckgjbrjk 0 298 train
+jwckqcvpoc 1 298 train
+jwcnguujiv 0 300 train
+jwcsqxzdlv 0 300 train
+jwdmybnpee 1 300 train
+jwdodejosj 1 300 val
+jwdsnktmhq 1 300 train
+jwduqoictl 1 136 train
+jwdysrhfqa 1 301 val
+jweaeexdbp 1 241 train
+jwehxetnmg 1 241 train
+jwekvqpmes 1 300 train
+jwelkizwxd 1 300 train
+jweqnfjxww 1 300 val
+jwerbdhrmu 0 297 val
+jweuoqgyld 1 300 train
+jwexyiydtv 0 300 val
+jwfizmebox 1 299 train
+jwfjptfxnf 1 300 train
+jwfnagnajn 1 241 train
+jwfplrhnou 1 300 train
+jwfxbianjp 1 300 train
+jwfxywlyjt 1 300 train
+jwgadxzcju 0 300 train
+jwgajaydgv 0 300 train
+jwgasxcjou 1 300 test
+jwgcsjbqqx 1 300 train
+jwgdpsfpev 0 300 train
+jwgfhyetvy 0 301 train
+jwgfvqfwki 1 300 train
+jwgtnolvsh 1 241 train
+jwgvjcjkbs 1 300 train
+jwhdfrrrsf 0 302 train
+jwhixqplji 1 300 val
+jwhjmfgnvx 1 300 val
+jwhqfaoimh 1 300 train
+jwhsfrbrzw 1 300 val
+jwiapmcyok 1 300 train
+jwieuusxut 0 300 train
+jwiitwnpxc 1 299 train
+jwiuwkpmmf 1 300 train
+jwiybvglul 0 300 train
+jwjegckisi 1 300 val
+jwjejpuxwp 1 300 train
+jwjflkvisu 1 300 train
+jwjldnotbj 1 300 train
+jwjojpswlo 1 288 train
+jwjomhkyxo 1 300 train
+jwjomszxtm 0 300 val
+jwjrmxrgbl 1 300 train
+jwjymqansz 1 136 train
+jwjyxtjdvp 0 300 val
+jwkgjrmfxp 1 300 test
+jwkkkrsjvg 1 300 train
+jwktnswhsw 1 300 train
+jwkxtntrzz 1 99 train
+jwlfunyzqs 1 300 train
+jwlhahtbmk 1 300 train
+jwlknkklyh 1 300 val
+jwllclsfup 1 299 val
+jwlngcqkar 1 300 train
+jwlnlxrqtq 1 300 train
+jwlomkgyga 1 298 train
+jwmbhisqhn 1 300 train
+jwmkeennzf 1 300 test
+jwmrzujmee 1 300 train
+jwngqjxevo 1 300 val
+jwngxmfpgw 1 300 train
+jwnounilmq 1 300 train
+jwnpyrhcty 0 301 train
+jwnsfxrcuk 0 300 train
+jwodisvnmw 1 300 train
+jwosnmryka 1 300 train
+jwowwkpaog 1 241 train
+jwparibsae 1 300 train
+jwpdfqwqyt 0 300 train
+jwpiwefsdi 1 300 val
+jwpnepuxil 1 300 train
+jwpnlmwbtt 1 300 train
+jwpwducvzg 1 300 val
+jwpwtrckks 1 300 train
+jwpycdnsxs 0 300 train
+jwqddauwzp 0 301 train
+jwqemwcozq 1 298 val
+jwqenfucid 1 300 train
+jwqfhcyjtt 1 300 train
+jwqfviwtzy 1 300 train
+jwqhmvfdhr 1 300 train
+jwqlywbftq 1 300 train
+jwqoitayuj 1 301 val
+jwqplyokhy 1 301 train
+jwqtedxfed 1 239 val
+jwquegqnyc 1 300 train
+jwqvujrofw 1 299 test
+jwrarbxlpx 0 300 train
+jwrardpibq 1 301 train
+jwrjdjviqe 1 296 val
+jwrsnlbroa 1 298 train
+jwrupyzdpz 0 300 train
+jwrxbnzxcp 1 301 train
+jwrypvpvpx 0 300 train
+jwrzplnlfn 1 300 train
+jwsaofatad 1 300 train
+jwscmcuxnp 1 300 val
+jwsiosxyhw 1 300 train
+jwsjjkjobh 0 302 train
+jwssdeyaky 1 300 val
+jwtcthyuxh 1 241 train
+jwtdrqmvga 1 300 train
+jwteyoaxtx 1 300 train
+jwtldqgmyk 0 300 train
+jwtljeywdu 0 300 train
+jwtouqoeat 1 300 val
+jwtxwnfvtf 1 300 train
+jwuiourbih 1 300 train
+jwuolcfxil 1 300 val
+jwuopwkbps 1 301 train
+jwuozkqqkw 1 300 val
+jwuqabfzlx 0 300 train
+jwutgqnmsj 1 300 train
+jwuvyyuizf 1 301 train
+jwuxheiifo 1 300 val
+jwuxhuwuva 1 300 train
+jwuxouajqx 1 300 train
+jwuyeomibc 1 299 test
+jwvakkhvkp 1 298 train
+jwvbunnmhb 0 300 train
+jwvdustzrb 1 300 train
+jwvdxajidd 1 300 train
+jwvgaznkqi 1 300 train
+jwvkgbyqxz 1 300 train
+jwvojvpdco 0 300 train
+jwvoyfnqic 1 300 train
+jwvrsanehy 1 298 train
+jwvsqtdkuk 1 300 train
+jwvvwjiatk 1 301 train
+jwvxsyvenp 1 300 train
+jwwbeysysz 1 300 train
+jwwenrxcrk 1 300 train
+jwwixozsqx 1 302 train
+jwwnxkyauv 1 300 train
+jwwnyjcpmu 1 300 train
+jwwrcjwuwi 1 300 train
+jwwrifjlwk 1 300 val
+jwwuhcxrxb 1 296 val
+jwwygbtthh 1 300 val
+jwxfbezulj 1 300 train
+jwxfgfsmyq 1 300 train
+jwxkrgolju 1 301 val
+jwxonvtakl 1 300 train
+jwxpmszoes 1 239 train
+jwxsnuclie 1 300 train
+jwxxsmbxvq 0 300 train
+jwxykmwglo 0 300 train
+jwygbuprhr 1 300 train
+jwyhhbaail 1 300 train
+jwyksfczxe 0 300 train
+jwylmiqpbz 1 300 train
+jwyobizobx 1 300 val
+jwytbayitl 1 300 train
+jwyyoregvg 0 300 train
+jwzgggzfzz 1 300 train
+jwzgumwrfe 1 300 train
+jwzmmregcn 1 300 train
+jwzsypsene 1 300 val
+jwzxcpwclh 1 300 train
+jwzzfnafcv 1 300 train
+jxaawrsxdd 1 300 train
+jxachdybaj 1 300 train
+jxaebijyjp 1 300 train
+jxakrbkttd 0 300 train
+jxanssquse 1 300 train
+jxarfcwoxz 1 298 train
+jxawdzmebv 1 300 val
+jxawzdqlam 1 300 train
+jxazhpydqf 1 301 val
+jxbatthzmm 1 300 train
+jxbbipfpvv 0 300 train
+jxbeyjxmhv 1 300 train
+jxbgimtjix 1 300 train
+jxbnpngtam 0 300 train
+jxboywjitl 1 300 test
+jxbqefkgfx 1 300 train
+jxbwqhgand 1 300 train
+jxbwvyhmvf 1 301 val
+jxbxknupll 1 300 train
+jxccepfwwa 1 300 train
+jxchbmkrls 0 300 train
+jxckvenuot 1 300 train
+jxclryemim 1 301 val
+jxcpmfppqu 1 300 train
+jxcpvbshka 0 300 train
+jxcqdljodi 1 299 train
+jxcqiqjroj 1 300 train
+jxcyduqhah 1 300 train
+jxdhxofqqf 1 300 train
+jxdkksfgwt 0 300 train
+jxdntslmcw 1 300 train
+jxdoogmynr 1 300 train
+jxdpdxrunk 1 300 val
+jxdsezuxvs 1 301 val
+jxdwjidema 1 300 train
+jxearunhrv 1 241 train
+jxebflghvt 1 300 val
+jxedwcjpct 1 300 val
+jxeijpflbj 0 300 train
+jxemsrsrmc 1 299 val
+jxenpoodhg 1 300 train
+jxeqhujuvh 1 300 train
+jxewmrajdp 1 300 train
+jxfaryekxn 1 300 train
+jxfegpimxc 1 300 train
+jxfhixgzgw 1 300 train
+jxfjlrqroq 1 300 val
+jxfkckkutd 1 600 train
+jxfritqygx 1 300 train
+jxfzaedlbk 1 301 train
+jxfzqfndul 1 300 val
+jxgcqvykfy 0 300 train
+jxghkmdywf 1 300 train
+jxgjbjgtvo 1 300 train
+jxgkmoscja 1 300 val
+jxgmikhyva 1 301 train
+jxgxbpwvij 1 300 val
+jxhdlpmqfp 0 300 train
+jxhdybmyux 1 301 val
+jxhfgcyked 0 300 val
+jxhgprbewp 1 300 val
+jxhkgpvaii 1 300 train
+jxhkniejlk 1 300 train
+jxhpbimuma 1 298 train
+jxhrirhjpr 1 300 val
+jxhzcibdrb 1 300 train
+jxibbrebda 1 300 train
+jxiehkeknv 1 300 train
+jxieyvxjbj 1 300 train
+jxifedurmr 1 300 val
+jxioficcxl 1 300 train
+jxiojnhvfu 1 300 train
+jxjahoczxz 0 300 train
+jxjmkenozl 1 300 val
+jxjrskqvzn 0 300 train
+jxjupddzap 1 300 train
+jxjutaswiq 1 300 train
+jxjyufzczt 0 300 train
+jxkcbimjnd 1 300 train
+jxkfqcosed 1 300 val
+jxkhcxifpr 1 300 train
+jxkitecygp 1 241 train
+jxknsvmgjk 1 300 train
+jxknxarhqj 1 300 train
+jxkvukbxlw 1 300 train
+jxkzvhoaoq 1 300 train
+jxlhrgwjdt 1 300 test
+jxlkwmjvny 1 300 train
+jxlocqbsmq 1 301 train
+jxlpjemyhv 1 300 train
+jxlplcproi 1 300 val
+jxlvlahpsm 0 300 train
+jxmdmtsugk 1 300 train
+jxmkxhlphh 0 300 val
+jxmpyjkxoc 1 299 test
+jxnafkoduv 1 300 train
+jxncmhyizn 1 300 train
+jxneiuqiex 1 241 train
+jxnhuoofmp 1 300 train
+jxnigzjdbv 1 300 train
+jxnupbchrs 1 300 train
+jxnutsjkxm 0 300 train
+jxnvtreaoi 1 300 val
+jxoacmmdsm 0 300 train
+jxoefmqjdh 1 300 train
+jxohraoavk 1 300 train
+jxohrnekha 1 300 val
+jxohspcigm 1 301 train
+jxoldgleas 1 300 train
+jxoljcajdh 1 300 train
+jxoqxnvvpv 1 300 train
+jxouhmiuys 1 300 train
+jxowsgbsvc 1 302 train
+jxpamthxui 1 300 train
+jxpflwdqcs 1 300 train
+jxphdifuqd 1 298 train
+jxpodcendq 0 300 train
+jxpogbgibi 1 300 train
+jxppeenxtm 1 297 train
+jxprqiusey 1 301 train
+jxqhiycsbw 0 300 train
+jxqibxwhlc 1 300 test
+jxqmntxjdo 1 301 val
+jxqwnnhgjg 1 300 train
+jxrejahpqa 0 300 train
+jxrlgynjos 1 300 train
+jxrnlcoeba 0 300 val
+jxrpqynwlt 0 300 train
+jxrxlmvxew 1 298 train
+jxrycmvkib 1 241 train
+jxrymemecp 1 296 train
+jxsbpgigjh 1 301 val
+jxsdqoixva 1 300 train
+jxshjcdoyp 1 300 train
+jxsjcuncyg 1 300 train
+jxtdcojidk 1 296 train
+jxtgjddbpg 1 300 train
+jxthvcqaut 1 300 train
+jxtpjlpcca 1 300 train
+jxtxqvphdo 1 300 train
+jxtykwekpi 1 300 val
+jxucddaulv 1 300 val
+jxudztyxmw 1 301 train
+jxuhwzpmfu 0 300 train
+jxuitkngyp 1 300 train
+jxuyorcpuu 1 300 train
+jxvoarslil 1 300 test
+jxvofbtarv 0 300 val
+jxvvlrifyg 1 300 train
+jxwhdzuplx 1 297 train
+jxwkqvpvwf 1 300 val
+jxwnmvdrrz 1 301 train
+jxwpllmpom 1 300 train
+jxwskmzbfm 0 300 train
+jxwvsvrede 1 300 test
+jxwzgwcgpv 0 300 train
+jxxfgwhhas 1 300 train
+jxxhoziqfh 1 300 val
+jxxqdfljbx 1 300 val
+jxxqsgsctq 1 298 train
+jxxvhhmwhq 1 300 train
+jxyeldcvze 0 300 train
+jxyjkehelw 1 300 train
+jxyllltekh 1 300 train
+jxyrgnijpk 1 301 train
+jxysnnoqvy 1 301 train
+jxyzhpcdfu 0 300 train
+jxzfdgcykd 1 301 train
+jxznledkja 1 300 train
+jxzosnbcor 1 300 train
+jxzrmfalti 1 300 train
+jyaayteeax 1 300 train
+jyathcgzbx 1 300 val
+jybhofmryi 1 300 val
+jyblnizqwb 1 300 train
+jycbjwoxqz 1 300 train
+jycearowfp 1 297 val
+jycivoraph 0 300 train
+jycjkkzocb 1 300 train
+jycmcdzuwz 1 300 val
+jycotlrgwl 1 300 train
+jycywnrsjz 1 300 val
+jydanfaxzg 0 300 train
+jydccimjww 1 300 train
+jydcerezgs 1 300 train
+jydfbpwrld 1 300 train
+jydggbwnpq 1 300 train
+jydicakmin 1 300 train
+jydjmvxubu 1 300 train
+jydlswzfjd 1 298 train
+jydmfidpix 0 301 train
+jydndqspey 1 300 train
+jyduisigji 1 301 val
+jydwduifvu 0 300 val
+jydxrsvqaz 1 300 train
+jydyvivovg 1 300 train
+jyebichvun 1 300 train
+jyebpagpnl 1 300 train
+jyeinxcuis 1 300 train
+jyepcrdaoo 1 301 train
+jyesjccdcb 0 300 train
+jyesxgltqh 1 300 train
+jyeuuferqy 1 300 val
+jyeyhqadbc 1 300 train
+jyeyzaahhl 1 300 val
+jyffnyqeot 1 300 val
+jyfkrgwora 1 300 train
+jyfnzyvznx 0 301 val
+jyfocxohsr 1 300 train
+jyfosgjout 1 300 train
+jyfpqernil 1 301 train
+jyfuodeqkv 1 300 val
+jyfvaequfg 0 300 test
+jyfzqkkqab 1 299 train
+jygaauqopw 1 300 train
+jygbqsigcr 0 300 train
+jyginmjsyv 1 300 train
+jygjnlgnqd 0 300 val
+jygnpdukjy 1 300 train
+jygzsmacpv 1 302 train
+jyhgclktzs 1 301 train
+jyhnlmolay 1 300 train
+jyhqzzallt 1 300 train
+jyhvnksgox 0 300 val
+jyhwkeqwqe 1 300 train
+jyiahkzrmd 1 300 train
+jyiftmaiht 0 300 train
+jyikynwiwt 1 300 val
+jyimocbzdg 1 300 train
+jyimxshiqz 1 300 val
+jyiojumcst 1 298 train
+jyiokxyphl 0 301 train
+jyitbfnsnk 1 300 train
+jyiuicqojr 1 301 train
+jyivpctrnl 1 300 train
+jyizmybtmi 1 300 train
+jyjggcxkvt 0 300 train
+jyjhibjxnt 1 300 train
+jyjhtumuyt 1 301 train
+jyjjbfhlqg 0 300 train
+jyjmrznbvu 1 300 train
+jyjowsyxhy 1 300 val
+jyjterhfex 1 301 val
+jyjvstkrfn 1 300 train
+jyjyhpvkaz 1 300 val
+jyjzzlvspb 1 300 train
+jykgcdqnqx 1 300 train
+jykrbbnxhw 1 300 train
+jykukvfihb 1 301 val
+jykzklobzn 0 300 train
+jylajrjrfy 1 298 train
+jylbuqloci 1 301 train
+jylcevnnuo 1 300 train
+jylhmcwdfq 0 300 train
+jylozuizhq 1 300 train
+jylqnuaybd 1 300 train
+jylsswchsi 1 300 train
+jyltszlbbq 1 300 val
+jymadinhnm 0 300 train
+jymfjyctip 1 300 val
+jymgnvcbkc 1 300 train
+jymjgpfoqr 1 302 train
+jymmdldqhb 1 300 train
+jymmnlytlx 1 300 train
+jymsxddqhv 1 300 train
+jynjlmsvyj 1 300 train
+jyobchsald 1 300 train
+jyocsnitrl 1 301 train
+jyodymmfmz 1 300 train
+jyokmdpngl 1 300 train
+jyoltmsngg 1 300 train
+jyornxfvbd 1 300 train
+jyosfcmcao 1 300 train
+jyovcnnwsu 1 300 train
+jyoxdvxpza 0 300 test
+jyoylcsgcm 1 301 train
+jyprfzyriq 1 300 train
+jyprlnqdmu 1 300 val
+jyqaqxchbz 1 300 train
+jyqcbvdpnj 1 300 train
+jyqcrcstcu 1 300 train
+jyqhfvddhz 1 300 train
+jyqopbmwnw 1 300 train
+jyqqebjosj 1 300 train
+jyqysuhyjb 1 300 train
+jyrdziqmjv 1 255 train
+jyredvphdl 1 300 val
+jyrhitwyxp 1 300 train
+jyritfmuzo 1 298 train
+jyrnrfpdvl 0 300 val
+jyrqdwxydn 1 302 train
+jyrufiytyy 1 240 val
+jyrvsifszr 1 300 test
+jyrwsqgedx 1 300 train
+jyrxhceptc 1 300 train
+jysalgidzv 1 300 val
+jyscjzagjg 1 300 val
+jyscvvqfoc 1 300 train
+jysdcedlww 0 300 train
+jyseigrfah 1 300 train
+jyshlqahpm 1 300 train
+jysnaviinz 1 298 train
+jysoesutak 1 300 train
+jysqfhizih 1 299 val
+jysrnjyelb 1 300 train
+jysvhvwfke 1 300 train
+jytcvgxzbn 1 300 val
+jytiexqjbl 1 300 train
+jytnikqjci 1 300 train
+jytnqjsozb 1 300 train
+jytobhzwqf 1 300 train
+jytokghrts 1 302 train
+jytpcjdtol 1 300 train
+jytpyhrwho 0 300 train
+jytrvwlewz 0 300 test
+jytyijewbu 1 300 train
+jyuaglvbvv 1 300 train
+jyuaxigvdi 1 300 val
+jyuctyzqsf 1 301 train
+jyugbxoded 1 300 train
+jyuhqauxgp 1 300 train
+jyurhlyzhw 1 300 train
+jyuuhpejkt 1 300 train
+jyuylunlgq 1 300 train
+jyuzlarico 1 300 train
+jyuzscglow 1 300 train
+jyvahtpmxe 1 300 val
+jyvbjopxlv 1 300 train
+jyvfryeqmj 0 300 train
+jyvlalljen 0 300 train
+jyvrnyjaaa 0 300 train
+jyvsqshekv 1 298 train
+jywpnrbxoh 1 300 train
+jywpuepzjv 1 300 train
+jywtxiywti 1 300 train
+jywvvyypwb 1 300 train
+jywvvzoxvl 0 300 val
+jyxbwyvawa 1 301 val
+jyxconjpel 1 300 train
+jyxdpfccde 0 300 train
+jyxiysbcqg 1 300 train
+jyxmpkwbfa 1 300 train
+jyxnmhxmlc 1 300 train
+jyxnvmzhyb 1 298 train
+jyxpxpqmqf 0 300 train
+jyxsngtxxs 0 300 train
+jyxuyxghov 1 300 train
+jyychrjnuo 1 303 train
+jyykmugygy 1 300 val
+jyykwfwywd 1 300 val
+jyylcycvek 1 300 train
+jyyoxieimv 1 300 train
+jyyriqplgm 1 300 train
+jyyvhnsyys 1 300 train
+jyywssuxwr 1 300 val
+jyyxernmsr 1 300 train
+jyyzadtooi 1 300 train
+jyzfnuaujf 1 300 train
+jyzlvivrmr 1 300 train
+jyzncweyld 1 300 train
+jyzpwkchwp 1 300 train
+jyzqwbkizd 0 300 train
+jyzriyujcb 1 300 train
+jyzsdiibiv 1 300 train
+jyzveemewp 1 300 train
+jyzxegmmwv 1 300 train
+jzadfisdnk 1 300 train
+jzaedaoqcm 1 300 train
+jzaedkieix 1 300 train
+jzaenbjuyw 1 300 train
+jzalhnzwpr 1 300 train
+jzaqsfyati 0 300 train
+jzasxgxqom 1 300 val
+jzbcemlvvt 1 300 train
+jzbclihsto 1 300 val
+jzbhqjddmd 1 300 val
+jzboowbluf 1 300 val
+jzbpdfviwd 1 300 train
+jzbrpejxia 1 300 val
+jzbwughver 1 300 train
+jzbxqjnzoi 0 301 train
+jzbzaqzmok 1 300 train
+jzcibqlqxo 1 301 train
+jzcolbuuhw 0 300 train
+jzddtjxvqn 1 300 train
+jzdfcsctdt 1 300 train
+jzdsaqiiut 1 300 train
+jzdyeglvai 1 297 train
+jzegtrfqbn 0 301 train
+jzenzaooip 1 301 val
+jzesseprpx 1 300 train
+jzeuajqgxh 0 300 train
+jzezhadlck 1 300 train
+jzfevdkihp 1 300 train
+jzflqvfwxs 1 241 train
+jzfmnyylqi 1 300 train
+jzfqdskbtk 1 300 val
+jzfywkhfzg 1 300 val
+jzgdlzarhl 1 300 val
+jzgffyhnog 1 300 train
+jzginaohpw 0 300 train
+jzgmnepusu 1 136 train
+jzgslftukh 1 299 test
+jzgsugmdsp 1 288 train
+jzgwompjqh 1 300 train
+jzhacwypqz 1 300 val
+jziabgtzyb 0 300 train
+jzidweqdem 1 299 val
+jziltecjtq 1 300 train
+jzimocxipm 1 300 train
+jzinbxbycg 1 300 train
+jzirtjysqv 1 300 val
+jziucejrzb 1 301 val
+jzivhbafnj 1 300 train
+jzjibrcwkj 0 300 val
+jzjvcjrrfv 1 300 val
+jzkadwicxo 1 300 train
+jzkfaniokb 1 300 train
+jzkfcyqaip 1 300 train
+jzklrkclja 1 241 train
+jzkwdaddjj 1 300 train
+jzlaeruvok 1 240 train
+jzlawtutrh 0 300 train
+jzlfdmhrvo 1 300 train
+jzlkgyrjqc 1 300 train
+jzlkxmpvlw 1 300 train
+jzllaqyqkd 1 298 train
+jzlofhizsp 1 300 val
+jzlxsuevsu 1 300 train
+jzmdcrxxdz 1 300 train
+jzmdganfys 0 300 train
+jzmdzmzxto 1 300 train
+jzmibcxjim 1 300 train
+jzmkfyijbz 1 300 train
+jzmkulogxk 0 300 train
+jzmpcdnmox 1 300 val
+jzmqcigydt 1 300 val
+jzmxmyafls 1 300 train
+jzmzdispyo 0 300 test
+jznbuckvmo 1 300 train
+jzncpilmob 0 300 train
+jzneqofkrp 1 299 test
+jznfteqzjm 1 300 train
+jznfyhhbwv 0 300 train
+jznqrvdmmo 1 300 val
+jznqxvobpx 1 300 train
+jznuqwfhlw 1 300 train
+jznuvvooqv 1 300 train
+jznzhsanqk 1 301 train
+jzofrvnvqa 1 300 train
+jzoiyampqq 1 300 train
+jzooztsozg 1 301 val
+jzoqvqqbji 1 300 val
+jzoxbjscsa 0 300 train
+jzoylwikgm 1 300 val
+jzoyzlgwlc 1 299 test
+jzpaqypejn 1 300 val
+jzpfqoubsx 0 300 train
+jzphdhaqnd 1 300 train
+jzpjazfzvh 1 301 train
+jzpjlfctui 1 300 train
+jzpmdanbau 1 300 val
+jzppkwdtzi 1 300 val
+jzpuawkrbd 1 300 train
+jzqbizbyon 1 300 val
+jzqcswxiej 1 300 train
+jzqikkevpz 1 300 train
+jzqinrpmwb 1 300 train
+jzqjrntfav 1 300 train
+jzqkwqfyvq 1 300 train
+jzqqylacnn 0 302 val
+jzqvbphdqh 1 300 train
+jzqyvqcmar 1 300 val
+jzqyzewqtv 0 300 train
+jzraxqjplq 1 300 train
+jzrbilttsa 1 300 train
+jzrdfehytl 1 300 train
+jzreqcktan 1 300 val
+jzrhoicrbq 1 301 train
+jzrkkfhdqe 1 288 train
+jzrtfzijgd 1 300 train
+jzrxaqsdzr 0 300 train
+jzsdlsaodc 1 300 train
+jzsgopccpe 0 300 train
+jzslgdahcs 1 300 train
+jzsspmufri 1 300 val
+jzsswyycpg 1 300 train
+jztbbimrsr 1 300 val
+jztlxgspbo 1 300 train
+jztmpixlze 1 301 val
+jztxgjbxwo 1 300 train
+jzueqvefwn 1 300 val
+jzuheuhgwi 1 300 train
+jzulcnoifd 1 300 train
+jzupayeuln 0 300 train
+jzupyirlgk 0 300 train
+jzusdqoqhl 1 300 train
+jzutfbfsdk 1 300 train
+jzuvttoidb 1 300 val
+jzuytevkmi 1 299 train
+jzvduwtvod 1 300 train
+jzvflwwjoo 0 300 train
+jzvfskvvoq 1 298 train
+jzvhigkbxt 1 300 train
+jzvkmkoazp 1 298 train
+jzvphhwlqf 1 300 train
+jzvsqkcbxb 1 300 train
+jzvyavgiki 1 300 train
+jzvyysjsdw 0 300 train
+jzwknexchj 1 300 train
+jzwktjagsv 1 300 train
+jzwmxvkgwi 1 300 train
+jzwnkchvee 1 300 val
+jzwolulwzk 1 300 train
+jzwsqyjinh 1 298 train
+jzxjrsafrx 1 299 train
+jzxqjjffrw 1 300 train
+jzxzzmcplq 1 296 val
+jzybgijazv 1 300 train
+jzyejinoju 1 300 train
+jzythvncud 1 300 train
+jzyxcuglcz 1 300 train
+jzyzufsccs 1 300 val
+jzyzvokduk 1 300 train
+jzzbqygsas 1 300 train
+jzzcdlgklg 1 300 val
+jzzcskarto 1 300 train
+jzzlmolwdd 1 301 train
+jzzmtrlnen 1 300 train
+jzzpayejdt 1 300 train
+jzzvmsilyx 1 300 val
+jzzzldndhb 1 300 train
+kaabnhdvdo 1 298 val
+kaadddpkpb 1 300 val
+kaajaxzivt 1 300 train
+kaawkjbtqd 1 300 train
+kaaxaqllth 1 300 train
+kaaypzytle 0 300 train
+kaazjzypen 1 300 train
+kabasifffk 1 300 train
+kabdprnxfw 1 100 train
+kabdtrxlay 1 300 train
+kabgjapmic 1 297 train
+kabkawqwns 0 300 train
+kabnxafzfn 1 300 train
+kabwebwdlm 1 300 train
+kacmdpdchh 1 299 val
+kacmgvthyt 1 301 train
+kacowjtvvm 0 300 train
+kacpwvfkmq 1 301 train
+kacwtblcdu 1 301 val
+kacwynbcsd 1 299 train
+kacxidbjxh 1 300 train
+kadarrfhjj 1 301 train
+kadijizmln 0 300 val
+kadlkyckjz 0 300 train
+kadqadpbkl 1 300 train
+kadzgvxsii 1 300 test
+kaebjlamcq 1 300 train
+kaebqtyefo 0 301 val
+kaeeiiasfw 1 300 train
+kaeouvuasm 1 300 train
+kaeruzxyzz 1 241 train
+kafftwoxxe 1 300 train
+kaffwaiexj 1 300 train
+kaffwemocw 1 300 train
+kaffysxkxg 1 300 train
+kafhxsauou 1 300 train
+kafkryrelj 1 300 train
+kafmsctues 1 300 test
+kafvmqfypt 1 147 train
+kafylrkyjf 1 301 train
+kafzwjrhwj 1 300 train
+kagdaclapf 1 297 train
+kageukvqgp 1 302 train
+kaggpclkjm 1 300 train
+kaghfeyhwl 1 300 train
+kagjmprdwh 1 300 val
+kahfwcnrvj 1 302 train
+kahgcdrbgw 1 300 train
+kahgyhumgh 1 300 train
+kahjemskay 1 300 test
+kahkedgaab 1 300 val
+kahlpbleou 1 301 val
+kahohhqvzu 1 300 train
+kahoiruzzj 1 300 train
+kahoqwrnkr 1 300 train
+kahpzkmodg 0 300 train
+kahyjjcvuw 1 300 train
+kaihuboofk 1 300 train
+kaiiqiwffi 1 300 train
+kaipnxidic 1 300 train
+kaiqdfrwvz 1 300 train
+kaiqljqnnc 1 300 train
+kaiqoaliro 1 300 train
+kajawowzrq 1 300 train
+kajossgmiq 0 300 train
+kajzbtxqdk 1 300 test
+kakbmpfvwg 1 300 train
+kakipwemfn 1 300 val
+kaklqxzcgt 1 300 val
+kakogazsbz 1 300 val
+kakrqvifvu 1 300 train
+kaksbdqbts 1 300 val
+kakxhgfllh 1 298 train
+kakynrjihb 1 301 train
+kakzqfiyil 1 301 train
+kalcoatnnz 1 300 train
+kalfytbmiz 1 300 train
+kalkcrhcau 1 300 train
+kallylxwfm 1 300 train
+kalnudrequ 1 300 train
+kalvfzrewe 1 300 train
+kamabtemwe 1 300 train
+kamanyqgbd 1 300 val
+kamfcfhmnh 0 300 val
+kamgolmamo 1 300 train
+kamjhvfvnh 1 300 train
+kamklnltfn 1 300 val
+kamlcjukto 1 300 train
+kamnathqgi 1 300 val
+kamsnbdcga 1 300 train
+kamudoalqk 1 300 train
+kamuyiutyi 0 300 train
+kamyrxnnld 1 300 train
+kandafymng 1 301 val
+kanfyaxyue 1 300 train
+kangomlkoy 1 300 val
+kanmrbqbwt 1 300 train
+kannyasnok 1 300 train
+kanodwpdss 1 300 train
+kantctjcjx 1 300 val
+kanuhxwqaa 1 300 test
+kanuqtrfoj 0 300 train
+kanxymmtcx 1 300 val
+kanyzlpwgd 1 300 train
+kaoctrhfjj 1 301 train
+kaojqcodsu 1 300 train
+kaokftvufu 0 296 train
+kaolbrodka 1 300 train
+kaoostulnc 1 300 train
+kaoouztuav 1 300 val
+kaosxjmmqo 1 300 val
+kaozdubluo 0 239 train
+kaozthjaxt 1 300 train
+kapylxhvzl 1 300 train
+kapzkxdgqb 0 300 train
+kaqdptlbfx 1 300 train
+kaqecwolil 0 300 train
+kaqhfpmyhp 0 300 train
+kaqicoqmje 1 300 train
+kaqlboezem 1 300 train
+kaqlfhpxoc 1 241 train
+kaqmecjxor 1 300 train
+kaqnldflbz 1 300 train
+kaqwssafgd 1 300 train
+kaqzhclcrc 0 303 train
+kargedhxah 1 300 train
+karlglntmt 1 300 train
+karmdcfptc 1 302 val
+karpwitscp 1 300 train
+karzkohlnx 0 300 train
+kascamuifw 1 301 train
+kasgftjjmu 0 300 train
+kasklrffvn 1 301 train
+kasljoowim 1 300 train
+kasxhsylce 0 300 train
+katagkpjku 1 300 train
+katekmmpel 1 300 train
+katmliewya 1 299 test
+kaubygnbuq 1 301 train
+kaucpxhfhn 1 300 train
+kauinlzojy 0 302 train
+kaulnbxpry 1 239 train
+kaumgzndzt 1 300 train
+kaumwnfhbl 0 300 val
+kaunyejtna 0 300 train
+kaurxqscvh 1 300 train
+kautazuajs 0 300 val
+kautnpexno 1 300 train
+kavcuhjzgx 0 300 train
+kaveeoaarb 1 300 train
+kavfrbqacm 1 300 val
+kavhaaoziw 0 300 train
+kavkmxswhr 1 300 train
+kavmvtmxwr 1 299 val
+kavnxhwdyy 1 300 val
+kavsiqzuqz 0 300 train
+kavtwiaazn 1 300 train
+kawepzbfbe 1 300 train
+kawfkxalfq 1 300 train
+kawgvzzdze 1 300 val
+kawjjcrooq 1 300 val
+kawsiwdbxl 1 300 train
+kawtsuffus 1 300 train
+kawwxiglyt 1 299 train
+kawxnfacqs 0 301 train
+kaxbwjqnxd 1 300 train
+kaxcxbrkdw 1 300 train
+kaxfvwyvqa 1 300 train
+kaxpjejlle 0 300 val
+kaxrdvenvh 1 297 train
+kaxuhvblig 1 300 val
+kaxvkocwkw 1 300 train
+kaxwbzncnb 1 301 train
+kaxyvhnwao 1 300 train
+kaybcrsyni 1 143 train
+kayesdnimi 1 300 train
+kaygmthlsw 1 300 train
+kayhfpxrdf 1 300 train
+kayivkuaci 0 300 train
+kayqwzsqaw 1 300 val
+kayuqgxufc 1 300 val
+kayvxgbwgh 1 300 train
+kayvzxaesv 1 298 train
+kaywvciuyr 1 300 train
+kayycgsxll 1 298 val
+kazdviolwl 1 301 train
+kazeppbfsm 1 300 train
+kazihkzqlt 1 300 val
+kazjfzgayu 1 300 val
+kazmvsfpxt 1 300 train
+kazofjpxmk 0 300 val
+kazwzzbgty 1 300 train
+kbacwigsnp 1 301 train
+kbasdipype 0 300 train
+kbasecegsw 1 300 train
+kbavtiujaq 1 300 train
+kbaxwdpxqm 1 300 val
+kbbewozsdr 1 300 val
+kbbfddbsbe 1 300 train
+kbbhjrtbef 1 301 train
+kbblbjarlp 1 300 train
+kbbsbxfupu 1 301 train
+kbbwzwqbeg 1 300 val
+kbbzwqjxwk 1 300 train
+kbcakqswjc 0 300 train
+kbcdwrffjm 1 300 train
+kbcexfjiwd 1 300 train
+kbcjbiqegs 1 299 test
+kbczekotya 0 300 train
+kbdajrhppw 1 300 val
+kbddtkgnmu 0 300 train
+kbdfvpatrl 1 299 train
+kbdgkojhvh 0 300 val
+kbdjlansnq 1 298 train
+kbdjxocfhl 1 300 train
+kbdtgbianq 1 300 train
+kbdutiybxg 1 300 train
+kbdwpgaurl 1 300 train
+kbdwudhhwf 0 301 train
+kbdwxflsla 0 300 train
+kbeemwsesq 1 300 train
+kbeiszqtnr 1 300 train
+kbemlegrws 0 300 train
+kberplkkzg 0 300 val
+kberujkjfo 0 299 val
+kbffkmwfnn 1 300 train
+kbflhsjelv 1 300 train
+kbfmtujkqg 1 300 val
+kbfnbumdmi 1 299 train
+kbfrznubqd 1 300 train
+kbfvqwizvc 1 300 train
+kbfyhxoygl 0 300 train
+kbfzpyefvi 1 300 train
+kbgbwtiqzn 1 297 train
+kbgdtsrfme 1 299 val
+kbgeaaknlx 1 300 train
+kbgynbpxnx 1 300 val
+kbhbiertfn 1 301 train
+kbhjquptyv 1 300 train
+kbhlvljpre 1 300 train
+kbhqxcdcuf 1 299 test
+kbhwefoxaq 1 301 val
+kbhygaddqy 1 301 train
+kbictfefby 1 300 train
+kbihrvypuy 1 300 train
+kbikjlvsev 1 300 train
+kbinbgcspj 0 301 train
+kbirfevcnc 0 300 train
+kbirhirmkd 1 300 train
+kbistvluxj 1 300 train
+kbisvijdmm 0 300 val
+kbiuvxjulg 1 300 train
+kbixwxubty 1 300 train
+kbiyiwtjed 1 300 train
+kbjaxxlrtz 0 300 val
+kbjjjmaegk 1 300 train
+kbjjpphxxb 0 300 train
+kbjornqlkr 1 300 train
+kbjtcfcbys 1 300 val
+kbjwjdimks 1 300 train
+kbjxogxxbg 1 300 train
+kbjxzyywjv 1 300 train
+kbkelubadc 1 300 train
+kbkhtxptah 0 300 train
+kbkihqvojt 1 300 train
+kbklbmzwyf 1 300 train
+kbklfuwgjb 1 301 train
+kbkmsujeud 1 300 train
+kbknajxism 1 300 train
+kbkrmkhewa 1 300 train
+kbkzbdblsg 1 302 val
+kblapvwrlt 1 300 val
+kblcbhlwdz 1 240 train
+kblhsjjdxf 1 255 train
+kblixhiwxu 1 299 train
+kblrnversn 1 241 train
+kbltforcip 1 300 train
+kblvozydot 1 301 train
+kblzgrqbmm 1 300 train
+kblzndgyqf 1 300 train
+kbmaltbfhv 1 300 train
+kbmbiktzso 1 300 train
+kbmfddppvj 1 302 val
+kbmgigemqq 0 300 train
+kbmpdpujje 1 300 train
+kbmtsbvptr 1 300 train
+kbmwlkfoeh 1 300 val
+kbmyurapjd 1 299 test
+kbmzfvrqep 1 299 test
+kbnafeecfv 1 300 val
+kbnjrdxovx 1 301 train
+kbnjwtifnf 1 298 val
+kbnskaoeyv 1 300 train
+kbnslnfgyi 0 300 val
+kbntqomiww 1 299 test
+kbnuplbbvd 1 300 val
+kbodjivgqu 0 300 train
+kboeatcpkf 1 300 train
+kboezrnkmd 1 300 val
+kboixyviey 1 298 train
+kbotycwffb 0 300 train
+kbovtsruga 1 300 train
+kbowozakwe 1 301 val
+kboxqlwvqm 1 241 train
+kbozphwdpo 1 301 val
+kbpebzzmpt 1 300 train
+kbphkkwrzs 1 301 val
+kbphlwcaxx 1 300 train
+kbphucawml 1 300 test
+kbplevfivn 1 300 train
+kbpqlezqeh 1 301 train
+kbpzwkfndc 1 299 val
+kbqlktsewz 0 300 train
+kbradkklfy 1 300 train
+kbrcioheth 0 300 train
+kbrkvsxcqr 1 300 val
+kbrphwshik 1 300 train
+kbrsrmcggq 1 300 train
+kbrxzshnez 1 300 val
+kbsbjfyhhj 1 300 train
+kbseiesebw 1 300 val
+kbsejqafrz 1 300 val
+kbsjcsrzhd 1 300 val
+kbslojamcc 1 300 train
+kbssbcdcxx 1 300 test
+kbtghkasze 1 300 train
+kbtgialpme 0 300 train
+kbtzjlgmgt 1 300 train
+kbubftoczs 1 300 val
+kbucwslhxt 1 300 train
+kbukwskamw 1 300 train
+kbulxcnrhd 0 300 test
+kbvdscuknm 1 300 train
+kbvfuehabt 1 300 val
+kbvgbomgqb 1 300 train
+kbvibjhfzo 0 300 train
+kbvmfoaibz 0 300 train
+kbvmkdkcad 1 300 train
+kbvodnmjko 1 300 train
+kbvqzihgan 1 300 train
+kbvtyzqqsj 1 300 train
+kbvugdqqsx 1 301 train
+kbvzgiohpz 1 288 train
+kbwjtytuje 1 300 train
+kbwkqtvnze 1 300 train
+kbwlnlehcu 1 300 train
+kbwouxpyxt 1 301 train
+kbwphvfbzp 1 300 train
+kbwquvelaz 1 300 train
+kbwsbhaqyk 1 300 train
+kbwsksjqpy 1 301 val
+kbwtjvcdnt 1 300 val
+kbwwazhpku 1 300 val
+kbwwifmuga 1 300 train
+kbwxzfjrvj 1 300 val
+kbxbmrkdnn 1 300 val
+kbxbrehget 1 300 train
+kbxcexrfck 1 301 val
+kbxdfpfqbg 1 300 train
+kbxdvqucrq 1 301 train
+kbxkmatqoo 1 300 train
+kbxmnovqbo 0 299 val
+kbxpxwyxsh 1 300 val
+kbxqrquqfj 1 300 train
+kbxszafkhv 1 300 train
+kbxxmzmyio 1 300 train
+kbybnvenum 1 300 train
+kbydjhfxhs 1 300 train
+kbygxagetb 1 300 train
+kbyilspmwt 1 300 val
+kbyunqyqtq 1 300 val
+kbyutxvuzr 1 300 test
+kbyvdqbvkk 1 146 train
+kbzbqdvtjd 1 300 train
+kbzkctaeja 0 300 train
+kbzqvekuhb 1 300 val
+kbzvekqwyr 1 299 train
+kbzvjrpuso 1 300 train
+kcaihzgvom 1 300 train
+kcakczhuit 1 300 train
+kcamqjquls 1 300 train
+kcaqoojbyc 1 300 train
+kcawhmjzvb 1 300 val
+kcaxtdqgxe 0 300 train
+kcbdtiafgx 1 301 val
+kcbdyzrxxe 1 300 train
+kcbfqtrnkl 1 300 train
+kcbkctnmfc 1 297 train
+kcbmhtnmds 0 300 train
+kcbolgogbw 1 300 train
+kcbvvaqrbg 1 298 train
+kcbybymbna 0 300 val
+kcbysujhqs 1 300 train
+kccicuhxgk 1 300 train
+kcckvrweqn 1 300 train
+kccmgradon 1 240 val
+kcdbqpoxwg 0 300 train
+kcdfhglxag 1 300 train
+kcdhxbblyr 1 300 train
+kcdiwqvgzv 1 300 train
+kcdlxeiglm 1 300 train
+kcdnfmexts 1 300 val
+kcdtacccpk 1 300 train
+kcdzznagjw 1 300 train
+kceasaqpww 1 300 train
+kceclydxpp 1 300 train
+kcehhyfxjs 1 300 train
+kceifzdxoo 0 300 val
+kcekegxunk 1 300 train
+kcetjgsctj 1 300 train
+kcetnnwqxv 1 300 train
+kcetyroimp 1 300 val
+kcfadogpny 1 300 train
+kcfbaulmcz 1 300 train
+kcfcklczok 1 300 train
+kcfmiobnhd 1 300 train
+kcfoilqmwp 1 300 train
+kcfqfbagfs 1 300 train
+kcfqgqxsgd 1 300 train
+kcftrwqtmx 1 300 train
+kcfvqngurd 1 300 val
+kcfvycrugv 1 300 train
+kcfwyjxykj 1 300 train
+kcfwyumtut 1 300 train
+kcgcufurur 1 300 val
+kcgjixienn 1 300 train
+kcgsaikxui 1 300 train
+kcheihsxpq 1 300 val
+kchjolzjnr 1 298 train
+kchknmhqfx 1 300 train
+kchrvflpuz 1 241 train
+kchtotcgjz 1 300 train
+kchvyrhtwc 1 300 train
+kcidxranvr 1 300 test
+kcifrwuwih 1 300 train
+kcigedckrv 1 300 train
+kciiyjnttg 1 300 train
+kcilnbsztf 1 301 train
+kcimtztanq 1 300 train
+kciudzjdwb 1 299 test
+kcjamjqazk 1 300 train
+kcjhyfrbqe 1 300 train
+kcjkwhtwyk 1 249 train
+kcjoabiyri 1 300 val
+kcjtllkoer 1 300 train
+kcjvhgvhpt 1 300 test
+kckgjydcal 1 288 train
+kckraglzka 1 300 train
+kckrasewbz 1 300 val
+kcktvlwrez 1 300 train
+kckxroxhnz 1 301 val
+kclfhzfwpn 0 301 val
+kclflittyf 0 300 val
+kclonizmyq 0 300 train
+kclssddmrf 1 297 train
+kclwzbwsrv 1 300 train
+kcmbhgeksj 1 300 train
+kcmcojwvhp 1 301 train
+kcmcvvjaad 1 303 train
+kcmfhutzsw 1 240 train
+kcmgivcdcf 1 300 train
+kcmgynzgiq 1 300 val
+kcmqbjiriy 1 301 val
+kcmuqrevji 1 300 train
+kcmwlrnuka 1 300 train
+kcnhdbkqbo 1 300 train
+kcnheferep 1 300 train
+kcnjrrohtz 1 301 val
+kcnlwkzdln 1 300 val
+kcnrjfnbov 1 300 train
+kcnstrdbqa 1 300 train
+kcnuykktzr 1 300 train
+kcnwntsgja 1 300 train
+kcodekuokm 1 300 train
+kcoedzdmjj 1 301 val
+kcofyffhkx 1 300 train
+kcolstjuit 1 292 val
+kcoyyopziw 1 300 val
+kcpamicxjs 1 300 train
+kcpdwxdxml 1 300 train
+kcpekahuma 1 300 train
+kcpgfopqdm 1 300 val
+kcpnbervto 1 300 val
+kcpnjysnwy 0 300 train
+kcpocdehkq 0 300 val
+kcppcpzonz 1 302 train
+kcpxpvdkzg 1 300 train
+kcqaptvzmv 1 300 train
+kcqdhhikmh 1 300 train
+kcqlyaqejj 1 269 train
+kcqrjdhivx 0 300 train
+kcqsaktscl 1 300 train
+kcqwljhcqm 1 301 val
+kcqxkdwdjv 1 241 train
+kcqydiwhsp 1 300 train
+kcrltxjhaj 1 300 train
+kcrnhzdeln 1 300 train
+kcrnyvhcys 1 300 train
+kcrqcqcbmn 1 300 train
+kcrvcexazv 1 301 train
+kcsapjroqa 1 300 train
+kcsihhaviw 1 300 val
+kcslsetuzb 1 302 val
+kcsnjielft 0 300 train
+kcspioxxig 1 301 train
+kcsthllhbl 1 300 train
+kcsyhhywnp 1 298 train
+kcthyxljua 1 300 train
+kctirmugzw 1 299 val
+kctjlickdj 1 300 val
+kctknracre 1 300 train
+kctomyqhrb 1 301 val
+kctopjjkey 1 300 train
+kctoyjtard 1 300 val
+kcttjzytpa 1 300 train
+kctujahgsd 0 300 val
+kctzlwxrnn 1 300 train
+kcurhrizjt 1 300 train
+kcusmosymx 0 300 train
+kcutxbbrir 0 300 train
+kcuujslbmx 1 300 train
+kcuuowwupx 1 300 train
+kcuyyfpyku 1 301 train
+kcuzwukqsg 1 301 train
+kcvcnixrim 1 300 train
+kcvnosymrw 1 300 train
+kcvqzukrpu 1 297 val
+kcvrckcpba 0 300 train
+kcvtahsomj 1 300 train
+kcvtrsoksi 1 300 train
+kcweqaagpd 1 300 val
+kcwhikniym 1 300 train
+kcwhynkmlr 1 240 train
+kcwrqqzvsy 0 300 train
+kcwsvbnjmr 1 301 val
+kcwsyzjwfw 1 241 train
+kcwtihguek 0 300 train
+kcwwoqsivh 1 300 train
+kcxanahahl 1 300 val
+kcxbsmglir 1 300 train
+kcxccsjzus 1 300 train
+kcxeujjbyr 1 300 train
+kcxivnufkm 1 300 train
+kcxlqftnzn 1 300 val
+kcxlshjctd 1 300 val
+kcxmndytpm 1 300 val
+kcxnlszise 0 300 train
+kcxpnsyobj 1 300 train
+kcxsdadcuh 1 300 train
+kcxzhcdxkz 1 300 train
+kcxziwytym 1 300 train
+kcycpmprzr 1 301 train
+kcyfvtvjlv 1 300 train
+kcyhizsupj 1 300 train
+kcynaaxbve 1 300 train
+kcysdllhsl 1 300 train
+kcytvtqjsg 1 300 val
+kcyvhkclqv 1 300 train
+kczbhztwmg 1 300 val
+kczfyszzee 1 300 train
+kczkcbxjpc 1 300 train
+kczkjyntbx 0 300 train
+kczovqojew 1 299 test
+kczoxdjadr 1 300 train
+kczsafjstw 1 299 val
+kcztklrmkz 1 300 val
+kczzbcmiws 1 301 val
+kczzchcsrk 0 301 val
+kczzcmgbsf 1 300 train
+kdabfjuzqo 1 300 train
+kdahrgbary 1 300 train
+kdakjqybdp 1 300 train
+kdaokqysaw 1 300 val
+kdaopdnhbv 0 300 train
+kdarkzfezn 1 300 train
+kdbbvuxnze 1 302 train
+kdbdrgkkve 1 300 val
+kdbfuhmqgu 1 300 train
+kdbkemnotp 0 300 train
+kdbmrgjgnk 1 300 train
+kdbnvdnmjw 1 241 train
+kdbpyrjrmp 1 300 train
+kdbvbybhvz 0 296 train
+kdbvhudies 0 300 train
+kdcfilawue 1 300 train
+kdchudzrie 0 300 val
+kdcmnzjbzk 0 300 train
+kdcshrgdcw 0 300 train
+kdctuhvecr 1 300 train
+kdcxfjrrbt 0 300 train
+kdczsnkgeg 1 300 train
+kddaaifoyz 1 300 train
+kddednywlm 1 300 train
+kddggwajii 0 300 train
+kddjcesyqm 1 300 train
+kddkkjwyid 1 300 train
+kddkkkxftt 1 300 train
+kddooggusu 1 300 train
+kddrzelzce 1 300 train
+kddskbgbib 1 300 train
+kddstczrwt 1 300 train
+kdefnrodrw 0 300 train
+kdejmhyywb 0 241 train
+kdejuwcarc 1 300 train
+kdeknkwyza 1 300 train
+kdeyosbkqv 1 300 train
+kdfdgmedoc 1 300 train
+kdffomdlxw 1 300 train
+kdfocjnlnw 1 300 train
+kdfsgweyqa 0 300 val
+kdfyjxvxva 1 300 train
+kdgqkztgci 0 300 train
+kdgqrczsax 1 300 train
+kdgttslitt 0 300 train
+kdhdcxbeti 1 300 test
+kdhfvtnpik 0 300 val
+kdhkpacnfx 1 300 test
+kdhnahabuw 1 300 train
+kdibleqjbx 1 300 train
+kdidjwenrq 1 300 train
+kdigpctszt 1 300 train
+kdijwsmjnc 1 300 train
+kdilzzhjks 1 302 train
+kdioikogxu 1 300 train
+kdiokpezzi 1 300 test
+kdiooiibof 1 300 train
+kdiszetioa 0 300 train
+kditexxqgl 1 300 val
+kdiucqdkus 1 300 train
+kdixbdmucw 1 300 train
+kdiyvrgkzz 1 301 train
+kdiztayhmn 1 300 train
+kdjfdesctw 1 300 val
+kdjnblxrad 1 300 train
+kdjnrcuomk 1 300 val
+kdjqeizaaq 1 300 train
+kdjqtxsfqi 1 300 train
+kdjsvneqgy 0 301 train
+kdjtauqdjd 1 302 train
+kdjvajxkpm 1 300 val
+kdjwatykhg 1 300 val
+kdkbppzzmc 1 300 train
+kdkdralkpe 1 300 train
+kdkffgmbfu 1 300 train
+kdkmpiwome 1 300 train
+kdkpduclks 1 300 train
+kdktifamhl 1 300 train
+kdkxgnmuey 1 301 val
+kdlerbketd 1 300 val
+kdlhoknlks 1 300 train
+kdluiyjesi 1 300 train
+kdlzgmfvec 1 300 train
+kdmnqxfbkz 0 300 train
+kdmonvkpqd 0 300 train
+kdmqpwsorv 1 301 val
+kdmrcstvje 1 300 train
+kdmsrxsjxo 1 300 train
+kdmuuxmmpp 1 300 train
+kdnaffzofo 1 300 train
+kdnehmzkla 1 297 train
+kdngmqjtlk 1 300 train
+kdnhgzxapl 1 300 val
+kdnhxkjeic 1 301 val
+kdnkskzbbo 1 300 train
+kdnkurbkjq 1 300 val
+kdnmdusclb 1 299 test
+kdnopngcya 1 301 train
+kdnrkbjjql 1 300 train
+kdnurosway 1 300 train
+kdnuutharo 1 136 train
+kdnvfpobng 0 300 train
+kdnwqamydh 0 300 val
+kdoauauyxg 1 299 val
+kdocutvxrv 0 300 val
+kdodakdubt 1 300 train
+kdodrvufdh 0 300 train
+kdondlgdus 1 300 val
+kdonzcbasj 1 300 train
+kdownrfwmf 1 300 val
+kdowsulnwf 0 300 train
+kdpgbzsjso 1 300 val
+kdpplkdctb 0 300 train
+kdpwpdrdoh 1 300 val
+kdpxsoquog 1 300 val
+kdpymatjtr 1 300 train
+kdpzibspoe 1 300 train
+kdqcobuktr 1 300 train
+kdqesvetah 1 300 train
+kdqgcnowmr 0 300 train
+kdqkabofmc 1 301 train
+kdqklsmubp 1 300 train
+kdqneekply 0 300 train
+kdqocheoyz 1 298 train
+kdqspjqjdh 1 300 train
+kdqtkmiluz 1 300 val
+kdqzoccsmv 1 300 train
+kdrflluxxq 1 299 train
+kdribwofxg 1 299 test
+kdringxdit 1 300 train
+kdrjycvkdv 1 300 test
+kdrmdjcktg 1 300 train
+kdrxbnkjvm 1 300 train
+kdsebdrkyx 1 299 test
+kdsjgthtiq 1 300 train
+kdsultamxv 1 300 train
+kdswzohjqj 1 300 train
+kdtativvgb 1 300 train
+kdtbxvoslf 1 300 train
+kdtigewgth 0 300 train
+kdtivinvct 1 300 train
+kdtljdgumq 1 299 train
+kdtmaaicxd 1 300 train
+kdtryycxhy 1 300 train
+kdtuzdtudj 1 300 train
+kdtwbjzpgl 1 300 train
+kdtyloixap 1 300 train
+kdtzkywmke 1 300 train
+kduobgihuy 1 300 train
+kdupthdnas 1 300 train
+kduvumcynw 1 300 train
+kduxeqhwcx 1 300 train
+kduyknkfnw 1 300 train
+kdvcexakou 0 296 val
+kdvfdktarb 1 300 train
+kdvhhotnej 1 300 train
+kdvlxetdkt 0 300 val
+kdvxfhdjeo 0 300 train
+kdvzjnknxq 0 300 val
+kdwmfiatqd 1 300 train
+kdwndylhph 1 300 train
+kdwsdpqhna 0 301 train
+kdwvkknasn 0 300 train
+kdwylpqkqb 0 300 train
+kdwzrljwgf 1 300 train
+kdxibxbcxi 1 241 train
+kdxjncawfy 0 300 train
+kdxksxnhko 1 300 train
+kdxtrmaooh 1 300 train
+kdxwvysven 1 301 train
+kdyarrovgo 1 300 train
+kdycxkmnnw 1 300 test
+kdycydbfqm 1 300 val
+kdygeqbkra 1 300 train
+kdymlwwuyq 1 300 train
+kdymzqobxr 0 300 val
+kdyoaduumf 1 300 train
+kdysptqukx 0 300 train
+kdywawfmfe 1 300 train
+kdzamqkwyu 0 300 val
+kdzawbgzwb 0 300 train
+kdzgixdzce 1 300 train
+kdzihtzpkr 0 300 val
+kdzirwrnyk 1 300 train
+kdzmljkfex 1 301 val
+kdzsbiugrv 1 300 train
+keafxnhakm 1 300 train
+keagcyyswz 1 300 train
+keajbbcwio 0 300 train
+keanvlkgyk 1 136 train
+keavvdjqzg 1 300 val
+keawblilph 1 300 train
+keaxvgnpgl 1 300 train
+keazrmtzuw 1 301 train
+kebacxytud 1 300 train
+kebedcylrq 0 301 val
+kebhwraavx 1 300 train
+kebnusolat 1 300 train
+kebojjpbmu 1 300 train
+kebosyahzk 1 300 train
+kebsibtnuz 1 300 train
+kebxfgzmsj 1 300 val
+keckgmvewj 1 300 train
+kecmqvnqeh 1 300 train
+kecpjuvcti 0 298 train
+kecqrmuimo 1 300 train
+kedahvzait 1 300 test
+kedakiyggh 1 300 train
+kedazlhndc 1 300 train
+kedbwxonlk 1 300 train
+keddthzqkd 0 300 train
+kedpjacqca 1 300 val
+kedpnhcayw 1 300 train
+kedsiilhqw 1 255 train
+keecvpbncd 0 300 train
+keesntetwj 1 300 train
+keezrezept 1 300 train
+keffmeugkx 1 300 train
+kefilxjbhg 1 300 train
+kefotfmfwf 0 300 train
+kefqnjazvl 1 300 train
+kefrpktrjt 1 300 train
+kefxfaenlq 1 300 val
+kegcgoewsj 1 302 train
+kegebtrzqi 0 300 train
+kegfwspupv 1 301 train
+keggddidhg 1 301 train
+keghmutlan 1 300 val
+keghwpstzb 1 240 val
+kegrvfoujv 1 301 train
+kehdwajyvn 1 300 train
+kehipjcriz 1 300 train
+kehjcejgbs 1 296 train
+kehjzihtfv 1 300 train
+kehpbkzvue 0 300 val
+kehrsvkzgc 1 300 train
+kehxabezoe 1 300 test
+kehyerywza 1 300 val
+kehyspyxep 1 300 train
+keibvghazb 1 300 train
+keiiwtehzc 0 300 train
+keikgjgled 0 300 train
+keioymnobc 0 300 test
+keiryedmne 1 301 val
+keiztwhmch 1 300 train
+kejlkfjvaf 1 300 train
+kejqgshrnk 1 300 val
+kejretnuys 0 300 train
+kejsddbcfh 1 300 train
+kejuxgkuqj 1 240 train
+kejwthcfcc 1 300 train
+kejyacmwic 1 300 train
+kekcewiqhl 1 299 val
+kekigsssia 1 300 train
+kekissxbow 1 300 train
+kekkrrvpwi 1 300 val
+keknvxogcs 1 300 train
+keknwckzgy 1 300 train
+kekqnsvpwn 1 301 val
+kekscwpfqa 0 300 train
+keksyaghxu 1 241 train
+kekvzxzftb 1 300 train
+kekwrolpae 1 300 train
+kekyviyhwh 1 300 val
+kekzhipmqc 1 300 train
+kelbhtsayy 1 300 val
+kelgughqjl 1 300 train
+kelhpwdpde 1 300 train
+kelowksbeq 1 300 train
+kelpuvljgc 1 300 train
+kelqcenkel 1 300 train
+kelrajsiwk 1 300 train
+keltutgxut 1 300 train
+kelwafpvza 1 300 train
+kelwjtaalp 1 301 train
+kemappvqpu 1 300 train
+kembqzwnci 1 300 val
+kemhiqtxyi 1 300 train
+kemjyynuvp 1 240 val
+kemkgrgbnm 1 300 train
+kemoqtisql 1 300 train
+kemqkamxkq 1 300 train
+kemrbncqkr 1 300 train
+kemtbmrfkf 1 300 test
+kemvhruqqm 1 300 val
+kemvqjfhel 0 300 train
+kenjywouix 1 301 train
+kennocbson 1 299 val
+kenygufisj 1 300 train
+keojyllpcl 1 300 train
+keoqpwuogz 1 299 train
+keorvtcykj 1 300 train
+keosevgnsa 0 298 train
+keoubasyjf 1 300 val
+keouswdypi 1 299 val
+keowcpkxdg 1 300 train
+keowsejphr 0 300 train
+keoycltjdq 0 300 train
+kepibsjkns 1 300 train
+kepkoldynk 1 300 train
+kepnpratvf 0 300 val
+kepsurvxfc 1 300 train
+kepynrnjtg 1 300 val
+keqgbttoxn 1 300 train
+keqhacfqtj 0 269 train
+keqnrncuxe 1 300 train
+keqojddgfa 0 300 train
+keqzympksz 1 300 train
+kerhzoiiii 1 300 train
+kerjpypfxv 1 300 train
+kernyrgjym 1 300 val
+keroikrtca 1 300 train
+kerpokjmkf 0 300 train
+kerqjkysdq 1 300 train
+kertrqjmkx 1 297 train
+kesclicujq 1 302 train
+kesgerqzsb 1 300 train
+keshjzahqd 1 300 train
+kespzwdtyw 1 300 train
+kesvuffxiz 1 300 train
+keswwamyir 1 300 train
+ketamuinxn 0 300 train
+ketdqutnsp 0 302 train
+ketdztjdfu 1 300 train
+ketybyrzmd 0 300 train
+ketzwlufzw 0 300 val
+keucpwebpn 1 300 train
+keufqpkxbk 1 300 train
+keulftbtiy 1 241 train
+keunxijtsh 1 300 train
+keuocbzlxc 1 300 train
+keupjykkdg 1 300 train
+keuvybqsbr 1 300 val
+keuyfcoetv 1 300 train
+keuyosbbdn 1 300 val
+keuyvolsmv 1 300 val
+keuzdsejqj 1 300 train
+keuzhkpoga 1 302 train
+keuzwwwvja 1 300 train
+kevbkpfmib 1 300 train
+kevdmmixhz 1 300 train
+kevdysuura 1 300 train
+kevjzltkuc 1 300 train
+kevklcbpvi 0 241 train
+kevojywljd 1 288 train
+kevqpidfmu 1 300 train
+kevsapqqel 1 300 train
+kevycxuwvd 1 298 train
+kewcrafasg 1 299 test
+kewhahqurl 1 300 train
+kewjgfclxa 0 300 train
+kewjtdgmtz 1 300 train
+kewntarldr 1 300 train
+kewoyefvnw 0 300 val
+kewxgjjwts 0 300 train
+kewxtyiztg 0 300 train
+kexbtwwmuj 1 300 train
+kexnskzmjs 1 302 train
+kexoofvjyz 0 300 val
+kexppkhfzf 1 300 train
+kexqutzaja 1 298 train
+kexwadwqsn 1 300 train
+keycrypyil 0 300 train
+keyifhdmur 1 300 val
+keyiratboy 1 300 val
+keymvwytgn 1 300 train
+keyngrgpvp 0 300 val
+keytazvtbq 1 300 val
+keyvdefmvl 1 301 train
+keyxjvtgsw 1 300 val
+kezelmkykv 1 300 train
+kezexkagoa 0 300 val
+kezfzeblfg 1 300 train
+kezjvfspat 1 300 train
+kezlksyprh 1 300 train
+kezobyclef 1 300 train
+kezpaqosyh 1 299 val
+kezrmmzmoz 1 300 train
+kezvvweubg 1 300 val
+kezwgkvssn 1 300 train
+kezwvsxxzj 0 300 test
+kezzqtfohk 0 300 val
+kfakmxsoxc 1 300 train
+kfakttjekk 1 298 train
+kfatfrlhtq 1 300 train
+kfayptluft 1 299 val
+kfbaclhmlh 1 300 train
+kfbdnasciu 1 300 test
+kfbgdwovuj 1 300 val
+kfbgmfmymf 1 300 train
+kfbqypuqjz 1 300 train
+kfbuactypx 1 301 train
+kfcmbxycol 1 300 train
+kfcoqeubef 1 300 train
+kfcpbwsbqd 1 300 train
+kfcxihahhx 0 300 train
+kfdfoyueqc 1 301 train
+kfdgkmkwsc 0 300 train
+kfdiwiymyk 0 240 train
+kfdubsaups 1 300 train
+kfeajzzucv 1 300 train
+kfeiazhdxk 1 300 val
+kfekgfhthe 1 300 train
+kfekxkjcro 1 300 train
+kfeqbcyjct 1 300 val
+kfeyesogyn 1 300 train
+kffblwjwzt 1 301 val
+kfffndzywe 1 301 train
+kfffrnrxkz 1 300 train
+kffgnnehka 1 300 train
+kffoisceba 1 296 val
+kffomciavo 1 300 train
+kfftmeidws 1 300 train
+kffumfasnn 1 300 train
+kffwdagndv 0 300 train
+kfgcbjjklh 0 302 train
+kfgcktdsul 1 300 val
+kfgdvqjuzu 1 300 val
+kfgiedvwxz 1 296 train
+kfgizruzpf 1 300 train
+kfgliptdpl 1 300 train
+kfgnydkvul 1 300 val
+kfgouegxgv 1 300 train
+kfgsqjstds 1 300 train
+kfgvdrdejn 1 300 train
+kfhdsjswbp 1 299 test
+kfhehvvtrq 1 300 train
+kfhfeqpdwp 0 300 train
+kfhflkhmiy 1 300 train
+kfhfqmbynz 1 300 train
+kfhjdrkhgj 1 300 train
+kfhkiliqpz 1 300 train
+kfhkmcvwvd 0 300 val
+kfhmdeltlt 1 300 train
+kfhmhoxjtx 1 300 test
+kfhnmyyobm 1 300 train
+kfhvmvyztj 1 300 train
+kficyqkhjg 1 300 train
+kfihjlyzlv 0 300 train
+kfiivhmpsy 1 300 train
+kfijhlxurb 1 300 train
+kfioqgxmar 0 300 train
+kfiszsbzob 1 300 val
+kfiwqymccy 1 300 train
+kfjalioqsz 1 300 test
+kfjfieodni 1 300 train
+kfjghnethd 1 301 val
+kfjoofxjnn 1 300 train
+kfjzlimqpo 1 300 train
+kfkbirostv 1 299 train
+kfkitzzrym 0 300 train
+kfkpofaxrh 1 298 train
+kfktclygxc 1 300 val
+kfkvhiauvi 1 300 val
+kfkzdxhpjo 1 300 train
+kfllvviuwm 1 300 train
+kflonpuswr 0 249 train
+kflorzgkqi 1 300 train
+kflrkksfkc 1 300 train
+kflseijemd 1 300 train
+kflwfiafix 1 300 train
+kflwminmxs 0 300 train
+kfmbuztorx 1 300 train
+kfmpsrzlzp 1 298 train
+kfmqlqcqks 1 300 train
+kfmtdqndxt 1 300 train
+kfmucuxvhe 1 300 train
+kfneqlosgg 1 300 train
+kfngjylqax 1 300 train
+kfnjscqwpr 1 300 train
+kfnkllhzov 1 300 train
+kfnkpgpzwy 1 300 train
+kfnmqommrr 1 298 val
+kfnrvxndoj 1 300 test
+kfntnvnzph 0 300 val
+kfntzsnaeu 0 301 train
+kfntztgxzm 1 299 test
+kfocfvurhp 0 300 train
+kfociglqlh 1 300 train
+kfojppnupm 0 300 train
+kfolefcbce 0 298 train
+kfonieobru 1 300 train
+kfooogqbym 1 300 train
+kfounuanuu 1 300 train
+kfozfzfzra 0 300 train
+kfpnunsimt 1 301 train
+kfpompgyje 1 300 train
+kfpooalfvo 1 300 train
+kfpowzvsem 1 300 train
+kfptadhure 1 300 train
+kfpxdluxsv 1 301 train
+kfpylyykva 1 300 train
+kfqmqbmsjf 1 240 val
+kfqoigflcg 0 300 train
+kfqpqimlhv 1 300 train
+kfqragdykf 0 301 train
+kfqtsqutmg 1 300 train
+kfqvqklplx 1 242 train
+kfqymoepjy 1 300 train
+kfratfjmxj 1 300 val
+kfrcpyjluj 1 300 train
+kfrnxbiebb 1 300 val
+kfroajeyzh 1 300 train
+kfrtfdxing 1 300 train
+kfrtvfahle 1 300 train
+kfrwwomubw 1 300 train
+kfrxwzmydn 1 300 train
+kfsbwsbzmu 1 302 train
+kfsfhggbfo 1 300 train
+kfsstlbmru 1 300 train
+kfstkxzkhq 1 300 val
+kfsubdugwr 0 300 train
+kfsulvfizj 1 298 train
+kftpsubgie 0 300 val
+kftrvgwepy 1 300 train
+kftylachac 1 300 train
+kfucsdebdl 1 299 val
+kfuflhqnpj 1 300 train
+kfufwbprvy 1 300 train
+kfuhunxnno 1 300 train
+kfuintgalj 1 300 train
+kfuixpgwth 1 241 train
+kfuvmvhrhy 1 300 train
+kfuyegklzi 1 300 val
+kfviyuzifl 1 301 train
+kfvjbounxn 1 298 val
+kfvqbdvjvb 0 300 train
+kfvrfwbahh 1 300 train
+kfvvshqgyw 1 300 train
+kfvyomcqkz 1 300 train
+kfvywsdmaa 1 300 train
+kfvzdyhrhl 1 300 train
+kfwgtbrjlx 1 300 train
+kfwgzwepuk 1 300 train
+kfwhclywec 1 301 train
+kfwikyxkbj 1 300 train
+kfwoggnhrh 0 300 val
+kfwsdjhqku 1 301 train
+kfwtdyladi 1 298 train
+kfwtokkzqr 1 300 train
+kfwvriaadr 1 300 val
+kfxbhftgld 0 300 train
+kfxcrxdtvy 1 300 train
+kfxemywbfk 1 300 train
+kfxetzkzsh 1 300 train
+kfxgedybnb 1 300 train
+kfxhvujcjz 0 300 train
+kfxixntrak 1 300 train
+kfxsfnhdre 1 300 train
+kfxznfbikz 1 300 train
+kfxzxzjpmw 1 300 train
+kfyaydcwjc 1 300 train
+kfyfoyvitx 1 300 train
+kfygoedobk 1 300 train
+kfyjyegbeh 1 300 train
+kfykpvnplm 1 300 val
+kfynfjcydf 1 300 train
+kfyoqyhfzd 1 241 train
+kfypfuydhp 1 300 train
+kfytzhsdkk 1 300 train
+kfyvyoejjz 1 300 val
+kfywgjbkdg 0 300 val
+kfyyzmhmit 1 300 train
+kfyzmggrsu 1 300 train
+kfyzwqkovu 1 300 train
+kfzgxyeiug 1 301 train
+kfzjvhbvpz 1 298 train
+kfzohivjbx 1 241 train
+kfzpdnsgks 1 300 train
+kfzqutsbgb 1 300 train
+kfzsrfmahx 1 300 train
+kfztdvoaym 1 300 train
+kfzuekxbbb 0 300 train
+kfzvossczm 1 300 val
+kfzxrsyzyi 0 300 train
+kgacawfyvy 0 300 val
+kgadktigbv 1 300 val
+kgaelpgbac 1 300 train
+kgafyxvlhz 0 298 val
+kgamulnbhn 0 300 train
+kgankggyry 0 300 train
+kgavkpwkkl 1 300 train
+kgaxonmgpn 1 300 val
+kgbeujsnix 1 300 train
+kgbkktcjxf 0 300 train
+kgbmcfqqqs 1 300 train
+kgbxvoxsjv 1 300 train
+kgcbejdwal 1 300 train
+kgccdnzmrc 1 300 train
+kgcejveukx 1 300 train
+kgcgjpamca 1 300 train
+kgckxrwwut 0 300 val
+kgcllsmaai 0 300 train
+kgcndoyouu 1 300 val
+kgcofaixqq 1 300 train
+kgcsutjzzd 1 300 train
+kgcuoolvun 1 300 train
+kgcwjuoeud 1 300 train
+kgcxjjxaxx 1 300 train
+kgczfxvqzq 0 300 train
+kgczixcdod 1 300 val
+kgddgxunxz 1 300 train
+kgdinuaubo 0 300 train
+kgdvgipvae 0 300 test
+kgedavcuvc 1 300 train
+kgeeivvuhe 1 300 train
+kgeixehmwu 1 300 train
+kgejshrtmz 1 300 train
+kgepgiucac 1 300 train
+kgewzwihli 1 300 train
+kgezzhuuko 1 300 train
+kgfaubjulw 0 300 train
+kgfcnradwq 0 300 train
+kgfcupxgur 1 300 test
+kgfituyvju 1 300 train
+kgfjkhfhvg 1 300 test
+kgfjnhcjju 1 300 train
+kgfjzwezku 1 300 train
+kgfrpsuxkq 1 300 train
+kgfwdablxa 1 300 train
+kggbciadwj 0 301 train
+kggcytfhaf 1 296 train
+kggwjwiyyx 1 300 val
+kggzchuqlq 1 300 train
+kghbmythwp 1 301 train
+kghcxtmytq 1 300 val
+kghdooheux 1 300 train
+kghjluhoxn 0 300 train
+kghkqfixcl 1 300 train
+kghoowqtiw 1 300 train
+kghvqllikj 1 300 train
+kghyuuthoa 1 302 train
+kghzdckyyc 1 300 train
+kgiaxegsex 1 300 val
+kgibnyexrr 1 300 val
+kgidhklpgb 1 300 train
+kgijbehbxm 1 300 train
+kgirhdnwgb 1 300 train
+kgjdgttzbb 1 300 train
+kgjdzgczjz 1 300 val
+kgjxdfpbvp 1 300 train
+kgkacwnjlr 0 300 train
+kgkaumsdna 1 300 train
+kgkbbtizfo 1 300 train
+kgkdmbdhgw 1 301 train
+kgkpukplcu 1 300 train
+kglbnkwynx 0 300 train
+kgldeywydb 1 300 train
+kgldphztpa 1 300 val
+kglgdgrtzt 1 300 train
+kgljekkgyx 1 300 val
+kglksmojqu 1 300 train
+kglmiyagka 1 300 val
+kglorexrch 1 300 train
+kglvjkrpio 1 300 train
+kglwnrneil 1 300 train
+kgmaobkbdu 1 300 val
+kgmbyyyuwx 1 300 val
+kgmdkfgkkb 1 300 train
+kgmjrrlbkp 1 298 train
+kgmostqiwb 1 299 val
+kgmqjplqkn 0 300 train
+kgmvqxkmkq 0 300 train
+kgmxrcsccw 1 300 val
+kgmyrpdxne 1 301 val
+kgneqqpciu 1 300 val
+kgnggknxoq 1 300 train
+kgniiohowv 1 298 train
+kgnlqeqkpy 1 301 train
+kgnlyovxsj 1 300 train
+kgnqswkxkx 1 300 train
+kgnsknhola 1 300 train
+kgnsvfdqfs 1 300 train
+kgntrnptxj 1 300 train
+kgnyfafbul 1 300 val
+kgobofayxb 1 300 train
+kgonuqaxgg 1 300 val
+kgophcfvac 1 300 val
+kgotoprpim 1 300 train
+kgovnmvhal 0 300 train
+kgowzoxjfq 1 300 train
+kgpaxrtobr 1 300 val
+kgpbxglcrl 1 300 val
+kgpibfbwhy 1 299 test
+kgposxeaju 1 300 train
+kgpuzwmsgw 0 300 train
+kgpyrwhtba 1 300 train
+kgqaexrpas 0 300 train
+kgqehcadhi 1 300 val
+kgqhcsmhri 1 300 train
+kgqismprab 1 300 train
+kgqkeovzny 1 300 train
+kgqnhbbwlw 0 300 train
+kgqoelgizx 1 300 train
+kgqqvvfbgn 1 300 val
+kgqsghywpz 1 300 val
+kgqxhnyvfx 1 300 train
+kgrakuskwl 1 241 val
+kgrdhsqvhl 1 300 train
+kgrhopnsar 1 300 val
+kgrlfqhkji 1 300 val
+kgrnovymch 1 298 train
+kgrnzjimiw 0 300 train
+kgrsrskuqd 1 300 val
+kgruikspbz 0 300 val
+kgrzmwmlkq 1 300 train
+kgsaofsayk 0 300 train
+kgsfkfdltq 1 300 train
+kgsgnwoahd 1 300 train
+kgsidhuspz 1 300 train
+kgskceihsg 1 301 val
+kgsnfjekwa 0 297 train
+kgsrscgjia 1 300 train
+kgsszrmscq 1 300 train
+kgstnooggv 1 300 train
+kgsvfqpmvq 1 300 val
+kgtbhqxjqb 0 300 train
+kgtgcvefcm 1 300 train
+kgtifwsogv 1 300 val
+kgtrqmtmfc 1 300 train
+kgtsvifroa 1 300 train
+kgtyiuehxe 1 300 train
+kguaqibgvg 1 299 test
+kgubvuwnso 1 300 train
+kguffaizuu 1 300 train
+kguvjazjus 1 300 train
+kguvswpwxq 1 301 train
+kguyxqaikd 1 300 val
+kguzqxckys 0 300 train
+kgvajhgttb 1 300 train
+kgvcuqddty 1 301 train
+kgvgauikxu 1 300 train
+kgvknrfbfm 1 300 train
+kgvtpnauwc 1 301 train
+kgwgafevnk 1 300 val
+kgwgifzknm 1 300 train
+kgwlpdleai 1 300 train
+kgwoxikjna 1 300 train
+kgwuynmxig 1 300 train
+kgwvstiibd 1 300 train
+kgwvvwfhuu 1 300 train
+kgwwlghmpp 1 300 train
+kgwxyscpus 1 300 train
+kgxlhqystd 1 300 train
+kgxtuawffm 1 300 val
+kgxyoaowsl 1 301 train
+kgxzlkkpkx 1 300 train
+kgyahfrbjh 1 300 train
+kgydaqaojf 1 300 train
+kgyetyyqdd 1 300 train
+kgyfxkxacg 1 300 train
+kgygjjktti 1 300 train
+kgyksrmnmr 1 300 train
+kgymyaqsge 1 300 train
+kgynainlug 0 300 train
+kgyowtaqzn 0 300 train
+kgzcddojzo 1 300 train
+kgzrlqhhwl 1 300 train
+kgzsrmpawl 1 300 train
+khacbzoysu 1 300 train
+khachptymr 1 300 train
+khaeuyycza 0 300 train
+khakpjjrcx 1 300 train
+khamcqjqwc 1 300 train
+khamhfpaxv 0 300 train
+khbdyrozhb 1 299 train
+khbufwgxca 1 300 train
+khcapezpst 0 300 val
+khcdqlbuiv 1 300 train
+khcdvggbnz 1 300 train
+khchxooimk 1 300 train
+khcjelhozo 1 301 train
+khcvgrphvs 1 300 train
+khcvxfequp 1 300 test
+khcwgdciqq 0 269 train
+khdaxdnlma 1 300 train
+khdgaxcppw 1 300 train
+khdgfiymfp 1 300 train
+khdhvtkydy 1 300 train
+khdpbidakx 1 300 val
+khdqonmvdt 1 300 train
+khdsluivuv 1 300 train
+khdsotglwl 1 300 train
+khdstlsxzy 1 300 train
+khdvwqlfsf 1 301 train
+khdwpvxxvn 1 300 train
+khednkubdd 1 300 train
+khejzdbqjq 1 300 train
+khewuhkxrz 1 300 train
+khfasjktid 1 300 train
+khfdxotgoo 1 300 val
+khffedgwsx 1 300 train
+khfmfrezrx 0 300 val
+khfofkuihm 1 300 train
+khfokvjkyt 1 300 train
+khfybbuyhm 1 300 train
+khfyqlxazq 1 300 test
+khfzmflsqp 1 298 train
+khgaczpocu 1 300 train
+khgbeqytbw 1 300 train
+khgggkhauc 0 300 train
+khgpibpjjc 1 300 val
+khgudrinjz 1 300 train
+khgvtyubpy 0 300 train
+khhcdzxtxq 0 300 train
+khhcuireab 1 299 test
+khhfdandyw 1 300 train
+khhsdtspvv 0 298 val
+khhsscplrp 0 300 train
+khiakfbewd 0 300 train
+khicvwooti 1 300 train
+khieseezfx 1 298 train
+khiigqoloz 0 300 val
+khiszbboum 1 300 train
+khivgfmoax 1 300 train
+khjhrvanbr 1 300 train
+khjhyzkpzz 1 300 train
+khjjyinpnj 0 300 train
+khjkpcgfek 1 300 val
+khjwgmcyva 0 300 train
+khjxzztgoc 1 300 train
+khjycbrlhn 1 300 train
+khkcybhrmg 1 300 val
+khkhbvikve 1 300 train
+khkohvyxzx 1 301 train
+khkpcktvib 1 302 train
+khkpeefsbg 1 300 train
+khksbzgaif 1 300 val
+khkvfgtevg 0 300 train
+khldlagich 1 301 train
+khlfbdyape 0 300 train
+khlirnptkg 1 299 val
+khluefvxep 1 300 train
+khmeblwrds 1 300 val
+khmkdepeiw 1 300 train
+khmmdqcbfh 0 300 train
+khmolcsrzf 1 301 train
+khmozbhqcn 1 300 train
+khmsjyzueh 1 300 train
+khmsppvxbx 1 300 train
+khnbiihakw 1 296 train
+khngjmooqc 0 300 train
+khnlfqgmam 1 300 train
+khnnpoanvi 1 300 train
+khnovwlusf 1 300 train
+khnqntehnr 1 300 train
+khnquvnyvp 1 300 train
+khnshohpty 1 300 train
+khnwykkxca 1 241 train
+khofdipryp 1 300 train
+khoipuozlx 1 300 test
+khokghrfko 1 300 train
+khokwspqph 1 300 train
+khomejpszv 1 300 val
+khoogmqdci 1 300 train
+khopyeuvoj 1 300 train
+khowqcfplw 0 300 train
+khozecxqni 1 300 val
+khozklpxkf 1 300 train
+khpcdgvysr 1 255 train
+khpipxnsvx 1 299 test
+khplwrqrvk 0 300 train
+khpotafrqx 1 300 train
+khqozfxkxw 1 300 train
+khqspvddyp 1 300 train
+khqvhndhqu 1 239 train
+khqvuwpram 1 300 val
+khrceebsah 1 300 train
+khrfiaghrc 1 300 train
+khrhdodsjt 0 300 val
+khronohhsm 1 300 val
+khrqsabqtc 1 299 train
+khrqxvmaei 1 300 train
+khrscgxlgs 1 300 train
+khrufheolf 1 300 train
+khryhqwkyu 0 300 val
+khsbxuwknn 1 300 train
+khsmjtdwms 1 300 train
+khsukxiupl 1 241 train
+khsvrymllj 0 300 train
+khsxexgsbt 1 300 train
+khtcmtefmd 1 300 train
+khtfmxsabv 1 300 val
+khtjmvrcqs 1 300 train
+khtkjqrmpa 1 300 val
+khtkticsfh 1 300 val
+khtmdimcvu 1 300 val
+khtwrijuqn 0 300 val
+khtypqmpjw 1 300 train
+khubzoyepz 0 300 train
+khuibgkfkc 1 300 train
+khuinxaybo 1 300 train
+khumnjptcm 1 300 train
+khupgnpjmx 1 300 train
+khvhiqufnj 1 300 train
+khvjnymdxa 1 300 train
+khvkficvrr 0 300 train
+khvkxzhtou 0 300 train
+khvlzqaptr 1 300 val
+khvswyndvh 1 300 val
+khvukcxpur 1 300 train
+khvwzdrbyu 1 300 val
+khvzgypmem 1 300 val
+khwebpmikb 1 301 train
+khwkxhmroj 1 300 train
+khwpnovwbm 1 300 train
+khwutyqqno 1 301 train
+khwynwtidu 1 300 train
+khwysqiqtx 1 300 train
+khwztjfaju 1 300 train
+khxfftrfdu 1 300 train
+khxfrwycqz 1 301 train
+khxjqgkglk 1 300 train
+khxluhpuoh 1 298 train
+khxolfqumh 1 300 train
+khxoqmmdfu 1 300 train
+khxpgnkkkm 1 300 train
+khxqrwhvwq 1 300 train
+khxrtlrlwm 1 300 train
+khxxlscikz 1 300 train
+khxyzgsqho 1 300 train
+khybkobcmj 0 300 train
+khyjctbbpp 1 300 val
+khytagwxqt 1 301 train
+khywmadssk 1 300 train
+khzbazhqbb 1 300 val
+khzgjlgsuk 1 300 val
+khzkmmrmsn 0 300 train
+khzrkumnfv 1 299 test
+khzsoflwga 0 300 train
+khzyuwlvou 1 300 train
+kiabmtndql 1 300 val
+kiafndyzjw 1 300 test
+kiajkilbge 1 300 train
+kiaqmwuoiw 1 300 val
+kiayjqtala 0 300 val
+kibaqbcill 1 299 val
+kibfploxax 1 300 train
+kibghcojrv 1 298 train
+kibijicrhv 1 300 val
+kiblarjvtb 1 300 train
+kibsniqaqp 0 300 train
+kibsronapn 0 300 train
+kicbctwjtw 1 300 train
+kicgvgukqs 1 301 train
+kicjrzzsht 0 301 train
+kicodkhfgk 1 301 train
+kicrawvzlx 1 300 train
+kictjhpmxe 1 300 train
+kicveuizmb 0 300 train
+kicvqpjpru 1 300 train
+kicxxcczgt 1 300 train
+kidcscavby 1 300 train
+kiddybzxtf 1 300 train
+kidjnmlypc 1 300 train
+kidkiokwmq 1 300 train
+kidnbazrie 1 300 train
+kidyoyklcg 1 301 train
+kidzciupzx 0 300 val
+kieeiwrmvl 1 300 val
+kiefgnkgxi 0 300 train
+kieicwdevq 1 298 train
+kiejxwwvsi 1 300 train
+kiekmocqcs 1 300 train
+kiemrreszo 1 300 val
+kieolinulu 1 300 train
+kieqepfvbd 1 302 train
+kievtjvlhr 1 300 train
+kifcczjfgo 1 301 train
+kiffbbtjfe 1 300 train
+kifgzqfogn 1 300 train
+kifkxzoytp 1 300 train
+kifpwtuhaq 1 300 train
+kifyfzqzjj 0 300 train
+kifzxbsnku 1 300 val
+kigahxiwil 1 299 train
+kigbtbzpht 0 300 train
+kigbymagcu 1 300 train
+kigcwfifyq 1 301 train
+kiggwcrxkb 1 300 train
+kigimaoxmy 1 300 train
+kigiwbwfng 1 300 train
+kigjthtsmb 1 300 train
+kigxlvtcsv 1 300 train
+kigykhiiwl 1 300 train
+kigzhpiqfg 1 300 train
+kigzizkmvc 1 300 train
+kiheawautx 1 300 train
+kihfyvqjrl 1 300 val
+kihhgbacjz 1 300 train
+kihlszeprq 1 300 train
+kihmejsxhq 1 147 train
+kihnopcodq 1 300 train
+kihrpdtbwy 1 300 test
+kihtyodtmz 1 300 train
+kiibbbtaau 0 300 train
+kiiciaolkj 1 241 train
+kiinrooggn 0 300 train
+kiiqilegso 1 300 train
+kiirzipeaf 1 300 train
+kiitdgkwmq 0 300 train
+kiiufwyict 1 300 train
+kiiwtsqnzj 1 300 train
+kijblayujp 1 300 val
+kijhalclhh 1 300 train
+kijixmfcou 1 241 train
+kikchqrfnw 0 300 train
+kikeurtrpc 1 300 train
+kikffwctwo 0 300 val
+kikfjtdgui 0 300 train
+kikkiisvxz 1 299 val
+kikkklixzf 0 300 train
+kikkpjltws 1 300 train
+kikkqsjzfk 1 300 val
+kikkwfjfdo 1 300 val
+kiksapzsoj 1 300 train
+kikszvblwy 1 300 train
+kikxhinzjn 1 300 train
+kikyxrdjpj 1 299 val
+kilioqxnmq 0 300 train
+kilkyjkrkb 1 298 train
+kilnrakvbq 1 300 train
+kilpmyuydv 1 300 train
+kilryrkuox 1 300 val
+kimdvlkkra 1 300 train
+kimeupkpls 1 300 val
+kimgtneysx 0 300 train
+kimistoaix 0 300 train
+kimkwleugt 1 300 train
+kimxcwwkej 1 300 val
+kimywdtyss 1 240 train
+kinekbuzkx 1 300 val
+kinjihgcbo 1 300 train
+kinmvqhdnb 1 300 val
+kinoworanz 1 300 train
+kinqjsgfum 1 301 train
+kinudeutxr 1 300 train
+kioeibgvcn 1 301 train
+kiomgwmpkr 1 301 train
+kiondxntpt 1 300 train
+kiooxaxzqu 1 300 train
+kiotoqmmfj 0 301 train
+kiowppxfro 1 300 train
+kipbghbytd 0 300 train
+kipeikysgn 1 300 train
+kipkhepqlc 0 300 train
+kipsisnlxc 1 300 train
+kipwdelbrk 1 301 train
+kipxrdmlhi 1 300 train
+kiqadjyiii 1 300 train
+kiqjajfnoa 1 300 train
+kiqkrnjsxn 0 300 train
+kiqktgjxno 0 300 train
+kiqlwwdfox 0 300 train
+kiqmfixsvb 1 300 train
+kiqphqnazo 1 300 train
+kiraxyosjd 1 300 train
+kircengljw 1 300 train
+kircyfvjhb 1 300 train
+kirdcsvshn 1 298 train
+kirdvnvjgg 0 300 train
+kiresyxsem 1 300 test
+kirfczxxmf 0 300 train
+kirftnfovy 1 300 train
+kiroxdavqf 0 300 train
+kisdvrjfba 1 300 train
+kiskxniggx 1 300 train
+kismfsfbwe 1 299 train
+kisrwrtnuv 1 301 val
+kisvmxjmeb 1 300 train
+kiswqpqwvj 1 300 train
+kiswvzlayw 1 300 test
+kisxaykdwy 1 300 train
+kitdutenhv 1 300 train
+kitefzixya 1 300 val
+kiubpbzzrp 1 300 train
+kiufjzfjni 1 300 train
+kiujesxknb 1 298 train
+kiujlawptr 0 300 train
+kiujopxeti 1 300 val
+kiusvvynbq 1 300 train
+kiutlkwmcx 1 300 train
+kiuydxhbwr 1 299 val
+kivcvkyisj 1 300 train
+kivdflowlf 1 300 train
+kivhswiamp 1 300 train
+kivifwsmyv 1 300 train
+kivjzpzzpw 1 300 train
+kivkgrmdjt 1 300 train
+kivozfjybj 1 300 train
+kivrmvxuqz 1 301 train
+kivshognnh 1 300 val
+kiwauyqykt 1 301 train
+kiwgwgsjip 1 300 train
+kiwhblnbop 1 300 train
+kiwyyzmhme 1 300 train
+kixbyjkiom 1 300 train
+kixemjosma 1 300 train
+kixgtnykln 0 300 train
+kixhugwqjx 1 300 train
+kixqpmzmus 1 300 val
+kixraztuwt 1 300 train
+kixviudoan 1 300 train
+kixwkicmru 0 300 train
+kiyezfofrs 1 298 train
+kiykqmbhgd 1 300 train
+kiyogntlor 1 300 train
+kiyuduxzuc 1 300 val
+kiyvsruaai 0 300 test
+kiyzirghra 1 300 train
+kiyzudznxw 1 300 train
+kizhemzguv 1 300 train
+kizkjspwyf 0 300 train
+kizlbipvca 1 300 train
+kizmbzuvyt 1 300 train
+kizpvkwtcc 1 297 train
+kizqsjddwf 0 300 train
+kizuiaorho 1 300 train
+kizyjqkrmu 1 300 train
+kizyqfkuqu 1 300 train
+kizzrdnitt 1 298 train
+kjaeatxbxh 1 300 train
+kjajbhvrvk 1 300 train
+kjaojkkuor 1 301 train
+kjaqrgysro 1 300 train
+kjaujmuvdz 0 300 train
+kjawzgnwrn 1 300 train
+kjbceqbnvt 1 300 train
+kjbfoacgzi 1 300 train
+kjbjzswdsw 0 300 val
+kjbtcebopg 1 296 val
+kjbvqmofst 1 300 train
+kjcgwbvibe 1 300 train
+kjcjgkzaca 1 300 train
+kjcplixvyt 1 300 train
+kjcpzbpfgg 1 300 train
+kjcstjpivk 1 300 val
+kjdcilayyz 1 300 train
+kjddyomarb 0 301 train
+kjdjuyjdmf 1 300 val
+kjdoizhtxn 0 300 train
+kjdpieyulg 1 300 train
+kjdslrpxht 1 300 val
+kjdutcvais 1 300 train
+kjdvngbwfl 1 301 train
+kjdxjrwgic 0 300 train
+kjdydwjaqa 1 300 train
+kjebwyjqdv 1 300 train
+kjedcvjjgk 1 301 train
+kjedgbvxmc 1 300 train
+kjekclpkbf 1 300 train
+kjemaljofw 1 300 train
+kjerkikmzp 1 300 val
+kjeukspigf 1 300 train
+kjevmkanfb 1 300 train
+kjfcbxlvlp 1 300 train
+kjfjipyzvw 1 300 train
+kjfzffnsuf 1 300 train
+kjgbdaldxv 1 298 train
+kjgbindikv 1 300 train
+kjgbyidnby 1 300 train
+kjgiqmxurs 1 301 train
+kjgkvoloyf 1 300 train
+kjgtiagnsq 1 300 train
+kjgtktaupu 0 300 val
+kjhcwydrmb 1 300 train
+kjhdbpknub 1 300 train
+kjhfrlqytz 0 300 val
+kjhkwvmiio 1 300 train
+kjhuewmqlv 1 241 train
+kjidmntvlb 1 300 train
+kjifaikhzh 1 300 val
+kjifjnyiql 1 301 val
+kjiisfaqzr 1 300 val
+kjikqbixhz 1 301 val
+kjishoaqiz 1 300 train
+kjisvbgwcp 1 241 train
+kjitkmaivo 1 298 val
+kjivbugfzy 1 300 train
+kjizlyyior 1 300 train
+kjjanhdpcz 0 300 train
+kjjdbwrars 1 300 val
+kjjejstame 1 301 train
+kjjnxsoqub 1 300 train
+kjjqcjrazi 1 301 val
+kjjrhwmpjk 1 300 train
+kjkibegrgy 1 300 train
+kjkipmknsr 0 300 train
+kjkksxoqjl 0 300 train
+kjkvpzfjew 1 300 train
+kjkvqwkhjj 0 300 train
+kjkxvvxhkn 1 300 train
+kjlaxlrmya 1 300 train
+kjlfnzjgrz 1 301 val
+kjliqevwig 1 300 val
+kjlnonwyfo 1 300 train
+kjluhpgvxh 1 300 train
+kjmagrkwjk 1 300 train
+kjmccdjcdx 1 300 train
+kjmfzdlnki 1 300 val
+kjmgpungmk 0 300 train
+kjmijsgwmu 1 303 train
+kjmjmwhres 1 300 train
+kjmkffkxag 1 300 train
+kjmmkusnvx 1 300 test
+kjmpbeiazl 0 300 train
+kjmsftlmqb 1 301 train
+kjmxljxkdx 1 301 val
+kjmzbyzapb 0 300 val
+kjmzgtkrvz 1 300 train
+kjnabqlvsj 1 300 val
+kjnffimpfp 1 300 train
+kjnmsgtezt 0 300 train
+kjnncsedba 1 298 train
+kjnpjcutjr 0 300 train
+kjobwfjomn 1 300 train
+kjobwmrzli 1 300 train
+kjofqgpmam 1 300 val
+kjoguaubwx 1 301 train
+kjohsinudf 1 300 val
+kjoisqgffw 1 300 train
+kjolizkfqo 1 300 train
+kjomjfjevn 0 300 train
+kjorkudgro 0 300 train
+kjotggfugr 1 300 train
+kjphqeouji 1 300 train
+kjpnsdjrlp 1 300 train
+kjprelngva 1 300 train
+kjprxkipkn 0 300 train
+kjpsxqrdhc 1 300 train
+kjpxfnxhsy 1 300 train
+kjpxvgjsal 1 300 train
+kjqcbcgguv 1 300 train
+kjqcxqcpfn 1 300 train
+kjqfgkyjsw 1 300 train
+kjqtxknfmw 1 300 val
+kjqujvzjau 0 300 val
+kjrjgpzmxh 1 300 train
+kjrybakcra 1 300 train
+kjsdztujyv 1 299 val
+kjsqyjqhkb 1 300 train
+kjsritevmv 1 300 train
+kjsvzlwyzm 1 300 train
+kjtatqmrnu 0 300 train
+kjtecpvuai 1 301 train
+kjthvxzzzb 1 300 train
+kjtnuickkm 1 300 train
+kjtuluwqtn 1 300 train
+kjtygkuxbc 0 300 train
+kjtykqntzg 0 300 train
+kjtzhkrpnt 1 300 train
+kjtzxbttut 0 300 train
+kjuhzydvwq 1 300 train
+kjvczswcgw 0 300 train
+kjvdekaqfp 1 300 train
+kjvdxqccrw 1 300 val
+kjvnpcqnrm 1 300 train
+kjvqueujeb 1 300 train
+kjvrzbfihr 1 301 train
+kjvussgtbm 1 300 val
+kjvykdvuxo 1 300 train
+kjwdinzplo 1 300 train
+kjwdtqztjn 1 300 train
+kjwlfrwqxn 0 300 train
+kjwmnfabpb 1 302 train
+kjwnylvwuo 1 300 test
+kjwplqnkpl 1 300 train
+kjwtokbhfc 1 300 train
+kjxsbmwfde 1 236 train
+kjxxhjqysn 1 300 val
+kjxygflezk 1 301 train
+kjyapeagbg 0 301 train
+kjybakhmkb 1 300 train
+kjyeeaxvaz 1 297 train
+kjygbbzozg 1 300 train
+kjyjavqbsn 0 299 val
+kjylepubtv 1 300 train
+kjypviopcd 1 300 train
+kjywjqvivn 1 300 val
+kjzdniedqb 1 300 train
+kjzdpktsoi 1 300 train
+kjzecsljuh 0 300 train
+kjzopscndy 1 301 val
+kjzyrkhnaf 1 300 test
+kkagauhyka 1 300 train
+kkakmcyusr 1 240 val
+kkalfbklrb 1 300 train
+kkamhfcwgc 1 301 train
+kkarrrpnmh 1 300 train
+kkautgqcwq 1 300 val
+kkbjxrufzs 1 300 train
+kkbpiztaqi 1 300 train
+kkbxravwji 1 300 train
+kkbznuwipg 0 300 train
+kkcatvccnj 1 300 train
+kkcdtxivue 1 300 val
+kkceddfgfe 1 301 train
+kkcfmuydyq 1 300 train
+kkchqgwzxa 1 300 val
+kkcmpozyjb 1 300 val
+kkcoclrrle 1 301 train
+kkcqykomkx 1 297 train
+kkcrxqltpy 1 301 train
+kkcsvjkkzy 1 300 train
+kkcxdmkpzq 1 300 train
+kkddmyeeye 1 297 train
+kkdfmkitkk 1 300 train
+kkdqcqzqzg 1 300 train
+kkdxjzfaen 1 300 train
+kkdxuftecw 1 300 train
+kkecudynsk 1 300 val
+kkednymluy 1 300 train
+kkefuikkkc 1 300 train
+kkeleqnchb 1 300 train
+kkemhrscxz 1 300 test
+kkemnnznim 1 300 train
+kkewagnike 1 300 train
+kkezeprxza 1 300 train
+kkfbhpiwrg 1 300 val
+kkfcnomayq 1 300 train
+kkfgefeqfr 1 300 train
+kkfgzqhhmy 1 300 train
+kkflfzcnbu 1 300 train
+kkfmznaben 1 300 train
+kkfpruxlvn 1 300 val
+kkfshiusuy 1 300 val
+kkfueigtop 1 300 train
+kkfzfabefr 0 300 train
+kkgazwkqot 1 300 val
+kkgfsjtwis 1 300 train
+kkggcxjuol 0 300 train
+kkgggmtlct 1 300 test
+kkghjrohcv 1 300 train
+kkgybvbosw 0 300 train
+kkhcbvlpfr 1 300 train
+kkhcddrnll 1 297 train
+kkhddunvpw 1 300 train
+kkhfptvjnd 1 301 train
+kkhkcdyuyu 1 300 train
+kkhksokwvz 1 300 train
+kkhosxllhk 1 300 train
+kkhrcocktr 1 300 train
+kkhrtmftlq 1 300 test
+kkhtabarcx 0 300 val
+kkibthjsqs 1 300 train
+kkicmcrycn 1 300 train
+kkiexeaqwm 1 240 train
+kkiwjyykph 1 300 train
+kkiwroyhqr 1 300 train
+kkiwwwgixc 1 300 val
+kkjchhfjul 1 300 train
+kkjxitvtep 1 300 train
+kkjzeflvui 1 299 test
+kkkebpevcw 1 300 val
+kkkouswmgq 0 301 train
+kkkqdbjvgs 1 300 train
+kkkzlyzoon 1 299 test
+kklkqitffk 1 300 train
+kkloaeoxbb 1 301 val
+kklxritesp 1 241 train
+kklydoysvu 1 300 train
+kkmacsnegk 1 300 train
+kkmbxyqbta 0 300 train
+kkmuehgkmx 1 300 val
+kkmugypzhc 1 300 train
+kkmvqcvdvx 1 300 train
+kkmvzuzeiy 1 300 train
+kkmwqrzyxw 1 302 train
+kkmzagnxpn 0 300 train
+kknhxivufr 1 300 train
+kknksocggx 1 300 train
+kknnpymcxs 1 300 train
+kknqgwymnt 1 300 train
+kkobnbbaln 1 300 train
+kkoeseechn 1 300 train
+kkoflzlmzy 1 300 train
+kkorxlajxc 1 300 train
+kkowzyqrmt 0 300 train
+kkoxojbyko 1 300 train
+kkoxvzxofh 1 298 train
+kkpddzaexu 1 301 val
+kkpgyhdvmb 0 300 train
+kkpirylhig 0 300 val
+kkppldwsiw 1 300 val
+kkprjgypbz 1 300 train
+kkqhkbaqku 1 300 train
+kkqkjvbvfp 1 301 train
+kkqmmvhsie 1 300 train
+kkqnivzdzc 1 300 train
+kkqwiruktw 1 300 val
+kkqzpivsbd 1 300 train
+kkqzyillvc 1 300 train
+kkrdphgolp 1 296 val
+kkreskoowm 1 300 train
+kkrlczrlcy 1 300 train
+kkrlgukgxs 1 300 train
+kksdxtcduf 1 300 val
+kksgjsgatk 0 300 train
+kkshfqyydv 1 298 train
+kksizrmaxw 1 300 train
+kksqrskybv 1 299 val
+kkssymbsrg 1 300 train
+kksxnjqsco 1 300 train
+kksyrrjgsg 1 298 train
+kkszgvwgqr 1 300 train
+kktdxwgdlo 1 300 train
+kkthrvcuzs 1 300 train
+kktjrfdacw 1 300 train
+kktoqqqjab 1 298 train
+kktqitsegi 1 301 val
+kktrnahwug 1 300 train
+kktuwbobhe 1 300 train
+kktvbingqt 1 300 train
+kktxxryyya 1 300 train
+kktzicobyz 1 300 train
+kkuabqnvwi 1 300 train
+kkuelcuyki 1 300 train
+kkuorsdetj 1 292 train
+kkuowrhmzl 1 301 train
+kkupumluql 0 300 val
+kkuqjnxbnv 0 300 train
+kkuuolsxfq 1 300 train
+kkvaezpcsb 1 300 val
+kkvdkfhgob 1 300 train
+kkviitkafe 1 300 train
+kkvktewfvj 1 301 train
+kkvphraiiz 1 300 train
+kkvqrgzanl 1 300 train
+kkvreaiidi 1 300 train
+kkvuxgkdmv 1 300 train
+kkvxnfxhho 1 300 train
+kkwmaneklh 1 300 train
+kkwqddpqlv 1 300 train
+kkxetlfimi 1 301 val
+kkxgqvpusd 1 300 val
+kkxnpuhfsk 0 300 train
+kkxpcxcxrs 1 300 train
+kkxqbqzxjw 1 300 train
+kkxslcuaxj 1 300 train
+kkxtbcosnk 1 300 train
+kkxtcywtrn 1 299 val
+kkxwdgwmpd 1 300 train
+kkxxsoapik 1 300 train
+kkybwlfzph 1 300 train
+kkydgnetga 1 299 val
+kkyinqjpyl 1 297 train
+kkymnndioi 1 300 train
+kkynneribb 1 300 train
+kkyqvoegfm 1 300 train
+kkyulqzhsd 1 300 train
+kkzbwqdbbk 0 300 train
+kkzeqaxrpt 0 300 train
+kkzkffvget 1 300 train
+kkzqoetoym 1 300 train
+kkzsnmrkqk 0 300 train
+kkzusolqfw 1 300 train
+kkzuugfoqj 1 300 train
+kkzyjzttyi 1 300 train
+kkzyrncmet 1 300 train
+klammpmros 1 300 train
+klapbzltam 1 300 train
+klapyuhmgc 1 300 train
+klaruoxyvq 1 241 train
+klavqvgpye 1 301 train
+klbboosojp 1 300 val
+klbfdsrfwn 1 299 train
+klbfjzxdgh 0 300 train
+klbptplvva 1 298 train
+klbrgzqfzv 1 300 train
+klbsdpnrls 1 300 train
+klcfvbtksk 1 241 train
+klcgzimbce 1 299 val
+klcjxgkbks 0 300 train
+klckinpbgj 1 300 val
+klcomxhdbf 0 300 val
+klcvqhwbqs 0 300 train
+kldgbppqcb 1 300 train
+kldqpsyynz 1 299 test
+kldtmtlhvw 1 300 val
+kldvjzjrdf 1 300 val
+kldwoybtzz 1 300 train
+klecbedwuq 1 300 train
+kledmjtqya 1 300 train
+klekqpnjrx 1 300 val
+klelhmgtho 0 300 train
+klenndseva 1 300 train
+klfabimgiw 0 300 train
+klfcosrrju 1 300 train
+klfqlxyqes 1 300 train
+klgfgsltsx 1 300 train
+klgjfsnefz 0 300 train
+klgqcvtcbo 1 300 train
+klgtcaeamm 1 300 train
+klgtknoteq 1 300 train
+klguzuspvv 1 300 train
+klhciqtaxh 1 300 train
+klhegkocta 1 300 train
+klhjxxrrlm 0 300 train
+klhnlmcgrt 1 301 train
+klhoeyozvi 1 300 val
+klhpomwpzs 1 299 val
+klhqxedmll 0 300 train
+klhrwllfsy 1 300 val
+klhspxmazo 1 301 val
+klhuadecnh 1 301 train
+klhvfqkaje 1 300 train
+klhxqybapi 0 300 val
+klidyuxkjv 0 300 val
+klifbclerd 0 300 train
+kligjmklcw 1 300 test
+kligyzlcuk 1 125 val
+klihnmenag 1 298 train
+kliktwdilw 1 298 train
+klinjohpse 1 300 train
+kliphfgwgq 1 300 train
+kliqbzlmus 1 300 train
+kliqnhmoxd 1 299 test
+klisuzrptl 0 299 val
+kliwzsvdyd 1 300 train
+kljepvvmau 0 300 val
+kljgzhdwml 1 300 train
+kljiusgslo 1 300 train
+kljixcdmpg 0 300 train
+kljizofgfn 1 300 train
+kljnmxtnft 1 300 train
+kljqmbzuav 1 255 train
+kljsndnejv 1 300 train
+kljsosbpwv 0 300 train
+kljvnozpfj 1 300 train
+kljvxubmrj 1 300 train
+kljxgnoprt 0 300 train
+klkapynfwe 1 300 train
+klkclkuobx 1 300 train
+klkzjzjtbz 1 300 val
+kllagufrhq 1 300 train
+klldbpoujs 1 300 train
+kllhzzcwbh 1 300 val
+klllapfmgd 0 300 train
+kllpibckia 1 241 train
+klluldrjqz 1 300 val
+kllvostzmc 1 300 train
+kllyfvgyps 0 300 train
+klmaeumvul 0 241 train
+klmbynpagk 1 300 val
+klmchlcbii 1 300 train
+klmihaypzb 1 300 train
+klmocuzbxa 1 300 train
+klmomliweu 1 300 train
+klmpjdvkvv 1 300 train
+klmqspxbxv 0 300 train
+klnctldhby 0 300 train
+klncwqllnq 1 300 val
+klncxcncuc 1 300 train
+klngoauxgy 0 300 train
+klnqjfibuf 1 296 train
+klotqkivfv 1 300 train
+kloynebafd 1 300 train
+klpakjyoyr 1 298 train
+klphgedsms 1 300 val
+klpiqujaet 1 300 train
+klpkkudujl 1 241 train
+klpknikdfz 1 147 train
+klpubyviri 1 300 train
+klpvmipays 1 300 train
+klqcaxcwej 1 300 train
+klqfpygmin 0 300 train
+klqllljjkm 0 300 train
+klqufdyaxx 0 300 train
+klqyhmwper 0 300 train
+klqzvnrfyk 1 300 train
+klrpymmlkn 0 300 val
+klrtggryjl 1 300 train
+klrypdjrat 1 300 val
+klryypoecq 1 300 train
+klsdwqcpme 1 300 train
+klsjhbmduk 1 99 train
+klsoplemxk 1 300 train
+klspkxerhf 1 300 train
+klspoouqnm 1 300 train
+kltcynmatb 1 299 train
+kltgupniuv 1 300 train
+kltldqdwjf 1 301 train
+kltqlsenwv 1 300 train
+kltrrqzkjd 0 300 train
+kltziwbehe 1 298 train
+klubfzwvma 0 300 train
+kluheuceib 1 300 train
+klulkcdrnx 1 300 train
+klumuemvpu 1 300 test
+kluvzbayla 1 300 train
+kluxpavmxo 1 292 train
+klvgdbhzwy 1 300 train
+klvgyworxz 1 300 val
+klvlmkolvx 1 300 val
+klvmamrgvn 1 300 train
+klvpqabkcc 1 300 train
+klvzaxkahq 1 300 train
+klwduyxtun 1 300 train
+klwnoukxpy 1 300 train
+klwnpusofy 1 241 train
+klwrakurce 1 300 train
+klwuwpxdsy 1 298 train
+klwxsurrwp 1 300 train
+klxjwttmcv 0 301 train
+klxqsnyans 1 301 train
+klxtojahon 1 300 train
+klydmuqlma 1 300 train
+klyedgsmlx 1 300 train
+klyoflqbdp 1 300 train
+klywiihdhk 1 300 train
+klyxptgxrg 1 300 train
+klyyaehwgx 1 300 train
+klzirehxqq 0 300 train
+klznljhmin 1 300 val
+klzuqcnjlt 1 300 val
+klzvqhmxpw 1 300 train
+klzzmudfcb 1 300 train
+kmaallebhh 1 300 train
+kmadboxxvg 1 300 val
+kmakhupeac 0 300 train
+kmakwrqxvf 1 300 train
+kmamcrmkbf 1 300 train
+kmarniljak 1 300 train
+kmatdqzpxd 1 300 train
+kmawrfoqcn 1 297 train
+kmbeaikclk 0 300 train
+kmbewsqvqo 1 299 train
+kmbiamdteu 0 300 val
+kmblgfwkai 1 300 val
+kmboedsmeq 1 300 train
+kmbruhyrxb 0 300 train
+kmbtpctkrx 1 300 train
+kmbtvsrstu 1 300 val
+kmbvuxcfkp 1 300 val
+kmcdjxmnoa 1 300 test
+kmcffzemiv 1 300 val
+kmcjdqubqh 1 294 train
+kmcqhchvxi 1 300 train
+kmcsdkojcm 1 301 train
+kmctqrbklq 1 298 train
+kmcylsrkvl 1 296 val
+kmdaosbweo 1 300 train
+kmdfaktlxb 1 300 train
+kmdhbujylo 1 300 val
+kmdmbkghpo 1 300 train
+kmdxguxguc 1 301 train
+kmdxrmzwsd 1 167 train
+kmeakbpxsm 1 298 val
+kmeedhwxxd 1 298 train
+kmefotakie 1 300 train
+kmenymzhas 1 300 val
+kmeubcvmon 0 300 val
+kmexkdcjmh 1 300 train
+kmezsgwwcq 1 300 train
+kmffwfsuuf 1 298 train
+kmflbaixsk 1 300 train
+kmflgeclij 0 300 train
+kmfxuedygw 1 300 train
+kmgemglxjj 1 301 val
+kmgepmkqoc 1 301 train
+kmggfkgwrh 0 300 val
+kmgklpxwfw 1 300 train
+kmglvqypyb 1 300 train
+kmgmixoiib 1 300 val
+kmgribiuez 1 300 train
+kmgudgiwxv 1 300 train
+kmgwdupbgp 1 300 val
+kmhiqddyhh 1 300 test
+kmhkacmyiy 0 300 train
+kmhqhdjkwe 1 298 train
+kmhqszaumf 1 300 train
+kmhudofqkh 1 300 val
+kmhyyrlayu 1 300 train
+kmicgzlqtz 1 300 train
+kmiddvzggp 1 300 train
+kmigcpmqoq 0 300 val
+kmixuyltfr 1 300 val
+kmiyuhklns 1 300 train
+kmjezkofjd 1 300 train
+kmjfnlokoo 1 301 train
+kmjhokfeca 0 300 train
+kmjmfdhjgv 1 300 train
+kmjqxxcwwi 0 300 train
+kmkigkvlsm 1 300 train
+kmkmjaoeeh 1 300 val
+kmkrpnhqkd 1 300 val
+kmktfamvoi 0 300 val
+kmkvxunbop 0 300 train
+kmkzatvadx 1 300 train
+kmldmopdca 1 300 train
+kmliyduces 0 300 val
+kmlmtpcymt 1 300 train
+kmlnxzkvjf 1 300 train
+kmlpekvpuf 1 300 train
+kmlrtuusvc 1 301 train
+kmmjnahumx 0 300 train
+kmmlscocgr 1 300 train
+kmmmkqxkzj 1 300 train
+kmmwnkjldd 1 301 train
+kmnajlmwcr 1 300 train
+kmnboeohyo 0 300 train
+kmncrgmawu 1 300 train
+kmnfdhzlsf 1 300 train
+kmnjuslbyy 1 301 train
+kmnpesunza 1 299 val
+kmodjpjktk 1 300 train
+kmogegpwvf 1 300 train
+kmomekqvwj 1 300 train
+kmonapegyg 0 300 train
+kmoqmjgpqk 1 300 train
+kmorgymjrq 1 300 val
+kmpanvxxuv 1 300 train
+kmpmvpjduk 1 300 train
+kmpugyvbhg 1 300 train
+kmqbhhryow 0 300 val
+kmqedahlpt 1 300 val
+kmqiktnykh 0 300 train
+kmqkiihrmj 1 300 test
+kmqprpvlob 0 300 train
+kmqsmciqeh 0 302 train
+kmqswesijv 1 301 train
+kmquivkgue 1 299 test
+kmrbkfwowc 1 300 train
+kmrcvqpfcs 1 300 train
+kmrfmumknp 1 301 train
+kmrjhsbqqy 1 300 val
+kmrnovukoj 1 300 train
+kmrojywxvz 1 296 val
+kmrpxncfbz 1 300 train
+kmrrspogst 1 300 val
+kmrsuhzgyg 1 300 train
+kmrtmlvvvn 1 300 train
+kmrtyrsmrs 1 298 train
+kmrvujlwmf 0 300 val
+kmryxfqkfk 1 300 train
+kmrzrpgrje 1 301 train
+kmscrlfgku 0 300 train
+kmsfmffrrp 0 300 train
+kmsleeprob 1 301 val
+kmssecpvav 1 300 train
+kmswpobxgf 0 300 train
+kmswwidsrb 1 300 val
+kmszngykll 1 300 train
+kmtfxfdyoj 1 298 train
+kmtpfrbfoa 1 300 train
+kmtqqzwtox 1 300 train
+kmttiquyop 1 300 train
+kmtwntzbfy 1 300 val
+kmueahptyl 1 301 val
+kmujxmbolf 1 300 train
+kmumkpqvcc 1 300 train
+kmuntdqjrf 1 300 train
+kmuokauspb 0 298 train
+kmurgwzrdo 1 300 val
+kmuzkpmeka 1 300 val
+kmvfeofizf 1 241 train
+kmvftcwart 1 300 train
+kmvjyknxom 1 300 train
+kmvsuicqeu 0 301 train
+kmwclbipvp 1 298 train
+kmwfqjhsvw 1 300 val
+kmwqashqwd 1 300 train
+kmwrkglljs 1 300 train
+kmwxvfxqha 1 300 train
+kmxdgdvmql 0 300 train
+kmxgykaxkz 1 297 train
+kmxjfwuuje 1 300 train
+kmxpuaqxyj 0 302 train
+kmxrwdmcrz 1 300 train
+kmxsddcuvi 1 300 val
+kmxtqojqmk 0 300 train
+kmxwqlezxf 1 240 train
+kmxzhunpgf 1 301 train
+kmybabuwxc 1 300 train
+kmyhzsuequ 1 300 val
+kmykskbxfu 1 300 train
+kmypxpegzf 1 300 train
+kmyrnchata 0 298 train
+kmzbjdkvtc 1 302 val
+kmzhrokipl 1 300 train
+kmzisasygt 1 300 train
+kmzlyhldkp 1 299 val
+kmzmtkxway 1 300 val
+kmzpcrmiah 1 300 train
+kmztaltwlb 1 300 train
+knafngkgen 1 300 train
+knajheusei 1 300 train
+knaqctfysu 1 300 train
+knaycfwpzx 1 300 train
+knazfjwyei 1 300 train
+knbbxhbbav 1 300 train
+knbnstxjcd 1 290 train
+knbodjyiew 0 300 train
+knbpqrlrei 1 298 train
+knbsiylwur 1 300 train
+knbvhuplgm 1 300 train
+knbxqitaro 1 300 train
+knbyfhpjvn 1 298 val
+knbyjrotuv 1 300 train
+knbymnlzbw 0 301 train
+knbzfypqud 1 300 train
+knccjiqepg 0 290 train
+knceeulwam 1 300 train
+knceuenbna 1 300 train
+kncmmzuzjy 1 300 train
+kncsobhrlq 1 300 train
+kncsruowxl 1 300 train
+knctmvctns 1 300 val
+kndbnfrxij 1 300 train
+kndbqpbejm 1 299 train
+knddyeyosu 1 299 test
+kndgyphmoz 1 298 train
+kndiwendcy 1 300 val
+kndjdczyzx 1 240 val
+kndtikqylz 1 300 train
+kndvzqjfil 1 300 train
+kneanotiir 1 300 train
+knelidzqnj 1 300 train
+kneosolmlk 1 300 train
+knepeputoj 1 300 val
+kneshqdhzn 1 297 val
+knetclxsmc 1 298 val
+kneubnuequ 1 300 train
+kneuzwgghn 0 300 train
+knewbhtaqu 1 301 train
+knfbyvokfh 1 300 train
+knfddtsssw 1 300 train
+knfgsefogt 1 300 train
+knfuvlebtw 1 300 train
+knfxukpgcm 1 299 test
+kngejhzonc 1 300 val
+kngemmhvrg 0 300 train
+knglmsvnek 1 300 train
+kngmznnhuh 0 300 val
+kngnwvjgrq 1 300 train
+kngqzbzsae 1 300 train
+kngvfkigcp 1 300 train
+kngwtbtmsy 1 300 val
+kngxukvdfw 1 300 train
+kngzdgpmbc 0 300 train
+knhaeseapg 1 300 train
+knhdrnaitz 1 300 train
+knhfkgpmgl 1 300 train
+knhmlrxtxi 1 299 train
+knhtooezfa 1 300 train
+knhwezewod 1 300 train
+knhyhxhdqd 1 300 train
+knhzciotgi 1 299 test
+kniifrhbhd 1 300 train
+knikbvyevp 1 300 train
+kniszwrbmn 1 299 val
+knityxvmft 1 300 train
+knjbuviztq 1 300 train
+knjceurdhv 1 300 train
+knjdcfbrzn 1 300 train
+knjfzzpxoa 1 300 train
+knjhijgdoy 1 300 train
+knjjftwiuh 1 300 train
+knjoasqzvt 0 300 train
+knjogjzgzy 1 300 val
+knkdomojlq 1 241 train
+knkfxtpidm 1 300 train
+knkguuudiq 1 300 val
+knkhspjotx 0 300 train
+knkomyxmkt 1 300 train
+knkuclzcpq 1 300 val
+knlblibrtt 1 300 train
+knljhjknnu 1 300 train
+knlkanvkjs 1 300 train
+knlmlbcvxe 1 300 train
+knlnwborfz 1 300 train
+knlobqrnux 1 300 train
+knlpfccddv 1 300 train
+knlpnpafsh 1 241 train
+knlsdvsdtv 1 300 val
+knlszjnqmi 1 100 train
+knlueurvzs 1 298 train
+knlxhtaapi 0 300 train
+knmcdtyyaw 1 249 train
+knmdukovvm 1 300 train
+knmfrovsdm 1 298 train
+knmfzlhzzf 0 300 train
+knmmosribv 0 300 train
+knmndkxahq 1 300 val
+knmpnjpwpe 1 300 train
+knmrhhsnqw 0 300 test
+knmttzbtaw 1 300 train
+knmwzvhfos 1 300 train
+knmxhdafpy 1 300 train
+knnbozikey 0 300 train
+knnpesqlwf 1 300 train
+knnpmoznoa 1 300 val
+knnqtenzyy 1 300 train
+knnzdtpyki 1 300 train
+knoaflgjao 1 300 train
+knobhdaern 1 300 val
+knocekbvyd 1 300 train
+knofhbbqbp 1 300 train
+knolhqgjan 1 300 val
+knombgxhyv 1 300 train
+knomjvjhei 1 300 val
+knonrnqlwg 1 300 train
+knoraxuctp 1 240 train
+knotnslkfd 1 300 train
+knovqeiqdg 1 300 train
+knowxlvaui 1 300 train
+knptkumgzk 1 300 train
+knpxmrizay 1 300 train
+knqgkhzeau 1 300 train
+knqhpwoigk 0 300 train
+knqjkahous 1 300 train
+knqlqtkusl 1 301 train
+knqpkxrmsi 1 300 train
+knqvkagvyk 1 300 train
+knqxhgcyyg 1 300 train
+knrcipgwcv 1 300 train
+knrdttmfpy 0 300 train
+knrhiuinku 1 300 train
+knrkpjtrtl 1 300 val
+knrmffbghi 1 300 val
+knsdcdsuts 1 300 train
+knsdlrpacm 1 300 train
+knshvzsynq 0 300 train
+knsikqqjrw 1 300 test
+knsvzouvxr 1 301 train
+kntckcixlj 1 300 train
+kntegyslhd 1 300 train
+kntguwshwb 1 298 train
+kntinphmto 1 300 train
+kntmkzayjl 1 300 train
+kntssjvndx 1 300 train
+knttlzqbxz 1 300 train
+kntvedmgqm 1 300 train
+knubjfldpt 1 300 val
+knucgcyzod 1 301 train
+knuemfusqz 1 300 train
+knuurwluca 1 300 val
+knuvukmrxx 1 300 val
+knvdxjcfdh 1 300 train
+knvfnbcfjp 1 288 train
+knvgmakfmf 1 300 train
+knvhslqkrr 0 300 train
+knvntdiazl 1 298 train
+knvpxotkqn 1 300 train
+knvqwsmxid 1 300 train
+knvutviaep 0 300 train
+knvzskufkt 1 300 train
+knwatildbk 1 301 train
+knwhnjhhhs 1 300 train
+knwhzylxvs 1 300 train
+knwnqrvira 1 299 train
+knwomsqidk 1 300 train
+knwpjkmogc 1 300 train
+knwsclzhle 0 300 train
+knwswiwkui 1 241 train
+knxamupysc 1 241 train
+knxfhboqdl 1 300 train
+knxirddqfb 1 300 train
+knxltsvzyu 0 300 test
+knxtvegigd 1 241 train
+knyjygzoat 1 300 val
+knykexaifz 1 300 train
+knymzrjvso 1 300 test
+knyplmogof 0 300 train
+knyxzfrtry 1 298 train
+knyyyzohyr 1 300 train
+knzapnazlb 1 300 val
+knzedqltyt 0 300 train
+knzmwugfab 1 301 train
+knztraazwn 1 300 train
+knzwbnkzob 1 300 train
+koablqmidm 1 300 train
+koadexkljm 1 300 train
+koadjxgaip 1 300 train
+koaesyuhye 0 300 train
+koaskscqxd 1 301 train
+koatnkjzsa 1 300 val
+koayhruklm 1 299 val
+koaythwkcn 1 300 train
+kobawuytol 1 300 train
+koblrekzes 1 300 train
+kobntgjzjo 1 300 train
+kobofsbvfx 1 99 train
+kocbvddihw 1 300 train
+koceuyenhi 0 300 train
+kocfmbbtfm 1 300 train
+kocfrywowl 1 300 train
+kocjkqdqej 1 300 val
+kockoseapp 1 300 train
+koclwknbsc 0 300 train
+kocqinykzc 1 300 train
+koctbntdsl 1 300 val
+koctgewurj 1 302 train
+koctmvrupm 1 300 train
+kocvvvrlqj 1 300 train
+koczcffhqi 1 300 train
+kodagphkpn 1 300 val
+kodbvtzfiy 1 301 train
+kodoqikrxs 1 300 train
+kodszzmdow 1 300 train
+koduncziii 1 300 train
+kodzcafonz 1 300 train
+koejiurbvx 0 300 val
+koejtodecs 1 300 train
+koemuajhfk 1 300 train
+koeqtmielt 1 300 train
+koerhbmweb 1 300 train
+koeuoinpwo 1 301 train
+koeytonnaz 1 300 train
+kofexfbelw 1 300 train
+kofijqkbfs 1 300 train
+kofofvdhgy 1 300 train
+koftxmwwlw 0 301 val
+kogaceakif 1 300 val
+kogfcdmmtd 1 300 train
+kogkauafqp 1 301 train
+kogsdcoygg 1 300 val
+kohirzagfm 1 300 train
+kohllnzigb 1 300 train
+kohpcxdnaw 1 298 train
+kohqndohti 1 301 train
+kohrhtitja 0 301 val
+kohrycolil 1 301 train
+kohvzfkpqb 1 298 train
+koifnfvjbv 1 300 test
+koifuzmcyj 1 300 train
+koiifpthwj 0 300 train
+kojdbsktjh 1 301 val
+kojiijovie 1 300 train
+kojlfqmgbz 1 296 train
+kojoeweget 0 300 train
+kojpmryjau 1 301 train
+kojsoyqxrd 1 300 val
+kojstlzxyz 1 300 train
+kojumodwqz 1 300 train
+kojuvjsqok 1 300 train
+kojwophkft 1 300 train
+kokgbhrhoc 1 300 val
+kokjdjaraq 1 299 train
+kokkoxtvph 1 300 val
+koklqvyfwy 0 300 train
+kokmotludb 1 300 train
+koktazrfxy 1 300 train
+koktunjsfv 1 270 train
+kokxuoeoyj 1 300 val
+kokzhjrikg 1 300 train
+kokzykdryo 0 300 train
+kokzznygap 1 300 train
+koljpwhvfq 1 300 train
+kolmdxcxyo 1 240 val
+koluqlpreb 1 300 train
+kolwnennqk 1 300 train
+kolwvxizei 0 300 train
+kolwwlqmof 1 300 train
+komdwqrvpx 1 300 train
+komhwojiyu 0 300 train
+komngcqveq 1 300 test
+komspxrdyh 0 300 train
+komxgsfxkk 1 300 train
+komxwlaqcq 1 299 train
+komzotmlbr 1 298 train
+kondrgiemw 1 300 train
+konewukzos 1 300 train
+konhekeqlk 1 300 train
+konotxxnvc 1 300 train
+konpiwpxkm 1 300 val
+konrrzaqtc 0 300 train
+konsyybrks 1 300 train
+kooasxwudv 1 300 train
+koocctcseh 0 300 train
+kooldgrvmi 1 300 train
+koorkaelxe 1 300 train
+koowbgunvg 1 300 train
+koowljkerd 0 300 val
+kooxfzmxqz 1 300 train
+kooybbtlzo 1 300 train
+kopalxwqpr 1 241 train
+kopaxyksys 1 300 val
+kopbdqnnni 1 301 train
+kopprfckue 1 300 train
+koprpzskyb 1 300 train
+kopsrkkcbq 1 300 train
+koqczibqxz 1 300 train
+koqdjjtuhu 1 249 train
+koqenedhsa 1 300 train
+koqhckuikj 1 300 train
+koqiruevet 1 301 train
+koqtsngkvg 1 300 val
+koqxhnmkjl 1 167 train
+koqykrcxxe 1 300 train
+koraracdsp 1 300 test
+korehlsawt 1 300 train
+koriheylkr 1 300 train
+korjxjawvu 0 300 train
+korjxpqzhy 1 300 val
+kormbdrhpy 1 300 train
+korpnmhwkx 1 300 train
+korpsbxqcv 1 299 test
+korrsqtkke 0 300 train
+korxxcldmc 1 300 train
+korycjwnlt 1 300 val
+koscqwcqkb 1 300 val
+koselfodym 1 300 train
+kosgvmbucr 1 241 train
+koshrdyqec 1 300 train
+kosjbrfoxt 1 300 val
+kosmfnsuew 0 300 train
+kosqkknhqy 1 300 train
+kosqmmusyd 0 240 train
+kosrqithbz 1 300 train
+kosvbdxsfy 0 300 train
+koswtrvvgq 0 300 val
+kosytzjuno 1 301 train
+kotiabmmnn 1 300 val
+kotljqefuu 0 300 train
+kotlwwqzll 1 300 train
+koturskxjs 1 300 train
+koudmdituj 1 298 train
+koujdryqvr 1 301 train
+koujwceods 1 300 train
+kounllaaza 0 300 train
+koupybgylu 1 300 val
+koutcqnqck 1 300 train
+kouwykaoxb 1 300 train
+kovcpuxwtx 1 300 train
+kovhiyolbp 1 300 train
+kovidjygqn 1 300 train
+kovqcfeghf 1 300 train
+kovvstvbgq 1 300 val
+kovzwqmhjr 1 300 train
+kowccxcnye 1 300 train
+kowddifurz 1 300 val
+koweuxvahw 1 300 val
+kowgjpephu 1 297 train
+kowgqrymzs 1 300 test
+kowiwvrjht 1 299 test
+kowtiypnkp 1 300 train
+kowvctnhee 1 300 val
+kowvzgemqi 1 300 val
+koxarqcnej 1 300 train
+koxgcuuzwx 1 300 train
+koxmqsvhwp 1 302 val
+koxqpeopjh 1 298 train
+koxrvcebsp 1 300 val
+koxuucgqbp 1 241 train
+koxwykmawn 1 300 test
+koxyamtudy 1 300 train
+koxygpaatu 1 300 val
+koyandzswg 1 300 val
+koybynevak 1 300 train
+koydycmlzr 1 300 train
+koyignjpay 1 300 train
+koypvicxpm 1 300 train
+koyxhengws 1 297 val
+koyyirxumw 1 300 val
+kozaofkgvk 1 300 train
+kozaxpoobi 1 300 val
+kozbfhwrxu 1 300 train
+kozbnhsyqp 1 300 train
+kozbrfykwf 1 300 train
+kozhkngoxk 1 300 val
+kozpkldsby 0 302 train
+kozpsqutua 1 300 train
+kozqsrdbfv 1 300 train
+kozqvdlubv 1 300 train
+kpaahafkvb 1 300 train
+kpaannwjzb 1 300 train
+kpaapikjrf 1 300 train
+kpagnxlquk 1 300 train
+kpaimwkvnd 1 300 train
+kpajsgpmdc 1 300 train
+kpanqmbssf 1 249 train
+kpaqfimynn 0 300 train
+kpatdgjera 1 300 val
+kpavkhwehg 1 300 train
+kpaxztlqrz 0 300 train
+kpayrtubgh 1 300 train
+kpbemykxhh 1 300 val
+kpbfssfcoy 1 300 train
+kpbfwsusvo 0 300 train
+kpbkjgxhun 1 300 val
+kpboyfgsii 0 300 train
+kpbqtcxihi 1 300 train
+kpbuoeuzoi 1 300 train
+kpbxapzamz 1 300 test
+kpclztndoj 1 301 train
+kpcrdurodw 0 300 train
+kpcurkiuzl 0 300 train
+kpdgybasbo 0 300 train
+kpdilxcrrt 1 300 train
+kpdmfsjhdl 1 300 train
+kpdqzfaukd 1 301 val
+kpdrduvhir 1 300 train
+kpdsblcqvg 1 300 test
+kpdwxgqctp 1 300 train
+kpebjtxmqu 1 300 train
+kpehmlqszc 0 300 train
+kpemftnnoj 1 300 val
+kpesjiqazt 1 300 train
+kpfgdenhre 1 298 val
+kpfiadskoi 0 241 train
+kpfjxfyqth 1 300 train
+kpfopijwix 1 300 val
+kpfqowchhs 1 300 train
+kpfqvgmnzw 1 296 val
+kpgcspadwi 1 299 train
+kpgecsmtnp 0 300 train
+kpgffzzwcm 1 300 train
+kpgohptpie 1 300 train
+kpgsnjdggg 1 300 train
+kpgsqazbpe 0 298 train
+kpgubxneed 1 300 train
+kpguqwojtm 1 300 val
+kpgusxpouq 1 300 train
+kpgzywsvny 1 241 train
+kpheemtvzg 0 240 val
+kphflojove 0 300 val
+kphfzaullq 1 300 train
+kphmeitiqy 1 300 train
+kphqopmkgn 0 300 train
+kphtlddddl 1 300 train
+kphyujfefw 1 300 train
+kpijegiuth 1 300 train
+kpikqnizoz 1 300 train
+kpimlebzdf 1 300 val
+kpimyiwuhd 0 301 train
+kpinbeueci 1 300 train
+kpiozjsuec 1 300 train
+kpiwvuxijf 1 300 train
+kpjfsetqvz 1 300 train
+kpjhxhxmje 1 300 val
+kpjkugpmgz 1 300 train
+kpjmtrfrhi 0 300 train
+kpjowswook 1 300 train
+kpjqjoqbbq 1 300 train
+kpjttqyoyu 1 300 val
+kpjvpidxqr 1 300 train
+kpjvtbikne 1 300 train
+kpjwnnrxjg 1 240 train
+kpkbtvsxlz 0 297 train
+kpkkksswww 1 292 val
+kpkljoebwm 1 300 train
+kpktmafsnl 1 300 train
+kpkzqbpivj 1 300 train
+kplgwaqclf 1 298 train
+kpllrzoznl 1 300 train
+kplraprrrj 1 300 train
+kplrofuing 1 301 val
+kplsbogrxo 1 300 train
+kpltzztlvj 0 300 train
+kpluwasvkq 1 288 train
+kplwmpwixn 1 300 train
+kpmhpiridn 1 300 train
+kpmieleslf 1 300 train
+kpmmyhsxey 1 301 val
+kpnakfmmlh 0 299 val
+kpnefqrkup 1 300 train
+kpnnheddzz 1 300 train
+kpnqwouwbq 1 300 train
+kpnsiqmksz 1 300 val
+kpnykaldom 1 300 train
+kpobtgvmpy 0 300 train
+kpohpmbmom 1 300 train
+kpohueldae 1 300 train
+kpokelvdzs 1 300 val
+kpokwpxxbu 1 300 val
+kpolcjxscc 1 300 train
+kpoojjexob 1 300 val
+kposduxhqo 1 300 train
+kposzqfakj 0 300 train
+kpouuxyjtd 1 300 val
+kpovuvhbey 1 298 train
+kpoxjpxtwn 1 300 val
+kppbdlqiux 1 298 train
+kppczhiupv 1 300 train
+kpphjbpcwv 1 300 val
+kppildykmo 1 300 train
+kppsvwgyms 1 299 test
+kppteglomr 1 300 train
+kpptwnxyrv 0 300 train
+kppuciykot 1 300 train
+kpqfjljref 1 297 val
+kpqqjbbugp 1 300 train
+kpqtbdnano 1 300 train
+kpqwzjkytx 1 301 train
+kpqzbeooyn 1 300 train
+kpreqvvzsu 1 300 train
+kprfdarqfw 1 302 train
+kprgaqwvjm 1 300 train
+kprhbuhjyo 1 300 train
+kprkhdlhej 1 301 val
+kprmvqvqso 1 241 train
+kprnuzjwbw 1 298 train
+kpropgluhn 0 300 train
+kprusfxear 1 300 train
+kprwsebfzd 1 300 val
+kpseauxfgv 1 300 train
+kpsfbhqbbu 1 300 train
+kpspwqtytd 1 301 train
+kpssytguof 1 300 train
+kpstxygjaf 0 301 train
+kpsxbmwfyv 1 299 val
+kptawiyrtr 1 300 train
+kptlnodcdb 1 300 train
+kptmhmbexi 0 300 train
+kptoxhoojf 1 300 train
+kpttbjxpqn 1 300 train
+kptybpvpxf 0 300 train
+kptzwwansv 1 300 train
+kpuakmdiie 1 300 train
+kpufyrwugr 1 300 train
+kpuklrhfcj 1 300 val
+kpuldjakep 1 300 train
+kpumkghqll 1 297 train
+kpumnbeqnh 1 300 train
+kpurgzhjzp 1 300 train
+kputxwfoxd 1 297 val
+kpuzatwdao 1 300 train
+kpvdllhzqe 1 301 val
+kpvlqlhdwr 1 300 val
+kpvvdydcev 1 300 test
+kpvwqqfzss 1 300 train
+kpvysfuhvp 1 300 val
+kpwculkvxi 1 300 val
+kpwhjcpkhg 1 300 test
+kpwhuuxcgl 1 300 train
+kpwohccsea 1 300 train
+kpwqqppymg 1 300 train
+kpwqugbnoh 0 300 train
+kpwudyslbr 1 241 train
+kpwvmeuvkd 1 300 train
+kpwwhpqfkx 1 300 test
+kpxfgblduw 1 300 train
+kpxgkvzrag 1 300 train
+kpxujltitc 1 299 test
+kpxvrnqsnj 1 300 train
+kpxxtxcazp 1 300 train
+kpxymrpgxe 0 300 train
+kpygyprrlu 1 300 train
+kpyhthwwbs 0 300 train
+kpykyjnwwz 1 300 val
+kpymuzbftx 1 300 train
+kpywkynrjy 1 300 train
+kpyyjmxmoj 1 300 train
+kpzavntlel 1 300 train
+kpzcfmqbcx 0 300 train
+kpzecdyhby 1 300 train
+kpzgnatqol 1 300 train
+kpzhosxvqv 0 300 train
+kpzupdeqzb 1 300 train
+kpzvepcvpv 1 301 train
+kpzzfztwrt 1 300 train
+kqabylejhe 1 300 train
+kqadjczzng 1 300 train
+kqamviihso 1 300 train
+kqapefqnnh 1 300 train
+kqaqujjdca 1 300 train
+kqatztogld 0 300 train
+kqauortnis 1 300 train
+kqbiejgili 1 300 train
+kqbnlnrzxx 1 300 train
+kqbpwnvvjc 1 300 train
+kqbstqpdst 0 301 val
+kqbtuywibk 1 300 test
+kqciwlqxjq 1 300 val
+kqcjqltrql 1 300 train
+kqcnjxhkfp 1 300 train
+kqcosusffn 1 300 val
+kqcqccdhul 1 241 train
+kqcxyyewep 1 300 val
+kqczjscrdm 1 300 train
+kqdcjtprry 1 300 train
+kqdfrirxbr 1 300 train
+kqdgbrfaau 1 300 train
+kqdhlgiauk 1 300 val
+kqdhsarbvc 1 300 train
+kqdjxgjodj 1 300 train
+kqdkmvplpu 1 300 train
+kqeaqekvbb 1 300 train
+kqedczfnqm 0 302 train
+kqedjggwcd 1 300 train
+kqekclcmnd 1 300 val
+kqekzprzvl 1 300 train
+kqengqmphn 0 300 train
+kqepmqpxmo 1 300 train
+kqetzheiep 1 300 train
+kqfaiaxafz 1 300 val
+kqffmsdgsg 0 300 val
+kqfhsniyug 1 300 train
+kqfmgvwigp 1 300 train
+kqfpeocxls 1 300 train
+kqgbzqtafz 1 300 train
+kqgcdjwdmb 1 300 train
+kqgeuoiiyo 0 300 train
+kqgihluusi 1 300 train
+kqglyumfzk 1 300 train
+kqgmianwmk 1 300 val
+kqgnmikzxr 1 301 train
+kqgrayrrao 1 300 train
+kqgtsmqbpa 1 300 train
+kqharllfus 1 300 val
+kqhhhplrrb 1 300 train
+kqhonufdwk 1 300 val
+kqibkytqav 1 300 train
+kqiineqoca 1 302 val
+kqiqdulrcu 0 300 val
+kqivuqbpad 1 300 train
+kqjckpllev 0 300 train
+kqjcuycosi 1 300 val
+kqjdzskjst 1 301 train
+kqjkdhjksu 1 300 train
+kqjqkcciwy 1 298 train
+kqjsssjqll 1 299 val
+kqjvgccwou 1 302 train
+kqkblcxaas 1 299 val
+kqkedvkxiu 0 300 train
+kqklkdaada 1 300 train
+kqkloetrzh 1 300 train
+kqkokbnszx 1 300 train
+kqkzvbsdni 1 300 train
+kqlcgqebdp 1 301 val
+kqlhcyobci 1 300 train
+kqlpuckbhx 0 300 train
+kqlvggiqee 0 300 test
+kqlxflempd 0 300 train
+kqnfqtxnci 1 300 train
+kqnhfrytab 1 300 train
+kqnhkmwbyo 1 300 train
+kqnkixpkex 1 300 val
+kqnuloxwny 1 297 train
+kqnvlydjgx 1 300 val
+kqnwutdvpd 0 300 train
+kqodvsytik 0 300 train
+kqoiygbfea 1 300 train
+kqojzcgrbc 1 300 train
+kqooxvrjpe 1 297 train
+kqoxwzvdgn 1 300 train
+kqoznjrund 1 300 val
+kqpabgbbcp 1 301 train
+kqpensnace 1 301 val
+kqpmzqkkuc 1 300 val
+kqpongirxu 1 300 train
+kqpppjhyqb 1 298 val
+kqpqevotdi 1 300 train
+kqprwlfsvh 1 300 train
+kqprxujjmz 1 300 train
+kqpyjqbmyl 0 301 val
+kqqadtuwzu 1 300 train
+kqqehipuno 1 300 train
+kqqhjppcsw 1 300 train
+kqqvbsxutx 1 300 val
+kqrgeujhxk 1 300 train
+kqrkeicucp 1 300 val
+kqrmfsqkce 1 299 train
+kqrnwizptc 1 300 train
+kqrolcboab 1 300 train
+kqrueihnta 1 300 train
+kqrwehyplx 1 300 train
+kqrxoqripz 1 300 train
+kqsckjtqle 1 300 train
+kqsdelqwbu 1 300 train
+kqsjsjvdyg 1 300 train
+kqsjsvinkd 1 300 test
+kqspqkonuk 1 239 train
+kqspzixyar 0 300 train
+kqsuzvvkxa 1 300 train
+kqtgbugagh 1 300 train
+kqtgplevgj 1 300 val
+kqthjhutfw 1 300 train
+kqtiirclbd 1 300 train
+kqtlolhabw 1 300 train
+kqtmvnxhjg 1 300 val
+kqtpbljvwy 1 301 val
+kqtrwybweg 1 298 train
+kqtveehysj 1 300 val
+kqtxdgdrol 1 297 val
+kqtxuuqpxx 1 301 train
+kquayldfeb 1 300 train
+kquembvlju 1 300 test
+kqulsjxhro 0 300 val
+kqvepwqxfe 0 300 val
+kqveudxgvj 1 300 train
+kqvfburfar 1 300 train
+kqvflvfzeu 0 300 train
+kqvrjglpou 1 300 train
+kqvztkasba 0 300 train
+kqwflqwnfm 0 301 train
+kqwmnqlfjf 1 300 train
+kqwxfglcgo 1 300 train
+kqxbsmkpkn 0 300 train
+kqxbthkapw 1 300 train
+kqxeplidmp 1 301 train
+kqxmagywnc 0 300 train
+kqxmqrzcvs 1 300 train
+kqxmtebgsm 1 298 train
+kqxqlbiskj 1 300 train
+kqxwlnytfh 1 300 val
+kqxykozvlg 0 300 train
+kqyeuaihff 1 300 train
+kqygkdbeey 1 300 train
+kqynuvnxmw 1 300 train
+kqyqgpauql 1 300 train
+kqyvnckpzn 1 299 train
+kqyvscimow 1 300 val
+kqyzhvcuyc 1 300 train
+kqzbkkboos 0 300 train
+kqzchexoru 1 300 train
+kqzeaaojiu 1 299 train
+kqzlcheyjj 1 300 train
+kqzorxfcim 0 241 train
+kqzsbwhgpo 1 300 train
+kqzwlhhcfd 1 300 train
+kqzwownrqh 1 300 train
+kqzwtgilmv 1 298 train
+krafcbrvbn 1 301 train
+kraonkanja 1 300 train
+kravfkhyfg 1 300 train
+kravjwtlnt 0 300 val
+kravugiqkg 1 300 train
+kraylusoss 1 300 train
+kraywetwrt 1 300 val
+krbdlemuzz 1 300 test
+krbdxferiy 1 300 test
+krbgpxdaal 0 300 train
+krbmjygvip 1 300 val
+krcahkpiwj 0 300 train
+krcawujhgx 1 300 train
+krcdaogpuv 1 300 train
+krcicabhwb 0 300 train
+krcmrghpiy 1 300 train
+krcprigjdj 1 300 val
+krcrmrtiss 1 300 train
+krcwkrxklr 1 300 train
+krcwnqcmyg 0 300 train
+krdgfockzt 1 300 train
+krdhyvukrg 1 300 train
+krdjchtrto 1 298 train
+krdqwwfaop 1 300 train
+krdrbvvlrk 1 300 train
+krdsrresci 1 300 train
+krdwaiuwml 1 300 train
+krejttudaw 1 300 train
+kremyiqjdi 0 300 train
+kretdpwvgp 0 300 train
+krevdgqbuz 1 300 train
+krexkbcndp 1 300 train
+krexqkiccb 1 300 train
+kreyyuqvje 1 300 train
+krfepdakbi 1 299 train
+krffmcgdsi 0 300 val
+krfikbkhck 1 300 train
+krfouhxwsm 1 300 val
+krfrzaghpv 1 300 val
+krfuaarffj 1 300 train
+krfyaaruhm 1 300 train
+krfyvinpmo 1 300 train
+krfzimyfws 1 298 train
+krfzpznfum 1 300 train
+krgalbqcsr 1 298 train
+krgcjlljxj 1 300 val
+krgdrnmezx 0 300 train
+krgtejyztc 0 241 train
+krgwthlzns 1 298 train
+krhlahbowp 1 300 train
+krhpfuxlne 1 300 train
+krhqhnxdpt 1 300 val
+krhvpeiueh 1 300 val
+krhwkeshpd 0 300 train
+kriabgdcvz 1 300 train
+kridorvyaq 1 300 val
+krifcuqyay 0 300 val
+kripvvxfwd 1 300 val
+kriulujgus 1 301 train
+kriuxhjrrm 1 300 train
+kriwnhdxla 1 300 train
+krjfecsubr 1 297 val
+krjgzlvlzt 1 300 train
+krjlcacojx 1 241 train
+krjnlcjctk 1 301 train
+krjpdezazg 1 300 train
+krjucerfjp 1 300 val
+krjxsqhshk 1 300 test
+krjzuziezw 0 300 train
+krkamnjist 1 300 val
+krkkaoqobz 1 300 train
+krkmoahpmx 1 300 val
+krlamyoiww 0 300 train
+krlhfgtjgr 1 300 train
+krlmmmwgnh 1 300 train
+krlosfjfpm 1 300 train
+krluoydxay 0 300 train
+krmenpqgjg 1 300 val
+krmeqcqcnb 1 300 train
+krmuzpxnbu 0 300 train
+krmwmnvwat 1 300 train
+krmwywvysg 1 301 train
+krmxlyfuwp 1 300 val
+krneyutinp 1 300 train
+krnhgqxkwo 1 300 train
+krnhpqtmiu 1 300 train
+krnisjmwns 1 301 train
+krnjodwmsb 1 300 train
+krnkcunqqa 0 300 train
+krnnelfkhu 1 296 train
+kroehvbrbd 1 300 val
+krojphsrok 0 300 train
+krooxscbam 0 300 train
+krormvaqye 0 300 train
+kroyxorqtz 1 300 train
+kroyztpegq 1 300 val
+krozjidepo 1 300 val
+krozjqwupz 1 300 train
+krpbbuhnwp 1 300 train
+krpcvryehy 1 299 test
+krpgmvouvw 1 300 train
+krplpzuxss 1 300 train
+krpqcpghry 1 301 val
+krptmrbezx 1 297 train
+krpynxnfaf 1 300 train
+krqweabkjx 1 300 train
+krqzboalln 1 300 train
+krrnydciaa 1 300 val
+krrxfxqahs 1 299 train
+krsezmgpcm 1 300 train
+krshdmroea 1 300 train
+krskhbqfxm 1 300 train
+krskrpdcad 1 300 val
+krsorcwelh 1 300 train
+krsqwgohxy 1 300 train
+krsrhspnuk 1 300 train
+krsyftoods 0 300 train
+krtcbagqri 1 300 train
+krtieukroj 1 300 train
+krtokxwylc 1 300 train
+krtpqcelgf 0 300 val
+krtsanfgvc 1 300 train
+krtsnoljze 1 300 train
+krtsygzllg 1 300 val
+krtwyczcan 1 300 train
+krueqiavpd 0 300 train
+kruqmzaqsa 1 300 val
+krurqawrev 1 300 train
+kruvzexqam 1 300 train
+krvaxgxbhq 1 300 val
+krvbwmboog 1 299 train
+krvetunxyz 0 302 val
+krviialzvc 1 299 val
+krvxgdktxr 1 300 val
+krvzccwvcq 1 300 train
+krwihcsnwm 1 300 train
+krwtsxpasu 1 300 train
+krwzbmqdtt 1 241 train
+krxaboisrq 1 298 train
+krxbkladav 0 241 train
+krxndiuane 1 299 train
+krxoilflwe 1 300 train
+krxoipopjy 1 299 test
+kryjshcqmc 1 298 train
+krykjfhbpj 1 299 train
+krynmxqbzq 1 300 train
+kryrpsthjp 1 296 val
+kryujcblfv 1 300 train
+kryxqdxfig 1 300 train
+krzdsjxyjf 1 300 train
+krzqizdgjv 1 298 train
+krzvphitmj 1 300 train
+ksaausdpbe 1 300 train
+ksacmynuby 1 300 train
+ksadzljwkj 1 300 val
+ksaivzcdrk 1 301 train
+ksaoehvsae 1 300 train
+ksasdgqsuy 1 300 val
+ksavlwzqeu 1 300 train
+ksbczvbqhy 1 300 train
+ksbjwyvigd 1 300 train
+ksboekkbls 1 300 train
+ksbtcwhead 1 296 val
+kscchcttix 1 300 train
+kscfwslynp 1 300 train
+kscgfownjj 0 300 val
+kschkvuucy 1 300 val
+kschtbpkmh 0 300 train
+ksckwxzbig 1 300 train
+kscoeoluiy 1 300 train
+kscpdaisdb 1 300 train
+kscupmybgf 1 301 train
+kscvkpnekn 1 300 train
+kscwlvoove 1 300 train
+kscyrfcuyo 1 300 train
+ksdctcehxh 1 300 val
+ksddrdgaee 1 300 train
+ksdgkzetwb 1 299 test
+ksdhikfraz 1 300 train
+ksdohprrko 0 300 train
+ksdqodntwc 1 299 val
+ksdvyuzqdi 1 300 train
+ksebsmydbg 1 240 train
+ksedvwytxh 1 300 train
+kseffrmenc 0 300 train
+ksekxsnvou 1 300 train
+ksepojnwsn 1 300 train
+ksesjqkhzv 1 300 train
+kseuobctla 1 241 train
+ksevvcocwp 1 301 train
+ksezqktegk 1 301 train
+ksfgswbvck 0 300 train
+ksfixouajv 1 300 val
+ksfkyiyrif 1 300 train
+ksfllaoifr 0 300 val
+ksfuiztwuc 0 300 train
+ksfvmolret 1 300 train
+ksfyrvchxj 1 300 train
+ksfzdewnkx 0 300 val
+ksgefastix 1 299 val
+ksghjeqxtv 1 300 train
+ksgtyuuxzg 1 300 train
+ksgwrgqrgi 1 300 val
+ksgxhtgsjf 1 300 train
+kshdqwkgtw 1 298 val
+kshexbxkqy 1 300 train
+kshkjrzams 1 300 val
+kshkocfkdr 0 300 train
+kshlyriwdh 0 300 train
+ksieftrsaz 1 300 train
+ksiftgzpxr 1 300 train
+ksinwykitt 1 300 train
+ksirojbwzg 1 300 train
+ksiwjygwrw 1 300 val
+ksixhxprbh 1 300 train
+ksiysmzgnl 1 300 train
+ksjchfxluc 1 300 val
+ksjdckvshl 1 300 train
+ksjdjkgkve 1 298 train
+ksjdmnkrwd 1 300 train
+ksjhytoorq 1 167 train
+ksjiwgddid 1 300 train
+ksjmvyddyh 0 300 train
+ksjnnjbouj 1 300 train
+ksjpgrujqv 1 300 test
+ksjtexrsuk 1 300 train
+ksjwdxgwwi 1 300 train
+kskooyetsh 1 298 train
+kskrctgahx 1 300 train
+kskxxzvrrj 1 300 train
+kskycpifdt 0 300 val
+kslfjqibrf 1 299 test
+kslgjwskxu 1 300 val
+kslnrgpzax 1 298 train
+kslpxkfrpc 1 300 train
+kslzlblirp 1 300 train
+ksmcctrbyj 1 300 train
+ksmdmleiqc 1 301 train
+ksnaneimlg 1 300 test
+ksndksdtpn 0 300 train
+ksneekqtzt 1 300 train
+ksnemqnwkw 1 302 train
+ksnhjzekbo 1 300 train
+ksnklrsvul 1 300 train
+ksnslzjpoe 1 300 val
+ksnxkofkfy 1 298 train
+ksnyodpbar 0 300 train
+ksogmhvotd 1 300 train
+ksohjbdhgd 1 300 train
+ksphilyouc 1 300 train
+kspjxpefrq 1 301 train
+kspmibcbkb 1 300 train
+ksppkhssez 1 300 train
+ksppwzyefv 1 300 train
+ksprwbilef 1 300 val
+ksqbmcfwso 1 300 train
+ksqjhkbcth 1 300 train
+ksqmzlotkf 1 300 train
+ksqttpgwgn 1 300 train
+ksquagjhxq 1 300 train
+ksqxmiqxwq 1 298 train
+ksqybmrwyg 1 300 train
+ksqyojunbe 1 300 train
+ksrchxowoi 1 300 train
+ksrnkgdxbv 1 300 train
+ksrnzzbcsz 1 300 train
+ksrsgyasdb 1 302 train
+ksrwphnfly 1 300 val
+ksryakzhhi 1 300 val
+kssaxxtmkg 1 300 train
+kssjbbrmem 1 300 test
+kssmtufmpm 0 300 val
+kssnusteqo 0 300 train
+ksssewdjzp 1 298 train
+ksswljnjcg 1 300 train
+kstaorcnic 0 300 train
+kstddunndj 1 300 train
+kstjcrrbds 1 300 train
+kstjjetwrf 1 300 train
+kstmekinaw 1 300 test
+kstoczbyzr 1 300 train
+kstorrocvg 1 300 train
+kstqwjzkft 1 300 train
+kstrpowvav 1 300 train
+kstwqhttcr 1 300 train
+kstwwfmgdo 0 301 train
+kstxilxppg 1 301 val
+ksuipkffpm 1 301 train
+ksukzenixh 1 300 train
+ksuwagezws 1 300 train
+ksuwunipsc 1 300 train
+ksuxvpsdeg 0 300 train
+ksvaotekjy 0 300 train
+ksvdqwaioe 1 300 val
+ksvdykglmc 1 300 train
+ksvibjmpni 1 300 train
+ksvqppeqcm 1 300 train
+kswayywkup 1 300 val
+kswbwsgoud 1 300 val
+kswetcwyss 1 298 train
+kswghclnmi 1 300 train
+kswiszkwki 0 300 train
+kswnnqrutp 1 300 train
+kswqxmqmqn 1 300 train
+kswxalumzl 1 300 train
+kswzebpkwi 1 300 train
+ksxaausoof 0 300 train
+ksxfufwplx 1 299 train
+ksxijjfcdq 1 300 train
+ksxnxsoonr 1 300 train
+ksxsqxhnww 1 300 train
+ksxvbgttnz 1 300 train
+ksykhmakyy 1 300 train
+ksyknkfzuv 1 241 train
+ksytxquudk 1 300 val
+ksyusmyapq 1 299 val
+ksyvbcodfc 1 300 train
+ksyvrepnua 0 300 train
+ksywjtiebv 1 300 train
+ksyyavokoz 1 300 val
+kszbjwgsby 1 300 train
+kszbuwupdl 1 300 train
+kszxfysbxp 1 300 train
+ktaailvunq 1 301 train
+ktaakgjlll 1 300 train
+ktacovvozp 1 300 val
+ktaetdruly 1 300 train
+ktafldulfb 1 300 train
+ktagooptgq 1 300 train
+ktahlkkhhr 1 300 val
+ktahytvzvl 1 300 val
+ktamugxlwy 1 241 train
+ktasbrxioe 1 300 val
+ktazdfvzxh 1 300 val
+ktbhfhchmg 1 300 train
+ktbphoramw 1 300 val
+ktbqtbuwsw 1 300 val
+ktbrplyuax 1 300 train
+ktbsegcghb 0 300 train
+ktbslrkbce 1 240 val
+ktbxvmcpqm 0 300 train
+ktcdquypov 1 301 train
+ktcdysrkpp 1 241 train
+ktcejywuds 1 300 train
+ktchrqxhlo 1 300 train
+ktcjlrxium 1 299 train
+ktcnctqrbr 1 300 train
+ktcpqdytve 1 300 train
+ktctecjuyz 1 300 train
+ktcyhakxfn 1 300 val
+ktczmqezyp 0 300 train
+ktdfrdpgsb 1 300 train
+ktdjkcftqv 0 300 train
+ktdklnmmro 1 301 train
+ktdknmmakm 1 300 train
+ktdrwvfkdv 0 300 train
+kteetwvqlv 1 300 train
+kteeyvdgkp 1 300 val
+ktefjscbmb 1 300 train
+kteoabjrha 1 301 train
+kteyirbiwc 1 297 train
+ktezvpxpao 0 300 train
+ktfmvdegkj 1 300 train
+ktfnhulmcj 1 300 train
+ktfqpdvghp 1 301 val
+ktfqrgopjv 1 301 train
+ktfxoeictt 1 300 train
+ktfysokjbw 1 300 val
+ktgakheylr 1 300 val
+ktgfbbghtf 1 300 val
+ktgfninnmp 1 301 train
+ktggxhgykk 1 300 train
+ktgioyysnx 1 299 val
+ktgyteecoa 1 301 train
+ktgyxkjubr 1 300 train
+kthiikwiii 1 301 val
+kthjyjiuuy 0 300 val
+kthmdwlcid 1 301 train
+kthmgbrozc 1 300 test
+kthokhsmzr 1 300 train
+kthtqknvpr 1 300 train
+kthyjjxgws 1 300 train
+ktibjtuyiy 0 300 train
+kticvunuab 1 300 train
+ktigstvyoy 0 300 train
+ktikdxgsun 1 299 test
+ktiltjolhw 1 300 val
+ktinhwqcym 1 300 train
+ktinottfdn 1 300 train
+ktisqxuleh 1 300 train
+ktiwinayfo 1 300 train
+ktjexqcmec 1 300 train
+ktjhioapdg 1 300 train
+ktjlzhypah 1 300 train
+ktjmfcxqyd 0 300 val
+ktjoendyit 1 300 train
+ktjsetopzq 0 300 train
+ktkjmqrvxt 1 300 test
+ktknobjyfc 1 301 train
+ktkutbntpj 1 298 train
+ktkzefbejz 1 300 train
+ktldtluama 1 298 val
+ktleqscxqe 1 300 train
+ktlfuovlcm 1 300 train
+ktlgpzhyij 1 300 train
+ktlkbjimki 1 301 val
+ktlpberdwq 1 298 train
+ktlqzbaesk 1 300 train
+ktlrrjwuna 1 300 train
+ktlssmizpx 1 300 train
+ktmcajxaws 1 300 train
+ktmdpragph 1 300 train
+ktmeotbcrd 1 300 val
+ktmgumjjou 1 300 val
+ktmluiowtd 0 300 train
+ktmmzmgvma 1 300 train
+ktmxluzxvp 1 300 train
+ktnaytdfst 0 300 train
+ktngjmgfut 1 300 val
+ktnjhftfpo 1 269 train
+ktnjyhlzpl 1 300 train
+ktnkoqfjeb 0 300 train
+ktnlqtwrdv 1 300 train
+ktnovgcglh 0 300 train
+ktnuxjqspw 0 300 train
+ktoiaelwgj 1 300 train
+ktokhbmbzp 1 300 train
+ktolivqnlx 0 300 train
+ktolkyuchy 1 241 train
+ktonqqjvjk 1 300 train
+ktoziuijnh 1 300 train
+ktpbvspyxz 1 300 train
+ktpfgjxkjy 1 300 train
+ktpjnkejhm 1 300 val
+ktplrnxprr 1 300 train
+ktplrsqjgb 0 300 train
+ktppwxfiql 1 300 val
+ktpsifsbge 1 297 train
+ktqdzqbzgm 1 300 train
+ktqkhqensy 1 300 val
+ktqqvsbsvv 0 147 train
+ktqridbbyo 1 301 val
+ktqvxxdyaj 1 301 train
+ktrbioavqb 1 300 train
+ktrfrcpjre 1 298 train
+ktrkpmnnlg 0 300 val
+ktrleojxlf 1 300 test
+ktrrihbdgp 1 300 train
+ktrrsqatcf 1 300 train
+ktsbmyurdw 1 301 train
+ktsernkjuz 1 300 val
+ktsexepquh 0 300 train
+ktsidkhnud 0 300 train
+ktsiezchda 1 300 train
+ktsjabctti 1 300 train
+ktsmigetsu 1 300 train
+ktsowyvltg 1 300 train
+ktspfobies 1 300 train
+ktspwavhqg 1 300 train
+ktsteiufun 1 300 train
+ktsuralgmr 1 241 train
+kttbhknmtp 1 300 val
+kttgpjwhqb 1 300 train
+kttkgxrcwr 0 302 train
+kttqsybvsi 1 300 train
+kttrqglpcz 1 300 train
+ktubtjwpca 0 300 val
+ktugarohtt 1 300 train
+ktujzthgpb 1 300 train
+ktunyfpghc 1 300 train
+ktuqvyqtax 1 300 val
+ktuuixbkyz 1 300 train
+ktvcgbilff 1 300 val
+ktvdplgwro 0 300 train
+ktvdyyelcb 1 298 train
+ktvfuhimqn 1 299 val
+ktvhcbnvlj 1 300 train
+ktvkhiijzq 1 241 train
+ktvmufyaqf 1 300 train
+ktvqmoploc 0 300 val
+ktvvpqqupl 1 300 test
+ktwfxtzjbn 1 300 test
+ktwkfhhqhd 1 300 val
+ktwncxyawq 1 300 train
+ktwogadnwr 1 300 train
+ktwqcrfeyc 1 300 train
+ktwqytqmmd 1 300 val
+ktwrnrnmhl 1 300 train
+ktwvmsdbam 1 300 train
+ktwvnwxpwl 1 300 train
+ktwxkwrivo 1 300 train
+ktwztwirmv 1 300 train
+ktxafitolf 0 300 train
+ktxbfmqsei 1 300 train
+ktxexxglgk 1 301 train
+ktxluramzl 1 300 train
+ktxlznkoeu 1 300 val
+ktxorburzs 1 300 train
+ktxrfshdgl 1 300 train
+ktxurhfxsy 1 300 train
+ktydfbehhh 0 300 train
+ktyjezetxr 1 300 val
+ktyjsnpvzh 1 300 train
+ktylgxijeg 1 301 train
+ktyoqqddwy 0 300 train
+ktyrkuiqeo 1 300 train
+ktyunfwnuv 1 300 train
+ktyzrmlpry 1 300 train
+ktzmeowvqp 1 301 train
+ktzqqczwlu 1 300 train
+ktzvbxfzmx 1 300 train
+kuaiujxqkh 1 300 val
+kuakvgktac 1 300 val
+kuaorfivth 1 300 train
+kuaoteityc 1 301 train
+kuapqkjzya 1 300 train
+kuatanwdch 1 300 train
+kuawgyerrt 1 300 train
+kubasdkleg 1 300 val
+kubdpfoudx 1 300 val
+kubfsxmecg 1 300 train
+kubscbyzay 1 300 val
+kubwhaokml 0 300 train
+kubzuvbjmk 1 300 train
+kucidldvst 1 300 val
+kuckixeqso 1 300 train
+kucmvbtlaf 1 300 train
+kucoqzfsnh 0 300 train
+kucosddfoi 0 300 train
+kucyhrzvlx 1 300 train
+kucyonhyim 1 300 train
+kudawjdwzq 1 300 train
+kudbhwulll 0 300 train
+kudjixvwmz 0 300 train
+kudprnomkm 1 300 val
+kudukdfvqj 1 300 train
+kudvvlgiff 0 300 train
+kudwvcrfpw 1 300 train
+kudyccoimg 1 301 train
+kudzyixxsm 0 300 val
+kueejzyctt 0 300 train
+kuefmneugs 1 300 train
+kuehazbwuc 0 300 train
+kuelhabsmz 0 300 train
+kuepdmmpye 1 300 train
+kuewdoyptn 1 288 train
+kuffngxyvg 1 297 train
+kufgoxqdlq 1 300 train
+kufjedpjyi 1 298 train
+kufnmiriex 1 300 val
+kufpfejdwa 1 300 val
+kufrfqqulg 1 300 train
+kufzletqqp 1 300 train
+kufzoapffv 1 298 train
+kufzsrdfrc 0 300 train
+kugfpimhcx 0 300 train
+kugjvnhxpe 1 300 train
+kugmfwrpoi 1 300 train
+kugswflarc 1 300 train
+kuheucdkst 1 301 val
+kuhkimzhfr 1 298 val
+kuhkrhjhjj 1 300 train
+kuhmnhkgix 1 300 train
+kuhopynref 1 300 train
+kuhqmymkcq 1 301 val
+kuhvklgurx 1 300 train
+kuhwtggmri 1 300 train
+kuihikronb 1 300 val
+kuilavcjwz 1 300 train
+kuimixwanz 1 300 val
+kuiqhbashf 1 300 train
+kuiscdpqpj 0 300 train
+kuitqwxsgf 1 241 train
+kuiurcmxdl 1 299 val
+kuiwngehwn 1 299 val
+kuiwtzvrqo 1 241 train
+kuixweepfb 1 300 test
+kujewkwdtr 1 240 val
+kujjwjaewk 1 300 val
+kujqyoyrtv 1 301 train
+kujrctpymx 1 300 train
+kujvvxpted 1 300 test
+kukfxxfuxw 1 300 train
+kukhpqacwc 1 300 train
+kukohwsimv 1 300 val
+kukscsidua 1 300 train
+kulhlphfrb 1 300 val
+kulmpcidkp 1 300 val
+kulniblyob 1 300 train
+kulouaaozf 1 300 val
+kulozbyxnt 1 300 test
+kulsfhiigr 1 300 train
+kulwzypdor 1 300 train
+kumfnjadhi 1 300 test
+kumhuypulx 1 300 train
+kumkssozaf 1 241 train
+kummqvwaax 1 300 train
+kumqlqovmi 1 300 train
+kumsrllezr 1 241 train
+kumstsuayh 1 301 train
+kumudcywnr 1 298 train
+kumvopyfhj 1 300 train
+kundvmyzou 1 300 train
+kunffnnlhv 1 300 val
+kuntbqilit 1 241 train
+kuoabeunqo 1 300 train
+kuokgeklnk 1 125 train
+kuoliszvvz 1 300 train
+kuoobhjmgf 1 300 train
+kuoraiutvy 0 241 train
+kuowsbnndg 1 301 val
+kuplvrqjkd 0 240 val
+kupmkzilbv 1 300 val
+kupmkzzfkq 1 300 train
+kuqbgbrypa 0 301 train
+kuqbporoxw 1 300 train
+kuqdhhxers 1 298 train
+kuqetimmsa 0 300 val
+kuqixpekfs 1 300 train
+kuqjdfmhit 1 302 train
+kuqjhtqprl 1 300 train
+kuqpyvryyr 1 300 train
+kuquamspph 1 302 train
+kuqxfkvnzp 1 300 train
+kuqxlbhcvq 1 300 val
+kureeyroub 1 300 train
+kurmerljte 1 300 val
+kurybyykbr 1 300 train
+kuryemfqdw 1 300 train
+kuryxaqwqz 1 300 train
+kusktcqily 1 300 train
+kustinuqny 1 300 train
+kuszszwvdk 1 300 train
+kuthbmqsmp 1 300 train
+kuthbtukcz 1 300 train
+kuthmsdkwd 1 300 val
+kutkduyqlm 1 300 train
+kutlyftigr 1 241 train
+kutmatymyw 1 300 train
+kutvmtyaxp 1 300 train
+kuugjjnzvb 1 300 val
+kuunlmwpoi 1 300 val
+kuuohzwhyh 1 300 train
+kuuswvzwtv 1 301 train
+kuuylhiqmg 1 300 train
+kuuzhiduim 1 300 train
+kuvauwlhcg 0 300 train
+kuvibtcdkg 1 300 train
+kuwdhvsoyl 1 300 val
+kuwprqphze 1 300 train
+kuwtukoczp 1 301 train
+kuwvfrxqaw 1 300 val
+kuwwgrlxaf 1 300 train
+kuxeuxuwqq 1 300 train
+kuxglynwko 1 300 train
+kuxiuolwxo 1 300 train
+kuxjzsttxh 1 300 val
+kuxlxisniw 1 300 train
+kuxrfqwhqg 1 300 train
+kuxvqogtkd 0 300 train
+kuxvsehhxc 0 300 train
+kuxxzjfism 1 300 train
+kuydemhyjy 0 300 train
+kuyeuwsext 1 300 train
+kuyfozlwvu 1 300 val
+kuyiecbmlm 1 300 val
+kuyjxpcwsq 1 299 train
+kuyowgtvvy 1 300 train
+kuypyeseeu 1 300 train
+kuyrregmbl 1 298 train
+kuywbgujuo 1 136 train
+kuzcdkyues 1 300 val
+kuzdfabnks 0 300 train
+kuzepboxuw 1 300 val
+kuzkknhjjw 0 300 train
+kuzlqnsjne 1 299 test
+kuzpeylqup 1 300 train
+kvaelhhfgr 1 300 val
+kvaidnruya 0 300 val
+kvajckdith 1 300 train
+kvajvgmref 1 300 train
+kvandbrfbu 1 300 train
+kvaprwizkk 1 300 val
+kvarzqvcab 1 300 train
+kvaspgbudq 1 300 val
+kvauwnejeb 1 300 val
+kvbicaaqot 1 300 val
+kvbkrkiwmz 0 300 train
+kvbmuuywfy 1 300 test
+kvbnrdcrkn 1 300 train
+kvbqjubgrt 1 300 train
+kvbqyqaqtp 1 300 val
+kvbsmrjsak 0 298 train
+kvbtmdtydx 1 300 train
+kvbtzqgiyh 1 301 val
+kvbxyspkym 1 300 val
+kvcnunaaob 0 300 val
+kvcrolixxf 1 300 train
+kvcserurrw 1 300 train
+kvctdchsuz 1 300 train
+kvctjyadrz 1 300 train
+kvcuajpirg 1 300 train
+kvcuyudczp 1 301 val
+kvcvndpudo 1 300 train
+kvcvxfqbvo 1 300 train
+kvcwpzfstd 0 300 val
+kvcxwgyiwm 0 301 train
+kvdbhvdjib 1 300 val
+kvdckuwuyw 1 136 train
+kvdgxhfnly 1 300 train
+kvdnaxkcbz 0 300 val
+kvdnzpwaen 1 300 val
+kvdxkqxyjn 0 300 train
+kvehgdcsej 1 300 train
+kvekfnbojk 1 300 val
+kveokkamsl 1 300 val
+kverutwcbw 1 300 train
+kveutrxkes 1 300 val
+kvfdleysdq 1 241 train
+kvfjqolqgv 1 300 train
+kvfkkcctax 1 298 val
+kvfnikeowy 1 300 val
+kvfvfdbbje 1 301 train
+kvfvqoyoff 1 299 val
+kvgcqccxzz 1 300 train
+kvgdzkixtj 1 300 val
+kvgfsugjoh 0 300 train
+kvgopiylbq 1 300 train
+kvgvtjgntt 1 300 train
+kvhaubpfex 0 300 train
+kvhbyuklfv 0 300 train
+kvhdpfzpon 1 300 train
+kvhfbesxqm 1 300 train
+kvhhyobklj 1 300 train
+kvhiyqccpl 1 300 val
+kvhkpkwfwk 0 300 train
+kvhqiaatsm 1 300 test
+kvhuckfvmk 0 300 train
+kvhwznqpkj 1 300 val
+kvidlzexqa 1 299 val
+kviesaqfdo 0 300 train
+kvietnmxfr 1 300 val
+kvikryidho 1 300 train
+kvilddnlfx 1 300 val
+kvimdrdtpf 1 300 train
+kvipktfypj 1 300 train
+kviukblvlg 1 300 train
+kviymjchga 0 302 train
+kvjaqgihat 1 300 train
+kvjgwdzhnv 1 300 val
+kvjigkxhfu 1 300 train
+kvjlzgvvws 1 300 train
+kvjpkscmgq 1 300 train
+kvjrcrsxwm 1 300 train
+kvjsthexya 1 301 train
+kvjywltiof 1 300 val
+kvkaxmgrfy 1 300 val
+kvkgwihmby 1 300 train
+kvkhdvvifo 1 300 train
+kvklczjukh 0 300 train
+kvkqqoxbej 1 300 train
+kvlcswnmwp 1 298 train
+kvldmtznjx 1 300 train
+kvlfhklrua 1 300 train
+kvlmbfssxs 1 300 train
+kvlnncsifn 1 300 train
+kvlpuskymw 1 300 train
+kvlvcqunqj 1 300 train
+kvmbnlewpr 1 300 train
+kvmiojraip 1 300 train
+kvmmepvfia 1 300 train
+kvmmmsyccu 1 300 train
+kvmpkajdru 1 300 train
+kvmpmhdxly 0 299 test
+kvmvkwnzae 1 300 train
+kvmxqzzizw 1 300 train
+kvmzlqfbcn 1 300 train
+kvnanercuo 1 300 train
+kvnbczjjcp 1 300 train
+kvnffasrei 1 300 train
+kvnlbsniql 1 300 val
+kvnnfpebdn 1 301 train
+kvnrcwelty 1 300 train
+kvnsctfpgm 1 300 train
+kvnvtfqldh 0 301 train
+kvnxaqrjgf 1 300 test
+kvnxcfkctx 1 299 test
+kvnxqoxyci 0 300 train
+kvnybortuz 1 300 train
+kvnypblepl 1 300 train
+kvodclrfch 1 300 train
+kvoeizmnbn 1 300 train
+kvofccfvay 1 301 val
+kvohnjaiqm 0 300 val
+kvoiwaedwd 1 298 train
+kvovjpgucm 1 300 train
+kvowohscey 1 300 train
+kvoxvhtglu 1 300 train
+kvpbmhvnwa 1 300 train
+kvpfhcphpu 1 300 train
+kvpgwfudix 1 299 test
+kvpgxhcewg 1 300 val
+kvpnkhlzuk 0 300 train
+kvpthktttf 1 300 train
+kvpybuxglo 1 300 train
+kvqbtnsjvi 1 300 train
+kvqezskdaq 1 241 train
+kvqhkpkbwd 0 300 train
+kvqjodnxqc 1 300 train
+kvqtesbopd 0 300 train
+kvqvmduqgn 1 297 train
+kvqwqcbiou 1 300 train
+kvqxiiemxo 1 300 val
+kvqxvzaqmu 1 300 train
+kvrdlwbdld 1 240 train
+kvrncaemvv 0 300 train
+kvsbhjdqam 1 301 train
+kvsgdbghke 1 300 train
+kvslbdyvxn 1 300 test
+kvslzyjejv 0 300 val
+kvsndnymhm 0 299 test
+kvsrouayjm 1 300 val
+kvstouhthx 1 300 val
+kvtbykcwsv 1 300 train
+kvtdcfpsdc 0 300 train
+kvtpwlelrs 1 301 val
+kvtrtolcvx 1 300 train
+kvttnipvjo 1 300 train
+kvtxaueqgq 0 300 train
+kvuevajdzf 0 300 train
+kvunxtjnjg 1 300 val
+kvusgrwugw 1 300 train
+kvuwnqtqhk 1 299 train
+kvuwxspozi 1 300 train
+kvvbbmqkld 1 300 val
+kvvbtsohwm 0 300 train
+kvvbxazeln 1 301 train
+kvvdwtclio 0 300 train
+kvvesbjqkd 1 300 train
+kvvsvzufok 1 301 train
+kvwdqffacb 0 300 train
+kvwfgcxdgg 1 300 val
+kvwflsxwac 1 300 train
+kvwusunqag 1 300 train
+kvwykkauxm 1 300 train
+kvwyzcngkj 1 300 val
+kvxdcbxdcd 1 300 test
+kvxmbnqkuc 0 300 train
+kvxmqlghdo 1 300 train
+kvxoojclth 1 300 train
+kvxrkxellk 1 300 val
+kvxxeohlzb 1 300 train
+kvyoetiwjj 0 300 train
+kvyssgzpyo 1 300 train
+kvyvazqlev 1 300 train
+kvyvdtwapi 0 300 val
+kvyxbnwaiv 1 249 train
+kvyzhxwwfb 1 300 train
+kvyzrqpihg 1 300 val
+kvzejjekmc 1 300 train
+kvzjhdtarp 1 300 train
+kvzmousokk 1 300 train
+kvzqzhxrnc 1 300 val
+kvzuxrtfkd 0 300 train
+kvzzhejuhs 1 300 train
+kwaktkfdxu 1 300 train
+kwapbrbhzl 1 300 train
+kwarcxdpzb 1 301 train
+kwashhmwyh 1 300 train
+kwaucvfnas 1 300 train
+kwbilvwtgy 1 299 train
+kwbowssmwq 1 300 train
+kwbvipecaa 1 300 test
+kwbwtvhqjf 1 300 train
+kwbzpvdtfe 1 300 train
+kwciqpupuf 1 301 val
+kwcsntexqm 1 300 train
+kwcspgwbbv 1 301 train
+kwcylalnbf 1 300 train
+kwdbvgqkmn 1 301 val
+kwdduinhpu 0 300 train
+kwdezvsfdm 1 300 train
+kwdgkwrvrl 0 300 train
+kwdjukteng 1 300 train
+kwdrxdztpp 1 300 train
+kwdsjwxqli 1 300 train
+kwdvxqigls 1 300 val
+kwdxmvetaf 1 300 train
+kwdzvcbhjt 1 300 train
+kwedhwysxx 1 300 train
+kwedkgkwki 1 300 val
+kwehcwaymb 1 300 train
+kweimubylr 1 300 train
+kwektzqcat 1 300 train
+kwevavqrup 0 300 val
+kwevbektjw 1 301 train
+kweyclluse 1 300 train
+kwfdyqofzw 0 299 test
+kwffekvdcc 1 301 train
+kwfjtkewpj 1 241 train
+kwfjzxlwly 1 300 train
+kwfklohybc 1 300 train
+kwfmfluhxq 1 300 val
+kwfntstogn 1 298 train
+kwfooyighx 1 300 train
+kwfrybsugq 1 300 val
+kwfvnxlxon 1 300 train
+kwgaqhzcer 1 300 train
+kwgbanctdq 1 300 train
+kwgbevkaet 1 300 train
+kwgcxdnvdj 1 300 train
+kwgdretqag 1 240 train
+kwggwxwirq 1 300 train
+kwghopkfcy 0 300 train
+kwghqmxhsl 1 300 val
+kwgoptfjwy 1 300 train
+kwhanxgsti 0 300 val
+kwhbmxqpyd 1 300 train
+kwhioqtaig 1 300 val
+kwhiouosjf 1 300 train
+kwhmexnexb 1 300 train
+kwhqaregef 1 300 train
+kwhvqlfceh 1 300 train
+kwhxnlfcmw 1 300 train
+kwhzfxbugv 1 300 val
+kwibbalctp 1 300 val
+kwifcxrbui 1 300 train
+kwifwmjyld 1 300 train
+kwigocueyo 1 300 train
+kwijuoikqk 1 300 train
+kwilwzrhxu 1 297 val
+kwimjoduve 1 300 train
+kwirwpgdnt 1 298 train
+kwivlwvree 1 300 train
+kwjbyjvlcr 1 300 train
+kwjcecbziu 1 300 train
+kwjmvtdgsp 1 300 train
+kwjpmwdkde 1 300 val
+kwjqhbnooe 1 300 train
+kwjwijwgav 1 300 train
+kwkfsgvclq 1 300 train
+kwkhohrbuc 1 300 train
+kwkjrvwhfs 1 300 test
+kwknmfjcix 1 298 train
+kwkocvppff 1 300 train
+kwkqosokdu 1 300 train
+kwkruxggan 1 300 train
+kwkxfgncsg 1 300 test
+kwlbvqubhz 1 300 train
+kwletdaogb 1 300 train
+kwmguhpgyo 1 299 test
+kwmjphovwe 1 300 train
+kwmkaiwaij 1 300 train
+kwmvssudkj 1 300 train
+kwmxvbhkwi 1 301 train
+kwmyiegkpc 1 240 val
+kwmymwxlei 1 300 train
+kwndtwzjyg 0 300 train
+kwnfzorxlv 0 300 train
+kwngozmnbu 1 300 train
+kwnxpvaqox 1 300 val
+kwnynjzmvo 0 300 train
+kwnzknmnsb 1 300 train
+kwobmfatrm 1 300 val
+kwodzpxxjj 1 300 train
+kwoizrcccy 1 300 train
+kwojbcsrxp 0 300 train
+kwolevjxed 1 300 train
+kwopoailtp 1 300 val
+kwouebfrqu 1 300 train
+kwovbiafin 1 300 train
+kwoyymfsfo 1 301 train
+kwpbkogrlt 1 300 train
+kwpdamvvbw 1 298 train
+kwpdqspfwl 0 300 train
+kwphjmsenz 1 300 train
+kwpjtvietw 1 239 train
+kwppzamydp 1 300 val
+kwprqsipok 0 300 train
+kwqdmpmiok 0 301 train
+kwqdzkbyoc 1 300 train
+kwqhorfuuv 0 300 train
+kwqjbgikku 0 300 train
+kwqmhdxrul 1 300 train
+kwqmmrgman 1 298 train
+kwqoibjdxp 1 300 val
+kwqovfzity 1 300 train
+kwqqjgrcjv 1 300 train
+kwqtclyong 0 300 train
+kwqzoiiojg 1 300 train
+kwrftshybi 1 300 train
+kwrjmgjamo 1 300 train
+kwrkjstvlv 1 300 train
+kwrltqfxwc 1 298 train
+kwrlvhvdxe 1 300 train
+kwsqhpxfge 1 300 train
+kwsraaqime 0 300 train
+kwsurvunlh 1 300 train
+kwszruxmwa 1 300 train
+kwtkwmnapm 1 300 val
+kwtnafmicd 1 300 train
+kwtwgpknir 0 300 train
+kwtwsktzsj 1 300 train
+kwtyjqiayr 1 300 val
+kwuawfmpkp 1 300 train
+kwuljirghd 1 300 train
+kwuniwqesl 1 300 train
+kwutfkcsng 1 300 train
+kwuubqdose 1 300 train
+kwuywxrciy 1 300 train
+kwvaoojpkj 1 300 val
+kwvdjgiuws 1 300 train
+kwveccqyyg 1 300 train
+kwvhnffffv 1 300 train
+kwvljmliee 1 301 train
+kwvpllescn 0 300 val
+kwvyddqgoo 1 288 train
+kwwbklisbi 1 300 val
+kwwdbsyzcv 1 300 test
+kwwfppkixy 1 298 train
+kwwopsvlkq 1 301 train
+kwwrpybezr 1 300 train
+kwwveltzqp 1 301 train
+kwwvkwbznd 1 300 train
+kwwwibveax 1 301 val
+kwwwyiyqzq 1 300 train
+kwwxeugxqt 1 300 train
+kwxgiifbqt 0 300 train
+kwxjncspoh 1 300 train
+kwxnrrocnb 1 301 train
+kwxovkqiht 1 300 train
+kwxpbatfiq 1 300 train
+kwyqbppbvh 1 300 val
+kwyripquko 0 300 train
+kwyvikrgmx 0 300 train
+kwyxuamigk 1 301 val
+kwzdyatjln 1 300 train
+kwzjmnnxst 1 300 train
+kwzmiysbax 1 300 train
+kxaktbsauw 1 300 train
+kxakxifevr 1 300 train
+kxampzfwbc 1 300 train
+kxarjtvlly 0 300 train
+kxatfeeueg 1 300 train
+kxaxlsonpe 1 300 train
+kxbdknapgt 0 301 train
+kxbeaeuwnm 1 300 train
+kxbembmtgx 1 300 train
+kxbezlngzt 1 300 train
+kxbkpndjeg 1 300 val
+kxbksekoed 1 300 train
+kxbthduwkj 1 300 train
+kxbyxeiiqe 1 300 train
+kxbzhypmum 1 300 train
+kxchlpfmuu 1 300 train
+kxchysmyhl 0 300 train
+kxcjeykzsz 1 300 train
+kxcjngsukr 1 298 train
+kxclsatqdn 0 300 train
+kxcsvkxltd 1 300 train
+kxctdbgngw 1 300 val
+kxdbixcyyv 0 300 train
+kxdenxfzpn 1 300 train
+kxdhtnjfyy 1 241 train
+kxdiveaars 1 300 train
+kxdjghjvxh 1 300 train
+kxdlyvdmtr 1 301 train
+kxdpjkzjsg 1 300 train
+kxdvofszdb 1 300 train
+kxejwuloil 1 300 val
+kxewunrmam 1 300 val
+kxfldtcbxo 0 300 train
+kxfsgbwnbc 0 300 train
+kxfuajzzdo 0 300 val
+kxfxwnpiqb 1 300 val
+kxgcybcdep 0 300 train
+kxgioybxrq 1 300 train
+kxgnktdoxs 1 301 train
+kxgqkakasv 1 300 val
+kxgqxceudw 1 299 train
+kxhdrbehre 0 300 train
+kxhexfuyfo 0 300 train
+kxhfhcrkbh 1 300 val
+kxhfionfwn 1 300 val
+kxhiiuysgg 1 300 train
+kxhmgxeymr 1 300 train
+kxhqkzzaxl 1 300 train
+kxhqohzkqt 1 299 test
+kxhtuxhvmi 1 300 val
+kxhwssipyi 1 300 test
+kxhylyinoq 1 300 train
+kxhzbeybsj 1 300 train
+kxihvcqpkn 0 600 train
+kxipsndrne 0 300 val
+kxirfiiaeq 1 300 val
+kxissmjepq 1 300 train
+kxiujrtrqs 1 241 train
+kxiwkztigw 1 300 train
+kxiyxqkbwp 1 299 train
+kxjdoagdqj 0 300 train
+kxjzjcxlkd 1 300 train
+kxjzykflnf 1 301 train
+kxkpozbwhz 1 300 test
+kxktvzlqdu 1 298 train
+kxlcjdoord 0 300 train
+kxldgmqnlb 1 300 train
+kxlehffktu 1 300 train
+kxlinejatf 1 300 train
+kxljculnyz 1 300 train
+kxlpngcejr 1 300 train
+kxlprsoigl 1 300 train
+kxlqpzjhst 1 300 train
+kxlwahnbyq 0 300 train
+kxlxizoohe 1 300 val
+kxmivxaoct 1 300 train
+kxmjtxeaep 1 300 train
+kxmlmyassq 1 300 train
+kxmlroxgjq 1 300 train
+kxmnxvzmjy 0 300 val
+kxmsgjcosz 1 299 train
+kxmvjkbemo 1 299 train
+kxmyczrayl 1 300 train
+kxmyydyoiy 0 300 val
+kxmzhikvir 1 300 train
+kxnfqjansf 1 300 train
+kxnhgtamku 1 300 val
+kxnsmwhqtl 1 300 train
+kxnwxdnoxu 1 300 train
+kxnybtbpkl 0 300 train
+kxocuspfpu 1 300 train
+kxogbpyucj 1 300 val
+kxogzgeqyk 1 300 train
+kxoiigclji 1 300 train
+kxojueoowk 1 295 train
+kxomcuqhmy 1 300 train
+kxoouvjilg 1 300 train
+kxopvnpqvm 1 300 train
+kxozkgpqlf 0 300 train
+kxpaazjfff 1 300 val
+kxpavclztu 0 300 train
+kxpawkoruz 1 241 train
+kxpcutyvty 0 300 train
+kxpikqvecz 1 300 train
+kxpjzkgktr 1 300 train
+kxpkynpmws 1 300 val
+kxppqyujvj 0 300 train
+kxprxomtcl 1 299 val
+kxptuwngop 1 300 train
+kxqgjfdebm 1 300 val
+kxqhiylfao 1 300 train
+kxqiwtdmbb 1 300 train
+kxqkaeizwl 1 300 train
+kxqlsmmqmb 1 300 train
+kxqmvdatkv 1 300 train
+kxqndyqxsc 1 300 train
+kxqnvgrxqu 0 300 train
+kxqpyldfzj 1 300 train
+kxqsdhdmjj 0 300 train
+kxqvmerjaa 0 300 val
+kxqwbmnuty 1 300 train
+kxqxhviipl 1 300 train
+kxqzeupdyz 1 300 train
+kxranclnuf 1 300 train
+kxrfdwfaeq 0 300 train
+kxriebupgl 1 301 train
+kxrklowoby 1 300 val
+kxrlbvaejj 1 298 train
+kxrolubbyy 0 300 val
+kxrqzswvvq 0 300 train
+kxrsvkaddq 1 301 train
+kxserhilpo 1 300 train
+kxsffyrkiq 1 300 train
+kxspftcepn 1 300 val
+kxsswwfcan 1 300 train
+kxsvprooaf 1 300 train
+kxsxcrfdzs 1 300 train
+kxteltrioh 1 300 train
+kxteplqxyk 0 300 train
+kxtkjfqlma 1 300 train
+kxtlzlwfsa 0 241 train
+kxtqjpqhjw 1 300 train
+kxtthemxip 1 300 train
+kxtuskzjmz 1 300 train
+kxtzjutjke 1 300 val
+kxubabxgoj 1 301 train
+kxujxasobq 1 300 train
+kxuybjovvm 1 300 train
+kxvcunmyed 1 241 train
+kxvhbrlzpm 1 300 train
+kxvluaeevg 1 300 train
+kxvnqzigyu 1 300 train
+kxvowszzuo 0 300 train
+kxvrmszevj 1 298 val
+kxvyibwboe 1 300 train
+kxwcgyfntb 1 298 train
+kxwhxonyqp 1 300 train
+kxwmaawawl 1 300 val
+kxwrffkwch 1 300 train
+kxwzdslzad 1 300 train
+kxwzxqowht 1 300 val
+kxxbzlzawn 1 300 train
+kxxcrzwiin 1 300 train
+kxxeiwshdw 1 300 train
+kxxhxvdeak 1 300 val
+kxxiuspacl 1 299 val
+kxxkrciffe 1 300 val
+kxxmiemhls 0 300 train
+kxxmijtqwn 1 601 train
+kxxrtnxiik 1 300 train
+kxxutslfec 1 300 val
+kxxwbsevie 1 241 train
+kxxwsjmepu 1 300 train
+kxyfnixexh 1 300 train
+kxykdyhxow 1 297 train
+kxyksjxnrd 1 300 train
+kxzasfgizt 1 300 train
+kxzgidrqse 1 300 test
+kxzioxavgp 1 298 train
+kxzlfgqfzz 1 298 train
+kxznqdhewk 1 300 train
+kxzthxhfgl 1 300 train
+kxzvtswktn 0 300 val
+kxzyciuuqa 0 300 train
+kyadqymepj 1 301 train
+kyadxujccy 1 300 train
+kyaejhghgm 0 300 train
+kyaijizqok 1 300 train
+kyairrflgg 1 300 train
+kyajzhnjjv 1 300 train
+kyakjhxoxe 0 300 train
+kyantkimbq 1 300 test
+kyartvdwqs 1 300 train
+kyatxtbrhs 1 300 train
+kyavdudyld 1 300 train
+kyavtyexlf 1 301 val
+kybbauytlk 1 300 train
+kybgwcuafr 1 300 val
+kybpujkrqa 1 300 train
+kybsfyuyyw 1 300 train
+kybvnompyv 1 240 val
+kycfivhnkr 1 300 train
+kycguftqix 0 300 train
+kycjiqjyos 1 300 train
+kyclcoxudc 1 300 train
+kycmqgqssf 1 300 train
+kycuhvvxty 1 300 train
+kycyvdwtqp 1 300 train
+kydcuirveh 1 299 train
+kydkdomuqf 1 300 val
+kydlpqfrvv 0 300 train
+kydmcatqof 1 300 train
+kydtueuqhh 1 300 val
+kydxknbtdp 1 300 train
+kyebtgoqdg 0 300 val
+kyectsmryr 1 147 train
+kyeewoffli 1 300 train
+kyeisbhtzf 1 300 train
+kyelvbfjei 0 300 train
+kyenuqeejo 1 300 train
+kyerhghbdq 1 300 train
+kyevsuzuem 0 300 val
+kyfwctavtq 0 300 train
+kyfyndhsvm 1 301 train
+kygacwfvpa 1 300 train
+kygcbdoedd 1 300 train
+kyggjfisyj 1 300 val
+kyggopwswh 1 300 val
+kygkgngiex 1 300 val
+kygmgbcrjg 1 298 train
+kygoggxvuq 1 300 val
+kygosechir 1 241 train
+kygqxoztzb 1 300 train
+kygtgeqhvm 1 300 train
+kygtjyjozh 1 300 train
+kygwadghkz 1 301 val
+kygxxcfecl 1 301 val
+kygzjuajlc 1 300 train
+kyhburireo 1 300 train
+kyhbwmyjtn 1 299 train
+kyhyoqnkuj 1 300 val
+kyidjwmity 1 301 train
+kyiekdvlmi 1 300 train
+kyifakevhk 1 300 train
+kyiivwctwe 0 300 val
+kyiklsipxj 1 300 train
+kyikoqijlt 0 300 train
+kyinkmzqas 1 300 train
+kyipwdbedm 1 300 train
+kyirqvfadb 1 300 val
+kyirwrjbsd 1 300 train
+kyisphqysj 1 300 train
+kyitsyzrme 0 300 train
+kyiunkmdpd 0 300 train
+kyjbwhecoc 1 300 train
+kyjfrkwzmy 1 300 train
+kyjftliybj 1 300 val
+kyjoepabtm 1 300 train
+kyjvosnnpe 1 300 train
+kyjwwytldk 1 300 train
+kyjydeuttn 0 300 train
+kykfgjhirn 1 300 val
+kykjynyqvn 1 300 train
+kyklrdulgk 1 300 train
+kykmrtoitd 1 300 train
+kyknzgpgvh 1 302 train
+kykofpdlbt 1 300 val
+kykojflkao 1 300 train
+kylfkbnvyr 1 300 train
+kylfxvgkdj 1 300 train
+kylhplopji 1 300 train
+kylihgrkex 0 301 train
+kylkchjfux 1 300 train
+kylnwddomq 1 301 train
+kylqyoxeqm 1 299 val
+kylrtistga 1 301 train
+kyltzmuzks 1 300 train
+kymloapbdc 1 241 train
+kympplvsgw 1 300 train
+kymucuduhj 0 300 train
+kynajpvbip 0 300 val
+kynisdudvh 1 300 val
+kynuygfmlh 0 301 train
+kynxwoterg 0 300 train
+kynyykjlwj 1 301 train
+kyoahgwfnp 1 300 train
+kyogpoarsx 1 300 train
+kyohluvykj 1 300 val
+kyoihwhooi 1 300 train
+kyonpqkuhx 1 300 train
+kyopmwtaqr 0 300 train
+kyoqfyiact 1 300 val
+kyorfjcikv 1 301 val
+kyorfmvcur 1 300 train
+kyoyqqtemj 1 300 val
+kyozbjbdan 1 300 train
+kypbxaowwj 1 300 train
+kypdormwra 1 301 val
+kypiwidnwt 0 300 train
+kypookzawx 1 300 train
+kypqqvwvvn 0 300 train
+kypsfzomjw 1 300 train
+kypxrzcpzx 1 300 train
+kypxxesehh 1 300 train
+kyqdabkhlq 1 300 val
+kyqibupien 0 300 train
+kyqzddhrkn 1 300 train
+kyradorwwn 1 300 train
+kyrbveruev 0 300 train
+kyreronwdr 1 300 train
+kyrildyxfg 1 300 train
+kyriuszlzq 1 300 train
+kyrixxcvfb 1 300 train
+kyrjcgtdnr 1 300 train
+kyrmvlmvfx 1 301 val
+kyrnhguexi 1 300 train
+kyrtlgwkrm 1 300 train
+kyrwbjjgoy 1 300 val
+kyseobpeim 1 300 train
+kysghtqyes 0 300 val
+kysjlkziba 1 300 train
+kyskvpsvcl 1 241 train
+kystnwgluu 1 300 train
+kysuvsrlei 1 300 train
+kyswyowwgb 1 300 train
+kysxawkest 0 300 train
+kyszarzcfg 1 300 train
+kyszeafcgb 1 300 val
+kyszyhnkij 1 295 train
+kytmjxjodz 1 300 train
+kytoyrhhqb 1 300 train
+kytpbjkrts 0 300 train
+kytqjymits 0 300 train
+kytsosuxou 0 300 val
+kytsyimetr 1 300 val
+kytvtbmaug 1 300 val
+kytwyrusew 0 300 train
+kytzoyblhx 1 300 train
+kyueoygidm 1 240 val
+kyugxlcymu 0 300 train
+kyuidvsxix 1 300 train
+kyunaekyik 1 300 val
+kyunsgrssk 1 300 train
+kyuntycryf 1 300 val
+kyuumoosro 1 300 train
+kyuywofmck 1 300 train
+kyuzllbpjw 1 301 val
+kyvlxwogtp 1 300 train
+kyvxzpwohk 1 300 val
+kyvydsxjdx 0 300 train
+kywaaiauiu 1 300 train
+kywkcmgtuh 0 300 val
+kywmrygswk 1 301 train
+kywrzlaqot 1 300 train
+kywvgklcul 1 300 train
+kywwpojzzs 1 300 train
+kywwxosbsq 1 300 train
+kyxapvaupf 1 298 train
+kyxemmeppi 1 300 train
+kyxfjuzlcq 0 300 train
+kyxklqbwnb 1 300 train
+kyxmtfyceu 1 125 val
+kyxqqazucy 1 300 val
+kyxvlwovgo 1 300 train
+kyychehozn 1 300 val
+kyykwaftqw 1 300 train
+kyyplhtepd 1 300 train
+kyysuucbox 1 300 train
+kyyykomocw 1 300 train
+kyyzjgfxlr 1 300 train
+kyzcgktdbx 0 300 train
+kyzjenzjgn 0 300 train
+kyzrpirjnn 1 300 val
+kyzudqvqyp 1 299 train
+kyzyltiodn 1 300 train
+kzajsnbfjn 1 301 train
+kzarnfaqzt 1 300 val
+kzatoiyzqi 1 300 train
+kzbbizohjj 1 299 val
+kzbeaeldsm 1 298 train
+kzbefaqcvj 1 300 train
+kzbgopcsci 1 241 train
+kzbiferkpx 1 300 train
+kzbogmyknr 1 299 val
+kzbqagtyqc 1 298 train
+kzbqeukvra 1 300 train
+kzbtvuzvom 1 300 train
+kzbwthqkzd 0 300 train
+kzbyefqvzh 1 301 train
+kzcasssofc 0 300 train
+kzchjhhckl 0 300 train
+kzchklafiy 1 300 train
+kzclqehcwb 1 300 val
+kzcnhvkopb 0 300 val
+kzcpbaknml 1 301 val
+kzcrsygmvs 0 300 train
+kzcvymocrb 1 301 train
+kzcxpenrly 1 300 train
+kzdeykbtus 1 301 train
+kzdocvizbx 1 300 val
+kzdrfmzvhq 1 300 train
+kzdsprxnbh 1 300 train
+kzdvuqacej 1 300 train
+kzdvzysxmu 0 300 train
+kzdxzezhri 1 300 val
+kzeaudeeom 1 300 train
+kzebhufsil 1 300 val
+kzebtgypqt 1 300 train
+kzedpchqhp 1 300 train
+kzejkmzzxh 1 300 train
+kzeltawxvr 1 300 train
+kzepfydppv 0 300 val
+kzesgcmzzm 1 300 train
+kzexpqtlku 1 300 train
+kzezrsewki 1 300 test
+kzfafrbfhg 1 301 train
+kzfghcmjks 1 300 val
+kzfrnpgwtk 1 300 train
+kzfvovouyb 1 300 train
+kzgftubvzq 1 300 val
+kzgfvvedjk 1 300 train
+kzgjrjukex 1 300 val
+kzglmuecdv 1 300 train
+kzgouiyozh 1 300 train
+kzgrvkueba 1 300 train
+kzhdgumeby 1 300 train
+kzhdjyvgkx 1 300 val
+kzheptictt 1 300 val
+kzhgbsnrpv 1 300 train
+kzhhviwkzo 1 300 train
+kzhjvmplby 1 300 train
+kzhlphzgid 1 300 val
+kzhmouvfzu 1 300 train
+kzhtepvrif 1 300 val
+kzibaxznnb 1 300 train
+kzihxvwsmy 1 300 train
+kzijeeirts 1 297 val
+kzikkzzval 1 300 train
+kzikuujllt 1 300 train
+kzikveqkud 1 300 train
+kzimidhlfc 0 300 val
+kzimphuypd 1 300 test
+kziolpwfue 1 300 test
+kziqnxiswn 1 300 val
+kziwktsxhx 1 300 train
+kzixeyhhtx 1 300 train
+kzjfafysat 1 300 train
+kzjhkkpmch 1 300 val
+kzjqjyxjba 1 300 val
+kzjsxbnazp 1 298 train
+kzjtxcefds 1 300 train
+kzjuzkmsyj 1 300 val
+kzjwshhnkn 1 298 train
+kzjysoofnm 1 300 val
+kzkahxopak 1 300 train
+kzkdlrpmgy 1 300 train
+kzkeckbqca 1 300 val
+kzkjzasyez 1 300 train
+kzkpvyfnbj 1 300 train
+kzkqjyioqf 1 300 train
+kzkqxqpmqd 0 300 train
+kzkzcuxiug 1 300 train
+kzlfjgfqrz 1 300 train
+kzlgbrclpb 0 300 train
+kzlldythox 1 300 train
+kzlmmxkbqu 1 300 train
+kzlvtanimu 1 300 train
+kzlyhfpnil 1 300 train
+kzmacengrr 1 300 val
+kzmlvznypt 0 300 val
+kzmwjpvgad 1 300 train
+kzmylbfxtx 1 300 val
+kzmywxbybr 0 300 train
+kznajacnvq 1 300 train
+kznbwkzjie 1 300 train
+kzndxsqhdi 1 300 train
+kznifirrqz 1 300 train
+kznjyibisr 0 300 train
+kzntrdxatr 1 241 train
+kzogihehct 1 300 train
+kzoiyebyzm 1 300 train
+kzojbxhemm 1 300 train
+kzompfjcwq 1 292 val
+kzosjeoedo 0 300 train
+kzousjvpzq 1 300 train
+kzowogriby 1 300 train
+kzozmqqzjb 1 300 train
+kzpdsiuuzq 1 300 train
+kzpkhwamco 1 292 val
+kzpoqqufaa 1 300 val
+kzpxnqzems 1 300 val
+kzpyvpuakt 1 300 train
+kzpzriyzwt 1 300 train
+kzqhzwolml 0 300 train
+kzqnfljlpa 1 300 train
+kzqnnztceu 1 300 train
+kzqqgctnoy 0 300 train
+kzqtqaspoe 1 240 val
+kzqyfljzfp 1 300 train
+kzqznorymf 1 300 train
+kzraurjfca 1 300 train
+kzrbfsoxtj 1 300 train
+kzrccrxrkj 1 300 train
+kzrcxxmwxt 1 300 train
+kzrjkklsin 0 300 val
+kzrnhpliaj 1 302 train
+kzrtmgygnq 1 300 train
+kzruxaefck 1 300 train
+kzrvdggflw 1 301 train
+kzrvlajeey 1 300 train
+kzrzgvkise 1 299 val
+kzsbawujer 0 298 train
+kzsbfekdpg 1 300 val
+kzshxutfbg 1 300 train
+kzsjqiorqf 1 300 train
+kzsncayjgo 1 300 train
+kzsoooiuxb 1 300 train
+kzsthcxtnq 1 300 train
+kztcysczln 0 300 train
+kztdoxvjkj 1 300 train
+kztdrlsyof 1 240 val
+kztejftipd 1 300 train
+kztgonlqey 1 300 train
+kztgvpxskr 1 300 val
+kztmwobiza 0 300 train
+kztwhaafok 1 300 train
+kztyvcecfp 1 300 train
+kzujeijgxc 1 300 train
+kzumnqhshb 1 300 train
+kzupellgtr 1 300 val
+kzuuaonyru 1 299 train
+kzvbrhdhca 1 300 train
+kzveulpfku 1 300 val
+kzvinhnqbh 1 300 train
+kzvtobnwzb 1 300 val
+kzvtudfgch 1 300 train
+kzvxkbqvfj 1 301 val
+kzvzrzyrsp 1 300 val
+kzwannudqe 1 298 train
+kzwlxdnxud 1 300 train
+kzwmumymkw 1 300 train
+kzwmxhplnd 1 300 train
+kzwpsznvwf 0 300 train
+kzwtvfxbct 1 300 train
+kzxavxanis 1 300 train
+kzxpndejui 1 300 train
+kzxurqbymj 1 300 train
+kzxxducnht 0 300 train
+kzycggjleq 1 300 train
+kzydcqhpql 1 300 test
+kzyejtxbud 1 300 train
+kzyqoesccm 1 300 train
+kzyswcsexk 1 300 train
+kzyymncvjg 1 300 train
+kzyynmdkzr 1 300 train
+kzzerkiiif 0 300 train
+kzzewzibdu 1 301 train
+kzzfhaarmy 1 300 train
+kzzilaaygs 1 300 train
+kzzmrgktaw 1 300 train
+kzznpnpsuf 1 298 val
+kzzqoaoooo 1 300 train
+kzzrdghppm 1 300 train
+kzzytxgshy 1 300 train
+kzzzequpdt 1 300 val
+laaaegtiku 0 300 train
+laajtlyura 1 301 train
+laarpodtry 1 300 test
+labjmmhqke 1 300 train
+labptdtslj 0 300 val
+labsbmiggg 1 301 train
+labvodsojl 1 300 train
+lacdsemozm 1 301 val
+lacelvudpn 1 300 train
+laclyckjxt 1 300 train
+lacsibmxoo 1 300 val
+lacuurfajw 0 301 train
+lacwjuhxby 1 300 train
+lacysohmqs 0 300 train
+ladafwlvgy 1 300 train
+ladjdgroxm 1 300 train
+ladjhvyigq 1 300 train
+ladnuitrey 1 300 train
+ladpdxhyeu 1 300 test
+ladwdrjkzc 1 300 train
+laefolwgra 0 300 train
+laeorjcbbd 0 300 train
+laepnhqkjd 1 300 val
+laeugkuxrj 1 300 train
+laezjityvv 1 300 train
+lafawkhxhi 1 300 train
+lafdvfnsob 1 300 train
+lafdyucwvu 0 300 val
+lafftwaoce 1 299 test
+lafoxxnlkt 1 300 train
+lafsnrurnk 1 300 val
+laftauhhnl 1 240 train
+laftelzwdu 1 300 train
+lafuomwezr 1 300 train
+lafydhwxpc 1 300 train
+lafzhxxrec 1 300 train
+lagaytbhyh 0 300 val
+laghodtoje 1 300 train
+laglgdftel 1 300 val
+lagnmizzrq 1 300 val
+lagnvmxexq 1 300 test
+lagwkzjwdl 1 300 val
+lagxgxjnil 0 300 train
+lagzvqjevr 1 300 train
+lahidhmmli 1 300 val
+lahrfljpue 1 300 train
+lahssvvsuf 1 300 train
+laihqoslma 1 300 train
+laihwpwiee 1 300 train
+laisokmcpi 1 300 train
+lajfaaenhi 1 300 val
+lajfcrkvdj 1 300 train
+lajhmhhhyj 1 300 val
+lajluoftvb 1 301 val
+lajpfpukbn 1 300 train
+lajsmnqznz 1 300 train
+lajuvbhurv 1 297 train
+lajwftyrml 0 300 train
+lakeqbnkhv 1 300 train
+lakgfkctah 1 300 val
+lakhvrwodn 0 300 train
+lakmzwcwgy 1 298 train
+laknyuomlm 0 300 train
+lakobgxkmp 1 297 train
+lakswdzpug 1 300 train
+laktekqvjo 1 300 train
+lakthcscey 1 300 train
+lakxvehimc 1 300 train
+lalhhivdea 1 300 train
+laljlawsoc 0 300 train
+lalkdmjmnw 1 300 val
+lalsvlverl 1 300 train
+lambzoqnwl 1 300 train
+lamilgnfxw 0 300 train
+lamlbxcrjq 1 299 train
+lammpmsywf 1 300 train
+lamofwnndg 1 300 train
+lamovzelwr 1 300 train
+lamoxzcpny 1 300 train
+lamxbgvzrs 1 300 train
+lamycblfft 0 301 train
+lamylbljvb 1 300 train
+lamzaegadx 1 300 train
+lanedqqpix 1 300 val
+langkfbayd 1 301 train
+laniiylape 0 300 train
+lanltosgtn 1 300 train
+lanoulpcmk 1 300 train
+lanyslnnss 1 296 train
+laoauaxcal 1 240 train
+laobunorxn 1 301 val
+laodnbqfdj 1 300 train
+laodzhkyrb 1 300 train
+laofvlstpo 0 300 val
+laojqujlsg 1 300 val
+laoqibggmh 1 300 train
+laoxooujkk 1 300 train
+laoyfuspvq 1 298 train
+lapazhyokx 1 300 train
+lapbrokvri 1 300 test
+lapcqbbwuu 1 300 train
+lapjgxrufj 1 300 train
+lapjljegrs 1 298 train
+laplbvrvwn 1 300 train
+laqgjooojl 1 298 train
+laqhokzxma 1 300 val
+laqigokfpl 1 300 train
+laqjcrrkxf 0 300 train
+laqlygroed 0 303 train
+laqvesrjsk 0 298 val
+larlahnisk 1 300 train
+larmhvyhye 1 300 val
+larshmfxyv 1 241 train
+larwnfncyq 0 300 train
+larzbmlbuj 1 300 train
+laskukekyz 0 300 train
+laslnyydno 1 300 val
+lasnomrrlr 1 300 train
+lasoktwjxo 1 300 train
+lasrqldmon 1 300 train
+lasszfurox 0 300 train
+lastrgwwxv 1 301 val
+lasucnprgi 1 300 train
+lasuunxboi 1 300 test
+lasyuwijjx 1 301 train
+latbsovkps 1 300 val
+latbyxbioo 0 300 train
+latselczds 1 300 train
+latwrvqqzg 1 300 train
+laubkbaeew 1 241 train
+laugsqcihw 0 300 train
+lauhmmtjki 0 300 train
+lauifordgs 0 300 val
+lauirwarpd 1 300 train
+laumqvjrgp 1 300 test
+laupbbdwmz 0 300 train
+lautmrhmin 1 239 train
+lauulmshvq 1 300 train
+lavccgvjjx 1 301 val
+lavdaiappn 1 301 val
+lavfmduxov 1 301 val
+lavkbgrukm 1 299 val
+lavkwuevnk 1 300 train
+lavnzallny 1 300 train
+lavqqeemqu 1 300 train
+lawdpxkvpy 1 300 train
+lawfymygda 1 300 train
+lawhopjppb 0 300 train
+lawlosmqvt 1 298 val
+lawnipsakn 1 241 train
+lawrvyrtbt 1 300 train
+lawtlbhflv 0 300 train
+lawtrihmzm 1 300 train
+lawxxudonx 1 300 train
+laxeomdwou 1 300 train
+laxfkwfywv 1 300 train
+laxfurjged 1 300 train
+laxjttpaea 1 300 train
+laxlpqhovd 1 297 train
+laxoxhpnbu 0 300 train
+laxtnqnnbm 1 300 train
+laxvcsetkn 1 300 val
+laxvfuytfn 1 300 train
+laxzxafhpm 1 297 train
+laybdbghfv 1 296 val
+layftsiufo 1 300 train
+laygayvzpx 1 300 train
+laynpnpmeo 1 300 val
+layowoihdg 1 301 train
+laytvmltyd 0 300 train
+layvlrbfnz 1 300 val
+layxaluscy 1 300 val
+lazrytnafg 1 300 val
+laztimnuiw 1 301 val
+lazyofgcmi 1 300 train
+lbacihfwqx 1 296 val
+lbagsgasgq 1 300 train
+lbahlrfswz 1 300 train
+lbaizmwrdl 1 300 train
+lbalxmqcpo 1 301 train
+lbanotpxhl 0 300 train
+lbapaexcrc 1 300 test
+lbaqljuzgt 0 300 train
+lbaqvldubx 1 301 train
+lbavhkpsph 1 301 train
+lbawmmqveg 1 300 test
+lbawqxabtx 0 300 train
+lbbhppglec 1 300 train
+lbbifmdbaf 1 300 train
+lbbsofshdu 1 300 val
+lbbtmzcuyu 1 300 val
+lbbxkmfjqw 1 300 train
+lbbxqmjeby 1 299 test
+lbcbswcfdd 1 300 train
+lbcbyrdjkv 1 300 train
+lbchwcyxix 1 300 train
+lbchzdzvks 1 300 val
+lbcijquzrd 1 300 train
+lbcmajcowr 1 300 val
+lbcromsctg 1 300 train
+lbcvjglgpa 0 300 train
+lbdbcqydfk 1 300 train
+lbdckxjucw 1 300 val
+lbdgkasimm 1 300 val
+lbdjgpqwwk 1 299 train
+lbdjuxuvoe 1 300 train
+lbdmlrdamb 1 300 train
+lbdpnfnqzk 1 300 train
+lbdsgizlfz 0 300 train
+lbdtcuswip 1 300 train
+lbdxzzckia 1 300 train
+lbebhmomvv 1 300 train
+lbebogglke 1 301 train
+lbeizhykvf 1 300 val
+lbeodffhlj 0 300 train
+lberhdyjtl 1 300 train
+lbfernokky 1 300 train
+lbfirzjowr 1 300 train
+lbflwoaoyu 1 299 val
+lbfqksftuo 1 300 test
+lbfqnvoqqh 1 300 val
+lbfumjhose 0 300 train
+lbfycqulxx 1 301 val
+lbfyoxprpc 0 300 train
+lbgfcmdliq 1 301 train
+lbgmryeglx 1 300 train
+lbgnipxpnx 0 300 val
+lbgohgvmlj 1 300 train
+lbgtofruyh 1 300 train
+lbgvtogpka 1 300 train
+lbgwpmpown 1 301 train
+lbhbghrhkn 1 300 train
+lbherxbspj 1 300 train
+lbheueqbcf 0 300 train
+lbhuumotgm 1 288 train
+lbigcunjai 1 300 train
+lbigytrrtr 0 300 test
+lbihjdswtl 1 300 train
+lbinkxefxo 1 300 val
+lbiprboxjx 1 300 test
+lbipvzwlut 1 301 train
+lbiqtadxgy 1 300 train
+lbiwnkffks 1 300 train
+lbizlvhouh 0 300 train
+lbjaypbogz 1 300 train
+lbjcikdfsu 1 301 val
+lbjdjmcnoz 1 300 test
+lbjdvtwdpe 1 300 train
+lbjesbbeuz 1 300 train
+lbjgcqbkgz 1 300 val
+lbjhueqjqb 0 300 train
+lbjkndnzbc 1 300 train
+lbjlsrqbbv 0 300 train
+lbjlvzpxkw 1 300 train
+lbjmlghnkt 1 300 train
+lbjmvsxruc 1 300 val
+lbjnaamjin 1 300 train
+lbjnzysfmf 1 300 train
+lbjofnophg 0 300 val
+lbjyebtbab 0 300 train
+lbjyragfls 1 300 test
+lbkbpmtqcc 1 300 val
+lbkvnpgdug 1 300 val
+lbkyeddffy 1 299 val
+lblaoukhmy 1 300 val
+lblixdkcqr 1 300 train
+lblizadwkn 1 298 train
+lblnaurkhp 1 300 train
+lblpusrxfe 1 300 train
+lblpuyasnp 1 300 train
+lblrfrqjac 1 300 train
+lblrnqfefq 1 300 train
+lblrymsaof 1 300 train
+lblsjsbeym 1 299 test
+lblutuitzf 1 300 train
+lblweiecpx 1 300 train
+lblzlrujtv 1 300 train
+lblzsydwit 1 300 val
+lbmbuypqaa 1 300 val
+lbmfchhtjq 1 300 train
+lbmlxkfzku 1 300 train
+lbmnlxrcph 1 300 train
+lbmwnookqb 1 300 train
+lbmxcbgbbo 1 300 train
+lbnagdkozn 0 300 train
+lbnhgcywcd 0 300 train
+lbnkgqmnrb 1 300 train
+lbnkpdvpfi 0 300 train
+lbnorhliji 1 298 train
+lbnpjbrovu 1 249 train
+lbnsoxhcav 1 300 train
+lbnurmcuxs 0 300 train
+lbnuxynggy 1 300 train
+lboalepbxp 1 300 train
+lboemtrbko 1 297 train
+lbokccsktn 1 299 train
+lbolzpgvov 1 300 val
+lbooddsyfl 1 241 train
+lboqnoayih 1 300 val
+lbovyrfmze 1 300 val
+lboxejvqyh 1 300 train
+lbpawrfnyh 1 298 train
+lbpdfegpqm 1 300 train
+lbpfomllae 1 298 train
+lbppqwqelz 0 300 train
+lbppsmfyvw 0 300 train
+lbpsijmimo 1 300 train
+lbqbhxxwpa 1 301 train
+lbqfkivkqr 0 300 train
+lbqhqdbzsz 1 300 val
+lbqhtfdhfr 1 300 train
+lbqrludiqd 1 300 train
+lbqrnzlzkx 1 241 train
+lbqskvhlch 1 300 val
+lbqtuxrvzx 1 300 train
+lbqwonpufw 1 300 val
+lbqzspawst 1 300 train
+lbrbngoekw 1 301 val
+lbrgxxvswd 1 300 train
+lbrlutazmo 1 300 train
+lbrxaaonqa 1 300 train
+lbryesqbhr 1 298 train
+lbsausmrjl 1 298 val
+lbscgwbzrl 1 300 train
+lbsdvxbrcs 0 300 val
+lbsltufgrh 1 300 val
+lbsmepuuyt 1 300 train
+lbsmijxkmt 1 300 train
+lbsqpqibxk 1 300 train
+lbsslmvykx 1 300 train
+lbsxldrbmm 1 300 train
+lbsyjisaod 0 300 val
+lbsymurptm 1 300 val
+lbtcxvrcwp 0 300 train
+lbthonvffl 1 300 train
+lbtnxtlfps 0 300 train
+lbufcuhqnt 1 300 train
+lbumdiutyp 1 300 train
+lbuomrrcgz 0 300 train
+lbuwnfpzky 0 300 train
+lbuwogzooa 1 300 test
+lbvconwraa 1 300 train
+lbvkbfdiid 0 241 train
+lbvmexxafz 1 300 train
+lbvpjkfemg 1 300 train
+lbvsreiamr 1 300 train
+lbvwmvvkqn 1 300 train
+lbwiwstqgi 1 300 val
+lbwjjruzkl 0 300 train
+lbwkauppxq 1 300 train
+lbwkgimbez 1 300 train
+lbwmciaztf 1 300 val
+lbwmvzraew 0 300 val
+lbwojyfexb 1 300 train
+lbwtduqqth 1 301 train
+lbwvzecphf 0 300 val
+lbwxtdxduw 1 300 train
+lbwzzntrcc 1 300 test
+lbxbstcwwl 1 300 test
+lbxfcmmmju 1 300 val
+lbxkexkqvu 1 298 train
+lbxnylolxy 1 300 train
+lbxtrlqmgf 1 301 val
+lbxyqbhcky 1 300 train
+lbxzrmgvfa 1 300 train
+lbyhrspkit 1 300 train
+lbyjvhhwup 0 302 train
+lbyukmndzx 1 300 train
+lbywhswpgc 1 300 test
+lbyxvxnkwu 1 300 val
+lbzasnzfhz 1 300 train
+lbzavxgnph 1 300 train
+lbzcmoxbpc 1 301 val
+lbzhwugumm 1 300 val
+lbzndgdxbv 1 300 train
+lbznpnwvbw 1 300 train
+lbzrhlxwei 1 167 train
+lbztzfhxuu 1 300 val
+lbzyuktruk 1 301 train
+lcadzcgupc 1 300 train
+lcanownakd 0 300 train
+lcapscbhtj 1 300 val
+lcapzqqsuf 1 300 train
+lcatozstpl 1 300 train
+lcavluowmf 1 302 train
+lcawidzlgm 1 241 train
+lcazaxwjuq 1 300 train
+lcbcjcfbet 1 300 val
+lcbkzoxmbw 1 300 train
+lcbsusnexz 1 300 val
+lcbykfjdyp 1 300 train
+lcbzsugujo 1 240 val
+lccbicazgk 1 300 train
+lccbmqgvjf 1 300 train
+lcceyptnwd 0 300 train
+lcchaliyve 1 239 train
+lccjeaeqkv 1 302 train
+lccmzlcvjw 1 300 val
+lccunsxtov 0 300 train
+lcdguqhxtb 0 300 train
+lcdjbhzvla 1 300 train
+lcdkepqawt 1 300 train
+lcdogjdxow 1 299 train
+lcdrsvfquk 0 241 train
+lcdwxnbwvj 1 301 train
+lcebinpxzn 1 300 val
+lcegpefqvk 1 300 train
+lceisumtjd 1 300 train
+lcejfttupr 1 300 train
+lcejqpmevk 1 300 train
+lcemnbpexb 1 300 train
+lceofuavwx 1 299 train
+lcetatgjlq 1 300 train
+lcewphddrf 1 300 val
+lcfcrgpiaa 1 300 train
+lcfeallqlh 1 300 train
+lcfikdgtrl 0 300 train
+lcfwkgjjko 0 300 val
+lcfxbfwonz 1 300 train
+lcgpbpdyzm 0 300 train
+lcgsihcudt 1 300 train
+lcguemezhh 1 301 train
+lcgzpgalop 1 300 train
+lchaueijja 1 300 train
+lchdbwoqwu 1 300 val
+lchkrtyohq 0 300 train
+lchmxzjjkj 0 300 train
+lchshnnoyb 1 300 val
+lchwnfddji 1 300 train
+lchxfwzdpa 1 300 val
+lcichiiawi 0 300 train
+lcijgcfvdx 1 300 train
+lcijjgtqrr 1 300 train
+lcimkktbsb 1 240 val
+lcipixrtmn 1 300 train
+lcivuxaiiy 1 300 train
+lcizhuffgc 1 241 train
+lcjfodnqal 1 300 train
+lcjiwuujru 1 300 train
+lcjjveygjf 1 300 train
+lcjjzbtiet 1 300 train
+lcjpcvctby 0 300 train
+lcjqoxhdvs 1 300 train
+lcjtcqmbvq 1 300 train
+lcjtgubzxn 1 300 train
+lcjvdkuiiw 1 300 train
+lckbvteskz 1 296 train
+lckjjtlhpv 1 300 val
+lckpyomxuq 1 301 val
+lckzahpllp 1 301 train
+lcleywyfhi 1 300 train
+lclgwlyngm 1 300 train
+lcloalkyrx 1 300 train
+lclrhuuwnj 1 300 val
+lclsnsrxup 0 300 train
+lclxizyita 1 301 train
+lclyxqctwg 1 300 train
+lcmaqjgmse 1 300 train
+lcmerlqabp 1 300 val
+lcmhkrhokb 1 241 train
+lcmjchynim 1 300 train
+lcmjyjdbqn 1 300 train
+lcmlizzbwo 1 301 train
+lcmlketlhl 0 300 val
+lcmrmtpayq 1 300 val
+lcmtixxkzd 1 300 val
+lcmutwpzve 1 249 train
+lcndemqsox 1 300 test
+lcndoxapjk 1 300 val
+lcneqkoznb 1 301 val
+lcnhlggddw 1 300 val
+lcnibninqg 1 300 train
+lcnmouwvcq 1 300 val
+lcnoyeenvo 0 300 val
+lcnytundba 1 300 train
+lconqdflxc 1 299 train
+lcowymgwgp 1 300 val
+lcoznjvffy 1 300 train
+lcpeyewsvl 1 300 test
+lcpjqjuvyd 1 300 train
+lcpkazptbe 1 300 train
+lcpkbezzkg 1 300 train
+lcpnxqptsa 1 300 train
+lcppbikeyq 1 300 train
+lcptrwocqi 0 300 train
+lcpxaziuhg 1 300 train
+lcqguoqxrb 1 300 test
+lcqimhcylj 1 300 train
+lcqjtryjzk 0 300 val
+lcqllakwdw 1 300 train
+lcqqawbmnn 0 300 train
+lcqrrrmhnl 1 299 train
+lcqsussosu 1 300 train
+lcqvhqfaji 1 300 train
+lcqvnjqyji 1 299 test
+lcqydrkdvh 1 300 train
+lcreqvvhja 1 300 train
+lcridqataq 1 300 train
+lcrkqdxnin 1 300 train
+lcrkvspjmk 1 300 train
+lcrtagiehq 1 300 val
+lcrtuazjgq 1 300 train
+lcrxfkezdg 1 300 train
+lcsbskccjf 1 300 train
+lcsdgmunwt 1 300 train
+lcsgwvpzgp 1 300 train
+lcsiickkjp 1 301 train
+lcskxgzkct 1 249 train
+lcskzcnbhg 1 300 train
+lcslpzxhmr 1 300 train
+lcsojymlot 1 300 train
+lcsqehuqlq 1 300 val
+lcssknfpel 1 301 train
+lctadvptrm 1 300 train
+lctgltfsnu 0 300 val
+lcthzklfhw 1 300 train
+lctlqbabqr 0 300 train
+lctmbwcoho 1 300 train
+lctrojihbc 1 299 val
+lctxavylvz 1 300 train
+lcuaqzuosr 0 300 val
+lcubertsau 1 300 val
+lcubueumvd 1 300 train
+lcuqagpkgi 0 300 val
+lcutrxuyzg 1 297 train
+lcuvarnwxw 1 300 val
+lcuxypgept 0 300 train
+lcuyzxpbkg 1 301 train
+lcvkqsoczm 0 300 train
+lcvltkguio 1 300 val
+lcvtpjkusg 1 300 train
+lcvwsdrhzh 0 299 val
+lcwhgoklxr 1 300 val
+lcwpkxdevw 1 300 train
+lcwrjirjzz 1 240 val
+lcwwdaaqlq 1 300 train
+lcwzotrptw 1 300 train
+lcxjhecrwq 1 300 train
+lcxsmhpfbm 1 300 train
+lcxvxzlrqa 1 300 train
+lcxxfyiobj 1 300 train
+lcyfeiefju 0 300 train
+lcygvjuntw 1 300 train
+lcygzzmijy 0 300 val
+lcyjrsfrfx 1 300 test
+lcytmaffdk 1 300 train
+lcytrktuxg 1 300 train
+lcytuzivrf 1 300 val
+lcyvxnirwa 0 300 train
+lcyypcvika 1 300 train
+lczciktans 1 300 train
+lczhglwidq 1 300 train
+lczkbwwart 1 300 train
+lczmqitlgd 1 300 train
+lcznirhyci 1 300 train
+lcznvwwrtc 1 300 train
+lczxgvazvr 1 301 train
+lczxtmerdn 1 300 train
+lczxunqhdo 1 300 train
+ldaaabkxrz 0 300 train
+ldaahdneqv 1 300 train
+ldakgqfroe 1 300 train
+ldaohvduxn 1 300 train
+ldaqjtsczu 1 300 train
+ldasdpxtjb 0 300 train
+ldayjylmsy 1 300 train
+ldayqxvwph 1 300 train
+ldbgthbsps 1 301 val
+ldbldpvjab 1 269 train
+ldbsmsgxch 1 300 train
+ldbvmsrpxt 1 300 train
+ldbvriseze 0 300 train
+ldbxonongx 1 301 val
+ldcdewxoes 1 300 train
+ldcihxxznw 1 300 train
+ldckbqdbuv 1 300 train
+ldclhbxrhd 1 300 train
+ldcpxcnimy 1 300 train
+lddcwhhszn 0 298 train
+lddozszaus 1 301 train
+ldeccxgyqn 1 301 train
+ldefkanmkf 0 300 train
+ldefmlfcdg 1 300 val
+ldetmmkruo 1 300 train
+ldezarsegt 1 300 train
+ldfcljydlh 1 300 train
+ldffodtquh 1 300 train
+ldfhdudjcj 1 300 train
+ldfihrnstj 0 300 train
+ldfrouxwls 1 300 val
+ldfvhnzcnh 1 300 train
+ldfwfcdulq 1 300 val
+ldgapvnmru 1 300 train
+ldgjjwxskw 1 300 train
+ldgkhykvif 1 300 train
+ldglvopiff 1 300 train
+ldguhpfsur 1 300 train
+ldgvehqkpu 1 300 train
+ldgxjgfrhj 1 300 train
+ldgyvmesld 1 300 train
+ldgzcqeyrm 1 300 val
+ldhdbuoejy 1 300 train
+ldhdtfbuip 0 300 train
+ldhnbuppfy 0 300 val
+ldhylgmuhd 1 300 train
+ldicddsxec 0 300 train
+ldieczfxql 1 300 train
+ldiqcgvqgj 1 300 train
+ldirrcafbx 1 301 train
+lditbgpdly 1 300 val
+ldivkyfnci 1 301 train
+ldixdiuwoh 0 300 val
+ldizaxllvr 1 300 train
+ldjcmotzod 1 300 train
+ldjflbmxmk 1 300 train
+ldjgncjzfw 1 299 train
+ldjhbsudib 1 300 test
+ldjkfuycqk 1 300 train
+ldjrbrgqql 1 300 train
+ldjsjdbjrz 1 300 train
+ldjtsczhoc 0 241 train
+ldjzrikuek 1 300 train
+ldklsbtqan 1 300 val
+ldkowblylm 1 300 train
+ldkqzyospt 1 299 test
+ldkxbstlac 1 300 train
+ldlcaucqhw 1 300 train
+ldllhthxnh 0 300 train
+ldlmvjvvmp 1 300 train
+ldlnjqegow 1 300 train
+ldloctgunu 1 300 val
+ldlooekesr 1 300 train
+ldlorjoyts 1 300 val
+ldlpdtwmif 1 300 train
+ldluuhmgvg 1 300 train
+ldlwlefhld 1 300 train
+ldlxxcfcvy 0 300 val
+ldmdjnvkjb 0 301 train
+ldmehcxveg 1 298 train
+ldmfupwexi 1 300 train
+ldmgwzlghm 1 300 train
+ldmjlmcevn 1 300 train
+ldmjtzcjin 1 300 train
+ldmkjxnpct 1 300 train
+ldmmqyutaq 1 300 train
+ldmoiyqtwd 1 299 test
+ldmoodikzl 1 300 train
+ldmprfuilo 0 300 train
+ldmxihjqta 1 300 val
+ldmznorbhe 1 300 train
+ldnapibjxv 1 301 train
+ldnbmcsxwv 1 299 train
+ldnbyjrhwx 0 301 train
+ldndyksvkt 1 301 val
+ldngvlhild 1 300 train
+ldninryhsh 1 300 train
+ldnknfmeck 1 300 train
+ldnkwmffsg 1 241 train
+ldnkxoswzu 1 300 train
+ldnxpcqrww 1 301 train
+ldoaprlmsq 1 300 train
+ldohyltjih 1 300 train
+ldoimhjogx 1 300 train
+ldojdgswqa 1 300 train
+ldolscylre 1 300 val
+ldomsanpgg 0 300 val
+ldonwzhrhg 1 298 train
+ldorvcvtms 1 300 train
+ldosgcwcyd 1 300 val
+ldoskfvcoe 1 300 train
+ldoubwctoy 1 300 val
+ldoxbzupoj 1 300 train
+ldpfwhrhcx 1 300 test
+ldpneakmqf 1 300 train
+ldpsunxnsj 1 300 val
+ldpuoyalqs 0 300 train
+ldpwlgxbfz 1 300 train
+ldqecgdsef 1 300 train
+ldqfppocrz 1 298 train
+ldqsqgnyol 1 300 train
+ldqvmhzyvi 0 300 train
+ldqygueerd 0 300 train
+ldrinwxert 0 300 val
+ldrkxggbed 1 300 train
+ldrnaydypn 1 241 train
+ldrutobvmg 1 298 train
+ldsexfwemc 1 300 val
+ldsmtvgmdj 1 301 train
+ldsorsepac 1 300 train
+ldstkidqpg 1 300 train
+ldsuhdoarq 1 241 train
+ldsunxtchf 0 300 val
+ldsvwroaru 1 301 train
+ldtbcomiab 1 300 train
+ldtgofdaqg 0 300 val
+ldtibsniik 0 300 train
+ldtihaxrwe 0 300 train
+ldtjvlhjdk 1 300 train
+ldtkxdqbtb 1 300 val
+ldtnjrqeaz 1 300 train
+ldtscpryms 0 300 train
+ldttffteee 1 300 train
+ldttilkfvi 1 300 train
+ldtwtuhgzz 1 296 train
+lduczwkytg 1 300 train
+ldufpxopfa 1 300 val
+ldumcerqdf 1 300 train
+lduxzipcuj 1 300 val
+lduypvhady 1 298 train
+lduzgyzaes 0 300 train
+ldvatorpzp 1 300 train
+ldvepizegx 1 300 train
+ldvgfuqfbr 1 300 train
+ldvgigslzg 1 300 train
+ldvjtwszhi 1 300 train
+ldvkytxxvn 1 300 train
+ldvsivfruq 1 301 train
+ldvtyirqec 1 300 val
+ldvvhkeshr 0 300 train
+ldwbjklfjm 1 300 train
+ldwgfsxbty 1 269 train
+ldwntpexco 1 300 val
+ldwtjdckpc 1 300 train
+ldwxjylmvu 0 301 train
+ldxagtmtqq 1 300 train
+ldxaiybgnx 1 300 train
+ldxeoxkuqb 1 301 train
+ldxevwpjba 1 300 train
+ldxnaemqsb 1 300 val
+ldxocmiruc 1 300 train
+ldxossgaus 1 301 train
+ldxupprqbq 1 300 train
+ldxvdsyugs 1 300 val
+ldxydczsxb 1 300 train
+ldyfkelqcn 1 300 train
+ldygpayfmp 1 300 train
+ldygtrfyyo 1 300 train
+ldyhecxuex 1 300 train
+ldypmfhsyr 1 300 train
+ldyrbbnxii 1 298 val
+ldyryrmjll 1 300 train
+ldyuqndngl 0 300 train
+ldyuzawxsm 1 300 val
+ldywnlcrlg 1 300 train
+ldzabkfyqj 1 300 val
+ldzpmgxeii 1 300 train
+ldzrfpjyct 1 300 val
+ldzwhfnwdx 1 300 val
+ldzxxwwaxc 1 300 train
+ldzxyuclwp 1 300 val
+ldzzxddzle 1 300 val
+leabqicrsg 0 301 val
+leagdgdmgi 0 300 train
+leampwttka 0 300 train
+lebhcgextb 0 300 train
+lebllfpewj 1 301 train
+lebqbfzvbn 1 300 val
+lebszoxool 1 300 train
+lebzjtusnr 1 300 test
+lecdwfkeza 1 301 val
+lecemakjln 1 300 train
+lecfjqrzpj 1 241 train
+lecgijnnra 1 298 val
+lechclcmwa 1 297 train
+lecjgdqkqm 1 300 train
+lecmisyxll 1 300 train
+lecotjgcsn 1 300 train
+ledddkfcbk 1 299 val
+ledwcahvbf 1 300 test
+ledydynbcs 1 301 train
+leecnrzodp 1 300 train
+leekjavohd 1 300 val
+leekzwugxw 1 300 train
+leenrzrrfs 0 300 train
+leeoienwxp 1 302 train
+leerzenlzq 1 300 train
+lefrotdttd 0 300 train
+leftxeykif 0 300 train
+lefyyuztoz 0 300 val
+legcdodock 1 300 val
+legegarybk 1 296 val
+legilvljip 1 301 train
+lehcfslwze 1 300 val
+lehdukjqpz 0 300 val
+lehirzymse 1 241 train
+leiaivngtt 1 300 train
+leiecxlhqz 1 300 train
+leifirzfiu 1 300 train
+leingqtuba 1 255 train
+leirdwkmqv 1 300 train
+leiwlaalez 1 300 train
+lejhbjohek 1 300 train
+lejikwpgwt 1 300 train
+lejjsomakh 1 301 train
+lejluauqlq 1 300 val
+lejnxfqhnl 1 300 train
+lejrkxqoxy 1 300 train
+lejssmnxls 1 300 train
+lejujtqqho 1 300 train
+lejvsficfs 1 300 val
+lejzouanmd 0 300 train
+lejzwfrfuv 1 300 train
+lekdrkgmfl 1 300 val
+lekerrfduk 0 300 train
+lekkxwdqdp 1 300 train
+lekpmobnzr 1 300 train
+lektyfijgx 1 297 train
+lekwvenbtt 1 300 val
+lelbefvdtb 1 300 train
+lelbusxdlj 0 300 train
+lelfdrvjad 1 300 val
+leljeavimg 1 300 train
+lelncdydjm 1 300 train
+lelrfkggds 1 300 train
+lelswvfgcf 1 300 train
+leluokcdvd 1 300 train
+lelxhkmeea 0 300 train
+lelyqjqmjx 1 300 train
+lemiuwfnmk 1 300 train
+lemnvllwuw 1 300 train
+lemqvgmmgt 1 296 train
+lemzmbuzbj 1 300 val
+leniyppbsk 0 147 train
+lenjqrjsho 1 300 train
+lenkbngyxw 1 301 val
+lenqnapony 1 300 train
+lenrpxoono 1 301 train
+lenuozooiz 0 300 train
+leoicyngqc 0 300 train
+leokuowcwf 1 300 train
+leolpikvdf 1 300 train
+leoqohpbef 1 300 val
+leospsirmn 0 300 train
+lepazquxoh 1 300 train
+lepcaxkmdg 1 300 train
+lepdlyfinf 1 300 train
+lepebnckiq 1 269 train
+lepkummoih 1 301 train
+lepmeylzpc 1 300 train
+lepqvhstws 1 300 val
+lepwpfefrv 1 300 train
+lepymemcss 0 300 train
+leqaaznhtq 1 298 train
+leqfomaphf 1 300 val
+leqiguaeab 1 300 train
+leqsjlcbyh 1 300 train
+leqxpppfxo 1 300 train
+lergxoxyna 1 300 train
+lerjgqpwfr 1 300 val
+lerjmloxre 1 300 train
+lerpmjrqgf 0 300 train
+leruraeqlk 1 300 train
+lerwjgaslm 0 300 train
+leryqdpnau 1 300 train
+leswbvawiu 1 302 train
+lesyspuqwa 1 299 test
+letkwgxnnl 1 300 val
+letukyywrx 1 299 train
+leuakvfdmj 1 300 val
+leudxrrcxq 1 300 val
+leuejftlvj 1 300 train
+leufyqrcbz 1 300 train
+leurankyic 1 300 val
+leurknulkb 1 300 val
+leuwpfqcwa 1 300 train
+leuxaewilr 1 300 train
+leuxqndrwq 1 300 train
+levfubvyhx 1 300 val
+levrhzdleq 1 300 train
+levyzeuzve 1 300 train
+lewavatapm 0 300 val
+lewcatrqbj 1 300 train
+lewemordqy 1 300 train
+lewfcyumbk 1 301 val
+lewgxsdrok 1 300 train
+lewhgbxwom 1 300 train
+lewizrkgtn 1 241 train
+lewoxkkdst 1 300 train
+lewzseskcf 1 300 train
+lexbzkffgy 1 301 train
+lexerfkkau 1 300 train
+lexhjexkbd 1 300 train
+lexkzglgdj 1 300 train
+lexkzhnvlu 1 300 train
+lexsbjnrga 1 300 train
+lexuivzvju 1 300 val
+lexusclwax 1 300 train
+lexwwbrzja 1 300 train
+leycoieybz 1 300 val
+leyfiqjyqp 1 300 train
+leyikhjkdl 1 300 train
+leymeqbzho 1 300 test
+leyrbovjjq 1 300 train
+lezbaroauu 1 297 train
+lezcunlftx 1 300 train
+lezebhwkpu 0 300 train
+lezkxyytil 0 296 train
+lezmvrttfp 1 300 train
+lezoiiqrcs 1 300 train
+lezolbxlrr 1 298 train
+lfacihvibc 1 300 val
+lfaeipaobp 1 297 train
+lfaghsvbbi 1 300 train
+lfasojwagr 1 298 train
+lfatxnpwgk 1 300 val
+lfaugsdlek 0 300 train
+lfaujjbhkj 1 300 train
+lfavylubvm 1 300 train
+lfayuxyqsb 1 300 train
+lfazrdbhwg 1 300 train
+lfbgdlvhme 0 301 train
+lfbgnwylfy 1 300 val
+lfbjzioqpj 1 300 train
+lfbmhzyldi 1 300 train
+lfbpkctemk 1 300 train
+lfbvwqwfdu 1 300 val
+lfbxgelruh 1 300 train
+lfcesukbyf 1 300 val
+lfcltjjmen 1 300 val
+lfcnrvontq 1 300 train
+lfcuniuhav 1 301 val
+lfcuzbpbme 1 301 train
+lfdjsbmfhq 1 300 val
+lfdmwuvcgy 1 300 train
+lfdnvyjryt 1 300 train
+lfdqnlrrfh 1 300 train
+lfdqzgeouj 1 300 train
+lfdsldcldf 1 300 train
+lfebjpyjvn 1 300 train
+lfecgkvspu 1 302 train
+lfefoblise 1 300 train
+lfejcahaps 1 300 train
+lfemwsypci 1 300 val
+lfeoebiyht 1 300 test
+lfeokaeaxl 1 300 train
+lfexwvajgl 1 300 train
+lfezkxuqdz 1 300 train
+lffbjekzzp 1 301 train
+lffhrnkhse 1 300 train
+lffkgiinds 1 300 val
+lfflgwzgov 1 300 val
+lffromlxxx 1 300 train
+lffvbyjimd 1 300 val
+lfgnzzkblu 1 300 train
+lfgwtrmjrg 1 299 val
+lfgwzncswb 1 300 val
+lfgyljbznn 1 298 train
+lfhcacjvtk 1 147 train
+lfhoiazzau 1 300 train
+lfhyiyirdj 1 300 train
+lfhylfpbem 1 300 test
+lfieqmffwz 1 300 val
+lfigrarene 1 300 train
+lfijyevfcq 1 300 train
+lfiuxgvxkf 1 300 val
+lfiwelzupa 1 300 train
+lfiyoyymnn 0 300 val
+lfjinhvepc 1 300 val
+lfjrbnrcot 1 300 train
+lfjwiittlk 1 300 val
+lfjwwyvwfo 1 300 train
+lfkdlirkdt 1 300 train
+lfknfgkztz 1 300 train
+lfkueenicm 1 300 train
+lflchzkymw 1 300 val
+lflczswguq 1 300 train
+lfleoypucd 0 299 train
+lfljtvgdoh 1 301 train
+lflqhsufkh 1 300 train
+lflzgjckta 1 300 train
+lfmakqrmqo 1 300 train
+lfmffuaqid 0 300 train
+lfmuyscjvs 1 300 train
+lfmxcavxhw 1 300 train
+lfmxlbqlsg 1 300 train
+lfnckostyr 0 300 val
+lfngvnzbau 1 300 train
+lfnuajhyxy 1 300 train
+lfnvgnmsxx 1 300 train
+lfojzdtuyb 1 300 val
+lfommaxeco 1 300 train
+lfopaeaajl 0 300 train
+lfoubkkevo 1 300 train
+lfozgqbcue 1 300 train
+lfpaxjolfv 1 300 train
+lfpbyzgvuq 1 300 val
+lfpgpeckzx 0 300 train
+lfplotmega 1 300 train
+lfpswgdzzw 1 240 val
+lfpwidyxim 1 300 train
+lfpwtzcqqs 1 300 train
+lfpzududjy 1 300 test
+lfqkdphwne 1 300 val
+lfqprxzaco 0 300 train
+lfqwipvpmf 1 241 train
+lfqwuoukyb 0 300 train
+lfqywknpmp 1 300 val
+lfrdfppcej 0 300 train
+lfrfzcjsru 0 300 train
+lfrogrspmg 1 301 train
+lfsghhbvgm 1 300 val
+lfsmnxvgtz 1 300 train
+lfswfminkh 1 300 train
+lfswgagulf 1 300 train
+lfsykmsrtl 1 300 val
+lfszpvcfch 1 300 train
+lftaudkamy 1 299 val
+lftgukbytl 1 300 train
+lftiqiamng 1 300 train
+lftkqegjob 1 301 train
+lftoneujss 1 300 train
+lftqnxobov 1 300 train
+lftqqjdmhr 1 300 train
+lftrreamyz 1 300 train
+lfttvkezox 1 301 val
+lftupxbged 1 136 train
+lfuoylafhw 1 136 train
+lfusruocgx 1 298 val
+lfuvwehcoz 1 300 val
+lfuzankmbf 1 300 train
+lfvfavnelx 1 300 val
+lfvikiacph 1 300 val
+lfvmalzbxb 1 300 train
+lfvmfaqnmc 1 300 val
+lfvobvqbdn 0 300 val
+lfvpvqaqmn 1 300 train
+lfvqgeormv 1 300 val
+lfvsfxqmym 1 300 train
+lfvvzweczk 0 300 train
+lfwffuahkl 1 300 train
+lfwhcmjscu 1 167 train
+lfwknricvc 1 300 train
+lfwllmfouk 1 300 train
+lfwrfmvgpn 1 300 train
+lfwzebjsmd 1 300 train
+lfxaxzsqxz 1 241 train
+lfxewjuwow 1 300 train
+lfxhbpecbl 1 300 train
+lfxiqdrmks 1 300 train
+lfxjiojtvf 0 300 train
+lfxkcmyzen 1 300 train
+lfxlnkxeun 1 300 train
+lfxpmsuqek 1 300 train
+lfybykwilm 1 300 train
+lfycoyqbuy 1 300 train
+lfyuuzvkru 1 300 val
+lfzaufknbs 1 300 train
+lfzbojghxa 1 300 train
+lfzdoxzqfv 1 300 train
+lfzfwgoinm 0 300 train
+lfziuvtnay 1 300 train
+lgakrjoryn 1 300 train
+lgaorclzlm 1 300 train
+lgbadkhwxi 1 300 train
+lgbhmzkgvn 1 298 train
+lgbmbhipms 1 300 train
+lgbmtowhli 1 299 train
+lgbncbacho 1 300 train
+lgbnqsbmmr 1 240 train
+lgbnsghoto 0 300 val
+lgbpnpdmse 1 300 train
+lgbxtwunoz 1 300 train
+lgbxwzcrpx 1 240 train
+lgcgvooqal 1 301 val
+lgcjbnnzdc 1 299 val
+lgcshibpzt 1 296 val
+lgcxzvppqs 1 300 train
+lgdabqkijt 1 300 val
+lgdlptqclj 1 300 train
+lgdmireaib 1 300 val
+lgdmndcvee 0 300 val
+lgdoenjhib 1 300 val
+lgdpxgfnmd 1 298 train
+lgdqpjgcqk 1 300 train
+lgdrrbdihe 1 300 train
+lgdryqnyml 1 300 val
+lgdtmwfudu 1 300 train
+lgdusxgszd 0 300 train
+lgdvvslzqy 1 300 val
+lgejhjovdw 1 300 train
+lgeqtbpsji 1 300 train
+lgeszwplgu 1 300 val
+lgewstjhru 1 300 train
+lgexartiib 1 300 train
+lgfiqaelue 1 300 train
+lgfxhototk 1 298 train
+lggaanrbpk 0 300 train
+lggbzoeowz 1 300 train
+lggjjvjasb 1 241 train
+lggsafwzpp 1 300 train
+lggtifpfap 1 300 train
+lggzpbikjj 1 300 val
+lghdcimpgu 1 300 train
+lghodqkraj 1 300 train
+lghoezmekk 1 300 train
+lghxrraqjj 1 300 train
+lghyxzzhyq 0 300 val
+lghzfhfxaf 1 300 val
+lghzvwilaj 1 300 train
+lgifxwwiss 1 300 val
+lgimdvqxaq 1 300 train
+lgityhcczl 1 300 train
+lgiuxymuhh 1 300 train
+lgiykrspyb 1 300 train
+lgjdijtenk 1 292 val
+lgjdksuddj 1 300 train
+lgjgvfxiat 1 301 val
+lgjmxefwpq 0 300 train
+lgjqenfkud 1 300 train
+lgjsrsihfc 1 300 train
+lgjtuooxmu 1 300 test
+lgjwrptfxi 0 300 train
+lgkageagiy 1 241 train
+lgkakqesov 1 300 test
+lgkfozyquu 0 300 train
+lgkfxlnxrd 1 300 val
+lgkqqktrjr 1 300 train
+lgksniqhis 1 300 val
+lgkxvzlsnh 1 300 train
+lgkyznxayb 1 300 train
+lglayylfcu 1 300 train
+lgldjpyjeq 1 300 train
+lglfuxiapl 1 300 train
+lgllabftfj 1 300 val
+lglrbqnoya 1 300 train
+lglvmmsztj 1 300 train
+lgmbsgzqqv 1 298 val
+lgmibtekph 1 300 val
+lgmkhtfmls 1 300 train
+lgmnvzyatg 1 300 train
+lgmppglbml 1 299 val
+lgmtjfgpgr 1 301 train
+lgmuapfhua 1 300 train
+lgmuyxupnn 1 300 train
+lgmxcngfyg 0 300 train
+lgmzijstqg 1 298 train
+lgncgzkcpo 1 300 train
+lgnebmhpby 1 298 train
+lgngfvswql 1 300 train
+lgngmarwtz 1 300 train
+lgngvfdvap 1 300 train
+lgnrjuaofm 0 300 val
+lgntqfklfx 0 300 train
+lgntwyjanc 1 300 train
+lgnxeyzclt 0 300 val
+lgoaetnjui 1 297 train
+lgoyltneud 1 300 train
+lgpehgmxom 1 300 val
+lgpfpttbki 1 300 val
+lgpjmkqwmt 1 300 train
+lgqfanavff 1 300 train
+lgqfyqkjhd 1 300 train
+lgqlkfrnuc 1 300 test
+lgqmbnwdrq 1 300 train
+lgqmdmflyd 1 300 train
+lgqrxgyiep 1 300 train
+lgqtocohmm 1 300 train
+lgqvghjztq 1 300 train
+lgqxinvuka 1 300 train
+lgraohftvw 1 300 train
+lgrhvxuqgy 1 300 train
+lgricnungz 1 300 train
+lgrjazxwnl 1 300 val
+lgrrdpwdde 1 300 val
+lgrvbambkr 1 300 train
+lgrvbicxcr 1 300 train
+lgscptipef 1 300 val
+lgsivowhce 1 300 train
+lgskahfkcb 1 300 train
+lgsmxidkje 0 300 val
+lgtbokgqsj 1 300 train
+lgtvynmift 1 298 train
+lgtwdcyttt 1 300 val
+lgtxdxnmdd 1 300 train
+lgtyozmgan 1 300 train
+lguaxcolie 1 301 train
+lgubusfcxz 0 300 train
+lguqmcyssv 1 300 train
+lgutwwyjtv 1 300 val
+lguuzkyehf 1 300 train
+lgvbdveuyj 0 300 train
+lgvgzncyfy 1 300 test
+lgvjtveroj 0 300 train
+lgvmsxivrl 1 300 val
+lgvpvxzbje 0 300 train
+lgvqjartda 1 300 train
+lgvylkvmdb 1 301 train
+lgvzgonqcq 1 300 train
+lgwhyevouk 1 300 train
+lgwkaereih 1 300 train
+lgwkjdthox 1 298 train
+lgwokwixfg 1 300 train
+lgwqffzhub 1 300 train
+lgwrhimtfj 1 300 train
+lgwtkzqltl 1 300 train
+lgwvrroocj 1 301 train
+lgxesvqirp 0 298 train
+lgxjxputug 1 300 train
+lgxkggfgri 1 298 val
+lgxoubaxnk 1 300 train
+lgxweyjnxq 1 298 train
+lgxwfxnqfh 1 300 train
+lgxwxzszpy 1 300 val
+lgxxzmmfjy 1 300 val
+lgydpnaufg 1 300 train
+lgygzgpanq 1 300 train
+lgyhtfojox 1 300 train
+lgyputrddd 1 300 train
+lgyqfumfhw 1 300 train
+lgyybhfedg 1 300 train
+lgzclplvnt 1 301 train
+lgzfdmimms 0 300 val
+lgziinbgrm 0 300 val
+lgzprsttbk 1 300 test
+lgztawyzgt 1 300 train
+lgzwdozeho 1 300 train
+lgzxvrgiup 1 300 train
+lhadwzmthb 1 300 train
+lhapfxcabo 1 300 train
+lhavhaqxti 1 302 val
+lhayhvqjmg 1 300 train
+lhbhhwhrtq 1 300 train
+lhbhnxfpyo 1 300 train
+lhbkelqnoa 1 300 train
+lhbppxooqt 1 301 train
+lhbrmieyng 1 300 train
+lhbspfslpq 1 300 train
+lhbwwfsixj 1 300 train
+lhcdmlbqou 1 300 train
+lhcecvneqx 1 300 train
+lhcktmbftr 1 300 train
+lhcmizahgs 1 300 train
+lhcojltrqg 1 300 train
+lhcybhuryg 1 300 train
+lhdfnmaptx 1 301 val
+lhdqfupbxo 1 300 train
+lhdtkllfrs 1 300 train
+lhdtsierbz 1 300 train
+lhdxbgteho 1 300 val
+lhdxfzuzrf 1 300 val
+lhefhyffdq 0 302 train
+lheggpjgwa 1 301 train
+lhelkzkcju 1 301 train
+lherlsdtcy 0 300 train
+lhezceprkm 1 300 train
+lhezjvaxig 1 300 train
+lhfdiftvbn 1 300 train
+lhfdvgvywd 1 300 train
+lhfgslevuy 1 300 val
+lhfngqvexu 1 300 test
+lhfoewkjfu 1 298 val
+lhfwyouedq 1 300 val
+lhgcuoqntg 1 299 train
+lhglvsajka 0 300 val
+lhgoghqmub 0 300 train
+lhgopyiojw 1 300 train
+lhgujlbkqr 1 300 train
+lhgxgjefgs 1 301 val
+lhhblffabv 1 300 test
+lhhcqhluxt 0 300 train
+lhhfibhlge 1 301 train
+lhhflkrcrb 1 300 train
+lhhjurmkfn 1 300 train
+lhhqmvyaax 1 300 val
+lhhxgytswd 1 300 train
+lhhzkikwok 1 300 train
+lhickumrzu 1 300 val
+lhidwmuooy 1 241 train
+lhifaggrzr 1 301 train
+lhimehjcrv 1 300 train
+lhimnmquqj 1 300 train
+lhipivaobq 1 300 test
+lhiqsyqjxu 1 298 train
+lhissglxli 1 300 train
+lhisvlunsz 1 300 train
+lhjbkcvfur 0 300 train
+lhjcaaaxbc 1 301 train
+lhjcdavmmg 0 300 train
+lhjclmpeyg 0 300 train
+lhjedpkurj 1 300 train
+lhjlyqnofv 0 300 val
+lhjqcarvdj 1 300 val
+lhjyjgraks 1 300 train
+lhkcvmclbt 1 300 train
+lhkczknelg 1 300 train
+lhkdjnnzzh 1 300 train
+lhkefkmxsq 1 241 train
+lhkklydpin 1 300 train
+lhklvngngj 1 300 val
+lhklzrbkns 1 300 train
+lhkqbslhqc 1 241 train
+lhksewixyd 1 299 test
+lhlbsqsdzf 1 300 train
+lhlccdpzyq 1 300 train
+lhlewwawgc 1 300 train
+lhlfshyxrp 1 300 train
+lhlhngsmam 1 300 train
+lhlmzjyvrh 1 300 train
+lhlsecdhax 0 300 train
+lhltkubrvr 1 300 train
+lhlufcqdpg 1 300 train
+lhlvztiygl 1 300 train
+lhlzvxfjup 1 300 train
+lhmasgvera 1 300 train
+lhmepffmzk 1 300 train
+lhmiyvrent 1 300 train
+lhmmwaigmr 1 300 train
+lhmpofvgej 1 300 train
+lhmsibscjv 1 300 val
+lhmxhsxtmp 1 300 train
+lhmyakkzwr 1 300 train
+lhnbcqhuqk 1 300 train
+lhnbfdrnhh 0 300 train
+lhncbtgvfi 1 300 train
+lhnoolzvoa 0 300 train
+lhntrtxyjl 1 299 train
+lhnuxnarti 1 300 val
+lhnvizywcr 1 302 train
+lhodrdmhix 1 300 train
+lhoiccuwdu 1 300 train
+lhopwatilk 1 300 train
+lhosimxpqc 1 301 train
+lhovgmdcxs 1 300 train
+lhozfukhiw 1 300 train
+lhozgvcxbp 1 300 val
+lhpdjvxthq 1 300 train
+lhpdzzituh 1 300 train
+lhpinnfqas 1 299 test
+lhpkjgtikn 0 300 train
+lhprshhyvo 1 300 val
+lhpwfocycv 1 300 train
+lhqcviyfji 1 301 val
+lhqfswriiy 1 300 train
+lhqgbwxviv 1 300 train
+lhqskrcynv 1 300 val
+lhqxuwestq 0 300 train
+lhqypymefm 1 301 train
+lhqzgsnvxw 1 301 train
+lhrdeqnnqh 1 242 train
+lhrdtpdqyt 1 300 train
+lhrfqnnpon 0 300 train
+lhrtljxmpk 1 300 val
+lhsekjxbxm 1 300 train
+lhseruyytu 1 300 train
+lhsfdajqrq 1 300 train
+lhsfyddoml 1 300 train
+lhspvbtkuj 1 300 train
+lhsqgcxfyt 0 300 val
+lhsuaiqgkm 1 241 train
+lhsvuzvmvl 1 300 train
+lhtbgiucxu 1 298 train
+lhtbzttpcj 1 300 train
+lhthyajxgf 1 299 train
+lhtjkjiyqy 1 300 train
+lhtohlvehk 0 300 train
+lhtpzwfnqc 1 300 train
+lhtsqtvtpm 1 300 train
+lhtwwnttbt 0 300 train
+lhtycppdmk 1 298 val
+lhucbkabai 1 300 val
+lhuopgwxmq 1 299 test
+lhurhgpffk 1 300 train
+lhvashzoru 1 300 train
+lhvdfdhmhw 1 300 train
+lhvjzhjxdp 1 300 test
+lhvlmcnhov 1 300 train
+lhvmynaabq 1 300 train
+lhvntwotfa 1 300 train
+lhvqwxgyfg 1 300 train
+lhvrpmfzrh 1 300 train
+lhvvsoopzz 1 300 val
+lhwdhgjgtd 1 241 train
+lhwgkpbkgp 1 300 train
+lhwgruznkt 1 300 train
+lhwjobsxta 1 301 train
+lhwmejzvaw 1 300 train
+lhwnchdcjc 1 300 train
+lhwnqbhyei 1 300 train
+lhwpsnzmah 0 300 train
+lhwwhjhyqx 1 300 train
+lhwwupeezi 0 300 train
+lhxiffvvze 1 240 train
+lhxlsbiccd 0 300 train
+lhxqihuixf 1 300 train
+lhxrjeynkd 1 300 train
+lhxshnawpw 0 300 train
+lhyflbfmoy 1 300 train
+lhylfsahql 1 301 train
+lhyoxzfwrz 1 301 train
+lhzicgtrjv 1 300 train
+lhziofawpb 1 300 train
+lhznzytgry 1 300 train
+lhzupqwwyw 1 300 train
+lhzvmslyxu 0 300 train
+lhzyxpetvj 1 300 train
+liaciwzxlw 1 300 train
+liafkksaer 0 300 train
+liaijxxewt 0 300 train
+liajelribh 1 300 train
+liajqqkpta 1 298 train
+liaobrcktb 0 300 val
+liarcyxqco 1 300 train
+liatfxbjlx 1 300 train
+liavrgdfru 1 300 train
+liawtrmvqj 1 300 train
+liawyvnzkv 1 300 train
+libkveeqmj 1 300 train
+libmahdeva 1 300 val
+libmsmajwz 0 300 train
+libqdcavvb 1 297 train
+libqjtyhwo 1 300 train
+libuupadiz 1 300 val
+libveqocal 1 299 train
+libzzgidoa 1 300 train
+licbjffirh 1 300 train
+licciftlgn 0 300 val
+liccnhjjvr 0 300 train
+licjtgdygk 1 300 train
+licmkxxorw 1 300 train
+licuyrxdia 1 300 val
+licyaanvrp 0 300 train
+lidetzyzjl 1 300 test
+lidfnjgwsz 1 298 val
+lidtnbnzko 1 300 train
+lidvputxql 0 300 train
+lidzpuchyx 1 298 train
+liebleqpiw 1 300 train
+liecdfvtry 1 300 train
+lieimcjeke 1 298 train
+lielpxdxcj 1 301 train
+lierfqvljh 1 241 train
+lietldeotq 0 300 train
+lievwdwxkb 1 300 train
+liezbuzmta 1 301 train
+lifbrgjtfs 1 300 train
+lifdytsjky 1 300 train
+lifgikqkee 1 300 train
+lifgmjcybk 1 300 test
+lifjflpich 1 300 train
+ligauehciq 1 300 val
+ligbregedh 1 301 train
+ligclvdmtv 1 300 train
+ligfahzqwe 1 300 train
+ligiuhyfsy 1 300 train
+liglqsrgib 1 300 val
+ligpaqbycq 1 300 train
+ligsfdpnbq 1 300 train
+liheortwbu 1 300 test
+lihihnkntm 0 300 train
+lihikdletj 1 300 train
+lihimbabnm 1 300 train
+lihlszypgp 1 300 train
+lihrgmqrff 1 298 train
+lihvznfdxy 0 300 val
+liiphzhvez 1 300 train
+liitmtnuvb 1 300 train
+liiymssblw 1 300 train
+lijccmxacw 1 300 train
+lijfcncczj 1 300 train
+lijhbmtmfl 1 300 train
+lijkyzdndx 0 300 train
+lijodtitxz 0 300 train
+lijpeujqot 1 301 train
+lijrgcicxo 1 300 train
+lijwxyecja 1 300 train
+likanfmhkm 1 300 train
+likcwtxjbb 1 300 train
+likgrgbgrk 1 300 test
+likhvpxanp 0 300 train
+likrsqenig 1 300 val
+likwbnnnli 1 300 train
+likxmbtcon 1 300 train
+likyruhpjb 1 300 train
+likzpmdjak 1 300 train
+lilanxqzsm 1 300 val
+lilcnnkhjb 1 237 train
+lilcuunwet 1 300 train
+lildtedrec 1 300 val
+lilisowagc 1 300 train
+liloryfkmk 1 241 train
+lilqpinovo 1 300 val
+lilwdyktoa 1 300 train
+lilzprpwez 1 300 val
+limbqbfbyv 1 300 val
+limdeyymym 1 300 train
+limfkjjjtz 1 300 val
+limflrfank 1 300 val
+limfpbujtk 1 300 train
+limkbtqkbq 1 300 train
+limkffcjki 0 300 train
+limkkqtecc 1 300 val
+limouabtda 1 300 train
+lindhffzkp 1 300 train
+linfqpzlbh 1 300 train
+liniegczcx 0 298 train
+linkoikqwo 1 300 val
+linnmxvibu 0 300 train
+linoanfcal 1 300 train
+linrqnplfo 1 300 train
+linuresbpk 1 300 train
+linwyxqngg 1 301 val
+liofxthbkk 1 301 train
+liorpjcram 1 300 train
+lioxyqtfna 1 301 train
+lioylftclv 1 300 train
+lipjottfco 1 300 val
+liplvjpyew 0 300 train
+lipvfcfusx 1 300 train
+lipwxxllue 0 300 val
+lipzdvhewv 1 300 train
+lipzzgzure 1 300 train
+liqicrjmgp 1 300 train
+liqjhqqzmt 1 300 train
+liqoyhafvf 1 300 train
+liquekzujn 0 300 train
+liranljgjo 1 300 train
+liraruefay 1 299 train
+lirclscpfu 1 300 train
+lirihnvayp 1 300 train
+lirijrgbnm 1 300 train
+lirjchjbll 1 300 train
+lirjslerep 0 301 train
+lirvejvygy 0 300 train
+lisahsoohl 0 300 val
+lisbkafrvj 1 301 train
+lisbuvwyvg 1 301 val
+lisgjwueqv 1 300 val
+lisjicmknp 1 300 train
+lisljbiezp 1 300 train
+lisljpaixu 1 300 train
+lispjtnprs 1 300 train
+listkrowrn 1 300 train
+listvvcsxj 1 300 train
+litakpzghb 1 300 test
+litbmmqiuh 1 300 train
+litcgxfibk 1 300 train
+litkwywxfg 1 300 train
+litobdljrt 1 300 train
+liuadwpciu 1 301 train
+liucvdigif 1 300 val
+liuherxggz 1 300 train
+liuposlbzt 1 300 train
+liureznisp 0 300 train
+liuujwwgpr 1 300 val
+liuxjgdcqh 1 300 train
+liuycbrnwy 1 300 val
+liuyprmjlo 1 298 val
+livfyzzxsj 1 300 train
+livkyxaslq 1 301 train
+livrpbltef 1 300 train
+livxzjtmmh 1 300 train
+liwbxcnlfc 1 300 train
+liwjjdhggc 1 300 val
+liwkgmampt 0 300 train
+liwnbexxlg 1 300 test
+lixfkxresa 1 300 train
+lixldshqhu 1 301 train
+lixlhvjwby 1 300 train
+lixmvuauvp 0 300 train
+lixnoghcaj 1 300 train
+lixokokrpg 1 300 train
+lixxjfrzig 1 300 train
+liybarpvcb 1 300 train
+liycyqbnux 1 300 train
+liydqeovvr 1 301 train
+liynjxljcy 1 300 train
+liypzhwdza 1 300 train
+liyvxlwvei 0 300 val
+liyxtbkpsi 0 300 train
+lizknrgdff 1 300 train
+lizpuoccho 1 300 train
+lizqddywxz 1 301 train
+liztigsszz 1 240 train
+lizwqdfukb 1 237 train
+lizxanuhpa 1 300 train
+ljaaicoglm 1 300 val
+ljaifbsfuw 0 300 train
+ljajsmujna 1 300 train
+ljambawfzx 1 300 train
+ljauauuyka 0 300 test
+ljbdjmqqam 1 299 train
+ljbdywukfr 0 300 train
+ljbgvdfjoz 1 300 train
+ljbmnepoiz 1 300 train
+ljbpakdbhq 1 301 train
+ljbtqlsgot 1 300 train
+ljcafhkuti 1 300 val
+ljcdnoqowh 1 300 train
+ljcjiehoav 1 300 train
+ljcjouvznz 0 300 train
+ljcrzjavmv 1 300 val
+ljcswtsdat 1 300 train
+ljcuakusdh 1 300 train
+ljcuqhvssf 0 300 train
+ljcuyukzpx 1 167 train
+ljcxcafkrn 1 300 train
+ljdgxwuvia 1 300 train
+ljdwegxppl 1 300 train
+ljdxulukns 1 301 val
+ljdzuakwor 1 300 train
+ljeapddvuv 1 300 train
+ljebxaetsk 1 300 train
+ljedchviiy 1 300 train
+ljeezbryke 0 300 train
+ljemyykxsk 1 300 train
+ljengeqthj 0 300 train
+ljenlvwnlm 1 300 test
+ljeqaxtwiu 1 300 train
+ljeqmqyttf 0 300 train
+ljfazrltza 1 300 train
+ljfhhshqbu 1 300 val
+ljfmdappex 1 300 train
+ljfodoanqq 0 300 train
+ljftfhqcym 1 300 val
+ljfwffhbvd 1 300 train
+ljfwkqyopm 1 300 val
+ljgdyjfvje 1 300 train
+ljgfrgtxta 1 300 train
+ljgjtzouac 1 300 train
+ljglqrhqgv 1 297 val
+ljgouqcbxi 1 299 test
+ljguanvlml 1 300 val
+ljhaqgiggk 1 301 train
+ljhffglopa 1 300 val
+ljhmrrvqkt 1 300 train
+ljhnagllap 1 300 val
+ljhyapikru 1 300 train
+ljiawnbhch 1 300 train
+ljicatxyfk 0 300 val
+ljieiulczn 1 300 val
+ljieqsssjp 1 300 train
+ljigonxihx 0 300 val
+ljihktujcz 1 300 train
+ljiohovavc 1 301 train
+ljjoeunhkt 1 300 val
+ljjoslwtku 0 300 train
+ljjrqrpbce 0 300 train
+ljjrqszpna 1 300 val
+ljjuxvbukg 1 301 train
+ljkbcwdusn 1 300 train
+ljkbmkjsrw 1 300 train
+ljkeaiwyiv 1 300 train
+ljkfbaybdu 1 300 train
+ljkjnwrzxv 1 300 test
+ljkojsckvg 0 300 train
+ljkqnlvgud 1 300 train
+ljkwqghwpj 0 300 train
+ljlaiuqagh 1 301 train
+ljldhbwtne 1 300 val
+ljlhigyaui 1 302 train
+ljlxqiyvte 0 300 train
+ljlzvvxtat 1 300 train
+ljmadvrlmn 1 300 train
+ljmdahqhlm 1 300 val
+ljmfspasvu 1 300 train
+ljmhoavvis 1 300 train
+ljmvunkiss 1 300 val
+ljmwewyjqw 1 300 train
+ljmxbqvidr 0 300 val
+ljmzirnrle 1 300 val
+ljnasyvolh 0 300 train
+ljnflpsgra 1 300 train
+ljnkwjjeld 1 298 train
+ljnnrqdtrz 1 300 val
+ljnvnifucq 1 300 train
+ljnwojwbdg 1 300 train
+ljnypdqvcp 1 300 train
+ljocuosozu 1 300 train
+ljodcrrxqu 1 300 train
+ljogploktn 0 300 train
+ljogstsxpg 1 300 train
+ljojbxpqzb 1 300 train
+ljouzjaqqe 0 300 test
+ljphqdpzkm 1 300 train
+ljptlmsdzl 1 297 train
+ljpypwvsko 1 300 test
+ljqbqtdsiv 1 300 train
+ljqiywmozo 1 300 train
+ljqjosstiw 1 299 val
+ljqmkrqrvy 1 300 val
+ljqmnxxpzt 1 300 val
+ljqnkeojup 1 300 train
+ljqnljgqve 1 300 train
+ljqrqejspq 1 300 train
+ljqrzsmnpi 1 301 train
+ljqwmsaavv 1 300 train
+ljqwwuzrca 1 301 val
+ljqzzlxhxl 1 300 train
+ljrcafxwrn 0 241 train
+ljreebbwgf 1 300 train
+ljrgrzikxi 1 298 train
+ljrikjsgis 1 300 train
+ljrqivrkay 0 300 train
+ljrvqpoimu 1 300 train
+ljrwzoqzem 1 300 train
+ljrzysihun 1 300 train
+ljscwdnlyk 1 300 train
+ljsynrrgbz 0 300 val
+ljszidnroi 1 300 val
+ljszxvwlaw 1 300 train
+ljtadkfwvm 1 300 train
+ljtdcrtzkh 1 300 train
+ljtjjimyhr 0 300 train
+ljtjvzxtfq 1 300 train
+ljtkjhntue 0 300 val
+ljudwxkzwf 0 300 train
+ljueaoshxi 1 300 train
+ljuidsluoq 1 300 train
+ljundhkvsr 1 300 train
+ljuorayfjt 0 301 train
+ljuuovfkgi 0 300 test
+ljvbgkmuss 1 300 val
+ljvbqaxndc 1 300 train
+ljvflijwqo 1 300 train
+ljvkpxzwuu 1 300 test
+ljvrfvssno 1 301 train
+ljwdqwkynu 1 300 val
+ljwfjeciuj 1 300 train
+ljwghjrlct 1 300 train
+ljwiegeffl 0 300 train
+ljwkwrxnby 1 300 train
+ljwqvxfila 0 300 train
+ljwrrtsfiw 1 300 train
+ljwsbxmern 0 301 train
+ljwwatfbjy 1 299 train
+ljwwxmxdzy 0 300 train
+ljxdmlaanv 1 300 train
+ljxktgthip 1 300 train
+ljxpqhvydy 1 300 test
+ljxqvztlfj 1 300 train
+ljxshzbtte 1 300 train
+ljybfmnvgr 1 300 train
+ljydeqaumt 1 300 train
+ljyemaggjw 1 299 val
+ljylzwsgcn 1 300 train
+ljzdzfjjsg 0 300 train
+ljzdzjetkp 1 300 train
+ljzgbkcvgi 0 300 train
+ljzgurlygl 1 300 val
+ljzhzvrvhj 0 300 train
+ljzlewlqyi 1 300 train
+ljzxzutjvm 1 300 train
+lkajvpbztr 0 300 val
+lkakdxttlz 1 300 train
+lkaszujqxc 1 301 train
+lkaujabuvv 1 300 test
+lkaxbcynpi 1 300 train
+lkazyduuwz 1 300 val
+lkbajmzbsk 0 300 train
+lkbctojbnt 1 300 train
+lkbdbrckxe 1 300 train
+lkbfplmfja 1 300 train
+lkbpavasad 0 300 val
+lkbqistyrb 1 301 train
+lkbuocvulj 1 300 val
+lkbxgoyknt 1 298 train
+lkbyaldnkl 1 300 train
+lkccgljibp 1 136 train
+lkccjgrvbf 1 302 train
+lkccvpybxd 1 300 train
+lkcekqvbwl 1 298 train
+lkcmgdptkv 1 300 train
+lkcodojhuz 1 300 val
+lkcpxavjay 1 300 val
+lkcqxdtpim 1 300 train
+lkctbccaki 1 301 train
+lkcwxpxtpp 1 300 train
+lkcxvnsqwv 1 300 train
+lkcyeinqug 1 300 val
+lkczpjuhgz 1 299 train
+lkczrlhvkh 1 300 train
+lkdaxtzqiv 1 300 train
+lkdbtxjusm 1 300 train
+lkdfnzxhqw 1 300 train
+lkdfyltnbu 1 167 train
+lkdlzpkukw 0 300 train
+lkdqvgrmzh 1 300 test
+lkdtszjxxp 1 300 train
+lkfbztsysf 1 99 train
+lkfehltytq 1 241 train
+lkfoelyxpq 0 300 train
+lkformlpas 1 300 train
+lkfulaaiix 1 301 train
+lkfvcaqywr 1 300 train
+lkfxzxvjvg 1 298 train
+lkgamwbygt 1 298 train
+lkgecmjwht 1 297 train
+lkgfvsarwj 1 300 val
+lkglbjuyea 1 300 train
+lkgrqfcrps 0 125 train
+lkgrxiicog 1 297 train
+lkhcfjsizo 1 300 train
+lkhjyvpbzp 1 300 train
+lkhpizdcli 1 300 train
+lkhszpabzv 1 295 train
+lkhuaoeley 1 300 train
+lkhxhkdtry 1 300 train
+lkieitnaom 1 300 train
+lkihljwqdu 1 300 train
+lkijspqnch 0 300 train
+lkimzrjncr 1 300 train
+lkiorkwapx 1 300 train
+lkisfjodss 1 300 train
+lkisvnpeet 0 300 val
+lkjaumkjpo 0 300 train
+lkjbahunlp 1 300 val
+lkjgzcuaoi 0 301 train
+lkjlytgssv 1 300 train
+lkjufnrktf 1 300 train
+lkjvhtckjs 1 300 train
+lkkandgvbi 1 300 train
+lkkdxlvtiq 1 298 train
+lkkfboheul 1 300 train
+lkkjzevwlf 1 300 train
+lkklqydivm 1 301 train
+lkkzcncavi 1 300 train
+lkkzrnbwtq 1 300 train
+lklceaasio 1 300 train
+lklfngotia 1 299 test
+lklifqzlrl 0 300 train
+lklkhtiqem 1 300 train
+lklsrahzle 1 300 train
+lklswpdfig 1 300 train
+lklxnnznwk 1 288 train
+lkmbngpjib 1 300 val
+lkmcfuqtfb 1 300 train
+lkmeawyywp 1 300 val
+lkmgxwtsjq 1 301 val
+lkmgyyyrpk 0 300 val
+lkmmhcmmkr 1 300 train
+lkmppajcwu 1 300 val
+lkmrjtsrsv 1 300 train
+lkmuzjhcdm 1 300 val
+lkmzehsbos 1 300 train
+lknarmusgj 1 300 val
+lknbqmikwg 1 300 val
+lknemxscab 1 300 train
+lknkofgefp 1 300 train
+lknpzmzypy 1 300 train
+lknsotfwct 1 300 train
+lknxhkhejo 1 300 train
+lkohptymng 1 300 train
+lkokgauotm 1 300 train
+lkomcvfnsn 1 300 train
+lkoozjttqx 1 300 train
+lkoqbenwer 1 300 train
+lkoufdgcef 1 300 val
+lkoutyjote 1 300 train
+lkowuvorey 1 239 val
+lkpkioynwq 1 298 val
+lkpotrabfp 0 300 train
+lkppttaxoq 0 300 train
+lkpwfajdgl 1 300 train
+lkpxzehihg 1 125 val
+lkpylgwtye 1 301 train
+lkpzptnmaq 1 300 val
+lkqhtjxacz 1 300 train
+lkqjedijjt 0 301 train
+lkqlofrpql 1 300 train
+lkqotnclpd 1 300 test
+lkqvfiskik 0 300 train
+lkrbkexkyi 1 300 train
+lkrexbonsl 1 300 val
+lkrotkklco 1 297 train
+lkrvyczcqx 1 300 train
+lkrvzuktte 1 300 train
+lksdfdegma 1 300 train
+lksonkxhck 1 300 train
+lkssuapyqr 0 300 train
+lksypnpkuv 1 300 train
+lksznksbsl 1 301 train
+lktjvibixr 1 300 train
+lktmoybwqr 1 300 train
+lktpvfaxrf 1 300 val
+lktympxjnd 1 300 train
+lkudcemyto 0 300 train
+lkujxcpbmf 1 300 train
+lkukldrsko 1 300 val
+lkuqmjowfl 1 299 train
+lkuwbmzpwr 1 300 train
+lkuyqpnezs 1 300 train
+lkuzinkpoj 1 300 train
+lkvclfhvpk 1 300 train
+lkvlzgpobk 1 300 val
+lkvouattut 0 301 train
+lkvpwhhelv 0 300 val
+lkvqgykgvt 1 301 val
+lkvshairpp 0 300 train
+lkvxqvpzmu 1 300 val
+lkvxusscdq 1 300 train
+lkvzmcszqx 1 300 val
+lkwbuvcgna 1 301 train
+lkwevjqgdb 1 302 val
+lkwtqysqwr 0 300 train
+lkxdupxuks 1 300 val
+lkxlzjejzw 1 300 train
+lkxxewoogt 1 240 train
+lkyfwfpjjz 1 300 train
+lkyjryanyz 1 300 train
+lkymvhqbid 1 299 test
+lkyodrmcdm 1 300 train
+lkypktyokl 1 301 val
+lkypoiafbx 0 300 train
+lkyrcmahve 1 300 train
+lkyxpszfnv 1 300 val
+lkyybimxid 1 300 val
+lkzbvgirfj 1 300 train
+lkzdhwedzk 1 300 val
+lkzgecrxpj 1 300 train
+lkzibqlfts 1 300 train
+lkzngfudax 1 300 train
+lkzoxfepfz 0 300 train
+lkzroxmxzs 1 288 train
+llagpqxcma 0 300 train
+llaqdzerwc 1 300 val
+llasgshpnl 1 300 train
+llasouvlkr 1 300 train
+llauavbwur 1 300 train
+llawldlgej 1 300 val
+llayeqnuxx 0 300 train
+llayimdzgf 1 300 val
+llayrsvxmy 1 300 val
+llbgqzimao 1 300 train
+llbhwffeqx 0 300 train
+llbjkukujk 1 300 train
+llbticqvai 1 300 train
+llcazzjhje 0 300 train
+llcbayaaol 0 301 train
+llcwtfhmjd 1 301 train
+llddssknpw 1 167 train
+lldfiwvzgl 1 300 train
+lldfopgquq 1 241 train
+lldgblyhak 1 300 val
+lldgrgtmty 1 300 train
+lldmclvqvu 1 240 train
+lldncuzoxg 1 300 train
+lldrkbdavb 0 300 train
+lldtnwojuj 1 300 train
+lldtrmyzbe 1 300 train
+lldvmpawap 0 300 train
+lldwfapztv 1 300 train
+lldzxbxswj 1 300 train
+lleaocomre 1 300 train
+llehjzitbo 1 300 train
+lleipzlsku 1 300 train
+llemyadwxk 1 300 val
+llepzglslm 1 249 train
+lleqvkicdq 1 299 test
+llerpzcfnq 1 300 train
+llerssxyrv 1 300 train
+llevvlxjvs 1 300 train
+llfaiyjdce 1 300 val
+llfxhjazch 1 300 train
+llfxsyhvtn 0 300 train
+llfxvxzllg 0 300 train
+llgdmrgrcb 1 300 train
+llgnevncwr 1 300 train
+llgoufhasn 1 300 train
+llgpkbhorg 1 300 test
+llgvbjanwg 1 300 val
+llhizmdtzb 1 300 val
+llhnspjegj 1 300 train
+llhqjvjyyy 1 300 train
+llhrspaijp 1 301 train
+llhueupcmx 1 300 train
+llhzhszklp 1 300 train
+lliejdshvv 1 300 train
+llisgnekde 1 300 train
+llitffcdsi 1 300 train
+lljccqqcta 1 300 val
+lljcozrqxr 1 301 val
+lljlffretz 1 298 train
+lljlzhmrhp 1 300 test
+lljtmxybum 1 300 train
+llkceusnfd 1 300 val
+llkcftkuin 1 300 val
+llkecthqrx 1 299 train
+llkfrznryq 1 300 train
+llkhessplz 1 300 train
+llkhptusjn 1 300 test
+llkiqwisnb 1 300 train
+llkiunqvzt 1 300 train
+llkivzeort 1 300 train
+llkkgrflif 1 300 val
+llkmzohxwl 1 300 train
+llkqmeohtr 1 241 train
+llktewzzri 1 300 train
+llkwskavvg 1 300 train
+lllejofvot 1 300 train
+lllektdbny 1 300 train
+llleshtgrp 0 300 train
+llljjxrqem 1 300 train
+lllldekfoy 0 300 val
+lllnfswlxz 1 300 val
+lllogvnyrw 0 300 train
+llluhoapfb 1 300 train
+lllwszepet 1 300 train
+llmbgdhkzj 1 300 val
+llmephbvue 0 300 train
+llmftzgeec 1 300 train
+llmlqisnfq 1 300 val
+llmofcjqpu 1 300 train
+llmpbdycvp 1 300 train
+llmqjctcuj 1 300 train
+llmrbtcofv 1 288 train
+llmufuowed 0 300 train
+llmuylcuqq 1 300 train
+llmwvkyjnr 1 300 train
+llnfhemqex 1 240 train
+llninqtann 1 300 train
+llnqscnnll 0 300 val
+llnulhuwmv 0 300 train
+llobqnuvav 1 300 val
+llofxntpgv 1 300 val
+llohgjjwhy 1 299 test
+lloilbqxht 1 300 train
+llotjejsex 1 300 train
+llowzxnmag 1 300 train
+llozjplcad 1 301 val
+llpbmmnpbc 1 298 train
+llpdyxwxrb 1 300 train
+llplshnovc 1 300 val
+llplvmcvbl 0 300 test
+llptzabmta 0 300 train
+llqbpoknjt 1 300 val
+llqrkdxmti 1 300 val
+llqsstybvp 1 300 train
+llqtlwzzdy 1 300 train
+llqyftnpnl 1 240 train
+llrbpmkrlr 1 301 train
+llrynzgwgs 1 300 train
+llryrtszxq 1 300 train
+llsblnbukk 1 300 val
+llsbsueqwf 1 300 train
+llsduzqqhi 0 300 train
+llseqxuobs 1 300 test
+llskezvobp 1 300 val
+llskrpcrys 0 300 train
+llsthnvqyr 1 300 train
+llszqdvvmn 1 300 train
+lltekxtlou 1 300 train
+lltlorhjeb 1 300 val
+lltnqnduyw 1 300 train
+lltplbrjta 1 300 train
+lltrotfarq 1 300 train
+llturivtni 1 300 train
+lltvkkjdsw 1 299 test
+lltvsxiysz 1 300 val
+llueexwrva 1 300 val
+lluhifwguy 1 301 train
+lluhkilbeu 1 300 train
+lluitimeqd 1 300 train
+llutlpwmtz 0 298 train
+llutmjhhpp 0 300 train
+lluxnneqnc 1 300 train
+llvboqgkhj 1 300 train
+llvfmsiape 1 300 train
+llvkelfqxw 1 300 train
+llvlronfmw 1 241 train
+llvtsmiuzk 1 300 train
+llvwcqhiid 1 300 train
+llvwxomxag 1 300 train
+llwajzixvu 1 300 val
+llwjceyylu 1 298 train
+llwjhmnnvq 1 298 val
+llwjpzzrur 1 300 train
+llwmwxosgl 1 300 val
+llwuotwccz 1 301 train
+llwwbktump 1 300 train
+llwwlfhcxw 1 241 train
+llwwtszbiq 1 300 train
+llxchhpgxq 1 300 train
+llxfrytcrh 1 300 train
+llxirqejfd 1 300 train
+llxjcyyxeh 1 300 train
+llxrtycvsa 1 301 val
+llxsdvwypg 1 300 train
+llxuxzxiiw 0 300 train
+llyaoxunsb 1 300 val
+llyfzrffsd 1 300 train
+llyhxagnol 1 300 train
+llykbrkins 1 300 train
+llyloisrny 1 297 val
+llylpbwkdc 1 300 train
+llypatkcie 1 300 test
+llytxypwvn 0 300 train
+llzccdvnon 0 300 val
+llzdduhmht 1 301 train
+llzjnmbgez 1 300 train
+llzltrusyp 1 300 val
+llzoogilhw 1 300 train
+llzxwswkms 0 300 train
+lmacjchowb 1 301 train
+lmacrzidyh 0 300 train
+lmafcqaqyi 1 300 train
+lmalgwsflv 1 300 train
+lmavgunaup 1 296 train
+lmazkuewed 1 143 train
+lmbahomxft 0 300 train
+lmblfvqvri 1 301 val
+lmbovvkxij 1 301 train
+lmbrkvvcto 1 299 train
+lmbvoxhowe 0 300 train
+lmbxdibnwz 1 300 train
+lmcawcioze 1 300 train
+lmccjyztbs 0 301 train
+lmccntashy 1 300 train
+lmcmotustf 1 300 val
+lmcnonfhgz 1 301 train
+lmcohghnke 1 300 train
+lmczsiwqtw 1 300 train
+lmdcuvtozu 1 240 train
+lmddlkbjiq 1 300 train
+lmdeveqyyh 1 300 train
+lmdjukzovh 0 300 train
+lmdllckith 0 300 val
+lmdlsqvtor 1 301 train
+lmdpmvrbys 1 301 train
+lmdrgorezo 1 300 train
+lmdrichttx 1 300 train
+lmdtgrilof 1 300 val
+lmdwgkssmz 1 299 val
+lmdwpdiumn 1 301 train
+lmdxhkajem 1 240 train
+lmdyicksrv 1 299 test
+lmebsbbddy 1 300 val
+lmegljdeop 0 300 val
+lmegrfmlbt 1 300 train
+lmeihvlvup 1 300 train
+lmeoosixpd 0 300 val
+lmeqwauimf 1 301 val
+lmfbeiysou 1 300 train
+lmfbgvaiyn 1 300 train
+lmfjyswesg 1 300 train
+lmfsdfjcrx 0 300 train
+lmfuxivcsi 1 297 train
+lmfzhndeli 1 301 train
+lmgbrxnyjk 0 300 train
+lmgdjtzwau 0 300 val
+lmghurrbsh 1 300 val
+lmgjdayqvh 1 300 train
+lmgyytuuld 1 300 train
+lmhctkeayu 1 301 train
+lmhedjbvbd 1 300 train
+lmhhqotfbm 1 300 train
+lmhihrhjjo 1 300 train
+lmhkuaobue 1 300 test
+lmhqfacxia 1 300 train
+lmhqzoxodk 1 300 train
+lmhrauxeqr 1 301 train
+lmhuxdtwgs 1 300 train
+lmhvagdhjh 1 300 val
+lmibdzouid 1 300 train
+lmikisikew 0 300 train
+lmiozveicz 1 300 train
+lmipethxsm 1 300 train
+lmivsadxxk 1 300 train
+lmjbyrygbg 1 300 val
+lmjehchfap 1 300 train
+lmjubnbftw 1 301 train
+lmjzfqizks 1 300 test
+lmkhixsfek 1 241 train
+lmkqexawao 1 300 val
+lmkrdscoug 1 302 val
+lmkvyswvdf 1 300 val
+lmkxbeojfp 1 300 train
+lmkxvfkfpi 1 300 val
+lmkzatubcx 1 298 train
+lmldctlbgo 1 300 train
+lmljfkndju 0 301 train
+lmlmmhqzee 1 300 train
+lmlyvmfbbe 0 300 train
+lmmasupdow 1 300 val
+lmmbmagbza 1 300 train
+lmmiwyanra 1 300 val
+lmmnjkwoto 1 240 train
+lmmqsaived 1 241 train
+lmmwvfsxlm 0 300 train
+lmmyibivqv 1 300 train
+lmmystjvhm 1 300 train
+lmnnfovqpx 1 300 train
+lmnvioxzqu 1 300 train
+lmnwmlodrs 1 300 train
+lmohkvdrtn 1 300 train
+lmohwldxmh 1 300 val
+lmoldbnnwt 1 300 train
+lmoxouwpfi 0 300 train
+lmpaogvvsc 1 300 train
+lmpfbmeade 1 300 test
+lmpgeehvfw 1 300 train
+lmpgsfasor 0 300 train
+lmpobwmsdd 1 300 train
+lmptnqyrxj 1 298 train
+lmpxfwvxpl 1 300 val
+lmpxxuouon 1 300 train
+lmqaqnvvhh 1 300 train
+lmqdhmoznj 1 300 train
+lmqjsakklt 1 300 train
+lmqpkvjpru 1 300 train
+lmqqcbrboq 1 300 train
+lmqrpqoruz 1 300 train
+lmrgdusvgw 1 300 val
+lmrgxtepyu 1 241 train
+lmrksqgmty 1 300 train
+lmrqxokzqo 1 300 train
+lmrshqypdg 0 300 val
+lmrzkerufi 1 300 train
+lmslshymly 0 300 val
+lmspyyjzsr 1 301 train
+lmstadadwc 1 300 train
+lmsuafgtoc 1 300 train
+lmtdzxeein 1 297 train
+lmtfeqnnvh 1 300 train
+lmtjjlrlup 1 300 val
+lmtldeqybq 0 300 train
+lmtlkeqvli 1 300 train
+lmtprngclw 1 300 val
+lmtswyedyz 1 300 train
+lmttuiemgy 1 301 train
+lmtvmldyka 1 298 train
+lmtzulzyjj 1 300 train
+lmuhhwkhts 1 300 train
+lmunrhcpac 0 300 train
+lmuovxendk 1 301 val
+lmuzggjixz 1 300 val
+lmvabutvyc 1 300 train
+lmvbxcrpux 1 298 train
+lmvdlokale 1 300 train
+lmvenblffb 1 300 train
+lmvfpvnkmr 0 300 train
+lmvgprgmlh 1 300 test
+lmvjejnthq 0 300 train
+lmvlwdnifa 1 300 train
+lmvtaezcev 1 136 train
+lmvvnmqcjo 1 300 train
+lmwjelxszz 1 300 val
+lmwojqzzhk 1 301 val
+lmwsdpnvos 1 300 train
+lmwtsepkuj 0 300 train
+lmwurjknlg 1 300 train
+lmxasxdlog 1 300 val
+lmxdmvvval 0 300 val
+lmxgflzptd 1 240 val
+lmxpugqwhc 1 300 train
+lmxpvgiemh 1 298 train
+lmxsjlaoyr 0 300 train
+lmyaqrdaka 0 300 train
+lmyrbghnkp 1 300 train
+lmyroqrffh 1 300 val
+lmyrywqbqy 1 300 train
+lmysqmrute 1 299 test
+lmyssukrhn 1 300 train
+lmzbahfkji 1 300 val
+lmzcgqiptq 1 300 train
+lmzjiqodmv 0 300 train
+lnaktfnbwo 1 301 train
+lnamqmnjru 0 300 train
+lnapjsfsrb 1 300 train
+lnavqqfump 1 300 train
+lnawdflpnw 0 300 train
+lnbckrjmds 1 300 train
+lnbdpjdsfs 1 300 train
+lnbgouvgjz 1 300 train
+lnbmjzbemv 1 300 train
+lnbogaveip 1 147 train
+lncevtcwya 1 300 test
+lnckrixjug 1 301 val
+lncmjtftrg 1 300 train
+lnctlajjbb 1 300 train
+lndhysvhvq 0 300 train
+lndlflfpps 1 300 val
+lnduwidebv 1 300 val
+lndvgnppxi 1 300 train
+lnecdgsigz 1 300 train
+lnedxogeis 1 300 train
+lneiqnecbb 1 300 train
+lnewtbkcjn 1 300 train
+lneyewpabh 1 300 val
+lnfcazoshs 1 299 train
+lnfctblpju 0 298 train
+lnfcvriupb 1 300 val
+lnfdrbhion 0 300 train
+lnfextzkma 1 300 train
+lnffdhygzk 1 300 train
+lnffehsqwd 0 300 train
+lnfgnieebi 1 301 train
+lnfllpdddc 1 100 train
+lnfmifgbde 0 298 train
+lnfnzdyelg 1 299 val
+lnftjpyahp 1 300 train
+lnfvijcfzk 1 300 val
+lngapkhfur 1 300 train
+lngfplnqrm 1 298 train
+lngkrqvkck 1 301 train
+lngrrzshew 1 300 train
+lngvhtbnvb 1 301 train
+lnhbdacijq 1 300 val
+lnhdvgwwwb 1 300 train
+lnhkjhyhvw 0 300 test
+lnhoqciklc 1 300 train
+lnhowupzob 1 300 train
+lnhshsgucc 1 301 train
+lnhugebdwn 1 300 val
+lnhuqdsoer 0 300 val
+lnieuaoklr 1 300 train
+lnifjturzc 0 300 val
+lnipywskyn 0 300 train
+lnitxcpngr 1 300 train
+lnjbjftbgs 1 300 val
+lnjbvwcgkk 1 300 train
+lnjchxojri 0 300 val
+lnjdutgkns 1 300 train
+lnjgpvpfpm 1 300 val
+lnjkffjjop 1 300 train
+lnjkpdviqb 0 300 test
+lnjkvkjuds 1 301 val
+lnjplngtsn 1 300 train
+lnjuwpbivu 1 300 train
+lnjwsqaulo 1 300 train
+lnjxnjoned 0 300 train
+lnjyovmfui 1 300 train
+lnkbhiqfqc 1 300 train
+lnkgjipbwo 1 300 val
+lnkrlcsiex 0 300 train
+lnkteszfiv 1 300 train
+lnkyzfeuwl 1 300 val
+lnkzexivij 1 300 val
+lnlmpwrafv 0 300 train
+lnlozrcdkl 1 300 val
+lnlrgrchoc 1 300 train
+lnlvwtlpfw 0 302 train
+lnlwbzgyql 1 300 train
+lnlwtdkksw 1 99 train
+lnlwywdome 1 300 train
+lnmbpwdikx 1 300 val
+lnmcmybwpt 1 296 val
+lnmipiyylq 1 300 train
+lnmktvepqn 1 299 train
+lnmpbhczfc 1 300 val
+lnmzryqrvm 1 300 train
+lnncjvqxts 1 292 val
+lnnflacpfl 1 241 train
+lnnmgxwqjg 1 300 train
+lnnmitdeze 1 300 train
+lnnngjlaon 1 300 train
+lnnnqlgtld 1 300 train
+lnnonnhrci 0 300 val
+lnnvsldgle 1 300 train
+lnnwcqvujn 1 300 val
+lnomwfidpm 1 300 train
+lnonlukvbm 1 300 train
+lnooeewjsp 1 300 test
+lnootpkwvv 1 297 train
+lnopfwsajt 1 300 train
+lnotnnpmyg 1 300 train
+lnpakizjpy 0 300 train
+lnpakrfugx 1 300 train
+lnpebujelv 1 300 train
+lnphlyflxn 1 300 val
+lnpryicgcu 1 300 train
+lnpsnoufkq 1 300 val
+lnpszhqjbv 1 300 train
+lnpznkerzw 1 300 train
+lnqapliwfm 1 301 train
+lnqbkzenwg 1 300 train
+lnqbvwhxkl 0 300 train
+lnqenhcmcv 1 298 train
+lnqfqyfjup 1 300 train
+lnqguujura 1 298 train
+lnqjafzxom 0 300 train
+lnqsbrhklt 1 300 train
+lnqscykrhg 1 300 train
+lnqttvbefa 1 300 val
+lnqzyvpcgg 1 300 val
+lnrezbtukv 0 300 val
+lnrfxdyfgt 1 300 train
+lnrgnjgojp 1 300 val
+lnrkhhefys 0 300 train
+lnrkpcwvnm 1 299 test
+lnrlatqkyh 1 300 train
+lnrnzseeft 1 300 train
+lnsfaklswh 1 300 train
+lnsghhfkko 1 298 val
+lnsgzqpynt 1 240 val
+lnsijmbeuo 0 300 train
+lnssmsljkd 1 300 train
+lnswibqjtc 1 300 val
+lnthydudcq 1 300 train
+lntibqyjad 1 300 train
+lntmyhhrzt 1 300 train
+lntptywnxf 1 300 train
+lntzovectn 1 300 train
+lnuetivvcr 1 300 train
+lnutojzxiz 0 300 train
+lnuuobzsdt 1 300 train
+lnuwkizkiw 1 300 test
+lnvfwarcne 1 300 train
+lnvhytfsia 1 300 train
+lnvnesdidu 1 300 train
+lnvsrnfdcf 1 300 train
+lnvucjeqcr 1 301 train
+lnwblmvlmb 1 298 train
+lnwckxbijl 1 300 train
+lnwhkekmqr 1 300 train
+lnwttwttcw 1 298 val
+lnxamsukga 0 300 train
+lnxbquwemv 1 241 train
+lnxeohvkpu 1 300 train
+lnxfjzqdiy 1 300 train
+lnxhgfjpuz 1 300 val
+lnxjomjyuk 1 300 train
+lnxkungfyu 1 300 val
+lnxzptjwxt 1 300 train
+lnyconlqik 1 300 train
+lnygocgcst 1 301 train
+lnynsvhhtq 1 300 train
+lnyypslmlt 1 300 train
+lnyzithzme 1 300 val
+lnzfzvxigc 1 300 train
+lnzitwaxwy 0 298 train
+lnzizqodwj 0 300 val
+lnznhupubl 1 300 val
+lnznyxvumr 1 301 val
+lnzpdjuxju 1 300 train
+lnzqkoxomf 1 300 train
+lnzuuyzlff 1 300 train
+lnzxyscjdi 1 300 train
+loaaetvrwu 1 301 train
+loaajymwvm 1 301 train
+loaczontzh 1 301 val
+loaddqbplu 1 300 train
+loafornila 1 300 train
+loapmwscbg 1 300 train
+loareicaec 1 300 train
+loaslohdxc 1 300 train
+loavmgivoo 1 300 test
+loawuskwek 1 300 train
+lobqwxujgr 1 300 train
+lobucnofjd 0 300 val
+lobxktzhbg 1 300 train
+lobyiumwce 0 300 train
+lobywtfcmi 1 300 val
+locbjirkex 0 300 train
+locbylfkoh 0 300 val
+loceqbfjxb 1 300 val
+lochlndgsp 1 300 train
+lococpyqfb 1 300 val
+lodawmsneu 1 302 train
+loddwuxljh 1 300 train
+lodmvsbplf 1 300 val
+lodpimmshz 0 300 train
+lodqkqocot 1 300 train
+lodxsbqefu 1 300 val
+loedgetxar 1 300 val
+loewlxedrc 1 300 val
+loezszktwx 1 300 train
+lofdvdkycg 1 300 train
+lofhhbaxrn 1 300 train
+lofmhyuhpr 1 300 train
+lofmxxroqm 1 301 val
+lofoedbjlt 1 300 train
+lofpmlgywe 1 300 val
+lofqssjmmk 1 300 train
+lofqvymrtu 0 301 train
+lofsodiyxk 1 298 train
+lofyajpsll 1 300 train
+logfzpkxtk 1 301 train
+loghihbzck 1 300 val
+logjpgwpny 1 300 train
+logricueuw 1 300 train
+logwqccgdg 1 300 train
+lohataawgk 1 300 train
+lohdqjvxea 0 300 train
+lohehbktmz 1 301 train
+lohopuynrt 1 300 val
+lohpuwsglw 1 300 train
+lohvbaadme 1 300 train
+lohygeytob 1 288 train
+loiajhczyc 1 300 test
+loidyglldp 1 300 train
+loijppwjze 1 300 train
+loinfhbpig 1 300 train
+loitoqwgdo 1 300 train
+loiveqicfl 1 241 train
+loivoqngeh 0 300 train
+lojnkyymjr 1 300 train
+lojugsogpt 1 300 val
+lokdiajibp 1 300 train
+lokfxdpryi 1 300 train
+lokhfpyrvx 0 300 train
+lokiqptivn 1 300 train
+lokllylswd 1 300 train
+lokodvoorr 1 300 train
+loktngfzor 1 300 train
+lokzlecwpa 1 301 train
+lokzwdldxp 0 300 val
+lolhvdwtup 1 300 val
+lollkigjpp 1 300 train
+lolqyjohvw 1 300 train
+lomeciiboj 1 300 train
+lomhyblssm 1 300 train
+lommizrmbh 1 300 train
+lomncyicmg 1 300 train
+lonfeywaqi 1 300 train
+loniapqrlw 1 297 train
+lonpfqffba 1 300 train
+lonsqjntkl 1 301 val
+lonsrnweor 1 300 train
+lonuxpyene 1 300 train
+lonvqofqei 1 300 train
+lonwrdofgj 1 300 train
+lonxgrulum 1 298 val
+looavyfvgu 0 300 train
+looevuixui 1 300 val
+loohmcjwne 0 301 train
+loohmqmvra 1 300 train
+loopbqtccw 1 301 train
+looreydpcs 1 300 train
+loothbiuvv 1 300 train
+lopbgtvlqi 1 300 train
+lopdthnwhy 1 300 val
+lopgfogzkx 1 300 train
+lopmispumq 1 300 val
+lopqduahoi 1 299 train
+lopvybuizb 1 300 val
+lopwqbglmi 0 300 train
+lopztubzne 1 300 train
+lopzyltyig 1 297 train
+loqaeykidq 1 241 train
+loqatpixkr 1 302 train
+loqbobrwtm 1 136 train
+loqbryihps 1 299 test
+loqchsjsvy 1 300 train
+loqfboqoir 1 300 val
+loqhmepgjy 1 300 val
+loqixyqqme 1 300 train
+loqjnimazy 0 300 train
+loqkacotyy 0 300 train
+loqkottbpd 1 302 val
+loqogafgxo 1 300 train
+loqxlpjugj 0 300 train
+lorefjdfie 1 300 train
+lorszcsxfi 1 300 train
+lorurfbryy 0 301 train
+lorxtsejml 1 301 train
+lorysiznty 1 300 train
+loscbcucal 1 300 test
+losccelkab 1 300 val
+losdmmgngh 0 300 train
+losgqyhukq 1 300 val
+lostibbbqn 1 300 train
+lotbvowgqg 1 300 train
+loterabbxs 1 300 train
+lotjxrabtr 1 300 train
+lotqgzngfo 1 298 val
+lotqxtzxlx 1 300 train
+lotraeoaom 1 300 train
+lotrrluowm 1 300 train
+loujcgoyet 1 300 train
+loumbomfcu 0 300 val
+loupeisbvj 1 300 train
+loursvuiav 1 300 train
+lousrytsse 1 300 train
+louszkbzak 0 300 val
+louyyobufp 1 300 test
+louzhesvcx 1 300 val
+lovaqzesxn 0 301 train
+lovhagzpaa 1 300 train
+lovkthgavz 1 300 train
+lovlbhkosl 1 302 train
+lovwhlaxqb 1 300 train
+lovwvifwwo 1 300 train
+lowapvktcj 1 300 train
+lowfnmpdxc 1 300 train
+lowluqbxcz 0 240 train
+lowqsihdtp 0 299 train
+lowtyhjrie 1 300 val
+lowvwhgnps 1 300 train
+loxagpgfei 0 300 test
+loxetsjspz 1 300 train
+loxrvukpvg 1 300 train
+loyeqdlekt 0 298 train
+loyjwxwfoa 1 298 train
+loynozokrn 1 301 train
+loyqlghaeu 1 300 train
+loyscbebcv 1 300 val
+lozsplzqrq 1 300 train
+lozxbowcwm 0 299 train
+lozzkyahfv 1 300 train
+lpajeafiqi 0 300 train
+lparpftkpm 1 300 train
+lpawpmeubv 1 298 train
+lpaycmmwjx 1 300 train
+lpbfypmgql 0 302 train
+lpbobaovmj 1 300 train
+lpbokkysaz 1 300 train
+lpbwhpbrgi 1 241 train
+lpbyguydrt 0 300 train
+lpbzqozaxo 1 300 test
+lpcaqximim 1 300 train
+lpccuslkvv 1 300 train
+lpcdphzgnw 1 299 test
+lpckpmxeay 1 300 train
+lpckrjqvfn 1 300 train
+lpckumhueh 1 300 train
+lpclrcopmh 1 300 train
+lpcmicsxjy 1 300 train
+lpcqefemsy 0 300 val
+lpcqumwcia 1 300 train
+lpcwqrofbs 1 300 train
+lpcztdljbq 1 300 train
+lpdcpiuuds 1 300 val
+lpdiuhapgi 1 300 train
+lpdnbezgsg 1 300 val
+lpdnvmgtrg 1 299 test
+lpdqfeicxe 0 300 train
+lpehcmqazm 1 300 train
+lpekkabdgx 1 300 train
+lpeltbvqtu 1 300 train
+lpemiuudcx 1 300 train
+lpencintgp 1 300 train
+lperomvunw 0 300 train
+lpevnzejky 1 300 train
+lpewiyhzdb 1 240 train
+lpezdnkzwq 1 300 train
+lpffmsefdm 0 300 val
+lpfhotgggf 1 300 val
+lpfmkvkbrj 1 300 val
+lpfmqnxogg 0 300 val
+lpftkgpphm 1 300 train
+lpfwaohigk 1 300 train
+lpfwdnwdtu 1 300 train
+lpgbxpbbtg 1 300 train
+lpgcklgdrf 1 300 val
+lpgcxosqff 1 300 train
+lpgliunbwf 1 298 train
+lpglnuqhgb 1 300 val
+lpglyzsjtp 1 300 train
+lpgsypeasg 1 300 train
+lpgtkrtqdv 1 300 train
+lpgxwdgnio 0 300 test
+lphdbiytfm 1 300 train
+lpheupsipg 1 300 test
+lphombbcvi 1 300 train
+lphvpkxakv 1 299 val
+lphwoqchqs 1 301 train
+lphxlyszub 1 300 train
+lphxyomden 1 300 val
+lpiexjylhj 1 300 train
+lpiqjiipni 1 300 train
+lpirwikcgr 0 301 val
+lpitjxhwfv 1 300 train
+lpitqucprq 1 300 train
+lpixtoyiqk 1 300 val
+lpjaglbwos 1 302 train
+lpjgxomtvg 0 300 val
+lpjircutgd 1 300 train
+lpjivjurlw 1 301 val
+lpjsqvjmqj 0 300 train
+lpjtsgztfg 1 298 train
+lpjusdgyqv 1 300 train
+lpjvrskjlz 1 300 train
+lpkeffwcye 0 300 val
+lpkgabskbw 1 300 test
+lpklkwjayb 1 300 train
+lpkphzcfua 1 300 train
+lpkpqhrxup 1 300 train
+lpkrajwyvz 1 300 train
+lpkutxfoip 0 300 train
+lplbajbpfd 1 300 train
+lpljeudkaj 1 300 train
+lplkkcyild 1 300 train
+lplyxysyad 1 300 train
+lpmdcstqog 0 300 train
+lpmijmbgiv 1 300 val
+lpmjgfjpec 1 299 test
+lpmjqkscjc 1 288 train
+lpmkksszis 1 300 val
+lpmoynhgcg 1 300 train
+lpmqkzjfaj 1 300 train
+lpmqtgsran 0 300 train
+lpmtqahqof 1 300 train
+lpmzvipwvr 1 300 train
+lpnkowuchc 1 300 train
+lpnvhehuvt 1 299 train
+lpnzqmgzrg 1 300 train
+lpnzrkuvts 1 300 val
+lpoendujep 1 300 val
+lpoiokvljf 1 300 train
+lpojpyqglx 1 300 train
+lpomyqbodh 1 300 train
+lpoobruoxo 0 300 train
+lpoorssrdj 1 300 test
+lpooskwpin 1 300 train
+lpopwjkdav 1 300 val
+lpougvmrue 1 300 val
+lpoxsfaqkf 1 300 val
+lpoyrzlnnd 0 300 train
+lpozgphguh 1 300 train
+lppbbyjbcd 1 300 train
+lppbnplrow 1 300 train
+lppccwwyeq 1 300 train
+lppfywtrfb 1 300 train
+lpphaworro 1 300 train
+lpprabfgmy 0 300 train
+lppsvozhae 1 301 train
+lpqcuileue 1 300 val
+lpqlelecoi 1 300 train
+lpqngulmoh 1 300 train
+lpqobasyuf 1 300 train
+lpqryduyxj 1 300 train
+lpqstzsbqv 1 300 val
+lpqxwrshfb 1 241 train
+lpqykuwtco 1 300 train
+lpqyzjaxzi 0 300 train
+lprejvwtsh 1 300 train
+lprfbxqans 1 300 train
+lprhmbssgf 1 300 train
+lprkpkqevs 1 300 train
+lprnpkpfui 1 300 val
+lprzdqixuf 1 241 train
+lpshblgzyg 1 300 train
+lpsjuvtlbq 1 300 test
+lpspojirrl 0 300 val
+lpspyejhsx 0 302 train
+lpstxxumpp 1 300 train
+lpsvtamgge 1 300 train
+lpsypztflr 1 299 val
+lptblkvwdt 1 300 train
+lptikwsizk 1 300 train
+lptongiurm 1 300 train
+lptoozyjas 1 300 val
+lptpzbkkks 1 300 val
+lpttjsaoax 0 300 train
+lptxnfcidr 1 300 train
+lptyfynqif 0 300 train
+lptzfjybqg 1 300 train
+lpufpduswj 1 300 train
+lpugzvwpws 1 300 val
+lpusajiuqr 1 301 train
+lputgrtity 1 300 train
+lpuuhxjsvt 1 300 train
+lpuzzmqqnp 1 300 train
+lpvaxbampu 1 300 train
+lpvdhpaxna 0 300 train
+lpvenvfrcb 1 300 val
+lpvezonbvb 1 300 train
+lpvgsasxxn 1 300 val
+lpvmqbtnrg 1 300 train
+lpvokyqtum 1 300 train
+lpvpoasehn 1 300 train
+lpvsbfthxm 1 300 val
+lpvybneyaa 1 300 train
+lpwblbyqyc 1 300 train
+lpwcwgtgdx 1 300 train
+lpwhcfbwgs 0 300 train
+lpwmqgvbbd 0 300 val
+lpwnvvgday 1 300 train
+lpwtacajzf 0 300 train
+lpwuzhneuh 1 300 train
+lpxbacokot 0 300 val
+lpxlcohyvb 0 300 train
+lpxoncmnrc 1 300 train
+lpxsiunlmw 1 300 train
+lpxsreixxi 1 300 val
+lpxvbwaiwu 0 300 train
+lpxxwxtwqb 1 300 train
+lpyaddwakj 1 241 train
+lpyipjjhad 0 300 train
+lpylauqvsx 0 300 train
+lpymgpaiup 0 300 val
+lpynxkaopd 1 302 train
+lpyrpfbzgo 1 300 train
+lpyyxskryb 1 300 train
+lpyzupzjjt 1 300 train
+lpzaoewuyp 1 241 train
+lpzbxnnuhr 1 300 train
+lpzjifhvyo 1 300 train
+lpzuerojbb 1 300 val
+lqadnfmexe 1 300 train
+lqaeqctjtb 1 300 train
+lqairdpals 1 300 train
+lqalfomvab 1 240 train
+lqamibiwly 1 300 train
+lqaqlmyhor 1 301 train
+lqbcxpsvgt 1 300 val
+lqbdnoglfj 1 300 val
+lqbomwknem 1 300 val
+lqbqkjlzma 1 300 val
+lqbulwtygp 1 300 train
+lqbveliilg 1 301 val
+lqbvhsvnni 1 300 val
+lqbyyrqlmv 1 300 train
+lqcdpwqpcu 1 300 val
+lqcfmypshi 0 301 train
+lqcigdcmrg 1 299 test
+lqcotpccag 0 300 val
+lqcubyaeyz 1 300 val
+lqdcbdonly 1 300 train
+lqdfxvghdz 1 300 train
+lqdhjppodv 1 300 train
+lqdilzikre 1 300 train
+lqdlbhccwe 1 269 train
+lqdojrijtz 1 300 train
+lqdtpjdrrw 1 300 train
+lqduqdokyx 1 300 train
+lqehaglolf 1 300 train
+lqeocxkfmm 1 300 train
+lqeprskvea 0 300 train
+lqeucjhmmb 1 300 val
+lqewdrrvqv 1 300 train
+lqffsigdlc 0 300 train
+lqfjiqlokh 1 241 train
+lqfwjosrab 1 302 val
+lqfywemubc 1 300 train
+lqggkcoktd 1 300 train
+lqghtpbccp 1 298 train
+lqgiihfyqh 1 300 train
+lqgjxtfyfc 1 300 val
+lqgmoiswmf 1 300 val
+lqgolmlfvz 1 298 train
+lqgqlkiqjp 1 301 val
+lqgvmoqjbj 0 300 train
+lqhiazcove 1 241 train
+lqhrfubojo 1 300 val
+lqibltouvk 1 300 train
+lqicvgibpu 1 300 train
+lqieyfypdv 1 300 train
+lqifqrbopc 1 300 train
+lqijbuonqq 1 300 val
+lqijkhqtbr 1 300 train
+lqijupwllg 1 300 train
+lqirgwrdek 1 298 val
+lqiswzgheg 1 300 train
+lqjechsnzg 0 300 train
+lqjgeyboch 1 300 train
+lqjiacgfxu 1 300 train
+lqjinfnxse 1 300 train
+lqjinslmrx 1 300 val
+lqjmtmtxep 1 300 train
+lqjscbqlur 1 241 train
+lqjzptovqy 1 301 val
+lqkgttngqk 1 301 train
+lqkqtmahyv 0 300 val
+lqkryvooom 0 301 train
+lqkyroubqx 1 300 val
+lqlcywxxqm 0 300 train
+lqlldouufo 1 300 train
+lqlmshoabc 1 300 val
+lqlngaogej 1 301 train
+lqltokcvsn 1 300 train
+lqmbphbskn 1 300 train
+lqmbzyabot 1 300 val
+lqmhacvjga 1 297 train
+lqmhhvhekv 1 300 train
+lqmnslqmlr 1 297 train
+lqmqhiestz 1 301 train
+lqnbnlotqr 1 300 train
+lqndvflpdg 1 300 train
+lqneeissgw 1 300 train
+lqnetyeblu 1 298 train
+lqnfvuqnyo 1 298 train
+lqnglnltcx 1 298 train
+lqngnhxqay 1 300 val
+lqniocztnj 1 300 train
+lqnkziioma 1 300 train
+lqnnwtpzhk 1 300 train
+lqnqlwfayq 1 300 val
+lqntrtzwqo 0 300 train
+lqnxmwcdpd 0 300 train
+lqoakzjlti 1 300 train
+lqoduakagv 1 298 train
+lqophkssqy 1 300 train
+lqopvifkqn 0 300 train
+lqoulrbukd 1 300 train
+lqouzrgsrv 1 300 val
+lqpawumgrn 1 300 train
+lqpitpmzmp 1 300 train
+lqplevdrkz 1 300 train
+lqpqpgdbgr 0 300 train
+lqpuiooftj 1 300 train
+lqpvtsczcs 1 300 train
+lqpzpubfgg 1 300 val
+lqqbbwvckr 1 300 val
+lqqbmrruvs 1 301 val
+lqqeejrhux 1 296 val
+lqqjwyanwl 1 300 train
+lqqohgoenc 1 300 train
+lqqtfmkloa 1 241 train
+lqqwapwgyt 1 301 val
+lqrbopoqso 1 301 train
+lqrdrihmcq 0 300 val
+lqrfjiteca 1 299 test
+lqrkmodvrw 1 300 val
+lqrndtjjbu 1 300 train
+lqrnsotrrs 1 300 train
+lqrodivicg 1 300 val
+lqrrwyqxqq 1 300 train
+lqsajutdhb 1 300 train
+lqsbgioxpu 1 300 train
+lqsbmprjje 1 300 train
+lqshbxmree 1 300 val
+lqsikexkia 1 300 train
+lqsjpgqztt 0 300 train
+lqsjszthxx 1 300 train
+lqsniprvvb 1 298 train
+lqsruijctb 1 300 train
+lqsukukfyk 1 300 train
+lqsuysuorm 1 300 train
+lqsvbnfnbp 1 300 train
+lqszaqyduy 1 300 val
+lqtaaiquqt 1 300 val
+lqtstubztq 1 300 train
+lqtudpjxii 0 300 val
+lqtuvbicet 1 296 val
+lqtxhduxdl 1 301 train
+lquelehzoi 1 300 train
+lqufcavnda 1 300 train
+lqulpaourj 0 300 train
+lquqeuuqbj 1 300 train
+lquyzqhcrh 1 298 train
+lqvfubuvfz 1 300 train
+lqvfwpevcq 0 300 train
+lqvopaikwa 1 300 train
+lqvzdenwia 1 300 val
+lqwdfekuir 1 300 train
+lqwhxzdnjq 1 295 train
+lqwkuvnitm 1 300 val
+lqwsieuyfl 1 300 train
+lqwskhvmnf 1 300 train
+lqwyfqxgbc 1 300 train
+lqxeobfuil 1 300 train
+lqxowbrtkd 1 300 train
+lqxpsrkxzr 0 300 train
+lqxtgdfifi 0 300 train
+lqxubptkea 1 300 train
+lqxuipuvpa 0 300 train
+lqyckwtvnl 0 300 train
+lqyfxyptlt 1 300 val
+lqyhykfygd 1 297 train
+lqytlikxnm 1 300 train
+lqywpbeiwo 1 300 train
+lqzabhlxhd 1 299 test
+lqzaxknerr 1 301 val
+lqzbkveqra 1 300 train
+lqzdxmtkkr 1 301 train
+lqzlfhnhtt 0 300 train
+lqzpwjgslk 1 300 train
+lqzrztpmju 1 300 val
+lqzsnkbmkt 1 300 val
+lqztwaegdg 1 299 train
+lqzvbikuxo 1 300 train
+lqzxkbmenm 1 300 train
+lraaqqxvsc 1 300 train
+lrakxrqwfc 1 301 train
+lramuybciv 1 300 train
+lraonebekp 0 300 train
+lrarrrhuig 1 300 val
+lratvtrxow 1 298 val
+lrauhhgxwv 1 300 train
+lravaasmwo 1 300 train
+lrawjkopub 1 300 train
+lrawjvkdcc 1 300 train
+lrayvgnluh 1 299 val
+lrbiebobgp 0 300 train
+lrbqlvsplj 1 300 train
+lrbtezmmvk 1 300 train
+lrbxmjafxp 1 302 val
+lrbziwcphu 1 300 test
+lrcdwizglh 1 300 train
+lrcfabzeqt 1 300 train
+lrcflllala 0 300 train
+lrcggjcmge 1 300 train
+lrcgsmudjd 1 298 train
+lrckqkzekj 1 300 val
+lrcmbedrds 1 301 train
+lrcvyjskwj 0 300 train
+lrcxjizbrw 1 300 train
+lrcxwerhwl 1 300 val
+lrdbknzelx 1 300 train
+lrdfoepazp 1 300 train
+lrdfvvoqqv 1 301 train
+lrdgvzkswl 1 300 val
+lrdgwktxja 1 298 train
+lrdmpqabxj 0 300 val
+lrdnmalbhr 1 300 test
+lrdziwxgql 1 300 train
+lrectrbffn 1 300 train
+lremkwxelu 1 300 train
+lremwjkfcc 1 300 train
+lreuxrfrsz 1 300 val
+lreytwldez 0 301 val
+lrfhazksyp 1 301 train
+lrfttqnlnj 1 298 train
+lrfxnkpxll 1 300 val
+lrgastzivx 1 300 train
+lrgbovrxay 1 301 val
+lrgeacuhsa 1 300 train
+lrghgpugsi 1 300 train
+lrgmcnavfr 0 301 train
+lrgnfwiiyj 1 300 train
+lrgtofeomo 1 300 train
+lrhaswnflf 1 300 train
+lrhaxlkbzp 1 298 train
+lrhlvdnszs 0 301 train
+lrhoazzxij 1 300 train
+lrhvjcsxgl 1 300 train
+lrhvquzolq 1 300 train
+lrhwwlrhjc 1 300 val
+lrhyxpbvwd 1 300 train
+lribrvaxhc 1 300 train
+lriddpcmuk 1 300 train
+lrilesqlcm 1 300 val
+lrivahrzxi 1 300 val
+lriwxfastl 1 300 val
+lriyprqxkq 1 300 train
+lrizpgjftb 1 300 train
+lrjbdfypjm 1 300 val
+lrjfwstjpr 1 300 train
+lrjngxxvqq 1 300 test
+lrjoqosagm 1 300 train
+lrjsvobqwr 1 300 train
+lrjvoeeqee 1 299 train
+lrjwelfzyf 1 300 train
+lrjxcwrzls 1 300 test
+lrkbomgkrm 1 300 train
+lrkhmfsntu 1 300 val
+lrkilmkobu 1 300 val
+lrkjlmsxlm 1 300 train
+lrkjvocagr 1 300 train
+lrkmgiikqf 1 300 val
+lrknwcngdu 0 300 train
+lrknyidgjx 0 241 train
+lrlbofuacv 1 300 val
+lrlfhgddzm 1 300 train
+lrlhivqsys 0 300 val
+lrlqrrtvso 1 300 train
+lrlvpyfppw 1 300 train
+lrlzafkbpx 1 300 train
+lrmhrrzfgd 0 300 train
+lrmlvvhbnz 1 300 train
+lrmoolzrrq 1 298 train
+lrmtjcnaja 1 300 train
+lrmylhcyye 1 300 train
+lrnaphwvem 1 299 train
+lrndqqloyg 1 300 train
+lrnheiqgxn 1 300 train
+lrninukmqn 0 300 train
+lrnkxcooik 0 300 train
+lrnpthfiia 0 300 train
+lrnszjqwyt 1 300 train
+lrnxpopgkl 1 300 train
+lrnyggifyi 1 300 train
+lrodokrket 1 297 train
+lromlwrocn 1 300 train
+lropamzagp 1 300 train
+lropweocye 1 298 train
+lrortfffem 1 300 train
+lrouxckewl 1 300 train
+lrpakszrpi 1 300 train
+lrpjtzwsdt 1 300 test
+lrpmmlccui 1 300 train
+lrpmubsedv 1 299 val
+lrpnezedev 0 300 val
+lrpnzqotio 1 300 val
+lrpvoemezq 1 300 train
+lrpxtofdmg 0 300 train
+lrqazpfbsg 1 300 val
+lrqhmruflh 0 300 train
+lrqkvwkcnp 1 301 train
+lrqlzxapvx 1 300 train
+lrqmgytbjj 1 300 train
+lrqmrkrzmd 1 300 train
+lrqncpgcci 1 300 train
+lrquoplrdy 1 301 train
+lrqxxjojqz 1 300 train
+lrrjkqkhpx 0 300 train
+lrrkaezbaf 1 300 train
+lrrlokmmuo 1 300 train
+lrrptmaseg 1 300 train
+lrrsdjoiob 1 300 train
+lrrtpfllrm 0 301 val
+lrruubzmwv 1 300 train
+lrrybromea 1 300 train
+lrsemotzuh 1 240 train
+lrsemzbnmc 1 300 train
+lrsmdwodxh 1 300 train
+lrsrvursst 1 300 train
+lrswjasfps 1 300 train
+lrtksdxojh 1 300 train
+lrtksynvic 1 298 train
+lrtnfxnapq 0 300 train
+lrtpvxhwrz 1 300 train
+lrtqzfxgzy 1 288 train
+lrtrklgmws 1 300 train
+lrtsfzstfl 1 300 train
+lrttgphoxk 0 300 train
+lruccssahi 1 300 val
+lrurnzbpwh 0 300 val
+lrvbsctjbm 1 300 train
+lrvhyocope 1 300 train
+lrvmamsdoe 1 300 train
+lrvrnxfoxy 0 300 val
+lrwhdioasg 0 300 train
+lrwpbylkco 0 300 val
+lrwvfbybky 1 300 train
+lrwywitjew 1 300 val
+lrwzmiwzfl 1 300 train
+lrxdbdtwxy 1 300 train
+lrxfnffqsf 1 300 val
+lrxgwjlpfr 0 300 train
+lrxgwogdet 1 300 train
+lrxmylsxbe 1 300 train
+lrxndjedng 1 300 train
+lrxogqqdng 1 300 train
+lrxsznrmgy 1 300 train
+lrxvxvhvfu 0 300 train
+lrykwtbcrx 0 300 train
+lrykxoboha 1 300 val
+lrymeoxedb 1 300 train
+lrynzzmnoh 1 300 train
+lryvorptpd 1 300 train
+lryymllymn 1 300 train
+lrzamyhamw 1 300 train
+lrzexjawrx 1 300 train
+lrzkfxxqfs 1 300 val
+lrzqhstodd 1 300 val
+lrzrbjrmpo 1 296 val
+lrzvhdpvov 1 300 val
+lrzycpajwe 1 300 train
+lrzywproql 1 300 train
+lrzyxhyplm 1 300 train
+lsaaakgruc 1 300 train
+lsabrrdhse 1 301 train
+lsacilouqc 1 143 train
+lsadkstabm 1 300 test
+lsadzakoio 1 240 train
+lsahqgzytb 1 300 train
+lsaiadoutq 0 300 train
+lsaovzhhku 1 299 test
+lsatzfryek 1 299 train
+lsavuvsskn 1 300 train
+lsawgdkxzn 1 300 train
+lsawyhvjfy 1 300 train
+lsaxhlpesb 1 300 val
+lsbatcczfp 1 255 train
+lsbnakpblr 1 300 train
+lsbohfmkgw 1 300 train
+lsbpzkwklc 1 300 train
+lsbrrbmiwx 1 300 train
+lsbttztgcp 1 300 train
+lscfknafba 1 300 train
+lscljluuvg 1 302 train
+lscmyzlmqf 1 301 val
+lscnkcxfiw 0 300 train
+lscrerzfmk 1 300 train
+lscstktpwl 1 300 val
+lsctfjcnil 1 300 train
+lscvqxcilu 0 302 train
+lscyoslzbs 0 300 train
+lsczkczxxj 1 300 train
+lsdcdgekyw 0 300 train
+lsddcneqwj 1 300 train
+lsddhheqgb 1 298 train
+lsdgrdqlqe 1 301 train
+lsdmpcafzq 1 300 val
+lsdwttuvdn 1 300 train
+lsdxegjjlx 1 300 train
+lsdzbzurtu 1 300 train
+lsecdbtopn 1 300 train
+lseeaywmkz 1 300 val
+lseggaeaza 1 300 train
+lseigyxuvh 1 301 train
+lsekwptcdr 0 300 val
+lseldxmqqf 1 300 val
+lselyybgcj 1 300 train
+lsenemsptg 1 298 train
+lseqjdrppx 1 300 test
+lsetxasdxl 1 299 val
+lsfjzfqbqd 1 300 train
+lsfluuclyb 1 300 train
+lsfrtmpubn 1 301 train
+lsfsintfky 1 300 val
+lsfsnohreg 1 300 train
+lsfxegkreh 1 300 train
+lsgaqurwin 1 300 train
+lsgjyoucvv 1 300 train
+lsgndlthal 1 300 val
+lsgsmosfbx 1 300 train
+lsgtnrwehr 0 299 val
+lsgzahnjvr 1 300 val
+lshgrpfbts 1 300 train
+lshioelzvz 1 301 train
+lshiryiwjs 0 300 train
+lshmgdgkfu 1 300 train
+lshmqhcqfr 0 300 train
+lshpxglsmy 1 300 train
+lshuppklae 1 300 val
+lshvuaztno 0 300 val
+lshxvcdeku 0 300 train
+lshzdobech 1 300 val
+lsifexhzsy 1 300 train
+lsihyyfaoh 1 300 val
+lsimdgjeuy 1 300 train
+lsinrsczki 1 300 train
+lsjjujufql 1 300 train
+lsjkhtcjxg 1 300 val
+lsjltvlpuk 1 300 val
+lsjohcdftj 1 301 train
+lsjrkfbucb 1 300 train
+lsjscxkako 1 300 train
+lsjvxakidz 0 300 train
+lsjzqnoexg 1 300 val
+lskdixeqat 1 301 train
+lskklmkuak 1 300 train
+lskqrvnfjw 1 301 train
+lskulzrwue 1 300 train
+lskzgeezie 1 300 train
+lslcunkccv 1 300 val
+lslkefhabn 1 301 train
+lslmnvlhhe 1 300 test
+lslnbgdras 1 300 train
+lslnqfdcll 1 300 train
+lsmcicxjwu 0 300 train
+lsmjqrdpxr 1 300 train
+lsmnqsnqld 0 300 train
+lsmoqbtzsg 1 300 train
+lsmorxsvkw 1 300 train
+lsmravnqsm 1 300 train
+lsmrcbrdbd 1 300 val
+lsmzzyrwtr 1 300 train
+lsnkrqnwvd 1 300 val
+lsnlxmcnto 1 298 train
+lsnvxcjvsl 1 300 val
+lsohkpdfjc 1 300 val
+lsonxkurea 1 301 train
+lsoouyownv 0 300 train
+lsosnwjana 0 300 train
+lsovaktldf 1 300 val
+lsoxumksad 1 300 val
+lspayliojl 1 300 train
+lspcklphpw 1 300 val
+lspcvuaorl 1 301 train
+lspczolmlc 1 300 train
+lspfhavcna 1 300 train
+lspkqwfdkf 1 297 train
+lspyblubob 1 300 train
+lspyiradyt 1 300 val
+lsqbbbpppp 1 301 train
+lsquhuilwj 1 300 val
+lsqvfhilcy 1 301 train
+lsrbuyiggh 1 300 train
+lsrgoxurqy 1 300 train
+lsrhcapdoz 1 240 val
+lsrrcctjxt 1 300 val
+lssnptkzro 1 300 train
+lssyheudpo 0 300 val
+lstcndurdm 1 300 train
+lstdoqonns 0 300 train
+lstejyjeky 1 300 train
+lstgujovzj 1 300 train
+lstkgrrvor 1 300 train
+lstkhesefg 0 301 train
+lstmbmzquj 1 300 train
+lstriernyw 1 300 val
+lstujsnkvp 1 300 train
+lsublsmtyo 1 300 val
+lsucpudnec 1 300 val
+lsuhmstevj 1 300 train
+lsuihvywzr 1 300 train
+lsuusjjclk 1 300 val
+lsvcshazxd 1 301 train
+lsvhhyutgv 1 300 val
+lsvkfsewcn 1 300 val
+lsvmzdzbiu 1 300 val
+lsvtaeyvqp 1 300 val
+lsvupsvgix 1 300 train
+lsvvdxpmmj 0 300 train
+lswcpdrcqe 1 300 train
+lsweehznwt 1 300 train
+lswfkymfuo 1 300 train
+lswjbshvcu 1 301 val
+lswjuelmhd 1 300 train
+lswtmnngaj 1 300 train
+lswulhmdxj 1 300 train
+lsxcjdgthx 1 300 train
+lsxedqnonw 1 300 val
+lsxgpyiaep 1 300 val
+lsxpwzgaer 0 300 val
+lsxscnrupg 1 300 train
+lsxxafdomq 0 300 train
+lsycsgrelv 1 300 train
+lsyfeltfuk 1 300 train
+lsylgzbfce 1 300 train
+lsyyjpxjzq 1 298 train
+lszdctpwpa 1 300 train
+lszsnqgacz 1 300 train
+lszuuqkmrl 1 300 val
+lszvjhrkca 1 300 train
+lszyncnkby 1 300 val
+ltablevgcz 1 300 train
+ltadqzbppw 1 300 train
+ltafjiwhps 1 300 train
+ltakadwxjo 1 300 val
+ltalxemxvo 1 300 train
+ltardccvam 1 300 train
+ltarodmblq 1 300 train
+ltaspbjhna 1 298 val
+ltaubzncql 1 300 train
+ltawnfaomp 1 297 train
+ltbkxsufne 1 300 val
+ltbtlcgqwb 1 301 train
+ltbudmedse 1 301 train
+ltbzaimzmh 1 300 val
+ltcdbgucot 1 300 test
+ltcdxgwjgt 1 241 train
+ltcgtoprqk 1 300 train
+ltclqwottk 1 300 train
+ltcrtncbeu 1 300 train
+ltctatwdny 1 241 train
+ltctfoayrn 1 300 train
+ltctttgupm 1 300 train
+ltdbcslnoi 1 300 train
+ltdgjzgdds 1 301 train
+ltdipxtrul 1 300 val
+ltdjlmepgq 1 298 val
+ltdjsxkvgz 1 300 train
+ltdkuugmgg 1 300 train
+ltdoleynhr 1 300 train
+ltdrdqwsas 1 241 train
+ltdwtgrads 1 83 train
+ltehinzdjb 1 300 train
+ltelioyyzj 1 300 train
+ltetbelgve 1 300 train
+ltezcmdcfp 1 300 train
+ltfagtaafd 0 300 train
+ltfijjnyac 0 300 train
+ltfphvxspl 1 301 train
+ltfpjuodqm 1 300 val
+ltfvpafmgk 1 299 train
+ltfyxkvlwf 1 300 val
+ltgipmlojm 1 300 train
+ltgrlpbgmu 1 301 train
+ltgxxquckx 1 300 train
+ltheclxveb 1 300 train
+lthhnbvcyp 0 300 train
+lthhyfcrby 1 300 train
+lthjbibrbq 1 300 val
+lthliysdpo 1 300 train
+lthqfvpfjj 1 300 val
+lthuwimxlk 1 299 val
+lthydkbysa 1 300 train
+ltidmzdpzs 1 300 train
+ltiekbqamw 1 301 train
+ltigamxmii 1 300 train
+ltijgzptym 1 299 train
+ltikqymaew 1 300 val
+ltiocelfdu 0 300 val
+ltioynuvwb 1 300 train
+ltixokrvjv 1 297 val
+ltiyvpzqrd 1 300 train
+ltjdomokdw 1 301 train
+ltjfjxaapl 1 300 val
+ltjgveekdo 0 300 train
+ltjibmsojr 1 241 train
+ltjkddggay 1 300 train
+ltjtzdqllb 1 300 train
+ltjxjpfrwm 0 300 val
+ltjyyomzub 1 301 train
+ltkcnavlsq 0 300 train
+ltkdrbszjh 0 302 train
+ltkdsqslgz 1 288 train
+ltkesswcyn 1 301 train
+ltkhjqzrwf 1 300 train
+ltkkbnhjak 1 300 train
+ltkkntboeh 1 300 train
+ltkmlnhxvs 0 300 train
+ltknevivba 1 300 train
+ltksiyjnki 1 301 train
+ltksrmszen 1 300 train
+ltkvpexvao 0 300 val
+ltkwtskyba 1 300 train
+ltladympzu 1 300 train
+ltlahtkdni 1 298 train
+ltledzrpjv 1 300 val
+ltlrhgrlsx 1 300 train
+ltlxavhhbf 1 300 val
+ltlxflszdw 1 241 train
+ltmczdvlpe 0 300 train
+ltmkgkppwx 1 300 val
+ltmuraxwex 1 300 train
+ltmvkqfcgt 1 300 train
+ltmwfdmjlu 1 301 train
+ltmyfqjbpo 1 300 train
+ltncdlqzay 1 300 train
+ltnceyxber 1 300 train
+ltnckkemvj 1 300 val
+ltnlxegeko 1 300 train
+ltnukcazoy 1 301 train
+ltnuuyoovr 1 297 val
+ltnxymosza 1 300 train
+ltoacphegl 1 300 train
+ltodfvjysr 0 300 val
+ltofkqszdg 1 300 train
+ltogxmsuzx 1 300 val
+ltokpgkvkq 1 300 train
+ltolmoksfs 1 300 train
+ltoppzmiyg 0 300 train
+ltotcjgnms 1 300 val
+ltozimnbny 1 300 val
+ltpguvcqna 1 300 train
+ltpnknzlsp 0 300 train
+ltpumwqijs 1 300 val
+ltpywknqaz 0 300 train
+ltpzhzneor 1 300 val
+ltqbmdvsuu 1 300 train
+ltqdtclsds 1 298 train
+ltqeuoexom 1 300 train
+ltqganauzp 0 300 train
+ltqghwybkf 1 300 test
+ltqhaymjrf 1 300 train
+ltqjglyiqd 1 300 val
+ltqmtdmone 1 300 train
+ltqrvfmthj 1 300 train
+ltqubwmqml 1 300 train
+ltqyzztasy 0 300 train
+ltrcdtmwpo 1 300 train
+ltrfgcytlz 1 300 train
+ltrmmlxhiy 1 300 train
+ltrylhdfob 1 300 train
+ltrzlbdwal 1 300 train
+ltrztutmkf 1 299 train
+ltrzwdqqhk 1 301 train
+ltrzyozxmd 1 297 val
+ltsfbcjouq 1 300 train
+ltsfdmtlez 1 300 val
+ltsfojqyrn 1 300 train
+ltsitblieu 1 300 train
+ltsnjlutyy 1 300 train
+ltsqbnacho 1 300 test
+ltssgxfwqj 1 301 val
+ltsypwqaeh 1 300 train
+lttacqrpvy 1 300 train
+lttdbugapc 1 300 train
+lttgekonaa 1 300 train
+lttgkdulfy 0 300 train
+lttnazdrxy 1 300 val
+ltttpemdhe 1 300 train
+lttxcouizy 1 240 train
+lttzmtzpsk 1 300 train
+ltuaxakemd 1 300 train
+ltuehqaibe 1 300 train
+ltuembwowc 1 300 train
+ltulcsfcyd 0 300 val
+ltunrovguv 1 300 train
+ltuofuujzk 1 300 train
+ltuxjcvdsv 1 300 train
+ltuxmrvwnr 1 300 train
+ltvehaiyfv 1 300 train
+ltvgksopqp 1 300 train
+ltvnvskspt 1 300 train
+ltvpvpzzel 1 298 train
+ltvsejcpzp 0 300 train
+ltvulvzjwr 1 300 train
+ltwapzajht 1 301 train
+ltwawxhgch 1 300 val
+ltwequjvae 1 300 train
+ltwfcwodml 1 300 train
+ltwhhsvjhy 1 300 train
+ltwjnjafld 1 300 train
+ltwofbmeuf 1 300 train
+ltwpahbitr 1 300 val
+ltxaihidlr 1 300 train
+ltxvpviytx 1 300 train
+ltyatdewoi 1 300 train
+ltydrgyfrr 1 300 train
+ltyfcvoydf 1 300 train
+ltyiqdgybh 1 300 val
+ltypcoorqc 1 300 train
+ltyrtesjnq 1 300 train
+ltyscwokwa 1 300 val
+ltyxbyibfh 0 300 train
+ltzaxbchij 0 300 train
+ltzfmazbuh 0 300 train
+ltzijsyral 0 300 train
+ltzkrtshzm 1 300 train
+ltzpabbpou 1 300 val
+ltzpkkpqpo 1 300 train
+ltzsnoykde 0 300 train
+ltzvyxdjjt 1 300 train
+luackpldiy 1 300 val
+luacxvfbbl 1 300 train
+luagrfpkog 1 300 train
+luajsolqjy 1 300 train
+luakfugxcq 1 300 train
+luaksmjqbg 1 300 train
+lualxnrggz 1 300 val
+luavgmsemj 1 301 train
+luayzhozhs 1 300 train
+lubdzwftbi 1 300 train
+lubfkhewod 1 300 train
+lubjdakceq 1 300 val
+lublurxkug 1 299 train
+lubrmeiccb 1 241 val
+lubtqdfnwi 1 301 train
+lubvjblnvh 1 300 train
+lubwlolrih 1 300 train
+luccrnkgey 1 300 train
+luchdgwyra 1 300 val
+luckkjonis 1 300 train
+lucmsnisai 1 300 train
+lucoicwtri 1 300 train
+lucpbeexdk 0 300 train
+lucpovssjg 1 300 val
+lucvvupjew 1 300 train
+ludbsbowai 1 300 val
+ludehllvez 1 300 train
+ludekmqaoa 1 300 train
+ludeqgyyct 1 300 test
+ludkyskjzw 1 300 train
+ludtlxpbob 1 300 train
+ludxretizp 1 300 train
+ludylolezl 1 300 train
+ludywggjtb 1 300 train
+lueanpvcqp 1 300 train
+lueiywzwoc 0 300 train
+luetpbgumn 1 300 val
+luevykrhbn 1 300 train
+lufafslqpv 1 167 train
+lufecurxmu 1 300 test
+lufflxmktd 1 301 train
+lufggxygaf 1 300 train
+lufpvtyklq 1 300 train
+lufqtixtzb 1 300 train
+lugcggbehx 1 300 train
+luggvvjmuh 1 299 test
+lughxdkcli 1 300 train
+lugolhzrpe 1 300 train
+lugqekylbt 0 300 train
+lugsdibpat 1 300 train
+lugxxugtal 1 300 train
+lugzkkhoer 1 300 test
+luhirnycmf 1 300 train
+luhlllcbij 0 300 train
+luhndqsljl 1 300 train
+luhnqyfvzf 1 300 train
+luhrdqghty 1 241 train
+luiawfiqea 1 300 train
+luifdbezkk 0 300 train
+luiqqsfzgz 0 300 val
+luisbvtrwa 1 299 val
+luisdnrumh 1 301 train
+luiwfjrezd 1 300 train
+luiyhqkgpc 1 300 train
+lujhjwdvho 1 300 val
+lujhttrrpf 1 300 train
+lujjudnqwk 1 300 train
+lujkvntbco 1 300 train
+lujqvznuxh 1 300 train
+lujrzsgjqp 1 300 train
+lujsvdauhs 1 300 train
+lujvyveojc 0 299 test
+lujwkvsmiz 0 300 train
+lujxppbtzk 0 300 train
+lujzudmdhz 1 300 train
+lukcxqbdws 1 299 train
+lukeumafbd 1 300 val
+lukfofshlo 1 241 train
+lukixbdiaz 1 300 train
+lukmfaiapo 1 300 train
+lukrgjuxgi 1 300 val
+luksuvlrom 1 300 test
+lukvrerksm 1 300 train
+lukwwubwyp 1 147 train
+lulgagqlci 1 300 train
+lulhtkitub 1 300 train
+lulmevqtla 0 300 train
+lulnvagyst 1 301 train
+lulyoxicmi 1 298 train
+lumcpnwgjb 1 301 train
+lumdcytaoy 1 300 train
+lumfmlmpxe 1 301 train
+lumnfnfdwu 1 301 train
+lumpnrsgox 1 300 train
+lumqbgkzti 1 300 train
+lumsgiktxx 1 298 train
+lumypoekot 1 298 train
+lumzlgsjvj 1 300 train
+lumzlkyfye 1 300 train
+lumzoajkfv 1 300 train
+lundobgccp 1 301 train
+lunpfphkfo 1 300 test
+lunwjklczu 1 300 train
+luobkqbspr 1 300 train
+luoibfmcye 0 300 train
+luomuixnzz 0 300 train
+luoptdxdkk 0 298 train
+luozlmhsll 0 300 train
+lupihccfew 1 301 train
+luplnqnhxp 1 301 train
+luppvpvxab 0 298 val
+lupqxrtgwe 1 300 train
+lupwespgml 1 300 train
+luqalxrheg 1 300 train
+luqkrrldap 1 301 train
+luqnrvhzzw 1 300 val
+luqtkjkmye 0 301 val
+luqupwdngq 0 300 val
+luqxrtltek 0 300 train
+luqynkuirp 1 301 train
+lurfocmlqf 1 300 train
+lurgyrniwf 1 300 train
+lurlwzpzdz 1 300 train
+lurozpmsqd 1 300 train
+lurreytiha 1 300 val
+lurtlrbeak 1 300 val
+lurvzfahme 1 301 train
+lurwdsohbu 0 241 train
+lurxqngcgz 1 300 train
+lurzcvfcww 1 300 train
+lurzjlhdwy 1 300 train
+lurzowfubv 1 299 test
+lusdfarzvf 1 301 train
+lusesnntol 1 300 train
+lusgnyjwcr 1 300 train
+lusicopdpx 1 300 val
+lusmwexoxz 1 300 train
+lusnpmmuxz 1 301 train
+lustdsegqq 1 300 val
+lusvmlysik 0 300 train
+lutcpypbkp 1 300 train
+lutdstduwz 1 300 train
+lutjtvpahx 1 301 train
+lutmlvonku 1 300 train
+lutmpiwqju 1 300 train
+lutqfzfrlj 1 300 train
+lutseltfpu 1 298 val
+lutvxmmfxs 1 300 val
+luubupzupe 0 300 train
+luugakcroo 1 300 test
+luugalwkfa 1 300 train
+luuupdjlmu 1 300 train
+luuwyccutf 1 300 train
+luuwykgpxq 1 300 train
+luvasmspox 0 300 train
+luverjecuo 1 300 val
+luviiupowk 1 300 val
+luvukpxgnv 1 301 train
+luvwcddjmz 1 300 train
+luvxqrqcze 0 300 train
+luwdgawkmq 1 300 train
+luwdgyhscb 1 300 train
+luwesgqxzv 1 300 train
+luwfwwfolm 1 300 train
+luwhbersrw 1 300 val
+luwmaojqno 1 300 train
+luwrjrrood 1 300 val
+luwszblomo 1 300 train
+luwtycokmn 1 301 train
+luwvlbioft 1 241 train
+luwvnkgoks 1 298 train
+luxfemgerq 1 300 train
+luxltthory 1 300 train
+luxltzdvjo 0 300 train
+luxybgpeww 1 296 train
+luxymrpxij 1 300 train
+luyervyqfj 0 301 train
+luymqojsos 1 300 train
+luynogpajn 0 300 train
+luypwcyzsd 1 300 train
+luzftfpyec 1 300 train
+luzjnapcal 1 300 val
+luzjvuisxv 1 300 train
+luzschwsbi 1 300 train
+lvaaipiolj 1 100 train
+lvaazeqepn 1 299 val
+lvacyekgdx 0 300 train
+lvagtgyvwc 1 301 train
+lvagubsukw 1 299 train
+lvanrgudth 1 241 train
+lvavrwmfdm 0 300 train
+lvazyngbtu 1 299 test
+lvbbscumkz 1 300 train
+lvbfcxtocs 1 300 train
+lvbxitmujr 1 300 train
+lvbyubftbz 1 300 train
+lvcilkddni 1 300 val
+lvcmkukqxi 1 300 train
+lvcncsclba 1 302 train
+lvcufdxmwl 1 300 train
+lvcwietqbw 1 298 train
+lvcxviuecm 0 300 train
+lvdaclryee 1 300 val
+lvdddcxjox 1 300 val
+lvddrimsie 0 300 train
+lvdeivpqur 1 300 val
+lvdiwaszay 1 300 train
+lvdnghlfpy 1 300 train
+lvdpkzbplu 0 300 train
+lvdporkrxf 1 300 train
+lvdstzmeme 1 300 train
+lvdtudroiy 1 300 train
+lvdvxolmnm 1 300 train
+lvdwemxvgj 1 300 train
+lvecnxplwi 0 300 train
+lvectghssh 1 300 train
+lvegskcttn 1 299 val
+lveilcmehg 0 300 train
+lveozuebkb 1 300 train
+lveqznrmgz 1 300 train
+lverrbvqbe 1 298 train
+lveszlkkbk 1 300 train
+lveutffttk 1 300 train
+lvezyjazzd 1 299 test
+lvfcygroyw 1 300 train
+lvfjgwkeds 0 300 val
+lvfuvtmbvv 1 300 val
+lvgcwbvrgc 1 300 train
+lvgezhrkez 1 300 val
+lvglcazbst 1 299 val
+lvgnyxsmgl 1 300 val
+lvgpazmvjm 1 300 val
+lvgxlibzrg 1 300 train
+lvgyhedqxs 1 300 train
+lvhcnwsasy 1 301 val
+lvhevthpee 1 300 train
+lvhjocwloj 1 300 train
+lvhmmxhkes 1 300 val
+lvhnjblacy 1 300 train
+lvhxmjsdhz 0 300 train
+lvidjhhjbw 1 241 train
+lvidvlwsah 1 134 val
+lvikqjyaiw 0 300 train
+lvinrrfyir 0 300 train
+lvipnebaps 1 301 train
+lvipqrzjgm 1 300 train
+lviqjnrdmh 1 300 train
+lvitlonnqo 1 300 train
+lvjfppajlo 1 300 val
+lvjfxqqnem 1 241 train
+lvjhvsbdoy 1 300 val
+lvjtgjhrft 1 300 train
+lvjxvlhalr 1 300 train
+lvkgzquamd 1 300 train
+lvkompzpun 1 301 train
+lvkrtlbhww 1 300 train
+lvkskxpjqn 1 300 train
+lvkuovvday 1 300 train
+lvkvmojpal 1 300 train
+lvkzrirrlz 1 300 train
+lvlbdnhqsa 1 300 train
+lvldvonmbg 0 300 train
+lvlhczjedz 1 301 train
+lvllxmgunk 1 301 train
+lvlpynhhhs 1 300 train
+lvluiulpzh 1 301 train
+lvlvifjoyj 1 300 train
+lvlvyoqmrw 1 300 train
+lvmgoqfqha 1 300 train
+lvmmprinjg 1 300 train
+lvmthzdaiz 1 300 val
+lvnfhvbmuj 1 300 train
+lvnjzrvzwy 0 301 val
+lvnllstzvu 1 99 train
+lvnnkpddsi 1 298 train
+lvnqqhmlma 1 300 train
+lvnxdeqmod 1 300 train
+lvnylzfwdl 1 299 val
+lvnzbtpthm 1 300 val
+lvobqqwevl 1 302 train
+lvolmefkai 1 301 train
+lvomvkrszu 1 299 test
+lvphdpcqlc 1 299 train
+lvpiezukud 1 300 val
+lvpifaenhc 1 300 train
+lvprfpmrxs 0 300 train
+lvpxhfsvir 0 300 train
+lvpxmvhosa 1 300 train
+lvpyjkphya 1 300 train
+lvpzvysigy 1 301 val
+lvqaeuptoh 1 299 train
+lvqajmfheb 1 300 train
+lvqgonobra 1 298 train
+lvqgtqebrb 1 240 train
+lvqpkwnzpz 1 300 train
+lvqqplonjw 1 300 train
+lvqqydgktr 1 300 val
+lvqtcpwoqv 1 301 val
+lvqtrvbsle 1 300 train
+lvqxtzsnhy 0 300 train
+lvqxwgavnu 1 299 val
+lvrdtviiqi 1 300 train
+lvrhszyrlj 1 300 train
+lvrhxvwwfu 1 300 val
+lvriciaexj 1 300 train
+lvrlrbgrdp 1 300 train
+lvrnoggfia 0 300 train
+lvrrehuflq 0 300 train
+lvruwxtolw 1 300 train
+lvrzbitwvw 0 300 val
+lvsifwmgnx 1 301 train
+lvsqhiisfx 1 241 train
+lvsqosyids 0 301 train
+lvsqztsvjo 1 300 train
+lvsrzolktk 1 300 train
+lvssjwtfhu 1 298 train
+lvsukkhqpj 0 300 train
+lvswcztxap 1 300 train
+lvsxvaeatg 1 300 train
+lvszkcszcu 1 240 val
+lvtesorlxs 1 241 train
+lvtirqatfn 0 300 train
+lvtpvzwwwx 1 300 val
+lvtsaaomxh 1 300 train
+lvttaicutc 1 300 train
+lvtylsfaox 1 300 train
+lvtzefjson 1 300 train
+lvtzxmunlu 0 300 val
+lvudmznnpn 1 300 train
+lvukvkzwbf 1 300 train
+lvulwyklur 1 298 train
+lvuqxnyqse 1 300 train
+lvuvvfmmli 1 300 test
+lvuwtmmmmo 1 300 train
+lvuxlomwns 1 300 train
+lvvanomqyc 1 296 train
+lvvdtzkqqe 1 300 train
+lvvixvighu 1 300 train
+lvvpdlucwk 1 300 train
+lvvpfgszfq 0 299 train
+lvvphmcuax 0 300 train
+lvvpomwegl 1 300 val
+lvvrczoipc 1 301 train
+lvvwqorhmr 1 300 val
+lvwbwyaahs 1 300 train
+lvwivkxnxs 1 300 train
+lvwkenmoxl 1 300 train
+lvwlbrgkpo 1 300 val
+lvwmbzgwei 1 300 train
+lvwmciedaw 1 301 val
+lvwsxwdjfp 1 300 train
+lvwwztyqxg 0 300 train
+lvxcnyykaf 1 298 train
+lvxhdzpwex 1 300 train
+lvximugjcn 1 241 train
+lvxpflzyhp 1 300 train
+lvxprirwmn 0 300 val
+lvxzjwiklq 1 301 train
+lvydlxnyzc 0 300 train
+lvyfgfceys 1 298 train
+lvytmqynzu 1 301 train
+lvywprifax 1 298 train
+lvzaifdcio 1 241 train
+lvzdmkveur 1 301 train
+lvzgzxmjcg 1 300 train
+lvzibxmaeo 1 300 train
+lvznaintak 1 302 train
+lvznuabref 0 300 val
+lvzumnpnor 0 300 train
+lwaatqeuxv 1 300 train
+lwaavueeng 1 299 val
+lwabmflkot 1 300 train
+lwapeuqzlz 1 300 val
+lwaracigbw 1 300 train
+lwasdlhiiv 1 300 train
+lwaugxhcbz 0 255 train
+lwayubnfgf 1 303 train
+lwbiygcdug 1 300 val
+lwbjqgydzc 1 300 train
+lwblexpkbx 0 301 train
+lwbmaqzgaw 1 300 train
+lwbntepqpe 0 300 train
+lwbozvohir 1 300 val
+lwbybvjnak 1 300 train
+lwckcudhzj 1 300 train
+lwckqmlfss 1 300 val
+lwcmvwtzws 1 300 val
+lwcnwhpjtn 1 300 train
+lwdevwupcb 1 300 train
+lwdjuxzfdg 0 300 train
+lwdkbbwbdy 0 300 train
+lwduwjzthf 1 300 train
+lwdylopqda 1 300 train
+lwebipdepl 1 300 train
+lwehidsvhx 1 300 train
+lwehwetpgq 1 300 train
+lweiedukhj 1 300 train
+lwejqrhbsb 1 300 train
+lwekpxuuco 1 300 train
+lwemtybijm 1 300 train
+lwepwikzfr 1 297 train
+lwesbcdfqn 1 300 train
+lweuakikbi 1 300 val
+lweyqsgphu 1 299 val
+lwezffnmxh 1 300 train
+lwfikbnufm 0 300 val
+lwfjgunnkh 1 300 train
+lwfpcqtsjb 1 300 train
+lwfrcaibkg 1 300 val
+lwfzweejtm 1 300 train
+lwggwgsazo 0 300 val
+lwgjxkpntl 1 300 train
+lwguoajtej 1 300 train
+lwgwmeaydr 1 300 train
+lwgxzsdxmc 0 300 train
+lwhbjsczbi 1 300 train
+lwhgmqbbqb 1 300 val
+lwhjpmjkmt 1 300 val
+lwhllmgkut 1 300 train
+lwhujtngis 0 300 train
+lwidlvzfrp 1 300 val
+lwigksgxwf 1 300 val
+lwihtrafuo 1 300 train
+lwimtzjtgb 1 300 train
+lwipjlyaov 1 300 train
+lwislgkluo 1 300 train
+lwiziramni 1 300 train
+lwjckssnbd 1 301 val
+lwjfvspoxx 1 300 train
+lwjhjecawz 1 300 val
+lwjhrxiire 1 298 train
+lwjncjtcky 1 241 train
+lwjrmxvvag 1 300 val
+lwjshklriv 1 300 train
+lwjuvshizo 1 300 val
+lwjwohhsmw 1 300 train
+lwjxjkyroa 1 241 train
+lwkmbpwukb 1 300 train
+lwkobdwnay 1 301 train
+lwkpeduisa 1 300 train
+lwkviokzub 1 300 val
+lwkwvfmmxv 1 300 train
+lwkygtfkja 1 301 val
+lwlapejglm 0 300 val
+lwleumrouk 0 300 val
+lwleyeuwhy 1 300 val
+lwlpjzobjr 1 300 val
+lwlppyyhyt 0 300 val
+lwlspugubo 1 300 val
+lwlywdmwto 0 300 train
+lwmbepxbgs 1 300 train
+lwmfcesuht 1 300 train
+lwmgdowwhc 1 239 train
+lwmhvxwubf 0 143 train
+lwmibgydkx 1 299 test
+lwmliuhzmf 1 300 train
+lwmqlzeyat 1 300 train
+lwmufxrefm 0 300 train
+lwnductjvi 1 300 train
+lwngstecxa 1 300 train
+lwnhqncode 1 300 train
+lwnhtezwok 1 300 train
+lwnkbqxrdb 0 301 train
+lwnmbktzmq 1 300 train
+lwnxwkykcq 1 300 train
+lwoagjgpxm 1 300 train
+lwodidevjt 0 300 val
+lwoeaypbyg 1 301 train
+lwoohpengk 0 298 train
+lwoopmypnr 1 300 train
+lwowtlvxho 1 300 val
+lwoxicjdyc 1 300 train
+lwoxpbrqts 0 300 train
+lwpdaapnpc 1 241 train
+lwpnghmykz 1 300 train
+lwppotxmup 1 241 val
+lwprdawybb 0 300 train
+lwprttpyxg 1 300 train
+lwpxliwpfu 1 300 train
+lwpzmijvoq 1 300 train
+lwqaxttfbq 1 300 val
+lwqbzfybeg 0 300 val
+lwqctvhygm 1 300 train
+lwqddgejxh 1 300 train
+lwqkgvyeas 1 300 test
+lwqkwwtmaw 1 167 train
+lwqmfcsjvp 1 300 train
+lwqqqlvnyd 1 300 train
+lwqsmxqtbk 1 300 test
+lwrcvyijvr 1 300 train
+lwrjzzlyje 1 299 test
+lwrpqotcht 1 300 train
+lwrrrzwvho 1 300 train
+lwryrvbxen 1 300 train
+lwshsanvtw 1 300 train
+lwsidhquyg 1 301 train
+lwsjwnomlx 1 300 train
+lwskydnwaj 1 300 train
+lwssnoizxz 1 300 train
+lwstolipcm 1 300 train
+lwsuvtsuhj 1 300 train
+lwsxmripmh 1 300 val
+lwtcbmmobp 1 301 train
+lwtdthvvsf 1 300 train
+lwtgwggkpb 1 300 test
+lwthjrxgly 1 300 val
+lwtjkykrfh 1 299 val
+lwtmvqqfvt 1 300 train
+lwtoxbmyxl 1 300 val
+lwtsuekjgr 0 300 train
+lwufwhpqog 1 301 train
+lwumdgeivp 1 300 train
+lwurnzvhgt 1 300 val
+lwuswllcbn 0 300 val
+lwutssrfou 1 300 train
+lwuwxmruhp 0 300 train
+lwvfipldks 1 300 train
+lwvgjsxkby 1 300 train
+lwvlenifrf 1 300 train
+lwvmrhugjh 1 300 train
+lwvoqjrkoe 1 300 train
+lwvpaqzjux 1 300 train
+lwvrrggvch 1 300 val
+lwvuqhkimy 1 300 train
+lwvxxgjngs 1 300 train
+lwwkgsbqfn 1 300 val
+lwwnqousho 1 300 train
+lwwqxenadf 1 300 train
+lwxchoefjl 0 298 train
+lwxettzaai 1 300 val
+lwxlleeolp 1 241 train
+lwxmbnfrdy 1 167 train
+lwxmrrgjem 1 300 train
+lwxnusafzk 0 300 train
+lwxxmollbr 1 300 train
+lwxyhpuieh 0 300 train
+lwymdxklxn 0 300 train
+lwyrcctfbh 1 300 train
+lwytftudxm 1 300 val
+lwyutmecnm 1 301 val
+lwywesagym 1 241 train
+lwyxnywcvs 0 300 val
+lwyxxdjiqp 1 300 train
+lwzgfluloq 1 300 train
+lwziasznji 0 300 train
+lwzklkaxio 1 300 train
+lwzkzhqikl 1 300 train
+lwzlzbojyo 0 300 train
+lwztszmmge 1 300 val
+lxadgjqzbf 0 300 train
+lxaffoifga 1 298 train
+lxahncwfzq 1 300 train
+lxaleaqgnw 1 300 train
+lxbfnnhmju 1 298 train
+lxbfsfowmv 1 300 val
+lxbjoeimbc 1 300 train
+lxblqcxvee 1 301 train
+lxblwmfkzj 1 300 val
+lxbnqfkkiv 1 300 val
+lxbokiszqx 1 300 train
+lxbvmfdxxs 1 300 train
+lxbwgshkam 1 300 train
+lxbzivlqnk 1 300 train
+lxbzlfbixq 1 300 test
+lxcaipnidg 1 300 val
+lxcasrljsq 1 300 train
+lxcdhbemjy 1 301 train
+lxcwvpqarc 1 300 train
+lxcxwsvrsn 1 300 train
+lxczjcqkwa 1 298 train
+lxdchxfslz 1 300 val
+lxdeqripfq 1 299 train
+lxdkaxsbra 1 300 val
+lxdkuhmocd 0 300 train
+lxdlgfpgjb 1 300 train
+lxdloiaafo 0 300 train
+lxdlrhadmt 1 302 train
+lxdyuoofhd 1 300 train
+lxecgwhnke 1 300 train
+lxefrgcpsc 1 300 train
+lxejwgvxwk 1 298 train
+lxekhqziuc 1 300 train
+lxepbdglsc 1 300 train
+lxeqbyddvt 0 300 train
+lxeqmbyhoe 1 300 train
+lxetdwpbvc 1 300 train
+lxfeonkcec 1 300 test
+lxfepvvdeh 1 300 train
+lxfrifiujz 0 300 test
+lxfrkziemh 0 300 val
+lxfrssijva 1 301 train
+lxfytwagck 1 300 train
+lxgahxecpv 1 241 train
+lxgdlsvudr 1 300 train
+lxgsnghukx 0 300 train
+lxgxwjgqce 1 300 train
+lxgzsgdigx 1 300 train
+lxhhpbkpkb 1 300 val
+lxhilbhxmz 1 300 train
+lxhphsudqz 0 300 train
+lxhsqlkahe 1 300 train
+lxibxdwlca 1 300 train
+lxicnzdokc 1 300 train
+lxiczgmeyg 0 298 val
+lxifonasvx 1 241 train
+lxihbksbtm 1 300 train
+lxihpvezwj 1 300 train
+lxijdfvshc 0 300 train
+lxilqmxrwz 1 300 train
+lxiqduoesh 0 300 train
+lxixtcrfrg 0 300 val
+lxiyrhpkfi 0 300 train
+lxjlesktnz 1 300 train
+lxjnznqvtu 1 300 val
+lxjqvxemcy 0 300 train
+lxjtmfskwa 1 300 train
+lxjvdkhxwb 1 300 train
+lxkfwwxdga 1 300 train
+lxkhmsqvoz 0 298 train
+lxkjyqrrxo 1 300 train
+lxkyjjvhox 1 298 train
+lxldrzojcb 1 300 train
+lxlfcsrwup 1 297 val
+lxlklnhagc 1 300 val
+lxlnphfzqx 1 300 train
+lxlpkydllx 1 300 train
+lxmerfcvkk 1 299 val
+lxmkqfquyx 0 300 train
+lxmvvwqfet 1 300 val
+lxncpycwbm 1 300 train
+lxndsasqrl 1 300 train
+lxneftdyog 0 300 train
+lxnfclxmik 1 300 train
+lxnjlskmko 1 241 train
+lxnjmcvkbp 1 300 train
+lxnpneywjj 1 300 train
+lxnpwpztqi 1 300 train
+lxnqzocgaq 1 300 val
+lxnsgwpylz 0 300 train
+lxochfuwtg 1 300 val
+lxocjkclvl 1 300 val
+lxodbcrssc 1 300 val
+lxodqgtjbz 1 300 train
+lxolgfxvfc 1 300 train
+lxopmugzjr 1 300 train
+lxoqnnvomh 1 300 train
+lxowjswqjf 1 300 train
+lxoyzgfgxg 0 300 train
+lxphgotkgu 1 300 train
+lxphinsrbe 1 300 val
+lxpjxggnqw 1 300 train
+lxpmksvnos 1 300 train
+lxprtdtlqx 1 300 test
+lxqoazkxjy 1 300 train
+lxqqjutqiz 1 300 train
+lxqrrpjleu 1 301 train
+lxqtfoopqi 1 300 train
+lxrjqnyvsc 1 300 val
+lxrrxgzbvw 1 300 val
+lxsonurmmo 1 300 train
+lxsootkxqy 1 299 test
+lxspgmhscm 1 300 val
+lxsqpdmxli 0 300 train
+lxswrmqcpw 0 300 train
+lxteqcltdj 1 300 train
+lxtirdebyc 1 300 val
+lxtjgefowh 1 300 train
+lxtkcgrkhb 1 299 val
+lxtlmnubzm 1 300 train
+lxtpfywztc 1 300 train
+lxtpqbrebk 1 300 train
+lxtrhozzop 1 300 train
+lxtrxxlzsa 0 146 train
+lxttqeegkj 1 300 train
+lxubdzurrp 1 300 train
+lxuefcwyyk 1 299 train
+lxueluejmz 0 300 train
+lxufgmsinv 1 300 train
+lxulljntfn 0 300 train
+lxuotrcwjo 1 300 train
+lxurwqptom 1 300 val
+lxutmyqzlh 1 240 train
+lxvavsmyru 1 300 val
+lxvdbjndkc 1 300 train
+lxvfkzgjyt 1 300 train
+lxvfuemoyh 1 300 train
+lxvghiuihp 1 300 train
+lxvlyrphod 1 300 train
+lxvyftfqjs 1 300 train
+lxwbouhaxy 1 300 train
+lxwbunjebt 1 300 train
+lxwfnowyzb 1 296 train
+lxwhzuenjs 1 300 train
+lxwialnhbi 1 300 val
+lxwjpkbxug 1 300 train
+lxwlvuponk 1 288 train
+lxwoflvqif 1 300 train
+lxwvmoeaqd 1 300 train
+lxwxleiptt 1 300 train
+lxwygjsqdd 1 300 train
+lxxcvnfxlp 1 300 val
+lxxghetows 1 300 train
+lxxtfbrila 0 300 train
+lxxuolvfng 1 300 train
+lxyckdarwa 0 300 train
+lxydfujnzg 1 300 train
+lxygxxfhuj 1 300 train
+lxyhxgfukg 1 300 train
+lxynqoviyi 1 300 val
+lxynzlevlk 1 300 train
+lxyruamlmf 0 299 train
+lxzdyejrvs 0 300 train
+lxzfgvmveo 1 300 val
+lxzfyiwnxh 1 300 val
+lxzptuwcfi 1 300 train
+lxzswmdxxh 1 297 train
+lxzvvfkikj 1 300 train
+lyaikcwore 1 300 train
+lyakmlcmzb 1 300 train
+lyappzmrxf 1 300 val
+lyaqgyaxnm 1 300 train
+lyatfctbby 1 301 train
+lyatugpsbw 1 300 train
+lyawtudnyr 0 300 train
+lyaxxuqubo 1 300 train
+lybnraowwq 1 300 val
+lybpliopfg 1 300 train
+lybvbsonmi 1 300 train
+lyccdacdbm 1 300 train
+lycgrrymbx 0 300 val
+lychwmahoa 1 299 test
+lyclddlnnr 1 300 train
+lycwvqdnqt 1 300 train
+lycylumvbt 0 300 train
+lyddnyernl 1 300 train
+lydemyfffs 0 300 train
+lydeyraqdi 1 300 train
+lydmtsqouh 1 300 train
+lydmxmeegq 1 300 test
+lydscrmisv 1 300 train
+lyduwpljfb 1 300 train
+lydwbtafft 1 300 train
+lydxafrxsy 1 300 test
+lyeeiccojm 1 300 train
+lyenjpbiny 1 300 val
+lyepvpxdyx 1 299 val
+lyeroixpiu 1 136 train
+lyetgpyqun 1 300 train
+lyezawysoz 1 300 train
+lyffdrzfmv 1 300 train
+lyfgrfcwzy 1 300 train
+lyfmgizqnc 1 301 train
+lyfqsbnzuw 1 300 train
+lyfrjvektr 1 300 val
+lyfxbobwyi 1 301 train
+lyfzzwoewp 1 300 train
+lygflrvsau 1 299 test
+lygfmhbqxm 1 300 train
+lygjkvrtfg 1 300 val
+lygmlwnkrl 1 300 val
+lygoqermgt 1 300 val
+lygqsjkbne 1 298 train
+lygulfboeh 1 300 train
+lygymcmkog 1 300 train
+lyhcqyevyf 1 300 val
+lyhkvncmye 1 300 val
+lyhqnuoycr 1 300 train
+lyhvgwbphy 0 300 train
+lyhzuujwvp 1 302 val
+lyidbelkit 1 300 train
+lyidgjejam 1 300 val
+lyilwuxesh 1 300 val
+lyinrqlzyj 1 300 train
+lyitrzyylk 1 300 train
+lyiwrgqipo 1 300 train
+lyjanpywsl 1 300 train
+lyjbrubuxc 1 300 train
+lyjorijwdt 1 300 train
+lyjpcgbpug 1 300 val
+lyjqayxdyh 1 300 val
+lyjxdyybtj 1 300 train
+lyjxghehdj 1 300 val
+lykfjgxrxh 1 300 train
+lykjqnftyl 1 300 train
+lyktsgkukh 1 300 val
+lykxmmmlwl 1 300 train
+lykzwaudqq 1 300 train
+lylghxmszd 0 300 train
+lylmghnmzr 1 300 train
+lylmnzidni 1 300 train
+lylulddbzt 1 241 train
+lylweizdbx 1 300 train
+lymbbethwo 1 300 train
+lymbbordqx 0 300 train
+lymelkavok 1 300 train
+lymenafcef 1 300 train
+lymeyhwjtg 1 300 train
+lymgawkqzw 1 300 train
+lymrhwqqyw 1 300 train
+lymvhkwswt 1 300 train
+lynaeydofd 0 300 train
+lynmkbmcja 1 300 train
+lynnnumymh 1 300 train
+lynpsduasp 1 300 train
+lynreeitbs 1 300 val
+lynxjxlcsl 1 300 val
+lynzyrssge 1 300 train
+lynzzrjuuy 1 240 train
+lyoglramoo 1 300 val
+lyoslorecs 1 300 test
+lyovlhnutg 1 301 val
+lyoxmnawto 1 300 train
+lyoxuuwdas 1 298 train
+lypcnmpokz 1 300 train
+lypeqktrlk 1 300 train
+lypiewmqhr 1 241 train
+lypoukzzag 1 300 train
+lypshjumqf 1 300 train
+lyptahlmly 1 300 train
+lypwcppdkw 1 298 val
+lyqavssmtp 1 300 train
+lyqnhrvdff 1 300 val
+lyqpazadyt 1 299 test
+lyqpprxqbc 1 300 train
+lyqqzjcjvl 1 255 train
+lyqwgwmbkn 1 241 train
+lyqyffrbaj 1 300 train
+lyqyiratig 1 300 train
+lyrclrkwmb 1 300 train
+lyrkhmyebn 1 300 train
+lyrmmkfady 1 299 val
+lyrrkgagxb 0 300 val
+lyrvxheouf 1 299 train
+lyrwlogfle 0 300 train
+lysajzwqvt 1 300 train
+lyshsjkgjx 1 300 train
+lyslyzohgo 1 300 train
+lyssnzrksj 1 301 train
+lyssuagqrc 0 300 val
+lysttlprmm 1 300 train
+lyszecuytu 0 300 train
+lyszqifmsb 1 300 val
+lyszqobfkc 1 300 train
+lytcartuqs 1 300 train
+lytpzqatcr 1 301 train
+lytqqhwvlv 1 300 train
+lytrlcaget 1 301 train
+lyttxbhfdd 1 298 train
+lyuchouzxk 1 240 train
+lyuevomvnr 1 300 train
+lyufssfwyp 1 300 val
+lyuguwqdjb 1 300 train
+lyukjvgwoa 0 299 test
+lyukwkabcx 1 299 test
+lyutbqynlp 1 300 train
+lyuttwtqro 1 298 train
+lyuzrrrafd 1 300 train
+lyvegkgwxp 1 300 train
+lyvklbqkmb 0 300 train
+lyvlnqduqg 0 300 train
+lyvozahmpy 1 300 train
+lyvyiujgdp 1 300 train
+lywaemenbr 1 300 val
+lywcagznan 1 300 val
+lywcnxtwcf 1 300 train
+lywidahwfr 1 300 train
+lywobhfyyf 1 300 train
+lywsnaxmvj 1 300 train
+lywycrekfz 1 300 train
+lyxfcmrrln 1 300 train
+lyxnuongzn 1 300 train
+lyxyzeuxed 1 300 train
+lyxzhtifsg 0 300 train
+lyycpfgyoh 1 300 val
+lyyctrjyhr 0 300 train
+lyyxiejwln 1 300 train
+lyyyrmwsih 1 300 train
+lyzashzagd 1 300 train
+lyzslkylia 1 300 val
+lzajqbwech 1 300 val
+lzarawqafo 1 300 train
+lzbgqiybhn 1 300 train
+lzbkrasjmm 1 300 train
+lzbmwwejxb 0 300 test
+lzbrnfeepd 1 300 train
+lzbxdouccd 1 300 train
+lzbywctalw 1 300 val
+lzcfvpedir 1 300 val
+lzcgadneut 1 300 train
+lzcljabohp 1 300 val
+lzcppvqomf 1 300 train
+lzcuenswvr 1 300 val
+lzcwbhacwy 1 300 train
+lzcwcfelew 1 300 val
+lzczfvtzix 1 300 train
+lzdpxkydke 1 300 train
+lzdtgzczma 1 300 train
+lzdxwizkbk 1 300 train
+lzeaqswnce 1 300 train
+lzeflzdetb 1 300 train
+lzegvduesc 1 300 train
+lzemjinbah 1 300 train
+lzertxjdds 1 300 test
+lzewcixujf 1 298 train
+lzexzlshim 0 300 train
+lzeyelsztu 1 300 val
+lzfcdqnumh 1 300 train
+lzfgrtjpty 1 241 train
+lzfolrfbph 1 300 train
+lzfwhsxmul 1 300 train
+lzfxzqbraf 1 300 train
+lzfzbjqscr 0 300 train
+lzggfqecvr 1 298 train
+lzggytwwwe 1 301 val
+lzgpnzsilk 1 300 train
+lzgtymhxye 1 300 train
+lzgvdgtdhq 0 300 train
+lzgznxucvh 0 301 train
+lzgzsqltom 1 300 val
+lzhfrwybzo 1 300 train
+lzhoufnofj 1 300 train
+lzhoygaiic 0 300 train
+lzhrcezvwz 1 301 val
+lzhtqpymsc 1 301 train
+lzhtvficnu 1 241 train
+lzhyzjwwrk 1 300 train
+lzhyzqtjsa 1 300 train
+lzicbnmzta 1 300 train
+lziifbwnue 1 300 train
+lziphtuxyx 1 300 train
+lzipmumqlu 1 300 test
+lziqzcienv 1 300 train
+lziubxxwdr 1 300 train
+lzizdgcqlx 1 300 train
+lzjarokmea 1 300 val
+lzjivjsfqy 1 298 train
+lzjkwfpcdc 1 298 train
+lzjmjqahye 1 298 val
+lzjsxpefxl 1 300 train
+lzjuhvzokl 1 300 train
+lzjwezlfvl 0 300 val
+lzkaxpevwn 1 300 train
+lzkcuidkvz 1 300 train
+lzkddbpqno 1 299 val
+lzkdgvvlfd 1 300 train
+lzkfnswimv 1 300 train
+lzkgojjcvp 1 300 train
+lzkhknuqet 0 300 train
+lzkqfypidy 1 300 train
+lzkyontpcf 1 299 val
+lzkzjhuqbx 1 301 train
+lzliirnsex 0 300 train
+lzlmiioxco 1 300 train
+lzluicndko 1 300 val
+lzlyaaenim 0 300 train
+lzmduoaega 1 300 train
+lzmgccnqjb 1 301 train
+lzmsudqlmt 1 300 train
+lzmxqxrruv 0 300 train
+lzndqguqqw 1 301 train
+lznejdjqmg 1 300 train
+lznhpsctff 1 300 train
+lznjfuglra 1 300 train
+lznkdhgwms 1 300 test
+lznlemwsgf 1 300 val
+lznqagzwyk 0 300 val
+lzntdxykfg 1 300 train
+lznzzzsdde 0 300 train
+lzojztuvud 1 300 val
+lzolueyghs 1 300 train
+lzornlpnqx 0 300 train
+lzoxnjuwmd 1 299 val
+lzpguvmvus 0 300 train
+lzphmdzbsy 1 300 val
+lzpkfgnqhk 0 300 train
+lzpktgjecw 1 300 train
+lzpqwdpkjm 1 300 val
+lzpyfqslcd 1 300 train
+lzqwiiozmg 1 300 train
+lzqwxwhgst 1 300 val
+lzrozaxqci 1 300 train
+lzrttsdusf 1 300 train
+lzruzgmhox 1 300 train
+lzrxjhljcs 1 241 train
+lzryzpiyxo 1 300 train
+lzrzihalqz 1 300 val
+lzsmgidbbi 1 300 train
+lzsyrphzxc 1 298 train
+lztlvstdyz 1 300 train
+lztmpydgib 0 300 train
+lztyrbizxy 1 300 train
+lzuagvhetg 1 300 val
+lzudaikydx 1 300 train
+lzuhpudnuh 1 300 val
+lzujwmzxwc 1 300 val
+lzuoywtots 1 300 test
+lzushfgxoa 1 300 train
+lzvixjakkc 1 300 val
+lzvjbbmjve 1 300 train
+lzvkaltkfz 1 300 train
+lzvnlihurd 1 299 val
+lzvnmpzfhw 0 300 train
+lzvqheepgw 1 298 train
+lzvzidxgpp 1 300 train
+lzwczhsfna 1 300 val
+lzwgaarglg 1 301 train
+lzwpfjbepu 1 300 train
+lzwvciowhu 1 300 train
+lzwwxvlttv 1 300 train
+lzwxrqmcjc 1 300 train
+lzxaunichq 1 301 val
+lzxdvgrvzu 1 300 val
+lzxekllbdh 1 300 train
+lzxfvfcxra 0 290 train
+lzxfyvzphl 1 300 train
+lzxglaiznr 0 300 train
+lzxlllardl 0 300 train
+lzxzceimmq 0 300 train
+lzyexfpsgu 1 300 train
+lzyluxjgsa 1 300 train
+lzywjpktju 1 300 train
+lzzeeyguyt 1 300 train
+lzzlgtbvmx 1 301 train
+lzzpsosige 0 300 train
+lzzqbqakel 0 300 train
+lzzrbnphlh 1 300 train
+lzzrzfcwiy 1 300 train
+lzzyeqvgxn 1 301 train
+maaisyozrr 1 301 train
+maaltmrbpq 1 300 train
+maapzmcfql 1 300 train
+maargttira 1 300 train
+maarmjyizg 1 300 train
+maarvaeyeo 1 301 train
+maasonjjan 1 300 train
+maatsuvmdk 1 300 val
+maaxznykzy 1 300 train
+mabyqmpwbc 0 300 train
+macihbrqjh 1 300 train
+macnetdjdc 1 300 train
+macobycxqr 0 300 val
+macyflayac 0 240 train
+maczkptqhf 1 300 train
+madahwcsrb 1 300 train
+madnckdlwt 1 300 train
+madvbgarrm 1 300 train
+madvyqeaeh 1 300 val
+madxifyyau 1 300 train
+maeisqnxdh 1 301 train
+maejfjzxmx 1 297 val
+maeqwbvzrq 1 300 train
+maesnzmogl 1 300 train
+maeuhonjah 1 300 train
+maevllldfr 1 300 train
+maeylxlgfc 1 298 train
+maeytvmwmi 1 300 train
+maezcimfkx 1 300 train
+mafctkiedz 0 300 train
+mafpfwpmbx 1 300 val
+mafqmcwarm 1 300 train
+mafrgxljhe 1 300 val
+maftgojivu 1 300 train
+mafvibesfg 0 300 train
+mafwwatqke 1 300 train
+magkooowtk 1 300 val
+magmbradqz 1 298 train
+magmhtikgy 1 301 train
+magmudwdhp 1 300 train
+magolkahuw 1 300 train
+magoolrtrs 1 300 train
+magtfjspzo 1 300 train
+magxfozkhj 1 300 train
+mahfgfcthx 1 300 train
+mahhvhhnku 1 300 train
+mahiiegajb 1 300 train
+mahlfxcgft 0 300 val
+mahomwgonr 1 300 train
+mahpiddmnp 1 300 val
+mahsygvljl 0 300 train
+mahwxuquqj 1 300 train
+mahwxymdka 1 300 train
+mahyxsgjch 1 298 train
+maiarumojd 1 300 train
+maibuamukf 1 300 train
+maifszktyp 1 300 train
+maijabwxhp 1 300 train
+maikyivydy 1 299 val
+maiwbmusjt 1 300 val
+maizmayhdw 1 297 train
+majfemmfzq 1 300 train
+majjxrhshl 1 297 train
+majpoitklb 1 300 train
+majpqblxzv 0 300 train
+majrkoxvsu 1 300 train
+majrssxjkw 1 288 train
+majsueufco 1 300 train
+majtrxqcjy 1 300 train
+majxwnrhin 1 300 train
+makbkfzgvg 1 300 train
+makbmdgmdz 1 299 test
+makfpnyjgd 1 301 train
+makgfbjlze 1 301 train
+makoctodwb 1 300 val
+makpjkjczc 1 300 val
+maktypgsfl 1 299 test
+makuarkrwh 1 300 train
+makwjvntae 1 300 train
+makznueroo 1 300 train
+malanowrhk 1 301 train
+maliqvytnm 1 301 val
+malqhfthee 1 300 val
+malsgublpt 1 300 train
+malsqhzfzt 1 301 val
+malvlezlqf 1 301 val
+malxqfzpfi 1 300 train
+malzaqmoko 1 298 train
+mamcqrzxhh 0 300 val
+mamkiovkrs 1 300 train
+mammihdztm 1 301 val
+mamywmhzvm 1 300 train
+mandzsjlgl 0 300 train
+manhezizaf 1 301 train
+maninslpth 1 300 val
+mannqzezgw 1 300 train
+manqchicur 0 300 train
+manyrujlmk 1 300 val
+maohudqexp 1 300 val
+maombkeefz 1 300 train
+maowtfmsdg 1 300 train
+mapkjstmip 1 300 test
+mappfodejs 1 300 test
+mapvprdoni 1 300 train
+mapwcamedw 1 300 val
+maqcrrtttb 1 300 train
+maqfrnkidt 1 300 train
+maqgedtnrq 0 300 train
+maqszubufw 1 300 val
+maqvbxocqt 0 300 train
+maqwxwinfm 0 300 train
+maqyydnrgm 1 300 train
+maravhdjyj 0 300 train
+markutusaf 1 300 val
+markyirrax 1 298 val
+marmhdrpfw 1 300 train
+marnfroybi 1 300 train
+marofgqhrv 1 300 train
+marqutqrer 0 300 train
+maryzovueh 1 300 val
+masczbqcsi 1 300 train
+masfbyrtxd 1 300 train
+masfllwgjt 1 300 train
+mashwfjsvs 1 300 train
+masivdzbxi 1 300 train
+masjmouoou 1 300 train
+matazfvlzu 1 300 train
+matbflakmq 0 300 train
+matfmojqpk 1 300 train
+matfoqygky 0 300 train
+mathczokbt 1 300 val
+matmepwiel 0 300 train
+matubxtxvo 0 300 train
+mauedplsdt 1 300 train
+mauhbkpwoa 0 300 train
+mauhkjfaww 1 300 test
+mauhvrtjcq 1 300 val
+mausgeoraa 0 300 val
+mavgmcjbmi 1 300 train
+mavhhsyqua 1 300 train
+mavitcblnh 0 300 val
+mavkhkcdiu 1 301 val
+mavskbxnos 1 300 train
+mawblkhmjs 1 300 train
+mawbvfkvin 1 300 train
+mawdvmxwkp 1 300 val
+mawfcppdnn 1 297 train
+mawlbkvbfi 1 300 train
+mawochrpnr 1 301 train
+mawwihwqzj 1 300 train
+maxbjmmsbw 0 300 train
+maxetxjqhl 0 300 train
+maxignyllv 1 300 train
+maxiujczzl 1 300 val
+maxjdmaaax 1 300 train
+maxuragqen 0 300 train
+maxvhossxf 1 296 train
+maxwvfaprc 1 300 train
+maxybxfgts 1 300 test
+mayapvslhh 1 300 val
+mayizlixmb 1 298 train
+maylwhhtld 1 300 val
+mayvnzhqij 0 300 train
+mazcrpfkni 0 300 val
+mazmrfplfz 0 300 val
+mazoaligoi 1 300 train
+mazpsbzlub 1 298 train
+mazufjoico 1 300 train
+mazvvdleva 1 300 val
+mazwbuohsk 1 300 train
+mazxonwbog 1 300 train
+mazzqigsxx 1 300 train
+mbaeoohgox 1 300 train
+mbajtdoxpn 1 300 train
+mbalogpvxl 0 300 val
+mbalzndlgv 1 300 train
+mbapaffxim 1 300 val
+mbaqjlwdjx 1 300 train
+mbarbaitxt 1 300 test
+mbaxrknkyh 0 300 train
+mbaygqqswm 1 300 train
+mbbernvvou 1 300 val
+mbbhmfmhws 1 300 train
+mbbixqpeau 1 301 train
+mbbwjlypgm 1 300 train
+mbcasihfhc 1 300 val
+mbcbbdqdqt 1 301 train
+mbcbtccvaq 0 300 train
+mbcfumztqv 1 301 val
+mbcghoeetc 1 297 val
+mbclkjakwb 0 300 train
+mbcmbmicce 1 300 train
+mbcnfuvnlc 1 300 train
+mbcqewfsiu 1 298 val
+mbczboumwr 1 300 train
+mbdjwoaxcq 0 300 val
+mbdljgtilt 1 300 train
+mbdmfqenja 1 300 train
+mbdqvwnieq 0 300 train
+mbdyqjcujx 1 300 train
+mbdzvgovnd 0 300 train
+mbebwjekbo 1 300 val
+mbeqxhliks 1 300 train
+mbesjokdwf 1 298 val
+mbfbtbsmwd 1 300 val
+mbfgewpect 1 300 train
+mbfhzooobz 1 300 train
+mbfkiuzhpo 0 300 train
+mbfozpiffa 1 300 train
+mbftdyjyfm 1 300 train
+mbfucrguet 1 300 train
+mbgaiwpzkh 0 300 val
+mbgbxqvxfl 1 301 train
+mbgiqctjzk 0 300 val
+mbgmcayehc 1 300 train
+mbgwfdosas 0 300 train
+mbgymtzsfn 1 300 val
+mbhqamdutj 0 300 val
+mbhtbgaivj 1 298 train
+mbhtmxcyfq 0 300 train
+mbhxiaunnd 1 300 val
+mbiagmcxdk 1 300 train
+mbibbvazqo 1 300 val
+mbicfxcwqy 1 301 val
+mbifxgtsre 1 302 train
+mbiideuzia 1 300 val
+mbiipgpfww 1 300 val
+mbikhfrglf 1 300 train
+mbikhzndpo 1 300 test
+mbirvgaiwa 1 300 train
+mbisftbzgx 1 300 train
+mbitoucsnh 1 300 train
+mbivttemgp 1 300 val
+mbivvnaawj 1 300 train
+mbiycqvdxh 1 300 train
+mbiyqplimk 0 300 train
+mbjcxbdgzn 1 300 val
+mbjfuxyfmj 1 300 val
+mbjpaydogy 1 300 train
+mbjssphfec 1 298 train
+mbjzfctrim 1 300 val
+mbkbiqkmnv 1 300 train
+mbkgcmpihi 1 300 train
+mbkhcoezpn 1 300 train
+mbkhjuleuv 1 300 train
+mbkrxpaacb 1 300 train
+mblcxibhkp 1 300 train
+mbleawicec 0 300 val
+mblfskqwil 1 301 train
+mblgxldwhd 1 300 val
+mbljcbjpsf 0 300 val
+mblkzdgmby 1 300 train
+mblotgcylb 1 300 train
+mbloubdhcs 1 300 train
+mblwyyofxr 0 300 train
+mblzetrqah 1 300 train
+mbmftocnnu 0 300 train
+mbmiuwgixg 0 300 train
+mbmizairys 0 300 val
+mbmolrqvre 1 300 train
+mbmpgexazm 1 300 train
+mbmpsrxtkq 1 300 val
+mbmruhrpfd 1 300 train
+mbmxbsyiaz 1 300 val
+mbnfvgjwse 1 300 train
+mbngpsuzmn 1 301 train
+mbnifniery 1 136 train
+mbnineoksr 1 300 train
+mbnjarpmew 1 300 val
+mbnndraqnb 1 300 val
+mbnoftngsb 1 301 train
+mbnqlnxjtt 1 300 train
+mbnvlpwewk 1 300 train
+mbnxdkivyd 1 300 val
+mbnzdxplie 0 300 train
+mboapeamuo 1 298 train
+mbobymsxyq 1 300 val
+mboekkzymy 0 300 train
+mbolmhhuse 1 300 train
+mbopvzlqyb 1 300 train
+mboqxfdrso 1 301 val
+mborrudvjx 1 300 train
+mbotrhcmxi 1 300 train
+mbpbbekqks 0 300 train
+mbpjnujtpe 1 300 train
+mbpnlnjgrz 1 300 train
+mbpofpeook 0 300 train
+mbpvfxtnww 1 300 train
+mbpzdmmsax 1 300 val
+mbpzizgfwb 1 301 train
+mbqctmgdhl 1 300 train
+mbqcydqiih 1 301 train
+mbqkesvpxi 1 300 train
+mbqnwjzdif 1 300 train
+mbqpmbgxve 1 300 test
+mbqpuqlpmj 1 300 train
+mbqqiftaar 1 300 train
+mbqqufbibs 1 300 val
+mbqukzfzcs 1 300 train
+mbqxmgtuwj 1 300 val
+mbrcfwtfjl 1 301 train
+mbrdmflclz 1 300 train
+mbrjpyipua 0 300 train
+mbrljwqaje 1 300 train
+mbrnowangw 1 300 train
+mbrpmopqst 1 302 train
+mbrqkicpcu 1 300 train
+mbsedwmrmi 1 300 train
+mbsnwahcij 0 300 train
+mbspqtczah 1 241 train
+mbsrhidckc 1 300 train
+mbtpgarfiu 1 300 train
+mbucjikddn 1 300 train
+mbuipzmwwu 1 300 train
+mbumkkluve 1 301 train
+mbuucapgsb 1 300 train
+mbuxemwpfk 1 240 train
+mbuyixtqzz 1 300 train
+mbvhkvabku 1 300 train
+mbvikrsheh 0 300 train
+mbvnqmwkdn 1 300 train
+mbvtbvyvob 1 300 train
+mbvzfcsemj 1 300 train
+mbwdhnlwuq 1 300 val
+mbwkhpqovs 1 300 val
+mbwmerbjap 1 300 train
+mbwoomhods 1 300 train
+mbwrqxlrye 1 300 train
+mbwrxfzqgl 1 300 train
+mbwscmofjs 1 300 train
+mbwuugptrf 1 300 train
+mbwuwfqprn 1 300 val
+mbwwxaqppz 1 301 train
+mbwyzdghic 1 300 train
+mbwzumrxml 1 300 train
+mbxblocpyw 0 300 train
+mbxgrocflo 1 300 train
+mbxstccvyq 1 300 train
+mbyhuxozip 1 300 train
+mbyknmzzzb 1 300 train
+mbyledcify 1 300 train
+mbyruyvbyp 0 300 train
+mbyuyxhfqb 1 136 train
+mbyyzbfpaz 1 300 train
+mbzdiuofuc 1 301 train
+mbzfmsbsjz 1 300 train
+mbzgpdvbwo 1 300 train
+mbzlzphbuq 1 300 val
+mbzrmeoiiv 1 300 train
+mbzybpgnfr 1 300 train
+mcadrrcjlw 0 300 train
+mcavgribws 1 99 train
+mcbbqifvzc 1 298 val
+mcbubknuyd 1 300 test
+mcbxmatatt 1 300 train
+mcbxztarfp 1 300 val
+mcbyoomvqg 1 300 val
+mccamrndpx 1 300 train
+mcchrddyxx 0 300 val
+mccibfjkqx 1 300 train
+mcclpxumjg 1 300 train
+mcctwqjerd 0 300 train
+mccuqwrscl 1 300 train
+mcdgaxfego 1 301 train
+mcdlkseldo 1 301 train
+mcdthrhbep 1 300 train
+mcdydajwbb 1 300 train
+mcdyxsesgl 1 301 train
+mcegchbskv 1 300 train
+mceglujidl 0 300 train
+mcehiufkaw 1 300 train
+mcehvkoidm 0 300 train
+mceildthyn 1 300 train
+mceixcangb 0 300 val
+mcejionblb 1 300 train
+mcejkjitcs 1 300 train
+mcejyycbyp 1 300 train
+mceooocbap 1 300 train
+mceowpsakr 1 299 train
+mcesaopunn 1 300 train
+mcesdhhpkp 1 300 train
+mcfcafmidh 1 300 train
+mcfeqhmeyn 1 300 train
+mcfgivpdsj 1 300 val
+mcfladdkju 1 300 train
+mcfltjywod 1 300 train
+mcfrlyyvaf 1 300 train
+mcftsjflpr 1 300 train
+mcgablbjrj 1 299 val
+mcguuplknf 1 300 train
+mcgyhumaob 0 300 train
+mcgzlkwwlr 1 300 train
+mchagyepti 1 241 train
+mchciionlj 0 300 val
+mchdjihnjc 1 297 train
+mchimqhkjm 0 300 train
+mchktetrla 1 300 train
+mchkzqiixt 1 300 train
+mchlodcyov 1 300 train
+mchnykrtrq 1 300 val
+mciazygicw 1 300 train
+mcidhzsvpu 1 300 train
+mcifgcboxx 1 300 train
+mcihikvzqn 1 300 train
+mcijsvvfrp 1 301 val
+mcinjivitc 0 300 val
+mciplwrzzg 1 301 train
+mcjbuzyjny 1 300 train
+mcjckkided 1 300 train
+mcjdazxnxh 1 147 train
+mcjildlznb 1 300 val
+mcjitkvbyx 1 300 train
+mcjmhovlmd 0 300 train
+mcjnnywohl 0 300 val
+mcjnnzxkzg 1 300 train
+mcjocflwhp 1 299 test
+mcjopjucos 1 301 train
+mcjvcndrey 1 300 test
+mcjvoyiywe 1 300 train
+mckaszyjvs 1 300 train
+mckiotlqwx 1 301 train
+mckiqlbvsp 0 300 train
+mcklgbmuqc 1 300 train
+mckmotruyd 1 300 val
+mckwsnrrfq 1 300 train
+mckwvvspiq 1 241 train
+mclhnurizg 0 300 val
+mcllgspbtl 1 300 test
+mclqahxpyl 1 294 train
+mclysxctwi 1 301 train
+mclznsozua 0 300 train
+mclzqajgza 0 300 train
+mcmauxcfay 1 301 train
+mcmiyabubr 0 300 train
+mcmjwrsura 1 300 train
+mcmoofxuih 1 300 train
+mcmqorlbgb 1 300 train
+mcmymvanui 1 300 train
+mcmztvtjaz 0 300 train
+mcngzvrtwp 0 300 train
+mcnmtccsyc 1 300 train
+mcnneodlyv 1 300 train
+mcnorrmmoa 1 300 train
+mcnwvsfglk 1 300 test
+mcnyrbcquj 0 300 train
+mcopshkpza 1 301 train
+mcoqcnxqha 1 300 train
+mcormsgtoq 1 300 train
+mcovnjmuiu 1 300 train
+mcoyszzpfw 1 300 train
+mcpcezlneb 1 300 train
+mcpcfozbtq 1 300 train
+mcphfpzhoh 1 300 val
+mcpqhcqquk 1 300 train
+mcpryhnizf 1 300 train
+mcqcxzddvi 1 300 train
+mcqdwaylas 1 300 train
+mcqhbpeaeb 1 300 train
+mcqimtbsmw 1 300 train
+mcqirmwljn 1 300 train
+mcqmzqjian 1 300 val
+mcqnltqmzt 1 300 train
+mcqpqcrqtq 1 300 train
+mcqxygxexv 1 300 train
+mcrbqeubzs 1 239 train
+mcrcdjrfsr 0 300 train
+mcrhgksove 0 301 train
+mcrkrzsfur 1 300 val
+mcrkufpwdi 1 300 train
+mcrllkntub 1 300 train
+mcrlradmdz 1 300 train
+mcrneghqyw 1 300 train
+mcrqutcxad 1 300 val
+mcrvdrzxzi 1 300 train
+mcrvlmifyc 1 300 train
+mcsatqbvfc 1 300 train
+mcsbpcggtn 1 300 val
+mcschjslqf 1 300 train
+mcscsgskza 1 300 train
+mcsnlwbdzj 1 300 val
+mcsthrmykz 1 300 train
+mctatxfyfv 1 298 train
+mctgqamexh 1 301 train
+mctkydssdj 1 300 train
+mctswsuukt 1 300 val
+mctvwqstnt 1 300 train
+mctxgzxzfu 1 300 train
+mcucmgtilu 1 300 train
+mcudpulxlf 1 300 train
+mcuqldaimy 1 301 train
+mcusepildv 1 300 train
+mcuuejgamc 0 300 train
+mcuuggsqcr 0 300 train
+mcuwyizdah 0 300 train
+mcuzdzgcyj 1 300 train
+mcvbizeusu 1 300 val
+mcvcykszik 1 300 val
+mcvjroxtlf 1 300 train
+mcvlzoagss 1 300 train
+mcvmivylnz 1 300 train
+mcvxrfgkgc 0 300 train
+mcvxwwwlrw 1 298 train
+mcvywyrdek 1 300 train
+mcwrfmujuv 0 300 train
+mcwshpfold 0 300 train
+mcwxamdypc 1 300 val
+mcwxaubcjg 1 300 train
+mcxhedikzn 1 300 train
+mcxsnxzhif 0 300 val
+mcxvonzpzg 1 300 train
+mcyepeixqc 1 300 train
+mcygtlfbuc 1 300 val
+mczbpdjnhe 1 300 val
+mczefokwcj 1 249 train
+mczlixicbu 1 300 train
+mczlxyhthe 1 300 train
+mczysusjvd 1 298 train
+mdabugzwcq 1 300 train
+mdadsdfjzt 1 298 train
+mdahmdjnkk 1 300 test
+mdahntpycu 1 300 val
+mdaioebtjn 1 298 val
+mdajegmldf 1 298 train
+mdajfjzfjg 1 300 train
+mdampijxqe 0 301 train
+mdanmuqgdv 1 300 train
+mdanxmrvxd 1 300 train
+mdaqgqlflw 1 300 val
+mdaxlfuyun 1 300 train
+mdbhkmijka 1 300 train
+mdbohaixtf 0 300 val
+mdboifpakl 1 300 train
+mdbszcqwko 1 300 train
+mdbtnjspno 1 300 val
+mdbvvpakky 1 300 train
+mdbweivafi 1 300 train
+mdcdmwfkab 1 300 train
+mdcdycqnjn 1 300 val
+mdclapycmo 1 300 train
+mdclawykfg 1 300 train
+mdcnckyfgb 1 300 train
+mdcnptnqwc 0 300 train
+mdczhdenwb 1 300 train
+mdczrgxwne 1 300 train
+mddmhodfpc 1 298 train
+mddmzafdxt 1 300 train
+mddpwkvfcv 1 300 val
+mddvihgskg 1 300 train
+mddyxbuifh 1 300 val
+mdeatksqex 1 300 train
+mdefhssykh 1 300 train
+mdegyhtzqs 1 301 train
+mdekvsttxd 1 300 train
+mdeluanqxe 1 300 train
+mdeqwxvodl 0 300 train
+mdeuxouswx 1 300 train
+mdezaahvyt 0 300 val
+mdfblwjagl 1 300 train
+mdfixjgewd 1 290 train
+mdfjkuavyh 1 300 val
+mdfndlljvt 1 299 test
+mdfozxrfwy 1 241 train
+mdftufihjk 1 302 val
+mdgbfnyoys 0 300 train
+mdgejagcih 1 300 val
+mdghefhiye 1 300 val
+mdgklevhza 0 300 train
+mdgmvbgsdu 1 300 train
+mdgqovzdnp 1 300 train
+mdgrowwebm 1 241 train
+mdhhkbhwfc 1 300 train
+mdhllojtrn 1 300 train
+mdhmxwjmuk 1 300 train
+mdhnlfcbqr 0 300 train
+mdhqlmdxvq 1 300 val
+mdhtdtjett 1 241 train
+mdihiuwzea 1 300 test
+mdisstrpgl 1 301 train
+mdjhnhmqlx 1 301 train
+mdjysoesln 1 301 train
+mdkdzxhyye 1 300 train
+mdkpffksty 1 300 train
+mdkqmouddq 1 300 train
+mdkuzayqyn 1 300 train
+mdlhybnhed 1 300 val
+mdllctxjfk 1 300 val
+mdlreolmoo 1 300 train
+mdlrijrqvw 1 300 train
+mdlwompdxe 0 300 train
+mdlxmywjef 1 300 train
+mdlxsqgnxc 1 300 train
+mdlyqcsdkb 1 300 train
+mdlztfqcvx 1 299 test
+mdmerzjrea 1 301 val
+mdmfyeqgsr 1 300 train
+mdmieprwwd 1 300 train
+mdmuvxdjzy 1 301 train
+mdmxkjxobk 1 301 val
+mdnagtvxvw 1 300 train
+mdninuqaez 1 300 val
+mdnpyzjrky 0 300 train
+mdnsekdbta 1 300 train
+mdnwibsbiw 0 300 val
+mdohovpabc 1 300 train
+mdokgndttf 1 300 train
+mdolmcykxz 0 300 train
+mdomrngqic 1 300 train
+mdoovomndl 0 300 train
+mdopnaieqb 1 300 train
+mdoprdcvzh 1 300 train
+mdosrinpqb 1 296 val
+mdotfrlysa 1 300 train
+mdouovgpra 1 300 train
+mdpbfhjtmk 1 300 train
+mdpdbaynzn 1 300 val
+mdpdfgiekp 1 300 train
+mdphurahjg 1 300 train
+mdpkidzzlm 1 298 train
+mdpmbwutiv 1 300 train
+mdpsvdjfrh 1 300 train
+mdpxoldnpc 1 298 train
+mdpyllcmrj 0 136 train
+mdqcqdzlhw 1 300 train
+mdqggpofpr 1 301 train
+mdqiyygqrw 1 300 train
+mdqoooqtfs 1 300 train
+mdqpdlmfkb 1 300 train
+mdqrrbvhus 1 300 train
+mdqsmabykq 1 300 train
+mdqvwuijag 1 147 train
+mdqzounmpo 1 300 train
+mdrafvgbnl 1 300 train
+mdrijqznyt 1 300 train
+mdrimrqivt 1 300 train
+mdroybtgna 1 300 train
+mdrtwiltam 1 300 train
+mdryjfonbv 1 300 train
+mdsbgceuhv 1 300 train
+mdsbvwfcwf 0 300 val
+mdshwrzfeu 1 300 train
+mdsigfwmht 1 300 train
+mdsmgzaltc 0 300 train
+mdswvitxhx 1 300 train
+mdszltopjc 1 300 train
+mdtgousjad 0 300 train
+mdtgtilknd 0 300 train
+mdtjdusycf 1 300 train
+mdtltsgfsq 1 296 val
+mdtmbidzql 1 300 val
+mdtmxciteo 1 300 val
+mdtoybdkpk 1 301 train
+mdtweuftbx 1 300 train
+mduhdknmle 1 300 train
+mdulkdtlsv 1 300 train
+mdumndhqdu 1 300 train
+mduqxrbmjd 0 300 val
+mduviougta 0 300 train
+mdvactbzmq 1 300 val
+mdvcwapetj 0 300 val
+mdvdqvaijm 1 300 val
+mdveaszlmw 1 298 train
+mdvmskcivk 1 300 train
+mdvwugbreu 0 300 train
+mdvxfisypb 1 300 train
+mdwatjczrb 1 298 train
+mdwdabtaxv 1 300 train
+mdwtpvlbrz 0 301 train
+mdxhizdryw 1 300 val
+mdxhympkan 1 300 train
+mdxirvziws 1 300 train
+mdxmkhewnl 1 300 train
+mdxoqpzgyb 1 300 train
+mdxqfbojxr 1 300 train
+mdxuveqdxf 1 297 val
+mdxvholoia 1 270 train
+mdxyexwqyg 1 300 train
+mdydgtvghc 1 300 train
+mdyhgbwkhn 1 300 train
+mdyibevqtd 1 300 train
+mdyjlhxbqw 1 300 train
+mdytvhrkjd 1 300 train
+mdyxkhtldv 1 240 train
+mdyystiqtv 1 300 train
+mdzgrtnykj 1 300 train
+mdziujitvx 1 300 train
+mdzlajezqj 0 300 train
+mdzpmqyjpx 1 302 val
+mdzupjvdwr 1 301 train
+mdzvpgcxxb 1 300 train
+meahqxacit 1 301 val
+meaipafdql 0 300 train
+meaofsannn 0 300 train
+meapgldmvy 1 300 train
+meapgyenzb 1 300 val
+meardvctul 0 300 train
+mearewayhx 1 301 train
+meatgdbndy 1 301 train
+meawmsgiti 0 300 train
+meaylfnpap 0 300 train
+meayummqkj 1 300 train
+mebegnsprb 1 300 train
+mebjuflegl 1 300 train
+meblbzlwet 1 300 train
+mebndddijb 1 300 val
+mebtakxqbg 1 300 val
+mebtchtyrv 1 300 train
+mebwjtnnlb 1 300 val
+mecfiegzft 1 300 train
+mecqioyawu 1 300 train
+mecqzzijbd 1 300 train
+mecrgujypj 1 300 train
+mecrmhalsn 1 299 train
+mecsubivra 1 301 train
+medbimtasq 1 300 train
+meddfnhvgd 1 300 val
+meddqufcwh 1 301 train
+medjwfkvbk 1 300 train
+medmxbyxoh 1 300 train
+medonqrohb 1 300 train
+medxlyfwea 1 300 train
+meedjzqvfy 1 300 train
+meefpsrdxk 0 300 val
+meehftqexr 1 300 test
+mefcclseia 1 301 train
+meffiirpee 1 301 train
+meffrnwwph 1 241 train
+mefjoidkyv 1 301 train
+mefzlyckro 0 300 train
+megsljjxmz 1 300 train
+megxbkujzz 1 300 train
+megxyffexb 1 300 test
+megyyoczsw 1 300 train
+mehaicpsss 1 300 train
+mehaqfykxa 1 300 train
+mehcyqrryk 0 300 train
+mehnyvaxxy 1 300 train
+mehodcanvk 0 300 train
+meholjmdfv 1 301 train
+meieazsnau 1 300 train
+meifxwtvnv 1 300 val
+meilbbyxku 1 300 train
+meiqosyrwj 1 300 train
+meiyjcknbl 1 300 test
+mejgvrwhyg 0 300 train
+mejmnhrjgg 1 300 val
+mejnvawdny 0 300 train
+mejwexizfy 0 300 train
+mejwtedsgx 1 300 train
+mejxwrvpiu 1 300 train
+mejyaqmmyg 1 299 train
+mekajzbyha 1 300 train
+mekbwgjdak 1 300 train
+mekcmawglg 1 300 train
+mekfzsmini 1 300 train
+mekideagof 1 300 train
+mekkncnxfi 0 300 val
+mekogmrvqq 0 300 train
+meksaaboua 1 300 train
+meksrztljm 1 298 train
+melkdmtdct 1 298 train
+melvppvbjj 1 300 train
+memcfxjmmh 1 300 train
+memhhqnczl 1 300 train
+memnkrfujy 1 301 train
+memnxlijxy 1 300 train
+memogbhprf 1 300 train
+mempczgugr 1 241 train
+memtktjttw 0 300 train
+memxryggjc 1 300 train
+menaqevftw 1 300 train
+mendsyiyhf 1 300 train
+menlikjesp 1 300 train
+mensvxsmzv 1 300 train
+menuqpqkay 1 300 train
+menyidamkz 1 299 val
+meogqxlubf 1 288 train
+meojjtkgzk 1 300 val
+mepduxezyg 1 300 train
+mepiuiseem 1 300 train
+mepolbslvm 0 300 val
+mepquopvko 0 167 train
+mepsxfhqcz 1 300 train
+mepwlhbeve 1 300 train
+meqdihrbbi 1 300 train
+meqekbxpzh 1 300 val
+meqenphmnq 1 299 train
+meqwhaqahv 1 298 train
+meqwqkqjjd 1 300 train
+merjkufpti 1 300 train
+merlruunpy 0 300 val
+mermyutaos 0 300 train
+mervwbgmlw 1 300 train
+merwgbyinz 0 300 val
+merzraxzsk 1 300 train
+mesgklrmea 1 300 train
+mesgtlzige 1 300 train
+mesliumkwa 1 300 val
+mesmxqitcl 1 300 test
+mesuqccbha 1 300 train
+mesyfmgozo 1 301 train
+metdggaini 0 300 train
+metfucwpmq 1 300 val
+metjmclgqa 1 300 train
+metkcjswzi 1 300 train
+metnjklgqz 1 300 train
+mettoicqwx 1 300 train
+metuhhgtsx 1 300 train
+meudjaoicz 0 300 train
+meumybmwti 1 300 train
+meunzmcjcv 0 300 train
+meuvcvqjpf 1 300 train
+meuybbzzrw 1 300 train
+mevczpibbs 0 300 train
+mevhczxakl 1 300 train
+mevjrqwfwm 1 300 train
+mevjvsgbmk 0 300 train
+mevlgwjaew 1 300 train
+mevliovheo 1 300 val
+mevloqmlvk 1 300 train
+mevmuyqcgw 1 301 val
+mevnqvpwna 1 300 val
+mevqacbojw 1 300 train
+mevuhsmhfn 1 300 val
+mevuqpcwug 0 300 train
+mevxcbeuwy 1 300 train
+mewaafuknw 1 299 train
+mewakogfvc 1 301 train
+mewbjpaoke 1 300 train
+mewglgiqqi 1 300 train
+mewjnesaix 0 300 val
+mewobrfvrv 0 300 train
+mewozhoyag 1 300 train
+mewrkipeus 1 300 train
+mewuxyczye 1 300 train
+mexcchwnba 1 301 val
+mexhfpqdlf 1 300 train
+mexhppnbna 1 100 train
+mexqrnqdnk 1 300 train
+mexwrnhhyo 1 300 train
+mexxpmdfcr 1 300 train
+meyctdtbmj 0 300 val
+meyhljfyxw 1 300 train
+meymsnbryl 1 300 train
+meyooznyso 1 300 train
+mezfwvykdu 1 300 train
+mezipblicc 1 300 val
+mezqmohxhb 1 301 val
+mezqphyqsu 1 300 train
+mezufhyhtr 1 300 train
+mezzmybzgm 1 301 train
+mfaqfjhdih 0 300 val
+mfaqvlpodq 0 300 train
+mfarnviwjb 1 300 train
+mfbenlptlg 1 300 train
+mfbfmbbhqh 1 300 train
+mfbhshcwsp 1 300 train
+mfblutnplz 1 300 train
+mfbpacleqo 1 300 train
+mfbpiljizu 0 300 val
+mfbrvrqtwq 1 300 train
+mfbtblomej 1 300 train
+mfcbgbcuvb 0 300 train
+mfcdogcags 1 300 val
+mfcfhhxzif 0 300 train
+mfchwiwczp 1 300 train
+mfcnysztdp 1 300 train
+mfcqmrljlf 1 300 train
+mfcsiztcyz 0 300 train
+mfcvohnhjt 1 300 train
+mfcyfdmoet 1 300 train
+mfdianmloz 1 300 train
+mfdsglialu 1 241 train
+mfdxipttco 1 300 train
+mfdzamounj 1 300 val
+mfebxvocjg 1 301 train
+mfedcyumji 1 300 train
+mfehmurezk 1 300 train
+mferfrsajs 0 301 train
+mfeyhgdplr 1 300 train
+mfezjwulyh 1 300 train
+mffatqcrhl 1 300 train
+mffbrshfnj 0 301 train
+mffjwgmdlw 1 300 train
+mffloyzmov 0 300 train
+mffrwszycg 1 300 val
+mffuywjeqj 1 300 train
+mffxcbvdyj 0 269 train
+mffyuwgjoq 1 300 train
+mffzfcimih 1 300 train
+mfggxwxyai 1 300 train
+mfgihrurqm 1 299 test
+mfgiieixzf 1 240 val
+mfglmtyfrj 1 300 train
+mfgmajettc 1 300 train
+mfgqkpubzs 1 300 train
+mfgswvvnba 1 300 test
+mfgysymexq 0 300 val
+mfhdprwfcs 0 300 train
+mfhfpghyso 1 300 train
+mfhghyjnzy 1 300 train
+mfhhybudyr 1 298 val
+mfhilfgqgq 1 300 train
+mfhmlcpbqj 1 300 train
+mfhoawwpvy 1 241 train
+mfhpnpeuil 1 300 train
+mfhqonawni 0 300 train
+mfhsgjziss 1 300 val
+mfhtahbxqq 1 300 train
+mfhvszhgpi 1 300 val
+mfiacnbuwi 1 300 val
+mfijnuuerm 1 300 val
+mfinknmtew 1 300 train
+mfixnjhpqj 1 300 train
+mfizvnubvr 1 300 train
+mfjaakzvkp 1 300 val
+mfjdatqvgg 0 300 val
+mfjewwbzmj 1 240 val
+mfjfheaery 1 300 val
+mfjfpupwge 1 300 train
+mfjkuhlrni 0 300 train
+mfjtulxaix 1 300 val
+mfjwfwvaxr 1 300 train
+mfkiewzzic 1 301 train
+mfkjfjplbw 0 300 train
+mfkoyxwuyj 1 299 test
+mfkwnwrwdr 1 300 test
+mfkwvfaujm 1 300 val
+mfkxsdihrx 1 300 train
+mfkxwgijwn 1 300 val
+mfkzoapcqm 1 300 test
+mflawivwsc 1 300 train
+mfldjobbln 1 300 train
+mflgpxxywb 1 300 val
+mflrxtzvae 0 300 train
+mflsylzhdh 1 300 train
+mfltshiqny 1 300 train
+mfltygzuau 1 300 val
+mflyunqjwr 1 300 train
+mflzbhmygn 0 300 train
+mfmakapupv 1 292 val
+mfmdiclwce 1 301 train
+mfmfkiqihw 1 301 train
+mfmkjmlzmr 1 300 train
+mfmlmaeobo 1 300 train
+mfmqgcyrhu 1 300 train
+mfmsjckpic 1 300 val
+mfmtfifvro 0 300 val
+mfnclaztzj 1 300 val
+mfngdronih 1 298 train
+mfnikjfuxu 1 300 val
+mfnjjhtlrp 1 300 train
+mfnkfyedro 1 301 train
+mfnmplfesw 1 300 val
+mfnowqfdwl 0 300 train
+mfnsxrdygp 1 300 test
+mfnwfnxdep 1 300 train
+mfnxrqfprz 1 300 train
+mfodqgnnav 1 300 test
+mfofrjdcmo 1 300 train
+mfofuymolr 0 300 train
+mfoimzqecc 1 300 train
+mfonxmoakg 1 300 val
+mfovbyucgq 1 300 train
+mfozqhiyav 1 299 train
+mfpgdgsaxg 0 300 train
+mfphivtusf 1 300 train
+mfphjimfnv 1 300 train
+mfpkvxltta 1 300 train
+mfplbdhpno 1 300 val
+mfplnxyqda 0 300 val
+mfpqgzbnvc 1 301 train
+mfpzbuuvhm 1 300 train
+mfpzwetcyv 0 300 val
+mfqaexykvd 1 299 test
+mfqrvneqiq 1 300 val
+mfqvhurzcz 1 300 val
+mfqzskhlnk 1 300 val
+mfrcgszcco 1 301 train
+mfrhbcboex 1 300 train
+mfrtpwxtur 1 300 val
+mfrxdjwlwh 1 300 train
+mfsdcwdauo 1 300 val
+mfsekznork 1 300 train
+mfsjlolpxd 0 300 train
+mfsoouplpq 1 300 train
+mfsoyljskv 1 300 train
+mfsrobtjmn 1 136 train
+mfsuuumxrz 1 300 train
+mfsvnuglii 0 300 train
+mfszujdaqw 1 300 val
+mftiblbele 1 300 train
+mftigyjtaz 1 300 train
+mftlagcsyb 1 300 train
+mftoludykz 1 99 train
+mftoqnedyj 1 300 train
+mftsjsptwe 1 301 train
+mftsmkczel 1 299 train
+mftwrjybnb 1 300 train
+mfupprckjy 0 301 train
+mfutbbpzur 1 300 train
+mfuuhsfaxp 1 300 train
+mfuulqhjgz 1 300 train
+mfuvenipvo 1 300 train
+mfuwobyyfn 1 300 val
+mfvcutimfv 0 300 val
+mfveugcynw 0 300 train
+mfvidfnnye 1 241 train
+mfvmlqluot 0 300 train
+mfvmyzvxtq 1 300 train
+mfvnqsgssa 0 300 val
+mfvqmuulak 1 300 test
+mfwbktpefb 1 300 train
+mfwbolwwrm 1 298 train
+mfwetfchbq 1 300 train
+mfwgnyysjw 1 300 val
+mfwlqpumuz 1 300 val
+mfwmrzpobr 1 300 train
+mfwtraepgl 1 300 train
+mfxbxghiff 1 300 train
+mfxhzjjjke 0 300 train
+mfxuelgnft 1 300 val
+mfxwhrwomd 1 300 val
+mfxwqdrrkx 1 300 val
+mfxzzvenex 0 300 train
+mfykmcaeod 1 300 val
+mfylgjclzo 0 300 train
+mfyqcmjhln 0 300 val
+mfyyttjrmw 1 300 train
+mfyztaevmh 1 300 train
+mfzesrmqbh 1 300 train
+mfzftfxxyn 1 300 train
+mfzjqwwdpu 1 300 train
+mfzkggfyhe 0 300 val
+mfzqxktxud 0 300 train
+mfzqxwzusu 0 300 val
+mgaactvljt 0 300 train
+mgagdgincp 1 300 val
+mgahaaogif 1 301 train
+mgaldszncn 1 300 train
+mgamahbmhe 1 300 train
+mganwomkeh 1 300 train
+mgaouyarhm 0 300 val
+mgapgfdmqg 1 300 train
+mgauoejftk 1 300 train
+mgazriljmm 1 301 train
+mgbcxdsnhv 1 300 train
+mgbcxhxzfx 0 270 train
+mgbifuzkjl 1 300 train
+mgbqujfpob 1 300 val
+mgbreujfhd 0 300 train
+mgbrsgijyr 1 147 train
+mgbwtbkhkr 1 300 train
+mgcaxolkbv 1 300 train
+mgcpxqjjqr 1 300 train
+mgcqoynhne 1 300 val
+mgcxitynzu 1 300 val
+mgcxxktczy 1 292 train
+mgdnyxspbs 1 300 train
+mgehiimjyz 1 300 train
+mgekqrdzpl 0 300 val
+mgelghvdvv 1 301 train
+mgenpzhswm 1 300 val
+mgeybfdckm 1 300 val
+mgfagsfczg 1 300 train
+mgffakbhvu 1 300 train
+mgffjmjnik 1 300 train
+mgffqovfzc 1 300 val
+mgfnonbgfy 1 300 train
+mgfrvmyjep 1 300 train
+mgftwehkjc 1 288 train
+mgfvxootxo 1 300 train
+mgfwrreqgy 0 301 train
+mgfxummjtg 1 300 train
+mggawucehk 1 301 val
+mggcjkzkrl 1 301 val
+mggcvaadmy 1 300 train
+mggekzzbrg 1 300 train
+mggeokkrme 0 300 train
+mgghpbbmgt 1 301 train
+mggmjvqgnu 1 241 train
+mggmmokece 1 301 train
+mggsjmcobq 1 300 val
+mggyzqwagn 1 300 train
+mghhwnalpd 1 300 train
+mghimumgzc 1 300 train
+mghkhofalh 1 300 val
+mghlaegzxy 1 300 train
+mghmzqouwk 1 300 train
+mghspxtpac 0 300 train
+mghyrztebm 0 301 val
+mgidsfaxnv 0 300 train
+mgihyaeyzx 1 300 train
+mgijshtnhc 1 300 train
+mgikgekvol 1 297 val
+mgintdeaii 1 300 train
+mgiofhkmqe 1 300 train
+mgiqwuqfmr 1 300 train
+mgivheipcw 1 298 train
+mgjcsexroi 1 298 train
+mgjozqlxrj 1 300 train
+mgjqztjkrz 1 300 val
+mgjskcaukt 0 300 train
+mgjswiuvkt 1 300 train
+mgjtubalsm 1 300 val
+mgjufiycno 1 300 train
+mgjwxjopnd 1 300 train
+mgjziehmep 1 241 train
+mgkkbmfumw 1 300 train
+mgkrqbliuw 0 300 train
+mgkrriubxt 0 300 val
+mgkvhkzffl 1 300 train
+mgkyurkpqv 1 299 test
+mglagycslz 1 301 val
+mglevosjfn 1 300 train
+mglljtqonk 1 300 train
+mglryfluzt 0 300 val
+mglteznjoo 1 301 val
+mgmbvcbpmn 1 300 train
+mgmdckoswf 1 300 train
+mgmfamvkyc 1 300 train
+mgmlvymvvf 1 300 train
+mgmotiynik 1 300 train
+mgmstkxrkj 1 300 train
+mgmtbzdkgz 1 300 train
+mgmvrynbto 1 300 train
+mgmwgpuxxg 0 300 train
+mgmwvsrtvu 1 300 train
+mgnfzoueof 1 300 train
+mgnjkbjnfj 0 300 train
+mgnoftqmia 1 301 val
+mgnqkbtorj 0 298 train
+mgnwvygyzm 1 300 train
+mgnxkvyoer 1 300 train
+mgnyvajbsp 1 300 train
+mgodhqcsdf 0 300 train
+mgoknnjaer 1 300 train
+mgoopqrhew 0 300 train
+mgooxpdsgo 1 298 train
+mgowgnxopo 1 300 train
+mgowkzsbyx 0 300 train
+mgpcffqeua 1 300 train
+mgpdagorze 1 300 val
+mgppxfqtvs 1 300 train
+mgpuunqwrx 0 300 train
+mgpvxglrkt 1 301 train
+mgpwwfhrxj 1 300 train
+mgpxxgvgbv 1 300 train
+mgpyzkzswg 1 301 val
+mgqbghmiik 1 301 val
+mgqceuafmt 1 297 train
+mgqfapjavf 1 299 train
+mgqlxlnize 0 300 train
+mgqmcbtfdq 1 300 train
+mgqnmkiywu 1 300 val
+mgqsbsgfzn 1 300 train
+mgqvcgbxiy 1 300 train
+mgqwzfrxmk 1 301 val
+mgrsqyxcsd 1 300 val
+mgrwudpefe 1 300 train
+mgscjwykcg 1 99 train
+mgsizenxgo 1 299 val
+mgskrududu 1 300 val
+mgspcywubk 1 300 train
+mgssylcwny 0 300 train
+mgsyqhjzoz 1 292 val
+mgtctpvzdt 1 300 train
+mgtmgmluru 1 300 train
+mgttaigwue 1 300 train
+mgtupalflu 1 301 train
+mgufhcqmja 1 296 train
+mguicjhxmq 0 300 train
+mguipgxjkk 1 300 val
+mguvbpjjwd 1 300 train
+mguwgkdjhj 1 300 train
+mguyxtcrlv 1 300 train
+mguzxxwwkl 1 300 train
+mgvepggeok 1 300 train
+mgvexgxjsi 1 300 train
+mgvgbsmpul 1 300 train
+mgvglvwovs 1 299 train
+mgvjqaapsj 1 300 train
+mgvjzaevmk 1 300 train
+mgvsksvulb 1 300 val
+mgwayxuife 1 300 val
+mgwbfzhxjf 1 300 train
+mgwbjxpbxr 0 300 train
+mgwbncyafe 1 300 train
+mgwfbbzmod 1 300 train
+mgwkuspspp 1 300 train
+mgwrmymiue 0 300 val
+mgwsapzwym 1 298 val
+mgwsgeszwn 1 300 train
+mgwtoqonaf 1 300 train
+mgwuocuold 1 300 train
+mgwwlmhtie 1 300 train
+mgwysiozwn 1 300 train
+mgxbugmyre 0 300 train
+mgxdtegobh 1 300 train
+mgxharnhgr 1 300 train
+mgxjmuxvez 1 300 train
+mgxkzuxhdh 1 301 train
+mgxqmjtjlb 1 300 train
+mgygcsisld 1 300 train
+mgynrmzbmu 1 300 train
+mgytaoorce 1 300 train
+mgytvtfutc 1 300 val
+mgyyyryhbf 0 300 train
+mgzctjcgzz 1 300 test
+mgzefmbccb 0 300 train
+mgzkbezuib 1 300 train
+mgzozupgiz 1 300 train
+mgztuebtqi 1 300 train
+mgzvoivcdw 1 300 train
+mhacmuplap 1 300 val
+mhaflpleny 0 300 train
+mhajtqnzip 1 300 train
+mhakmlpdyr 1 300 train
+mhauggkvbb 1 298 train
+mhaxtsrgfk 1 302 train
+mhaxyafguf 1 300 val
+mhazvvsnnq 1 300 train
+mhbbirvchq 1 300 val
+mhbmzupnrn 0 300 train
+mhbrikvqzo 1 300 train
+mhcclzkgxn 1 300 train
+mhcdzjgaak 1 300 train
+mhcklyazrf 0 300 train
+mhcluxnbxo 1 300 train
+mhctqckhxj 1 300 val
+mhcvugfhjv 1 300 train
+mhczfnggdu 1 300 val
+mhdfvzberk 1 300 val
+mhdnutxwed 0 300 train
+mhdugjpmkg 1 299 test
+mheamosoni 1 300 val
+mhedfkvapx 1 300 train
+mhegqgdtat 1 301 train
+mheltyvedp 1 300 train
+mhesjzgsbt 1 300 train
+mheyevxpbk 0 300 train
+mheyprkyyu 1 300 val
+mhfdamnmpw 0 300 val
+mhfkhqmukj 1 298 val
+mhfltxnfvw 1 300 train
+mhflwchqba 1 299 train
+mhfmljjxlf 0 300 train
+mhfnldxixw 0 300 train
+mhfnqpxelw 1 301 train
+mhfooaulrx 1 300 train
+mhfuzkzsos 1 300 train
+mhfwijtxxj 1 300 train
+mhgcspaoen 1 300 train
+mhgoafjfwq 1 300 train
+mhgpjsdotq 1 298 train
+mhgrjhdutc 1 269 train
+mhgtquwyko 1 300 train
+mhgwskbcgu 1 300 train
+mhgyqcjtpn 0 300 train
+mhgytqtrnf 1 300 train
+mhhcbynpls 1 300 val
+mhhcsyiobk 0 300 train
+mhhfoyzxyb 1 300 train
+mhhnqlpbiw 1 300 val
+mhhpbifneh 1 300 train
+mhhpgiaovb 1 300 train
+mhhxsljvfx 0 300 train
+mhinrkcjtd 1 300 train
+mhiotvftaq 1 300 train
+mhiywyxypg 1 301 train
+mhjafyjzeo 1 298 train
+mhjbunqoch 1 300 train
+mhjhajczdx 1 300 train
+mhjkcxbvvx 1 300 train
+mhjlktudzn 0 301 train
+mhjmklcowm 1 300 train
+mhjsoioxvt 1 300 train
+mhjyvtibkt 1 301 train
+mhknvdzfxy 1 300 test
+mhkqwlfujs 1 300 val
+mhletfuffq 1 300 train
+mhlieqqwhs 1 300 train
+mhlildiivh 1 300 train
+mhllqixqud 1 300 train
+mhlqhnuycn 1 300 val
+mhlrkzbydm 1 300 train
+mhlucuawil 1 300 val
+mhlviycfpq 0 300 train
+mhlxinrrba 1 298 train
+mhmipnffot 1 300 val
+mhmknnucmx 1 300 train
+mhmmbfwove 1 300 train
+mhmtfwbmsr 1 300 train
+mhmxkxmmfm 1 300 train
+mhnbzzaodo 1 298 train
+mhnfhzbzan 1 300 val
+mhngzlqmyo 1 300 val
+mhnormhqdv 0 300 train
+mhnvpjrbrm 0 300 train
+mhnvuzoucd 0 300 train
+mhoaaejiuk 1 298 train
+mhocahvtwc 1 299 test
+mhodpmscfi 1 299 train
+mhojzdqmib 0 300 val
+mholkuftuf 0 300 train
+mholrxkvzz 1 300 train
+mhontvpbbe 1 300 train
+mhorrhfkiy 1 300 train
+mhouvavsws 0 301 train
+mhovvnvttx 1 299 val
+mhowsshwzo 0 300 train
+mhowtleznm 1 300 val
+mhpavogfxb 0 301 train
+mhpfornvnc 1 300 val
+mhpgyqlaad 0 301 train
+mhpkbsgucr 1 300 train
+mhplyirnlu 1 83 train
+mhpmnbhyvk 0 300 train
+mhpmzqalov 1 299 test
+mhptaljwme 1 300 train
+mhpufkzvbw 1 300 train
+mhpuylvgcm 1 300 train
+mhqafosshj 1 300 val
+mhqcccufbu 0 300 train
+mhqfyrnnir 0 300 train
+mhqhkcuniu 1 301 val
+mhqqoeqhim 1 300 train
+mhqqvkaewa 1 300 train
+mhqswhdglf 1 300 val
+mhqtqrkxil 1 299 train
+mhquudpeyw 1 300 train
+mhqveymbha 1 300 val
+mhrayxalse 0 300 train
+mhrguzfats 1 300 train
+mhriwvmxij 1 301 val
+mhroputoso 1 300 train
+mhrqokvzmx 0 300 train
+mhrsezuwcd 1 300 train
+mhrvmmkvrp 1 300 train
+mhrzwepcfp 1 300 train
+mhshpurlet 1 300 val
+mhstgsafny 1 299 val
+mhtggvnsyy 1 298 train
+mhthibxczx 1 300 train
+mhtnvmaiby 1 300 train
+mhtnzwhzoe 1 300 train
+mhtohpkfxk 1 300 train
+mhtrlxbtku 1 299 train
+mhtxbatbnq 1 300 train
+mhtzilkamz 1 300 train
+mhuicmjayr 1 299 val
+mhukaqwoqa 1 300 val
+mhuudzilvn 1 300 train
+mhvebxvhsx 0 300 train
+mhvjknncfz 1 300 train
+mhvjlwbcnw 0 300 train
+mhvoastzmn 1 300 train
+mhvphnquoh 0 300 train
+mhvpyfhthd 1 300 train
+mhwfjwwnta 1 300 train
+mhwhznaley 1 300 train
+mhwjvpynya 1 300 train
+mhwozrtfzr 1 300 val
+mhwuahbcbt 0 300 train
+mhwzrcjgcu 1 300 val
+mhxdbykfat 0 300 val
+mhxghkwqff 1 300 train
+mhxkecpxhh 1 300 train
+mhxqbhgxgr 1 300 train
+mhxykhhfyc 0 300 val
+mhycgjmtnr 1 301 val
+mhyfqyhblt 1 300 train
+mhykdzwmra 0 301 train
+mhyrxbiwfn 1 301 train
+mhyujzhybb 1 300 train
+mhzarfzbrp 1 300 train
+mhzclfcbix 1 300 train
+mhzhlpcmut 1 300 train
+mhzhupfrlf 1 300 train
+mhzkpbirvi 1 300 val
+mhzqgmlnyk 1 300 train
+mhzviutemn 1 301 train
+mhzvjqacfd 1 300 train
+miaigizqew 1 300 val
+miajbknfvi 0 300 train
+miajipbaut 1 300 train
+miamtdwvgi 1 300 train
+miaobjhtgg 1 300 train
+miaqcqdpdi 1 300 train
+miaqzuzdqs 1 301 train
+mibbivalty 1 300 train
+mibjsxichk 1 300 val
+mibroomoth 1 300 train
+mibtdfozlk 0 300 val
+mibwzssjaa 1 300 val
+micahsvvgk 1 300 train
+micgiwtqbw 1 300 train
+micmnryskh 1 300 train
+micmolsplw 1 241 train
+micnvcnjjo 1 300 train
+micogytjfe 1 302 val
+micvjzsayv 1 301 train
+micyuwflpj 1 300 train
+mideqocvkz 1 299 val
+midhwbxlba 0 300 val
+midjxktmhc 0 300 train
+midkumgovn 1 300 train
+midpeunjaz 1 134 val
+midvhpinvf 1 300 val
+mieffggtdl 1 300 train
+miekjilhnz 1 297 train
+mieymoayqm 1 300 train
+miezsztvjn 1 300 val
+miffezeisy 1 300 train
+mifhqxrplf 1 300 val
+mifhzopvac 0 300 train
+mifkehwwyz 0 300 train
+mifnxlnrre 1 300 train
+miftcmdfkt 1 300 train
+miftqwsvrb 1 300 train
+mifukgvbjz 1 300 train
+mifwziornb 1 298 train
+migbhnuwfd 1 300 val
+migerlence 1 300 train
+mignklqheo 1 298 val
+mihfrorbbk 1 301 val
+mihgfdbmci 1 300 val
+mihmgeixxo 1 300 train
+mihpigaiiz 1 300 train
+mihuxyaibd 0 300 train
+mihvgkrred 1 300 train
+mihvjdxmzb 1 301 train
+miiaudwrsp 0 300 train
+miilpjjjxr 1 300 train
+miinwuvunx 1 300 train
+miiocrddnj 1 300 val
+miiymgajty 0 300 train
+miizliwvzp 1 300 train
+mijazqagcf 1 300 train
+mijcndoajb 1 300 val
+mijdrainqd 1 300 val
+mijhxkvqjp 0 300 train
+mijiotoewf 1 300 train
+mijparamji 1 300 train
+mijpygdheq 1 249 train
+mijvnkzvic 0 300 train
+mikekwwjlf 1 300 train
+mikewowtop 1 300 val
+mikfurszuu 1 300 train
+mikjecomyg 1 300 train
+mikknnpbfw 1 300 train
+mikpzgbgss 1 300 train
+miktwfbxwx 1 300 val
+mikzhzibzk 1 300 train
+milbyxizqu 1 300 train
+mildthplys 1 300 train
+mildxwcoen 0 300 val
+milfleydfa 1 300 train
+milfnnagex 1 300 train
+miltxpsvmr 0 300 val
+milynayncg 1 300 train
+mimbqeyuel 1 300 train
+mimczjjwfq 1 299 test
+mimeseeebb 1 298 train
+mimirmzpfa 1 300 train
+mimixvwwxu 1 300 train
+mimlmhrluv 1 300 train
+mimxcyfnpj 0 300 val
+mimxuwpveu 0 301 train
+mimypeuhfs 1 300 train
+minkalozqj 1 300 train
+minpodxkuj 1 240 val
+minqtfpttp 0 300 train
+minuszrvlf 1 300 train
+miofchbvht 0 300 train
+miogqxvnov 0 300 val
+miomxrbxbl 1 300 train
+mioqwrvlqh 1 300 train
+mioumavyso 1 300 train
+miovsaqwmt 1 300 train
+mipigidtnz 1 300 train
+miplnqyalb 1 300 train
+mipuisjvnk 1 300 train
+mipxyecgcb 1 300 train
+mipytuozkc 1 300 test
+miqbgypdzu 1 300 train
+miqdockzwf 0 300 train
+miqgexfant 0 300 train
+miqqlrmyjj 1 300 train
+miqsoyztik 1 300 train
+mirgioyvjt 1 300 train
+mirgysgddb 0 300 val
+miropyxfuq 0 300 train
+mirrjdymnz 1 300 val
+mirtrzrvsb 1 300 train
+mirupkdioz 1 300 train
+mirxcuqzeh 1 300 train
+misadqpnmp 1 300 train
+misitumkmh 1 300 train
+misusdkemd 0 300 train
+miswpmnkkb 1 300 val
+mitarneamy 1 300 train
+mitgfpwmqp 1 300 train
+mitjfkkjqo 1 300 train
+mitjzudefb 1 300 train
+mitkblyvjt 1 300 train
+mitmcjtbca 0 300 train
+mitnemgsew 1 300 train
+mitpghrqno 1 300 train
+mitqbmfhef 1 300 train
+mitviaecyj 1 300 val
+miuaiytuus 1 300 val
+miubyqsveo 1 302 train
+miujnvhynt 1 300 train
+miuklsthpp 1 300 train
+miusulscga 1 300 val
+mivamcdkfj 0 241 train
+miveiztdxk 0 300 train
+mivgqaekuc 1 301 train
+mivhpsubzw 1 300 train
+mivnewdfya 1 300 val
+mivvdrmvyh 1 299 val
+miwnzmeucy 1 300 train
+miwoxsjayv 1 300 train
+miwsnvijjt 1 300 val
+miwszqhpcl 1 300 val
+mixbzqwxxj 1 301 val
+mixjmprcjz 0 301 train
+mixllmkjqi 1 298 train
+mixsnsndgm 1 300 train
+mixuaegpmy 1 300 val
+mixuhvgzfk 1 300 train
+mixuqelwcx 1 300 train
+miybizdwkq 1 292 val
+miydooprln 1 241 train
+miyfwiaiee 1 300 train
+miyhawycjt 1 300 train
+miypqfywkt 1 300 train
+miysdgsjvp 0 300 train
+miytsiefmq 1 300 train
+miyuyiyobf 1 300 val
+miyvdzmmjh 1 300 train
+miywrjuewa 1 300 val
+miyzalzegh 1 300 train
+mizamkaulc 1 300 train
+mizldzaypr 1 300 train
+mizsfcuacz 1 300 train
+mizslqxsru 1 300 train
+mizwnmzxvz 1 301 train
+mizyasvwrk 1 300 train
+mjaazuoqfh 0 300 train
+mjacbitzkz 1 300 train
+mjakyzigqy 1 147 train
+mjanyjoohc 1 300 train
+mjapfvflxr 1 300 val
+mjarwdrxkt 1 300 train
+mjaviyjxob 1 300 val
+mjawqtjcls 1 300 train
+mjborojgyq 1 300 train
+mjbqbwzsnq 1 300 train
+mjbrhvptbt 1 300 train
+mjbsecjdrs 1 300 train
+mjchoyrkcz 1 300 train
+mjclckdtqd 1 300 train
+mjcxmewucz 1 301 train
+mjczaopxxm 1 300 val
+mjdbjwruav 1 241 train
+mjdbqxbvqt 1 300 train
+mjddtvnwli 0 300 val
+mjdhqdjgll 1 300 train
+mjdjryawks 1 301 train
+mjdmsdqmty 1 300 val
+mjeciynclw 1 300 train
+mjehomolmu 1 300 train
+mjekrjsysi 1 300 train
+mjenyhgkpr 1 300 train
+mjetzeswnn 1 299 val
+mjevjwpkgg 1 300 train
+mjezjlcqju 1 300 train
+mjfjaazbbs 1 300 train
+mjfkfksrfd 1 300 train
+mjfpfvqare 1 300 val
+mjfpjwssvv 1 300 train
+mjfplichsx 1 300 train
+mjfrrsrlfv 1 300 val
+mjfwbgyczg 1 300 train
+mjfyrqxxpd 1 300 train
+mjfzhfzkqm 1 300 train
+mjfzyzhask 0 300 train
+mjgaoewdpl 1 300 train
+mjgdueyfxs 1 300 train
+mjghuumhti 1 300 train
+mjgjtniunh 0 300 train
+mjglsobpen 1 300 train
+mjgnusmyvt 0 300 train
+mjgquvwnna 1 300 train
+mjhapgjiul 1 301 train
+mjhazrzeeg 0 300 train
+mjhomnkvys 1 300 train
+mjhsdviywb 1 300 train
+mjhtykeebu 1 300 train
+mjhxcarjjr 1 300 val
+mjihgsfeyo 0 300 train
+mjijjjqdqf 1 300 val
+mjijxfzwel 1 300 train
+mjilrbhewf 1 300 train
+mjitszabsg 1 301 val
+mjjcsxynrv 1 125 train
+mjjfachjxw 1 300 test
+mjjonwppll 0 300 train
+mjjskzwxfj 1 302 train
+mjjtxvykso 1 300 train
+mjkbdkheto 1 301 train
+mjkbvazkvc 1 300 train
+mjkgbltnav 1 301 val
+mjkgxxepym 1 147 train
+mjkjapqdaq 1 300 train
+mjkmgnetur 1 300 train
+mjkqvfywge 1 300 train
+mjkwisgelb 1 300 train
+mjkxlihigq 1 241 train
+mjldbxggbe 1 300 test
+mjlfbcgrbd 1 300 train
+mjlietchzg 1 300 train
+mjlqcikpbb 1 300 train
+mjmalbpqin 1 300 train
+mjmazdehlr 1 300 val
+mjmbkhsjlk 1 300 train
+mjmizpuvri 0 300 train
+mjmndqjkzx 1 300 train
+mjmwlaafnb 1 300 train
+mjnixlfyme 1 300 val
+mjnjxisziq 1 297 train
+mjnkwyrvqh 0 300 train
+mjnmplfspj 0 300 train
+mjnunrkacw 1 300 val
+mjoafcwkac 1 300 train
+mjohwwdvce 1 300 train
+mjomlqohrj 1 300 train
+mjooxdonbv 1 300 train
+mjosqprczi 1 300 train
+mjovqyhfcg 1 300 train
+mjoxqsdwfb 1 300 train
+mjpdokcdbf 1 300 train
+mjpgbgdadg 1 300 val
+mjpgdctjqx 1 301 train
+mjpjvpclnv 1 240 train
+mjpnxvljbn 1 300 train
+mjqfxqjkkc 1 300 train
+mjqhfjmdia 0 300 train
+mjqktsbgyj 0 300 val
+mjqncbrymc 1 300 train
+mjqrqqutkc 1 300 train
+mjqtuozaey 0 298 train
+mjrakujtle 1 297 train
+mjrdizjvsc 1 298 val
+mjrggwhnga 1 300 train
+mjrhgpzael 1 300 train
+mjrlhfwfzd 1 300 train
+mjrngifuko 1 300 train
+mjrqjaxlls 1 300 train
+mjrqooshbs 1 300 train
+mjrytxkmlz 1 300 train
+mjsbalcyqw 1 300 train
+mjsdygsjds 1 241 train
+mjtgoedhei 0 300 train
+mjtoqprbwc 1 300 train
+mjtvfjrgbx 1 300 train
+mjumqkkpaf 0 300 train
+mjuzhpghht 1 301 train
+mjvgnqftky 1 300 train
+mjvhjdrokp 1 300 train
+mjvicqsnkc 1 300 train
+mjvjzqlrog 0 300 train
+mjvnjsjyny 0 300 train
+mjvnwsmvvm 1 300 train
+mjvqyntgss 1 300 train
+mjvsodexca 1 269 train
+mjvxkorliv 1 300 train
+mjwfcmeagh 1 300 train
+mjwhuetegg 1 300 val
+mjwjprlcye 0 300 train
+mjwnghbkwq 1 300 train
+mjwnzmpiup 1 300 train
+mjwrwpbtcr 1 300 train
+mjwswqujru 0 300 train
+mjwyrorrjl 1 300 val
+mjwzercnpj 1 300 train
+mjwzyarpbf 1 300 train
+mjxahvvxja 0 300 train
+mjxcnuywxf 1 301 train
+mjxnjckass 1 300 val
+mjxrekxahg 1 300 train
+mjxsrxxxkc 1 241 train
+mjyawvyhes 0 300 train
+mjyhmgmzcb 1 300 train
+mjyiggtyrn 1 300 val
+mjykhpgzqh 1 300 train
+mjykrmeqja 1 288 train
+mjymjwsfnd 1 300 train
+mjyrjygfun 1 300 val
+mjyrodrtat 1 300 train
+mjyvtfwbol 1 300 train
+mjyxeggsnu 1 241 train
+mjyynevytl 1 300 train
+mjzcejuggb 1 288 train
+mjzhdjujih 1 300 train
+mjzmlmeamj 0 300 val
+mjzrwdkscp 0 300 train
+mjzrxyvqwm 1 300 train
+mjzvnuxbzi 1 301 train
+mjzwhqyvux 0 300 train
+mjzysooysz 0 300 train
+mkafqtmiqq 0 300 train
+mkajkmnnbd 1 300 test
+mkalscbxub 1 301 train
+mkalzssdha 1 299 test
+mkawffchpo 1 300 train
+mkbbsnaksn 1 300 val
+mkbcwcfjzf 1 301 train
+mkbeatsghr 1 241 train
+mkbiklhmfm 1 300 train
+mkblttkrmq 1 300 test
+mkbmqtkiuj 1 301 val
+mkbmwqvjaa 1 300 train
+mkbnkdnzoh 1 300 train
+mkbnyfeywp 1 300 train
+mkbrhmeogy 1 300 train
+mkbuiiqfkb 1 300 val
+mkbuwdmrgg 1 301 train
+mkcbcklvdf 1 300 train
+mkcfnzuvso 1 300 train
+mkcmhdexey 0 300 train
+mkcmnwgwcm 1 300 train
+mkcopkvpxp 1 300 train
+mkdknbyxdo 1 300 train
+mkdlgsxjil 1 300 train
+mkdowahpgn 1 300 train
+mkdtiamkdo 1 301 train
+mkdvewbfie 0 300 train
+mkeeqnipgc 1 298 train
+mkefqksxbz 1 302 train
+mkegrwrfmq 1 300 val
+mkejzspdrg 1 300 train
+mkekdeolvn 1 298 train
+mkenkegdkg 0 300 train
+mkepctfdaw 1 300 train
+mkerbbyzle 1 300 val
+mkervgvphw 1 300 val
+mketotqlqs 1 300 val
+mkevcigaff 1 300 train
+mkexihfsaa 1 300 val
+mkffajjctf 1 298 val
+mkfgkdbljr 1 300 train
+mkfhemeicf 1 300 val
+mkfjvbixjb 1 300 train
+mkfjyiondl 1 300 val
+mkgbcumtar 0 300 train
+mkgfduszjw 1 241 train
+mkggrfrtiy 0 300 train
+mkgijroufc 1 300 train
+mkgrjszxiz 1 300 train
+mkguudhxjt 0 300 val
+mkguynxvby 1 298 train
+mkgyhnnngv 1 300 train
+mkhrzrquts 1 299 train
+mkhugpdwna 1 240 train
+mkhxeeejsq 1 300 train
+mkhzfpfppo 1 300 train
+mkhzusebru 1 300 train
+mkhzvgwtpj 1 300 train
+mkibxglzfg 1 300 train
+mkidwbzpts 1 300 train
+mkigbwxhsl 0 300 train
+mkimvyhtgk 1 300 train
+mkiqjhagtx 1 300 train
+mkitrdiiwf 0 300 train
+mkiuxbzacw 1 300 train
+mkiyscwyvx 1 300 val
+mkjgninegt 1 300 train
+mkjjpdpavo 1 297 val
+mkjnfkhfbd 1 300 train
+mkjrjuxgnw 0 300 train
+mkjwbmpcwf 0 298 train
+mkjyhvzzaa 1 299 val
+mkkdnbvows 1 241 train
+mkkgfwwylk 0 301 train
+mkkhvadwst 1 300 train
+mkkrjxgffy 1 300 train
+mkkvrqxibm 1 83 train
+mkkyntgbay 0 300 train
+mkkywkfxgo 1 300 train
+mklclbnubu 1 300 train
+mklgltprmz 1 300 train
+mklhprzocd 1 300 train
+mklifsrgoe 1 300 train
+mkljsbyaro 1 300 train
+mklrxcmatv 1 300 train
+mklwqgyktp 1 300 train
+mkmgcxaztt 0 300 test
+mkmmotqjcn 1 300 train
+mkmprdclww 1 300 train
+mkmqkzpily 1 300 train
+mkmubikplv 1 300 train
+mkmxgchlfx 1 300 train
+mkmznavham 1 300 train
+mknbbmjhdf 1 300 train
+mknhehovob 0 269 train
+mknhojywui 1 300 train
+mknjphtizt 1 300 train
+mknlwgapes 1 298 val
+mknprbxcsv 1 300 train
+mknyjrwszz 1 300 train
+mkocsyigir 1 300 train
+mkokzwtuoq 1 299 test
+mkoqcomakl 1 300 train
+mkorgsgmwb 1 300 val
+mkornkzcen 1 300 train
+mkotiqzbwv 1 300 train
+mkoulkiqwv 1 300 train
+mkowuaiumn 1 300 train
+mkoydwravm 1 296 train
+mkpdtglgrg 1 300 train
+mkpfyprvdo 1 300 train
+mkphymhgbd 1 300 test
+mkpiffokbc 0 300 train
+mkpimvqjeo 1 300 train
+mkpjsahuns 1 300 train
+mkpmimttil 0 300 train
+mkpnvosonk 0 300 train
+mkpvhmbgmp 0 300 train
+mkpxlnvlil 0 300 train
+mkpxulecxi 1 300 train
+mkqbuzeepg 1 297 train
+mkqdxfdojg 0 300 train
+mkqfsxplor 1 301 train
+mkqmwdhewv 1 300 train
+mkqreykxet 0 300 val
+mkqtqinolz 1 300 train
+mkqvrbywon 1 300 train
+mkqvyanriv 1 300 train
+mkqztylkgz 1 300 train
+mkrajqwqnc 1 300 train
+mkrbbupdrx 1 300 train
+mkrbwywdjs 1 299 train
+mkrgszcrsn 1 300 train
+mkrhkyhwcu 1 300 train
+mkrilwheno 1 300 train
+mkrpxokppu 1 300 train
+mkrrzayugk 1 298 train
+mkrtnaxjyq 1 300 train
+mkryasxsjv 0 300 val
+mkscgiqmvg 0 300 train
+mkspcatszv 0 300 train
+mksvxnrrum 1 300 val
+mktbnkbqwu 1 300 train
+mktjrllbit 0 300 train
+mktoozqbnc 1 300 train
+mktreqjjyz 1 300 train
+mktvahjxup 1 301 train
+mkunzsixlt 1 300 train
+mkuzbgxucn 1 300 train
+mkvbnqfexi 1 300 val
+mkvgimuxbe 1 300 train
+mkvkcxqowh 1 300 train
+mkvmlkgoyb 1 300 train
+mkvoydosrv 1 300 train
+mkvpsqcggo 1 300 val
+mkvuuxacvv 1 300 train
+mkvveabzip 1 300 train
+mkwhpzswmo 0 300 val
+mkwzzapnfy 1 300 train
+mkxanxikul 0 300 val
+mkxmvreoth 0 301 train
+mkxoqgkseh 0 300 train
+mkxvwyxsbq 1 300 val
+mkxzfysiua 0 300 val
+mkxzudujpi 0 300 train
+mkyaaxrhuc 1 298 train
+mkyezxiqtx 1 300 val
+mkyjbcilgo 1 300 train
+mkyoyacesx 1 299 test
+mkyprfrver 1 300 val
+mkypxmzqac 0 300 train
+mkyrsdaxkh 1 241 train
+mkywshyyed 1 298 train
+mkyxeoisam 1 301 train
+mkzaekkvej 0 299 test
+mkzdedcnxs 1 300 train
+mkziijlgsh 1 241 train
+mkzlarjhnf 1 300 train
+mkzsfzldon 1 300 train
+mkztxvglnl 1 298 train
+mkzyvjdlrx 1 301 train
+mlajsldmhz 1 300 val
+mlapkogbzz 0 299 val
+mlaqizzoue 1 300 train
+mlawsdcvgp 1 109 train
+mlaxxgpqlx 1 300 test
+mlbaxilvxn 1 300 train
+mlbbyrvqar 1 300 train
+mlbffnvqlc 1 300 val
+mlbhojlrzv 1 300 train
+mlbkenfucz 1 300 train
+mlbllqnuml 1 300 train
+mlbvnxbize 1 300 train
+mlbxgllrqi 0 300 val
+mlcdfxfbhd 1 300 train
+mlcfdzogvy 1 300 train
+mlcgbmgzka 1 300 train
+mlcsjaecux 0 300 train
+mlcxvhpapr 1 301 train
+mlcxxmlikg 1 300 train
+mlcxywqjzj 1 300 train
+mlczkmmgnm 1 298 train
+mlddfvsusz 1 300 train
+mlddleytwm 0 300 train
+mlddufufkr 1 300 val
+mlddwqfbpa 1 99 train
+mldhxgkaqm 1 300 train
+mlditgqkpt 1 297 train
+mldkjetsfy 1 300 val
+mldkxuuwze 1 300 train
+mldnbcsnfk 0 300 train
+mldnrqmhfs 0 300 train
+mldvbiuelb 1 301 val
+mldvhtjqhj 1 300 train
+mldxkftymx 1 300 train
+mldxmnzkkm 1 300 train
+mlecirsqrw 1 300 val
+mleipuqost 1 300 train
+mlejlmzczj 1 300 train
+mlenpljdkk 1 300 train
+mlerygvade 1 240 train
+mlfbccdtoy 0 300 val
+mlfbyfnulv 1 300 train
+mlfqvenftk 1 300 train
+mlfuzuwsty 0 300 train
+mlfvzcejpj 1 301 train
+mlgewttjnf 1 298 val
+mlgizjagdo 1 300 val
+mlgqybmotk 1 300 train
+mlgrtcszpc 1 288 train
+mlguvuxlbr 1 241 train
+mlgvyccwcg 1 300 val
+mlhehbckam 1 300 val
+mlhjazstxo 0 300 val
+mlhktmccdi 1 300 train
+mlhrazrnmx 1 300 train
+mlhrxiunuz 1 300 train
+mlhtwxhndd 1 297 train
+mlhuxixymc 1 300 train
+mlibpdhpoo 1 300 train
+mliebogaye 1 300 train
+mligtzwori 1 301 train
+mlilusapoq 1 299 test
+mlivldbdxg 1 300 train
+mliyjgevkl 1 300 train
+mliynshaib 0 300 train
+mlizcisxro 0 300 train
+mljecwshtj 1 300 train
+mljgbhezde 0 300 train
+mljisymedo 1 300 train
+mljmfajswx 1 240 train
+mljyvflayk 1 300 train
+mlkbmsstqk 1 300 train
+mlkcecxwoe 1 300 train
+mlkgpgszyq 1 300 train
+mlkgsjcyjr 1 300 val
+mlkhsrpjpj 1 300 train
+mlkmpkazrv 1 300 val
+mlkqqghbru 1 300 train
+mlkrkufjlx 1 301 train
+mlksowfuay 1 300 train
+mlkvyopavx 0 300 val
+mlkxjgpzpd 0 300 train
+mllhzgcbgz 1 300 train
+mllmufivlm 1 300 train
+mllnjyzxyr 1 300 train
+mllqfiowhs 0 300 train
+mllrbuekom 1 300 val
+mllrjscukk 1 300 train
+mlltielaoz 1 300 train
+mllvfismax 0 301 train
+mllyttwsjh 1 301 train
+mllzkpgatp 1 300 test
+mlmatmawcb 1 300 train
+mlmdkpdvvx 1 300 val
+mlmeqtdknz 0 300 train
+mlmgockhuq 0 300 train
+mlmndeebak 1 300 val
+mlmpqzhehi 1 301 train
+mlmtumrnbq 1 300 train
+mlnazyfrhq 1 300 train
+mlniluajml 1 300 train
+mlnkchjuhs 1 300 val
+mlnlngbtjt 0 300 train
+mlnufwdvoz 1 300 val
+mlobkafnrq 1 298 val
+mloccvfnmo 1 299 train
+mloeefokyq 0 239 train
+mlogkwvpsi 1 297 val
+mlogvlfmoo 0 300 train
+mlooxlmwig 1 300 val
+mlovnncbqr 1 300 val
+mlozmrhbee 1 300 train
+mlpavmazzi 1 300 val
+mlpdsknnzu 1 300 train
+mlpfcinibo 1 300 val
+mlpfpliiwc 1 300 train
+mlpigpthee 1 300 train
+mlpmxhjcdx 1 298 train
+mlpwffuitx 1 300 train
+mlpyeuuivu 1 300 train
+mlpywvfpdf 1 300 train
+mlqcbzzohi 1 300 train
+mlqeewmmuo 1 300 train
+mlqejommbr 1 302 val
+mlqfrubohk 1 300 train
+mlqkxvtgay 0 300 train
+mlqpifjefq 1 300 train
+mlqqlgkteh 1 300 train
+mlqrbawapd 1 300 train
+mlqtepcdhs 0 300 train
+mlqxrrpwbv 1 300 train
+mlqziduhcx 1 300 val
+mlrildvish 1 300 train
+mlrjardewq 1 301 val
+mlrkpbzonb 1 300 train
+mlrktgdwlp 1 298 train
+mlrqvftlxt 1 300 train
+mlruidevki 1 300 test
+mlrupsogap 1 300 val
+mlsjtektyk 1 288 train
+mlsqognxgh 1 300 train
+mlsrcayqar 0 300 train
+mlszktxehr 1 300 train
+mltbqrvddm 1 300 train
+mltdczturk 1 296 val
+mlthcffxdw 1 300 train
+mltjiftqcu 1 301 val
+mltqdiesrj 1 300 train
+mltsotgrqa 1 300 train
+mluddpbvpg 1 300 train
+mlujtnqiaa 1 300 val
+mlukgqhcmy 1 301 val
+mlulatevzu 1 300 train
+mlvdrqjjup 1 300 val
+mlvfcgovjw 0 300 train
+mlvhrkzqwg 1 301 val
+mlvodakwhn 1 300 train
+mlvojaaocm 0 300 train
+mlvrsntepy 1 300 train
+mlvudfbshm 0 300 train
+mlvvuximna 1 300 train
+mlvvzybhqk 1 300 train
+mlwcpuewjs 1 300 val
+mlwdwjemlw 1 300 train
+mlwivuinpr 0 300 train
+mlwkqukbpl 1 300 val
+mlwnlxchfy 0 300 train
+mlwsochmlb 1 300 train
+mlxbtnifob 1 300 test
+mlxepnmnbd 1 300 train
+mlxhgvyggr 1 300 train
+mlxhjqdglp 1 299 test
+mlxlijxzeu 1 300 val
+mlxltyplsa 1 300 train
+mlxmjypeju 1 301 train
+mlxoyqimzq 1 240 val
+mlxtlkgucw 1 298 train
+mlxtzpuxqg 1 146 train
+mlxvhxnlku 1 300 train
+mlxvtisgts 1 300 train
+mlyaxbhdpa 1 300 train
+mlyfoiahzs 1 300 train
+mlygtwoerd 1 288 train
+mlykcpufag 1 300 train
+mlyonwvynm 0 300 train
+mlyqaqnrop 1 300 train
+mlysfuisob 0 300 train
+mlytcikfcq 1 300 train
+mlyuozbqww 1 300 train
+mlzdswsaxa 0 300 train
+mlzhkdxdcx 1 300 train
+mlzmtkspdd 1 300 train
+mlznlqmcet 1 300 train
+mlzpdzboif 1 298 train
+mlzxdfseaw 1 300 train
+mlzxzjsnag 1 300 train
+mmabdoidef 1 300 train
+mmabmgfxcn 1 296 val
+mmafrbslls 1 300 train
+mmagrwmhri 1 300 train
+mmaiitirig 1 300 val
+mmakatptff 1 302 train
+mmaozzcjyd 1 300 train
+mmaqnbggam 1 300 val
+mmazmlnsbf 1 300 train
+mmbjdoekpw 1 300 train
+mmboceybol 1 249 train
+mmboytdtrm 1 300 train
+mmbrxrxbmc 1 300 train
+mmbvtqvqni 1 300 train
+mmcepzpwdn 1 300 train
+mmcexkzxww 0 300 train
+mmcfuiqpkb 1 300 train
+mmcgrtblgx 1 297 train
+mmchaywvdn 1 299 val
+mmcoydzbui 1 300 train
+mmctedypsy 1 301 train
+mmcuuvrkiq 1 300 val
+mmcyzfyztu 1 300 val
+mmdbkjwraz 1 300 train
+mmdjxhgudd 1 300 val
+mmdkogggyc 0 300 train
+mmdlnqdomd 0 300 train
+mmdmvnlctv 1 298 train
+mmdoinutep 1 241 train
+mmdykoamvh 1 300 train
+mmeuivnvmy 1 300 val
+mmeuqzbxeg 1 302 train
+mmfbcmwyph 0 300 train
+mmfdbsospc 0 300 train
+mmfdjlcnqf 1 300 train
+mmffbxzzul 1 300 train
+mmffoscwcq 0 300 train
+mmfghjqmbv 0 300 val
+mmflvskhuh 1 300 train
+mmflxjuaji 1 300 train
+mmfygzgovw 1 300 train
+mmfzdnuzta 1 300 train
+mmfzqstpcp 1 300 train
+mmgcszbwrg 1 147 train
+mmgghfbwbd 1 300 train
+mmgmgdtkxf 0 300 train
+mmgqneybyy 1 300 val
+mmgvyvdaqt 1 300 train
+mmgwvcbsqj 1 300 train
+mmhdcoqsve 0 300 train
+mmhnfsktln 1 300 train
+mmhqiilfxe 1 301 train
+mmhqllmlew 0 300 train
+mmhrdpvkxe 1 300 train
+mmhrkzptld 1 300 test
+mmhuxvvmrd 1 298 train
+mmhyninywo 1 298 val
+mmieogqhxt 1 300 val
+mmifqasqyt 0 300 val
+mmilfjdvlh 1 300 train
+mmimgxqddz 1 300 train
+mmimzookbf 1 300 train
+mmirnuyvix 1 300 val
+mmixeqqxnf 1 300 train
+mmjdrqyjpg 1 300 test
+mmjhaoldfj 0 300 train
+mmjlmlrtmm 1 301 val
+mmjnkwfdtn 1 300 train
+mmjtjxiugn 1 300 val
+mmjuwimfmr 1 300 train
+mmjvwbqfyi 0 300 train
+mmjxqnmail 1 300 train
+mmjzmtiupi 1 300 val
+mmkmdsrphs 1 301 train
+mmkxshbgky 1 301 train
+mmlfzdancp 1 300 train
+mmlggwxvbo 1 300 train
+mmlnibzrzq 1 300 val
+mmltzbfpav 1 300 train
+mmlyfeyvqj 1 300 train
+mmlywvacyj 1 300 train
+mmmfdypfsl 1 300 train
+mmmhyapdrm 1 300 train
+mmmkqbsmhk 1 300 train
+mmmmtvbofq 1 300 train
+mmmrftlnhz 1 300 train
+mmmrhkfgyd 1 297 train
+mmmtjatemb 0 300 train
+mmmuvpidtp 0 300 train
+mmmxbeymwf 1 300 train
+mmndlbvwnz 1 298 train
+mmnhbaozzt 1 300 train
+mmnpcyncul 1 300 val
+mmnuothpbg 1 300 train
+mmnvdrhnzx 1 300 train
+mmnxkghycj 1 300 train
+mmnydlupmz 1 300 train
+mmocxmpvdy 0 300 train
+mmodkqumnh 0 300 train
+mmodrnwivy 1 300 train
+mmoftyaanm 1 241 train
+mmojpeyfax 1 301 val
+mmolobdfvo 1 300 train
+mmootiymqo 1 300 train
+mmpaqcnuib 1 300 val
+mmpdlocepc 1 300 train
+mmphbdmecj 1 300 train
+mmpixsmwao 0 300 train
+mmprbqidgj 1 297 train
+mmqdkxkoja 1 300 train
+mmqgopsczd 0 300 val
+mmqhndqekm 1 300 train
+mmqizaiwng 1 300 train
+mmqjanoirc 1 300 train
+mmqkateles 1 300 train
+mmqltllaqd 1 300 train
+mmqregvnii 1 300 train
+mmqryghsjg 1 300 train
+mmqtmikdlc 1 300 train
+mmqwucucjx 1 300 train
+mmqyaysxlm 1 300 train
+mmqzyecdos 1 300 train
+mmrfoucigq 1 300 train
+mmrikqidtv 1 300 train
+mmrjxzbczm 1 300 train
+mmrkjwypqv 1 301 val
+mmrmyjuqdz 1 300 train
+mmrnzxgwvp 1 300 train
+mmrtvkmxyd 1 300 val
+mmryvpdecx 1 301 val
+mmscdqgipl 0 300 train
+mmsdufgcqc 1 300 train
+mmsqbfvrll 1 300 train
+mmsqgolkrz 1 301 train
+mmsqwjycri 0 300 train
+mmsuchlnep 1 300 train
+mmsxambsmi 1 241 train
+mmsxtonagc 1 300 train
+mmtdeoxolg 1 300 train
+mmtguxjmhz 1 300 val
+mmthbfjgzi 1 300 train
+mmthpnegeq 1 300 val
+mmtinwxzyh 1 299 test
+mmtzgffapv 1 301 val
+mmubhzffti 1 300 train
+mmufeafjtg 1 300 train
+mmumsbwfzp 1 300 val
+mmumyssdwf 1 300 train
+mmuntdijje 0 300 val
+mmunumqhpf 0 300 train
+mmuolksboc 1 300 test
+mmuuxfplfa 0 300 train
+mmuzsnjyte 1 301 train
+mmvcqhantw 1 298 train
+mmvfohlxgv 1 300 val
+mmvggsnizy 0 300 train
+mmvheqsviw 0 300 train
+mmvndghehe 1 300 train
+mmvseejtwb 1 300 train
+mmvustkebu 1 300 train
+mmwaomsqbo 0 241 train
+mmwavjoccr 1 300 train
+mmwgulvxxs 0 298 val
+mmwjbcweji 1 300 train
+mmwsnbizbt 1 301 val
+mmwvxzjwgk 1 300 train
+mmwwmqjezi 1 300 train
+mmwyxsucqf 1 300 val
+mmxaygikgl 1 300 train
+mmxsetbwcu 0 300 train
+mmxzfgnsqy 1 300 train
+mmyafpfltd 1 300 train
+mmycwzkfyg 1 300 train
+mmyhjipdxb 0 300 train
+mmyiwljruq 1 300 train
+mmyntjgyke 0 300 train
+mmypcqudth 1 300 train
+mmyrxwfayb 1 300 train
+mmytpargho 1 301 train
+mmzbobxfhd 1 300 train
+mmzdahmiob 0 300 val
+mmzgwysvwo 1 300 train
+mmzmpkolda 1 300 train
+mmzqhhford 1 300 train
+mmzqpatknv 1 300 train
+mmzvopqaen 1 299 test
+mmzyykqddf 1 299 test
+mmzzgegrma 1 300 train
+mnabssekto 1 300 train
+mnaeujsvor 1 301 train
+mnaqhfnjre 1 300 train
+mnauchmbdz 1 300 train
+mnbdkpwqhk 1 300 train
+mnbixddevd 1 300 val
+mnbjqdvlnx 1 300 train
+mnbrtdchxx 1 300 val
+mncauczhpu 1 241 train
+mncfwsutav 1 300 train
+mncikvahhj 1 300 train
+mncivmgcyi 1 300 val
+mncixabwgy 1 302 val
+mncjaoadtx 1 300 train
+mncritvzqz 1 300 train
+mncrxmgooy 1 300 train
+mndcdkcvnb 0 300 train
+mnefjszcxp 1 300 val
+mnegtfapfm 1 300 train
+mneimxuoac 1 302 train
+mnepaxtvit 1 300 train
+mneqoarzdo 1 300 train
+mnersioyzn 1 300 train
+mneyfatuki 1 301 val
+mneyunmmik 1 300 train
+mnfbkxexcv 1 300 val
+mnfcaoqvkd 1 300 train
+mnfjovosvb 1 300 train
+mnfkngxftz 1 298 train
+mnfnidoris 1 301 train
+mnftldewyt 1 300 train
+mnftwkbozo 1 300 train
+mnfuffsfjl 0 300 train
+mnfumgnkml 1 300 val
+mnfwhucfsa 1 300 train
+mngbbxafui 1 300 train
+mngdibvvjk 1 301 train
+mngqlwxhmp 1 300 train
+mngtbauptp 1 300 train
+mngtierijq 1 300 train
+mnhbyoxjll 1 300 train
+mnhfvwmivg 1 300 train
+mnhhfelxdy 0 300 train
+mnhkpflvzu 1 300 val
+mnhmvegrlq 1 298 val
+mnhqpsbvuu 1 298 train
+mnibtfmpjl 1 300 train
+mnicddcljt 0 300 train
+mnijiihwla 0 300 train
+mnitdyuati 1 300 train
+mnizcgetfn 1 300 val
+mnjbrpwlcd 0 300 train
+mnjipvhwps 1 300 train
+mnjmnznwvf 1 300 train
+mnjnrhbztu 1 300 train
+mnjuaqjuss 1 300 val
+mnjvjpdwcr 1 241 train
+mnjwtcsxcu 1 300 train
+mnkbqhedfq 1 300 val
+mnkedtotqb 1 300 train
+mnkemaypkl 1 300 train
+mnkgppuikv 1 300 train
+mnkianiixq 1 300 train
+mnksguayti 1 300 train
+mnktdnukki 0 300 train
+mnkyyvhzhh 1 300 val
+mnlaooswgz 1 300 train
+mnleayiwzw 1 300 train
+mnlegvxmbo 1 300 train
+mnlfwyppzl 1 300 train
+mnlixezqsk 1 300 val
+mnljdvqdwg 1 300 train
+mnljgllcpy 1 297 val
+mnlvqrsiwl 1 300 train
+mnlxxoicoo 0 300 train
+mnmgiihnce 1 300 train
+mnmhvjxzrs 1 300 train
+mnmorlpvki 1 300 test
+mnmpfbdgyl 0 300 train
+mnmsqekzpi 0 300 train
+mnmucmdztf 1 301 val
+mnmxhznbjv 1 301 train
+mnnnhjgvmr 1 300 val
+mnnourlgyh 1 300 train
+mnnvfccygp 1 300 train
+mnnxgycfik 1 300 test
+mnocmfylmg 1 300 val
+mnorhduwqd 0 300 train
+mnosqaufnf 0 300 train
+mnowxangqx 1 300 test
+mnozdbwjpc 1 300 val
+mnozrthnfv 1 300 train
+mnplyxzxma 1 300 train
+mnppydhxpk 0 300 train
+mnpvjvoxzj 1 300 train
+mnqhpwzycn 0 300 train
+mnqidylcpm 1 300 train
+mnqwcveeqr 1 300 train
+mnqxygpnmf 1 300 test
+mnraxduffa 1 300 train
+mnrbtnulrw 1 301 train
+mnrghjfohp 0 300 train
+mnrhjvpicj 1 300 train
+mnrkabnumq 1 300 train
+mnrnptdpec 0 301 train
+mnrrsffpmg 1 300 train
+mnryzkbmls 1 300 train
+mnsglkvdtz 1 241 train
+mnslaqqghi 1 300 test
+mnsnxzfofw 0 300 train
+mnsqcjelzm 1 300 train
+mnsvqqqfgg 1 300 train
+mnszzjljni 1 300 val
+mntenlthcj 1 300 train
+mntrrpuzhv 0 300 train
+mntsiinqgy 1 300 train
+mntwvwcaiq 1 300 train
+mntxphtklp 1 300 train
+mntzlliqix 1 300 val
+mnullmxfui 1 300 val
+mnumnjvglq 1 300 train
+mnuutqvnmm 1 300 train
+mnuvzbmjuz 1 300 val
+mnuxudmiqe 1 300 train
+mnuzxesfkp 1 300 train
+mnvaadjwcz 1 300 train
+mnvasfdppb 1 300 train
+mnvbsvsuru 1 300 train
+mnvdijuyvs 1 300 train
+mnvgbmzxun 1 300 train
+mnvjeuiyeh 1 147 train
+mnvnriswgw 1 300 train
+mnvoukzemv 1 300 val
+mnvpcrupxd 1 300 train
+mnvrpnpgsd 1 300 train
+mnvukztgxd 0 300 train
+mnvuysmnzq 1 300 train
+mnvvrvfeun 0 300 train
+mnvyuokhem 1 300 test
+mnwhhhhrla 1 300 train
+mnwmlztson 1 300 train
+mnworobpfx 0 300 train
+mnwtljaqwv 1 300 train
+mnwzjackyz 1 300 train
+mnwzqjfapt 1 298 train
+mnxmecmtsf 1 300 train
+mnxsptnjbw 1 300 val
+mnxtcliyou 1 300 train
+mnylsrenbo 0 301 train
+mnytkwhtvx 1 300 train
+mnzabbkpmt 0 300 test
+mnzaejupdn 1 241 train
+mnzghyjkvw 1 300 val
+mnziclwlyf 1 300 val
+mnzqivjzco 1 300 train
+mnzsbmneru 1 300 train
+mnzuibujnf 1 298 train
+mnzvumrmkh 1 241 train
+mnzwccytqg 1 300 train
+moabeatmyh 1 300 val
+moabmldqfw 1 300 val
+moafsgeavo 1 300 train
+moaoyskura 1 300 train
+mobjgaefgm 0 300 train
+mobjgmcrgc 1 193 train
+mobnaipjiw 1 300 test
+mobotpngkx 1 167 train
+mobpepncvh 0 300 train
+mobpjnxddn 1 300 train
+mocctqnubl 1 300 train
+mocdzsbwii 1 300 train
+mocgvcyudw 1 300 train
+mociypgcox 1 300 train
+mocjxxscfy 1 300 train
+mocnjrogph 1 300 val
+mocnqrkaee 1 301 train
+mocwcmlrwu 1 300 train
+mocynzouym 0 300 val
+modeuxjbdx 0 300 train
+modeybhctx 1 300 train
+modhiastfm 1 300 train
+modhzkgxyz 1 300 train
+modjdqzxbr 0 300 train
+modvascehh 1 300 val
+modwqruopr 1 299 test
+moemckcmbx 1 300 val
+moenmdthtj 1 300 train
+moerpiyczb 1 300 test
+moetggyxsc 1 300 train
+moetxgswnj 0 300 train
+moewcmixoa 1 300 train
+moezhyyudz 0 300 train
+mofffbxgnu 1 300 train
+mofhslkfol 1 300 train
+mofhvdmufu 1 300 train
+mofieqeomr 1 300 train
+mofnucrxzq 1 300 train
+mofobetyqy 0 300 train
+mofsviqutr 0 300 train
+moftjdwdps 1 301 train
+mogoqkfmfa 1 300 train
+mogtsahgmr 1 300 train
+moguawjrgf 0 300 train
+mogvaichzb 1 300 train
+mogvbxympc 1 300 train
+mogwgizctk 0 300 train
+mogxguathv 1 241 train
+mogyfuooan 1 300 train
+mohcndxtzi 1 300 train
+mohergefts 1 301 train
+mohimgison 1 300 train
+mohiqoogpb 0 300 test
+mohmwmpumo 1 300 train
+mohnseaoto 0 300 train
+mohtuktaaq 0 300 train
+mohzifxufy 1 300 val
+moiamctvbz 1 300 train
+moiehodfkl 1 300 train
+moiilbntyj 1 300 val
+moiqmdktye 1 300 train
+moirvkrtwd 1 300 val
+moitnvktdb 1 300 train
+moixuooefk 1 300 train
+moizjmymyc 1 300 train
+mojjbckizh 1 300 val
+mojmzcokef 1 300 train
+mokeznwbxc 0 300 train
+mokhiboedg 1 300 train
+mokhwrljbw 1 300 val
+mokpqooliy 1 300 train
+mokxslxlur 1 300 train
+mokxtkclll 0 300 train
+mokyyutwfz 1 300 train
+molgfjfzhs 1 300 train
+moliflmkmq 1 300 train
+mollokzdxh 1 300 train
+molsfyacmw 1 300 val
+moltcujdwt 1 298 train
+momcxqpell 1 301 val
+momktzzirn 1 298 train
+momlabeskg 1 300 train
+mommmecgto 1 300 train
+momsyrkpma 1 300 train
+momvvwoawk 1 300 train
+momyzcxmrz 1 300 train
+monatxmsbm 1 301 val
+monecpmbqd 1 300 train
+monifdaxol 1 301 val
+monkmiecnm 1 300 train
+monleifwyg 1 300 train
+monpghgyjw 1 301 train
+monumbirio 1 300 train
+moobaxornj 1 300 train
+mooecqfhqo 0 300 train
+moohauhlpv 1 300 val
+mooiunmfet 1 301 train
+moorubqvhh 1 300 train
+moosxkzotj 1 300 train
+mooyzravef 1 300 train
+mopahyjgba 1 300 train
+mopiuzviiz 1 300 train
+mopmxdjwvl 1 300 train
+mopnndpagm 1 300 train
+mopqndishn 1 300 test
+mopzomybjd 1 300 train
+moqenssvrs 1 300 train
+moqfaxmnmy 0 300 train
+moqhjwlefs 1 302 val
+moqiivseti 1 300 train
+moqiqpjhna 1 300 train
+moqowbogps 1 300 train
+moqrwhzbjh 1 301 val
+moqrxmkqsw 0 300 train
+moqtyvkgke 0 300 train
+moqvepcynm 1 300 train
+morccwlplu 1 300 train
+mordcwbchi 1 300 test
+morpifgiml 0 300 train
+morrmtzxtk 0 300 train
+morrnuhapk 1 300 train
+mortnvtbye 1 296 val
+mosbaapupv 1 298 train
+mosdjjbbgj 1 298 train
+mosgaxcsdo 1 300 train
+mosjjkreuy 1 300 train
+mospgimhlu 1 240 train
+moszgxfici 1 300 train
+moszjdkiss 1 300 train
+moszpornul 1 300 val
+motasxfqhz 1 300 train
+motfposykz 0 300 train
+motokngbqf 1 299 test
+motowaofoi 1 300 train
+motywdlngy 1 300 train
+moukcmhzle 1 300 train
+mouvarenzx 1 300 train
+mouxgnmzmt 1 300 train
+movpfwmohd 1 300 train
+mowekbmwgx 1 300 train
+mowkdaiums 1 300 train
+mowkpdsrby 0 300 val
+mowkvebfdo 1 300 val
+mowmwjzsgk 1 300 train
+mowpwtlrkq 1 300 train
+mowsgnsors 1 300 train
+mowverekwg 1 300 train
+mowvjebiol 1 100 train
+mowwxgwner 0 301 val
+moxcwrdvka 1 300 train
+moxqahxkgm 1 300 train
+moxuyuchcp 1 300 train
+moxvmdtvfm 1 241 train
+moyhszxymv 1 300 train
+moyljhcxok 0 300 train
+moynpkwtfr 1 300 train
+moynurfzjj 0 300 train
+moytbqbnun 1 300 test
+moytwoyusu 1 299 test
+moyyrcmnfx 1 300 val
+mozbuksqvr 1 301 train
+mozhujvdxd 1 300 train
+mozjxdmwug 0 300 train
+mozkmfiwaz 1 300 train
+mozkxfyeif 1 300 train
+moznaytche 1 300 train
+moznxvssef 1 300 train
+mozsyttixt 1 300 train
+moztzxmyju 1 300 train
+mpaeoafcxe 0 300 train
+mpahdotors 1 300 train
+mpaqhbsomr 1 300 train
+mparfojahr 1 301 train
+mpavnpkeou 1 300 train
+mpbaqpxptp 0 300 train
+mpbcfvbvax 0 300 train
+mpbddoyjda 0 300 train
+mpbngshxjb 1 301 train
+mpbvaumtlo 0 298 train
+mpbwfoljoa 1 301 train
+mpbwoktlvy 1 301 train
+mpcdrpociu 1 298 val
+mpcjoaipkb 1 300 train
+mpcluwvrlr 1 300 train
+mpcmvqondf 0 300 train
+mpcrfmngqu 1 301 train
+mpddkhxbtu 1 300 train
+mpdljgjwpk 1 300 train
+mpdlzgwqpg 1 300 train
+mpdvvrvtur 1 300 train
+mpeahjgsvz 1 300 train
+mpehopbzac 1 301 val
+mpektyojav 1 300 train
+mpemtjrgit 1 298 train
+mpeqislrlk 1 300 train
+mpeqnueqgc 1 300 test
+mpevnpmbfd 1 300 train
+mpewyzatih 0 300 train
+mpeysbsihm 1 300 val
+mpfavjaajt 1 300 train
+mpfeaipyij 1 300 val
+mpfekzxuct 1 300 train
+mpfgfljezf 1 300 train
+mpfifcflrb 1 300 train
+mpfjbgblsd 1 300 val
+mpfswrzaek 1 300 train
+mpfugyawni 1 300 train
+mpfwwmiheu 1 300 val
+mpgafsheqi 1 241 train
+mpgbgmgkrw 1 300 val
+mpgfzpsivw 1 300 val
+mpghbyemea 0 300 train
+mpgmkgiceb 0 300 val
+mpgmxyraya 1 300 val
+mpgpikincg 1 298 train
+mpgulknsba 1 300 train
+mpgwbeasob 1 300 val
+mphdnxdxvb 0 300 train
+mphfaamhel 0 300 train
+mphjiqyquq 1 300 train
+mphnufjern 1 300 train
+mphsgertmm 1 300 test
+mphvjqmwji 1 300 val
+mphvvzwxox 1 300 val
+mpiazbcgxk 1 300 train
+mpibnmnhqk 1 300 train
+mpiiuuqbwt 1 300 train
+mpijkopwrf 1 300 train
+mpivbgsohk 1 300 test
+mpivmvlkyo 1 300 train
+mpiwnvmryp 1 300 train
+mpjcomiphj 1 300 train
+mpjcyyuwni 0 301 train
+mpjfwilxvf 1 300 val
+mpjiuzojzc 0 300 val
+mpjqgvgqar 1 300 train
+mpjumjlgsu 1 300 train
+mpjxpkkwne 1 99 train
+mpjzcymwkr 1 301 train
+mpjzmftxol 1 300 train
+mpkatxoftg 1 300 train
+mpkbbxaqww 0 300 train
+mpkkjoismj 1 298 train
+mpkknizhlp 1 241 train
+mpkmkclffv 1 300 train
+mpkufiekdi 1 298 train
+mpkvsxgdgx 1 300 val
+mplapssgzp 1 300 train
+mpllltxnic 1 300 val
+mplyhvifpg 1 300 val
+mpmafvmwyf 1 300 train
+mpmmdzjoqm 1 300 train
+mpmsykdhka 1 300 train
+mpnsorctmr 1 300 train
+mpnxaoahcx 1 300 train
+mpnypfhpbb 0 300 train
+mpnzxhxwhn 1 301 val
+mpodyrxloh 1 301 val
+mpoelcqwhb 1 300 train
+mpohietqsw 1 300 train
+mpojbiqvms 1 240 val
+mpojwpycjy 1 300 val
+mppizvdmom 1 300 train
+mppjpwwcom 0 300 val
+mppmherzrr 1 300 train
+mppmzqwngq 1 240 train
+mpprxuetfd 0 300 train
+mppyfhpgec 1 300 train
+mpqlorzdfc 1 300 val
+mpqqeckhvo 1 301 train
+mpqwwymarr 1 300 train
+mprailcjhw 1 300 train
+mprbuwqpyh 1 300 train
+mpresqprcg 1 300 train
+mprkhuwxfe 1 300 train
+mprocmdczn 1 300 train
+mprpkfbkya 1 298 train
+mprqawxbbq 1 300 train
+mprtmhylyj 0 300 train
+mpruptnwpo 1 301 val
+mprzzwuowr 1 300 train
+mpsnhqicrx 1 300 train
+mpssbdgdml 1 300 val
+mpstyaodrs 0 300 val
+mpsxokcmtf 1 300 val
+mpsytmxizd 1 300 val
+mpszbvxvsj 1 300 train
+mptliaefjp 1 300 train
+mptpjemkjk 1 300 train
+mptpnkfudq 1 300 train
+mpttaqmnor 0 300 val
+mptwftuslr 1 300 train
+mpumrumehj 1 300 train
+mpunearycu 1 298 train
+mpuskzruaj 1 300 train
+mpuugiqewv 1 300 test
+mpuxxcnieg 1 300 train
+mpuzhbnvov 1 300 train
+mpuzypbyne 1 300 train
+mpvafozdci 1 300 val
+mpvbgowpyx 1 300 train
+mpvdxbmfrt 1 300 train
+mpvnvvihzp 0 300 train
+mpvzbdbvxb 1 300 train
+mpwifghvex 1 300 train
+mpwjdvihkq 1 300 train
+mpwlnqtjst 1 300 train
+mpwrzzskjk 1 300 val
+mpwtgbufwm 1 300 train
+mpwuhpmwqz 1 300 train
+mpwwsltwhw 1 300 train
+mpwwtxabqx 1 300 train
+mpwwvnprkw 1 301 val
+mpxdhfameu 1 300 train
+mpxiadhtiu 1 300 val
+mpxqenkeux 1 301 train
+mpxtthmnei 1 300 train
+mpxwgxdtje 0 300 train
+mpychcebct 1 300 train
+mpycpnkoub 1 300 train
+mpygebmzos 1 300 val
+mpykxkfeaj 1 300 train
+mpyqmihomi 1 300 train
+mpyropiroe 1 300 train
+mpyrpicmjq 1 300 train
+mpyugohgsy 0 300 train
+mpyvvoaymv 1 300 train
+mpyxohompx 1 300 train
+mpyxwanaqt 0 300 train
+mpyyohnpeb 1 300 train
+mpzaxkvzjs 0 300 train
+mpzfhtdcqs 1 300 train
+mpzogwbfpd 1 300 train
+mpzrpapqra 1 300 val
+mqacqmfmda 1 298 val
+mqafyqvlnd 0 300 train
+mqaiamdhxp 1 300 val
+mqatynlckd 1 300 train
+mqbayostmj 1 300 train
+mqbimmjhfj 1 240 train
+mqbktovcxh 1 300 val
+mqbystvtfh 0 300 train
+mqcairdmjz 1 300 train
+mqchrmwcss 1 300 val
+mqcikmuonc 1 300 train
+mqcnpxdynh 0 301 train
+mqcphtizsc 1 298 train
+mqcqjynvym 1 298 train
+mqcrtnxawg 1 300 train
+mqcsnkuzqy 1 300 train
+mqcuvxipxe 0 300 train
+mqcxawoyjf 0 300 train
+mqdcsfnuwh 1 300 train
+mqdcuhncqr 1 300 train
+mqdcxuzxqs 1 300 val
+mqdexicgpl 1 300 val
+mqdfitguqe 0 300 train
+mqdhixhkxq 1 300 train
+mqdiuiaqff 0 301 train
+mqdmgcklbi 1 298 train
+mqdoqlzebi 0 300 train
+mqdqonxtin 1 300 train
+mqdtlaeqsu 0 300 val
+mqdweuowpp 1 300 train
+mqeabrxdyp 1 300 train
+mqearwuymg 1 300 val
+mqehadhyxi 1 300 train
+mqeldnokuq 1 300 train
+mqemgyzdib 1 300 val
+mqenloibvd 1 300 train
+mqeqiytluf 0 300 train
+mqetscoobc 1 300 train
+mqeygjppbt 0 300 train
+mqeygktbwe 0 300 train
+mqezenjzxz 1 300 train
+mqezqhnykg 1 300 val
+mqfcfvtawy 1 300 val
+mqfiyiyjcu 1 301 val
+mqfvuzdryz 0 300 train
+mqfyboific 1 300 train
+mqfyudkvvx 0 300 train
+mqghvhewez 0 300 train
+mqgjceiikk 1 300 train
+mqgnpuhulp 1 300 train
+mqgrtndnna 1 300 train
+mqgsdvheak 1 300 train
+mqgssfwold 1 300 train
+mqhaeaakdr 1 300 train
+mqhcbvmqcm 1 297 train
+mqhcosdesd 1 300 val
+mqhjnpncqp 0 300 train
+mqhnklnypc 1 298 train
+mqhxoggrxm 1 300 train
+mqiaqfwhhl 1 300 train
+mqicndrfyk 1 300 train
+mqifnsxndt 1 301 train
+mqihnkodey 1 300 train
+mqiklixwyy 1 300 train
+mqjaxlurlr 1 300 val
+mqjgbzflpu 1 300 train
+mqjsmbpjoy 1 298 val
+mqjvimerbh 1 298 val
+mqkarjsubc 1 300 train
+mqkbgozyay 0 300 train
+mqkdfrqyfw 0 300 val
+mqkdhydvkt 1 301 train
+mqkeehhczy 1 300 val
+mqkemxxpvq 1 300 train
+mqkfhdknre 1 300 train
+mqkkobfofx 1 300 train
+mqknsvbxpa 1 300 train
+mqkonmfepa 0 300 val
+mqkunluxkv 1 300 train
+mqkuwoamqq 1 300 train
+mqkxdbmyey 1 300 train
+mqlewdkeiq 1 298 train
+mqlhtjjfaz 1 300 train
+mqlnafsmph 1 300 train
+mqlnnysqzj 0 300 train
+mqlnujfnqh 1 300 train
+mqlnwfzxmg 1 300 train
+mqltcftzfz 1 300 val
+mqmfuzsrnt 0 300 val
+mqmgqlbzct 1 300 test
+mqmlqiepki 1 300 train
+mqmnmawtju 1 300 val
+mqmntnqhtk 1 300 train
+mqmshnkkwv 0 300 train
+mqnaqyocqm 1 300 train
+mqncsiqjsd 1 300 train
+mqnddeyzlm 1 292 val
+mqnegfevjk 1 300 train
+mqngbqqehn 1 300 train
+mqnkkgnpqr 0 300 val
+mqnofqsoot 1 300 train
+mqnonmqggw 1 300 train
+mqnphfpsoe 1 301 train
+mqoisltzfl 1 300 train
+mqoqbikkcc 1 301 train
+mqovvypcuy 0 300 train
+mqowpygrgy 1 301 train
+mqoytqjmon 1 300 val
+mqpgmwvezm 1 300 train
+mqpjkvafso 1 300 train
+mqpnqdqdps 1 300 train
+mqppdrgzlq 1 300 train
+mqprzlarem 1 300 train
+mqpxobundk 1 300 val
+mqqbevqxwh 1 300 val
+mqqblleray 1 300 train
+mqqbtjxrem 1 300 val
+mqqdbdqwyy 1 301 train
+mqqdcetuai 1 300 train
+mqqdqdvfsp 1 300 train
+mqqgudhleo 1 300 train
+mqqkfkdfyd 1 300 train
+mqqkycavnm 1 301 val
+mqqtaxunzd 1 300 train
+mqqxoaijdy 1 300 train
+mqrbaxrmwo 1 300 val
+mqrcgigngb 1 300 train
+mqrdoqhhoj 1 300 val
+mqrjqovicg 1 241 train
+mqrmanamru 1 300 train
+mqrnwqhcbm 1 269 train
+mqrtafmlyb 1 300 train
+mqrtnlmqnl 1 300 train
+mqrxfxgrlk 0 300 train
+mqsaktdfnw 1 167 train
+mqsjnmzqtc 1 300 train
+mqsnwyfjyq 1 298 train
+mqsqfkrqki 1 300 train
+mqsuoaynsx 1 300 train
+mqtfxzrrrz 1 300 val
+mqtozuqgtz 1 300 train
+mqtswlzctb 1 300 val
+mqtyrczivx 1 300 train
+mqtzwtljlu 1 300 train
+mqubnlqsma 1 300 train
+mquhhuktlo 1 300 train
+mquiqxtsoy 1 240 train
+mqukycwlwj 1 300 test
+mquogtcryi 1 300 train
+mquozjaiiw 0 300 train
+mqusxziwyk 1 301 train
+mquwvzfqrw 1 300 train
+mquyugnixi 1 300 train
+mqvhbmsjcg 0 300 val
+mqvhifdmgx 1 300 test
+mqvihpwtov 1 300 train
+mqvknowhxc 1 301 train
+mqvmphrlsj 0 300 train
+mqvuvxaamd 1 300 train
+mqwcdmtzsz 1 300 val
+mqwdzpeecs 1 300 train
+mqwptxujhl 1 300 train
+mqwqpmzbfd 1 300 train
+mqwxjqddcv 1 300 train
+mqxehzlfpz 1 300 train
+mqxicvgiay 1 300 train
+mqxnnpvsgc 1 300 val
+mqxobfscyc 1 300 val
+mqxvklfjmy 1 300 train
+mqxwslmiyt 1 301 train
+mqyjlibiqr 0 300 train
+mqykoqcwla 1 301 train
+mqyneecaqg 1 301 val
+mqyqjzccao 1 300 train
+mqyuenkwzp 1 300 train
+mqyzxzqonj 0 300 val
+mqzcoujvfm 1 300 train
+mqzkwzdqfp 1 300 train
+mqzljodtyn 1 300 train
+mqzprxvdmo 1 240 val
+mqzrlecakr 1 300 val
+mqztkdxuyz 1 298 train
+mqzvfufzoq 1 300 train
+mraarmpaor 1 300 train
+mraccgqnpn 1 300 train
+mrafywzcds 1 298 train
+mramfwksyc 1 300 val
+mraplctiok 1 300 train
+mrauhibkcz 1 300 train
+mrawkhgzze 0 300 train
+mrawreqxxc 0 300 train
+mrayekscit 0 300 train
+mrazaobhbw 1 300 val
+mrbcujsrtt 1 298 train
+mrblfwhigo 1 300 train
+mrbsdffnds 1 300 val
+mrbsjtsbnl 1 300 test
+mrbvjsgjcw 0 300 train
+mrbxelgkbw 1 300 val
+mrbxvvhtqh 1 300 train
+mrbzygybxu 1 300 val
+mrcfxvggtd 1 300 val
+mrckwwiagx 1 241 train
+mrctprnqnq 1 299 val
+mrdaucsise 1 300 val
+mrdenipxvc 1 300 train
+mrdorfqqnv 1 300 train
+mrdwsmjyex 1 300 val
+mrdzcykera 1 300 train
+mrenpvmykc 1 300 val
+mreogyjzjo 1 237 train
+mrepayhnrw 1 300 train
+mreqoahxal 1 300 train
+mreqonfbku 1 300 train
+mrerhvgogr 1 300 train
+mrerjxgkgx 1 301 train
+mrerjyjvds 1 300 train
+mrevakjdlt 1 300 train
+mrfcpxebfu 1 300 train
+mrffobxmkd 1 299 test
+mrfhlqpfmo 1 300 train
+mrfrezwobg 1 300 val
+mrfwmdqxqp 1 301 train
+mrfyaengfi 1 300 train
+mrgbytmuzz 1 300 train
+mrgdnqvtmx 1 300 train
+mrghcjcomq 1 300 train
+mrglakllaw 0 300 train
+mrgmchwvfk 0 300 val
+mrgtafagne 1 300 train
+mrhacvsbkp 0 300 train
+mrhajrsgxh 1 300 val
+mrhbozvtlm 1 300 train
+mrhiqrjqaj 0 298 val
+mrhjcqgyse 1 300 val
+mrhmyxbiuf 1 300 train
+mrhohcfluj 0 300 train
+mrhptutmto 1 300 train
+mrhxlfruci 0 300 train
+mrhydcndij 1 300 train
+mrhyjedgkq 1 300 train
+mriownzdhq 1 300 train
+mrizcmibnm 1 300 train
+mrizgeqwsk 1 300 train
+mrizixikhs 1 300 val
+mrjbuxntxx 1 300 train
+mrjdfrhrcc 0 300 train
+mrjfcsxcvj 1 301 train
+mrjglfhndq 1 300 train
+mrjichnrtl 1 300 train
+mrjqqjcxcc 1 299 train
+mrjxiflanz 0 300 train
+mrjzfxasyx 1 300 train
+mrkdpydcma 0 300 train
+mrkfpyngoo 1 300 train
+mrkrigbzgq 0 300 train
+mrkudevjvw 1 298 train
+mrkwspdvna 1 299 test
+mrkwwadnqs 0 299 val
+mrkzdchbtj 0 300 val
+mrkzhuzfek 0 298 train
+mrlijyislg 1 300 train
+mrlnoorcwf 0 300 train
+mrloxorinb 1 300 train
+mrlwazwhol 1 299 train
+mrlzvnwdwq 1 300 train
+mrmaezpwoc 1 136 train
+mrmaimxhjn 0 300 train
+mrmcqldicq 1 300 train
+mrmdipovpb 1 300 train
+mrmexkpvgd 1 300 train
+mrmgtijafq 1 300 train
+mrmmbjshao 1 300 train
+mrmmzasxtf 1 300 train
+mrmpsnapbo 0 300 train
+mrmtyaxupb 1 300 train
+mrmyjjrsxk 0 300 val
+mrnciwaosk 1 300 train
+mrnemsggkq 1 300 train
+mrnezzhhpf 1 300 val
+mrniyuqfxq 1 300 val
+mrnjztmetc 1 300 train
+mrnqweozil 0 301 train
+mrnqzlkenr 0 300 train
+mrntbubgqc 1 300 train
+mrnzkluvbs 1 300 train
+mroaffgtfs 0 300 train
+mrocfplptw 1 300 train
+mrojeohqps 1 300 train
+mronnwwsxu 0 300 train
+mrotkdmavr 0 300 train
+mrotkpylbg 1 300 train
+mrotvssmlo 0 300 train
+mrousdqzsb 1 300 train
+mroviqmznc 1 300 train
+mrovsdlffg 1 300 test
+mrpiqodkqr 1 300 train
+mrpizlozwt 1 300 train
+mrplndkidi 1 300 train
+mrpmyugdln 1 300 train
+mrptdklhnq 1 298 train
+mrputwxira 1 300 train
+mrqdkngrde 0 300 train
+mrqpwvysyy 1 300 val
+mrqsewkfqi 1 300 train
+mrqwmzditf 1 300 train
+mrqzxkrpdv 1 288 train
+mrrmtlpjas 1 300 train
+mrrqbiewzh 0 300 train
+mrruhaqghd 1 300 train
+mrryympfkz 1 300 train
+mrseagjhks 1 300 train
+mrsksioeuz 1 300 train
+mrslwzaftc 1 300 train
+mrsmyeyzmb 1 300 train
+mrsqbsrvif 1 300 train
+mrsqqqwegd 1 300 train
+mrsqrtwgiu 1 300 train
+mrstmoabpe 1 300 train
+mrsufdqtec 1 300 train
+mrsykfpnii 1 300 train
+mrtbzjbvop 0 300 train
+mrterhiguj 1 300 train
+mrtfaykavo 1 300 train
+mrtgilghpn 1 300 val
+mrtnwfshgc 1 300 train
+mrtqthuxbm 1 300 train
+mrtrvdpyhh 1 300 train
+mrtxyivfzi 0 300 val
+mrtyhpjwop 1 300 train
+mrtzwjfpke 1 300 train
+mruejctvzq 1 300 train
+mruhuaaqqm 1 300 train
+mruhwoufgb 1 300 train
+mrusdfkuil 1 300 train
+mruukfmxne 1 300 train
+mruzsjaeez 1 300 train
+mrvdmwcblt 0 300 val
+mrvsozbuot 1 300 train
+mrvtxwjvny 1 300 val
+mrvumgzbzq 0 300 train
+mrvvceanlh 1 300 train
+mrvxihragi 1 300 train
+mrvzyrqlls 0 301 train
+mrwaqtlwjn 1 300 train
+mrweovkpks 1 300 train
+mrwerotrpw 1 299 val
+mrwillpfwg 1 300 train
+mrwmnvnwmb 1 300 train
+mrwninxqyq 1 300 train
+mrwobwiera 1 300 train
+mrxamfkixd 1 300 train
+mrxgqyrfsz 1 300 val
+mrxjfaxmmm 1 301 val
+mrxklusnkm 1 300 val
+mrxpxhyxzh 1 300 train
+mrxuhhgozz 1 301 train
+mrxycatmdj 1 300 val
+mrycmawtce 1 300 test
+mrycxqnavc 1 300 val
+mryevngbqt 1 300 train
+mryhpfudjn 1 298 val
+mryugdmwds 1 300 train
+mryzdcmnrq 1 300 train
+mrzcriijyt 1 300 train
+mrzfqxviiz 1 300 val
+mrzpwxwfot 1 300 val
+mrzqivtnmr 0 300 val
+mrzqsitprj 1 300 train
+mrzqtewocv 1 300 val
+mrzumxsjld 0 300 val
+mrzvbvlruf 1 300 train
+mrzwdwpzgt 1 296 train
+mrzxwbdycf 1 300 val
+msaecegxgv 1 300 test
+msaibijnay 0 300 train
+msajqbourq 1 300 train
+msalmydrng 1 300 train
+msaofiaxna 1 296 val
+msaqianmva 1 300 train
+msauawcsbd 0 300 train
+msawthyeun 1 301 val
+msbbpcyurb 1 298 train
+msbnbprtqw 1 300 train
+msbnbuvcby 0 300 train
+msbqgoxxlh 0 300 train
+mscckixmjk 1 300 val
+mscdatdkfr 1 300 train
+mscgjnwftv 1 301 train
+mscukrhcuw 1 241 train
+mscvbpniwl 1 300 train
+mscvxjwosc 1 300 train
+msdeifwhzj 1 300 val
+msdhpfwbil 1 300 train
+msdjclfkuf 1 300 train
+msdnnuxqzn 1 300 train
+msdnruegfh 0 300 train
+msdnwrmttb 1 241 train
+msdoukrdof 1 300 train
+msdsxxdffx 1 300 train
+msdtzpmmae 1 300 train
+msegqgxgbb 0 300 val
+mserijlxsh 1 300 train
+msevlbxolo 1 300 train
+msezywsagh 1 300 train
+msfbznafbi 1 300 train
+msfhpjlxya 1 300 test
+msfikwsoib 1 300 train
+msfkchggsk 1 300 val
+msfmealadz 1 300 train
+msfmmxwzsx 1 300 val
+msfnbgroee 1 301 train
+msfssnmldu 1 300 test
+msfzxrlykv 1 237 train
+msgekmyxtc 1 300 test
+msgfigqtmn 1 300 val
+msgqtgrfaf 1 300 train
+msgtjhyyny 1 300 train
+msgybbtiao 1 300 train
+msgysrnlep 1 300 val
+mshechsves 1 300 train
+mshernruud 1 300 test
+mshfuaygyq 1 300 val
+mshibrgvlv 1 300 train
+mshtebowpn 1 300 test
+mshxwkglsp 1 300 train
+msibgrrblc 1 300 train
+msibqyvapv 1 298 train
+msiewlssbr 1 300 train
+msijsiuepw 1 300 train
+msinudfuvi 1 300 train
+msiqijycqg 0 300 train
+msirimynch 1 300 val
+msjbkakdfw 1 300 val
+msjdwnrshn 1 300 train
+msjiqwbhyp 0 300 train
+msjjkdbznp 1 301 train
+msjlddkxzo 1 300 train
+msjqpugjit 1 300 train
+msjrwsfnom 0 300 train
+msjutkgnho 1 300 val
+mskfpxodmk 0 300 train
+msklqmhfsp 1 300 train
+mskudffplm 1 300 train
+mskudsvpmn 0 299 val
+mskuywhlfh 1 300 test
+mskvxmihus 0 300 val
+mslaejfhoh 1 300 train
+mslgnyuhos 0 300 train
+mslmcbbbwv 1 300 train
+mslnokoegu 1 300 val
+mslojpszbg 1 300 val
+msltbbqqvs 1 300 train
+msluplmxhj 1 300 val
+mslupudciv 1 300 train
+mslushphcx 1 300 train
+mslxbtomli 1 300 train
+mslyxdilrs 1 301 train
+msmbqjylfc 1 299 train
+msmhqcutdf 1 300 train
+msmszboaup 1 300 train
+msmtscbwrh 0 99 train
+msmzaltckc 1 300 train
+msnfesjjnu 1 300 train
+msnhcukzfa 1 300 train
+msnkzcjnry 0 300 train
+msnlkdnept 1 300 train
+msnlugaqow 1 300 train
+msnsqoheqf 1 300 val
+msoakyxyov 1 300 train
+msoedqwowg 1 288 train
+msofoayqgi 1 300 train
+msojyurqax 1 301 val
+msonpiomob 0 300 train
+msonxxwrnc 0 301 train
+msooqufvgr 1 295 train
+msophvmixk 1 300 train
+msoqnkucal 1 300 test
+msordizknp 1 300 val
+msosljiuee 1 300 train
+mspfqguhld 1 300 train
+msphfyuwey 1 300 train
+msphqcwzfm 1 300 train
+mspjbypjon 1 300 train
+mspsqvowvr 1 300 train
+msptrmyvah 1 297 train
+msqaemphef 1 300 train
+msqdpgokcx 0 300 val
+msqgetepdb 1 300 val
+msqhpibjls 1 300 val
+msqkjfjfyt 0 300 val
+msqmpfcjcd 1 300 train
+msqwlfmxca 1 298 val
+msrewkfzwq 1 300 train
+msrexvwvrj 1 300 val
+msrkuohcqx 0 301 train
+msrokvendy 1 300 val
+msrorwllwt 1 298 train
+msrspqaogq 1 300 train
+msrsxiiusp 1 300 train
+msruxqhmcu 1 300 train
+msrwprlcqq 1 300 train
+msrxorkdgn 1 300 train
+msrzmjjhsq 0 300 train
+mssemsdmfs 1 300 train
+msskyrkwcq 0 300 val
+msspartjvl 0 298 train
+mssqywmizl 1 300 val
+msstznyhpb 1 298 val
+msswoqgzsz 1 300 val
+mstcqunlmu 1 300 val
+mstpvlajvh 1 300 train
+mstsikyndk 1 300 val
+mstujejihp 1 300 train
+msuczgewkm 0 300 train
+msudruobog 1 300 train
+msudshinnu 1 301 train
+msuprqytax 1 300 train
+msupzjqlqd 0 300 train
+msvcknalyc 1 300 train
+msvcxwwqbf 1 300 train
+msvignjhmu 1 301 train
+msvjfalfax 0 300 train
+msvreqoixy 1 300 val
+msvurrqguh 1 300 train
+msvwjzxxfe 1 301 train
+msvydnlmxq 1 300 val
+mswakfmvrh 1 300 val
+mswcpciuar 1 300 train
+mswdjfzsih 1 300 train
+msweetvgys 1 300 train
+mswmmgrxbk 1 241 train
+mswpazfxgk 1 300 train
+mswvmjpdiz 1 300 train
+msxararmif 1 301 val
+msxbatajhx 1 300 train
+msxbrrfttv 1 300 train
+msxdcqbjep 1 300 train
+msxgidfbbf 1 300 train
+msxgrrtqrn 1 300 train
+msxhcmzjyi 1 300 val
+msxibuomjg 1 300 val
+msxioxebam 1 301 train
+msxqtzvreq 1 300 val
+msxsewjitg 1 300 train
+msxtsdxryd 0 300 val
+msxxhzlmmb 1 300 val
+msyelewqwb 1 300 val
+msyeslrxir 1 300 train
+msyhcluenb 1 300 train
+msywjakvfe 1 300 val
+msyxwuselj 1 300 train
+mszblrdprw 1 300 test
+mszckicxcm 1 300 val
+mszecwvnnb 1 288 train
+mszeqrmrvl 1 300 train
+msziwpojuw 1 300 train
+mtaahjaomk 1 300 train
+mtabzafcgv 1 301 train
+mtaezkotwl 0 300 train
+mtagmvjhkq 1 300 train
+mtagwiaprz 0 300 train
+mtahbpogdp 0 300 train
+mtahzeawib 1 300 val
+mtalfisspv 1 300 train
+mtamchlnoh 1 300 train
+mtaoreymwj 1 300 train
+mtappwaimm 1 299 train
+mtavycdtie 1 300 train
+mtbbqqbiwu 1 300 train
+mtbhlnjopc 1 300 train
+mtbkavihsc 1 301 train
+mtbpvsxkqe 1 300 train
+mtbvgkmslq 1 300 train
+mtbxqnwnnn 1 300 train
+mtbyqrpboq 1 300 train
+mtbyuhclxm 1 300 train
+mtcchczxwd 1 300 train
+mtcknoaegd 1 300 train
+mtcnfarewb 1 300 train
+mtcqbvwmpt 1 300 train
+mtcqkdyrba 1 300 train
+mtcxxjjzvt 0 300 val
+mtdawjxbgw 0 300 train
+mtdjgkijxc 0 300 val
+mtdlsfalcu 0 302 train
+mtdnetpayr 0 300 train
+mtdylbjsxb 1 300 val
+mteamhhkyy 1 300 val
+mtecfllphy 0 301 train
+mtecspfpao 1 300 train
+mtecsrxwyv 1 300 train
+mtehfsxsee 1 299 val
+mteijttcyj 1 300 train
+mteuihdheq 0 300 train
+mtevvitucu 1 300 train
+mtfhqqlkgs 1 300 test
+mtfqqvypqi 1 300 train
+mtfrwvgfod 1 298 train
+mtftwnrzpl 1 300 val
+mtfynyymlw 1 300 train
+mtgduejvjd 0 288 train
+mtgelpeflh 1 300 val
+mtghshmpkq 0 300 train
+mtgipmzfld 1 300 val
+mtgrhuwucu 1 301 val
+mtgsmmqjen 1 300 val
+mtgtkxqjzv 0 300 train
+mtgurjzaxl 1 300 train
+mthdnuwugz 1 300 train
+mthkmtbuab 0 300 train
+mthkpnpkgp 1 300 train
+mthubyxsku 1 300 train
+mtiebggcla 1 300 val
+mtighbgbcy 1 300 train
+mtiloinkfq 1 300 train
+mtilpvablx 1 300 train
+mtinvzqrfu 0 300 val
+mtiqyulcjn 1 300 val
+mtirphezqa 1 298 train
+mtirqkystg 1 300 train
+mtiwgcnmtq 1 300 train
+mtjdvkgnif 1 300 train
+mtjfaffnqi 1 300 val
+mtjitcgpfy 0 300 train
+mtjmueszgl 1 300 val
+mtjumzomci 1 300 train
+mtkbvalqky 1 298 train
+mtkedzwcvo 1 300 train
+mtkegmoyir 0 300 train
+mtkmdkxdmg 1 300 val
+mtkrgnhcxq 1 241 train
+mtksqcdffx 1 300 train
+mtkwgbxdgx 1 300 train
+mtlmydhbyo 1 300 train
+mtlnrrybqj 1 300 val
+mtlrjqtdke 1 300 val
+mtlwiislme 1 300 train
+mtmfekdsic 1 300 train
+mtmhxsreix 1 300 train
+mtmhyeavat 0 300 train
+mtmkodzkcs 1 300 train
+mtmrzbrfsh 1 300 train
+mtmutriwai 1 300 train
+mtnahwfzjr 0 300 val
+mtnipssbic 1 300 train
+mtnjnxobkt 0 301 train
+mtnpsaanpb 1 300 train
+mtnqvtmunt 1 300 train
+mtnzllsqcw 1 299 test
+mtodcmwwhp 1 300 train
+mtokttufpy 1 300 train
+mtolbugekd 1 300 train
+mtomaszyjr 1 300 train
+mtomexzpvg 1 300 val
+mtoncuryys 1 300 val
+mtonivxibl 1 300 train
+mtopuhuqsu 1 300 train
+mtoufpmlba 1 298 val
+mtowgsfoti 1 300 train
+mtowsykuhq 1 300 train
+mtpfuvxlxw 1 300 train
+mtpjebuqhs 1 300 train
+mtptybfjba 1 300 train
+mtpvrsdblr 0 300 train
+mtpvwgyxvd 1 301 train
+mtqemsusbc 1 300 train
+mtqfequqng 1 300 train
+mtqppyofws 1 301 val
+mtquhqaxcb 1 300 train
+mtqvtbxwej 1 300 train
+mtqwluufwm 1 301 train
+mtqwmnjqgo 1 300 val
+mtqxfiltpk 1 300 val
+mtrjwtnmru 1 300 train
+mtrnxqfpcf 1 300 train
+mtrsqrmsqs 1 300 train
+mtrszjrxpc 1 298 train
+mtrwraidkc 0 300 train
+mtryaoxtul 1 301 train
+mtryxydvdh 1 300 train
+mtsiclmwqy 0 301 train
+mtsolejuay 1 300 train
+mttjelpgma 0 300 train
+mttrakryht 1 300 val
+mttrlbvjjz 1 300 train
+mttsurxjue 1 240 train
+mttxgmffjz 0 300 train
+mtuiubgotu 1 300 train
+mtupaleexd 1 300 train
+mtupotnavx 0 300 train
+mtuvqbdkav 1 297 train
+mtuvvmdyrt 1 300 train
+mtvasvksnb 1 292 val
+mtvbwvysut 1 300 train
+mtvffctboh 1 300 train
+mtvkldkzrg 1 300 train
+mtvsezptkn 1 300 train
+mtvwmdmenk 0 300 train
+mtvwmzxqrh 1 300 train
+mtwgyxoyhn 1 300 train
+mtwhvexksv 1 300 train
+mtwqaqazwg 1 301 train
+mtwshatyif 1 300 train
+mtwtqsypeo 0 300 val
+mtwwampvvq 0 298 train
+mtwwhqlmvl 1 300 train
+mtxbbpghjk 1 300 train
+mtxcthgqsc 1 300 train
+mtxpzoutyw 1 300 train
+mtxreyjgqk 1 300 train
+mtyfsdjiyp 1 300 train
+mtyspxmnci 1 299 val
+mtytgvwonx 1 300 train
+mtzcowdgia 1 300 train
+mtzletcgnp 1 300 train
+mtznckbeqx 1 300 train
+mtzpntagtb 1 300 train
+mtztyxxwwa 0 300 train
+mtztzksquz 1 300 train
+mtzvnmxgqj 1 300 test
+mtzyxoxutv 1 300 val
+muaahwnyco 1 301 train
+muaasxszvk 1 300 train
+muaejwrrbr 1 300 train
+mubcfquvbh 1 300 train
+mubgelyfjr 1 299 test
+mubgtqhytp 1 300 val
+mubqivmfzp 1 300 test
+mubqqhzlhg 1 300 train
+mubvsrlgvl 1 302 train
+mubvznduog 1 300 train
+mubxlmxjse 1 300 train
+mubyegzfdm 1 300 train
+mucalgsphi 1 300 train
+muceumxabj 1 300 train
+mucgcfwaye 1 300 train
+mucowamxhg 1 300 train
+mucqmposdd 1 300 train
+muddiscimv 1 302 train
+mudfhdppfp 1 300 train
+mudiofzppp 1 300 val
+mudjcfiakq 0 300 train
+mudjvgjsws 1 300 val
+mudvgjscpw 0 300 val
+mudwtywsuo 1 300 train
+mudzyxxxzq 1 300 train
+mueekicuyv 0 300 train
+muehxzehgs 1 300 train
+muenoaowlr 1 299 val
+muespoijkh 1 301 val
+muetyerlvf 1 300 train
+mufbcvrgen 1 300 train
+mufdhtsqhi 0 300 train
+mufdqvarwa 0 300 train
+muffgclzqp 1 300 train
+mufhpxvugf 1 301 val
+mufmqwfukc 1 300 train
+mufozlwijf 1 300 train
+mufpsfcwnd 1 299 test
+mufpuntnvc 1 300 val
+mufsxklwqh 1 300 train
+mufxppnnrg 1 298 train
+mufzpbhkeb 0 300 train
+mugckenamu 1 300 train
+mugjoqxxqf 0 300 train
+mugmmfovtw 0 300 train
+mugpedpwbl 0 300 val
+mugxsllhlk 1 301 val
+muhbluorkm 1 300 val
+muhcavczvk 1 300 train
+muhedpozpg 1 300 val
+muhfarktvd 1 300 train
+muhgbpklnc 0 300 train
+muhgixhdmd 1 300 val
+muhiosuytx 1 300 train
+muhnoxbtjm 1 300 train
+muhvenpsap 1 300 train
+muiecwckxp 1 300 train
+muigaklbyb 1 300 train
+muihshunds 0 301 train
+muineajmbz 1 300 train
+muisqjusye 1 300 val
+muitjjkmjr 1 241 train
+mujbyfgopc 1 300 train
+mujdjxunet 1 300 val
+mujjzbuggx 1 300 train
+mujkihoqji 1 298 train
+mujmyarcbg 1 300 train
+mujnrnntqq 1 300 train
+mujssgwqhs 1 300 val
+mujubwlspn 0 301 train
+mujulobfte 0 300 train
+mujvaawfap 1 300 train
+mukbljjdph 1 300 train
+mukgthioxj 1 298 val
+mukqjbortp 1 300 train
+muksyyltmg 1 300 test
+mukyckrtih 1 300 train
+mulbnsfwui 1 300 val
+mulebpmvzo 0 300 train
+mulkkedouv 1 301 train
+mulpjifchw 1 300 train
+mulzcbwjni 0 300 train
+mumdexeaen 1 300 train
+mumiutdpdk 0 300 train
+mumpseobdk 0 300 train
+mumsfylhnz 1 300 val
+mumujmxvso 1 300 val
+mumyovxjdz 1 300 train
+munawgoswt 1 99 train
+munhurgdot 0 300 train
+munkjkkrfl 1 300 train
+munqszknaw 1 300 train
+muntsvmpps 1 300 train
+muogigmdpk 1 300 val
+muohrognps 1 298 train
+muohzusixr 1 301 train
+muoiysiuwl 1 300 train
+muolqfwicr 0 300 train
+muonplikax 1 300 val
+muoyujregk 0 300 val
+muozoripwz 1 300 train
+mupgxnuzam 1 300 train
+mupxsoodhf 1 300 train
+muqgpmtofx 1 300 train
+muqllsuzyp 1 300 train
+muqnnfyjak 1 300 train
+muqopkbkfu 1 300 train
+muqppncgrf 1 298 val
+muqszlkghj 1 299 val
+murgkzdncb 1 300 train
+murkpgajof 1 300 train
+murnucmpqu 1 299 test
+murowxrezg 1 301 train
+murpsmxdii 1 300 val
+murqahmgyj 0 300 train
+murqgmxknx 1 300 train
+murtvsctfj 1 300 train
+murujielfp 1 300 train
+murwigvceo 0 300 train
+musfgemnqi 1 301 train
+musizvxxev 1 241 train
+mussdizapp 1 300 train
+musshonidg 0 300 train
+musujcrury 1 300 train
+musvjwtibp 1 301 train
+musynmzeuu 1 302 train
+musytuwwhy 1 300 train
+mutcnezgfz 1 300 train
+mutfpfruab 1 300 train
+mutkbxjhie 1 300 val
+mutlsuuhqh 1 300 train
+mutmhajwwo 0 300 train
+mutoprdgcj 0 300 train
+mutowesqfp 1 300 train
+mutpheqenn 1 294 train
+mutsnzjwqj 1 241 train
+mutszuoyey 1 300 train
+mutuhmwjdv 1 299 train
+mutuvpzhuu 0 300 train
+muualantym 1 298 train
+muuaqzqwtz 1 300 train
+muuchygtud 1 301 train
+muuuxszgfl 1 300 train
+muuwtyrtxs 1 300 train
+muuzizblos 1 297 train
+muvkxsaszk 1 300 train
+muvoviysrd 1 300 train
+muvtkwxiuf 0 300 val
+muvzufkrsp 1 299 train
+muwenfzbcq 0 300 val
+muwfbiuddn 0 300 train
+muwmwpyqfs 1 300 train
+muwnjcabgg 1 300 train
+muwnreemii 1 300 train
+muwoxanfpt 1 300 val
+muwpkcoklh 1 300 train
+muwrjazmkq 1 300 train
+muwrzivuoj 1 300 train
+muwtxxoghp 1 300 val
+muwwmmhpzf 0 300 train
+muwygnuptm 1 300 train
+muxayhwwfm 1 300 train
+muxdhgpmwa 1 300 train
+muxejwktkc 0 300 train
+muxjcwqjuk 1 301 val
+muxjpsgxyj 0 240 val
+muxmsvlejq 1 300 train
+muxnkkuwti 1 300 train
+muxnyzidvh 1 300 train
+muxrsrdhgg 1 300 val
+muxskocfsp 1 300 train
+muxtdxavxp 1 300 train
+muxttodhic 1 300 train
+muybljrqel 1 300 train
+muyfipzxto 1 300 train
+muyuducdwg 1 300 train
+muyvajjpge 1 300 train
+muzcmfrzqa 1 299 val
+muzgmepgcp 1 300 val
+muzmpuwglz 0 300 train
+muzoszxxkd 1 300 train
+muzpvrmtvf 1 300 train
+muzyxgwkml 0 300 train
+mvaedbokqr 0 300 train
+mvaiqiqndp 1 300 train
+mvarahecum 1 300 train
+mvathrqhbe 1 301 train
+mvavxzgiul 1 300 train
+mvayuvunnd 1 300 train
+mvbajucnap 1 300 train
+mvbczareau 1 300 train
+mvbjwqicqc 1 300 train
+mvbmdtjvba 1 300 train
+mvbnvuwuvr 1 300 train
+mvbtedffej 1 300 train
+mvbucspkbf 1 300 train
+mvbxuwqyjt 1 300 val
+mvcnjkuccx 1 300 train
+mvcnvdmxcj 1 300 val
+mvcochjior 1 300 test
+mvconsggts 1 300 train
+mvcteiyrge 1 300 train
+mvcusklvqb 1 241 train
+mvdbumhxin 0 300 train
+mvdchkdnaa 1 300 train
+mvdctklrth 1 300 train
+mvdfhvlxlr 1 298 train
+mvdfppfonx 1 300 train
+mvdgziiruf 1 300 train
+mvdpgepgen 1 300 train
+mvdqlootwv 1 300 train
+mvdsqrszzb 1 300 train
+mvdwsurwhe 1 301 train
+mvdxfumtyi 0 300 train
+mvdyqzynwn 1 300 train
+mvebakttnc 1 300 train
+mvecnjvxls 1 300 train
+mvekilmvkl 0 298 train
+mveoqfdzcs 1 300 train
+mvepfabhif 1 300 train
+mvepjqywiw 1 300 train
+mveqfuojat 1 300 train
+mvereewiyq 1 241 train
+mvfeurfoyq 1 300 val
+mvffpaklnn 0 300 train
+mvffsicuai 1 300 train
+mvfghayhnr 1 301 train
+mvfgwhwerv 1 300 train
+mvfiaqknzs 1 300 train
+mvfjeykklz 1 298 train
+mvfnmxzbon 1 300 train
+mvfnwtwktp 1 300 train
+mvfrifsgrb 1 300 train
+mvfvefsgik 1 300 train
+mvfyexeghq 1 299 val
+mvfzkpdzen 1 300 train
+mvgbgnbboo 1 300 val
+mvggahjxsx 1 300 train
+mvgkbvcvlg 1 300 train
+mvgkfyqugf 1 241 train
+mvgsoqirtn 0 300 train
+mvhbegdndh 0 300 val
+mvhezsldom 1 300 train
+mvhlfhlnys 1 300 train
+mvhqiepvdi 1 300 train
+mvhrhcbgwk 1 300 train
+mvhslqtiyd 1 300 train
+mvhuootfad 1 300 train
+mvhyzazoot 1 300 train
+mvigprgrsg 1 300 train
+mvinjwbjye 1 298 train
+mvirzurtvk 1 300 train
+mvistwvqia 0 301 train
+mviwmmyody 1 300 train
+mvjcdbvymi 1 300 train
+mvjgprwafm 1 241 train
+mvjovkcfql 1 300 train
+mvjyivbmwr 1 301 val
+mvkdlefvtw 0 300 train
+mvkeqpfwey 1 300 train
+mvkhbeiskl 1 299 val
+mvkndnbjns 0 300 train
+mvknwklwma 1 300 train
+mvkuqdhtqj 1 300 train
+mvkwidbbdw 1 300 train
+mvlaaoplxi 1 300 train
+mvlatpnpfz 1 300 train
+mvlbdahfum 1 300 train
+mvlcormynt 0 300 val
+mvlgtkndns 1 300 train
+mvlljogbpa 1 300 train
+mvlyixqgtl 1 300 train
+mvmbdizipz 0 300 train
+mvmhzxzham 1 300 train
+mvmkcpekmd 1 300 val
+mvmrhosjlc 1 300 train
+mvmsknuvge 1 241 train
+mvmxrrfxui 1 300 train
+mvmxyomsne 1 298 train
+mvmzcpoerq 1 300 train
+mvnahpueuk 1 300 test
+mvnansxzwu 1 300 train
+mvnckjyuqs 0 300 val
+mvneuvwisv 0 300 train
+mvngturoad 1 300 train
+mvnhspdeyx 1 300 train
+mvnldrnlzk 1 300 train
+mvnmdxgsfm 0 300 train
+mvnpljulpe 0 300 train
+mvnxteclvt 1 300 train
+mvofqyugsp 1 300 train
+mvonbopivb 1 300 train
+mvoontjhmj 0 300 train
+mvooosflqp 1 300 train
+mvoqztckkl 1 300 train
+mvoxtmsadh 1 300 train
+mvpcgvxloo 1 300 train
+mvphfcjhzu 1 300 val
+mvpjvgexli 1 300 train
+mvplwzoirr 0 300 val
+mvpvveirjm 1 300 train
+mvpwpfxvli 1 300 train
+mvpwumlwfc 1 300 val
+mvpzvlpcly 1 298 train
+mvqbhtivtb 1 300 train
+mvqelazvsk 1 300 val
+mvqkyeyrct 1 300 val
+mvqooxjncc 1 300 train
+mvreczmgks 0 300 train
+mvrfxvxwga 0 300 train
+mvriefoacl 0 300 train
+mvronzzqar 1 300 train
+mvrtyfmeit 1 300 train
+mvrzuonkfy 1 269 train
+mvsasyujaa 1 300 train
+mvscywwpex 1 300 train
+mvsfidzcno 1 241 train
+mvsrhbeylb 0 300 train
+mvssdaprux 1 300 train
+mvsvwgdyqz 1 300 val
+mvswfbqmss 1 300 train
+mvtbgbqkyj 1 300 train
+mvtjwjfdta 0 300 train
+mvtkwavkoy 1 300 train
+mvtmurxona 1 300 train
+mvtnzxsjqp 1 300 train
+mvtptwalrv 1 298 train
+mvtqjdryyf 1 300 train
+mvtqxxtcfn 1 300 train
+mvtucrowxm 1 300 train
+mvubyetxwd 1 300 train
+mvudoqgmzx 1 300 train
+mvuhentlcg 0 300 train
+mvuhtwzcjr 1 298 train
+mvuiapsmya 1 297 train
+mvuidgordx 1 300 val
+mvuqomvwsq 1 300 train
+mvuqzhdncl 1 300 train
+mvuxczjfkt 1 299 test
+mvuyaxaefk 1 300 train
+mvvbcjmyqg 1 300 train
+mvvdfadkem 1 301 train
+mvvfowghab 1 300 train
+mvvhprmrkq 0 300 train
+mvvjepiwug 1 299 val
+mvvkfbvajj 0 300 train
+mvvkowjmdz 0 300 train
+mvvrdfleux 1 300 test
+mvvsrmeezw 0 300 train
+mvwnlfdbjl 1 300 train
+mvwqxvoxmj 1 300 train
+mvwsfefuwh 1 300 val
+mvwulmuucs 1 300 train
+mvwwrcqibu 1 241 train
+mvxkoydxux 1 300 val
+mvxvwetdwr 0 301 train
+mvxwmkdvsf 1 300 train
+mvxxevjibr 1 300 train
+mvxyurhwpm 1 301 val
+mvygfdpohx 1 300 val
+mvykbvqwfh 1 167 train
+mvyruzyska 0 300 train
+mvywocnpfk 1 300 train
+mvywqqtyff 1 300 train
+mvyzzouzvq 1 300 train
+mvzakhzrrn 1 300 train
+mvzaulbdmb 0 300 val
+mvzbyfqaav 0 301 train
+mvzjldqsat 1 300 train
+mvzkabdclc 0 300 train
+mvzmdrdqpd 1 300 train
+mvzmyafcbc 1 300 train
+mvzqixcapj 1 300 train
+mvzrgjnxvv 1 300 train
+mvzwkrlmza 1 300 val
+mwapcvbqco 1 300 train
+mwasdyytkx 1 300 val
+mwazutvezv 1 300 train
+mwbhwrjoiq 1 296 val
+mwbjozxran 1 300 train
+mwbnwqjzor 0 300 val
+mwbucknxeu 1 300 train
+mwbvkkqsob 0 297 train
+mwbzfedlfm 1 300 train
+mwcllqiump 1 300 train
+mwcutgoatt 1 300 train
+mwdaeeovif 1 301 train
+mwdbajzshb 1 300 train
+mwdpmfxebg 1 300 train
+mwdvjquzeo 1 300 train
+mwdytsnmpx 1 300 train
+mweacxabjh 1 300 train
+mwejnhmqkj 1 300 train
+mweksbsjeg 1 300 train
+mwesddtthb 1 300 train
+mwetmmkjnu 1 300 train
+mweuuccmxt 1 300 train
+mwevxhvnac 1 300 train
+mweyejimuy 0 300 val
+mwezcucqzv 1 300 train
+mwfatmdvci 0 300 train
+mwfdtbducd 1 300 train
+mwferisoiu 1 249 train
+mwfggjgvly 1 300 train
+mwfjksimpu 0 300 train
+mwfljyfowi 0 300 train
+mwfsimggkl 1 300 val
+mwfyzcznjm 0 300 train
+mwghzsaysw 1 301 train
+mwgnxuptqu 1 298 val
+mwgreobzaf 1 300 train
+mwhhjftdhf 1 300 train
+mwhkrqbdwz 0 300 train
+mwhnpujxrx 1 300 train
+mwhnylxjun 1 300 train
+mwhrzpysky 1 300 train
+mwhsytjubk 1 298 train
+mwifzhcxkx 1 300 train
+mwilojzhlq 1 300 val
+mwimvyakjq 0 300 val
+mwinhzcwju 1 300 val
+mwiogtcryd 1 297 train
+mwizcjywkd 1 300 train
+mwjbchqkpg 1 300 val
+mwjbvrbmti 1 300 train
+mwjecnmcen 1 298 val
+mwjnvghsbe 0 300 train
+mwjnvqeyqp 1 300 val
+mwjtzkbhvm 1 299 val
+mwjvcjeagj 1 300 train
+mwjvuzvjfk 1 300 train
+mwjytdtdgi 1 299 train
+mwkeajyhal 1 300 train
+mwkhupdprz 1 300 train
+mwkhzfllsh 1 300 val
+mwkjkmoqtn 1 300 train
+mwkknldjkb 1 300 train
+mwkmpyvhlp 1 300 train
+mwkpweoord 1 300 val
+mwlbprxmwi 1 301 val
+mwlixxpinj 1 300 val
+mwlkndwulr 1 300 train
+mwllpimsds 1 300 train
+mwlmuwsrbi 1 298 train
+mwlnaiefuf 1 301 train
+mwlqoyrjaq 1 300 val
+mwlthmfjmc 1 300 train
+mwluvmcmws 0 300 train
+mwlwlieswy 0 301 train
+mwmaekdlev 1 300 train
+mwmcabdsjt 0 301 train
+mwmdfctdsb 0 300 train
+mwmetnjqvs 1 300 train
+mwmkazaoqf 1 298 val
+mwmkjfzjcw 1 300 train
+mwmlzexega 1 300 train
+mwmosbyzfq 1 300 train
+mwmrorbyfo 1 300 train
+mwnblpyrfh 0 300 val
+mwnfrkjzul 1 300 train
+mwnibuujwz 0 300 test
+mwoafiolcx 1 300 train
+mwobxgqgru 1 300 train
+mwocdprfiu 0 300 train
+mwocqlzyqs 1 300 train
+mwoeriylvo 0 300 train
+mwoglcoypf 1 300 train
+mwohauqovp 1 299 val
+mwoleudtoq 0 300 train
+mwopilvgux 1 300 train
+mwowglxcyx 1 301 train
+mwowkpkzdp 0 300 train
+mwowtprdzz 1 300 train
+mwpbzzadir 1 300 train
+mwpkteojuk 1 300 train
+mwplarojji 1 300 train
+mwprlctrzh 1 300 val
+mwpzprkegu 1 300 train
+mwqbzonpaz 1 300 train
+mwqflgsuwc 1 300 train
+mwqgbdbsdg 1 300 train
+mwqjzxrjkj 1 300 train
+mwqongwqrt 1 300 train
+mwqpsyyiqe 1 300 train
+mwqruspmsb 1 297 train
+mwqwnxdijw 1 300 val
+mwrblsiixn 1 300 test
+mwrcxfgezs 1 301 val
+mwrezgpbsm 1 99 train
+mwrhjbfoyx 1 300 train
+mwrrhuyjbm 1 300 train
+mwrruurbxv 0 300 val
+mwrtbalqcd 1 300 train
+mwrtsxzshf 1 300 train
+mwrvjfceye 1 300 train
+mwrwiicybk 1 300 train
+mwrzhqncfc 1 300 val
+mwsolqifsf 1 300 train
+mwsozgddjw 1 300 train
+mwsrdozmsx 1 300 train
+mwsxxgjeop 1 300 train
+mwtamzmmjs 0 300 val
+mwtctlizcx 1 298 train
+mwtcwknkuv 1 300 train
+mwtwynwudg 1 300 train
+mwtxlrfkxh 1 300 train
+mwubcjgmzp 1 300 val
+mwueotrptb 1 297 train
+mwueqcntpa 1 302 val
+mwumamlvyn 1 300 train
+mwuonuhdjr 1 300 train
+mwustljhji 1 300 train
+mwuywloapn 0 300 train
+mwvgzctktm 1 300 train
+mwvhyjhnel 1 301 val
+mwvrjvumnu 1 299 train
+mwvytbcjeg 1 300 test
+mwwanomecb 1 300 train
+mwwgnidhaw 1 300 train
+mwwloqsskl 1 301 train
+mwwngpungf 1 300 val
+mwwploizlj 0 299 test
+mwwselsikq 1 300 train
+mwwvigqovm 1 300 train
+mwwyzvkdln 1 300 train
+mwxaqiiqzo 1 300 val
+mwxclqsohq 1 298 train
+mwxecbuidu 0 300 train
+mwxhvzhwiy 1 240 train
+mwxjavxhiu 1 300 train
+mwxnateceo 1 300 train
+mwxqbfogwi 1 300 val
+mwycrqgdfp 1 300 train
+mwyczmwyyg 0 300 train
+mwyolxsvmz 1 301 val
+mwyxwhoarn 0 300 train
+mwzaybyxtv 1 301 train
+mwzbfhpgnt 1 300 val
+mwzcpjptem 1 300 train
+mwzdmuwefm 1 300 val
+mwzemjwyfu 1 300 train
+mwziqqpqfu 1 300 train
+mwzknqqvim 1 300 train
+mwzslplwzr 1 300 train
+mwzzkkaswn 1 300 train
+mxaganqcxr 1 300 train
+mxahdrptoq 1 300 train
+mxahsihabr 1 300 test
+mxanqnhqgy 1 301 train
+mxautbfbyk 1 300 train
+mxavjgxvcc 1 300 train
+mxbdgikmyj 1 300 val
+mxbgogvssp 0 301 train
+mxbmwzhprr 1 241 train
+mxbpwtjoio 1 300 val
+mxbrhtjxsu 1 300 train
+mxbsrzreof 1 300 val
+mxbvkvgrjc 1 300 train
+mxbwbdoerd 1 300 val
+mxbwezrsvs 1 300 train
+mxcgwoxjmx 1 300 train
+mxcifjtnhl 0 300 train
+mxckmtkvsq 0 300 train
+mxcljeqhqa 1 300 train
+mxcmrvvpqm 1 300 val
+mxcogkgmkl 1 300 train
+mxcswuzdad 1 300 train
+mxcwkwdnqz 0 301 train
+mxcxxyesby 1 301 train
+mxczokbutl 1 300 train
+mxdalvgyaa 1 300 train
+mxdglglbbl 1 300 train
+mxdjnmhfhi 1 300 val
+mxdlbasaax 1 300 train
+mxdnqrhdxj 1 300 val
+mxdrynixzp 1 300 val
+mxdynpbzhr 1 300 train
+mxdzimnxcc 1 299 test
+mxebgmvjdg 1 300 train
+mxedmyiofh 1 300 train
+mxefcnixrk 1 300 val
+mxelnshmqu 1 300 train
+mxepcxgzxz 1 300 train
+mxezzuvrve 0 301 train
+mxfblxtind 1 300 val
+mxfdyfrtla 1 292 val
+mxfewopdlf 1 300 train
+mxfppuzljp 1 300 val
+mxfpxlivec 0 301 train
+mxfqceeois 1 300 train
+mxfslxgyco 1 300 train
+mxfvcqjgfw 1 298 train
+mxgdaffjmt 1 296 train
+mxgeiysgoc 1 300 train
+mxgoirainp 0 300 train
+mxgoyqwnwx 0 300 train
+mxgscubddd 1 300 train
+mxgtlcplms 1 300 val
+mxgxywswzw 1 300 train
+mxhbbvwvfl 1 300 train
+mxhgangalw 1 300 val
+mxhyievkmx 1 300 train
+mxhzidoquq 1 300 train
+mxibogtmey 1 300 test
+mxieqwbubj 1 298 train
+mxiklciwoj 1 300 train
+mxincbtffo 1 300 val
+mxiphogwdy 1 301 val
+mxiuxwrjdy 1 300 train
+mxixvfhtnl 1 300 train
+mxjdaearlo 0 300 train
+mxjelenbye 1 300 train
+mxjfuswavn 0 300 train
+mxjodtlgjw 1 300 val
+mxjsgejaep 1 300 train
+mxjsimsntb 1 300 train
+mxjsmozsyu 0 301 val
+mxkcmlofoh 0 301 val
+mxkevgxgyz 1 300 val
+mxkfkuzosk 0 300 train
+mxkrvzlcac 1 300 train
+mxkviefswl 1 300 train
+mxkwkkhbmw 1 300 train
+mxkztjyibx 1 300 val
+mxlfwpyvtj 1 300 train
+mxlhodjzni 1 300 val
+mxlipjhmqk 0 300 test
+mxlqkaklcl 1 300 val
+mxmjsdcaau 1 300 train
+mxmmpiogik 1 300 train
+mxmqcgmxrz 1 300 train
+mxmqhchbac 0 300 val
+mxmrbzboon 1 298 train
+mxmvvoqgkz 1 300 train
+mxmwjptprn 1 300 val
+mxmxqqcpqq 0 300 train
+mxmywttnpl 0 300 val
+mxmztctrws 0 300 train
+mxnbqfecsc 1 300 val
+mxnfsesbjj 0 300 train
+mxngpymwgv 1 297 val
+mxnkdfvzvf 1 300 val
+mxnnapyfiu 1 300 test
+mxnpusyppq 1 300 train
+mxnquwuszt 1 300 train
+mxnrazfoao 1 300 train
+mxnswycbdh 1 300 val
+mxntgvqvzg 0 300 val
+mxntszejmw 1 300 train
+mxnvzecblj 1 300 train
+mxnyibtgve 1 300 val
+mxoqitjkii 1 300 val
+mxoqupakny 1 300 train
+mxovjjsnfq 1 300 train
+mxoxjpnldw 1 300 train
+mxphcctvuu 1 300 val
+mxpqyayjka 1 300 train
+mxpznwoqvu 0 297 train
+mxqdgkueut 1 300 train
+mxqeljikfy 1 300 train
+mxqfbzwiwt 1 300 train
+mxqodqynnn 1 300 train
+mxqvemhkod 1 300 train
+mxqyyqqhgn 1 241 train
+mxqzatqeym 1 300 train
+mxrcygkfug 1 300 train
+mxrgytmokq 1 300 train
+mxrniclsaw 1 300 train
+mxrnlrylrq 0 300 train
+mxrpnkuhmd 1 241 train
+mxrtvqwlyd 1 300 train
+mxrzdzcgru 1 300 train
+mxsavywnji 1 298 train
+mxsdxajbkn 1 300 train
+mxskqwskrq 1 300 train
+mxsmrmjcsv 0 300 train
+mxspjiwado 1 296 train
+mxsppbuimb 1 300 train
+mxstnbsyll 0 300 train
+mxtlzqmlif 1 300 train
+mxtnyysfuj 1 299 test
+mxtqsghchy 1 300 train
+mxttogsufv 1 300 train
+mxtwvuqgsc 1 300 train
+mxtxvzyemi 1 300 train
+mxtyafuuly 1 300 train
+mxuehwnvrx 1 300 train
+mxuiqjzleu 1 300 train
+mxunzxxtza 1 300 val
+mxupurrbfp 1 300 train
+mxuqornpnp 1 300 train
+mxusoexayz 1 300 train
+mxuvdcuvjc 1 300 train
+mxuviiuuks 0 300 train
+mxuwtkorlm 1 300 test
+mxvbjgcrsq 1 300 train
+mxvjutzfhf 1 300 train
+mxvlajomuy 1 300 test
+mxvpjakqvl 0 300 train
+mxvuiwicds 1 300 val
+mxwbzvmgzg 1 302 train
+mxwcsvstzj 1 299 train
+mxwgqjafcv 1 300 train
+mxwgxsnfhc 1 300 train
+mxwqmxncer 1 300 test
+mxxfckevyo 1 300 train
+mxxocedoll 1 300 train
+mxxuhornea 1 300 train
+mxxwxzeqib 0 300 train
+mxybhnmmqp 0 300 train
+mxybyhghxc 1 300 train
+mxyjycdvkk 1 300 train
+mxypluhkya 1 300 train
+mxyskmamws 1 301 val
+mxysmbnojj 1 300 train
+mxythdwshv 1 300 train
+mxyxmioler 0 301 train
+mxyzjggzpw 0 300 train
+mxzfcangte 1 298 train
+mxzkpiksvv 1 300 train
+mxzosxshju 1 300 val
+mxzqguvsnt 1 300 train
+mxzrdigsdm 1 300 val
+mxzuznbuki 1 300 train
+mxzvchgfnn 1 300 train
+mxzwudxfvh 1 300 val
+mxzwvhpltk 1 300 train
+mxzywkvxmb 1 241 train
+myaknzjmmc 1 300 val
+myakvnaypl 1 300 val
+myaplrhysw 1 302 val
+myapslokax 1 300 train
+myaukmfnow 1 299 train
+myazaclzdr 1 301 val
+mybehwvwzr 1 300 val
+mybekwsvlj 1 300 train
+mybheqhsnf 1 300 train
+mybonfvyaq 1 300 train
+mybwbtegui 0 300 train
+mycbfskdhh 1 299 test
+mycsljsdmu 0 300 train
+mycwlbcxdm 1 300 train
+mydednjket 1 300 train
+mydlpaleai 1 300 val
+mydomrezbo 1 300 train
+mydwobkfuy 1 300 train
+myeayvxlsn 1 300 train
+myebjqbxsl 0 300 train
+myeeorqmiw 1 300 val
+myeiiuazgb 1 300 train
+myeirmpprg 1 300 train
+myelaqodcy 0 300 train
+myetadgooo 1 300 val
+myeuawgjbr 1 300 train
+myewuiruqd 0 300 train
+myezfikqtl 1 300 train
+myezgvnivo 1 300 train
+myfcyqybae 1 301 train
+myfhumqhsf 0 300 train
+myfpgqqfry 1 300 train
+myfrokfnka 1 300 val
+myfxbrkrsw 0 300 train
+mygbtknviz 1 300 train
+myghjhjvxo 1 300 train
+mygtpgseqd 1 298 train
+mygusxjlyn 0 300 train
+mygvbgyejk 1 300 train
+mygwsxvckl 1 300 val
+myhcboqdfl 1 300 train
+myhecmuutc 1 300 train
+myhipsckog 1 300 train
+myhoutffrl 1 300 train
+myhqeaghtx 1 300 train
+myhvdmgaji 0 300 val
+myhyqbaouf 1 300 val
+myiaptjpme 1 300 val
+myiatfcllq 1 300 train
+myiaznyvpq 0 298 train
+myieeneqqx 1 298 train
+myijzocdsg 0 300 train
+myitknpeec 1 300 test
+myjhgnezbc 0 300 train
+myjjddlfoy 1 300 train
+myjllmyijj 1 299 val
+myjnthzkhv 0 301 train
+myjslpqppw 1 300 val
+myjsvitihd 1 300 val
+myjsyoglmc 1 300 train
+myjvkeibdm 1 300 train
+mykdihynjd 1 300 val
+mykhviweod 1 301 train
+mykjiudasb 1 300 train
+mykjpizilf 1 300 train
+myklxndndp 1 300 train
+mykprqsgeh 1 300 train
+myksdjvpuq 1 301 train
+mylbrogsyi 1 300 train
+myldaqelfu 1 300 train
+myleyyxpjx 1 298 train
+mylsbiceio 1 297 train
+mymcgoolnx 1 300 train
+mymdvihnlj 1 300 train
+mymhdntqyf 1 300 train
+mymhqwifwb 0 269 train
+mymluijctr 1 300 train
+mymovcxtxe 1 300 train
+mymqltrdiu 1 300 train
+mymrgqfjdi 1 300 val
+mymtcayabt 1 300 val
+mymtgvkdan 1 301 train
+mymvjbskxd 1 300 train
+myndksorvf 1 300 train
+mynimmzeav 1 300 train
+mynozykhbg 1 99 train
+mynptneqbe 1 300 train
+mynqiakzcg 1 300 val
+mynsawrfjy 1 301 train
+mynuaelnnc 1 300 train
+mynzbwzilg 1 301 val
+mynzuyrmdy 1 300 test
+myocnhhofe 1 298 train
+myoddpiqdp 1 300 train
+myoecijkpe 1 300 train
+myorncepwu 1 297 train
+myosibuprq 0 300 val
+myotorzjrg 1 300 train
+myotyhygti 1 299 train
+myoydssaii 1 300 test
+mypddzlcao 1 300 train
+mypfevdlkz 1 300 train
+mypgrvhvuc 1 300 train
+mypuhqslxq 0 300 train
+myqacvmljg 1 300 train
+myqotqhdwv 0 298 train
+myqrxrorzs 1 300 val
+myqursfula 1 300 train
+myqvdwvfbe 1 300 train
+myqvmmihrz 1 301 train
+myqymglyxd 1 300 test
+myqzfgcqsd 1 300 val
+myrcbjsdzd 1 298 train
+myrgqwhrvk 1 300 train
+myrhcwgzxr 0 300 train
+myrieacubk 1 300 train
+myrikcpius 1 300 train
+myritpvkzt 1 146 train
+myrkbdmnev 1 300 train
+myrrisyzya 1 600 train
+myrsanapro 1 302 train
+myrzfhyqnu 1 300 train
+myrzkltfqg 1 300 train
+myseqtaakr 1 300 test
+myslupojxl 1 300 train
+myssnicyar 0 300 train
+mysufmfwrt 1 300 train
+myszscymzv 1 300 test
+mytnqzubag 0 300 train
+myttjyjoen 1 300 val
+myttmsgzuv 1 300 train
+mytyrxlwpk 1 300 train
+myuaxepflh 1 300 train
+myuebcgczn 1 301 train
+myuiqyjfiy 0 300 train
+myuiuhcdrw 1 301 train
+myuubtcecq 1 299 train
+myuvyrfhtw 1 300 val
+myuxukczgx 1 300 val
+myveerzwtv 1 301 val
+myvftihsny 1 301 val
+myvwyfdnxu 0 300 train
+mywatjqbyt 1 300 train
+mywbbwqetn 1 300 train
+mywbwhbqfp 1 300 train
+mywdozriss 1 300 train
+mywhfyizdl 1 300 train
+mywpfvuwrz 1 300 train
+mywukrvlwr 1 300 test
+mywxsotrec 1 301 val
+myxdhntyth 1 300 train
+myxgowbelb 1 299 train
+myxzpguowy 1 300 train
+myyairednq 1 300 val
+myydbsyecm 0 300 train
+myygiusjjb 0 300 train
+myyngykzfo 1 300 train
+myytqreqft 1 300 val
+myyvbloazh 1 301 train
+myzdslbyjk 1 300 train
+myzgxrfxmy 1 298 train
+myzkirjdft 1 300 train
+myzlafzqqu 0 300 train
+myzrrktppy 1 300 train
+myzydoxgil 1 300 train
+myzyrsrdyy 1 300 val
+mzadezhlir 1 300 train
+mzaggsvtyp 1 300 train
+mzamrxtqfa 1 300 train
+mzassrztxz 1 300 train
+mzazslymsa 1 300 train
+mzbdqjirht 1 300 val
+mzbdwuqjrd 0 300 train
+mzbipeefcj 1 300 train
+mzblcoocgm 1 300 val
+mzbsxfndjp 0 300 train
+mzcabzwmcz 1 300 train
+mzcblhjyja 1 300 val
+mzcbuvzlab 1 300 train
+mzccvujkfo 1 300 train
+mzcfqxzhjd 1 300 train
+mzcnvopgut 1 240 val
+mzcpxclunk 1 300 train
+mzcvekhzyh 1 297 val
+mzcwlmotfs 0 300 train
+mzdakgaxlw 1 300 val
+mzdcdgoxcy 1 300 train
+mzdeffbuaz 1 300 train
+mzdkdiplny 1 300 val
+mzdlwlbvql 1 300 train
+mzdqnihzag 1 300 train
+mzdynemmwv 1 300 train
+mzdzmczoga 1 300 train
+mzeagufruq 0 300 train
+mzebtvndcr 1 300 train
+mzecdtmasg 1 300 train
+mzecordeuu 1 300 val
+mzeeggnzcm 1 301 train
+mzeglwmfxd 1 300 train
+mzejzorbsy 0 300 train
+mzeqnorkow 1 300 train
+mzfdaznsek 1 299 val
+mzfdfqvait 1 300 train
+mzflwnhvam 1 241 train
+mzflznofvm 1 300 val
+mzfmmuxppm 1 300 train
+mzfmzxtzgo 1 298 train
+mzfsybqnyc 1 298 train
+mzfxcnpuxy 0 300 val
+mzgbikvhee 0 300 val
+mzgfychtfc 1 300 train
+mzgjqqkbbd 1 300 train
+mzgrmpkeod 1 301 val
+mzgxfwajoi 1 300 train
+mzgylwlcwu 1 299 train
+mzhewgslmm 1 300 val
+mzhigmfuby 0 241 train
+mzhpouvuum 1 299 val
+mzhtmlimru 1 301 val
+mzhvmyyrwk 1 240 train
+mzhvqhzplx 1 300 val
+mzigbjvwii 1 299 test
+mzigcgbdsn 1 300 train
+mzijagvmmz 1 300 val
+mzildexern 1 297 train
+mzinpazyck 1 300 train
+mzipbzjgyw 1 147 train
+mzirxufvvf 1 300 train
+mzivtdymvk 1 300 val
+mzixlzxqbk 0 300 train
+mzjdlojlgq 1 300 train
+mzjhuztfed 0 300 val
+mzjuzotmfq 1 298 train
+mzjxrbywbv 1 300 val
+mzjxuwxieq 1 300 train
+mzjyoohstx 1 240 train
+mzkcwlunbj 1 299 train
+mzkczryaia 1 300 train
+mzkeiznyfu 0 300 train
+mzkenkxwaz 1 300 train
+mzkpdjdrlw 1 300 train
+mzkyhquxmx 1 299 train
+mzlcqdkxrl 1 300 train
+mzldbrbgjv 1 302 train
+mzlhthocbk 1 300 train
+mzlhyrcvuu 1 300 train
+mzlixfmlfc 1 300 train
+mzljojdvin 1 301 train
+mzlvwnpyoc 1 299 test
+mzlwubaavq 1 300 train
+mzlxoxafgf 1 299 test
+mzlzqbwdth 1 300 train
+mzmbjmfvsq 0 300 train
+mzmevvslsp 1 290 train
+mzmikbuvwf 1 300 val
+mzmnjmwunq 0 300 train
+mzmptdahjw 0 300 train
+mzngitwont 1 300 train
+mznjyljmmk 1 301 train
+mznlaayitn 1 300 val
+mznmhdgyvy 1 300 train
+mznuchnxkj 1 300 train
+mznupbhpyw 1 300 val
+mznwphxltw 1 301 train
+mznwtrqdib 1 300 train
+mznyyikozq 1 300 train
+mzoapatlpw 1 300 train
+mzobgqyihz 0 241 train
+mzogcdmarh 1 300 val
+mzohowxiyz 1 300 train
+mzojpxzoqu 0 300 train
+mzolcisxha 1 299 val
+mzosxuastx 1 300 train
+mzovngxppz 1 301 val
+mzovnxbrnd 1 300 train
+mzpdszgwiq 1 300 train
+mzpfwmnjkq 1 300 val
+mzpivwpwgo 1 300 train
+mzpljnqykr 1 300 train
+mzpmvuvhqz 1 300 val
+mzppqxmqzz 1 241 train
+mzpqfnojnn 1 301 train
+mzpqjbbibt 1 301 val
+mzpveglnyf 1 299 val
+mzpvongxdf 1 300 train
+mzqawxrfxd 1 301 train
+mzqbopzqrb 1 300 train
+mzqcuodhkb 1 240 train
+mzqdmalalf 1 301 val
+mzqegfmtlc 1 300 train
+mzqkkesflc 1 301 val
+mzqrwkymxj 1 300 train
+mzqsimucmb 1 300 train
+mzqvbbrfxo 1 300 train
+mzqvsxnujs 1 300 val
+mzrerrrxes 1 300 train
+mzrhfooytl 0 300 train
+mzrimujteu 1 300 train
+mzrluleznq 1 300 train
+mzrmizvxsq 0 300 train
+mzrqflgqhm 1 300 train
+mzrsaeqxsy 1 300 train
+mzrsmvctwg 1 301 train
+mzrzzhsdax 0 300 train
+mzsgoseeti 1 300 train
+mzshodoqvn 1 300 train
+mzsjcryhbw 1 300 train
+mzssknmpxu 1 300 train
+mzstyjsxpj 1 300 train
+mzsxjnhjqv 0 300 train
+mztcditwki 1 300 val
+mztkzmbgkn 1 600 train
+mztlucosuc 0 300 train
+mzttokfhca 1 300 train
+mzttyjenag 1 300 val
+mzudzbqckq 1 300 train
+mzuegqwwqr 1 300 train
+mzukefhnfn 0 300 train
+mzukjtldcu 0 300 train
+mzuljqoefl 1 300 train
+mzullguyun 1 299 train
+mzumfjlrhe 1 300 train
+mzummswaya 1 300 train
+mzurunkulx 0 300 train
+mzuyaimbdz 1 302 train
+mzvbjnrgbe 1 300 train
+mzvcxlwrcu 1 300 train
+mzvdjyomrd 1 300 train
+mzvfeqheqy 1 300 train
+mzvhhsbwkf 1 302 train
+mzvkrctnjn 0 300 train
+mzvqpjgcpx 1 300 train
+mzvsjyqvmi 1 300 train
+mzvtzecszp 1 300 val
+mzvwymewml 1 302 train
+mzvxossfyj 0 300 train
+mzwcwlwbfd 1 300 train
+mzwdbkmjnb 1 300 train
+mzwdblwztn 1 300 train
+mzwduojdat 1 299 train
+mzwfaambxx 1 300 test
+mzwjnyeizv 1 298 train
+mzwouwcpxh 1 300 train
+mzxhptuyyn 1 300 train
+mzxonupwgs 1 297 train
+mzxquocqxq 1 300 train
+mzxsftbegm 1 299 train
+mzxtfngffh 1 300 val
+mzxtrdcccw 1 300 test
+mzxyhrmhhk 1 300 train
+mzxyqchubw 1 300 train
+mzybpbboto 1 300 train
+mzycaughzv 0 240 val
+mzydxbcvxd 1 300 train
+mzyedsenne 0 300 train
+mzyhpqybqh 1 300 train
+mzzfsddhse 1 136 train
+mzzwpfazkb 1 300 val
+naaaxmbvqe 0 300 train
+naadaydsqi 1 300 train
+naaghuyyud 1 298 train
+naaknmkpxz 0 300 train
+naanukhnra 1 300 train
+naaqxncjpz 1 301 train
+naatucffzt 1 300 train
+naazrtqktn 1 301 val
+nabdomebrp 1 300 train
+nabedcrfdr 1 300 train
+nabikymljp 1 300 train
+nabvkgwzox 1 300 train
+nabxkonnmf 1 300 train
+nacbccbdvf 1 300 train
+nacddgwqqs 1 300 train
+nachjzzaob 1 241 train
+nacldwtuwp 1 300 train
+nacoxwjfls 0 300 train
+nacupwakve 1 300 train
+nacwxpaqzu 0 301 train
+nadbnxyblh 1 300 train
+nadiaqbbeo 1 300 train
+nadprinqny 1 300 test
+naduqdimkv 1 300 train
+naduxvdple 1 300 train
+naegyjynzp 1 300 train
+naehlpvyth 0 300 train
+naeihomeze 1 300 train
+naelcubjlh 1 301 train
+naepzaksmd 1 300 train
+naevgucgiq 0 300 train
+nafhlyxrkc 1 300 train
+nafiieiwwq 1 301 train
+nafoemjjfl 0 300 val
+naforhmjjz 1 301 train
+nafoyzdpka 1 300 train
+nafwukjwpw 1 300 train
+nagfrylsdj 1 300 val
+naglenfptd 1 300 val
+nagohhtzfk 1 300 train
+nagqdeienh 1 300 train
+nagrrvjhnh 0 300 val
+nagrtnxqth 1 300 train
+naguvipish 0 300 train
+naguybtwbl 1 241 train
+nagyrjcrhd 1 300 train
+nahczkoide 1 300 train
+nahiduxbpe 1 300 train
+nahotslqox 0 300 train
+nahwhutklw 1 300 train
+nahwxzsjiy 1 300 val
+nahxuegxhp 1 300 train
+naiehdmahn 1 301 val
+naigugftkc 1 298 train
+naijysjeic 1 301 train
+naikfijwhr 1 300 train
+nairefvyfq 1 300 train
+naitmknkhr 1 300 train
+naitnubmfw 1 300 val
+naiyxicrfn 1 300 val
+najhikzjld 1 300 train
+najphkkwhw 1 300 train
+najtlbsygy 1 300 train
+najtzqgigt 1 300 train
+najzxxsiqu 1 298 val
+nakejhxxae 1 300 train
+nakpzdjxmn 1 301 train
+nakqjvoids 1 300 train
+nakrbvvjft 1 300 train
+nakrjdvxgr 0 300 train
+nakvamxvdj 1 300 train
+nallwasfbx 1 300 test
+nalpnekwbg 1 300 train
+nalstjqemq 1 299 test
+nalwkssfay 1 300 train
+namgagxcng 1 300 train
+namjjyjymv 1 300 train
+nammwwydpn 0 300 train
+namnscpddh 1 300 train
+namoatwlkh 1 300 train
+namostxtut 1 300 val
+namtxvqbvi 1 300 train
+namxrdtoua 1 300 train
+nanajofczq 1 300 train
+nanixzycaw 1 300 train
+nanptgayaf 0 300 train
+nanyjxjvlq 0 241 train
+naofxasawb 1 300 val
+naojiqqeln 1 298 train
+naojqxfykz 1 302 val
+naoswpvzpn 1 300 train
+naovblixxe 0 301 train
+napbeptbuv 0 300 train
+napfdcvrlk 1 300 val
+naplxsnwpu 0 300 train
+naprwzpwfo 1 300 val
+napsgejgvl 1 300 train
+napubvzmzo 1 300 val
+napynbbhoz 1 300 val
+naqitolkdk 1 301 train
+naqivbtyog 1 300 train
+naqtotwuvm 1 300 val
+naqwisjkip 1 300 train
+naqwmmjjva 1 300 train
+naqzxgrifn 1 300 train
+narbometbo 1 300 val
+nardhwsjrc 1 300 train
+nardjixugp 1 240 train
+narfmfezcg 0 300 train
+narmvcsfpy 1 300 test
+narnjljqjv 1 300 train
+narsabkgfl 1 300 train
+narybtqinj 1 300 train
+narzmahedf 1 300 train
+nasdxatlyi 1 301 val
+naskqpdkzb 1 300 val
+nasnfyedny 1 300 train
+nasqyzeisr 1 301 train
+nasrqqcips 1 300 val
+naswhsiwry 1 300 train
+nasyildaor 1 300 train
+nataaoqgsc 1 300 train
+natetvoufx 1 300 train
+natijzvjud 1 300 train
+natjbovrga 1 300 train
+natlcidrmm 1 300 train
+natlglvblt 1 299 test
+natloteigx 1 300 val
+natovdcxxq 1 300 train
+nattvpfaie 0 300 train
+natxstfuem 1 301 train
+naugnwszid 0 300 train
+naujebwgmv 0 300 train
+naukvwyegb 1 300 train
+naumeulvyt 1 301 train
+naunvapgyl 1 301 val
+naunxuggwy 1 298 train
+nauoqhhash 0 300 train
+naurxjekvo 1 300 val
+nauwnobmwb 1 298 train
+nauznkzktz 1 296 train
+navbmtvacb 1 298 train
+navdwzihsr 1 300 train
+navdzyrwsl 1 300 train
+navfsrjvbr 1 300 train
+navivqderz 1 300 train
+navjvngbdq 1 300 val
+navoiyfxpr 0 300 val
+navwmqduac 0 300 val
+navymnewfh 1 300 train
+nawekljpds 1 298 train
+nawemexwio 1 300 train
+nawgnhluzu 1 298 train
+nawgunifgm 1 300 train
+nawmthvlow 1 239 train
+nawnetfyny 0 300 train
+nawnihsbgc 1 298 train
+nawqeddlwh 1 300 val
+nawtezpgnm 0 300 train
+naxalzyvuj 1 300 train
+naxbhpgfds 1 300 val
+naxbjerarz 1 302 train
+naxoejzizp 1 300 val
+naycgijwtz 1 300 train
+nayeqxnold 1 300 train
+nayixvgqdn 1 255 train
+naymesdztn 1 300 val
+nayorflber 0 301 train
+naypafwwtz 1 300 train
+nayqgdojvv 1 300 train
+naytkgyxkh 1 298 train
+nazagsglnq 1 300 train
+nazahspgny 1 300 train
+nazfcbxhwn 0 300 train
+nazfnkguwf 1 301 train
+nazorehocq 1 300 train
+nazpckfuyx 1 300 train
+nazrkaxbzt 1 297 val
+nazxxczaxi 1 300 train
+nbaccqkufs 1 300 train
+nbadfnkmrj 1 300 train
+nbaebccpws 1 298 train
+nbagbmjgka 1 301 train
+nbalxafbxx 1 301 train
+nbbekvpkui 1 300 train
+nbbhqwekhu 1 301 train
+nbbppvdwix 0 300 train
+nbbpypqmuv 1 300 train
+nbbutfggfz 1 300 train
+nbbxssrkhg 0 300 train
+nbccsvozit 1 300 train
+nbcdwlwxou 1 300 train
+nbcffonudi 1 298 train
+nbckokihww 1 300 train
+nbcvyxosiu 1 300 train
+nbcwakzpus 1 249 train
+nbdbfxofcf 1 300 val
+nbdixxfjph 0 300 test
+nbdlaqndcg 1 300 train
+nbdtsbxhkt 1 300 train
+nbedffrual 1 300 train
+nbejntccig 1 301 val
+nbenswlbtu 1 300 train
+nbepegajdb 1 300 train
+nbetitepnt 1 300 val
+nbeumorawg 1 300 train
+nbeveeztxy 1 300 train
+nbfcfpiqts 1 300 train
+nbfhzbdpua 1 300 train
+nbfnmiwtbq 1 300 train
+nbfsletooq 1 300 train
+nbfslikshr 0 300 train
+nbgbjkltkk 1 300 val
+nbgchneapz 1 297 train
+nbgdxyhelp 1 301 val
+nbgepetpyw 1 298 val
+nbgfbqbuxm 1 300 train
+nbgjuhzmgr 1 300 train
+nbgpquigat 1 298 val
+nbgqctpzym 1 300 train
+nbgxafgabx 1 300 train
+nbgydnodgl 1 300 train
+nbgyggislz 0 300 train
+nbgzdljnzw 1 300 val
+nbhcewtdqw 1 300 train
+nbhenrmcze 1 300 train
+nbhhsahcng 1 300 train
+nbhildvafs 1 300 val
+nbhrkijthy 1 300 train
+nbhzhypcmb 1 240 train
+nbiargxffh 1 301 val
+nbiatbrnam 1 300 train
+nbibouebku 1 300 test
+nbigdewjyd 1 299 train
+nbilheyily 1 300 train
+nbilkqardi 1 300 train
+nbinpzrwfz 0 300 train
+nbirrolmrt 0 300 train
+nbitqyzefn 1 300 val
+nbiupylzko 1 300 train
+nbizfvmjdd 1 300 train
+nbjigjmxfc 1 300 train
+nbjjeprsln 1 296 val
+nbjmsxmkro 1 300 train
+nbjrxufaew 1 300 train
+nbjtqxnzet 1 300 train
+nbjvabtmyd 1 300 val
+nbjwcgpeoi 1 300 test
+nbkauiqejy 1 300 train
+nbkdrrujjl 1 300 val
+nbkfendeyb 1 300 train
+nbktfdkrrg 1 300 train
+nbkuwfcwnd 0 300 train
+nbkzlgluxa 1 300 train
+nblgnrrtjz 1 300 train
+nblnzskmfo 1 300 train
+nblqbknrdv 1 300 train
+nblsdjrazz 1 300 val
+nblsqfispc 1 300 train
+nblttuvurj 1 300 val
+nblylleytz 1 300 train
+nbmgydvhmf 1 298 train
+nbmhltbwia 1 299 test
+nbmlalfmaj 0 299 train
+nbmlxgxuxb 1 300 train
+nbmnzytoqi 1 300 train
+nbmshhsmqv 1 301 train
+nbmufxynnz 0 300 val
+nbmvxivumr 1 300 train
+nbmwjrqxva 1 298 train
+nbneoabmks 0 300 train
+nbnhzvjdfe 1 300 train
+nbnipejygk 0 301 train
+nbnljwbmhi 1 300 train
+nbnnpgcahd 1 300 train
+nbnpjxbwyk 1 300 val
+nboatxhgoc 1 241 train
+nbobaomqox 1 300 train
+nbociznosq 1 300 val
+nboksdyost 1 300 train
+nbolimzqfr 1 300 train
+nbouxnabgq 1 300 train
+nbpbjkfzlh 1 300 val
+nbpciitjgr 0 300 val
+nbpfjkaznf 1 301 train
+nbphsempfr 1 300 train
+nbpkqeskxg 1 300 val
+nbprwttixf 1 300 val
+nbpvlcqckc 1 300 train
+nbpwwmnyxa 1 300 train
+nbpxpfgqej 0 300 val
+nbqbrvzbyg 1 241 train
+nbqbukndps 1 301 train
+nbqdamaflo 1 300 train
+nbqsjmmdas 1 300 train
+nbqsomcotk 0 300 train
+nbqtidnjms 1 300 train
+nbqvqulwye 1 300 train
+nbqwucgepv 1 300 val
+nbqxpcgwbl 1 300 train
+nbqzcusjhm 1 300 train
+nbrbwqrwnb 0 300 val
+nbrkoihtck 0 300 train
+nbrliwonhz 1 300 train
+nbrypwfcrk 1 300 train
+nbsbgftqym 1 302 train
+nbsciorjom 1 300 val
+nbsckxvkqa 1 298 train
+nbscmtskvm 1 300 train
+nbscnyddnz 1 300 train
+nbsfwbpuri 1 240 train
+nbsghoucqu 1 300 train
+nbsjrgghfg 1 300 train
+nbskocndxl 1 300 val
+nbsrmnyaiv 1 300 train
+nbsuxmsimu 0 300 train
+nbswsddiio 1 300 train
+nbtjvclewz 1 300 val
+nbtolrdrtu 1 300 train
+nbtskfzobv 1 301 train
+nbtyeoapln 0 300 train
+nbtymwnxcw 0 300 train
+nbtzgpucwx 1 300 val
+nbtzmlhnng 1 241 train
+nbuaurdlci 1 301 val
+nbucoppcwn 1 300 train
+nbuegvjmjy 1 300 test
+nbuohbgntg 1 300 train
+nbuquihslw 1 300 val
+nbutkkctrb 1 300 train
+nbutmaarpm 1 301 val
+nbuvxsbejc 1 300 test
+nbuypqthyx 1 300 train
+nbvatcxcln 1 300 val
+nbvbdpinbw 1 300 val
+nbvclnwtee 0 300 train
+nbvqcmvwiu 1 300 train
+nbvxpduknx 0 300 train
+nbwcazqsrr 1 300 train
+nbwcrgpthp 1 300 train
+nbwewyqvyr 1 300 train
+nbwnfysoci 1 297 train
+nbwnqqqtlp 1 300 train
+nbwrldtczi 1 300 val
+nbxduynjlg 1 300 train
+nbxggzgmfm 1 301 train
+nbxjbsomza 1 300 train
+nbxnrzafup 0 300 train
+nbxzlqzypt 1 300 train
+nbyaxzmueg 1 300 train
+nbycyqcicf 1 300 train
+nbyeqsjbxp 1 300 train
+nbyhqpaumb 0 601 train
+nbyibxmqit 1 301 train
+nbyippfmmi 0 300 train
+nbyixzzyms 1 300 train
+nbyjfnzqne 1 300 train
+nbylacehqe 1 300 train
+nbymjiwxnp 1 298 val
+nbymxrswmu 1 300 train
+nbypuhsjwp 1 300 test
+nbyqlvfykh 1 300 train
+nbyvelzjzs 1 301 train
+nbyvuvbnxm 1 300 train
+nbyylsccci 0 300 train
+nbyyspkdkk 1 300 train
+nbyyvtctdf 1 300 train
+nbzctqjoki 1 300 val
+nbzsfubfdd 1 300 val
+nbztlmotqq 1 300 train
+nbztuiyxfq 1 300 train
+nbztuzykzj 1 300 train
+nbzuqruwwg 1 300 train
+nbzvqnmvtl 1 301 val
+nbzwhpbwbk 1 300 val
+ncagjkzyxh 1 300 train
+ncaoxltbsa 1 241 train
+ncbdfcyuav 1 300 train
+ncbempbsch 1 300 val
+ncbjpxrpbv 1 300 val
+ncbmqxvdum 1 297 val
+ncbokabwxv 1 300 train
+ncbxrjssdo 1 300 train
+ncbyedvxgp 1 300 train
+nccbctegue 1 298 train
+ncchhmtapf 1 300 val
+nccigdndow 1 299 val
+nccjwyjpsk 1 300 val
+ncckmopfoj 1 300 train
+nccoxpnvlq 1 300 train
+nccqgtempp 1 300 train
+nccsmsnysy 1 300 val
+nccwscmxww 1 301 train
+ncdbfsbrbf 1 300 train
+ncdccrmjcs 1 299 test
+ncddommjsf 1 300 train
+ncdhilcjye 0 300 val
+ncdhtzvtjd 1 300 val
+ncdipylsrq 1 300 val
+ncdmkdgthr 1 300 train
+ncdojzteem 1 300 val
+ncdxngmtoz 1 300 train
+ncdzufmnhc 0 300 train
+ncebrhagkb 1 300 train
+nceedltqkq 1 300 train
+ncefruqmhs 1 300 val
+ncehizkjqv 1 300 val
+ncexggkanu 1 300 train
+ncexxykzyp 1 300 train
+ncexylfjfk 0 300 train
+ncfgdgdumj 1 300 test
+ncfitvsfcm 1 300 train
+ncfizlitbp 0 300 train
+ncfkflbbdq 1 300 train
+ncfmvxefqv 1 300 val
+ncfomcfrtg 1 300 train
+ncfooskkuh 1 300 train
+ncfoydwtwa 1 300 train
+ncfvnmydzr 0 300 val
+ncfvyeklcy 1 300 train
+ncgenygrai 1 300 val
+ncgnlvypha 0 301 train
+ncgoxlscyw 1 300 val
+ncgqhseegh 1 300 train
+ncgrcpbnxi 1 298 val
+ncgtvyouhf 1 241 train
+nchnudxmsg 0 300 train
+nchnxucaru 1 300 train
+nchqcwdesl 1 300 val
+nchqnieiri 1 300 train
+nchtatrenu 0 300 train
+nchtltwjdl 1 300 train
+ncicqareep 1 299 test
+ncijlpxdco 1 300 train
+nciksxtcql 0 300 train
+ncirpxdcdr 1 298 val
+nciujwbttq 1 300 train
+ncjakxlyzp 1 300 val
+ncjedcjvfi 1 300 val
+ncjhudadww 1 298 train
+ncjmltaoqu 1 300 val
+ncjmnhfkvm 1 300 train
+ncjqganhal 0 300 train
+ncjqhjnkme 1 300 train
+nckblgojoc 1 301 val
+nckckgutyj 1 300 train
+nckjztxpfb 0 300 val
+ncklihamxl 1 300 train
+nckpnvxtbd 1 300 val
+nckufeswqn 1 300 train
+nckvyafrhu 1 300 train
+nckwwfdpyr 1 300 train
+nckzuzznch 1 300 train
+nclgxngmcx 0 300 train
+nclihsfdcq 0 300 train
+nclmdfcbbn 1 300 train
+nclmfksxsl 1 300 train
+ncmdnjgijn 0 300 train
+ncmdwvzcwn 1 300 train
+ncmfiprfwc 1 300 train
+ncmivzsycf 0 300 train
+ncmlhwxlgt 0 300 train
+ncmpqwmnzb 0 300 test
+ncmrmnobds 1 241 train
+ncmscdktnp 1 300 train
+ncmtepztza 0 300 val
+ncmwgkyajq 1 300 train
+ncmxzviawx 1 300 train
+ncnqeeinxm 1 300 train
+ncnsiycfhf 1 300 train
+ncnubwzwhf 1 300 val
+ncnwsxnhah 1 300 train
+ncoeewrdlo 1 300 test
+ncoetisvvx 0 300 val
+ncokiwnqdj 0 300 train
+ncomojcryo 1 300 train
+ncooitzncv 1 301 train
+ncovayibdl 1 300 train
+ncoxkqthhw 0 300 train
+ncpkleegld 1 300 train
+ncpqewudov 1 300 train
+ncpsxqukeo 1 300 train
+ncpszttxgy 1 300 train
+ncpvftqsxg 1 298 train
+ncpvmwtvmm 1 300 train
+ncpykopdst 1 269 train
+ncqfgospql 1 300 train
+ncqjcvgayx 1 300 test
+ncqqanlehb 1 300 train
+ncqqwqtzsp 1 300 train
+ncqrrpeort 1 300 train
+ncqubtttxt 1 300 val
+ncqvkpojuu 1 299 val
+ncqvoffguc 1 301 train
+ncqvyxgtkz 1 300 train
+ncqwpzghzq 0 300 train
+ncrfdnodcz 0 300 train
+ncrfihafvw 1 300 val
+ncrhejmzud 1 300 train
+ncriemndos 1 300 train
+ncrkggcdqp 0 300 train
+ncrnziejwg 1 300 train
+ncrrzxmrwe 1 300 train
+ncrtvxdnmb 1 300 train
+ncrvujbkqs 1 300 train
+ncrwgivkxi 0 300 train
+ncsammzkxp 1 241 train
+ncsbeqnuyk 1 300 val
+ncshnztnda 1 300 train
+ncsjqqjtek 1 294 train
+ncskasykgz 0 302 train
+ncslcpqowh 1 300 train
+ncsqbdipft 1 300 train
+ncsqfrlkxc 1 300 train
+nctfzxyxyu 1 239 train
+ncthmksvid 1 300 train
+nctpxcrfcf 1 300 train
+nctssvaeda 1 300 test
+nculypdvzc 1 301 train
+ncuxbddlhi 1 301 train
+ncuxovimvh 1 300 train
+ncvevwnadn 1 300 val
+ncvjumxdzg 1 300 val
+ncvlimnpqv 0 300 val
+ncvmthnfmq 0 300 train
+ncvneqorof 1 240 train
+ncvogwncsz 0 300 train
+ncvqlqywft 1 301 train
+ncvrvmweon 1 300 train
+ncvtgryovd 0 300 train
+ncvttqmssc 0 300 train
+ncvuucibxk 1 299 test
+ncvvqeqtci 1 300 train
+ncvydqtkbi 1 300 val
+ncvzhacdjk 1 300 train
+ncwecnmkjt 1 300 val
+ncwiwkthme 1 301 val
+ncwoxrstou 1 300 train
+ncwqfujhon 1 300 train
+ncwrbwyubb 0 300 train
+ncwttjzxcl 1 241 train
+ncwurnfuep 1 300 train
+ncwwjxtpic 1 300 train
+ncwyatzoff 1 300 train
+ncxkqhajrl 1 300 val
+ncxstxgbvl 1 300 train
+ncxwabwcyb 0 300 train
+ncyaawguhc 1 298 train
+ncykygpxiw 1 300 train
+ncynhltofb 1 300 train
+ncysibcigr 1 300 train
+ncyzutjjeb 1 301 train
+nczdvzbdfg 0 300 train
+nczegkklog 1 300 train
+nczfpizwfe 1 300 train
+nczmyyozbp 1 300 train
+ncztaoflxo 1 300 train
+ncztvjgajl 1 299 val
+nczxovnlsl 1 300 train
+nczylceavu 1 300 train
+ndadmtndpq 1 300 train
+ndadxdzios 1 300 train
+ndaeasdtck 1 300 train
+ndaetluhcr 0 300 train
+ndagmfmlrs 1 299 val
+ndakdkpudk 1 300 train
+ndamkbrqxh 1 302 val
+ndamphgyab 0 300 train
+ndaqopgpwc 1 300 train
+ndarhtfeun 1 300 val
+ndarjzhpjc 1 300 train
+ndasmuptcl 1 300 val
+ndaujsfrqs 1 300 train
+ndbchqwddo 1 300 train
+ndbdkjokjq 1 298 train
+ndbgglaxjz 1 300 train
+ndbielbamn 1 300 train
+ndbkraxdbg 1 300 train
+ndbsmrdiqj 0 300 train
+ndcdpizzth 1 301 train
+ndcfahbmhl 1 300 val
+ndchdiiarh 1 300 train
+ndcsqoiceg 1 298 train
+ndcvyufvte 1 300 val
+nddepqnpvd 0 300 val
+nddetnxxmi 1 300 train
+nddjzwotit 1 300 train
+nddlpzwcdc 1 300 train
+nddwcsgbof 1 300 train
+nddyapuznp 1 249 train
+ndedatonaa 1 300 train
+ndeefobajm 1 300 train
+ndejisxtyk 1 302 train
+ndeojmhafo 1 298 train
+ndesekaueu 0 300 val
+ndexnspbog 1 301 train
+ndfbaxlseo 0 300 train
+ndfdryfpit 1 300 train
+ndffzxuhse 1 300 train
+ndfhcmlzqx 1 300 train
+ndfokrbwnr 1 300 train
+ndfrtxtzvb 1 300 train
+ndfvyzcewj 1 300 val
+ndfwdmawcv 1 300 train
+ndfyqbgpfn 1 241 train
+ndgdtxorcm 0 300 train
+ndgedkmnqo 1 300 train
+ndgftklgjz 0 300 train
+ndghbdqxaw 1 300 train
+ndgjxvbvxd 0 300 val
+ndgofjkjvv 1 300 test
+ndgybupgup 1 301 train
+ndhetcimxh 1 300 train
+ndhfwcoqjd 1 300 train
+ndhigthhzm 1 300 train
+ndhkinkjaz 1 300 train
+ndhmanzwwd 1 300 train
+ndhnfzlcbw 1 300 train
+ndhrlcjesi 1 300 train
+ndhunelbbg 1 300 val
+ndhytzvnzs 1 300 train
+ndicdlvezt 1 300 train
+ndikguxzek 1 300 test
+ndilmregrw 1 300 train
+ndimhxnoxf 1 300 train
+nditsndzah 1 300 train
+ndiubgmbhg 1 300 train
+ndiwereorx 1 241 train
+ndixgditym 1 301 train
+ndiztmdymo 0 300 val
+ndizxhwrac 1 301 val
+ndjeeezmax 1 300 train
+ndjemgrhqr 1 300 train
+ndjerymuzq 1 298 train
+ndjljobilu 1 300 train
+ndjmmxekid 1 301 val
+ndjtyaaieg 1 300 train
+ndjwprmhfs 1 300 train
+ndkbashetm 1 300 val
+ndkfrykosp 1 300 train
+ndkmolotlk 1 300 train
+ndkmsjqxpp 1 300 train
+ndkrblisgp 1 300 train
+ndkstserhd 1 302 train
+ndlaqefovy 0 300 train
+ndldhhfxyu 1 300 val
+ndleldyxig 1 300 train
+ndlexgyeim 1 300 train
+ndlojawreg 0 300 train
+ndluibvlem 1 299 train
+ndlzvtwvke 1 300 train
+ndmeajgebk 1 250 train
+ndmhkzkues 1 299 train
+ndmnuoibfz 1 301 train
+ndmpamowsd 1 300 train
+ndmptgtdfc 1 300 train
+ndmwkldqpn 1 300 train
+ndmzxmfjkf 0 300 train
+ndnbssuqrl 1 241 train
+ndncmjaplk 1 300 train
+ndndzdgoax 1 300 train
+ndnojigcru 1 298 val
+ndnryukeft 1 300 train
+ndntnxhgsr 0 300 train
+ndoditkpjm 1 300 train
+ndolirqjac 1 300 train
+ndomojllfe 1 300 train
+ndonldsrsr 1 300 test
+ndoopbvemg 0 300 train
+ndorvjinqx 1 301 train
+ndovwzhure 1 300 train
+ndovwzrrvx 1 301 val
+ndozjdodze 1 300 train
+ndpdopglxk 0 300 train
+ndpeyxbrmp 1 300 train
+ndpfhbvauv 1 300 val
+ndpkorqsvv 1 300 val
+ndpljsdofg 1 300 train
+ndpmoazufj 1 300 train
+ndppzfuynx 0 300 train
+ndpxqutyti 1 300 train
+ndpxrbzfmy 1 300 train
+ndpytliklg 0 300 train
+ndqgkgnylx 1 300 train
+ndqiudmlwo 1 300 train
+ndqkbljwva 1 298 train
+ndqoaayaws 1 301 train
+ndqsqwgith 1 300 train
+ndqstjaloe 1 300 train
+ndqugdzpdd 1 300 train
+ndqvcezrwv 1 300 val
+ndqwevrpnb 1 301 train
+ndqxtifvbw 0 300 train
+ndqzbihbgt 1 300 val
+ndriqllvto 1 241 train
+ndrmjpfqgl 1 300 train
+ndrnxgzlmn 1 300 test
+ndrovtwvzw 1 239 train
+ndrrlzsisg 1 301 train
+ndrtuazsnd 1 298 val
+ndrtvognez 1 300 train
+ndsaaagqpg 1 300 train
+ndsdrnuikp 1 300 val
+ndshxjhsxt 1 300 val
+ndsqbsemzp 0 300 val
+ndswfrjvvl 1 300 train
+ndthilback 0 300 train
+ndtiibckyr 1 300 train
+ndtiurivhc 1 300 train
+ndtjbujeqt 1 290 train
+ndtmnusqiw 1 300 val
+ndtnemllzp 1 300 train
+ndtouoonmq 1 300 train
+ndtrwfmctj 1 300 train
+ndtshemwsm 1 300 val
+ndtvtyrzdu 1 300 val
+ndtxojuztg 1 300 train
+ndtzdyqmun 1 300 train
+ndukijynyi 1 300 train
+ndunzzpprj 1 300 train
+nduwcnqkvy 0 297 train
+ndvaqbmiqd 1 299 val
+ndvbekiqsq 1 300 val
+ndvgjdyvvg 0 300 train
+ndvjdqqjpt 1 300 train
+ndvollgrhf 1 300 train
+ndvrfpnuxh 1 300 val
+ndvssqditd 0 296 train
+ndvtnuwrqi 1 300 train
+ndvtxyhtmn 0 300 train
+ndwcvblfux 1 300 train
+ndwxvkswkw 1 300 train
+ndxodmkaia 0 300 train
+ndxqfwlesn 1 300 train
+ndxscfmatv 1 300 train
+ndxvdxwabf 1 300 train
+ndxxzxdqit 1 300 val
+ndxyakrywf 1 300 train
+ndyatztelp 0 300 train
+ndyawyqspd 1 143 train
+ndyfmioebl 1 300 train
+ndyhhqdmsf 1 300 train
+ndyhndewtu 1 300 train
+ndymwzxmoa 1 300 train
+ndyrkulusj 1 301 train
+ndyssxvehq 1 300 train
+ndyyewuntx 1 301 train
+ndzaasjzmx 1 300 train
+ndzgunchdr 1 300 train
+ndzhjoguky 1 300 train
+ndzhyipsgf 1 300 train
+ndzlhdhzek 1 300 val
+ndzseeklyg 1 300 train
+ndzuccesdj 1 297 train
+ndzxrizjmq 1 300 val
+ndzydaaxlz 1 300 train
+ndzzbqctva 1 301 train
+ndzzxaoepr 1 300 train
+neaailrkdh 1 300 val
+neadqcorwr 0 300 val
+neaoqchkli 0 300 train
+neapbkemvc 1 300 train
+neawnhakxq 1 300 train
+nebevwudhr 0 300 train
+nebhktvwcf 1 299 train
+nebixspans 1 300 val
+nebktdhbpr 1 300 train
+nebmxwsmya 1 300 train
+nebnxoafrr 1 300 train
+nebsjsaqie 0 300 train
+nebulnhpun 1 300 train
+nebulziuvi 1 301 train
+nebuzuiibt 1 300 train
+neclxcbxio 1 299 val
+necqbjtoyl 1 300 train
+necryczoyb 1 300 train
+nectisitzm 1 301 train
+necwvulqsa 1 300 train
+nedavsdhgw 0 300 train
+nedgimdrmp 1 300 train
+nedicmcvuc 1 300 val
+nedjklnkvv 1 300 train
+nedjqsotku 1 300 train
+nednqvfmfk 1 300 train
+nedxsueslh 1 300 train
+neeeoarioo 1 300 train
+neehuqbqms 0 300 train
+neejajmbdy 0 300 train
+neemtgxozf 0 300 train
+neesvzrjcl 1 300 train
+neetofpeop 1 300 train
+neevdicqvp 1 301 train
+neewjwzual 1 300 train
+nefaglbonh 0 300 train
+nefdyhzqtb 0 300 train
+nefkffbhzb 1 294 train
+nefstkupsd 1 300 train
+neftqrxcgx 1 299 val
+nefwkyjktt 0 300 train
+nefxlafflp 1 301 train
+negcjjhsnw 0 300 val
+negebgrpek 1 300 val
+neghoxgolw 1 237 train
+negmelwwvx 1 300 train
+negmymftfw 1 300 train
+negnavupsk 1 300 train
+negnjndvyn 1 300 train
+negopynjky 1 301 train
+negvgwtyeu 1 300 train
+negxvyedxi 1 301 val
+nehaztzcyz 1 269 train
+nehdmrljlx 0 300 val
+nehjmxipfp 1 300 train
+nehjqeevgz 1 300 train
+nehkmaotoy 1 300 train
+nehqorkiil 1 301 val
+nehuvaaiow 1 300 train
+nehyifjmtx 1 300 train
+nehyqroszo 1 300 train
+neihpjarlt 1 300 train
+neijzwrgck 1 300 train
+neikoguacv 1 301 train
+neimmepcpb 1 300 train
+neipvzqojf 1 300 train
+neistapywg 1 300 train
+neiwlbhzom 0 300 val
+neiwzqygll 1 301 train
+neiyvfdpeb 1 300 train
+nejcsyoxvo 1 300 train
+nejdfhnjen 1 300 train
+nejnnahmuq 1 301 train
+nejtxbldgv 1 300 train
+nejuxyzoyd 0 300 train
+nejydbwyde 1 300 train
+nekabxuwbe 1 300 train
+nekeugsope 0 301 val
+nekfgxguie 1 301 train
+nekkbqdjpq 1 300 val
+nekkflbpfl 1 300 train
+neklzzpkyo 1 300 train
+nekqaqfvbk 1 300 val
+nekrdzkhxy 1 300 train
+nekrzqaklo 0 300 train
+nektrpzwwp 1 298 train
+nekvytawch 1 239 val
+nekyfdwnuz 1 298 train
+nekzuvream 1 300 train
+nelgqwnzya 1 298 train
+nelhfrdmfg 1 300 train
+nelvcxixcd 1 300 val
+nelvwppjke 1 300 train
+nelwkjhuhv 1 300 val
+nembfxuvne 1 300 train
+nemclvjfhz 1 300 train
+nemehpslrc 0 300 train
+nemhdqnybj 1 300 train
+nemikhqxwj 1 300 train
+nemimkngst 1 241 train
+nemjrrjhff 1 300 val
+nemkomthrg 0 294 train
+nemkpqjcvt 1 300 train
+nemmjvieky 1 300 train
+nemqvtyxei 1 300 train
+nemxrkqqoc 1 300 train
+nemzrqisrf 0 300 train
+nenbnxxmrk 1 300 val
+nendpzgymo 1 300 val
+nendwdixmz 1 300 train
+nenjrzfjmg 1 300 train
+nenmhrkqtw 1 300 train
+nennvjajxq 1 240 val
+nenpawpvqz 1 300 train
+nenxtujdkb 0 300 train
+neofyuhhoc 1 300 train
+neogubgerq 1 300 val
+neonfkiuqa 1 300 train
+neonrxuutb 1 300 train
+neopuirujb 0 300 val
+neorkmuset 1 300 train
+neotrnwthu 0 300 train
+neovatqdtj 1 300 val
+neowwwmohf 1 300 train
+nepenhsesr 1 300 val
+nepiitaaql 0 300 train
+neplpggrqz 1 300 train
+neqaqslbon 0 300 train
+neqchlgivu 1 300 train
+neqiqekunr 1 300 train
+neqzdmmlpp 1 300 train
+neqziyganl 1 300 train
+nerdngaozu 1 302 val
+nermnqhdfq 1 300 val
+nermptaloh 1 300 val
+neshzpiejd 1 300 train
+neslgimvva 1 300 val
+nesonnafoh 1 300 train
+nesshvtwtr 1 300 train
+neszpchdrk 1 302 train
+netaquhwsi 1 300 val
+nethltegub 1 300 train
+netkdctqjq 1 300 train
+netkxloawi 1 300 val
+neufcsfawi 1 300 train
+neulmbbdrn 1 300 train
+neunuapiyr 1 299 test
+neupqmvglo 1 300 val
+neuptrhfdr 1 300 val
+neuxddbhqk 1 269 train
+nevcfvcuch 1 300 train
+nevgvsfsfj 1 300 train
+nevmytxcuf 1 300 val
+nevqptocih 1 300 val
+nevvtcjlcd 1 300 train
+nevwxpdhbq 1 300 val
+nevzamgoje 0 300 train
+nevzumkxgv 0 300 train
+newajfsdrm 0 300 train
+newgttpezs 1 298 train
+newmjwyren 1 300 train
+newrcqjphg 1 302 train
+newvmgudic 1 300 train
+newzcrvihm 1 300 train
+newzqzzavk 1 300 val
+nexboyozrm 1 300 train
+nexicsuwfg 1 300 val
+nexkqdemjm 1 300 test
+nexxcytnsl 1 300 val
+nexxuuitpy 1 300 train
+nexyayzihn 1 237 train
+nexzcfkclq 1 300 train
+neyapofpos 1 300 train
+neygqqkbbn 1 300 train
+neythsqlgv 1 300 train
+neyukfjayp 1 300 train
+neyzcqwlgw 1 300 train
+nezdynaehr 1 300 train
+nezeqwgbug 1 300 val
+neziwobkqi 1 300 train
+nezjldpigi 0 300 train
+nezoqskjji 0 300 train
+neztbwhurl 1 300 train
+nfadcirbwn 0 300 train
+nfaebrnjmb 1 300 train
+nfafdgautl 1 300 train
+nfafsubvpa 1 300 train
+nfagxfxxmo 1 300 train
+nfajzrtscr 0 300 val
+nfarqwepfq 1 300 train
+nfautgslrd 0 298 train
+nfavgeygvm 1 300 train
+nfbazsgnzb 1 300 train
+nfbfmasozw 1 300 train
+nfbfzdcwot 1 300 train
+nfbgyojrbm 1 301 train
+nfblnpidkn 1 300 train
+nfbmkqtsfb 1 299 val
+nfbqtphesv 0 300 train
+nfbrnndrlx 1 300 train
+nfccfekmzw 1 300 train
+nfccydyhxu 0 299 train
+nfcgdhpzrq 1 301 train
+nfckwrsfif 0 300 train
+nfcnuimfdp 1 300 train
+nfdbbfnuyg 1 300 train
+nfdbdrdxeu 1 300 train
+nfdgtsiwlo 1 300 train
+nfdhuaduld 0 301 train
+nfdimrrjpf 0 301 train
+nfdioyvrad 1 301 train
+nfdiyfdxum 1 300 train
+nfdxgcrdwo 1 298 train
+nfdzorxafd 1 300 train
+nfehhhsmou 1 300 val
+nfehwrndgp 1 301 val
+nfemavrhhm 1 300 val
+nfeppuvcsi 1 300 train
+nfewomiuex 1 300 train
+nffeuloxid 1 301 train
+nffgksynro 1 300 train
+nffhohhmdg 1 300 train
+nffispdihw 0 300 train
+nffjatdlne 1 300 train
+nffjmidzpv 1 300 train
+nfflgwzixe 1 240 val
+nffnvyoqey 0 300 val
+nffrthwoou 1 300 train
+nffwindckj 1 300 train
+nffxmvelie 1 300 train
+nffzvrduzp 1 300 train
+nfgbtzjfcx 1 300 train
+nfgffbxmzf 1 301 train
+nfgfjxunyp 1 298 train
+nfggecmjpb 1 300 train
+nfggixifqp 1 300 test
+nfgswmtjrm 1 249 train
+nfguqmxyit 1 302 train
+nfgvbtjnhp 1 299 val
+nfgwvvfdjl 1 300 val
+nfhazzzmie 1 300 train
+nfhbgvzqwx 1 300 train
+nfhclzgibh 1 300 val
+nfhdjadrtn 1 300 val
+nfhiqrhejq 1 300 train
+nfhmhdscus 1 300 train
+nfhmissfbn 1 300 train
+nfhriyhtji 0 300 val
+nfhuunyiir 1 300 train
+nfhxqwdmsf 1 301 train
+nfigeiizzv 1 300 val
+nfihkomttx 1 300 train
+nfimdsszyf 0 300 test
+nfioodwnmy 1 297 train
+nfioorpqxn 1 300 val
+nfisvcdmml 1 300 train
+nfixlbjpxh 1 300 test
+nfjddajvdf 1 300 val
+nfjdhjlmty 1 241 train
+nfjftplasm 1 301 val
+nfjfylwjvj 0 300 train
+nfjggywdum 0 300 train
+nfjgjcyefh 1 300 train
+nfjhxghbts 1 300 train
+nfjjukjaei 1 300 val
+nfjozoqkbh 1 269 train
+nfjsqdybmm 1 300 train
+nfjxrglzru 1 298 val
+nfjzeblmbw 1 300 train
+nfkfkrthsl 1 300 train
+nfknivueqd 1 300 train
+nfkpmwvonf 1 300 train
+nfksmyvixl 0 300 train
+nfkyqfkvkc 1 298 train
+nflbphjubl 1 300 train
+nflbwkeqpz 1 300 test
+nflhgaehdw 1 301 train
+nflpevcalu 1 300 train
+nfluwsgsds 1 300 train
+nflvzmhrav 1 300 train
+nflyqnmiih 1 300 train
+nfmcghjaxe 1 300 train
+nfmhygmlro 1 300 val
+nfmkfgadlq 1 300 train
+nfmkoepkuv 1 300 val
+nfmsmasccl 1 300 train
+nfmsnrpxiv 1 300 train
+nfmtzetvqd 1 298 train
+nfmzmdtrda 1 299 test
+nfngjfysmp 1 300 train
+nfnhahkawa 0 300 train
+nfnkgxnhsf 1 301 train
+nfnreimomi 1 300 train
+nfnshohubd 1 300 train
+nfntxmrguq 1 300 val
+nfnwjahbdp 1 300 train
+nfnzfveobw 1 300 train
+nfoapxiece 1 301 val
+nfocoshfhp 1 300 val
+nfoevsgtox 1 300 train
+nfoknuwnqe 0 300 train
+nfolnrluih 1 300 val
+nfomwdgbnx 1 241 train
+nfonkfzpyr 1 300 train
+nfoqvryexl 1 300 train
+nfoqyaryyn 1 301 train
+nfozzfizpn 0 300 train
+nfpegzgpzn 1 300 val
+nfpevkxopv 1 298 train
+nfpffxmsxu 1 300 val
+nfpkdasxso 1 300 val
+nfpkoyxozo 1 300 train
+nfpoyhnozd 1 300 train
+nfpwqayugo 1 300 train
+nfqahhtctq 0 300 val
+nfqbsywoxg 1 300 val
+nfqihxdzjq 1 300 train
+nfqkknkocy 0 300 val
+nfqksjydxv 1 300 train
+nfqpnrwvep 0 300 train
+nfqpzchywu 1 300 train
+nfrabhcdtz 1 300 train
+nfrkuzjyie 1 300 val
+nfrlaisaut 0 300 train
+nfrlgqgapp 1 300 val
+nfrmetmxwj 1 300 train
+nfrrqzlkng 1 300 train
+nfrrtmwxdh 1 300 val
+nfrtbhjtvq 1 300 val
+nfrtblzomw 1 300 train
+nfsbuncbka 1 300 train
+nfsdvqbnie 1 300 val
+nfsefnoqmf 1 241 train
+nfsppextfd 0 300 train
+nfstajzaot 0 300 train
+nfstlbkqmn 1 300 train
+nfsvuvaxhh 1 301 val
+nfswiagvow 0 300 val
+nfsztvjqpk 1 300 test
+nfteepieyv 1 300 train
+nftgltmqxj 1 300 train
+nftojzxzoa 1 300 train
+nftyqgftbe 1 300 train
+nfucjensoq 1 300 train
+nfucslbbqn 1 300 train
+nfujenqduw 1 300 train
+nfupcronao 1 300 train
+nfutdgeibm 1 300 test
+nfuuhqslgt 0 300 train
+nfvbwozpco 1 300 train
+nfveajborr 1 300 train
+nfvfntlyuf 1 301 train
+nfvieuqwra 1 300 train
+nfvirrfmsq 1 300 train
+nfvlgrpjra 1 300 train
+nfvqnqwzdx 1 300 train
+nfvqyrztxb 1 300 train
+nfvsoknggg 1 298 train
+nfvzlihqng 0 300 train
+nfwgvmgunv 1 300 train
+nfwikcmaps 1 300 val
+nfwjkoawry 1 300 val
+nfwqshwxgy 0 300 train
+nfwtcosqtn 1 300 test
+nfwtspkhvb 1 300 train
+nfwvbaszzy 1 300 val
+nfwzedwqlq 1 300 train
+nfwzmbpnuv 1 300 val
+nfxbfgxgqn 1 298 train
+nfxbkxzkha 1 300 train
+nfxgnefjvn 1 300 val
+nfxicfgzfh 1 298 train
+nfxiobzujj 0 300 train
+nfxlifwqks 1 300 train
+nfxujkttnm 1 300 train
+nfxxtygkcm 0 300 train
+nfyeeouelx 0 300 train
+nfygeskgdl 1 241 train
+nfykgngdiq 1 300 train
+nfythnqwxk 0 300 train
+nfyzqymxhj 1 297 train
+nfzaibnpow 1 300 val
+nfzbslpenp 1 300 train
+nfzenikqql 1 300 val
+nfzlizyixm 1 300 val
+nfzofkbyva 1 300 train
+nfzovvkiwx 1 300 train
+nfzxfxigys 1 300 train
+nfzyopsbqw 1 298 val
+ngactsuezs 1 300 train
+ngadlpokyf 1 300 train
+ngaewacwce 0 300 train
+ngagorxtbd 1 300 train
+ngajcyqubu 1 301 val
+ngaosflxgo 1 300 train
+ngbenpjzdy 1 300 train
+ngbixvttnd 1 300 train
+ngbpjliria 1 300 train
+ngbylctlzv 1 300 train
+ngcqupievt 1 300 train
+ngctygbncn 0 300 val
+ngczgnnyet 1 298 val
+ngdhepgoms 0 300 train
+ngdkobqvsu 1 300 train
+ngdnashzmu 1 300 val
+ngdpqiorqa 0 300 train
+ngdpzvwisg 1 301 train
+ngdsfhzrya 1 300 train
+ngdswpaqnt 0 298 train
+ngdyamcqwe 1 300 train
+ngeaavegic 0 300 train
+ngefbiylwf 1 300 train
+ngejylulca 1 300 train
+ngeomqzowc 1 300 val
+ngesleahtm 1 300 test
+ngewgqjitm 1 300 train
+ngexuxgwct 1 300 train
+ngfkevhzjk 1 300 train
+ngflglvzbi 1 300 train
+ngflylujmu 1 300 train
+ngfpoxudtj 1 300 train
+ngfprnzwwn 1 301 train
+ngfqihtamh 1 300 train
+ngfqvzdhnj 0 300 train
+ngfsjmmpqa 1 300 train
+ngfuvecyeu 1 300 train
+nggaarypjp 1 300 train
+nggamlamjg 1 300 train
+nggemodzrx 1 300 train
+nggmleqfnq 1 300 train
+nggoqzrngg 1 300 train
+nggrodpfsn 0 301 train
+nggwaxvlzw 1 300 train
+nghcjfduje 1 300 train
+nghecwwzkv 1 296 val
+ngheregwar 0 300 train
+nghoezpthp 1 300 train
+nghrgsavfa 1 300 train
+nghuvgrpzd 1 240 train
+nghzbiizbo 1 300 train
+ngieuvlvky 0 300 val
+ngijsdrhwf 1 297 train
+nginxgpnrc 1 301 val
+ngiraafgbc 1 300 train
+ngitksgpua 1 300 train
+ngivystkkk 1 300 train
+ngixbybxdq 0 300 train
+ngiyhnmnik 0 300 val
+ngjalyvqst 1 301 train
+ngjgqjxfyq 1 301 train
+ngjkwgffpb 1 300 train
+ngjssklboy 1 298 train
+ngjyloqqtz 1 300 val
+ngkbutwngd 1 300 train
+ngkllonpkt 1 300 train
+ngkrlyoazt 0 300 train
+ngktbwztro 1 300 train
+ngkubwnpwt 1 300 train
+ngkwnaqkcw 1 300 train
+ngkwzwskhe 1 300 train
+ngkxqtabyc 0 300 train
+ngkzoykdkh 0 300 train
+nglcipwrsh 1 300 train
+nglitpseyp 1 300 val
+ngljxaopeb 0 300 train
+nglkpcqpob 0 300 val
+nglnvdbdxs 1 300 train
+nglogdpjwn 1 300 train
+nglohvjfku 0 300 train
+nglozmzpcd 1 300 val
+nglruwlshn 1 300 train
+nglsejvegf 1 300 train
+ngluidoqzq 1 300 train
+nglxgcncgt 0 300 train
+ngmddfsssu 1 300 train
+ngmfcgpvrl 1 300 val
+ngmfwswrag 1 300 train
+ngmixnpljc 1 241 train
+ngmjjareeb 1 300 train
+ngmlngwlkv 1 300 train
+ngmorkepcx 0 300 train
+ngmsqkaogv 1 300 train
+ngmtolyqmr 1 300 train
+ngmwybhzoc 0 300 val
+ngnhfloutm 1 300 train
+ngnkrtzghl 1 300 train
+ngnoguzzkd 1 300 test
+ngnzqheiic 1 298 train
+ngomywonyp 0 300 val
+ngopbwjicq 1 300 train
+ngorbnmyld 1 300 train
+ngosuoqkkw 1 301 train
+ngpjamefuo 1 300 train
+ngplqtbcxb 1 300 train
+ngpmkwfqbl 1 301 train
+ngpquggdta 1 300 train
+ngpvjrkpnb 1 300 train
+ngqbmzsnxp 1 300 val
+ngqxeydokv 1 301 train
+ngscwofpih 1 300 train
+ngsirktveq 1 300 train
+ngsjqziqmc 1 301 val
+ngslofohfp 1 241 train
+ngslrhavvk 1 300 train
+ngsqzhgnwz 1 300 train
+ngsrsoqizm 1 300 train
+ngsxtujmtm 1 300 val
+ngtgoxypor 1 136 train
+ngtwruwbup 1 300 train
+ngueyhtojp 1 300 train
+ngulptlssh 1 300 train
+ngutasalqd 1 300 train
+nguwsanafn 1 300 val
+ngvamtarwx 1 298 val
+ngvbaolyub 1 300 val
+ngvbavyoqd 1 300 train
+ngvcqxjhyb 0 300 train
+ngvlrslwpk 1 300 val
+ngvndbobah 1 300 train
+ngvscvetrq 1 301 train
+ngvvgveogh 0 300 train
+ngvwszejci 1 300 val
+ngvwxzfoyc 1 301 train
+ngvxubpton 1 300 train
+ngvzdnpuew 1 300 train
+ngwgfjjqrp 1 300 train
+ngwlbmzmke 1 301 train
+ngwvgtaqgj 1 300 train
+ngwycidxmn 1 300 train
+ngxcxpdpot 1 300 train
+ngxfhthyol 1 300 train
+ngxgcuotvc 1 300 train
+ngxpvkinsd 1 300 train
+ngxzvrfstg 1 300 train
+ngygnxotbf 1 301 train
+ngygzyhawv 1 300 val
+ngylgfllmf 0 300 val
+ngyoubuxyf 1 300 test
+ngyslvhoek 0 300 train
+ngywuqvqcf 1 302 val
+ngywzsneek 0 300 val
+ngzcoejlxp 1 300 train
+ngzducuvwq 1 240 train
+ngznjjdpmg 1 300 train
+ngzoqkyney 1 300 train
+ngzpwtfunv 0 300 train
+ngzqnucpqt 0 300 train
+ngzxcrnkjx 1 300 val
+ngzxexjflf 1 300 train
+nhaahtulzi 1 300 val
+nhaitefmdo 1 300 train
+nhampbvryx 1 299 val
+nhaoocremb 1 300 train
+nhaougjoex 1 300 val
+nhbbwrhute 0 241 train
+nhbeoxqhtq 1 300 train
+nhbvdshvas 1 300 val
+nhbyfqkixv 1 300 train
+nhcfanpwlg 1 300 train
+nhcfgewaic 1 300 train
+nhchfdgqtd 1 300 train
+nhcnifdumr 1 301 train
+nhdirtckat 0 300 train
+nhdjglbekk 1 300 train
+nhdkjojdpc 1 300 train
+nhdmtkjxap 1 300 train
+nhdngnotff 1 300 val
+nhdwrthria 0 300 train
+nhdxzascur 1 300 train
+nheiwhyrio 1 300 train
+nhepmqtzyw 1 300 train
+nheslaitil 1 300 val
+nhfdckldpi 1 300 train
+nhfsobmiri 1 298 train
+nhfstcfmdx 1 300 train
+nhfsxjrivn 1 300 train
+nhfzdczcig 1 300 train
+nhgdvdtzzk 1 300 train
+nhgfddysua 1 300 train
+nhggigrlac 0 300 train
+nhgnfbsaoi 1 300 train
+nhgtbxbxqd 1 300 train
+nhgxigaeit 1 300 train
+nhgxoveopv 1 300 train
+nhgyntvhbg 1 300 test
+nhgzydcyrn 1 300 train
+nhhflbslqm 1 300 train
+nhhixdaorj 1 299 train
+nhhjhtrkxy 1 300 train
+nhhllmxnbl 1 300 train
+nhhvemcytp 1 300 val
+nhibxybdec 1 300 train
+nhikvdyyyg 0 300 train
+nhilkmbtbw 1 296 val
+nhirfybtea 1 300 train
+nhisztqano 1 300 train
+nhjcpgoadi 0 300 train
+nhjfadakup 1 300 train
+nhjffzcvnz 1 300 train
+nhjfonhgva 0 300 train
+nhjmmazyos 1 300 train
+nhjpypcjiq 1 300 train
+nhjwirsocg 0 300 val
+nhjxfskcqi 1 300 train
+nhkapympwu 1 300 train
+nhkdyjuttj 1 300 train
+nhkegaqwuc 1 300 val
+nhkenclutb 0 300 val
+nhkesvygtx 1 300 train
+nhkhwylufd 1 300 train
+nhknkdzana 1 300 val
+nhkwncutyp 1 300 val
+nhldlpnhvr 1 300 train
+nhljynpxic 1 300 train
+nhlnbqfhnr 1 301 train
+nhlxuqvqdl 1 300 train
+nhmdqcpasy 1 300 train
+nhmgobonzm 1 297 train
+nhmjzkrdjo 1 300 train
+nhmmllqntc 0 300 train
+nhmnavhkwa 1 300 val
+nhmqxumijx 1 300 train
+nhmsyimuds 1 299 val
+nhmuxadvdf 1 300 train
+nhncsonhuw 1 301 val
+nhncvqokpr 1 300 val
+nhnhwalplb 1 300 val
+nhnigmigey 1 301 train
+nhnjomeasw 1 300 train
+nhnklazruy 1 300 train
+nhnmicfjkc 1 300 train
+nhnpsdmiig 1 300 train
+nhnqozmwdx 1 300 train
+nhnqzsreme 1 300 train
+nhnwsdgfrn 1 300 train
+nhnxidckkq 1 300 train
+nhodgljvbd 1 300 train
+nhodnuetwx 1 300 train
+nhofvtgydm 1 300 train
+nhohecyvrr 1 300 train
+nhohwyteco 0 300 train
+nhomcfqwgr 1 300 train
+nhophozygb 1 301 val
+nhozmjxaxb 1 300 train
+nhpkonrcgr 1 300 train
+nhpoezjtev 1 300 val
+nhppgzxctv 0 300 train
+nhpsxqewrt 1 300 train
+nhptpzfeon 1 300 train
+nhpwolnhnx 1 301 train
+nhqbgxzbuj 1 300 train
+nhqdroreqr 1 300 train
+nhqnxuxcet 1 301 train
+nhrfdwucfz 1 300 train
+nhrjbxmjus 1 301 train
+nhrqjnyvjl 1 300 train
+nhshcfhcxe 0 300 train
+nhsijqpoda 0 300 test
+nhsjaoognc 1 297 val
+nhsjbsfvgv 1 300 train
+nhslhschni 1 300 train
+nhsmgcdzrh 0 300 train
+nhsprpibiv 0 300 train
+nhsqkozagd 1 300 test
+nhstiqnefx 1 300 val
+nhsybaiakc 1 301 val
+nhsyvtkfhr 1 300 train
+nhtkueolya 0 298 train
+nhtmxvnaaw 1 300 train
+nhtrrujbpd 1 300 train
+nhtskizprq 1 300 train
+nhtuqbjuth 1 300 train
+nhtuwustoz 0 300 train
+nhtwtvzaxv 1 300 train
+nhugfmgmvh 0 300 train
+nhuntfthtx 0 298 train
+nhuxbfzqqf 1 300 train
+nhuymurici 1 300 train
+nhvcsdbemf 1 241 train
+nhvmninozk 1 300 train
+nhvmwpqkhb 1 301 val
+nhvnvvlqfc 1 300 train
+nhvoglnald 1 300 train
+nhvqelmcgw 1 301 train
+nhvqpqfqvm 1 301 train
+nhvrclypnh 1 301 val
+nhvrgmxvth 1 300 train
+nhvzjtvtsg 1 298 train
+nhwafxmheu 1 300 train
+nhwdszregz 1 300 val
+nhwfyccnte 1 300 train
+nhwgjozzhi 1 300 train
+nhwioieafd 1 300 train
+nhwlousrxj 1 300 train
+nhwpcxkwfv 0 300 train
+nhwsriodri 1 300 val
+nhwyxoahrd 1 300 train
+nhwzdmqtbf 1 300 train
+nhxolaztxi 1 299 test
+nhxowvyapk 0 300 train
+nhxpgschgn 1 300 train
+nhxuxwpinw 1 300 train
+nhydwyrlyk 1 300 val
+nhyeoieamo 0 300 train
+nhyewdfskp 1 300 val
+nhygglussv 0 300 train
+nhyoienivq 1 300 train
+nhyqkwcbod 1 301 train
+nhyuseptxe 1 299 train
+nhzcwlqwrp 1 300 train
+nhzjxfptjw 1 296 val
+nhzmuwaojm 1 298 val
+nhzoxrrctp 1 300 val
+nhzuxozhzh 1 300 train
+nhzvqxdaom 1 300 train
+nhzzaivpfk 0 300 train
+nhzzdenlxg 1 300 train
+niaikexztg 1 241 train
+nialojrqyu 1 300 train
+niapdlqizx 0 300 train
+niawhrtfjv 1 300 train
+niawpcjeaj 1 300 val
+niawrimrpv 1 300 train
+niaxqbtnln 1 241 train
+nibcfatbyo 1 300 train
+nibfaulvut 0 300 train
+nibhnrwrbe 1 300 train
+nibllzvqhv 1 240 train
+nibmfggegz 1 300 train
+niboxwakue 1 300 train
+nibrkkkwii 1 241 train
+nibyvqklbi 1 300 train
+nicbbtmvby 1 300 train
+nicbyzkump 1 300 train
+nicfzvaddb 1 300 train
+nictagyvad 1 241 train
+nictvjnrlt 1 300 train
+nidaabockz 1 300 val
+nidaifmzrn 1 300 val
+nididmnfsy 1 300 train
+nidtgegbkx 1 300 train
+nidvpqcuim 0 300 train
+nieakdpjas 1 300 val
+niefubifmg 1 300 train
+niehaxsjvw 0 300 train
+niejsodevw 1 300 train
+niekvmyblc 1 300 val
+niekwwunkb 1 300 train
+niepdenckv 1 301 val
+nierjgguuk 1 300 train
+nifbnssmtu 1 300 train
+nifezyvknz 1 300 train
+niffiixoya 1 300 train
+niffjezaqu 1 241 train
+niffjfzfmk 1 300 train
+nifgzvkblp 1 300 train
+nifppgslou 1 300 train
+nifqihvmho 1 300 train
+nifrcsjyse 1 301 train
+nifuvhzbmb 1 300 train
+nigakthqeg 1 300 train
+nigebvgmga 1 300 val
+nigewpbmmo 1 300 train
+nigfvdrfqs 1 300 train
+niginimxca 1 136 train
+nigngkzouh 1 300 train
+nigrfxanhb 1 298 train
+nigvovtyac 1 300 train
+nigwtgamqq 1 300 train
+nigwzriyci 0 300 train
+nigytcchgw 0 300 train
+nihbdlomse 1 300 train
+nihgpzhylu 1 300 train
+nihguufyth 1 298 train
+nihklzhshj 1 300 val
+nihupchegh 0 300 train
+nihwthpyma 1 301 val
+nihzmujqqg 1 300 train
+nihzulmhyy 1 300 val
+niimyzzvcc 1 300 train
+niiskmwmbv 1 300 train
+nijdjghknu 1 301 train
+nijgcrkdxh 1 294 train
+nijvrcwpfv 0 300 train
+nijvxczeyp 1 300 train
+nikbukawsf 1 300 train
+nikgipbrgn 1 300 train
+nikjmzghma 1 300 train
+niksmfgbkz 1 300 val
+nikynwcvuh 1 299 test
+nikyzfyurx 1 300 train
+nilkyzjtka 1 300 train
+niloopqatp 1 300 train
+nilsnzagxe 1 301 val
+niltlqlxku 0 300 train
+nilxaonflk 0 300 train
+nilziheylw 0 300 train
+nimdyhpdhr 0 300 train
+nimfdfkezw 1 300 val
+nimflfwddz 1 300 train
+nimjvlvgfj 1 300 train
+nimlffokes 1 300 train
+nimmkalbst 1 300 train
+nimtaswerb 1 300 train
+nimtpislrg 1 300 val
+ninekezjqo 1 299 val
+ninnmxlimr 0 300 train
+ninqzofbpo 1 300 train
+ninujeulpr 1 300 train
+ninzisesmh 1 300 train
+nioaaxmktc 1 300 val
+nioeronoih 1 300 train
+niogdjyida 1 300 train
+niohjyngfx 1 300 train
+niomsqrrvk 1 300 train
+nioqtolubb 0 300 train
+niozxpkvnn 1 300 train
+nipfntybst 1 298 train
+niphzrcipb 1 300 val
+nipmejgibb 1 300 train
+nipneftcvz 1 300 train
+nippajsgbk 1 300 val
+nippkrswfw 0 295 train
+niptrdsfjq 1 300 train
+nipyrzpohd 0 300 train
+niqjcavool 1 300 train
+niqloidxft 1 300 train
+nirbpdaqgf 1 300 train
+niretxbhcr 1 300 val
+nirgmefaec 1 300 train
+niriojrxdv 1 300 val
+nirirlsfrj 1 300 train
+nirjrklqzu 0 300 val
+nirwqaczoe 0 300 val
+nirxtmboor 1 300 val
+nislgxqedt 1 299 val
+nispatcyxi 1 300 train
+nisxdaqdxi 1 300 train
+nisxmgovee 1 300 train
+nitltcamre 1 300 train
+nitmcepdct 1 300 train
+nitnwcfloi 1 300 val
+nitsucojax 1 299 test
+niuahgmais 1 300 train
+niuazxrnvw 0 300 train
+niuchraldf 1 300 train
+niutomctwy 1 300 train
+niuurktsiv 1 298 train
+niuvisssml 1 300 val
+nivcoeziwq 1 300 val
+nivmbunhta 1 300 train
+nivpykcvbk 1 300 train
+niwekxqplu 1 300 train
+niwmvhbuqc 1 300 train
+niwnfixqqn 0 300 train
+niwnrlfdkj 1 300 train
+niwobfvevz 1 300 train
+niwufzpnxl 1 300 train
+niwuivythg 1 300 train
+niwwecztgw 1 250 train
+niwyixzidw 0 300 train
+niwzouepad 1 300 train
+nixdovcacr 1 301 val
+nixmbgkwlo 1 300 val
+nixohljfqx 1 300 test
+nixtujglhn 1 298 train
+nixtuusgmn 1 301 train
+nixvrxgpzp 1 300 val
+nixwzywtrj 1 300 train
+niyghrbqtl 1 300 val
+niylpksclj 1 300 train
+niypamicvn 1 300 train
+niypapnoea 1 298 train
+niyypzefnu 1 300 train
+niyyybaleg 0 300 train
+niyzdxuwav 0 300 val
+nizarkvxtd 0 300 train
+nizgkigpxj 1 300 val
+nizhllsqpr 1 300 val
+nizibcuznt 1 300 train
+nizimzttpj 1 302 train
+nizjecvkji 1 297 val
+nizuthbrif 1 300 train
+nizyqplmoy 1 300 train
+njabmaaiog 1 300 val
+njacfyjxfg 1 300 val
+njakplskrz 0 300 train
+njanvyfzpv 1 300 train
+njatznypkg 1 298 train
+njavildrws 1 300 train
+njavqpidtj 1 300 train
+njbkmkoqfr 1 300 train
+njbnvuigqk 1 300 train
+njbqytcmvp 1 300 train
+njcaovbtyh 1 300 train
+njcmmvvjhs 1 298 train
+njcqcxqviz 1 300 train
+njcqrxzvep 1 300 val
+njcrpzrbth 1 300 train
+njcuuluowh 1 300 train
+njcwryerlv 1 300 train
+njcxcjexkv 1 300 train
+njdckgtusp 1 297 train
+njdgiohqdv 1 300 train
+njdhjhyymo 1 299 train
+njdoflinsx 1 301 train
+njeltjdjqx 1 300 train
+njewytntow 0 300 train
+njfcejvwds 1 300 train
+njfcuslhoc 1 300 train
+njfedlglxs 1 300 train
+njfeeyfkev 1 300 train
+njfeteruka 1 300 train
+njfghucgoi 1 288 train
+njgazdvzfg 1 301 train
+njgfbcdxqa 1 300 train
+njgirarbot 1 300 train
+njgljwiwns 1 302 train
+njglrfrulp 1 241 train
+njgmgmnasn 1 300 val
+njgpdwjvpz 1 300 train
+njgpwosuoo 1 300 train
+njgrwwkkzd 1 300 train
+njgumijotw 0 300 train
+njgxifopwk 1 298 train
+njgxybsyrt 1 300 train
+njgymtktgd 1 300 train
+njgyzsjgap 1 241 train
+njhbbxuahu 1 300 train
+njhdmaeykp 1 300 train
+njherbcetm 1 300 val
+njhgyxlzuy 1 300 val
+njhjdgvvnp 0 300 train
+njhttpwbxu 1 298 val
+njhuvobalq 1 301 train
+njicwikklr 1 298 train
+njiglmiahe 1 300 train
+njihyijkpv 1 300 train
+njiqmszzww 1 300 train
+njiscgkiqm 1 300 val
+njjeykdehp 1 241 train
+njjgsjxsgc 1 300 train
+njjnuesxkt 1 300 train
+njjnvekhkd 1 300 val
+njjsexdgbx 1 300 train
+njkfskuivz 1 300 val
+njkxkxfpux 1 300 train
+njkzwdpdxb 1 300 val
+njldlyzwja 1 300 train
+njljgtgfmo 1 300 train
+njluugaspf 1 300 train
+njmistdrwr 1 300 val
+njmukysnot 1 300 train
+njmwrhwirv 1 301 train
+njmywmiirk 1 301 train
+njncyiroge 1 297 val
+njngzutjpt 1 300 train
+njnkhqprzw 0 300 train
+njnqmtotwi 1 300 train
+njnswmorjb 1 300 train
+njntytmhrg 1 300 val
+njnvjpiglm 1 300 train
+njojuwquvs 1 300 train
+njolwsyukw 1 301 val
+njomchggzk 1 298 train
+njomdecrei 1 300 train
+njopsdktpu 1 300 train
+njovfvvkeq 0 300 val
+njoxqoghns 0 300 train
+njpbtftgqm 0 300 val
+njpdcldtar 1 300 train
+njpjjvdrzc 1 300 train
+njpnjcaxjl 1 300 train
+njpocpskec 0 300 train
+njpofvqdho 0 300 train
+njposiufoa 1 300 train
+njpppozopc 1 300 train
+njpqdbsubj 1 301 train
+njprnrjqva 1 300 val
+njpvzcnqxg 1 300 train
+njpxisseey 1 300 train
+njqbwiajss 1 301 train
+njqeamadfq 1 300 train
+njqfnhrusb 0 300 train
+njqgtckcjz 1 300 train
+njqlwxrenw 1 298 train
+njqszxgrds 1 300 train
+njqunjobbq 1 301 val
+njqvtduwyp 0 300 train
+njqwtamryw 1 300 train
+njradgdzmj 0 300 train
+njrcaurral 0 300 train
+njrcbkogwk 1 300 train
+njrdqqcnpm 1 300 train
+njrnbiujiv 1 300 train
+njrnkqsovu 1 300 train
+njrpcrpkvt 1 300 train
+njrruiimws 1 300 train
+njrwiabeix 1 300 val
+njrzonefqr 0 300 train
+njsewokhqh 1 301 val
+njshbwdkyp 1 301 train
+njshzxnawy 1 300 train
+njsrbuetyy 1 241 train
+njstygawje 1 300 val
+njswqktpfh 1 302 train
+njtcvkweqk 1 300 train
+njtczhbbpi 1 300 val
+njtlixpjki 1 241 train
+njtuxxlmrk 0 301 train
+njtvpzyysk 1 299 test
+njtxerejrr 1 300 val
+njtyydboml 1 300 train
+njucxfjbfj 1 300 val
+njudiwupgh 1 299 val
+njufvsurrp 1 300 train
+njugjgwrbp 1 300 train
+njuhuzmooi 1 300 val
+njujfjksku 1 300 val
+njvhtymjyd 1 300 val
+njvksnsuju 1 300 train
+njvlsykkxc 1 300 train
+njvqgnzdgf 1 300 train
+njvtpqastk 1 300 val
+njwfepinvj 1 300 train
+njwgkgufyp 1 300 val
+njwimwazsv 0 300 train
+njwjtzzfxs 1 300 train
+njwnwambff 1 301 train
+njwohzoznz 1 300 train
+njwpepamvf 1 300 val
+njwsmltmvb 1 300 train
+njxmuszjcm 1 300 train
+njxpkrjgyv 1 300 train
+njxsgdjuyy 1 300 train
+njxvnijnbq 1 300 train
+njxycoikti 1 300 train
+njyeutrdhi 1 301 train
+njyfbkkojn 1 300 train
+njygdjslty 1 300 train
+njyinaxucj 1 300 val
+njyowkvohi 0 300 train
+njyuixnlbz 0 300 train
+njyujbkxco 1 300 train
+njyyzfyzrf 1 301 train
+njyzojvzjz 0 300 train
+njzlbzpmhj 1 300 train
+njzooaihel 1 300 train
+njzpbybjjh 1 301 val
+njzrcktcow 1 300 val
+njzshtfmcw 1 300 test
+nkaffgirvk 1 300 train
+nkaknobori 1 300 val
+nkantstxcy 1 300 train
+nkasoobayk 1 300 train
+nkauocpskr 1 300 val
+nkauzqennc 1 300 train
+nkaxowbysf 1 239 train
+nkazzgivmu 1 300 train
+nkbdsynomh 1 299 val
+nkbfjtdlsi 0 300 train
+nkbgibdilf 1 300 train
+nkbiflbcpm 1 300 train
+nkbkeqplzq 1 300 train
+nkbolqzdjr 0 300 train
+nkcazzgjcv 1 302 val
+nkckizodme 1 300 train
+nkcnpbyqnh 1 300 train
+nkcqdkoimm 1 300 train
+nkcswhzmac 1 300 train
+nkdbsnoutg 1 297 val
+nkdezlyzlz 1 300 train
+nkdmiohkha 1 301 train
+nkedosswxb 0 300 train
+nkeebgvqmh 1 300 train
+nkefkzmccs 1 300 train
+nkehauktfp 1 300 train
+nkeotjdnuw 1 300 train
+nkesfyzogu 1 301 train
+nkeyiwhgjm 1 300 train
+nkfheprvkq 1 300 train
+nkfkvpcydd 1 298 train
+nkfmrhfqgl 1 300 train
+nkfnoabmcp 1 300 val
+nkfwgkmlgy 1 301 train
+nkfxfvglzp 0 300 train
+nkfydoeqqd 1 300 train
+nkgaobgovi 1 300 train
+nkggblonvi 0 300 train
+nkgimgddzu 1 300 train
+nkgjczfdrh 1 300 train
+nkgwffbete 1 300 train
+nkgzseqjqe 1 301 train
+nkhefxuveu 1 300 train
+nkhhjotauz 0 300 train
+nkhskoelyv 1 301 train
+nkhsouvpkl 1 300 train
+nkhvyiyfsk 1 300 train
+nkhymwamrq 1 297 train
+nkhzxomani 1 300 test
+nkicdspfbc 1 300 train
+nkidbjwiql 1 300 train
+nkiecrrcsk 1 300 train
+nkifiktozw 1 300 train
+nkigpnjaqg 1 300 train
+nkihilgprc 1 301 train
+nkijeknzna 1 300 train
+nkijmnwyaq 1 300 val
+nkiojhmoxu 1 300 val
+nkirtgsbae 1 300 val
+nkisgusori 1 300 train
+nkiufevrju 1 297 train
+nkiwfdlcyk 0 300 train
+nkjahbmcmy 0 301 train
+nkjewulqox 0 300 train
+nkjiljpiie 1 300 train
+nkjpqxamjt 0 300 train
+nkjqlylfhs 1 300 train
+nkjvxekngp 1 301 train
+nkjxxlsphn 1 241 train
+nkkavcrugm 1 300 val
+nkkpwzkphz 1 300 train
+nkkwhxcsmf 1 301 train
+nkkwxbkdxc 0 300 train
+nkkygthtoc 1 298 train
+nkkysnrppj 1 300 val
+nkkyverkkz 1 300 train
+nklbgukskk 1 300 train
+nklfiklxfw 1 300 val
+nkljanlsjo 1 300 train
+nklqgcupkf 1 300 train
+nklugzzkgm 1 300 train
+nklwtatmtq 0 300 train
+nklwuvsboo 0 300 train
+nkmahfuvzt 1 298 train
+nkmbyjikgt 0 300 val
+nkmccauprc 1 300 train
+nkmfmbvsjl 0 300 val
+nkmpgflizt 1 300 train
+nkmvotdexf 1 299 test
+nkmvypwzpp 1 300 train
+nknaynkpbw 1 300 train
+nkndhurlsy 0 300 train
+nkndkmguuz 1 300 val
+nkndqgjmbb 1 300 train
+nknhdfseig 1 300 val
+nknnudgbdj 1 300 val
+nknnzhvjcw 1 298 train
+nknrahnnai 1 300 train
+nknvnlsuhw 1 300 train
+nknzisrxby 1 299 test
+nkodmxpluk 1 300 train
+nkojmntmdg 1 300 test
+nkolxqvrtq 1 299 train
+nkoqaasrfe 1 300 train
+nkowfejbbk 0 300 train
+nkpkkkzsbg 1 300 train
+nkpmcykiyf 1 301 train
+nkppbhzwqc 1 300 train
+nkpqkddsgt 0 300 train
+nkpvzvsedv 1 300 train
+nkpywupdbi 1 300 train
+nkpzeyyhdt 0 300 train
+nkpzfipxbl 1 298 train
+nkqahghhxx 0 300 train
+nkqfmnymfh 1 300 train
+nkqgtvnvrr 1 300 train
+nkqkvwpghi 0 300 train
+nkqvjykgmm 1 300 val
+nkqxscvsxy 1 300 train
+nkqzsmhmhq 1 300 train
+nkrgpzbpwz 1 300 val
+nkrobnhexu 0 300 train
+nkrpqrpecv 1 300 train
+nkrptbphvs 1 297 train
+nkrwbfhvzt 0 300 train
+nksfulptfj 1 300 train
+nkskjgxsdc 1 300 train
+nkthitfanz 1 301 train
+nktkwcewbz 1 301 train
+nktpksrdpo 1 300 train
+nktugsvimx 1 300 val
+nktvkktetv 1 300 train
+nkvgaupnen 1 300 train
+nkviplblzz 0 300 train
+nkvjwninde 1 298 train
+nkvsnwkdes 1 300 train
+nkvtnaljxg 1 300 train
+nkvuqlqpkg 1 298 train
+nkwcryvgfm 1 300 test
+nkweonabbb 1 300 train
+nkwinutkgu 1 300 train
+nkwizirrcw 1 300 val
+nkwjnyzyjm 1 300 train
+nkwmfkzzlf 1 300 val
+nkwnsnvyjr 1 300 train
+nkwouxhiut 1 300 val
+nkwppmhbzc 1 300 val
+nkwwgbetle 1 302 val
+nkwyvavckm 1 300 val
+nkxcticcdv 1 300 train
+nkxthkyjph 0 300 val
+nkxvbxxypj 1 300 train
+nkxxaiodnu 1 300 train
+nkxybyoptw 1 300 train
+nkxyfksfvj 1 300 train
+nkykagvhxp 1 241 train
+nkykfkfsjn 1 300 train
+nkyutijnxe 1 147 train
+nkywneibsa 1 300 train
+nkywuecmkl 1 300 train
+nkyxaggsxd 1 300 train
+nkzbfhgbbk 1 300 val
+nkzcnejvov 1 298 train
+nkzedbuccb 1 300 val
+nkzugfsbna 1 300 train
+nlaemmrytw 1 300 train
+nlaevfisim 1 300 train
+nlajeoqhgr 1 241 train
+nlakalpoce 1 300 val
+nlalsbvoin 1 299 train
+nlamrwoqba 1 300 train
+nlamtdyzwr 1 301 train
+nlarphiexs 1 300 train
+nlasavgzow 1 300 val
+nlaycddtsf 1 300 train
+nlbbatlhwh 1 299 val
+nlbdjpegpt 1 300 train
+nlbejgudfx 1 300 train
+nlbeldnhpa 0 299 test
+nlbpcsrtac 1 300 train
+nlbpgqqmoi 1 300 train
+nlbruwbslp 1 300 train
+nlbvqcirdo 1 298 train
+nlbvtntmqj 1 300 train
+nlbzoppfoq 1 300 train
+nlcaewqvhl 1 300 train
+nlcjwjdafj 1 300 train
+nlcmkmgnqk 1 300 train
+nlcqykqsdp 0 300 train
+nlcthitrqk 1 300 train
+nlcvvunqdl 1 300 train
+nlcyetqxys 1 300 train
+nlddmiyjhg 1 300 train
+nldkysannp 1 300 train
+nldlhraynp 1 300 train
+nldohkaotb 1 300 train
+nldopkdett 1 301 train
+nleahexbay 1 300 train
+nlefioftoo 1 300 val
+nlefohhkwi 0 300 val
+nleiazpozc 1 300 train
+nlepcxcoze 1 300 train
+nlerwupaqr 0 300 train
+nletzyperq 0 300 train
+nlfgmfttno 1 300 val
+nlfhfkckjj 0 300 train
+nlflhzbnwx 1 300 train
+nlfmhobpni 1 299 train
+nlfqpyfjbl 1 300 train
+nlfunzrrts 1 300 train
+nlfwahkgfw 1 300 val
+nlgccbseha 1 300 val
+nlgencrtas 1 300 val
+nlgfjhnxse 1 241 train
+nlgklygytj 0 300 train
+nlgocixjwn 1 300 train
+nlgvjjjkch 1 300 train
+nlgwdsbjti 0 300 train
+nlgzdkbpud 1 300 train
+nlhcwuxjxj 1 300 train
+nlhgdyqmpt 1 300 val
+nlhvhuwujo 1 300 train
+nlhxuxnjhr 1 300 train
+nliawulyhm 0 300 val
+nlidzcnuue 1 300 train
+nlifrbprrj 1 300 train
+nlinyollix 1 301 val
+nliofvksed 0 300 train
+nlirlqqijp 1 241 train
+nlirmxvjjs 1 241 train
+nlixkyvunj 0 300 train
+nljhfekcxb 1 300 train
+nlkhocvisb 1 300 train
+nlkkkowtag 1 300 train
+nlkniiykwh 0 300 train
+nlknuljczo 1 300 val
+nlkpdwyydv 1 300 train
+nlkrzhshmd 1 297 val
+nlktemafjx 0 300 train
+nlkzdppkvb 1 300 train
+nllayzgfof 1 301 train
+nllbwuenuk 1 300 train
+nllkhjmsed 0 300 val
+nllnjrcpgt 1 300 train
+nllujkwkye 0 300 train
+nllvvuifoj 0 300 train
+nlmhzevtqy 1 300 train
+nlmljpbvis 1 300 train
+nlmyjrweod 1 300 train
+nlnahjavoc 1 300 train
+nlnawavdzb 1 300 train
+nlnlmphrry 1 300 train
+nlntwnqrzj 1 300 test
+nlnwdndxgd 1 300 train
+nlnydoghdv 1 300 train
+nlnziakqhq 1 300 train
+nlocqqoppk 1 300 train
+nlodeoxwxa 1 300 train
+nlohjjpjxq 1 300 train
+nlonlegrdk 1 300 val
+nlootffhhf 1 299 val
+nlooxatorh 1 300 val
+nlooyiqxcw 1 300 train
+nlortejvvc 1 300 val
+nloyfmwjwm 1 300 train
+nlpgclbklx 1 300 train
+nlpgqvxsna 1 300 train
+nlpuzhuxst 1 300 val
+nlpvkvxgma 0 300 train
+nlqaucnttx 1 300 train
+nlqjezgbtl 1 299 train
+nlqvmczxbz 1 300 train
+nlqvzzuvbn 1 300 train
+nlqyedaokg 0 300 train
+nlqyfjiwna 0 300 train
+nlqzjxdhas 1 300 train
+nlrberithx 1 301 train
+nlrjefgrov 1 300 train
+nlrjrefadt 1 296 train
+nlrlewifkr 1 300 train
+nlrmblqcks 1 300 val
+nlrmgdqfnr 0 300 train
+nlrmvmkoux 1 241 train
+nlrpzibfxi 1 300 val
+nlrstzykho 0 300 train
+nlsfrzugtz 1 300 val
+nlsmkijbka 1 300 val
+nlsnfgxits 1 300 train
+nlsqkoisdk 0 301 train
+nlsteigwzm 1 300 val
+nlsxhahnsr 1 299 test
+nlsxqhkbsr 1 301 train
+nltevgeqah 1 300 train
+nlthgstqvc 1 300 val
+nlthwueuzl 1 300 train
+nltihqekcg 1 300 val
+nltnhsdkqf 1 300 val
+nluktmdgip 1 300 train
+nluleubpho 1 300 train
+nlumvlqios 1 300 train
+nlurbvsozt 1 300 test
+nlusjtqfxy 1 297 train
+nluwruwldi 1 300 train
+nlvafvpwgu 1 300 train
+nlvahugotq 1 300 train
+nlvazcizhw 1 300 train
+nlvesutbkx 1 240 train
+nlvvgrinhn 1 300 train
+nlvwdttcgh 1 300 val
+nlvybmxxcx 1 300 train
+nlwcyplofa 1 300 train
+nlwlfpixly 1 300 train
+nlwppcfipz 1 301 train
+nlwqnujbjo 1 300 train
+nlwzsymrlr 1 300 val
+nlxhqoxrgl 1 300 train
+nlxjamaxhb 1 300 train
+nlxlxqlomt 1 300 train
+nlxqjepvrj 1 300 train
+nlxxxhkrjf 1 301 train
+nlxyfrchud 1 300 train
+nlycdjsntx 1 298 val
+nlyckygjxj 1 299 val
+nlymxfaevd 1 300 train
+nlyudjboxs 1 300 val
+nlzfavdtdz 1 300 val
+nlzgtcyhau 1 300 val
+nlzhplggol 1 300 train
+nlzifcedph 1 300 train
+nlzirbtmqm 0 300 train
+nlzkjejoum 1 300 train
+nlzravyzgo 1 300 train
+nmaajbnbwv 1 300 train
+nmabouezyc 1 300 val
+nmaitpztva 1 300 train
+nmaiwkihuo 1 300 train
+nmarhxamlz 1 269 train
+nmasawegxx 1 300 train
+nmazatkxyp 1 300 train
+nmbaoehwbw 1 300 train
+nmbevgcuec 1 300 train
+nmbhfywdbj 1 300 train
+nmbrhonhae 1 298 train
+nmbtiqerxz 1 298 train
+nmbvilqkig 1 300 val
+nmbwjguczt 1 300 train
+nmbywogdbw 1 300 train
+nmbznvrnkf 0 300 train
+nmccwdncxm 1 299 val
+nmcdroqhae 1 301 train
+nmcmwhaiyr 1 301 train
+nmcopoqyxm 1 99 train
+nmdbawqgbz 1 300 train
+nmdbuoxgmy 1 300 train
+nmdbwbkzhm 1 300 train
+nmdfzasfsy 1 300 train
+nmdhbdjocb 1 296 val
+nmdibzykwl 1 300 train
+nmdkoichxj 0 300 train
+nmdksnzkqd 1 300 train
+nmdmfmqztf 0 300 train
+nmdmonwiyc 1 300 train
+nmdouylnnc 1 241 train
+nmdpkvbxbc 1 300 train
+nmdvrzfbjy 1 300 train
+nmdzujhjid 0 300 val
+nmeaureick 1 298 train
+nmeezsxfif 0 300 train
+nmeiiyedyw 1 300 val
+nmeotngklv 1 300 train
+nmesqtaegv 1 300 val
+nmexlfuxsf 0 300 train
+nmexuorkfo 0 300 train
+nmezpugyci 1 300 train
+nmfdffzfjm 1 300 train
+nmfhwrsvdj 1 300 train
+nmfjzzgsyj 1 300 train
+nmfklzabbb 1 300 train
+nmfnpezxfg 1 302 train
+nmfubsjexi 1 269 train
+nmfvfatngw 1 300 val
+nmfxzmrdko 1 300 train
+nmfymytwam 1 300 train
+nmgezmdtlw 1 300 train
+nmggzyzkiz 1 300 train
+nmghbwwliq 1 300 train
+nmgnxptofk 1 300 train
+nmgrbmmzjy 1 300 val
+nmhcnvinzr 0 300 train
+nmhgmueqie 1 300 val
+nmhkvqyayy 1 300 train
+nmhuoljhzl 1 240 train
+nmicidrvps 1 300 train
+nmijvcsgar 1 300 train
+nmisncmqul 1 300 train
+nmivzfstyq 1 298 train
+nmjaxebwee 1 300 val
+nmjesbwiux 0 300 train
+nmjlqtwyta 0 301 train
+nmjrbfvzkt 0 301 val
+nmjsuiwpcz 1 299 val
+nmjsymvggu 0 300 train
+nmjxwyqgbn 1 300 train
+nmkajlvfli 1 300 train
+nmkcfzadnw 1 300 train
+nmkdfyleld 0 300 train
+nmkkpgffnc 1 301 train
+nmkvlryswx 0 300 train
+nmkxdhmwaq 1 300 train
+nmkzwoiwlk 0 298 train
+nmlgdcchon 0 300 train
+nmlkxzmehs 1 300 train
+nmlovqouaz 0 300 train
+nmlsjeasad 1 300 train
+nmlsxlffao 1 300 train
+nmlyosefdp 1 298 train
+nmmaatxnkc 1 300 train
+nmmabrormj 1 241 train
+nmmbrlhdey 1 301 val
+nmmfwycsov 1 300 train
+nmmhhlggfy 1 300 train
+nmmizonqhs 1 300 test
+nmmllacamk 1 300 train
+nmmmkmpdfl 1 299 train
+nmmtfrgyjo 1 300 train
+nmmxllgsqq 1 300 val
+nmmzvnlgek 0 300 train
+nmnfngdscc 0 300 train
+nmnlknzyet 1 300 train
+nmnlsarsto 1 300 train
+nmnmuxwexe 1 300 train
+nmnvztcbtv 0 300 val
+nmnxbayyvt 1 300 train
+nmobfoivkk 1 300 train
+nmobsppfaa 1 300 train
+nmoclaubes 0 300 train
+nmoejsbfhm 0 300 train
+nmokhyzpem 1 300 train
+nmoriwezhz 1 300 val
+nmoxwutfpd 1 300 train
+nmoyfozzsz 1 300 train
+nmozxlrkls 1 299 test
+nmpfcqcjby 1 300 train
+nmpgdfpajk 1 299 train
+nmphdbflzj 0 300 train
+nmphmnmsbe 1 300 train
+nmpxkbdztl 1 300 val
+nmqnkwxwhi 0 300 train
+nmqvhfyrky 1 300 val
+nmqwhnlkux 1 300 train
+nmqwohtfle 1 300 train
+nmqxfuysue 1 301 val
+nmrdabsqem 1 300 val
+nmrfqmhabc 0 300 train
+nmrfwkhcar 1 300 train
+nmrnwusggp 1 300 train
+nmryglrlxk 1 300 train
+nmsjgzamxp 1 300 train
+nmtbqblekl 1 300 train
+nmtersqlqa 1 301 val
+nmtrhomiip 0 300 train
+nmuapzdbda 1 300 train
+nmubvzvakr 0 300 val
+nmucgeimdv 1 300 train
+nmueyvtkrw 1 241 train
+nmufqvtyds 1 300 train
+nmujsijdwt 1 300 train
+nmupmlzmld 1 300 train
+nmupwhyxen 1 300 train
+nmupzhpgns 0 300 train
+nmusnzzzqu 1 298 train
+nmusooihlb 0 300 val
+nmvjhqdpdy 1 300 val
+nmvritrdvq 0 300 train
+nmvujwport 1 300 val
+nmwledkggh 1 301 train
+nmwlejikul 1 300 train
+nmwpnbliet 1 300 train
+nmwreojynt 1 300 train
+nmwrlssrlr 1 300 train
+nmxhxhkhxj 0 300 train
+nmxogwisml 1 300 train
+nmxwnxdirg 1 300 train
+nmxzjhnuap 1 301 train
+nmycoyoyxr 1 300 train
+nmyemiebip 1 300 train
+nmyermsnhi 1 300 train
+nmyfrxeqko 1 300 train
+nmyhzwggkh 1 300 train
+nmyluwvvew 1 298 train
+nmyrpwrowm 1 300 val
+nmytuerpev 1 298 train
+nmyvarypvj 1 300 train
+nmyxbozphu 1 301 train
+nmzogypaew 1 300 train
+nmzpxxakaa 1 300 train
+nmztuqrxky 1 300 train
+nmztvulquu 1 300 train
+nmzwkanjaq 1 299 train
+nmzzjillhc 1 301 train
+nmzzvpawgg 1 300 val
+nmzzzlgayc 1 300 test
+nnadmydirf 1 300 train
+nnaetodvny 1 300 train
+nnamqkfxas 1 301 train
+nnamukhwmc 1 300 val
+nnblcynzqp 1 300 val
+nnbmqkbmhp 1 300 train
+nnbswijihq 1 300 train
+nnbxxozqge 1 300 train
+nnccthpiws 1 300 val
+nncdxgzrcf 1 300 train
+nncfuuyncs 1 300 train
+nnchfswufs 1 300 test
+nnckfqzdlh 1 300 train
+nncmhbrfsl 1 147 train
+nnctqxheey 1 300 train
+nncuwjiczj 1 300 val
+nnddpcgvce 1 300 train
+nndemqhngx 1 300 train
+nndhvkpctq 1 300 train
+nndoszzxru 1 300 val
+nndsymayxt 1 297 val
+nndtplomqk 1 241 train
+nnebxpadgc 0 300 train
+nnehwerxtk 0 300 train
+nnepapvrlv 1 300 val
+nnepbflpxd 1 300 train
+nneqtkmzli 1 300 train
+nneshdsxzg 0 300 train
+nnfgkpbpgy 0 301 val
+nnfjipbviz 1 288 train
+nnfneewhmg 1 300 train
+nnfroudcan 1 300 train
+nnfsouknps 1 300 train
+nnfukmdgvw 1 300 train
+nnfwfojmri 0 300 val
+nnfwiqhoyn 1 300 train
+nngajjgbsn 1 300 val
+nngbkahvah 1 241 train
+nnglisilhj 1 300 train
+nngphqdnot 1 300 train
+nngspjuznz 1 300 train
+nngtsajuzl 1 239 train
+nngvktxaza 0 300 train
+nnhgfalqfr 0 301 train
+nnhjeyfroh 0 300 train
+nnhlbghvii 1 300 train
+nnhrltxles 1 300 train
+nnhxczhyjk 1 300 train
+nniasjivsj 1 301 train
+nnibamvzjl 0 300 train
+nnicbqmtug 1 300 train
+nnicujerkl 1 298 val
+nnidrukacg 1 301 val
+nnifcnwpnc 1 300 train
+nnikfxjakt 1 301 train
+nnipuwwehv 1 300 train
+nnitajlwru 1 300 train
+nniurlhwwy 1 300 train
+nnjdyqcklv 1 301 train
+nnjhfldeep 1 300 train
+nnjmbcmolg 0 300 train
+nnjnjgfric 1 301 train
+nnjpeveevx 1 300 train
+nnjpfzusji 0 300 train
+nnjqtvqdvl 1 300 train
+nnkchsorlr 1 300 val
+nnkrrtnnzc 1 300 val
+nnkvgtmecd 1 300 test
+nnkymdgsrg 1 300 val
+nnlabrcwqb 1 301 val
+nnlsyaqkof 1 300 train
+nnmdczieqv 1 300 train
+nnmeojwfld 1 255 train
+nnmhsibqml 1 301 train
+nnmintyqzp 1 300 val
+nnnepedcir 1 300 val
+nnnfaivpcm 0 300 train
+nnnfgwzbru 0 301 train
+nnnhvsiezg 1 301 train
+nnnjvnjqtv 1 300 train
+nnnkkjlkwr 1 300 train
+nnnluqzfhr 0 300 train
+nnnngxbgbq 1 300 train
+nnnnztpjzy 1 300 train
+nnnvtrkvow 1 300 train
+nnnyyjdstl 1 300 val
+nnoewbrfdn 0 300 train
+nnohgquveh 1 300 train
+nnoljmakba 1 300 train
+nnonokkuhv 1 300 train
+nnorradrqm 1 300 train
+nnpdsowuhz 1 300 train
+nnpiyeaqpp 1 300 train
+nnpmvozcmf 1 300 val
+nnpnaukqlp 1 300 train
+nnpolboyog 1 241 train
+nnpuaismqx 1 300 train
+nnpulqoqtr 1 300 val
+nnpxjpjdwl 1 300 train
+nnqcyporze 1 300 val
+nnqfwqrcov 0 300 val
+nnqhvhwrvm 1 300 val
+nnqlasuoqh 1 300 train
+nnqmiccqjl 1 300 val
+nnqpqbnmol 1 300 train
+nnqrpygvif 1 300 train
+nnqvdssiam 1 300 train
+nnrdysxryo 1 300 train
+nnregnyxcq 1 300 train
+nnrfmhqxcy 1 301 train
+nnrndpakpn 0 241 train
+nnrntxpckq 1 300 train
+nnrykhgzgs 1 300 train
+nnsarxezod 1 299 train
+nnsesoohxm 1 300 test
+nnsfldzzry 1 300 train
+nnshsdsefa 1 300 train
+nnsjsdiprc 1 300 train
+nnsviegopy 1 300 train
+nnsxspouof 1 300 val
+nntacyokiy 1 300 train
+nntoakjlik 1 300 train
+nntxawutik 1 301 train
+nnuarswldu 1 300 val
+nnuiegiysb 1 300 train
+nnupbyeyox 1 300 train
+nnuwlchsxj 0 300 train
+nnuyijzlju 1 300 train
+nnuytuhcfc 0 300 train
+nnvbkgvsli 1 299 test
+nnvddjuzym 0 300 train
+nnvguviyuk 1 300 val
+nnvpxpyhta 1 300 train
+nnvyreexca 1 300 train
+nnvzfahmxq 1 301 train
+nnwhdgobod 1 300 train
+nnwkycvpir 0 300 train
+nnwmmpgdsp 1 300 val
+nnwrcrvpaa 1 300 val
+nnwrkbtdgh 1 298 train
+nnwyarwyip 1 300 train
+nnwyjeeoiw 1 300 train
+nnwyxcciub 1 300 train
+nnxeqwxjev 0 300 train
+nnxhpanpel 1 301 train
+nnxkvtdqrd 1 300 train
+nnxohuibvx 1 300 val
+nnydvpvips 1 300 train
+nnygcxtetl 1 300 train
+nnyqrcuxxz 1 300 train
+nnyrwiffmv 1 301 val
+nnywpsbxbi 1 241 train
+nnyyrrfscc 1 300 val
+nnzekxbqwe 1 301 train
+nnzewiglox 1 300 train
+nnzhqibote 1 300 train
+nnzqouukoj 1 300 train
+nnztzqdnmx 1 300 val
+nnzvjykscy 1 300 train
+nnzxldrkri 1 300 train
+noagmcpxfb 1 300 train
+noaidzswrw 1 300 train
+noakirsksp 1 298 val
+noaotlbcgf 1 300 train
+noasfunvwq 1 300 train
+noaulghwun 1 300 train
+noavesktql 1 300 test
+noaziqxtib 1 300 train
+nobrvdftmd 1 300 train
+nobtuwxcqf 1 300 val
+nobvmsqzlc 1 300 train
+nobywyclyy 1 300 train
+nocdjmbcxn 1 300 train
+nochzluwyp 1 300 train
+nocritjjhk 1 300 train
+nocuhkkvqz 1 300 train
+nocwpqyubc 1 299 test
+nocxgtwswm 1 300 train
+nodblgoqxu 1 300 train
+nodhgebrya 1 300 train
+noeaapdfzt 1 300 train
+noenwkskzp 1 301 val
+noerwsussl 1 300 train
+noewghxtnb 1 299 val
+nofbccsqkn 1 301 val
+nofbozkher 1 301 val
+nofeuceuea 0 300 train
+nofexdvatp 1 300 train
+nofipjebdq 1 300 train
+nofjocnhoy 1 300 train
+nofmjiduph 0 300 train
+nofpccqmiy 1 300 train
+nofpptlanp 1 300 train
+nofqcwbhmc 1 300 train
+nofybcorda 1 297 train
+nofyjiivre 0 300 train
+nogfnwjwwd 1 300 train
+nogfpilfjg 1 300 train
+nogftawsny 1 300 train
+nogfxrnhgf 1 300 val
+nogfydfpcg 1 300 train
+noghkwghyx 1 300 train
+noglozytaq 1 300 train
+nogqagafls 1 300 train
+nogrooslre 1 300 train
+nogxisbqcq 0 300 train
+nogxmbvoic 1 300 train
+nohkcwutuv 1 300 val
+nohkximasq 1 300 val
+nohleduxvk 0 298 train
+nohvjixdca 1 300 train
+nohvqxcxzl 1 300 train
+noicltfhyg 1 301 train
+noicuhrszm 1 300 val
+noigwncefk 1 300 train
+noikrimmmm 1 300 train
+noimhehxij 1 300 train
+noiojkacja 1 300 train
+noiorsbnni 1 300 train
+noirumgwxx 1 298 train
+noisbvumhr 1 300 val
+noiseliqqu 1 300 train
+noisidrypu 1 300 train
+noitrwvpuf 1 300 train
+noivkhdmqh 1 300 train
+noiyxtqstj 1 299 train
+nojcvxhksp 1 300 train
+nojdkjbkzp 1 300 train
+nojgizgrbw 0 241 train
+nojgvywlnn 1 300 val
+nojjqdxckm 1 300 train
+nojywmvorp 1 300 train
+nokldtllhe 1 300 test
+nokwmkrlov 1 300 train
+nokytrqdho 1 301 train
+nolbuzhjim 1 300 train
+noljdyeghv 1 300 test
+nolmsgsvxh 1 300 train
+nolwrjekvl 1 300 val
+nomadqoezc 1 298 train
+nombfkmhum 1 300 test
+nomcjmusaf 0 300 train
+nomcobcetp 1 300 train
+nomejbyfhl 1 300 train
+nomhiwvfvj 1 300 val
+nomkqqfjml 1 300 train
+nomnlcessa 1 300 train
+nomplycice 1 300 train
+nonexycyia 1 299 val
+nonthincke 1 300 train
+nonubiiklc 0 300 train
+nonwqkyict 0 300 train
+nonzkllsaw 1 300 val
+nonzoemsfd 0 302 train
+nonzsfeouu 0 300 val
+nookkyodde 1 300 train
+noolwotbdh 1 300 train
+noonwrxiwg 0 300 train
+noorpkozxl 1 299 val
+nooyedqmxp 0 300 train
+noozhkzkru 0 300 train
+nooziurtor 1 288 train
+nopfkczwsv 1 300 train
+nopfvlisch 1 300 train
+nopjjvwwrg 0 298 train
+nopszqsspf 1 300 train
+nopvkzzcqp 1 301 val
+nopvoumfhr 1 296 train
+noqgfzallu 1 300 train
+noqpthzgxo 1 300 val
+noqtlqcipx 1 300 train
+noqyfwpqii 1 300 train
+noraklfhax 0 300 train
+norbabdxvt 0 300 train
+norbqwdyxt 1 300 train
+norlaobivm 1 300 train
+norltdnjez 0 300 train
+norszaredh 1 300 train
+norxttisyg 1 300 val
+noslowakso 0 300 val
+nosshgxzii 1 301 train
+nosskvpsal 1 300 train
+notcrobkvh 1 300 val
+notdbkrzwi 1 300 train
+notdfnubxa 1 300 train
+notesdzqcd 1 300 train
+notmhaxgxz 1 300 train
+notprrantw 1 300 train
+notsqhoqzn 1 300 val
+notviccbkr 1 300 val
+notzhvnjcw 1 297 train
+nouaxqrvlp 1 300 train
+noufeolxrs 1 300 val
+noujstxfgm 1 300 train
+nousxdidaq 1 300 train
+nousyfacxi 1 300 train
+nouwxoeiiq 1 300 train
+nouyhrlkiw 1 300 val
+novarhxpbj 0 300 test
+novgixysji 1 300 train
+novnncrpgw 0 300 train
+novrnyseyt 1 300 train
+novxeacjde 0 299 train
+novyrpxign 1 100 train
+nowhicwoms 1 300 train
+nowiaznocl 1 300 train
+nowjdzuevg 0 300 train
+nowuwozmws 1 167 train
+nowwwwnmyb 0 300 train
+noxbjnidkp 1 300 train
+noxjzomiym 1 300 train
+noxlelyrnq 1 300 train
+noxpzvacis 1 300 train
+noxrxayyox 1 301 train
+noxsuggkxv 1 300 train
+noxwquvsxd 1 300 train
+noxxoluzqz 1 300 train
+noxyhlxczd 1 300 train
+noyefhqexa 1 300 train
+noygqvlquo 1 300 train
+noynlqeman 1 241 train
+noyomrfcgp 1 300 train
+noyszfsbov 0 300 train
+nozcnwhwmr 1 300 train
+nozjtdprgf 1 300 train
+npaabhuyuq 0 300 train
+npaezmaduh 1 301 val
+npajtovoyr 0 300 train
+npajzcjzfd 1 300 train
+npalnvsaaj 0 300 train
+npanmfkrfv 1 300 train
+npatrimkki 1 300 train
+npaumcpfsj 1 300 train
+npauszswwt 1 300 val
+npaweyaged 0 298 train
+npawfhyprv 1 296 train
+npayobbfjy 1 300 train
+npbaspnwax 1 300 train
+npbcodcrvo 1 300 train
+npbdjjgfbh 1 300 train
+npbhjusgbm 1 300 val
+npbreznxbl 1 300 train
+npbruzyguz 1 300 train
+npbwrejgeu 1 300 val
+npbymrlgis 0 300 train
+npcgoabzds 1 300 train
+npcpszfmpy 1 300 train
+npcqxjndip 0 300 train
+npcsgvejxh 1 301 train
+npcstodmwq 1 300 train
+npcwajsurh 1 299 val
+npcxioucdl 1 300 train
+npddnhfhoo 1 300 train
+npddtibfem 1 300 train
+npdegwqexz 1 300 train
+npdepbgwiv 1 301 train
+npdhyvzkkl 0 300 train
+npdmxyudhi 1 299 val
+npdnxmhnpy 1 298 train
+npdomfybya 1 301 train
+npdtwialqk 1 300 train
+npdxidgpgz 1 300 train
+npdycydgac 1 300 train
+npebbtzpno 0 300 train
+npeexozwbr 1 300 train
+npefamzdlg 1 300 train
+npegmofvkg 1 300 train
+npemjjupmd 1 300 train
+npenlyxzfv 1 300 train
+npeqjyptma 1 300 train
+npermerlix 0 300 train
+nperofhujp 1 300 train
+npfaklyxop 1 300 train
+npffculfnf 1 299 val
+npfftxegxs 1 300 train
+npfibhksla 1 300 val
+npfkhytdww 1 300 train
+npflsvxwlw 0 301 train
+npfrkyjhme 1 300 train
+npfuofxucz 0 300 train
+npfzyudomm 0 300 train
+npghatigbw 1 300 train
+npgikxkcfk 1 300 train
+npgkgevhhw 0 301 train
+npgllqlrrf 1 300 train
+npglsjpygr 1 300 train
+npgorxeeyh 1 300 train
+npgqvhwoys 1 301 train
+nphbdipfce 1 300 train
+nphejbnvqh 1 298 train
+nphjnyqcor 1 302 train
+nphtrwjtff 1 300 test
+nphuxjfxfk 1 301 train
+npifevtuca 1 300 val
+npigvzszfi 1 300 train
+npimmxjudc 1 300 val
+npiptahdld 1 300 val
+npiqvirqkh 0 300 train
+npirajbeag 1 300 train
+npjemrwacb 0 301 train
+npjidwfvyi 1 300 train
+npjmcqwimm 1 290 train
+npjmiuyfmh 1 300 train
+npjtgmzhwb 0 301 train
+npjuanylkr 1 300 train
+npjwiaxcjd 1 300 test
+npkbsxelmj 1 301 val
+npkkjtbxeo 1 300 train
+npkoiwiska 1 300 train
+npkrchlint 0 300 train
+npkyzxgmzj 1 301 train
+npljawkozq 1 298 train
+nplsybhpqe 0 300 train
+nplvbcaujj 1 300 train
+nplviymzlg 1 299 test
+nplwscliza 1 300 test
+nplxrbjtbn 1 300 train
+nplxuhhlom 1 300 train
+npmpoiuoxh 1 298 val
+npmqxikhgm 1 300 train
+npmtpszgzs 1 300 train
+npmvipqgsl 1 300 train
+npmvwnakvt 1 300 train
+npnbnpbbim 1 300 train
+npnctwcxyw 1 300 val
+npndbkmdei 1 300 val
+npneqyjgiq 1 300 test
+npnkwyfkxe 1 298 train
+npnllumbmi 1 300 train
+npnmstkfsz 1 300 val
+npnovsqqso 1 300 train
+npnrvehlil 1 300 train
+npntekdlue 1 300 val
+npnvuadawx 1 300 train
+npnxkpscbe 1 292 val
+npnxvnozcs 1 300 train
+npoairoicb 1 300 train
+npobpzkdui 1 300 train
+npocfcwmge 1 300 train
+npodmhsumc 1 299 val
+npofldlttc 1 300 test
+npogxbtxwg 1 300 train
+npophxnrpo 1 300 train
+npotcizfal 1 300 test
+npovcpwcsg 0 300 train
+npowjyfbiv 0 300 train
+npozaxogbe 1 300 train
+nppczasfbk 1 300 train
+nppfxvdjmm 1 300 val
+nppgqtucxy 1 300 train
+nppgzesgvl 0 300 val
+npphoktpnv 1 300 train
+nppmmwitha 0 300 train
+npppxzljbd 1 300 train
+nppxhesbth 1 300 train
+nppykegcai 1 300 train
+npqbrnaxsb 1 300 val
+npqfnxhfbu 1 300 train
+npqipwrwon 0 300 train
+npqopmpguh 1 300 test
+npquayfbbk 1 300 train
+npqybkqysx 1 301 train
+nprmrjciyy 1 299 train
+nprpelwrtc 0 240 train
+nprqsxxjae 1 300 train
+nprwfvvqur 1 300 train
+npsezjulqs 1 299 val
+npsiyllsvw 1 300 train
+npslfbkkns 1 300 train
+npsnpdjcux 0 300 train
+npsotexafg 1 300 test
+npsqplujhy 1 301 train
+npsvcdiywt 1 301 train
+npthgupiqh 1 300 val
+nptmqvfuhz 1 300 train
+nptnlxtqtn 1 300 val
+nptxjldsws 1 300 train
+npufdsziqr 1 300 train
+npufvmzddi 0 300 val
+npugmsmqig 1 300 train
+npummsmkbt 1 300 train
+npuplviqjf 1 300 train
+npuqwhbzut 1 300 train
+npuritzfat 0 300 train
+npuvpugdkv 1 300 train
+npuvrhsnoe 1 300 train
+npvgcxmpdt 1 300 train
+npvhjcjgdp 0 300 train
+npvitjmjhx 1 300 train
+npvwsnmpqt 0 300 train
+npvzfusefv 1 300 train
+npwanvonrz 1 300 train
+npwdbikzjb 1 300 train
+npwefnyvwf 1 300 train
+npwekyspjo 1 298 train
+npwierprus 1 300 test
+npxafzweti 1 300 train
+npxazykbwf 0 300 train
+npxervphco 0 300 train
+npxgjslmxz 1 298 train
+npxhjrnjyb 1 300 train
+npxhlyymml 0 300 train
+npxjgwchlb 0 300 train
+npxmmfyekt 1 300 val
+npxnwwuvqh 1 300 train
+npxtahzueo 0 300 train
+npxvnxidfa 1 300 train
+npxvuqfaho 1 300 train
+npyprpqhlv 1 300 test
+npyvfrhxjn 1 301 train
+npyvifjggf 1 300 train
+npyxxaavjj 1 300 train
+npzidjrmup 0 300 train
+npzjkinuox 1 298 val
+npzklokfgz 1 300 train
+npzsekxhjd 1 300 train
+npzvxvhjuy 1 300 val
+npzzblguof 1 241 train
+nqabjvkxuf 1 300 val
+nqacwklhjp 1 300 train
+nqadwwnfcj 1 241 train
+nqaizaygys 1 300 train
+nqajzftvwb 1 300 train
+nqastlnxgw 1 300 train
+nqawqewtnu 1 300 train
+nqbdsybiil 0 301 val
+nqbnwrsftl 1 300 train
+nqbogdnxbl 1 300 train
+nqbyjxbvwm 1 300 train
+nqcammjhwz 1 300 train
+nqcpqgracq 1 298 train
+nqctdktbtb 0 300 train
+nqdaltgxlr 1 300 train
+nqdddxgokr 1 300 train
+nqddjmmxxp 0 298 train
+nqdrmgawce 1 300 train
+nqdrtuzafi 0 300 train
+nqdvhwmmmo 1 300 train
+nqdvvzopgs 1 299 test
+nqdzlvvdkp 0 300 train
+nqegtvqlkq 0 300 val
+nqemjsuswh 1 300 train
+nqenaokyna 1 300 val
+nqeqziwdiy 1 300 train
+nqesppbjpt 1 300 val
+nqeuzfqjif 1 300 train
+nqfpecqeab 1 300 test
+nqfrylhttr 1 300 train
+nqftlqigri 1 300 train
+nqgdjwblvh 1 300 train
+nqgpauxxco 1 298 train
+nqgxolmpgm 1 299 test
+nqgzmlhrur 1 300 train
+nqhjzzacte 1 300 val
+nqhkqsrobr 1 300 train
+nqibajftlx 1 300 train
+nqibmvlhsu 0 300 train
+nqieqdnwjf 1 300 train
+nqiopzupqx 1 300 train
+nqipcparmx 1 300 train
+nqisiswprn 1 300 train
+nqislhrreb 0 300 val
+nqismrrwiz 1 300 train
+nqiumhtswt 1 300 train
+nqiyvgwqbn 1 240 train
+nqjffgwbes 1 300 train
+nqjkibmsoz 1 300 train
+nqjnrvypxs 0 301 train
+nqjrsrnvhh 1 300 val
+nqjzedheda 0 300 val
+nqkboitiaz 1 300 train
+nqkcqxpjpd 1 300 val
+nqklsooiik 1 300 train
+nqktroeqqr 1 300 train
+nqllygcmou 1 300 train
+nqlxvtyjjs 1 300 train
+nqlybpayjm 1 300 train
+nqmadycdkw 1 300 train
+nqmcicguio 1 300 train
+nqmeunktvn 0 300 val
+nqmkdnlkiq 1 300 train
+nqmlbhdwio 1 301 val
+nqmvwotvsv 1 300 val
+nqmwdcpncj 1 300 val
+nqmyaryapl 1 300 val
+nqmzfbqere 1 298 train
+nqnauflarj 1 298 val
+nqncwnadry 1 300 train
+nqneldjejy 0 300 train
+nqnhkzezvj 0 300 train
+nqnixifbgj 1 300 train
+nqnnsoisyr 1 298 train
+nqnriuihjr 1 301 train
+nqnrqjxxpp 1 300 val
+nqnwznpmgr 1 300 val
+nqobranitv 1 300 train
+nqokwmcjde 1 300 train
+nqomytaewp 1 301 train
+nqoojvyaiy 1 300 val
+nqotnalbul 1 300 train
+nqotvzfcck 1 300 train
+nqoygqqyby 1 300 val
+nqpclnatsm 1 300 train
+nqpfeyuupo 0 300 train
+nqpheccrju 1 300 train
+nqplvlygic 1 300 train
+nqpovpvwig 1 241 train
+nqptouihyw 0 300 train
+nqpwfcajug 1 300 train
+nqpxmavjit 1 300 train
+nqpzeijwru 1 300 train
+nqqdryjhrt 1 300 train
+nqqmevnerb 1 300 train
+nqqojagqeg 1 300 train
+nqqomjbdyl 0 300 train
+nqqqalqzaj 1 300 train
+nqqrqoodbv 1 300 train
+nqqrxhcpdt 1 300 train
+nqqvfypiqo 1 300 train
+nqqzvxjysy 1 300 val
+nqramwlnae 1 300 train
+nqrcttpsme 1 300 test
+nqrmezvxnm 0 300 train
+nqrqwswgnl 1 300 val
+nqryzqvokp 1 300 train
+nqsszwjnvf 1 241 train
+nqswtubptv 1 300 train
+nqszeemevi 1 300 train
+nqtlzuwvqt 0 300 train
+nqtnjisjmh 1 300 train
+nqtnlgswmi 0 300 train
+nqtqafxori 1 300 train
+nqtujgqoid 1 300 train
+nqtvthaakr 1 300 train
+nqtwxxgixv 1 300 train
+nqtymxrgnp 1 300 train
+nqucugalmj 0 300 train
+nqudmlqlyn 1 298 train
+nqueglyico 1 300 train
+nqujtoigfk 1 300 train
+nqvbdzixhe 0 300 train
+nqvjczrebz 1 300 train
+nqvkiylfiy 0 300 val
+nqvpzgelrm 1 249 train
+nqvuifyskg 1 300 train
+nqvzbdcdbi 0 300 train
+nqvzprxpjq 1 300 train
+nqvzweblqk 1 300 train
+nqwckyaaph 1 300 train
+nqwegbjqjz 1 300 train
+nqwkmhbiuu 0 302 val
+nqwnbnxaoq 1 300 train
+nqwypfxyas 1 300 train
+nqxbkwbekr 0 300 train
+nqxiouvxjw 1 292 train
+nqxkmokygc 0 300 val
+nqxmyhuacv 1 300 train
+nqxpnabgys 1 300 train
+nqxqpvjykl 1 298 train
+nqxuzmcqol 1 300 train
+nqxxmrpjof 1 300 train
+nqxzpyqksq 1 300 train
+nqykysrhnu 1 241 train
+nqynuhnklk 0 300 train
+nqyqkfrjhz 1 301 train
+nqzambflwv 1 300 train
+nqzemwpwff 0 300 train
+nqziprqjec 1 300 train
+nqzljemaoo 1 300 train
+nqznacause 1 301 train
+nqzoedoidj 1 301 train
+nqzpvwyeni 1 167 train
+nraafmfpda 1 300 train
+nraagkrxjq 1 300 train
+nraebdlbpb 1 300 train
+nrafokigjf 1 300 train
+nraghgolqd 1 241 train
+nrahftzzny 1 300 val
+nrahlhmrbk 1 300 train
+nralzvqicb 0 300 val
+nrapipcizp 1 300 train
+nraqgmsnmm 1 300 test
+nrawmjiyav 0 300 val
+nraxrkbbdy 1 300 train
+nrbdmqvuzu 1 300 val
+nrbkfamzur 1 300 val
+nrbnmstyvx 1 300 train
+nrboackadj 1 300 val
+nrbupxwucw 1 300 train
+nrbwzpkatu 0 300 val
+nrbzfxrzun 1 300 train
+nrcikcukhf 1 300 test
+nrcikwtfjf 1 300 train
+nrcmbtjkrl 1 300 val
+nrdanxfibd 1 300 train
+nrdcltovnr 1 300 train
+nrdnytturz 1 300 test
+nrdrtmlxqp 0 300 train
+nrdvcqxlnx 1 300 val
+nrdvdjropz 1 300 train
+nrdvmhqenf 1 300 train
+nreccqwijb 1 300 train
+nrecykduyh 1 300 train
+nredxtlvxr 1 300 val
+nreekohhwx 1 300 train
+nreerhgakh 1 300 val
+nrejfcjyvn 1 300 train
+nrejgewmad 1 300 test
+nrekjzntec 1 239 train
+nrensguenu 0 300 train
+nreowcfxki 1 300 train
+nrepjxqgqn 1 301 train
+nrerltbafi 0 300 val
+nrevjmoolb 1 300 val
+nrfcalwqnp 1 300 train
+nrfcufckxa 1 299 test
+nrfkbfxsco 1 300 train
+nrfmboprlj 1 300 train
+nrfmehosle 0 300 train
+nrfvlzgtge 1 301 train
+nrfwrjlnfz 0 300 train
+nrgaopwdhi 1 300 train
+nrgdvuqltf 1 300 train
+nrghvutnse 1 300 val
+nrgkltaqrm 1 300 train
+nrgkxkkvhu 1 300 train
+nrgljucorv 1 302 train
+nrgtzbnojs 1 300 train
+nrhekachxa 1 300 train
+nrherwjzle 0 300 train
+nrhgbhqixu 0 300 train
+nrhpclokqt 1 300 train
+nrhuaxmaei 1 300 val
+nribkcwaty 0 300 val
+nriiwfzqsl 1 300 train
+nrijcdtbmu 1 300 train
+nriuciunak 1 300 val
+nriugrowxm 1 300 train
+nriuzxvido 1 300 train
+nrizbmqhxw 1 301 train
+nrjiegycif 1 300 train
+nrjoluntfh 1 301 val
+nrjooufext 1 300 test
+nrjsflekkm 1 601 train
+nrjysgstdl 0 300 val
+nrkfnwfmmq 0 300 train
+nrkhloopau 1 300 train
+nrknrodwza 0 297 val
+nrkvsrekbo 1 300 train
+nrkwroypeh 1 301 train
+nrkygqwmjo 1 288 train
+nrkytuhsig 1 300 train
+nrlfkmwhix 0 300 val
+nrlhhfbkwa 1 300 train
+nrlhlkpnyb 1 300 val
+nrlkdzjdbh 1 300 train
+nrlkmwarrh 1 241 train
+nrllfjreds 1 300 train
+nrlnvtdile 1 300 train
+nrloxsqltq 1 300 train
+nrlptdimhy 1 300 train
+nrluhgnhdx 1 301 train
+nrlztzipqm 1 300 train
+nrmfccdsbf 0 300 train
+nrmghlajwz 1 300 train
+nrmtxmrcqh 1 298 train
+nrnalofuwn 0 300 val
+nrneuuirjq 1 300 train
+nrnfyuwwmd 0 300 train
+nrnklcxdzq 0 300 test
+nrnlmblczk 1 300 train
+nrnrdjglst 1 300 train
+nroandyoda 0 300 train
+nrorzygitl 1 300 train
+nrosulgdaa 1 300 train
+nrpasaonsc 1 300 val
+nrpjiatbhb 0 300 train
+nrpshcmtzu 1 300 train
+nrqeqlhbfo 1 240 train
+nrqiqmracd 1 300 train
+nrqmlbuojc 1 298 train
+nrqmutqous 1 300 val
+nrqtdftnns 1 300 train
+nrqtqborgz 1 300 val
+nrqvxmfaih 1 300 train
+nrqytqtuox 1 300 val
+nrrgdpkyaz 1 300 train
+nrrhrhjqio 1 99 train
+nrrmbdempe 1 300 train
+nrrnadtucw 1 299 train
+nrrselamng 1 300 test
+nrrwisdyab 1 300 train
+nrrwxmoowv 1 241 train
+nrryctkldj 1 300 train
+nrsapyqdqy 0 302 train
+nrsbjnrbmw 1 300 train
+nrscfrjxpb 1 300 train
+nrsfkaptcv 1 300 val
+nrsqnrcidv 1 298 train
+nrszppdsgg 1 300 train
+nrtbfucnph 1 300 train
+nrtogvzsfv 1 300 train
+nrtqatztcr 1 301 val
+nrtrphhakf 1 297 train
+nrttgubeum 1 300 train
+nrtvbpnsvs 1 300 train
+nrtwbhsxne 1 296 train
+nrtwlhektm 1 300 train
+nrtycmqqcg 0 300 train
+nrtyicwvrm 1 300 train
+nruahvthlg 0 300 train
+nruhibpcqv 1 240 train
+nrujcvxszu 0 300 train
+nrukasjymw 0 300 train
+nrulyucxxq 1 300 train
+nrupdzgtot 1 300 train
+nruppkjfbh 1 300 train
+nrvcafkbxc 1 300 train
+nrvdlsryuf 1 301 train
+nrvhkcezyu 1 300 val
+nrvhpzsvbo 1 301 train
+nrvkjpqjqs 0 300 train
+nrvnsoucor 1 300 train
+nrvuisjyex 1 300 train
+nrvungixci 1 300 val
+nrwcfhbqgx 1 300 train
+nrwcufxspx 0 298 train
+nrwfiholjx 1 300 val
+nrwfmqnbfg 1 300 train
+nrwoaqcgfm 1 300 train
+nrwuxwesnb 1 300 train
+nrwwdsrilc 1 300 train
+nrxlyopspl 1 300 train
+nrxoyzjvgk 1 241 train
+nrxsqtqdrd 1 300 train
+nrxxnkagdt 1 300 train
+nrxxvdatug 1 300 train
+nrycnoehre 1 300 train
+nryitiqdwj 1 300 train
+nryoehjuec 1 299 test
+nryzsamlcc 1 300 train
+nryzsuekri 0 300 train
+nrzgbofbkb 1 300 test
+nrzgobdgzg 1 300 train
+nrzouuwyke 1 300 train
+nrzrjlloaa 1 300 train
+nrzxgzsvyt 0 300 train
+nsadvqmaft 1 300 train
+nsajdvjqzj 1 300 train
+nsanaxscsx 0 300 train
+nsaucwfsni 1 300 train
+nsavbfpwjc 0 301 val
+nsavbywhlu 0 300 train
+nsbexvztiz 1 301 train
+nsbnlwfboi 0 300 train
+nsbvamlvez 1 300 train
+nscbdoleew 1 300 train
+nsccdwwlsc 1 300 test
+nscquvlkba 1 300 val
+nscwodwptx 1 300 train
+nsdfroeaho 1 300 val
+nsdfwjazft 1 300 train
+nsdzdlqypi 1 300 train
+nseapxuzsx 0 300 train
+nsecqgpsyf 1 300 val
+nsekagvjyy 1 300 train
+nseltleptq 1 300 train
+nsepdwvrcu 1 300 train
+nsexpjcsrx 1 301 val
+nsfbecdmhw 1 300 train
+nsffoqdapx 1 300 train
+nsfnxqvgxn 0 300 train
+nsfrytgiwj 0 300 train
+nsfxduzgxe 1 300 train
+nsgcfhrzpq 1 300 train
+nsgeidtrzj 1 301 train
+nsgjhdfnel 1 300 train
+nsgrfxfgzx 1 300 train
+nsgyliipcl 0 300 val
+nshfqgwbeh 1 299 val
+nshinjeija 0 300 train
+nshqdmmgau 1 300 train
+nshtybzqlj 1 298 train
+nshytsoidy 1 300 val
+nsifmpyfnq 1 300 test
+nsincszyvn 1 300 train
+nsiqrhgszg 1 300 train
+nsjdugtcyj 1 300 val
+nsjdygrxom 1 301 train
+nsjtrpiibq 1 300 train
+nsjtsvvsly 1 300 train
+nsjxwdnkqb 1 301 val
+nsjxxvfsii 1 300 train
+nskdiscpzc 0 300 val
+nsklzemzdh 1 300 train
+nskodlffxd 1 300 train
+nskpxsnqdn 1 300 train
+nslahfiahv 1 300 train
+nslannegol 1 300 train
+nsleavclcw 1 300 train
+nslgtrjqto 1 296 train
+nslhmkeicc 1 300 test
+nsllepqolu 1 300 train
+nsloxqskrl 1 300 train
+nslrtpxvmz 1 301 train
+nslssdugqw 0 241 train
+nslwkpcdxk 1 300 train
+nslxkqcpyj 1 302 train
+nsmevaihtm 1 300 train
+nsmquvcfsa 1 300 train
+nsmvbicswb 1 300 train
+nsmvnozsub 1 241 train
+nsnfjsinvl 1 241 train
+nsnjxeefii 1 300 train
+nsnlyrljpb 1 300 val
+nsobahczzz 1 297 val
+nsohfcgsxk 1 300 val
+nsoorkvvlr 1 300 train
+nsozqvhalr 0 300 train
+nspjujjjvq 1 300 train
+nspyimljof 1 300 train
+nsqgovyzeb 1 300 train
+nsqjhyorrl 1 300 val
+nsqqrbbcrr 1 241 train
+nsqsajnwhj 1 300 train
+nsqskncjdb 1 300 train
+nsqssmxbuk 0 300 val
+nsqznrirkq 1 300 train
+nsrbvbkpfr 0 300 train
+nsrkxszxew 1 300 train
+nsrlkkcsru 1 300 train
+nsrxvwgqba 0 300 val
+nsryvzjgum 1 300 train
+nssbqeqxxw 1 300 val
+nssdjquweg 1 298 train
+nssgmhumfu 1 240 train
+nssmzulvqc 0 300 train
+nssszcymey 1 300 val
+nssyiwnehq 1 300 train
+nssyrxoopx 1 300 train
+nstfrsslwk 1 300 train
+nstlzwxslt 0 300 train
+nstpkcwhnx 1 300 val
+nstplpzoix 1 300 train
+nsttcqelrl 1 300 val
+nsttvkuhvj 1 300 train
+nstujyrrbr 1 301 train
+nstykvcgvj 1 241 train
+nstzvosclg 1 300 train
+nsubyolzbh 0 300 train
+nsufkociux 0 300 train
+nsuxqkbstm 1 301 train
+nsvaeuebhc 1 300 train
+nsvdrlugkt 1 299 val
+nsvhzrlnys 1 300 train
+nsvjutkfsd 1 300 train
+nsvnpcqfkr 1 300 train
+nsvqkdtcth 1 300 train
+nsvqqhqyez 1 300 train
+nsvsgjbnmr 1 297 train
+nsvumcpmkk 1 299 val
+nsvwwlkmwp 1 300 val
+nsvyciepsk 1 300 train
+nswghqbqbt 1 300 train
+nswlwuzzda 1 300 test
+nswmgtflfq 1 300 train
+nswprksruw 1 300 train
+nswtvttxre 0 300 test
+nswvmumbyp 1 301 train
+nswyxycnuc 1 300 train
+nswzlobimy 1 301 train
+nsxelihgsi 1 300 train
+nsxeoewlsq 1 300 train
+nsxfdjtkzy 1 301 train
+nsxmshaaxt 1 297 train
+nsxqzffpmr 1 300 train
+nsxtvvgmak 1 300 train
+nsxvwdqedk 1 300 train
+nsxyamblpl 1 300 train
+nsxzeazlgm 1 301 train
+nsxzkhwbph 1 301 train
+nsybnsfnbv 1 300 train
+nsyebcpbtr 1 300 val
+nsyelwvuyy 1 300 train
+nsypyinhvp 1 300 val
+nsysyqeexx 1 136 train
+nsyxopfoau 1 300 train
+nsyzvthdvk 1 301 val
+nszhfynfla 1 300 train
+nsznvjuzrd 1 300 train
+nszqdgagcm 1 300 train
+nszuwmjcoy 1 300 train
+nszxkhqmrg 0 300 train
+nszylqzkqy 1 300 train
+ntaoccysxa 1 300 train
+ntaqujyzes 1 300 train
+ntbdqcrzbs 1 300 val
+ntbfpyqmjs 1 300 train
+ntbglqqeiq 1 300 val
+ntbkejmttr 1 300 train
+ntbkqlecod 0 300 train
+ntbosaxyys 0 300 train
+ntbqcmocdd 1 300 val
+ntbsgdskdt 1 300 train
+ntcbrfzxop 1 300 train
+ntccayuotc 1 241 train
+ntcfyojagi 0 300 val
+ntckrnxnze 1 300 val
+ntcmywdxfh 1 300 val
+ntcqlwxbhu 1 300 train
+ntcufdjdqa 0 300 train
+ntddpzorcw 0 301 val
+ntddrnimyn 1 300 train
+ntddufonlu 0 300 train
+ntdfqvhsuv 1 288 train
+ntdgkueydl 1 298 train
+ntdmumievw 1 300 val
+ntdmwjvjgx 1 300 train
+ntdqogmcnu 1 300 train
+ntdtubxayn 1 300 train
+ntebigummi 1 300 train
+ntefdatbyi 1 300 train
+ntefjqjahr 1 300 train
+ntewtdnlzp 1 300 val
+ntfjkxwfqt 1 300 train
+ntfnqcgfkg 1 300 train
+ntfzxisgja 1 300 train
+ntfzzevqkw 0 300 train
+ntgbrgihst 0 300 train
+ntgfnmjssx 1 300 train
+ntglhdufhx 1 300 val
+ntgokmtsuh 1 300 train
+ntgpkvratg 1 300 train
+ntgqxpnxps 1 300 train
+ntgrebzqps 1 300 train
+ntgrzfrfae 0 300 train
+ntgsnhvjoe 1 300 train
+ntgwsllyez 1 300 train
+nthdwymnqx 1 300 train
+nthlmvjxac 0 300 train
+nthojjycja 0 300 train
+nthoozcwom 1 300 train
+nthozmlfme 1 300 train
+nthpnwylxo 0 300 test
+nthudnaozl 1 300 train
+nthvovzbtp 1 300 train
+ntigmejomp 1 300 val
+ntiniuxyqx 1 301 train
+ntisgmlwsd 1 300 train
+ntjeizzcyt 1 300 train
+ntjfxueeph 0 300 train
+ntjlknlcvn 1 300 test
+ntjlrxljey 1 300 train
+ntjqbcpstr 1 300 train
+ntjrfucfrj 1 300 val
+ntjroriout 1 300 train
+ntkahhxqha 1 301 train
+ntkawpunrj 1 301 train
+ntkcvchxqc 1 301 train
+ntkgylpilw 1 300 val
+ntklaaxlxu 1 300 train
+ntklfrjzeq 1 300 train
+ntknpmfvgd 0 300 train
+ntkrwyqoop 1 300 test
+ntkzgtjadu 1 300 train
+ntlikoxlhb 1 300 val
+ntlqtnqbbx 1 241 train
+ntlrcbwxps 1 241 train
+ntlzabqwkd 1 300 train
+ntmcbbxyxs 1 300 train
+ntmellhygi 1 300 train
+ntmlwvaxps 1 300 train
+ntmmlrjree 1 300 train
+ntmndmbccv 1 300 train
+ntmnrxtvpk 1 301 val
+ntmntmjzno 0 300 val
+ntmrwnzvzt 0 300 train
+ntmywvygja 1 300 train
+ntnacvfydh 1 300 val
+ntnkyyqged 1 300 train
+ntnmovxbyt 0 300 val
+ntnpxyctbl 1 300 train
+ntnvgzqntw 1 301 train
+ntnymwwyxh 1 298 train
+ntoaoupwxq 1 300 train
+ntobxgonji 1 300 train
+ntocljcbec 1 300 train
+ntodtzjdmz 1 298 train
+ntowgaktll 1 300 train
+ntoxyjliyn 1 300 train
+ntoytmuoty 1 300 train
+ntpmamjdyk 1 300 test
+ntpuuuwjmd 1 300 train
+ntpvqwgmqe 1 300 test
+ntpxcwwyuz 1 300 train
+ntqjyvcjdh 1 300 train
+ntqwhlovhk 1 300 val
+ntqxykagix 1 301 train
+ntqysdsfmf 0 300 train
+ntqzfgmhnj 1 300 train
+ntqzuirfkg 0 300 val
+ntrbehijsu 1 296 train
+ntrksclvhq 1 300 train
+ntrlqjcyyu 1 300 train
+ntrnnutlwl 1 300 train
+ntrogisqfh 1 301 val
+ntrxltqxbj 1 255 train
+ntsabyuqrc 1 300 val
+ntsdlgbqhp 0 300 train
+ntsiqfonch 1 300 train
+ntsovbsebg 1 300 train
+ntssjzspmo 1 300 train
+ntstgfpnxb 1 300 train
+ntsyvhkfyb 1 300 train
+nttcjrrynk 1 300 train
+nttffkxnok 1 300 train
+nttjlaoisr 1 300 train
+nttkjjshnb 1 301 train
+nttmucnjjl 1 300 train
+nttnjwzaxh 1 300 train
+nttpvtdvwq 1 300 train
+nttpzkfpzg 1 300 train
+ntttcqmyjm 0 300 train
+nttuvajych 1 300 train
+ntudixyodq 1 300 train
+ntuhqblpqz 1 300 train
+ntumqcnwcx 1 300 train
+ntunzrdehe 1 300 train
+ntuodovnsy 0 300 train
+ntupidyvif 1 299 test
+ntuwypwqpn 1 300 train
+ntvhqlwgin 1 300 train
+ntvjivuwes 0 300 train
+ntvvvfxxak 1 300 train
+ntvvvvhwdq 1 300 train
+ntvxqzlpke 1 300 train
+ntwedxqpnx 0 300 train
+ntwgdzmyas 1 300 train
+ntwqjgyrqc 0 300 train
+ntwunwljei 1 300 train
+ntwvtpjdlw 1 300 val
+ntwzneeyre 1 301 train
+ntxaeqizxy 1 301 train
+ntxcdcxvoc 0 300 train
+ntxcgnddhp 1 301 train
+ntxghjjcal 1 300 train
+ntyhipqmnx 1 300 train
+ntyjdognai 1 300 val
+ntyqdgdvry 1 300 train
+ntyuddpeve 1 300 train
+ntyxlzsxrz 1 299 test
+ntyxnzblsp 0 300 train
+ntyyvsnmks 1 301 train
+ntyzkslmaj 1 300 train
+ntzbmwcatz 1 83 train
+ntzdddfzui 1 300 train
+ntzesquehy 1 300 train
+ntzgbkzofo 1 301 val
+ntzghxinnx 1 300 train
+ntzjpeycpc 1 300 train
+ntzksgkdxo 1 300 train
+ntzlyvufuc 1 300 train
+ntzsbgobew 1 300 val
+ntzunomgei 0 300 train
+ntzxguqfnz 1 300 train
+ntzzprwarc 1 300 train
+nuabbgsjmi 1 300 train
+nuatmlqcck 1 300 train
+nuaycubzbi 1 300 train
+nuayllevfl 0 300 train
+nubbvxsmcn 1 300 train
+nubljfajla 1 300 train
+nubmcasuju 1 300 train
+nubtguqycp 1 300 train
+nubuehaydu 1 298 train
+nucezildwg 0 300 train
+nucqorkejg 1 300 train
+nucrfmvtcm 1 300 val
+nucthtkfvg 1 300 train
+nudavmlpkv 1 300 train
+nueesidovh 1 300 train
+nuegnlhpzc 1 300 val
+nuekxljdnt 1 300 train
+nueldyxqil 0 300 val
+nuelozwnxd 1 300 train
+nuelrpdvlj 1 300 train
+nuenpqzchb 1 300 train
+nuenudnayj 1 300 train
+nuessblxds 0 300 val
+nuezgqczkl 1 303 train
+nufdwjhmym 1 300 train
+nufkzsexhj 1 300 train
+nufllojhny 1 298 train
+nufmdpalck 1 301 train
+nufqxmyffp 0 300 train
+nuftqgdthd 0 300 val
+nufudxdzir 0 300 train
+nufwktfmfq 1 299 train
+nugcgrqmkf 0 300 val
+nugjfjross 0 300 train
+nugkfydnpf 1 300 train
+nugmqruvno 1 300 val
+nugvcomfet 1 300 train
+nugvvrtdhw 1 300 train
+nugylldwvo 1 300 train
+nugzdguskg 1 300 val
+nuhdmwyrqw 1 301 train
+nuhencoeic 0 300 train
+nuhezzhhus 1 298 train
+nuhmeanhpu 0 300 train
+nuhmpqsnzn 1 300 train
+nuhsewhqke 1 300 train
+nuhsjnlleg 0 300 train
+nuhtzsbvll 1 300 train
+nuhvodokrm 0 300 train
+nuhvrbitxv 1 300 train
+nuhzsombrh 1 300 train
+nuihrezbty 1 300 train
+nuilcvfbub 0 300 val
+nuimkdzsrq 1 300 train
+nuinncmjhp 0 300 train
+nuitrhnxaz 1 300 train
+nuizrvbyks 1 300 val
+nujenczvyk 1 300 val
+nujhgmhtmr 0 300 train
+nujjkljawd 1 255 train
+nujpgxavmm 1 300 train
+nukdjlxyje 1 301 train
+nukgkyjwwt 1 300 train
+nukgxdhuoe 1 147 train
+nukidmlrif 1 300 train
+nukkvsnszt 1 300 train
+nukljlrzti 1 300 train
+nuknrhaizy 1 300 val
+nukrjhjreq 0 300 train
+nukzdidabh 1 300 train
+nulauhsuqe 0 300 train
+nulcujoias 1 300 train
+nulfeatedd 1 300 val
+nullkvwixz 0 300 train
+nulnignjni 1 300 train
+nulorpclou 1 300 train
+nulqhgmnir 1 300 val
+numgcafniu 1 300 train
+nummjzfiil 1 300 train
+numqhgeepm 1 300 train
+numtjfjzcp 1 300 train
+numtupzazb 1 300 train
+nunawoqjxf 1 300 train
+nunbxzlpig 1 300 train
+nunihttdvn 1 300 val
+nunjcarakf 1 300 train
+nunpfokifc 1 299 val
+nuntivxdpf 1 300 train
+nunwnfaewu 1 300 train
+nunyzzmfdw 1 300 val
+nuogvbqdve 1 300 train
+nuoivcqmpo 1 300 train
+nuolfdjuan 1 300 val
+nuonfkbcjq 1 300 train
+nuosmaivve 1 300 train
+nuoynmlytn 0 300 train
+nupevxiclv 1 300 train
+nupkeclpvx 1 300 val
+nupmnrytuy 1 300 val
+nuppyekpaf 1 299 train
+nuprhamhvs 1 300 train
+nupwpoocqp 1 300 train
+nupxdfkuth 1 300 val
+nuqfexppak 0 300 val
+nuqhhkhhux 1 301 train
+nuqjveeomt 1 300 train
+nuqmmobatk 1 300 train
+nuqocwxdpe 1 300 train
+nuqqzxoncc 1 301 val
+nurcrzybbw 1 300 train
+nurdmznknt 1 300 train
+nurdpmxpzr 0 300 val
+nuredaeafl 1 300 train
+nurudpsnyz 0 300 train
+nusaceysig 0 300 val
+nusaixrafp 1 301 train
+nusbqbtqvi 0 300 val
+nuskecuqis 0 300 val
+nuskqeciru 1 300 val
+nusohzpbzg 1 300 train
+nussrkyuzy 1 300 train
+nutazlhrji 1 300 test
+nutillbije 1 300 train
+nutnilxlfo 1 301 train
+nutxpqqfka 0 302 val
+nutxvrhmit 1 300 val
+nutyeqzuex 0 300 train
+nuueulufli 1 298 train
+nuumleudbr 1 301 train
+nuumrezfak 1 300 train
+nuusplgics 1 300 train
+nuuuevgtlk 1 241 train
+nuuvzlxrbg 1 300 train
+nuvdbubaaz 1 300 train
+nuvqchwcup 0 300 train
+nuwmkxkzaq 1 298 train
+nuwpvmgbxy 1 300 train
+nuwsfchvgj 1 300 val
+nuwvwqcmks 1 241 train
+nuwypcyftm 0 300 train
+nuwznpojpl 1 300 train
+nuxbddbixj 1 300 val
+nuxgftzhmb 1 299 test
+nuxkpuflig 1 300 train
+nuxlrjpkzm 1 300 val
+nuxmwtgveu 1 300 train
+nuxmykqqkv 0 300 val
+nuxyxvogmk 1 300 val
+nuybulswos 1 300 train
+nuyjmlcfse 1 300 train
+nuzbbjlaed 1 300 train
+nuzctbfemh 1 300 train
+nuzkysrxqg 1 300 train
+nuzlbjavcd 0 300 train
+nuzsqkacjx 1 301 train
+nuzuzynhuj 1 300 train
+nvaelccmql 1 300 val
+nvahuocllf 1 300 val
+nvaovmezke 1 300 train
+nvappvsftu 1 300 train
+nvarnevska 1 300 train
+nvaupehodq 1 300 val
+nvazbnmusu 1 300 train
+nvbaqvriaf 1 300 train
+nvbbknvphe 1 300 val
+nvbhlcfjxu 1 300 train
+nvbjjeouim 1 300 train
+nvbnzfujly 1 300 val
+nvbskcsuyu 1 299 val
+nvbtetbpom 0 300 train
+nvbtmbxplm 1 300 train
+nvbuidyove 1 300 val
+nvbvrkrkml 1 300 train
+nvbxhyabfo 0 300 train
+nvcabjerom 1 300 val
+nvcczlkuvt 1 300 test
+nvceraixly 1 300 val
+nvcqtijkbm 1 301 train
+nvcwsleafg 1 300 train
+nvdbkedvsx 1 300 train
+nvdfhaowqj 1 298 val
+nvdhqlbqlr 1 300 train
+nvdiqwjofe 1 301 val
+nvdlipgrjp 1 302 val
+nvdtfikdvz 1 298 train
+nvdydexbln 1 301 train
+nvdzhsjkda 0 300 val
+nvebeebkwj 1 300 train
+nvedqltuoi 1 300 val
+nvegneixhd 1 300 val
+nveihtidxl 1 300 train
+nvezjvkfbu 1 300 train
+nvfdexehxo 1 299 train
+nvfeurolww 1 300 train
+nvfkbbncah 1 300 train
+nvfppusmdg 1 300 train
+nvfrljnvwe 1 300 val
+nvgeelmvgd 1 300 train
+nvgijpcbrr 1 300 train
+nvgrtyokmz 1 300 train
+nvgtdodhwx 1 297 train
+nvgxnoqate 1 300 train
+nvgyxlqavb 1 300 train
+nvhkxpehws 1 300 train
+nvhoimbgmf 0 298 train
+nvhosphkdk 1 242 train
+nvhownfxma 1 300 train
+nvhpjjwdpk 0 300 train
+nvhpqcogwj 1 300 train
+nviaaukoct 1 300 train
+nvifyzaqrn 0 300 val
+nviqansysv 1 300 train
+nviqscyhuy 0 300 train
+nvirhglbbz 1 300 val
+nvirvscqzx 0 298 train
+nvitncrnmb 1 300 val
+nvizrdbayx 1 300 train
+nvjdasvkoe 0 300 val
+nvjlivbbwz 1 300 val
+nvjljkegle 1 300 train
+nvjlkudcgs 1 300 train
+nvjmiibgbp 1 300 train
+nvjpxgqpci 1 300 train
+nvjryupimn 1 300 train
+nvjsriohlv 1 300 train
+nvkalwiywu 0 301 train
+nvkbbgsiju 0 300 train
+nvkeyxxefq 1 298 val
+nvkgcaotzp 1 300 train
+nvklphdtpf 1 300 val
+nvkogvurth 1 301 val
+nvkqkvnwfq 1 300 train
+nvkscyradi 1 300 train
+nvkshjogvp 1 300 train
+nvkvfbwmav 1 300 train
+nvkzmhtfeb 1 300 train
+nvkzpexyzg 0 301 train
+nvlcncbghk 1 300 test
+nvldbqbakm 0 300 val
+nvlebxsvek 1 300 val
+nvlizsbzkn 1 300 train
+nvllpjeryv 1 300 train
+nvlvsyigrl 1 300 train
+nvlzpldvqm 1 300 train
+nvmcsfltrr 1 300 val
+nvmhslnabc 1 300 val
+nvmkjnfdss 1 300 val
+nvmmvpfesr 1 300 train
+nvmnvsqjsq 0 300 train
+nvmouwwlqw 1 300 train
+nvmsgtqbsh 1 300 val
+nvmuypouph 1 297 train
+nvnkillsgv 1 300 train
+nvnmjargql 1 300 train
+nvnrdguvoa 0 300 train
+nvnxwhzflw 1 300 train
+nvohlmnuwx 0 300 train
+nvohodosno 1 301 train
+nvoinszddi 1 300 val
+nvoqeoqzhs 1 300 train
+nvoshqrlzq 1 300 train
+nvoxusmktd 1 300 train
+nvpdqwulpu 1 300 val
+nvpiwzqual 1 299 train
+nvpjtfhhuz 1 298 train
+nvplmzzffk 1 300 train
+nvpluswotp 0 300 train
+nvpoclbbkh 1 301 train
+nvpspxabqh 1 300 val
+nvptcoxzah 0 136 train
+nvpurgnotz 1 300 train
+nvpwvgyuwp 1 299 test
+nvpxlfgkep 0 300 train
+nvqiursmbh 0 300 train
+nvqtkjfwva 1 301 val
+nvqxfueunb 1 300 train
+nvqxjiooms 1 300 train
+nvrjfquioy 0 300 val
+nvrjjxjduw 1 300 train
+nvrlpyydkz 1 300 train
+nvrmglatkl 1 300 train
+nvrnvrqqch 1 300 train
+nvrpkmwvww 1 301 val
+nvrrohytvz 1 302 train
+nvrvudvylz 1 299 train
+nvrvwenaka 1 300 train
+nvsecbicpr 1 300 train
+nvsgjptpyl 1 300 train
+nvsjgqrqfu 1 300 val
+nvslsuynsq 1 300 train
+nvsoqpdota 0 302 train
+nvswjowrci 1 300 train
+nvtcrgsmky 1 300 train
+nvtlghsqlw 1 136 train
+nvtqvmwpoq 1 300 train
+nvtvaqqaru 1 300 train
+nvubemsnqc 0 300 train
+nvupnivaxi 0 300 train
+nvusdlmiak 1 300 train
+nvuuithlem 0 300 train
+nvvbypihii 1 299 train
+nvvghjfiqq 0 296 train
+nvvheyhlru 1 298 train
+nvvrmgjpek 1 300 train
+nvvvzuhpes 1 300 val
+nvwgwfghgl 1 300 train
+nvwhhgjmzr 0 300 val
+nvwiyobehy 1 300 train
+nvwjgpgusw 1 300 train
+nvwshdfbpl 1 300 train
+nvwucrvmib 0 300 train
+nvwxboncyx 1 300 train
+nvxbthbhaz 1 300 val
+nvxgxrvjww 1 300 test
+nvxokmwzig 1 298 train
+nvxpmzgmmv 1 300 train
+nvxzztkilo 1 300 val
+nvyubogqjt 1 300 train
+nvyulvwhfp 1 300 val
+nvzepplmum 1 300 train
+nvzmqiohes 1 300 val
+nvzuvfktkn 0 300 train
+nwaflnmkss 1 301 train
+nwakqrxpbh 1 300 train
+nwakxhfqhx 1 300 train
+nwaljopist 1 300 train
+nwapznmmfx 1 300 train
+nwazybtjqh 1 300 train
+nwberwsenp 1 300 train
+nwbisexjhn 1 300 train
+nwbixgpidd 1 300 train
+nwbjlxvumg 1 300 val
+nwbkpvxmtm 1 300 train
+nwbltpwrly 1 300 train
+nwbmhiwxfs 1 300 train
+nwboifkqfm 1 299 train
+nwbunqzyzi 1 299 test
+nwbuqdfaym 1 300 train
+nwbvprlpto 1 299 train
+nwbwmvbsmd 1 300 train
+nwbwxejtov 1 300 train
+nwbxbahmrl 1 300 train
+nwbyeexinp 1 300 train
+nwbytavtnf 1 301 train
+nwbzeupoyn 1 300 train
+nwcgptkxrv 1 300 train
+nwcjuolyzc 1 300 train
+nwcluqjiyl 1 300 train
+nwcsggseqf 1 300 val
+nwcslgxdel 1 296 train
+nwdfbzrtsa 1 300 train
+nwdhwzcpoi 1 300 test
+nwdogawahk 1 300 train
+nwdtvxxqhw 1 300 val
+nwducgwand 1 300 val
+nwdwfmabnc 1 300 train
+nwdwrnmbbq 1 301 val
+nwdxowdahh 0 300 train
+nwedfeohwd 1 300 val
+nwejclhiqe 1 300 train
+nwelgeweaf 1 241 train
+nwequzggbv 1 300 train
+nwespmetih 1 300 train
+nweufafotd 0 300 test
+nweuhahyuh 1 300 train
+nweuuovoaa 1 300 train
+nwfakcgahh 1 300 train
+nwffuspknq 0 300 val
+nwfhiittig 0 301 train
+nwfhtrtjrx 1 300 train
+nwfhuxhelf 1 300 train
+nwfkcoqjrg 1 300 train
+nwfplcjnen 1 300 train
+nwfprtqvlb 1 300 train
+nwfpthkuti 1 299 train
+nwgaqkjmki 1 300 train
+nwgbsdkryv 1 300 train
+nwgdmwhaik 1 300 train
+nwggcjdzxf 1 300 train
+nwghsgcurj 0 300 train
+nwghuxrovi 1 300 train
+nwgqkhjwci 1 298 train
+nwgvlgpcxh 1 300 train
+nwgwuxpztr 1 300 train
+nwgxfzbjrd 1 298 train
+nwhcimpytx 1 300 train
+nwherawboe 1 300 train
+nwhleyjguj 0 300 train
+nwhttzifrx 0 300 val
+nwhvpavont 1 300 train
+nwibsvyrdg 1 300 train
+nwiducncsk 1 300 train
+nwignmweqz 1 301 val
+nwijtqnfuw 1 300 train
+nwinjfdyjv 1 300 train
+nwinoueqyn 1 300 train
+nwiowikcrd 1 300 train
+nwiqrbitkj 1 300 train
+nwiutpbkhg 1 300 train
+nwiwdmkkwn 0 299 val
+nwiwvpfler 1 300 val
+nwjabgcyma 1 300 val
+nwjazksytp 0 300 train
+nwjfvfmzps 1 300 train
+nwjmjtqccp 0 300 train
+nwjqgbssma 1 300 train
+nwkbugtmlk 1 301 train
+nwkgxtimxn 1 300 train
+nwkonzosjc 1 300 train
+nwkqnloqad 1 301 val
+nwkthrkhnd 1 300 train
+nwktprjqng 1 301 train
+nwlblsvpgf 1 300 val
+nwlbqrgbic 1 300 train
+nwldurfeyb 1 300 val
+nwltuahqhg 1 300 train
+nwlzgfrgxg 1 300 val
+nwmalfyqyz 1 300 train
+nwmawuxsel 1 300 val
+nwmeroofac 1 300 val
+nwmhcjgikq 0 302 train
+nwmleiuhpu 1 300 train
+nwmpwimelt 1 300 train
+nwmqxljeuf 1 301 train
+nwmtwtovds 1 300 train
+nwmukdplmc 1 300 train
+nwmyiwtuhv 1 300 train
+nwndlagvxh 0 300 train
+nwngteggrb 1 300 train
+nwnimkrvyp 0 300 train
+nwnmvpzmws 1 300 train
+nwnrhhgssv 1 300 train
+nwntwdnqch 1 300 train
+nwofbgsebt 1 300 train
+nwojxekzah 1 298 train
+nwospyzick 1 300 train
+nwosyxbnpg 1 300 train
+nwowmmhjcl 0 300 train
+nwoyzwczsf 0 295 train
+nwpdrtlfkn 0 300 train
+nwpjfdronk 1 300 train
+nwplpcubie 1 300 train
+nwppyufqfc 1 300 train
+nwqacsqelt 1 300 train
+nwqbjauaim 0 300 val
+nwqccywlvs 1 300 train
+nwqfxhyjyd 1 300 train
+nwqgbbwywe 1 301 train
+nwqixiajbb 1 300 val
+nwqlqawvqb 1 300 train
+nwqnwmyipy 1 300 val
+nwqoxdruen 1 300 train
+nwqvacaoxx 1 301 train
+nwqvohefin 1 300 train
+nwrektpeut 1 300 train
+nwrhaaibmg 1 300 val
+nwrioylyfa 1 300 train
+nwrkihkoko 1 300 train
+nwrkoiekdz 1 300 val
+nwrmecizmg 1 300 train
+nwrmvgztnf 1 300 train
+nwrwgeymzv 1 300 train
+nwseytwegi 1 301 train
+nwshpabyrv 0 300 train
+nwtdlrhqtf 1 300 test
+nwtogwomkw 1 300 val
+nwtxntdwsd 1 300 train
+nwtyomipsp 1 300 train
+nwufgtsotz 1 300 train
+nwusthgoam 1 300 val
+nwuzhlxiex 1 300 train
+nwvckvsxbx 1 300 train
+nwvcnmhzkv 1 300 train
+nwvdrgcowy 1 300 train
+nwvfhdxlaf 1 300 val
+nwvfmsjiap 1 300 train
+nwvloufjty 1 300 test
+nwvoyiqloo 0 300 train
+nwvqhdkzvj 1 300 train
+nwvsbmyndn 0 300 test
+nwvtbjcvsd 1 300 train
+nwvyxfmycx 1 300 train
+nwvzszmcso 0 300 train
+nwwmccmles 1 300 train
+nwwqjeyaux 1 300 train
+nwwrhedlhc 1 300 train
+nwwtcqrkgx 1 300 train
+nwwvbgkbgc 1 300 test
+nwwwavfyyj 1 300 train
+nwxgvwpzay 1 300 train
+nwxskvcwha 1 300 val
+nwxstfyhbe 1 300 train
+nwyaacfgnq 1 300 train
+nwydxizggu 1 300 train
+nwypeqqonh 1 300 val
+nwyqweomhm 1 300 test
+nwyqwgzxvu 1 298 val
+nwyseixlso 1 300 val
+nwyuppqbin 1 301 train
+nwywllzwgc 1 300 train
+nwyynkkngk 1 300 val
+nwzhvrblqt 1 300 train
+nwzicpgeyh 1 300 train
+nwzmcngqvz 1 298 train
+nwznzsmegd 1 300 train
+nwzrdkxhql 0 300 val
+nwzrmhrwgu 1 297 val
+nwzrzsjlkj 1 300 train
+nwzvljonuc 0 301 train
+nwzvlzuweg 1 300 train
+nwzwoxfcnl 1 300 train
+nwzxxhzsnp 1 300 train
+nwzyqizeog 1 300 train
+nwzzalxjnh 1 301 train
+nxaaytgqkj 1 300 val
+nxabngwifq 1 300 train
+nxafqzngpn 0 300 train
+nxahgemazn 1 300 train
+nxanysfxgs 1 300 train
+nxaoyuzdsz 1 300 train
+nxatfyatdv 0 240 val
+nxayyzufuw 1 300 val
+nxazlrbtub 1 300 train
+nxbakpkutv 1 299 test
+nxbbiuqnpk 0 300 train
+nxbctyvkgg 1 300 val
+nxbhwochud 1 300 val
+nxbkmfosfp 1 300 val
+nxblqicdne 1 300 train
+nxbmkntfzt 1 300 test
+nxbqzrfgtj 1 269 train
+nxbsezgvrq 1 300 train
+nxbuaxwhna 1 300 val
+nxbufaxyzg 1 300 train
+nxbugavqfh 1 300 train
+nxbxnlmjlp 0 300 train
+nxbysllaap 1 301 train
+nxchtflclj 1 301 train
+nxckbvijqw 1 300 val
+nxczwowbna 1 300 train
+nxdbpyblyu 1 300 train
+nxdilovogq 1 300 train
+nxdkqtvxdv 1 300 train
+nxdnzmmpel 1 300 train
+nxdrfyaezn 1 300 train
+nxdrpqrypt 1 300 val
+nxdtndncds 1 300 train
+nxduaruxvq 0 300 train
+nxdubandjx 1 299 test
+nxeazxbofa 0 300 val
+nxedafmmyx 0 300 train
+nxefvbucjb 1 300 train
+nxelkxqlvi 1 298 train
+nxenrjcfjf 1 300 train
+nxepolnpgo 1 300 train
+nxerdvqszr 1 300 train
+nxeuhfqduq 1 300 train
+nxfbpqkosg 1 300 val
+nxfcgirikh 1 241 train
+nxfdrxshdh 1 299 val
+nxffmpzszb 0 300 train
+nxfoapzdfd 1 300 train
+nxfozfkdto 1 300 train
+nxfwjxwria 1 300 val
+nxgeoiqlkb 1 300 train
+nxgkearxsq 1 300 val
+nxglbjayqa 1 300 train
+nxgmjfgtjy 1 300 train
+nxgmqlbfkl 1 300 train
+nxgvevioea 1 300 train
+nxgvforigs 1 300 train
+nxgzmgzkfv 1 299 test
+nxhbjdrosg 1 300 train
+nxhbxtqhtb 1 300 train
+nxheolhgom 0 300 train
+nxhlsqkxfv 1 300 train
+nxhnkqhygg 1 300 val
+nxibzxvypr 1 300 train
+nxiecpzelr 0 300 train
+nxifwzieou 1 300 train
+nxihjsvfwo 1 300 train
+nxijklmnev 1 83 train
+nxioraqqoe 0 300 train
+nxipnkaszw 0 241 train
+nxisgwjymu 0 300 val
+nxixchauos 1 300 val
+nxizmfseqt 1 300 train
+nxjdnnvejg 1 237 train
+nxjlwigapc 1 296 train
+nxjlzvthfa 1 300 train
+nxjntgvpzt 1 300 train
+nxjrucsptp 0 300 train
+nxjwiqqccm 1 300 train
+nxjwqeutdb 1 300 val
+nxjzjiposq 1 300 train
+nxkajcxqas 1 300 val
+nxkbimdtcq 1 299 val
+nxketuekxm 0 298 train
+nxkmywcbwp 0 300 train
+nxksjqfuzk 1 300 train
+nxkszdswaq 1 300 train
+nxkvakwtnx 1 300 val
+nxkwviyyhu 1 300 val
+nxkyciqhab 1 300 train
+nxlkhvpijm 1 300 train
+nxlkjxwehy 1 300 train
+nxlmreahhi 1 300 train
+nxlrgpoamt 1 241 train
+nxlwghipqa 1 300 train
+nxmgxzlvba 0 300 train
+nxmmpvtkst 1 241 train
+nxmprxgaiy 1 300 train
+nxmusmcjpw 1 300 train
+nxmwhvjrvf 0 300 val
+nxmysghell 1 300 train
+nxmzivfrjh 0 300 train
+nxnbsnvllf 1 300 train
+nxnelrhins 1 300 test
+nxnmkytwze 0 300 test
+nxnnkufvoz 1 300 train
+nxnsmqjnqk 1 300 train
+nxnvceaihv 1 300 train
+nxnyfbpdvd 1 301 train
+nxoabkfcju 1 249 train
+nxoaeefhqb 1 299 test
+nxobpksauw 0 301 train
+nxobvhrpab 1 300 train
+nxoefqvlia 1 300 train
+nxokyagjyh 1 300 train
+nxomblhzlu 1 300 val
+nxoofsqiit 1 300 train
+nxopoxyhcr 1 300 train
+nxosnovbjl 0 298 val
+nxotfpumiv 1 300 val
+nxpasusupk 1 300 train
+nxpbfsphyc 1 300 train
+nxpcjfmeib 1 300 train
+nxpisuysgv 0 300 train
+nxpmyqwkdj 1 300 train
+nxppqwyucy 1 300 train
+nxqhckyoba 1 300 train
+nxqhyzvcdn 1 301 train
+nxqvdemtja 1 241 train
+nxqwzwtddh 1 300 train
+nxrlohdpxq 1 300 train
+nxrwuvuton 1 300 val
+nxryfqmkjz 0 300 train
+nxsanutmyh 1 301 train
+nxshcedptk 1 300 train
+nxstitahab 0 300 train
+nxstqqaexq 1 300 val
+nxtcsqmibe 1 300 train
+nxtctfktyg 1 300 val
+nxtggqnpdr 1 300 train
+nxtrfmiapb 0 300 train
+nxtsawqotg 0 300 train
+nxtstdqkrq 1 300 train
+nxtvazbmrk 0 300 val
+nxtwjubqed 1 300 train
+nxtztibhhs 0 300 val
+nxubdebuwq 0 300 train
+nxudkrhkzm 1 301 train
+nxuypaqrse 1 300 val
+nxvdbatskc 0 300 val
+nxvjxvykqp 0 299 train
+nxvmjekpbw 1 301 train
+nxvqgtzqbe 1 300 train
+nxvsxhmyyc 1 301 train
+nxvtkiegcx 1 300 train
+nxvxmphdol 0 300 val
+nxweavwqix 1 300 val
+nxwgpssriy 1 300 train
+nxwmvvfpdv 1 300 train
+nxwnpxpyzg 1 301 train
+nxwsgyvydw 1 300 val
+nxwwommfst 1 300 train
+nxwywidxjb 1 300 train
+nxxdrmvths 1 241 train
+nxxejtyzph 1 147 train
+nxxicqsjsd 1 300 train
+nxximtsmar 1 300 train
+nxxktzrwie 1 300 train
+nxxscyzmkl 1 300 train
+nxxwblrxzl 1 300 train
+nxyfqrfcta 0 300 train
+nxykzwlgdk 1 300 train
+nxylqxbxnz 0 300 train
+nxymcivnhf 1 300 train
+nxyphuqugl 0 300 train
+nxyqurbpyc 0 300 train
+nxywpewupc 1 301 val
+nxzcetiafw 0 300 val
+nxzcmjoqnd 1 302 train
+nxzfjrjbsc 1 298 train
+nxzgekegsp 1 300 test
+nxzmsnafdd 1 300 val
+nxzngogygj 1 300 val
+nxzpmygaut 1 300 test
+nxzqgygvgt 1 299 train
+nxzrkijvtx 1 300 train
+nyacyvnujd 1 301 val
+nyaeawzybh 0 300 train
+nyaerkamjg 1 300 val
+nyajttovbx 1 300 train
+nyamcaufxi 1 299 test
+nyavwtjvmd 1 297 val
+nyaxmngtmk 1 300 train
+nyaxpnfutl 1 300 train
+nyayqkqtre 1 300 train
+nybasqsdbv 0 300 train
+nybbxyzmox 1 300 train
+nybdqzbctb 1 301 train
+nybdxscrqz 1 300 train
+nybkkqlbhc 1 300 train
+nybkyknftp 1 300 val
+nyborsczcr 1 300 train
+nybsuvztau 1 300 val
+nybubisgar 0 300 train
+nybutishxr 1 300 train
+nybvecttsh 1 300 train
+nybwcoxish 1 300 train
+nybyfaqyjo 1 299 test
+nybyvbsgya 1 300 train
+nybzfwuddi 1 300 train
+nycgvcdxsr 1 300 val
+nyciofqknv 1 298 val
+nycjijfkvc 0 300 train
+nycmyuzpml 0 300 test
+nycsejabqm 1 300 train
+nydkdimatv 1 300 train
+nydklaadwx 1 300 train
+nydllwdktl 0 300 val
+nydmgquwov 1 301 train
+nyduwflrzb 1 300 train
+nyedvendva 1 300 val
+nyefmfbsmb 1 300 train
+nyefvrmocz 0 300 val
+nyekuvmjba 1 300 train
+nyenuhszcb 1 99 train
+nyesdngeyn 1 300 val
+nyewjwqiaa 0 300 val
+nyfcbktuoy 0 300 train
+nyfixzjala 1 300 train
+nyfkgdhskk 1 301 train
+nyfqdjrcxr 0 300 train
+nyfwigdxrh 1 300 val
+nygbcvakxx 0 300 train
+nygdsaunud 1 300 train
+nygdvpofdb 1 300 train
+nygflyjbhp 1 240 train
+nyghtjodio 1 300 train
+nygjirllpy 1 300 train
+nygkdvoyli 1 300 val
+nygraqccsy 0 300 train
+nygscpfcmc 1 301 train
+nygtvtsfiw 1 300 train
+nyguzzmsop 1 300 train
+nygvnlillv 1 300 train
+nygwvwlvkf 1 301 val
+nyhauisjuh 1 300 train
+nyhdwklxnu 1 298 train
+nyhietkbdm 1 300 train
+nyhvhszbuw 0 300 train
+nyhvldjpjh 1 300 train
+nyhypmuqhq 1 300 train
+nyibnxwblj 1 300 train
+nyidwbbujk 1 300 train
+nyifrlbdst 0 300 train
+nyifvxekww 1 300 train
+nyilhwrrxs 1 300 train
+nyinbuetik 1 298 train
+nyipbqspwl 1 300 test
+nyishxxncb 1 300 train
+nyitlsbdcb 1 300 train
+nyixyzcnhv 1 300 val
+nyizrzkoiu 1 241 train
+nyjainpusm 1 300 train
+nyjldzjdvd 1 300 val
+nyjqqdnzdn 1 300 train
+nyjqseodlv 1 241 train
+nyjuzbmgmj 1 300 train
+nyjxveffwj 1 300 val
+nykfckrlki 0 300 train
+nyknlonjxq 1 300 test
+nykshzwuch 1 300 val
+nylaahxmbf 1 300 train
+nyldwpjjbc 1 301 train
+nylgbtvigb 1 300 train
+nylgvfzjao 0 300 val
+nylieipcvh 1 300 train
+nylpybavnh 1 300 val
+nylsbhhbpx 0 301 train
+nylslipbxh 0 300 train
+nylwgsofis 1 298 train
+nylwyrqaot 1 300 test
+nylyfdtbik 1 300 train
+nylzkdswth 1 300 train
+nymalzlpda 1 300 val
+nymjkhzaud 0 300 train
+nymodlmxni 0 300 test
+nymofzyqpn 1 300 train
+nymrpnrnzi 1 300 train
+nymsmmqenu 1 300 val
+nyndgulhrd 1 300 train
+nynuhbttfe 1 300 val
+nynwipdwwx 1 300 train
+nynxvndtpx 1 300 val
+nyoecnptpx 1 300 train
+nyoosqsqey 1 300 train
+nyoossxsjk 0 300 train
+nyosszdasm 1 300 val
+nyoydluvhp 1 300 train
+nyoyrufezb 1 300 train
+nypcdllnnq 1 300 train
+nypfqpmogz 1 300 val
+nypgafnmnd 1 300 train
+nypgflidng 1 299 val
+nyphxxdmwt 1 300 val
+nyplqgduin 1 301 val
+nypqtnpowz 1 300 train
+nypzrhupbm 1 298 train
+nyqfxfhvrm 1 300 train
+nyqixjobcr 0 300 train
+nyqohcgwai 1 300 train
+nyqooevati 1 302 train
+nyqpkhlgpe 1 300 train
+nyqvhhhogs 1 300 val
+nyrbawwubp 0 300 train
+nyrdgxqyjs 1 300 train
+nyrjcdijfj 1 300 train
+nyrkttpzxm 1 300 val
+nyrvlqxzvy 1 300 train
+nyrwcxqriq 0 300 train
+nysvmlbgmq 1 300 train
+nytibweyda 1 300 train
+nytizeqavr 1 300 val
+nytqjpizty 0 300 train
+nyukgmudmb 1 300 train
+nyuklzgkcw 0 300 train
+nyukvfreey 1 241 train
+nyunkpqkan 1 300 val
+nyurpvblrp 0 300 train
+nyuskvnauk 1 299 test
+nyutzyhxvm 1 300 train
+nyuxotvhoq 1 240 train
+nyvadgqzno 1 300 val
+nyvfjptskv 1 241 train
+nyvifevxlh 1 300 train
+nyvjdscuoa 1 299 test
+nyvjtxbiql 1 300 train
+nyvocgnwqi 1 300 train
+nyvvwczjjk 1 301 val
+nyvzfszhew 1 300 train
+nyvzzgsyae 1 300 train
+nywafxuwcs 1 300 train
+nyweilfoca 1 300 train
+nywkpsypto 1 298 train
+nywlxsvlgh 1 300 val
+nywoptxkwu 0 300 val
+nywphgcvmv 1 300 train
+nywwniqcsb 0 300 val
+nyxfiudflc 1 300 train
+nyxkeujnir 1 300 val
+nyxrmccdss 1 300 train
+nyxwwwyqag 1 298 train
+nyxzclwvmr 1 300 train
+nyyiljbgne 1 300 train
+nyyjhchcia 1 300 train
+nyypvkmqsg 0 300 train
+nyyqqlvfkw 0 300 train
+nyyrcevhrc 0 300 train
+nyysglnjxl 0 300 train
+nyyujgogpc 1 302 train
+nyyyofcysx 1 300 train
+nyzenatvho 0 300 train
+nyzgfcjzgy 0 300 train
+nyzgkefwxf 1 300 train
+nyzjfnpeqx 0 300 train
+nyzltiepvx 1 302 train
+nyzppfjfxo 1 300 val
+nyzqcwaxwj 1 300 train
+nyzuudmawc 0 300 val
+nyzytczwrf 1 300 train
+nyzzogaxfk 0 300 train
+nzahnpeynk 1 301 val
+nzaofzwzzg 1 300 val
+nzauupxsqk 1 298 train
+nzazihwjar 1 300 train
+nzbgohmaja 0 299 val
+nzbnqvtljv 1 300 val
+nzbrkjfieq 1 300 train
+nzbukyaylg 1 300 train
+nzbxykspbu 1 300 train
+nzcdcvndxm 1 300 train
+nzcdgloqsw 1 300 train
+nzcjogtncv 1 300 train
+nzckarhlhq 1 300 train
+nzcmxhwdrw 1 300 train
+nzcvewjvoq 1 300 train
+nzczhhwogb 1 300 val
+nzdrcgvhtw 1 298 train
+nzdvbsiecc 1 300 train
+nzeabmqifb 1 300 train
+nzebweshcr 0 300 val
+nzefbvasyc 1 300 train
+nzejrsetam 1 300 train
+nzemaahdrd 1 300 train
+nzenclbdlm 1 300 train
+nzenvakksy 0 300 val
+nzepxsbotb 0 300 val
+nzeqbdtlla 1 300 test
+nzeutxsney 1 300 train
+nzevgmfqay 1 300 train
+nzexdonnht 1 300 train
+nzfcvznfpu 1 300 val
+nzfedneure 1 300 train
+nzfezmyinv 1 300 train
+nzfqirbsbd 1 300 val
+nzfqvclijp 0 300 train
+nzfvtbwpmu 1 299 test
+nzgfplxjpv 1 300 train
+nzghlsrkjc 1 300 train
+nzhbxkycpx 1 300 train
+nzhigdjdcw 1 301 val
+nzhkmhwbrt 1 300 train
+nzhlwidapj 0 300 train
+nzhlwvjxmy 1 300 train
+nzhrnqrbum 1 300 val
+nzhsdscung 1 299 test
+nzhvbpcihb 1 236 train
+nziakjetbs 1 300 train
+nzjaqsvwsi 1 299 train
+nzjcfkzssw 1 300 train
+nzjrdhejrt 1 300 train
+nzjvsfyonv 1 300 train
+nzjytxaetf 0 300 val
+nzkdgmimzf 1 300 train
+nzkhnevqpq 1 300 train
+nzkpslmjpc 1 300 train
+nzkuzdblea 1 300 train
+nzlbwrhkls 1 300 train
+nzlfbilwow 1 300 train
+nzlikttaft 1 300 train
+nzlvxadauc 1 300 val
+nzlxgtpfja 1 300 train
+nzmeuitznn 0 300 train
+nzmmgmgptr 1 300 train
+nzmrqscwsn 1 300 train
+nznkapbnox 1 300 train
+nznlluqvvg 1 300 train
+nznmnfnneb 1 300 train
+nznnkmkwcs 1 300 train
+nznptkguft 0 300 train
+nzodddkcvj 1 300 train
+nzomzgmqay 1 298 train
+nzoodavizv 1 300 train
+nzosikbaob 1 300 train
+nzoyutubwj 1 300 train
+nzpbjfippe 0 300 train
+nzperxctme 1 300 train
+nzpitnljll 0 300 train
+nzpoikselb 1 300 train
+nzpqolzttb 1 300 train
+nzprvbgkob 1 298 val
+nzpyaxujvd 1 300 val
+nzqbzbywvr 1 300 val
+nzqkhbnmrv 1 300 train
+nzqrlqkgxq 1 300 train
+nzqtvipnoc 0 300 train
+nzquxipbye 0 300 train
+nzqwrswqkc 0 300 train
+nzqygjbbsq 1 300 val
+nzqzukeayy 1 300 train
+nzralrkmvg 1 301 val
+nzrbkxjcqr 0 300 val
+nzrcmggcfp 0 300 train
+nzrlgvnhvd 1 300 val
+nzryiidfwt 1 300 train
+nzrzqviayc 1 300 train
+nzsbpkufpd 0 300 val
+nzscowxfkm 1 300 val
+nzsegwqmiz 1 300 train
+nzsksvpchg 0 300 train
+nzslndcilp 1 300 train
+nzsoelkgcx 1 300 train
+nzspqyjuft 1 300 train
+nzssrxgbpg 1 300 val
+nzsypbpqqz 1 301 val
+nztcbpfwun 1 239 val
+nztfbokoej 1 241 train
+nztipmihht 1 300 train
+nztplbqlve 1 300 train
+nzujzjpgaz 1 300 train
+nzukunrvnc 1 300 train
+nzulxsqtrh 0 300 train
+nzuniynsua 1 300 train
+nzuvtbkmye 1 300 test
+nzvbfzvtib 1 300 train
+nzvdonllxo 1 300 train
+nzvnslyepn 1 300 train
+nzvriijisz 1 300 train
+nzvsdrplbs 1 300 val
+nzvtjxftae 1 300 train
+nzwajxdjed 1 300 train
+nzwbrzpoqs 1 300 train
+nzwcqiwimu 1 300 val
+nzwidsettp 1 300 train
+nzwqstlacm 0 300 train
+nzwvvptpss 1 300 train
+nzwwlrlahm 0 300 train
+nzxdgjqehb 1 300 val
+nzxdqcayyg 1 300 train
+nzxekpmvsg 1 300 val
+nzxjdcixqu 1 300 train
+nzxjkjukpt 0 298 train
+nzxncyfeaj 1 300 val
+nzxnsyruzo 1 300 train
+nzxrfzdmoz 1 300 val
+nzxstxsdvl 1 300 train
+nzxtgyjerf 1 300 val
+nzycclllqm 0 300 val
+nzyjjerssg 1 300 val
+nzyncssiea 1 300 train
+nzyuhrasfq 1 300 train
+nzzafcoiua 1 300 train
+nzzbmstfgt 1 300 train
+nzzbquenvu 1 300 train
+nzzhokxgyu 1 300 train
+nzzwtmalua 0 300 train
+nzzxtcazkv 1 300 train
+nzzydpplyd 1 240 train
+oaacqnpoia 1 300 train
+oaaipndlse 1 300 val
+oaaoicrccb 1 300 val
+oaaokbhdwl 1 300 train
+oaaouxhpzu 1 300 train
+oaaranlryg 1 301 train
+oaauafzkyh 1 300 train
+oaauoagcrb 0 300 train
+oaauvbwciy 1 300 val
+oaavnubudw 0 300 val
+oaavxofgkz 0 300 train
+oabalxnaov 1 300 train
+oabbdqgsap 0 300 train
+oabgudxxol 1 300 val
+oabhokdrqd 1 300 train
+oabivrxlzi 1 300 train
+oabnwnlywr 1 300 train
+oabsuggrws 0 300 train
+oachchcaxc 1 301 train
+oacmwzdetc 0 300 val
+oacngxsqxf 1 300 train
+oacoqhlldj 1 301 train
+oacyetngaq 1 300 train
+oacylwoldp 0 300 train
+oadgeyvzxs 1 300 train
+oadqgpmvre 1 302 train
+oadqkzlwyw 1 300 train
+oadqnabrke 1 300 train
+oadwdtgvlr 1 300 train
+oaedytdvph 1 300 train
+oaefhzfppb 1 300 train
+oaeflbjiiq 1 300 val
+oaegsogpyu 1 300 train
+oaerjtztea 1 300 val
+oaetdjquxr 0 300 train
+oaezdqhnjq 1 300 train
+oafhptuosi 0 300 train
+oafjdciclt 1 297 train
+oafrxztueo 1 249 train
+oafvglmknj 0 300 train
+oagradupbw 1 300 train
+oagszxajzz 1 300 train
+oaguiggjyv 0 300 test
+oahewwpdxq 0 300 val
+oahsnmmqeh 1 300 val
+oaifhwqmwn 1 299 test
+oaiiokpdwu 1 298 train
+oainrgzugl 0 300 train
+oaioeivsbq 1 299 test
+oajdfxyonb 1 300 train
+oajfsgjmmu 1 300 train
+oajfyjvnoa 1 300 train
+oajrtijube 1 300 train
+oajvmnnxal 1 300 train
+oajykosmjr 1 300 val
+oakeurzxww 1 300 train
+oakllftzky 1 300 val
+oaknfjboxe 1 299 test
+oakntpdygb 1 300 test
+oakowznniw 1 300 train
+oaksmghptd 1 302 train
+oaldbuzvxx 1 300 train
+oalgcmabfc 1 301 train
+oalmnizuud 1 300 train
+oalnjgsxzg 1 300 train
+oalpawqyfe 1 300 val
+oalsgbxzmc 1 298 train
+oalztsxhbl 1 300 val
+oambyopbqc 1 300 train
+oamfqqvuds 1 300 val
+oamnpjuawk 1 300 val
+oamolpnueb 0 300 train
+oamtblkzpt 1 300 test
+oamvcryqdq 1 298 train
+oamwmgcavo 1 300 train
+oamysrdywr 1 300 train
+oandkyzuvb 1 300 train
+oanpxxyzov 1 300 train
+oanqscndhx 1 297 train
+oanuxtqkhk 0 301 val
+oaojkurgam 1 300 train
+oaomsvvnbo 1 300 train
+oaoobzedru 1 301 train
+oaopjmcgas 1 300 val
+oaowugtlpi 1 300 train
+oaoxmkcpmz 1 300 train
+oaoyqlemqa 1 300 train
+oapgceqolw 0 300 val
+oapixnlyml 1 300 train
+oapsrxgpab 1 300 val
+oaptmwroki 0 300 val
+oapvypyift 1 300 train
+oapxnkneco 1 300 val
+oapxsoaoyr 1 301 train
+oaqapkwcyk 1 300 val
+oaqdxmjrmc 1 300 train
+oaqfjcrxgv 1 300 train
+oaqnefwnon 1 300 val
+oaqqtgvelv 1 301 train
+oaqqvslfva 1 300 val
+oaqtybhmvv 1 300 train
+oaqvjtwkww 1 300 train
+oaqwwpvsjn 0 300 train
+oaqwxklnve 1 302 train
+oarfchvqdk 1 300 train
+oarfrizbfz 1 300 val
+oarkfydagp 1 301 val
+oarpgfiukt 1 298 train
+oarptxjwlm 1 300 train
+oaruliortd 1 300 test
+oasbkawjsf 1 300 train
+oasexvmonv 1 301 train
+oashvrqssi 0 300 train
+oasmcsdjnh 0 300 train
+oasssvymrh 1 300 train
+oatavcpftq 1 300 val
+oatemsgkua 0 301 val
+oathlhqdnz 1 300 train
+oatrcmircj 1 300 val
+oattssamnr 1 240 train
+oaubboazvv 0 300 train
+oaubuajywo 1 300 val
+oaujjepahy 1 300 train
+oauslnwtyg 1 300 train
+oaustqzprg 1 299 test
+oautoycxiv 1 300 train
+oauuzdtdaw 1 301 val
+oavhkxwsrw 0 300 val
+oavlsvwjnn 1 300 train
+oavnezlriq 1 298 val
+oavnkntrmz 1 300 train
+oavrralgxd 1 300 train
+oavxesqhyx 1 300 train
+oawcfkqawo 1 300 train
+oawdcinmlc 1 300 val
+oawgxyvuoo 1 300 val
+oawqlifzsl 1 300 val
+oawrpoakvk 1 300 val
+oawxtqolob 0 300 train
+oaxnzhyvuw 1 241 train
+oaxptfaxtl 0 300 train
+oaxsjqtisp 1 241 train
+oaxtrmbycy 1 300 train
+oaxttpuqvi 0 300 train
+oayizefyhv 1 300 train
+oayjfjuqog 1 300 train
+oayjvbpand 1 300 train
+oaymfurcmo 1 300 train
+oaynnmbsjo 0 300 train
+oayqrnwban 1 300 train
+oazbnvxsqp 1 298 val
+oazdldludx 1 300 val
+oaziospulm 1 300 train
+oazkjrccob 0 300 train
+oazlbwavil 1 300 train
+obaehcxctj 1 300 train
+obaeooqwly 1 300 train
+obagskknsc 1 301 train
+obahajvqzm 0 300 train
+obaicpnvhj 1 297 train
+obaugfytia 1 301 train
+obbbhnaxzu 1 301 train
+obbhgtppov 1 300 test
+obblchdnoe 1 300 train
+obblzvmayt 1 300 val
+obbtzpvvba 1 300 train
+obbueeynyi 1 300 train
+obcbwdxaoo 1 300 val
+obccyqbach 1 301 train
+obcebdiwzg 0 300 train
+obcqnwxsjk 1 300 train
+obcuckmetu 1 300 train
+obcuhcbvdv 0 300 train
+obcuplfjkv 1 300 train
+obcupojzlq 1 300 train
+obcvmeadvg 1 300 train
+obdcjfjdwk 1 300 train
+obdfhidvki 0 300 train
+obdneajqok 1 300 train
+obenmoqdse 1 300 train
+obevvefulh 1 300 train
+obfbakmdnz 0 300 train
+obfhpffedl 1 300 train
+obfqinocan 0 300 train
+obfuuktqdl 1 301 train
+obfvdnixvr 1 255 train
+obgapfkblc 1 300 train
+obgdidzkpc 1 299 val
+obgnfjrprg 1 300 train
+obgtnibnrf 1 300 train
+obguojihof 1 297 train
+obguslzouh 1 300 val
+obgvgkcdln 1 300 val
+obgybzcrje 1 300 train
+obgzphtxyl 1 241 train
+obhazawiur 1 300 train
+obhfoccwcc 1 300 train
+obhggjbeji 0 300 train
+obhgvxiuhx 1 300 train
+obhgxolkee 1 300 train
+obhkcatugu 1 300 train
+obhkqvdvnf 1 300 train
+obhtdnqwta 1 300 val
+obhwqeaxmz 1 301 val
+obhwrfyddp 1 300 train
+obhwstittv 0 300 train
+obidcuzvef 0 300 train
+obidvhxtjn 1 300 train
+obieonvaxm 1 300 train
+obifapcvef 0 300 train
+obiirtrrku 1 301 train
+obinbbzleu 0 300 train
+obipnqrddi 1 300 train
+obisomyeum 1 300 train
+obitvczhwp 1 300 train
+obitzopumq 1 300 train
+obivwekppy 1 300 val
+obiwlecdau 1 300 train
+obiwzhctwf 0 300 train
+objbpuofjo 1 300 train
+objeubyoyh 1 301 train
+objgwnmscm 0 299 test
+objkjmlipn 1 300 train
+objlrnhyjq 0 300 train
+objucgvqzs 1 300 train
+objvmiikyr 1 301 train
+objwcjbabq 1 300 val
+obkcgwegfm 0 300 train
+obkcsjsjco 0 300 train
+obkhmspqfc 1 300 train
+obkxksftly 1 300 val
+oblbranwpt 1 300 train
+obldhnnnlh 1 300 val
+oblneqhlah 1 300 train
+oblwqjlsji 1 300 train
+oblzkknkne 1 300 val
+obmfjpwhgs 1 300 val
+obmjcklysy 0 300 train
+obmjzptgfq 1 300 val
+obmxxmnjzd 1 240 train
+obnlewylpd 1 300 train
+obnnyjtchk 1 300 train
+obnzojzvte 1 300 train
+obodlqklgz 1 300 train
+oboixalhaz 1 300 val
+obokfocdbh 0 300 val
+obothmujgr 1 300 train
+obovgsvept 1 300 train
+obovuicyzf 1 300 train
+obowzjzjxr 1 302 val
+oboxmiushg 0 300 train
+obozirvzxd 0 299 test
+obpncdcxbv 1 300 train
+obpolnmhgo 1 300 train
+obpqhzvrvf 0 300 val
+obpseaabvi 1 300 train
+obpxzorkar 1 300 test
+obqbrzsxul 1 300 train
+obqcxspnwe 0 300 val
+obqkepmnkz 1 300 train
+obqooawsdf 1 239 train
+obqxzmncak 1 300 train
+obrbjarzaz 1 300 train
+obrchniwrr 1 300 train
+obrerthkpl 0 300 train
+obrfqxsnnw 0 300 val
+obrlocqism 1 241 train
+obrlpvegwd 1 300 train
+obrmbvxnoc 0 300 train
+obrzhtzqmf 1 298 train
+obsfweklmh 1 300 train
+obskacwhna 1 300 val
+obstnesxmq 1 300 train
+obsvitysjq 1 300 val
+obtflqoldv 0 300 train
+obtgkbkpuu 1 241 train
+obthlnbgjk 1 300 train
+obtizvjhmw 1 300 train
+obtjplezut 1 300 train
+obtmlpqzid 1 300 train
+obtqawwaaj 0 300 train
+obtsmtqpec 1 301 val
+obttmvmtvi 1 300 test
+obtvuxwwta 1 297 train
+obtwefmgln 1 300 train
+obtxhnkhkb 0 300 val
+obtyjfkelk 1 300 train
+obuazdpdoi 1 299 test
+obubjmxxiz 1 298 train
+obubkmtiff 1 300 train
+obucsppuqo 1 300 train
+obueljrnaf 1 299 train
+obuginrbzn 1 300 train
+obuhmomdhv 1 300 train
+obuhqzjnnu 1 300 train
+obumkiydzq 1 300 train
+obutchbzkp 0 300 train
+obvbmbynuy 0 301 train
+obvczqhpzx 1 301 train
+obvezylejq 1 301 val
+obvgvlypkq 1 300 val
+obvhczcrlj 1 300 train
+obvlrrsrtn 1 300 train
+obvmlowojq 1 301 train
+obvupealnp 1 300 train
+obvxnormtu 1 300 train
+obwdcomrsq 1 300 train
+obwfugpccr 0 300 train
+obwormrfus 1 300 train
+obwxvosvux 1 300 train
+obwygkicpv 1 300 test
+obwzdemdvz 1 300 train
+obxjbeilnl 1 300 val
+obxkclcnia 1 300 train
+obxwiqpnvr 1 300 train
+obxwjnaftd 1 300 train
+obxxxpbbsb 0 300 val
+obycbfbqoq 1 300 train
+obycpsaazq 1 300 val
+obycwvdmpz 1 299 val
+obyeuwvvjr 1 301 train
+obyfatkctv 1 300 val
+obyhtyvotm 1 300 train
+obylehoihn 1 300 train
+obyovynrza 0 300 train
+obzdynopsw 1 300 train
+obzihjsior 1 300 train
+obzlnidsrv 1 300 train
+obzlnzuwsx 1 300 train
+obzursrjqt 1 300 train
+obzxpuegvf 1 300 train
+ocacdtgsio 1 300 train
+ocaivtykmb 1 300 train
+ocakfjvzli 1 301 train
+ocaltsptla 1 300 val
+ocaocnrehd 1 300 train
+ocazrzdbqs 1 300 train
+ocbcrvubib 1 300 train
+ocbkeoasmx 1 300 train
+ocbmnmzyns 1 241 train
+occcvysowm 1 300 train
+occelhylxf 1 300 train
+occenqcbkz 1 299 val
+occhclwrcs 0 300 train
+occipikyys 1 299 test
+occkpccqxi 1 300 train
+occmsbebjn 1 300 train
+occrrsyizc 0 300 train
+occttwpuuq 1 300 test
+occxcjiamc 1 300 train
+ocdcdnxwbw 1 300 train
+ocdvoshamf 0 300 train
+ocdydbxfhl 1 300 train
+ocegouzcdu 1 299 train
+ocehsmeiqc 1 300 val
+ocehtmvojg 0 300 val
+oceigzllhv 1 300 train
+ocelnllsfa 1 300 train
+ocemimdamx 1 300 val
+oceozvusvv 1 300 train
+ocepjalpaa 1 300 train
+ocerfumosk 0 300 train
+ocevdiqfqa 1 302 val
+ocexnepnth 1 240 val
+ocfdulocfq 1 300 train
+ocfiyleaic 0 300 train
+ocfmurwlqo 1 300 train
+ocfpjywqfh 1 300 train
+ocfsxzekgt 1 241 train
+ocfugvrepz 1 255 train
+ocfvawheol 1 300 train
+ocfvdawihy 1 300 train
+ocfwzgzwfu 1 300 train
+ocgcbqznfa 1 299 test
+ocgdbrgmtq 0 300 test
+ocgfovgiaf 1 300 train
+ocggvgyisf 1 300 train
+ocgrlkvzfy 1 301 train
+ocgsjeefjn 1 298 val
+ocguwrotdy 1 300 train
+ocgyfccoee 1 300 val
+ocgyxshvhp 1 300 train
+ochaxsiumj 1 300 train
+ochbsblpnv 1 298 train
+ochctetzwh 1 241 train
+ochecdqslx 1 300 train
+ochicrfxew 0 300 train
+ochwalfmnm 1 300 train
+ochzczbwxz 0 300 train
+ochzghrhsm 1 301 train
+ociaviunty 1 300 val
+ocictrroen 1 300 train
+ocihwchsqo 1 300 val
+ociikqulrp 1 298 train
+ocikupktlc 1 300 train
+ociqmyzysd 1 300 train
+ocjlstcklq 1 300 train
+ocjvhqqraw 1 300 train
+ocjyxxfhfq 0 300 train
+ockavxfckg 0 300 train
+ockbzpictw 1 300 train
+ockfqfgwmm 1 297 val
+ockhacaexx 1 301 train
+ockrccvkou 1 300 train
+ocleckhcbx 1 300 train
+oclfbskmhx 1 300 train
+ocllronhwf 1 300 train
+oclqvwqvwf 0 300 train
+oclrnfzqdg 1 301 train
+ocltsvvics 1 300 train
+oclwvvapcf 1 300 train
+oclztgkszr 1 300 val
+ocmmjtolxf 1 300 train
+ocmxrstuhd 1 297 train
+ocnanobhym 1 300 train
+ocnddjvlvz 1 300 val
+ocnfbztkza 1 300 train
+ocngufnlua 1 300 train
+ocnmnsqwsg 1 300 train
+ocnqcaojtf 0 299 val
+ocnrycgmwm 0 300 train
+ocntllyptc 0 241 train
+ocnwfryqiy 1 300 train
+ocobzwzymt 1 298 train
+ocojvythhz 1 300 val
+ocokqlgxts 0 300 train
+ocolvabpqf 1 300 val
+ocolyrfzpw 1 300 train
+ocopknjkzs 1 300 train
+ocorzgtsmz 1 300 train
+ocoxlosqln 1 300 train
+ocoyaadhps 1 300 train
+ocozccwdhg 0 300 train
+ocpdyljoqx 1 301 train
+ocpecwdbut 1 300 train
+ocpkerjzme 1 300 train
+ocppbjwqrf 1 300 train
+ocprokknqi 1 300 train
+ocpwijwdit 1 300 train
+ocpwqziggn 1 300 train
+ocpyqooapk 1 300 train
+ocqbmprrzy 1 241 train
+ocqcewwett 1 300 train
+ocqgxxuetm 1 300 train
+ocqhpmdwwu 1 300 train
+ocqiogozeg 1 300 train
+ocqkvzxnxo 1 300 train
+ocqrblgifq 1 300 train
+ocqswvkfyt 1 300 train
+ocrgyvtjpm 0 300 train
+ocrhgwavid 1 301 val
+ocrswinipu 1 296 train
+ocrvinzykg 0 300 val
+ocrwnavaqx 1 300 val
+ocrxwhvuaa 1 300 train
+ocsfspgksg 1 300 val
+ocsfwubpxd 1 300 val
+ocsmirgrak 0 298 train
+ocsnhldayx 0 241 train
+ocsocnnpxu 0 300 train
+ocsolevyyq 1 300 train
+ocsqqqduxx 0 300 val
+ocsrqixtjk 0 301 train
+ocsrydzcqx 1 300 train
+ocstqzlitx 1 300 train
+ocsyicjyqb 1 300 train
+octcsyucti 0 300 train
+octjyydyur 1 300 train
+octnezlnfn 1 300 test
+octomjbpki 1 300 train
+octqkaomhs 1 300 train
+ocubcfshnn 1 300 train
+ocuiuronrp 1 300 train
+ocumhotirc 1 300 val
+ocunaudmnl 1 300 train
+ocunhzszxa 1 300 train
+ocupnbhckp 1 300 train
+ocuunzfabh 1 300 train
+ocvainmgfr 0 300 val
+ocveomkblt 1 300 test
+ocvfuhzain 1 300 train
+ocvnznifcn 1 300 train
+ocvvyjodlz 1 301 train
+ocvwmcwyqd 1 300 train
+ocvyftynhw 1 297 train
+ocwazmnydh 1 300 train
+ocwkbqjebk 1 300 train
+ocwkmbqfuh 1 300 train
+ocwvbbwbpe 1 300 train
+ocxdmxtdll 1 300 train
+ocxievbzjv 1 300 val
+ocxorikztw 1 300 train
+ocxwmnqnlc 1 300 train
+ocxwpzhquq 1 300 train
+ocxxnnwfkb 1 298 train
+ocyfudbrxs 0 300 train
+ocylvuufjf 1 300 train
+ocyslmmxkc 0 300 val
+ocysplvoms 1 300 train
+oczbsnyquj 1 300 val
+oczfynmyoe 1 299 val
+oczlotfjrl 1 301 train
+oczoldluwu 0 301 train
+oczpgclisg 0 300 train
+oczvknylbx 1 300 val
+odadetjxno 1 300 train
+odakarlobu 1 300 train
+odaltnoaqw 1 300 val
+odarcpekif 0 300 train
+odatzdeavb 0 301 val
+odawmxhizc 1 300 train
+odayafewew 0 300 train
+odayfkeaug 1 300 val
+odaynlxjyq 1 300 train
+odbcrtgmbt 1 300 train
+odbduxearc 1 241 train
+odbhevldvo 1 300 train
+odbjkpcvjj 1 300 val
+odboxkdiam 1 299 val
+odbpvacjym 1 301 train
+odcbqfeggu 0 300 train
+odcqqwiwzs 0 300 train
+odcyiwmpuj 0 300 train
+oddnirumzt 0 300 train
+oddprtqfey 1 300 train
+oddrnqaysp 1 300 train
+oddshgfhww 1 300 train
+oddwiwirqd 1 300 val
+odebvwocsf 1 299 test
+odejmyxjsn 1 300 val
+odenjjxlex 1 300 train
+oderfyngho 1 300 train
+odesmdrzfn 1 301 train
+odetfquvfu 1 301 train
+odeuhkybmj 0 241 train
+odexyxhdxq 1 300 train
+odfecedxts 0 301 train
+odfegqcgci 1 300 train
+odfhdogijr 1 300 train
+odfonacbrv 1 300 train
+odfqozsdmq 1 300 train
+odfrjlghze 1 300 train
+odgqjkmyls 1 300 train
+odgsohkpfu 1 300 val
+odgsucvwco 1 300 val
+odgtjsijuv 1 300 train
+odgvkuzgks 1 300 val
+odgysrikcl 1 296 train
+odhleyghtp 1 300 train
+odhmcecpbn 1 300 train
+odhmuveywb 1 300 val
+odhpbztful 1 300 train
+odhrjeeinx 0 300 val
+odhrkralht 1 300 train
+odhtghxmtz 1 249 train
+odhtxuanhj 1 300 train
+odhuywimgu 1 300 train
+odiacmeljx 1 300 train
+odiaqqnpxs 1 301 train
+odidbykbar 1 300 val
+odidqnheoy 1 300 test
+odieurrtjb 1 300 val
+odigpuwcbj 1 300 val
+odijdzsvce 0 300 train
+odimzpboxe 1 300 train
+odinclaohf 1 300 train
+odioowlayj 0 300 train
+odisbicvlp 1 300 train
+odiylddlzb 1 300 train
+odjtvuqqwr 1 300 train
+odkeovzhyg 1 300 train
+odkfpcfnhs 1 300 val
+odkfrobalp 1 300 train
+odkjabziza 0 300 val
+odkkoyhlyh 1 300 train
+odkodohhik 1 300 train
+odkogezzuo 1 300 train
+odkrxupfzi 0 300 train
+odksflgkon 0 300 train
+odkugnvwoe 1 300 train
+odlegvilii 1 300 train
+odlejjfjaj 1 300 train
+odlidgmzqf 1 300 train
+odliickrfl 1 297 train
+odlqdnztww 0 300 train
+odlqgtlbsf 1 298 train
+odlvfcwtia 1 300 train
+odlzoqlfhq 1 300 train
+odmcwgyvij 0 300 train
+odmeoekpyu 0 300 train
+odmhsqhryt 1 300 train
+odmmvpzkwe 1 300 train
+odmnqqqdci 1 300 train
+odmrwqddlm 1 301 train
+odmtwcjdhs 1 300 train
+odmwmckrxy 1 299 val
+odmwoavpit 1 298 train
+odmyurcpoj 1 300 val
+odmyxlcmaz 1 300 val
+odnicwpqyh 1 300 train
+odniyoaktc 1 300 val
+odnqiwftsb 1 299 test
+odnrklbcol 1 298 train
+odnrxtcxjj 1 301 train
+odnusklbpe 1 300 train
+odoaqpcqtt 1 300 train
+odoatjfszl 1 300 train
+odobufziuh 1 300 train
+odogkxkmqm 1 300 train
+odojatrrnx 1 300 train
+odopkpaixy 1 300 val
+odosgkhpuy 1 300 train
+odotpnxgou 0 300 train
+odozgywtkv 1 300 train
+odpcadnlsj 1 300 train
+odpvfxmeiw 1 300 train
+odpwvdtety 1 300 val
+odpycdtvky 1 300 train
+odqaifxrjo 1 300 train
+odqhnxhmrd 1 300 val
+odqyarcthr 1 300 val
+odqyqdbahn 1 300 train
+odrricydub 0 300 train
+odruqsfkgh 1 300 train
+odrylsffts 1 300 val
+odsbfphzfx 1 297 train
+odsfnzgtay 1 300 val
+odshmmzmcn 1 300 train
+odssrkeuxy 1 300 val
+odsvmzheme 1 300 train
+odsydseugj 1 301 val
+odtdsnrigv 1 301 train
+odteaaynal 1 300 train
+odteugmftq 0 300 train
+odtfvaebvu 1 300 val
+odttzxfprw 1 298 train
+odtvqwnjpi 1 300 train
+odtwsblwwa 1 298 train
+oduhqgthej 1 300 train
+odusjdlmsx 1 300 train
+oduusmhcem 1 241 train
+oduwjsscjo 1 300 train
+odvencajnr 1 300 train
+odvqbtoczb 1 300 val
+odvxpcjxfg 1 241 train
+odwhmezcnz 0 302 train
+odwjxxpnbz 1 300 train
+odwmqazixr 1 300 val
+odwqisytvw 0 300 val
+odwrbpigyr 1 300 val
+odwshpqaos 1 300 train
+odwvegiiuq 1 298 train
+odxcohtxge 1 300 train
+odxdkangki 1 300 train
+odxetivvot 1 300 test
+odxmtcxema 1 300 train
+odxpccovae 0 301 train
+odxtplwzjr 1 300 train
+odyafubgji 1 301 train
+odyctadiyt 1 300 train
+odyiznhjrj 1 300 train
+odyphqfzdq 1 300 train
+odysiofrlk 1 300 train
+odysoxjyrd 1 300 train
+odyucmgcvg 1 300 train
+odyxiflvar 1 300 val
+odzdvdsuds 0 300 train
+odzffkaftd 1 300 train
+odzgkngaza 0 300 train
+odzhpbyvkx 0 298 train
+odziwslvsf 1 300 train
+odzlpsuoft 1 300 train
+odzmxqcagj 1 300 train
+odzphlrpnz 1 300 val
+oeagdxayvb 1 300 train
+oeamsogcjz 1 300 train
+oeanhumqlt 1 300 val
+oeaudrfgow 1 300 train
+oeaxxbnotz 1 300 train
+oebaztypsg 1 298 train
+oebchwftht 1 300 val
+oebcvthfeq 1 300 train
+oebeexyutq 1 299 test
+oebkdhhway 1 300 train
+oebumnajit 1 300 train
+oebxywcmuo 1 300 train
+oecamgmbpk 1 299 test
+oeccccnpxu 0 300 val
+oecgmnxbjv 0 300 train
+oechyzquzv 1 300 train
+oecjqhkxry 1 300 train
+oeclfgftka 1 300 train
+oecnrpjefi 1 300 train
+oecsemwfvb 1 300 train
+oecutozkfi 1 300 val
+oecwwneeol 1 300 train
+oecygubjvk 1 300 train
+oedffcxidl 1 301 train
+oedfzeywmp 1 300 train
+oeedcefyoy 1 300 train
+oeehuctlac 1 300 test
+oeemhayfji 1 300 train
+oeemhyqfkp 1 300 train
+oeetzdepvg 1 300 train
+oeewrpfasi 1 300 train
+oefimkpjdo 1 300 train
+oefpibuwji 1 300 train
+oefqufyium 1 300 train
+oeftvjcbry 1 300 train
+oefukgnvel 0 300 test
+oefxacxmvl 1 300 train
+oefzonhfga 0 193 train
+oegfxstyyn 1 300 train
+oeggkuyylx 1 300 train
+oegkmwtvmd 1 300 val
+oegtqqjnfs 1 300 train
+oegzpfctlc 1 300 train
+oehcimdlll 1 300 train
+oehcopssyz 1 300 train
+oehiulnncr 1 241 train
+oehnikgtug 1 249 train
+oehrjztgxg 1 300 train
+oehykcuwpj 1 300 val
+oehzwrrhve 0 300 train
+oeibgzoqus 0 300 train
+oeicoznexr 0 300 train
+oeicqiobub 1 301 val
+oeicxgiqkb 1 300 train
+oeiihfgrbn 1 300 train
+oeiqpnagyp 1 300 train
+oeirxkaklj 1 300 val
+oeitousvqp 1 300 train
+oeivcmmpvp 1 300 train
+oejblxsukk 1 301 train
+oejdvvzuav 1 300 train
+oejdyjjkfs 1 300 val
+oejfypsbfh 1 300 val
+oejkjxkpdy 1 298 train
+oejkvdjgqq 1 301 train
+oejlipxtai 1 300 test
+oejoqhqjya 1 297 train
+oejowaknsm 1 300 train
+oejpioaacb 1 300 train
+oejvgvjljg 1 300 train
+oejzrvvmii 1 300 train
+oekageffih 1 300 val
+oekdjsokkb 1 300 train
+oekeietccl 1 301 train
+oekkxxaadp 1 241 train
+oekleyyeyg 1 298 train
+oeklmndxpj 1 300 train
+oeklsfhgqv 1 300 train
+oekmgqpmcp 1 300 train
+oekynafnit 0 300 train
+oelabpslca 0 301 train
+oeldlagrwb 1 300 val
+oeldomqxkm 1 300 val
+oeldxwjovy 1 300 val
+oelleelbqj 1 300 train
+oelqpetgwj 1 300 test
+oeluedpebu 1 300 val
+oelwmyflfz 1 300 train
+oelxeqlmyn 1 298 train
+oelygwizii 1 300 val
+oemaqmmytc 1 300 train
+oemcbvxwad 1 300 train
+oemhtukett 1 301 train
+oemkyqdwzl 1 300 val
+oemkzolrsl 0 300 val
+oempdlzpgq 1 300 train
+oemvcbrmmr 1 300 train
+oemvdggyyq 1 301 train
+oemwpbnhig 1 300 train
+oemzvcyivl 1 300 train
+oendughayp 0 300 val
+oenezghuwm 1 301 train
+oengjcryao 1 300 train
+oenjfwbhsr 1 300 train
+oenkutfplz 1 300 train
+oennhuxorr 1 300 train
+oenruojxyr 1 300 train
+oenuvpoacn 1 300 train
+oeobpjjspn 1 300 train
+oeocgqjtmn 1 300 train
+oeochguxsd 1 300 train
+oeodamaqxv 1 300 train
+oeoflpjgua 1 301 train
+oeoimoidcu 1 240 val
+oeoklzfojq 0 300 train
+oeoliupynd 1 241 train
+oeoyavfdwx 1 600 train
+oeoycyooyr 1 300 val
+oepbjkbaxz 1 300 train
+oepibyxyry 1 300 train
+oepisgvvxh 1 300 train
+oeplwjlhxd 1 300 train
+oeposxukaa 1 298 train
+oepotttwuk 1 300 train
+oeprhtxhrg 1 301 train
+oepwiawfhm 1 300 val
+oepzkokdhg 1 300 train
+oeqaswspef 1 300 train
+oeqelrusrs 1 300 train
+oeqgbnhijl 1 300 val
+oeqiwfnxlc 1 300 train
+oeqjhgzeai 0 300 val
+oeqjtdvvvl 1 300 val
+oeqlaaaqvv 1 300 train
+oeqoihpmmw 1 300 train
+oeqqmgyxaa 1 300 val
+oeqtdzabkq 1 301 train
+oequguujid 1 300 train
+oeqwfhyeos 1 300 train
+oeqwfljllr 1 300 train
+oeqwtawzcd 1 300 train
+oerbtbtgkg 0 300 val
+oeremogflx 1 300 train
+oerjyadypg 0 300 train
+oerogyatcq 1 302 val
+oertexvscw 1 300 train
+oeskgriyjz 1 300 train
+oesmmyhzmi 1 300 train
+oespqpqvvm 1 297 train
+oesrucmptw 1 300 train
+oessxyktpm 1 300 train
+oesupnlnll 1 300 train
+oesxbvktem 0 300 train
+oetaeitgsz 1 300 train
+oetbokpalq 1 300 train
+oeteqitnwi 1 300 train
+oetgphffvn 1 301 train
+oetobrolei 1 300 val
+oetuazcxnk 1 300 train
+oetugfddxa 1 300 train
+oetyusiicd 0 300 train
+oeuelgagdm 1 300 train
+oeuntzesdf 1 300 val
+oeuryhvguc 1 300 train
+oeuszzavxl 1 300 test
+oeuufzbozk 1 301 train
+oeuyjnboku 1 300 train
+oevdwgfpqc 1 300 train
+oevydbvxbe 1 298 train
+oewbvvrzsw 1 297 train
+oewhsmeags 1 300 val
+oewkovdhbl 1 300 train
+oewksjvwbh 0 300 train
+oewlimbdoo 1 299 train
+oewlnkifph 1 300 val
+oewnsrjnmx 1 302 val
+oewomccntj 1 300 train
+oewrzbniqn 1 241 train
+oewutjgulw 1 300 train
+oexdmllrjk 1 300 train
+oexgmepmkf 1 300 val
+oexkzdylsz 1 300 train
+oexoavedkb 1 300 train
+oextegpgmk 1 298 val
+oextnxbzrx 1 241 train
+oexvjynpnx 1 299 train
+oexznbsulp 1 300 train
+oeydkaunul 1 300 train
+oeyftftnqi 1 300 train
+oeyhwrvdhg 1 300 train
+oeypfwjgpu 1 300 train
+oeytdpzlze 1 300 train
+oeywnxpioy 1 300 val
+oezboosvco 0 300 train
+oezhkdntds 1 300 train
+oezolrvzax 1 300 train
+oezufleysu 0 300 train
+ofalghtojl 1 300 train
+ofalngcjis 1 300 train
+ofalonjlxp 1 300 train
+ofaltpvuru 1 300 train
+ofapaanpkl 0 300 train
+ofawekwuem 1 300 train
+ofayjatxtn 1 300 train
+ofbgurmlpw 1 300 train
+ofbjiuemkr 0 300 val
+ofbkhvteqo 1 300 train
+ofbkkkfuvs 1 241 train
+ofblacvpri 1 300 train
+ofcaweirnf 1 300 train
+ofcbevdvdn 1 300 train
+ofcfgklehs 1 300 val
+ofcpczmuiz 0 300 train
+ofcvvtryfp 1 300 train
+ofcvzlmkyv 1 300 train
+ofcxcrbpab 1 300 val
+ofcyeekdnx 1 298 train
+ofczzfyogw 1 300 train
+ofdauhdzah 1 300 train
+ofddpxglao 1 300 train
+ofdegtykvm 1 300 train
+ofdhwdwvqb 0 300 val
+ofdolzwedv 1 300 train
+ofdrqgfvfs 1 300 train
+ofdumjfzdp 1 300 val
+ofdwbhyhoi 1 300 val
+ofdylgmxtm 1 300 train
+ofedxywxhw 1 300 train
+ofeedkhgvm 1 300 val
+ofehekupht 1 300 train
+ofeivayznp 1 300 train
+ofejygejmx 1 300 train
+ofemahvmvm 0 300 train
+ofenuaprkl 1 300 train
+ofepymbrlu 1 301 val
+oferjryffj 1 300 train
+offdmpifvm 0 300 train
+offfnshnnh 1 300 train
+offksstwow 1 300 train
+offktoxbmq 0 300 train
+offkxnhtbx 1 300 val
+offwteepbu 1 300 train
+ofgbvjcxuw 1 300 train
+ofggknmqii 1 300 train
+ofgjrewcmp 1 299 train
+ofgkronoih 1 300 train
+ofglgmozmg 1 300 train
+ofgordjjne 1 300 train
+ofgqjiclbm 0 300 train
+ofgwamdaug 1 300 train
+ofharrjjae 1 300 val
+ofhcxwwvvu 1 300 val
+ofhfexlphk 1 300 train
+ofhgcwcbmg 1 300 val
+ofhohsywlu 1 300 train
+ofhtxenrbb 1 241 train
+ofhxvaenhh 1 241 train
+ofiaecwslg 1 300 train
+ofibjmgurk 1 299 train
+ofihciodof 1 250 train
+ofiqwrklae 1 300 val
+ofirliljrd 1 300 train
+ofishcvdnv 1 300 train
+ofjgkpwses 1 300 train
+ofjgwkmcoc 1 300 train
+ofjmkolexs 1 300 train
+ofjngaymyq 1 300 train
+ofjsoptbkk 1 300 train
+ofjznjgeuk 1 300 train
+ofkcziraai 1 300 train
+ofkdyalzqw 1 300 train
+ofkhoosakc 1 300 train
+ofkrvdfhui 1 300 train
+ofkvhxpcya 1 300 train
+oflczrszkk 0 300 train
+oflfdjtlmx 0 300 train
+ofliafjirm 1 300 val
+oflowrqucp 1 300 val
+oflpknfqyr 1 300 val
+oflrdnxapc 1 300 val
+oflrggwdkm 1 300 train
+ofluzanvce 1 300 train
+ofmkbqhcdn 1 300 val
+ofmlruxjde 1 300 train
+ofmmfbprkn 1 300 train
+ofmqeahobj 1 300 train
+ofmrqfemne 0 300 train
+ofmtflyqop 1 300 train
+ofmuekczoo 1 300 train
+ofnkfgdvwx 1 300 train
+ofnmctcjma 1 300 train
+ofnodyyeoe 1 300 train
+ofnpozaxzx 1 300 train
+ofntcunuqn 0 300 train
+ofntkmxuen 1 300 val
+ofnwekjzfk 1 300 train
+ofnybrddzx 0 300 train
+ofoinycpua 1 288 train
+ofolutvpfb 1 300 val
+ofoqvctjaf 1 298 train
+ofosaxpffz 0 301 train
+ofouaavqrm 1 300 train
+ofpaotnqno 1 300 val
+ofpflgwsds 1 300 val
+ofpnzadyvx 1 298 train
+ofprdcbhzf 1 300 train
+ofpugszjdt 0 300 val
+ofpvnbprdp 1 300 val
+ofpwsxvwpr 1 300 val
+ofqhzkbvbh 1 301 train
+ofqjjqlkfc 1 300 train
+ofqjspmccr 1 300 train
+ofqkefrrrt 1 299 train
+ofqnxzjaff 1 299 train
+ofqqblotez 1 300 val
+ofquuujxmu 1 300 test
+ofqwrvmvxg 1 300 train
+ofrapvpkpf 1 300 train
+ofrgxlvuww 1 300 train
+ofrhaytvoj 1 297 train
+ofrivhedps 1 301 train
+ofrllazejo 1 300 train
+ofrmvlfyxd 1 300 train
+ofrnkzpngq 1 300 train
+ofrpnuvpxx 1 300 val
+ofrqaqhmmu 1 300 train
+ofrszkvqoh 1 300 train
+ofrtktvfzp 1 300 train
+ofrxxtvzsv 1 167 train
+ofrzfyflvt 0 300 val
+ofsfitukep 1 300 train
+ofsgrlmkgk 1 300 val
+ofslrnnldg 1 300 train
+ofsmavqaio 0 300 train
+ofsuufcixk 1 300 train
+ofsxappdgn 1 300 train
+ofsxivhhcf 1 300 val
+ofthynldrz 1 300 train
+ofuauojhto 1 300 train
+ofubnuvlel 1 300 train
+ofudimpbfh 1 300 val
+ofuedivutf 1 241 train
+ofugihyuia 1 300 train
+ofullbozco 0 300 train
+ofuojttonr 1 300 train
+ofuomunudr 1 300 train
+ofupqybhjy 1 300 train
+ofuruwzcit 1 300 train
+ofuviodasc 1 300 train
+ofuyapzsca 1 301 train
+ofvgnqzscp 1 300 train
+ofvifngcgm 1 300 train
+ofvmzsroqt 1 300 train
+ofvqcwgeap 1 300 train
+ofwcnyyfpn 1 300 train
+ofwfaxpqmy 1 299 val
+ofwjhasywd 0 300 train
+ofwjwemovw 0 297 val
+ofwjyvgwnk 1 300 train
+ofwmrrtncx 1 300 train
+ofwrcfcqqy 1 300 train
+ofwtafbdtp 1 300 train
+ofwvgwosbj 1 300 val
+ofxdydegsc 1 300 train
+ofxhxmkpob 1 300 val
+ofxjoeebby 1 300 train
+ofxtugevfx 0 300 val
+ofyojxolmd 1 300 train
+ofyrwgbrab 1 300 val
+ofytjertwv 1 300 train
+ofyxwsahdd 1 300 train
+ofzbuuchlv 1 299 train
+ofzrdqyrdt 1 300 train
+ofzscppeyw 0 300 train
+ofzvznbcru 1 300 train
+ofzztoeoyu 1 300 train
+ogaakxbtdl 1 300 train
+ogaghxvfyr 0 303 train
+ogaqhblnri 0 300 train
+ogaqkbajxk 1 300 test
+ogawylhzzl 1 300 train
+ogaxeeegzg 1 300 train
+ogazgvktfr 1 299 train
+ogbdbwales 1 301 train
+ogbhbectlr 1 240 train
+ogbhknawmi 0 240 train
+ogbjslmezh 1 300 train
+ogcktjzanx 1 300 train
+ogcpxrvgfb 1 300 train
+ogcyuohtco 0 300 train
+ogdeiprfur 1 300 val
+ogdlanboqg 1 240 train
+ogdlfceemp 1 300 val
+ogdnngytni 0 300 train
+ogdsifiwlx 1 300 train
+ogdvophhin 1 300 train
+ogdwteaydn 1 300 train
+ogdzbnuntv 1 300 val
+ogeahrurwk 1 269 train
+ogefwsfivd 1 300 train
+ogeidkkcun 1 300 train
+ogesxrayqv 0 300 train
+ogesymxfqj 1 300 train
+ogevlfcqqa 1 300 train
+ogewlxoxqi 1 300 train
+ogfaxgdcwm 1 300 val
+ogfddtgjpx 0 300 train
+ogffjkjhna 1 300 train
+ogfnbktupy 1 300 val
+ogfnmmqhqn 1 300 train
+ogfswkjdbv 1 300 train
+oggaudwerx 1 300 train
+oggcdaynjt 1 300 train
+oggelygfsg 1 300 val
+ogghhskfdr 0 300 train
+oggjtmpnrb 1 300 train
+oggtplowfa 0 300 train
+ogguggusha 1 300 train
+oggwxheojt 1 241 train
+oghfaenvqv 1 300 train
+oghmjzhamx 1 300 val
+oghquwifhu 1 300 train
+oghuvyeeoy 1 300 train
+oghvmzqrbc 1 300 train
+oghylfodsy 1 241 train
+oghyyclecl 0 300 val
+ogicrevvcp 1 300 train
+ogjagduqpi 0 302 train
+ogjcvtnges 0 300 train
+ogjesffbyz 1 300 train
+ogjgcgjisu 1 300 train
+ogjgchawhp 1 301 val
+ogjhppawub 1 300 train
+ogjiicvwia 1 300 val
+ogjkrvwany 0 300 train
+ogjninicit 1 300 train
+ogjolljnxx 1 136 train
+ogjpwwvpbw 1 300 train
+ogjrtlojue 1 241 train
+ogjtecvqai 1 300 train
+ogkbionmon 1 241 train
+ogkfdgcxgg 1 300 train
+ogkiosrfxy 1 300 val
+ogknepbtqn 1 240 train
+ogkrpzqwgv 1 300 val
+ogkskitjde 1 300 train
+ogktmsozkv 1 300 train
+ogkudilajs 1 300 train
+ogkxbszfbf 1 300 train
+ogldevfqqx 1 300 train
+ogldymqxtt 1 300 train
+oglmvhyfdq 1 299 train
+oglndykjqq 1 300 train
+oglspjpovz 1 300 train
+oglstgrhcx 1 297 train
+oglvuwidwh 1 300 val
+ogmclyrcmj 1 300 val
+ogmfalzqep 1 301 train
+ogmfhrdwtl 1 300 train
+ogmsmygvus 1 300 train
+ognhckpvsi 1 301 train
+ognqbysnfw 0 300 train
+ogntwndjeu 1 300 train
+ognvrnmnie 1 300 train
+ogockoiyao 1 300 train
+ogogeaooxh 1 300 train
+ogoixtqpgj 1 300 train
+ogomcnnmoa 0 300 train
+ogonirmuko 1 300 train
+ogopotfmbr 1 300 train
+ogoqbsdgjp 1 300 val
+ogoucjbwiq 1 300 train
+ogpbqcuryw 0 300 val
+ogpfoeeuwq 1 300 train
+ogphivcsix 1 300 train
+ogpkdabaxm 1 300 val
+ogpkqhvhcf 1 300 train
+ogpngwmrkz 1 300 val
+ogpszgkkgw 0 300 train
+ogpuoqgqut 0 300 train
+ogpxnrlwzk 1 300 val
+ogqccjfncg 0 300 train
+ogqfqstvsd 1 300 train
+ogquoubrtx 1 288 train
+ogqwgftjdh 1 300 train
+ogqwlwvygf 0 301 train
+ogqzxlcecf 1 299 test
+ogrmztqkny 1 300 train
+ogrpobgdtl 1 301 train
+ogrybyzbnh 1 300 train
+ogrzmxwtom 1 300 test
+ogsettrepr 1 300 train
+ogshgsinnl 1 300 val
+ogsyjjxfop 1 300 train
+ogtdgmdass 0 300 train
+ogtdsajkve 1 300 train
+ogtgnhltab 1 300 val
+ogtkrijcdj 1 300 train
+ogtktxhecq 1 300 val
+ogtvdjlpbc 1 300 train
+ogtxnpejff 1 300 train
+ogtxtbiibu 1 300 train
+ogtxytsich 1 300 val
+ogtyrnqtgp 1 300 train
+oguaftumgs 1 300 train
+ogualjbong 1 297 train
+ogucjkrnsu 1 300 val
+ogudhhrgqy 1 300 train
+ogueotgdts 1 300 train
+oguqwtfjlx 1 300 test
+oguxfuamjb 1 300 train
+ogvjbxdbyv 1 300 train
+ogvkeyvxjf 1 300 val
+ogvnzdahho 0 300 val
+ogvpquznpa 1 300 train
+ogvufygdjr 1 300 train
+ogvumzxtrq 1 300 train
+ogvuslvebn 0 300 train
+ogwdenptly 1 300 val
+ogwedmpojq 0 300 train
+ogwonjsnkv 1 300 train
+ogwvszpons 1 300 train
+ogxbhuwzmg 1 300 train
+ogxclikmst 1 300 train
+ogxilhjehh 1 299 val
+ogxkmnjcro 1 300 val
+ogxxgicqvw 1 299 val
+ogyampufzj 0 300 val
+ogyfnjldvf 1 300 train
+ogygtbfkyz 1 300 train
+ogyhguoqxf 0 300 train
+ogyileofct 1 300 val
+ogykwizlya 1 300 train
+ogymvqamqw 1 300 train
+ogynflmier 1 300 train
+ogyxnnmlvn 1 300 train
+ogzaflxjtk 1 300 test
+ogzbfoyxdh 0 300 train
+ogzdlongzp 1 300 train
+ogznalgvrd 1 300 val
+ogzrsddhur 1 300 train
+ogzsnowlkn 1 300 train
+ogzsodcnba 1 300 train
+ohaidohmou 1 300 val
+ohaikbkbzl 1 300 train
+ohaizlyhlh 1 300 train
+ohamwfscpw 1 300 train
+ohamwsxzxv 1 300 val
+ohanvmbeab 1 300 train
+ohaqlzfnuv 1 300 test
+oharjasfhu 0 300 train
+ohatitksud 1 300 val
+ohavzsoals 1 300 train
+ohawblkxip 1 300 train
+ohbausoxyg 1 300 train
+ohbbjonxye 1 241 train
+ohbkwsxtfx 0 300 train
+ohblqpjyui 1 241 train
+ohbotjrllv 1 300 train
+ohbottlrkx 1 300 train
+ohbskyezon 1 300 train
+ohbufxxsvh 1 301 train
+ohbwrsgvpz 1 301 train
+ohbyiroygz 1 300 train
+ohbywxavga 1 300 train
+ohcannkcdv 1 299 val
+ohcffsdwgu 1 300 train
+ohcjnxmuuy 1 300 train
+ohdkprpkcs 0 300 train
+ohdmchloaw 1 300 train
+ohdmktcjot 1 300 train
+ohdnzyvfid 1 300 val
+ohdtmpzbtp 0 300 train
+oheaiioatv 1 300 train
+oheajszzel 1 300 train
+oheihtgjwb 1 300 train
+oheladqefz 1 300 train
+ohesfqpeky 1 300 train
+ohetfzyiao 0 300 train
+ohfghqdclk 1 300 train
+ohfnusmqex 0 300 train
+ohfokpxnqm 0 300 val
+ohfozqywzi 1 300 train
+ohfpzxektl 1 300 val
+ohggelmndb 1 300 train
+ohgkhfboyh 1 300 train
+ohgknoiuoa 1 300 train
+ohglebsevh 0 300 train
+ohgmtkasqp 1 300 train
+ohgzhzkyle 1 300 train
+ohhaiqbles 1 301 train
+ohhczhtipb 1 300 train
+ohhncubjkn 1 300 train
+ohhwlqhezp 1 299 val
+ohhxkbwypo 1 300 train
+ohiieiswfk 1 300 train
+ohijgnwewv 1 300 train
+ohinkwamsv 1 301 train
+ohirnaqplk 1 298 train
+ohishpvvge 1 300 train
+ohjbotuzcn 1 300 train
+ohjbwqchda 1 300 val
+ohjcblseuj 1 300 train
+ohjlnzeydn 0 300 train
+ohjnmmugtm 1 300 train
+ohjqhtqelz 1 300 train
+ohjszilxwg 1 301 train
+ohkgfzugti 1 300 val
+ohknpyiysq 1 300 train
+ohkxcxiock 1 300 val
+ohkxgejaha 0 300 train
+ohlgluprcq 1 300 train
+ohljhhvqtr 0 300 train
+ohljydoxfj 1 300 train
+ohlkfryyij 1 301 train
+ohlnqjxhyj 1 300 train
+ohlnwszyfm 1 300 val
+ohlrkazatj 1 300 val
+ohlyfbqgpe 1 301 train
+ohlypraoil 0 300 train
+ohmaazefwp 1 300 train
+ohmbomcnrs 0 300 train
+ohmcrsaayi 1 300 val
+ohmeqcadci 1 300 train
+ohmfaexocy 1 300 train
+ohmfgfvfxj 1 300 train
+ohmfufuaia 1 301 train
+ohmkmcfxul 1 300 train
+ohmmdllsun 1 300 train
+ohmsurfroh 1 297 train
+ohmvmcptwv 1 301 train
+ohnnmhkmhz 1 300 train
+ohnocvcnov 0 300 val
+ohnonevlro 0 300 train
+ohnpjpuouq 1 241 train
+ohnxxjzatk 1 300 val
+ohnygpzimi 0 300 train
+ohocbeznct 1 300 train
+ohoezzotpe 1 300 train
+ohofmyydou 1 300 train
+ohopppqwkd 1 300 train
+ohorcyverg 1 300 train
+ohoryvscdz 1 300 train
+ohoxwhqaal 1 300 train
+ohpctdcahv 1 301 train
+ohpdwmuhyp 1 299 test
+ohpepbwwew 1 300 train
+ohpfcuzddj 0 300 train
+ohppxnoecg 1 167 train
+ohpqgvhsni 1 301 val
+ohpqptkahi 0 300 train
+ohptxpsivl 0 300 val
+ohpuhpvcel 1 300 train
+ohpxcywerq 1 300 train
+ohqjbjsblu 1 300 train
+ohqjkinidb 1 300 train
+ohqjlanxrz 1 301 val
+ohqugyduoe 1 298 train
+ohraninazv 0 300 train
+ohrawcomlc 1 300 val
+ohrgczqjfb 1 300 train
+ohrjukvldc 1 241 train
+ohrldmapja 1 300 val
+ohscekcqjo 1 300 train
+ohsdhpxxky 0 300 train
+ohsfimhmrm 1 300 test
+ohsjmlvxen 1 300 train
+ohspzuoxrq 1 300 train
+ohsqnjmdzr 1 300 val
+ohssphythj 1 300 train
+ohsuduorcy 1 300 train
+ohsuexvbax 1 300 train
+ohtfcukqqb 1 300 train
+ohtgaalrue 1 300 test
+ohtgqbyuxy 1 297 train
+ohtngifnek 1 300 train
+ohtocfbovi 0 300 train
+ohtxilfvgo 1 300 train
+ohumrywber 1 300 train
+ohunylgmat 1 300 train
+ohuskazqjx 1 300 train
+ohuskpbrje 1 300 train
+ohusujrkrv 0 300 train
+ohuxxtkdey 1 301 train
+ohuzzfkldf 1 300 test
+ohvbhupyzz 1 300 train
+ohvfqwoxvy 1 300 train
+ohvgsowpbl 0 300 train
+ohvhsopjko 1 299 train
+ohvkbwxklk 1 241 train
+ohvkhcckaw 0 300 train
+ohvtnavzpf 1 300 train
+ohvxhouikp 1 300 train
+ohwcabbcma 1 300 train
+ohwwmrnowu 1 300 train
+ohxakpffzs 1 300 train
+ohxfrmzlnq 1 300 train
+ohxjfjlxpv 0 300 train
+ohxrlxxzge 1 301 val
+ohxsunoiye 1 300 train
+ohxyqfgtip 1 300 train
+ohxzmopbvc 1 300 train
+ohyizhvnpr 1 300 train
+ohyjyznasc 1 300 val
+ohyktzolom 1 300 train
+ohytlxchfr 1 300 train
+ohzhpjxlzs 1 300 val
+ohzmvxbaio 1 300 train
+ohzpttgymc 0 300 val
+ohztlqzxhv 1 300 train
+ohzwoiqmmh 1 300 train
+ohzzhiodpi 1 100 train
+oiacesakaf 1 300 val
+oiakfaiqad 1 300 train
+oianwekcdl 1 300 train
+oiaoivirfx 1 300 val
+oiataegfag 1 300 val
+oiatfiiifs 1 241 train
+oiavasqizv 1 300 train
+oiawwtcfxf 0 300 train
+oibgiudhqb 0 300 val
+oibiczyubz 1 300 train
+oibovkdoht 1 300 train
+oibpqbpdkg 1 300 train
+oibrdhopxr 0 300 train
+oibtsgqujh 1 300 test
+oibttkvtvm 1 300 val
+oibuidoyss 1 255 train
+oibuofqnqx 0 300 train
+oiccyggyxi 1 300 train
+oicjcxhqyo 0 300 train
+oicopvnhrq 1 300 val
+oicpfshela 1 300 train
+oicrevmtjz 1 300 train
+oictoadzik 1 301 val
+oicwjiwxxt 1 300 train
+oiczcwnmwi 1 241 train
+oidbaqvvcs 1 300 val
+oidbljarqk 1 237 train
+oidksdtssc 1 300 train
+oidotbypqr 1 300 train
+oidthpmdmt 1 300 val
+oiefzkqjjr 1 300 train
+oiekutdwwf 1 298 train
+oietefeimp 1 300 train
+oifiecsfby 1 300 train
+oifnorczzm 1 301 train
+oifrfqrqyh 1 300 train
+oigdvwbfuz 1 300 train
+oigekiwybj 1 301 train
+oiggmpkjfr 1 300 train
+oigplhmsvb 1 301 train
+oigpxmfohm 1 300 train
+oigqeiiuqb 1 300 train
+oigvsiqjoc 1 300 train
+oigvziollp 1 300 train
+oihfthykfi 1 300 train
+oihnqftsls 0 300 train
+oihpmxfmgn 1 300 val
+oihrffzjpu 0 300 train
+oihuaskucn 1 300 train
+oihuwcliek 0 300 train
+oihvxovxfu 1 298 train
+oiihikqjna 1 300 train
+oiilknhpqy 1 300 train
+oiiltikngy 1 300 train
+oiilxmtydj 1 300 train
+oiinjyctcf 1 298 train
+oiiqooepcg 0 302 train
+oiiuowhunk 1 299 val
+oiivhktxgg 1 300 train
+oijkufnmzp 1 300 train
+oijocicvxu 1 300 train
+oijqjygibm 1 300 train
+oijrbdqexc 1 300 train
+oijtwnpzis 1 300 train
+oijxagsklo 1 300 train
+oikcenlmly 1 300 train
+oikgnmcdte 1 300 train
+oikhytmnol 0 300 train
+oikkmazrsf 1 299 train
+oikkodgjwp 1 300 val
+oiklwkjhte 1 301 train
+oikocmdhou 1 300 val
+oilbmrivdn 1 298 train
+oilbycqjoa 1 300 train
+oildclpnpu 0 300 train
+oilhrggdyj 1 300 val
+oilkyyfage 1 301 train
+oillyuobrt 1 301 train
+oilojtbqni 1 301 val
+oilrhsbanj 1 300 train
+oilsewqgmf 0 303 train
+oilsfqwnrk 1 299 val
+oiltxryhre 1 300 train
+oilwzrduyn 1 300 val
+oimdawtxix 1 300 train
+oimivjeigb 0 301 train
+oimofwlbjk 1 300 val
+oimptuagmz 0 301 train
+oimtcnblbu 1 300 train
+oimucgvqid 1 300 val
+oimvnhbyon 0 300 train
+oimwjsntjm 1 300 train
+oimxhtavvi 1 300 train
+oimxompivs 1 300 train
+oinggypaet 0 300 train
+oinhhamyyh 1 301 train
+oinlcsryjf 1 300 train
+ointiyeyat 1 300 train
+oioagqiwcg 1 300 train
+oiobzkxhop 0 300 train
+oiocwfauot 0 300 train
+oiofrwkshs 1 299 train
+oiogrjbkjq 0 300 train
+oiogvyqyrx 1 300 train
+oiohmvjvvk 0 300 train
+oiolrsuabx 1 302 val
+oiompmerks 0 300 val
+oionkojbxk 1 300 train
+oioxhypgrx 1 300 train
+oioxogxlwu 1 300 train
+oiozdaqzps 1 298 train
+oiozwvrdry 0 300 train
+oipfpxlzfo 1 301 train
+oipiedofek 1 300 train
+oipnidejww 1 300 train
+oiprhjzheh 1 300 train
+oipxtufbmu 1 300 train
+oiqafijewi 1 299 test
+oiqbnoptif 1 300 test
+oiqfiooodk 1 298 train
+oiqpelxhkp 0 300 train
+oiqrpafzlx 1 300 train
+oiqvzbywoz 1 300 train
+oiqwlkguhj 1 300 val
+oiravfidiu 1 297 train
+oiremrvjbs 1 300 train
+oirfkzwfmj 0 297 train
+oirgusnios 1 241 train
+oirmxctmvs 0 300 train
+oirqrzbhbg 1 300 train
+oirqwdrmbv 1 300 val
+oirtumfsar 1 300 train
+oirvlkospn 1 300 train
+oirwhjbqcx 1 300 train
+oirxdvllpl 1 300 train
+oirzpbvtsc 1 300 train
+oisawcxxab 1 300 train
+oisdkmdsft 1 300 train
+oiseyvgouu 1 300 train
+oisfiaillm 1 300 test
+oisiorgsau 1 300 train
+oisiyudtkv 0 300 train
+oisjtoumuu 1 300 train
+oisprqtmce 1 299 train
+oisrptbamr 1 300 train
+oiszifqloq 1 300 train
+oisztpucxp 1 300 train
+oitcqmvnsa 1 300 train
+oitfjlwpqu 1 300 train
+oitgrqfwvn 1 300 val
+oitgyzoakj 1 301 val
+oitjtxrffs 1 300 train
+oitlkdosie 0 300 val
+oitockkykw 0 300 val
+oitpfxwgiz 1 299 test
+oitqddnspw 1 300 train
+oitrjyjsts 1 300 val
+oitsembcaw 1 300 train
+oittxxvlzx 1 300 train
+oitufpplvc 1 300 train
+oitxhwlgis 1 300 train
+oitybyvsce 1 300 train
+oitzjesvlx 1 300 train
+oiucehczou 1 300 val
+oiudsgbkyx 1 298 train
+oiupvmfdwq 1 301 val
+oiutlrmcfv 1 300 val
+oiveokjspk 1 300 val
+oivfuwsgar 1 300 train
+oivgyuzthp 1 241 train
+oiwbkxlbyc 1 300 train
+oiwcusszoz 1 300 train
+oiwgdplgju 1 300 train
+oiwjqfwrsf 1 300 train
+oiwosxqzqp 0 300 val
+oiwudwxevw 1 297 train
+oiwvgfyplw 1 300 train
+oixbmyzhev 1 301 val
+oixcwrkzte 1 300 train
+oixjbwzqvn 0 300 train
+oixqnpxgza 1 300 train
+oixygmjiwg 1 300 train
+oixzlbfean 1 300 train
+oixznooelj 1 300 train
+oixzsakbwl 1 300 train
+oiyewsuhoj 1 298 val
+oiyidmvmge 1 300 train
+oiylihmnsl 0 300 train
+oiysfgeifc 0 300 train
+oiysuizjdo 0 300 train
+oiytjybsxo 1 300 val
+oiyuisookv 0 300 train
+oizeltxdna 1 300 train
+oizgennqfn 0 300 train
+oizgiyaphb 1 300 train
+oizgrthylf 1 300 val
+oizkxentmu 1 301 val
+oizliasvax 1 300 train
+oizmfyqqkj 1 300 val
+oizmzniadv 1 301 train
+oizobhdkkn 1 300 train
+oiztpcrlqs 0 300 train
+ojadcnlsno 1 300 val
+ojagblcuat 1 300 val
+ojagvrntgw 0 300 val
+ojalowgroo 1 300 train
+ojanzjnopb 1 300 val
+ojaoquzovc 1 300 train
+ojaqchuykw 1 300 train
+ojayvjcdna 1 300 test
+ojbdddhnwc 1 300 train
+ojbinapzqz 1 300 train
+ojbnddjuzy 0 300 test
+ojbxyemvzp 1 241 train
+ojbzbrwufi 1 296 train
+ojcbytzqyq 1 301 val
+ojcjshvhny 1 300 train
+ojckzdsylk 1 300 train
+ojcpsqzulv 1 300 train
+ojcutnkyhp 1 300 train
+ojcvdrnsry 0 300 train
+ojcvsfjvtt 1 241 train
+ojdasshcfi 1 300 train
+ojdcnamnbu 1 298 val
+ojdeleaqdr 1 300 train
+ojdoramflb 1 300 train
+ojdrqflslr 1 300 val
+ojdxcntccc 1 300 train
+ojdxdewxbu 1 300 train
+ojefspxyxr 1 269 train
+ojehmzwupf 1 300 train
+ojenhiliko 1 300 train
+ojenqjrftj 1 300 val
+ojeswibpis 1 300 val
+ojettodhul 1 300 train
+ojeytojvzo 1 292 train
+ojffloftih 1 300 val
+ojffpkrdpf 1 300 train
+ojfgmpmwqk 1 300 train
+ojfgrnmtaj 1 239 train
+ojfhecabkn 1 301 val
+ojflrkzrte 1 300 train
+ojflyjrsks 1 300 val
+ojfmzzwhkg 1 241 train
+ojfqbqihfa 1 300 val
+ojfxeemhxz 1 300 train
+ojgckrpqgt 1 300 train
+ojgetwmygj 0 300 train
+ojgqahuaok 1 300 val
+ojgvofahtf 1 300 train
+ojgwhscpoa 1 300 train
+ojhhvdfarw 1 300 train
+ojhhygepag 1 300 train
+ojhikvniox 0 300 train
+ojhmlqvpgt 1 300 train
+ojhmqnchvz 1 300 train
+ojhowiiaws 1 239 train
+ojhruwbrrq 1 300 train
+ojhtkybbph 1 300 train
+ojhtormkdm 1 300 val
+ojhxltxycg 1 301 train
+ojhzppasfk 1 300 train
+ojictegbbf 1 300 train
+ojilgzmked 1 300 train
+ojimgiumme 1 301 val
+ojiocbyazp 0 300 train
+ojiqyqqeof 1 300 val
+ojirnpashi 1 300 train
+ojitdmtpvv 1 300 train
+ojitvwmijd 0 300 val
+ojizcnxvjm 1 300 train
+ojjaajdzhv 1 299 train
+ojjchcqzsp 1 300 train
+ojjdcomvfn 1 300 train
+ojjkapcqls 1 300 val
+ojjmbrjpzh 1 300 train
+ojjucgcldd 1 300 train
+ojjypdygmp 1 300 train
+ojkimdyipt 1 300 train
+ojklaajnpj 0 300 train
+ojkpuxkcsw 1 300 train
+ojkwflqyen 1 300 val
+ojlavlnptg 1 300 train
+ojlcnmtnwo 1 300 train
+ojldcyezun 1 297 val
+ojldeigrnr 1 241 train
+ojlmhsjqoc 1 299 test
+ojlorcjfex 1 300 train
+ojlpuchxdp 1 300 train
+ojlsrhsecd 1 300 train
+ojlxhospsm 1 242 train
+ojmcamhpcz 1 300 train
+ojmjfqccij 1 300 train
+ojmrgskuvx 1 300 val
+ojmrjfeiij 1 300 train
+ojmrvaqqbt 1 300 train
+ojmwqqxjzk 0 300 train
+ojmxlrtmdb 1 300 train
+ojmzeaywwf 1 300 train
+ojmzinvfgy 0 300 val
+ojnidsttay 1 300 train
+ojnkrlzemh 1 300 val
+ojnkwmlpaj 1 300 train
+ojnmfsnwkn 1 300 train
+ojnvessbqr 1 300 val
+ojnywiloxs 1 300 train
+ojoazrcrcv 0 300 train
+ojocqwolhk 1 300 train
+ojoecorksr 1 300 train
+ojojjbsuqj 0 300 val
+ojolkgbexx 1 300 train
+ojooqawlyu 1 300 val
+ojopezsqmx 1 300 train
+ojornmqizc 1 301 val
+ojoulkkydk 1 300 train
+ojptcnaztx 1 300 train
+ojpuotwlya 1 300 train
+ojpvmxgxrn 1 297 train
+ojpwgsamlt 1 301 train
+ojpxakaesx 1 300 train
+ojpyddpthd 1 300 train
+ojqaffhyse 1 300 val
+ojqaruboei 1 300 train
+ojqcwtvvkp 1 299 test
+ojqjomykky 0 300 val
+ojqmnevvfw 1 300 train
+ojqoiycaaz 0 300 train
+ojqwqkcibi 1 300 train
+ojravfhiwk 1 300 val
+ojrdptzhkf 1 298 train
+ojrjdfniha 1 300 val
+ojrpdwhwkx 1 300 val
+ojrqmfkxcs 0 300 train
+ojrrnfzoks 1 300 train
+ojrsovhzxv 1 300 val
+ojrvajrmuf 1 300 train
+ojrwklhxok 1 300 train
+ojrzheoxfj 0 300 train
+ojslpnejkq 1 300 train
+ojsptylexg 1 300 train
+ojssrtnase 1 301 train
+ojsuevypkx 0 300 train
+ojsvcvwrol 1 300 val
+ojswrkgezt 1 300 train
+ojswuysbxh 0 300 val
+ojsxxkalat 1 300 test
+ojsydwghji 1 300 train
+ojsyoevyul 1 300 train
+ojtdfobvre 1 300 train
+ojtdurbejd 1 300 train
+ojtjlqlbdb 1 300 train
+ojtmqhqgmd 0 300 train
+ojtorcuxll 0 300 train
+ojtsaaxmhz 1 300 val
+ojtxlznvfl 1 300 val
+ojuhklwakz 1 300 val
+ojuldyhkhv 1 300 val
+ojulnlzmso 1 300 train
+ojuqbndxro 1 300 train
+ojuqtjcfvm 1 300 train
+ojuymkssiu 1 300 train
+ojuywnpxdm 1 300 val
+ojuyxrireq 1 300 train
+ojvackhebv 0 300 val
+ojvlojhqed 1 300 train
+ojvoapwfpm 1 300 train
+ojvpuhxpzx 1 300 val
+ojvqqhggla 1 300 train
+ojwahapaxy 1 300 train
+ojwgkvgiot 1 300 train
+ojwlticwca 1 300 train
+ojwrwcizkz 0 300 train
+ojwrwdhdfx 1 300 train
+ojwxkpqbbr 1 300 train
+ojwztgooqv 0 300 train
+ojxatfjhjg 1 300 train
+ojxbrpoihy 1 300 val
+ojxejcoufe 1 302 train
+ojxeusdtmm 1 300 train
+ojxmxpfuxg 1 300 train
+ojxqyyeqnw 1 300 train
+ojxrkovede 1 300 train
+ojxteshhhu 1 301 val
+ojxxzocrpt 1 300 train
+ojyacvpwry 1 300 train
+ojyazraovz 1 300 train
+ojybpypdln 1 300 val
+ojylfhidke 1 300 train
+ojynwshpjk 1 296 val
+ojypmftikg 0 300 train
+ojyrxbxgky 1 300 train
+ojywhqdfnr 1 241 train
+ojyxewdviz 1 240 train
+ojyxspwzhq 1 298 train
+ojyxyomgpu 1 302 train
+ojyzbzawps 1 300 val
+ojzajduden 1 300 train
+ojzbsuvrts 0 300 train
+ojzhlajkrh 1 300 val
+ojzifocjwr 1 300 train
+ojzppycgvg 1 300 train
+ojzqvmnriv 0 300 train
+ojzwrwwyio 1 300 val
+okackvcdds 1 300 train
+okaeghhtdk 1 301 train
+okagfzyggi 1 300 train
+okalyrfbcz 0 300 train
+okarhweycf 1 300 val
+okazfvsmse 1 300 train
+okbarlnmwm 1 300 train
+okbcxmaqbo 0 300 train
+okbddajder 1 300 train
+okbfcvxojs 1 301 val
+okbyjqosxj 1 255 train
+okbyzbldcy 0 300 train
+okcasglgvo 1 300 train
+okcdbmsusn 1 300 val
+okcqnwrcmh 1 300 train
+okdaolbilh 1 301 train
+okdbicafxu 1 298 train
+okdicgtxsb 0 300 train
+okebcifotg 1 300 val
+okebdsxqvf 1 300 train
+okebppwpzs 1 298 val
+okegqbwvve 0 300 train
+okeimfxnmh 1 298 train
+okelkcnkvv 1 300 train
+okesgxjoej 1 300 val
+okeyrdiept 1 300 train
+okfanujisw 1 300 train
+okfinkhovh 1 300 train
+okfitgsukn 1 298 train
+okfjnnozuz 1 300 train
+okfrzbdcat 1 298 train
+okgbaygetj 1 300 train
+okgbhxkynh 1 300 val
+okgelildpc 1 300 test
+okgheddknx 1 300 val
+okglsiwizj 1 300 train
+okgoflrwph 0 300 train
+okgrsopppw 0 300 val
+okgzwzlasg 1 300 train
+okhfribkrr 1 300 train
+okhhmztzsf 1 300 val
+okhirwvpbw 1 298 train
+okhtzfnfff 1 300 train
+okhugxlaoa 0 300 val
+okiesquksn 1 300 train
+okijphsdtt 1 301 train
+okirhpyshr 1 300 train
+okitloehws 1 299 val
+okiudgsyng 1 300 train
+okivnefwqy 1 300 train
+okixfxcyim 1 300 train
+okjgvmdvph 1 298 train
+okjhfifjkr 0 299 val
+okjjlzkmud 1 301 train
+okjmzqeawq 1 300 train
+okkjhnevjd 1 300 train
+okklerwsnc 1 297 val
+okkotojkqf 1 300 train
+okkppsyymp 1 299 val
+okkrkoatis 1 300 train
+okkyysftyq 0 300 train
+okkzguiwlj 1 300 train
+oklabgtbqj 1 300 val
+oklcemyvrz 1 300 val
+oklebptrhl 0 301 train
+okleitalcw 1 300 train
+oklfahbqif 0 300 train
+oklitoepwa 1 292 val
+okllegwaop 1 300 train
+oklnlbtyxy 1 300 train
+oklqybrmhv 0 301 train
+oklrzugipc 1 300 val
+oklsuetnrd 1 300 train
+okltnuqfol 1 298 train
+okluiruxjy 1 302 train
+oklzhpdjmo 1 300 train
+okmhdmfdlh 1 300 train
+okmjwmeswh 1 300 train
+okmlcbefeu 1 300 train
+okmqucjlso 0 301 train
+okmwufewfb 1 300 train
+okmyzqbuiq 0 300 train
+okndkghlvh 1 300 train
+oknfbpcqqz 1 300 train
+oknkjpbcra 1 300 val
+oknovpajeb 1 300 train
+oknsfvqqfo 1 300 train
+okntpqqfrw 1 300 train
+okntuhavel 1 300 train
+oknxowqcvn 1 300 val
+okoueyswyl 1 300 test
+okouvrwunn 1 300 train
+okpfhsgahc 1 300 train
+okpiknxasj 1 300 train
+okpndbulck 1 300 train
+okpnmxnvhi 1 300 train
+okpvvzzibm 1 300 train
+okpzntrqkc 1 300 train
+okqaqesrul 1 300 train
+okqhqeuxxp 1 300 train
+okqmlpxson 1 300 train
+okqrvkecxk 1 300 val
+okquvuujlu 1 239 train
+okrcmmllkg 1 300 train
+okrgeubcph 1 300 train
+okrinvhnzg 1 300 val
+okrjfzrsla 1 300 train
+okrmitowjf 0 300 train
+okrqqppbjm 0 300 train
+okrrtlhqlz 1 299 test
+okrtdomibp 0 300 train
+okrtipbqbq 1 300 train
+okrvtlxltu 1 300 train
+okrxijdnnp 1 300 train
+okscalwxzb 1 300 train
+oksgazbawn 1 300 train
+oksjjthgyq 1 300 train
+okskuwwics 1 300 val
+okslzmfrbd 1 299 val
+oksphujxmc 1 300 train
+oksteyiysx 1 300 val
+oktclksytw 1 300 train
+oktcujefyf 1 300 train
+oktfjzznny 1 300 train
+oktglkuhkr 1 300 train
+oktgnpoelx 1 300 train
+oktmfdthkl 1 300 val
+oktogiqzrt 1 300 train
+oktprtsbfl 1 300 train
+okttkcsjou 1 301 val
+okubqwajpe 0 300 train
+okuibbfohb 1 300 train
+okuxkniigh 1 288 train
+okuxrjvcgq 1 300 val
+okuxypqhpm 1 300 train
+okvcsurxoz 1 300 train
+okvfljyiel 1 300 train
+okvfyiarxb 1 300 val
+okwbecwied 1 300 train
+okwbmythvs 1 300 train
+okwfizlgml 0 300 train
+okwgsisgwn 0 301 train
+okwivofbnd 1 300 train
+okwxfnpdfj 1 300 train
+okwzrxvnqq 1 300 train
+okxgxnrnbh 1 300 test
+okxhyxqwno 1 300 train
+okxmoanvkb 1 300 train
+okxojybctj 1 300 val
+okxqmyinjf 1 300 train
+okxrkhzqva 1 300 train
+okxrmnqsjp 1 300 train
+okygdtttah 1 300 train
+okyiroviaz 1 300 train
+okykjekhtf 1 300 val
+okylnqwhbm 1 301 train
+okynhwegmp 1 300 val
+okyqibtvge 1 300 val
+okyufzgvay 1 300 train
+okyxbhzklr 1 300 train
+okyygzflvk 1 301 train
+okzfyjgzgb 1 300 val
+okzjmogdvj 1 300 train
+okzopdyhot 1 300 train
+okzriilplc 1 300 train
+okzsakbvfk 1 300 train
+okztydaxqm 1 300 train
+okzxerhjxy 1 300 train
+olabdqzebq 1 300 val
+olacrmzrjg 1 300 train
+olafodcahi 1 300 val
+olakcrnuro 0 300 train
+olamtmlblj 1 300 val
+olanjvskzc 1 300 val
+olbarmbqpp 1 300 train
+olbekbspkv 1 300 val
+olbevmqltf 1 300 train
+olbidfmvld 1 300 train
+olbwirykbf 1 300 train
+olbyukmrdf 1 300 train
+olcgbybaxi 1 301 train
+olchsmmyjj 1 300 train
+olcixmadwc 1 300 train
+olczadekwi 1 241 train
+oldaipeaqt 1 301 train
+oldcloattz 1 300 val
+oldicbeuaa 1 301 train
+oldlcsvlpv 1 300 train
+oldrywdygw 1 300 train
+oldtafzhde 1 300 train
+oldvaioqvq 1 300 train
+oldwsggyaw 1 300 val
+oldwuwtiui 1 300 train
+oldzdbgzmw 1 300 train
+olebnvxoyl 0 300 train
+olecwjcvmz 1 300 val
+oleepraewl 0 300 train
+olegakwwlb 1 300 train
+olegoclzyr 1 301 val
+olenwxclmf 1 297 train
+olfanhpiaj 1 300 train
+olflffvlup 1 300 train
+olfotakxys 1 300 train
+olfuwgqxdy 1 300 train
+olfxekxtpn 1 241 train
+olfxrsknkx 1 300 val
+olfzsjgedd 1 300 val
+olgaicgeax 1 300 train
+olgbljtutz 1 300 val
+olggqyesne 1 300 val
+olgnkctgdg 1 302 val
+olgtvklzeu 1 300 train
+olguyoivho 1 300 train
+olheajbvle 1 296 val
+olhiyewffl 1 300 train
+olhmxytcyj 1 298 train
+olhredpggz 1 300 train
+olhvxkstwl 1 300 train
+olhwbczcgt 0 300 val
+olianjbqsi 1 300 val
+oliayodelk 1 302 val
+oliigwfyvt 1 300 train
+olikbfeqyu 1 300 train
+olinrvqtyz 1 300 test
+olioguvafe 1 300 train
+olirnmrrwy 1 301 val
+oliwoxrsfu 1 300 val
+olixgkqwcq 1 300 train
+oliyjlypid 1 300 val
+oljbrcgwlh 1 300 val
+oljvsbwrhn 1 300 train
+oljwcxiqlq 1 298 train
+oljyhwonyj 1 300 train
+olkbmbnoqo 1 300 train
+olkcmrmvbh 1 300 train
+olkrkcrhcx 1 300 train
+olktzqzoxo 1 300 train
+olkxmovjxa 1 300 train
+olkyijzubh 0 300 train
+olleeauetp 1 300 train
+ollitendxk 1 300 train
+ollnhyirqt 1 301 val
+ollpdsvksf 1 300 val
+ollprramzh 1 300 train
+ollunrhvpk 0 300 train
+olmkztlhss 1 300 train
+olmlbokeym 1 241 train
+olmnbwprjp 1 300 train
+olmndbetml 1 300 test
+olmufavhbl 1 300 train
+olnegzoimk 1 300 val
+olngpzdvwr 1 301 val
+olnikyoxmv 1 300 train
+olnlxkanpq 1 300 train
+olnpzamrez 1 300 train
+olohhmmdaz 1 298 val
+ololvouvmy 1 300 val
+olonwmahgp 1 301 val
+olootfqrmt 1 300 train
+olopqblnpo 1 300 train
+olouirnmle 1 300 val
+olovespbfy 1 300 val
+olpfnnwmri 1 300 train
+olpipxjxqf 0 300 train
+olpjobfdqc 0 300 train
+olpkgxdqih 1 300 train
+olpmsspiva 1 300 train
+olpoagoucj 1 300 train
+olppmgcwgc 1 300 train
+olputntqjg 0 300 train
+olqctxmttw 1 300 test
+olqklntoju 1 300 val
+olqnjjfoyf 1 300 val
+olqquuhbhc 1 300 train
+olqshoikjs 0 300 train
+olqumripli 1 300 val
+olqxsxieuu 1 301 train
+olqydtewpe 1 298 train
+olrssrqege 0 300 train
+olruhyohvl 0 300 val
+olrulxguui 0 301 train
+olsbyvmxeo 1 301 train
+olsfnscnfb 1 299 val
+olsgmqlgdk 0 300 train
+olsiddqsqa 1 302 train
+olslsldbob 1 299 val
+olswcryavu 1 300 train
+olsxidphhj 0 300 train
+olsyyvlboz 1 300 train
+olszsqatof 0 300 train
+olszypzpro 1 300 train
+oltalqthyz 1 300 train
+oltbfqntaq 1 300 train
+oltexwbmjq 1 300 train
+olthkdzvzx 1 300 train
+oltjahgizr 1 300 train
+oltqvzdqnb 1 300 train
+oltvidrazd 1 300 val
+olufivknxv 1 300 train
+oluluzpcmq 1 298 train
+oluoopnctw 1 240 train
+oluphqqpsb 1 300 train
+olurfjfbcf 1 300 train
+oluyiucqss 1 301 train
+olvgikplou 1 300 train
+olvhqcpnvq 1 300 val
+olvjftfahz 0 300 train
+olvrdzyzhb 1 300 val
+olwccjkxna 1 300 train
+olwhakyyau 0 300 train
+olwlnlmkfw 1 300 train
+olwmrlywjx 1 300 train
+olwsfvjqoc 1 300 train
+olwukylloa 1 300 train
+olwvckswme 1 300 train
+olwxhotbsj 0 300 val
+olwxxevrto 1 301 train
+olxfrrwxek 1 300 test
+olxmwkypcn 1 301 train
+olxqodazsv 1 300 train
+olxrsgtnrt 1 300 train
+olxuxttfce 1 300 train
+olxvejxqcq 1 300 train
+olxwwpeiqu 1 300 val
+olxxvrlrsk 1 300 train
+olyndjrmex 1 297 val
+olysqkcxlx 1 300 val
+olyxerqshs 1 300 val
+olyyoxoylf 0 299 val
+olyyzxuogv 1 301 train
+olzjecehcq 0 300 val
+olzkwxrlzf 1 301 train
+olzrcqlblz 1 241 train
+olzrgcrgop 1 300 train
+omaabqsujm 1 300 train
+omabkwmwvh 1 301 train
+omaggoyqnu 0 300 train
+omavgmbdfb 1 298 val
+omawvauhig 1 236 train
+ombfehyjxv 1 300 train
+ombuuqhceb 1 300 train
+ombwzzhhhk 1 300 train
+omcdamjshk 1 300 train
+omceymdank 1 296 train
+omcfiyorcc 1 302 train
+omcjdzoqyt 0 300 train
+omcofcmzll 1 300 train
+omcppqqvem 1 300 train
+omcyntlcjf 1 300 val
+omdjjdssjx 1 298 train
+omdprgfuii 1 300 train
+omdwriqrpp 1 300 train
+omeacljwty 1 300 train
+omecqbbviq 1 301 train
+omeeiavbhk 1 300 train
+omefspbgqm 1 300 train
+omevhssnvx 0 300 train
+omfixgpkdz 1 300 train
+omflghsojd 1 300 val
+omfnfjycik 1 300 train
+omfnvaihmv 1 300 train
+omfqrxsgtw 1 300 val
+omfsuzvgxn 1 300 val
+omfvhpdvio 1 300 train
+omfwrusaqd 0 300 train
+omgauauhzo 1 300 train
+omgcydugep 1 300 val
+omggotplak 1 300 train
+omgiyacrrj 1 241 train
+omgkxzclff 0 300 train
+omgltyzcep 1 300 train
+omgozkenhu 1 297 train
+omgupchlyb 1 300 train
+omgxgxelth 1 300 train
+omgxlpgxar 1 300 val
+omhaalckdd 1 300 train
+omhqksxhxb 1 300 val
+omhqzvwltt 1 300 train
+omhsncezty 1 300 train
+omhtuhxmbm 1 301 train
+omhuumpxaw 1 300 train
+omhziynqka 1 300 train
+omhzxmlgqd 0 300 train
+omihpppgbg 1 300 train
+omiicbvxpz 1 300 train
+omiqlapspf 1 249 train
+omizcfnsic 1 300 test
+omjcqdgaer 0 300 train
+omjjumnzpm 1 300 train
+omjsnpwomu 1 300 val
+omkaqwosqj 1 300 train
+omkbbtdvmk 1 300 train
+omkeeybmrc 0 300 val
+omkvaclfcz 1 300 train
+omkzlprxmf 1 300 train
+omlbujfcnj 1 300 train
+omldkwpzwx 1 300 train
+omlftudlje 1 296 train
+omljcgdsfk 1 298 train
+omlmfbrurg 0 300 train
+omlsbyypkr 1 300 train
+omlvlllncs 1 300 train
+omlwjsptgg 1 300 train
+ommdwvhwzg 1 300 train
+ommfpsjbfj 1 300 val
+ommvnsljtz 1 300 val
+omnearznmi 0 300 val
+omnieyidxe 1 300 train
+omniwudjjb 1 300 val
+omnuhgdgwt 1 300 train
+omodwoqqhv 0 300 train
+omofhfkeck 1 300 val
+omofkgvjyn 1 300 train
+omonptfuas 1 300 val
+omotodymgb 1 300 train
+omouxcqajy 0 300 train
+ompewhuois 1 241 train
+ompgnszdng 1 300 train
+omphglkwem 1 301 train
+omphqltjdd 0 300 test
+ompiehpmrl 1 300 train
+ompjlvbtmw 0 300 train
+ompknvthvu 0 300 train
+ompmhluiyc 1 300 train
+ompoqjuzmm 1 300 train
+ompupvrqbu 1 300 val
+ompwgsngan 1 300 train
+ompyqcitmj 1 300 val
+ompyrqhuuv 1 300 train
+omqdyndjrq 1 300 train
+omqmuozzld 1 300 train
+omqqahldhc 1 301 val
+omqsxaxles 1 300 train
+omqygviyld 1 301 train
+omrcrmiknk 1 300 train
+omrhclwaix 1 300 train
+omrnigclqj 1 300 train
+omroozvfre 1 300 train
+omrrtonofo 1 300 train
+omrtielsni 1 300 test
+omruvyshqv 1 300 train
+omsdjjsoge 1 300 val
+omsrabdtnu 1 300 val
+omtcbfkumq 1 300 train
+omtkpavvjx 1 300 train
+omtlvmbtto 0 300 train
+omtmwizecw 1 300 val
+omtnalawgc 1 300 train
+omttirmjex 1 300 train
+omtwfillar 1 300 train
+omtzobnqys 1 300 train
+omublmrsuz 0 240 val
+omucyzhlwt 1 269 train
+omulfnnaal 0 241 val
+omuxfsyfrj 1 240 val
+omvfwttfwm 1 300 train
+omvhoougii 1 300 train
+omvirtyjge 1 300 train
+omvsfqhqou 1 300 train
+omvyiatilz 1 300 train
+omwhsfiffq 1 300 val
+omwnhxqyjc 1 301 train
+omwrpgmsad 0 300 val
+omwshllujo 1 299 test
+omxcghyend 1 300 train
+omxgzfgigg 1 300 val
+omxhxkqohv 1 300 val
+omxjqbbsjp 0 300 train
+omxovghlqa 1 300 train
+omxpnkkokq 1 300 train
+omxvstrmhv 0 300 train
+omyfionqph 1 301 train
+omyhxclgkl 1 300 val
+omyicmcbbu 1 300 train
+omyjjbseli 1 300 train
+omyljadvpr 1 300 val
+omynanvctc 1 300 train
+omyszbwxbs 1 300 train
+omytlpzopy 1 300 val
+omyvobiemd 1 300 val
+omywaxdvwu 1 300 train
+omywprxiga 1 300 train
+omyykafihi 1 298 train
+omzbvjzrdy 1 300 val
+omzdgqhpnl 1 300 train
+omzofhdxrf 1 300 train
+omzthunciu 1 300 val
+omzttvdbva 1 299 test
+omzwehodud 1 300 train
+omzwsxdvyi 1 300 train
+omzxdzsssb 1 300 train
+onabrugqce 1 300 train
+onaewxqqkd 1 300 train
+onagcholps 1 300 train
+onamfppxfu 1 300 train
+onampwjnne 1 300 train
+onamslbzbj 1 296 train
+onamvpxumf 1 300 val
+onanezqlke 1 300 val
+onanqtsdjk 0 300 test
+onaveztzed 1 300 train
+onavgkayge 0 300 train
+onawpuycug 1 298 val
+onbfpiklki 1 300 val
+onbgbghesu 0 300 test
+onbgdxjkjx 1 300 train
+onbgqzocfy 1 297 train
+onbhvlmihd 1 300 val
+onbihoohtx 1 300 train
+onbillmrth 1 300 train
+onbjoadugg 0 300 train
+onbpawtkeu 1 300 train
+onbvolwtdp 1 300 train
+onbxelnbdg 1 301 val
+onccdzxcqh 1 300 train
+onchjseuec 1 300 train
+oncjwhsgas 1 300 train
+oncogvnkab 1 300 val
+oncqnrruuw 1 300 val
+oncrhjcgln 1 300 train
+onctxamdum 0 300 train
+ondaioswxt 1 297 val
+ondemwjhkt 1 300 train
+ondezmgykk 1 299 train
+ondhgghktg 1 300 train
+ondhkjvvoj 1 300 train
+ondkkapdcb 1 300 train
+ondpojctbi 1 300 val
+ondpqdolhg 1 300 train
+ondrruihyu 0 300 train
+ondvbgcsyq 1 301 train
+ondwevgwfm 0 300 val
+ondwspvliv 1 300 val
+oneevoyahb 0 300 val
+onegazlwgn 1 300 val
+oneizjknqm 1 300 val
+onelbrxypo 1 300 train
+onepaeivvr 1 300 test
+oneqrnpzjg 1 300 train
+oneqztownt 1 300 val
+onesoycvnp 1 300 train
+onewdbuehd 1 299 test
+onewxhcbxl 1 301 train
+onexhsspsl 1 300 val
+onexxlxsob 0 300 train
+onfcbmuktx 1 300 train
+onfculxhtr 1 300 train
+onffvuobqo 0 300 val
+onfuucdgui 1 300 val
+ongakdqvrc 1 300 train
+ongcmveggf 1 300 train
+onglnczpnv 1 300 train
+ongutcrqme 1 300 train
+ongypsaevx 1 300 train
+onhcgxgble 1 300 train
+onhfwknfro 1 300 train
+onhhgzsrvo 1 167 train
+onhorpulda 1 300 val
+onhriqkenu 1 300 train
+onhrqiwqgh 1 300 train
+onhthjbayk 1 300 val
+oniyuokicx 1 302 train
+onjgoxtmiq 1 300 train
+onjihwnfqm 1 300 train
+onjinaahul 1 300 train
+onjldfssra 0 300 train
+onjndgfbkw 1 300 train
+onjpsstiuq 1 299 val
+onjqmwyewq 1 300 train
+onjssjcddo 1 300 val
+onjundhlxa 0 300 val
+onkcpfxldr 1 300 val
+onkfcftkoz 1 300 train
+onkgvpzzli 1 300 train
+onkjfuhhol 1 300 train
+onkkwebcuf 1 300 val
+onknhowfqb 1 300 test
+onkvupoapt 1 300 train
+onkxxnyyla 0 300 train
+onlaexzolo 1 300 val
+onleprzynp 1 300 train
+onlhjlvzvl 1 300 train
+onlitrixto 1 300 train
+onlpjkmwwr 1 300 train
+onlzlhuzuy 1 301 val
+onmpqutdgo 1 300 train
+onmtxdjrin 1 300 train
+onmvidaewf 1 301 train
+onmwnvjevh 1 300 train
+onmyonvlbw 1 300 train
+onmzudmwze 1 298 val
+onnbnuskcj 1 300 train
+onnhzcjrez 1 301 train
+onnpghvisw 1 300 train
+onnrrbvaoc 1 300 train
+onofcghoat 1 300 train
+onojshreyv 0 299 val
+onoowfeded 1 299 test
+onoroxvlxe 1 300 train
+onotjxcvoj 1 300 train
+onotmddzhj 1 301 val
+onottzzoib 1 300 train
+onoxzuesym 1 302 val
+onoyyvnxbs 1 300 train
+onozottyon 1 300 train
+onozukvxyj 1 298 train
+onpcjkzyoa 1 299 train
+onplxaturx 1 300 train
+onppqzpbaw 1 299 train
+onprahphaz 1 299 train
+onptnfefnx 1 300 train
+onqbpyrtlh 1 300 train
+onqfohuqip 1 299 val
+onqhkapmwn 1 300 train
+onqldydruc 1 300 train
+onqllyizpf 1 298 train
+onqsufbvnm 1 300 val
+onrabvhfsl 1 300 train
+onrfbznpew 1 300 train
+onrhqvetxa 1 300 train
+onriysxjws 0 300 train
+onrlpcuzir 0 300 train
+onrqndzzfk 0 300 train
+onrwqixejl 1 300 train
+onrzkraexi 1 300 train
+onsamvcafc 1 300 val
+onsawuadcg 0 300 val
+onsjqisgbt 1 301 train
+onsjvpniat 1 300 train
+onslebjxyp 1 300 val
+onsrfcenzg 1 300 val
+onsvqlwjgw 1 300 train
+onsxznhftc 1 300 train
+ontoieaefb 1 300 train
+ontubjvsrx 1 300 val
+ontufesvli 1 300 train
+onuadbcgzf 1 298 train
+onuhsbmfaj 1 300 train
+onurdtdwew 1 300 train
+onusvwphyt 1 300 train
+onuswinobs 1 300 train
+onuzugluyf 1 300 train
+onvczpoemg 1 300 train
+onvjtdquwl 0 300 train
+onvswuxuok 1 301 train
+onwhtirmce 1 298 train
+onwmeqsslw 1 300 train
+onwpirpbdt 0 300 train
+onwszftnwj 1 300 train
+onwuhohdjn 1 300 val
+onwumaoshv 0 300 train
+onwvpxcabr 1 300 train
+onwzxyouet 0 300 train
+onxckqkgjh 1 300 train
+onxdyexufh 1 300 train
+onxepzyurl 1 301 val
+onxgqvzpht 1 300 val
+onxjcmidvu 1 300 train
+onxjxcfcmd 1 300 train
+onxpthoczj 0 300 train
+onxrwylxbh 1 300 val
+onxwyfyjmv 1 241 train
+onxzsmyagg 1 300 train
+onyaiipubw 1 300 train
+onyecbzgmi 0 300 val
+onyemomoug 0 300 train
+onygmnjhph 0 301 train
+onyizaqvif 1 300 val
+onyngdxyen 1 300 val
+onysopsoch 1 241 train
+onywiqrpou 1 300 train
+onyydbkdue 1 300 train
+onzrbjeqvb 1 300 train
+onzrmrwili 1 300 val
+onzrvkhmzz 1 300 train
+onzxroudok 1 300 train
+ooackdhquw 1 300 train
+ooafcxxfrs 0 299 test
+ooafdtvatu 1 300 train
+ooarfstzxd 1 301 train
+ooavdkhcnf 0 301 train
+ooaxwmilyd 1 300 train
+oobcrqikih 1 300 train
+oobeaklccb 0 300 test
+oobmorozgk 1 300 test
+oobviyybtb 1 300 train
+oobxxnohbf 1 300 train
+oobzybjtul 1 300 train
+oochdgckho 1 300 train
+oocincvedt 0 300 test
+oocmtgslck 1 300 train
+oocqjchiih 1 300 train
+oocvlktamt 1 290 train
+oocyvcsziv 1 300 val
+ooczenomzk 1 300 val
+oodapnhybc 0 300 train
+oodkwsfekb 1 249 train
+oodmaihbgq 1 300 train
+oodphlttej 1 300 train
+ooeawbvoyo 0 300 train
+ooeawvpwct 1 300 train
+ooedijmplb 1 299 val
+ooeejwslmx 1 301 train
+ooeemdynht 1 300 train
+ooejhirbjl 0 300 val
+ooeopkhgnw 1 241 train
+ooepvekhxu 1 300 val
+ooeqgtqomh 1 301 val
+ooeyhoyxxf 1 300 train
+ooezdbgdse 1 300 train
+oofdvzymxr 1 300 train
+oofffbxkjy 1 241 train
+oofiogwceg 1 300 train
+oofldkgyns 1 300 val
+ooflqxghgs 0 300 val
+oofltqijvc 1 300 train
+oofncpjpnk 1 300 train
+oofprjtqiq 1 300 train
+oofvlqdfmr 1 300 train
+oogbcrdgwj 1 300 train
+oogegpcqlh 1 300 train
+oogjulgona 1 300 train
+oogojomwqd 1 300 train
+oohcodnooj 1 300 test
+oohhlzapio 1 298 train
+oohhugqsjs 1 300 train
+oohjrdjpqs 0 300 train
+oohmiwhzze 1 298 train
+oohnjmonuy 1 300 train
+oohodsrjrj 1 300 train
+oohvisxicy 1 300 train
+ooiaifcicb 0 297 val
+ooigjwehuh 1 300 train
+ooijvhhwdr 1 300 val
+ooikhdsuxj 1 300 train
+ooilmrihrc 1 300 train
+ooimwyxgvc 1 300 train
+ooinjslmwf 0 300 val
+ooirzgbgba 1 300 train
+ooiuejetdr 1 300 train
+ooiwjzgkwp 1 300 train
+oojotcvvee 1 300 train
+oojowbflrz 1 299 test
+oojtzovnfn 1 300 train
+oojvczbnse 1 300 train
+oojxonbgow 0 300 test
+ookagoidlv 1 300 train
+ookcjwxhpq 1 298 train
+ookfdaswha 1 300 train
+ookfwggxvr 1 298 train
+ookggwwwpa 1 300 train
+ookjtngnft 1 300 train
+ookknankar 0 300 train
+ookqbberfc 1 301 val
+ookqpmfrkj 1 299 test
+ooktlyrkwr 1 300 train
+ookuelmxpi 1 300 train
+ookvttsbqn 1 300 train
+ookwdfuxzy 1 300 test
+ookwinesyd 1 300 train
+oolaulwnuc 1 300 train
+oolnekhvhx 1 300 test
+oolrfcqlok 1 300 train
+oolvtdigom 1 300 train
+oolvvchczh 1 300 val
+oombbocbfr 1 300 val
+oombfacasc 1 300 val
+oombthpecq 1 300 train
+oomjlvxkwp 1 300 train
+oomnygkufm 1 300 train
+oomtdwuvll 1 300 train
+oomunfasvt 1 300 train
+oomyjfmqay 0 300 train
+ooncfuzhip 1 301 val
+oondkawisg 1 298 train
+ooneuawpta 1 300 val
+oonmnnlscr 1 300 train
+oonnjuyhwa 0 300 train
+oonsyrdrms 1 300 train
+ooocwpthtq 1 300 test
+oooeqhmrqd 1 300 train
+oooirnmiwe 1 300 train
+oooppwvboj 1 300 train
+oootuokpdx 1 298 train
+ooovkuctso 1 300 train
+oopawwxrnr 1 300 val
+oopdllwyyx 0 300 train
+oopjrkkgkz 1 300 train
+ooplcrcwpg 0 300 train
+oopljduclp 1 300 train
+oopnmdadnz 1 300 val
+oopnmglwac 1 300 train
+ooprzmpooz 1 300 train
+oopuxximja 1 300 train
+oopzotineh 1 300 test
+ooqmebpyzs 1 300 train
+ooqslezzaz 0 300 train
+oorbkttqel 1 300 val
+oorcpflnqe 1 300 train
+oordpcvddy 0 300 train
+oordwlugci 1 300 train
+oorezsgdvl 1 300 train
+oorffeudfg 1 301 train
+oorgkmeyop 1 300 train
+ooriomjmhm 1 300 test
+oorlxfdxmm 1 300 train
+oornjqiead 0 300 val
+oorsvotrya 1 300 val
+oortedrxgx 1 300 train
+oorxmvapak 1 241 train
+ooshurwwtk 1 300 train
+ooskipbxtx 1 300 train
+ooslfcxqcv 1 300 train
+ooslortawx 1 300 train
+oospkdrvbj 1 300 train
+ooswfaxrxx 0 301 train
+oosylvapll 1 300 train
+ootmrvevwi 1 300 train
+ootmykhdga 1 299 test
+ootqeemscd 1 300 train
+ootymkxhwm 1 300 train
+ooucvotslu 1 298 train
+ooucwrscqf 1 300 train
+ooufbciavt 1 300 train
+ooufzebafh 0 300 train
+oouhmwtkwi 1 300 train
+oouilnpioh 1 298 train
+ooumyscohi 1 300 train
+ooupnrbfqr 1 269 train
+oourmwstbr 1 300 train
+oousltqjcf 1 297 val
+oouvqbfhao 1 300 train
+oouvrspxmb 1 300 train
+oouziuedww 1 300 train
+oouzsgznio 1 241 train
+oovaksexmh 0 300 train
+oovbzdlsiv 1 300 train
+oovixpmsci 1 300 train
+oovsalyhmv 1 300 train
+oovwjjxjmm 0 300 train
+oovzfmploa 0 300 train
+oowcrcxdmj 0 300 train
+oowetjkwkm 1 300 train
+oowhgukclx 0 300 val
+oowhohayti 1 301 train
+oowmchnsed 1 301 val
+oowqcuqczs 1 300 val
+oowrksqjoy 1 300 train
+oowswkomhm 1 300 val
+oowtouyugr 1 300 val
+oowwxjzmaz 1 300 train
+oowxwfiiid 1 300 train
+oowyvfykhl 1 300 train
+oowzhfqyyv 1 300 train
+ooxnksfypf 0 300 train
+ooxqxzwpwv 1 300 val
+ooxrbdpbas 1 300 train
+ooxrgvtsxr 1 300 train
+ooxwefpmcc 1 300 train
+ooxwwsfbib 1 300 val
+ooyimaqfie 1 300 train
+ooyrtijwfg 0 300 train
+ooywhojclq 1 300 train
+oozctoecyu 1 300 train
+oozfxgqjku 0 300 train
+oozjnzknnl 1 300 val
+oozounhpyj 1 300 val
+oozqewipzq 1 300 train
+oozqnykkgx 1 300 train
+oozqtipigw 0 300 train
+oozvrychbr 1 300 val
+oozwehjaov 1 300 train
+oozwmptkku 1 299 test
+oozxbbrcyi 1 300 train
+oozxsnvfvb 1 300 val
+oozzembcgo 1 298 train
+opacvstysi 1 300 train
+opapgkrsmf 1 300 train
+opaqzwdhtf 1 241 train
+opatbowacp 1 300 val
+opavejjqtl 1 300 val
+opawiplpxy 1 300 train
+opbclicyld 1 300 val
+opbjreysjj 1 300 train
+opbmtexvnh 1 300 train
+opbocuewxl 1 300 val
+opbpochwzs 1 300 train
+opbsbnmhzp 1 299 train
+opburbxznu 0 300 train
+opbxmgbboe 1 300 train
+opcfixwicm 0 300 train
+opcgkcuiwk 0 300 train
+opcgvmmeff 1 300 train
+opckvwaqhp 1 250 train
+opclkerwod 1 300 train
+opcnktezbw 1 300 train
+opcvaatzqa 1 298 train
+opczliwiig 1 300 train
+opdbgsqdsq 0 300 train
+opddoaqrpp 1 300 train
+opdivuhhml 1 241 train
+opdkexxibm 0 301 train
+opdknicmau 1 300 test
+opdqcwqxzy 0 300 train
+opdqgiurbg 1 300 val
+opesuanmso 1 300 train
+opfbltyqhy 1 300 train
+opfmnupxtt 1 300 val
+opfwbdvone 1 300 train
+opgjsfygbe 1 300 train
+opgkmkxdla 1 301 val
+opgmpkydlv 1 300 train
+opgrgresql 1 300 val
+opgxyhkslj 1 300 train
+ophcnrhajv 1 300 val
+ophdpgowiq 1 300 val
+ophelkmnlh 1 300 train
+ophlmdjitq 0 300 val
+ophyipwtci 1 300 train
+opidovxmlg 0 300 train
+opifbarfwa 1 299 test
+opifjnpsrx 1 300 val
+opimzerqpw 1 300 train
+opisxoojed 1 300 train
+opithuhnkd 1 300 val
+opiwyowplx 1 300 train
+opixjqovkm 1 300 train
+opizceidzc 1 300 train
+opizockopw 1 300 train
+opjakdohfw 1 300 val
+opjeptueub 1 300 train
+opjffxqcxq 1 300 train
+opjmdsizhg 1 300 train
+opjurebney 1 300 train
+opjvngvwnj 1 300 train
+opkatfccwc 1 249 train
+opkavicyqn 1 300 train
+opkcrxskta 1 300 train
+opkemidchv 1 300 train
+opknndijle 1 300 train
+opksfgcpcf 1 301 val
+opkthzgiij 1 300 val
+opktmvvboo 1 300 train
+opkxugymmf 1 300 val
+opkzmywqwe 1 300 train
+oplbxoqcpt 1 300 train
+opldjbanfi 0 300 train
+opldxgfaoq 1 300 train
+opletbcjvs 1 300 train
+oplwvujnqq 1 300 train
+opmellczlu 1 298 val
+opmpobgbsi 1 300 train
+opmtlqexfq 1 300 train
+opmuolitoe 1 298 train
+opmuubciul 1 300 train
+opnaobdjhk 1 300 train
+opnlppwwpy 1 300 train
+opnsbkgpcm 1 300 train
+opobaqiejv 0 297 train
+opoodcszjf 1 300 test
+opoqdlpliw 1 300 train
+opowggdbdh 1 300 train
+oppkjziwnq 1 300 train
+oppkqplzip 0 300 val
+opptprocqw 1 300 train
+opqebfobar 1 300 train
+opqecssgfd 1 301 train
+opqeorqknk 0 300 train
+opqhcojlvy 1 300 train
+opqnjtwoyv 0 300 train
+opqpbnwcxx 1 300 val
+opqtgolofy 1 300 train
+opriltyahr 1 300 train
+oprjoylwlv 1 301 train
+oprmacgbni 0 300 train
+oprnpylutz 1 300 val
+oproityyiy 0 300 train
+opsdpfofpl 0 300 train
+opsgvfjlgh 0 299 val
+opsjddoxui 1 300 test
+opslvgrmrm 1 300 val
+opsobncaay 1 300 train
+opsrznetys 1 301 val
+opssendhae 1 300 train
+opsswckvib 0 300 train
+opsyghlkxn 1 300 train
+optattjoud 1 301 train
+optehyaqby 1 300 train
+optipzwgow 1 300 train
+optkkjrkif 1 300 train
+optmfqtcww 1 300 train
+optpgbyzgj 1 300 train
+optsghycbh 1 300 train
+optyshszya 1 300 val
+opudeowozc 1 300 val
+opudhirwrr 1 299 test
+opudkcsxgp 1 300 train
+opudvdjvju 1 300 train
+opuhoerhxb 0 300 train
+opujeaoxmw 0 300 train
+opulghzzrs 1 300 train
+opurrslrab 1 300 val
+opvqdabdap 1 300 test
+opvrhiximy 1 300 train
+opwdyelesv 1 300 val
+opwhdottpi 1 241 train
+opwmyhcrht 1 300 val
+opwonhbrnq 0 300 train
+opwqlxzcaf 0 134 val
+opwxhjfrvv 1 300 train
+opxaryydqm 1 300 train
+opxdqaecvm 1 300 train
+opxfeymrwb 1 300 train
+opxgtfndvc 1 300 val
+opxlisnfme 1 300 train
+opxqxvytbu 1 300 train
+opxtanobal 1 300 train
+opxtgyrmae 1 300 train
+opxvtbabbb 1 300 train
+opxytgekxt 1 298 train
+opyhfrjgzf 1 241 train
+opyhrylkvm 1 298 train
+opylkehctg 1 300 train
+opymvojpuv 1 299 test
+opynjavqmg 1 300 train
+opyqhzedxd 1 300 train
+opyqudaics 0 301 train
+opyychqzhz 1 300 train
+opyzeznpiw 0 300 val
+opzceliarq 1 302 train
+opzchpdtfl 0 301 train
+opzdcslxjd 1 300 val
+opzdgkjnqo 1 301 train
+opzixctkbx 1 300 train
+opzjopubkw 0 300 train
+opzqqrapoi 1 237 train
+opzwcraugz 1 241 train
+opzxnzcebg 1 241 train
+oqaammffqx 1 240 train
+oqaedrnlql 0 300 train
+oqahdxlekx 1 300 val
+oqakfecoms 1 300 train
+oqamjjgrno 1 300 val
+oqaonlutrm 1 300 val
+oqatjmvive 1 299 test
+oqbeorohkh 1 300 train
+oqbfuafali 1 300 train
+oqbigvtgya 1 300 train
+oqbitiyjez 1 300 train
+oqbjlplltl 0 300 train
+oqbltrmhvt 0 300 val
+oqbmgbahya 1 300 train
+oqbowgguyu 1 300 train
+oqbsgrifhp 0 300 val
+oqbtcqsurp 1 300 val
+oqbveryvbv 1 300 train
+oqbwxfnkxn 1 300 train
+oqbzomesmq 0 300 val
+oqcaxvbmyc 1 300 train
+oqcfouasvq 1 300 train
+oqcnzikgjf 1 300 train
+oqcpcbzjot 1 300 train
+oqcqnndpcv 1 298 val
+oqcwzfilfw 0 300 train
+oqdfeqdjpf 1 300 val
+oqdpiefpij 0 301 train
+oqdsmmmxta 1 300 train
+oqduevrlbs 0 300 train
+oqeaztfgir 1 300 train
+oqecjzppih 1 300 val
+oqehnuhbwa 0 300 train
+oqehruazsh 0 300 train
+oqejtxqvhp 1 300 test
+oqekmemzit 1 146 train
+oqeoibjbim 0 300 train
+oqexsxhaao 1 300 train
+oqfbwpnpjw 1 301 train
+oqfdfedsus 0 300 train
+oqfhupwjto 0 300 val
+oqfkvrodjy 1 300 train
+oqfnxchxvt 0 297 train
+oqfvinuroi 1 240 val
+oqfwzlebex 1 300 val
+oqgbhltpmu 1 300 train
+oqgeqvxukk 0 240 train
+oqgezyhmau 1 301 train
+oqgjufqaeg 1 300 train
+oqglliennm 1 300 train
+oqgnixmqqu 1 300 train
+oqgqqmqzev 1 300 train
+oqgtonfnxl 1 300 train
+oqhiqiduep 0 300 train
+oqhiwpjlrr 1 300 train
+oqhlytcimo 1 300 train
+oqhosxxkdj 1 300 val
+oqhqvsiyaz 1 300 test
+oqhsxugwit 1 300 val
+oqhtpyhcso 1 300 train
+oqhyqwmnad 0 300 train
+oqhzpmqnft 1 300 train
+oqicvaswem 1 300 train
+oqielrltwr 1 300 train
+oqifuwoiec 1 300 train
+oqisxcvofd 1 300 val
+oqiybqhepu 0 300 train
+oqiyrtpwyf 1 288 train
+oqizhpvsxp 1 300 train
+oqizxucnnz 1 300 train
+oqjeboelcg 1 300 train
+oqjfpsiwrg 1 300 train
+oqjmyrgnwh 1 300 train
+oqjrzfrjnq 1 300 train
+oqkchtguca 1 300 val
+oqkhbtevbm 1 300 train
+oqkmvibkcw 1 301 val
+oqkmvmkylo 1 300 train
+oqkthrsmfj 1 300 train
+oqlcqlxmaa 1 298 train
+oqlgshcira 1 298 train
+oqliriyhis 1 300 train
+oqlnkziqdh 1 300 train
+oqlpeklhca 1 301 train
+oqltezdtla 1 300 train
+oqlyiapavb 1 300 train
+oqlzcsssoe 1 300 train
+oqmesuxcup 1 300 train
+oqmfiigvon 1 300 train
+oqmfplwmph 1 300 train
+oqmgquqrzg 1 83 train
+oqmkplatxm 1 290 train
+oqmqvrkcjh 1 300 train
+oqmrwqdhqq 1 300 train
+oqmtjnxrbn 1 300 train
+oqmudrgeda 0 298 val
+oqmwbfcejq 1 300 train
+oqmxtimbbk 1 300 train
+oqmzuebopv 0 300 val
+oqnhdclviu 1 300 train
+oqnhxhzzws 1 299 train
+oqnpzvjsac 1 300 test
+oqntpoliph 1 300 train
+oqnyknzjlq 0 300 train
+oqoazapqyd 1 300 train
+oqoeqoffor 1 300 val
+oqojahmyjr 1 300 train
+oqoohpkfkd 1 300 train
+oqopyfdctp 1 300 train
+oqoqqqwgop 1 300 train
+oqordnxkxc 1 301 train
+oqoxpzwwjz 1 300 train
+oqoxxanpmu 1 300 train
+oqoyinfxcb 1 300 train
+oqpixhijkg 1 300 train
+oqpiysziam 1 300 train
+oqqfuzihnn 1 300 train
+oqqswtqyvi 1 301 train
+oqrdigzjls 0 300 val
+oqriegpolf 1 300 train
+oqrmyzxvfw 0 300 val
+oqrrqeszae 1 300 train
+oqskzunwuc 1 300 train
+oqsueypbhz 1 300 train
+oqsusydmkm 1 300 train
+oqszqpllcu 0 300 train
+oqtbldhlzt 1 300 train
+oqtcqzgjza 1 300 val
+oqtgrtywqz 1 300 train
+oqtgyuhyhn 1 300 train
+oqtroabgrl 1 300 train
+oqttiamttf 1 300 train
+oqttnyuffo 1 300 val
+oqtzdvdjid 1 302 val
+oqugflbjso 0 300 val
+oqusgwfain 1 300 train
+oqutckhbzw 1 300 train
+oquxsdudzn 1 301 train
+oquzrhlhip 1 300 train
+oqvaglsbgn 1 300 train
+oqvcyijgsg 1 298 train
+oqvexenuei 1 300 train
+oqvgxepzwn 1 300 train
+oqvkjuncux 0 300 train
+oqvndrxurj 1 300 val
+oqvqrspsuj 1 300 train
+oqvsehbxyq 0 300 train
+oqvsejsdus 1 300 train
+oqvvickaxs 1 300 train
+oqvymdodta 1 300 train
+oqwdpayvna 1 300 train
+oqwfcxelxa 0 300 train
+oqwmglahkz 0 300 train
+oqwnlpbzuc 1 300 train
+oqwoaaaxqv 1 300 train
+oqwokxuygj 1 300 test
+oqwpakepin 1 300 train
+oqwtdayrbf 1 300 train
+oqwvjyxlej 0 300 train
+oqwwfwkwin 1 300 train
+oqwxsbecil 1 300 val
+oqxcsgorfe 1 300 train
+oqxdpsbsee 1 300 train
+oqxdrqmqpz 1 300 train
+oqxlgpxfas 1 300 train
+oqxrrmxqph 1 299 train
+oqxtttmshs 1 300 train
+oqxwipljvo 1 301 train
+oqxylknngd 1 300 train
+oqybzbiazu 1 300 train
+oqydrorubb 1 299 val
+oqylekdsxx 1 241 train
+oqyybywrhn 1 300 train
+oqzuvlxuex 1 300 train
+oqzwblaggz 1 300 train
+oqzwwfztzq 1 300 val
+oqzxykgxqc 1 300 train
+oqzzwlfmbo 1 300 train
+orabrinseb 1 299 train
+oraclpfeuc 0 300 train
+oradifpeez 1 300 train
+oragbrohsj 0 300 train
+oramozyimv 0 300 val
+orapdmsxpx 1 300 train
+orascrofjq 1 301 train
+oraygdytwq 1 300 train
+orbbsdehap 1 300 train
+orbbzurpjs 1 300 val
+orbcxzortb 1 300 train
+orbjtxzrqj 1 300 train
+orbjwouldq 1 300 train
+orbjyprjmf 1 300 train
+orbkwleidc 1 300 train
+orblnqzpra 0 299 test
+orbmmatbpy 0 300 train
+orcapomjaz 1 300 train
+orceunvpmt 1 300 train
+orcjpmqyuo 1 300 train
+orcllueitm 0 300 train
+ordbmlumud 1 300 val
+ordbprvfia 1 300 train
+ordjtgafzy 0 301 train
+ordmqjhzis 1 300 train
+orduzxhaso 1 300 train
+oredhzwztp 1 300 test
+oreegdephy 1 300 train
+orekjthsef 1 300 test
+orestlrmcz 1 300 train
+oreuhpaeyg 1 300 train
+orfbaopdhe 1 300 val
+orfbhztwcb 1 300 train
+orfibhyltg 1 300 train
+orfjoxqyzp 1 300 val
+orfjqhsxdz 1 300 train
+orfngidrio 1 300 train
+orfsriylyy 0 300 val
+orftarkbne 1 300 train
+orftxlubyz 1 300 val
+orfwkkexxy 1 300 train
+organgsicu 0 300 train
+orgbgvcqvl 0 300 train
+orgmpemwbq 1 300 train
+orgpcogfgj 0 300 train
+orgwifadtw 1 300 val
+orhcqqwkmn 1 300 train
+orhcrzcvfo 1 300 val
+orhhfueuka 1 300 train
+orhmrjouqv 1 241 train
+orhotmsnxt 1 300 train
+orhpztubzy 1 300 train
+oriiwwgrck 1 301 train
+orimprghvd 1 301 train
+orimzngucp 1 300 train
+oriqfbjkei 1 300 train
+orisbikbvp 1 300 train
+orixbcfvdz 1 299 test
+orixbfpmdh 1 147 train
+orixcnfnuv 1 300 train
+orjcbpbevk 1 301 train
+orjhjhvoix 1 300 train
+orjklbwlbd 1 300 train
+orjmhtggmm 1 241 train
+orjnwefoel 1 300 train
+orjwkmnmrw 0 300 train
+orjzhiztqm 1 301 train
+orkaspifip 0 300 train
+orkbzcydjv 0 300 train
+orkccpsdba 0 300 train
+orkjtqlweh 1 301 train
+orkmmmutnc 1 300 train
+orldpmngae 1 300 test
+orlidmtjcn 1 300 train
+orliuxsdah 1 300 train
+orljzzylmq 1 240 val
+orlkqojtxg 1 300 train
+orlqxnzaxg 1 300 train
+ormijnmkvd 1 300 train
+ormikeyscm 1 301 train
+ormmjvxgkg 1 300 train
+ormqafvysd 1 300 train
+ormzmakltr 1 301 train
+orngymqvxn 1 300 val
+ornhlqsdyu 1 302 val
+ornnpocxab 1 300 train
+oroamxxelo 0 300 train
+oroaqrcjll 1 300 train
+orodrluscm 1 300 train
+orohsyamcx 1 300 val
+orohwsgbpw 1 300 train
+orojkxscjl 0 300 train
+oroluojdip 1 300 train
+oronhfsmgr 1 300 train
+oroqyybrgh 1 300 train
+orouqodhrs 1 298 train
+oroxurusew 1 300 train
+orpnrdksul 1 302 val
+orpsyofhiz 1 300 train
+orpywbwptk 1 300 train
+orpzcsjjdz 1 300 train
+orqafstesq 0 300 train
+orqbqildro 1 300 train
+orqcakrxur 1 300 train
+orqcddnxmv 0 147 train
+orqebsplwq 1 300 val
+orqeqtbhaf 1 300 train
+orqfdpgsxt 1 300 val
+orqhbnmfec 1 300 train
+orqipgmcql 1 300 train
+orqsbsxfba 1 300 train
+orqueaecyq 0 300 train
+orqvavlncg 0 300 train
+orqxtracdn 1 300 train
+orrltuoxgt 1 300 train
+orrmbukudq 1 300 train
+orrqxnevvz 1 300 val
+orrskoijnb 1 300 train
+orrxokuuoo 1 301 train
+orscvzevlu 1 300 val
+orsexnontc 1 269 train
+orshkoxczy 1 300 train
+orsoqifwkd 1 300 train
+orsqgnxahy 1 301 train
+ortaqzibtj 1 298 train
+ortfvecpgt 1 300 train
+ortlvqzjpk 1 300 train
+ortmkisttk 1 300 train
+ortsllpxtf 0 300 train
+ortuxbrhsh 1 300 train
+ortvcnoghh 1 299 test
+ortxvzoneb 0 300 train
+orueinhrhh 1 300 train
+oruflnazwk 1 301 train
+oruiaksfqi 1 300 train
+oruvebzymm 1 300 train
+oruvgeukhf 1 300 val
+oruyccyata 1 300 train
+orvcnhaoeg 1 240 train
+orvdzsoiel 1 300 train
+orvlwfocki 1 301 train
+orwcedlqrf 1 300 train
+orweihnpge 1 300 train
+orwhqkpton 0 300 train
+orwkqlkrna 1 300 train
+orwpqqrlev 1 300 val
+orwpyprgvu 1 300 train
+orwqwnwghc 1 300 train
+orwvtpzrtu 1 300 val
+orxbqxcqfr 0 300 train
+orxcjhvtht 1 300 train
+orxecxcpyp 1 300 val
+orxnbtvkxk 1 300 train
+orxnlwtbwe 1 300 val
+orxvfgrjsm 1 600 train
+orxxejpfbp 1 300 train
+oryadcrsam 0 300 train
+orycgqemxn 1 300 train
+orydydsjqy 1 298 val
+oryetmnmtg 1 301 train
+oryncebpmf 1 300 train
+orynwmvmwz 1 300 train
+oryxkroikf 1 300 train
+oryxqexhku 1 300 val
+oryzldljno 1 300 train
+orzftoxvmc 1 300 train
+orzivjiegb 0 300 train
+orzjfiadvh 0 300 val
+orzltllnmg 1 300 train
+orznablmkk 1 301 val
+orznsybnyo 1 300 train
+orzysslzoc 1 301 train
+osabpdtucu 0 300 train
+osaesqnzgw 1 300 test
+osanhtlpgw 1 300 train
+osaqfchczp 0 300 val
+osashdrxxu 1 300 train
+osatldoscj 0 300 val
+osatxdopue 1 300 val
+osbekorjud 1 297 train
+osbkdjpjdt 1 300 train
+osbmqmyrxj 0 300 train
+osbycsralb 1 297 val
+osccivhmlb 1 300 train
+oscfcyxjhw 1 300 train
+oscfyzrmgo 1 300 train
+oscgqqclma 0 300 train
+oscmrmrafo 1 300 val
+oscnyyzmuj 1 298 train
+oscoxxwged 1 300 train
+oscxjoddld 0 300 train
+oscytbinok 1 300 train
+osddpqeqox 1 300 train
+osdfnikfpq 1 300 train
+osdhxajzlp 1 300 train
+osdjajxbpd 1 298 train
+osdjcccnci 1 241 train
+osdrrmdkgg 0 300 train
+osdypvnjvc 1 300 train
+oseedxjxag 1 301 val
+oseffojane 0 300 val
+oseiieaglw 1 300 train
+osenzhppim 0 300 val
+osepwkfuph 0 300 train
+oseroaqish 1 300 train
+osfaackzob 0 300 train
+osfdvsflzb 1 300 train
+osfflgpiia 1 300 train
+osffneskka 0 300 train
+osfjhckptt 1 300 train
+osflukecxk 1 300 train
+osfmbjnjsl 1 300 train
+osfontgvxz 1 300 train
+osfqnjuzhx 1 300 train
+osftntcbbq 1 300 train
+osfyspxohu 1 300 train
+osgewvcbuv 1 300 train
+osgfteqlva 1 300 train
+osgigzqmrp 1 300 train
+osgiimpzjq 0 300 train
+osgmuptyfv 1 300 train
+osgxmzpumw 0 300 train
+osgxvfnusa 0 250 train
+osgygejxjr 1 298 train
+oshbmeanjj 1 300 train
+osiaoilvjf 1 301 train
+osidnsoicr 1 300 train
+osiebgewld 1 301 val
+osieekzdgq 1 300 val
+osifkphznd 1 301 train
+osigbttmxy 0 300 train
+osipsjkubw 1 300 train
+osiqobxdnn 0 300 train
+osivgitpxo 1 300 train
+osixpynvpu 0 300 val
+osjaqtkkdt 0 300 train
+osjavbizqc 0 300 train
+osjdlhpqcv 0 300 train
+osjlbtfazy 1 300 train
+osjsaofupm 1 300 train
+osjvlnohwr 1 300 val
+osjxxblajo 1 300 train
+oskfexvzbw 1 300 train
+oskhznnfwi 1 300 val
+oskvvjveyq 1 300 train
+oskwlbbrai 1 300 train
+oslaimenzf 1 300 val
+oslhkqabsn 0 300 train
+osloynddjh 1 300 val
+oslpfwdplo 1 300 train
+oslpqjparu 1 300 train
+oslrwgfzxa 0 301 train
+osltltqytd 1 300 val
+osltzozems 0 300 train
+oslxrqchqp 0 300 train
+oslzbwdaeo 1 300 train
+osmddxsgfa 1 301 val
+osmkcnlhnx 1 298 train
+osmnegfehr 1 300 test
+osmpvlbtvb 1 240 train
+osmxliyvbf 1 300 train
+osnazdhulb 0 300 val
+osncortkcr 1 301 train
+osndijcoyz 1 300 train
+osnfpfbqhv 1 300 train
+osntnoxbci 1 299 train
+osnumdcwdp 1 300 train
+osnuxyotnv 0 300 train
+osnxlpysuj 1 298 train
+osnxmmzucw 1 300 train
+osnykkldob 1 300 train
+osobrjgrda 1 300 train
+osofqiherk 1 300 train
+osohgmymcy 1 300 train
+osoozqwxtu 1 300 train
+osopquegkp 1 300 train
+osowkcyjzt 1 300 val
+ospbyujbsp 1 300 train
+ospeltvcrn 1 300 val
+ospffszlet 1 301 val
+osphukakhs 1 300 train
+ospkstlobq 1 300 val
+osplyksmpi 1 300 train
+ospmjmcazn 0 300 train
+ospngvrono 1 300 train
+osptihltfp 0 300 train
+osqbtoddpd 1 300 train
+osqgjfstyl 0 300 train
+osqhthnkir 1 301 train
+osqmxxkdeg 1 300 train
+osqpoxmpfk 1 300 train
+osqqbcnohn 1 300 val
+osqrubjdvn 0 299 train
+osqruujwxd 0 300 val
+osqxeuzojw 1 300 val
+osqyiendxp 1 300 val
+osqyiobyum 1 300 train
+osqykwdgxc 1 300 train
+osqzqlxmin 1 300 train
+osramoobmu 1 300 train
+osrmpgqhbx 1 300 train
+osrnwbcemu 0 300 train
+osrobbwqsd 1 301 train
+osrpepdagi 1 300 train
+osrpfpubzw 1 300 train
+osrwcsncwj 1 300 val
+ossdjcsnkm 0 300 train
+osseqnjnyr 1 300 train
+ossheoezod 1 301 val
+osshfmdpgr 1 300 val
+ossjpbfyyp 1 300 train
+ossjvfuzve 1 241 train
+ossofalzqd 1 301 train
+ossogpohxi 1 300 val
+ossoqigdyf 0 300 val
+ossqgahpqp 1 300 train
+ossrzhqvsi 1 288 train
+osstbzotrc 0 300 train
+osstneikjx 1 301 train
+ossvftqkam 1 300 train
+ostcsbcbdb 1 300 val
+ostlebidwy 1 300 train
+ostpsxndfv 1 300 val
+ostyspddor 1 300 train
+osuawkyoot 0 302 train
+osufnholvl 1 300 train
+osufrflpnf 1 300 train
+osufvbeehp 1 300 train
+osugaohitk 1 300 val
+osuizfzpov 1 300 val
+osuurnhhie 0 300 train
+osuutehpyn 1 300 train
+osveadsfnz 1 300 train
+osvlvfgrfn 1 300 train
+osvnsqtdrf 0 300 train
+osvphqmstr 0 300 train
+osvwyfzpjm 1 300 train
+osvztqvsvv 1 301 train
+oswodkxhch 0 300 train
+oswovdjokq 0 300 train
+oswqudbune 1 301 val
+oswzlidcel 0 300 val
+osxaqqowdx 1 300 train
+osxdncsylh 1 300 val
+osxfzzzlbs 1 301 train
+osxhrnllsk 1 300 train
+osxirajjhp 1 300 train
+osxjcahnfz 1 300 val
+osxovvngpq 1 300 train
+osxqabtgvz 1 298 train
+osxxjjzegf 1 300 train
+osxzzaaoqj 1 300 train
+osydgeqgik 1 298 train
+osyfcyjccv 0 300 train
+osyfuiltpq 1 300 train
+osyhvfdcme 1 300 train
+osyklqiscv 0 300 train
+osyknuntpt 1 297 train
+osyohwaedt 1 240 train
+osyswevrib 1 300 train
+osytznjtok 1 301 train
+oszbxuamyj 1 300 train
+oszcmcdlcm 1 300 val
+oszcovipbm 1 300 train
+oszgibdqle 1 300 train
+oszgybwgbz 1 300 val
+oszibzgspe 0 300 train
+otaahqoath 0 300 train
+otabzuvmjo 1 300 train
+otacaenihv 1 302 train
+otaevpekqf 1 300 train
+otagstfqor 0 300 train
+otakcxftoa 0 300 val
+otalkhphjl 1 300 val
+otascjpamo 1 300 train
+otawcvcmxt 1 300 val
+otbbsyoixr 1 298 train
+otbfyqpbko 1 300 train
+otbgdgrgkd 1 300 val
+otbhiuniuw 1 300 train
+otbhndvkpn 0 300 train
+otbjmeibcw 1 300 train
+otbmvppkra 1 241 train
+otboeryjyv 1 288 train
+otbortrnlm 1 300 train
+otbsxufnxd 1 300 val
+otbtpuprww 1 241 train
+otbvnxwrol 1 300 train
+otbvsqaraq 1 300 train
+otbyhrdzyb 1 300 val
+otcfsycwmh 1 300 train
+otcgvkdbwh 0 300 train
+otczmvoclg 1 302 train
+otddrufuae 1 300 test
+otdgefvyim 1 300 val
+otdjaalvub 1 300 train
+otdkmvqrro 1 241 train
+otdmjuavgs 1 300 train
+oteajexrlu 0 300 train
+oteftssoem 1 300 train
+otegznikgy 1 300 train
+otekpoljav 1 300 val
+otezxbkygi 1 300 train
+otfewufpsw 1 241 train
+otfhmjjgxy 1 300 train
+otfiqoblfk 0 298 train
+otfnnntkzi 0 300 train
+otfqjrryvs 1 300 val
+otfuuivikj 1 300 train
+otgfxevvvc 1 300 val
+otgormuepq 1 300 val
+otgoshxhfs 1 300 train
+otgpbdokoa 1 300 train
+otgvcfldbc 1 300 val
+otgzrnqhoy 1 300 train
+othchpjokc 1 300 train
+othfbpeqyn 1 300 train
+othinadguw 1 300 train
+otiatduyhk 0 300 train
+otihjrggcr 1 300 val
+otilzpjrfc 1 300 test
+otiqxfixwi 0 300 train
+otirtaigaj 1 300 train
+otjdhqgzhp 1 300 val
+otjfvisthd 1 300 train
+otjpediivq 1 300 train
+otjspegxdv 1 300 train
+otjtpfvwzd 1 300 train
+otjvvhrscg 1 300 train
+otjzwqnkis 1 300 train
+otkbbozsqu 0 300 val
+otkickragq 1 241 train
+otkkiwhxrw 1 300 test
+otkkmovhip 1 241 train
+otkmoahrcb 1 300 train
+otkrjrhfhm 1 300 train
+otksjspxnv 1 300 train
+otktiyaidr 1 300 train
+otkvimtbby 0 300 train
+otkxomdwpt 1 300 train
+otkxyvwefe 1 300 train
+otlcbjzoly 1 300 train
+otljczxgei 0 300 train
+otllqyeyqo 0 300 train
+otllxtsccv 1 300 train
+otlmuxrfcc 1 300 train
+otlnlvkmqm 1 300 train
+otlotqyrii 1 240 val
+otlqvnvcni 1 300 train
+otlruwmohj 1 300 train
+otlslugjai 1 296 val
+otlvtaistg 1 298 train
+otlwekplev 1 300 train
+otmarvtrrk 1 300 train
+otmcckypar 1 300 train
+otmgwrxtss 1 300 val
+otmqtimfza 1 300 val
+otnavkjzor 1 300 train
+otnfibrzvp 1 300 train
+otnhtpvttv 0 300 train
+otnlwzcwlo 1 300 train
+otnmzhzsdv 1 299 val
+otnpwnipct 1 300 train
+otnvpvoulf 1 300 val
+otodmcwvkl 1 298 train
+otokvtjter 1 300 val
+otoqbkjvwo 1 300 train
+otovwyidul 1 300 train
+otovzqsidt 1 300 train
+otplqohdoj 1 136 train
+otpvpcndja 1 300 train
+otpzsasueb 1 300 train
+otqbyjinfo 1 300 train
+otqftsfgwy 1 300 train
+otqhwpbrcp 1 300 train
+otqiyrcros 0 300 train
+otqsovjlsm 1 299 train
+otqtbkifpf 1 300 train
+otqxsxinqo 1 300 val
+otqzutddtd 1 300 train
+otqzylawvi 1 300 train
+otraviktvw 1 300 train
+otrfvggftk 1 300 train
+otrkmujlck 0 301 train
+otrqcxyjzk 1 300 train
+otrthevyvz 0 300 train
+otrurmahje 0 300 val
+otrustcycj 1 300 train
+otsffwpoms 1 300 train
+otshjfaztb 1 300 train
+otskzdsevy 1 300 train
+otspbfzant 1 300 train
+otsqyydxdb 1 240 train
+otstolupuo 1 300 train
+otsviewqwp 1 300 train
+ottambzllu 0 300 train
+ottceqscky 1 300 train
+ottiiobbrh 1 300 train
+ottiwnggbd 1 300 train
+ottnyzledl 1 300 train
+ottrcenkyp 1 300 train
+otudmwcikv 1 301 train
+otugbgzdnn 1 300 val
+otujttmrov 1 300 train
+otujtwkkbk 1 300 train
+otuklexlad 1 300 train
+otukzgomdw 1 299 test
+otulyvnejm 1 300 train
+otumyuuzkl 0 300 train
+otvgqhtxkq 0 300 train
+otvkkjnijp 1 300 train
+otvntlpfgn 1 300 train
+otvosbgbsz 1 300 train
+otvqmtgsnw 1 241 train
+otvvasykro 1 300 val
+otvyvukchr 1 300 val
+otwaywcdkb 1 300 train
+otwckzpmkj 1 300 val
+otwrzyhfmy 0 300 val
+otwuwuiksc 0 300 train
+otwuydmkyu 1 300 val
+otwyjhfnqs 1 300 val
+otxdugkaxh 0 300 train
+otxithzagg 1 300 train
+otxljipcqb 1 296 val
+otxmdyzwic 1 300 train
+otxxgemnnj 1 301 val
+otybhhgpml 1 300 train
+otyhadpkmz 0 300 val
+otyqxxbslh 1 300 train
+otyrbsrkhn 1 300 val
+otythiweau 1 300 train
+otyxsinhzh 1 298 val
+otzadudfpi 1 300 train
+otzdaggozg 1 301 train
+otzmadzzqa 1 299 val
+otzpdcaumu 1 300 train
+otzptukjtu 1 298 train
+otzvthnejq 1 300 train
+ouafqcvuos 1 300 train
+ouaowjmigq 0 299 test
+ouasdbxgfm 1 300 train
+ouasgppjhj 1 300 train
+ouasybuekg 0 300 train
+ouaxfnbaxj 1 300 train
+ouazajlgtk 0 300 train
+oubatifbba 1 299 train
+oubbkiwxjc 1 300 train
+oubbxnbbre 1 300 train
+oubgmkozqz 1 300 train
+oubhnxayiq 1 300 train
+oubhpfalgv 0 301 train
+oubjbqjtoh 1 300 train
+oubjhbhfiu 0 300 train
+oubkncenhv 1 300 val
+oublneqbak 1 300 train
+oublntsdsu 1 300 train
+oubmkiqtux 1 300 val
+oubqdxunpo 1 301 train
+oubqoguxxc 1 300 train
+oubqtfwmgd 1 300 train
+oubtibjzfh 1 300 train
+oubtqzvafd 0 300 train
+ouccgcfaso 0 300 train
+oucdhchdkb 0 300 train
+oucjntzkac 0 300 train
+ouclabgsad 0 300 train
+oucorcaikg 1 300 train
+ouddxdjtzh 1 301 val
+oudideevde 1 300 train
+oudktnykth 1 300 val
+oudoutqyfm 1 300 train
+oudphxnhxv 1 300 train
+oudsjdedxf 1 241 train
+oudvhmidou 1 300 val
+oudwhzqpck 1 300 train
+oudyexpgvw 1 299 test
+oueediidhf 1 300 train
+ouelrevrmp 1 300 train
+ouenqwrgzt 1 300 train
+ouesxdmtvh 1 300 train
+ouetzpfrnh 1 300 val
+ouexljqvdw 1 300 train
+oufbxjadvz 1 300 train
+oufdosyzfu 0 300 train
+oufhhjxfhq 1 300 train
+oufidacgwf 1 300 train
+oufnvqrgxs 1 300 train
+oufxdhqmva 1 300 train
+ougeeoojhh 1 300 val
+oughejkndd 1 300 train
+ougovkslli 0 300 train
+ougovqflgw 1 300 val
+ougzigrhvi 0 300 train
+ouhetpvtew 1 298 train
+ouhlfeqolk 1 300 val
+ouhuqktnna 1 300 train
+ouhwtkhlcc 1 300 train
+ouibzjjlxs 1 300 train
+ouieqrlchi 1 300 train
+ouimlwvgic 1 300 train
+ouiuvzdxmw 1 298 train
+ouixhturuw 1 300 train
+oujgnraxln 0 300 train
+oujkrlxliv 1 241 train
+oujlabhhmx 1 300 train
+oujljuqqvv 1 300 train
+oujtvuirva 1 300 val
+oujvssjrqr 1 299 train
+oujxladjth 1 300 train
+oukblvbyxv 1 299 test
+oukfxkyuys 1 300 val
+ouklamzdym 1 300 val
+ouklczpngo 1 300 train
+oukrbcojfk 0 300 train
+oukvrouhox 0 300 val
+oukvxhpuat 1 300 val
+ouldkvbvzg 1 300 val
+oulfwhntjj 1 300 train
+oulimleysn 1 300 val
+oulrneyosa 1 300 val
+oulxsqzkwe 1 300 train
+oulyfsnsam 1 298 train
+oulzcrhayd 1 300 train
+oumbqyjahu 1 300 train
+oumcymkaof 1 300 train
+oumeoqmzxq 1 298 train
+oumhlirlzk 0 300 train
+oumnlpznlf 1 299 test
+oumvlthfdj 0 300 val
+oumxssjnem 1 299 train
+oundixpyst 1 300 train
+ounfiuexwc 1 300 train
+ounltapexr 1 300 train
+ounmpvfhqa 1 300 train
+ounsrmikkd 1 300 val
+ountpqlqhr 1 300 train
+ounuyrizwm 1 301 val
+ouodafpgef 1 300 train
+ouofnkhqcf 1 300 train
+ouopeunsmf 1 300 test
+ouoqfjpcqy 1 300 test
+ouoqwjryap 1 300 val
+ouosgpaywa 0 300 train
+ouotuvytsy 1 300 train
+ouowatdzki 1 300 train
+oupcbkiokq 1 299 val
+oupfjqneoh 1 300 train
+oupjhtodai 0 300 train
+ouplrozcqo 1 298 train
+ouprhkimkm 1 300 train
+oupsermued 1 300 val
+oupudlphvg 1 300 train
+oupuxsoqub 1 300 val
+oupyagutog 1 300 train
+oupztxzdln 0 301 train
+oupzvikibn 1 300 train
+ouqckocbcs 1 300 val
+ouqfurrtyq 1 300 train
+ouqksymfyt 1 299 val
+ouqodnevxv 1 300 train
+ouqoeoroue 1 300 train
+ouqpnjoshj 1 300 val
+ouqqbpbakd 1 300 train
+ouqqjbaitq 1 300 train
+ourcjujbvb 1 300 train
+oureyqbdrp 1 300 train
+ourgqdpuok 1 301 val
+ourgzxqfxe 1 298 train
+ouritaizmi 1 300 train
+ourklihdqs 1 300 train
+ourlqadkyi 1 300 train
+ournmgofjy 1 300 train
+ourqnmpodn 1 300 train
+ouruynaloe 1 301 train
+ousfgrioye 1 301 train
+ousfjvhzdo 1 300 train
+ouslpwefgh 0 300 train
+oussxgrhxc 1 300 val
+ousteynfwq 1 300 train
+ousuxhzswj 0 300 train
+outdbpjais 0 300 train
+outfhdrzsp 1 298 train
+outipbzqhm 1 300 test
+outknatnbt 1 300 train
+outmesmmhg 1 300 train
+outmykvudw 0 300 train
+outspmgrxp 1 300 train
+outwxlrobr 1 300 train
+ouuaekvzls 1 300 train
+ouuagupnxm 0 300 val
+ouuahiqwvs 1 300 train
+ouueahjbmd 1 300 train
+ouulhovezr 1 300 val
+ouumxqezhv 0 300 val
+ouupxheyxb 1 300 train
+ouuxhddgsw 1 300 train
+ouuxpzqxjd 1 301 val
+ouvjqoaznf 1 300 train
+ouvjvtsvti 1 300 train
+ouvlzfmqsz 0 300 train
+ouvsuyancp 1 300 val
+ouvuihdhxt 1 300 train
+ouvvruxhaq 1 300 train
+ouvziinihk 1 300 val
+ouwafhkubj 1 300 val
+ouwbjprgsd 0 300 train
+ouwbmdjqgz 1 300 train
+ouwgkbhkbm 1 300 train
+ouwiqfiatg 1 300 train
+ouwkcqjujp 1 300 train
+ouwkwnkzlr 1 300 train
+ouwmdrevsh 1 300 val
+ouwmjrkwnl 1 300 train
+ouwvdpyxpz 1 300 train
+ouwwzldtky 1 300 train
+ouwxxfvltq 1 300 train
+ouwyjdtqwq 0 300 train
+ouwysiwtxv 1 302 train
+ouxamdkjbk 1 298 train
+ouxhatvhum 1 300 train
+ouxixrpsnd 1 300 test
+ouxlzbudmi 1 300 train
+ouxplhqrgi 1 300 train
+ouxyjxlbkx 1 298 train
+ouydppqdmw 1 300 train
+ouyegiokna 1 300 train
+ouyhcvfhfo 1 300 train
+ouyjaxjzpc 1 300 train
+ouyjjhlatg 1 298 train
+ouynicgxld 1 300 train
+ouyqvtliyj 1 300 train
+ouyzewagul 1 300 train
+ouzagmjgkc 1 300 train
+ouzavqyyuy 1 300 train
+ouzbhijaxn 1 300 train
+ouzkwlefbz 0 300 val
+ouzonztess 1 300 train
+ouztqcqkjv 0 300 train
+ovabbbytjy 1 300 train
+ovarzjfvwd 1 300 train
+ovavyalwhq 1 300 train
+ovawdhyzft 1 300 train
+ovbewwyuvb 1 298 train
+ovbfhsfqbs 1 300 train
+ovbjhuvlwh 0 147 train
+ovblgaynru 1 300 train
+ovbydhbvfg 1 300 train
+ovcbbsdtas 0 300 train
+ovcdgefpdj 0 300 train
+ovchdyqimz 1 300 train
+ovcjljoylw 0 300 train
+ovcjzkodgw 1 300 train
+ovcshbboun 1 299 train
+ovctxzpvtl 1 300 train
+ovcyhsanjf 1 300 train
+ovdcmdrcfa 1 300 train
+ovddwoiwxw 1 300 val
+ovduudukfn 1 300 train
+ovdzeeppdj 1 301 train
+oveanytndm 1 300 train
+ovevjfjrwa 1 300 val
+ovewzjygsu 1 300 val
+ovfbhgeqcz 1 300 train
+ovfbrxyutk 1 300 val
+ovfbxmgrbm 1 300 train
+ovfdtwwbyw 1 300 train
+ovfhvudctc 1 300 train
+ovfofddavt 1 300 train
+ovfsgyzbnb 1 300 train
+ovgdweyuio 1 300 train
+ovgfzeeosd 0 300 val
+ovgmdjryiz 1 300 train
+ovgnepwkjq 1 300 train
+ovgqrnnpbl 0 300 train
+ovgsjciwha 1 300 train
+ovguvtnrpz 1 300 train
+ovgvuyqrik 1 301 train
+ovgxgioloa 1 300 train
+ovgxlmesrr 1 300 train
+ovgxmqkekh 0 300 train
+ovhareepul 1 300 train
+ovhchddqzj 0 300 train
+ovhcslzxcd 1 300 train
+ovhhfetnri 0 300 train
+ovhhswylxd 1 301 train
+ovhlmtegsc 0 300 train
+ovhoatgcxk 1 300 train
+ovhsjaciyc 1 300 train
+ovhypdobgc 1 300 val
+ovibsmihvz 1 301 val
+oviehgcscx 1 300 train
+ovigmunwel 0 300 train
+ovigrkqksq 1 300 val
+ovinjtsgyp 1 300 train
+ovipqeeaih 1 298 val
+ovirwjxtht 0 300 val
+ovitaajrqt 1 300 train
+oviywpupnv 1 300 train
+ovizjrutwx 1 300 train
+ovjbjpldzr 1 300 train
+ovjbpiyvtg 1 300 val
+ovjegqynom 1 300 train
+ovjhzdcasd 1 300 train
+ovjqwreykm 1 300 train
+ovjuqhpihp 1 300 test
+ovjyhhnbep 1 300 train
+ovkdbhvkcj 1 300 val
+ovkhhccwao 1 300 train
+ovkjlyfjcd 1 300 train
+ovknujzxrm 1 300 train
+ovkqlfuzsh 0 300 val
+ovkqrxftpo 0 301 train
+ovkqshmusd 1 300 val
+ovlfoixhec 1 300 train
+ovliomjvys 1 300 train
+ovliwusmif 1 300 train
+ovlnhkyatq 1 300 train
+ovlvskmlmn 1 300 train
+ovlyuhmntt 1 300 val
+ovlzztzwor 1 300 train
+ovmbevbxeu 1 300 train
+ovmlyyefja 1 301 train
+ovmokxchsg 1 300 train
+ovmopsyelx 1 300 train
+ovmpdgljcj 1 298 val
+ovmxokkmtn 1 300 train
+ovmzjlhffk 1 300 train
+ovnbtfrvau 1 300 val
+ovnknqhath 1 300 train
+ovnqkxqzua 1 300 train
+ovnzubskbn 1 300 train
+ovockosfnh 1 301 train
+ovocnsotnd 0 300 train
+ovogkdhknn 1 300 test
+ovomxjvrvy 1 298 train
+ovophzxgys 1 300 train
+ovorerqvmd 1 300 train
+ovouujlgap 0 300 train
+ovovxqpgyd 1 300 train
+ovozllyabv 0 300 val
+ovpacrbhay 1 241 train
+ovpbnwrqwl 1 299 test
+ovpbznkgev 1 300 val
+ovpcdagqay 1 300 val
+ovpdmwnggm 1 300 train
+ovpfbapfgb 1 300 train
+ovpfeogoyo 1 300 val
+ovpiqxyxln 0 300 val
+ovpykhowdo 1 300 val
+ovpzbvkuss 1 300 val
+ovqagtungu 1 300 train
+ovqaooglpp 1 301 train
+ovqctgmfpr 1 300 train
+ovqdavuowh 0 300 train
+ovqdjonmlp 1 300 train
+ovqhixefor 1 300 val
+ovqqstqfbk 1 300 train
+ovqxiufqqk 1 300 val
+ovqyuocpet 1 300 train
+ovrcyvavpr 1 300 train
+ovrdqmifez 1 300 val
+ovrfehhrld 1 300 train
+ovrmcqfbdt 1 301 train
+ovrpqqqply 1 300 val
+ovrrzbjthq 1 300 train
+ovrwqsrxgy 1 300 train
+ovrzuqvmnq 0 300 train
+ovsjtbttiq 1 300 val
+ovsmlemylp 0 300 train
+ovsraliubt 0 300 train
+ovsuzzzrpp 1 300 train
+ovtgpwwkrn 1 300 train
+ovtiiepztg 1 300 train
+ovtkuvresc 1 300 train
+ovtlllivpb 1 300 train
+ovtoblnpmj 1 300 train
+ovtpetnzcy 1 300 train
+ovuhszzetv 1 300 train
+ovuubdstvc 1 301 train
+ovvaimjkex 1 300 test
+ovvekkawcx 1 301 train
+ovvjwvejrm 1 300 val
+ovvoywlhig 1 300 train
+ovvqmhpxml 1 300 train
+ovvspzuyjh 1 300 train
+ovvxedmzna 1 300 val
+ovwolrwktu 0 300 train
+ovwqtvisie 1 301 val
+ovwsljwhxp 1 300 val
+ovxgmixhqs 1 300 val
+ovxhrtuuhu 1 300 train
+ovxirtcnpb 1 300 train
+ovxjknuakm 0 301 val
+ovxqacozqb 0 300 train
+ovxwligoon 1 300 val
+ovxyzvbzyj 0 300 train
+ovycdqoabt 1 301 train
+ovyefepixy 1 300 train
+ovymlrdfef 1 300 train
+ovynyicanw 1 300 test
+ovyorvwxpi 1 300 val
+ovysbfaapz 1 300 train
+ovzczlmbcc 0 300 train
+ovzegelwbu 1 300 test
+ovzgfrzwwz 1 300 val
+ovzgovomaw 1 300 train
+ovznffekdv 1 300 train
+ovzqftlomy 0 301 train
+ovzrybxvgr 1 300 train
+ovztlegjtm 1 300 train
+ovzutipuaz 1 300 val
+ovzvfyieyc 1 300 val
+owakmmcyqn 1 300 train
+owalvogmee 1 298 train
+owaogcehvc 1 299 test
+owaslepiun 0 300 train
+owaueogrxh 1 300 val
+owaxsjkxxe 0 241 train
+owbhxjqwvt 1 300 train
+owbictydnj 1 300 train
+owbrnxbprz 1 241 train
+owbtjejult 1 300 val
+owbwunhani 1 300 train
+owbxljwuve 0 300 train
+owccsycepe 1 300 val
+owcfsrkjlm 1 300 train
+owcghnyjey 1 301 val
+owcmgztrrw 0 300 val
+owcrjmtbtq 1 300 train
+owcryyprpv 1 300 val
+owcujgpjir 1 299 test
+owddhzjsto 0 300 train
+owdexridgj 1 299 val
+owdfhkuhum 1 300 train
+owdfxyqayt 1 300 train
+owdnerdiwi 1 300 train
+owdrxaruqd 1 300 train
+owdzltgpey 1 300 train
+oweanvtcuw 1 300 train
+owecaxhloz 1 300 train
+oweduymzqm 1 300 train
+owenlnzkzp 1 300 train
+owfikslizm 1 300 val
+owfjiohsgh 1 300 train
+owfloxjoan 1 300 val
+owfsujuleq 1 300 val
+owfwbipthh 1 300 train
+owfygbgeua 1 300 train
+owfyzzyoca 0 298 train
+owgefmanby 0 298 train
+owgmfjldup 1 300 train
+owgmgeqjyu 1 300 val
+owgnqjrscy 0 300 train
+owgrbqgdqu 1 300 train
+owgrgejzac 1 143 train
+owgwowavcs 1 300 train
+owhdyzbsot 1 300 train
+owhejevdvv 1 239 val
+owhfsgxicr 1 300 test
+owhhlfbyqd 0 300 train
+owhksklreq 1 298 train
+owhlxfnpuk 0 300 train
+owiclrvobm 1 301 train
+owidtvgulx 0 300 train
+owigahxhiy 1 299 train
+owivgxukuu 1 300 val
+owiwfxqzuo 1 300 train
+owjerqchnz 1 300 train
+owjsssuuyk 1 301 train
+owjyagavce 1 300 train
+owjyquhmis 1 300 train
+owkjazxoyy 1 300 train
+owkkmwkfbi 1 300 train
+owklurbwjr 1 298 train
+owkqxibagi 1 300 train
+owkrfyfxpw 0 300 val
+owkuilbyau 1 300 train
+owkvbejepx 1 300 test
+owkvdnrodr 1 300 train
+owlijwianz 1 300 train
+owlkhaplbc 0 193 train
+owllblcors 1 300 train
+owlvlldrmv 1 300 train
+owlwpkwqdy 1 300 test
+owlyaijjkr 0 300 val
+owlzqtoqzm 1 300 train
+owlztwwnum 1 300 train
+owmavenrkh 1 300 train
+owmbbljzuf 1 302 train
+owmrreevyn 1 301 val
+owmsjhkaix 1 300 val
+owmtltdpxu 1 300 train
+owmxgmnafa 1 300 train
+owmzjclufi 1 300 val
+ownaffcado 1 301 train
+ownaiohdwx 0 300 val
+ownidvcljt 1 240 val
+owniqnqpqs 1 300 train
+ownmsiiffw 1 300 val
+ownpxybyxm 1 300 val
+ownxhyntdk 0 300 train
+ownzhpvrrg 1 300 val
+owobcbnvek 1 297 train
+owofixzztz 1 300 train
+owokbsqlqi 1 300 train
+owolozokre 1 300 train
+owonohfmga 0 300 train
+owookbmndy 1 300 val
+owoolnkcpn 0 300 val
+oworeogkmk 1 300 val
+oworhztrsw 1 300 train
+owouphgxul 1 300 train
+owpfabjqyz 1 300 train
+owpgmrzsnk 1 300 val
+owpicswkrh 1 300 train
+owpmmjwttd 1 301 train
+owpngukvfs 1 300 train
+owpnmnygal 1 237 train
+owpoaejeff 1 300 train
+owpqparhxm 1 300 val
+owprqsfeij 1 300 train
+owpuvhkeun 1 300 train
+owpvrudttg 1 300 val
+owpvsbiqia 1 297 val
+owqfinhzwr 1 301 train
+owqgyjveoz 1 300 train
+owqjordbfe 1 300 train
+owqniynalw 0 301 train
+owqoapnvac 0 300 train
+owqqtqhvzx 1 300 train
+owqtpqsqkq 1 300 test
+owqvzzkjki 1 300 val
+owrehfscjb 1 300 train
+owrkhoolbu 1 300 train
+owrowxytoj 1 300 train
+owsesuawmk 0 300 train
+owshgvgpqr 0 300 train
+owsmzuoghm 1 298 train
+owsoljqlob 1 300 train
+owsottcucc 1 300 val
+owsqvrrsfe 1 300 train
+owstcqxrio 1 300 train
+owstggwavf 1 241 train
+owswrljxmw 1 300 train
+owtqwjgalr 1 298 train
+owtuobjmpf 1 300 train
+owtwpphmbc 0 300 val
+owtxrzeqym 1 300 train
+owtzydzwga 1 300 train
+owuawexxrz 0 302 val
+owuhxflwjd 1 300 train
+owujdciifx 1 301 train
+owurwvnzrf 1 300 train
+owusuqruaj 1 300 val
+owuzhberwz 1 300 train
+owvarfpscj 1 300 train
+owvlbkkttz 0 300 train
+owvlkecmxc 1 300 train
+owvmifoxiv 0 300 train
+owvoizqqdu 1 298 train
+owvsphocft 1 300 train
+owvtmwlouu 1 300 val
+owvxxmuceg 0 300 train
+owwelseuah 1 298 val
+owwhciwimz 1 300 train
+owwimwpwba 1 300 train
+owwlwixovi 1 300 train
+owwnesxrsn 1 300 train
+owwsgqubpp 1 300 train
+owwyxgoihe 1 300 train
+owwzpxinio 1 167 train
+owxbbpjpch 1 300 test
+owxdknmbpz 1 300 train
+owxkwkgsar 1 300 train
+owxteuqpay 1 300 val
+owxvfwtgvk 1 300 train
+owxxnqkjoa 1 300 train
+owxyvzlofe 1 300 train
+owxzmycbeh 1 300 train
+owybjhupqb 1 301 train
+owycntpniv 1 300 train
+owyhqsjfbl 1 300 val
+owyihyasfg 1 300 train
+owysamavpo 1 300 val
+owyvdhmvft 1 300 val
+owyvoyjtka 1 301 val
+owyxzafejo 1 300 train
+owzlpciulx 1 300 val
+owznwcnxui 1 301 val
+owzthatuxx 0 300 train
+owzvjlxrbl 1 300 train
+owzwuxrpvk 1 299 train
+oxarxmpfao 1 298 train
+oxaybcwtmr 1 300 train
+oxbbqrgezj 1 300 train
+oxbcpirwua 0 301 train
+oxbhnctrva 1 300 train
+oxbpzwxthc 1 300 val
+oxbqwwiruo 1 298 train
+oxbuvomrto 1 298 train
+oxbygboopc 1 300 val
+oxbzxmjkts 0 300 train
+oxcbalcbmx 1 300 train
+oxcdubjlrv 1 300 train
+oxcimjbwmo 1 301 train
+oxcjtgzvhu 1 300 train
+oxclhaqmbg 1 240 val
+oxclyequth 1 298 val
+oxcmgzeppb 0 301 train
+oxcmjdroro 1 300 train
+oxcoardvze 1 300 train
+oxcodpecir 1 302 val
+oxcpnfyyhp 0 300 train
+oxculumxbc 0 300 train
+oxcvvyjtlr 1 300 train
+oxcztzhmnw 1 300 train
+oxdgfedaav 1 300 train
+oxdkfogcgl 1 301 train
+oxdpbalruk 0 300 train
+oxdqnbjkas 1 300 train
+oxdrbsmogg 1 300 train
+oxdsqzexhu 1 301 val
+oxdstaafic 1 300 val
+oxdwdoeger 1 300 train
+oxebdaqvbm 1 300 train
+oxedkysbst 1 300 train
+oxeerddfob 1 298 train
+oxeujnjtsr 0 300 train
+oxeupoccru 1 300 train
+oxfbbeohio 1 300 val
+oxfbjycxvy 0 300 train
+oxfjzzlxqo 1 300 train
+oxfndxwalz 0 300 train
+oxfptozvcf 1 300 test
+oxfqynvvjy 0 300 train
+oxfzuxwuof 1 300 train
+oxgakbtlrk 1 301 train
+oxgdiacczk 1 300 train
+oxgtzozgtv 1 300 train
+oxgwpghrkm 1 300 val
+oxgyyzdlqh 0 298 val
+oxhcurdwox 1 241 train
+oxhikmjeam 1 300 train
+oxhjvjiswr 1 297 train
+oxhwbownya 1 288 train
+oxiawnwcrq 1 300 val
+oxideejwaq 1 300 train
+oxifigiajh 1 300 train
+oxigonuzjv 1 300 train
+oxijxkrkin 1 300 train
+oxisumxmnu 1 300 val
+oxivdwjxwd 1 300 train
+oxiytzzkia 1 300 train
+oxjakqclvj 1 300 train
+oxjbhtdilp 1 300 train
+oxjehppguj 1 300 train
+oxjlvoodfh 1 300 train
+oxjnuwwuyt 1 300 val
+oxjorlppdh 1 300 train
+oxjzbmgbtl 1 300 train
+oxjzlgifyn 1 300 train
+oxkcckqrng 0 300 train
+oxkgjhjsly 0 300 train
+oxkhvzttzb 0 300 val
+oxkhwrhsui 1 300 val
+oxkkzmshir 1 301 train
+oxktzfjjgj 0 300 val
+oxkxhfbhdo 1 300 train
+oxleitdidp 1 300 val
+oxlfmmwgvi 1 300 train
+oxljjggptm 1 300 test
+oxlkjinaye 1 300 train
+oxlklvpuil 1 297 train
+oxllkntlaq 1 300 train
+oxlneoubcj 1 298 train
+oxltznqogr 1 300 train
+oxluexycgw 0 300 train
+oxmdtzclyh 1 300 train
+oxmggxooin 1 296 train
+oxmhtrdqvf 0 300 train
+oxmiqrbhfv 1 300 train
+oxmkdaymli 1 300 train
+oxmmvpptfo 1 300 train
+oxmxkdizmc 1 300 val
+oxmypwhycs 1 300 train
+oxmyuhoxif 1 301 train
+oxngllhbbo 1 300 train
+oxoavcxkls 1 300 train
+oxokstotfw 0 300 val
+oxolkweezf 1 297 train
+oxopeqblnw 0 297 val
+oxoshlkxmh 1 300 train
+oxoxvrcjti 1 300 train
+oxphfznjkm 1 298 train
+oxplrvbopu 1 300 val
+oxqaxohwmu 1 300 train
+oxqbwgveqh 1 300 val
+oxqfhuofgq 0 300 train
+oxrbleoqze 0 300 train
+oxrgvbynmg 1 300 train
+oxrhxiuhaq 1 241 train
+oxrigyxbuj 1 300 train
+oxrrtafxaw 1 300 train
+oxrvizvmaf 1 300 val
+oxsbxdmpti 1 300 train
+oxsklxucmf 1 298 train
+oxsmxlvbzo 0 300 train
+oxspyzjdrz 1 300 train
+oxsqnojeir 1 300 train
+oxsujfzqgf 1 300 train
+oxsvfsutgx 1 300 train
+oxtdkvspjl 0 300 train
+oxtfktvxui 1 300 train
+oxtfykpjix 1 300 train
+oxthhmwxnz 1 300 test
+oxtszqekyb 1 300 train
+oxttqkjwis 1 300 train
+oxubejzeku 1 300 train
+oxucpxjajz 1 300 train
+oxuhxkzaqj 1 301 train
+oxumzrvhei 1 300 train
+oxuoodqmdm 1 301 val
+oxusjrrkpv 1 301 val
+oxuxaezpgl 1 300 train
+oxuxytmzos 1 300 val
+oxuyvxxlfl 1 300 train
+oxvdzzizbj 0 300 train
+oxvfbwhsej 1 300 train
+oxvzwmxmmt 1 300 val
+oxwfgxmggc 1 300 train
+oxwglsatdl 1 300 test
+oxwhokpriu 1 300 train
+oxwlpqqizc 1 300 train
+oxwvzutbxl 1 300 train
+oxxefnkmfx 0 300 val
+oxxhoqrcop 1 300 val
+oxxiqskgbe 1 300 train
+oxxjesksvt 1 300 train
+oxxkuzvaql 1 300 val
+oxxmrvwwxl 1 300 train
+oxxombdqnk 1 300 val
+oxxoxreyhh 0 299 train
+oxxvycocvt 1 300 train
+oxxyoouphc 1 143 train
+oxyclfakcn 1 300 train
+oxyfirwpvb 1 300 train
+oxyrbtpnad 1 301 train
+oxytemldvt 0 300 val
+oxyyhngqmg 1 300 train
+oxzbmvekxq 1 299 train
+oxzmxkitwc 1 300 train
+oxzrpnxmri 1 300 train
+oxzynkafmq 1 301 train
+oyablneekc 1 300 train
+oyafyvlxwx 0 300 val
+oyaruxqzju 1 300 train
+oyasjkoyyn 1 300 train
+oyawkfyjgs 1 300 train
+oyazcgupml 1 301 train
+oybjngtpsq 1 300 train
+oybkhhbynb 1 300 train
+oybpmgrxwf 1 300 val
+oybwzyvrhn 0 300 train
+oybxaloitb 1 300 train
+oyccygpdwj 0 300 val
+oyclbcxhyi 1 298 train
+oycqiowwmy 1 300 train
+oycurfplrx 1 300 val
+oycxnnxaxd 1 302 train
+oycxpnypzx 1 300 train
+oycymvhpme 0 300 train
+oydauenaco 0 300 train
+oyduhnhtpv 1 300 train
+oydvaohqkv 1 300 train
+oyeknleqqh 1 300 train
+oyeknpowwn 1 300 train
+oyewjxwqec 1 300 val
+oyezqyqogd 0 300 train
+oyfbqpnumn 1 300 train
+oyfkhqrmlq 1 300 train
+oyflnblwlw 1 300 train
+oyfnmrxqkh 0 300 train
+oyfojtsitm 1 300 train
+oyfqgggjix 1 300 train
+oygarvulyn 0 300 val
+oygkytgmtv 1 300 train
+oyglwortsb 1 300 train
+oygpufwaqw 1 300 train
+oygvvmtzjv 1 300 train
+oyhdirhgnv 1 300 val
+oyhhtpvsaj 1 300 train
+oyhiaxpwfa 0 300 train
+oyhkfazbcf 1 300 train
+oyhmctxaua 1 300 train
+oyhwrkvunc 1 300 train
+oyhzfcxirm 1 299 val
+oyijlfccwf 1 300 train
+oyiniibfdc 0 298 train
+oyivdxeewu 1 300 train
+oyivoexwpp 0 300 train
+oyixebfpcl 1 299 train
+oyiycltnaa 1 300 train
+oyjgsuyybk 1 300 train
+oyjhhfsjbd 1 300 train
+oyjjcvcvnv 1 241 train
+oyjmtruwsb 1 300 train
+oyjnnyiege 0 300 train
+oyjrcsexru 1 300 val
+oyjvcyjigb 0 300 train
+oyjzcpvrfg 0 134 train
+oykagryjjd 1 300 test
+oykcgkszaa 1 298 train
+oykggigakm 1 300 train
+oykknrcdzn 1 300 train
+oyknbiotql 1 300 val
+oykspxpzga 1 301 val
+oykuxkfsjv 0 300 train
+oykwlqtcmj 1 300 test
+oylaxlpwrx 1 300 train
+oylcxlwbjs 1 300 val
+oyllgjgwht 0 300 train
+oyllptnzwu 1 300 train
+oylvwuhzbx 1 299 val
+oylwlyvszw 1 300 val
+oylwxegigr 1 240 train
+oymaffzzjv 1 300 train
+oymnojhnuk 1 298 train
+oympxjlwci 1 301 train
+oymwxrcrwd 1 300 train
+oynermlyas 1 300 train
+oyngsppdiv 1 300 train
+oynkwsagfx 0 300 train
+oynljxwyps 1 300 train
+oynlwlruwj 1 300 train
+oynowyqypi 1 300 train
+oynyglnxzk 0 300 train
+oyolfqojjc 1 300 train
+oyomfswhuw 1 300 train
+oyoofaunlk 1 300 train
+oyoqfzutse 1 269 train
+oyotxldqqo 0 300 train
+oyouqfvees 1 301 train
+oyovgwrtdw 1 300 train
+oyowqaxjym 1 300 val
+oyoyvpwnhl 1 300 val
+oypbrohayt 1 241 train
+oypktepcyv 1 301 train
+oypktlycez 1 300 train
+oypqzdrhcr 1 300 test
+oyprndrjcx 1 296 train
+oyptgguhac 1 298 val
+oypuaodmql 1 300 test
+oypyuwsmgy 1 300 val
+oypywnkyrl 1 300 train
+oyqbvqoczz 0 298 train
+oyqdcubpdt 1 300 train
+oyqgwjdwaj 1 300 test
+oyqjkjmpuu 1 301 val
+oyqqanbttr 1 300 train
+oyqutbraxs 1 300 train
+oyqyqwkcjw 1 301 train
+oyqzcawjmh 1 300 train
+oyrarqkntz 1 300 train
+oyrdyxgujt 1 300 val
+oyrykwqidx 1 300 train
+oysaohhfjc 1 300 train
+oysduiwswq 1 300 train
+oysfyrmxkb 1 300 train
+oyskhyfkfe 1 288 train
+oysopgovhu 1 299 test
+oysuxrlirx 1 296 train
+oysxizjpph 1 300 val
+oytafisswv 0 300 val
+oytdishbjw 1 300 val
+oytdvkcyle 1 300 val
+oytgojrqzf 0 300 train
+oytoyafuml 1 301 train
+oytpwrtpvr 0 301 train
+oytuvmdajj 1 300 val
+oyuboltpuv 0 300 val
+oyuduhuobo 1 300 train
+oyustpaaex 1 300 train
+oyusyddofk 1 300 train
+oyuvnuscvz 1 299 test
+oyuvwrvlyp 1 300 train
+oyvmvoikbp 1 300 val
+oyvqovluom 1 298 train
+oyvqwcrorq 1 300 val
+oyvybgekce 1 300 train
+oywddipqux 1 300 train
+oywjytnqpa 1 300 val
+oywoembpla 1 300 train
+oywremcjgb 1 298 train
+oywsozuuyn 1 299 val
+oywyzxrdrh 1 300 train
+oyxcukjayh 1 301 train
+oyxeaakecm 1 300 val
+oyxnhjxagl 1 300 val
+oyxrfcrbjm 1 300 train
+oyycqqgyov 1 300 train
+oyygqcekgh 1 300 train
+oyyihnfjjo 1 300 train
+oyyparauwh 1 296 val
+oyytepfmkv 1 300 train
+oyzbbdngww 1 300 train
+oyzbwojurh 0 300 train
+oyzcbxqqty 1 300 train
+oyzcrfhruy 1 300 test
+oyzvwlpach 1 300 train
+oyzxlcxaxt 1 301 val
+oyzyyowcts 1 299 test
+oyzzqieeyo 1 300 train
+ozaaxjcghl 1 300 train
+ozafahgexq 1 300 train
+ozaghzmdgu 1 299 val
+ozapryfofz 1 300 train
+ozaunurvng 1 300 train
+ozavilhncg 1 300 train
+ozbtaxcfkt 1 300 train
+ozcauqkuhl 1 300 val
+ozcbpsannl 1 298 train
+ozcftgbjeu 1 300 train
+ozclpniwji 0 300 val
+ozcqjxfjwo 0 300 val
+ozcvhxieog 1 300 val
+ozdatjlwpj 1 300 train
+ozdlktjswd 1 301 train
+ozdmdlzfyb 1 300 train
+ozdqbqmtjd 1 300 train
+ozdritglkj 1 300 train
+ozdshlgbul 1 241 train
+ozdubcgxle 1 300 train
+ozdxszexcj 1 300 train
+ozdzhknikx 0 300 val
+ozeacapvug 0 300 train
+ozeczmmafh 1 300 train
+ozehrmmsdn 0 300 train
+ozeihzidqz 1 300 train
+ozeqabydww 1 300 test
+ozezucksgp 1 300 val
+ozfdeamsxw 1 298 train
+ozfihvlapz 1 300 val
+ozfjtggupk 1 300 train
+ozfkbbjzsn 1 300 train
+ozfkbpxyuw 0 300 train
+ozfpcmcffr 1 300 train
+ozfsyclxiq 0 300 train
+ozgaaegfqi 1 300 val
+ozgcmnllow 0 300 train
+ozggqtnllu 0 300 train
+ozggxcpwnm 1 300 train
+ozgirqhhya 1 300 train
+ozgkxhnwcl 1 300 val
+ozgmdndqgl 1 300 train
+ozgqfhubmh 1 300 train
+ozgrnalsrj 0 300 val
+ozgsdfnksv 1 300 train
+ozgwbykjew 1 300 train
+ozgxobguhy 1 300 train
+ozhclfkumk 1 296 train
+ozhcqiyqso 1 300 train
+ozhhaoydlq 0 298 train
+ozhhcvdags 1 300 val
+ozhkcbvilj 1 301 train
+ozhkwjhzxk 1 301 train
+ozhprapubj 1 300 train
+ozhsexdenz 1 300 train
+oziabvzzqc 1 300 train
+ozibrtbhar 1 300 train
+oziciulcow 1 297 train
+ozihohgouk 1 300 train
+ozijvyvxaw 1 300 val
+ozimqtvkht 1 300 val
+oziunbzict 1 300 train
+ozixsxpjkw 1 300 val
+ozjcecsvly 1 241 train
+ozjsukibfx 0 300 train
+ozjvlnehul 1 300 train
+ozjwgstlqm 1 300 train
+ozjxkkzven 0 300 train
+ozkheilyke 1 300 train
+ozkkedgmnk 1 300 train
+ozkkvvcfdm 1 300 train
+ozkkwmlpxl 0 300 train
+ozkwffzdzb 1 300 train
+ozkzexmwpx 1 300 train
+ozlgofxpre 1 300 train
+ozlhgahzrv 1 300 train
+ozlqtmhgus 1 300 train
+ozlweahhsy 1 300 train
+ozlyvycdpq 1 300 train
+ozmdfkkwgs 1 300 train
+ozmhykaadk 1 300 train
+ozmjxwvceb 1 300 train
+ozmsrekfwq 1 299 test
+ozmuryzcbl 1 300 val
+ozndswpkrs 1 300 val
+oznlazhbxn 1 300 train
+oznnxarrlj 1 300 train
+oznopaytrg 1 241 train
+oznstmgvun 1 300 train
+oznxybegip 0 300 train
+oznyyhvzxk 0 299 val
+ozoaccscai 1 300 val
+ozokdwkpwr 1 300 val
+ozomiwmotj 1 241 train
+ozoovdyefi 1 300 train
+ozpjsjrvxi 1 300 val
+ozpqfvzptz 1 301 train
+ozpszrfkej 1 240 train
+ozpwikbqxo 1 300 train
+ozqcccyimc 0 300 train
+ozqgkfxzfn 1 300 train
+ozqhymfrqf 1 300 train
+ozqjfteube 1 300 train
+ozqtybvchj 1 300 train
+ozqysilrin 1 300 test
+ozrdrdfulo 1 300 train
+ozrexytgif 1 300 train
+ozrhdjnfrn 0 300 train
+ozriudaktd 1 146 train
+ozruicxpfb 1 300 train
+ozrvetmbzr 1 300 train
+ozrvtdtxug 0 300 train
+ozryfsmpay 1 300 train
+ozsbqvbdkf 1 300 train
+ozshojgecj 1 300 train
+ozsnwjjjpn 1 300 train
+ozssyofgym 1 300 train
+ozsttdkwqk 0 300 train
+oztagfurmn 1 300 train
+oztamywxjz 1 300 train
+oztclqduvd 1 300 train
+oztdghmdxo 1 300 train
+oztehrzgoh 1 299 val
+oztlyaksqz 1 300 train
+oztsfutdfb 1 300 train
+ozuaquprow 1 300 train
+ozueigbuml 1 300 train
+ozuglqsumz 1 300 train
+ozugngfwmh 1 300 train
+ozunaotrpe 0 301 train
+ozurqvcdvi 1 300 train
+ozusubrnfw 1 300 train
+ozutpoylnz 1 300 train
+ozvhfjilge 1 300 train
+ozvmvzvyao 1 300 train
+ozvoyrduxf 1 300 val
+ozvvnnnhrf 0 300 train
+ozvzbiaoet 1 300 train
+ozvzlqahes 1 300 train
+ozwinjhkeg 0 300 train
+ozwmzqdftr 1 300 train
+ozwwwcbpnr 1 300 train
+ozxfzirmvt 1 300 train
+ozxjhblotg 0 300 train
+ozxmdkchkq 1 300 val
+ozxnjahnyo 1 300 val
+ozxnlkagvs 1 297 val
+ozxpgzwzbx 1 299 train
+ozxpvamtdl 1 301 train
+ozxrqttooz 1 300 test
+ozxwpsnsmz 1 300 train
+ozyaqiajpu 0 302 train
+ozyasrrung 1 300 train
+ozyddamcsi 1 301 train
+ozyflyjsil 1 300 val
+ozynveksqa 1 300 train
+ozyqcnubdl 1 301 val
+ozyuwiepjv 1 300 train
+ozyzfsbehg 1 300 train
+ozzdytjuzq 1 300 train
+ozzeofnvmc 1 300 val
+ozziggrddv 1 300 train
+ozzluqibbw 0 300 train
+ozzqwxvual 0 300 train
+ozztwjorii 1 300 train
+paafevqtsu 1 300 val
+paafipipmy 1 300 train
+paahvepzue 1 300 val
+paaiaerwrc 1 83 train
+pabbtlamdf 1 300 val
+pabdphvxfu 0 300 train
+pabgitcndk 1 300 val
+pabiynasln 1 300 train
+pabjzodbzp 1 300 val
+pabodwqszw 0 300 train
+pabourmqww 1 300 train
+pabrjfbwfz 1 300 train
+pabtvtqbpz 1 300 test
+pabzcmdhpz 1 300 train
+pabzxozppp 1 300 train
+pacbscfltm 0 300 train
+pactbbhnhl 0 300 train
+pacuurfbzl 0 300 train
+paczgushdz 1 300 train
+padavcxqep 1 300 train
+padfwbhhor 0 300 train
+padmotdbpg 1 301 train
+padqeyutvq 1 300 train
+padqtwbzzo 1 300 test
+padwwudrto 1 300 train
+padwzgpltm 1 300 train
+paeamodxqn 1 300 train
+paeclkouob 0 300 val
+paeklpoera 1 300 train
+paepvjfaax 1 300 val
+paeqsfnttc 1 300 train
+paervsnozl 1 298 train
+paeswplkco 1 300 train
+paetjcfzdw 1 300 val
+pafdypymzz 0 300 val
+paflizqbgw 1 300 val
+paftqwwezq 1 300 train
+pagaahnols 1 300 val
+pagiklescm 1 300 train
+pagjhpefjp 1 300 train
+paglifevpx 1 300 train
+pagnmwtkkt 1 296 val
+pagqurxpys 1 600 train
+pagucilkbi 0 300 train
+pagvofnias 1 300 val
+pagwosgroh 1 300 train
+pagyuimypc 1 241 train
+pahafqjgzn 0 300 train
+pahipwmyne 1 300 train
+pahniynyvg 1 143 train
+paholsfnda 1 300 train
+pahullrcpj 1 300 train
+pahzldvzku 1 300 val
+paibvyjuwa 1 300 train
+paigtzbcuv 0 300 train
+paikwrklxc 0 300 train
+pajetbvxkh 0 300 train
+pajggbycri 0 298 val
+pajjlooieh 1 300 val
+pajmnfrixj 1 300 train
+pajqppzkni 1 300 val
+pajzvnmpps 1 300 train
+pakaqfunjq 1 299 test
+pakeiuucnx 1 300 val
+pakfodwmft 1 300 train
+pakgdhujyf 1 300 train
+pakgykbcwg 0 300 train
+pakhovjpht 0 300 train
+pakijlehhl 1 300 train
+pakiuqlpxf 1 300 train
+paklcqiiqq 1 300 train
+paktldrjyr 1 300 train
+pakukatclt 1 300 val
+pakzfoykef 1 300 val
+paljdxjnve 1 299 test
+palrnfqupc 1 300 train
+palsywrlab 0 300 train
+palwgzlmba 1 300 val
+palygabqnw 1 300 train
+pamojtjusq 1 300 train
+pamsdbqrch 1 300 train
+pamsrmxgqt 1 300 train
+pamvpjozlt 1 300 train
+panahwbamx 1 300 train
+panbzognqk 1 300 train
+pancwgfskn 1 300 train
+panievnmvg 1 300 train
+panimijodj 0 301 train
+panktmwixz 1 300 train
+panoentlhl 1 300 train
+panpgwjbkq 1 300 train
+panuaehcgq 1 300 train
+panxpirkfq 1 300 train
+paoknhqggv 1 300 train
+paolclrgbu 1 300 val
+paompiqkwk 1 300 train
+paomqwzfsv 1 300 val
+paonqiveaj 1 300 train
+paorozwtbf 0 300 val
+paozbgimbc 1 300 train
+papagllumt 0 299 test
+papczlmkge 1 300 train
+papialikbm 1 300 train
+papoalwbmv 0 241 train
+papogkywdx 0 300 train
+pappnptcnm 1 299 test
+paprkanano 1 300 train
+paprnidzsl 1 301 train
+papsokzhxh 1 300 train
+paqbaossvc 1 300 val
+paqcbtdulm 0 300 train
+paqeiebsdb 1 300 train
+paqgdupziv 1 300 train
+paqjmbnhng 1 300 train
+paqjslrtim 1 300 train
+paqlwtovpi 1 300 train
+paqrmpmhxq 0 300 val
+paqsyxpozz 1 300 val
+paqwsoroqe 1 300 val
+paqwyiulah 1 300 val
+paqzlxpnvw 1 300 train
+parhbnkojm 1 300 train
+parhhndxxx 1 300 train
+parjwcvtpk 1 300 val
+parkdjbhjp 0 300 train
+parknkxkpz 1 300 train
+parleeczfc 1 300 train
+parqhrknkf 0 300 train
+parqyvrvwr 0 300 train
+parroswabm 1 300 train
+partcfzlbj 0 300 train
+paruakofnh 1 300 val
+parwxygsid 1 300 val
+pasagecaqn 1 300 train
+pasbcpumba 1 300 train
+pasdtqdjcl 1 300 train
+pasfalkyou 1 300 train
+pasgsxejek 1 300 train
+paskmdhehe 1 300 val
+pasrrspfhv 1 301 train
+patfknpnyh 0 300 train
+patqgyehdy 1 297 train
+patvpcdeiv 0 300 train
+patwcfeiaw 1 300 train
+patwngrazw 1 300 train
+pauaxqyfdp 1 300 train
+pauevuopjh 1 241 train
+pauisfxlrl 1 300 train
+paulsbdfla 1 300 train
+paupkdijut 0 300 train
+pautpmicey 1 147 train
+pauvmbrlze 1 300 val
+pavaxttcme 1 298 train
+pavazfdcwu 1 300 train
+pavemgcqot 1 300 train
+pavjetbetb 1 300 train
+pavnwvxcma 1 300 train
+pawihqctpq 1 299 test
+pawkkvfccw 1 300 train
+pawlrrdtqo 1 299 val
+pawlwpbuaj 1 302 train
+pawoqhjpgx 1 300 val
+pawtdtckoc 1 300 train
+pawudloqxi 1 300 val
+pawykqgbvb 1 300 train
+pawztognqj 1 300 train
+paxazaamaw 1 300 val
+paxfyfwnck 1 300 train
+paxjtitipz 1 299 val
+paxluzbqwh 1 300 train
+paxojiwtrl 1 300 val
+paxsvxyngh 1 300 train
+paxsxhsmpb 1 300 train
+paxvaojuay 0 300 train
+payhdwaoar 1 300 train
+payrrychvs 0 300 train
+payxeesfsl 1 300 val
+payznbqsnk 1 300 train
+paziifeeti 1 299 val
+pazjiswczb 1 300 train
+pazpnfrbbc 1 300 train
+pbadlmyohy 1 299 test
+pbadrsbupq 1 300 train
+pbaigknvsm 1 297 train
+pbaihmmyqg 1 301 train
+pbakacwezb 1 300 train
+pbanfxxban 1 300 train
+pbaxktspvn 1 300 train
+pbbbruqnsu 1 300 train
+pbberjqqwe 1 300 val
+pbbmbfwjkl 1 300 train
+pbbrakpsar 1 241 train
+pbbsdbuhfp 1 300 train
+pbburyjavj 1 300 train
+pbbvacvvut 1 300 train
+pbbvzuznel 1 300 val
+pbckyvtqyo 1 300 val
+pbcqfwdvoj 1 300 val
+pbcsghohqz 1 300 train
+pbcsijfsyl 1 300 train
+pbcvtwwles 1 300 train
+pbcyhaxhem 1 300 train
+pbdefybvgw 1 300 train
+pbdfjxodgf 1 300 train
+pbdgeuzspo 1 301 train
+pbdgtdthhb 0 300 train
+pbdqptjxnl 1 300 train
+pbdrgiiccs 0 300 val
+pbdrtbigux 1 300 train
+pbduywizte 0 300 train
+pbdvdpiaqg 1 300 train
+pbechewwtv 0 300 train
+pbecluopht 1 300 train
+pbeipnpbic 1 300 train
+pbeisagfnd 1 241 train
+pbemxkshzl 1 300 train
+pbevlulgcu 1 300 train
+pbewqmmyap 1 301 val
+pbfeaioghf 0 300 train
+pbffbvwvim 1 301 train
+pbfpmtiaxt 0 300 val
+pbfrpuykia 0 269 train
+pbfuoxvsfs 1 300 train
+pbfvoegymi 1 299 train
+pbgfhjnguc 1 301 val
+pbgpdkrpls 1 300 train
+pbgwbzpljw 1 300 train
+pbgwegzcfa 1 300 train
+pbgwovaiao 1 300 val
+pbgzttqrkk 1 300 train
+pbhchnekxp 1 300 train
+pbhhuushkx 1 299 test
+pbhjwpusct 1 301 val
+pbhjzyhcjb 0 298 train
+pbhlrdnarg 0 300 train
+pbhmhadoyy 1 300 train
+pbhopujhoc 1 300 train
+pbhpyjdncc 1 300 train
+pbhqkrqlyw 1 300 val
+pbhufwzsmt 1 300 val
+pbhxrbrrku 1 300 train
+pbifzwsjsl 1 300 train
+pbijstkdiv 1 300 train
+pbimffnqyd 1 300 val
+pbimgfrvyy 1 300 train
+pbimynoliq 0 300 train
+pbinuattig 1 300 train
+pbiruqsdug 1 300 train
+pbiwxfosmq 1 300 train
+pbizryvgyk 0 301 train
+pbizxfzolw 1 300 train
+pbjbpxlhxy 1 300 train
+pbjcdbtkzv 1 300 train
+pbjgkewobu 0 300 train
+pbjhatueqr 1 300 train
+pbjhpkaabb 1 301 train
+pbjtasawpo 1 300 train
+pbjumemtzj 1 300 train
+pbjwfwbgne 1 300 train
+pbjxzxtevq 1 300 train
+pbkkxiasqu 0 300 train
+pbklpeenas 1 300 train
+pbkusfbjtl 1 300 train
+pbkzogduqw 1 300 train
+pblbpyssvo 1 300 train
+pblecccxyh 0 300 train
+pblkmexcne 1 300 train
+pblyfvrqyf 1 300 train
+pbmfrzicsf 0 300 train
+pbmjffmnuy 1 299 val
+pbmokscggz 1 300 val
+pbmxograym 1 300 train
+pbnbnxonox 1 296 train
+pbncfobgyt 1 300 val
+pbnhejrnng 1 300 train
+pbnmyuerwl 1 300 val
+pbnodcmdey 1 297 val
+pbnvhlbdyc 1 300 train
+pbnvrikjca 1 300 train
+pbnxhakrvi 1 241 train
+pbohdlntwi 0 300 train
+pbokzxhchq 1 300 train
+pbolggoodz 1 301 train
+pbomitcxqq 1 300 train
+pbonhwkcyu 1 300 train
+pbonwsviel 1 300 val
+pbopreglsb 1 297 train
+pboqrebanl 1 300 train
+pbouztyjui 1 301 train
+pbpcmorgzt 1 300 train
+pbpgyiimwt 1 300 train
+pbpsgdxplu 1 300 train
+pbpsreimyb 1 301 val
+pbpvclhzlu 1 300 train
+pbqbacuwun 1 300 train
+pbqdffedrq 0 300 val
+pbqdlewphi 1 299 train
+pbqeczokgb 1 300 train
+pbqkcyelgj 1 300 train
+pbqlycmkbr 1 298 train
+pbqmvcjhff 0 300 train
+pbqpyksnhh 1 300 train
+pbquugeujq 1 300 train
+pbrbwgfidv 1 300 train
+pbrfxajzjr 1 241 train
+pbrippwimm 1 300 train
+pbrlugklke 1 300 train
+pbrmaiwpwj 1 300 train
+pbrohovcwm 1 301 train
+pbruohsrvn 1 300 train
+pbrxdmqcxk 1 300 train
+pbsccacgff 0 300 train
+pbsgbpmwst 1 300 val
+pbsgzcgzzd 0 300 train
+pbsmlhgpfm 1 301 val
+pbsolvwful 1 300 train
+pbsrpfvkxl 1 300 train
+pbsuigiaru 1 300 train
+pbsuxscszz 1 300 train
+pbtbftzpia 0 300 val
+pbtnlnnjje 1 300 train
+pbtryzbgpk 1 300 train
+pbtvzniqmb 1 300 train
+pbtzfhwwws 1 300 train
+pbucjlvkvy 1 300 val
+pbulqhifgj 1 300 train
+pbupmskggu 1 300 train
+pbusjrdidl 1 300 train
+pbutehuzky 1 300 train
+pbuxzgoosy 1 300 train
+pbvbnklkjk 1 300 train
+pbvbughief 1 299 test
+pbvdlafiys 1 300 train
+pbvgdthvrs 0 300 train
+pbvgwcwzkg 1 300 test
+pbvmkuszmd 1 297 train
+pbvohvjksz 1 301 train
+pbwkjxypwb 1 301 train
+pbwkrxzgkd 1 300 test
+pbwsljxsku 1 300 val
+pbwsxqabod 1 300 train
+pbwujlzzqk 0 300 val
+pbwvamuxtm 1 300 train
+pbwvwutimh 1 300 train
+pbxbjnsren 1 300 train
+pbxfdrlxit 1 300 train
+pbxibkqmbs 1 300 train
+pbxihvgadx 1 301 train
+pbxlaatohf 1 300 val
+pbxvqvqxem 1 299 test
+pbxzemqngk 1 300 train
+pbyjfcljot 0 300 train
+pbykuchifz 1 300 train
+pbyqtslkmz 1 298 train
+pbzccpcqbz 1 300 train
+pbzdjqryzx 1 300 train
+pbzebyrmqt 1 299 test
+pbzicvjphu 1 300 train
+pbznarokkc 0 300 train
+pbzrnrqasa 1 300 train
+pbzysvigzw 0 300 train
+pcakwgjykd 1 300 train
+pcaleepizr 1 288 train
+pcawwrtvvj 1 300 train
+pcbcpiynqq 1 300 val
+pcbedhrlwc 1 300 train
+pcbupsxmdm 1 300 val
+pcbwggbzpc 0 300 train
+pccwidwbwh 1 300 train
+pccwvkjcpz 1 300 val
+pcdbuvrswx 1 300 train
+pcdmsbhhdc 1 300 val
+pceaundfcd 1 300 test
+pceehdmvzx 0 300 train
+pcegaugmyi 1 300 test
+pcekdmftve 1 300 train
+pcelrizujy 1 298 train
+pceltvtnxu 1 300 train
+pcemgkfqgn 0 300 val
+pceotpzdll 1 298 train
+pcesxmldov 1 300 val
+pcfcdhopca 1 300 train
+pcfixkvnpv 1 300 train
+pcfjybkxff 1 300 train
+pcfoywvxnp 1 300 train
+pcftmgjsii 1 300 train
+pcgccqmgdr 1 300 train
+pcgcdubyfw 1 300 train
+pcghnjekdj 1 300 train
+pcgljdewbq 1 300 train
+pcglwzvjin 1 300 train
+pcgwcmyivm 1 301 val
+pcgyivytcz 1 300 train
+pcgzjlvefp 1 300 val
+pchdcgnyri 1 167 train
+pchjdrkhym 1 300 train
+pchjmpnvyk 1 300 train
+pchqazuitr 1 300 val
+pchqtckpvj 0 300 val
+pchrmtxlvu 0 301 train
+pciinfwwee 1 300 train
+pcipptzbsq 1 300 train
+pcisxemswa 0 298 train
+pcizbxenqk 1 300 train
+pcjbefpcgk 0 300 train
+pcjbktvrfl 1 300 train
+pcjbtaaelo 1 298 train
+pcjksvmulo 0 300 train
+pcjlvsgftq 1 300 train
+pcjobgihdr 0 300 train
+pcjobowefy 1 300 val
+pcjqzgekmj 1 298 train
+pcjsnvqjoh 1 300 val
+pcjwcvnxqg 1 300 train
+pcjwegddfk 1 300 train
+pcjztfcqbz 0 300 train
+pckawmhiec 1 300 val
+pckhdreqzc 0 300 train
+pckjcqwfen 1 300 train
+pckpmctioh 1 298 train
+pckpwzonwu 0 301 val
+pckrcmdoba 1 300 train
+pcktimfquw 1 300 train
+pclbskdaxh 1 300 train
+pcliymzygd 1 300 train
+pcllaioxdh 1 300 train
+pclqdwygdl 1 300 train
+pclvpwxkfm 1 300 train
+pclyaaosgu 1 241 train
+pcmbheaecs 1 299 train
+pcmeaptwyj 1 300 train
+pcmmcgmlon 1 300 val
+pcmmslxfri 1 298 train
+pcncwlmvwt 0 300 val
+pcneengvnh 1 300 train
+pcnftszcof 1 300 train
+pcnhkkxczq 1 301 train
+pcnhxmvamd 1 299 val
+pcnkmybith 1 300 train
+pcobbwvofa 1 300 train
+pcocyshmul 1 301 train
+pcoenxjslw 1 300 val
+pcofbsscpk 1 300 train
+pcokajmcog 0 300 train
+pcoqlgxiha 1 298 train
+pcowuhggmf 1 300 train
+pcoxcmtroa 0 300 test
+pcozzgnflr 1 298 train
+pcpjhubqkv 0 300 train
+pcpkiaeylj 1 300 train
+pcplvkiyis 1 99 train
+pcppquzaji 1 300 train
+pcpqrtrpjr 0 300 train
+pcpzyghloe 1 300 train
+pcqjtlhnkz 0 300 train
+pcqqvhwaov 1 300 train
+pcqqyxwlln 1 300 train
+pcqrvwevar 1 300 train
+pcqsyieekh 1 300 train
+pcqvhpcffq 1 301 train
+pcqyoiwsyq 1 300 train
+pcraykcrki 1 300 train
+pcrcdpjqla 1 300 train
+pcrlgyixwh 1 299 val
+pcrmrwdhrf 1 300 train
+pcrnptmbpe 1 300 train
+pcrosucgdh 1 301 train
+pcrsoapbyt 1 299 train
+pcscrdrpua 1 300 train
+pcsmvapmop 1 300 train
+pcsrwxsymg 1 300 train
+pctbluapeb 1 300 train
+pctfrguzoi 1 300 train
+pctljbtwvx 0 300 train
+pctpdjneks 0 300 val
+pctuczgrlp 1 300 train
+pctvgacdmp 1 300 train
+pcucurduis 0 300 train
+pcufniysrm 1 300 train
+pcuotyhntu 1 298 train
+pcuueshkhj 1 300 train
+pcuvztjqcp 1 300 train
+pcvbkxisks 1 300 train
+pcvhjtzblk 1 299 train
+pcvimrnoim 1 300 train
+pcvpkdmppy 1 300 test
+pcvxanfscx 1 300 train
+pcvygmmnwo 1 300 val
+pcwavxhyrj 1 300 test
+pcwgywgzjf 1 300 val
+pcwkualcwy 1 300 val
+pcwkykzkbn 1 300 train
+pcwnsdytbi 1 300 train
+pcwucommhq 1 300 train
+pcxhggpzuv 0 300 train
+pcxqdiidxu 1 300 train
+pcxzrcnpqp 1 301 train
+pcyakzphsh 1 300 val
+pcyjpslfae 1 300 train
+pcyqmgpayx 1 301 train
+pcyswtgick 1 299 test
+pcyviknuex 1 300 train
+pcywlveepr 1 300 train
+pcywtlkjuu 1 300 train
+pczesudwva 1 299 train
+pczknawtyv 1 300 train
+pczmmzcyct 0 300 train
+pczqsicacb 0 300 val
+pczrmlkgus 1 300 train
+pczsymikmz 1 301 train
+pcztahkayg 1 300 val
+pcztubhrev 1 300 train
+pdaayrmapp 1 300 train
+pdaegbpwwa 0 300 val
+pdahdjknoh 0 300 train
+pdalljyzor 1 301 train
+pdancoiron 1 300 train
+pdanjicwxg 1 300 train
+pdasccqjoa 1 299 val
+pdavwfcdog 1 300 train
+pdaxozyqhl 1 300 train
+pdaykkhfyp 1 300 train
+pdbavdnjcw 1 300 train
+pdbfkvicvd 0 301 train
+pdbkkdhryu 1 300 train
+pdbnzfzqsw 0 300 train
+pdbvtgibqb 1 300 train
+pdbxexfbgp 1 300 test
+pdcdqobnwt 1 300 val
+pdcknnmpmx 1 300 val
+pdcppxebla 1 300 train
+pdcpwuwggl 1 300 train
+pddkcbhapd 1 300 val
+pddpexynxf 1 300 val
+pddplbkfgi 1 300 val
+pddtwssata 1 300 train
+pdebgrasgr 1 300 test
+pdeiloauvd 1 300 train
+pdelesycuv 1 300 train
+pdelmalwsz 0 300 train
+pdeuwimuru 1 300 val
+pdevogygpd 1 300 train
+pdfatkzwiy 1 300 val
+pdfesltdmo 1 300 train
+pdfeuspqnu 1 300 train
+pdfjsxoiaf 0 300 val
+pdfovbcvuw 1 300 train
+pdfqquvstp 1 300 train
+pdfrxjahtk 1 300 val
+pdfsbomyae 1 300 val
+pdgjupwbjd 1 300 train
+pdglgootkv 1 300 train
+pdgvhbetgs 0 300 val
+pdgzsvxvht 0 300 val
+pdhcxpreut 1 300 train
+pdhozabkzd 0 300 train
+pdhrguedab 1 300 train
+pdhvopnmai 1 300 val
+pdhvpsweqz 1 300 train
+pdhxnndbbt 1 301 train
+pdiapkumma 1 300 train
+pdiihkmiih 1 300 train
+pdilvgdayq 1 300 val
+pdinwwqhep 1 302 val
+pdiozvcjlh 0 300 train
+pdiuyakpgs 1 300 train
+pdjfgrdkmm 1 300 train
+pdjmsicglg 0 300 train
+pdjrykqwhi 1 300 train
+pdkaffjxtx 0 300 train
+pdkgklawrq 1 300 val
+pdkmxhnfmx 0 300 val
+pdksxjxrba 1 300 val
+pdkupdaaig 1 300 val
+pdlhczckcp 1 300 train
+pdlkgfrkpj 1 300 train
+pdlltmgala 1 300 train
+pdlqgytjtg 1 298 train
+pdluagfvve 1 298 train
+pdlvqmrvvr 1 300 train
+pdlxtkajzt 1 300 train
+pdmkdopqkg 1 300 train
+pdmnppvldn 1 301 train
+pdmqbywdfc 1 300 train
+pdnjugtmmp 1 300 train
+pdnnaosgga 1 241 train
+pdnwaekrtn 1 300 train
+pdoagttqyt 1 300 train
+pdohqavwbu 1 300 train
+pdoiepxpxz 0 297 train
+pdoifsuglx 1 301 train
+pdoisliruc 1 300 train
+pdooagkgdl 1 300 val
+pdooqxqfrm 1 300 train
+pdotikoxhv 1 300 train
+pdotjwgdhi 1 300 train
+pdouadxxba 1 300 test
+pdoytnqzvo 1 300 train
+pdozhcjezh 1 299 test
+pdpcxdtpvw 1 301 train
+pdpdcqefib 1 300 train
+pdphhsdbls 0 300 train
+pdpmufxbuf 1 300 val
+pdpngvznpd 1 300 train
+pdpnuwozmd 1 301 train
+pdppmhzdrd 1 300 val
+pdpqzrrept 1 300 train
+pdpuqjqffh 0 300 train
+pdpvowopmv 1 299 val
+pdpwmrlmcd 0 300 train
+pdqejvlnmz 1 300 train
+pdqeumircg 0 300 val
+pdqiwdmydh 0 300 train
+pdqmaekjjh 1 300 train
+pdqqkuclvd 1 300 train
+pdrazlhnxg 1 300 train
+pdrfgftkcg 1 300 train
+pdrmddxfwb 0 300 train
+pdrnulyvee 1 298 train
+pdrwwtfzpc 0 300 train
+pdryawowdi 0 300 val
+pdrzpgpgpf 1 300 train
+pdsbvaladp 1 300 train
+pdscdzzipt 1 300 train
+pdsdivtzew 1 300 train
+pdsfmfmmvn 1 298 train
+pdsnkudnsw 1 300 train
+pdsvyhsfhf 1 300 train
+pdswwyyntw 0 300 test
+pdtjbwfuva 1 300 val
+pdtuzuvwvv 1 300 train
+pdtwuudbpd 1 300 train
+pdtxxkldij 1 300 val
+pduchcpqhj 1 300 val
+pduddvgwes 1 300 train
+pdufsewrec 0 300 test
+pduhrlplwh 0 300 val
+pduoolrqno 1 300 val
+pdupvpsldz 1 300 train
+pdurppbdiw 0 300 train
+pduskesxgz 1 299 test
+pduxraqmjn 1 300 train
+pdvgvbeauu 0 300 train
+pdvowfwnhw 1 298 train
+pdvqechvay 1 300 train
+pdvqjhozha 1 300 train
+pdvwrffsyb 1 300 train
+pdwcwgyzxh 1 300 train
+pdwifqspsy 1 300 train
+pdwlwtneaz 1 298 train
+pdwmypzojj 1 300 train
+pdwotqldbz 1 136 train
+pdwsngffox 1 301 train
+pdwvmcymhl 1 300 val
+pdwwczhhla 1 300 val
+pdwyyugyvx 1 300 train
+pdxgdaldbe 1 301 train
+pdxrkshcdo 0 300 val
+pdxrlgsqix 1 300 train
+pdxvcaqsau 1 300 train
+pdxvxptjdr 1 300 train
+pdxwcjbeks 1 300 train
+pdycxfmwxo 1 241 train
+pdygulyckt 1 300 train
+pdyijrcwoj 1 300 train
+pdyrfqhgip 1 300 train
+pdyrvsvwyi 0 300 train
+pdywmdvvjy 1 300 val
+pdyzfebndx 1 300 train
+pdzadxxidz 1 299 test
+pdzaguqmze 1 298 train
+pdzhiputvx 1 300 train
+pdziklnxmv 1 300 train
+pdzjuvqtxa 0 300 train
+pdzjyvinqh 1 300 train
+pdzrfhgvql 1 300 train
+pdzshpxeoc 1 249 train
+peaadqwyrb 1 300 train
+pealxhfsyw 1 300 val
+peanfbmcfe 1 300 val
+peanrghvrj 1 300 train
+peaunwrbwi 0 300 train
+pebhzwnycq 1 300 train
+pebowyptab 1 300 train
+pebxahyaac 1 300 train
+pecbwoiwnf 0 300 train
+pecfebamhg 1 300 train
+pechdwdmxb 1 300 train
+pecmokwhqn 1 300 train
+pecuvosgtj 1 300 train
+pecvomwcjv 1 300 train
+pedfvxzrrn 1 301 val
+pedmbqvqml 1 300 train
+pedsclwnst 1 240 train
+pedtyyixbi 1 300 train
+pedvwzmuqx 1 300 train
+pedwbegauf 1 300 train
+peegnhnmgz 1 300 train
+peehtgcnda 0 300 train
+peemmndlzq 1 300 train
+peemztweyz 1 300 test
+peenogqkhs 1 300 train
+peepznuezr 1 300 train
+peeujyxwyv 0 300 train
+peezjbhcny 0 300 train
+pefenralgo 1 300 train
+peffbdnipj 1 300 val
+pefjixgwzc 1 300 train
+pefpvnmcxj 1 301 val
+pefqwgnptw 1 300 train
+pefwyzhjuw 1 300 train
+pefzmeuuoq 1 300 train
+pefzusozao 1 300 train
+pegahbxhmc 1 300 val
+pegcpyymnc 1 300 train
+pegeauyezt 1 300 test
+peghucgqnp 1 301 val
+peglbfleye 1 300 train
+pegqehthsn 1 300 train
+pegwjwhwey 1 300 train
+pegyahnwzv 1 300 train
+pegzryxnmn 1 300 train
+pehcvcxwax 1 300 train
+pehfopbcsu 1 300 train
+pehjcqlhih 1 297 train
+pehkqyoddu 1 300 val
+pehmdoijqb 0 298 train
+pehpmkoltv 1 300 train
+pehrqgnrix 1 300 val
+pehzjkpbrd 1 300 val
+peifyrheof 0 300 train
+peinusukoj 1 300 val
+peitvmldwj 1 300 train
+peiylbrdvd 1 300 train
+peiyocyctt 1 300 train
+pejauhugvd 0 240 val
+pejglsqhbk 1 298 train
+pejjmegtvd 1 300 val
+pejngsqzrb 0 300 train
+pejnqlovvf 1 300 train
+pejrnudjqj 0 300 train
+pejtahlmir 0 298 train
+pejzqhnful 1 300 val
+pejzzeqqso 1 300 train
+pekdfbzcbg 1 301 train
+pekdwcreph 1 300 val
+pekeufbstw 1 300 train
+pekiidkahg 1 300 train
+pekodqqbax 1 300 train
+pekoptuztj 1 300 train
+pekovmmyxu 1 300 train
+pekqurpsnz 1 300 train
+peksfslqei 1 300 val
+peksgfgnkm 1 301 val
+pelbstehdi 1 301 train
+pelfblynzg 0 300 train
+pelmgfqkmh 1 300 test
+peluotflpj 1 300 train
+pemiibmvkj 1 300 test
+pemmbepcqb 1 300 train
+pemnqzrjgf 1 300 train
+pempjmlwye 1 300 val
+pemtgysumu 1 300 train
+pemvnndlhg 1 300 train
+penedkkzfw 1 300 train
+penimmldnu 1 300 val
+penlswonan 1 301 train
+penmhaiumk 0 300 train
+pennrxudib 1 300 train
+peockgyzmh 1 300 train
+peocvrpoig 1 300 train
+peoqwxxdeo 1 300 train
+pepaibwxnd 1 300 test
+pepawstyfn 1 300 val
+pepjfmkwvj 1 300 train
+peponvetib 0 300 train
+peptttzoea 1 300 train
+pepucbvsvm 1 300 train
+pepxofvpjc 0 300 train
+pepxtpjycb 1 300 train
+peqcvngswr 1 300 train
+peqldvmjea 1 298 train
+peqlttygov 1 301 train
+peqrlhqeuk 0 300 train
+peqtejnxvv 1 300 train
+peqxzilwmp 1 300 train
+perdsgqlon 1 296 train
+perdujoudu 1 300 train
+periusnwzu 1 300 train
+perjjlopoj 1 240 val
+perpssnlds 1 300 train
+pertjakiyi 0 300 train
+pervbktnai 1 300 train
+pervjtfuqu 1 301 train
+perxsrzxzz 1 300 train
+perzdjoxiy 1 298 train
+pescizvikx 1 300 train
+peshwuxnud 0 300 train
+pesjaihbck 1 300 train
+pesqnkqhrw 0 300 train
+pesyqidiby 0 300 val
+pesyvsqgyu 1 241 train
+petmyhjclt 1 300 test
+petsnbtucc 1 300 train
+petuppxkja 1 241 train
+petywzdgbi 1 300 train
+peudqorlnf 1 300 train
+peudsjqzjk 1 300 val
+peugiwfvou 0 298 train
+peukesdpmk 1 296 val
+peurczgxaw 1 300 train
+peuvsalpjw 1 300 train
+peuxoirusp 1 300 val
+pevdekambm 1 300 train
+pevhrejwcc 1 300 train
+pevmkpamhv 0 299 val
+pevrpalcfm 1 300 val
+pevstfrnqp 1 300 train
+pevthmobaq 1 300 train
+pevufhyyni 1 301 train
+pevufxnibs 0 300 train
+pevwcvuuez 1 300 train
+pewbrjbels 1 300 val
+pewdreqrnp 1 300 train
+pewkirkxrp 1 300 train
+pewlzrwtay 1 300 train
+pewsydjklq 1 300 train
+pewuttcaoh 1 300 train
+pewxnsvmso 1 300 train
+pexasojmle 1 300 val
+pexholbdwg 1 299 train
+pexiqiljic 1 300 train
+pexjjnoqul 0 300 val
+pexlesuipw 1 300 train
+pexrwhavzg 1 300 val
+pexvnbrtsv 1 300 train
+pexvxscexv 1 300 train
+pexxvjcuzs 1 239 val
+peyahtabll 1 300 train
+peyfcytcef 1 300 val
+peygzpnkuf 1 298 train
+peysyddtmp 0 299 test
+peyunwdbci 1 300 train
+peywryldov 1 300 train
+peyxdbhxze 1 300 train
+pezhcpzztc 1 300 train
+pezibjdxzx 0 300 val
+peziuqyoov 1 300 train
+pezloxvvwu 1 300 train
+peznetkywq 1 300 train
+pezroiauas 1 298 train
+pfaifvzmaa 1 300 train
+pfakrrvjjz 1 241 train
+pfanufsftu 1 300 val
+pfatjcyalg 1 299 train
+pfaxkqcuqn 1 300 train
+pfazzaldpy 1 300 train
+pfbdxvexft 0 300 train
+pfbeoogfie 1 300 train
+pfbfasuujc 1 300 train
+pfbicotttj 1 300 train
+pfbkiautzr 1 300 train
+pfbweljqmw 0 300 train
+pfbwlvnqwy 1 300 train
+pfcigbbhvm 1 302 train
+pfcsaohymt 0 300 train
+pfctgceckn 1 300 train
+pfdaxdzrqa 0 300 train
+pfdbrzzphb 1 300 train
+pfdcrnrgnw 1 300 train
+pfdeaoykqt 1 300 train
+pfdisnlppn 0 300 train
+pfdjrgimcs 1 298 train
+pfdsyxmmjv 1 300 train
+pfdzvxaics 1 300 train
+pfeapodpao 1 298 train
+pfebepkzwr 1 300 train
+pfeesldjdn 1 300 train
+pfehljsywg 1 300 train
+pfejkynkyx 1 300 train
+pfelpammxb 1 300 train
+pfemtehnsy 1 300 train
+pfettcsavz 1 301 val
+pfewlslgav 1 300 val
+pfeydnthnw 1 300 train
+pfffjetpqf 1 300 train
+pffinncnps 1 300 test
+pffnbezptp 1 300 train
+pffsmfqkmi 1 300 train
+pffuozxjwd 1 300 train
+pffvlswgxc 1 269 train
+pfggbyhryz 1 300 train
+pfghlqtwvm 0 300 train
+pfgqzgufja 1 300 train
+pfgtpjzvqc 1 301 val
+pfgurhcfop 1 300 train
+pfgxumcwyo 1 300 train
+pfhfahmoys 1 300 train
+pfhgchbjqg 1 300 train
+pfhhczoboq 1 302 val
+pfhmcogosi 1 300 test
+pfhnyfdrwl 1 300 train
+pfhpjrqgto 1 300 train
+pfhqhxqhoh 1 300 train
+pfhturyril 1 300 val
+pfhweukfvq 1 300 train
+pfiigjlcct 0 300 train
+pfijgvbkjp 1 300 train
+pfikdljbay 1 300 train
+pfirqpwcwe 1 300 train
+pfiryryivq 1 300 train
+pfivzyerby 1 300 train
+pfixcuhlbc 1 300 train
+pfjeswpnez 1 300 train
+pfjhmlzsnw 1 241 train
+pfjirvgiue 1 300 val
+pfjmkrdbay 0 288 train
+pfjpbhijzr 0 300 train
+pfjqemmnwq 1 300 train
+pfjspqgbnr 1 300 val
+pfjvipszpa 1 300 val
+pfkfiqesoj 1 300 train
+pfkfvfsxfd 1 300 train
+pfkhukuyml 1 300 train
+pfklensnqd 1 300 train
+pfklhhzoqb 1 300 train
+pfkmfewiix 1 301 train
+pfkmnpeimc 1 300 train
+pfkoduevfa 0 300 val
+pfkpabocti 1 302 train
+pfkwfeddrt 1 300 val
+pflgqiqawo 1 300 train
+pflnmyfdea 1 300 train
+pflwvifizc 1 300 train
+pflxfgrahm 1 300 train
+pflxnexhbv 1 300 train
+pfmaqqxook 1 300 train
+pfmhuqdizq 1 300 train
+pfmnqiwfvv 1 241 train
+pfmpswwsih 1 301 train
+pfmqommgzg 1 300 train
+pfmtwnkbfc 1 299 val
+pfmwpzpald 1 300 train
+pfncoqnjpp 1 300 train
+pfnevzdekk 1 300 train
+pfnhpletgn 1 300 train
+pfnjqdebhk 1 300 train
+pfnlffezum 1 300 train
+pfnmvzjffw 1 300 train
+pfnqtomknq 1 300 train
+pfntrkxtau 1 300 train
+pfnwptulcp 1 299 test
+pfnzijbsvl 1 300 train
+pfohbtcvow 1 299 val
+pfoiiepvxb 1 300 train
+pfopkowwfo 1 300 train
+pfoptlyazk 0 300 train
+pfpahwmhos 1 300 train
+pfpbnavgkp 1 300 train
+pfpcjdevuy 1 300 val
+pfpeofasyl 0 300 train
+pfpnjcjzxh 1 300 train
+pfpoucdemr 1 300 train
+pfppqtgrko 1 300 val
+pfpxrcbrmj 1 300 val
+pfpywtuptj 1 300 train
+pfqdhamqgq 1 300 train
+pfqdlnafcx 1 298 train
+pfqinapvue 1 300 train
+pfqkvwlvtk 1 300 train
+pfqrgzszqf 1 300 train
+pfqrwqdvfv 1 300 train
+pfqteuxfip 1 300 train
+pframtxswx 1 300 test
+pfrghhmuwf 1 300 train
+pfrhiwfnia 1 300 val
+pfrhvklprx 1 300 val
+pfrijalpxc 1 300 train
+pfrribcoce 1 300 train
+pfrwwfnkhp 1 300 train
+pfsgcsckcf 1 301 train
+pfsolchpan 1 300 val
+pfsoupegvm 1 300 train
+pftbukprmr 1 300 train
+pftfakmxpw 1 300 train
+pftftfvqoa 0 300 train
+pftifpfbqr 1 300 val
+pftjmfpnld 1 300 train
+pftmgpdxte 1 300 train
+pftrwqispi 1 300 val
+pftsiqvimg 1 300 train
+pfubifotov 1 299 train
+pfujbaumtj 1 299 train
+pfujjbouxp 1 300 val
+pfunimrums 1 300 train
+pfutkryvxz 1 300 val
+pfuwmrlsey 1 241 train
+pfuzwoecsb 1 300 train
+pfvbpqjaxg 1 300 test
+pfvfpotmib 1 300 train
+pfvlgficdf 1 300 train
+pfvnhmbgfl 0 300 val
+pfvpevylmp 1 300 train
+pfvtjnsxni 1 300 train
+pfvtungyat 1 297 train
+pfvudxruqw 1 300 train
+pfvygvdlyi 1 300 train
+pfvynemzlz 1 300 train
+pfvyuxknea 1 300 train
+pfvywdrbno 0 300 train
+pfwipsalvc 1 302 val
+pfwjchfgcf 1 300 train
+pfwrsyhcfm 1 301 train
+pfwzlcyfmj 1 300 train
+pfxaczizct 0 300 train
+pfxfhcmtms 1 300 train
+pfxrwbrdzp 1 300 train
+pfxrzwtcpp 0 300 train
+pfxtruaxsa 1 300 train
+pfybfdfhrr 1 300 train
+pfyhpwzmdv 1 298 train
+pfymnavyvy 1 300 train
+pfymqrhdqc 1 300 train
+pfymuncwij 1 300 val
+pfyrmrezpf 1 300 val
+pfywkxivvl 1 300 train
+pfyzmrxkff 1 300 val
+pfzbxqaits 1 300 train
+pfzencsnra 1 300 train
+pfzernosgy 1 300 val
+pfzfafciut 0 297 val
+pfziqkaxsy 1 300 train
+pfzoljontz 1 300 train
+pfzxcvpscj 1 300 val
+pfzyojyifc 1 300 train
+pgaawyogty 1 300 train
+pgaetihrcu 1 301 train
+pgalolvmpb 1 300 val
+pgamqeolau 0 295 train
+pgauaefvqv 1 300 train
+pgaxcmlqoy 1 300 train
+pgayhfelvj 1 300 train
+pgayodzggm 1 300 train
+pgbafqqjfx 1 300 train
+pgbbbcmotu 1 300 train
+pgbbhqrosl 1 300 val
+pgbcjacpdm 1 302 train
+pgbebqbazd 1 300 train
+pgbekpvdrl 1 300 train
+pgblcbggla 1 300 val
+pgbogwgkty 1 299 val
+pgbtlcedst 1 300 train
+pgcdvzzwqu 1 270 train
+pgckoxvxvd 1 300 train
+pgcqanbpmm 1 300 train
+pgcqefcqxn 1 300 train
+pgcxyyuqud 1 300 train
+pgdjbepvga 0 300 train
+pgdjkimgen 1 241 train
+pgdjphqudl 0 300 train
+pgdnvaylvb 1 300 train
+pgdoulrxmv 1 300 val
+pgdrvshvtv 1 300 train
+pgehjsocyc 1 300 test
+pgeibxkxri 1 300 val
+pgeplqsucl 1 288 train
+pgeradpczz 1 300 val
+pgeromqhwc 0 300 train
+pgeticpgfe 1 300 val
+pgeuwajhnv 0 300 train
+pgewhmwsdj 0 300 train
+pgfdceyumq 1 300 train
+pgfgfaleuk 1 300 train
+pgfmcbofnx 1 300 train
+pgfoawjjzc 1 300 train
+pgfpqworwx 1 300 train
+pgfqwbzfgs 1 300 train
+pgfscelxqf 1 299 train
+pgftxrhtyr 1 298 train
+pgfxdqdsdj 0 300 val
+pggklhbzzr 1 301 train
+pggnkkcfcu 1 300 val
+pggznwtoyc 1 300 train
+pghdhuhktt 0 300 val
+pghhhcxhgr 0 302 val
+pghjlvczdr 1 301 train
+pghraehpov 1 300 train
+pgicbcvuct 1 300 train
+pgihjfeqap 0 300 train
+pgiicogiwa 0 300 train
+pgioqqehjk 0 300 train
+pgixnuwujy 0 300 val
+pgjedehsrc 1 300 train
+pgjfjhzsyx 1 299 val
+pgjhkmpido 1 300 val
+pgjhuvwjjj 1 301 train
+pgjjbewpjk 1 300 train
+pgjpqbonbc 1 300 train
+pgjvozsmtm 1 298 train
+pgkgnnxdgf 0 300 train
+pgkhzdbvpp 1 300 train
+pgkipgmpgm 1 301 train
+pgknsucirf 1 301 train
+pgksrfzfjq 1 300 train
+pgkwulqxfb 1 300 train
+pgkzwuslmz 1 300 train
+pglazlvhuh 0 300 val
+pglbgnclte 0 300 train
+pgligbvwjt 1 300 train
+pglroykzea 1 300 test
+pglsbtmyow 0 300 val
+pglxqhpuor 1 300 train
+pgmduvhmrb 1 300 train
+pgmnneikmh 1 300 train
+pgmnnzwcuu 0 300 train
+pgmofbgeam 1 300 train
+pgmomnsegu 1 301 train
+pgmtzjlzca 0 300 val
+pgmuaswkgc 1 298 train
+pgmvfgpayi 0 300 val
+pgnillxhdt 1 300 train
+pgnlxdoaeb 1 300 train
+pgnlzgbcxo 0 300 train
+pgnnygfrea 1 300 train
+pgnoiqaeka 1 300 train
+pgnvdnglop 1 300 train
+pgoadfkyxz 1 147 train
+pgoavrrrsw 1 300 train
+pgoblsrzra 1 299 test
+pgojgewclb 1 298 val
+pgopxdjajv 0 300 train
+pgoqoftykk 0 300 train
+pgpbzlgpmr 0 300 train
+pgppbfpdou 1 300 train
+pgprkusoma 1 300 train
+pgqcghptso 1 300 val
+pgqefposvd 1 300 val
+pgqeigxtew 1 300 train
+pgqjlflxxg 1 300 train
+pgqjsdjxhv 1 300 train
+pgqosmltga 1 300 train
+pgqpfxwjil 1 241 train
+pgqpnmhzfi 1 300 train
+pgqrjzhtlb 1 300 train
+pgqtothimz 1 301 train
+pgqxguqyyw 1 300 train
+pgqxsteufx 0 300 train
+pgrdsyycma 1 300 val
+pgrghbkdje 1 301 train
+pgrglkurfm 1 300 val
+pgrouxrodc 1 300 train
+pgrqayrsxm 1 300 train
+pgrsvdbdrs 1 297 train
+pgryrxzyrz 1 300 train
+pgsbxkcwrl 1 300 train
+pgsnltghzq 1 300 train
+pgspbngzjk 0 300 train
+pgsruznldm 1 300 val
+pgtbhvacae 1 300 train
+pgtcqolgtk 1 300 train
+pgteqymmle 1 300 train
+pgtfaxfujh 1 300 train
+pgtgwwqlco 1 300 train
+pgthoxzpbv 1 300 train
+pgthripvcc 1 300 train
+pgtvazqygp 1 241 train
+pgtwkdclhd 1 241 train
+pgtzthiias 0 300 train
+pgufzhctta 1 300 train
+pgumwaujqo 1 300 train
+pguofzxhww 1 300 train
+pgupgtjrkh 1 300 train
+pguqaxsskk 1 302 train
+pgutuxhmdu 0 300 train
+pguuromwvc 1 300 train
+pgvdvpudwz 1 300 train
+pgveoabpom 1 300 val
+pgvgeizpmw 1 300 val
+pgvkkpnfrg 0 300 train
+pgvklnnggc 1 300 train
+pgvsrgssys 1 300 train
+pgvvblzlzt 1 300 train
+pgvxcsjbts 1 601 train
+pgvxowmyxf 1 241 train
+pgwcoaaoey 1 298 val
+pgwfiyyecy 1 300 train
+pgwhxxyqsp 0 300 val
+pgwlpvpflv 1 240 train
+pgwlrcxmrj 1 300 val
+pgwnbbmjlz 1 300 train
+pgwpcyslaa 1 300 train
+pgwpxfigbd 1 300 train
+pgwvfxoarb 1 298 val
+pgwvpgnoeq 0 301 train
+pgwxfdnats 1 300 train
+pgxakoeuoz 1 300 train
+pgxgcdsaym 1 300 train
+pgxmzmhjfp 0 300 train
+pgxorcqskw 1 300 train
+pgxtpcxido 1 300 val
+pgxubagpzg 1 300 train
+pgxuwsjdil 1 300 train
+pgxxjaglrb 1 300 train
+pgyavbqnmd 1 300 val
+pgybijkufg 1 300 train
+pgybkismem 1 300 train
+pgybuuxxip 0 299 val
+pgykvnimbr 1 299 train
+pgymnjffbq 1 300 train
+pgymygjkvg 1 300 val
+pgyqassges 1 300 train
+pgyrbuytsb 0 300 train
+pgzcnjsocc 1 300 train
+pgzdmvrgkb 1 300 train
+pgzduygsyr 1 300 test
+pgzfmxuyeb 1 301 train
+pgzgiemasc 1 249 train
+pgzjhkinwl 1 300 train
+pgzuxaolfg 1 300 train
+pgzvpogpus 1 241 train
+pgzxihvukd 1 300 train
+pgzyjqokxi 0 300 train
+phabcdabjw 1 300 train
+phameqnkbp 1 300 train
+phamnqefsb 1 300 train
+phamutsikb 0 300 train
+pharlnoque 0 300 train
+phattrhhqe 1 300 train
+phayrtdwzc 1 300 train
+phayzlcgft 1 300 train
+phbalkodbj 1 300 train
+phbfereecq 1 300 train
+phbicwxpar 1 300 train
+phbipayqrd 1 300 train
+phblsyxojq 1 300 train
+phbmbfhavm 1 300 train
+phbpgrqwda 1 300 train
+phbrjhgwda 1 298 train
+phbxrphchc 1 239 train
+phbyfvzifo 1 300 train
+phbymmakgu 1 300 train
+phbyrwfsst 1 300 train
+phcagajawr 0 300 train
+phcbhjtqwa 1 300 train
+phckycghnc 1 300 train
+phcqqkwlcs 1 300 train
+phcsghljje 0 300 train
+phctsyvszl 0 300 train
+phczzdttii 1 300 train
+phdazfsqwm 1 241 train
+phdcbpvzec 1 300 train
+phdeeqinbn 0 300 train
+phdfcdvyeh 1 300 val
+phdfvwrsak 1 300 train
+phdljoezcb 1 298 train
+phdpevwbce 1 240 train
+phdpxlkmhg 1 300 train
+pheefnbikw 1 300 train
+pheffsftdw 1 300 val
+phemrvujbn 1 300 train
+phenmpozjd 1 300 val
+phetysaffc 0 298 train
+phfanfjvia 1 298 train
+phfawjofgg 1 300 train
+phfljescxp 1 300 train
+phfljuoghg 0 300 val
+phfmokppkl 1 300 train
+phfsxapcnl 1 300 train
+phfsylhfvy 1 300 train
+phfxhnfctk 1 300 train
+phgazakbji 1 300 train
+phgfbzahpm 0 300 train
+phgflxgihn 1 300 train
+phgpddrcpe 0 300 train
+phgrxkimke 0 300 train
+phgsierzvm 1 300 val
+phgttemupy 1 300 train
+phgztyaash 0 300 train
+phhbzksbkx 1 300 test
+phhegcugrp 1 300 train
+phhhcbwbzm 1 300 train
+phhqbvmftl 1 300 val
+phhqimjgfz 1 300 val
+phhurtgxzv 1 300 val
+phhwfqdnjw 1 300 train
+phhwvsvunt 1 299 train
+phhzyqiipa 1 300 train
+phihlosgyu 0 300 train
+phiirijpsr 0 300 train
+phikrokdvx 1 300 train
+philxwuuxh 1 300 test
+phipmxzwuq 1 300 train
+phixbbgzxv 1 241 train
+phiysjqfxs 1 300 train
+phjdnzohhi 1 300 train
+phjevxqkxu 0 301 train
+phjijpwnhi 1 300 train
+phjkvvycml 1 300 train
+phjlaexgcl 1 300 test
+phjlqbwqay 1 300 train
+phjmferyds 1 300 val
+phjmuqxvic 1 298 val
+phjpxiynnq 1 300 train
+phjvutxpoi 0 300 test
+phjzjjposx 1 300 train
+phkedcqloh 0 300 train
+phkfwtfvck 0 301 val
+phkpguovju 0 301 train
+phkpsptxrt 1 300 train
+phldkjsjun 1 299 train
+phljvfnjgq 0 300 train
+phmagcfdjt 1 300 train
+phmfgsbfgg 1 300 val
+phmfmuuahj 1 300 train
+phmnxnimmv 1 300 train
+phmpdrppom 0 300 val
+phmrzkqlbb 1 300 train
+phmuivlsju 0 300 val
+phnfmbvpxn 1 300 train
+phngwcpbqw 1 300 train
+phnhdibmjj 0 300 train
+phnhybgiyq 1 300 train
+phnjyrcrro 1 300 train
+phohkjxoaz 1 302 val
+pholfgxmyr 1 300 val
+phopeeawsq 1 300 train
+phoqlrkong 1 301 val
+phoqtdgldh 1 300 train
+photozuczx 1 299 train
+phovymgglb 0 300 train
+phoxxwoozc 1 300 train
+phpdlrumno 1 298 train
+phpnewbqxn 1 300 train
+phpnlnvffy 1 300 val
+phppqqvzom 1 300 val
+phpqcnwmie 1 300 train
+phprwvesya 1 300 train
+phpthopptz 1 301 train
+phpuisgsfb 0 298 val
+phqcahhnjv 1 300 train
+phqkqjvacf 1 300 train
+phqmeegezs 1 300 val
+phqmjblkoq 1 300 train
+phqotqxuia 1 300 train
+phqoziigfb 1 241 train
+phqpnbmwhd 1 300 train
+phqtmwabmh 1 300 train
+phqypasmvw 1 300 train
+phreufxewl 1 292 val
+phrfelrfcp 1 300 train
+phrjjuihwu 1 300 train
+phrjkqvyhw 1 300 val
+phrjyibmbf 1 298 train
+phrnndlphn 1 300 train
+phrqkgtawp 1 300 train
+phrrzsdjfm 1 300 train
+phryghhzqo 1 300 train
+phrzaeybdb 1 300 train
+phrzyfxbfg 1 301 train
+phsausetmv 0 300 train
+phscbtdjyy 1 300 val
+phsfuuykbt 1 300 train
+phskaqqyny 1 270 train
+phsmtxibak 1 300 train
+phsqfqwdog 1 298 train
+phsqksnojy 0 300 val
+phsqrefuqp 1 298 train
+phswpocsui 1 300 train
+phtequcrpl 1 299 val
+phtitcnzoa 1 300 train
+phtmhrboex 1 300 train
+phtptpmawy 1 241 train
+phtsbryuje 1 300 train
+phtsldprho 1 300 train
+phtwqvezao 0 300 train
+phtxyrkycp 1 147 train
+phunfxbkan 1 300 train
+phunswkrpy 1 300 test
+phunxwjbbf 0 300 train
+phuyufkjen 1 300 train
+phuyuhvtjy 1 300 train
+phvciecduz 0 300 train
+phviuccbwp 1 241 train
+phvleucvzu 1 300 train
+phvmwpiqzv 1 241 train
+phvngavaai 1 301 train
+phvoabhqqv 0 300 val
+phvoigvham 0 296 train
+phvpywaday 1 300 test
+phvqorbnts 1 300 val
+phvvoldgkr 1 300 train
+phvzvwsxtx 0 300 train
+phwhurlseg 1 301 train
+phwixzebet 1 298 train
+phwtljajfk 1 300 train
+phwwwjlwpo 1 300 val
+phwyicbucn 0 300 train
+phwzmrhumf 1 300 train
+phxchcvfpd 1 300 train
+phxhmbsnsm 1 300 train
+phxocczigm 1 300 val
+phxopxyzuz 1 300 train
+phxrzdairl 1 300 train
+phxwzvjuep 0 300 train
+phybnchidx 0 300 train
+phyiqavpra 1 300 train
+phyjzokkor 1 300 train
+phymbulszu 1 300 train
+phyrlhkiwp 1 300 train
+phyzznefwk 1 301 train
+phzdxfpdmm 1 300 train
+phzhryispv 1 300 train
+phzhxynpjx 1 300 train
+phzijipsqo 1 300 train
+phzmswkbcc 1 300 train
+phzpjgqufu 0 301 train
+phzsaimkga 1 300 train
+piadjgtnha 1 300 train
+piagrfffcx 1 300 train
+pialswwqxr 1 300 train
+piamkqfaed 1 300 val
+piapktaonp 1 300 train
+piawdsmxzv 1 298 val
+piaxrkzpkc 1 301 train
+piaybeiamv 1 300 val
+piaygiiqal 1 300 train
+pibajvthiq 1 300 val
+pibboacpjn 1 300 train
+pibcprkwpq 1 300 train
+pibhlumpvp 0 299 train
+pibjohutga 1 300 val
+pibqqlkngn 1 300 val
+pibrwzsawr 1 302 val
+pibtavvzhs 1 300 train
+pibzpbrslh 0 300 train
+picgjhojlj 0 300 train
+picistuafs 1 300 train
+picjtzdojg 0 300 train
+pictfcrxkm 1 300 val
+picuvanash 1 300 train
+picxyrchki 1 300 train
+pidamdufdk 1 300 train
+piddbbdexg 1 299 train
+pidlmnakye 1 300 train
+pidozsejoq 1 300 train
+pieasiqzkt 1 301 val
+piebtlkyes 1 300 val
+piedplkayh 1 301 train
+piegbzjyju 1 300 train
+pieljwtnpg 1 300 train
+pifbgbadwa 1 300 train
+pifekxxqlf 1 300 train
+piffvfvxuj 1 301 val
+piftieqsxl 1 300 train
+pifxpqfctr 1 300 train
+pigbhuihbc 1 301 train
+pigdplyasg 1 298 train
+pighueohyq 1 300 train
+pigsuchqbh 0 242 train
+pigwgqjdfc 1 300 train
+pigzvfybcf 1 301 val
+pihawujisz 1 300 val
+pihdxqxmla 0 300 train
+pihlmykztx 1 301 train
+pihpnnyefl 1 298 train
+pihucwrqbo 1 300 train
+pihzoekcus 1 300 train
+piihbtgjgj 1 300 val
+piihqntouq 0 300 train
+piiicjgdvu 1 300 train
+piijcmcsap 1 300 train
+piiqovlsir 1 300 val
+piiqqsrvgm 1 300 train
+piivmesyhm 0 300 train
+piiytlwgqj 1 300 train
+pijdcfzyqg 1 300 val
+pijlvgtdke 0 300 val
+pijnbsnxnd 1 300 train
+pijtgijpbo 1 300 train
+pijuaxbmej 1 300 val
+pijwnchuha 1 301 val
+pijwqlcgaf 1 300 train
+pijwznrtjh 0 300 val
+pijzjjchqn 0 300 train
+pikedfarkk 1 300 train
+pikfmmiacs 1 300 train
+pikidwbjsa 1 300 train
+pikjvhpfoe 1 300 test
+pikkbzkrqu 1 300 val
+piklezyfco 1 300 train
+pilaglcgpu 0 241 train
+pilnfoupip 1 300 train
+pilrepzjrb 1 300 val
+pilwejgexa 1 300 train
+pilxjufslv 0 300 train
+pilxtozlrg 1 300 test
+pimrqnukmm 1 300 val
+pimrsfwcwm 0 300 train
+pimvynbpgh 1 297 train
+pimwkeghsp 1 301 train
+pinahgjtcg 1 300 train
+pinatsphkj 1 300 test
+pinidxcirs 1 300 val
+pinreruizk 1 300 val
+pinulkppsh 1 298 train
+pinzifylhg 1 300 val
+pioasylqng 1 300 train
+piobzdcjez 1 300 train
+pioeebnvub 1 300 val
+pioikeufiu 1 300 val
+piokxdwqns 1 300 train
+piokyzziub 1 300 val
+piorfwffxx 1 300 train
+piovymzozl 1 300 train
+piozuhejhj 0 300 train
+pipdcgjway 1 300 val
+pipiskgjmf 0 300 train
+pipneqzewa 1 300 train
+pipnznintr 1 300 train
+pipoqoslyo 0 300 val
+piqdnslkof 1 300 val
+piqmkdyiyf 1 301 train
+piqpjvqlrn 1 300 train
+piqrfppjjx 1 300 train
+pirabltzfa 1 300 val
+pirgtujxlp 1 300 val
+pirrhhukja 1 300 train
+pirvhtqwoz 1 300 val
+pisbxyfrdi 1 300 train
+pisffdrole 1 300 train
+pisjbjcdlk 0 300 train
+piskiyyoxw 1 300 train
+piskvhpjqa 1 300 train
+piskwennwc 1 300 train
+pisnwocakb 1 298 train
+pisqdmzpcc 1 300 train
+pisqnmoyhe 1 300 train
+pissdabnmv 1 300 train
+pisvctlgab 1 298 val
+pisxzqepkr 1 300 val
+pitcfqjqft 0 300 train
+pitcrnywje 1 300 train
+pitepwjoyg 1 300 train
+pitiythfbh 1 300 train
+pitkhqasub 1 299 test
+pitpjawwwp 0 300 train
+pitpmrwsov 1 300 val
+piudhrzomc 1 300 train
+piumqgzyjh 1 300 train
+piuxpkwgxi 1 300 val
+pivbabhicb 0 300 val
+pivnbjtoti 0 300 train
+pivqcuvgds 1 241 train
+pivqoeckxs 1 300 train
+pivumqlgyl 0 300 train
+pivunfuemt 1 301 train
+piwcdadvvd 1 300 train
+piwcgqxvml 0 300 train
+piwguhxzks 1 300 val
+piwiyrrlca 1 300 val
+piwqanqktm 1 300 train
+piwtkahted 0 300 val
+piwtwjenkj 1 300 val
+piwyvttekm 1 300 train
+pixioecsmi 1 301 train
+pixixsfoii 1 297 train
+pixxxbomxn 1 301 train
+piyafdzszm 1 300 train
+piyckbokjg 0 300 val
+piyizriobr 1 298 train
+piynpykxjn 1 300 train
+piystccvyq 0 300 val
+piysygnysy 1 300 train
+piyvmxffsw 1 300 train
+piyxfcytqd 0 300 train
+piyyazuttu 1 300 train
+pizdihetet 1 300 train
+piziqhlndp 1 300 val
+piztvphixe 0 300 train
+pizwfjjwcl 1 300 train
+pjachukvqz 1 300 val
+pjacytqixw 1 300 val
+pjaednkscr 1 300 train
+pjafotgxtk 1 300 val
+pjajlrojun 1 300 val
+pjakkfkglg 1 300 train
+pjakuvwipq 1 301 train
+pjaoiojtch 1 300 val
+pjapslcyuy 1 300 train
+pjasxlfgbf 1 298 train
+pjawxyvftp 1 300 train
+pjayapberb 1 300 val
+pjbdhdvkts 1 300 val
+pjbdjzyvlw 1 300 train
+pjbewiubum 0 300 train
+pjblduprdp 1 300 train
+pjbulzfqxi 1 300 val
+pjbuzenimc 1 300 train
+pjbvvmlogk 1 300 train
+pjbxzwxgxi 1 300 train
+pjcfikztgk 1 301 train
+pjcftoqnsl 1 300 train
+pjciuhedrj 0 301 train
+pjckwrxexz 1 300 train
+pjclhiaogd 1 300 train
+pjcpyuwgui 1 300 train
+pjcueaqbka 0 300 train
+pjcvnirkwi 1 300 train
+pjczoaraco 1 300 train
+pjdmyuurxq 1 300 train
+pjdomenndg 1 300 train
+pjdpbvgikm 1 300 train
+pjdrtcyzce 1 299 val
+pjebbsewyk 1 300 val
+pjeejqpmym 1 300 val
+pjenbuiakt 1 300 train
+pjeqgpuhdf 1 300 train
+pjeqqdqzys 1 300 train
+pjfcbdevcn 1 300 train
+pjfgacdpbv 1 300 train
+pjfkpiiali 1 136 train
+pjfokagfuf 1 300 train
+pjfpohvvzh 1 300 train
+pjfyovbzvf 0 300 train
+pjgbvwqsum 1 300 val
+pjgezhtmnw 1 300 train
+pjgjvodbcj 1 300 train
+pjgpjncexr 0 300 train
+pjgqyoywlq 1 299 train
+pjgzjmnaon 1 300 train
+pjhboonkte 1 300 train
+pjhcqkwple 0 300 train
+pjhlykxmja 1 298 train
+pjhownfdgh 1 300 val
+pjhviilsrv 1 301 train
+pjhwkfbmsr 1 300 train
+pjibpowymk 0 300 val
+pjidtznrkw 1 300 train
+pjidunorcs 1 300 train
+pjipeclnub 1 300 train
+pjisuefyqb 1 300 train
+pjivtmbgel 1 301 train
+pjixgzvdea 1 299 train
+pjiygkinwj 1 300 train
+pjjaarcbgd 1 300 train
+pjjfydypqo 1 301 train
+pjjgqiondh 1 301 train
+pjjmeuhjzi 1 300 train
+pjjpymrtnt 1 300 train
+pjjrkmdvxj 1 300 train
+pjjroahzsq 1 300 train
+pjkgenkrgb 1 300 test
+pjkjsbgkuc 1 298 val
+pjkjwfpsxi 1 300 train
+pjkkgptduh 1 301 train
+pjkmbiofvd 1 300 val
+pjkmenibnx 1 300 test
+pjknwnhqnm 1 300 train
+pjlgousssl 1 300 train
+pjlkqigfgz 0 300 train
+pjlmyxpban 1 300 train
+pjlpcxmgyj 1 300 train
+pjlswenrwb 1 300 train
+pjlxydouya 1 300 train
+pjmcosnfam 0 300 train
+pjmfgufzvt 1 300 train
+pjmifdwfps 1 298 train
+pjmnypqmlf 1 300 val
+pjmstnfxfv 1 300 val
+pjmvbrwlkj 1 300 train
+pjmymlofwl 1 300 train
+pjnfmypyrq 1 300 train
+pjnfuaemia 0 300 train
+pjnhomqzdk 1 300 train
+pjnhyceuca 1 300 train
+pjnixwlsef 1 300 train
+pjnkdymcbd 1 300 train
+pjnnsbryzg 1 300 train
+pjnpzwdqoy 1 300 train
+pjnsejazpl 0 300 train
+pjnsijcadl 1 300 train
+pjntiigiqs 1 300 train
+pjoamzklby 1 300 train
+pjofjddsnu 1 300 train
+pjogiqxovu 0 300 val
+pjoinmammg 0 300 val
+pjojqplosw 0 300 train
+pjolasryaq 1 300 train
+pjomywmqnq 1 300 train
+pjonlkhyqh 1 300 val
+pjonoqkcio 0 300 train
+pjopbjhyqd 1 300 train
+pjopbltdpp 1 240 val
+pjoqljbaea 1 300 train
+pjorrahqhd 1 300 train
+pjospfkyoz 0 300 train
+pjozanqjmp 1 300 train
+pjpauqpika 1 300 train
+pjpdtsqyhg 1 240 train
+pjpfdrqixm 0 300 val
+pjpklcreot 0 300 val
+pjpodphqdu 1 299 val
+pjpqvjllvp 0 99 train
+pjqidbslxn 1 300 train
+pjqjrfngiy 1 300 val
+pjqpjafoku 0 300 train
+pjqqnbiiwv 0 300 val
+pjqretretp 0 300 train
+pjqrjkzezp 1 301 train
+pjqwaiphnt 1 299 test
+pjqxxtafix 1 300 test
+pjqydnrqeu 1 300 train
+pjqzjgyryg 1 300 val
+pjrhsvdlaj 1 300 train
+pjrlegmgry 0 300 train
+pjrnyngtrv 1 300 train
+pjrsquwlci 1 300 train
+pjrtztltrq 1 301 train
+pjsbuduywx 1 300 val
+pjsczfjhla 1 300 train
+pjskgadgih 1 240 train
+pjsndmaqef 1 300 train
+pjsziyqflx 1 300 train
+pjtirnqgwr 1 300 train
+pjtnrexaev 1 300 train
+pjtpsxxcdm 1 300 train
+pjtqjepwrm 1 300 val
+pjtvcmzezs 1 300 val
+pjtwokcuhv 0 300 train
+pjtzsemdgi 1 300 train
+pjubyykmkn 1 300 train
+pjuhjveqrh 0 300 val
+pjumwtgwmg 1 300 train
+pjundktgzu 0 300 train
+pjuzhtsbdr 1 300 val
+pjvhpqfoyr 1 300 val
+pjvnnakwnj 1 300 train
+pjvvfgfbew 1 167 train
+pjwbqthctn 1 300 train
+pjwhcrtjja 0 300 train
+pjwjqoymiz 1 300 train
+pjwkkijpwu 1 300 val
+pjwlrdjgbp 1 300 val
+pjwwzqhnjo 1 300 train
+pjwyjznkgn 1 300 train
+pjxjmwwaoj 1 300 val
+pjxoceyift 1 300 train
+pjxrevuhyx 1 300 train
+pjxtgzxgfq 0 300 val
+pjxtjxqpnn 1 300 train
+pjxxnotfdr 1 300 train
+pjydajuyry 1 300 train
+pjyjnmczaw 0 300 train
+pjykuzffza 1 300 train
+pjyqoserus 1 300 train
+pjytlwuocz 1 300 train
+pjyufyptom 1 298 train
+pjyvnwusne 1 297 train
+pjzcbwmjid 1 301 train
+pjzjauxlfg 0 300 train
+pjzkajmvkt 1 300 train
+pjzniyytro 1 300 train
+pjzsuxozit 1 300 train
+pjzvcrqhul 1 302 train
+pjzvvgwkpg 1 300 train
+pjzyiquxuh 1 300 train
+pkabspuzjp 1 300 val
+pkadxrjeaz 1 300 train
+pkaltewbpq 1 300 train
+pkamqvupne 1 300 train
+pkasfvgpjo 1 300 val
+pkbcflrzqb 1 300 train
+pkbcyczahz 1 300 train
+pkbcyefbto 1 300 train
+pkbocacgxl 1 300 train
+pkbrwryekp 1 300 train
+pkccnappts 1 300 train
+pkccuejnkk 1 300 train
+pkcfjjrjjv 1 298 train
+pkcjawttko 0 300 train
+pkcjjloujc 1 300 train
+pkcptxquew 1 300 train
+pkcqelgsdp 1 300 val
+pkcwmxcizh 1 300 train
+pkdcimcewe 1 300 val
+pkdeitjeaj 1 300 train
+pkdhnsrrwz 0 300 train
+pkdmtzuqjb 1 300 val
+pkdsbddewx 1 300 val
+pkdzrfcvcd 0 300 val
+pkeagdsnjo 1 300 train
+pkedupzgbm 1 300 train
+pkeehogssf 0 297 train
+pkejmfhdki 1 300 train
+pkemjsdtxm 0 300 train
+pkfadjlrtq 1 300 train
+pkfafqupxw 1 301 train
+pkfctlxcsj 0 300 train
+pkfdrbkahq 1 300 train
+pkfhzhlndv 1 300 train
+pkfrmglwsj 1 300 train
+pkfrzyvgyi 1 300 train
+pkfucuczdu 1 300 train
+pkgcnoonla 0 300 train
+pkgdbwrasc 0 300 train
+pkgdkzoeoh 1 301 val
+pkghgvtkml 1 300 train
+pkgmiwpnal 1 300 val
+pkgrxcumnm 0 300 val
+pkhddeeeqb 1 301 val
+pkhfledcxk 1 300 train
+pkhkfxdicm 1 300 train
+pkhkwliorq 0 300 train
+pkhqgndcyn 1 300 val
+pkhrllrjhw 1 300 train
+pkhsbksmbc 1 298 train
+pkhtxtxtsp 1 300 train
+pkhvszfhph 1 300 train
+pkijcexwow 1 299 val
+pkinzjqukb 1 136 train
+pkisaekjge 1 300 train
+pkititkein 0 300 train
+pkiywogejs 1 300 val
+pkjgbfifuc 0 300 train
+pkjhgyadnk 1 300 val
+pkjiipbwkb 1 302 val
+pkjmnwfcig 0 300 val
+pkjmvgitrm 1 300 test
+pkjnyyxaih 1 294 train
+pkjrfaanye 1 300 val
+pkjrvnwpyc 1 300 val
+pkkaewbtdk 1 300 train
+pkkjajgqmt 1 300 train
+pkkmysbvfh 1 300 test
+pkkoaumvhh 1 300 train
+pkkueemque 0 300 train
+pkkulhtbxs 0 300 train
+pkkvvhnrla 1 300 val
+pklkwgaqmw 1 300 train
+pklpoweghi 1 300 train
+pklrfexmao 1 300 val
+pklzyshphk 1 298 train
+pkmdbkbtye 1 300 train
+pkmeeggcyy 1 300 test
+pkmflclnwu 0 300 val
+pkmfyrunvb 1 300 train
+pkmhrujask 1 300 val
+pkmjflgidb 1 241 train
+pkmpnekczp 1 300 train
+pkmqgnveoy 1 300 train
+pkmuvqvetl 1 300 train
+pknbvilvkl 1 298 train
+pkndlfgmzt 1 300 val
+pknfrzqyrf 1 300 train
+pknibnxjvc 1 300 val
+pknjzsljrv 1 300 train
+pknnwjkxhx 1 300 train
+pknrjuicth 1 301 train
+pkoadvlpga 0 300 train
+pkomjevmkk 1 300 val
+pkovaypwgw 0 300 val
+pkozwhgwib 1 300 train
+pkpaynzffd 1 300 train
+pkpdsjrmip 1 300 train
+pkpdwznfyd 1 300 train
+pkphkvcynj 1 300 val
+pkplwbcjbz 1 301 train
+pkprmucppq 1 300 train
+pkpscgkrls 0 300 train
+pkptlhovpd 1 300 train
+pkpxhevjjz 0 300 train
+pkpyudokau 1 300 train
+pkpzbcpocu 1 300 train
+pkqegeehyp 1 300 train
+pkqhrdvypr 1 300 train
+pkqlqbqxde 1 300 train
+pkqpwczxpp 1 300 train
+pkqrfylguv 1 298 train
+pkqrvokzaq 1 300 train
+pkrdavwgjq 1 300 train
+pkretcflwd 1 300 val
+pkrfegucgn 1 301 val
+pkrpyvfnye 0 300 train
+pkrsunndqc 0 300 train
+pkrvynnwyg 1 300 train
+pkryonprfe 1 300 train
+pksawhjoar 1 301 train
+pksewwwpyz 1 300 val
+pksjrtzppp 1 300 test
+pkslahiwbp 1 298 train
+pksmvnisjw 1 294 train
+pksrytdmkk 1 300 train
+pksxomxkoz 1 300 val
+pktcakpntv 1 298 train
+pktcwbjmab 1 300 train
+pktiwqqjrt 1 299 train
+pktyfrvywo 1 300 test
+pktzahnxie 1 300 train
+pkubgafsaa 1 300 val
+pkudbxhyss 1 300 train
+pkudojorwu 1 300 train
+pkuizvrqae 1 299 val
+pkulawhjci 0 300 train
+pkulqwqphl 1 300 train
+pkumyfdkga 0 300 val
+pkutvabuls 1 300 val
+pkuuvpmgmj 1 300 train
+pkvcqzjsim 0 300 train
+pkvijgfcsv 1 300 train
+pkvnsefldz 1 300 train
+pkvopnishr 1 300 train
+pkwaygzfwf 1 298 train
+pkwdokzcvg 0 300 train
+pkwhvcbwbt 1 300 train
+pkwiouetyr 0 300 train
+pkwnblkdbq 1 300 train
+pkwzqtbnwi 1 300 train
+pkxaznzjhl 1 300 train
+pkxgbfppae 1 241 train
+pkxivzdglf 1 300 train
+pkxnlvobty 1 300 train
+pkxnnlwpja 0 300 train
+pkxvjqmbkv 1 300 train
+pkxvjvqjyc 0 300 train
+pkxxihigvt 1 300 train
+pkyavigtyl 1 300 train
+pkykejjvgc 1 298 train
+pkylobdssc 1 298 train
+pkyxxemoat 1 302 train
+pkzaqynwoe 1 300 train
+pkzawancce 0 300 train
+pkzdpystaw 0 300 train
+pkzgfmxztj 1 300 train
+pkzijiwvtr 1 300 train
+pkzjyrozpq 1 300 train
+pkzopjllws 1 300 val
+pkzvllcxjr 1 300 val
+pkzxaxeqmr 1 300 train
+pkzzncilqm 1 301 train
+pladypzcgb 1 300 train
+plalfkegrv 1 300 train
+plamviwlvz 1 300 val
+plaxrifjkk 1 300 train
+plbeexzawi 1 300 train
+plbgcakdko 1 300 train
+plbhbjlzkk 1 300 train
+plbiekrgig 1 301 train
+plbjyspszr 1 300 train
+plblamfptn 1 300 train
+plboaosmir 1 300 train
+plboestduy 0 301 val
+plbrhjitqu 1 300 train
+plbtpvjmae 0 300 train
+plbvzzsjnw 1 300 train
+plbycndvfu 1 300 train
+plccjliaxn 1 300 val
+plcetnsilv 0 300 train
+plchjedipm 1 301 train
+plchmazoqv 1 300 train
+plcmuilvyf 1 300 train
+plcubpryia 1 300 train
+plcyabhtbn 1 301 train
+plcylurjmq 1 300 train
+plczaniyed 1 300 train
+pldagpoppb 1 300 train
+pldgpdtzwo 0 300 train
+pldiwcmrdp 0 300 train
+pldoaeueim 1 300 val
+pldttsmnan 1 300 train
+pldulzcfad 1 300 train
+pldxafyoww 1 241 train
+pldxshnrxi 1 300 train
+pldzgzznwl 1 300 train
+plecauxmnc 1 300 train
+plefxpirtu 1 300 train
+pleioyrjyj 1 302 train
+plelqmhdxi 1 300 val
+pleqihjpif 1 299 val
+plesoobicl 1 301 val
+plexynljoa 1 300 train
+plezpbktqc 1 300 train
+plfphqkpdv 1 300 train
+plfzfbnmpm 1 300 train
+plgasfhgsm 1 301 val
+plgastgqng 1 300 train
+plgeiqeqyj 1 300 train
+plgeqfsvmq 1 300 train
+plggrlvgxe 1 300 train
+plglzarjxa 1 300 train
+plgpfjbfiy 1 296 train
+plgulgffhs 1 300 val
+plgxkmiibg 1 300 val
+plhcceboag 0 300 train
+plhimyrwko 1 300 train
+plhkbirlol 0 300 train
+plhmgtjpfh 1 300 train
+plhpxrnebu 1 300 train
+plidwlxzuj 1 296 train
+pliebacntu 1 300 val
+plihptbblj 0 300 val
+plimntivef 1 300 train
+plippwihgk 0 300 train
+pliqrpjnfd 1 300 train
+plitngosri 0 300 train
+pljdzxdgdt 1 300 val
+pljfgmogdr 1 301 val
+pljhcyvmer 1 300 train
+pljjaouhdy 1 300 train
+pljnvpebkl 0 300 train
+pljqtedavt 1 300 train
+plkbyavvqp 1 300 test
+plkcksnqxc 1 300 train
+plkdahgwvq 1 301 val
+plkdwbceoh 1 300 val
+plkgpciabc 0 300 train
+plkliodisu 1 300 train
+plkuuphonq 1 300 val
+pllgovampw 1 300 train
+plljpjscih 0 301 train
+plllffcxdt 1 300 train
+pllpgldqxd 1 300 test
+pllpxvzpok 1 300 test
+pllqdqkkgg 1 300 train
+pllqrtbjdv 1 300 train
+pllwlgzbkd 0 300 train
+pllykonjem 1 298 train
+pllymqhieo 1 300 train
+pllyvkmvqb 1 299 test
+pllyywolvy 0 300 train
+pllzmsfihy 1 300 train
+plmohuyirr 1 300 val
+plmpewmelg 1 300 train
+plmqpbksiv 1 300 train
+plnczvkemn 1 300 train
+plnencmzwl 1 300 train
+plnkvnwbla 1 300 train
+plnljweahg 1 300 val
+plofuntfqo 1 240 train
+plogjhefol 1 300 train
+plojogdbua 1 300 train
+plonelnbet 1 299 train
+plonfwxohr 1 300 train
+plonseaifb 1 300 val
+plooixloch 1 301 train
+ploqanhaow 1 300 train
+ploqepnxcv 0 300 train
+plorsilvov 1 300 val
+ploxfheign 1 300 train
+ploygehorz 1 300 train
+plpcftpcyg 1 300 train
+plphlfbsib 1 146 train
+plpkbnqpcv 0 300 train
+plplvfbjca 1 300 train
+plppsbvkan 1 298 train
+plpqspvsls 1 300 train
+plprlgstvq 1 300 train
+plpsanbykp 1 300 train
+plpsrmulpk 1 300 train
+plpxrhbirc 1 300 val
+plqabfpytl 0 300 train
+plqlsipcqj 1 300 train
+plqohcxmzv 1 300 train
+plqyhhhosp 1 300 train
+plrbbgkrrf 0 300 train
+plrcmlnnqp 1 300 train
+plrkbldxyp 1 300 train
+plrtfgcwau 1 300 train
+plrwirlumk 1 300 train
+plsfwhallo 1 300 train
+plsithgicx 1 300 train
+plsjfbulnp 1 300 val
+plspoakirp 1 300 train
+plsptwuohu 1 300 train
+plspxkewlv 1 300 train
+plsqdnqkns 1 300 train
+plstcrcgcn 1 241 train
+plsttxlqoo 0 300 train
+plsumwddmu 1 300 train
+plswvbglbb 1 300 train
+plsymjphbl 1 300 train
+pltaulohnf 0 300 val
+pltevshhxu 1 300 train
+plthqrvwfi 1 301 train
+pltknshwwk 1 300 val
+pltlfhlduc 1 300 train
+pltwjwcncn 1 300 val
+pltxnccjnv 1 300 train
+pluadmqqta 0 300 train
+plukixxapg 0 300 train
+plukqioezl 1 300 train
+pluqjkqszt 1 300 train
+plusrukaam 1 300 train
+pluszdsjrz 1 300 train
+pluygursxv 1 301 train
+pluzjstlql 0 300 train
+plvaizshin 1 301 val
+plvauswlpq 1 300 val
+plvdpxbwvh 1 300 train
+plvgsxzvyo 1 296 train
+plvjwlicpt 1 300 train
+plvrykakdu 1 300 train
+plvtwtexuz 1 241 train
+plwdzhnewz 1 300 val
+plwrlsizpz 1 300 train
+plwutrvbrc 1 300 train
+plxfksaale 1 300 train
+plximzjlup 1 300 train
+plxjzlcxhl 1 297 train
+plxoblbkiv 1 300 val
+plxoyojaaz 1 300 train
+plxqkcocqk 1 300 train
+plxzimfwjj 0 298 train
+plyfuebkxu 1 300 train
+plyptzlztw 1 300 train
+plyqivfoeh 0 300 train
+plzekolipk 1 300 train
+plzgzzciwl 1 300 train
+plzmuenklb 0 300 train
+plzsbqqrwh 1 300 val
+pmamadybpb 1 300 train
+pmazhpkmnp 1 300 val
+pmbgdlkhde 1 240 train
+pmbqvlqhhl 0 300 train
+pmbrslvzzt 1 300 train
+pmbtcwpbhw 1 300 val
+pmbwahkhrb 1 300 train
+pmbzrjpvub 1 300 val
+pmcbxqjgdt 1 298 train
+pmcdskwvve 0 300 train
+pmcecvmwlg 0 300 train
+pmchatnxba 1 300 train
+pmciczkrmq 0 241 train
+pmciwmkszl 0 296 val
+pmcqagqhdc 1 300 val
+pmcscrkcpq 1 300 train
+pmcxrzpafk 1 300 val
+pmdazvzawj 0 298 val
+pmddllpeau 1 300 train
+pmdhfwrpvc 1 300 val
+pmdjwlnizi 0 300 val
+pmdqzfnvjn 1 300 train
+pmdrdiqsdt 1 300 train
+pmdzvhxrvd 1 300 val
+pmeityztpp 0 300 train
+pmemqlqwkb 1 300 train
+pmemvhyseo 1 300 train
+pmenqgyjiu 1 298 train
+pmeonrbgcx 1 300 train
+pmeruokgei 1 301 train
+pmffqjhseh 1 300 train
+pmfieukvwd 1 300 val
+pmfnksgznw 1 300 val
+pmfrzdmoye 1 300 train
+pmfsmeutmz 1 300 train
+pmfurjxdvg 1 300 train
+pmfvnctrpz 1 300 train
+pmfyiyrvzo 1 300 train
+pmgvhydmtr 0 300 train
+pmhilgxldy 0 300 val
+pmhmjyixnr 1 300 val
+pmhqncskwo 0 300 train
+pmhupiyxpw 1 300 train
+pmiantsstv 1 301 train
+pmjfwsvren 1 300 val
+pmjzpjymge 1 300 train
+pmkkxswvpy 1 300 train
+pmkmxihime 1 300 val
+pmkndqwira 0 300 train
+pmkolnffvt 0 298 train
+pmkuvmxdzj 1 300 train
+pmkwavkrqj 1 300 train
+pmkxbaeonp 1 300 train
+pmkxnqlmbj 1 300 train
+pmlivwstdj 1 300 train
+pmllsdkdoq 1 301 train
+pmlqdguaeb 1 300 val
+pmlvnwkgdy 1 300 train
+pmlymrqskn 1 299 val
+pmmehromkc 1 300 val
+pmmhsciico 1 300 test
+pmmnajdckf 1 300 train
+pmmqiwilvl 1 300 train
+pmmqrtzavl 1 298 train
+pmmuaouuwt 1 300 val
+pmmvhosvkh 1 300 train
+pmmxhotnjz 1 300 train
+pmnazdjsol 1 300 train
+pmncasrtkf 1 300 val
+pmnccnspxs 1 303 train
+pmndyilsbk 1 300 train
+pmnehcpmdg 0 300 train
+pmngqrxmfy 1 300 train
+pmnioznoyq 1 300 train
+pmnlwdgewd 1 300 train
+pmnmfwypgc 0 300 val
+pmnmnzvyno 1 300 train
+pmnmpobtnk 1 300 train
+pmnomszyjk 1 300 train
+pmnsqtpgry 1 300 val
+pmnvdzybju 1 300 train
+pmoiqwabqc 1 300 train
+pmoknfhyif 1 301 train
+pmpdirnxaj 1 301 val
+pmpfsskytk 1 301 train
+pmpiwcrjzb 1 300 val
+pmqateayyr 1 298 train
+pmqfrblroc 1 237 train
+pmqgnnywam 0 300 train
+pmqipedwwi 1 300 train
+pmqknwnimt 1 300 train
+pmqldonxtx 1 300 train
+pmqmvsklst 0 300 val
+pmqqmvfdty 1 299 val
+pmqritfdoc 1 300 train
+pmqxbfkljo 1 300 train
+pmrbdfiery 1 301 train
+pmreglzwjm 1 300 train
+pmriwtbcmn 0 300 train
+pmrtzeyewa 0 300 train
+pmrxgiizwz 1 300 train
+pmrygmlumz 1 300 train
+pmrzdxjmxw 1 300 train
+pmsajeqzpl 1 300 train
+pmsbrhfkcn 0 300 train
+pmsccgvvut 0 300 train
+pmsdftutgm 0 300 train
+pmsievlvpx 1 300 train
+pmsijdfohr 1 300 val
+pmsjopmocd 1 300 train
+pmsmntwnlj 1 300 train
+pmsokrxggj 1 300 val
+pmsoxgfmhy 1 302 val
+pmsuwugjuo 1 300 val
+pmtcahciol 1 301 train
+pmtcmzolir 1 300 train
+pmtcverdaf 1 295 train
+pmtfvfuhkh 0 300 train
+pmtgzafbsg 1 300 train
+pmttzfseaj 1 300 train
+pmubsjfhdo 1 300 train
+pmubtgzzoq 1 300 val
+pmufanqvph 0 300 train
+pmufuqkcvd 1 300 train
+pmulgdcejl 1 301 train
+pmuntzlxku 1 300 val
+pmuoweeack 1 300 train
+pmuqfywvhy 1 300 val
+pmuuqbvylu 1 300 train
+pmuwrgyitd 1 300 train
+pmuxdiwcjy 1 298 val
+pmuxvytfai 0 300 train
+pmvdfssqbq 1 300 train
+pmvhosomdy 1 300 train
+pmvizltcdl 0 300 train
+pmvliwxozn 0 300 train
+pmvoksbnoi 1 300 train
+pmvrmuhuha 1 300 train
+pmvtmnlnnr 1 300 train
+pmvvidunuk 0 300 val
+pmwdgdtnib 0 300 train
+pmwhyvxcvr 1 300 train
+pmwluouped 1 300 train
+pmwmuvzomj 1 300 train
+pmworyrbze 1 300 train
+pmwpzpjtjs 1 300 train
+pmwslwdetx 1 300 train
+pmwuehqlmk 1 300 train
+pmwuinaikg 1 300 train
+pmwvdylmeg 1 167 train
+pmwvepegll 1 300 train
+pmwvyalpwt 0 300 train
+pmxfyxcyvk 0 300 val
+pmxiakpljo 1 301 train
+pmxiikatcx 1 300 val
+pmxoptrowy 1 300 train
+pmxteuotjg 1 300 val
+pmxudsxyus 1 300 train
+pmxyfiyjim 1 300 val
+pmyalswaqw 1 300 val
+pmydsnjqvg 1 300 train
+pmyeivvckd 1 300 train
+pmyirgdgra 1 300 train
+pmyjgyyqls 1 300 val
+pmylrgnsns 0 300 train
+pmymyqewcy 1 300 train
+pmyunkwxsy 1 300 train
+pmyvezobbm 1 300 train
+pmywbdljmw 1 300 train
+pmyzwyncor 1 300 train
+pmzatdudmu 1 300 train
+pmzfmajnzh 1 299 test
+pmzpdrjsmq 0 300 val
+pmzqmzivpy 1 300 train
+pmzujwmgtz 1 298 train
+pmzupdqfpq 1 300 train
+pmzxykeigt 1 300 train
+pnabjscunm 1 300 train
+pnahiwqhrj 1 300 train
+pnalawyffq 1 300 train
+pnanauydrw 1 300 train
+pnashuxnit 0 299 train
+pnasrgcdli 1 300 train
+pnauelqbxq 0 239 train
+pnbdbcevqs 1 300 val
+pnbjrnmkwk 1 298 train
+pnbmspkblt 1 300 train
+pnbuvfphhc 1 300 train
+pnbznglcbk 1 300 train
+pncgcxqehb 1 300 train
+pncnsmgeut 1 301 train
+pncnugplau 1 300 train
+pncqrfxnmy 1 300 val
+pnctmlfama 1 300 train
+pncwmrogfz 1 300 train
+pndcdfogji 1 300 train
+pndfpqjbfg 0 301 train
+pndoiimrsu 1 301 val
+pndozpftoa 0 300 train
+pndwdmavyj 1 300 train
+pnecvmcwiw 0 300 train
+pnefwmfkuo 1 300 val
+pnejkjolgb 1 300 train
+pnemcedplw 1 300 train
+pnemgbwnlj 1 298 train
+pnemimivxo 1 300 train
+pneqgfkgyw 1 301 train
+pnewsrdzpn 1 300 train
+pnfcjcwvqt 1 300 train
+pnfekwenbd 1 300 val
+pnfizwuebk 1 300 train
+pnfntyddbk 1 300 train
+pnfrqctmed 0 300 train
+pnfutbmbyu 1 300 val
+pnfvuxvjby 1 300 train
+pnfxlyahfl 1 298 val
+pnghtmxjhy 1 300 train
+pngjcdtqnc 1 300 train
+pngnzctffz 1 296 val
+pngxwrscfv 0 300 train
+pnhgfderbb 1 300 train
+pnhpggfiyg 0 300 train
+pnhpsksyke 1 300 train
+pnhxtiqyef 1 300 train
+pniityffuj 1 300 train
+pniolmigcg 1 300 train
+pniyoniycd 1 300 train
+pnjbszaplh 1 300 train
+pnjlgkdusv 1 300 train
+pnjpqgcqho 1 300 val
+pnjsfoqaxk 1 300 train
+pnjzfeokjv 1 300 test
+pnjzvelthy 0 300 train
+pnkjrsohjk 1 300 train
+pnkngxzuxc 1 300 val
+pnksxmyogv 1 300 train
+pnkxmdurwy 1 300 train
+pnkzqfgdaw 0 300 val
+pnlbnshuvt 1 300 train
+pnlcofiyaj 1 241 train
+pnljeroaga 1 300 train
+pnlposaqjg 0 300 train
+pnlqazskcv 1 300 train
+pnmekhguzp 1 300 val
+pnmnzzxbjq 1 300 train
+pnmtglcwwh 1 300 train
+pnnepdbobv 1 300 train
+pnnhpyfkym 1 300 train
+pnnjdevrun 1 300 train
+pnnqrbnihf 0 300 train
+pnnvhrfrnp 1 301 train
+pnohkehlfn 1 300 train
+pnoigkjkic 1 300 val
+pnolpthtsj 0 300 train
+pnoogzbpjb 1 300 val
+pnooyxdnwq 1 300 train
+pnotaniiuh 0 300 train
+pnotngvwsc 1 300 train
+pnpalkrznu 0 300 train
+pnpctgjcwp 1 300 train
+pnpgiugmxr 1 241 train
+pnpkbjiiwr 1 298 train
+pnpnfwimcz 1 300 train
+pnppsiohoy 1 300 train
+pnpqdndtpm 1 300 train
+pnpssuckje 1 300 train
+pnptubzyld 1 300 train
+pnpudnxlff 0 300 train
+pnpyiohvrh 1 300 train
+pnpylbwrxe 1 300 train
+pnpzfrvuse 1 300 train
+pnqfaupcyt 1 300 train
+pnqfzizfys 1 300 train
+pnqhrbusul 1 300 train
+pnqrgzrhmo 1 300 train
+pnqrmirozd 0 300 train
+pnqtvpcgqb 1 300 train
+pnrjwvxosn 1 300 train
+pnrkefngcs 1 300 train
+pnrqtxkvvr 0 298 train
+pnrrvbecod 1 300 val
+pnrtppildr 1 300 train
+pnruniguok 1 300 train
+pnrvsyhomx 0 300 train
+pnrvyszoku 1 300 train
+pnsacbrtmr 1 288 train
+pnsdkpufyb 1 300 train
+pnsfianxst 1 300 train
+pnsnyojsph 1 300 train
+pnswzpejom 1 300 val
+pntbngsuke 1 300 train
+pntckmogke 1 301 train
+pnthjxopty 0 300 train
+pntkddkhoc 0 300 train
+pntlhxkvmk 0 300 train
+pntmfxrtbf 0 300 train
+pntqucycxy 0 300 train
+pntvmiyque 1 301 val
+pntydwvbbs 1 300 val
+pntyqjbvcq 1 300 train
+pnuaczdxdj 1 300 train
+pnuazbrjkw 1 300 train
+pnudwkzqua 1 298 val
+pnuieeypbl 1 300 train
+pnumreufox 1 300 train
+pnuniulniz 1 300 val
+pnunughkny 1 300 train
+pnuqitwfxf 1 300 train
+pnutdupakr 1 300 train
+pnuvljnprr 0 300 train
+pnuxhefjyj 1 240 val
+pnuzyfgaif 1 300 train
+pnvapfikra 1 300 train
+pnvdvbnkfi 0 300 train
+pnvfuwimil 1 300 train
+pnvkzhgusd 0 300 train
+pnvllbncra 1 300 train
+pnvrrhnsfb 1 300 train
+pnvsuyusxr 1 300 train
+pnvwghaiir 0 300 train
+pnwbmckzuh 0 300 train
+pnwcqjdtld 0 300 train
+pnwfabzbfk 1 300 train
+pnwgnlebvo 1 300 train
+pnwgvpsdxd 1 300 train
+pnwizhkofn 0 300 val
+pnwjdpjlup 0 300 train
+pnwjnbzudk 1 300 train
+pnwuuhkfxk 1 300 train
+pnwwpmehic 1 300 train
+pnwxopafue 1 300 val
+pnxevbwavg 1 300 train
+pnxlkrnakj 1 300 train
+pnxmphjyyo 0 300 train
+pnxooovlrp 1 300 train
+pnxqdaukqn 1 301 val
+pnxtyycxbm 1 136 train
+pnxxebiplr 1 300 train
+pnxxfbbfqc 1 300 val
+pnyaurxcrx 1 300 train
+pnyifxtzny 0 300 train
+pnyjnjiiqx 1 300 train
+pnypoxjkpv 1 300 train
+pnysliqlnp 1 300 train
+pnysqmwieh 1 300 train
+pnysxmpnkx 1 300 train
+pnyuokwckh 1 300 train
+pnyvaspzbc 1 300 train
+pnyvxscgpl 0 301 val
+pnzaqayhrw 0 300 train
+pnzhnavmdd 1 300 train
+pnzimvaffq 1 294 train
+pnzjahgfcj 0 300 val
+pnzqwfjyau 1 300 train
+poaehtdkhm 1 300 train
+poagygqekh 1 300 train
+poagyhywlx 1 241 train
+poahumqnsp 1 300 train
+poahxxbghk 1 300 train
+poangahcby 0 300 val
+poaotoqpgk 1 300 val
+poatjqruio 1 297 train
+poavejyrmk 1 300 train
+poawijamqy 1 300 train
+poaytcvjuw 1 300 train
+pobkivostz 1 300 train
+pobpsxjbzg 0 300 train
+pobrnbspcf 1 300 train
+pobrnxaezk 0 300 val
+pobtjgnbxd 1 300 train
+pobtqwjlte 1 240 train
+pobxpwxqex 1 301 train
+pobymmwcwy 1 300 train
+pocbvjxbil 1 300 train
+pocgglfufn 1 300 train
+pocgqyccuv 1 300 train
+pocindeeib 1 301 val
+pocjaqpnzv 1 300 val
+pocnzpnzqr 1 300 train
+pocsjydjyz 0 300 train
+poctmcxnhq 1 300 train
+pocxqccwbv 1 300 train
+pocxyupjyf 1 300 train
+pocznsxxuy 0 300 train
+podhdvixwu 1 297 train
+podtsmhble 1 241 train
+podvtqnukf 1 300 train
+poebmykhvt 0 300 train
+poehfckhcf 0 300 val
+poekonfhku 1 298 train
+poembpwcku 1 300 train
+poeopbtivq 1 300 test
+poerlmxmbk 1 300 train
+poesbvjtzk 0 300 train
+poeuxfppbs 1 301 train
+poexqllusv 1 300 train
+pofatjklly 1 299 train
+pofgopwkjj 0 300 train
+pofoifjafs 1 300 train
+pofpcjvpse 1 300 train
+pofqblkokd 1 300 train
+pofseaaenh 1 300 train
+pofuklunkl 0 300 val
+pofyqoeaaw 1 300 train
+pogcmzrlhe 1 299 val
+poggnpxcjk 0 300 train
+poghsiouyo 1 300 val
+pogmtuxoxc 1 300 train
+pogmzfjyxy 1 301 train
+pogoqxuxxo 1 300 train
+pogqgrvodn 0 300 train
+pogrwbxyhi 1 300 val
+pogscnxllh 1 300 train
+pogxidwkoc 1 300 train
+pogzpnwkbl 1 300 train
+pogzzbceta 1 298 train
+pohbefxytm 1 300 train
+pohhjdfiod 1 298 train
+pohltxwtau 1 241 train
+pohnfudvyb 0 300 train
+pohsarnnke 1 301 val
+poicriureq 1 300 train
+poidakmnym 1 301 val
+poidzldbuj 0 300 train
+poihukvspz 1 298 train
+poiiriaxoe 1 300 train
+poityevofb 1 300 train
+poiywgblss 1 167 train
+pojmyoedft 1 299 train
+pojncdgzes 0 300 train
+pojvwuawan 1 300 train
+pojvzwdlwd 1 300 test
+pokaexnnen 1 300 train
+pokctfragw 0 300 train
+pokfbdequm 1 300 val
+pokpzfvuli 0 300 train
+pokrarzquk 1 300 train
+pokscsbens 1 299 test
+pokwkvrlpx 0 300 train
+polcyiapuw 1 300 val
+polebsimsb 1 292 val
+polehxttnl 1 300 train
+polfqtcksh 1 300 train
+poljvsypou 1 300 train
+polmciaate 1 300 train
+polmmrrxhn 1 301 train
+polpmdcrab 1 300 train
+polqketbsq 0 300 val
+pomhnqtnzd 1 300 train
+pomoerfbhi 1 300 train
+pomoyqqqql 1 300 train
+pomtnbjmsu 1 300 train
+ponawscikf 1 300 val
+poneifueiv 1 600 train
+ponigwbxyc 1 300 val
+ponnrdirve 0 300 val
+ponquljatl 1 300 val
+ponsfiacfu 1 300 train
+ponvsykciz 0 300 train
+ponydssdcb 0 300 train
+pooedbhjvo 1 300 train
+pooenivrnj 1 300 train
+poomzdaplh 1 300 train
+pooqotncon 1 300 val
+pootxlrbkt 1 301 train
+pooydnvuvl 1 241 train
+pooyjoentg 1 300 test
+popaqgktnf 1 300 train
+popilngtmi 1 300 train
+popjjlpwap 1 300 train
+popkqrcarn 1 300 train
+popofupbwe 1 300 train
+poqdlbpgdk 1 300 train
+poqfmwsmeb 1 300 train
+poqnjwqfbz 1 300 val
+poqucwaqrx 1 300 train
+poqxechmdd 1 300 train
+pormwxcwgc 1 300 train
+pornicpzrs 0 300 train
+pornxsxtvi 1 301 train
+porpclfhsm 1 300 train
+porqucsjpf 1 83 train
+porwfrwdno 1 300 train
+porwtimrmt 1 299 train
+porzntkhvq 1 300 train
+posdcejefv 1 300 train
+poselxvtgd 1 300 train
+posljzgpog 1 300 val
+poslobamtx 1 300 train
+posmjvxmqj 1 300 train
+pospbelqnh 0 300 train
+posttieqlq 1 300 train
+posvkklyyl 1 300 train
+potiaqgtly 0 300 train
+potisvxxtl 1 300 train
+potkccweye 0 300 train
+potovwyppe 1 300 train
+potpqmbksm 1 300 train
+potrwteswi 1 300 train
+pottltryso 1 300 val
+potvkhpngv 1 300 train
+potwhcjoor 1 300 test
+potzjvaikd 1 295 train
+poucximcgb 1 300 train
+pouiedctwg 0 300 train
+pouihjtatj 1 300 val
+pouwoqmsxi 1 300 train
+povcjadezk 1 300 train
+povmjnfiah 1 300 val
+povofxfmyg 1 300 train
+povqiodava 0 300 train
+povuakzrhk 1 300 val
+povxjetlon 0 300 val
+povyhigfoq 1 300 train
+poweaodebb 1 300 val
+powefqurtr 1 300 train
+powehvvxpm 1 300 val
+poweiwpymm 1 300 train
+powglfahdo 1 300 train
+powgoqjeip 1 300 train
+powjcbrxhy 1 300 train
+powjmmpbun 1 300 train
+pownbedzsu 1 300 train
+powrtawkpq 1 300 train
+powtgmqzjf 1 300 train
+poxckzplzk 1 296 val
+poxcwungti 1 300 train
+poxeniomzj 1 300 train
+poxhzrfhha 1 300 test
+poxvearhtv 1 300 val
+poyajjsybi 1 300 train
+poyayvgoly 1 300 val
+poyfrdwelj 1 300 val
+poyiixlbpd 1 300 train
+poylontakg 1 300 train
+poymvdmdpq 1 300 train
+poyobepyfa 1 300 val
+poyotaksrd 1 300 train
+poyrorjblc 1 300 train
+poyrrtkpaw 1 296 train
+poysgfmpbv 0 300 train
+poysxwelws 1 301 val
+pozbjdjuvr 1 301 val
+poznnvoute 1 300 train
+pozsogvxfx 1 300 val
+pozstarzxs 1 300 train
+pozusfswcm 1 297 train
+pozwpvqqlf 1 300 train
+pozzldjteq 1 300 val
+ppaapfxzrh 1 300 train
+ppacguqcus 1 300 train
+ppafdisvfs 0 301 train
+ppahluazwa 1 300 val
+ppajginrgg 1 99 train
+ppapefxjki 1 300 train
+ppauzwuecv 0 300 train
+ppazvbxfkq 1 300 train
+ppbavicywa 1 300 train
+ppbfducoef 1 300 train
+ppbnnrjjbj 1 300 train
+ppbognztbj 1 300 train
+ppbuvsygxv 1 300 train
+ppbzceyipm 1 300 train
+ppcbfnvbhq 1 300 train
+ppcirpmocc 1 300 train
+ppcmjfzkfs 1 300 val
+ppcnutulcq 1 300 train
+ppcwfitldw 1 300 train
+ppczxbcxrl 0 300 train
+ppdhogqjyx 1 298 train
+ppdkrhmmyw 1 300 train
+ppdmldrwmq 0 300 train
+ppdoujcqie 1 241 train
+ppdpgwyjgm 0 300 train
+ppdtcsoptx 1 300 train
+ppdydududs 1 300 train
+ppdyfatazf 1 301 val
+ppecrtgorb 1 296 val
+ppegxwyrxb 1 300 val
+ppevfwbihj 1 300 train
+ppfaexaiyv 1 300 train
+ppffwddamo 1 298 train
+ppfgtnxulq 1 300 train
+ppfkrkdfsq 1 300 train
+ppflfxmjhj 1 300 train
+ppflyporak 1 300 val
+ppfqgppkqa 1 300 train
+ppfuxngnjh 1 300 test
+ppfwisfqiz 1 300 train
+ppgeheejij 1 300 val
+ppghcvwxhb 0 300 train
+ppgkelcxld 0 300 val
+ppgpesmnom 0 300 train
+ppgwazusyl 0 300 train
+pphnvzemyi 1 300 train
+pphswoggxd 1 300 train
+pphtxhdwjf 1 300 train
+pphwgkzdts 1 301 train
+pphyzwkllk 1 300 val
+ppieurzlrm 1 301 val
+ppinqrlfmm 0 300 train
+ppiofyqwwu 1 300 train
+ppiumatmbs 1 300 train
+ppivhoaxjn 1 300 train
+ppiwodoncp 1 300 train
+ppixfzoqxv 1 300 train
+ppixsivjfy 1 300 train
+ppjaaacxea 0 300 train
+ppjbamhhnx 1 300 train
+ppjgltdrpw 1 300 train
+ppjpgfoghj 1 300 train
+ppjqxhscgh 0 300 val
+ppjwswwuwn 1 298 train
+ppjymfqupj 1 300 train
+ppkgdfxzcl 1 300 train
+ppkifjyqjm 1 300 val
+ppkkijrzsn 1 300 train
+ppknavmshm 1 300 train
+ppkzbgzogq 1 300 val
+ppkzpkiart 1 300 val
+pplbptybkm 1 300 train
+ppleefsnqh 1 298 train
+pplguxlthg 1 300 train
+pplkiknxfp 1 300 train
+pplkqtzuly 1 298 train
+ppllnfeqlx 1 300 train
+pplmlyesyn 1 300 train
+pplpvzasyz 1 300 train
+pplrbkfnne 0 300 val
+ppmamjdpzw 0 300 train
+ppmbtcphop 1 300 train
+ppmkczdlxf 1 300 val
+ppmnjncbky 0 300 train
+ppmvkeqmuj 1 300 train
+ppmvktsmkc 1 300 test
+ppmvlauyfm 1 300 train
+ppmvtqigqf 0 300 train
+ppmwhgzcwl 1 300 val
+ppmxmsjbbx 0 301 train
+ppmyxrpxcf 1 300 train
+ppncwxbpeu 1 300 train
+ppnfwtwqdn 1 300 train
+ppnlasqbib 1 300 train
+ppnoyrgicy 1 300 train
+ppnsdlgnmd 1 301 val
+ppnsretpkp 1 300 train
+ppnsxpquur 1 300 train
+ppntiydhgy 1 301 val
+ppnuihlwkx 1 300 train
+ppnwmscqma 1 300 val
+pporbhucqx 0 300 train
+ppoteqgiso 1 300 val
+ppowjsufcw 0 300 train
+pppakyhsqd 0 300 train
+pppdeikeib 1 300 val
+pppeebxoxb 1 301 train
+pppnauerjb 1 300 train
+pppxsojqis 1 300 train
+pppywrdngk 1 300 test
+pppzygkcrq 1 300 train
+ppqjjvrkbs 1 300 train
+ppqnqmccck 0 300 train
+ppqrtnnoms 0 300 train
+ppqtrzmrtg 1 300 train
+ppqwdurihd 1 299 val
+ppqzcshlwi 1 300 train
+pprgcdyzbr 1 300 train
+pprglkapba 1 301 train
+pprjttaplj 1 300 train
+pprlfufyvt 1 300 train
+ppruxbqpmc 0 300 train
+ppsbepncbu 1 300 train
+ppsbikyorb 1 300 train
+ppsetmbjoc 1 300 val
+ppsfdtngje 1 300 train
+ppsifhjquc 1 300 train
+ppskdarbou 1 300 train
+ppssbxijvn 1 301 train
+ppssnupzyz 1 300 train
+ppsuoqqjmh 1 301 train
+ppsuqxxdez 1 300 train
+ppsvxlgzgt 1 300 train
+ppswzoloye 0 300 train
+ppsyprbsby 0 300 train
+pptaxuasze 1 300 train
+pptcuafaqt 1 298 train
+pptiqmhvxe 0 300 val
+pptlgfiuqu 1 301 train
+pptoptpfoa 0 300 train
+pptowvulkd 1 300 train
+ppubnhsdoq 1 300 train
+ppulbuhtsc 0 300 train
+ppumysdmtg 1 300 train
+ppuwieuquq 1 300 train
+ppuxxylkqp 1 300 train
+ppvegigiuf 1 300 val
+ppvfunraqw 1 300 train
+ppvmbkdyar 1 300 train
+ppvpwxicte 1 300 train
+ppvqtfbccs 0 301 val
+ppvumvqmac 0 300 train
+ppwbivexjb 1 300 val
+ppwfmtgugh 0 301 val
+ppwojeoqgo 1 302 val
+ppwpmbboyj 1 300 train
+ppwqgomjeo 1 300 val
+ppwuntpllz 1 300 train
+ppwypsxgef 0 300 train
+ppxakibmeq 1 300 train
+ppxchonmif 1 300 train
+ppxecmjiiv 1 300 train
+ppxeiiuyzd 1 300 train
+ppxqgoqcnd 1 300 train
+ppxxxsnrle 0 300 train
+ppxzlzozlo 1 300 train
+ppyflmssst 1 298 train
+ppyjaapxsl 1 300 train
+ppyoehenmg 1 300 train
+ppyoleobwp 1 300 train
+ppyolutkqo 1 300 train
+ppytockqbg 1 300 train
+ppytumgusj 1 300 train
+ppzejehyib 1 300 train
+ppzhamyqkh 1 300 train
+ppzmoazoca 1 255 train
+ppznhbvkmg 1 300 val
+ppznjjsfrs 1 300 train
+ppzvprvyub 1 300 train
+pqaayzxsrk 1 300 train
+pqakbzgbgx 1 300 train
+pqavaksffx 1 300 test
+pqbbtnllkn 1 300 train
+pqbcjrahfr 1 301 train
+pqbesiqwyd 0 300 train
+pqbiasbmew 1 300 train
+pqbjwjdyju 1 300 train
+pqblmpxdhq 1 300 val
+pqbyjmgmrk 1 300 train
+pqcbwsbunr 1 300 train
+pqcethhayu 1 300 val
+pqcjagansh 0 301 train
+pqcmvupjkq 0 300 train
+pqcqmcmmdn 1 300 train
+pqcuzuvuac 0 300 train
+pqcxyoffjh 0 300 train
+pqdblfdjdx 1 300 train
+pqddxqunwp 0 300 train
+pqdeutauqc 0 300 test
+pqdhurprzr 1 300 train
+pqdixqyrnn 1 300 train
+pqdmxfnqup 1 300 train
+pqdpkvyzkd 1 300 train
+pqdpvsllpu 1 300 train
+pqdqwikgas 1 298 train
+pqdvbqdewe 1 298 train
+pqdxvcmzxy 1 300 train
+pqdxxmjijv 1 300 train
+pqebmzfvhx 1 300 train
+pqeggwylbx 0 298 train
+pqeorssiaa 1 300 train
+pqespeizrz 1 301 train
+pqetdjqyji 1 300 train
+pqeuxuzyli 1 300 train
+pqexbhcasg 1 300 val
+pqfazgwlgz 1 300 train
+pqfbzjonux 1 300 train
+pqfnubcquz 1 300 val
+pqfpzhxtld 0 300 train
+pqfqgmjnpt 1 300 train
+pqfqigfoku 1 300 train
+pqfthhnbpi 1 300 train
+pqfuagoxjp 1 300 val
+pqfudknvne 1 300 train
+pqfvznyeip 1 297 train
+pqfxpdvxbz 1 300 train
+pqgrojmnfc 1 300 val
+pqgwhfmkwf 1 300 train
+pqgyjosogl 1 300 train
+pqhaqiumgu 1 302 train
+pqhdvfvbxu 1 298 train
+pqhmroolul 0 300 train
+pqhoroszar 1 300 train
+pqhoujdeco 0 300 train
+pqhsksvphq 1 300 val
+pqhuqykrhb 1 300 train
+pqiehoxkhk 1 300 val
+pqijsrwump 0 300 val
+pqijxhlbyw 1 300 test
+pqikxlmztl 1 300 train
+pqinvkaudr 1 300 train
+pqisdncyld 1 300 train
+pqizuxdmvl 1 298 train
+pqjbxncmbx 1 301 train
+pqjgyjlesf 0 301 train
+pqjjvrkkrv 0 300 train
+pqjlbhkhzr 1 300 test
+pqjmokcmcp 1 301 train
+pqjohdhtga 1 300 train
+pqjuzmfsbf 1 300 val
+pqjyewlzon 0 300 train
+pqkacknadd 1 300 train
+pqkeknmxfi 0 300 train
+pqkigveluq 0 300 train
+pqkiuplrih 1 300 val
+pqkiyjuqio 0 300 train
+pqkjbumyvo 1 300 train
+pqknmymlpp 1 302 train
+pqkpmaimgv 1 300 train
+pqkqejctyo 1 241 train
+pqkwqylnnf 1 300 train
+pqlauglmgs 1 300 train
+pqlbaxkabs 1 300 train
+pqlddnmcos 0 301 train
+pqlirihvaz 1 299 test
+pqlmnmfcxl 1 236 train
+pqlmqnkaon 1 300 val
+pqloxalgwn 1 300 train
+pqlrefmwjy 1 300 train
+pqlrhqqvqr 1 241 train
+pqlvucqofr 1 300 train
+pqlvvcczji 1 241 train
+pqlxblnyut 1 300 train
+pqlxybtkbo 1 300 train
+pqmbpqdayi 1 300 train
+pqmgonafxz 1 300 train
+pqmoclnmka 0 300 train
+pqmolaziou 0 300 train
+pqmrrobvmc 0 300 train
+pqmsnutwew 1 241 train
+pqmxoshepp 1 300 train
+pqmzswopvf 1 300 train
+pqndbpdthi 1 300 train
+pqndnfyxvd 1 300 train
+pqnodbtfcw 1 300 train
+pqnozlhbvx 1 300 train
+pqonpngniv 1 300 train
+pqosythwla 1 300 train
+pqozaytpmi 1 298 train
+pqpgmvkxmd 1 300 val
+pqptjbjykf 1 300 val
+pqpudpjjmp 1 301 train
+pqpvlzwhax 1 300 train
+pqpzedggfh 1 288 train
+pqqcsvxqxx 1 300 train
+pqqfqrxbmc 1 301 val
+pqqhlranyg 1 300 val
+pqqsmsnriq 1 300 train
+pqqxpmmzxg 0 300 train
+pqrbxifkas 1 300 train
+pqrclrgllx 1 300 val
+pqrggejzlk 1 300 train
+pqrgnusrwc 0 302 train
+pqrguzazzc 1 301 train
+pqridhzkxb 1 300 val
+pqrjmnwnws 1 300 train
+pqrqnzwzcv 1 300 train
+pqrsikapjs 1 301 val
+pqrsizpxss 1 300 train
+pqsagmqjeh 0 300 train
+pqsbrkingj 0 301 train
+pqsgodjjzn 1 300 val
+pqsjhsesvs 1 300 val
+pqsmwjofnv 1 300 train
+pqsvadvbnh 1 300 train
+pqsxnaplgi 1 300 train
+pqtcazpwkz 1 300 train
+pqtdnrrwxw 1 239 train
+pqthmvwonf 1 299 test
+pqtpoxqfhs 1 301 val
+pqtqiibaup 1 300 train
+pqtwfknjcr 1 300 train
+pqubtxsdgi 1 300 train
+pquucrhgyo 0 300 val
+pquzrfikma 1 241 train
+pqvbpjvtzc 1 300 train
+pqvebtwlfy 0 298 train
+pqvpyhwqeb 1 300 train
+pqvygeowrw 0 300 train
+pqvygunruz 1 301 val
+pqvypayzrp 0 300 train
+pqvzyeptpf 0 300 train
+pqwcldcjrg 1 300 train
+pqwclycfyv 0 288 train
+pqwdiyugub 1 300 train
+pqwlkshmwv 1 301 val
+pqwowxintv 1 300 train
+pqwphkegdg 1 300 val
+pqxedsvbqs 0 302 train
+pqxfkckukq 1 300 train
+pqxgdvyywb 1 300 train
+pqxllcnefi 1 300 train
+pqxoffhwri 1 300 train
+pqxxlxcbah 1 299 test
+pqyfnbxiiv 1 300 train
+pqykwfnywv 1 300 train
+pqysrybspl 1 301 val
+pqywogwvke 1 301 train
+pqyxpfzmtq 1 301 val
+pqzchuizou 1 300 val
+pqzirfrvnr 1 300 train
+pqzkiaideh 1 241 train
+pqzltkbggi 1 299 test
+pqzrtjstho 1 300 train
+pqzwczcugr 1 300 train
+pqzygnzjal 1 300 train
+prabglktpg 1 299 train
+praejvzobk 1 300 train
+prakjmmuyl 1 300 val
+prauyhlmgw 1 300 train
+praxxqfbca 1 300 train
+prbizkjaze 0 300 val
+prbopxwpbg 1 300 train
+prbqnhgizg 0 300 val
+prbudnoamd 1 300 train
+prceiatpzp 1 300 train
+prcfknncwz 1 300 train
+prckbqjuss 0 301 train
+prcndkhjfm 1 300 test
+prcobqjqfa 1 299 test
+prcokfpzev 0 300 val
+prcoyakamp 1 300 val
+prdircfvcn 0 300 train
+prdpqvvxmo 1 300 train
+prdrkaxeob 0 300 val
+prdrojamhn 0 300 train
+prduffcddg 0 300 val
+prebzxsfyg 1 300 train
+precbwldip 1 298 train
+premxoyino 0 300 train
+prfazktmtj 1 298 train
+prfazywuin 1 300 train
+prfgrrfhvn 1 300 train
+prfhnhcjit 1 300 train
+prfkopjxlo 0 300 val
+prfocjkspe 0 300 train
+prfqrpkmiz 1 300 train
+prfrehxxwo 1 300 train
+prftrufdtk 1 300 train
+prfunrywhi 1 300 val
+prgabxklps 1 300 train
+prgbodzhlt 1 300 train
+prgdhntsla 1 300 test
+prglmoibam 1 300 train
+prgsjxouys 1 300 train
+prgutjbuuh 1 300 train
+prhdmizihl 1 300 train
+prhfaiflgm 1 300 train
+prhivwkcsx 1 241 train
+prhkqzyzpo 0 300 train
+prhmixykhr 1 300 test
+prhprpdfta 1 301 train
+prhtkxwvmv 1 300 train
+prhtsikveb 1 300 val
+prhzrybbyv 1 300 train
+priafybxqd 1 300 val
+pricuaggzj 1 301 train
+prifeisowc 1 300 train
+prjdyabqeb 1 241 train
+prjefzbysc 0 300 train
+prjgmbrrul 1 300 train
+prjhcdeenj 1 292 val
+prjlrcdzgn 1 300 train
+prjrcfilhx 1 300 train
+prjxmomsvx 1 300 train
+prkdqkqaey 1 300 val
+prkeiiurgk 1 300 val
+prkgshbsxm 1 300 val
+prkiqmcwhy 0 301 train
+prkkrkplmz 1 241 train
+prkkxjtjau 0 301 train
+prkmzzyazj 1 300 val
+prknsveask 1 241 train
+prkpmhkzsk 0 300 val
+prkycvmwqx 1 300 train
+prlcitdohn 1 300 train
+prlyhzyvin 1 300 train
+prmkszkwma 1 301 val
+prmlfaijin 1 300 train
+prmnjagfou 1 300 train
+prmsipiaar 1 300 train
+prmtxejqai 1 300 train
+prmwoaeeng 0 300 test
+prnfptjcqm 1 300 test
+prninybudx 1 300 train
+prnkefehur 1 300 train
+prnknlacco 1 241 train
+prnylfnbuc 0 300 val
+prnzloklyt 1 300 val
+procvpiwtw 1 300 train
+proelltjgn 1 301 train
+profecleig 1 300 val
+prohubvwro 1 300 train
+proiippuup 0 300 train
+prokybxxyb 1 300 train
+prolhpsbmn 1 302 train
+prpbdxldml 1 301 val
+prphfuefsv 1 300 train
+prpnjyvijk 1 300 train
+prppukxmax 1 300 train
+prpwmciuun 1 300 train
+prqcekdmwm 1 300 train
+prqdplvhyb 1 298 train
+prqennmmxg 1 301 train
+prqiuxpdkf 1 300 train
+prqmuxhuxz 1 300 val
+prqqhpfxtu 1 300 val
+prqsrrntqj 1 300 train
+prqwoaxndv 1 300 train
+prrcrjeoon 1 300 val
+prrmqbiqrq 1 167 train
+prrocjvhir 1 300 train
+prropvmcke 0 301 train
+prrtodxlpf 1 300 train
+prruktoyam 1 300 val
+prrunyloar 1 300 train
+prrzkbaicq 1 300 test
+prsbugjqmo 0 300 train
+prsfdcbtic 0 300 train
+prspbvivnc 0 300 train
+prsrxsaovf 1 300 train
+prstbgokea 1 300 train
+prsuzakumu 1 300 val
+prsuzvpamj 1 300 train
+prswswedvt 1 300 train
+prswuwlrpw 1 300 val
+prsxidlaqr 0 300 train
+prtldxpsns 1 300 train
+prtmksqbcv 1 300 test
+prtvgnappt 1 300 train
+prtvyumpti 1 300 train
+prtwvvtdto 1 300 val
+prulxmmjmt 1 300 train
+prunoewxoq 1 300 train
+pruqpfsula 1 300 val
+pruqyaiife 1 300 val
+pruskulhhm 1 300 train
+pruvhwligx 1 300 train
+pruwctpcbi 0 300 train
+prvravbahs 1 300 train
+prvutuwrfy 1 300 train
+prvyilhfbb 1 300 train
+prvytafjrk 1 300 train
+prvywumnxp 1 300 train
+prwcfvlbxt 1 300 val
+prwhicvvvz 1 241 train
+prwqccopko 1 300 train
+prwsdpvgvk 0 300 train
+prwsfljdjo 0 300 test
+prwxnkdjvn 1 300 val
+prwzaizkfy 1 300 val
+prxhknqiyr 1 300 train
+prxibpoybd 1 300 train
+prxkevwrug 1 300 train
+prxrziqmxp 1 300 train
+prxvbhiufo 1 298 train
+prygcizpfk 1 300 train
+pryhnrjpqx 1 300 train
+prykceywau 1 300 train
+pryldgytcj 1 300 train
+prymcazhvz 1 300 val
+prypqfuqom 0 298 train
+pryqgrbtnu 1 300 train
+pryvtahjru 1 300 train
+prywkmtclk 1 300 train
+pryxtabnpi 1 300 val
+przaaqgtum 1 300 train
+przaseupwe 1 300 train
+przcqlamse 0 301 train
+przdkptfpp 1 300 train
+przeoxdbzt 1 300 val
+przkpfwrmr 0 300 train
+przmougwsm 0 298 train
+prznheagqp 1 300 train
+przscnfglk 1 300 val
+psajmusbbu 1 300 train
+psalqzavtc 1 301 train
+psaokntwiy 1 299 val
+psaqsnkuyv 1 300 train
+psawrjcfdu 1 300 train
+psazslaorf 1 297 train
+psbannuovk 1 300 train
+psbaqedyql 0 300 train
+psbcvgfccy 1 300 train
+psbgxhroec 1 300 train
+psbgyrmswy 0 300 train
+psblnhztzm 1 301 train
+psbmmlmhtt 1 300 train
+psbmqhbixe 0 300 train
+psbtwxcors 1 300 train
+psbxinwmzi 0 301 train
+psccxyywfp 1 300 train
+pscdwkknno 1 300 train
+pscgggihkg 1 300 train
+pscilvlcfe 1 300 train
+pscjganiiz 1 300 train
+psckptrrys 1 300 train
+pscolfeoau 1 300 val
+pscsecpnhp 1 300 train
+psdcglgadb 1 300 train
+psdcgttrur 1 300 train
+psdftvfewc 1 300 train
+psdnsoapba 1 300 val
+pseatxfbza 1 300 train
+psecynamaj 0 300 train
+psegambhyq 1 300 train
+pseiechzco 1 300 train
+psesgswysh 1 300 train
+psesikjaxx 0 300 test
+pseztyrlso 1 300 train
+psfaanpnqo 0 300 train
+psffpiwnao 1 300 train
+psfhnebcxe 1 301 train
+psfnavhkox 1 300 train
+psfudmkhan 1 300 train
+psfueokvrh 0 300 train
+psfzgwrher 0 301 train
+psgbuqshod 0 300 train
+psgcmeevqw 0 300 train
+psgeptbhlk 1 300 train
+psgfoiwcof 1 300 train
+psglltlchs 1 300 train
+psgqslyyct 1 300 train
+psgvvlbosy 1 300 train
+psgxemizbf 0 300 train
+psgxwqrqse 1 300 val
+pshagenxml 0 300 val
+pshetjwdcn 1 301 val
+pshppncsis 1 300 train
+pshqinwkqc 1 294 train
+pshvwyylic 1 300 val
+psiahtkjin 1 300 train
+psikfpkmvy 0 300 train
+psisqzlzqv 1 300 val
+psiwyiktka 0 300 val
+psiwzhnvnf 1 300 train
+psjamnzvbl 1 300 train
+psjbyfcubk 1 300 train
+psjffjrnvi 0 298 train
+psjfwjzrrh 0 300 test
+psjltzzzlb 1 298 train
+psjnkzpili 0 301 train
+psjqjhdfej 1 300 train
+psjvaeamke 1 300 train
+psjvcvakau 1 300 train
+pskhcdanob 1 300 train
+pskjrrupny 1 300 test
+pskpgmwcjj 1 300 train
+pskrepsber 1 300 train
+pskslqctsq 0 300 train
+pskybfspex 1 300 train
+pskzhjepes 1 300 val
+pslavnuzte 1 240 val
+pslcdcjmle 1 300 val
+pslgsswpuv 1 300 train
+psllfggoyy 1 300 train
+pslnizmjib 0 300 val
+pslnqfybnb 1 300 val
+pslodahayi 1 300 train
+pslqdxgkoc 1 300 train
+pslqjqpbgu 1 300 train
+psltqmakjh 0 300 train
+pslumxunya 1 300 val
+pslxecvayx 1 301 train
+pslxmuatrm 1 300 train
+psmfxfstis 1 300 val
+psmgbygjcc 1 300 train
+psmirnmcmj 1 301 train
+psmnnjrwgb 1 300 val
+psnivxcrjb 1 300 train
+psnpxubqoa 1 300 train
+psnwzhfdao 1 300 train
+psnznfywkd 1 301 val
+psofetjjkx 1 300 val
+psofrcnrgj 1 300 val
+psognfwlxk 1 300 val
+psolbicyli 0 300 train
+psomgzytro 1 300 train
+psounuyhsk 1 300 train
+pspdlkseym 1 241 train
+pspojyizal 0 300 train
+pspowoowfn 1 300 train
+psppdyzxwn 1 300 train
+psppnmmhlr 0 300 train
+psptkqaviq 1 300 train
+pspvfiepjs 1 298 train
+pspwqpiigs 1 300 train
+pspxnhbwgy 1 298 train
+psqdkvmuus 1 300 train
+psqesimzbe 1 300 train
+psqezccjav 1 300 train
+psqfjnwcie 1 300 train
+psqgyzlhhq 0 300 train
+psqheyfgdj 1 300 val
+psqjbosito 1 300 train
+psqjdhvrfr 1 301 val
+psqjnmfhua 1 300 train
+psqlpoxqhk 0 300 val
+psqvrrxuiv 1 300 train
+psqwmochwx 1 300 train
+psqxmzptxx 1 300 train
+psrafaxxrw 0 300 val
+psrcrajmmo 1 300 val
+psrhatxoye 0 301 train
+psrnjaooiu 1 300 val
+psrtgeevbs 1 300 train
+psrwibjyuz 1 300 train
+psryskuxbd 0 300 train
+pssipdjqmk 1 300 train
+pssixzwzlr 1 241 train
+pssmmowqqc 1 300 train
+pssrxuhhzx 0 300 train
+pssuagmhqe 1 300 train
+psswspmmjg 0 300 train
+psszewcfrt 1 301 train
+psthmmpqzs 1 300 train
+pstkkfubvq 1 299 train
+pstmnmnetg 1 300 train
+pstnwcsdde 0 300 train
+pstqbmtlri 1 301 train
+pstvcbupkm 0 300 train
+pstvilzury 1 300 train
+psueeblydl 1 299 val
+psufknjvkp 1 301 val
+psuktdtnuq 1 300 val
+psunkvudmg 1 300 train
+psuzfwxhwc 1 300 train
+psvcdjojbb 0 300 train
+psvgcdqodl 1 300 train
+psvjlhuzrx 1 301 val
+psvvbtlttj 1 300 train
+psvvootmtk 1 300 val
+psvwnycwwd 1 300 train
+pswbextasn 1 298 train
+pswdsdsfha 1 300 test
+pswjkqhdgd 1 300 train
+pswkuttlel 1 300 val
+pswlvjnqxa 1 241 train
+pswonpmzlk 1 300 train
+pswpwsihyh 1 300 val
+pswwmkspts 1 300 train
+pswwwdklvv 1 300 val
+pswwwnkozz 1 241 train
+pswxaetdjj 1 300 train
+pswxwumwvb 0 300 train
+psxcpbpccq 1 300 train
+psxdpainbx 1 300 train
+psxhjgbmjc 1 300 train
+psxmyfhtwl 1 300 train
+psxmywrvbh 1 301 train
+psxqkzlkmv 1 300 train
+psxrqbfwyw 1 300 train
+psxugpwbol 1 300 train
+psxvmehkfb 0 302 train
+psygyubfhy 1 300 train
+psyjocudqa 1 300 train
+psyozwuxvh 0 300 train
+psyrjsoiys 1 300 train
+psytlhwyum 1 298 train
+psyxxwppgx 1 300 train
+psyyushnlf 1 300 train
+pszhomolcr 1 300 train
+pszhuamqdr 1 300 train
+pszkfghvci 1 300 val
+psznphvwax 1 241 train
+ptadbqjzih 1 300 val
+ptalayawet 1 300 train
+ptatgjbsfs 1 300 train
+ptaurjmrva 1 300 val
+ptaxdkncjm 1 241 train
+ptbbgjgjdk 0 300 val
+ptbbxfllmn 1 300 val
+ptbfnkajyi 1 300 test
+ptbianjtws 1 241 train
+ptbnewtvon 1 299 test
+ptbqojfbbj 1 301 train
+ptbtnbbctl 1 239 train
+ptbtuynmhm 0 241 train
+ptcdqoiuel 1 300 train
+ptchnzeeqc 0 300 val
+ptcrjmzmdl 1 300 val
+ptcxyflhku 1 300 train
+ptdawaxkyp 1 300 train
+ptdcjzmqea 1 300 train
+ptdcpkvzjp 1 301 val
+ptdmgkolnb 0 300 train
+ptecwsxxoq 1 300 train
+ptegweijrr 0 300 train
+ptehdebjge 1 240 train
+pteiaddjmj 1 298 train
+ptejxhztrw 1 300 val
+ptepivjkjl 1 300 train
+ptesqyfsvl 1 300 train
+pteureichh 1 241 train
+ptewxqetvo 1 300 train
+ptexkavgvu 1 300 train
+ptexzwohvg 0 300 train
+ptfbpjlwcy 1 298 val
+ptfcnxqvob 0 300 train
+ptfdtopsfn 1 300 train
+ptfekpqytz 0 300 train
+ptfemodnzw 1 300 train
+ptffmacbwf 1 300 train
+ptffofifnz 1 300 train
+ptfpegxozl 0 300 val
+ptfpxubayi 1 298 train
+ptfqgznfww 1 300 train
+ptfqhiqkgd 1 300 train
+ptggxwwewn 1 298 train
+ptghltsnbo 1 300 train
+ptgknknrfm 1 302 val
+ptgpefayqs 1 300 train
+ptgpqdnxtd 1 300 val
+ptgvxdueef 0 300 val
+ptgzllaest 1 301 train
+pthbuiuswl 1 300 test
+pthbzlbnhd 1 300 val
+pthlshvzqz 1 299 val
+pthnonoxoj 1 298 train
+pthqwzgocx 1 300 val
+pthvzhzbqp 0 301 train
+pthxmybodk 1 240 val
+pticjimqju 1 300 train
+ptickeoewq 1 302 train
+ptifpnogkc 1 300 train
+ptigqidlnr 1 300 train
+ptiiiqkqgs 1 300 train
+ptijmcgspq 1 300 val
+ptinzvstrk 1 300 train
+ptiqmqsjly 1 300 train
+ptirnbtsct 1 300 train
+ptivgzjnix 1 298 train
+ptizifndmz 1 241 train
+ptjgutvhoc 1 301 train
+ptjgvacvem 1 300 train
+ptjgyuwsgh 0 300 train
+ptjihahpmt 1 300 train
+ptjzgjopac 1 300 train
+ptkcmwnfjv 0 299 test
+ptknnwmxet 1 300 val
+ptkofkgpvk 1 300 train
+ptkykdajdz 0 300 val
+ptkynxwwnh 1 300 train
+ptlhohlyxq 0 300 train
+ptlrtncaqy 1 300 train
+ptlwvhdjqb 1 300 train
+ptlzpuawoo 1 300 val
+ptmhpsvdnu 0 300 train
+ptmnhskybc 1 300 train
+ptmoowylgr 0 301 val
+ptmxaucxlh 1 296 train
+ptmxzhidvv 0 300 train
+ptnbjausxb 1 297 train
+ptngovnwti 1 299 train
+ptnldszkif 1 300 train
+ptnzsvzlej 1 300 train
+ptobzydrwa 1 300 train
+ptocqdufns 1 301 train
+ptoebvtfqn 1 301 val
+ptofgxlgos 1 301 train
+ptokilxwcx 0 300 train
+ptolwfdzjt 1 300 train
+ptonxdzcbp 1 300 train
+ptopxblgje 1 300 train
+ptoqpwlydy 1 300 train
+ptorvipsoq 0 300 train
+ptotgfhhti 1 300 train
+ptowpogiby 1 301 train
+ptozvzlhny 0 300 train
+ptpbhibdix 1 300 train
+ptpcrwinzo 1 301 train
+ptpusmxreb 1 300 test
+ptpwappdyx 0 301 train
+ptpwirgwfz 1 300 train
+ptpzrqekgf 1 300 train
+ptqavjzsdb 1 300 train
+ptqgpxscnp 1 300 train
+ptqgzekfid 1 300 train
+ptqhyfnqrh 1 300 train
+ptqizffivr 1 300 train
+ptqkwtkwpq 1 300 train
+ptqsphywja 1 300 train
+ptqtbnjqeg 1 302 train
+ptqthgwsnt 1 300 train
+ptquauwruu 1 300 train
+ptqwsbbuxi 1 300 train
+ptrdkljjfh 1 300 train
+ptrkaagphv 0 300 train
+ptrldmvjvb 1 241 train
+ptrminytzx 1 300 train
+ptrqtgvrqf 1 300 val
+ptrvkabcys 1 301 train
+ptrwdjolho 1 301 train
+ptskyqbwek 1 300 train
+ptsmdvjijz 1 300 val
+ptsoeirkem 1 300 test
+ptsrrwkmqp 1 300 train
+pttcukoeon 1 300 train
+pttmamyudu 1 300 train
+pttmkamnkw 1 300 train
+pttsfakrqz 1 300 train
+pttsxrwows 1 300 train
+pttxfjzsti 1 300 train
+ptubhvthkl 1 300 train
+ptubyqtxip 1 300 val
+ptvfbmvvnf 1 300 train
+ptvnrlztcb 1 298 train
+ptvpbuutlp 1 300 train
+ptvvpfwrop 1 301 val
+ptvvqchzxm 1 300 val
+ptvwfthsjg 0 300 train
+ptvwojjuez 1 300 train
+ptwfypbazx 0 300 val
+ptwlgtvhmt 0 300 train
+ptwvktbrkb 0 300 train
+ptwxxjqnnf 0 301 train
+ptxbxvopbp 1 302 train
+ptxcpwhcwg 1 300 train
+ptxmbsgifn 1 300 train
+ptxnzxbfbt 1 300 train
+ptxrrvbgjc 1 300 train
+ptxxeysqwz 0 301 train
+ptyddhxfis 1 298 train
+ptyexioocn 1 298 train
+ptymzaomrb 1 300 train
+ptywykisek 1 298 train
+ptyxyqqexv 0 300 train
+ptyybmorhf 0 300 train
+ptyyglfweg 0 300 train
+ptznrexlyq 1 300 train
+ptzpojqopm 1 288 train
+ptzsbpefvr 1 300 train
+ptzxvjgjwz 0 300 train
+puadtimaph 1 300 train
+puajakcqsb 1 301 train
+puamjvtpxs 1 300 train
+puankmtkpx 0 300 val
+puapxpobsn 1 299 test
+puaqavfiui 1 300 train
+puaqffndyl 1 300 train
+puaqyhykdj 1 300 train
+puassueris 1 241 train
+puawxeztom 0 300 train
+puaxomzuof 1 300 train
+puayaegfzc 1 300 train
+puayuddapu 1 300 train
+pubicpfuma 1 300 train
+publsojwjn 1 241 train
+pubxbancvm 1 298 train
+pucbyzevhg 1 300 val
+puccrqvzbn 1 300 train
+pucdgmijoz 0 300 train
+puckporfwj 1 300 train
+puclqugcvs 1 300 val
+puclrvpuxs 1 300 train
+pucrncfqug 1 300 train
+pucrqtfevv 1 299 train
+pucwejjpdg 1 300 train
+pucwpflfiy 1 241 train
+pudbzateow 1 302 val
+pudistmysg 1 300 val
+pudronlbzz 1 300 val
+pudrrwhwpr 1 300 train
+pudvapwppf 0 300 val
+pueavxabai 1 300 train
+puebkyijmi 1 300 train
+puecbpxyqo 1 300 val
+puefyybyiz 1 241 train
+puehpcuogn 1 300 val
+pueipmaude 1 300 train
+puekyxazbi 1 300 train
+puemvkoblm 1 300 val
+pueogprluj 1 300 train
+pueqlvhrwe 1 300 train
+puexbfedbu 1 300 train
+pufblpwikl 1 299 test
+pufnpandex 1 302 val
+pufrjniraf 1 300 train
+pufzbiegpb 1 300 val
+pugogunilb 1 300 train
+pugpbktags 1 300 train
+pugskpcbwo 1 300 train
+pugtgocjzr 1 300 train
+puguqhbdvh 1 300 train
+pugvoalmgu 1 300 train
+pugzrwechr 1 300 val
+puhcrhifhw 1 300 train
+puhhqubmrv 0 300 train
+puhjrwiugy 1 300 train
+puhmctjugr 0 300 train
+puhmumufcy 1 299 val
+puhskmytrc 1 300 val
+puhtjlzuqw 1 300 train
+puhybjenqt 1 300 test
+puiapwsced 1 300 train
+puifrhvwij 1 300 test
+puigcvenlb 1 300 train
+puikzqtlir 1 241 train
+puinuzgmcu 1 300 train
+puiomqyjhv 1 300 val
+puisdvqpcg 1 297 train
+puixmrlgke 1 300 train
+pujesybccy 0 300 train
+pujrqbaiba 1 300 val
+pukadnvszm 0 300 val
+pukazvyxsq 1 300 train
+pukdmxmyta 1 300 train
+pukfvcfugs 1 300 train
+pukgfyejhx 1 300 train
+pukmuzfsqo 1 300 train
+pulcwtbbys 1 300 train
+pulemkckas 1 300 train
+pullzicjlk 0 300 train
+pulsefmxgy 1 300 train
+pulxdhquqz 1 300 train
+pumcwenhvq 1 300 val
+pumddnsxwx 0 300 train
+pumdyutcwr 1 300 val
+pumffnnouu 1 300 val
+pumjpkyctp 1 300 train
+pummhwdbej 1 300 val
+pumnrqagpu 1 300 train
+pumozgsobv 1 300 val
+pumsloercf 1 300 train
+pumwbrpyuj 1 300 train
+pumywgewee 1 300 test
+pumzjcddou 1 300 train
+punagkmsre 1 300 train
+pundurrjbg 1 300 train
+punpfcakvs 1 300 val
+punqbfjyrc 1 300 train
+punreadfhf 1 297 train
+puntestxix 1 300 test
+puntvfhjrn 1 298 val
+punuozfxbm 1 300 train
+puodjlqdcc 1 298 train
+puoqeuzlow 1 299 test
+puorotbdiv 1 300 train
+puotmtodbn 1 300 train
+puovyafeld 1 236 train
+puowduonmd 1 300 train
+puowyznsdq 1 300 train
+pupczrsusw 0 300 train
+pupinebqev 1 300 train
+pupjadwkax 1 239 train
+pupjfiopkk 0 300 train
+puplpheshf 1 300 train
+puplpoaiqf 1 300 train
+pupojdyqlw 0 300 train
+puppdcffcj 0 300 train
+puprpprrvq 1 300 train
+puqdtunitc 0 300 train
+puqnpcuwsy 1 300 train
+puqojlpouk 1 300 train
+puqqqnmgia 1 300 val
+puqtetnhue 1 300 train
+purhadhjku 1 300 train
+purmwibzcn 1 300 train
+puroflwjfs 1 300 train
+purusnswkx 1 300 train
+purxqukfuh 1 300 train
+pusajukxil 1 300 train
+pusaxlfiud 1 300 train
+pusdwikemw 1 300 train
+pusesezkcd 1 300 train
+pusfbqewwf 1 300 train
+pusfdyrggi 1 300 train
+pushoizzcn 1 300 train
+pushugqeto 1 301 val
+pusklupezx 1 300 train
+pusldsubqy 0 300 train
+pusmcmsihq 1 300 val
+putdirfiry 0 300 train
+putnlunxni 0 300 train
+puttddbrkz 1 300 train
+putvyjellt 1 300 train
+putyzkxcjz 1 300 val
+puudvugxrl 0 300 val
+puugukhsrk 1 298 train
+puulczljgm 1 300 train
+puupfthjwb 1 300 test
+puusxoqgev 0 300 train
+puutrzxais 1 300 train
+puvfnogfkr 1 300 train
+puvpowzusj 1 300 train
+puvuqrlolz 1 300 train
+puvvjgzryj 0 300 val
+puvvywduwt 1 300 val
+puwduxnicf 1 300 val
+puwgjnaimb 0 300 train
+puwjvgezys 1 300 train
+puwwiljdre 1 300 train
+puxasptaov 1 300 train
+puxgaenjhv 1 300 val
+puxjlqikgw 1 300 train
+puxpxchdzm 1 298 train
+puxsudeeov 1 300 train
+puxusolkbv 1 300 test
+puxyqrfjta 1 300 train
+puybhpzlhy 1 301 train
+puybjjviqg 1 300 train
+puydativvj 1 302 val
+puyeatljay 1 300 train
+puylpqprqd 0 300 val
+puynovlhnp 1 300 train
+puyptpptbp 1 300 train
+puytpmdnrs 1 300 train
+puyxvhkodv 1 301 train
+puyyqevntm 1 301 train
+puyziegkva 1 300 train
+puzolsalqh 1 301 train
+puzrickksz 1 300 train
+puztlquftu 1 300 train
+puzwelcdiy 1 298 train
+puzwojcrbe 0 300 train
+pvaeizstfs 1 300 train
+pvahjhdqxt 1 300 val
+pvakyzpcfd 1 300 train
+pvalhrgcbo 1 241 train
+pvaqstcfjk 1 300 train
+pvarujznbl 1 300 train
+pvavxqylhc 1 300 val
+pvazedypms 1 300 train
+pvazrnlkpo 1 301 val
+pvbarubdrg 1 300 train
+pvbdhnfemx 1 300 train
+pvbdifolam 0 300 train
+pvbewjhnjp 0 301 train
+pvbgaiuqns 1 300 val
+pvbgxirmzd 1 300 train
+pvbgxkkcat 0 299 val
+pvbhchdjbf 1 300 train
+pvbinrxwtm 1 300 train
+pvbkjdoomb 1 300 train
+pvbngziwju 1 300 train
+pvbqfsjkau 1 240 train
+pvbqiphibf 0 300 train
+pvbvaosojl 1 300 train
+pvbzxpsick 1 300 train
+pvcawvxzom 1 300 val
+pvcfpdevfm 1 300 train
+pvcjlcqspa 1 300 train
+pvclpwyuby 1 240 val
+pvcxoterzh 0 300 val
+pvdoujjofx 1 300 train
+pvdwkitwcm 1 300 train
+pvdysvkach 0 300 train
+pvebjakgkr 1 301 train
+pveeurpzey 1 300 train
+pvegwounyt 1 300 train
+pvehbbhjcc 1 300 val
+pvelrttiji 1 300 train
+pvenevvffc 1 300 train
+pvesxwlxgl 1 300 train
+pvetudqank 1 300 val
+pvevprrtnu 1 300 test
+pvewomynek 1 300 train
+pvezupgald 1 298 train
+pvfewkcgrp 0 300 val
+pvfgokembu 1 300 train
+pvfiljtfns 1 300 train
+pvflezopur 1 298 train
+pvfluzncii 0 300 train
+pvfnkxpaqd 1 300 train
+pvfruqwnqn 1 299 train
+pvftdbjqcw 1 300 train
+pvfwhqthav 1 300 train
+pvgotgpsft 1 300 train
+pvhegpzrlx 0 300 train
+pvhhdpasbc 1 300 val
+pvhhetqvpi 1 300 train
+pvhjbuffsw 1 301 train
+pvhjgvgvie 1 300 train
+pvhluckinx 1 300 val
+pvhoqxcwjn 0 300 train
+pvhprzdbpm 1 300 train
+pvhsfxjapb 1 300 train
+pvhznuvjim 0 300 train
+pvicuwqucg 1 241 train
+pviejtcpvi 0 300 train
+pviekdmubr 0 300 train
+pvinqmwvsm 1 298 train
+pviofymdzo 1 300 train
+pviulkqfkj 1 300 val
+pviwtrccdg 0 300 train
+pvixruqpez 1 300 train
+pvjdudsjri 1 300 val
+pvjelmhiee 1 298 train
+pvjjqfavjb 0 300 train
+pvjpcbveym 1 301 train
+pvjqwjoeuf 1 300 train
+pvjruodnai 0 300 train
+pvjwuaajjd 1 300 val
+pvjybkpdsy 1 300 train
+pvjzcunyca 1 301 val
+pvjzffabqd 1 300 train
+pvjzjjeful 1 300 train
+pvkcqmhdvj 1 300 val
+pvkltwwkwh 1 300 train
+pvknvizxhx 0 300 val
+pvktyesgur 1 300 train
+pvlbqbyxxi 1 300 test
+pvlddrdvoz 1 300 train
+pvljjyeuyi 1 300 train
+pvllgbwlbg 1 300 train
+pvlqsnxkpb 0 300 train
+pvlsmorwch 0 300 val
+pvlzulokmy 1 300 train
+pvmbcdmajf 1 300 train
+pvmdlkmifj 1 300 train
+pvminukwso 1 300 train
+pvmnhjpuwv 1 298 train
+pvmokvewhb 1 300 train
+pvmutazdgu 0 300 train
+pvmwuzzclt 1 300 train
+pvnautgzwp 1 300 train
+pvncknmdzb 1 300 val
+pvnhodzpvf 1 300 val
+pvniezibwb 0 300 train
+pvnooavkvn 1 300 train
+pvnpmbpwxn 1 300 train
+pvnsvczxkh 1 300 train
+pvnzajnwxz 1 300 train
+pvodinbyjc 1 300 train
+pvoktifemd 1 300 train
+pvowbefokt 1 300 train
+pvpbwurpee 1 300 train
+pvpbwxosrx 1 300 train
+pvpcemmguo 1 300 val
+pvpfmghnif 1 300 train
+pvpwbbfdjq 1 298 val
+pvpwmfnpco 1 300 train
+pvpwrlobcx 1 300 train
+pvqppdmqqg 1 300 train
+pvrbpkrrfk 1 300 test
+pvrdcolevr 0 300 train
+pvrencaywq 1 300 train
+pvrfbgpgje 1 300 val
+pvrggltqrl 0 300 val
+pvrijmergz 1 300 val
+pvrjjvoihs 1 300 train
+pvrlmnqxfu 1 301 val
+pvrmstiyry 1 240 train
+pvrncpaovg 0 241 train
+pvrqrjywet 1 300 val
+pvrsaweacx 1 302 train
+pvrvhyoqhg 1 241 train
+pvsdnhqebq 1 298 train
+pvsjanaugn 0 300 train
+pvsjewpxmi 1 300 val
+pvsjhvzhgz 1 300 train
+pvsmrssume 1 296 train
+pvsmtyuhxx 1 302 train
+pvsslamopo 0 300 train
+pvstgeijgo 1 300 train
+pvtcrpqoet 1 300 test
+pvtcxqusay 1 300 train
+pvtedksvmc 1 299 train
+pvtljvxtqz 1 300 train
+pvtlyjliyi 1 300 train
+pvtoqwhhpw 1 300 train
+pvtrkaxahz 1 300 train
+pvtsjgugdp 1 300 train
+pvtuczlvaq 1 300 val
+pvuajqhnxc 1 300 val
+pvudwuaxpd 1 297 train
+pvueaojage 1 297 train
+pvujmqubwu 1 300 train
+pvupowsims 1 300 train
+pvurqhwkpk 1 300 train
+pvuxcxsoxy 1 300 train
+pvuzdyfnou 0 300 val
+pvvdrezghj 1 301 train
+pvveucnxsa 1 300 val
+pvvgbvmjed 1 300 val
+pvvkcudjjq 1 300 train
+pvvskuhbkc 1 300 train
+pvvvmrjpny 1 300 train
+pvvvzoybal 1 300 train
+pvvwgaqwef 1 300 val
+pvvxzkkhfc 1 300 train
+pvwmgrtott 0 300 val
+pvwsgjbvmi 1 300 train
+pvwxpfbicg 1 300 train
+pvxazfydoz 1 300 val
+pvxcqhhgfk 1 300 train
+pvxiloudsj 1 300 train
+pvxkpphtcs 0 301 val
+pvxlbjyehg 1 300 val
+pvxnqhtwda 1 300 train
+pvxroukbzo 1 298 train
+pvyadcqekd 0 300 train
+pvybjnqszo 1 300 train
+pvycdsluwg 1 300 train
+pvydbwrdgi 1 300 train
+pvyqvuwwut 1 300 train
+pvysivcqdd 1 300 test
+pvyzkmeswp 1 300 train
+pvzgufiliz 0 300 train
+pwablachdg 1 300 train
+pwagadvxrs 0 300 train
+pwaluxvqcn 1 300 train
+pwaqrbyaat 1 300 test
+pwaximtuxq 1 300 val
+pwbegjvvgm 1 300 train
+pwbgbuwgyj 1 300 train
+pwbifbezht 1 300 train
+pwbjjeivka 1 300 val
+pwbpbksysm 1 300 train
+pwbqppnqhb 1 300 train
+pwbuloqjcv 1 300 train
+pwclwohxgz 1 301 train
+pwcniqcure 1 301 train
+pwdakyifzk 1 300 train
+pwdglwjtgn 1 301 train
+pwdicbfotk 0 300 val
+pwdrlbhjjv 1 300 val
+pwduwistqx 1 300 val
+pwdvfmaywo 1 300 train
+pwdworvuzz 1 300 train
+pwdwxpwbyp 1 300 train
+pwdyxmhngn 1 300 train
+pweassbteg 1 300 train
+pwecsohwac 0 300 train
+pwelobqqwe 1 300 train
+pwenpbvjar 1 300 train
+pweozdkpjf 1 300 train
+pweswxvjem 1 241 val
+pwewkvapmm 1 300 train
+pwewtupevo 1 300 train
+pwfamnakmq 1 300 train
+pwfbnkdqlt 1 300 train
+pwfcdhggjy 0 300 train
+pwfgwvhwvo 1 300 train
+pwfipeanwn 1 300 val
+pwfkaioedj 1 298 train
+pwftvlkjqp 1 300 train
+pwfuznmeya 1 300 train
+pwgbzxpmgt 1 136 train
+pwglpxzofe 0 300 train
+pwgpewfjvf 1 300 train
+pwgsifceaj 1 300 train
+pwgtdgnidb 1 300 train
+pwhbiwkcpp 1 300 train
+pwhfyhiylv 1 300 train
+pwhiztzjqx 1 300 train
+pwhtfnrmhu 0 300 train
+pwicpqzvdr 1 300 train
+pwigvuwspl 1 300 val
+pwihptsjpa 0 300 train
+pwinbqoyez 1 300 train
+pwipwrosab 1 300 train
+pwixhhbnpy 1 300 train
+pwiyrsvgtn 1 300 train
+pwjhidsxtc 1 300 train
+pwjjzdinia 1 300 train
+pwjrkujnlr 1 300 train
+pwjvtymoel 1 300 train
+pwkcllsrft 1 300 val
+pwkdhzxlhb 1 300 train
+pwkmcxnguy 1 300 train
+pwkmgeuolb 0 300 val
+pwkmosbrkn 1 300 train
+pwkoqrlhkx 1 300 train
+pwkqbtxyei 1 300 train
+pwkrnbfzex 0 300 train
+pwkvbzeocw 1 300 train
+pwkybpotkd 1 300 val
+pwkylkjdjp 1 300 val
+pwlftlhgua 1 300 train
+pwlgoeopkd 1 300 train
+pwmahldzbr 1 299 val
+pwnfhdvxkq 1 300 val
+pwnfyidcej 1 300 train
+pwnwbevioy 1 300 train
+pwnwtljvyy 1 300 train
+pwnydczknu 1 300 train
+pwoeaeutpq 0 300 train
+pwojjsancx 1 300 train
+pwojnyhlyy 1 300 train
+pwomjjcxft 1 300 train
+pwomyrqlpn 1 300 train
+pwoscxepfi 1 300 train
+pwplooonzr 1 300 train
+pwplxgafzo 1 298 train
+pwppruapvi 0 300 train
+pwpvbcksde 1 300 train
+pwpxmcsmqu 1 300 train
+pwpxnberdn 1 300 val
+pwqcfklfqn 0 300 train
+pwqcpexcoi 0 300 train
+pwqdcoipzh 1 300 train
+pwqfoprgkw 1 300 train
+pwqigiztxg 0 301 train
+pwqmzgwwnu 1 300 val
+pwqowswofh 1 298 train
+pwqrdibcoh 1 300 train
+pwqrhnzwak 1 300 train
+pwqypdapsq 1 300 train
+pwrchlvidf 1 300 train
+pwrjjomcsq 0 300 train
+pwrudpreyl 1 300 train
+pwrwtspihu 1 300 train
+pwrybtzkku 1 292 train
+pwseejrfof 1 301 train
+pwsguuppwe 1 300 train
+pwskzytvbq 1 300 val
+pwslgedegj 1 300 val
+pwspmvzdmn 1 301 train
+pwsqpukvxu 1 300 train
+pwssgblgzu 0 300 train
+pwsstujldo 1 301 train
+pwswsvzyaf 1 300 train
+pwswtdarnp 1 300 train
+pwsxqxfpvm 1 300 train
+pwtaarnvzf 1 301 val
+pwthauvkpm 1 300 val
+pwtmqgnftv 0 300 train
+pwtsxotqzw 1 300 train
+pwttfmbvdg 1 300 train
+pwtvoidtgb 0 300 train
+pwugkqlpeh 1 300 train
+pwugzqrzqu 0 300 train
+pwuidwlspg 1 298 train
+pwuiufybau 1 300 train
+pwvbyeccmw 1 300 val
+pwvidqwogv 1 300 val
+pwvihadqqr 1 300 train
+pwvnzblmuf 0 300 train
+pwvpfttgsf 1 300 val
+pwwdehqvoc 1 300 train
+pwwdtbvbuu 1 292 val
+pwwgiqiybt 0 300 val
+pwwjdomzxi 1 300 train
+pwwopgnljb 1 300 train
+pwwqvkbxdy 1 301 train
+pwwrsdjwer 0 300 val
+pwwrycbwku 0 300 train
+pwwrztartb 1 302 train
+pwwtbzbbiz 1 300 train
+pwxahrrboa 1 300 train
+pwxefhyxxu 1 299 test
+pwxqijjaci 1 300 val
+pwxsqzuphk 1 290 train
+pwyhowpyra 1 241 train
+pwyhucpuec 1 300 train
+pwykrfsnwi 1 300 train
+pwyourazpb 1 298 train
+pwyouvrckw 1 300 train
+pwzbbarjex 1 300 train
+pwzbkywnec 1 300 train
+pwzeckclkl 1 300 val
+pwzgdaenka 1 300 val
+pwzgshjfyh 1 300 train
+pwztmwvivr 0 300 train
+pwztnpzvhx 0 300 train
+pwzzorrlkk 1 300 train
+pxaceeskeg 1 300 val
+pxatunhkih 0 299 train
+pxbbrnmrxl 1 300 train
+pxbfexoxkk 1 301 train
+pxblqvswbc 0 300 train
+pxbztcqpio 1 300 train
+pxcfixpryg 1 300 train
+pxcfrszlgi 0 300 test
+pxchphifup 1 300 train
+pxcjdwfpga 1 300 train
+pxclpmcsmf 1 300 train
+pxcumwtops 0 239 val
+pxcyvjgldm 1 300 train
+pxdagwqxxk 1 300 val
+pxdahxdyeq 1 300 train
+pxdjqakcyf 0 300 val
+pxdkjopwcv 0 300 val
+pxdmdyvkul 1 300 train
+pxdncokkgn 1 300 val
+pxdqykoimv 1 300 train
+pxdtilqmlb 1 301 train
+pxdwcuxvjv 0 300 train
+pxegpancna 1 300 train
+pxelzgjhmv 1 300 val
+pxempkbhsw 1 300 train
+pxesrflxxf 1 300 train
+pxevsrdzrr 1 300 train
+pxeykrpjaa 1 300 val
+pxfaovedsm 1 301 train
+pxfmtdcdgz 1 300 train
+pxgcsltbuo 0 300 train
+pxgeaiygef 1 300 train
+pxggyipbau 1 301 train
+pxgnazvpjg 1 300 train
+pxgzahcusu 1 300 val
+pxhcfbebvr 1 302 train
+pxhgktplnn 1 300 train
+pxhkycpdll 1 300 train
+pxhwgskonh 0 300 train
+pxhwnciafz 1 241 train
+pxhxckwmlo 1 300 val
+pxhymuwsgk 1 301 val
+pxhytkjqso 1 300 train
+pxhzhjufts 0 300 val
+pxiiaizoeh 1 300 val
+pxikipycvd 1 300 train
+pxjareobxm 1 300 train
+pxjepyolrx 1 300 train
+pxjkzvqomp 0 300 test
+pxjsnrepmv 1 300 train
+pxjtropsqz 1 300 train
+pxkcgqewsh 1 301 train
+pxkhfnxeta 1 297 train
+pxklenwixy 1 300 train
+pxklgtgees 1 300 train
+pxkvswtvif 0 300 val
+pxkzujgyio 0 300 train
+pxlbxfvijw 1 300 val
+pxleaiojzt 1 300 train
+pxlfksaczd 1 300 train
+pxlvfbkkhv 1 298 train
+pxlvssqqqn 1 300 train
+pxlzhtrerz 1 300 train
+pxmgelxfdb 1 301 train
+pxmhoaqcek 1 300 test
+pxmqbfgrrg 1 300 train
+pxmyzylodg 1 300 train
+pxnaxnviej 1 300 train
+pxnbdijzfp 1 300 train
+pxncjvxtcb 1 297 val
+pxncmrrwpd 1 300 train
+pxncrwhyia 1 300 val
+pxnjwmafbx 1 300 train
+pxoflohafi 1 300 train
+pxohsvuaxb 1 300 train
+pxotgakoal 1 300 train
+pxowiglhyj 1 299 test
+pxowmfjlhp 1 300 val
+pxpbqjnvfb 1 300 train
+pxpgpipzko 1 300 val
+pxphjdphnu 1 298 train
+pxphjgbuan 1 300 train
+pxpiataokv 1 299 val
+pxpjtwxsqz 1 300 train
+pxpjybydpw 1 300 train
+pxpkrqihdv 1 300 train
+pxpmuntifv 1 300 val
+pxpuekwznq 1 300 train
+pxpxhzacds 1 300 train
+pxpzbkubiw 1 300 train
+pxqbgycgke 1 300 train
+pxqdpfpmtl 1 300 val
+pxqfxrmrvq 1 300 train
+pxqqrxpefh 1 300 train
+pxquvkikhd 0 300 train
+pxqvoaocjc 1 300 train
+pxqvtrlqpd 1 300 train
+pxqwixgavc 1 300 val
+pxqyxqcmhp 1 300 train
+pxraxbjqdk 1 300 val
+pxrfzilxji 1 240 train
+pxrhjlzird 0 300 val
+pxromamyke 1 300 train
+pxrxonthng 1 300 train
+pxrynvoctn 1 300 train
+pxshjbdlop 1 300 train
+pxskrvxbpv 1 241 train
+pxskzikenf 1 300 val
+pxsnwtbyuo 1 298 train
+pxstpntfik 0 300 val
+pxsxcohmkm 0 300 train
+pxsycerdgr 1 300 train
+pxtbggezxb 1 300 train
+pxtcqbkjxh 1 300 train
+pxtcygccjy 0 301 val
+pxtexyzpca 1 300 train
+pxtfzcgygo 1 300 train
+pxtmceyexo 1 300 train
+pxttaffhxj 1 298 train
+pxttorxdsz 1 300 train
+pxtwhbaxjq 0 300 train
+pxtzoehded 1 300 train
+pxubdynfdd 0 300 train
+pxugccqdyw 1 300 train
+pxumydsgqo 1 300 train
+pxuuntphvg 0 300 val
+pxuwgrhhsu 1 300 train
+pxuxgffpke 1 297 train
+pxvbhruceg 1 300 train
+pxvbjifcvg 1 299 test
+pxvfrpedgb 1 300 train
+pxvhejkhal 1 300 val
+pxvhtvzlhl 1 300 train
+pxvigtypiw 1 300 train
+pxvjtyewfr 0 300 train
+pxvsojeozk 1 300 train
+pxvtfvrmdd 1 269 train
+pxvxurfyuy 1 299 val
+pxwbdfwpis 1 300 val
+pxwfbwdwpf 1 300 train
+pxwgczivlv 1 300 train
+pxwhwijmwu 1 300 val
+pxwpztrghg 1 241 train
+pxwsxsqrxo 0 300 val
+pxwsyikzhk 1 300 train
+pxwxgvggyy 0 300 train
+pxxgfubfbq 1 300 val
+pxxguhagfn 1 301 val
+pxxiaiplbf 1 300 train
+pxxifkcwmi 1 300 train
+pxxopnfcws 1 300 val
+pxxovutfdk 0 300 val
+pxxplpktyu 0 300 train
+pxxqtafjkm 1 300 train
+pxxssjunne 1 300 train
+pxxuiipgyj 1 300 train
+pxxxrpahuy 1 300 val
+pxyagrehlm 0 300 train
+pxybdhuebe 0 300 train
+pxyhugggrw 1 301 train
+pxynifqxla 1 300 train
+pxyobrqczs 1 300 val
+pxzcnrmkqb 1 299 val
+pxzezkckui 1 300 train
+pxzhqmqcxd 1 300 val
+pxziqjbvav 1 300 train
+pxzomoqglb 0 300 train
+pxzpyqedjr 0 300 train
+pxzsjiielc 1 300 val
+pxzvashwaj 1 136 train
+pxzwyhbznd 0 300 train
+pyacwtagya 1 300 train
+pyadjhgwwg 1 300 train
+pyakbfrsrg 1 300 train
+pyaomnlesn 1 300 train
+pyatfykggq 1 300 train
+pyautqenin 1 301 val
+pybccybcre 1 301 train
+pyblvfivrb 1 300 train
+pybvlrezic 1 300 train
+pybzhyijuj 1 300 train
+pycazxlngs 1 300 train
+pycijresne 1 300 test
+pycmkonrip 1 300 train
+pycppejrvn 1 300 train
+pycsiiaegv 1 300 train
+pycyethsgf 1 99 train
+pydbvfkslp 1 299 val
+pyddtnougq 1 300 train
+pydepcohgy 1 300 train
+pydgkpxwui 1 300 train
+pydicxfaui 1 269 train
+pydldpbojl 1 298 train
+pydubklpub 0 300 val
+pydxemoazo 1 300 train
+pyekujrkdr 1 241 train
+pyeurwnxrm 1 300 train
+pyfdoezmny 1 300 train
+pyfefgwgbv 1 300 train
+pyfelgwsqz 1 300 train
+pyffhfjguz 1 300 train
+pyfhkjnvnj 1 300 val
+pyfrxgbrvy 1 300 train
+pyfrykmkax 1 300 train
+pyfsongfdl 1 300 train
+pyftcpudgj 1 300 train
+pyfvwrfjxx 1 300 train
+pygdxfxybc 1 299 val
+pygzpsiiir 1 299 val
+pyhdqhvfmi 1 300 train
+pyhhghgxvl 1 300 val
+pyhhvpyngr 1 300 val
+pyhizdvmlh 1 300 test
+pyhlmkqmkl 1 240 val
+pyhnclwgja 1 300 train
+pyhwajmxej 1 300 val
+pyhwnclaoi 1 300 train
+pyiazrtgdo 0 300 train
+pyicfuaoci 1 300 train
+pyiglawaxn 1 300 val
+pyigrfaqdk 1 301 val
+pyiknfgqnm 1 300 train
+pyiokgdmtn 1 300 train
+pyirqybluh 1 300 train
+pyiuwbshfp 0 300 train
+pyivwtgcrm 1 136 train
+pyizpldjtt 1 300 train
+pyjakvqnje 1 300 train
+pyjjdvbrtx 1 300 train
+pyjruevzip 1 298 train
+pykaqukcdj 1 300 train
+pykibtukcv 1 300 val
+pykjeuufie 0 300 val
+pykpkrhrsx 1 300 train
+pykqvcgxnw 1 300 val
+pykyigwsae 1 300 val
+pylfnyqpzt 1 300 train
+pylmelcbxb 1 300 train
+pylmlpcdas 1 300 val
+pylmqtgaqa 1 300 val
+pylnolwenx 0 300 train
+pylvfulqjd 1 300 train
+pylvroowzf 1 300 train
+pylwstofpv 1 300 train
+pylyqgcgrc 1 301 val
+pymgphyzhr 0 300 train
+pymmhbnuah 1 300 train
+pymszauioy 0 301 train
+pynldfzutf 1 300 train
+pyoajfcztr 0 298 train
+pyoercpbfp 1 300 train
+pyofawujfb 1 300 val
+pyogeyqhfl 1 241 train
+pyohkkismk 1 302 train
+pyoktlubkx 0 300 train
+pyomnllkvj 0 300 train
+pyoocmexws 0 300 train
+pyotdcocdp 1 300 val
+pyoxnqhzqq 1 300 train
+pyphimtais 1 300 train
+pypoimfydm 0 300 train
+pyppzflwvm 1 300 train
+pypuojcxmx 0 300 train
+pypxedrzav 1 300 train
+pypxrwqgaq 0 300 train
+pyqjzlzvko 1 300 train
+pyqsgndnrw 1 300 train
+pyqtbypnqg 1 300 train
+pyqyxeurrc 1 298 train
+pyrcjmefio 0 300 val
+pyrdmilads 1 300 train
+pyrfcanewv 1 300 train
+pyrhvfzopv 0 300 train
+pyriecynrt 1 300 train
+pyrllhzvyu 1 300 train
+pyrnlqpikr 1 300 train
+pyrrycctbs 1 241 train
+pysfhzxocc 1 300 train
+pysigszjgo 1 300 train
+pysjedccrf 1 300 train
+pyskazffta 1 300 train
+pyskxmbfpg 1 300 train
+pysprzjdii 1 300 train
+pysrzmolcv 1 300 train
+pytasbxgag 1 300 train
+pytfvdizyu 1 300 train
+pytjfyvstk 0 300 train
+pyttfccelg 0 300 val
+pytwpmkybn 0 301 train
+pytzixuhcj 1 300 train
+pyugwpidny 1 297 val
+pyujkxwaks 1 300 test
+pyujsaxume 1 300 train
+pyuptimtqb 0 300 train
+pyusookest 1 299 train
+pyuuehmsva 1 300 val
+pyuufqkdlk 1 300 val
+pyuwzxdvxp 1 300 train
+pyvmibpvuf 1 300 train
+pyvqkydhle 1 300 train
+pyvrjronhh 1 300 train
+pyvrvflide 1 301 train
+pyvukxabop 1 300 val
+pywkcnaknk 0 300 val
+pywlbwwfjn 1 300 train
+pywrgddeca 1 300 train
+pywweersld 1 300 train
+pywxdairkd 1 300 train
+pyxcmukmrv 1 300 train
+pyxhwbzyrg 1 300 train
+pyxizjlicm 1 241 train
+pyxkdrqrvg 1 300 train
+pyxvtgzlmh 1 300 train
+pyxycqbfne 1 300 train
+pyyaxsbbbp 1 300 train
+pyyduhakzc 1 300 val
+pyyfcvmmwh 1 300 train
+pyyfwmxzwn 1 300 train
+pyyhwtdpls 1 300 train
+pyymbotmkt 1 300 train
+pyypnunksp 0 300 train
+pyysctdofd 1 300 train
+pyyxxpegwi 0 300 val
+pyzepotmxt 1 300 train
+pyzgaiiyxu 1 300 train
+pyzhngmdxg 1 301 train
+pyzhzuztqm 1 300 train
+pyzlhybrth 0 300 train
+pyzpnlvtuf 1 300 train
+pyzuldgecn 1 300 train
+pyzvvschtr 0 300 train
+pyzwbwtpii 1 240 train
+pzafdvtdkm 1 300 val
+pzahbznjkk 1 300 val
+pzahcjixkg 1 300 train
+pzakekzhfi 1 300 train
+pzamxhibmn 1 302 train
+pzavvsvgcx 1 300 val
+pzbksnozia 1 300 train
+pzbljhvmge 1 300 train
+pzbpgfmroj 1 300 train
+pzbvvdccng 1 301 val
+pzbxiysdzt 1 300 train
+pzbxyooyeq 1 301 train
+pzcdutquno 1 300 train
+pzcglyxlwk 1 300 train
+pzckrglsvu 1 300 train
+pzcmgsmatm 1 300 train
+pzcqzgxoun 0 300 val
+pzcxyzdmiv 0 300 val
+pzddciqvlv 1 300 train
+pzdfwdnmyx 1 300 train
+pzdjflmdus 0 300 train
+pzdmbizzii 0 300 train
+pzdoevuzwv 1 300 val
+pzdpebciok 1 300 train
+pzdsiytket 0 300 train
+pzdtyjvvll 1 299 val
+pzdzczpiox 1 300 train
+pzebwxugkt 1 300 train
+pzebzpasgj 1 300 train
+pzecuoitxn 1 300 train
+pzecurkcxx 1 300 train
+pzefwcjqzr 1 300 val
+pzelfccoiu 1 300 train
+pzercnfmug 1 300 train
+pzevymunna 1 300 val
+pzfbwefhdc 1 300 train
+pzfcwlopqb 1 300 train
+pzfhcgandq 1 300 train
+pzfhfsydwy 0 300 train
+pzfmpubhjb 1 300 train
+pzfpgrwbgb 0 300 train
+pzgagecgnf 1 301 train
+pzgcgbulgl 1 301 train
+pzgdntfzno 1 298 train
+pzgeyymivj 1 300 train
+pzgjlhmtva 0 300 train
+pzgjnqkbhv 1 300 train
+pzgsrmdlvz 1 300 val
+pzhoqhdizu 1 300 val
+pzhpuuvyex 1 300 train
+pzhsscrccn 1 300 train
+pzhuxutuvi 1 299 val
+pziarhvygf 1 301 train
+pziftezdor 1 300 train
+pzimoyoury 1 300 train
+pzioltkmrj 1 300 train
+pzirdftiaz 1 300 train
+pziufroodg 1 300 train
+pziuwipjfm 1 241 train
+pzivjwhqov 1 300 val
+pzizprtwso 1 255 train
+pzjdhpvpys 0 300 train
+pzjryvkrpk 0 300 val
+pzjuqlbdnf 1 300 train
+pzjxvvumft 1 299 test
+pzjzulbhgl 1 298 train
+pzkchwafox 1 300 val
+pzkdefgfyc 0 300 train
+pzkdouathv 0 300 val
+pzkisgedux 0 300 train
+pzkmoyuvoh 1 288 train
+pzkoumfjrg 1 300 train
+pzkowyngkm 1 300 val
+pzkrainssc 1 300 train
+pzkteuwrpk 1 300 val
+pzktyzitwf 1 301 train
+pzkultibyi 1 300 train
+pzkvwtadta 0 300 val
+pzkwhewjpi 1 300 train
+pzlfxmbxdv 0 300 val
+pzliedxvvz 1 300 train
+pzliwprbii 0 299 val
+pzlkotrorp 1 300 train
+pzlnfgsbnx 1 300 train
+pzlpkxbigp 1 300 train
+pzlpudvjix 1 300 train
+pzlqlbruyf 1 300 train
+pzlrywlidi 1 302 train
+pzltkmutgm 1 299 train
+pzltoefehu 1 298 train
+pzlwkpdahw 1 300 val
+pzmfblsxrt 1 300 val
+pzmmdpmshf 1 300 train
+pzmoqduqjq 1 300 train
+pzmutdcadh 1 300 train
+pznghedtcx 1 300 train
+pznoxmtzbh 1 300 train
+pzntdswwjs 1 300 val
+pzocrmonpf 1 300 train
+pzocwlihge 1 300 val
+pzomelmnrp 1 300 train
+pzoqbkkbit 1 298 train
+pzowceokcd 0 300 train
+pzozhfkofr 1 298 train
+pzpcjqlfpk 0 300 train
+pzpcmdrocu 1 300 train
+pzpfiaxhor 1 300 val
+pzpjrxiepf 1 300 train
+pzpoynnlib 1 300 train
+pzpptibplh 1 300 train
+pzpqeeuchy 1 300 train
+pzpwphlnxu 1 300 train
+pzqaygzvjf 1 300 train
+pzqhthngpn 1 288 train
+pzqsdqdxhb 1 301 train
+pzqxcaetjv 1 300 train
+pzqxgrujyy 1 300 train
+pzqxrczvxb 1 300 val
+pzqxzikhwm 1 300 train
+pzrhmglghk 1 301 train
+pzribvqgrm 1 300 train
+pzrigrcqzv 0 300 train
+pzrkuvruxc 1 300 train
+pzropodbpk 1 300 train
+pzrtrvoigd 1 300 train
+pzrvfirsqj 1 300 train
+pzrwraqsyv 0 300 train
+pzslbxmxfw 1 300 train
+pzsocepgmv 0 300 train
+pzspgkvlll 1 300 val
+pzspkxtant 1 300 val
+pzsprkukia 1 300 val
+pzssykyqhv 1 300 train
+pzsuborsgk 0 300 train
+pzsxcaflwj 1 300 train
+pztbkrlqor 1 300 train
+pzteeuvujy 1 300 train
+pztxqnhvae 1 300 val
+pztyqnncle 1 298 train
+pzufavdbfv 1 300 val
+pzufkabvqa 1 299 val
+pzumrlxamm 1 300 train
+pzutzgcnbv 1 300 train
+pzuwsbuyqv 1 300 train
+pzvqmdizij 0 300 train
+pzvrzgvaks 1 300 train
+pzvsfsttsa 1 300 val
+pzvsluejic 1 240 train
+pzwlyqggah 1 300 val
+pzwnxjngva 1 300 train
+pzwoxlterv 1 300 train
+pzwqfnobtp 1 300 train
+pzwsysrpnj 1 300 test
+pzwtizynzc 1 300 train
+pzwzvfuqdm 1 300 train
+pzxfnkuwgd 0 300 val
+pzxhxjkbjl 0 300 train
+pzxleueqvr 1 300 train
+pzxlsfkipw 1 300 val
+pzxlvqmvql 1 300 train
+pzxmziiyrk 0 300 train
+pzxyxrzsax 1 300 train
+pzycnmhhfn 1 300 train
+pzyfqmmyxh 1 299 test
+pzygaqboct 1 300 train
+pzyhjedqpq 1 300 train
+pzykicgewh 1 300 train
+pzymesrkiw 0 300 train
+pzyunstlnx 0 300 train
+pzyzhtnurv 1 300 train
+pzzbhentbn 0 300 train
+pzzbxvjdcg 1 300 train
+pzzhudpjlo 1 300 train
+pzznppagla 1 300 val
+pzzrcsfrtq 1 299 test
+pzzsoygjrt 0 300 train
+pzzuimgwei 1 300 test
+pzzwoskbbp 1 300 train
+pzzzekfocy 1 300 train
+qaactlmcul 1 300 train
+qaacvxxgaq 1 300 train
+qaaljoehxg 1 300 train
+qaankaakfw 1 300 train
+qaaqqeklux 0 300 train
+qaayoyasrs 0 300 train
+qabasbfbvq 1 300 train
+qabiffosed 1 300 val
+qabimlgdtc 1 301 train
+qabkhtwkec 1 300 val
+qablpysmuq 0 300 train
+qabpbodvcg 1 300 train
+qabqakntpo 1 241 train
+qabreprhxg 0 300 val
+qabugzivdh 1 300 val
+qabuymqudn 1 301 train
+qabyhuewjv 1 298 train
+qaccjuutkr 1 300 val
+qacdnclndl 1 300 train
+qacriikvff 1 300 train
+qacskiibcp 1 300 val
+qacvhhqluv 0 300 train
+qacvrhuglh 1 297 val
+qacyhfxtyz 1 300 train
+qadbnbiycj 1 300 train
+qaddmzepko 0 300 train
+qadiozyirg 1 300 train
+qadiwadjzf 1 300 train
+qadjptxmws 1 300 train
+qadjshhikn 1 300 val
+qadqzqlgcf 1 299 test
+qadvldcecp 1 300 train
+qadwnwxxcv 1 299 val
+qaedmapjyv 1 301 train
+qaehvzuaga 0 300 train
+qaejtaqspn 0 300 train
+qaemextuyi 1 300 train
+qaeqahfvja 1 298 train
+qaetdhiuwm 1 300 train
+qafakioflg 1 300 train
+qafmbpxygc 1 301 val
+qagdamakmt 0 300 train
+qagitrexta 0 300 train
+qagonymubk 1 300 train
+qagvwkahbt 0 300 train
+qagxvohvxo 1 300 train
+qagzbnldcu 1 301 train
+qahafsxfce 1 300 train
+qahcgiiddc 1 300 train
+qahcngjhej 1 300 train
+qahgyczoze 1 301 train
+qahixmadzr 1 300 train
+qahkdeyvnf 1 240 train
+qahmjcobin 0 298 val
+qahqmfanfr 1 300 train
+qahtfludkl 1 300 val
+qaicgyflnw 1 300 train
+qaicktgxsq 1 300 train
+qaihxszzod 1 300 train
+qaimindcap 1 301 val
+qaiozzeueb 1 300 train
+qaitolgfpi 0 300 train
+qaizpjityn 1 300 train
+qajemupvld 1 300 train
+qajfhljzre 1 300 train
+qajiyobrtr 1 300 train
+qajjqlqimm 1 300 val
+qajldfonyi 1 300 train
+qajofxldjm 0 300 train
+qajuyojvdd 1 300 val
+qajvbvmsyx 0 300 train
+qajyqferyy 1 300 train
+qakawyiuci 1 300 train
+qakdnzxzfi 1 300 train
+qakejlwwve 1 300 train
+qakelecikv 1 300 train
+qakilppebo 1 300 train
+qaknxageki 0 300 train
+qakowhpqlm 0 300 val
+qakprhrdpo 0 300 train
+qakpzhhcgp 1 300 train
+qakyqobzcl 1 300 train
+qalehnebou 1 300 val
+qalfxhcyun 1 302 train
+qalidvxrjo 0 301 train
+qalmltlbad 1 300 val
+qaltdjnrbd 0 300 train
+qaltnoczta 0 300 train
+qalypuyyuw 1 300 train
+qalzvxpkea 1 300 train
+qalzzdwwpp 1 300 train
+qambfuuviy 1 300 train
+qambtseykx 1 301 train
+qamnnzfaso 1 300 train
+qamskblnuz 1 300 train
+qanhjfvdar 1 300 train
+qanpwofprw 1 601 train
+qanupcllau 1 300 val
+qaoevtvccu 1 300 train
+qaojhmwxnh 0 300 train
+qaooedqhzc 1 298 val
+qaoxmcakyq 1 300 train
+qaoyiujvot 1 300 train
+qaozfttguh 1 300 train
+qapfbyxxxz 1 241 train
+qapltwpoug 1 288 train
+qapnbtdypb 0 300 train
+qapwbtkssg 1 300 train
+qapzukzocc 1 300 train
+qaqbdgmbea 1 300 val
+qaqcgthfea 0 300 train
+qaqeyfsjzt 0 167 train
+qaqisumcgw 1 300 train
+qaqmyriyqw 1 301 val
+qaqselfmvk 1 300 train
+qarbtmjwhm 1 300 train
+qarnjijetz 1 300 val
+qarpewfwec 0 300 train
+qarpynklhz 1 300 val
+qarqtkvgby 0 300 test
+qarwqwtpbl 1 300 train
+qasdxczbbq 1 300 val
+qasegxokhd 1 300 train
+qasptbtcyf 1 300 train
+qassiadisq 1 301 val
+qasuvdzvve 0 300 train
+qasyncralw 1 99 train
+qateunrlfb 1 300 train
+qathnxbqyg 1 300 train
+qatpflatwm 1 300 train
+qatqdgvqlv 1 300 train
+qatxeqhtec 1 300 train
+qaubhdsftl 1 300 train
+qaudxfmaih 1 300 train
+qaugcsknos 1 301 train
+qaulojkrjl 1 300 train
+qauptousmh 1 300 train
+qaurwlbpuk 1 300 train
+qausgxlesa 1 300 train
+qauvunegtk 1 300 val
+qauxtdfmpg 1 300 train
+qauypppugu 1 300 train
+qavfnunwko 1 300 train
+qavkaanptn 1 300 train
+qavmygtuwp 1 302 train
+qavohtomni 1 300 train
+qavopmteyk 1 300 train
+qavpbkhhnd 1 300 train
+qavplwpgaq 1 300 train
+qavsxnpgyk 1 300 train
+qavthobolt 1 298 train
+qavtqtsrka 1 299 train
+qavvoguryv 0 300 train
+qavxwrowsr 1 300 train
+qawbfjnakn 1 300 train
+qawbflilul 0 300 val
+qawcrdqhzm 1 300 train
+qawfrjdwud 0 300 train
+qawgpkpizv 1 300 train
+qawhqaraxg 1 300 train
+qawlzyeanh 1 300 train
+qawqquinvi 1 301 train
+qawrphpowc 1 300 train
+qawwancemn 1 299 train
+qawxksvzgg 0 300 train
+qawzmmogfi 1 300 train
+qawzsfefqs 1 300 train
+qaxeaodetm 1 300 val
+qaxemihkhx 1 300 train
+qaxgscubjl 1 300 train
+qaxiumarxz 1 300 train
+qaxktxyrkq 1 300 val
+qaxlixhfjr 1 300 train
+qaxvviirsh 1 300 train
+qaxxbuqynr 1 301 val
+qayauexvxs 1 300 train
+qayaypesdv 1 300 val
+qaydrxmkyy 0 300 val
+qayduodvkj 1 300 train
+qayfduhgrg 1 300 train
+qayflmehei 0 300 val
+qaykajuehl 0 300 train
+qaymboiwnh 1 300 train
+qaynucyryk 1 134 train
+qaysmkugbl 1 300 train
+qayupdvjps 1 300 train
+qazfxgpwoz 1 298 train
+qazgpjuxaf 1 167 train
+qazhafeotq 1 300 train
+qazhiwtzxx 1 300 train
+qazigkzejf 1 300 train
+qazjesxsez 1 300 train
+qazliewpdc 1 300 train
+qazoxlmqwq 0 300 train
+qazsmxyqru 0 300 train
+qazxcjelwv 1 300 train
+qazyugjnac 1 300 train
+qazzhddotd 1 300 train
+qbaedqcork 1 99 train
+qbaezlvfyf 0 300 train
+qbafcuzlra 1 300 train
+qbafljpfhw 1 300 train
+qbaqcltmfw 1 299 test
+qbatdzuagw 1 300 val
+qbavhwffiv 1 300 train
+qbazbfwwfr 0 300 train
+qbbfmjxrky 1 300 train
+qbbrkxhoio 1 300 train
+qbbxoavbkn 1 300 train
+qbcbyraqss 1 300 train
+qbcfkasycp 0 300 train
+qbcicoxbre 1 300 train
+qbclqicpvo 1 300 train
+qbcltiyjqg 1 300 train
+qbcqkzqvsm 1 300 train
+qbcqqpfiio 1 300 train
+qbctjxuzop 1 300 train
+qbctkzubvk 0 298 train
+qbctptvuka 1 300 train
+qbcwxidpbe 1 300 train
+qbdcyvbwgt 1 300 val
+qbeagpoffg 1 300 train
+qbeappuocx 1 300 train
+qbearsyziz 0 300 train
+qbeejihtgw 1 301 val
+qbenzjrmys 1 300 train
+qbeoexrvhg 1 300 train
+qbepeomeah 1 300 train
+qbewiycpda 1 300 train
+qbfdtumuct 1 300 train
+qbfeehccgm 0 300 train
+qbffpkpmkf 1 300 train
+qbfhyplyxi 1 300 val
+qbfxidkjyc 1 300 train
+qbfxwbmzvn 1 300 train
+qbgbbhwubk 1 300 train
+qbgcdjndjv 1 300 train
+qbgegquhcv 1 300 train
+qbgtrswilz 1 300 val
+qbgxbcbdsy 1 300 train
+qbgxteuxcm 1 300 train
+qbgxujaprf 1 300 val
+qbgziwaytb 1 300 train
+qbhatcqjeb 0 301 train
+qbheuriuph 1 300 train
+qbhoufagsa 1 301 train
+qbhqkhyhzs 1 300 train
+qbhqvurazh 0 301 train
+qbhwgtoxtw 0 300 train
+qbhwlloqtk 1 300 train
+qbhxdesvnu 1 300 train
+qbiauhajds 1 300 val
+qbibxjqica 1 300 train
+qbicjqwqvn 0 301 train
+qbickdrspc 1 300 train
+qbievnxvpk 0 300 train
+qbigcxlref 1 300 train
+qbincplcvg 1 300 train
+qbiqbalfjw 0 300 train
+qbitwemclz 1 300 train
+qbiuqqayss 1 300 val
+qbiztrxhkl 1 296 train
+qbjdtscers 0 300 train
+qbjflowsot 1 301 train
+qbjjkwellp 1 294 train
+qbjkfyxndy 1 300 train
+qbjntjytmt 0 300 train
+qbjompsooo 1 300 train
+qbjplyzhtg 1 300 train
+qbjrwksdxt 1 300 train
+qbkiiitkni 1 300 train
+qbkmhgoirz 1 300 train
+qbkmqbqklc 1 300 train
+qbktkqpxpg 1 300 train
+qbkzflbjmg 1 300 train
+qblfuddfpf 1 300 val
+qblixmliay 1 300 train
+qbljrttfbv 1 300 val
+qblllkjjbx 1 300 val
+qblzitowmd 1 298 train
+qbmegadgdi 1 300 train
+qbmfahfsjf 0 300 train
+qbmibamish 1 241 train
+qbmpfmhddr 1 301 val
+qbmrcveaty 1 300 val
+qbmsseaffx 1 298 train
+qbmtskqwos 1 300 train
+qbmypojdyi 1 300 val
+qbnveglmgs 1 300 train
+qboebijfdo 1 302 val
+qbolqxeymc 1 300 train
+qbopltyhph 1 241 train
+qboupinbkg 1 300 train
+qboxvhjwkv 1 300 val
+qbpaxeuhzz 1 300 train
+qbpeldzoli 1 301 train
+qbpxgmfkgp 1 300 val
+qbpzwkhkng 1 298 val
+qbqgrqzqir 1 300 train
+qbqimiiqil 1 300 train
+qbqiripjiw 1 300 val
+qbqkqqmapt 1 298 train
+qbqpmnxlzo 1 300 train
+qbqtdvvvvh 1 300 train
+qbqydqdrxz 1 300 train
+qbrbjnguaq 1 300 train
+qbrhnfuqik 0 300 train
+qbricanvor 1 300 train
+qbrqomfafq 1 300 val
+qbrqxwauto 1 300 train
+qbrspkkntl 1 300 val
+qbrugtuuqo 1 300 train
+qbruydwzcc 0 300 train
+qbruzfywhk 1 300 train
+qbrwttszvd 1 300 train
+qbrydvysxr 0 300 train
+qbrzztsnmb 1 300 train
+qbsdcifxsh 1 300 train
+qbsdjkabhx 1 300 train
+qbspardptp 1 299 train
+qbspgynfev 0 300 train
+qbswxkvlzf 1 300 train
+qbtaywnova 1 300 train
+qbtckkvnap 1 241 train
+qbtlkurrwh 1 300 train
+qbtmzaucmt 1 300 train
+qbtogciltz 1 300 test
+qbtqsiupbp 1 302 train
+qbtwwoiotm 1 300 train
+qbueqfyixe 1 296 train
+qbuhzfkjvj 1 300 val
+qbuifwjeya 1 300 train
+qbukeztlrm 1 300 train
+qbukkfjscz 1 300 train
+qbuvkjniiu 1 300 train
+qbuvslghcc 1 301 val
+qbvaqbiwvh 1 297 val
+qbvtaqopnh 1 301 train
+qbwgzkomsh 0 239 train
+qbwjxylrnj 0 300 train
+qbwkcbtvdi 1 300 train
+qbwmzlyqkk 0 300 train
+qbwogsfwmm 1 300 train
+qbwwpvgyhh 0 288 train
+qbwxbjhaep 1 300 train
+qbwxjdzjra 1 300 val
+qbwzfmddmg 1 300 train
+qbxbcffsai 1 300 train
+qbxdkocqaq 1 300 test
+qbxmrfmazf 1 300 train
+qbxpyhzacb 0 300 train
+qbxtgiikpc 0 300 train
+qbxtodatnt 1 301 train
+qbybdqzpfz 1 302 train
+qbygrzcpev 1 300 train
+qbyizszgvw 1 300 train
+qbymswegth 1 300 train
+qbysbsszfy 1 300 train
+qbywcaojhy 1 241 train
+qbzjjvbybm 1 147 train
+qbzlvljdge 1 300 val
+qbzsfwwciq 1 300 train
+qcabzbzpbr 1 241 train
+qcagzqgrob 1 300 train
+qcakjqbslu 1 300 val
+qcarktkmfw 1 300 val
+qcauximmlr 1 301 val
+qcaxjegmms 0 300 train
+qcbbixyego 0 300 train
+qcbcypifeo 1 301 train
+qcbgpehmrh 1 300 train
+qcbhpzipjj 1 300 train
+qcbjskiqhc 1 300 train
+qcbkztamqc 1 300 test
+qcbmzucdkb 1 300 train
+qcbrbselom 1 241 val
+qcbyvitkgx 1 300 train
+qcccdaicit 1 300 train
+qccdzhepbo 1 300 train
+qcciietoau 1 300 val
+qcciqakhhx 1 300 train
+qcckddiriz 1 300 train
+qccllvprho 1 300 train
+qccyrzyylf 0 301 train
+qccztbjauc 1 300 train
+qcddeigxhq 1 300 train
+qcdfrnydvr 1 300 train
+qcegcfcazb 0 300 train
+qcemrfnege 1 298 train
+qcenayroih 1 302 train
+qceqxoeuhv 1 300 train
+qcewpdldym 1 300 val
+qcfaclnzfu 1 300 train
+qcfjhtckhd 1 300 train
+qcfjnrvukm 1 300 train
+qcftbnynor 1 300 train
+qcfviarsic 1 300 train
+qcfwiogzgu 1 300 train
+qcgodnafwo 1 300 train
+qcgtqnatxp 0 301 train
+qcgtwpyxth 0 300 train
+qcguerhcsl 1 300 train
+qcgvjxtvev 1 241 train
+qcgwmbhxrf 1 301 train
+qcgyxmuvpi 1 300 train
+qcgzyvlaqk 1 300 train
+qchcfdisuo 0 300 train
+qchdyrlogx 1 300 val
+qchglbhjlr 0 300 train
+qchgluoajg 0 269 train
+qchlieqmgx 1 300 train
+qchlvnlvbq 0 300 train
+qchmkcjlwi 1 300 train
+qchydkncfx 1 300 train
+qciaozmrjj 1 300 train
+qcigzolsmv 1 300 train
+qcijdjhhgd 1 300 train
+qcijzqxfrm 1 300 val
+qcimqovmvo 1 300 train
+qcinzstvzy 1 300 test
+qcisdurnzt 1 300 train
+qcjddzgxuo 1 300 train
+qcjgabgrmm 1 300 train
+qcjntslwao 1 300 val
+qcjwsygnxe 1 300 test
+qckawgxxme 1 300 train
+qckdcytetj 1 300 train
+qckgsogoli 1 300 train
+qckjihxoze 1 300 train
+qckndouuwc 0 301 train
+qcknvfndam 1 298 train
+qckonxvveg 1 301 train
+qckpcqitnd 1 300 train
+qcksscwvkm 1 300 train
+qckwfjyoqq 1 297 train
+qclgfxjqxv 1 300 train
+qclhbfpyzh 1 300 train
+qclpbcbgeq 0 300 test
+qclxjhdxwy 1 300 train
+qclxwzxhxw 1 300 train
+qclycbpjqu 1 298 train
+qclytvnchv 1 300 train
+qcmhohwoni 1 300 train
+qcmmdedmfx 1 301 train
+qcmpjhmsuf 1 300 test
+qcmpzewwto 1 300 train
+qcmqhyrdff 1 300 train
+qcmwlfhpdy 1 300 train
+qcmwxpsxwp 1 300 train
+qcnbbxhbxx 1 300 train
+qcnbifmlvf 1 300 train
+qcnbrwmhyg 1 300 train
+qcnipswqyi 1 300 train
+qcnjnwebtv 1 300 train
+qcnjqaeoyy 1 300 val
+qcnkgyvxnj 0 302 train
+qcnosqhgcs 1 300 train
+qcnsahyrvi 1 300 test
+qcnxqwcveq 1 300 val
+qcnzvebzip 1 300 train
+qcocjxdoor 1 300 train
+qcofcfboyd 1 241 train
+qcohlfrfzb 0 300 train
+qcoiimlwmq 1 299 test
+qcolxecfxr 1 300 train
+qconrwcsqu 1 300 val
+qcoswscyff 1 300 train
+qcpbapccjf 1 300 train
+qcpbbtzyvm 1 300 train
+qcpmwobtsi 1 300 train
+qcpnnqzslq 1 300 train
+qcppqcosbq 0 300 train
+qcqbzfczbs 1 300 train
+qcqduqlzgl 0 300 train
+qcqlhreopt 1 300 train
+qcqqrmxiwe 1 298 train
+qcqzjeecqo 1 300 train
+qcrchecdto 1 300 train
+qcrkeithwj 1 301 train
+qcrofjquht 1 300 val
+qcromzecju 1 301 train
+qcroujlnlz 1 300 train
+qcrpmdwizz 1 299 val
+qcrqpfsepo 1 300 train
+qcrrlmsbxe 1 300 train
+qcrrqvzult 1 300 train
+qcrrxqomya 0 300 train
+qcsfyfuibd 0 300 train
+qcshdjmmyn 1 299 val
+qcsmctqcdx 1 300 train
+qcsnqtbhga 0 300 train
+qcsslegxho 0 300 val
+qcsuzqqohv 1 300 test
+qctagnsnqa 1 300 train
+qctcumfqty 1 300 test
+qctdmbxpkl 1 300 train
+qctfnmumnz 1 300 val
+qctfpvkjeq 1 297 val
+qctntszyuq 1 301 train
+qctpzulzfb 1 302 train
+qctwmqwixb 1 300 train
+qctzpmzrmm 0 300 train
+qctzubdnke 1 299 test
+qcucdrolwk 1 300 train
+qcucmqepde 1 300 train
+qcufxavgti 1 300 val
+qcugsjsuzt 1 300 train
+qcuobsfbgz 1 300 train
+qcuqbqrfet 1 300 train
+qcusoawsce 1 300 train
+qcusznoptm 1 300 train
+qcvaewqluc 1 299 val
+qcvaivxnpj 1 300 train
+qcvbxjvwui 1 299 val
+qcvctfwlam 1 300 train
+qcvfnunaii 1 300 train
+qcvxqjcjop 1 300 train
+qcvyclhhuq 1 300 train
+qcwfsrlbwp 1 300 train
+qcwfxjoktn 1 300 train
+qcwguuumkb 1 300 train
+qcwhkhxsxp 1 300 train
+qcwicuoutm 1 300 train
+qcwnjxtwkx 1 300 val
+qcwotrrgbf 1 300 train
+qcwubobffx 1 300 train
+qcwwcdckwo 1 301 val
+qcwxkavpma 1 300 train
+qcwxyaedgo 1 300 val
+qcwynifwtv 1 300 train
+qcwztcyolx 1 300 val
+qcxkxcemcb 1 300 test
+qcxkzxksxm 1 301 train
+qcxmaefecu 1 300 val
+qcxmjcuvls 1 300 train
+qcxqsfretg 1 300 train
+qcxsfsrcgx 1 241 train
+qcxtsddkbt 0 300 val
+qcxwcqhzgd 1 300 train
+qcybxocopd 1 239 val
+qcyggexcva 1 301 train
+qcyikdnpcz 1 299 train
+qcyjmpqqau 1 298 train
+qcyjwpyzre 1 300 train
+qcykxlusqr 1 298 train
+qcyrdgigaj 1 300 train
+qcytuqvxym 1 300 train
+qcyvmkzmkn 1 300 train
+qczafofnsv 1 300 train
+qczbbylumq 1 300 val
+qczfrfkhxp 1 300 train
+qczjnkzuds 1 300 train
+qdabqsxuwy 1 299 val
+qdadlhpnjn 1 300 train
+qdaefntzbm 1 300 train
+qdagttotgb 1 301 val
+qdagzcsgyj 1 300 train
+qdahcroyxh 1 300 val
+qdalidxckj 1 300 train
+qdamwtliks 0 300 train
+qdanomggxf 1 301 train
+qdantvtdji 0 300 train
+qdapzenpcn 1 300 train
+qdasygvnms 1 300 train
+qdatmkjpel 1 300 train
+qdbaiciceo 1 300 train
+qdbiwougrn 0 300 train
+qdbolnetao 1 301 train
+qdbqecwwsr 1 300 val
+qdchvtrjnx 1 300 train
+qdcizgkyvh 0 300 train
+qdcrekhngu 1 300 train
+qdctvtvvhu 1 300 train
+qdcvavoeza 1 300 train
+qdcvosbeul 0 300 train
+qdcxmiebmn 0 300 train
+qdcxpoyoib 1 300 val
+qdcytygejy 0 300 train
+qddeclhfde 1 300 train
+qddgokzhtm 1 298 train
+qddptxyuis 1 300 train
+qddtfmurxi 1 299 train
+qddycmeefa 1 300 train
+qdeavaxwfd 1 300 train
+qdeddghxvf 1 300 val
+qdedmpcthy 0 300 train
+qdedumithq 1 300 train
+qdefejdnni 1 300 train
+qdehcalinw 1 300 train
+qdeihfefcn 1 300 val
+qdeiiltkpb 1 300 train
+qdeizenkjk 0 300 train
+qdemtherbw 1 300 train
+qdeoczzuri 1 300 train
+qdeoocmxki 1 300 train
+qdewvfdqes 1 300 train
+qdfagbjuis 1 300 train
+qdfgiyanke 1 298 train
+qdfijwelsj 1 300 train
+qdfmiqozpn 0 300 train
+qdfoiguwaf 1 300 test
+qdfvvckune 1 269 train
+qdgiiuzjdb 1 300 train
+qdgisabgve 1 300 train
+qdgkxwjeuw 1 300 train
+qdgpigaalp 1 299 test
+qdgrrfeazr 0 300 train
+qdgxsfkqiu 1 300 val
+qdgxsgkxdr 1 300 val
+qdhcklxqhv 1 300 train
+qdhdnmrgkf 1 300 val
+qdhkyhriqi 1 299 val
+qdhloyonpq 1 300 train
+qdhvwtdiay 1 297 train
+qdhzxxckjo 0 300 train
+qdiclkoxze 0 100 train
+qdijdyiutg 1 300 train
+qdilwzelwp 1 300 val
+qdirksoqim 0 300 train
+qdiufdxior 1 300 train
+qdjdzkhnnk 1 300 train
+qdjfbfqwau 1 301 train
+qdjgpdlcfd 1 300 train
+qdjkbhhkch 1 300 train
+qdjrghdsss 1 300 val
+qdjrihdsra 0 300 val
+qdjrsyyvyd 1 300 train
+qdjtietmjx 1 300 train
+qdjuznbtxf 1 301 train
+qdjwgsjrml 1 300 train
+qdjxabkqsu 1 300 train
+qdkcjwbzek 1 300 train
+qdkdmwybuk 1 301 train
+qdkjdzvoes 0 300 train
+qdkkmvsjnv 1 300 train
+qdklyiwwrq 1 300 train
+qdkpphviay 1 300 train
+qdkqbcvbhx 1 300 train
+qdktnsxljc 0 300 train
+qdlefybhht 0 298 train
+qdlrznczud 1 300 train
+qdmfeengfz 1 300 train
+qdmkmfomas 1 300 train
+qdmlbvbqjr 1 300 train
+qdmmbyksot 1 300 val
+qdmmrcurog 1 300 train
+qdmvzknbua 0 300 train
+qdmziefhyk 1 302 train
+qdnbunubas 1 301 val
+qdnfwzurgi 1 300 train
+qdngiuorvs 1 300 train
+qdngwwhqhr 1 300 train
+qdnivjptrz 1 301 train
+qdnjnohbiy 1 300 train
+qdnwdedkrk 1 300 train
+qdnzagjlcv 0 301 train
+qdoeusvajh 0 300 train
+qdofrrdnim 0 300 train
+qdogpgieqw 1 300 test
+qdomnebwdz 1 300 val
+qdonjyzgxn 1 300 train
+qdonojiofl 1 301 train
+qdovkhjhgp 1 300 train
+qdowedxida 1 300 val
+qdpkezyqib 1 300 train
+qdpllbwuck 1 300 train
+qdpsfnrtiq 1 300 train
+qdptbhikbg 1 301 val
+qdpwadxiuw 1 300 train
+qdqaqufmft 1 300 train
+qdqbgaselz 1 300 train
+qdqdsaiitt 1 300 test
+qdqfugivnx 1 300 train
+qdqgwpnhur 1 300 val
+qdqopybovr 1 300 train
+qdqtawtkdo 1 300 train
+qdrdrwcani 1 299 train
+qdrjugpyhy 1 300 test
+qdrkucwghz 1 300 train
+qdrurqesar 1 300 train
+qdscynormj 0 301 val
+qdsemavzrz 1 300 train
+qdskxicgas 0 300 train
+qdsmgemzbh 1 298 train
+qdsoatwrfm 1 300 train
+qdsrgrrfki 1 300 train
+qdsrylqbpr 1 300 train
+qdssobwcxv 1 300 train
+qdszbldxrq 1 300 train
+qdtarwtswk 1 300 train
+qdtcxywgnm 1 300 val
+qdtdrgztgu 0 300 train
+qdtgqujwjj 1 300 val
+qdtjdlzsqq 1 300 val
+qdtsfjcrok 1 300 train
+qdtsrvticn 1 300 train
+qduehswbjt 1 301 val
+qdulrallpz 1 298 val
+qdumndmniy 1 300 train
+qdusrefisl 1 301 val
+qduukqkozh 1 300 train
+qduwslhkom 1 300 train
+qdvaogedny 1 300 val
+qdvcaecfwo 1 300 train
+qdvfqrxkac 1 300 val
+qdvhfjeseu 1 300 train
+qdvimwzjka 1 300 val
+qdvksyerxb 1 301 val
+qdvkuwavxh 0 300 train
+qdvnqmskzw 1 300 train
+qdvwtjmpzd 1 301 train
+qdvygqhbel 1 300 train
+qdvzaxpbbc 1 300 train
+qdvzovpzxz 1 300 train
+qdwbxkqsyd 1 299 val
+qdwcydrmpl 0 300 train
+qdwoqilpwf 1 300 val
+qdwudkptxp 0 300 train
+qdwuhbpvep 1 300 train
+qdwvvoimhk 1 300 train
+qdxbeysqef 1 300 train
+qdxedafoiq 1 300 val
+qdxgpisunq 1 99 train
+qdxmxypccp 1 300 val
+qdykxkafki 0 300 train
+qdyreokdxz 1 300 train
+qdytgvitjm 1 300 val
+qdzadbpiod 0 300 val
+qdzbtimfmf 1 297 val
+qdzlaqopsf 1 300 val
+qdzpltwlof 1 300 train
+qdzpsueudu 1 300 train
+qdzpvshylg 1 300 train
+qdzqkqxstc 1 300 train
+qdztqzjndd 1 300 train
+qdzwfutwtr 1 301 train
+qeadoprquq 1 300 train
+qeaenmeqch 1 300 train
+qeaidqxbcr 1 300 train
+qeamgtnnsf 1 300 train
+qeapomuzvr 1 300 val
+qeaptjerog 1 300 train
+qeaxtxpvyq 1 300 test
+qeazdknzss 0 300 val
+qebckdodmc 0 300 train
+qebkcpyefz 1 300 train
+qebmjazeky 1 300 train
+qebmvcnrci 1 300 train
+qebpsryhmk 0 300 train
+qebvcnhbej 0 300 train
+qecgeqnvta 1 300 train
+qechlfmdtv 1 299 train
+qeclzbbqan 1 300 train
+qecngoxudb 1 300 train
+qedcylqyod 1 300 train
+qedisiyorp 1 298 train
+qedkgyebad 1 301 val
+qedogjvglv 1 300 train
+qedqcparat 1 300 train
+qedrmmjzgo 0 300 train
+qedsgieuqn 0 300 train
+qedweideez 0 300 train
+qedxernyvg 1 300 train
+qeeeralsay 1 300 train
+qeefkatpus 1 299 train
+qeefpaarrl 1 298 train
+qeehyzgisi 1 300 train
+qeeqexmorg 1 300 train
+qefjahzqjx 0 300 train
+qefmxjllxx 1 301 train
+qefpqclgyw 0 300 val
+qefqgbtfhk 0 301 val
+qefrgzlcfm 1 300 train
+qegjobljzo 1 300 train
+qegmssagyr 1 300 train
+qegnidgfdh 1 300 val
+qegspyzueh 1 300 train
+qegsyxifws 1 300 val
+qegxloociq 1 300 train
+qehbnhaaob 1 300 val
+qehekvzpko 1 300 train
+qehfmglquk 1 300 train
+qehhvbqcqb 1 300 train
+qehjebtcnd 1 300 train
+qehuvzvqqg 1 299 train
+qehxxibphk 1 298 train
+qeiajsrnsf 1 300 train
+qeiavjqjhn 1 300 train
+qeicjrsrou 1 300 train
+qeidrdoowl 1 300 train
+qeihozmlzy 1 300 train
+qeiieirdew 1 300 train
+qeiilycvtd 0 300 train
+qeisrntpof 0 300 val
+qeixbflvlm 1 302 train
+qejatnitfa 1 301 val
+qejaxtxuqb 1 300 train
+qejbkgrhhc 1 300 train
+qejbogbmwp 1 300 train
+qejcjbqktv 1 300 train
+qejdameern 1 301 train
+qejdhlinqb 1 300 train
+qejmjsetgd 1 300 train
+qejnfvzozc 1 301 val
+qejqaitidi 1 300 val
+qejykotkmu 1 300 train
+qekehrobys 1 300 train
+qeksmemriz 0 300 train
+qekttcqtpm 1 301 train
+qekucblmnn 1 299 test
+qeldlwllvu 1 301 val
+qeldxuikby 1 300 train
+qelebriybu 1 300 train
+qeliekmpgw 0 300 val
+qeliwabvll 1 300 train
+qelkostpnn 1 298 train
+qelncdmypn 0 300 train
+qelnerqher 1 300 val
+qelvdjuonf 0 300 val
+qelvshsgnv 1 300 val
+qelwnkpmlf 1 300 train
+qelyibfked 1 300 train
+qemdkwwbrt 1 300 train
+qemibopbwn 1 301 train
+qemmyefgtu 1 300 train
+qemnbegrho 1 299 train
+qemsqijsia 1 300 train
+qemtpanxez 1 300 train
+qemtxrlujo 1 300 train
+qemuphggwx 1 300 train
+qemzklmumc 0 301 val
+qenfcfpnyu 1 300 train
+qengnxaujw 1 300 train
+qenhgiioxg 1 300 train
+qenmgitlwr 1 300 train
+qentasnpvu 1 300 train
+qenxlqqzvi 0 300 train
+qenyjosekb 1 300 val
+qeogpsbavh 1 301 val
+qeohiqsvtr 1 300 train
+qeoiaopota 1 300 train
+qeojeoulrw 1 300 train
+qeomvnbhqk 1 240 val
+qeoorfcnln 0 300 train
+qeopftwnwe 0 300 train
+qeozopebix 1 300 train
+qepgiaxgpc 1 300 train
+qepkrnfibo 1 300 val
+qeplzsixvj 1 300 train
+qepoibkeoq 1 299 train
+qepouweoaa 0 300 train
+qepurfmlnj 1 300 train
+qepydkyjsp 1 300 train
+qeqhrejxbu 1 300 train
+qeqirjftzj 1 300 train
+qeqismarzh 1 136 train
+qeqkgnbacl 1 300 train
+qeqleurpmu 1 299 val
+qeqmjjnojg 1 300 val
+qeqrppouwj 1 300 train
+qeqwigwfho 1 300 train
+qerdwvoopp 0 300 train
+qerezhdujr 1 300 val
+qerfvwacdh 1 300 train
+qergvpdkpq 1 300 val
+qerhciumgk 1 301 train
+qerpuyfhef 1 300 train
+qersvgvzxy 1 301 train
+qertpzqryh 1 299 val
+qervyeodfw 1 300 train
+qerwrumvqe 1 300 train
+qerzuiktae 1 300 train
+qesblsqjmd 1 300 train
+qesiggdoxo 1 300 train
+qesjxqvzce 1 298 train
+qesmxvzqug 1 300 val
+qesnaogado 1 298 train
+qesomwbpii 1 300 train
+qesrvvmpvm 1 300 train
+qesshfuked 1 300 val
+qeswxeeizh 1 301 train
+qetbbevrhn 1 300 train
+qetboljnzl 0 300 val
+qetcosphde 1 300 train
+qetenneagd 1 300 train
+qethauxnwk 0 300 train
+qetspshozl 1 300 train
+qeuemnaocl 1 298 train
+qeuhipxcaz 1 300 val
+qeuiugjhqg 0 300 train
+qeulyguklg 1 296 val
+qeumxirsme 0 300 train
+qeurndelvm 0 300 train
+qevxadpcmq 1 300 train
+qewhficabz 1 300 train
+qewjikijzh 1 300 train
+qewmbrrtay 1 300 train
+qewqnjgauj 1 300 train
+qewxqkzxci 1 298 train
+qexbrbnpvk 1 300 train
+qexfqixxvo 1 298 train
+qexgjiiepq 1 301 train
+qexywkebun 1 300 train
+qeyanjfztf 1 300 train
+qeybglsiyp 1 300 val
+qeydkmdzam 1 300 val
+qeyfuwvgry 0 301 train
+qeyheaxmpv 1 241 train
+qeysxtnltj 1 300 train
+qezaswxjjc 1 300 train
+qezdfuypuk 1 300 train
+qezedhmcby 1 300 val
+qezeuursux 1 300 train
+qezhpkeajf 1 299 test
+qezjhmedvm 1 240 val
+qezniunogy 0 300 train
+qezvzcriaj 1 299 train
+qfacgscnvs 0 300 train
+qfafmrybtk 1 301 val
+qfalftifws 0 300 train
+qfanjfikou 1 300 train
+qfautbisug 1 300 val
+qfbfnbvmyv 0 300 train
+qfbjbbyggl 1 300 val
+qfbktumuyy 1 300 train
+qfblxltdok 1 300 val
+qfbqwmwrej 0 300 train
+qfbyocchwl 1 300 train
+qfcbwmmapg 1 300 val
+qfcknonxzl 1 300 train
+qfcnafbfcf 1 300 train
+qfcpqwbatk 1 300 train
+qfcsaafznl 1 302 train
+qfcvnmmjkb 1 300 train
+qfdictbypd 1 300 val
+qfdiqwviho 1 300 train
+qfdlnvxdgj 0 300 train
+qfdnqijtto 1 300 train
+qfdywqdzlj 1 300 train
+qfdzlgbrbl 1 300 val
+qfeeomcnkt 1 300 train
+qfeqrzvrgn 1 298 val
+qffbssbjze 1 299 val
+qffghppbsz 1 300 train
+qffgjduhoe 1 300 train
+qffjbxgkwd 1 241 train
+qffjwgvpxz 1 300 train
+qffnrfvdrv 1 300 train
+qfghdrjlwf 1 300 train
+qfgniqtltm 1 301 val
+qfgnlxibpa 1 301 train
+qfgpwxvhay 0 300 train
+qfgpxqzhzp 1 296 val
+qfgxitlutn 1 300 test
+qfhbqqmmls 1 298 train
+qfhbsyjana 1 300 train
+qfhczvsdro 1 300 train
+qfhdvlslyh 0 300 train
+qfhgilfcjj 0 300 train
+qfhgkkpwfs 1 300 val
+qfhmrgssju 0 296 val
+qfhqkllpzt 1 301 train
+qfhqtbavpl 1 300 train
+qfignkscqm 1 300 train
+qfipvubhgj 1 300 train
+qfiqridjni 1 300 val
+qfitoqtuxp 1 300 train
+qfivssvisf 1 300 train
+qfiwnyhkqc 1 300 train
+qfiyombztt 0 300 val
+qfjadgtkyd 1 300 val
+qfjejsrpwt 1 300 train
+qfjsamulau 1 300 train
+qfjtmqetlk 0 300 train
+qfjuydngdb 0 300 train
+qfjxksudna 1 300 train
+qfjzryulkj 1 301 train
+qfkfqzykjt 1 300 train
+qfkgkxeexa 1 300 val
+qfkhjtzjrh 1 300 train
+qflapbegbj 1 300 train
+qfljdkoqep 1 301 val
+qflpehfxtp 0 300 val
+qflslgrosa 1 300 train
+qfltpvdsjf 1 300 train
+qflvhvhymj 1 300 test
+qfmajvthzz 1 300 train
+qfmbgyidck 1 300 train
+qfmcmnajyq 1 300 val
+qfmgdbbovy 1 300 train
+qfmrpgcufb 1 300 train
+qfmyjptlse 1 300 train
+qfmzymuhxs 0 300 train
+qfnbjfaiog 1 300 train
+qfncewickn 1 299 train
+qfnklzwwdk 1 300 train
+qfnodwwnpx 1 300 train
+qfoatowenz 1 300 train
+qfogctlkvu 1 300 train
+qfogmbqkpx 1 300 train
+qfolgincli 1 301 train
+qfooyvaiii 1 300 train
+qfopltnmmw 1 300 train
+qfotggmytr 1 300 train
+qfotvxlypn 1 300 train
+qfpbaywxpi 1 300 train
+qfpbijvpau 1 300 train
+qfpbwdmjyt 1 241 train
+qfpkxndiis 1 300 train
+qfpnnqalzd 1 300 val
+qfpurllewq 1 300 val
+qfqemcoito 1 300 train
+qfqkqwpdzz 1 300 train
+qfqrbspvml 0 300 val
+qfqxmlnwgg 1 300 val
+qfrjidpspj 1 300 val
+qfrsnwsqhh 1 300 train
+qfrtyotceb 1 300 train
+qfrupnycgn 1 300 val
+qfrxxdiimw 1 300 train
+qfsbqwlhge 1 300 train
+qfsfuccmaw 1 300 train
+qfslxeigpv 1 300 train
+qfsneinsku 1 300 train
+qfsqghbllj 1 300 train
+qfstwhujci 1 301 val
+qfsufrfrgr 1 300 train
+qftajfrcyu 1 300 train
+qftctcuynf 0 300 train
+qftekstcak 1 241 train
+qftfxdlguy 0 300 train
+qfthkysoex 1 300 train
+qftkffogzs 1 301 train
+qftoybvjmf 1 299 val
+qftsaxhpxt 1 301 val
+qftuqaiqqa 1 300 val
+qftwzgqden 1 300 train
+qftxfwzudq 0 301 train
+qfudvgtsvb 1 300 train
+qfufdlvwmm 1 300 train
+qfugjezhbi 1 300 train
+qfujasbtxf 1 300 train
+qfuqcagqzv 1 300 train
+qfvhfbvusv 1 300 train
+qfviucsqdg 1 300 train
+qfvooavkif 1 300 train
+qfvqrbjfpa 1 300 train
+qfvtnsaont 1 300 train
+qfvwjynnqm 1 300 train
+qfvxtpgdjz 1 300 train
+qfvzwllxfc 1 300 val
+qfwdwfjimg 1 298 train
+qfwfpsgrjr 1 301 train
+qfwgvhiiib 1 300 train
+qfwnpxbuqi 1 300 val
+qfwthjydjk 1 255 train
+qfwxfabsvb 1 300 val
+qfxbywuyon 1 300 train
+qfxcxwtxjn 1 300 train
+qfxdehbmxh 1 300 train
+qfxhsxdcug 1 300 train
+qfxjflovbm 1 300 train
+qfxnhpzbrq 1 300 train
+qfxoqjbsin 1 300 train
+qfxqqhaagl 1 300 train
+qfyhcgcwax 0 300 train
+qfyhtmjzye 1 255 train
+qfymlxjqeg 0 300 train
+qfynhcomcc 1 300 val
+qfynmlqudk 1 300 train
+qfyoeodvek 1 300 val
+qfysibusjl 1 300 val
+qfziqyabor 1 300 train
+qfzlclsckz 1 300 train
+qfzmalingo 0 300 val
+qfzmoiywft 1 300 train
+qfzqpsqmwp 1 300 train
+qfztnbmhky 1 300 train
+qfzxalrbch 1 300 train
+qfzxsyfdxg 1 300 val
+qfzylqortq 0 300 train
+qfzywhuwrh 1 300 train
+qgabaegfth 1 300 train
+qgaeqlskxv 1 300 train
+qgafzmudde 1 301 train
+qgalcgvqoz 0 301 train
+qgaoranqna 1 300 train
+qgaqxgozya 1 300 train
+qgauinldgq 1 300 train
+qgbawqtulf 1 300 train
+qgbbcbddkw 0 300 train
+qgbrqvxrvg 1 300 train
+qgceqqxgdy 1 300 train
+qgcopzugsl 1 300 train
+qgczlxqpfh 0 300 train
+qgdhufigqh 1 300 train
+qgdkprmliu 1 300 train
+qgdorrdnwl 1 300 train
+qgdtpsklgm 1 300 train
+qgebtgsjgp 1 300 train
+qgedixuyfi 1 300 train
+qgeexzvica 1 300 train
+qgeflumyqt 0 300 train
+qgefryzetr 1 299 train
+qgegnisbuy 1 301 train
+qgelxflgdw 1 300 train
+qgenivlwxx 1 300 train
+qgeztfafin 1 237 train
+qgfgphazhd 1 300 train
+qgfusfbufk 1 301 train
+qgfxkgofjl 0 300 train
+qgfztfdjeo 0 300 val
+qggeaivwgp 1 300 train
+qggfpdkyzi 0 299 val
+qgghaexmph 1 300 train
+qgghrrukui 1 300 train
+qggnwollya 0 300 train
+qggoaluomc 1 300 train
+qggorpxlar 0 300 train
+qggqlpnptg 1 300 train
+qggzegfwde 1 300 train
+qghmhdqihp 1 300 train
+qghmmyafhm 1 300 train
+qghoidzrdu 0 301 train
+qghqahtjdy 1 296 train
+qghsjfwowo 1 300 val
+qghuclzrkb 1 300 train
+qghxomiqga 1 300 train
+qgibcvkeeb 1 300 train
+qgidnasexm 1 300 val
+qgiidsfxsr 1 300 val
+qgikbkkady 1 300 train
+qgimorktns 1 300 train
+qginpntgzc 1 296 val
+qgioqjfncl 1 300 train
+qgipgmfyay 1 300 train
+qgivlublru 0 300 train
+qgiygiqybs 0 300 val
+qgizmdoefp 1 300 train
+qgjbbfouho 1 300 train
+qgjcclleed 1 301 val
+qgjehqhned 0 300 train
+qgjelpkxhp 1 241 train
+qgjkufzlqe 1 300 val
+qgjmwsjewa 1 300 train
+qgjsymcviq 1 300 train
+qgjtjtybfe 0 300 train
+qgjwclcggm 1 301 val
+qgjwebhigi 1 300 train
+qgkaaltznq 1 300 train
+qgkdddiiai 1 298 train
+qgklsksocd 1 300 train
+qgkngvwbjk 1 300 train
+qgkqxjgjcj 1 301 train
+qgkstdlmtp 1 301 val
+qgktqfhjav 1 300 train
+qgkvanquab 1 300 val
+qgkxeyelzs 1 300 train
+qglcjjklhu 1 300 train
+qgliltfbng 1 300 val
+qglvmhycuz 1 300 train
+qglwmjjwaa 1 241 train
+qglxglmptt 1 300 train
+qgmaotonwu 1 300 train
+qgmcbtkrep 1 300 train
+qgmhchlepr 0 300 train
+qgmjhmnpfx 1 300 val
+qgmmbqjivx 1 300 train
+qgmttqlpea 1 300 train
+qgmtytfqrs 1 300 train
+qgmuhybfpf 1 298 train
+qgmxbftvrn 1 299 test
+qgmxhsifhu 1 300 train
+qgnfirqiia 1 300 val
+qgnhqmtbko 1 300 val
+qgnlnfugoh 1 300 val
+qgnlsfxjnw 1 300 train
+qgnnpcojvu 1 300 train
+qgoicknfxp 1 300 val
+qgokzyhxzl 1 300 val
+qgompoqklx 1 300 train
+qgoobexpnm 1 299 train
+qgoydwvfff 1 300 train
+qgpabkriss 0 300 train
+qgpdybvbgt 1 300 train
+qgpeqdwejy 1 300 train
+qgpgoaebqm 1 300 train
+qgpxmovzga 1 300 val
+qgqcngfzat 1 300 test
+qgqdlhcpli 1 300 val
+qgqjikgruc 1 241 train
+qgqkgcaddb 0 300 train
+qgqlxwyphq 1 300 train
+qgqmcskgxv 1 300 train
+qgqnqwysrv 1 298 train
+qgqsgtekwl 1 301 train
+qgqvxmdsqd 1 300 val
+qgraqykxdo 1 300 train
+qgrejnsnfh 1 300 train
+qgrieuqruw 0 300 train
+qgrlklhrhy 1 300 train
+qgrmigkxlw 1 300 train
+qgrmsdxdzq 0 300 train
+qgrqnyiinn 0 300 train
+qgrrqopwjw 1 300 train
+qgrwmopjhy 1 300 train
+qgrykrdzzp 1 301 train
+qgsidryiuq 1 300 train
+qgsnvozsnr 1 300 train
+qgsoddttae 1 300 train
+qgssjxqkez 1 300 test
+qgsvrioyox 1 298 train
+qgteffehuo 1 301 train
+qgtnbfqbra 1 300 val
+qgtniqqpzf 0 300 train
+qgtyghedfl 1 298 train
+qguauknhcp 1 300 train
+qgukpdasjp 1 300 train
+qgukqqnucw 1 300 train
+qguoavkuzb 1 297 train
+qguogqrstd 1 300 train
+qguojjuoik 0 300 train
+qguqtlgwlq 1 301 train
+qguuizkcji 0 300 train
+qguxarkhje 1 300 train
+qgvbolqcnx 1 300 train
+qgvfnphfqc 1 300 train
+qgvoxogmsk 1 300 val
+qgvpayyowv 1 300 train
+qgweofbmie 1 300 train
+qgwjcftfwn 1 300 val
+qgwmmiblom 1 241 train
+qgwnhffosn 1 300 train
+qgwsgxxbvh 1 300 train
+qgwthpvlxl 1 300 train
+qgwzddqsxa 1 300 train
+qgwzvwfhcb 1 300 train
+qgxfanaiaf 0 300 train
+qgxpbdjclw 1 300 train
+qgxqbinntj 1 300 train
+qgydgdfexo 1 300 train
+qgyeqblrzk 1 300 train
+qgyftraasm 1 300 train
+qgyfyqxdmy 1 300 val
+qgyigrhnmj 1 300 val
+qgylbcujuz 1 300 train
+qgylpvnvfo 1 300 val
+qgymqxysfq 1 300 train
+qgynefjfnp 1 300 train
+qgysfkpefh 1 300 train
+qgzafofgvg 1 300 val
+qgzehexlft 1 300 train
+qgzhxokbsj 1 300 val
+qgzjhkfdcs 1 300 train
+qgzsxiivsh 1 300 train
+qgztrlaprq 0 300 train
+qgzvwmogms 1 300 train
+qgzvxqyiwc 1 300 train
+qhaawkjucp 1 300 test
+qhaaxyogzi 1 300 train
+qhagyfkqpl 1 300 val
+qhanuectob 0 300 train
+qhaohgfehs 1 300 train
+qhaqcgkknh 1 300 val
+qharxzhzpl 1 300 train
+qhauyogdmh 1 300 train
+qhavagleri 1 300 train
+qhbbkghiql 1 300 val
+qhbbvqwrlf 0 300 train
+qhbknwttom 1 300 val
+qhbmhxlytd 1 300 train
+qhbomegqbe 1 300 train
+qhbpglaqsb 1 300 val
+qhbqkbqcyd 1 300 train
+qhbwmeuvlk 0 300 train
+qhcncdvumq 1 300 val
+qhcrglyfcc 1 300 train
+qhcrrlwgub 1 300 val
+qhcwcbftwe 0 300 train
+qhcygwysox 0 300 train
+qhdnbtoodt 1 302 train
+qhdqhjbujm 1 300 train
+qhdxdsekcl 1 300 train
+qhenulofmh 1 300 train
+qhescyhiyc 1 300 val
+qheuupgvbr 1 300 train
+qhewdskbzi 1 300 train
+qhexjozokp 1 300 train
+qhfcbqcogt 1 300 train
+qhffcaotsm 1 300 train
+qhfjujfrio 0 300 train
+qhfkfabfxh 0 298 train
+qhfkllhcwq 1 300 train
+qhfmkiduph 1 300 train
+qhgatctqbg 0 300 val
+qhgnepyfkq 1 300 val
+qhgparsqwe 1 300 train
+qhgttbukjs 1 300 train
+qhgwzcngjl 1 300 train
+qhgyvzctxa 1 300 train
+qhhcyzinds 1 300 train
+qhhdapwbnq 1 300 train
+qhhghykaji 1 300 val
+qhhjjzwvkt 1 300 train
+qhhkcsvlod 0 300 train
+qhhowomgim 1 300 val
+qhhsdhzpot 1 300 train
+qhhuilcdfg 0 300 train
+qhhwmxnbuy 1 300 train
+qhibrkzvtd 1 300 val
+qhirrywhwt 0 300 train
+qhjhdjqjyc 1 300 train
+qhjlfpkszm 0 300 train
+qhjqrajaua 1 301 val
+qhjskqiqec 0 300 train
+qhkbseidwc 1 300 train
+qhkdzkepbn 1 299 val
+qhkkwmfeou 1 301 train
+qhknubmuzk 1 300 train
+qhkpconctz 1 300 train
+qhkqqfznrg 0 300 train
+qhkwjzpuud 0 300 train
+qhkzlnzruj 0 300 test
+qhkzosvlzx 1 300 train
+qhlfcgkkcl 1 300 train
+qhlfevbzrb 1 298 train
+qhlftgpmai 1 300 train
+qhlodwkmyh 0 300 val
+qhlohmupqx 1 300 train
+qhlovacjcq 1 300 train
+qhlsraccva 1 300 train
+qhlsutgkzv 1 300 train
+qhlybfsdsr 1 300 train
+qhmegocnsz 1 300 train
+qhmkhzoadp 1 300 train
+qhmkklxqlw 1 300 test
+qhmpvfydoy 1 301 train
+qhnbbcdbev 1 298 train
+qhnegrdqcw 1 300 train
+qhnjiyljob 1 300 train
+qhnjqseloc 1 300 train
+qhnmjifxvn 1 300 train
+qhnnhpzaas 1 300 train
+qhnpgzgfcp 1 288 train
+qhnptqkbpb 1 300 train
+qhnqwugein 1 301 train
+qhnxbdjpma 1 300 train
+qhofqthgwz 1 300 train
+qhogrpgfcv 0 300 train
+qhojdvfpgv 1 300 train
+qhonqrxcjc 1 300 train
+qhornnqxmb 1 299 train
+qhothhtyjm 1 241 train
+qhouamtvuj 1 300 train
+qhovhrdkju 0 300 val
+qhoximbfox 1 301 val
+qhozgfjkma 1 300 train
+qhpaohnalk 1 300 train
+qhpcrojqpe 1 300 train
+qhpeiqezyd 1 301 train
+qhpeunnbvr 1 301 val
+qhppjfvvnd 1 300 train
+qhprjamitv 0 300 train
+qhpylfgdwx 1 300 val
+qhpzlqzkjs 1 300 train
+qhqduqavkh 1 300 train
+qhqiarfckg 1 300 train
+qhqludsfni 1 300 val
+qhqtbeahkh 1 300 train
+qhqtmjtpjm 0 300 val
+qhqydvdjqp 1 300 val
+qhqzefzhcz 1 300 val
+qhrlxcsecc 1 301 val
+qhrmsrhqfy 1 300 train
+qhrndykupy 1 300 train
+qhroeiedcg 1 255 train
+qhsadkcakq 1 300 train
+qhsehzgxqj 1 300 test
+qhslfuxjeg 1 298 train
+qhsocnydkz 0 300 train
+qhsqocbfcc 1 300 train
+qhswsmizny 1 300 train
+qhtdxgqrgc 0 300 val
+qhtjyczlxy 0 300 val
+qhtommnsyr 1 300 train
+qhttfwakwr 1 300 train
+qhtubfherc 1 300 train
+qhtucdghie 1 300 train
+qhtwtxvlan 1 300 val
+qhtynlhtjf 1 300 train
+qhtyzltjxc 1 298 val
+qhtzfvtlwt 0 300 val
+qhuavqhohe 1 300 train
+qhugrooovy 1 300 test
+qhukhgopvk 1 300 val
+qhuklcsudv 1 300 train
+qhulhuunpe 1 300 train
+qhupsusbfb 1 301 train
+qhusfwulxk 0 300 train
+qhuugoaniw 1 300 train
+qhuyugstih 0 300 val
+qhvaqcmqha 1 300 train
+qhvbdtsacw 1 299 train
+qhvbznomas 1 300 train
+qhveaeshkr 1 300 train
+qhvjhqerbn 1 300 train
+qhvplkfsry 1 301 train
+qhvrgrjvaw 1 300 train
+qhvsxatale 1 300 train
+qhwdfvhfji 1 300 train
+qhwkphcmhx 0 300 train
+qhwndxvxrl 0 300 train
+qhwtdwdvko 1 300 train
+qhwvegmmkh 1 300 train
+qhwxovphvx 0 300 train
+qhwzhtpmeh 1 300 train
+qhxdtsgexq 1 298 train
+qhxhzjgcdj 1 300 train
+qhxlqguasx 1 298 train
+qhxmayuvaj 1 300 train
+qhxmonghqz 1 300 train
+qhxmwgtaxb 1 300 train
+qhxpjajdsk 1 300 val
+qhxvwwfbdv 1 300 train
+qhybyxcqyh 1 300 train
+qhycbnkkir 1 300 train
+qhyfzfnzyk 1 300 train
+qhynsxlqfk 1 300 train
+qhyqeoiikm 1 300 train
+qhyvfidltb 1 300 train
+qhzbgfpwqm 0 300 train
+qhzdqyhcxi 1 300 train
+qhzdxuntiq 1 300 train
+qhzjlsnoac 1 300 val
+qhzlgrtgto 0 300 train
+qhzmhuieou 1 300 train
+qhzotbmmwx 1 300 train
+qhzsjgdnmi 1 300 train
+qhzszqjbky 0 302 val
+qhztjyryuh 1 301 train
+qhztttcyba 1 300 train
+qhzwkaawic 1 300 train
+qhzzzropqo 1 300 val
+qiacppxuff 1 300 train
+qiahslvndt 1 300 train
+qiajjiwxnh 1 301 val
+qialdjupji 1 300 train
+qianzoqvum 0 300 train
+qiavmjzzoo 1 300 train
+qiavrufjrz 1 299 val
+qiaweruutt 1 300 val
+qiazbidtsu 1 300 train
+qibjyvobaj 1 299 val
+qiboimkfgf 1 300 train
+qibqfptxxa 1 300 train
+qibykrrjbm 1 300 train
+qicatlbnfr 1 298 val
+qiccukosrw 1 300 train
+qickkzifqq 1 300 train
+qicmcrfkuw 1 300 train
+qicrkbsndm 1 300 train
+qictduddwj 1 269 train
+qicwnwunsy 1 300 train
+qiczijfwzc 1 300 val
+qidedtmztd 1 300 train
+qidllqhcmn 1 301 train
+qidqgrufew 1 301 val
+qidtwwcuun 1 300 val
+qidxtaxqnl 1 298 train
+qidxyekgyv 0 300 train
+qiecarkcbo 1 300 train
+qiedeatkdn 1 300 train
+qieejdykzq 1 300 train
+qiencoqvif 1 300 train
+qieriiphvb 0 300 train
+qifcdhktps 1 301 val
+qifcgpsomj 1 300 train
+qifhccqwpi 0 301 train
+qiflakrrwc 1 300 train
+qifmbjzakv 1 300 train
+qifncvpzyr 0 300 train
+qifpzexvma 1 300 val
+qifxbfhtoe 1 300 val
+qigelwcwpj 1 300 train
+qigllobyai 1 300 train
+qignvncqky 1 300 val
+qigoosoxrw 1 300 val
+qigskimisr 1 302 val
+qigvuxrdhd 1 300 train
+qigxibvhit 1 300 train
+qigxtdctsr 1 300 train
+qigyfjakmj 1 300 train
+qigyukwqnd 0 300 train
+qihliclcso 1 300 val
+qiifwnclpl 1 300 val
+qiiigtcpft 1 300 train
+qiinxqndlg 1 300 train
+qiioediphr 1 300 train
+qiiseezelr 1 300 train
+qiiybqjnzw 1 300 train
+qijfwydmuw 1 300 train
+qijsvjkmsr 1 300 train
+qijtymyvog 0 300 train
+qikdhhjwlj 1 298 val
+qikebvpwvk 1 302 train
+qikfqayesb 1 300 val
+qikhsgvjer 1 300 train
+qikimsyxqy 1 300 train
+qikiwjtnwq 1 300 train
+qiklmoeita 0 300 train
+qikodmxysh 1 300 train
+qikpixlygi 1 301 train
+qikuzwgoxt 1 300 train
+qikvnezusi 1 300 val
+qilfqxiidj 1 300 val
+qilihvfrte 1 298 val
+qilkmlkovm 1 300 train
+qilonbvqqj 1 299 val
+qilsdbinay 1 300 train
+qilwdrtnzl 1 300 train
+qilycjntjt 0 300 train
+qilzftwueq 1 300 train
+qimajportn 1 300 train
+qimccbsvtv 1 301 train
+qimceosgfg 0 300 train
+qimfjdtegk 1 300 train
+qimohymtxo 1 300 train
+qimqbyybxc 1 300 train
+qimrefcrsq 1 300 train
+qimrhkozaj 1 300 train
+qimrrpwmcj 1 300 train
+qimsyvckje 0 300 train
+qinaurlkvw 0 300 train
+qinmcwphzx 0 300 train
+qinngytenn 1 300 train
+qinpkkfegb 1 300 train
+qinqgdpcxj 1 301 train
+qinyhsxbgf 1 300 train
+qiocyhiqde 1 300 train
+qiodlmhmeg 1 300 train
+qiolcjxlfa 0 302 train
+qionjxbrrt 0 300 train
+qionwqprhw 1 300 val
+qiorirtbxy 0 297 val
+qiosphoted 0 300 train
+qiovoreqkt 1 300 train
+qiowzezcuz 1 300 train
+qiozqjvdij 1 300 train
+qiphljhsob 0 300 val
+qiphpqnxxz 1 300 val
+qipufogxbv 1 300 val
+qipuoiuveu 0 300 val
+qipvtesjat 1 300 train
+qiqadusnha 1 301 val
+qiqctsoubc 1 300 val
+qiqdfujmpi 1 300 train
+qiqieplpxn 1 300 train
+qiqonryknn 1 300 train
+qiqukydmin 1 300 val
+qiqwehhmrg 0 301 val
+qirdqgprcg 1 300 train
+qirerpsggs 1 300 train
+qiripfhfbx 1 300 train
+qirlrtrxba 1 300 train
+qirlzxqfyi 1 300 train
+qirrjbewsw 1 147 train
+qirsazxtan 1 301 val
+qirtzxqvwu 1 300 train
+qirvgxbtrd 1 298 train
+qirxhqkusg 0 300 train
+qirzbmqnww 0 300 train
+qisajqkctm 1 300 val
+qisjkztwii 1 300 train
+qiskqhdpzu 1 300 train
+qiszrxtqty 1 300 val
+qitbqqavwi 1 300 train
+qitcddzecx 1 300 val
+qithvzqhrd 1 300 train
+qitiabilhn 0 300 train
+qitjfirxhv 1 300 train
+qitjmadsok 1 300 train
+qitrxbxcpv 1 300 train
+qitshgitgv 1 300 train
+qittorkjwn 1 241 train
+qitydywudu 1 300 train
+qiujpybmhc 1 300 val
+qiupjzwiso 1 301 val
+qiuvlhixsm 0 300 train
+qiuwjcrxav 1 300 train
+qiuzeqtfjh 0 300 val
+qivcmnkjte 1 300 val
+qivdijhwng 1 298 train
+qivfkhhmsc 1 300 val
+qivhebebqp 1 300 train
+qivilhvxup 1 300 train
+qivlmpppwf 1 300 train
+qivnumuetu 0 300 val
+qivpypiwlp 1 300 test
+qivqhjfjda 1 300 val
+qivrfrtgfu 1 300 val
+qivscggdxa 0 300 train
+qivufhbmyo 1 241 train
+qivxpjealv 1 300 val
+qivywlsyud 1 300 train
+qiwddiorzh 1 300 test
+qiwhwafbgy 1 300 train
+qiwlbuwtxk 1 301 train
+qiwlriftns 1 241 train
+qiwwbbfnfx 1 300 train
+qiwzqperke 0 300 train
+qixgnvnktr 1 301 train
+qixjbbvhfz 1 300 train
+qixvgwxtsu 0 300 train
+qixxotadmr 1 241 train
+qixxwvudhj 1 300 train
+qixyiibywq 1 300 val
+qiyfmmstkg 1 300 train
+qiyiyzkgzh 1 300 val
+qiykbribkj 1 300 train
+qiylmahizx 1 300 train
+qiymboucvy 1 300 train
+qiyouszelr 1 241 train
+qiysgwdark 1 297 train
+qiyzfjrloz 0 300 test
+qizbobmese 1 300 train
+qizdwvhwvj 1 300 train
+qizehpisuk 1 300 train
+qizfcejlpj 0 300 train
+qiziibfhqv 1 300 val
+qizleqtjxw 1 299 train
+qizmuwjilt 1 300 val
+qizpvopjgi 1 300 train
+qiztjdgund 1 300 train
+qizwmtngkx 1 270 train
+qizwpdsmmn 1 300 train
+qjastnhahm 1 300 train
+qjavujyfdb 1 300 train
+qjbajyxjrl 1 302 train
+qjbhlvrpgv 1 300 train
+qjbkgngvjm 0 300 train
+qjblgbrgkr 0 300 train
+qjbuxskslw 1 300 train
+qjbwmqfnyo 1 300 train
+qjbyrxywaw 1 302 train
+qjcandlggc 1 300 train
+qjcapekscq 1 241 train
+qjcbjujnim 0 300 train
+qjcgdmaozj 1 298 train
+qjcgyqgdfa 1 298 train
+qjcieuzlgj 1 299 test
+qjckvoipla 1 301 train
+qjcmkbqshg 1 300 train
+qjcnnmpipq 1 300 train
+qjcsboclei 0 269 train
+qjcworudck 1 300 val
+qjdaxcevqx 1 300 train
+qjdertwgkv 1 300 train
+qjdltxiluo 0 300 train
+qjdncxwgzn 1 298 train
+qjdnvnboja 1 300 train
+qjdoivqffx 1 300 train
+qjdoyicbym 1 241 train
+qjdsflfznw 1 300 train
+qjdtgggqym 0 300 val
+qjdtzcalxt 1 300 train
+qjdunrpahp 1 300 train
+qjdvogjflt 1 300 train
+qjebontdqf 1 299 val
+qjefhikrwz 1 300 train
+qjeidqbpgj 1 300 test
+qjekoykrbv 1 300 val
+qjeovxqskj 0 300 train
+qjevfogcqn 1 300 train
+qjewpmfqyk 1 300 train
+qjfmlltkin 1 300 train
+qjfoeuwyjf 1 300 val
+qjfqgmiaii 1 300 train
+qjftklhdbe 0 300 train
+qjgbbwbyvv 1 300 train
+qjgbispdqw 0 300 train
+qjgiutecmv 0 300 val
+qjgnmyjhrt 0 300 val
+qjgqdcpxbj 1 241 train
+qjgrfmtpbt 1 300 train
+qjgstykaqn 1 301 val
+qjgumuaoid 1 298 val
+qjgwlbctqa 1 299 train
+qjgwplghku 0 300 train
+qjhddyiarc 1 297 val
+qjhgmqzjxi 1 300 train
+qjhhpmzdht 1 300 train
+qjhlsrombu 1 300 test
+qjhqctxknd 0 300 val
+qjhskndjxm 1 300 val
+qjhvgkxags 1 300 train
+qjhxhhumfm 1 299 test
+qjhzesjbwh 1 300 train
+qjibvucnes 1 300 val
+qjifrjydhs 1 300 train
+qjigmgahoy 0 300 train
+qjihxkwwsy 1 300 train
+qjilklnynm 0 301 train
+qjiotjvrcd 1 300 train
+qjironhyyh 1 299 train
+qjivjommrk 1 300 train
+qjivvtfbyy 1 300 train
+qjizfcryuv 1 297 val
+qjjqrwcpqj 1 300 train
+qjjqwmxmwp 1 300 val
+qjkcdeosyi 1 300 train
+qjlctymlwe 1 300 val
+qjlhemtkxk 0 300 train
+qjlirsyyuf 1 300 train
+qjlmozvhhr 0 241 train
+qjludewkhj 1 300 train
+qjlwxtgfkb 1 300 train
+qjmhtujhww 1 300 train
+qjmmfjyorx 1 300 test
+qjmqiyatjh 1 300 val
+qjmsqyknsd 1 300 test
+qjmvtrvzmh 1 300 train
+qjmxmyhmje 1 300 val
+qjniezcakg 1 301 val
+qjnkguwzga 0 300 train
+qjnnqdmwha 1 300 val
+qjnrsisslk 0 300 train
+qjntsyyzxg 1 241 train
+qjoaalquhy 1 241 train
+qjobgkijpe 1 300 train
+qjocrfbdrl 1 300 val
+qjoixevzqv 0 300 train
+qjojlsxuro 1 241 train
+qjojvzrbfz 1 300 train
+qjopcxvzqj 1 300 train
+qjoqnqyvkl 1 300 train
+qjormspuna 1 300 train
+qjoyrxlebq 1 300 train
+qjpctcyecg 0 300 train
+qjpeztdrnm 0 298 val
+qjphwyykjf 0 300 train
+qjpjsbuowe 0 300 train
+qjpnmpzkxe 1 300 train
+qjppdsmwxc 1 299 val
+qjpsrwftcm 1 300 val
+qjpugmbxhb 1 300 test
+qjpuunrrkx 1 300 train
+qjpvmtoaum 1 237 train
+qjpxpkpnju 1 300 train
+qjqafllxfz 1 300 val
+qjqetocnmy 1 300 train
+qjqoxvnaep 1 300 val
+qjqoztwved 0 300 val
+qjqvbqypbj 1 300 train
+qjqwxdfwyf 1 301 train
+qjqxfcgsyd 0 300 val
+qjqxkytcfi 1 300 train
+qjracbrmzo 1 300 train
+qjrehkhxft 1 300 train
+qjrigaoqqi 1 300 test
+qjrjuhxlhs 1 300 train
+qjrnmoqeoq 1 300 train
+qjsizrraty 0 300 train
+qjsknebypo 1 300 train
+qjskzoczau 1 300 train
+qjsntnutiy 1 300 train
+qjsqusidwr 1 300 train
+qjsroipniu 1 300 test
+qjstyfsobe 1 300 train
+qjsxbbcnub 1 300 train
+qjszghlgdt 0 300 train
+qjtbhtgrar 0 300 train
+qjtdefppmp 1 300 val
+qjtflskimw 0 300 train
+qjtgdcrkwb 0 300 train
+qjtoekqqcz 1 241 train
+qjtwwkgdkm 1 300 train
+qjtzxcctvb 1 299 train
+qjuagjhdth 1 300 train
+qjubfhspxz 1 300 train
+qjuccwixzq 1 298 train
+qjucmrbepf 0 300 train
+qjufaenmzd 1 300 train
+qjuhejzyeq 1 300 test
+qjunkcvdrx 1 300 train
+qjustchaja 1 300 train
+qjutgzgooa 1 300 train
+qjvehghyvb 1 300 val
+qjvhrpljlb 1 300 train
+qjvjkojjkl 1 300 val
+qjvjlvuhue 1 300 val
+qjvorprquk 0 300 train
+qjvufjcirw 1 301 train
+qjvvyalesh 1 300 train
+qjvwhzoaek 0 300 train
+qjvxwjerzs 0 300 train
+qjvzhisszu 1 300 train
+qjwamqdiph 1 300 val
+qjwcddsnoa 1 300 train
+qjwdojkcng 1 300 train
+qjwjxhdkam 1 300 val
+qjwltbnstb 1 300 train
+qjwomijmcb 1 300 test
+qjwonodzpk 1 297 train
+qjworrzkuu 1 300 train
+qjwpwgpskr 0 300 train
+qjwrnebksa 0 300 train
+qjwujikrmf 0 300 train
+qjxbwvopqh 1 300 train
+qjxcbsqdye 1 241 train
+qjxhhdxktb 1 300 train
+qjxmhgaaet 0 300 train
+qjxoxbqlce 1 298 val
+qjxsbswtnc 1 300 train
+qjxukectwt 1 300 train
+qjxvtpxhxw 1 301 train
+qjxzelzwjj 1 300 train
+qjyequmrfi 1 300 val
+qjyfljeaxy 1 300 val
+qjyocqfdob 1 300 train
+qjyoroowkm 1 300 train
+qjyotqjmuf 1 300 train
+qjyykerdmj 1 300 train
+qjzfeknofb 1 300 train
+qjzhnsjvxo 1 300 val
+qjzianajjn 1 300 train
+qjzndtuumm 1 300 train
+qjzzeyijyv 1 300 test
+qkaaaapifk 0 300 val
+qkaafsvwxs 0 299 val
+qkaqmybrgw 1 300 train
+qkatcnxayz 1 300 train
+qkayepnyep 1 300 train
+qkbcijlnls 0 300 train
+qkbgohclnp 1 300 val
+qkbinsawpr 0 300 train
+qkbiuhmpoy 1 300 train
+qkbkvjaijr 1 300 train
+qkbnmdxliw 1 300 train
+qkbowpmjpj 1 300 train
+qkbqjsznza 1 300 val
+qkbsxifwre 0 300 train
+qkbtcymbvd 1 300 train
+qkbxhpgdyb 1 300 train
+qkbybmliqg 1 300 train
+qkbywibxqf 1 299 test
+qkcbfgmlcw 1 300 train
+qkcfeqoonm 1 299 val
+qkcgzogaco 0 300 train
+qkchcuiljp 1 300 train
+qkcrhpqayv 1 300 train
+qkcxcecfnv 1 300 val
+qkdfluzasa 1 167 train
+qkdgqdbxcx 1 300 val
+qkdhsyavds 1 300 train
+qkdihcaufr 1 300 train
+qkdjcpazpp 1 300 val
+qkdjtfkzkz 1 300 val
+qkdqgtlifi 1 300 train
+qkdtardcmv 1 300 val
+qkdxbwzakm 1 298 val
+qkeetxcqeb 1 300 val
+qkekqjtxus 1 300 train
+qkemkbnsys 1 300 val
+qkeqwekltf 1 297 train
+qkewkrmwtj 1 300 train
+qkewzvbngi 0 300 train
+qkezljynts 1 300 val
+qkfpkofngs 1 300 train
+qkfyrhvkul 1 300 train
+qkgaabnswx 0 300 train
+qkgicklwyn 1 300 val
+qkgjlvkxtj 1 300 train
+qkgnctdfbe 1 300 val
+qkhgbszhwh 1 300 train
+qkhgozcmia 1 300 val
+qkhnixhnyl 1 300 val
+qkhnqcilhv 1 300 train
+qkhqtedugp 1 300 train
+qkhtblugcf 1 300 train
+qkhwatgmkb 1 300 train
+qkhwhlmtmw 1 300 train
+qkhwkgevey 1 300 train
+qkicqzirnd 1 300 train
+qkiexiryau 1 300 val
+qkixjmuyud 1 301 val
+qkiyshqurv 1 300 train
+qkjavxjgop 1 301 train
+qkjdawzkvu 0 300 train
+qkjjntqbdz 1 300 train
+qkjldksftc 1 300 train
+qkjnqdupub 1 146 train
+qkjrgnfquw 1 99 train
+qkjuyuiuwv 1 301 train
+qkjwdscfar 1 301 train
+qkkacvdrwl 1 300 train
+qkkekxynfd 1 236 train
+qkklqzcdkx 0 301 train
+qkkruzzpvx 0 300 train
+qkkshziqpy 1 300 val
+qkksmvhpjh 1 300 val
+qkktwtqmzj 1 300 train
+qkkubsdlzn 0 300 val
+qkkzignpbc 0 300 train
+qklcfndqwg 1 300 train
+qklhvwavad 0 300 train
+qkliebaumg 1 300 train
+qkljwyfvln 1 300 train
+qklqkmqubu 1 300 val
+qklrtcpnfa 0 300 val
+qklvqreuqy 0 300 train
+qklzwfvgpf 1 99 train
+qkmbpxojvo 1 300 train
+qkmfwgyrjp 1 300 val
+qkmhiuxpcn 1 300 train
+qkmhohutfl 1 301 train
+qkmittvzcn 1 298 train
+qkmixzfeit 1 300 train
+qkmpqwnuhy 1 300 train
+qkmpyeuzow 1 300 train
+qkmqgfutzu 1 300 train
+qkmtguumch 1 300 train
+qkmvciheye 1 300 train
+qkmyjqryax 1 300 train
+qkmzesolsi 1 300 val
+qknghegybf 1 300 train
+qknnpddobj 0 300 train
+qknolltspg 0 300 train
+qknomlsfbq 1 301 train
+qknqbyxfaj 0 300 val
+qknrjwuotr 0 300 train
+qknsdfybhj 1 300 train
+qknujpiibr 1 300 train
+qknxagsmdq 1 300 train
+qkoeeeupbd 1 300 train
+qkojxgnntr 1 298 train
+qkontvlioj 1 300 train
+qkoqclvwex 1 300 train
+qkpceyfxya 1 300 train
+qkpisaeoms 1 300 train
+qkpjmnzppr 0 300 train
+qkptrvsobe 1 300 train
+qkpvlralvw 1 300 train
+qkpyisccpf 1 298 val
+qkqbmmldnb 1 300 train
+qkqfljizts 1 300 train
+qkqgbbpphm 1 300 val
+qkqhocurfv 1 300 val
+qkqhovigyz 1 300 train
+qkqkbebvgq 1 300 val
+qkqluzslny 1 300 train
+qkqmaxgnlq 1 300 train
+qkqoaiafxx 1 301 train
+qkqopqpxtm 0 300 train
+qkqpqlhoxq 1 300 train
+qkqqynrayl 1 298 val
+qkqrgxecak 1 300 val
+qkqtzfkiqq 1 300 train
+qkqzqsvvpx 1 300 val
+qkrbqtpdpn 1 300 val
+qkrficezjn 1 300 val
+qkrhraldoi 1 300 train
+qkromhcvfm 0 300 train
+qkroqoybcm 1 301 val
+qkrpkmoigh 1 300 val
+qkrpyomjdl 1 300 train
+qkrshpdmch 1 300 train
+qkrshxlpyt 1 300 train
+qkrtsheqrs 1 301 train
+qkrumcvepk 1 300 train
+qkrydvcmsa 1 300 train
+qkrytxyqfx 1 301 val
+qksjhpeiae 1 300 test
+qksxgjvpex 1 300 train
+qkszfitgii 1 300 train
+qkszuvvval 1 300 train
+qktbokxwrr 1 301 train
+qktgqwwxpq 1 300 train
+qktmwvdjjf 1 300 train
+qktvtpkmmx 1 300 val
+qkucdxgolt 1 300 train
+qkueyxlhhv 1 300 val
+qkufepheoi 1 301 val
+qkufsulvwx 1 301 train
+qkuqafslla 0 300 train
+qkvddyclet 1 300 train
+qkvfwhemab 1 300 val
+qkvgvoerxy 1 300 val
+qkvhjisfka 1 300 train
+qkvhsdbxkp 1 300 train
+qkvivhodkx 1 300 train
+qkvomxkjun 1 300 train
+qkvvzdazqk 1 300 train
+qkvybvlifk 1 300 val
+qkvzcyfmdv 1 300 train
+qkwedsvjkc 1 300 val
+qkwhykhtgi 1 300 train
+qkwkiaxbfx 0 300 train
+qkwkkizbep 1 300 train
+qkwklxtgus 1 300 train
+qkxdcugdzp 1 299 val
+qkxfibnahs 0 300 train
+qkxkmukrjg 1 300 val
+qkxvgicdxt 1 301 train
+qkxwgctvyr 1 300 train
+qkycekbvxz 1 300 train
+qkydeztsln 1 301 train
+qkypyxxorb 1 300 train
+qkysecoqyh 1 297 val
+qkzabeimvu 1 300 test
+qkzblznagc 1 300 val
+qkzcannklm 1 300 train
+qkzhcmlvjj 1 300 train
+qkzjydlcsq 1 300 train
+qkzkhoigbo 0 300 train
+qkzlftpxlm 1 300 train
+qkzrtibkdi 1 299 test
+qkzubieloh 1 300 train
+qkzugbahsa 1 300 val
+qlaesabhcw 1 300 train
+qlafdwjela 1 301 val
+qlafecjhau 1 300 val
+qlaftuuvfz 1 299 test
+qlaogvtstw 1 300 val
+qlarnqliwe 1 300 train
+qlbapiibba 0 300 train
+qlbcyhaddf 1 300 train
+qlbfklnrfc 1 300 train
+qlbgumdyqv 1 300 val
+qlbhyfplkh 1 300 train
+qlbicllunf 1 300 val
+qlbkidgsow 1 300 test
+qlblstzxim 1 298 train
+qlbphfahuf 1 299 test
+qlcbfvbjoe 1 300 val
+qlccwtarer 0 300 train
+qlcdgkjqkj 1 299 val
+qlcndevwog 1 300 train
+qlcwjbrnur 1 298 val
+qlcxmydwyx 1 300 train
+qlczyutmml 1 300 train
+qldbpgkccd 1 300 train
+qldfxrllvm 1 301 train
+qleawlggxr 1 300 train
+qleiwjmtuq 1 301 train
+qlejantevh 0 300 train
+qlejqhjtpc 0 300 train
+qlenfhypny 1 241 train
+qlfcrxjmpf 1 300 train
+qlfddsdesx 1 300 train
+qlfdwthkwy 0 300 train
+qlffmdnveh 1 300 train
+qlfggexabn 1 301 val
+qlfiutdsqu 1 300 train
+qlfkeidolu 0 300 train
+qlftvgsrds 1 300 train
+qlfuqhkbqy 1 300 val
+qlfyorosko 1 300 train
+qlglbxtddh 1 300 train
+qlgpeknfxl 1 301 val
+qlgpprqvad 0 300 train
+qlgthbfcjv 1 300 train
+qlgwfcomin 1 300 train
+qlhefekfba 1 300 train
+qlhkakbrbl 1 300 train
+qlhmdpbgis 1 300 train
+qlhqgnuehw 1 300 train
+qlhsauiovb 1 300 train
+qlhzwkknbk 1 300 train
+qlineszgvu 1 300 train
+qlininxlhl 1 300 train
+qlitejizqt 1 300 train
+qlizhzamzj 1 300 train
+qljkhsgmjk 1 302 train
+qljnhratda 1 300 val
+qljocdjrrp 1 301 val
+qljqygtsqy 1 300 train
+qljththfso 1 301 train
+qljxcwihvt 1 300 val
+qljzmerlaf 0 300 train
+qlkatwftet 1 300 train
+qlkkdzwwmk 1 301 train
+qlknkxzsjx 1 300 train
+qlkqkosvap 1 300 val
+qlkuhkkpkx 1 300 train
+qlkzcdofbw 0 300 train
+qllcvajmzl 1 300 val
+qllhpepyum 0 301 train
+qllhzoysct 1 300 train
+qlllruitwc 1 300 train
+qlltgzkjyt 1 300 train
+qlmadkjjdp 0 241 train
+qlmdfgoely 1 300 val
+qlmtjbujjq 1 300 train
+qlmxnhiwzk 0 300 val
+qlndlhchqw 1 300 train
+qlnfexfowr 1 300 val
+qlnuvimwjj 1 300 val
+qlnuzkilpa 1 300 train
+qlnzqujlxy 0 300 val
+qloyrbpobv 1 300 test
+qlpnlkrumr 1 300 train
+qlppxrfbls 1 300 train
+qlpqgzgeyz 1 302 train
+qlpvmsbiqd 1 300 train
+qlpxhvlwuf 1 300 train
+qlqbkqjpbe 1 300 train
+qlqebstuou 1 300 train
+qlqhjcshpk 1 299 test
+qlrgypuumd 1 301 train
+qlrhhdeaju 1 298 train
+qlrnellhgj 1 300 train
+qlrnvefxho 1 300 train
+qlruueasjr 1 302 train
+qlrwofdstn 1 300 train
+qlrxdfyipx 1 300 train
+qlrzbtcbbh 1 298 train
+qlsgazlpfj 1 299 train
+qlsgmmzpll 1 300 train
+qlslomuczb 1 300 train
+qlslwvpsbh 1 300 train
+qlsognohlv 0 300 train
+qlsppxxrfh 0 300 train
+qlstcyptrk 1 300 train
+qlsvdhmqqt 1 300 val
+qlsvoedlsj 0 300 train
+qlszzijehf 1 300 train
+qltbzknwxj 1 301 val
+qltdvyiclt 1 296 train
+qltfpcrpbu 1 300 test
+qltjkhlmjo 1 300 train
+qltnzrhmnn 1 300 train
+qltolwckdw 1 300 train
+qltsgaqxfp 1 300 train
+qltulgxipp 1 300 val
+qltwksifcp 1 300 train
+qltxzfmikv 1 300 train
+qltyllmuug 1 300 val
+qluayjymoh 1 301 train
+qlucicvvst 1 300 train
+qluebrnvej 0 300 train
+qluekvmuuu 1 300 train
+qlueobbhbc 1 300 test
+qluijkvvpl 1 300 val
+qlvacgucnm 0 300 val
+qlvdrusajh 1 302 train
+qlvhphfill 1 300 val
+qlvmkwxwcq 1 301 train
+qlvsczvzsp 1 300 train
+qlvsqdroqo 1 299 test
+qlvtdetuto 1 300 train
+qlvvvgdzgo 0 299 train
+qlvxhguitr 1 300 train
+qlvyhzlxox 1 300 val
+qlvzzxaalc 1 300 train
+qlwakmlpnq 1 299 test
+qlwapziczb 1 300 train
+qlwbvwpuow 1 300 train
+qlwekbyqql 1 300 train
+qlwfgbivnp 1 300 train
+qlwkkyflpu 1 240 train
+qlwzbhejwp 1 300 train
+qlxcigukij 1 297 train
+qlxclapxup 1 300 train
+qlxdcgqdww 0 300 train
+qlxkjwlzwk 0 300 train
+qlxtcakhnu 1 300 train
+qlxthplibo 1 300 train
+qlxujdewuz 1 300 val
+qlxvyqepab 1 298 train
+qlxyddpujh 1 136 train
+qlyegjnxxk 1 300 val
+qlykqpcyze 0 300 train
+qlytukkgbl 1 300 train
+qlyztgznvf 1 300 train
+qlzdrhqjwa 0 300 train
+qlzfgzyuly 0 300 val
+qlzkylxvui 1 300 train
+qlzlofugok 1 300 train
+qlzshcqple 1 298 train
+qmaehrupub 0 300 train
+qmafvwqixq 0 300 train
+qmajtoiqoj 1 300 val
+qmamcpqxox 1 300 train
+qmasntuhuz 1 300 train
+qmawfruebo 1 300 train
+qmbcjegqjh 1 300 train
+qmbhopeksv 1 300 train
+qmbihytemw 0 300 train
+qmbjxqtgdm 1 300 train
+qmbvrwntlq 1 300 train
+qmbzovoorj 1 300 train
+qmcayvmezs 1 300 val
+qmccqwtbqj 1 300 val
+qmcdpwplms 1 299 train
+qmchqfrycq 1 299 val
+qmcjofgpso 0 300 train
+qmcmwrqzhu 1 300 val
+qmcowinuvi 0 300 train
+qmcrfhgbsn 1 300 train
+qmdidlruuf 1 298 val
+qmdqgeienp 1 300 train
+qmdvgkxpdg 1 300 train
+qmecpgloub 1 300 train
+qmeidtdmbz 1 300 train
+qmeitgqfdq 1 300 val
+qmeslywzuy 1 300 train
+qmewfojuij 1 300 train
+qmfgajwndp 1 300 train
+qmfidjhnwb 1 298 train
+qmfnpmddeq 1 300 val
+qmfumjrmir 1 300 train
+qmfwopzxet 1 300 val
+qmfxkopdpj 1 300 train
+qmfxxsppvd 1 300 test
+qmggllewyw 1 300 train
+qmggrtevft 1 300 train
+qmghsvfqoc 1 300 val
+qmgkqdvmfl 0 300 train
+qmgyrjhtft 1 300 val
+qmhakuwxky 0 300 train
+qmhcpivqct 1 300 train
+qmhepooczx 1 167 train
+qmhjedcfbb 1 301 train
+qmhlbwpium 1 300 train
+qmhspzoqml 1 297 train
+qmhvvzwfjr 1 300 train
+qmibuzwwfk 1 300 train
+qmichcfsci 1 300 train
+qmidpmsgsu 0 300 train
+qmieoubnwr 1 300 train
+qmifyvokds 0 300 train
+qmiipltnbv 1 300 train
+qmipdlsgzc 1 300 train
+qmiqffaqkl 1 300 val
+qmiqxayknw 1 300 train
+qmitaqtqbj 1 297 val
+qmivkdeert 1 300 train
+qmjdiocliw 1 296 val
+qmjffjebve 1 300 train
+qmjgfnmmgu 0 300 train
+qmjrbzbphe 1 300 train
+qmjtvuofjt 1 300 val
+qmjzmtnpma 1 300 val
+qmkhxkkdla 1 300 train
+qmkihvyqmj 0 300 train
+qmkpqgkxvu 1 300 train
+qmkracngvu 1 301 train
+qmkvwzhxyb 1 302 train
+qmkzyouvlk 1 300 val
+qmlbfwtyhj 1 300 train
+qmlfzgampj 0 300 train
+qmlijogtyi 1 300 train
+qmlkqfwxoy 1 300 train
+qmllagrlqh 1 300 train
+qmlqgdkixu 1 300 train
+qmlshbcgqz 1 300 train
+qmlyoftbqg 1 300 val
+qmmeayhyph 1 300 train
+qmmjdgfcwd 1 300 train
+qmmpikwetb 1 240 train
+qmmrgkejli 1 300 train
+qmmxwozpgx 1 300 train
+qmmzklpowl 1 300 test
+qmnavfujpk 0 300 train
+qmnorkttjj 1 300 train
+qmnxrxchdq 1 300 train
+qmnzmglufm 1 300 train
+qmobnwdmpo 0 300 train
+qmofjcazrf 1 301 train
+qmofvlylbv 1 300 train
+qmohlplkhq 1 301 train
+qmomfbzxyn 1 301 train
+qmonskilte 1 300 train
+qmooxhqpui 0 300 train
+qmotssycti 1 300 train
+qmouaqpkll 1 300 val
+qmoxippfmp 1 300 train
+qmpbladznr 1 300 train
+qmpeuuojbz 1 300 train
+qmpgekcwer 1 300 train
+qmpixcbcic 1 300 train
+qmpjwtyoya 1 300 train
+qmpkirynaf 1 300 train
+qmpmuxtfsn 1 300 train
+qmpsjnkngn 1 300 train
+qmqbrbarea 1 300 val
+qmqcefbthj 1 301 train
+qmqcnvoylp 1 300 train
+qmqeegyqct 1 300 val
+qmqfqyqmfx 1 300 train
+qmqgfjgnji 1 300 val
+qmqgmozyjm 1 136 train
+qmqjoqbfcn 1 300 train
+qmqjtabtaf 1 300 train
+qmqlgobfhn 1 300 train
+qmqoprzuhw 0 300 train
+qmqpgawtcc 0 300 train
+qmqraeuuxo 1 300 train
+qmqylztxuk 1 300 train
+qmqyqblejn 1 300 train
+qmqzjkmxgw 1 301 train
+qmraflnpfv 1 300 train
+qmrofeopey 1 300 train
+qmrxehtvsc 1 240 train
+qmscispuji 1 300 train
+qmsdrcgima 0 300 train
+qmsqtzzkwz 1 300 train
+qmsrebyika 1 300 val
+qmsxwsqsqn 1 300 val
+qmtbmvcvhb 1 299 val
+qmtchqhakj 0 300 train
+qmtjlksrbs 1 300 train
+qmtouvuniv 1 300 train
+qmtzrixfaf 1 301 val
+qmuesbacjp 1 300 train
+qmuhbyclhk 1 300 train
+qmuojetavs 0 301 train
+qmuzoudtvv 1 300 val
+qmvribjjvz 1 301 val
+qmwdtgoill 1 300 train
+qmwfkqpzht 0 300 train
+qmwjglozeh 1 298 train
+qmwjjozruz 1 301 train
+qmwjpsvdoe 1 300 train
+qmwmsmevli 1 300 val
+qmworbjopm 0 300 train
+qmwpmtjkew 0 300 train
+qmwqnrhhyl 0 241 train
+qmwwmyirzr 1 300 train
+qmxbfsswdg 1 300 train
+qmxkbjfrbs 1 269 train
+qmxljrjjrs 1 300 train
+qmxlslwqaq 1 300 train
+qmxoxpshxl 1 300 train
+qmxryaxhue 1 300 train
+qmxzdqguuv 1 296 val
+qmxznylkcy 1 300 train
+qmybplcltn 1 300 train
+qmydljemri 1 300 train
+qmydvrenkd 1 300 val
+qmyelrpvbz 1 302 train
+qmyeokbdtf 1 300 val
+qmyltzdawo 1 300 train
+qmypodqylm 1 301 val
+qmyvdcrrmg 1 300 train
+qmyxlogtye 0 297 train
+qmyyjvahqn 1 300 train
+qmyykfinod 0 300 val
+qmyyqelqlk 1 300 val
+qmzezihwkm 1 241 train
+qmzfcdmzlr 1 300 train
+qmzlcvygun 0 300 val
+qmzucjfbrm 0 300 train
+qmzvdpjzag 1 300 train
+qmzvnovhwv 1 300 train
+qmzyeblmom 1 301 train
+qnaaropcyi 1 300 train
+qnaavgdrgi 1 300 train
+qnafoptykj 1 300 train
+qnagmkkjqz 1 300 train
+qnaherlopv 1 301 val
+qnahmrwqzl 1 300 val
+qnailvsuly 1 300 val
+qnajyrcpzk 1 300 train
+qnakezygow 1 300 train
+qnannztfqx 1 301 val
+qnaqahotum 1 240 val
+qnaqcjmssv 1 300 train
+qnaqizzzdp 1 297 val
+qnashjggkr 1 298 train
+qnaukjpqns 1 300 val
+qnavkdckzr 1 300 train
+qnavwelumi 1 298 train
+qnawsrxueg 1 300 train
+qnaxmhylhs 1 300 train
+qnbadxgzqm 1 300 train
+qnbehhanzz 0 300 train
+qnbjuzyvgi 1 300 train
+qnbnlmpqpu 0 301 train
+qnbppiapar 1 300 val
+qnbxhdufkr 0 300 val
+qncbvzovqu 1 300 train
+qncisquriq 1 300 train
+qncnpxdpqc 1 298 train
+qncvtujrng 0 300 train
+qncxpokutx 1 299 val
+qndejzlinr 1 301 train
+qndirwgpxt 1 300 train
+qndwycufke 1 299 train
+qndzhbrbds 1 300 train
+qnehneyxlu 1 300 val
+qnejnslsvj 1 300 val
+qnenlegpxk 1 300 val
+qnepdvqrrp 1 300 train
+qnesvosgbr 1 300 val
+qneyyxushu 1 99 train
+qnfuimgzmx 1 300 train
+qnfuuxtify 1 300 train
+qnfwzalyfz 1 300 train
+qnfzvbdsbk 1 300 train
+qngaddilqt 1 300 train
+qngcaxeqry 0 300 train
+qnghrfvbgb 1 300 test
+qngowoldjd 1 300 val
+qngsngievt 1 300 val
+qnguklblax 1 299 val
+qngveotoav 0 300 val
+qnhaxahmnr 1 300 train
+qnhbpidutk 1 241 train
+qnhcmscgzg 1 300 train
+qnhtcwjooa 1 298 train
+qnhudksiag 1 300 val
+qnhwftiogd 1 300 train
+qnhyvrwthb 1 300 train
+qnielttwwe 1 300 val
+qnifatwznk 0 300 train
+qnilaqoaui 1 301 train
+qninuljfwo 1 300 train
+qnioelzjxr 0 300 val
+qnipxkjinu 1 300 val
+qnixmqrjmj 1 300 train
+qnjdjpypvb 1 300 train
+qnjggzgiuc 1 300 train
+qnjkelywea 1 300 train
+qnjnyauxdy 1 300 train
+qnjxnkncoh 1 300 train
+qnjzmxrsrs 1 300 val
+qnjzruxibf 1 300 train
+qnjzxqcwlh 1 300 train
+qnkskuqvlo 1 300 train
+qnkvjufsyp 1 300 val
+qnkxdacjjg 1 301 val
+qnlbcsnxvb 1 300 train
+qnldzdtkvo 0 300 train
+qnlepsrqph 1 300 train
+qnllzpnmjl 1 300 train
+qnlmlqisdo 1 300 train
+qnlnghmgkw 1 300 train
+qnlyrlrnmn 1 300 test
+qnmdsymmqc 0 301 train
+qnmedwwzka 1 299 train
+qnmifyljpy 1 302 train
+qnmniaopcn 0 300 train
+qnmpnkqnfp 1 300 train
+qnnbrplkon 1 302 train
+qnngnvkplz 1 301 train
+qnnnvkzfzp 1 300 train
+qnnratpkqg 1 300 train
+qnntfbdyqq 0 300 val
+qnnyxjpvps 1 300 train
+qnoatpxxae 1 298 train
+qnobktyvaw 1 300 train
+qnoiswwhld 1 300 train
+qnolbkizuh 1 300 val
+qnonqqblue 1 300 val
+qnopoljjrl 0 300 train
+qnorpipnfm 1 300 train
+qnotyzkjom 0 300 train
+qnplktsfcp 1 300 val
+qnpqyazrfq 1 300 train
+qnpsikebde 0 297 train
+qnpxtqzgmt 1 300 train
+qnqqlhpktl 1 302 train
+qnqqqmblqj 1 300 train
+qnrbcvboqx 1 300 train
+qnrfzfxaae 0 300 train
+qnrhxvjesz 1 300 train
+qnrmeedsey 1 300 train
+qnrpcnxmdv 1 300 train
+qnrqnchkwn 1 300 train
+qnrqxcyjea 0 300 train
+qnrsjkazcc 1 300 train
+qnrthdzkyg 1 241 train
+qnrucaffzr 1 301 train
+qnruupnxxu 1 300 train
+qnrxvoxrxz 0 300 train
+qnsiakkqlb 1 298 train
+qnskfcawdb 1 300 train
+qnslgeajnt 1 300 train
+qnsqiausbj 1 300 val
+qnsuboqpfw 1 298 train
+qntlplbbvr 0 300 train
+qntmamtovw 0 300 train
+qntpalcjor 1 300 train
+qntxxnkqkb 1 300 train
+qnuagpcukx 1 300 train
+qnufhukqnx 1 300 train
+qnuhltujpb 1 300 train
+qnuijlbbma 1 300 train
+qnuqtsojbg 1 300 val
+qnussffnxl 1 300 val
+qnvaijybyo 1 300 val
+qnvbsecznf 1 300 train
+qnvhjktmdo 0 300 train
+qnvipsinla 1 300 val
+qnvjmuhqif 1 300 train
+qnvmkjbnfp 1 241 train
+qnvpzdhfyc 1 300 train
+qnvwcaviel 1 300 val
+qnwglgnnec 0 300 train
+qnwjynmypb 1 298 train
+qnwplgpjcg 1 300 val
+qnwrcomndg 1 300 val
+qnwrwwbeia 1 300 train
+qnwsmqpuao 1 300 train
+qnwtpnnjif 1 300 train
+qnwvsyirjy 0 300 train
+qnwxkohbgz 1 300 train
+qnxgwttuzv 1 300 train
+qnxhwnmbsb 1 300 train
+qnxmglaoka 1 297 val
+qnxnrzonvv 1 300 test
+qnxqnoausv 0 300 train
+qnxrpppmsn 1 300 train
+qnxrxflnou 1 300 train
+qnxsrvcyxp 1 300 train
+qnxthlwtnd 1 300 val
+qnxyrntvsj 0 300 train
+qnxyumzeve 1 300 val
+qnxzramtox 1 300 train
+qnyfkruais 1 300 val
+qnygjjuhwp 1 300 train
+qnygqqsuda 1 300 train
+qnyhkzylfn 1 300 train
+qnypdambva 0 300 train
+qnyprujmbv 0 300 train
+qnypwrzkwi 1 300 train
+qnyxdmsuyf 1 300 train
+qnyxjefvco 1 300 train
+qnyyakvufb 1 301 train
+qnyzelwyjh 1 300 train
+qnzffjwxxy 0 300 val
+qnzjwsppwd 1 240 train
+qnzksykzlc 1 300 train
+qnzlzrntkx 0 300 train
+qnznfiqpmi 0 300 train
+qnzrmlnexu 1 298 train
+qoalrzguua 1 300 train
+qoalwspkzc 1 300 val
+qoanpyvmaw 1 300 val
+qoasfzksgo 1 300 train
+qoavoxkwfn 1 300 train
+qoaxnacjgl 1 300 train
+qobunxjtio 1 299 test
+qobyqhmqgu 1 300 train
+qobytwcryc 1 300 test
+qoccrnafqj 1 300 train
+qochkdutxy 1 300 train
+qockiexese 0 300 train
+qocoeiihvb 0 300 train
+qocxdsvjka 1 301 val
+qoczixthmr 1 300 train
+qodbckqtye 1 240 train
+qoddkufnto 0 300 train
+qoddwlvmlb 1 300 train
+qodhawquub 0 300 val
+qodmojlgxx 1 300 train
+qodskintkl 1 300 train
+qodykiwotk 1 300 test
+qoejwusmgs 1 300 train
+qoeowmrexg 1 300 train
+qoewcpprkw 0 300 train
+qoewfrqljx 1 300 train
+qoeyikcmnc 1 300 train
+qoezejzwtf 1 300 train
+qofgcsmeqp 1 300 train
+qofgicylsa 1 300 train
+qofgvuhkeq 1 300 train
+qofsyeabhp 1 300 train
+qoggumwuoz 1 298 val
+qoggyloxol 1 300 train
+qognlahzpa 1 300 train
+qogxnjcrcl 1 300 val
+qohdhuuhxr 0 300 train
+qohfdtjyds 1 300 train
+qohfmypklp 1 241 train
+qohhhhkzyw 1 300 train
+qohlimlizt 1 300 train
+qohooxdwvh 0 300 val
+qohqennihb 1 300 train
+qohrezecko 1 300 train
+qohtjkzity 0 300 train
+qoienvsltv 1 300 train
+qoihghfryp 0 300 train
+qoilbspzmh 1 300 val
+qoioohxuga 1 301 train
+qoitslaoaf 1 300 train
+qoixdznnyf 1 300 train
+qoiydfuczw 1 300 train
+qojbgkxnac 1 300 train
+qojekebyww 1 300 train
+qojgeidoat 1 300 train
+qojgphkqyz 0 300 train
+qojquiczlp 1 298 train
+qojycogodr 0 300 train
+qokdbiolgs 1 300 train
+qokhivrdmq 1 298 val
+qokisvxfsj 0 300 train
+qokntutfen 1 300 train
+qokuqjbpji 1 300 train
+qokvxsjtbs 1 300 train
+qokxxuayqn 0 300 train
+qoldmdyxqs 1 300 val
+qollefgenu 1 300 val
+qolmlyecjj 1 300 val
+qolpuoqnrl 1 300 train
+qolsrevzid 1 300 train
+qoluylsxho 1 300 train
+qolyxqlefl 1 300 val
+qomddxzjqk 0 300 val
+qonihxkeqb 1 300 train
+qonoflvgou 1 300 train
+qonorwhmkk 1 300 val
+qonwqdnlwl 1 241 train
+qonxvjqguv 1 300 train
+qoobopwqdh 1 300 train
+qoodqgyteo 1 300 train
+qoogcaveqk 1 300 train
+qoohgmtwqz 1 300 train
+qoomojjzps 1 300 val
+qooqfrnije 1 300 train
+qooxnxqqjb 0 300 test
+qoozinpwwy 1 300 train
+qopocadpmr 0 300 train
+qoptapgmcd 1 298 train
+qopzjdzapa 1 300 train
+qoqhybtpce 1 300 train
+qoqiztyyvg 1 300 train
+qoqnejndnj 1 300 train
+qoqnwrfvty 0 300 val
+qoqszykwzq 1 300 train
+qoquiszdvo 1 300 train
+qorekzqhle 1 300 train
+qorkhuszpj 1 300 train
+qorlmhzzij 1 300 train
+qormsicjig 1 300 train
+qormslhpqt 1 300 train
+qorrcqtvzh 1 302 train
+qoruzoamkv 1 300 val
+qorwhbylgz 0 300 train
+qorxkksejn 1 300 train
+qorxoylihq 1 300 train
+qoryfspcrz 1 300 val
+qorytsanvq 0 300 train
+qosfozkrro 1 300 val
+qosgkfxfuv 1 300 train
+qosizsmowb 0 300 val
+qoslholkxc 1 300 train
+qosnwseemh 1 300 train
+qoswldklie 1 290 train
+qosynfrcih 0 302 val
+qoszqldspb 1 299 val
+qotakuiydq 1 300 val
+qotgffzjzo 1 300 train
+qotmcdlyar 1 300 train
+qotqjzqlnr 0 300 train
+qotqrohjzr 1 300 val
+qottvtdiqy 1 300 train
+qotxloqhna 1 300 train
+qougfhiqze 1 300 train
+qouibdtenz 0 300 train
+qousvzlqvn 1 302 train
+qouurihyah 1 300 train
+qouyvocdrs 1 300 val
+qovboadqci 1 300 train
+qovlsylaql 1 300 train
+qovooqrinp 1 301 train
+qovpidorer 0 300 train
+qovsqozmtz 1 300 train
+qovttefwmn 1 298 train
+qovwhhmcfv 1 300 train
+qowjcixqji 1 300 train
+qowkhqmzam 1 300 test
+qowlgbwbqd 1 298 train
+qowtrgujpd 1 300 train
+qowwbxhjos 0 300 train
+qowxmuafis 0 300 val
+qoxeqixeck 1 300 train
+qoxipuugyo 1 300 val
+qoxjeaywhv 0 300 train
+qoxjqdxwxk 1 300 train
+qoxjrysuxg 1 300 train
+qoxnjztdty 1 300 train
+qoxpedkjyn 1 300 train
+qoxpmwnzxp 1 300 train
+qoxpqghyaj 1 300 train
+qoxpxajrlu 1 300 train
+qoxxdwpogi 0 300 train
+qoxywpegvq 1 300 train
+qoyabvyiiu 1 300 train
+qoyfkewpyh 0 300 val
+qoynaixfuu 1 300 train
+qoywhyrcjw 0 300 train
+qoyxcxtdld 1 300 train
+qozedxjziq 0 300 train
+qozhbqrujz 1 300 train
+qozvbhudar 1 300 train
+qozxffebjc 1 300 train
+qozzzicozo 1 300 train
+qpadalellh 0 241 train
+qpagahcewf 1 300 train
+qparfnuxsg 0 300 train
+qparmdkxul 1 300 train
+qpawsjhhrt 1 300 train
+qpbbuzzsmh 1 300 train
+qpbksklnpr 0 300 train
+qpbqnhmjpq 1 300 val
+qpbrjjfhyx 1 300 train
+qpbrknxeci 1 300 val
+qpbrwqllst 1 241 train
+qpbssjlbgf 0 300 val
+qpbtdjczoz 1 288 train
+qpbzdltdxm 1 255 train
+qpcerduowt 1 300 train
+qpcgkqdydv 1 299 test
+qpchzgfrpn 1 300 train
+qpclghgnrh 1 298 train
+qpcngtbrkh 1 300 train
+qpcnsacdug 1 302 train
+qpcrmlkmmi 1 300 train
+qpcvbyixyu 1 300 train
+qpcwnuqpvo 0 300 train
+qpcxurbqbw 1 300 train
+qpdcbftcff 1 300 train
+qpdceyusud 1 300 train
+qpdoiljqwk 1 300 val
+qpdpmyccxr 1 301 val
+qpdsjtcinf 1 300 val
+qpdtegajev 1 300 train
+qpduehyfqj 1 300 val
+qpdulmrqzo 1 300 train
+qpdyttlkyu 1 241 train
+qpehnbrbgn 1 300 train
+qpejmvfmsu 1 300 train
+qpeldtspzn 1 300 train
+qpesrfohjg 1 300 train
+qpeuuengtx 0 300 train
+qpevfrkxbn 1 300 train
+qpeyrejuyw 0 300 train
+qpfadurkaz 1 300 train
+qpfbybxerb 1 300 val
+qpfgjhbgub 1 300 train
+qpfihmnqth 1 298 train
+qpflszinsf 1 300 train
+qpfncztgki 1 300 train
+qpfptydstc 1 300 train
+qpfsxadgac 1 300 train
+qpftobdznt 1 300 train
+qpfxypliml 1 300 train
+qpfyfxcnht 1 241 train
+qpgbjptbbl 1 300 train
+qpgcdkfxuf 1 300 train
+qpgdcsfnqx 1 300 train
+qpgfhsmrnl 1 300 train
+qpgqabxanh 1 300 train
+qpgxiukrbf 1 300 test
+qpgxsixzag 1 241 train
+qphlxprwtm 1 300 train
+qphmrbybfy 1 300 val
+qphnhhdywk 1 300 train
+qphtffkvrv 1 300 train
+qpicftiubt 1 300 val
+qpicuticrb 1 300 val
+qpidodqzhy 1 300 train
+qpifwyqodx 0 300 train
+qpiglwpyfb 1 301 val
+qpiiostyab 1 300 train
+qpiivfetmk 1 300 train
+qpioktwuue 1 300 train
+qpiuwkehpc 1 300 train
+qpiwothmpz 1 300 train
+qpjdazinjc 1 300 val
+qpjjgcmpnl 1 300 train
+qpjldfksqp 1 300 val
+qpjsxkfncj 1 300 train
+qpjuficohz 0 300 train
+qpjuqzeelk 0 300 train
+qpkfrvfuhv 1 300 train
+qpkhdvcqkw 1 300 train
+qpkqxppgbs 1 300 train
+qpkqyuiiee 1 298 train
+qpkrdmotdk 1 300 val
+qpkxpzfhei 0 300 train
+qpkznotaih 1 300 val
+qplghdvrkz 1 300 train
+qpllynnmdd 1 300 val
+qpluummakg 1 300 train
+qplyzcfavt 1 300 val
+qpmagegtbs 1 300 train
+qpmepdhqlv 0 300 train
+qpmfyjtkld 1 296 train
+qpmhnuvprc 0 297 val
+qpmilbhwuu 1 300 train
+qpmlotpzww 1 300 train
+qpmovegayu 0 300 val
+qpmtqbnguc 0 296 train
+qpmvwhozfc 0 300 train
+qpncfrjtdv 1 301 train
+qpnhhjazya 1 300 train
+qpnpitvios 1 300 train
+qpnqenncmj 1 300 test
+qpobbumrhm 1 300 test
+qpokaqevty 1 300 train
+qpopbbyxfa 1 300 train
+qpopfoykiv 1 301 train
+qposgsibtu 1 300 train
+qpoxmwsmro 1 300 train
+qppjjwvfbg 0 301 train
+qppmjvtrsi 1 301 val
+qppnwoodzt 0 301 train
+qppqflphhz 1 300 val
+qpprvfrmun 1 241 train
+qppscmsdgx 1 300 train
+qppxqiciew 1 298 train
+qpqgjwpbbq 1 300 val
+qpqozdlxgv 1 298 train
+qpqpmaqhtj 1 300 val
+qpqrgfytup 1 300 train
+qprdefhnbv 0 300 train
+qprpaintta 1 300 val
+qprrlvwpxn 1 300 train
+qprtbkloye 0 298 train
+qprxxttbnl 0 300 train
+qpsjlloqzn 1 240 train
+qpssfjytgk 1 300 train
+qpstcrmthz 1 298 train
+qptbhixmql 1 300 train
+qpthjnyuuz 1 300 train
+qpthqdhucj 0 300 train
+qptkhfnocw 0 249 train
+qptmaymgpz 1 300 train
+qptnyduigz 1 300 train
+qptogrvbcp 1 300 train
+qpttgwtqxo 0 300 train
+qptthjmomb 1 301 train
+qpuahtczie 1 300 train
+qpuejqfxgr 1 300 train
+qpuhhveyoj 1 300 train
+qpuhwuodnm 1 300 train
+qpuqrfwooq 0 300 val
+qpuuoebket 1 300 val
+qpuvmliiad 1 300 train
+qpvdkhuxje 1 300 train
+qpvgdzncxe 1 300 test
+qpvpmoblwo 1 300 train
+qpvtbobmmd 0 300 train
+qpvusdcyzn 1 300 train
+qpwmrzhjhg 1 300 train
+qpwxogyrdk 1 300 train
+qpwzmbqafu 1 300 val
+qpxexbtrma 0 300 train
+qpxfpesjlh 1 296 train
+qpxicfhtms 1 300 train
+qpxpdimykl 0 300 val
+qpxqyrfwec 1 300 val
+qpxzuzaoan 1 298 val
+qpydfpclkp 1 301 val
+qpyhstoxnw 1 300 train
+qpyigyrafw 1 300 val
+qpyjhumisp 0 300 val
+qpykonptfx 1 300 train
+qpynrfdsaf 1 301 train
+qpynyxqpfq 0 300 train
+qpyolptuqc 1 300 train
+qpysfrjzjg 1 300 train
+qpzkmyvonm 1 300 val
+qpznygskpt 1 300 train
+qpzzmipkvr 1 300 train
+qpzzzncyza 1 300 train
+qqaanohkkf 0 300 train
+qqabvnilld 1 302 train
+qqagsgedni 1 300 train
+qqaugefeit 1 300 train
+qqavuffanf 1 300 train
+qqaxpxxpyj 1 241 train
+qqbdbidpca 1 300 train
+qqbhnibrwx 0 300 train
+qqbiqodhwl 1 288 train
+qqbizlufok 1 300 val
+qqbjxjzefk 1 300 train
+qqbsgnmpko 1 300 train
+qqbuqqoeal 0 300 train
+qqbwqetyta 1 300 train
+qqcodichfr 0 300 train
+qqcpraqdqw 1 296 train
+qqcsbjmvfn 1 300 train
+qqcshzwwdg 1 300 train
+qqcwxozecp 1 300 val
+qqcythnsfu 1 300 train
+qqdfsbkfbo 1 300 train
+qqdjtkcbps 1 301 train
+qqdkguczpc 1 298 train
+qqdlowagvn 1 300 train
+qqdobobila 1 100 train
+qqdrmpzcqr 1 300 train
+qqedzczizc 1 300 train
+qqeeqpsnfh 1 300 train
+qqeiegxafi 1 300 val
+qqeiydqswz 1 300 train
+qqemspwnxp 1 299 train
+qqenjmwpep 1 300 train
+qqewdrlakt 1 300 train
+qqeysoevjt 1 300 train
+qqfmqogypv 1 300 train
+qqfogdstzm 1 300 train
+qqfrhlputc 1 300 train
+qqgashfzig 1 300 train
+qqgbdhrjcf 1 300 train
+qqgbiwevcp 1 300 train
+qqggnhzxmb 1 300 val
+qqgqxhgznp 1 300 train
+qqguyiauww 1 300 val
+qqgxawsnlj 1 300 val
+qqhcdypoaf 1 300 train
+qqheewjvsj 0 301 train
+qqhigpesbt 1 300 val
+qqhjdfkbjp 1 297 train
+qqhnpgzfxj 1 300 train
+qqhrtjjcgr 0 300 val
+qqhxdlxqxi 1 300 train
+qqibjuelja 1 301 train
+qqiedmmibt 1 299 val
+qqifulqlhw 1 301 val
+qqinvatvkt 1 300 train
+qqisdvvgfi 1 299 test
+qqisrgnngt 1 300 train
+qqiudnamfi 0 300 train
+qqjcirwwyi 1 299 val
+qqjfbzewvy 1 300 train
+qqjjlfichi 1 300 val
+qqjmgyicqe 1 300 test
+qqjnlscjmu 1 300 val
+qqjntwygwa 1 239 train
+qqjqodwaap 1 298 train
+qqkdyqiekp 1 300 train
+qqklpwukuf 1 300 train
+qqknlqejlp 0 300 train
+qqkpszkrqm 1 300 train
+qqkstkdaps 1 297 train
+qqkvcggekq 1 300 train
+qqkvodfenu 0 300 train
+qqkyznondw 1 300 train
+qqlrnamptt 1 300 train
+qqlwrbdvrl 1 300 val
+qqlznnnixn 0 300 val
+qqmdtfmife 1 300 train
+qqmifvppeh 1 300 train
+qqmkybtkns 1 300 train
+qqmobtuenw 1 300 val
+qqmrhyftwz 1 300 train
+qqmtdomqde 1 300 train
+qqmvuyirxs 1 300 train
+qqmwalyugi 1 300 train
+qqmwvgoznm 0 300 val
+qqnfqxjxru 1 300 val
+qqnhgtftxw 1 300 train
+qqnlrngaft 0 300 test
+qqnpgbhbog 1 300 train
+qqoczyrgyo 1 300 val
+qqoffwakaw 1 300 train
+qqohmvgqhg 1 300 val
+qqokpshvil 1 300 train
+qqolhciztc 1 298 train
+qqontzpfxr 1 300 test
+qqopsjndxz 1 241 train
+qqopzjovpo 1 300 val
+qqpemybxbc 1 300 train
+qqplrvxzjq 1 298 train
+qqpnvkqgzz 1 300 train
+qqpxqqwyzt 1 300 train
+qqqdidtvja 1 300 train
+qqqfldwehi 1 300 train
+qqqfrgcnsb 1 300 train
+qqqfvitexk 1 300 val
+qqqvmcwnrc 1 300 val
+qqqwvktntk 1 302 val
+qqqyeipyhu 1 300 train
+qqradmkuzc 1 300 val
+qqraqwhjoh 1 300 train
+qqrbrktugb 1 300 val
+qqrfjzdcqt 0 300 train
+qqrmcprbvd 1 300 train
+qqrnrgqvbn 1 300 train
+qqrnypeprj 1 299 train
+qqrpauxfqn 1 300 train
+qqrqlucpeo 0 301 val
+qqrvyhjznq 0 300 train
+qqsadmeqrr 1 300 train
+qqsgwigpzb 1 241 train
+qqsgyjtbmb 1 300 train
+qqsqhjiskm 1 300 train
+qqtddqoxoc 1 300 train
+qqtkxotuqs 1 300 train
+qqtlwnfjwt 1 300 train
+qqtoccrfzs 1 300 train
+qqtpfeutmo 1 300 train
+qqtqjlkqwp 1 300 train
+qqtqmcybcn 1 300 train
+qqtwebjicx 1 300 train
+qqtweqhhtj 0 300 train
+qqtyrvuqpz 1 300 train
+qqtyxwfhpa 1 300 train
+qqujivuvxv 1 298 train
+qqumeyaysj 1 300 train
+qquuumylek 1 300 train
+qquxhrfohe 1 300 val
+qqvdlzfqib 1 300 train
+qqvlvuouft 1 301 train
+qqvysrslyg 1 300 val
+qqwdbhkgol 1 301 train
+qqwoqhvamz 1 301 train
+qqwpvqxnqg 1 300 train
+qqwsabrgxh 0 300 train
+qqwtwtceri 1 298 train
+qqxbgedxdk 0 300 train
+qqxelyjmmw 1 300 train
+qqxohuaupb 1 300 val
+qqxrpfqhyz 1 300 train
+qqxwjdqkll 1 300 train
+qqxzbhmqnk 1 300 train
+qqycxjzfxj 1 300 val
+qqygbffevh 1 300 val
+qqyhdcrsqc 1 300 val
+qqyjxknjuo 1 299 train
+qqykkzbcol 1 300 train
+qqyrzwwsyk 1 300 train
+qqzcqdpdbq 1 300 train
+qqzfwbguzo 0 300 train
+qqzfztcrif 0 300 train
+qqzjlyusyj 1 300 train
+qqzlflimyw 1 300 train
+qraarjjoac 0 300 train
+qrabiakhvo 1 300 train
+qrajtbrmqf 1 300 val
+qrajuyzyxy 1 300 val
+qranzyoqdn 1 300 train
+qrapcrmpgr 1 300 val
+qrapjvhoxj 1 300 train
+qravzkjego 1 300 val
+qraxizidol 1 300 train
+qrbdmfcchh 1 300 train
+qrbdowyzrp 1 300 val
+qrbejdqnkb 1 301 val
+qrbffcxiel 1 300 val
+qrbjzzpunu 0 300 train
+qrbpkxbaeh 0 300 train
+qrbravowxo 0 302 val
+qrbrioqccb 1 299 train
+qrbshgpskd 1 241 train
+qrbwcoklmh 0 300 train
+qrccnamwfv 1 300 train
+qrcotgkrhb 1 300 test
+qrcwkvufjq 1 300 train
+qrdfjbbqkp 1 300 train
+qrdkajruxs 1 301 train
+qrdvnggsfv 1 301 train
+qrdwswxeky 0 300 val
+qreeovjmfd 0 300 train
+qresptsjop 1 300 train
+qrezkkaymo 1 300 train
+qrffxlivhp 1 300 train
+qrfncgmtqj 1 300 train
+qrfrrpxijg 1 300 train
+qrfsoqruhn 1 300 val
+qrftequyly 1 300 val
+qrfufmhaaw 1 298 train
+qrfxgrivwa 0 300 val
+qrgerfuzwe 1 300 val
+qrgezzxkzw 1 300 val
+qrgfafwmvb 1 300 train
+qrgilgikga 1 300 train
+qrgmmaiayq 1 300 val
+qrgnctxitp 0 300 train
+qrgrezupjj 1 300 test
+qrhoztkodu 1 300 val
+qrhsnefequ 1 300 train
+qrhwwnlutq 1 300 train
+qriclwybjs 1 99 train
+qricozphfk 1 300 train
+qricsifpkl 1 300 train
+qridkwzbgu 0 300 train
+qriicptrta 1 300 test
+qrinvxwnxz 1 301 train
+qriusqtwkt 1 300 train
+qrivxgwqga 1 300 train
+qrizbzenzg 1 300 test
+qrjaqnkhyp 1 301 val
+qrjasxlfod 1 300 val
+qrjestcmhc 1 300 train
+qrjhrwibwc 0 300 val
+qrjifnyzbv 1 300 val
+qrjspdgjgl 1 300 val
+qrjydgidga 0 300 val
+qrjyrvywwd 1 300 train
+qrkjzekzkc 1 300 train
+qrkvtrsnoq 1 300 val
+qrlaplhufl 1 300 train
+qrlfqcpnvv 1 300 train
+qrlggibjzu 1 298 train
+qrllzgwift 1 300 train
+qrlsfqdpiu 1 300 val
+qrluazojdx 1 300 train
+qrlvebnfwo 1 300 val
+qrmexadhug 1 300 train
+qrmgfosriq 1 298 train
+qrmukphmzh 0 300 val
+qrmwydlgcy 1 300 train
+qrnaekswrx 1 300 train
+qrnbmdgynf 1 300 train
+qrncyiybxg 1 300 train
+qrncyqoibh 1 297 val
+qrnjmhzfth 1 300 train
+qrnksxuegi 1 297 val
+qrnmvmbqxo 0 241 train
+qrnvgyznns 1 300 train
+qrnwrjqfbv 1 300 train
+qrogkembje 1 300 test
+qrogzlkzfi 1 300 train
+qroyvjcvhd 1 300 train
+qrpaaityqn 1 300 train
+qrphrcohbk 1 300 train
+qrpidduqmh 1 300 train
+qrpjgxnydx 1 300 train
+qrpolmejsl 1 300 val
+qrpoyppdgo 0 300 train
+qrptqjimaj 1 300 val
+qrpzlxhcwu 1 300 train
+qrqdfjsxcs 0 300 train
+qrqezvukut 1 240 val
+qrqhttdesi 1 300 train
+qrqmizsfdb 1 298 val
+qrqpvuqgld 1 300 train
+qrqsmyhwmk 1 300 train
+qrqywgvnzu 1 300 train
+qrrbuexwry 1 300 val
+qrrheadxbj 1 300 train
+qrrlicqepo 0 300 train
+qrrpghwqxj 1 300 train
+qrrtieahbx 1 300 train
+qrrwhhhiqn 0 300 val
+qrrydlbefo 1 300 train
+qrrywyhvir 1 300 train
+qrsgmacyfs 1 300 train
+qrskwfuerk 1 300 train
+qrssrcmzzq 0 300 val
+qrstthlqfn 1 300 train
+qrsvsbpjze 0 300 train
+qrswwstcvq 1 300 train
+qrsxqnrhbm 1 296 train
+qrtbuyiaas 1 300 train
+qrtoobohkm 1 300 train
+qrtudzgxmy 1 300 train
+qrtulookgl 1 300 train
+qrubhcdcou 1 300 train
+qrublmrbiv 0 300 train
+qrucsosyns 1 301 train
+qruifuklcy 1 300 train
+qrupnzlffr 1 300 train
+qruqeimjfv 1 300 train
+qruuruircl 1 300 train
+qrvdasxngx 1 300 train
+qrvnowqofr 1 302 train
+qrvptemnso 0 300 train
+qrvrwipzgv 1 300 val
+qrvxnmzyqj 1 299 val
+qrvymyxkwl 1 300 train
+qrwcrrbnjt 1 300 train
+qrweyuryei 0 300 train
+qrwfgtqybx 0 300 train
+qrwgkgajxb 1 300 train
+qrwicptqzi 1 300 train
+qrwlohihfc 1 300 val
+qrwpqiwjhb 1 300 val
+qrwrscbesb 1 300 val
+qrwsuzhtbc 1 300 val
+qrwzemzyqa 1 300 train
+qrxabxbmqp 1 300 train
+qrxdvknfga 1 300 train
+qrxdxcxfro 1 249 train
+qrxghndvmh 1 300 train
+qrxgkksxfu 1 300 test
+qrxjtkafos 1 300 val
+qrxnipvefb 1 300 train
+qrybiyyfdw 1 300 train
+qryroqnlhm 1 300 train
+qryvuoivrl 1 300 train
+qrywugjotp 1 301 train
+qryxdtpbvb 0 300 train
+qryzwdkszk 1 300 train
+qrzesuzufd 1 300 val
+qrzflzikfz 1 300 train
+qrzldfwjbo 1 300 train
+qrzqgkazih 1 300 val
+qrzwnglmyy 0 300 train
+qsabzugwtz 0 300 train
+qsakckygbj 1 300 val
+qsakhvaram 0 300 val
+qsapwncedv 1 301 train
+qsarvcjpwa 1 300 train
+qsauvnonrw 1 300 val
+qsauznmnlx 1 298 train
+qsavgssgnj 1 300 train
+qsavtvzigc 1 299 val
+qsawsatkfg 1 239 val
+qsaygyogue 1 300 val
+qsbbiqlzts 1 300 train
+qsbhjtunoo 1 300 train
+qsbkfucbwb 1 300 train
+qsblnqnsso 1 300 val
+qsbobohzls 0 300 train
+qsbvgcswyt 1 300 train
+qsbyhxdglo 1 300 train
+qsbyimbwqa 1 300 train
+qscczuokhe 1 300 train
+qsciegbgga 1 296 val
+qsciorylrm 0 300 train
+qscqqfmzyx 1 300 train
+qsctrdoklk 1 300 train
+qscuydoqyv 1 300 val
+qsdeohsvlg 1 300 train
+qsdjaqcmzl 1 298 train
+qsdjfqmrxs 1 302 train
+qsdjsstgyg 1 288 train
+qsdzskajsg 1 300 train
+qsegsgqxpy 1 300 train
+qseioligxt 1 300 train
+qselhammzc 1 300 val
+qseoarxfgo 1 300 train
+qseqojzkzk 1 300 train
+qseyxprzee 1 300 train
+qsezbaahes 1 299 train
+qsezypkxcf 0 300 val
+qsezzquzzh 1 300 train
+qsfayyjriz 1 288 train
+qsfeacqytt 1 300 train
+qsffbtclsl 0 300 train
+qsfisbrsxk 1 301 val
+qsfomthinb 1 300 train
+qsfrvlacbu 1 300 val
+qsftqxkogo 1 300 train
+qsghveihpz 1 300 train
+qsgjsmnfyu 1 300 val
+qsgkzzuzyz 1 300 val
+qsgouuaxjd 1 300 val
+qsgvolxtfl 1 300 train
+qsgwdetqmx 1 300 train
+qsgwkdkdvi 1 300 train
+qsgwkephyr 0 300 train
+qshlqczekr 1 300 train
+qshnruukru 0 300 train
+qsiklokgqi 1 300 val
+qsinmfgooy 1 300 train
+qsinqesqjv 1 240 train
+qsiprbwaay 1 300 train
+qsiszplrjk 1 300 train
+qsiujezpwk 1 300 train
+qsiydsugmm 0 300 train
+qsjfweswrv 1 300 train
+qsjgywaizl 1 300 train
+qsjiththcz 1 300 train
+qsjiypnjwi 1 300 test
+qsjjfnvzyr 1 297 train
+qsjjrpctyh 1 300 val
+qsjlbnecul 1 300 train
+qsjludwqli 1 300 train
+qsjtbgrfyw 1 298 train
+qsjuenkyqs 1 300 train
+qsjxldnssl 1 300 train
+qskciwabjp 1 300 train
+qsknsrpoue 1 300 train
+qskrjjgupy 1 300 train
+qskrzocapw 1 298 train
+qsksoqzeeo 1 302 train
+qskstyrigj 0 300 train
+qskuvqcchm 1 300 val
+qskynmcqyv 1 300 train
+qslbphrqkh 1 241 train
+qslehpmrzx 1 300 train
+qslerxmbjt 0 300 train
+qslmgrpjcb 1 298 train
+qslpxzwwxb 1 241 train
+qslqrxndnh 0 298 train
+qslukqcaaf 1 300 train
+qslvmobffh 1 300 train
+qsmbinkaaw 1 301 train
+qsmcpczncg 1 300 train
+qsmfsqpryo 1 300 test
+qsmhuoclie 0 300 train
+qsmkdoaiyp 1 301 val
+qsmohujxhi 1 300 val
+qsmqdklqgy 1 300 train
+qsmtnyumoa 0 300 train
+qsmyzvcxpk 1 300 val
+qsnbwjxlgu 1 300 train
+qsnjrkyafd 1 240 train
+qsnoosckdw 1 300 train
+qsnyqpwdex 1 300 train
+qsnyubocuj 1 300 val
+qsodarajtu 0 300 train
+qsoetgulee 0 300 train
+qsopapatjn 0 300 train
+qsoszkxsjx 1 300 train
+qsowmsiyxd 1 300 train
+qspdmgpzkn 1 300 train
+qspenjrcjm 1 300 val
+qsptlvtecx 1 300 test
+qspzboydnc 1 300 train
+qsqctsmfeg 1 300 train
+qsqdxpmfzs 1 300 train
+qsqgvwwvqk 1 300 train
+qsqmonpnlw 1 300 train
+qsrahhgpky 1 300 train
+qsrahioxmj 1 300 train
+qsrdyqvkza 1 300 train
+qsrgislucx 1 300 train
+qsrnfaktkp 1 301 train
+qsrwgwmwfl 1 301 train
+qsrwpyhevy 1 300 val
+qsrzkstona 1 300 train
+qssaubrnrz 1 300 train
+qssgremolx 1 300 val
+qssmifxflr 1 300 train
+qssoivhzbh 0 300 train
+qssqmsbneb 1 300 train
+qssrehhwfw 1 300 train
+qstajrjufs 1 300 train
+qstdenvivl 1 300 train
+qstdrlmcuf 1 300 train
+qsthfcjxtl 1 300 train
+qstoqsdfzs 1 301 train
+qsttkhukyb 1 301 val
+qstwkxxdor 1 300 train
+qstwsouygg 1 300 train
+qsugvnmrwj 1 300 train
+qsuinwnjjb 0 300 train
+qsuiuigxlo 1 300 train
+qsunabnqru 1 300 train
+qsvahbeumm 1 300 train
+qsveflhqdd 1 300 train
+qsvjbcmtjd 1 300 train
+qsvvbutumv 1 300 train
+qswcgqfwwa 1 300 train
+qswcorawas 1 147 train
+qswcthmqbc 1 297 train
+qswdfonccj 0 300 train
+qswhipbkxy 1 300 train
+qswlzfgcgj 0 300 test
+qswvgqgqvj 0 300 train
+qswxxakwhi 1 300 train
+qswyavoxzc 1 300 train
+qsxfqulvft 1 298 train
+qsxhlijcix 1 298 train
+qsxhumospo 1 299 val
+qsxifntntg 0 300 train
+qsxrljjftl 1 300 val
+qsxvfbcfid 1 298 val
+qsxxrzrssy 1 300 train
+qsyahidemw 1 300 test
+qsyczeclwu 1 167 train
+qsytiugmez 1 300 train
+qsyvxfydbt 1 300 val
+qszcbjsryb 1 300 train
+qszcdvuhdc 1 301 train
+qszgwasoqt 1 300 train
+qszmiurntz 1 300 val
+qszpiuxdsl 1 300 train
+qszrrwxras 1 298 train
+qsztibzzcy 1 300 train
+qszvvljwav 0 300 train
+qszwjftvcm 1 300 train
+qszynmtrwk 1 300 train
+qtahsllohp 1 300 val
+qtahsmphdv 1 300 train
+qtahzsqvgw 1 300 train
+qtalqljgss 1 300 train
+qtanleedpd 1 300 train
+qtanpnszex 1 300 train
+qtaojfvwse 1 300 train
+qtbakomdbu 1 298 train
+qtbdbfqnek 0 300 train
+qtbknmllwv 0 300 train
+qtbntggfwk 1 300 train
+qtborprvvl 1 300 train
+qtbtbdedbv 1 300 train
+qtbwpjppdr 1 298 train
+qtbzcmqweb 1 300 val
+qtcfeioduu 1 300 train
+qtcjbmwcge 1 300 train
+qtclbqrxqc 1 300 val
+qtclqxlfat 1 300 val
+qtcqmbqltm 1 300 val
+qtcrtofeed 1 300 train
+qtcvrisfvr 1 300 train
+qtdcjdcplc 1 300 train
+qtddmmjmub 0 300 train
+qtdgxcgjgv 1 300 train
+qtdhmczvvt 1 300 train
+qtdudlgzbx 0 300 train
+qtdxrbazya 1 300 train
+qtdyhcwdyi 0 300 train
+qtdyuihpvh 1 300 train
+qtelsrvetz 1 300 train
+qtemagwjla 1 241 train
+qtenejpvzx 1 301 val
+qtetwhbqjw 1 300 train
+qtexqeccmw 1 300 train
+qtfajulxrd 1 300 train
+qtffcaxrck 1 300 train
+qtfieshmjo 1 300 test
+qtfoizwxkr 1 300 train
+qtfqkbfxui 1 300 train
+qtftvismyz 1 300 train
+qtfuxsncrn 1 300 train
+qtfvgmwsfx 1 300 train
+qtfvzjvzlz 1 300 val
+qtfwkguaks 1 300 train
+qtgacuszan 0 301 train
+qtgivhjbjk 1 300 train
+qtgjpeayav 1 300 train
+qtgnlnozth 1 300 train
+qtgvrxepqx 0 300 val
+qtgxgrytqy 1 301 train
+qtgyzmingu 1 299 test
+qthcvrbidj 1 300 train
+qthekxmfvs 0 300 train
+qthgemsgsj 1 300 train
+qthhxdrnir 1 300 train
+qtholvackd 1 300 train
+qtijptvonr 1 300 val
+qtiqkcjuod 1 300 train
+qtiripqwir 1 300 train
+qtjeziukwk 1 300 train
+qtjgyuegif 1 300 val
+qtjigaxcqf 1 300 train
+qtjjmoibkn 1 300 train
+qtjjvuyvzc 1 300 train
+qtjjwfutqs 1 300 train
+qtjkrgyxjh 1 300 val
+qtjphxxuhl 1 300 val
+qtjqsanznp 1 300 val
+qtjqtzvnvi 1 300 val
+qtjqyufhrw 1 300 val
+qtjsohybiq 1 300 train
+qtjttnehew 1 300 val
+qtjuclgqgu 1 241 train
+qtjuhlppot 1 300 train
+qtjuhozohs 1 300 train
+qtjxsfsjrp 1 300 train
+qtkavxgnsw 1 300 val
+qtkewdoqqe 1 300 train
+qtkewtsleu 1 300 train
+qtkshvduqq 1 299 train
+qtkslflbvm 1 300 train
+qtkuakizvv 1 300 train
+qtlazhsxry 1 300 train
+qtlbxcupfm 0 300 train
+qtlcdhmtzh 1 300 train
+qtlcsanaoz 1 300 train
+qtlequpmtj 1 300 train
+qtletddfik 0 300 train
+qtletddkze 1 300 train
+qtlfwksvmy 1 288 train
+qtlgrmsptk 1 300 val
+qtlgvftgpt 0 300 train
+qtlidomjgs 0 301 train
+qtljjtavrz 1 301 train
+qtllouinrd 1 300 train
+qtlnflmkfz 1 300 train
+qtlseghuyr 0 300 val
+qtlvfxetxy 1 300 train
+qtlvhjktmf 1 300 train
+qtlvrmwrni 0 300 train
+qtlzybbjhm 0 300 train
+qtmfbdnoxh 1 300 train
+qtmjgwerxr 1 301 train
+qtmmyrzrbd 0 300 train
+qtmmzetbse 1 300 train
+qtmnqlzqyv 1 300 val
+qtmpsepexy 1 300 val
+qtmqsziqgu 1 300 train
+qtmrjlrgov 1 300 train
+qtmxmllllw 1 300 val
+qtnaoqbyvi 1 300 train
+qtnikivnig 1 300 train
+qtnjyomzwo 0 300 train
+qtnlgdnhvd 1 143 train
+qtnqqgllmx 0 300 train
+qtnshwprau 1 300 train
+qtnsldokmk 1 300 train
+qtoaetpxln 1 300 train
+qtobsgfidr 1 300 train
+qtocjfadqh 0 300 train
+qtoctusxyk 0 300 val
+qtoewyqzoc 1 300 train
+qtofhpfbeo 1 300 val
+qtofhzaozq 1 300 train
+qtoftqwqou 1 301 val
+qtoobybasa 1 300 train
+qtopybgnyl 1 300 train
+qtpjpxvhfg 1 300 val
+qtpmdvwqhh 0 300 val
+qtppqpyqdw 1 300 train
+qtprigwkms 1 298 train
+qtptypguko 1 249 train
+qtpxbrfzui 1 300 train
+qtpyxjpotj 1 300 train
+qtqaqwekux 1 300 train
+qtqbljpgti 1 300 train
+qtqqmbjlbv 1 300 train
+qtqyglbdem 0 300 train
+qtrhlbhdjt 1 300 train
+qtrhqqarbh 1 300 train
+qtrhucxfaj 0 300 train
+qtrurtupfl 1 167 train
+qtrwekjweq 1 300 train
+qtryoazkjv 1 300 train
+qtrzipcyga 1 300 train
+qtrzmhqbml 0 300 train
+qtsaqxgurd 1 300 train
+qtsbipvgcr 1 300 train
+qtslctfoog 1 300 train
+qtslkxqieq 1 301 val
+qtsqtriczp 1 300 train
+qtsuwnskdr 1 300 train
+qtsxsaahex 1 299 train
+qtsywszhmv 1 302 train
+qtsywumldu 0 300 train
+qttdlsecod 1 300 test
+qttjeebsxj 1 297 train
+qttjycrjpk 0 300 train
+qttlpfctqh 1 300 test
+qttltcqerf 1 241 train
+qttorxqiub 1 300 val
+qttpdqchfv 1 298 train
+qttyviknbz 1 300 val
+qtudktftrc 0 241 train
+qtukqczgxy 1 300 val
+qtulvrsbnl 1 300 val
+qtumgbdagm 0 300 train
+qtunnvngjw 1 300 train
+qtuptldzhe 1 300 train
+qturxbjqxl 1 300 train
+qtvactlygz 1 300 train
+qtvbhylcsp 1 300 train
+qtvddzhxyu 1 300 train
+qtvhpmoukj 1 300 val
+qtvjkrnnfq 1 300 train
+qtvrbwsson 1 300 train
+qtvxbenoiv 1 300 val
+qtvyypdgsc 1 300 train
+qtwbpbascr 0 300 train
+qtwecgsmve 1 300 train
+qtwekmlouz 1 300 train
+qtwqkkmmyt 1 300 train
+qtwtiaihsq 1 301 train
+qtwttqcurl 1 300 train
+qtwwafpxcn 1 300 val
+qtxlxaijnm 0 300 train
+qtxorhdfos 1 300 val
+qtxqyvidom 1 300 train
+qtxraeaxeh 0 300 train
+qtyhdqilzb 1 301 val
+qtylbotbqa 1 300 train
+qtymkcrnph 1 300 train
+qtyndvpmdb 1 300 val
+qtyoypxumf 1 300 train
+qtyphagtuw 1 300 train
+qtyqskkgly 0 300 train
+qtyqvmdsal 1 300 train
+qtyvhcjqwd 0 300 train
+qtzckzoydx 0 300 val
+qtzdwjkwgo 1 300 val
+qtzgudxfpz 1 300 train
+qtzhupcuap 1 301 train
+qtzmxpfilk 1 300 train
+qtzsfdjhau 1 300 train
+quacjxezar 1 300 train
+quaggmpylh 1 300 val
+quagmkdjgn 1 300 val
+quajdxbqvd 1 300 train
+quajsnhtpk 1 300 train
+quaplknunm 1 300 train
+qubbhilnwi 1 300 train
+qubcvltqbr 1 300 train
+qubncwyamy 1 300 train
+qubnscmmti 1 297 train
+qubpfaponl 1 300 train
+qucamnjqqf 1 300 train
+qucelvhhbb 1 300 train
+quchewttay 1 300 train
+quckfgtghv 0 300 val
+quckkrsnpu 1 300 train
+quclbzlsvz 0 300 train
+qucldpktnk 0 300 train
+qucmffhkfa 1 300 train
+qucndxwjbd 1 300 train
+qucsdfajaw 1 300 train
+qudassbguq 1 300 train
+qudcfpslik 1 300 train
+qudctgzkel 1 300 train
+qudhlvaxtc 1 300 train
+qudlmboesy 1 300 train
+qudnblnukz 1 300 train
+qudtljncvy 1 300 train
+qudzjrpjlj 1 300 val
+quecyuklcq 1 300 train
+quefgrmkyb 1 299 val
+quejgdzzbo 1 300 train
+quemoxufdl 1 300 train
+queqdqiqwj 1 300 test
+quercuatrr 1 299 val
+quexoxnfel 1 300 train
+quezhztwux 1 300 train
+quezxkfdsd 1 269 train
+qufsecdalr 1 300 val
+qufstrlknm 1 300 train
+quftvwnleq 1 300 val
+qufwulvfmc 1 300 train
+qufzahhvws 1 300 train
+qufzdwetss 0 300 train
+qugdksqaia 1 300 train
+qugdoaoklb 1 297 train
+qugdzpssrk 1 300 train
+quggpxveqo 1 300 train
+qugmenjujh 1 301 val
+qugrienizt 0 300 train
+qugsymzknq 1 300 train
+qugvtlmmgt 1 300 train
+qugwsnxuhu 1 300 train
+qugxygzplb 1 300 train
+quhsdssjsg 1 300 train
+quhwzhubag 1 301 val
+quhxbmhosd 1 300 train
+quhyynvnou 1 299 val
+quhztsndpr 1 301 train
+quibiltcfc 1 301 train
+quihoepsxz 0 300 train
+qujcuoyaay 1 301 val
+qujevbdicn 0 300 train
+qujjkkjiod 1 300 val
+qujrxdekxh 0 300 train
+qujumemxpd 1 300 train
+qujvdegxjv 1 239 train
+qukcaouasb 1 300 train
+qukfizlfea 0 300 train
+qukhfelsei 1 300 val
+qukjfhjisw 1 300 train
+qukrtwnqui 1 300 val
+qukuaopubd 1 241 train
+qulhjxhrtj 1 300 train
+qulqdevpzf 1 301 train
+qulqwmjsqx 1 300 val
+qulyycecst 1 301 train
+qumaotbviq 1 300 train
+qumtorkivw 1 300 train
+qumwfrunqq 1 300 train
+qundhdchms 1 300 train
+qunhmabbrn 1 300 val
+qunjehlsff 1 300 train
+qunjtbfclc 1 300 train
+qunpwgbnsa 1 300 train
+qunqhwcxzp 1 300 train
+qunqyshzky 1 300 train
+qunydyyxxk 1 298 train
+quokjmmfee 1 300 train
+quokxosnjg 1 300 train
+quoncyglpc 0 300 train
+quorspjedj 1 300 train
+qupekbkiux 1 300 train
+qupretbioy 1 300 train
+quptchgnqi 1 300 train
+qupucojlwo 0 300 train
+quqlmhrmqy 1 298 train
+qurcxbznni 1 300 train
+qurfjcrigq 1 300 train
+quromqghwg 1 300 train
+quroritzrq 1 300 train
+qurpdihwxi 1 300 train
+quryavqrmu 1 297 train
+qurzdehtdy 1 300 val
+qusajxrbya 1 300 train
+qusbywwrag 1 300 train
+quscjzvend 1 300 train
+qusebhvbba 1 300 train
+qusnfjluuh 1 300 test
+qusppvrrds 1 300 train
+qusvpuruuj 1 300 train
+quswtlxyci 1 300 train
+qusxgmircg 0 300 train
+qutdvdwovi 0 300 val
+qutrnyplby 1 300 train
+qutrtjujjq 1 300 train
+qutvcdewxm 1 241 train
+qutxrcooob 0 300 train
+quudqerhsr 1 300 val
+quuftbrmtx 1 300 train
+quumsxtyli 1 300 train
+quutalyuik 1 300 train
+quutldbrrr 1 300 val
+quuzylrdna 1 300 train
+quvgenpffl 1 300 train
+quvknldsar 0 300 val
+quvlvcqrnq 1 269 train
+quvseyayds 1 300 test
+quvzowqkli 1 300 train
+quwauoauwx 1 300 train
+quwcmcazbu 1 300 val
+quwnrbjhsx 1 301 train
+quwshigier 1 300 val
+quwulxonta 1 300 train
+quwvyztlrg 1 300 train
+quwwzmlnqa 0 300 train
+quwzfzflrc 1 301 train
+quxaoheqdt 1 300 train
+quxdpokjmu 1 300 train
+quxmablhdt 1 300 train
+quxnfuatsc 1 300 train
+quxpjjimyi 1 300 val
+quxpyigutx 1 300 train
+quxxfzxyee 0 300 val
+quycttumrg 1 300 val
+quyfbyblav 0 241 val
+quygtqxadv 1 300 val
+quyohepfdf 1 300 train
+quyqeotcqm 1 301 train
+quyuqubjqp 1 300 train
+quyvcndwgx 1 300 train
+quyvduwqwt 1 300 train
+quyvmzbeeo 0 300 train
+quyzfrphft 0 300 train
+quzcovnkje 1 300 train
+quzfxkkaqu 0 300 train
+quzmnziglv 1 300 train
+quzugnyxdh 1 300 train
+quzzdiyktt 1 300 train
+qvaegkgdsk 1 300 train
+qvagkwnwcx 1 300 train
+qvawrgmqcr 1 300 train
+qvaxapfttc 1 299 train
+qvbabvwtrs 1 147 train
+qvbfhxwbgd 1 300 train
+qvbhffochl 0 300 train
+qvbudwjjqs 1 300 val
+qvbwbvaksm 1 300 train
+qvccmmidrt 0 299 val
+qvckqrlyit 1 300 train
+qvclfrivhp 1 300 train
+qvcnbgrqhi 0 300 train
+qvcsiotvxl 1 300 train
+qvctowqtdw 1 299 val
+qvcvnvxfdk 1 300 train
+qvcylmihur 0 300 val
+qvdkibrxei 0 300 train
+qvdlvhtxyn 1 300 train
+qvdqpscjvf 1 301 val
+qvdqtnduia 1 300 train
+qvdrjnvmht 1 300 train
+qvdxlyoybr 1 300 train
+qvebuvzhcs 1 300 test
+qvedkofrey 1 300 train
+qveeatoxpu 1 300 train
+qvegrhcewt 1 300 train
+qveirhdwya 1 300 val
+qvekqcngrz 1 300 train
+qveozlbddv 1 300 train
+qveqzicfzc 1 300 train
+qverurmqra 1 241 train
+qveslosusc 0 300 train
+qvfbnjvznm 0 300 val
+qvfdryghjx 1 300 train
+qvfeggdtvs 1 300 val
+qvfkcoupqk 1 300 train
+qvfpyaaotl 1 300 train
+qvftdvvslk 1 300 train
+qvftjvfcyz 1 300 train
+qvgadteibf 1 300 val
+qvglhokwlp 1 300 train
+qvgqfeozev 1 297 train
+qvgutokvct 0 300 train
+qvhbegsyjg 1 300 train
+qvhjhyfgta 1 300 train
+qvierhwxmk 1 300 train
+qviizybvfz 1 300 train
+qvijlekckl 1 300 train
+qvinznkuab 1 301 val
+qvipgscbpd 1 300 train
+qvipgwiujw 1 299 test
+qviszdxcxf 1 300 train
+qviugiidam 1 300 train
+qviyebwxba 1 300 train
+qviyhxvysb 1 300 train
+qvjegpohkg 1 300 val
+qvjfyzixtu 1 300 train
+qvjljhxvis 1 300 train
+qvjlnrjfgg 1 300 val
+qvjpqilvar 1 299 test
+qvjuaposvh 1 300 train
+qvkeqtgupt 1 300 val
+qvkesrghgn 1 300 train
+qvkgdonrcg 1 300 val
+qvkhlmdqgk 1 300 train
+qvkxjcadah 1 301 train
+qvkxmjftzb 0 300 val
+qvlfubybxh 0 300 train
+qvlmzhprus 1 300 train
+qvlodfkghb 1 300 val
+qvlpvnpcdg 1 300 train
+qvluvtwhds 1 300 train
+qvlxxbnfbo 1 301 train
+qvmadvtfzf 0 300 train
+qvmctxubuo 1 300 train
+qvmpteeerj 1 300 train
+qvmzbhdtft 1 300 train
+qvnawikimb 1 300 train
+qvnffjwzil 0 300 train
+qvngqavofg 0 300 train
+qvntsjtahk 1 300 train
+qvnuyypttd 1 300 val
+qvnwyallgu 1 300 train
+qvnysyguhq 1 300 train
+qvobgjezpe 1 300 train
+qvojhlzyqg 0 300 train
+qvokqyqyyy 1 300 train
+qvootmcxia 1 300 train
+qvovojyrea 1 301 train
+qvovwxlcgx 1 300 train
+qvpijvpktb 0 300 train
+qvpntddupb 1 299 train
+qvqekhgmvc 1 300 train
+qvqjzwubwz 0 300 train
+qvqkdqftnm 1 301 train
+qvqndubvga 1 300 train
+qvqqvxuvmo 1 300 train
+qvqwftakqo 1 300 train
+qvqzirmmqt 1 300 train
+qvrbtbnzsa 1 300 train
+qvrdmajxtr 1 300 train
+qvrgoabojk 1 300 train
+qvrhatuqdo 1 300 train
+qvrmtpcqrq 1 300 val
+qvrmuzebup 1 300 train
+qvrnribeyr 1 300 train
+qvrnsixvrv 1 300 train
+qvrsttodxo 1 300 val
+qvrtpfuamq 1 300 train
+qvrtsdskgn 0 300 train
+qvsccggoyi 1 300 train
+qvshmtymdk 1 298 train
+qvshmytosa 1 298 train
+qvsntcmwti 1 299 val
+qvsntzkdrh 1 300 train
+qvsrhlylpq 1 300 train
+qvsskinsyi 1 300 train
+qvtlbitbrd 1 300 train
+qvtokhjmvs 1 300 val
+qvtxdznisg 1 300 train
+qvtylkszka 1 300 train
+qvtynrcftd 1 300 train
+qvuaaakphs 1 300 train
+qvubfjvujf 1 300 val
+qvudvfntjy 1 300 train
+qvutgirvlk 1 301 train
+qvutnqsvcg 1 300 val
+qvuxdpygaa 1 298 train
+qvuxyucdje 1 300 train
+qvvfzolbxs 1 300 train
+qvvlvhylbn 1 300 train
+qvvpnoxutu 1 301 val
+qvvrvlciiq 1 300 val
+qvvvyysynb 1 99 train
+qvvybavznh 1 300 train
+qvwaescihs 0 300 train
+qvwrkpukjb 0 300 train
+qvwscrgxwv 1 241 val
+qvwzyydjtt 1 300 train
+qvxaknnxiy 0 301 train
+qvxbmyeifh 1 300 val
+qvxeecdqoa 0 300 val
+qvxgbkggcp 1 300 train
+qvxhcsymjm 0 300 train
+qvxkpvgrtm 1 300 train
+qvxuzqovtk 0 300 train
+qvxvgnoopq 1 300 train
+qvyghudsuq 0 300 train
+qvymrrbvqw 1 300 train
+qvyozhwbaj 1 300 train
+qvyqrsygsw 1 300 train
+qvyrlitoka 0 300 train
+qvyxncyhua 0 300 train
+qvznjhppvt 1 300 train
+qvzshtmnig 0 300 train
+qvzvpmhqic 1 300 train
+qwabudetug 1 300 train
+qwahwfhyux 1 300 train
+qwajxqtpjm 1 300 train
+qwanidssgl 1 300 val
+qwarurttbs 0 300 train
+qwaywadnxu 1 300 val
+qwayyekbhd 1 300 train
+qwbhdymffr 1 299 train
+qwbjcvqsdj 0 300 train
+qwbkbwaonv 1 298 train
+qwbmvqfdcd 1 300 train
+qwbpqfsdwy 0 300 train
+qwbpwpesxx 1 300 val
+qwbwqpzgwx 1 300 val
+qwcbzwpvqd 1 300 train
+qwcesxcnfz 1 241 val
+qwcgvfwtgt 1 300 train
+qwchejweqe 1 297 train
+qwchzldmrv 0 300 train
+qwcictvrdp 0 300 train
+qwcismrvgr 0 300 val
+qwcnmpekwx 1 300 val
+qwcoqllmdr 1 298 train
+qwcoyjfpni 1 300 val
+qwcprhuhvs 0 300 val
+qwcqpxxome 1 300 val
+qwcrbsireo 1 300 train
+qwcrwumbht 1 300 train
+qwcurhzwpq 1 301 val
+qwcvsjgfip 1 301 train
+qwcwozchec 1 300 val
+qwcwytogit 0 298 train
+qwdagvcaep 1 301 train
+qwdgcewzio 1 298 train
+qwdgovaarb 1 300 val
+qwdheqgzql 1 300 train
+qwdihfkpyi 1 300 train
+qwdjbmpvlr 1 240 train
+qwdktilbrk 0 300 val
+qwdmpavusl 1 300 train
+qwdoikpbwm 0 300 val
+qwdpmyfows 1 300 val
+qwdxwsnwrr 1 300 train
+qwdycrpdqc 1 300 val
+qweasxsvdh 1 300 train
+qwecszcbxn 1 300 train
+qweglkmxpp 1 300 train
+qwehdvohas 1 300 train
+qweikxnvyq 1 300 test
+qwemrefkwh 1 300 train
+qwenaoymth 1 300 train
+qweoocwxqn 1 300 train
+qwerhadygj 1 300 train
+qweuffvsqv 1 300 val
+qwewawjnih 1 300 train
+qwewxfungv 1 300 val
+qweylvmagw 1 300 test
+qwezztawyv 1 300 train
+qwfjxnwjqm 1 300 train
+qwfmmmrvmz 1 300 train
+qwfngqzvwf 1 300 train
+qwgejjzbmk 1 300 val
+qwgenjluof 1 300 train
+qwgewpgxfs 1 290 train
+qwggbnikmh 1 300 train
+qwggfvbwtr 1 300 train
+qwgjbtntyb 1 300 train
+qwgmdbnovi 1 300 train
+qwgnlpyvpm 1 301 train
+qwgyceznzh 1 300 train
+qwgyyicbrg 1 301 train
+qwhjcwwbld 1 300 train
+qwhlxjadoq 1 300 train
+qwhxkeulrp 1 300 train
+qwijpfudxq 1 300 train
+qwilmyiskx 0 300 train
+qwiorlwosn 1 300 train
+qwiuacrzwd 1 300 val
+qwiukqgotv 0 300 val
+qwiwkepytf 1 300 train
+qwixeupgtz 1 300 train
+qwizaphcwo 1 300 train
+qwjnaskhau 1 300 train
+qwjskopakn 0 300 train
+qwkeprkbjy 1 300 train
+qwkhktdtjj 1 300 train
+qwkmfcrcxm 1 300 test
+qwkopukgzm 1 300 train
+qwkrpefjjq 1 300 train
+qwksbqhmbo 1 300 train
+qwkvjxzzuw 1 300 val
+qwkztkfpgk 1 300 train
+qwlcwionwb 1 300 train
+qwleauyffp 1 300 val
+qwlfakvkjp 1 298 train
+qwlfkfyref 1 300 train
+qwlgftdhqu 1 300 train
+qwlkmxwjmw 1 300 train
+qwltfyrlvl 1 300 test
+qwlwixugzd 1 301 train
+qwlyqderla 1 301 train
+qwmnqvcdcr 1 300 train
+qwmswserws 0 300 train
+qwmuepplrx 1 300 val
+qwnjdipavr 1 301 val
+qwnjzzivps 1 301 train
+qwnntkhsko 1 298 val
+qwnvsiuxqo 1 297 train
+qwnzubbutj 1 241 train
+qwoafyatox 1 300 train
+qwocosaxwe 1 300 test
+qwogpogmqo 1 297 train
+qwosbspgoi 1 297 train
+qwowuatiyq 0 300 val
+qwphiksimu 1 300 train
+qwplipmnde 1 300 train
+qwpmjozvki 1 299 train
+qwpnwxbxeb 0 300 train
+qwprawqrpw 1 298 train
+qwpwyjgabe 1 300 train
+qwpxprweaw 1 300 val
+qwpypedkpr 0 301 train
+qwqayqksda 1 300 val
+qwqdohncmx 1 300 train
+qwqdxcwpwy 1 300 train
+qwqefbalkv 1 239 train
+qwqidbbiyz 1 300 train
+qwqiqjkvvf 1 300 train
+qwqoyrabox 0 300 train
+qwqsyeppwg 1 300 val
+qwqvvbmgkd 1 300 train
+qwqwuoijeh 0 300 train
+qwrcqccyvi 0 300 train
+qwremnmzss 1 300 val
+qwrgbkqzvy 1 300 val
+qwrhrqjcyv 1 300 val
+qwrpagiovn 1 300 train
+qwryrbpasi 1 301 train
+qwsabcgeup 1 297 train
+qwsdxncgzh 1 300 train
+qwsfusjung 1 299 train
+qwsgzllqxl 0 300 train
+qwsudzyusb 1 300 train
+qwswcikefx 1 300 train
+qwsxiadtsl 1 241 train
+qwtcmikhmd 1 300 train
+qwtfgjaxwh 1 301 val
+qwtljvjnge 1 300 train
+qwtmidmcpm 1 301 val
+qwtrmhrdyr 1 300 val
+qwtvysmmdk 1 300 train
+qwtzojwzzo 1 301 train
+qwuicwdltv 1 300 train
+qwusasrebv 1 300 train
+qwuwgxstmb 1 300 train
+qwvejgkune 0 300 val
+qwvhiipmtr 1 300 train
+qwvkiibqeo 1 300 train
+qwvscgtvrj 1 300 train
+qwvwkzjsbq 1 300 train
+qwvxbksoeo 1 300 test
+qwvxfewpwj 1 300 val
+qwvxniksvq 1 300 train
+qwvykwekym 1 300 train
+qwwcgypoia 1 300 val
+qwwfsrdgze 1 300 train
+qwwimruaqy 1 301 val
+qwwovfbfel 1 299 train
+qwwrbmggki 0 300 train
+qwwsckvxma 1 300 train
+qwwwrmoxrb 1 300 val
+qwwxsmdfid 1 300 train
+qwxekdfymh 1 299 test
+qwxivpwxee 1 300 train
+qwxjnbdwdv 1 296 val
+qwxkakefcj 1 298 train
+qwxlekgzml 1 300 train
+qwxmblgcmj 1 300 train
+qwxttzvdav 1 300 val
+qwxtwaqlpb 1 300 test
+qwxudxbqvj 0 300 train
+qwxyxyxiwf 1 300 train
+qwyoqvvvry 1 300 train
+qwyuwvfdsh 1 300 val
+qwyvvojezq 1 300 train
+qwzegysenf 1 297 train
+qwzhtjigbe 1 300 train
+qwzirmuiaf 0 300 train
+qwzrlkkwsa 1 300 train
+qwzsonakep 1 300 val
+qxadtnbjti 1 300 train
+qxaeivbwjt 0 300 train
+qxaeqlbnio 1 301 train
+qxahagktng 1 300 train
+qxakwwjdsa 1 300 train
+qxatnspkbp 1 300 test
+qxayqxxonh 1 300 train
+qxaywtmmnn 1 300 train
+qxbhxtuvmv 1 83 train
+qxbkmqeerz 1 299 test
+qxbnmwwgzp 1 298 train
+qxbrdvfzga 1 300 val
+qxbretbcgs 1 301 train
+qxbsowxdyv 1 300 train
+qxcfawhaex 1 300 train
+qxcfyrqlyx 1 301 train
+qxcgsvitrh 1 301 train
+qxczllkvwv 1 300 train
+qxdblontfc 1 300 val
+qxdfnkfeox 1 301 val
+qxdhujeikr 1 298 train
+qxdkyypxoo 1 300 test
+qxdsuhbtiq 1 300 train
+qxdvcosnjq 1 298 train
+qxefejazzl 1 299 train
+qxefjiidmg 1 300 train
+qxefkvizfu 1 300 train
+qxehrxcsif 1 300 train
+qxekuoxjox 1 300 val
+qxekwkorng 1 292 train
+qxepjyrtiu 1 300 train
+qxepwictie 1 300 val
+qxfaiqqvlc 0 300 val
+qxfczznpyb 0 300 train
+qxfhktbwli 1 300 val
+qxfhygppeb 1 300 train
+qxflgrafcq 1 300 train
+qxfnacrxyj 1 300 train
+qxfopjptut 1 300 train
+qxfroxwskk 1 300 train
+qxfxhgikxo 1 300 train
+qxfybzsxfr 1 301 val
+qxfzozylcl 1 300 train
+qxgfeiotrx 1 301 train
+qxggfpnbml 1 300 train
+qxgghpfsil 1 300 train
+qxgnrlkvkt 0 300 val
+qxgnwoqcjr 1 298 train
+qxgrmwwpif 1 300 train
+qxgtqqzxou 0 300 train
+qxguvdlkql 1 299 val
+qxgwcsugvd 1 300 train
+qxheqdcopd 1 300 train
+qxhfetfjyf 1 300 train
+qxhfpsxkbk 1 300 train
+qxhgveiqxz 1 300 train
+qxhkrngfyx 0 300 val
+qxhohcgdte 1 300 train
+qxhpkztmbp 1 300 train
+qxhyhhkywc 1 300 train
+qxiladowcl 1 300 train
+qxiosifzzt 1 300 train
+qxipvjgqby 0 300 train
+qxjdnugkho 1 300 val
+qxjknnxtzl 1 300 train
+qxjovfsrcs 1 300 val
+qxjrrknttr 1 300 train
+qxjvqhwevt 1 300 train
+qxjxtfbsyc 1 300 train
+qxkdcrkiuk 0 299 val
+qxkhbvpomm 1 301 train
+qxkhenevls 1 301 train
+qxkjmggdtx 1 300 train
+qxkkyqpttd 0 300 train
+qxkuxaazcv 1 297 train
+qxlmkrptxn 1 300 train
+qxlpkgewoi 1 299 val
+qxlptlapgv 1 298 train
+qxmgmaabbs 1 300 train
+qxmtngbkbq 1 297 train
+qxmvgpsbpg 0 300 test
+qxnfmledve 1 300 train
+qxngihsrxl 1 300 test
+qxninqhwbc 1 300 train
+qxnnrbcsot 1 300 train
+qxnqawvgug 1 300 train
+qxnwbnplav 0 299 val
+qxoaxmuztm 0 300 val
+qxobasdywc 1 301 val
+qxobwvomwm 1 300 train
+qxondxofry 1 300 test
+qxotjveryu 1 298 train
+qxowuprxzl 1 301 val
+qxoxlmeafu 1 300 train
+qxpacncnfp 1 241 train
+qxpatpvlhr 1 300 train
+qxpcbvoaet 0 300 val
+qxpfzavbzc 1 300 train
+qxphnlhftg 1 300 val
+qxpldrakil 1 301 val
+qxplesvocj 1 300 train
+qxpszyqjwm 1 300 train
+qxptzfeziw 0 300 train
+qxpyekaknf 1 300 train
+qxqbixdpmd 1 300 train
+qxqekwwezo 1 300 train
+qxqghulgoi 1 300 train
+qxqknrqzhk 1 300 train
+qxqktcxqpk 1 300 train
+qxqlthzlqt 1 300 train
+qxqnvsdjaw 1 300 train
+qxqqthpujj 1 300 val
+qxqtwricad 1 300 train
+qxramfeoin 1 301 train
+qxrutfkith 1 300 train
+qxrzvoupsv 1 300 train
+qxshqecclf 1 300 train
+qxsltlzxyc 1 300 train
+qxsorkbpxk 1 300 val
+qxsshsgosm 1 300 train
+qxsvjwhtyz 1 300 train
+qxsyrjyuxs 1 300 train
+qxsziseqly 1 300 val
+qxtboblspn 1 300 train
+qxtccyvbks 1 301 train
+qxtdsnnosy 1 300 val
+qxtedpsliv 1 300 train
+qxthkomtmn 1 300 train
+qxtkhiwflp 0 300 train
+qxtkmjciyz 1 300 train
+qxtmjxiltq 1 297 train
+qxtoukhyts 0 300 train
+qxttkmklex 1 300 train
+qxtucskxes 1 300 train
+qxtwjuhisv 1 300 val
+qxtwqgbwql 1 300 train
+qxtwyupdrd 1 301 val
+qxubnxabpu 1 300 train
+qxudrmbfes 1 300 train
+qxufaehcmf 1 300 train
+qxuivoxvhl 1 297 val
+qxusaokrer 1 300 val
+qxuwpyespq 1 300 train
+qxuxxvlkdr 1 300 val
+qxuyjuvhht 1 300 train
+qxuzpfrtbc 1 300 train
+qxvawxgamu 1 300 train
+qxvdghbrse 0 300 train
+qxvejczqdd 1 300 train
+qxvhoajcrc 1 300 train
+qxvkqvzldh 1 300 train
+qxvppuoeeo 1 300 val
+qxvtbbguee 1 300 val
+qxvvxlzgwz 1 301 train
+qxvyagavul 1 300 val
+qxvychduae 1 300 train
+qxvzfgsjou 0 300 train
+qxvzphuqgg 1 300 val
+qxwfszuqgy 1 300 train
+qxwisvccpi 0 300 train
+qxwjlkabsx 1 300 train
+qxwmamefgj 1 300 train
+qxwpxnqjtj 1 300 train
+qxwqaplewk 1 300 train
+qxwqqhruvz 1 300 train
+qxwuqsefki 1 300 train
+qxxfgtcuxc 1 300 train
+qxxgdrqzdr 1 300 val
+qxxmauaxnq 1 300 train
+qxxpgtfqig 1 300 train
+qxxuvvmbzg 1 300 train
+qxxyndbiff 1 300 train
+qxylkwsijy 1 300 train
+qxyrtwozyw 1 300 test
+qxyuqjzblq 1 300 test
+qxzcbpxkwt 1 300 val
+qxzkrdnnvj 1 300 train
+qxzlwhpnow 1 300 val
+qxzqnnfaii 0 300 train
+qxzrotmvpy 1 299 test
+qxzrrypssd 1 300 train
+qxzstqrvcg 1 300 val
+qxztjtnbwh 1 300 train
+qxztuvvaht 1 300 train
+qxzuuzvpmg 0 300 train
+qxzvifodqn 0 300 train
+qxzvvvbblq 1 300 train
+qxzxjjcamh 1 300 train
+qxzzwarths 0 301 train
+qyaaoxchgk 1 301 val
+qyaggqgkwm 1 302 train
+qyaiavfdcv 0 300 train
+qyaohhcxcw 1 300 train
+qyaorevpck 1 300 val
+qyarbnrrvk 1 300 train
+qyatusnrny 1 300 train
+qyaylxdski 1 300 train
+qyaymzlytq 1 300 train
+qybcxegimz 1 300 train
+qybdpcijzm 1 297 val
+qybhoqjybb 1 300 train
+qybienvved 1 300 train
+qybjhljexi 0 300 train
+qybjkjeiyd 0 300 val
+qybjmxtvia 1 300 train
+qyblmkwjjc 1 300 train
+qybpwwpcor 1 300 train
+qybrkcdjyj 0 300 train
+qybyarppgc 1 300 train
+qycfkcfbdy 1 300 train
+qycgqfqoql 0 300 train
+qycjisbrwf 1 300 train
+qyclzcggqj 0 300 train
+qycmrgkppq 1 300 train
+qycqellygx 0 300 train
+qycsqpyjwv 1 300 train
+qyctqclkty 1 300 train
+qycxsbythv 1 301 train
+qycxsqlkir 1 300 val
+qydafrlagu 0 300 train
+qydaqpouib 1 300 train
+qydeuhuygh 1 300 train
+qydfmjvthk 1 300 train
+qydhcvvjys 1 300 test
+qydkustmdn 1 300 train
+qydlzwwvzc 1 300 train
+qydncnbbdc 1 300 val
+qydnyeundb 1 300 train
+qydoetemno 0 300 train
+qydotqsawl 1 300 val
+qydowrrzfv 1 300 val
+qydxcorvsb 1 300 train
+qyeccgboqd 1 300 train
+qyefejorlb 0 299 train
+qyehiscxbr 0 300 train
+qyenuecjgh 0 300 train
+qyerwbrvit 1 300 train
+qyesslnghe 1 300 train
+qyeunoykln 1 300 train
+qyevvfxxxp 1 300 val
+qyfczovavl 1 300 train
+qyffyttbrc 0 300 train
+qyfkgwbubi 0 300 train
+qyfltwkqio 1 301 val
+qyfozoqcig 1 300 train
+qyftztqolj 1 300 train
+qyfuygqsch 1 300 train
+qygnngsptk 1 300 train
+qygvgnmqvr 1 300 train
+qygvqadqzp 0 300 train
+qygwcooksi 1 300 train
+qygwdnhoua 1 300 train
+qygzshrfan 1 298 train
+qyhddjgavt 1 300 train
+qyhiyrikrh 1 300 train
+qyhlzalxzm 1 300 train
+qyhntxeyxi 1 300 train
+qyhuunvlal 1 301 train
+qyhvkqqobg 1 300 test
+qyiahrqgnk 1 300 val
+qyijvwfdvx 1 241 train
+qyiwevbmce 0 300 train
+qyjbhkeqes 1 300 train
+qyjdpluerd 1 300 val
+qyjescqpya 1 300 train
+qyjqyxfznb 1 300 train
+qyjztfmmgr 1 241 train
+qykcjkjxsd 0 300 train
+qykihacqea 1 300 train
+qykqnehufy 1 300 train
+qyksotcywq 1 300 train
+qykuagqkjz 1 300 train
+qyladnongb 1 300 train
+qylffyykeu 0 301 train
+qylfwaqpqe 1 301 val
+qylhskzhqr 1 300 train
+qyliyswble 1 300 val
+qylmfpljrf 1 300 train
+qylmmxdppn 1 300 train
+qylogqsvxq 1 300 train
+qylpueqddb 1 300 train
+qymlbodazp 1 301 train
+qymqwsvnow 1 300 train
+qymuvqgggr 0 300 val
+qymuyfgefa 1 300 train
+qymvdsiwop 1 300 train
+qynbklgrrm 1 300 train
+qynboiimaa 1 300 val
+qynbslvuha 1 300 train
+qynetswxga 1 300 train
+qynjpndjbh 1 300 val
+qynkehmbcv 1 298 val
+qynlzaxcur 0 300 val
+qynqpctxpj 1 300 test
+qynrzyhqcv 1 249 train
+qynunjbkrv 1 298 val
+qynvqyhrns 1 300 train
+qynzlamqwr 1 300 train
+qynzmivnnj 1 300 train
+qynzrujsnj 1 300 train
+qyofhfaazs 0 300 train
+qyooflswtq 1 300 val
+qyoseulvtt 1 241 train
+qyoxkqrnvy 0 300 train
+qyoxvhfkrh 1 300 train
+qyoycygwqu 0 300 val
+qypaddpxcr 1 300 train
+qypdgcexcr 1 300 train
+qypedtpatd 1 300 test
+qypftspxir 1 301 val
+qypgtrcpzt 1 300 train
+qypgyrxcme 0 300 train
+qypjdviuoj 1 300 train
+qypnegfoxe 1 300 train
+qyprogscdh 1 299 train
+qypsjvuqwb 1 300 train
+qypuhvjnor 1 300 train
+qypwgbrgct 1 300 val
+qyqavdtzbs 1 301 val
+qyqebzlkro 1 298 train
+qyqfufqenu 1 300 train
+qyqktxkytc 1 301 train
+qyqufaskjs 0 300 test
+qyrbwunbae 1 300 train
+qyrejadrtf 1 300 train
+qyrgnqguez 1 300 train
+qyrpkpvzmb 1 300 train
+qyrpzdmfqp 1 300 train
+qyrrozbgxw 1 300 val
+qyrtsnhyor 1 300 val
+qyrvdeonst 1 300 val
+qyrzpfwscc 1 300 train
+qyrzyfrvmx 1 300 val
+qysabipxhr 0 300 train
+qyscponfaf 0 300 train
+qysdsucpbx 1 300 val
+qysmkypwcf 1 300 val
+qyswvpting 1 300 val
+qysxiqdpqz 0 300 train
+qysxmvrtsc 1 300 val
+qysxqoredd 1 300 train
+qytaiboeep 0 300 train
+qytcvvxvsb 1 300 train
+qytdwfhonf 1 300 train
+qythavtvdw 1 300 train
+qytjmqkfhh 1 300 train
+qytnljavlp 1 300 train
+qytqmxzwjs 1 299 val
+qyttsunbew 1 300 val
+qytvtbqezq 1 300 val
+qyufvpqgct 1 300 train
+qyulpzekti 0 300 val
+qyuwbegowk 1 249 train
+qyvafvcjzs 1 300 train
+qyvdxrdoig 1 300 train
+qyvkpkqdwh 1 300 val
+qyvldozdqi 1 300 train
+qyvqrtscbk 0 301 train
+qyvszolgza 1 300 train
+qyvtjgnrdc 1 300 train
+qyvvubsyvw 1 300 train
+qyvzuyhkju 1 300 val
+qywebapqhk 1 300 train
+qywkfrpfii 0 300 train
+qywrqzsixf 1 300 train
+qywtzjmxlp 1 300 train
+qywumoyjqg 1 300 train
+qyxboecmzu 1 300 train
+qyxgeosqbi 1 300 train
+qyxidkesez 0 300 train
+qyxlicusfv 0 300 train
+qyxmnahwky 1 301 val
+qyxqqkawro 1 300 train
+qyycohxsaw 1 300 train
+qyyebirxwe 1 300 test
+qyyedqlsjx 0 300 train
+qyyhuvqmyf 1 299 test
+qyynaedwil 0 300 train
+qyyogceuxn 1 300 val
+qyyrnydpub 1 300 train
+qyyvmdcwxc 1 300 val
+qyyynuqisv 0 300 train
+qyzatmdano 0 300 train
+qyzdgaltuz 1 300 train
+qyzmcggcuh 1 301 train
+qyzyuqkihm 1 300 train
+qzacigepbo 1 301 val
+qzadywgwha 1 270 train
+qzahasoupj 1 300 val
+qzaijnwvva 1 299 train
+qzaqqnsoeb 0 300 train
+qzbfhdrfim 1 300 train
+qzblhojwat 1 300 train
+qzblrcdvvl 1 300 train
+qzbuujgnwh 0 301 val
+qzbwcpojht 1 300 train
+qzcfiylsfx 1 300 train
+qzchhaoptt 1 300 test
+qzcmrqthtf 1 301 val
+qzcptzjtoz 1 301 train
+qzcrvxlrmc 1 300 train
+qzcsywocvv 0 300 train
+qzctgmlmxa 0 300 train
+qzcuesemts 1 300 train
+qzcvnlgfim 1 298 train
+qzcwimwasx 0 300 train
+qzcxcjxvqb 0 300 train
+qzdaonraxt 1 300 train
+qzdiphkloq 0 300 train
+qzdirjlxbw 0 300 val
+qzdplxxvwj 1 300 train
+qzdpsvfxtv 1 300 val
+qzdtpbtpvi 0 300 train
+qzdupbzgss 1 300 train
+qzdzugxibd 0 301 val
+qzebexdvck 1 300 train
+qzecsaxlqa 0 300 val
+qzedzkjwkw 1 300 val
+qzeniplmgh 0 300 train
+qzeujgwgiz 1 300 val
+qzexcszwqh 1 300 test
+qzfchrletm 1 241 train
+qzfgbrcgnz 1 301 train
+qzfjkhplot 1 300 train
+qzfmctgxcs 0 300 train
+qzfpbulfjr 1 240 val
+qzfsrkstzo 1 300 val
+qzfuytbexm 0 300 train
+qzfxdddahc 1 300 val
+qzgdazqwzy 1 300 train
+qzgeuowtnv 1 300 train
+qzgexkljgk 1 300 train
+qzgivlglua 0 300 train
+qzgjayabdn 1 300 train
+qzgnrxnozn 0 300 val
+qzgoehdssy 1 300 train
+qzgsgefwhy 1 300 train
+qzgzphskcf 1 300 train
+qzhawqgpuf 1 300 train
+qzheucgsag 1 298 train
+qzhipvoqgc 1 300 train
+qzhmbvmqtc 1 300 val
+qzhrdqxpax 1 300 train
+qzhssuzyhd 0 300 val
+qzhwjnbxkw 1 300 train
+qzilpovjzb 1 300 train
+qzimdytywy 1 301 val
+qzimuostzz 0 300 train
+qziphesclu 0 300 train
+qzisqairpe 1 300 val
+qziuhapogs 0 300 train
+qziwkqjlis 1 300 val
+qzjdvsloso 1 300 train
+qzjfpupvfo 0 300 train
+qzjfttrrqo 1 300 train
+qzjpcshjjr 0 241 train
+qzjpjnnjyr 1 301 train
+qzjstjlebf 1 300 val
+qzjvaoimae 1 300 val
+qzkeinseeu 1 300 test
+qzkjuamfkf 1 300 val
+qzklcjjxdq 0 300 train
+qzklovxive 1 300 train
+qzknfejyfn 1 300 train
+qzkpbsqlaf 1 300 train
+qzkpufejso 1 300 val
+qzkzkxdvva 0 301 train
+qzkzlywhts 1 300 train
+qzlbdqnpoo 1 300 val
+qzlezuamfa 1 300 train
+qzlfqqpkwb 1 240 train
+qzlivsyhai 1 300 train
+qzljksytqq 1 300 val
+qzlnablvce 1 300 train
+qzlnazgsto 0 300 train
+qzlokfoexi 1 300 train
+qzlxaqsoky 1 300 val
+qzlxcxayoj 1 300 train
+qzlxnhzlta 1 300 val
+qzlzbnbkmr 1 301 train
+qzmnwnivqx 1 300 val
+qzmpndazrh 1 300 train
+qzmsurujkz 0 300 train
+qzmxlxjgsq 1 300 train
+qzmytylyrv 1 300 val
+qznbvgvyku 1 300 train
+qznbzpbhme 1 300 train
+qzngiqvbmr 1 300 train
+qznhyuycnu 1 300 train
+qznkxcwrtr 1 300 val
+qznnndswcf 1 300 val
+qznqdsoenc 1 300 train
+qznvkzpjwp 1 300 train
+qznxfbqyvq 1 300 train
+qznyjcmthh 1 300 train
+qznyqrcmex 1 300 val
+qznzzmksgr 1 300 train
+qzodlzyvbn 1 300 train
+qzodylcndq 1 241 train
+qzogmgikik 1 300 train
+qzogojapop 1 300 train
+qzoppthlbf 1 300 val
+qzowbpoqgs 1 300 train
+qzowurzxoc 1 300 train
+qzpdkijcgy 1 301 train
+qzpepnnmxm 1 300 train
+qzpmjpqxgw 1 300 train
+qzprijltsc 1 300 train
+qzprrccgkd 1 300 train
+qzpvozxlps 1 300 train
+qzpwniycty 0 299 test
+qzpyblfain 1 297 val
+qzpzvieaia 1 300 train
+qzqbfdkuyn 1 300 train
+qzqbxvwfyq 1 300 val
+qzqdcosswe 1 300 train
+qzqhzloabq 1 300 train
+qzqsrandpc 1 300 val
+qzqzmfkimx 1 300 train
+qzrbnevmtn 1 298 train
+qzrddhkthd 1 300 train
+qzreqmeamc 1 300 train
+qzrfmiqbgr 1 301 val
+qzrhsayuav 1 296 val
+qzrhwbvigt 1 300 val
+qzrqqhfrgz 0 302 train
+qzrsogvhcj 1 301 train
+qzsccuwnsc 0 302 train
+qzslwgygnl 1 300 train
+qzspuhinbs 1 240 train
+qztbyrwtjb 0 300 train
+qztdsfdnml 1 300 train
+qztkdlvurz 1 300 train
+qztkxneejm 1 300 train
+qztnbhhziz 1 300 train
+qztngflhgi 1 300 train
+qztqimgtgz 1 300 train
+qztsnbrcsm 1 300 train
+qztvmlncsu 1 300 train
+qztzqeafya 1 300 train
+qzucqrxmaj 0 300 train
+qzuhjrhozy 1 300 train
+qzuluiluyc 1 300 val
+qzutpnswsb 0 300 val
+qzuyjzdinf 0 300 train
+qzuzqmywwr 1 300 val
+qzvdioyoes 1 300 train
+qzvdogaagq 1 302 val
+qzvhtdvkuy 1 300 train
+qzvmlmlbgj 1 299 val
+qzvqikrtln 1 241 train
+qzvtiilqkd 0 300 train
+qzvxibmhfm 1 300 train
+qzvxrzgzyj 1 300 train
+qzwalffoda 1 300 train
+qzwanmhryw 1 300 train
+qzwgkrampj 0 300 train
+qzwjnswhke 1 298 train
+qzwmmvsjjc 1 299 test
+qzwpvwhist 1 300 val
+qzwtswjatz 0 300 train
+qzwvioovie 1 299 val
+qzxaqhqzon 1 300 val
+qzxaqkaedr 1 300 train
+qzxaxrsyud 1 300 train
+qzxflcajaj 1 300 val
+qzxfohujoh 1 298 train
+qzxgystonu 1 300 train
+qzxjirkysy 1 300 val
+qzxjoblkui 1 300 train
+qzxlsnlfbm 1 300 train
+qzxmypvspx 1 300 train
+qzxodrxvrf 1 241 train
+qzxrxwpqip 1 300 train
+qzxsbvqnlp 1 300 train
+qzyaijdbfe 1 300 train
+qzydcypxig 1 298 train
+qzyeppjldo 1 300 val
+qzyfnfxcml 1 300 train
+qzygdebllx 1 300 train
+qzyhlwwpyi 1 300 train
+qzywwuoxqb 1 241 train
+qzzamisyuu 0 300 train
+qzzasztgsp 1 301 train
+qzzfnwjusx 1 300 train
+qzzmxxqdlp 1 298 train
+qzzqyaortf 1 300 train
+qzzvuptjpl 1 300 train
+qzzwrsrfkx 1 300 train
+raaeqtxmqu 1 300 train
+raahwubhxa 1 300 train
+raanmukjft 1 300 val
+raaqfwevxg 1 300 train
+raawzmhdgx 0 300 val
+rabipmnhhl 1 301 train
+rabiwjlmuw 1 300 train
+rablbufbvg 0 301 train
+rabtmpnzzq 1 300 train
+rabwasyxpa 0 300 val
+rabzhtiuak 1 297 train
+raccuygcih 1 301 train
+racfcjilxg 1 300 train
+raciwiczgn 1 300 train
+racjvqnvgk 1 300 train
+raclbaeprc 1 300 val
+racokwyzky 0 300 val
+racpazpgqy 1 300 train
+racravhatf 1 300 train
+racuddkpzl 1 300 train
+radbccigbq 1 300 train
+radllsiaxa 1 300 train
+radnhabelb 1 298 train
+radnlhpacw 1 300 train
+radtbgzivc 1 300 train
+radxwapaqh 1 300 train
+radyyavwaa 1 301 val
+raecimflzm 1 300 train
+raehcmqety 1 300 train
+raehpbyvsy 1 241 train
+raeipcmnzn 1 300 train
+raekzabcrw 1 300 train
+raenmzbwbc 1 300 val
+raenxkvkjo 0 300 train
+raeqoefpwj 1 298 train
+raesetqbfx 1 299 train
+raeuxwwtrt 0 300 train
+raezrmclul 1 300 train
+rafbnikdhw 1 300 val
+rafdiucvur 0 300 val
+rafkckikvh 1 300 train
+rafqexdapt 1 300 train
+rafuugjdfn 1 241 train
+ragcfauznz 1 300 val
+raghzoboqc 1 301 val
+ragjclplkx 0 300 train
+ragxlkpudy 1 300 val
+rahieuuylx 1 300 val
+rahizhvmbp 1 302 train
+rahsswuhlc 1 300 val
+rahtnmmlhf 1 300 train
+rahuzbbulq 1 300 train
+rahwlajhjl 0 300 val
+raibziuvyq 1 300 train
+raiilwewfd 1 239 train
+raijbjrdcg 1 300 train
+raijzpxwpz 1 300 train
+raiqyyzhrw 1 300 train
+raiqzffikb 1 300 train
+rairdqhkmu 1 297 train
+rairvefwmc 0 301 train
+raiszpydud 1 301 train
+raiwxwidsw 1 298 train
+rajjnhytqf 1 301 val
+rajwmkfwud 0 300 train
+rakequwfzp 1 300 train
+rakfrwixrq 1 300 train
+rakkeycska 1 300 train
+rakpnlyqeb 1 301 train
+rakqwcmoxi 1 300 train
+rakwdhemxm 1 300 train
+rakzdfejpz 0 300 train
+raldaikwer 1 300 train
+raliovmzbt 0 300 val
+ralkvpeiwi 1 300 train
+ralrzpyebq 1 300 train
+raltjbvzov 0 300 train
+ralvymdrrf 1 300 train
+ralwvbavjc 1 300 train
+ralxvviqje 1 300 val
+ralyfolylx 1 300 train
+ramdkgiccm 0 300 train
+ramdtlseis 1 300 train
+ramhqgzlii 1 300 train
+ramotheuuu 1 300 val
+ramwyfdaxt 1 300 train
+ranjcemxhn 1 300 train
+ranligugpq 1 300 train
+ranltctdti 1 300 train
+ranoqmqjyh 1 300 val
+ranqxlzoqv 1 300 train
+ranvoqkzwn 1 300 test
+ranwvoaajl 1 300 train
+raoclkeoej 1 300 val
+raodkuhsdj 0 300 train
+raoksnpnna 0 300 val
+raonuulael 1 300 train
+raordaotvd 1 300 val
+raozerusmg 0 300 train
+rapdkmvnjm 1 300 train
+rapdvylmce 1 300 train
+rapefeahqz 1 300 train
+rapfwfntyj 1 300 train
+rapmrhkphc 1 300 val
+raqdscgbwg 1 300 train
+raqjtmxstb 1 300 train
+raqnrcaxfs 1 300 train
+raqpiusrxc 1 300 train
+raqpthrkuy 0 300 train
+raqssofsaf 1 300 train
+raqvunnvrg 1 300 train
+raqypaerdy 1 300 train
+raqzpsejtj 1 298 train
+rarifkochl 1 300 train
+rarkumvdhu 1 300 val
+rarpgopqiy 1 240 val
+rarqriredu 1 300 train
+rarrkvnosw 1 300 train
+rarzuhlmdm 1 301 val
+rasaeezcvr 1 300 train
+rasahvhecx 0 300 train
+rasmcvlsvz 1 300 train
+rasmyfgmrh 1 301 train
+rasqnvdthx 1 302 train
+rassraqafy 1 300 train
+rataozorio 1 300 train
+ratjvamsbu 1 300 train
+ratmcmybgj 1 300 train
+ratpzflzau 1 300 train
+ratqpajlsc 0 300 train
+ratrgupddt 1 300 train
+ratriscfqg 1 300 train
+ratscdfvdk 1 300 test
+ratvwqlrlh 1 300 val
+ratwljpldh 1 301 train
+raujzzwkdt 1 300 train
+raukfbfdpj 1 300 train
+rauyrxosyg 1 301 train
+ravikrnefd 1 300 train
+raviuchpma 0 240 train
+ravmezjflv 1 300 train
+ravwrpompl 1 300 train
+ravwxtbkgt 1 300 train
+rawfeilrtu 1 300 train
+rawfjpmuip 1 300 train
+rawmvtbcts 1 300 train
+rawpcsjedc 1 300 train
+rawsvtxeqe 1 300 train
+rawyfbcvjr 1 299 test
+raxhsslhnz 1 241 train
+raxkwrgpnv 0 300 train
+raxupverqg 1 300 train
+raxuvqdivm 1 300 train
+raxvclgsqt 1 300 train
+rayekvigxv 0 300 train
+rayemjaelt 1 300 val
+rayglprivb 1 300 train
+rayhrvqorn 0 300 val
+rayikkznjm 1 300 val
+rayohqewhd 1 297 train
+raywvmbtqr 0 300 train
+rayxtqfosv 1 300 train
+rayyvdfaea 1 300 train
+rayzefcjvj 1 300 train
+razacdewcv 1 300 train
+razfejrsvt 1 300 train
+raznzfrxql 1 300 train
+razxducjvl 1 300 val
+razycsvijs 0 300 train
+rbabuyhufj 1 300 val
+rbakeasslx 1 300 val
+rbanxullmk 1 300 train
+rbapiqnmfh 1 300 val
+rbawfgnenw 1 300 train
+rbayctqafd 1 300 train
+rbbhchyouc 1 300 train
+rbbhlrhnsn 1 300 val
+rbbuvpcycq 1 298 val
+rbbviehjfh 1 300 train
+rbbxarkisw 1 300 train
+rbbzekkies 1 300 train
+rbcbeuonyg 1 300 train
+rbcbjwxolw 1 300 train
+rbcfwkpwen 1 300 train
+rbcqlydifr 1 298 train
+rbcrzadcme 1 300 train
+rbcvbrppdu 0 297 train
+rbdagesbay 1 300 val
+rbdelwycos 1 300 train
+rbdgobmnen 1 300 val
+rbdgwewypd 1 300 train
+rbdlxwyhjl 1 300 train
+rbdnouwvuo 1 300 val
+rbdqqpmsss 1 300 val
+rbdtfebawd 1 300 train
+rbdyoidvom 1 240 train
+rbedtqlell 1 300 val
+rbeizqzgno 1 300 train
+rbfbqfomob 1 300 val
+rbfbzjmxot 1 300 train
+rbfczyohxf 0 300 train
+rbfezkfqey 0 300 train
+rbflhcsklo 1 300 val
+rbfowmivnh 1 300 train
+rbfpylzics 1 300 train
+rbfqsnaqyt 1 300 train
+rbfstoyfzg 1 300 val
+rbfvimgnid 1 301 train
+rbfwqmithu 1 298 train
+rbfzboagad 1 300 train
+rbgdveuqcq 1 300 train
+rbgjrkqejh 1 300 val
+rbgjsoiind 1 300 train
+rbglamdtad 1 300 train
+rbgsqnrlul 1 300 train
+rbgxugtxru 1 299 train
+rbgxzchzhv 1 300 val
+rbhauhohct 1 241 train
+rbhcgtpcuu 0 300 train
+rbhecseopz 0 300 train
+rbhidowssy 0 300 train
+rbhjjcarwf 1 300 train
+rbhorxkdoe 0 300 train
+rbhtlmgqqa 1 300 val
+rbhuoccrdv 1 300 train
+rbhvotzvsf 1 300 train
+rbhwagdxvx 0 300 val
+rbhwdcujyp 1 300 train
+rbhwnxqfbc 1 300 train
+rbhyrckyqc 1 300 train
+rbicsnfqgs 0 300 val
+rbinrjroaa 1 300 train
+rbinvfhzdg 1 300 train
+rbinzvmbuj 0 300 val
+rbiojhfplp 1 300 val
+rbivftepgg 1 300 train
+rbjjcgzxgr 1 299 val
+rbjrdfrhck 1 300 train
+rbjsioxjac 1 301 train
+rbjvhykhfq 0 300 train
+rbjvwozlxh 0 300 train
+rbjxztkahh 1 300 train
+rbkbybqmat 1 300 train
+rbkcpkwhjn 0 300 train
+rbkesmrvgu 1 300 train
+rbkgvkadij 1 300 train
+rbkhnyougu 1 300 train
+rbkkdrobxw 1 300 train
+rbkkpnepae 1 299 val
+rbkpzormou 1 300 train
+rbksgcybof 1 300 val
+rbksthwwnt 1 301 val
+rbkxjcwygf 1 300 train
+rblfmcfotj 0 300 val
+rblgnprkoy 1 241 train
+rbliyjiyeh 0 300 train
+rblnpbepjh 1 300 train
+rblrskywsp 1 300 train
+rbltrwzhkp 1 300 val
+rblumzaove 1 301 val
+rblupcszbx 1 300 train
+rbmffisqae 1 300 train
+rbmfmrclqn 1 298 train
+rbmfwexzgh 1 300 val
+rbmhzcuqrk 1 300 train
+rbmopexsvs 1 299 val
+rbmstejuot 1 300 train
+rbnfvqyses 0 298 val
+rbnmzwjxwj 1 300 train
+rbnphbljll 1 300 train
+rbofaepkap 1 300 val
+rbofwdoqbh 1 300 train
+rbofxrojxq 1 300 train
+rboggzhtjs 0 300 train
+rbokpxtmti 0 300 train
+rbolaefevd 1 300 train
+rbolsifybo 1 300 train
+rbooypuidn 1 300 val
+rboruxqizl 1 301 val
+rbovrhdobw 1 301 val
+rbpdgkvpxf 1 300 train
+rbpeonuoid 1 300 train
+rbphbnqsew 0 300 train
+rbplupfpkq 1 300 val
+rbprbvzutx 1 300 train
+rbpzdyxdtr 1 300 test
+rbpzgvmdrj 1 300 train
+rbqcizjzfu 1 241 train
+rbqlwkmggj 1 300 train
+rbqqlducfh 1 300 val
+rbqribawxt 1 300 train
+rbqufczjbc 1 300 train
+rbqvxwonjp 1 300 train
+rbqxscjcaw 1 300 train
+rbqzyymeqn 0 300 train
+rbrbxjooel 1 300 train
+rbrdkudfpz 0 300 train
+rbrgxuoove 1 300 val
+rbrjoknzpd 0 301 train
+rbrjykbheg 1 300 train
+rbrpwbvbbh 1 300 train
+rbrxameydz 1 300 train
+rbsacuwtcx 1 301 train
+rbsbbhjtqc 1 300 train
+rbsduzycak 1 300 train
+rbsfjrhtcc 1 300 train
+rbsoczbsdu 1 300 train
+rbsooyjghi 1 300 train
+rbsqytvobx 0 298 val
+rbsufwdfel 1 300 train
+rbsznefhpr 0 300 train
+rbtdxwhvgw 1 298 train
+rbtflalxmn 1 300 val
+rbttksdaen 1 302 train
+rbtvfrxtou 1 300 train
+rbtyzpmwkd 1 300 val
+rbuaurtetg 1 300 train
+rbufvipinj 1 300 train
+rbukttezjq 1 300 train
+rbummlbqdr 1 300 train
+rbuqsirnxh 1 300 train
+rbuteckzgh 1 300 train
+rbuvrwajvo 1 300 train
+rbuxdgaatz 1 300 train
+rbuzigczwv 1 300 train
+rbvcifizzm 0 300 val
+rbvhhloyua 0 300 train
+rbvjkdjipf 1 300 val
+rbvlmjljev 1 300 train
+rbvqghnbez 0 300 val
+rbvrmojort 1 299 test
+rbvsiqjnqd 1 300 train
+rbvtvmlyho 1 300 train
+rbvuowntbo 1 300 train
+rbvxbxwnrm 1 300 train
+rbwanmuagv 1 300 train
+rbwbmqvtkr 1 300 test
+rbwjthghwl 1 300 train
+rbwuopkhsx 1 300 train
+rbwxfaloaw 0 300 val
+rbwzfypxen 1 300 train
+rbxgerogtn 1 300 train
+rbxhgulnvi 1 300 train
+rbxnulhwav 1 300 train
+rbxsnlwkrs 1 300 val
+rbycjeiqmv 0 300 train
+rbyclpfzhl 1 300 val
+rbydjieaci 1 299 val
+rbyhazdpsj 1 300 train
+rbylzcdzyl 1 300 train
+rbymfthdfa 1 300 val
+rbynmbihfv 1 300 train
+rbyrwvsgeb 1 300 train
+rbywxpyjpa 1 300 train
+rbzdjrvjnk 1 300 train
+rcacwtyaca 1 240 train
+rcaitmlocj 1 241 train
+rcavvozpzg 1 300 train
+rcawpyqnmd 1 300 val
+rcawttvtrp 1 301 train
+rcazvdadti 1 300 train
+rcbbnnxhsg 0 300 train
+rcbhezdeou 1 300 train
+rcbkruzaop 1 297 train
+rcbwugacsh 1 299 test
+rcbxoojslb 0 300 train
+rcbzoqddhg 1 300 val
+rccawplwcy 1 298 train
+rccdijoiwz 1 300 train
+rcchrsnvtp 0 300 train
+rccmgtgaad 1 300 test
+rccmslprej 1 300 train
+rccpsnfotz 1 300 val
+rccsvcinoz 1 300 train
+rccxaadrsu 1 300 train
+rccxjxzaaw 1 300 val
+rccypumibp 1 300 val
+rcdmtxehbo 0 300 train
+rcdpxmnsjl 1 300 train
+rcdrotflax 1 300 train
+rcdvcnsatq 1 300 train
+rcdxwvmjnu 1 300 train
+rcecrgeotc 1 299 test
+rcejkynepf 1 300 train
+rcejovizlt 1 300 val
+rcejudmaru 1 300 train
+rcelostggm 1 300 train
+rcembihfll 1 241 train
+rcenwbfnws 1 300 train
+rceuabpvba 1 300 train
+rcfakutvez 1 300 train
+rcfaokeusr 1 300 train
+rcfcitfwmy 1 300 train
+rcfdabcwoj 1 300 train
+rcfeoetewy 1 300 train
+rcfjfkmpxi 1 300 train
+rcfmpfkglb 0 300 val
+rcfnkwtthd 0 297 train
+rcfqjdyrsl 1 300 train
+rcfubalrmc 1 300 train
+rcfyvqqohn 1 300 val
+rcfztfrouh 0 300 train
+rcgccchtvn 1 300 test
+rcgdrsvfke 0 300 train
+rcggtytdrw 1 300 train
+rcgjaofhgt 1 300 train
+rcgkalblfr 1 300 train
+rcgmxtenus 1 300 train
+rcgpggmbnq 1 300 train
+rcgrbvspat 1 298 val
+rcgwksttwk 1 300 train
+rchagmtmny 1 299 val
+rchhpxquai 0 300 val
+rchmsaoeyi 0 300 val
+rchpononkc 1 300 train
+rchrcsiwkv 0 300 val
+rchrrpzyzb 1 300 train
+rchsrzntnv 1 300 train
+rchvxtfiws 1 300 train
+rchzryisyp 1 146 train
+rcikijjebo 1 300 train
+rcinlnxyes 1 300 train
+rcinlxdwtt 1 300 val
+rcinunpjgt 1 296 train
+rcixkdiuds 1 300 val
+rcizjhtxuf 1 300 train
+rcjcofptsj 1 300 val
+rcjdocdlml 1 298 val
+rcjevsaigb 1 298 train
+rcjfenutoo 1 99 train
+rcjfxxhcal 1 299 test
+rcjkpbmtmu 1 300 val
+rcjlrotzoy 1 300 val
+rcjpzgnrsn 0 301 train
+rcjvpxfevz 1 298 train
+rcjxzkuxwc 0 300 train
+rcjyfjozsp 0 297 train
+rckbbwquji 1 301 train
+rckbyufszr 1 301 train
+rckdmkkfpe 0 300 train
+rckjekygut 1 300 val
+rckklmtemj 1 240 val
+rckrdubomt 1 300 train
+rckrviuyuy 1 241 train
+rcksvbjhyg 1 300 val
+rckvbtjosu 1 300 train
+rckvcarnmg 1 300 train
+rckvyynmuw 1 301 val
+rcllalqhow 1 299 val
+rclnfldnws 1 300 train
+rclpjrzvrt 1 300 train
+rclslgzjay 1 301 train
+rcmbefdvml 1 300 train
+rcmbtzywqo 1 300 val
+rcmcjakmlh 1 300 val
+rcmfwomzhx 1 300 train
+rcmikrsamy 1 300 train
+rcmlgvvgoe 1 300 train
+rcmnccewdv 1 300 train
+rcmuxfaqfh 1 299 train
+rcmwrmuyuc 1 300 train
+rcmxobbrja 1 300 val
+rcncybvyun 0 300 val
+rcndjmkidm 0 298 train
+rcnvikbxkq 1 300 train
+rcompctabm 1 300 train
+rcooasixes 1 300 train
+rcoolgvuxd 1 300 train
+rcovjvmlcu 1 296 val
+rcozdzanxe 1 300 train
+rcpcfdxiti 1 300 val
+rcpcvijghn 1 300 train
+rcpdpacrki 1 300 train
+rcpjctvthx 1 300 val
+rcpjrfhggi 1 300 train
+rcplsrtsub 1 300 train
+rcpmjwwtyb 1 300 train
+rcpodulvkm 0 300 train
+rcprnffjgi 0 300 train
+rcpvportuy 0 300 train
+rcqcattfsu 0 300 train
+rcqignemkt 1 300 train
+rcqoybeond 1 298 val
+rcqtwptpqr 1 241 train
+rcqwfgbzyj 1 300 train
+rcrbmffaka 1 300 train
+rcreiryfeq 1 299 val
+rcrfbnbjzu 1 300 train
+rcrqwqzjta 0 300 train
+rcrrfirmsc 1 300 train
+rcrtgwfwys 0 300 train
+rcrupvuxdf 1 301 train
+rcsbscjmfs 1 300 train
+rcsdwyosav 1 300 train
+rcsedfbnny 1 300 train
+rcsfdnnqlo 1 298 train
+rcsfrtqmig 0 300 train
+rcsgzcough 1 300 train
+rcslbgtxzs 1 300 train
+rcsoeqgjky 1 300 train
+rcsrgoacvi 1 300 train
+rcswqppwsc 1 300 train
+rctjmjvyvz 1 300 train
+rctkmvjnaw 1 300 train
+rctmoawxbn 1 300 train
+rctosbzann 1 298 train
+rctronqqjs 0 300 train
+rctshwqjvp 1 300 val
+rcttjovqdv 0 301 val
+rcubywzqdz 1 300 train
+rcusajllyo 1 300 train
+rcuwgbjbpr 1 300 train
+rcuwuhsetm 0 300 val
+rcvgwraymk 1 302 train
+rcvngveexh 1 300 train
+rcvotlpusf 1 300 train
+rcvpmlkvzk 1 290 train
+rcvvpkoyac 1 300 train
+rcvxydarbj 1 300 train
+rcwgrccvar 1 300 train
+rcwicljypx 1 300 val
+rcwqpluyia 0 300 val
+rcwqyvqjmh 1 300 train
+rcwurajcut 1 300 train
+rcwwidinmv 1 301 val
+rcwwsrusfx 1 300 train
+rcxcsniefp 1 241 train
+rcxeisjfaz 1 300 train
+rcxeypjgnl 1 300 train
+rcxgtkiwnu 1 300 train
+rcxhiwqykk 0 300 train
+rcxjkfdhoe 1 300 train
+rcxohmfwhl 1 300 train
+rcxsxkscws 1 300 train
+rcxvohtsig 1 302 train
+rcyagevhqx 1 300 train
+rcykreuhop 1 300 train
+rcyqtdksjx 1 300 train
+rcytnuefvt 1 300 test
+rcyxyjfvrz 1 300 val
+rczaxiryex 1 299 val
+rcznfldjuy 1 298 train
+rczofofyny 1 300 train
+rczqfrjubn 1 300 train
+rczqjjqoor 1 300 train
+rczqubhdel 1 300 val
+rdaaohhkny 0 300 train
+rdajhoxjfx 1 296 val
+rdaktuviek 1 298 train
+rdatehxjgx 1 300 train
+rdauhpvwpl 1 300 train
+rdaurvwjkh 1 300 val
+rdaztcqhbj 1 300 train
+rdbpzmutyq 1 300 train
+rdbuuzuxgp 1 300 val
+rdbxcbseek 1 300 test
+rdbyppomvp 1 300 train
+rdcbecqugg 1 300 train
+rdcfutkpnn 1 300 val
+rdcgcavkuj 1 301 val
+rdciqrrwze 1 298 train
+rdckswmwsm 1 300 train
+rdcqelneor 1 241 train
+rdcsqjipgr 1 300 train
+rdcxxbvkfh 0 300 train
+rddaehtwvk 1 300 train
+rddffwfkeu 1 301 train
+rddmpvgagi 1 300 train
+rddsjnntya 1 300 train
+rddzwabube 1 301 train
+rdedmstpfn 1 300 train
+rdedmzpiwm 0 300 train
+rdeimtfukk 1 297 train
+rdeixpsoab 1 301 val
+rdeyakpiwj 1 301 val
+rdezagjwpb 0 300 train
+rdfdbmyrqm 1 300 train
+rdfjrtpnsv 1 300 train
+rdfmibakjm 0 300 train
+rdfpsyryss 1 301 train
+rdftmwfljq 1 300 val
+rdfwvhoagh 1 300 train
+rdfyrycggk 1 300 val
+rdgatfwsmt 0 300 train
+rdgfxoxcwt 1 300 val
+rdgjobouvt 1 300 val
+rdgnjflypb 1 300 val
+rdgozcjroa 1 300 train
+rdgruvdipv 1 300 train
+rdguejhomm 1 300 train
+rdgunwydxy 1 300 train
+rdhcmvujqa 1 300 train
+rdhcsmpbil 1 240 train
+rdhdhxszuc 0 300 train
+rdhfakejmb 1 300 train
+rdhfttmktp 1 300 val
+rdhjgflrjg 1 300 test
+rdhltwxkwk 1 300 train
+rdhnpqxdsy 1 300 val
+rdhomoizjm 0 298 val
+rdhtjkgpub 1 300 val
+rdiazfyvhh 1 300 train
+rdiegzplvf 1 300 train
+rdieogexpi 0 300 train
+rdihyoyhlk 1 288 train
+rdiogxmrwa 1 300 train
+rdiqugbboo 0 300 train
+rdiuczxzar 1 300 train
+rdiwgpwtgq 1 300 train
+rdiyhpvqcq 1 300 train
+rdiziyuodw 1 300 train
+rdjdakeijt 1 300 train
+rdjhzdocul 1 300 train
+rdjjdscpkl 1 300 val
+rdjqfyymdg 0 298 train
+rdjqqtyjlr 0 300 train
+rdjrrazozz 1 241 train
+rdjwlvvwtv 1 301 train
+rdjwpgkzaq 1 300 train
+rdjxtczphi 1 241 train
+rdjzvudxus 1 300 train
+rdkefshrty 1 300 train
+rdklsoqzxu 1 239 train
+rdkodifvjp 1 300 val
+rdkqpgajlg 1 300 test
+rdkshykjpd 0 300 train
+rdktirowyr 1 300 train
+rdleogshfk 1 300 train
+rdlfudwlgj 0 300 train
+rdlgugouog 1 300 train
+rdllcphmgv 1 300 train
+rdlpqszngw 0 298 train
+rdlsqzeadp 1 299 val
+rdlttiglxq 1 300 train
+rdmbdjzvom 1 301 train
+rdmfzozfgi 0 300 val
+rdmizncshu 1 300 train
+rdmnblvyzy 1 300 train
+rdmowwjlfc 1 300 train
+rdmuhuiepx 1 300 train
+rdmyllnaxb 0 300 val
+rdncyjhnru 1 301 train
+rdniwxnwyw 1 298 val
+rdnyqgwwvv 1 300 train
+rdobrtuvqk 1 300 train
+rdofxhjszo 1 300 val
+rdojtcccdw 1 301 train
+rdonczobvw 1 288 train
+rdonmoqdcg 1 300 train
+rdoqqakjfs 0 300 train
+rdotwevlvm 1 300 val
+rdpausigpg 1 301 train
+rdpcwufovt 0 300 train
+rdpdlgeywm 1 300 train
+rdpseeyfgp 1 298 train
+rdpumvchul 0 300 train
+rdpuptnhrw 1 300 val
+rdpvsfvvdg 1 269 train
+rdpydirdlj 1 300 train
+rdqanntvqj 1 300 test
+rdqapigsyb 1 300 train
+rdqfwzpzlg 1 300 train
+rdqkurfmsa 1 241 train
+rdqnjmhoeq 1 300 train
+rdqocrevfa 1 300 train
+rdqokuannd 1 301 train
+rdqqxrhfmz 1 300 train
+rdqwxzikyp 1 300 train
+rdqynerbru 1 300 train
+rdqysxdoko 1 300 train
+rdrefxezwp 1 300 train
+rdriyshqep 1 301 val
+rdrlqfioqc 1 300 train
+rdrtksqxic 1 300 train
+rdrtpuszmy 1 300 train
+rdrwfjdyjn 1 300 val
+rdsgutvpvl 1 300 train
+rdsnmcvgyk 0 300 val
+rdsrbzzoyn 1 300 val
+rdsxhdwxpa 1 301 val
+rdszvoprdc 1 300 train
+rdtcetmywq 0 300 train
+rdtchxorzz 1 300 val
+rdtevevmua 1 300 train
+rdtswopgdj 1 300 train
+rduaawcqpp 1 300 train
+rducxknyhr 1 300 val
+rdudggrlnq 1 298 train
+rdugbvxaxa 1 241 train
+rdundildsa 1 300 train
+rdupdjnjyh 1 300 val
+rdvffjxguz 1 241 train
+rdvfpxqwnn 1 300 train
+rdvjmsalvv 0 301 train
+rdvkzpkmep 1 300 train
+rdvldjmhbt 1 300 train
+rdvmpcuhvd 1 300 train
+rdvqwqapja 1 299 test
+rdvtkfouro 1 300 train
+rdvvkfvtnm 1 300 train
+rdwavfndgq 0 300 val
+rdwbpmdyzg 1 301 train
+rdwenayiqb 1 300 train
+rdwlnskhlx 1 300 train
+rdwzennpqj 1 300 train
+rdwzjzlphz 1 300 train
+rdxapxcgyf 0 300 val
+rdxfcupiyo 1 300 val
+rdxhieurnc 0 300 train
+rdxixcurzj 1 300 train
+rdxokcnyvp 1 300 train
+rdxrlhkfsc 1 241 train
+rdxxfgjgqm 1 300 val
+rdxzepfjrs 1 300 train
+rdzfcalfvc 1 300 val
+rdzkjusxrz 1 300 train
+rdznzbnxyo 1 300 train
+rdzuenwtjz 1 300 train
+rdzyzwqhde 1 300 val
+rdzyzyccwv 1 300 val
+reahpihzlm 1 300 train
+reamgsosuu 1 136 train
+reaqhcgrti 1 300 train
+rebaioocax 1 300 val
+rebajepjaf 1 300 train
+rebillzyow 1 300 train
+rebntxspcn 1 300 train
+recaenqacg 0 300 train
+recbbtqpbu 1 300 train
+reccwuefen 1 300 val
+recdyopidh 1 300 train
+rechvdnrlp 1 301 train
+reckpejoef 1 300 train
+reclcicerz 1 300 val
+recmhmjttq 1 300 test
+recobhmjad 1 298 train
+recogqypfz 1 300 train
+recwvyhtgu 1 300 test
+recyhzkihw 1 300 train
+reddxthswm 1 300 val
+redeywjpuw 1 300 train
+redhlohvyi 1 300 train
+redmibyrnj 0 300 val
+redplmsvpf 1 301 train
+redptfsrpv 1 300 train
+redunhhlku 0 300 train
+redzcbuldi 1 296 train
+reefwfxjot 1 269 train
+reepsdjbie 1 300 train
+reesbefvpz 1 300 train
+reewxlyouf 0 294 train
+refasbqxrh 0 300 train
+refbfhzxip 1 300 val
+refdoaazmz 1 300 train
+refehmjafs 1 300 train
+refiqvdsmh 1 299 test
+refjvzrooz 1 300 train
+refnrunbag 1 301 train
+refrkbeeym 1 300 train
+refrswzkdr 1 298 val
+refshytvob 1 300 val
+refwonexvz 1 300 train
+refzhsrqco 0 300 train
+regahkpsko 1 300 train
+regcuyroaa 0 300 train
+regiyqjuoh 1 300 train
+regkrsafpf 1 300 train
+reglrriuri 1 300 train
+regnbbnlrp 1 298 train
+regyrgtpky 0 300 train
+rehayrqspw 1 300 train
+rehewmdutb 1 240 train
+rehfblwbgf 1 299 test
+rehflwrnyo 1 300 train
+rehvamfzys 1 300 train
+rehyrkfyle 1 300 train
+reiaglkyjc 1 300 train
+reicagumns 1 300 val
+reidnpqmqn 1 300 train
+reiefuerfu 0 300 val
+reieplhaaf 1 255 train
+reigrllhxr 1 300 val
+reikakbuct 1 300 train
+reikncunht 1 300 train
+reiochaqce 1 301 train
+reiqexmnel 1 300 train
+rejbekusmh 1 300 train
+rejbgucbqn 1 299 test
+rejepsdbqv 1 300 val
+rejmrurgnf 1 300 val
+rejntsyoht 1 300 train
+rejtrzgozq 1 300 train
+rejxllylip 1 300 train
+rejzshsszf 0 300 train
+rekamrhcmg 1 300 train
+rekbqaqdmg 0 300 train
+rekjpgvgkk 1 300 val
+rekoxqsexe 1 300 train
+relgsofzvh 1 298 train
+reliceogpx 1 241 train
+relkjgoblh 0 300 train
+relqsupkti 0 300 train
+relqzrvewy 0 300 train
+relrfifywa 0 300 train
+relrochpci 1 300 train
+relshwvbck 1 302 train
+relukgpngy 1 300 train
+remavoohjm 1 241 train
+rembcffwwi 1 300 train
+remfdtczwp 0 300 train
+remfraaykj 1 300 train
+remjlzfyyl 1 300 train
+remmtzwkll 1 300 val
+remsnfztja 0 300 train
+remumaaehj 1 300 train
+remvprybji 1 300 train
+remxshuflu 1 300 train
+renpslndlv 1 300 train
+renqnzwuhn 1 301 train
+rensmrgvuy 1 300 val
+reoafpgwdq 1 301 train
+reojwapmic 1 300 train
+reoncfgvfd 1 241 train
+reoqyctxwq 1 300 train
+reowrwoxgc 1 300 train
+repsjlzyae 1 300 train
+reptpdidos 1 300 train
+repufoluci 1 300 train
+reqapkhajz 1 300 train
+reqdtkkhda 1 300 train
+reqemhodll 0 300 train
+reqopfzfju 1 300 train
+reqvcvdefa 1 300 train
+rerbxujgoz 1 300 val
+rerhbfqvdz 1 300 train
+rerhhkbcdf 1 300 val
+rerizjpxes 1 300 train
+rerolslsqj 1 300 train
+rerpivllud 1 299 test
+rerrdqjdne 1 300 train
+reruntevii 1 300 val
+rervgafhre 1 297 train
+rerywwfxmz 1 298 train
+rerzjqutnu 1 300 train
+rerzxsnuif 1 300 train
+resfqgwhri 1 300 train
+resgaevflx 1 300 train
+resjnmbtch 1 300 train
+reslpowdbv 1 300 train
+resmgcexcf 1 300 val
+restcryzzl 0 300 train
+retlnzihfr 1 300 train
+retnipyswj 0 300 train
+retwcfaujx 1 300 train
+reudiptskb 1 300 val
+reuekpvtff 1 300 train
+reupqrdjos 1 300 train
+reurmirvyb 1 300 val
+reuveljibk 1 300 train
+reuvgzpgnt 1 300 train
+reuwabmpuf 1 300 train
+reuyimrqxg 0 300 train
+reuzxamqxx 1 300 train
+revfprplje 1 298 val
+revncvbvbv 0 300 val
+revrhzwyxw 1 241 train
+revsvdclbg 1 300 train
+revzcgwupj 1 300 val
+revzcyldgc 1 300 train
+rewagripxi 0 300 val
+rewlovnefe 1 300 val
+rewlvzaoit 1 300 train
+rewmhexmno 1 300 train
+rewyhkernx 1 300 val
+rexaqfaowd 1 300 val
+rexfxfobui 1 240 val
+rexgunpmvz 1 300 train
+rexixeqtkv 0 300 val
+rexmjwkuwd 1 300 val
+rexqwjibjt 1 300 train
+rexrhyyvrq 1 300 train
+reyjdnlcej 0 300 train
+reysoekyhe 1 299 val
+reyyqbhhhc 1 300 val
+rezfcgkjlx 1 300 val
+rezhkfqzpc 1 300 train
+reziumjnmx 1 300 val
+rezjkpxzpk 1 300 train
+rezkynwaly 1 300 train
+reztzulhbq 1 300 train
+rezwsrfwci 1 300 train
+rezwzbbqyb 0 300 train
+rfabeyednj 1 300 train
+rfadutedir 1 300 train
+rfaedgbfib 1 300 train
+rfaeimbkle 1 301 train
+rfaewfobiz 1 300 train
+rfahyynkuf 0 241 train
+rfakffjumr 0 241 train
+rfasjmhgvc 1 300 train
+rfatjcnbju 1 300 train
+rfaxlhfvvs 1 300 train
+rfaxpthggb 1 300 val
+rfazfszzxj 1 300 val
+rfbdzbhfbk 1 300 train
+rfbfnghamo 1 300 val
+rfbhmfkysx 1 300 train
+rfbpamuuxb 1 300 train
+rfbuyouchk 1 300 train
+rfbwlgmiup 1 300 train
+rfbwukxpye 0 300 val
+rfbxlzlzsj 1 300 val
+rfcgheaqwm 1 300 test
+rfcgjdwpri 1 299 val
+rfchxnbnaz 1 300 train
+rfcsmhrgvs 0 300 train
+rfctgidtwy 1 300 train
+rfcxvumqie 1 297 train
+rfcyldbeme 0 300 val
+rfddyxijhx 1 300 train
+rfdefzisms 1 241 train
+rfdfjrgyei 1 300 train
+rfdfswqegy 1 298 train
+rfdfxeuebl 0 300 train
+rfdlpetdtc 1 300 val
+rfdodjkccm 1 300 train
+rfeagdwnnn 1 300 test
+rfeomcivbi 1 300 train
+rfeqrvnnme 1 301 train
+rfesbewgwz 0 300 train
+rffcelfjuc 1 301 val
+rffoncdaqy 1 300 val
+rffttupbkx 0 300 train
+rfgfslexzm 1 300 train
+rfggjvrocs 0 300 val
+rfgkhremwh 0 300 train
+rfgknbzfrv 1 300 train
+rfgxuqplfd 1 241 train
+rfgzgrsdel 1 300 train
+rfhboxpypk 1 300 train
+rfhhprvmse 0 300 val
+rfhhwnicyq 0 300 train
+rfhwnzuihr 1 300 val
+rfhztjztat 1 300 train
+rfibiinwbq 0 300 train
+rfibpaymwb 1 300 val
+rfiitcaryo 0 300 train
+rfizmzchgw 1 300 train
+rfjahigzmu 1 300 val
+rfjlyniqby 1 249 train
+rfjomkkorn 1 300 train
+rfjuhbnlro 1 300 test
+rfjvjoycgr 1 300 train
+rfkhkzvonm 1 300 train
+rfkjinpthj 1 300 train
+rfklwxlaxy 1 300 train
+rfkseshjtt 1 298 train
+rfkvceigfk 1 300 train
+rfkybcpfxo 0 300 train
+rfkzwstncy 1 300 val
+rflghteuxx 1 300 train
+rfllwbwugy 1 301 val
+rflndregaz 0 300 train
+rflnmkwrmi 1 300 train
+rflqcmvymf 1 300 train
+rflqwepfwt 1 300 train
+rflttobidv 1 300 train
+rflvhdenli 0 300 train
+rfmdbaoesa 1 300 val
+rfmfbwqbvs 1 241 train
+rfmmvhkqus 0 300 train
+rfmrqmwjkh 1 300 train
+rfmusgukat 1 300 train
+rfmvpngexo 1 300 val
+rfmxxzpcyt 0 300 train
+rfngbcfwqt 0 300 train
+rfnlrnhess 1 298 train
+rfnoegtfgl 1 300 val
+rfnsaehrqs 1 300 train
+rfntnnarwd 1 300 train
+rfnumbdiik 1 300 train
+rfnvxrkyfy 1 298 train
+rfnwrnkokw 1 300 train
+rfoeydlrvv 1 300 val
+rfofjldvtb 1 300 val
+rfofxtwdxp 1 288 train
+rfojosxqcn 1 300 train
+rfpaqnoosd 1 300 train
+rfpcprybif 1 300 val
+rfpdkjstaj 1 300 train
+rfpjsloxzg 1 300 test
+rfpjvmqzre 1 298 train
+rfpmritkaq 1 300 train
+rfqcscdvbu 1 300 train
+rfqhpayvga 1 301 train
+rfqhqfrixk 1 298 train
+rfqkgewkvf 1 300 val
+rfqkpuctnz 1 300 train
+rfqqtszrdj 0 300 train
+rfqsjzabra 0 300 train
+rfqxewdkgx 1 299 test
+rfqyxalbmz 0 300 train
+rfrccyrnjw 0 300 train
+rfrcwmnpdk 1 300 train
+rfrdhoxcch 1 300 train
+rfreelhcas 1 300 train
+rfrhzqfbwa 1 300 train
+rfrjmsfjcz 1 297 val
+rfronnyujq 1 300 train
+rfrulefxdj 0 301 val
+rfrwtfsuku 0 300 val
+rfsabfhicg 1 298 train
+rfscglbdiv 1 300 val
+rfsivygfhh 1 300 train
+rfsjfghjef 1 300 train
+rfsjhjwwtf 1 300 train
+rfspfmsofw 1 300 train
+rfssaqlhhw 1 300 train
+rfsukgulqd 1 300 train
+rfsuolriur 1 300 train
+rfsxjcepjw 0 300 train
+rftflqvkil 0 300 train
+rftgfdduft 1 300 train
+rftgjbfckv 1 300 train
+rftqyddfmd 1 241 train
+rftseuxqkl 1 300 train
+rftyolnnnh 1 301 val
+rfuhnmpclz 1 302 val
+rfuhuytaqp 1 299 test
+rfuiletayc 1 300 train
+rfujtrhnga 1 300 train
+rfukeoxpqu 0 300 train
+rfunifaaev 1 300 train
+rfuugyfcfk 1 300 train
+rfuvdyrose 1 300 train
+rfvbziooub 1 300 train
+rfvcqrfvsq 1 300 train
+rfvdaqhndi 1 300 train
+rfvjjpmbwp 1 300 train
+rfvmtpuvps 0 300 val
+rfvojczcnx 1 300 train
+rfvqellwek 0 300 val
+rfwdakvqht 1 300 test
+rfwekwegqi 0 300 train
+rfwfuempkp 1 300 train
+rfwixigmps 1 300 train
+rfwnqdcnyc 1 300 train
+rfwqfxmxtf 1 300 train
+rfwvqfvjfo 1 300 train
+rfwwmusvah 1 300 train
+rfwxcinshk 1 299 test
+rfwylyhhzl 1 298 train
+rfwyxbrxxj 1 300 val
+rfxgqjrjnz 1 300 train
+rfxlyttirs 0 300 train
+rfxogycbbi 1 300 train
+rfxrgmvouq 1 300 train
+rfxvqpkvzt 1 300 train
+rfykxekxer 1 300 train
+rfyoggbopm 1 300 train
+rfysbajarq 1 300 train
+rfywczujdb 1 300 train
+rfyzkkjnrz 1 300 train
+rfzisdvpdt 1 300 train
+rfzotlhmce 0 300 train
+rfzzdnmefy 1 300 test
+rfzzrftgco 0 300 train
+rgaeiwscyr 1 296 val
+rgarqfixsm 1 300 train
+rgasvymjrj 1 300 train
+rgawxnijtz 0 300 train
+rgayepdcla 0 300 train
+rgbdumupgz 1 300 val
+rgbjrcwcip 1 300 val
+rgboidzqtb 1 301 val
+rgbsqmzjht 1 300 train
+rgbtqlxpxd 1 300 train
+rgceyymbvr 1 300 train
+rgcfodclts 1 300 train
+rgcjolidhg 1 300 train
+rgcluqvueg 1 300 train
+rgclzcauea 1 300 train
+rgcplyuqwy 1 300 val
+rgcsjzqcis 1 300 train
+rgcvczcqmb 1 300 train
+rgcyajkwuq 1 300 train
+rgcysoaikl 1 300 train
+rgdctplzim 1 301 val
+rgdekydncq 1 300 train
+rgdptgovnb 1 300 val
+rgduernkfc 0 300 train
+rgeaimngac 0 300 train
+rgeenmnicf 1 300 train
+rgeevtswuc 1 300 train
+rgegpilfvx 0 300 train
+rgexghhtkh 1 300 val
+rgfcghlcuv 1 300 train
+rgfuqhnpex 1 300 train
+rgfxrhrptn 1 300 val
+rgfypgfozg 1 300 train
+rggchknust 1 300 train
+rggeuqntqd 1 300 train
+rgghiebzvx 1 300 train
+rggiaaozlm 1 300 train
+rggimejhsu 1 300 train
+rgglgyfbfk 1 300 test
+rggnvwizgh 1 300 val
+rggxmtabqi 1 300 train
+rggzyowekk 1 300 train
+rghfvkwxum 0 302 train
+rghirbnsvt 1 300 train
+rghkdfgbkl 1 300 train
+rghpjsecso 1 301 val
+rghtglfaht 1 300 val
+rghtqvqyel 1 300 train
+rghxapzhkj 0 300 train
+rghyzxjzqo 1 300 val
+rgicgcedud 1 300 train
+rgigbjpsis 1 300 val
+rgiknexmjo 1 300 val
+rgimsqlxre 1 300 train
+rgiujjmbna 1 300 train
+rgivquufbd 1 300 train
+rgjeclushz 1 301 train
+rgjgkxordy 1 300 train
+rgjktorqtd 1 300 train
+rgjmlvwiig 1 300 train
+rgjphbslsj 0 300 train
+rgjvczuemu 1 300 train
+rgkauxyqtf 1 300 val
+rgkcvawyop 1 300 val
+rgkfjsiyvu 1 300 train
+rgkgeurmky 0 300 train
+rgkocywrem 1 300 train
+rgkojcmqcm 1 300 train
+rgkpiojsoh 1 239 val
+rgkqulzaem 0 300 train
+rgksdbawuc 0 300 train
+rgksfueguz 1 300 train
+rgkvzthnhr 1 300 train
+rglbeyhbai 1 300 train
+rglfdnekjv 1 300 train
+rglfmhxhwo 1 300 val
+rgljdgzhys 1 300 train
+rglkbzfbyy 1 300 train
+rglwsosvfy 1 301 val
+rgmdnlqojd 1 300 train
+rgmdqlpukt 1 300 train
+rgmdykowkk 1 288 train
+rgmhkqkpjs 1 300 train
+rgmkwprqjo 1 300 val
+rgmllhylbj 1 298 train
+rgmrwsxlxw 1 300 train
+rgmyjcyejd 1 300 train
+rgnjmgyusx 1 300 train
+rgnlapnfjh 1 301 val
+rgnrdxtack 1 300 train
+rgnsguiuvm 1 288 train
+rgnwiqqkrz 1 301 train
+rgouxvqauk 1 300 train
+rgowwuybit 1 300 train
+rgoxwoofkw 1 300 train
+rgpdkaijyc 1 300 train
+rgpephqfnj 1 300 train
+rgpnfljbwf 1 300 train
+rgppjevnpn 1 300 train
+rgpridicbi 1 300 test
+rgpurtzxoy 0 300 train
+rgpvjzjeyd 1 300 val
+rgpwvpxzgl 1 300 train
+rgpxmlcnhe 1 300 train
+rgqcygqsjz 1 300 train
+rgqgssltna 1 300 train
+rgqlfgblri 1 300 train
+rgredpxmpo 1 300 val
+rgrqhjtoby 0 300 train
+rgrsiddkgk 1 300 train
+rgsbrkstic 0 300 train
+rgsifpgnec 1 299 test
+rgsmnodvyv 1 298 train
+rgsmthcmel 1 300 train
+rgsnuysymu 1 300 train
+rgsqvjtyqc 1 300 train
+rgtdvgmaey 1 300 train
+rgtggtkpaf 1 300 train
+rgthvflads 1 300 train
+rgtkdxwebb 1 300 train
+rgtlvoskty 1 300 val
+rgtmbxxalj 1 241 train
+rgtofufpzc 1 298 train
+rgtpympngy 1 300 train
+rgtuioqsxu 1 301 train
+rgtwjkftpa 1 298 val
+rgvdkuqajm 1 298 train
+rgvgtfpfad 1 300 train
+rgvnuqxzni 1 300 train
+rgvoihexjm 1 301 train
+rgvovnivwc 1 300 val
+rgvpctvdkn 1 300 train
+rgvpeunazx 1 300 train
+rgvspxurey 1 300 train
+rgvtnmbkvy 1 241 train
+rgvuaskhwj 1 300 train
+rgvvvzgsxr 1 300 train
+rgwajagfcb 1 300 train
+rgwenetndf 0 300 train
+rgwflpowfv 1 300 train
+rgwklilpzl 1 300 val
+rgwnakzckp 1 300 train
+rgwpafpkah 1 300 train
+rgwpkgdluf 1 300 train
+rgwtkpoycx 1 300 train
+rgwvudmxtv 1 300 train
+rgxaccnokf 1 300 val
+rgxbivulnj 0 300 train
+rgxhztngwi 0 300 train
+rgxjohmray 1 300 train
+rgxpzevrsp 1 300 train
+rgxvxwktsf 1 300 train
+rgyfloxnff 1 301 train
+rgyhdgurdd 0 300 train
+rgyidsgwgv 1 300 train
+rgyseheqcn 1 300 val
+rgyypohipo 1 300 train
+rgzaaigzgk 1 300 train
+rgzgylwxoi 1 300 train
+rgznjgwxzj 0 300 train
+rgzrtypdxv 1 300 train
+rgzuuwwkol 0 300 val
+rgzuvzimzk 1 300 train
+rgzvjfpwlo 1 300 train
+rgzwmifgcj 1 300 val
+rgzydsstqm 1 300 train
+rhafxgiuie 1 300 train
+rhardruycd 1 300 train
+rhauuajgwq 0 300 val
+rhawulgwmz 1 300 train
+rhayeawnsq 1 300 train
+rhbaymjnwd 1 300 val
+rhbbjxsdkz 1 300 train
+rhbchjrums 1 300 train
+rhbcyezlzl 1 300 train
+rhbdmlhgmr 1 297 train
+rhbfjvjzmz 1 300 train
+rhbhyafnfz 1 300 val
+rhbjenzjhz 1 300 val
+rhbmpmcnxx 1 300 train
+rhccwstztr 1 300 train
+rhcifqslqe 1 300 train
+rhcktumnsc 1 300 train
+rhclxglqls 1 300 val
+rhcovagajb 0 300 train
+rhcppchebc 1 300 test
+rhcrveuxtn 1 300 train
+rhcsjkanrq 1 300 train
+rhcspbranh 1 300 train
+rhcvhpxkbg 1 300 train
+rhcyvdfomq 1 300 train
+rhczhjkppk 1 300 train
+rhdefwaryk 1 300 train
+rhdmpvhclp 1 300 train
+rhdnckvctt 1 300 val
+rhdpmppbtr 1 300 train
+rhdxvfeclz 1 300 train
+rhdzoxajzn 0 300 val
+rhebjliqxg 1 300 train
+rhegyzoyet 1 300 train
+rheivndyri 1 300 train
+rheivzupzg 1 301 train
+rhelvutplh 1 300 val
+rhemiwruny 1 299 test
+rhesaccltu 1 301 train
+rhetqgxrjx 1 300 train
+rhewtlbnwa 1 300 train
+rheztgdonj 1 300 train
+rhfaapsync 1 300 val
+rhfczwnhtr 1 300 val
+rhffxnzzvi 1 300 val
+rhfmgfmxoj 1 300 val
+rhfmjnlvvj 1 300 train
+rhftkrhlzo 0 300 train
+rhfuztrfnz 1 300 train
+rhgbhdtxkj 1 300 val
+rhgcuwjojf 1 300 train
+rhgcvbpsby 1 300 train
+rhgjhjmqdi 1 300 train
+rhglckodhm 1 300 train
+rhglfykrhj 1 300 train
+rhgmworndk 1 600 train
+rhgxtpcson 1 300 train
+rhgyuyppmc 1 300 train
+rhgzohvxet 1 301 train
+rhhcpshqch 1 300 train
+rhhdeovjjc 1 300 train
+rhhfdmrzmp 1 300 train
+rhhvmnluiz 1 300 train
+rhhyonwjyg 1 300 train
+rhifjirdzn 1 300 train
+rhikzqzota 1 300 train
+rhindwschv 1 300 train
+rhiorgxahb 1 300 train
+rhipoojqrs 1 300 train
+rhirwypfbf 1 300 train
+rhisobjals 1 300 train
+rhivrzngsd 1 297 train
+rhjoactdaa 0 301 train
+rhjoyedcwv 1 300 val
+rhjrndafnu 1 300 train
+rhjzplqoes 1 300 train
+rhkeuhtgpt 1 300 train
+rhkkiauywh 1 300 train
+rhkomopevh 1 300 train
+rhkqfhobbu 1 300 val
+rhkrchpycn 1 300 train
+rhkvadpfgh 1 299 test
+rhkxewmfec 1 300 train
+rhkxofkyja 0 300 train
+rhlbdsamue 1 300 val
+rhlbryumtx 1 300 train
+rhlbxcznio 0 299 val
+rhlcikjgjk 1 300 val
+rhlcyrksia 1 300 val
+rhlerhvthk 1 300 train
+rhlhdalzfk 1 300 train
+rhlhzuxgkd 1 300 val
+rhlojfgydd 0 298 train
+rhlyvdfdjm 1 300 val
+rhmhlfyxjg 1 300 train
+rhmjgvfpvn 1 300 train
+rhmjrydrtq 1 300 val
+rhmoopqfgk 1 301 train
+rhmyhzfzdf 0 300 train
+rhncgvckxz 1 300 train
+rhncslawoz 0 300 train
+rhnftlotrq 1 300 train
+rhnihakgig 1 300 train
+rhnjbuqxcs 1 301 train
+rhnlbwsyyz 1 300 val
+rhnlieivnw 1 298 train
+rhnoijcvcb 1 241 train
+rhnqxqvmzs 1 300 val
+rhobpvgzij 1 300 train
+rhodslrygu 1 300 train
+rhofnjliwh 1 300 train
+rhojtobzuj 1 300 train
+rhomcxcufp 1 300 train
+rhonujrrtj 1 300 train
+rhotsujndc 1 83 train
+rhotzsptag 1 300 train
+rhouqfomuk 1 300 train
+rhozehfcxt 1 300 train
+rhpgrxtmwq 1 300 train
+rhpkxybsqu 1 300 train
+rhplzukuuu 1 300 train
+rhpmrvglxw 0 300 train
+rhpnsrypay 1 300 train
+rhpwnedqmj 1 300 val
+rhqbprthgg 1 241 train
+rhqdxqciwo 1 300 train
+rhqgdkpfbt 1 300 train
+rhqgihaney 1 300 train
+rhqmlnvxfs 1 300 val
+rhqoytkngh 1 300 train
+rhqpdtmdlx 1 297 train
+rhqpxohjlk 0 300 train
+rhqrpbygxy 0 300 train
+rhqrsyewgg 1 300 val
+rhqwzlnyuf 1 301 train
+rhraglplun 1 298 val
+rhrgxyrizv 1 300 train
+rhrijrnjof 1 300 train
+rhrkcsjfzq 1 298 val
+rhrougesbg 1 249 train
+rhrpqsrfdc 0 300 val
+rhrutmynym 1 300 train
+rhrykauqqy 1 301 val
+rhsfhjjfmt 1 300 train
+rhsrmlubrz 0 300 train
+rhstovhynw 1 301 train
+rhsvunxqtl 1 300 val
+rhtcoibdpc 1 300 train
+rhtkkklkcm 1 300 val
+rhtnfqygcw 1 300 train
+rhtnuwftaf 1 300 train
+rhtowksqbd 1 300 train
+rhtvkbrnyh 1 300 val
+rhtwwixphj 1 300 train
+rhuahwxhlr 1 300 val
+rhucpsbexd 1 300 train
+rhudqymzuo 1 300 val
+rhuhjrguel 1 300 train
+rhumlndepk 1 269 train
+rhuvtpcucs 0 300 train
+rhuwogthox 1 300 train
+rhuxlnvrph 1 299 val
+rhvcubgvpi 1 299 test
+rhvdrqlhxe 1 300 train
+rhvponjpjq 0 300 train
+rhvrtrfune 1 296 train
+rhvsxaewcr 1 300 test
+rhvtboqqkh 1 300 train
+rhvtyzpmhx 0 300 val
+rhweihtjlk 0 300 train
+rhwiigokes 1 300 train
+rhwijorjsk 0 300 train
+rhwlxurwzo 1 300 val
+rhwnodoydg 1 300 val
+rhwnrhnxob 1 300 train
+rhwqsuuqsr 1 300 train
+rhwstdvlsb 1 300 train
+rhwzunhzgv 1 300 val
+rhxgcqmcuh 1 300 train
+rhxifbofoc 1 300 train
+rhxsvscfpu 1 300 train
+rhxwrotcvi 1 300 train
+rhydpgtapx 1 300 train
+rhyewqosge 1 300 train
+rhygosiygb 1 300 train
+rhyjkoobby 1 300 train
+rhylluriac 0 300 val
+rhylsjrigb 0 300 train
+rhymgzxdyp 1 300 train
+rhynzlttmu 1 300 val
+rhypjpmmxw 0 300 train
+rhyukllpqy 1 300 val
+rhyxgxuwhd 1 300 train
+rhyzpxqgbd 1 300 train
+rhzaeythmm 0 300 train
+rhzhhszfss 1 295 train
+rhzrzwwdla 1 241 train
+rhzwvzcmay 1 300 val
+riaapnoqxv 1 300 test
+riacuezakc 1 300 train
+riadnybysl 1 300 val
+riagxfntkf 1 300 train
+riajyglxur 1 300 train
+riajyjbhmx 1 300 train
+ribewasyjd 0 300 train
+ribgusctec 1 302 val
+ribgxmtdaz 1 300 val
+ribhvopifx 1 300 train
+ribmcqumcm 1 299 val
+ribrlukbkn 1 300 train
+ribxzoelli 1 300 train
+ricaaszpbg 1 300 train
+riccitfbge 1 300 val
+ricdstvqpb 1 300 val
+ricegozcwb 1 301 val
+ricfxftfxr 1 301 val
+richkklwsj 1 300 train
+riciqhftax 1 300 test
+riciyrtwdh 1 300 train
+ricjiupsse 1 300 train
+riclmjgoqu 1 300 train
+ricpbuzctz 1 298 train
+rictcemrzk 1 300 train
+ricuheqvdb 0 300 train
+ricwivccgd 1 300 train
+ricxksboqi 1 300 train
+ridbmwwtwz 1 300 train
+ridctzpucu 1 300 train
+ridcuyswqu 1 300 train
+ridiczlgdt 1 300 train
+ridiekiqvm 0 300 train
+ridnxbaomi 1 300 train
+ridpsnuevu 1 300 train
+ridrlfphki 1 300 test
+ridtjjnatr 1 300 train
+ridtvjxixf 1 300 train
+ridwvsdxzf 0 300 train
+rieagnsetc 1 300 val
+rieamybrpj 1 300 val
+riebrjdlqq 1 300 train
+riejnnyxir 1 300 train
+rielxbrjup 1 300 train
+rieqbjzzxs 1 300 train
+rierqyzbty 1 300 train
+riesfpayda 1 300 val
+rieuddzplv 0 300 val
+rievkxunge 1 300 val
+rifcvwgwdc 1 300 train
+rifgebvnli 1 300 train
+rifiyadulj 1 300 train
+riflgvvznr 1 300 train
+rifljnmkcl 1 300 train
+rifsgutrkr 1 301 val
+rigahmawld 1 241 train
+rigaqdvgsa 1 300 train
+rigelqnswz 0 300 train
+rignbxgswt 1 300 train
+rigopvdcci 1 300 train
+rigpuflxop 1 298 train
+rigsjeonxa 1 300 train
+rigvpugoip 0 300 train
+rigxpjxfhc 1 300 val
+rihgjplyfb 1 300 train
+rihjqaikez 1 300 train
+rihmmvubqq 1 300 train
+rihqhztxdy 1 300 train
+rihuiaegjh 1 300 train
+rihuurjkgi 0 300 train
+rihuwhgmen 0 300 val
+rihzypkzjd 1 300 train
+riiasslukr 0 300 train
+riimtodfiz 1 300 train
+riiqlriqzx 1 300 train
+riiroggcxl 1 300 train
+riiwlkkert 1 300 val
+riixshdqna 1 300 train
+riizlqngim 1 300 val
+rijdjarigk 1 300 train
+rijhmtzwxi 1 301 train
+rijhrkkvkw 1 300 train
+rijjizyqay 1 300 val
+rijpvzghaa 1 300 val
+rijpxsjcwl 1 300 train
+rijqaijfad 1 300 train
+rijudscyuc 1 300 train
+rikiylalwk 1 300 train
+rikqcxzvhy 1 300 train
+riktdgneac 0 300 train
+rikuzqxsyb 1 300 train
+rikxkfkhsx 1 300 train
+rildbtyaoa 1 300 val
+riljfrtubt 1 300 train
+riljgleqzj 1 241 train
+rilowfufdo 1 300 train
+rilulssouy 1 300 val
+riluoonkqn 1 300 train
+rilxalwmfz 1 300 train
+rilyevizdk 1 300 train
+rilypvmlnp 1 301 train
+rimbigwobi 1 301 val
+rimccnquim 1 300 train
+rimgarlgod 0 299 train
+rimmvyebhj 0 300 train
+rimpjuzxdw 1 300 train
+rimrqutsnt 1 299 test
+rimsuvbdkq 0 300 train
+rimwvphzqs 1 300 train
+rimxlkorjg 1 300 val
+rimxuemjbz 1 300 val
+rinfdxjoqu 1 300 train
+rinhlpfkvj 0 300 train
+rinhshinvv 1 300 train
+rinjzyqllh 0 300 train
+rintrysqqu 1 300 train
+rinxnnealn 1 300 train
+rinzzdmqun 1 300 train
+rioaiqzguu 1 300 train
+riobjlbzmr 1 300 train
+riolylselx 1 300 val
+riopdiqieg 1 300 train
+riorjqcudm 1 241 train
+riorygbhcw 1 300 train
+riosmbifsw 0 301 train
+riourrdfsw 1 300 val
+riowiwhgil 1 300 train
+rioxyowqkb 0 300 train
+rioyuibhhq 0 300 val
+ripekykbia 1 300 train
+riplbxlyeb 1 300 train
+rippuedwzs 1 300 train
+ripvajoeue 1 300 train
+ripvguqqop 1 300 train
+ripwqpdqtz 1 301 val
+riqasfedlc 1 300 train
+riqdieafus 1 300 train
+riqjqnyrlo 0 300 train
+riqkulkeam 1 300 train
+riqlojrbrz 1 300 train
+riqpmljsdd 0 300 val
+riqruzjcqo 1 300 train
+riqscqxedk 1 300 train
+riqsligtkj 0 300 train
+riqsogxost 1 300 train
+riqulthbsk 1 301 val
+riqvfktrlj 1 300 val
+riqviyxuvz 1 300 train
+riqyjmrzpe 1 300 val
+riraxebxai 1 300 val
+rirebmjwyw 1 300 train
+rirlttfyas 0 300 train
+rirqgoraes 0 300 train
+rirymstiia 1 241 train
+rirzhrtoub 1 300 train
+rishvdlhom 1 300 val
+risidhrulo 1 300 val
+riskgfvhwi 0 297 train
+riskowbvrb 1 300 val
+risqfmjppn 0 300 train
+rissjlexca 1 300 train
+ritdokqatm 1 300 val
+ritkznokux 1 300 train
+rituczdgub 1 298 train
+riudkrwpsb 1 300 train
+riugyrgzvl 1 300 train
+riugzzscau 1 300 train
+riuhfsrzqt 1 300 train
+riukrufpgh 0 300 train
+riulgghtea 1 300 train
+riumbxkmyo 1 300 train
+riuopoyiyd 1 300 val
+riuwqjyedm 0 300 train
+riuxfayrdo 1 300 train
+rivbpgbqcm 0 301 train
+riveshxlce 1 298 train
+rivffvdsst 1 300 train
+rivgzvhhgw 0 300 train
+rivptoxgke 1 300 train
+rivrppbwgg 1 300 train
+rivyxgixod 1 300 train
+rivzzbaxqv 1 300 train
+riwbdsvtmb 1 300 train
+riweqzxvlv 1 297 train
+riwgueksrk 1 301 val
+riwklzijip 1 300 train
+riwkoifdub 1 302 train
+riwnlgahzk 1 300 train
+riwnybbjqy 1 300 train
+riwuhdrfaw 1 300 train
+riwvkzboar 1 136 train
+rixhcjkapl 1 300 train
+rixipotxkt 0 300 train
+rixjixvthd 0 300 train
+rixkkyppdm 0 300 train
+rixpoeqiaq 1 300 test
+rixrsqftcj 1 300 train
+rixvgnvbln 1 298 train
+rixviasvaw 0 300 val
+riyeevtaon 1 300 train
+riyqlhcalf 1 300 train
+riyswpkkrn 1 300 train
+riyubmitvk 1 300 train
+rizkegptmw 1 300 train
+rjaeswoums 1 301 val
+rjagsjwajb 0 300 train
+rjakceyuxb 1 299 train
+rjanjkrkql 1 300 train
+rjaohqrslt 1 300 train
+rjasojrhjn 1 241 train
+rjazicvdco 1 300 train
+rjbfjpafvs 0 300 val
+rjblhiaico 1 298 train
+rjbrjxlatq 1 300 train
+rjcggzoswh 1 300 train
+rjciqpobvv 1 300 val
+rjcjcdkzkw 1 300 train
+rjckfvtlyv 1 300 train
+rjcokdendz 1 296 train
+rjdasmpapw 1 300 train
+rjdcjijubm 0 300 train
+rjdgekljgm 1 300 train
+rjdghgsrqy 1 300 train
+rjdmlxmqce 1 300 train
+rjdnwvynxk 0 300 train
+rjdpaxcacv 1 300 train
+rjdrbewusn 0 300 train
+rjdzzozyhc 1 300 train
+rjedvdzput 1 300 train
+rjeffhfpdr 1 300 train
+rjeicgezvi 1 299 train
+rjeisvlbos 1 300 train
+rjenxqsdpj 1 300 train
+rjeqjgnpcz 1 300 train
+rjfgiartwk 1 146 train
+rjfikssvxj 1 300 val
+rjfjbjxqcw 1 300 train
+rjfjmzgqzb 0 300 val
+rjfjnmuzte 1 301 train
+rjfjoquznu 1 241 train
+rjfkkwwkli 1 300 val
+rjfkmrhpur 0 300 train
+rjfoplnuuu 1 300 val
+rjgcicnjbi 1 300 train
+rjgmgqwbpz 1 300 train
+rjgqbcgaqp 1 300 train
+rjgqkowhuj 1 241 train
+rjgqugfvfd 1 300 train
+rjgrqjurhw 1 300 train
+rjgshsswzv 1 299 val
+rjgtoeqwfn 1 301 train
+rjgvdvvmbl 0 300 train
+rjgvngaopm 0 300 train
+rjgvucvdrq 0 300 train
+rjhocbovjz 1 301 train
+rjhptdeshw 1 300 val
+rjhqryrfmb 1 300 train
+rjhrfqgwun 1 241 train
+rjhswebbst 0 300 train
+rjiawhqfhi 1 300 train
+rjibcmrbep 1 300 train
+rjidakggck 1 300 train
+rjimoemmim 0 300 train
+rjixghpivz 1 300 val
+rjjnvvakqe 1 300 train
+rjjquzcape 1 300 train
+rjkcafnguk 1 300 train
+rjkjvbklrx 1 299 val
+rjkmppnvfz 1 300 val
+rjkpzynacp 1 297 val
+rjkrejuatj 0 301 train
+rjkumofcvi 1 300 train
+rjkyhxocmm 1 300 val
+rjkyubznpi 1 300 val
+rjlciltijo 1 301 val
+rjlgchzmfv 0 300 train
+rjlkwdrfbn 1 300 val
+rjloubmjpi 1 300 val
+rjlpyqmiet 1 300 train
+rjlquzkujy 1 300 train
+rjltfcozac 0 300 train
+rjlthqxwlr 1 300 val
+rjluzlvbdd 1 300 train
+rjlvnhiozq 1 298 val
+rjmbhdeafl 1 299 test
+rjmpltcntc 1 300 train
+rjmquskzfy 1 301 train
+rjmtflzlvs 1 300 train
+rjmwcjiavx 1 300 train
+rjmxcwolhm 1 300 val
+rjnkxcmiwm 1 300 train
+rjnudqdmdq 0 300 train
+rjnzjvfaiz 1 300 train
+rjoabjswwx 1 300 train
+rjohqqxzyh 1 300 train
+rjoradvcsv 1 300 val
+rjotmltspl 1 241 train
+rjoyvhljld 1 301 val
+rjozjwvmku 1 300 train
+rjpbjigjcc 1 300 train
+rjpiwfchaq 0 300 train
+rjpjxluosx 1 300 train
+rjpksognpg 1 300 train
+rjpweremwb 1 296 train
+rjpxcvrwlw 1 302 train
+rjpxxunwwt 1 300 val
+rjqatoncop 1 300 train
+rjqauvxxzp 1 300 train
+rjqpwmcezv 1 241 train
+rjqrwzlleq 1 300 train
+rjqtuxhyoj 1 301 train
+rjqtyaxdyw 1 300 train
+rjraiizdsc 1 300 train
+rjrcehqsbs 1 300 val
+rjrfrverfx 1 300 train
+rjrguvwaof 1 300 train
+rjrlfzfxqi 1 298 train
+rjrudhdbpf 0 300 train
+rjrufwsmob 1 300 train
+rjrvnjybgg 1 300 train
+rjrwxebuoq 1 249 train
+rjrwywxrno 1 300 train
+rjrypoldpl 1 300 train
+rjrzsqacth 1 300 train
+rjsfnlecdh 1 300 train
+rjsfvvojba 0 300 train
+rjshquskjw 1 300 train
+rjsiixajds 1 300 train
+rjsmlstaaq 1 300 train
+rjsszjuqaj 0 300 train
+rjsxqhnzqq 1 300 train
+rjtdjjfxzi 0 300 train
+rjthvnaiad 1 301 train
+rjtiulmezk 0 300 train
+rjtnickasn 1 300 train
+rjtsbdysdz 1 300 train
+rjtwbhiaxx 0 300 train
+rjtxmfklwi 1 300 train
+rjtymxeamb 1 300 val
+rjuddimxce 1 300 train
+rjudlivnao 1 300 train
+rjuefvzrqj 1 300 val
+rjugiiprad 1 241 train
+rjuxhxrjfd 1 300 train
+rjvombtxro 1 300 train
+rjvpdiukpj 0 300 train
+rjvqzzkaqz 1 300 train
+rjvvqnyetx 0 300 train
+rjvwbxfokp 1 300 test
+rjwbmzksiz 1 100 train
+rjwcybsaeh 1 300 train
+rjwdxvcsdg 1 300 test
+rjweulggzf 1 300 train
+rjwftlbrfh 1 300 test
+rjwhssvzly 1 300 val
+rjxdjiaefw 1 300 val
+rjxmorolsj 1 300 train
+rjxpgojbqb 1 300 train
+rjxpntahbf 1 298 train
+rjxrjdwntf 1 300 train
+rjxtizfxbp 1 300 train
+rjxtsiycme 0 300 val
+rjxyzmwsqm 1 300 train
+rjyamsinkv 1 300 train
+rjycbnxsvv 1 300 train
+rjydtdmmld 1 300 train
+rjypclfkci 1 300 val
+rjytutzwrc 1 300 train
+rjyuimecje 1 300 train
+rjyujdxnbl 1 300 val
+rjyvbdcygj 1 300 train
+rjyxdsjlen 0 300 train
+rjzafaghui 0 299 train
+rjzcloipoq 1 300 train
+rjzhmuindb 1 300 train
+rjzjxbhhxf 1 300 train
+rjzorwdzor 1 300 train
+rjzouvtgvg 1 300 train
+rjzpduzvha 1 301 train
+rjzpxwjcsy 1 301 train
+rjzvgihmuu 0 300 train
+rjzzbkhgih 1 300 train
+rkacapjxgh 1 300 train
+rkaccvprrz 1 300 train
+rkadsvtyfd 1 300 train
+rkadyenfsr 1 301 val
+rkaeqrmbtd 1 301 train
+rkafihsjnd 1 300 train
+rkafqojwlz 1 299 test
+rkanbumofm 1 300 train
+rkanmooidr 1 300 train
+rkasxaljmj 1 301 train
+rkaxetzemd 1 300 train
+rkaxfulwbu 1 300 val
+rkayvtkulj 1 300 train
+rkbautpdzv 1 300 train
+rkbgajlymx 1 298 val
+rkbmomerdm 1 300 val
+rkbnxzufqe 1 300 train
+rkbqdnjteg 0 300 train
+rkbrbxhywo 0 300 train
+rkbrqfzpvk 1 300 train
+rkbtwjeyeb 1 300 train
+rkbugznaub 1 300 train
+rkbwhvciej 1 300 train
+rkbxgozdju 1 301 train
+rkbxybizvj 0 300 train
+rkbynalsjc 1 288 train
+rkcggmqsdo 1 300 train
+rkchlldgpz 1 300 train
+rkcjmbmahn 1 300 train
+rkcmjsasfu 1 298 val
+rkcnbasgex 1 241 train
+rkcwnyiybx 1 300 train
+rkcwunmzds 1 300 train
+rkcywmtvrm 1 300 train
+rkdbrlqicf 1 300 train
+rkdfqxsjfi 1 300 train
+rkdheztcht 1 300 train
+rkdhthhfdf 1 300 train
+rkdhwnzpzx 0 300 train
+rkdjyszkae 1 300 train
+rkdoczwqky 1 300 train
+rkdskvpzvn 1 301 train
+rkdwwwwasl 1 300 train
+rkdxatjvqe 0 300 val
+rkebekzfiy 1 300 train
+rkecxcyblt 1 300 val
+rkegztisxp 1 301 val
+rkejngjuzn 1 300 train
+rkepudotbp 0 300 val
+rkerpasnur 1 300 val
+rketdymbog 1 300 val
+rkettrjjhi 1 300 train
+rkewdbjmeu 1 297 val
+rkezgzxnoo 1 300 train
+rkezlwzxao 1 300 train
+rkfbpnxilw 1 300 train
+rkfduxmdrc 1 300 train
+rkfimbwyir 1 300 train
+rkflgbgcol 0 300 val
+rkfrwjeemq 1 301 val
+rkfzwbhqry 0 300 train
+rkgejsqhcf 1 300 train
+rkgfxhbrqk 1 241 train
+rkgnqbsujd 1 300 train
+rkgrcuiaxx 1 300 train
+rkgxnoppto 1 300 train
+rkhbjclqjx 1 300 train
+rkhbofdrvp 1 300 train
+rkhdbhehfq 1 300 val
+rkhewcchbn 1 300 train
+rkhjqexnys 1 241 train
+rkhlwuybxn 1 300 train
+rkhoiiedxv 1 300 train
+rkhpwllwbc 1 300 train
+rkhyonaypy 1 300 train
+rkhytbaejo 1 300 train
+rkibmhxkwr 1 300 val
+rkijvkmrvb 1 300 val
+rkirdxcydv 1 300 train
+rkiuncowha 1 300 train
+rkjeizprgg 0 300 val
+rkjestwldq 1 300 val
+rkjhxvdnsv 0 300 train
+rkjkgkgpni 1 300 train
+rkjtiaznur 0 300 train
+rkjukwvult 1 300 val
+rkkdenjfrr 1 300 train
+rkkhdunjzr 1 300 train
+rkkmlqufmf 1 300 train
+rkknpjkxsm 1 300 val
+rkkoosljig 1 300 train
+rkkqebtkch 1 300 test
+rkkqkxkggn 1 300 test
+rkktwbiskw 1 300 train
+rkkygstyyx 1 300 train
+rklawjhbpv 1 300 test
+rkldstosuu 1 300 train
+rklhljcpwt 1 300 train
+rklvjjvfcv 1 300 train
+rkmabbjgla 1 298 train
+rkmafjxdve 1 300 train
+rkmdpgiyzy 1 301 train
+rkmqikcacs 1 301 train
+rkmsxwhpui 1 300 train
+rkmtyexpjc 1 300 train
+rkmyglwkgi 1 300 train
+rkmykkoubd 1 300 train
+rkmyulpjuo 1 300 train
+rkmzavobdn 1 299 train
+rkmzdldobl 1 300 train
+rknnkxwjhl 1 300 train
+rknogxbklz 0 300 val
+rknrpqjmtg 1 300 train
+rknvbdykkb 1 301 val
+rknzwqpqgl 0 300 train
+rkoackkynp 1 300 train
+rkoimhzssp 0 297 train
+rkojuygepw 1 300 train
+rkojxksaoi 1 300 train
+rkpdbkapfv 1 301 train
+rkpjcqewbj 1 300 val
+rkpkitclys 1 300 train
+rkpkmymrie 1 299 val
+rkpkrpuwal 0 300 val
+rkppryzjum 1 241 train
+rkpzrrqiwu 1 300 train
+rkqnzqrxlc 1 300 val
+rkqoghhppr 1 300 train
+rkqqgwurqt 0 239 train
+rkqrsvkxxu 1 240 val
+rkqvvayfqu 0 301 val
+rkqwwxjduw 0 300 val
+rkqzmjzzsg 0 300 train
+rkraxwkndr 1 300 train
+rkrizcgzgt 0 300 train
+rkroldvwni 1 300 train
+rkrpbbuwmr 1 300 train
+rkrqasmjvi 1 300 train
+rkrscgdhjm 1 300 train
+rksbaxynlb 1 300 train
+rksowurrwf 1 300 train
+rkssmmlwlp 1 300 train
+rksxpymttm 1 241 train
+rktbrmrgpj 1 300 train
+rktdlafmma 1 300 train
+rktfpkiqzq 1 300 train
+rktfumvxjw 1 300 train
+rktrpsdlci 0 300 test
+rktzwbzgna 1 300 train
+rkukylmybd 1 300 val
+rkunuhzufh 1 300 train
+rkuuztuidk 1 297 train
+rkvszomxzm 1 300 val
+rkvzvrsohl 1 300 train
+rkwdeizthx 1 300 train
+rkwdttbfcc 1 300 train
+rkwgxkbwgh 0 300 train
+rkwlvcnevt 0 296 val
+rkwomxrhnl 1 300 train
+rkwqyenzxk 0 300 train
+rkwsmhkngc 1 300 val
+rkwtrgmfmt 1 301 val
+rkwxdgemup 1 300 train
+rkxepdkger 0 301 train
+rkxjhbtqhw 1 300 train
+rkxtedaesl 1 300 train
+rkxvniszwy 1 301 train
+rkxwibdptz 1 300 train
+rkygzeyegz 1 300 train
+rkyheqgits 0 295 train
+rkyjehrrrr 1 300 train
+rkykeovyes 1 300 train
+rkyqglffxs 1 300 train
+rkytpdhnxz 1 300 train
+rkyzuqxtdw 1 300 train
+rkzabzjtbv 1 300 train
+rkzfxgrluh 1 300 train
+rkzhwkvytv 1 299 test
+rkzmduihsz 0 300 val
+rkzwwqassz 1 300 val
+rlaczpbrgz 1 300 val
+rlajawsrkd 1 300 train
+rlanlrwraj 1 301 train
+rlarqhcyxa 1 301 val
+rlasgfidha 1 300 train
+rlatrksjpf 0 300 train
+rlbajvttrj 1 300 train
+rlbemckxpk 1 300 val
+rlbmtsewjr 1 300 train
+rlbppizezq 1 300 train
+rlbtunaqib 1 298 train
+rlbxdarrup 1 299 train
+rlbxjwajuh 1 300 train
+rlcczepaol 1 300 train
+rlcjruwejs 1 147 train
+rlcsyuitlg 1 300 train
+rlcudlobuk 1 300 train
+rldaeqjzqe 1 300 train
+rldaiatzur 1 301 train
+rldbmzntrp 1 300 train
+rldbztgjay 1 300 train
+rlddeqccmq 1 300 train
+rldfpzqgiv 1 300 train
+rldhylnyzs 1 300 train
+rldoejloex 1 300 train
+rldqrlnvde 1 301 train
+rldvkobvdc 1 300 train
+rleblhhbyf 1 297 train
+rlejhsaetv 1 300 train
+rlephvzrar 1 300 val
+rlerxsnsid 1 300 train
+rlespxvibl 1 300 train
+rlezpphnre 1 300 train
+rlfdfosjgs 1 300 train
+rlffdgfuyq 1 300 train
+rlffjkxsqq 1 300 test
+rlffjyqing 1 300 train
+rlfohgzdsr 1 301 val
+rlgejwkiea 1 300 val
+rlgekygvjn 0 301 train
+rlgeuaphpd 1 301 train
+rlgihsegsm 1 300 val
+rlglbrseeu 1 299 val
+rlgqjbcpzr 0 300 val
+rlgtivkoyy 1 298 train
+rlgumwinrx 0 300 train
+rlgwlyllel 0 300 train
+rlhbyejtff 1 300 train
+rlhlzbilbe 1 300 train
+rlhmppiklf 0 300 train
+rlhocrystt 1 300 train
+rlhpnehlal 1 300 train
+rlhxvxvnqg 1 300 val
+rlhxzjilze 1 300 val
+rlibyiywym 1 300 train
+rligkgkhna 1 300 val
+rlijcagqpg 1 295 train
+rlilafvfjm 0 300 val
+rlizttazbi 1 300 val
+rljdbxyscr 1 300 train
+rljifiitdw 1 300 val
+rljipfupod 1 300 train
+rljlhgqymp 0 300 train
+rljmwhopju 1 300 train
+rljtsqgrrv 1 300 train
+rlkkfalgru 1 300 train
+rlkrteswpq 1 300 test
+rlkueiemkf 0 300 train
+rlkygewnwi 1 300 train
+rllcorzadx 1 300 train
+rlldzrnmdn 0 300 train
+rllevpaqrk 1 300 val
+rllgkitjfx 1 300 train
+rllpgflwaq 1 300 test
+rllqptmgxi 0 300 train
+rllqzqjvat 1 300 train
+rlltowzizq 1 300 train
+rllwhliuxp 1 300 train
+rllzwllwsq 1 298 val
+rlmbsayayf 1 300 train
+rlmeureizn 1 300 val
+rlmhejztfu 0 300 val
+rlmmjzfalc 1 300 train
+rlmmzgdpgs 1 298 train
+rlmnkudfke 1 301 train
+rlmuxjdmem 1 297 train
+rlmvpmsudv 1 300 train
+rlmwbawvpv 1 300 train
+rlmxbaujyy 1 241 train
+rlmzkecohf 0 300 train
+rlnhkhvaaf 1 296 val
+rlnjtkcngq 1 300 train
+rlnkgcghpg 1 300 val
+rlnvwfcnek 1 300 train
+rlnysftewy 1 300 val
+rlobkmavkx 1 300 val
+rloltgotif 1 300 val
+rlooeyoxfs 1 300 train
+rloviuuxky 1 300 val
+rlpaboktyp 1 300 val
+rlpkfdyaho 1 300 train
+rlpncrnxjv 0 300 train
+rlpnkcttik 1 300 val
+rlpqbpoyir 1 300 train
+rlpukzycni 1 300 train
+rlpzlortnh 1 300 test
+rlpzqjiclq 1 300 train
+rlqbowounu 0 300 test
+rlqehdfztg 1 300 train
+rlqeqblpea 1 241 train
+rlqfqgaoxx 0 300 train
+rlqhoiplla 1 300 train
+rlqkrecipi 1 298 train
+rlqktunbyn 1 300 train
+rlqotzcvyi 1 300 train
+rlqvjnfsqt 1 300 train
+rlqwurjdwa 1 302 val
+rlrdqgxkub 1 300 val
+rlrgefioak 1 300 train
+rlrhgbpyol 1 300 train
+rlrtjcvlqz 0 300 train
+rlrwqiragp 1 300 train
+rlsighguhz 1 300 train
+rlspukkkmb 0 298 train
+rlstxjyvsf 0 300 train
+rlsxupuvol 1 300 train
+rlszkgaoqs 1 300 train
+rltsrqhbff 0 300 val
+rlttvcbrgs 1 300 val
+rluazbqfuq 1 300 val
+rluijtmipe 1 300 train
+rlunhmvfuv 1 301 val
+rlvammwcub 1 300 train
+rlvaxiqant 1 300 train
+rlvfsudzvh 0 300 train
+rlvgpdrgvi 1 300 train
+rlvgtsjyer 0 300 train
+rlvsrjqfey 1 300 train
+rlvundeiso 1 300 train
+rlvvppfrpc 1 301 train
+rlwafcctmp 1 300 train
+rlwjctlalt 0 300 val
+rlwjuegqts 1 300 train
+rlwkdhgoqw 1 300 train
+rlwlrvoojl 0 300 train
+rlwmotblyw 1 270 train
+rlwrjnefhf 0 300 train
+rlwtwlytnp 1 300 test
+rlwxezhmxi 1 300 val
+rlxbqpoqob 1 300 train
+rlxenjzsdo 1 300 val
+rlxlgeaiqo 1 300 val
+rlxmmsmenp 1 300 val
+rlxvftboxj 1 300 val
+rlxyjxuxeq 1 300 train
+rlyegorhwk 1 301 val
+rlyghwdwar 1 300 train
+rlykpevqkl 1 300 val
+rlyuzkzxlv 1 300 train
+rlywckmghl 1 300 train
+rlzaurucfj 0 300 val
+rlzczhlode 1 301 val
+rlzxqplqpk 1 300 train
+rmadnocgpo 0 300 val
+rmahstfeke 0 300 train
+rmanmzhjkm 1 299 val
+rmantvehsv 1 300 val
+rmasyprhny 1 300 val
+rmaumsajjv 1 300 train
+rmayfmkrlr 1 300 train
+rmayjzerxw 1 300 train
+rmbfitfevx 1 300 val
+rmbgwgqdad 1 300 train
+rmbiuunnfm 1 300 train
+rmbjonxddg 0 298 train
+rmbmfjtqrs 1 300 train
+rmbqavymcd 1 300 train
+rmbqcgzcfl 1 300 val
+rmbrgigdxl 1 300 train
+rmbssoveuc 1 300 train
+rmbthnrnkn 1 300 train
+rmbvcmqray 1 300 train
+rmcfkmfzpi 1 297 train
+rmchuqjjwr 1 300 test
+rmckaifnnp 1 300 val
+rmcoritpow 0 300 train
+rmcplxaisa 1 300 train
+rmcumidsoz 1 136 train
+rmcuoghsmr 0 300 val
+rmcwnpvsdq 1 301 train
+rmdagcivrq 1 300 train
+rmddonjtxs 1 300 train
+rmdqtzxuky 1 300 train
+rmdrgepkdk 1 300 train
+rmduekewrs 1 300 val
+rmdyblxsch 0 301 train
+rmeazmvqhm 1 300 train
+rmebmfxdua 1 300 train
+rmeevdmpkq 1 300 val
+rmegtvvcys 1 300 train
+rmendzfbmz 1 300 train
+rmeoisgdld 1 300 train
+rmetbovdtp 1 300 train
+rmeutxmbad 1 300 train
+rmfehcyrwr 1 300 train
+rmfpdtabww 0 300 train
+rmfxmlfbik 0 300 val
+rmgbphzipt 1 300 train
+rmgfmdijjq 1 300 train
+rmgfraxziy 0 301 train
+rmgkwussuk 1 300 train
+rmgmravhdx 1 300 train
+rmgowfiaen 1 300 val
+rmguqcorxp 1 300 train
+rmgyrtrhso 0 300 train
+rmhcezasax 1 300 val
+rmhfzfoqrh 1 301 train
+rmhhjaowhs 1 300 train
+rmhikvcdcj 1 300 train
+rmhiviwbym 1 300 train
+rmhjfourvq 1 300 val
+rmhsahyvta 0 299 val
+rmhtwvkepi 1 300 train
+rmhyayslbg 1 300 train
+rmhzpunjad 1 300 train
+rmibmpregy 1 300 train
+rmidnpympq 1 300 train
+rmiffyggfw 1 301 val
+rmimrkkxzl 1 301 val
+rmiwrebpnt 0 300 train
+rmjdbbhhog 1 300 val
+rmjdiciglo 1 300 val
+rmjfkuehpt 0 300 train
+rmjfmgcqbb 1 300 train
+rmjjyjfedr 1 300 train
+rmjswqwgcw 1 300 train
+rmkdrzlgod 0 300 val
+rmkllkgxxd 0 300 train
+rmkncdvpdu 1 302 train
+rmkzkfzecv 1 300 train
+rmldoykgzt 0 300 train
+rmlfspnfcp 0 300 val
+rmlhoogvza 1 300 train
+rmllhhppjh 1 300 val
+rmlqyndocv 1 300 train
+rmlzgerevr 0 300 test
+rmmcypdfbr 1 300 test
+rmmdaqurmv 1 300 train
+rmmdfsqfjq 1 300 val
+rmmektgipe 1 300 train
+rmmnxxhcrk 1 300 train
+rmmyceqpgn 0 300 val
+rmmylvdurj 1 147 train
+rmmzjunzxa 1 300 train
+rmnaysdtaa 1 300 train
+rmndwrumtv 1 300 train
+rmnhmhmvbl 1 300 train
+rmnqmuawij 0 300 train
+rmnrvrqbky 1 300 train
+rmnvkdnruz 1 300 train
+rmnzimqvml 1 300 train
+rmnztsjarv 1 300 train
+rmoqjlqmzg 1 301 val
+rmotmvbkrq 0 300 train
+rmovankcux 1 300 train
+rmovgyikbd 1 300 train
+rmoyiobxti 1 298 train
+rmpbqeawlq 0 299 test
+rmpcfsmoie 1 300 train
+rmpcrrwhzv 0 300 train
+rmplscucbt 1 300 test
+rmpnhrymci 1 300 val
+rmpvriplny 0 300 train
+rmpwmbbzot 1 300 train
+rmpwnnxmye 0 301 train
+rmqadoreht 1 300 test
+rmqajbgjsy 1 300 train
+rmqaqhkpsd 1 300 train
+rmqccvmeak 1 300 train
+rmqfuhvhlx 1 300 train
+rmqgnqckbh 1 240 train
+rmqinzojuv 1 300 train
+rmqlfrfktn 1 300 train
+rmqngnuqau 1 300 train
+rmqubbrvhr 1 300 train
+rmrfekpclo 1 300 train
+rmriqlejuv 1 300 train
+rmrtsnompc 1 298 train
+rmscrwokhz 1 300 train
+rmsikbxhiy 1 300 train
+rmskuissxs 0 300 train
+rmspnlyqmw 1 300 train
+rmspokureu 1 300 train
+rmsuzlbffb 0 300 train
+rmtirproxe 1 300 train
+rmtjpqqhje 1 298 train
+rmtjqcucqb 1 300 train
+rmtminrkmz 1 300 val
+rmtrybjlpb 1 300 train
+rmtuocxuuf 1 301 train
+rmuaywqcbx 1 300 val
+rmufsuogzn 0 300 test
+rmuojgvjra 1 300 train
+rmurgpuxvz 1 300 train
+rmuthxsdjq 1 300 train
+rmuucuytfi 1 300 train
+rmuueenmha 1 300 train
+rmuuujodkx 0 300 train
+rmuxdcnpng 1 300 train
+rmuxlgsedw 0 300 val
+rmuyiybkxk 0 300 train
+rmuyjpczhp 1 300 train
+rmvbmhrmtg 1 300 val
+rmvbrxpjwn 1 300 train
+rmvbsmqpkw 1 300 val
+rmveagltcn 1 300 train
+rmvhavnlme 1 300 test
+rmvoyhhbiz 1 300 train
+rmvraortuw 1 300 train
+rmvuvfpkme 1 300 train
+rmvxwnuowq 0 300 val
+rmvypmuucs 1 300 train
+rmwbblteju 1 300 train
+rmwbrucyvz 1 300 train
+rmwjfrmqjh 1 301 train
+rmwmfkebjo 1 298 train
+rmwndimdia 1 301 train
+rmwpfsjktl 1 300 train
+rmwtewxaur 1 300 train
+rmwujindih 1 300 train
+rmwvicexuo 0 300 train
+rmxcfrflji 1 300 val
+rmxghjhbxw 1 300 train
+rmxvptssww 1 301 train
+rmyffihljt 1 299 val
+rmyfxxhhov 0 300 val
+rmygsfjyvt 0 300 train
+rmyhshwqui 1 300 train
+rmyijywipw 1 299 val
+rmyljulkgw 1 301 train
+rmypklpcjw 1 302 val
+rmywlcmgma 1 300 train
+rmzcimrbkt 1 301 train
+rmzcmqwaca 0 300 train
+rmzgepdjyc 1 300 train
+rmzsmkullq 1 301 train
+rmztfignml 1 300 train
+rnailbpdmr 1 299 val
+rnasgmbhys 1 300 train
+rnasqtqnne 1 300 train
+rnblmunwrt 1 300 val
+rnbufwpxda 1 300 train
+rnbvxxzjkz 1 300 train
+rncahwggfw 1 300 train
+rnccjcdgwh 1 300 train
+rncdxzxctx 1 300 val
+rncfusbenv 1 298 train
+rncgmmcdtd 1 300 train
+rnchxylyjc 1 300 train
+rnckeghtyz 0 301 val
+rncpzkrlsv 1 300 val
+rnctbtxurc 1 300 train
+rncwseonva 1 301 val
+rncxclfvuz 1 300 train
+rndbixxkcw 1 300 train
+rndcqgjrqk 1 300 test
+rndfvvcxik 1 300 train
+rndkddecxr 0 298 train
+rndlhczhdm 1 300 train
+rndrqkdndn 1 301 train
+rndrzdtvzx 1 300 train
+rndudduisb 1 300 val
+rndxhmcatw 1 300 val
+rndxiiyacu 1 299 train
+rndxzqfjfk 1 300 train
+rndzojptfn 1 300 val
+rneiarxkwt 1 298 train
+rnemedxvyr 1 300 val
+rnenyahilx 1 300 train
+rnerfcdmjg 1 300 train
+rnerozzwam 1 301 train
+rneucagbvg 1 300 train
+rnfbjblemd 1 300 val
+rnfchzufze 0 300 train
+rnfcjxynfa 1 300 test
+rnfdqvkgtx 1 300 train
+rnfiirxyve 1 300 train
+rnfixfugwa 1 300 train
+rnflbfowvb 1 300 train
+rnfvcslcmf 1 300 test
+rnfxwsbdrs 1 240 train
+rnghnfgpci 1 300 val
+rngrstsich 1 301 val
+rngtdqodpi 1 300 val
+rngupntsot 0 300 train
+rngzwsothz 1 300 val
+rnhaozvasw 0 300 train
+rnhfqrwwkx 1 300 train
+rnhmavtmgy 1 300 train
+rnhqcoqucw 1 300 train
+rnhscfffwm 1 299 train
+rnhsouhjxu 1 300 test
+rnhstrkmie 1 300 train
+rnhtvzkfqv 1 300 train
+rnhucleiuy 1 300 val
+rnhyfmjlfx 1 300 train
+rniegvduke 1 301 val
+rnijxqmmpb 1 300 train
+rniqxpdsoz 1 300 train
+rniuubmcle 1 300 train
+rnjbgbrnmv 1 300 train
+rnjcusueiu 1 300 train
+rnjerxavww 0 300 val
+rnjfkmerlz 1 300 train
+rnjhdunvmz 1 298 train
+rnjjnkzdjb 1 300 train
+rnjmfjzqwg 1 300 train
+rnjrqwrgbo 1 300 train
+rnjzzvuhwa 0 300 val
+rnkjnzwotn 1 300 val
+rnkkemwhfq 1 300 train
+rnkksjxasm 1 300 train
+rnkloibzse 1 300 train
+rnkluunfnu 1 301 train
+rnkpunqxas 1 300 train
+rnktshdsfa 1 300 train
+rnlcnbdcdf 1 300 train
+rnlocgpyqv 1 300 train
+rnmgxrxckb 1 300 train
+rnmhadeflp 1 300 train
+rnmilvkfmi 1 300 val
+rnmlezjkyt 1 300 train
+rnmsjlemec 1 300 train
+rnnjsqroat 1 300 train
+rnnkrkzpyt 1 298 train
+rnoaglzwbo 1 300 train
+rnokbekphp 1 300 train
+rnootesqel 1 300 train
+rnoyqvozej 1 300 train
+rnozzrfhkq 1 300 train
+rnpbbkzaux 1 300 train
+rnpefxwptv 0 300 test
+rnpihmgobb 1 300 train
+rnpjwabnht 1 300 train
+rnpldcfekw 1 299 val
+rnppmzthdu 1 300 train
+rnprjxheic 1 300 train
+rnpsnnbrwu 0 300 train
+rnpwccbhlr 1 300 train
+rnpwrkqgmz 0 300 train
+rnpzpgncvx 0 300 train
+rnpzvkrllm 1 300 train
+rnqtouthbt 1 301 train
+rnqtslhcka 1 300 train
+rnquyribbz 0 300 train
+rnqvcwkmwa 1 300 train
+rnqvjzhgol 1 300 train
+rnqxhxqfia 1 300 train
+rnqxzafqii 1 300 train
+rnqzrtahnd 0 300 train
+rnrbvxaoib 1 241 train
+rnrcrhiqqw 1 300 train
+rnreddssfe 1 300 train
+rnrlenfhdy 1 300 train
+rnrnnhcbpd 1 300 train
+rnrpkmfklx 1 300 train
+rnrqbpxnst 1 298 val
+rnrqgfqodh 0 300 train
+rnrqjbysxn 1 300 train
+rnrqoellvi 1 300 train
+rnshusewsv 1 298 train
+rnspxjflyf 1 300 val
+rnsqsqezle 1 294 train
+rnszwayqfk 1 300 train
+rntagozdll 1 300 train
+rntckkherf 1 300 train
+rntcritstr 1 300 train
+rntjtobier 1 300 train
+rntvjoprlf 1 240 val
+rnuaapicnv 1 300 train
+rnubcomdcn 1 300 train
+rnuisonnyh 0 300 val
+rnuvhhikbn 1 301 val
+rnvcglroyq 1 299 test
+rnvhaihlyn 1 301 train
+rnvhpzasky 1 300 train
+rnvmyjkezq 1 300 train
+rnvqaxewfi 1 299 train
+rnwidtkbxr 1 300 train
+rnwjcvaiko 1 300 train
+rnwkoljfnl 1 300 train
+rnwolhkews 1 300 train
+rnwrvccbns 0 300 val
+rnwvqzfzdq 1 300 train
+rnxbyscvww 0 300 val
+rnxhygnutt 1 298 train
+rnxkvljhtr 0 300 val
+rnxnytbudq 1 300 test
+rnxnzkttat 1 300 val
+rnxqalxtgi 1 300 train
+rnxtkpblcu 1 300 train
+rnxyofoodj 1 300 train
+rnxzqumvvl 0 300 test
+rnyaqgtqwq 1 300 train
+rnygrothcm 1 300 val
+rnyljaxyvd 1 300 train
+rnzdwpytce 1 300 train
+rnzkwxpeud 1 300 train
+rnzqjtpezq 1 300 train
+rnzvomaldt 0 300 train
+rnzynmbfed 1 300 train
+rnzyogpmnf 1 300 train
+rnzzerbosq 1 300 train
+rnzzuxmigr 0 301 train
+rnzzvvikom 1 300 train
+roabvhmgnb 1 300 train
+roaffigaqw 1 300 train
+roahztgdju 1 300 train
+roamyrmtzh 1 300 train
+roantcttsg 1 300 val
+roateysvls 1 300 train
+roaubbdctl 0 300 train
+robdthvplg 1 300 train
+robpzrdojw 1 300 train
+robvzsowex 1 300 val
+robzalqcge 1 300 train
+rocaqylpqv 1 300 train
+roccuyjydl 1 300 train
+rocgpftvws 1 300 train
+rocmxliauc 0 300 val
+rocqqpawck 1 300 train
+rocqtecrsj 1 295 train
+rocuzbwswd 1 300 train
+rocvkrgjjf 1 300 train
+rocwecmgxc 1 300 train
+rocxfnldie 1 300 train
+rodaoirzgq 1 300 train
+rodgsmgued 1 300 train
+rodgzjzxqp 1 296 val
+rodhkqwqpp 1 300 val
+rodiinftvq 1 300 train
+rodiliilkt 0 300 val
+rodjbbtzkn 1 300 train
+rodvkpkity 1 241 train
+rodywaihwm 1 298 train
+rodznzhbjz 1 301 val
+roebqjihwk 1 301 train
+roeecmiguh 0 300 train
+roegyvvbug 1 297 train
+roexgtxldr 1 301 val
+rofdkzkxuf 1 300 train
+rofgoeqfbf 1 300 train
+rofgychiss 1 300 train
+rofisthyxs 1 300 train
+rofjckejia 1 300 train
+rofluklzpv 1 300 val
+rofpobbanh 1 301 val
+rofpwxfcwy 1 300 train
+rogbffkenw 1 300 train
+rogclgcsqo 1 300 train
+rogcxjnekn 1 300 train
+roggcjwdjn 1 298 train
+rogggrregs 1 299 train
+rogktwskzt 1 300 train
+rogmgebtye 0 300 train
+rogmwncrkp 1 300 train
+rogojnrslr 1 300 val
+rogpmagxtp 1 300 train
+rogvasrxwz 1 300 train
+rogvhqquvo 1 298 train
+rohakxryar 1 299 train
+rohjntdukb 1 241 train
+rohmojwvif 1 298 val
+rohorrggyx 1 300 train
+rohtdnpfoa 1 300 train
+rohtmxfape 1 300 train
+rohuegtohf 0 300 train
+rohwvmkvjg 0 300 train
+rohysgbpoh 1 300 train
+roiathsrwq 1 300 train
+roiayixtdf 1 300 train
+roikafzzpf 1 300 train
+roikljqjxi 1 300 val
+roilwdmonz 1 300 train
+roinhuwikn 1 300 val
+roinluqcyy 1 300 train
+roiumkcfix 0 300 val
+roivdutkrz 1 300 train
+rojbyjytyl 1 300 val
+rojcacrxbm 1 300 train
+rojqhigadj 1 299 train
+rojsigziqf 1 300 train
+rojsxotnvo 1 300 train
+rojtpsivkw 1 301 train
+rojwdahjuh 1 301 train
+rokgoeaybe 1 300 test
+rokjasydjc 1 300 train
+rokkljsocg 1 300 train
+rolaqxritd 1 300 train
+rolaufvind 1 300 val
+rolcvttgte 1 300 train
+rollrgxutg 0 300 val
+rolmpzrhls 0 300 train
+rolrvkgvyt 0 300 val
+roltkgcnoc 1 300 train
+roltlfyzwg 1 301 train
+rolunqqjgw 0 300 val
+rolvjuaqht 1 300 train
+romchuiymq 1 300 train
+romnwzacmp 1 300 train
+romwprrrue 1 297 train
+romzicylpm 1 300 train
+romzqwhhlb 1 300 test
+roncswrecs 1 300 train
+ronuccpona 1 300 train
+ronwdhfyxm 0 300 train
+ronwmidhjm 1 301 train
+ronzyhssvp 1 301 val
+roomncorbj 1 300 val
+rooqurubia 1 300 train
+rooztlscpz 1 300 train
+ropifziheq 0 300 train
+ropllvinca 1 300 val
+ropsccjlgj 0 300 val
+ropuikmfgo 1 300 train
+ropvlealpl 1 300 train
+ropvntilku 1 300 train
+ropvpuwcsl 1 300 train
+ropvwnbrzn 1 300 train
+roqbnlondz 1 300 test
+roqcnydjbf 1 300 train
+roqgtismye 0 297 train
+roqgwhancp 1 300 train
+roqidxpxso 1 300 val
+roqkadbbap 0 193 train
+roqnflyoys 1 301 val
+roqucblbhe 1 300 train
+roqyiqgwzd 1 300 test
+rorgjkeqke 1 300 train
+roricbxvev 0 298 train
+rorjfhlakf 1 300 train
+roroqidyua 0 300 train
+rorqafpfjw 1 300 train
+rorsxmgusi 1 300 train
+rortwhsuas 1 299 val
+rorvdyyyef 1 298 train
+rorwltxcsl 0 300 train
+rorxilcmqb 1 300 train
+rosgqjjnnb 1 300 train
+rosiwluxev 1 300 train
+rosmfuynpn 1 300 val
+rosnfjctls 1 300 val
+rosrbrgyrc 1 300 train
+rosuouoepg 1 300 train
+roszmjbioz 1 300 train
+rotdtacrcn 1 301 train
+rotkssssyn 1 300 train
+rottyedvaw 1 300 train
+rotytwmzjc 1 300 train
+roufopvnnp 1 300 train
+roufpunqee 1 301 val
+rougiapsti 1 300 val
+rouhxkadcj 1 300 test
+rouleciwdb 1 300 train
+roulqishnt 1 300 train
+roupasnenj 1 300 train
+rourvegbvr 0 300 train
+rovapsdkjr 1 300 train
+rovikudkjj 1 300 train
+rovilxwhnt 1 300 val
+rovlmaszay 1 300 train
+rovrcxjbsx 1 300 train
+rovrreexlc 1 302 val
+rovrsntnru 1 300 val
+rovsffvpit 1 288 train
+rovzigqfbs 1 300 train
+roweahxvew 0 300 val
+rowhhbrpup 0 300 train
+roxcktcxmt 1 300 train
+roxevcougz 1 298 train
+roxiealfig 1 300 train
+roxjrgyxlf 1 300 train
+roxnlqvqbb 1 300 train
+roxnzrdawi 1 300 val
+roxuqecolx 1 300 train
+roxvxpdrff 1 300 train
+roxwqhzxrb 1 300 train
+roxxygzohw 1 300 train
+royhdljuso 1 300 train
+roykwzcnwf 0 300 train
+roylanbffi 1 240 val
+roymddgcom 1 298 val
+roymxblliy 1 300 train
+roypjyiitb 0 300 train
+roypoehzjg 0 300 train
+royqxauyfl 1 300 val
+royuzifhhm 1 300 val
+royxzkwnkc 1 297 train
+royyjnijng 1 300 train
+rozeukiens 1 300 train
+rozezjrbjt 1 301 train
+roznidpfxz 1 301 train
+rozowkykwk 1 300 train
+rozrjmrmeo 0 300 val
+roztwoltig 1 300 train
+rozyzvhddx 0 300 train
+rpamtneasj 1 300 train
+rpanzyxdwh 1 300 val
+rpaopzzxgh 1 300 val
+rparcvlpjn 1 300 train
+rpatqowutm 1 301 train
+rpawgezjby 0 300 train
+rpaxlrwkkc 1 300 train
+rpbbkbtcfq 1 300 train
+rpbeznpkke 0 300 val
+rpbnhhrcnb 1 300 train
+rpbobzieup 0 300 val
+rpboxnryjl 1 300 train
+rpbvjtzapd 1 300 train
+rpbzdciheg 1 300 val
+rpchgqmxbm 1 300 val
+rpcjluowkz 1 300 train
+rpclovgyab 1 302 train
+rpcmfephic 1 300 train
+rpcmpbxfja 1 300 train
+rpcprryjpo 1 300 train
+rpcueyycgm 0 296 val
+rpcvgsuozm 0 300 train
+rpczjptpat 1 300 train
+rpdidqtifj 1 300 train
+rpdknjdhxa 1 300 train
+rpdqtwfgeh 1 300 train
+rpdtsqbbun 1 300 val
+rpdvcfgzrw 1 298 train
+rpdvuoovqd 1 300 train
+rpdyezccyh 1 300 train
+rpdyxohbsd 1 300 val
+rpdzhweqtv 1 241 train
+rpechqrcug 1 300 val
+rpefafadut 1 300 val
+rpekauizcr 1 300 train
+rpekmbrfrc 1 300 train
+rpenbcgyxf 1 300 train
+rpexbvllae 1 241 train
+rpfcrletuq 1 300 train
+rpfculimra 1 167 train
+rpfeafvrea 1 300 val
+rpfiiclltl 0 300 train
+rpfjjlcswr 1 300 train
+rpfkoavwmf 1 300 val
+rpfpyxmlbb 0 300 train
+rpftppudxo 1 301 train
+rpfzebwhtb 1 300 train
+rpgjgpzzdm 1 300 train
+rpgqmniaco 1 300 train
+rpgqpzjuye 1 300 val
+rpgtygtudf 1 300 train
+rpgutupcvw 1 298 train
+rpgwsltfcj 1 300 train
+rpgzcrqmvl 1 300 train
+rphdtleagg 0 300 val
+rphfwyleld 0 300 train
+rphjvqgjys 1 300 train
+rphoqfukfh 0 300 train
+rphvdsnund 1 300 val
+rphzyqvfhr 1 300 train
+rpidhujqgu 1 300 train
+rpiecpkfas 1 300 train
+rpieqdamhl 1 299 val
+rpikgyvzcz 1 301 train
+rpikzxccwn 1 300 val
+rpjizcvdte 0 300 train
+rpjkhmpdfw 1 300 train
+rpjlunryri 1 300 val
+rpjnfmephe 1 301 train
+rpjngnpiwp 1 298 val
+rpjppjjzsm 1 300 train
+rpjwcsnnhl 1 300 train
+rpjyerifvt 1 300 train
+rpjyucgnhi 1 300 train
+rpkbktwnon 1 300 train
+rpkbocrpar 1 300 train
+rpkicouwvd 1 300 train
+rpkkormzdi 1 300 train
+rplfdwhyya 0 300 train
+rpljvwirib 1 300 train
+rplkffclru 1 301 train
+rplompjhkv 1 300 train
+rplruomhyd 1 300 val
+rpltcilwga 1 300 train
+rplxcgcmaq 0 300 val
+rplxdenqzv 1 300 train
+rpmbobzfic 1 300 val
+rpmffmwprz 1 300 train
+rpmmkydblh 1 300 val
+rpmqhlcbcu 1 300 train
+rpnauamgep 1 300 train
+rpnenirvva 1 300 train
+rpnetwqgqz 1 300 test
+rpoaigqgvo 1 301 train
+rpoarefkju 1 300 train
+rpoavokdsf 1 300 train
+rpoffvvbgp 1 300 train
+rpohehwnrk 1 300 train
+rpojlagpxg 1 300 train
+rpojqovyxd 1 302 train
+rpojyvvuid 1 301 val
+rpounthunx 1 300 train
+rpouwonovm 1 300 train
+rpovhltcyq 1 300 train
+rppioltzqd 1 300 train
+rpponnsvvr 1 300 train
+rppsdyelep 1 300 train
+rppsooovbw 1 300 train
+rppvnvhlwc 0 300 train
+rppydlkzmu 1 300 train
+rppzbeeypx 0 241 train
+rpqglkacpf 1 300 train
+rpqhsvysqa 1 300 train
+rpqigkabsd 1 300 train
+rpqiyfvbvp 1 300 train
+rpqjlvfjnj 1 301 train
+rpqmboxhri 0 300 train
+rpqpopztwh 1 300 train
+rpqqaoqndc 1 300 train
+rpqqboplgs 1 300 train
+rpqswaxbpk 1 300 train
+rpqtfjkyer 1 300 train
+rpqvjsbovg 1 300 train
+rprciljzjr 1 300 train
+rpreeqxlya 1 300 train
+rprgultaxw 1 301 train
+rpriyeauyn 0 300 train
+rprsfihiki 1 300 train
+rprwdjeeaz 1 298 train
+rprwibrydl 1 301 train
+rpscymwpin 1 299 val
+rpsfqcqcai 1 300 train
+rpsjeiqugg 1 300 train
+rpsncogkpm 1 300 val
+rpsnjtsgrz 1 300 train
+rpsoduzyjx 1 300 train
+rpsqgjyacu 1 300 train
+rpstspiseo 1 300 train
+rpsttrnmql 1 300 train
+rpsuycfyup 1 300 train
+rpsxwxyafn 1 300 train
+rpszieknsa 1 300 train
+rptdoymypo 1 300 train
+rptgltzwek 0 300 val
+rptgunzuyd 1 300 train
+rptnprdzxe 1 300 train
+rptpaznupo 1 301 train
+rptpdrmwkk 1 301 train
+rptqbxpesg 1 300 test
+rptqlfwtbp 1 241 train
+rpunznztmv 1 300 train
+rpurekrbxl 1 300 train
+rpuwfxgteu 1 300 train
+rpuxnnqmln 1 300 train
+rpuzuvxdpu 0 300 train
+rpvfnbwjct 1 300 train
+rpvgkxsdno 1 300 train
+rpvhsmtanu 1 300 train
+rpvmkddcmp 1 300 train
+rpvxbanjkb 1 296 train
+rpwfaxcuip 0 300 train
+rpwjfquqal 1 300 test
+rpwnjppqqh 1 300 val
+rpwpdnrxih 1 300 val
+rpwpmrqofq 1 300 train
+rpwqeunuvn 0 300 train
+rpwzenehik 1 300 train
+rpxdemxjku 1 300 train
+rpxilobmtf 1 300 train
+rpxlcfnyur 1 298 train
+rpxnyljmsf 1 300 test
+rpxxslpjuq 1 300 train
+rpyctfhoev 1 301 val
+rpyjpwnsgq 1 300 train
+rpynhhdirq 1 300 train
+rpyswwabyp 1 300 train
+rpywnvrxga 1 300 train
+rpzgbhzswt 1 300 train
+rpzhtgjvtk 1 300 train
+rpzlxpoubb 1 300 train
+rpzmrnykdv 1 300 train
+rpzqnylecq 1 300 train
+rpzsfgjnlf 1 301 train
+rpzxfxoljv 0 300 val
+rpzzllbtsd 1 298 train
+rqactdzemv 1 300 val
+rqahpvvgmz 0 300 train
+rqamawdvhn 1 300 train
+rqatmndpzs 1 300 train
+rqauhvfqxr 1 299 val
+rqbdayault 1 300 train
+rqbmwgisuw 1 300 val
+rqbqazrufc 1 241 train
+rqbqpdypac 1 300 val
+rqbupxjvvp 1 300 train
+rqbuugcjgn 1 300 train
+rqbuwycjyl 1 300 train
+rqbxvcctky 0 300 train
+rqcbsxymvu 1 301 train
+rqcgsldlxh 1 300 train
+rqchqlakmd 0 300 train
+rqcifcowbd 1 297 train
+rqckrhzqqc 1 300 train
+rqcsjlsmiz 1 300 train
+rqcspvxxrs 1 300 train
+rqctzwkgkw 1 300 val
+rqcwoozbvr 1 300 train
+rqczidbofz 1 300 val
+rqdapiyldx 1 297 val
+rqdcnbyqeo 0 300 train
+rqddkpdidv 1 300 train
+rqdmrkeght 1 241 train
+rqdqfwwgis 0 300 train
+rqdvizclus 1 300 train
+rqdvuqnlnc 1 301 train
+rqdxztvzlh 1 300 val
+rqeecjldfq 1 298 train
+rqemqgnuan 1 300 train
+rqeurrbijk 1 300 train
+rqezbiotrw 1 300 train
+rqfbuwfiqx 1 300 train
+rqfewuvpqu 1 300 train
+rqfexaedot 1 300 train
+rqfxnalntb 1 300 train
+rqgahajzgc 1 300 val
+rqgdchivrl 1 300 train
+rqgdnzrjbh 1 299 val
+rqgprxvris 1 300 train
+rqgrrifxnn 1 300 train
+rqgtxhzimu 1 300 val
+rqgvpvogqv 1 300 train
+rqgzqwujgo 0 300 train
+rqhcrydatm 1 300 val
+rqhcvlwdal 1 300 train
+rqhdgbctmr 0 300 train
+rqhdmutocs 1 300 train
+rqheiaivlc 0 300 train
+rqhkeugxad 1 300 train
+rqhmtjhudb 1 300 train
+rqhnjzpixl 0 300 train
+rqhqxjvnib 1 301 train
+rqhtqlzrea 1 300 val
+rqhvqjsvsb 1 300 train
+rqhwomvkrx 1 300 train
+rqhydsgrdq 1 300 val
+rqiawtigky 1 300 val
+rqigtggvee 1 300 train
+rqiusjgyuw 1 298 train
+rqixtupxso 0 300 train
+rqjcaliuea 1 300 train
+rqjgnhozqa 0 300 train
+rqjhvdvoiw 1 301 train
+rqjiogtjoo 1 300 train
+rqjkmkaasg 1 300 train
+rqjnyealsn 1 300 train
+rqjwpflium 1 300 train
+rqjytvbrjg 1 300 train
+rqjyzixjre 1 300 val
+rqjzgviqwd 0 300 train
+rqkfesufqh 1 300 train
+rqkmvkyjzr 1 300 train
+rqknnwbdei 0 300 train
+rqknwcdnsh 1 300 train
+rqkorynhco 1 300 val
+rqkqeeninx 0 301 train
+rqkqxkwecu 1 300 train
+rqksyxaqtt 1 300 val
+rqkxhfoyku 1 298 train
+rqkybbbijt 1 300 train
+rqkyzqciud 1 300 val
+rqllfvkred 1 300 train
+rqlpmeyhqh 1 300 test
+rqlsllnzjx 1 300 train
+rqluxomzag 1 300 train
+rqmdhgkyjc 1 300 val
+rqmectcojk 1 301 val
+rqmfaplitz 1 300 train
+rqmglaheji 1 300 train
+rqmhdpwpxp 1 300 test
+rqmwermthr 1 300 val
+rqmwrqpcnk 1 300 train
+rqmxxaboet 1 300 val
+rqmyzuctsw 0 300 train
+rqnczeidfc 1 300 val
+rqnddnjgec 1 300 train
+rqndfubbro 1 300 test
+rqneiusdzg 0 300 train
+rqnfspmeam 1 300 train
+rqngjywnpv 1 147 train
+rqnoirnlnd 1 300 train
+rqnslrafri 1 300 train
+rqnwjwgtkk 1 300 train
+rqnyhvrich 1 300 val
+rqoiikyyon 1 300 train
+rqokigauwl 1 300 train
+rqomealtxk 1 300 train
+rqovrunqqn 1 300 train
+rqpdpfewfi 0 300 train
+rqpisaghxp 1 300 train
+rqpkgnnxcv 0 300 val
+rqpqlyrren 1 300 val
+rqpsuqvytc 1 300 val
+rqpynscbkb 1 300 train
+rqqaexurdl 1 300 train
+rqqcimatkj 1 300 train
+rqqddqqfpi 0 300 train
+rqqhrlfmgy 1 300 train
+rqqhwoptep 1 300 train
+rqqlsbniwi 1 300 train
+rqqqbxanqg 1 300 train
+rqqrsbjhyl 0 300 val
+rqraatghrg 1 300 train
+rqrdrehgju 1 300 train
+rqrggjlktn 1 300 train
+rqrgzthsdh 1 301 val
+rqrhixmkhz 1 301 train
+rqrikkiurs 1 300 train
+rqriuezjkz 0 300 val
+rqrkbgtfot 1 300 val
+rqrnngwqyu 1 300 train
+rqrqfuxyvr 1 300 train
+rqrqrciudj 1 300 train
+rqrtqjbwmu 1 300 train
+rqrxgseigp 1 300 train
+rqrxpvmjyj 1 300 train
+rqsfmrqnbx 0 300 train
+rqsjhrzhto 1 300 train
+rqsjnyjukt 1 300 test
+rqsnqniwvr 1 300 train
+rqsoelyedy 1 300 train
+rqsotnryhj 0 301 val
+rqstvaluvg 1 300 train
+rqtbpcobca 1 300 train
+rqtvhuspsd 1 300 train
+rqtxvhlizt 1 300 train
+rquahefvoa 1 300 val
+rqudjztmgx 1 300 train
+rqudvlgfhk 1 300 val
+rquezcbiey 1 300 train
+rqufsxbocb 0 301 train
+rquraijvma 0 300 train
+rquxcwczac 1 300 train
+rqviqcsbzw 1 300 train
+rqvlandrvd 0 300 train
+rqvthsszcw 0 300 train
+rqwfblxyrg 1 288 train
+rqwilveqiv 1 300 train
+rqwjfdvndt 0 300 train
+rqwsbjnlms 1 300 train
+rqwviepils 1 300 train
+rqwvmwkwtt 1 300 val
+rqxbxfssrz 0 300 train
+rqxbyycjxo 0 301 train
+rqxfewkmvw 0 300 train
+rqxiddngke 1 300 train
+rqxtwlfhey 0 300 train
+rqxvqkmoaw 1 300 train
+rqxwaxbwny 1 300 val
+rqxzciscnu 0 300 train
+rqydoskdqm 1 300 val
+rqyfsnxdla 1 300 train
+rqyiyuufkd 1 300 train
+rqyjkpzelf 1 300 train
+rqypikztox 1 300 train
+rqzecufyma 1 300 train
+rqzemnvqxx 1 301 train
+rqzhbznhrx 1 300 train
+rqzqdbxzbt 1 300 train
+rqztarwnat 1 300 val
+rqzuikccfv 1 300 train
+rqzxntfdfi 1 300 val
+rracbzrsmc 1 300 train
+rrachjhlzw 1 300 train
+rraibzkuuw 1 300 train
+rrajoyjklj 1 299 val
+rraluxdmqu 0 301 val
+rraqykaepv 1 300 train
+rrarnepsqt 1 300 train
+rrasaheeex 1 300 train
+rrashpauln 1 298 val
+rrasxcwooh 1 300 train
+rraumpegdq 0 300 train
+rraxfwnmzs 0 300 train
+rrayueedqw 1 288 train
+rrazknhgwr 1 297 train
+rrbcauyypg 1 300 train
+rrbjckixkk 1 297 train
+rrbnvosigo 1 300 train
+rrboxwdfzo 1 300 train
+rrbpoptnfc 1 300 train
+rrbsfwljsq 1 299 test
+rrbteabbya 1 240 train
+rrcctjjirw 1 300 train
+rrcmzjlrux 1 300 train
+rrcoqadebn 1 300 train
+rrcovrpngt 1 300 train
+rrcsuwgpnd 0 300 train
+rrcwfszzgy 1 300 train
+rrdamrrple 1 300 test
+rrdbitxtja 1 300 train
+rrdgikkpci 1 300 train
+rrdiwonvyq 0 300 train
+rrdldjamrn 0 300 train
+rrdqahbwvb 0 300 val
+rrdumvjejz 1 300 val
+rrduwkwpsi 1 300 train
+rrdvubejml 1 300 train
+rrebyhcccs 1 300 train
+rrecmejams 1 301 train
+rreddmxybn 1 301 train
+rredgmmygy 1 300 val
+rrerpidzkz 1 300 train
+rreuwvbone 1 300 train
+rreuzqlync 1 299 test
+rrewnecshj 1 300 train
+rrewuwzrtl 1 300 train
+rrfgwswboq 1 300 train
+rrfkxcvqvn 1 300 train
+rrfmtkaegx 1 300 train
+rrfowaueut 1 300 train
+rrfrmzwiao 1 300 test
+rrfxmoxtqn 1 300 train
+rrfyrpbttx 0 300 train
+rrgdtjjsfx 1 300 val
+rrgflltirj 0 300 train
+rrggroennz 1 300 train
+rrghzrxntt 1 298 train
+rrgmkciwnk 0 300 train
+rrgpzfynme 1 299 test
+rrgqserhsi 1 299 train
+rrguwkqxho 1 301 val
+rrgxikqqvq 1 300 test
+rrhhjyvayb 0 300 train
+rrhlyezlne 1 300 train
+rrhqfbkwtx 0 300 train
+rrhrtgvvbd 1 297 train
+rrhxnmzmoh 1 300 val
+rrhyhkqgzq 1 300 train
+rrhzvjovtq 1 300 train
+rriczyaaut 1 300 val
+rriiadtddt 1 300 val
+rriljgbojh 1 300 train
+rrinmjocdp 1 300 train
+rrjdtfbygt 1 300 test
+rrjgzpugww 1 300 train
+rrjknxseqv 1 301 val
+rrjtryvfwx 1 300 train
+rrkchlwksg 1 300 train
+rrkeuqmfsm 1 300 train
+rrkfektvfg 1 298 train
+rrkkhkeddu 1 300 train
+rrkklrkwil 1 300 train
+rrkokchngl 0 300 train
+rrkqgbcwyw 1 300 train
+rrkuwrrpia 1 300 val
+rrkwxaghun 1 300 train
+rrlcbhagil 0 300 train
+rrldnflyrx 0 300 val
+rrlfoseecl 1 297 train
+rrlgynofwd 1 300 test
+rrllurfvig 1 298 train
+rrlrdzwgio 1 241 train
+rrluavsnpt 1 300 train
+rrlxcxpxsa 1 300 train
+rrmbizcdwv 1 300 val
+rrmcolhbnc 1 300 train
+rrmefdtebj 1 300 train
+rrmhobgxhe 0 300 train
+rrmlgzdyyu 1 300 train
+rrmprmgsha 1 300 train
+rrmrjwosxc 1 300 train
+rrmynqblsf 1 241 train
+rrmzfhmlcj 1 300 train
+rrmzywvigx 1 300 train
+rrnkukxlax 1 300 train
+rrnmhbkcvz 1 300 train
+rrnqlzzqft 1 300 train
+rrntjexhcs 1 300 train
+rrnxoizohf 1 298 train
+rroasyblee 1 299 test
+rroehmezeq 1 299 train
+rrofistwhq 1 301 train
+rrogokaxoz 1 300 train
+rrogrqmlwn 1 300 train
+rroibmqhwx 0 300 val
+rroiccbavr 1 299 train
+rronivvmsf 1 300 val
+rrpetufqsc 1 300 train
+rrpingynbu 0 300 train
+rrplieqrbo 1 300 train
+rrppihtdgq 1 298 train
+rrpstiorkb 0 300 train
+rrqfujkhhj 1 300 train
+rrqhbijzoe 1 299 val
+rrqlhknsmh 1 300 train
+rrqmvluzdu 0 300 train
+rrqqbljbdk 1 300 train
+rrqvcvpbhy 1 300 val
+rrqyfcacqu 1 300 train
+rrrcszdiqw 1 300 val
+rrrfjhugvb 1 300 test
+rrrhbbucxk 1 300 val
+rrrhlnrqhc 1 100 train
+rrrndlfftv 0 300 train
+rrrnzvksri 1 300 val
+rrrsgfwuvr 1 300 val
+rrsahjrozs 1 300 train
+rrsczkvqso 0 300 train
+rrsiukmrdd 1 300 train
+rrsnoipdrp 1 299 test
+rrssrmsimg 1 297 train
+rrswbwmkma 1 300 train
+rrsybdbper 1 300 train
+rrsynqjeoj 0 300 train
+rrtbdobekw 1 300 train
+rrtdgbxwul 1 300 val
+rrtjtpiakl 1 300 train
+rrtoiewooo 1 300 train
+rrtsqgulba 1 300 train
+rrtwgqrvhp 1 300 val
+rrublvorxr 0 301 val
+rrucigosoz 1 301 train
+rruelkdxez 1 302 train
+rrufovofvy 1 302 train
+rruvnirdoo 1 301 train
+rrvadrfacv 1 298 train
+rrvbcljjhe 1 300 train
+rrveldowlr 1 300 train
+rrvinqaydx 1 300 train
+rrwajtxojs 1 301 train
+rrwcwerktl 1 300 train
+rrwdacnzcd 0 300 train
+rrwedqzejr 0 300 train
+rrwekozdlb 1 300 train
+rrwerrmyna 1 301 train
+rrwfznycmz 1 300 train
+rrwgkfbahc 1 300 train
+rrwgtachie 0 300 train
+rrwkockips 1 300 train
+rrwmqtpbdr 1 300 train
+rrwtiskubb 1 300 train
+rrwwaccajb 1 300 train
+rrxlxmamzz 1 300 train
+rrxulbsppi 1 300 train
+rrxvooolxi 0 300 train
+rrybwattkq 1 300 train
+rryfgngtkm 1 300 val
+rrygkjskib 1 300 train
+rryjfrillp 1 300 train
+rryjtivktt 1 300 train
+rrythizzsk 1 298 train
+rrytrtjloc 0 300 train
+rryueaqkgh 1 300 train
+rryzxfxcoh 1 301 train
+rrzabwture 1 300 train
+rrzfnqcakl 1 300 train
+rrzgbpmwsb 1 292 val
+rrzmmaqshj 1 300 train
+rrznorzbjs 1 300 train
+rrzpvemkgk 1 300 val
+rrzszbdffd 1 300 train
+rrzwzowcgm 0 300 train
+rsalptpmrc 0 300 val
+rsampqohud 1 300 train
+rsapxoqybk 1 300 train
+rsbblpurhw 0 300 train
+rsbhiwnkpl 1 300 train
+rsbipeqima 1 300 train
+rsbjuzcaem 1 301 train
+rsbmnoxgqs 1 300 train
+rsbmryngci 1 299 val
+rsbovwekev 1 300 train
+rsbpniwokj 1 300 val
+rsbypiulwo 1 300 train
+rscbjabwer 1 298 val
+rscdiyuevh 1 301 val
+rscgeebwnq 1 298 train
+rscmyngnqt 1 300 val
+rscreuunhv 1 301 train
+rscwiihmmr 1 300 train
+rscwogqlai 1 300 train
+rsdgwfbwvr 1 300 train
+rsdkithrxw 0 300 train
+rsdlmvrhoe 0 300 train
+rsdmlndoqm 1 300 train
+rsdrjnkqkj 1 300 train
+rseaglgdbn 1 300 train
+rsebexwysm 1 298 train
+rsecahjwsk 1 300 train
+rsedztueyj 1 300 train
+rseeidxoll 1 300 train
+rsegdldhtt 1 300 train
+rseqypfqsc 1 300 train
+rsezdyovap 1 300 train
+rsezpbulme 1 300 train
+rsfbgrqpmm 1 300 train
+rsfbypelwz 1 300 train
+rsfdnmxerg 1 300 train
+rsfgqnmwyg 1 249 train
+rsfnhzomsp 1 298 train
+rsfpbsjvcy 1 300 train
+rsfvdbuqpq 1 300 val
+rsfysacneu 1 301 val
+rsghvfqkhz 1 300 val
+rsgikiocix 1 300 train
+rsgioikgcv 1 300 train
+rsgknvsisd 1 300 val
+rsgkuvzjvt 1 300 val
+rsgpovfvjp 0 300 train
+rsgskodsnk 1 300 train
+rshgtcsqze 1 300 train
+rshhxfrjwh 1 300 train
+rshncuwqhx 1 300 train
+rshrdzinvu 1 300 val
+rshyczrcil 1 300 train
+rshypywiyo 1 300 train
+rsiitbxvtk 1 300 train
+rsiivaccnc 1 300 train
+rsimwwqaul 1 300 train
+rsioozqbxu 1 300 train
+rsipcvyltc 0 301 train
+rsircfewji 1 300 train
+rsirnemcmq 1 296 val
+rsjexexuzw 1 300 train
+rsjhmrvdwg 1 300 train
+rsjnzpgrfb 1 300 train
+rsjosqxzoq 1 300 train
+rsjqvihqtz 1 300 train
+rsjtztwzbc 0 300 train
+rsjurplcqa 1 301 train
+rsjvfwvfem 1 300 train
+rskepponez 1 300 train
+rskmlwpvfh 0 300 train
+rskrntaywd 0 301 train
+rskxkbaaac 1 301 train
+rskxtzudpj 1 136 train
+rskzlfutiv 1 300 train
+rslxpafeir 0 300 val
+rslyfjpqup 1 300 val
+rslzpcoiro 0 300 train
+rsmaqnmbxx 0 300 train
+rsmfvnwjyp 1 300 train
+rsmguaehdu 1 288 train
+rsmkhsryhb 1 300 train
+rsmpadmomf 1 300 train
+rsmshlzwbo 1 300 train
+rsmskjyekb 0 301 train
+rsncdopwrt 1 300 val
+rsncpveuuz 1 301 train
+rsndozdbcw 1 300 val
+rsnisxlujf 1 300 train
+rsnkepuopz 1 300 train
+rsnnvworkx 1 300 train
+rsnrcisldc 1 136 train
+rsnuiqbadv 1 300 train
+rsnwepfims 1 301 val
+rsnwvtvozn 1 301 train
+rsnzkkrodr 1 300 train
+rsokobrkrz 1 300 train
+rsorxxuztg 1 298 train
+rsotwmjkck 1 300 train
+rsozrpetpt 1 300 train
+rspjsmarjt 1 297 train
+rspnpxqnpn 1 300 train
+rspsjttbpq 1 301 train
+rspunhlisj 1 300 train
+rspxylznwq 0 298 train
+rspzzovuct 1 300 train
+rsqblsfgli 1 300 train
+rsqmifhunk 1 300 train
+rsqtyghjbe 1 300 train
+rsqxvdohdq 1 300 train
+rsrdyvnyre 1 300 train
+rsrkgoxrzz 1 300 train
+rsrmxelvep 1 300 train
+rsrqkwakkv 1 300 train
+rsrwqknhlq 1 300 val
+rsrytryznr 1 300 train
+rsschcqzqi 1 300 train
+rssftyijge 1 298 train
+rssipjnzzw 1 301 train
+rssofmcpuf 1 300 val
+rssqooscwn 1 300 train
+rsssrzjlfl 1 300 train
+rstlwzctdt 0 300 train
+rstqwuedxo 1 299 test
+rstsuhmzqz 1 300 train
+rstxllpnab 1 301 train
+rstxrkejyv 1 300 val
+rsuddxiapl 0 300 train
+rsughpanho 1 300 train
+rsumvjrbor 1 300 train
+rsunjufbsb 1 300 train
+rsunoyzyfy 1 301 train
+rsuoaccoph 1 296 val
+rsuwbozmxt 1 300 train
+rsuzqyjrhm 1 300 test
+rsvehqvkjo 1 299 train
+rsvqeunwup 1 300 test
+rsvrohepud 0 109 train
+rsvtkzxufe 1 300 train
+rsvvmphfrr 0 300 train
+rsvynirmnp 1 297 train
+rswcxnstdm 1 300 val
+rswdnreqsp 1 300 train
+rswefytioa 1 300 val
+rswgvhldux 0 300 train
+rswhrqslti 1 300 train
+rswmrfllpo 0 300 train
+rswongbvxz 1 300 train
+rswpcbcleb 1 300 train
+rswrkccemc 0 300 train
+rswrlshpev 1 300 train
+rswyrgdlaq 1 300 train
+rsxaorhtkn 1 300 train
+rsxfiggvrf 1 300 train
+rsxhaufcfc 1 241 train
+rsxhgpqbdj 0 241 train
+rsxihsmkrq 1 300 train
+rsxipcdpge 1 300 val
+rsxkjvkvrv 1 300 train
+rsxmopdryo 1 302 train
+rsxpgvqbud 1 241 train
+rsxrtmxvds 1 300 train
+rsxsfpqpde 1 301 val
+rsxtvgbukd 1 300 train
+rsxvcbgzba 1 300 train
+rsxwhvlkvs 1 300 train
+rsyhrnrrsk 0 300 train
+rsyqijqrtz 1 300 train
+rsyukoalsi 1 300 train
+rsyumziooy 1 300 train
+rsyzbadofz 1 300 train
+rszcuxvjtl 1 300 train
+rszdvsayiv 0 300 train
+rszfilfvcx 1 300 train
+rszixgvkce 1 296 train
+rszlyynddw 1 300 train
+rszmrlpfdo 1 300 train
+rsznrudrjz 0 300 train
+rszpazyccf 1 299 val
+rszphkzzjs 1 300 train
+rszqqwhnkj 0 300 train
+rtaajqrbds 1 299 val
+rtadrcsexg 1 300 train
+rtaejfywvc 1 300 train
+rtaggvdxbh 1 300 train
+rtahwegkfs 1 300 train
+rtalzuxuwf 1 300 train
+rtaosfaufb 0 300 val
+rtapzlzvqs 0 300 val
+rtauthkfzj 1 300 train
+rtawydpugq 1 300 train
+rtayspnmef 1 300 val
+rtbbiyjxkl 1 300 val
+rtbchvojlv 1 300 train
+rtbkkeebvf 1 300 train
+rtblddedtx 1 300 val
+rtcdspyolj 0 300 train
+rtcgmlzdkz 1 300 train
+rtciqqcarr 1 300 train
+rtcjifrjaw 1 300 train
+rtcnwhskkw 0 300 train
+rtcvqhoypr 1 299 val
+rtdalobuhl 1 300 train
+rtdkgaxmyy 1 300 val
+rtdkyhvmsm 1 300 train
+rtdogbpems 0 300 train
+rtduxfitee 1 300 train
+rtdxmcyzkn 1 300 train
+rtdyobmgnv 1 300 train
+rteaqrkhur 1 300 train
+rtebudrlmj 1 300 val
+rtejmqlqrs 1 300 train
+rteyekiwdy 0 300 train
+rtfbcclxju 1 300 val
+rtffucmikh 1 300 val
+rtfgdlcjjw 1 300 train
+rtftoejbxj 1 300 train
+rtfvorctqn 1 300 train
+rtfxirhldr 1 300 train
+rtfyxzmueo 1 300 train
+rtgbzhsgug 0 300 train
+rtghwkccsq 1 300 train
+rtgqsdljos 1 300 val
+rtgvlbzyvc 1 300 train
+rthgbuzbds 1 300 train
+rthgrenscs 1 300 train
+rthnegierz 1 300 train
+rthsqmszkc 1 298 train
+rthtceougm 1 300 val
+rthtvpztdu 1 300 test
+rthutnlyqd 1 300 train
+rthzbngjxc 1 300 train
+rtiebmpcty 0 300 train
+rtiiagfdvy 1 300 train
+rtixqjdqhb 0 300 train
+rtiyduycrn 0 136 train
+rtjcbaqrks 1 299 test
+rtjfyrrmzc 1 300 val
+rtjmoslsii 0 300 train
+rtjmzqmhqa 1 300 train
+rtjtgxdrcn 1 300 train
+rtjvpbtcjp 1 301 train
+rtkaaezjha 0 300 train
+rtkdgvnhdz 1 300 val
+rtkdqnqzhc 1 300 train
+rtkdznjuzy 0 301 train
+rtkhyvbcjg 1 300 test
+rtkthsvqve 1 300 train
+rtkuqukvhj 1 300 train
+rtliozyjjy 1 300 train
+rtlluhezha 1 300 val
+rtlnmevktw 1 300 train
+rtlouoyept 1 300 train
+rtlqnbtrek 1 300 train
+rtlrmdoijk 1 300 train
+rtlrttqfoz 1 300 train
+rtlsvykino 1 300 train
+rtmbucxfef 1 300 test
+rtmhmeagmu 1 300 train
+rtmmxowsfc 1 299 train
+rtmuogtafs 1 300 train
+rtmuttxbsy 1 300 val
+rtmxgvqwho 1 300 train
+rtmxixqcpv 1 300 train
+rtneymsway 1 297 val
+rtnhsalwwa 1 300 train
+rtnhyhrxny 1 300 val
+rtnmhthdmx 1 300 train
+rtnultsauv 1 300 train
+rtojdasnsq 1 300 train
+rtopzfsanh 1 300 train
+rtotcpzdcl 1 300 val
+rtotvxeisg 1 300 train
+rtozywbglx 1 300 train
+rtpbawlmxr 1 300 test
+rtpblvywlq 1 299 test
+rtpdrmcguf 1 300 train
+rtphoescwz 0 300 train
+rtpuwtrxsr 0 301 train
+rtpzfzwnko 1 300 val
+rtqfogdstt 1 300 val
+rtqjbgslxg 1 300 train
+rtqovkvmfo 1 300 train
+rtqpqqrknh 1 298 train
+rtqzweqnuj 1 300 train
+rtrbgbesqf 1 300 train
+rtrgtcillv 1 300 train
+rtrhzpryus 1 300 train
+rtrjpoepxi 0 300 train
+rtrlqaicxk 1 300 val
+rtrnpctaug 0 300 val
+rtrrlwhlfu 1 300 val
+rtrtqgxlio 1 297 train
+rtsatcelin 1 300 train
+rtsdmcdkls 1 300 train
+rtsfzxslej 1 300 train
+rtsomqepxw 1 300 train
+rtsqmvquvs 1 300 train
+rtsqoqgctf 1 300 val
+rtsrogfuta 0 300 val
+rtsuwgyvbo 0 300 train
+rtsxrpmbpz 1 300 train
+rttdpnnvpm 1 300 val
+rttedpxiuk 1 300 train
+rtteygvedk 1 300 train
+rttkickivq 1 300 train
+rttqevnyox 1 301 val
+rttusodfgg 1 300 train
+rttutfqyiq 1 300 train
+rttwudubuc 1 300 train
+rttxrofrbj 0 300 val
+rtuaxyuvqs 1 300 val
+rtudujbwbn 1 300 train
+rtujpfxswi 1 300 val
+rtuoohyikq 1 300 train
+rtuothmxko 1 300 train
+rtuphrnptm 1 300 val
+rtuthjqxrg 1 299 val
+rtuttkvivd 0 300 val
+rtvfioxmfg 1 300 val
+rtvjzetgmu 1 241 train
+rtwalcvkbe 1 300 train
+rtwdhvxrgw 1 300 train
+rtwipuesde 1 301 train
+rtwjaonbin 1 300 train
+rtwlskwxqy 1 300 train
+rtxenusqra 1 300 train
+rtxpczzzej 0 300 val
+rtxrjresox 1 300 train
+rtxwwphaak 1 300 train
+rtygyaqpjb 1 300 train
+rtyygfxbga 1 300 train
+rtyzzuuvvi 1 299 train
+rtzcwnflig 1 300 train
+rtzjkmwksm 1 241 train
+rtznseikyj 1 300 train
+rtzpmdzawl 1 300 train
+rtzqeldqsc 1 300 val
+rtzqxwcoke 1 300 train
+rtzxnlqhqt 1 299 test
+rtzyrfajgf 1 298 train
+ruafobsido 1 300 train
+ruakghtual 1 300 val
+ruamngqldz 0 301 train
+ruaqtjrcic 1 300 train
+ruasonvcvd 1 300 train
+ruawzgnvxr 0 300 train
+ruayjprjbx 1 300 train
+rubaqwhhzw 1 300 train
+rubdszhjtj 1 300 train
+rubhzlddup 1 300 train
+rublfgiqcc 1 236 train
+rubmvqodty 1 300 train
+rubodktfzu 1 300 train
+ruboidsfqk 1 300 train
+rubozrgvgg 1 300 train
+rubptnpcdr 0 300 train
+rubqttwchw 1 299 train
+rubsrklwhx 1 299 test
+rubvfzixsr 1 300 train
+rubxkyqksa 1 300 train
+rubykuiild 0 300 train
+rucctscaqp 1 300 test
+rucezoldds 1 300 train
+rucfeubuev 0 300 train
+rucnlxjnyl 1 300 train
+rucpnkznux 1 300 train
+rudaltlcni 0 300 train
+ruddhfbpdj 1 300 train
+rudiflkxas 1 300 train
+rudtljomnj 0 300 train
+rueblwbjpg 1 300 train
+rueeidfwvg 1 301 train
+ruefwrrhgm 1 300 train
+ruenzqaiww 0 298 train
+ruevtebxlf 1 300 train
+ruewieftom 1 299 train
+rueyylafpn 1 300 test
+rufilscqdq 1 300 train
+ruflbpqcjl 1 300 train
+ruflllykcg 1 300 train
+rufpevnfjo 1 300 val
+rufqxmaljx 1 300 train
+rufvneuvau 1 300 val
+rugedgyywy 1 301 val
+rugmzrtgha 1 301 train
+rugokyvope 1 300 val
+rugvatcrhf 1 300 train
+rugxydqfdj 0 300 train
+rugyotxxkn 1 300 train
+ruhdqdevfr 1 298 train
+ruhjnjwokl 0 300 train
+ruhmtpruim 1 300 train
+ruhmwfqklg 1 300 val
+ruhnciwkqb 1 300 train
+ruhojbsehl 1 298 train
+ruhrdhrxud 0 241 train
+ruhtnngrqv 0 300 test
+ruifjqbxxk 1 300 train
+ruiifngphz 0 301 val
+ruinmlnbze 1 300 train
+ruiufeetsd 1 300 train
+ruivmuqhho 1 300 train
+ruivuupija 1 236 train
+ruiwkrckex 0 300 val
+rujaqmzmyd 1 300 train
+rujcsopbhx 1 300 val
+rujcwrjwhf 1 300 test
+rujkgfpjye 1 300 train
+rujqmfghnd 1 300 train
+rujsevinxy 1 300 train
+rujvrtqddt 1 600 train
+rujvxjnuya 0 300 val
+rujwyrhdka 1 300 train
+rujxqforxj 1 300 train
+rukamuynfx 1 300 train
+rukbpgtsfm 1 300 train
+rukbrzqftr 1 300 train
+rukkrrrlfo 1 300 val
+ruklnzpgly 1 301 val
+rukyxomwcx 0 300 test
+ruldbjlfmg 1 300 val
+rulefrhiug 1 300 train
+rullulnzec 1 301 train
+rulsynmkii 1 300 train
+rulvnayuug 1 299 test
+rulwfmdhtz 1 300 val
+rumgqoxqdd 1 301 train
+rumjubqsdq 0 300 train
+rumsbihkul 1 298 train
+rumvnjlmiy 1 300 train
+rumvwwwvam 1 300 train
+rumxbqgmld 0 300 val
+rumxuyrjjt 0 302 val
+rumyjhyayo 1 300 train
+runchrnhwl 1 300 train
+rundvhxkgi 1 300 train
+rundxkqvtz 1 300 train
+runeqcjqmw 1 300 val
+runjevrpbq 1 298 train
+runmncglnj 1 300 test
+runqlregsp 1 300 val
+runqzmfxhs 1 300 test
+ruoaaiwtki 0 300 train
+ruojxqsrzk 1 300 train
+ruommqpish 1 300 train
+ruonzmdflz 0 300 val
+ruoqxpevvf 1 300 train
+rupmycdwnn 1 300 val
+rupnmwgvua 1 300 train
+ruprvdicng 1 300 train
+ruprylzwbw 1 301 val
+rupudccrgd 0 301 train
+rupudiqost 1 300 train
+rupvxhbbhk 0 300 train
+rupxkhjmhe 1 299 test
+rupywiactt 1 83 train
+ruqcqjpssw 1 300 val
+ruqcuxistz 1 300 train
+ruqdhyekiv 1 300 train
+ruqedmfwoh 1 300 val
+ruqhnpqsyc 1 301 train
+ruqxarjklw 1 241 train
+ruraoelttp 0 301 val
+rureifhgbt 1 300 train
+rurfhvlsxf 1 298 train
+rurhhdcdba 1 300 val
+rurhwraqyg 1 300 train
+rurhyzsnyi 1 300 train
+ruriarpqpz 1 300 val
+rurshwwlha 1 300 val
+rursrvigxm 1 300 train
+rurtndrzcw 1 300 train
+ruscdzjdbs 1 300 val
+rushagxgvl 1 300 test
+ruskhalxmp 1 300 train
+rusklmgidz 1 299 val
+rutcykotns 1 300 train
+rutdietotw 1 300 train
+rutdkocinw 1 300 train
+ruthxwmdod 1 300 val
+rutpdfqmzk 1 300 train
+rutpskylur 1 300 train
+rutwnoagbl 0 300 train
+rutyozknjj 1 300 train
+ruufnypjin 1 300 train
+ruuoggubgs 1 300 train
+ruuqgljcbd 1 300 train
+ruuqroocnb 1 300 train
+ruvadafqri 1 300 test
+ruvalipugu 1 300 val
+ruvgtoihye 1 298 train
+ruvkehebah 0 300 train
+ruvlmxtaoo 0 300 train
+ruvnibkldo 1 300 train
+ruwdqyecgj 1 300 val
+ruwgianibq 1 300 val
+ruwlnronut 0 300 val
+ruwwxklbpw 1 300 train
+ruwymkmmfz 1 301 train
+ruwznwdmpo 1 300 train
+ruxepxrfva 1 300 train
+ruxervcmff 1 300 train
+ruxflvkmsu 1 300 train
+ruxttozsgd 1 300 train
+ruxztsvlek 1 301 train
+ruybjmsakd 1 300 train
+ruygiejuad 1 300 train
+ruyharoosu 1 302 train
+ruyhieoern 1 300 train
+ruyhmbksig 1 300 train
+ruyidcwgyz 0 300 train
+ruyjsluajj 1 300 train
+ruyvziayhf 1 300 train
+ruzfgwqxvu 1 300 train
+ruzidtdqpo 1 300 train
+ruzjqdupxk 1 298 train
+ruzrbyvzte 1 300 train
+ruzwmfvsjg 0 301 val
+ruzxutdzvr 1 300 val
+ruzykmxhwl 0 300 train
+rvaliysfnr 1 300 test
+rvaorlrsei 1 300 train
+rvatoiuupu 1 300 train
+rvavyaksyx 1 300 val
+rvaxddndkq 1 300 train
+rvbdlrkjbo 1 299 test
+rvboqmwnwx 1 301 train
+rvbrkkygty 1 300 train
+rvbrrhukmg 1 300 train
+rvcalvhoxm 0 300 train
+rvcepkmike 0 300 train
+rvcjbayygx 1 300 val
+rvcjmaevmq 1 300 train
+rvckmbubar 1 300 val
+rvckpavfxf 1 301 val
+rvcpjbrcba 1 300 train
+rvcprdzvxx 1 300 train
+rvcujvmqxe 0 300 train
+rvddogzste 0 300 val
+rvdetsdslx 1 301 train
+rvdkdntbbj 1 300 train
+rvdrsfubrl 1 300 train
+rvdundlcho 1 300 train
+rvdzpkyljd 1 300 train
+rvechrgcuq 1 300 train
+rveeftxxls 1 300 train
+rvefcbqxfz 1 301 val
+rvetbtgbzi 1 300 train
+rveydftcdl 1 300 val
+rvfhfbutlx 1 300 train
+rvfkompkqt 1 300 val
+rvfsjvmzkg 1 300 train
+rvgedehoeg 1 300 train
+rvgfjhlnlc 1 288 train
+rvggegluxf 1 300 train
+rvgloqqqxx 0 300 val
+rvgshixbom 1 300 train
+rvgskgtyrw 1 300 val
+rvgwbqrzdy 1 300 train
+rvgzqoyujl 1 301 train
+rvhbdgubzp 1 301 train
+rvhbvdorwy 1 301 val
+rvhdiancpz 1 300 val
+rvhfywlzzz 1 301 val
+rvhgjamyew 1 300 train
+rvhgmyilms 0 300 train
+rvhkguqcff 1 300 train
+rvhowfwbwr 1 299 val
+rvhpvkuvlh 1 241 train
+rvhrxxkstm 1 300 train
+rvhvqyxtae 1 300 val
+rvibnufops 1 300 train
+rvigswfecj 1 300 train
+rviufxprir 0 300 train
+rvivxbtbda 0 300 train
+rvizlqbazq 1 300 train
+rvjdnwgeji 1 300 train
+rvjfsjkzhx 1 299 train
+rvjjdvnjlw 0 300 train
+rvjjnuwauj 1 300 train
+rvjjoqnhrn 0 300 train
+rvjohlokmi 1 300 val
+rvjtspiwpa 1 300 train
+rvjwtvplxb 1 300 train
+rvjyvhspha 0 300 train
+rvkabkpqvw 0 298 train
+rvkartfixs 1 300 train
+rvkdxjfhdp 1 300 train
+rvkmeqmifs 1 300 train
+rvkrmvjabj 1 299 train
+rvlhzuvldj 1 301 train
+rvlmndvdxc 1 300 train
+rvlttmkiqz 1 300 val
+rvlyhhwfyr 1 300 train
+rvmagfoegh 1 300 train
+rvmckqwhrg 1 300 train
+rvmnhrokqk 1 300 train
+rvmoyrngqg 1 300 val
+rvmpwtyzoi 1 300 train
+rvmxhaanrn 1 300 train
+rvmxixzfka 1 241 train
+rvmxjyvavt 1 300 train
+rvngusoeob 1 300 val
+rvngxtbpgz 1 300 test
+rvnqribuqq 1 300 train
+rvnsxxxcde 0 300 train
+rvnudmjnqr 1 300 train
+rvnyclqodm 0 300 val
+rvobmrlvyw 0 300 val
+rvogwowmda 1 296 train
+rvopjnnnet 1 300 train
+rvoudrbyac 0 300 train
+rvppvrowpb 1 300 train
+rvpqrjpsxy 1 300 train
+rvpvgqjmzv 1 300 train
+rvpvjsdivf 1 300 train
+rvqbvfnygr 1 300 train
+rvqcikpyiz 1 301 val
+rvqcqpmaqo 1 300 val
+rvqcxiyswy 1 300 val
+rvqjfxadgn 1 300 train
+rvqmgdaplp 1 299 train
+rvqpvsgork 1 298 val
+rvqrkmddqq 1 300 train
+rvquxhomxo 1 300 train
+rvqvwvfjzo 1 300 train
+rvqxsxfcjl 1 300 val
+rvrajhkznm 1 300 train
+rvrcvcfbog 1 300 train
+rvrgbpnjwg 1 300 train
+rvrhnuhemp 1 300 train
+rvrkjfmbzn 1 301 train
+rvrksltaqz 1 300 train
+rvrlzxepiu 1 300 val
+rvrnyqrcei 0 300 train
+rvrqtftadz 1 297 train
+rvsxiadkae 1 301 val
+rvtfddfweu 1 300 train
+rvthvxwzix 1 300 train
+rvtoewphds 1 300 train
+rvtrekytyv 0 300 val
+rvtxzuosjp 1 300 train
+rvuippyzzr 1 300 train
+rvumwfklvj 1 300 train
+rvupeitjbs 1 300 train
+rvurjokwcw 1 300 train
+rvuspjfybf 1 300 train
+rvuzzxltla 1 300 train
+rvvbdzhbzu 1 300 train
+rvvcvbzafq 1 300 train
+rvvoayidmf 1 300 train
+rvvpazsffd 1 300 test
+rvvslrkycm 1 301 train
+rvvyxifekg 1 241 train
+rvvzhkhvcd 1 300 train
+rvvzluzhdu 1 301 train
+rvwaittydo 1 301 val
+rvwcegmugs 0 300 train
+rvwfojipwu 1 300 val
+rvwizqgzgm 1 300 train
+rvwnarheob 1 300 train
+rvwrxtpmrq 1 300 train
+rvwukdlcqs 1 300 test
+rvwwotbcuu 1 300 val
+rvxcidyrtl 0 300 train
+rvxfymgqyw 1 300 train
+rvxhabobcq 1 300 train
+rvxpklxrhz 1 300 val
+rvxquexjhi 1 300 train
+rvxsaajmot 0 300 train
+rvxspacvhp 1 300 train
+rvxtljkfgz 0 300 train
+rvxtngrltm 1 300 train
+rvxzaegqqz 0 300 val
+rvyhgnrigd 1 300 train
+rvyjdcsatd 1 300 train
+rvyjojzido 1 300 val
+rvynjuegxp 1 300 train
+rvyoztwigc 1 300 test
+rvyvuuvdxs 1 300 test
+rvyymzylws 1 300 train
+rvzawracfw 1 288 train
+rvzbysgzir 0 300 train
+rvzeodzdqx 1 300 val
+rvzeofaerx 1 300 val
+rvzfiizxln 1 301 train
+rvzfqwgxda 1 300 train
+rvzmqjyudm 1 298 train
+rvzmzjdaio 1 300 train
+rwahqscbrs 1 300 val
+rwanhvnnhs 0 300 train
+rwapgdxbuz 1 299 val
+rwarkxrhfb 1 300 train
+rwauburhbs 1 300 train
+rwavyafihz 1 300 train
+rwawjevwss 1 300 train
+rwbcaaicxe 1 300 train
+rwbdbdlbei 0 300 val
+rwbhqkrdri 1 237 train
+rwbjrzjphi 0 300 train
+rwbuebaset 1 300 train
+rwbuzlaidi 1 300 train
+rwbvuwcbql 1 300 train
+rwcafkwvec 1 300 val
+rwcuunyfpa 0 300 val
+rwcwopfvax 0 300 train
+rwdcqrhskv 1 300 val
+rwdhrtecfv 1 300 train
+rwdkdmwkxd 1 300 train
+rwdlslukzo 1 300 train
+rwdozgqudb 1 300 train
+rwduxfvfzy 1 300 train
+rwdvsphipn 1 300 train
+rwdykjxacb 1 300 train
+rwdzvyzmph 1 300 train
+rweaihhmdc 1 300 train
+rweaiwuccm 1 300 train
+rwebpkkopc 1 300 val
+rwecrhrccs 1 298 train
+rwehwmmutn 0 300 train
+rwelvvvjay 1 300 train
+rweucpsmyu 1 300 train
+rwevjscqef 1 301 train
+rwewziejot 1 300 val
+rweysqamtm 0 300 val
+rwfhnpjegw 1 300 train
+rwfiiicxde 1 300 train
+rwfolcmzpu 1 300 train
+rwfwsbbavr 1 300 train
+rwfxlwvfth 1 300 train
+rwfxoquonc 1 301 train
+rwfxsapvkm 1 300 train
+rwfzyepxjx 1 300 val
+rwgebfwvkr 1 300 train
+rwgiztqciz 1 300 train
+rwgmanlebe 1 300 train
+rwgshbgfot 1 300 train
+rwgwekqfij 1 240 train
+rwhbejfscj 1 300 train
+rwhghbdnim 1 300 train
+rwhiyhyswq 1 300 val
+rwhkojrmel 1 300 val
+rwhocevtfb 1 300 train
+rwhqjyzexf 1 301 val
+rwhrnqngxb 0 302 train
+rwhrszgqvt 1 299 val
+rwhuchgfzm 1 300 train
+rwhziqhxww 1 302 train
+rwicktrjqr 1 300 train
+rwitgcilms 1 292 train
+rwitlhkdel 1 300 train
+rwitpjbfko 0 300 train
+rwiymusbmg 1 300 val
+rwjdijuspp 1 300 train
+rwjicdsjbj 1 300 val
+rwjipjzwpn 1 300 train
+rwjmxvjikr 1 300 train
+rwjouirhtm 1 300 train
+rwjrwbzgwh 1 300 train
+rwjtahpfnx 0 300 train
+rwjzskeugc 1 300 train
+rwkfxxgkrh 1 300 test
+rwkghritnd 1 300 val
+rwklpnnnml 1 300 val
+rwkwaycqra 0 300 train
+rwlcyxozxm 1 300 train
+rwlriztrqo 0 300 train
+rwlxkctupy 1 300 train
+rwlzkxskkf 1 300 train
+rwmdyqnxmn 1 300 train
+rwmvtqzxza 1 300 val
+rwmygtzoux 1 300 train
+rwndzuwddb 0 300 train
+rwnfimbcxu 1 300 train
+rwnhjiliro 1 300 val
+rwnjaxsyec 1 300 val
+rwnlqryxef 1 300 train
+rwnnywkkdq 0 300 val
+rwnuakcfhh 1 300 train
+rwnuinotrl 1 297 train
+rwnyguelho 1 296 train
+rwnzmcameu 1 300 train
+rwoakkstgx 1 300 train
+rwoelhvtma 0 300 train
+rwoheeyoow 1 300 train
+rwokjyfsbv 1 300 train
+rwomluvsea 1 300 val
+rwoprybjir 1 300 train
+rwopvnfyov 1 298 train
+rwoujcuecn 1 300 train
+rwoywxdxra 1 300 train
+rwpdgxavbq 1 301 train
+rwpjhgyhep 1 300 train
+rwptbzcjfd 1 298 train
+rwpxsdzyti 1 301 train
+rwpyvhwmbb 1 300 train
+rwqehxadyl 1 300 train
+rwqfofpolc 1 302 train
+rwqjvaoiqu 1 300 val
+rwqmyggamp 1 300 train
+rwqpthrvfs 1 300 train
+rwqtqrphei 1 300 train
+rwqudnvtsh 1 300 train
+rwqxhirsgm 1 300 train
+rwqzraylnn 1 300 train
+rwrhvpmgwa 1 300 train
+rwricgjqrg 1 300 train
+rwrjuqydlm 1 300 train
+rwrlpkrruo 1 300 train
+rwrxltmsto 0 300 train
+rwsblyznuk 1 300 train
+rwsdcygvef 1 300 val
+rwsewagwav 1 300 train
+rwshvgcntx 0 300 train
+rwsjlwhccg 1 300 val
+rwspftbusa 1 300 train
+rwsplfkqwy 1 300 train
+rwssyzwvsa 0 300 train
+rwsucitkwt 1 300 train
+rwsvyxrubl 0 300 train
+rwszlscbgg 1 83 train
+rwtdszgykp 1 300 train
+rwteevndjx 1 300 val
+rwthfzmntz 1 300 val
+rwtnbzhryi 1 300 train
+rwtpwyzvdt 1 241 train
+rwtqlcqdbs 1 300 train
+rwtwmofmln 1 301 val
+rwueubvqub 1 300 train
+rwujfsipsz 1 299 test
+rwusdttdzk 1 301 val
+rwvbxqgwdi 1 300 train
+rwvczsklzg 1 300 train
+rwvlnrarag 1 299 val
+rwvqaoqund 1 300 val
+rwvrmmvqdp 1 300 train
+rwvtygyzdk 1 300 train
+rwvzsgpgej 1 300 train
+rwwdyjcoab 1 298 train
+rwweepglie 1 300 train
+rwwqimturn 1 300 val
+rwwqyhovus 1 300 val
+rwwstqjugd 1 300 val
+rwwwroflwb 1 300 train
+rwxevqflag 1 296 train
+rwxfywgyrm 1 240 train
+rwxisoajqo 1 300 train
+rwxkjggsjk 1 300 train
+rwxlfjwhkg 1 300 train
+rwxoetidfa 1 300 train
+rwxskajvqx 1 241 train
+rwxtbuazte 1 300 test
+rwydmfxfsa 1 300 train
+rwydnzpyzw 1 300 test
+rwyepawbub 0 300 train
+rwysfpdwqa 0 300 train
+rwyuvqrsaq 0 302 val
+rwzbdnjurj 1 300 train
+rwzcczbbmm 0 300 train
+rwzdajygdq 1 300 val
+rwzeswqdlr 1 300 train
+rwzqeboccw 1 300 train
+rwzqvwznhp 1 300 train
+rwzrbzubij 1 300 val
+rwztrsvtoh 1 300 train
+rwzvapisro 1 300 train
+rxaffykqgb 0 300 train
+rxagyszsky 1 300 train
+rxaifdbjjg 1 300 val
+rxamkwuflj 1 300 train
+rxatfyjawy 1 300 train
+rxbabwdbhj 1 299 test
+rxbcmlcgoq 1 299 train
+rxbgpfpapw 0 300 val
+rxbjkevtif 1 301 train
+rxbkkayajy 1 300 train
+rxbnyemwfi 1 240 train
+rxbrupmwpd 1 300 train
+rxbsalifts 1 300 train
+rxbsxhmmdu 1 300 train
+rxbuwrqbpe 1 241 train
+rxbxlygzcj 1 300 train
+rxcaaikatg 1 300 train
+rxcgxogpsj 1 300 train
+rxckizrvaq 1 300 train
+rxckyxjana 1 300 train
+rxcoeekqae 1 298 train
+rxcomvqjtk 1 300 train
+rxcpmlelhv 1 299 test
+rxcqczfxth 0 300 train
+rxcxlwnfji 1 300 val
+rxczhtxivr 1 300 val
+rxdajlkfbx 1 300 val
+rxdajrvleg 0 300 val
+rxdasqikap 1 300 val
+rxdinxhihx 0 301 train
+rxdoimqble 0 300 test
+rxdoovneoq 1 300 train
+rxdxidflbz 1 300 train
+rxeffqzqcf 1 300 train
+rxehzkomnj 1 300 train
+rxeqlheqtj 1 300 train
+rxesxxvrll 1 300 val
+rxetkeabeg 1 300 train
+rxevhpcqjy 1 300 train
+rxezxyjzls 1 300 train
+rxfawebswj 1 300 train
+rxfbkqeydi 1 300 val
+rxfhpaeebw 1 300 train
+rxfmyrgkti 0 300 train
+rxfqmnlirx 0 300 train
+rxfqtredtd 1 300 train
+rxfsftinsq 1 300 val
+rxfxbgehsi 0 300 train
+rxgauiprbb 1 300 val
+rxgcxcitsz 1 301 train
+rxgfhyzsbf 1 300 train
+rxgnvtwkpb 1 300 train
+rxgobmmgtf 1 300 train
+rxgrwmqjpz 1 300 train
+rxgtnfsxmu 1 298 val
+rxgubfqezh 1 300 train
+rxgvzycvzr 1 301 train
+rxgxzjcydj 0 300 train
+rxhbkvlfau 1 300 train
+rxhhbmjcfw 1 300 val
+rxhjgmlzwk 1 300 val
+rxhklivqeh 1 300 train
+rxhkmeflpw 1 300 train
+rxhmlawrit 1 300 train
+rxhmzplblv 0 300 train
+rxhqanmeew 0 300 train
+rxhqujqzwh 1 300 val
+rxhzammrmh 1 300 train
+rxhzfvbmyb 1 300 train
+rxicpvwbdn 1 300 test
+rxietabpsm 1 298 train
+rxifqugtcu 1 300 train
+rxiiaaarex 1 300 train
+rxiirxakdf 1 300 train
+rxilpbpeqt 0 300 train
+rxiocufkvm 1 241 train
+rxiqlqppgg 1 299 train
+rxissgjwrr 1 300 train
+rxiwhncdmh 0 301 val
+rxjalpwkha 1 299 val
+rxjcinqyqd 1 300 test
+rxjktvtwpy 1 300 train
+rxjpuhenph 1 300 train
+rxjutcewkg 1 300 train
+rxjvbmczyt 0 300 val
+rxkcjyrqyk 1 300 train
+rxkfayific 0 300 val
+rxkgzbdzsj 0 300 val
+rxkmnibcpy 1 300 train
+rxkpsfadjt 1 300 test
+rxkreikivx 1 300 train
+rxkrsgmqoi 1 300 val
+rxksakznnw 1 301 train
+rxkuelpjdf 1 241 train
+rxkvexffiq 1 300 train
+rxkwhvbxmg 1 300 train
+rxlcjaiijw 0 300 train
+rxlcuqfeud 1 301 val
+rxllfvrkzj 1 300 train
+rxlnbvevtr 0 300 train
+rxmkmrffrj 1 300 train
+rxmlvcaabw 1 300 test
+rxmoevkqrz 1 301 val
+rxmolwpoqi 0 297 train
+rxmriyayks 1 300 train
+rxmxrjsvgz 1 300 val
+rxmxxbetwk 1 300 val
+rxnhtijqli 1 300 val
+rxnrnlmipx 0 297 train
+rxnrrkekrs 1 300 train
+rxnxqycacw 1 300 train
+rxogcjfzxc 1 241 train
+rxogziruza 1 300 train
+rxowpchqve 0 300 train
+rxpaouedza 0 300 train
+rxpbhenvhs 0 300 train
+rxpdinklip 1 300 train
+rxpgvorgkd 1 300 train
+rxpkqqcxmr 1 300 train
+rxpqdpvtia 1 300 train
+rxptmrjmtx 1 167 train
+rxpwfcsqum 1 300 test
+rxqetwxrjs 1 300 train
+rxqhcoswgv 1 300 train
+rxqlkrwqkc 1 300 train
+rxqpesbufk 0 300 train
+rxqrcbuvzd 0 300 train
+rxqsisvdgf 0 300 train
+rxqskwbltj 1 300 train
+rxquvjrjmi 1 300 train
+rxqvqczepk 1 300 train
+rxreozlvxh 1 300 train
+rxrostunit 1 300 train
+rxrtxejcpg 1 301 train
+rxrumcfvnn 1 300 train
+rxrumdpwzr 1 300 train
+rxrxxjdmsh 1 300 train
+rxsbfisfay 0 300 train
+rxsfmffagc 1 300 train
+rxsirnxkwu 1 300 train
+rxsokdoavl 1 300 val
+rxsreybnfs 1 300 train
+rxsrmnrysk 1 300 train
+rxsxmxjmus 1 300 train
+rxtbobmeuq 1 300 train
+rxtcnqugkc 0 300 train
+rxtcqqswko 1 300 val
+rxthiqvlgq 1 300 train
+rxtjzlmhpf 1 300 val
+rxtmukvrts 1 300 train
+rxtpmslwet 1 300 val
+rxtqqoncwj 0 301 train
+rxtrjrious 1 300 val
+rxtvskynkv 0 300 train
+rxtwuaollu 1 300 train
+rxubvykqhi 1 300 train
+rxucdvnmev 1 300 train
+rxufykpyzl 1 300 train
+rxuhuimoen 1 300 train
+rxuwdeztil 1 300 train
+rxuxzutkjo 1 300 train
+rxuzbchiit 1 300 train
+rxvacjteob 1 300 train
+rxvbtutnnd 1 299 test
+rxvciyzheh 1 300 train
+rxvjjdrevo 1 300 train
+rxvjndftfd 0 300 val
+rxvlkhhchk 1 298 train
+rxvornrvss 1 300 train
+rxvumshkuh 1 300 train
+rxwbejjdyl 1 300 train
+rxwchpfvbh 1 300 val
+rxwetxsexq 1 299 test
+rxweyfpeql 1 300 train
+rxwjimqzti 1 300 train
+rxwpgkmamy 1 300 train
+rxwqoruisz 1 300 test
+rxwrsfnvjx 1 301 train
+rxxbhqppcc 1 300 test
+rxxepfnjzz 1 300 train
+rxxibjqnuj 1 300 val
+rxxifkujnz 1 301 train
+rxxjcsamco 1 300 train
+rxxjiewjjg 1 300 train
+rxxlnlldrt 1 301 train
+rxxmebighg 0 300 val
+rxxpgsxvyq 1 300 train
+rxxqsjrmno 1 300 val
+rxxwgydcqi 1 298 train
+rxxxurjxhf 1 300 train
+rxylusmegv 1 300 val
+rxyogxosym 1 300 train
+rxypqicyks 1 300 train
+rxyxpgsppp 1 240 train
+rxzrmusvbz 1 300 train
+rxzwqoiiov 1 300 train
+ryaaorslsj 1 300 train
+ryableasrr 1 300 val
+ryacbikjpd 0 300 val
+ryadzmmgnf 0 300 train
+ryajloavlf 1 300 train
+ryakgkynpb 1 302 val
+ryammlrvsj 1 300 train
+ryamyrpjvf 1 300 train
+ryavbgakmu 1 300 train
+ryawbpfknp 0 300 val
+ryayavewnz 1 300 train
+rybveocxtd 1 301 val
+rybyylwzse 1 300 train
+ryccazlbju 1 300 test
+rycdbymefh 0 300 train
+rycdrulbds 1 300 train
+rycgfbvrgc 1 300 train
+ryckahmoey 1 300 train
+rycshkwuix 1 300 train
+rydeyrbugx 1 300 train
+rydezrheqs 1 300 train
+rydkaduotj 1 300 train
+rydqjmzqnn 1 300 val
+rydxdjrbmj 1 300 train
+ryebdxmqaq 0 300 train
+ryegxfgkuo 1 300 train
+ryejgnrjvv 1 300 train
+ryelryovjj 1 298 val
+ryelwhhfxx 1 301 train
+ryenloufcu 1 298 train
+ryeqvtkqdh 1 299 test
+ryetnpjbdk 1 300 train
+ryeufmndck 1 300 train
+ryevadcshl 1 600 train
+ryezakpmly 1 300 train
+ryfayykpho 1 300 train
+ryfbvghxjf 0 301 val
+ryfgnvircw 1 300 train
+ryfqnbcpmt 0 300 train
+ryfqpkymzy 1 240 train
+ryfwqgesrn 1 298 train
+rygeviuiix 1 241 train
+ryggmbhrmc 0 300 train
+rygosdntcc 1 302 val
+rygsyqcjfn 1 300 train
+rygufmsldx 1 300 val
+rygzhgtjfw 1 300 train
+ryhglxejac 0 300 train
+ryhjizeesu 1 300 train
+ryhosupltm 1 300 train
+ryhtrzvogm 1 300 val
+ryhyoslnxj 1 300 train
+ryicboysci 1 300 train
+ryiphumaay 1 300 train
+ryiznrdyct 1 300 val
+ryizulfvyl 1 300 val
+ryjgatifmt 1 300 val
+ryjmxaiyvz 0 300 train
+ryjofphcjc 0 301 train
+ryjoyfmcvf 1 300 train
+ryjrjdrirc 0 300 train
+ryjspnezjd 1 300 val
+ryjtfrypkh 0 300 train
+ryjtkxdewd 1 300 train
+ryjwsnyohb 1 300 train
+rykbpptyem 1 300 train
+rykminuhlv 1 300 val
+ryksgskunt 1 300 train
+ryksvwanwl 0 300 train
+rykvjfugkj 1 301 train
+rylhewqivd 1 300 train
+rylnrbleev 0 300 train
+rylokfavrg 1 300 train
+rylubfffup 1 300 train
+ryluptqobt 1 300 train
+rylxfswnpl 1 300 val
+rylynffzhh 1 296 val
+rylzoymlfq 1 302 val
+rymgqrxukx 0 300 val
+rymizhpiro 1 300 train
+rymkjrzney 1 300 train
+rymnlezplu 1 300 train
+rymujjkzwb 1 298 train
+rymunrbbnt 1 241 train
+rymuuyhhkc 1 300 train
+rymuxggieg 0 300 train
+rymuydrcpc 1 300 train
+rymwjjmhuw 1 300 train
+ryncrlvjes 1 300 val
+rynwaixuma 1 300 train
+ryoaeodcux 0 300 train
+ryocokscze 1 300 val
+ryoecaorar 0 300 train
+ryokxeplbx 0 300 train
+ryopkcnpqt 1 300 train
+ryowoczves 1 300 val
+ryowxmsqnk 1 300 val
+rypbvfjrqd 1 298 train
+ryphrxthdz 1 300 train
+rypilvzsqx 1 300 val
+rypkkqmfsx 1 300 val
+ryprcddvkg 1 300 train
+rypskjitjn 1 300 train
+rypustitrx 1 300 train
+rypxbfmato 1 300 train
+rypxodxlko 1 300 train
+ryqgkylxqj 0 300 train
+ryqgxsjooy 1 301 train
+ryqjpimpej 0 301 train
+ryqunmwalv 1 300 train
+ryrcpewnxg 1 300 val
+ryrnimyzjk 0 300 train
+ryryihcyjn 1 300 train
+rysahavxjg 1 300 train
+rysbdspwgl 1 299 train
+rysearmrnl 0 300 val
+ryseujrzkv 1 300 train
+rysgjdukyg 1 300 train
+ryshesrcep 1 300 val
+rysjopsese 0 300 val
+rysmxgsgly 1 300 test
+ryspruxmpi 1 300 train
+ryspsmtomm 1 300 train
+rysqnfbrca 1 300 train
+rysrtoxeip 1 300 train
+rysvpaytze 1 298 train
+rytbavycbc 1 300 train
+rytczudlso 1 299 train
+rytjwbsnaa 1 300 test
+rytlcnwgek 1 299 test
+ryttsiofzl 1 300 train
+rytusspynn 1 300 train
+rytwarwyeo 1 300 val
+rytynpbqih 1 300 train
+rytzlyopvr 1 300 train
+ryufagkdwp 1 300 train
+ryujdteuhp 1 300 train
+ryuocfdklj 1 300 train
+ryuoogfoqd 1 300 train
+ryusydlszk 1 300 train
+ryuvtpqeur 0 300 train
+ryuzxqvtdd 1 300 val
+ryvbahxrge 1 300 train
+ryvdjxyvgk 1 300 train
+ryvgiyoqct 1 300 train
+ryvpvojahp 1 300 train
+ryvqfrumgm 1 300 train
+ryvqkriqum 1 136 train
+ryvspmfzyy 0 300 train
+ryvwwdkjlf 0 300 val
+rywcoyoxtd 1 300 train
+rywibbrenm 1 300 train
+rywkhysnga 0 300 train
+rywmkxrcmr 1 300 val
+rywngijgtq 1 300 train
+rywpezvuit 0 300 train
+rywrrnzkak 0 300 train
+rywrwenvvs 1 300 train
+rywrydqplg 0 300 train
+rywtrjwrbr 1 300 val
+ryxaqpfubf 1 300 test
+ryxczvahog 1 300 val
+ryxczwecnn 1 300 val
+ryxdvmzafq 1 300 train
+ryxdxcyqtp 1 300 train
+ryxitjlsve 1 301 train
+ryxnucuogh 1 300 train
+ryxwupacki 1 300 train
+ryxykawftt 1 300 train
+ryxznoadpt 0 300 val
+ryyexgpadg 1 300 train
+ryygkppakk 1 300 train
+ryyjrelfkf 0 300 train
+ryysfdslkj 1 300 train
+ryyskemqkv 1 300 train
+ryzbrpipre 1 300 train
+ryzgkivwcj 1 300 train
+ryzjzycgax 1 300 val
+ryzkdrcvic 1 298 train
+ryzmplqmyf 1 300 val
+ryzscnukem 1 300 val
+ryzxwmwpii 1 241 train
+rzacpodaem 1 300 train
+rzadvdgaol 1 300 train
+rzafutlchx 1 300 val
+rzaldnulgo 1 300 train
+rzbbqkrukm 0 239 train
+rzbcevssgi 1 300 train
+rzbcovgibn 0 300 train
+rzbdzermkb 0 300 val
+rzbfrexxfc 1 301 train
+rzbgmwtzcx 0 300 train
+rzborasjae 0 301 train
+rzbrnamzoz 1 299 train
+rzbyomxwhd 1 300 train
+rzcbrqoasw 0 300 train
+rzcchrnidu 1 300 val
+rzcdamptnr 1 300 train
+rzcrzbrhxz 1 300 train
+rzcsxcggve 1 300 val
+rzcvvyvbmw 0 300 val
+rzcxccejjz 1 300 val
+rzcxmxpdiu 0 300 train
+rzcxwraelu 1 300 train
+rzdbxbkhwk 1 300 val
+rzdkrtzrlz 1 300 train
+rzdkwvmibs 0 300 train
+rzdpntmodl 1 300 train
+rzdwalauiq 1 300 train
+rzdwtglomb 0 300 train
+rzefbdxnte 1 301 train
+rzehecpcqi 0 300 train
+rzekdyfhks 0 300 train
+rzersauqmo 1 241 train
+rzezevluka 1 300 val
+rzfbqhgjwz 1 300 train
+rzfdmenmce 1 300 train
+rzfikhhpnc 0 300 train
+rzfluxwhmq 1 300 train
+rzfmlcqlne 1 300 train
+rzfsnzzwnv 1 241 train
+rzfuspmsky 1 300 test
+rzfvhvjpzk 1 300 train
+rzgdszqase 0 300 train
+rzgfmamzjo 1 298 train
+rzglourivm 0 300 train
+rzhaioihpj 1 300 train
+rzhieqpwzo 1 300 train
+rzhjieqlgb 1 301 val
+rzhmdwtttc 1 167 train
+rzhqbgaxxw 1 300 train
+rzhrwcvgdl 1 300 train
+rzibzmcuuo 1 299 train
+rzicshpblu 1 300 train
+rzicvpdgtt 1 300 train
+rzihxsmujj 1 300 train
+rzimeubkmu 0 300 val
+rzimmqgasu 1 300 val
+rzinffqnql 1 300 train
+rzinjngqbe 1 300 train
+rziudhqfzg 1 300 train
+rzivhgpbxh 1 300 val
+rzivzpozjr 1 300 train
+rziziscker 1 300 train
+rzjazgejby 1 300 train
+rzjbenkcpo 1 300 train
+rzjdcjtyms 1 300 train
+rzjknrnbzh 1 300 train
+rzjmebzgea 1 300 train
+rzjoanehpx 1 300 val
+rzjokyjnnp 1 300 train
+rzjpckpslj 1 300 train
+rzjsdmslwm 1 301 train
+rzjsfhwyfa 1 300 train
+rzjzmdkyat 1 300 train
+rzkfsenoyp 1 300 val
+rzkqrncfyo 1 300 train
+rzksdeteuw 0 300 train
+rzksobxwik 1 241 train
+rzktvodala 0 300 train
+rzkymynqsr 0 300 train
+rzlaisbwag 1 300 train
+rzlixfoioj 1 300 train
+rzljiqidhj 0 300 train
+rzlvyzdosp 1 300 train
+rzlxpvmdob 0 300 train
+rzlzmppvdi 1 300 train
+rzmcindhyt 1 300 train
+rzmjaablyb 1 301 val
+rzmloisode 1 300 train
+rzmnztzdrf 1 300 train
+rznecommqh 0 302 val
+rznegqdxlt 1 300 val
+rzngiaomjn 1 300 train
+rznhkfwgib 0 300 train
+rznhsemash 1 300 test
+rznoejyckv 1 300 train
+rznpqrkcqp 1 300 train
+rznqhqvgue 1 300 train
+rznttlsqko 1 300 val
+rzoflxoxwe 1 300 train
+rzoliumcak 1 298 train
+rzomlwbjlm 1 298 train
+rzongbagaq 1 300 val
+rzooeapldr 1 300 train
+rzorgjmkjm 1 300 train
+rzorqxynsl 0 302 train
+rzosxksgkt 1 300 val
+rzotiimdmc 1 300 train
+rzozakfdjc 1 300 train
+rzpazvyglt 1 300 train
+rzpdhglvph 1 300 val
+rzpejrpzwb 1 300 val
+rzpsyofzaa 0 300 val
+rzqhunmbrd 1 300 train
+rzqifnkbmq 1 300 train
+rzqleunkcn 1 300 train
+rzqsregbtx 1 300 train
+rzqzpdcust 0 300 train
+rzrmfxvxdw 1 300 val
+rzrocuvhqm 1 300 train
+rzroplycws 1 300 train
+rzrrblxotd 1 300 val
+rzrtgeudul 1 300 train
+rzrydrpdry 1 300 train
+rzrynkejvi 1 300 train
+rzrzhdjahm 1 300 train
+rzscqwsity 0 300 train
+rzscvqvfgc 1 301 train
+rzseolqmby 1 300 val
+rzsnhacqzu 1 300 train
+rzstglqnxy 1 300 train
+rztadfgghi 1 300 train
+rztadokvei 0 300 train
+rztbxxzwlw 1 300 train
+rztckddvwt 1 300 train
+rztfvluvkm 1 300 train
+rztmgywyrn 0 300 train
+rztnkepotf 1 300 train
+rztzkkkxqx 1 300 train
+rztzpzxeiw 1 300 train
+rzubwutrtd 1 300 val
+rzubzbjgtp 1 300 train
+rzufbacvfh 1 300 train
+rzuhfqalzx 1 300 val
+rzuifyfjor 1 300 train
+rzumcvcfqa 1 300 val
+rzumcyhuxt 1 300 train
+rzumqdrrjr 1 299 val
+rzuojhknyx 1 300 train
+rzuouwnzrh 1 239 val
+rzuqhttvjm 1 300 train
+rzurwtzrkj 0 300 train
+rzusijnenv 1 300 train
+rzuuyouhmp 1 241 train
+rzuwmaqfre 1 300 train
+rzverjjefr 1 300 train
+rzvfckjjrw 1 300 train
+rzvgrmqgqk 1 300 val
+rzvqhfyoyk 1 300 train
+rzwpdhlyjs 1 299 test
+rzwvhesfws 1 300 train
+rzxbpcqefn 1 300 train
+rzxeyoowdr 0 300 train
+rzxffukyfc 0 300 val
+rzxgegjfax 1 300 val
+rzxoinicyv 1 301 train
+rzxrlycdbt 1 300 train
+rzxslqqecc 0 300 train
+rzxygegdnb 1 300 train
+rzxzqzhbxz 1 300 val
+rzybzgqijd 1 301 train
+rzyiutcvei 1 300 train
+rzyjgrswoh 1 300 val
+rzyjmjmzdx 1 300 train
+rzykslnkdi 1 136 train
+rzymphrydg 0 300 train
+rzyscflezv 1 300 train
+rzytdiivhu 0 301 train
+rzzaegimta 1 300 train
+rzzbsmhdyx 1 298 train
+rzzjjspeuj 0 300 val
+rzzmknnlwd 0 301 val
+rzzrrqsrou 1 300 train
+rzztkamxbm 1 299 train
+rzzxccvtsj 1 301 val
+rzzxqttqop 1 300 train
+saabaxpuzg 0 300 train
+saahvmiuws 1 300 train
+saalbotqyo 0 300 val
+saapkivgiu 1 300 train
+saaqklozeb 1 300 train
+saasmevrsw 1 300 val
+saayqqksze 1 300 train
+sabdeisrai 1 300 train
+sabiuqmhbj 0 300 train
+sabjrwbpnw 1 300 val
+sabpsmmbwu 1 300 train
+sabrbnceya 1 300 train
+sabugunzhh 1 300 train
+sabuikrxhr 1 300 train
+sabzeokkuk 1 298 val
+saccdbyovs 1 299 train
+sachnddxsh 1 300 train
+sacjkenugu 0 300 train
+sackbsykqo 1 300 train
+sackkrvhiv 1 300 train
+saclongjoz 1 298 train
+sacrjzfefm 1 300 train
+sacuxfoqpo 1 300 train
+sadaunifio 1 300 val
+saddkbymps 0 300 val
+sadeyfhimv 1 300 train
+sadohknkdi 1 300 train
+sadovbitff 1 299 test
+sadsifgfvf 1 300 train
+sadsolgnww 1 300 train
+saegbidusa 1 300 val
+saejoxswaq 0 300 train
+saenxccbvk 1 300 val
+saessjulfv 1 300 train
+saeuxotnna 0 300 train
+saevypsnrt 1 300 train
+saewdvwtes 1 300 train
+safakpmwqz 1 300 train
+saffgjgwzy 1 300 train
+safkdrudrs 1 300 train
+safmejeucy 1 300 test
+safpwcucqa 1 300 train
+safvlgwjmm 1 241 train
+safyvuease 1 300 val
+sagffcencu 1 300 train
+sagfyyshga 1 300 val
+sagiarytrf 1 300 val
+sagmurytwp 0 300 train
+sagojdzrxj 1 300 train
+sagsdgscit 1 300 val
+sagsdzeiwz 1 300 train
+sahcncjojl 0 300 train
+sahcphuauy 0 300 val
+sahufqryir 0 300 train
+sahwptqelr 1 301 train
+sahwxlbrmg 0 300 train
+sahxnezubx 1 300 train
+sahzdydlgm 1 300 train
+saiaojszgp 1 300 train
+saiaxikiea 1 300 train
+sailbngdsk 1 301 train
+sailncwlmk 0 301 train
+sainjnwynb 1 300 train
+saiobudxcm 0 300 train
+saiowjrpgj 1 300 train
+saivfswzxq 1 299 val
+sajawpobsx 1 300 train
+sajgjcvale 1 300 val
+sajgolzwjm 1 147 train
+sajogyommh 1 300 train
+sajqwyaljm 1 300 train
+sajsifpzhy 1 300 train
+sajuhhqcmi 1 300 val
+sakbbxwcvo 0 301 train
+sakehvmjgw 1 298 train
+sakfjthofg 1 300 train
+sakjyrqajx 0 301 train
+saktyxuosv 1 297 train
+sakuogenej 1 301 train
+sakwtlksrs 1 300 train
+sakyyeqyts 1 301 val
+sakziaduuh 1 300 test
+salaseekxa 1 300 train
+salattzmhs 1 300 train
+salbhluqer 1 300 train
+saldkmpykv 1 300 train
+salfqztimu 1 300 train
+saljlsmnet 1 300 train
+salmmcbost 0 300 train
+salnyzxnsk 1 300 train
+salqxytmaf 0 300 train
+salsuohkph 1 301 train
+salsuwvckq 1 300 train
+salvqwywhp 1 300 train
+samasfzfsk 1 300 train
+sambcgikru 1 297 train
+samdmhcrbz 1 300 train
+samigjpnqv 1 300 val
+samoyntgyo 1 300 train
+sampbuferp 1 288 train
+samuiteaoh 1 302 val
+samuncdmgn 1 300 train
+sanbnkhrho 1 300 train
+sanbvgulxh 0 300 train
+sandgylbbk 1 300 val
+sandhgjwkk 1 299 test
+sandyafynz 1 300 train
+sanflzvaof 1 300 train
+sanfylabug 1 300 test
+sanhibjnvd 1 300 train
+saniimivsj 1 300 train
+sanmxgeboz 1 297 val
+sanofqxbfp 1 300 train
+sansvxpjsu 1 300 train
+sanuuwitaq 1 300 train
+sanygoqcwd 1 300 val
+sanzhznfcb 1 300 train
+saobhyhkke 0 300 val
+saohrmpovc 1 300 train
+saohubluvq 1 300 train
+saojbsgqgt 1 300 train
+saokspyemj 1 300 test
+saoohazizg 1 241 train
+saoolihnnj 1 300 train
+saormighvs 0 241 train
+saoucxwpfi 1 300 train
+saoxxmbvub 1 300 train
+sapamdjbxc 1 300 train
+sapdkjvkrp 0 300 train
+sapkjpexcu 0 300 train
+sappbabmdh 1 300 train
+saprxfvznw 0 300 val
+sapthdrats 1 300 val
+sapzgbmjro 1 300 train
+sapzqwfbxx 1 300 train
+saqbresoab 1 300 train
+saqgabsqef 1 300 train
+saqgpunfes 1 300 train
+saqkkuzvcf 1 300 train
+saqqigkyhg 1 300 val
+saqxgcsujs 1 300 val
+saqzkzxbog 1 240 val
+sarahjxgse 1 83 train
+sarfklalnp 1 300 test
+sarifxktiv 1 300 train
+sarkbeohtr 1 300 train
+sarrnaikil 1 300 train
+sasljryywx 1 300 train
+sasomduuei 1 300 train
+sasoxcqisz 0 300 train
+sasprkssrp 1 301 train
+sasszrrrgo 1 300 train
+saswxthuel 1 299 test
+sasytzmuul 1 299 val
+satgywkyru 1 300 val
+satlkzqitm 1 300 train
+satmufemgg 1 300 train
+satnjuxrxi 1 300 train
+satnmpebqw 1 300 train
+satqlycwnv 0 300 val
+satsslimef 1 301 train
+satupehxyl 0 300 train
+satxaprmer 1 300 train
+satxxxlhjl 0 300 train
+sauctgpeyy 1 300 train
+sauczyiyap 1 300 train
+saudnnetmi 1 300 train
+sauedybtsl 1 300 train
+sauqegxmgy 1 301 train
+saurxeoocv 1 300 train
+sausaxtjuv 1 300 train
+sauxlnrmww 1 300 train
+savjqmbswq 1 300 train
+savqrjnncg 0 300 train
+savtwwpcki 1 300 val
+sawiawgbuz 1 300 train
+sawqlefnux 1 300 train
+saxbjxsbjf 1 300 train
+saxceiqewl 1 300 val
+saxckzirin 1 298 train
+saxdfsdphm 1 300 test
+saxjjbllvh 1 300 train
+saxjsouvwy 1 300 train
+saxujjilsf 1 300 train
+saycmizfln 1 300 train
+sayltcvsng 0 300 train
+sayreqvsws 1 297 train
+sayyjcsnri 1 300 val
+sayyjwtjol 0 297 val
+sazcnznkjo 0 300 train
+sazffkfruu 1 300 train
+sazhdeeuxe 1 300 train
+sazmuinkqa 1 292 train
+sazofmoait 1 300 val
+sazygturfl 1 300 train
+sbabcxubea 1 300 val
+sbabkthnhs 1 300 val
+sbagfqoyuk 1 300 train
+sbaghvgpif 1 300 train
+sbahcvlcwm 1 300 val
+sbanqvulyl 0 300 val
+sbaoikjlnk 1 300 train
+sbazpzqwsn 0 300 val
+sbbafydtpg 1 300 train
+sbbbidysbz 1 300 train
+sbbctsilmc 1 300 train
+sbbjfmpftd 1 298 train
+sbbteevjjr 1 300 val
+sbbtmhcsct 1 300 val
+sbbwupygxh 1 300 train
+sbcfersqng 1 300 val
+sbchgqzhyw 1 300 train
+sbckcwzcyp 1 297 train
+sbcupveybx 1 298 train
+sbcuttoehw 1 300 train
+sbcvngabuy 1 300 train
+sbdakmfhhs 1 300 train
+sbdaycykrl 1 302 train
+sbddnndmzk 1 300 train
+sbdevixeul 0 300 train
+sbdhygnktf 1 300 train
+sbdjpgruus 1 300 train
+sbdnfnmipw 1 300 val
+sbdnlcktvi 1 300 train
+sbdoerarrt 0 300 train
+sbdozegqgc 1 300 train
+sbdplqvamf 1 300 train
+sbdzaklgsi 1 297 train
+sbeawqslfn 1 300 train
+sbenlfniha 1 300 train
+sbeocxojri 1 300 train
+sbeowuztyq 1 300 train
+sbeprggkde 1 300 train
+sbezvvicif 1 300 val
+sbfazeorrv 1 300 train
+sbfbkxjpyd 1 300 train
+sbfijbueaf 1 300 train
+sbfiyomqhy 0 300 train
+sbfleznbmc 1 300 train
+sbfmvdmxhh 1 301 val
+sbfowmconp 1 300 train
+sbfphdbtwc 1 298 train
+sbfqskzcxw 0 299 train
+sbfsrusrbl 1 300 val
+sbfuddornz 1 300 train
+sbfxzmhzyv 1 300 train
+sbgajsyted 1 300 test
+sbggfpjyfq 1 300 train
+sbghromnxb 0 300 train
+sbgnqpkpyt 1 300 val
+sbgpnindik 1 300 train
+sbgqqmotju 1 300 val
+sbgvomirpr 0 300 train
+sbgxlnqpaa 1 301 train
+sbhmhdhrjo 1 300 train
+sbhnywxsfg 1 300 val
+sbhqmwexhj 1 299 test
+sbhrtuyifh 1 300 train
+sbhsrncybd 1 300 train
+sbidmyijtf 0 300 val
+sbilujylwe 1 300 train
+sbiobixpqm 1 300 train
+sbiugxtrkc 1 300 train
+sbiyangkdy 1 300 train
+sbjauhupne 1 300 train
+sbjipfuops 1 241 train
+sbjjhcgfuz 1 300 train
+sbjkhxnjni 1 300 val
+sbjouovbep 1 300 val
+sbjpftggfb 1 300 train
+sbjvoqcett 1 300 train
+sbjwklplsg 1 300 train
+sbjxvrdjhz 1 300 train
+sbjyrlbqpm 1 300 train
+sbkesocrlc 1 300 train
+sbketndksn 1 300 train
+sbkidgwrgf 1 300 train
+sbkmnkzlxd 1 241 train
+sbkupuqxdg 1 300 train
+sbkyzqjelt 1 298 val
+sblaxjdfgk 1 301 train
+sblcoyjgfv 1 300 test
+sblfnihedz 1 300 train
+sblkmkchiz 1 300 train
+sblrdebfos 1 300 train
+sblrpzhxzw 1 300 train
+sblwccdbrm 0 300 train
+sblzjklgin 1 300 train
+sbmacpggcj 0 300 train
+sbmaleanxw 1 302 train
+sbmdjtpoaw 1 300 train
+sbmfakhsez 1 300 train
+sbmlekhkao 0 300 train
+sbmndrkqmu 1 300 train
+sbmnndiqdq 1 300 train
+sbmpwcohba 0 300 val
+sbmrxaaomv 1 300 train
+sbmszbciou 1 300 train
+sbmtiybsrh 1 300 train
+sbnahukiju 1 300 train
+sbnfxnkljd 1 300 train
+sbnpdwmafe 1 300 train
+sbnzcqhqrj 1 300 val
+sboafbslkn 1 300 val
+sbofkqoepl 1 300 train
+sbogamqsie 1 294 train
+sbohgiomki 1 300 train
+sboiescabo 1 300 train
+sbokgwonui 1 300 train
+sbotjdyrxx 1 300 train
+sbotucwqdc 1 301 train
+sbotxkdorv 1 301 val
+sbpbpxzspy 1 300 val
+sbpcvbqoiz 1 300 train
+sbpkctvgbr 1 300 train
+sbpmtpkbya 1 300 train
+sbpqhjktzr 1 300 train
+sbqatvqaey 1 300 train
+sbqdmipsai 1 300 val
+sbqdnvpevr 0 300 train
+sbqhhclhwi 1 300 train
+sbqmenaejo 1 300 train
+sbqrymkxri 1 300 train
+sbqtdkjmel 1 300 train
+sbrjiwfrtg 1 300 train
+sbrnzhxxyh 0 300 train
+sbrycqangw 1 300 val
+sbrzfmqlek 1 300 train
+sbrzjwexte 1 300 val
+sbsclbjjjh 1 300 val
+sbslgwiiel 1 300 train
+sbsndyuqjd 1 300 train
+sbsonxryir 1 300 val
+sbspezimpw 0 300 train
+sbsqzwjwog 1 300 val
+sbssdlrhhu 1 300 val
+sbssvzhtqz 0 300 train
+sbsumluyzq 1 300 train
+sbswpedlgt 1 300 train
+sbsxwovolk 1 300 val
+sbsylgxhnj 1 241 train
+sbtbhponof 1 300 train
+sbtcukrgmb 0 300 train
+sbtmydndtz 1 300 train
+sbtpdydomw 1 300 val
+sbuhfnrwer 1 300 val
+sbuohkefof 1 300 train
+sbuqdalbho 1 300 train
+sburmokfqc 1 300 train
+sbuvogitpz 1 300 train
+sbuxtyxvhv 1 300 train
+sbuyrzimsw 1 300 train
+sbvaggfhze 1 300 train
+sbvarowqws 1 300 train
+sbvchdtkup 1 300 train
+sbvmkxewns 1 301 train
+sbvncmmubs 1 300 train
+sbvnwameis 1 300 train
+sbvoswzwet 1 300 train
+sbvtjrwxng 1 300 train
+sbvvtqulcx 1 300 train
+sbwemwjlsl 1 300 train
+sbwiplmiei 1 300 train
+sbwpbbytvs 1 300 train
+sbwubysmox 1 300 train
+sbwvgpznnm 1 301 val
+sbwxzcauup 1 300 train
+sbwyljsyld 1 301 train
+sbxbsiwwnc 1 296 val
+sbxlfehzjc 0 300 val
+sbxvmficyn 1 300 train
+sbxwirrias 1 300 train
+sbxxgwrmwa 1 300 train
+sbxzscxyjh 1 298 val
+sbyckvrrlz 1 300 train
+sbyhgdnkca 1 300 train
+sbyjgxrqgf 1 301 train
+sbykdtsvxs 1 300 train
+sbyppemigv 1 300 val
+sbypubftlo 1 300 train
+sbysitanks 1 300 train
+sbyuorrlqd 1 297 train
+sbyvfklmtj 1 300 train
+sbyynfgtmp 1 300 train
+sbyzbieqsn 1 300 train
+sbzbwgbpzb 1 300 train
+sbzdufzlyi 1 300 train
+sbzhqdbslb 1 300 train
+sbzudgwrno 1 300 train
+scaerrkxws 1 300 train
+scakkxcyej 1 300 train
+scaljzcpcf 1 300 train
+scaptkelpb 1 300 test
+scavsycbux 1 300 train
+scbbkalnxl 1 300 train
+scbdenmaed 1 300 test
+scbetbullx 0 301 train
+scbfkrlytb 1 300 train
+scbifafxla 1 300 train
+scbjgarcas 1 301 train
+scbjqctmod 1 300 train
+scbllulioi 1 300 train
+scbuwbnphb 1 300 train
+scbwxvvjbo 1 300 train
+scchljludm 1 300 val
+scchmtbzar 1 300 train
+scclhewfew 0 300 train
+scclzguzqr 1 300 train
+sccqbzyikm 0 300 train
+scctwsfkxg 1 300 train
+sccxwwayqo 0 300 val
+scdixszdbs 1 300 train
+scdkwxvspt 1 300 train
+scdqcszlpq 1 300 train
+scdqmdyxss 1 299 test
+scdsgzdect 0 300 train
+scdsqrprzo 1 300 val
+scemuxppxm 1 300 train
+scewobxjsd 1 300 train
+scffgtmxgz 1 300 train
+scfgnpggvf 1 300 train
+scfumzorzi 0 300 val
+scfuttedcw 1 299 test
+scfvbaghje 1 300 train
+scgmayfgcw 1 300 train
+scgrtggjag 1 300 train
+scgruwvnmu 1 300 train
+scguzrfxke 1 301 val
+scgylrsydh 1 300 train
+scgzvthhrx 1 300 train
+schahmhhsk 1 300 train
+schixuaiok 1 300 train
+schjtrxwli 1 301 train
+schmqfgebe 0 300 train
+schrrunsfk 1 300 train
+schtkhzivy 1 298 train
+scidaiqmwo 1 300 train
+scihemdklk 1 241 train
+scihhzghat 1 298 val
+sciiklphqi 1 300 train
+scijrwllgd 1 300 val
+scikublujg 1 300 train
+sciwfjidua 1 300 val
+sciwrpnbfd 1 300 train
+scjdkezndi 0 300 train
+scjzuxdjma 1 301 val
+sckdsnhnmq 0 241 train
+sckgpvbzpc 1 300 train
+sckktwooft 0 300 train
+sckxicculi 1 300 train
+sclanmgtva 0 300 val
+scleplqhgl 1 300 train
+sclfnvmobn 0 300 train
+sclhkvykgw 0 300 train
+scliivqeha 1 300 train
+sclmvqrkew 0 300 train
+sclnioekai 1 300 train
+sclquorbsv 1 300 val
+sclrgxruwm 1 299 train
+scltsfnnba 1 301 train
+scltvggodu 0 300 train
+sclvdumbkh 1 299 test
+sclztagggd 1 300 train
+scmduxmopf 1 300 train
+scmqycwnpt 1 300 train
+scmsaxjimq 0 300 val
+scmslxzkae 1 301 train
+scmtduaitf 1 300 train
+scnasqkaro 1 300 train
+scnfkchvad 1 300 val
+scngvceiih 1 301 train
+scniqgazbo 1 300 train
+scnmfwidia 1 300 train
+scnpxsahsx 1 300 train
+scnttvlbkt 1 300 train
+scnwnjpbfh 1 300 train
+scnylgfkhq 1 300 train
+scobbkpgap 1 300 train
+scoelswnja 1 300 train
+scohyittdw 1 300 train
+scojsbrjro 1 300 train
+scorolwfhy 1 300 train
+scoxxcadex 1 300 val
+scoyfdnukj 0 300 train
+scpcdzexwo 0 300 train
+scpeawtvvz 1 300 train
+scpglaliyh 1 300 test
+scpindfzsb 1 300 train
+scpyvgwfiu 1 240 val
+scqcbzwcvg 0 300 train
+scqcdvqiyq 0 299 val
+scqgzixpyc 1 301 val
+scqmsfcsmx 1 300 val
+scqtbeyasr 1 300 train
+scrbqgpvzz 1 300 test
+scrcjvobtj 1 301 train
+scrgeupzge 1 300 train
+scrirvoacx 0 300 train
+scrogtfgmn 0 299 val
+scrrnqrsnc 1 300 val
+scrtkrsojr 1 300 train
+scrvvtnctb 0 300 train
+scrwlmqnyg 1 300 train
+scrwqafuqc 1 300 train
+scrzydajma 1 300 train
+scsbdwawox 1 300 train
+scscrzgtxc 1 300 train
+scsjhmvpfw 0 300 val
+scssmbfchs 1 300 test
+scswhprxwj 1 300 train
+scsxobfowb 1 300 train
+scsykoxtfw 1 300 train
+sctcdtdzgv 0 300 train
+sctgkvypos 1 300 train
+scthgfdcvr 1 300 train
+sctiqozecg 1 300 train
+sctphvyvoo 1 300 train
+sctqpvpixx 1 301 val
+sctshiflkt 1 300 val
+scucbnqnom 1 300 train
+scuduuoezr 1 300 train
+scuffekebm 1 136 train
+scumloobkn 1 300 train
+scunminwyb 1 300 train
+scunsguqjt 0 300 train
+scuqaozduq 1 300 train
+scutzugpvt 1 300 train
+scvdhzeqps 1 300 train
+scvfbtdmav 1 300 train
+scvhikwhdn 1 299 test
+scvhyqjvwk 1 300 train
+scvimwmnwh 1 300 train
+scviovhqhu 0 300 train
+scvivjzlku 1 300 train
+scvkxznabj 1 300 train
+scvlxikuoi 1 300 train
+scvojqbebd 1 300 train
+scvrvmrxrm 1 300 train
+scvuztsgie 1 292 train
+scvzgusnav 1 302 val
+scwegycyru 1 300 train
+scwlsajopq 1 300 val
+scwlwoqeeb 1 300 val
+scwqgqbvrm 1 300 train
+scwvikzavz 1 240 train
+scwzdjelch 0 300 train
+scxbdbgtkn 0 300 train
+scxdmmlmmp 1 300 train
+scxeuutngj 1 300 train
+scxgpnknil 1 300 test
+scxhscuvgm 1 300 train
+scxhtxvhsf 1 301 train
+scxjhrejub 1 300 val
+scxjonbnog 1 300 val
+scxnxghasx 0 300 train
+scxqsgpdpw 1 300 train
+scxrriwshy 1 300 train
+scxrwnofhb 0 300 train
+scxukzmuhz 1 300 train
+scxustzywt 0 300 train
+scyfuvaowq 1 300 train
+scymdunydn 0 300 val
+scymivjhqh 1 241 train
+scyowrqkep 1 300 test
+scyuasekwk 1 301 val
+scyyjstmts 1 300 train
+sczapfktsu 1 300 train
+sczbdmybho 1 300 train
+sczdudsbyv 1 300 train
+sczhajogqp 1 300 train
+sczkjoyuvs 1 300 train
+sczotewblh 1 300 train
+sczqsptlul 1 298 train
+sczulsyijo 1 300 train
+sczurcculo 1 241 train
+sdacwaoens 1 241 train
+sdaczwqohn 1 300 train
+sdaffzzwsb 0 300 train
+sdaiwadgoi 1 300 val
+sdaqskuweg 1 302 train
+sdasnjiqhv 1 300 val
+sdawyswyno 1 300 train
+sdaxvnkkui 1 298 val
+sdbectiibm 1 300 train
+sdbldddgsw 1 300 train
+sdbrethchy 1 300 train
+sdbxulvkvi 1 300 train
+sdbydgsbkf 1 300 val
+sdcdorsejf 1 300 train
+sdcgznpwmf 1 300 val
+sdcjjvsgiz 0 300 val
+sdckiswzpg 1 300 val
+sdcpqvvfbd 1 300 train
+sdcpxweghq 1 300 train
+sdctyhncem 1 298 val
+sddapiesde 1 300 val
+sddfxeptfs 1 301 train
+sddgmxeomr 1 300 train
+sddkopbouy 1 300 train
+sddkqwwckt 1 300 train
+sddlkdjjqt 1 300 train
+sddnxbnpbh 1 301 train
+sddszusumt 1 300 train
+sddykpcvia 1 300 val
+sddzovdsoz 1 300 train
+sdebpvublf 1 300 train
+sdecymtbsh 1 300 train
+sdedimlsbe 1 300 train
+sdekftetnp 1 300 train
+sdetnpbgki 1 300 train
+sdeuqqbcxp 1 302 train
+sdewpktsnx 1 300 train
+sdezsvktyj 1 300 train
+sdfboadkrh 1 300 train
+sdfnakqxov 1 300 train
+sdftowxcrd 1 300 train
+sdftymphhv 1 300 val
+sdfzqisrhs 1 300 train
+sdgecamghx 1 300 val
+sdgeniwnvt 0 300 train
+sdggvktkii 1 300 val
+sdghnqwqbn 1 300 train
+sdgjjhxjmh 1 300 train
+sdgvcuqqee 1 300 train
+sdgwdjjztr 1 300 train
+sdherpgtdk 1 300 train
+sdhinvudec 1 300 train
+sdhkdnzvux 1 300 train
+sdhxemxqko 1 299 val
+sdibedfnep 1 300 train
+sdistqkqim 0 300 train
+sdiuyonxwr 1 300 train
+sdixtksisf 1 300 val
+sdjeetvczw 0 300 train
+sdjiaxmbwc 1 300 val
+sdjinzujfu 1 300 train
+sdjjxrnkxm 1 300 train
+sdjshfeiqa 1 300 train
+sdjwdudgbl 1 300 train
+sdkhiowfwc 1 300 train
+sdkhqxvzol 1 300 val
+sdkltjozqs 1 300 train
+sdkoygugks 1 300 val
+sdkpjshgef 1 298 train
+sdkzpyuxkr 1 301 train
+sdlrdthahz 1 300 train
+sdlvashkzs 0 300 train
+sdmnayfktx 1 301 train
+sdmoeirnuh 1 300 train
+sdmsqtucqz 1 300 val
+sdnbbuojnu 1 300 val
+sdndjbuuns 1 300 train
+sdnfgejwip 1 300 train
+sdngqdnfcb 1 300 train
+sdnuhxwqen 1 300 train
+sdomnorhme 1 100 train
+sdonaayztt 0 300 train
+sdoqcxpkyp 1 300 train
+sdorhlibip 1 300 test
+sdosowmctz 1 300 train
+sdovycllcf 1 300 train
+sdoyumapor 0 300 train
+sdozfsvwde 1 300 train
+sdpnvrlaxc 1 300 train
+sdptloakhj 1 300 val
+sdptshemzm 1 300 train
+sdptyzcycx 1 300 val
+sdpwoyqnvd 1 300 train
+sdqaedtyon 1 300 train
+sdqbuvafmb 1 300 train
+sdqfyqkokw 1 300 train
+sdqiwyciek 0 300 train
+sdqjjttckw 1 300 train
+sdqrfmpwnw 1 300 val
+sdquluvcrf 1 302 train
+sdqyqontsp 1 300 val
+sdrafirfss 1 300 train
+sdrartupkt 1 241 train
+sdrbksvvee 1 300 train
+sdrcgqbbpn 1 300 val
+sdrexrgxdv 1 300 train
+sdrhpnronp 0 301 train
+sdrpjtgnur 0 300 train
+sdryxtamcq 1 300 train
+sdsbdpexrm 1 300 train
+sdsdijnxjd 1 300 train
+sdsgbzkjpx 1 300 val
+sdsmshpoyl 1 300 train
+sdsnuonqbf 1 300 val
+sdsrvllgpc 1 300 train
+sdstjytlpe 1 300 train
+sdsvxkrqnk 0 300 train
+sdtfloekhb 1 300 train
+sdtpedrmmq 1 300 train
+sdtpixcmxs 1 300 train
+sdtqrpcztf 1 240 val
+sdttqggnca 0 300 train
+sdttzxfmek 1 300 val
+sdtwbfeofc 1 300 train
+sdtxghkgie 1 300 val
+sdtzxdzqww 1 300 train
+sdudnjwzyh 0 299 train
+sdueexnbbz 1 300 val
+sdueikdqxj 1 300 train
+sdufiuyimi 1 301 train
+sdukdaykjb 1 300 train
+sdustdkmol 1 300 train
+sdutqxtcxo 1 300 train
+sduuqnyuuf 1 300 train
+sduxzrkwkp 1 300 train
+sdvifrabmf 1 300 train
+sdvjwcofdx 1 300 train
+sdvlaetgtz 1 300 train
+sdvrtzmcvd 1 300 train
+sdvumeekom 1 300 train
+sdwbjxblnx 1 300 train
+sdwcoklcsv 1 299 val
+sdxejfublr 0 300 val
+sdxfhccfrn 1 300 val
+sdxjjqeomi 1 301 val
+sdxsjrkznf 1 300 val
+sdxtqsgcpy 1 300 train
+sdxvdeooxz 1 301 train
+sdyjbfiqtp 1 300 train
+sdynnnnokh 1 300 train
+sdywpxcuza 1 300 train
+sdyykysbml 1 300 train
+sdzclucfkz 1 300 train
+sdzdnrmqnw 1 300 train
+sdzeilcubq 1 300 train
+sdzjrmpmzo 1 300 val
+sdzwwgqlpp 1 298 train
+sdzxbhfhfu 1 241 train
+sdzzeqsggj 1 298 val
+sdzzjnfxtw 0 300 train
+sdzzzxteas 1 300 test
+seabqfiqdj 1 300 train
+seaingdjyu 1 300 val
+seajqleghs 0 300 train
+sealrxdhla 1 300 train
+sebbuhkgie 1 301 train
+sebhddbxbr 1 300 train
+sebhwuuods 0 300 val
+sebqdraffe 1 300 val
+sebrejwpaa 0 300 train
+sebsryxlzt 1 300 train
+sebuayottj 0 300 train
+secfenlviu 0 300 train
+secgqjbhdi 1 299 val
+secgswbvsr 1 300 train
+secnvhbdjy 1 300 train
+sectcrwsak 0 300 train
+secteygxse 1 300 train
+secxpiqmlg 1 300 train
+seddkcboce 1 300 train
+seddkpnfty 1 301 val
+seddxiphzu 1 298 train
+sedkmbkqqy 1 297 train
+sedoblbays 1 300 train
+sedsyebeli 1 300 train
+sedzpplmnt 1 301 val
+seebczdmzl 1 300 train
+seebdoxxxz 0 300 train
+seellwbtdq 1 300 val
+seemxsdwoq 1 300 train
+seetvrnaqo 1 300 train
+seewwvvzrb 1 300 train
+sefciimtoz 0 300 train
+sefihyluav 1 300 val
+sefjxbskoj 1 300 train
+sefkawqmve 0 298 train
+sefmumiber 1 300 train
+sefnosuubr 1 299 test
+sefqjsfpbi 1 301 train
+sefyffsroe 0 300 train
+segtjvkvuh 1 296 train
+segxdoasfo 1 301 val
+sehcrnpzkv 1 300 val
+sehmmawdak 1 300 val
+sehmystfib 1 300 train
+sehpizscgh 1 298 train
+sehtghjoap 1 300 val
+sehtobdelp 1 300 train
+sehwhlyqho 1 300 train
+sehwrijpum 1 300 train
+seigpgelwg 1 300 train
+seigtuqzvp 1 300 train
+seihoetmmz 1 301 train
+seikvvsodi 1 300 train
+seinulznhl 1 300 train
+seitzajfsn 1 302 val
+seiupetkwn 1 300 val
+seixbdzkrw 1 298 train
+sejhstonxs 1 301 val
+sejmzolvtv 0 300 train
+sejoguutmv 0 300 train
+sejpjfbypy 1 300 train
+sejttfsefa 0 298 train
+sejuhgvhwo 1 300 val
+sejwhhsaok 1 300 train
+sejzeqnika 1 300 train
+sekdasumtw 1 300 train
+sekddsdagd 1 300 train
+sekfrtrvyb 1 300 val
+sekfxqjlsg 1 300 train
+sekosqymqa 1 299 train
+sekstsavtc 1 300 train
+sekwbcwnfq 1 300 train
+sekwncgkzc 0 300 train
+selliofhdy 1 300 val
+sellwmoebk 1 300 train
+selntdceha 1 300 train
+selrivfagu 0 300 train
+semevzkeik 1 300 train
+semhfxqhzu 1 300 train
+semkwpxsom 1 300 train
+semzlljnzj 1 298 train
+senctxjvxj 1 300 train
+senfctfkqn 1 300 val
+senftxkwzm 1 300 train
+senmfuvpka 1 299 train
+senrirjhwh 1 300 train
+sentrxkchb 1 300 train
+sentzzguhv 1 300 test
+senvnpnkqi 1 300 train
+senxhotyhi 1 300 train
+seohpnkydn 1 300 val
+seomqwrwdi 1 301 train
+seonqpzbco 1 299 val
+seoomartef 0 300 train
+seopteeeld 1 298 train
+sepaeanxmk 1 300 train
+sepjarhriw 1 300 train
+sepjgukdti 1 300 train
+seprgxonhp 1 300 val
+sepwbaktax 1 298 val
+sepycohyva 1 300 train
+sepygxhiqk 1 300 train
+seqbtrzodj 1 300 train
+seqdrcgqmt 1 296 train
+seqqibgwjy 1 300 train
+seqzvlunse 1 301 train
+serbwjbxdk 0 300 train
+sercbullrv 1 300 train
+sercmhsqgw 1 300 train
+serijhyfxj 1 300 train
+serparxqiw 1 300 train
+serwygnhiz 0 300 train
+serxntdxpl 1 299 test
+sesactirxu 1 300 train
+sesadudazr 1 298 train
+sesbvgfdfy 0 300 train
+sesguawjew 1 300 train
+sesmbkxhpw 1 240 train
+sesrxpfkci 1 301 val
+sesseuzxgv 0 300 train
+sesymwhmvn 1 300 train
+seszakerdc 1 300 train
+seszvlylke 1 300 val
+setangebtn 1 300 train
+setekuwzzn 1 300 train
+setilpbdgz 1 300 train
+setizlpfza 1 300 train
+setjkedlki 1 298 train
+setukxcsib 1 300 train
+seugcjaziq 1 300 train
+seujnkaucr 1 300 train
+seuljxvyof 0 300 train
+seumizxuis 0 300 train
+seuopwfltu 1 300 train
+seusqjaupb 1 300 val
+seustcckot 1 300 train
+seuxoppxta 1 298 train
+sevcmzjyvo 1 300 train
+sevjnqwtjr 0 300 train
+sevpubemdc 1 300 test
+sevslgapij 0 300 val
+sevvxpkios 1 300 train
+sevxalfpiw 0 300 train
+sevxhibais 0 300 val
+sevxzulmrk 1 300 train
+sevycddsdk 1 300 train
+sewkrjtill 0 300 val
+sewkvbwylx 1 301 train
+sewmedjjdt 1 302 train
+sewnzymdlx 1 300 train
+sewqfvdtjh 1 300 train
+sewqiqzfki 1 300 train
+sexhmctrjp 1 299 train
+sexkkeinqk 1 299 train
+sexpztwqsq 1 301 train
+seyjxguulj 1 300 train
+seyswbkbup 1 300 train
+seyuvdvnnp 1 300 train
+seyzkxexlc 1 300 train
+sezanwxmkk 1 300 val
+sezddfsbzd 0 100 train
+sezezzahjn 1 300 train
+sezlgyxbfn 1 300 train
+sezqbnpzft 0 300 val
+sezrfrlzcq 1 300 train
+sezrrmaceu 1 300 train
+sfabflkkoo 1 300 train
+sfaibczzbq 0 300 train
+sfamlxmkhg 1 300 val
+sfaqoacxjg 0 300 train
+sfaznrfmlb 1 300 val
+sfbbqsrzjk 1 300 train
+sfbfoapvim 1 300 train
+sfbjlwwvfo 1 300 train
+sfbnrbvbpn 1 300 test
+sfbpjefdus 0 300 val
+sfbpyskkjp 1 301 train
+sfbsckvyfc 0 300 train
+sfbvubzwvb 1 300 val
+sfbzqkseyn 0 301 train
+sfciaiaglt 1 300 train
+sfckrqryip 1 300 train
+sfcsjsisqe 1 299 test
+sfcumlxfgi 1 300 train
+sfczvbdnfh 1 300 val
+sfdadywxgp 1 300 train
+sfdbltsjah 1 300 train
+sfdcvwpzty 1 300 val
+sfdexwqthl 0 300 train
+sfdhaujswn 1 300 train
+sfdlhkypix 0 300 train
+sfeslgxoik 1 299 val
+sfewxjuaag 1 300 train
+sfexlnvhfy 1 300 val
+sffcmqtrsu 1 297 train
+sffcwlhlku 1 300 train
+sffqiyjjsl 0 300 train
+sffwbiwkxj 1 300 train
+sffxfxpgki 0 300 train
+sffzirgzvt 1 300 train
+sfgcvgmpiv 1 300 train
+sfgddstquc 1 300 train
+sfgdliqurl 1 300 train
+sfgnirvosg 1 298 train
+sfgoaxwmwy 1 300 train
+sfgpdqviku 1 300 val
+sfgsnfzgcd 1 300 train
+sfhatncbbv 1 300 train
+sfhduwqkdn 0 300 train
+sfhdynunvw 1 300 train
+sfhfrbqcvb 1 300 train
+sfhgrqfeni 1 300 train
+sfhkdfvfkc 1 300 train
+sfiddgphvw 1 300 train
+sfidefwfhf 1 300 train
+sfiurvnpef 1 300 val
+sfiuxreuzl 1 301 train
+sfjcqsxoxj 0 300 train
+sfjggmyfuj 1 300 train
+sfjmwcolyd 1 299 test
+sfjsmbrsnu 1 301 train
+sfjtewgmuy 1 300 test
+sfjtjotflz 0 300 val
+sfjualzaic 1 300 train
+sfjvqkywvz 0 300 train
+sfjxazuhaz 1 300 train
+sfjxhbdesg 0 300 train
+sfkbbqscfd 1 300 train
+sfkihngpxa 1 300 val
+sfkjfitpaq 1 301 val
+sfknqxketc 1 300 train
+sfkvpiggix 1 300 train
+sfkyzmjvwo 1 300 train
+sfkzfeciog 1 300 train
+sfkzgfhxui 1 300 train
+sflczqufzh 1 298 train
+sflmemiaxx 1 300 val
+sflspenmhb 1 300 train
+sfmcmbyuuy 1 300 val
+sfmhpvahzi 1 83 train
+sfmpwebofr 1 240 val
+sfmunruqjy 1 136 train
+sfmuycewzb 1 300 train
+sfndgpozbg 1 300 train
+sfnmhcifbc 1 300 val
+sfnmojeevk 1 300 train
+sfnpccubyn 0 300 train
+sfntjrywgw 1 298 train
+sfnwhdjlla 1 300 val
+sfnynmywbl 1 300 val
+sforadgblh 1 300 test
+sfouebyxvi 0 300 train
+sfovkwrrpf 1 300 train
+sfpbvudltp 1 301 train
+sfpfcmjnhj 0 300 train
+sfpqgobgof 1 300 train
+sfqbkemsoz 1 300 train
+sfqbvdhifm 0 300 train
+sfqntplece 1 300 train
+sfqstysbbl 1 301 val
+sfqsvtbsju 1 300 train
+sfqwnoixtm 0 300 train
+sfrazvuxlj 1 300 train
+sfrcmdrqqv 1 300 train
+sfrnlubsqc 1 300 train
+sfrtbenmel 1 300 train
+sfrwijmcky 1 300 train
+sfsayjgzrh 0 299 test
+sfscwenwej 1 300 train
+sfsfaxbwcs 1 300 train
+sfsgvcyque 1 300 train
+sfsjgkxvie 1 301 train
+sfsjyvldnj 1 300 train
+sfslnpbvtq 0 300 train
+sfsqqsxdkv 1 300 val
+sfsqzkmnck 1 300 train
+sfsvhjqglo 1 300 train
+sfsvylfstw 1 300 train
+sfsyqyeqcc 0 300 train
+sfszkpytqz 1 300 train
+sftbveoswv 1 300 train
+sftdwiyojb 1 300 val
+sftnnikifa 1 300 train
+sftsbbozeo 1 301 train
+sftvafvaxj 1 300 train
+sftwnqisbm 1 298 train
+sftyapugxy 1 299 train
+sfuhcflils 0 300 train
+sfujxhuyje 0 300 train
+sfuplgvhds 1 300 train
+sfuwuzguli 1 300 train
+sfvfxbliox 1 300 train
+sfvgyrakql 1 298 train
+sfvhqnulzm 1 300 val
+sfvqcsnima 1 300 train
+sfvttczlrl 1 300 train
+sfwmfngbnx 1 300 val
+sfwvejpaid 1 302 val
+sfxdunvuhf 1 300 train
+sfxkdqzctb 1 300 train
+sfxmqyoahx 1 300 train
+sfxpdqxzir 1 300 val
+sfxycknqco 1 300 val
+sfyarnisms 1 300 train
+sfyfgmxewo 1 300 train
+sfyjropdvy 0 299 val
+sfyntyankj 1 300 train
+sfyqkdekqm 1 300 val
+sfyscepcfe 1 300 train
+sfyvqqovnm 1 300 train
+sfyxlizyly 1 300 train
+sfyymvabas 1 301 val
+sfyyzmwjvt 1 300 train
+sfzbjyskjx 0 300 train
+sfzddvkenj 0 300 train
+sfzeczujwx 1 298 train
+sfzixpdhsl 1 300 train
+sfzuhqbkzg 1 300 train
+sfzwytttbl 1 300 train
+sgaauagrzn 1 300 train
+sgaclwsnhp 1 300 train
+sgadezemmc 1 300 train
+sgalwxyrzo 1 300 train
+sganfbijvm 1 300 val
+sgaxkrhijj 1 300 train
+sgbavunqyt 1 300 train
+sgbghvwvnc 1 300 train
+sgbkpxoqko 1 300 val
+sgbrszbdgo 1 300 train
+sgbtdgsqds 1 300 val
+sgbwtnzwjk 0 300 train
+sgbydzkcpi 1 300 train
+sgcatwfcvn 1 300 train
+sgcbmlvlrc 1 300 train
+sgccguuwpb 1 300 train
+sgccjmjhho 1 294 train
+sgceduzmzl 1 241 train
+sgclbvlypn 1 300 train
+sgclhrswid 1 300 train
+sgcmgytgzn 1 300 val
+sgcrnqvtyv 1 301 val
+sgdakyticz 1 300 train
+sgdavpqoqg 1 300 train
+sgdeperrpi 1 300 train
+sgdiraogcc 1 300 test
+sgdksrclls 1 300 train
+sgdnbofecu 0 300 val
+sgdypiliht 1 300 train
+sgehmqxfjw 1 300 val
+sgentclzpl 1 300 train
+sgerqiqowe 0 300 val
+sgeyxrgpul 1 300 train
+sgezhwlsdq 1 296 val
+sgfbjmiukp 1 300 train
+sgfdydkoon 1 300 train
+sgfqaytite 1 300 train
+sgfsancfew 1 300 train
+sgfvqkpycp 1 300 train
+sggcrvezmb 1 300 train
+sggkeodpfr 1 301 train
+sggkwmtcul 1 300 train
+sggoinedya 0 300 train
+sggryhrkum 1 300 train
+sggxohvcmt 1 302 train
+sghbruybbg 1 299 test
+sghdekqnnn 0 300 train
+sghpqfzzyu 1 300 train
+sghqlqjbso 1 300 train
+sghridiszj 1 300 val
+sghxmjyymj 1 301 val
+sghxxchsiq 1 300 train
+sgidnbtrer 0 302 train
+sgiiudjafn 1 300 train
+sgijfgrvni 1 300 val
+sgiszkyedg 1 300 train
+sgjbakrrix 0 300 val
+sgjiauphuh 0 300 train
+sgjjfzddba 1 300 val
+sgjnvxvcpu 0 300 train
+sgkebqsuzw 1 300 train
+sgkfkrbfho 1 300 train
+sgknzbmosh 0 300 train
+sgkzajvfmk 1 300 test
+sglawmtccl 1 300 train
+sgleazzkwf 1 300 train
+sglirjvwru 1 300 train
+sgllwpovte 1 241 train
+sglmestxbm 0 300 val
+sglqgohuwx 1 300 val
+sglupkczzl 1 300 train
+sglwmbbhkj 1 300 train
+sglzgdcjkb 1 300 test
+sgmccrghmu 1 297 train
+sgmkrpzomy 1 300 train
+sgmtuyhfic 1 301 train
+sgmvjdsvxu 1 300 train
+sgmwflnrvq 1 300 train
+sgmzwjkhrz 1 300 train
+sgnahtqhxr 1 298 train
+sgnchximip 1 300 train
+sgngwwxapl 1 300 val
+sgnlwllhzk 1 298 train
+sgnqhmqksm 1 300 train
+sgnvldmgki 0 300 train
+sgolydgoxx 1 300 train
+sgowhefeng 1 301 train
+sgozvsiqwy 1 298 train
+sgpdbjvnjg 1 298 train
+sgperyitce 1 300 val
+sgpivaqxhw 0 300 train
+sgpizxbdhy 1 300 train
+sgploekvaa 1 300 val
+sgpocgyjax 1 237 train
+sgppeqppkb 1 300 train
+sgpqzsnvif 0 300 val
+sgqbgmhzeb 0 300 train
+sgqcgikvft 0 300 train
+sgqdigiguw 1 297 train
+sgqdyynshg 1 300 train
+sgqjtzsgrt 1 300 val
+sgqnwsscop 1 300 val
+sgqruiabdi 0 300 train
+sgqttcbhxf 1 299 test
+sgqysuytts 1 300 train
+sgqzvfjtpi 1 301 val
+sgrcftjvos 1 300 train
+sgrivzmklt 1 301 train
+sgrlhcutyl 1 300 train
+sgrzpfohdw 0 300 train
+sgsdheabbs 1 300 train
+sgskcdxozv 1 300 train
+sgskgmpubp 1 300 train
+sgskgtzowt 1 300 train
+sgslmybprh 1 300 val
+sgsrjchbsh 0 300 val
+sgstwbyole 1 300 train
+sgtinqyfmf 1 300 val
+sgtngibvra 1 300 train
+sgtpaqvlng 1 255 train
+sgtrjcbuna 1 300 train
+sgtulmvely 1 300 train
+sgupdtowsm 1 300 train
+sguuydmoav 1 300 train
+sgvgaqcrec 1 300 train
+sgvntscgnc 1 300 train
+sgvsiwydte 1 300 train
+sgvtnejlmb 1 300 test
+sgvtwuyrpn 0 300 train
+sgwdvuwzvg 1 136 train
+sgwfxrzzjm 0 300 train
+sgwlfucorn 1 300 train
+sgwukgsdit 1 300 train
+sgwyhlfzby 1 300 train
+sgxnsrkxmd 1 300 train
+sgxnuqilma 1 300 train
+sgxovbbdcb 0 300 train
+sgxqirbgzp 1 300 train
+sgxsoeletu 1 301 val
+sgxuilsdgs 1 299 val
+sgyabuvzfw 1 301 train
+sgyavbrkly 1 300 val
+sgycbnsydz 1 300 train
+sgyfhzseie 1 300 train
+sgyljokcaj 1 143 train
+sgypglmdnx 1 300 train
+sgyrvomqcf 1 300 test
+sgyukghvrh 1 300 train
+sgyydgxpva 1 300 train
+sgyytfkici 1 300 val
+sgyzllcext 0 300 val
+sgyztejbsh 1 300 test
+sgzbxqhles 1 300 train
+sgzdjbfdzz 0 300 train
+sgzdnmbopr 0 300 train
+sgzeyzeajv 1 249 train
+sgzmybstkz 1 300 train
+sgzporhkno 0 300 train
+sgzpqvfbif 1 300 train
+sgzthgjrlg 1 300 train
+shadxgdsez 1 300 val
+shahocmicn 1 300 train
+shajwddgbg 1 300 train
+shakyzpdlb 0 300 train
+shamemqjid 1 300 train
+shbafrmaza 1 300 val
+shbapwnpjw 1 300 train
+shbnikkvsv 1 300 train
+shbwdodhrg 1 300 train
+shciglcfsf 1 300 train
+shclgsfxtj 1 299 train
+shcluhsags 1 300 train
+shcssgfzet 1 300 train
+shcwflhqfu 1 300 train
+shdbgsxmoe 1 300 train
+shdobyqvjk 1 298 train
+shdqrmymgu 1 136 train
+shdtfepios 1 300 val
+shdyjrckgk 1 300 val
+shdyuvnxzh 1 300 train
+sheaydkjge 1 301 val
+shedktnxfa 0 300 train
+shefxrlguk 1 300 train
+shehvyhzsd 0 300 val
+shenidieml 1 300 train
+sheqedfnqf 1 300 train
+sherosbvvz 1 300 val
+sheunnhdxe 0 298 train
+shfbdjuecv 1 300 val
+shfefddltk 1 300 train
+shfhlufwvb 1 300 train
+shfhpujaxz 1 300 val
+shfqggnmrv 1 300 train
+shfqskhiaf 1 300 train
+shfqwmpril 0 301 train
+shfsmwxhdm 1 300 train
+shftbthgex 1 300 val
+shfvdbtusb 0 300 train
+shfyavkpqz 1 300 val
+shgcqnbriu 1 300 train
+shgkcjblvr 1 300 train
+shglbyvkny 1 300 train
+shgoenqqkd 1 300 train
+shgtlzdzeg 1 300 train
+shgwshcvde 1 300 val
+shgxfwcczl 0 300 train
+shgxlbcywd 1 300 train
+shhcngealn 0 298 val
+shhduevjeu 1 300 train
+shhijaluey 1 300 train
+shhjiavlvw 0 300 train
+shhoravmgn 1 300 train
+shhtfogdle 1 300 train
+shhtzerfbb 1 300 train
+shhvnvgcng 1 300 val
+shhxysvhfy 1 300 train
+shhzhiwppa 1 241 train
+shhzzsoiqy 1 300 train
+shibxrzlsj 1 300 train
+shiijtgazd 0 300 train
+shikzxipov 1 300 train
+shilefcaqi 1 301 val
+shiuhedocv 1 300 train
+shjaqypyli 1 299 val
+shjargirkt 1 300 train
+shjfguaqpo 0 301 train
+shjlqbijdg 1 300 train
+shjpuxwkos 0 300 train
+shjulwhnlm 0 300 train
+shjvyvtdfx 1 300 train
+shjwludvye 1 299 val
+shjxnkrbuu 1 300 train
+shkapjfqdc 1 300 train
+shkbzuhmlr 1 299 train
+shkclvsaix 0 300 val
+shkhgtqgze 1 300 train
+shkjseybst 1 300 val
+shkmhbdnfm 1 300 train
+shkufpxwqc 1 300 train
+shkvqrndfi 1 300 train
+shkzjtsoku 0 300 train
+shlflheepx 1 298 train
+shlqreycrj 1 300 val
+shluntxihe 1 300 val
+shlwjcbprf 1 300 train
+shlxphgmtw 1 300 train
+shlzbpwicq 1 300 train
+shmajobspx 1 300 train
+shmecmjrgn 1 300 val
+shmjfkrjjx 1 300 train
+shmkfwlhwr 0 300 val
+shmlqhtbam 1 300 train
+shmmaeinqr 1 300 train
+shmrmyayzg 0 300 val
+shmtigwtcd 1 296 val
+shmwduefdx 1 300 train
+shnjgkvlhj 1 300 val
+shnpmcukxy 1 300 train
+shnsajrsow 1 300 test
+shnsjssqqd 1 300 train
+shnxpxyqea 1 300 train
+shoklqfuil 0 300 train
+sholufpcbk 1 300 val
+shopbbapgj 1 300 val
+shopcethfr 0 300 train
+shozdlrpxa 1 300 train
+shpavsycvx 1 300 train
+shpejgwexv 1 300 train
+shphhzkequ 1 300 train
+shpnotzsvp 1 301 train
+shpnxqfpsa 1 300 val
+shpvoqfnka 1 300 train
+shqazqmydw 1 239 train
+shqgzupjfp 1 300 train
+shqiieiyiy 1 300 train
+shqlblzizl 1 300 train
+shqoaurlnd 1 300 train
+shqreopxtp 1 298 train
+shqrlgxpnm 1 300 test
+shqshmbjra 1 300 train
+shquhxqrtj 1 300 train
+shqvlgselm 1 300 train
+shqyaiksak 1 300 train
+shrexvazoa 1 300 train
+shrglavkpw 1 300 train
+shrovhivlg 1 300 train
+shrpamtirw 0 300 train
+shrqnckzik 1 300 val
+shrucywawd 1 300 train
+shrvdkivqg 1 300 train
+shrzbcofrk 1 300 train
+shsczgecay 1 300 train
+shsgrgvzuz 0 300 train
+shsknhctxp 0 300 train
+shslgpeisw 0 300 train
+shsnskdgpz 1 302 val
+shsyqwptsb 1 297 train
+shtnxygjpt 1 300 train
+shtoxstjna 1 300 train
+shulbptmvc 1 300 train
+shuqrvhhaq 1 250 train
+shuwtkriuy 1 299 train
+shvaqyduzg 0 298 train
+shvfupmrho 0 300 train
+shvlyoydeb 1 99 train
+shvobxixzk 0 300 train
+shwcjhoqag 1 300 val
+shwhnfwwfx 0 300 train
+shwkznunyp 1 300 train
+shwmpxlokj 1 300 train
+shwrvaktbs 1 300 train
+shwulrbsfx 0 301 train
+shxhsscqnj 1 300 train
+shxwuzwonb 1 300 test
+shxzpjkxli 1 300 train
+shyajdztjj 0 300 train
+shybcjwcii 1 300 train
+shygmutvzv 0 300 train
+shyjwprsso 0 300 train
+shykehejkh 1 300 train
+shykwffzrd 1 301 train
+shyxysdgpy 1 300 val
+shzesnjozd 1 300 train
+shzhktkbvn 1 300 train
+shzqiovptk 1 300 train
+shzsteamvv 1 300 train
+shzvxgailq 0 300 train
+shzyluikml 1 300 train
+siadyrvnsi 1 300 val
+siajmpjzjz 1 300 train
+sialmitpdk 1 300 train
+sianpqcthw 0 301 val
+siavketkir 0 300 train
+sibbvaywuz 1 300 train
+sibdghppea 1 300 train
+sibforxpjp 1 300 train
+sibjrdfshj 1 300 train
+sibkoyqbfo 1 300 train
+sibpryxtpn 1 300 val
+sibvnegdqq 1 300 val
+sicabomivi 1 301 val
+sicixwrnjs 1 300 train
+sicmaxiury 1 296 val
+sicmayctjj 1 300 val
+sicobdfwed 1 300 train
+sicswuleun 0 300 val
+sicuzairzx 1 300 train
+siczgqjhjv 1 300 train
+sidelrrpdn 1 301 train
+sidfpzhfmg 0 300 train
+sidlthhuxy 1 300 train
+sidnrqgebm 1 300 train
+sidscsbyir 1 241 train
+sidvaqtibx 1 300 train
+sidzeeoaum 1 300 train
+siebfpwuhu 0 300 test
+siedibyuqy 1 300 train
+siexafxqln 1 300 train
+sifbwqwexo 1 300 train
+sifkmgsqun 0 300 train
+sifohlniaz 1 300 val
+sifoppndtt 1 300 val
+sifsucjmgc 1 300 train
+siggrdjgwd 0 300 train
+sigkkykscq 1 300 train
+sigrlwzhlf 1 300 train
+sigtxuuutc 1 300 train
+sigxwqulio 1 301 train
+sihjlonfmz 1 300 train
+sihmgmbxwn 1 300 train
+sihqsouxym 1 298 val
+sihwiashxa 1 300 train
+siicrfhinn 1 300 train
+siilnbyjnc 1 300 train
+sijcscxjca 1 300 train
+sijcxhjtcp 1 300 train
+sijhfakbgl 1 241 train
+sijizvyfxi 0 300 train
+sijlhnazfj 1 300 train
+sijlkbmjws 1 300 train
+sijokvhcjl 1 300 train
+sijpqafxlx 1 300 train
+sijqoyddwj 1 301 train
+sijxjsdfev 0 300 val
+sijzcbwppo 1 300 test
+sikbymjpeh 1 300 train
+sikfaofylw 1 300 train
+sikjrcesif 1 300 train
+sikxsgxpeu 1 300 train
+silbzsxzax 1 300 val
+silffjrasj 1 298 val
+silkvrozud 1 300 val
+silrrtsmav 0 300 train
+silrsndmpk 1 300 train
+silxjjbcsw 1 300 train
+silyramuhb 1 300 train
+silyuhawvq 0 300 train
+silzpeptcq 1 300 train
+simamsujuu 1 300 train
+simbaadhiy 1 300 val
+simdowaaid 0 300 train
+simiojtbqm 1 301 val
+simmveubsc 1 300 val
+simmvvxpyp 1 300 train
+simnyzyiis 1 300 train
+simredhfhu 1 300 train
+simrrkygok 1 301 val
+sinekahldk 1 301 train
+sinfhganrv 0 300 train
+sinlkfhjti 1 300 val
+sinpqlmroz 1 300 train
+sinratamuu 1 300 train
+sinwfzkkga 1 300 train
+sinxhzrhie 1 300 train
+sioagbbntu 1 300 val
+siodzfercg 0 300 val
+siogvmoxpf 0 300 train
+sioiqldyvy 0 300 train
+siomdmqxni 1 300 train
+siosnasygg 1 300 train
+siowghokqd 1 300 train
+sipuxpudya 1 300 train
+sipwdoqlxx 1 300 train
+siqafljvfm 1 300 train
+siqbgxzssi 1 300 train
+siqgdrcjqj 1 300 train
+siqkfvlrvc 1 300 train
+siqxqrbedn 1 300 val
+siqyydnfsk 1 300 train
+sirckcjmov 0 300 train
+sirdjpbuka 1 298 train
+sirhlngcew 0 300 val
+siriifwdyg 1 300 train
+sirruhazin 1 298 train
+sirsquaduu 1 300 train
+sisabqbfot 1 300 val
+sischkcthb 1 300 val
+siscvnluzl 1 299 test
+sislohhpkm 1 147 train
+sislybmjvp 0 300 val
+sistdbvtsd 1 300 train
+sisthpviax 1 300 train
+sisymflqba 0 301 train
+sitbtiszpt 1 300 train
+sitgpqrixw 1 300 train
+sitgykbyzp 1 300 train
+sitkcsewjn 1 300 train
+situxkwdjn 1 300 train
+sitvymbvfh 0 300 train
+sitztlcfkx 0 300 train
+siufoiwxuh 1 300 train
+siusadtzqt 1 300 train
+siuwdunegb 0 300 train
+siuxbabsrb 1 300 train
+siuxiwxvvl 1 300 val
+siuzsssysm 1 300 train
+sivdiyqeli 1 300 train
+sivdjwsqwh 1 239 val
+sivgirrdae 1 302 train
+sivnraghku 1 300 train
+sivooqlapo 1 300 train
+sivrgbsaog 1 300 val
+sivsnajtie 1 300 train
+sivvpetfdd 1 300 train
+siwmglrdle 0 300 val
+siwooxfwoe 1 300 val
+sixdaqjkec 1 300 train
+sixiznpihv 1 300 train
+sixryecafp 0 300 train
+sixsscgrbh 1 300 train
+siydemvysq 0 300 train
+siydodagkk 1 300 train
+siydovycde 0 300 train
+siyffifnbt 1 300 val
+siyfunllmn 1 300 train
+siyjjonkyt 1 300 val
+siypyikrup 1 301 val
+siyrvwrfew 1 299 train
+siysxtmtoz 1 300 val
+siytbamdan 1 300 train
+sizaujapgb 1 241 train
+sizifwwpvf 1 300 train
+sizvyvuuuc 1 300 val
+sjaaqwgppw 1 300 train
+sjagsjethf 0 300 train
+sjagubkwob 1 300 train
+sjaiurvfip 1 300 val
+sjaognjlom 1 300 train
+sjasadttqf 1 300 train
+sjbbazfacg 1 300 train
+sjbbmcbzhv 1 300 train
+sjbeccezmt 1 300 train
+sjbeprwfeb 1 300 train
+sjbrjajlds 1 300 train
+sjbsbaxbxe 1 300 train
+sjbsyezxrn 0 300 train
+sjccoibjpf 0 300 train
+sjcitromod 1 300 train
+sjclrxxizz 0 300 train
+sjcvuajruw 1 300 train
+sjdelgmcah 1 300 val
+sjdepepazd 1 300 val
+sjdhexvtpc 1 300 val
+sjdiejkbmz 1 300 train
+sjdirrbrkl 1 300 train
+sjdmjaosjp 1 300 train
+sjeatjdyad 1 300 train
+sjedcuygtv 1 297 train
+sjegpgmtmn 1 300 train
+sjembkcnrf 0 300 train
+sjenxqodzh 1 300 train
+sjeujtxgpf 1 300 train
+sjeyosrvxx 0 301 train
+sjfcvndbks 1 300 train
+sjfgscqnvh 1 300 test
+sjfnwkiqin 0 300 val
+sjfxdqbzga 1 300 val
+sjgbiywngj 1 300 train
+sjgkkdxsxa 1 300 train
+sjgkzwbfmz 0 300 val
+sjgmmecazy 0 300 train
+sjgppstnfw 1 300 train
+sjgzxlsvvv 0 300 val
+sjhdpkjzvp 1 300 val
+sjhdwvfdbi 0 300 val
+sjhfvydhwq 1 300 train
+sjhlfesvds 1 300 train
+sjhmoowxum 1 300 train
+sjhruuarsb 1 300 val
+sjhtuovugl 0 300 train
+sjhuatqirt 1 296 val
+sjhvhsfmro 1 301 train
+sjhynfdkjr 0 300 val
+sjiabdrzic 1 300 train
+sjiixxiygu 1 300 train
+sjijcmieny 1 300 train
+sjikbuyuri 0 300 val
+sjinmmbipg 1 299 test
+sjipeifdrn 0 300 train
+sjircsamfy 1 296 train
+sjiyajszfi 1 300 train
+sjizkayscq 0 300 train
+sjjdkyumzi 1 300 val
+sjjlxqqheh 1 300 train
+sjjospvqap 1 300 train
+sjjtgfcdxp 1 300 train
+sjjvvahesv 1 301 train
+sjkcvwllmo 1 300 train
+sjkezsevou 1 300 val
+sjkfxrlxxs 1 300 test
+sjkigpouuh 0 300 val
+sjkiqaaqfr 1 301 val
+sjkmxzwiod 1 300 train
+sjktolptzh 1 300 train
+sjkwxqukox 1 300 val
+sjladhresg 1 300 val
+sjloudnlji 1 300 train
+sjlunnlfel 1 300 train
+sjluxqrcko 0 301 train
+sjlwbyjekn 1 300 train
+sjmjjndfde 0 300 train
+sjmmxrngsy 0 300 train
+sjmqizvlym 1 300 train
+sjmqjqzbli 1 300 val
+sjncxmpaib 1 300 train
+sjnozerfpz 1 241 train
+sjntqkpgtu 1 241 train
+sjnunuerci 1 300 train
+sjnykcfqif 1 300 train
+sjocionvvn 1 193 train
+sjodnseywq 1 300 train
+sjodqbdnsv 1 301 train
+sjoociefyl 0 300 train
+sjooumwlzb 1 300 train
+sjovujvjfe 1 299 val
+sjpcgcsxsz 1 300 train
+sjpdxmrvms 1 300 val
+sjpfsgblyt 1 294 train
+sjpiunhhce 1 298 train
+sjpzztqkpq 0 300 val
+sjqkqnazyt 1 300 val
+sjqlnqjnoz 1 300 train
+sjqrdxemye 1 300 train
+sjqrdyzkgl 0 300 train
+sjrhibhmso 1 300 train
+sjrinpnbfw 1 300 val
+sjrljpcyzr 0 300 train
+sjrpypsiyt 1 300 train
+sjruktxnas 1 300 test
+sjrxmzovhz 0 300 train
+sjrxvdbrtu 1 300 train
+sjrzrxttqy 1 300 train
+sjskybbfpx 1 300 train
+sjsnmrpohp 1 301 val
+sjsweftixr 0 300 train
+sjsycapehf 1 300 train
+sjsyrijyvm 1 300 train
+sjtgmownvr 1 300 train
+sjthyqzihq 0 300 train
+sjtkamgdqa 1 301 train
+sjttsrfmjf 1 299 train
+sjtuoasekc 0 297 train
+sjtvirizlt 1 301 train
+sjudknssdn 1 300 train
+sjutrsymsg 1 300 train
+sjuvewzpcw 1 301 train
+sjuxjzlyxx 1 241 train
+sjuxnvbjrg 1 300 train
+sjuztahktm 0 300 train
+sjvczmvtgo 1 241 train
+sjvmpjtndn 1 300 train
+sjvpgwrbmv 0 300 train
+sjvpzmaxgh 1 300 train
+sjvqaasrdv 1 300 val
+sjvrkhnccp 0 300 val
+sjvwawgpvs 1 300 val
+sjvzgczhcv 1 300 val
+sjwcwsaqbc 1 300 train
+sjwedraykt 1 300 test
+sjweineqiv 1 300 train
+sjwhelhgyl 1 300 train
+sjwhlpivbd 1 300 train
+sjwkkkmaly 1 300 train
+sjwklycfzv 0 300 train
+sjwlvficai 1 300 train
+sjwsvnowgf 1 300 train
+sjwuodezyh 1 300 train
+sjwvkrvwxo 1 300 val
+sjwvvfdfjy 1 300 train
+sjwywglgym 1 300 test
+sjxdmdshzq 1 300 train
+sjxfiihgow 0 301 train
+sjxfynsiwd 1 301 train
+sjxnaejpks 1 300 val
+sjxsycszbu 1 300 train
+sjyacyfblj 1 300 train
+sjyaizwoib 1 300 val
+sjydrhtgrb 1 300 val
+sjygwkiceq 1 300 train
+sjyjyvwpbl 0 300 train
+sjynetplbw 1 300 train
+sjyolsjmpq 1 300 train
+sjyozbucqn 1 300 train
+sjyrdtjddq 1 300 train
+sjyrpqacrk 0 300 train
+sjytdklrci 0 300 val
+sjywwochbi 1 300 val
+sjzauewezr 1 300 train
+sjzgqxnjoc 0 301 val
+sjzhljyjdq 1 300 train
+sjzijdqpuo 1 300 train
+sjziqvsvru 1 300 train
+sjzkpusafz 1 301 train
+sjzovxcpst 1 300 train
+sjzquestef 1 300 train
+sjzwpqupnm 1 300 train
+skadyesnbw 1 300 val
+skahaiukmy 0 300 train
+skaimvshsj 1 300 val
+skajydiuvh 1 299 val
+skakwwbjdm 0 300 train
+skalsyxrln 0 300 train
+skaonlmqhz 0 300 train
+skaotlvtik 1 300 val
+skarhddhcg 1 300 train
+skarkrylhu 0 300 train
+skawlhnjsz 1 300 train
+skbekcwkne 1 300 val
+skblurqkbj 0 300 val
+skbpwareru 1 300 train
+skbrdgycah 1 301 val
+skcamtycoz 1 300 test
+skcdschjfk 1 300 val
+skcdzlcxtq 1 300 train
+skcfaolwgh 1 300 train
+skcihxqylb 1 300 train
+skcunqgxxs 1 300 val
+skcvlzgafb 1 300 train
+skcwoiyepg 1 300 train
+skdehbnbvj 0 300 train
+skdeimxquv 1 300 train
+skdfuxblwu 1 301 val
+skdgygiiqj 1 301 val
+skdjfxhnyi 1 300 val
+skdsektask 1 300 train
+skdwkainpa 1 300 train
+skdxovvbku 1 300 train
+skecgexbqx 1 300 train
+skepmmcjsh 1 300 train
+skepvpqbhk 1 241 train
+skepxzvxnw 0 300 train
+skeucresjq 1 300 train
+skewcclbhg 1 300 test
+skewngleuz 1 300 train
+skfjaptuon 1 300 train
+skfkcjinfd 1 300 val
+skfkkaenwv 1 300 train
+skfmvmfxuy 1 300 val
+skfnhumwpn 1 300 val
+skfotfijae 1 300 train
+skfysfiunh 1 300 train
+skghfqfquk 1 300 train
+skgiwmlmou 1 301 train
+skgojnlrnp 0 300 train
+skgrxxxbmj 0 300 train
+skgtskslgb 1 300 val
+skguzmmvef 1 300 train
+skhlpqxrqw 1 300 test
+skhnvzyukn 0 300 train
+skhvdnpqzu 1 288 train
+skhwejqifd 1 301 train
+skhwruzxpu 1 300 train
+skhzkboasa 1 300 test
+skibpmbunj 1 300 train
+skigbqqshl 1 300 train
+skihuvavvp 1 301 train
+skiockaegt 1 300 train
+skiojciloa 1 300 train
+skipjcgjjv 0 300 val
+skitfybwhb 1 300 train
+skivcwzkan 1 300 train
+skiypzqvbi 1 300 train
+skjaajgyof 1 300 train
+skjbtvmwwd 1 300 train
+skjdpmgnde 1 300 train
+skjikzwdtt 1 300 train
+skjkithfek 1 300 val
+skjnbfbmhk 1 299 train
+skjsqgynnv 1 300 train
+skjzebhser 1 300 val
+skkcojgfmd 1 300 train
+skkcothrqz 1 300 train
+skkcsjxtse 1 300 train
+skkpgyjxwj 1 300 train
+skkqcgrdfl 1 300 train
+skktrcgrce 1 300 train
+skkzgucmdv 0 300 val
+sklevsoagj 1 300 train
+sklsqulmde 1 300 train
+skltdwhkib 1 300 val
+skltusseol 1 300 train
+sklzeozsfm 1 300 train
+skmaopyjsl 0 300 val
+skmatemtcj 0 300 train
+skmibjwozz 0 301 train
+skmofczpll 1 300 train
+skmuamgebu 1 300 train
+skmwhprvoc 1 300 train
+skmzqadsyb 1 300 train
+sknarckids 1 301 train
+sknbdnvuuw 0 300 train
+skniidvyeh 1 300 train
+sknijyvekh 1 241 train
+skntktuabs 1 300 val
+sknvycxyan 0 300 train
+skobpbclau 1 300 train
+skoghkxkbr 1 301 val
+skomchngws 0 300 train
+skorodmxdv 1 300 train
+skoxffalth 1 300 train
+skoxrekvkr 1 300 train
+skpckxfukp 1 300 train
+skpdpjxvhc 1 298 train
+skpftgvojr 1 300 train
+skpnutloel 1 302 train
+skpobtldgf 1 298 train
+skpvbijpso 1 301 train
+skpwudvvmb 1 300 train
+skqdwcjaji 1 300 train
+skqekganer 1 300 train
+skqeqgflvx 1 100 train
+skqkyvogku 1 300 train
+skqljpvste 1 241 train
+skrftjxdqa 1 249 train
+skrjfhvhnr 1 300 val
+skrpivsmry 1 300 test
+skrqefdmcd 1 300 train
+skrqoagxle 1 300 train
+skrwnpzxfz 1 300 test
+skryhopnvk 1 241 train
+skrzehxzuc 1 300 val
+sktnefogwf 1 300 train
+sktpeppbkc 1 299 test
+sktptnsgtf 1 300 train
+skubxeevva 1 300 train
+skudlmvrnr 1 300 train
+skuizldlru 0 300 train
+skunjwijoh 1 300 train
+skunmtdkil 1 300 val
+skussyicyg 1 300 train
+skusxkzfrg 1 300 train
+skuvjoyukn 1 300 val
+skuwbihote 1 301 train
+skvaqlnybp 1 300 train
+skvnmeboyq 1 300 val
+skvowrpuff 0 300 val
+skvplilbid 1 300 val
+skvpqkdhxc 1 300 train
+skvuqgdblv 1 298 train
+skvwpxovmi 0 300 train
+skvzvtmqvw 1 300 train
+skwbzxjptd 1 300 train
+skwdeiwkhv 1 300 train
+skwgkomhwg 1 300 test
+skwmrskbtg 0 300 train
+skwstwotsa 1 300 train
+skwvbewzpg 1 300 val
+skwvgroumd 1 301 train
+skxadlypii 1 300 train
+skxbhcoley 1 300 train
+skxbtzvszf 1 300 train
+skxdkyxneg 1 300 train
+skxkwpiivm 1 300 val
+skxmxucqqh 1 300 train
+skxnqkptoq 1 300 train
+skxnruuake 1 300 train
+skxpvgzpsa 1 300 train
+skxqrexqsp 1 300 val
+skxtrhhlum 1 300 train
+skxwkfgscd 1 300 train
+skxxieofmi 1 300 train
+skyamiumuu 1 300 train
+skybvjqoht 1 300 val
+skycfrjmns 1 299 val
+skyfahzuvx 0 300 train
+skyitgxixd 1 300 val
+skylvgpnjw 1 300 train
+skynstiglg 1 300 val
+skyswnvwfx 1 300 val
+skywvrgxir 1 300 train
+skyyaicwfb 1 301 train
+skyyjikwrg 1 300 train
+skzdcfptze 1 301 val
+skzhyhrlyv 1 301 train
+skzjkzrudg 1 300 val
+skzqihmzjp 1 300 train
+skzrewvamy 0 300 val
+skzsadlkqn 1 300 val
+slabsfjkta 1 300 train
+slaetxuicg 1 241 train
+slajgzvwzz 1 300 train
+slakzltuxq 0 300 train
+slaqauiuvy 1 300 val
+slaramijgv 1 300 train
+slaschiobj 0 300 val
+slayysqett 1 300 test
+slbbuysyhe 1 300 train
+slbbvsuinj 1 300 val
+slbhiftdwk 1 300 train
+slbhraklcc 1 300 val
+slbloafxus 1 300 val
+slbnzmdydv 1 300 val
+slcbbolzap 1 300 train
+slcnclckqx 1 300 train
+slcpruxggn 1 300 val
+slcuboabpm 0 300 train
+slcygyejys 1 300 train
+slcznunrhg 1 300 train
+slczqsvxcx 1 300 train
+sldbbzftyw 0 300 train
+sldfoldwfa 1 300 val
+sldhoyqmqo 1 300 val
+sldnhnzehl 0 300 train
+sldoajkpnw 1 300 train
+sldpkwpzsc 1 300 val
+sldrasgedn 1 300 val
+sldravrmgd 1 300 train
+sldrngkvwj 1 300 train
+slduzbfmfc 0 300 train
+sldzqxrflv 1 300 train
+sleakeetov 0 300 train
+slealwjsku 1 300 train
+sleblmpnkx 1 300 test
+sledglmlyu 1 300 train
+slehlzkwnv 0 300 train
+sleieaiwez 0 297 train
+sleijzemhz 1 241 train
+slemzgdhro 1 300 train
+slesgixeqy 1 300 train
+slexuatzxj 1 300 train
+sleykxpevy 0 300 train
+slezrnrbsf 1 300 train
+slfbfwfobf 1 301 train
+slffjxwtaz 1 300 train
+slfqpulzyl 1 298 train
+slfqrkqlwe 1 300 train
+slfrhqozlm 1 300 train
+slfrkadfcr 1 299 train
+slfrlepduf 1 83 train
+slfwivhnle 1 301 train
+slfwxkmdgo 0 300 val
+slghgyzahi 1 300 train
+slgnpdundj 1 300 train
+slgoaebcqo 0 300 train
+slgqatyppy 1 301 val
+slgqsvzusq 0 300 val
+slgsmhgyso 1 300 train
+slguojfsit 0 300 train
+slgxaxlugm 1 300 train
+slgylvmzba 1 300 train
+slhibizexb 1 300 train
+slhiikrbyx 1 300 val
+slhinthqcq 1 300 test
+slhkaosehs 1 299 train
+slhnuyjzwv 0 300 val
+slhvicdiwr 1 297 train
+slhyfbfdhb 1 300 train
+slidqcvoii 1 300 train
+slillojong 0 300 train
+sliqncisxo 1 300 train
+slirgxnazt 1 300 train
+sliucntfgl 0 300 train
+slixispipy 1 300 train
+sljaizccqh 1 300 test
+sljnvlehev 0 300 val
+sljprieitv 1 300 train
+sljpwcrwkn 1 300 train
+sljsmusjva 1 300 train
+sljudkvhjy 1 288 train
+sljvslcggd 1 301 train
+sljvxlngbn 1 300 train
+slkehjusli 1 300 train
+slkhnbrhja 1 300 train
+slkhwtlzio 1 298 train
+slkjexrmax 1 300 train
+slkkhfuojm 0 300 train
+slkmlgxvqg 0 301 train
+slkqbehdcq 1 300 val
+slkusnxxst 0 300 train
+slkxvzdonv 1 300 train
+slkznsanta 1 300 train
+sllftzipbi 1 300 train
+sllguadfon 0 300 train
+slljlqjygl 1 300 val
+slljlunhug 1 300 train
+sllndzvmea 1 300 train
+sllqhcykyz 0 300 train
+sllwodvjum 1 300 train
+slmambgymx 1 300 train
+slmfvbnowv 0 300 train
+slmsbwciib 1 300 train
+slmzmuivzm 1 300 train
+slncaditco 1 300 train
+slncbitmka 0 300 train
+slncowaxxr 1 300 train
+slnkiessak 0 300 train
+slnlvmukiz 1 300 train
+slnlvscqdq 1 300 train
+slnnsmbaja 1 300 train
+slnqsnpefc 1 300 train
+slnqupqyjj 1 300 train
+slnrvwkeaj 1 300 train
+slnunapipq 1 300 val
+slnvjmpqxh 1 300 val
+slnwzzepqz 1 300 test
+slnyhzkrea 0 300 val
+slodzfhvbo 1 300 val
+slolrzwatv 1 300 train
+sloltmctwu 1 300 train
+slopfaupds 1 300 train
+slorrtkzvs 1 300 train
+slovmtbagb 1 300 train
+slpduqrulv 1 297 val
+slpnmekswx 1 300 train
+slpofacjxs 1 300 train
+slppdghltj 1 300 train
+slpxqmwuqm 1 300 train
+slqdtwacdx 1 300 val
+slqosdknze 1 301 train
+slqruxxiau 1 300 train
+slraurmpjq 1 300 train
+slrcfsuqxw 1 298 train
+slrcshmwnj 1 300 train
+slreuysmqz 1 300 train
+slrfqkkyzu 1 300 val
+slrkzcngns 1 300 train
+slruxtzosd 1 300 train
+slrzqogyeq 1 300 train
+slrzwbijui 0 300 val
+slscvfvezw 0 300 val
+slsdljxgjy 1 300 train
+slsjdyqilt 1 269 train
+slskowjlax 1 300 train
+slsnfovqvr 1 301 val
+slspwcbiwf 1 300 train
+slswgcwncr 1 300 train
+slswuscdkx 1 300 train
+slsxfgywgf 1 300 train
+slsyjvgfpu 1 300 val
+slsyyhpujk 1 300 train
+slszaqrlte 1 300 train
+sltashfytm 1 300 val
+sltburykjp 1 300 train
+sltcgpngkd 1 301 train
+sltfpveqzb 1 300 train
+slticljueu 1 301 val
+sltqmzjfna 1 300 val
+sltqsbwufk 1 300 train
+sltuyhzwty 1 300 val
+sltwrisrjk 1 300 train
+sltwtdsuzt 1 302 train
+sltyddkiak 1 300 train
+slugbakrmk 1 300 train
+sluipdtmdh 0 300 train
+slulwkuggs 1 300 train
+slunrufbzp 1 300 train
+sluqtzpkey 1 147 train
+sluspabdog 1 300 val
+sluurkpwyj 1 241 train
+sluwywdyip 0 300 val
+sluxffkriw 1 301 train
+slvblqqhjy 1 300 train
+slvcfpalev 0 300 train
+slvfcfawvw 1 300 train
+slvfmkhsuf 0 300 train
+slvkfeutoe 1 300 train
+slvopguzil 1 300 train
+slvoufwdfy 1 300 val
+slvpusdkei 1 300 train
+slvtfdxsmd 1 300 test
+slvtflibjo 1 300 train
+slwgyldojb 1 300 train
+slwjervbni 0 300 train
+slwkikzaup 1 301 train
+slwkmefgde 0 300 train
+slwmoicemq 1 300 train
+slwnpiwesu 1 301 train
+slwzsvwbqz 1 300 train
+slxcuykodu 0 300 train
+slxdynmjqw 0 300 train
+slxeuszqnx 1 300 train
+slxotfovvb 1 299 val
+slxtreuuzd 0 300 train
+slyephfbjy 1 300 train
+slyfnpzvyh 1 301 train
+slysceozct 1 300 train
+slyseidalf 1 300 train
+slytjsmdcu 0 300 val
+slyyfctglt 1 300 train
+slzccfkgfc 0 300 val
+slzetbjxax 0 300 train
+slziswcgda 1 300 val
+slzjhbzfto 1 297 train
+slzmcnxjlf 1 300 val
+slzpmvafvy 1 300 train
+slzrqwkerw 0 300 train
+slzxxffrit 0 300 train
+smadtpgagb 1 300 train
+smafloqmot 1 300 train
+smafssewmu 1 99 train
+smahhtkiqd 0 300 train
+smaikulspm 1 300 train
+smaqccoqyt 1 300 train
+smautsszjs 1 288 train
+smaxkwvymf 1 300 train
+smbcuqtuvn 1 300 train
+smbgqxpuuz 0 300 train
+smblwrjdnn 1 300 train
+smbwklqmca 1 300 train
+smcaedowkf 1 193 train
+smcdowcbzj 1 300 test
+smcdunqkaw 1 300 val
+smcelxixcs 1 298 train
+smcgduwboh 1 300 train
+smchlpuqac 1 299 val
+smclyyspli 1 300 train
+smcuubkkig 1 300 train
+smcyybtwrp 0 300 val
+smdrewlpel 1 241 train
+smeawqunuq 1 300 train
+smehtpwbzy 0 300 train
+smeiiuzirr 1 300 val
+smemmrfxyd 1 300 train
+smeonozvfq 0 300 train
+smeqdbsroo 1 301 val
+smetiqozst 1 300 train
+smetziqkzr 1 299 train
+smeubiwvsa 1 300 test
+smevricgci 0 300 train
+smezfhfslk 1 300 val
+smfaajipno 1 298 train
+smfadvqqlu 1 300 train
+smfekouwyo 1 300 train
+smfszezifa 1 297 train
+smftfaeywi 1 300 train
+smgbohjurd 1 300 train
+smggzgxymo 0 300 train
+smgnhpxilr 1 300 train
+smgopungaj 0 300 train
+smgqfiyqyf 1 300 train
+smgrckcqpr 1 300 train
+smgupfkkjo 1 300 val
+smgweetqdr 1 300 train
+smhcigposo 1 300 test
+smhmwffveg 1 300 train
+smhnjxibov 0 300 val
+smhoenlupa 1 270 train
+smhxspbgfo 1 300 train
+smigbfmhew 0 299 val
+smigwcfxxf 1 300 train
+smihyqplin 1 300 val
+smilxcljmf 1 300 train
+smiqcstjwc 1 300 val
+smizbwuhgv 1 301 train
+smizuemaso 1 300 train
+smjbjprumz 1 300 train
+smjgzakyso 0 300 train
+smjhgdbuut 0 300 train
+smjnzdimqc 1 300 train
+smjvboszkd 1 301 train
+smjvgjlvzh 1 300 train
+smjzsungqs 1 300 val
+smkgnkexog 1 300 val
+smknnhxqpt 1 300 train
+smknvmxixt 1 239 train
+smkpttaqlr 1 300 train
+smkvfugdie 1 301 train
+smkvpdrleb 1 300 train
+smkxbyrcma 1 300 val
+smkxoeasyl 0 300 train
+smkxsgejze 1 300 val
+smleulbyxq 1 301 val
+smlitsmghh 1 300 val
+smlizabomm 1 300 train
+smljfzntha 1 300 train
+smljtxxrqu 1 300 train
+smlkevdmyi 1 300 val
+smlpdcchjd 1 249 train
+smlthcmbvz 0 300 train
+smmcswnvrx 1 300 train
+smmcvxizxg 1 300 train
+smmdunggfg 0 300 train
+smmgysaxvl 1 300 val
+smmgyubsuu 1 300 train
+smmhreaylg 1 300 train
+smmkselzwc 1 300 train
+smmncdmemv 1 300 train
+smmnmnkokw 1 300 train
+smmommoglu 1 300 train
+smmtcxrcxx 1 299 test
+smmtuigjgs 1 300 val
+smnqzesmsk 1 300 train
+smoajkkkew 1 300 train
+smoewvhyvv 1 300 train
+smofdllgft 1 301 train
+smovdpuhyc 1 300 train
+smowxigmfr 0 300 val
+smplgjukxl 0 300 train
+smpozqlbuo 1 300 train
+smprnjkbeg 1 300 train
+smpsaxbzeg 1 300 train
+smpspdupbh 0 300 train
+smptxlklxc 0 300 train
+smpumyohup 1 300 train
+smpzwkmmbe 1 300 train
+smqeusbudb 1 301 train
+smqhsbmfgf 1 300 val
+smqxlvnouf 1 300 train
+smrdjziwad 1 300 train
+smrfngvorp 1 300 train
+smsaywqpxm 1 300 train
+smsbhtftsy 1 300 train
+smscmlgwmc 1 301 train
+smsiqaqyer 0 300 train
+smsqmnkidm 1 299 val
+smstqzhdak 1 300 train
+smsxazmowk 1 300 val
+smtdgmffws 1 297 train
+smtdkyekma 0 300 train
+smthduyjzz 1 300 val
+smtjvqjcnf 1 300 train
+smtopnqeiw 1 300 train
+smtqniwxoi 0 300 val
+smtvfdewyn 1 300 train
+smuahbqhru 0 300 val
+smuaunviif 1 269 train
+smufbwvcnn 1 300 train
+smufipqjyy 1 300 val
+smuhnskvma 1 300 train
+smuktoevab 1 300 val
+smupitfsdm 1 300 test
+smuqemtlkj 1 298 train
+smuvptlacz 1 300 val
+smvgtbapvr 1 300 val
+smvrceazzw 1 300 val
+smvrstqifd 1 300 train
+smvyymdsdc 1 300 test
+smwdwrzsdo 1 300 val
+smwezpkhsn 0 300 train
+smwnoimfqu 0 300 train
+smwpthfdcd 1 300 val
+smwqziliaj 1 300 val
+smwscsfnul 1 300 val
+smwtoljkcd 1 300 train
+smwvziqtod 1 300 train
+smxeoqfzoj 1 300 train
+smxftvdptl 1 300 train
+smxhvrjiqk 0 300 train
+smxifhpxtv 1 300 train
+smxmfmyhiy 1 300 train
+smxqivzwed 1 300 val
+smxxhrcwlv 1 300 test
+smynsdcrki 1 300 val
+smypsdrfal 1 298 train
+smyyyyqrux 1 300 train
+smyzqjipcp 1 240 train
+smzgpdtyyj 1 300 train
+smzhfrjsim 1 240 train
+smzhsciwvu 1 298 val
+smzhxgppol 0 300 train
+smznmwyegn 1 300 train
+smzplltnou 0 300 val
+smztqqioaj 1 301 train
+smzttvqnrw 1 300 val
+smzvlamllt 1 299 train
+snacjldsed 1 300 train
+snaemhbcui 1 300 train
+snbayparzv 0 300 train
+snbdpbuaat 1 301 val
+snbjavluci 1 300 train
+snbnavovmy 0 300 train
+snbprwnjcr 0 300 train
+snbvolxdjb 1 300 val
+snbzzyhnpz 1 300 val
+sncbbupkok 1 300 train
+snchpqgwic 1 300 train
+sncsvwctqh 1 301 train
+sncvyenkxe 1 300 train
+sndgthpewi 1 300 train
+sndiwjhlaq 1 298 train
+sndmvzbufc 1 300 train
+sndsnqxmjh 1 299 test
+sndvvtyfwa 1 300 train
+sndxykdojj 0 300 val
+sndyekoyjj 1 301 val
+snedcfbkkd 1 300 val
+snehddaher 1 300 train
+snemobcacy 1 300 train
+snenbdxyaz 1 300 train
+snervnvqel 1 300 val
+snesygifla 0 300 train
+snevclcrkp 1 147 train
+snevsowlnx 1 300 train
+snfddvpzfx 1 300 train
+snfdzaqirq 1 300 train
+snfhwyymwg 1 300 train
+snfjxqyrec 0 300 train
+snflapfzge 0 300 train
+snfmmfmvvw 1 300 val
+snfpthhjqx 0 300 train
+snfpthikol 1 300 train
+snfqbkihqn 1 300 train
+sngafhoolv 0 300 train
+sngcdvisjk 0 300 train
+sngjsueuhs 1 299 test
+sngolnoxhz 1 300 val
+sngpalmpvs 1 300 val
+sngrwupyhb 1 301 val
+sngufxuual 1 300 train
+sngvajugzk 1 300 test
+sngykgnbke 1 300 train
+snhctdwvbo 1 300 train
+snheolxmzs 1 300 train
+snhjjbcqef 1 300 train
+snhlagfzql 1 300 train
+snhnuwzwms 1 301 train
+snhorjifjz 1 300 train
+snhqpfqbsf 1 300 train
+snhsvdcgpm 1 300 train
+snhzxkuuht 1 300 train
+sniadnofof 1 300 val
+sniatmheyt 1 298 val
+snibvogjja 1 300 train
+snicfpsbem 1 300 train
+snidmndycp 1 300 train
+snidpujjti 0 300 train
+snihjhcvvr 1 300 train
+snijmzqzux 0 300 train
+sniooxgfnk 1 300 train
+sniowpskgo 0 300 train
+snisbhcgqy 1 300 train
+sniuqkdsrc 1 300 train
+sniymrrysg 1 300 train
+snjcinquse 0 301 train
+snjflwmzhx 0 298 train
+snjgutkulg 1 300 train
+snjmfmpsch 1 300 train
+snjqmdldpy 1 298 train
+snjtedkhxu 1 300 train
+snjyuftxga 1 300 val
+snjzgkxvym 1 300 test
+snkcmwzpve 1 300 train
+snkpjieurz 1 300 train
+snkrtwndpc 1 300 train
+snkwzajnab 1 300 val
+snlfgymwqe 1 241 train
+snlgtdudja 1 241 train
+snlhedivvu 0 300 train
+snlhmitcwn 1 300 train
+snliqflqyq 1 300 train
+snlkormodl 1 300 train
+snlrwdhljz 0 300 train
+snlyjbnpgw 1 300 test
+snmcsqzqcs 0 300 train
+snmigurind 1 300 train
+snmylixxiu 1 300 train
+snmzmoioov 0 300 train
+snncqvivym 1 300 train
+snncubsfod 0 300 train
+snngihtdlw 1 300 train
+snnidbycuh 1 300 val
+snnimrntco 1 300 train
+snnipswsol 1 301 train
+snniqaamrb 1 300 train
+snnitkhvyu 1 300 train
+snnlkopjbd 1 249 train
+snnyhrnwdx 1 300 train
+snnzhpriji 1 300 train
+snnzxxhgtr 1 301 val
+snoddvdajq 1 300 val
+snodvycutq 0 300 train
+snodzzqisg 1 300 val
+snohkhuyoy 0 300 train
+snpatwskmo 1 240 train
+snpcazlcyc 1 241 train
+snpgkcbief 0 300 train
+snpgokjmba 0 300 train
+snphlfsrmr 1 299 test
+snphwtfljw 1 300 train
+snprgkehsa 1 301 train
+snpsaecisg 1 301 val
+snptbacegv 1 300 train
+snptsbcldf 0 300 train
+snqewjfxow 1 298 train
+snqflqhxeg 1 300 val
+snqfngvbqz 1 300 train
+snqnnpmdly 1 300 train
+snqogorujs 1 298 train
+snqppedaah 1 300 train
+snqpxfecxh 1 299 test
+snqseknzpx 0 239 train
+snrblxwbtr 0 300 val
+snrgbdpxag 1 300 train
+snrmqmqsfe 0 300 val
+snrpgvxncx 1 300 val
+snrvdywggj 1 300 train
+snryuwgzxr 1 300 train
+snsdcfvmrv 1 300 train
+snsgacnmvy 1 300 train
+snsgnxrygs 1 300 train
+snskjzblqd 0 300 train
+snsrdzneby 1 300 val
+snsvdgvlci 1 300 train
+sntgwappqq 1 301 val
+sntkppjpgm 1 301 train
+sntmobhnfe 1 298 val
+snttyfdjsu 0 300 train
+sntubdkzmu 1 300 train
+sntwdkhrjd 1 300 train
+sntwfqtrjd 0 300 val
+sntylrgopw 1 300 train
+sntzbpzfel 0 300 train
+snucmecdyr 1 300 train
+snugcdumnl 1 300 train
+snugrvjmoa 1 300 train
+snuiuqyklj 1 300 train
+snulkitgac 0 300 train
+snullhmfys 1 300 train
+snumpacvvq 1 300 train
+snupjxpwcy 1 300 train
+snuxbdurdj 0 300 val
+snuyygsxca 1 298 train
+snuznpiumj 1 300 train
+snvgdxhfkb 1 299 test
+snvqcwfxza 1 300 train
+snvradbnby 1 300 val
+snwguwrtcx 1 300 val
+snwhyjxgrr 1 300 train
+snwpumymjr 1 299 val
+snwvzbrgvg 1 300 val
+snwwydmiyh 1 300 val
+snwxfwcrtp 1 300 val
+snwzkbimkr 1 301 train
+snxejjcjkx 1 300 train
+snxhwllifz 1 300 train
+snxlrzfrtn 1 300 val
+snxmwwrful 1 300 train
+snxoijwuvx 1 300 train
+snxrffeexy 1 300 val
+snxsgonfsz 1 300 train
+snxtsblzqg 1 299 test
+snxujxluda 1 300 train
+snxxdmaxbx 1 300 train
+snxxlpcppu 1 298 train
+snyatxpeia 1 296 train
+snytnhgeqk 1 300 val
+snyxtagdrq 1 300 train
+snyyhjqyhi 1 301 train
+snyzrpusbn 1 300 test
+snzfbtmchf 0 300 train
+snzgrhwegl 1 300 train
+snzhayjobi 1 300 train
+snzimiaoih 0 300 train
+snzrkhxmze 1 300 val
+snzuymeeet 1 300 train
+snzwjacvkd 1 300 val
+snzyifwhot 1 300 train
+soadooqwcv 1 301 train
+soafivngii 1 300 train
+soahunbhux 1 300 train
+soamkgxcum 1 300 train
+soamslmipp 0 300 train
+soauthuntn 1 300 train
+sobblmyurt 0 300 train
+sobeauwqnk 1 300 train
+sobgfhhcam 1 300 train
+sobmdipgdv 1 300 train
+sobnwizvwl 1 300 train
+socandsxpw 1 300 train
+socbtjsjze 0 300 train
+socbvajuat 1 300 val
+sochasndqj 0 300 train
+sochqsfsow 1 300 test
+socnoafqic 1 300 val
+socvglqdgm 1 300 train
+sodgmndamq 1 300 train
+sodhrqqote 1 300 train
+sodmfozapk 1 300 val
+sodngshfey 0 300 train
+sodvtfqbpf 0 300 test
+sodyzppjga 1 301 val
+soeacmvrtf 1 300 train
+soeayaypqm 1 300 val
+soegooiqam 0 300 train
+soellqnrep 0 300 val
+soescagcut 1 300 train
+sofdiunesb 1 300 train
+sofgwqaoti 1 300 train
+sofkvgzlly 1 300 train
+soflilboqk 1 300 train
+sofsttmbpk 1 300 train
+sofyxjihrw 1 300 train
+sofyzbhjmr 1 300 val
+sogdryihob 1 297 train
+sogeignvip 1 300 val
+sogevtgfit 1 300 train
+soggolpqbu 1 300 train
+sogkvutgwu 1 300 train
+sogobxlkwg 1 300 train
+sogpjykjlz 1 300 train
+sogswysgnr 1 300 train
+sogvwbofhy 1 299 val
+sohaelcubd 1 300 train
+sohagbttyj 1 300 train
+sohbnjtoqe 1 298 train
+sohfaeuuzz 1 301 train
+sohfmjtldi 0 301 train
+sohnfiacxb 1 300 train
+sohspzcsrk 1 300 train
+sohugbvifm 1 300 val
+sohvhralvd 1 301 train
+soiiwyzmfe 0 300 train
+soiobgysrb 1 301 train
+soipgztqut 1 300 val
+soiutmwegq 1 300 train
+sojapnshoi 0 301 val
+sojicsvmej 1 301 train
+sojkpwixqw 1 240 val
+sojmzkusgb 1 300 train
+sojqdrftns 1 300 val
+sojqpmiatd 1 300 val
+sojwhvdqwx 1 300 train
+sojxeyjdat 0 300 val
+sojzehenkq 1 300 train
+sokaefmenf 1 300 train
+sokjtnswzn 1 300 val
+soklpfdyox 1 300 test
+sokneenxvu 0 301 train
+sokqvwhjwh 0 300 train
+soladmqunl 1 300 train
+solfesnwzd 1 301 train
+solgarzvhx 1 300 train
+solhpljwtu 1 300 train
+sollivjqqt 1 300 train
+solncvzbgn 1 300 val
+somlurimwl 0 300 train
+somqriispa 0 300 train
+somqvnqzjs 1 269 train
+somsivlcgy 1 298 train
+sondipaqyg 0 300 train
+soniarmsib 1 300 train
+sonqgysner 1 301 train
+sonrfhclyu 1 298 train
+sonxupdvru 1 300 train
+sooepnutvq 1 300 val
+sooilknojr 1 300 train
+sooiqetuqg 1 300 val
+soojfvqwmf 1 300 val
+sookyepgdl 1 250 train
+soomcfiiaz 1 300 train
+soovtjyzpb 1 299 val
+sopashzpkk 1 300 train
+sopdeyeakb 0 300 val
+sopjykbhjm 1 300 train
+sopmqwhfrn 1 300 train
+sopqhrhsma 1 299 val
+sopuwjzgpq 1 300 train
+soqhwplcpf 1 300 train
+soqiedyzhg 1 300 train
+soqxyqltcn 1 300 train
+sorfpwpscx 1 300 train
+sorhdrehkz 1 300 train
+sorhqukcgp 1 300 train
+sorlojolvz 0 300 val
+sorqmssglp 1 301 train
+sorrjervob 1 300 train
+sorvfvlhgb 1 300 train
+sorwnrzsuo 0 300 train
+sorwnwmejh 1 292 val
+sorxgzzrmg 1 300 train
+sosbijzxbb 1 300 val
+sosfyjcuji 1 298 train
+sosxvcbrri 1 300 train
+sotclwmskg 0 300 train
+sotfronkgb 0 300 train
+sotgjryjnc 1 300 train
+sotnhpckzq 1 300 train
+sotsxtxedq 1 300 train
+sotvrcxiao 1 300 train
+souczoeetc 1 300 train
+soudeaqdlg 1 300 test
+soufdnbsto 1 300 val
+soufokgujx 1 300 val
+souicmefpc 1 301 train
+souquoouds 0 300 train
+sovawuhact 1 300 val
+sovdhmmbmu 1 300 train
+soviruirve 1 300 val
+sovkehyqry 1 300 train
+sovmlursob 1 300 train
+sovmyqevnp 1 300 val
+sowargwatp 1 300 train
+sowbpouocc 1 300 train
+sowbynzlrt 0 301 train
+sowchioelh 0 300 train
+sowjdfscuo 1 300 train
+sowmxypmbs 1 300 train
+sownklshbw 1 300 val
+sowpchftkd 1 300 train
+sowuyjudky 0 300 val
+sowvbswgya 1 300 train
+sowvzhlcpe 1 298 train
+sowyyxkxvq 1 300 val
+soxglbothk 1 301 train
+soxmnfilyi 1 300 train
+soxnfsrdar 1 300 train
+soxqxxtiqn 1 300 train
+soydhxeajh 0 300 train
+soygcurude 1 300 train
+soyrktqznj 1 300 train
+soyvjikiic 1 298 train
+soyzipkfey 1 300 train
+sozipgnian 1 146 train
+sozoqczsux 1 302 val
+sozpcjmebz 1 300 train
+spaehtchns 1 300 val
+spajqkfaid 1 301 train
+spajtbokup 1 300 train
+spaobunymy 1 300 train
+spaqfombcd 1 300 train
+spastqbytw 1 300 train
+spatjqdfqh 1 300 val
+spauwchgct 1 300 train
+spbaoyrutx 1 300 val
+spbcnwldhk 1 300 val
+spbxiacqpx 1 300 train
+spbyxflmdh 1 294 train
+spccmwkksz 0 300 val
+spcdbvjeir 0 300 train
+spcdvnpooh 1 300 train
+spcjqcmwri 0 300 train
+spcmarknmw 1 300 val
+spcowtjevh 0 300 train
+spctohmrmd 1 288 train
+spczljorfm 1 300 train
+spdjblprnu 1 300 train
+spdkvaocut 0 300 train
+spdppsukju 1 300 val
+spedvhakxi 1 300 train
+spehwgtncu 0 300 train
+spejhxfqra 1 300 val
+spelnjjqqo 1 300 train
+sperdfbpta 0 300 train
+spetzyllrv 1 299 test
+spfbdwnnvk 1 300 train
+spffipltwo 1 300 train
+spflqgvyes 1 300 train
+spgfwdwkov 0 298 train
+spgmcfrisi 0 300 train
+spgrxmypmm 1 300 train
+spgyjitrvu 0 300 val
+spgyzeynsx 1 300 train
+spgzovqysj 0 300 val
+spgzygrabf 1 300 train
+sphirandia 1 300 test
+sphkchapom 1 300 train
+sphnoixvpx 1 300 train
+sphoakivij 1 300 val
+sphobivwkn 1 300 train
+sphshamkqc 0 300 train
+sphxantczl 0 300 train
+spiarzgony 0 300 train
+spicmqgvrw 1 300 val
+spigbvvxgf 0 300 train
+spikfbwnbs 1 300 train
+spilkqhfbq 1 300 train
+spislbxpxv 1 300 train
+spiupokylx 1 300 train
+spjhfgahuw 1 300 train
+spjlpgrvwg 1 300 train
+spjonmqfxl 1 300 train
+spjxtvkvjg 1 300 train
+spkapwbkqu 1 300 train
+spkgpjvbfh 1 300 train
+spkkvmcbmy 1 300 test
+spkopdnnkf 1 300 train
+spkorcenyh 1 300 train
+spkpmiozgf 1 300 train
+spkpqwhhdt 1 299 test
+spkupbhgih 1 300 train
+spkuzunuvn 1 301 val
+splcbaiaqw 1 300 val
+splpdkopjr 1 300 train
+splqjmdwzs 1 299 test
+splqoslhvk 1 300 train
+spmaajcmzg 1 300 train
+spmbdmwypu 1 300 train
+spmeekkana 0 300 train
+spmjurlnir 0 300 train
+spnaichhhe 1 300 train
+spncbnrbmt 1 301 train
+spngnyplne 1 299 val
+spnntlrfby 0 300 train
+spnpdtvuyr 1 300 train
+spnpqwmvdx 1 298 train
+spnuxxbcpk 1 296 train
+spnxpklfqd 1 300 train
+spnywzqwbd 0 300 train
+spnzabjyto 1 300 train
+spocnqkpnd 1 300 train
+spoeraobzx 1 300 train
+spoezekgpo 0 300 val
+sposxnzqtj 1 299 test
+spoushvthu 1 300 train
+spowjwzfha 1 300 train
+spoyuyihnp 1 300 train
+sppcmqfihc 1 300 train
+sppsaybdcr 1 301 train
+sppyyoqaey 0 300 val
+spqacwtaom 1 300 train
+spqaihffwm 1 300 train
+spqavtzigv 1 299 val
+spqcmedyou 1 300 val
+spqcomtvnr 1 300 train
+spqevczjku 1 300 train
+spqjmzvjtv 0 300 train
+spqngxffea 1 300 train
+spqqrjvrlf 1 300 train
+spqurdilom 1 300 train
+sprbzuxvns 1 300 train
+sprejlmapw 1 300 train
+sprenxdpqc 1 300 train
+sprkylblxq 1 298 train
+sprtqpixpt 0 300 train
+sprylmddah 1 300 train
+sprzdodinp 0 300 train
+spsaejhgsa 1 301 train
+spscjnjdsx 1 300 train
+spscubqzrl 1 300 train
+spsevdcrnu 0 301 train
+spswtgazix 1 300 train
+spsyaiylsd 1 241 train
+sptefjlzud 0 300 train
+sptgayzwjb 1 299 train
+sptqnpgeys 1 300 train
+sptqsljymy 1 300 train
+sptxbpmgdv 1 301 val
+spuhxqfzjv 1 301 train
+spuinvajyz 1 300 train
+spujmayfbp 1 301 train
+spukimfmxx 1 300 train
+spukysblyo 1 300 val
+spumxhysym 1 300 train
+spuuozrmxj 1 300 train
+spvcifnkbz 1 300 train
+spvdhwscww 1 301 train
+spvgqcprzb 1 300 train
+spvkgtkjvh 1 300 train
+spvwezgsru 1 300 train
+spvwlyhjil 0 300 train
+spvzwtearm 1 300 train
+spvzzqcqfg 1 298 train
+spwacsrgam 1 300 val
+spwdmzvbvx 1 300 train
+spwgrwvgah 1 300 train
+spwtacmqyy 1 300 train
+spwvgoafiz 1 301 train
+spxbbffqqf 0 300 val
+spxbtvgpjy 1 300 val
+spxialcvtc 1 298 val
+spxiebbmas 1 300 val
+spxnygtjqa 1 300 val
+spxpspfcwr 1 301 train
+spxqkpmopb 1 299 test
+spxsiabtfa 0 297 train
+spxwownsoy 1 302 train
+spxxmyrfud 1 300 val
+spxxylhqyh 1 300 val
+spxyhhnerj 1 300 val
+spxyvjkiso 1 300 val
+spyazeqqds 0 300 train
+spydvdxqkn 0 298 train
+spygsdrmsa 1 240 train
+spyksrxwuh 1 300 train
+spylpkmhwj 1 300 train
+spymllvajl 1 300 train
+spyophhesn 0 300 train
+spyqjhzpcy 0 300 train
+spytdimvtn 1 300 train
+spywfjcdga 1 300 val
+spyywqsozg 1 301 train
+spyzdfjgts 1 300 train
+spyzjkiczk 1 300 train
+spzchgewcf 0 300 train
+spzdrkbtol 1 300 train
+spzfqirkzv 1 300 val
+spzgqhdilk 1 300 train
+spzimtziqe 1 300 train
+spzmqugvtn 0 300 val
+spzmteogiy 1 300 train
+spznzscvui 0 300 train
+spzooclodg 1 300 train
+spzopxqmgv 1 300 val
+spzrkdkkte 0 300 train
+spztnzrbez 1 300 train
+spzvfdfmcl 1 300 train
+sqahewrssc 1 300 train
+sqanzrzyyf 1 300 train
+sqbbihqvaz 1 300 train
+sqbggtbiah 0 300 train
+sqbtnrfzzv 1 300 val
+sqbuqpxvtt 1 300 train
+sqbwiuyyia 1 300 train
+sqbyylskze 1 300 test
+sqbznsprnp 1 300 train
+sqccxaacys 1 300 train
+sqcjocxvqu 1 300 train
+sqcryidszu 1 300 train
+sqcyxtjrus 1 300 train
+sqdsuiwvpp 1 300 train
+sqdykqrxtb 1 300 train
+sqdzgiataz 0 301 train
+sqervywtri 1 300 train
+sqezxcsdhk 1 300 train
+sqfftygvgp 0 300 train
+sqfrjrrksa 1 300 train
+sqfthpaagj 1 299 train
+sqfwamivwy 1 300 val
+sqfzwnkpph 1 300 test
+sqgcpxhajx 1 300 train
+sqgiolaeah 0 300 train
+sqgotdyifo 1 300 train
+sqgtalzquj 1 300 train
+sqgvteugwr 0 300 train
+sqgwvkiesv 0 300 train
+sqhepmsden 1 301 train
+sqhjpqcnjv 1 300 train
+sqhmhmngzq 1 300 train
+sqhniznryi 1 300 train
+sqhodapoug 1 300 train
+sqhtbcpgtz 1 300 train
+sqhtgseatf 1 300 train
+sqhvaupsui 1 300 train
+sqhxvknkvb 1 300 train
+sqhzwhqthe 1 300 train
+sqichkhscx 1 300 train
+sqifmmoken 1 300 train
+sqifpgqbic 1 300 train
+sqijfardzw 1 300 train
+sqintuggou 1 300 train
+sqirhtxpzl 1 300 train
+sqiwlaezeo 1 300 train
+sqixhnilfm 1 300 test
+sqjeadluoe 1 300 train
+sqjkpdoavb 1 299 test
+sqjldjmhuz 1 300 train
+sqjttdaxnu 1 300 val
+sqjuzztmxk 1 300 train
+sqkdajiohh 1 300 val
+sqkgesaxlh 1 300 train
+sqkggobwqs 1 300 train
+sqklwyntht 1 300 train
+sqkozghvnp 1 300 train
+sqkpikvqqb 1 300 train
+sqkpimvjpe 1 300 train
+sqksmflehj 1 299 train
+sqksyseqmc 0 300 train
+sqladvmecy 0 300 train
+sqlgevuajy 1 300 train
+sqlipvvjgu 0 300 train
+sqlobantyy 0 300 train
+sqlorbbbgm 1 300 train
+sqlsmxzjfd 1 300 train
+sqmarjoyas 1 300 train
+sqmjhxebxu 1 300 val
+sqmocpagkn 0 300 train
+sqmsmxhbaz 0 299 train
+sqmtyvrism 1 300 train
+sqmvtmdteh 1 300 train
+sqmwdtpjlu 1 300 train
+sqnlfpydsm 1 300 train
+sqnllaanol 1 300 test
+sqnowaadwp 1 301 train
+sqnstcwydo 1 300 train
+sqnxedgabx 1 300 train
+sqnxpftnzf 1 300 train
+sqoamafahu 1 300 train
+sqoapfxtpk 1 300 train
+sqomlqiyem 1 300 train
+sqosxgtoqm 1 300 val
+sqozqdrbha 1 300 val
+sqpavwaegt 1 300 train
+sqpesceknr 1 300 train
+sqpevzmjpt 1 300 train
+sqpfmkepff 1 297 val
+sqpmdxxose 0 300 val
+sqprxjgzlr 1 300 test
+sqpulofcgo 1 300 train
+sqqamveljk 0 300 train
+sqqdxayvvu 1 300 train
+sqqgqnolwf 1 301 train
+sqqiqthefl 1 300 train
+sqqkeoppus 0 300 val
+sqqpkymhwc 1 300 train
+sqqvbosuab 1 300 val
+sqqzvxjviz 0 300 train
+sqragijyff 1 300 train
+sqrjoqavds 1 300 val
+sqrlmwoknq 1 300 test
+sqrmytpmcm 1 300 train
+sqroobfhid 1 300 val
+sqryfxcvii 1 300 train
+sqsaiehvhb 0 300 val
+sqsbuaptuj 1 300 train
+sqsgpkjdoo 1 300 train
+sqshjultyi 1 241 train
+sqsiohuulc 1 300 train
+sqsmqmegae 1 300 train
+sqsokfhyia 0 288 train
+sqspjnqhun 1 300 val
+sqsrcvdxwb 1 300 train
+sqsriogsbn 1 300 train
+sqsufyhscy 1 300 train
+sqsvvxlsdm 1 300 train
+sqsxyvqjdq 1 302 val
+sqtbxsgmxj 1 300 train
+sqtcjhbmjs 1 300 train
+sqthspwhai 1 302 train
+sqtkloneup 0 300 val
+sqtolgjqgy 1 300 train
+sqtpcavnyr 1 300 val
+sqtqgpbsov 0 241 train
+sqtujfkdfd 1 301 train
+sqtujxaxig 1 300 train
+squhndfeey 1 300 train
+squknlkemc 0 300 val
+squprvznij 1 300 train
+squxcnsyam 1 300 train
+sqvbqmwvoh 1 300 train
+sqvdvxwbkj 1 300 train
+sqveqjjxlh 1 300 train
+sqvgxxktht 1 300 train
+sqvijifncv 0 300 val
+sqvstmunit 1 300 train
+sqvwastbho 1 300 train
+sqwbentvzg 0 300 train
+sqwhlwtlxc 1 300 val
+sqwihacezb 1 300 train
+sqwsvdwpgu 1 300 val
+sqwvfgwdxr 0 300 train
+sqxalszicr 1 300 train
+sqxbonnndg 1 300 train
+sqxddvctyt 1 300 val
+sqxseogvrh 0 241 train
+sqxucdsdnx 1 298 val
+sqxylnymep 1 300 train
+sqybetzlkm 1 300 train
+sqycbtcwxw 1 300 train
+sqydryzuqz 1 241 train
+sqyoiesevc 1 301 train
+sqyrsilnrw 1 300 val
+sqyvwvexrr 1 300 train
+sqyvzzmimv 1 300 train
+sqyyclnwas 0 300 train
+sqyznyderl 1 300 train
+sqzembikvw 0 300 train
+sqzftmjbks 1 300 train
+sqznwaczgz 1 300 val
+sqzsoazaws 1 300 val
+sqztemxfte 0 300 train
+sqzweanhbw 1 300 train
+sqzyhhhgii 1 300 train
+sqzyucpnva 1 301 train
+sqzzafvbxy 0 300 train
+sradvolkvk 1 300 train
+sraekvrxks 1 298 train
+sragfwuxey 1 299 val
+srajwayono 1 300 train
+srarjnnewc 1 300 train
+srasjjgbwq 1 301 train
+srawpiehbc 1 300 train
+sraxtldzwp 1 300 val
+srbadqgjti 1 300 train
+srbddtbigw 1 300 train
+srbefnrtzx 0 300 val
+srbhgozyca 1 300 val
+srbiwebhac 1 300 val
+srbperijhe 1 300 val
+srbrnievwy 1 299 train
+srbvyvchmm 1 300 train
+srchyjeepi 1 300 train
+srcmouvnva 1 300 train
+srcohkaswn 1 300 train
+srcrilemvy 1 300 train
+srcsmdogkp 1 300 train
+srcznqjdzt 1 241 train
+srdbiykeja 1 301 train
+srdimtqpip 0 300 train
+srdpkrzyew 1 300 train
+srdrsrbfzj 1 300 train
+sreffgmknl 1 300 train
+srehmodygj 1 300 val
+sreiqrloia 1 300 train
+srejaytuwg 1 300 train
+sresxnmbxr 1 300 train
+srewbbqyas 1 300 train
+sreyrldfki 1 300 train
+sreztdckbi 1 300 val
+srfaqcxnea 1 300 train
+srfcivkxpc 1 241 train
+srfefmyjvt 0 300 test
+srfptlpwyr 1 300 train
+srftfzaabl 1 300 train
+srfvwcbegl 1 300 train
+srfwfcobzh 1 300 val
+srfxdqschx 1 299 train
+srfxuowskr 1 241 train
+srgbuihjgq 1 301 train
+srgbxbqkjq 1 300 train
+srglkowbrs 1 299 test
+srhntssrpx 1 300 train
+srhqpympak 1 301 train
+srhrarlmco 1 300 train
+srhulryoad 1 300 train
+srhwnvdhfh 1 300 train
+sricfzqjtp 1 300 train
+sriguouosg 1 300 train
+srimpkigup 1 300 train
+srioayxizs 1 300 train
+srioodmtmm 1 300 train
+srirkcysce 1 301 train
+srjaoppiqr 1 300 train
+srjcgwuhdc 1 300 train
+srjdthfwvw 1 240 val
+srjkmsfwin 1 300 train
+srjlbeyoig 0 300 val
+srjoihwtrj 1 300 train
+srjpfgdbfi 1 300 train
+srjwopuhes 1 300 train
+srkhkdnule 0 300 train
+srkihxqjkl 1 300 val
+srkqfhyhjf 1 300 train
+srkrptntea 1 300 val
+srkxvsdvdn 1 300 train
+srlbhqggbu 0 300 train
+srlilcjhaf 1 300 train
+srlkweialw 1 300 val
+srlnuziqxc 1 239 train
+srlscwjgzb 1 241 train
+srlxpizuxs 1 300 train
+srlxrlvpbk 1 300 val
+srmfnqhfxp 1 300 train
+srmgprspip 1 300 val
+srmsbgbeqi 0 300 train
+srnavvtcjb 1 300 train
+srncaxcnfm 0 300 val
+srnehgnrgq 1 300 train
+srnjwggrnt 0 301 train
+srnseorykn 1 300 test
+srnuhjbzaw 0 300 train
+srnwomifzx 1 300 train
+sropalvwuy 1 298 train
+sropiogmvg 1 300 train
+sropjlupxe 1 300 train
+sropxiectt 1 300 train
+srouowsbee 1 298 train
+sroyseyftn 1 300 train
+srpasrmgxw 1 300 train
+srpehzessc 0 300 train
+srphznkrel 1 299 test
+srpqrfwevg 1 300 train
+srpracqqgk 1 300 train
+srpujcksbj 1 600 train
+srpvgysqdx 1 300 train
+srpwbbiwby 1 300 train
+srqdeqtxmw 1 300 train
+srqdmcnjef 1 300 train
+srqkmuobpy 0 300 train
+srqmozosdx 1 300 train
+srqmqibqed 1 300 train
+srqogltgnx 1 299 train
+srrhsfcpcr 0 300 val
+srrjkxkhcw 1 300 train
+srrpgenajv 1 300 train
+srrtsgtkip 1 300 train
+srruzmpcpz 1 300 train
+srrxfjszab 0 300 val
+srryqnqdaz 1 300 train
+srsadmspmy 1 300 train
+srsaxaghht 1 300 train
+srscvsfyei 1 300 train
+srsfrucugn 1 300 train
+srskjjvwfm 1 300 val
+srstmgqgwo 1 300 train
+srsustslnp 1 300 train
+srsvdvzklt 0 300 train
+srtaopsdrc 1 300 train
+srtltundmp 0 300 train
+srtquminoi 1 300 train
+srtwhbzzlr 1 300 train
+srtwszxrqc 0 300 train
+srugqqiuoh 1 300 val
+sruhfgdvrx 1 298 val
+srvavlvfpa 1 300 train
+srvcxmdamn 1 300 train
+srveziyvay 1 300 val
+srvgozezdn 0 300 train
+srvhuhutfg 1 300 val
+srvkzbpbnx 1 300 train
+srvsajrtth 1 301 train
+srvsqdcekm 1 300 train
+srvunlalon 1 136 train
+srvuuxphtl 1 288 train
+srwhyjhklf 1 301 train
+srwiwctzng 1 300 train
+srwiwzblep 1 300 train
+srwkomwenu 1 241 train
+srwlkrwzeb 1 300 train
+srwvyfmwso 1 300 train
+srwzavkija 1 300 train
+srxgfofvyv 1 298 train
+srxheyjdwt 1 300 train
+srxigfckvw 1 300 train
+srxlegrhly 1 300 train
+srxpdlixap 1 300 train
+srxtjrlbma 1 300 train
+sryaeqwufs 1 300 train
+srycweyhir 0 300 train
+srydhkepnz 1 300 train
+sryifhhmtd 1 300 val
+srymsyxwjv 1 300 train
+srypjdjezl 0 300 train
+sryzapzbbw 1 300 val
+srzatvffqu 1 300 train
+srzfnmwicz 1 301 train
+srzjrzezkq 1 300 train
+srzmayhxen 1 300 train
+srznelhtoq 1 298 train
+srzobeaavr 1 241 train
+srzrquplty 0 300 train
+srzttvcofx 1 300 train
+ssaosooadl 1 301 val
+ssaurmoabv 1 300 val
+ssavajveue 1 300 train
+ssawqvthzf 1 300 val
+ssbasvsptd 1 298 train
+ssbdlgbjrj 1 300 train
+ssbdqcpqbk 0 300 train
+ssbhgciwrt 1 300 val
+ssbjlmmeku 1 300 train
+ssbljyptyd 0 300 val
+ssbotgnhqb 1 301 train
+ssbqitgiil 1 99 train
+ssbqszxmhm 1 300 val
+ssbvmxqbyt 1 241 train
+ssbzegnbzw 1 300 train
+ssbzkbrcto 1 300 train
+ssbzojpgir 0 300 train
+sscbgwhmru 1 300 train
+sscgkwyzbb 1 300 train
+sscrakrzom 0 300 val
+sscwoazjdt 1 300 val
+sscxyjmztv 1 300 train
+ssdhtytbih 1 300 train
+sseaemazyk 1 300 train
+ssebqpbtir 1 300 train
+sseiywleli 1 298 train
+ssemlzkapm 1 301 train
+ssemnsvhuy 1 300 train
+sserarlpip 1 301 train
+sseuygjksk 1 241 train
+ssezlzrlwn 1 300 train
+ssezvngwjh 1 298 val
+ssfaxjwths 0 300 train
+ssfayqyaxs 1 300 train
+ssfmqvniia 1 294 train
+ssfpcwfyxf 1 300 train
+ssfrpxjrsm 0 302 train
+ssfrqmkeoo 1 300 train
+ssfscsquns 1 300 train
+ssfsudlhcc 0 300 train
+ssgitjfqku 1 300 train
+ssgyxrhpse 0 300 train
+sshmcxojgw 1 300 val
+ssicmhswvf 0 300 train
+ssicvpawtz 1 300 train
+ssiirtzxja 1 300 val
+ssitlrruir 1 300 train
+ssizsnovcj 1 300 val
+ssjizrjnzu 1 300 train
+ssjpjlkdtm 1 300 train
+ssjpogjprj 1 300 val
+sskcskyxls 1 300 train
+sskgrzvqhk 1 300 val
+sskhkmsrxi 0 301 val
+sskiuzcenz 0 300 train
+sskrmxktha 1 300 val
+ssktcfblwf 1 300 val
+sskuuyfrmu 1 300 train
+sslewqhhmm 1 300 val
+sslobhtwdy 1 300 train
+sslpdxghbf 1 300 train
+sslrtrxyaj 1 300 train
+sslsctgqve 1 300 train
+ssluyhpcqp 1 300 train
+sslvbfnxbh 1 300 train
+sslxctsvjk 1 300 train
+ssmawzklfe 0 300 train
+ssmbknypsx 1 241 train
+ssmbpqrjug 1 300 train
+ssmftrmalz 1 300 train
+ssmmwwfelv 1 300 train
+ssmpmogtsg 1 299 test
+ssmsaqcwou 1 300 train
+ssnbbtmgpw 0 300 train
+ssnbwxewyl 0 298 train
+ssngqzuzig 1 300 train
+ssnpuwzixz 1 300 train
+ssnszxdrrq 1 301 train
+ssnzbiomhq 1 300 train
+ssnzokeckc 1 300 train
+ssogfzhjyl 1 300 train
+ssoranznrw 0 300 train
+ssoutkswgl 1 300 train
+ssouvrkjhl 0 300 train
+ssovnbhhid 1 300 train
+ssoxfnoygp 1 300 train
+ssoyfcbatv 0 300 val
+sspgnufmlo 1 300 train
+sspgsqwcdr 1 300 train
+ssplazhosb 1 300 train
+sspmcrfofz 1 292 train
+sspmqvcejh 1 300 train
+ssqfyxrubc 1 300 train
+ssqgmwdtvb 0 300 train
+ssqjfnjsjj 1 300 val
+ssqjunefvw 1 300 train
+ssqpuzwjsg 1 300 train
+ssqzjuhylc 0 300 train
+ssqzyrzhkc 1 300 train
+ssrccxncxi 0 300 train
+ssrnztvqbz 1 300 train
+ssrurhueaa 1 300 val
+ssryaazgjv 1 300 train
+ssrztvkhdi 1 239 train
+sssdmzihea 1 300 train
+sssfttnfam 0 300 train
+sssnifqueh 1 300 train
+sssrdjzftr 1 300 train
+sssrdltekp 1 300 train
+sssuagsvfl 0 300 val
+ssttgbbvni 1 300 train
+sstvwnobdt 1 241 train
+ssuabvqzpr 1 300 train
+ssumpmrbdi 0 300 train
+ssutaxtotc 1 300 val
+ssuteaoloo 1 299 test
+ssuxrxhshr 0 300 val
+ssuztxupnh 1 300 train
+ssvapactsv 1 300 train
+ssvcjgwrdh 1 300 val
+ssvfzufcpw 1 297 train
+ssvkjlmsrj 1 300 train
+ssvkrewrjc 1 300 train
+ssvnaeilqm 0 300 train
+ssvumjrcop 1 300 train
+ssvwugigpz 1 300 val
+ssvxlljvij 1 298 train
+sswasyoxlg 1 300 train
+sswbgeyxmx 0 300 train
+sswccbiann 1 241 train
+sswhgeqjrt 0 300 train
+sswhprisha 0 300 train
+sswnqnmdub 1 300 train
+sswydvaojs 1 300 train
+sswzkumown 1 300 val
+ssxaalchup 1 300 train
+ssxiuiksqx 1 300 train
+ssxjtjxext 1 298 train
+ssxkxouavr 1 300 train
+ssxnvxdpur 1 300 train
+ssxqypkahm 1 300 train
+ssxwzxmmzc 1 300 train
+ssxxpkjhlc 1 300 val
+ssxyggaqxc 1 300 train
+ssyaqyuyxa 1 300 val
+ssybniuhhz 1 300 val
+ssycivenqc 1 301 val
+ssyfgvngrn 1 301 train
+ssyfvhmlao 1 300 val
+ssyhelvzlp 1 298 train
+ssyhvijfrd 1 300 train
+ssyjzobteu 1 300 train
+ssymxnbxhp 0 300 train
+ssyochxeeq 1 298 train
+ssyqrcivva 1 300 train
+ssyrhuudhz 1 300 val
+sszgrmcubw 1 300 train
+sszsfzqqot 1 300 val
+ssztffswml 1 301 train
+sszvuoxyuc 1 300 train
+staahqyjsa 1 300 test
+stamaaoxht 1 300 train
+staqnjvhzm 1 601 train
+staxevrzkb 1 300 train
+staykvhzvl 1 300 train
+stbgmbcqid 1 300 train
+stcgajjaez 1 298 train
+stcizoyeyn 1 300 val
+stcuuehqbq 0 300 val
+stdavraahk 0 300 train
+stdgophtxj 1 300 train
+stdjzkahan 1 300 train
+stdsxxbsjo 1 300 train
+stdwultbku 0 300 train
+steejfstvp 1 300 train
+stefgytblq 1 301 val
+stefyhkjdg 1 300 train
+stehhhvplr 1 300 train
+stejepgobs 1 299 train
+steoxyqjkp 1 300 train
+steqjxorfa 1 300 test
+stesvfctgg 1 300 val
+stfcspyrqy 1 300 val
+stfpzieill 1 300 train
+stfqbsbvfy 1 300 train
+stfsoattfs 1 300 train
+stfsomwoie 0 300 train
+stftfbmdgu 0 300 val
+stgawazdze 1 300 train
+stglxrxdcl 1 300 train
+stgusxhcta 1 300 test
+stgusymtgn 1 300 train
+stgwaadvip 1 300 val
+stgweqepva 1 300 train
+stgxrclxzq 1 300 train
+stgzugxypy 1 300 train
+sthdieiufh 1 300 train
+sthjxgskpg 0 300 train
+sthmsqixqq 1 300 train
+sthrrkxksy 1 300 val
+sthyysvjlf 0 300 train
+sthzjvunwn 1 299 train
+stidkgkvvc 1 300 train
+stijlkexgv 1 300 train
+stiqdmkzmq 1 288 train
+stivhlfwrb 1 300 train
+stixwmpppk 0 300 train
+stiybgdukf 1 301 train
+stjcaikbkq 1 300 train
+stjkwveloq 1 300 train
+stjlezvnfz 1 300 train
+stkajdftlo 1 301 val
+stkkrejciq 0 300 train
+stkpxhkclf 0 300 train
+stkqpavaxn 1 300 train
+stkwvpiswg 1 300 train
+stkxixvyub 1 300 train
+stkygawqaf 1 298 train
+stkyigunrb 1 297 train
+stlauqpnej 1 300 val
+stldzhoszg 1 300 train
+stlqgxcmsp 1 300 val
+stlqpfqbcw 1 300 train
+stlrzhsqfx 1 300 val
+stluozsggc 0 300 val
+stmblasavv 0 300 train
+stmlgebdbu 1 300 train
+stmlldzdyn 0 298 train
+stmmmyhjxl 1 300 val
+stmngqbffj 1 300 val
+stmoslhmvt 1 300 train
+stmqeciblm 1 300 train
+stmqpsakem 1 300 train
+stmwtebvpy 0 300 train
+stnaintcgr 1 300 train
+stnccawemg 1 300 train
+stnjfezcjk 1 296 val
+stnrhtlyur 1 294 train
+stnzgohfcf 1 300 train
+stnzqffhax 1 298 train
+stnzxqrspy 0 300 train
+stodmioasm 1 300 val
+stojmeodpd 1 300 val
+stokwravll 1 297 val
+stomlgohed 1 300 val
+stomqqpyct 1 300 val
+stopgeenru 1 300 train
+stotyptnow 1 300 train
+stowugnqcq 1 300 train
+stpfxqeuiw 1 300 val
+stpjxyxagl 1 300 train
+stprvhmezo 0 300 val
+stqcnfwzrv 0 300 val
+stqfvfnoyd 1 300 train
+stqgwfdknf 1 300 train
+stqifjbqsh 1 300 train
+stqkltbfvp 1 300 train
+stqmyincfr 1 300 train
+stqocivpmv 1 300 train
+stqqcwjqsz 1 299 test
+stqvudqrdo 1 300 train
+stqwthojeb 1 300 val
+strakkcymp 1 300 train
+strqdkvswm 1 300 train
+stsgwlujmx 1 300 train
+stsqvujmwd 0 300 train
+stsyzvrerh 1 300 train
+stteqjblgs 1 301 train
+sttgmrqpec 1 300 train
+sttjoqcsec 0 300 train
+sttjzwvvnu 1 300 train
+sttnfyptum 0 300 test
+sttoamngtq 0 301 train
+sttoxniflx 1 300 train
+sttqvlsnnr 1 241 train
+sttumnzaws 1 300 train
+sttvaacmgj 1 298 train
+stuaqjvnsx 1 300 train
+stupenpbvv 1 288 train
+stvapkvuyd 1 300 train
+stvbfigxqp 1 300 train
+stvesebljc 0 300 val
+stvheugtad 1 300 val
+stviurptyt 1 298 train
+stvrwpfufa 1 300 train
+stvvxdlfhv 1 301 train
+stvxyplryd 1 301 train
+stvyycybmb 0 300 train
+stwatdvfop 1 300 train
+stwaypekwh 0 300 train
+stwbygpliy 1 300 train
+stwccynisc 1 301 train
+stwdgrdnwi 1 301 train
+stwirivyvc 1 298 val
+stwsvtbegi 1 300 train
+stwuxnskas 1 300 train
+stwviayefj 1 300 train
+stwvmpdodl 1 300 val
+stxbwphgyj 1 300 val
+stxdmclohu 1 300 val
+stxgnkoqqt 1 300 train
+stxgskflmk 0 300 train
+stxnpttwka 1 300 train
+stxpjcspgw 1 300 train
+stxrwzuxte 1 299 train
+stxsbgkham 1 300 train
+stybihvfba 0 300 train
+stycrlveli 1 300 val
+styekjjbpd 1 300 train
+styfekwufb 1 300 train
+styhzwgwxp 1 300 train
+stylanuirx 0 301 val
+stylurlpxy 1 300 train
+styopusbgb 1 300 train
+styrkhiknj 1 300 train
+stysfprtdg 0 301 val
+styudvyezj 1 300 val
+styxylilce 1 300 val
+stzaqxktvl 1 300 train
+stzdrzizpq 1 300 train
+stzjetaupj 0 300 train
+stzkqbnqbc 0 300 val
+stzvkplrrg 1 300 train
+stzvmyitmu 1 300 train
+stzzoaktpw 1 300 train
+suanoccymg 1 300 train
+suarqbllge 1 300 train
+suazhhjuky 1 300 train
+subsaavowk 1 300 train
+succfegxfv 1 300 test
+sucgkfwhvt 0 300 train
+sucgswubji 1 300 train
+sucjfdrehz 1 300 train
+sucjotwrhv 1 300 train
+sucssjqjph 1 301 train
+sucvktxvir 1 300 train
+sucvrlazkp 1 300 train
+sucwanurae 1 300 val
+sudcddyfsc 1 300 train
+sudclpklts 1 300 val
+sudhffrwig 0 300 train
+sudpphwcnr 1 300 train
+sudsuffzhj 1 300 train
+sudsxgrwba 0 300 train
+sudzolvppu 0 300 train
+suegfrmmtl 0 300 train
+suekqxrbni 1 300 train
+sueliyoptm 1 301 val
+suemlhslqm 0 300 train
+suenouugfr 0 300 val
+sueqhgzpyn 1 300 val
+suernepbnb 1 300 train
+suevsrwyrq 0 300 val
+suewtvvdrr 1 300 train
+sufadfttzf 1 300 train
+sufgpikzsg 0 300 train
+suficmeiul 1 302 val
+sufjxebsut 1 300 train
+sufprsunbs 1 300 train
+sufujtnmxd 0 300 train
+sufvvwmbha 1 300 test
+sufwnxoxug 0 300 train
+sufwtyllre 0 300 train
+sugawhoyju 1 300 train
+sugbbeyefi 1 300 train
+sugcicasle 1 300 train
+suggnfynol 1 300 train
+sughvclwur 1 300 train
+suglpnnlng 1 300 train
+sugnrpmemc 1 300 train
+sugshhjwsn 1 300 val
+suheohirvj 1 300 train
+suhinrieua 1 300 train
+suhuilfonk 1 300 train
+suhutttxhd 1 300 train
+suhxkqfseh 1 300 train
+suiacorobv 1 301 val
+suicnzjtcc 1 300 train
+suidwxiyzu 1 300 train
+suifcffkyo 1 301 train
+suigngiafa 1 300 train
+suihcprceb 1 301 train
+suijwzeikj 1 300 val
+suikcitbln 1 300 train
+suiowjkvul 1 300 train
+suiusgvsut 1 300 train
+suixjnubqo 1 300 train
+suiznrogks 1 302 train
+sujafsfzdc 0 300 val
+sujfmmgvju 1 300 train
+sujgbwtdks 1 300 train
+sujhhjvsym 1 241 train
+sujpsdbziz 1 300 train
+sujslfzmqk 1 300 train
+sujubydrja 1 300 val
+sujulahsjs 0 300 train
+sujzalcsvb 1 300 train
+sukfcvwfmy 1 301 train
+sukkonkuvi 1 300 train
+sukoopilqp 0 300 val
+suktswviha 1 300 train
+suktzgdetv 0 300 train
+sukxejbmto 1 300 val
+sukzzxgxvh 1 300 val
+suleggscox 0 300 train
+suljkkkfwc 1 300 val
+sulunwrzam 1 300 train
+sulvpuytgx 1 301 train
+sulwtygonw 1 300 train
+sulxgycexe 1 300 train
+sulxhhojjg 1 300 train
+sumbcarbbh 1 300 train
+sumqqmntul 1 300 train
+sumxixcxfu 0 300 train
+sumyrohudh 1 300 train
+sunabqifhp 1 300 train
+sunaztywbr 1 300 train
+sungfkwncc 1 301 train
+sunhsuzfwg 1 300 val
+sunkssxdme 1 300 train
+sunktvavrh 1 300 train
+sunqpocnyf 0 300 train
+sunqwnmlkx 0 300 train
+sunvohtvef 1 300 train
+sunzloiilo 1 300 val
+sunzusmigx 1 300 train
+suohhqgqsn 1 301 train
+suohrphvbe 1 300 train
+suohvxwqcy 0 300 train
+suoiuztczl 1 300 val
+suonegpsou 1 300 val
+suopbmsrdo 1 300 train
+suorsqvfau 1 300 train
+suorubswku 1 300 train
+suosinpxee 1 300 train
+suovfgnpev 1 300 val
+suoxjwxvpj 1 298 train
+suoxoyvdhh 1 300 train
+suoxrhzujc 0 300 train
+supitghuyy 1 300 train
+supjelpakj 1 300 train
+supjothycq 1 301 train
+supmyuhdsh 1 300 train
+supnlwjoxr 1 300 val
+supqrijixd 0 301 val
+supvbwapej 0 300 train
+supzxjddnc 1 300 train
+suqjzjwxvv 1 300 val
+suqoloibni 1 300 train
+suqspoqkuf 1 300 train
+suracgxmob 1 300 test
+surcmsyrlz 1 300 test
+surdndtyhp 1 300 train
+surdxjcesz 1 300 train
+surgivccgr 1 300 train
+surihbpbeg 1 300 train
+surnrvfnae 1 300 train
+surqcuurvj 1 301 train
+surrxdndti 1 300 train
+sursqqaznx 1 300 train
+survauoxpg 0 300 val
+surwoyeyjg 1 300 train
+surxrjjvfg 1 300 train
+susbqdbdij 0 294 train
+susdceyusi 1 300 train
+susggomzdn 1 300 train
+susuxqxbwm 1 300 train
+suszmfospy 1 298 train
+sutbvdbrxc 0 300 train
+sutlgxydvi 0 300 train
+sutngsgwcm 1 300 train
+sutpvknvml 1 300 val
+sutxeagjoo 1 300 train
+sutyzrbiqc 1 300 train
+suujykbbdx 1 300 train
+suunedqyxl 1 300 train
+suuohkqlkb 1 300 train
+suuozdgqgv 1 300 train
+suurdgtysl 1 300 val
+suuvjyupkt 1 300 val
+suuwxsmivn 1 300 train
+suuxeiqhho 0 300 val
+suviwtawno 0 300 val
+suvpaxhsqc 1 300 val
+suvpcafidl 1 241 train
+suvpooovtn 1 301 train
+suvuclrwbk 1 300 train
+suvvyowajw 1 300 train
+suwioqfhdm 1 300 train
+suwndzsylo 1 300 train
+suwqjazdtb 1 300 train
+suwvxhuewq 1 288 train
+suwwmmypru 1 300 val
+suwyxotzab 1 300 train
+suwzujipxd 1 241 train
+suwzyuufnn 1 300 train
+suxbyottif 1 300 train
+suxevtqmyb 1 300 train
+suxhgeshgd 1 167 train
+suxlwssckc 1 300 train
+suxngkmisr 1 300 val
+suxxfvbhlq 1 288 train
+suybcasguz 0 300 val
+suyblxyyhc 1 300 train
+suyejqggns 1 300 train
+suyifljldl 1 299 train
+suyjqrvoon 1 300 train
+suyvzrnihk 1 300 train
+suzambwnee 0 300 train
+suzeugzqjq 1 300 train
+suzowftflr 0 300 val
+suzswficla 1 300 val
+svaewiqlis 1 298 train
+svafvyukgb 0 300 train
+svasalmzid 1 300 train
+svawbdbowf 1 300 train
+svayozshlw 1 300 train
+svaytnurer 0 300 val
+svbcewtjvh 1 300 train
+svbdiucoph 1 300 train
+svbpedufqq 1 300 train
+svbtmlmodg 1 300 train
+svbxaggedm 1 300 train
+svceswtcda 1 300 val
+svcfbpxpjp 1 300 train
+svcnlasmeh 0 300 train
+svctvggabk 1 298 train
+svcuacwiwg 1 300 train
+svcwwctrlb 1 300 val
+svcyfvpoxo 0 300 train
+svczsyaksm 1 300 train
+svcztvpdxp 1 301 val
+svdfdjduru 1 300 train
+svdgknyyay 0 300 train
+svdiiejtvh 0 300 train
+svdjmhpwnb 0 300 train
+svdkrljwzp 1 300 train
+svdlbqqjlf 1 300 train
+svdpcjxzik 1 300 train
+svduthpfjd 1 300 train
+svdwmdvifm 1 300 val
+svdzgbnpjj 1 300 train
+svebeiuqjl 1 301 val
+svehemyhnb 1 300 train
+svehewpgdc 1 300 val
+svejwletic 1 300 train
+svekmurpps 1 301 train
+svemdbepfv 1 300 train
+svezjnrwrg 1 241 train
+svfecjdcxx 1 300 train
+svfepnwwlc 1 300 train
+svffkeeouu 1 300 train
+svfiqxdqjo 1 297 train
+svfmehxhnp 1 300 train
+svfpfpafrw 1 300 val
+svfqtrjljs 1 300 train
+svfxtdzvtv 1 300 train
+svgbkdyrln 1 300 train
+svgcaikqez 0 300 train
+svgckjdrur 1 300 train
+svggomahgg 1 300 train
+svgjmmhwil 0 298 val
+svgkbslfwv 1 300 val
+svgklmijgk 1 300 val
+svglcqlxpw 0 300 val
+svgmvhhztq 1 300 train
+svgngeewwx 1 241 train
+svgtieoevd 1 300 train
+svgusrintk 1 300 val
+svguwviycd 0 300 val
+svhamkfnya 1 300 train
+svhargnxez 1 300 train
+svhbigxvzx 1 300 train
+svhdxvtmin 1 301 val
+svhekmfapg 1 300 val
+svhfxjlmov 1 300 train
+svhjgopnmn 1 300 train
+svhmadwanz 1 300 train
+svhowkluuv 1 300 train
+svhskhpjde 1 300 train
+svhyndcsyj 1 241 train
+svibevdrjz 1 300 train
+sviexytuuo 1 300 val
+sviiiofzvi 1 300 val
+svisnzduhx 1 300 train
+svitgklrup 1 302 train
+sviulyyqin 1 300 val
+sviviatimj 0 300 train
+svjmgnhaiw 1 300 train
+svjopciuft 1 300 val
+svjtuoxuvk 1 300 val
+svjwnflmfw 0 300 val
+svjxrrwyew 1 300 train
+svkazbgodh 1 300 train
+svkgvesvdy 0 300 train
+svkmyzxdfa 0 300 train
+svkpcgjrlj 1 300 train
+svkwcezbse 1 300 train
+svlhuvqmtl 1 300 train
+svlhzlaknf 1 300 val
+svljlxnblq 1 240 train
+svlmacfffr 0 300 train
+svlqkqwsyh 1 299 test
+svlrwdshik 1 300 train
+svlxzardad 1 300 train
+svmgbkjvhz 0 300 train
+svmhzxlabo 1 300 train
+svmkjxqlub 1 300 val
+svmscjzeyo 1 300 train
+svmsnuohyk 1 300 train
+svmtnvbrgr 1 301 train
+svmubmqwwm 0 300 train
+svmzwfgkwr 1 301 val
+svnbuxwjfa 1 300 train
+svncuvnnqe 1 300 train
+svngfajlmf 1 300 train
+svngkmchby 1 298 train
+svnjbuxdlx 1 300 train
+svnjntpwob 1 301 train
+svnpocwbhw 0 300 train
+svnxcxwhxl 1 300 train
+svnyaecnhk 1 300 train
+svnzzspxqh 1 298 train
+svobeufkzl 1 301 train
+svodgmtwsu 1 300 val
+svodvlwnpg 1 300 train
+svofzaylsp 1 300 train
+svohfprydx 1 300 train
+svoskwmroy 1 300 train
+svotbssdqg 1 300 train
+svpaixzglm 1 300 train
+svpetiwsjc 1 241 train
+svpiogkavp 1 298 train
+svpjthtuss 1 300 train
+svpniozebk 1 300 train
+svpnunhmqe 1 301 train
+svpquewaph 1 302 val
+svpvapgkxa 0 300 train
+svqelqfbhv 0 301 train
+svqhsezhiv 1 300 train
+svqjreghph 1 300 train
+svqkfjfucw 1 300 train
+svqmjgnvdm 1 300 val
+svqrpveliu 1 300 train
+svquzcvxvt 1 300 train
+svqvrsyuah 1 300 train
+svqymonojx 0 300 train
+svrhfpcdws 1 300 train
+svriqzmius 1 300 val
+svrmjcovcs 1 300 val
+svrrlyfewj 1 300 train
+svrxyrarmb 1 300 val
+svrzxqjfnq 0 300 train
+svsaaqsqse 1 301 train
+svsbxqlqmj 1 300 train
+svsckehedf 1 300 train
+svsefaskeb 1 300 train
+svsqmlgoch 1 300 train
+svssonlnsp 1 249 train
+svtcfskbrf 1 300 train
+svtfdjawin 1 300 val
+svtffdosqc 0 301 train
+svtjuqkvae 0 300 train
+svtkbhgqsv 1 300 train
+svtnilogao 1 300 train
+svtocotxob 1 300 train
+svtooougxu 1 300 train
+svttpeszvx 1 300 val
+svtuluxajn 0 300 train
+svtxfmfnho 1 300 train
+svuanhlbtk 1 300 train
+svubaadmxq 1 300 train
+svuccelljy 1 300 train
+svucxmxxjo 1 300 val
+svufgqgkbf 1 300 train
+svufiqglan 1 300 train
+svupgtplaa 0 300 train
+svuvnqbxri 1 300 train
+svuwkwfbik 1 300 train
+svvicoewvg 1 297 train
+svvqezbbzj 1 300 train
+svvsmdafpc 1 300 train
+svwfjarqgy 1 300 train
+svwlwkfmhj 1 300 train
+svwpjzdgvv 1 300 train
+svwudbkbxq 0 300 train
+svwvmjonbp 1 300 train
+svwzaijczm 1 300 val
+svxnxjcxwb 1 300 train
+svxnzkktgy 1 300 train
+svxsnwkvdt 1 301 train
+svxteouikz 1 300 train
+svycbvuvgc 0 300 train
+svycuadeyq 1 241 train
+svygeyqbor 1 300 train
+svynrdoglx 1 300 train
+svynysfmaq 1 299 test
+svyrunawef 1 300 val
+svytabsqio 1 299 train
+svytpoqmoa 1 300 train
+svzgpoeicz 1 300 val
+svzisjojjj 1 300 train
+svzjgrwsso 1 300 train
+svznqnzzqj 1 300 train
+svzsaesufj 1 300 train
+svzsyzerfx 0 300 train
+svzuyqhqmn 1 300 train
+svzvknkdns 1 300 train
+svzyxamwkr 1 300 test
+swadapvqlf 0 300 train
+swbcpoazft 1 300 train
+swbeagljwn 1 300 val
+swbgoxjmbr 0 298 train
+swbiogmgun 0 300 train
+swbkiqkbaz 1 300 train
+swbukgycks 1 300 train
+swchhjblce 1 300 val
+swciiqrzor 1 300 train
+swcmcyukdu 1 300 train
+swcmybhiey 1 300 train
+swcnedwckl 1 300 train
+swcwveilsf 1 300 train
+swdfgswmvo 1 300 train
+swdgvesbou 1 300 train
+swdiaghihp 1 236 train
+swdrxizwib 1 300 val
+swdsexridq 0 300 val
+swdwrphlin 1 300 val
+swdyoqnjtk 1 300 train
+swebfjvves 1 300 train
+swebiejvkv 1 300 train
+swecvokyga 1 300 train
+swedbyuehz 0 300 train
+sweeqbjgrm 1 300 train
+swefihnbwe 1 300 train
+swekfwvqdj 1 300 train
+sweozakmmi 0 300 train
+swerneemsi 1 300 train
+swevrhuvwf 1 300 train
+swewtxjqmg 1 300 train
+swfbbdgult 1 299 test
+swfcriykur 1 300 train
+swfeaaitng 1 300 val
+swfgfkycjm 1 300 val
+swfgtivddf 1 298 train
+swfifgmhev 1 300 train
+swfkwzmztq 1 300 train
+swflsqlknt 1 300 val
+swflybujtm 1 297 val
+swftkyiklu 1 300 val
+swggxftycm 1 300 train
+swgopbcfas 0 302 train
+swguecbavx 1 300 train
+swgvspkogs 1 300 train
+swgylzaapi 1 301 val
+swhdbstcyl 1 300 train
+swhfjvxpad 1 241 train
+swhgbmqwoy 1 300 val
+swhkpualmx 1 300 train
+swhmasrbeb 1 300 train
+swhoutyqtq 0 300 train
+swhrgafdag 0 300 train
+swhwvoopzb 1 300 train
+swidhipsqt 1 301 train
+swidxlhpft 1 300 train
+swieakzjcz 1 300 train
+swiejguiyh 1 300 train
+swimbvtqhd 1 300 val
+switcinffz 1 300 train
+swjayzwxvx 1 300 train
+swjecizpwt 1 300 train
+swjenidcez 1 300 train
+swjocihupl 1 300 train
+swjphtorus 1 300 train
+swjwcrfkbo 1 239 train
+swjyciyrha 1 300 val
+swkcowemoq 1 300 train
+swkdvdyzuo 1 301 train
+swkiblawat 1 296 val
+swktkvkwcp 1 300 train
+swktwteccp 0 300 train
+swkwmfklts 1 300 train
+swkyjuccjb 1 300 train
+swkyzqsmoq 1 300 train
+swljyvwykf 1 300 val
+swlyxzdbmg 1 300 train
+swmfxxvncx 1 300 val
+swmiyywkuo 1 300 train
+swmkcwcmdh 1 300 train
+swmpmkdbye 1 300 train
+swmreanmmk 1 300 train
+swmstxyjbg 1 300 train
+swmwfckjev 1 298 val
+swmwybagzp 1 300 val
+swmxertoxu 1 300 train
+swmykyqhli 1 300 train
+swnhgamljr 1 99 train
+swnhihwacr 1 300 train
+swnluxjpzu 1 298 train
+swnnmekzyn 0 300 train
+swnpavtiwe 1 300 val
+swofmvbsjj 1 300 train
+swogbtsrkk 1 300 val
+swoluwmhyv 1 301 train
+swowqixyuj 1 300 test
+swoxtfgmpd 1 299 train
+swozlnezbo 0 300 train
+swplwqvovs 1 300 val
+swppvgkgnm 1 299 val
+swpxvzgdal 1 300 train
+swqazbkruv 1 300 test
+swqexzdqsz 1 300 train
+swqmnvzkgv 1 302 val
+swqsphgsqj 0 300 val
+swqtkkpdkq 1 300 train
+swqxbdnsze 0 300 val
+swqzlwwsig 0 300 train
+swrachmaqb 1 300 train
+swrdlcrmjn 1 300 train
+swrhscskif 1 240 val
+swrlrnmfvj 1 301 train
+swrnkafksr 0 300 train
+swrttmrmmj 1 300 train
+swrtulahal 1 300 train
+swrxkntcpi 0 300 train
+swsaoktwgi 1 300 test
+swsaqahefv 1 300 train
+swsasxoatb 1 300 train
+swsjorhurk 1 300 train
+swskulmtas 1 300 train
+swsrlhgawc 1 300 train
+swstbicxya 1 300 train
+swstoalhjp 1 301 val
+swsvmalmmz 1 300 train
+swsyliplgf 1 300 train
+swtygjislq 0 300 train
+swuaaposzo 1 292 val
+swucolsqxc 0 300 val
+swugkajjis 0 300 train
+swujnifgsf 1 300 train
+swuqhzsdet 1 300 train
+swuuzrjsbb 1 300 val
+swuvceecmj 1 300 train
+swvddevivk 1 301 val
+swvegnbcfq 1 300 train
+swviuhyvmg 1 300 train
+swvnlemzis 0 301 val
+swvosiirrn 1 298 train
+swvpjthigd 1 300 val
+swvxipghvu 1 300 train
+swwajptxav 1 300 train
+swwcnysfmk 1 301 train
+swwgnsqcrj 1 300 train
+swwkljegll 0 300 val
+swwskrimwl 1 299 val
+swwudagxer 1 300 train
+swxadgdkto 1 301 train
+swxfzhkhmf 0 300 val
+swxhrurlij 1 300 train
+swxjlfbaxd 1 300 train
+swxjpjaehd 1 300 train
+swxoosqtkl 0 300 val
+swxurqhxqm 1 300 train
+swxuyjovld 1 300 train
+swxysaobfn 1 300 val
+swykyghrpt 0 300 val
+swyqqpemki 1 300 val
+swytqxpnid 1 300 train
+swyucxjgbj 1 300 train
+swyykxajju 1 300 train
+swzdbnheov 1 300 train
+swzqcwmmsp 0 300 train
+swzqsqbbuz 0 300 val
+swzwncupqq 1 298 train
+sxacwoqctx 1 300 train
+sxahdsbpsa 0 300 train
+sxakofagzd 1 300 train
+sxannttcvw 0 300 val
+sxavyfcdcq 0 300 val
+sxaxltemxl 1 300 val
+sxbcymvxyf 1 300 train
+sxbfdmebrp 0 250 train
+sxbffmmoqo 1 300 train
+sxbfivkdll 1 300 train
+sxbgpkupft 1 300 val
+sxbhnsrodz 0 300 train
+sxblpuzjtw 1 300 train
+sxbqodicnv 1 301 train
+sxcamjmdcl 1 241 train
+sxceeoickj 1 300 val
+sxchkliqka 1 300 train
+sxckdjxdgt 1 300 train
+sxcnxzhpqd 1 300 train
+sxcsecxjku 1 300 train
+sxcvmglbtu 1 300 train
+sxcwymmves 1 299 val
+sxcytodsgx 1 300 train
+sxdbxvwsaq 1 301 train
+sxdcjsnsgw 1 300 train
+sxdeqxmghk 1 300 train
+sxdettnear 1 300 train
+sxdmqrhrzn 1 300 train
+sxdxjvwird 1 300 train
+sxdykwwzjt 0 300 train
+sxebdhvizr 1 300 train
+sxebhsszpr 1 300 train
+sxebnpmpjh 1 300 train
+sxecdqrdli 1 300 train
+sxefjtoqot 0 300 val
+sxefxwzush 1 300 train
+sxegneugcb 1 300 train
+sxekjjvfkh 0 300 val
+sxellmjboe 1 300 train
+sxemoahvbz 1 301 val
+sxenprahkm 1 241 train
+sxevlshkuo 1 300 train
+sxevzumeut 1 300 train
+sxfaibzdkz 1 300 train
+sxfeteoqpr 1 300 train
+sxfkdrznan 0 302 train
+sxflqycnym 1 300 train
+sxfmelexpe 1 301 train
+sxfmhtwazr 1 299 train
+sxfoaajecn 0 300 train
+sxfppsverr 1 299 test
+sxfrubpqtj 1 300 train
+sxftpozoex 1 300 train
+sxfxiyffyj 1 300 train
+sxfxkbgndh 1 300 val
+sxfxmigcjk 0 300 train
+sxgcanycdl 0 300 train
+sxgdjvfkgj 1 300 train
+sxgjwikrjb 1 300 val
+sxgpprzcay 1 300 train
+sxgvftmczr 1 300 train
+sxhcthylvd 1 300 val
+sxhexjgzdl 1 300 train
+sxhhvmzejl 1 241 train
+sxhiirvxwi 1 299 test
+sxhogrqzhy 0 300 train
+sxhtbljghi 1 300 train
+sxhvpfpkgs 1 300 train
+sxhwdvetbh 0 300 train
+sxhzrduynx 1 300 train
+sxibdzimft 1 301 val
+sxidqyinyq 1 300 val
+sxixvpxzkj 1 300 val
+sxjatudkgp 0 300 train
+sxjbspwgtp 1 300 val
+sxjdqerkfp 0 288 train
+sxjqylrnhr 0 300 val
+sxjubjmztd 1 300 train
+sxjybmxvms 1 300 train
+sxkcactoic 1 300 val
+sxketjxinx 1 300 train
+sxkffuoxyi 1 300 train
+sxkkwgghqz 0 300 train
+sxkpwexccj 1 300 train
+sxkqidtohg 1 300 train
+sxkubcwkgh 1 301 val
+sxkwnjayyk 1 300 train
+sxlgqmhstj 1 300 train
+sxltuzpcxj 0 301 train
+sxlywoqfic 1 300 train
+sxmditukrr 0 237 train
+sxmfxmyohf 0 300 train
+sxmggjuqhi 1 300 train
+sxmjhbrswr 0 300 train
+sxmqvznwwq 0 300 train
+sxmxquozdu 1 300 train
+sxncxaeqto 1 300 train
+sxnfprslzp 1 300 val
+sxnhvmsjje 1 300 train
+sxnqynxdpd 1 302 val
+sxnvaogirf 0 300 train
+sxobmauqtc 1 300 train
+sxoclfdfvk 0 300 train
+sxofteuigj 1 300 train
+sxogdtqngo 1 298 val
+sxotvtyoul 1 300 train
+sxovehtehh 1 300 train
+sxowdiunca 1 299 train
+sxpbnfsqgj 1 300 train
+sxpdhycvie 1 300 val
+sxpdkmplaz 1 300 train
+sxpegjsjzy 1 300 train
+sxphowedwg 1 300 val
+sxpmpmsdqg 1 301 val
+sxpnpetwvy 0 300 train
+sxpufxocnw 0 300 train
+sxqfncfomi 1 300 val
+sxqfygniwk 1 299 test
+sxqroedlhr 0 300 train
+sxrawtuutq 1 300 train
+sxrorqczon 1 300 val
+sxrsniutyo 1 300 train
+sxrukvmrvg 1 297 train
+sxrxjtqxkv 0 300 train
+sxryoeigag 0 300 train
+sxsazibbyp 1 300 train
+sxsbxvtrtw 1 302 val
+sxscmttzum 1 300 train
+sxscnjzfbo 1 300 test
+sxseiasrva 1 300 val
+sxskbtitzz 1 300 train
+sxskpozjcz 1 300 train
+sxsqzekmxc 1 300 val
+sxstkpjtbc 1 301 val
+sxstufcwgk 1 300 train
+sxtbsovjqb 0 300 train
+sxtdqcoyiy 1 300 val
+sxtiprymmc 1 299 test
+sxtsonkluu 0 300 val
+sxtwruekmc 1 300 train
+sxucmzlqvu 1 300 train
+sxucvltbzp 0 300 train
+sxudekrmkw 1 300 train
+sxugebeyba 1 301 train
+sxultduxtw 1 299 test
+sxumzvkfln 1 300 val
+sxusxfdazh 1 241 train
+sxuuldvhix 0 300 train
+sxuvpygveh 1 300 train
+sxuzdfzoon 1 300 train
+sxviarxvdv 1 300 train
+sxvjxktnaa 1 241 train
+sxvuibwyki 1 300 train
+sxvurhicry 1 300 train
+sxvxjgrieg 0 298 train
+sxwctkzlke 1 300 val
+sxwdupqijr 0 300 val
+sxwhcmytkp 0 300 train
+sxwjyxvozg 1 300 train
+sxwtmafdtd 1 300 train
+sxxgprtnxt 1 300 train
+sxxiukaejv 1 300 train
+sxxklmhcma 0 300 val
+sxxksrnvld 0 300 train
+sxxmdwpdoj 1 300 train
+sxxpgmzsbq 1 300 train
+sxxvubkavd 1 300 train
+sxxwfcobji 1 300 train
+sxxxeyuqax 1 298 val
+sxxzkpmwfb 1 300 train
+sxycnyijpq 1 300 train
+sxydpsziue 1 301 train
+sxyqfremjz 1 240 val
+sxyrfylqcf 1 300 train
+sxyrkshzsg 1 300 val
+sxysimhbmy 1 300 train
+sxyvtdzene 1 300 train
+sxyydjyziy 1 300 train
+sxyylnncse 1 300 train
+sxyzmmjchv 1 299 test
+sxzadtlzxt 1 300 train
+sxzbmbaqhs 1 300 train
+sxzddbulvt 0 300 train
+sxzpkemmcc 1 300 train
+sxzqdaiulo 0 300 train
+sxzqyvwgkd 1 301 train
+sxzrrnxzzs 1 300 train
+sxztqqxouc 1 300 train
+sxzyfbfssf 1 300 val
+syacqpjjzr 0 300 train
+syaggwdftn 1 300 train
+syaludhwxe 1 300 train
+syaostfofw 1 300 val
+syaspnptuk 1 300 train
+syauamddit 1 300 train
+sybensnwzj 0 300 train
+sybnzcpwvy 1 300 val
+syboqqflhz 1 300 train
+sycdopydln 1 241 train
+sycdyrhpxh 1 300 train
+sycfrgvkry 0 241 train
+sychesiyyu 1 299 test
+sycmpafxbc 1 300 train
+sycmyirtut 0 255 train
+sycnsgxyxp 1 300 val
+sydcstkoet 1 298 train
+sydmxkinkc 1 300 val
+sydomiglrf 0 300 train
+sydvzglxyi 1 300 train
+sydxqogdlf 1 300 val
+syeabhanwc 0 300 train
+syedrogkhe 1 298 train
+syeeipcyhk 1 300 train
+syekmkwpds 0 300 train
+syemrecplt 1 300 train
+syemxznzhs 1 300 train
+syewknbemq 0 300 train
+syfasdjogh 1 300 train
+syfbyohaem 1 300 test
+syfjswfmtr 1 240 val
+syftukgutg 1 300 train
+syfzjjdmxh 0 300 train
+sygbgeqsrx 1 301 train
+sygcrurhtm 1 300 train
+sygkgsmhqa 1 300 train
+sygmzpownx 1 300 train
+sygqcvmttw 0 300 val
+sygwvvspiu 0 300 train
+sygzgdyvpq 1 300 train
+syhcgmzbeg 1 300 train
+syhlcjazeu 1 301 val
+syhpyilhte 1 299 val
+syhqfmodoq 1 300 val
+syhzdgxcne 0 136 train
+syijbkakrt 0 300 train
+syijyhegoo 1 300 train
+syimlucprj 1 301 train
+syjckfbhpi 1 300 train
+syjiswtrvr 0 300 train
+syjkxjekyf 1 300 train
+syjohbeufz 1 300 train
+syjugbmlfh 1 300 train
+sykanpwtpg 1 300 train
+sykbggbkky 1 300 val
+sykbwiueyz 1 301 train
+sykcwrqtxy 1 300 val
+sykeqsobah 1 300 train
+sykgxdxhzv 1 300 train
+sykiihbjgg 1 301 train
+sykzeetoct 1 300 train
+sykzzwoxgi 1 300 val
+sylaknjpkx 1 300 train
+sylcpqbcpz 1 300 train
+syldzgkfna 1 300 train
+sylkeidflp 1 300 train
+sylnrepacf 0 300 test
+sylpwdycuf 1 300 val
+sylqtyrbdo 1 300 train
+symcxijlii 1 300 train
+symhqkwsds 1 300 train
+symmevwigf 1 300 train
+symowbrqof 0 300 train
+symrcthcvp 1 300 train
+symtdzxjcn 1 301 train
+syndbsmgyb 1 298 train
+syneqablzi 1 270 train
+synotequif 1 300 train
+synovbcnrh 1 300 val
+synptkekgs 1 300 train
+syojpqlvxx 1 300 train
+syomlwoate 1 300 train
+syopiahrxi 1 300 train
+syosrfxuip 1 300 train
+syosxhfgyr 0 300 val
+syperuofbv 1 301 train
+sypezzvbhu 1 300 train
+sypilddxdv 1 300 val
+sypojmwzsz 1 300 train
+sypqqghfxa 1 299 test
+sypuihtitt 1 300 train
+syqgirfopa 0 300 train
+syqmleojeh 1 300 train
+syqmrinrir 1 299 val
+syqnetbybf 1 300 train
+syqnnflpjv 0 300 train
+syquwwvymh 1 301 train
+syqwefkawl 1 301 train
+syqwojokcn 1 241 train
+syrbvskdhj 1 300 train
+syrjqbojxo 1 301 train
+syrkkynaxy 0 300 train
+syrpedkwvv 1 300 train
+syrqidpqrj 1 300 train
+syrufrirdo 1 241 train
+syrzfjmhlq 1 239 val
+sysdotnfua 0 300 train
+sysfumegvh 1 300 train
+sysxrgmjzs 1 300 train
+syszyewbet 0 300 train
+sytahoqhsj 1 300 train
+sytddqezij 0 300 val
+sytjgcxluo 1 300 val
+syubdrkovi 1 167 train
+syueovtetw 0 300 train
+syujvyqdlu 1 298 train
+syunjkwvjk 1 240 train
+syuroytdoc 0 300 train
+syuxttuyhm 1 300 test
+syvaynmcod 1 299 val
+syvjvjafek 0 300 train
+syvkqrbglh 0 300 train
+syvmbbzsvd 1 300 train
+syvmoluoqx 0 300 train
+syvufgcpch 1 300 val
+sywftkehlc 0 300 val
+sywheibhbw 1 300 train
+sywiuziyod 1 300 train
+sywjkrzcvf 1 300 train
+sywkyamfnm 0 300 train
+sywmsnybye 1 300 train
+sywnbmxpef 1 300 train
+sywqailxvn 1 300 train
+sywrssxkac 1 300 val
+syxbjyxzoq 0 300 val
+syxbztmoim 1 300 train
+syxljrfocr 1 300 val
+syxlmynhsi 1 300 val
+syxluwqxvc 0 300 train
+syxobtuucp 0 300 test
+syxuxmlixi 1 300 train
+syxvgaljwo 0 300 train
+syxxajctwj 1 300 train
+syxyqzzrlu 1 300 train
+syybbzdttf 1 300 train
+syynclvesz 1 301 train
+syyqagkkyk 1 300 train
+syyxmbnwfm 1 300 val
+syyzlkofif 1 301 train
+syzbpbevar 1 300 val
+syzccarxko 0 300 train
+syzfjqjasp 1 300 train
+syzlazqkmp 0 300 train
+syzmyoemwp 1 298 train
+syznvceaek 1 300 train
+syzpgcndwj 1 300 train
+syzqbmytnz 1 300 train
+syzrwrglkl 0 300 train
+syzwnmstao 1 300 train
+szaaqvdand 1 300 train
+szaauyjmbh 1 300 train
+szabeuxytk 1 300 train
+szadufrgqe 1 302 train
+szagmsazfa 0 301 train
+szahbvuilm 1 300 train
+szapfvewns 1 299 train
+szarxrmwrw 1 300 train
+szatrnucqu 1 298 train
+szaudddfyq 1 300 train
+szavemqgzg 1 300 train
+szbaleiejw 1 301 val
+szbiiogvjv 0 300 train
+szbinyrtiq 1 300 train
+szbkcloxwk 1 301 val
+szbwcfpktx 1 298 train
+szbxckefdt 1 300 train
+szcjqbissu 1 300 train
+szctvqsfqv 1 240 train
+szcuefibvs 1 300 val
+szcvjbhcny 1 300 train
+szcwtcgtlh 1 300 train
+szddzrhmep 1 300 train
+szdssgvpxd 1 301 train
+szdyyyuglp 1 300 train
+szedrozpdr 1 298 train
+szehyehbkq 1 300 train
+szekpgvtrs 1 300 val
+szepuhspue 1 300 train
+szeqeiitnx 1 301 train
+szfcaayjrk 1 300 train
+szfgeblfcj 1 301 val
+szfiektjqw 1 300 test
+szfifyvsso 1 300 train
+szfrqkcljy 0 300 train
+szftsfmvsb 0 300 val
+szfzlnesdu 0 300 train
+szgfwvswck 1 300 train
+szghjhivxf 1 300 train
+szgiedcosa 1 300 val
+szgjbfwnxs 1 300 val
+szgjfwphhd 1 300 train
+szglkumyuw 1 300 train
+szgnqiuawm 1 300 train
+szgxpdvaxx 1 300 train
+szgyiaffwg 1 300 train
+szgzhidgrq 1 300 train
+szgzrgwyuu 1 300 val
+szhamvioqz 1 300 train
+szhseoemfz 0 300 train
+szhuqrvfcn 1 300 val
+szhwzdmgxd 1 300 train
+szhxeeahto 1 301 train
+szioleshcj 1 300 train
+sziosufhqd 0 300 train
+szivkpgcki 1 300 val
+szixccrsku 1 301 val
+sziyduhlje 0 300 train
+szjajlmyex 1 300 train
+szjbkskyph 1 300 train
+szjdqwekbf 1 300 train
+szjneukrbj 1 300 train
+szjqmeikqw 0 301 train
+szjqrpismd 1 300 train
+szjrcrgolo 1 300 train
+szjrtznnfy 1 300 train
+szjxiaikvr 1 301 train
+szkeyhways 1 300 train
+szkfstxnlk 1 300 val
+szkkfzcwlv 1 300 train
+szklntqqjo 1 300 train
+szkodmxxtz 1 300 train
+szkoxlypql 0 300 val
+szksmgxzna 1 300 train
+szkurqygcu 1 297 train
+szkuviecfs 1 301 val
+szlsbbgufw 1 300 train
+szlumhuyer 1 300 val
+szmaoqvhlj 1 300 train
+szmlrbcfnd 1 300 val
+szmluuycej 1 300 train
+szmogtxlmp 1 300 train
+szmrgymgey 1 300 train
+szmsuiadqt 1 299 val
+szmtulcofq 1 300 train
+szmxyslsmn 1 302 train
+sznecnvrct 0 301 train
+sznedufhmv 1 300 train
+szngyomziu 1 301 train
+sznkemeqro 0 300 test
+sznmcgvxxz 1 300 train
+sznqwzesga 1 241 train
+szntqtidsl 1 300 val
+szoecaldzl 0 300 train
+szolumnysp 1 300 val
+szphwfzcfl 1 296 val
+szphzvfwgc 0 300 train
+szpqjojaji 1 300 train
+szpqmaxzwp 1 300 train
+szqbmybhgs 1 300 train
+szqfeoofmy 1 299 val
+szraxxwtbw 1 301 val
+szrfljeuts 1 300 train
+szrhsmnuuf 1 300 val
+szrrqbovti 1 240 train
+szrvguxoph 1 300 val
+szrxkdmvfy 0 300 val
+szscmixwxe 1 300 train
+szsmcpdjpz 1 300 train
+szsumsmuxa 1 300 train
+szsutanboa 1 300 train
+sztaqfjddw 1 300 train
+sztbtmhuwg 0 300 train
+sztjfgysek 1 300 train
+sztutlgfem 1 300 train
+sztwxfzfkw 1 300 train
+szueibxcyz 1 298 val
+szukrqabpm 1 300 val
+szulggywzw 1 300 test
+szumpozalo 1 300 train
+szuoacauxp 0 300 train
+szuqjqxrsb 1 300 train
+szutayiykg 1 301 train
+szuynagefb 1 300 train
+szuzivgywg 1 300 train
+szvnsjmeqj 1 300 train
+szvwegdmap 0 301 train
+szwbbvsnvk 1 300 train
+szwhgmrrhm 0 300 train
+szwqpsexmc 1 298 train
+szwsswwyxy 1 300 train
+szxfjsgobt 1 300 train
+szxpllkpde 1 300 train
+szxtveuqia 1 300 train
+szxwdswkwi 1 300 val
+szydvlynjc 1 300 train
+szymawumxb 1 300 train
+szypcquaia 1 300 train
+szypruzige 0 300 val
+szyurwvspl 1 300 val
+szywehpwkl 1 300 test
+szyzfljbzt 1 300 train
+szzdkrmelh 1 300 train
+szzglsjjyj 1 300 train
+szzkevknky 1 300 val
+szznkobkqz 1 300 train
+szznpramru 1 300 train
+szzxtehbhi 1 300 train
+taaewzoaim 1 300 train
+taafnrtsnw 1 301 train
+taagzkcswj 1 300 test
+taamavklfw 1 300 train
+taanizhqhp 1 300 train
+taaqdtzfxm 1 300 train
+taaqgcxrmd 1 300 train
+taatmjkyfb 1 300 train
+taatqjjfmk 1 300 train
+taavlhagzv 1 300 train
+taawexersb 1 300 train
+taaxaiggek 1 300 val
+taaxkkcdpi 1 301 val
+tabakzihxq 0 300 train
+tabczyzgnd 1 300 val
+tabrovqipy 1 300 val
+tacdksyghx 1 300 val
+taceetjchl 1 299 train
+tacgxuttcz 0 300 train
+tacmbklrdc 1 298 train
+tacsodsdoo 0 300 train
+tacsprppyp 0 300 train
+tadazsngow 1 300 val
+taddtnnipk 1 300 val
+tadhbhquye 1 300 train
+tadhdzqvgr 1 300 train
+tadkklwhqa 0 300 val
+tadkyfawkn 0 300 train
+tadsvlhcrp 1 300 train
+tadvunmhbq 1 300 train
+tadvywjdlg 1 301 train
+tadwydnrjy 1 300 train
+taebaxrfvh 1 301 train
+taefeypdtx 1 300 val
+taegmcfyxx 1 300 train
+taegqksydj 1 300 train
+taehacpqrz 1 300 train
+taeiifqwek 1 300 train
+taekbjnycp 1 300 train
+taemtpobee 1 300 train
+taenokmnkp 0 300 train
+taeorkqqhz 1 300 train
+taesskzmlg 1 298 train
+tafbvqzrvm 1 300 train
+tafkqecrpd 1 300 train
+tafnwehrnp 1 298 train
+tafoqsmvdo 1 300 train
+tafsqvrhuv 1 300 test
+taftveajrg 1 300 val
+tagbkqoodp 1 300 train
+tagfxspakz 0 300 val
+tagqvpicea 1 300 val
+tagsbwsrvy 1 300 train
+tahhujetet 1 300 train
+tahqovnsyo 1 301 val
+tahvzvozxo 1 300 train
+taibqeiajv 0 300 train
+taibypyzzf 1 300 val
+taikzedkhg 1 300 train
+taiosvirky 1 300 train
+tajqykgbje 1 300 train
+tajshqjylg 1 300 train
+tajslvbdzq 1 241 train
+tajwqwtmhb 1 300 val
+tajxfhicou 1 298 train
+tajxnoawur 1 300 train
+tajydvpomy 0 300 val
+takaqlmhbp 1 300 train
+takbuccohz 0 300 train
+takdfmvwvs 1 301 val
+takedfkvfq 1 300 train
+takenflmve 1 300 train
+takhxpjtuy 1 298 val
+taklkhnqqq 1 300 train
+takntlvyln 1 300 train
+takrvvwhcd 0 300 train
+taktxpevnm 1 300 train
+takvjijwmk 1 300 train
+takwnhtevy 1 300 val
+takyybgohq 1 300 train
+talbgkczww 0 300 train
+talvyktmvw 1 300 test
+talwznclcs 1 300 train
+tamayudqqx 0 300 train
+tamazprxch 1 300 train
+tambojjank 1 301 train
+tamdudyymj 0 300 val
+tamjlthbdh 1 300 train
+tamlohvayl 1 301 train
+tamsoaapfo 1 300 train
+tamtqnnvtg 1 300 val
+tamvgvhhbr 1 300 test
+tamygoiadq 1 300 train
+tangibggtn 0 300 train
+tannobxohn 1 300 val
+tanrvtsims 1 300 train
+tanuilyrcq 1 300 train
+tanujgxgnw 1 300 train
+tanwdhezve 1 241 train
+tanyuloluq 1 300 train
+tanzxmtcpo 0 300 train
+taoamapqgx 1 299 train
+taoaqqoieb 1 300 train
+taoauwzowm 1 300 train
+taofzcrygi 1 300 train
+taomyrhkqk 1 300 train
+taoodjkink 0 300 train
+taopvxsnjs 1 301 train
+taoxcdrpai 0 300 train
+tapcpdowzd 1 240 train
+tapcwiwwde 1 300 train
+taphiyetvs 0 300 val
+tapkdmgvgq 1 300 train
+tapmkwomxv 1 300 train
+taprhjnthk 1 300 train
+tapvyvwkmy 0 300 train
+taqnnsyxip 1 300 val
+taqpnyzyye 1 300 val
+tarfpxmjah 1 300 train
+tarmlpitpj 1 300 train
+tarncgrswp 0 300 train
+tarpiunjch 1 300 train
+tarwpmmuyo 1 300 train
+tarxyjfpae 1 300 train
+tasfvqdjjj 1 300 test
+taskwbtdje 1 300 train
+tasqyqkfcd 1 239 val
+tasrhqorsz 1 300 train
+tassoafzsu 0 300 train
+tassvtxamo 0 300 train
+tasungjnnu 1 300 train
+tatbleiczc 1 301 val
+tatfoivceq 1 300 train
+tatfpdvzoz 1 300 train
+tatkioybgo 1 300 train
+tatqnyfypg 1 300 val
+tatwoazjzb 1 302 train
+tatxnobhen 1 300 train
+tatzippgpp 1 300 val
+taucyhzrso 1 300 train
+taudjrquwa 1 300 val
+taujhahtof 1 300 train
+tauyycrazn 1 300 val
+tavfcllrwk 1 300 train
+tavgczqvyg 1 300 train
+tavkwwahzm 0 300 val
+tavnboabqu 1 299 train
+tavofdkgvt 0 300 train
+tavsxtaoup 0 300 train
+tavvipinca 0 300 train
+tavvtdshty 1 300 train
+tavweuclga 1 300 train
+tavzdlvssd 1 300 train
+tawhbhezpl 1 300 train
+tawirwpzve 1 300 train
+tawlojmnzk 1 300 train
+tawqkgdzsw 1 298 train
+tawzmrljir 0 300 train
+taxdvmyyfh 1 300 train
+taxhcbcftw 1 298 train
+taxjrcmkcz 0 298 train
+taxovsvycj 1 300 train
+taxsjmdjdd 1 301 train
+taxspqhwsv 1 300 train
+taxszvyhbm 0 300 train
+tayacfzhpw 1 300 train
+tayblsnzzd 1 300 train
+taycpophmu 1 300 val
+tayegnjblr 1 300 train
+tayhpivfgx 1 300 train
+tayizhcmgw 1 300 train
+taykmwtpqj 1 300 val
+taymbteuhy 1 300 train
+tayoxuthwl 1 302 train
+taypzfeooe 1 300 train
+taysfknhsg 1 300 val
+tayxxsnbeg 1 300 train
+tayykmblhg 0 300 train
+tayzeywgzs 1 298 val
+tazdyiouyb 1 300 train
+tazfoudfop 1 298 train
+tazlckybzu 0 300 train
+tazpoyngfx 1 301 val
+tazqvhawmt 1 300 train
+tazytufpcv 1 300 train
+tbafqcfvje 1 300 val
+tbahawsjhe 1 298 train
+tbahbggfjm 1 300 train
+tbamhrgmus 1 300 train
+tbanzpghwq 1 240 train
+tbatfkfepv 1 298 train
+tbatuxenma 0 300 train
+tbaugpuvqu 1 300 train
+tbaxhxvgsq 1 300 train
+tbbeuurvrv 1 300 train
+tbbmfttmab 1 300 train
+tbbpzrunpp 0 300 train
+tbbrshkrsw 1 300 train
+tbbsipbdoe 1 300 train
+tbbykjmrvv 1 300 train
+tbcbvehccy 1 300 val
+tbcjkrlhbw 1 300 val
+tbckdlscsf 0 300 val
+tbcynlkyog 1 300 train
+tbdavpyxni 1 300 train
+tbdgixstek 1 300 train
+tbdkohgzqm 1 301 train
+tbdmtzdspz 0 300 train
+tbdnsqefsq 1 301 val
+tbdoocfnft 1 300 val
+tbducfscjs 0 300 val
+tbecsmzjau 1 300 train
+tbeimqpjjk 1 300 train
+tbejulqtdp 1 302 val
+tbekzbrcmz 0 300 train
+tbellhyoxs 1 300 train
+tbemdombaa 1 300 train
+tbeoifmmhh 1 300 val
+tbeorlvpcl 1 298 train
+tbepxddoyw 1 300 train
+tbeqvpohue 0 300 train
+tbexzgfnrl 1 300 train
+tbezfufxna 1 300 train
+tbfcrehghp 1 300 train
+tbfdekkqhb 1 300 train
+tbfevpmqyo 1 300 val
+tbffeacfev 1 300 val
+tbfgotfygx 1 300 train
+tbfqkkpdxd 1 300 train
+tbfrnttsjw 0 300 train
+tbgggwypua 1 300 train
+tbgllketip 0 298 train
+tbgocvihfs 1 300 val
+tbgvzmayve 0 300 train
+tbgynbsazh 1 300 val
+tbgzihrnds 1 300 train
+tbhdqgntcp 1 300 val
+tbhepxzopw 1 301 train
+tbhhdfqdst 1 300 train
+tbhjwcqnrq 1 300 train
+tbhkdxshej 1 241 train
+tbhnggstuk 1 300 train
+tbhsvpythc 1 300 train
+tbhtlnrbut 0 300 val
+tbhzygwwto 1 300 train
+tbianzpgqj 1 300 train
+tbibvnzmxw 1 300 train
+tbicpmetzl 1 300 val
+tbioczrwqj 1 300 train
+tbiurydase 1 300 train
+tbiyacqeew 0 300 train
+tbiybjrhiv 1 300 train
+tbjhddvqgh 1 300 train
+tbjhgcojkw 1 300 train
+tbjithdaih 1 300 val
+tbjobmrpbw 1 298 train
+tbjoijrnxq 1 301 train
+tbjuzesels 1 298 train
+tbjyeamosz 1 300 val
+tbkbabercu 1 300 train
+tbkfdwfuzu 1 300 train
+tbkkoshzld 1 299 val
+tbkloilqkg 1 300 train
+tbklxweian 1 300 train
+tbkquzfvkr 1 300 train
+tbksxjjzso 1 300 train
+tbkttmmeyw 1 300 train
+tbkwkmaxbr 1 300 val
+tblcswchep 1 300 train
+tblxwzpbdy 0 300 train
+tblzusityl 1 300 train
+tbmbelbqxn 1 300 train
+tbmdatvcvb 1 300 train
+tbmfuadhug 1 300 val
+tbmkxkbpoh 1 300 train
+tbmqcmwxdh 1 300 train
+tbmudpdnpb 1 301 val
+tbncewrofv 1 300 val
+tbndgcfnak 0 300 val
+tbnemycqts 1 300 train
+tbnlgodkly 1 300 train
+tbnmncpktm 0 300 train
+tbnpjqhmhn 1 300 val
+tbogehuuyg 1 300 train
+tboglxdrxs 0 300 val
+tbohivnzoe 1 302 train
+tbomjqtdyd 1 300 test
+tbonoxkntr 1 300 train
+tbouemphpn 1 241 val
+tbowpmcrot 1 300 val
+tbpdvtuuci 1 300 train
+tbpegtaiqm 1 301 train
+tbpglyvahk 1 300 train
+tbpnpixbce 1 301 val
+tbptxbcmet 1 300 train
+tbpvxyjsbs 1 300 train
+tbpxaacbvv 1 300 train
+tbpybcxdrt 0 300 train
+tbqgrrqxwt 1 300 val
+tbqgvuyano 1 297 train
+tbqhgedlzu 1 300 train
+tbqjjrhapo 1 241 train
+tbqnvxmtga 1 300 train
+tbqogksrgg 1 300 train
+tbqojwejrc 0 300 train
+tbqpzeejso 1 300 val
+tbqqloecqn 1 298 train
+tbqrjyrzmm 1 300 train
+tbqrwehekx 0 300 train
+tbqxswvzxl 1 300 train
+tbqynhntxo 1 241 train
+tbrkhebabw 1 301 train
+tbrktogdff 1 300 train
+tbrkzvxynz 1 241 train
+tbrmmxscbx 0 300 train
+tbrrmhkbof 1 298 train
+tbrsinssyo 0 300 val
+tbrtzxnmlt 1 299 test
+tbrwatytdp 1 300 train
+tbrwzjrusk 1 300 train
+tbsbklubov 1 300 train
+tbsbtboejg 1 300 train
+tbsgtffckm 1 300 train
+tbshfichoo 1 299 test
+tbskaescql 0 300 train
+tbsnoyknfu 1 300 train
+tbsoqouejm 1 300 train
+tbszykuskl 1 300 val
+tbtbhuncfm 1 300 test
+tbtckqxqtw 1 298 val
+tbtegocpkm 0 301 train
+tbtpfsosxp 0 300 val
+tbtrtrabbi 1 300 train
+tbtsmhfrvr 1 300 val
+tbtsufhdet 1 300 train
+tbtukbokgr 1 300 train
+tbtxfqzxos 1 300 val
+tbuclehoms 0 300 train
+tbuerkufoo 1 296 train
+tbujzmjpsl 1 300 test
+tburgvpvri 1 300 val
+tbutqcgnht 0 300 train
+tbuuuamwak 0 300 train
+tbuylftpnv 1 300 train
+tbvbwxjstu 1 300 train
+tbvfnkzyvu 1 300 train
+tbvgvnhhhb 1 300 train
+tbvicjneav 1 301 val
+tbvugeywtg 1 300 val
+tbvvqleyzm 1 300 train
+tbwbbbjsmg 1 300 train
+tbwkcbkubx 1 300 train
+tbwlosjlco 1 301 val
+tbwmfvprzy 0 300 val
+tbwmgqjere 1 300 train
+tbwqckqire 0 300 train
+tbwtekasqc 1 300 train
+tbwtzcxnaq 1 300 train
+tbwunjmpir 1 300 train
+tbwydsaebx 1 298 train
+tbwyfvhycw 1 300 train
+tbxisuwppo 1 300 val
+tbxjwcjdox 1 300 train
+tbxqdlgvor 1 300 train
+tbxwrqqihv 1 301 train
+tbydphaczk 1 297 val
+tbydswthsu 1 300 train
+tbygbthxzv 1 300 train
+tbyjzlqslc 1 300 val
+tbyojhbkvj 1 300 train
+tbyrjoowsv 1 299 test
+tbzbzhgrtm 1 300 train
+tbzplzkowt 1 300 train
+tbzrscdomu 1 288 train
+tbzwpkwvxz 1 300 val
+tbzyydcnpa 1 300 train
+tbzzorjdaj 1 300 train
+tcaawqgnam 1 300 train
+tcabdazfrt 1 300 train
+tcabqevamc 1 300 train
+tcagvkfklr 1 300 train
+tcamjltluy 1 298 val
+tcaogvsare 1 298 train
+tcarlvyaec 1 300 train
+tcarsvtmlc 1 300 val
+tcawfspikr 0 300 train
+tcbgotbbts 1 298 train
+tcbjhkshde 0 300 val
+tcbkjjwzcr 0 300 train
+tcbkqmttdp 1 300 train
+tcbksssubn 0 300 train
+tcboepkimy 1 300 train
+tcbszxjovf 1 300 train
+tcbvjijrtw 1 300 train
+tccapvdmmv 0 300 val
+tccilmeshf 0 300 train
+tcclxoxpwb 1 300 train
+tccmjlbomw 1 300 train
+tccnpmerne 1 300 train
+tccoiaymek 1 298 train
+tccvrdqlta 1 299 train
+tccyuyggjl 1 300 val
+tccyuzrync 1 300 train
+tccyyuzjrt 1 300 train
+tcddebryok 1 300 train
+tcdiqwnynu 1 300 train
+tcdjcvrumn 1 300 train
+tcdjvrpzoi 1 300 train
+tcdmymwwwe 1 300 train
+tcdnpxmukw 1 300 train
+tcdnrwuayp 0 301 train
+tcdnuoxdtt 1 300 train
+tcdooxhevx 1 299 test
+tcdqoxqkci 1 240 train
+tcecvksptw 1 300 train
+tcehhsqclx 1 300 train
+tceixzheic 1 300 val
+tcejitlyny 1 300 train
+tcesmzmoyr 1 300 train
+tceygjbfrn 1 300 val
+tcfbirndir 1 300 train
+tcfimyfkmt 1 300 train
+tcfvlxunbg 1 241 train
+tcfyqkcimd 1 301 train
+tcgluewbfg 1 300 train
+tcgmdvqlvk 1 300 train
+tcgnhvozuc 1 300 train
+tcgqqccuvx 1 300 train
+tcgtwgfwuu 0 300 train
+tcguvulxvo 0 300 train
+tcgzntdyqd 1 300 train
+tchcjdtipe 0 300 val
+tchdlkhcym 0 300 train
+tcheayssmx 1 300 train
+tchfcokmrs 1 300 val
+tchonhsifc 0 300 train
+tchqfddubz 1 300 val
+tchshfguii 1 300 train
+tchvkplmju 1 300 train
+tciyjjvzsf 1 300 val
+tcizhqxeak 1 300 train
+tcjafngqcq 1 300 train
+tcjbxyygjk 1 302 val
+tcjeoetmhv 1 300 train
+tcjgcbgsjy 0 300 train
+tcjtcybkyn 1 147 train
+tckamdfigl 1 296 train
+tckaqhpdeq 1 240 val
+tckdtsunrg 1 300 train
+tckeizubsz 1 300 train
+tckifpsxtv 1 300 train
+tcknbmalyc 1 300 train
+tcktgrdqom 1 300 train
+tcktipisad 1 300 val
+tckzbynlix 1 299 val
+tclhmsrccc 1 298 train
+tcllqhkyvg 1 300 train
+tclnvluxiz 1 298 train
+tcloaxofyu 0 300 train
+tcmghpeuwp 1 300 train
+tcmhsfehdu 1 300 train
+tcmmobbkrf 1 300 train
+tcmqazqrcv 1 300 train
+tcmstiljkk 1 300 train
+tcmupscyya 0 300 train
+tcmyigwekr 1 300 val
+tcnakvondn 1 300 train
+tcnbwcphju 1 300 train
+tcnehflodv 1 300 train
+tcnfhhzoqb 1 300 train
+tcnhkcuntk 1 300 train
+tcnhmbtaeu 1 301 train
+tcodaaewxu 1 302 train
+tcodtwcppn 1 300 val
+tcoktfjdkf 1 300 val
+tconladzxl 1 288 train
+tcouxmqrkx 1 300 train
+tcovatotee 1 300 train
+tcpbxoifch 1 300 train
+tcpcfsheae 1 300 train
+tcpduegqxj 1 300 val
+tcpfbfdqcz 1 300 val
+tcphemozgx 1 300 train
+tcphrhtblu 1 300 val
+tcpibudrje 1 300 train
+tcpikfazxw 0 300 train
+tcpmfbaoht 1 300 train
+tcpnhavbrf 1 300 train
+tcpnyzwdpk 1 300 train
+tcpqijnvmy 1 301 train
+tcpszpnyhw 1 240 train
+tcpvkevoqb 1 300 train
+tcpvkgfoet 1 300 train
+tcpvpxhhcq 1 300 train
+tcpwjasjoc 1 301 train
+tcpxqdfazu 0 300 val
+tcpxwtquou 1 300 val
+tcqbmrciww 1 300 train
+tcqirvgugz 0 300 train
+tcqmtsbhwy 1 300 train
+tcqpgvbnpy 1 300 val
+tcqtzkjeda 1 300 val
+tcquctnaeu 0 300 train
+tcqvduwwao 1 300 train
+tcrbiefsmg 1 300 val
+tcrbwwngla 1 300 test
+tcrckphuoq 0 300 train
+tcrjgukmpt 1 300 train
+tcrmyiblzg 1 300 train
+tcrtqlfiag 0 300 train
+tcsazidpma 1 300 train
+tcsddvsewk 0 299 train
+tcsdjwbihw 0 300 val
+tcsgpsjohj 1 300 train
+tcshpsupeg 1 300 train
+tcskubdwkr 1 300 val
+tcsoacltvv 1 300 train
+tcsovevfpf 1 300 train
+tcspzuexlr 1 300 train
+tcsrkqxtie 1 299 train
+tcsvwqybes 1 300 train
+tcswizzdbz 0 300 val
+tcthryshxe 1 300 train
+tctowpuweb 1 300 train
+tctsemvyga 1 300 train
+tctuytrzad 0 300 val
+tctxsbhnnl 1 300 val
+tcuafsexvn 0 300 train
+tcueflmywv 1 300 train
+tcujrensqw 1 300 train
+tcupiakadl 1 300 train
+tcuqtfvwkv 1 300 train
+tcuqvwoxqw 1 300 train
+tcusewmlgy 1 300 train
+tcuxfnznmq 1 301 val
+tcvdwbhkpt 0 300 train
+tcvenmofex 1 300 train
+tcvltppkps 1 300 train
+tcweftbnus 1 300 train
+tcwfcdwbtb 1 300 val
+tcwhwssdnv 0 300 train
+tcwiexuysy 1 300 train
+tcwqbqyizt 0 300 train
+tcwsnqstqa 1 125 train
+tcwuysqwav 1 300 train
+tcwwdvkcrg 1 300 train
+tcwxsymxnn 1 300 train
+tcwyxrvdpe 0 301 train
+tcwzglkljg 1 294 train
+tcxbfjtdkp 1 300 val
+tcxflmfzhv 1 300 train
+tcxgercomn 0 300 train
+tcxjunfctk 1 300 train
+tcxjzbiahc 1 299 val
+tcxpgoxssd 1 300 train
+tcxpwleham 0 300 train
+tcxuahxiho 1 300 val
+tcxzfeznrl 0 300 val
+tcxzhmlony 1 300 train
+tcychsyltm 0 300 train
+tcykppgtjg 0 300 train
+tcypabrcff 1 300 train
+tcyumnnyhp 1 299 train
+tcywfzbuke 0 300 val
+tcyzcunttw 1 300 train
+tcyzswrqqu 0 300 train
+tczkaxezlq 1 300 val
+tczlttyujj 1 301 train
+tczoejbcza 1 300 train
+tczpbbxfjy 1 297 train
+tczqwbvcld 1 300 train
+tdaenaarep 1 300 train
+tdafzociag 1 300 train
+tdahgbtenl 0 300 val
+tdajdslzji 1 300 val
+tdakbtkudn 1 301 train
+tdalkowcza 1 300 train
+tdancborni 1 300 train
+tdaqnjaquj 0 300 train
+tdareickov 1 300 train
+tdasoyknaq 0 300 train
+tdatdohgji 1 300 train
+tdayektiim 1 300 train
+tdaylzgkgb 1 300 train
+tdbkqadbza 1 300 val
+tdbmvevsoc 1 298 train
+tdcdquqdia 1 296 val
+tdcmgllsvo 1 300 train
+tdctqkptov 1 300 train
+tdczxskeno 1 300 train
+tdddhrhwak 1 298 train
+tddmodqmse 1 300 train
+tddmqroqzl 1 300 train
+tddutikadt 0 300 val
+tddygbolsj 1 300 train
+tdeejpojly 1 300 train
+tdefkrduzz 1 300 train
+tdefnlqmvn 1 300 train
+tdegndgvel 1 300 train
+tdejrlgnzj 0 300 val
+tdeklhahns 1 300 train
+tdemgyewhr 1 300 train
+tdfeprqwjw 1 300 train
+tdfibiuqnm 1 301 val
+tdfieeqwfg 1 300 train
+tdfjmkrnbk 0 299 train
+tdflzbwcww 1 299 val
+tdfpfdlavl 1 300 val
+tdfprubqnr 1 300 train
+tdfrmgafrx 0 300 train
+tdfucrfygt 1 300 train
+tdgbgdtbcg 1 299 val
+tdgcgcekoq 1 241 train
+tdgdqmtfma 1 300 train
+tdgfccsvpf 1 299 test
+tdgglfmpsm 1 300 train
+tdgktlbblz 1 300 train
+tdgmgoaxxp 1 167 train
+tdgnrrdvba 1 300 train
+tdgwgvhwmk 1 300 val
+tdgznaiann 1 300 val
+tdhbmxjdow 1 298 train
+tdhcertpxm 0 302 train
+tdhjquktbo 1 300 val
+tdhkvlavhr 0 300 train
+tdhrfgmeje 1 300 train
+tdhtjtjeqd 0 300 train
+tdieodxnji 1 300 val
+tdihipibei 1 300 val
+tdipxvcumi 1 300 train
+tdiqexdmty 1 300 train
+tdistonhxi 0 300 train
+tdivpngaxx 1 300 val
+tdiyizbfuq 1 299 val
+tdjjggduvn 1 300 train
+tdjkglamco 1 300 train
+tdjriecpju 1 300 train
+tdjrqrcrle 0 300 train
+tdjxgblhmo 1 300 train
+tdjxvtjlox 1 300 train
+tdkaqjzqxj 0 300 val
+tdkeokhiqq 1 300 train
+tdkloqlmkr 1 300 train
+tdknsiihhe 1 300 train
+tdkpjclgvz 1 297 train
+tdkpqtuxeu 1 240 train
+tdkqsmzazd 1 300 train
+tdkufbnrgy 0 300 train
+tdkvibcoud 1 241 train
+tdkywbcgnk 1 300 train
+tdlfpiflqf 1 241 train
+tdlfzxbrim 1 300 val
+tdlhyvnixe 1 300 train
+tdlkukhaqq 1 300 train
+tdlkuzkzuo 1 300 train
+tdlpyxbwnj 1 299 val
+tdlvxbhfvw 1 300 val
+tdlwdzfbcd 1 300 val
+tdlzglwrpb 1 300 train
+tdmgywqwdo 1 300 train
+tdmhlfbpkb 1 299 val
+tdmiovbpwa 1 300 train
+tdmlkhupqc 1 300 train
+tdmtbbjrsj 1 300 train
+tdmuayoqzu 0 300 val
+tdmyjvptzv 1 300 train
+tdmzhfsvty 1 300 train
+tdmzwkhpha 1 300 train
+tdnezvbjpd 1 300 train
+tdnhrxslny 1 300 val
+tdnisjkizo 1 300 val
+tdnjwijxop 1 301 val
+tdnlwffywn 1 300 train
+tdnorlxeqz 1 300 train
+tdnwkwomgs 1 300 train
+tdnygbzxcv 1 147 train
+tdnzjodvhl 1 300 train
+tdodjaqsjw 1 300 val
+tdoduhmbps 1 299 train
+tdohqkzvbk 0 300 train
+tdomftcuzy 1 300 train
+tdontxxzek 1 300 test
+tdoyktjsdh 1 300 val
+tdpdsjvkmo 1 297 train
+tdpedccagg 1 300 test
+tdpnrxkwww 1 300 train
+tdptngjiyr 1 300 train
+tdpxawxzll 1 300 train
+tdqbywglvo 1 300 train
+tdqgujtfyd 1 300 train
+tdqljcqezh 1 300 val
+tdqmvqupgs 1 300 train
+tdqwhafeql 1 300 train
+tdrdyokwgf 1 300 train
+tdrewqtsgl 1 296 val
+tdrhemdjpu 1 300 val
+tdroxiiqcu 1 300 train
+tdrraoezra 0 300 train
+tdrwlyufaw 1 301 val
+tdsczpygqq 1 300 train
+tdsfndvjsj 0 302 train
+tdsfqvucbj 0 301 train
+tdsgjxjxhi 1 301 val
+tdshyxifhx 1 300 train
+tdsndnisso 1 300 test
+tdsoorivke 1 300 val
+tdspbqidzz 1 300 train
+tdspxlwxst 1 241 train
+tdsuwoibur 1 300 train
+tdsyddjkgu 1 300 train
+tdtgsaspxk 0 300 val
+tdtgtgnoys 0 300 train
+tdtkoikaab 1 300 val
+tdtmewscpv 1 300 val
+tdtrkrgqho 0 300 train
+tdtveiyyfs 1 300 train
+tdtxttoqou 1 300 train
+tduduhnlxb 1 300 val
+tdudzxhsrk 1 300 train
+tdueeymjpi 1 300 train
+tdugcuamwt 0 240 train
+tdumqulems 1 300 train
+tduodnsonl 0 300 val
+tdutibbied 1 300 train
+tdvhddyaci 1 300 train
+tdvjhkaiqb 1 301 val
+tdvovkccep 1 300 train
+tdvtkdcwwg 1 300 train
+tdwegkksfl 1 300 train
+tdwheeczve 1 300 train
+tdwhrgrdol 1 241 train
+tdwmarckcn 1 300 train
+tdwobzatik 0 300 train
+tdwsygpssz 1 300 train
+tdwtovbsya 0 300 train
+tdwykdehqe 1 300 train
+tdxetyllcj 1 300 train
+tdxhbefjky 1 300 train
+tdxjnmyaox 1 300 val
+tdxkcecimi 1 301 val
+tdxkuiudmj 0 300 train
+tdyerkmluz 1 300 train
+tdyihpfdba 1 300 train
+tdyjofxsjv 1 301 train
+tdytyxyttv 0 601 train
+tdyvziumyr 1 299 train
+tdzclcjfkn 1 300 train
+tdzigpfhzf 1 300 train
+tdzjcffaec 1 301 val
+tdzqkcamch 1 300 train
+tdzsgrdneg 0 300 train
+tdztkzzrpy 1 300 val
+tdzwjjnqzl 1 300 train
+teajofwyfz 1 300 train
+teawnjdnrh 1 300 train
+teawobmgqy 1 300 train
+tebattlfrp 1 300 train
+tebbjilzmb 1 302 val
+tebhyvrvrf 0 300 train
+teblnhhyir 1 300 val
+teboaoxhpy 1 300 train
+tebrwhkckg 1 300 train
+tecgrspzjb 1 300 train
+teckjvmbsd 1 300 train
+tecrulzonc 1 300 train
+tectojecvs 0 241 train
+tecvfjzers 0 300 train
+tecwwiiobf 1 300 train
+tedgsjuecs 1 300 train
+tedhmsrlsv 0 301 val
+tedqbmfczn 1 300 train
+tedskkhovd 0 300 train
+tedwxoqtxk 1 300 train
+tedyppzfiz 1 300 train
+tedztempns 1 300 train
+teehidqtii 0 300 val
+teekjmfxzx 1 300 test
+teeqojzbxq 1 300 val
+teerjkkneb 0 300 val
+teetvagxux 1 300 train
+teffiqocch 1 300 train
+teffzzoqnf 1 300 train
+tefgiujusv 1 300 train
+tefhoyxzqm 1 300 train
+tegagsjkub 1 300 train
+tegdndofhb 1 300 val
+tegkoyhvli 1 300 train
+tegokigxgp 1 300 val
+tegpkzcxcj 1 300 train
+tegrhvlxbc 1 298 train
+tegtsvtlgk 1 298 train
+tegxyazbqq 1 300 val
+tehauhlfsa 1 300 val
+teheaiyrgm 1 300 train
+tehgaziced 1 300 train
+tehioveyjl 1 300 train
+tehiwkmctd 1 300 val
+tehkdrdiur 1 300 val
+tehtfcecpf 1 300 train
+tehzhlryre 1 299 test
+tehzmpadre 1 300 train
+teieyyxkme 0 300 val
+teihmxslwz 1 300 val
+teiphqwfvy 1 300 train
+teiwamzqsl 1 300 train
+teiwygzskx 1 300 train
+teixdcyvew 1 301 val
+teixswjkcb 1 300 train
+teiysliahp 1 300 train
+tejdkuljwn 1 300 val
+tejfudfgpq 0 300 test
+tejrikfgum 1 300 train
+tejvwdmylq 1 300 train
+tejwdhvdjc 1 300 val
+tekkprdnas 1 300 train
+tekqkzxlwb 1 300 train
+tektnsvmkf 1 300 train
+teldtnyokj 1 300 train
+telhwxhfvz 1 300 train
+teljdtlrel 1 300 train
+telpqfxjnz 1 300 train
+telralakoi 1 300 train
+telryiogyz 1 300 val
+telsdablyu 1 301 train
+telxjimqms 1 300 train
+temeqbmzxu 1 299 test
+temjefwaas 1 300 test
+tempcxniwq 1 301 train
+temrdtxzgo 1 300 train
+tenetlqiwg 1 300 train
+tenfyxwvms 1 300 train
+tenofxnuww 1 300 train
+tenvpttihf 1 301 train
+teogufqfnv 0 300 train
+teohokreqz 1 300 test
+teopjuprps 1 300 train
+teoqafxonh 1 300 train
+teorkehqpe 1 300 train
+teosxnspck 1 300 train
+teovupdlnk 1 303 train
+tepaqbxcfm 1 300 train
+tepbvnrwbx 0 301 train
+tepkizgulg 0 300 train
+tepovbsgiv 1 300 val
+tepveovrdk 0 300 train
+tepxybfdas 1 300 val
+teqhpjlpza 1 300 val
+teqplrnukp 1 300 train
+teqqkfnyxf 1 300 train
+teqslnbzni 0 300 train
+teqtrmfnfz 1 300 train
+teqtxbuuvq 1 300 val
+teqtxtbzkn 1 300 train
+teraptabzy 1 300 val
+terdojzqpc 1 300 train
+terfjrpehg 0 300 train
+tergpjcdbq 1 300 train
+terivbcgpp 0 241 train
+terlujixxf 1 300 test
+terpscrqhy 1 300 train
+tersxqtrjx 1 300 train
+tervrnaawi 1 300 train
+terxtwftwb 1 600 train
+tesktkddpk 1 300 train
+tespazgblv 0 300 train
+tesqddrvcp 0 299 train
+tesxlcozsx 1 300 train
+tesxxazgrc 1 300 train
+tesyfvtjvc 1 302 train
+tesygtqjlf 1 300 train
+tetaptwulo 1 300 train
+tetceqqfvw 1 301 val
+tetcmnvwah 1 300 val
+tetcqjmeti 1 300 train
+tetdhlrbvn 1 300 train
+tetihmpzwp 1 300 train
+tetjtnqxfq 1 300 train
+tetkqiqgki 0 300 train
+tetpxkxdag 1 300 train
+tetssskfkx 0 300 train
+tetxelvqan 1 299 train
+tetybxirys 1 300 train
+teubpbknnw 1 300 train
+teueftdaqy 1 300 train
+teuejjjrqw 1 300 train
+teulinjcdd 1 300 train
+teupnvihpn 1 300 train
+teusbquuse 1 300 train
+teuwvkvnzg 1 300 train
+tevefbheon 1 300 train
+tevixrowti 0 300 train
+tevneuhohv 1 300 train
+tevthqtlzp 0 300 train
+tevuebmruk 0 300 train
+tevzouteet 0 300 train
+tewbmkvadt 1 300 train
+tewewjlsvp 1 298 val
+tewxrlxaim 1 300 val
+tewxrpmabs 1 300 val
+texdtshvug 1 300 train
+texfhpozcp 1 300 train
+texivifjve 1 300 train
+texlmamqqc 1 300 train
+texmppxjxo 1 300 val
+texnarygjk 1 300 train
+texqtliuqz 0 300 val
+texscgtpzl 1 300 train
+texuagukbg 1 300 train
+teyduxpsea 1 241 train
+teygedxkck 1 300 train
+teygtjzwtx 1 269 train
+teymmlnnna 1 301 val
+teynfrwgex 1 300 train
+teyqhwicre 1 301 train
+teyshmhwtl 1 300 val
+teytocyalh 0 300 val
+tezfdlfcli 1 300 train
+tezjtpctqs 0 300 train
+tfadrxsfpi 1 300 train
+tfaebxrodn 1 298 val
+tfagibypej 1 300 train
+tfanykvkvi 1 300 train
+tfapxxlmxm 1 300 train
+tfautjhnle 1 298 train
+tfaxqkuhoh 1 300 train
+tfbbffzdph 0 300 train
+tfbetllutk 1 294 train
+tfbgohkzzz 0 300 train
+tfbjbnmyxo 1 300 test
+tfbmzgnzgi 1 300 train
+tfbsfycgfr 1 298 train
+tfbvbyliwh 0 241 train
+tfbyprbhpl 1 298 train
+tfceaqvefa 1 300 train
+tfcevtpnyz 1 300 val
+tfcibjtfhs 1 300 train
+tfcmaarnrn 1 300 train
+tfcmnuikne 1 300 train
+tfcsdfdsgq 1 300 train
+tfdblagmjg 1 300 val
+tfddwvpqxx 0 300 train
+tfdiwrskxx 1 300 train
+tfdkskrtwv 1 300 train
+tfdsagrxcc 1 300 train
+tfdtzsmmok 1 300 train
+tfdvpocfaa 1 300 train
+tfdxnecemn 1 300 train
+tfdzfcjmzv 1 300 train
+tfecruwfoo 1 300 train
+tfeguxahut 1 300 train
+tfelmzyikr 0 300 train
+tfevairenr 1 300 train
+tfezuwyrbh 1 300 train
+tffeskkazq 1 300 train
+tffgqtjmqv 1 300 train
+tffoedqaxq 1 300 train
+tffpdgvdko 1 300 train
+tffqzimrax 1 300 val
+tffuqbqshe 1 300 train
+tffwojlksq 0 300 train
+tfggknlbam 1 298 train
+tfgjykyhum 0 300 train
+tfgowstawg 1 300 train
+tfgrohwcbq 0 300 train
+tfgsrjnfiz 1 298 train
+tfgxcftuon 1 300 train
+tfheclbxtr 0 300 train
+tfhgklnicz 1 300 train
+tfhgywecka 1 300 val
+tfhrbrpvch 1 300 val
+tfhrnoapsg 0 300 train
+tfhvqipcet 1 301 train
+tfhzvfpqzg 1 300 train
+tficwgxtsv 1 300 train
+tfifxsnqyo 1 300 train
+tfikfqietj 0 300 train
+tfilnvzecm 1 300 val
+tfimzhkhfr 1 300 train
+tfincmnmwv 0 300 val
+tfisrhgszu 1 300 train
+tfivpvandt 0 300 train
+tfiyuzgwqw 1 300 train
+tfjbwjises 1 300 train
+tfjhkglqqe 1 300 train
+tfjjtbmwyc 1 298 val
+tfjnpnvwkd 1 300 train
+tfjqhinnmr 1 300 val
+tfjrbekdbk 1 300 train
+tfjuqjsrnv 1 300 train
+tfjuxlncqx 0 300 train
+tfjvbeihlx 1 300 test
+tfkhefgiqw 1 300 train
+tfkisiimqv 1 300 train
+tfkjujxssl 0 300 train
+tfknwgmsnd 1 300 train
+tfkodpvmpn 1 300 train
+tfkrpxgipy 1 300 train
+tfkscoffwe 0 300 train
+tfktxumxry 1 300 train
+tfkugcfzqe 1 300 train
+tfkxcxtexu 1 300 train
+tflbxeudbx 0 300 val
+tfldqcsela 1 300 train
+tfljqjbysg 1 300 train
+tfljxqezoh 1 300 train
+tflngihrat 1 300 test
+tfltrzibfo 1 300 val
+tflwinehym 0 300 train
+tfmbfmwwyb 1 300 train
+tfmlfgwiak 1 300 train
+tfmtlmxbjx 1 300 train
+tfmwmmtpgj 0 300 val
+tfmxtyqzfo 1 300 train
+tfnitflqff 0 300 train
+tfnkurgtkj 1 300 val
+tfntoycadg 1 300 train
+tfnuiwjlxd 0 300 train
+tfnvfftiug 1 300 train
+tfoixxmpoo 0 300 train
+tfojyouihi 1 300 val
+tfoqyfjjqc 1 301 train
+tfosakjvyu 1 300 train
+tfowqhdpgi 1 300 val
+tfoxelmnjx 0 300 train
+tfoxkuhfpb 1 300 train
+tfpbamftua 1 288 train
+tfpderarge 1 300 train
+tfpegwjgra 1 300 train
+tfphynshks 1 300 val
+tfpntzgnfm 1 300 train
+tfpqdyatpo 1 300 val
+tfprsyrhjj 1 300 train
+tfpsnwsdgo 0 300 train
+tfptxfvcqs 0 300 train
+tfpzjsytdd 1 300 train
+tfqbmnfdtm 1 300 train
+tfqcajnbnw 1 240 train
+tfqiymtlwd 1 300 train
+tfqjcptcqt 1 300 train
+tfqmfxwwer 1 300 train
+tfqrimpcfz 0 300 train
+tfqsdczjfy 1 241 train
+tfrjmynpms 1 300 train
+tfrkbosnhl 1 301 train
+tfrkkklllb 1 300 train
+tfrkyaosws 1 300 train
+tfrmveqota 1 298 train
+tfrquxdoxy 0 300 train
+tfrrqszima 1 297 train
+tfrtdisjbp 1 300 val
+tfrvwonbvk 1 300 train
+tfsbglocei 1 136 train
+tfsbqlbhxu 1 301 train
+tfskkxxpfl 1 300 train
+tfssegcxar 1 300 train
+tfstrtpqgr 1 300 val
+tfszjrhbhu 1 301 train
+tftcoyjfuv 1 300 val
+tftevdpqob 1 300 train
+tftewbeqgk 1 299 train
+tftmqbeqgl 1 298 train
+tftoxpbzqo 1 300 train
+tftrcgwjdt 1 300 val
+tftvimylrn 0 300 val
+tftweyltmh 1 300 train
+tfueqgfgph 1 300 train
+tfuevrpfbb 1 300 train
+tfunvwggdj 1 300 train
+tfupbmfhin 1 241 train
+tfutwoccmy 0 300 train
+tfuwpvywkw 1 300 val
+tfvaeovnqa 1 300 train
+tfvdgxheph 1 300 train
+tfvgejoqwt 1 300 train
+tfvkczsdmw 1 300 train
+tfvlewbimv 0 300 train
+tfvoqsfagr 1 300 train
+tfvpheeyyq 1 300 train
+tfvpypxupm 1 300 train
+tfvrawanbk 1 301 train
+tfvuuqqlkp 1 300 train
+tfvvnjnywa 1 300 train
+tfwdbkwvgz 0 300 train
+tfwgohpnlv 1 300 train
+tfwguyebqt 0 300 train
+tfwnyzxsoi 1 300 val
+tfwojzhzsr 1 300 train
+tfwqooumdi 0 300 train
+tfwwujmztf 1 300 val
+tfxdjbczua 0 239 train
+tfxdunkxew 1 300 train
+tfxkhcttdz 0 300 train
+tfxmcthwmd 1 300 train
+tfxtegykcp 1 300 train
+tfxzlbitch 1 300 train
+tfyefacxnu 1 300 train
+tfyfppivdw 0 300 train
+tfylliakig 0 300 train
+tfynrvmosp 1 299 test
+tfyugtlhga 1 300 train
+tfyyefqpfs 0 300 val
+tfzgqygpuk 1 300 train
+tfzwymfuyk 1 300 train
+tgabnlqtyd 1 300 train
+tgadummuwk 1 300 train
+tgahqyzpod 0 300 train
+tgalwbrxqb 1 300 val
+tgarhezjgj 1 300 train
+tgatardsah 1 300 train
+tgawasvbbr 0 300 test
+tgbciglpoi 0 300 val
+tgbdepcnzc 1 300 train
+tgbemtluoz 1 300 val
+tgbjptvwqh 1 300 val
+tgbjtksars 1 300 train
+tgbmnyajus 1 300 train
+tgbvzixzhe 1 301 val
+tgbxaqrsxp 0 300 train
+tgcaovozum 1 300 train
+tgccbkmgxr 1 300 train
+tgcgtnvikk 1 300 train
+tgcgughqjf 0 300 train
+tgdackqoek 1 298 train
+tgdfcwrccc 0 300 train
+tgdmlshtgn 1 300 train
+tgdphqvvnb 1 300 train
+tgdpszdrmm 1 300 val
+tgdvnjxqiq 0 300 train
+tgdwaawqyu 1 301 train
+tgdwqisubw 0 300 val
+tgdyerrnuc 1 300 train
+tgdzfoemni 1 300 train
+tgekngausz 1 300 val
+tgekpoxtfm 1 300 train
+tgeoqtnjsp 1 300 val
+tgepzyrrkm 1 300 train
+tgeqlltfiy 1 300 train
+tgewycdvfa 1 300 val
+tgfcowpkfj 0 300 train
+tgffjoebej 1 299 train
+tgflcpfwiz 1 300 val
+tgfouaxtro 1 300 val
+tgfqhupkvy 1 300 train
+tgfrvltqgb 0 300 train
+tggfrybqqr 1 300 train
+tggkhloxvs 1 302 train
+tgglcwjxez 1 300 train
+tggvkvjppv 0 300 train
+tggwdcmmyv 1 300 train
+tggyqzqwpg 0 300 train
+tggzienvlz 1 300 train
+tghhmitmpp 1 300 train
+tghrnzeomv 1 300 train
+tghslxvxlx 1 300 train
+tgideafqrm 0 300 train
+tgifrhctpt 1 300 train
+tgirivkxvf 1 300 train
+tgisyodwfi 1 300 train
+tgiyvnddyn 1 300 train
+tgizgcvegh 1 300 train
+tgjartzakw 1 297 train
+tgjeihxolq 0 300 train
+tgjpbxzknd 1 300 train
+tgjqbtoiyj 1 301 val
+tgkeytunnd 1 300 train
+tgkfpzaezd 0 300 train
+tgkgvebadw 1 300 train
+tgkhgnukkq 1 300 test
+tgkjhdyxww 1 300 train
+tgkjzanykb 1 300 train
+tgknwvdjxj 0 300 train
+tglaamchts 1 300 train
+tglgmfwwus 1 300 train
+tglgtnseox 0 300 train
+tglxshkgjx 1 300 train
+tgmbhvxfik 1 300 train
+tgmbrgobyr 1 298 train
+tgmqfzsznf 0 300 train
+tgmqpnqqwr 0 301 train
+tgmsusdydi 1 300 val
+tgmvreobsz 1 300 val
+tgncpfpqop 1 300 train
+tgndwphrkz 1 300 train
+tgnemoqyzn 1 241 train
+tgniuovpll 1 300 val
+tgnuyyuzay 1 300 train
+tgnvfnpdcp 1 300 train
+tgnwpalgyz 1 300 train
+tgnynnlgym 0 299 val
+tgnzsapzlx 1 300 train
+tgobqutmvi 0 300 train
+tgodszkhbc 1 300 train
+tgofjcvdgn 1 300 train
+tgoirngscy 1 299 train
+tgoocrrbks 1 300 train
+tgotngwspp 1 300 train
+tgovgvzzfi 1 298 train
+tgpnlfjmbq 1 300 train
+tgpqkhbvhz 1 300 train
+tgpuqooahy 1 300 train
+tgpyhxgfux 1 300 train
+tgqaahxkss 1 300 train
+tgqcdiscau 1 300 train
+tgqekaivqf 1 301 train
+tgqjetehoc 0 300 train
+tgqnrtyrew 1 301 val
+tgrgseiwzg 1 300 train
+tgrmyxlwsu 1 300 train
+tgrrzbaatg 1 300 train
+tgrsdblazp 1 241 train
+tgsaatpcin 1 300 train
+tgshggdnzq 1 83 train
+tgshlaaskm 1 300 train
+tgsnckjmjb 1 300 train
+tgstgjvann 1 300 val
+tgswsrxunu 1 300 train
+tgtaisacai 1 300 val
+tgtdvzzere 1 301 val
+tgtfoodpww 1 300 train
+tgtilqdelb 0 300 train
+tgtjwjefpq 1 300 train
+tgtlaidaij 1 300 train
+tgtndszori 1 299 train
+tgtsgfggdc 1 300 train
+tgttockvgc 1 300 train
+tguafotcqk 1 300 train
+tgubqgefyz 0 300 train
+tguhkxelik 1 300 train
+tguhofieuv 1 301 train
+tgujtcwcax 1 300 train
+tgulamvlno 0 300 train
+tgumgzbpql 1 300 train
+tgupiincqn 1 300 train
+tguqyatciq 1 299 test
+tgushfdzru 1 301 val
+tguwctdjsp 1 300 train
+tguxjwlqiu 1 300 train
+tguymfezce 1 300 train
+tgvfypoxcr 0 300 train
+tgvsnyronj 1 300 train
+tgvsstngam 1 298 train
+tgvvlrtbxp 1 300 train
+tgvwkmmxra 0 300 val
+tgvymitbia 0 300 train
+tgwcfahbts 1 300 train
+tgwebqwptj 1 300 val
+tgwgktjdyi 1 300 train
+tgwhudtbjo 0 298 train
+tgwjmhotdf 0 300 train
+tgwkvbtunv 1 300 val
+tgwncsjkyr 1 300 train
+tgwpcoljin 0 300 train
+tgwptkzquf 0 300 train
+tgwvfwtycs 1 300 train
+tgwvzoncvd 0 300 val
+tgwxkfzotc 1 300 train
+tgxhlgspvk 0 300 train
+tgxikrcxug 1 300 train
+tgxnsbwlcm 1 300 train
+tgxpotsudo 0 300 train
+tgxqaixsic 1 300 val
+tgxryxiyay 1 301 train
+tgyfipzczb 0 300 train
+tgyqwaclzv 1 301 train
+tgytvianbj 1 300 train
+tgywjzbmpk 1 299 train
+tgywkgigal 0 300 train
+tgyxfnkxne 1 300 val
+tgyyqyyfau 1 299 val
+tgzcwemgsn 1 300 train
+tgzhreuuev 1 300 train
+tgzjeolcta 1 300 train
+tgzscowxdm 1 300 val
+tgzvujhqzk 1 300 train
+tgzwxryluo 1 301 train
+tgzyaxustu 0 300 train
+thacvefhjg 1 300 val
+thahnnupnn 1 300 val
+thaionimas 0 300 train
+thavoxushk 1 300 val
+thayjyxttf 1 300 val
+thazdjtlqt 1 300 val
+thbcyriycr 1 300 train
+thbfqqmkck 1 300 val
+thbgmsjosa 1 300 val
+thbireesjw 1 300 train
+thbpurlwnf 1 299 val
+thbtcgwigl 1 300 train
+thbtdgiser 1 300 train
+thbysieadx 1 300 val
+thchvaykwk 1 300 train
+thcyqqtfza 1 301 train
+thdepbwxpz 1 300 train
+thdhkgjztp 1 300 val
+thdpnshbmm 1 300 val
+thdpsjnzjr 1 300 train
+thdsasvqkp 1 300 train
+thdxqdfwix 1 300 train
+thdznppfkj 1 300 train
+thehtluqor 1 301 train
+thekddwmqt 1 300 train
+thentwgugx 1 300 test
+theuxvkump 1 300 val
+thewpixpjb 1 300 train
+theyuezzhi 0 301 train
+thfhyhpdxp 1 300 train
+thfjhumgbp 0 300 train
+thfjophgee 0 300 train
+thfmznxrde 1 300 val
+thfoujygtn 1 300 train
+thfqhyrtdo 1 300 train
+thfztsiodr 1 249 train
+thfzywypts 0 298 train
+thgdukjjbc 0 300 train
+thgfrncxwb 1 301 val
+thghbyxhrg 1 300 train
+thgmrtyzen 1 241 train
+thgpthxqgi 1 300 val
+thgtoweyol 1 300 train
+thgxxchekr 1 297 val
+thhaazlsrx 1 300 train
+thhdwkbsya 1 300 train
+thhfbcekyp 1 300 train
+thhgvxqnqv 0 300 train
+thhnijsuoy 0 300 train
+thhogdsshi 1 300 train
+thiciviobx 1 300 train
+thigerzepj 1 300 train
+thikiylwje 1 299 val
+thirkyozuy 1 300 train
+thiudmdydz 1 300 train
+thivvzjdlr 1 300 train
+thiwfkrjae 1 300 train
+thizsjymdn 1 299 train
+thjfoawfgz 1 300 train
+thjudqtide 0 301 train
+thjugpbwcv 0 300 val
+thjyzdrlqo 1 300 train
+thjzrpohya 1 300 val
+thkdzpjesm 0 300 train
+thkennrhfz 1 300 train
+thkfrdqitc 0 300 train
+thkmpocydv 1 300 train
+thkqbovggl 1 300 train
+thkrpzsgzw 1 301 train
+thksmvfnvx 1 300 val
+thkuhklthb 1 300 train
+thlbusrchr 1 300 val
+thlbzjhjzy 1 298 val
+thlgymarlx 1 300 train
+thlidrchzq 1 299 train
+thljdjipby 1 300 train
+thljzzhgur 1 300 val
+thllkmstev 1 300 train
+thlpytumpx 1 300 train
+thlsdnvgqd 0 300 train
+thluelsens 1 298 train
+thluesaiiy 1 300 train
+thluuropvl 1 300 train
+thlzaujkbk 0 300 train
+thlzutaroj 1 300 train
+thmfeqhhhe 1 299 val
+thmskpnxlx 1 300 train
+thmvnybdje 1 300 train
+thmwcolqan 1 300 val
+thmzcnvwbn 1 300 val
+thnbadkefl 0 300 train
+thnehpctli 1 300 val
+thnflydbas 1 300 train
+thnfxnpcqc 1 301 train
+thngpalfbb 0 300 train
+thnjlpwbte 1 300 val
+thnlphmtgt 1 300 train
+thnvuwfgaw 0 300 train
+thnwyexeos 1 300 train
+thnywrwayf 1 300 train
+thocwbvgls 1 300 train
+thodjevvjy 0 300 train
+thoepocubf 1 300 train
+tholihuyvc 1 300 train
+thomfdglym 1 300 train
+thoruidnqf 1 300 train
+thoscvlkkl 1 300 train
+thoutipzpm 1 300 train
+thpjwmvayl 0 300 train
+thpykdidhj 1 300 train
+thqcvpxobk 1 300 val
+thqdktvfeh 1 298 train
+thqevqbxwt 0 300 train
+thqgotpcog 1 300 val
+thqkpnwxit 1 299 test
+thqmzjvsxx 1 300 train
+thqydrstbq 1 300 train
+thraffactp 1 296 val
+thragtlguq 1 300 val
+thrclnvxxc 1 300 train
+thrdjkzvcg 1 302 train
+threzdislf 1 301 val
+thrgahftid 0 300 train
+throsxiubj 1 300 train
+thrrywlnqx 1 300 train
+thrscnnsws 1 300 train
+thrsffnrjl 1 300 train
+thrwnbldwv 1 300 train
+thrwtpnunp 1 300 val
+thscnjkqdk 1 300 train
+thsfjeqtav 1 300 train
+thswmhtcqn 1 300 train
+thsxmnsxir 1 300 val
+thtfstyzbb 1 300 train
+thtksvmnyc 1 300 val
+thtlpwgswn 1 300 train
+thtsbqkeht 1 300 train
+thtupjefsl 1 300 train
+thtzgjtcnn 1 300 train
+thubwixidp 1 300 train
+thuizkzoox 1 298 train
+thukxnhxmw 1 240 train
+thumialdgv 1 300 train
+thumxdxgbq 1 300 train
+thuqxmuhib 1 300 train
+thuzabuggs 1 300 val
+thvdoktlxs 0 300 val
+thvnmktzgq 0 300 train
+thvoxjbcsx 1 300 val
+thwdckrmkm 0 300 train
+thwftysuwz 1 300 train
+thwifdrtjy 0 300 train
+thwnudevjb 1 296 train
+thwusdptql 1 300 val
+thxdwdaypi 1 240 train
+thxibhebft 1 300 val
+thxmpsntub 0 300 train
+thxymosdkd 1 300 train
+thyhbnqitj 1 300 train
+thylhxljlh 1 300 train
+thyliacqnm 1 299 val
+thyoqkcvqq 0 300 train
+thypmfwbbk 0 300 train
+thysagyepq 1 298 train
+thytheoonq 1 301 train
+thzgowdakt 0 240 train
+thzhmnupqi 1 300 train
+thzhsmszle 0 301 train
+thzpzzrfzt 1 300 val
+thztiiwwww 1 300 val
+thzusyjfgz 1 300 train
+tiaatozsiv 1 300 train
+tiacxnwmle 1 300 train
+tiadduupyx 1 301 train
+tialngbhpj 1 300 val
+tiapefjwiv 1 300 train
+tiarotbkhs 1 300 train
+tibcdluugm 1 301 train
+tibdxlookq 1 300 val
+tibobbpjmk 1 300 train
+tibqizvosh 1 300 train
+tibqnusenx 1 241 train
+tibriahpyg 1 298 val
+tibuazsrhs 1 300 train
+tibukcdzku 1 298 train
+ticavyanwu 1 300 train
+ticespjbeg 1 300 train
+ticjgcirbg 0 300 train
+ticjmleyoz 1 300 train
+ticjnwfzmb 0 299 train
+ticmmnfdio 0 300 train
+ticpxguaeh 1 300 train
+ticviqtltg 1 300 train
+ticvyndluk 1 300 train
+ticxlioypa 1 300 train
+tidggqadsi 1 300 train
+tidmjpkayi 1 300 train
+tidpozouyy 1 300 val
+tidvyvpsyk 1 300 train
+tidykgohwc 1 300 val
+tidymxhejr 1 300 train
+tiegoagqmz 1 298 val
+tiehpkmrnq 1 300 val
+tieigjtpaq 1 300 train
+tienmuhffw 1 300 train
+tiewzptsfi 1 300 train
+tiexcrjlgt 1 300 val
+tiexfqisyh 1 300 train
+tifjesmfso 1 300 val
+tiflulqvkg 1 300 train
+tifogrmsft 1 300 train
+tigezkwzyt 1 300 train
+tigfogulpr 1 300 train
+tighgodjvk 0 301 train
+tignxzuhya 1 300 train
+tigpnyqrcj 1 300 train
+tigrqefect 1 300 train
+tigvmzzwfy 1 300 train
+tigzwcbtcq 1 300 train
+tihatezxmw 1 300 train
+tihbjbojbf 1 300 train
+tihcdjinxj 0 300 train
+tihgxlmfcj 0 300 train
+tiibmzthaq 1 300 val
+tiidnvaqax 1 300 val
+tiifsjmhtc 1 300 val
+tiigaxuznt 1 300 val
+tiiiyglzkz 1 300 train
+tiimocrkzi 1 300 train
+tiiraktqze 1 300 val
+tiitophlip 1 300 train
+tijaxeyloi 1 301 val
+tijfsvpqwj 1 300 train
+tijgslysnz 1 241 train
+tijjjsqqwu 0 241 train
+tijmyvyqxm 1 301 val
+tijqcwetii 1 300 val
+tijqecnztc 1 300 train
+tijqzpjcmz 1 299 test
+tikhuugzbo 1 300 val
+tikhxzwttd 1 302 train
+tikkzjolwc 1 300 train
+tikmpkjjxk 1 300 train
+tiknlybyey 1 301 train
+tikokrtwmx 1 300 train
+tikuczylfz 1 300 val
+tikxvyrhbc 1 300 val
+tikykgmnym 1 300 train
+tilaqsomfa 1 300 val
+tilbomnrla 0 300 train
+tilhcwenpk 1 300 val
+tilhfrpkgb 1 300 train
+tilljolrta 1 300 train
+tilsfipanc 1 300 train
+tilsqqoevp 1 298 val
+tiluljwptt 0 300 train
+tilustvgvk 1 300 train
+tilvetgmve 1 300 train
+tilvrghvxx 1 298 train
+tilxajcdhd 1 300 val
+timeyvktbt 1 300 train
+timfpvlsyb 1 300 val
+timlyltsly 1 146 train
+timombalcv 1 300 train
+timwdcsrwe 1 300 train
+timwuzokks 1 300 train
+tinbwdmmlh 1 300 val
+tinpqseqtb 1 300 train
+tinsyeppzh 1 300 train
+tinxmihpvr 1 298 val
+tinydluywq 1 300 train
+tinyzmufap 0 300 train
+tiofbsmhhz 0 300 train
+tiofpikbjx 1 300 val
+tiomadqphd 0 300 train
+tiooezppxi 1 300 val
+tioqelwqxk 1 300 train
+tiossaglty 1 241 val
+tiovwppjwn 1 300 train
+tiownrvsjo 1 300 train
+tipalopddb 1 300 train
+tipgfzdvfw 1 300 train
+tiphfpmdfv 1 300 train
+tipifwinxu 1 300 train
+tipjlfpggx 1 300 val
+tipkvvkgqq 1 300 train
+tiplfsyyxw 1 300 train
+tipncxzpeb 1 300 train
+tippuckvia 1 300 val
+tiptcssohr 1 300 train
+tipvemrumo 1 300 val
+tipzfawsdj 1 300 train
+tiqieyohsm 1 300 train
+tiqzetjopn 0 300 train
+tiraaofdss 1 300 train
+tirhxkpzlb 1 288 train
+tiriiqoqmt 1 300 train
+tirisncdwc 1 300 train
+tirjsoiyne 1 300 train
+tirntxpiur 1 300 train
+tirsfciofb 1 300 val
+tirwaljykv 1 300 test
+tirwgtjajt 1 300 train
+tisirplzzo 1 300 train
+tismpfydkh 1 297 val
+tisoqkakos 1 300 train
+tistzmhqdh 1 299 train
+tisvgpukjp 1 300 val
+titjbmfwzl 1 300 train
+titljuwzlf 0 300 train
+titlyyrfyv 0 300 train
+titmflflrv 0 300 train
+titmmjeogu 1 300 train
+titqrokdpy 1 298 train
+titungrbgd 1 300 test
+titvikgntw 0 300 train
+titwncacic 1 300 train
+tiugxrlamh 1 300 train
+tiuhqipcse 0 301 val
+tiuoitqcgy 0 300 train
+tiuqzpdeoj 1 300 train
+tiusgaoruc 1 301 train
+tiuukfnpap 1 300 train
+tiuuzndxdn 1 300 val
+tiuvfbgvse 1 300 train
+tivkmbqgwp 0 300 train
+tivksreuuj 1 300 train
+tivrtzgsvg 1 300 test
+tivrxoldxt 0 300 train
+tivuluucre 1 300 train
+tivweerslp 1 300 train
+tivyfktzvu 1 300 train
+tiwddyinoj 1 239 train
+tiwfpcvjqu 1 300 val
+tiwqjqaclx 1 302 val
+tiwunihtno 1 300 train
+tiwvgmuvnq 1 300 val
+tiwwduuhpa 1 300 train
+tixcaovmkv 1 300 train
+tiximgupfo 1 300 train
+tixjufrvid 0 300 train
+tixmokzepk 1 300 train
+tixncbfrwy 1 300 val
+tixrviqupu 1 300 train
+tixvsvgxaq 1 300 train
+tiyauksfos 1 300 val
+tiyaxvmcds 1 300 train
+tiyndudbql 1 249 train
+tiyulgywmb 1 300 train
+tiyxrljqrm 1 301 train
+tizfmhjqps 1 300 train
+tizglmxtyw 1 300 train
+tizltishhf 1 298 train
+tjahyhforn 1 300 train
+tjaipfsjpq 0 300 train
+tjajqlymxz 1 300 train
+tjakcacjok 0 300 train
+tjamabqlge 1 300 train
+tjapnyvxuv 0 301 train
+tjaqabsmmp 1 241 train
+tjatdkhhou 1 300 train
+tjbcivkwta 1 300 train
+tjbqbxpelz 0 300 train
+tjbqmyaimq 0 300 train
+tjbqzyqoqy 1 300 train
+tjcctwqdzu 1 300 train
+tjckcgbkgn 1 300 train
+tjckidsjfm 1 300 train
+tjcnczgdni 1 300 train
+tjcnwzzvnq 1 300 train
+tjcovoruiy 1 301 train
+tjcutwpjtq 1 301 val
+tjdujjbhla 1 241 train
+tjdvvlhdpq 1 300 train
+tjdwczbxqr 1 300 val
+tjdxwdoumt 1 300 train
+tjdzbotira 1 298 train
+tjecojevwp 1 300 train
+tjemkmxoak 1 300 train
+tjeoezbhzb 1 300 train
+tjepjhwopa 1 300 train
+tjesaachtd 0 300 val
+tjeteztywm 0 300 train
+tjeudtcivi 1 300 val
+tjeyrzuutd 1 300 train
+tjffaohwru 1 300 train
+tjfjmiccgu 1 299 val
+tjfjyispfe 0 301 train
+tjflivqctv 0 300 train
+tjfqfpsvgx 1 302 val
+tjfsgzbhid 1 300 train
+tjfsojcljp 1 300 train
+tjgjfhzvqh 1 300 train
+tjgjttqiok 1 301 train
+tjgjzurayi 1 300 train
+tjgnosirqh 1 301 train
+tjgpjassvu 1 300 train
+tjgqkseyta 1 300 test
+tjgqswybdr 1 300 val
+tjgrywupew 1 300 train
+tjhmyeukma 1 301 train
+tjhnmnhrhm 1 300 train
+tjhpelcdis 1 300 train
+tjhpwqxqlu 1 299 test
+tjhxtvbwgl 1 300 train
+tjhzgrwfqu 1 300 val
+tjiaopxcyp 1 300 train
+tjictfucmh 1 299 train
+tjieiokfcv 1 300 val
+tjijyivqji 1 301 train
+tjimpfdnta 1 300 train
+tjioyscshr 1 300 train
+tjisgyfzrm 1 300 val
+tjjbchgfgp 1 300 val
+tjjblctjfx 0 300 train
+tjjdqikgym 1 300 val
+tjjiejdbgx 0 300 train
+tjjjtkqrfz 1 300 train
+tjjlbeogvx 1 300 train
+tjjruxwtip 1 300 val
+tjjyyhbbus 1 300 val
+tjjzuotxny 1 300 train
+tjkbgkuupe 1 300 train
+tjkiypgods 1 300 train
+tjkldszijv 0 300 train
+tjkpazonti 1 300 train
+tjkqyexqoe 1 300 train
+tjkxdsvhtn 1 193 train
+tjkzjjrskd 1 300 train
+tjldzakzpk 1 300 train
+tjlmkaxsxp 1 300 train
+tjlrvidbxw 1 300 train
+tjlvyydprd 1 300 train
+tjlybsguby 1 299 test
+tjlykktabv 1 300 test
+tjmaadclla 1 300 val
+tjmarccuel 0 300 train
+tjmbssapbd 1 297 train
+tjmgpqjnla 0 300 train
+tjmhimdjxy 1 241 train
+tjmhnvxhin 1 300 train
+tjmhuqvdct 1 300 train
+tjmjjbucuc 1 300 val
+tjmppqyqzc 0 300 train
+tjmvfygfoc 1 300 val
+tjmwibqhih 1 300 train
+tjncimzhub 1 300 train
+tjnenpeteb 1 300 train
+tjnffavxxd 1 300 train
+tjngqjptzw 1 300 train
+tjnkhaahgz 0 300 val
+tjnkvikkpv 1 302 train
+tjnlcylcoe 0 300 train
+tjnlhpaoow 1 300 train
+tjnsflfqfs 0 300 train
+tjofgrazce 1 298 train
+tjogyenhia 1 299 val
+tjohdcbdea 1 300 train
+tjohfabohy 1 300 train
+tjoknbnowx 1 300 train
+tjozlxlsav 1 300 train
+tjpqsayhgq 1 300 train
+tjprllvjkl 1 300 train
+tjpvhgsjxt 1 300 val
+tjqbibvdug 1 300 train
+tjqfcdjjwv 1 300 train
+tjqfotzikl 1 300 val
+tjqionptya 1 300 train
+tjqjumumjm 1 300 test
+tjqqvsomef 1 300 val
+tjqrbghiiz 0 300 val
+tjqrswzssx 1 300 train
+tjrbfcehzg 1 300 train
+tjsaerauij 1 300 train
+tjsitgstsh 1 300 train
+tjsndnmeco 1 300 val
+tjsosawkmq 1 300 val
+tjsvszjycb 1 300 val
+tjtedxfyhc 1 300 train
+tjtfhraczv 0 300 train
+tjtiavdugu 1 300 train
+tjtjzhwfjp 1 300 train
+tjtlnaujez 0 301 train
+tjtmlczbqy 1 300 train
+tjtukyyenr 1 300 train
+tjtuzrkmqw 1 300 val
+tjtvaoubkx 1 300 val
+tjtxivvbcq 0 300 train
+tjuclkratk 0 300 train
+tjucqbfrms 0 300 train
+tjuflztium 1 300 train
+tjufyikcjq 1 300 train
+tjuihawuqm 1 300 test
+tjumanauqk 1 300 test
+tjupfspjfr 0 300 val
+tjuwinphzn 1 300 train
+tjuxtcojfp 1 300 train
+tjvdtwifam 1 300 val
+tjvfjghbhc 1 300 train
+tjvfjksaty 1 300 train
+tjvgqsblzc 1 301 val
+tjvuabaomx 1 300 train
+tjvvxxrgqj 1 241 train
+tjvzanqulh 1 300 val
+tjvzjpyrfz 1 300 train
+tjwdnagiqh 1 300 train
+tjwfexckqn 1 300 train
+tjwknczjsg 1 298 train
+tjwpcbaehz 1 300 val
+tjwqlokmpf 1 300 train
+tjwssciggc 1 300 train
+tjwumcmtks 1 300 val
+tjxaccpqhz 1 301 train
+tjxbnqsryt 1 300 val
+tjxiuanejr 1 300 val
+tjxsvrqlka 1 300 train
+tjxunamuze 1 300 val
+tjxxwwchhs 1 300 train
+tjybakgrwr 1 300 train
+tjycbocbwa 1 300 train
+tjyhnrrkcn 1 300 val
+tjymgkuijg 1 300 train
+tjysngujmq 1 300 train
+tjystutfka 1 300 train
+tjyuudtkme 0 300 val
+tjywwgftmv 1 300 test
+tjyyxanwdc 1 300 val
+tjzisdorws 1 298 train
+tjzkzoslxc 1 300 train
+tjzmecgyxc 1 300 train
+tjzofuvxsr 1 301 train
+tjzopfewoa 1 241 train
+tjzyonelqc 1 300 train
+tkafypqcut 1 300 train
+tkagekjkqp 1 300 train
+tkaithblic 1 300 val
+tkakcsqqyv 0 300 train
+tkasfmoode 1 300 val
+tkauikwgbs 1 300 train
+tkaxsaterw 1 300 train
+tkaxufvjgw 1 301 train
+tkaybnjwhg 1 300 train
+tkbbhoknpf 1 300 train
+tkbbkexndf 1 297 train
+tkbdkceeug 0 300 train
+tkbgpwtkza 1 300 val
+tkbitxdgpz 1 300 train
+tkblcctxqx 1 301 val
+tkbqnkeyib 1 300 train
+tkbrgsauba 1 300 train
+tkbrswdzfb 1 300 val
+tkbuggrchg 1 298 val
+tkbvfagvff 1 300 val
+tkbvjzsvyu 1 301 train
+tkbxdtkxgf 1 300 train
+tkcalhnzpz 1 300 train
+tkcbvnzhib 0 300 train
+tkcicvjzef 1 300 train
+tkcjucqbsx 1 240 train
+tkclskewfg 1 297 val
+tkcsemeptq 1 300 val
+tkcthfzrqa 0 300 train
+tkcuhfhdzs 1 300 test
+tkcwbxfroj 1 300 val
+tkcyszraqd 1 298 train
+tkczrwsanm 1 300 train
+tkczsozatk 1 300 train
+tkddrixuff 1 300 train
+tkdficpqyr 1 300 train
+tkdgukvsck 1 300 val
+tkdibirwdo 1 300 train
+tkdmssusof 1 241 train
+tkdmuzzpbn 1 300 train
+tkdnuqpefh 1 269 train
+tkdtonbpsd 0 300 train
+tkecyiimoq 0 300 train
+tkefhxnzct 1 300 val
+tkefwhktoc 1 300 train
+tkeicxruuf 0 300 val
+tkejctiioh 1 300 train
+tkenvaiqkd 1 300 train
+tkeorziquu 1 299 val
+tkfgoklkww 0 300 train
+tkfgrkrbks 1 300 train
+tkfmyrqzqr 1 300 val
+tkfnkphqek 1 300 train
+tkfptgeuyy 1 300 train
+tkgabzkgnj 1 300 train
+tkgbjtcxyl 1 300 train
+tkgcgwkxdy 1 300 train
+tkgiznnyod 1 300 train
+tkgksuqqyl 1 301 val
+tkgukulixj 0 300 train
+tkhgcfbric 1 300 train
+tkhhlzmdaf 1 301 train
+tkhlzrtopi 1 301 val
+tkhmkbgoki 1 300 train
+tkhttgergf 0 300 val
+tkhvfnjmqd 0 300 train
+tkhydmjnyq 0 300 train
+tkhzovatiu 1 300 train
+tkijogebio 1 300 train
+tkiktkqbxg 0 300 train
+tkimsggbko 1 300 val
+tkinhawpwg 1 300 train
+tkioenelzs 1 300 val
+tkirxsozcd 1 300 val
+tkitigvnyx 1 300 train
+tkiupqhmud 1 300 test
+tkjkbcpisg 1 300 train
+tkjtyqsrsp 1 300 train
+tkjzorbgim 1 300 val
+tkjzrlilpj 1 299 train
+tkkdojaodp 0 300 train
+tkkghgaagw 1 298 train
+tkkpzptjrz 0 300 train
+tkkqofqtsd 1 300 train
+tkktifoqoa 1 269 train
+tkkvtispnh 1 300 train
+tkkwgvmfed 1 300 train
+tkkwwzhkxv 1 300 train
+tkldxtsuya 0 300 train
+tklfpbfotb 1 241 train
+tklgpqzzkj 1 300 val
+tkllmcerhz 1 300 val
+tklnuprbdx 1 298 train
+tklpppaprq 1 300 train
+tklsyykofk 1 302 train
+tklugwweax 0 300 train
+tklvbzcbvi 1 300 train
+tklxusbjpt 1 300 train
+tklyaivdjr 1 300 train
+tkmbczjxjr 1 300 train
+tkmbufybhs 1 302 train
+tkmcaftoxj 1 300 val
+tkmdmipxvh 0 300 val
+tkmhqwsxqe 0 300 train
+tkmnqvujri 1 300 train
+tkmoinncef 1 300 train
+tkmozezmhg 1 301 train
+tkndzqjuyf 1 300 val
+tknitojdwb 1 300 train
+tknkaqckju 0 300 val
+tknluzkeeh 1 300 val
+tknpxhxidq 1 300 train
+tkofwngclr 0 301 train
+tkondiqois 1 300 train
+tkowbcisjd 1 300 train
+tkoxrtmcoy 1 167 train
+tkoyswvpjj 0 300 train
+tkozmpfutn 0 300 train
+tkpebzronl 1 301 train
+tkpjxkvtjg 1 99 train
+tkpkwcwnzp 1 300 train
+tkplsqobra 0 300 train
+tkpnnjqryo 1 300 train
+tkpotdwnlo 0 300 train
+tkppzgecvr 1 300 train
+tkpqyqmtgk 0 302 train
+tkpxxlyoaj 0 300 train
+tkpykqxedq 1 300 train
+tkqajjqjfc 1 297 train
+tkqergsqqw 1 300 train
+tkqfidyqnr 1 300 train
+tkqmsrgjgp 1 300 train
+tkqozrpqsr 1 300 train
+tkqqrbkngb 1 300 train
+tkqrrhksya 1 300 train
+tkqxzmhdfe 1 301 train
+tkrfoxvcvi 0 300 val
+tkrgcekjco 1 301 train
+tkrksosymh 0 300 train
+tkrrcoabgs 1 297 train
+tkrworlkkq 0 300 train
+tksfutxvhf 1 300 train
+tksnplchfd 1 300 val
+tksrerdlzq 1 300 val
+tkstcnzimo 1 300 train
+tkstmvxukx 0 300 train
+tktitjrdsu 1 300 train
+tktlbalbag 1 300 train
+tktmacftbm 0 300 train
+tktsmomimq 1 300 test
+tktvlncybw 1 300 train
+tktynuruzc 1 300 train
+tkuhxnjvpk 1 300 train
+tkupothecr 1 300 train
+tkusuxvcbg 1 301 val
+tkuwxyypaz 1 299 val
+tkuztxpuut 0 300 train
+tkvavoxmts 1 300 train
+tkvhbpjuvd 1 300 test
+tkvlargohf 1 300 val
+tkvnkezsqq 1 300 train
+tkvnsugpxp 1 300 train
+tkvpbgiiva 1 300 train
+tkvpzfvdna 1 300 val
+tkvxgpkamr 1 300 train
+tkwbtukcue 0 300 train
+tkwccpqgev 0 300 train
+tkwhwrjwtc 1 300 train
+tkwingrnrn 1 300 train
+tkwqhkqctr 1 298 train
+tkwsbtwxhz 1 300 train
+tkwsiwrfut 1 300 train
+tkxblcleyd 0 300 train
+tkxdnlvyzw 1 300 train
+tkxemlhsdi 1 300 train
+tkxnrnsitp 1 300 train
+tkxpvcrhne 1 301 train
+tkxqsbvvgq 1 300 train
+tkxrrgkgmo 1 300 train
+tkxuzykzfe 1 240 train
+tkxvwexksu 1 301 val
+tkxxzzmqzy 0 300 train
+tkxzneqajx 0 300 train
+tkxzpcbocw 0 300 train
+tkygmnaifp 0 300 train
+tkyrdtknxv 1 300 val
+tkyrsegtdw 1 300 test
+tkysdetoxn 1 300 train
+tkzbljeboq 1 300 train
+tkzcroylys 1 300 val
+tkzhajldax 0 300 val
+tkzmtfacgj 1 300 train
+tkzxqyoiue 1 300 train
+tlarqsgefm 1 300 val
+tlasuabguz 1 300 train
+tlatbxters 1 300 train
+tlavmiyixn 1 300 val
+tlaxtosyoi 0 298 train
+tlbcwxjcds 1 300 val
+tlbeohlojv 1 300 train
+tlbjcyeqxa 1 300 train
+tlbkvhgtjz 1 300 train
+tlbvvcioge 1 300 train
+tlbyzmdejy 1 300 train
+tlbzggnbxp 1 300 train
+tlcigpzhwy 1 301 val
+tlckzyddpt 1 299 test
+tlcvcbarnk 0 300 train
+tlcvvwohom 1 301 train
+tldekrvqhs 1 300 val
+tldeynvaqh 1 296 train
+tldhgjvtvl 0 300 val
+tldkrftxbe 1 300 train
+tldktxhhbz 1 297 train
+tldnpwxdxw 1 300 train
+tldyompxcf 0 300 train
+tldywavqln 1 299 train
+tlebbhthoa 1 300 train
+tlendgbvbg 1 300 train
+tleyjmuted 0 300 val
+tlfdaxizdx 1 300 train
+tlfhfylwez 0 300 train
+tlfvftcqqc 1 300 val
+tlfxrxmtmv 1 297 train
+tlgdwymjxg 1 300 val
+tlgfjqbqeq 1 300 train
+tlgvytnqvn 0 301 train
+tlgwbhzzoa 1 300 train
+tlgxqmqmlb 1 300 val
+tlhdaasgav 1 300 train
+tlhelzwqie 0 240 train
+tlhnmypxlx 1 300 train
+tlhoxbeehz 0 300 train
+tlhqmyerrn 0 299 train
+tlhttqvjxa 0 300 train
+tlikmuuvzj 1 300 train
+tlimufbiog 0 300 train
+tliqdvoxos 1 300 val
+tljkhzfpwn 1 297 train
+tljnxfdlhi 1 300 train
+tljqhsohsi 1 300 train
+tljwcstorv 0 300 train
+tljzlnahgg 1 301 train
+tlkdwclwsq 0 300 train
+tlkdysmcbs 1 241 train
+tlkezxbudy 1 301 val
+tlkjqzjlwv 1 249 train
+tlkjtstxog 1 300 val
+tlkqppughq 0 300 train
+tlkynujfqr 1 300 train
+tlkyzhqnwf 1 300 train
+tllcwgndsd 1 241 train
+tllfusprik 1 300 train
+tllkdshoby 1 300 train
+tllrvorhwo 1 300 train
+tlmhfrpnmz 1 300 val
+tlmhhkozpn 1 300 val
+tlmhxzgnfc 0 300 train
+tlmkyzhliw 1 300 test
+tlmlrntoxs 1 299 test
+tlmnwgauei 0 300 train
+tlmryidpqa 1 300 train
+tlmzctmqvg 1 301 train
+tlnaypbflt 1 300 val
+tlnearikan 1 300 train
+tlngowakdx 1 301 train
+tlnkgdeufm 1 300 train
+tlnpemvubb 1 300 val
+tlnpnxtbqu 1 300 train
+tlnuckndqr 1 300 train
+tlnuxwsnrh 1 300 train
+tlogreulov 1 300 train
+tloinwfdnz 1 298 train
+tloiukuqpx 1 302 train
+tloowiyedz 1 300 train
+tloymbfpcr 1 300 train
+tlphauhdyr 1 299 test
+tlpilcwpsp 1 300 train
+tlpiupizgf 1 301 val
+tlplswznmm 1 300 train
+tlpmkrjfoe 1 300 val
+tlprogpcqj 1 300 train
+tlpwnagnmg 1 300 val
+tlpyfwrcok 1 298 train
+tlpzyhlgdi 1 300 val
+tlqapqqspa 0 300 train
+tlqfwajlot 1 300 train
+tlqigrtcnz 1 300 train
+tlqpnaklyv 1 300 train
+tlqrmultsq 1 300 train
+tlqsngfust 0 300 train
+tlrcbdyjus 0 300 val
+tlrhhressm 1 300 train
+tlrkbtpfdd 0 300 train
+tlrnbcrjqg 1 299 test
+tlrrfkqbhb 1 300 val
+tlrypooilu 1 301 train
+tlsdqbpcps 1 300 test
+tlsicrqvty 1 300 train
+tlslgklqyn 1 300 train
+tlsmzutdvy 1 300 train
+tlsoagxovk 1 300 train
+tltaxzvcsr 1 300 train
+tltbfeoyze 1 300 train
+tltfrzoyio 1 300 val
+tltgdjhhjw 0 300 train
+tlthhnwadn 1 300 train
+tlthtqzbwa 1 241 train
+tltkrnbwei 1 300 val
+tltwgtjupw 1 301 train
+tltydwaogq 1 300 train
+tltyusajlj 1 300 val
+tluchtuten 1 299 val
+tluhibhnlq 1 300 train
+tlunycuqcw 1 300 train
+tluuhsbvta 1 300 val
+tluwspstia 1 300 train
+tluxkmwyzy 1 300 val
+tluzxvwbrb 1 300 train
+tlvdlevpgl 1 300 val
+tlvdmhfmuy 1 300 train
+tlvecijcmu 1 300 train
+tlvhpebcnc 1 300 val
+tlvkzntvto 1 300 train
+tlvmkdnapr 1 300 train
+tlvotdrkfa 1 300 train
+tlvronrktg 1 300 train
+tlvrpscrnl 0 300 val
+tlvutijbrf 1 301 val
+tlvzteofzw 1 300 train
+tlvzwceawu 1 300 train
+tlwbrrcnme 1 300 val
+tlwffdhger 1 300 test
+tlwfjlqtzo 1 300 train
+tlwidysfxg 1 301 train
+tlwtvonqvn 1 299 test
+tlxalzftlu 1 241 train
+tlxeeqfqeg 1 300 val
+tlxgwzheli 0 300 train
+tlxpxdumii 1 298 train
+tlxrxywuhr 1 300 train
+tlyjlgibtl 1 300 train
+tlymecvwoc 1 299 val
+tlzaxoslci 1 300 train
+tlzazugfnm 1 300 train
+tlzchzsbkc 1 300 train
+tlzhujcnyg 1 300 train
+tlzllrhhra 1 300 train
+tlzlqmqysq 1 300 train
+tlzomxnncq 0 300 val
+tlzordotqw 0 300 train
+tlztlpackl 1 300 train
+tlzukjppsl 1 300 train
+tmabkyuunq 0 300 train
+tmabrfkbib 1 300 val
+tmadjtypjv 0 600 train
+tmadkdromc 1 302 train
+tmafyakcnk 1 300 val
+tmamoteute 1 300 val
+tmankoitgp 1 300 train
+tmavjzbemi 1 300 train
+tmaxjkfgnc 1 300 train
+tmaydrcjxb 1 299 val
+tmazhpcqmx 1 300 train
+tmbcltbgmg 1 300 train
+tmbjqnbuuy 1 300 train
+tmbjwevprb 1 300 val
+tmbkarejpv 1 300 train
+tmbkyxtzrn 1 300 train
+tmcbniizru 1 300 train
+tmcqfxmqah 1 300 train
+tmcwlhyiwv 1 298 val
+tmcwuukgpx 1 301 val
+tmddpwraco 1 300 train
+tmdformfqp 0 300 train
+tmdfusvvkx 1 298 train
+tmdivybbdz 1 300 train
+tmdmtddvel 1 300 val
+tmdnbdlobz 1 300 train
+tmdsctfqyi 1 300 val
+tmefslcfod 1 300 train
+tmepwrldlk 1 300 train
+tmesgzxpae 1 298 train
+tmesyomanx 1 300 val
+tmfamikbwm 1 296 train
+tmfbxnljyz 1 300 val
+tmfcuimhqe 1 300 train
+tmfpjfuyzh 1 297 val
+tmfschpvyo 0 300 train
+tmfvbrktwj 1 300 val
+tmfvrareyv 1 300 val
+tmfvsxrxnk 1 300 train
+tmfyayqkdw 1 300 train
+tmgdhykjbo 1 300 test
+tmgdrjjalz 1 300 train
+tmgfgbezfh 1 300 train
+tmgmbnzrrz 0 300 train
+tmgmtwznkr 1 300 val
+tmgrmmjfjl 1 300 train
+tmgtoheynj 1 300 train
+tmgxdytvqm 1 300 val
+tmgyctdeio 1 300 train
+tmhbfupaiu 1 300 train
+tmhbklwacz 1 300 train
+tmhmqitlkv 1 300 train
+tmhmzccmql 1 300 train
+tmhnjscqou 1 300 train
+tmhpspyhbl 0 300 train
+tmhtgjqelm 1 300 train
+tmhvbtmddg 1 296 val
+tmhvwyjjou 1 301 train
+tmhwmfrlcp 1 241 train
+tmiafnveuk 1 300 train
+tmihgwwbia 1 300 train
+tmiljxyjnz 1 300 train
+tminlngfxc 1 300 val
+tmiqhpmbbm 1 300 train
+tmjcigspif 1 300 test
+tmjdjamlkq 1 301 train
+tmjjhyxkwu 1 300 train
+tmjqjcvewp 1 300 train
+tmkgzneeqo 1 300 train
+tmkmabjsix 1 300 val
+tmkqqffuwl 1 300 train
+tmkqvrdcpg 1 300 val
+tmkszgtymf 1 300 train
+tmktocmjsz 1 300 train
+tmkvixuchy 0 301 train
+tmkxhlzolm 1 301 val
+tmldrqcmkh 1 301 val
+tmlrdldhhe 1 301 train
+tmlsyouvon 1 296 train
+tmluuhutbd 1 300 train
+tmlwoisvnv 1 300 train
+tmmakbzbqw 1 300 train
+tmmjeiysan 0 300 train
+tmmmonfspe 1 300 train
+tmmmzdfxod 0 300 train
+tmmqygdfkk 1 298 train
+tmmrhcmvzi 0 300 train
+tmnfakdyes 1 300 train
+tmnogrwqty 1 300 train
+tmnqlzvuxo 1 302 val
+tmnromayen 0 300 train
+tmnxsegten 1 300 train
+tmodfqaizl 0 300 train
+tmoipoitgo 1 300 train
+tmolegourx 1 300 train
+tmoocljjtx 0 300 train
+tmoojrcaut 1 300 train
+tmorbgrrgd 1 300 train
+tmosperiab 1 300 val
+tmowrpjacr 1 300 val
+tmowslyblf 1 300 train
+tmoxlbcntm 1 241 train
+tmpbhdozhe 1 300 train
+tmpkevafhh 1 300 train
+tmpnjyeemo 1 300 train
+tmpoliijgg 1 300 train
+tmpoxhozos 1 301 train
+tmpsfqbcul 0 298 train
+tmptblijnb 1 301 train
+tmpvgviduc 0 300 train
+tmpwokkjnz 1 301 val
+tmpzryirdw 1 300 val
+tmpzveqsou 0 301 train
+tmqdjzeblu 1 300 train
+tmqiddrjil 1 300 val
+tmqjqhiqfi 1 300 train
+tmqjqolmmn 1 300 val
+tmqtedphow 1 300 val
+tmqvqotzmk 1 300 train
+tmrdfiljrk 1 300 train
+tmrfqhjiwd 0 300 train
+tmrpipnvkj 1 300 train
+tmrsxdaybx 1 300 train
+tmruxcnrhn 1 301 train
+tmrxzjtuvs 1 300 train
+tmrzevirxz 0 300 train
+tmsmicganv 1 300 val
+tmsvonxpnz 1 300 train
+tmtalkfxuu 1 300 train
+tmtbjxnrpv 1 300 train
+tmtfovkvfb 1 300 val
+tmthiqwbjd 1 300 train
+tmtjizkuqy 1 300 train
+tmtkxuhxof 1 300 train
+tmtmbqiazy 1 300 train
+tmtmecuvho 1 300 train
+tmtogzkfzq 0 300 train
+tmtoypmqwt 0 300 train
+tmttnsziij 1 298 train
+tmuaoxxwza 0 300 train
+tmuecenxah 1 300 train
+tmughcavoo 0 300 val
+tmumlegryy 1 301 train
+tmuourqerp 1 300 train
+tmuygbaiae 1 300 train
+tmuyidvvsa 0 300 train
+tmuysfibsq 1 300 train
+tmvjjqjqwo 1 299 train
+tmvocpxkqu 1 300 train
+tmvpsciuzt 1 300 train
+tmvqmdzyln 0 300 train
+tmvucypmro 1 300 train
+tmvvtliuow 1 300 train
+tmvzwabeun 1 300 train
+tmwarctiim 1 300 train
+tmwaynxgyc 1 300 train
+tmwgrforma 1 300 train
+tmwjdbrlhl 1 301 val
+tmxcslnloq 0 302 train
+tmxdrhjrix 1 300 train
+tmxlqdnilg 1 300 train
+tmxryudjcy 0 300 train
+tmydlmmdrh 1 300 train
+tmyjpyhogx 1 300 train
+tmywsxixwd 0 300 train
+tmyyqswqnx 1 300 train
+tmyzzxmhip 1 301 train
+tmzcvtlrae 1 300 train
+tmzdlqvsjs 1 300 train
+tmzekqtavu 1 300 train
+tmzfczmlsr 1 300 train
+tmzhggzzqg 0 300 train
+tmzkhlbwyh 1 300 train
+tmzqiywiep 1 300 train
+tmzwscbfnt 1 301 train
+tmzwuptonj 0 300 train
+tnacrktmoc 1 300 train
+tnaeehpcnb 1 300 train
+tnafseauhv 0 300 train
+tnagfjqngs 0 300 train
+tnanzxfyik 1 300 train
+tnbbrnrjtc 0 300 train
+tnbeazsyyl 1 300 train
+tnbhgjzfng 1 300 train
+tnbklfhdux 1 300 val
+tnbongyrve 0 300 train
+tnbwkospyz 0 300 val
+tnbxaapurp 1 300 train
+tncbacqrot 1 300 train
+tncmmpovjn 1 299 test
+tncnsgewaw 1 299 test
+tncpuhxtic 1 300 train
+tncqrbwumb 1 300 val
+tncyfgrahd 1 300 train
+tncyzngnev 1 301 val
+tndcoytrjt 1 300 train
+tndcrdrcde 1 300 val
+tndfavubba 1 300 val
+tndfndlkyw 1 300 train
+tndissjjxy 1 300 train
+tndnhmfswg 1 300 val
+tndpduztim 1 300 train
+tndudimvjx 0 300 train
+tndzgxtcnk 0 300 train
+tndzmzshsg 1 300 train
+tneakfgnzj 1 300 val
+tnecbhfzba 1 300 test
+tnecxogjpt 1 300 train
+tneevrdiwb 0 300 train
+tnegutxgrv 1 300 train
+tnejujplgd 0 300 train
+tnepfrvrjr 1 300 train
+tnetytnegv 0 300 train
+tnfjerwkgx 1 298 train
+tnflrofguu 1 240 train
+tnflukwdnc 1 300 train
+tnfpyjngnd 1 300 train
+tnfrteibgk 1 300 train
+tnfuystqkg 1 300 train
+tnfvqoqkgc 1 300 train
+tnfzgkkwvn 1 300 train
+tngawdmiye 1 300 train
+tngeakdmrf 1 300 val
+tnggazmfhc 0 300 train
+tngkmevcot 1 300 train
+tngozonnjt 0 300 train
+tngqavxqyh 1 300 train
+tnguddazae 1 300 train
+tngykktdbz 1 241 train
+tngyzdnwyu 1 300 train
+tngzrrpncl 1 300 train
+tnhcxnyqkn 1 300 train
+tnhhsqllnk 1 300 train
+tnhpqlqeau 1 300 train
+tnhvhtswgq 1 300 train
+tnijjjncgd 1 300 train
+tnileeeohm 1 300 val
+tnilmodraj 1 300 train
+tnitdtingx 1 300 train
+tnitypftlb 1 300 train
+tnjgbtlict 1 300 val
+tnjgskshpo 1 300 train
+tnjrofvrba 0 300 train
+tnkbioabkm 1 300 train
+tnkdhvneyk 0 300 train
+tnkgaspfll 1 298 train
+tnkmovifrb 0 300 train
+tnkmzthocq 1 240 train
+tnkpjuppiz 1 300 val
+tnkqdvbare 0 300 train
+tnktchngfa 1 300 train
+tnkzjvqxno 1 299 train
+tnlcdqywvv 1 300 train
+tnlfcbqxqe 1 299 train
+tnlksuelac 1 300 train
+tnllrflsez 1 300 train
+tnlxxheyex 1 300 train
+tnmaofewvl 1 300 val
+tnmjwnwhnz 1 300 train
+tnmmihprvw 0 300 train
+tnmolkboei 1 300 train
+tnmrvixxdm 0 300 train
+tnmtuunyvx 1 288 train
+tnmugaxzaa 1 300 train
+tnmuokilgt 0 242 train
+tnmwsmhnfx 1 300 train
+tnnawsjmhb 1 300 train
+tnnjexhjay 1 300 train
+tnnnjvjvwx 1 292 val
+tnnrbyjbhb 0 300 train
+tnnwcqrafy 1 300 val
+tnnyoqifhi 1 240 train
+tnnztxlbsp 1 300 train
+tnodirkwxi 1 300 train
+tnoqgdnpdz 1 300 train
+tnoqjyqtbw 1 300 val
+tnoraqksrz 1 300 train
+tnoubmcodq 1 300 train
+tnougkhbju 1 300 test
+tnpcjzoprv 1 300 train
+tnpczxignn 1 300 train
+tnpdxbddvy 1 300 val
+tnpetaxalw 1 300 train
+tnpilkafcb 1 300 val
+tnpswtqsfe 0 300 val
+tnptfmiodz 1 298 train
+tnptlyiytc 1 300 train
+tnpwvkcdyv 1 300 train
+tnqbwjkivf 1 300 train
+tnqmmhqzbi 1 300 train
+tnqnvcbhyl 0 300 train
+tnqqzpebqc 1 300 train
+tnqrssgeei 1 301 train
+tnqvokgiym 1 300 train
+tnqzijplan 1 300 train
+tnrasovsbr 1 300 test
+tnrcyxvdqs 1 300 train
+tnrdnomwxx 0 300 train
+tnrdqxiwym 1 298 val
+tnrhcjntxc 1 300 train
+tnrjilxomb 0 300 train
+tnrkjobuis 1 300 val
+tnrmnayszi 1 300 test
+tnrmvcktxz 1 300 train
+tnrntugxdo 1 300 train
+tnrohrzriw 1 300 val
+tnrrnbujan 1 300 train
+tnrvfrjpfa 1 300 train
+tnrxvsvaak 1 300 val
+tnryohgoli 1 300 val
+tnsaqegyqt 1 300 val
+tnsbntkpjz 1 300 val
+tnsuuzoimb 0 300 train
+tnswdkhcgn 1 299 test
+tntbyoptrq 1 300 train
+tntgawrlwl 1 300 train
+tntlxehwfv 1 300 train
+tntoptmvax 1 300 train
+tntxnewled 1 300 train
+tntxsmeghn 1 302 train
+tntykiphjw 1 300 train
+tnuojreaen 1 298 train
+tnuprddpnn 1 298 val
+tnuqsfassf 1 300 train
+tnuzzqfbxp 1 300 train
+tnvabkfjpw 1 300 train
+tnvffqvand 1 300 train
+tnvlrmblsz 1 300 train
+tnvpcujswe 1 300 val
+tnvupncnpj 0 300 val
+tnwavwcrmn 1 300 test
+tnwghrborx 0 300 train
+tnwpyygehw 1 300 train
+tnwqpccbne 1 300 train
+tnwqsmwgha 1 300 train
+tnwqtcfuyz 0 300 train
+tnwvxgwphk 1 300 train
+tnxgtbgnho 1 298 train
+tnxiykdwwh 1 300 train
+tnxnylgvna 1 302 train
+tnxrfejwrt 1 300 train
+tnxvpbqxza 0 300 train
+tnxvuevtqp 1 300 test
+tnxxvepdsr 1 300 train
+tnyabaexao 1 300 train
+tnyhsiwwsc 1 300 train
+tnypaqonqs 1 300 train
+tnywycgeot 1 301 val
+tnyzgaiwea 1 300 train
+tnyzkkuydp 1 300 train
+tnyzlscjat 0 300 train
+tnyzsuxdqk 1 240 train
+tnzehiyfaz 0 300 train
+tnzjbmmang 1 300 train
+tnzjcftmbh 1 300 val
+tnzufnqixi 1 300 train
+tnzvxkivth 1 300 val
+toacektzmm 1 300 val
+toajgwared 1 300 val
+toamqcgppx 1 299 train
+toancqulka 1 300 train
+toapnxrpjo 1 300 val
+tobcoiepxe 1 300 val
+tobdgusxij 1 300 val
+tobjmvytry 1 301 val
+tobkpktdmr 0 300 train
+tobqkgccoq 1 300 train
+tobtpxvtra 1 300 train
+toccxqobhy 1 300 train
+toccypftya 0 300 train
+tocencrkgq 1 300 train
+tocoxndqco 1 300 train
+tocsckcezh 1 300 train
+tocsinrihd 0 300 train
+tocvvjfjzz 0 300 train
+tocyccctcy 1 300 train
+toczipnzst 1 300 train
+todbwfbpxe 1 300 test
+todewezdgz 1 300 train
+todipebcgp 1 300 train
+todmxhamgy 0 300 train
+todrmsqplr 1 302 val
+todvzqzwit 0 300 val
+todweadblm 1 300 train
+todxkniupi 0 300 train
+todzazcpgr 1 300 train
+toefpflocw 1 300 train
+toeixngyyj 1 301 train
+toetljfmvi 1 301 train
+toevldljyp 1 300 train
+toewhlbcgt 1 300 test
+toezvafnih 1 300 train
+tofemsijra 1 300 train
+toferwxcvj 1 300 train
+tofgobjkgv 1 300 train
+tofgwwrswe 1 300 val
+tofmbxllyq 1 301 train
+tofnqucttl 1 300 train
+tofvcolfpg 1 300 val
+togdknwzie 1 300 val
+togegmxget 1 300 train
+togewxzwcm 1 300 train
+togfsvdkax 0 300 val
+toggbitvfd 1 300 train
+togkvcofeu 1 300 train
+togtvbfjrt 1 300 train
+togyrprqnl 1 300 train
+tohghjrpbj 1 300 val
+tohigipsdo 0 300 train
+tohloefevs 1 300 val
+tohnzukiir 1 300 train
+tohrqjyter 0 298 val
+tohupdesga 1 301 val
+tohwrxinix 0 300 train
+toifquoawo 1 300 train
+toiicedekh 1 300 train
+toilsxpnma 0 300 train
+toinozytsp 1 300 test
+toiqsyjwpt 1 300 train
+toirfnzurp 1 300 train
+toixtgfshx 1 300 train
+tojggibgsg 1 241 train
+tojggkcaxc 1 300 train
+tojifcpizq 1 300 train
+tojojaisaw 0 299 val
+tojoplavae 1 300 train
+tojriguehd 1 255 train
+tojvnsuila 1 300 val
+tojzejzwaz 1 300 val
+tokbawkjui 0 300 val
+tokemedmyu 1 298 train
+tokjqgjbfs 1 300 train
+tokkkdfyds 0 300 train
+tokpamhwdj 1 300 val
+tokxnbqgdj 1 300 train
+toldgekody 1 300 val
+toldwkkmzn 1 300 val
+tolfmidlum 1 300 train
+tolfmxowsr 1 300 train
+tolinccdfu 1 301 train
+tolkgbcqeo 1 301 train
+tolkqndwno 0 298 train
+tolotyowoy 1 136 train
+tolskpcvln 0 300 train
+tolvrmiumn 1 300 train
+tolylkupay 1 298 train
+tomahgosir 1 300 train
+tomcgrgzft 0 300 val
+tomdbeciuw 1 300 train
+tomfehexjw 1 300 train
+tomfizqpmo 1 301 val
+tomgjjgdia 1 300 train
+tomrdqcrcl 0 300 val
+tomunwedej 0 300 test
+tomuyzomwx 1 300 train
+tomvljxvdy 1 296 train
+tomzpivjic 0 301 train
+tonlgjtqak 1 300 train
+tonpeevxck 1 300 train
+tonppbqxmd 1 300 train
+tonsbyvqjn 1 300 val
+tonvanqrum 1 297 train
+tonyntkkvq 0 302 val
+tooblbmjvf 1 300 train
+tooczscybi 1 300 train
+toofpyjmtt 1 300 train
+toosouurcv 1 300 train
+tootdqyzdc 1 300 train
+tootprfpqg 0 300 train
+topezmraqq 1 300 test
+topggsmscx 1 300 val
+topjxzsfzn 1 300 train
+topnmdezrr 1 300 train
+topwurqcsy 1 300 train
+topxckuyhd 0 300 train
+topxupriyd 1 298 train
+topyiohccg 0 298 train
+toqcubtxwm 1 300 val
+toqgjqsqlv 1 269 train
+toqiytotzj 1 300 val
+toqkidvyxp 1 302 val
+toqmgncqsw 1 300 train
+toqngheyvq 1 300 val
+toqnlablma 1 249 train
+toqsroahdz 0 300 train
+toqsxmseyd 1 300 val
+toqtdogdma 0 300 train
+torbdovazx 1 300 train
+torjqecxjw 0 300 train
+torlanoeip 1 300 train
+torlpqwpfj 1 301 train
+torqggyeyg 1 300 train
+torsafixfh 0 300 val
+torskymphz 1 300 train
+torsvjlmtk 1 300 train
+torxncfkrj 1 300 train
+tosaapqeiq 1 301 val
+tosbzklgvk 0 300 val
+tosebikbvk 0 300 train
+tosepmtdch 1 301 val
+tosfnjmuwy 1 300 train
+tosfstbgxm 1 300 train
+toshfcrwop 1 300 val
+toslvivusc 1 299 test
+tosndhrxvh 1 299 train
+tosqjrdxxg 1 300 train
+tostmagsiq 1 301 train
+totglomavw 1 300 train
+tothsmyvoy 1 300 train
+totlhgpcws 1 298 train
+tottifwolb 1 300 train
+totujkiwgd 1 300 train
+totuynbejy 1 300 train
+touinthtia 0 300 train
+toukipiujn 1 300 train
+tounczqdfn 1 249 train
+tousrstezy 1 300 train
+tousyjnhic 1 300 train
+touvjievwf 1 297 train
+tovclebrnw 1 300 train
+tovdcuktlv 1 300 train
+tovhbmrdcx 1 300 train
+tovkafdjlm 1 300 train
+tovxgyattq 1 300 test
+tovybdvykw 1 255 train
+towerzohyf 1 300 train
+towgiiqjty 1 300 train
+towhxegyzv 1 298 val
+towijyksqo 1 300 train
+towimsjpar 1 297 val
+townkrjaub 0 300 train
+townqlsvhu 1 300 train
+towvmrajqe 1 300 train
+toxcbnqbol 1 300 train
+toxdjqiazo 0 300 train
+toxhdspkmy 1 300 val
+toxmyrgjsb 1 300 train
+toxobqirio 1 300 train
+toxpbvzswn 1 300 val
+toxsrzsksc 1 300 train
+toxxhledyr 1 300 train
+toyatftbyo 1 300 train
+toybgikcyz 1 300 train
+toyyvicmae 1 300 train
+tozdwknhcd 1 300 train
+tozkujtzdp 1 299 val
+tozxbqqisy 1 300 train
+tozyxrqqfz 1 301 train
+tpasegbttb 1 300 train
+tpayhhzgfe 1 300 train
+tpbasbfozd 1 300 train
+tpbderjkpc 1 300 train
+tpbfnscoxd 1 300 train
+tpbgzrgmvd 1 300 train
+tpbvypjbsp 1 300 train
+tpbxbdgmss 1 297 train
+tpbyccqemm 1 300 train
+tpcflvfoqo 1 300 train
+tpcijdapjt 1 300 train
+tpctqpygqm 1 300 train
+tpdfkoznff 1 298 train
+tpdpdffvho 1 300 val
+tpdzlmfxia 1 300 train
+tpeiuavlfd 1 300 train
+tpemopyikw 1 300 val
+tpetnotlbj 1 300 train
+tpeuljqyua 1 300 train
+tpeyllulxl 1 300 train
+tpezzzvsip 1 300 val
+tpfacrgpkc 1 300 val
+tpfcwgtsrr 1 300 train
+tpfjysjysn 1 300 test
+tpfnrhuhrf 1 300 train
+tpftkaveyq 0 300 val
+tpftrbdxjz 1 300 train
+tpfwnsgsmh 1 300 train
+tpfzfrvhey 1 298 val
+tpfzofmtww 1 300 train
+tpganbjtxh 1 300 train
+tpgbpkksxs 1 300 train
+tpgcdzyzic 1 300 val
+tpgcqvavhv 0 300 train
+tpgfecmnia 1 300 train
+tpgnrtdjmz 1 300 train
+tpgozsbebx 1 300 train
+tphhmywmmz 1 300 val
+tphllmvods 1 241 val
+tphoyfxmpo 1 300 val
+tpiddeudvc 1 300 train
+tpifabzupg 1 296 train
+tpifqwnpzj 1 300 train
+tpihwwkzcu 1 300 train
+tpilpqylqs 1 300 val
+tpimxrtuxf 0 300 train
+tpinzksjaf 1 300 val
+tpiohdvwyf 0 300 train
+tpipudybft 1 300 train
+tpiyykipnd 1 300 val
+tpizlhtfla 1 241 train
+tpjdjbdqck 1 300 train
+tpjincxhkn 1 298 train
+tpjqvldpao 1 300 train
+tpjrujinri 1 300 train
+tpjydgkvdt 0 300 train
+tpkawovfsk 1 300 test
+tpkcodbqhe 1 301 val
+tpkewfvwfl 1 300 train
+tpkgaaratu 1 300 train
+tpksbvlosr 1 300 train
+tpkueujisn 1 300 train
+tpkuvclhgi 1 298 train
+tplfcncfvf 1 300 val
+tplknrvvcg 1 301 train
+tpllvuidve 1 300 train
+tplofbaklk 1 298 train
+tplofwzozz 1 300 train
+tplojghgtf 1 298 train
+tpltcnrezb 1 300 train
+tpltdeedfr 1 300 train
+tplthyxbes 1 300 train
+tpmkyfnlgz 1 300 train
+tpmmmtdoty 1 300 train
+tpngcvxqen 1 300 train
+tpniptcxas 1 300 train
+tpnosbwdyc 1 301 val
+tpnrxwdhvu 1 300 train
+tpnsegvgdq 1 300 train
+tpnstemnyl 1 300 val
+tpnxlnuzsn 1 300 train
+tpocmszkhh 0 301 train
+tpogcinmkk 1 300 train
+tpogqctbge 0 300 train
+tpohuvtilk 1 301 train
+tpoigdwwuk 1 241 train
+tponvddrem 0 300 train
+tpoqsqeatu 1 300 train
+tpotlnaogw 1 300 train
+tpotpmmmuv 1 300 train
+tpphqgrtla 1 300 val
+tpppulohon 1 300 train
+tppunhkvef 0 300 train
+tpqdixzqqk 0 300 train
+tpqglmhtem 1 301 train
+tpqhuyrxes 1 288 train
+tpqixlleie 1 300 train
+tpqkryednb 1 300 train
+tpqkvpeias 1 300 train
+tpqxmppyuy 1 300 train
+tpragfcvet 1 300 val
+tprjeaqlqe 1 300 train
+tprkccmfyh 0 300 train
+tprlyeabci 1 300 val
+tprlzimxkg 1 300 train
+tprnabqyrj 1 298 train
+tprrgequkl 1 300 val
+tprzawmxem 0 301 train
+tpsgathbfh 1 143 train
+tpshsgvjso 1 300 train
+tpslvemxbe 1 300 val
+tpsqqrqexv 1 300 train
+tpssbrfvce 0 300 train
+tpsyixflvr 1 300 train
+tptalpxwlv 1 300 test
+tptcufepei 1 300 train
+tpteooakcd 1 300 train
+tptgkfibny 1 300 train
+tptmjdbpio 1 300 train
+tptrzibaxl 0 300 train
+tptveeqpvb 0 300 train
+tptwynpret 1 300 train
+tpuaaqksjs 1 300 train
+tpubgqiqqv 1 300 train
+tpuekohmmq 1 298 train
+tpuqjkapsg 0 300 train
+tpuymkcccq 1 300 train
+tpvukvpape 1 300 test
+tpvwqbpipy 1 301 val
+tpvyqwleln 1 301 train
+tpvzdfkquv 1 300 train
+tpwclfztft 1 300 train
+tpwijkexhf 1 300 val
+tpwsebtxfp 1 300 val
+tpxcxtjolt 1 300 val
+tpxglrbrkw 1 300 train
+tpxjvkgewy 1 300 val
+tpxkhzhqjk 0 300 train
+tpxpejlgev 1 300 test
+tpxsofwsik 1 298 val
+tpybuszenk 1 300 val
+tpyewpbemi 1 300 train
+tpygxzaern 1 300 train
+tpyiiojxzj 1 300 train
+tpyqxipnjw 1 300 train
+tpyrrhzwkx 0 300 train
+tpyrrrcugn 1 300 train
+tpyrslrlxq 1 300 train
+tpytdanvhz 1 300 train
+tpzcpkffia 1 300 train
+tpzecuwvyf 0 300 train
+tpzexcdnqr 0 300 train
+tpzfqzjpka 1 298 train
+tpzgfwqnqd 1 301 train
+tpzkjzrmwd 1 300 val
+tpzkutkzsc 1 300 train
+tpzqfuwimg 1 300 train
+tpztvhiiyt 0 300 train
+tpzuvantap 1 300 train
+tpzxewnpyt 1 300 train
+tqaaxebfgr 0 299 train
+tqabzfvspv 1 300 train
+tqacgypxts 1 301 train
+tqaeohwrxx 1 300 train
+tqaeqjczaz 0 300 train
+tqaipndobs 1 300 train
+tqavhnyfvs 1 299 train
+tqawtxllam 1 299 val
+tqawydaamw 1 300 train
+tqaztyvwpn 1 300 train
+tqazylqnyz 1 300 train
+tqbfcbzldu 1 240 val
+tqbhqtogog 1 300 val
+tqbosszwmn 1 300 train
+tqbpwjicex 1 300 train
+tqbuhktkzs 0 300 train
+tqcddzwrby 1 300 train
+tqchsroivr 1 301 train
+tqckeepzdz 1 300 train
+tqcnonzrwn 1 300 train
+tqcvwosock 0 300 train
+tqcvzxsmuc 1 300 train
+tqddjtiqzc 1 300 train
+tqdhmwdzho 1 240 train
+tqdixfliwk 1 300 train
+tqdneyzlnu 1 241 train
+tqdocbbvgq 1 299 train
+tqdsgviver 1 300 train
+tqeaflmnhr 1 300 train
+tqeeodxthq 1 300 train
+tqeggikdab 1 300 train
+tqeippsxwe 1 300 train
+tqelzdtdqu 1 300 train
+tqengjgcin 1 300 train
+tqepbbrxcw 1 300 train
+tqesvoueiw 1 300 train
+tqezaylkrn 1 300 val
+tqfabtawrc 1 300 train
+tqfbjandmm 1 299 test
+tqfhvnxumz 0 300 train
+tqfivmjdhj 1 300 train
+tqfqjuqtvy 1 300 train
+tqgiylzbxk 1 299 test
+tqgjmwzsij 0 300 val
+tqgodcuwif 1 300 train
+tqgsgdboir 1 300 train
+tqguikzhjl 1 300 train
+tqhbgzfwsf 0 300 train
+tqhthygumd 1 300 train
+tqhuzdckcc 1 300 train
+tqhwoaaydq 1 300 train
+tqhxvnqfkc 1 300 train
+tqhyoyevor 1 300 train
+tqicffjnbl 1 300 train
+tqijkqktmm 1 300 train
+tqiovjldzi 1 300 test
+tqitdjezhi 1 301 train
+tqitexxknw 1 300 train
+tqixcjetnx 1 300 train
+tqixzrprkc 1 299 train
+tqiyhdxclb 1 300 train
+tqjbbckaqq 1 241 train
+tqjfamkugs 1 300 val
+tqjjothuxf 0 300 train
+tqjkzliath 1 298 train
+tqjmzkjlsd 1 300 train
+tqjnbjnohx 1 298 train
+tqjqiwshyb 1 300 train
+tqjxjwhhlb 1 300 train
+tqjzblvsnk 1 300 train
+tqkfdvizsl 1 300 train
+tqkjwiwcbc 0 300 train
+tqkmtqxtwh 1 300 train
+tqksudximg 1 300 val
+tqkxwtpwpc 1 300 train
+tqlbbllgwz 1 300 train
+tqlfyctkob 1 300 train
+tqljyqrltf 0 300 train
+tqlpegjoiu 1 300 train
+tqlzfqaxci 1 300 val
+tqmfebykyi 1 300 train
+tqmgwvxnjj 1 300 val
+tqmhgwvuzf 1 300 val
+tqmhshfxom 1 300 train
+tqmlplqmrz 0 300 val
+tqmlqemsqb 1 301 train
+tqmmvmxqpn 1 300 val
+tqmnlkgypb 1 300 val
+tqmpbswzip 1 300 val
+tqnneolghh 0 300 val
+tqnpopdflm 1 300 train
+tqnrzvkumn 1 300 val
+tqnvspgtda 1 300 val
+tqnytsurko 0 300 train
+tqnzeyowab 0 300 train
+tqoblsshku 1 300 train
+tqobzwjahr 1 301 train
+tqohkhnjgr 1 300 train
+tqoktgmwqk 1 300 train
+tqolhfajpr 1 300 train
+tqolighuom 1 302 train
+tqomqlndpd 1 300 train
+tqomwetaiv 0 300 val
+tqopvnytds 1 300 train
+tqpdmcmbcc 1 300 train
+tqpgqgxufi 0 300 train
+tqpjrtizgl 1 300 train
+tqpnuqlbqz 1 298 train
+tqpxjalcgw 1 300 val
+tqqdafufch 1 300 val
+tqqjiejdhp 1 300 train
+tqrfkqzkje 1 300 train
+tqriwfsqnm 1 300 train
+tqrizlvlgd 1 300 train
+tqrjmasczr 1 300 train
+tqrlcktjzk 1 300 test
+tqrpjzhfer 1 300 train
+tqrwfbpbzd 1 300 train
+tqrxxjluoo 1 300 train
+tqsbfvillb 1 300 val
+tqsbmniqan 1 300 val
+tqsirljhpd 1 300 train
+tqsmbshugy 1 300 train
+tqsratgvwa 1 300 test
+tqsvnmsohw 1 300 train
+tqtatnepzi 1 300 train
+tqteokvspn 1 299 test
+tqtmevoybn 1 300 train
+tqtoupdnab 1 300 val
+tqtrbwrjwg 1 300 train
+tqtsmvddjz 0 300 train
+tqttbskszw 1 300 val
+tqttmlubzr 1 300 train
+tqttoppjmo 1 300 val
+tqtushrgev 1 300 train
+tqubzfpoum 1 300 train
+tqunzyxiwd 1 300 train
+tquojygjmf 1 300 train
+tquwnrfeiu 0 301 train
+tquwtfmrkx 1 300 train
+tquzovayqv 1 300 train
+tqvbydvocx 1 300 train
+tqvdelijls 0 300 val
+tqvdzgpzwp 1 300 train
+tqvgtimyiu 1 300 train
+tqviutgypu 1 299 test
+tqvnpokbml 1 300 train
+tqvoigiion 1 301 train
+tqvqaxdatc 0 300 train
+tqvtvuvuoz 1 300 train
+tqvubheeue 0 300 train
+tqvyxcxplw 1 300 val
+tqwaudnvzv 1 300 train
+tqwduwmhkw 1 300 train
+tqwpnyunye 1 300 train
+tqwyfihyqu 1 300 train
+tqwzdikjoe 0 300 val
+tqxifjgmbc 1 298 train
+tqxmhhmsyv 1 300 test
+tqxmhyrglp 1 300 train
+tqxmxvofpt 1 300 train
+tqxrfjvcdw 0 300 train
+tqxvppdxgx 1 300 val
+tqxwatjrlg 1 241 train
+tqxxjgaudi 1 300 train
+tqyjydyvky 1 300 train
+tqylfrrrkq 1 300 train
+tqymjlgdsf 0 300 train
+tqynacztnp 1 300 train
+tqypumsbjy 0 300 train
+tqypzygchy 1 300 val
+tqyrwbhoyz 1 300 train
+tqyuwylsxu 1 300 val
+tqyveduvez 1 300 val
+tqyybklunz 1 300 train
+tqzemlqluj 0 300 train
+tqzgxmktuj 1 300 train
+tqzgzujrij 1 300 val
+tqzmwyzfxe 1 300 train
+tqznpzvret 1 300 train
+tqzouiqsne 0 300 val
+tqzuvogoim 1 300 train
+tradwugucx 1 300 train
+tragpkmuit 1 300 train
+traixshodn 1 300 train
+trbaxqmbrj 1 300 val
+trbdicpeov 0 300 train
+trbefryenf 1 300 train
+trbfdajzyy 1 300 train
+trbflipdvl 1 300 train
+trbfvzvpgo 1 300 train
+trbganyvna 0 300 val
+trbgzlulao 1 300 train
+trbofhwxqn 1 300 train
+trbpoeddqz 1 300 train
+trbxbafikz 1 300 train
+trbxpbsrua 1 300 train
+trbzvrewvx 1 300 train
+trccjsqhqv 1 300 val
+trcmcqzilk 0 300 train
+trcpidisyh 1 299 train
+trcrzcqgdb 1 301 val
+trczberdjl 1 300 train
+trdbxmrouu 1 300 train
+trddonzcjv 0 300 train
+trdeyteyky 1 300 val
+trdmmncyhp 1 300 train
+trdwqsonpo 1 301 val
+trdxflaivn 0 300 train
+trdzdmrcdy 1 300 val
+treamiyvjr 1 300 val
+trecjopqxv 1 301 train
+tregpywxpy 1 300 train
+treklubxvy 0 300 train
+trelkpvmtn 1 301 train
+treocxijvi 1 300 train
+treqgkwfhc 1 300 train
+trerignfto 1 300 train
+trfddvqdid 1 300 train
+trfjkrliea 1 301 train
+trflljtoam 1 300 val
+trgeveouxp 0 300 val
+trgfajogvq 1 300 train
+trgfnzdvdu 1 300 train
+trginvkaom 0 300 train
+trgixtifng 1 300 train
+trgnjggsmg 1 300 train
+trgqwykusk 1 300 train
+trgxeznqjh 0 300 train
+trhhpiqqfw 1 300 val
+trhpvvybkf 1 300 train
+trhqexwnno 1 300 val
+trhqrdommy 1 299 val
+trhsvmhhtk 1 300 train
+trhuvltfko 1 300 val
+trhygiyufe 1 300 train
+trifnvfkez 1 300 val
+trihrpvpir 1 300 train
+triirhugvj 1 300 val
+trimxjevrn 0 300 train
+trisvgyxtn 1 300 train
+triwebzkhc 1 300 train
+trjkfsqvwa 1 300 train
+trjnojreci 1 301 val
+trjujuajck 1 300 val
+trkkrhirav 1 239 train
+trkmqwysym 1 300 train
+trkzaxcjdq 0 300 train
+trlcezbeve 1 301 train
+trleisfecz 1 303 train
+trleydxtsd 1 301 val
+trlhchyeij 1 300 train
+trlnvcnomf 0 300 train
+trlpaebjir 1 300 val
+trlrqjfvox 1 300 val
+trlsaggttc 0 300 train
+trltdpitif 1 300 train
+trlxmcrbdm 1 300 train
+trmalppcgd 1 300 train
+trmcaiqewn 1 300 train
+trmcdgwtve 1 300 val
+trmicvlepb 1 301 train
+trmrimvmfc 1 300 train
+trmsvjmltz 1 300 train
+trmviebthh 0 300 train
+trmviskqet 1 300 train
+trmzlmbwqx 1 300 train
+trndgdtwte 1 300 train
+trnmnepudz 1 300 train
+trnobhkyqm 1 300 train
+trnznvybjo 1 300 train
+troirmltsa 1 300 val
+troloutufx 1 300 train
+trolxesysi 0 300 train
+troqylwami 1 300 train
+trpikoisjn 1 301 train
+trpmabgeyv 0 300 train
+trpofaspmo 0 300 val
+trpujbpppb 1 300 train
+trpvqatyjq 1 300 train
+trpxkgffug 1 300 train
+trpyxikerg 1 300 train
+trqburqocr 1 300 train
+trqolsqrxl 1 300 train
+trqoqtfhyj 1 301 train
+trqrbkihfm 1 300 train
+trqwyehsmg 1 300 train
+trrenlxfwz 1 300 train
+trrfqnfnhf 1 300 train
+trrgajdcki 1 302 train
+trrgjelmuc 1 300 train
+trrkhkddif 1 299 train
+trrmubgyat 1 300 train
+trrodhsxof 1 300 val
+trsibjdeqx 1 300 train
+trsmehubwm 1 300 train
+trsomgqkyu 1 300 train
+trspwbjkkp 1 300 train
+trsqoonxko 1 298 train
+trsrhodjti 0 300 val
+trsxhepbiy 1 300 train
+trtasyvhtu 0 300 val
+trtlxaiklz 1 300 train
+trtojatnmr 1 300 train
+trtrgmaieb 1 300 train
+trtsgrbyep 1 300 train
+trtwtgnsii 1 300 train
+trtxfafvta 0 300 train
+trtzvslykq 1 300 train
+trueahnqya 1 300 train
+trukrigvbu 1 300 train
+truoopylcr 1 300 train
+truovigemq 1 300 train
+trupprgvmb 1 292 train
+trupvvuhbb 1 302 train
+truremwrti 1 300 val
+trutamvult 1 300 train
+truwgbqpni 1 300 test
+trveiyrpnt 1 300 val
+trvmsmpdcb 1 300 train
+trvnfzxofg 1 300 train
+trvqryiuqr 0 300 train
+trwdbzydsp 1 300 train
+trwgttshhr 1 300 train
+trwpmgqpib 1 298 train
+trwqtqimvu 1 300 train
+trwucycqvi 1 299 train
+trxdejolnf 1 300 test
+trxfhvnzjv 0 300 train
+trxflypbhl 1 300 train
+trxnelqpyr 1 300 train
+trxnflrfwu 1 239 train
+trxoxgbcps 1 300 train
+trxrunpvcr 1 300 train
+trxtbwcgex 1 300 train
+trxunwqklo 1 269 train
+trxvyohffm 1 300 train
+tryompagoh 1 299 val
+tryqdhfowp 1 300 train
+trzdsncewk 1 300 train
+trziaftapb 1 300 train
+trzkfhabyh 1 300 train
+trzmqcunvu 1 300 train
+trzrrqxqwl 0 299 train
+trzuslwxnh 1 300 val
+tsaeniusmc 1 300 val
+tsahjizngo 1 300 train
+tsajvpfjdk 1 300 train
+tsakdikwxd 1 300 train
+tsalzbhvze 1 301 train
+tsasvgamkg 1 300 val
+tsaufoajpo 1 300 train
+tsavabiikh 0 300 val
+tsbaaxtcby 1 300 train
+tsbczzhory 0 300 train
+tsbjjiafmc 1 300 train
+tsbpntkqqf 1 241 train
+tsbpwarhse 1 300 train
+tsbsvwxfye 0 300 train
+tsbuvexmck 1 298 train
+tsbvorjiix 1 300 val
+tscegfccol 0 300 train
+tscildauwc 1 300 train
+tscirisbab 0 300 val
+tscjhttowt 1 300 train
+tsclngmzde 1 301 train
+tscnylwezq 1 300 train
+tscucodjsf 1 300 train
+tscuocqrau 1 300 val
+tscwdmbhea 0 300 train
+tsdbgfwhah 1 300 train
+tsdgbvepxl 1 300 val
+tsdhmlgsfw 1 301 train
+tsdkoitfxl 1 300 val
+tsdmkalaoh 1 300 train
+tsdyxxkswk 1 300 val
+tsdznnygdu 0 300 train
+tsedyytonr 1 300 train
+tsehzohpdd 1 300 train
+tseijahcuz 1 300 val
+tsemmqvtch 0 300 train
+tseoopukua 1 300 train
+tsevwssfmm 1 300 train
+tsewavfjss 1 300 train
+tsfjumuayd 1 300 val
+tsfoxavpig 1 300 train
+tsgbactcqh 1 300 train
+tsgcssoqur 0 302 val
+tsgrfwkrpq 1 300 train
+tshdcohmxk 0 300 train
+tshfetjhxz 1 300 train
+tshfoikelz 1 300 val
+tshoolpsgy 1 300 train
+tshtheczgj 0 300 val
+tshytxtqiv 1 301 val
+tshzrrgznx 1 300 train
+tsidhveryz 1 300 train
+tsihjrttjt 1 298 val
+tsikjyzgsf 1 300 val
+tsiqgfbvxt 1 147 train
+tsiqukgoov 1 300 train
+tsirnlveao 1 300 train
+tsiukmwwoz 1 300 train
+tsiwpotmvo 1 300 val
+tsiybxecpy 1 300 train
+tsiywxrqja 0 300 val
+tsjabwxwqf 1 300 val
+tsjkocidgd 1 300 val
+tsjlhnfsfy 0 301 train
+tsjpmigtoz 1 300 val
+tsjqnsxetq 1 300 val
+tsjvabvdod 1 300 train
+tskjnnvjsa 0 300 train
+tskkksbvgv 1 300 val
+tslmzdlrwt 1 300 train
+tslqtmoybi 1 300 train
+tsltlmmbfc 1 300 train
+tslvvfelkq 1 300 train
+tslxhjhmwo 0 300 val
+tslxxrlmca 1 298 val
+tsmctsldxx 1 300 val
+tsmgnijtvj 1 300 train
+tsmmqtabuh 1 240 train
+tsnbatvgnr 1 300 train
+tsndinzbyj 1 300 val
+tsniibefcn 1 300 train
+tsntunhtac 1 300 train
+tsnwogqhyu 1 300 train
+tsocsygnwl 1 300 train
+tsonotqqmp 1 300 train
+tsoornnftj 1 300 train
+tsoqqcbsmx 1 300 train
+tsoutamxqz 1 300 train
+tsowxoyixp 1 300 val
+tsphyuydjj 1 300 train
+tspkyrtxxs 1 301 train
+tspmizgqzx 1 300 val
+tspntsgzsw 0 147 train
+tspxsnmgvn 1 298 train
+tsqacaahpj 1 300 train
+tsqkcdohhi 1 300 train
+tsqnshpqga 0 300 val
+tsqrtoxmoj 1 300 train
+tsquvmborq 1 300 train
+tsquvzlopx 1 301 train
+tsrdzfmvvc 1 300 train
+tsrhomotnw 1 300 train
+tsrifkpfwf 1 301 train
+tsrjzzynxa 0 300 train
+tsrngiblym 1 300 train
+tsrpyijjpi 1 300 train
+tsrturndzh 0 300 train
+tsrzkvefwi 1 300 val
+tssdlowath 1 299 test
+tssnkrqorm 1 300 test
+tssnuwdddc 1 300 train
+tssriiuacg 1 300 train
+tsssvunxbs 0 300 train
+tssuodrgon 1 298 train
+tssvjchlwe 1 300 val
+tsswadcspp 1 300 train
+tsswxgwnta 0 300 train
+tssyzhyyjr 1 300 train
+tstdqksicl 1 300 train
+tstecqtwjq 1 270 train
+tstfombuow 1 300 train
+tstsmsltfx 1 300 train
+tstuuttitb 1 300 train
+tsucddxntw 1 300 train
+tsueokowln 1 300 train
+tsuqgeekdl 1 300 train
+tsuwjokkra 1 300 train
+tsuyysvtoq 1 300 train
+tsvblzbrhz 1 300 train
+tsvbsrtcom 0 300 train
+tsvgzwcxnj 1 300 train
+tsvhwitvah 0 300 val
+tsvivpurjs 1 300 train
+tsvkpzczfu 1 300 test
+tsvtztuzyv 0 300 train
+tswfawjeei 1 300 val
+tswmtnhfmn 1 300 train
+tswxrzbmrg 1 300 train
+tsxdgndtjs 1 300 train
+tsxgzcfkik 1 301 val
+tsxkpsxzeo 1 300 val
+tsxlpuzlro 1 300 val
+tsxrpkdjfy 1 300 train
+tsxuijektx 1 301 train
+tsxuvfenqn 1 300 val
+tsycwnssva 1 300 train
+tsyhaasqip 0 300 train
+tsyrafkwre 1 300 val
+tsysmawzmi 1 301 train
+tsysuyuwcn 1 300 train
+tsyterbepz 1 300 train
+tsytikdawz 1 299 val
+tsywoxwcyg 1 300 train
+tsyxvaseol 1 300 train
+tsyzjopkwc 0 300 train
+tszfidtxav 1 300 train
+tszhgiauyc 1 300 val
+tszlmblfyi 1 300 train
+tszltmgdhs 1 302 train
+tszpeiqmlj 1 300 train
+tszqfifqto 1 300 train
+tszsvitufh 1 300 test
+ttaatgafav 1 300 train
+ttaawifovj 0 300 train
+ttabixavia 1 301 train
+ttalapiway 1 300 train
+ttamnrlxel 1 300 val
+ttapcqlwjc 1 300 train
+ttapwbgmsx 1 300 train
+ttarpmofov 1 300 train
+ttaubdahlh 1 241 train
+ttaxezvfah 1 300 val
+ttazkeufcv 1 300 val
+ttbaztvjwt 1 300 train
+ttbazvtelg 1 300 train
+ttbbjjhzwl 1 300 val
+ttbeqetgcm 1 300 val
+ttbkjddrnn 1 296 train
+ttbozizmlx 1 300 train
+ttbxcjfwzf 1 300 train
+ttbxgolmuc 1 300 val
+ttcfoartvz 1 300 train
+ttcjqldbzq 1 300 train
+ttckjjxzlq 0 300 train
+ttcnvnywdv 0 300 val
+ttcpopibvv 1 300 val
+ttcycqpkwf 1 298 train
+ttdeiwijfl 1 300 train
+ttdhvxgfel 1 300 val
+ttdjjdgdpt 1 300 train
+ttdkjruqnb 1 296 val
+ttdljjqpmj 1 300 train
+ttdoufpizp 1 300 train
+ttdpxkthet 0 300 train
+ttdqsoiefg 1 300 train
+ttdqufypgq 1 300 train
+ttdvijptfl 0 300 train
+ttdyyyurmb 1 301 train
+tteascindy 1 300 train
+tteirtovcw 0 300 train
+ttejnjklwk 1 300 train
+ttetdytpgh 1 300 val
+ttevgxparf 1 300 train
+ttfgmhsxms 1 300 train
+ttfljfbadv 0 300 train
+ttgaikzvix 0 300 train
+ttgfcsyfcg 0 300 train
+ttgfxftmyx 1 300 train
+ttgngfkyje 1 300 train
+ttgnpnujpr 1 300 train
+ttgrridluz 1 300 train
+ttgsjzwccb 1 300 val
+ttgwobzpuc 1 300 train
+ttgyygmioj 1 300 train
+ttgzukzxnw 1 300 train
+tthbqtxjzn 1 300 train
+tthdbizdpd 1 300 train
+tthfmeatkb 1 300 train
+tthhuhqfwb 1 300 train
+tthojjjmsi 1 299 val
+tthtrbbwqc 1 300 train
+tthujangcy 1 298 train
+tthvqtkbgs 1 300 train
+tthyjtlxby 1 301 val
+tthzwvzcir 0 300 train
+ttigvhyfql 1 300 train
+ttihkcxndp 1 241 train
+ttihwdmjyp 1 241 train
+ttikysnxik 1 300 train
+ttizjhiwdt 1 300 train
+ttjlwxvogd 1 300 val
+ttjnfovyxd 1 300 val
+ttjooofork 1 301 val
+ttjviidmte 0 300 train
+ttjxosproz 0 300 train
+ttjynsccut 0 300 train
+ttkhxwvmkm 1 300 train
+ttkwwdhyuy 1 300 train
+ttlcpskkju 1 300 train
+ttlpmvmhdv 1 300 val
+ttlyeouzwx 1 300 train
+ttlzknpenh 1 300 train
+ttmcywlhft 1 300 train
+ttmfpigzth 1 300 train
+ttmgegmswe 0 300 val
+ttmqbqqusg 0 300 train
+ttmqsshqer 1 300 val
+ttmrzpktii 0 300 train
+ttmvvejsem 1 300 train
+ttnabjytup 1 300 train
+ttnajmkchw 1 300 train
+ttndcofuso 1 300 train
+ttneifrdwi 1 300 train
+ttnezhrema 1 300 train
+ttnkdaeegv 1 300 train
+ttnlsbcmhh 1 300 train
+ttnmcxixdu 1 300 val
+ttnpcklnuy 1 300 train
+ttnpjbugkg 1 300 val
+ttnqevvpjd 1 300 val
+ttntwrydrg 1 301 train
+ttnvzvoyum 1 300 train
+ttoasmpprn 1 300 val
+ttobmbsfoo 0 300 train
+ttojeckitg 0 300 train
+ttolgnigix 0 269 train
+ttorjyfhxq 1 300 train
+ttorxjzuwe 1 300 train
+ttoyoneodi 1 300 train
+ttparldmom 1 300 train
+ttpjelqpbh 1 300 train
+ttpkekxdrp 0 300 train
+ttpmnmfqyu 1 300 train
+ttpnpcrksg 0 300 train
+ttptjkbgfl 1 300 train
+ttpuegajcg 1 300 train
+ttpyorjpem 1 300 train
+ttqczoopps 1 300 train
+ttqenwctml 0 300 train
+ttqivwztsp 1 300 train
+ttqmlkniio 1 300 val
+ttqorodgfc 1 300 train
+ttquukytcc 1 300 train
+ttqzxsedbv 1 300 train
+ttrojbjmwb 1 300 train
+ttrpqkdans 1 300 train
+ttrvldfybz 1 300 train
+ttryccqkdy 1 288 train
+ttryiygtow 0 300 val
+ttshpcbltc 0 300 train
+ttsiapwbgk 1 300 test
+ttslztqwhg 1 300 train
+ttspguaped 1 300 train
+ttspsxomfi 1 301 train
+ttszqfsoki 1 300 train
+ttthyobsfj 1 301 train
+tttnfmobkg 1 300 train
+tttnqhksxz 1 301 train
+tttpqnxllt 1 300 val
+ttufvfkhuc 1 299 test
+ttuihqevkr 1 300 train
+ttujtsurby 0 301 train
+ttukxwnbwj 1 300 train
+ttunobtudy 1 300 train
+ttuonsdlyo 1 300 val
+ttupsdiplu 1 300 train
+tturtmfind 1 300 train
+ttuufyevkz 1 300 train
+ttuvdnmyue 1 300 train
+ttvboahiwc 1 300 val
+ttvbzmhuvw 1 300 train
+ttvflqupgx 1 300 train
+ttvhcxblqy 1 297 train
+ttvjuizino 1 300 train
+ttvtkvvgts 1 300 train
+ttvuhxbtdm 1 300 val
+ttvvebauxz 1 300 train
+ttvxwzwfqo 1 298 train
+ttvzbvjyff 1 300 val
+ttwevlteef 1 300 train
+ttwhkhnwmh 0 300 train
+ttwjtntofw 1 300 train
+ttwqcaciys 1 300 train
+ttwtyqfhgo 1 300 val
+ttwzibdyja 1 300 train
+ttxgzyncay 1 302 val
+ttxlteiqci 1 300 train
+ttxowtjykr 1 298 train
+ttxuegkaew 0 300 val
+ttxxlrsjio 1 300 train
+ttyivknbzg 1 300 train
+ttylmzjjzo 1 300 train
+ttyltugycf 1 300 train
+ttymvnbfdw 1 300 val
+ttyswwybad 1 300 train
+ttywcqiqod 1 300 train
+ttzdwuqjuj 1 300 train
+ttzeordczl 1 300 train
+ttzfojkcna 1 300 train
+ttzjcgdjue 1 300 train
+ttzugxbojx 1 300 train
+ttzvrcpdlj 1 298 train
+ttzwpvnubk 1 300 train
+ttzyhkkugz 1 300 train
+ttzzprelxj 1 300 train
+tuagcqsqvm 1 300 val
+tuaksmzukt 1 297 train
+tualcoeyyu 1 300 train
+tuambrlror 1 300 train
+tuauvfigxs 1 298 train
+tubdgpgrrl 1 300 train
+tubsamespx 1 300 train
+tubtjxtstv 1 301 train
+tucdskhtcj 1 300 train
+tucfsmbiop 0 300 val
+tucgexaclt 0 300 train
+tucktnnmrw 1 300 val
+tucmlafmmo 1 300 train
+tucmtzezyh 1 301 val
+tucnheakht 1 300 train
+tucqgjzpip 0 300 val
+tucqunndgv 0 301 train
+tuczksimuw 0 300 train
+tudhvzaumf 0 300 train
+tudovrmtmj 0 300 train
+tudppsopzl 1 301 train
+tudyjsuits 1 301 val
+tudzforvyd 1 300 train
+tuedmfsldt 1 300 train
+tueecvtcms 1 298 train
+tuefpaawhm 1 300 train
+tuegzyngiz 1 300 train
+tuehqilqlm 1 300 train
+tuejnxflke 1 300 train
+tuelspyjfu 1 300 train
+tuelzpgmug 1 241 train
+tuexsjexvl 1 300 train
+tufacqdefx 1 300 val
+tufairxmjd 0 300 val
+tufbiaohaq 1 300 train
+tufrizdkdx 1 300 val
+tufvgomcnr 1 300 train
+tufvqtakge 1 299 val
+tufxnslbom 1 299 val
+tufzgfkwla 1 300 train
+tugapbqniy 1 300 val
+tugbcryoqj 1 300 val
+tugduuxria 1 298 train
+tuguvkftxa 0 303 train
+tuhacvtkxk 0 300 train
+tuhdfeqxqo 1 300 train
+tuhhorlytp 1 300 train
+tuhidwjaaq 0 300 val
+tuhizamjah 1 298 val
+tuhjzrwyqm 1 300 train
+tuhkycixjj 1 300 val
+tuhmfvuxbe 1 300 train
+tuhoqckeeq 1 300 train
+tuhplfgyig 1 300 train
+tuhxnjowwx 1 300 train
+tuiamailyy 1 300 train
+tuifmqomsl 1 300 val
+tuigraltwh 1 241 train
+tuitlooreh 1 300 train
+tujiuhdpwg 1 300 train
+tujmfugmuh 1 300 train
+tujmugpbrc 0 300 train
+tujnmixmiw 1 300 val
+tujoqrjrxp 1 300 val
+tukcflhsbq 0 300 train
+tukcocanpj 1 300 train
+tukjsxgkgq 1 300 train
+tukrpygsny 1 300 val
+tuksqjvtmp 1 300 train
+tuktnbjjoz 0 299 train
+tukwtgucft 1 300 train
+tukxjvjyxx 1 301 train
+tulxkqjvty 1 301 train
+tumdyfzmjg 1 300 train
+tumfhsunuy 1 300 val
+tumhpiarww 0 300 val
+tumiaggrwh 1 298 train
+tumlgqqqjt 1 300 train
+tumwdwjkue 1 300 train
+tunmsjunhl 1 300 train
+tunordjlke 1 300 train
+tunskdvtlx 1 300 train
+tunylbakfl 1 300 train
+tunylyceda 1 300 test
+tunzaxvzyd 1 300 train
+tuodlailoc 1 300 val
+tuodvkkxjb 1 300 train
+tuoenkmyun 1 299 train
+tuofsfbqfa 1 300 train
+tuohbdljsz 1 300 train
+tuoijbdgkn 1 300 train
+tuokutdaqu 1 300 val
+tuonorfbpp 1 300 train
+tuouqwwemu 1 301 val
+tuowlpbeyy 1 300 train
+tupariqkuw 0 300 val
+tupbtdthgn 1 300 train
+tupereyivk 0 300 val
+tupifyvthw 1 300 train
+tupkyokihe 1 300 val
+tupuzhcmpz 1 300 val
+tuqdlhdizi 1 300 train
+tuqezcesrs 1 241 train
+tuqgljzqex 1 300 train
+tuqgsyrvsj 1 300 train
+tuqhujzdaj 1 299 val
+tuqnflsxdf 1 300 train
+tuqoizdhbn 1 300 train
+tuqoofucqf 1 300 train
+tuqwnnjcpg 1 300 train
+tuqxtlnsit 1 300 train
+turcevujvw 0 301 val
+turcfqzohb 1 300 train
+turhmezheg 0 300 train
+tusdifubww 1 300 val
+tuseenotyk 1 300 train
+tusnwjncpe 1 300 val
+tuspqonrmz 1 300 train
+tuspwtbyku 1 300 train
+tustdksqvc 1 300 train
+tusyeuetbe 1 300 train
+tutdxyfwva 1 300 train
+tutiwwsydm 1 300 train
+tutjmrbsid 1 297 train
+tutlckgpey 1 300 train
+tuubgkjkmr 1 300 train
+tuufvbwtfk 0 300 val
+tuuqcbbknr 1 300 train
+tuvbppsbqp 1 300 train
+tuvhryncii 1 301 val
+tuvlavlccd 1 301 train
+tuvlvdluyk 0 300 train
+tuvnzuowyw 1 300 val
+tuvwbvrrpe 1 300 train
+tuwospmmrn 1 240 train
+tuwpriwvid 1 300 train
+tuwpwnleww 1 300 train
+tuwqwhvnwi 0 300 train
+tuxbhywzxz 1 298 train
+tuxbzsrszr 1 241 train
+tuxcettlkx 1 300 train
+tuxilwesnn 1 300 train
+tuxkqcphyd 1 300 train
+tuxqumwqtr 1 300 train
+tuxttrixuo 1 297 val
+tuxwejoxwa 1 300 train
+tuycrjemab 1 298 train
+tuykyajhbr 1 300 test
+tuynrrsmff 1 300 train
+tuypqalivh 1 299 test
+tuysjkbime 1 300 train
+tuzevydpuo 1 300 train
+tuzhhlljoc 1 300 train
+tuzjvctlul 1 300 train
+tuznghodsj 1 301 train
+tuzqnzmysx 1 301 train
+tuzzosjhhs 1 300 train
+tvaakmcivp 1 300 train
+tvabuxyehy 0 300 val
+tvaffzeqfg 1 300 val
+tvailvbaln 1 299 test
+tvakgnqyew 1 300 val
+tvaksixieq 1 300 val
+tvakyyfsvb 1 300 test
+tvamzroemc 1 300 train
+tvaoebxlyg 1 300 train
+tvaqsqaiwp 1 300 train
+tvaucrpjyu 1 300 train
+tvaukpnzwq 1 298 train
+tvaxisdvio 0 298 train
+tvazrcdkpq 1 300 train
+tvbemaendu 1 301 train
+tvbmabbsmn 1 300 train
+tvboyzurgi 1 299 train
+tvbvxqnjxo 1 298 val
+tvbwrursff 1 288 train
+tvbzuboeel 1 300 val
+tvcbchahyb 1 300 train
+tvccihmyqj 1 301 train
+tvccutphzk 1 301 train
+tvcjyzkezk 0 300 train
+tvcnkufnaj 1 240 train
+tvcpvybtvo 1 300 val
+tvcthtkrvc 1 300 val
+tvcudsmmsr 1 300 train
+tvdatfpmoh 1 300 train
+tvddjqbhho 0 300 train
+tvdlpqwnzl 0 300 train
+tvdpvooffo 1 300 train
+tvdqmpoctc 1 300 train
+tvdtyyckmf 0 300 train
+tvdymfxwzp 1 300 train
+tvdzwxjcnb 0 300 train
+tvecaxibmw 1 301 train
+tveemckeug 0 300 train
+tvefifmgrt 1 300 val
+tvelhvrphe 0 300 train
+tvfbdavhvq 1 300 train
+tvffpggbrc 0 300 val
+tvfgigqlvc 1 300 train
+tvfsdhxgxz 1 298 train
+tvftbukfve 1 296 val
+tvfurkbios 1 297 train
+tvfyffofef 0 300 train
+tvfyjxvmsi 1 300 val
+tvgalilkud 1 300 train
+tvgmcyuucu 1 300 train
+tvgwxzluns 0 300 train
+tvgxhqxxuu 0 300 train
+tvhdnxlxiu 1 300 val
+tvhjcfnqtg 1 300 test
+tvhmkyenpd 1 300 val
+tvhmzzlgbt 1 300 train
+tvhnnjdkro 1 300 train
+tvhotjkuge 1 300 train
+tvhotrqmlt 1 301 train
+tvhptfwvew 1 300 train
+tvhqrnwctp 1 300 train
+tvhrpxktzp 1 300 train
+tvhwcpfuuz 1 300 val
+tvhwudroac 1 300 train
+tvhziawdmq 1 299 val
+tvifqcgorm 1 300 train
+tvifseguxd 1 300 val
+tvigqdctll 1 300 train
+tvihrjypvr 1 300 val
+tvihzkjdmm 0 297 train
+tviimcqeub 1 301 train
+tvikgdjous 0 300 val
+tvitzaqswn 1 300 train
+tvivejpzsc 0 300 train
+tvivpiqlcq 1 300 train
+tviyeeibss 1 300 val
+tvizjprigb 1 300 train
+tvjasbrchx 1 300 test
+tvjccircgt 1 300 train
+tvjfpzdiar 1 300 train
+tvjgcqlaie 1 300 train
+tvjgxftsea 1 299 train
+tvjlounpor 1 300 test
+tvjpcgbjnc 1 300 train
+tvjrimupbc 1 300 test
+tvjtctrbai 1 300 train
+tvkcxgznur 1 300 train
+tvkgkxuvhb 0 300 val
+tvkgolydsf 0 300 val
+tvkhoafvbd 1 300 train
+tvkomshbiu 1 300 train
+tvktmvdnqm 1 299 val
+tvkwgcxaaq 1 300 train
+tvkxahpxci 1 300 train
+tvldfilpwz 1 300 train
+tvldikzfgo 1 300 train
+tvleyudzsu 1 300 train
+tvlouqncfr 1 300 train
+tvltuhtylm 1 300 val
+tvmcdocvhv 1 300 train
+tvmdobgyfl 1 300 train
+tvmeuhemsm 1 300 train
+tvmhtenbmn 0 300 train
+tvmkyxqlsc 1 299 val
+tvmnokdwuw 0 300 train
+tvmnxkhbgw 1 300 test
+tvmtmtscno 1 300 train
+tvmxozdmtx 1 300 train
+tvmzuxpluu 0 300 val
+tvngstvaua 1 300 val
+tvnhbhcmra 1 300 train
+tvnhmwpqwt 1 301 train
+tvnisvybvq 0 300 train
+tvnogfwxsy 1 301 val
+tvnppdihxj 0 300 train
+tvnpxneyde 1 300 train
+tvnrihazgp 1 239 train
+tvnsqdgkrp 0 300 train
+tvnssyoqqv 1 300 train
+tvnuukeyih 1 300 val
+tvnxbxkepd 1 300 train
+tvolfiusfg 1 299 test
+tvowbquorj 1 300 train
+tvowfywxab 1 300 train
+tvoyqshutk 0 300 train
+tvpbbojlyg 1 297 val
+tvpbumvdsa 1 300 train
+tvpdydluzo 0 300 train
+tvpgycgtdt 1 298 train
+tvphzptlia 1 298 train
+tvpnmwpkcx 1 300 train
+tvppsaexpd 1 300 train
+tvprrlprkh 1 300 train
+tvpsubzwir 1 300 train
+tvpvwxxfhw 1 300 train
+tvqawxstdq 1 300 train
+tvqhwcvmbj 1 294 train
+tvqmbcohnp 1 300 train
+tvqtrqjcqm 1 299 train
+tvqxgtinxr 1 300 train
+tvrbwnuegh 1 300 train
+tvrcvwzlql 0 300 train
+tvrdritale 1 300 val
+tvrgnlmlmd 1 300 val
+tvrmnmnnjr 1 300 train
+tvrnccfcqz 1 300 train
+tvrnrgphyj 1 300 train
+tvrpxmyzky 1 300 train
+tvrwjmjeyn 0 300 train
+tvryxflkia 1 300 val
+tvsaebtpzj 1 300 val
+tvshbatdmr 1 300 train
+tvshjpkytc 1 300 val
+tvskduixkx 1 300 val
+tvsnikdxbb 1 301 val
+tvsutayeom 1 299 val
+tvtccmqnoy 1 300 train
+tvtcytxgox 0 249 train
+tvtczkxdor 1 300 train
+tvtjeyxhve 1 241 train
+tvtldmidst 1 297 train
+tvtomisfeo 1 300 train
+tvtqlopnat 1 301 val
+tvtrxluaca 1 300 val
+tvtvuchjgp 1 300 train
+tvtzzkbvqt 1 300 train
+tvuhwarvfv 1 300 train
+tvulqpavdv 1 300 train
+tvunhrwhol 1 301 train
+tvuoohmsvl 1 300 train
+tvustqhukp 1 300 val
+tvutdegicm 1 300 train
+tvuuzwiaor 1 300 val
+tvuvmuxvoy 1 300 train
+tvvamxrbhp 1 300 train
+tvvbgviufe 1 300 train
+tvvbpeqwui 1 300 val
+tvvqfgzcff 1 300 train
+tvvqnnanvn 1 300 train
+tvvzvvwicn 1 300 train
+tvwjbvsgim 1 301 train
+tvwrmhszkm 0 300 train
+tvwrowvqiy 0 300 val
+tvwwuguahy 1 300 val
+tvwyjnvbff 1 300 train
+tvxcfucbsx 1 300 train
+tvxmiyhtzt 1 300 train
+tvxnfvjtvw 1 300 train
+tvxpfahvzr 1 300 val
+tvxpilzatc 1 300 train
+tvxpwsknsi 0 300 val
+tvxrrbkzog 1 300 train
+tvxymtijbx 1 300 train
+tvxyrmitbf 1 300 val
+tvxzanebzx 1 300 train
+tvyeebmhap 1 300 train
+tvyetovusc 1 300 train
+tvyfhuaqjm 1 300 val
+tvyhhjskpy 1 300 train
+tvyiaovewb 1 300 train
+tvyjpshqql 1 299 test
+tvyrciwxjy 1 300 train
+tvytzeiccz 1 300 val
+tvyxxfdhvj 1 300 train
+tvyynmqlll 0 300 train
+tvzcqaoiok 1 300 train
+tvzkcjpwas 1 300 val
+tvzlpdplrs 1 300 train
+tvzoxhunpp 1 300 train
+tvzpsgkdvx 1 300 test
+tvzpuvfhxk 0 300 train
+tvzqiqimum 1 300 train
+twalqmzbzt 1 300 train
+twaologocl 1 301 train
+twaqtyqdxt 1 300 train
+twauymbvit 1 300 train
+twaxosuslj 0 300 train
+twaxtvjujk 1 300 val
+twbbmcwkuj 1 300 train
+twbejffnfw 1 298 train
+twbherswwp 1 300 val
+twbvktxizv 1 300 val
+twbvssbknk 1 298 train
+twbzqhwfug 1 300 train
+twcockprrc 1 300 train
+twctgyjhnt 1 300 train
+twdduhlgnu 1 301 train
+twdhojvmfq 0 300 train
+twdjnmqbwa 0 300 train
+twdyadyipb 1 300 val
+twdzulstzv 1 300 val
+twedxghltu 1 300 train
+tweflxqdrl 1 300 train
+twehitrqam 1 300 train
+twemijwbsm 1 300 train
+twemxfuput 1 298 val
+twenwjpqvo 1 300 train
+twepznqdsk 1 300 train
+twetrtahtt 1 300 train
+twfcluqtri 1 300 train
+twfdesgsrk 1 300 train
+twfgybpbfc 1 301 train
+twfjiqvgpk 1 300 train
+twfknwahjz 0 300 train
+twfsoikegs 1 300 train
+twftutgael 1 300 train
+twftweslyp 1 300 val
+twfzmwxbix 1 296 val
+twgexzvaqf 1 300 train
+twgjbmodjk 1 300 train
+twgjuuhtzw 1 300 train
+twgkgbovph 0 300 train
+twgnqdszeg 0 300 train
+twgobosowv 0 300 val
+twgsxvgxvq 1 300 train
+twgvbzaecy 0 300 train
+twgvxxxnqv 1 300 train
+twhbdcavuv 1 167 train
+twhhldrxzx 1 300 train
+twhmxneift 1 300 train
+twhnhiaflq 1 300 train
+twhszjfkfx 1 300 val
+twhwouycfg 1 300 train
+twhzxprcqy 1 300 train
+twidckwatq 1 300 train
+twiesdacmg 1 300 val
+twijqqackk 1 301 train
+twimcmzyuo 1 300 train
+twioyfmqvb 1 297 train
+twjasxgdxb 1 300 train
+twjbujrhxb 1 300 train
+twjcgqwjua 1 298 train
+twjdckwave 1 300 train
+twjdwzkxit 1 300 train
+twjkdrkusa 1 299 train
+twjkmepiaf 0 300 val
+twjmkqoybq 1 300 train
+twjpsjdrgn 1 297 train
+twjrrqxque 1 300 train
+twjtwjhdte 1 301 val
+twjtzvvqji 1 300 train
+twjyoaznal 1 300 train
+twkbhtuvyk 0 300 train
+twkcdwrtwd 1 300 train
+twkfmlzuqy 1 300 train
+twkfvezlmn 1 300 val
+twkjnztpdv 1 300 train
+twkpeqxiww 1 300 train
+twkrmeqvjh 1 300 val
+twlgmuvdng 1 300 train
+twlorhhbya 1 298 train
+twlqsedqpe 1 300 train
+twlqsfknpb 1 300 train
+twlsufnadp 1 241 train
+twlttzfjqh 1 300 train
+twmbfdxmxc 1 300 train
+twmdeprxla 1 300 train
+twmdrofgjl 1 300 train
+twmjtstljp 1 300 val
+twmmodfrea 1 300 train
+twmqnnupdi 1 300 val
+twmrmvafjk 1 301 train
+twmrqnzndg 0 300 train
+twmvbgbwff 1 301 train
+twmwxndkae 1 288 train
+twmzbqtwbr 1 298 val
+twnefwbfgk 1 300 train
+twnilkytoe 1 300 train
+twniwdmspv 1 300 train
+twnjzqvlnn 1 300 train
+twnpfjfxaw 1 241 train
+twntheorhj 1 300 test
+twoegzinpj 0 300 train
+twoeqfkfeb 0 300 train
+twogaebjzx 0 300 train
+twojxyxdvh 1 300 train
+twondkoqsr 1 300 train
+twonssxwhw 1 300 train
+tworzxrwuf 0 300 val
+twosaysulj 1 300 train
+twotrytoqh 1 298 train
+twovjcbdmv 1 300 train
+twoypgmkjj 1 242 train
+twpbcxohca 1 300 train
+twpcdzcffq 1 300 train
+twpevxbilh 1 299 test
+twpnqqsilg 1 300 train
+twqggqgsgd 1 300 train
+twqjkgpvlf 1 297 train
+twqjktiolh 1 300 train
+twqonyttvd 1 299 val
+twqoxyzhtk 1 300 train
+twquqdxkfz 1 300 train
+twqwnsblvn 1 241 train
+twqxewnclu 1 300 train
+twqxiioazc 0 300 train
+twqzjwhsit 1 301 val
+twqzvsfqpj 1 300 train
+twrhnxfzuo 1 300 train
+twrmbsvrbk 1 300 train
+twroxkvfjk 1 300 val
+twrpkapnkf 1 301 val
+twrwfstajh 1 300 train
+twrxnnxtje 1 300 train
+twryhnbazi 1 300 train
+twsavjswax 1 241 train
+twsblybdag 1 300 train
+twsbrhrpzm 1 300 train
+twsektzneb 1 300 train
+twsijynhay 1 300 train
+twskdfzqqg 1 300 train
+twsmclzjrd 1 300 train
+twswvdozxs 1 300 train
+twszkxrtqw 1 300 train
+twtafpjrbv 1 300 train
+twtatlojkn 1 300 train
+twtqbhgjlm 1 300 train
+twtrgjvbic 1 300 train
+twtuhwhglv 1 300 train
+twtyfgcvcc 1 300 train
+twubmysxwb 1 300 train
+twuetomiis 1 300 train
+twuibzrspz 1 300 train
+twuiiwhjmo 1 300 train
+twujzdvvby 1 300 train
+twumhemqae 0 301 train
+twuncucpuc 1 300 train
+twunegpglj 1 300 train
+twurqiahju 1 300 train
+twuyxulwye 1 300 val
+twvcmlebof 1 300 train
+twvcumcvdb 1 300 train
+twvdcuwpsu 0 300 train
+twveawiiab 1 302 train
+twvpabzqph 1 300 val
+twvrhdfubk 1 300 train
+twvrkhrcso 1 300 train
+twvvpbtdzm 1 300 train
+twvzxeywqb 1 300 train
+twwqomtcld 1 300 train
+twwreouyna 1 300 val
+twwutvictq 1 300 val
+twwxfkocjh 0 300 train
+twwyffjbsq 1 300 train
+twxargwhjw 1 298 train
+twxfrcqxfu 1 300 test
+twxgdwreye 1 300 train
+twxhtqqvsy 0 300 val
+twxktkkwzv 1 300 train
+twxnazwxup 1 300 test
+twxrauhysz 1 300 val
+twxsfqbvnm 1 300 val
+twymhtbegy 1 300 val
+twyqjppxhj 1 300 train
+twyuptofek 1 300 val
+twyvahcswb 1 300 train
+twyxajmmud 1 300 train
+twyyaczivo 1 300 train
+twzeepmpbr 1 301 train
+twzeouyuag 1 300 train
+twzknvarpc 1 301 train
+twznnuzhuh 1 300 train
+twzqmdwuse 1 300 train
+txaamomnpj 1 300 val
+txaetgbbne 1 300 train
+txaflmzbrh 1 300 train
+txafsjtkoj 1 300 train
+txagznfgvj 1 300 train
+txakcpkxrn 1 300 train
+txaxkqsifu 1 300 train
+txbdtwgibv 1 300 train
+txbjwlckfc 1 300 val
+txbmthvjzm 1 300 val
+txboupeqha 1 300 val
+txbqzsvgje 1 300 train
+txcbkicwgk 1 300 test
+txcbqzervc 0 300 val
+txcegmtcte 0 300 val
+txcfmwkgld 1 300 train
+txcyyfxaws 1 300 train
+txdcmspaaa 1 299 train
+txdewjtqjl 1 300 train
+txdhkcamyp 1 300 train
+txdkyyqons 1 300 train
+txdlctsgnz 1 300 train
+txdofdqlfp 1 300 train
+txdoftsego 1 300 val
+txdpukhdbs 1 300 train
+txdumtqkvi 1 299 train
+txecywhbwn 1 300 train
+txeflzyhit 1 301 train
+txeivwgivy 1 300 val
+txeqrbrbta 1 300 train
+txetdkigdm 1 300 train
+txewxgasrw 1 300 train
+txfbbrjymc 1 301 train
+txfhiwipsr 0 300 train
+txflmhcbav 1 300 train
+txfozivwlq 0 300 train
+txfpvolpnm 1 300 train
+txfymgwywr 0 301 train
+txfyxohbso 1 147 train
+txgbgzkiza 1 300 train
+txgnvdjpfl 1 300 val
+txgpzepsiq 1 300 train
+txgqzdwslh 0 300 train
+txgvmnalxq 1 300 train
+txhdxalijo 1 300 train
+txhedicful 1 298 train
+txhibvcheh 1 300 train
+txhmbhmfen 1 300 train
+txhmrahjzu 0 300 val
+txhptdopqg 1 300 train
+txhvyhbyig 0 600 train
+txhxcswliu 1 300 train
+txiegxfhjs 1 300 val
+txigfcrvgz 0 300 train
+txilgtwyvc 1 300 train
+txisadkjdc 1 300 val
+txitsdxsby 1 300 train
+txivqvoruo 1 299 val
+txjbljqgze 1 298 val
+txjbxfpihu 1 301 train
+txjevrpmby 1 300 train
+txjgmrrnrs 1 300 train
+txjgnebtoi 1 300 train
+txjjrgclao 1 300 train
+txjlsuxtxu 1 300 train
+txjrxrvmsi 1 300 train
+txjsrwbdfo 1 300 train
+txjxlaiaey 1 300 train
+txjymvxbgf 1 300 train
+txkiaghiuj 1 300 train
+txkkbfzoyj 1 300 train
+txkmfseehd 1 300 train
+txkrodkgpj 1 300 train
+txktatkuhe 1 300 train
+txkunepczb 1 300 train
+txkvjjizry 1 300 train
+txlablpnaf 1 300 train
+txlanwjbwq 1 300 train
+txlbaahrjw 1 300 train
+txldwapzna 1 298 val
+txljinhqzx 0 300 train
+txloqnorpa 1 300 train
+txlqytmqqn 0 300 val
+txlthnwdgj 1 300 train
+txlvflemac 1 300 val
+txlwdahhmc 1 300 train
+txlzfnddji 1 300 train
+txmnoyiyte 1 300 test
+txmqqegfba 1 300 val
+txmswkzxhz 1 301 train
+txmtssaobb 1 99 train
+txmumsxqzj 0 300 train
+txmwfufuqw 1 300 train
+txnboiqfaa 1 300 train
+txnmkabufs 0 300 test
+txnrcvllsg 1 300 val
+txnykzvjhu 1 300 train
+txodvfaajx 1 300 train
+txofupwyxj 1 300 train
+txokuxlkif 1 300 train
+txonkpwlxv 1 240 val
+txopvwjpho 1 297 train
+txoqxgixmn 1 298 val
+txoroydndn 1 300 train
+txowuqeova 0 299 val
+txphoyrjzs 1 300 train
+txplcagttp 1 300 train
+txpsdrqaqv 1 300 train
+txpwiknfnx 1 300 val
+txpwntdhmq 1 300 train
+txpybjybdh 1 300 train
+txqadxnpew 1 300 val
+txqbhiluyg 1 300 val
+txqeizhvzf 1 300 train
+txqfblxkkt 0 300 val
+txqfnonsfk 1 300 train
+txqhduvlpn 1 299 val
+txqishnmth 1 300 train
+txqjviakef 1 300 train
+txqkcjverp 1 300 train
+txqnlrtkmc 1 300 train
+txqpyangbo 1 300 val
+txqsljyirt 1 300 train
+txrfaceegd 1 288 train
+txrjrakxll 1 300 train
+txrosoxcab 1 300 train
+txrpnykqqy 1 300 train
+txrsqajykv 1 300 train
+txrxokszxv 1 301 train
+txrzsutbun 1 298 train
+txsevwbcfp 1 300 train
+txshgvrava 0 300 train
+txskugbkar 1 300 train
+txsplscctm 1 300 train
+txsqtuwbqf 1 300 train
+txsxcwznxe 1 300 train
+txsyoxlotc 1 300 train
+txsyzefnur 1 300 test
+txtbpgfzzi 1 300 train
+txtcnkprtn 1 239 train
+txtrbqitgt 0 300 train
+txtwccefim 1 300 train
+txtzdfwgvx 0 300 train
+txucekgbek 1 298 train
+txueqmcalh 0 302 train
+txufvsufou 0 300 val
+txugtcxqgj 1 300 val
+txumuwmlvw 1 300 val
+txurtylnlv 1 300 train
+txvaqhlhts 1 300 train
+txvcwipjsf 1 299 test
+txvfdvoxfa 1 300 train
+txvfkjorjf 1 300 train
+txvodfpnmy 1 300 train
+txvsucfafy 1 299 train
+txwodmrpij 1 298 train
+txwplezfea 1 300 train
+txxebsjqvw 0 300 train
+txxevapkkh 1 300 train
+txxswotlzl 1 300 train
+txxungvxms 1 300 test
+txxydiyety 1 298 train
+txxyjdxsmz 0 300 train
+txybycxcxq 1 300 train
+txygbgjpxk 1 298 train
+txyprjavbo 1 300 train
+txyseddquo 1 300 train
+txysmzzvch 1 298 train
+txywmpduxj 0 300 train
+txznpvdplj 1 300 val
+txzqertcbx 1 301 train
+txzydhejdx 1 300 val
+txzzgoudlf 1 300 train
+tyaakhhemf 0 300 train
+tyakheorkb 1 302 val
+tyamaxmysq 0 300 val
+tyatbyiulg 0 300 train
+tybayeuopi 1 300 train
+tybdsmbofg 0 300 train
+tybhacjkty 1 300 train
+tybhlzloyu 1 300 train
+tybjnixgub 0 300 val
+tybrtkszjl 0 300 train
+tybxsyvhko 1 300 train
+tybzfcbqqf 1 300 train
+tycakarvpn 0 300 train
+tycckhxejh 1 300 train
+tycjqobctl 1 300 train
+tyckuuocay 1 301 train
+tycnpummbw 1 300 train
+tycukywbas 1 300 train
+tycvfrhzlq 1 300 train
+tydcmnkvzb 1 300 val
+tydgbpqhws 0 300 train
+tydhmmabra 1 300 train
+tydwfsugaq 1 300 train
+tyefqvlhtd 1 300 train
+tyeqemuntr 1 300 train
+tyeqhfshgt 1 300 val
+tyevgzbeyc 1 300 train
+tyeylevexm 1 301 train
+tyezdclxvc 0 300 train
+tyfkqgzvhn 1 300 val
+tyfshvrbtx 1 300 train
+tyfsqzssvt 1 301 train
+tyfwbskxbs 1 300 val
+tyfwmpccch 1 300 train
+tyfxosqosz 0 300 train
+tygatpmvwr 1 300 train
+tygaurfrgm 0 300 val
+tygdxvvjlk 1 300 train
+tygfcetojw 1 300 train
+tyggornfxw 1 300 val
+tyglqjlgmo 1 300 val
+tygltdzubn 1 300 train
+tygwurlgrs 1 300 train
+tygwzobwco 1 300 train
+tygzlpfsmy 0 300 val
+tyhcyogsop 1 239 train
+tyheigivpq 1 300 train
+tyhjwgdupc 1 300 val
+tyhkrheolg 1 300 val
+tyhmvguzyd 1 298 train
+tyhpiabguv 1 301 train
+tyhrrwxdmb 1 300 train
+tyhrtgjmoa 1 300 train
+tyhxxjltbs 1 300 train
+tyhykbqbab 0 300 train
+tyiaqcxwix 0 300 train
+tyiazydvns 1 300 train
+tyiezazgug 1 300 train
+tyifsjalvr 1 298 train
+tyijqmixbp 1 300 train
+tyijytqowe 1 300 val
+tyirisslih 1 300 train
+tyiwrbwibo 1 300 train
+tyjaebbgyl 1 298 val
+tyjdtibczq 1 300 train
+tyjfjxobtr 0 241 train
+tyjhravbjf 1 298 train
+tyjpjpglgx 0 300 test
+tyjwcdmgfu 1 300 train
+tyjxmknivy 0 300 train
+tykghgkrpm 1 300 train
+tykguezggp 1 300 train
+tykkinunxx 1 300 train
+tykngavssg 1 300 train
+tykpfgtcgd 1 300 val
+tykqnrffer 1 301 train
+tykrhbejbe 0 300 train
+tyktexgzhh 0 300 val
+tyktzdbkjg 1 300 train
+tyldpyudek 1 300 train
+tylfjhnwbr 0 300 train
+tyluelydzm 0 300 train
+tylvomxqjp 1 300 val
+tylvugyyfy 1 300 train
+tymcuyunhe 0 300 train
+tymfvwlmzk 1 300 val
+tymhvqkpdp 1 301 train
+tymjllbiif 1 301 train
+tymngtaytz 1 240 train
+tymtoibcmn 1 300 train
+tymyjhafis 1 300 train
+tynejafvov 1 300 train
+tynfjqrmqg 1 300 train
+tynfsthodx 1 299 test
+tynhsppcvp 1 301 val
+tynmvmtvbv 0 300 train
+tynocfjdtv 1 300 val
+tyoajgawsz 0 301 val
+tyobejnzyu 0 300 train
+tyobywlmuv 1 300 val
+tyocdxkstw 1 300 train
+tyohgpnmbs 1 298 train
+tyojwenpaf 0 299 train
+tyopeuxlqa 1 302 train
+tyoptvxczl 1 300 train
+tyopvoqpga 1 301 train
+tyowfefncw 0 300 val
+typbhdcoun 1 300 train
+typcleiyai 1 300 train
+typjuqzmhy 1 300 train
+typpgrthrh 1 298 train
+typtqkjnva 1 300 train
+tyqbfidphg 1 299 val
+tyqceggtuf 1 300 train
+tyqjqawlyu 1 300 val
+tyqktgfvhq 1 300 train
+tyqqnncxki 1 301 val
+tyqrlwsjji 1 300 train
+tyqywmyqas 1 300 train
+tyqziqvxhw 1 300 val
+tyrclauybz 1 241 train
+tyrhexxoge 1 300 train
+tyridwujmx 1 300 train
+tyrkdrfzsg 1 300 train
+tyrnpwxzju 1 300 train
+tyrpdghbfo 1 240 train
+tyrqomxjhx 1 300 train
+tyrvednxoc 1 301 train
+tyrzltyeet 1 300 train
+tyscjrxabn 1 300 train
+tyshwhdnti 1 300 train
+tysijgdpdi 1 301 val
+tyspjrtmot 1 300 train
+tysqvcnuqt 1 300 train
+tysrnftddc 0 301 train
+tyswjkrowg 1 300 train
+tytawcpdlj 1 300 val
+tytbsxygwa 1 300 train
+tytjzblcbu 1 300 val
+tytlxfqksf 1 300 train
+tytpmxdyan 1 300 train
+tyttpgphnn 1 301 train
+tyuddojeib 1 301 val
+tyuiftjksw 1 300 train
+tyuneuphue 1 300 train
+tyuogvsbjg 1 300 val
+tyvaqjlgfq 0 300 val
+tyvctlnqma 1 146 train
+tyvehspuil 0 301 val
+tyvnebhivl 0 300 val
+tyvwufmegc 0 300 train
+tyvzvipgtn 1 297 train
+tywfbwlowa 1 300 train
+tywgogemum 1 300 train
+tywkofgusd 1 300 train
+tywrqoumuc 1 300 train
+tywrtuthpr 1 300 train
+tyxhsjclja 1 300 val
+tyxiuohdfk 1 300 val
+tyxkyfapkf 1 300 val
+tyxldynimg 1 301 train
+tyxnbpqrhj 0 300 val
+tyxsgbghyz 1 300 train
+tyyfzycpci 0 300 train
+tyyhrqvnry 1 300 train
+tyyijtlgys 1 300 train
+tyymzqnciy 1 300 train
+tyysmwpxmt 1 300 val
+tyyvblvcfi 1 300 train
+tyyvocmgve 1 300 train
+tyywgzbcnb 1 300 train
+tyzafyeaif 1 300 test
+tyzdvdxmra 1 300 val
+tyzovrtcoe 1 300 train
+tyzozcjoxq 0 300 train
+tyzqpgyhhp 1 300 train
+tyzunexroh 1 300 train
+tzablgewui 0 300 train
+tzafafmqrl 1 302 train
+tzaicpbnog 1 300 train
+tzamrgyzbv 1 300 train
+tzarmiufzl 1 300 train
+tzaxqnlyhn 1 300 train
+tzbfmcwjrg 1 300 train
+tzbglleskg 1 300 train
+tzbmwkkmja 1 300 train
+tzbnbzlpoh 1 300 train
+tzbpevdzwr 0 300 train
+tzbqgormqk 1 300 train
+tzbrooiwuk 1 300 train
+tzbvbyswxf 1 300 val
+tzbvkfvsik 1 300 val
+tzbwnrrnqr 1 300 train
+tzbxeejafc 1 298 val
+tzcaptwwkt 1 301 train
+tzcdyqctcl 1 300 val
+tzcevfmbaz 1 300 train
+tzcjlfnget 0 300 train
+tzcmeuimda 0 300 val
+tzcuzyosrc 1 300 val
+tzczmqjzpw 1 300 train
+tzdanyvort 1 300 train
+tzdbqhknxg 1 300 train
+tzdcqvlqhx 0 300 val
+tzdozaagcd 1 300 train
+tzdpzecrys 1 300 train
+tzectnaqyj 0 300 train
+tzeeodmaxn 1 300 train
+tzegdvincl 1 300 test
+tzekgxhwkw 1 300 val
+tzekijbzcl 1 300 val
+tzepjrndgb 1 300 train
+tzeushzkoj 0 300 train
+tzewrcebfr 0 300 val
+tzfapzrglv 1 300 val
+tzffjidlrz 1 300 train
+tzfkenqmcp 1 300 train
+tzflghmsed 1 300 train
+tzfmnbjgmz 1 300 train
+tzfsaupara 1 300 train
+tzftvixuzs 0 301 train
+tzgaghfpww 1 300 train
+tzgdtdugrt 1 300 val
+tzgoroiixc 0 300 train
+tzgwrkyhps 1 288 train
+tzgxwlubnr 1 298 val
+tzgyftrshu 1 300 train
+tzhbdzcrbt 1 300 train
+tzhcjdvaoi 1 300 train
+tzhgzykjri 1 300 train
+tzhotvejsw 1 299 test
+tzhqbgyftz 1 300 train
+tzhumpeijr 1 300 train
+tzhvatiemi 1 300 train
+tzickiqkiu 0 300 train
+tzieufabln 0 300 train
+tziifpanvw 1 300 train
+tziqxffotj 1 300 train
+tzjfoqatss 1 300 train
+tzjjothtsl 1 301 train
+tzjrdtitkv 0 300 train
+tzjuyqnkiv 1 300 train
+tzkdfmmbcu 1 241 train
+tzkglkvofq 1 300 val
+tzkhizsovr 1 300 train
+tzkjsmmsiy 1 298 val
+tzkkqywuqz 1 300 train
+tzkowrralc 1 300 train
+tzkwtsrsvf 0 300 train
+tzkxumuidc 1 300 val
+tzlakogkik 1 300 train
+tzlcyvbqwd 1 299 test
+tzlgahhccz 1 300 train
+tzlnewnwbj 1 300 train
+tzltrgvjdn 1 298 train
+tzmcnaynzv 1 300 val
+tzmgkvkqvz 1 300 train
+tzmithsdcj 0 300 train
+tzmizwnrky 1 300 val
+tzmjpwetxk 1 300 val
+tzmjxuyilb 1 301 train
+tzmlfaphbg 1 300 train
+tzmqfjsfxp 1 300 val
+tzmrgkevvj 1 299 test
+tzmzcszhiv 1 300 train
+tznaadzmsu 1 300 train
+tznfndhciu 1 300 train
+tznjkubiml 1 301 train
+tznkzweueh 0 300 val
+tznmodvzoy 1 301 val
+tznntzqsou 1 300 val
+tznpkoutag 1 300 train
+tznxngxohy 1 300 train
+tzodxkvvdq 0 300 train
+tzodzyzhwx 1 300 train
+tzoiwglzin 1 300 train
+tzopbjhajl 1 300 train
+tzorcbkbzp 1 300 train
+tzorrxrczq 1 300 train
+tzorwbqvcn 1 300 train
+tzovcturqn 0 300 train
+tzowhyhbvu 1 300 train
+tzowwbwfwe 0 300 train
+tzpcnkkilq 1 300 train
+tzpdgetbpu 1 300 val
+tzpeafqzfs 1 300 train
+tzpgvrhwyn 0 300 train
+tzphntivkm 1 300 train
+tzplyjrchz 1 300 train
+tzpsftgtpv 1 300 val
+tzpueoxeor 1 300 train
+tzqacklzyt 1 300 train
+tzqazzdwlx 1 300 train
+tzqbhtvflg 1 299 val
+tzqhgawmxh 1 298 train
+tzqkxihefo 1 300 train
+tzqllvhpan 1 300 train
+tzqqrnnvbb 1 300 train
+tzqtflkqou 1 300 train
+tzqukzzdtl 1 300 val
+tzqxbrfngi 1 300 train
+tzqzwyxbby 1 241 train
+tzrcdmavkm 1 301 val
+tzrhguqmvb 1 300 train
+tzrjwnqzui 1 300 train
+tzrmdeizco 1 300 train
+tzrwnpqyev 1 300 train
+tzrzdrntqg 1 300 val
+tzserxwijb 1 300 train
+tzslitnyzp 1 300 train
+tzsnrrptgs 0 300 train
+tzsvcngsgo 1 300 train
+tztayrjnhd 1 300 train
+tztcxgbols 1 300 train
+tztczcujqt 1 300 train
+tztehbwdcg 0 300 train
+tztgmmhgqu 1 300 train
+tztibdgnuf 1 300 train
+tztmjhnjrc 1 300 val
+tztmsxucpa 1 300 val
+tztptbrdld 1 300 test
+tztvmnllop 0 301 train
+tzuooyvbgp 1 300 train
+tzuqmumzrs 1 300 train
+tzutfefcgv 1 300 train
+tzuulawcdw 1 300 train
+tzuwhnvrfv 1 300 train
+tzvifcoosi 0 300 train
+tzvimvnydj 0 300 train
+tzvmedqksb 1 301 val
+tzvtevhkgm 1 300 train
+tzvtmdyaon 1 300 val
+tzvupxegqs 1 300 train
+tzvvzcdldj 1 300 train
+tzwdvmzjce 1 301 train
+tzwitggfhn 1 300 train
+tzwjkdgfcy 1 300 train
+tzwjmlybpn 1 300 train
+tzwjstiltl 1 300 train
+tzwrmkepyc 1 300 train
+tzwthejbpe 1 300 train
+tzwtnxyxfa 1 300 train
+tzwywrsuvl 0 300 train
+tzxbrzacpa 1 300 train
+tzxdpjtvme 1 300 val
+tzxganphod 1 300 train
+tzxivnjskh 0 300 train
+tzxkecwsxq 1 300 train
+tzxyodclxt 1 300 train
+tzybvmvyyd 1 300 val
+tzyeyrkbxv 1 300 train
+tzyhepkkew 1 300 train
+tzyjdrfjtd 1 301 train
+tzykcbbgqp 1 300 train
+tzykmkyfro 1 300 train
+tzymnaotuh 1 300 val
+tzyvvtyfzf 1 300 train
+tzzcwyfjrt 1 300 train
+tzzfvhicxf 1 300 train
+tzzfwjxmwc 0 300 train
+tzzkpikzcx 1 300 train
+tzzlcdmsge 1 298 val
+tzzowhqrfw 1 300 val
+tzzpofvhji 1 300 train
+tzztpzvjik 1 300 train
+tzzwqaxtrk 1 300 train
+uaatopoexy 1 300 train
+uaazyxkykq 1 301 train
+uabnmkxtsd 1 240 train
+uaboxxxiqy 1 300 train
+uabqscrwqg 1 300 train
+uabtksaprw 0 300 train
+uaceohcklh 1 300 val
+uacgfljxrz 1 300 train
+uacorxsmpx 1 300 val
+uacpdaskeu 1 300 train
+uacsjjovzb 0 300 train
+uacsvpnhdr 1 300 train
+uacueksmdr 1 300 train
+uadarctaqw 1 300 train
+uadclmhbxx 1 300 val
+uadjqcpazo 1 301 train
+uadktddymi 1 300 val
+uadntefipb 1 300 train
+uadnxpgsyw 1 300 train
+uadqvxwsxp 1 300 train
+uadynooxit 1 298 train
+uaeidlznqh 1 300 train
+uaemumjygq 1 300 train
+uaeoblrhcf 1 300 train
+uaeokyodum 1 300 train
+uaeublhbow 1 300 train
+uaeuppoqrx 1 298 train
+uaewfsclwg 1 300 train
+uafgnqzztf 1 298 train
+uafllzhzps 1 298 train
+uafpckeiyf 0 300 train
+uafpynytut 0 300 train
+uafrormjab 1 300 train
+uagajqmiiv 1 300 train
+uagcrisovu 1 300 train
+uagkrixiwa 1 300 train
+uaglxwxjpm 1 300 train
+uagrzcpqfo 1 300 train
+uagswfjjsm 1 300 train
+uagwnsoszd 1 300 train
+uagxmizlpv 1 301 train
+uahckunyap 1 301 train
+uahdoyjqqv 1 300 val
+uahdvyrizu 1 300 train
+uahedawjmj 1 300 train
+uahjxhawtw 1 300 val
+uahmcdqhgo 1 300 train
+uahxrmkpkt 1 300 train
+uaikpklbvs 1 300 train
+uaipnqqlhm 1 240 train
+uaisxmqcfy 1 300 train
+uaivywpfxw 1 300 train
+uaixvsxxyi 1 300 train
+uajavewshp 1 143 train
+uajcixseap 0 300 train
+uajjaufaap 1 300 val
+uajjhgjkbr 1 299 val
+uajmaxyvix 1 299 test
+uajsewmluo 1 300 train
+uakcetqnvc 0 298 val
+uakltsxjsy 1 300 train
+uakmltagvm 1 300 val
+uakqhmniih 1 300 train
+uaksgtuuny 0 300 train
+uaksqasofl 1 300 val
+uakvwcppkc 1 300 train
+uakyftdzes 1 300 train
+ualfefzngn 1 300 train
+ualsryghmv 1 300 train
+ualwurxlal 1 300 train
+ualxxctfjq 1 241 train
+ualxzvqonf 1 300 train
+ualynkvqch 1 300 val
+uambqlgxwt 0 300 val
+uamfjuwhqh 1 297 train
+uammvwkybn 1 297 train
+uamozyuslc 1 300 train
+uamukpictq 1 300 train
+uanfjvhdnk 1 300 train
+uannnudkig 1 300 train
+uantlrvpff 1 300 train
+uanuuvqwnt 1 300 train
+uaocvaeghd 1 300 train
+uaodigowvs 1 300 train
+uaogqdzhip 1 298 train
+uaonslxgtx 1 300 train
+uaoqmpdrxz 1 300 val
+uaoymbdjpo 1 298 train
+uapcteqzjn 1 300 train
+uapnddxvjk 1 300 train
+uaprallcni 1 300 train
+uapshbefsa 1 300 train
+uaqdjknzvr 1 300 train
+uaqsajoudl 0 300 val
+uaqurcripg 1 300 train
+uaqvffouxp 1 300 train
+uaqxrykyxq 1 300 test
+uarbsevgjo 1 300 val
+uarfnpuayt 1 300 train
+uarkueisee 0 300 train
+uarqstmana 0 300 train
+uartgdodtb 1 299 val
+uarxfpjgrr 1 300 train
+uasfuejxjq 1 300 train
+uasniqlskr 1 300 val
+uasnsagodn 1 300 train
+uasondsxfr 1 300 train
+uasontfiho 0 300 train
+uaspniazcl 1 300 test
+uasrjxxrpl 1 300 train
+uasrnbxdby 1 300 train
+uasrterhcr 1 241 train
+uasvwbgjge 1 298 train
+uaswhaeaoi 1 298 train
+uatauijxdr 1 300 train
+uatcwhzzke 1 300 train
+uatehnumgl 1 300 val
+uatlzzxvvo 1 302 train
+uatnrewegx 1 300 train
+uatqhvjbqu 1 300 val
+uatsfwahwn 0 300 train
+uattabslit 1 300 train
+uatziuqdfx 1 300 test
+uauaqljioo 1 300 train
+uaudywgnfk 1 300 train
+uaukglhmje 1 300 test
+uautjmprzo 1 300 train
+uauvrioftl 1 299 val
+uavcnuldga 1 300 test
+uavdtoiawe 1 300 train
+uavfzwknsp 1 300 train
+uavnqivqas 1 300 train
+uavoytxkcd 1 300 val
+uavwpeximn 1 300 train
+uavxwetbmp 1 301 train
+uawcwshloc 1 300 train
+uawflbaxia 1 300 train
+uawheugzzu 0 300 val
+uawkbkukve 1 300 val
+uawnxfdeof 1 300 train
+uawpvduxkr 1 300 train
+uawvmqhsyo 1 298 train
+uawyxbchtv 1 300 train
+uaxmqpmswz 0 300 val
+uaxnalzsde 1 302 train
+uaxoybuwem 0 300 val
+uaxpsobtgs 1 300 train
+uaxuujmjkz 1 300 test
+uayicqrxqd 1 300 val
+uayiyymdsw 1 300 train
+uayodrbpyi 1 300 train
+uaytppmydj 1 299 train
+uayuxdqzjd 1 300 train
+uayzvvmhjr 0 300 train
+uazbhwyysx 0 300 test
+uazggumuvf 1 300 val
+uazqfdtslm 0 300 train
+uazuxdwcjg 1 300 train
+uazxeiwcrh 1 300 train
+ubaczmonai 1 300 train
+ubaegqolay 1 300 train
+ubaeqdbaut 1 300 val
+ubaeweaqpx 1 301 val
+ubafabjhrj 1 297 train
+ubamjoeswt 1 301 train
+ubarhvreoj 0 300 train
+ubasafrfsx 1 300 val
+ubasuwcnrj 1 300 train
+ubbelngqln 1 300 val
+ubbqzreokx 1 300 train
+ubbwqjlefp 1 300 train
+ubbwxjtcxo 1 300 val
+ubbzrfgzer 0 300 train
+ubcnhlrrdk 0 300 val
+ubcqrlglnr 1 300 train
+ubcsjlizsw 1 301 val
+ubctqmglhv 0 300 train
+ubczzzocep 0 300 val
+ubdadjgzbo 1 300 train
+ubdedjnpyr 1 241 train
+ubdkgejvtl 1 299 test
+ubdouhkxfs 0 300 train
+ubdvfljeha 0 300 train
+ubdwihstre 1 241 train
+ubdwojnsrq 1 300 val
+ubebziknbg 1 300 train
+ubeftiwrrg 0 300 train
+ubepvjjdlm 1 300 train
+ubeujmdnbg 1 300 train
+ubeutewpwa 1 300 val
+ubewydpmgn 1 300 train
+ubeydrocht 1 300 train
+ubfagtsurd 1 300 val
+ubfdqxoxry 1 300 train
+ubfimnnqyw 1 300 val
+ubfrqinwri 1 301 train
+ubfrzcphlm 1 300 train
+ubfyjffadv 1 300 train
+ubgbencriw 1 300 train
+ubgdanvzzx 1 300 train
+ubgeozxdug 1 299 test
+ubgmfzorgx 1 300 train
+ubgvhnlxkb 1 300 train
+ubgwmqxugd 1 300 train
+ubhxbrmrhk 1 300 train
+ubiaxzquoa 1 296 val
+ubieghmqdq 1 298 train
+ubiqtdnewk 1 300 train
+ubiybggquz 1 300 train
+ubjbdllbil 1 300 train
+ubjqfjmljw 1 300 train
+ubkhkdghhr 1 298 train
+ubkjgqjzwl 1 300 train
+ubklgctsek 1 300 train
+ubkwegucdc 1 241 train
+ubkwscggmo 1 301 val
+ubkykpofff 1 300 train
+ubkznqreys 1 300 train
+ubleacpfxh 1 300 val
+ublfumrjsq 1 300 train
+ubliqtsusq 0 300 train
+ubljcvpxun 1 300 train
+ublxtefugk 1 300 train
+ubmidxsman 1 300 train
+ubmmgsumut 1 300 train
+ubmnraecqz 1 300 val
+ubmrdjftxe 1 300 val
+ubmugwqfol 1 300 train
+ubnbtwquoq 1 300 val
+ubnciwtuox 1 300 train
+ubnevwpkgd 1 300 train
+ubnfluppcb 1 300 train
+ubnjfybeou 1 300 train
+ubnrrjdfeg 1 300 val
+ubnshdcnzk 1 297 train
+ubnxmiqwim 0 300 train
+ubnxuyqwvf 0 300 train
+uboebnjurz 1 300 val
+ubogmlusof 0 300 val
+ubogsfrlzy 1 300 train
+ubopcfrdsf 1 300 train
+uboptyspww 1 300 train
+uboyerjjcq 1 300 val
+ubpbrbkmuz 0 298 train
+ubpeywbkpb 1 298 train
+ubplsigbvj 0 300 train
+ubptcynhaj 1 300 train
+ubpxbvweiv 1 300 val
+ubqaymjceb 1 298 train
+ubqffrolzv 1 300 train
+ubqmcudjhb 1 300 train
+ubqpakoobv 1 300 train
+ubqwpyqdnj 1 300 val
+ubqzolzarg 1 300 train
+ubrbrhhhpp 1 241 train
+ubrhdfbyre 1 300 train
+ubrkwlhgmr 1 300 train
+ubrquujnks 1 99 train
+ubrvtqznom 1 300 train
+ubscyrnxsp 0 300 train
+ubsdkdgdov 1 300 val
+ubsmsgyakt 1 300 train
+ubsnavshog 0 241 train
+ubsnvmvfyr 1 300 train
+ubsrtauwrn 1 300 train
+ubsvhgqphc 1 300 train
+ubsytrahus 1 298 train
+ubtdgoxibk 1 300 train
+ubtebdmyrd 1 269 train
+ubthgcffiw 1 300 train
+ubtikiqoeg 1 300 val
+ubtknwmhyi 1 301 train
+ubtptsudra 0 300 train
+uburnkuytf 1 300 val
+ubutlicfsd 1 300 train
+ubuuvzzviu 1 241 train
+ubvbukkwmo 1 300 train
+ubvetbtujo 1 300 train
+ubvfwekawe 1 300 train
+ubvlokfrmm 1 300 train
+ubvnkpfgcx 1 300 train
+ubvnwlwuky 1 300 train
+ubvokqnitj 1 300 train
+ubvqirgajh 0 300 train
+ubvqrpevrn 1 300 train
+ubvugaiutf 1 300 train
+ubwceumtst 1 300 val
+ubwgmlzjzc 1 299 test
+ubwpzmleuc 1 300 train
+ubwwnofjvs 0 300 train
+ubwywdsyyc 1 300 val
+ubwzhahybr 1 300 train
+ubwztrlvjd 1 300 train
+ubxbahkkwj 1 300 train
+ubxfbuyruz 1 300 val
+ubxlhztujz 1 300 val
+ubxljabbvc 1 300 val
+ubxtgmoxjg 1 300 train
+ubxunrtocn 0 301 val
+ubxvubymps 1 300 train
+ubxxfhlgtm 1 300 train
+ubydbjxdmr 0 167 train
+ubyeqyguvq 1 300 train
+ubyhbxawde 0 301 val
+ubyopwazjr 1 300 train
+ubyrgvlqlz 1 300 train
+ubznssaspg 1 300 val
+ubzoyfwmzz 1 300 train
+ubzqkaoqbk 0 300 train
+ubzrwqyevt 1 300 val
+ubzwpartrm 1 300 val
+ucacfasdqc 0 300 train
+ucahnqkqim 1 300 train
+ucazfkenjx 1 300 train
+ucbakeloqw 1 300 train
+ucbfsyxnuu 1 300 train
+ucbgfvxgcf 1 300 train
+ucbpzgqevc 1 299 train
+ucbwlgzlto 1 301 train
+ucbxvhpnqi 0 300 train
+ucbzlaiaut 1 300 train
+ucckvgaels 1 301 train
+uccnkjyonv 1 301 train
+uccpzqrgsb 1 300 train
+uccwyoqmtq 1 300 test
+ucdcxqjxxy 1 300 train
+ucdeuyjsbf 1 297 train
+ucdxdikiee 1 300 val
+ucebwhrynr 1 300 val
+uceijqqerw 1 297 train
+uceiqpzeke 1 301 train
+uceuudgijr 1 300 train
+ucewivzjea 1 300 train
+ucewnzqmex 1 300 train
+ucexeajwns 1 300 train
+ucfczepxoq 1 300 val
+ucfdcyuint 1 298 val
+ucfghukirq 1 298 train
+ucfhnvwydk 1 300 train
+ucfjthhfqr 1 300 train
+ucfmrreqff 0 300 val
+ucfogqvbft 1 299 val
+ucfoqnytpf 0 300 train
+ucfpotzguv 1 301 train
+ucfuqbrrcc 0 300 train
+ucfzsgwxxf 1 298 val
+ucgaxulxxy 0 300 train
+ucgkhrsose 1 300 val
+ucgkzhfujq 1 301 val
+ucgookdwqm 1 300 train
+ucgozpljle 1 300 val
+ucgpxynzid 1 300 train
+ucgzjcoxyo 0 300 val
+ucheuhoqvo 0 300 train
+uchjtnhizc 1 300 val
+uchjyaeqnm 1 300 train
+uchpigmzkd 1 300 val
+uchtxmzvpe 1 300 train
+uchuazawmt 1 300 train
+uchulctitk 1 300 train
+uchzxjmkgi 0 300 val
+ucidfsqdkw 0 301 train
+ucigwusacz 1 300 train
+ucijajsrtu 1 300 train
+ucinamccsx 1 301 train
+ucipjeryff 1 300 train
+ucjdnexpkr 1 300 val
+ucjehtpbxt 1 300 train
+ucjhjbljlm 0 300 train
+ucjntwnyyd 1 300 train
+ucjppdixjz 1 301 train
+ucjqufyrhm 0 300 train
+ucjsidtzve 1 300 train
+ucjzvclvrq 1 300 val
+uckeigqcml 1 300 train
+uckkghmdor 1 300 train
+uckkigrcoo 1 241 train
+ucklvdjlcr 1 300 train
+uckonrvlnr 1 300 train
+uckooqqnlm 1 300 train
+uckscgssmu 0 300 train
+uckwompfii 1 299 train
+uckwrdlojc 1 300 test
+uclacnshpd 0 300 val
+uclaifhwxb 0 300 train
+uclaxvjnqx 1 300 train
+uclgdotbct 1 300 train
+ucljktpwrh 1 300 train
+ucllbckgkc 1 300 val
+uclqapwfwl 1 299 train
+uclruqbktp 0 300 train
+uclzxnftij 1 300 train
+ucmaekqmxy 1 300 val
+ucmfbukrkj 0 300 train
+ucmfhfurwx 1 241 train
+ucmgkukqpg 0 300 val
+ucmjjvdmzf 1 300 train
+ucmxdeamtw 1 300 train
+ucmxzhjjio 1 300 train
+ucmyvirgny 1 300 train
+ucnbccruar 1 300 train
+ucnehbdydg 1 300 train
+ucnnsarnao 1 300 train
+ucnsejrsgq 1 300 train
+ucorsbcixd 1 300 train
+ucorvldjhi 0 300 train
+ucotuvlloo 0 300 train
+ucozjmuzvz 1 300 val
+ucpcewqgtl 1 301 val
+ucphiclnkk 1 300 train
+ucpjibvvus 1 300 train
+ucpnuwaszw 1 300 train
+ucpokgvxup 1 300 val
+ucputfupah 0 300 train
+ucpxblzsvo 0 300 val
+ucqjnnypsz 1 300 train
+ucqqhfygcg 1 300 train
+ucqrttbieb 0 300 train
+ucqvmegfci 1 300 train
+ucqvmhltqw 0 300 train
+ucqvmmhbhv 1 302 train
+ucqxtucqva 1 301 train
+ucrcbovlbu 1 239 train
+ucrdqczhtu 1 301 val
+ucrffulyjt 1 300 train
+ucrhplzmbs 1 298 val
+ucrodisezz 1 300 train
+ucrpkxqxoy 1 300 train
+ucryyubbqk 0 300 val
+ucrzkzlepu 0 300 train
+ucsapfougv 1 300 train
+ucsllepjbe 1 300 train
+ucsqdtucfi 1 300 train
+ucsxrkwjeu 1 167 train
+ucszfyitlr 0 300 train
+uctbvfvnzs 1 301 train
+uctbxbimav 1 300 train
+ucteqgplkr 1 300 train
+uctexlbetl 1 300 train
+uctgggbrii 1 301 train
+ucthmsajay 0 300 test
+uctnnuqyxe 1 300 train
+uctofipyeo 1 300 train
+uctrjndkze 1 299 val
+uctwqnogiy 0 300 train
+uctzrohtlt 1 269 train
+ucuckkkwiz 1 601 train
+ucuczetzbs 1 300 train
+ucufuvhwqv 1 300 val
+ucugtwgmrt 1 300 train
+ucuicuxuum 1 300 train
+uculsaoukm 1 297 train
+ucunavdvhn 1 300 val
+ucuoymuoyj 0 300 train
+ucuqokvtum 1 300 train
+ucuyjcbdbt 1 300 train
+ucuziogliw 1 300 train
+ucuzjytluc 1 300 train
+ucveegzccr 1 269 train
+ucveeogevx 0 300 train
+ucvfkwojqm 1 300 train
+ucvfnmzafz 1 300 train
+ucvkzepdqe 1 301 train
+ucvpytpixm 1 298 val
+ucvpzauvoh 1 300 val
+ucwbwoqylo 1 300 val
+ucwhvgauch 1 302 train
+ucwhygvsrx 1 301 train
+ucwptrurrn 1 300 train
+ucwqruljku 1 300 train
+ucwtjcuwoo 1 300 train
+ucwvxiyvtm 0 300 train
+ucwwycqpeu 0 300 train
+ucwxcxmfiz 1 300 val
+ucxazxenwk 1 300 val
+ucxdacbmhu 1 300 train
+ucxdugalts 1 300 train
+ucxjlujwfm 1 300 val
+ucxlzfxvlr 1 241 train
+ucxnaqenaw 0 300 train
+ucxowzeosz 1 300 train
+ucxvmskxnq 1 300 train
+ucydtsgsnd 1 300 val
+ucyfyfdzzp 1 301 train
+ucyntzndlr 1 300 val
+ucyuwurana 1 300 train
+ucyvjyqswr 1 300 val
+uczdixentp 1 300 train
+uczgcrolis 1 301 train
+uczixqxtpq 1 300 train
+uczjjwgkoz 1 300 train
+uczjlslprk 1 300 train
+uczkzjljxv 1 300 train
+uczpqizegg 1 300 train
+uczwkxwjpb 0 300 train
+udaamfyjqd 1 298 train
+udaayppxcy 1 300 train
+udaltwcgch 1 300 val
+udanghwruk 1 300 train
+udaquseplm 1 241 train
+udbjrvwqmr 0 301 train
+udbmhdgkkb 1 300 train
+udbmmuvkbe 0 300 train
+udboanabcz 1 300 train
+udbqzbqoty 1 300 train
+udbsdiyrus 1 300 train
+udbygnpoix 1 300 train
+udcixxbaef 1 300 train
+udcmnfwzmq 1 300 train
+udcpjfvqro 1 300 train
+udcvbjmalz 1 300 train
+uddbkeoobm 1 300 train
+uddguruvej 1 300 train
+uddhsafcuq 0 300 train
+uddmjkewsv 1 300 train
+uddnbiezbv 1 300 train
+uddsbdybad 0 300 train
+udecjhfbev 1 300 train
+udecqcgqgr 0 300 train
+udeqznwkle 0 300 val
+udfaxgzbcm 1 240 val
+udfhgndovq 0 301 train
+udfiqkaajp 1 300 train
+udfkqszmoq 1 300 train
+udflcpvawb 1 300 train
+udfmgkjhnq 1 300 train
+udfmguouqh 0 300 train
+udfppwnevm 1 300 train
+udfpulrpay 1 302 train
+udfrgunvim 1 300 val
+udfrzoydrj 1 300 val
+udghprzqpq 1 300 val
+udgrldcppn 1 301 train
+udgswgspcm 0 300 train
+udgtlywrmt 1 300 val
+udgvikcfwh 1 300 val
+udgxoewuqf 1 300 train
+udhdgaacgr 1 300 val
+udhgyxhfgx 1 300 train
+udhjcljtxr 0 300 train
+udhmrgwpss 1 298 train
+udhoamgxmx 0 300 train
+udhpbnlglb 1 300 train
+udhrjqdycg 0 241 train
+udhrnsnbmb 1 300 test
+udhrscmeet 1 298 val
+udhynmbmkw 1 301 train
+udialxiebo 1 300 train
+udiapjqeaf 1 300 train
+udibpixgcr 0 300 train
+udiekxzeus 1 300 train
+udjaxrdxcq 1 300 test
+udjeghexzb 1 241 train
+udjqbuaqch 1 300 test
+udjrommryg 1 300 train
+udjtmpppuj 1 300 train
+udkaiwgcoo 1 241 train
+udklffwmgy 1 300 train
+udkrxqdbmx 1 300 train
+udlbacrypm 1 300 train
+udldxmeurc 1 300 val
+udlhyjwokj 1 300 train
+udlipwvqdl 0 300 train
+udlnnrvcms 1 301 train
+udlqvdbwad 1 300 train
+udlyqiyemy 1 300 train
+udmaefzqln 0 300 train
+udmeldbnbc 1 300 train
+udmibqkqsz 1 301 train
+udmlfkqvrz 1 300 val
+udmpufyrfh 1 301 val
+udmtsgatoq 1 300 train
+udmyftnraz 1 300 train
+udngnaopdr 1 300 train
+udnjgmsonh 1 300 train
+udnxjwmglg 1 298 train
+udoaggmzvh 1 300 val
+udondgvmxg 1 300 train
+udopdmkptf 1 300 train
+udoprmzaws 1 300 train
+udorrtoaqi 1 300 val
+udovtbsosl 1 300 val
+udoxycwubo 1 300 train
+udpcrpdhgg 1 300 train
+udpmccmnpt 1 300 test
+udpmeyovdm 1 300 test
+udppbnlqdu 1 300 train
+udpubrmkln 1 300 val
+udpvsbvwew 1 300 train
+udpvvkhltc 1 300 train
+udpxeyppqp 1 300 train
+udqafcvkrw 1 147 train
+udqlxkgvxf 1 301 val
+udqmtqsfgp 1 300 train
+udqofwtnxu 1 300 val
+udqrmgwulo 1 300 train
+udqwignmmk 1 300 val
+udqyrzfepv 1 300 train
+udrgwezxft 1 300 train
+udrnceyomx 1 301 train
+udrpnanxeq 1 300 train
+udrptynqyk 1 300 val
+udrttqwocj 1 300 train
+udrvghemqu 1 300 train
+udsaeobgzy 1 300 train
+udsfonlruc 1 300 val
+udsomuueeq 1 300 train
+udsyeyojsn 0 300 train
+udtlwsptql 1 300 train
+udtnheecwi 1 300 train
+udtnqddjvx 1 300 train
+udtzggatoe 1 300 train
+udtzmtjbji 1 300 train
+uduhjboqul 1 295 train
+uduidrxdge 1 300 train
+udvbdqsfdj 1 300 train
+udvbpkubnz 1 300 train
+udvgmhbasx 1 298 train
+udvgzianem 1 300 train
+udvjwmiwlr 0 300 train
+udvkbiatof 1 300 train
+udvrglbfcm 1 300 train
+udvxxbufeo 1 300 train
+udvyumbltk 1 300 train
+udvzsjgjjv 1 300 train
+udwcmvzmmk 1 300 train
+udwdqdktao 1 300 train
+udwfnpifkh 1 300 train
+udwiuopdab 1 300 train
+udwoqyttxx 1 300 train
+udwttqzpjs 1 301 train
+udxadxgjxe 1 300 train
+udxeurhjxf 1 300 train
+udxlfkswse 0 300 train
+udxqbhgvvx 1 300 test
+udxqxrslun 1 298 train
+udxsalqcdk 1 241 train
+udxtaaipdt 1 300 train
+udxwofolfs 1 300 train
+udxxviwfkw 1 301 train
+udybabnsxp 1 300 val
+udybhjzjsw 1 241 train
+udybvrbzfv 1 300 val
+udygaigkzn 1 300 train
+udykwnzior 1 300 train
+udynlsccpj 1 299 test
+udynwctfkp 1 300 train
+udyoafhagx 1 300 train
+udzcqwjwin 0 300 train
+udzgjsohky 1 300 train
+udzjuhzkyw 1 300 train
+udznkrcupa 1 300 val
+udzpbdfxxq 1 300 train
+udzqgcvpyc 1 300 train
+udzuptdfzl 0 300 val
+udzzxugsdm 1 300 train
+ueabrnwrlj 1 300 val
+ueaevadbmn 1 300 train
+ueaexetysz 1 300 train
+ueamkomtbu 1 298 train
+ueanhqjneu 1 301 train
+ueaohhmcwb 1 300 train
+ueatdgjfmi 1 300 train
+ueazlabegv 0 300 train
+uebjocpkna 0 300 train
+uebkyvdovg 0 300 train
+uebtnuadbc 1 300 train
+uebwuafhgq 1 300 train
+ueckxmmefk 1 300 train
+uecmszugeu 1 300 train
+uecxyvbgnj 1 300 train
+uedejxevad 1 300 train
+uedfohquje 1 300 train
+uedhrkjsts 1 300 train
+uedzgrjgki 1 300 train
+ueeehxaezp 1 300 train
+ueengmtdnl 1 300 train
+ueepreoehb 0 300 train
+ueetmeckna 1 302 val
+ueeunxfric 0 300 train
+uefibkzmxf 1 300 train
+uefkfmrohb 1 300 train
+uefoskteyl 1 300 train
+uefsfqvskz 1 300 val
+ueftcpewmr 1 300 train
+uefwvpunuf 1 300 val
+uefyogluva 1 300 train
+uegbdtjxgz 0 300 val
+uegcobaebi 1 300 val
+uegkvbnpwm 0 300 train
+uegmuuwlzn 1 300 train
+uegqrilsda 1 299 train
+uegqzewkua 1 301 train
+uegsvqxklf 0 300 train
+uehbcgdudu 0 300 train
+uehgflgibx 1 300 train
+uehtfqvijt 1 300 train
+uehxlrribj 1 300 val
+uehywpeftz 1 300 val
+uehzaxtxgw 1 300 train
+ueibdvpitk 1 300 val
+ueidqotxkz 1 300 train
+ueiedsygit 1 299 val
+ueigtgcuwb 1 300 train
+ueinjvcjae 1 300 train
+ueiowljylm 1 300 train
+ueitvhiums 1 300 val
+ueiwbnwwsb 1 298 train
+ueixxpsyhm 1 300 train
+uejhmqjwwn 1 300 train
+uejsvcmacb 1 298 train
+uejubakasq 1 300 train
+uejxckekrt 1 300 train
+uejyfbbyzy 1 300 train
+uekajbdhzg 1 301 train
+uekbdxgnip 0 300 train
+uekbkglyof 1 300 train
+uekhnsggfp 1 300 train
+uekiaunxsu 0 300 train
+uekizhdyud 1 298 train
+uekjzshnwo 1 300 train
+uekvmpoqdv 1 300 val
+uekwpshfam 1 300 train
+uekzpmhjti 1 300 train
+uelanbinme 1 300 train
+uelcstudya 1 299 val
+uelefitims 1 300 train
+ueletbodbr 1 300 train
+uelhshxcqc 1 300 train
+ueloqkqbta 1 300 train
+ueloristnk 1 300 train
+uelpyoxrzk 1 300 val
+uelvovtuiv 1 300 train
+uelyvmonzs 1 300 train
+uembubqfms 1 300 train
+uemcrujvid 1 300 train
+uemdnrvyos 1 300 train
+uemmkfspec 1 300 val
+uemnawybdf 1 300 train
+uempltmwyb 1 300 train
+uemrhunqfg 1 300 val
+uemryxhskr 0 299 train
+uemwnzdgjl 0 301 train
+uemxcwafyc 1 300 val
+uenjyupjyj 1 239 train
+uenlihzayc 1 300 train
+uenpgrxnir 1 240 train
+uenpvojsdc 1 300 train
+uenuibtcuw 1 300 val
+uenwpeiaev 0 300 train
+ueobjeflda 1 300 train
+ueocpwunji 1 301 train
+ueoduqehgw 1 300 train
+ueodzoosxm 1 300 train
+ueonhdvfdb 1 300 train
+ueoosdrklc 1 300 train
+ueovyeengl 1 300 train
+uepdruryum 1 300 train
+uepnpgrhzn 1 300 train
+uepsmvfvyy 1 300 train
+uepsxmapxp 1 300 train
+uepwnmexak 1 300 train
+uepzadisje 1 300 train
+ueqbcbqpep 0 300 train
+ueqdjrngyo 1 300 train
+ueqemgevkh 1 301 train
+ueqfguswof 1 298 train
+ueqfshfour 1 300 test
+ueqgyxnlnl 1 300 train
+ueqkvhbihn 1 300 val
+ueqlgnkiiz 1 300 train
+ueqsirkzed 1 300 train
+ueqxiroiqn 0 300 train
+uerapqglmr 1 300 train
+uerfbpgdbq 1 300 train
+uerglzmire 1 300 val
+uerijyeaoj 1 300 train
+uermksedmu 1 300 train
+uernqkytai 1 300 train
+uerpntagly 1 300 train
+uerqfdfhvk 1 300 val
+uersnquxyv 1 300 train
+uertjvswzh 1 300 train
+uervoluite 1 300 train
+uerzhgwhhn 1 301 val
+uerzocxziu 1 301 train
+uerzvukiaw 1 300 train
+uesajynrjx 1 300 train
+uesasehikd 1 300 train
+uescttvvue 0 300 train
+ueshqvntrl 1 300 train
+uespfgstut 1 300 train
+uesrhvqztn 1 300 test
+uesxldpvdl 1 300 train
+uesxuupyjh 1 300 train
+uesyklfgjj 1 300 train
+ueszxbwgkz 1 300 train
+uetfcmaryk 0 300 train
+uetiqgpkut 1 300 train
+uetnqujivl 1 300 train
+uetqkzhzyq 1 300 train
+uetstgvnnh 1 300 train
+ueubtanxdy 0 300 train
+ueuccsgqug 1 300 train
+ueuewllftq 1 300 train
+ueukrlauqc 1 298 train
+ueunbhpksq 1 301 train
+uevfzpgrbk 1 300 val
+uevqmhiddt 1 300 train
+uevqvnwoye 1 299 train
+uevxdeenvj 0 300 train
+uevxtvppdn 1 301 val
+uewjjyovkw 1 300 train
+uewmpueacf 1 300 train
+uewrivutuy 1 300 train
+uewvyltinv 0 300 train
+uexmgefzxy 1 300 train
+uexriibzil 1 298 train
+uexroisrtm 1 300 train
+uexujmaowq 1 300 test
+uexutnlpdh 1 300 train
+uexybopqor 1 301 val
+uexzgjidiw 1 300 train
+uexzuieavb 1 299 test
+ueyaftmaci 1 300 train
+ueyccdhgfr 1 300 train
+ueyklehmkg 1 300 val
+ueylrpqvce 1 300 val
+ueylwuwyie 1 300 train
+ueynafyyvu 1 241 train
+ueynkqgvdh 1 300 train
+ueypichnye 0 300 train
+ueyqiwnaka 1 300 val
+ueytxdmdpn 0 300 train
+ueyvyjtycn 0 300 val
+uezivatpvs 0 300 train
+uezqggbrcf 0 300 train
+uezqwzdfso 1 298 train
+uezwpfgtzq 1 301 val
+uezyltahpe 1 300 train
+ufaclhfpjs 1 300 val
+ufadqtpbwp 0 300 train
+ufaeofhqmy 1 300 train
+ufaigyxttb 1 300 test
+ufamzlflqa 1 300 train
+ufamzokjmq 1 300 train
+ufasbwlwuh 1 301 train
+ufavdaiyyi 1 300 train
+ufbbmuquvp 1 300 train
+ufbisqiyxp 1 300 train
+ufbknuufrs 1 300 train
+ufblkfgvzy 1 300 train
+ufbnvxizjh 0 240 train
+ufbpnozltu 1 299 val
+ufbtccwmhu 0 300 train
+ufbtjxjhfe 1 300 train
+ufbyulvjxa 1 300 train
+ufcbemjchn 1 300 train
+ufckihneoa 1 300 train
+ufcxtzoxhl 1 300 train
+ufdphycjtk 0 300 val
+ufebcwsraz 1 300 train
+ufedyttzhu 1 300 val
+ufeeoveuks 0 300 val
+ufehtrprux 1 300 test
+ufekrzhfrw 1 300 val
+ufeqnlerfw 1 300 train
+ufeyqlcmqu 1 300 train
+ufezgkiqjy 1 300 train
+uffbcmondb 1 300 train
+uffdtmiwep 1 300 train
+uffgkqnynv 1 300 train
+uffktidjaz 0 300 train
+uffopxgdzh 1 300 train
+uffpenifmn 1 300 train
+uffsdzapva 1 300 train
+uffvswrkim 1 300 train
+ufgbzfywfz 1 300 val
+ufgethuzey 1 300 train
+ufglaqhwvn 0 300 train
+ufgnkssdme 1 300 train
+ufhhfehiju 1 240 val
+ufhjyqzqky 1 298 train
+ufhmekgpzq 1 300 train
+ufhptnarfy 1 300 val
+ufhsosbhrl 1 300 train
+ufhumrlnqm 1 300 train
+ufienyulkw 1 300 val
+ufifaektfz 0 300 train
+ufiiglcdnh 1 300 train
+ufimmamzor 1 300 train
+ufimvjjche 1 300 train
+ufipyxggkp 1 300 train
+ufiqqkffrk 1 299 val
+ufiwltnbqn 0 300 val
+ufiyqckars 1 300 train
+ufizpokygp 0 300 train
+ufjbgrrbpc 1 300 test
+ufjeoyfjpj 1 300 train
+ufjfromxmw 1 300 train
+ufjhkhldct 0 300 train
+ufjibzdkqq 1 300 train
+ufjlphjhzy 1 300 train
+ufjubuswod 0 300 train
+ufkgroaxik 0 300 train
+ufkkogcskn 1 300 train
+ufktnnzrev 1 300 val
+ufkuvxsouo 1 300 train
+ufldhiyoue 1 300 train
+ufleamtwer 0 298 train
+uflkladpvr 1 600 train
+uflkvyginx 1 300 train
+uflmfdrfhb 1 300 train
+uflprpvhhy 1 300 train
+uflqkzgkmr 1 300 val
+uflrjpsqzs 1 298 train
+uflxvlverf 1 301 train
+ufmaxtcrwz 1 300 train
+ufmccwojed 1 300 train
+ufmhtoqirq 1 300 train
+ufmnipobjc 1 300 train
+ufmoxddxcd 1 300 train
+ufmuhoaetg 1 301 train
+ufmulnhely 1 300 train
+ufmuprtnyx 1 300 train
+ufnbfvyfih 0 300 train
+ufnclfkxtl 1 300 train
+ufnjieanun 1 300 train
+ufnjtesmuh 1 300 train
+ufnufdtqtt 1 300 train
+ufnxektzbk 1 300 val
+ufocnkykps 1 300 train
+ufodhtzvmm 1 300 train
+ufogdrppkw 1 299 val
+ufoipgblmn 0 300 train
+ufolikvolv 1 300 val
+ufomydjjvm 1 300 train
+ufphvibxhl 1 241 train
+ufplgyxega 1 300 train
+ufpmkakssk 1 300 train
+ufpnuejkxz 1 300 train
+ufptyivwgr 1 300 train
+ufpuqhsfxu 1 300 train
+ufpxtididk 0 300 train
+ufqdkwuzeb 0 300 train
+ufqeokijvk 0 300 train
+ufqjmibvkq 1 300 train
+ufqlylhixm 0 301 val
+ufqqirebbp 1 297 train
+ufqqjghikx 0 300 train
+ufqsdaorjg 1 300 train
+ufqtdvalsm 1 240 train
+ufqvupdrvh 1 298 train
+ufrcftifgq 1 300 train
+ufremskbnb 0 300 train
+ufrgkqebsw 1 300 train
+ufrizjdfqj 1 300 val
+ufrmqiuklb 1 300 train
+ufrnitcaqt 1 300 train
+ufryblrohx 1 300 val
+ufsbizfrxl 1 300 train
+ufscdwpbkw 1 300 train
+ufsircwtcv 1 300 train
+uftamnqijh 1 300 train
+ufthszxsxv 1 300 train
+uftlyvxgtj 1 300 train
+uftrzkegbd 1 302 train
+uftuqhiyzi 1 300 val
+uftzuzdncw 1 300 train
+ufucquemsr 1 298 train
+ufulktfywv 1 300 train
+ufummndxvq 1 300 train
+ufunfswczg 0 300 train
+ufuphfzglj 1 300 train
+ufutnmxzzp 1 300 train
+ufvfndsadp 1 300 train
+ufvhgbesxf 1 300 train
+ufvzzuptyk 1 288 train
+ufwezjezip 1 300 train
+ufwgsgjurv 1 301 val
+ufwilcbdjv 1 300 val
+ufwjozzcpd 1 300 val
+ufwsepxqbr 0 300 val
+ufxafdxpat 0 301 train
+ufxfgwvreh 1 298 val
+ufxfhowwwm 1 300 train
+ufxgosbnnv 1 255 train
+ufxjihpsnj 1 301 train
+ufxkptofgh 1 300 val
+ufxkymbqik 1 300 train
+ufxotzkgda 1 299 val
+ufxxihccqa 1 300 train
+ufyenconbv 1 300 val
+ufyiaejjmt 1 300 train
+ufymigddma 1 300 train
+ufynlwmnos 1 300 val
+ufynsihjit 1 300 train
+ufyrmbxahb 1 300 train
+ufyvkriwut 1 300 train
+ufyyxquyaa 1 136 train
+ufyznbuayi 1 300 train
+ufzeqrrfad 1 300 train
+ufzhmhimyf 1 299 test
+ufzmblbemg 0 300 train
+ufzoikhlpv 1 300 val
+ufzpaevwrr 0 300 train
+ufzpkasigm 1 300 train
+ufzqvoaozx 1 300 train
+ufzrjhsqkw 1 300 train
+ufzrwyudhr 1 300 train
+ufztcqwftt 0 300 train
+ufzurbscda 1 300 train
+ufzwbdynqt 1 300 train
+ufzxfkwaxx 1 300 val
+ugaeyybdeg 1 300 train
+ugafanvnqp 0 300 train
+ugafqbbxhq 1 300 train
+ugafxncrge 1 300 train
+ugagvibmsu 0 300 train
+ugahgbupwz 1 300 train
+ugamwfwnmq 1 300 train
+ugaplgxvls 1 301 val
+ugappgpcty 1 300 train
+ugbkexlzgv 1 299 test
+ugbqimxwhj 0 300 train
+ugbvacemrs 1 300 train
+ugbvcucfwc 1 300 train
+ugbymbawuh 1 300 test
+ugcazrivrj 1 300 train
+ugccizzpzk 0 300 val
+ugcgahiiob 1 300 train
+ugclmpzvjq 1 300 val
+ugcmhosdjs 1 300 val
+ugcsnrygxc 1 300 val
+ugcuqdtqqf 1 300 train
+ugcuxrlfwo 1 300 val
+ugcvaezeio 0 300 train
+ugdccvnrxi 1 300 train
+ugdepqjmlc 1 300 train
+ugdlazckto 0 300 train
+ugdoarifto 1 300 train
+ugdqkhzuiq 1 300 train
+ugdteljfgb 1 300 train
+ugegbxipye 1 300 train
+ugehfvqgbq 0 300 train
+ugepabcunl 0 300 train
+ugephsatdc 1 300 train
+ugeqwqcmzb 1 298 train
+ugeuuziexz 1 296 train
+ugevnsoemv 1 300 train
+ugexakzhom 1 300 val
+ugfbswphij 1 300 train
+ugfllaonow 1 299 val
+uggcsrxjxa 1 300 val
+uggdsbwisb 1 300 val
+uggjeoreoz 1 300 train
+uggjvftuua 0 300 train
+uggleprhuq 1 300 train
+uggnfmqfka 1 300 val
+uggnyxhqbi 1 300 train
+uggsnpctkd 1 300 train
+ughbtpdabx 0 300 train
+ughpqvtrhn 1 300 val
+ughtgfrcxq 1 300 train
+ughvqstpvg 1 300 train
+ughzjpnyss 1 300 train
+ugiafckfik 1 300 train
+ugitfhliiq 0 300 train
+ugitishqur 1 300 train
+ugiwnoaltx 1 300 train
+ugjbxqirgl 1 241 train
+ugjstvjpbq 1 300 train
+ugjufkwtrc 0 300 val
+ugjvoibpxf 1 300 train
+ugkkyacovg 1 300 train
+ugkwxruczv 1 300 val
+uglfptoirh 1 300 train
+uglirmzhox 1 300 train
+ugllkfkcxp 1 300 train
+uglsgrmcbr 1 300 train
+ugmyqmsayp 1 300 train
+ugndmaamyq 1 300 train
+ugnhpkmprl 1 298 train
+ugnikyemsb 1 300 train
+ugnkgmthhq 1 300 train
+ugnnkhxjsr 1 300 train
+ugnqazwhgb 1 300 train
+ugnzyudejt 1 300 train
+ugodnfosge 1 300 val
+ugoiyutczh 1 300 train
+ugolghjdmp 1 300 val
+ugonlihhoc 1 301 val
+ugooshulwj 0 300 val
+ugozwrxycw 0 300 val
+ugpesqbrdu 1 300 train
+ugpgxcljaj 1 299 test
+ugpptoozyo 1 301 train
+ugpufkleno 0 300 train
+ugpvzbtuhs 1 301 train
+ugqaxxrybr 1 300 train
+ugqbsegika 1 300 train
+ugqehnyojp 1 300 train
+ugqepubgjo 1 300 val
+ugqeuxruef 0 300 val
+ugqhbfrsdb 1 300 val
+ugqlenmrtl 0 300 val
+ugqmplyjdq 1 300 val
+ugqmwxqgck 1 301 train
+ugqqkwmcbk 1 300 train
+ugqrmagfps 1 300 train
+ugqvajjrbl 1 300 train
+ugrehmduul 1 300 train
+ugriuqabdp 1 301 train
+ugrjculalj 1 300 train
+ugrkszjion 1 302 val
+ugrlhuxwkw 0 300 train
+ugrmyvfzdz 1 300 val
+ugrqklsgrx 1 300 train
+ugrscetigx 1 300 train
+ugsdfnwbvp 1 300 train
+ugskjblnmu 0 300 train
+ugslzlvazt 1 299 train
+ugsngvegeb 1 300 train
+ugsvjmljrg 1 300 val
+ugsxnjqnti 1 300 train
+ugtbefqmqa 1 241 train
+ugtcrhnfml 1 300 train
+ugtdegxdqv 1 300 val
+ugteohzsut 1 300 train
+ugtoipqlja 1 300 train
+ugtxpawoso 1 300 val
+ugueeljcck 0 300 train
+ugujwdhxjd 0 300 train
+ugulbgulon 1 300 train
+ugusefbydg 0 300 train
+uguyjswcct 1 300 train
+ugvjcdlkin 1 300 train
+ugvnbpkqie 1 301 train
+ugvugidcji 1 300 val
+ugvurtaxqv 1 300 train
+ugvvmsnalo 1 298 train
+ugvzfxyuyl 1 300 train
+ugwotrmxag 1 301 train
+ugwuvtiukl 1 300 train
+ugwyeubpzy 1 300 train
+ugxeqibhwv 1 300 train
+ugxerzejht 1 300 train
+ugxmzszzyo 0 300 train
+ugxnuzqple 1 297 train
+ugxoajwoiy 1 300 train
+ugxpktwtoq 1 300 val
+ugxplxnxxb 1 300 train
+ugxqwwjrpb 1 301 train
+ugxqzksovp 1 300 val
+ugxwngzlmw 0 300 train
+ugxzhlqxpf 1 300 val
+ugybhswuaq 1 292 val
+ugybuhnuoy 0 300 train
+ugyeuuwkla 0 300 train
+ugygvsdatj 1 300 train
+ugyqdwadeo 1 300 train
+ugyyuzcegt 1 300 train
+ugzonpnovr 1 300 val
+ugzpmmyogi 1 299 test
+ugzrhiwigv 1 300 train
+ugzzotnqbh 1 300 val
+uhabienydy 0 300 train
+uhadsgrtju 1 300 train
+uhahxusasd 1 300 train
+uhaiwuxwox 1 300 val
+uhakqelqri 1 300 test
+uhaozesefw 1 300 train
+uhasvltgqn 1 300 train
+uhatylfxkx 1 300 train
+uhawwtdxbl 1 300 train
+uhaxgxrtdx 1 300 val
+uhbbfvhnpe 1 300 train
+uhbdquaigx 1 300 train
+uhbmabnbkn 1 300 train
+uhbqewipcd 0 300 train
+uhbxhharht 1 300 val
+uhcbanfylw 1 300 val
+uhccchvlop 1 301 train
+uhcowpcuok 1 300 train
+uhcsfdhpen 1 300 train
+uhcyauurnh 1 300 train
+uhcyyrpscf 1 300 train
+uhddzxthgf 1 300 train
+uhdfvpnezl 1 250 train
+uhdikkbnhg 1 300 val
+uhdlpyhbis 1 241 train
+uhdqecemtc 1 298 train
+uhebylplqw 1 300 val
+uheecajznz 1 300 train
+uheeqofioj 1 300 train
+uhegfyqwlt 1 300 val
+uhekljjqtj 1 300 train
+uheltvvhrl 0 300 train
+uheoswsuja 0 300 val
+uherdillhb 1 300 train
+uhfcjwmuhk 1 300 train
+uhfckvfofy 1 300 train
+uhfgxhjmgw 1 301 val
+uhfjfbvjdf 1 300 train
+uhfmuoxxty 0 300 train
+uhfmyeefsz 0 300 train
+uhfniimird 1 301 val
+uhfqabofgg 1 301 train
+uhfrjeyveg 1 300 val
+uhfzpdidyb 0 300 val
+uhgbucmqnc 1 301 train
+uhgfhzxdkb 1 300 train
+uhghcnbnsc 1 299 test
+uhghtrtwyg 1 239 val
+uhgtynaaxi 1 300 train
+uhgxwxlait 1 300 test
+uhhbqnlthf 1 300 train
+uhhfwrqons 1 300 val
+uhhhfibqvx 1 298 train
+uhhmiswpxi 1 300 val
+uhhochbcgk 1 300 val
+uhhpppdvjc 1 241 train
+uhhquzgztr 1 301 train
+uhhzxsluka 1 300 train
+uhiptgpwsq 1 300 train
+uhircpbhkb 1 300 train
+uhituhhfeq 1 300 train
+uhiwrtehvs 1 300 train
+uhjdylxche 1 301 train
+uhjgynzpze 0 300 train
+uhjrqnqlac 1 300 train
+uhjvpeoagd 1 300 train
+uhjzkwfeqk 1 300 train
+uhkmsuosni 1 300 train
+uhknwoqaxo 1 300 val
+uhkrrduzkc 0 300 train
+uhksnblalh 1 136 train
+uhkwvsqeog 1 300 train
+uhlljqoxln 1 300 train
+uhlnuwidjy 1 300 train
+uhlzhercpe 1 300 train
+uhmgigpumj 1 300 train
+uhmhdbgvwr 1 300 train
+uhmixfmlpt 1 300 train
+uhmjczicte 1 300 train
+uhmrljgfxt 1 300 train
+uhnaizpqtj 1 300 val
+uhndegdcvw 0 300 train
+uhnhexuqcv 1 300 train
+uhnhzamxrw 1 300 val
+uhnnptttkl 1 301 train
+uhnobvbowi 1 300 train
+uhnpdddtkm 1 300 train
+uhnsqumkdh 1 300 train
+uhoasjgnsc 1 300 train
+uhoddnuikv 1 301 train
+uhoiswejqd 1 300 val
+uhojzlbfpa 0 300 train
+uhorhpfohw 1 300 train
+uhowmniyzu 1 300 val
+uhozevycgj 1 300 test
+uhpnixcknb 1 300 train
+uhpyfhdbse 1 301 val
+uhpyqmrnff 1 241 train
+uhpzrsglum 1 300 val
+uhqbwdgeur 1 300 train
+uhqcziqcaf 1 241 train
+uhqfhwxspu 1 300 train
+uhqvafqwiu 1 300 train
+uhqwaoxxcj 0 300 train
+uhqwoxsqsi 1 300 val
+uhrdauvnlx 1 236 train
+uhrofvfghh 1 300 test
+uhrqlmlclw 0 300 test
+uhrszjyulu 1 299 train
+uhrvmearuj 0 300 train
+uhrvvxtwom 1 300 val
+uhrwuwgcyz 1 300 train
+uhsfbqylim 1 300 train
+uhsfwtmkrm 1 300 train
+uhskadmuwb 1 300 train
+uhskcqybgm 1 300 train
+uhspcdwvml 1 300 train
+uhsplcyhds 1 300 train
+uhssjxjqsb 1 300 val
+uhsvvhecng 1 300 test
+uhswpjqirh 1 300 train
+uhswwyrhon 1 300 train
+uhtdcjjydi 1 300 train
+uhtfebbvin 1 300 val
+uhtfrxfdfo 1 300 train
+uhtgpjtebq 0 296 train
+uhtixmsrkw 1 300 train
+uhtmgorbnm 0 300 train
+uhtmiodzsq 1 298 train
+uhtnbqrrzx 1 300 train
+uhtrcowrjw 1 300 train
+uhtrpqhgwy 0 297 train
+uhtvdralih 1 300 train
+uhtwowliza 1 300 val
+uhudvkbmat 1 300 val
+uhufojbuau 1 300 train
+uhujmeszhh 1 300 train
+uhupqscwds 1 300 train
+uhutmeamhm 1 301 train
+uhutuyxmtw 1 300 train
+uhvmmmfknw 1 300 val
+uhvmrfksax 1 300 train
+uhvsrhbtwt 1 300 train
+uhvttzvdnt 1 300 val
+uhwqhrpkfr 1 301 train
+uhwqqtlfhc 1 300 train
+uhwrjookhq 1 300 val
+uhwtmcssjh 1 300 train
+uhwvultbtb 1 300 train
+uhwwumfsix 1 298 train
+uhxdcxnhrz 1 300 train
+uhxmcolvzv 1 299 train
+uhxvusxogm 1 298 train
+uhxxjfvogf 1 298 val
+uhyanecmga 1 301 val
+uhydodxuvb 1 299 val
+uhyftfoupd 1 240 train
+uhygboilej 0 300 train
+uhyizbpmzk 0 300 train
+uhykldereg 1 300 val
+uhykndptvh 0 300 train
+uhynwthfhf 0 300 val
+uhyokbwzcb 1 298 train
+uhypztgxsn 1 300 train
+uhyrdsuruo 1 300 val
+uhyujckuan 1 300 train
+uhyvsxwcxw 1 300 train
+uhywfefjth 1 300 train
+uhyztpvfhn 1 300 train
+uhyzzlkiku 1 300 train
+uhzezmtsek 1 301 val
+uhzfamieuz 0 302 train
+uhzgpoxmuq 0 300 train
+uhzicmklxi 0 300 train
+uhzkiwaftk 1 301 train
+uhzlbtrvme 1 300 val
+uhztpfkkvk 1 300 train
+uhzuqaedfo 1 300 train
+uiagmwtclv 1 300 train
+uiagrrseif 1 300 train
+uiaihofntw 1 300 train
+uiaubrlxyl 1 300 test
+uiauimdvsa 1 300 train
+uibpwqeryl 1 300 train
+uibqdzcojz 1 300 val
+uibsxskypy 1 300 train
+uibtgrxhzo 1 300 train
+uicmpptfdm 1 300 val
+uicqmalcmh 1 300 train
+uicwisezwg 1 300 train
+uicxnnhven 1 300 val
+uiczdxmxmf 1 300 train
+uidlalkquf 0 300 train
+uidllncyjd 1 299 test
+uidnpxhiax 1 300 train
+uidycotnew 1 300 val
+uiehztqkjb 1 300 train
+uievqldxgg 0 300 train
+uifapvqsvw 1 300 train
+uifbnrbgpx 1 300 train
+uifgnlmosn 1 300 train
+uifivxqvnp 1 300 val
+uifkegagsf 0 300 train
+uifnbetnuq 1 300 val
+uifnrsrviy 1 300 train
+uifnvzmdtq 1 301 train
+uifsaeponw 1 300 train
+uifvrpxudn 1 300 val
+uifzzichej 0 300 train
+uigdezenjc 1 300 train
+uigfkvrkvv 1 300 train
+uigjiayurq 1 300 train
+uigltxmbmo 1 300 val
+uigpzvckuc 1 300 train
+uigqdmqjkh 1 300 train
+uigseqauqz 1 300 train
+uigumjoigj 1 300 train
+uihbkxebur 1 300 train
+uihfymknbd 0 300 train
+uihhczxmqr 0 300 val
+uihpdaqxau 1 136 train
+uihsgfhhrt 1 299 val
+uihudeajwz 0 300 train
+uiidarolup 1 99 train
+uiiefiddbu 1 300 train
+uiiehkxvew 0 300 val
+uiiicsxuql 0 300 train
+uiiiophjmf 0 300 train
+uiiiubzdyp 1 300 val
+uiikcmtjvi 1 241 train
+uiipbgczmx 1 300 train
+uiisqrsxtd 1 300 train
+uiiyasziuo 1 300 train
+uijbhguddo 1 300 val
+uijihpwycf 1 147 train
+uijmritfav 1 300 train
+uijodhxavs 1 300 train
+uijsszexav 1 300 train
+uikdbchdjm 1 300 train
+uikdqlccas 1 300 train
+uikefrcrvj 1 300 train
+uikhuivfom 1 300 train
+uikihjldyy 1 300 train
+uikpmbsozb 1 300 test
+uilibrrrvf 1 300 train
+uiljitboxg 1 300 train
+uilvfvgagt 1 300 val
+uilxcencvx 0 300 train
+uilxedormt 1 300 train
+uilypbkthd 1 300 train
+uilzfjlhxb 1 300 train
+uimejlrwlk 1 300 train
+uimepvrlqw 1 241 train
+uimkoyxrjp 0 300 train
+uimowegica 1 300 train
+uimraybknu 1 299 test
+uimvmzaveh 1 300 train
+uimynipbzt 1 300 train
+uinbaobfsp 1 300 train
+uingugmwbz 1 300 train
+uinhlopjgs 1 300 train
+uinnawbifs 1 300 train
+uinolrohev 0 300 train
+uinpjahwvy 1 300 val
+uinqbonxod 1 300 train
+uiofjtvvmb 0 300 val
+uioftdjrgq 1 300 train
+uiogltbahq 1 300 train
+uiorebzitw 1 300 train
+uiouplsood 1 300 train
+uioxplbbbt 0 300 train
+uipbzhbofo 1 300 train
+uipcqpdyef 0 300 train
+uipindbexi 1 300 test
+uipkkhqira 1 300 train
+uipkpbgxkr 0 300 train
+uipnntqgmm 0 300 train
+uipnxxcpwk 0 300 train
+uipufnymrc 1 300 train
+uipujsobwe 1 300 train
+uipvgtjczh 1 300 train
+uipygodqdq 1 300 test
+uiqacajfeo 1 300 train
+uiqbbywasv 1 301 val
+uiqbshgcve 1 300 train
+uiqhpnzcmp 1 300 test
+uiqmumgafo 1 242 train
+uiqryfrmiy 1 300 val
+uirahoityi 0 300 train
+uirbaztuqc 1 299 val
+uirbjvjowz 1 300 train
+uirbsagvgg 0 300 train
+uirgofpzqr 1 303 train
+uirhgxojrn 1 300 train
+uirjwskgfm 1 300 train
+uirnetlwhl 1 300 train
+uirqisdmez 1 300 train
+uirqyhpswp 0 300 train
+uiryybekmf 1 300 val
+uisbxbtebx 1 302 train
+uisbxiaoej 1 297 train
+uislxipqhe 1 300 train
+uispjlldur 1 300 train
+uispvqamlt 1 300 val
+uisrispicg 1 300 val
+uisuxausdz 0 241 train
+uiswjjxeox 1 301 val
+uisxbctznn 1 300 train
+uitduchtwi 0 301 train
+uitjjeddgv 1 300 val
+uitojzobvp 1 300 test
+uitpahefah 1 300 train
+uitpfwppcm 1 300 train
+uitzbzdxnl 1 300 train
+uitziixwma 1 300 train
+uitzqhxgha 1 300 train
+uiuritmtkl 1 300 train
+uiutzqhdqn 1 300 train
+uiuvswslvl 1 300 train
+uiveonyzzx 1 300 train
+uivjkcqxct 1 300 train
+uivrajgexg 1 300 train
+uivrkfeplw 1 300 val
+uivtonoogk 1 300 train
+uivvfpskpa 1 300 train
+uivxkfydjx 1 300 val
+uiwehzvkla 1 301 train
+uiwhlyjcmz 1 300 train
+uiwjvauleo 0 300 train
+uiwwusstzb 1 298 train
+uiwxbwiilr 1 300 train
+uixdqqiyiz 1 301 train
+uixmggnprp 0 301 train
+uixnzwqwpz 1 301 train
+uixrscmuqx 1 300 train
+uixyhhlnwu 1 300 val
+uixzlmczgd 1 300 train
+uiyfscynck 1 301 train
+uiyibmrads 1 300 train
+uiykwgaarz 1 300 val
+uiylhiemwp 1 300 train
+uiynchkmgc 1 300 train
+uiyrgumkmh 1 300 train
+uiyzddlral 1 300 train
+uizazbbqnz 0 300 train
+uiznbyyadm 1 300 val
+uiztnpxfnh 1 300 train
+ujabtrnrbi 1 300 val
+ujaehtqxde 1 300 train
+ujaemekjcx 1 300 test
+ujaknbycwv 1 300 val
+ujalswypnk 1 300 train
+ujanwlkufe 1 300 train
+ujaobhugdf 1 300 train
+ujashjvlpt 1 300 train
+ujasiapdbe 1 302 train
+ujaszufrwz 1 299 test
+ujawrfthtz 1 300 val
+ujbamwxyvo 1 300 train
+ujbdgblolk 1 300 train
+ujbkkujoea 0 300 train
+ujbookfnth 1 300 train
+ujbqwvaack 1 300 train
+ujbrspsivv 1 300 train
+ujcaowotrc 1 300 train
+ujcbqxpmis 0 300 train
+ujcjpasyqa 1 300 train
+ujckelmzxm 1 241 train
+ujcmgohscl 1 301 train
+ujcpoyesak 1 300 train
+ujcwaytgmy 1 299 val
+ujddfaoxqq 1 300 train
+ujdlrroaec 0 300 train
+ujdokhdprk 1 301 train
+ujdpypuzmd 1 300 train
+ujdtnatije 1 240 train
+ujdxwsyxlf 0 300 val
+ujdykwazjx 1 299 val
+ujdzutgpbr 1 300 train
+ujecxwxlad 1 300 train
+ujeqegzawu 1 300 train
+ujesaqwitp 1 300 train
+ujetgfahjj 1 298 train
+ujevbjyhby 1 300 train
+ujewbyvruv 1 300 train
+ujfebxyvdr 1 300 train
+ujfiavjzhz 1 298 train
+ujfjhtsqbf 1 300 val
+ujfuskyowo 1 300 train
+ujfxakdqln 1 300 val
+ujfyfyhfiz 1 300 val
+ujfzezehgt 1 300 train
+ujgcgqysia 0 301 train
+ujgjwwqebw 1 300 train
+ujgktdegfw 1 241 train
+ujgmzuzjsd 1 300 train
+ujgrnmuaxt 1 300 val
+ujgybfcnrt 1 301 train
+ujgzcxwpdx 1 300 train
+ujhcautvje 1 300 train
+ujhhksskil 1 300 train
+ujhjgutsfc 0 300 train
+ujhrcihqns 1 300 train
+ujhxwcfwyd 0 300 train
+ujiklghcbe 1 300 train
+ujikprpimq 1 298 train
+ujinondbrv 1 300 val
+ujivurbzyc 0 300 val
+ujiwhorqyl 0 300 val
+ujjkzsdtiz 0 300 train
+ujjlelliwc 1 300 train
+ujjnevkkir 1 300 train
+ujjulfkdis 1 301 train
+ujkgexkbos 0 300 train
+ujkjagqvae 1 300 val
+ujkjjuwryf 1 300 val
+ujkphhjpvi 1 300 train
+ujlasmtfcl 1 300 train
+ujlcxdckbe 0 300 train
+ujlmoaepee 1 301 val
+ujltjvrpez 1 300 val
+ujlumbllpt 1 300 train
+ujlusvhjgb 1 300 train
+ujlvwgyhgk 1 300 test
+ujmekagdoy 1 300 train
+ujmgyxgoss 1 300 train
+ujmjnwlife 1 300 train
+ujmnnaxuss 1 300 train
+ujmtqszexn 1 300 train
+ujmwkkeyol 1 300 train
+ujndiaeoqu 1 300 train
+ujnfgrlfgp 1 300 train
+ujnhlrzwyr 1 300 train
+ujnkrjgtwi 1 300 train
+ujnojldxpl 1 300 train
+ujnoqpfldl 1 300 train
+ujnoyvmfhj 0 300 val
+ujnsgalkuh 1 301 val
+ujnuonfteb 1 300 train
+ujnvizfsze 1 300 train
+ujnzetbrhb 1 300 train
+ujokxjazjz 1 300 train
+ujoslrgaoj 1 297 train
+ujowtoffvt 1 299 val
+ujoyxrqwud 0 300 train
+ujpedccctl 1 300 train
+ujpezoihxn 0 300 train
+ujplqlutpa 1 297 train
+ujpmcwctjg 1 300 train
+ujpmzkwspk 1 300 train
+ujpygeatkz 1 300 train
+ujpzgghvrp 1 300 val
+ujqctxxqvk 1 300 val
+ujqdkbogdl 1 300 train
+ujqlkpuohi 1 239 train
+ujqmktjnsn 1 300 train
+ujqsadgjxw 1 300 train
+ujqslldfja 1 300 val
+ujqteznrom 1 301 train
+ujqzmwhvjk 1 300 val
+ujrcqqydxz 1 300 train
+ujrkussqvz 1 300 train
+ujrmoxcxjz 1 300 train
+ujrsxalowc 1 300 train
+ujrszwqqkx 1 300 train
+ujrybviukn 1 300 train
+ujryldwrra 1 300 train
+ujrysamivo 1 300 train
+ujsihxqppu 1 300 test
+ujsjwilugf 1 300 train
+ujslmfluwe 1 299 val
+ujsvraajfg 1 301 train
+ujtagofmfe 1 301 train
+ujtrrhtfgj 1 241 train
+ujtvaszjxf 1 300 train
+ujtvfxcwqq 1 300 train
+ujtvukaomn 1 300 train
+ujtyvmiwnl 1 300 train
+ujtzlhxgof 1 300 train
+ujuawttqdq 1 300 val
+ujufhktbif 1 300 train
+ujuifeoqmd 1 300 train
+ujuklkcvnf 1 300 val
+ujunqskegt 0 300 train
+ujvefgmdbx 1 300 train
+ujvfjetoti 1 300 train
+ujvkfduclv 1 300 train
+ujvrrbmmye 1 300 test
+ujvuhadomd 1 300 train
+ujvxohohuq 0 300 train
+ujwqgoagmh 1 300 val
+ujwsgcseyo 1 299 test
+ujwwqsvkjs 1 300 val
+ujxjmbpylx 1 300 val
+ujxrycscos 1 301 val
+ujxtmbrzxt 1 300 train
+ujxtugyffe 1 300 train
+ujxusdbteh 1 300 train
+ujxzmdswfk 1 300 train
+ujyeiolabx 1 300 train
+ujygjrbxjb 1 240 val
+ujyowwqpri 0 300 train
+ujysvoqnvq 1 300 val
+ujyzdfyghi 1 300 train
+ujzcqnrxgc 1 299 train
+ujzcznmdjw 1 300 train
+ujzduhqgiv 1 300 train
+ujzinlzrbw 1 300 train
+ujzncalkmc 0 300 train
+ujzqvtzbqx 1 300 train
+ujzwwfkeia 0 300 train
+ukaaxdrqqj 0 300 train
+ukacifecol 0 300 train
+ukadcylgrg 1 301 train
+ukafpypnfl 1 300 val
+ukahuysdcs 1 300 train
+ukamuiipsx 1 300 train
+ukanjumvwr 1 300 train
+ukapiztezj 1 300 train
+ukapsfdrfn 1 300 val
+ukarvhmrxp 1 300 train
+ukavvqeufc 1 300 test
+ukbffptlvj 1 300 train
+ukbksxpfjg 0 300 val
+ukbqvnifld 1 300 val
+ukcclynsce 1 300 train
+ukciaexlcb 0 300 train
+ukcirjgasd 1 167 train
+ukclebahfm 1 300 test
+ukclynosts 1 300 train
+ukcwgfxugy 1 300 val
+ukcyzdgtcx 1 300 train
+ukddragknx 1 300 train
+ukdhnwwnmt 0 301 train
+ukdkpbfakp 1 301 train
+ukdocncxpz 0 300 train
+ukdququojq 0 300 train
+ukdtxoihrp 1 300 train
+ukdxjfskpf 1 300 val
+ukeuyulwyh 1 300 train
+ukezkomunq 0 300 train
+ukfcnpdwcs 1 300 train
+ukfleerauf 1 300 train
+ukflzvniyp 1 300 train
+ukfpgxoyyq 1 300 train
+ukfrvugjji 1 300 train
+ukghnocwfw 0 300 val
+ukgrdyvdzx 1 300 train
+ukgtwvykpw 1 300 val
+ukgvracfyq 1 300 train
+ukheqmmuch 0 300 val
+ukhlulglgy 1 300 val
+ukholynptx 1 301 train
+ukhqrlwvtc 1 300 train
+ukhqtirecl 1 300 val
+ukhtgvybdk 0 300 train
+ukhvsvgjib 1 300 train
+ukhwkvszoc 1 300 train
+ukhxncuuys 1 300 val
+ukiaaxuliu 1 300 train
+ukiheldhqs 0 300 val
+ukijyhnbex 1 300 train
+ukiplhpsen 1 241 train
+ukirzltdhx 1 300 train
+ukisxuhmlh 1 300 train
+ukivitxdrp 1 301 train
+ukjadomrax 0 300 train
+ukjdsjoerp 1 300 train
+ukjglffpto 1 269 train
+ukjlzxvlkz 1 300 train
+ukjnbjcnqy 1 298 val
+ukjrrxkdcm 1 300 val
+ukjryifgdc 1 301 train
+ukjymhrxda 1 296 val
+ukjzqqkvpf 1 300 val
+ukkasncnkh 1 300 val
+ukkcjoimnk 1 301 val
+ukkdbcenei 1 300 train
+ukkdgzuipd 1 300 train
+ukkeejwxfs 1 301 train
+ukkftinlcw 1 300 train
+ukkqbsvhtw 1 300 train
+ukkrwuhdem 1 300 train
+ukkspugfiz 1 299 val
+ukkunrcwuo 1 300 train
+ukkzfbnrth 1 300 val
+uklcztomai 0 300 train
+uklgnlpbsp 0 299 train
+uklnhhpvuf 1 300 train
+uklugukcmw 1 300 train
+uklvblasbr 1 300 train
+uklvicywwv 1 296 val
+uklvqsnxgv 1 300 test
+uklyvfycur 1 302 train
+ukmfykwbdc 1 300 val
+ukmgypzayv 1 300 val
+ukmiuwpsif 0 300 train
+ukmurtebpz 1 300 train
+ukmzhpeezl 1 300 train
+ukncbgatib 1 300 val
+uknehjobxl 1 301 train
+uknfhgiifi 1 269 train
+uknlhztnly 1 300 train
+uknoecdzdi 1 300 train
+ukoerjqjcj 1 300 train
+ukoocfhise 0 300 train
+ukoooovirs 1 300 train
+ukoqpolyys 1 300 train
+ukotfzrlge 0 300 train
+ukotmrdpjw 0 300 train
+ukoutbtiau 1 299 test
+ukovttjgxh 1 299 train
+ukoxilzord 1 300 train
+ukpahpwqlr 1 296 train
+ukpaybhftz 1 297 val
+ukpgboldxc 1 300 train
+ukpzcalere 1 301 train
+ukqbxtqccr 1 301 train
+ukqigddbbz 1 300 train
+ukqkaptsdo 1 300 val
+ukqmdmrgoh 1 300 train
+ukqmkczqsz 1 241 train
+ukqobskpxj 1 300 train
+ukqpbtrriu 1 300 train
+ukqpqrioss 1 299 test
+ukqsdlepga 1 294 train
+ukrckkvaqi 1 300 train
+ukrebhncqp 1 300 train
+ukrrkladqf 1 300 train
+ukrvmiddhp 0 300 train
+uksgsyodam 1 300 train
+uksqzousoi 1 300 test
+uksvydjluh 1 301 val
+ukszxhnsgx 1 300 val
+uktabnbfsu 1 300 train
+uktboyfsgn 1 300 val
+uktbwkihhl 0 300 train
+uktgnpudhu 1 300 val
+ukthabiilt 1 300 val
+uktzwkmvqn 1 300 train
+ukuajnxcgv 0 300 train
+ukuckqhujg 1 300 val
+ukuhgmnled 1 300 train
+ukuhplitcd 1 300 train
+ukuiypccwh 1 300 train
+ukujsdeyol 1 300 train
+ukukacghzr 1 300 train
+ukvakjhrzo 1 300 train
+ukvkdkkdtm 1 301 train
+ukvlzkqutn 1 300 val
+ukvmxgbmfe 1 300 train
+ukvtossymq 1 300 train
+ukvuqzbpkr 1 300 train
+ukvwasdalj 1 300 train
+ukvxlkdgwc 1 300 train
+ukvzegpclr 1 300 train
+ukwbmryplw 1 301 train
+ukwjomvjiq 1 300 train
+ukwkfqnmxs 1 300 train
+ukwmmvpdrd 1 300 train
+ukwsguqwwc 1 241 train
+ukwwsukwvs 1 300 train
+ukxdazlghx 0 300 val
+ukxdicgdew 1 301 train
+ukxfswtgud 1 300 train
+ukxfypqesk 1 300 train
+ukxhrlhlif 1 300 train
+ukxiewpape 1 300 train
+ukxswhkyuh 1 300 train
+ukxulfmlut 1 300 val
+ukxvriimlq 1 300 train
+ukylbcgoyi 1 300 train
+ukyzorjthi 1 300 train
+ukzbarqwrq 1 300 train
+ukzbdnibwe 1 300 train
+ukzbnlbplu 1 300 train
+ukzdzszlqx 1 300 val
+ukztifhqwh 1 300 train
+ukzucvolnu 1 300 train
+ulaitoszdo 1 300 train
+ulajuiablp 1 300 val
+ulayctahen 1 300 train
+ulazwizska 1 300 train
+ulbbklhnjy 1 300 train
+ulbibofwez 1 300 train
+ulbjczitij 1 241 train
+ulbobvtbmg 1 300 val
+ulboigugvz 1 300 val
+ulbqrhxcxg 1 300 train
+ulbqxiejgi 0 300 train
+ulbuihipbv 1 301 train
+ulbvjauchz 0 301 train
+ulbycwpaif 1 300 train
+ulcbmkniuu 1 300 train
+ulceehmoyg 1 300 train
+ulcgyxjzgx 1 300 train
+ulcjqkweit 1 300 train
+ulckbdczqj 1 300 train
+ulcmsqttol 1 300 val
+ulcxwigsrn 1 300 train
+uldxllxtkm 1 301 val
+uldztpgvze 1 301 val
+ulekccndce 1 302 train
+ulemomlvpx 1 300 train
+uleoboutyl 1 300 train
+ulevggstoz 1 300 train
+ulfexdgnej 1 300 train
+ulfppedvdb 1 300 val
+ulftewmdto 1 300 train
+ulfuuyduub 1 300 train
+ulfziupnkp 1 300 val
+ulfzoinpcs 0 300 train
+ulgieqzcoz 1 300 train
+ulgpzmdawn 0 300 train
+ulgunprcyc 1 300 train
+ulgvqcniwm 1 300 train
+ulgwbvqgta 0 300 train
+ulgygqcvpx 1 300 train
+ulhborgscf 1 301 val
+ulhdpsqyub 1 300 val
+ulhtxdulhx 1 300 val
+ulhtxnjqbm 1 300 train
+ulhujkjcmz 1 300 train
+ulhxdukmya 1 300 train
+uliadnmydy 1 300 train
+uliaqwwhtj 1 297 val
+ulibdtoetp 0 300 train
+uliblojdwu 1 300 val
+ulihokoeqx 1 300 train
+ulisijbzem 1 300 val
+uliucqioee 1 300 train
+uljktfoujq 1 300 train
+uljtgezhbh 1 300 train
+ulkeqdyccf 1 300 train
+ulkeuykkgp 1 300 train
+ulkewjzbjm 1 300 train
+ulkigpbixj 1 300 train
+ulkjjlyaft 1 300 train
+ulkmrwykqx 0 300 train
+ulkpdngyln 1 241 train
+ulkrhrktaz 1 300 test
+ulktozegxh 0 300 train
+ulkzmzycib 1 300 train
+ullbgqgutm 1 298 train
+ullpxezqil 1 300 val
+ullqmpaqjs 1 300 train
+ullzxopvgo 1 300 train
+ulmrpqrqvy 1 300 val
+ulmwfnbfcz 1 300 train
+ulmydxkimr 1 301 train
+ulnfvjfxiv 1 300 train
+ulnjtimexc 1 300 train
+ulnlaxusuw 1 300 train
+ulnyzixuii 1 300 train
+ulocqfuzzj 1 300 train
+ulofgxniva 0 298 train
+ulomzhbckw 1 297 val
+uloplwbwbk 1 301 train
+ulpbyiiqsp 1 300 train
+ulpduzddhu 1 300 train
+ulpogiqaqf 1 301 train
+ulpwhcmkln 0 300 val
+ulpyjuxolu 1 300 train
+ulqboeaekv 1 298 train
+ulqckpzekt 0 301 train
+ulqhsizsyn 1 300 train
+ulqquwnmsa 1 300 train
+ulqtrnyipb 1 300 train
+ulquclfdjv 1 300 train
+ulqxxidpmx 1 299 train
+ulqzkltejh 1 241 train
+ulrigadwds 1 300 val
+ulrjntckev 1 241 train
+ulrnavreps 1 300 test
+ulruufnvtt 1 301 train
+ulrvzaozvl 0 300 train
+ulrxaqmhrr 0 300 train
+ulsumehrrj 1 300 train
+ultbrsqruz 1 300 val
+ultbygiibk 1 300 train
+ultlinksik 0 300 val
+ultlscatag 1 300 train
+ultsfomlez 1 300 train
+ultuzbwtbr 1 300 train
+uluaihmygx 1 300 train
+ulubxioaxe 0 298 train
+uluebrwgra 0 300 val
+uluiyrcghb 1 300 val
+uluozvjcmr 1 300 train
+ulvnqoxiud 0 300 train
+ulvpvkwwfc 1 301 train
+ulvtnhhfjo 1 300 train
+ulvttmwhgl 1 300 train
+ulvtuaeutx 0 300 train
+ulvxvhpgvq 1 300 train
+ulvzpojvys 0 302 train
+ulwbmcaode 0 300 train
+ulwgqkfozh 1 300 train
+ulwnduonzx 1 300 val
+ulwprtnavc 1 300 train
+ulwzjpupjd 1 300 train
+ulxcazmtcm 1 301 train
+ulxcidbhdc 1 300 train
+ulxckagimn 1 241 train
+ulxdqcjtxu 1 300 train
+ulxitgynnp 1 300 train
+ulxnsfkewu 0 300 val
+ulxovjiijy 1 300 train
+ulxzalaqhb 1 300 val
+ulygywporv 1 300 train
+ulyvqfdtfv 1 240 train
+ulzaghcnza 1 300 train
+ulzcsrlkxn 1 300 train
+ulzejgwfhq 1 301 val
+ulzgvacuew 1 296 train
+ulzjgbvdcf 1 300 train
+ulzohinrsb 1 237 train
+ulzuolkbjc 1 300 train
+ulzwslkhnj 1 300 val
+ulzwtgjmpn 0 300 train
+ulzxfnbqdw 1 300 train
+umaapupckb 0 300 train
+umajkyqlbc 1 298 train
+umandpehef 1 300 train
+umaxmshjjn 1 301 val
+umayucewoi 0 300 train
+umaznsoiao 1 300 val
+umbgeawmln 0 300 train
+umbkerzgab 1 300 train
+umblsvikcm 1 300 train
+umbtsfjfpz 1 300 train
+umbwadaeth 1 300 val
+umcfiohdme 1 300 train
+umchsuhfor 1 301 val
+umcnwdkero 1 300 train
+umcpoltxeb 1 300 train
+umcpyjmyge 1 241 train
+umdmyolede 1 300 train
+umdojzbwds 1 300 train
+umdtztcsnp 1 241 train
+umduhcebay 0 300 val
+umdybbmjkb 1 146 train
+umegxpnqoj 1 301 train
+umensyykfm 1 300 train
+umeprzcdcd 0 300 train
+umerhoubxw 0 301 train
+umesravcvu 1 300 train
+umeurbiaka 1 300 val
+umfacwjsfh 1 301 val
+umfjeabksw 0 300 train
+umfnkxzzeh 1 300 train
+umfntrazqd 1 300 train
+umfofgurar 1 300 train
+umforpoorw 1 300 val
+umfquxkalu 1 301 train
+umfwthjpzx 1 300 train
+umgdjzeqke 1 300 train
+umgiynjues 1 300 train
+umgmlregyv 0 300 train
+umhboyyvkh 1 298 train
+umhsxmwvnd 0 300 train
+umhwerhtpj 1 300 train
+umhwtpsifb 0 301 train
+umibcyqoar 1 298 train
+umicymstag 0 300 train
+umidsaepvc 1 301 val
+umitcwjotn 1 300 train
+umivhpizzt 1 241 train
+umixsrabzn 1 300 train
+umjfbrahnn 1 300 val
+umjfxbtnya 0 300 train
+umjqpdoxko 1 301 train
+umjzvjtxuw 1 300 train
+umkcmvnmrp 1 299 val
+umkjjmiper 1 300 train
+umkmlfwwwg 1 300 train
+umknqwudod 1 300 val
+umkxoagtyp 1 300 train
+umloaoulgo 1 300 test
+umloxyrpbh 1 300 train
+umlrvhkktr 1 300 val
+umlyrbidzz 1 302 train
+ummamaagbh 1 300 train
+ummckzpanc 1 300 train
+ummeogcaej 1 300 train
+ummfefjqgc 0 300 val
+ummfqwhecf 1 298 train
+ummgdlxuqc 1 300 val
+ummgmwfqvl 1 297 train
+ummpkysvdk 1 300 train
+ummsgvlpuh 0 300 train
+ummxukwbnf 1 300 train
+umnejfuhgg 1 300 train
+umnfxsznnt 1 300 train
+umngwqthnn 1 300 train
+umnllhvurx 1 300 train
+umnnzsmika 1 300 train
+umntzceeps 1 300 train
+umnujcpazm 1 300 train
+umnzyngdai 1 300 train
+umofhumprr 1 300 train
+umoijebzjp 1 300 val
+umokkjrdmn 1 300 train
+umoolxnyzg 1 300 train
+umoutofncx 1 301 train
+umovgarcut 0 300 val
+umoxwdaitp 1 300 val
+umpjfhpcxa 1 301 train
+umpjhrpzmu 1 300 val
+umpscxhfsk 1 300 test
+umpwfzjhuy 1 300 train
+umqdthxpqf 1 300 val
+umqkvkovqq 1 300 train
+umqmhgjlfo 1 301 train
+umqnndcukh 1 298 train
+umqqsmwlas 1 300 train
+umqqxbaxoo 0 300 train
+umqwtfzxbi 1 298 train
+umqyjcnaue 1 300 train
+umrabkypsl 0 83 train
+umrpgvwqis 1 299 train
+umrruwqtcg 1 300 val
+umrtfpfchb 1 300 train
+umrtrkhsac 0 147 train
+umruvgbthd 1 299 test
+umrvsrftms 0 241 train
+umsaiuhlxj 1 300 train
+umsenbtkxk 1 300 train
+umsfujvlog 1 298 train
+umsiycwlgn 1 300 train
+umsjbaoqzh 1 298 train
+umsjbpjqjx 0 301 train
+umsnfssapq 0 300 train
+umtdpjvjgx 1 300 val
+umtffiuldt 1 301 train
+umtkkrdyxk 0 300 train
+umtmvguudo 1 300 train
+umtqdtidfm 0 241 train
+umttlfnuvm 1 300 val
+umttosaubd 1 300 val
+umtxxlapaw 1 300 train
+umuffpuhji 1 300 train
+umukykyqpv 0 300 train
+umulgsatfu 1 99 train
+umuvegufyw 1 300 train
+umuvvijuvm 1 298 train
+umuwrbjzvy 1 300 train
+umvcmsuhgd 1 300 train
+umvdlretns 1 300 train
+umvdtehxpn 0 301 train
+umvgecqtez 0 300 train
+umvhbmmgvk 1 300 train
+umvjerzxqr 1 300 train
+umvpwnixvc 1 300 train
+umvqagqmpt 1 298 train
+umvqhomwpi 1 300 train
+umvrpvjooi 1 300 train
+umvwfynjoo 0 300 train
+umwdmqqlkk 1 300 train
+umwgftjaxi 1 300 train
+umwguzuryd 1 300 train
+umwktfpiyb 1 241 train
+umwwkbyyzv 1 300 val
+umxcceiyzo 1 300 train
+umxedadgci 1 301 train
+umxfriluuu 1 300 train
+umxhjfkcfn 1 300 val
+umxkzmoogu 1 241 train
+umxnblngtb 1 300 train
+umxpqkdxkq 1 300 train
+umxyaqeqrs 1 300 train
+umyaxqtbef 1 300 train
+umynsbiwmj 1 300 train
+umyqrzpscl 0 300 val
+umyrvioygt 1 301 train
+umysbzmrku 1 299 train
+umyscrcixv 1 300 train
+umytvrrjrk 0 300 train
+umytxmjuga 1 300 train
+umyynblqex 1 297 train
+umzfclhmpm 1 300 train
+umzhqfsatf 0 300 train
+umzitjnxrn 1 300 train
+umzlotkqsr 1 302 train
+umzxeornls 1 300 val
+umzykkmyot 1 300 train
+umzztrlpfa 1 300 train
+unaaotirke 1 300 train
+unagaklygz 1 300 train
+unalzvcclv 0 300 train
+unatmyuzqv 1 300 train
+unbfigrqpi 1 241 train
+unbigjuqws 1 300 train
+unbmxumici 1 300 train
+unbnrrmbwv 1 300 train
+unbnujvson 1 300 train
+unbpdfqagl 1 300 train
+unbpinxfmk 1 300 train
+unbshgwprn 1 269 train
+unbvktbhsi 1 301 train
+unbytbcwpt 1 301 train
+uncgfegsgh 1 240 train
+unciahaaok 0 300 val
+uncisftbyl 1 300 train
+uncpwycfwx 0 300 train
+uncrsrqkzt 1 300 val
+uncyecqmtf 0 300 train
+uncyrvjnyo 1 300 val
+undacbsroe 1 300 train
+undloyactk 1 300 train
+undpfuqmuf 1 302 train
+undrwckwva 1 301 train
+undxbsbrrb 1 300 val
+uneanxojth 1 300 train
+uneappholu 1 300 train
+uneattgpli 1 300 train
+unegkmrxte 1 300 val
+unemrspjie 1 300 train
+uneskfqnsf 1 300 train
+unezjxrymu 1 297 train
+unfeefzjhj 1 300 train
+unffcgnbem 1 301 train
+unfffgqqqj 1 298 train
+unfifycdki 1 301 train
+unfqnunrmo 1 241 val
+unfrndwjxz 1 300 val
+unftihmpsq 1 300 train
+unfvumgxlj 1 301 train
+unfxekymco 1 241 train
+ungasnkxoz 1 300 train
+unggaeogeb 0 300 train
+ungifdhsbs 1 300 train
+ungikzaugs 1 298 train
+ungpwpgyrz 1 298 train
+ungswhoovd 1 300 train
+ungtptaifv 1 300 train
+ungurxhlyr 1 300 val
+ungzosiyka 1 299 val
+unhgktaxjr 1 300 train
+unhhxtyytk 1 300 train
+unhovrqpey 1 300 val
+unhqeelntj 1 300 train
+unhxiuflnm 1 300 val
+unhxlmyozc 1 300 train
+unidhvozmc 1 300 train
+unioedzrhy 1 300 train
+unipiswovd 1 300 val
+unipwyfqcd 0 300 train
+univoddide 1 300 train
+unjbbkicfa 1 300 train
+unjcsfshdl 1 300 train
+unjkwldybt 1 300 train
+unjssbwldd 1 300 val
+unjtetrgig 1 300 train
+unjwnnkvbl 1 301 train
+unkdehmjiv 1 300 train
+unkqflwzcz 1 300 val
+unkvwttnqk 0 300 val
+unkwpjspeu 1 300 train
+unlabhqkal 1 300 train
+unlewqwudu 0 300 train
+unlkcwtlvt 1 300 train
+unlpnwzhdg 1 300 train
+unltsfsceq 0 300 train
+unlvgutmvv 1 300 train
+unlvsryxwk 1 299 train
+unmcqeahzf 1 300 train
+unmfaaaeln 0 300 train
+unmgpywogh 1 300 val
+unmijbepst 1 300 train
+unmjjivnns 1 300 train
+unmpiwboha 1 300 test
+unnbemtkve 1 298 train
+unnlprzjvr 1 300 train
+unnreejfhh 1 300 train
+unnvrkthai 0 300 train
+unnxgoshqv 1 300 val
+unnxrzsion 1 300 train
+unnyxoaotv 1 300 val
+unoackfdpo 0 300 train
+unoakgaizd 1 300 train
+unomkmkkkc 1 300 train
+unotcqwfph 1 100 train
+unozczsbfy 1 299 test
+unpbvnvlrl 1 300 val
+unpddtkrrf 1 300 train
+unpkuhuphj 1 300 val
+unpwttoyhu 1 300 val
+unpxsnhsft 0 300 train
+unqatfflwv 0 300 train
+unqcbybnqp 1 300 train
+unqgeeodcb 1 300 train
+unqjtjdvau 1 300 val
+unqljlpcwe 1 301 train
+unqrsvtogq 0 300 train
+unqullugkd 1 300 train
+unqwlzzckc 0 300 train
+unqwxyedve 1 300 val
+unrciisjok 1 300 train
+unrrijrbgh 1 300 train
+unsktqmhvp 1 300 train
+unssydxkvp 1 300 train
+unsuvravsb 1 300 train
+unsvzmknde 0 300 train
+unsyiirxsp 0 300 train
+untapynnze 1 241 train
+untfxruois 1 300 train
+unthlermem 1 300 test
+untiaiqvuz 1 300 train
+untibpphcq 1 297 train
+untkllghmh 1 301 train
+untqatuyld 1 300 val
+unttrwvksn 1 300 train
+untxvzuldz 1 300 test
+unuchpnjxb 1 300 train
+unuimdymla 1 300 val
+unuldcgdls 1 300 train
+ununjoggmu 1 300 val
+unuopcveph 1 300 train
+unuqkggkib 0 300 train
+unusvrwwpc 1 300 train
+unuxwfsksb 0 300 train
+unvjkpqkyg 1 300 train
+unvonesajn 1 300 train
+unvoufxooi 1 300 train
+unvriianzd 1 300 train
+unvvprbgom 1 300 train
+unvxphxtsf 1 300 train
+unvyawcuzx 1 296 val
+unvyhivqxr 1 301 val
+unwqmtkhlc 1 300 train
+unwsaztmff 1 300 val
+unwvdugxbj 1 300 val
+unxasrosgl 0 300 val
+unxoiqzmdk 1 300 val
+unxvvpohcw 1 301 train
+unycpqaiqf 1 300 train
+unydcggrbd 1 301 val
+unypenmwrb 1 297 train
+unywvlbnwl 0 300 val
+unzdswjtwj 1 300 val
+unzglryvni 1 300 train
+unzgopcuuq 1 301 train
+unztxfbswt 1 302 train
+uoajjolmzt 0 300 train
+uoakayuzzz 1 300 train
+uoalgiliqp 1 300 test
+uoantcwpwm 1 300 test
+uoanwkrbbh 1 240 val
+uoarbqcnkd 1 300 train
+uoawpgthjz 1 300 val
+uoaymtdtrx 1 239 val
+uobcbayafg 1 300 train
+uobebowold 1 300 train
+uobgrquzri 1 300 val
+uobwaqqbif 1 249 train
+uobyllyroc 1 300 train
+uocadvysjv 1 300 val
+uoccaiathd 1 300 test
+uoccytmrwc 1 300 train
+uodakzwdey 1 300 train
+uodarndzsb 0 300 train
+uodiwnpryc 1 300 val
+uodwphygbp 0 300 train
+uodxluqnyz 1 300 val
+uoeebxpetx 0 300 train
+uoefuafkja 1 300 val
+uoekdzjonu 1 241 train
+uoeqjjhnfv 1 300 train
+uoexhitxcx 1 300 train
+uoexhrywdl 1 300 train
+uoeznumgnu 1 300 val
+uoflaxwzez 0 300 train
+uofvmcxbgg 1 298 train
+uofvmwnkuv 1 300 val
+uofwcmrhmr 0 300 val
+uofwyzsldm 0 241 train
+uofzwkeapv 0 300 val
+uogbbddidc 1 300 val
+uogfivukli 1 300 train
+uogkikugah 0 300 val
+uogrczqptf 0 300 train
+uogywxvrvt 1 300 train
+uogzybnclc 1 300 train
+uohbzxmdza 1 300 train
+uohileyyis 1 300 train
+uohizrkrej 1 300 val
+uohjdlbnas 1 301 train
+uohyivcphn 1 300 train
+uoidzqctxa 1 241 train
+uoiqjeonve 1 300 val
+uoitxwmtgm 1 300 train
+uojfslnehm 1 300 train
+uojgiwhlfg 0 300 train
+uojmmyhkuw 1 300 train
+uojvnnotwi 1 300 train
+uojxlxwuzd 0 300 val
+uokicwazzd 1 297 train
+uoklbrkyqz 1 300 train
+uokpystlpj 1 298 val
+uolchgabpf 1 300 train
+uolfsouxpz 1 301 train
+uolklgfocm 1 300 train
+uolqmqsgbs 0 300 train
+uoltcpnukd 1 300 train
+uomapsnmwy 0 300 val
+uomcihbcgy 1 300 train
+uomfimsutw 0 300 train
+uomjxpjnab 1 300 train
+uomxsreoxx 1 300 train
+uonfozzcon 1 300 train
+uonguauuua 0 300 train
+uonqfxhjbc 1 300 train
+uonshkejav 0 300 train
+uonuagldyy 1 300 val
+uonuzvcmhh 1 300 train
+uonweuclyn 1 301 val
+uonwfowmfa 0 299 test
+uoojkbcjoz 1 300 train
+uoojzdywhv 1 300 val
+uookxidzxy 1 300 train
+uooqjqphai 1 300 val
+uoosazyhmf 1 300 train
+uootkfuvqq 1 300 train
+uootqjddcw 1 300 train
+uoowvqcxjf 1 300 train
+uopbogfelb 1 300 val
+uoperrtxhh 1 300 train
+uopfaluncc 1 300 train
+uopfrzszpp 1 300 train
+uopfswyygk 0 300 train
+uoppnewhyk 1 299 test
+uoptulivph 0 300 val
+uoqaspmtib 1 300 train
+uoqivxlorh 1 300 train
+uoqmwwdujw 1 300 val
+uoqpweopmc 1 301 train
+uoqrpfctwl 1 300 train
+uorejlkuqj 1 300 train
+uorhfryoru 0 300 train
+uorlyerlzm 1 300 train
+uorpnlhqux 1 300 train
+uoscnbnnfb 1 301 train
+uosrnkkijx 1 300 train
+uossxdapws 1 300 train
+uosucktcpt 1 300 train
+uosyyixqtr 1 300 val
+uotfigpizd 1 300 train
+uotkopqsnc 1 300 val
+uotmmdoenm 1 300 train
+uotonwywgq 1 300 val
+uotxbrzcmg 1 300 train
+uotxcyzzfw 1 300 train
+uotxnsybqe 0 300 train
+uoulbnvlej 1 300 train
+uoulwvrurh 1 300 train
+uoupjcutcp 0 300 train
+uovgarlaly 1 300 val
+uovovdpjcf 1 300 train
+uovspumzpe 1 300 train
+uovwbmkbjy 1 300 train
+uowafcidmo 1 301 train
+uowdwfzhss 1 300 train
+uowiocuqqt 1 300 train
+uowkstynct 1 300 train
+uowrnxnqyo 0 300 train
+uowrqajbry 1 299 train
+uowywtotcr 0 300 val
+uoxachoagj 1 300 train
+uoxbglromy 1 300 train
+uoxcuwtocu 1 300 train
+uoxdsdyrcb 0 300 train
+uoxhfedrpt 0 300 train
+uoxhjctyfp 1 298 train
+uoxhousdgv 1 241 train
+uoxkuybwkc 1 300 train
+uoxlvtlelj 1 300 val
+uoxmesdlrc 1 300 train
+uoxnzfvjdn 1 300 train
+uoxrvybgja 1 300 val
+uoxtopncoo 1 300 val
+uoxviglkbm 1 300 train
+uoyabkqpex 0 300 train
+uoyiffhkge 1 300 train
+uoyikorptf 1 298 train
+uoyklhrqav 0 300 val
+uoyqchrzaa 1 300 train
+uoyrbpucyl 1 300 train
+uoywrrhasp 0 300 train
+uoyycxbbzb 1 300 val
+uoyzdziaia 1 300 train
+uoyzugcsqe 1 300 train
+uozecebzki 1 300 test
+uozfacwovt 1 300 val
+uozkhpozjw 1 300 val
+uozkhsgtfy 1 300 train
+uozlwqeyvf 1 300 train
+uoznjlqxcj 1 300 train
+uoznkyoext 1 300 train
+uozpugqwfr 1 300 train
+uozvvzhsxr 1 300 train
+uozwzewrpt 1 300 train
+uozzanniwp 1 300 val
+upabsnugwg 1 300 train
+upadewcohq 1 300 train
+upaefpamqq 1 300 train
+upahgmozwj 1 300 train
+upaiseidfl 1 300 val
+upajgpnybr 1 300 test
+upajolsqqb 1 302 train
+upaoluyuab 1 300 val
+upatxapfpe 1 300 val
+upawcvzjcq 1 300 train
+upawlovoyb 0 300 val
+upaxbnnjlf 1 300 train
+upbercvjsr 0 300 train
+upbfilvvsn 1 300 val
+upbgvatwft 0 300 train
+upbjozuurj 1 298 train
+upbmtwzgli 1 300 train
+upbqmldoka 0 300 train
+upbvukttjs 1 300 train
+upcgeucbzp 1 300 val
+upcivrlmjs 1 241 train
+upclyjxtjw 1 300 val
+upcofjresc 0 300 val
+upcpqraglb 0 300 train
+updcxohtnn 0 300 train
+updgklljiv 1 299 train
+updjivevfn 0 300 train
+updjprrxyi 1 300 train
+updmpuotfw 1 300 train
+updoydlxxd 1 300 val
+updsnwikxs 1 300 train
+updxpjzkob 1 300 train
+updysdxnwc 1 300 train
+upecvobjzl 1 302 train
+upejpqvvfl 1 300 train
+upekdcbedf 1 300 train
+upelddahsd 1 300 val
+upetjoixvy 1 300 train
+upevmegdae 1 300 train
+upeyobdibl 1 300 val
+upezcrcdqz 0 300 train
+upfazrjlgx 1 300 train
+upfcyxxulb 1 300 train
+upfdcqmqna 1 300 val
+upfdsamiwf 1 300 train
+upfgaxnrcm 1 298 train
+upfgdyshre 1 300 test
+upfiawxrwu 1 301 train
+upfihkxrcz 0 300 train
+upfizcpwaf 1 300 train
+upgbumhpzo 1 300 train
+upgeoljmuf 1 300 train
+upgerjvcjb 0 300 train
+upghghmmvt 1 300 train
+upgoekpvep 1 300 train
+upgupickuj 1 300 val
+upgwpxpjew 1 300 train
+upgxnkryjs 0 300 train
+uphbhavksa 1 297 train
+uphfxcrpxf 1 299 test
+uphkzkvshe 1 300 val
+uphqymqhik 0 300 train
+uphqywpluy 1 300 train
+uphspzevgc 1 300 val
+uphyxffruw 1 300 train
+upicitmyln 1 300 val
+upicjqzrld 1 300 train
+upicyxbept 1 300 train
+upiglnuxww 0 300 train
+upikzruscn 1 301 val
+upimquyuzb 0 300 val
+upjbnptrcg 1 301 val
+upjdccuuzr 0 300 train
+upjfzuzpmd 1 300 val
+upjjvxowtp 1 239 train
+upjpywzofs 1 301 train
+upjsffsjto 1 301 train
+upjvuouney 1 300 val
+upjwnlxnry 1 300 train
+upjwungwii 1 299 train
+upjxnffxqn 1 300 test
+upkbzdwtgm 1 300 train
+upkcqguedw 1 301 val
+upkjdogriu 1 297 train
+upkqxlcpmk 1 300 train
+upkvltupip 1 300 train
+upkyrdjauz 1 301 val
+upkytynpel 0 300 train
+upkzlwxlza 1 300 train
+upkzpbdlbj 0 300 train
+uplcuyuvgf 1 300 val
+uplffqntfb 1 300 train
+upllirmhcd 1 300 train
+uplqdmwval 1 300 train
+uplsyyljtv 0 300 train
+upltgkcbzw 1 300 train
+upmcelriqd 1 300 val
+upmgtackuf 0 300 test
+upmiapadtj 1 300 train
+upmpdyeova 1 300 val
+upmsoebmpc 0 300 train
+upmwlpgyoy 1 301 val
+upncganvtg 1 300 train
+upnjhdtfpb 1 300 val
+upnlaucocm 0 239 train
+upnroajjzq 1 300 train
+upntjwlcjh 1 301 train
+upnuwqcgjp 1 300 train
+upnywxkcuw 0 300 train
+upnzyzlwnh 0 300 train
+upobpjhylz 1 300 train
+upoepwrnok 1 300 train
+upoexxyqor 0 300 val
+upokkayukg 1 300 train
+upoqfmefjv 1 300 val
+upoudjfpxr 1 300 val
+upouynojfh 1 300 train
+upowrtzdno 0 300 train
+upoygoavyg 1 298 train
+upphlazxcl 0 300 train
+uppihahqem 1 301 train
+upppyqjddg 0 300 train
+upqbalnwcw 1 300 train
+upqgpwzejd 1 298 val
+upqhelowpp 1 300 train
+upqslkidev 1 301 val
+upqxtkjdww 1 300 train
+upqypbozfx 1 300 train
+uprbkhpwni 1 301 val
+uprcnqizdm 1 300 train
+uprhmcacrm 1 300 test
+uprobtxyfq 1 300 val
+uproumsuby 1 301 val
+uprponwkob 1 300 train
+uprtlntgeb 1 300 val
+uprwuohbwx 0 300 test
+uprxolxcqf 1 300 train
+upsbzlrvgw 1 300 train
+upsfqhyzqr 1 300 train
+upsqvunimy 1 300 val
+upstqsvauf 1 298 train
+upstqszxjq 1 297 train
+upswpfarqz 1 300 test
+upswyxjfed 1 300 train
+upsyfmfmtl 1 300 val
+uptahgtulm 1 300 train
+upthdwrdwb 1 300 val
+uptijmoind 1 301 val
+uptkuuchme 1 300 train
+uptrderdxw 1 300 train
+upttkhclrb 1 300 train
+uptujieixg 1 301 train
+uptwajzwzy 1 301 train
+uptzjojfqk 1 301 train
+upuaklqqcs 1 300 train
+upubekspin 1 300 train
+upubtgycvq 0 301 train
+upufdnalyp 1 241 train
+upugetckpx 0 300 train
+upumdeuyrn 1 300 train
+upuobpieop 1 301 train
+upupdkkmtu 1 300 train
+upvhitbugz 1 300 val
+upvicjkrrt 1 298 train
+upvkxtdtie 1 300 train
+upvpiynjun 1 301 val
+upvqtkmdvp 0 298 train
+upvvaqwevl 1 300 train
+upvvwkppgn 1 300 train
+upwblpvvca 1 300 train
+upwdvsqvcf 1 300 train
+upwozqxiav 1 300 train
+upwqffzusq 1 300 train
+upwsvjdtgo 1 300 train
+upwtmbvqvb 1 300 train
+upwuufxocl 0 300 val
+upwyvqbjlq 1 300 train
+upxbzxgoco 0 300 train
+upxhhdpcii 0 300 train
+upxkigbddh 0 300 train
+upxmmhkivc 1 300 val
+upxmtwqqik 0 300 train
+upxozqexfa 1 300 train
+upycebbxjj 1 300 val
+upypnfwhqx 0 300 train
+upyqxcfiwn 1 241 train
+upyvrlsnbl 1 300 train
+upznkmslxk 1 300 train
+upzolpdrwa 1 300 train
+upztrqgfmd 1 300 train
+uqaaspbgtz 0 300 train
+uqaczgvsks 1 300 train
+uqadoepiic 0 300 val
+uqadrepzlz 1 300 val
+uqagpenhmy 1 300 val
+uqajkglnmm 1 300 val
+uqalgbooko 1 300 train
+uqapchaums 1 298 train
+uqawciamaf 1 300 train
+uqawzjjpre 1 300 train
+uqbafobbzq 1 300 train
+uqbeazhlcn 1 301 train
+uqbeuuvxfo 1 296 train
+uqbfqecudh 1 300 train
+uqbhdwljtw 1 300 train
+uqbhrsbnip 1 300 train
+uqbkqwymth 1 300 val
+uqbpznmcjj 0 300 train
+uqbsxmihbv 1 298 train
+uqbtxcmgtc 1 300 val
+uqcjoriqvy 1 300 train
+uqcpozlkfa 1 300 train
+uqddgucqbq 0 300 train
+uqdeichczm 1 300 val
+uqdikoshmi 1 300 train
+uqdkigumqe 1 300 train
+uqdrezlsxt 1 300 val
+uqecltwday 1 300 train
+uqerbjayta 1 300 train
+uqerusmaka 0 301 train
+uqeynbcjbv 1 301 train
+uqfawpqmjg 0 300 train
+uqfebqqyan 1 300 train
+uqffqijvxt 0 300 train
+uqfgpbmvry 1 300 val
+uqfhskqqrf 1 300 train
+uqfnqniamo 1 299 val
+uqfupetnht 1 298 train
+uqfzniktbx 1 300 train
+uqgalmrbtg 1 298 train
+uqgetizntv 1 300 train
+uqgtugqkxj 1 300 train
+uqguyibemu 0 300 train
+uqgwuhjzlo 1 300 train
+uqhoisnxye 1 300 val
+uqhoxraupo 0 300 train
+uqhtyfkant 1 300 val
+uqhwkjbxcu 1 147 train
+uqhxcvdsfj 1 300 train
+uqhzazznvl 1 298 train
+uqidpaginj 1 300 train
+uqidvkpfxa 1 300 val
+uqiehguuzl 1 300 val
+uqiglxjnhz 1 300 train
+uqiibrvtcv 1 300 train
+uqijkukqyy 1 300 train
+uqiouyadgp 1 300 train
+uqirnrsmja 1 300 train
+uqitcsdqra 1 300 train
+uqizqntekg 1 300 train
+uqjakflmnk 1 300 train
+uqjbenkczf 1 300 train
+uqjftfbwgk 1 300 train
+uqjnqgregj 1 300 train
+uqjvcygcuu 1 299 val
+uqjwtcmhek 1 134 val
+uqkbctetpi 0 300 train
+uqkcqduxfw 1 300 train
+uqkdiusxtz 1 300 train
+uqkkpcispv 1 300 train
+uqkntienaz 1 297 train
+uqkttsjcxz 1 300 train
+uqkweznhqt 1 300 train
+uqkwkynmlu 1 300 train
+uqkxwatsyt 1 301 train
+uqlbpoleew 0 300 train
+uqlbzgfhrp 1 300 train
+uqldhfdypp 1 301 val
+uqlmwmxmqn 1 300 train
+uqlxndbjuq 1 300 train
+uqlyfsjwck 1 300 train
+uqmdorxhqd 0 300 train
+uqmibbupxx 1 300 train
+uqmnkmtnzq 1 300 train
+uqmrousaoy 1 300 train
+uqmwwqkppo 0 300 val
+uqmyqomxgj 0 300 train
+uqndjhyrat 1 298 train
+uqnhilzzey 1 300 train
+uqnjkrcxwh 1 300 train
+uqnmqbbdyl 1 300 val
+uqnsynghnc 1 301 train
+uqntkvpntd 1 300 train
+uqocbmiuxg 1 300 train
+uqoctszbev 1 300 train
+uqognreaor 0 300 train
+uqohwjybkg 1 300 train
+uqolpndkbw 1 300 train
+uqosmhxymk 1 300 train
+uqounkkldx 1 300 train
+uqowakubef 1 300 val
+uqowckhnlo 1 297 train
+uqpgwzhlvd 1 300 train
+uqphgvjweq 1 300 val
+uqpigevvkm 1 300 train
+uqplddijii 1 300 train
+uqprlobtsn 0 300 train
+uqpvpdcdjl 1 299 val
+uqpwibielr 0 300 train
+uqpyfhjdpr 1 301 val
+uqqcaaukdg 1 300 train
+uqqczhylto 1 300 train
+uqqegrmuth 0 300 train
+uqqivuldlu 1 300 test
+uqqrxxgwgd 0 300 val
+uqrcoimmit 1 300 train
+uqrfgxremg 1 300 train
+uqrgyoozvq 0 300 train
+uqrhpwmrjo 1 301 train
+uqrjhxsydw 1 300 train
+uqrjsjwkdq 1 300 test
+uqrkgwxcjb 1 300 train
+uqrkjmmtjn 1 300 val
+uqrtkvkwdu 0 300 train
+uqrwgslayc 0 300 train
+uqsbkvfkif 1 300 train
+uqsfobfhjf 1 300 train
+uqsianxhju 1 300 train
+uqsictgsxf 0 300 train
+uqslcsyvqy 1 300 train
+uqsnyzcjte 1 300 train
+uqsrlbjpsi 1 300 train
+uqssnjpkzr 1 300 train
+uqsvynmjuk 1 300 train
+uqtezgfjgd 1 300 train
+uqtffidyag 1 300 train
+uqthoawaxk 1 300 train
+uqtjjxdflt 1 300 train
+uqtlkbtjsf 1 301 train
+uqtpkpcphi 1 300 train
+uqtqhiqymz 0 300 test
+uqtrvfugdi 1 299 val
+uqtscxeeje 1 300 train
+uqtxeslhzq 0 300 train
+uquhgcoafp 1 269 train
+uquiozoudk 0 300 train
+uqumixjkam 1 300 train
+uqumoqocnx 1 300 val
+uqunxvrfhd 0 300 train
+uquolpapnm 1 300 train
+uquqtmvrar 1 301 val
+uquqxomuhg 1 300 train
+uqusfsdsbi 1 300 train
+uquyglwmax 1 300 train
+uqvbuptnfv 0 300 train
+uqvhrkcnfg 1 296 val
+uqvlfblttj 1 300 train
+uqvttodxsh 1 300 train
+uqvxjfpwdo 1 300 test
+uqwfmgsrxc 1 300 train
+uqwlownylw 1 300 train
+uqwzbcmqwq 1 300 test
+uqxckbbafz 1 300 train
+uqxckixojj 1 300 train
+uqxddszhef 1 300 train
+uqxeoibzvv 0 300 train
+uqxiwhpkcw 1 300 val
+uqxjxoduuy 1 300 val
+uqxmskujse 0 300 train
+uqxqmikdqe 1 301 val
+uqxtcfebga 1 241 train
+uqxzdeivfv 1 296 train
+uqyffesjft 1 300 train
+uqyfpmyfjx 1 300 train
+uqyicbrmuq 1 299 test
+uqyyookybd 1 300 train
+uqyzdorjos 1 300 train
+uqzbwowjai 0 300 val
+uqzenivpjc 1 300 train
+uqzgsfqjxw 1 300 train
+uqzgyxstct 1 300 val
+uqzhzxhnwv 1 300 train
+uqzkqbdpfx 0 300 train
+uqzkxkmhmw 1 300 train
+uqzndggowe 1 300 train
+uqzztyryyp 1 241 train
+urahsuedia 1 299 train
+uraibiaste 1 300 test
+urajpnzzvs 1 300 val
+urarchzvhl 1 300 train
+uratvdiptg 0 300 train
+uravmovghg 1 300 train
+urawgdmtzy 1 300 val
+urbazdmzwg 1 300 train
+urbhjtjqlp 1 241 train
+urbktryrig 1 300 val
+urbkzzqnop 1 300 train
+urbnivhpsz 1 300 train
+urbpopprjv 1 298 train
+urbulrzowx 0 300 train
+urbxghqejl 0 300 train
+urbybjokuy 0 300 train
+urcfwpvseg 1 241 train
+urchvqmbpu 1 300 train
+urchwltyde 1 300 train
+urcieothwt 1 300 train
+urcxgvwykl 1 241 train
+urdaaeyvre 1 299 val
+urdbkcaiqo 1 300 train
+urdegesals 1 300 val
+urdgvejrzz 1 300 train
+urdnnksdpz 1 300 val
+urdywvhxdm 1 300 train
+ureaimdzsn 0 300 train
+urebotcvja 1 300 train
+urehmtzoet 1 300 train
+urepmiaqqr 0 300 train
+ureqteopum 1 300 train
+urevcaskwe 1 300 train
+urexgwkkwy 1 300 train
+urfgbrgbbg 1 301 val
+urfhsvdeac 1 300 train
+urfinczxve 1 300 train
+urfnmqjzcm 1 300 train
+urfpwxqqif 1 300 train
+urftoetmji 1 300 train
+urfuhntprf 0 300 train
+urfxvtisay 1 300 val
+urgbvbwgud 1 301 train
+urgdtdchei 1 300 test
+urgjjrklfv 1 300 train
+urgnibbjnl 1 300 train
+urgplwgjzd 0 300 train
+urgrdxyooa 1 300 train
+urhablfodn 1 300 train
+urhafrmeox 0 300 train
+urhgwhqhkr 1 301 train
+urhjflxaxx 1 300 train
+urhkxvdudv 1 301 val
+urhnruwybr 1 300 train
+urhykuhlzk 1 300 train
+urhzdfzsqa 1 299 train
+urhznpzcea 1 300 train
+uriaxvhlhu 1 300 val
+uriioqeait 1 300 val
+uriivjuinh 1 300 train
+urikzkgaze 1 300 train
+uriohazzqe 0 300 val
+uripyyofxy 1 300 test
+uriwqjslbk 1 300 train
+urizvuzukr 1 300 train
+urjalhwlby 1 300 train
+urjhlwwihm 1 300 train
+urjmqsfzma 1 300 train
+urjqbwxfwd 1 298 train
+urjxsgqdpu 1 300 train
+urkakoappt 1 300 train
+urkdwctnan 1 301 train
+urkghvdumm 1 300 val
+urkhwikktw 1 300 train
+urkkpopfzg 1 300 train
+urklstpxps 1 300 train
+urknrcqmgq 1 298 train
+urktldcubd 1 300 train
+urletjgqbo 1 300 train
+urlkfbvuyz 1 300 train
+urlkwrljdo 1 300 train
+urloiqxdwi 0 300 train
+urlxcfzdxd 1 299 train
+urmgsrkwid 1 300 test
+urmvetkkyw 1 301 val
+urmwakciim 1 300 val
+urnbluvmqs 1 240 train
+urnglymoaa 1 300 train
+urnjvhmafb 1 292 val
+urnppyywnk 1 298 train
+urnqalzaon 0 300 val
+urnuztutgi 1 300 train
+urnwbwaocu 1 300 train
+uroeempcme 1 300 train
+uroivvahux 1 300 train
+urooekxlmq 0 300 train
+uropdnfcxp 0 298 train
+urorioavby 0 300 train
+urovdzyyff 1 300 train
+urpdwjsjkf 0 300 train
+urpebtxyav 1 300 train
+urphbybmrq 1 301 val
+urphtccqnm 1 300 train
+urpjyivumo 1 300 train
+urpneylxje 1 300 train
+urpoywfqow 1 300 train
+urpqcasyii 1 300 train
+urpriwazhh 1 300 val
+urprknapog 1 300 train
+urqaihjkol 0 301 train
+urqfnccczs 1 300 train
+urqjezrqya 1 300 train
+urqmictmau 1 300 val
+urqnlofnpa 0 300 train
+urqphmbbwt 1 300 train
+urqtyxbwce 0 300 train
+urqurvnufu 1 240 val
+urrbejkrri 0 300 val
+urrcsprniv 1 300 val
+urrcwvfmun 1 300 train
+urrmqfhbwx 0 300 train
+urrrqoybnq 0 300 train
+urrtnflaqi 1 300 val
+ursdhuutkf 1 300 train
+ursnzpvqvc 1 300 val
+ursswbwnwd 1 301 train
+urszjvavkl 1 300 train
+urtdvnkodp 1 300 train
+urtkjcthyu 1 299 val
+urtkxkzqot 1 300 train
+urtogxlthb 1 300 train
+urtoptlzqs 1 300 val
+urtrdzioob 1 300 train
+urtxlamxes 1 300 train
+urtxmrxlsp 1 300 train
+urufyqzawd 1 300 val
+uruioabeay 0 300 val
+urukdrrowr 1 288 train
+urulyifjjs 1 300 train
+urupmbgfzy 1 300 train
+uruvfgzgjy 1 300 train
+uruzfuhoft 1 300 train
+urvbhukwqm 1 300 train
+urvifexbsd 1 300 train
+urvjcuwtde 1 300 train
+urvjkwyygo 1 300 val
+urvmevrjut 0 300 val
+urvpisjzlv 0 300 train
+urvsslnhee 0 300 train
+urvzpbswoh 1 300 test
+urwawhmzin 1 241 train
+urwdvnypnf 1 300 val
+urwiaadvhl 1 300 train
+urwkhiitcw 1 300 train
+urwlbpwsqg 1 300 train
+urwmdcngau 0 300 train
+urwsukpwtt 1 301 train
+urwteitazn 0 300 val
+urxcrhkvda 1 300 train
+urxdctqpqx 0 300 train
+urxgkghlrw 1 300 train
+urxifmrcll 0 300 train
+urxizgowsj 0 300 train
+urxkhxietl 1 300 train
+urxrgmhqjq 1 300 train
+urxxliiarv 1 300 val
+uryamchmyh 0 300 train
+urybulcjjj 1 300 train
+urydhdejxz 1 300 val
+urydyzuuiz 0 299 train
+uryftkditg 0 301 val
+urygzzowre 1 300 train
+urymjmciep 0 300 val
+urynqxxkxx 0 300 train
+uryntxpnaq 1 300 val
+uryractxga 1 300 train
+uryuqtrxqu 1 300 train
+uryveedswz 1 241 train
+urzdmrzkcm 1 301 train
+urzgrfqlww 1 300 val
+urzjldavfo 1 300 test
+urzqzbnmkf 1 300 test
+urzvuvzohy 1 301 train
+urzwaqzndl 1 300 train
+urzzvxaoyq 1 300 train
+usaanzxier 1 300 train
+usadfkaxpl 1 300 val
+usagzyjssz 1 300 train
+usatwyxmao 1 300 train
+usayqqnvpu 1 300 val
+usbetlgwhj 0 300 train
+usbfdqgbym 0 300 train
+usbmgbycdi 1 300 val
+usbnkvscld 1 301 val
+usbnyondzf 1 300 train
+usbzfkhyth 0 300 train
+uscaynzueb 1 298 train
+usckhmrgev 0 300 train
+uscpcutfra 1 301 val
+uscvdwdtvp 0 301 train
+uscypfggee 1 300 val
+usdqlvfjvu 1 300 val
+usdslswrat 1 300 train
+usdspcjqmu 0 301 train
+usdsqvdgfj 1 300 train
+usdtpjplub 1 300 train
+usegeascpc 1 300 train
+usemwbkwvz 1 300 train
+usenqorfbm 0 300 val
+usepjynxtl 1 241 train
+useqpjezlp 1 300 train
+usesdmuqzh 0 301 train
+useuukguiy 1 300 train
+useyqsfxsr 0 300 train
+usfdcagnsp 1 301 val
+usfevxqgfb 1 300 val
+usfhusvngv 1 300 train
+usfmolmtuy 1 300 train
+usfonypnnm 1 300 train
+usfowtggox 1 300 train
+usfpcrskep 1 300 train
+usfqqokkhe 1 300 train
+usftabqojg 1 300 train
+usftmangwb 0 300 train
+usfwkpursg 1 300 train
+usgjegmdgr 0 300 val
+usgolujbuf 1 300 val
+usgooifxkz 1 301 train
+usgpvwcncz 1 300 train
+usgsmxfelo 0 300 train
+usgtyvixrq 0 300 train
+usgumjluzh 1 300 train
+usgwrhgafb 1 300 train
+usgzyilrwn 1 300 train
+ushakujdoi 0 300 val
+ushfsgkbit 0 300 train
+ushjtzfvyn 1 300 test
+ushmaagcnn 1 301 val
+ushmsbvaap 1 300 val
+ushqdzxdrj 1 300 train
+ushsnajgdf 1 300 val
+usicnmwdll 1 299 test
+usidlfjmyo 1 300 train
+usihgkrbvk 1 300 train
+usilohmdbj 1 300 train
+usilttkrzx 1 300 val
+usizruoopi 0 300 train
+usjaafgemb 1 301 val
+usjbgypsdm 1 298 train
+usjbortonm 0 300 train
+usjdpptrju 1 301 val
+usjebzgmce 0 300 val
+usjekoukzs 1 300 train
+usjlckywbi 1 300 train
+usjnlahlcj 1 300 train
+usjoggggua 1 300 train
+usjqdvsbdh 1 299 test
+usjqyfgrpu 0 300 train
+usjuqnhyta 1 292 val
+usjxwnqvtw 1 300 train
+usjzfmtoxx 1 301 val
+uskjtnuvbd 1 301 train
+uskqtejvlw 1 300 val
+uskrifltcy 0 300 train
+uskrkaasta 1 298 train
+uskteiefkc 1 300 train
+uskysinzim 0 300 val
+uslfuhiexh 0 300 train
+uslhldurdj 1 300 val
+uslnmnpyty 0 300 val
+uslrdwoywo 1 300 train
+uslscwulok 0 299 val
+uslxvyvyqd 1 300 train
+usmbitsezo 1 301 val
+usmciumoyl 0 300 train
+usmkpzrmdu 1 301 train
+usmmpqmokb 0 300 train
+usmnxvogut 1 301 train
+usmqeolvdy 1 300 train
+usmvmvlxlg 1 300 train
+usmwfoeysu 0 300 val
+usmxakqiml 0 300 train
+usnebepgbk 1 300 val
+usngbzxmnd 1 300 train
+usnkjdugyt 1 300 val
+usnkvutfzz 1 300 train
+usnowmcuqk 1 299 test
+usnyozppis 0 298 train
+usobniufak 1 300 val
+usofmqgeqo 1 300 train
+usopcidiqn 1 300 train
+usoqomvlrc 1 298 train
+usorkdoptf 0 300 train
+usowbfpjgv 1 300 train
+usoxrswrap 1 300 train
+uspbvpmuul 1 300 train
+uspnygmzlf 1 300 train
+usprpssifn 1 300 train
+usqbxicsum 1 300 train
+usqdcavxco 1 299 val
+usqlztyxsn 1 300 train
+usqngjxenw 1 301 train
+usqnovyhes 1 301 val
+usqqvxcjmg 1 300 test
+usqwjtjrjg 0 300 train
+usreqgzenq 1 300 train
+usrhzywhjt 0 300 train
+usrkylpntf 1 300 train
+usrlhbzwqn 1 300 train
+usrqadpesh 0 300 train
+usrupbtxuu 1 300 val
+usrupiiqwm 1 300 train
+usrvunyylx 0 300 train
+usryigygqc 1 300 val
+ussimgbbgp 1 300 train
+ussjvcgpmt 1 300 train
+ussksxfcrd 1 302 train
+ussywadmdl 1 300 val
+ustctvevep 1 300 train
+ustezmxibd 1 300 train
+ustfjidvdh 1 298 train
+ustgurzygd 1 296 train
+ustgxpfrze 1 300 train
+ustjkjqlup 1 300 train
+ustjseongh 1 300 train
+ustsdmxebc 1 298 train
+ustzhrwopt 0 300 train
+usuenlcdcd 1 301 train
+usuiydeyqr 1 300 train
+usurlmfkjh 1 300 train
+ususmqdnwk 1 300 val
+usutboyyqq 1 300 val
+usuuamrxjp 1 300 val
+usuutiylge 1 300 val
+usvbatdkxz 1 300 train
+usvbvmlafg 1 241 train
+usvdgziumg 1 300 train
+usvjzoinhn 1 300 train
+usvqsfcsol 1 300 train
+usvtrbpqks 1 300 train
+usvtycwvwk 0 300 train
+usvywysqdl 1 300 train
+uswefjjphg 1 298 train
+uswgudfwoe 1 300 train
+uswonbndql 0 300 train
+uswrijmnfv 1 300 train
+uswyutecjl 1 298 train
+usxbjyowsi 0 300 train
+usxdfkyiuz 1 300 train
+usxhouantd 1 300 train
+usxizgqsxx 1 300 train
+usxooyvbni 1 300 train
+usxqkanmrv 1 301 val
+usxqrytcze 1 240 val
+usxsdztgzq 1 300 train
+usxsoajthj 1 300 train
+usxwvvhtih 0 300 train
+usyqjfaryg 1 300 val
+usyuzzmkyx 0 300 val
+usywrisusw 1 300 train
+uszersxejh 1 300 train
+uszmotkxks 1 300 train
+usznduzbug 1 300 train
+uszudvazae 1 300 train
+uszxdmvdos 1 300 train
+utadltmezl 1 300 train
+utailgpcpk 1 300 train
+utapxokove 1 300 train
+utapzqwexe 1 298 train
+utbbnubmcn 1 300 train
+utbdmqjrhg 0 300 train
+utbdpayeeb 1 300 train
+utbepravqt 1 299 val
+utbhuezerm 1 300 train
+utbiwnkzct 0 300 train
+utbqagvslm 1 300 train
+utbukhjacn 0 300 train
+utccmvubvy 1 301 train
+utckcscuyz 1 300 train
+utcpkwzmxt 1 300 train
+utcykgtpfq 1 300 train
+utdaemefpv 1 300 train
+utdahcaubc 1 300 train
+utdcjeaidc 1 300 train
+utddbwtdjz 1 300 train
+utdfrnkyov 1 302 train
+utdlebzgoc 1 300 train
+utdlsqfykm 1 300 test
+utdnfsfkap 0 300 val
+utdqvtzcwx 1 241 train
+utdylnarnm 1 300 train
+utebhplinb 1 300 train
+utegbirfii 1 300 train
+utejavsqss 1 300 train
+utesurhign 1 300 train
+utevdmzzen 0 300 val
+utevfswzay 1 300 train
+utfamtxcne 0 300 train
+utfhswstjn 1 300 train
+utflcqrvnr 1 300 train
+utflkdvchw 1 301 train
+utfvrzienn 1 300 train
+utfydtrgqo 1 300 train
+utgbmipcmp 0 300 train
+utgpfzdlrz 1 302 train
+utgpkekahm 1 300 train
+utgsknxgwb 1 300 train
+utgxchqsqj 1 300 train
+uthdefddbm 1 300 train
+uthokfhxko 1 300 train
+uthqexubgl 1 301 val
+utiasydqaq 1 299 train
+utibdceofc 1 300 train
+utiephcocy 1 300 train
+utifnqizgh 1 301 train
+utiirgwbdw 1 300 train
+utijijklnq 1 298 train
+utinfiqowk 1 300 train
+utiqyssfsn 1 301 val
+utiqzvhbok 1 300 train
+utjayyhely 1 300 train
+utjgszkkpx 1 300 train
+utjhiuhizj 1 300 train
+utjillbnvu 1 300 train
+utjkrwcexm 1 300 val
+utjlovulfq 0 300 train
+utjrjnqbae 1 300 train
+utjrtrmbrt 1 300 train
+utjtcobrzg 1 297 train
+utjwjpkidv 1 300 train
+utkaptlbpw 1 300 train
+utkchehzaa 1 241 train
+utkfpuuvop 1 300 train
+utkjvotqni 1 300 train
+utkpjuvsof 1 300 train
+utkrkbayup 1 301 train
+utkrusiplj 1 300 train
+utkujzslgl 1 300 train
+utkvpomfvj 1 300 train
+utlfzwucse 1 240 train
+utlickvkfl 1 300 train
+utmbokytiu 1 300 val
+utmexpmahh 1 300 train
+utmllvpzkv 1 300 train
+utmmdexsxb 1 300 train
+utmyjsjnxs 1 300 train
+utndcmipgm 0 300 train
+utndoisncb 1 300 val
+utnfadqqea 1 300 train
+utngfmlhmp 1 300 val
+utnizyqmri 0 300 train
+utnnipjsbr 1 300 train
+utnqkpbhvs 0 300 train
+utnwupjdpp 0 300 train
+utnwynygrf 1 300 train
+utnxmqunkj 1 300 val
+utnxucbghl 1 300 train
+utocfkmovz 1 300 val
+utoltzhxhd 1 300 train
+utowigcouc 1 300 val
+utowkxstiq 1 300 train
+utpjlpviln 1 300 train
+utpsqkrgtc 1 300 train
+utpwzmqgdn 1 300 train
+utpxijaiuf 1 300 train
+utqangjsad 0 300 val
+utqeognvoq 0 300 val
+utqhlximwa 1 300 train
+utqiyokaxa 0 300 train
+utqkrroeoz 1 300 train
+utqotljcer 1 300 train
+utqxvfbpok 1 300 train
+utrjinfwvn 1 300 val
+utrmwnogjd 0 300 train
+utrtvyrbps 1 296 train
+utsawapsbs 1 300 train
+utskpxqijx 1 299 test
+utsmbwigyi 1 300 val
+utsqgwqadw 1 300 val
+utsqkbuvjv 1 255 train
+uttchmlnnv 1 300 val
+uttfptteah 1 300 train
+uttheobodn 0 300 train
+uttjoocfba 1 300 train
+uttkcmnqiu 1 300 train
+uttnfmvqxk 1 300 train
+uttsmmtehm 1 300 train
+uttucnjlcc 1 241 train
+uttuhnntpv 1 300 train
+uttveiwvcq 1 301 train
+utumhfamjb 1 300 train
+utuootjwlc 0 300 val
+uturqnfaer 1 300 train
+uturwxdnmd 1 300 train
+utuuymtpln 1 301 val
+utuxbbvqde 1 300 train
+utuxeawqrt 1 297 train
+utuyrqozse 1 300 train
+utvjutckcc 1 300 train
+utvnuhrhxe 0 300 train
+utvuhdghsm 1 300 train
+utwbyfsysg 1 300 val
+utwenybrtk 1 300 train
+utwhgassbw 1 300 train
+utwhtoowwm 0 300 train
+utwnfmgzgr 1 302 train
+utwwebrler 1 300 train
+utxbqyxdwo 1 300 test
+utxjkofcdy 1 300 train
+utxsqzcrbt 0 300 val
+utxxopbcuk 1 300 train
+utybghumrf 1 300 val
+utycbfoswp 1 241 train
+utyfeywfyv 1 300 train
+utyhmbxfvy 1 300 train
+utyifybkkr 1 300 train
+utykcmxvxp 1 300 train
+utylupjqfi 1 300 train
+utyrstessb 0 300 train
+utyrzfpems 1 300 val
+utyyjiqeuo 1 300 train
+utzfjwgwqv 1 300 train
+utzjvukuhg 1 300 val
+utzkxisewv 1 300 train
+utzrzvhnbe 0 300 train
+utzsehqspn 1 300 train
+utzvrdyvbr 1 300 train
+uuakbooujv 1 301 val
+uuakfvajme 1 300 val
+uuanrpgsja 1 300 train
+uuarpcxxoy 1 301 train
+uuavndpnxs 1 300 train
+uubaefmgxt 1 300 train
+uubfhzvuco 1 300 train
+uubfyqtaho 1 300 train
+uubgqnvfdl 1 299 test
+uubjjckmej 0 301 train
+uubommbnlf 1 300 val
+uubstedpln 1 301 train
+uubvowiegs 1 300 train
+uubzzbfcpu 1 300 train
+uuceddjxyj 1 300 train
+uucnlezlzo 1 300 train
+uucsgyuejy 1 300 train
+uudatczgxs 1 297 train
+uudhxrgrix 0 300 train
+uudlbgvuwz 1 300 train
+uudouzhchc 0 300 train
+uudrzpnzdr 1 300 train
+uudslbyvqb 1 300 train
+uudzjeddrl 1 300 train
+uuecllezla 1 300 train
+uuedatpjxc 1 300 train
+uueedptzma 0 300 train
+uuemauhfph 1 300 val
+uueofqovjj 1 300 train
+uuesxzdxol 1 301 train
+uueufvybgq 1 300 train
+uuevnglpje 1 300 val
+uuexerjsmk 1 300 test
+uueykqzcll 0 300 train
+uufdlyayxp 1 300 train
+uufofdpfds 1 300 test
+uufozqkfkf 0 300 train
+uufppmldvm 1 300 train
+uufrocttjs 1 300 val
+uufwakhvqo 1 239 val
+uufxagcqrl 1 300 val
+uufyiigqbi 1 241 train
+uugdjzyrqj 1 300 val
+uugkcetjxj 0 300 val
+uugmrwcnwt 1 300 train
+uugpraqpja 1 239 val
+uugsdhqfka 1 300 train
+uugsqqrrbr 1 300 train
+uugtxdxizk 1 300 train
+uugunhfxrj 1 300 val
+uugytivxaq 1 300 val
+uuhjprorxb 1 300 val
+uuhlkmfdux 0 300 train
+uuhnhpsnct 1 300 train
+uuhvxweduw 1 300 train
+uuhzxllyug 1 300 train
+uuiaghtmqa 0 300 train
+uuickmjguc 1 300 train
+uuifkhztqq 1 300 val
+uuihvfgqau 0 300 train
+uuilzsbtgz 1 300 val
+uuiodajqzm 1 300 train
+uuipomilwe 1 300 train
+uuisaarhzt 0 300 train
+uuivunypag 1 300 val
+uuiwlluaeh 1 300 train
+uuixytykuc 0 300 train
+uuiyczhoql 1 300 train
+uujdeyaips 1 300 train
+uujermqbpb 1 300 train
+uujtgpehhz 0 300 train
+uukbdjaedq 1 300 train
+uukgsmowac 1 300 train
+uukvoagswe 1 300 train
+uukvpszvcr 1 300 train
+uulabkvfns 0 300 train
+uulbfrrfdr 0 300 train
+uulkdyuvrj 1 300 train
+uulplqqlom 0 300 train
+uulrdidwbe 1 300 train
+uumaxedycc 1 300 val
+uumdjtwgel 1 300 train
+uumfectifw 1 241 val
+uumhbwghwr 1 300 train
+uumjcbvlmq 1 300 train
+uumsnmtmyg 1 300 train
+uumvhzutpo 1 300 val
+uumxnzjpzk 1 300 train
+uumylzfykw 1 300 train
+uumzxasaxv 1 300 train
+uunbmttqbx 1 300 train
+uundjlzalq 1 300 train
+uunealgwvj 0 300 train
+uungjhphuv 0 300 train
+uunigvwoir 1 241 train
+uuniyowdis 0 300 train
+uunrfposre 1 300 val
+uunsajfqxx 1 300 train
+uunsdlndti 1 300 train
+uunsgpnxiw 1 300 train
+uunvggokej 1 300 val
+uuobtdhvaz 1 300 train
+uuoeukncsv 1 300 train
+uuohuvuylm 1 297 train
+uuopbqklch 0 298 train
+uuotyjxvod 0 300 val
+uuowkwtkkj 1 299 val
+uupifagjqo 1 298 train
+uupjscimhi 1 300 train
+uuposvodqz 1 300 train
+uuppqhueun 1 300 train
+uupsepswze 1 300 train
+uupvpqjihk 1 301 train
+uuqfasulad 1 300 train
+uuqidbazkb 1 300 train
+uuqkvuejdf 1 300 val
+uuqlhitjcx 1 300 train
+uuqocrpabe 1 300 val
+uuqpvxmfnw 1 300 val
+uuqrzdhjuh 0 300 train
+uuqtsdgbei 1 300 train
+uuqufnpocs 1 300 train
+uuqvgipzxq 1 300 train
+uurhbyktzw 1 300 train
+uurjvuvaag 1 301 train
+uurpocvenf 1 300 train
+uurqeigztd 0 300 val
+uurrbdmvlc 1 298 train
+uursiulmds 0 300 train
+uursnsxszo 1 300 train
+uurvcmdqwc 1 300 train
+uurycrrtfc 0 300 train
+uuryihjvzf 1 241 train
+uurysjbcwn 1 300 train
+uuscfojzrt 1 300 train
+uuscpmxhpi 1 300 train
+uusihxiomf 0 300 train
+uusmztzrkb 0 300 val
+uusnayebqq 0 300 train
+uusoeynjla 1 300 train
+uutbvtpkfc 1 300 train
+uutchkbwsj 1 300 train
+uutiybwouv 1 300 val
+uutjxdvywj 0 300 train
+uutjxogujq 1 301 train
+uutnzoenpv 1 300 train
+uutslsqons 1 302 train
+uutvtucijo 1 301 train
+uutxmgqajd 0 300 train
+uuulaqwgny 0 300 train
+uuuokilkbr 0 300 val
+uuuriugdem 1 300 train
+uuuupjmscy 1 298 train
+uuvasflgaw 1 300 train
+uuvgkkwnmp 1 300 train
+uuvnxfzdtj 0 300 val
+uuvoiaekth 0 300 train
+uuvomcizpo 1 300 train
+uuvwzuvbmb 1 300 train
+uuwbuffwpk 1 300 train
+uuwexeuzwt 1 300 train
+uuwfgichjb 0 300 train
+uuwidltakm 0 300 train
+uuwkcqqhku 0 300 val
+uuwtppisur 1 300 train
+uuwwppbqma 1 300 train
+uuwxzuccwb 0 300 train
+uuxajkbaga 0 300 val
+uuxchiaqou 1 300 val
+uuxopbcfcv 1 300 val
+uuxpvjfble 1 300 train
+uuxqylnzls 0 300 train
+uuxslyqkrs 0 300 train
+uuxxyhwtqw 1 300 train
+uuyedvpghw 1 300 train
+uuygguarwr 1 300 train
+uuyhlqbugo 1 300 val
+uuykfhxihi 1 300 train
+uuyluuzfdd 1 300 train
+uuynfvpdzz 0 300 train
+uuyqhdblpl 1 299 train
+uuyrvfvavu 1 300 train
+uuywuhtqfi 1 300 train
+uuyyezfcnx 0 300 train
+uuyyrlbrdu 1 300 val
+uuzalivrsv 1 300 train
+uuzbemotoh 1 300 val
+uuzhgdmkoy 1 301 train
+uuzyzglejw 0 300 train
+uuzzmxbjwd 1 300 train
+uvadhpabps 1 301 val
+uvadhsbbhm 1 300 train
+uvafzrjvqg 1 300 val
+uvarwbjvcv 1 300 train
+uvatcqnhoz 1 301 train
+uvazygkstj 1 300 train
+uvbfjiohah 1 300 val
+uvbrpyxale 1 300 train
+uvbsmndrna 1 300 train
+uvbtguwzer 1 298 train
+uvbualonpg 1 300 train
+uvbzzcthwp 1 300 train
+uvcaryazhi 1 300 train
+uvccplpsoe 1 300 val
+uvcdjksizj 1 300 train
+uvcekvvrfu 1 300 train
+uvchwckcte 0 300 train
+uvciahkhzw 1 300 train
+uvciapfbqr 1 300 train
+uvcmnjvwwg 0 301 train
+uvcselqnls 1 300 val
+uvcwifmnjj 1 300 train
+uvcxmvabgx 0 300 train
+uvcxzaxsli 1 298 train
+uvdbekxklb 1 300 train
+uvdtaigxsk 1 300 val
+uvdzymytyr 0 298 train
+uveaklifbi 1 300 train
+uveclbfpfo 1 300 train
+uvecpjaupp 1 300 val
+uveghnihnz 1 300 train
+uvemyzwoos 1 300 train
+uvenksrapv 0 300 train
+uveqhhfdnw 1 300 train
+uvetxzvwrv 1 300 val
+uveucfohux 1 300 val
+uvfiplgrex 1 300 train
+uvfkppqsjy 1 300 val
+uvfkrhnllr 1 300 train
+uvfpvrykfq 1 300 val
+uvfvbjdqrp 1 300 train
+uvfybmqdxc 1 300 train
+uvgeeahvpv 1 300 val
+uvgjewintf 1 300 val
+uvgqoqxyhy 1 300 train
+uvgtzdwnfl 1 301 train
+uvgvttmapk 1 299 val
+uvhawicszh 1 301 val
+uvhdrfnaxn 1 300 val
+uvhgalfgre 1 300 train
+uvhgrgeady 1 300 train
+uvhgyietjs 1 299 test
+uvhjgpqpik 1 300 train
+uvhlspucua 1 300 train
+uvhxgaoieh 0 300 train
+uvijfspmjb 1 300 val
+uvijrvbfdi 1 300 train
+uvipfcegwd 1 298 train
+uvivqehlky 1 300 train
+uvixoukpiv 0 300 val
+uviywgksgd 0 300 val
+uvjapszjxq 0 300 train
+uvjevytnqy 0 300 train
+uvjndtihbf 1 300 train
+uvkacoxuzk 1 300 train
+uvkamblolg 1 300 train
+uvkbpwbvix 1 300 train
+uvkepukszg 1 300 train
+uvkitydyla 1 300 train
+uvkjcjncow 1 300 train
+uvkommfses 1 300 train
+uvkqkizktr 1 299 val
+uvlagehhac 1 300 train
+uvlmcgybkk 1 300 val
+uvlpfcpvvj 1 297 val
+uvlpkbwvda 1 300 train
+uvlrgrtggg 1 300 train
+uvlwxxdbid 1 300 train
+uvlynrnmgb 1 299 val
+uvmjqkbdfu 1 300 train
+uvmnbnminv 0 300 train
+uvmsuaploo 1 298 train
+uvmukuqcay 0 300 val
+uvmxltcqxw 1 300 train
+uvmzrydsml 1 300 train
+uvnefxyqsy 0 300 train
+uvnfaqaojw 1 300 val
+uvnfpzlbcm 1 300 val
+uvngeollxs 1 300 train
+uvngwtikqt 0 300 train
+uvnnkusleo 1 300 train
+uvntelzsnn 1 300 train
+uvnvsnfgvh 1 301 train
+uvnvzstxmv 1 301 train
+uvoaszbjuv 1 269 train
+uvogzfylos 0 300 train
+uvospoaill 0 300 val
+uvoxyvokzq 1 300 train
+uvozmhibat 1 300 train
+uvpcmbutwe 1 301 train
+uvphdbgsia 1 300 val
+uvpxabrlln 1 300 val
+uvpzejdwos 1 300 train
+uvqfmpbxos 1 300 train
+uvqgbpumou 1 300 train
+uvqiaycegp 1 301 train
+uvqirjmnxe 1 301 train
+uvqoqaicbo 0 300 val
+uvqpbzcqtc 0 300 val
+uvqwmpfklm 0 300 train
+uvrlcdakej 1 300 train
+uvroruyqea 1 299 val
+uvrpmdxenk 1 300 train
+uvrxpikmjw 1 300 train
+uvrzaczrbx 0 300 test
+uvsdfheaiv 1 300 train
+uvskkqzull 1 300 train
+uvsptpxhep 0 300 train
+uvsqiqyjcs 1 300 val
+uvsvcmktvi 1 300 train
+uvsxysqatj 1 300 train
+uvtzwenpdz 1 300 train
+uvuahskwrx 0 300 train
+uvubglruyj 0 300 train
+uvublgiomi 0 300 val
+uvucbujofz 0 300 train
+uvuioxigps 0 301 train
+uvukxbzevm 1 300 train
+uvuqibkiiq 0 300 train
+uvuqozqxqt 0 300 val
+uvutyijqmy 1 300 train
+uvuzjfjytj 1 300 train
+uvvgckwppy 1 301 train
+uvvjswjozo 1 300 train
+uvvkfjicgr 1 300 train
+uvvnlsgoiu 0 300 train
+uvvqwcvguv 1 300 train
+uvvwfyvyzy 1 300 train
+uvvwjtmbzt 1 300 train
+uvvwsvgsax 1 300 train
+uvvzgtmqcm 1 300 train
+uvwhhohdvp 1 300 val
+uvwqakhkxi 1 301 train
+uvwxsczsrk 1 236 train
+uvxbqscnab 0 300 val
+uvxgvjaydu 1 300 train
+uvxgxixgmy 1 301 train
+uvxicudfgh 0 300 train
+uvxqxreoxr 1 300 train
+uvyjhjlwtu 1 300 train
+uvykwkdbbe 1 301 train
+uvynkucayw 1 301 train
+uvyrabzenf 1 241 train
+uvyvbfhchf 1 300 train
+uvyvfvkatq 1 300 train
+uvyvpcgghn 1 301 val
+uvyxhwohay 0 300 train
+uvyygycohf 1 300 train
+uvzbzorhxm 1 237 train
+uvzktioygx 0 300 train
+uvzlfuxalu 0 300 val
+uvzoyxihnt 1 300 train
+uvzxliznqp 1 300 train
+uwaazdihiw 1 300 train
+uwabthymod 1 143 train
+uwaddunbkj 1 300 train
+uwaebatuei 1 302 val
+uwagdhnadr 0 143 train
+uwazhvyyzh 0 300 train
+uwazrtsbpk 1 300 train
+uwbalexjwp 1 300 train
+uwbckessmf 1 301 val
+uwbehzysnc 1 300 train
+uwbhcogubo 0 300 train
+uwbhmaqhrb 1 301 val
+uwbhsqzknz 1 301 train
+uwbjjzighs 1 300 train
+uwbpcdtmlb 0 300 train
+uwcazfyqqw 1 300 train
+uwccodyhgh 1 300 train
+uwcheneckw 1 300 train
+uwcseyxmng 1 298 train
+uwctsjhxyh 1 300 train
+uwctwtdsiq 1 300 train
+uwdbazipjk 1 299 train
+uwdesyepqx 1 300 val
+uwdgnsvqke 1 300 train
+uwdkrptpuk 1 300 train
+uwdlrnzitd 1 300 val
+uwdmyewvtz 1 300 train
+uwdoybmqes 1 300 test
+uwdybwrszg 1 600 train
+uwecmaysay 1 300 train
+uwedeuqopj 1 300 train
+uwedjfvlgv 1 300 train
+uweqfetuwc 1 300 train
+uweqkojgcd 1 300 train
+uweunfixll 1 298 train
+uwezcnmwhs 1 300 train
+uwfkyglras 1 302 train
+uwfqiblqtz 1 301 val
+uwfryvyjko 1 300 val
+uwfwsprjoo 1 241 train
+uwfyzjdrif 1 301 train
+uwfzqjknes 1 300 train
+uwgabzlkfx 1 300 train
+uwgayiejac 1 300 train
+uwgbfkztlz 0 300 train
+uwgcitwggp 0 241 train
+uwghsfmeik 1 300 val
+uwgjjehvpt 1 300 train
+uwgjxfsvco 1 300 val
+uwgnkpisiz 1 298 train
+uwgokcxcjz 1 288 train
+uwgsemwkxn 1 301 train
+uwgseyhcfk 1 300 val
+uwgwrjeskv 1 300 train
+uwhchfinak 1 300 train
+uwhdqtpvfw 1 300 train
+uwhiklpzwq 1 300 val
+uwhpbvytpu 1 300 train
+uwhuhyleff 1 300 train
+uwiexiqats 1 300 train
+uwifmjbrkf 1 300 train
+uwigpiavvn 0 300 train
+uwivqrgaqb 1 241 train
+uwiwgklufd 1 300 train
+uwjbwegyfx 0 300 val
+uwjldovxhd 1 300 train
+uwjnsouqrr 1 300 val
+uwjrjiycxw 1 241 train
+uwjvhlqeob 1 300 val
+uwkazachvs 0 300 train
+uwkbtdezji 1 300 train
+uwkfgynugo 0 300 train
+uwkgtxowos 1 300 train
+uwkudvgwqy 1 300 train
+uwkzdulgps 1 300 train
+uwlejlnfjy 1 300 train
+uwlmntfcms 1 300 train
+uwlnxywktv 1 300 train
+uwloqhsial 1 300 train
+uwlroynzaq 1 301 train
+uwlvvqlhgp 1 301 val
+uwlyjzyxzy 1 300 train
+uwlzegtnya 0 300 train
+uwmejkcemy 0 300 train
+uwmgsskeay 1 300 train
+uwmttcglvn 1 300 train
+uwmtxgrdhd 1 300 train
+uwmwswfbgx 1 300 train
+uwneubrpkx 0 300 val
+uwngsmmtts 1 300 train
+uwnhmmohoh 1 288 train
+uwnmnneryj 1 300 train
+uwnogtuazk 0 300 val
+uwnrfieuaq 1 300 train
+uwnwipuzvk 1 300 train
+uwnxfmvpde 1 300 train
+uwnyfxsnam 1 300 train
+uwnymzkgxe 1 300 val
+uwnzdnhohf 1 300 train
+uwoioyihog 1 298 train
+uwokjfkknh 1 300 train
+uwomnscyfb 1 300 train
+uwongbnqos 1 300 train
+uwotmeffrh 1 300 train
+uwoxusohwy 0 300 train
+uwoycallmh 1 300 val
+uwpemamgpx 1 300 train
+uwpuaikywj 1 300 train
+uwpvviiste 1 300 train
+uwqdbmgrlh 1 300 train
+uwrhqmymsq 1 300 train
+uwriopccgu 1 300 val
+uwrjhozxyi 1 300 train
+uwrjugxfeu 1 300 test
+uwrteaxxtt 1 300 train
+uwsfvxrfar 1 301 val
+uwsmwnxqyf 1 298 train
+uwsqssxxtw 1 298 train
+uwssufxvii 1 300 train
+uwsxymmirf 1 300 train
+uwtbceprig 1 300 val
+uwtbsguzbt 1 301 train
+uwtvwxdlyy 1 300 train
+uwudqqxall 1 300 train
+uwudsyomnt 1 300 val
+uwudxxvovh 1 300 train
+uwufxaczqi 0 300 train
+uwunzwyimj 1 300 train
+uwuytbmjgz 1 300 val
+uwvkdiymbf 1 300 train
+uwvleiongl 1 240 val
+uwvlwwkbow 1 300 train
+uwvrhwdbrp 1 300 train
+uwwfiiqssb 1 300 train
+uwwnakcrdk 1 300 train
+uwwqocrypp 1 300 train
+uwwuzyshur 1 300 train
+uwxdraosyo 1 300 train
+uwxhiebnci 1 300 train
+uwxhkcxmqm 1 300 val
+uwxiebylnv 1 300 train
+uwxnaseruv 1 241 train
+uwxsfliwai 1 301 train
+uwxvvywkfo 1 300 train
+uwxyrcwgue 1 301 val
+uwyastvevc 1 300 train
+uwyilxpckd 1 300 train
+uwyschhcnn 1 300 val
+uwyshkvtgr 0 300 val
+uwytinporr 0 300 train
+uwyvkyujhg 1 300 train
+uwyyfstznc 1 300 train
+uwyzbbbxqz 1 300 train
+uwyzedekiv 1 300 train
+uwzexrflnv 1 300 val
+uwzhrbbkuz 1 300 train
+uwzijlswnb 1 300 train
+uwzlafwdra 1 300 test
+uwznchbfkq 1 300 train
+uwztugirjr 1 300 train
+uwzuaveowu 0 300 val
+uxaavcfujo 1 301 train
+uxagoucxhc 1 301 train
+uxaisqejol 1 300 train
+uxakdcbhzp 1 300 train
+uxalgdwabq 1 300 train
+uxaufyecfa 1 300 train
+uxauuygolf 1 300 train
+uxbbzrhoaj 0 300 val
+uxbeupxqqr 0 300 train
+uxbevjrqiu 1 300 train
+uxbjqnphle 1 300 train
+uxbmpeeqak 1 300 val
+uxbpiqxdij 1 300 train
+uxbwhgenbh 1 301 val
+uxcgopzrod 0 300 train
+uxchsxvvme 1 300 test
+uxciuwhgvk 1 240 val
+uxcqcztgyd 1 299 val
+uxddcumowl 1 300 train
+uxdgkmicjo 1 298 val
+uxdilljouv 1 300 train
+uxdmrwdyhz 1 300 train
+uxdpyolauo 1 300 val
+uxduqdrsge 1 300 val
+uxdvzuwlsg 1 300 train
+uxdwkdtmyo 1 298 train
+uxdxfnvvvq 1 300 train
+uxebiobocr 0 300 val
+uxeghvdkci 1 299 val
+uxehqfsezq 0 301 train
+uxephphvbz 1 241 train
+uxffnlkpui 1 300 val
+uxfrxtjhwp 1 300 train
+uxftflxbtn 1 300 train
+uxfumnmxkl 1 300 val
+uxghkmxdyd 1 300 train
+uxgiiltywt 1 300 train
+uxgkqpiykp 0 301 train
+uxgrowpizt 1 300 train
+uxgwnnoolh 0 300 train
+uxhjkyfkpe 0 300 train
+uxhldogxrr 1 300 train
+uxhmlgjcji 1 300 train
+uxhmnhoege 0 300 train
+uxhqwlmtaa 1 301 train
+uxhwdfbfmu 1 300 train
+uxickxjkfm 1 300 val
+uxicyysovl 1 300 train
+uxifqsovve 0 300 train
+uxigesmnmc 1 300 train
+uxinzynpnn 1 300 train
+uxiopicest 0 300 val
+uxiwmpsbxe 1 300 train
+uxixrgrcit 1 300 train
+uxjccyabfc 1 300 train
+uxjdqivotq 1 300 val
+uxjgndmpzk 1 300 val
+uxjqrgtbck 0 300 val
+uxjrgfjgtx 1 300 train
+uxjuyqjxbg 1 300 train
+uxkojffbsr 1 300 train
+uxkpdqghjw 1 300 train
+uxkrscrlgw 1 300 train
+uxkupaupvl 1 301 train
+uxkxebqquf 1 300 val
+uxlhbytqjp 1 300 train
+uxlknkfash 1 249 train
+uxlqsobqix 1 300 train
+uxlrcicjge 1 300 train
+uxlsxewlrd 0 300 train
+uxlttjokvq 1 300 train
+uxlwuuaqnc 1 300 train
+uxlzsdgwzt 0 300 train
+uxmjvpcggx 1 300 train
+uxmkaxaeyr 1 300 train
+uxmlxwtsuw 0 300 train
+uxmphmduay 1 300 train
+uxmthmjwwk 1 300 val
+uxmtpfohri 1 300 train
+uxmtuwptvu 1 300 train
+uxmtvkcafb 1 146 train
+uxmxkdvjje 1 300 val
+uxnaaimitn 1 300 val
+uxnbrlfpuz 1 301 val
+uxncexcmuz 1 300 train
+uxnhxyippv 1 294 train
+uxnocdxnqc 1 300 train
+uxnxhvsyoi 1 300 train
+uxoaicbwyn 1 301 train
+uxobzampss 1 300 train
+uxodfhnerf 1 300 train
+uxojdmarwk 1 300 train
+uxojgudkci 1 298 train
+uxojvdlrje 1 300 test
+uxollclqvb 1 300 train
+uxoqfgydnl 1 300 val
+uxorfqhvgh 1 300 val
+uxouojxhlk 1 300 train
+uxovttinwg 1 300 train
+uxpauykbsg 1 300 val
+uxpimdnggv 1 300 train
+uxpmzezmub 1 300 train
+uxpolafvbt 1 300 train
+uxpydukepe 1 300 train
+uxqbeipiec 1 300 train
+uxqdtwootv 1 300 val
+uxqenejhbf 1 300 train
+uxqwoblsor 1 300 train
+uxqzpuvwjq 0 300 val
+uxraycluin 0 300 train
+uxrfloqltk 1 300 train
+uxrjifrkkk 1 300 train
+uxrydthmou 1 300 train
+uxsitfutdu 1 240 val
+uxsjbeatki 0 300 val
+uxskcsnjzv 1 300 train
+uxsndxcols 1 301 train
+uxsogpkqcx 1 300 train
+uxsornonck 0 300 train
+uxssisvfez 1 299 test
+uxsvlskimn 1 300 train
+uxsxbgombk 1 300 train
+uxsypoielb 1 300 val
+uxtaphyiwy 1 298 train
+uxthpvfaix 1 298 train
+uxtjqiikfd 1 300 train
+uxtnooctnv 0 300 train
+uxtruqwtdz 1 300 train
+uxttbwkmbo 1 300 train
+uxtwqvljir 1 300 train
+uxtxjtveey 1 300 train
+uxtydubdhm 1 300 train
+uxtzadhtyh 1 298 train
+uxubstyxzt 1 300 val
+uxucjnlnby 1 300 train
+uxuetrjkvw 1 300 train
+uxunebmxvx 0 300 train
+uxupidfqkm 1 300 train
+uxurjsxund 1 300 train
+uxuroduqmh 1 300 train
+uxuvkrjhws 0 300 test
+uxvarukjxl 1 300 train
+uxvbykfxnc 1 300 train
+uxvfyphcoq 1 300 train
+uxvgfgwide 0 300 train
+uxvocmsqwu 1 300 train
+uxvuxoabmi 1 300 train
+uxwsxkmmao 1 300 train
+uxwuanbgkb 1 300 train
+uxwzngvsyz 1 300 train
+uxwzubexti 0 300 train
+uxxboorxbe 1 300 train
+uxxippwrve 1 300 train
+uxxjdaxdgs 1 300 train
+uxxlmmugzt 1 300 train
+uxxmmyruzq 1 300 train
+uxxmuyixpf 1 300 train
+uxxrwrurut 1 299 test
+uxyahhivjk 1 300 train
+uxynygwdiu 1 299 test
+uxyqlpvpwk 1 300 train
+uxyxafbofn 1 301 train
+uxzehoezps 1 241 train
+uxzguadsee 1 300 train
+uxzkgvidhz 1 300 train
+uxzkxacftd 1 241 val
+uxzltouzmc 1 298 train
+uxzmahqptw 1 301 val
+uxzrqtuuqa 1 300 train
+uxzsoijepr 1 296 val
+uxzxaahtob 1 300 train
+uxzxbkxegt 1 300 train
+uxzxnkqqna 1 300 train
+uyaocjjsib 0 300 train
+uyaoyhigkg 1 300 val
+uyaqvalgow 1 300 train
+uyauzwkvpz 0 300 val
+uyaxlsnssn 1 300 train
+uybatywocp 0 300 train
+uybcftswwy 1 300 val
+uybcxiahmn 1 301 val
+uybglzasrd 1 300 train
+uybsejchpc 1 300 train
+uybtwxcirb 1 300 train
+uybxkaopwn 1 298 train
+uybyowehar 1 300 val
+uyccyxegnj 1 300 train
+uycnthxgws 0 300 val
+uycqpeidlg 1 300 train
+uycskzxyzw 1 300 train
+uyddeofvvz 0 300 val
+uydduzfxvj 0 300 train
+uydfaqxwhw 1 300 train
+uydlsvuore 0 300 train
+uydniprivd 1 300 train
+uydpxezmwi 1 297 train
+uydssdlohm 1 300 val
+uydtaldvla 1 300 train
+uydzkjefzg 1 300 train
+uyefddtyth 1 300 train
+uyefluroxw 1 300 train
+uyeiheygxk 0 300 train
+uyelnylonp 1 300 train
+uyelypputx 1 300 train
+uyemjrkiub 0 300 train
+uyeolluenx 1 300 train
+uyesaflvkt 1 300 train
+uyeuaymgdf 0 300 train
+uyextxwokc 1 300 train
+uyfdgspinp 1 298 val
+uyfdoedjoj 0 300 train
+uyfenrgwtl 1 300 train
+uyfjnvvofs 1 300 train
+uyfmgzlonc 1 300 val
+uyfmzymkmc 1 300 val
+uyfnfvsxez 0 300 train
+uyfnlwzhkj 1 300 train
+uyfornonln 1 300 train
+uyfowwaqck 1 301 train
+uyfqyelbgz 1 300 train
+uyfrarhvjm 1 299 test
+uyfsoiaych 1 300 train
+uyftiwbolt 1 300 val
+uyfvdpqkkw 1 300 train
+uyfwsphnjb 1 300 train
+uyfwyhaqrl 1 300 train
+uygevltaqg 1 300 train
+uyghebrnju 0 300 train
+uygqocflrp 1 300 train
+uyhaeqbldf 1 83 train
+uyhbbzgrkq 0 300 train
+uyhgmreglt 1 300 train
+uyhkttlaiz 1 300 train
+uyhkwtjbwb 1 300 train
+uyhmogukwo 1 300 train
+uyhofqespp 1 301 train
+uyhqrokmfe 1 300 val
+uyhruevqqg 0 300 train
+uyhsejordi 1 299 train
+uyhugpkvub 1 300 val
+uyhwlicggj 1 300 train
+uyhxbrcezh 1 300 train
+uyhyskrotc 1 300 train
+uyicbgrtkh 1 301 train
+uyicbkmyef 1 300 train
+uyiedzttyr 1 300 train
+uyiemlorwo 1 300 val
+uyifiaydqj 1 300 val
+uyimssgwwb 1 300 train
+uyirrtqxym 1 241 train
+uyiscrrdpe 1 303 train
+uyisdbjrao 1 300 train
+uyiskfomnb 1 300 train
+uyivturgwr 1 300 train
+uyiwyulzej 1 255 train
+uyiyxrnyee 1 300 train
+uyizpqbaxn 1 300 train
+uyjbrbdeoq 1 300 train
+uyjcuvowxm 1 300 train
+uyjfsnpryr 1 300 train
+uyjizmtxsr 1 300 train
+uykbxjtgqo 1 296 train
+uykggjjozu 1 300 train
+uykgxddhno 1 300 train
+uyktazpjkr 1 300 train
+uykypucxbn 1 300 train
+uylajhuozd 1 300 train
+uylcifbyvw 1 300 train
+uylcrqkqou 1 300 train
+uylkasnsdz 1 300 val
+uylmoywwhg 0 300 train
+uyludcgqqs 1 300 train
+uylukcctgv 1 299 val
+uylwfddgyr 1 300 train
+uylyikoexu 1 300 val
+uylzoijflt 0 300 train
+uymeandgmh 1 300 train
+uymfycalah 1 300 val
+uymiuxummv 1 300 val
+uymmcdurdl 1 300 train
+uymriggagi 1 300 train
+uymtkmlfma 1 300 val
+uymtmgkblj 1 300 train
+uymxzufmmq 1 300 val
+uynadilphv 1 300 train
+uyndmiqdei 0 300 val
+uynecsddew 1 300 train
+uynhhjdjlk 1 300 train
+uynqrxrltx 1 300 train
+uynsghtaqe 1 301 train
+uyntcoigrn 1 300 train
+uynwbwljil 1 300 train
+uynzprsvko 1 300 train
+uyoghxdsym 0 300 train
+uyogufqlec 0 300 train
+uyopjtrmul 0 300 train
+uyoqozgdcy 1 300 train
+uyosepupcy 1 302 train
+uyoznxqkbk 1 300 train
+uypatuhzra 1 300 val
+uypcizndsr 1 300 train
+uypcutfokd 1 300 train
+uyphplhfmc 1 300 train
+uyplcsfgjg 1 300 train
+uypopceldq 1 300 val
+uypxdrrajh 1 300 train
+uyqadnxxfv 0 300 val
+uyqdtftimc 1 301 train
+uyqmmdesty 1 300 val
+uyqndfcesf 1 300 val
+uyqnthceru 1 301 val
+uyqreongcd 1 300 val
+uyqztjxtte 0 300 train
+uyrfbdbgsl 0 301 train
+uyrhbkmzat 0 300 train
+uyrllyfhez 0 300 train
+uyrmllxmpe 0 300 val
+uyrphokgcd 0 300 train
+uyrvxhvljs 0 300 train
+uyrwtobgwm 1 300 val
+uysbekdxsr 0 300 train
+uysfgwieod 1 300 train
+uysrvriege 0 300 train
+uyszohikoe 1 300 train
+uytabnlzvw 1 300 train
+uytkdgwrqw 1 300 train
+uytlxiwnqz 1 300 train
+uytozanytf 1 300 train
+uytvjdcicy 1 300 train
+uytvvddlmq 1 300 val
+uytwcloisr 1 299 train
+uytwclomcl 1 300 train
+uyuftqkzff 1 300 train
+uyuhvubudu 1 300 train
+uyuihadkxo 1 300 val
+uyuimimand 1 300 val
+uyujqzncws 1 300 train
+uyumolhfdh 1 300 train
+uyvdqzzwlt 1 300 train
+uyvillbprb 1 300 train
+uyvjgfsiqd 1 300 train
+uyvlmbnuhs 1 300 train
+uyvqrhygfg 1 300 train
+uyvwldmuym 1 300 train
+uyvzsejsbq 1 299 test
+uywaaxlaca 1 296 val
+uywaxmjjzq 1 300 train
+uywczsqzcs 1 300 val
+uywdjgfgqr 1 300 train
+uywjkfvrwn 1 301 train
+uywmnyrwff 1 300 train
+uywnytuagf 0 300 train
+uywpmngmhz 1 300 val
+uywpnxqqne 1 300 train
+uywsdvlwos 1 301 train
+uyxbonjytu 1 300 train
+uyxcjhrvko 1 300 train
+uyxdlmcaon 1 301 val
+uyxhvcnczz 1 300 train
+uyxmpjkmgz 1 300 train
+uyxszqnrtv 1 300 train
+uyxtplxoha 1 300 val
+uyxutdwcep 1 300 test
+uyxyfbcdxd 0 300 train
+uyybbgjpcc 1 302 train
+uyycjrvorw 1 300 val
+uyycnpjvqj 0 300 train
+uyyvrjeufe 1 300 train
+uyyxcqflpc 0 300 train
+uyyzwpcxpf 1 300 train
+uyzaejuzyn 1 300 train
+uyzbcptmea 1 300 train
+uyzfnhqppa 0 300 train
+uyzfxraarq 1 300 train
+uyzggeepxn 0 300 train
+uyziijrawo 1 300 train
+uyzkpebdni 1 300 train
+uyzkptjqas 1 300 val
+uyzofgzrvw 0 300 train
+uyzvpvxclu 0 300 train
+uyzwtvrpxk 1 300 val
+uyzwvjizwq 1 300 test
+uzabmrkzvk 1 300 train
+uzacaxnoda 1 300 train
+uzakyofajs 1 300 train
+uzalxpoqhu 1 300 train
+uzavlulzzk 1 300 train
+uzavvzuism 1 300 val
+uzawooqxrq 1 300 train
+uzbbfxbkud 1 298 train
+uzbcydhiqb 1 299 train
+uzbeqpcpla 1 301 train
+uzbjgegtje 0 300 val
+uzbllfrzob 1 300 val
+uzbmjbskdd 1 300 train
+uzceumzqrk 1 301 val
+uzcezdepho 1 300 test
+uzcfalpfss 0 300 train
+uzcfbthcin 1 300 train
+uzcjqwawex 0 300 train
+uzcnpkyrjh 1 300 train
+uzcoipkltv 1 300 train
+uzcpzcdwfv 1 300 test
+uzcrkotvrk 1 300 train
+uzczzvvjal 1 300 val
+uzddlnfdzh 1 300 train
+uzdgolggka 1 300 val
+uzdjnpbrvf 1 301 train
+uzdmlxunsd 0 300 train
+uzdmxmfcqe 1 300 val
+uzdqvqogdw 1 300 train
+uzdzrjkjsd 1 300 train
+uzedywuhhq 1 300 train
+uzeidqykos 1 300 train
+uzejpnkuap 1 300 train
+uzeoobytsp 1 299 val
+uzfcvoouwv 0 300 train
+uzfhsugpal 1 300 train
+uzfizackaz 1 300 train
+uzfxlwmdqi 0 300 train
+uzgceznapm 1 298 val
+uzgkzxruoe 1 300 val
+uzgrffkifk 1 300 train
+uzgyehotay 0 300 train
+uzhadpdyti 0 300 train
+uzhbwfpoqz 0 300 train
+uzhegvyddw 1 300 train
+uzhgryrhdc 1 300 train
+uzhhdivrsq 1 300 train
+uzhjkdujit 1 300 val
+uzhkxyirva 1 300 train
+uzhthurfzm 1 300 train
+uzhujugirn 1 300 test
+uzhzlutzfu 1 300 train
+uzifolyjvu 1 300 train
+uzigniqqkj 1 241 train
+uziohtecjc 1 300 train
+uziqxnmrvm 1 300 train
+uzirqfsjnm 0 300 train
+uziruaneur 1 300 train
+uzishruvmm 1 300 train
+uzjutihkia 1 300 train
+uzjzliaail 1 300 val
+uzkbktgrom 1 300 test
+uzkchkrwuh 1 300 train
+uzketnbfvk 0 300 train
+uzkpplcmxg 1 300 train
+uzkqngecer 1 300 val
+uzkqwteyce 1 301 val
+uzkrgmuqti 1 300 train
+uzkzdvavdx 1 300 train
+uzlatnjxop 1 300 train
+uzlehukzwk 0 300 val
+uzlhbmrwld 1 300 train
+uzlkfyluxj 0 300 train
+uzlriqpgzs 1 300 train
+uzmcftvqox 1 301 train
+uzmdhiifdn 1 300 train
+uzmehmteau 1 300 train
+uzmklsweum 1 300 train
+uzmksevlro 1 300 train
+uzmqxbulvn 1 301 train
+uzmssdmeje 1 300 train
+uzmuovkewv 1 301 train
+uzngkhpsfy 1 300 train
+uzngntvcto 1 300 train
+uznhxlovsd 1 300 val
+uznlkerdwl 1 300 train
+uznoahixkw 1 300 train
+uznqmhpmel 1 300 train
+uznqukpeqp 1 300 train
+uzntskwlar 1 300 train
+uznvrkptpc 0 300 train
+uznzhtokgq 0 301 val
+uznzymwxbu 1 300 train
+uzodvhnaok 1 299 val
+uzogcdcdmf 1 300 train
+uzoixvnqjd 1 301 train
+uzojxptkte 1 300 train
+uzoodbatvz 1 301 train
+uzoqnyivuk 0 300 train
+uzouluzyft 1 300 train
+uzoxicwhmy 1 300 train
+uzpcgibejh 1 300 train
+uzpczuvrao 1 300 train
+uzperzaawk 1 300 train
+uzpfkobaiz 1 301 val
+uzpgpelflj 1 300 val
+uzpikmojmt 1 300 train
+uzpioarfch 0 300 train
+uzpistsraq 1 300 val
+uzpnbfhzmg 1 300 train
+uzpuojlifp 1 300 train
+uzpyaiqxwl 1 300 train
+uzpyorgdet 1 300 train
+uzqbjsggyc 1 300 train
+uzqbuleabg 1 300 train
+uzqdjsfrix 1 300 train
+uzqerpapft 0 300 val
+uzqinpslgj 1 300 train
+uzqmyjlyln 1 300 train
+uzqqlhtnxv 1 298 train
+uzqqyfmjbh 1 300 val
+uzqvxvtvka 1 300 train
+uzqwcknfrc 1 83 train
+uzrauzmgas 1 300 train
+uzrbokfzmp 1 300 test
+uzrcpdnfmt 1 300 train
+uzrejiuxtl 1 300 train
+uzrizaspkf 1 300 train
+uzrkbzwdvi 0 301 train
+uzrnppkdtl 1 300 train
+uzrnrvxyiy 1 300 train
+uzrqoiceqe 1 300 train
+uzrrjqmzax 1 300 train
+uzrsmulqll 0 300 val
+uzsbhdyhgn 0 300 train
+uzsbkxeinl 1 302 train
+uzscrvuepx 1 300 train
+uzskiheefi 1 299 val
+uzsnqddqem 0 300 train
+uzstcuseii 1 300 train
+uztiycslpc 1 300 train
+uztopaickb 1 300 train
+uztrloeuqh 0 300 train
+uztttikeuj 0 300 val
+uztyuhpmrb 1 167 train
+uzuhtskajc 1 300 train
+uzulwctbpf 1 300 train
+uzurdcundg 1 299 val
+uzuscrzuoi 1 300 val
+uzusitvarg 0 300 train
+uzuszkqnch 1 299 test
+uzvemiaktx 1 300 train
+uzvjmjjqgz 1 300 train
+uzvydatkpd 1 241 train
+uzwhknkitr 1 300 train
+uzwilxhtss 1 300 train
+uzwmhgnvct 0 298 train
+uzwmnlbyll 0 300 val
+uzwoxtyzzh 1 300 train
+uzwpemcmfu 1 299 train
+uzwqoaijmo 1 300 train
+uzwsyltfsk 1 300 train
+uzxfdqtdyn 1 300 train
+uzxixpvmcg 1 300 train
+uzxnfuawsq 1 300 train
+uzxpnhvzqt 1 301 train
+uzxpsvyefk 1 299 val
+uzxuezozjx 0 300 train
+uzxurqcdis 0 300 train
+uzxwirslom 1 300 train
+uzybvjyhsk 1 300 train
+uzyfjvbstv 1 300 val
+uzypmjxnqb 1 297 train
+uzyxwskhxx 1 300 train
+uzzcrwkbin 1 300 val
+uzzctavevn 1 300 train
+uzzmzkonxn 1 300 val
+uzznztgfwd 1 298 train
+uzzqkwcwzd 1 300 val
+uzzqnmncxm 1 300 val
+uzzzfknrpd 1 299 test
+vaabxfnlek 1 300 train
+vaaklqubkr 0 300 train
+vaanjlkzfn 0 300 train
+vaaqnxwsbs 1 300 train
+vaatkdgylq 0 300 val
+vaaxmeltki 1 300 train
+vaaxzughpn 1 300 train
+vabhbfiifl 0 300 train
+vabnxszwug 0 300 train
+vabyxsnlcn 1 300 train
+vacaujsoam 1 300 val
+vacayinkey 0 300 val
+vacfdybetb 1 300 train
+vacgglejhw 1 300 train
+vacmivsdsr 1 300 val
+vacpjvuxfa 1 300 train
+vacpwhnksv 0 300 train
+vacvxfykpk 1 300 train
+vaczbzyhgi 1 301 train
+vadhvruhjs 1 300 train
+vadigvsijb 1 300 train
+vadksrlcod 0 300 train
+vadnlydzua 1 300 train
+vadrruqshj 1 300 val
+vadzdqwzez 0 300 train
+vaehsyjmfa 1 300 train
+vaerthjpwc 1 300 train
+vaewqxabkj 1 300 train
+vafcspnrcg 1 300 train
+vafktcgapr 1 301 val
+vafkxhbpml 1 300 train
+vafmillywd 1 300 train
+vafnuuxovp 1 300 val
+vafnyfogcz 1 300 train
+vafqiijgxh 1 301 val
+vaghiaapwi 1 299 val
+vaghpqphva 1 301 train
+vagnoygtux 1 300 val
+vagofhbsmd 0 300 val
+vagzowjsxb 1 300 train
+vahicbizml 0 300 val
+vahqmewacr 1 300 train
+vahuzuhzsy 1 300 val
+vahvielxsu 1 300 train
+vahzfyqpmi 1 300 train
+vaibbkpvps 1 300 train
+vaicfyqaje 0 300 train
+vaidclapew 1 300 train
+vaidoqeblk 1 300 train
+vaiedvrqrr 1 300 val
+vaieshykhk 1 300 train
+vaifrxxydl 1 300 train
+vaikesmhcv 0 300 train
+vaikntoixi 1 300 train
+vaimtkgxia 1 300 train
+vaipxojhhe 1 301 train
+vairkxksha 1 301 val
+vairuzvydz 0 301 val
+vaivelipfj 0 300 train
+vaiyfqbuiz 0 300 train
+vajhspvilv 0 297 val
+vajkicalux 0 300 test
+vajouqpugm 1 300 train
+vajqsggcfk 1 300 train
+vajuyjivag 1 300 train
+vajxjvanpn 1 300 train
+vakcnljnpc 0 300 val
+vaketglffj 1 300 train
+vakfmzvikh 1 302 train
+vaklfmlarv 1 300 train
+vakozbstwr 1 300 train
+vakqjgammj 1 300 val
+vakyowiikg 1 300 train
+valczjlvii 1 300 train
+valgtwitdo 1 300 train
+valhijoqtd 1 300 train
+valoivtdaw 1 300 train
+valphjeyoj 1 300 train
+valwvmgbrc 1 300 train
+valytdbssj 1 300 train
+valzjgnbcj 1 301 train
+vamckfoaxg 1 300 train
+vamfoovwrv 1 300 train
+vamickgkfv 1 300 val
+vamicuaopj 1 300 test
+vamkopxvtj 1 301 train
+vamljacdhn 1 300 train
+vamnclfdhf 1 302 train
+vamsokbgtw 1 301 train
+vamxkrwasc 1 300 train
+vamxofolwd 0 300 train
+vanndppkap 1 301 train
+vanqxnvpds 1 300 val
+vanrrdlsts 1 300 train
+vansmfbqdl 1 300 train
+vaoahwryzb 1 300 train
+vaobozpotd 1 300 train
+vaodijuuyp 1 269 train
+vaofvulukv 1 300 train
+vaoikijchv 1 301 val
+vaorrrqbux 1 300 train
+vaozzirfnj 1 300 test
+vapcruhvis 1 300 train
+vapjeoaisp 1 300 train
+vapnnvovwq 1 300 train
+vapuddgzcr 1 300 train
+vapuelkdug 1 300 train
+vapxptvubq 1 300 val
+vapznfzfle 1 300 test
+vaqbfawpnf 1 300 train
+vaqpwfkbev 1 300 train
+vaqrevufsk 1 300 train
+vaquxsivgy 0 300 train
+varfagexso 0 300 train
+varfxelcfa 0 300 train
+varksutsvk 1 300 train
+varlwogcck 1 298 train
+varnjkrohb 1 300 train
+varoylcnht 1 300 train
+vartdbvmir 1 300 val
+varyqeuood 0 300 train
+vasbhjrmqz 1 302 train
+vasbxjbiyl 0 300 train
+vasffzldui 0 300 val
+vasjqunygd 1 300 val
+vasrrhdcdk 1 296 train
+vastdazvjc 0 300 train
+vatcsgbkbr 1 301 val
+vatfjjlghs 1 300 train
+vatfwwirro 1 300 train
+vatkjfgwov 1 300 val
+vatmotxgvh 1 300 train
+vatnapxxqy 1 300 val
+vatyrhynal 0 300 train
+vatyutluaw 1 300 train
+vaucfgptaj 1 300 train
+vaudlvhyby 1 300 train
+vauhwngubd 0 300 val
+vauiwkokjy 1 300 val
+vaukfhcafc 1 300 train
+vauwkkjikv 0 300 train
+vauwynfqoz 1 300 test
+vavdqqfrgi 1 301 train
+vavfrftuen 1 300 val
+vavicqdceb 1 301 val
+vavmtgexqo 0 300 train
+vavphgfaan 0 300 train
+vavpoksnsi 1 300 train
+vawcnpriqa 1 300 train
+vawecrrlvf 1 300 train
+vawlbsbqxj 1 300 train
+vawlovkkur 1 298 train
+vawotznxqn 1 300 train
+vawpwqeiiw 1 300 train
+vawzzxehog 1 300 train
+vaxbalgofa 1 301 val
+vaxgnbjpyj 1 300 train
+vaxlswfddx 1 297 val
+vaxnuedexe 1 300 train
+vaxrdfpecx 0 300 val
+vaxswdxebr 1 300 train
+vaxthppsce 1 300 train
+vaxwvytrxy 1 300 train
+vaxxedxjlz 1 300 train
+vaxzhhyiyg 1 300 train
+vaybapwjtm 1 300 train
+vaydtpnudn 1 300 train
+vayjqolrns 1 297 train
+vaysrqhdzb 1 136 train
+vayzwmwmdd 1 300 val
+vaznbwwqcr 1 300 train
+vazoblhsmf 1 300 train
+vazpntchpa 1 301 val
+vazqohualj 1 300 train
+vaztgfhkid 1 300 train
+vazvwfbygy 1 298 val
+vbaanvfqbn 1 300 train
+vbacamczvk 1 300 train
+vbaexdmrtb 1 300 val
+vbajpmxfrw 0 167 train
+vbantlggwb 1 300 train
+vbaqxhhnxb 1 300 train
+vbatwpbewy 1 300 train
+vbbahllztg 1 302 train
+vbbhmmqudq 1 300 train
+vbbjhlmtsq 1 299 train
+vbblpofexr 1 300 train
+vbbuxmblnp 0 300 val
+vbbwarchsv 0 300 train
+vbbxmmnlry 1 300 train
+vbbxwmhcbc 1 300 train
+vbcaefsitt 1 300 train
+vbcbzilsts 1 299 train
+vbcgaigppw 1 301 train
+vbcgoyxsvn 1 300 test
+vbcjbecyos 1 300 test
+vbckyiygjj 1 241 train
+vbclrisrve 1 300 val
+vbcobttbuh 0 301 train
+vbcoklceez 1 300 train
+vbcpcaigmu 1 300 train
+vbcpiuegnf 1 300 val
+vbcqmyshxr 0 300 train
+vbcwkzcbcl 0 300 train
+vbczrzwkpp 1 300 val
+vbdcjvwbih 1 300 train
+vbddzrqlfg 1 300 train
+vbdeoxobdv 1 300 train
+vbdhzukhjs 1 300 train
+vbdirwrfnr 1 300 val
+vbdpbjjzol 0 300 train
+vbdvyqadtg 1 300 val
+vbdxegoddt 1 300 train
+vbdxszxpvs 1 300 train
+vbdzuwcfvh 1 300 train
+vbepzdvgku 0 300 val
+vberwozvmz 0 298 train
+vbfdobghyk 1 300 train
+vbffufuynb 1 300 val
+vbfhinnprl 1 300 train
+vbfixmtici 0 300 train
+vbfjacamax 1 300 train
+vbfjlcuswe 0 300 train
+vbfmqnvwaj 1 300 val
+vbfrubtwyr 1 300 train
+vbftxnxnib 1 300 val
+vbfxqmhmrs 0 300 train
+vbgaxczdap 0 300 train
+vbgdwifnuv 1 300 train
+vbgdxtjbpb 1 300 val
+vbgkguxrvy 1 300 train
+vbglsnijhh 1 300 train
+vbguoacpun 1 300 train
+vbhchzblzy 1 300 train
+vbhcoxxbmg 1 300 train
+vbhkjskcab 1 300 train
+vbhnpncyns 0 300 val
+vbhsyoigsu 1 300 test
+vbhwappahp 1 300 train
+vbhyzossqg 1 301 val
+vbigmimfjp 0 300 train
+vbikrjlxlb 1 292 val
+vbioetqfii 1 300 train
+vbioqjntgg 1 300 test
+vbisojlhpy 0 300 train
+vbisrwmpah 1 302 train
+vbisvunrwd 1 300 train
+vbiuzazmle 1 300 train
+vbjajngdsk 0 300 val
+vbjbzamjmm 1 300 train
+vbjgdeaxsr 1 300 val
+vbjnzqfwwc 1 300 val
+vbkqykgoiz 1 241 train
+vbkshpaqui 1 300 train
+vbkwjmwtcg 1 301 val
+vbkxlndyus 1 300 train
+vbkysdiexz 1 300 train
+vbldlfyuij 1 300 train
+vblfzgmypv 1 299 test
+vblkpyrktq 1 300 val
+vblmiqnntb 1 300 train
+vblnxpxxqc 0 301 train
+vblplpqrlj 1 300 train
+vblwbkqurx 0 300 train
+vblwozxrwy 1 300 train
+vbmavfgmge 1 300 train
+vbmbparfsf 1 300 train
+vbmciijzwx 1 299 val
+vbmezehlps 1 300 train
+vbmfcxagzt 1 300 train
+vbmlexgwdg 1 300 train
+vbmlhiuiof 0 300 train
+vbmnyscpev 0 299 train
+vbmtvmhdlx 1 300 train
+vbmunhsxhr 1 300 train
+vbmvaucztq 1 300 train
+vbmwwdmhzu 0 300 train
+vbnimjsjia 1 298 train
+vbnmqkfhlu 0 300 val
+vbnsoqcsdc 0 300 train
+vbocreoktm 1 300 train
+vbodsguxxt 1 300 train
+vboizcpbgh 1 301 val
+vbolzlkcxa 1 300 val
+vbonzuulnn 1 298 train
+vbotmfoynq 1 300 train
+vbozllmhwl 1 300 val
+vbpdwvkvxs 0 300 train
+vbpmiadyuu 1 241 train
+vbpmwpmooy 1 300 train
+vbputtjekp 1 300 train
+vbpzfhhmlt 1 300 train
+vbqasscuva 1 300 train
+vbqkbnktwg 1 300 train
+vbqpkjauhb 1 300 train
+vbrekeqcbx 1 300 val
+vbrhabyypn 1 300 val
+vbrjnuoxmx 1 301 train
+vbrlgqadyl 1 300 val
+vbrplsozds 1 301 train
+vbrtimysvf 1 300 train
+vbrumhpafq 1 300 train
+vbrviucyqc 0 300 train
+vbrwjqueqz 1 300 train
+vbrwkczfox 1 300 train
+vbrzbcqrnw 1 300 val
+vbseqidsbq 1 300 val
+vbskbtjwxs 1 300 train
+vbskmjcpxh 1 298 train
+vbslxobktu 1 300 train
+vbsqhusjhp 1 300 train
+vbtbewyvxf 1 300 train
+vbtcaeomal 1 300 train
+vbtdoaemke 1 301 val
+vbtfipdgaz 1 301 val
+vbtirwqjug 1 300 val
+vbtjbgnlif 1 300 val
+vbtnqbjuux 1 300 train
+vbtoetnnyx 1 298 train
+vbtvivcsaw 1 300 train
+vbtxieghai 1 300 train
+vbujjjzgxs 1 300 train
+vbuklpogen 1 300 train
+vbuonvhhdj 0 300 train
+vbuqpaugzy 1 300 val
+vbvcmubccp 0 300 train
+vbvoqmpjkk 1 300 val
+vbvqmsxunj 0 300 train
+vbvqsrowzw 0 300 train
+vbvwodxqoq 1 301 val
+vbwgtabpcv 0 300 val
+vbwhyjhiiw 1 300 train
+vbwpcarauq 1 300 train
+vbwpzenvxg 1 300 train
+vbwscvshzq 1 300 train
+vbwtdnstsq 1 300 train
+vbwtnyqttl 0 300 train
+vbwwhcmfwx 1 300 train
+vbwzrduaun 1 300 test
+vbwztmgqgp 1 300 val
+vbxaqahzjw 1 300 val
+vbximegpug 1 300 train
+vbxmpyyybf 1 300 train
+vbxorsxlpg 1 300 val
+vbxrpiotsz 1 300 val
+vbxtjqksqc 1 301 train
+vbxtwsozyq 0 300 train
+vbxztkvyhi 1 300 train
+vbycfqgyxi 1 300 test
+vbyhlwimwy 1 300 train
+vbyjwspnie 0 300 train
+vbylthsdar 0 300 train
+vbymgzprqg 1 300 val
+vbyofneccr 1 300 train
+vbyrdcldyu 1 300 train
+vbyspsttir 1 300 train
+vbywxlwjka 0 300 train
+vbyzamqzkt 1 300 train
+vbzattfgpn 1 301 train
+vbzbfhzyku 1 300 train
+vbzdlbcxwf 0 300 train
+vbzxgqhbhn 1 300 val
+vbzzpkwnet 0 300 val
+vcaajjqosr 1 300 val
+vcaexkyjye 1 300 train
+vcallxwiuw 1 301 val
+vcatxbnsck 1 300 train
+vcawzvkoob 1 300 val
+vcbfvmjtbp 1 300 train
+vcbgvdnvlc 1 300 val
+vcbibflbmm 1 298 train
+vcblbuxbpk 1 300 train
+vcbocnyhuk 0 300 train
+vcboelljsh 1 300 train
+vcbtvrseaf 0 300 train
+vcbyffaxac 1 300 train
+vccgbreqta 0 302 train
+vccirdiyyb 1 300 val
+vccjsrmzlx 1 300 train
+vccjyvbfpt 1 241 train
+vccnncxydl 1 299 train
+vcdkmpoykh 1 300 train
+vcdqjbfacm 1 300 train
+vceahbarjg 1 300 train
+vcefwgfdug 1 300 train
+vceglrzmit 1 300 test
+vceiirqbwj 1 300 train
+vcenwynstv 1 300 train
+vceplrexke 1 288 train
+vcereugewk 1 300 train
+vcetxvlwho 1 301 val
+vceufoedzi 1 300 train
+vcfeloarsk 1 300 train
+vcffloguhj 1 300 test
+vcfmumdmpt 1 125 val
+vcfmwusghg 1 300 train
+vcfowchmxz 0 300 train
+vcfppymvnx 0 300 train
+vcfvkywcxe 1 300 train
+vcgcimeehe 1 300 train
+vcgclyiiif 1 300 val
+vcgelshrli 0 300 train
+vcghillvej 0 300 train
+vcgjazgwwa 1 241 train
+vcgupjrrmo 1 300 train
+vchabruuxz 1 300 train
+vchaormrma 1 300 train
+vchdlpsjjn 1 300 train
+vcheshtocq 1 300 val
+vchgbyqolg 0 300 train
+vchghnkojo 1 300 train
+vchlzzsbyp 0 300 train
+vchpmjyero 1 300 train
+vciaykiwmz 1 298 train
+vciegnusjr 0 236 train
+vciejrdkgf 0 300 train
+vcigjnvpeo 1 300 train
+vcioownnuq 1 300 train
+vcipesjwyd 1 300 train
+vcisozbeuw 1 300 train
+vcjfrtgfsg 1 300 train
+vcjhonlkys 1 300 train
+vcjhxpcdbh 1 298 train
+vcjzuiasai 1 300 train
+vckcwbvbsg 1 300 train
+vckdshpudq 1 300 train
+vckdweltri 0 300 train
+vcklvvpait 1 300 train
+vckrtidobg 1 300 train
+vckufwhogm 1 300 train
+vclhlksckw 1 300 val
+vclisimdvl 1 300 train
+vcmdjpepdv 1 300 train
+vcmfurwwhf 1 300 train
+vcmhigfrbk 1 300 train
+vcmscpjjer 1 300 train
+vcmxfrzaoq 1 300 train
+vcmxwpboxv 1 301 train
+vcnaslopsd 1 300 val
+vcnekqcsgm 1 300 train
+vcnhwihecj 1 300 train
+vcnlzqulvk 1 300 val
+vcnqejrxhr 1 300 train
+vcnrswbejs 1 300 train
+vcnvsosfio 0 300 train
+vcnwrcwqcs 1 300 train
+vcnwszucoi 1 300 val
+vcoctnystv 1 300 train
+vcogqoawqj 0 300 train
+vcohguvfpq 1 300 train
+vcoilwjhcp 1 300 test
+vcoxcsxkmq 0 300 train
+vcoxhbyfgw 1 300 train
+vcpblwgtat 1 300 train
+vcphckxbrw 1 300 train
+vcplefwtte 1 301 train
+vcplnhsufh 1 300 train
+vcprhykruh 1 300 val
+vcpxlmuhdo 1 299 train
+vcqcervdzi 1 300 train
+vcqdmzirff 0 300 train
+vcqgfemqgt 1 300 train
+vcqgihwpvz 1 300 train
+vcqxvyrfva 1 297 train
+vcqzdmidpt 1 300 val
+vcqzrpkqqt 0 240 val
+vcrdyfgjld 1 299 val
+vcrhnsvmfy 0 300 train
+vcrjcvfmuf 1 300 train
+vcrjobrfjw 1 300 val
+vcrmlccwlo 0 300 val
+vcroxnocty 1 300 train
+vcrpfwfyxw 1 300 train
+vcrsbaumvo 1 300 val
+vcsckxqgwo 1 300 val
+vcslnzbsbc 1 301 train
+vcsnxlcviz 1 300 train
+vcsnxzuwmz 0 300 train
+vctdihrfoz 1 300 train
+vctemjbusz 1 300 test
+vctoulnzwy 1 300 val
+vctrfddyjn 1 301 train
+vctsapivrr 1 300 train
+vctwucgixu 1 300 train
+vctzgnsqti 1 299 val
+vcumowlzxb 1 300 train
+vcupnuytpb 1 300 train
+vcurnjevdg 1 300 train
+vcuubrsigr 1 300 val
+vcuvyspfxh 1 300 train
+vcuwljflau 1 300 train
+vcuyjclura 1 300 train
+vcvmrllfis 1 299 train
+vcvnxynkfu 1 300 train
+vcvqfkaatg 1 300 val
+vcvrrmacdl 1 300 val
+vcvshhptft 1 300 train
+vcwhldwplh 1 300 train
+vcwhqingpg 0 300 train
+vcwilvbihi 1 300 val
+vcwjvigiyf 0 300 train
+vcwjvrfvge 1 300 train
+vcwwqfuoed 1 300 val
+vcwxdwngnq 0 300 train
+vcxbloxcms 1 300 train
+vcxckqbaya 0 300 train
+vcxejqfdim 0 300 train
+vcxjnsrgqh 1 300 train
+vcxpzapfhm 0 300 val
+vcydvlacqr 1 300 train
+vcygknydgs 1 300 train
+vcyiqndlpr 1 300 train
+vcyliojgtf 1 300 train
+vcypgpkhug 1 300 train
+vcyuowrmnd 1 298 train
+vcyybfgytl 0 299 val
+vczeeetzpy 1 300 val
+vczkillphl 1 300 train
+vczkkqlmaa 1 300 train
+vczmpcsqga 0 300 train
+vczqlbiqzt 1 300 train
+vdadegkktt 1 300 train
+vdaeabtran 1 300 train
+vdaehwlbdd 0 300 train
+vdaiwsswzr 1 300 val
+vdajzsoqat 1 300 train
+vdarshgprl 1 302 val
+vdavbnqpfp 1 300 val
+vdbepxvrql 1 300 train
+vdbgwbysyz 1 300 val
+vdbhxmlldx 1 300 train
+vdblyisner 1 302 val
+vdbmrmbyri 0 300 train
+vdbsmwvpli 1 300 train
+vdbvsvobgq 1 300 train
+vdbxgdtmrp 0 300 train
+vdbyjmzzji 1 300 train
+vdcefzukbf 1 301 train
+vdciygezjx 1 300 train
+vdcpqlevzt 1 300 val
+vdcrskaapz 1 300 train
+vdcxojkuvk 1 300 train
+vddanxmkiv 1 300 train
+vddddtoqhw 1 300 train
+vddivtygdd 1 300 train
+vddjnfumrx 1 300 train
+vddkwpxfhb 1 300 train
+vddmjkvitf 1 300 train
+vddmkkcejx 1 300 train
+vddzflpeat 0 301 train
+vddznyuhxi 1 300 train
+vdeaqdxdsm 1 300 train
+vdebdjqrri 1 298 train
+vdefzrnsmx 1 300 train
+vdejewavxa 1 301 train
+vderwgzgdx 1 300 train
+vderzuoimd 1 300 val
+vdevdspjrb 1 301 train
+vdevvrpqdk 0 300 train
+vdfgtzwhiq 1 300 train
+vdfkpfxrxd 1 300 train
+vdfqbzfdvk 1 99 train
+vdfriqcjub 1 300 train
+vdgaewfami 1 300 train
+vdgccykqnz 0 300 train
+vdgefdsrda 1 300 train
+vdgibxqylz 1 300 train
+vdgikilkzx 1 300 train
+vdgnalptbi 1 300 val
+vdhaiewyrl 1 300 train
+vdhmmcbfqi 1 300 val
+vdhmwmmdwc 1 300 train
+vdhpdjgzaz 1 300 train
+vdhrnrrnhd 1 300 train
+vdhsnyfbep 1 298 train
+vdhsqkojfw 1 301 train
+vdibvwhfgl 0 300 train
+vdifebtexk 1 299 train
+vdijntwqge 1 300 train
+vdikcppvyu 1 300 train
+vdimteojep 1 300 train
+vdinbayunq 1 300 train
+vdjjanykyc 1 300 train
+vdjjvfhngz 1 300 train
+vdjkiusseu 1 300 train
+vdjnxezbqn 0 300 train
+vdjqkyodsj 1 300 train
+vdjyomnhjf 0 300 val
+vdjyuvrfbf 1 300 train
+vdkacknwck 0 300 train
+vdkbgjzjah 1 300 train
+vdkdgnyqdl 1 300 train
+vdkdpgiccu 0 300 train
+vdkfjetpaa 0 300 train
+vdkyloetfp 1 300 train
+vdlaicgfze 1 300 train
+vdlchuptjz 0 300 train
+vdlkdbmmmb 1 300 train
+vdlloylhqt 1 300 val
+vdlprgyuer 1 300 train
+vdltwguhex 1 300 train
+vdmaeysfhq 0 300 val
+vdmbchexkc 0 300 val
+vdmhoecuay 1 300 train
+vdmkgepgku 1 300 train
+vdmlewddtf 1 300 val
+vdmlnjupqm 1 300 train
+vdmpnmnsmv 1 300 train
+vdmsfnbtse 1 300 train
+vdmtksgsth 1 300 train
+vdmvvywayz 1 300 train
+vdmxlfuqfi 1 300 train
+vdmyzrdarn 0 300 train
+vdnengvmew 1 300 train
+vdnfwpwpbx 1 301 train
+vdnhwhbxlj 1 298 val
+vdnitwfbvr 1 300 test
+vdniupszfp 1 300 train
+vdnmkdweiy 1 300 train
+vdnqsbyxmu 1 300 train
+vdnsbjfqkq 1 300 test
+vdntxzmxgk 1 300 train
+vdnzcrdwdg 1 300 train
+vdohwdkefq 1 241 train
+vdoolqsszc 1 297 train
+vdotcxvngl 1 300 val
+vdpaklekmk 1 300 train
+vdpftagzyt 1 300 train
+vdpftwbuzb 1 300 train
+vdpjbtmwtm 1 300 val
+vdpnyzxccm 1 300 train
+vdprdmbzez 1 300 train
+vdpwvtrykz 1 300 val
+vdpzavvuam 1 300 train
+vdqdwpcpwd 1 300 train
+vdqjzcsjxy 1 298 train
+vdqlcevfys 0 300 train
+vdqlwezaha 0 300 val
+vdqpbsymja 1 298 train
+vdqqjryleq 1 300 train
+vdqritvjfl 0 300 train
+vdqsuavbja 1 300 val
+vdradjcgrv 1 241 train
+vdrgkmyhax 1 300 train
+vdriwbzkqt 1 300 train
+vdrmxusitt 0 300 train
+vdropwdrtx 1 300 val
+vdrotdezmh 0 300 train
+vdruhipudk 1 296 val
+vdsilkxkgv 1 300 train
+vdsirrbcar 0 300 train
+vdsvkclzcl 1 300 train
+vdsyclnzdy 1 301 train
+vdszyrvtog 1 301 train
+vdtavvqruc 1 300 val
+vdtmlbzhwi 0 300 val
+vdtsbqidjb 1 299 test
+vdtuvgzrdt 1 300 train
+vdtvohankg 1 300 train
+vdtxmlxdpp 1 300 val
+vdupljnepp 1 300 val
+vduqphtrei 1 300 train
+vduscajecy 1 300 train
+vdusoqmoyq 1 300 train
+vduuwytkka 1 299 test
+vduxnxtgoc 0 300 train
+vduysxixmw 1 301 val
+vdvckawpsm 0 300 val
+vdvdyybgpr 1 301 train
+vdvffooule 0 300 train
+vdvgqeujbd 1 300 train
+vdviepstwv 1 300 train
+vdviynltwo 1 300 train
+vdvmegmkoh 1 300 train
+vdvqjblzkp 1 300 train
+vdvqyocatg 1 300 train
+vdvsbtcxmw 1 300 train
+vdvsekvhhg 0 300 train
+vdvstqzaeb 0 301 train
+vdweedtabg 1 301 train
+vdwgivzwmg 1 299 train
+vdwhghrocr 1 300 train
+vdwoazrodt 1 300 train
+vdwoptjlva 1 300 train
+vdwuccikks 1 300 train
+vdwwzvbrvx 1 300 train
+vdwxhqsypv 0 300 train
+vdwybveasu 1 300 train
+vdwyyyqanw 1 300 train
+vdwzarbfro 1 300 val
+vdxkjjvjba 1 300 train
+vdxnwswuan 1 300 train
+vdxrhsrtxi 1 300 train
+vdxsqkzlbl 0 300 train
+vdyaqeknrp 1 300 train
+vdycfwhcnw 1 300 train
+vdyfxzjhuj 1 300 train
+vdyhcesmes 1 300 train
+vdyihusaht 1 300 train
+vdytlipovj 1 300 train
+vdyzgpytqi 1 300 train
+vdzbypwcsp 1 300 train
+vdzdwdfpjv 0 300 train
+vdzlykljaf 1 300 test
+vdznouqxdj 1 300 train
+vdzvjazinb 1 300 train
+veadbrywlp 1 300 val
+veadqmoyki 1 300 train
+veajipktdz 1 301 val
+veaqlpwxfa 1 300 train
+vearizarkq 1 300 train
+veasqdjezk 0 300 train
+veasufbwru 1 300 train
+vebazvakbk 1 300 train
+vebdzodnfd 1 300 train
+vebezzibnl 0 300 train
+veblceeyfh 1 300 train
+vebmzzbjmw 0 300 train
+vebpwqhssp 1 300 train
+vebqnnskmx 1 300 train
+vecbhhersv 1 301 val
+vecbuhlbqk 1 300 train
+vecdesnjqd 1 300 test
+veceeydhdu 1 300 val
+vecewykzfw 1 300 train
+vecgvsbzqd 1 300 val
+vecncurxxs 1 300 train
+vecpsduyek 1 300 train
+vecsopqwlg 1 300 val
+vectnhewkd 1 300 train
+vectwerkdu 1 300 train
+vedfvbgmlw 1 300 train
+vedptrbvwf 1 300 val
+vedpwiuuff 1 300 train
+vedwlahahw 1 300 val
+vedxkubmtj 0 300 train
+vedxldsjsx 1 300 train
+vedycgwjnb 1 300 train
+veeaxpcaqv 1 300 train
+veebbmwxcy 1 300 train
+veecjbgkph 0 300 train
+veepybdxwi 1 298 train
+veeqdotkmn 0 300 train
+veerssdxux 1 300 train
+veeshygosz 1 300 train
+veeszxrvos 1 300 train
+vefoinrpez 0 300 train
+vefoirxtxg 0 300 train
+vefsefzior 0 302 val
+vefvrjmywy 1 298 train
+vefxfnthoc 1 241 train
+vefzvvdknj 0 300 train
+vegcrfiaiq 1 300 train
+vegcstposn 1 300 train
+veghrwyrei 1 300 train
+vegikoijyv 1 167 train
+vegkmvahjd 0 298 train
+vegucnsdfs 1 300 train
+vegxooikmg 1 300 train
+vehavdpudy 1 300 train
+vehfrbzqic 1 300 train
+vehowqzjma 0 300 val
+vehpszvabs 1 298 train
+vehqbmyjyp 1 300 train
+vehvnfriqh 0 300 train
+vehvtcsqtw 1 300 train
+veinkpxjra 1 300 train
+veiqxmojds 1 300 train
+veivhympzw 1 300 train
+veixrkjqvi 1 300 train
+veizjojmka 1 300 val
+veizpmvwsd 1 300 train
+vejadazcyr 1 300 train
+vejalpxadv 1 300 train
+vejsqfkluh 1 300 train
+vejylrlysf 1 300 test
+vekglqdkdn 1 299 val
+vekifszeqs 0 300 train
+vekmecwuii 1 296 train
+vekowwvpdl 1 300 train
+vektcdswxa 1 300 train
+vekuanlmlt 0 300 train
+vekujpugrw 1 241 train
+vekurevxav 1 300 train
+vekvxnlifq 1 300 train
+veljdnicrj 1 300 train
+velnmjuvsi 1 241 train
+velriuvkct 1 300 train
+velsbbrsxo 1 300 val
+vemhpgqbqs 1 298 train
+vemkifcxcn 1 300 train
+vemnbnqoqk 1 300 train
+vemrgsglez 1 300 train
+vemwitcote 1 300 val
+venacxpweh 1 300 train
+vencojpgda 1 300 train
+vengymopwy 1 300 train
+venkcnwdyi 1 294 train
+venldubpdi 1 300 val
+venlqferdg 1 300 train
+vennttcyah 1 301 val
+venocbjbce 1 300 train
+venohbcqbn 1 302 train
+venolarbbi 1 300 train
+venzzkodbd 1 300 train
+veobxhjydo 1 297 train
+veochyfnmr 1 300 train
+veoidmjctt 1 298 train
+veoitrrmpx 1 300 train
+veojzmqyzn 1 301 val
+veoljutdiu 1 300 train
+veonctwtvy 1 300 train
+veoqevbrix 1 300 train
+vepfbtcvru 0 300 train
+vepgtlihug 1 300 train
+vepqerlwrr 1 300 train
+vepsrhoemi 1 300 train
+veptkrjscn 1 300 val
+vepuhmimta 1 241 train
+vepulbnzfr 1 300 train
+vepwfvaowm 1 300 train
+vepwvsjryi 1 300 train
+veqhymmhib 1 299 train
+veqmbjkpdd 1 300 train
+veqmvtcipb 1 300 val
+veqrbadssl 1 298 val
+veqtpbhmne 0 300 val
+vequthjwqt 1 300 train
+veqxojkjch 0 302 train
+verbtavntb 1 300 val
+verjftplzg 1 300 train
+veromclviy 1 301 val
+verpifrngx 1 300 train
+verpxkucoi 0 300 train
+veruihwrka 1 300 train
+verwcejnbt 1 300 train
+vesammdzij 1 299 train
+vesgckwjdx 0 299 train
+vesmpvvlrf 1 301 train
+vesrpvbeil 1 300 train
+vessqxcgjp 0 300 train
+vestutvkuc 1 300 train
+vetaifcrgb 1 300 train
+vetgneddor 0 300 train
+vetjxiiqmo 0 300 train
+vetlxcoypg 1 298 train
+vetudzjkpl 1 302 val
+veuidhqltu 1 300 train
+veujgyyigk 0 300 train
+veuuiabxhl 1 299 train
+veuxumhcok 1 300 train
+veuyqjgqqf 1 300 train
+vevbgrnncl 1 300 test
+vevflsutlk 0 300 val
+vevgmzjwyh 1 300 train
+vevkftlhae 1 241 train
+vevndjwbxp 1 300 train
+vevqccgdmi 1 300 train
+vewackcavc 1 300 train
+vewbfrmdxp 1 300 val
+vewjmlbtfc 1 300 train
+vewoqdyhfb 1 299 test
+vewpuspywj 1 300 val
+vewqndwgnj 1 300 val
+vexcwzcmuh 1 300 train
+vexdqmwvxn 1 297 train
+vexkkinfoj 1 300 train
+vexotpgdtv 1 300 train
+vexrpgxzpx 1 300 train
+vexrwmqauv 1 300 val
+vexsmecivv 0 300 train
+vexxenktvx 0 297 train
+veyaiqvubs 1 300 train
+veyarkmtry 0 300 train
+veyejigaka 1 241 train
+veyeyosrxz 1 300 val
+veyjifwweq 0 300 train
+veyldhtfon 1 300 val
+veynowrrav 1 300 test
+veypfxnbmx 1 300 train
+veyxvfmxsd 1 300 train
+vezhmeziqa 1 300 train
+vezmltphcx 1 300 train
+vezsoxophr 1 300 val
+vezunsqqur 1 300 train
+vezvjuniqo 1 300 train
+vfaipnxqwb 1 300 train
+vfaqxbheec 1 300 train
+vfaunzkssf 1 300 train
+vfaxuefsgq 1 301 val
+vfaybygqdj 1 300 train
+vfaydtmbhy 1 290 train
+vfazvlobwl 0 300 val
+vfbfbbcgtc 0 300 train
+vfblawfshw 1 301 train
+vfbnamtpdk 1 300 train
+vfbqapwssl 1 300 train
+vfbseokfie 1 298 train
+vfbsnuopin 1 300 train
+vfbtsfenme 0 300 train
+vfcewkxfjb 1 300 train
+vfctsfsnxt 1 300 val
+vfcuebkkzk 1 292 val
+vfdaxmilhm 1 240 train
+vfdevuaarz 1 300 train
+vfdfsnzlqd 1 300 train
+vfdgfxvbaa 0 300 val
+vfdgnprlqz 0 300 train
+vfdtziqiwv 0 300 train
+vfdtzziwho 1 300 train
+vfdwndutod 1 300 val
+vfeaatkbgo 1 143 train
+vfeagofxwb 1 300 train
+vfehwfuuse 1 298 train
+vfeszwyzwx 1 300 val
+vfevqvhexh 1 300 train
+vfewftvulj 0 300 val
+vfextwbkrc 0 300 train
+vffbnhhjeo 1 300 train
+vffcezqrqs 1 300 train
+vffnvaxspb 1 300 val
+vffremtvap 1 300 val
+vffrnlprcl 1 300 train
+vffzgzccpe 1 298 train
+vfggfuqsou 1 300 train
+vfgmrulcwt 0 300 val
+vfgnyjnqms 1 297 train
+vfgrhbtjwh 1 300 train
+vfgsrjoovx 1 300 train
+vfgtltwwkj 0 300 train
+vfgzsuybfi 1 300 val
+vfhbukfngf 1 300 val
+vfhcukrbjz 1 300 train
+vfhfduegkh 1 300 train
+vfhkpehaqe 1 241 train
+vfhltutaae 0 300 train
+vfhsrhbxxn 1 300 train
+vfhtavkckb 0 300 train
+vfhvblavjt 1 298 train
+vfhvyufylj 1 300 train
+vfidhgkhbo 1 300 train
+vfidpmpbqd 1 300 val
+vfigcyaqcf 1 300 train
+vfilhflcke 0 300 train
+vfilwdmibe 1 300 train
+vfiuieuoie 1 300 val
+vfjearzksp 1 300 train
+vfjhtazznp 1 300 train
+vfjkvarpsb 1 300 val
+vfjqemdcvr 0 300 train
+vfjstwnimg 0 300 train
+vfjsxdipsb 1 300 train
+vfkgzfdjsl 1 300 val
+vfkodimpir 1 300 test
+vfkoirexjw 1 300 train
+vfkopjopor 1 301 train
+vfkpjirbkm 1 300 train
+vfkyswacal 1 300 train
+vflaeohpdd 1 300 train
+vflbsumpzz 1 300 train
+vfleyzslul 1 300 train
+vflfzgsion 1 300 train
+vflgpfrofk 0 300 train
+vflgvlkmfl 1 300 train
+vflhddkpyd 1 300 train
+vflhlzzokx 1 300 train
+vfllzbpgsr 0 299 train
+vflnaqhknr 1 299 val
+vflotlehgp 1 298 train
+vflsqbagxg 1 300 train
+vflvbqcjsb 1 300 train
+vfmakpzrts 1 300 train
+vfmdtymljv 1 300 train
+vfmhvzgfcs 1 300 train
+vfmkuhkbcn 1 301 train
+vfmquywpnx 1 300 train
+vfmyfdxjrv 1 300 val
+vfnfkqnxiz 1 300 train
+vfnhjlvwfg 1 300 train
+vfnhsbklan 0 290 train
+vfnhzsxvsg 1 300 train
+vfnkpcsdid 1 300 train
+vfnqzmmxkl 1 301 train
+vfnrczdlux 1 300 train
+vfntfbauih 0 300 train
+vfntqoubyh 1 300 train
+vfnumclzfx 1 301 train
+vfnvrertzs 1 300 train
+vfolffzflf 1 297 val
+vfoqyhpeoe 1 298 train
+vfowrktccu 0 300 train
+vfozursqsh 1 300 train
+vfpjchlnnd 1 300 train
+vfpkyicjeu 1 300 train
+vfqgfbhkzs 0 300 train
+vfqgwtqwrr 1 299 test
+vfqkbxfofg 0 300 val
+vfqnhruluc 1 300 train
+vfquueicnw 1 300 train
+vfqvlxsefa 0 300 train
+vfqvqdnjtf 1 300 val
+vfqwjagemf 0 300 train
+vfqywuedxv 1 300 train
+vfrbcotnwe 1 300 train
+vfrdxvexlm 1 300 train
+vfrfkovrga 1 299 test
+vfrghwtdlj 1 300 train
+vfrgsynvwy 1 300 train
+vfrlbhvpap 1 300 train
+vfrmnckbjp 1 300 train
+vfsfvslzxa 1 300 train
+vfsnvaimdh 1 300 val
+vfstwnqdce 1 300 train
+vfsulsugqp 1 300 train
+vfszaqentw 1 300 train
+vftabsvdcv 1 300 train
+vftargtdwb 1 300 train
+vftarmtpce 1 300 train
+vftavpyqby 0 300 train
+vftbepkuwz 1 299 val
+vftcidkfpi 0 300 train
+vftdmduipx 1 300 train
+vftfacniuh 1 300 train
+vftgddsfjr 1 241 train
+vftkjmozdj 1 300 train
+vfttfmjztd 1 298 train
+vfubytxlca 1 300 train
+vfucizhdjk 1 241 train
+vfufnweawx 0 300 train
+vfuhpwyctw 1 300 train
+vfuincabvi 1 300 val
+vfuioczzpe 1 299 test
+vfuixopjaf 1 300 train
+vfumdcywiu 1 300 train
+vfumwyxiyh 1 301 train
+vfusicdzzg 1 300 train
+vfuvjltxjy 1 300 train
+vfuwcjhaez 1 300 train
+vfuyhtbwqx 1 300 train
+vfvqptursj 1 300 train
+vfvrnujhku 1 300 train
+vfvrydyerz 1 136 train
+vfvschhvon 1 300 train
+vfvuuhbgny 1 300 train
+vfxfouwbyj 1 300 train
+vfxkgrhzpj 1 300 val
+vfxnwwuprd 1 300 val
+vfyctljbef 1 300 train
+vfyhzbwrqr 1 300 val
+vfyiqvnvbx 1 300 train
+vfykzmppbv 0 301 train
+vfyofexiqr 1 300 train
+vfyqgyaucy 1 300 train
+vfyqjtfudm 0 300 train
+vfyqvklnwa 1 300 train
+vfzdwfqakx 1 300 train
+vfzgfoovfl 1 300 train
+vfzkimbvhv 1 298 train
+vfzsssiznm 1 300 train
+vfzuwbrzfw 1 300 train
+vfzzgcnrvh 1 300 val
+vfzzmennou 1 300 train
+vgacirblsz 1 300 train
+vgaibwilpk 1 300 train
+vgajigcsqw 1 300 val
+vganqiexfq 1 300 train
+vgbflegefs 1 300 train
+vgbpnsvsuf 1 300 train
+vgbxifvwgh 1 300 train
+vgbxjtljac 1 300 train
+vgbzhesioo 1 301 train
+vgcghzvajg 1 300 val
+vgcgpiyhbm 1 300 train
+vgcknnpsbf 1 301 train
+vgcmsahofy 1 300 train
+vgcogsxijn 1 300 train
+vgcspdaege 1 300 train
+vgcuubwckm 1 300 train
+vgcwxcyiof 1 300 test
+vgdllmzjcw 0 300 train
+vgdlwfxlrq 1 301 train
+vgdnjlezqp 0 300 train
+vgdnnifpwx 1 300 train
+vgdoycbfzh 1 300 train
+vgdsgijqpv 1 300 train
+vgdsqikwgd 1 300 train
+vgdvlvjhod 1 300 train
+vgdwxafmnp 1 300 test
+vgecwlcakv 1 300 val
+vgeffvgwxi 1 298 train
+vgehtbkfpe 1 300 train
+vgekasigqp 1 300 train
+vgeowvmdic 0 300 train
+vgepwukqsj 1 300 train
+vgezorjzst 1 301 train
+vgezzdapxd 1 300 train
+vgfapiefqq 1 300 train
+vgfdryazlz 1 301 train
+vgfrfuvdcy 1 300 val
+vgfuloptua 1 300 val
+vgfxjwupga 1 301 train
+vgfzllyeel 1 301 train
+vggajruyks 1 300 train
+vggbllpyuz 1 302 train
+vgghejragx 1 301 val
+vggkehvpvt 1 300 train
+vgglcdhnoe 1 300 train
+vggowdkxlt 1 300 train
+vgguczkjbz 1 300 val
+vghiburcxc 0 300 train
+vghpqzmhcz 1 300 val
+vghtllobjq 1 300 train
+vghybdtpch 1 300 train
+vgiaotyvjm 1 300 test
+vgiipejkbo 1 300 train
+vgimszrkun 1 300 val
+vgirlxhkir 1 300 val
+vgivgyrijm 0 300 train
+vgiwjhtzcw 1 300 train
+vgizljblzy 1 300 train
+vgjezvwiau 1 300 train
+vgjjfhabto 1 302 val
+vgjlvgostr 1 301 train
+vgjwsjvapa 1 300 train
+vgjwuvrjil 1 300 train
+vgjxpspryy 1 300 train
+vgjyjoqqda 1 300 train
+vgkavsxkbu 1 300 train
+vgkcynisyn 0 300 train
+vgkeiamink 1 300 train
+vgkffuboll 0 300 val
+vgkkfjwbmo 1 300 train
+vgklopyqvn 1 301 val
+vgkokxzshx 0 300 val
+vgkqcdmaew 0 300 train
+vgksgivitz 1 301 train
+vgkwuigjhs 1 298 train
+vglkltoonj 1 300 train
+vglpsurlpe 1 300 train
+vglslxotoc 1 300 train
+vgltcvlskp 1 300 train
+vgmckbclkg 1 301 train
+vgmecbdpfr 0 300 train
+vgmgkepdwi 1 241 train
+vgmvjwslby 1 301 train
+vgmvkrdwjn 1 300 train
+vgmykxblbg 1 300 train
+vgmywsaype 1 300 train
+vgmzygrzbx 1 300 train
+vgndywbmgf 0 83 train
+vgngnciziy 0 300 val
+vgnoguhscj 1 300 train
+vgnvpdxetj 1 300 train
+vgnybxowkd 1 300 train
+vgnygnxuqi 0 300 train
+vgodinrcwk 0 298 train
+vgoiksaddg 1 241 train
+vgolzmuqve 0 300 train
+vgorklvyph 1 300 val
+vgotiegrfo 1 300 train
+vgotmcmoea 1 241 train
+vgpflbusem 1 300 train
+vgpjbehlzv 1 300 val
+vgpqbanpus 1 300 train
+vgpvetmhaw 1 300 train
+vgpvskdear 0 300 train
+vgpzvckjup 1 299 test
+vgqdlzfgou 0 300 train
+vgqeucbdzh 1 301 train
+vgqicgmdxy 1 299 test
+vgqihhasxp 0 300 train
+vgqlrclkbd 1 300 train
+vgqnfhsxxs 0 299 train
+vgqotmftcr 0 300 train
+vgqthzxium 1 300 train
+vgrbygvlvs 1 300 train
+vgrcfoqkys 1 300 train
+vgrhobnbfo 1 300 train
+vgrmeaelov 1 301 val
+vgrnrsdrhh 1 300 val
+vgrrhhfdof 1 300 train
+vgrrktbveh 1 300 train
+vgrscvxomm 1 136 train
+vgrssfesyn 1 298 train
+vgrvobnbyc 1 300 val
+vgrxvbdztf 1 300 train
+vgrzgfgkct 1 298 train
+vgrzkmceeb 1 300 val
+vgrzsujvfb 1 302 train
+vgsfcmmmjz 1 300 train
+vgslbubshw 0 300 train
+vgsnqqagqx 1 300 train
+vgsqqboiey 1 300 train
+vgsvlukfad 1 300 train
+vgswacpvls 0 300 train
+vgtggjgbez 1 300 train
+vgtlvzefkj 1 300 train
+vgtngkojts 1 301 train
+vgtnujiubf 1 300 train
+vgtpssvbve 1 300 train
+vgtrxbmpry 1 300 train
+vgttrdzwyd 0 300 val
+vgucxgaxth 1 300 train
+vgujrwpdkv 0 300 train
+vgumqiicht 0 300 train
+vguoilzpql 1 300 val
+vguuctiaho 1 240 val
+vguxwdkxtr 1 300 train
+vguyewjvsd 1 300 val
+vgvfkjafiv 0 300 train
+vgvkaibqdc 1 300 train
+vgvpjmdbhb 1 300 train
+vgvqcbtepv 1 299 test
+vgvwhfjodh 1 300 train
+vgvzbxfqay 1 300 train
+vgwaolvigk 1 302 val
+vgwgtwuizh 1 300 train
+vgwhrgaefk 1 300 train
+vgwpixfpaa 1 300 train
+vgxeuvagxh 1 300 train
+vgxfdvtnic 0 300 train
+vgxgtbmzga 1 301 train
+vgxlmompns 1 300 train
+vgxroylscx 0 300 train
+vgxsofufgk 1 147 train
+vgxvfzwdgb 1 300 train
+vgybiuwawn 1 300 train
+vgycmueljc 1 301 train
+vgyftxulpj 1 300 train
+vgylnflyrg 1 299 val
+vgyrybdmzc 0 300 train
+vgzenxhrez 1 300 val
+vgzexvdwxv 1 300 train
+vgzffcuqvi 1 300 train
+vgzvuhpcnc 1 300 train
+vhapgiijym 1 300 train
+vhazbwqznu 1 300 train
+vhbakkudnn 1 300 val
+vhbbwdflyh 1 300 test
+vhbcbkdznd 1 301 train
+vhbfckjdwt 1 300 train
+vhbfhsqcwf 1 300 train
+vhblpxzhsg 1 300 val
+vhblqkervg 1 300 train
+vhbpktghmd 1 300 train
+vhbrdglzgv 1 236 train
+vhbvkycgty 1 300 val
+vhcdsovnca 1 300 train
+vhcepcwbxy 1 300 train
+vhcghhjkul 1 300 train
+vhcgkywmti 1 299 train
+vhcgtddult 0 300 train
+vhclcqiqej 1 300 train
+vhcmlontoy 1 300 train
+vhcmnakmwa 1 300 train
+vhcnckkcmb 1 300 val
+vhcnfrupqk 0 300 train
+vhcrrcszbc 0 300 train
+vhdgemrscb 1 300 train
+vhecaycdri 1 300 train
+vhedjqdzdj 1 300 train
+vhejcdylza 0 300 train
+vhelobkunu 1 300 train
+vheovvsuua 1 300 train
+vheoxjagto 1 300 val
+vhfdkgcwll 1 300 val
+vhfiokdsty 1 301 val
+vhfnsnwmjg 1 300 train
+vhfoqvbucu 1 300 train
+vhfpkonfad 1 298 train
+vhfrvatyxh 1 300 train
+vhgemrfnpy 1 300 val
+vhgjbjjhby 0 300 train
+vhgpmsooha 1 300 val
+vhgsftxefi 1 301 train
+vhhbcwqhvl 0 300 train
+vhhcmcepsc 1 300 train
+vhheakzdyz 1 300 train
+vhhjovigpz 1 300 train
+vhhlfodsgr 1 300 val
+vhhlniitqv 1 302 train
+vhhrdwqayw 1 300 train
+vhhsjaeniw 1 299 val
+vhhwcoaciv 1 300 train
+vhhycwgvmu 1 300 train
+vhidioegvr 1 300 train
+vhidqarhqi 1 239 train
+vhifhryrmv 1 301 train
+vhifkqeodh 1 300 val
+vhigixbfei 1 300 train
+vhihjnunqv 1 300 train
+vhiixsmvyc 1 298 train
+vhipamioud 0 300 train
+vhirvynhnq 1 300 train
+vhitpoxhpm 0 300 train
+vhjcnhzejg 1 300 train
+vhjebldqnu 1 300 val
+vhjnzmecgg 1 300 train
+vhjpgqtmlk 1 300 val
+vhjzscovkk 1 298 train
+vhkgrwqpvk 1 300 val
+vhkxxdxgcn 0 300 val
+vhlswgbsan 1 298 train
+vhmdfhvqql 1 300 train
+vhmihxpuot 0 300 train
+vhmjeqagkc 0 300 train
+vhmrtrnhnk 1 300 train
+vhmucitody 1 300 train
+vhndkmeklc 1 300 train
+vhndnaalra 1 299 val
+vhnmunxjpz 1 300 val
+vhnnlnkeyf 1 300 test
+vhnocygtpq 1 300 val
+vhnopvzqfp 1 300 val
+vhnqnoecro 0 269 train
+vhntbpbzfm 1 301 train
+vhntgygdqw 1 241 train
+vhocmuuvph 1 300 train
+vhofdjmwkv 1 300 train
+vhoiiowhsz 1 300 train
+vhojcxuqba 0 300 val
+vhojjwsnli 0 300 train
+vhopvbmsgy 1 300 train
+vhorpvvjow 1 300 val
+vhovixtqjs 1 300 train
+vhpfejhytt 1 300 train
+vhpgkvscom 1 300 train
+vhpgqjuowh 1 300 train
+vhphdqsajw 0 300 train
+vhphtddasg 1 300 train
+vhpinxcqhj 0 300 train
+vhpjdjspre 1 300 val
+vhpjgvryvv 1 300 train
+vhpjhwzccg 1 300 train
+vhpmqlnxyu 1 300 train
+vhpupxveay 1 300 test
+vhqaiwbumb 1 300 train
+vhqgeyngzg 1 300 train
+vhqgmvyxwf 0 300 train
+vhqnsjfnsl 1 300 test
+vhqsrhweef 0 300 val
+vhqusscmtz 1 296 train
+vhqzxlahov 0 300 train
+vhrafoxdrn 1 300 val
+vhrbkhptlq 1 300 train
+vhrdxvgvsz 1 300 train
+vhrhkimkpw 0 300 train
+vhrsinaqlr 1 300 train
+vhrsrexhgu 1 300 train
+vhrxopyhtm 1 300 val
+vhrzdxqvwp 1 300 train
+vhsbatxysm 0 300 train
+vhshlcjkco 1 300 train
+vhsnjqelan 1 300 train
+vhsqcfrtzn 1 300 train
+vhssjeykri 1 300 val
+vhsswhnyzx 1 300 train
+vhswkbvlej 1 298 train
+vhtcueypbp 1 300 train
+vhtdseotwe 0 300 train
+vhtefwolqi 1 300 train
+vhtiyhyhdy 1 300 train
+vhtknmbods 1 300 train
+vhtyafwwzs 1 300 train
+vhuatvtfpu 1 300 val
+vhufnslszj 1 298 train
+vhugfxmgmd 1 301 train
+vhuleslynd 1 301 val
+vhulrzdwhz 1 300 train
+vhumwelpsz 1 255 train
+vhunokeedw 0 300 val
+vhuqgyiaeq 1 300 train
+vhuvavatcj 1 300 train
+vhuwfqtzlk 0 300 train
+vhvcdvthzf 1 300 train
+vhvfewspbu 1 300 train
+vhvisstbus 1 300 train
+vhvtjsiirh 0 299 train
+vhvvkakhce 1 300 val
+vhvxjlhdtt 1 300 train
+vhweerhrvj 1 300 train
+vhwgtyefgv 1 300 val
+vhwgvwxdmm 1 300 train
+vhwhsusxmg 1 298 train
+vhwjhwygap 1 300 val
+vhwmivkxqp 1 300 train
+vhwqbvdpnq 1 300 train
+vhwshcljrl 1 300 val
+vhwxihxlwk 1 300 train
+vhxainwxwj 1 298 train
+vhxbgaivvn 1 300 train
+vhxemanczc 1 300 val
+vhxilqsezm 1 300 val
+vhxkjmmspl 1 300 train
+vhxqvdsurr 1 300 val
+vhxrzboohi 1 300 train
+vhxyusuyxq 1 300 train
+vhxzlpzvaz 1 300 train
+vhyagubmot 1 300 train
+vhyajcyngz 1 300 train
+vhyeoznjwp 1 300 train
+vhygkuxczf 1 300 train
+vhykpqniml 1 300 train
+vhynmylwkd 1 300 train
+vhytgewrbh 1 300 train
+vhyuqdbzog 1 300 train
+vhyvttctxs 1 300 train
+vhywjmfros 0 300 train
+vhzapxhfib 0 300 train
+vhzheryhdq 1 300 train
+vhzjmxxnxa 0 300 train
+vhzsdmwdmk 1 300 train
+vhztrcmmzn 1 300 train
+vhzzdaeeyd 0 300 train
+viafkisgid 1 300 train
+viairejnyw 1 300 train
+viajonjcyn 1 300 train
+viakcwofos 1 300 train
+viaktvuoyk 1 300 train
+viaygikfgh 1 300 train
+viayvyetye 1 300 train
+vibhrvveql 0 300 val
+vibnrwzrhb 0 300 train
+vicavjdlxp 1 300 train
+vicdkyasvt 1 300 train
+vicfqzlwfn 1 300 train
+vickoeuevr 1 300 train
+vidbdhdkad 1 300 train
+vidbfpiyru 1 300 train
+vidfrfnvbd 1 300 train
+vidkrzkzot 1 300 val
+vidyizdisg 0 300 train
+viehattipr 1 300 train
+vieltxisfw 1 300 val
+vieoxrjclk 1 300 val
+vieulkyluk 1 300 train
+vievmrbywf 1 300 train
+vieyvdrgix 0 300 val
+vifejjrjcj 1 300 train
+vifhvtsavf 1 300 train
+vififfintx 1 300 train
+vifwwjykez 1 300 train
+vigbdgmudk 0 300 train
+vigbooecqv 1 300 train
+vigdnkgpiv 1 300 train
+vigdsuezrg 1 300 train
+vigevybpbi 1 300 val
+vigfpzbbqa 1 300 train
+vigikyjcvp 1 300 train
+vigknetmzb 1 300 train
+vignlknrfl 1 300 train
+vigpdarnvy 1 300 train
+viguwrzvjy 1 300 val
+vigvppwmkg 1 300 train
+vigypenwpk 1 300 train
+vihdnojgsg 1 300 train
+vihekzssnq 1 300 train
+vihjcaqdrl 1 301 val
+vihlzjrfel 0 300 train
+vihmjqbzxv 0 300 val
+vihsdbpbww 1 300 train
+vihtlkyrhu 1 300 train
+vihvthadnj 1 300 train
+vihykadidr 1 300 train
+vihysxfgxf 1 300 val
+viidhkoxyv 0 300 train
+viidtrqxzf 0 300 train
+viikpeobea 1 299 train
+viiltedtog 0 300 train
+viioeoyzwt 1 300 val
+viipflhljj 1 300 train
+viiygflhqg 0 300 train
+vijawemkwv 0 300 val
+vijbrlicxj 1 300 val
+vijesmbyzu 1 299 train
+vijjpwlzkx 1 300 val
+vijprrcxrn 1 301 train
+vijuirxebt 0 300 train
+vijvqwywhz 0 300 val
+vikbeujczb 1 300 train
+viklaxjryk 1 301 train
+vikzgkueda 1 300 train
+vilgdgqeug 1 241 train
+vilgwlados 1 300 train
+vilgyxzzvw 1 300 train
+vilmnnwjhm 1 300 train
+vilqffdwwb 1 300 train
+vilrluwcbf 1 300 train
+vilrxwruah 1 300 train
+vilsbcjqhf 1 300 val
+vilwomgvay 1 300 train
+vimegooaqs 1 300 test
+vimhuqnopj 1 298 train
+vimoevopcg 1 300 train
+vimtixnggh 1 300 val
+vinbwcqcdw 1 300 train
+vindsdwhee 1 300 train
+vinguynpez 1 300 test
+vinhlcntpz 1 300 train
+vinizhvgzr 0 300 train
+vinqcpfgud 1 301 train
+vintgxxmaz 1 300 train
+vinvhjvqai 1 300 train
+vinvomtdwr 1 301 train
+viobxkyyux 1 300 train
+vioebnkulq 1 300 train
+viojofykip 1 300 train
+viojphlnrc 1 301 train
+viojxltwfo 1 300 val
+vionhvwqig 1 300 train
+vioocrzszj 1 298 train
+vioqhwltxp 1 300 train
+viowvpammv 0 300 train
+vioxusvgwc 1 298 train
+vipkguihza 0 300 val
+viporlwbod 0 300 val
+vipswthtgr 1 300 train
+vipuvvczrg 1 300 train
+vipzjswkri 1 300 train
+viqdrqflap 1 300 val
+viqlegaftr 1 300 train
+viqmbxnpti 1 300 train
+viqmsywjqz 0 300 train
+viqowfgzsy 1 300 val
+viqqmrojgo 0 300 train
+viqrvsildi 1 300 val
+viqugytdfc 1 300 train
+viquhuuabm 1 300 train
+virgyikvuy 1 301 train
+virthnnwcq 1 300 train
+virufnfelm 1 300 train
+virxxbfcou 0 300 val
+visadvjvru 1 298 train
+visbxrfmwy 0 300 train
+visigorggj 1 83 train
+visjxbolmr 1 300 train
+vismzulnpa 1 300 train
+vispdxphpq 1 300 train
+vissslhapl 0 300 train
+visvupmrkk 1 300 val
+visykaldyg 1 300 train
+viszphgvmi 1 300 train
+vitakliaju 1 300 val
+vitervhitc 1 300 train
+viteugozpv 0 299 test
+vitjdpnfpi 1 300 train
+vitjzfurlh 1 300 val
+vitrledcff 1 300 train
+vitxwqjyhu 1 301 train
+vityyuvmzw 1 300 train
+vitzkattzq 1 301 train
+viufwkiuto 1 300 val
+viuioldtnu 1 300 test
+viukiigwtc 0 300 train
+viukymvgmb 1 300 train
+viummkpoun 1 300 train
+viutjhxipi 0 300 train
+viuxaligim 1 300 train
+vivibxdxsp 1 300 train
+vivkoqgnht 1 300 val
+vivqztcxcm 1 300 train
+vivuivitho 0 300 train
+viwanuestq 1 300 train
+viwcjjwrar 1 301 train
+viwkdohrpx 1 300 train
+viwkneexlx 1 301 val
+viwptlywir 1 300 train
+vixbpixgwz 0 300 val
+vixgtrhsrb 1 298 train
+vixjxycvix 1 300 train
+vixugdoqwc 1 300 train
+viycilvxhq 1 299 val
+viyedrhbvr 0 300 train
+viyjgdeadi 1 301 train
+viylujrvtf 0 300 train
+viyukuoprd 1 300 train
+viywjijmrh 0 300 train
+viyyebjalf 1 300 val
+vizcdbkjmo 1 300 train
+vizcnsjsit 1 300 train
+vizerpsvbz 0 299 test
+vizkprocjc 1 301 train
+vizmftbsfr 1 300 train
+viznmxrjqi 0 300 train
+vizobysqns 1 300 train
+vizyxieisj 1 301 train
+vjaiypverb 0 300 val
+vjanjdulzv 1 300 val
+vjapwemvti 1 300 val
+vjarwcfcop 1 300 train
+vjaucljrkn 1 300 train
+vjayareydu 1 300 train
+vjbajrkdxk 1 300 train
+vjbexkufuq 1 300 train
+vjbfjaolra 1 300 train
+vjbmdlazie 1 300 val
+vjbnrukjfu 1 300 train
+vjbrktuwpf 1 300 train
+vjbsscdaow 1 300 val
+vjbtclkeiq 1 301 train
+vjcgfjzpnq 0 300 train
+vjchscfdzw 1 300 train
+vjcoppzmrx 1 300 val
+vjcxvlunio 1 300 train
+vjddijgekg 1 300 train
+vjdnanakdg 1 300 val
+vjdtgbncqw 1 300 train
+vjdtxmimbz 1 300 train
+vjdxkodaoe 1 300 val
+vjeagnjbdk 1 300 val
+vjectuwoxn 1 300 val
+vjeduczihf 1 300 train
+vjegxiyvla 1 300 train
+vjeipjvxme 1 300 val
+vjekkdudfj 1 249 train
+vjekyrqcdq 0 298 train
+vjenypjkzt 0 300 val
+vjepxgipfi 1 300 test
+vjerhpiuyw 1 301 train
+vjeutxwxao 1 300 train
+vjexwwkoml 0 298 train
+vjeyhiwbvy 1 300 train
+vjeywrdbih 1 300 train
+vjfjniqnxx 1 300 val
+vjfjzgwibp 1 300 train
+vjfljqjqiu 1 300 val
+vjftdzltzr 1 300 train
+vjfvcvfbde 1 300 train
+vjgdxlrygd 0 300 train
+vjgfrjkawv 1 300 train
+vjggtmdzsu 1 240 train
+vjghipcdwx 1 300 train
+vjgmsiuqzq 1 301 val
+vjgopjjzmw 1 300 train
+vjgppgbdav 1 300 train
+vjgtbujhqd 0 300 train
+vjgvtnmrxm 1 300 val
+vjhcbtdcgd 1 300 val
+vjhhaopwjk 0 300 train
+vjhlqumzon 1 269 train
+vjhvqaykhm 1 300 val
+vjhxiwhqnl 1 300 train
+vjhzbkyhdw 1 300 val
+vjifvssash 1 300 train
+vjiicsofet 1 300 val
+vjiiikrtva 1 300 val
+vjilsvyvuu 1 300 train
+vjipcihnos 0 300 train
+vjiuppkgns 1 301 train
+vjjcivyfgq 0 300 val
+vjjicoufhl 1 300 train
+vjjmfkdkla 0 300 train
+vjjqrnsosy 1 300 val
+vjjsvmpxul 1 300 val
+vjjueyuaee 1 300 train
+vjjufwkogw 1 300 val
+vjjuhwczys 1 300 train
+vjkdbgpqnm 0 300 train
+vjkiyqaset 0 300 train
+vjktxelkca 1 300 val
+vjkyeumonr 1 300 train
+vjlbticgds 1 300 train
+vjldyultkm 1 300 train
+vjleprpcgw 1 300 val
+vjljdfopjg 1 300 test
+vjljetyhqx 1 300 train
+vjlnfjbbdt 1 300 train
+vjlpspyfqg 1 300 train
+vjlszitvfu 1 300 train
+vjltcrkyjk 1 300 val
+vjlzzqnjbb 0 300 val
+vjmafouyza 0 300 train
+vjmlyldnnf 1 300 train
+vjmnoobnaz 1 300 train
+vjmtmqkyti 1 300 val
+vjmyjwwwbg 1 300 val
+vjnbpougse 1 300 val
+vjnbtebjhv 0 300 train
+vjneqpysot 0 300 train
+vjnmgqnbkm 0 300 val
+vjnmnonubo 1 300 train
+vjnmnqvcwq 1 300 train
+vjnovdqina 1 300 train
+vjnpepcmoa 1 301 val
+vjnwowmvcj 1 300 train
+vjoaifuasz 1 300 train
+vjodrdxhej 1 300 train
+vjojpjftab 1 300 val
+vjokpmmkhe 0 300 train
+vjokxcywyt 0 300 val
+vjopqgxmca 0 300 train
+vjovroroyw 1 299 val
+vjowdfxqbq 1 300 train
+vjowxauwnt 1 300 train
+vjpblrvene 1 300 train
+vjpcxqehpl 0 300 train
+vjpgbyhfic 1 299 train
+vjpokjrsxm 1 299 train
+vjprkfputr 1 302 train
+vjpzbfbmfn 1 300 train
+vjqavaocrp 1 300 val
+vjqgkscksu 1 300 val
+vjrecnanfb 1 300 train
+vjrioyrusu 1 300 train
+vjrkvicvlg 1 300 val
+vjrqkyznnm 1 300 train
+vjrwsyibzm 1 300 val
+vjsefhweyg 0 302 train
+vjsepnyvpv 0 300 train
+vjsjlkxide 1 300 train
+vjstfrjmhr 1 288 train
+vjsvdnnrck 0 300 train
+vjszhscscx 1 298 train
+vjtfltccyw 1 300 val
+vjtgjgekwl 1 300 train
+vjtnjuhrkz 1 300 train
+vjtqegolwb 1 300 train
+vjtqhafbyd 1 298 val
+vjtxndheoz 1 300 val
+vjuametrqy 0 302 val
+vjubqmmqtm 1 301 train
+vjudsbuepu 0 300 train
+vjujyhfhrz 1 300 test
+vjupencgns 1 300 train
+vjuxdcaaew 1 300 test
+vjvenrdskl 1 300 train
+vjveodffpm 1 301 train
+vjvhcudghv 1 300 train
+vjvlrpyaev 1 300 train
+vjvlrroinh 1 300 train
+vjvnshamff 1 298 train
+vjvrbgqgvd 1 300 train
+vjvruvsyvj 1 99 train
+vjvzfugiqe 1 300 train
+vjvzihjgrj 1 300 train
+vjwebqvvfz 1 300 train
+vjwmdnrvuf 1 300 train
+vjwmefotby 1 300 train
+vjwmjdmnfh 1 301 val
+vjwnhzuwpc 1 300 val
+vjwpuuwfyy 1 300 val
+vjwpvemixj 1 300 train
+vjwqqugabo 1 300 train
+vjwvgxgydu 0 300 train
+vjwwcunuhh 1 302 val
+vjwwqswfvd 0 300 train
+vjxmismlde 1 300 train
+vjxovbbopn 1 298 train
+vjyaixfppd 1 300 train
+vjydkkczpi 0 300 train
+vjyfgpooko 0 300 val
+vjyieaccgn 1 300 train
+vjyllpezdm 1 300 train
+vjymlebfiy 1 300 train
+vjysdqaktx 1 300 train
+vjyuvvdine 1 300 train
+vjyvrugkoe 1 300 train
+vjyvxalibt 1 300 train
+vjzdetdusx 1 300 train
+vjzhumqpwi 1 300 test
+vjzlacvbbg 1 300 train
+vjzojynhcc 1 300 val
+vjzroevdib 1 300 train
+vjzuhhdvuo 0 300 train
+vjzwymmpka 1 300 train
+vjzxgtimer 1 300 train
+vkajucyjml 1 300 train
+vkamgjzest 1 300 train
+vkavnvgbpa 1 300 train
+vkbkqbbqdv 1 300 train
+vkblckoyzb 0 300 val
+vkbrsqmbfi 1 301 val
+vkbvirioum 1 300 val
+vkbxuhsvis 1 300 val
+vkchewraap 0 302 train
+vkctlgbhoe 1 300 train
+vkddyjktzb 1 269 train
+vkdeyfqork 1 300 train
+vkdfdufywg 1 300 train
+vkdhdeflsx 1 299 train
+vkdjerviml 1 239 train
+vkdodrhzpd 1 300 train
+vkedlslozl 1 300 val
+vkemazrtak 1 300 train
+vkewcogjuj 1 302 val
+vkeyhxykvm 1 300 train
+vkfcgyrnhu 1 300 train
+vkfffjjncl 1 300 train
+vkfkacvsvc 1 300 train
+vkfrcmajnk 1 300 train
+vkfrebmona 1 298 val
+vkfyqjrtkq 1 300 train
+vkggssizhl 0 300 val
+vkghjeygsg 0 301 train
+vkgirazfac 1 300 train
+vkgjjmbojl 0 300 val
+vkgqnmeagh 1 299 val
+vkgzdtoyae 1 300 val
+vkhdcfdcqf 1 300 train
+vkhhheqfvo 1 300 train
+vkhopttpck 1 300 train
+vkhpaibymp 1 300 train
+vkhtcgkibh 1 299 val
+vkhuwcfjfn 1 300 train
+vkicyqodkk 1 300 train
+vkirqaiuoc 0 300 train
+vkjauhkqtr 1 300 train
+vkjaxfweqr 1 300 val
+vkjgvgakcs 0 300 train
+vkjjqcplou 1 300 train
+vkjnyiaknv 1 300 train
+vkjpagqtxb 1 300 train
+vkjtjwpchx 1 301 val
+vkjyhhztei 0 300 train
+vkkeiamoou 1 300 train
+vkketnrfud 1 300 val
+vkkmleainv 1 300 train
+vkkssrvejb 1 300 val
+vkktdwglos 1 300 train
+vkkvvrwqxt 1 300 train
+vklahwebsb 1 301 val
+vkleyvbkmr 1 241 train
+vklggpdnqd 1 300 train
+vklqijaowj 1 300 train
+vklqsyelsj 1 300 train
+vkmfmegkiy 1 300 val
+vkmhohfopp 1 300 train
+vkmtbphtdi 1 300 train
+vkmvqinplq 1 300 train
+vkmycppntq 1 300 train
+vkmzmffkxy 1 298 val
+vkmzqsswji 1 239 val
+vknbiljqir 1 300 train
+vknoymfawn 1 300 train
+vkoutrzzre 1 300 train
+vkowdlpges 1 300 train
+vkpbaanrgc 1 300 train
+vkpdqpqpla 1 300 train
+vkpdzhuvjz 1 300 train
+vkpfkzljpl 1 297 train
+vkpixamasg 1 300 train
+vkpnerzefy 1 300 val
+vkpqabrmip 0 300 train
+vkpzeopgjo 1 299 train
+vkqcvtpefs 0 300 train
+vkqhhredbo 1 241 train
+vkqivxnett 1 300 test
+vkqixwsxuq 0 300 train
+vkqlekiyri 1 300 train
+vkqmzqfrok 1 300 val
+vkqnmpfvlx 1 300 train
+vkquzefowk 1 301 train
+vkqxrqpgdi 1 300 train
+vkrbbhcarq 1 300 val
+vkrezjrbkp 1 300 train
+vkrfiplcxu 1 300 train
+vkrlcimcda 1 300 train
+vkrofednrb 0 249 train
+vkrpxhokgb 1 301 train
+vkrvipdbhy 0 300 val
+vkrwzbgeur 1 300 train
+vkrxxjpwcg 1 301 train
+vksdndwdns 1 298 train
+vkshpszghw 1 298 train
+vksxufnaly 1 300 train
+vksymkuahf 1 300 train
+vktbtvfrmv 1 301 val
+vktckxpsse 1 300 train
+vktgnfnkpq 1 300 train
+vkthrczrzf 1 300 train
+vktsppjslw 0 300 val
+vkucbpxzra 0 299 train
+vkufnpacxk 1 297 train
+vkumnrgeky 0 300 train
+vkunbdghkb 1 300 train
+vkuoqjhpjs 1 300 train
+vkuxvfwfqu 1 300 train
+vkuymbddlv 1 300 train
+vkvawjbwmq 1 249 train
+vkvbafamjp 1 300 val
+vkvcvpseot 1 300 val
+vkvitobppp 1 300 train
+vkvjazreth 1 300 train
+vkvnatqfpn 0 300 val
+vkvnliinjg 1 300 train
+vkvtzhgmpk 1 600 train
+vkvwmdnqjz 1 300 train
+vkvzrnmjuv 1 301 train
+vkvzzoimxp 0 300 train
+vkwakqxfiz 1 299 train
+vkwaywuumj 1 300 train
+vkwmxkohuh 1 300 val
+vkwnmsimyw 1 300 train
+vkwtbzhxxk 1 300 val
+vkxbcvmanq 1 300 train
+vkxgplpkyn 1 298 train
+vkxhchwzpy 1 300 train
+vkxlntrbbf 1 300 train
+vkxnzfrqym 1 300 train
+vkxvyfpuhu 1 300 train
+vkxwevqwhv 0 300 train
+vkxwqbhrqc 1 300 train
+vkxxcrczdi 1 300 train
+vkyfqyimeo 1 300 train
+vkykuveblj 1 300 val
+vkyrtkgpnd 1 300 train
+vkyszouppa 0 300 val
+vkzauartyf 1 241 train
+vkzbigqhrx 1 300 val
+vkzflyigcd 1 300 val
+vkzpxhcrjx 1 300 val
+vkzsakhrfw 1 300 val
+vkztrlmcqy 0 300 train
+vkzucmdssd 1 300 train
+vladsvbfbb 1 301 train
+vladvnyeiv 1 300 train
+vlambpsxkj 1 300 train
+vlamodouaz 1 241 train
+vlaokifxkp 0 300 train
+vlastaykkk 1 300 train
+vlauwpzgqf 1 300 train
+vlavhjzgve 1 300 train
+vlbairfcep 1 300 train
+vlbdxxitbh 1 300 train
+vlbfacgfnh 1 300 val
+vlbimpjemh 0 300 val
+vlbjjuhpbh 0 300 train
+vlbmxriufd 1 300 val
+vlbnnvlydp 1 300 train
+vlbomdvoja 0 300 train
+vlboynaltr 1 300 train
+vlbpkrarqo 0 300 train
+vlbvdlbkwb 1 300 train
+vlbypmmhwq 0 300 train
+vlcbaytswm 1 301 val
+vlcccegfrv 1 300 train
+vlccyfrzkr 1 298 train
+vlchgcideb 0 300 train
+vlcjitqpjz 0 300 train
+vlcnvhanxr 1 300 train
+vlcvoppbbj 1 300 train
+vldaezlifv 0 300 train
+vldedrgvgo 1 300 train
+vldixcvisy 1 302 val
+vldstovjwu 0 300 train
+vlduixqrjx 1 300 train
+vlegvkwxdx 1 301 train
+vleicnhecu 1 300 train
+vlentymfmv 1 300 test
+vleuqknkpa 1 300 train
+vlfkebcnvy 1 300 val
+vlftkeaizu 0 300 train
+vlfulatfhl 1 300 train
+vlfyxaxlhx 1 300 train
+vlfzpkdunx 1 300 val
+vlfzukfccc 1 298 val
+vlgbexschr 1 300 train
+vlgehmytoe 1 300 train
+vlgldlsucz 1 300 val
+vlgovmbawb 1 300 train
+vlgzgzglih 1 300 train
+vlgzojfalb 1 300 train
+vlhbvwhvdf 1 241 train
+vlhdzfaqtx 1 301 val
+vlheohethw 1 300 train
+vlhgrirhmi 1 300 val
+vlhgwurhod 0 300 train
+vlhoupilhh 1 300 train
+vlhrgeyvqy 1 300 train
+vlhtpwjkte 1 300 train
+vlhwkieaep 1 300 train
+vlijpccghv 1 300 train
+vlijwlulnz 0 301 val
+vliksucltv 1 300 train
+vliowvjowm 1 300 val
+vliozkhzkp 1 241 train
+vliqbnejte 1 300 val
+vlirighakl 1 299 test
+vlistwmudb 1 300 train
+vlitsxjbka 1 301 train
+vliuallevi 1 99 train
+vlivtqeock 1 300 train
+vliyzoomly 1 300 val
+vljgyqklbz 0 300 train
+vljiptyngb 1 300 val
+vljmsimmbq 1 300 train
+vljufiycdc 1 302 train
+vljumscvtl 1 300 train
+vlkbweamqm 1 300 train
+vlkhmgqnwq 0 300 val
+vlkmjaybvm 1 300 train
+vlkpgibhgk 1 298 train
+vlkypafsor 1 300 train
+vllaigeulm 1 300 train
+vllaywfxer 1 298 train
+vllngjydtk 1 300 train
+vllrgwplce 1 300 train
+vlluwerdrf 1 300 val
+vllviebxnr 1 300 train
+vllwxtmcfj 1 300 train
+vllyshohnt 1 300 train
+vlmblrjort 1 300 train
+vlmcahccjj 1 300 train
+vlmccqxgft 0 300 train
+vlmclyrduz 1 300 train
+vlmdvzqjyx 1 300 train
+vlmhmxykgr 1 300 train
+vlmkudpvpw 0 300 train
+vlmkusmtnq 1 300 val
+vlmlhwsvmw 1 300 train
+vlmllzbcbe 1 300 train
+vlmlqvuxic 1 300 val
+vlmrlprnpx 1 300 val
+vlmublevbg 1 300 train
+vlmwdogdra 1 300 train
+vlmyorsprv 0 300 train
+vlndxesxym 1 300 train
+vlneabhohi 1 300 train
+vlnioebjkh 1 301 val
+vloauagxet 1 300 train
+vlodycfrfy 1 300 train
+vlokpywwjr 1 300 train
+vlonumqomf 1 300 train
+vlonzebjqp 0 300 train
+vlosmhxkgw 1 298 train
+vlpegdvokk 1 300 test
+vlpfcqtfpr 1 300 train
+vlpjjmibwr 1 300 train
+vlplaxowmp 1 300 val
+vlpmiheura 0 241 train
+vlpmklxnxy 0 300 val
+vlprdhtkdn 0 301 train
+vlpxpmswcm 1 299 val
+vlpzndqasb 1 240 val
+vlqfypwrxc 1 300 val
+vlqghoyrxc 1 300 val
+vlqrlmomry 1 300 train
+vlrimhfcmb 1 299 test
+vlrjcxuxsx 1 300 train
+vlrkfbqajs 0 301 val
+vlrozxsbcq 1 300 train
+vlrrakumcd 1 300 val
+vlrtqptolv 1 300 val
+vlruzzuvrf 1 300 train
+vlsbqvqete 1 301 train
+vlshxwulqf 1 300 train
+vlsjqcoqgp 1 300 train
+vlsudqfhkr 1 300 train
+vlswekcqtl 1 300 train
+vlsxutjhqz 1 301 train
+vlszdowies 1 300 train
+vltexnjcdp 1 300 train
+vltjrrgbcg 0 300 val
+vltqivzltb 0 300 val
+vltqktpvnx 1 302 val
+vltrakrzec 1 300 train
+vltsepourt 1 300 val
+vltwlzqcph 1 300 train
+vltxrrimhw 1 300 val
+vltyfdmvms 1 300 train
+vlufqntxvc 1 301 train
+vluhdcpmkh 1 302 val
+vlulrpckxf 1 300 val
+vlvalfbvnm 1 300 train
+vlvcubglaq 1 301 train
+vlvdqecnnj 1 300 train
+vlvqypypgw 1 300 train
+vlvsqekxro 1 300 train
+vlwdhnwjlb 1 300 val
+vlwfwkozzg 1 300 train
+vlwgfksjha 1 250 train
+vlwksozbnm 1 300 train
+vlwpgauoij 1 300 train
+vlwtggcodf 0 300 train
+vlwudpdije 1 300 train
+vlwylbdtqv 0 300 val
+vlxanpctsw 1 300 train
+vlxcdtzgbp 1 300 train
+vlxfyuzygn 0 300 train
+vlxhexolum 1 302 train
+vlxiupojog 1 300 train
+vlxmqleltz 0 300 train
+vlxqflgqtr 1 300 train
+vlxzbbftdc 1 300 train
+vlyapolayz 0 301 train
+vlygsgdvnd 1 240 train
+vlyjwngjwz 1 300 train
+vlyncoavxo 1 300 train
+vlypfdqlfy 1 300 train
+vlyrlqiead 0 300 train
+vlzgrroxoh 0 298 train
+vlzkhrxcdb 0 300 train
+vlzwcejywm 0 300 val
+vmaarhebuf 0 300 train
+vmaiputdme 1 300 train
+vmakjnpbmv 1 300 train
+vmakwptcpn 1 300 train
+vmalpcczmq 1 301 train
+vmanrnolbk 0 300 train
+vmapxyjnmb 1 300 train
+vmaqvrswmd 1 300 val
+vmasbhlvba 1 300 val
+vmbggfbkac 1 302 train
+vmbkkffgza 1 300 train
+vmbkxmjsar 1 300 test
+vmbntxvwro 1 300 train
+vmcdalwkvo 1 300 val
+vmcgrdvujq 1 298 train
+vmcigumadi 1 300 train
+vmciyzwglm 1 298 train
+vmckfdrklb 0 301 val
+vmctqtkuty 1 300 train
+vmcvebmqzw 1 300 val
+vmdenkmlhi 1 300 train
+vmdfgujeqc 1 300 train
+vmdjplxgfj 0 300 train
+vmdkamjafs 1 300 train
+vmdkeczkkh 1 300 train
+vmdpbmbfau 1 300 train
+vmdpfyfkwi 1 300 test
+vmdrbfktsp 1 300 train
+vmdtkugivw 0 300 train
+vmecnqblay 1 300 train
+vmeljciqnr 1 300 val
+vmerzuoedh 1 300 train
+vmevbnbyvg 1 300 train
+vmexxvekvx 1 300 train
+vmfabhoqax 1 300 train
+vmfdbgiliv 1 300 train
+vmflpiklqj 1 300 train
+vmfntlgmdz 1 300 val
+vmfqztaeyp 1 300 train
+vmfuxypvar 1 300 train
+vmfzbazxrr 1 300 train
+vmgfgqaune 1 298 train
+vmgfoxxmhx 1 300 train
+vmgiqwoyvt 1 299 test
+vmgjtzksgo 1 300 test
+vmgqjmbhuj 1 300 train
+vmgygpnqze 0 300 train
+vmgyhhcclj 1 300 train
+vmhibgxpsi 1 300 train
+vmhporqqym 1 300 train
+vmhpsmdiab 1 300 val
+vmhscypxba 0 300 train
+vmhxgccoiq 1 297 val
+vmigrsncac 1 300 test
+vmiiyyefra 1 300 train
+vmirklkeyi 1 300 val
+vmiscvenui 1 300 test
+vmisvhtgjh 1 300 train
+vmjculitwz 1 300 val
+vmjizlqenc 1 300 val
+vmjkvyclqh 1 300 val
+vmjmvdimji 1 241 train
+vmjqpwgvnq 1 300 train
+vmjxjwbjse 1 299 val
+vmkqzqtkmu 1 300 train
+vmkracbvkj 0 300 val
+vmksyqbkpl 0 300 train
+vmktcesfcg 0 300 train
+vmkuxqxkrz 1 300 train
+vmkwaeafqr 1 300 train
+vmkyxyowef 1 300 train
+vmldsazxrw 1 300 val
+vmlelhbuio 1 300 train
+vmlfjnfwhi 1 300 train
+vmlpsftoph 1 300 train
+vmluhrimpn 1 300 train
+vmlvpjjrrv 1 300 train
+vmmisgyagl 0 300 val
+vmmjapnzab 1 300 train
+vmmnbaktjy 0 300 train
+vmmpymyuyd 1 301 val
+vmmqqnktlt 0 300 train
+vmmttqnknl 1 300 train
+vmmxvfwbgp 1 301 val
+vmnatbbkam 0 300 train
+vmnmqumnpu 1 241 train
+vmnmsnhxpj 1 300 train
+vmnqltuzmx 1 300 val
+vmnrqsfaga 1 241 train
+vmnsqsedbm 0 300 train
+vmnwzwtqdf 1 300 train
+vmnxuccacc 1 300 train
+vmoerhwqsw 1 300 train
+vmofmcjlst 1 300 train
+vmonvjunsz 1 300 train
+vmosjmgcpx 1 301 val
+vmospzljws 0 300 train
+vmosrwhocn 1 300 train
+vmouibweej 1 300 val
+vmowjajdgw 1 300 train
+vmphcwkvel 1 300 train
+vmpvocstjw 1 269 train
+vmqaejhtoa 0 300 train
+vmqbnadjpe 0 300 train
+vmqkqokkqt 1 300 val
+vmqlfxlatf 1 300 train
+vmqmekmdhl 1 300 train
+vmqpalnuxn 1 300 train
+vmqrdoiyhc 1 297 val
+vmrsgffaxh 1 300 val
+vmrtbtwehe 1 300 train
+vmsavyqpqv 1 241 train
+vmsijampfx 1 300 train
+vmsikphyuw 0 299 val
+vmskipiiyt 1 300 train
+vmsklqlhfw 1 300 train
+vmstgdvols 1 297 train
+vmszbwofgp 1 300 val
+vmtdlmtrtm 0 300 train
+vmtymtievb 1 300 train
+vmuddxnpgx 1 300 train
+vmuebfnmak 0 300 train
+vmugekqrpa 1 300 val
+vmujlevghf 1 302 val
+vmurpvzeby 1 300 val
+vmuunfwjuu 1 300 train
+vmuuspexiy 1 300 train
+vmvdjplrrb 1 298 train
+vmvihaqibh 1 301 val
+vmvjfkbrxs 1 300 train
+vmvmsiktzg 1 300 train
+vmvpazkwkj 0 300 train
+vmvssmytbn 1 241 train
+vmwcynlwee 1 300 test
+vmwiceadjy 1 300 train
+vmwmipqkff 1 300 train
+vmwtddqzmg 1 300 train
+vmwwvzervm 1 300 train
+vmxbfylntq 1 300 train
+vmxbudhonm 1 301 val
+vmxeiydeml 1 301 train
+vmxfwxgdei 0 300 test
+vmxjsdkuju 1 300 train
+vmxmafazny 1 300 train
+vmxpxxuvpp 1 300 train
+vmxtcstilx 1 241 train
+vmxurpilcs 1 300 train
+vmybacvzdx 0 301 val
+vmyocgxrxi 1 297 train
+vmytbzisxu 1 300 train
+vmytxryfpl 1 300 train
+vmzdwmknuz 1 300 train
+vmzeggvbvu 1 300 val
+vmzeuiorgs 1 298 train
+vmzggxddgd 1 301 train
+vmzgpaafno 1 300 val
+vmzihqstqa 1 300 train
+vmzrjytbge 1 300 train
+vmzshewnxq 1 300 train
+vmzyqeubjd 1 300 train
+vnaawyjxik 1 300 val
+vnabwefldm 0 300 train
+vnactmbahi 1 300 train
+vnaczkvazd 1 301 train
+vnadaakkgk 0 300 train
+vnamtyilxv 1 298 train
+vnasubcekx 1 300 train
+vnatgarprj 1 300 train
+vnatggaafz 1 300 train
+vnauaqovhv 0 300 train
+vnawjonjkj 1 300 train
+vnawmwjiak 1 300 train
+vnaxakdaoy 0 302 train
+vnbidvjxfw 1 300 val
+vnbjteoglx 1 300 val
+vnbsqmaoyd 1 299 test
+vnbxaybmbg 1 300 train
+vncfwkhxmd 0 300 val
+vnchczzmfe 1 300 train
+vncicnqnyk 0 300 train
+vncnsmnnlq 1 300 train
+vncuomdtlb 1 300 val
+vncvnhxlpw 1 300 train
+vndcqexgur 0 300 train
+vnddyrvqer 1 300 train
+vndeurkxfk 0 300 train
+vndgmpwqsc 1 300 val
+vndmgydpon 1 299 train
+vndmytcvri 1 300 train
+vndymimndn 0 300 train
+vneaxzrtde 1 300 train
+vnejvzmoam 0 300 train
+vnexfwrcuk 1 300 val
+vnexprlzju 1 298 train
+vnfakjaspu 1 300 train
+vnfglpeugi 1 300 train
+vnfinlbecj 1 300 train
+vnfljvkhqz 1 300 train
+vnfrrtluid 0 300 train
+vnfstemawi 1 301 val
+vnfyclbwlb 1 300 train
+vnfzyjlehx 1 300 train
+vngmafoyik 0 300 train
+vngnujnpzo 1 300 train
+vngrljqtjc 1 300 train
+vngueqqcmz 1 300 train
+vngxazoptz 1 300 train
+vnhdlnpppa 1 300 train
+vnhhpivrab 1 300 train
+vnhjapijkm 1 300 train
+vnhulktgxh 1 300 test
+vnhunisscr 1 299 test
+vnibrxqooc 1 300 train
+vniceantpi 1 300 train
+vniglgwbin 1 300 train
+vnijmufkns 1 300 train
+vninpbciju 0 601 train
+vnioomfhlp 1 301 val
+vnjdsaklra 1 99 train
+vnjedttiuf 1 301 val
+vnjndtraot 1 301 train
+vnjrzywtrd 0 300 val
+vnjxookilu 1 299 train
+vnjzgroonv 1 300 train
+vnkcpuiuxv 1 300 train
+vnkecdalpd 0 300 train
+vnklmlbjeg 1 300 train
+vnklygwiix 0 300 val
+vnkntupixt 1 300 val
+vnkojjbeek 1 300 train
+vnkoyvfxnp 1 301 val
+vnkszsbmnq 0 300 train
+vnkuonhrlo 1 300 val
+vnkuwthaop 1 300 val
+vnldthxqbz 1 300 test
+vnlnhgwhkg 1 301 train
+vnlwmwbkdr 1 300 train
+vnlwteuizj 1 300 val
+vnlzxqwthl 0 300 test
+vnmfjouunr 1 300 train
+vnmpdhlfyl 1 300 train
+vnmxsdidfr 1 300 train
+vnnewgevky 1 300 train
+vnnfcokdal 1 300 train
+vnnfxhegzw 1 136 train
+vnngbicgvx 0 302 train
+vnnglnnnip 1 300 train
+vnnohpqhjq 1 300 test
+vnnondfndh 0 300 train
+vnnvivdxfc 1 300 train
+vnnyycnumn 1 300 train
+vnnzwvvhjc 1 300 val
+vnoirmbehi 1 300 train
+vnojvztsws 1 300 train
+vnokttmtho 1 300 train
+vnolaloukn 1 300 train
+vnomvagnsi 1 300 train
+vnorfntjyd 1 300 train
+vnotmfgttc 1 300 train
+vnowhxpcny 1 300 train
+vnoyyzlrhl 1 300 train
+vnpdkeemzp 0 300 train
+vnpgdojdpl 0 300 train
+vnphrilqrd 1 300 train
+vnpkomujry 0 300 train
+vnpzuzemho 1 300 train
+vnpzvqphkm 1 300 val
+vnqbgrywgs 1 269 train
+vnqbrqkyst 1 300 train
+vnqongnfed 1 241 train
+vnqpzwmohz 0 300 train
+vnqttlyubf 1 300 train
+vnqzoaxubj 1 300 val
+vnrjpyqjxd 1 298 train
+vnrjsakchu 1 300 train
+vnrloxxgpf 1 300 val
+vnrmmdcoyx 0 300 train
+vnrmrkvred 1 300 val
+vnrmxwtsmf 0 300 train
+vnrtottxmd 1 300 train
+vnrybsmire 0 300 train
+vnskrqkpcg 1 300 val
+vnspocydlv 1 241 train
+vnsvqrjpje 1 300 train
+vnsxdkjjtk 1 300 train
+vntbyeepdy 0 300 train
+vntcntebmr 1 300 train
+vnteansskm 1 301 train
+vntfzgejhj 0 300 train
+vntgzyrwvq 0 300 train
+vntkhpeycf 0 300 train
+vntnnzrivx 0 300 train
+vntseqaeej 1 297 val
+vnuccgfhub 1 300 train
+vnujcpztrf 1 301 train
+vnundsmzzl 1 300 val
+vnunhruyle 1 300 train
+vnupirkwau 0 300 train
+vnupxijubk 1 300 train
+vnvhqupmzl 0 300 train
+vnvhrnslpp 1 300 val
+vnvjxhsymd 0 300 train
+vnvmimjvux 1 300 train
+vnvpwsjsdd 1 297 val
+vnvqcbunxx 1 299 test
+vnvujyecjn 0 300 train
+vnvvkzkfhw 1 300 train
+vnvwhpkedj 0 300 val
+vnvxuhubts 1 300 train
+vnvygsamsn 1 300 train
+vnwbsatlha 1 300 train
+vnwouygwjh 1 300 train
+vnwrvdsnzw 1 300 train
+vnwsvirper 1 300 train
+vnxdmkpdcv 1 300 val
+vnxhvoeiex 1 300 train
+vnxsxsatvk 1 300 val
+vnxtkkwixs 1 300 train
+vnxupuryad 0 300 train
+vnxzqadjly 1 299 train
+vnyayavwsz 1 301 val
+vnycluspfa 1 300 train
+vnyhlnpjzv 1 240 train
+vnyhwiefde 1 300 train
+vnyicpbvgn 1 300 train
+vnykfswvqd 1 300 train
+vnzbcizfsc 1 300 train
+vnzcpoqipv 1 300 train
+vnzfjmxalx 1 301 train
+vnzfkjxkhr 0 300 train
+vnzhrqkmao 1 300 train
+vnzhtrgtuk 1 300 train
+vnzllfjpwd 1 300 val
+vnzsxpdhhg 0 300 train
+vnzukydvqk 1 300 train
+voanbpmarp 1 301 train
+voaojmmecs 1 300 train
+voaslfkslq 0 300 train
+voauqwwpeg 1 241 train
+voawxrmqyl 1 300 test
+voazwmmlgi 1 300 val
+vobbnfrnsw 1 300 train
+vobcdlawhi 1 300 val
+vobctvbqrb 1 300 val
+vobdelgtug 1 300 train
+voburxzcnz 1 300 train
+vocejnowbm 1 300 train
+vocjacgxzv 0 300 train
+voctsciikj 1 301 train
+vocvsaozqt 0 301 train
+voczbudwmt 1 300 train
+vodbqueiwq 1 300 train
+voddhhtvrt 1 300 train
+vodfsbxdtf 1 300 val
+vodftzcdfa 1 300 train
+vodgksbhef 1 301 train
+vodhqqrjjo 1 300 train
+vodkcuylye 1 300 train
+vodmdhbkjh 1 300 train
+vodqladhoa 0 300 train
+vodqyuluyr 1 300 train
+vodsjegctz 1 300 train
+vodvztthek 0 300 train
+vodxzvewum 1 300 train
+voebotgkqf 1 300 train
+voeivfysur 0 300 train
+voeqocrele 1 300 train
+voeqzzljlx 1 300 train
+voerdzrokj 1 300 train
+voetjerpmk 0 300 train
+voeyftxnik 0 239 train
+voezstmqje 1 300 train
+vofniuitsm 1 300 train
+vofnjqymjs 1 301 train
+vofqcpscue 0 300 train
+vofqnhcypj 1 300 val
+vofrdiwplv 1 300 train
+vofsdcsskk 0 300 train
+vogbpacvzn 1 298 train
+vogejocyvv 1 300 train
+vogfhcbroq 1 300 train
+voghvypasj 1 300 train
+vogigzjqav 1 300 train
+vogqrfzqfp 1 300 train
+vogrnkncog 1 167 train
+vogutjrcxk 1 300 val
+voguwzlpcv 1 241 train
+vogwbosucz 1 300 train
+vohguniokm 1 300 train
+vohsqhwudv 0 300 train
+vohwauspnx 0 300 val
+vohwtkvhwl 1 300 train
+vohxrvzaff 1 300 train
+vohyklzylo 1 300 val
+voiansjcwk 1 300 train
+voicfnnrxq 1 300 train
+voiulimrjw 1 299 val
+voivjdtfck 1 300 train
+voixykymat 1 300 train
+voiyeuhxkb 1 300 train
+voizaxdjnz 1 136 train
+vojcfgoxgc 1 300 train
+vojdhmduir 1 300 train
+vojlnasyae 1 300 val
+vojsghpebv 0 300 train
+vojtorajbj 0 300 train
+vokftvvbnj 1 300 val
+vokiezeddp 1 302 train
+vokkpekgav 0 300 train
+vokkqsaqrl 1 300 train
+vokpcroold 1 300 train
+vokqctlugf 1 300 train
+vokrpfjpeb 0 300 test
+vokuaozsxh 1 300 train
+vokunmhqum 0 300 val
+vokvyztkur 1 300 train
+volckblrmm 0 300 train
+voldoxhfto 1 300 train
+volftuvmlk 0 300 train
+volgvvvgyq 1 300 train
+volgwfjscu 1 302 train
+volsvlttlm 1 300 train
+volxbhigyt 0 300 train
+vomfihhrzi 1 300 train
+vomicublvr 1 300 train
+vomoibytvl 1 241 train
+vomqkscben 0 300 train
+vomvolijuh 1 301 train
+vomyajnckm 1 300 train
+vomyfdpeoj 1 300 train
+vomypszoet 1 300 val
+vomzaykdzx 1 136 train
+vonawupxtn 1 298 train
+vonibrwhlp 1 300 train
+vonjmenykq 1 300 train
+vonkuuyvps 1 301 val
+vonmfxajan 1 300 train
+vonuocawci 1 99 train
+vonvtfcldp 1 300 val
+vooeiaeqnw 1 300 train
+voogxlrser 1 300 train
+vooodvaacw 1 300 val
+voorpovevu 1 300 val
+voosmazlpk 0 300 train
+voospsfncu 1 300 train
+vootmsovby 1 300 train
+voovatsqet 0 300 train
+voovtxdhbl 1 300 train
+voovtydyve 1 300 val
+vooyswwqmd 1 300 train
+vopakbncpr 1 300 train
+vopetnkpdn 1 301 train
+vopklbyrfy 1 300 val
+vopnwhylpf 1 300 train
+vopokawkip 1 300 test
+vopykqmvwo 1 300 train
+voqbmgazju 1 300 train
+voqndnufbf 0 300 train
+voqpvihnvs 1 300 val
+voqtbyyjjr 1 300 train
+voqywsygaq 1 300 train
+voradwdsxz 1 301 train
+vorbdgudpv 1 300 train
+vorfsbpdqw 1 301 val
+vorpbcicjb 1 300 val
+vorpfgswwn 1 300 val
+vorsmesegs 1 301 train
+vorxskdvpy 1 300 train
+vosdfoltkt 1 300 train
+voskgwpdar 1 300 train
+vosnekcnek 1 301 val
+vostrioupy 1 300 train
+vosujftshh 1 300 train
+vosvixbeqf 1 300 train
+vosxsqboko 1 300 train
+votatpsfzo 1 300 train
+votdjutpwb 1 300 val
+votenscpph 1 300 val
+votjekacxt 1 300 train
+votkxbjnrn 0 300 train
+votnotgdim 1 300 train
+votqcuwpae 0 300 train
+votslfpuam 1 300 train
+votvjtjisw 1 300 train
+voucpidonq 0 300 val
+voudmumlov 1 300 test
+vouewvfkbc 1 300 train
+vougjwegcy 1 300 train
+vouhiqxlrk 0 300 train
+voulvvuqwz 1 300 train
+voupzrrfsc 1 300 train
+vourfvzupw 1 300 train
+vouyjulssc 0 300 train
+vouzdnonty 1 300 train
+vovsbprnqr 1 300 train
+vovyseeldv 1 300 train
+vovzjtbacs 1 300 val
+vowhvpnqdx 1 300 val
+vowijkcdlb 1 300 train
+vowjrrxkuf 1 300 val
+vowliadzhk 1 300 train
+vowmrrkrcr 1 300 train
+vownmzwfwv 0 136 train
+vowukmkgps 1 299 train
+voxcbaldki 1 300 train
+voxdumsqok 1 300 train
+voxgfqwqxm 1 300 train
+voxtvcqmeb 1 300 train
+voyldnbmbc 1 99 train
+voymstymfe 1 300 train
+voypmliwie 1 300 train
+voyrdgggwa 0 300 train
+voyvdizumd 0 300 train
+voyvplyvtb 1 301 val
+vozenudamz 1 300 train
+vozhxcagmw 1 301 train
+vozmlxqdks 1 302 train
+vozmpidcla 1 240 val
+voztvddhnf 1 298 train
+vozzxtdbuz 1 300 val
+vpacqxwuzz 1 300 train
+vpajkmacyx 1 301 train
+vpamslbafq 0 300 train
+vpamulkxzm 1 300 train
+vpaopizlcy 1 300 train
+vpavvgohtf 1 300 train
+vpbdnktryp 1 255 train
+vpbhiwdjmd 1 299 test
+vpbhuomkaa 1 300 train
+vpbllqdqlv 0 300 train
+vpbncllccw 1 300 train
+vpbnroqqrx 1 296 train
+vpbsqpnolc 1 300 val
+vpbwzqvbsa 1 300 train
+vpcwwzaxmn 1 300 train
+vpdgtarkiv 1 300 train
+vpdkhufhhw 1 300 train
+vpdlqtdpgd 1 300 train
+vpdpfywqxd 1 296 train
+vpdriyqcli 1 300 train
+vpecllokeh 1 300 train
+vpewshwial 1 147 train
+vpfjixuzkk 1 300 val
+vpfrnffbkt 1 300 train
+vpfryxbeqz 1 300 train
+vpgapvachm 0 300 train
+vpgjaoyvir 1 300 val
+vpgmadwntk 1 300 train
+vpgthafeta 1 300 train
+vphjnjhoub 1 301 val
+vphollgrel 1 300 train
+vphopflrsk 1 300 train
+vphpdpwgbl 1 83 train
+vphvagjvlh 1 300 test
+vphynfhigk 1 300 val
+vphzarsoea 1 300 val
+vpihjyjxun 1 300 train
+vpilorjjgd 1 300 train
+vpimodaeym 1 300 train
+vpiopzgibn 1 300 train
+vpiqmvxclb 0 300 val
+vpjaeglugx 1 300 val
+vpjauwwglt 1 298 train
+vpjccqjoks 1 300 train
+vpjdsjizeb 1 299 val
+vpjfmetsvn 1 300 test
+vpjixugvmm 1 300 train
+vpjnpmexys 1 300 train
+vpjqhvzmqx 1 300 train
+vpjqndsnmf 0 300 train
+vpjrlsnfzy 1 300 test
+vpjwhrkdkj 0 300 train
+vpjzbyrwmo 0 300 train
+vpkgloxpvo 1 300 train
+vpknpyreao 1 300 val
+vpkqjedfnn 1 300 train
+vpkqwghbbw 1 300 train
+vpksvxfrdj 1 300 val
+vplasjzbaj 1 300 train
+vpleqkttbh 1 300 train
+vplhlaegkr 1 300 train
+vpljytwlkq 1 297 train
+vplltjclog 1 300 test
+vplnauucuc 1 300 train
+vplriikihk 0 300 train
+vplyyujkof 1 300 train
+vpmatzrdwu 1 300 train
+vpmcpeoakl 1 300 test
+vpmsfzrzrp 1 300 train
+vpmvdtpzzt 1 300 train
+vpmwtrntrz 1 300 train
+vpmyeepbep 0 300 test
+vpncajagtf 1 300 val
+vpnctaldns 1 241 train
+vpndmdvowh 1 300 train
+vpnpulfcoh 1 300 train
+vpnshwxwwt 1 300 train
+vpnzmryjsb 1 300 val
+vpobphqohi 1 300 train
+vpofqqzhme 1 301 train
+vpolvvzwsw 1 300 train
+vpoowoqrdl 1 300 train
+vposulcbcg 1 298 train
+vpovscxqza 1 300 train
+vpovyjvoig 1 300 train
+vppimhczbl 1 300 train
+vppoqnrpzt 0 300 train
+vppsyhhxes 1 300 train
+vppucqymyx 1 300 train
+vppuvbgjzp 1 300 train
+vppzcozzwf 1 299 val
+vpqazxvdno 1 300 train
+vpqlpcnscp 0 300 train
+vpqlqaryds 1 300 val
+vpqsnrsjlw 0 300 train
+vpqsolhamg 0 300 train
+vpqzrrqkji 1 300 train
+vprbbqfhie 1 300 train
+vprblapbbe 1 300 train
+vpreqrrdjs 1 300 train
+vprhanjumg 1 300 train
+vprogharta 0 300 train
+vprrnxtryn 1 300 train
+vpruqexaop 0 300 val
+vpsdzetywv 1 300 train
+vpsgvwjwxg 1 300 val
+vpskcoeyfw 1 241 train
+vpsngiunec 1 300 test
+vpsnlmzarx 1 300 val
+vpssuqupvi 1 300 train
+vpsxodalkn 1 300 val
+vpsyeajimn 1 300 test
+vpsyuggmff 1 300 train
+vptafloefm 1 300 train
+vptdxpdmyk 1 300 train
+vptetjxjyn 1 300 train
+vptrrrmhyb 0 300 train
+vptrvimiek 0 300 val
+vptukmzakw 1 300 train
+vptxwtqklm 1 300 train
+vpuemhkkyd 1 300 train
+vpuhginyam 1 300 train
+vpuhquxnzl 1 300 train
+vpunbhspjv 1 300 train
+vpunfnwmlq 1 300 train
+vpuxflgqqm 1 300 train
+vpuxqkpkra 1 300 val
+vpuynrreii 1 300 val
+vpveeyyzhz 1 300 train
+vpvgroamfj 1 300 train
+vpvtkvxuyu 1 300 val
+vpvuklgjyc 0 300 train
+vpvwyxgosb 1 300 val
+vpvzavgqrv 1 300 val
+vpwberkmsj 1 300 train
+vpwdbdgfiw 1 300 train
+vpwebrkiqc 1 300 train
+vpwejabivm 1 300 val
+vpweqxyrku 1 300 val
+vpwfvogpsu 1 300 train
+vpwhgbehbc 0 300 train
+vpwiniwmfs 1 300 train
+vpwklvgpvz 1 300 train
+vpwnqqtgdd 1 300 test
+vpwrwozmnn 1 300 train
+vpwscqjskp 1 301 train
+vpwznjbvor 1 301 train
+vpxfbcafux 1 298 train
+vpxisojgue 1 298 train
+vpxixoonll 1 300 val
+vpxkjisoqh 1 300 train
+vpyaedfoxn 1 300 val
+vpyfvwdcsr 1 301 val
+vpyfxjhgsm 1 300 train
+vpynbnxvoy 1 300 train
+vpysbzvfol 1 300 test
+vpysufofud 1 300 train
+vpyyigiofr 1 300 train
+vpzafynzyr 1 300 train
+vpzvuuizby 1 300 train
+vpzzqcsfdx 1 300 val
+vpzzsdlqyt 1 300 train
+vqabitwekg 1 300 train
+vqaenhshou 1 300 val
+vqaesghnol 1 300 train
+vqahmgujzv 1 300 train
+vqanoaxrtl 1 300 train
+vqaptjacdp 0 300 train
+vqarlbcqlc 1 300 train
+vqasxhblzt 0 300 val
+vqbacmbakt 1 300 train
+vqbbwvtywo 0 300 train
+vqbfgydwoi 1 300 train
+vqbhcspbxr 1 300 train
+vqbjqrrzib 1 300 train
+vqboqalgxf 0 300 train
+vqbrffjwbj 1 300 train
+vqbyrifcoq 1 300 train
+vqbyxeiuzk 1 300 train
+vqcavsssms 1 300 train
+vqcrhtrzwu 1 300 train
+vqcyzcxnvs 0 300 val
+vqdbxmolda 1 300 train
+vqddfauruv 1 300 train
+vqdekziptx 1 300 train
+vqdezmkeak 1 301 val
+vqdjsrcewp 1 300 train
+vqdjykszyw 1 301 val
+vqdqktsyvi 1 300 train
+vqegfnepqw 1 299 train
+vqeioemlxo 1 300 train
+vqelbvngnc 1 300 val
+vqelldkral 1 300 train
+vqenysfbme 1 301 train
+vqepawpzsk 1 300 train
+vqepunqaie 1 299 train
+vqetjpiqlf 1 300 train
+vqeuhuwzoh 0 300 train
+vqfjetdgxd 1 300 train
+vqfjgcrddh 1 300 train
+vqfknemjqo 1 240 val
+vqftbdaqgt 1 300 val
+vqfvfpvugs 1 300 train
+vqfztxqbml 1 299 train
+vqgcpztfzs 1 300 train
+vqgkxozajf 1 300 train
+vqgpksovpd 1 298 val
+vqgrmlzard 1 300 train
+vqgwwsoduw 1 299 test
+vqhbsxcpid 1 300 train
+vqhnrkaedq 1 300 train
+vqhpgdkvzv 0 300 train
+vqhygrhtcw 1 300 val
+vqibhetnwa 0 300 train
+vqijtaxplt 0 300 train
+vqilaqgack 0 300 train
+vqiwjruuqc 1 300 val
+vqjhgvkqcz 1 300 val
+vqjibmcsdp 1 300 train
+vqjiegizzn 0 300 train
+vqjjrfszsx 1 302 val
+vqjlmpdhge 0 299 train
+vqjsjlemfj 1 300 train
+vqjukqdnyj 1 298 train
+vqjvtgaaqb 0 300 train
+vqkdmyxdmh 1 300 train
+vqkhhaktkq 1 300 val
+vqkjosgfte 1 300 train
+vqkkrgizdh 1 298 train
+vqkoocqjvx 1 300 val
+vqktsvqfdj 0 300 train
+vqkuyiuced 1 300 train
+vqkvomtoip 1 300 train
+vqkxybvvdt 1 300 val
+vqkyjfjkat 1 300 val
+vqlpfhugfe 1 300 train
+vqlrjxbxwn 1 300 val
+vqltkitmdb 1 298 train
+vqluhvsvvc 1 241 train
+vqlvevgyfx 0 300 train
+vqlvvympeb 1 288 train
+vqlyxnkprs 1 300 train
+vqmhjqdrww 1 300 train
+vqmjysskug 1 300 train
+vqmnaqdrtu 1 301 train
+vqnalrcskp 0 300 train
+vqnbjxudpp 1 300 val
+vqncfmywjb 1 300 train
+vqnemhhyqj 1 301 train
+vqnfiywvps 1 300 train
+vqnkveciyx 1 300 train
+vqnocyqksq 0 300 val
+vqnopxghew 1 300 train
+vqnsrcmsjc 1 300 train
+vqnzqbqypp 1 300 train
+vqocwkpftq 1 300 train
+vqodjqmqto 1 300 train
+vqoffrnzmz 1 300 val
+vqojdgrvvr 1 300 train
+vqoldieemq 1 300 train
+vqomcklsyn 1 300 train
+vqonjzhnad 0 300 val
+vqouplerye 0 300 train
+vqowmxhhdd 1 300 train
+vqoxhdrwsx 1 300 train
+vqoyxovpve 1 301 val
+vqpaotdttq 1 300 train
+vqpbpqvyuj 0 300 train
+vqplthnttn 0 300 train
+vqpppktecq 1 300 val
+vqpruhegck 1 300 train
+vqqcdwpgyk 1 300 train
+vqqibukdgb 0 300 train
+vqqqcjoscl 1 300 train
+vqqvveifjn 1 300 train
+vqqwbdyxhp 1 300 val
+vqqzrfagay 1 300 train
+vqrbczlrgo 1 300 train
+vqrsnqwezt 0 300 train
+vqruoluamf 1 300 train
+vqrvgctzdi 0 300 train
+vqseehupzh 1 300 train
+vqsehstdfy 0 300 train
+vqserlbytb 1 300 train
+vqsgtapaup 1 300 val
+vqslzijrwb 1 299 train
+vqspsdkblb 0 300 train
+vqsuxzauzw 1 300 val
+vqsxhswhdz 1 301 val
+vqtatkpbxi 0 300 train
+vqtazlcnfc 1 300 train
+vqtbpwvcqj 0 300 train
+vqtidfguyf 1 300 train
+vqtjnmbjyk 0 300 val
+vqtpvljpmu 0 300 val
+vqtspwkgwe 1 300 train
+vqtuvahlpw 1 300 train
+vqtyawibvn 0 300 train
+vqtykyuzqw 0 300 train
+vqucjkjpes 1 300 val
+vqukicfflg 1 300 val
+vqulyuhgdo 1 300 train
+vqurloftbq 1 301 train
+vqurmqzmex 1 300 train
+vquurvkimn 1 300 val
+vquuylimyj 1 300 train
+vquxvdlcpb 1 300 train
+vquyobyugb 1 300 train
+vqvamfsdla 1 300 train
+vqvdkpgunw 1 300 train
+vqvhpbslon 1 300 val
+vqvisduclj 1 301 train
+vqvkwsipfl 1 298 train
+vqvkxnleku 1 300 test
+vqvmlwhabu 1 300 test
+vqvpqosovt 0 300 train
+vqvqmnomhv 1 300 train
+vqvqoxcjiv 1 300 train
+vqvvlfslej 1 301 val
+vqvvtoakps 1 241 train
+vqvvuieuie 1 300 train
+vqvxsedbiw 1 300 train
+vqwavqlbxr 1 300 train
+vqwawjrbjf 1 300 train
+vqwbavjvqd 1 301 val
+vqwemmgbqx 1 300 train
+vqwfgoiqen 1 300 val
+vqwkmjorkj 1 300 test
+vqwlakkkkm 1 301 val
+vqwouqysgt 0 298 train
+vqwvvhxzdq 1 300 train
+vqxgubkkuu 1 300 train
+vqxmksylit 1 302 train
+vqxpkfxwcx 1 300 val
+vqxrjplroe 1 300 train
+vqxrpdyiii 1 299 train
+vqyakldsay 1 301 train
+vqybdfadtl 0 300 train
+vqykxuffve 0 300 train
+vqynllghpf 1 288 train
+vqyvotfkix 1 300 train
+vqywmxftdc 1 301 train
+vqyxfytddc 1 300 train
+vqyyykohlo 1 300 train
+vqyzasadxu 1 300 train
+vqzffjrqkt 1 300 val
+vqzibtrssb 1 300 train
+vqzimdprvg 1 300 train
+vqzurmckor 1 301 train
+vqzwsgbqgt 1 300 train
+vrakgwxtlm 0 600 train
+vrakleyxek 1 299 train
+vramlofpey 1 300 train
+vrapfndadu 1 300 train
+vrbgrbfnpr 1 241 train
+vrbpfalcjh 1 300 train
+vrbvrxdfmz 0 300 train
+vrbxcjujiz 1 302 train
+vrbzstiqjp 1 300 val
+vrcdeqaomc 1 300 val
+vrceadqnhq 1 300 test
+vrcgehbfqu 1 300 val
+vrcoqdypin 1 300 val
+vrctkqjbqu 1 300 train
+vrcucenlrh 1 300 val
+vrcwlpipir 0 300 train
+vrdclbckkp 1 300 val
+vrdilrbxqj 1 299 val
+vrdkygymis 1 241 train
+vrdlaeqzuo 1 302 train
+vrdsuhuvrf 1 299 val
+vrdugvoufo 0 300 train
+vrduuogkrs 1 297 train
+vrealryztp 1 249 train
+vregbpiqgb 1 301 val
+vreglunjau 1 300 train
+vreolbyxae 1 300 train
+vreyfjnixd 1 301 train
+vrezdvvuab 1 299 test
+vrfdwhejrq 1 300 val
+vrffapgmja 0 300 val
+vrfgknkmqz 1 300 train
+vrfkulnqzc 1 300 train
+vrfmupvimm 1 300 train
+vrfqrdihjc 1 300 train
+vrfufmkpgs 1 241 train
+vrgitaorgx 1 300 val
+vrgkrbrmel 1 300 train
+vrgqcqlqvi 1 300 train
+vrgubwmtyo 1 300 test
+vrguefuwqk 1 300 train
+vrhcrszgoi 1 300 val
+vrhjgajenm 1 301 train
+vrhqhhpwgz 1 300 train
+vrhzmfinwl 0 300 train
+vricufjwgv 0 300 train
+vrieljpngv 0 300 train
+vrihpmcikh 0 300 train
+vriivjhzpk 1 300 test
+vrimykzxeg 0 300 train
+vrisbopsgt 1 300 train
+vrjcphirxn 1 300 train
+vrjdoxkgmv 1 300 train
+vrjiouzxmp 1 299 val
+vrjlwsfexm 1 300 val
+vrjrxtofbx 0 300 val
+vrjwsnmgef 1 300 train
+vrjxdcmosw 1 300 val
+vrjyzhzktp 1 300 train
+vrkajpyygi 1 300 train
+vrkcffbthe 1 300 val
+vrkjaeqbsb 1 300 val
+vrkyslrkgy 1 300 train
+vrlfrowzcu 1 300 train
+vrlnyzgiav 1 241 train
+vrlqdxnayj 1 300 train
+vrlrtwlwqy 0 300 train
+vrlubyeorc 1 300 train
+vrlumjhmbk 0 300 train
+vrlunwwcrw 1 300 train
+vrlwkywnia 1 300 train
+vrmcmwaejc 1 300 train
+vrmirrirnl 1 300 train
+vrmjuimkvy 1 300 train
+vrmopglski 1 300 train
+vrmpyicsoa 1 300 train
+vrmrsfclaa 1 300 val
+vrmsbupuix 0 300 train
+vrmwdjeqkx 1 301 train
+vrmyhxztyd 0 300 train
+vrnbiwsmfk 1 300 val
+vrndtmconm 1 300 train
+vrniyyreuo 1 300 train
+vrnmcvimyt 1 300 train
+vrnndletfk 1 298 train
+vrnovxueit 0 300 train
+vrnznvmwon 1 300 train
+vrobbpvhhz 1 300 train
+vrohklbhbk 1 300 train
+vrovjdzggn 1 300 val
+vrowrcgjvo 0 300 train
+vroyiyohzb 1 300 train
+vrpaukzvai 0 300 train
+vrpfkvjckn 1 300 train
+vrplmmuuti 1 300 train
+vrpltwbshm 1 300 train
+vrpmfsdoot 1 300 train
+vrprflgvys 1 300 train
+vrptbmncwx 1 300 train
+vrptcabnxy 1 300 train
+vrpttrerbb 1 300 train
+vrpusszzdz 1 300 train
+vrpwrascfh 0 300 train
+vrpyzcuabm 1 300 val
+vrpzlampjd 1 300 val
+vrqcrvghrh 1 300 val
+vrqfktvxjm 0 300 train
+vrqjttlnuo 0 300 train
+vrqljnmysb 1 301 train
+vrqlrttwap 0 300 val
+vrqnseymxf 1 300 train
+vrqnyqqxfa 0 300 train
+vrqqklluql 0 300 train
+vrqressbnl 1 300 train
+vrqxebsspf 1 300 train
+vrqxknqpwv 1 300 train
+vrrdzohizm 1 300 train
+vrreokjsvi 1 300 train
+vrrjeqjmhx 1 300 train
+vrrsgrotys 1 300 train
+vrrtdmetws 1 300 train
+vrrvajfayp 1 300 train
+vrrzojetip 1 300 train
+vrrzpasggs 1 300 val
+vrsdljflug 0 300 train
+vrseszosch 1 300 val
+vrsfvjfcsn 1 300 train
+vrsinxahfh 0 300 train
+vrtdiwytyc 1 300 val
+vrtkfktkys 1 300 val
+vrtlsldeun 1 300 train
+vrtpfdejdq 0 300 val
+vrtrvkqfio 1 300 test
+vrtymxriej 1 300 val
+vrugzgbxbq 1 300 train
+vrukrernsn 1 300 train
+vruwrnwhah 1 300 train
+vruzqufwfi 1 300 val
+vrvbhsusyp 1 300 train
+vrvcdydasb 1 300 train
+vrvfgartzj 1 300 train
+vrvvplwuyg 1 300 train
+vrwfzgzruv 0 300 train
+vrwlzlvyxz 1 300 train
+vrwpihsuwj 1 300 train
+vrwqqccgmm 1 300 val
+vrwtatnwxk 1 300 val
+vrxfhcwwds 0 300 train
+vrxiifcnhg 1 300 train
+vrxmxturxg 1 300 train
+vrxntwvbvd 1 300 train
+vrxoikazxg 1 300 train
+vrxpfsfjsh 1 300 train
+vrxrtdkvjd 1 300 train
+vrxujlfbtp 1 300 val
+vrxvihwxea 1 300 train
+vryfsscqhy 0 300 train
+vrygfsxghl 0 300 train
+vryjwtzaus 1 300 train
+vrykuyazcz 1 300 train
+vrykylnafv 1 300 train
+vryqboviuu 1 300 val
+vryswxhujz 1 300 train
+vryvipqjni 1 300 train
+vrywrqixcf 1 300 val
+vrzbmrqubm 1 299 train
+vrzcdynbco 0 300 val
+vrzderrtfe 1 300 train
+vrzjuypurl 1 300 train
+vrznylvihm 1 300 train
+vrzpxnryrm 0 300 val
+vrzrdizpin 1 300 train
+vsafvjbumm 1 300 train
+vsaiqjxwfd 1 300 train
+vsalqrqyqr 1 301 val
+vsaxywrwwh 1 300 train
+vsbaxfpvdz 1 300 train
+vsbgrmtllm 1 300 train
+vsbifxfcjq 1 300 val
+vsbjbtcehl 1 300 val
+vsbobpehed 0 300 train
+vsbocnyxgr 1 300 train
+vsbrghzshm 0 301 train
+vscdnxseiw 1 300 val
+vscextmnhq 1 298 val
+vsclbzcxtd 1 300 val
+vsclpmjkjf 1 298 train
+vscvmqqjvy 1 300 train
+vscwgglzcf 1 300 val
+vscxlcdyoz 1 300 train
+vsdhpllvim 0 300 train
+vsdmydwkoi 0 300 train
+vsdqalnnpc 1 300 train
+vsdvqedwtp 1 300 train
+vsdyuwgkrz 1 300 train
+vseacuakup 1 241 train
+vseinenudj 1 300 train
+vsekvcewgw 1 300 train
+vseqwffxlg 1 300 val
+vsfctxhhkk 1 300 train
+vsfdnflqag 1 300 train
+vsfetmcnjj 1 300 train
+vsfhbxmkzn 0 300 train
+vsfqsxcdgi 1 300 train
+vsfswpfuqi 1 300 train
+vsgcpqfcoc 0 300 train
+vsgilobsjz 0 300 train
+vsgqcnycbe 1 300 train
+vsgqeehgad 1 300 train
+vsgqxthwwn 1 300 train
+vsgueeisof 1 300 train
+vsgzuqdavx 1 301 train
+vshavmtpst 0 300 train
+vshhiqgozo 1 300 train
+vshhodcyqu 1 300 train
+vshodwskha 1 300 val
+vshqkegxtd 1 300 train
+vshrujcytg 1 300 val
+vsiggkezez 0 300 train
+vsihnsoqwv 1 300 train
+vsijscstxy 1 241 train
+vsimocefjt 1 300 train
+vsimoenzie 1 300 train
+vsinqiaizy 0 300 train
+vsiqfnwpqr 1 300 train
+vsissslamo 1 300 train
+vsixkzehvf 1 298 train
+vsjeostabc 1 300 train
+vsjhvwqkxq 0 301 train
+vsjnsoptvq 0 300 train
+vsjtblqhkd 1 300 test
+vsjunynnqo 1 301 train
+vsjyeedhkq 1 296 val
+vskcpmupnt 0 300 train
+vsktgvihwz 1 300 train
+vskyakrspa 1 300 train
+vsladlbjus 1 300 train
+vslgyuzexf 1 300 val
+vsljugniny 1 299 train
+vsljxluebp 1 300 train
+vslkgqoabj 0 301 train
+vslmohcgrs 1 300 train
+vslnmavuek 0 300 train
+vslqeqyzee 0 301 val
+vslrxyvjcg 1 300 val
+vslxlaujnq 1 300 train
+vslycbvqzz 1 299 val
+vslzefizav 1 193 train
+vsmadeuczx 1 300 test
+vsmgdvhvtc 1 299 train
+vsmlvzpknv 1 299 test
+vsmrjonkjp 1 300 train
+vsmumdtqwf 0 301 train
+vsmyqhtxcp 1 300 train
+vsnbhgocuj 1 300 train
+vsndypqfur 1 300 val
+vsnjcgsrlk 0 300 train
+vsnjowpxev 1 298 train
+vsnmkqynju 1 300 train
+vsnnbyxjkg 0 300 val
+vsnnqycyeh 1 300 val
+vsogojyczb 1 300 train
+vsohijftmr 1 300 train
+vsoivwtzkm 1 300 train
+vsoptojyky 1 300 train
+vsospdopga 1 299 val
+vsosyqyvva 1 300 val
+vsozyqslhl 1 241 train
+vspaahwtew 1 300 val
+vspmuneolz 1 300 train
+vspryyodwa 1 300 train
+vspsvduzvv 1 300 train
+vsptifjjeg 1 301 train
+vsqafmmfbl 0 300 train
+vsqmaabapw 1 300 train
+vsqmqlbdgc 1 300 train
+vsqnddxguh 1 300 train
+vsqrgosrdt 1 300 train
+vsqtemnmfk 0 241 train
+vsqzbxwapk 1 300 train
+vsreebjsfs 0 300 train
+vsrksgfjga 1 300 train
+vsrlqdltnf 1 297 train
+vsrmgtcogv 1 300 train
+vsrpxqdzcs 1 299 train
+vsrqgwgfft 1 300 train
+vssasohihx 1 299 test
+vsseefgrpz 1 301 train
+vsskmwwzxg 0 300 train
+vsslkksnic 1 300 train
+vsslsumbrp 1 300 val
+vssmlqoiti 0 299 test
+vssmqqnkvx 1 300 train
+vsspxiiaxh 1 300 train
+vssqtdvkri 1 300 train
+vssrozcuwh 1 297 train
+vsssgidofv 1 300 val
+vsssjdydkf 1 300 train
+vssxdcswdu 1 300 train
+vssxkwwjvz 1 300 val
+vssykrqdbi 1 300 train
+vstajyctuh 1 300 train
+vstgtxicpy 1 300 train
+vstlputdrj 1 300 val
+vstmxsekmm 1 300 val
+vstpccsedy 1 300 train
+vstwdlylwj 1 300 train
+vsubnrrizh 0 300 train
+vsulopkjvr 0 300 train
+vsumphqlvu 1 300 train
+vsunyloqes 0 300 val
+vsusjzdihc 1 300 train
+vsuunmdexy 1 300 train
+vsvazkoszd 1 300 train
+vsvbwqviud 1 300 train
+vsvehebmtp 1 300 train
+vsvhtjrolr 1 300 train
+vsvmcmeiuu 1 300 train
+vsvwrocgzc 0 300 val
+vswceirobb 1 300 train
+vswguxmhup 1 300 train
+vswoxprwgl 1 300 train
+vswpbluebi 1 300 train
+vswqwdkyri 0 300 train
+vswsbwuwet 1 300 train
+vswwwdtwwf 1 299 val
+vsxaadduzr 1 300 train
+vsxahxsefv 1 300 train
+vsxaqjbeai 1 300 train
+vsxatyavqt 1 296 train
+vsxbaaovqj 1 300 train
+vsxlwpqzid 1 300 train
+vsxnlwhyrm 1 300 val
+vsxthyzjid 1 300 train
+vsxtsqvphy 1 300 train
+vsxuvpwqmm 1 300 test
+vsxvakbabp 1 297 train
+vsxzsogxsy 1 300 train
+vsydalpuyy 0 300 train
+vsyjjjeayt 1 300 train
+vsyokaxish 0 300 train
+vszavakmte 1 298 train
+vszciigspa 1 300 train
+vszibbcfgn 0 300 train
+vszjpxysie 1 299 test
+vszkqbndtl 0 300 train
+vszoyhcrdd 1 300 val
+vszwxixvne 1 300 train
+vtaagrckne 1 298 train
+vtaaptnkgf 1 300 train
+vtadejjbca 1 298 val
+vtajmvjasj 1 301 train
+vtavzbqvij 1 300 val
+vtaztagukf 0 300 train
+vtbaozyqyy 1 300 train
+vtbcptkdfl 1 300 train
+vtbotdwkbd 0 300 train
+vtbrpehlme 1 300 train
+vtbtthuegw 1 300 train
+vtcbxtsfsb 1 298 train
+vtccwzpgqu 1 301 train
+vtcixvcort 1 300 train
+vtcmfwcnmk 1 300 train
+vtcrsoekze 0 300 train
+vtcswwjgrq 1 300 train
+vtcuiifcue 1 241 train
+vtcwuamqiv 1 249 train
+vtcytrmoko 1 300 train
+vtdjnzsllb 1 300 train
+vtdmwrifoi 1 300 train
+vtdneioyyf 1 249 train
+vtdnqnswlb 1 301 val
+vtducodcmq 1 300 train
+vtdzngxprx 1 298 train
+vtdzocykmt 1 300 train
+vtebggnabq 1 300 train
+vteembmrne 1 301 train
+vtegoznzhb 1 298 val
+vtemhptawm 0 300 train
+vterzvpybi 1 300 train
+vtetstuphj 1 300 train
+vtfcqxlmze 1 300 train
+vtfhwznaid 1 300 train
+vtfpbtmgfh 1 300 test
+vtfwoqcgps 1 300 train
+vtfxzpmklo 1 300 train
+vtfydimoqg 1 300 val
+vtfzsqhfxt 0 300 train
+vtgitjlexc 0 301 train
+vtgwrdpjhu 1 300 train
+vtgxjwotlk 1 300 train
+vtgzexvhgc 1 300 train
+vtgzzhtqjl 0 300 train
+vthdvvxfpz 1 300 train
+vthdwxbovs 1 300 train
+vthlyqjjrz 1 300 train
+vthmrpqbxw 1 300 train
+vthnsquxwo 1 300 train
+vthwsdavvc 1 300 train
+vtielpponk 1 300 train
+vtiqlaagxx 1 300 train
+vtiqruyelb 0 300 val
+vtiumgfxtf 1 300 train
+vtiunangyp 1 298 train
+vtiwviltlz 0 300 train
+vtizaqifgb 1 300 val
+vtjedxnlhl 0 300 train
+vtjidnmwxh 1 300 train
+vtjktoekbp 1 301 train
+vtjlnsuflu 1 300 train
+vtjnvqabuc 0 300 train
+vtjrxeflyq 1 299 train
+vtjsuczrwt 0 300 train
+vtjtltcdfu 1 300 train
+vtjxvolovc 1 299 val
+vtjyflicoa 1 300 val
+vtjzpwvsyh 1 300 val
+vtkbjpfaoo 1 300 train
+vtkipkdnni 1 300 train
+vtktbshvvp 1 300 train
+vtktcmfqas 0 300 train
+vtkyppsmdx 0 300 train
+vtkzflamwy 1 300 train
+vtlbiwkann 0 300 train
+vtlhboikcp 1 300 train
+vtlhyrhdgl 1 300 val
+vtliuhlgiq 1 300 train
+vtloaxuxkk 1 300 train
+vtlrqjihtt 1 300 train
+vtlxnjhdvs 1 300 test
+vtlylvzfgc 1 299 test
+vtmcqtdsjs 1 300 train
+vtmdbbkqzp 1 300 train
+vtmermgffv 1 301 train
+vtmhtwczuc 1 300 train
+vtmoswnygl 1 300 val
+vtmsastagy 1 300 train
+vtmtsvyrzi 1 299 val
+vtmuoncdgf 1 300 train
+vtmztrtrdy 1 300 train
+vtnpnpldtp 1 300 train
+vtnuixsryw 1 300 train
+vtoabwnjsi 1 301 train
+vtocctjaqr 1 300 train
+vtofrusgdu 1 240 train
+vtogjcuzol 1 300 train
+vtokbstwzs 1 300 train
+vtonnkzcnd 1 300 train
+vtoorsnjeo 1 300 train
+vtoqrpsuox 1 300 train
+vtoznuozon 1 300 val
+vtpccmtlmt 0 300 train
+vtplgvkyxe 1 300 val
+vtpnnqlucv 1 300 train
+vtpnqkjgvs 1 300 val
+vtpttqxrop 1 300 train
+vtpvmpboxj 1 300 train
+vtpyezclns 1 167 train
+vtqcryaaig 1 300 train
+vtqemjfndr 1 300 train
+vtqfqmnrly 1 300 train
+vtqgoapfob 1 300 val
+vtqkvlrvbg 1 300 val
+vtqlkmvbid 0 300 train
+vtqpbcsacg 1 301 train
+vtqvymmukq 1 300 val
+vtrbdyslse 1 300 train
+vtrhywcnuo 1 300 val
+vtrjwnenjg 1 300 train
+vtrkwvlnrj 0 300 val
+vtrlyhhghn 1 300 val
+vtrsobbvze 1 300 train
+vtryxxkwsg 1 300 train
+vtsbizlvxg 1 300 test
+vtsmhhrfkk 1 300 val
+vtsmtejvmj 1 299 val
+vtsqppwbag 1 300 train
+vtsxkvlwnq 1 301 val
+vttclphuxu 0 300 train
+vttdokvnjo 1 300 train
+vttlyxprcg 1 300 train
+vttnackjht 0 300 train
+vttniubefn 1 300 train
+vttqqfrkxh 1 300 train
+vttqukwjqr 1 300 train
+vttujrwncg 1 300 train
+vttzubhiyi 0 300 train
+vtuamfqbzv 1 269 train
+vtueuttbrx 1 300 val
+vtugswwthj 1 300 val
+vtuhfbczni 1 300 train
+vtumllvkkq 1 300 val
+vtunvalyji 0 300 test
+vtvgwshklp 1 300 train
+vtvtmhfcys 1 300 train
+vtwbhvjsyx 1 301 train
+vtwcgcpekm 1 300 train
+vtwetysisy 1 300 train
+vtwkqhhnuz 1 300 val
+vtwmetnzax 0 300 train
+vtwngbsosg 0 299 val
+vtwobfpyxv 1 300 train
+vtwpgsywis 1 300 val
+vtwvmuuyfq 1 300 train
+vtwwlrpmit 1 300 train
+vtwxyegbsh 1 300 train
+vtxbbmeibh 1 300 val
+vtxdxmivyz 1 300 train
+vtxirhynyc 1 300 test
+vtxnuxiatg 1 300 train
+vtxypxsujj 1 241 train
+vtykckvhew 1 298 train
+vtynsinghq 1 298 train
+vtypbizkms 1 300 train
+vtyrercqgm 1 300 train
+vtzaoknadv 1 300 val
+vtzgnlpsgq 1 300 val
+vtzjsavyrw 0 300 train
+vtzlfurays 1 300 test
+vtzlptckxt 1 300 train
+vtznvjlyck 0 300 val
+vtzphtgsst 1 300 train
+vtzpigtqqo 1 300 train
+vtzzponycq 1 301 train
+vtzzqcftzj 1 300 train
+vuaacewavn 1 300 val
+vuabbfjvgd 1 300 val
+vuaduxjulp 1 240 val
+vuaoqsjxzh 1 298 train
+vuaqmthmrb 0 300 train
+vuattmmuuo 1 298 train
+vuawadtxbq 1 300 train
+vubblsefya 1 298 train
+vubcopfzqw 1 300 train
+vubdgyzsff 1 300 train
+vubjvkqmsu 1 301 train
+vubxbikjix 1 300 train
+vubxqxrllg 0 300 train
+vuccfkcimf 0 300 train
+vucchjvssd 0 240 train
+vucfiqavvc 1 301 train
+vuchwlofnr 1 301 train
+vuclirejpq 1 300 train
+vucozqkhiq 1 300 train
+vucwoqpqph 1 300 train
+vudaqhzqav 1 300 train
+vudbjgockf 0 300 train
+vudekhgmvp 1 300 train
+vudhvbgulb 1 300 val
+vudionnslj 1 300 val
+vudqhjbnse 1 136 train
+vudrnaqdbv 0 300 train
+vudsikyynk 1 300 train
+vudsinfgoq 1 300 train
+vudstovrck 0 300 train
+vuebhaxmug 1 300 train
+vuebtkngto 1 300 train
+vuefnyxplb 0 300 train
+vuegbjpvfj 1 301 train
+vueqdpnvln 1 300 val
+vuexkmmwzw 1 300 val
+vufazwmlsk 1 300 train
+vuffzqlgif 1 297 train
+vufoucpoxb 0 300 val
+vufppssjeo 1 300 val
+vufqqfokoy 1 300 train
+vufrzfmdit 1 300 train
+vugbaeziku 1 299 train
+vugeajjdpd 1 193 train
+vugjrmqphs 0 300 train
+vuglqfigbk 1 300 train
+vugmpifhkk 1 300 train
+vugswbibpa 1 300 train
+vugzcpitef 1 297 train
+vuhecbwnsr 1 300 train
+vuhkblgcll 1 300 train
+vuhkcriudb 0 300 train
+vuhmlocovs 1 300 train
+vuhpautpgu 1 300 train
+vuhwxulscn 0 300 train
+vuibbrrcgi 1 300 val
+vuibgvxaue 1 300 train
+vuicxedsgn 1 300 val
+vuiewcjhke 1 300 val
+vuihguvkdd 0 241 train
+vuikiiwjvt 0 300 train
+vuilyelkeg 1 300 val
+vuirbazsqr 1 300 train
+vuixqctwxz 0 301 train
+vujbyxtiio 1 301 train
+vujetqovdf 1 300 train
+vujmaijlrs 0 300 train
+vujvqcnbol 0 300 train
+vukgptwnqb 1 300 train
+vukkjqpiib 1 300 train
+vukogyramq 1 300 val
+vukoronzan 1 300 train
+vulcrsidql 0 300 train
+vulfhomwor 1 300 train
+vulirjzpza 1 300 train
+vulnpvolwv 1 300 val
+vulukprfvv 1 300 train
+vulzmdcgtr 1 300 train
+vumapsooel 0 299 val
+vumghnalez 1 300 train
+vumygyguna 1 300 train
+vunqlcyduq 1 298 train
+vunufofchc 1 300 train
+vunykhhwwo 1 300 train
+vunzthkkza 1 300 train
+vuodnhkifu 1 300 train
+vuodqfjivx 1 300 train
+vuofhivyfs 0 300 train
+vuofiadkqz 1 300 train
+vuoifjcubp 1 301 val
+vuonuxzhhb 1 299 test
+vuoovoksff 1 300 train
+vuoscfbycd 1 300 train
+vuouneapoh 1 300 train
+vuouumoskm 1 300 train
+vuoyefxvgw 1 300 train
+vuozicahos 1 300 val
+vupagtbqex 1 300 train
+vupfjiikym 1 297 train
+vuphbongzl 1 300 train
+vupkntqxrs 1 601 train
+vupmukvvxd 0 300 train
+vuppesuyal 1 300 train
+vupylnrzcs 1 300 train
+vupzqrlwjt 1 300 train
+vuqbgydugv 1 300 train
+vuqjikyjjv 1 300 train
+vuqjzziyyq 0 300 train
+vuqqwkwstu 1 300 train
+vuqtxyyjeb 1 297 val
+vuriadksqf 1 300 train
+vurjckblge 1 300 test
+vuropgffsi 1 300 train
+vurupbnwev 1 300 train
+vusdgqwjfg 1 301 train
+vusdykurfb 1 300 train
+vusfisygkz 1 300 train
+vusfsrzfcq 1 300 train
+vuskhfraba 1 301 train
+vusmxskfmn 1 300 train
+vusowhcbig 1 300 train
+vusvzjmgli 0 301 train
+vuszdhieam 1 300 train
+vutdcljddj 1 300 train
+vutgjdgqjq 1 300 val
+vutkeimbhg 0 300 train
+vutkspfojq 0 300 train
+vutvmjptxa 1 300 val
+vutwmldavx 1 300 train
+vuuahhkfjr 1 147 train
+vuuevgbesz 1 300 train
+vuugqppvuh 1 300 train
+vuuhdynmzr 1 298 train
+vuuobcqzhx 1 300 train
+vuuoqsaayq 0 300 val
+vuuprnkdhb 1 300 train
+vuurxsxpky 1 300 train
+vuuszelxhn 0 300 train
+vuutkmjbdk 1 300 train
+vuuwqdriya 1 301 train
+vuuylvbmde 1 301 train
+vuvakikxia 0 300 train
+vuvaydlmta 0 300 train
+vuvkhebmuz 1 300 val
+vuvlxpffao 1 300 val
+vuvqigwfvc 1 300 train
+vuwfdrbxyo 1 300 train
+vuwpbnsdzk 1 300 train
+vuwrkxzrbi 1 300 train
+vuwvlclovq 1 300 val
+vuwwjfnhge 1 300 train
+vuwzrolalx 1 300 train
+vuwzxvxmdu 1 300 train
+vuxargmijm 1 300 train
+vuxbddnduj 1 300 train
+vuxfsebfrd 0 300 val
+vuxgouhsfn 1 300 train
+vuximwtznf 1 300 train
+vuxnvagsiu 1 299 train
+vuxpkpkkeq 1 301 train
+vuxqripkoh 1 300 train
+vuxrjngncf 1 300 test
+vuxtlecuwu 1 300 train
+vuxxjhjnqw 1 300 val
+vuyaffkrtu 1 300 val
+vuycazunhy 1 300 train
+vuycopandh 1 300 train
+vuyhdukbet 1 300 test
+vuykmumtpc 1 300 train
+vuypolrcfy 0 300 train
+vuzbfohkwg 1 299 val
+vuzerfenfz 1 300 train
+vuzgbspuag 1 300 train
+vuzhapfdrt 1 300 val
+vuzhlzrxrp 1 300 val
+vuzoqeinxf 1 301 train
+vuzswufcgd 1 300 train
+vuzththpuc 1 298 train
+vuzvgxazcz 1 300 train
+vuzxnahdcz 1 299 val
+vvacparacn 1 300 train
+vvapbnhbik 0 300 train
+vvaprewhzv 1 300 train
+vvbchpxynv 1 300 val
+vvbfrezoks 1 300 train
+vvbiouwczg 1 300 train
+vvbjqsdror 1 300 train
+vvbnwalnmf 1 300 val
+vvbqqekzwv 1 300 val
+vvbutldixv 1 300 train
+vvbwnfebrm 1 301 train
+vvcgeteqzs 1 301 train
+vvchwlnikj 1 300 train
+vvckdgmmiv 1 300 train
+vvclsrjaxc 1 300 train
+vvcnnaruns 1 298 train
+vvcoiixerm 1 300 train
+vvcqspsggq 0 300 train
+vvctalmtqm 1 300 train
+vvcvpgbpyw 1 300 train
+vvcwirayut 1 300 train
+vvcwuodyfd 1 300 val
+vvcyulxdtz 0 300 train
+vvcziumaqd 1 300 train
+vvdeiktfxo 1 300 train
+vvdisddtuy 1 300 val
+vvdjjapzsi 1 300 train
+vvdngbqkjt 0 300 train
+vvdpzwyhnu 1 300 train
+vvdwczpwal 1 300 train
+vvdwmzctwb 1 301 val
+vvdxmjouwe 1 299 val
+vvdypdckev 1 300 train
+vvdypfmupb 1 300 train
+vveahuaufk 1 300 train
+vvedflppli 1 301 train
+vvedlcdxgm 1 300 train
+vveoacswag 1 300 train
+vveomkcwyw 1 300 train
+vveqbxsiot 1 300 train
+vvernryjfh 1 300 train
+vvfakkchyo 1 300 train
+vvfdtgkxyx 1 300 train
+vvfeqzvzef 1 300 train
+vvfmkgoyqd 0 300 train
+vvfszaosiv 0 299 test
+vvfxgisjpr 1 300 train
+vvgbrorobc 1 300 train
+vvgiakdsml 1 301 val
+vvglfffbmx 0 300 train
+vvgnmlzcdl 1 300 train
+vvgvipiyeq 1 300 val
+vvgztmypol 1 300 train
+vvhbvxinbi 1 300 train
+vvhfvhrapc 1 300 train
+vvhhqjltxf 1 300 train
+vvhlkhoolb 1 300 train
+vvhmumccgq 1 300 train
+vvickrfcho 1 300 train
+vvifmkhwmc 1 241 train
+vvijplbibj 1 300 val
+vvimicetzg 1 300 train
+vvirdruilr 1 300 train
+vviskjmrcq 1 301 val
+vvispdjqxd 1 300 train
+vvisqkvlgb 1 299 test
+vvixicbzkx 1 300 val
+vvjdojdzpq 1 300 train
+vvjfajsxig 0 301 train
+vvjmzgrzmc 1 300 train
+vvjnasvzju 1 300 train
+vvjpanxhps 1 300 val
+vvkfmqwpcr 1 300 train
+vvkqhedpgs 0 300 train
+vvkrvxfvqp 1 294 train
+vvkszedttq 1 300 train
+vvkugmoobi 1 300 val
+vvkzbahdff 1 300 val
+vvlbjptiel 1 300 train
+vvldcncxda 1 300 test
+vvlnyeqnha 1 300 train
+vvlyrfyyep 1 301 train
+vvlztowpdn 1 300 train
+vvmapwxzqr 1 300 val
+vvmbmopiwq 1 300 train
+vvmlilrghl 1 300 train
+vvmmwytctp 1 300 val
+vvmnhezmjo 0 300 train
+vvmntqbqxb 1 301 train
+vvndnaibqb 1 241 train
+vvnesespxu 0 300 train
+vvnjrgunbe 1 300 train
+vvnjxfommn 1 300 train
+vvnkxfwsdv 1 302 train
+vvnoeunikl 1 300 train
+vvoroznqyj 1 301 train
+vvoxycalkx 1 300 train
+vvpbuedczu 1 300 train
+vvpekcopdc 1 300 train
+vvpolopgck 1 300 train
+vvppqwsgru 1 299 val
+vvpqqpjlwn 1 300 train
+vvpuhtpdks 1 300 train
+vvpwtduldi 1 300 train
+vvqqctjwvx 1 300 train
+vvqrrzigit 1 300 val
+vvqserbnug 0 300 train
+vvqtglzcep 0 300 train
+vvqvxheurg 1 300 train
+vvqxwknycq 1 300 train
+vvrehbgcfh 1 302 train
+vvrenbyuud 1 300 train
+vvriuacduz 1 300 train
+vvrkupqacj 1 299 val
+vvrlglaepq 0 301 train
+vvrnccgliz 1 300 train
+vvrntobole 1 300 train
+vvrpexirsx 0 300 train
+vvrrvggesp 1 301 train
+vvsbchnyjv 0 300 val
+vvsicmdyzq 1 300 train
+vvsmatlhfs 0 300 train
+vvsoymxnol 0 300 train
+vvtbwgpebl 1 300 train
+vvtcvjvkqx 1 299 test
+vvtgxgykww 1 300 train
+vvtmrxkglq 0 300 val
+vvttydsihy 0 300 train
+vvtuwnvkvr 1 300 val
+vvtvjutqzd 1 241 train
+vvtzkgipvb 0 300 train
+vvuchmbuhs 0 300 val
+vvufazrnmd 1 288 train
+vvukrfwpho 1 300 train
+vvuvjclthy 0 300 train
+vvvchefpra 1 299 train
+vvvergxjbm 0 300 train
+vvvhjggwuk 1 300 val
+vvvlfwgxqd 1 300 train
+vvvnxceiay 1 241 train
+vvvuorcvfv 1 300 val
+vvvwelfxjv 1 300 train
+vvvxdbdjvo 1 300 train
+vvvzdxgwnn 1 300 train
+vvvzsluzws 1 300 train
+vvwfbzriyg 1 147 train
+vvwiqcvllt 1 300 train
+vvwmasnqga 1 300 val
+vvwpzzlvcr 1 300 train
+vvwqzzfxpl 1 300 val
+vvwtaztxtm 1 300 val
+vvwuqslvnq 1 300 test
+vvwvhvprht 1 300 val
+vvxalogzol 1 300 train
+vvxiemmuzq 1 300 train
+vvxjsvabau 1 298 train
+vvxnfaqbot 1 300 train
+vvxpvxptlw 0 300 train
+vvxqhoqqhp 1 300 val
+vvygpvfiyd 0 300 train
+vvygrihsvj 1 300 train
+vvymilfgzk 1 300 val
+vvymqmeupz 1 300 train
+vvysgggofo 0 109 train
+vvysqtxmop 1 300 train
+vvyuathbkl 0 300 train
+vvyvdngdhy 1 300 train
+vvyvvbgtjk 1 300 train
+vvyxwlcaax 1 300 train
+vvzaojmnaz 1 300 train
+vvzdaceobh 1 300 train
+vvzdpacufq 1 300 train
+vvzefxbzqv 1 300 train
+vvzjubnynb 1 300 train
+vvzmcirvmr 1 300 test
+vvzpczcwlc 1 300 val
+vvzqhexrxg 1 300 val
+vvzssblzxh 1 300 val
+vvzsstbyrd 1 300 val
+vvzzgraotq 0 300 train
+vwabptueck 1 300 train
+vwabpywqrp 1 300 val
+vwaerqpjdm 1 299 val
+vwaitvzcry 1 300 train
+vwapfmxoyf 0 300 train
+vwavxcyykd 1 300 train
+vwbdlklsjn 0 300 train
+vwbfauqcgc 1 300 train
+vwbgilrgeg 1 300 train
+vwbjiaczia 1 300 train
+vwblwlwlme 1 300 train
+vwbrfvbexi 0 300 train
+vwbzhldrub 1 300 test
+vwcacyqmpy 0 300 train
+vwcdgwdecc 1 300 val
+vwcjxvdmar 1 300 train
+vwcqknrggt 1 300 train
+vwcxetxeqt 1 299 train
+vwdbfqebag 0 300 train
+vwdcowoxxj 1 300 train
+vwddtkosep 0 300 val
+vwdfscfyho 1 300 train
+vwdfxkftlj 1 300 val
+vwdptyvlhz 1 300 val
+vwdupokjyb 1 300 train
+vwdveepjhm 1 299 test
+vwdvpeuzwh 1 241 train
+vwebkwlxvq 1 300 train
+vweghoydea 1 300 train
+vwejghweuu 0 300 train
+vweptzevkl 1 300 train
+vweromsagz 1 300 train
+vwetsvmkdj 1 300 train
+vwezeiczkt 1 300 train
+vwfccelneb 1 300 train
+vwfcckqewi 1 300 train
+vwfrwfzwhz 0 300 val
+vwfryxjtge 1 300 train
+vwfysmfiem 1 300 train
+vwfyzbfsvg 1 300 train
+vwgeflwkrz 1 300 train
+vwgjdpxisr 1 300 train
+vwglehgkey 1 300 train
+vwgrapvvsc 1 300 train
+vwhabqknzz 1 298 train
+vwhairfgdx 1 300 train
+vwhbaibyfr 0 302 train
+vwhedvhhus 1 300 val
+vwhkslntta 1 300 val
+vwhmbabhdb 1 300 train
+vwhqxjyzsq 1 298 train
+vwhuhlhctt 0 300 train
+vwiaiiyjuk 1 301 train
+vwibhbmknq 1 300 train
+vwicinmobb 1 300 train
+vwifcinzzz 1 300 val
+vwigrbqwbf 1 300 train
+vwigtbeivy 0 300 val
+vwiidzlkdv 0 300 train
+vwikfwhgdp 1 241 train
+vwikrwipol 1 300 test
+vwisontldv 1 300 train
+vwivusrmbc 1 300 train
+vwixuzwcoa 1 299 val
+vwjefjjqrr 0 300 train
+vwjegddiex 1 300 train
+vwjgswwkjf 1 300 train
+vwjieoenck 1 301 train
+vwjyffunrb 0 300 train
+vwjzomdjhk 1 300 train
+vwkcsnempq 1 300 train
+vwkdvxemte 1 299 train
+vwkfkzznho 1 301 train
+vwkgjsyarh 1 300 val
+vwkhwedtfr 1 241 train
+vwkkmxdrcp 1 300 val
+vwklcqcpxt 1 300 train
+vwkpvbmdgw 1 300 train
+vwktthlqsh 1 300 test
+vwldcakscn 0 300 train
+vwldgzgfht 1 300 train
+vwldsdxacj 1 300 train
+vwlelxjgey 1 300 train
+vwlhtziexs 0 241 train
+vwlkjebhvw 1 300 val
+vwlkymmhrz 1 300 val
+vwlnfyjesf 1 300 val
+vwlsdwchkg 0 300 val
+vwluqyyhpi 1 300 train
+vwlwbovhxl 1 300 train
+vwlxlybbad 1 300 train
+vwmaaaldtm 0 300 val
+vwmcoxzqkq 0 300 train
+vwmiebtfmp 1 300 train
+vwmjyzyqhk 1 300 train
+vwmmbclwgq 1 300 train
+vwmocnbdbm 1 300 train
+vwmvqrdyld 1 300 train
+vwmxadohky 1 300 train
+vwnbgvgzfc 1 300 train
+vwnhxugzsd 1 300 val
+vwnkmflyei 1 300 train
+vwnuhvbnsq 1 300 train
+vwnwktghtt 1 296 val
+vwnwmxtvdr 1 300 train
+vwoblphxsc 1 300 train
+vwociiejya 1 300 train
+vwoewnnobr 1 300 train
+vwonnkchmm 1 300 train
+vwooqihnhr 0 300 val
+vwovockaja 1 300 train
+vwpeiuxppi 0 300 train
+vwpkatldup 1 300 train
+vwplooqyfe 1 299 train
+vwpphgpqma 0 300 val
+vwprneelzg 1 241 train
+vwpsbjkjyc 0 300 train
+vwpsspcsmh 1 300 train
+vwptpipolj 1 297 val
+vwpuszlhrb 0 300 train
+vwpvsrphdd 1 300 train
+vwpwtblyah 1 300 train
+vwqlucuqto 0 300 train
+vwqmrisuzw 1 300 train
+vwqrtxbwye 0 301 train
+vwqzxciroy 1 298 train
+vwrcgnwdzo 1 300 train
+vwrpmmkmve 1 299 val
+vwrrieyzck 0 300 train
+vwrsgjzxcq 1 300 train
+vwrwhjomzm 0 298 val
+vwrzymrrag 1 300 train
+vwscgbgyon 1 241 train
+vwsduaioeg 1 300 train
+vwshkghebv 1 300 train
+vwsjyodjug 1 300 train
+vwsmyedhpf 1 300 train
+vwsxbgnlwz 1 300 val
+vwszajywog 0 300 train
+vwtbrtvsxh 0 300 val
+vwtchwfzlw 1 300 train
+vwtjszznws 1 300 train
+vwtkssqkrk 1 300 train
+vwtoiqzwtt 1 300 train
+vwtvxhmjue 1 300 val
+vwtwjbrgbt 1 300 train
+vwtztxpljw 0 300 train
+vwuieifxqv 0 300 val
+vwutuckdhq 1 299 val
+vwuvultekp 1 300 train
+vwvaddvdhb 1 300 val
+vwvdanwrct 1 300 train
+vwvdlzniwp 1 300 train
+vwvhsswchr 1 300 train
+vwvkjzwyuz 1 239 train
+vwvpfimnbv 1 300 train
+vwvxaufpht 0 300 train
+vwwahrmrtz 1 299 val
+vwwazwjgqa 1 300 train
+vwwjarofqf 1 299 train
+vwwqmjqrmv 1 300 train
+vwwtibcpnq 0 300 val
+vwwyakakss 1 300 train
+vwxbtjppjl 1 300 train
+vwxednhlwz 1 300 test
+vwxevdsvdl 1 300 train
+vwxoezsjbx 1 300 train
+vwxoisiedz 1 300 train
+vwxrnscsaf 1 299 val
+vwxsnitxwe 1 300 train
+vwxuqxuyuk 0 300 train
+vwxxuqutbt 1 299 train
+vwxzbxwndy 0 300 train
+vwylkxlcav 1 300 val
+vwymogzbsw 1 301 train
+vwyodmstpu 1 300 val
+vwyyxvqkmj 1 300 val
+vwyzyhetxt 0 300 train
+vwzaditkns 1 300 train
+vwzccaufjx 0 300 train
+vwzhwjenhg 1 300 train
+vwzihtdkcp 0 300 val
+vwzjgwpxhx 1 300 val
+vwzoikecng 1 301 val
+vwzprtfgpt 1 300 train
+vwzrviqaqk 0 300 train
+vwzwrgnhfm 1 301 train
+vwzxrdbiui 1 300 train
+vxaavhydjx 1 299 val
+vxakkmhcan 0 300 train
+vxamdcqrij 1 300 val
+vxariplxvb 1 300 train
+vxatsmcjwp 1 300 train
+vxavwwanpp 1 300 train
+vxawghqzyf 1 299 test
+vxayjzhphh 0 300 train
+vxazuxsirx 1 300 train
+vxbijjelis 1 300 train
+vxbnaacnvz 0 300 train
+vxbngbdohv 1 300 train
+vxbvibfyws 1 300 train
+vxbwwmwmbr 1 298 train
+vxbxvkgzoj 1 300 train
+vxbxvwazua 1 300 train
+vxbzxycewg 1 241 train
+vxcauvichw 1 301 train
+vxcazliomf 0 300 val
+vxcdlcipsv 1 299 test
+vxcfljdjbe 1 300 train
+vxchonbvlo 0 300 train
+vxcjkgerao 1 300 train
+vxcvxdxviu 1 300 train
+vxcwtlqnbv 1 300 train
+vxcxblgtcl 1 300 train
+vxdbtkmflb 1 300 train
+vxdczbejse 1 300 train
+vxdelrvtsm 0 300 train
+vxdeuyjhuq 1 300 val
+vxdmobeecq 1 300 val
+vxdrlavuiz 1 300 train
+vxdtvamulo 1 300 train
+vxecigmrxc 1 300 train
+vxeffpwgdm 1 300 train
+vxefrkhezg 0 300 train
+vxejmiiysy 0 300 val
+vxelxlqkjb 1 300 train
+vxfcclseww 1 300 train
+vxfemtltst 1 300 train
+vxfpfaneih 1 300 val
+vxfqivddfn 1 300 train
+vxfsdxzxnj 1 300 val
+vxfvavzscr 0 300 train
+vxfxyfxjhh 1 298 train
+vxfzvtjzhp 1 300 val
+vxfzwhttgo 1 301 val
+vxgcwydjlt 1 300 train
+vxgfvndtps 1 300 train
+vxgiwpqgsu 1 298 train
+vxglhyrdzc 1 300 train
+vxgnttzbly 1 301 train
+vxgtlxsxlj 1 301 val
+vxgzcbnsch 1 300 train
+vxgzxvarvc 0 83 train
+vxhdfsvihq 1 300 train
+vxhdogmgkw 1 298 train
+vxhdsgywlh 1 300 train
+vxhgbajzgq 0 300 train
+vxhgeakqkp 1 296 train
+vxhhjphktb 1 300 train
+vxhisgoyho 1 300 train
+vxhizpnfvv 1 300 train
+vxhjmyrhrb 1 300 train
+vxhmskalqh 1 300 train
+vxhqfhtsyz 1 300 val
+vxhqfzmnfl 1 300 val
+vxiafftrxk 1 300 val
+vxiavuaply 1 300 train
+vxibmpouix 1 299 train
+vxindsokyo 1 300 val
+vxiptsrljx 1 301 train
+vxivzbkhdk 0 301 train
+vxjcxwqobu 1 300 train
+vxjfmhoehj 1 300 train
+vxjlkxxzxa 1 300 train
+vxjnnwlxuj 1 300 val
+vxjoanibby 1 299 val
+vxjzqqyujp 1 300 train
+vxkenpvysi 1 301 val
+vxkeychldl 1 300 train
+vxkhloixxn 0 300 train
+vxkmbacdkh 0 300 train
+vxkrtqscmz 1 300 train
+vxkukidugz 1 300 train
+vxkzaoklbk 1 300 train
+vxlhqgjlpj 0 300 train
+vxljcjgbsw 0 300 train
+vxlqkjtyuk 1 301 train
+vxlqzgewuz 0 300 train
+vxlvixxxtz 1 300 train
+vxmgbdjlkk 1 300 train
+vxmhhyfcbu 1 300 train
+vxmiyfbbsu 1 300 train
+vxmkzjssht 1 300 train
+vxmntgzczw 1 300 train
+vxmzjuxoeb 0 301 train
+vxmzqllpag 1 300 train
+vxnbbnrfap 1 300 train
+vxnczzlpmr 1 300 val
+vxnfzncvua 1 300 train
+vxnjzhzwcx 1 300 train
+vxnrwwrbec 0 299 train
+vxnyfyxnmi 1 300 train
+vxoaanowge 0 300 train
+vxoahgdkoj 1 300 train
+vxoaxsgmyh 1 300 train
+vxocikxfef 1 300 val
+vxoddhovex 1 300 train
+vxofqfrzrm 1 300 train
+vxohbbjthl 1 300 train
+vxojnluipv 1 300 train
+vxokvtanxi 1 300 val
+vxolvggyft 0 300 train
+vxpabktsbm 0 300 train
+vxpgkelrns 1 300 val
+vxprrzvdgv 1 300 train
+vxptamrvpk 1 300 train
+vxpvnjllaf 1 300 val
+vxpzecdqti 0 300 val
+vxqcfwelie 1 302 train
+vxqgxjbcbe 1 240 train
+vxqofldgze 1 301 train
+vxqqgljfxb 1 300 train
+vxqtauhyvo 1 300 train
+vxqtweehrj 1 300 train
+vxrdidfgje 0 300 val
+vxrfbjctbw 1 300 train
+vxrgtuaknc 1 241 train
+vxrhpfangv 1 300 train
+vxrwcqyzuq 1 300 test
+vxrykynixm 1 301 train
+vxsahtujxi 1 300 val
+vxsfiaputa 1 288 train
+vxshzuregy 1 300 train
+vxsubowvod 1 269 train
+vxsvhjcpeh 1 300 test
+vxtbxyegcj 1 300 train
+vxtfcgjagn 0 300 train
+vxtlqowsxi 1 300 train
+vxtnqjouiu 1 241 train
+vxtqcieswl 0 300 val
+vxucpqtbuf 1 300 train
+vxuhkqqaqv 1 300 test
+vxukxlzvld 1 301 train
+vxuriuzzme 1 300 val
+vxusutrmjr 0 300 train
+vxuwvgnfon 1 302 train
+vxuzyzrbmx 1 300 val
+vxvbbcflxo 1 300 train
+vxvdmmcyzl 1 300 test
+vxvebmjqdu 0 300 val
+vxvffvdjnn 0 300 train
+vxvfnilipx 1 301 train
+vxvghzwwzk 0 300 val
+vxvkghqomn 1 300 train
+vxvweepggi 1 241 train
+vxvxzixaiv 1 300 val
+vxwaxehjux 1 300 train
+vxwgpiglqs 1 300 val
+vxwheccoaq 0 300 train
+vxwkhsvjxx 1 300 train
+vxwpjjlzbu 1 300 train
+vxwqrychgw 1 300 train
+vxwsisekmb 0 300 train
+vxwtnxnpho 0 300 train
+vxwynzxprl 1 300 train
+vxxajypjxx 1 300 train
+vxxbpbersr 1 300 train
+vxxcreqosa 1 300 train
+vxxiglhepy 1 299 val
+vxxlutjivk 0 300 val
+vxxowtpczo 1 301 train
+vxxxiaukut 0 300 train
+vxyddzxeco 1 300 train
+vxyflrjrqy 1 300 train
+vxyiqbqyvw 1 300 train
+vxyzlvqvhb 1 300 train
+vxzbvdfaqh 1 300 train
+vxzbzorpvx 1 300 train
+vxzevjxptf 1 300 train
+vxzjdyknbc 1 301 val
+vyacjkyvnt 1 300 train
+vyaduokoci 1 300 train
+vyalsygteh 1 300 val
+vyannrqxdy 1 300 train
+vyaoqsznth 0 300 train
+vyapqxtxdp 0 300 train
+vyashhbpgf 1 300 train
+vyavemhtbi 1 300 val
+vyawcaqsef 1 300 val
+vyaxwjevgp 0 300 train
+vyazlprxqy 1 299 train
+vybarxinlq 1 300 train
+vybbrqndcv 0 300 train
+vybbullejj 1 300 train
+vybdzsvmer 1 300 val
+vybgpmtpwx 1 300 train
+vybhnpffvn 1 300 train
+vybmkdshaw 1 296 train
+vybpefznnl 1 300 train
+vybsdxhwhs 1 300 train
+vybvqhigzq 1 300 train
+vycjqybuiw 1 300 val
+vycjvimbgl 1 300 train
+vycrhmlesx 1 300 train
+vycubfqbsw 1 300 train
+vycvfenloc 1 300 train
+vydaidnycn 1 300 val
+vyddxgodef 0 300 train
+vydiylglrd 0 300 train
+vydpnxshqy 1 300 train
+vydsnygyil 1 300 train
+vydubobzur 1 300 train
+vydurhzlok 1 300 train
+vyecastqxh 0 300 train
+vyefvxoqmh 1 300 train
+vyeikrbfrj 1 300 train
+vyejvtyqyq 1 297 val
+vyetamwqck 1 300 train
+vyetikapse 1 300 train
+vyeykiiasj 1 300 train
+vyezqvwnug 1 300 train
+vyfbdzoqbo 1 302 val
+vyfbiursvd 1 301 val
+vyfhhfywnl 1 300 val
+vyfiynmilj 1 300 train
+vyfmjzqudl 1 302 train
+vyfobcpbfq 1 300 val
+vyfqndrtbk 1 300 train
+vyfrgvajts 0 297 train
+vyfsvowbmx 1 300 val
+vyfxbvzhvx 1 300 train
+vyfyqbdijp 1 300 train
+vygawkzzop 1 300 train
+vyggbiovvt 1 300 test
+vygippnwij 1 300 train
+vygniftctl 1 300 train
+vygtdddmcc 1 300 train
+vygvjbdurk 1 240 train
+vyhdexfmby 1 300 train
+vyhejqfwbr 1 300 val
+vyhfemhath 1 300 val
+vyhgilqtaq 1 300 train
+vyhhcubgrb 1 300 train
+vyhqgmexxh 1 298 train
+vyhubiytsm 1 241 train
+vyhuqhrurt 1 147 train
+vyidmypboc 1 300 val
+vyifmjitkj 1 300 train
+vyiggzhvpl 1 300 val
+vyigmewuus 0 300 train
+vyiikcnkyw 1 301 train
+vyismybxnv 1 300 train
+vyistfyqmj 1 300 train
+vyjclmcbte 1 300 train
+vyjcqshdph 0 300 train
+vyjhpmgygg 1 300 train
+vyjimehxoo 1 298 val
+vyjtagjnsd 1 301 train
+vyjxjjazoh 1 300 train
+vykfklauzu 1 300 train
+vykjzkzmha 1 300 train
+vykngnqhju 1 300 train
+vykowaboqz 1 300 val
+vyksfxlwrx 1 300 train
+vykthjeqxf 1 300 train
+vylcawclna 1 300 val
+vyleqefdni 1 300 train
+vylqhhaece 1 300 train
+vyltxaezoc 1 301 val
+vylzsyazmx 0 300 train
+vymgrquazw 1 300 train
+vymmhcllqs 1 300 train
+vympbyunbk 1 300 train
+vymrbyamcs 1 299 test
+vymxfcxvkj 1 300 train
+vymxmksyrh 1 303 train
+vymynvldrw 1 299 train
+vymzvytitc 1 300 train
+vynalvxtdi 1 300 train
+vyncisxxci 1 300 train
+vyndaaclxx 1 300 train
+vynftymwuc 1 300 train
+vynhywgssy 1 300 train
+vynipsqagd 1 300 train
+vynjlfyfph 1 300 val
+vynnfkykky 1 300 train
+vynuuilfqu 1 300 train
+vyonvyawll 1 300 train
+vyoozsirec 1 239 train
+vyoygeuwop 1 300 val
+vypavhuqeh 0 300 train
+vypdtrxrqd 1 300 train
+vypfiufyvr 0 301 train
+vypkpnhzhy 1 298 train
+vypkyjvnew 0 300 train
+vypqvuqtiq 1 300 train
+vypwovaohd 1 302 val
+vypyrwpwdu 1 300 train
+vyqkbaazoj 1 300 train
+vyqqnwyrzi 1 300 train
+vyqyidqzsd 1 300 train
+vyqypnteha 1 301 train
+vyretbitgp 1 300 train
+vyriczolnr 1 300 train
+vyrkbvfpbd 0 300 train
+vyrosrtuyc 1 99 train
+vysbgwrsuo 1 301 train
+vyschgjrtg 1 300 train
+vysdpgxamp 1 300 val
+vysgznzxyi 1 299 val
+vyskzwemnq 1 300 train
+vysmflvyjr 1 300 train
+vysvnufvyc 1 300 train
+vytbixywfl 1 300 val
+vytbsarawp 1 300 train
+vytjkvplzu 0 300 train
+vytklfqusv 1 299 train
+vytnueykce 1 300 train
+vytvsnbdhx 1 300 train
+vytxzvtxbe 1 300 val
+vyurxfsukk 1 300 train
+vyuvcsjiwn 0 297 train
+vyvakdelwu 0 300 train
+vyvcnwyxkk 1 300 train
+vyvfceievp 1 300 val
+vyvgtzfstx 1 299 train
+vyvgxfxgxe 1 300 train
+vyvvqdutrx 1 300 train
+vyweaswaop 1 300 train
+vywqnyxgxw 1 300 train
+vywscpqxym 1 300 train
+vywtjgalte 0 298 val
+vywvktvkbs 1 300 train
+vyxbfwyxxu 1 300 train
+vyxcwihirt 1 296 train
+vyxdwkajlr 0 300 train
+vyxgqftjfs 1 300 test
+vyxlctqrww 1 300 train
+vyxleipcud 1 300 val
+vyxlelbqjh 1 300 train
+vyxlxecfdi 1 300 val
+vyxryahfuw 1 300 test
+vyxstuawio 1 300 train
+vyxvfsvkjo 1 299 val
+vyxznavlgp 0 300 train
+vyyrjslcgm 1 300 val
+vyzhmnpvsu 1 300 train
+vyzmfpeldh 1 300 train
+vyzvyspyms 1 298 train
+vyzyckcmpt 1 300 train
+vzaaiyqhaa 1 301 train
+vzabrlhzxy 1 300 train
+vzaciibkwh 1 300 train
+vzacrzgjtk 0 300 val
+vzakeziwka 1 300 train
+vzamxrrbiy 1 300 train
+vzaplbdhrh 1 300 train
+vzavtpmxjw 1 300 val
+vzawackcod 0 301 train
+vzawfsnetg 1 296 val
+vzbdwilegq 0 300 train
+vzbfqsmggp 0 300 train
+vzblrxdmxw 1 300 val
+vzbmegnnnp 1 300 val
+vzbmsspzyk 1 301 val
+vzbnffmsdu 1 300 train
+vzbtikceuq 1 300 train
+vzbyhpghmh 1 300 train
+vzckdbcooj 1 300 train
+vzcldbilmd 1 300 test
+vzcohqlrbk 1 300 val
+vzcsrijdln 1 300 train
+vzczmceyuc 1 300 train
+vzdbwerhpw 1 300 train
+vzdjpsxrma 1 300 train
+vzdlexfsfa 1 300 val
+vzdmxnuhkz 1 300 train
+vzdubwzzed 1 300 train
+vzdztucbmo 1 300 train
+vzeekfgafz 0 300 train
+vzeingelww 0 300 train
+vzetjkdprf 1 300 train
+vzewnmgser 1 300 val
+vzfiayzifu 0 300 train
+vzfmvyzyhy 1 300 train
+vzftnuycbj 1 300 val
+vzfuirywui 1 300 train
+vzfutyrlfu 1 300 train
+vzgcbkfkga 1 300 val
+vzggfetbga 1 300 train
+vzgrwuddfc 1 300 train
+vzhddunyik 1 298 train
+vzhekhuofe 1 300 train
+vzhhabdkic 1 299 test
+vzhljkqzja 1 300 val
+vzhnbxbmao 0 300 train
+vzhqsyaeay 1 300 train
+vzhxfjtkud 0 300 train
+vzhzpxtnnc 1 300 train
+vzicrvyshi 1 300 train
+vzidramzjr 1 300 train
+vziegwucrm 1 300 train
+vziiorztkr 1 300 train
+vzillcqktk 1 300 train
+vzinlbrvuw 1 300 train
+vzitwqwcii 0 300 train
+vzjdqyuhdm 1 300 train
+vzjiuuhlgz 1 300 train
+vzjktiexzp 1 300 train
+vzjlnbubxc 0 300 train
+vzjtlutekj 1 300 train
+vzjwwecbrb 1 300 train
+vzjxlvatvy 1 300 train
+vzkbkaytip 1 300 train
+vzkcfuvdnt 1 300 train
+vzkekmsnyk 1 300 train
+vzkjmyeyhk 1 300 train
+vzkrgudcmv 1 300 train
+vzkzxkpqdd 1 300 train
+vzlnetywmn 1 301 train
+vzloiamnpz 1 298 train
+vzlplnaedv 0 300 train
+vzltstjkwm 1 300 train
+vzmdeolhkj 1 300 train
+vzmearlypd 1 300 train
+vzmgapyugl 0 300 val
+vzmqvcguxq 0 300 val
+vzmvjibtrk 1 300 train
+vzmvymcuud 1 301 train
+vzmywijmup 1 300 train
+vznfvzkrgy 1 300 train
+vzngxvuasb 0 300 train
+vznietswdh 1 300 train
+vznvznmodh 1 300 val
+vznxsshhdy 1 300 train
+vznzbpywab 1 300 train
+vznzkukogh 0 300 train
+vzocjdjdcg 1 300 test
+vzockawbyi 1 300 test
+vzodkhkpdv 1 300 val
+vzoefemkme 1 300 train
+vzoejtikdm 1 300 train
+vzoixqqblu 1 300 val
+vzomknwbuv 1 300 train
+vzonmouobw 1 300 train
+vzovudfimk 0 300 val
+vzowqvxzhe 0 300 train
+vzpcoxcvve 1 300 val
+vzpdjijjwu 1 300 train
+vzpjiizwuh 1 301 train
+vzpmrsanyg 1 298 train
+vzqporvzyd 1 300 train
+vzqpsxusrg 1 300 train
+vzquaqkpiu 1 300 val
+vzquwvazbb 1 300 train
+vzquzlnnbn 1 300 train
+vzrgckofjv 1 300 test
+vzrhekqyot 1 300 train
+vzrokelbyl 1 300 train
+vzrqriafie 1 300 val
+vzrrkyipkj 0 300 train
+vzsbpfzmpr 0 300 val
+vzsfxqdiwt 1 300 train
+vzslwhsxpq 1 300 train
+vzsthtxqgc 1 300 val
+vzsvqprvla 1 240 val
+vztbiwmmem 1 300 train
+vztcxttmjh 1 301 train
+vztfzxzclg 1 300 train
+vztgyfusdu 1 300 val
+vztjmxdyyq 0 301 train
+vztqijiuxd 0 300 train
+vzudqxuefh 1 301 val
+vzujheqknk 1 300 train
+vzuwzgqooi 1 300 train
+vzuxewlhry 1 300 train
+vzvbazzbsp 1 299 val
+vzvgbfsqbv 0 300 train
+vzvgrwzrzd 1 299 train
+vzvlhcuybz 1 300 train
+vzvlujhvrg 1 269 train
+vzvtdriwmv 0 300 train
+vzwabzivqn 1 241 train
+vzwdbcvvqn 0 300 val
+vzwgiyspnv 1 300 train
+vzwilvmdia 1 300 train
+vzwjztahsh 0 300 train
+vzwpynlfkd 1 298 val
+vzwpzlmtlm 0 300 val
+vzwqwhwvsa 1 299 train
+vzwxzyygdn 1 300 val
+vzxadqdpwy 1 300 train
+vzxepjxzbk 1 300 train
+vzxgmtvvwa 1 300 train
+vzxkxnvuwb 1 300 train
+vzxlthrgth 1 300 train
+vzxluflrhn 0 300 train
+vzxqvkmynj 1 300 train
+vzxxpzqwcy 1 300 val
+vzybqptymo 1 300 train
+vzyfknevkw 0 300 train
+vzyigmkacd 1 300 train
+vzysajdfrb 0 300 train
+vzywqvchez 1 299 val
+vzzbnmupxz 1 300 val
+vzzfilclbc 1 301 val
+vzzjrmhidq 1 300 train
+vzzkunmkkl 1 300 test
+vzzndvloxn 1 300 val
+waaeyecbto 1 300 test
+waalpeyrtv 0 300 train
+waazjrotyv 1 300 train
+wabhktkmfy 0 300 train
+wabjhmmqww 1 302 val
+wabjhvgygp 1 300 train
+wabniqhixs 1 300 train
+wabqbhqqec 0 300 train
+wabsrjpgpx 1 300 train
+wabyiamgcs 1 300 train
+wacesnrysx 0 300 train
+waciontncf 1 300 train
+wacnqrpbso 1 300 val
+wacxaomorz 1 300 train
+wacyzcwcvr 1 300 train
+wadgdooqpl 1 301 train
+wadmizqokh 1 300 train
+wadmzlferi 1 241 train
+wadvbqwddb 0 301 train
+wadvzjhwtw 0 300 test
+wadyopfhgm 1 300 train
+waehykhfxa 1 300 val
+waejbmqode 1 300 train
+waejvkchgy 1 300 train
+waekcvtplt 1 300 train
+waelhbzekw 1 300 train
+waerrjnviq 0 300 train
+waeskngtfq 0 300 train
+waeyyfwjgv 1 298 val
+wafhfulyss 1 300 train
+wafkeynzwr 1 300 train
+wafsjwgopv 0 300 train
+wafyksehao 1 300 train
+wagcavhhpc 1 300 train
+wagthdtbpm 0 300 train
+wahawfhkqr 0 300 train
+wahixajhpv 1 300 val
+wahwqporrg 1 300 val
+waieuhasqu 1 300 val
+waikumywfw 0 300 train
+waisqhdfag 1 300 train
+waityroaiu 0 300 train
+waixrkgsuw 0 300 train
+wajeimazic 1 301 train
+wajekkipiy 1 300 train
+wajrokuqlv 1 301 val
+wakaawjoym 1 301 val
+wakdwqqvls 1 300 train
+waklkkedwe 1 300 train
+wakrfauvnf 1 301 train
+wakshhcdwv 1 299 val
+wakytbsygn 1 300 train
+wakztlctcx 1 300 train
+wakzzviddh 1 300 train
+waldenznri 1 300 train
+walezbgmbc 1 300 train
+walwffkgtr 0 300 train
+walwxoranx 1 300 train
+walyjzpowy 1 300 train
+wamoeksipk 1 299 train
+wamxhcfaga 1 301 train
+wamxhetipp 1 301 train
+wamxrtlrwp 1 300 train
+wanjyppioc 1 300 train
+wannogxtda 1 301 train
+wanqtjrijv 1 300 train
+waobqainwf 1 300 train
+waocsggrqe 0 300 val
+waocyhkffv 1 300 train
+waodzyidln 1 300 val
+waoehutdln 1 241 train
+waofmzjaei 1 301 train
+waoghlpzda 1 299 val
+waoqudqbro 1 300 val
+waordgyeox 1 300 train
+waoxgtosrb 1 300 train
+waoysegasl 0 300 val
+wapahvkmga 1 300 train
+wapebjxejr 0 300 train
+wapflpdhyi 0 299 test
+wapoobmgjl 1 296 val
+waposhkxgd 1 300 train
+wappqztpnr 1 300 train
+wapskzfmwf 1 300 train
+wapycogdhl 0 300 train
+wapytblnic 1 300 val
+waqajqrdnp 1 300 train
+waqelazvkw 1 298 val
+waqkzzfbll 1 300 train
+waqlwizilq 1 298 train
+waqocpjdjv 1 300 train
+waqohuqldv 1 300 train
+waqssoochw 1 300 train
+waqxoiabtw 1 300 train
+warbixkrja 1 300 train
+warlsqfhgv 1 300 val
+warmpnnigh 1 298 train
+warsqvoirc 1 300 val
+warwzhgiac 1 300 train
+wascdpzkhj 1 300 train
+wasjkmhoqx 1 300 train
+waspuacmqv 1 299 val
+watcnqibxj 1 300 train
+watgcivwwz 1 300 val
+wathakdnap 1 300 train
+watimdiuxs 1 299 train
+watiwlecjv 1 300 train
+watlphgtvj 1 300 val
+watpnbxoug 1 300 train
+watpnhaucp 1 302 train
+watuqwhpnl 1 300 train
+watxerbhhj 1 300 train
+waubsvmsoa 1 300 train
+waucixfohc 1 300 train
+waucvvmtkq 0 300 test
+waujrsehde 0 300 train
+wauncejidq 1 301 val
+waunwdrlni 1 300 train
+wauoeybril 0 300 val
+waupladggx 1 301 train
+waupxmdckc 1 300 train
+wauvumpffw 1 296 train
+wauxenrrem 1 298 train
+wauzbrlnhh 0 241 train
+wauznxenru 1 300 train
+wavjwvvskq 0 300 train
+wavutkxdrz 1 301 val
+wavziovmvo 0 300 val
+wawfomauar 0 300 train
+wawxmzcdjb 1 300 test
+waxcdqdjpx 1 300 train
+waxcfuxpae 1 298 train
+waxdnuvizs 0 300 train
+waxeptxjmt 1 300 train
+waxiuhpvjr 1 300 train
+waxknlqmui 1 300 val
+waxrtsfuap 1 300 train
+wayblmvxwh 1 300 val
+wayblxtvzm 1 300 train
+wayemavyza 1 300 val
+wayjgxrbub 1 300 train
+wazeinvyng 0 300 train
+wazfozebxi 1 301 train
+wazuwenqyy 1 298 train
+wazyccbopq 1 300 train
+wbakohwvam 1 300 val
+wbalhrcaxc 1 299 val
+wbauflvfzq 1 300 train
+wbbhccuhab 1 296 train
+wbbivdhqpi 1 241 train
+wbbmxcrssy 1 300 train
+wbcamhqfgx 1 300 train
+wbcbyijcpj 1 300 train
+wbcedifidc 1 300 train
+wbcexlqina 1 300 train
+wbcnvdycxo 1 300 val
+wbcoakvxvw 1 300 val
+wbctcqwbtc 0 300 val
+wbcvoxfsch 1 300 train
+wbcwyspkld 1 298 train
+wbdeybaazn 1 301 train
+wbdgvaagjx 1 298 train
+wbdivngivl 1 300 val
+wbdpryfqgy 1 300 test
+wbechqnxqm 0 300 train
+wbegjrceqs 0 300 train
+wbegnddgks 0 300 train
+wbelabeuad 1 298 train
+wbeloasrin 1 300 train
+wbeplfzuvf 1 300 train
+wbeytxcgpy 1 300 train
+wbezhimwhd 1 300 train
+wbezyiploa 1 300 train
+wbfezmodza 1 300 train
+wbfofluvxg 1 300 train
+wbgivbxtax 0 300 train
+wbgkmmeiff 1 300 train
+wbgqgrdnru 1 297 train
+wbhdvppkmw 1 300 val
+wbhgiqmjwp 0 300 val
+wbhgwgqgna 1 300 train
+wbhobkjdfp 0 300 train
+wbhrwyvmyb 1 300 train
+wbhszejhxx 1 300 train
+wbhusfdkwh 1 300 val
+wbhxgtaswg 1 300 train
+wbibseeetw 1 298 train
+wbiqndbqvl 1 297 train
+wbiuduihbh 1 241 train
+wbiuklwpml 0 300 val
+wbjbxxqhpa 1 300 train
+wbjdvyppqu 1 300 val
+wbjevjayir 1 299 test
+wbjjqvilmb 1 300 val
+wbjnkkmwls 1 300 val
+wbjovxmnin 1 300 train
+wbjtrlyjsm 0 300 train
+wbkiwlgyqr 1 147 train
+wbkmlpzaxw 1 300 train
+wbknhrsaor 1 300 train
+wbkseptvot 1 301 train
+wblbqllxwq 1 301 train
+wblcszxxbb 1 300 val
+wblglhtniu 1 300 train
+wblinksqmt 1 301 train
+wbljssjgnp 0 300 val
+wbllwuvlsk 0 300 train
+wblpwuihmo 1 300 train
+wblyuuanbr 0 300 val
+wbmdqqtnmr 1 300 val
+wbmfybqtry 1 300 train
+wbmgzfjkwu 0 300 train
+wbmkawolew 1 300 train
+wbmkzdqabg 1 300 train
+wbmpjqvdvy 1 300 train
+wbmtiennwo 0 300 train
+wbmvbetcdm 0 300 train
+wbmxzgevzq 1 300 train
+wbnepxefbp 1 300 val
+wbnjeuoytp 1 300 train
+wbnowcgdhl 1 300 val
+wbnsqvrugp 1 300 val
+wbnylvpxkb 1 300 train
+wbnzcxjjzb 1 300 train
+wbofyfsnxz 1 300 train
+wbohzwsidv 1 300 train
+wboooesvdf 1 301 train
+wborejzpjg 1 298 train
+wboxubjdlm 1 300 train
+wboybzuist 1 300 val
+wbozberqml 1 300 train
+wbpcawlkxt 0 300 train
+wbpcorrcyl 1 300 train
+wbpdvoppvp 1 300 train
+wbpekopuqu 1 300 train
+wbplllwijf 1 300 train
+wbplnmusci 1 300 val
+wbpnikwbii 1 301 val
+wbpnivczyi 1 300 train
+wbpvrvhedt 1 300 train
+wbqbiecsfe 1 300 train
+wbqckktphr 1 300 train
+wbqdwrulkm 1 300 train
+wbqehtsbzh 1 300 train
+wbqjrsmcxx 1 299 val
+wbqjzoihuf 1 300 train
+wbqnqjfsgi 1 300 train
+wbqqqeigie 1 298 val
+wbqxemjqqt 1 300 train
+wbrcgruewi 1 300 val
+wbrdeadtqs 1 300 train
+wbrkdcgwrv 1 301 val
+wbrlioguvj 1 300 train
+wbrvrwhgzp 1 298 val
+wbsaewrzpq 0 300 train
+wbsajsyaej 0 300 train
+wbsedosftd 0 300 train
+wbsgclrwby 1 300 train
+wbsjlgxstv 0 300 train
+wbsmjgzibv 1 299 val
+wbspcnfetp 1 300 train
+wbsrjipcla 1 300 train
+wbtjpjlsjo 1 300 train
+wbtmwtyjrc 0 241 val
+wbtolhwpyo 1 300 train
+wbtqklejpm 1 300 train
+wbtxmzbljt 1 300 val
+wbtxxrwhah 1 300 train
+wbtytqdygg 0 300 train
+wbuajbdcfs 0 300 train
+wbufbnhbgo 0 300 train
+wbujtkivtn 1 300 train
+wbvcmmnspe 1 300 val
+wbvfgpprzr 1 298 val
+wbvfuhlzqk 1 300 train
+wbvjhwxgfk 0 300 val
+wbvkciqhjp 1 300 train
+wbvlgevkmb 1 300 train
+wbvttgzgjr 1 300 train
+wbvytridup 1 300 train
+wbvztduzsb 1 300 train
+wbwevefzkj 1 300 val
+wbwipxamgj 1 300 test
+wbwjjvimxt 1 300 train
+wbwloupxse 1 300 train
+wbwojotqml 1 300 train
+wbwsscmgxb 1 300 train
+wbwughapax 1 300 train
+wbxajuueyc 1 301 train
+wbxgbgzbrz 0 300 train
+wbxncmmvvq 1 301 val
+wbxnjorrvo 1 300 train
+wbxnyopaix 1 300 train
+wbxofatybs 0 300 train
+wbxpuymxoa 1 300 val
+wbxsjknxbe 1 300 val
+wbxvdytfbs 1 297 train
+wbxvzdbcty 1 300 train
+wbxwesdpad 1 300 train
+wbxwlxngda 0 300 train
+wbyfiwfrgf 1 300 val
+wbyjfyqejz 1 300 train
+wbyrgkisio 1 298 train
+wbytduwkdj 1 300 train
+wbytxsolfy 1 300 train
+wbyxrxwodq 1 300 train
+wbyxvurava 1 300 train
+wbyzjuahgs 1 300 train
+wbzbeqchim 1 300 val
+wbzjcngbor 1 300 train
+wbzlqkabek 1 300 train
+wbzplejali 1 300 train
+wbzssuclak 0 300 train
+wbzuboyumt 1 300 train
+wbzzvjhdwy 1 301 train
+wcaaxxzzti 0 300 train
+wcafwzjouc 1 300 train
+wcagdhcwxf 0 300 train
+wcanduuelm 1 300 train
+wcarhoxzjw 1 300 train
+wcatyuvelb 1 300 train
+wcbfcmfjon 1 300 train
+wcbhgpjimp 1 300 train
+wcbnkhtwvj 1 298 train
+wcbobyxrpi 1 300 train
+wcbrjnwgax 1 300 train
+wcbvzlyltb 1 300 train
+wcbywrkxde 1 300 train
+wcbzijzyaq 1 301 train
+wccctilnog 1 300 train
+wcciqxrgmu 0 300 train
+wcckmuzcyh 0 300 train
+wccpwljmdp 1 300 train
+wccrmgmtxn 0 301 train
+wcctmgtcvk 1 300 train
+wcctpsulrb 1 300 train
+wcdcivtpti 1 300 train
+wcdgjnxxya 1 300 train
+wcdkdtysxu 1 136 train
+wcdlesgtcm 0 300 train
+wcdmpwfooh 0 300 train
+wcdnmobrhx 1 300 train
+wcdspbjwpe 1 300 train
+wcdtfemebs 1 296 train
+wcdugrpkav 1 300 train
+wcebzzgjxz 1 300 train
+wcegwouoht 1 298 val
+wcegztykxz 1 300 train
+wceieysdnf 1 300 train
+wcejzilhde 1 300 val
+wcensuhwcu 0 300 val
+wcerkoyqnm 1 300 train
+wcesicmvwc 1 143 train
+wcesppbxgb 1 300 train
+wcesrrufye 1 301 train
+wceyaursts 0 300 train
+wceyqinyms 0 300 train
+wcfapuiujd 1 300 train
+wcfavuwdya 1 300 train
+wcfhxxgyoj 1 300 val
+wcfiqthqyh 1 300 val
+wcfuseusyy 1 299 test
+wcgaoagczh 1 300 train
+wcgdutgbfz 1 301 train
+wcggfapnkg 1 300 train
+wcgjtycnyj 1 301 val
+wcgmsalwrw 1 167 train
+wcgnlptmhq 1 300 train
+wcgnnjkoyj 1 299 train
+wcgrxyynvx 1 300 val
+wcgseqbpbz 1 300 train
+wcgwcemzfg 0 300 train
+wchbngegmq 1 300 train
+wchdqfgzrf 1 240 train
+wchmfhotgt 1 300 train
+wchmpndmtt 1 300 train
+wchrejymst 1 300 train
+wchtllzpop 1 300 train
+wchxvtaxjd 1 300 train
+wchyzbvxaq 1 300 train
+wcibpopuzz 1 300 val
+wcicgnnamg 1 300 train
+wcijccsuwx 0 300 train
+wcimuqbkek 1 300 val
+wciqwqqgnr 1 300 train
+wcjdiuhuhx 1 300 val
+wcjhbdtezc 1 300 train
+wcjtwwbwdz 1 300 val
+wcjudtkzab 1 300 test
+wcjvgqhaup 1 300 train
+wcjyhjiffi 1 302 train
+wckkpkpzij 1 300 train
+wclfpamibf 1 300 train
+wcljxhvbuy 1 300 train
+wclkgjeacf 1 300 train
+wclmwjiotk 1 300 train
+wclqtyzuqt 1 301 train
+wclupzuocu 0 300 train
+wcluujyrgs 1 300 train
+wclvkepakb 0 300 test
+wclvwebtbv 1 300 val
+wclwrdpcbh 1 300 train
+wclyhaqcli 1 300 train
+wcmadayrjt 1 300 val
+wcmcakviru 0 300 val
+wcmcxbnlaq 1 300 train
+wcmdngxlzi 1 300 train
+wcmgrcbwxq 1 300 train
+wcmqpfjebd 1 300 val
+wcmqvldxtk 0 300 train
+wcmqzgrmot 1 300 train
+wcmshkluoi 1 299 val
+wcmupniqzu 1 300 train
+wcnnrwfvgi 1 300 train
+wcnoidetws 1 300 train
+wcnttkqepg 1 300 train
+wcnyglsxht 1 300 train
+wcogqdnaru 1 300 test
+wcohnatfuu 1 300 val
+wcoiactffy 1 300 val
+wcojahkcgn 1 300 train
+wcojcwkodh 1 300 train
+wcokafuarj 1 300 train
+wcosikguob 1 298 train
+wcovfnrnev 1 300 val
+wcpavuwnml 1 300 val
+wcpdrrnggv 1 300 train
+wcpfmnysix 1 300 test
+wcpgjdwupb 1 300 val
+wcpsjgsmhk 1 301 val
+wcqieyqcok 1 302 train
+wcqpzkkwmn 0 300 train
+wcqtnstwij 0 300 train
+wcqudssayk 1 300 train
+wcqvuohxze 1 300 train
+wcqvzujamg 0 300 test
+wcqxmjrmom 1 300 train
+wcravjrfnm 1 300 val
+wcrdjvkibw 1 300 train
+wcrehsadrr 1 239 train
+wcrirllire 1 300 val
+wcrlqsgepc 1 300 train
+wcrrxczbdg 0 300 train
+wcryqnreov 1 300 val
+wcsacsojke 0 300 train
+wcsjyepgam 1 300 train
+wcssbghcpc 1 300 test
+wcstfjyucj 1 300 val
+wcszcwucth 1 300 train
+wctjlgxmus 1 300 train
+wctnpuacux 0 300 train
+wctqfpaquy 1 300 val
+wctrppqdjo 1 300 train
+wctyfizosd 1 301 val
+wcuavvyokv 1 300 train
+wcuceputwq 1 300 train
+wcuiivptnj 1 300 val
+wcuisshpyt 1 299 train
+wcumrffolu 1 300 train
+wcuqilvtpy 1 300 train
+wcursjyswg 1 300 train
+wcusakgafv 1 300 train
+wcuszrhoti 1 300 train
+wcvadvurat 1 300 train
+wcvbqghjtq 1 300 train
+wcvckgnrsz 1 300 val
+wcvczchrmf 1 300 val
+wcvolzkcto 1 300 train
+wcvqitysib 1 288 train
+wcvsqnplsk 1 300 test
+wcvuxlupna 1 300 train
+wcvyiarpfo 1 300 train
+wcwkviunso 1 300 train
+wcwkxtzvhc 1 300 train
+wcwovskufz 1 300 train
+wcwszagibq 1 300 train
+wcwuyxekfd 1 300 train
+wcwvxpgmze 1 300 train
+wcwybzlmxi 1 239 train
+wcwygzkaau 1 300 train
+wcxatqxrgo 1 299 test
+wcxkpprmvh 1 300 train
+wcxmjligtp 1 300 train
+wcxombjhpz 1 250 train
+wcxpbeqhav 1 301 train
+wcxwqeehsn 1 300 train
+wcyasjdpao 0 300 train
+wcybpkdnmv 1 300 train
+wcydegrkti 1 301 val
+wcyeceujki 1 300 train
+wcyghduqvk 1 300 val
+wcyhcwiwxj 1 299 test
+wcyogabfzz 1 300 train
+wcyrtxkblp 1 300 train
+wcytzvhuin 1 300 train
+wcyzujklzv 1 300 train
+wczaflhpiz 1 300 train
+wczbchfnad 1 300 train
+wczeysgrys 1 300 val
+wczgyxmjnt 1 301 train
+wczmozxmdq 1 300 train
+wczpzvngzy 1 300 train
+wczqgzkbfk 1 241 train
+wczunnsfsw 1 300 train
+wdafpwgevq 1 300 val
+wdakzidfvv 0 300 train
+wdalfxivcx 1 300 train
+wdamflywsr 1 300 val
+wdamxsyytq 1 300 train
+wdaqdlvpwc 1 298 train
+wdargiqojp 0 300 val
+wdarrvkhsj 1 301 train
+wdavnujllg 1 301 val
+wdbacykmas 1 298 train
+wdbekjaggq 0 300 train
+wdbhkeiksl 1 300 train
+wdbhlmkdlc 1 300 train
+wdbkscizzo 0 300 val
+wdblvqyxyx 1 300 train
+wdbojfpkpd 1 300 train
+wdbqcctmev 1 300 train
+wdbvcayfrv 1 300 val
+wdbzmwrhtm 0 301 train
+wdcaxqeexp 1 300 val
+wdcbriukep 1 298 train
+wdcgykplwk 1 300 train
+wdchhgqbvo 1 300 val
+wdcpfuktuz 1 300 val
+wdcrhqtjhf 1 300 test
+wdcsmnfryn 1 249 train
+wdcynnazsq 1 136 train
+wdczlkfigr 1 300 train
+wdczohojva 0 300 val
+wddcyyyzqt 1 300 train
+wddhtmtnfk 1 300 train
+wddowvydtj 1 300 val
+wddsnkeghb 1 300 train
+wdduxdkkjh 1 300 train
+wdejfzljob 1 300 train
+wdejrmoyqc 0 301 train
+wdeomkqphx 1 300 train
+wdewictsdp 1 297 train
+wdewjtppey 1 300 val
+wdeyhdtczz 1 300 train
+wdfaepjpmv 0 301 train
+wdfbybgdnu 1 300 train
+wdfdvsazip 1 301 train
+wdfeezhsnk 0 300 val
+wdfezjypsf 1 301 train
+wdfgbyqdbn 1 300 train
+wdfnctbnru 1 300 train
+wdfonpthis 1 300 train
+wdfpiakijc 1 240 val
+wdfsehboox 1 300 train
+wdfxoezbbd 1 300 train
+wdfyezgwlx 1 300 val
+wdfzektepw 1 300 train
+wdgkajbgrg 1 240 train
+wdgkxihibu 1 300 val
+wdglwreetr 1 300 val
+wdgonxedkz 1 300 train
+wdgsdwsisj 0 300 train
+wdgswsxmpm 1 300 train
+wdgtjdnkro 1 300 train
+wdgzjksmht 1 300 train
+wdhbbkpdmy 1 300 train
+wdhcifldqh 1 300 val
+wdhfkfsraq 1 300 train
+wdhgcyidkt 1 300 val
+wdhhwfarpq 1 301 train
+wdhlvxigtr 0 300 train
+wdhqursqsw 1 300 val
+wdhqxcuysv 1 301 train
+wdhuwccdoa 1 300 train
+wdhvvkuwuq 1 300 test
+wdhxyuupmq 1 299 test
+wdiaqozpwe 1 301 val
+wdibrxgjni 1 300 val
+wdighnmqmu 1 300 train
+wdimntshsq 0 300 train
+wdisiugwzf 1 300 train
+wdizvgasiw 1 300 train
+wdjakibrey 0 300 train
+wdjjqrpidu 1 300 train
+wdjjrlzxyb 1 301 train
+wdjtcnjhxc 1 300 train
+wdjwaikjsj 1 300 train
+wdkofkdyrj 1 300 val
+wdkptmgkvp 0 300 val
+wdkqcgvcuc 1 301 val
+wdkrmyjita 1 301 val
+wdkttasjkq 1 300 train
+wdkueylvan 1 297 val
+wdkuqtcbzn 1 300 val
+wdldbjukvc 1 300 train
+wdleuwxqbi 1 300 val
+wdlsseyqzz 1 300 train
+wdltlvjooq 1 299 test
+wdmchegcio 1 300 train
+wdmddrpxca 1 300 train
+wdmiozfxer 0 300 train
+wdmjqlfrex 1 240 train
+wdmsbcmkzf 1 300 train
+wdmsefrxuh 1 300 train
+wdmxusxtlu 1 143 train
+wdnahfjjnj 1 300 train
+wdncfnhwto 0 300 val
+wdnfflixfp 0 300 train
+wdnozozckw 1 300 train
+wdnqklbqqc 1 300 val
+wdnvdcndwd 0 300 train
+wdodfdspgn 1 300 train
+wdopsqexah 1 300 train
+wdornezycd 1 300 train
+wdpgeewsfu 1 300 train
+wdpmkslapo 1 300 train
+wdpnfdlbgm 1 300 train
+wdpqxqapnv 0 300 train
+wdpsifpppf 0 301 train
+wdpsjixfue 0 301 train
+wdpvogcmmo 1 300 train
+wdqbtyqfkp 0 300 train
+wdqjpnxdtj 1 300 train
+wdqwtrbujn 1 300 train
+wdrgezpufy 1 300 val
+wdrmfouvjj 1 300 train
+wdrwvzbyqu 1 301 train
+wdryqahivw 1 301 train
+wdstmdrcil 1 300 train
+wdsvnqckah 1 300 train
+wdsxnkwhgu 1 300 train
+wdtdmkamkg 1 300 val
+wdtitxrfrh 0 300 train
+wdtjgdgnwq 1 300 train
+wdtnlcsmky 0 300 train
+wdtoumzbzd 1 300 train
+wdtstnmfsu 1 241 train
+wdtynlmcbv 1 300 train
+wdubzoxota 1 300 train
+wduchluqem 0 301 train
+wdudwghddu 1 300 train
+wdukmquzms 1 296 train
+wduqmznmym 1 300 val
+wduqqzrjqu 1 299 train
+wduqzhjsaq 1 298 train
+wdutdmuymr 1 300 train
+wduxmovedo 1 298 val
+wdvcgeauhu 1 300 train
+wdvmvtxtea 1 300 test
+wdvzlubzlr 1 298 train
+wdwiasclid 1 300 train
+wdwlrpoluq 1 301 train
+wdwohqxcvu 1 301 train
+wdwtxqosdc 1 300 train
+wdwxffgjab 1 300 train
+wdxhpkglvc 1 300 train
+wdxhtjvepo 1 300 train
+wdxncoxvsa 1 300 val
+wdxpipozvj 1 300 train
+wdxpppuxbe 1 300 train
+wdxtagpbeq 1 300 train
+wdxvdhlinc 1 300 train
+wdycpqchcn 1 300 val
+wdymodypoo 1 300 val
+wdyqozotdb 1 300 train
+wdysyqjwtw 1 298 train
+wdyzqwntoe 1 300 test
+wdyzzjzfdl 0 99 train
+wdzefhhcwt 0 300 val
+wdzhairokh 1 301 val
+wdzhfbnqmo 1 300 train
+wdzjppgkrq 0 300 train
+wdzldsjigx 0 300 train
+wdzloskajz 1 301 train
+wdzmnfhggz 1 300 train
+wdzobfuurv 1 300 train
+wdzoqzhxqa 0 300 val
+wdzrotmddf 1 298 train
+wdztudnjav 1 300 val
+wdzvmfiste 1 300 train
+wdzvtcyjuj 1 300 train
+weacbbuzyw 1 300 train
+weadapjagk 0 300 train
+weadnmzvzp 1 300 train
+weajkfxecl 1 300 train
+weandglxdp 1 300 train
+weapvdlcqm 1 300 train
+weavaatvho 1 300 train
+weavzfxjyl 1 298 val
+weayxefxch 1 300 train
+weazwvacod 1 300 train
+webckzlkmz 1 300 train
+webglcyckc 1 300 val
+webphdlozj 1 301 train
+webrimfvtt 0 300 train
+websfjgutg 0 301 train
+webtntciwo 0 300 train
+webyiqztha 0 300 train
+webzbvjxwo 1 299 test
+webznbrpcd 1 300 val
+wecdyinews 0 300 train
+weciwkccls 1 300 train
+wecmkjuisc 1 300 train
+wecoffyppz 1 300 train
+wecrmcismv 1 288 train
+wecwdkrpqg 1 300 val
+wedcpwykvg 1 300 val
+wediirbvdv 0 300 val
+wednxyugdb 1 300 train
+wedoghnkxh 0 300 val
+wedpftdihf 1 300 train
+wedyarmcvw 0 300 val
+wedzanatii 1 296 train
+weeafueyor 1 300 train
+weecilkiro 1 300 train
+weedqhoucd 1 300 train
+weefgzeiss 1 300 val
+weefzjbwsd 1 300 train
+weegoldkhf 0 300 train
+weeisgxzan 1 300 train
+weeivalxij 1 300 train
+weektplqak 0 300 train
+weemqgwewz 1 300 train
+weeqaeyjgo 1 296 val
+weexsxqrfz 1 300 train
+wefbhzmope 1 300 train
+wefgfotpqq 1 300 train
+wefnnwphmx 1 300 train
+wefpcyviem 1 300 train
+wefppgfedd 1 300 train
+wefqqkzlsv 1 300 val
+wefwgobwvc 1 300 val
+wefzoodgzq 1 300 train
+wegdzrspni 1 298 train
+wegixyltvu 1 300 train
+wegjhmzauw 1 300 val
+wegsexmajl 1 300 train
+wegungithy 1 300 train
+wegzajacex 1 300 train
+wehiwkddfu 0 301 train
+wehlixqebk 1 300 test
+wehtngqjxl 0 300 val
+weicpsauqx 1 300 val
+weiiyzemxs 1 300 train
+weimfflcqa 1 300 val
+weiuwbkdmm 0 300 train
+weizzhbowa 1 300 val
+wejapyzpbg 1 300 train
+wejevgjzeg 1 300 train
+wejmkcaien 1 300 val
+wejnjntkop 1 300 train
+wejqgsbysi 1 300 train
+wejvlpuesv 1 300 val
+wejwwupaik 0 300 train
+wekhxtinfx 1 300 train
+wekiwxapcm 0 300 train
+wekjizzdnr 0 300 train
+weknpuedwc 1 300 val
+wekvtahsgt 0 300 train
+welqkfcxzs 1 300 train
+weltyzkxfi 1 300 train
+weluahjayz 0 300 train
+welvauuxtk 1 300 train
+wemafqijor 1 300 train
+wemcysqjqg 1 298 train
+wemlulrzyn 1 300 train
+wemmxongrq 1 300 train
+wemnttlkzs 1 300 train
+wemqzoirng 1 298 val
+wemyjszqwx 1 299 train
+wemzpkinhk 1 300 train
+wenaoepxqb 1 300 train
+wengshxcnt 1 300 val
+wenokelglj 1 300 train
+wenuooympy 1 300 train
+wenvrplbwm 1 300 train
+wenwfrfcxp 1 300 train
+weocjrsseb 1 300 train
+weoeyxayeb 1 300 val
+weojjhprvp 1 300 train
+weolhjitcr 1 300 train
+weoljswltl 1 300 train
+weolvarpnq 1 300 train
+weorueggqi 1 300 train
+wepgcmncio 1 301 train
+wepheifffq 1 297 train
+wepkjtrppg 1 300 train
+wepyuhvezr 0 300 train
+wepyyehyzc 1 300 val
+weqlrboaef 1 302 train
+weqontqqhu 1 300 train
+wequgxsvxz 1 241 train
+wequwopjzq 1 300 train
+weqzcxzmrt 1 300 train
+werajjylcz 1 299 train
+werbixgrnt 1 300 train
+werlbvidvc 1 300 val
+weruepdgcd 1 300 train
+wervsihhmx 0 300 val
+werxiyabwf 1 300 val
+wesevwqryy 1 300 train
+wesfjdkwfn 1 300 val
+weskrryixa 1 300 test
+weslpkwtum 1 300 train
+wesnaptbrn 0 301 train
+wespklvmtp 1 300 train
+wesqlxsugc 1 301 train
+wesuycpyfi 1 300 train
+weswgpmomf 0 300 train
+wetemidcey 0 300 train
+wetheuhcha 0 301 train
+wethlpqjfq 1 300 train
+wetiddlmvf 1 300 train
+wetjdexndk 1 301 train
+wetquclipj 1 301 train
+wetwwizxnc 1 300 train
+wetxiumbte 1 300 train
+wetxtmuqbk 0 300 val
+wetzxtlqsu 1 300 train
+weueykzwsc 1 300 test
+weukwfnxfv 0 300 train
+weumbyyafm 1 300 train
+weuofjclhu 1 300 train
+weuqiknfgg 1 300 train
+weuwmsvsab 1 300 train
+wevaxsbyxd 1 300 train
+wevfueqyzy 1 300 train
+wevghdmqfm 0 300 train
+wevgokxxdj 1 300 train
+wevhybrgah 1 300 train
+wevregbfem 1 300 val
+wevscpnakv 0 300 train
+wevygelkrl 1 300 train
+wewawvsqlo 1 300 train
+wewcuhfxvw 1 300 train
+wewgyhtkqn 1 300 val
+wewmaulmxp 0 300 train
+wewpryxgrr 1 300 train
+wewvgopijp 0 300 train
+wewwfqwutz 1 300 val
+wewxquevzv 1 300 train
+wexlpxbfde 0 300 val
+wexmrpsaxu 1 300 train
+wexolpfvcl 1 301 val
+wexrpfohgb 1 300 train
+wexrwnpacs 1 300 val
+weyakuslmc 0 300 train
+weyaufavnr 0 300 val
+weyftpcbbz 0 302 train
+weyobbfsyi 1 300 train
+weyytoiztb 0 300 val
+wezdcdqokb 1 300 train
+wezixwqvbf 1 300 train
+wezyzowkwh 1 300 test
+wfaksjbvuh 0 300 train
+wfakuaafek 1 300 train
+wfamafxoyu 1 300 train
+wfaorlslor 1 300 train
+wfaujeyhne 1 300 train
+wfbcyjpvkb 1 300 train
+wfbfkkmxiz 1 300 train
+wfbqqomqmm 1 300 test
+wfbsgbgoxn 1 300 val
+wfcbpbwjsi 1 301 train
+wfchpcdbwv 1 300 train
+wfcottlcnd 1 300 val
+wfcpymyjbo 1 300 train
+wfcufxqxms 1 300 train
+wfdaedqvwc 1 300 val
+wfdepxayyw 1 249 train
+wfdhdbgvzm 1 301 train
+wfdhlzcncz 1 300 train
+wfdkhuappf 0 300 train
+wfdkvfpvbe 1 300 train
+wfdlblolif 0 300 train
+wfdlwplbci 0 300 train
+wfdteinwrg 1 300 train
+wfdtztengo 1 298 train
+wfdwtvhyzv 1 294 train
+wfdyaffsfj 1 300 train
+wfecziomie 0 300 train
+wfegbyszzq 1 300 train
+wfeggehgfn 1 300 train
+wfevlmiwco 1 300 train
+wffaplgfgn 0 300 val
+wffenwrkeq 1 299 test
+wffpfogivh 1 300 test
+wffpozbege 1 298 train
+wffrogdzbg 1 300 train
+wffvntfpfy 0 300 train
+wffykpcqun 1 300 train
+wffyvnejsq 1 301 train
+wfgcquoxzr 1 300 train
+wfgelanyvu 1 300 test
+wfgeptqlkv 1 300 val
+wfgfsbxqtf 1 300 train
+wfghfyvyfm 1 300 val
+wfgjfkmzkm 1 300 val
+wfgjidrquw 1 298 val
+wfgksfkuqd 1 301 val
+wfgrlmkaae 1 300 train
+wfgszrajcm 1 300 train
+wfgupxdioe 0 300 train
+wfgvemlxwq 1 300 train
+wfhddwrima 1 300 train
+wfhekrdvoq 1 298 train
+wfhhejwile 1 300 val
+wfhllbcvkq 1 300 train
+wfhpfqyrdg 1 300 test
+wfhqdmxybz 1 300 train
+wfhtynssbm 1 241 train
+wfhwotidis 1 300 val
+wfhyepctyv 1 300 train
+wfidleglqk 1 300 val
+wfifqgubse 1 300 val
+wfighodvzq 0 300 train
+wfihrxuczo 1 300 train
+wfihvsniyz 0 299 test
+wfimiyhnpn 1 300 train
+wfivtrnapo 1 300 train
+wfixshtmyn 1 300 train
+wfjahjzmuf 0 300 train
+wfjcilxofl 0 300 train
+wfjiflsxmn 1 300 val
+wfjmzuaxww 0 300 train
+wfjscimili 1 300 train
+wfkidlexeg 1 300 train
+wfkqobfukg 1 300 train
+wfkujvlhvp 1 301 train
+wfkwapjhts 1 300 train
+wfkxfzpglp 1 300 train
+wflbuuhpzk 1 300 train
+wflkiyvyqh 0 300 train
+wfltxqmlvo 0 300 val
+wflygwwijx 0 300 train
+wflzjovedm 1 300 train
+wfmdmbsjhy 0 300 val
+wfmeffvvce 0 300 train
+wfmgruqquc 0 300 val
+wfmqqboetr 1 299 val
+wfmxkxwhqp 1 301 val
+wfmxpuzxwe 0 300 val
+wfmyawhzax 1 300 val
+wfnelvowvg 1 300 train
+wfnfelbxnz 1 300 val
+wfnfpflpwz 1 241 train
+wfnjmnhmax 0 300 train
+wfnkdeizlp 1 300 train
+wfnlaftfac 1 300 train
+wfnlosmzis 1 300 train
+wfnvvrovkq 1 300 train
+wfnvzzevvc 1 300 train
+wfogcddvxz 1 300 train
+wfohnuoseg 1 300 val
+wfokdoloyz 1 300 train
+wfonwxyuly 1 300 val
+wfoubyslvu 1 300 train
+wfovmbxkor 1 298 train
+wfowfmmzto 1 301 val
+wfpdzdapqe 1 300 train
+wfpjjuxmiu 1 300 train
+wfpornfesv 1 300 train
+wfpunjtoee 1 300 train
+wfpvaenfjz 1 300 train
+wfpvkkxoia 0 300 train
+wfqcftvejn 1 300 train
+wfqcondnoq 1 300 train
+wfqctmmdkv 1 300 val
+wfqfpeuczb 1 300 train
+wfqgizxkww 1 301 train
+wfqlqxgtmc 1 300 train
+wfqmikiukn 1 300 train
+wfqqeykavq 1 300 train
+wfqsjudeok 1 300 train
+wfqukrdqot 1 300 train
+wfqurpfpmy 1 300 test
+wfqwlgdawn 1 300 train
+wfrdbsdyis 1 300 val
+wfrfrbuuga 1 300 train
+wfrjwfmkkv 1 300 train
+wfrkjyusxh 1 299 val
+wfrqudwtmb 1 300 train
+wfrsuhbxog 1 300 val
+wfrxbuteyq 1 298 train
+wfsbpofrws 1 300 train
+wfsqddoonu 1 300 train
+wfsrqfpsmh 0 300 train
+wfstkgaqgy 1 300 train
+wfsvuyhlvt 0 300 train
+wfsxvggzah 1 300 train
+wfsyvgiqqv 1 298 train
+wfsywbvbna 1 300 train
+wftahgwygi 1 302 train
+wftarxtbkk 1 300 val
+wftayzvvev 0 300 train
+wftjehygov 1 300 val
+wftkobkpsz 1 300 train
+wftmbvvxqs 1 298 train
+wftoukwgtk 0 300 train
+wftrpkkmvf 1 300 train
+wftyxlbzhq 1 300 train
+wftzbnqebf 1 300 val
+wftzeobawk 1 301 train
+wfudzmubsc 1 300 train
+wfuflkmrbl 1 300 train
+wfugqfvekh 1 300 test
+wfuhomoqcj 1 300 train
+wfuhqjbxtg 1 300 train
+wfuhwqrjgp 1 300 train
+wfumhclmcx 1 299 train
+wfunzfmcbs 1 300 train
+wfurdxubir 1 300 train
+wfusubuhhm 1 300 train
+wfuwzwkqvm 1 300 train
+wfuyduebtv 1 300 train
+wfuywqqkrt 1 299 test
+wfvcdhgtbi 1 300 val
+wfvibrawqm 1 300 train
+wfvipujbic 0 300 train
+wfvjyelmsr 0 300 train
+wfvtbscder 1 300 val
+wfwpftrqxx 1 299 val
+wfwpmwpuzk 0 300 val
+wfwsetddha 0 301 train
+wfxjifazcq 1 300 train
+wfxkwlmjlv 1 300 val
+wfxsepsnxb 1 300 train
+wfxtkkhebo 1 300 train
+wfxxhdlwxf 1 300 val
+wfxxvzswfg 1 300 train
+wfxyxrwdea 1 300 val
+wfyacooedg 1 300 train
+wfypremyfb 1 292 val
+wfyslosrax 1 300 train
+wfythnvztb 1 300 train
+wfyyfhrwcw 1 300 train
+wfzaaocega 1 301 train
+wfzdajooqb 0 300 train
+wfzfpjtecf 1 300 train
+wfzfwlocbv 1 300 val
+wfzgksqequ 0 300 train
+wfzhpqxgma 1 300 val
+wfzjxzhdkj 0 300 test
+wfzomvimem 1 301 val
+wfzramxbvi 1 300 val
+wfzxrfxohw 0 300 val
+wgadaxsdxf 1 300 val
+wgafduokly 1 300 train
+wgaghjuwez 1 300 train
+wgahunfdff 1 300 train
+wgajsougua 1 241 val
+wgaluxpmfe 1 300 train
+wgapnntrdc 1 300 val
+wgbbuxfsoe 1 300 train
+wgbkcqnkao 1 300 train
+wgbmiiaomb 1 300 train
+wgbvdhhngh 1 241 train
+wgcaothoxl 0 300 train
+wgcgqvntuy 0 300 train
+wgcjvhnjxr 1 300 train
+wgcnotpqeh 1 299 val
+wgcqiookwh 1 241 train
+wgcrxowuzt 0 300 train
+wgdchltqfh 1 300 train
+wgddfhuvoq 1 300 test
+wgdgtysmab 1 300 train
+wgdkqnruxb 1 300 train
+wgdmntidxn 1 300 train
+wgdnrufvjw 1 300 val
+wgdqfuadec 1 300 val
+wgdsalpjhv 1 270 train
+wgdttcpodm 1 300 train
+wgeeeyqpxk 1 298 train
+wgefyecmrc 0 300 train
+wgekoqdgny 1 300 train
+wgewdzlici 1 298 train
+wgezbnbyan 1 241 train
+wgfdoqcunc 1 301 val
+wgfgepdypu 1 300 train
+wgfidnxfdu 1 300 train
+wgfidwalea 1 300 train
+wgfimyyonx 1 300 train
+wgfmaikyin 1 300 val
+wggbecccla 1 300 train
+wgghxmydjb 1 300 val
+wgghzzunsp 0 300 val
+wggjumisno 1 241 train
+wggnvhltjo 1 300 train
+wggseropki 1 301 train
+wggsnlwcci 0 300 train
+wghcaavbrw 1 300 train
+wghdlvehhq 0 300 train
+wghkyxsgmi 1 300 train
+wghmafmcxz 1 300 val
+wghokboapu 1 300 train
+wghqjrelir 1 300 train
+wghuvnmapg 1 300 val
+wghvfbbckn 1 300 val
+wgiapfprph 1 300 train
+wgicfdvmii 1 300 val
+wgifgzkzog 1 300 val
+wgigiaznhn 1 300 train
+wginzoeejk 1 300 val
+wgiojoodyu 1 300 train
+wgionocrhk 0 300 val
+wgipqutduk 1 300 train
+wgiubssxye 1 300 train
+wgjeutkvqv 1 300 train
+wgjiesqhvs 1 300 train
+wgjjgidmdr 1 300 val
+wgjjkwixxf 1 300 train
+wgjqmxuxlo 0 300 train
+wgjuqjjiyp 1 300 train
+wgkeydcvej 1 300 val
+wgkixkzlvk 1 300 train
+wgklnmklxb 0 298 train
+wgkprrjgbj 1 241 train
+wgkuhqqfmc 0 301 val
+wgkxorvmtq 1 300 train
+wglaeeknxp 1 300 train
+wglovbedxu 1 301 train
+wgmbcqfgkp 0 300 train
+wgmfkaqppp 1 300 train
+wgmhlawtkd 1 299 train
+wgmhsapfeo 1 300 train
+wgmhyuxpjl 1 300 train
+wgmjelbsru 1 300 train
+wgmkhtwnri 1 297 train
+wgmlmeubsz 0 300 train
+wgmmtmlqxj 1 300 train
+wgmpnulkrh 1 300 train
+wgnkrmdudg 1 300 train
+wgnmktrtgx 1 300 val
+wgntgdnatf 1 300 train
+wgntrlqgou 1 300 train
+wgnujygkzy 0 300 val
+wgoelyubao 1 302 train
+wgoevxeyxj 0 300 train
+wgoikscjvl 1 300 val
+wgoxmkhqlv 1 300 train
+wgoyvnmjwu 0 300 train
+wgpdplwvwq 1 301 val
+wgpiwtjulu 1 300 train
+wgpmbgtayo 1 296 train
+wgpmpigjne 1 300 train
+wgpsjgjyci 1 301 train
+wgqgloycln 1 300 train
+wgqkfngwhk 1 300 train
+wgqlhxpvro 0 300 train
+wgqptridcs 0 300 train
+wgqsusjfci 1 300 val
+wgqubijutn 1 300 train
+wgqvvcrkci 1 302 val
+wgqxlqofbg 1 300 train
+wgrfzrdkqg 1 300 train
+wgrlttrxzo 1 300 val
+wgrripmxne 1 300 val
+wgrykwygnz 1 300 train
+wgsenzwsjp 1 300 train
+wgsfaaxkae 1 300 train
+wgslydpuvf 0 300 train
+wgsogwklkz 1 300 train
+wgspiygxdm 1 300 train
+wgsvouwkpe 1 300 train
+wgswphznis 0 300 train
+wgtasbplcj 1 300 train
+wgtdlmhdvy 1 300 val
+wgtffksmpz 1 300 train
+wgtgykboyz 1 300 train
+wgtjwbnaui 1 301 train
+wgtmthxikw 1 300 val
+wgtrqimuxj 0 300 train
+wgtxdrxzzu 1 300 train
+wgueijbvcs 1 300 train
+wgukicsxtf 1 300 val
+wguqentoiu 1 299 test
+wgusxqhklm 1 300 train
+wguzuevqxk 1 300 train
+wgvbltgmkl 0 300 train
+wgveczfyjy 0 300 train
+wgvgcrtcct 1 300 train
+wgvgzykgjh 1 300 train
+wgvjgjdhxg 1 300 val
+wgvklyzchl 0 300 train
+wgvpsthdan 1 300 train
+wgvvamvnnl 1 301 val
+wgvvnmfkyu 1 300 train
+wgvxdqdfol 1 301 train
+wgwhniunws 1 300 train
+wgwjixcfyk 1 241 train
+wgwknwkhcl 1 300 val
+wgwonzhpsm 1 300 val
+wgwsqupirx 1 300 train
+wgwtcbcnze 1 301 train
+wgwtkaniub 0 300 val
+wgwupnyscg 0 300 val
+wgxdjocbni 1 300 train
+wgxoacoprg 1 301 train
+wgxpmspqsp 0 300 train
+wgxzdmjxyu 1 300 val
+wgxzoorxfb 1 300 train
+wgycqahjww 0 300 train
+wgyikyzech 1 300 train
+wgylaldyma 1 300 val
+wgymxzipeu 1 300 val
+wgynyyhzrf 1 300 val
+wgysdlsqsr 1 300 train
+wgyuvkyedx 1 300 train
+wgyvrvrlam 1 300 train
+wgyxtquovo 1 300 train
+wgzcfcxljo 1 300 train
+wgzgexhqny 1 300 train
+wgzigaxpas 0 300 train
+wgziuzngqv 1 300 train
+wgznputozz 1 300 val
+wgzojtktxm 1 300 train
+wgzrhqihqt 1 300 test
+wgzrnjspbx 1 300 val
+wgzxvebcjf 0 300 train
+whaaecbouh 1 300 train
+whacxvjnyf 0 300 train
+whapqyycva 1 300 train
+whapuyfwuo 1 301 train
+whavdpjeza 1 300 train
+whawkommbm 0 300 train
+whazyyyaba 1 300 train
+whbknfcjtz 1 300 train
+whbuowllqi 1 300 val
+whbxafllos 0 300 train
+whbxmegtoq 0 300 train
+whcjfvwbmo 1 300 train
+whcndxbgww 1 300 train
+whcocqcpdn 1 298 val
+whcpszkhls 1 300 train
+whcrzevlil 1 300 train
+whcstdhmkf 1 300 train
+whcuavdzbo 0 300 train
+whcvxebrcb 1 300 train
+whcxqsyjrz 1 302 val
+whdawhamoy 1 300 train
+whdijawumf 1 300 val
+whdlwqwxxw 1 300 train
+whdmmwrjra 1 300 val
+whdrxadpxj 1 300 val
+whdsldoyms 1 300 val
+whdsqiezfs 1 300 val
+whdtnvuipr 1 300 train
+whdtvhdhlq 1 298 train
+whdujpfjrl 1 300 train
+whdukknppp 1 301 train
+whdwhmutkq 1 300 val
+whdwipuosf 1 300 val
+wheeozscgn 1 300 val
+whenoceqbc 1 300 train
+wherrrxgus 1 300 train
+whevvgxgis 1 300 train
+whewmbvccb 1 300 train
+whexbmwmbf 0 300 train
+wheyuvnwxe 1 300 val
+whfdwsqmrt 1 300 train
+whfdyvnska 1 300 train
+whffswfpqp 0 300 train
+whfntjazhf 0 300 train
+whfnyiavgp 1 299 test
+whfohevckh 1 300 val
+whgdxkzrgc 1 300 train
+whgewbjlmn 1 301 train
+whgfvrprxj 1 300 test
+whghgfejtv 1 301 train
+whghsysyqe 1 300 train
+whgmdrqkla 1 300 train
+whgynshfux 1 300 val
+whhmuvlaqe 1 300 train
+whhnuqkbpy 0 300 train
+whhrluqfbz 1 301 train
+whhsixqezj 1 300 train
+whiepoyiek 1 300 train
+whijyjefeg 1 300 train
+whimpibyvx 1 300 train
+whinjhdnkz 1 300 train
+whitruyxzu 1 300 train
+whixmoazmk 0 300 val
+whjftzzjwt 1 300 val
+whjmywcgid 1 300 train
+whjphkfaey 1 301 train
+whjruukdbv 1 300 train
+whjsoshoth 1 300 train
+whkeadfpnc 1 300 train
+whkimvklkw 0 300 train
+whkklqqwhh 1 300 val
+whklnxmbhj 1 300 train
+whkmwkevrb 0 300 train
+whkqmlphca 1 300 train
+whkrlhuqyg 0 300 train
+whlaztlswh 1 301 train
+whldccqxyd 0 300 val
+whlfpcoiiy 1 301 train
+whlmvorxly 1 300 val
+whlmvzuukw 1 298 train
+whlvxqqeob 1 300 train
+whlwupiuyq 1 300 train
+whmfatlqlv 1 300 train
+whmhqxdawx 1 298 train
+whmihriwfw 1 300 train
+whmonfcgwv 1 300 train
+whmpjkrwii 1 301 val
+whmuxyerwr 1 300 train
+whmuyzgdrh 1 300 train
+whmxhrwjus 1 300 train
+whmysxdudf 1 300 train
+whnbgzejdu 1 300 train
+whndyvyxid 1 240 train
+whneslhtcb 0 292 val
+whnhzzpgqz 1 300 train
+whnjoxfzcb 1 301 train
+whnudzrizn 0 300 train
+whnwgnmstd 1 300 val
+whnxagaazs 1 300 train
+whoblwbaww 1 298 train
+whocnbawsb 1 300 train
+whocrmxvqn 1 300 train
+whoffjnvky 1 300 train
+whogoapjje 1 300 val
+whomtrxofb 1 300 train
+whonhekqwg 1 300 train
+whoufcajgr 1 300 train
+whoumpjgxu 1 300 val
+whouwprivm 0 300 train
+whpccifotw 0 300 train
+whpdkjcrnt 1 237 train
+whpdmcjjhv 1 300 train
+whpktkqmls 1 298 train
+whpmskbqhw 1 300 val
+whpwsctanc 1 300 test
+whpyhuicpe 1 300 test
+whpynbgnhr 1 300 train
+whqcgvgvcq 1 300 train
+whqfcwfuih 1 300 train
+whqjqnbivg 1 300 train
+whqjwuqcek 1 300 val
+whqksmxyvz 1 300 train
+whqlxampuk 1 300 val
+whqovqzknc 1 300 train
+whqoyablqh 1 300 train
+whragbjpdp 1 300 val
+whrmienink 0 300 train
+whrotngqvs 1 300 val
+whrtpqhyrc 1 300 train
+whrykekthg 1 300 train
+whsbzsttzy 1 300 train
+whsdrgnrew 1 300 train
+whsejdjtsv 1 300 train
+whsfrnglgk 1 300 val
+whsgglurhh 1 300 train
+whsikwfkzv 1 300 train
+whsjrsjfzu 1 241 train
+whsqzlklam 1 300 train
+whsyqitobw 1 299 test
+whsywztptg 1 300 train
+whtffdhnvo 1 300 train
+whtgnseqen 0 300 train
+whtiqqpjwg 0 300 train
+whtjixlito 1 300 train
+whtmiuwmij 1 301 train
+whtnknkxul 1 300 train
+whtrmmevij 1 300 train
+whttnzfnno 1 300 train
+whtwlyhaez 0 300 train
+whtwurxrlg 0 300 val
+whuftrcnun 0 300 train
+whuixruojw 1 300 train
+whurggewea 0 300 train
+whuroxbmeb 0 300 train
+whusuiiqmt 1 300 train
+whuuyvlniq 0 300 train
+whvfsbhtzp 1 300 train
+whvgbpiqym 1 300 val
+whvxhwihnw 0 300 train
+whvznhsksm 1 300 train
+whvzrqbyxb 1 299 val
+whwamfbbgl 0 300 train
+whwgqnexeu 1 300 val
+whwlgbhjze 1 300 val
+whwqrltcsw 1 300 train
+whwzeetmij 1 300 val
+whwznxpssr 1 297 train
+whxbqwrkfq 1 300 train
+whxdrwokyw 1 300 train
+whxkvxzupx 0 300 train
+whxpqgywii 0 300 train
+whxqigkgyk 1 301 train
+whxsttlmxb 0 300 val
+whybpccwyn 1 300 train
+whyflhctml 1 300 train
+whygzcutmr 1 300 train
+whyivynzme 1 300 train
+whypsiiwaf 1 300 train
+whyyoyfdil 1 300 train
+whyytqqozs 1 300 val
+whzbgpbysc 1 300 train
+whzdpvroaf 1 300 train
+whzfxmhtzp 1 300 train
+whzghihvpj 0 300 train
+whzqvqmwbz 1 300 val
+wiaabzyupm 1 300 train
+wiahbxowps 1 300 val
+wiahmjbujk 1 300 train
+wiaiztlfzg 0 298 train
+wiajzozjlg 1 300 val
+wiapiercjk 1 300 train
+wiaqeabrqx 1 300 train
+wiarhvynhd 1 300 train
+wiastkfeee 0 300 train
+wibcwbhmtw 1 300 train
+wibhouoypv 0 300 train
+wibskravnb 0 147 train
+wibvzcwsed 1 300 train
+wicezznelv 1 300 train
+wicmkzwotp 1 300 train
+wicmufgnkm 1 300 train
+wicrqroazr 1 300 train
+wicszikqmg 1 300 train
+widacqadcw 0 300 train
+widixpakle 1 300 train
+widuwuoiur 1 300 train
+wiesvdoded 1 300 train
+wieyqxzqaw 0 300 train
+wiezacumeb 1 301 train
+wifadtngcb 1 300 train
+wifahkzivj 1 300 val
+wifddsdmnr 1 300 val
+wifmsniiws 1 300 train
+wifmzlfzxt 0 300 train
+wifosdehgx 1 300 test
+wifosicfzl 1 302 train
+wifteybbaz 1 300 train
+wifytkslgg 1 300 train
+wigcnigdrw 1 300 train
+wiggtnzjyi 1 300 train
+wigovvvifj 0 300 val
+wigsgjriah 1 300 train
+wigvdfttvd 1 300 train
+wigvufxjlt 1 300 train
+wigzumhqeg 1 300 train
+wihjnuxjjd 1 300 train
+wihlijilot 1 241 train
+wihwapvkkp 0 300 train
+wihxahqfwx 0 300 val
+wihyiwbmop 1 99 train
+wiibkhtofj 1 300 train
+wiieckkyll 1 300 train
+wiijvlcrvf 1 300 train
+wiiqwvxvqw 1 300 train
+wiivttlycd 1 300 train
+wiivzalzkj 1 300 train
+wijglmnfim 1 301 train
+wijivnlimz 1 300 train
+wijkrpfefx 1 301 val
+wijsiskflp 1 300 val
+wijsyrvfcn 1 300 train
+wijtbepopj 1 301 train
+wijwbliggv 1 300 train
+wijxpzqwny 1 147 train
+wikbszqloq 1 299 val
+wikcluuurj 1 99 train
+wikimrfezq 1 300 train
+wikivxzqhf 1 300 train
+wikmlgmwux 1 300 train
+wikovzsmwg 1 301 train
+wiksdqrdai 0 300 train
+wikteupetl 1 300 train
+wildyxdllm 1 300 train
+wilfhfcdmj 1 300 train
+wilfnlcsws 1 300 train
+wiljapzyyn 1 300 train
+wilkbkdlzn 1 301 train
+wilpwczcss 1 300 train
+wilqdbdllh 0 300 train
+wilswzogxn 1 300 train
+wilxvvmdmp 1 300 val
+wilyayimlj 0 300 train
+wimbntkoha 0 300 train
+wimdsuuvuo 1 301 train
+wimesowura 1 300 train
+wimfcxyaoi 0 297 train
+wimfnbfrhu 1 300 val
+wimfwyxqoz 1 300 train
+wimiizmsaj 1 300 train
+wimqdqazsf 1 300 train
+wimqhvyeto 0 300 train
+wimuvimnvz 1 300 train
+wimvqtlsaa 1 300 train
+wimwvvmqkb 1 300 train
+wimymsqyax 1 300 train
+winazjnkzh 1 300 train
+winfraqcmb 1 300 train
+winfzosmgf 0 300 train
+wingxtmuyy 1 300 train
+winigkdsri 1 301 train
+winjhwexch 0 301 train
+winlzqoque 1 300 train
+winsaloubg 1 298 val
+winzkykhjj 1 300 train
+winzwcodje 1 300 train
+wiodroakkr 1 300 train
+wiojkkefir 1 298 val
+wiourzkzhl 0 300 train
+wiouwlashq 1 300 train
+wiouxielyd 1 300 train
+wioxcubcnc 1 300 train
+wipbbotmtl 1 300 train
+wipdgljgkr 1 298 train
+wipdkmbnrs 1 300 val
+wipegsvwqx 1 300 train
+wipftrplom 1 301 train
+wipoxzlrml 1 300 train
+wiptqcblgh 1 301 val
+wiqdiiskbi 0 300 val
+wiqdobisno 1 301 train
+wiqhrbsfoj 1 300 train
+wiqlevukih 1 300 val
+wiqlpmenil 1 300 train
+wiqmlyydvl 1 300 val
+wiqnhlayat 1 300 train
+wiqnwcizhc 1 300 val
+wiqpqgigmb 1 300 val
+wiqpzuqjhl 1 300 train
+wiqtkqwfsw 0 300 train
+wiqxgptfar 1 300 train
+wiqxnnotxa 1 241 train
+wirblaouzv 1 300 test
+wirdaebvyh 1 300 train
+wirednjdjt 1 240 val
+wirfnucuua 1 300 train
+wirnofcwpj 1 300 train
+wirrqskncd 1 300 train
+wirxxsutua 1 300 val
+wiryyniipz 1 300 train
+wisekeyeqh 0 300 val
+wishixpbsg 1 300 val
+wiszpsosqq 0 300 train
+witdmnwioz 0 300 val
+witduijexp 1 300 train
+witfoferki 1 300 train
+witjzcczsh 1 300 train
+witsyqmniy 1 300 train
+wituahqcbz 0 300 val
+witzdrryqk 0 300 train
+witzoinzvo 1 300 train
+wiubifhvrn 1 300 train
+wiucngpxdb 1 300 train
+wiugvfhuic 0 297 train
+wiumuudxeh 1 299 val
+wiunsyfana 0 300 train
+wiutgswibc 1 300 val
+wiuyswqzep 0 300 val
+wivbvrgvrb 0 300 val
+wivjejqcpw 1 300 val
+wivnhyxecw 1 300 train
+wivtjlzfdc 1 300 train
+wivvhcghpj 1 300 train
+wivvpxqwjm 1 300 val
+wivwkeceqg 1 300 val
+wiwdeadthn 1 300 val
+wiwgxgxexo 1 300 train
+wiwjmzsvse 1 300 val
+wiwnnundmd 1 300 train
+wiwtzjscyr 1 300 train
+wiwusfrevm 1 300 train
+wiwwxihjla 1 300 train
+wixamhpjea 1 300 train
+wixbuuzygv 0 300 test
+wixfcborhy 1 298 train
+wixgnqglrw 1 300 test
+wixklzfgtv 1 300 train
+wixmimgsqb 1 300 val
+wixujncvee 0 300 train
+wiyaihkozi 1 300 val
+wiybzaglwz 1 300 train
+wiyfrvlcal 1 300 val
+wiyqaqkswu 1 300 train
+wiytaphllp 1 300 val
+wiytrffzjp 1 300 val
+wiyyvzhxny 1 300 train
+wizboztwwm 0 300 train
+wizfegmwlq 1 301 train
+wizgqlhwhb 1 300 train
+wizwokrceh 1 300 train
+wizxwkxtrn 1 300 train
+wjakdxvkna 1 301 train
+wjbexdclie 1 300 val
+wjbezkpmlw 0 300 train
+wjbonjacrq 0 300 train
+wjbpogkzwb 1 300 train
+wjbpvjixdr 0 300 val
+wjbxxndmyc 1 300 train
+wjbzupwcge 0 300 train
+wjcceueaho 1 300 train
+wjcfgxahqh 1 300 train
+wjclipsrpg 0 300 train
+wjcrotcasg 0 300 train
+wjcteczhxq 1 298 train
+wjcwmqwkdh 1 300 train
+wjdaiwmilv 1 300 train
+wjdnmftvgk 1 300 train
+wjdprlklsn 0 300 val
+wjdqhgutru 0 300 train
+wjdxktgnvr 1 300 train
+wjdzvpqssp 1 300 train
+wjeeuorzhc 1 300 train
+wjelzkifwn 1 300 train
+wjesnindbk 0 300 train
+wjewnsibqo 1 299 val
+wjfaarobsg 1 300 train
+wjfeoichnb 1 300 train
+wjfinckiiz 1 300 train
+wjfjgybigt 0 300 train
+wjfjmtpmxo 1 143 train
+wjfpgayhty 1 300 val
+wjfpluuohk 0 300 train
+wjfuxsoonm 1 300 train
+wjfzrhsfvr 1 300 train
+wjgieovyyg 1 298 train
+wjhcvunert 1 300 val
+wjhhnnhjbi 1 300 train
+wjhlyohpuf 1 299 val
+wjhpisoeaj 0 300 test
+wjhqpzgicz 1 292 val
+wjhuumhiib 1 300 train
+wjiakveoqz 1 300 train
+wjifffemhm 1 300 train
+wjiklkawew 1 300 val
+wjilccyfwe 1 300 val
+wjilinpvsy 1 300 train
+wjiskacdmp 1 300 val
+wjiskihqqo 1 300 train
+wjiwvzydfq 1 300 train
+wjixbmipgn 1 300 train
+wjjeonpdjl 1 300 train
+wjjmpddtap 1 300 train
+wjjoqollas 1 300 train
+wjjqqdrxyr 0 300 train
+wjjrkayjjd 1 240 train
+wjjtaaztzf 1 301 train
+wjjtbxrqia 1 301 train
+wjjttlknjg 1 296 train
+wjjyzijfxg 1 300 val
+wjkbcgoegg 1 300 val
+wjkcknpamc 1 300 test
+wjkgvzphlr 1 300 val
+wjknicnryr 1 300 test
+wjkullbkff 0 241 train
+wjletbemlm 0 300 val
+wjliamjeqp 1 302 train
+wjllscdfky 0 300 train
+wjlmvjsncs 1 300 train
+wjlozvhhot 1 300 train
+wjmfgqxkge 1 300 train
+wjmgdhorkh 1 300 val
+wjmrgmppdm 1 300 train
+wjndqjmsje 0 300 train
+wjnfdnfqiy 1 299 test
+wjnfhwnoie 1 300 val
+wjnidkocqj 1 300 train
+wjnoyftjbj 1 300 train
+wjnuzooufw 1 300 train
+wjnxkyzjza 1 300 train
+wjofdmsref 1 300 train
+wjofiwnlyy 1 300 train
+wjoftgbkdy 1 136 train
+wjootfrwrq 1 300 train
+wjorrptner 1 300 train
+wjovoaidly 1 300 train
+wjovriuyvy 0 300 train
+wjoxvojixy 1 300 train
+wjoygwvvwf 1 300 train
+wjpbipinqe 1 134 train
+wjpceroqrx 1 300 train
+wjpcqfachl 1 300 train
+wjpeznrhww 1 300 train
+wjpxqnomab 1 299 train
+wjpzkwocal 1 300 train
+wjqdwzowcg 1 300 train
+wjqgjvdnag 1 300 train
+wjqlvukpjz 1 300 train
+wjqqxxabcv 1 300 test
+wjrepvzlsv 0 300 val
+wjrqrtqend 1 300 val
+wjruooxbhj 1 301 train
+wjsafkpnfo 1 249 train
+wjsbijgijx 1 300 val
+wjseloppwa 1 300 train
+wjsftxrqzj 0 300 train
+wjslbhjxdc 1 302 train
+wjsxxuciyt 1 300 train
+wjszamwliv 1 300 val
+wjtaovuksy 1 300 train
+wjtaxcqifj 1 300 val
+wjtjpqbrts 1 300 val
+wjtmkzhnlf 1 300 train
+wjtzscmyrq 1 300 train
+wjufizlyvw 1 294 train
+wjuslxjpyb 1 300 train
+wjuuqzqnbb 0 300 train
+wjuzpbmzwr 1 298 train
+wjvjtjgvhb 1 300 train
+wjvpahiuhw 1 300 train
+wjvsfurvix 0 300 train
+wjvulwubxo 1 300 train
+wjvvfrydbv 1 300 train
+wjwgfkyjev 0 301 train
+wjwpvfbxjy 1 300 train
+wjwrzpmlaa 1 300 train
+wjwuynimqt 1 300 train
+wjwwribfdr 1 300 val
+wjwxogvtkr 1 300 train
+wjxfaderai 1 299 val
+wjxibehpap 1 300 train
+wjxjolbxwz 1 300 train
+wjxmmjmchv 0 300 val
+wjxrbgkxvv 1 300 train
+wjxrlqcyvt 1 300 train
+wjxvzvzprt 1 300 val
+wjxxgbpflt 1 300 val
+wjxyrvwokt 1 300 val
+wjyardlrdx 0 300 train
+wjybfvhssr 1 300 train
+wjyegkytqf 1 300 train
+wjyjiibwdp 0 300 val
+wjykttglwn 1 299 test
+wjypybysuw 1 300 train
+wjysiybrdj 1 300 val
+wjytmmnvfm 1 302 train
+wjytumbccu 1 300 train
+wjyupidrlz 1 300 train
+wjzenzchmn 1 300 val
+wjzjsnjtra 1 300 val
+wjzrpcfvyv 1 300 train
+wjzypmjezi 1 300 train
+wkaitmsqjj 1 241 train
+wkajsuweae 1 300 train
+wkakkkowme 1 300 train
+wkanbdzfnu 1 298 train
+wkaojjcfag 1 300 train
+wkaracvivt 1 300 train
+wkbcpwthmx 1 300 val
+wkbdnatwkf 1 298 train
+wkbfyffbct 1 301 val
+wkbhodiaye 1 298 val
+wkbjnxyxqo 1 300 val
+wkbjpfcede 1 300 train
+wkbpresloa 0 300 train
+wkbqzgmmmn 1 300 train
+wkbrdphorp 1 300 train
+wkbxruxqna 1 300 train
+wkcbjmxlfx 0 300 train
+wkcccqarrb 1 300 train
+wkcffjdluo 1 300 train
+wkcgzkbwue 1 300 train
+wkckhxwket 1 298 train
+wkcovskjqg 1 300 train
+wkctmsuafr 1 300 train
+wkcuijaddk 1 300 train
+wkczijuamz 1 300 test
+wkdewpagvn 1 300 val
+wkdizumwgj 1 300 train
+wkdkvjtvje 1 301 train
+wkdnagybtb 1 300 test
+wkdzorhwfu 1 300 val
+wkebpcnjhb 1 300 train
+wkeevdsirt 0 300 train
+wkefoqudll 1 600 train
+wkenxmwkxc 1 136 train
+wkeqlffbdl 0 300 train
+wkevfzkbwg 1 300 train
+wkevskpaza 1 241 train
+wkfarafxbd 1 300 val
+wkffhlmfsy 1 300 train
+wkffpbgghy 1 300 val
+wkfjsqzatw 0 300 val
+wkfqpzpxbo 1 300 val
+wkfrdirbks 1 300 train
+wkfrqesjwp 1 300 val
+wkfumhhxhg 1 300 train
+wkfwvzhfpy 1 300 train
+wkgdylwhiz 1 301 train
+wkgmqyktye 1 300 train
+wkgnqiwhtz 1 299 train
+wkgnxvohlt 1 300 val
+wkgqovlfso 1 300 val
+wkgszsnwtz 1 300 val
+wkgueygsch 1 298 train
+wkgxzdoqha 1 300 train
+wkhasvjpkk 1 300 train
+wkhfspikjr 1 300 train
+wkhkbcmdpv 1 300 train
+wkhpggobmq 1 300 train
+wkhshwjvwl 1 300 train
+wkhyehqtzx 1 301 train
+wkhzxfxvqb 1 301 train
+wkimcgyvdg 1 300 train
+wkiohqafts 1 300 train
+wkiqbthroz 1 300 train
+wkixurgila 1 297 train
+wkjaebyftm 1 300 train
+wkjgklrhjl 1 298 train
+wkjhpzukba 1 269 train
+wkjivvdjcp 1 300 train
+wkjixufjbx 1 300 train
+wkjsxoscsi 1 300 val
+wkjtbmfupe 1 301 val
+wkkanqmtff 0 300 val
+wkkujiqffr 1 300 train
+wkkwpgjtfh 1 300 val
+wklbhxvfqw 1 300 train
+wklhogehdl 1 300 train
+wkliktcqzn 1 300 train
+wkljzwabqg 1 300 val
+wklrgvjlfd 1 300 test
+wklvdujzpx 1 297 train
+wklvpqcioc 0 300 val
+wklxuzscjk 1 298 val
+wkmdilzatq 0 300 train
+wkmhklcwrk 1 300 train
+wkmjfhlbhj 1 298 train
+wkmjjnoihk 0 300 train
+wkmnsbqhjo 1 300 train
+wkmpxylhum 1 300 val
+wkmsfikjaa 1 299 val
+wkmunnkybl 1 301 val
+wknaloiwwe 1 300 train
+wknazedpgu 1 300 train
+wkncznyxmr 1 300 val
+wkndqfgsqv 1 300 train
+wkndwtfzex 0 300 train
+wkneysnvyc 1 300 train
+wknfompqxl 1 300 val
+wkngcwczzv 1 300 train
+wknksoiaoq 1 300 train
+wknkvvtccv 1 300 train
+wknoqevfmw 1 299 test
+wknpfatwev 0 300 train
+wknulsawjv 1 300 train
+wknuqdschs 1 300 train
+wkofhslhdi 1 300 val
+wkoicnsjpp 1 240 val
+wkommtrbab 1 301 train
+wkonowlddi 1 300 val
+wkoqzslxrv 1 300 val
+wkoxurxilc 1 300 train
+wkoxxwextf 1 300 val
+wkpffpfhce 1 299 test
+wkpgwnttsn 0 300 val
+wkpngzmiil 1 300 train
+wkpvdjgekz 1 300 train
+wkqhhozlmd 0 300 train
+wkqpshykfy 1 300 train
+wkqpymzotc 1 300 train
+wkqtxhewzd 1 300 train
+wkrblrzfuo 1 300 train
+wkrdghadnr 1 300 val
+wkrhbeuvnv 0 300 train
+wkrivltdys 0 300 train
+wkroizxhbt 0 300 train
+wkrznuhrqj 1 299 test
+wksbmfzmdg 1 300 val
+wksesoohpq 1 300 train
+wksjezvlgk 1 241 train
+wksljtgqif 1 300 train
+wksmeabxsb 1 300 train
+wksotonppz 0 298 train
+wksrwwogyw 1 300 val
+wksybmxekv 1 300 train
+wktddmocmf 1 300 train
+wktdezchfx 1 269 train
+wktgdckobv 1 297 train
+wktholesnu 1 300 train
+wktsttvpwt 1 147 train
+wktximqubm 1 300 val
+wktxudokag 1 300 train
+wktyixzlhk 1 300 train
+wktyunnvrc 1 300 train
+wktzmsvbkj 1 300 train
+wkubkoeaui 1 300 train
+wkuhhgktpn 1 300 train
+wkuksbikzn 1 300 train
+wkupdirefo 1 300 train
+wkuqvzyxmx 1 300 val
+wkuuaywprz 0 300 train
+wkvdvgmknh 1 301 train
+wkvizfpiap 1 301 train
+wkvizgdpwc 1 300 train
+wkvmnknwdj 1 300 train
+wkwacdgjad 1 300 val
+wkwipohdkq 0 300 train
+wkwiwkbbsc 1 300 train
+wkwjypymey 1 300 test
+wkwmivfzzc 1 300 val
+wkwokaovyn 0 300 train
+wkwowsyejc 1 300 val
+wkwqblmohw 0 300 train
+wkwqlcckmx 1 300 val
+wkwurlkrnq 1 300 val
+wkwwadqvwd 1 300 val
+wkwwpmocfo 1 300 train
+wkxalrzefe 1 301 train
+wkxcgqrvqd 1 300 train
+wkxdmvixzi 1 300 val
+wkxetlcczy 1 300 train
+wkxfdajvui 1 300 train
+wkxftmoqsy 0 300 train
+wkxgniqnao 0 301 train
+wkxhyafkce 1 300 train
+wkxicmvtey 1 301 val
+wkxisndzma 1 300 train
+wkxouifkzc 1 300 test
+wkyftsfazg 0 300 train
+wkygntyiaj 1 300 train
+wkyiwauxag 1 300 train
+wkyjywobwt 1 300 train
+wkyksihrjj 1 300 val
+wkymakhxec 1 298 train
+wkyoaybzxb 0 300 train
+wkyvdvxuec 1 301 val
+wkzapqqxyi 1 300 train
+wkzepskrhs 1 241 train
+wkziczvsvi 1 300 train
+wkzkvrclob 1 301 train
+wkznwcrkfl 1 300 train
+wkzwofikgx 1 300 train
+wlachmspos 1 300 train
+wladqmjswf 1 301 train
+wlagevfvcr 1 300 val
+wlaupbidru 0 300 train
+wlbgkanqxl 1 298 train
+wlbozvwpwl 1 300 train
+wlbsazzjdb 1 300 train
+wlbspibmfg 1 300 train
+wlbvvldedb 1 300 train
+wlcdfpjyhi 1 299 train
+wlcjmzoyfg 1 298 train
+wlckkzwoem 1 300 train
+wlcpzhoijh 1 300 train
+wlczvqucwb 1 300 train
+wlddhbnhsp 1 300 train
+wlddznsbmi 1 300 train
+wldodxmmyo 1 300 train
+wldosqggas 1 301 train
+wldrgkoeql 1 300 train
+wldtjcifgl 1 299 test
+wldufnqseu 1 300 val
+wldvvaevyt 1 300 train
+wldyporbfz 1 300 train
+wldyxxffmu 1 300 train
+wleacnohno 0 300 train
+wledtdvsqn 1 301 train
+wleeubnujw 1 300 train
+wleewyfwni 1 300 val
+wlehzhjppc 1 300 test
+wleijleoao 1 300 val
+wleiojugcj 0 300 train
+wleodpjyks 1 300 train
+wleouhwyku 0 300 train
+wleppkzkjs 1 300 train
+wleulnxkqp 0 300 train
+wlezqygtev 1 300 train
+wlfemnwnhe 1 240 train
+wlfjlraraz 0 300 val
+wlfqeyrpur 1 300 train
+wlfqucfjfx 1 300 train
+wlfrljfyec 0 300 val
+wlfwnwfllh 1 300 train
+wlfykeoztu 1 300 train
+wlgqumelkx 1 300 val
+wlgybvqzim 1 300 train
+wlhknqygjg 1 300 train
+wlhlstnoqi 1 300 train
+wlhnxwleue 0 300 val
+wlhpniistw 1 300 train
+wlhqkmbquc 1 300 val
+wlhrjmuycr 0 300 train
+wlhtxeckiy 0 300 val
+wlhufkkjut 1 300 train
+wliifpsiul 1 300 val
+wliwyomyxb 1 301 val
+wlixzmuzyi 1 300 train
+wlizbrnsxd 0 300 train
+wljdyvozdp 1 300 train
+wljgipvxkk 1 300 train
+wljheeeifz 1 300 train
+wljkwsvrgn 1 300 train
+wljmkbczgv 1 300 val
+wljrxnarrp 1 300 train
+wlkdorvjns 1 300 train
+wlkdtddses 1 300 train
+wlkgmbfrsq 1 298 train
+wlkiwxiroa 1 298 val
+wllezmsnnv 1 297 train
+wllhdjdigp 1 298 train
+wlltpwqzio 1 300 train
+wllwqcbhvg 1 300 train
+wllwzkmuza 1 300 train
+wlmbrrtzlk 1 300 train
+wlmcraopjv 1 300 val
+wlmgtcsqxw 1 301 val
+wlmkggypzc 1 300 train
+wlmmyrmper 1 300 train
+wlmvldkkym 0 302 train
+wlmzwltota 1 299 val
+wlncomphlf 1 300 train
+wlncrxzqjh 1 300 train
+wlnefarntw 1 300 train
+wlnfkhwzfq 1 300 train
+wlnfnddxcy 0 300 train
+wlninybffn 1 300 train
+wlnsmumoey 1 300 train
+wlnymccicv 0 300 val
+wloavebugu 1 300 val
+wlolimpwos 1 300 train
+wlookjipea 0 300 train
+wlorflaqut 1 301 val
+wlorkihmcm 0 300 train
+wlorutsldu 1 297 train
+wlowshczkt 1 301 train
+wloxhpnucy 0 300 train
+wlpeeoxoot 1 300 val
+wlpelkmyvc 0 302 val
+wlpljmkcid 0 300 train
+wlpmeecjje 1 296 train
+wlpmxjvzak 1 241 train
+wlpncuxqzb 1 300 train
+wlpuzfthxx 1 300 train
+wlqbvywhpf 1 300 train
+wlqgesvfot 1 300 train
+wlqivsbtir 1 300 train
+wlqnwmsoeq 1 300 train
+wlqqnhdifs 1 298 train
+wlqssorvfi 0 300 train
+wlqxyshgal 1 300 train
+wlqznovuxg 0 300 train
+wlrafynbjd 1 300 val
+wlrbdhxcaw 1 300 val
+wlrgqwoqfx 0 300 train
+wlrmdagdqa 1 300 train
+wlrwalptyt 1 300 train
+wlrwbwmxnp 1 300 train
+wlrxbqhcix 1 300 train
+wlrzcxjmcp 1 300 train
+wlscoeejcj 1 300 train
+wlsoqzaqrs 1 301 train
+wlspvjsbuk 1 300 train
+wlsrspqdkx 1 301 train
+wlsutxwtqb 1 296 val
+wlszehxbys 1 302 val
+wlteuifgxa 1 300 val
+wlteyrlfpe 1 300 train
+wltgvpzlpf 0 300 val
+wltinokmmo 0 300 train
+wltnaejohb 1 299 train
+wltrbjuccx 1 300 train
+wltycinaot 1 300 train
+wludckcqnc 1 300 train
+wlufzacrfq 0 301 train
+wluigkzjdl 1 300 val
+wlulehtpor 1 300 val
+wluphqjdrk 1 300 train
+wlurvqspwf 0 300 train
+wlusshgwie 1 300 train
+wluvzydzsn 1 300 train
+wluynuuikw 1 300 train
+wlvjrvnado 1 241 train
+wlvmxuomea 1 300 train
+wlvqpiunzg 1 300 val
+wlvsxbsavc 0 300 val
+wlvsyerbke 1 300 train
+wlvuxdmqit 1 99 train
+wlvxhazuog 1 300 train
+wlvybmryxl 1 300 train
+wlvzyywbcr 1 300 train
+wlwdpfbdrg 0 300 train
+wlwhdybxah 1 300 train
+wlwjutvfzx 1 300 train
+wlwktuifen 1 300 val
+wlwlsvsedn 1 300 train
+wlwnwfypki 1 300 train
+wlwqprpkhj 1 300 val
+wlwwqbjgmj 1 300 val
+wlxamrcpar 1 300 train
+wlxatkenif 0 300 val
+wlxczwkylv 1 300 train
+wlxepdqvns 1 301 train
+wlxfmdspyc 1 300 train
+wlxgoipmwd 1 300 train
+wlxjzbncxh 1 300 val
+wlxnmrsihg 1 300 train
+wlxogqaoja 0 300 train
+wlxojbsqsi 1 300 train
+wlxpvwwqbf 1 241 train
+wlxqifkqhv 1 300 train
+wlxuddmwft 1 294 train
+wlybebfuhs 1 300 train
+wlyfcpecea 1 300 test
+wlyflmumps 1 300 train
+wlyhrhitui 1 300 val
+wlyjeuuiuk 1 300 train
+wlykphyxpl 1 300 train
+wlyqqhducp 1 300 train
+wlytdqnwvx 0 300 val
+wlyvphluux 1 298 train
+wlyvvvjgnv 1 300 train
+wlyxpujfao 1 300 train
+wlzamkdzxt 1 300 train
+wlzbbqqfln 0 300 train
+wlzboqygdm 1 300 train
+wlzpdhrsvw 1 300 train
+wlzsubdwab 0 300 train
+wlzvnqctyf 1 301 val
+wmagicgizb 1 300 val
+wmahsvadgn 1 300 val
+wmajtfbteo 1 300 train
+wmanpvojwj 1 300 train
+wmaotihjle 1 300 train
+wmaqobhmlu 0 300 train
+wmaqywpwup 1 300 train
+wmatrirlng 0 300 train
+wmavhagafr 1 300 val
+wmawvfpblo 1 300 train
+wmbandnhuv 1 300 train
+wmbdydnowb 1 300 val
+wmbhjkexim 1 300 train
+wmbiuvloxf 1 300 train
+wmbkxqteao 1 300 val
+wmbnqbhxca 1 298 train
+wmbnusyztf 1 300 train
+wmbsdtznii 0 300 train
+wmcdnstvry 1 300 train
+wmcoevwujc 1 300 train
+wmcqemuzbl 1 300 train
+wmcwqmiawm 1 300 val
+wmdamjouqh 1 300 train
+wmdnqpfcey 0 300 val
+wmdpqzeclg 1 300 train
+wmdrbqckkw 1 300 val
+wmdrewmuev 0 300 train
+wmeblcvpfs 1 300 train
+wmedzoeeet 1 300 train
+wmegtnlbjq 1 300 train
+wmehpcfhsr 0 300 val
+wmehznilji 1 300 train
+wmekgobjyy 1 301 train
+wmeoyvpjdk 0 300 train
+wmeqmkhmva 1 298 train
+wmfbwblhxx 1 241 train
+wmfhukshze 1 300 train
+wmfhwlpsvc 1 300 train
+wmfjzjgdce 1 300 train
+wmfqnyopwa 1 300 train
+wmfxaxryhn 1 300 val
+wmfxjumvdb 1 297 train
+wmfxpfzgjy 1 300 train
+wmgbavrmte 1 298 val
+wmgkqogawy 1 300 val
+wmglmtoswg 1 300 train
+wmglzfxxzp 0 300 train
+wmgmshwtws 1 136 train
+wmgoceuptd 1 298 val
+wmgqeqrxlk 1 300 val
+wmgswfypjd 1 300 val
+wmguqjojif 1 300 val
+wmgxnhiuvt 1 301 train
+wmhbinwlkj 1 300 train
+wmhpypmzur 1 300 train
+wmhspgkfqj 1 301 train
+wmhucaarmt 1 237 train
+wmhupbrqar 1 301 val
+wmhuxvpxyq 1 300 train
+wmhvqoodir 0 300 train
+wmhwkmotxr 1 300 train
+wmiayfeksy 1 300 train
+wmibnrgtet 1 300 train
+wmidfxmkbt 1 300 val
+wmipbjwwbq 0 301 train
+wmjahdrbyr 0 300 train
+wmjbpdwjln 0 300 train
+wmjdhtsvif 1 300 train
+wmjecgzfzg 0 300 train
+wmjfcunvmp 1 300 train
+wmjnlzsbgp 0 300 train
+wmkbgbvzdr 0 300 train
+wmkbornmzk 0 300 val
+wmkpajinla 1 300 val
+wmkyfrarib 1 300 val
+wmlbfpvvaf 1 300 train
+wmlhsnaupu 1 300 train
+wmlifvuulh 1 300 val
+wmljrvfrve 1 300 val
+wmljvqilkb 1 300 train
+wmltghyhfh 1 300 test
+wmlyktueqb 1 300 val
+wmmlekdufn 1 300 train
+wmmottlyys 0 300 train
+wmmuwsytjm 1 240 val
+wmnaczogmu 1 300 train
+wmnajexzkj 1 300 train
+wmnasbcwut 1 300 val
+wmnbrmjyey 1 300 val
+wmnkbqdgxj 1 300 val
+wmnqzmpxbw 1 300 train
+wmnsbbdnjj 1 300 train
+wmnsojpmwp 1 300 train
+wmnugafuqb 1 300 train
+wmnujiosmz 1 297 train
+wmnwendqoj 1 300 val
+wmobvmntzu 1 300 train
+wmoigsbnem 1 300 test
+wmojulzeul 0 300 train
+wmombvlsch 1 241 train
+wmoogannuv 1 301 train
+wmooshykkb 1 300 test
+wmoosietdr 1 300 train
+wmoqcpydip 1 299 train
+wmoqzxddkb 0 300 test
+wmoraawxhm 1 300 val
+wmosbflgub 1 146 train
+wmovqekbip 1 300 val
+wmoycfuwje 1 300 train
+wmpbfiemhr 1 300 train
+wmpdqhmbky 1 241 train
+wmpemjxavk 1 300 train
+wmpfrpibmc 1 297 train
+wmpquqyjky 1 300 train
+wmpwsdogqt 1 299 train
+wmqacieibj 1 300 train
+wmqdrsddao 1 300 val
+wmqehhaifz 0 302 train
+wmqesoefak 0 300 train
+wmqgueisyj 1 300 train
+wmqknuwrgq 1 300 val
+wmqlzexuzj 1 300 train
+wmqmsbnjsm 0 300 train
+wmqnaqxyuo 1 301 train
+wmqohxxweg 1 301 val
+wmqpublxyh 1 300 train
+wmqsbgfvjg 1 297 val
+wmqsknaifd 1 300 train
+wmqsmgzaga 1 300 train
+wmqtlwxrhd 1 300 val
+wmqunpkyiw 1 300 train
+wmqxzxigdh 1 300 train
+wmrbagvqif 1 300 val
+wmrbceysak 1 300 train
+wmrwqahdbo 1 301 val
+wmrzqowwlf 1 300 train
+wmscyopbrx 1 300 val
+wmsekbsjof 1 301 train
+wmsmrcfoow 1 300 train
+wmspqscinj 1 300 train
+wmsujhosjy 1 300 train
+wmtfqxryvi 1 300 train
+wmtmtmmjgn 0 300 train
+wmtmwuemhc 0 301 train
+wmtqaetlgs 1 300 val
+wmtvxafwxm 1 300 train
+wmtwvhgouy 1 300 train
+wmudgchwur 1 300 train
+wmupcrvghl 1 298 train
+wmusqyblnt 1 300 train
+wmuvkevctb 1 299 val
+wmuxwupsgx 1 300 train
+wmuysstuoh 1 300 train
+wmvcaxrstv 1 299 train
+wmviskkzoy 1 300 train
+wmvkdhzcuc 1 298 train
+wmvmonzkma 1 300 train
+wmvmxmwgzy 1 300 train
+wmvpbihyvs 1 300 train
+wmvwzgaztn 1 299 train
+wmwfcfwjdv 1 300 train
+wmwjijcndn 1 300 train
+wmwkkiykdl 1 300 val
+wmxauzmrjf 1 299 val
+wmxljnrvkp 1 300 val
+wmxmrtcydt 1 299 val
+wmxsqorxif 1 300 train
+wmxtaenrup 1 300 val
+wmxuepgtvy 0 300 train
+wmybdclyvw 0 300 train
+wmybrfjcbq 1 300 train
+wmygbzbyiq 1 299 train
+wmygvdtube 1 300 train
+wmyhpgwqkq 1 300 train
+wmyknbnfmk 0 300 val
+wmypkhusgm 1 300 train
+wmyuurxrjw 1 300 train
+wmzawizfxz 1 300 train
+wmzhhaskfw 1 300 train
+wmzlvvesqw 0 300 train
+wmzolzkmpt 1 300 train
+wmzshvrcgh 1 300 train
+wmzuuqidlb 1 298 train
+wmzvnzklzq 1 241 train
+wnaiobbjin 1 300 train
+wnaleeqtrf 1 300 train
+wnalungsqf 1 300 train
+wnamymdwzg 1 300 train
+wnaoastfys 0 300 train
+wnapcyuehu 1 300 train
+wnapijnlwm 1 167 train
+wnapxjuarz 1 300 train
+wnapzuuwgo 1 300 val
+wnauiblfvj 1 300 val
+wnaweyzlqh 1 300 test
+wnayfwzznr 1 300 train
+wnbjcujsae 1 241 train
+wnbjmruoef 1 301 train
+wnbjyaehwb 1 300 train
+wnbqayttji 1 300 train
+wnbuoyuevf 1 300 train
+wncajfjeph 1 300 val
+wncdvjwyaf 1 269 train
+wncjibpyzk 1 300 train
+wncmyojmnb 0 300 train
+wncuhzhgjv 1 300 train
+wndeoxjyhk 1 300 train
+wndgspaigj 1 300 train
+wndhbqtzpu 1 300 train
+wndkeakdza 1 300 train
+wndqracjyj 1 300 train
+wndursivcx 1 299 test
+wndyvvqokf 1 300 val
+wndzyviipz 1 300 train
+wnebaulkle 1 300 train
+wnemrrfoap 1 300 train
+wnemyzodsu 1 300 train
+wnfbrwwkuu 1 300 train
+wnffglghqa 1 300 train
+wnfhvgsfxb 1 300 train
+wnfiklrspt 0 300 train
+wnfqtbneoe 1 300 train
+wnfrzyehdm 1 300 train
+wnfumddcoa 1 297 val
+wngdoxstrb 1 300 train
+wngejyajyh 0 301 val
+wngfcsizhu 1 301 train
+wngqadhqol 1 300 train
+wngqvkmiwe 1 300 train
+wngswyocyd 1 300 train
+wnhcazgvev 1 288 train
+wnhcwozisy 1 300 train
+wnhlvjdtfg 1 300 train
+wnhmdjztfq 1 300 val
+wnhtplckuq 1 300 val
+wnifvdthjc 1 301 train
+wnigphxcwf 1 300 train
+wnilkonwrw 1 300 train
+wnimmovztf 1 300 train
+wniujdmckw 0 300 val
+wnivyrmprq 1 300 train
+wniwrntswx 1 300 val
+wnixchvuhc 1 296 train
+wnixovlrmu 1 241 train
+wniygkfxbu 1 300 train
+wniygvcktr 1 300 train
+wnjfpmczjv 1 300 val
+wnjqiwyiol 1 300 train
+wnjuyckbpj 1 300 val
+wnkalctidl 1 300 train
+wnkkffwxev 1 300 train
+wnkpjfidgm 1 300 train
+wnkqpydjck 1 300 train
+wnkvfntfna 1 301 val
+wnkyqhrmng 1 300 train
+wnlamfqjaj 0 300 train
+wnlnuotcpw 0 300 val
+wnlubukrki 1 300 test
+wnmcfjyokj 1 300 val
+wnmgclgiis 1 300 val
+wnmgokszin 1 300 train
+wnmqfppwxs 1 300 train
+wnmvjvllqn 0 300 val
+wnmxbqxzjq 1 300 train
+wnncnejtjt 1 300 train
+wnncyjgvyp 1 300 train
+wnnfxhrkpk 1 300 test
+wnnkfnnict 1 301 val
+wnnlyaykom 1 300 train
+wnnqokbedc 1 300 train
+wnnrqujftr 1 300 train
+wnodgaugvl 1 300 train
+wnoeywlvtx 0 300 val
+wnoitecfmf 0 239 train
+wnojtjhegc 1 300 train
+wnokwcbcsi 1 300 train
+wnokxrzpml 1 300 train
+wnolcftiyj 1 300 train
+wnoqyswmcj 1 241 train
+wnovcuyuqi 0 300 val
+wnowuqhbig 1 300 val
+wnowyaqnuz 1 300 train
+wnphjvijem 1 300 train
+wnpnagfzxq 1 300 val
+wnprxfbkrc 1 300 train
+wnpypxywap 0 300 train
+wnpzdccthh 0 300 val
+wnqkwlvnzl 1 300 train
+wnqliyuxjz 1 300 val
+wnqlzimgbg 0 300 train
+wnqodiowwt 0 300 train
+wnqrnnplrh 1 300 train
+wnqzpaunbs 1 300 val
+wnrcsaplwt 1 300 train
+wnroczyrtd 1 300 train
+wnrpylyohn 1 302 train
+wnrryjdghq 1 300 train
+wnrzvzpjpq 1 300 train
+wnsheabzwq 1 300 train
+wnshgqztai 1 300 train
+wnsrqqukld 0 300 train
+wnsvzfcwpo 1 300 train
+wnsywgmtyj 1 300 train
+wntdoofluy 1 300 train
+wntenovjrb 1 300 train
+wntmdeuqqp 1 300 train
+wntmwygmtl 1 300 val
+wntribefof 1 300 train
+wntshsaoyt 1 300 train
+wntvspdocl 1 300 val
+wntyomawif 1 300 train
+wntzmklerl 1 300 train
+wnugjdygmg 0 300 train
+wnumhjpmzh 1 301 train
+wnuomwpkfe 1 241 train
+wnuvipwbnk 1 300 train
+wnvejnuhyx 1 300 train
+wnvjncykat 1 298 val
+wnvrzdjelm 1 300 train
+wnvxospbbe 1 300 train
+wnwcciouvl 1 300 val
+wnweefhmza 0 300 train
+wnwkydfcjs 1 302 train
+wnwqudnwzo 0 300 train
+wnwtowryzg 1 300 train
+wnwuzorwye 1 300 train
+wnxayzetze 1 300 val
+wnxfxwvuec 1 300 val
+wnyeuvocho 1 300 train
+wnykcttbag 1 301 train
+wnyuvhjqjn 1 300 train
+wnzarbukpe 1 300 val
+wnzbgpvqhe 1 300 train
+wnzfpgjkte 0 300 val
+wnzfzxmfbg 1 300 train
+wnzktljvmz 1 300 train
+wnzoxlvpse 1 296 train
+wnzpvwrhyv 1 300 train
+wnzvupybzp 1 300 train
+woaarlwrni 1 300 train
+woadtvrptz 1 300 train
+woaebdlviz 1 300 train
+woagmcgppz 1 300 val
+woagxuelpw 1 300 val
+woahqydkcl 1 300 train
+woapkznuit 1 300 train
+woaqpovvpj 1 300 val
+woavkkhjiw 1 146 train
+wobljnzdrl 1 299 train
+wobomlluee 1 300 train
+woboxcfzcp 1 300 train
+wobsmwlefv 1 300 val
+wobswanamd 1 300 train
+wocazrxtsk 1 300 train
+woceenpyrh 1 300 train
+wocfdldqrj 1 241 train
+wocfkeeuul 1 300 train
+wocgdlsqpd 0 301 train
+wocgulikze 1 300 val
+wociscyyjv 1 298 train
+wocpdprlvy 1 300 train
+wocrjylvyj 1 300 train
+wocrwjagnr 1 300 val
+wocucddsji 1 298 train
+wocvoeesge 1 300 train
+wocxamvtsw 1 300 train
+wodcbungvz 1 300 train
+wodegjtczu 1 99 train
+wodjczsbdn 1 300 train
+wodlwjcmkn 1 301 val
+wodyvmsrro 1 83 train
+woewmsbgot 0 239 val
+wofbcrvzdm 1 300 train
+wofdncuhbz 0 300 val
+wofetcaklm 1 300 train
+wofhpjumfz 1 300 train
+wofkeknshd 1 300 val
+wofklhrnfm 1 300 train
+wofklplyoo 1 300 train
+wofnyginsw 1 301 train
+wofpgleeuf 1 300 val
+wofzfwxyvf 0 300 val
+wofzhjkjtj 1 300 train
+wofzkvmxnp 1 299 val
+wogcnvtwbx 1 300 val
+wogdwmhqsu 0 300 train
+wogiltegdx 1 300 train
+woglwielvo 1 240 train
+wogncpmbxj 1 297 val
+wograxpbzq 1 299 train
+wohatpqcpf 1 300 train
+wohhrvytaw 0 300 train
+wohujsshti 1 300 train
+wohvbuzeib 1 300 train
+wohxaslycl 1 300 train
+woigjkygmr 1 300 val
+woilwvqdmi 1 241 train
+woiqtkopxe 1 300 train
+woiusuqbnd 1 300 train
+woixvsbnab 1 300 train
+wojetawadt 1 300 train
+wojhrcbcjj 1 300 train
+wojnfpytps 0 300 train
+wojpparsfi 1 298 train
+wojudxwtqn 1 300 val
+wokjswpzat 1 300 train
+wokkpviuld 1 241 train
+woklqkxvro 1 300 train
+wokoyxivgo 1 301 train
+wokqgsrbrb 1 301 train
+wokzyujils 1 300 train
+wolbweudvu 1 236 train
+wolgusoonv 0 300 train
+woljhikhox 0 300 train
+wolnrzgnga 1 300 train
+wolpgixfay 1 300 train
+wolrzmfong 0 300 val
+woltsuoiam 1 300 train
+womczewzwr 1 300 val
+womdngjejh 1 300 train
+womjjzqryh 0 146 train
+womkcdcuoe 1 300 train
+wommxomlwr 1 300 train
+womphmezji 1 300 train
+womqmrqprk 1 300 train
+womwjwyqzs 0 300 train
+wonffukjon 1 300 train
+wonrzkirwi 0 300 train
+wonsdtouax 1 300 train
+wontxpoify 1 300 train
+woockxumil 1 298 train
+woocljcfbp 1 300 train
+woodviyivm 1 300 train
+woommqzvfr 0 300 train
+wooranbphj 0 300 train
+woorsicxkq 1 300 val
+woosdfqfdd 1 300 train
+wooxlbbpvb 1 300 train
+woozbsrgad 1 300 train
+wopkxvbtfu 1 301 train
+woppgjuqnn 1 300 train
+woptlijeiq 1 300 val
+wopygaznyw 1 300 train
+wopywyidjy 1 300 val
+wopzrimghc 0 300 train
+woqdkbxhgc 1 300 train
+woqegvifjv 1 300 val
+woqggmgnbw 1 298 val
+woqlxgsmct 1 300 train
+woqoadphrq 1 240 train
+woqrsxmcqd 1 298 train
+woquabuqla 1 300 train
+woqvoujhyj 0 300 train
+woqwjsvhff 1 300 train
+wordhlieve 1 300 val
+worjueqboo 1 297 train
+worovfsgay 1 299 train
+worpyusnxh 1 288 train
+worsrhrtis 1 300 train
+worxpxphsy 1 300 train
+worybrghvq 1 300 train
+wosbbuicnr 1 300 train
+wosbhvzaxz 1 300 train
+wosbjustic 1 300 train
+wosckhcmxq 1 298 train
+wosdlnwxfa 1 241 train
+wosglbmaey 1 300 train
+woshnzbxmc 0 300 train
+wotajmhzhr 1 300 train
+wotgiryojo 0 301 train
+wotjgzxgmb 1 298 train
+wotuvshiwk 0 300 train
+wotwhdptzm 1 300 train
+wotzpksvju 1 300 train
+woufaypmos 1 300 train
+woufjqfafm 1 297 train
+wouhmiwhpl 1 301 train
+woulxhujyh 1 300 train
+wounovfkwj 1 300 val
+wourqhbgos 1 300 train
+woutmtulyc 1 300 train
+wouwumpoov 0 300 train
+wouwvjljic 0 300 train
+wouycewchm 1 301 val
+wovilwekxv 1 300 train
+wovochgccx 1 300 train
+wovraiwadu 1 300 train
+wovufzgzkx 1 300 train
+wovwwjblus 1 300 train
+wowbfgzyiz 1 300 train
+wowduraqqp 1 300 train
+wowlzfxslk 1 300 train
+wowqljawhw 0 300 train
+wowqmwccsb 1 300 train
+wowwlbmpiq 1 300 test
+woxkvqtxjz 1 300 train
+woxlbmkeys 0 300 train
+woxnvxbmbx 1 300 test
+woxqngcbot 1 298 train
+woxymvgecq 1 300 train
+woxyzsfoyv 1 300 train
+woxzkqqdfp 0 300 val
+woyehyxpcr 1 301 val
+woygkaqapj 0 300 train
+woyiclpeft 1 300 train
+woyizmlwla 1 300 train
+woypixzllw 1 300 train
+woytcomghp 1 300 train
+woytucrsdw 1 300 val
+woytzlcssm 0 300 train
+woyykzwauk 1 300 val
+wozbffwkzp 1 300 val
+wozdhhgnxr 1 300 val
+wozfrointj 1 301 train
+wozjbukebj 1 300 train
+wozjdjdpse 0 300 train
+woztvjhzuo 1 300 train
+wozzcuoagt 1 300 test
+wpafxjaxnj 0 297 train
+wpavzxsjop 1 301 val
+wpaxsyrjjf 1 300 val
+wpbdojffio 1 300 train
+wpbeacntfv 0 300 train
+wpbivuvpcz 1 300 train
+wpbnfrercr 1 300 val
+wpbupcskuk 1 300 val
+wpbwkqlqdf 1 300 train
+wpbybtuphy 1 300 val
+wpbyhspoiy 1 300 train
+wpchhwveav 1 298 train
+wpcjrqaoeo 1 298 train
+wpckqlebut 1 300 train
+wpcmawhytz 1 301 train
+wpcsrbkztb 1 300 val
+wpcweuvtkf 1 299 val
+wpczkcwiwm 1 300 train
+wpdkwjcjjn 0 300 val
+wpdlxgyoim 1 300 val
+wpdnxrpdfy 1 300 val
+wpdrxrheoy 0 300 train
+wpdtfzdgyu 1 300 train
+wpeizdptiu 0 300 val
+wpekgryylc 0 300 train
+wpeniiryyz 1 300 train
+wperksoyjd 1 300 train
+wperoahege 1 300 train
+wpesomjqxs 0 301 train
+wpetoxysqs 0 300 train
+wpevsqyjca 1 300 train
+wpewycmqfk 1 300 train
+wpfdcggbsu 1 300 train
+wpfervugdg 1 300 train
+wpffeygcqb 1 300 train
+wpfitjhqed 0 302 train
+wpfmwlccvs 0 300 train
+wpfnqzeomr 1 300 train
+wpftmwkyuw 1 300 train
+wpfwsiyptg 1 301 train
+wpgcdskkyh 1 241 train
+wpgcusizze 1 300 train
+wpgdswxbbh 1 300 val
+wpgjfpxovx 0 302 train
+wpgmemgdgq 1 300 train
+wpgxphvhvo 1 300 train
+wphcgtgnyw 1 300 train
+wphdprtbhr 1 300 train
+wphjzsctkl 1 300 train
+wphojbnztl 1 300 train
+wphvrzobpt 1 300 train
+wphztpbiqb 1 300 train
+wpicijndjl 1 300 train
+wpicivhlmf 1 300 train
+wpjaljwawc 1 300 train
+wpjfllbibt 1 300 val
+wpjfnfxpbn 1 300 train
+wpjnhdjfrs 1 300 train
+wpjnujngcw 0 300 train
+wpjtbdsygr 1 300 train
+wpjxtpkesn 1 300 train
+wpkdthaczx 1 99 train
+wpkilmphfj 1 300 train
+wpkralpejo 1 300 train
+wpkwisfgyv 1 298 train
+wpkzcqdext 1 300 train
+wplfksomwh 0 300 val
+wplfwkwixo 1 300 test
+wplpoezbrt 1 301 train
+wpmbwkbwzp 1 300 val
+wpmdttgpex 1 300 train
+wpmnzhcaps 1 300 val
+wpmomqtpyv 1 300 train
+wpmznuuzlv 1 300 train
+wpnjytmnff 1 241 train
+wpntlmybej 1 300 train
+wpnukldybg 1 300 test
+wpnwxmiptv 1 300 train
+wpnxsexzix 0 249 train
+wpnyhatiho 1 300 train
+wpnzouusfb 1 298 train
+wpogxzaqyz 1 300 val
+wpoixknobj 1 300 train
+wpoljiqulf 1 300 train
+wpoomdzjmh 1 300 train
+wpoozynbtv 1 300 train
+wpoxpcievv 0 300 val
+wpoycoqumb 1 300 train
+wppplarvvl 1 300 train
+wppseasxvr 1 298 val
+wpptpjmjlh 0 300 train
+wpqbeeqjdi 1 300 train
+wpqibjddzb 1 300 train
+wpqixzxpng 1 300 train
+wpqknyiwvz 1 300 train
+wpqphfbvyx 1 300 train
+wpqumfidrb 1 300 val
+wpqvviskbk 1 300 train
+wpqxyjvasu 1 296 val
+wpravjxgka 1 300 train
+wprcmypsxh 1 300 train
+wprcvndusd 1 300 train
+wprkutbbor 1 300 train
+wprscsysul 1 301 train
+wpsjcktlfw 1 300 train
+wpsjikfifv 1 300 train
+wpspflzkhq 1 300 train
+wpssxendua 1 300 train
+wpsvhlbcio 1 300 train
+wptaksadya 1 300 train
+wptefeucmq 1 300 train
+wptohalkre 1 300 train
+wpulserdye 1 300 train
+wpuscyeswf 1 300 train
+wpusruriml 0 300 train
+wpuveopayd 1 300 train
+wpuwhnfjaq 0 301 train
+wpuxgilupb 1 300 train
+wpuyyofpri 1 300 train
+wpvgkzjtbi 1 300 train
+wpvhlligrh 1 300 train
+wpvitqvmia 1 300 train
+wpvjetzyjs 1 300 val
+wpvmakypfh 1 300 train
+wpvnnqoqvc 1 300 test
+wpvonwowfm 1 300 train
+wpvroruxtr 1 300 train
+wpvstjbuhx 1 300 train
+wpvuoaqddb 1 241 train
+wpwaolpsvy 0 300 train
+wpwipnpdmz 0 300 train
+wpwiygngwy 1 300 train
+wpwmfuhgta 1 300 train
+wpwritxgkd 1 300 train
+wpwsmgtrak 0 300 train
+wpwtgdzprq 1 301 train
+wpwvlwlsov 1 300 train
+wpxdrfsmws 1 300 train
+wpxgygecoa 1 300 val
+wpxicijtgk 1 300 train
+wpxivqyoww 1 300 train
+wpxknkuifu 1 241 train
+wpxqsgmmgz 1 300 train
+wpxvksuipc 1 300 val
+wpycciwnnj 1 241 train
+wpycrzdvcz 1 300 test
+wpykyqlfaq 1 300 train
+wpyqvfwwzz 1 300 train
+wpyrhtlloq 1 301 train
+wpysxggnok 1 300 test
+wpytmqmhea 1 300 train
+wpzbrdrnbj 1 300 train
+wpzbxwymmi 1 300 train
+wpzerceyjq 0 300 train
+wpzkwvqkjs 1 300 train
+wqaubutirr 1 300 train
+wqbeswzbtz 0 300 train
+wqbetjqhaz 1 299 test
+wqbfaitajc 1 300 train
+wqbnwuseym 1 300 train
+wqbqihfmgq 1 300 train
+wqbrqneydj 1 301 train
+wqbsiepbed 1 300 train
+wqbvktypda 1 300 train
+wqbwqsvsns 1 300 train
+wqbxrnrhuo 1 240 val
+wqbzbxjndx 0 300 val
+wqcbijxxbv 0 300 train
+wqcpbvrsli 1 300 train
+wqcpqvkqrl 1 300 train
+wqctxzdmhn 1 300 train
+wqddtxnbcx 1 300 train
+wqdhkzvfao 1 302 train
+wqdksrwolx 0 300 train
+wqdopmzmnr 1 300 train
+wqdrudcuql 0 300 train
+wqdrvdrrke 1 298 val
+wqdsarmger 0 299 val
+wqdsoohrwu 1 300 train
+wqdyfdihyu 1 300 val
+wqeaqhefve 1 300 train
+wqebygojbt 1 300 train
+wqefbjeclc 1 298 train
+wqejmmrdlc 1 300 train
+wqepicgirh 1 300 train
+wqeudsihbm 1 300 train
+wqeuyqimni 1 300 val
+wqewnewkhw 0 300 train
+wqewxnshij 0 300 train
+wqfjjssctd 1 300 train
+wqfjzcjbbz 1 300 train
+wqfmfquour 1 300 train
+wqfmitxuuu 1 300 train
+wqfycjbbsh 1 302 val
+wqgbeadabf 1 300 test
+wqgcygybmw 1 300 train
+wqghgjctpy 1 300 train
+wqgiqcujfj 0 300 train
+wqgkjaymoh 1 300 val
+wqgteosbel 1 300 val
+wqguccfqhq 1 300 train
+wqgxaazqux 1 300 train
+wqhcsehrqp 1 300 val
+wqhekcaoog 1 300 train
+wqhgvhqdky 1 240 train
+wqhvvxqoqy 1 300 val
+wqidhonezq 1 300 train
+wqiptbqphx 0 300 train
+wqivvcqrud 1 300 train
+wqjctacngc 1 300 val
+wqjehpmtjg 1 297 val
+wqjjjgluin 1 300 train
+wqjmkwzlbj 1 301 train
+wqjnelzbrk 1 240 train
+wqjrefiwmr 0 300 val
+wqjvhqvude 1 300 val
+wqjwaosbxl 0 300 train
+wqjzbcdili 0 301 train
+wqkaroiouf 1 300 val
+wqkgrkbkvo 0 300 train
+wqkqpnjtbp 1 300 train
+wqkrceuvus 1 300 train
+wqkrmoevaq 1 300 train
+wqlfjdmwbc 1 300 train
+wqlgktrnvr 1 300 val
+wqlhleycsk 1 301 val
+wqliycxgmf 1 301 train
+wqlogwihkp 1 298 train
+wqlsjubilg 1 300 val
+wqluwmwabk 1 300 val
+wqlzzyrwym 1 298 val
+wqmfbqogin 1 300 val
+wqmfmlthsg 1 300 train
+wqmllzylmd 1 300 train
+wqmmwdfrjp 1 298 train
+wqmndrkclc 1 300 train
+wqmrmtlfbm 1 241 train
+wqmsicmkzf 0 300 val
+wqmukgrnds 1 300 val
+wqnftvyqgs 1 300 val
+wqnlooubux 0 300 train
+wqnouugrqv 1 298 train
+wqnqkczixi 1 300 train
+wqnrlbuzcj 1 300 train
+wqnuraegce 1 300 train
+wqnurrssux 1 299 test
+wqnymtejwv 1 298 train
+wqoebadfln 1 240 train
+wqoihdhglu 0 301 train
+wqoqmvdepr 1 300 train
+wqoqyfbbzn 1 300 train
+wqosikqmmo 0 300 train
+wqowmddqri 1 300 train
+wqphfoxpor 1 300 val
+wqpnbzbeys 1 300 train
+wqpzaqvjil 1 300 train
+wqqdpbxzba 1 298 val
+wqqhjtkfwz 0 300 train
+wqqmefnjjc 1 300 train
+wqqmwtqcfy 1 300 val
+wqqpdjiela 1 298 train
+wqqpkdocts 1 300 train
+wqqrghknon 0 250 train
+wqqrvayayy 1 300 train
+wqqssafchz 1 300 train
+wqqvrqxihh 1 298 train
+wqrpozorjk 1 241 train
+wqrqyduawk 1 300 train
+wqrxribxgk 1 300 train
+wqsgordpuy 1 300 train
+wqskqmqntj 1 300 train
+wqsltapewl 0 300 train
+wqsuimspwa 1 300 train
+wqsveixiyo 0 300 train
+wqsvhfokfk 1 241 train
+wqtaezgrwv 1 300 train
+wqtahnlhyf 1 241 train
+wqtkesdpqt 1 300 train
+wqtmsiyfin 1 301 train
+wqtokcadnm 1 300 val
+wqtpgcfjlu 0 300 val
+wqtqbtysnk 0 300 val
+wqtraebanl 1 300 train
+wqttejdexc 1 300 test
+wqtyfdhyps 1 300 train
+wquagognqo 0 301 train
+wqubhvdext 1 300 train
+wqunkpcesq 1 300 train
+wquomaiagr 1 300 val
+wquqwazosd 1 300 train
+wquufklkzw 1 300 val
+wqvagblvgw 1 300 train
+wqvakxtdaz 1 300 train
+wqvdeewnho 1 300 train
+wqveaioeyc 1 300 val
+wqveobnlyz 1 300 train
+wqviirqrtj 1 300 train
+wqvtglpxri 1 300 train
+wqwgzqjkxf 1 300 train
+wqwiesvnvb 1 300 val
+wqwrkrubmc 1 300 val
+wqwsvsngjw 1 299 val
+wqwtcvskks 1 300 val
+wqwykjpfgf 1 300 train
+wqwzdhtxxd 1 300 train
+wqxbrmkexf 1 300 train
+wqxffyaftx 1 300 val
+wqxfurqwwb 1 300 val
+wqxnzouaar 1 301 train
+wqxpsveudn 1 300 train
+wqxqyuqjxf 1 300 train
+wqyhrjjcza 1 300 train
+wqyjlgsbqe 1 300 train
+wqyjwxjvwt 1 300 train
+wqylklyzjy 0 300 train
+wqylqadaso 1 300 train
+wqymzzraql 1 301 train
+wqyopamfak 1 300 val
+wqyqajatpf 1 300 val
+wqyrgpqvxj 1 300 train
+wqysrieiqu 0 300 test
+wqysuglqcf 1 300 train
+wqyvekwnko 1 300 train
+wqzdehopqh 1 300 train
+wqzfjwkbdn 1 300 train
+wqzftrirph 1 300 train
+wqzimznlwf 1 301 val
+wqznuzdyth 1 300 train
+wqzqgchcfa 1 241 train
+wraahyytaz 1 300 train
+wraazgrbuh 1 300 test
+wrajldrcye 0 300 train
+wramleoxcw 1 300 train
+wramxhempa 1 300 train
+wrawkurmjc 1 300 train
+wrbapltldk 1 300 train
+wrbbrzjscw 0 300 train
+wrbtvsforp 1 300 val
+wrbtvubjhe 1 300 train
+wrbuiboyat 0 300 train
+wrbutvjkjr 1 300 train
+wrbwtlhtqo 1 301 train
+wrcbundfmq 1 300 val
+wrcelewmpa 0 300 train
+wrcgslpcaj 0 300 train
+wrchmwtmwp 1 297 train
+wrchrjphgv 1 301 val
+wrchxdcjdl 1 301 train
+wrcjeiljen 1 300 train
+wrcjrzcjzf 1 300 train
+wrcqvnrgsk 1 300 train
+wrcuqngerf 0 300 train
+wrcynehbqx 1 300 train
+wrcyprdisa 1 300 val
+wrdcygesjk 1 300 train
+wrdeamxomm 1 300 val
+wrdezjcnwl 1 300 train
+wrdjjrakfj 1 300 train
+wrdmlvxuno 1 300 train
+wrehcnerdi 1 300 val
+wrehegwske 1 300 train
+wrejkbdasc 1 300 train
+wrelaeljqf 1 301 train
+wrentldfhl 1 241 train
+wrersztmaj 0 300 train
+wrerxvnaiz 1 301 val
+wreuwmdnmu 1 300 train
+wrfatoqjuq 1 296 train
+wrfppbaily 0 300 train
+wrfrkdsjku 1 300 train
+wrfrnandkk 1 300 val
+wrftxkepuq 1 300 train
+wrfvskczts 1 300 val
+wrfypoevcy 1 300 train
+wrgalbngpm 1 300 val
+wrgcgozlot 1 300 train
+wrgflmpxpi 0 300 train
+wrgghwhxsz 1 240 train
+wrgjqronyz 1 300 val
+wrgmiidjnt 1 300 train
+wrgmzrsugv 1 300 train
+wrgqxahnwh 1 301 train
+wrgtoanwvm 1 300 train
+wrgvsolqeh 1 300 val
+wrgywbrvqg 1 300 train
+wrhdobxffi 1 300 train
+wrhilosgmx 1 300 val
+wrhjjdbjld 1 99 train
+wrhmlwrtlz 1 300 train
+wrhnjjdjgr 1 300 train
+wrielnqukj 1 300 train
+wrigemxqaf 0 300 train
+wriieeailu 1 300 train
+wriimkdjbu 1 300 val
+wrijjkfndl 1 300 train
+wrijnggwum 1 299 val
+wrinhjgdsx 1 300 train
+wriqcrvezp 0 300 val
+wriqtybdnu 1 300 train
+wrjicexhrz 1 300 train
+wrjlkeipls 1 301 val
+wrjqdhunyu 1 300 train
+wrjquvghpj 1 300 train
+wrjwqnwiss 0 300 val
+wrkdlgconk 0 300 val
+wrkeyvpsiv 1 300 val
+wrkmvhoccc 1 300 train
+wrkmwyezbg 0 300 train
+wrknpyugtp 1 298 train
+wrkplbjpat 1 300 train
+wrkqqhkvje 1 300 train
+wrkromyjsy 1 300 train
+wrksqmliwx 1 241 train
+wrkumwpwms 1 300 train
+wrkwebyakb 1 300 test
+wrliclxsom 1 299 val
+wrlkyeoaid 1 300 train
+wrllqvmdid 1 300 train
+wrlmfnzirc 1 300 train
+wrlrzhlybr 1 301 train
+wrlvhykivf 1 300 train
+wrmasydsps 1 298 train
+wrmdiaexwl 1 298 train
+wrmgxlyekq 1 300 train
+wrmnlavlyb 0 300 train
+wrmuazxvgr 1 300 val
+wrmypaurck 1 300 test
+wrnakxgmim 1 300 val
+wrneqpqrkq 1 300 train
+wrnfrclvdo 0 300 train
+wrnhyqquxj 1 300 val
+wrnjnqkjcj 1 301 train
+wrnknepfhl 1 300 train
+wrnrglefvo 1 300 train
+wrnsbyevqx 1 300 val
+wrocbrsdfn 1 300 train
+wrodlubvuk 1 300 train
+wroedwbjrs 1 301 train
+wrofzjznze 1 300 train
+wrogbmvyer 1 300 train
+wrojkuimfn 1 300 train
+wrojvklnkk 1 300 train
+wrolznduyn 1 300 train
+wroncdgalv 1 300 train
+wrorpbopoi 1 300 train
+wrorqvpbsi 1 300 train
+wrovtgxgnh 1 300 val
+wrpasxekck 1 300 train
+wrpcuparss 1 300 val
+wrpigfecoi 1 301 train
+wrppsywutk 1 301 train
+wrprsamguk 1 300 train
+wrpvencgdy 1 301 train
+wrpvgmwxoh 1 300 train
+wrpvrooeac 1 300 train
+wrpycslzsz 1 300 train
+wrpzppoguy 1 299 val
+wrqdnqgart 1 300 train
+wrqiqqwzky 1 300 train
+wrqjkplmzx 1 241 train
+wrqobchgxa 1 300 val
+wrqpwncfai 1 300 train
+wrqqiusdpq 1 301 train
+wrqvfxdyzu 1 300 train
+wrradfkjwg 1 300 val
+wrrialmoka 1 300 train
+wrriipmitg 1 300 train
+wrrkppnpum 1 299 train
+wrrtklwiuf 1 300 test
+wrrwsbvwcq 1 300 train
+wrryhchxlc 1 300 train
+wrrzpnzizt 1 300 train
+wrsaausqwc 1 300 val
+wrsbabzvgz 1 300 train
+wrsppbjlhw 1 241 train
+wrsxxqkvay 1 299 val
+wrsyaburul 1 300 val
+wrsypvucwq 0 300 train
+wrtdemjmpm 1 300 train
+wrtgxnxosr 1 300 train
+wrthbfvfbk 1 300 train
+wrtifcouxn 1 300 train
+wrtikpfmte 1 300 val
+wrtqbywtvy 0 300 train
+wrtyglejwz 1 300 train
+wrtyxfvpsv 1 237 train
+wruglpwldh 1 300 test
+wruhcnrjue 0 300 train
+wrukpjuqhi 1 300 val
+wrundxbxwx 1 300 train
+wrupnwudll 1 300 train
+wrupxfszar 1 300 train
+wrvbcscloj 0 300 train
+wrvhqcejsg 1 300 train
+wrvlvrtarm 0 300 val
+wrvmffkfbk 1 300 train
+wrvpgpwyhf 1 300 val
+wrvuuxdxbe 0 298 train
+wrvwgnchqv 0 300 train
+wrvwxjnzls 1 300 train
+wrvzdcemwj 1 300 train
+wrwcocyzqq 1 241 train
+wrwcwnvdhd 1 299 test
+wrwethjyrk 1 299 val
+wrwukrncnw 0 300 train
+wrxeztqxpo 1 300 val
+wrxhqawyaj 1 300 train
+wrxqxkkxyi 1 299 val
+wrxrekscru 1 301 train
+wrxusrghky 1 300 train
+wrybstjzbb 1 300 val
+wryfbokimr 1 300 train
+wrygcoymnd 0 300 train
+wrygwoauva 1 301 train
+wrykrkydga 1 300 train
+wrylymfgvz 1 300 train
+wrythobgze 1 300 train
+wryzbpusvg 1 301 train
+wrzuojwklk 0 300 train
+wrzuyvgcog 1 300 test
+wrzxsnpdmv 1 300 val
+wrzyzdmjnk 1 300 train
+wsaaynadmn 1 300 train
+wsacvnltbj 1 300 train
+wsakxxhoae 1 300 val
+wsakyfrbca 0 300 train
+wsanbrfwmg 1 300 train
+wsaslefmeg 1 300 train
+wsaxvfvxiv 1 301 train
+wsbalvzdju 0 300 val
+wsbanqmvrr 1 300 val
+wsbeksyrjr 1 300 train
+wsbephsymx 1 300 train
+wsbmdyjgvg 1 300 train
+wsbpdqresx 1 300 train
+wsbsojuqeq 1 300 train
+wsbtkqapev 1 299 val
+wsbvyvmdmv 1 302 train
+wsbxcztvel 1 300 test
+wsbyphhumg 1 300 train
+wscbktdfig 1 300 train
+wscclwhfsr 0 300 train
+wscfgbfhjz 1 300 train
+wscjhgdwta 1 301 train
+wscmnkzpaz 1 300 train
+wscurxsmqd 0 601 train
+wscvtxpenw 1 300 train
+wsdaezrogo 0 300 train
+wsdapjagzu 1 300 train
+wsddebiizr 1 300 train
+wsddribrjr 1 300 train
+wsdguuiibr 1 241 train
+wsdkrqmetv 1 300 val
+wsdmluldfm 1 300 train
+wsdtzwmvmi 1 300 train
+wsdywquobb 1 300 val
+wsebjdlmpu 1 300 train
+wsebtxavoi 1 300 train
+wsehjyuxgf 1 300 train
+wserbzzjtc 1 301 train
+wsesvfjvoi 1 300 train
+wseswhoteo 0 300 val
+wseujdouzt 1 300 train
+wsevdaoxpo 1 298 train
+wsfcjhyurf 1 300 train
+wsfdumvwvq 1 300 val
+wsfkcvnzxj 1 300 train
+wsfknjgpbt 1 298 val
+wsfmbnekdk 1 300 train
+wsfwysxlsf 1 300 train
+wsfyunglos 1 300 train
+wsgmrrwxwt 1 300 test
+wsgnmyypsz 1 300 val
+wsgojpccig 1 300 train
+wsgraxqucy 1 300 train
+wsgrjxvjxt 1 300 train
+wsguuejitn 0 300 train
+wsgwuvbdas 1 300 train
+wsgzlhyxqm 1 300 train
+wshaxklwmm 1 300 train
+wshcxrtrvv 1 300 train
+wshiwrfkmd 1 300 train
+wshjkkbvui 1 300 train
+wshlurhfij 1 300 train
+wshmdjzmob 1 300 train
+wshnseesqc 1 300 train
+wshoqctusn 1 300 train
+wsizcajhei 0 300 train
+wsjkhlnval 1 300 train
+wsjszoiwxk 0 300 train
+wsjuvcyghy 1 237 train
+wskpccptcp 1 300 train
+wskvdyyjwy 1 300 train
+wslasvcbwn 1 300 train
+wslkikliky 1 300 val
+wsllqyqzgp 1 300 train
+wslnjeojxb 1 241 train
+wslnqfisgs 1 301 train
+wslsgytaav 1 300 train
+wslwbajajf 1 300 val
+wslxekjtyo 1 300 val
+wsmaogoawz 1 300 train
+wsmejikxds 1 296 train
+wsmgfkgzry 0 301 train
+wsmnhrpomc 1 298 train
+wsmqdgrkzf 1 300 train
+wsmuyaidpf 0 300 train
+wsmvqmfpfn 1 300 train
+wsmvrhsxpd 1 301 train
+wsmxcofadn 1 300 val
+wsmyrehokt 1 300 train
+wsmzreduuh 1 300 train
+wsnjhghyvb 0 300 train
+wsnlpfitef 1 300 train
+wsnybadpno 1 300 train
+wsoatzjtsu 1 300 train
+wsoiimkmvh 1 300 train
+wsojkycwgs 1 300 val
+wsomcxgzmm 1 300 train
+wsommruqyf 1 300 val
+wsomvuvpsu 1 269 train
+wsonbmnnbc 1 300 train
+wsontyfthg 1 301 val
+wsoorusvod 1 301 train
+wsoqydjebg 1 300 train
+wsowqgafhf 1 300 val
+wsphuogufg 0 300 val
+wspmyefsiv 0 300 train
+wsptmivopf 1 300 train
+wspzlksdsb 0 300 val
+wsqagfmhoq 0 300 train
+wsqbtabydl 1 300 train
+wsqjewusqp 1 300 train
+wsqjykletd 1 300 val
+wsqoayghop 1 297 train
+wsqommwqmf 1 301 train
+wsqqgzqorx 0 300 train
+wsqqihojra 1 300 train
+wsqtdstyyd 1 300 val
+wsqxgcgkzm 1 292 val
+wsqyyixomg 0 300 train
+wsrahogrkd 1 300 train
+wsrclsksle 1 300 train
+wsrdmoqfkb 1 302 val
+wsrgbixfae 1 300 train
+wsrkqltvcg 1 300 train
+wsrpozorjv 1 300 train
+wsrukvyqjp 1 300 val
+wssiqeuwfl 0 301 train
+wssiuonxge 0 300 train
+wsslnvzhdq 1 300 train
+wsssqeilpm 1 300 train
+wssvyxdsox 1 300 train
+wstdnoremg 1 300 train
+wstgvdiflj 0 300 train
+wstjfparsn 1 300 train
+wstplpgofm 1 300 train
+wstwunclrh 0 300 val
+wsufhnbbyq 0 300 train
+wsuhxkwpgq 1 300 train
+wsulrzcgzr 1 300 val
+wsuouxuuen 0 300 train
+wsusovpzyb 1 302 train
+wsuyynivgn 1 300 train
+wsvtbtnvls 1 300 val
+wsvworhyrq 1 299 train
+wswbrzugsn 1 300 train
+wswdtdiadq 0 300 val
+wswmgmtfnc 1 300 val
+wswnlvujup 0 300 val
+wswreaygcq 1 300 train
+wswsptapvq 1 300 train
+wswxsgbvwa 1 300 train
+wswylwaylm 1 300 val
+wswzulamik 1 300 train
+wsxfskskbe 1 300 train
+wsxltqhmwi 1 300 train
+wsxnvbobyw 0 300 train
+wsxuvrzzre 1 300 train
+wsxvmuloch 1 300 train
+wsxxdlhnhh 1 300 test
+wsxyuwcrfx 0 300 train
+wsybiqfawv 1 300 train
+wsyptfbnbl 1 300 train
+wsyrjpuxsx 1 300 train
+wsyrpvtfne 1 300 val
+wsyscepfyf 1 300 train
+wsyszvqqqy 1 300 train
+wsyxoulibo 1 301 train
+wsyxuihxcp 1 300 val
+wszbxwswac 1 300 train
+wszebkrprd 1 300 train
+wszezcapgi 1 300 train
+wszltsolxr 1 300 train
+wszlwjntoi 1 300 train
+wszlxixmte 1 299 val
+wszppqgytq 1 300 train
+wszvhoeuyz 0 301 train
+wszywhvame 1 300 train
+wtaatddekg 1 300 train
+wtaghbgiln 0 300 val
+wtahejnbel 1 300 val
+wtajyouerz 1 300 train
+wtanjtncth 0 300 train
+wtaoxkutmc 1 300 train
+wtaqquzolu 1 300 train
+wtaradydlz 1 300 val
+wtariodlhw 1 300 train
+wtarywxums 0 300 train
+wtaxqylhyk 1 300 val
+wtaxylahuf 1 300 train
+wtbaoqadts 1 300 train
+wtbbjzmqft 1 300 train
+wtbbypnsir 1 300 train
+wtbeuclbtp 1 300 train
+wtbgotbkky 1 300 val
+wtbhlbuiqi 1 300 train
+wtbijofqxd 0 300 train
+wtbipkvlbb 1 300 train
+wtbnhgpjcz 1 301 val
+wtbnhotsyr 1 300 train
+wtbnmhswrx 1 300 train
+wtbptkjzdm 1 300 train
+wtbqzappqs 1 300 train
+wtbtcunklv 0 300 train
+wtbxfjxvpd 1 300 train
+wtbxixcqwr 0 299 train
+wtbymahdkr 1 241 train
+wtccimfyiz 1 298 val
+wtcfywxbut 1 300 train
+wtcifohuqs 1 300 val
+wtcucxffhj 1 299 val
+wtcvgvuqzd 1 300 test
+wtcyvgqipx 1 300 train
+wtdmgazqdu 0 300 train
+wtdnljorij 0 300 train
+wtdpjzybmb 1 301 train
+wtdrujgqaw 1 300 train
+wtduhkvivp 1 300 train
+wtdwlioard 1 300 train
+wtdzwkcxwb 0 300 train
+wtecgxnwvw 1 300 train
+wtemuunvcc 1 301 train
+wteoyjpszy 1 300 train
+wtepvazeyq 0 300 train
+wteqtorytl 0 300 train
+wteueacknc 1 300 train
+wteuilkjci 1 300 train
+wtevldzrgu 0 237 train
+wtewzztpkz 1 240 train
+wtfbmeltka 1 249 train
+wtfdqqohhr 1 300 train
+wtfgfzqlgb 1 300 train
+wtflqeomcq 1 300 train
+wtfqzzrxmx 1 300 test
+wtfrjlqnit 1 300 val
+wtfxmkdcgn 1 300 train
+wtfzwexbjl 1 300 train
+wtgdnkeogm 1 300 val
+wtgeszgkeu 1 300 train
+wtgfrdyxka 1 301 val
+wtgnhvqocu 1 300 train
+wtgnniucez 1 300 train
+wtgnuwahwq 1 300 val
+wtgnzwybsi 1 300 train
+wtgoueyuyq 1 300 train
+wtgrblmkfw 1 300 val
+wthducuplp 1 300 val
+wthekfboxv 1 298 train
+wthgwbqtlf 0 300 train
+wthieczdrf 1 300 train
+wthjdvoqih 1 300 train
+wthrnfhwww 0 300 train
+wthxksfpti 1 299 train
+wtibohskib 1 298 train
+wticrcwlut 0 300 train
+wtiesshbnh 1 300 train
+wtiewggmhr 0 300 train
+wtiiirtceq 1 300 train
+wtiqgsbrmv 1 300 train
+wtiscahftt 1 300 train
+wtiydmauea 1 300 val
+wtjkptrfqi 1 301 train
+wtjpiqfsxi 1 300 train
+wtjxirptnm 0 300 train
+wtkenmfkss 1 288 train
+wtkgrlrxwo 1 300 train
+wtksmqsqjo 1 300 train
+wtlbvxygla 1 300 train
+wtlcpbauip 1 300 train
+wtleprqedb 1 300 train
+wtlquahwwu 1 301 train
+wtlxmwrrsv 1 300 val
+wtmggpeiom 1 300 train
+wtmhjldbti 1 300 val
+wtmhkoctjf 0 300 val
+wtmkiianwm 1 301 val
+wtnbntuaet 1 300 train
+wtnloygygs 0 301 train
+wtnorqpfed 1 300 train
+wtnqmcwadh 1 302 train
+wtnqmgffjm 1 301 train
+wtnydqjsun 1 288 train
+wtnyvmgwvc 1 301 train
+wtobkqodrn 1 300 train
+wtodmcqznh 0 300 train
+wtomnouzjy 1 301 val
+wtooqmfqsq 1 300 train
+wtoqmdcdiu 1 300 train
+wtoqnvchtu 1 300 train
+wtosjkwjyl 1 300 train
+wtoxfiiidm 0 300 train
+wtoymlcfxo 1 300 val
+wtozgoeiye 1 300 train
+wtparmhfcp 1 269 train
+wtpayeacxh 1 300 train
+wtpbgggcga 1 300 train
+wtphvujfxn 1 300 train
+wtpmqxjbgl 1 300 train
+wtptdggoni 1 300 train
+wtpwgrucvn 1 300 train
+wtpzfyqvyu 1 300 train
+wtqfhcucsp 1 300 train
+wtqjuvkbgi 1 300 train
+wtqpqgdpkx 1 300 train
+wtqrmqnqvf 0 300 train
+wtqsolhdal 1 297 train
+wtqviskydz 1 300 train
+wtqwvhlpdl 1 300 train
+wtqxnnemoi 0 300 train
+wtqxtwpltv 1 300 train
+wtreibcmgm 0 300 train
+wtroauoykb 1 300 val
+wtrooinibf 1 250 train
+wtroqagvzk 1 300 train
+wtsguxyrkq 0 300 train
+wtsklpmrwp 0 300 val
+wtssfdealc 1 300 train
+wtsstxpita 1 300 val
+wtstryomgh 1 300 train
+wtsyahfooi 1 300 val
+wttdavqxij 1 300 train
+wttdpxzalp 1 300 train
+wttduqfhvo 1 300 train
+wttefcxxlk 1 300 train
+wttghgtooh 1 300 train
+wttgqrzwef 1 300 val
+wttnuawrvh 1 300 train
+wttxitxhen 0 300 train
+wttzqronyy 1 300 train
+wtuhwrpnio 1 300 train
+wtuxdsaxdo 1 300 val
+wtvcumvxjq 1 300 train
+wtvdnpyslw 1 300 val
+wtvghvmphb 1 300 train
+wtvhfnsnmr 1 300 train
+wtvponpppa 0 300 train
+wtvritaikp 0 300 train
+wtvswrthcc 1 300 train
+wtvvzotpvp 1 300 train
+wtvwzxfbrg 1 300 train
+wtwcaozswq 1 300 train
+wtwdpalgla 1 300 train
+wtwgtnbhme 0 300 train
+wtwhntlegi 0 300 train
+wtwozczklu 1 300 train
+wtwvuyisfc 1 300 train
+wtwwfsqnjj 1 292 val
+wtwygxzgjp 1 300 train
+wtwzabqriy 1 300 train
+wtxbmlzyff 1 300 val
+wtxcbhnmao 1 298 train
+wtxdmdquhm 1 301 train
+wtxkwbvtqo 1 300 val
+wtxollncfy 1 300 train
+wtxudtaebc 1 300 train
+wtyggqowze 1 300 train
+wtyhtvvkfy 1 300 train
+wtykrjdsvo 1 300 train
+wtykulolsd 1 300 val
+wtymotrufg 0 300 train
+wtyqqogjwf 1 300 val
+wtysqugerf 1 300 train
+wtzhpderof 1 300 train
+wtzihgrqei 1 300 train
+wtzjtumkbz 0 300 train
+wuafwwsopo 1 300 train
+wuaoezxmdm 1 300 test
+wuazmgotru 1 300 train
+wuazsmjusz 1 300 train
+wubcgigcfd 1 300 train
+wubfserltl 1 300 train
+wubkawsoey 0 300 train
+wublpnmyzy 1 300 train
+wubvkmiugp 1 300 train
+wubxcfyiud 0 300 train
+wubygrcsbs 1 300 train
+wucfhjkugx 1 302 train
+wucrjkwdxe 0 300 train
+wucyoanghr 0 300 train
+wudkmejywf 0 300 train
+wudncdmcli 1 100 train
+wudvgajlpk 1 298 train
+wudvgiqljj 1 297 train
+wudzyuvjwx 1 300 val
+wuejumpnpj 1 299 test
+wueltsmvon 1 300 train
+wuephgpttf 1 300 train
+wuepoflvkx 1 300 train
+wuerpubzlq 1 300 train
+wuesrzmujo 0 300 train
+wuetedwkxe 1 300 train
+wufljleufw 1 300 train
+wufrggusgu 0 300 train
+wufsogqfhx 1 300 train
+wufubdiuow 1 300 train
+wufurcqsnc 0 300 train
+wufyuokxla 1 300 train
+wugacbfclz 1 269 train
+wuggjlcxoc 1 241 train
+wughaobomg 1 300 train
+wughgongbo 1 300 train
+wugkgprala 0 300 train
+wugnnrsolg 1 300 test
+wugryppvfr 1 300 train
+wugwyvxgxc 1 300 train
+wugzepvpix 1 301 train
+wuhaehooxn 1 300 train
+wuhdzjhwmb 1 301 train
+wuhfgfwvje 1 300 train
+wuhhbhhfce 1 300 train
+wuhhueyezm 0 300 train
+wuhrhzdfyc 1 300 val
+wuhsetsmba 1 300 test
+wuhumqjoya 1 300 val
+wuhxicjmkj 0 300 train
+wuhxphfeul 1 300 train
+wuiabpdxjy 1 300 train
+wuibnvebom 1 300 val
+wuibwvbtfd 1 300 train
+wuieyeoaca 1 241 train
+wuiiauthrr 1 300 train
+wuikplzxgc 1 300 train
+wuinmxmupl 1 300 val
+wuivvxzamz 1 301 train
+wujiaaoasw 1 300 train
+wujmeijboc 1 300 train
+wujzfknpfb 1 241 train
+wujzgtmhve 1 301 train
+wukaqaoorx 1 300 train
+wukbidwwhd 1 300 train
+wukdfhaovv 1 300 test
+wukdokngxd 0 300 train
+wukdzzkhne 1 300 val
+wukekfmtha 1 300 train
+wukfwqdsyt 0 300 train
+wukpaivfrp 1 300 train
+wukprnrnlv 0 300 train
+wukrqihtjc 1 241 train
+wukvctblmd 0 300 train
+wukxigivxf 1 300 train
+wukxspspat 1 298 train
+wulbfxmthd 1 300 train
+wuldwujmhw 1 300 train
+wulqkgrpgs 1 300 train
+wumamxjocm 1 300 val
+wumbpgobtw 1 300 val
+wumhhlnzfg 1 299 train
+wumjuyiegg 1 300 train
+wumkadhelo 1 300 test
+wumohkrqpa 0 300 train
+wumqybiwxk 1 300 train
+wumsqxvtrj 1 300 train
+wumxdxsnsm 1 300 train
+wumyechwrx 1 300 train
+wumyyrqqqy 1 300 train
+wunexybbqe 1 300 train
+wunigwmyit 0 300 train
+wunlacbrdn 1 300 train
+wunlbtnyow 1 300 train
+wunrpcbbpw 1 300 train
+wuoxykvoee 0 300 train
+wuoyuhmixr 1 300 train
+wupekdigtq 1 300 train
+wupiyutxjw 1 300 train
+wuplybnjoi 1 300 train
+wupmdvkstt 1 300 train
+wupoiiknff 0 300 train
+wupqwhzzuz 1 300 val
+wuprhbkgjh 1 300 train
+wupsrvmats 1 301 val
+wupxckqsiv 1 300 train
+wupxehnqmf 1 241 train
+wupycrhbnu 1 300 train
+wupzrhdzee 0 298 train
+wuqastichm 1 300 train
+wuqbhatrhd 1 300 train
+wuqfstvvuh 1 300 train
+wuqgkqcpqz 1 300 train
+wuqivhwjuw 1 300 train
+wuqofkqwcg 0 300 train
+wuqojhhghj 1 300 train
+wuqopyuwgc 1 301 train
+wuqugthrbo 1 300 train
+wurddwxbhk 1 300 train
+wureffmvbl 1 300 train
+wurlkjdhix 1 301 train
+wurlmkmjdz 1 300 train
+wurouzavgm 1 300 train
+wurrrkccib 1 300 train
+wursaaderz 0 301 train
+wurzsvkseg 1 300 train
+wusbiwxoig 1 300 train
+wusdugjahp 1 300 train
+wusmmlbiey 1 300 train
+wusopfvmiz 1 300 train
+wuspozzszs 1 300 train
+wuszzqsacr 0 300 train
+wuteixflxl 1 300 train
+wutjqxsbwy 1 300 train
+wutlluusdq 1 301 val
+wutqmgtqac 1 300 test
+wutyhpijbf 1 300 val
+wuucxbsnok 0 300 train
+wuuekucgjv 1 300 train
+wuukgazskn 1 300 train
+wuukscrgck 1 300 train
+wuusthsvhm 1 300 train
+wuuvcuozwm 1 300 val
+wuuwynrxyc 1 241 train
+wuuynkzrgo 1 300 train
+wuvdutfecc 1 300 train
+wuvfhsljni 1 300 train
+wuvfqqwknv 1 300 train
+wuvhebfqko 1 300 train
+wuvhlkvrwx 1 300 train
+wuvjksedfn 1 250 train
+wuvlrtgqem 1 300 train
+wuvnontvod 1 300 train
+wuvpewldnx 0 300 val
+wuvsllezbv 1 300 val
+wuwjbgoggt 1 300 train
+wuwluwpbco 1 270 train
+wuwlzwmbdt 1 301 val
+wuwohbbohp 1 300 train
+wuwoujnrfn 1 300 train
+wuwpxwvmxd 1 300 train
+wuwxyvlfsg 1 300 train
+wuwznqirri 1 300 train
+wuxbixoqkr 1 298 train
+wuxcxwdack 1 300 train
+wuxhkqfxun 1 300 train
+wuxhlgdtca 1 300 train
+wuxjibilxd 1 300 train
+wuxmzsxlyv 1 300 train
+wuxsmzxkfk 1 300 test
+wuxuvrdtmy 1 301 train
+wuxwvevyry 0 300 train
+wuxyxnyteh 1 300 train
+wuxzucippy 1 300 train
+wuydpzanps 1 296 train
+wuyfhaublo 1 300 train
+wuyiwpahlh 1 302 train
+wuylpubnjt 1 300 train
+wuyphpuqab 1 241 train
+wuyqbxuaay 1 300 train
+wuyxgrolqy 1 300 train
+wuyxrdccff 1 300 train
+wuyzidtfnb 1 298 train
+wuzargauni 1 269 train
+wuzcwsdvdf 1 300 train
+wuzdcvejpa 1 300 train
+wuzdkxkzge 1 300 train
+wuzdxyybdd 1 300 train
+wuziejscwj 0 300 train
+wuzxcgxvqr 1 300 train
+wvafukaycj 1 300 train
+wvarmvipep 1 300 train
+wvartnpkqz 1 298 val
+wvatstfqdp 1 300 val
+wvatuqkdjx 1 300 train
+wvatwxplew 1 300 train
+wvavgsllrx 1 300 train
+wvaxyxliim 1 300 train
+wvbedpkbci 1 300 train
+wvbfrerdmv 1 300 train
+wvbgmbjfal 1 300 train
+wvbijgptdw 1 299 val
+wvblxosrcj 1 300 train
+wvbpwhleci 1 300 train
+wvbpxcxqjd 0 143 train
+wvbrjkbcds 1 300 train
+wvbrqpkykd 1 300 train
+wvbsqowiwh 1 301 val
+wvbvcbghrx 0 300 train
+wvbyeavnpk 0 300 train
+wvbzxaspaa 1 300 test
+wvccagxjni 0 301 train
+wvccljnvbx 1 300 train
+wvcddgkyqc 1 301 train
+wvcndrevvc 0 300 train
+wvcqevnjta 1 300 train
+wvcttyyotq 1 298 train
+wvcurgjium 1 300 train
+wvdczwsksw 1 296 train
+wvduthysvb 1 300 train
+wvdwbzdhub 1 300 train
+wvdxuyxera 1 298 train
+wvdysjxxxh 1 300 train
+wvdzmvoihl 1 300 train
+wveczdwupd 1 300 train
+wvekjsptyp 1 300 train
+wvemhnofyd 1 300 train
+wverprfbsh 1 300 train
+wveshjdqcm 1 300 train
+wvexmnjsmw 1 300 train
+wveyfgpchl 1 300 train
+wvfcqexlox 1 298 train
+wvfdsinawu 1 300 train
+wvfirpiqam 0 300 train
+wvfkdzqwxk 1 300 val
+wvfogdcqun 1 300 train
+wvfwdxclpe 1 300 val
+wvgbivcdmf 0 300 train
+wvgeaycdab 1 239 val
+wvghyzwiub 1 300 train
+wvgmraeauh 1 300 train
+wvgorflckf 1 301 train
+wvgpbefknk 0 298 val
+wvgpythqqe 1 300 train
+wvgviwnwob 1 300 test
+wvgwvktvzb 0 300 train
+wvgzsmivuu 1 300 train
+wvhadwnfhv 1 300 train
+wvhdplgccl 1 300 train
+wvheuonrbk 1 300 train
+wvhgkjrbre 1 300 train
+wvhgqlaiun 0 300 train
+wvhmrpyezi 1 300 val
+wvhqimwfqm 1 300 val
+wvhqnobxii 1 300 train
+wvhrbddrfm 1 300 train
+wvhsizqfqc 0 300 train
+wvhuofmkbv 1 249 train
+wvhxtfpjym 1 301 train
+wviccdzclo 0 300 train
+wvidwatgqo 1 300 train
+wviixuiizk 1 241 train
+wvivhzmnyr 1 300 train
+wvjbkmpfre 0 300 train
+wvjdbenjif 1 300 train
+wvjdbxaxdq 1 300 val
+wvjgnxdkqw 1 300 train
+wvjlljxfdj 1 300 val
+wvjmrkhhnl 1 300 val
+wvjrbtuvae 1 300 train
+wvjtrmduky 1 300 val
+wvjuhsrnuz 0 300 train
+wvkaurrdqg 1 136 train
+wvkcackxyk 1 300 train
+wvkixatwdp 0 300 train
+wvkkbigbww 1 300 train
+wvkkeeqiax 1 300 val
+wvkkqapkjv 1 300 train
+wvklmiggae 1 300 train
+wvknjyuwax 1 300 val
+wvknzfvqhx 1 301 train
+wvkvcmxrhq 1 300 train
+wvkwwhibwr 1 297 train
+wvkxybusdb 1 239 train
+wvkysjpokb 1 300 val
+wvkyuahffy 1 300 train
+wvkzhvueob 1 300 train
+wvlagvverc 1 300 val
+wvljksdyzt 1 300 train
+wvllhzqeje 1 301 val
+wvlmhsbhhh 1 300 train
+wvlnveemuy 0 300 train
+wvlpmhtkis 1 301 val
+wvlrwangku 0 300 train
+wvlspkziod 1 300 val
+wvlspxyxlb 1 300 train
+wvlzalvbft 1 300 val
+wvmdvshdif 1 300 train
+wvmjouzbfy 1 300 train
+wvmnylsikk 1 300 train
+wvmrsucbsq 1 300 val
+wvmswjdtjo 0 300 train
+wvmypnucmc 1 301 val
+wvnaqfxyvw 1 300 train
+wvngbenors 1 300 train
+wvnjcwevzo 0 300 train
+wvnkcfstpn 1 300 val
+wvnnqdvgsa 1 300 train
+wvntktxgnd 1 300 val
+wvnvcgworu 1 300 train
+wvnyqjpwvu 1 300 train
+wvofdgzfij 1 300 train
+wvofjmpceq 0 298 train
+wvogcdupho 1 300 train
+wvolharzyg 1 300 train
+wvowpyqjjp 0 300 train
+wvowwzbgbd 1 300 test
+wvpjakoned 1 300 train
+wvplwbyxpy 0 300 train
+wvpnravyge 1 300 train
+wvpvheatlc 1 300 val
+wvpwszxxpx 0 300 train
+wvpxqmpjya 0 300 val
+wvqeikcirb 1 300 train
+wvqgqiyhvn 1 300 train
+wvqhwvdppe 1 300 train
+wvqqbexyas 1 300 val
+wvquphksdy 0 300 train
+wvqxswnlza 1 300 train
+wvrjrdaead 1 300 train
+wvrkriyavi 1 300 train
+wvrmjfobub 1 298 train
+wvrukkxukm 0 300 val
+wvrzowftpz 1 300 val
+wvsbunlvnx 1 300 val
+wvsiixsqhe 1 300 train
+wvsqhuzeto 1 300 train
+wvsvkxdphg 1 300 val
+wvtkikkvdk 1 300 train
+wvtlbewjks 0 300 train
+wvtsixkchg 1 241 train
+wvtymfvbwq 1 300 train
+wvtzzlcujg 1 300 train
+wvuaculbxg 1 298 train
+wvuckdwpfv 1 300 train
+wvudmojtnc 1 300 train
+wvudpejgdg 1 300 train
+wvuevznshn 1 300 train
+wvufcbiifb 1 300 train
+wvugomrhus 1 300 train
+wvuquwzaib 1 300 train
+wvurelqgfw 1 300 train
+wvustidpql 1 299 test
+wvuualjyur 1 300 test
+wvvapfomrv 1 300 train
+wvvgmyhggx 1 300 val
+wvvhsklwun 1 300 train
+wvvmhhqqsf 1 300 train
+wvvpqxdlmr 1 300 train
+wvvqyqidmi 1 301 val
+wvvruudgho 1 300 train
+wvvugqjxdx 1 300 train
+wvvzbxnnhw 1 300 train
+wvvzfioonp 0 300 train
+wvvzhovtff 1 300 train
+wvwhdvlngc 1 300 train
+wvwhlywznt 1 300 train
+wvwmiaqwoe 0 300 val
+wvwpsklbax 0 300 train
+wvwrmzseab 1 300 train
+wvwtlmysty 1 300 val
+wvwzbzgcxz 1 300 train
+wvwzndwrnp 1 300 train
+wvxcpnamya 1 300 train
+wvxgxcukbb 0 300 train
+wvxlbegcgn 0 300 val
+wvxmbfqzrf 1 300 train
+wvxnypxnwu 1 300 train
+wvydgwnwba 1 241 train
+wvynuzhokw 1 300 train
+wvywfrvxxy 1 300 train
+wvyxosxpii 1 300 train
+wvzccmymsy 1 300 train
+wvzctryowi 1 300 train
+wvzdvmznxr 1 300 train
+wvzfvppvmp 1 300 train
+wvzfyhqymz 1 300 train
+wvzwzyttty 1 300 train
+wvzxihummi 1 300 val
+wwagqraavr 1 301 train
+wwanpbqkcu 1 300 train
+wwanxwacln 1 300 train
+wwaworzfbr 1 300 train
+wwbbevqdac 0 301 val
+wwbkujggiy 1 300 val
+wwbqrjjmwg 1 300 train
+wwbvcyialw 0 300 train
+wwbyxfgqhv 1 301 train
+wwcckunhbu 1 300 train
+wwcowbnwms 0 300 val
+wwcqezgvfz 1 147 train
+wwcsevedoc 1 300 train
+wwcuqgzbgp 1 300 val
+wwcvjdlrdf 1 300 train
+wwdijfkpss 1 300 train
+wwdnlqnfrb 1 300 train
+wwdtqfsepw 1 300 train
+wweauubbst 1 300 val
+wweglcwrov 0 300 train
+wwegzjbkyl 1 300 train
+wweitzjyve 1 298 train
+wwemjraffl 1 300 val
+wweongzngy 1 300 train
+wweptsajlq 1 300 train
+wweuywblun 1 300 train
+wwfbaufwlb 1 300 val
+wwfdlsmjmg 1 300 train
+wwfdmnhlty 1 299 test
+wwfehhmmhl 0 241 train
+wwffrwubph 0 300 train
+wwfqrtuitk 1 301 train
+wwftgfyzln 0 300 train
+wwfviieqbe 1 300 train
+wwfwludyqk 1 300 val
+wwglepzxyi 1 300 train
+wwgmzeavbd 0 300 train
+wwgppzxacy 1 300 val
+wwhiwivvgv 1 300 train
+wwhknolvct 1 300 train
+wwhksmygxt 1 299 train
+wwhlwueoax 1 300 train
+wwhnldwusk 1 300 train
+wwhoskwcpa 1 301 val
+wwhrhyqbtb 1 300 val
+wwhywvbglv 1 300 train
+wwibanagfz 1 300 train
+wwibennpjf 1 300 train
+wwicrwrxkr 1 300 train
+wwifkqnbyf 1 300 train
+wwiixjiuld 0 300 train
+wwinewszce 1 300 val
+wwjbhplvds 1 300 val
+wwjectsuyx 1 300 val
+wwjkwbvorq 1 300 val
+wwjqfmivqm 1 300 train
+wwjtyvbyrl 1 300 train
+wwkbytibhl 1 300 train
+wwkfsshyyo 1 300 val
+wwkgmbzvss 1 300 train
+wwkiddjuma 1 300 train
+wwkmeypytp 1 299 test
+wwkraoiksx 0 300 val
+wwlesapydn 1 300 train
+wwlmrvdktj 1 300 val
+wwlnrlkvqo 1 300 train
+wwlogtlpau 1 300 train
+wwltqkgxev 1 300 train
+wwlxqmoswf 1 300 train
+wwmfpzskba 1 300 train
+wwmjfkgzyj 1 300 val
+wwmjsyjawr 0 300 train
+wwmkrcogpg 1 299 test
+wwmugwsirs 1 298 train
+wwmvkhdysc 1 298 train
+wwnauklarb 1 299 val
+wwnawqejsq 1 300 val
+wwndogmadr 1 300 val
+wwnggpmpqb 1 300 train
+wwnkihrywu 1 300 train
+wwnrsxxqjb 1 300 train
+wwntrbozng 1 300 train
+wwnxdjcyoy 1 300 train
+wwolrxvqkq 1 300 train
+wwosyigcii 1 300 train
+wwoukeyjtf 1 300 train
+wwozuefkgl 0 300 train
+wwozzfwflr 1 300 train
+wwpiiumcyw 1 300 train
+wwpkedzkkq 1 300 val
+wwpktjxirp 1 300 train
+wwpmcbctbo 1 300 val
+wwpmjsyeta 1 300 train
+wwpnuahvkz 1 300 train
+wwpnzhevou 1 301 val
+wwqefbwwso 1 300 val
+wwqifurkes 1 300 train
+wwqiuiwdbz 0 300 train
+wwqlfsximb 1 300 val
+wwqnrsjgdn 1 300 train
+wwqptmclnt 0 300 val
+wwqqibrycf 1 300 train
+wwqqutfxxe 1 300 train
+wwrkilcjdh 1 300 train
+wwrrzvhpqg 1 300 train
+wwrzdnaoap 1 299 train
+wwsfqkfkep 0 300 train
+wwsrewoygk 1 300 train
+wwsviizdcp 1 301 train
+wwswaybymx 0 300 train
+wwszykqgqk 1 300 train
+wwtencfqpf 1 300 train
+wwtinsbkru 1 300 val
+wwtkglbqqq 0 300 val
+wwuodnejun 1 298 train
+wwvcpyzdki 1 300 val
+wwvdpqjrih 1 300 train
+wwvhxbpjuj 1 300 val
+wwvsdyrofn 1 300 train
+wwvwoppudl 1 300 train
+wwvykizoms 1 300 test
+wwvzjspizs 1 300 val
+wwwbocaabd 1 301 train
+wwwgkzucth 1 300 train
+wwwhqdekfe 1 300 val
+wwwhrimalk 0 300 val
+wwwnwpitjl 0 300 train
+wwwpyljqin 1 300 train
+wwwwowftkr 1 255 train
+wwxbhnpois 1 300 train
+wwxepftxbv 1 300 train
+wwxgzqjcba 1 300 train
+wwxlhjpqou 1 300 train
+wwxrjeillm 1 300 train
+wwxtkyplyq 1 300 train
+wwxugucmzx 0 300 val
+wwxvvzuesx 1 300 val
+wwycqkthwl 1 300 train
+wwysaksksm 1 300 val
+wwytygqhzh 1 300 val
+wwzcwueeas 1 298 train
+wwzfxsvubn 0 299 val
+wwzgmogotk 1 300 train
+wwzhegmyfd 1 300 train
+wwzjffjmfo 1 301 train
+wwzkmddgcf 1 301 train
+wwzlklvytz 1 300 train
+wxacbnohsk 1 300 val
+wxajoyaxnm 1 302 train
+wxaowhmopb 1 302 val
+wxasmxwwup 1 300 train
+wxaucsbekq 1 300 test
+wxavtnsmdr 1 300 train
+wxavwmybea 0 300 train
+wxaxyyatph 1 301 train
+wxbfeciqbt 1 300 val
+wxbhdoyjec 1 300 train
+wxbjxyrrpb 1 300 train
+wxbkyghibx 0 300 train
+wxbnwdcxwl 1 300 train
+wxbsgcpjsi 1 300 train
+wxbtpkhdie 1 300 test
+wxbtskxdzy 1 300 train
+wxbxmnvmkn 1 300 train
+wxcbceuyrb 1 300 train
+wxccemraeb 1 300 val
+wxceoaedfx 1 300 train
+wxcgepdptw 0 300 train
+wxcvmzqpsy 1 300 train
+wxcwmtunoi 1 300 train
+wxdbxfgtgt 1 300 train
+wxddvpskqv 1 299 val
+wxdechnlvk 1 300 train
+wxdhxyoory 1 300 train
+wxdhzqpzem 1 300 val
+wxdjztedeg 1 255 train
+wxdljcjcud 0 300 train
+wxdlspyrov 1 302 train
+wxdtsmszxj 1 300 test
+wxecaxeyew 1 300 train
+wxegjawfof 0 300 val
+wxehyzqfqc 1 300 train
+wxeidueoyu 1 300 train
+wxenkxwymo 1 300 train
+wxeohxknkm 1 300 test
+wxestvhrql 1 300 train
+wxfbrkllqs 1 242 train
+wxfdxuovei 1 300 train
+wxfivpobfa 1 300 train
+wxfkbikude 1 300 train
+wxfpifvicy 1 300 val
+wxfqdkxweb 1 300 val
+wxfsaflnst 1 300 train
+wxfvvnbfnd 1 300 val
+wxfyabjujx 1 241 train
+wxfylnwgfj 1 300 train
+wxgfpqascd 1 300 train
+wxgphbzlpn 1 300 test
+wxgqhhzsur 1 301 val
+wxgwqnrvmw 0 300 train
+wxhaqrvsif 1 300 val
+wxharhdalm 1 300 val
+wxhdazemzb 1 300 val
+wxhfpfbrob 1 300 val
+wxhgomjhnr 1 300 train
+wxhivsowqf 1 300 train
+wxhlgzasqm 1 300 train
+wxhmspjpve 1 300 val
+wxhnoaiswp 1 300 train
+wxhoviaupm 1 300 train
+wxhrtnsxkw 1 300 val
+wxhswsgaud 1 300 train
+wxiboojdnq 1 300 val
+wxidgolzcc 0 301 train
+wxiksddeef 1 300 train
+wxilslivgv 1 298 train
+wxistscclb 1 300 train
+wxiuwgrqwt 1 300 train
+wxivowlezc 0 300 train
+wxivyqkcuo 0 300 train
+wxjafexjsw 1 300 train
+wxjbdhaxcy 1 300 val
+wxjjpajdod 0 300 train
+wxjlppbixm 1 300 train
+wxjoirvrzb 1 300 train
+wxjsfpwryh 1 301 train
+wxjxtnfijx 1 300 train
+wxjypsvpxe 1 301 val
+wxjyzfzstb 1 300 val
+wxkgwtkvfl 1 300 train
+wxknsmhcfx 1 300 train
+wxkoqowrxt 1 300 train
+wxkxuzaxox 1 300 train
+wxlanyghsv 0 300 train
+wxlbcishuo 1 300 train
+wxlcnxwkzt 1 300 train
+wxlleekyan 1 300 train
+wxluilwgru 1 288 train
+wxlwawltbg 0 288 train
+wxlydtkmex 1 300 train
+wxmahmyrnz 1 300 train
+wxmglytpbf 1 300 train
+wxmhpunzqe 1 300 train
+wxmhpzoqhi 1 288 train
+wxmkbqnciw 1 300 train
+wxmpbsczba 1 300 val
+wxmrlucalu 1 300 val
+wxnbsjlriz 1 300 train
+wxncnevluq 1 300 val
+wxndbtenax 1 300 train
+wxnddisaey 1 300 train
+wxnfaqzfwf 0 301 train
+wxnkjzohuh 1 300 val
+wxnszxspji 1 300 train
+wxnurvshjq 0 300 train
+wxnvhhsazc 1 300 train
+wxnwlupidk 1 300 train
+wxnzbrcoow 1 299 test
+wxocufpfox 1 300 train
+wxoivivyhd 1 300 train
+wxoolmmuvg 1 300 train
+wxossnvxun 1 300 train
+wxotbcsbnt 1 300 train
+wxotqppgxr 1 300 val
+wxotxrfdef 1 300 val
+wxounfzqks 1 300 train
+wxovupaocf 0 299 train
+wxowshmgun 1 300 train
+wxpbsltkgs 1 300 val
+wxphbclnho 1 300 train
+wxpmjhdtwz 1 300 train
+wxpvbwtzfc 1 300 val
+wxpwtgvbrz 1 300 train
+wxqapcezlq 1 300 train
+wxqcerzwfw 1 300 train
+wxqhzlgbbw 1 297 train
+wxqmnnmpbh 1 300 train
+wxqsbaujah 1 300 val
+wxqyuhnhno 1 241 train
+wxqzqirmuz 1 300 train
+wxrdzofyrx 0 300 train
+wxrejedlzu 1 300 train
+wxrfuemtxj 0 300 train
+wxrggtmjqv 1 300 train
+wxrqkiqgix 1 298 train
+wxrrhqmynp 1 136 train
+wxrvnihmnm 1 300 train
+wxsadodudh 0 300 train
+wxsbkjsglo 1 300 train
+wxscorszan 1 300 val
+wxsdjusfjg 1 300 train
+wxsfurwchm 0 300 train
+wxsjszngzp 0 300 train
+wxsptftjqx 1 300 train
+wxsradfqcx 1 300 train
+wxsrpemyau 1 300 train
+wxsvabjvnn 1 300 train
+wxtaezlkxu 1 300 train
+wxtebheqbv 1 300 train
+wxtiaudeag 1 300 val
+wxtlfngfgx 1 300 val
+wxttwnnjqe 1 300 train
+wxtuyelztd 1 301 train
+wxtzhefuon 1 300 train
+wxukovbmac 1 300 train
+wxumwgftzi 1 300 train
+wxuskhbdrn 1 300 train
+wxutankhcc 1 300 val
+wxutfufylt 1 300 train
+wxuwnodjax 1 300 train
+wxuypralbq 1 300 train
+wxvbroicji 1 300 train
+wxvciarwpx 1 300 train
+wxvdvouvld 0 300 train
+wxvqlamqgl 0 300 train
+wxvqpqoqud 1 300 train
+wxvtaveqvb 1 300 test
+wxvufmryax 1 300 train
+wxvxaodmnc 1 300 val
+wxvxwwadtd 1 300 train
+wxwdzuibwp 1 300 train
+wxweicvtou 1 301 train
+wxwerbwbzg 1 299 test
+wxwfbbmzxb 1 300 train
+wxwjgawfhy 1 300 train
+wxwnvnekhz 1 300 val
+wxwppcbrmc 1 241 train
+wxwqwnbjqv 1 136 train
+wxwsihwjse 0 300 train
+wxwwtrnfxa 1 300 train
+wxxhkicxgb 1 300 train
+wxxoldznwe 1 300 train
+wxxpnijdvo 1 300 val
+wxxrufgzzf 1 300 train
+wxxxufwenr 1 300 train
+wxybheqhes 1 301 train
+wxyfhhzdje 1 300 train
+wxygmoyfrx 0 300 train
+wxyjtncrax 0 300 train
+wxykvaamuc 1 255 train
+wxynvujoge 1 300 train
+wxyqgfuydc 1 297 train
+wxzeidnrpx 1 300 val
+wxzekbdrqk 1 300 test
+wxzfhgzeqn 0 300 train
+wxzhbyysjr 1 300 train
+wxzicjjoof 1 300 train
+wxzjmwdufr 0 300 train
+wxzmsudejm 1 300 val
+wxzobongwa 1 300 val
+wyalzwcjgr 1 300 train
+wyapapeifa 1 300 train
+wyarhmssco 1 300 train
+wyarqgbjlg 1 300 train
+wyasimswwe 1 301 train
+wyasjrvehf 1 300 val
+wyaxczmuxr 1 301 train
+wyaxtkuvmf 0 300 train
+wyayehrtgn 0 301 val
+wyaymhujdu 0 300 train
+wybdnikfyx 1 300 train
+wybdqxlowh 1 300 val
+wybhgbzgqi 1 300 train
+wybkxfewcc 1 300 train
+wyboojblcx 1 300 train
+wybqtuzhfq 1 300 train
+wybrmwlccn 1 298 train
+wybzffkwcc 1 299 test
+wyccmpbtzi 1 300 train
+wycddsspdu 1 300 train
+wychizeojz 0 300 train
+wycimrxgss 1 300 train
+wycjcrcnuk 1 300 val
+wyclmxwbpm 1 300 train
+wycspzyaxj 0 300 val
+wyctcclbfy 1 300 val
+wyctddnyko 1 300 test
+wydbwjnxak 1 299 val
+wydemjmvws 1 299 train
+wydfrjeniu 1 300 test
+wydgcgjzds 1 301 train
+wydhxivxhq 1 241 train
+wydkvyqaxj 1 300 test
+wydsxlcdqx 1 300 train
+wydulmqhzj 1 300 test
+wyegxilzwh 1 300 train
+wyenndmypq 0 300 train
+wyenzhsikh 1 300 train
+wyeobdlqoe 1 300 train
+wyeobynmkl 0 300 train
+wyepphmogz 1 300 train
+wyeqtqhfhg 0 300 val
+wyevhwjqqt 0 300 train
+wyevpnzvgi 0 300 train
+wyevylgxhv 1 299 test
+wyezncdvsx 1 300 train
+wyezqofzcq 0 300 train
+wyfbacymfl 1 301 train
+wyfbrbliyj 0 300 val
+wyfciynyxs 1 300 val
+wyfckvawpg 1 300 test
+wyflzszarj 1 300 train
+wyfnjqlyuk 0 300 train
+wyfnnasmbx 1 300 train
+wyfrjupxjc 0 300 val
+wygacaxzkh 1 300 val
+wygcyvwezm 1 300 train
+wyggfojshh 1 300 val
+wygjvivoha 1 300 val
+wygnwqccea 1 300 val
+wygtsppbqt 1 301 train
+wygtzqjpdc 1 300 train
+wyguizytuq 1 300 train
+wyhcxlywxf 0 300 train
+wyhfmaocqr 1 300 train
+wyhikairnl 1 300 train
+wyhkdfvmmu 1 241 train
+wyhnveqgys 0 301 train
+wyhtcmefqt 0 300 train
+wyhtsbuwjw 1 300 train
+wyiajvmitt 0 300 train
+wyidhnitvi 1 300 val
+wyidocwznj 1 300 train
+wyijplzouh 1 300 train
+wyipxgtnyk 1 300 train
+wyisggziyv 1 300 train
+wyiudxrzam 0 300 train
+wyjikkylzx 1 301 train
+wyjjefwjzr 1 300 train
+wyjpqjdpjq 1 298 train
+wykfussmdp 1 300 train
+wykijtbhaj 0 300 train
+wykjfvwnaz 1 300 val
+wykqjiughm 1 300 test
+wyksxkzxan 1 300 train
+wykvjlhrrf 1 300 train
+wykxjzqpti 1 301 train
+wykyadrqyg 1 301 val
+wylamsqccj 1 300 train
+wylcqttiam 1 300 val
+wylfywhbff 1 300 train
+wylhbbcgtd 1 300 train
+wyltffozkq 1 300 train
+wyltlilbbh 1 300 train
+wylwikcbkd 1 300 val
+wymdzznamt 1 300 val
+wymgrmkwuy 0 300 train
+wymlvlyomw 1 300 train
+wymmbwifmh 1 300 train
+wymqpoxaqf 0 300 train
+wymqtvswfl 1 300 val
+wymxeiqssm 1 300 train
+wymzsngpfg 1 300 train
+wyncesxcil 1 300 train
+wynctqwpjm 1 301 train
+wyndqysgnt 1 300 train
+wynfererkd 1 300 val
+wynhbckewc 1 300 train
+wynitszgex 1 300 train
+wynotylpnm 0 300 test
+wynqlyaexl 1 299 val
+wynrqptzed 1 300 train
+wynssmvkpd 1 300 train
+wynyofminq 1 300 train
+wyoauleyxz 1 300 val
+wyodrkxpxe 1 300 train
+wyofsbgrvd 1 300 train
+wyogyhucud 1 298 train
+wyokvgjqld 1 302 train
+wyovsagvmi 1 301 train
+wypdykzzma 1 300 train
+wypfvzyiiy 1 300 val
+wypgcwerxm 1 300 train
+wypjaaoktd 1 300 train
+wypkjyjhmk 1 300 train
+wyplspojlv 0 300 train
+wypncwazmj 1 300 train
+wypnxezteg 1 301 val
+wypvdlbobd 1 300 val
+wypxhuoiwd 1 300 train
+wyqaueyxfu 1 300 train
+wyqdbqmbjk 1 300 test
+wyqestykgb 1 298 val
+wyqhadmmcy 1 301 train
+wyqjhmngma 1 300 test
+wyqnjdttaz 1 300 train
+wyqnxlonyy 1 300 val
+wyqqxogvkt 1 300 train
+wyqseodqaj 0 300 val
+wyqshcnytp 1 300 train
+wyqspxhjrc 0 300 train
+wyqwldnvqc 0 300 train
+wyramrxebi 0 300 train
+wyrknmgres 1 300 train
+wyrmfcvxig 0 300 train
+wyrqxpzztf 0 300 train
+wyrtztnqcs 1 300 val
+wyscfriecz 1 300 train
+wysfnuxrpc 1 300 train
+wyshvkdiqg 1 299 test
+wysuksnxag 1 300 val
+wytaipjjua 1 300 val
+wythfkwvco 1 300 train
+wytpaehszj 1 301 train
+wyttjinowl 1 300 val
+wytvwwvest 1 300 train
+wytygqdnha 1 298 train
+wyubcvqewq 0 300 train
+wyucbpaatu 1 300 train
+wyudvbhffu 1 300 train
+wyuhafyruq 0 300 train
+wyuhbtjwys 1 300 val
+wyujjgnzob 1 300 val
+wyujqlrcoi 1 300 train
+wyuorpudue 1 300 train
+wyuqkpglth 1 301 train
+wyuwbkywwa 1 299 test
+wyuwklxctg 1 300 train
+wyuxqpmiff 1 300 val
+wyuxsdmakd 1 300 train
+wyuyogxcow 1 300 train
+wyventiuyy 1 300 train
+wyvewvtzlp 1 300 train
+wyvkshssbq 1 300 train
+wyvlgsegyn 1 300 train
+wyvpgchwjh 1 300 train
+wyvrpizhjc 1 300 train
+wyvtjhzwuv 1 300 train
+wyvvgikzpv 1 300 train
+wyvwjfvdvg 1 300 val
+wyvxptgiky 1 300 train
+wyvxvchdqa 1 300 train
+wywgcyedhv 1 300 train
+wywgwazovz 1 300 train
+wywhbjazxq 1 300 train
+wywmsnneuv 1 300 train
+wywucxhgvp 1 300 train
+wywuxgrwxi 1 302 train
+wywxjgfwdt 1 300 val
+wyxcwkarxs 1 300 train
+wyxgpiibua 0 302 val
+wyxjhtssjb 0 301 train
+wyxmbmycsd 1 241 train
+wyxxltcvlb 1 300 train
+wyyceiwsmg 1 301 train
+wyycfezsha 1 302 train
+wyydmusnea 1 300 val
+wyyfdwkwpv 1 300 val
+wyyjwgwjnb 1 300 train
+wyywuthzsk 0 300 train
+wyyxqcqtkd 1 300 val
+wyzaxpckul 1 300 train
+wyzbpziytr 1 300 val
+wyzhmkgxgb 0 300 train
+wyzogfkgyi 1 300 train
+wyzqsjyxqu 1 300 train
+wyzycuhqwx 1 300 train
+wzaevmzfqs 1 300 train
+wzaiowwdoe 0 300 train
+wzajmsftde 1 300 train
+wzapcbcyky 1 300 train
+wzaqjwxlkl 0 300 train
+wzarsojkkm 0 300 val
+wzassqqhbd 1 300 train
+wzauqeajlj 0 299 train
+wzawzwmngy 1 300 train
+wzaxafauwn 1 300 train
+wzbbvbqhqq 1 300 train
+wzbchihwuz 1 300 val
+wzbfuefhxm 1 300 val
+wzbgpicmao 1 300 train
+wzbhlvojxv 1 300 train
+wzbhnryjxb 0 300 train
+wzbjskhmtr 1 300 train
+wzblnuhdql 1 301 train
+wzbmpqcdof 1 300 test
+wzbteapfxf 1 300 train
+wzbvajwpal 1 300 train
+wzccjxkbyp 1 300 val
+wzcqlpmtbe 1 300 train
+wzctjlievz 1 300 train
+wzcwudcind 1 300 train
+wzcxdzftki 0 300 train
+wzdbfkexln 1 300 val
+wzdemwbtur 1 300 train
+wzdfhkdcsn 1 300 train
+wzdlhutmdu 1 301 train
+wzdmqsfwzv 1 300 train
+wzdnvgackt 0 300 train
+wzdpdxajtq 0 300 val
+wzdpuiabmu 1 236 train
+wzdsgmvdrs 1 300 train
+wzdtwjdwss 1 298 train
+wzduhzgxfo 0 300 train
+wzdxvddvrw 1 300 train
+wzdybffyzl 1 125 train
+wzdydqgzyc 1 301 train
+wzeckhnwyw 1 240 train
+wzehklnvjt 1 300 train
+wzeplhzhoy 1 300 train
+wzeslnsvuj 1 300 train
+wzetgjsqvn 0 300 val
+wzeuljhwqd 1 300 val
+wzeuysuidu 1 300 train
+wzexnizsdc 0 300 train
+wzfathozxz 1 300 train
+wzfbvxemxn 1 300 test
+wzfenpfrnf 1 240 val
+wzfewzqjmm 1 300 val
+wzfhhzhump 1 300 val
+wzfikllecs 0 300 train
+wzfjrlhohh 1 300 val
+wzfkboqnot 1 300 train
+wzfkdecodn 1 300 val
+wzfpvmalyf 1 300 train
+wzgacusbiv 1 298 train
+wzgbtkbgkg 1 300 train
+wzgdhqrxpi 1 300 train
+wzgfmtkgjx 0 300 train
+wzghlxhfyl 1 300 train
+wzgjpnrxty 1 300 train
+wzgmlzddjt 0 300 val
+wzgmzhyuac 1 300 train
+wzgprxgons 1 300 train
+wzgtvjhpky 1 300 train
+wzhljjufmc 1 240 train
+wzhmelnczt 1 300 train
+wzhrjsmtwr 1 300 train
+wzhyrcskbg 1 300 train
+wzigjughfp 1 300 train
+wzihfsuhni 1 300 train
+wzijiaqujt 1 300 train
+wziqnhppji 1 300 train
+wzitsvxsmm 1 301 val
+wziugfxzzd 1 300 train
+wzixmzzrnu 1 300 val
+wziytovzdg 1 300 train
+wzjhfrnesf 1 301 val
+wzjknaaogp 1 300 val
+wzjpryjdku 0 300 train
+wzjreqcakk 1 300 train
+wzjvtaqskv 1 300 train
+wzkcdylyra 1 300 train
+wzkchhjwax 1 302 train
+wzkespuign 1 300 train
+wzkfhbectq 1 300 train
+wzkhjmezcs 0 301 train
+wzklyczodl 0 301 train
+wzkovvmdkq 1 300 train
+wzkrqglztq 1 241 train
+wzkwfysoyp 1 300 train
+wzldwhdxfm 1 241 train
+wzlfecmmao 1 298 val
+wzlgyinxcp 1 301 train
+wzljchuvzz 1 298 train
+wzlnusxefj 0 300 val
+wzlperlkzu 1 300 train
+wzltgvmcut 1 300 train
+wzlxlmxjsw 0 300 val
+wzmgvgfemg 1 300 train
+wzmhcfajcj 1 300 train
+wzmmetktpl 1 301 train
+wzmpyixajn 1 300 train
+wznmwfwhvq 0 300 train
+wznnbteclq 1 300 train
+wznnfertes 1 300 train
+wznogjrvvr 0 300 train
+wznrdhbfdk 0 300 train
+wznvvnxcmf 1 300 train
+wznwraryji 0 300 train
+wzoanvyeef 1 300 test
+wzogajzmev 0 300 train
+wzohsxyfei 1 300 train
+wzokfwjjit 1 300 train
+wzollctkpt 1 300 val
+wzozahtpjc 1 300 train
+wzpcumzosr 1 300 train
+wzpjfddxfi 1 300 train
+wzpjwbdgjv 1 300 train
+wzqbebycvf 1 241 train
+wzqosvxzwr 1 300 val
+wzqptzrztk 1 297 train
+wzqqobsobj 1 301 val
+wzqtsfszsz 1 241 train
+wzquerizus 1 300 train
+wzqwspyoxi 1 296 train
+wzqxkdkxoa 1 300 val
+wzrhbqrcra 1 300 val
+wzrhdvpktx 1 300 test
+wzrkgntquh 1 300 test
+wzrocvfzql 0 241 train
+wzrtluuunu 1 300 train
+wzrvwaipxw 1 300 train
+wzrwsreyep 1 300 val
+wzrybcopcd 0 300 train
+wzrynqlsdd 1 300 val
+wzrzjdwssl 0 300 train
+wzsfnpjlbu 1 300 train
+wzsfoifswy 1 300 test
+wzsghovwjh 1 300 train
+wzsgtfzriy 1 300 train
+wzsmoditjg 1 300 val
+wzsovqramv 1 300 train
+wzspdhfsvf 1 300 val
+wzspjjmwur 1 300 train
+wzstwebsxd 0 300 train
+wzswiqbwoo 1 300 train
+wztayempfs 1 300 train
+wztdvfqqqm 1 300 train
+wztjdgqklu 1 300 train
+wztrudcmqm 1 300 train
+wztvsceimr 1 300 train
+wztythgahw 1 300 test
+wztzfsldna 1 300 train
+wzuiazkgqt 1 300 val
+wzuqittcvn 0 296 train
+wzuudnkdmj 1 300 train
+wzuwpzwtba 1 300 train
+wzuyckjsts 1 300 val
+wzvbvrxalb 1 300 val
+wzvpwwfpmj 1 301 train
+wzwahocred 1 300 train
+wzwlqcjuoc 1 300 val
+wzwodsfiyo 1 300 val
+wzwpsmhijs 1 300 val
+wzwtetgvwn 1 241 train
+wzwvfaqzqw 1 300 val
+wzwwkzjujv 1 300 train
+wzxefllyyp 1 300 train
+wzxhwvtloi 1 299 val
+wzxlwlkgbx 1 300 train
+wzxqfglgnn 1 300 train
+wzxvvzbabw 1 300 train
+wzxytgdfep 1 300 train
+wzxzqvxtvp 1 300 train
+wzyeipmbqb 1 300 train
+wzykukkvgk 1 300 train
+wzynalqgww 1 300 train
+wzynqdfzku 1 300 train
+wzyzadkbdr 1 300 val
+wzzbooywao 1 300 train
+wzzhfcpvxf 1 300 train
+wzzibnuoxp 0 300 train
+wzzqfqgzwp 1 301 train
+wzzxaxaqbb 1 300 train
+wzzxqkjfnh 1 300 train
+wzzyccdpyf 1 300 val
+wzzymhoaxw 1 300 val
+wzzzcabynx 1 300 train
+xaagarafhs 0 300 val
+xaaiaxqcbg 1 300 train
+xaaihartcm 1 300 train
+xaajbefufw 1 300 train
+xaaopsrhpu 1 299 test
+xaarfgflox 1 300 train
+xaaugazmkf 1 297 train
+xaaxakbkbs 1 300 train
+xabazrwdgm 1 300 val
+xabmdypvaw 1 300 val
+xabmgqurmw 1 300 train
+xabvtpjlgn 1 300 train
+xacnoxrodr 1 300 train
+xacpmkqfec 0 300 train
+xacqlcpegl 1 300 train
+xacsxvlfvm 1 300 train
+xacvqczazm 1 300 train
+xacyofrdcn 1 300 train
+xadbkzpnfq 1 300 train
+xadebmmekj 1 300 train
+xadeqairna 1 300 train
+xadgpwdplh 1 300 val
+xadifkdebv 1 300 train
+xaduspemrg 1 300 val
+xadwuicyaf 1 300 train
+xadxtrdubm 1 300 val
+xaeaxgsdye 0 300 val
+xaedthtkkb 1 300 train
+xaehhjcihv 1 301 train
+xaeiqjajxf 1 300 val
+xaekcmjnsa 1 241 train
+xaeqlbizvx 1 241 train
+xafbspgyen 1 300 val
+xafhoqwbae 1 300 train
+xafibokjvk 1 300 train
+xaflvnrrvw 1 300 train
+xaftlwfrnx 0 300 train
+xafwvanapa 1 300 val
+xafytkibti 1 300 train
+xafywmrvqg 1 297 train
+xagcihtnmv 1 298 train
+xagpwvuyim 1 301 train
+xagsvjctmp 0 300 train
+xagtrahpoe 0 300 train
+xaguawxnih 1 298 train
+xagvkuozuy 1 301 train
+xahjdvwebi 1 240 val
+xahnmodzbb 1 299 train
+xahocyotzk 1 300 val
+xahpdpoykc 1 300 val
+xahqykmkfx 1 301 train
+xahroukdra 1 300 train
+xahzrjxdni 1 300 train
+xaieraxufm 1 300 train
+xaihaudjsg 1 300 val
+xaipfagwxw 1 300 train
+xajcrzlpft 0 300 val
+xajnrxzgqd 1 300 train
+xajqriyqxl 1 300 train
+xajwjjuzzy 1 300 val
+xajzgrabnj 1 300 val
+xakgjcexsg 1 300 val
+xakgymasfr 1 301 train
+xakmfsifjd 1 298 train
+xakvgtrydq 1 300 train
+xalapiimji 1 300 val
+xalcmhlexa 1 300 val
+xalmvegccm 0 300 train
+xalnoajelq 1 300 train
+xalpmzedue 1 301 train
+xalyhvbeyh 1 300 train
+xamqepuitd 1 300 train
+xanjtkadbr 1 300 train
+xanlgfevqn 1 301 train
+xanrtzvssc 1 300 train
+xanwcpnual 1 298 val
+xanyqzjdsw 1 300 val
+xaohmbgdog 1 300 train
+xaouodwsjt 1 300 train
+xaowqyecyd 1 300 train
+xapaukwymw 1 300 train
+xapaxvqkcd 1 300 train
+xapeioqpva 0 300 val
+xapiepxzae 1 300 train
+xapohfhwil 1 300 train
+xapqmlfggn 1 300 train
+xaprxjoaom 1 300 val
+xapzzuqkhg 1 300 train
+xaqjcrdyvy 1 300 train
+xaqjebxshq 1 300 train
+xaqjxnfmwk 1 300 train
+xaqqmnjlmd 1 300 train
+xaqzfgitvj 1 300 val
+xarblfkrlw 1 300 train
+xarczzmhbi 1 300 val
+xarfrtqenk 0 298 val
+xarletcyje 1 300 val
+xarriwpiwq 1 300 val
+xartlyjtjw 1 300 test
+xarzdpcwqt 1 300 val
+xasczpanpx 1 300 train
+xasfkipwvl 0 300 train
+xasidfdyoz 0 300 train
+xasiruuazi 0 300 train
+xastujefzw 1 300 train
+xatcoyelxr 1 300 train
+xatgjaschu 1 300 val
+xatibakipz 0 300 train
+xatkdkmfcn 1 300 train
+xatrtkoqaz 1 300 train
+xatruuhtpv 0 300 val
+xatvzzjfzm 1 300 train
+xatyqjonqv 1 300 train
+xaufrrlmgw 0 300 train
+xaugdeigiy 1 301 train
+xauhzmhqdk 1 300 test
+xaukkvluui 1 300 val
+xaunbtrpag 1 300 train
+xautxvrpjm 1 300 train
+xauutgvrro 1 300 train
+xauwencxab 0 302 train
+xauwinqgbh 0 300 train
+xauxajvqjq 1 300 train
+xauxiqwjbz 1 300 train
+xavbyplmgd 1 300 train
+xavcvmyuah 1 301 train
+xavhhcmjml 1 300 train
+xavujcgixf 1 302 train
+xavvwgwpgq 1 300 train
+xawmscabwf 1 300 train
+xawmvfnnmc 1 300 train
+xawnomckho 1 300 train
+xawoabtjgf 1 300 val
+xawrxpyoau 1 300 test
+xawtcbcxqe 1 300 val
+xawuovujut 1 300 train
+xawxxaftlo 1 300 train
+xaxatfhkzf 1 300 train
+xaxfckboxg 1 300 train
+xaxfqvsoll 1 300 train
+xaxhcaevif 1 300 train
+xaxjngudny 1 301 val
+xaxmbqheea 1 298 val
+xaxptdvide 1 300 val
+xaxrvumfix 1 300 val
+xaxuewagud 1 300 test
+xaxuxyxjta 1 297 train
+xaxvurgsuj 1 300 train
+xaxvwwugft 1 300 train
+xaxzeplffo 0 300 train
+xaydfymrkf 1 300 train
+xaykipcgmm 1 300 train
+xayudgfpmy 1 300 train
+xayumdzjrd 1 241 train
+xayuvzqasy 1 300 train
+xazdhddhca 1 300 val
+xazdhdnwhh 1 300 train
+xazeuzzarq 1 300 train
+xazilpeqlg 1 300 train
+xazngkumbv 1 300 train
+xazpthdbaq 1 300 train
+xbafncjzbl 1 302 train
+xbagebegub 1 300 train
+xbaianpvsf 1 300 val
+xbanyawouv 0 300 train
+xbaodyqqxn 1 300 train
+xbapjhsutr 1 301 train
+xbaquxatgh 1 300 train
+xbauymrejf 1 299 val
+xbbadnnyxr 0 300 train
+xbbdlfmccu 1 300 train
+xbbmlygnof 0 300 train
+xbbtltvihi 1 300 val
+xbcnupxqlc 1 300 val
+xbctgvzitp 1 299 test
+xbcvipelyp 1 300 val
+xbdclrpogh 1 300 train
+xbdifxrhcd 1 300 val
+xbdnqfbxcv 0 301 train
+xbdqbydiwc 1 300 test
+xbdxojpliq 1 288 train
+xbeagkwpft 1 300 train
+xbefwtxoeu 1 300 val
+xbegnfrzwq 1 301 train
+xbehymppwn 1 300 train
+xbeihxyjyf 1 300 train
+xbemxjqsma 1 300 train
+xbentgemej 0 300 train
+xbetnelpui 1 300 train
+xbfibiuyll 1 298 val
+xbfpoccnhz 1 300 train
+xbfpojtibo 1 300 train
+xbftijjbpz 1 300 train
+xbfvykfcmx 1 167 train
+xbfxuvuwyl 1 300 val
+xbgaymkhoo 0 300 train
+xbgeqboloh 1 300 train
+xbgkwwtfwx 1 300 train
+xbgmlwnwou 1 300 train
+xbgueanmht 1 300 train
+xbhjfflwzv 1 300 train
+xbhkldkqzw 1 300 train
+xbhmumcyvr 1 300 val
+xbhpnwimyh 1 300 train
+xbhppttlaz 1 300 val
+xbhqzkqztt 1 300 train
+xbhvvknxcl 0 300 train
+xbhvxugsck 1 300 val
+xbhzxbftrn 1 300 val
+xbiaduwszb 1 300 train
+xbibxusaha 1 298 train
+xbicqkmbtp 1 300 train
+xbiorkerlf 1 300 train
+xbiybzrdzp 1 300 val
+xbiyhyjsji 0 300 val
+xbizcvgvvb 1 301 train
+xbizutklwa 0 301 train
+xbjcuqhwgc 1 300 train
+xbjffkzsuv 0 241 train
+xbjhfkeqcq 1 300 train
+xbjzgheiqa 1 300 train
+xbkaxzcjwy 1 298 val
+xbkdiofqjl 1 300 train
+xbkfgcdccp 1 300 train
+xbkgjfnlss 0 300 train
+xbkitkttqe 1 300 train
+xbkltcjfoq 1 299 test
+xbkrdfuffq 1 300 train
+xbkvmkozpc 1 300 train
+xblbwhhzxd 1 300 train
+xbldjghchx 1 239 train
+xblfaldagl 1 298 train
+xblhipfkpf 1 300 val
+xbllkhogji 1 300 train
+xblodifrkk 1 300 train
+xblsrhezwq 1 301 train
+xblxnsrqfp 1 299 train
+xbmcmbhtnx 1 300 train
+xbmgnchcfy 1 300 train
+xbmlpwvygi 1 300 train
+xbmxoquauv 1 300 train
+xbmyeokzxs 1 300 train
+xbndsesqdq 1 240 train
+xbnexxtwrg 1 300 val
+xbnitlqjop 1 300 train
+xbnoabamxx 1 301 train
+xbnojgfgny 1 600 train
+xbnxqnchxn 0 298 train
+xbnyxavkmw 1 300 val
+xbobzlspve 1 241 train
+xboisnvddr 1 300 train
+xbokoalmlv 1 300 test
+xbolgviewp 0 300 train
+xbotqwxhom 1 300 train
+xbpcdmldvs 1 298 train
+xbpdobiiim 1 300 val
+xbpjrblvin 1 300 train
+xbpknypvay 1 301 train
+xbpkokfeul 1 300 val
+xbprgmgrvm 1 300 train
+xbptxkalqi 1 300 train
+xbpumcamxz 1 298 train
+xbqjfhlrhm 1 300 train
+xbqklretjk 1 300 train
+xbqkmrabwh 1 300 train
+xbqmeyvujc 0 300 train
+xbqqsqvfwb 1 300 train
+xbqqzexnzz 1 300 train
+xbqsuylnmf 1 300 train
+xbqteepfny 1 300 train
+xbrbfxcggm 1 300 train
+xbrenpsttb 1 300 train
+xbrgoqxmju 1 300 train
+xbrhfeddnt 1 300 train
+xbrntmewic 1 300 train
+xbrqzdiuxp 0 300 train
+xbrsmnqrux 1 300 train
+xbrwljqjwi 1 300 train
+xbswruvggb 1 300 train
+xbtclnggmt 1 300 train
+xbtcywlomf 1 300 train
+xbtgvkgyeu 1 298 train
+xbtjskjjdy 1 300 train
+xbtjzjegwi 1 300 train
+xbtmhdgcie 1 300 test
+xbtpvhfgbg 1 300 val
+xbttmgjsop 1 302 train
+xbttoybwsf 1 295 train
+xbtultprza 1 300 train
+xbtuqfmquq 0 299 train
+xbtwairosj 1 300 val
+xbtxdcrsce 1 300 train
+xbtzqnnaoz 1 300 train
+xbubkxrpxd 1 300 train
+xbuloxmtda 1 300 train
+xbulqrefxo 1 300 val
+xbundzujih 1 300 train
+xbunipxnoy 1 300 train
+xburrtmrts 0 300 train
+xbutazzecy 1 300 train
+xbvcpqwbji 1 300 train
+xbvggqqocu 1 298 train
+xbvhubqzlq 1 301 train
+xbvjrriwxn 0 300 val
+xbvlbpgdtb 1 300 train
+xbvqfcxvub 1 300 train
+xbvtfpaflj 1 300 train
+xbwcjyspur 1 300 train
+xbwdfapbek 1 300 train
+xbweygftap 1 300 train
+xbwiblkrqn 1 301 train
+xbwqdrmwln 1 300 train
+xbwrpfwbry 0 300 train
+xbwsanpumn 1 297 train
+xbwtbmwrpj 1 299 val
+xbwxkpzryg 0 303 train
+xbwzvkfxfp 1 241 train
+xbxdzcqeva 1 300 train
+xbxfbipchc 1 300 train
+xbxhsjhjxv 1 300 train
+xbxlucxunr 0 300 train
+xbxphkltwx 0 300 val
+xbxpnlyjvv 1 241 train
+xbxqmpiihn 1 300 train
+xbxyljtjkv 1 300 val
+xbxzkihnys 1 300 train
+xbyacqjsqv 1 301 train
+xbybweqqbk 1 300 train
+xbygcbnanc 1 300 train
+xbygwroqdr 1 300 val
+xbyivztfnr 1 300 train
+xbymqvlhti 1 300 train
+xbynzcnonz 0 300 train
+xbypqcerzq 1 300 train
+xbyqbslupr 1 300 train
+xbyqmnxygz 0 300 train
+xbyrobwpqh 1 300 train
+xbysqpiihz 1 301 train
+xbywpszmzp 1 300 train
+xbyyhjzsbm 1 300 val
+xbyzxslant 1 300 train
+xbzgexvpvi 1 300 val
+xbzlqexrdv 1 300 train
+xbzpmcskkd 1 300 test
+xbzswkjvyx 1 300 train
+xbztzundti 1 300 train
+xbzuxmmysy 1 300 train
+xcabhdpygc 1 300 train
+xcadpmhzvk 1 300 train
+xcafnzsopy 1 300 train
+xcahaboihz 1 300 train
+xcapvnxinx 1 300 train
+xcayzcjsgp 1 300 val
+xcbavqdhii 1 299 train
+xcbckitcgh 1 301 train
+xcbdlzehao 1 300 val
+xcbgqihhqt 1 300 val
+xcbqqjwbdd 1 300 val
+xcbrhibiue 1 300 train
+xccbaancfj 1 300 train
+xccejqijqg 1 300 train
+xccslnqwdk 1 300 train
+xccwmpkkda 1 297 val
+xcczivkikc 0 300 train
+xccznjimgh 1 299 val
+xcdazpgjmk 1 300 val
+xcdcmgmqbl 0 298 train
+xcdcxybjic 1 300 train
+xcddbnalqr 1 298 train
+xcdeedoidc 1 300 train
+xcdgptjrfz 1 299 train
+xcdjrcbhob 0 300 train
+xcdkppxfby 0 300 train
+xcdmskvkvl 0 300 train
+xcduqsrpwb 1 300 val
+xcdxgcnkrn 1 300 train
+xcdxpbkgah 0 300 val
+xceeptuahm 1 300 train
+xceobxispq 1 300 train
+xcfaqasoiz 1 300 train
+xcfdhsivdp 1 300 train
+xcfdidxani 0 300 train
+xcfgqlhrir 1 300 train
+xcgalosmcs 1 300 train
+xcgayyyene 1 300 test
+xcgmdqbgir 1 298 train
+xcgntbiwos 1 300 train
+xcgvhaatgt 1 300 train
+xchejzkjvn 1 300 train
+xchjfklncb 1 300 val
+xchktpdfys 0 300 train
+xchkubfwrn 1 300 train
+xchwjakwfq 1 300 train
+xchzardbfa 0 300 val
+xchzcnddwb 1 300 train
+xcigqqnqyl 1 300 train
+xcigzlpywx 1 299 test
+xcihypsuad 1 300 train
+xcijmaoamt 1 300 train
+xcikdsbzre 1 300 val
+xcikofjdka 1 300 train
+xcikxizrej 1 300 train
+xcindkljlt 1 300 train
+xcjcjedzsa 1 241 val
+xcjmianatk 1 300 train
+xcjsyzigyv 1 300 train
+xckawnbcxs 1 302 train
+xckfdjolom 0 300 train
+xckipphmtx 1 300 test
+xckjexszrr 1 300 train
+xckjlunrod 0 300 train
+xckjxglwmm 1 300 train
+xcklfrhwyh 1 300 train
+xckthttecd 1 300 train
+xckxzzgjop 1 299 val
+xclkyavepa 1 300 train
+xcllnfyznn 1 300 train
+xclqbefnvc 0 300 train
+xclqflwygx 0 300 train
+xclvgiyjyk 1 300 val
+xclvyurqsr 1 300 train
+xclxmddvoz 1 300 train
+xcmekpbpyu 1 300 train
+xcmgliovac 1 300 train
+xcmhowsrrc 1 300 train
+xcmkbpzfzw 1 300 train
+xcmrhxjhfr 1 300 test
+xcmrmucmvt 0 300 train
+xcmtevwwga 1 300 train
+xcmuirlwwe 1 300 val
+xcngenqgvs 1 300 val
+xcngulpltq 0 300 train
+xcnhlloinj 1 300 train
+xcnmkzoxbt 1 300 train
+xcnrztcgpq 1 302 train
+xcnxdhjznx 1 300 val
+xcnzqrekdo 1 300 train
+xcocizhmoe 1 299 val
+xcodksogvg 1 300 train
+xcoqrifofq 1 300 val
+xcowblozsy 1 241 train
+xcpbhjefgt 0 300 train
+xcpfwqvwil 1 300 train
+xcpgmgjjvg 1 300 val
+xcphjhsbja 1 300 val
+xcpngwulrb 1 300 train
+xcpwcbsapw 1 300 train
+xcpxmrrrtx 1 300 train
+xcqcjvdrse 0 300 train
+xcqlnsqcrr 1 300 train
+xcqnflcmor 1 301 train
+xcqoktxrmf 1 300 train
+xcquyhcvjx 1 300 train
+xcqwaetyql 1 300 train
+xcraameygq 1 300 train
+xcrbcszeqb 1 300 train
+xcrbdnaadp 1 300 train
+xcrbnrkuwc 1 300 train
+xcremjxscc 1 297 val
+xcrfebhpzf 1 300 train
+xcrjchjjzn 1 300 val
+xcrpoppwhm 1 300 val
+xcrrllynbo 1 300 train
+xcruhaccxc 0 300 test
+xcrxxutuxo 1 300 train
+xcrybujqsp 1 300 train
+xcrzescmko 1 300 train
+xcsakwixuq 1 300 train
+xcsblcaakv 1 300 train
+xcsceubwml 1 300 val
+xcscqlhifh 1 300 val
+xcshohrbgi 1 300 train
+xcsnvfgwpg 1 302 train
+xcspmsqidw 1 300 train
+xctdevlnff 0 300 train
+xctggwkoit 1 300 val
+xctpdujlok 1 300 train
+xctqqllezp 1 300 train
+xcttnmvgwn 1 300 train
+xctujnmdei 1 300 val
+xctveobpyi 1 300 train
+xcuaojonlf 1 300 train
+xcuclbqrsu 1 298 train
+xcucvaoznq 1 300 train
+xcunmkyxrv 1 300 train
+xcupkvkyfi 1 301 train
+xcutpnpfhy 1 300 train
+xcuvmjssbo 1 300 train
+xcvglbxlbw 0 300 train
+xcvguozfac 1 300 train
+xcviojioko 0 300 train
+xcvmwbzgfo 0 300 train
+xcvmyhgfxw 1 300 train
+xcvoifsqua 1 300 train
+xcvozkqknd 1 300 train
+xcvuccuvuz 1 300 train
+xcvxjqcavz 1 300 train
+xcvzvkasyq 1 300 val
+xcwbuzdwsi 1 301 train
+xcwbxsdkda 1 301 val
+xcwdxiblec 0 300 train
+xcwlsndayg 1 300 train
+xcwxipuyes 1 300 train
+xcxaaagdzr 1 300 train
+xcxiuqhbqc 1 298 train
+xcxjbmkvby 1 300 train
+xcxluqcnyf 1 300 train
+xcxpsoawga 1 300 train
+xcxyhwwelx 1 300 train
+xcybpvrpaq 1 300 train
+xcydehthbl 1 297 val
+xcyhufudcz 1 297 train
+xcyknzowor 1 300 train
+xcynwjlevf 1 300 train
+xcyumxqgvf 1 300 train
+xcyuozheti 1 298 train
+xcyxzyajpn 1 300 train
+xcyytpfhau 1 300 val
+xczagnysbr 0 300 val
+xcznhjzxig 1 300 train
+xczoxdxaoe 1 300 train
+xczxyogxbb 1 300 train
+xdanwezlbq 1 300 train
+xdaotadsjf 1 300 val
+xdapclpbip 1 300 test
+xdapuyalkj 1 241 train
+xdapydbemw 1 300 train
+xdatcpktxs 1 300 train
+xdatolfrod 1 300 train
+xdavamlzfn 1 300 val
+xdayyopwrk 1 300 val
+xdbenbdbna 1 300 train
+xdbhbekmyy 0 300 train
+xdbnawbnvf 1 300 train
+xdbolbpbpt 0 300 train
+xdbqqxsrnz 1 301 train
+xdbqzgtptb 0 298 train
+xdbtmuxuii 0 300 train
+xdbyrfrodq 1 300 train
+xdbzldxpuf 1 300 train
+xdchsmxebo 1 300 train
+xdctsgjpsp 1 300 train
+xddemfriio 1 301 train
+xddeobvthp 1 300 train
+xddfdhuirk 1 300 train
+xddnchypdi 1 300 val
+xddnhgeuch 1 300 train
+xddnphkgor 1 300 train
+xddqeutcsf 1 300 train
+xddthrpsiu 1 300 val
+xdduvcvwuv 1 300 val
+xdeamsejyc 1 300 val
+xdewpcxlmx 1 300 train
+xdezcezszc 0 300 test
+xdfancaenq 0 300 train
+xdfflhjcef 1 300 train
+xdfkrozmrg 1 300 train
+xdfonwbyih 0 301 train
+xdfsnztavk 1 300 train
+xdfydnjecy 1 300 train
+xdgdhejxes 1 300 train
+xdghamgpyt 1 300 val
+xdglcsbrij 1 299 train
+xdglzmcgel 1 298 train
+xdgrmiiieq 1 300 train
+xdguvnpmlf 1 300 train
+xdgxbajocr 1 300 train
+xdhadvlenj 1 301 val
+xdhbnnywct 1 300 train
+xdhmmxcycj 1 300 val
+xdhpkwnpon 1 300 train
+xdhtlgvoqf 1 300 val
+xdhwwujuci 1 300 test
+xdibdmwpkh 1 298 train
+xdicqooujc 1 300 train
+xdiovojisq 1 300 train
+xdiwtdskoa 1 302 train
+xdixdkzvaa 0 240 val
+xdiydkorqv 1 300 train
+xdiyqmeeez 1 241 train
+xdjbvepdic 1 300 train
+xdjkzuefju 1 301 train
+xdjliqsvpd 1 300 val
+xdjoajcvgw 1 300 val
+xdjrruqjre 0 300 train
+xdjsrvpzmz 1 300 val
+xdjvaijptu 1 300 train
+xdjxasjfrp 1 299 train
+xdjxhxaerg 1 300 train
+xdkigezvyt 1 300 train
+xdkrcntpso 0 300 train
+xdlcrmwefl 1 300 val
+xdldryztjq 1 300 train
+xdlmfvngvp 1 300 train
+xdlolctane 0 300 train
+xdlqbsyypt 1 300 train
+xdlrerpndc 1 300 train
+xdlthttsxu 1 300 train
+xdlvoxxplo 1 300 train
+xdmhgnkpkq 1 299 train
+xdmhxgyyqg 1 301 val
+xdmppwexrj 1 300 train
+xdmqadtghu 1 299 val
+xdmvimchwx 0 298 train
+xdmyqjlted 1 300 train
+xdmzeltcse 1 300 train
+xdnlhrkcqb 1 300 train
+xdnmquqeae 1 300 train
+xdnozzkthn 1 300 train
+xdnsgubktn 1 300 train
+xdnswlmuel 1 301 val
+xdnuglvkho 1 300 train
+xdnysbdtlf 1 300 train
+xdnzzzlkrv 1 300 train
+xdoaxlerbq 1 299 val
+xdodtqirhx 0 300 val
+xdopouptfu 1 300 train
+xdosyzxpyw 1 147 train
+xdovpcpxxo 1 300 train
+xdoxstynyc 1 297 train
+xdoyeygezt 1 300 train
+xdpbzbmoan 1 300 train
+xdprpigljl 1 300 train
+xdpwlsbqjd 1 300 train
+xdpxdgqfma 1 300 train
+xdpxdjlxff 1 300 train
+xdqbaelmcr 0 300 val
+xdqcctacmz 1 300 train
+xdqdrtzasj 1 296 val
+xdqgjcmsxe 1 300 train
+xdqlzasiut 1 301 train
+xdqrsjzsul 1 300 test
+xdqrswutyx 0 300 train
+xdqxbvaojq 1 302 train
+xdqznbmwip 1 241 train
+xdrbdgskha 1 300 train
+xdrhlykrth 1 300 train
+xdrjyrptst 1 300 val
+xdrkhkkczt 1 300 val
+xdrlnzupcu 1 300 train
+xdrmtdvyig 0 300 train
+xdrofbzkag 1 300 train
+xdrrpikucq 1 300 train
+xdrruuhwed 1 301 val
+xdruftddbm 1 300 train
+xdrupokegs 0 300 train
+xdrztmfqqg 1 300 train
+xdsantjnmg 1 300 train
+xdsdelhobq 0 300 train
+xdsqaadinm 1 300 train
+xdsqumvcuu 1 300 train
+xdssolqmxa 1 300 test
+xdszhnbujn 1 300 train
+xdtapzzgnj 1 300 val
+xdtdazjmtu 1 300 train
+xdthwnwnhs 1 300 train
+xdtsandqce 1 300 train
+xdttypxpru 1 240 val
+xdtuvxwenq 1 300 train
+xdtyihrmet 1 301 train
+xdufzdujbc 1 301 val
+xdumkwwwpk 1 300 train
+xdurgwgifz 1 300 train
+xduyjrncqg 1 300 train
+xdvaksalzr 1 300 train
+xdvblsjuuv 1 300 train
+xdvdkkxkki 1 300 train
+xdvdsjsllo 1 300 train
+xdvgifjtdp 1 300 val
+xdvmfracaz 1 300 train
+xdvqcwtppr 1 300 train
+xdvuhravko 1 300 val
+xdvzdtzjql 1 300 train
+xdwndowyis 1 300 train
+xdwtjacggh 1 300 val
+xdwvlfrywz 1 300 val
+xdxfmvnghz 0 300 val
+xdxhajjcno 1 300 train
+xdxjgujacy 1 300 train
+xdxkbcyfgi 1 300 val
+xdxkpflfri 1 300 train
+xdxliibdhi 1 297 train
+xdxlqljnut 1 301 val
+xdxmcxbyjz 1 300 test
+xdxoqjntjp 0 300 train
+xdxpdhcqdf 0 136 train
+xdxrilkqam 1 298 train
+xdyazwnapn 1 300 val
+xdyddccmse 0 300 val
+xdydyjggsb 1 300 val
+xdyfofmzzv 1 300 train
+xdygwgezub 0 300 val
+xdyiwjodvy 1 299 train
+xdymokazer 0 300 train
+xdyuhnnzte 1 300 train
+xdyuvgvhvv 1 300 train
+xdyuwpzbyz 0 300 train
+xdyuzumecf 0 300 train
+xdyuzzhupx 1 300 train
+xdyxgbejrq 1 298 train
+xdzblegont 1 300 train
+xdzgzzeflh 1 300 train
+xdznjyebff 0 300 train
+xdzwyilgrt 1 300 val
+xeagsjhxkb 0 300 val
+xeaqpgxxva 1 136 train
+xeaulvyczm 1 241 train
+xeaunyoiyb 1 300 train
+xeawrxpvco 1 300 val
+xeayalpvfp 1 300 train
+xeazmwjayg 1 300 train
+xebhvbcoxc 0 300 train
+xebmnrdrmn 1 300 train
+xebotqrsyd 0 300 val
+xebpxorees 1 300 val
+xebrhymorz 1 298 val
+xebszilvtp 1 300 val
+xebxdghzpb 1 300 train
+xebzkappwp 1 300 val
+xecauofrsw 0 300 train
+xecavumlcb 1 300 val
+xecgqkezbe 1 301 train
+xecljpkalk 1 300 train
+xeclsssrqw 1 241 train
+xecpeqdrfu 1 300 train
+xedgmqcadw 1 300 train
+xedhivxehk 0 300 train
+xeduzfyyua 1 300 train
+xeeaortnna 1 300 train
+xeecgsvqyd 1 299 train
+xeecmvpbir 1 269 train
+xeeetjduql 1 300 train
+xeeftpnxzd 1 300 train
+xeemhzcqdk 1 300 train
+xeeqosyrbl 1 300 train
+xeeveuktlc 1 300 train
+xeezdmaazr 1 298 train
+xeffcvhich 1 300 train
+xefjpozsjr 1 300 train
+xefkfzevnl 1 300 train
+xefmlzrhsj 1 300 train
+xefqgfnrim 1 300 train
+xefrllrkmo 1 300 val
+xefswlhnbj 0 300 train
+xefuyapovj 1 300 train
+xegakwuxob 1 301 train
+xegdbcoscn 1 300 val
+xegipwhpaz 1 300 train
+xegiykwnbr 1 301 train
+xegkjraksh 1 300 val
+xeglmqqwzc 1 300 val
+xeglvieaar 1 300 val
+xegwwtutim 1 300 train
+xehgproyja 1 241 train
+xehhdmbsvg 1 300 train
+xehhlhraas 1 300 train
+xehhtcrdes 1 300 val
+xehioaiduy 1 300 train
+xehnpstjoa 1 600 train
+xehptbmril 1 300 val
+xehxbtwwjg 1 300 val
+xehyizudcd 1 301 train
+xehzvymayu 1 300 val
+xeicvsvxnl 1 300 train
+xeidbgquug 1 296 val
+xeigatcnfa 0 300 train
+xeikkekrng 0 300 train
+xeiliievla 1 300 val
+xeiopfasdx 1 301 train
+xeioxpwiag 1 300 val
+xeiuqliokj 1 300 train
+xeiywpkzlq 0 300 val
+xeizmorozk 1 300 train
+xeizsdveat 1 300 train
+xejfttxqkz 1 301 train
+xejqfnhojp 0 300 train
+xejvpxiram 1 300 train
+xekbhzggjr 1 300 test
+xekqqlpvyi 1 300 train
+xekwdpwhjr 1 301 train
+xekxbmlsug 1 300 train
+xekyvykhqr 0 300 train
+xelbexhxyr 1 300 test
+xelfbaoikw 0 300 train
+xellarnppg 1 300 val
+xelqhqstlq 1 300 train
+xeluxionnd 0 300 train
+xemebqzfsf 1 300 train
+xemhvuvgrn 0 300 train
+xemweeztgy 1 300 train
+xemwywfcmq 1 300 train
+xengqxwhpx 1 300 train
+xenimbkkgk 1 300 train
+xenoqncbcr 1 300 train
+xenrrjivnr 1 299 test
+xensfgmdvq 0 300 train
+xenxqtgxhj 1 255 train
+xenyxslmwr 1 300 train
+xenzrgygen 1 300 train
+xeobqbqdnz 1 241 train
+xeoctgevmy 1 297 val
+xeoeweglgk 1 300 train
+xeofwjlyzr 0 300 val
+xeojjlwthn 1 300 train
+xeojkompvk 1 300 train
+xeojzlrney 0 300 train
+xeomhisdsp 1 300 train
+xeooivicvt 1 300 train
+xeoporttgy 0 300 train
+xepedatinz 1 300 train
+xepiuhjxtt 1 240 train
+xeprfjhqna 1 300 train
+xepuljreln 1 300 train
+xepzgkdect 1 300 train
+xeqjwwyolt 1 300 train
+xeqlwjkdmg 1 300 val
+xeqomrbvgl 0 300 train
+xerazsvzuy 1 300 train
+xergqhjcaj 0 300 train
+xerpfyksal 1 147 train
+xerrohminy 1 301 val
+xerxxjxnrl 1 301 train
+xesaatyxhq 1 300 val
+xesjusykgn 1 300 train
+xessvsyaot 1 300 val
+xeszevnech 1 301 train
+xeszqdbvwi 0 83 train
+xetjsqbkxa 1 300 train
+xetlvqfhuf 1 300 train
+xetmvtombb 1 300 train
+xetxwmauwl 1 300 train
+xeuapajhih 1 300 train
+xeublweqrm 1 300 train
+xeubnwdagy 1 300 train
+xeubzwbpyr 1 300 train
+xeuhrskjdz 0 300 train
+xeuneldomh 1 300 train
+xeuorusmcj 0 300 train
+xeupguvrhv 1 241 train
+xeurswbsql 1 300 val
+xeurwrtray 1 300 train
+xeuvksvdke 1 300 train
+xeuxhxtccm 1 300 val
+xeuzubpylq 1 300 train
+xevaysjyse 1 300 val
+xevfamnwbo 1 300 val
+xevhvruzsq 0 300 train
+xevohgazsq 1 300 test
+xevsziwazf 1 300 train
+xewmqacdmm 1 300 train
+xewnqsxbju 1 300 train
+xewsaoddzg 1 300 val
+xewtnmgpuh 1 298 train
+xewuuxsodg 1 300 train
+xewwsdhdro 1 300 test
+xewyfkdvvz 1 255 train
+xewzfcrhyi 1 297 val
+xexhoyqxvg 1 301 train
+xexmngtcha 1 300 test
+xexngzszer 1 300 train
+xexqjemxyq 0 300 val
+xexsencjjk 0 300 train
+xeyceemrzs 0 300 train
+xeygjgpaaa 0 300 train
+xeylgaufog 1 300 train
+xeywuypopi 1 300 train
+xeyzelhshg 1 300 train
+xeyzkwymwu 0 300 train
+xezayzlkqi 0 300 train
+xezjoofwnh 1 298 train
+xezkldtvhk 0 300 train
+xezkoktsdg 1 300 train
+xezkyzjzmd 1 241 train
+xezmgzmauf 1 300 val
+xfabmcoyvf 1 300 train
+xfabyagydb 1 269 train
+xfagsnqhby 1 300 val
+xfaoigampc 1 297 train
+xfaojctbok 1 300 val
+xfapkgqvpq 1 300 train
+xfapqkjqjx 0 301 train
+xfbedcmkav 1 300 train
+xfbjbaeasf 1 300 val
+xfblwfgdfp 1 300 train
+xfbpatvuww 1 300 train
+xfbtpfflvd 1 300 val
+xfbwszevjn 1 300 train
+xfchpjbfby 1 193 train
+xfchtkchlu 0 300 val
+xfcsosewti 1 300 train
+xfcvywhuut 1 300 train
+xfdaiupotu 1 300 train
+xfdjdsvdoq 0 300 train
+xfdjpzmfjo 1 301 train
+xfdmqoqaqa 1 300 test
+xfdqklwidy 1 300 test
+xfdrbejofz 1 300 train
+xfdxfggwgz 1 301 val
+xfdxjlywwy 1 237 train
+xfdywwiqdh 1 300 train
+xfefteheod 1 300 val
+xfemcankau 1 300 train
+xfemsgumbe 0 300 train
+xfenokyrkn 1 300 val
+xfethgiiof 0 300 val
+xfevpccbrl 1 300 test
+xffcwmucvx 0 300 val
+xffekigayj 1 300 train
+xffgvwldwc 1 298 train
+xffjagiwxy 1 301 train
+xffjesgeey 1 300 train
+xffnioucxh 1 300 train
+xffoyhtbye 1 300 val
+xffpqhboqa 0 300 train
+xffqakkyjz 1 301 val
+xffwgztgwo 1 300 train
+xfgdnsbnto 1 300 test
+xfggnpofye 1 298 train
+xfgmnpvmcb 1 300 train
+xfgsspfpjq 1 300 train
+xfgvcfhref 1 300 train
+xfgyuytgze 1 300 train
+xfhegxbnpo 1 300 test
+xfhqlzlntk 0 300 train
+xfhqnrcefd 1 300 train
+xfhsuykavn 1 297 train
+xfhuczqtld 1 300 train
+xfibazxdlm 1 300 train
+xfihhsgkqx 0 300 train
+xfiiintrvg 1 300 train
+xfimbeeqma 1 300 train
+xfistiolek 1 300 train
+xfitpyudht 1 300 train
+xfjjlcoadu 1 297 val
+xfjrcseeno 1 298 train
+xfjxruxuzp 0 300 train
+xfkcxonwhl 1 300 val
+xfkcyymdah 1 300 val
+xfkejxhnnz 1 300 train
+xfkfpxkzbt 1 300 train
+xfkjsxiqji 1 300 train
+xfkoqbtqwk 1 297 train
+xfkqixxutp 1 300 val
+xfktljgmkm 1 301 train
+xfkxvowiwd 1 241 train
+xfkydbbosi 0 300 val
+xfkyloxlef 0 300 val
+xfkyyrrlpx 1 300 train
+xflbgxryef 1 300 val
+xflgnpinue 0 300 train
+xflhxvykmq 1 300 train
+xflieuscem 1 300 train
+xflptzlkqc 1 300 train
+xflrtqxddp 1 300 train
+xflthpbkeq 1 302 val
+xflvxobqkw 1 298 train
+xflwncxyis 1 301 train
+xfmbwdszed 1 300 train
+xfmcdyaipa 1 300 test
+xfmhyxfkgf 1 300 train
+xfmifnussv 1 300 train
+xfmkawnodd 1 300 val
+xfmkgmehlh 1 300 train
+xfmssdwize 0 300 train
+xfnayypnuj 1 300 train
+xfncslssic 1 300 train
+xfndoxyoem 1 300 train
+xfnefoodtb 1 300 train
+xfngttrczf 1 300 train
+xfnhthioeb 1 300 train
+xfnniyiiwd 1 300 train
+xfnwgkcgpr 1 300 train
+xfnxwbfpod 1 300 train
+xfoaofsmzi 1 300 test
+xfoiquxxlx 1 301 train
+xfoqplfspj 1 300 train
+xfornwuyxa 1 300 train
+xfovfwpumk 1 300 train
+xfpcywugzj 0 300 val
+xfpdtqitsc 1 300 train
+xfpkwcbacv 1 301 val
+xfpnbsefky 1 300 val
+xfpojvdygk 1 300 train
+xfpqztjygo 1 300 train
+xfprrrcioh 1 300 val
+xfpvsrrebl 0 300 train
+xfpyeygjnn 1 300 train
+xfpznkgirw 1 299 test
+xfqzriqfjk 1 300 train
+xfrbluzaag 1 300 train
+xfrewaissn 0 300 train
+xfrfdspnox 0 301 train
+xfrjvfbicd 1 300 train
+xfrkflyqta 1 301 val
+xfrnorjjul 0 300 train
+xfrqthtmmv 1 300 train
+xfrretcsml 1 300 val
+xfrswzqrmn 0 300 val
+xfrteolbdy 1 300 train
+xfrtysswmy 1 301 val
+xfrzsfdiqo 1 240 val
+xfsigfozqe 1 300 train
+xfsilplmao 1 301 train
+xfsnptwqof 1 300 train
+xfsqkrfdir 0 300 train
+xfssjmahyp 1 300 train
+xfsujijfjt 1 241 train
+xfsvfaocfd 1 301 train
+xfsvhrqrup 1 300 val
+xftimuieqk 0 300 train
+xftvwiocrs 1 300 val
+xftwottrbp 1 300 train
+xfufaedien 1 300 train
+xfuggktaqu 1 300 train
+xfuhudhfel 1 300 train
+xfujnmbkcx 1 300 train
+xfuorzscac 0 300 train
+xfusijsgsl 0 300 train
+xfuvtugwrp 1 300 train
+xfuwgzipgt 1 300 train
+xfuxnmctzx 1 300 train
+xfvayogrtd 1 300 train
+xfvdfkwuay 0 300 val
+xfvecntdgh 1 300 train
+xfvenobqat 1 300 val
+xfvginjkmg 1 237 train
+xfvjcbvapk 1 300 val
+xfvjcpmgqw 1 300 val
+xfvjsztftm 0 300 val
+xfvllwtnws 1 300 train
+xfvodbanvx 0 300 train
+xfvvkbvkvg 1 300 train
+xfvvpatbef 1 300 val
+xfvyrjlfij 1 300 train
+xfwbqizsya 0 300 train
+xfwedambmd 1 300 val
+xfwijtshxy 1 300 val
+xfwmdwfive 0 300 train
+xfwyinujqg 1 300 train
+xfwzyuetud 1 300 val
+xfxavmekqj 1 300 train
+xfxfulmigh 1 300 train
+xfxjghfgql 0 300 train
+xfxsfmwrtw 0 300 train
+xfxtwzlgzj 1 300 val
+xfxveglmyx 0 300 train
+xfydljveze 1 300 val
+xfygcakrlc 1 300 val
+xfyhleqdwz 1 300 train
+xfyoksjdbf 0 300 train
+xfyqmvimwx 1 241 train
+xfzctfcitq 1 300 train
+xfzdqqpfzv 1 300 val
+xfziktbhmx 1 300 val
+xfzteoanrd 1 300 train
+xfzwhpaxdl 1 300 train
+xgahugyjju 1 300 train
+xgajieufoz 1 300 train
+xgaoiixqfp 1 298 train
+xgaoirxplo 1 300 train
+xgaotwngok 1 300 val
+xgawqpwdfr 1 298 train
+xgaxojsidv 1 300 train
+xgbdyxgavt 1 300 train
+xgbgxozjej 0 300 train
+xgbhkjqfgj 1 301 train
+xgbqgactfx 1 300 train
+xgbqwgvfxh 1 300 train
+xgbrtjtiuy 1 300 train
+xgbsfvvbpj 0 270 train
+xgbwxcddmy 1 300 train
+xgbxdiqays 0 301 train
+xgbzbgxdmq 0 300 train
+xgcabxqkwt 1 300 train
+xgcezdewrk 1 300 train
+xgchfopsni 1 300 train
+xgclkvwydg 0 300 train
+xgcngusuxq 0 300 val
+xgcnpdyack 1 300 train
+xgcotkynac 1 300 val
+xgcumxdjyg 1 300 test
+xgdbgulajq 1 300 train
+xgdpjkxhgu 1 300 train
+xgdsfwvaky 0 300 val
+xgduxhlwzo 0 300 train
+xgebxjostl 1 269 train
+xgegokbpca 1 300 train
+xgekquqhgh 0 300 train
+xgelqxcxdy 1 299 test
+xgepkiukla 1 300 train
+xgergxojqh 1 300 train
+xgfcuinnll 1 300 val
+xgfgwmtuyx 1 300 train
+xgfthczgot 1 237 train
+xgfudmbojn 0 300 train
+xgfwgrhrsl 1 300 val
+xggcinunip 1 300 train
+xggcounrqf 1 300 train
+xgggldxlpa 0 300 val
+xggnohwiwt 1 300 train
+xggpeykikx 1 300 test
+xggqgfgtix 1 300 val
+xggsjgogat 1 301 val
+xggxilbftx 1 298 train
+xggxiunuhp 0 300 train
+xghbdwbolr 1 300 train
+xghenjuceo 1 300 train
+xghficswdv 1 300 train
+xghgwnqfqz 0 300 train
+xghnxuxvgn 1 300 train
+xghpoxtbwu 1 300 train
+xghtjxcrde 1 269 train
+xghtwvcmtg 1 300 train
+xgiaoncoeh 1 300 train
+xgibfzgbun 1 300 test
+xgibozgdmm 1 300 train
+xginibwvlc 1 300 train
+xgipvnuvat 1 300 train
+xgixgceryh 1 300 train
+xgixnxmwwd 1 301 train
+xgjebeefmi 1 298 train
+xgjfcfgnwl 1 300 train
+xgjglgqpod 1 300 train
+xgjglpmggs 1 300 train
+xgjjazzkjr 0 300 val
+xgjjifxiav 1 297 val
+xgjjxydqbe 1 300 train
+xgjkjlsasi 1 300 train
+xgjkxemsmk 1 301 train
+xgjohteemg 1 300 train
+xgjudwhebz 1 241 train
+xgjyoopaaz 1 300 train
+xgkkhbebap 1 300 train
+xgkoyuitgi 1 300 train
+xgksbuuiql 1 300 train
+xgktqwvknw 0 300 train
+xglcvwzicu 1 300 train
+xgldsicloo 1 269 train
+xglkrbenai 1 300 val
+xglposcmhp 1 300 train
+xglspuzths 1 300 train
+xgmiupkrvx 1 301 train
+xgmknkbour 1 300 val
+xgmlqoscet 1 300 train
+xgmurhbrbx 0 300 val
+xgmzxkwmtd 1 300 train
+xgnljlchbx 1 300 train
+xgnqplyvhb 1 300 train
+xgnymodqpb 1 300 train
+xgnzqmzxml 1 300 train
+xgohnozhqe 1 300 test
+xgouxdewum 1 300 train
+xgowhhcpjh 0 300 train
+xgoxdpldxn 1 300 train
+xgpaqzxjed 1 300 train
+xgpctqnhyv 1 300 train
+xgpghvkjiv 0 300 train
+xgpicdcbrc 0 300 train
+xgpqvqoxgd 1 300 train
+xgprdemfir 1 300 val
+xgqddmsmnb 1 296 train
+xgqerzezcm 0 301 train
+xgqfinxjgw 1 300 val
+xgqioqcgxa 1 300 val
+xgqqsfmosk 1 300 train
+xgrbkgbbpk 1 300 train
+xgrdfjrhyq 1 300 val
+xgrixqwsjy 1 300 train
+xgrpifonmm 1 300 val
+xgrvwexxib 1 300 train
+xgryaftwhr 1 300 val
+xgryydkazq 1 300 train
+xgsatjfhrf 1 299 train
+xgsbgfioyk 1 300 train
+xgsbzzvpmu 0 300 train
+xgscdzbugy 0 300 train
+xgshqgvawy 1 300 train
+xgsuimgeqz 1 300 train
+xgtagqnaec 1 300 train
+xgtahlfjin 1 300 val
+xgtpequfam 1 300 train
+xgtqkqitmt 1 300 train
+xguaxicdxi 1 301 train
+xgudftdybj 1 300 train
+xgueirzcqy 1 301 train
+xgufzfqvcr 1 300 val
+xguhxkdtow 1 300 train
+xgunntlaqm 1 300 train
+xgurqibwmy 1 300 train
+xguuadleva 1 300 test
+xgvbuhafks 0 300 train
+xgvdewwghd 1 300 train
+xgvkdufrto 1 300 val
+xgvkfekpxv 1 241 train
+xgvpdukndc 1 300 train
+xgvxoziojj 1 241 train
+xgvxxusfnv 1 300 train
+xgwelqejmi 0 300 train
+xgwgfhpxyc 1 300 train
+xgwxjmsxiv 1 301 train
+xgxacqpvod 1 301 val
+xgxjqxxjsf 1 300 train
+xgxjtmzsfe 1 300 train
+xgxnfrzeql 1 300 train
+xgxqfpvqqb 1 301 train
+xgxvkedjhr 1 301 train
+xgxxomnrun 0 300 val
+xgycdkbkws 1 300 train
+xgyeextktw 1 300 train
+xgygzngqvi 1 167 train
+xgyirqehkl 1 298 train
+xgykwwczjw 1 300 test
+xgyqgwtrxi 1 300 train
+xgysbrbsjv 1 299 test
+xgzaoasouj 0 300 train
+xgzbktepse 1 300 train
+xgzgnpxhng 1 300 test
+xgzkdvlyex 1 300 train
+xgztmjhtkg 1 298 train
+xgzueumhot 1 300 test
+xgzvhkwzyh 1 300 train
+xgzzqallhj 0 300 train
+xhacwodscf 1 300 val
+xhahqjrexr 1 300 train
+xhamlzayhv 1 300 val
+xhaqzuorrc 1 300 train
+xhaxplpegb 1 300 test
+xhazjfuqyp 0 300 train
+xhbioadozv 1 300 train
+xhblgefrgw 1 300 train
+xhbszvhyhq 1 300 train
+xhbtxqknvi 1 299 train
+xhccwnbakv 1 300 val
+xhcelfjvvl 0 300 train
+xhclspisbv 1 300 train
+xhcmxbypyc 0 300 train
+xhcoywjdba 1 300 train
+xhctlznhta 1 300 train
+xhcwboalah 1 300 train
+xhcwnmdjkd 1 301 train
+xhcwnnvweo 1 300 train
+xhcxlgyjdj 1 300 test
+xhcxpelshy 1 300 val
+xhdbbnhzbq 1 300 test
+xhdjyqpdgk 1 300 val
+xhdoyhdikh 1 299 train
+xhdudafyne 1 301 train
+xhdyakctou 1 249 train
+xhdyshdiit 1 300 train
+xhedzhzvtu 1 300 train
+xheebdhuhn 1 298 val
+xhegjwkfaa 1 299 test
+xhfbnrcfao 1 300 train
+xhfbvmlygm 1 300 train
+xhfqsughap 1 300 train
+xhfuoubivf 0 300 train
+xhfwcbnhet 1 300 train
+xhfwtxgvbn 1 241 train
+xhfwxgiqxf 1 241 train
+xhggldftgt 1 300 train
+xhggmmliqb 1 300 val
+xhgkdeprfl 1 301 train
+xhgsjkwadd 0 300 train
+xhgwrcxtuf 1 299 train
+xhhiycnnmp 1 300 train
+xhhjxdyqei 1 300 train
+xhhkfqmuzx 0 300 train
+xhhptoanjf 1 300 val
+xhhqryotsu 1 300 train
+xhhvlufrjd 1 300 train
+xhicxpfwal 1 300 val
+xhipciugot 1 300 train
+xhiqdiyzph 1 300 train
+xhizcimlzp 1 300 train
+xhjihkhtsr 1 300 val
+xhjkefdzbr 1 300 val
+xhjkofmulp 1 301 train
+xhjltahzgs 1 300 train
+xhjnnipcdc 1 300 val
+xhjwglveyp 1 240 val
+xhjxtzeazx 1 300 train
+xhjzkecikh 1 300 val
+xhkeheuflp 1 299 train
+xhkkwlltzi 1 300 val
+xhklrotzrh 1 300 train
+xhkmamdxke 1 300 train
+xhkmhdrwxz 1 297 train
+xhknawsegg 1 300 train
+xhksdgxtqk 1 300 train
+xhkxdixqiq 1 300 train
+xhlccizokd 1 240 val
+xhlcrrbpff 1 300 val
+xhldizmuqm 1 300 val
+xhlixlelbj 1 297 val
+xhljdvjzoo 1 300 train
+xhlnvxhekg 1 300 train
+xhlwdhtulm 1 300 train
+xhmcnywgaz 1 300 train
+xhmdydztcc 1 300 train
+xhmgxwutmf 1 300 train
+xhmiapbwsj 1 300 train
+xhmiwsuwln 0 300 val
+xhmtqrruaa 1 300 train
+xhmukdonsg 1 300 train
+xhmwzezquo 1 300 train
+xhmycaqsse 1 300 train
+xhnfhlwbid 0 300 train
+xhnicutnri 1 300 train
+xhnkhqsdyx 1 300 train
+xhnlfztlin 1 300 train
+xhnoowimyd 1 300 train
+xhnqyqqyut 1 300 train
+xhnrwjldth 1 300 train
+xhnxrwvhix 1 300 train
+xhonoegyad 0 300 train
+xhopnbhoiq 0 300 train
+xhoruswklx 0 300 val
+xhotkjyjqd 1 300 train
+xhourslujq 1 299 test
+xhpdblckfs 1 300 train
+xhpgqwlyff 0 300 train
+xhpjiveluj 1 300 train
+xhpkbubsik 1 302 train
+xhpmpyzlfp 1 300 train
+xhpsuepfro 1 300 train
+xhptmczwjg 1 300 train
+xhpvgvvnys 1 300 train
+xhpwtvrcvj 1 300 val
+xhpxjgnxth 1 300 train
+xhqhzmptrt 1 300 train
+xhqlwtehrz 1 300 train
+xhqnqpepiy 1 300 train
+xhqqnfiewn 1 299 train
+xhqtvlnwrf 1 300 train
+xhqumnwnud 1 240 train
+xhqvlmevuo 1 300 train
+xhqvxfhjrn 1 300 val
+xhqypewgyb 1 300 train
+xhrhgdgtzu 1 301 train
+xhrlyqifqe 1 300 train
+xhrpdybqxq 1 300 train
+xhrtyqwwmf 1 296 train
+xhrvrdvpqp 0 300 train
+xhscyrzbhh 1 300 train
+xhshkbboer 1 300 train
+xhshzcghth 0 300 val
+xhsijmkono 0 300 val
+xhsjvwqtem 1 300 train
+xhskyeplud 1 300 train
+xhsnujtnec 0 300 train
+xhsnyxymjs 1 300 train
+xhspqxhrxb 0 300 train
+xhsramepav 0 300 val
+xhssclqbvg 1 300 train
+xhsswoapsx 1 300 train
+xhssxmjzrm 1 300 test
+xhswhlxuue 1 300 train
+xhtbkjgrjv 1 298 train
+xhtcampgph 1 300 val
+xhtchlrkfg 1 300 train
+xhtdflcytj 0 269 train
+xhtgwtnbvt 1 300 train
+xhtmrlavkq 1 300 train
+xhtnpalynh 1 299 train
+xhtnxeqjhp 1 300 train
+xhtojftkga 1 300 train
+xhtpkmpaba 0 300 train
+xhtppuyqdr 1 300 test
+xhtvdpdhtu 1 300 train
+xhubfhglte 1 300 train
+xhujafidzn 1 300 train
+xhuoilsome 1 300 train
+xhupoyhlic 1 300 train
+xhuuyaeaxu 1 300 train
+xhuwarazzq 1 300 train
+xhuxjilijb 1 255 train
+xhvcslyhtm 1 300 train
+xhvqggroxd 1 300 train
+xhvxvrcfve 1 300 train
+xhwacojjdg 1 300 val
+xhwesgeatq 1 300 train
+xhwjtmumsr 1 301 train
+xhwnzeozrd 1 299 val
+xhwqubpwru 1 300 train
+xhwrkcvlnr 1 300 train
+xhwshezlrb 1 300 train
+xhwtocsxgs 1 300 train
+xhwzideahc 1 300 train
+xhxbalyulq 1 300 train
+xhxcbcamwo 1 300 train
+xhxcpuiekn 1 300 val
+xhxfqeqbgd 1 300 train
+xhxlsedcyb 1 300 test
+xhxpeibbli 1 300 val
+xhxqqbugwh 1 241 train
+xhxtlczxxh 1 300 train
+xhxybwvujo 1 300 train
+xhyjcncbcl 1 300 train
+xhykdwekvl 0 300 train
+xhynmxmfwq 1 300 train
+xhyuntdhcr 1 300 train
+xhywuayloi 0 301 val
+xhyxbgagkv 1 298 train
+xhyzpfrbud 1 300 test
+xhzekazqrg 1 300 train
+xhzznbwfxz 1 300 train
+xiadxthrzx 1 300 train
+xiafygwfvc 1 300 val
+xiahoomxje 1 300 train
+xialcjbiop 1 300 train
+xiayholmqs 1 300 train
+xiaykkootc 1 300 test
+xibkzmsbtq 1 300 train
+xibsqpmuqx 1 300 val
+xibtcvhmsf 1 300 train
+xibtfhsvyw 0 300 train
+xibxuyhmel 0 300 val
+xibybojsxn 1 300 train
+xicbbzpvzw 1 300 train
+xicejvlsxq 1 300 val
+xicfancdrx 1 300 train
+xicgyscsiu 1 300 val
+xichjlzzxw 1 300 train
+xicpdtxqvv 1 301 val
+xicwrurdmw 1 300 train
+xicwsixkcx 1 300 val
+xicwzjeahw 0 300 val
+xicyzykqmv 1 300 train
+xiczdxnhuf 1 300 train
+xidlplincc 1 300 train
+xidossyjwx 1 301 train
+xidqzrdbzg 0 300 train
+xidsbcpobx 0 300 train
+xidthgahxh 1 300 train
+xiduaeaxqw 1 241 train
+xidzhympqu 1 300 train
+xiecdelptx 0 300 val
+xiecsxktvo 1 300 train
+xiekprhlqw 1 298 train
+xierbqybwt 0 300 train
+xiesaacmcb 1 300 train
+xifbbnqcmq 1 300 train
+xifkdtawnh 1 300 val
+xiflwiywqo 1 299 test
+xifnhpcpnz 1 297 train
+xifuovpydw 1 300 train
+xifydpcakx 1 300 train
+xigedrtcuf 1 300 train
+xigerhttnn 1 300 train
+xigkcfjpdg 1 300 train
+xigwnytqbj 1 301 val
+xigzbgwkcl 1 249 train
+xihbicgsqe 1 300 train
+xihcuecetu 0 300 train
+xiheppoelj 1 83 train
+xihezvabxa 1 300 train
+xihfjrfqie 1 300 train
+xihmwcgijt 0 300 val
+xihqwglcgb 0 300 train
+xihstnaams 1 300 train
+xihszunjln 1 300 train
+xihuurrqxl 1 300 train
+xihxyfasjq 1 300 train
+xihyxxpvpw 1 300 train
+xiicefdzta 1 300 train
+xiiciwqxvg 1 300 train
+xiiioplxik 1 300 train
+xiiqnxqvqc 1 297 train
+xiircvqmne 0 300 train
+xiirvcxxgm 1 300 train
+xiixbaptvz 0 300 val
+xiiyfelcak 1 288 train
+xiizouutms 1 300 val
+xijcwhmffk 1 300 train
+xijdwagfke 1 300 train
+xijgariqqh 1 300 train
+xijqnlocqp 1 300 train
+xijvitkqlt 1 300 train
+xijwzghfsv 1 300 val
+xikirwouvb 1 300 val
+xiklvzllux 1 241 train
+xikmpejguq 0 300 train
+xiknmepqen 1 301 train
+xiknwpuwed 1 300 train
+xikpwmuvxy 1 300 train
+xikufeenos 1 300 val
+xilaffirwr 1 241 train
+xilpmegfkq 1 300 train
+xilquenqtd 1 300 train
+xilsqhsrcr 1 300 train
+xilttmnhnt 0 297 val
+xilvwavqvu 1 301 val
+xilyoitgzr 1 300 val
+ximaxvytgd 1 301 val
+ximdpdyida 1 241 train
+ximgfgdhla 1 300 val
+ximgxanicc 1 300 train
+xinfjvbhad 1 300 train
+xintsrupel 1 300 val
+xioaknevdr 0 300 val
+xiobpyhjqz 1 300 train
+xiocdasaeg 1 300 train
+xioolrhtlf 1 300 train
+xioozkmgfx 1 300 val
+xioqvkwlaj 1 300 val
+xiotfhakdb 1 300 train
+xioutskxhb 1 300 train
+xiovxhjrtr 1 299 val
+xiowwjstqd 1 300 val
+xiozdebbcd 1 300 train
+xipdtuiznh 1 300 train
+xipffqcudf 1 300 train
+xipflwsfdx 1 300 val
+xiplpfevlw 1 300 val
+xipofifwew 1 300 train
+xiprlcbxxd 0 100 train
+xipvqunqjx 1 300 val
+xipwzyokif 1 299 train
+xiqalfasqq 0 300 train
+xiqbkvdpzy 0 300 train
+xiqbyflpqk 1 300 val
+xiqecarvpb 0 300 train
+xiqehtmhbu 1 300 train
+xiqjfyfwte 1 298 train
+xiqjwvqeit 1 300 train
+xiqrzmtuet 1 300 train
+xiqxxlbvry 1 301 val
+xiraodtgnt 1 301 train
+xiriffwqri 1 300 test
+xirkoqnzjk 0 300 train
+xirrbpmlja 0 300 train
+xirrnbhdpm 1 300 train
+xirximrith 1 147 train
+xisbtmyevw 1 300 train
+xisdwnvqwd 1 300 val
+xisljdekrc 1 300 train
+xispwaswzq 1 300 train
+xitgdpzbxv 1 300 test
+xitiqqbxvw 1 300 train
+xitkmhsala 1 241 train
+xitosplcpz 1 300 train
+xituyrljzd 0 300 train
+xitvbsjxoe 0 300 train
+xiubeffgfi 1 301 val
+xiufgdrwge 1 300 train
+xiulzucchh 1 300 train
+xiupkiowwb 0 300 train
+xiuqadclan 1 300 train
+xiurmuojfq 1 300 train
+xiutcafpof 0 300 val
+xiutydegfu 1 300 test
+xiuvltlmbl 1 300 train
+xiuxsxawpj 1 301 train
+xiuycgppds 1 300 train
+xivbvewnkv 1 300 train
+xivcanualo 1 301 val
+xivflrbixl 1 300 val
+xivfssfypr 1 300 test
+xivhwzxipt 1 300 train
+xivjklxggb 1 301 train
+xivkqjpgdz 1 300 train
+xivkudauuu 1 300 val
+xivovgwyhq 1 300 train
+xivvoqjawo 1 300 train
+xivzljaclt 1 300 train
+xiwawmqxst 1 298 train
+xiwfjymxlc 1 300 train
+xiwgdxzocf 1 300 train
+xiwintetuy 1 300 train
+xiwjzapdmt 1 300 train
+xiwpvcxuhr 0 301 train
+xiwpxkdsvk 1 298 val
+xiwrzrhyzu 1 300 train
+xiwsirfgob 1 300 train
+xiwtezqoyb 1 300 train
+xiwwvpkpam 1 300 train
+xiwycfcnhi 1 300 train
+xiwyueuqpn 1 300 train
+xiwznuvygu 0 300 train
+xiwzrhcnfi 1 300 train
+xixetxtqog 1 300 train
+xixruqmlcx 1 300 val
+xixtbdxefo 1 300 train
+xiybrafzqm 0 300 train
+xiydrffydd 1 300 val
+xiyfglhqlg 1 300 train
+xiyhfdybci 1 300 train
+xiyqyqevde 1 300 train
+xiyukypioq 1 300 val
+xizegktjil 1 298 val
+xizenrbleu 1 300 train
+xizgtkfefo 1 300 train
+xizkunzksi 1 300 val
+xiznkcizxd 1 240 train
+xizorawlsg 1 300 val
+xizwimsgux 1 300 val
+xjaamriopq 0 300 train
+xjabnijtoe 0 134 val
+xjafjquber 1 300 train
+xjaramnzru 0 300 train
+xjatrqlsfi 1 297 train
+xjaumaiirx 1 300 train
+xjaweneunl 1 300 train
+xjbehcutqo 1 300 train
+xjbemzsoru 1 300 train
+xjbgqsdmvu 1 300 train
+xjbnrkztwu 1 300 train
+xjbzpzqrbn 1 300 train
+xjchppalhv 1 300 train
+xjcieqijcn 1 300 train
+xjclxnxjkx 1 300 train
+xjcoinhsdx 1 300 train
+xjdbbrunql 1 300 train
+xjdfqtetfq 1 300 train
+xjdglixclr 1 300 train
+xjdpwdzbmz 1 300 train
+xjdqjydlff 1 300 train
+xjdvgijosl 1 300 train
+xjeavrnqry 1 300 val
+xjefbadvmv 1 300 train
+xjefxshzbg 0 300 train
+xjehwzyppe 1 300 train
+xjekugqeho 1 300 test
+xjenhmxxma 1 300 train
+xjepolduuh 0 300 train
+xjeykyxwrx 1 300 train
+xjeyxwjnrg 1 300 train
+xjfabwzxpi 1 300 train
+xjffizvhhs 0 300 train
+xjfmirjqdf 0 300 train
+xjfourpghd 0 300 train
+xjfozccdtg 1 300 train
+xjftidgkpr 1 300 train
+xjfuijedai 1 300 train
+xjfvhfyunl 1 300 test
+xjfxakvynp 0 300 train
+xjfzvlgzed 1 241 train
+xjghkkvwuu 1 300 train
+xjgkoepjku 1 300 train
+xjglkyvxdm 1 300 train
+xjgusulnbn 1 300 train
+xjgvtqcldv 1 300 train
+xjgxvbteqa 1 300 train
+xjgyeppcnv 1 300 train
+xjgzmfwnft 1 300 train
+xjgzwprwne 1 300 val
+xjhdzhgkno 0 300 train
+xjhepcifmz 1 300 train
+xjhevtsuux 1 300 train
+xjhewcnmsr 1 300 train
+xjhkylpywh 0 302 train
+xjhlsnmhuy 1 300 train
+xjhnaeiswi 0 300 val
+xjhnbgoaok 1 300 train
+xjhoigdlew 1 300 train
+xjhonbnslc 1 301 train
+xjhsxnjjad 1 300 train
+xjhuorrcpv 1 300 train
+xjhvkkdnfd 0 300 train
+xjiaqujfqg 1 300 train
+xjidghxsfk 1 300 train
+xjidmljhxe 1 300 test
+xjihohrlga 1 300 train
+xjiluusyoc 1 300 train
+xjinzawywt 0 300 train
+xjjatvvlzg 1 300 train
+xjjavnfjje 1 300 train
+xjjdhltngl 1 300 val
+xjjezowxnw 1 300 train
+xjjnbyvjil 1 298 train
+xjjndtjnwk 1 300 val
+xjjppmcvgn 0 300 train
+xjjtejtfar 1 300 train
+xjkaankpjj 0 300 train
+xjknccfmwp 1 300 train
+xjkpdytjdo 1 300 train
+xjkwfwnrwy 1 301 train
+xjlaojpzvz 1 300 train
+xjlaormxuu 0 300 train
+xjlkjzcfgu 1 301 train
+xjlpqffzoq 1 300 test
+xjlrrfqrxa 1 300 test
+xjmaavkaxl 0 300 val
+xjmicmjrgm 1 300 train
+xjmjnvcwze 1 300 val
+xjmjvyjhgq 1 301 train
+xjmnerypjf 1 300 val
+xjnczgpxwy 1 301 train
+xjndyrsvfr 0 300 train
+xjnflcfxhn 1 239 train
+xjnisbsatw 1 300 train
+xjnkgrhlxa 1 298 train
+xjnmeuvvuu 1 298 val
+xjnptropld 1 300 val
+xjnygeuqux 1 300 train
+xjnzdvfhpp 1 300 train
+xjolijoawd 1 300 train
+xjoprlujok 1 302 train
+xjpdicdtxd 1 241 train
+xjpinnfjxw 0 300 train
+xjpmceyryy 1 299 train
+xjpuqaqamf 1 300 train
+xjpuzxrfxe 1 288 train
+xjpwlxducl 1 300 test
+xjpwvgwrmo 1 300 train
+xjpxgbmhsn 1 300 train
+xjqehvqxza 1 300 train
+xjqihtqqec 1 302 train
+xjqlexuqhp 1 300 train
+xjqlfbrtwb 1 300 train
+xjqqegvmzd 1 300 val
+xjqsnypjjg 0 300 val
+xjrbfgcvlu 1 300 train
+xjrcwrcssj 0 300 train
+xjrhelznsm 1 300 train
+xjrpjxxfam 1 300 train
+xjrrkbsqyk 0 300 val
+xjrsbdqdyn 1 300 train
+xjsbsgisgv 1 300 train
+xjsemellqq 1 301 val
+xjsgnqjowb 1 300 train
+xjshfrgbub 1 300 val
+xjsjlxfqmx 1 300 train
+xjsovchfkg 1 300 test
+xjsscmzsrk 1 300 train
+xjsyeinqbk 1 300 train
+xjtckaejyi 1 300 train
+xjtfbvynof 1 240 train
+xjttpezwcg 1 300 train
+xjuezovkbt 0 300 train
+xjugytcndb 0 300 val
+xjujnhwgjb 1 300 train
+xjuprdnynp 1 300 train
+xjuudjewce 0 300 train
+xjuvfolpbg 1 300 val
+xjvbptjhan 1 300 train
+xjvdvxujwq 1 241 train
+xjvfacvyvo 1 300 train
+xjvtkebyez 1 300 train
+xjvxnklaus 1 300 train
+xjvxtuakyd 1 300 test
+xjwfnsakas 1 300 train
+xjwwjcjocc 1 297 train
+xjwyjwvlwn 1 241 train
+xjwyksuopn 1 300 val
+xjxacegczt 1 300 train
+xjxfonxtcx 1 298 train
+xjxgmbkkxe 1 300 val
+xjxhlsfhnd 1 300 train
+xjxkzgkdnz 1 239 train
+xjxrqnyvsg 1 300 train
+xjxyhsjzzs 1 300 val
+xjyfnnvfnf 1 300 val
+xjynjwcohw 1 296 train
+xjyrvdnxrv 1 300 train
+xjzbutlpup 0 301 train
+xjzdwnmdrs 1 300 val
+xjzfsgeizn 1 300 train
+xjzkfqddyk 0 300 val
+xjzmkuxskq 0 300 test
+xjzncerlbw 0 300 val
+xjzsvhdess 1 300 train
+xjzttepkkq 0 300 train
+xjzxugtqyc 1 300 val
+xjzznlvggk 1 300 train
+xkapdbabng 1 300 train
+xkaxpvujmy 1 241 train
+xkaxzswqcn 1 300 train
+xkbjexqnwo 1 300 train
+xkblcaopmw 1 300 train
+xkblnsntnr 0 300 train
+xkbnezabmd 1 300 train
+xkbnizadxr 1 300 train
+xkbvqelobg 1 300 train
+xkckjxpknj 1 300 train
+xkcrkrdokw 1 300 train
+xkcykjbgou 1 300 val
+xkczlfyxwy 1 300 val
+xkdcfghskb 1 300 train
+xkdcgfgzit 1 300 train
+xkdfchnwha 1 300 train
+xkdhlnchgo 1 298 train
+xkdizhmpzd 1 300 train
+xkdoyetaeb 1 300 train
+xkdpunpbqy 1 300 train
+xkdpwxzlxw 1 300 train
+xkdsqhiizi 1 297 train
+xkdyomjahe 1 300 train
+xkdzqitjcd 1 300 val
+xkedszorai 1 300 train
+xkeiiwdbrh 0 300 train
+xkfaumdhlx 1 299 test
+xkfgptnoyj 1 300 train
+xkfjmbqpbp 1 300 train
+xkfliqnmwt 0 300 test
+xkfmaesdfp 1 300 train
+xkgcibmnoh 1 300 train
+xkgduvqzyn 1 300 train
+xkgfafkidn 0 255 train
+xkgfsbglko 0 300 train
+xkgkmlosfa 1 298 train
+xkgrahebgp 1 300 train
+xkgxfucltb 1 300 train
+xkgxknqbak 1 300 train
+xkhcmoiymh 1 300 train
+xkhcoryrri 1 300 val
+xkhdksfnel 1 300 train
+xkhesepfww 1 300 train
+xkhhrqpula 1 300 val
+xkhomcfvko 0 300 train
+xkhqswzqde 1 300 train
+xkhrmvuukj 1 300 train
+xkiacmotuy 1 300 train
+xkiaznwsoo 1 300 train
+xkicasophk 1 299 test
+xkiccouzag 1 299 val
+xkichouvzp 1 300 test
+xkifczipma 1 300 train
+xkikoxtneh 1 300 train
+xkimgoyswv 0 300 train
+xkinpumbun 1 300 train
+xkisxybwna 1 301 train
+xkiulyxgwh 1 300 val
+xkjegqflca 1 299 train
+xkjftdistb 1 297 train
+xkjjlpwjul 1 301 train
+xkjjvbjmrt 1 301 train
+xkjkliotjs 1 300 train
+xkjnrsxlns 1 300 train
+xkjoqenltu 1 300 train
+xkjvhwddmz 0 300 train
+xkjvqrfncn 1 300 train
+xkjwdgyqhi 0 300 train
+xkjwfbelsh 1 300 val
+xkjxqiwrow 1 300 val
+xkjykqypsb 1 300 val
+xkkasacbqf 1 301 train
+xkkdsndlpr 1 300 test
+xkkpnwfsgd 1 300 train
+xkksfulade 1 300 train
+xkkwljxxqy 0 300 val
+xkkwrvphtp 1 300 train
+xklaopgefe 1 300 train
+xkldhegteg 1 300 train
+xklkkvztgc 0 301 train
+xklldpsnnm 1 300 train
+xklmdgemio 0 300 train
+xklmnjsqva 1 300 train
+xklnwrmaxq 1 300 train
+xklrkmldun 1 300 train
+xkltttyeop 1 301 train
+xklzkakxcw 1 300 train
+xkmhhsbilj 1 300 train
+xkmjnbfifd 1 301 val
+xkmkgakdqm 0 300 train
+xkmmrmxwde 0 300 train
+xkmpyvtdch 1 300 test
+xkmvwzyaqv 1 300 train
+xkmyyjztoo 0 300 val
+xkncagmryo 1 288 train
+xknfrytuan 1 300 train
+xkngypbexi 1 241 train
+xknhvawkev 1 241 train
+xknliyklhp 1 300 val
+xknpxwqehc 1 300 val
+xkoaiukxcq 1 300 train
+xkokkanfcj 0 300 train
+xkookamkfj 1 300 train
+xkopklfugl 1 300 train
+xkowyhuhks 1 300 train
+xkozmahkeb 1 300 train
+xkpaqvpzvj 0 297 train
+xkpcpjnlul 1 301 val
+xkpejwpdfl 1 300 train
+xkphrpjkab 1 300 train
+xkpsjzvoss 1 300 train
+xkpssaixjg 1 300 train
+xkpthizeuj 1 300 train
+xkqofeegvk 1 299 train
+xkqucgzmnr 1 300 train
+xkqusyptmm 1 299 test
+xkqzvwznhl 0 300 train
+xkrcahzhkm 1 300 train
+xkrhzvriqg 0 300 train
+xkrktrhuxv 1 301 train
+xkrloldqad 0 300 train
+xkrrmawgaz 0 297 val
+xkruuvofkf 1 301 train
+xkrvwbgmiz 1 300 train
+xkrzgbulrm 1 301 val
+xksakcfxuk 1 300 train
+xksbvlkung 1 99 train
+xksiylvovg 1 300 train
+xkspwcmsid 0 300 train
+xkssscurqs 1 300 train
+xkstqrneyc 0 298 train
+xksyafiemp 1 300 train
+xktfphoeba 1 300 train
+xktipmfwcx 0 300 train
+xktmelfems 1 300 train
+xktoyncrav 1 300 train
+xktswlkdys 1 299 train
+xkttbfurhh 1 300 train
+xktwgzpomg 0 300 train
+xktxmoeexp 1 300 train
+xkublwkqhi 1 300 train
+xkucyqqcsx 1 300 train
+xkuhkhbyys 1 300 train
+xkuisjlwgd 1 300 train
+xkujzzpzik 1 301 train
+xkukyjokbg 1 300 train
+xkurqxmdnq 1 300 train
+xkurtfxgtp 1 298 train
+xkuwzsbrwr 1 241 train
+xkvafjalpe 0 300 train
+xkvbhgeugc 1 300 val
+xkvdncadav 1 300 train
+xkvgeehqrq 1 300 train
+xkvnhplmdy 1 300 train
+xkvszzqaky 1 300 train
+xkwcbtpbvf 0 300 train
+xkwjjjkcam 1 300 val
+xkxhaooxgz 1 240 train
+xkxhviuxjp 1 300 train
+xkxibofjux 1 300 train
+xkxjgzhuge 1 300 train
+xkxodgubhh 1 300 train
+xkxpxvbxil 0 300 train
+xkxryjpmwk 0 300 train
+xkxyedjqvs 1 300 train
+xkxyusmczj 0 298 train
+xkybhxtgqs 1 300 train
+xkydpwqkxf 1 300 val
+xkymybesey 1 300 train
+xkzavewqnh 0 300 train
+xkzcxoxoxf 1 300 train
+xkziknvgen 1 298 train
+xkzmagkqqa 1 300 train
+xkznbmutcv 0 300 val
+xkzqfblqqq 1 301 train
+xkzxogkqyr 0 300 val
+xlahpjsdxq 1 239 train
+xlaioofnws 1 300 val
+xlamieldxy 1 300 val
+xlapirebur 1 298 train
+xlaqzkixmr 1 298 val
+xlbglumoag 1 300 train
+xlbkicrvzo 1 300 train
+xlbmareait 1 300 train
+xlbnmndmku 0 300 train
+xlbqvbhjyu 1 300 train
+xlbvnooctn 1 300 val
+xlcbtcyrzh 1 300 train
+xlchhfrrxw 1 300 train
+xlchvtbnpf 1 300 val
+xlcjydbhsh 1 300 train
+xlckparmrj 1 298 train
+xlclcojbtv 1 300 train
+xlcnxkqysr 1 300 train
+xlcurcvkyv 1 300 val
+xlcvyovmaq 1 241 train
+xldcwunomk 1 300 train
+xldnvpbneb 1 300 train
+xldohgosrb 1 300 train
+xlduqztuoi 1 300 train
+xldzfcejov 0 300 train
+xleadejchd 0 300 train
+xledahfgac 1 300 test
+xleihiqgxt 1 300 train
+xleoyazwyk 1 300 train
+xlettggvts 1 299 val
+xleuufeoti 0 300 train
+xlewytmgee 0 300 train
+xlfaqxxxiw 1 300 train
+xlfbhfwlte 0 300 val
+xlfbpvsfqm 1 136 train
+xlfhcyfpgr 1 147 train
+xlfjdhkvic 1 301 train
+xlfkmfhelb 1 300 train
+xlfmaytwqx 1 300 train
+xlgejurbsg 1 297 train
+xlgevjtsog 1 300 train
+xlghufwrke 0 300 train
+xlgjchndlo 1 300 train
+xlgjrzdlrk 1 300 train
+xlgqywsgfj 1 300 train
+xlgrbsgelf 1 298 train
+xlgsgclvgm 1 300 train
+xlgwtpqtyj 1 300 val
+xlgzdiwdnr 1 297 train
+xlgzsipnhf 0 300 train
+xlhjedtvwu 1 300 train
+xlhjkjbybx 1 300 train
+xlhrsefbpk 1 300 val
+xlhxkekacj 1 300 test
+xlhyukrrmt 1 300 train
+xlibckpcus 1 299 train
+xlidewmffb 1 300 train
+xlijxbocay 1 241 train
+xlinawzewi 0 300 val
+xlintwhoku 1 300 val
+xliopagnex 1 300 train
+xlivyxzwar 1 300 train
+xlixnbjyhz 1 300 train
+xljemofssi 1 299 test
+xljfdhhgfi 1 300 train
+xljifguhfa 1 300 train
+xljksfbzpn 1 300 train
+xljqfthuzp 0 300 val
+xljsgbmygt 1 301 train
+xljxbwqztb 1 300 train
+xljydsvlur 1 300 train
+xlkcgfyfax 1 300 val
+xlkdujikry 1 300 train
+xlklgamhbq 1 300 test
+xlkmcijvsg 1 300 train
+xlkqkmatgp 1 300 val
+xlkvtpsewc 1 300 train
+xlkyrcnybu 1 300 val
+xlkzrninyj 1 300 val
+xllkiqsfnc 1 300 train
+xlllrhropy 1 301 train
+xllpbhdgwt 1 300 train
+xllpvwxqtr 1 300 train
+xllrqbrqdb 1 301 val
+xllunmevmk 1 300 train
+xllvxerqht 1 300 train
+xllzvdxwiv 1 300 train
+xlmadlrzen 1 300 train
+xlmduthjih 1 300 test
+xlmeyxzlqw 1 300 val
+xlmljmrazg 1 300 train
+xlmqpciqvw 1 300 train
+xlnaamlirk 1 300 val
+xlnaxrwvcx 1 300 train
+xlncoajjum 0 300 train
+xlnhcyfibr 1 300 train
+xlnjrddfgd 1 300 train
+xlnovvjfhv 1 300 train
+xlocqtmbgr 1 300 train
+xlokewodzu 1 300 train
+xlommplrep 1 300 train
+xlpgwezdvs 1 300 train
+xlpliewehj 0 300 train
+xlpwfnxpdv 1 240 train
+xlpwsmqfob 1 300 train
+xlpymkbxyv 1 301 train
+xlqdwwxxzb 1 300 test
+xlqhioxxqj 1 300 train
+xlqsvlvqep 1 300 train
+xlquhgpnbe 1 300 train
+xlqvwogzww 1 300 val
+xlrcwooept 1 241 train
+xlrjgmpfqe 1 300 val
+xlrlwolzfs 1 167 train
+xlrofhbtzg 0 300 train
+xlrslctwat 1 302 val
+xlrtwaqxxs 0 300 train
+xlsdmekqyf 1 300 train
+xlsgcwoopy 1 300 train
+xlsvvzghbo 1 300 val
+xltkixojao 1 300 train
+xltllxrdfg 0 300 train
+xltosanmhi 1 300 train
+xltymjdxqc 1 299 test
+xlubltdxza 0 300 train
+xlubviardp 1 300 train
+xluerxyxtg 1 300 val
+xlujpqvksc 1 300 train
+xlukbnmkfz 1 300 train
+xlurhxaqcu 1 300 train
+xlusjtfzjc 1 300 train
+xlvneejsyd 1 300 train
+xlvvoocsdb 1 300 train
+xlvxpzdqfa 1 298 train
+xlwebdaikv 0 301 train
+xlwgcjqqph 1 300 train
+xlwkfjoxmm 1 300 val
+xlwlctecwe 0 300 train
+xlwmfyphoo 0 300 val
+xlwtrpwrhl 0 290 train
+xlwvliqwiy 1 298 train
+xlwxlnjros 1 300 train
+xlxdaljhze 1 300 train
+xlxffrtqhm 1 300 train
+xlxhbvvwor 1 300 train
+xlxnrqzcrk 1 300 train
+xlxrlesuds 0 300 train
+xlxrqkzpys 1 300 train
+xlxukgsdcy 1 300 train
+xlxwcbdfps 1 300 train
+xlxwyikefo 1 300 train
+xlxyzouisc 0 300 train
+xlycadmnzu 0 300 val
+xlycsdtapk 1 300 val
+xlyhhwudyq 1 298 train
+xlyrtjtrus 1 300 train
+xlyvwofsdz 1 300 train
+xlyxbyhjsq 0 300 train
+xlyxstdumn 1 300 train
+xlzbtjencd 1 298 train
+xlzcdtjiwk 1 300 train
+xlzedszsgp 1 298 train
+xlzhzudnny 0 300 val
+xlzopuigul 1 300 train
+xlzraxvakv 1 300 val
+xlztcepaup 0 300 train
+xlzvqpfcde 0 300 train
+xmaecjtlyx 1 300 train
+xmaltooilz 0 301 train
+xmbfxuhund 1 299 test
+xmbgflopiw 1 300 test
+xmbhmhwnhb 1 300 train
+xmbneugzsp 1 300 train
+xmbscdqzuq 0 300 train
+xmbtnyfimf 1 299 test
+xmbuwvigko 1 300 val
+xmchzktvty 1 300 train
+xmddxkgsts 1 300 train
+xmdfnldfyc 1 301 train
+xmdhsaalct 1 300 val
+xmdowqtcwi 0 300 train
+xmdqvblbfh 1 300 train
+xmdviljuzz 1 300 val
+xmeapyzgej 1 299 train
+xmeflrelzc 1 301 train
+xmemmkxqid 1 300 val
+xmenaksqst 1 300 train
+xmephobexu 1 300 train
+xmeqfvhvjp 1 300 train
+xmewblvhmq 0 300 val
+xmeyjfcooa 1 300 train
+xmfaswgsqs 1 300 train
+xmfcxuikuw 0 299 train
+xmfgobzcnc 1 300 train
+xmfmalxugv 1 299 val
+xmfnvdhbxw 1 300 train
+xmfqdmlixo 1 300 val
+xmftxipfks 1 300 val
+xmftxmapnq 1 302 val
+xmftyqqnyn 1 301 train
+xmgbsslszp 1 300 val
+xmgdvugizi 1 300 train
+xmggpxzakw 1 300 train
+xmgiaricwx 1 300 train
+xmgoisqfaj 1 240 train
+xmgttawlsn 1 300 val
+xmgurzfwov 1 288 train
+xmhdllgras 1 300 train
+xmhirifhqd 1 300 val
+xmhizzwznq 1 298 train
+xmhyaumawt 1 300 train
+xmiawargkx 1 300 train
+xmidsivtbc 1 300 train
+xmigklprdt 1 300 train
+xmiqdgedyt 1 300 train
+xmisyapgxv 1 300 val
+xmiulkdqxz 1 300 train
+xmiuokxjlx 1 300 train
+xmivfmjngt 1 300 train
+xmivrtwlos 1 300 train
+xmjdzmyhtb 1 300 val
+xmjhkvrrvk 1 300 train
+xmjmtxpmho 0 300 train
+xmjrjpauyh 1 300 train
+xmjsnwltkc 1 300 train
+xmjtygwyae 1 300 train
+xmjulcecbl 1 300 train
+xmjvwrprxl 1 300 train
+xmkgjkptcv 1 300 train
+xmkjfyuuox 1 237 train
+xmkpamjozc 1 301 train
+xmkqoawrev 1 301 train
+xmkrimauvs 1 301 train
+xmkwsnuzyq 0 300 test
+xmkxqasvig 1 303 train
+xmlbtgpqfo 1 300 val
+xmldamsigm 1 241 train
+xmlfnnncxr 1 300 val
+xmlfvzvjci 1 301 train
+xmlfxugjgt 1 300 train
+xmlgvhkivr 0 300 train
+xmlhohpkai 0 300 val
+xmljmdhgbj 1 300 train
+xmlnitpkpj 1 300 train
+xmlrmnyygp 1 301 train
+xmlzbotcny 1 167 train
+xmlzldvtox 1 300 train
+xmmacfcrck 1 300 train
+xmmhtbzfii 1 300 train
+xmmluiswhs 1 298 train
+xmmoixcdre 0 300 train
+xmmpljozqy 1 300 train
+xmmriavvjo 1 300 train
+xmmycuvrks 1 300 val
+xmnafyhinq 1 300 train
+xmndajwnlr 1 300 train
+xmnmkizest 1 300 train
+xmnohpdmqa 1 300 train
+xmntybcgwa 0 300 train
+xmnvivqjps 1 300 val
+xmnxvpprpy 0 300 train
+xmnyqtahyx 0 300 train
+xmnzschkfx 1 300 train
+xmodyeeaxr 1 301 train
+xmognwolwu 1 300 train
+xmosmddmbn 1 300 train
+xmoudyvwoq 1 300 val
+xmouttqmih 1 300 train
+xmoxfrdace 1 300 train
+xmpdvguwps 1 300 train
+xmpgdhqbqe 1 300 train
+xmphbtlrck 1 300 val
+xmphmxoxcw 0 300 train
+xmpjhfried 0 300 val
+xmplwbxxwh 1 300 train
+xmpxmqvair 1 300 train
+xmqbevczno 1 300 train
+xmqgkmlmtu 1 297 train
+xmqlfsjtgs 1 300 train
+xmqyvthzeb 1 300 train
+xmrgsxxiek 1 300 train
+xmrkukifci 1 300 val
+xmrleaftbk 1 300 val
+xmrofudeqy 1 300 train
+xmrzizjeet 1 300 val
+xmsfoxihuk 0 300 train
+xmsgcbptln 0 300 train
+xmsmcvinac 1 300 train
+xmsmpvetfm 0 300 train
+xmsosoltkv 1 298 train
+xmsudeotlp 1 300 train
+xmsulpvcag 1 300 train
+xmsvfzvzln 1 300 val
+xmswsrpjcq 1 300 test
+xmsxjmqojy 1 300 val
+xmthxlnxfn 1 300 train
+xmtnuwsaxa 1 300 train
+xmtpyqiklt 1 300 train
+xmtrafnqab 1 300 val
+xmtsjwlucl 1 300 train
+xmtsonmwbw 1 300 train
+xmttvflvyl 1 300 train
+xmtummzttz 1 299 val
+xmugaqgobo 1 300 train
+xmujjjnnrw 1 300 train
+xmulqkwpyk 1 300 train
+xmulzzwmkp 0 300 train
+xmumdfcmad 0 300 train
+xmunbqeemd 1 299 val
+xmuqdpzkqb 1 300 train
+xmusztvreb 1 300 train
+xmutsluwxc 1 301 train
+xmvatvmhnd 1 300 train
+xmvdklxqym 1 300 train
+xmvdornmgd 1 300 train
+xmvtrebupa 1 300 train
+xmvytrqcpl 1 300 train
+xmwdivqczl 1 300 train
+xmweproioc 1 300 train
+xmwhfalrid 1 300 train
+xmwsagdeis 1 300 train
+xmwsugdohi 1 300 val
+xmwxfctxcr 1 300 train
+xmxqpkfvbz 1 298 train
+xmxqsnmfib 1 300 train
+xmxrrdlmyf 1 300 train
+xmxswrmfba 1 300 val
+xmxxhzdntt 1 300 train
+xmydcntkxj 1 300 train
+xmygrtoxpw 1 300 val
+xmyitpohoy 1 300 train
+xmykednhkz 1 300 train
+xmymrbbvmp 1 300 val
+xmyoobuyat 0 300 train
+xmyzqwabdy 1 300 train
+xmzeylrkuh 1 298 train
+xmzfmamfqy 1 300 train
+xmzpfgxpwt 1 300 train
+xmzvuqajmu 1 300 train
+xmzxihxeie 1 300 train
+xmzzevqmnj 1 300 train
+xnajnlmhuc 1 300 train
+xnanaqvsbx 1 300 train
+xnanjpradc 1 300 train
+xnarvhxkfy 0 298 val
+xnaywmypvz 1 300 train
+xnazdhvdbw 1 300 train
+xnbanuwzpc 1 300 train
+xnbflkxfau 1 300 train
+xnbgwgplvo 1 300 train
+xnbmsdvqmy 1 300 train
+xnbvdqknin 1 300 train
+xncaumlnaf 1 300 train
+xnceozqdue 1 300 train
+xncgusyghe 0 300 train
+xnchgengsw 1 239 train
+xnclpblgip 1 300 train
+xncqpmoabm 0 300 train
+xncsoryrnz 1 300 val
+xnctbdxocm 1 300 train
+xndaoxtmjk 1 300 train
+xndeknnxbi 1 300 train
+xndgwxxfug 1 300 train
+xndjuoyewh 1 298 train
+xndliuntob 1 297 train
+xndmjtayyd 1 300 train
+xndolpvahz 1 301 val
+xndrhvaavc 1 298 train
+xneabhqwib 1 297 val
+xneemieflw 1 300 val
+xneidptkul 1 297 train
+xneksgmzpw 0 300 val
+xneptoabue 1 300 train
+xnevdkbmkd 1 299 test
+xnewzfnmlm 1 300 train
+xneynfejbp 0 300 train
+xnezzuotho 1 301 train
+xnffzeybqq 1 298 train
+xnfjrjcnwt 0 300 train
+xnfrhixfym 1 300 test
+xnfuklvqgy 1 300 train
+xnfwdpptym 0 300 train
+xnfwyuxpmw 1 300 val
+xngpzquyhs 0 300 train
+xngtmlvoet 1 300 train
+xngulalhzi 1 300 val
+xngumtjmyj 1 301 train
+xngvdvxmlw 1 300 train
+xnhcreiyqg 0 300 train
+xnhdwynmmo 0 300 train
+xnhfbwlupc 0 298 train
+xnhhubddln 1 300 train
+xnhkxwrxtj 1 300 val
+xnhndnkbhj 1 300 val
+xnhnyfffeu 0 300 train
+xnhsjbzmux 1 300 train
+xnhsqvdreo 1 300 val
+xnhszvsxtr 1 301 val
+xniceiyqyb 1 300 train
+xnieamqykv 1 300 train
+xniepfeaue 1 294 train
+xnijaxpblb 1 300 train
+xnikkckcht 1 300 val
+xnikysqolj 0 300 train
+xniocvzamo 0 300 val
+xnipwslfnv 1 300 train
+xniqgoauyj 1 300 train
+xniszkvyiv 0 300 train
+xnitfsazel 1 300 val
+xniuxdhzew 0 300 val
+xnjdrixvtx 1 300 val
+xnjfuoqvxy 0 240 val
+xnjfvzjirs 1 300 val
+xnjhczeafm 1 300 train
+xnjklxduwc 1 301 train
+xnjlrqnodo 1 300 train
+xnjmslecoh 1 300 train
+xnjofwbsfg 1 299 test
+xnjpkvycba 1 300 train
+xnjxjofabc 1 300 train
+xnjytizzgl 1 300 train
+xnkbfgrrvz 1 300 train
+xnkcvmtiwg 1 300 train
+xnkfakdfbo 0 300 train
+xnkfiyuzga 0 301 train
+xnkhlmjkpg 1 300 train
+xnkkhqodvx 1 300 train
+xnkktewjmu 1 300 test
+xnklblizyu 1 300 train
+xnkumjgdfw 1 300 train
+xnkwwirdpa 1 300 train
+xnkzddgvmt 1 301 train
+xnljlvxxes 0 300 val
+xnlmsfumww 0 300 train
+xnlnbvryzn 1 298 train
+xnlplanvyz 0 300 train
+xnlppevmyl 1 300 train
+xnlsovllsp 1 300 train
+xnmfdcmmwl 1 300 train
+xnmgideuye 1 300 train
+xnmgyggveo 1 298 val
+xnmksqayel 1 300 train
+xnmmweqmdt 1 300 val
+xnmnhtwtex 1 300 test
+xnmqcdyokn 1 300 val
+xnmsrnzanl 1 300 train
+xnmsutvqgx 1 300 train
+xnmuzfjmpx 1 300 train
+xnmypgrycw 1 301 train
+xnnfyibslk 1 300 train
+xnnpkexkmv 1 300 val
+xnnplucykw 1 300 train
+xnnxenqpmn 1 300 val
+xnodtgvtcv 1 300 train
+xnohosrnku 1 300 train
+xnojggkrxt 0 300 train
+xnonsyusjp 1 241 train
+xnooobvepy 1 300 val
+xnoskmqurr 1 300 train
+xnouupfpkw 1 300 train
+xnoyolnyog 1 300 val
+xnpeljyqeu 1 300 train
+xnphxztlqt 1 300 train
+xnpjasumvg 1 300 train
+xnppyfbmlm 1 300 train
+xnprhafruz 1 300 train
+xnpvjyobre 1 301 val
+xnqdgiupew 1 300 val
+xnqdgqaraj 1 300 train
+xnqizzjnyr 0 300 train
+xnqlgwcdns 1 300 train
+xnqmkqdnct 1 300 train
+xnqnucwroy 1 300 train
+xnquvlotxa 1 300 train
+xnrhevindi 1 300 val
+xnruhaarln 1 300 train
+xnrvqxocjg 1 300 val
+xnrwmpxhrk 0 300 train
+xnsiigmwxk 1 300 val
+xnslswafht 1 300 train
+xnsohfzwqy 1 300 val
+xnssefkkqd 1 297 train
+xnsviqtwyr 0 300 train
+xntefilrbz 1 300 train
+xntjuldwap 1 300 train
+xntovhysij 1 300 train
+xntvmkpfxt 1 301 train
+xntvsitxhh 1 300 train
+xntwfzhlue 0 300 train
+xntxhnoghp 1 301 train
+xntzsahbvl 1 143 train
+xnubcfgfet 1 300 train
+xnubotvgff 1 300 train
+xnuqoyfhfm 1 300 train
+xnurkhdtxd 0 301 train
+xnvblwqjqb 0 300 train
+xnvpeumbbq 0 300 val
+xnvvoscjjc 0 300 train
+xnvzxpbhmj 1 301 val
+xnwenqdtwn 1 300 train
+xnwgdiozdk 1 300 train
+xnwiybvxoa 1 292 val
+xnwjbuflop 1 300 train
+xnwlmxlwsw 1 300 train
+xnwrytdxmo 1 300 train
+xnwxcwewvq 1 300 train
+xnwxjbzlfr 1 300 train
+xnxfdngbtf 1 300 val
+xnxfrzkkwo 1 300 train
+xnxtzrldwj 1 300 train
+xnxuzpmktw 1 300 train
+xnxwvxwaix 1 300 train
+xnxzevsedt 1 300 train
+xnydjwnzlz 1 300 train
+xnydmgdhum 0 300 val
+xnydzmkkrj 0 300 train
+xnyesmzssg 1 300 train
+xnyhnlhybw 1 301 train
+xnyjzfkjse 1 301 val
+xnylzkyfhi 1 300 val
+xnyryxpmoo 1 299 test
+xnytgehbnh 1 300 train
+xnyytgnoqn 1 242 train
+xnyzzzuhak 1 300 train
+xnzbhulqim 1 300 train
+xnzdpxwrce 1 300 train
+xnzgdeluhs 1 298 train
+xnzhlgindk 1 300 train
+xnzhzfhxcn 1 300 train
+xnzmsntcew 1 300 train
+xnzqffqczk 1 300 train
+xnztznqlis 1 300 test
+xnzukywbuk 1 300 train
+xnzwwmioyx 0 300 val
+xoacxwalxw 1 300 train
+xoagcfxybv 1 292 val
+xoaifvijgo 1 300 train
+xoakmtnicf 1 298 train
+xoaolfscjt 1 300 train
+xoapkwkuia 1 300 train
+xoatylayqx 1 300 val
+xoawtiwpru 1 300 val
+xobbzqqtqx 1 300 train
+xobchqwgrx 1 300 train
+xobfswaeef 1 301 train
+xobhsemxmv 0 300 train
+xobjrvpdzt 0 297 train
+xobskjwrsk 1 300 train
+xobukhdegf 1 300 train
+xobvooztra 1 301 train
+xocdnlovwo 1 300 train
+xocdwrxgxm 0 300 val
+xocihpjsbv 0 300 train
+xocxiqxrzn 1 300 test
+xodbjulkzz 1 299 train
+xodoqfbfag 0 300 train
+xodwvnneol 1 301 train
+xoeasjvtxw 1 300 val
+xoebzwapwo 1 300 val
+xoecceqbpz 1 300 train
+xoecfwfkwi 1 300 val
+xoedqewlun 1 300 train
+xoeiyltigh 0 300 train
+xoejghzrta 1 298 train
+xoelalrlzz 1 300 train
+xoelxhwhkm 0 300 train
+xoevrvpbni 1 300 train
+xofazlfwia 1 301 val
+xofcjdjjom 1 300 train
+xofgapycum 1 297 train
+xoflilbmth 1 300 train
+xoflsrxnrq 1 300 train
+xofltpagqq 1 300 val
+xofmniptpl 1 300 train
+xofpvguvxr 1 300 val
+xofrpsegqz 1 300 train
+xofswkdrvb 0 300 train
+xoftlalemo 1 300 train
+xoftlhonih 1 300 val
+xofwxwicui 1 300 train
+xofyhcjguj 1 300 train
+xogjjkxxpb 1 300 train
+xogkkrwhpx 1 299 val
+xogotmzqlc 1 300 train
+xogovqbbus 1 300 train
+xogslakysm 1 300 train
+xogusjcata 0 250 train
+xogwctpikv 0 300 train
+xohbtqfkfc 1 300 val
+xohekdasxo 0 300 train
+xohemvmkef 1 300 train
+xohfkmvalw 1 300 train
+xohinthdwz 1 300 val
+xohmwakhdb 0 300 val
+xohsacasxf 0 300 train
+xohvzwxcfs 1 300 train
+xohyoaqhmh 0 249 train
+xoicrtzjce 1 300 train
+xoiipxnrcv 1 300 train
+xoiqqwwyla 1 300 train
+xoitmjpmdi 0 300 train
+xoiugdvlcs 0 300 train
+xoiwuzyxbd 1 300 train
+xoiyevqols 0 300 train
+xoiylowlwk 1 300 train
+xojajsntod 1 300 val
+xojauzdavy 1 300 train
+xojavkscdx 0 300 train
+xojgmgasuq 1 300 train
+xojhypvwyr 1 300 val
+xojuahsfdv 1 300 train
+xojuannegi 0 300 train
+xokcawbloe 1 300 val
+xokismykfz 1 300 train
+xokkkyyagn 1 300 val
+xokshtsqbf 1 300 train
+xolbrupcwp 1 300 val
+xolffgtedl 1 300 train
+xoljaeckui 1 299 val
+xoljqdmcpk 1 300 train
+xolmiheqtm 1 300 train
+xolnhxomhz 1 300 train
+xolonyryhe 1 300 train
+xolvnfinjt 0 300 train
+xomdnrenca 1 300 val
+xomgjjjhhr 1 300 train
+xomjpqxtdh 1 300 train
+xomlalgauw 1 300 train
+xomnkmurzw 1 300 train
+xomrftndmq 1 300 train
+xomsxytksj 1 300 train
+xonaeungnm 1 300 val
+xonouhbsrt 1 300 train
+xonqtbsdti 1 301 train
+xonsffcpsi 1 299 test
+xoocqckwwg 0 241 train
+xoocwzsvxu 1 300 train
+xoodxratdi 1 300 train
+xoogdfsnof 1 300 train
+xookyvzepe 0 300 train
+xootorsmyh 1 100 train
+xoousvrlyn 1 300 train
+xoowpymrmj 0 301 val
+xopahtmybg 1 300 train
+xopdpwykpk 1 240 train
+xopkazwlxt 0 300 val
+xopktztrrn 1 298 train
+xopxepmoav 1 300 train
+xopyhcaofq 1 300 train
+xorcelpbzl 1 300 train
+xordkkatfr 1 300 train
+xorjeykqsr 1 300 train
+xorjjvkyzp 1 300 val
+xorltrktms 1 299 train
+xornjfxczn 1 300 train
+xorrjvoenz 1 300 train
+xorrpcjyxp 1 298 train
+xorrsueuhg 1 298 train
+xorspaztbe 0 301 train
+xorveoemph 1 300 train
+xorveyaiyh 1 300 train
+xorzknialr 1 300 train
+xosbvurwon 0 301 train
+xosjgwympx 1 300 train
+xosuppaomr 1 298 train
+xotfrdqemv 1 301 train
+xotjbxkxyf 0 300 train
+xotlljxpai 1 300 train
+xotmblspja 1 300 val
+xotvsgyvdg 1 300 train
+xotxccczga 1 300 val
+xoumvznkrv 1 300 train
+xoupnramxr 0 300 val
+xouuqyrdyx 1 300 test
+xouyaqivfy 1 300 val
+xovijtdgus 1 300 train
+xovjybreqq 1 300 train
+xovueqgsvz 1 300 train
+xovvyvzqee 0 300 train
+xovweigifa 1 300 train
+xovzqpxhht 1 300 train
+xowepsvqqi 1 300 train
+xowmjjuavg 0 300 train
+xownsgmhhw 1 300 train
+xowpdtxjbl 1 300 train
+xowwghfppj 1 299 val
+xowyipikeo 1 300 train
+xoxeibxoml 1 298 train
+xoxjzgitfu 1 300 train
+xoxlrbhuda 1 301 train
+xoxnjeqvbx 0 240 train
+xoxrasyyvp 1 302 train
+xoxtmvggfg 1 300 train
+xoxzdogmfx 0 301 train
+xoyiftrygg 1 299 train
+xoyijfhpgo 1 300 train
+xoyjovtkat 1 300 train
+xoykoskcrw 1 300 train
+xoymaorvjw 1 300 train
+xoyqulbhqs 1 300 train
+xoysiuwlbn 1 300 train
+xoywgwfidk 1 300 train
+xoyxgfratq 1 300 train
+xoyxyvfvcr 1 300 val
+xoyyfdrdts 1 300 train
+xoyynavepm 0 300 train
+xozbnihlrg 1 300 train
+xozcfnejlk 1 296 train
+xozfnqukes 1 300 train
+xozhwieaap 1 300 train
+xozpbfqfej 1 303 train
+xozuqzauma 1 301 train
+xozzwaekjl 1 300 train
+xpacrdcxlh 1 299 val
+xpagjcaggq 1 297 train
+xpahczzssc 1 300 train
+xpajeyvltu 1 300 train
+xpamogdpoj 0 300 train
+xpapwfkgdc 1 300 train
+xpatyuhvaq 0 288 train
+xpbbnilrkn 1 300 train
+xpbgrrnxsy 1 300 train
+xpbiboccba 1 301 train
+xpbigmirpz 1 300 train
+xpbqsvdwbg 1 297 val
+xpbrjbstgn 1 300 train
+xpchnctfoo 1 300 train
+xpckfehuoi 1 300 train
+xpcojoxtif 1 288 train
+xpcwhmqqtw 1 300 train
+xpdahpktpy 1 300 train
+xpdcurwcqa 1 300 train
+xpdktunzqf 1 300 train
+xpdlabyztx 1 300 train
+xpdmujbsch 1 300 val
+xpdpybilvg 1 300 train
+xpdqqyrqtb 1 241 train
+xpdtudeepr 1 300 train
+xpduqgrskn 1 300 train
+xpdvjzznhk 1 240 val
+xpdwisawdx 1 300 train
+xpdwqvnafq 0 300 train
+xpealhmykd 1 300 val
+xpecubsuvx 0 288 train
+xpedyhitul 1 300 test
+xpeeotclqn 1 302 train
+xpehzjgxal 0 300 val
+xpeinddjwj 1 300 train
+xpemvlvcqw 0 300 val
+xpeolpzxzb 1 300 train
+xperivyoby 0 300 val
+xpexotnioo 0 300 val
+xpeyuvgcqb 1 300 train
+xpfcvlfcev 1 300 train
+xpfhawmzbe 1 300 train
+xpfjevhfsi 1 300 val
+xpfkegthnu 1 300 val
+xpflsgexnu 1 300 train
+xpfnwshfju 1 300 val
+xpfqsouqpo 1 300 train
+xpfukgkumy 0 300 train
+xpfwswzdgw 1 300 train
+xpgnlphhug 0 300 val
+xpgqfivwtq 1 300 train
+xphdfgmfmz 1 300 test
+xphevwqhye 1 300 train
+xphgqcimqk 1 300 train
+xphgsrhcev 1 300 train
+xpiadxzcdw 1 300 val
+xpifxynebo 1 300 val
+xpiiuvhtpk 1 300 train
+xpipdhbufu 1 302 train
+xpiujdvahv 1 300 train
+xpivslxbup 0 300 val
+xpjdlsjogr 1 300 train
+xpjkanztms 1 300 train
+xpjkuvnuux 1 300 train
+xpjlfmmtza 1 300 train
+xpjoktrsdi 1 300 train
+xpjznusfxk 1 300 train
+xpkcjubxlx 1 300 train
+xpkonnjkzz 1 300 train
+xplbxrdcid 0 301 train
+xplegyuyte 1 300 train
+xplgpliaev 1 300 train
+xplkzxwhfh 1 241 train
+xpllnmqqbv 1 300 train
+xploilhkfz 1 300 val
+xplpkcpsue 1 300 train
+xplqloyqlu 0 300 val
+xplqvmndbo 1 300 train
+xpltavotbe 1 300 val
+xplxzhzeum 0 300 train
+xpmcxuvbqc 0 300 val
+xpmfmmybhh 1 300 train
+xpmowtezpr 0 300 train
+xpmrowpwux 0 300 train
+xpmuqugevj 1 300 train
+xpmwisonoz 1 298 train
+xpndzhodlh 1 300 train
+xpngnapgyx 1 300 train
+xpnmdbjxly 1 301 train
+xpnnkdnmno 1 300 train
+xpnodlbzxu 1 300 train
+xpnqviexvo 1 300 train
+xpntwjlmjt 1 300 train
+xpnwxlkpgz 1 300 train
+xpoagzemfx 1 298 train
+xpogcwyyfr 1 241 train
+xpopeovmlp 1 300 train
+xposltkzgy 1 241 train
+xpottmtghj 1 300 train
+xppimveozp 1 300 train
+xppjdztzpx 1 300 val
+xppjhsqnnm 0 300 val
+xpptbnlvht 1 300 train
+xpptxuppxc 1 300 train
+xpptxuvpqm 1 300 test
+xpqatmhgyr 1 300 train
+xpqeyyrhmn 0 298 train
+xpqgjhxikr 1 300 train
+xpqgzpwins 1 136 train
+xpqjfxfcrz 1 300 train
+xpqlcziqqb 1 299 test
+xpqmyekwch 1 240 train
+xpqnexkjqw 1 300 train
+xprbrzabza 1 300 val
+xprijbqhtf 1 300 train
+xpriokkmhr 1 300 train
+xprwhptmzi 1 300 train
+xprzbzwwbi 1 300 train
+xpscxgktto 1 300 train
+xpsiypjkio 1 300 train
+xpskuqhuam 1 300 train
+xpsngbdpgk 1 300 train
+xpspcxmqqi 0 300 train
+xpsqbbahaq 1 300 train
+xptaevshxi 1 300 train
+xptdlqzrdf 1 300 train
+xptdnihjdr 1 300 train
+xptdonvkbv 0 300 train
+xptgnpgfkn 1 300 train
+xptgvykoji 1 300 val
+xptlhelsxw 1 300 train
+xptqwopxbp 1 301 val
+xptrdoszrj 1 300 train
+xptrgsmuvp 1 300 val
+xpttchstmj 1 300 train
+xpuedlesmz 1 300 train
+xpufyxnfjo 1 298 train
+xpukbfhfed 1 300 test
+xpukeyyqux 1 300 val
+xpukjbdxtp 1 298 train
+xpuleairnz 1 300 train
+xpuntxtdbs 1 300 train
+xpunzwycxm 0 300 val
+xpupubbpmu 1 300 train
+xputpatbat 0 300 train
+xpuwgktquc 1 300 train
+xpvbewtcll 1 299 val
+xpvjuebdop 1 297 train
+xpvmgotokj 1 300 train
+xpvszipktd 1 300 train
+xpvwmnsbfd 1 300 train
+xpvykjcdkh 1 300 val
+xpvykneojm 1 300 train
+xpwazyjdsf 1 300 train
+xpwbafhaap 1 300 train
+xpwemugiot 0 300 train
+xpwimscbue 1 301 train
+xpwnemywhh 1 300 val
+xpwnhqnbin 1 300 train
+xpwsooatyg 1 300 val
+xpwvfmphsx 1 300 val
+xpwxosxopu 1 300 train
+xpwzoebyho 0 300 val
+xpxqxdbjud 0 300 val
+xpxrhbtddy 0 300 train
+xpxrjwwibn 1 300 test
+xpxssnqedu 0 300 train
+xpxvszxmdx 1 299 val
+xpxvudpigc 1 241 train
+xpyabdzqnd 1 300 train
+xpykehjlth 1 297 train
+xpywazpppp 1 300 val
+xpyxqgsqed 1 300 train
+xpzfhhwkwb 1 300 test
+xpzhqbuvkn 1 300 val
+xpzzmesgcg 0 302 train
+xqaadijtwc 1 300 val
+xqaavkxuky 0 301 train
+xqaaykkmvk 1 300 train
+xqacvowqbu 1 298 train
+xqaojmjgxt 1 300 train
+xqaqsfzuxu 1 300 train
+xqaracaoeg 1 300 train
+xqavrcmpfc 0 300 train
+xqbctqmdog 1 300 train
+xqbfwwegaq 1 300 train
+xqbjizvmfu 1 300 train
+xqbqzsyhgo 1 298 train
+xqbxplkddj 1 300 train
+xqbyzltydd 0 300 train
+xqbzivcbcx 1 300 train
+xqckqkmsao 1 300 val
+xqclqvihqo 1 301 val
+xqdeghavlg 1 297 train
+xqdewddcft 1 300 val
+xqdhbuxjjt 1 241 train
+xqdjpdsyhx 1 300 train
+xqdkopasgj 0 300 train
+xqdpvrggxz 1 300 val
+xqdpzhqwet 1 300 train
+xqdwstullw 1 300 train
+xqdyjrybes 1 300 train
+xqeajcymaw 1 300 train
+xqecrwqiai 1 302 train
+xqeinjfzco 1 300 train
+xqejqsmwbl 1 299 val
+xqekoomnwt 1 300 train
+xqemgxhljg 1 300 val
+xqenuhfjkr 0 301 train
+xqenvalont 0 300 train
+xqeoanflfr 1 300 val
+xqeqfogmhc 1 300 train
+xqeuvgclvw 1 300 train
+xqfdjmadkd 1 301 train
+xqfeqamotg 1 300 train
+xqfljmfjui 0 300 val
+xqftrtkzzf 1 300 train
+xqfvnauoid 0 300 train
+xqfzrpzqwy 0 300 train
+xqgdzayldw 1 300 val
+xqgieeldyp 1 300 train
+xqgixbcrrg 1 300 val
+xqgkswtxtv 1 300 train
+xqgpccecnt 1 299 test
+xqgtmxrcbl 1 300 val
+xqgzqqrcnr 1 300 train
+xqhfrphvuf 0 300 train
+xqhktszosc 0 300 val
+xqhlqhuwtc 1 301 train
+xqholsrjce 1 300 train
+xqhoucjinm 1 300 train
+xqhrmefbin 1 301 val
+xqhwinqcxd 0 301 val
+xqhwwhtzdh 1 300 train
+xqidzzgqek 1 300 train
+xqiedklrdk 1 299 train
+xqihocfhlm 1 300 train
+xqissttfoi 1 300 train
+xqitmrsduj 1 300 train
+xqitshdinv 1 300 train
+xqivbjwzdd 1 300 val
+xqjcescgfe 1 300 train
+xqjkzfyhew 0 301 train
+xqjoabeqkl 1 300 val
+xqjsmgwroo 1 300 train
+xqjwwueqrv 0 300 train
+xqkmezrtql 1 300 train
+xqkxidcewm 1 300 train
+xqkymwopbi 1 300 train
+xqldqrsovg 1 300 val
+xqllbxbdzc 0 300 train
+xqlpsvcjey 1 300 train
+xqltdkjisv 1 300 train
+xqltjzqtmm 1 300 val
+xqmbosufux 1 300 train
+xqmlqfzqqi 1 300 train
+xqmnnszgyi 1 300 train
+xqmrrciral 0 300 val
+xqmwbyopbp 0 300 train
+xqncefgrmq 1 300 train
+xqndcrkoie 1 300 train
+xqnfwnaicw 1 300 train
+xqnqyiirwz 1 300 train
+xqnvbrujjo 1 300 train
+xqnykluhws 0 300 train
+xqnyljscap 1 300 train
+xqofjuekpv 1 299 test
+xqogfwlhbn 1 300 train
+xqogxcqzoy 1 300 train
+xqojsfifdt 1 300 val
+xqokmdyjsk 1 298 train
+xqpbazogri 1 294 train
+xqpbgowycq 1 298 train
+xqpbhvyxfi 1 300 train
+xqpbsablhy 1 300 train
+xqpkmgfyhn 1 300 test
+xqpmlnucwn 1 300 train
+xqpuslrtuu 0 300 train
+xqpxdxykem 0 300 val
+xqpxeeurvn 1 300 train
+xqpxxtnryn 0 298 train
+xqpzznwems 0 300 val
+xqqpuhtsbn 1 147 train
+xqquwelybj 1 301 train
+xqqzvrmvre 1 300 train
+xqredxlgze 0 300 train
+xqrlrmaqzz 1 300 val
+xqrxpffkpz 0 300 train
+xqscbrdhsy 1 300 train
+xqsfkikzqg 1 300 train
+xqsivexncg 0 300 val
+xqsiyqmqry 1 300 train
+xqsjkumycq 1 300 train
+xqskvoppky 1 300 train
+xqslrjthjz 1 300 train
+xqsorrluix 1 300 train
+xqtafgpgsz 1 269 train
+xqtddclyqi 1 298 train
+xqtgkjauqu 1 298 train
+xqttxbnlfd 0 300 train
+xqtvigokok 1 300 train
+xqtvoxkifb 1 297 train
+xqtwdempos 0 300 train
+xqtwhgsler 1 300 val
+xqtwofxgip 1 300 val
+xqtyfrcnww 1 300 val
+xqubbhtcad 1 300 train
+xqufgzlnbz 1 300 train
+xqugirraqm 1 300 train
+xqugrvqbgm 1 301 train
+xquioomput 1 240 val
+xquneqfqzl 1 300 train
+xquopmcyhf 1 300 val
+xqupyytwpk 1 300 train
+xqvdxqyvbb 1 300 train
+xqvehrhgaf 0 300 train
+xqvhhcahxn 1 300 train
+xqvovvqxfk 1 300 val
+xqvsqrniqw 0 300 train
+xqvsupjdkb 0 300 train
+xqvvrzaxma 1 300 train
+xqvxxnucbo 1 300 train
+xqvzcbjhea 0 300 train
+xqwgjhoumm 1 299 val
+xqwinjfyqx 1 241 train
+xqwkzocvkm 1 300 train
+xqwqegasjw 1 300 val
+xqwsvfuvui 1 300 train
+xqwtvuwrrt 0 300 train
+xqwurtjzbt 0 300 val
+xqwxgavnjy 1 300 train
+xqwzanxbpb 0 300 train
+xqwzunkulz 1 300 train
+xqwzwtxons 1 301 train
+xqxglqtojb 1 300 val
+xqxmeaetvc 1 300 val
+xqxqrhyhtl 1 300 train
+xqxwxjvtvc 1 300 train
+xqxxekqwuu 1 300 val
+xqxxvrrcnb 1 300 train
+xqyhzrdoie 1 300 train
+xqylqwuwkb 1 300 train
+xqyukofqww 1 300 val
+xqzaybyajw 1 300 train
+xqzdabdmdt 1 300 train
+xqzghgelmy 1 300 train
+xqzoiltqab 1 300 train
+xqzpcunvla 1 300 train
+xqzrwenryk 0 300 train
+xqzrxatnwy 1 241 train
+xqzzghcqsy 1 300 train
+xqzzydzmtq 1 167 train
+xragcjyfqs 1 301 train
+xrahxsyzqw 0 300 train
+xrajozksyi 1 301 train
+xrakuvthyr 1 301 train
+xraljbenwk 0 300 train
+xraopsanrc 1 300 train
+xrastfpkge 1 300 train
+xrayywctjo 1 300 train
+xrbabaiddk 1 300 val
+xrbbqdkqfq 0 300 train
+xrbevgovxw 1 301 train
+xrbguzgtsz 1 300 val
+xrbomeyefg 1 300 test
+xrbqpfmtrn 1 143 train
+xrbrbnkmjc 0 300 train
+xrclmbmjme 1 300 train
+xrcpsgypui 1 300 train
+xrcrofsnly 1 297 val
+xrcsmqiekd 0 300 train
+xrcxzsbidn 1 300 train
+xrcyqsqnhr 1 300 train
+xrdbjgmayg 0 300 train
+xrdfibwovf 1 300 train
+xrdkntysvh 1 300 test
+xrdnhxgfca 1 300 train
+xrdopedqcu 0 300 train
+xrdovfzlzy 1 300 val
+xrdtisplaq 1 300 train
+xrdufokoun 1 300 val
+xrduhzwpsh 0 300 train
+xrdvkjfxxl 1 300 train
+xregtrvzyz 0 300 train
+xrekuqkrdf 1 300 train
+xrenkfjbqa 1 299 test
+xrenrfhsoj 1 300 val
+xretarybyh 1 300 train
+xrexmjcofm 0 300 train
+xrfapxdbic 1 300 train
+xrfffpdqin 1 300 val
+xrffkmqgco 1 270 train
+xrfgnmuiae 1 300 val
+xrfhngvtau 1 300 train
+xrfiicmibx 1 300 train
+xrfkmcazzr 0 300 val
+xrfnloxedr 1 300 train
+xrfnrllgjg 0 300 train
+xrftcfiubs 1 300 val
+xrftrmrgtt 1 300 val
+xrfyssidqn 1 300 val
+xrfzbnlgdr 1 300 train
+xrgbqhhgkf 0 301 val
+xrgbtbohrr 1 300 train
+xrgeoihqkv 1 300 train
+xrgfpjkqex 1 300 train
+xrggrjtdwj 1 301 val
+xrgvnrierh 1 300 train
+xrgwxiqtrw 0 300 val
+xrgxzzrpuw 1 300 train
+xrgympgawc 1 300 train
+xrhbngqlbk 1 300 test
+xrhehxyuyx 1 300 val
+xrhemqpmcs 1 300 val
+xrhhxldmnv 1 300 train
+xrhmzhdlhf 1 300 train
+xrhniwhnfs 1 300 train
+xrhqtmxlvx 0 299 val
+xrhvfgkdwr 0 298 val
+xrhxajxuwq 1 300 train
+xrhyqsctph 1 300 train
+xribbkhadz 0 300 train
+xridozpmnn 1 300 val
+xrimyhzjsi 1 300 train
+xrinweojcy 1 300 train
+xrippfacit 1 298 train
+xriqshfznn 1 241 train
+xrivgtqgyg 1 300 train
+xrjjgtclwo 1 300 train
+xrjkdhwfma 1 300 train
+xrjkhaoaad 1 300 train
+xrjlfoczoh 1 300 train
+xrjnixtgfo 1 301 train
+xrjpyrwgke 1 300 train
+xrjsujvluo 1 300 train
+xrkaosylbg 1 300 train
+xrkdooflmj 1 300 train
+xrkhgjgxmv 1 301 val
+xrkhnrpjdi 1 301 train
+xrkijerqdw 0 300 val
+xrkjjhcevc 1 300 train
+xrkkjudaks 0 300 train
+xrkpufpirm 1 300 train
+xrkvaszxew 1 300 train
+xrlgxodnxe 1 300 val
+xrlpicdrdq 0 300 val
+xrlqkwnoyj 1 300 train
+xrlsnxfsbu 1 298 val
+xrltimmbyc 1 300 test
+xrluvbhiqk 1 300 train
+xrluwubrhs 1 300 train
+xrlviejxmp 0 300 train
+xrlwngzokh 1 300 val
+xrmdfdksga 1 300 train
+xrmhfiahic 1 241 train
+xrmkmjxwdd 1 300 val
+xrmqroypln 1 300 train
+xrmslnoqku 1 300 val
+xrmszmqflp 1 300 train
+xrmtpqwgfi 1 300 val
+xrmtrnbgbi 1 301 val
+xrnbajzoii 1 147 train
+xrnbnmufgy 1 249 train
+xrnclcwwid 1 300 train
+xrnjghfbcq 1 300 train
+xrnqbsulyo 1 300 train
+xrnrtmxfad 0 300 train
+xrnwzutccp 1 300 train
+xrnxekclfx 1 300 train
+xrnzgyudyo 1 300 train
+xrodjwoies 1 301 train
+xrodqpeitc 1 301 train
+xroeioxsdr 1 300 train
+xrohejiedw 1 300 train
+xroherivlw 1 301 train
+xrojnupaaz 1 300 train
+xrokehvngb 1 300 train
+xrokphyoub 1 300 train
+xromptqmqk 1 300 train
+xromylidmb 1 301 train
+xroslebnzu 0 300 train
+xrovlcnlaw 1 300 train
+xrpbhqdxvq 1 301 train
+xrpftmsngf 1 300 train
+xrpkwdgzxu 0 300 train
+xrppjccxur 1 300 train
+xrptgxzcry 0 300 train
+xrputznjht 1 299 val
+xrqdltsqry 1 300 train
+xrqdorruiu 1 300 train
+xrqfwykmhw 1 300 train
+xrqhflacsg 1 300 val
+xrqqjfjrxu 1 300 train
+xrqrhtyrgz 0 300 train
+xrqrvoniyr 1 300 val
+xrqstavwjd 1 300 val
+xrrjwghkqw 1 300 train
+xrrrawsepu 1 300 train
+xrrvtyoxaz 1 300 val
+xrrzdkymek 1 298 train
+xrsbogvdne 0 301 train
+xrsfxvgqoa 1 300 train
+xrskkplkuv 1 300 train
+xrsugukwwr 1 300 train
+xrsxkkqxzw 0 300 train
+xrszwfhufn 1 300 train
+xrtculndez 1 288 train
+xrtenpoayf 0 300 train
+xrtkqyeffn 1 300 train
+xrtmepdfyh 0 300 val
+xrttfzjtka 1 300 train
+xrtufflsto 1 300 val
+xrtvpgzddg 1 300 train
+xrtvqhdibb 1 300 test
+xrtvtthfec 1 300 test
+xrtzmjrnvm 1 300 train
+xrucdboqpi 1 300 train
+xrudhupvsr 1 300 train
+xrudpzhmpb 1 300 val
+xruftugyqh 1 300 train
+xrugmaiubc 0 300 train
+xrukafgmhy 1 300 train
+xrunfssynq 1 300 train
+xruskcsekd 1 301 val
+xrutmgrmcq 0 300 train
+xruvxetnpc 1 300 train
+xrvdyliuux 1 298 train
+xrvemlykui 1 300 train
+xrvhhztdme 1 300 train
+xrvhpdvjaw 1 300 train
+xrvljjnfrr 1 300 train
+xrvuqulgdg 1 301 val
+xrvzrlswst 1 301 train
+xrwcylsgrb 1 297 train
+xrwgfbqwin 0 300 train
+xrwipvuhle 1 300 train
+xrwygdsykq 1 300 train
+xrxgertlxp 1 300 train
+xrxizzwyxk 1 299 test
+xrxkowksns 1 302 val
+xrxmjaapgj 1 300 train
+xrxphmnsui 1 300 val
+xrxurudwng 1 300 train
+xrxwcevksd 1 300 train
+xrxzalqmrz 0 300 val
+xrykpuoaxo 1 239 train
+xrylavznmk 1 300 train
+xryocqnyji 0 300 val
+xryoimscsg 1 300 val
+xryrhuskyd 1 300 train
+xrzgsezrik 1 300 val
+xrzhrmsqty 0 300 train
+xrzljewfzf 1 300 val
+xrzobanxmp 1 300 train
+xrzolkhdgx 1 300 train
+xrzvdhuwsl 1 300 train
+xrzwucnsmg 1 300 train
+xrzzlibqwi 1 301 train
+xrzzoboflf 0 300 val
+xsaabhampx 1 300 val
+xsaclnvjcu 1 300 train
+xsaehkqsxs 1 300 train
+xsagzcpxac 1 300 val
+xsanbrdgbi 1 298 val
+xsaqcorfgp 1 300 train
+xsauiuyqvq 1 299 val
+xsaxqyatqb 1 298 train
+xsbancuxvm 1 300 train
+xsbdwnhhvz 1 298 train
+xsbewmpvka 1 300 val
+xsbmrzdocj 1 300 train
+xsbujsrrzn 1 300 train
+xsbvtbycws 1 300 val
+xsbzlovkyp 1 300 train
+xscbuewezk 1 300 val
+xscdjswpeu 1 300 train
+xscekehtlf 1 300 val
+xsceojrydk 1 300 train
+xscjpladjx 1 302 val
+xscmciwbtw 1 300 train
+xscmmhinzu 1 300 train
+xscsjnesyj 1 300 train
+xscuywobdn 1 300 train
+xscyinomby 1 300 train
+xsdalwwoqy 1 300 train
+xsdcxpmuhx 1 300 train
+xsdifiwaqq 1 300 train
+xsdqbzvhgp 1 300 train
+xsdqnsoenk 1 300 train
+xsdrtwhpix 1 300 train
+xsdtlhcnhk 1 300 val
+xsdudxmpfl 1 300 val
+xsdvbjvnah 1 300 train
+xsdxgpilpn 1 300 train
+xsecnogalr 1 300 train
+xsehaxnstq 1 300 train
+xseppojysh 1 300 train
+xseulyzyer 1 300 train
+xsewirjdmr 1 300 train
+xsezahtyhg 1 300 train
+xsezhcgzax 1 300 train
+xsezychbeb 1 301 train
+xsfihvecjw 1 300 val
+xsfjhxaosa 1 300 val
+xsfrsnicrp 1 300 train
+xsfvtcotaq 0 300 train
+xsgagfxetg 1 300 train
+xsgizxkxyp 1 300 train
+xsgmwwbeib 0 300 val
+xsgqyokzbe 0 300 train
+xsgrpepuvb 1 300 train
+xsgtujbpuw 1 300 train
+xsgtxfbwte 1 300 val
+xsgyoyzxqe 0 302 train
+xshednuzab 1 297 train
+xshegwwwqt 1 300 train
+xshgcpanax 1 300 train
+xshixmrxot 1 300 val
+xshkouonsr 1 300 train
+xshneksxuk 1 300 val
+xshsmrimaq 1 298 val
+xshuzthonp 1 300 val
+xsibczsnbr 1 300 train
+xsingdtive 1 300 train
+xsiulnntaf 1 301 train
+xsixsnzucg 0 300 train
+xsjsncykyt 1 300 val
+xsjvpvpaib 1 300 train
+xskbzajhqh 0 300 train
+xskcfkfjun 0 300 val
+xskhrrifym 1 300 val
+xskmajvpjg 1 300 val
+xskmpedclu 1 300 train
+xskoraeagh 0 300 train
+xskrrsokrd 1 301 train
+xskwykhqwd 0 300 train
+xslaiedvgv 0 300 train
+xslfncykid 1 300 val
+xslfvjzdru 1 298 train
+xslgptuism 0 300 val
+xsligcuwcc 1 300 train
+xsljppzuip 1 300 val
+xslmoyvgey 1 300 train
+xslxboadvn 1 300 train
+xsmdxtkdjb 1 300 train
+xsmfwucyne 1 300 train
+xsmgcxehef 0 300 train
+xsmmbecbxo 1 300 train
+xsmnjjnykd 1 300 train
+xsmrbdbyyj 1 300 train
+xsmszmxgou 1 301 train
+xsmtrfrxin 1 297 train
+xsmxbtaeuw 1 300 val
+xsnancjurw 1 300 val
+xsngbnywdr 1 300 val
+xsnhxcsxpv 1 240 val
+xsnlyihyxu 1 300 train
+xsnnqhhdto 1 299 val
+xsnqmsivxr 1 300 test
+xsnxydbhjj 1 167 train
+xsnxzswags 1 300 train
+xsnztoaagz 1 300 train
+xsoaeigpft 1 300 train
+xsomqcwyil 1 300 val
+xsotnvclnm 1 300 train
+xsperbvguc 1 300 val
+xspievylvf 1 300 train
+xspleqigrq 1 301 train
+xsplikqcsv 1 143 train
+xsplzlkske 1 300 train
+xspnxeyque 1 300 train
+xspwbaarsu 0 300 train
+xspwwcpoig 1 300 val
+xspyysfmdj 0 300 train
+xsqazrqgah 1 300 train
+xsqhcxoncs 1 300 train
+xsqqubzyip 1 301 train
+xsqvafllyp 1 300 train
+xsqzctwhge 1 299 test
+xsrbccytqi 1 300 train
+xsrdbogsuu 1 300 train
+xsrgwipdqk 1 300 train
+xsrjvybnrx 1 300 train
+xsrkbvofrk 1 300 train
+xsrmsrzfpz 1 300 train
+xsrqmyfyrw 0 300 val
+xsrrkijyqa 0 301 train
+xsrydslifk 1 300 val
+xsrzauxxbf 1 301 val
+xssddhiocz 1 241 train
+xsseowifxw 1 300 train
+xssesbrdia 1 300 train
+xssjsyismu 1 300 train
+xssljajlck 1 301 train
+xssoioxpdm 1 300 val
+xssuxipwtu 1 300 test
+xsswirhdze 1 299 test
+xstcizsctw 0 300 val
+xstcnbsmnn 0 300 val
+xstdxkoany 1 300 val
+xstgkuqelq 1 300 train
+xstgslmoeu 1 300 val
+xstkngzhta 0 300 train
+xstoeihzvf 0 300 train
+xstohwjyji 1 300 train
+xstvzbvjsq 1 300 val
+xsufntvtoi 1 300 train
+xsusyzmwcg 1 300 train
+xsuthzpywj 1 300 train
+xsuyadjtfd 1 298 train
+xsvfjvptex 1 300 train
+xsvgeqvpdw 1 300 train
+xsvjmljxcb 1 300 train
+xsvuirlzfv 1 300 train
+xswcuzezrm 1 300 train
+xswdwufkyy 1 300 train
+xswjhgttlk 1 300 train
+xswunnlswz 1 300 train
+xswuriaalw 1 301 train
+xswwteswgt 1 300 train
+xsxbdrtvmp 1 300 train
+xsxcdnkdjb 0 300 train
+xsxdnmzawz 0 300 val
+xsxseyabhw 1 300 train
+xsxsspavof 1 300 val
+xsxwrwvfkg 0 300 train
+xsxwvqqbxq 1 300 train
+xsyhjoyulw 1 300 val
+xsypntxmpl 1 300 train
+xsyrejaslm 1 300 train
+xsyvjzbniq 1 300 train
+xszbsanhdu 1 300 train
+xszdfdwjzg 1 302 train
+xszeyiyutv 1 298 train
+xszhbfwajj 1 300 val
+xsznmjtqji 1 298 val
+xszpbtciwo 1 300 train
+xszsemeklp 1 300 test
+xsztearkpt 1 300 train
+xszusbrbgm 1 300 train
+xszwbxrtgc 1 300 val
+xszzixgenz 1 300 val
+xtaazwyess 1 300 train
+xtajlsgrvl 1 300 val
+xtaktzlrme 1 300 test
+xtauuysynl 1 300 val
+xtazywaafq 1 300 train
+xtblofiosv 1 300 train
+xtbnshcyyx 1 300 train
+xtbtfyfrtm 1 300 val
+xtcbnasaew 1 300 train
+xtcghfmcyr 1 300 train
+xtcmgcsuox 1 300 train
+xtcpfsukph 1 300 train
+xtcpqogdoh 0 300 val
+xtcqjzneht 1 300 train
+xtcrtfllbc 1 300 train
+xtcwyjmlbb 1 300 val
+xtddrizgoy 1 300 train
+xtdobataon 1 300 train
+xtdwmoyzvc 1 301 train
+xtegzrbvaz 1 300 val
+xtehadqndf 0 300 train
+xteogoxndl 1 300 train
+xtequyjssk 1 300 test
+xteseowsud 1 300 train
+xtevltafix 1 300 test
+xtewtsxdir 1 300 train
+xtfbhqexdu 1 300 train
+xtfctaiohv 1 300 train
+xtfsmcbbez 1 300 train
+xtftapqcmv 0 300 val
+xtgabawtuc 1 300 train
+xtgbwerrgv 1 300 train
+xtggctsflw 1 301 val
+xtgsnqtfjo 1 299 train
+xtgzbxmvvq 1 300 train
+xthfgogasl 1 300 train
+xthifkignl 0 300 train
+xthmmlxwzf 1 300 train
+xthnqitrhg 1 300 train
+xthobrrdnn 0 300 train
+xthorjahhh 1 300 train
+xthphgryzk 1 300 train
+xthvewmjxj 0 300 train
+xticvyqqjn 1 300 train
+xtihopzbsx 0 300 train
+xtiiaxvjuq 1 300 train
+xtiithplqj 1 300 train
+xtilkqiiup 1 300 val
+xtilpnkmug 1 300 val
+xtirlofavu 1 300 train
+xtitfpjuri 1 300 train
+xtivswsqyo 1 301 train
+xtixietgjp 0 300 train
+xtjbeenzqv 1 300 train
+xtjggebvph 1 300 train
+xtjgibhzvs 1 300 val
+xtjgzcumvj 0 270 train
+xtjlyrfjzx 1 300 val
+xtjmopnuwh 1 300 val
+xtjpdshefz 1 300 train
+xtjxviqexo 1 300 train
+xtkehdbbca 1 300 val
+xtkfgqkdgn 1 300 val
+xtklrqzbov 0 300 val
+xtldzbntvd 1 300 train
+xtlmqgvjow 1 300 train
+xtlreouywq 1 300 train
+xtlyjdbtwo 1 301 val
+xtmbtcaeuy 1 300 train
+xtmefzrqej 1 301 val
+xtmpucrjkq 1 300 train
+xtmqtphjxb 1 297 train
+xtmsrzuidr 1 300 train
+xtmtrntyrl 1 302 train
+xtmycsvhkf 1 300 train
+xtnamlkyfx 1 297 train
+xtnaqvfklu 1 300 val
+xtnfeuxmbc 1 301 train
+xtnhzowrxi 1 300 train
+xtnjquqneo 1 300 train
+xtnlcgvvrq 1 300 train
+xtnsmeopnl 0 300 train
+xtnsydjuqs 1 300 test
+xtofwfuumy 1 302 train
+xtohlpjxcs 1 300 val
+xtohsezbek 1 300 train
+xtorjfunwo 1 298 train
+xtosspfrfz 1 300 train
+xtotbukren 1 300 train
+xtouptjifb 1 300 train
+xtovzqbqld 1 300 val
+xtoxvosuzj 1 300 train
+xtozgnrgsd 1 300 train
+xtpeexhiph 1 300 val
+xtpeiaipyn 1 300 train
+xtpeyyltfi 0 300 val
+xtpfnofcbp 1 300 val
+xtphzpptxc 1 300 train
+xtpjsqbxmd 0 300 train
+xtpjtmsydd 1 299 val
+xtpkcflemy 1 300 train
+xtplbpicos 1 300 train
+xtplqfcbxk 1 300 train
+xtpypmnndt 1 300 val
+xtqawgbgww 1 300 val
+xtqgkyigrd 1 300 train
+xtqjlqgjrv 1 300 train
+xtqrieogyh 1 300 train
+xtqtagfyug 1 300 train
+xtqythayks 1 300 train
+xtratvysew 1 300 train
+xtrdtctmuo 0 300 train
+xtrfzzbuim 1 300 val
+xtrhwvmlry 1 299 train
+xtrjgjrryt 1 300 train
+xtrlntlawm 1 300 val
+xtrqhxskgr 0 300 val
+xtsbmbmllo 1 300 train
+xtsddxqimp 1 300 train
+xtshbkixzi 1 300 val
+xtsneapeqv 1 300 train
+xtsuqkbzxi 1 300 train
+xtsvnajzhf 1 300 train
+xtsvrqyzdv 1 300 test
+xtsykcxqbx 1 300 train
+xttbiehjdf 1 300 train
+xttdkfsiti 0 300 train
+xttegbpxdh 1 298 train
+xttglwcspr 1 300 train
+xttqggwaze 1 299 train
+xttqyzudoa 1 300 train
+xttvxgcpgc 1 300 val
+xttwbloiwj 0 300 train
+xttwhovagj 1 300 train
+xtubeumopg 1 300 val
+xtuegdtimc 1 300 train
+xtugoihhbm 1 300 test
+xtugrytxgq 0 300 train
+xtupkgvyim 1 300 val
+xtupmazgyv 0 300 train
+xtuquxoxft 1 300 train
+xtuqxfiwbn 1 300 train
+xtutdkkhva 1 300 val
+xtutjndgjm 1 300 train
+xtuupoodnw 1 300 train
+xtuyrjwavb 1 300 train
+xtvcfygweu 0 300 train
+xtvcisrxob 1 301 train
+xtvdwgtogy 1 300 train
+xtvyjezbdc 1 300 train
+xtvzihfzmt 1 300 val
+xtwqxgmlar 1 147 train
+xtwrzitqhn 1 300 train
+xtxederbsv 1 300 train
+xtxpokrqgz 1 300 train
+xtxqeagsxn 1 300 train
+xtxqroiohw 1 300 train
+xtxsografg 1 300 train
+xtxtdbiaud 1 300 train
+xtxthqcdhp 1 300 train
+xtxvehejup 1 300 train
+xtxxpbobhl 1 300 train
+xtxyguekjk 1 297 train
+xtxzangzji 1 300 val
+xtyalmuivq 0 300 train
+xtyldfhpth 1 300 train
+xtyszkpnyn 1 300 train
+xtzbukvobk 0 300 train
+xtzeudeznu 1 300 train
+xtzfnjvnwa 1 300 train
+xtzfqngkwu 1 300 train
+xtzqtgfucc 0 300 train
+xtzrubsyub 1 300 train
+xtzwerusjx 1 300 train
+xuabvfaspj 1 299 val
+xuaettqvfk 1 301 train
+xuajnffpqo 1 300 train
+xuajtwfpwd 1 300 val
+xuaugakbyx 1 300 val
+xubgdudrva 1 300 val
+xubhwxipoy 1 300 train
+xubnvgxuou 1 300 train
+xubpgqwzkr 1 300 train
+xubqriqwbk 1 300 train
+xubvwqksfr 1 300 train
+xubykcmhqv 1 300 train
+xucbeymshb 1 301 train
+xucexvfcij 1 298 val
+xuchqsqkup 1 300 val
+xuchsnnyra 1 300 train
+xuchywaqck 1 300 train
+xucnojxahm 1 301 val
+xucpzwjtne 1 300 val
+xucqibgwmq 1 301 train
+xucqmtigax 1 300 val
+xucswxwmpm 1 300 train
+xucymkatbz 1 300 train
+xudfzxngou 1 296 train
+xudpvdezft 1 300 val
+xudsfjedcx 1 241 train
+xudthxgqhr 1 299 test
+xuebwehxdr 1 300 train
+xueiaudupv 0 300 train
+xuelsqpflp 0 300 train
+xuewijpxwo 1 300 train
+xuezegrjfg 1 300 val
+xufrmpwmgq 1 300 train
+xufrnqgysj 1 296 val
+xufyybetre 1 300 val
+xugassdpfc 1 301 val
+xugbywbvgv 0 300 train
+xugenbxalr 1 298 train
+xugfcnepbm 1 299 train
+xugflrdauw 1 300 train
+xugictrqww 1 300 train
+xugjmemyne 1 298 val
+xugmhbetrw 0 300 test
+xugnmurffo 0 300 train
+xugohglukx 1 301 train
+xugpdvjicd 1 300 train
+xugrceeldg 0 300 train
+xugsuqkeox 1 300 train
+xuhcvxtzxd 0 125 val
+xuhkgzaztc 1 300 train
+xuhluqilnn 1 300 val
+xuhlytwhkb 1 300 train
+xuijoprhoc 1 301 val
+xuiqfvasci 1 300 train
+xuismtvfgk 1 300 train
+xuixlwwlrv 1 301 train
+xujbhvdrlx 1 601 train
+xujfscqrzg 1 300 train
+xujgsolgcq 1 300 train
+xujlxeunfr 1 300 train
+xujnfkipkz 1 300 train
+xujnzhgnzk 1 300 val
+xujqzzadbx 1 136 train
+xujweiwwke 1 297 val
+xujybryjmp 1 300 train
+xukqnojifb 1 302 train
+xukuexrqqt 1 300 train
+xukvzaurgn 1 300 val
+xukwfyprsa 0 300 train
+xukyofsjzl 0 300 val
+xuldmmzgci 0 300 train
+xulearbmde 1 300 train
+xulgulyvaq 1 300 val
+xulgzxjidw 1 300 train
+xulikllhro 1 300 train
+xulrfoyvjm 1 300 train
+xulrnoafmb 1 300 train
+xulrqfqbhi 1 301 train
+xulyukymrz 0 300 train
+xulzcoybqe 1 300 train
+xumdemvmqz 1 300 train
+xumfkgpdfv 1 300 train
+xumgnmzseo 1 300 test
+xumhfwesvw 1 300 train
+xumhhfwytr 0 300 train
+xumpnyjszu 1 300 val
+xumrrieufz 0 300 train
+xumsdjtsoq 1 299 val
+xumudadztd 1 300 train
+xumufxeamd 0 300 val
+xumvmlvqdj 1 300 train
+xumwlvuxym 1 300 train
+xumyjngjgs 1 300 train
+xumyrneznp 1 300 train
+xumzhxofkw 1 299 train
+xundigwfsk 0 300 train
+xungeudcsl 1 300 train
+xunxsjbvxa 1 300 train
+xunzowwleo 1 288 train
+xuohixzbju 1 300 train
+xuoiogtjmp 1 300 train
+xuolsyrgaw 1 300 train
+xuopnqdjhl 1 300 train
+xuoqfchsfj 1 299 train
+xuoszxecos 1 300 train
+xuoxhdtfkl 1 300 val
+xupaelklwc 1 300 train
+xupeekvvrj 0 300 train
+xuphssebxb 1 300 train
+xupjoqnhiy 1 300 train
+xuplbedsry 1 300 train
+xupmuivfmr 1 300 train
+xupnjjriof 1 241 train
+xupoewxoni 1 298 val
+xupovjjbfl 1 300 train
+xupquzffji 1 300 val
+xupypigymh 1 300 train
+xuqbgnabmy 1 300 train
+xuqczjkmwa 1 300 train
+xuqdqbszdr 1 300 train
+xuqfvpgytw 0 300 train
+xuqnnutplm 1 300 val
+xuqqagbesg 1 298 val
+xurghevfhl 1 300 val
+xurhczlfps 1 300 train
+xurmyveihi 1 300 train
+xurntpvfma 1 301 train
+xurxhvbawi 1 301 train
+xuscbdvlnn 1 298 train
+xusitrtnnq 1 300 train
+xusmhslwfm 1 300 train
+xusrbdngnt 1 301 train
+xustjewkxy 1 300 train
+xuszvuvabr 1 300 val
+xutjbcibdm 1 300 train
+xutjriqmyn 1 300 train
+xutollfhnl 1 301 val
+xutoojasri 1 302 train
+xutzudyhsp 1 300 test
+xuuffhtfbs 1 241 train
+xuuhkjkowc 1 300 train
+xuulhovajk 1 300 val
+xuumilkydb 1 300 train
+xuundwbviz 0 241 val
+xuutmrrlle 1 300 train
+xuutqiitvu 1 300 val
+xuuydvytqf 1 300 train
+xuuzfmdqyk 1 300 train
+xuvbuzhblf 1 300 train
+xuvjbhkfqu 0 300 val
+xuvvcgjllv 1 241 train
+xuvvjiwuay 1 300 train
+xuvwdyuhuz 1 300 train
+xuwcmlevkh 1 300 train
+xuwifatrwx 1 300 train
+xuwkeitvlr 1 300 train
+xuwmdtanya 1 300 train
+xuwnqxoxju 0 300 train
+xuwouqlgce 1 300 val
+xuwtvhjzik 1 300 train
+xuwvglszoz 1 300 train
+xuwvttrixt 1 300 val
+xuwzwgmuvo 1 300 train
+xuxcsgzbcq 1 300 train
+xuxdcvjnor 1 300 train
+xuxhyuyroq 0 300 train
+xuxikyfxru 1 300 train
+xuxiuacwuy 0 300 val
+xuxkfhqjiu 0 300 train
+xuxtuueash 1 299 val
+xuxtwkozvd 1 300 train
+xuyiufkpsk 1 300 train
+xuymlytqyc 1 297 train
+xuympcmldg 1 300 val
+xuyovmzsza 1 300 train
+xuyxyxifgy 1 297 train
+xuzgdtbtke 1 300 val
+xuzkaasfwx 1 300 val
+xuzmlnadbw 1 300 train
+xuztiyokuz 1 300 train
+xvaacqjaso 0 300 train
+xvabqehegx 1 298 val
+xvakdzxakw 1 300 val
+xvakloixhr 1 300 train
+xvamwuhciu 1 300 val
+xvapotlvyf 1 299 val
+xvaqeccmwf 1 300 train
+xvblyagblw 1 300 val
+xvbzdpsegk 0 300 train
+xvcidcnvdj 1 300 train
+xvckxvgqes 1 298 train
+xvcnflbyyg 1 240 train
+xvcprvexrx 1 241 train
+xvcslfhzqo 1 297 train
+xvctscyglo 1 300 train
+xvcuihzdpb 1 300 train
+xvdcmkmqvn 1 300 val
+xvdhisdfhw 1 300 train
+xvdvvfnbfu 1 300 train
+xveensywhc 1 300 val
+xveixsoikz 1 300 val
+xveizltxsf 1 300 train
+xvemlxvlzr 1 300 train
+xvenxcxqzk 1 300 train
+xveopvfelk 1 300 train
+xveotgmpbh 1 301 val
+xvesyhowdk 1 300 train
+xvetzramez 1 300 train
+xvfghbnncz 1 300 train
+xvfldlnhkr 1 300 train
+xvfnzabgwi 1 300 train
+xvfoemfrie 1 300 train
+xvfpfystld 1 301 train
+xvfwhspzvb 1 301 train
+xvfyyvxblp 1 300 train
+xvgcmftnlo 1 300 train
+xvgcrjvgdu 1 300 train
+xvgezlhthq 1 300 train
+xvggyxiuhf 1 300 train
+xvgkojxxwd 1 300 train
+xvgqnqfcrx 0 300 train
+xvgxpwkyng 1 300 train
+xvhauplfag 1 300 train
+xvhdtwzild 0 300 train
+xvhfwanjnb 1 298 train
+xvhqpznppn 1 300 train
+xvidsulroh 1 300 train
+xvifpjctlf 1 300 train
+xvigyhtchd 1 249 train
+xviqackyjy 1 300 train
+xviukwksny 1 301 val
+xvjhjsprln 0 300 val
+xvjjxhjqka 1 241 train
+xvjvxlmjth 1 300 train
+xvjwqniyaq 0 300 val
+xvkcbphklp 0 300 train
+xvkccnehrk 1 300 train
+xvkgurhkig 1 300 train
+xvkniaxffb 1 300 train
+xvkwijqxvg 0 300 train
+xvldbpnjcv 1 300 train
+xvlfzehxhw 0 300 train
+xvlkrfyggv 1 300 train
+xvlmrxxjix 1 300 train
+xvluedgpge 1 300 train
+xvlxjhclws 0 300 train
+xvlyaqmhlq 1 300 train
+xvmgaarifs 1 300 train
+xvmqbqczbc 1 300 train
+xvmqzlpchb 1 302 train
+xvmtnkfuwx 1 300 train
+xvmtxnclli 1 301 train
+xvmwxpwtgf 0 300 train
+xvmxlukwil 1 300 train
+xvncdmcdlv 1 300 train
+xvndasydxv 1 300 train
+xvnlxvfcgs 1 300 train
+xvnqwfsabe 1 301 train
+xvnrqylzvf 1 300 val
+xvnsrbedle 1 300 train
+xvnxmelhkw 1 300 train
+xvnxwemnyx 1 300 train
+xvnztwkpnw 1 300 train
+xvoghshkwe 1 300 train
+xvojwtymba 1 300 train
+xvoskzqprq 1 300 train
+xvoslmyksa 1 299 test
+xvouxvukwr 1 300 val
+xvoyxlhqmd 1 300 train
+xvpvmthkpe 1 298 val
+xvpyayjsmf 1 300 train
+xvpywnxxuv 1 300 train
+xvqcwbhkde 1 300 train
+xvqfkmsyze 1 300 val
+xvqiloxtuo 1 298 train
+xvqpycctmf 1 300 train
+xvqqlmmtsh 1 301 train
+xvqsgqztro 1 300 train
+xvqvyrijin 1 300 val
+xvqwcdibgj 1 300 train
+xvqxiqlftx 1 300 train
+xvqyzejpfh 1 240 train
+xvqzzgoabm 1 300 train
+xvrabiupoy 0 301 train
+xvrabtkamk 1 300 val
+xvreklxokj 0 300 val
+xvrgebjjsm 1 300 train
+xvririjiuv 1 300 val
+xvrlmamzup 1 300 train
+xvrmugrctg 1 299 val
+xvscpvkflu 1 300 train
+xvscslotco 1 300 train
+xvsdxyhyrc 1 300 train
+xvslnmfinj 1 300 train
+xvslzohiei 0 300 train
+xvsngnerhu 1 300 train
+xvstfiiybt 1 300 val
+xvtefxkqih 1 299 train
+xvtehhsybk 1 300 train
+xvtgxgoepk 1 300 train
+xvtyicoatv 1 300 train
+xvtztnhjwb 1 299 test
+xvugcoyoyt 1 300 train
+xvuiacvuyd 1 300 train
+xvunatyuye 1 300 train
+xvupaxhgwv 1 300 train
+xvusgcwqfd 1 300 val
+xvuvlqhtix 1 300 train
+xvuvvcgzpj 1 300 train
+xvuwpdjtpn 0 300 train
+xvuxxbivjx 1 300 val
+xvvfflofln 1 300 train
+xvvgtomjas 1 300 train
+xvvitwdlzi 1 300 train
+xvvrtjtism 0 136 train
+xvvwqmaoej 1 300 train
+xvvwtyxmtn 1 300 train
+xvwanoabil 1 300 train
+xvwbtrlokn 1 300 test
+xvwsffzsfm 1 300 train
+xvwzcguypx 1 296 train
+xvxgrfuuia 1 300 val
+xvxhxmbopd 1 300 train
+xvxiadagpc 0 300 train
+xvxlzlmlrn 1 300 train
+xvxyivgiky 1 300 test
+xvykrmxyuk 1 300 train
+xvykxozqpq 0 300 train
+xvylbtekqe 1 300 train
+xvymkpbfno 1 300 train
+xvympxyxau 1 300 train
+xvymrfmjzo 1 300 train
+xvyvvrqcme 1 301 train
+xvywercizr 1 300 train
+xvyyenfcdi 1 300 val
+xvzbvktqdj 1 300 train
+xvzgnwwajx 1 300 train
+xvzjzkrmlm 1 300 test
+xvzoepsnyv 1 300 train
+xvzqkmwxlv 1 300 train
+xvzsbxrlxq 1 298 train
+xvzwwkbkav 0 301 val
+xvzzozpbvi 1 300 train
+xwaecjesje 1 300 train
+xwagwrvaqc 1 300 train
+xwahjbjnyy 1 300 train
+xwattbryrz 1 300 train
+xwbeomswvv 1 300 val
+xwbfbueegy 1 300 val
+xwbjtlqxeo 0 301 train
+xwboqimxxs 0 300 train
+xwbussrpzh 0 300 train
+xwbzxptaun 1 296 train
+xwcggrygwl 0 300 train
+xwchjncolr 1 298 train
+xwckqhyahy 1 300 train
+xwdcuffwni 1 300 train
+xwdeeuchcy 1 300 train
+xwdhebuuhi 1 300 train
+xwdjuretoc 0 300 train
+xwdsllovij 1 300 val
+xwdspcjets 1 300 val
+xwegsyeocv 1 249 train
+xwemukdrzt 1 300 train
+xweqknwojv 1 301 train
+xwesosgpcc 1 300 train
+xwfbotxcrr 1 300 train
+xwfbvbevtu 1 300 val
+xwfdpmfwpz 1 300 train
+xwfeczcqcr 1 300 train
+xwfknogydf 1 300 train
+xwfmedrwfu 1 300 val
+xwfnqncjqc 1 300 test
+xwfnwfhknb 1 300 val
+xwfreolkib 1 300 val
+xwftzpjzdy 1 300 val
+xwfwyzzxhs 0 301 train
+xwgccilzho 1 300 train
+xwghgkidmx 1 300 train
+xwgkejeduu 1 300 val
+xwgnmpcuav 1 300 train
+xwgqgubgmj 1 300 train
+xwgvhytknz 1 300 train
+xwgwoyzdva 1 300 train
+xwgwwbwtev 1 300 val
+xwhchxhrdq 1 300 train
+xwhgihnrtm 1 300 val
+xwhgkmottx 1 300 train
+xwhjeyzqbw 1 300 train
+xwhscarivu 1 301 val
+xwhszsfuqf 1 301 train
+xwhuapurws 1 300 train
+xwhxqkqezg 1 301 train
+xwhzvvhkhw 0 301 train
+xwhzwokdxw 1 300 train
+xwigfqjjku 1 300 train
+xwisbvfvfu 1 300 train
+xwiucgsycp 1 300 train
+xwizkaonkl 1 300 train
+xwizwjdjdw 0 300 train
+xwjitvhxqc 1 300 val
+xwjnbakaek 1 300 train
+xwjnrlfdsm 1 300 train
+xwjskqwwuz 1 300 train
+xwjuibxkky 1 300 train
+xwkbyrubjw 1 269 train
+xwkghzywfy 1 298 val
+xwkmqehfeg 1 300 train
+xwkqdyyypi 0 300 val
+xwkqieflch 1 300 train
+xwkqtufgev 1 300 train
+xwkuyuvpns 1 298 train
+xwlabafuhh 1 300 train
+xwlbpsyndf 1 300 val
+xwlhzlxarl 1 300 val
+xwlwgvujnz 1 300 test
+xwlwinfdco 1 300 train
+xwlyopymbw 1 300 train
+xwlzdyspbv 1 300 train
+xwmjwzygbn 1 300 train
+xwmpuddams 1 300 train
+xwmpxujbso 1 300 val
+xwmrrppsml 1 300 val
+xwmyogjeaj 1 300 train
+xwnamdbolx 1 300 val
+xwndyovxel 1 300 test
+xwnexwrhwc 1 297 train
+xwnkmcgadl 1 300 val
+xwnkzsgnqc 1 300 train
+xwnmynmnrt 1 300 val
+xwnrkzuafj 1 300 train
+xwnszofzzt 0 300 val
+xwnttzojvs 1 300 train
+xwoatawzvo 0 300 train
+xwojylnwtl 1 300 train
+xwokqgizgw 1 302 val
+xwolztajgo 1 301 val
+xwomeqanfv 0 300 val
+xwotyajtkq 1 300 test
+xwowkhmhwg 1 301 train
+xwowltanwe 1 300 train
+xwozmutfvs 1 300 train
+xwpbfuyxxd 1 300 train
+xwpcgrdpqy 1 300 train
+xwpcimjyuz 1 301 train
+xwpgvnpswk 1 300 train
+xwpmeyrfkc 0 300 train
+xwpmvvaisl 1 300 val
+xwpoyyikpo 1 300 train
+xwppnelcde 1 300 train
+xwpqsjdzts 1 300 train
+xwprlgakrl 1 300 train
+xwptlhziyb 1 298 train
+xwqhkhaoyr 1 300 train
+xwqlnwxsua 1 300 train
+xwqosjsyjf 1 301 train
+xwqucxeryw 1 299 test
+xwqwopuuuy 1 300 train
+xwqyzljkrq 1 300 train
+xwqztfpxtp 0 300 train
+xwrercqtfk 0 300 train
+xwroyfpdjz 1 300 train
+xwrqwazdpf 0 300 val
+xwrwsqsxuo 1 300 train
+xwrxtfankr 1 300 train
+xwryrmsmbm 1 300 val
+xwsbkiaclt 0 300 train
+xwseajedfy 1 300 train
+xwsspafkcw 1 300 train
+xwsudeqxmc 1 300 train
+xwtcmccgdp 1 269 train
+xwtcmxmami 1 300 train
+xwtinzjokb 1 300 train
+xwtizvngtf 0 300 train
+xwtmpfmidp 1 300 train
+xwtpsggosx 1 300 train
+xwtqoyrtys 1 300 train
+xwubopspkr 1 300 val
+xwubxqevgb 1 300 train
+xwudozrkrr 1 300 val
+xwufihtkav 1 300 train
+xwugvqfvoo 1 300 train
+xwuhbmctmw 1 300 train
+xwukecfpeb 1 300 test
+xwurgqhdby 0 300 train
+xwvdsidxxu 1 300 train
+xwvnxrskde 1 300 train
+xwvpbhquwg 0 300 train
+xwvsycepjt 1 300 train
+xwwapswrtn 1 300 train
+xwwiwiivsn 1 300 train
+xwwlczuzzf 1 300 train
+xwwnlzvgtj 1 300 train
+xwwrdvnbho 1 300 train
+xwwtkxtzny 1 300 train
+xwwtqguvev 1 300 train
+xwwzcmklvx 1 300 val
+xwxcyaawbm 1 300 train
+xwxfgepypg 1 300 train
+xwxxnjdgmp 1 241 train
+xwylkxledn 1 300 train
+xwymddoebc 1 300 val
+xwymxohvup 1 300 val
+xwypbrocok 1 300 train
+xwyqeyhzxn 1 241 train
+xwyrjwucym 1 300 val
+xwytjlgflc 1 300 train
+xwytvbgtox 1 300 train
+xwzbbwsvls 1 299 test
+xwzipgnsfq 1 300 val
+xwznbrzasc 1 300 train
+xwzoytuehc 1 300 train
+xwzsxyrjzl 0 300 train
+xwzttlnuxq 1 300 train
+xxabehwhcg 0 300 train
+xxabzwphvq 1 136 train
+xxajwzyeso 0 300 train
+xxakqqjrao 1 298 train
+xxapkjcvps 1 300 val
+xxarnezgbi 1 300 train
+xxarseoapp 1 300 train
+xxbdurtubx 1 300 val
+xxbgrggplz 0 300 train
+xxbivelfwe 1 300 train
+xxbkebfrno 1 300 train
+xxbnbdjkau 1 249 train
+xxbpamwotq 1 300 train
+xxbunqmupn 0 134 val
+xxbvyfyvqr 1 300 train
+xxcbzfqwkv 1 300 train
+xxcoaiivlo 1 301 train
+xxcphprgau 1 300 train
+xxcqjmfoyw 1 300 train
+xxcryrjpfq 0 300 train
+xxctgcsxwj 1 299 train
+xxctscldjf 1 300 train
+xxdgopvncj 1 300 train
+xxdhpzystx 1 300 train
+xxdjxicnja 1 300 train
+xxdurledpq 0 300 train
+xxdzmuhnil 1 300 train
+xxeffwxbvk 1 300 train
+xxefgzivsj 1 300 train
+xxfbzfekxn 1 300 train
+xxfdozlaxq 1 300 train
+xxfgwddjxo 1 301 train
+xxfojdodmt 0 300 train
+xxfytxbwbg 1 300 val
+xxgbnmsgak 0 299 val
+xxgczzezxl 1 300 train
+xxghqdjgce 1 300 train
+xxgiskbcad 1 300 train
+xxgswfpndb 1 300 train
+xxgswxrvmc 1 300 train
+xxhapzmnlc 1 299 train
+xxhbjrpyij 0 300 train
+xxhernpcvb 1 300 train
+xxhfzcacpx 1 300 train
+xxhjtdereu 1 300 train
+xxhuecshhw 1 300 val
+xxhxixrypm 1 300 train
+xxidgpinpo 1 300 train
+xxidluxdnc 0 300 train
+xxigldllip 1 300 test
+xxihbusxxn 1 300 train
+xxihmrjplk 1 300 train
+xxihzvtvuw 1 300 test
+xxiijbrfwd 1 300 train
+xxilydbjxh 1 300 train
+xxilykaxlz 1 300 train
+xxiufodxge 1 300 train
+xxiviqqljk 1 300 train
+xxjlqsnuqr 1 300 train
+xxjmtjbvte 1 300 train
+xxjnvhixka 1 300 test
+xxjpxuovwa 1 300 train
+xxjrouqcmk 1 300 train
+xxjtarrvvt 1 300 train
+xxjvdqxhuh 0 300 train
+xxjyzmbpma 1 300 train
+xxkcpcojsn 1 300 train
+xxkdclftms 1 300 val
+xxkevsmgsb 1 298 train
+xxllwsgkam 1 300 train
+xxlqjautfj 1 300 train
+xxlrddnaub 1 301 train
+xxltlzvgwu 1 300 train
+xxltqgramg 1 300 val
+xxlyukpmtg 0 300 train
+xxmaeemuql 1 300 train
+xxmcihfilw 1 299 val
+xxmdknsonl 0 300 train
+xxmdpyifxt 1 300 train
+xxmgbcrfki 1 241 train
+xxmjgkgpeo 1 300 train
+xxmkvcyptj 1 300 train
+xxmryknshd 1 300 val
+xxnffgfhrf 0 300 train
+xxnkbderrn 1 300 val
+xxnofoeqhm 0 300 val
+xxnopajicm 1 300 train
+xxnoxvcpxz 0 300 train
+xxnwkzfbpm 1 298 train
+xxnzdqitzr 1 300 train
+xxoarigmuf 1 301 val
+xxoatqkezq 1 301 train
+xxobsyxjej 1 300 train
+xxojrvudqb 1 300 val
+xxojwcmuij 1 300 train
+xxomiivxhe 0 300 train
+xxosewixoo 1 300 train
+xxpakvdced 1 300 train
+xxpffgdrgh 1 300 train
+xxpizciplj 0 300 val
+xxpjtjhxnh 1 296 train
+xxpxhngmaq 1 300 train
+xxpxvgbysd 0 300 train
+xxqclifhxq 1 300 train
+xxqduonemp 1 300 train
+xxqgaanejb 1 301 train
+xxqgubjugh 1 300 train
+xxqkbpqltq 1 300 train
+xxqpfuoagg 1 300 train
+xxqpqvfbsm 1 300 val
+xxqttuofrn 1 300 train
+xxqyqmmpmd 1 300 val
+xxragkvyxj 1 298 train
+xxrdblkmlm 0 300 val
+xxrebpimum 1 300 train
+xxrhhkitse 0 302 train
+xxrjefioke 1 300 train
+xxrltrqmbm 0 300 train
+xxrwotvzbm 1 288 train
+xxrzzncksa 0 300 train
+xxscjscvkw 1 300 train
+xxsemivmdj 1 299 test
+xxsknooffv 1 300 train
+xxsvyvxhxi 0 301 train
+xxsxktyvzt 0 300 train
+xxtasqbooh 1 300 train
+xxtatbfdfk 0 300 train
+xxtawzuqsg 1 301 train
+xxtbukztkx 0 300 val
+xxterdxipx 1 300 train
+xxtnpustur 1 300 train
+xxtpvjzmps 1 300 train
+xxtvkcgnwk 1 300 train
+xxtwgtyqio 0 300 train
+xxtwsodnny 1 299 test
+xxtycujixt 1 300 train
+xxupwwukoh 0 300 train
+xxuurqcszb 1 300 val
+xxuywxxgdt 1 300 train
+xxvciuyawj 1 300 train
+xxvfbouhcr 0 300 train
+xxvjqfmlhx 1 300 train
+xxvuyemjfh 1 300 train
+xxvwbfmgzy 1 300 test
+xxvypqgjdr 1 301 train
+xxwcbyghcz 1 300 train
+xxwcxfnuax 1 300 val
+xxwecnhrii 1 300 val
+xxwiifioix 0 300 train
+xxwqdreijw 1 300 val
+xxwscpvlfe 1 300 train
+xxwuhluwte 1 300 train
+xxxrnkdsso 1 300 val
+xxxvoklqjw 1 300 train
+xxychrullw 1 240 train
+xxydtdydln 1 300 train
+xxyiignzyn 1 301 train
+xxyilybkoq 1 300 val
+xxymcyhbeb 1 300 train
+xxystyaufk 0 300 train
+xxysxmftkk 1 300 train
+xxytweziir 1 300 val
+xxzadettpc 1 300 train
+xxzcocidtw 1 300 train
+xxzefxwyku 0 299 test
+xxzfpirxyh 1 300 train
+xxzgohgjhv 1 300 train
+xxzupleytn 1 300 train
+xxzxwyduww 1 300 train
+xyadqwdugl 1 301 val
+xyakwxwgtt 1 300 train
+xyaqhpapms 1 300 train
+xyaqswphsn 1 300 train
+xyatphjwtk 1 301 train
+xyavetpesu 1 300 train
+xyavmpaknu 1 301 train
+xyblnmemqi 1 300 train
+xybsuqrftm 1 300 train
+xybvgsaqso 0 300 train
+xybwacgcsx 1 300 test
+xybydjpwfc 0 300 train
+xycfzkbnhy 1 300 train
+xycrjvihik 1 300 train
+xycvfqygqq 0 300 train
+xydaaegbxm 1 300 val
+xydfonlbyl 1 300 train
+xydstaiyzq 1 300 train
+xyeehejdkk 1 300 train
+xyejqdufmz 1 241 train
+xyekkeueqc 1 301 train
+xyenqhqtns 1 300 val
+xyeqnjodwl 1 300 train
+xyfdpuushc 1 300 val
+xyfflekgsp 1 300 train
+xyfmhzgqjz 0 300 val
+xyfvdnvaqa 1 300 train
+xygcyawuxx 1 300 val
+xygfaawffv 1 301 train
+xyglqdtqhj 1 300 train
+xygmixtfni 1 301 val
+xygoduopss 1 300 val
+xygyoqvnal 1 301 val
+xygyrrquer 1 300 train
+xyhabwrvrp 1 300 val
+xyhcihzbxi 1 300 train
+xyhefrzptw 1 300 train
+xyhjlkivyn 1 300 val
+xyhlypcopc 1 300 train
+xyhmgbsnkh 1 302 train
+xyhojsanyb 1 300 val
+xyhqgcspxt 0 300 train
+xyhrecpibe 1 300 train
+xyhtxcgtwy 1 300 train
+xyhubhqgju 0 300 train
+xyicaryreh 1 300 val
+xyifqrbiqm 1 300 train
+xyigodyold 1 300 train
+xyiiqrjxos 1 300 train
+xyioxposka 0 300 train
+xyjhiwmyvy 1 300 train
+xyjimzusak 1 300 val
+xyjkrxyakj 1 300 train
+xyjpcwpebs 1 300 train
+xyjtfubjpn 1 300 val
+xyjuiyobos 1 300 train
+xykfexpxnv 1 300 test
+xykgsbirag 1 300 train
+xykhxluzpn 1 269 train
+xykikfvfuf 1 300 train
+xyklkuuumr 0 300 train
+xykogatibm 1 300 train
+xykwkrpmbo 1 300 train
+xykxkysbpu 1 300 train
+xykyaotifw 1 298 train
+xykyyafsml 0 299 train
+xylefnjdzx 1 300 val
+xyliqgyqmx 1 300 train
+xylrltjypo 1 300 train
+xylxjtdsdq 0 300 train
+xylxkeohqi 1 299 train
+xylxklxchv 1 147 train
+xymefdvtan 1 297 train
+xymeodlrhb 1 300 train
+xymgayfgbp 1 298 train
+xymikxpvub 1 300 train
+xymkznzziz 1 298 train
+xymozosbak 1 301 train
+xymqwrboof 1 300 val
+xymrwyzajc 0 300 train
+xymwluhyko 1 300 train
+xynqbceyjg 1 301 train
+xynsewvklo 1 300 train
+xynzctcfqe 1 241 train
+xyobbjywdf 0 300 val
+xyockehads 1 300 val
+xyoghqavta 1 298 train
+xyogrdcbyt 0 300 train
+xyoqviargc 1 300 val
+xyowjmnemv 1 300 train
+xyoxzgundl 1 300 train
+xypgzeasix 1 300 train
+xypirpknql 1 297 train
+xypuokcifd 1 300 train
+xyqdxqhync 1 300 train
+xyqimudret 1 300 train
+xyqjetlgql 1 300 val
+xyqkrwtzmu 1 300 train
+xyqmqkthij 0 300 train
+xyquodhgyh 1 300 train
+xyqvwhfumo 1 300 val
+xyqwihcnbx 1 300 train
+xyqygotqwd 1 300 train
+xyrdjmggfr 1 300 train
+xyrdxhiiju 1 300 train
+xyrjgabbfv 1 300 train
+xyrmqwetua 1 301 val
+xyrmuxxufw 1 300 train
+xyrslykzlj 1 300 test
+xyrvehpgze 1 301 val
+xyrxssekxk 1 300 val
+xyscendxir 1 300 val
+xysfmxcsci 1 300 train
+xysjhiemoo 0 300 train
+xysoqvpvfe 1 300 train
+xytbaygyuc 1 298 train
+xytjzqqmcu 1 301 train
+xytvlwxhak 1 240 val
+xytxjydyft 1 300 train
+xytzavilqb 1 301 train
+xyuakzshhn 1 300 train
+xyuapdolga 0 300 train
+xyucutnxhz 0 300 val
+xyuiabqlbu 1 300 train
+xyuoscxius 1 300 train
+xyuwskmavt 1 301 train
+xyvelulyyq 1 300 train
+xyvixgnraw 1 300 val
+xyvjposbln 1 300 train
+xyvvgbdwde 0 300 train
+xyvyskucfp 1 300 val
+xyvzlulfxn 1 300 train
+xywbmzyrlu 0 300 val
+xywddjvklk 1 300 train
+xywdirutxf 0 300 train
+xywwihzkwb 1 300 val
+xywzdzryyn 1 300 train
+xywzlzokvt 1 300 train
+xyxdfdbmyo 1 300 train
+xyxsfzsmyd 1 300 train
+xyxuomjbvq 1 300 train
+xyyiqjttzz 1 300 train
+xyykomgbvi 1 300 train
+xyylimgrim 1 298 val
+xyynvfwdgo 0 300 val
+xyyqfpmznq 1 298 train
+xyywrpqetv 1 300 train
+xyyzkihhhn 1 300 train
+xyzbkthkye 1 296 train
+xyzfkluhjv 1 300 train
+xyzistkxbw 1 300 train
+xyzofgjlbl 1 300 train
+xyzosynvdn 1 300 train
+xyzqyadxps 1 300 train
+xyzrwffogg 1 298 train
+xzacabzxlj 1 300 train
+xzafoterjz 1 299 val
+xzaivqnapk 0 300 train
+xzamqvovkw 0 300 train
+xzanrsqxne 1 300 val
+xzaourmddl 1 300 test
+xzavftnhdl 1 300 train
+xzawgkvvwj 1 300 train
+xzaypsyvcv 1 300 train
+xzayxilesu 0 300 train
+xzazjubssm 1 300 train
+xzbcsieawk 1 300 train
+xzbcujyguy 1 299 train
+xzbgyspccw 1 300 train
+xzbkneczno 1 300 test
+xzbrvoeapt 1 300 train
+xzbvqjxpha 1 300 train
+xzcexrifxq 0 300 val
+xzchpjydkn 1 300 val
+xzciyalfba 1 300 train
+xzcohfjfvn 1 300 train
+xzcsvcknkn 0 300 train
+xzdbasahyo 1 301 val
+xzddzmzsup 1 301 val
+xzdghrlhze 1 300 train
+xzdjfhcvms 0 300 train
+xzdmavxixr 1 300 val
+xzdpiovitd 1 301 train
+xzdvlrcknf 0 300 train
+xzdxygzlky 1 300 train
+xzeagqhcvf 0 300 train
+xzelgotfys 1 300 train
+xzelyfouvo 0 300 val
+xzeoszmiai 0 300 train
+xzesrzgebd 0 300 train
+xzexmqojxj 1 300 train
+xzeynshixd 1 241 train
+xzfdtwlsth 1 300 train
+xzfhjcopxs 1 300 train
+xzfnavofil 0 300 train
+xzfppbayms 0 300 train
+xzfqilabpf 1 300 train
+xzfqnmoehk 1 300 train
+xzfvoikrhl 1 300 train
+xzfzrtsefl 1 295 train
+xzgbdohfpe 1 299 test
+xzgiggykyx 1 300 train
+xzgkiaaxje 1 300 train
+xzgtehofbl 1 300 train
+xzgvdrtnek 0 300 train
+xzgzmurqzd 1 300 train
+xzhaeeinmi 1 300 train
+xzhdjvzjhv 1 300 train
+xzhghbizqk 1 300 train
+xzhjevklzf 1 300 val
+xzhlkyuyvq 1 300 train
+xzhlniwqng 0 300 val
+xzhnkmqhjs 1 300 train
+xzhxdssqsy 1 241 train
+xzhxntumio 1 300 train
+xzhxxivuad 1 300 train
+xzigppwqig 1 300 val
+xzihygkiad 1 300 val
+xzimhmuldq 1 300 train
+xzirolxbnc 1 300 val
+xzisoplszl 0 300 train
+xzitvidqpr 1 299 train
+xziyveomua 0 300 train
+xzjlmosjvw 1 300 train
+xzjmkktdsj 1 300 train
+xzjnbbtitm 1 299 train
+xzjparkpwf 1 300 train
+xzjraltplt 1 299 val
+xzkavsdbrt 1 298 val
+xzkbwmyogl 0 300 train
+xzkcaicrxs 1 300 val
+xzkikmghps 0 300 test
+xzkmggahsk 1 300 train
+xzkvpuciyu 1 300 train
+xzkwbswkao 0 300 train
+xzkxbxyijw 0 301 train
+xzkzfwofar 1 301 train
+xzligjwzet 1 300 train
+xzlqysylfv 1 300 train
+xzmnzmzdxu 1 300 val
+xzmplldajk 0 300 train
+xzmsjjsywy 1 300 train
+xzmspcmdxy 1 300 train
+xznhrlcnwa 1 241 train
+xznxpyndsn 1 300 val
+xznypedfzb 1 300 train
+xzoajdfrea 1 300 train
+xzoaofnozj 0 300 train
+xzociwkgio 1 298 train
+xzoeyqarko 1 300 val
+xzofnsmqza 1 300 val
+xzouvgiqha 1 301 train
+xzoxqsokvh 1 300 train
+xzoyuaucnu 1 300 train
+xzpfwhypft 1 300 train
+xzpityeljb 0 300 train
+xzpkekxrts 1 298 val
+xzpomrkjtx 1 241 train
+xzppwruzpq 1 300 train
+xzpsscarze 1 300 val
+xzqfvaeiic 1 300 val
+xzqgptotdo 1 300 test
+xzqmyupcwa 1 300 train
+xzqootlsqp 1 300 train
+xzqpygxdun 1 300 train
+xzqtkkqfie 0 300 train
+xzqyktihqu 1 300 train
+xzrigfliat 1 299 test
+xzrkaufhgr 1 300 train
+xzrmelidhp 0 300 train
+xzrtrxbpfx 1 300 val
+xzsjdywgaz 1 300 train
+xzsmgydcub 1 300 train
+xzsnnfqhkt 1 298 val
+xzspowphav 1 300 train
+xzsptaymli 1 296 val
+xzsshnkqpv 1 300 train
+xzsxjudpgw 1 300 train
+xztcnuoigs 1 300 train
+xztdbborzr 1 300 train
+xztdrwuwrm 0 300 train
+xztksikyaf 1 300 train
+xztoomyaas 0 300 train
+xztqdkmuem 1 300 train
+xztrxhudga 1 301 val
+xztvldtstc 1 300 val
+xztwiqinnh 1 300 train
+xztxqagmkz 1 300 train
+xzucjaagcc 1 300 train
+xzuczqvbhz 1 300 train
+xzumjmcawo 1 300 val
+xzumzpalce 1 300 train
+xzunftecrx 1 300 train
+xzuztwusnd 1 300 train
+xzvavhpnfx 1 301 train
+xzvbnqnuui 1 300 train
+xzvdqlxwje 1 300 train
+xzvjktglle 1 300 train
+xzvkblgxvd 1 301 train
+xzvldcxuij 1 300 train
+xzvnnhzbqd 0 300 val
+xzvojbmtyc 1 300 train
+xzvrgckqkz 0 300 train
+xzvtbwryet 0 300 train
+xzvtwhywkr 1 300 train
+xzvvegmzjn 1 300 test
+xzvwdanxjt 1 241 train
+xzwilbpfba 1 301 val
+xzwjwjfysd 1 300 train
+xzwnunbzqf 1 300 val
+xzwuhfwhxw 1 301 train
+xzwxocqkez 1 300 train
+xzxalmnubr 1 300 train
+xzxbrbxplh 1 300 train
+xzxiydqftt 1 300 train
+xzxjnehqvr 1 298 train
+xzxnsadpgh 1 300 val
+xzxoeaaxnv 1 300 train
+xzxqknbchy 0 300 val
+xzxztrafpb 1 300 train
+xzyvxrmbug 1 300 train
+xzzdkjfjyx 0 301 train
+xzzdxxosrc 1 300 train
+xzzfdxzkys 0 300 train
+xzzoamlcqf 1 300 train
+yaahpquxyp 1 300 train
+yaaknwcfjz 1 300 train
+yaakrzfooj 1 300 train
+yaaodzqhai 1 298 train
+yaarxqkywl 1 300 train
+yaautxbvwk 1 300 train
+yaawipmswe 0 300 train
+yabbcpvssk 1 300 train
+yabbecufmd 0 300 train
+yabcqxnrqh 0 300 val
+yabdbyxply 1 300 train
+yabdoqamov 1 301 val
+yabhorsjru 1 300 train
+yabqnsbpmc 0 300 train
+yabvnuhvkn 1 300 test
+yabxtiyimg 1 300 val
+yaccysuoeq 1 300 val
+yacilqlipr 1 300 val
+yaclitpayf 1 300 train
+yacmpvgdln 1 300 train
+yacncsxmzz 1 300 val
+yacpateomv 1 300 train
+yadesprund 1 300 train
+yadevcuzdo 1 298 train
+yadgcquvdm 1 300 train
+yadgxfudsu 1 300 train
+yadkdooxnq 0 300 val
+yadnjfpztj 0 300 train
+yadowcwycz 1 300 train
+yadtoviwwr 1 300 train
+yaebgvtnqq 1 300 train
+yaefbkmefz 1 300 val
+yaejbhulkr 1 300 train
+yaejzsepky 1 300 train
+yaenxjvhxu 1 300 train
+yafcezdrcn 1 300 train
+yaficrjzqt 1 300 train
+yafssqtlti 1 300 train
+yafutqpmup 1 300 train
+yafvszhdil 1 241 train
+yagcuywmfk 1 300 train
+yaggczgzwf 0 300 val
+yagllixjvh 0 300 train
+yagpekvnde 1 300 val
+yagreqqsqe 1 300 train
+yagrukpvcu 1 298 train
+yagsdsjnuz 1 269 train
+yagyfkdesm 1 302 train
+yagzoyuxhy 1 300 train
+yahfuxjics 1 300 train
+yahpsimhyn 1 300 train
+yahtfkwdft 1 249 train
+yahycsubkj 1 300 train
+yaiemcnypq 1 301 val
+yaikyjpifq 1 300 train
+yainphudae 1 300 train
+yaitfqrcjp 1 240 train
+yaivbfubpr 0 300 val
+yaivzmwaiu 0 301 train
+yajgepyvft 1 300 train
+yajhwipypq 1 300 test
+yajjayfvwh 0 300 train
+yajvyxrrkb 1 297 train
+yajwfjzxam 1 300 train
+yajxpbdccj 1 300 train
+yajxywnzpr 1 300 val
+yakbbcdpsx 1 299 train
+yakbkegdby 1 300 test
+yakdhrtgez 0 303 train
+yakheupwkw 1 300 train
+yakhnpkaim 1 300 train
+yakixushrx 1 300 train
+yakxlkkeuz 1 300 train
+yakyoofhti 1 300 train
+yakzirnamy 1 300 train
+yakzwnvovg 1 299 train
+yalacwdjzk 1 300 train
+yalemnjbma 1 300 val
+yalgggfzpx 1 301 val
+yallvgzmqo 1 301 val
+yalrrtbrte 1 300 train
+yalvatvxph 1 300 val
+yamaaygsrf 1 300 train
+yamkdzjxfp 1 300 train
+yamkwrlnbv 1 300 train
+yamudgymhz 1 300 train
+yamynyibqt 1 300 val
+yanaertrpl 0 300 val
+yanijimloi 1 300 train
+yanjitgylg 1 300 test
+yanosxgyqm 1 300 train
+yanwjumfzt 1 300 train
+yanxasernr 1 298 train
+yanyxsjwfv 1 301 train
+yanzsjwhrb 0 300 train
+yaofzzcesn 1 301 train
+yaogkcrolf 1 301 val
+yaolhdfoet 1 300 train
+yaoopktrov 1 300 train
+yaoosnvbct 1 301 train
+yaosnskqet 1 300 train
+yaoxyysgyr 1 300 val
+yapacvciin 1 300 val
+yapizkutqu 1 300 train
+yapodjtogw 1 298 train
+yappxlifmm 1 300 train
+yapvlgucam 1 300 train
+yapxuyifzu 1 300 train
+yaqapwpuzu 1 300 val
+yaqduktvtx 0 300 train
+yaqepvfkgu 1 300 train
+yaqihrbiko 0 300 train
+yaqmpriaxm 0 300 train
+yaqmxgktuk 1 298 train
+yaqmyzloai 0 300 train
+yaqpsbexym 1 300 train
+yaqtqnaidf 1 298 train
+yaqvahwsni 0 300 train
+yaqyvienqb 1 300 train
+yaqzcoozsx 1 299 test
+yaremrzozb 1 300 train
+yareqjmumx 1 300 val
+yarfaofelt 1 300 train
+yarfzirpzw 1 298 train
+yarmavazct 1 300 val
+yarodrgcoe 1 301 train
+yaroumkbcf 1 300 train
+yarpxfqejd 1 300 test
+yarujwnbse 1 300 train
+yarujznhjt 1 300 train
+yaruwzhoma 1 300 train
+yarvkyboft 1 300 train
+yarwpoqqdi 1 300 train
+yasqmkxujm 0 300 train
+yasubamzva 1 300 train
+yaswbpnlpw 1 241 train
+yasxapunrf 1 300 train
+yatfokptmg 1 301 train
+yatkmpftdb 1 300 train
+yatqctprkq 1 300 train
+yatrwbfybl 1 300 train
+yatwyftvgr 1 300 test
+yaugcmkhrr 1 301 val
+yaugurnefp 1 300 train
+yauptnvsum 0 300 train
+yauqgdhejd 1 301 train
+yaurmteyna 1 300 train
+yauttvjxos 1 300 val
+yauwlfgbnc 1 300 test
+yauxzeznbz 1 300 train
+yavarnralk 1 300 train
+yavbbrxkco 1 300 train
+yavfzcwbru 1 249 train
+yavfzygiez 1 300 train
+yavglvswie 1 301 train
+yavswhuxyv 1 300 train
+yavtuvqbsh 0 300 train
+yavuuerbcy 1 300 train
+yawbxszxql 1 300 val
+yawdhzbnrp 1 300 train
+yawfxchzzu 0 300 train
+yawkhoolnu 1 301 train
+yawknkwbuk 1 300 train
+yawvhfszsm 1 300 train
+yawwieerrj 1 300 train
+yawymqtypk 1 300 train
+yaxghgfxfx 1 300 train
+yaxgjlahjv 1 299 train
+yaxgpxhavq 1 299 test
+yaxqtglnhe 1 300 train
+yaxrqafsok 0 300 train
+yaxtnvonbf 1 300 train
+yaxtwiztxa 1 300 val
+yaxvawxngh 1 300 train
+yaydymmmyn 1 300 train
+yayiggnpuw 1 300 train
+yaysqxwckj 1 300 train
+yayuwikpcn 1 301 train
+yayvrsvhlv 1 300 train
+yazbhlitpf 1 300 train
+yazfzhtmlj 1 300 train
+yazrsbwbnd 1 300 train
+yazzcowywe 1 300 train
+ybaakskjlo 1 301 train
+ybabhnaoga 0 300 val
+ybafyfaarh 1 300 train
+ybagfgwnas 1 300 train
+ybanjewtqe 1 300 train
+ybavfdsheg 1 300 val
+ybbauxsttp 1 300 train
+ybbbgwckts 1 300 train
+ybbbkocsao 0 300 train
+ybbbniaaje 1 298 train
+ybbcmleutc 1 300 train
+ybbftsrsro 1 297 train
+ybbiuleqfq 1 300 train
+ybbmekktth 0 300 train
+ybbrkacebd 0 300 test
+ybbyeyelju 1 300 train
+ybbypeggid 1 241 train
+ybbziapzmv 1 299 test
+ybcazrkatu 1 300 train
+ybcbqonmyl 1 300 train
+ybcgvygpjw 1 288 train
+ybchdxrktn 1 301 train
+ybcogwtbew 1 300 train
+ybcqxbweww 1 300 val
+ybcwybczkm 1 300 val
+ybcybeupwo 1 300 train
+ybddlvvidm 1 300 train
+ybdftiwspd 1 300 train
+ybdjfoymqx 1 300 train
+ybdkwtpqwp 0 300 train
+ybdstkoyri 1 255 train
+ybdtapfqzq 0 300 train
+ybdtbtocoh 1 300 train
+ybdtkypwez 1 300 test
+ybdwqtwbqx 1 296 val
+ybearjuymh 1 300 train
+ybefzibreb 1 300 test
+ybegoygsdd 1 300 val
+ybeipkespm 0 300 train
+ybekxpqfdw 1 300 train
+ybelhxpgtp 1 300 val
+ybeqdosyeu 0 300 val
+ybeqihhiuo 1 300 train
+ybeqjfoqfd 1 300 train
+ybetenmsye 0 298 train
+ybetmwdpzu 1 300 val
+ybexfrxoga 1 300 train
+ybexscfulg 1 300 train
+ybeyqjbnin 1 301 val
+ybfbhjprir 1 301 train
+ybfbwnjmrz 0 300 train
+ybfcxmfoka 1 300 train
+ybfepeemsw 1 300 train
+ybfumhbiba 1 300 train
+ybgauydpjv 1 300 val
+ybgiotlclg 1 300 train
+ybgjbafxuc 1 239 val
+ybgjijobya 1 300 train
+ybgmyqkxjh 0 300 train
+ybgvzotihl 1 300 val
+ybhbmmgbuk 1 300 train
+ybhhivlbci 1 300 val
+ybhjtgpooa 1 300 train
+ybhlbadxwo 0 300 train
+ybhlejchyi 1 300 val
+ybhsmotqua 1 300 train
+ybifgnnocy 1 300 train
+ybjbxrpmod 1 300 test
+ybjrqnqnno 0 300 train
+ybkcodajlw 1 300 train
+ybkdiyccgd 1 300 train
+ybkekjntal 1 300 val
+ybketgvwjj 1 301 val
+ybkficvdcg 1 300 train
+ybkltjepoi 1 300 train
+ybkqykotud 0 300 train
+ybkvchqkas 1 300 val
+ybladzjtwv 1 300 train
+yblfcaffix 1 300 val
+yblfrwurbj 1 300 train
+yblnympbkn 1 300 val
+ybloubzugo 1 300 val
+yblphdvyry 1 300 train
+yblwcftree 1 301 train
+yblwnprulq 1 300 val
+yblxtrlhpn 1 300 train
+yblzpeegnk 1 300 test
+ybmbyjmzpv 1 300 train
+ybmhobcxpx 1 300 train
+ybmhvdkerv 1 300 train
+ybmlurdvoa 1 298 train
+ybmlzhowvr 1 300 val
+ybmmldbefh 1 300 val
+ybmpcnodrg 0 300 val
+ybmwavvtuk 1 300 train
+ybmyhjyabe 1 300 train
+ybnaifwufz 0 300 train
+ybnemycaum 0 300 train
+ybnhywnczo 1 300 train
+ybnjvhunta 1 300 train
+ybnoincncr 1 301 train
+ybnucgidtu 0 300 val
+ybnwjbjtzi 1 300 train
+ybocqlrhvt 1 301 train
+yboctdaujc 0 300 train
+ybogvwgyhr 1 300 train
+ybonxvbfmy 1 300 train
+yboofyemks 1 300 val
+ybpbyqqrgl 1 300 train
+ybpciafdah 1 297 train
+ybpjsisfqg 1 300 train
+ybpjxmzeew 1 300 val
+ybpmyfilxw 1 298 train
+ybpsqaindb 1 241 train
+ybptxiwyqb 1 300 val
+ybpwyzwvjj 1 300 train
+ybpxqzmepb 1 300 train
+ybpywbhhig 1 300 train
+ybqboicycm 1 300 train
+ybqeurufjk 0 301 val
+ybqevzyiou 0 300 train
+ybqirlmfdz 1 300 train
+ybqksxkbrf 1 300 train
+ybqlfvjppm 1 300 train
+ybqmttnept 0 300 train
+ybqowvqyhm 1 301 train
+ybqrcwpbfn 1 300 val
+ybquxguikt 1 300 train
+ybqzodpuyv 1 300 train
+ybrdijdwox 1 297 train
+ybrebzqrhp 1 241 train
+ybrgaiveux 0 300 train
+ybrjwfpszr 1 300 train
+ybroqkxxnt 1 300 train
+ybrpamhhks 1 300 train
+ybrqugbigj 1 300 train
+ybruvnxfit 0 300 train
+ybrvzivria 1 300 train
+ybrxcsyxyl 1 300 train
+ybrzvsjdfx 1 298 train
+ybsbipoacu 0 301 val
+ybsdhmsuun 0 300 train
+ybsdzkzntn 1 300 train
+ybsncjgjoq 1 298 train
+ybsxuujuvd 1 300 train
+ybsyskzmec 0 300 train
+ybtbgkxaxq 1 300 train
+ybtefuoqfb 1 300 train
+ybtgphyeeb 1 302 train
+ybtrbrcqzc 0 300 train
+ybtrpcjpia 1 300 train
+ybttezhhux 1 300 train
+ybtuohhkoy 1 300 train
+ybtxayjyaz 0 300 train
+ybtzxxmajp 1 300 train
+ybubbzysno 1 300 train
+ybugjnqcyn 1 300 train
+ybuwgqsbls 1 297 train
+ybvefuzbmr 1 300 test
+ybvfaxjsic 0 300 train
+ybvqonmaji 0 301 train
+ybvrdzwlcw 1 300 train
+ybvwvncszj 0 300 train
+ybvxpbkhkx 0 300 train
+ybweipckyy 1 300 train
+ybwhpwzdwg 0 300 train
+ybwjcpognh 0 300 val
+ybwjytlfsr 1 136 train
+ybwkmchtjf 1 300 train
+ybwpqcefqd 0 300 train
+ybwuprwmsy 1 298 train
+ybwvoogtii 1 300 test
+ybxebjoeov 1 300 train
+ybxgudnkse 1 300 train
+ybxihysjtb 1 299 val
+ybxnmctbyf 0 300 train
+ybxphbdbkb 1 300 train
+ybxskewcgt 1 300 train
+ybxwuujmot 1 300 val
+ybydrqveki 1 300 train
+ybyovwwpup 1 300 val
+ybypmwsjoy 1 300 val
+ybyqycxndx 1 300 train
+ybytszahxf 1 300 train
+ybywuetvaz 1 300 train
+ybzbevfyom 0 300 train
+ybzfaamwsj 1 300 train
+ybzkppnhvn 1 300 train
+ybzqtyuulg 1 300 val
+ybztbncgbq 0 300 train
+ybzxlzsxxh 1 300 train
+ycaarpteux 1 300 train
+ycahvklnzb 1 300 val
+ycaohiiurf 1 300 train
+ycarzdbzwy 1 299 test
+ycatkndztm 1 300 train
+ycaywstzis 1 300 train
+ycazcscjfa 1 300 val
+ycbdophsmv 1 300 train
+ycbekhneij 1 301 train
+ycbixwbriz 1 298 train
+ycblzkkton 1 301 train
+ycbmcijpbk 1 300 train
+ycbntefdye 1 301 val
+ycbsvyyvbd 1 300 train
+ycbtivkeku 1 296 train
+yccnxtbknq 1 300 train
+yccwrnmltz 1 300 train
+yccxkjdwcp 1 300 train
+yccydfxugq 1 300 val
+ycdhlyrnhg 1 300 train
+ycdzikivhi 1 300 train
+ycdzvybhuj 1 300 train
+yceetmtcsn 1 300 train
+ycegltztvx 1 301 train
+ycejywkbki 1 240 train
+ycekvuocgl 1 300 train
+ycemlgklie 1 300 train
+yceploelog 0 300 val
+ycfeylsnjc 1 301 train
+ycfmjaaxhn 1 300 train
+ycfqtxiifr 1 143 train
+ycfwoyprch 1 298 train
+ycfxtemkuj 0 300 val
+ycggzbchat 1 300 val
+ycgmovacdu 1 300 train
+ycgnfhwxzb 1 300 train
+ycgrwhoaqk 0 300 train
+ycgultkxor 1 300 train
+ycgyjqlygh 0 300 train
+ychbjvqiju 1 300 val
+ycheayspna 1 300 train
+ychhvofuau 0 300 train
+ychlldajfk 1 300 train
+ychnzdjprp 0 300 train
+ychojzxyzd 1 300 train
+ychpnlmlkm 1 300 test
+ychrdwpnai 1 300 val
+ychsgwlmhb 1 300 val
+ychtesljrc 1 300 train
+ychxinivcp 1 300 train
+ychyaqjpmq 1 300 train
+ychzyajfck 0 300 train
+yciairlpqz 1 300 train
+ycibpbsivc 1 300 train
+ycifllhqdm 1 300 train
+yciiryvoxs 1 298 train
+ycioptsepm 1 300 val
+yciouipvsc 1 300 val
+yciyyfogex 0 300 val
+ycjbvwgnmk 1 300 val
+ycjcjyjzxy 1 301 val
+ycjebkbcii 1 300 train
+ycjlszmxmo 1 300 train
+ycjuantwvl 1 300 train
+ycjxywqonv 1 300 train
+yckaejmzas 1 300 train
+yckblemoyr 1 300 train
+yckdwvnaou 1 241 train
+ycklgzfmpw 1 269 train
+ycklqgnxkb 1 300 val
+yckltoblhr 1 301 train
+yckmtjaqlu 1 299 val
+yckrngzuyy 1 300 train
+ycktfoutus 1 297 train
+yckwgdrxhx 1 300 train
+yckyjgyvkb 1 301 train
+yckyxxeqtd 1 300 test
+yckzeqejet 1 300 train
+yclmotqpvp 1 298 val
+yclmzzboyn 1 300 train
+ycltrqcdxr 1 300 val
+yclwcuyogk 1 300 train
+ycmhieorrk 1 300 train
+ycmlexgbio 1 298 train
+ycmnawavou 1 300 train
+ycmqedefbt 1 300 train
+ycmuriliwe 1 300 train
+ycmxnievjv 1 300 train
+ycnsgvbwpz 1 300 train
+ycntyippab 1 301 train
+ycoaclsdov 1 301 train
+ycoftlnqkb 1 300 train
+ycofwmfnuf 1 300 val
+ycoozaicpy 0 300 train
+ycopcojgpy 0 300 val
+ycoqnbmxmk 1 300 val
+ycpdnnftav 1 300 train
+ycpiszbssv 1 241 train
+ycpljobxzk 1 300 val
+ycptyqmohe 0 300 val
+ycpuhmcdom 1 300 test
+ycpykyxjcx 1 300 val
+ycpzktqwmi 1 300 train
+ycqlyotowt 1 300 train
+ycqojhujkr 1 299 val
+ycqrcqkrsi 1 300 train
+ycqxwzrorr 1 300 test
+ycqzyztvqi 1 300 train
+ycrakjtqzd 1 300 train
+ycrdvxadhb 0 300 train
+ycreaqjipl 1 301 train
+ycrnhmuons 0 300 train
+ycrnvrhera 1 300 train
+ycrojsqtrd 1 300 val
+ycruqtlfzn 1 302 train
+ycsalbqmhi 1 241 train
+ycscgknizb 1 298 train
+ycsdkqevsj 1 301 train
+ycsghchjml 1 300 train
+ycsosobhoc 0 300 train
+ycspotxvjx 1 300 train
+ycszmelaqh 1 300 train
+yctauryddd 1 300 train
+yctiinwdfy 0 300 train
+yctjskowrp 1 300 train
+yctjtbfehf 1 297 train
+yctmsbhrma 1 300 train
+yctoiivqlg 1 300 val
+yctpvfrqcb 1 300 train
+ycttwzwkpx 0 300 val
+yctyzyactb 1 300 train
+yctzcxcwaq 1 299 train
+ycuhxtmdfg 1 301 val
+ycunotrbab 0 300 train
+ycuowoxzfo 1 301 train
+ycuptcjteb 1 300 train
+ycuyszxdfb 1 300 train
+ycvinrzpar 1 300 train
+ycvqznokqy 1 298 train
+ycvyqtrzft 0 300 train
+ycwapqtfai 0 300 train
+ycwdddoigp 1 300 train
+ycwkxkukar 1 300 val
+ycwlvljiqi 1 300 val
+ycwqaitbxp 1 301 val
+ycwtjvasly 1 300 train
+ycxcfzimln 1 300 train
+ycxeapovhu 1 300 train
+ycxesitomc 1 301 val
+ycxfxsfjdg 1 300 train
+ycxhekspak 1 300 train
+ycxjwmkurm 1 301 train
+ycxkcnwrbw 1 300 train
+ycxqxubnvy 1 300 train
+ycxychhfix 1 300 train
+ycxygwkogw 0 300 val
+ycxznnicma 0 300 train
+ycybtwdpej 1 300 train
+ycydhlctiw 0 300 train
+ycynjgqjba 0 300 train
+ycynnqixii 1 300 train
+ycyykkvoij 1 301 val
+yczfvbljff 1 300 train
+ycznpzwurl 0 301 val
+yczwfqgluz 1 300 val
+yczykxxoqc 1 300 train
+ydafabdxqt 1 300 train
+ydanxqoycq 0 300 train
+ydarronbwj 1 300 train
+ydawjbtnwi 0 300 val
+ydbbyvetdb 0 300 train
+ydbecbjshl 1 300 val
+ydbgcsdduv 1 300 train
+ydbimudfrc 1 300 val
+ydbjaimikq 1 300 train
+ydblbpdkpq 1 300 train
+ydblosceaw 1 300 train
+ydbnctieuk 0 300 val
+ydbspqwdjr 1 300 train
+ydbuiluelu 0 300 train
+ydbwxazmxt 1 300 train
+ydbycgzpzm 1 300 train
+ydbyibzamr 1 300 val
+ydcgatghdv 1 300 train
+ydcuctypks 1 300 train
+yddgxvwbkm 1 300 train
+yddmjmvesb 1 302 train
+yddonqydvb 1 298 train
+yddwyookjg 1 300 train
+ydefdghwzn 0 300 train
+ydekfazetf 1 300 train
+ydelctjwjb 1 300 train
+ydenjwycvr 1 300 train
+yderfasldg 1 300 train
+ydevxdfbqi 1 300 train
+ydfcdsrrff 0 300 train
+ydfcqqrcbv 0 300 train
+ydflvkcukw 1 300 train
+ydfntnxriy 0 298 train
+ydfoxuffem 1 300 train
+ydfrgdlbcx 1 300 val
+ydfrzhxhaf 1 300 val
+ydfuqpxbom 0 300 train
+ydfviiiuqs 1 241 train
+ydfxbxyxve 1 300 train
+ydgewcrxfk 0 300 train
+ydgkmyvtnv 1 300 train
+ydgluxcmux 1 300 train
+ydgmijnbkp 1 300 train
+ydgmqvwhoy 1 300 train
+ydgtctdttz 0 298 val
+ydgwtxaand 1 301 train
+ydgxjmywug 1 300 train
+ydheuuecdn 1 300 train
+ydhgdxaecu 1 300 val
+ydhrbvwxvm 1 300 val
+ydhucliygb 1 240 train
+ydhyiksucc 1 300 train
+ydicaccpbg 1 300 train
+ydinyksqdz 1 300 train
+ydioddxgkj 1 300 train
+ydipbbvuhi 1 300 train
+ydiuetyfpz 0 300 train
+ydiwlrowzh 1 300 train
+ydiyqerzrg 1 300 train
+ydjaehrtys 1 300 train
+ydjoghkbim 1 299 train
+ydjrdkwoud 1 167 train
+ydjtvbfjnm 1 300 train
+ydjvphftks 0 300 train
+ydjvwzsrdt 1 300 train
+ydjxfgqbpy 1 300 val
+ydkaapqizq 1 300 train
+ydkbdiymmx 1 300 train
+ydkbmjvlog 1 300 train
+ydkhndvhrp 1 300 train
+ydkocfookm 1 300 train
+ydkroekumt 1 300 val
+ydkrpkwxxo 1 300 val
+ydktqwcfzn 1 300 train
+ydkxtwgvwc 1 300 val
+ydkydlqjme 1 301 train
+ydkynrkpop 1 300 val
+ydkzqxozzx 1 300 train
+ydlaxdolno 1 300 train
+ydlbbbpkne 1 300 train
+ydlitsqkza 0 300 train
+ydlkctmffw 1 300 train
+ydlqzalqia 1 299 test
+ydltmkhfdh 1 300 train
+ydlusiluer 1 300 train
+ydmemmmhfa 1 301 train
+ydmftzzrtd 1 296 train
+ydmgrxwuyi 1 298 train
+ydmgtywlti 0 300 val
+ydmhrmqspc 1 300 train
+ydmiqbfbsg 1 300 val
+ydmmbvibbk 1 300 train
+ydmsiwsfhu 1 300 val
+ydmteqpjpe 1 300 val
+ydmulwzcko 1 300 train
+ydnehvnxtd 1 298 train
+ydnjbfktwt 1 299 val
+ydnolptgxi 1 300 train
+ydnozelryv 1 300 train
+ydntymedcu 0 300 val
+ydnuhxkjfd 1 300 val
+ydnvgacdnv 1 300 train
+ydnxjptikv 1 300 train
+ydohykmnwd 1 300 val
+ydomhvhuwz 1 300 train
+ydonrcfivq 1 300 train
+ydorlzopai 0 300 train
+ydouwpwxfo 1 300 train
+ydpamssgkj 1 300 train
+ydpaqdpiqa 1 300 train
+ydpqykkqkg 1 299 val
+ydqcckctqf 1 300 train
+ydqcucbqii 1 300 train
+ydqeopjemz 1 300 train
+ydqjpvqcsc 1 300 train
+ydqovcxvum 0 300 val
+ydqsidqlfs 1 300 train
+ydqvbgbwup 0 300 train
+ydqvbxdgvr 1 125 val
+ydrdhgwewi 1 300 train
+ydrdwldexh 1 299 val
+ydrhofjcji 1 298 train
+ydrmpdgsdv 1 300 train
+ydrmyinlma 1 300 train
+ydrtkntscm 1 300 train
+ydruehgdxi 1 300 train
+ydryrajclq 1 301 train
+ydrzlvuslj 1 300 train
+ydskaqimqc 1 300 train
+ydskzecnhc 1 300 train
+ydsmkrqnhv 1 300 train
+ydtfpbanqj 1 300 train
+ydtpwdqkcn 1 300 train
+ydtqmvjoih 0 300 train
+ydtvgedlqm 1 300 train
+ydufdshwpb 1 300 train
+yduuhbctce 1 300 val
+yduytqeaqv 1 300 train
+ydvirbhctz 1 300 train
+ydvjzdjajt 1 299 train
+ydvkwvsdxq 0 300 train
+ydvljrwivu 0 300 val
+ydvmbklvxo 1 300 val
+ydvmpemaks 1 300 val
+ydvspkswjp 0 300 train
+ydvwivmlhk 0 301 val
+ydvzdwgfeh 1 301 train
+ydwjoykflj 1 300 train
+ydwkgauhlo 1 300 val
+ydwmjrwwdd 1 300 val
+ydwwwsdqlu 1 300 train
+ydxcpykdma 1 300 train
+ydxdqnkkfn 1 297 train
+ydxglijged 1 300 train
+ydxmecfzvc 1 301 val
+ydxpnwqpnd 1 300 train
+ydxurbwnbe 1 300 val
+ydxutkwsoa 1 299 val
+ydxvqaohtq 1 300 val
+ydxzcxzqeo 1 298 val
+ydxzosoyij 1 300 train
+ydybknbtvw 1 300 train
+ydyksrqclh 1 300 train
+ydykxcrspt 1 300 train
+ydylghbzgz 1 241 train
+ydyolkfmxc 1 300 train
+ydyopvabyo 1 300 train
+ydyrmgtpgt 1 300 train
+ydyuefqkyk 1 300 train
+ydywdtsrtb 1 295 train
+ydzbpreamo 1 300 train
+ydzehlcijg 1 300 val
+ydzmrwbipm 1 300 train
+ydznzkztgw 1 300 train
+ydzqfbttcm 1 300 train
+ydzqfzlqlv 1 300 train
+ydzzmxoisb 1 300 train
+yeaaojfbml 1 300 train
+yeabzuilfx 0 300 train
+yeafhzeomq 0 300 train
+yeaozghrhd 1 301 train
+yeapwlvzwb 1 300 val
+yeasrhspcl 1 301 train
+yeatjwiqum 1 241 train
+yebeeujegi 0 300 train
+yebezdlvmw 1 300 val
+yebjnqvoyw 1 300 train
+yebzwzdbgv 1 300 train
+yecbohsssc 1 300 train
+yeccuaezhz 1 300 train
+yecjrztlwm 1 300 train
+yecldwzgxx 1 298 train
+yecliythar 1 146 train
+yecnupbavt 1 300 train
+yeczmaggmp 1 300 train
+yeczvjvdcb 1 300 train
+yednejmedv 0 300 train
+yednyneaag 1 300 train
+yedrixstja 0 300 train
+yedujuvwdn 1 301 train
+yedwlusohd 1 300 train
+yedwuxtupt 1 300 val
+yeeceldqpx 1 300 test
+yeemuaroyj 0 300 train
+yeeochkmwh 1 300 train
+yeeodzzoxf 1 300 val
+yeezhwdofg 1 300 train
+yeezomdekw 1 300 val
+yefakavmdr 1 300 train
+yefgfikzlg 1 300 val
+yefjvbspdn 1 300 train
+yefkyegloc 1 300 train
+yefpfehtep 1 300 train
+yefpfwcice 1 300 val
+yefurawtzk 1 300 train
+yefvhmktvp 1 300 train
+yegbinkbmf 1 300 train
+yegcuezues 1 300 train
+yeggdwqoxd 1 300 train
+yegvwrsewn 1 300 test
+yehfurclja 1 298 train
+yehhckdtjp 1 300 train
+yehhsfukbg 1 300 train
+yehiwtpqdt 1 300 train
+yehmzmgcvx 1 300 train
+yehnjsxyzc 1 300 val
+yehrqzimur 1 300 val
+yehtngfnrp 1 300 train
+yehyyjdfte 0 300 train
+yehzxcoayi 1 300 train
+yeiceplyjx 1 300 train
+yeicirfkef 1 300 val
+yeidkihjvb 1 300 train
+yeifwpwrjc 1 300 val
+yeirqwzyww 1 300 val
+yeiteagpwk 0 300 train
+yeiwiysryd 1 301 train
+yeixvfdimg 1 300 train
+yeiyuafvhe 1 300 train
+yejekpzyuk 1 300 train
+yejjshzcpi 1 300 train
+yejvlyggtw 1 299 test
+yejvukmaqw 1 300 train
+yekddvtnew 1 300 train
+yekjiklmdk 1 300 val
+yekkkfuhqn 1 241 train
+yeknwbwxvt 0 300 train
+yekvrdnppi 1 300 train
+yelaceqqtw 1 298 train
+yeldthfbyv 1 300 train
+yelfzwykjb 1 300 train
+yelntvksvi 1 300 train
+yelseuucoz 1 300 train
+yelvyskdux 1 300 train
+yelwawgbdv 1 300 train
+yemcsrnkld 1 600 train
+yemutbnqcv 1 300 train
+yemwcnnqxv 1 300 test
+yemyamgwae 1 298 train
+yenapoggdn 1 300 train
+yenazjqyga 0 300 train
+yenejtnvys 1 300 train
+yengcmmwvh 0 300 train
+yeniyzmlje 0 300 train
+yenmlpbzut 1 300 train
+yennshallj 0 300 train
+yenpnrrvst 1 300 train
+yenrsxtxbf 1 300 train
+yenswtjadf 1 301 val
+yenuwyirhd 1 301 train
+yeoemydrdp 1 300 train
+yeoetfivot 1 300 val
+yeojpeeybf 1 300 train
+yeolhhzcpc 1 300 train
+yeoolgeujd 1 300 train
+yeoqxbmypk 1 300 train
+yeoregdhhk 1 297 val
+yeotajbmun 0 300 train
+yeouperxzc 1 300 test
+yeovhzxeph 1 300 train
+yeovsllafj 1 236 train
+yeoyxkprgi 1 300 val
+yepaqgceod 1 300 train
+yepaxqcdrl 1 297 train
+yepcodgagp 1 300 train
+yepeotjldk 1 300 train
+yephtexyrr 0 300 train
+yeppfsapvc 1 300 val
+yepycumjyp 1 300 train
+yepztbrcfn 1 301 train
+yeqfsinjyu 1 300 train
+yeqhdxjnav 1 300 train
+yeqhglocdp 1 300 val
+yeqopewmwr 1 300 train
+yeqqlbhgze 0 300 train
+yeqrsiagbx 1 300 val
+yeqsswrkqj 1 300 train
+yeqvlvijsm 1 300 train
+yerjzbscyz 1 300 train
+yerkmawrac 1 241 train
+yermnsnlgf 1 301 train
+yerppzhfiv 1 300 val
+yertudqmjb 1 300 train
+yerxtelogc 1 300 train
+yesctvwhgv 1 300 train
+yesfrhdayo 1 301 train
+yesouylztx 1 300 train
+yesudgncds 1 300 train
+yetdnphqkp 1 301 val
+yethxoexko 1 300 train
+yetivvxned 1 300 train
+yetmcgjpnp 1 300 train
+yetoyrfijk 0 300 train
+yetubnogcp 1 300 train
+yetyqnlnvc 0 300 train
+yeuembthmr 1 301 val
+yeuhjkxqgl 1 300 val
+yeuniqcsae 1 300 test
+yeunmuzwzb 1 298 train
+yeuuncegju 1 298 train
+yeuvkityyk 1 300 train
+yevbavvhgi 1 300 train
+yevgnmcdin 1 300 val
+yevgpssfcz 1 300 train
+yevidcaspu 1 300 train
+yevmhhjlkx 1 300 train
+yevqwlmbku 1 300 train
+yevtnyeaxq 0 300 train
+yewabcvapc 0 300 train
+yewpuddcek 1 300 train
+yewrlufoou 1 300 train
+yewviotueg 1 300 train
+yexbushfwe 1 300 train
+yexeazbqig 0 300 test
+yexekvzzht 1 300 train
+yexfywrwsn 1 300 train
+yexmdrccyx 1 300 val
+yexnwyshjh 1 300 train
+yexojpfhee 1 300 train
+yexyajaazk 0 300 train
+yeyhrbfasg 1 300 val
+yeyjwvwlxp 1 300 train
+yeynimarop 1 299 test
+yeyvvmuacv 1 300 train
+yeywbzdmsl 1 300 train
+yezjulrvbi 1 301 train
+yezkbaowru 1 300 train
+yezlduimla 1 300 train
+yezpgokanb 1 300 train
+yezrauqccu 1 301 train
+yezrqwimia 0 300 val
+yezwbmesfz 1 300 train
+yezyfykgds 1 300 train
+yfaasbdsei 1 300 train
+yfadxaydyg 1 300 val
+yfaozufzfe 1 241 train
+yfapbxhnpd 1 300 train
+yfarsvblwx 1 300 train
+yfavmkqxat 0 300 val
+yfaxshlqgo 0 300 train
+yfazzjrdbx 1 136 train
+yfbbicsyph 0 300 train
+yfbfgifkil 0 300 val
+yfbgvpcwyb 1 301 train
+yfbpxmodya 1 300 train
+yfbyvfpexv 1 300 train
+yfbzdiserx 1 300 val
+yfchcmazzr 1 300 train
+yfcmcnjvub 0 301 train
+yfcmcxfytn 0 300 train
+yfcsnqjspw 1 300 train
+yfcvcqyqfj 1 300 train
+yfduedzgne 1 300 val
+yfdxbzunhr 1 300 train
+yfdyaafjic 1 241 train
+yfefuwdrid 1 300 train
+yfehdvsfoq 1 301 val
+yfemtoneft 1 300 train
+yfeppvfnbd 0 300 train
+yferlfibnv 1 300 train
+yfezdwlyhe 1 300 train
+yfezfaztoj 1 300 train
+yffdrqtbrt 1 300 train
+yffohjknho 1 300 train
+yffphuoqck 1 300 train
+yffqoqlizu 1 241 train
+yffrlkovdk 1 300 train
+yffujvjwfd 1 300 val
+yffzawplrk 1 300 train
+yfgcvyhaay 1 300 train
+yfgeagownc 1 300 train
+yfgianlyxy 0 301 train
+yfgjtpedmm 1 300 train
+yfglxrbpja 1 240 train
+yfgxwrwowp 0 300 train
+yfhbgcliax 1 301 train
+yfhhrbbxsq 1 300 train
+yfhlqwzveq 1 300 train
+yfhqhjbtdb 0 300 train
+yfhtdpejwp 1 300 train
+yfhvlndiww 1 300 val
+yfhygvijla 0 300 val
+yfhyhinpfz 1 300 train
+yfhzmfhojv 1 300 train
+yfhzqlcprv 1 300 train
+yficnxueej 1 300 train
+yfiemkxpes 1 300 train
+yfihdxwmum 1 299 train
+yfihpubaxh 1 300 val
+yfijbmucjz 1 300 train
+yfilxwqpce 0 300 train
+yfiqhuyiyh 1 300 train
+yfjdaeocjy 0 300 train
+yfjdrdhkbm 1 300 val
+yfjepurdvu 1 300 train
+yfjhmblyxs 0 300 train
+yfjkgiynbi 0 300 train
+yfjlrhxffn 1 300 train
+yfjnhlwvqn 1 300 train
+yfjnrndymr 1 297 val
+yfjripqxze 0 300 train
+yfjswfzogx 1 300 train
+yfjtfdkygm 1 300 train
+yfjvfxpepl 1 300 train
+yfkifnthut 0 300 train
+yfkkailhbl 1 300 train
+yfkkkrwhls 1 300 val
+yfkkzazgae 0 300 train
+yfkmhjjrig 1 301 train
+yfkpzongcz 1 300 train
+yfkuojmkac 0 300 train
+yflbjydirs 0 300 train
+yflgptgirp 1 300 train
+yflloaxkzy 0 300 train
+yflojbacqe 1 301 train
+yflugkbqvu 1 300 train
+yflygvybrt 1 300 train
+yflzmdpkab 0 301 train
+yfmjaiscci 1 300 train
+yfmnhyfmzm 1 300 train
+yfmqitqasi 1 300 train
+yfmrxxfper 0 300 train
+yfmtqkqett 0 300 val
+yfmznksntm 1 300 train
+yfnalahkmb 0 301 train
+yfnatzdzen 1 300 val
+yfnbqoqjch 1 300 train
+yfnlrckeec 0 300 train
+yfnlwwefac 1 300 train
+yfnqnwzemm 0 300 val
+yfnryzrkoo 1 300 train
+yfnvwhnofw 1 300 test
+yfobedcwrw 0 241 train
+yfobnogzhp 1 300 val
+yfoiqtyqvy 1 300 train
+yfoplgwtxu 1 300 val
+yfopsxevsv 1 300 train
+yformzytou 1 300 train
+yfpdzcolmh 0 300 train
+yfpklcjcmu 1 300 train
+yfprwjgwir 0 300 train
+yfpwsrgeer 1 300 train
+yfqjyzznuk 1 300 train
+yfqkceqszv 1 300 train
+yfqmolfisc 1 300 train
+yfqqfcrpjx 1 301 train
+yfqsjkevgw 1 241 train
+yfqtnrsjtb 1 300 train
+yfquxzpxjt 0 300 train
+yfqwocaogm 1 300 train
+yfrdadfdwo 0 300 train
+yfrdijumxu 0 300 train
+yfrhoqvlly 1 300 train
+yfriabrama 1 300 val
+yfrjesxhil 1 300 val
+yfrqpsgblm 1 300 train
+yfrsdxalql 1 300 train
+yfrsqobwal 1 300 train
+yfrtnpjaav 1 300 train
+yfrvyilndp 1 300 train
+yfrzsmbaex 1 300 train
+yfsaspsghf 1 300 train
+yfshxyaqxs 1 300 train
+yfsjvihpyl 1 300 val
+yfsjywacjw 1 300 train
+yfsmevimjk 1 300 val
+yfsnwkbafm 0 300 train
+yfsogpuyko 1 298 val
+yfswhlskzp 1 269 train
+yftckvzukh 1 301 val
+yftdilwuco 1 241 train
+yftemqpmjs 1 241 train
+yftqfcwlfq 1 300 train
+yfttqqyexx 1 300 train
+yftxfbikwn 0 300 train
+yfubgumshj 1 300 val
+yfuofykert 1 298 train
+yfuudfkrod 1 300 train
+yfvbupshjk 1 300 val
+yfvfiygnhf 1 298 train
+yfvtdkqnwf 1 300 train
+yfvvmqdkcd 1 300 train
+yfwelsovoj 1 300 val
+yfwmwwfrew 1 300 train
+yfwqcaxnij 1 300 val
+yfwqckbpkm 1 300 val
+yfwtgurzjc 1 300 train
+yfxcxoulda 1 300 val
+yfxhxioqoe 1 300 val
+yfxjnsreql 1 300 train
+yfxsprjcqg 1 300 train
+yfxsxyakan 1 301 train
+yfxtlwlqkl 1 300 train
+yfxtuimubx 1 300 test
+yfxvjewtjq 0 300 val
+yfyijusxsf 1 300 train
+yfykpwwopz 1 299 val
+yfyyraimde 1 300 train
+yfzbituuyv 1 300 train
+yfzcqkyezb 1 300 train
+yfzcvdzhss 1 300 val
+yfzhahbzea 0 300 train
+yfznbbnjlt 1 300 val
+yfznoycznk 1 300 train
+yfznrrpoek 0 300 train
+yfzprgybcd 1 300 train
+yfzrvvmrzx 1 300 train
+yfzulfwjue 1 300 test
+yfzvqtpneb 0 300 train
+yfzwuzwdtm 1 300 train
+yfzxgshdqe 1 300 train
+yfzykkchht 1 300 train
+yfzzrthqwc 1 300 train
+ygaaujjova 0 300 train
+ygacdrpkns 1 300 train
+ygailoszoy 1 298 train
+ygarinrhrm 1 300 val
+ygartarjgc 0 300 train
+ygasktqyov 1 300 train
+ygaufyfoeg 1 300 train
+ygaxkjtrua 1 300 train
+ygaxoqabaq 1 300 train
+ygbajspsux 1 300 test
+ygbettzvue 1 300 train
+ygbfqvvxax 1 300 val
+ygbhnvyenv 0 300 train
+ygbnyzdsrm 1 300 train
+ygbrhmvsxe 1 300 val
+ygbrkugyvg 0 300 val
+ygbsrjuneo 1 300 train
+ygbvdcscsw 1 301 train
+ygbwpfgavp 1 300 train
+ygbxstvipt 1 300 train
+ygcrqskjni 0 300 val
+ygculodqcj 1 300 train
+ygdaasvspv 1 300 val
+ygdbohfkzp 0 300 train
+ygddgkryhz 1 298 train
+ygdezgtchk 1 300 train
+ygdgwyqyut 0 300 train
+ygdotvrkqj 1 300 train
+ygdsatkhrr 1 300 train
+ygdwuirokk 1 241 train
+ygeauvgaee 1 241 train
+ygedntwknr 1 300 train
+ygefiytago 1 301 train
+ygerdwiihw 1 300 val
+ygevfpkgjx 1 298 train
+ygewggaedz 1 300 train
+ygexkztwzv 1 300 val
+ygfaytefyd 0 300 train
+ygfbtxvomy 1 300 train
+ygffastgfy 1 300 train
+ygfoblbxcx 1 300 test
+ygfpdfjkqd 1 249 train
+ygfpfmncqb 1 300 val
+ygfpuifruw 1 300 train
+ygfsbazkxj 1 300 train
+ygfstzfgdw 1 300 train
+ygfvlbcojf 1 299 train
+yggapsxthg 1 300 train
+yggazskksr 1 255 train
+yggflwovqz 1 300 train
+ygggyeltxz 1 300 train
+yggkujyblt 1 300 val
+ygglrlqryk 1 300 val
+yghhfvwexf 1 300 train
+yghjvgpzvi 1 298 train
+yghlnsekrb 0 300 train
+yghnnikgkc 1 300 val
+yghpprwupr 1 300 train
+yghsouhfvb 1 300 train
+yghwvtjdrz 1 300 train
+yghxoihrle 0 300 val
+ygiahrrrdf 1 297 val
+ygiajlblev 1 298 val
+ygiawdrspo 1 300 train
+ygibaucydu 0 300 val
+ygifafqrbz 1 99 train
+ygigjerjnt 1 300 train
+ygiiuiahvf 0 300 train
+yginglenrq 1 240 train
+ygiscbckjl 0 300 train
+ygjetcnzyp 1 301 train
+ygjobqrpqn 1 300 train
+ygjrottnou 1 300 train
+ygjtgqjhzf 1 300 val
+ygjutqdwgt 1 298 train
+ygjycxicxp 1 301 val
+ygkefjuqop 0 300 train
+ygkjmugret 1 300 train
+ygkkzveljj 1 298 val
+ygknkubeyb 1 300 test
+ygkusubnvn 1 300 val
+yglfjvsaqx 1 301 val
+ygllsykoyz 1 300 train
+yglmdlours 1 300 train
+yglrrbqlhc 1 298 train
+yglwbumdeb 1 301 val
+yglxppklqq 1 300 train
+yglyhxinxl 1 146 train
+yglyozgxqx 1 300 train
+yglysfqlms 1 300 train
+ygmahkbjxe 1 300 train
+ygmattfezc 1 300 train
+ygmepsdowu 1 299 val
+ygmgikkblp 1 300 train
+ygmlbqonac 1 300 train
+ygmobxlwoi 1 300 test
+ygmszontji 1 300 train
+ygmyjlrjpe 1 300 train
+ygnbegsvrn 0 300 train
+ygncssfzmv 1 301 val
+ygndoiydlr 0 300 train
+ygngdbjmox 1 300 test
+ygnohrnvwf 1 300 val
+ygnrcogikg 0 300 train
+ygnwszflss 1 301 train
+ygnxletqhr 1 300 train
+ygobagrhmg 1 300 train
+ygocfjqlmk 1 301 train
+ygofrsydaj 1 300 val
+ygogzwonpj 1 300 train
+ygoikppluy 1 300 train
+ygolsvayls 1 300 train
+ygonnnkvzo 1 300 train
+ygopzzuswq 1 300 val
+ygorhdysrb 1 299 val
+ygosbyrqaj 1 300 train
+ygoupusgbb 1 300 train
+ygozaaiivf 1 300 train
+ygpbwstrzd 1 241 train
+ygpgdfamrd 0 300 train
+ygpgpgzywd 0 300 train
+ygptuziven 1 300 train
+ygqauginke 1 300 train
+ygqckwgteq 1 300 train
+ygqcvloktt 1 300 train
+ygqnnxeree 1 300 train
+ygqtfbzixa 1 300 train
+ygqzmkxuru 0 241 train
+ygreqqihyy 0 300 train
+ygrgmlnddj 1 301 train
+ygrjvvomfh 1 300 train
+ygrncnyesz 1 300 train
+ygrnuvcoji 1 300 train
+ygrqeqtndl 1 300 train
+ygrqerqqcd 1 298 train
+ygrzcwzpwc 1 300 train
+ygsavjtril 1 300 train
+ygsbmrsamk 1 300 val
+ygsffqgqcg 1 300 test
+ygshllkcaz 1 299 test
+ygsjatfccn 1 300 val
+ygsjcxauaw 1 300 train
+ygstjkpujy 1 300 train
+ygsxexgdwd 1 300 train
+ygsycttbar 1 300 train
+ygtakodngl 1 300 val
+ygtcgdqdeo 1 301 train
+ygthqlpmhy 1 299 train
+ygtrootala 1 300 train
+ygtxrxoxdp 1 300 train
+ygtyxvndqf 1 300 train
+yguhxjmphg 1 300 train
+yguknbohxc 1 300 train
+yguohtopgf 0 300 train
+ygusdkrwmw 1 300 train
+yguxnohxdy 1 300 train
+ygvgfctpoe 1 300 train
+ygvljdlqrx 1 300 val
+ygvslzzdhp 1 300 train
+ygvsuimehc 0 300 val
+ygvtnpapwb 1 300 train
+ygvvxtorpn 1 300 train
+ygwabhdgli 1 300 train
+ygwbfafuvr 1 301 train
+ygwnxyfqvj 1 300 train
+ygwuqgblbe 1 301 train
+ygxbopmdgf 1 300 val
+ygxeysiyue 1 300 train
+ygxoiribkn 1 300 train
+ygxorecpkq 1 300 train
+ygxtaulugw 0 300 train
+ygxudmryrm 1 300 train
+ygxwrhaese 0 300 train
+ygxxbrosot 1 300 train
+ygycynfrbd 1 300 train
+ygyfnmcrtl 1 298 train
+ygygssqtik 1 300 train
+ygyhurweua 0 241 train
+ygyqubhxwk 1 300 train
+ygysqlrqdl 1 300 train
+ygysuzkvri 0 300 val
+ygyutwsyra 0 300 val
+ygywrjcojd 1 301 train
+ygzajizgvi 0 301 train
+ygzbnyjnmi 1 300 train
+ygzbotsxew 1 300 val
+ygzdvjgmon 1 298 train
+ygzhnejvjq 1 300 train
+ygzqkfdsnr 1 300 train
+ygzuhgggqh 1 300 train
+ygzzhwvuhf 1 300 train
+yhaahxnbcv 0 300 val
+yhabvkdzeu 1 300 train
+yhabztznmj 1 300 train
+yhadancvgb 1 301 train
+yhajnuscfo 1 300 train
+yhatmntxbv 1 300 train
+yhbhhibwzo 0 300 train
+yhbpxjcglo 1 300 test
+yhbtgaruuf 1 300 train
+yhbumrqlhw 0 300 train
+yhbzqoraac 1 300 train
+yhccejexpf 0 300 train
+yhceqiugon 1 300 val
+yhchnvjcok 1 300 test
+yhcnrijzuu 0 300 train
+yhcnxzcbds 0 301 train
+yhcuprblci 1 300 train
+yhcvganuap 1 300 train
+yhcwqdjiuf 1 300 train
+yhdathaklw 1 300 val
+yhdhoirdec 1 300 train
+yhdmyyaocq 1 300 val
+yhdrnktlsl 1 300 train
+yhdtypzntp 1 300 train
+yhduemrsee 1 300 train
+yhekfgieoo 1 300 train
+yhesqsdwvq 0 300 train
+yhessichhu 1 300 train
+yheutrhsxs 1 300 train
+yhevztnbuk 1 301 train
+yhexvgfmum 1 300 train
+yhfcfzprgc 1 300 train
+yhfdlltacu 1 300 train
+yhffcuhhjy 1 301 train
+yhfgitaepl 1 300 train
+yhfnkaderm 1 300 train
+yhfpgbyoix 1 300 val
+yhfzdlgxnl 1 300 train
+yhgexqnlcm 1 300 train
+yhgfwwfepz 1 302 train
+yhggnawvpb 1 301 train
+yhgmdhzpgp 1 300 train
+yhgpoeudzq 1 298 train
+yhhiowhevi 1 300 val
+yhhmarsfgq 1 300 train
+yhhnlugzdk 1 300 train
+yhhntyxrlb 1 300 test
+yhhrxxfleo 1 301 train
+yhhwhgdaxi 1 99 train
+yhhzdvpkhm 1 300 train
+yhhzstaqsg 0 300 train
+yhisywlzwr 1 300 train
+yhivypatjc 1 300 train
+yhjayveuuj 1 300 val
+yhjgyriczb 1 300 train
+yhjlnisfel 0 300 test
+yhjlqgldfh 1 300 train
+yhjrsaosrf 1 239 train
+yhjrxkrtpz 0 300 val
+yhjsxvfynx 0 301 train
+yhjxyqikzn 1 240 train
+yhkdvjweoi 1 301 train
+yhkdwdlpyh 1 300 train
+yhkswjgrsj 0 300 train
+yhkteosfqs 1 300 train
+yhkvtidagk 1 300 train
+yhlarojulr 1 300 val
+yhlefwnmzk 1 300 train
+yhlgtpubcq 1 241 train
+yhlkmcxoal 1 300 val
+yhlmbxaabq 0 300 train
+yhmazfyaat 0 300 train
+yhmbjbljst 1 300 train
+yhmgdrbzcz 1 301 train
+yhmjeubjte 1 300 train
+yhmovlaskr 1 300 train
+yhmqhjipbz 1 300 train
+yhmtgevqtc 1 300 val
+yhmzabqxwx 1 300 train
+yhnatlfcnh 1 300 val
+yhnbgthgps 1 288 train
+yhnezzquhz 1 241 train
+yhnhgxwgxw 1 299 val
+yhnihzltca 1 300 train
+yhnplarxhw 1 300 train
+yhnwiuxnox 1 300 val
+yhoincdvdk 1 300 test
+yhoivjlvgd 0 300 train
+yhojaohjbf 1 300 train
+yholajhkwl 1 300 train
+yhorqnwdcw 1 298 train
+yhounrbtvg 1 300 train
+yhouydpdho 1 300 train
+yhoylflxjo 1 300 train
+yhpdkafiyq 0 300 train
+yhpetosozi 1 300 train
+yhpetxxwaj 0 300 train
+yhpezpcvvu 1 296 train
+yhpjpivpcx 1 300 train
+yhprjqndda 1 300 train
+yhptbsggwe 1 300 train
+yhptcmoewk 1 300 train
+yhpvoosduy 1 300 val
+yhqgxuuuut 1 300 train
+yhqicyejuf 1 241 train
+yhqltdyvcy 1 300 test
+yhqnurxlnm 1 300 val
+yhqqiaciir 1 301 val
+yhqqwnlqdi 0 300 train
+yhqrbiffba 1 301 train
+yhqwrblsvr 1 299 val
+yhriqeialm 0 300 train
+yhrollgmzs 1 300 train
+yhrpxoocia 0 300 train
+yhrtrargbm 1 301 train
+yhruoixlgu 1 300 train
+yhrwgdhurd 1 297 train
+yhrwnayfng 1 300 val
+yhsapjtdhe 1 299 train
+yhsgsyogrl 1 300 train
+yhsiijuloc 1 300 train
+yhsltdpfpk 0 300 val
+yhsylsmuwg 1 300 val
+yhtdwyutwh 1 300 train
+yhtfxmccjd 1 300 train
+yhtidcgcks 1 300 val
+yhtkkpvvun 1 300 train
+yhtvnvmpqj 0 300 val
+yhtyqgfivs 1 300 train
+yhubdxligw 1 300 train
+yhuifmkmld 1 300 train
+yhuioirzod 1 300 train
+yhupajgsnz 0 300 train
+yhuppibvve 1 301 train
+yhuumdcepz 1 300 val
+yhuxleqkiq 1 300 train
+yhuzxvurrw 1 300 train
+yhveuzhypa 1 298 train
+yhvginqkxo 1 300 val
+yhvhuljreb 1 300 train
+yhvkmwazup 0 300 val
+yhvnrzzbqj 1 300 train
+yhvrcepfzy 1 300 val
+yhvxdvnhgi 1 300 train
+yhvxttvzjd 1 300 val
+yhwewmfucb 0 300 train
+yhwkxfpoio 0 300 train
+yhwtfxnlwd 1 300 val
+yhwwejnaew 1 300 val
+yhwxowciga 1 300 train
+yhwzjygoah 1 300 train
+yhxegrhbdt 1 300 train
+yhxftabucb 1 300 train
+yhxgxxfcth 1 300 train
+yhxlweppnr 0 300 train
+yhxmzyqplp 1 300 train
+yhyaeakwgh 1 300 val
+yhyjoltgld 1 299 train
+yhyknpceig 1 300 val
+yhylappzid 0 299 test
+yhyrxzqtey 1 300 train
+yhytugtlog 1 300 train
+yhyyaxddqr 1 300 train
+yhyzqxurou 1 241 train
+yhyzylsuxz 1 300 test
+yhzknnoety 0 300 train
+yhzkwrrgze 1 300 train
+yhzuezezaq 1 298 val
+yhzuyxcroi 1 300 train
+yhzxcvhade 1 300 train
+yhzyqbiucz 1 300 train
+yiabajckla 1 300 test
+yiafckaqsb 0 300 train
+yiaflzjgak 1 300 train
+yiamlskfwr 1 300 val
+yiarsltdig 1 300 train
+yiazwmdiaa 1 300 train
+yibebkpvhz 1 300 train
+yibeqxcadd 1 300 train
+yibqiilrpj 1 300 test
+yibtjaqcnu 1 300 train
+yibubxuixs 0 300 train
+yibvyoxhgt 1 300 train
+yibwycyhaz 0 300 train
+yicabrvkrf 1 300 val
+yicbshfjvy 0 300 train
+yicfowyeqc 0 300 train
+yichoalaww 1 300 train
+yicmivfoay 0 300 train
+yicnyhsjfa 1 300 val
+yidjjaqgvl 1 300 train
+yidljukmlc 1 240 val
+yidndgcgbt 1 241 train
+yidrboessk 1 300 test
+yidtlofved 1 300 train
+yieavhyutk 1 300 test
+yiedkbrawo 1 300 train
+yiellkgifr 1 300 train
+yiemzdoxsm 1 300 train
+yieptjmvhm 0 300 train
+yietrwuncf 0 299 test
+yieyazbghz 1 300 train
+yifhjncfkv 1 300 val
+yifiohclta 1 255 train
+yifkkloalk 1 300 train
+yiflivektg 1 99 train
+yifrmjsswc 1 300 train
+yiftrmejxm 1 300 val
+yiftujqlxd 0 300 val
+yifueumsgl 1 300 train
+yifxgmhtie 1 300 val
+yifysybhfo 1 300 train
+yigakhlxts 1 301 val
+yigbywpiox 0 300 val
+yigeqqnxmp 1 300 test
+yighmfnnel 1 300 train
+yigiwunbep 1 301 train
+yiglhquvbq 1 300 train
+yigmrbapbi 1 300 train
+yigmtjwjmu 1 300 train
+yigujebuyh 1 300 train
+yigwexlczs 1 300 train
+yihaywgpus 1 300 val
+yihngrkmzb 1 300 train
+yihodfxbqj 0 301 train
+yihriwiouk 1 300 train
+yihsmubqwx 1 300 test
+yihssnxwzl 1 300 val
+yihudrxedv 1 300 train
+yihwrhcmms 1 300 train
+yihzmyqjpd 1 301 val
+yiibecelkn 1 300 train
+yijackyuhj 1 300 train
+yijbahpaxp 1 300 train
+yijbgyefrf 1 300 train
+yijczbxusa 0 300 train
+yijebdgjal 1 300 val
+yijecshxaq 1 300 val
+yijteiprpz 1 298 val
+yijyabicor 1 300 train
+yikahgeuey 1 300 train
+yikdbcmpal 1 300 train
+yikhuzkpeb 1 301 train
+yikjfigswp 1 300 val
+yikxqxnbhm 1 300 train
+yilhaiiopo 0 301 train
+yilmjnzbmx 1 300 train
+yilpvblxnd 1 300 train
+yilrjigsat 1 300 train
+yiluzrwomh 0 300 train
+yiluzssiis 0 300 train
+yilvrzwaya 1 300 train
+yimbaqilnp 1 300 train
+yimbzokrij 1 300 train
+yimegvkqzu 1 300 test
+yimfoccqzr 1 300 train
+yimqkeekjm 1 300 test
+yimsmlvjhk 0 300 val
+yinfppqxuj 1 300 train
+yinjkljhmq 1 300 train
+yinjnkxbym 1 300 train
+yinkesudvb 0 301 train
+yinmmriyfs 1 300 train
+yinonowoaa 1 300 val
+yinoxgapul 1 300 train
+yinwzittws 0 300 train
+yinyhvkcur 1 301 val
+yinzndedcy 1 300 train
+yiobxevqad 0 300 train
+yioduwbmzt 1 288 train
+yiooctyvit 1 300 train
+yiorwjvwqp 1 147 train
+yiotdunfpj 1 300 val
+yioylzndlz 1 300 val
+yipcjmhaho 1 300 train
+yipdoncykb 1 300 train
+yipqppbnty 1 300 train
+yipsskgtjz 1 300 train
+yipuwdbwqv 1 300 train
+yipveihnza 1 300 train
+yipwkudbxf 1 300 train
+yipwuvmeml 1 300 train
+yipyfdfwie 1 300 train
+yipygkgxsa 1 301 train
+yipzmaknol 0 300 train
+yiqdjbotyg 0 100 train
+yiqhbxgfav 0 301 train
+yiqphyicdn 1 300 val
+yiqtkidiec 1 300 train
+yiqtxlpcia 0 300 train
+yiqvndzmbn 1 300 train
+yiqvtnsczw 1 300 val
+yirfswnpvl 0 300 train
+yirhagecsp 1 300 train
+yirhsptlko 1 300 test
+yirifempza 1 300 train
+yirjnktepz 1 300 val
+yirkaxfwgb 0 300 train
+yirokhanse 1 300 train
+yirovpypuh 1 300 train
+yirrpeozia 1 300 train
+yirsrbjfjm 1 300 train
+yisdyigvrx 0 300 train
+yisizovsfg 1 300 train
+yiskhvuaxs 1 299 train
+yismsygbtj 0 300 train
+yisqoqvnsy 1 300 val
+yisrwcqlfa 1 301 train
+yiswcywwfc 1 300 train
+yithdpidam 1 300 val
+yitlgszydi 1 300 train
+yitobtigee 1 300 train
+yitodmowzy 1 300 val
+yitoykvoww 1 302 val
+yitqrzzogr 1 301 val
+yitsrqeiih 1 299 val
+yitzgpxhws 1 300 train
+yiuhppfnpk 1 300 val
+yiuhvibyxn 0 300 val
+yiujfjmkqt 1 300 train
+yiuknsckdk 1 300 train
+yiultxpfpc 1 300 train
+yiumowrzes 1 300 train
+yiuqtxbwjh 1 300 train
+yiurgxbllb 1 300 train
+yiuxpxqkta 1 300 train
+yiuxwriwmc 1 300 test
+yivaecncdt 0 300 train
+yivfufgxsi 1 298 train
+yivoplhlcj 1 300 test
+yivspcmkbk 1 300 train
+yivueijxxz 1 300 train
+yivyxagzay 0 300 train
+yivzzqafeq 1 299 train
+yiwiaghxqb 0 300 train
+yiwjftbcgm 0 300 train
+yiwldoyyvv 0 300 train
+yiwtakrkrh 1 300 train
+yiwudavgin 0 300 train
+yiwvutvvcv 1 300 train
+yiwyejujhz 1 300 train
+yiwyjhheul 1 300 train
+yixcnzhyxp 1 301 val
+yixddtzazz 1 300 train
+yixioevjln 0 300 train
+yixiwvyjfj 1 300 val
+yixkdodzfd 0 300 train
+yixmmlipsf 1 301 train
+yixossnghz 1 300 train
+yixscrxpvg 0 300 train
+yixtnswuke 1 100 train
+yixtzkgpdf 1 300 train
+yixwwgvjib 1 300 train
+yixxnoyuuo 1 298 train
+yixyduelno 1 300 train
+yixyztdwtb 1 302 train
+yiycrzrfkm 1 300 train
+yiygigeycb 1 300 train
+yiyhgtlnrs 1 300 train
+yiyholrtvy 1 300 train
+yiykshcbaz 0 300 test
+yiyqebnaxi 1 297 train
+yiyvrnijum 1 300 train
+yizeddjudz 1 300 train
+yizmbpqxqm 1 300 val
+yizqfqsisb 1 300 train
+yizruqskwj 1 298 train
+yjaiksguey 1 300 train
+yjajaokpal 1 300 val
+yjajbkcpwa 1 300 val
+yjataatykv 1 300 val
+yjbeyhsusk 1 300 train
+yjbjenmloj 1 298 train
+yjbkawftuc 1 300 train
+yjbnaqwxyf 1 300 train
+yjbnfyuuli 1 301 train
+yjbnrbhdhr 1 242 train
+yjbobcwgzl 0 300 val
+yjbphfzxch 1 300 train
+yjbqjlpumw 1 300 train
+yjbykmaoww 1 300 train
+yjchlfqxpj 1 300 train
+yjcipxyjkx 1 300 train
+yjclmylskw 1 300 train
+yjcrbcyref 1 301 val
+yjcseoucxk 1 300 train
+yjcwvskkcn 1 300 train
+yjcyvdwhkm 1 300 train
+yjczpzxgvt 1 300 train
+yjdcyvitjf 1 300 train
+yjdhbhesnq 1 301 train
+yjdlytyjlt 0 300 val
+yjdmyvbkhm 1 300 val
+yjdmyxutxa 0 300 train
+yjdrmeyjkr 1 300 val
+yjdrssqykm 1 298 train
+yjemkqbcwx 1 300 train
+yjeomdmfcq 1 300 train
+yjeslmwyfn 0 300 train
+yjetxeyjbp 1 300 train
+yjevthbxou 1 300 train
+yjeyyaeaho 1 300 train
+yjfcgwxzrd 1 301 val
+yjfdnylpab 1 300 train
+yjfjceqcds 1 302 train
+yjfqckuyub 0 302 train
+yjfxtrrgyu 1 300 train
+yjgemhxkry 1 300 train
+yjggnlcxmr 1 300 train
+yjgozkhvpg 1 300 train
+yjgrmqzzpe 1 300 train
+yjgullkuyb 1 300 train
+yjgxdluxfc 1 300 train
+yjhettfirr 1 300 val
+yjhgruujcq 0 300 train
+yjhmxguwbo 0 300 train
+yjholijqca 1 300 train
+yjhrkttnit 1 300 train
+yjhsvttsce 1 298 train
+yjhwfkxitv 1 300 train
+yjibqywydw 1 300 train
+yjioezslch 1 300 train
+yjipwagtrg 1 300 train
+yjjfcpbzqj 1 300 train
+yjjkhvwxtk 1 300 val
+yjjkyuxvgz 1 300 val
+yjjofebyic 1 300 train
+yjjwigjvpd 1 300 train
+yjkcewkhhn 0 300 train
+yjkgyvwyml 1 300 train
+yjkilchsji 1 300 val
+yjkiocvhko 1 300 val
+yjkoshemqd 1 301 train
+yjkpjxybkt 1 300 train
+yjkqrqnufx 0 300 train
+yjkzlqsqay 1 300 val
+yjlhbkwmdc 1 300 train
+yjlibddnpu 1 300 val
+yjlijwzcyk 1 300 train
+yjlixbnhpp 1 300 val
+yjljwqunpv 1 300 train
+yjllqhbmke 1 300 test
+yjloelifnn 1 300 train
+yjloopcthi 1 300 train
+yjlqmmufse 1 300 val
+yjlsozxrko 1 300 train
+yjlsxqoauz 0 300 train
+yjlucrtevv 1 300 val
+yjlvmdiodn 1 99 train
+yjlydmmjqt 1 301 train
+yjlytpedux 1 300 val
+yjmabrwmlp 1 300 test
+yjmabvrgcu 1 301 train
+yjmepfuxzb 1 301 val
+yjmlrmfpax 1 300 train
+yjmpthducm 1 302 train
+yjnbidnpov 1 300 train
+yjnjedutnl 1 299 train
+yjnnqduuvg 1 300 train
+yjnosocfrh 1 298 val
+yjnpygwhsh 1 300 val
+yjnsggmqum 0 300 train
+yjoebjlwkq 1 300 val
+yjoebtzbiw 1 300 train
+yjohzsbidq 1 300 train
+yjolhzmrlx 1 300 train
+yjopklxubl 0 301 val
+yjordihdrv 1 300 train
+yjowjvwwma 1 300 train
+yjoxcezfmk 1 300 train
+yjpbyugsfu 1 299 train
+yjpdjftjne 1 300 train
+yjpfhrfyfn 1 300 val
+yjpqksjzmc 1 300 train
+yjqhvzgwam 1 300 train
+yjqibziskb 1 300 train
+yjqvjuekuz 1 300 train
+yjqxutyyvi 0 300 val
+yjrijznpvc 1 300 train
+yjrtfnlnlx 1 300 train
+yjrtwxwyin 0 300 train
+yjrvtfcycu 1 300 train
+yjsdgtrskn 1 300 val
+yjsfekrwpq 1 300 train
+yjsmfknvpj 0 300 val
+yjsmkyqeff 1 298 val
+yjsraebvaw 1 300 val
+yjswanmffv 1 300 train
+yjszvnwaxt 1 301 train
+yjtgddbnow 1 298 train
+yjtmwjlswx 1 300 train
+yjtqlghbsw 1 300 train
+yjttwdlgkl 1 300 train
+yjtuoyotvf 0 300 train
+yjtykxbnao 1 298 train
+yjtzxwkoim 1 300 train
+yjuamrdwxu 0 302 val
+yjucabucje 1 300 train
+yjudofpgnf 1 300 train
+yjuelgwmiy 1 300 train
+yjuneayhdu 1 300 val
+yjursarfjz 1 300 train
+yjusuvaxzk 1 300 train
+yjuwuynnru 1 300 train
+yjvfctrykm 0 300 train
+yjvtkxiglv 1 300 test
+yjvvoxcmue 1 300 train
+yjvwwnrhuq 1 300 train
+yjvxjpuucr 1 300 train
+yjwdkocysf 1 301 val
+yjwfmjvkhs 1 300 val
+yjwjcxbeie 1 301 train
+yjwotdwusx 1 300 train
+yjwpdqlkee 0 300 val
+yjwqouaiwn 0 300 train
+yjxbokkowd 1 300 train
+yjxbunjucp 1 300 val
+yjxiwwsiyy 1 300 val
+yjxlcwqcgj 1 300 train
+yjxrpvwgxk 1 300 train
+yjxsncqvjh 1 299 val
+yjyecavupb 1 300 val
+yjyfytwkko 1 300 train
+yjyhcaqatu 0 300 train
+yjypqyrhyi 1 301 train
+yjywpiqrht 1 300 train
+yjzamvhcwq 1 300 val
+yjzapfbtoa 1 300 train
+yjzavgbujd 1 300 train
+yjzdaeizdr 1 301 train
+yjzdxuiprl 1 300 train
+yjzgrighqo 0 300 train
+yjzgxsnpom 1 99 train
+yjzpjnxzoi 0 300 train
+ykajndzpnt 1 300 train
+ykanztkjlg 1 300 val
+ykawxlgqcu 1 300 train
+ykbbuvbqsn 1 300 train
+ykbfcijwgw 1 301 train
+ykbhmueovi 1 300 test
+ykbingkwma 1 300 train
+ykbinjkdud 1 300 train
+ykbmdulxnz 1 300 train
+ykbowlpmcp 1 298 train
+ykbygjxhzo 1 300 val
+ykccbybjcj 0 300 train
+ykcvazqzpo 1 300 train
+ykcydkochm 1 300 train
+ykdbemyzig 0 300 val
+ykdduziywx 1 300 train
+ykdinxwggp 1 300 train
+ykdqxidoav 1 300 train
+ykdrzctodm 0 300 val
+ykecwwpvjy 1 300 train
+ykefxibtdf 0 300 val
+ykesbxrudc 1 301 train
+ykeskyixfn 1 300 train
+ykfbdovwsx 1 300 val
+ykffsgyxht 1 300 train
+ykfllpyawg 0 300 train
+ykfqrgnyrf 0 300 train
+ykfrtfnike 1 300 train
+ykfxvqaqqj 1 300 train
+ykgdmawthl 0 300 val
+ykgfznxxut 0 300 train
+ykggdiaytx 1 300 train
+ykghcdqkvp 1 300 train
+ykghorblvy 1 300 train
+ykgnehbnuw 1 300 train
+ykgoozqdbb 1 300 val
+ykgszzfwhc 1 300 val
+ykgzryuskq 1 300 train
+ykhcpnbuzb 1 300 train
+ykhcxtzbwt 1 300 val
+ykhnuvnjsx 1 300 train
+ykieefmksb 0 300 train
+ykiewiehnr 1 300 train
+ykifgltuke 0 300 train
+ykiiuksurb 1 300 test
+ykinyieskq 1 300 train
+ykiwqdacfa 0 300 val
+ykjgusdgfq 1 300 val
+ykjhlmtadp 1 300 train
+ykjkqjsuao 0 300 train
+ykjpjpacui 0 300 train
+ykjsfgxhjz 1 300 train
+ykjtabqedc 1 298 train
+ykjunwlspi 1 301 train
+ykjzmevqcq 1 300 train
+ykjzvvvuen 1 300 train
+ykkcozldil 1 147 train
+ykkdulddle 1 301 train
+ykkfllphon 1 300 train
+ykkjiqblht 1 300 train
+ykkpbjflcs 1 300 train
+ykkzfqkqjx 1 300 val
+yklamzsdff 0 300 train
+yklcvwlqah 1 300 train
+yklkjjlpyj 1 300 test
+yklkldmmaq 1 300 train
+ykllxnnttm 1 250 train
+yklmhxqubh 1 300 train
+yklprotsym 1 300 train
+yklrylijjp 0 300 val
+yklswtnvxl 1 300 train
+yklvkyiclr 1 241 train
+yklzjpvmid 1 300 val
+ykmdurqwlu 1 301 train
+ykmdxsklpv 1 302 train
+ykmooonxqg 1 300 train
+ykmpcxevug 0 300 train
+ykmtnkqmyp 1 300 val
+ykmuojlwfy 1 300 train
+ykmwtovmhj 1 300 train
+ykmymblgap 1 300 train
+yknbjgksfg 1 300 train
+ykndktgoxa 1 300 train
+ykneefbtbm 0 300 train
+yknjhdbpbw 1 300 train
+yknlciphae 1 300 train
+yknmgzawhk 1 300 train
+yknneawkrz 0 300 train
+yknscdyrsd 1 300 train
+yknsqdrlxp 1 300 train
+ykntspvmky 0 300 train
+yknzoyqlrq 0 300 train
+ykoajsnlgp 1 300 train
+ykoaplaytg 1 300 val
+ykofirxynw 0 300 train
+ykonyxjpma 1 299 val
+ykopaoehpv 1 301 train
+ykorkocspc 1 300 train
+ykosowqjpf 1 300 train
+ykouzxtxmg 1 300 train
+ykovpgxmso 1 300 val
+ykowakejcq 1 300 train
+ykoygrizmu 1 300 train
+ykoyjjokze 1 300 val
+ykozgmxgir 1 300 test
+ykpatcwgia 0 300 train
+ykpbxgerzh 0 300 train
+ykpegpytyc 1 300 val
+ykpgrjrxwq 1 300 train
+ykpknkzrnk 1 300 val
+ykpkruwbaq 1 298 train
+ykplsvyhhh 1 300 train
+ykpndjgerb 1 300 train
+ykpoxfkwqr 1 300 train
+ykppdftcnh 1 300 train
+ykpvzfdqpw 1 300 val
+ykpwpxgzmm 1 300 train
+ykpwsmvlkk 1 300 train
+ykqiofjeak 1 300 train
+ykqkczfplf 0 300 train
+ykqyzktvdj 1 300 train
+ykreamglgw 1 300 train
+ykrepdrjiz 1 300 train
+ykrgpcmcqs 1 300 val
+ykriblqkol 1 300 train
+ykrluzjwlo 1 300 train
+ykrmfevwbv 1 300 train
+ykrsdobhuc 1 300 val
+ykrwyglcce 1 300 train
+ykscxihxya 0 300 train
+yksfbwqbqn 1 298 train
+yksfwtxgtk 1 300 train
+ykssflesmk 1 300 train
+yksywrwkvn 1 300 train
+ykszlrzvpv 1 298 train
+yktepvdvwi 1 300 train
+ykthscmdyi 1 300 train
+yktmulzkth 1 300 train
+ykttsmysmg 1 300 train
+yktubzmmhr 1 136 train
+yktykcrzfg 1 299 test
+ykugnijjww 1 301 val
+ykulchujxe 1 301 train
+ykulljhtgx 1 241 train
+ykulohytyb 1 300 train
+ykumgyaucv 1 300 train
+ykuolnotfr 1 300 train
+ykupgmofml 1 299 train
+ykupqdlrbj 1 300 train
+ykupvorlma 1 300 train
+ykvaigfqyf 1 300 train
+ykvbsndwvl 1 300 val
+ykvdmksqkf 1 300 train
+ykvdqsidoo 1 301 val
+ykvfnicmbh 1 300 train
+ykvtmkadzm 1 299 val
+ykvycavksr 1 300 train
+ykvzbilhls 0 301 train
+ykwbhuapcb 0 301 train
+ykwcfpxysc 1 300 train
+ykwdwrzeud 1 300 val
+ykwmoztmjl 0 300 train
+ykwntqpstj 1 300 train
+ykwqtkrjdq 1 300 val
+ykwuoenwjm 0 300 train
+ykwxtnnsxe 1 300 train
+ykxevvuzis 1 300 val
+ykxfnneiuq 0 300 val
+ykxhelvsnf 1 300 train
+ykxkiylank 1 241 train
+ykxozptfan 0 300 train
+ykxtsuhlmi 1 300 train
+ykxuygbjwe 0 300 train
+ykxykabmlr 1 300 train
+ykybgxsizu 0 300 train
+ykygmjhmvr 1 300 train
+ykysqrbthc 0 300 train
+ykywskdwlc 0 300 val
+ykzjpgztgg 1 240 train
+ykzlqzhsar 1 301 val
+ykzxldzubl 1 241 train
+ylaangorem 1 300 val
+yladcglzmb 1 300 train
+ylaenwriae 1 300 train
+ylasjinpme 1 300 train
+ylazuxnobr 1 300 val
+ylbcyozlzl 1 300 train
+ylbdflgawa 0 300 val
+ylbkdjcqkq 0 300 train
+ylbnoyagmj 0 300 train
+ylbpsomcpw 0 300 train
+ylbsnpuyhz 0 300 train
+ylceeolaka 0 300 train
+ylchjoutvx 1 300 train
+ylcnztxsjr 1 300 train
+ylcuvzkhke 1 300 train
+ylcvnbeqgr 1 300 train
+ylcwtghrqs 0 300 train
+ylczwgpaft 1 300 val
+yldborqatm 1 300 train
+yldekmqepu 1 301 train
+yldfeutgrz 0 300 train
+yldgfzjrjv 1 300 val
+yldjtbmsjp 1 300 train
+yldkxfflqg 0 300 train
+yldthdjgsg 1 241 train
+yldumgmxdy 1 301 train
+yldxabbdiq 1 300 train
+yldygzohgq 1 300 train
+yleaqdongd 1 300 train
+yledmqctba 1 300 train
+yleenlhjbp 1 300 train
+ylejsmgrhi 1 300 train
+ylenhjkaph 1 300 val
+ylenvwmdgo 1 300 train
+yletclsdwc 1 300 train
+ylffcpknaj 1 300 train
+ylflvrieum 1 299 test
+ylftubupki 1 299 val
+ylfyzjrdpt 1 301 train
+ylfzxydjrj 1 300 val
+ylhccejbcc 1 300 train
+ylhcqovdsb 1 301 train
+ylhdpswnhc 1 300 train
+ylhkjrbxag 1 300 val
+ylhlnpwihi 1 300 train
+ylhmpevhvm 1 300 train
+ylhojczpug 1 297 train
+ylhtvfyaff 1 300 train
+ylhtymvmbn 1 300 train
+ylhycocgxq 1 300 train
+ylhzfjddxq 1 300 train
+ylicdnlwlj 0 300 train
+yliohrnnxc 1 300 train
+ylitelxxnw 1 300 train
+ylitqpvnkm 0 300 train
+ylizslnwph 1 298 train
+yljecirelf 0 300 test
+yljgbwluei 1 300 train
+yljipymrle 1 300 train
+yljtkudtlc 1 301 val
+yljvtrnhlf 1 301 train
+yljwahrcdm 1 300 train
+yljxhuhnrl 1 300 train
+yljxqjrbzr 1 300 train
+ylkcocrgao 1 300 train
+ylkfhlvttf 1 300 train
+ylkkuykoon 1 300 train
+ylkmhzpmiu 1 299 val
+ylkwdyryjz 1 298 train
+ylkyuzglto 1 298 train
+yllayfmpsw 1 298 train
+yllbvhqvso 1 300 train
+yllhxirmbc 1 300 train
+ylljxmljof 1 300 val
+ylllmzzakg 1 300 train
+yllncwzjrl 0 300 train
+yllssouhyh 1 300 train
+yllyvtyztm 1 300 val
+yllztsrwjw 1 300 test
+ylmfzydomw 1 300 train
+ylmmizjyro 1 300 val
+ylmqodygsj 1 300 train
+ylnanwuydj 1 300 train
+ylnedgotuc 1 299 train
+ylnftkhwzr 1 300 train
+ylnjrxpxpv 1 300 train
+ylnmmdxhvq 1 241 train
+ylnrikymqj 1 300 train
+ylnrvzkfzw 1 300 val
+ylntmnbfvk 0 300 train
+ylnxonqvoi 1 300 train
+ylodvyyoen 1 300 train
+yloezmjgix 1 300 train
+ylojfrjptp 1 301 train
+ylojkopvcc 1 300 train
+ylozkpufem 1 300 train
+ylphpfrnxe 1 300 train
+ylpmpzlxhc 1 300 train
+ylpwhsaqih 1 302 train
+ylpxggckax 1 300 train
+ylpxrfntxq 1 300 train
+ylqclqfhlt 0 300 train
+ylqqzvhvng 0 300 train
+ylqucqmtbi 1 300 test
+ylrcrtupec 1 300 val
+ylrcxxqvgp 1 302 train
+ylrdassulc 0 300 val
+ylrhmdwtfz 1 301 train
+ylrhxxluza 1 300 train
+ylrmefvfji 1 147 train
+ylrtfsmfns 0 300 train
+ylrwkkpahy 1 300 train
+ylrylvqgol 0 300 val
+ylsbpywvnn 1 300 train
+ylshuopyht 1 269 train
+ylsjsqapsk 1 300 train
+ylsntjobpd 1 300 train
+ylsrifcgco 1 300 val
+ylsrifhwxj 1 300 train
+ylsumuqfbm 1 300 train
+ylsydbhexc 1 300 train
+ylsylaffmx 1 300 train
+ylszaejlgj 1 300 train
+yltadnnbus 1 300 val
+yltbmjvxrc 1 300 train
+yltdzmmmcg 0 300 train
+yltfmnpbam 1 300 train
+ylthivoaia 1 300 train
+yltmjvmuln 0 300 train
+yltojzqtuc 1 300 train
+yltulwrtgj 1 300 train
+yltuykiwju 1 300 train
+yluafczbjb 1 301 train
+yluezjhwsi 1 300 train
+ylurhxptpq 1 300 train
+ylvcyrvksk 1 300 train
+ylvfhvkyzf 1 300 train
+ylvppinesp 0 300 train
+ylvwdiwltu 1 300 train
+ylvwfqdbzf 1 300 val
+ylwfzfreyi 1 301 train
+ylwhnoufzp 1 302 train
+ylwhogmxug 1 300 train
+ylwizzuzgr 0 300 train
+ylwljpzqhq 0 241 train
+ylwmomyfex 1 300 train
+ylwrmmryxj 0 300 train
+ylwsshcmdn 1 300 val
+ylwtmwkbch 0 300 train
+ylwutulcuc 1 300 train
+ylxbybggyq 1 300 train
+ylxeiuviiz 1 300 train
+ylxleoxzcm 0 300 train
+ylxwcwhjjd 0 300 test
+ylxwegyfqw 1 300 val
+ylyledyasw 1 300 train
+ylysrvpnjg 1 300 val
+ylzjwghgts 1 300 train
+ylznlnmfeu 1 193 train
+ylzraxqvxa 1 300 val
+ylzubxyrrc 1 299 train
+ylzzdvlkuj 1 299 test
+ymakzkwcnq 1 300 train
+ymamryqeve 1 301 val
+ymamvlkhwp 1 298 train
+ymanbaspre 1 300 train
+ymanszorlf 1 300 train
+ymaodrvpvb 1 300 train
+ymapogefom 0 300 train
+ymaybcgwit 1 300 train
+ymbbsgxpvd 1 300 train
+ymbgywcfyz 1 297 train
+ymbkmmrqzg 0 300 val
+ymblnqqtcf 1 300 train
+ymbnmhldpf 0 300 train
+ymbonknkzs 0 300 val
+ymbritrbfg 1 300 train
+ymbxursskk 1 300 train
+ymbzijlqya 0 300 train
+ymcbihuzva 1 300 train
+ymcdoqvvys 0 300 train
+ymcilvyooo 0 300 train
+ymcircfnnm 1 300 train
+ymcjszkoss 1 300 train
+ymcncxjpjh 1 300 train
+ymcoajtkjo 1 300 train
+ymcvfyzhcz 1 301 val
+ymcwwtkkgs 1 300 train
+ymczlhhdts 1 300 train
+ymczljwweo 1 300 train
+ymdavcbwut 1 301 val
+ymdbtiintr 1 300 train
+ymddrgrdyg 1 299 val
+ymdgtoirvc 1 300 train
+ymdiqvvejf 1 300 train
+ymdlmmpaqc 1 300 train
+ymdmdaolrp 1 300 train
+ymdmzhjpbr 1 300 train
+ymdsgdwnao 1 300 train
+ymeiwtseqj 1 300 train
+ymemkrspej 1 300 train
+ymeryxmtlp 1 300 train
+ymexnukksc 1 300 val
+ymexqizhns 1 300 val
+ymfapgjrwa 1 300 val
+ymffqzbvfl 1 300 val
+ymfrgnrvfw 0 300 train
+ymfxlrnjup 1 300 train
+ymgcutrcwe 1 298 val
+ymgcxcfaav 1 300 train
+ymgdrjwlnl 1 240 train
+ymgggxwmbw 1 300 train
+ymghgdxsgx 1 300 train
+ymglpqkhap 1 300 train
+ymgovzgett 1 300 val
+ymgvkdwrag 0 300 train
+ymgzshhkxh 0 300 train
+ymhcjjdluu 1 299 train
+ymhcswkpyf 1 300 train
+ymhdircshe 1 300 train
+ymhdluaqbs 1 300 train
+ymhjpkeqpg 1 300 train
+ymhodhncvv 1 300 val
+ymhpvjycuo 1 300 train
+ymhrnywgtu 1 300 train
+ymiandkiqw 1 300 val
+ymicogqjss 1 300 train
+ymifiuwjkz 0 300 train
+ymifmtmhzf 1 301 val
+ymijzdifid 0 300 val
+yminaozrxr 1 300 train
+yminuwlmoh 1 300 test
+ymipumkknq 1 301 train
+ymiqjsomvk 1 300 train
+ymiwvlawuk 1 300 train
+ymiyovggln 1 301 train
+ymjdbbqnbz 1 300 train
+ymjduagjlt 1 300 train
+ymjemdzwgr 1 300 val
+ymjjbvuiko 1 300 train
+ymjqaywshs 0 301 train
+ymjqzdyhuz 1 301 train
+ymjrnwsjxt 1 300 train
+ymjvxsuvwc 1 300 test
+ymkojzsvxz 0 300 train
+ymkqlnvytm 1 300 test
+ymkzitswzy 1 300 train
+ymlcpjipid 1 300 train
+ymldbifpdy 1 300 train
+ymldmiugoc 1 300 train
+ymljujzbhf 1 300 train
+ymlpfhxujl 0 300 val
+ymlufvgeaj 1 300 train
+ymluqnquvv 1 299 val
+ymlvcyksmi 0 300 train
+ymlzpeialt 1 300 train
+ymlzuwmsnh 1 300 train
+ymmbthggse 1 300 train
+ymmfejsufe 1 300 val
+ymmfjllaxv 1 300 train
+ymmjbgxugw 0 300 train
+ymmnqndqbv 0 300 train
+ymmuvgjtdu 1 300 val
+ymmvxajlsa 1 298 train
+ymmwbxjncs 0 300 train
+ymmydrpuzj 1 300 train
+ymndxusjew 0 300 train
+ymnemmugtq 1 300 train
+ymngcysczs 0 300 train
+ymnsydjywu 1 300 train
+ymobnqqnmr 1 300 train
+ymoczhvuof 1 300 val
+ymofihdaqg 0 300 val
+ymokejlzja 1 300 train
+ymomsmsott 1 300 train
+ymonlsscid 1 300 train
+ymoymwnliw 1 300 train
+ymoyngystn 1 300 train
+ympfpodyoz 1 300 train
+ympiyvgshh 1 300 train
+ympkvkiyik 1 300 train
+ymprxvokzn 0 300 train
+ymqadbkafj 1 295 train
+ymqanfgdzx 1 300 train
+ymqblgelbr 1 300 train
+ymqdvsjnen 1 300 train
+ymqhdcydbu 1 300 train
+ymqkptzdex 1 301 val
+ymqmxopzrl 1 300 val
+ymqqzovouv 1 300 train
+ymqrvnmsfu 1 300 val
+ymqwbzoksj 1 300 train
+ymqyzuwhmb 1 300 train
+ymqzsqqths 1 300 train
+ymrascxblk 1 301 train
+ymrmphksju 1 300 train
+ymroaehhyq 1 300 train
+ymrtsywvhu 1 300 val
+ymsavxeowb 1 300 train
+ymsemcinsv 0 300 train
+ymsezwprtu 1 300 train
+ymsfmzuove 0 300 val
+ymsiuwjegn 1 300 val
+ymsjaeweul 1 300 train
+ymsluppqtn 1 300 train
+ymswdhnnyp 1 300 val
+ymsxaemyex 0 300 train
+ymtdzzysny 1 300 train
+ymtgjvuegz 1 300 val
+ymtjhtiigv 1 300 val
+ymtldlhboa 0 300 train
+ymtmbvkaud 1 300 train
+ymtnyoycif 1 300 train
+ymtoczsjxj 1 301 val
+ymtudfsdqg 1 301 train
+ymtyiuxmdh 1 300 val
+ymugvrlvsy 1 300 val
+ymugvyxuka 0 300 train
+ymuufhthca 0 300 train
+ymuuqysmgp 1 300 train
+ymuvfopqkj 1 300 train
+ymuvqvmgdi 1 300 train
+ymvfatwkdb 1 300 val
+ymvfoeroru 1 300 val
+ymvkwrzzhs 1 301 val
+ymvlpjmixv 1 300 val
+ymvnxhkfzv 1 300 train
+ymvwlbsntz 1 300 train
+ymvwuqdcgf 1 292 val
+ymwdcywzgm 1 300 train
+ymwfrwtprs 1 300 train
+ymwiptcyud 1 300 train
+ymwmhfiwmb 0 300 train
+ymwphmbxdp 1 301 train
+ymwpkjcyyd 1 300 train
+ymwylcuuec 1 300 train
+ymxbfmyinc 1 300 train
+ymxdlvykkz 1 300 val
+ymxibekbia 0 300 train
+ymxoovisri 1 300 train
+ymxxythqwp 1 300 train
+ymxzgpdxut 1 300 train
+ymyjtjywus 0 300 train
+ymysdylirs 0 300 train
+ymystbihvt 1 300 train
+ymyyxdqfwe 1 300 val
+ymzftqosgs 1 300 val
+ymzihxvcsy 1 298 train
+ymzvcjmyck 1 300 train
+ymzwamafmr 1 300 train
+ymzwfrpfkf 1 300 train
+ymzyznqinj 1 301 train
+ynaaolvwob 1 300 train
+ynacmelwch 1 300 train
+ynagdfijwy 1 298 val
+ynakjahkrw 1 300 train
+ynamsaxxgd 1 300 train
+ynavzkdewu 1 300 train
+ynaxskshcg 1 300 train
+ynaxsrtgzy 1 300 train
+ynbezuopca 1 100 train
+ynbhxgjllx 1 300 train
+ynbnxmfzpq 1 300 train
+ynbsesiomp 1 300 train
+ynbspbggvc 1 300 test
+ynbttnqakp 1 300 val
+ynbwjtcecf 1 300 train
+yncbodnton 1 300 val
+ynccraymmc 1 300 train
+yncexnnufk 1 300 val
+yncjoacwmk 1 300 test
+yncjzqgunr 1 300 train
+yncoipxvti 1 300 train
+yncqzlcggq 1 300 test
+yncxnjwxym 1 300 train
+yncystdauz 1 300 train
+ynddcglzps 1 300 train
+yndffhhryj 1 300 train
+yndrghtxff 0 300 train
+yndvuscznt 1 300 train
+yndxdaujmd 1 298 train
+yndzvnxazv 1 300 test
+yneeguhhlb 1 300 val
+ynegflbdmd 1 300 val
+ynekhoilas 1 300 train
+ynewefvqnl 1 300 train
+ynfgxeqzcv 0 300 val
+ynfhymizhm 1 299 train
+ynfingiplu 1 300 test
+ynfrgztswk 1 100 train
+ynfssrepte 1 300 val
+ynftzizqiu 1 298 train
+ynfuicslww 1 300 train
+ynfxdkfoki 1 300 train
+yngdmqhcqs 0 300 train
+ynghvptvre 0 300 train
+yngithmzvs 1 300 train
+yngjsarkwz 1 300 val
+yngxbkjjxj 1 298 train
+ynhaiegzaa 1 300 train
+ynhdroiwzr 0 300 train
+ynhfmtsvrl 1 300 val
+ynhjqzmhsx 1 300 val
+ynhjsiaakw 1 300 train
+ynhkjmcuwp 1 300 val
+ynhlniipmb 1 300 train
+ynhohievnt 1 300 val
+ynhpdkhtqp 1 301 train
+ynhqeprmqe 0 300 train
+ynhtodqdis 1 300 train
+ynhvrjwkme 1 301 val
+ynihpnkjej 1 300 val
+ynijgimcsg 1 301 train
+ynilamdpnj 1 299 train
+ynipfplgjt 0 300 train
+yniurterkt 1 300 train
+ynivollkxu 1 301 train
+ynjjwrepha 1 300 train
+ynjvlojwtp 1 300 train
+ynjvvsrtdm 0 300 train
+ynjwmnnpuu 1 300 train
+ynjzxsfmeu 1 300 train
+ynkfeiqbrm 1 300 val
+ynkzlkahux 1 300 train
+ynldmagrsz 1 300 train
+ynlefabotd 0 300 train
+ynlrpsatas 1 300 train
+ynlucsymjj 0 301 train
+ynlxxzgrhu 1 300 train
+ynmblzufwm 1 300 train
+ynmfzpkeqo 1 300 val
+ynmkfhspjo 1 301 train
+ynmluajwre 0 300 val
+ynmnuequho 1 300 val
+ynmoqcvvct 1 300 train
+ynmsruuzpf 1 300 val
+ynmzcjbbkp 1 300 train
+ynnajlthpb 1 300 train
+ynnannlllo 1 299 test
+ynnjufeezy 0 300 train
+ynnkeoxiin 1 300 train
+ynnlbhdrzg 0 300 train
+ynnmkiljvl 1 300 train
+ynnqqvtytl 1 300 train
+ynntrwpvzs 1 300 val
+ynnyprxahm 1 300 train
+ynoagzhbvv 1 300 val
+ynodpgvpid 1 300 train
+ynodvexihp 1 300 train
+ynoespylgv 1 300 val
+ynogcpcefa 1 299 train
+ynoiykjrte 1 300 train
+ynozpoxnfa 1 300 train
+ynpaetoemt 1 301 train
+ynpeusjisu 1 300 train
+ynpissovbs 1 300 train
+ynpoongamk 1 301 train
+ynppcctwbr 1 300 train
+ynppilmiac 1 300 train
+ynpqkrmuap 1 241 train
+ynpqudtiss 1 300 val
+ynpugkhxgo 1 300 train
+ynqrdngnqh 0 300 train
+ynqtruewyc 1 301 val
+ynqxpbravt 1 300 train
+ynrcgpktto 0 300 train
+ynrcyyhdhv 1 300 train
+ynrdjvymcr 1 300 train
+ynrjmyxmet 1 298 val
+ynrkmuoaza 1 300 train
+ynrpoipvnu 1 300 train
+ynrueopehk 1 300 test
+ynrxklhckd 1 300 train
+ynsdslueqg 1 300 train
+ynseigwnvz 1 300 train
+ynsfendaeo 1 300 val
+ynsgdkgriu 1 300 val
+ynsgxozvqo 1 300 train
+ynshyzzdzl 1 300 train
+ynslrzvjvr 1 300 train
+ynsrefiaen 1 299 val
+ynsxzcicxv 0 300 train
+yntahlxcmy 1 300 train
+yntefuwajz 1 300 train
+yntmrmymvb 1 300 train
+ynturvywbo 1 300 train
+ynubsysiyc 1 300 train
+ynubvckkhw 1 301 train
+ynuhpdugzb 1 300 val
+ynuhtuvbqw 1 300 train
+ynvaljmyhd 1 300 train
+ynvloqbgmx 0 300 val
+ynvntxasqt 1 301 train
+ynvppidwwa 0 300 train
+ynvpxietfh 1 300 val
+ynvybzsdzq 0 300 train
+ynvyvpzgzm 1 300 train
+ynwazhtsul 1 300 train
+ynwcgdzzni 1 300 train
+ynwiyowdcn 1 300 train
+ynwkehwkog 1 300 val
+ynwwziznik 1 300 train
+ynxanuqspl 1 298 train
+ynxepbdtwt 1 300 val
+ynxtcmvyyg 1 300 train
+ynxvliidxj 1 300 train
+ynycdheids 1 300 val
+ynyfaqaovv 1 300 train
+ynykatpaku 1 300 train
+ynymkksxoj 1 300 train
+ynypedjdwz 1 300 train
+ynytskwser 1 299 train
+ynyvhvjpnm 1 298 train
+ynyzjkvrxc 0 300 train
+ynyzrfdkkl 1 241 train
+ynzdaxmsch 0 300 train
+ynzgdmtfkr 1 300 train
+ynzhhssuov 1 300 train
+ynzljkqsvl 1 300 train
+ynzolwtlvl 1 300 train
+ynzrxkzsrr 1 300 val
+ynztieuxfb 1 300 train
+ynzvxqslbg 1 301 val
+ynzwgbmdee 1 300 train
+ynzwxnpypm 1 300 train
+ynzynktiub 1 300 train
+yoacoyokcw 1 300 train
+yoakhkhqqt 1 300 val
+yoanxwnwnm 1 300 train
+yoaqfuzblq 1 300 train
+yoaqyfmbjz 1 300 val
+yoavqsqobz 0 300 train
+yobblwxpsx 1 300 train
+yobhvyiqpb 1 300 train
+yobixzolgw 1 301 train
+yobjltufud 1 300 train
+yobpriadmu 1 300 val
+yobtwoswvo 0 300 train
+yobvrjelvc 0 300 val
+yocahznzrv 1 297 train
+yockutjyao 1 300 train
+yocpmbyics 1 300 train
+yoctthxssu 1 300 train
+yocvhsaovj 1 300 train
+yocwsovneg 1 300 train
+yoczycbudz 1 300 train
+yodcjewowy 1 297 train
+yodegwnuyb 1 300 val
+yodehqooku 1 300 train
+yodgvvydlo 1 300 train
+yodpvkboee 1 300 train
+yodsqrvmxe 1 300 train
+yodwhcmozz 1 300 train
+yodzdyolvp 1 300 train
+yoeaunelcg 1 300 train
+yoeetkfxec 0 301 train
+yoehsxkbuw 0 300 train
+yoejbudtlp 1 300 val
+yoejnwugvj 1 300 train
+yoemwsbpym 1 300 train
+yoetuixbsf 1 300 train
+yoeyhuymio 1 300 train
+yofexoziov 1 300 train
+yoffqpqaqy 1 300 val
+yofkcmhgyi 1 300 train
+yofsgydgvx 1 299 train
+yofsjzpnzd 1 301 val
+yofslrsdjt 0 301 train
+yofsoklcfd 0 300 train
+yoftemfgxk 1 300 train
+yofvgjzmcq 1 300 train
+yogcymnpen 0 300 train
+yogfpwugql 0 300 train
+yogfqjetvp 1 300 val
+yogmaygfmn 1 300 val
+yogmspvhtc 1 300 train
+yogpjufirz 1 300 train
+yogwjwlaof 1 300 train
+yogwowiwoa 1 300 train
+yohaqnqomk 1 300 train
+yohcyoltlz 0 300 train
+yohobtttsv 1 300 train
+yohqzjiecm 1 241 train
+yohtaqcczj 0 300 val
+yohtlpxaiq 1 300 train
+yohwxdbinf 1 298 train
+yoicqcpxgm 1 300 train
+yoijfacueg 1 300 val
+yoijornhmt 1 300 train
+yojalwzegt 1 300 train
+yojdtucwfm 0 300 train
+yojgeqpgoi 0 300 train
+yojgjueqta 1 300 train
+yojgmnfrdg 1 301 val
+yojhdxksqc 1 300 train
+yojralswul 1 300 train
+yojwggxziv 1 300 train
+yokajmlbkv 1 300 train
+yokjmkzsbx 0 300 val
+yokjxerejd 1 301 train
+yokvexmmmc 1 299 train
+yokwqbiqle 1 300 test
+yokyjcaotk 1 300 train
+yolffvkudx 1 300 val
+yolhxvcwxh 1 300 train
+yolnvonbdj 1 300 val
+yoluabhrjj 1 300 train
+yolzlyziso 1 300 train
+yomaonepsu 0 300 train
+yomiippvfx 1 300 train
+yomnebtmbn 1 300 train
+yomwtdkhks 1 300 train
+yonbqehwfn 1 300 train
+yondrqudlr 1 300 val
+yoneqqlkgt 1 300 val
+yonidwhplw 1 299 train
+yonjrmwwyr 0 300 val
+yontmxrffq 1 300 val
+yonubusscv 1 300 val
+yonuuzfcmd 1 300 train
+yonvjhtiar 1 300 train
+yonwpepytq 1 300 train
+yoobuqxbhk 1 300 train
+yoocuiqeyt 1 300 val
+yoojgzabto 1 300 train
+yoommvagdz 1 300 train
+yoonfdohwq 0 298 train
+yooowqpwwb 0 300 train
+yooqyvwymf 1 300 val
+yoorhdcrqk 1 300 val
+yoosbxmtow 0 300 train
+yooykjjott 1 300 train
+yopculwqir 1 300 train
+yoplrjioqq 1 300 train
+yoppzbfnkr 1 300 train
+yopvrjirpt 1 301 train
+yopvumsfnp 1 300 train
+yoqcqkanhx 1 300 val
+yoqggpqyhb 1 241 train
+yoqhrhsmcb 1 300 train
+yoqiighgse 1 300 train
+yoqjaeoruv 1 300 train
+yoqjvbeeui 1 300 train
+yoqlikjhqk 1 301 train
+yoqqryxlll 0 300 train
+yoqxsxfdyj 0 300 train
+yoredbmvzx 1 300 train
+yoricwdmlk 1 300 train
+yorjdzftot 1 300 train
+yosayeiizv 1 300 train
+yosddukuyy 1 301 train
+yosdhakmbb 0 300 train
+yososwkiui 1 300 train
+yospxfvzqo 0 300 val
+yoswposjpb 1 300 train
+yoszvhzqvz 1 300 train
+yotembrpny 1 301 train
+yotfywfvgf 1 300 train
+yotgejovqt 1 300 test
+yotglyuzfb 1 299 train
+yotsfuryir 1 299 test
+yottsrssfs 1 300 val
+yotwiwrhpz 1 300 train
+yotyalfqqv 1 300 test
+youadnurdb 1 300 train
+youeftepbm 1 300 train
+youfqhlyqt 1 300 train
+youicxhpxh 0 300 train
+youpqtkibf 1 300 train
+youvmkdlqq 0 300 val
+yovawyfamy 1 300 train
+yovgkcbonu 1 300 train
+yovjqxwytr 0 300 train
+yovkaudkhn 0 300 train
+yovlaucuku 1 300 train
+yovnutdnsu 1 300 train
+yovokpsxxl 1 301 train
+yovtdhhmpw 1 300 train
+yovyamzkcf 1 300 val
+yovyfuhpif 1 300 train
+yovyitpgdf 1 300 train
+yowasixubd 1 300 train
+yowcsdwvmw 1 300 val
+yowiltettl 1 300 train
+yowlrvmqyq 1 299 test
+yowlwsczjc 1 300 val
+yoxawtclly 1 300 train
+yoxdduxfrc 1 300 train
+yoxdseoukl 0 300 val
+yoxgvdnnzz 1 300 train
+yoxoltlhyj 1 300 train
+yoxpppbyft 1 300 train
+yoxsfbqpsv 1 300 train
+yoxxztmqsm 1 300 train
+yoydrpxsyf 1 299 test
+yoyhmxtrys 1 300 test
+yoyiltfgdm 1 300 val
+yoynfqcrni 1 300 train
+yoytbxcbqs 1 300 train
+yoyuttrzdw 0 299 val
+yozgvygwdr 0 300 train
+yozmmpwapf 1 300 train
+yozvpkpnge 1 299 train
+ypaaobcnum 1 300 train
+ypabocwtfa 1 300 train
+ypanvoaglt 1 300 val
+ypaoqhyepq 1 300 train
+ypapiuwrst 1 300 train
+ypasdmkmuv 0 300 val
+ypavsvctpq 0 301 train
+ypaxbuazvj 0 300 train
+ypaydtceve 1 300 train
+ypbaqdannl 1 300 train
+ypbeauvuwm 1 301 train
+ypbjcbjhyp 0 300 train
+ypbjlvmiug 0 300 train
+ypbknxvoal 1 300 train
+ypblvvnzoq 1 301 val
+ypbmqrpmiv 1 300 train
+ypbmxliaky 1 300 train
+ypbnyofvxs 1 301 train
+ypboljepyk 1 298 train
+ypbqppidbz 1 300 train
+ypbtpunjvm 0 299 test
+ypcdqduufa 0 300 train
+ypcdzwfjso 1 301 train
+ypcffabslt 1 297 val
+ypcfjnfqfw 1 301 train
+ypchqlxdei 0 300 train
+ypcopqcgim 1 300 train
+ypcpvwtrnm 1 300 train
+ypcqakjcqp 1 300 train
+ypcvlrztkx 1 300 val
+ypcwodkcdr 0 300 val
+ypcxerryjr 1 301 train
+ypcygoytaa 1 300 train
+ypczasodgz 1 301 train
+ypddjvcfwh 1 300 train
+ypdinkplos 1 300 val
+ypdivhefwt 1 300 train
+ypdrlcsozk 1 300 train
+ypdsvbblgw 1 300 val
+ypdtvxzfzt 1 300 val
+ypducsyphm 1 300 train
+ypeprfeymg 1 300 train
+ypepsyuwmo 1 300 train
+ypepvrdeij 1 300 train
+ypergrhaui 1 300 val
+ypeuoqwgrf 1 300 val
+ypewpvpfmk 0 300 train
+ypffenibzl 1 301 val
+ypfigpdppq 1 300 train
+ypflceurxq 0 300 train
+ypflzahovn 1 288 train
+ypfmelkzak 1 300 train
+ypfnxatrmi 1 300 train
+ypfolrialc 1 300 train
+ypfrjxyday 1 240 val
+ypfvrtqjaq 1 302 train
+ypfyygrbke 1 300 train
+ypgapxpqug 0 300 val
+ypgayhhaxx 0 300 train
+ypgbeovnag 1 300 train
+ypgfmpzdrb 1 300 train
+ypgjntxqmy 1 300 val
+ypgwdqikol 1 301 train
+ypgxxyvbha 0 300 train
+ypgynzbshp 0 300 train
+yphbsgjuwt 1 241 train
+yphjcxkhmo 1 300 val
+yphkvzusyo 1 302 train
+yphlxspgdp 1 300 train
+yphugundor 1 300 train
+yphzqufolm 1 99 train
+ypiecvleod 1 300 val
+ypielmgegz 1 299 test
+ypigvanjor 1 297 train
+ypikcfaegw 1 300 val
+ypiobsfhuv 1 300 train
+ypisprdfyz 1 301 train
+ypiumyzmlj 1 300 train
+ypixsaibtz 1 300 train
+ypiyxaiqac 1 249 train
+ypjbhizfxy 1 241 train
+ypjdcifgvb 1 300 train
+ypjezfgmqk 1 300 train
+ypjqupfwcz 1 300 train
+ypjratctiq 1 300 train
+ypjrurkeza 1 300 val
+ypjthlvxsd 1 300 train
+ypjxfhnvur 1 300 val
+ypjxnxtytu 1 300 train
+ypkbiuyugr 1 300 train
+ypkcsluuay 1 301 train
+ypkcxputdw 1 300 train
+ypkeecgvpe 1 300 train
+ypkehhhckj 0 300 train
+ypkkcwseij 1 300 train
+ypklhwxhbc 0 300 train
+ypkqzogujw 1 300 train
+ypkrgcqvvw 1 301 train
+ypkrmzgccg 1 301 train
+ypksowvcfo 0 300 train
+ypktxlvsvi 1 300 val
+yplgmdzacb 1 300 val
+ypllnqocoj 1 300 train
+yplnlgkkxh 1 300 val
+yplytzpnam 1 300 val
+ypmgblojth 0 300 val
+ypmqznhogq 1 300 train
+ypmtmksnco 1 300 val
+ypmwyxlfvn 1 300 train
+ypnersinol 1 300 train
+ypngjtpxkg 1 300 train
+ypnktdctqh 1 300 val
+ypoadpyltn 1 298 train
+ypolxhillo 0 300 train
+yponqyxmdd 1 300 val
+ypozqwjikr 1 300 train
+yppgxadshy 1 301 train
+ypppdprahe 1 300 val
+yppsohptcm 0 300 train
+yppsrmyyfr 1 300 train
+yppssmexwg 1 300 train
+yppwksjuui 1 300 train
+yppybofyww 1 299 train
+ypqjxdwawy 1 300 train
+ypqsxalhkw 1 302 train
+ypqxbbydxe 1 300 val
+ypqzrivawi 1 300 val
+yprcjxgyro 1 300 val
+yprdarrkit 1 300 train
+yprhthcacq 1 300 train
+yprmkhffdi 1 300 val
+yprnmqkhga 1 300 train
+yprqkgcoid 1 300 train
+yprsoygtjn 1 136 train
+yprxcbpmaj 1 241 train
+yprxtgidkk 1 300 train
+ypsbicsrsf 1 300 train
+ypsdsqjjor 1 299 train
+ypsfvpanpn 1 300 train
+ypsgzbgbaz 1 300 train
+ypskfnxajx 1 301 train
+ypskjzncjy 1 300 train
+ypskxfumwo 1 299 train
+ypslvqfsrd 1 300 train
+ypsmruzzyt 1 300 val
+ypsqgodnrn 1 300 train
+ypsydrqqsl 1 125 train
+yptchajnvb 1 300 test
+yptpbyqgpf 1 300 val
+ypuexglyao 1 300 train
+ypufjcamul 1 300 test
+ypugeazvqo 1 300 train
+ypupzqdqla 1 300 train
+ypusimvlbm 1 300 train
+ypuslvumzk 1 301 train
+ypuwnoxnrj 1 301 val
+ypvertbbvx 1 300 train
+ypvmdghkwu 0 300 train
+ypvpgclafl 1 300 train
+ypvxmggbtj 1 301 train
+ypwbumtmcr 1 300 train
+ypwlfjvmwm 1 300 train
+ypwtpngnyu 1 300 train
+ypwvtnpygr 1 300 train
+ypwvvludad 1 300 train
+ypwxcrdjqs 1 300 train
+ypwymmnpxn 1 300 val
+ypxahkmham 1 299 train
+ypxcqfuodr 1 301 train
+ypxodnvntz 1 300 train
+ypxqtsvhyj 1 269 train
+ypxshhnywf 1 301 train
+ypxtnfpilb 1 300 train
+ypxvdremxw 1 300 train
+ypyibrpbpv 1 298 train
+ypyjurihek 1 300 train
+ypyrgihjbj 1 300 train
+ypyvopaeag 1 241 train
+ypywphjfgg 1 300 train
+ypzbqkypyc 1 300 train
+ypzcmddqgg 1 300 train
+ypzetakuym 1 300 train
+ypzhswhskq 1 300 train
+ypzjptvwvm 1 300 test
+ypzkiyoaap 1 300 train
+ypzucjxgjo 1 299 train
+ypzxxadhqx 0 300 train
+ypzynpqiga 1 299 train
+yqahpmrcmp 1 300 test
+yqahqscioc 0 300 train
+yqaivhilql 1 300 val
+yqakecshzh 1 300 val
+yqaoluahjl 0 300 train
+yqaswwaprk 1 300 train
+yqauackjci 1 299 test
+yqazucouzj 1 300 train
+yqbdslceau 1 300 val
+yqbgyyybpi 1 298 train
+yqbmjafzyx 1 300 train
+yqboacfobj 1 300 train
+yqbpeuujkw 1 269 train
+yqcafhtlyi 1 300 train
+yqccmdradp 1 297 val
+yqcfpwqlsl 1 300 train
+yqcgxgwuvj 1 300 train
+yqcgxihpgq 1 300 train
+yqcitynexv 1 300 train
+yqckmrgdyp 1 300 train
+yqcmdlkgkt 1 301 train
+yqconfhxnn 1 297 train
+yqcoukdgxl 1 300 val
+yqcrvbwnat 0 300 train
+yqcwvpwdpc 1 300 train
+yqczfdezmp 1 300 train
+yqdjxjidnm 1 300 train
+yqdngiiems 1 300 val
+yqdobkayqg 1 300 train
+yqdtywzxaf 1 300 train
+yqdxmdinok 1 300 train
+yqdyhlwlqf 1 300 train
+yqeelsyrpt 1 99 train
+yqejcaobin 1 300 train
+yqescuwrxz 1 300 train
+yqetdxwkul 1 300 train
+yqewegbqos 1 300 train
+yqewzluxoe 1 300 val
+yqfcxtwrkb 1 300 train
+yqfimczujy 1 300 train
+yqgamvwzxb 1 300 val
+yqgeblkngb 1 300 train
+yqgerdayhc 1 300 train
+yqgqmotfmg 1 100 train
+yqgwvahoax 1 300 train
+yqgzdgznfc 1 300 val
+yqhjvukvkh 1 300 train
+yqhkzmzvng 1 300 train
+yqhouqakbx 1 300 test
+yqhpyvyngk 1 300 val
+yqhpyzqlor 1 300 val
+yqhqpwrhvd 1 300 train
+yqhsocmfqo 1 300 train
+yqhtjglvdl 1 300 val
+yqiccklfqt 1 300 train
+yqiiwktalz 1 300 train
+yqijncscrf 1 300 train
+yqizkddidb 1 300 train
+yqjajjeyyb 1 300 train
+yqjaqwbhoo 0 300 val
+yqjaubfofy 0 301 val
+yqjbedxnlk 1 300 val
+yqjdkqdogp 1 298 train
+yqjkwkezbu 1 300 train
+yqjmouyxbr 1 300 train
+yqjnyjbaeo 0 300 train
+yqjuzpypwe 1 300 train
+yqjytvxqil 1 300 train
+yqjzsdjqiv 1 301 train
+yqkabfjjrp 1 301 val
+yqkabqkadk 1 300 train
+yqkdlpvcpp 1 300 train
+yqkemjpdux 1 300 train
+yqkfscfsfy 0 300 train
+yqkkmzohhv 1 300 train
+yqkmybbdlj 1 301 train
+yqkoxbdqih 1 300 train
+yqkpdvlusp 1 300 train
+yqkpzdxzri 1 300 val
+yqkqtmrpqf 1 301 val
+yqkwefxhmi 1 300 train
+yqkyxumanc 1 302 train
+yqlfjggioi 1 300 val
+yqljgxovkg 1 300 train
+yqllrwfpxz 1 300 train
+yqlojrwakg 1 300 test
+yqlpnxuzpc 1 300 train
+yqlqxrjdby 1 300 train
+yqlrcdofwr 1 300 val
+yqlritzwvc 1 300 train
+yqlryxbwhh 1 300 train
+yqlthjdmys 0 300 train
+yqltzypccg 1 301 train
+yqlussxvno 1 300 val
+yqmbkopwif 1 300 train
+yqmvwtmood 1 300 train
+yqnhauoluy 1 300 train
+yqnijtoxdk 1 301 train
+yqnjgbvhuh 1 300 train
+yqnnusqlwn 1 300 val
+yqnpxgpago 1 300 val
+yqnsdfwelt 0 298 train
+yqnsluwztq 1 300 train
+yqoaowymbr 1 269 train
+yqohyqqxmx 1 300 train
+yqomslmjpz 0 300 val
+yqoomcmxul 1 300 train
+yqovednfti 0 300 train
+yqpjnpjuap 1 300 test
+yqpqfyuwfy 1 300 train
+yqpujtlyig 1 300 train
+yqqarnkigp 1 300 val
+yqqcwbddnm 1 302 train
+yqqikzhwzg 1 300 val
+yqqokezxvw 0 300 train
+yqqoriksmt 0 300 train
+yqqwycbfqn 1 300 val
+yqrgmyulig 1 301 train
+yqrgyckggl 0 300 train
+yqrlxjjjko 1 300 train
+yqrvigicij 1 300 train
+yqrxlgxaqv 0 300 train
+yqryuzpaff 1 298 train
+yqryxbyppi 1 300 train
+yqsabhqeyd 1 300 train
+yqscmfaaks 1 300 train
+yqsdpjteec 0 300 train
+yqsgugcfcx 1 300 train
+yqskavzmmr 1 300 train
+yqskbuyllt 1 300 train
+yqslfoohsi 1 300 train
+yqswyygsah 1 300 val
+yqtadojbpz 1 300 train
+yqtbeidtzs 1 301 train
+yqtgcggwvr 1 136 train
+yqticbioux 1 300 train
+yqtsfpzukc 1 300 train
+yqtszzipnj 1 300 train
+yqtyagzqgt 1 300 val
+yquajckjml 1 299 train
+yqvaemyakx 1 298 train
+yqvckgoaai 1 300 train
+yqvewalsaf 1 300 train
+yqviqczmsw 1 300 train
+yqvjeiulqp 1 300 train
+yqvlqmkyip 1 300 train
+yqvlybfhbk 1 300 train
+yqvrohvzar 1 300 val
+yqvstvfjjo 1 300 train
+yqvsxlrxmb 1 300 train
+yqvyriemkl 1 300 train
+yqwcvpjeuw 0 239 val
+yqwgyexgfd 1 300 train
+yqwjqmskty 0 300 train
+yqwqzvscvv 1 298 train
+yqwqzzyjyv 1 300 train
+yqwtwlkabn 0 298 train
+yqwuzxcegw 1 300 train
+yqxdkrykvi 1 299 train
+yqxejuawyj 0 300 train
+yqximgmtgv 0 298 train
+yqxvagbqzw 1 300 train
+yqxynworvb 0 301 train
+yqyabvopub 1 300 train
+yqybyqxnze 1 300 train
+yqyleqfarb 1 300 train
+yqylrfhnrx 1 300 train
+yqyvgsyeof 0 300 train
+yqywawhrmt 1 300 train
+yqziqyqqqc 1 300 train
+yqznxarvwf 1 241 train
+yqztaacvao 0 301 train
+yqzwnxmbbt 1 241 train
+yqzzqvlrbr 1 300 val
+yralryvgnj 1 300 train
+yraoqjfcmr 0 300 train
+yraqiglxsz 1 300 train
+yraqiushkq 1 300 train
+yratcfatzm 1 300 train
+yravyvyzbg 1 300 train
+yraysfvtgv 1 301 train
+yrbouocjws 1 300 val
+yrbpgzhhwk 0 300 val
+yrbtadauuh 1 300 train
+yrbxenuxei 1 300 train
+yrbxmchxsm 1 300 val
+yrbyydsxdx 1 241 train
+yrcfwdywhc 1 300 train
+yrcjjmhwce 1 300 test
+yrcqbjfsal 1 300 train
+yrcsecijnz 1 300 train
+yrctrdwupi 1 300 train
+yrcuxosiif 1 300 train
+yrcwgrgeoa 1 300 train
+yrcwyybknj 0 300 train
+yrdazpxvpa 1 300 val
+yrdcwjjdge 1 143 train
+yrddygheiw 1 298 train
+yrdgvugcnm 1 300 train
+yrdknlvdnd 1 300 train
+yrdllbecgk 1 299 val
+yrdpvwjgvz 1 300 train
+yrdqoqggkh 1 300 test
+yrdrzkpxgz 0 300 train
+yrehvulczu 0 300 train
+yrekonvkib 0 300 train
+yrekvyyjog 0 300 train
+yreslhphmf 1 301 train
+yrfdimuwhc 1 300 train
+yrflznnutj 0 300 train
+yrfneracbq 0 300 val
+yrfqdptmsq 1 300 train
+yrfrmzgdrz 1 300 val
+yrgjgdpufu 1 299 train
+yrgjkxcrlw 0 300 train
+yrgkqjuxzp 1 300 train
+yrgmgkosmx 1 300 train
+yrgnvwinlk 0 300 train
+yrgojuxsmo 1 300 train
+yrgqagngao 1 301 val
+yrgsvandkl 0 300 val
+yrgsxrlljc 1 300 train
+yrhgxkegbq 1 300 val
+yrhgxwhrco 1 300 train
+yrhliynmkj 1 300 train
+yrhotuhkrl 1 300 val
+yrhsxrpdpc 1 299 train
+yrihnhjrjs 1 300 train
+yriiyaabau 1 300 train
+yriqqpcbpx 1 300 train
+yritxcffnz 1 300 train
+yrivmbpotx 1 300 test
+yriyghhybl 1 300 train
+yrjecewwtk 1 300 val
+yrjeltmcji 1 300 val
+yrjksklxbi 1 300 val
+yrjsaimbjq 1 300 train
+yrjtmqavvb 1 300 train
+yrjwwpysid 1 302 train
+yrjxewoxgb 1 300 train
+yrjyvgmfzc 1 300 train
+yrkcwbsofn 0 300 train
+yrkibdyumv 1 300 train
+yrkksihbpx 1 300 val
+yrklrcruwf 1 300 train
+yrkqvzrkmu 0 300 train
+yrkrqrbczq 1 300 train
+yrldnkponb 1 300 train
+yrljamdgxr 1 300 train
+yrlmslqybr 1 300 val
+yrlogqcteq 0 300 val
+yrltmjuykv 1 300 train
+yrlwyddogp 1 300 train
+yrmbwlxunm 0 300 val
+yrmioyrocv 1 300 train
+yrmktwrbqq 1 300 val
+yrmoebethm 1 300 train
+yrmtemvrfu 0 300 train
+yrmuznkgts 0 300 train
+yrmzjagwmb 1 300 train
+yrnbnbxftm 1 300 train
+yrndatprlv 1 300 train
+yrnewooafn 1 300 val
+yrninonaol 0 300 train
+yrnorsityu 1 300 train
+yrnuprgdpn 1 300 train
+yrnvshtcbz 1 300 train
+yrnvzuotht 1 241 train
+yrnzzsbvia 0 300 train
+yrohiammwh 1 300 train
+yronlutbgm 0 300 test
+yrooqplagb 1 300 val
+yroscbkzmd 1 300 val
+yrotnpazhr 1 300 train
+yroublwegz 1 300 train
+yrpagbqdsd 1 300 train
+yrprjvwpaz 0 300 train
+yrpuhyvhsu 0 300 val
+yrpxehbypm 1 301 train
+yrqgyiaksi 1 136 train
+yrqhcjnpix 0 300 train
+yrqofgvsca 1 300 train
+yrqqinbasv 1 300 train
+yrqzdvdhuw 1 301 val
+yrqzihiahf 1 300 val
+yrrexbomyi 1 300 train
+yrrppiaptl 0 300 train
+yrrrlagaet 1 300 train
+yrrtbsieyq 1 297 train
+yrrzepqsoz 1 300 val
+yrrzmcwivc 1 249 train
+yrsbfoefjk 1 300 train
+yrsdwjvmlv 1 300 train
+yrsmztkuqj 1 300 train
+yrsnudirsg 0 300 val
+yrspgjmqgh 1 300 train
+yrstgeonav 1 300 train
+yrswxzgdqr 1 300 train
+yrsxariopx 1 301 val
+yrszoojrxf 1 300 train
+yrtcjqtyuw 1 300 val
+yrtebwifno 1 300 test
+yrtibhaasz 1 299 train
+yrtmsmulbj 1 300 val
+yrtpcmtext 1 300 val
+yrtrhsvvjm 1 300 val
+yrtrmtywtb 1 300 train
+yrtugrkbwc 1 300 val
+yrtwtsrotm 1 300 train
+yruaoufmrp 1 300 train
+yrukazqmaq 1 300 train
+yrurollijb 1 300 train
+yrustprntr 1 299 val
+yruujqxhgk 0 300 train
+yruwgnhqlg 1 300 val
+yruymevbiz 1 300 train
+yruzhimaof 1 300 val
+yrvcgqpwau 1 300 train
+yrvmzmyqpw 1 300 train
+yrvrxrojgw 1 300 train
+yrvsabidav 0 300 train
+yrvxcycnwf 1 300 train
+yrvypgjvzl 1 300 train
+yrvzgvldop 0 300 train
+yrwhyhmzwi 0 300 val
+yrwjziewkj 1 300 train
+yrwosofwuf 0 300 train
+yrwxpjyvwm 1 300 train
+yrxageuzss 1 299 test
+yrxljghbmn 0 300 test
+yrxmrhbmsj 0 300 train
+yrxnqqjvrc 0 300 train
+yrxpbiicpo 1 300 train
+yrxqztbajr 1 298 train
+yrxuskqchf 1 300 train
+yrxxdadzac 1 301 train
+yrymtnnopv 1 300 train
+yrynjympop 1 301 val
+yrynnrtawa 1 300 train
+yryrszdkxb 1 288 train
+yryscwqjbf 0 300 train
+yryxkrwwql 1 300 train
+yrzaoivslh 1 300 val
+yrzgpibjkt 1 300 train
+yrzinpovyj 1 300 train
+yrzjrpkkei 1 300 val
+yrzjwztyjr 1 300 train
+yrzoaaycwd 1 300 train
+yrzunbqjiy 0 300 train
+yrzzoardje 1 300 train
+ysaarvtzgi 1 300 train
+ysabcaidhs 0 300 train
+ysabskzckv 0 300 val
+ysakocwmbf 0 300 train
+ysavazacem 1 300 train
+ysbahgypze 1 300 train
+ysbcvbckgh 1 300 train
+ysbfvikpfz 1 300 train
+ysbgplvwzh 1 300 train
+ysbpkuhzto 1 300 train
+ysbqseiwhc 1 300 val
+ysbseyhvhf 1 294 train
+ysbuxhjydp 1 300 train
+yscagmzvtf 1 300 train
+yscdezmotf 1 300 train
+yscvcoiuzq 1 300 train
+ysdetfdncg 1 300 train
+ysdfqdszoa 1 300 val
+ysdnlwofrn 1 300 val
+ysdswiqpmu 1 300 train
+ysdtdauppf 1 300 train
+ysdvcfbgto 1 300 train
+ysdyojsplg 0 300 train
+ysebpsmwpk 1 300 train
+ysefdimaau 1 300 train
+ysefhwaftq 0 301 train
+ysemreodsi 1 300 train
+ysevrzcrqr 0 298 train
+ysfgbfonju 0 300 train
+ysfhasicov 1 300 train
+ysfotvgdcm 1 241 train
+ysfxwnwgst 1 300 train
+ysgcmjcxva 0 300 train
+yshalcxbhe 1 300 val
+yshevqbvaj 1 300 train
+yshpmjclhw 1 296 train
+yshsrejbbq 1 300 train
+yshvncenxj 1 300 val
+yshxrajnxs 1 300 train
+ysicjrfikh 1 301 train
+ysigamxwoa 1 301 train
+ysiqanpxbt 1 300 train
+ysiqserurg 1 300 train
+ysiuzkgqlm 1 300 train
+ysiwrayfqf 1 299 train
+ysjhmhyvzi 1 300 train
+ysjnxxxycu 1 300 train
+ysjtkateqr 1 300 train
+yskcbgayhp 1 299 val
+yskccmbywb 0 300 train
+yskdptujaf 1 300 train
+ysklybotzy 0 300 val
+yskmtdayph 1 300 train
+yskzlzgiic 1 301 val
+yslbdrfmcd 1 300 train
+yslgjgzgqu 1 288 train
+yslktuwjql 1 300 val
+yslqfihokq 1 300 train
+yslrgttmvl 1 300 train
+ysmjhldryi 1 300 val
+ysmngwveyb 1 300 val
+ysmoxttsnw 1 300 train
+ysmqnrhmqj 1 300 train
+ysmsrltpvz 1 300 train
+ysnepsntpe 0 300 train
+ysnktfiiog 1 300 train
+ysnkzbctio 1 300 train
+ysnsmafhtk 0 300 train
+ysnvafzzji 0 300 train
+ysoblyvoyj 1 299 test
+ysoervdykl 1 298 train
+ysoexgdorl 1 269 train
+ysolveufbo 1 300 train
+ysovknigcl 1 300 train
+yspkuuwaim 1 300 train
+ysqbnccstr 1 300 test
+ysqlnjplhw 1 300 train
+ysqtditqnb 1 300 train
+ysqvflesvi 1 300 val
+ysqwcmfsrm 1 301 train
+ysqyvsuwkr 0 300 train
+ysrbwffcmr 1 302 train
+ysrddknlfm 1 300 test
+ysrngkogjl 1 300 train
+yssihfjync 1 288 train
+yssikhuetw 0 301 train
+yssjefyssu 1 300 train
+yssjgsuzbh 1 300 val
+yssklekbzq 1 300 train
+ysslazhvti 1 301 train
+ysspxnqqwh 0 300 val
+yssqkfetmn 1 300 val
+yssrddqfer 1 300 val
+ysstiajdfk 1 299 test
+ystdtnetgj 0 300 test
+ysudplzcag 1 300 train
+ysudveoube 1 300 train
+ysueqdisdo 0 300 train
+ysumyetkbb 1 300 val
+ysunoibjwc 1 300 train
+ysuomeesjp 1 300 train
+ysuqtgonsp 1 300 train
+ysusazdgmq 1 301 train
+ysusmmrcgd 1 300 val
+ysvcbbhzqj 1 301 val
+ysvcdnwgkx 1 300 val
+ysvgsparnh 1 300 train
+ysvhtnedha 1 300 train
+ysvisqifhf 1 300 train
+ysvlcovwun 1 300 train
+ysvogisftd 1 300 train
+ysvrdqpdwy 0 300 train
+ysvuiysbns 1 241 train
+ysvuzamals 1 300 train
+ysvweqfkll 1 292 val
+yswdlardcq 1 298 train
+yswtkelyfc 1 298 train
+yswvsfkbwx 1 300 val
+yswyaxvzkh 1 300 train
+ysxdwhjpfm 1 300 train
+ysxikzbbfb 1 300 train
+ysxrtuqiyx 0 300 train
+ysxtcdphlj 1 300 test
+ysxugdbdbg 1 300 val
+ysybimmzvv 1 241 train
+ysydozghlo 1 300 train
+ysygzsbwen 1 241 train
+ysynwbmiwq 1 300 train
+ysypfjjwsz 0 300 train
+ysythqqvyp 0 300 train
+ysyxejcswo 1 300 train
+yszbymxuip 1 300 train
+yszcllgrcr 0 300 train
+yszcpuoxam 1 300 train
+yszddvvtiy 1 241 train
+yszibcryti 1 300 val
+ytaajirkez 1 300 train
+ytaifkeiky 1 300 val
+ytaitemmic 1 300 train
+ytajdmfljr 0 301 train
+ytapmohqiw 0 239 train
+ytaprclkkd 1 241 train
+ytaqqmpuyw 1 298 train
+ytauhwmgim 1 300 train
+ytaxjwdfjw 1 300 val
+ytayculvny 1 300 val
+ytaylxrtvz 1 300 train
+ytazsgdpao 1 300 train
+ytbdhpfngo 1 298 train
+ytbdlyinfq 1 300 train
+ytbicfuwuh 1 300 val
+ytbvnzwcpp 1 239 train
+ytcfrfpohz 1 301 train
+ytcfwrgelg 1 301 train
+ytchflkjeh 1 300 val
+ytcjisqggd 1 300 train
+ytckgsopyh 1 298 train
+ytczdtiybq 1 300 val
+ytddugrwph 1 300 test
+ytdfyhyoyk 1 300 train
+ytdgresxbr 1 301 val
+ytdhuleksj 1 300 train
+ytdjtloaog 1 300 val
+ytdmacrssb 1 300 val
+ytdmgvfbsu 1 300 train
+ytdxwnikwe 1 300 train
+ytecrghdxg 1 301 train
+ytekobkixs 1 300 val
+ytelxepaun 1 300 train
+yteopgxjsb 1 297 train
+ytetwkesro 1 300 train
+ytfngzjnfm 1 298 train
+ytfpnwzega 1 298 train
+ytfsmudptx 1 255 train
+ytfzfftuga 1 300 train
+ytgakahgek 1 300 test
+ytgmhlwzhg 1 300 train
+ytgrwnrhdo 1 300 train
+ytgsnahajr 1 300 train
+ytgzwdisst 1 300 train
+ytgzznajup 0 300 train
+ythanuiomy 1 300 train
+ythqriczal 0 290 train
+ythtidouho 1 300 train
+ytiazhnrpd 1 300 train
+ytibwyntyz 1 300 train
+ytihioplhw 1 300 val
+ytikdaekqt 1 239 train
+ytikzhctma 0 300 train
+ytitoevzjx 1 300 val
+ytjujtfzbm 1 300 train
+ytjuvhrbav 1 300 train
+ytjwmglptg 1 300 train
+ytjxjdxmox 0 300 train
+ytkjkyjeei 1 300 train
+ytksejgliy 1 300 train
+ytljkwpban 1 300 val
+ytljvippwv 1 300 train
+ytlsdvrxfr 1 301 train
+ytlsleqsjr 1 300 train
+ytlvbifwgf 1 300 val
+ytmdcuxbcd 1 300 train
+ytmjzraeju 1 300 val
+ytmksofadn 1 300 val
+ytmoadhnnk 1 300 train
+ytmvaiukhh 1 301 train
+ytmverigih 0 300 train
+ytmvmpzgvq 1 300 train
+ytnhrbjgby 1 300 val
+ytnswbkmnx 1 300 train
+ytnylrosdc 0 300 train
+ytoamycnxq 0 300 train
+ytobcnddoj 1 300 train
+ytoghswfjl 1 300 test
+ytopzxrswu 1 300 test
+ytoqdjfrtl 1 300 train
+ytoqfjghfw 0 241 train
+ytowjkzvnz 1 299 train
+ytowqhkwnk 0 300 val
+ytpgtyrydb 1 241 train
+ytphubfbkc 1 300 val
+ytpiyuxhsl 1 300 val
+ytpvrulgmy 1 298 train
+ytqbluftbg 1 300 train
+ytqeurhxgu 1 300 train
+ytqhdzqdjd 0 300 train
+ytqlicmjsr 1 300 val
+ytqnoxsags 0 300 train
+ytqoqvjpek 1 300 val
+ytqsgduhqh 1 301 train
+ytqsgriblt 1 300 train
+ytquowarbu 1 300 train
+ytqwyptjpd 1 300 val
+ytrcqylcni 1 300 train
+ytrdwmsacz 0 301 train
+ytrlxthbal 1 300 train
+ytrmknbqpl 1 300 val
+ytrqamfjzr 1 300 train
+ytrqldbuof 1 300 train
+ytrwwrzzek 1 300 train
+ytrypszvxv 1 299 train
+ytsfxbmfje 1 300 train
+ytslutpvpu 1 300 train
+ytspqkjgnc 1 300 val
+ytsrcfmeos 1 300 val
+ytsrlchuzu 1 301 train
+ytssyibqre 1 300 train
+yttaoecvfy 1 300 train
+yttbwuxssf 1 300 train
+yttiwrqnmz 1 300 train
+yttjeribki 1 300 train
+yttxfjldgx 1 300 train
+ytufbmkdlq 0 300 train
+ytuyccfpuv 0 300 train
+ytvaqzbbwt 1 300 val
+ytvcachoir 0 300 train
+ytvdkuerzp 1 300 val
+ytvjkvtvnw 1 300 train
+ytvkznniws 1 301 train
+ytvnstdzze 0 300 train
+ytvoyjgmnh 1 300 val
+ytvpoparhx 1 300 train
+ytvxxwjypc 1 300 val
+ytwaizqxde 1 300 train
+ytwcxncsmn 1 300 train
+ytwfkrxwnb 1 300 train
+ytwpcvjikh 0 300 train
+ytwuhmaktf 1 300 train
+ytwyozozbw 0 300 train
+ytxeiqmosc 0 300 train
+ytxfncunvp 1 300 train
+ytxhrhnfcg 1 300 val
+ytxivhuomt 1 300 train
+ytxwkxxdmq 1 299 test
+ytycdntzvo 1 300 test
+ytyeroamnl 1 300 val
+ytyfspbsul 1 300 train
+ytylvucxfz 1 300 train
+ytynjlufzl 1 300 train
+ytyoicpqup 1 300 train
+ytyptdjoay 1 300 test
+ytyszxmqag 1 300 train
+ytyuseftub 1 300 train
+ytzcjvijhn 1 300 train
+ytzgidecyu 1 301 train
+ytzitqhhod 1 300 train
+ytznckxaed 1 300 val
+ytzowgokrv 1 300 val
+ytzsbxpknx 1 300 train
+ytztqzfwmi 0 301 train
+yuaatffcli 1 300 train
+yuagikuvbx 1 300 train
+yuagylvsja 1 300 val
+yuaneglmkw 1 300 train
+yuarccgvui 1 300 train
+yuarvichcp 1 297 val
+yuaxrdsgzy 1 300 val
+yuazorbfpj 1 300 train
+yubdbbwtpb 1 301 train
+yubisuhdbt 1 300 train
+yubjspziqe 1 301 val
+yubjvkyrqv 1 300 train
+yubkooqbsm 0 300 train
+yucbiocprl 1 300 train
+yuconpvmqh 0 300 train
+yudfbdidar 0 300 train
+yudiitprjj 1 300 train
+yudqjailbx 1 300 val
+yudsntzkka 1 300 train
+yudvffoyrz 1 301 val
+yudzbztyle 1 298 train
+yuefermpld 1 300 train
+yuehvycesz 1 300 train
+yuemudoxux 1 300 train
+yuephcvqzq 1 300 test
+yuevearyrb 1 298 train
+yuewgyhhyw 0 300 train
+yufcnpaerr 1 136 train
+yuffbhiwhi 1 300 val
+yufgacajvg 1 298 train
+yufgngrzys 0 300 train
+yufhhcaisy 1 300 train
+yufiyirsnf 1 300 train
+yufqcbifkk 1 300 train
+yufwsiphvi 1 300 train
+yugbeaqhlf 1 300 test
+yugfoiokjv 1 300 train
+yugpoqtwwf 0 300 val
+yugvuxhjyu 0 300 train
+yuhltllopo 1 300 train
+yuhvpeibmt 1 300 train
+yuhvvzeerg 1 300 train
+yuidorrfsm 1 300 train
+yuilazllfh 1 300 val
+yuimrvtija 1 300 train
+yujjwbpzxl 0 300 train
+yujmnmrqjz 1 300 train
+yujokknlge 1 300 train
+yujoqjiomi 1 300 train
+yujrcoartr 1 300 train
+yujwwwfopp 1 300 train
+yujxfujhax 1 301 train
+yujyfowfcv 1 300 train
+yukgstpxjp 1 241 train
+yukhvsxxvk 1 300 train
+yukmmtgxki 1 300 train
+yukprlgfnr 0 300 train
+yulzvcccfq 1 300 train
+yumbglcwvv 1 300 train
+yumeecupaw 1 300 train
+yumjmfjxmh 1 300 train
+yumouqtbtk 1 301 train
+yumwuqnwts 1 299 train
+yumwyzvhzf 0 300 val
+yunadvhwgm 1 300 train
+yuniojyjyq 1 300 val
+yunjtimhsm 1 300 train
+yunljlxazb 1 300 train
+yunqitmhjo 1 300 train
+yunxskqhec 1 300 train
+yunzfvsgit 1 300 val
+yuodbpdcen 1 300 train
+yuojninrqr 1 301 train
+yuojsiyuoe 1 300 train
+yuoqanqjex 1 300 train
+yuowilcrkg 1 300 train
+yuozmggtin 1 299 val
+yupfpsylqp 1 300 train
+yupkbkluoj 1 300 train
+yuplcdqypg 1 300 train
+yuprnhayoj 1 300 train
+yupsrmckii 0 300 train
+yupumvrfjy 1 300 train
+yuqdwjizdb 0 300 train
+yuqqamlvbh 1 241 train
+yuqsdnhupf 1 301 train
+yuqzdnztdn 1 299 test
+yuqzoeokll 1 300 val
+yurbunfeik 1 300 val
+yurtzoovou 0 300 train
+yusavlcuhm 1 300 val
+yusggafcoc 1 300 train
+yusjuhoblj 0 300 train
+yusqgmcwyp 1 300 train
+yuszeaayck 0 300 train
+yuteraqwck 1 299 test
+yutgeazjjh 1 300 train
+yuthuxfjvy 1 300 train
+yutkgffbmy 1 300 train
+yutlgduatj 1 300 train
+yutpjtcfsr 1 300 train
+yuuaxskvqi 1 300 test
+yuucnlzbzr 1 300 train
+yuueakgoev 1 300 train
+yuufjhqdfw 1 300 train
+yuuljlhiyu 0 300 train
+yuumtkgrml 1 301 val
+yuuvpwrofy 1 300 train
+yuvfkymeuk 1 300 train
+yuvfpyndab 1 300 val
+yuvigrauut 1 300 train
+yuvjldtuwl 1 301 train
+yuvombdncy 1 241 train
+yuvtzdlncy 1 300 train
+yuvyleouic 1 300 val
+yuvzsrxurn 0 300 train
+yuwcrgsvpq 1 300 train
+yuwoxpqeuv 0 300 train
+yuwvoviras 0 300 train
+yuwxvaizey 1 300 train
+yuxexfmmww 0 300 train
+yuxjhyneca 1 301 train
+yuxlainvfr 1 300 val
+yuxnighhox 0 300 train
+yuxshsiale 0 300 val
+yuxvcxcpcb 1 300 train
+yuyenszbrd 1 300 train
+yuyggmrapv 1 298 val
+yuygpqrecg 1 300 train
+yuyifueogn 1 300 val
+yuymadtheg 1 301 train
+yuynsznlnn 1 300 train
+yuypjkvzui 1 300 train
+yuysdfdqdu 1 300 val
+yuyyihzlud 1 300 train
+yuzdamakoa 0 300 train
+yuzebplfyc 1 300 train
+yuznqxmvkm 1 300 train
+yuzrbvyovn 1 300 train
+yuzuorzlyo 1 301 train
+yuzwhnemtx 1 300 train
+yvadypaetk 1 300 train
+yvaitthkpp 1 300 train
+yvawlzjnpe 1 301 train
+yvaxmtbtgx 1 301 train
+yvbamukfcm 0 300 val
+yvbimocexm 1 300 train
+yvbitmpqbc 1 300 train
+yvbjlmpaoi 1 300 train
+yvbljzgxrh 1 300 train
+yvbpvzvhpc 1 300 train
+yvbpxarwjl 1 300 train
+yvbrohhaam 1 300 val
+yvbsbakmve 1 300 train
+yvbsknaqom 1 300 train
+yvbwsatekt 0 300 val
+yvcbkkrfxe 1 300 train
+yvcevouctt 1 300 val
+yvcgpufyhf 1 241 train
+yvculfsagm 1 300 train
+yvcvjawqxo 1 300 train
+yvdanukioz 0 300 train
+yvdaurrxeh 1 300 val
+yvdccyvbgh 1 300 train
+yvdlkcsext 0 300 train
+yvdnbmbwyh 0 300 train
+yvdqvdqcqj 1 300 test
+yvdxquwtfh 1 300 train
+yveesygnvv 0 300 train
+yvehdwtota 1 300 train
+yvekmkiwoo 1 300 train
+yventrtrzi 1 299 val
+yvexseflkn 1 300 train
+yvfacuvjwr 1 300 train
+yvfeqrwuzk 1 300 train
+yvfhtwraue 1 300 test
+yvfoaoiclp 0 300 train
+yvfphbyljh 1 300 train
+yvfvoondlh 1 300 train
+yvfxmywfrq 1 301 val
+yvfyniialf 1 300 train
+yvgblexkfp 1 297 val
+yvggulvpbb 0 300 train
+yvgkathwkq 1 300 train
+yvgkydknyo 1 300 train
+yvgnaxkajm 0 300 val
+yvgxpjsnia 1 300 train
+yvhbqflikl 1 300 train
+yvhgixlhrt 1 300 train
+yvhitumirh 0 300 train
+yvhoifibra 1 300 train
+yvhtpnmvfv 1 300 train
+yvhtsawsqq 1 300 train
+yvhvnnshzj 1 300 train
+yvideeuyff 1 301 val
+yvidhwqrqd 0 300 train
+yvihggetwc 1 300 train
+yvijlwxlkh 1 300 train
+yvikoemmlc 1 300 train
+yvikpbcqzx 1 300 train
+yviucixoxg 0 300 train
+yvixrplqty 0 300 train
+yvjahuivjk 0 300 train
+yvjbmnslge 1 300 train
+yvjcdjyoof 1 300 train
+yvjcfahxpq 1 241 train
+yvjfclzwyn 1 300 train
+yvjtimjkdq 1 300 train
+yvjtmrfymn 1 300 train
+yvjvjmudzx 1 298 val
+yvkcsvebfj 1 300 train
+yvkggzwqgj 1 300 train
+yvkjazbfbd 1 300 train
+yvkqogkdwe 0 241 train
+yvkuususfu 0 300 train
+yvkyhbcajb 1 300 train
+yvkzqlbrea 1 300 val
+yvlfhcdvyo 0 300 train
+yvlgpktuuq 1 300 val
+yvlgyveglm 1 300 train
+yvlmobwnic 1 301 train
+yvlpyxdbga 1 300 train
+yvluejpsas 1 300 train
+yvlvaflbif 1 300 train
+yvmhvhstrv 1 301 val
+yvmitttopk 1 301 train
+yvmjvsnoip 1 298 train
+yvmnycdgmk 1 300 train
+yvmodxikld 1 300 train
+yvmrwdyxby 0 301 train
+yvmxgtmqks 1 300 train
+yvmyyeojnx 1 300 train
+yvmztzawtm 1 300 train
+yvndpwweao 1 300 test
+yvndufwogg 1 300 train
+yvneqyzasn 1 300 train
+yvnlaygbkm 1 301 train
+yvntaywart 1 300 train
+yvntutgixs 1 300 val
+yvntwsfocf 1 300 train
+yvnxsysrrs 0 300 train
+yvoanwlvzq 0 300 train
+yvojjqtrju 0 241 train
+yvokxcpfnu 1 300 train
+yvolowpgub 1 300 train
+yvoqmpcefu 1 301 train
+yvovxkxjxf 1 300 train
+yvowabxoto 0 300 train
+yvpagqaysy 1 300 val
+yvpimaskia 1 300 train
+yvpjkzcued 1 300 train
+yvpmfrnifh 0 300 train
+yvpqcofciy 1 300 train
+yvpujjznsn 1 300 test
+yvpzinlbqx 1 300 train
+yvqbezsntt 1 300 val
+yvqbiivsrs 0 300 train
+yvqcpqdmif 1 301 train
+yvqdiierll 1 300 train
+yvqdkqnrif 0 300 train
+yvqeershyk 1 300 train
+yvqphqqefo 1 300 train
+yvqquosrbf 1 300 train
+yvqsojbfhv 1 300 train
+yvqwqnmwkb 1 300 train
+yvqzlsapom 1 300 train
+yvraflsdjy 1 300 val
+yvrezovjkj 1 300 train
+yvrwgvnxmh 1 300 train
+yvrxbemnkp 1 301 train
+yvsaazhxhc 0 300 train
+yvsaqnoixr 1 300 val
+yvskmzqxqb 1 300 train
+yvsnmunfal 0 300 val
+yvsohcvcuj 1 299 val
+yvssvsvsav 1 300 train
+yvsuaijnwe 1 300 train
+yvszozejps 1 300 train
+yvtdcrvxbu 0 300 train
+yvtogabvsl 0 300 val
+yvtvnoyxbt 1 300 train
+yvtxrbovse 1 300 train
+yvtyxmujud 1 300 train
+yvtzzibsui 1 300 val
+yvudovnhum 1 300 train
+yvunlzbvqa 1 300 train
+yvupannsip 1 299 val
+yvuxjtlobo 1 300 train
+yvvhzcllri 1 300 train
+yvvnxnztoj 0 298 train
+yvvrjailpy 1 300 train
+yvvrjskesk 1 300 train
+yvvrvvkhob 1 300 test
+yvvtvrbcnr 1 300 train
+yvvycmrmbu 1 301 val
+yvwbmmyknq 1 300 train
+yvwbopmnnl 0 300 train
+yvwebuzrjf 1 300 train
+yvwmdbofvn 1 300 train
+yvwqzjqpwx 1 300 train
+yvwraerzqk 0 300 train
+yvwwehipqy 1 241 train
+yvwwtzjbli 1 300 train
+yvxcjfjryc 1 300 train
+yvxkfubdub 1 300 val
+yvxmmgxaat 1 300 train
+yvxugsxlem 1 300 train
+yvxwnqzgmy 1 300 train
+yvxwsuhbjw 1 300 train
+yvyawmdraa 1 300 val
+yvygbcfxzk 1 300 train
+yvymbkjjyb 1 301 train
+yvypwtkadh 1 300 val
+yvyugtnzvk 0 300 train
+yvyukogzub 1 300 train
+yvyuwnphuj 1 300 train
+yvywjfpmuk 1 298 val
+yvzauczrmw 1 300 val
+yvzhjokvyz 1 300 train
+yvzlvphjyt 0 301 train
+yvzozfmbic 1 300 train
+yvzqezsrfe 0 300 train
+yvzqhqobal 1 300 train
+yvzttekbap 1 300 train
+yvzzgykljx 1 300 train
+yvzzzkigwt 1 300 train
+ywaecundmo 1 300 train
+ywajbwquvw 1 300 test
+ywaqgxfucq 1 300 train
+ywaqmbqlol 1 301 train
+ywaratbwzq 1 302 train
+ywauchpgum 0 300 train
+ywauoonmlr 0 299 test
+ywbdkemvye 1 300 train
+ywbgixcrjf 1 300 train
+ywbhdurrtl 1 300 train
+ywbiqptlio 1 300 train
+ywbkypxava 1 300 train
+ywbltzuaet 1 300 train
+ywbpextslj 1 300 train
+ywbsafpsii 1 300 train
+ywbusfztfg 1 301 train
+ywbutxprrj 1 300 train
+ywbycmwfmw 1 269 train
+ywcbpiqote 1 300 train
+ywcbvxlmam 1 301 train
+ywcfkvqemt 1 300 test
+ywcimxlcor 1 300 train
+ywcizdgnai 1 300 train
+ywcmskduvg 1 301 val
+ywcozqxsmy 1 600 train
+ywcrpdilir 1 300 train
+ywcshmnlmp 1 300 train
+ywdfaqjhcq 1 300 val
+ywdhpecypj 1 300 train
+ywdqxdwtcu 1 300 train
+ywduacwolv 1 300 train
+ywdunvxvke 1 300 train
+ywdvacgwsi 1 300 train
+ywdxihdvbw 1 300 val
+ywebhiswuv 1 300 train
+ywecvdpbvq 0 300 val
+yweedkossg 1 302 train
+ywefocliek 1 300 train
+yweldtspty 1 99 train
+ywempnkrkc 1 300 train
+yweqqbbcbd 1 300 train
+ywerlxrqpm 0 300 train
+yweuzebews 1 240 train
+ywevetqdrb 1 300 val
+ywewsmrynk 1 300 train
+ywfyqomdvw 1 300 val
+ywfzqsyhus 1 300 train
+ywgkjuadyv 1 300 train
+ywgmecijso 1 298 train
+ywgmldultw 1 300 train
+ywgpguidel 1 300 train
+ywgxrmugxt 1 300 val
+ywhimmvgof 1 299 val
+ywhxdgewdt 1 300 train
+ywigqrwxsz 1 300 train
+ywiopkwcrj 0 300 train
+ywiumooetm 1 100 train
+ywiwjfbfuv 1 298 train
+ywizucuncd 1 298 train
+ywjedtnqak 1 300 train
+ywkbgqniad 1 300 val
+ywkcozzfou 1 300 train
+ywkcrvajcx 1 300 train
+ywkfdktsfq 1 300 train
+ywkijvlieh 1 299 val
+ywkjiubxbs 1 300 train
+ywkqwgcwhc 0 300 train
+ywlaercgfp 0 300 train
+ywlaxmgtww 1 300 train
+ywlbihpkjn 1 300 test
+ywldlwcfzz 1 300 val
+ywlpsjeuzy 1 300 val
+ywlqmtcggy 1 300 val
+ywlrptiwec 1 300 train
+ywltsyervd 0 300 train
+ywlyscieqz 1 300 train
+ywmdubxqoy 1 300 train
+ywmdunigmq 1 300 train
+ywmladcexp 0 300 train
+ywneybpohw 1 300 train
+ywngdqvpcd 0 300 train
+ywnjxxaqob 1 300 val
+ywnryqjpso 1 301 val
+ywnuerndit 1 300 train
+ywnyglamkm 1 300 train
+ywofbsqamm 1 300 val
+ywopmhpmqf 1 300 train
+ywothfjglx 0 299 val
+ywoyfkbzfm 1 299 train
+ywoyowesnn 1 300 val
+ywpbkpicbt 0 300 train
+ywpcrzitcu 1 300 train
+ywpevyaoyr 1 300 train
+ywpjoyxbdb 1 300 train
+ywplahmhnz 1 300 test
+ywpmywgoyy 1 300 train
+ywpoaedcut 1 300 train
+ywppcksjpc 1 300 train
+ywpsiygwqv 1 300 train
+ywpueiyzvo 0 300 val
+ywpwcqmabi 1 296 train
+ywpyitmima 1 300 val
+ywpzfjnbjm 1 300 train
+ywqgpzqnpl 0 300 val
+ywqmceihta 1 300 train
+ywqzgqcwub 1 300 train
+ywrffteseu 1 300 train
+ywrnasfhxi 1 300 test
+ywrrupyyub 1 300 train
+ywrubwyiit 1 241 train
+ywscfyvdek 1 300 train
+ywsjvnootr 1 300 train
+ywsnvyopdv 1 300 val
+ywsowwyyni 1 300 train
+ywspdqfhql 1 298 train
+ywsvhmoejx 1 300 val
+ywsvkotgux 1 300 train
+ywswolkhun 1 241 train
+ywtdrnutim 1 300 train
+ywtijutpsx 1 300 train
+ywtpmkuseg 0 300 val
+ywtqewlkzj 1 300 train
+ywtrgardha 1 298 train
+ywtujtswov 1 300 train
+ywuadwcnhy 0 300 train
+ywuapoqspy 1 300 train
+ywujazdszo 1 300 train
+ywuoxnsbos 1 300 train
+ywutssdgos 1 300 train
+ywuwtdernq 1 300 train
+ywuxuaxwug 0 300 val
+ywvbdslsgu 0 241 train
+ywveineanr 1 300 train
+ywvflzlhos 1 300 val
+ywvlvpvroj 0 300 train
+ywvymzyvlc 1 300 val
+ywwfrqugal 1 300 train
+ywwgbzcple 1 300 val
+ywwhaapskc 1 300 train
+ywwjjfkycm 1 300 train
+ywwotglcco 1 299 train
+ywwouysddl 1 300 train
+ywwqsdkqlg 1 249 train
+ywwspchdlo 1 300 train
+ywwvxzemdf 1 301 val
+ywxcvcedqc 1 300 train
+ywxfnlxtjg 1 300 train
+ywxivykvif 1 300 train
+ywxmzkwnoo 0 300 val
+ywxpquomgt 0 300 test
+ywxthmjkbf 1 300 train
+ywxuisqukt 1 300 val
+ywxynggyyi 0 300 train
+ywxzjfgqjc 1 299 train
+ywyiwqiock 1 300 val
+ywyoqzvhnp 1 298 train
+ywypogitjx 1 300 val
+ywyycvnbyv 1 300 train
+ywzapccczu 1 300 train
+ywzjlcpuum 1 249 train
+ywzkumpcjp 1 300 val
+ywznycvdna 1 300 train
+ywzpcodkqh 1 300 val
+ywzumxqcsf 1 300 test
+ywzvgfimjd 1 300 train
+ywzwcoekic 1 300 train
+ywzyngwyha 1 300 train
+yxadevzohx 1 300 test
+yxafhliofp 1 300 train
+yxalkhxfhq 1 300 train
+yxaojguzig 1 300 train
+yxaozsbhgf 1 300 train
+yxaqsflxnf 0 300 train
+yxbegeovkj 1 300 val
+yxbfjeoniv 1 298 train
+yxbpurtwvy 1 300 train
+yxbqsrpopc 1 300 train
+yxbtsvoren 1 300 train
+yxbxemeatd 1 300 train
+yxbxprfprj 1 300 train
+yxbzfwusxl 1 300 train
+yxcemuorah 1 299 test
+yxcghurwmw 1 300 train
+yxcvnawhfb 1 300 train
+yxczkvqmwh 1 300 train
+yxczphqwsw 1 300 train
+yxddifvkap 1 299 test
+yxdgmeaisq 1 299 test
+yxdleubquk 1 300 val
+yxdnfmtmkc 1 299 train
+yxdqckdjsb 0 301 train
+yxeiqbkcob 1 300 val
+yxemrtvovf 0 300 train
+yxeovhhakl 1 294 train
+yxexnvndkd 1 300 train
+yxfrkqsgqa 1 300 train
+yxfxcfcjks 1 300 train
+yxgaeuplno 1 300 train
+yxgcnhvdta 1 300 train
+yxggpbrqhc 1 300 train
+yxghyqgioe 1 300 train
+yxgljheoyy 1 301 train
+yxgtvkyvpg 1 300 val
+yxgyptclod 1 300 train
+yxhhjhyxkt 0 300 val
+yxhkjfdehu 1 300 train
+yxhkvmgijj 1 301 train
+yxhvplfhvu 1 300 train
+yxhzkfmgbe 1 300 train
+yxikjofijo 1 300 train
+yxinzzriuu 0 301 train
+yxiorfqcnp 1 300 train
+yxipahypoj 1 300 train
+yxipssjsyg 1 300 train
+yxirnfyijn 1 300 test
+yxitziwbra 1 300 train
+yxivkxmzee 1 300 train
+yxjjfaekev 1 300 train
+yxjpigvryg 1 300 train
+yxjqxlyvkq 1 300 train
+yxjskrymzu 1 299 test
+yxjvttatzw 1 300 train
+yxkbjxmtzr 1 300 test
+yxkpoqiouh 1 301 val
+yxkrhygdue 1 300 train
+yxkwfyzumw 1 300 val
+yxkymfgacj 1 300 val
+yxldactlic 1 298 train
+yxlizjiqts 1 300 train
+yxlkkiutjr 1 300 train
+yxlkovjssa 1 83 train
+yxlloqgqsz 1 300 train
+yxmbuaycdq 0 300 val
+yxmgksezfs 1 300 train
+yxmifgtpyg 1 300 train
+yxmkxvkcvl 1 300 train
+yxmnwiwdpb 0 300 train
+yxmqxzobbk 0 300 train
+yxmqycojfm 1 300 train
+yxmrbozaql 1 300 train
+yxmsiauteq 1 300 val
+yxnjqsomgw 0 300 train
+yxntkuahom 1 302 train
+yxnwnywsqk 0 300 train
+yxnwtrfuru 1 300 train
+yxoohrnjrz 1 299 train
+yxowgfgxvu 1 300 train
+yxowoyzgam 1 300 val
+yxoyqixupr 1 301 train
+yxpabnsbrs 1 300 val
+yxpdbhtxll 1 300 train
+yxpisabrjk 1 300 train
+yxpqisvrec 1 240 val
+yxpqpyejeg 1 300 train
+yxpqrndera 1 300 train
+yxpujepkub 1 301 train
+yxqelnpznf 1 300 val
+yxqhxlsngk 1 300 train
+yxqucilnlu 1 300 val
+yxqwbxjrtt 0 300 train
+yxrcbchseg 1 300 train
+yxrjoxmslx 1 300 train
+yxrocwpsin 1 300 val
+yxryufzwen 1 299 test
+yxryurgjex 1 300 train
+yxsdhcbmbk 0 300 train
+yxsettcask 0 300 train
+yxsfsjbrxz 0 300 val
+yxsmnsaefa 1 300 train
+yxspebqcym 0 300 train
+yxsqpqcqbb 1 300 train
+yxsuokknxl 1 300 train
+yxtgbofguf 1 300 val
+yxtggioytj 1 300 train
+yxtnhxxkfb 1 300 train
+yxtnjafacl 1 300 val
+yxtodyhxao 1 300 train
+yxtrwecpib 1 300 train
+yxtzngtscd 1 299 val
+yxufewmocj 1 300 val
+yxughcwsbq 1 300 train
+yxumqvnlsp 1 241 train
+yxuqretfae 1 296 val
+yxuszahffr 1 300 val
+yxuyvapdid 1 300 test
+yxvgptqnfd 1 241 train
+yxvmnvnoxf 1 300 train
+yxvmusxvcz 0 300 test
+yxvwudykpv 1 300 train
+yxvxcckbuq 1 300 train
+yxvzengowq 0 300 train
+yxvziflwgi 0 300 train
+yxwjqkjfrs 1 300 train
+yxwjxbilxz 1 300 train
+yxwnmuylsr 1 300 train
+yxwnobtvep 1 301 train
+yxwpxumqhf 0 300 train
+yxwvcicjav 1 300 train
+yxwweezzcy 1 300 train
+yxxedpxjms 1 300 train
+yxxidwmzag 0 300 train
+yxxvaihzep 1 300 train
+yxycaowuaa 1 300 train
+yxyhvdlrgk 0 300 train
+yxymghoach 0 300 train
+yxyohfljmx 1 300 train
+yxytxbsaek 1 300 train
+yxyuewmtrx 1 300 val
+yxyvbatxdm 1 300 val
+yxyysatklu 1 300 train
+yxzcyffmog 1 301 train
+yxzdupddoa 1 300 train
+yxzdyxwkzn 1 300 train
+yxzeronmsi 1 249 train
+yxzezhuaxw 1 297 val
+yxzfqbcilh 1 300 val
+yxzjybmzvy 1 300 val
+yxzugbmfyw 1 300 train
+yyacdikwrg 1 300 test
+yyadunmoad 1 300 train
+yyadxellcj 1 300 val
+yyaejjkbds 0 300 train
+yyagfjrogm 1 300 train
+yyaicxrixg 1 300 train
+yyansumnbl 1 300 train
+yyaqxfewto 1 299 val
+yyaxvycfvp 1 300 train
+yyazapusjj 1 300 train
+yybdkorjek 0 300 train
+yybejszdjm 0 300 train
+yybkobiseo 1 299 train
+yybmjbtavz 0 300 train
+yybndruxch 0 302 val
+yybyvwtodb 0 300 train
+yycdeptdnn 1 300 train
+yycgammbld 1 300 train
+yyconhglva 1 298 train
+yycuunghpn 1 300 train
+yycywqqajn 1 300 train
+yydbbxfgkx 1 300 train
+yydhnumnlx 1 300 train
+yydhopctzg 1 300 train
+yydjqurhyt 1 300 train
+yydnewntax 1 300 train
+yydocktjmn 1 300 train
+yydptbvwac 0 301 train
+yydrympyol 1 300 train
+yydxssgwjx 1 300 train
+yydzfachgi 1 299 val
+yyecgshcla 0 300 train
+yyehckvovh 1 300 val
+yyejqlepnj 1 300 val
+yyejxatcnz 1 300 test
+yyerfcvkcp 1 300 train
+yyevmkmzhl 1 300 val
+yyfdhmrfgg 1 300 train
+yyfibhoiij 1 300 train
+yyfjizorvf 1 249 train
+yyfknjxaey 0 300 train
+yyfmqzllbw 1 300 train
+yyfpfzgncp 0 300 train
+yyfsaxkfjt 1 300 train
+yygbjfwbek 1 301 train
+yygjogokma 1 300 val
+yygnepuemd 1 301 train
+yygtmzelts 0 300 train
+yyhexmlgyi 0 301 train
+yyhgpklnza 0 300 val
+yyhtipyqoj 1 298 train
+yyiagamlyb 1 300 train
+yyigjpvdem 1 300 train
+yyihneshiz 1 300 train
+yyiiywtiry 1 300 train
+yyilyommkf 1 300 train
+yyitvdtwvw 0 239 train
+yyjdgdwjrt 1 300 train
+yyjhtexlly 0 300 val
+yyjnrflkde 1 300 train
+yykbbbjfwu 0 300 train
+yykbfhimqt 1 300 train
+yykbgpddli 1 300 train
+yykhogwosu 1 298 train
+yykvajkgkp 1 300 train
+yylddjnged 0 300 train
+yylmbyolqw 1 300 val
+yylnfxuotk 1 300 train
+yyloxhjtmm 1 300 train
+yylreahcso 0 300 train
+yymedrgilu 0 300 val
+yymsepwlmz 1 300 train
+yymujmhqxq 1 300 train
+yymwixbvhg 1 300 train
+yymzbacqfv 1 298 train
+yynaukkiwh 1 300 val
+yynktoirrv 1 300 train
+yynrmqdzlw 1 300 train
+yynsgccwtn 1 300 val
+yynszivwba 1 300 val
+yynxwdhdto 1 300 train
+yyoguufzxz 1 241 train
+yyohndwbjd 0 300 train
+yyosdwoqdh 1 300 train
+yyotrobeci 1 300 train
+yyoxuakkcb 1 300 train
+yypbrzvfpa 0 298 val
+yypechxpkt 1 299 train
+yyptszxsxh 1 240 train
+yypwdybsll 1 300 train
+yypzndqyac 1 300 train
+yyqbcvqwzi 1 300 val
+yyqfgqdlgk 0 300 val
+yyqhvpnxot 1 300 train
+yyqkatwzxa 1 300 train
+yyqluybufr 1 300 train
+yyqqgnoixg 1 300 train
+yyqthfcirc 0 300 val
+yyqyhbzheb 1 300 train
+yyrjqydhhj 1 300 train
+yyrltwsdvx 0 300 train
+yyrpsrmjfd 0 300 train
+yyrrytwwva 0 300 val
+yyrueyfphr 1 301 val
+yysdbhsuwk 1 301 train
+yysdhxbpsz 1 300 val
+yysgbiypkx 1 300 train
+yysjbqhmsx 0 300 val
+yyslirpggv 1 300 val
+yysoyfehve 1 300 val
+yysryunzpb 1 301 train
+yysxcapiqg 0 300 train
+yytgnixnff 1 298 train
+yytkrbxdkg 1 241 train
+yytlybkewe 1 301 train
+yyttdbwmfq 1 300 val
+yyudmkuhxo 0 300 train
+yyuemfqduf 0 300 train
+yyufyxbpff 1 300 val
+yyuhfwpuzb 1 300 train
+yyumjpupnm 1 300 train
+yyuodrxazd 0 300 train
+yyuoirtquj 1 300 train
+yyupvxlosv 1 300 train
+yyurnkjpya 1 300 train
+yyuuymrkvr 0 302 train
+yyvyfdwijx 1 300 train
+yywazvikkv 1 300 train
+yywcdbcdhp 1 300 train
+yywlqpamxq 0 300 train
+yywvkziuvp 0 300 train
+yyxdlewtnc 1 300 train
+yyxkjsfqsc 1 300 val
+yyxkuxwbah 1 300 train
+yyxuidpkpt 1 298 train
+yyxuyzaycm 0 300 train
+yyxvnupjnq 1 300 train
+yyygernwew 1 300 train
+yyylolsfap 1 301 val
+yyypeblzmw 1 300 train
+yyyqdyejwn 0 302 train
+yyzbxajtkd 1 300 train
+yyzhqufluj 1 300 train
+yyzjwsepib 1 300 train
+yyzkkxpikq 1 300 train
+yyzpvifjrc 1 302 train
+yyzpzfhais 1 299 train
+yyzqbaexnn 1 300 test
+yyzqhvzxez 1 136 train
+yyzrhpllyu 0 300 train
+yyzsrlltjq 1 296 val
+yzaajgyhsn 1 300 val
+yzaawuryka 1 300 train
+yzabplnynk 1 298 train
+yzaensfopn 1 300 val
+yzakjkyhdv 1 300 train
+yzasourxza 0 300 train
+yzatjaurci 1 300 train
+yzazikwrvy 1 300 train
+yzbhbxlvlz 1 298 train
+yzbvkqdlir 1 299 val
+yzcaxdqopo 1 300 train
+yzcbrprtrg 1 300 train
+yzcilrwgvb 1 301 val
+yzclfxfgke 1 297 train
+yzcmqukoek 1 300 train
+yzcqbwxfrp 1 300 train
+yzcthicmmf 1 298 train
+yzdbfnuliw 1 298 train
+yzdhlmbjbq 1 300 val
+yzdrrwmztb 1 300 train
+yzdunlwhgi 1 300 train
+yzdurujkev 1 300 train
+yzdxgnkdlr 1 300 train
+yzeabkdwxm 1 302 train
+yzebcskiyu 0 301 train
+yzehwpdbzm 1 300 train
+yzenqkdufo 1 300 train
+yzenvofodf 1 301 val
+yzetolzbiu 0 300 train
+yzfnlowwcq 1 300 val
+yzgbsiugyk 1 300 val
+yzgmlvfxyv 1 299 train
+yzguqttvkg 1 300 train
+yzgvjnmahu 1 300 train
+yzgymanupx 0 300 train
+yzhlqeupei 1 300 train
+yzhndfopvt 1 300 train
+yzhrdoqqxk 0 300 train
+yzhvvgnihu 1 300 train
+yzhvwupmqf 1 300 val
+yzhywbpwkn 1 300 val
+yzihbxwepc 1 300 train
+yzihlxibvv 1 296 val
+yzilccrwcj 0 299 val
+yziqsfcxcv 0 300 train
+yzizgrgavw 1 300 train
+yzjfprhzno 1 300 train
+yzjhlsddmg 1 299 test
+yzjhtvgsbu 1 240 val
+yzjkkacood 0 300 val
+yzjnjwjzye 1 301 train
+yzjoowgicf 1 300 train
+yzjwkrwwnv 1 300 val
+yzjzczodyz 1 300 test
+yzkbgsewig 1 300 train
+yzkdchfhxv 1 300 train
+yzkhwvzsts 1 300 val
+yzknswlucq 0 301 train
+yzkvniwmrh 1 300 train
+yzkzawtzge 0 300 val
+yzkzvozzth 1 300 train
+yzlegxfjok 1 301 train
+yzliapajse 1 300 train
+yzlvetpxtb 1 300 train
+yzlzvcbdex 1 300 train
+yzlzwtbzkp 1 300 train
+yzmbtbeoxk 1 300 train
+yzmfpmfofh 1 300 train
+yzmjerisdr 0 300 val
+yzmlvibpcg 0 300 train
+yzmttxcaai 1 300 val
+yzmufwlsmf 1 300 val
+yznlohwait 1 298 train
+yznmncewlc 1 300 val
+yznqvwmwwk 1 240 train
+yznvbqwtzr 1 300 val
+yznyqfmvmq 1 299 train
+yzockhlrnu 1 301 train
+yzocyzvfrg 1 300 train
+yzotdtjnho 1 300 train
+yzoxtamjqc 1 300 val
+yzpclclzoh 0 300 train
+yzpgejhltv 1 300 train
+yzpjwsfgob 1 299 test
+yzpsardabs 1 300 val
+yzptdnjime 1 300 train
+yzpvteuxdt 1 300 val
+yzqbwkwxsn 0 300 val
+yzqcptzlwf 1 300 train
+yzqcwokdhg 1 300 train
+yzqecwatok 1 300 val
+yzqjxkipov 0 300 train
+yzqncfroxr 1 300 train
+yzqnsglcpq 1 301 val
+yzqpmnykha 0 300 train
+yzqsdudpvs 1 300 train
+yzqtfuawxb 1 300 train
+yzqttnbluj 1 301 val
+yzqvnbsbrl 1 300 train
+yzqwizknnw 1 299 test
+yzqxpbbepc 1 300 train
+yzrendtiky 1 300 train
+yzrnecgkua 1 300 train
+yzrngdribf 1 300 test
+yzsaxacpdn 1 300 train
+yzskgrixsf 1 297 train
+yzsshvkvgo 1 300 train
+yzthwqcnvo 1 241 train
+yztjbvubmp 1 300 train
+yztjtkpxml 1 300 train
+yztnuyzogg 1 300 train
+yztrudwrpn 1 300 val
+yztusyhujo 1 300 train
+yzubtlbstv 1 300 train
+yzubzsshny 1 300 train
+yzuestxcbq 1 300 test
+yzukgldmve 1 300 train
+yzusjwgyav 0 300 train
+yzuuewvznw 1 298 train
+yzuuimypnx 1 300 train
+yzuwrdxdvr 1 300 train
+yzvalquhwx 1 300 train
+yzvctdkzdz 1 301 val
+yzvdinivcj 1 300 val
+yzvekudmeq 1 300 train
+yzvucgxcan 1 300 train
+yzvuhignhw 1 300 train
+yzvunjoxhv 1 297 train
+yzvwjxnqvx 0 300 val
+yzvxntnwol 1 300 train
+yzwcjyytpv 1 300 train
+yzwclqyscl 1 300 train
+yzwdfgqiyp 1 300 train
+yzwdfpydyq 1 301 train
+yzwipzgylo 1 300 train
+yzwooljuve 1 300 train
+yzwoprptvj 1 300 train
+yzwrfgghhm 1 299 test
+yzwvmiyoak 0 301 train
+yzwymdzhkm 1 300 train
+yzwzekysjq 0 300 train
+yzxbklivlr 1 300 train
+yzxcoidtjs 1 100 train
+yzxiaovljy 1 296 train
+yzxjiptpxl 0 300 train
+yzxshnsrbd 1 300 train
+yzxtrgtfdw 1 300 train
+yzxtzzgjfk 1 300 val
+yzxusjbotb 1 300 train
+yzyalupwvt 1 298 train
+yzycpyiqyi 1 300 train
+yzyflvtlmu 1 300 train
+yzynqpxpvz 0 300 train
+yzyurhatfa 1 300 val
+yzzacafuzn 1 300 train
+yzzdzztndd 1 300 train
+yzzgcotxox 1 300 train
+yzzkecxlpt 1 300 val
+yzzlebgfwj 1 300 val
+yzzvllabdq 1 300 train
+yzzvxdbwbi 1 300 train
+yzzxuieiwv 1 300 train
+zaaamzxabg 1 300 train
+zaadqtlqqi 1 300 train
+zaaolvkyvv 1 300 train
+zaapxudcgn 1 300 train
+zaapxwklkm 1 300 train
+zaautldltd 1 300 train
+zabbfpkqrf 1 300 train
+zabggtpvjj 1 300 train
+zabilaniav 1 300 train
+zableigsip 1 300 val
+zabmvbfaht 1 300 train
+zabvfyouie 1 300 test
+zabzymvzuf 1 300 train
+zacdnctlxk 1 300 val
+zacfnohyqm 1 300 val
+zacgcrjdnw 1 300 train
+zacljvgxyx 1 300 val
+zacmifiguu 1 300 train
+zacwxnddcs 1 300 val
+zacymmxonw 1 136 train
+zadgkoqzve 1 300 train
+zadiletqlb 1 300 val
+zadjpfnrnn 1 301 train
+zadkjxobsl 0 300 train
+zadkpqptrc 1 298 train
+zadplaziiu 0 300 train
+zadqknstpo 1 300 train
+zadumoiiwz 1 300 train
+zadwecmqlx 0 300 train
+zaedzhgmfp 0 300 train
+zaeijjyodf 1 298 train
+zaelskeidf 1 300 train
+zaemboheyb 0 300 val
+zaendkbrip 1 300 test
+zaeoijlszr 1 300 train
+zaereerakn 1 300 train
+zaesbuygqy 1 300 val
+zaeztjetrs 1 300 train
+zafauldilj 1 300 train
+zafkmmmhpj 1 300 train
+zafmjbulxd 1 301 val
+zafsovivgq 1 299 train
+zagojegpzn 1 300 val
+zagqofxwlv 1 300 train
+zagtceiohx 0 300 train
+zahcxoudcn 1 300 val
+zahfvzdiod 1 241 train
+zahgauhnot 1 300 train
+zahivgfcll 1 300 val
+zahjoydgtg 1 300 train
+zahkpzcjuc 1 300 train
+zahxipjtzc 1 301 train
+zahxyscmlj 1 300 val
+zaicbihiam 1 241 train
+zaidpktvtf 1 299 train
+zaierovirg 1 300 val
+zaiiqohdji 1 300 train
+zainjaidcy 1 301 train
+zaiqehhhrh 1 297 train
+zaiqsgoelg 1 300 train
+zaitbytums 0 300 train
+zaiujcdpoa 1 300 train
+zaivsbjoja 1 300 train
+zaizlovybk 1 298 train
+zajcjzbwpa 1 255 train
+zajgpppsuy 1 300 val
+zajhsrzdcz 1 300 val
+zajlximmos 1 301 train
+zajmykfzxg 0 300 val
+zajoneixnm 0 300 train
+zajtjvrwqt 1 300 train
+zajvuegtbo 1 300 train
+zajyvdizpr 1 297 train
+zakalbcezc 1 300 train
+zakcmolrlu 1 300 train
+zakfeyskak 0 300 train
+zakhceksnr 1 300 val
+zaksjydcnc 1 300 train
+zalaajhjlw 1 300 train
+zalaycbexh 1 300 val
+zaleuyekxr 1 300 train
+zaluscsadm 1 300 train
+zalvucwplw 1 300 val
+zamdpqkmaz 1 300 test
+zamtfgrvts 1 300 train
+zanbjxeizv 1 298 train
+zanitaghoz 0 300 val
+zanjfsapec 1 300 train
+zanjisthwk 1 300 val
+zanpywjuap 1 300 train
+zanqihqitq 1 300 val
+zanufvvcjy 1 301 val
+zanukbrsgi 0 300 train
+zanvojxaau 1 301 train
+zaoaglpnay 1 300 train
+zaogpfdrol 0 300 train
+zaogyhqvxw 1 300 train
+zaoqrhgfov 1 301 train
+zaouvuiwph 1 300 train
+zaoyocjkgw 1 300 train
+zaoyyisuqe 1 300 train
+zapbuyemiu 1 300 val
+zapcuhkncj 0 300 train
+zapcuremnl 0 300 train
+zaphsmlmvl 1 99 train
+zaplsiayog 1 300 val
+zapmdhpwxj 0 300 val
+zapvbcktlf 1 300 train
+zapvyxmpez 1 300 train
+zapykiwtda 0 300 train
+zaqaedqmib 1 300 train
+zaqclhhmrf 1 300 train
+zaqhdqviez 1 300 val
+zaqhqtyygz 1 300 train
+zaqlwbfwhk 1 300 train
+zaqmembhlm 1 300 train
+zaqsqscuhr 1 300 val
+zaqvfoyyop 1 300 train
+zaqyqpordi 1 300 train
+zarahdlzit 1 301 train
+zarlwbxxug 1 300 val
+zarmfyrkjn 1 288 train
+zarxjamxbg 1 300 train
+zasjhrnzpf 1 300 train
+zastmlloxo 1 300 train
+zatavvakla 1 300 train
+zatmdumwvj 1 255 train
+zatmdyjfxd 1 300 train
+zatqoywasm 1 300 train
+zatzqqujsk 1 300 train
+zaubktsguu 1 300 val
+zauecncdtf 1 300 train
+zaunbinekr 0 300 val
+zaupoznjyn 1 300 train
+zauzzvhcxa 1 300 train
+zavaexsxwv 0 300 train
+zavafvausw 1 299 val
+zavdsjbcza 0 300 train
+zavgroapyc 1 300 train
+zavlfnwvjr 1 300 train
+zavlhwvrlg 1 300 train
+zavreaeihy 1 300 train
+zavtlwtdba 1 300 train
+zavwyssnyi 1 300 train
+zavyewbbfw 1 300 train
+zawbkeozgh 1 300 val
+zawcuxqngo 1 300 train
+zawerhnzxq 1 300 train
+zawfvsxcgd 1 300 train
+zawgfbhgek 1 301 train
+zawjnzhotz 1 300 train
+zawjptddsr 1 301 val
+zawnjpshal 1 300 train
+zaxanhklfr 1 300 train
+zaxcirkvlu 1 301 train
+zaxdmursoa 1 298 train
+zaxezhkqjy 1 299 val
+zaxhtzqfhl 1 300 val
+zaxqombvou 1 300 train
+zaxvuyaoyd 1 300 train
+zaycqewzmb 1 300 train
+zaynuhjaci 1 300 train
+zayoesfjdo 1 300 train
+zayqkxksbb 1 300 train
+zayvgeqvls 0 300 train
+zazfbbafed 1 299 val
+zazgzrgzuu 1 300 val
+zazjbfumru 1 300 train
+zazprikfup 1 300 train
+zazufhzeae 1 300 train
+zazvxkcjet 0 300 train
+zbaasqelzn 0 300 train
+zbafmuwlpi 1 300 train
+zbahuhkioa 1 300 val
+zbaicbtryp 1 146 train
+zbamwfeoly 1 300 val
+zbapyydbhw 0 300 train
+zbaqjablvx 1 300 train
+zbazzauavd 1 300 train
+zbbppuvgby 1 301 train
+zbcbdfzeql 1 300 train
+zbcfyuazhc 1 300 train
+zbchhnvqno 1 241 train
+zbchoijdka 1 300 val
+zbcjudsxeb 1 299 val
+zbcnzsnaqi 1 300 val
+zbcpjuppvw 1 300 train
+zbctauymbd 1 300 train
+zbcvhblmtv 1 300 train
+zbcyshikxh 1 299 test
+zbdadtkawr 1 300 train
+zbdffgbbtn 1 300 test
+zbditiudhb 1 300 train
+zbdrpoghqf 1 297 train
+zbdwhbovmc 1 300 train
+zbdzhzzsku 1 300 train
+zbeclgpehj 1 300 val
+zbedudwede 0 300 train
+zbehkjhnbg 1 301 train
+zbejpzmgcr 1 300 train
+zbenkghmif 1 300 train
+zbeuuklbju 0 300 val
+zbexovgtuo 1 300 val
+zbezxztqki 1 300 train
+zbfgvfpxhe 1 300 train
+zbfnrunvej 1 300 train
+zbfnyiowbv 0 301 train
+zbfonbojyv 1 300 train
+zbfqqlccak 0 300 train
+zbfsjewdrn 1 300 val
+zbfyhdvoen 1 300 train
+zbgahhfdgc 1 298 train
+zbgboiewov 1 298 train
+zbgenrzzis 1 300 train
+zbgietrjdu 1 300 train
+zbgmmfhyse 1 300 train
+zbgnvugdcf 1 299 test
+zbgssotnjm 0 300 test
+zbheqbnekd 1 300 val
+zbhicnfugc 1 300 train
+zbhlvhjjgt 0 300 train
+zbhqyecfnp 1 300 val
+zbhuelhsiw 1 300 train
+zbicnjaiyu 1 99 train
+zbighbgvap 1 300 train
+zbihcwdtiy 1 300 train
+zbihrkloya 1 300 train
+zbiofrdyla 1 300 train
+zbioyomfwo 1 300 train
+zbitxrxewd 1 300 train
+zbivmmunpc 1 300 train
+zbixoasrdd 1 300 val
+zbjczlrwen 0 300 train
+zbjgrkpbts 1 300 train
+zbjgzegvsx 1 300 train
+zbjhvukpwj 1 300 train
+zbjkrolxtk 1 300 train
+zbjlhzzbbj 0 300 train
+zbkjwfhkfs 0 300 train
+zbkvvjayyw 1 300 val
+zblfawxfxh 1 300 train
+zblfyipezv 1 298 train
+zblhwvbaze 1 300 train
+zblioepegz 1 300 train
+zblntxoxoi 1 300 train
+zblrmuyzva 1 300 val
+zblrqydhbj 1 300 train
+zblttowttq 1 300 train
+zblubmwcjb 1 300 train
+zblvmebdga 1 299 val
+zbmaptwpbw 1 300 train
+zbmjmuebvs 1 300 val
+zbmlihouhf 1 300 train
+zbmqhjbibh 1 300 train
+zbmsvslybw 1 300 val
+zbmynpywde 1 300 train
+zbmzfjxnxf 1 300 train
+zbnfdlhijj 1 300 train
+zbnhorpvdj 1 299 train
+zbniokorck 1 300 train
+zbnqgczmsm 0 300 val
+zbnrxmlkqx 0 300 train
+zbnsmyigpe 0 300 train
+zbnzkuoaeg 1 300 train
+zbogpueoxr 1 300 train
+zbomcappzx 1 300 train
+zboshbutob 1 300 train
+zbosqtxjay 1 300 train
+zbotrurper 0 300 val
+zbotyhigad 0 300 val
+zbovzupaxr 1 300 val
+zbpkxbctef 1 298 train
+zbpltusqqm 1 300 test
+zbpmhevknw 1 300 train
+zbpncrxqfu 1 249 train
+zbpnxmkidl 1 300 train
+zbppwczssz 0 300 train
+zbprrgnywz 1 300 train
+zbprvxrbbz 1 300 val
+zbpuyzshmb 1 301 train
+zbpwazdhtz 1 300 test
+zbqhwuzfgx 1 301 val
+zbqlzhirna 0 300 train
+zbqnkoykfo 1 147 train
+zbqnlyvtyz 1 300 train
+zbqueawqyw 1 300 train
+zbqupdrlyd 1 300 train
+zbqxgmyhdh 1 297 train
+zbriaewnmi 0 300 val
+zbriefjrdj 1 300 val
+zbrjrjuvrw 0 298 train
+zbrjspdcit 1 300 train
+zbrmezlilf 0 301 train
+zbrtsayrbi 1 300 train
+zbsjlcsetv 0 300 train
+zbspiadsqy 1 300 train
+zbspiirbrz 0 300 train
+zbsqoxcjhf 1 300 train
+zbthakohlz 1 300 train
+zbtureciwm 1 300 train
+zbudjhyrac 0 300 train
+zbufmwooqj 1 300 train
+zburbzqvqn 1 298 train
+zbuumbrstc 1 300 train
+zbvebqhaov 1 300 train
+zbvgfbzzjq 0 300 train
+zbvgprfqmk 1 300 val
+zbviwwzxie 1 300 train
+zbvkjuchoh 1 300 train
+zbvlctwcqr 1 300 test
+zbvuxvmefw 1 300 train
+zbvwfhvacc 1 298 train
+zbwdmqkoij 1 300 val
+zbwfjkkoas 1 301 val
+zbwhxgarqw 1 300 train
+zbwngxqqfk 1 300 val
+zbwnsbllgp 1 300 train
+zbwsftoldc 0 299 train
+zbwvauvdoa 0 301 train
+zbwvdcygmq 1 301 val
+zbwzwqpace 1 300 train
+zbxaalohcs 1 300 train
+zbxcinckka 1 300 train
+zbxmxvstsq 1 300 train
+zbxpsuwzwr 1 300 val
+zbxriugflj 1 300 val
+zbxucbnpqf 0 143 train
+zbxvrhujfz 1 300 train
+zbxwagwzpw 1 300 train
+zbxwfeypjy 1 300 train
+zbyigmkaih 1 298 val
+zbykuipoty 1 301 train
+zbymcnlvka 1 300 train
+zbyqxeooii 1 301 train
+zbyrrujrch 1 300 val
+zbzlkcauzv 1 300 train
+zbzreolkcx 1 301 train
+zbzujyyzdz 1 300 val
+zcaaxvybxs 1 300 train
+zcaewerejx 0 300 train
+zcanvuclit 1 300 train
+zcauzhgroj 1 300 train
+zcayavztsu 1 300 train
+zcazrmuyyr 1 300 train
+zcbafxiugf 1 300 val
+zcbawtqbnm 1 300 train
+zcbgulrivs 1 298 train
+zcbhmdweor 1 300 train
+zcbhokzkhf 1 298 train
+zcbhzngluj 0 300 val
+zccgqwyjjf 1 300 train
+zccithnczj 1 300 train
+zcciyajgyp 1 300 train
+zccpfawquo 1 300 test
+zccrrcecky 1 300 val
+zccumptxeq 1 300 train
+zccxuuwlvb 1 300 train
+zccyfdworg 1 300 train
+zcddqbaakm 1 300 train
+zcdjcoinzp 0 300 train
+zcdlowhkhh 1 300 val
+zcdobdftzk 1 300 train
+zcdqtqptzd 1 300 val
+zcdzrwelwn 0 300 train
+zceiocpkcw 1 300 train
+zcejcoiwqm 1 300 train
+zcekvcpzaf 1 300 train
+zcevhmarxz 1 300 train
+zceyyfgorg 1 300 train
+zcfaqzvvca 1 300 train
+zcfczfdwmi 1 300 train
+zcffoakqej 0 300 train
+zcfndiwmbr 1 301 train
+zcfoeeleeg 1 300 train
+zcfpsnaujx 0 300 train
+zcfqelgcgt 1 300 train
+zcfrisdzsp 1 300 val
+zcftohlrqf 0 300 train
+zcgbyfxzse 1 300 train
+zcgfdxbqtb 1 300 val
+zcghnkqkky 1 300 train
+zcgineeori 1 300 train
+zcgipaenny 1 300 train
+zcgljwtzdj 1 300 train
+zcgmvnmvyd 1 301 train
+zcgqlwqsfx 1 300 val
+zcgszofbno 0 300 val
+zcgxoriyrl 1 300 train
+zchaghhjto 1 300 train
+zchboxfety 1 300 train
+zchbzoosmt 1 300 train
+zchcqizrva 1 300 train
+zchdixjlyj 1 299 train
+zchetwpbpc 0 300 train
+zcheyzddyw 1 300 train
+zchgqxwqdn 1 300 train
+zchifaihzu 1 302 train
+zchjepmrpo 1 300 train
+zchxujppuu 1 298 train
+zcieexjgnl 1 300 train
+zcifiwkooz 0 300 train
+zcihqndutp 1 300 train
+zcijgqopyg 0 300 val
+zcinhwujjv 1 300 train
+zcinpkwdpy 1 300 test
+zcirxwemih 1 300 val
+zciukudrsj 1 300 val
+zcizquvjcv 1 300 train
+zcjapvmvae 1 300 train
+zcjcdajvnk 1 300 train
+zcjgvamtzz 1 241 train
+zcjhobqmus 1 300 train
+zcjjkcrrle 0 300 train
+zcjrdqfnsa 0 300 train
+zcjxupwomg 1 299 train
+zcjyhmcpsv 1 240 val
+zckcqrknhv 1 298 train
+zckipketmd 1 300 train
+zcklknuwnq 1 299 val
+zcknvzyyui 1 300 train
+zckxklibgw 1 301 train
+zclfdeovzw 1 300 val
+zclmotkolo 1 300 train
+zclnxtnykr 1 300 train
+zclobhjlrc 1 300 val
+zcmainbdah 1 300 test
+zcmeubktra 1 300 train
+zcmezmfvvx 0 300 train
+zcmlopdhhe 1 298 train
+zcmmzbejik 1 298 train
+zcmomlqegk 0 300 train
+zcmoypzqbs 1 300 train
+zcmtybsiam 1 300 train
+zcnfzmskfp 0 300 train
+zcngwdmvwh 1 299 train
+zcnslhnnhl 1 300 test
+zcnuoyfbce 1 299 val
+zcnuyafslm 0 300 val
+zcnwdrmdsk 1 300 train
+zcnxnfwopr 1 299 test
+zcnxosiidw 1 239 val
+zcnyeimkks 1 300 val
+zcodqvabbp 1 301 train
+zcoonicsua 1 300 train
+zcoshotvyf 0 300 train
+zcotdpusce 1 301 train
+zcotewnsxy 1 300 train
+zcoutyidzt 1 300 val
+zcpdiajsfj 0 269 train
+zcpglystak 1 297 train
+zcpowftyft 0 300 train
+zcptkjtnfp 1 300 train
+zcpyjvcakk 1 301 val
+zcqdodvbxs 1 300 train
+zcqfxadxpx 0 300 train
+zcqhobvufy 1 99 train
+zcqimtwtdm 1 300 train
+zcqpuoxinz 1 301 train
+zcqqcqskon 1 300 val
+zcqzyztiyg 1 300 train
+zcsdvaspjz 1 300 train
+zcsgoypmqp 1 300 val
+zcsixjvwaz 1 300 val
+zcsrycydho 1 300 val
+zcstppxyul 1 300 train
+zcswqkeiaq 0 300 train
+zcsxtxbjvk 1 300 train
+zctathiiwv 1 300 train
+zctcyovstn 1 300 train
+zctgaeefax 1 300 train
+zctgtnjpuu 1 300 train
+zcthiwrsfz 1 300 val
+zctlyefupp 1 298 train
+zctwbivjzh 0 300 train
+zctwfbqpyt 1 301 train
+zctzgovxsu 1 300 val
+zcucfxufwz 1 300 test
+zcupljcchq 1 300 train
+zcuvkwpspq 1 300 train
+zcuysatpfz 1 300 train
+zcvfvtosqn 1 300 train
+zcvinalvmz 1 300 val
+zcvipssezm 1 300 train
+zcvnauvcgg 0 300 train
+zcvqdvctua 1 298 train
+zcvxxffava 1 299 train
+zcwcmjubox 1 300 train
+zcwdcgcyrk 1 301 train
+zcwddkqley 1 300 val
+zcwfjgkepz 1 300 train
+zcwiftkadx 1 300 train
+zcwjeobgun 1 300 train
+zcwnacrail 1 300 train
+zcwnpkzfza 1 300 test
+zcwsatoobo 1 300 val
+zcwvmhvrom 1 300 train
+zcwyysgvjz 0 300 train
+zcxadvzmbp 1 300 train
+zcxatsweza 1 300 train
+zcxavlizzw 0 300 train
+zcxcmneefk 1 300 test
+zcxfxhepys 1 300 train
+zcxkbbmzcp 1 300 val
+zcxsdtdzqu 1 300 train
+zcxshimzyg 0 301 train
+zcxvjkexks 1 300 train
+zcxyedqnnl 1 298 train
+zcxymqfjxi 1 300 val
+zcxzifxhuu 1 241 train
+zcyorxiaeu 1 300 train
+zcyszwygds 0 300 train
+zcyujkwbhk 1 300 train
+zczcdldtqi 0 301 train
+zczcpapuju 1 300 train
+zczdhxixgw 1 300 train
+zcztxhaesn 1 300 train
+zdaaavldyi 1 300 train
+zdabddvnrb 1 300 train
+zdahenxqkw 1 241 train
+zdajrjjuuj 1 300 train
+zdaqmhxtlt 1 300 train
+zdawcjkuwt 0 300 val
+zdazldtjmj 1 301 train
+zdbcmhhigk 1 300 val
+zdbdbhyplo 0 300 train
+zdbdhdigbs 1 300 val
+zdbejgoqzy 0 300 val
+zdbpqzetex 1 300 train
+zdbzkymvvs 1 300 train
+zdbzspyrbo 1 300 train
+zdcbreqqzj 1 300 val
+zdccdhrsaj 0 300 train
+zdcdwxbftw 1 298 train
+zdchuhkbaz 1 300 train
+zdckayghhi 0 300 train
+zddcoycwxr 1 300 train
+zddghaforv 1 300 train
+zddjutmkux 1 298 train
+zddlakutev 1 300 train
+zddlxlbzfd 0 300 val
+zdetbejanc 1 241 train
+zdexnebabf 1 300 train
+zdeyxohjer 0 301 train
+zdfcyguoet 1 300 train
+zdfgpzdqub 1 300 train
+zdfonrohon 1 300 train
+zdfuizaagw 1 300 train
+zdgpyfnvfr 1 300 train
+zdgtyxwrnr 1 300 train
+zdhbbtuuzi 1 300 val
+zdhcwfpzut 1 300 train
+zdhgcalixr 1 300 train
+zdhkqlerlf 1 300 train
+zdhktcshkd 1 300 val
+zdhlzusyxx 0 300 train
+zdhmhvkvqf 0 300 train
+zdhqxxhplk 1 241 train
+zdhrbexqxz 0 300 train
+zdhrhqmorn 0 300 train
+zdhvdwlisa 1 300 train
+zdieiezcfx 1 300 train
+zdieverhrd 1 300 train
+zdifjhxlvb 0 300 val
+zdihoguqyl 0 300 train
+zdihvtnqgi 1 300 test
+zdikkwvklh 1 300 train
+zdiloqosrd 1 300 train
+zdiszsbkfx 1 299 val
+zdiumtjdbh 1 300 train
+zdiyfjlefv 1 301 train
+zdjbhyslao 1 300 train
+zdjdarpamb 0 300 train
+zdjggiwdqh 1 300 train
+zdjhvmtxvt 1 300 val
+zdjjvppdoo 0 300 train
+zdjqvjmfqn 0 300 train
+zdjtgmnaho 1 298 train
+zdjvlyllpj 1 301 train
+zdjwmnafph 1 240 train
+zdjwuiyjkt 1 240 train
+zdkewqipdd 1 300 train
+zdkhptrwid 1 300 train
+zdkjiipngr 0 300 val
+zdkldehthu 1 300 train
+zdkmfrwgap 1 300 train
+zdkwupmgmv 1 300 train
+zdkxhgkwvw 1 301 train
+zdkxmsmjwe 1 300 train
+zdkyyawcwe 1 299 test
+zdldobedod 1 300 train
+zdlhavfmit 0 300 val
+zdllrmzfnt 1 300 train
+zdlxyeciih 1 300 train
+zdlyjfwyxk 1 300 val
+zdlywudszl 1 300 train
+zdmelowuxs 1 299 test
+zdmkbrrjyt 1 300 val
+zdmknyhzoo 1 300 train
+zdmqenjybc 1 300 train
+zdmqvcbmxv 1 600 train
+zdmwnmegjh 1 300 train
+zdmxzwnphr 1 301 train
+zdncqbrhom 1 301 train
+zdndjqprgp 1 300 train
+zdnepyqjiy 0 300 val
+zdnhrmqxvu 1 300 train
+zdntzsnoyl 1 300 test
+zdnxjguogk 1 300 train
+zdnyhqfmri 1 300 train
+zdojcjusnh 1 300 val
+zdokeyjwbf 1 300 train
+zdpggedkfj 0 300 train
+zdpmjrfctz 0 300 train
+zdpnrmjsxk 1 300 train
+zdprazmiaa 1 300 train
+zdpvvfjwix 1 241 train
+zdqbsztiqv 1 269 train
+zdqhjbmvmt 1 300 train
+zdqxotvksm 1 300 train
+zdrgcthmjy 1 296 val
+zdrjfakfnt 0 300 train
+zdrlhxzrca 1 300 val
+zdrofssxwx 1 300 train
+zdrwflmpgk 1 300 val
+zdrwoaqygo 1 300 train
+zdsfaidpyy 1 300 val
+zdsgxenqvx 1 302 train
+zdsnvypbbu 1 300 train
+zdsqautfvv 1 300 train
+zdtkhaxrkj 1 300 train
+zdtptwysld 1 300 val
+zdtudfdgtp 1 300 train
+zdtumyprlv 1 300 train
+zdtuoykhnh 1 300 val
+zduehwyukt 1 300 val
+zdulrvmfyc 1 300 train
+zdunpeofrd 1 300 train
+zduohvqqed 1 300 val
+zduopmyxgr 1 300 val
+zduotrufji 1 300 val
+zdurkznxhi 1 300 train
+zdusbtzxyg 1 300 train
+zduvfavftl 1 300 train
+zduzxuywen 1 295 train
+zdvhmctfug 1 241 train
+zdvrkrjcts 1 300 train
+zdvvpfateh 1 249 train
+zdvxgyjsjr 1 298 val
+zdvzavvspr 1 300 train
+zdweakuapu 1 297 train
+zdwtvaqbmh 1 300 train
+zdwwupptev 1 240 train
+zdxdtfpgpi 1 300 train
+zdxihsdwlq 1 300 val
+zdxiiyoicd 1 300 train
+zdxjihflbe 1 298 train
+zdyckloybc 0 300 val
+zdyftooudp 1 300 train
+zdygffewqw 1 300 train
+zdypbhbbbl 1 300 train
+zdypuebxeh 1 300 train
+zdzffvzdcl 1 301 train
+zdzgsbqzml 0 300 train
+zdzkmkfzke 1 298 train
+zdzknyqdkl 1 300 train
+zdzlwayazi 1 300 train
+zdzpzoaafh 1 297 train
+zdzvkctcgd 1 300 train
+zdzydjqbps 1 300 train
+zeacsjqljl 1 301 train
+zeagjeexwd 0 300 train
+zeaijmbldb 1 300 val
+zeakelpslu 1 300 train
+zebbuiheiu 1 300 train
+zebguwkapm 1 300 train
+zebodtlxwp 1 300 train
+zebpoqrbot 1 300 val
+zecifnbehq 1 298 train
+zeckqixotc 1 136 train
+zecnetmwlu 1 300 train
+zecriwkwmg 1 143 train
+zecrrvsbvg 1 300 train
+zectsbzsks 1 300 train
+zecvvrarrz 1 300 train
+zecykjdlru 1 297 train
+zeczwhtenf 0 241 train
+zedgrjpnzj 1 300 train
+zedipvpaxn 1 241 train
+zedirvvbae 0 300 val
+zedntivqyd 1 298 val
+zedryckeqr 1 300 train
+zedvdaksqn 1 300 val
+zedvwmkaey 1 240 train
+zedwjloxfe 1 300 val
+zeedngbelh 1 299 val
+zeekakenpt 0 300 train
+zeeoowztak 0 300 train
+zeepectpta 1 301 train
+zeexzaquee 1 300 train
+zefgrejpez 1 300 train
+zefihtxbyt 1 298 val
+zefnkrakyl 1 297 train
+zefnxcyhde 1 300 train
+zefpvybkmp 0 300 train
+zefqhoewww 0 300 train
+zefsbbegjb 0 300 train
+zegezrubss 1 300 train
+zegionsphz 0 300 train
+zegivghsyd 0 300 train
+zegqimvoey 1 300 train
+zegtybkwtb 1 300 train
+zehhvurllf 1 300 train
+zehpwyukfd 1 300 train
+zehsfunzox 1 299 test
+zeijohxyjc 1 301 val
+zeiklglink 0 300 train
+zeiolofriw 1 300 train
+zeivojfkbb 0 300 val
+zeizwropst 1 300 train
+zejalimkaj 0 300 train
+zejayrbkts 0 300 val
+zejcwwndex 1 300 train
+zejkpghtay 1 301 train
+zejqflqcag 1 300 train
+zejscnlwpr 1 300 train
+zejvtwddac 1 300 train
+zejwzdeabv 0 300 train
+zejxfhjdpm 1 239 val
+zejydxripq 0 295 train
+zejznzandc 1 300 train
+zekcwwiwvv 1 300 train
+zekmffwenp 1 300 val
+zekmqgibhs 1 300 train
+zeknassdfm 1 300 train
+zekrcockwd 1 300 val
+zekycdkhdv 0 300 train
+zelfpkiuex 1 300 train
+zelgpxflfe 0 301 train
+zelilgxpvc 1 300 train
+zeljvtzwuw 1 300 train
+zeljwpjvei 0 300 val
+zelktqryvv 1 297 train
+zelpffzngu 1 300 train
+zelpigukcu 0 300 train
+zemajumdau 1 300 train
+zembaegzgz 1 300 train
+zembwbqyol 1 300 train
+zemdoyovrf 1 301 val
+zemefqmcvh 1 300 train
+zemfnixlhi 1 300 val
+zemjtdddfg 1 300 val
+zemkavenuv 1 300 val
+zemllauqxt 1 300 train
+zemnldabpd 1 300 train
+zemnrqungj 1 300 train
+zemxfadqul 0 300 train
+zemzjdbjqk 0 300 train
+zenigfpyzy 1 300 train
+zeniicgabd 0 300 train
+zenpspbukk 1 300 val
+zenwwyefzm 1 300 train
+zeobrlfuxk 1 300 train
+zeobruhtvs 1 300 val
+zeofgscpwj 1 300 train
+zeojjyremc 1 300 train
+zeomlrebqu 1 300 train
+zeoqaqnejv 1 300 train
+zeoradpeam 0 300 train
+zepazzmrsc 1 241 train
+zepgiunwkm 0 300 train
+zepjyviqxp 1 300 train
+zepqdiybci 1 300 train
+zepsangjjb 1 300 test
+zeqcvsbxyf 1 300 train
+zeqggvbkut 1 300 val
+zeqjgtjmxm 0 300 val
+zeqmlwnifg 1 300 train
+zeqocqwypy 1 300 train
+zeqqswqitb 1 298 val
+zeqrwhlnzz 1 300 train
+zequcibqpu 1 300 train
+zequmhrxet 1 300 val
+zeqxcnvtwn 1 300 train
+zeqxrfuxyg 1 300 train
+zergnjcszm 1 300 train
+zerubrkern 1 300 train
+zerwujccgz 1 241 val
+zeryimwryh 1 300 train
+zesampvxex 1 300 train
+zesghygqyo 1 300 train
+zesikjnoij 1 300 train
+zesmmfconp 1 300 train
+zesnphumru 0 301 train
+zesonxeudj 1 300 train
+zespqsepkp 1 299 val
+zesprlrchj 1 147 train
+zesrvnbegi 1 300 train
+zestnycbli 1 299 train
+zesugidyjg 1 300 train
+zetbqpucpu 1 298 val
+zetkmzprvm 1 300 val
+zetmtsauey 1 300 train
+zetvnmshmw 1 300 train
+zeuhmhopuw 0 239 train
+zeujhziova 1 298 train
+zeuqdyakda 0 300 train
+zevblyyjyz 1 300 train
+zevdrazbtl 1 300 train
+zevjaxtggn 1 300 val
+zevnbbpzan 0 300 train
+zevnkabogx 1 300 train
+zevpdhlbvz 1 300 train
+zevqhglyrv 0 300 train
+zevsgxgvme 1 300 train
+zevzdaoknm 1 300 train
+zevzoxnqlb 0 300 train
+zewamzzvcv 1 300 train
+zewcbmwtpx 1 300 train
+zewglgcial 1 300 train
+zewhiheboi 1 300 train
+zewjjvygcr 1 300 val
+zewluzlkbe 1 300 train
+zewrzexlut 1 300 val
+zewtytjwwd 0 300 train
+zewzrkwbsv 1 300 train
+zexdojdjph 1 300 train
+zexeesiazc 1 300 test
+zexgcnqtze 1 300 val
+zexlgncolb 1 301 train
+zexnxltjdh 1 301 train
+zeycjdqush 1 300 train
+zeyelxqrvp 1 300 train
+zeyrwmdlht 1 300 train
+zeyssybzup 1 300 train
+zeyukwhlnx 1 300 val
+zeyxpdznso 1 300 train
+zeyxycqrwc 0 300 val
+zezgnbwgzh 1 300 val
+zezletzemg 1 299 train
+zezmeqsafo 1 300 train
+zezndwpclc 1 300 val
+zezoujrxve 1 300 val
+zezrsaoswt 1 299 train
+zfabntnwpm 1 300 train
+zfalofgncr 1 301 train
+zfamzpsrxq 0 300 val
+zfarvtxcax 1 300 train
+zfbekxzpvf 1 299 val
+zfbrjkugbd 0 300 val
+zfbrpkojvc 1 300 train
+zfbyakbvai 1 300 train
+zfbyibpnuu 1 300 train
+zfbyxckzxh 1 300 train
+zfbyzerbwh 1 300 val
+zfcbqfafgc 1 301 val
+zfcldmwikh 1 300 train
+zfcsrmgzlo 1 300 train
+zfcydsodgk 1 300 val
+zfdgmiuyww 0 300 train
+zfecmsiodq 0 300 train
+zfeczhrdmy 1 300 train
+zfejvtggnk 1 300 train
+zfepwtqwsm 1 300 train
+zfesoogcfd 0 300 train
+zfewguavdq 1 300 train
+zfeydpvpxo 1 301 train
+zffcykhknq 1 300 train
+zffnhhhwes 1 300 train
+zffofixoeh 1 301 train
+zffuvcttin 1 300 val
+zfgbolrxzv 1 300 train
+zfgdlmzecu 0 300 val
+zfgeruxqez 1 300 val
+zfgfbzoltd 1 300 train
+zfgisahckz 1 300 train
+zfgjechdto 0 300 train
+zfgvatzvkk 1 300 train
+zfgywgnvau 1 301 train
+zfgzgwyjiv 1 83 train
+zfhgqbdupe 1 300 train
+zfhguufzut 1 300 train
+zfhiddxcul 1 300 train
+zfhjzvlxbp 1 301 train
+zfhvthqlgr 1 300 train
+zfiahqoaxf 1 300 train
+zfiheyhrvt 1 241 train
+zfilbmlbfu 1 300 val
+zfilkukzpy 1 300 train
+zfinhcqxwb 1 300 train
+zfiqxxmtwf 1 300 train
+zfivbrmnnt 1 300 train
+zfjcatexut 1 300 train
+zfjfsdyhko 1 300 train
+zfjkkfccrz 1 300 train
+zfjpfevuph 1 300 train
+zfjsgnpoeb 1 300 train
+zfkcdbrmzp 1 297 val
+zfkgevlnur 1 300 test
+zfkhzeamne 1 300 train
+zfkqowplog 0 300 train
+zfkrtmzvnw 1 300 train
+zfkudspkxk 1 300 train
+zfkzyksazl 1 300 train
+zfllatvnhp 1 300 val
+zflukbdaso 1 300 train
+zflwultxbq 1 300 val
+zfmcuqzxgc 1 99 train
+zfmghhqqmy 0 300 train
+zfmpynklai 1 300 train
+zfmxdptazo 1 300 train
+zfmxfyjnse 1 300 train
+zfnbkyefuh 0 300 train
+zfnjffauct 0 300 train
+zfnluuhkuw 1 241 train
+zfnozrolve 1 300 train
+zfnrrxzfpw 0 300 train
+zfnysyusmg 1 300 train
+zfnzyphqyt 1 300 train
+zfobicuigx 0 300 test
+zfofjlxing 1 300 train
+zfojhhzsnc 1 296 val
+zfooqrkgcz 1 296 train
+zfpadeycvf 1 300 train
+zfpgjdonve 1 300 val
+zfpifdbprt 1 300 train
+zfpjdmkmgy 1 300 train
+zfpnlcublw 1 301 val
+zfpoceeeof 1 300 train
+zfptqyaxnz 1 300 train
+zfpvzwerju 1 300 train
+zfpwhrtinq 1 300 train
+zfpzkjpunn 1 300 train
+zfqcegwacu 1 300 train
+zfqfcsumda 1 299 test
+zfqrsiefga 1 300 train
+zfqvqyzeyo 1 300 train
+zfrbmelcwy 1 300 val
+zfrdomsakt 1 300 train
+zfrdxuohtj 0 300 train
+zfrqdqczqc 0 300 train
+zfrqtzropn 0 300 train
+zfrrixsimm 0 300 test
+zfrwxjhifa 1 301 train
+zfsakgoqpw 1 299 train
+zfsixhoxke 1 301 val
+zfsjxtmgxc 0 301 train
+zfsklbauko 1 300 train
+zfsnfogosr 1 298 train
+zfstshvymv 1 300 train
+zfsxgimrqe 1 300 val
+zftamksfwq 1 300 val
+zftbxstamr 1 300 train
+zftekxeini 1 300 train
+zftexmgxrm 1 298 train
+zftmoqardo 1 300 val
+zftphdvghm 1 300 train
+zfumefvvle 1 300 train
+zfunokdrrs 1 300 train
+zfuofgrghp 1 300 train
+zfuxcwiwpq 1 300 train
+zfuxntvllr 1 300 train
+zfvcyvaked 1 300 train
+zfvejxjwat 1 300 train
+zfvfgzdzec 0 300 train
+zfvfqaujsf 1 300 train
+zfvozhecml 1 300 train
+zfvvioipqf 1 300 train
+zfvxcwwjpe 1 300 val
+zfvytrcptx 1 300 train
+zfwivfhtau 1 300 train
+zfwjyiklzz 1 300 train
+zfwmojpvrw 1 300 train
+zfwqmeqgky 1 300 train
+zfwzvcxzym 1 300 train
+zfxbsrnwyg 1 300 train
+zfxiddjpcy 1 300 train
+zfxlulxpdr 1 299 train
+zfxrdjimny 1 297 train
+zfxutnqnbo 1 300 train
+zfxutnznfa 1 300 train
+zfxydordsm 1 300 train
+zfybugafky 1 299 train
+zfyczzssiz 1 300 train
+zfydwibabm 1 300 train
+zfyegagxsu 1 300 train
+zfyjvpcdmt 1 300 train
+zfymnlesyt 1 299 train
+zfzfhbcfxq 1 300 train
+zfzggdaxja 1 300 val
+zfznxxzrdd 1 300 train
+zfzoyvhpta 0 300 train
+zfzwebeaby 1 147 train
+zfzwsnkokl 1 300 train
+zfzxgbddtt 1 300 train
+zfzzlgqmyj 1 300 train
+zgaeobvngf 1 300 train
+zgaipearkf 1 300 train
+zgambitwhp 1 300 train
+zganfnadhh 1 300 train
+zganvxsuud 1 300 train
+zgarfedssk 1 300 train
+zgaudgglyq 1 298 train
+zgbcgauaza 1 300 val
+zgbdwlnfrw 0 300 train
+zgbgdcsrvd 1 300 val
+zgbhzkditd 1 299 test
+zgbiisdyqv 1 300 train
+zgboxwraaw 1 300 train
+zgbsczmprl 1 300 val
+zgbxbwigdu 1 300 val
+zgbxpzlxcn 0 300 train
+zgcgrkbnjg 1 300 train
+zgchsfhzfk 1 300 train
+zgcpgaqhpg 1 300 val
+zgcppxticu 1 300 train
+zgcsorvrmy 1 300 train
+zgcwifidmo 1 300 train
+zgcwkjjcbk 1 300 train
+zgcwolwyol 1 300 train
+zgcyxqjjba 1 300 train
+zgdhyhygoz 1 300 train
+zgdsgcjdym 1 300 train
+zgdtgitkle 1 300 val
+zgdtjzfrad 0 301 val
+zgduyagunm 1 300 train
+zgebbpgcnb 1 299 val
+zgeemhokbd 1 300 train
+zgejiitsis 1 300 train
+zgektlpibs 1 301 train
+zgelpvbklv 1 300 train
+zgewgnybei 1 300 train
+zgfcwqhyvs 0 300 train
+zgfvukpxqr 1 301 train
+zgfyuvefmz 1 300 train
+zggfcswjex 1 300 train
+zggjxxwfhn 1 301 train
+zggktqilsk 1 300 train
+zggqnbdtfn 1 300 train
+zggsudeylf 1 300 train
+zgguimgjtt 1 298 train
+zggxtwddeu 0 300 train
+zggyeqgnle 1 300 train
+zghcedasdd 1 300 train
+zghlgskbze 1 300 train
+zghozyrqbj 1 300 train
+zghrewrzyx 1 300 train
+zghtbyossg 0 300 train
+zghygaskkf 1 300 train
+zghyggthto 0 300 val
+zghyucatto 1 300 train
+zgiaeieywi 1 241 train
+zgidgpzmwh 1 298 train
+zgiebwjann 1 300 val
+zgiiwgylsm 1 300 val
+zgijolxlbw 1 300 train
+zginlpggsb 1 297 train
+zgiplreccp 1 300 train
+zgisbdxwig 1 300 val
+zgivmxzann 1 300 val
+zgiypcmpic 1 300 train
+zgiyybvgdy 1 300 train
+zgjczchmlm 1 300 val
+zgjhmoppgp 1 300 train
+zgjnbmzbgl 1 300 train
+zgjosltkie 1 300 test
+zgjowddzft 1 300 train
+zgjsdcfsxd 1 300 train
+zgjuobyjvh 1 300 val
+zgjwakksoj 1 300 train
+zgkmysdjrp 1 300 train
+zgkucemvwx 1 300 train
+zgkvhssfev 1 300 train
+zgkvxcnkho 1 300 train
+zgkzdizmwu 1 300 train
+zgldagyxup 1 300 train
+zgldekzvnl 1 300 train
+zgldoafdwd 1 300 train
+zgleprqujq 1 300 train
+zglgidpizh 1 301 val
+zglixpvcna 1 300 val
+zglkqavueb 1 300 val
+zgloukmmdr 1 300 train
+zglpjttgus 1 300 train
+zglqbfofge 1 300 train
+zglrhmwxic 0 300 train
+zglykhffzv 1 300 train
+zglzprijut 1 300 train
+zgmaslzbfe 1 301 train
+zgmbofjvqn 1 300 train
+zgmewycnvs 0 300 val
+zgmjmhfqtx 1 300 train
+zgmvsysnms 0 300 train
+zgmyyshmgh 1 241 train
+zgnbmncyft 1 300 train
+zgnsapfgua 1 83 train
+zgnuoeryrx 1 301 train
+zgocmpqoii 1 300 train
+zgohgydzgr 1 290 train
+zgokkfuaqp 1 300 val
+zgonzimula 1 300 train
+zgooojrtxp 1 300 val
+zgoqlydiwd 1 300 train
+zgownpvohu 0 300 train
+zgpdfunuwf 1 300 train
+zgpfudknym 1 302 train
+zgpnmgvxoe 1 300 train
+zgpvzypvop 1 300 train
+zgpwwojcfi 1 300 train
+zgpxvrspxj 1 300 train
+zgqahnxjqh 1 300 train
+zgqccfhlqq 1 300 val
+zgqcqzzyxb 0 300 train
+zgqdrpqthv 1 300 train
+zgqedfngkz 1 300 val
+zgqkhlylny 1 300 train
+zgqqdsygeb 1 300 train
+zgquddsedf 1 300 train
+zgqvdvalog 1 300 val
+zgqznsmnqh 1 300 val
+zgrawkqsss 1 300 train
+zgrbgpktcp 1 300 train
+zgrcwercsf 1 300 train
+zgrewzzfim 1 300 train
+zgrhuhgylx 1 300 train
+zgrqcsehlm 1 300 train
+zgrzwmxare 0 300 val
+zgsbhofcsw 0 300 train
+zgshawbwve 1 300 val
+zgsimqzqvh 1 300 train
+zgsislcbjd 1 300 train
+zgsnvgtuhf 0 300 train
+zgsolhunip 0 300 train
+zgstchqyip 1 300 train
+zgsuzugoxi 1 300 train
+zgsxqikrrw 1 300 train
+zgtfkiupau 1 300 train
+zgtgimvohc 1 300 train
+zgtgjzhdpb 1 300 train
+zgtmiarwtu 1 300 train
+zgtmoitsdy 1 300 train
+zgtnfceyai 1 300 train
+zgtvracoga 0 300 val
+zgtvxabdot 1 300 train
+zgubecfzai 1 300 train
+zgufnqrzag 1 301 val
+zgugtvfqjk 1 300 train
+zgujlfsqtf 1 300 train
+zgukufhxjx 1 300 train
+zgusfjyxnr 1 300 train
+zguvdirihu 1 300 train
+zguxagcjvd 1 300 train
+zgvhfagmbv 1 300 train
+zgvjfpzubp 0 300 train
+zgvjquinjx 1 301 train
+zgvpbkobxe 1 300 train
+zgvpiqhnfp 1 299 val
+zgvtjdhxgj 1 300 train
+zgvzuzkror 0 301 val
+zgwbjjcozp 1 301 train
+zgwcwubyih 1 300 train
+zgwmfvutei 1 301 train
+zgwrggyysr 0 300 val
+zgwtthryut 1 300 train
+zgwxrrfgmi 1 301 train
+zgxaihofif 1 300 test
+zgxilcfxjn 1 300 val
+zgxksfhqws 1 300 train
+zgxpicelwz 1 300 train
+zgxwikvenh 1 300 val
+zgybigjlfn 1 300 train
+zgydecyona 1 302 train
+zgyhttfzoz 0 300 train
+zgylinemyt 1 300 train
+zgyljltymp 1 300 train
+zgysijwfxl 1 300 train
+zgyvitgjil 0 300 train
+zgzaazfbtq 1 301 train
+zgzbirdorr 1 300 val
+zgzgmesopd 0 301 train
+zgzkieocmh 1 300 train
+zgzonjuape 1 300 val
+zgzpeqtqen 0 300 train
+zgzvbmimiq 1 301 train
+zhaiqernms 1 300 val
+zhasnjankh 1 300 train
+zhauqfsqxv 1 299 test
+zhavwfaykm 1 300 val
+zhaycskxln 1 300 val
+zhbbbsbwdx 1 300 train
+zhbblejbmh 1 298 train
+zhbbvohoke 1 300 train
+zhbcrktupi 1 300 train
+zhbgrtmses 1 300 train
+zhbjdbheoo 1 300 train
+zhbnpqlfub 0 300 train
+zhboshabwb 1 300 train
+zhbpuwkhgo 1 300 train
+zhbrgotitl 1 300 val
+zhbyrtejou 1 301 val
+zhcayfvmzd 1 300 train
+zhcgzvvpzt 1 300 val
+zhcjdearuy 1 300 train
+zhcssdcnsy 0 300 train
+zhcxqdwyuc 0 300 val
+zhcxxovyze 1 240 train
+zhddlgbeov 1 300 train
+zhdfmxqkpc 1 300 train
+zhdmffauco 1 300 train
+zhdmqdwxgm 1 300 train
+zhdsgrbabo 1 300 train
+zhdukreulo 1 300 train
+zhdydypdme 1 300 train
+zhemiyftwi 1 300 train
+zheoimyoil 0 300 train
+zherehcaek 1 298 train
+zhfahrzish 1 300 train
+zhfscjzpfa 1 302 val
+zhfslndmwv 1 300 val
+zhftwvtutp 0 301 train
+zhfxzkaemy 1 300 train
+zhfyuhonra 0 300 train
+zhgdnlfnxc 1 300 train
+zhgoklnwir 1 300 val
+zhgrrcvxcw 0 300 train
+zhgzksbzec 1 299 test
+zhhbzsxfqo 0 300 train
+zhhcadoqpq 1 300 train
+zhhfzbykbc 1 300 val
+zhhmrewold 1 300 train
+zhhnxwdrbs 1 300 train
+zhhvtuxyjp 1 300 train
+zhicnepasr 1 300 val
+zhikfuveaj 1 300 val
+zhinwryvae 1 300 train
+zhiqmhsyhp 0 297 train
+zhiuvbnqda 1 300 train
+zhiyaowjdu 0 300 train
+zhiyefssqo 1 300 train
+zhizorcnvb 1 300 val
+zhizsrrjcn 0 300 train
+zhjbfjoshu 1 300 train
+zhjkgdxdvv 1 300 train
+zhjktimmgp 1 300 train
+zhjqkhuvrx 1 298 val
+zhjvabhncs 1 300 train
+zhjzgmopci 1 301 train
+zhkdynwxfv 1 300 train
+zhkizxdcnc 1 300 train
+zhkplaxcgc 1 300 train
+zhkqkqmbsb 1 299 val
+zhkqxjalrq 1 300 test
+zhksmqfown 1 299 val
+zhkxgdqfij 1 300 train
+zhkxohiohl 1 300 train
+zhkyjzenio 1 297 train
+zhlaiuesaa 1 241 train
+zhlbanepqg 1 300 train
+zhleflsapp 1 300 train
+zhlehdxaxn 1 300 train
+zhlfjythvv 1 300 train
+zhlhmvpugd 0 300 train
+zhlkdzmzjs 1 300 train
+zhlqcnncsi 1 300 train
+zhlujpyzxd 1 300 train
+zhmaznszye 0 300 val
+zhmfwuyoag 1 299 test
+zhmhrqhabu 1 300 train
+zhmjtavtpn 1 300 train
+zhmkixrfbe 1 300 train
+zhmllgwhjm 1 300 train
+zhmogtkubt 1 300 train
+zhmstikdvr 1 300 train
+zhnaywdiks 1 300 val
+zhnbvajhru 1 300 val
+zhneufevji 1 300 train
+zhngrivgvt 1 300 train
+zhniscbosy 1 300 train
+zhnldyqwkc 1 298 train
+zhnnrodwvb 0 300 val
+zhnojqbrlx 1 300 train
+zhnpkhlafc 1 300 train
+zhntfoflwh 0 301 train
+zhnxhajpyh 1 300 train
+zhnztdounz 1 300 train
+zhogqwufob 1 300 train
+zhomicrvyw 1 300 train
+zhopdnywsb 1 300 test
+zhoqpzerjf 1 300 train
+zhoszukpks 1 300 train
+zhouyytxyi 1 300 val
+zhozqakqxb 1 300 train
+zhpatactee 1 299 test
+zhplmoxofo 0 300 train
+zhpsntuuxr 1 300 train
+zhpsrldbfa 1 300 val
+zhpzlssdsq 1 300 train
+zhqknikezo 1 300 train
+zhqsyxrwqs 0 300 val
+zhquxrufpp 1 300 train
+zhqxbnwham 1 300 train
+zhqzhccypt 1 300 train
+zhrfozkumx 1 300 val
+zhrgqbbjvh 1 300 test
+zhrjlyrjsb 1 301 train
+zhrjrsloix 0 300 train
+zhseykqkni 1 300 train
+zhskzlekga 1 300 train
+zhspruktpo 1 300 train
+zhsximnhqp 1 300 train
+zhtjuiskcr 1 301 val
+zhtrhkbyuy 0 300 train
+zhtscwxxfe 0 301 train
+zhtvgdoubj 1 300 train
+zhtxmvflho 1 300 val
+zhtzndwcjg 1 298 train
+zhuiemjrhf 1 300 train
+zhujkmuphr 1 300 train
+zhumfupsnp 1 300 train
+zhuofnfhhr 1 240 train
+zhuvimuucr 1 300 train
+zhuwamxphz 1 300 train
+zhuwavdxtw 1 300 train
+zhuxwpvobo 1 301 train
+zhvbcgzaof 1 300 train
+zhvbeblrqt 1 300 val
+zhvbptnwkq 1 300 train
+zhvczysnva 1 300 val
+zhvhnwfjbc 1 300 train
+zhvkybfhhi 1 300 train
+zhvobvdgui 1 300 train
+zhvpotrxsq 0 300 train
+zhvpwcvfcx 0 300 train
+zhvrsazgpi 1 300 train
+zhvxfumcsi 1 300 train
+zhvytfblbd 1 300 train
+zhwcdftewl 1 301 train
+zhwjgxkggu 1 300 val
+zhwlsdwmvj 1 300 train
+zhwltzcxik 0 300 train
+zhwtvlawvg 1 300 train
+zhwwyazsnt 1 300 train
+zhxccuhpvm 1 300 train
+zhxeooddtt 1 300 train
+zhxncrzpkp 1 300 train
+zhxtbdjvss 1 300 val
+zhxtmgsjjw 0 300 train
+zhxwxepcjy 1 300 val
+zhxyjgawcz 1 300 train
+zhyaxgcwcm 1 300 train
+zhydviurkg 1 300 train
+zhyfhwzzut 1 300 train
+zhyfjjwnsg 1 300 train
+zhyokciyjo 0 300 train
+zhysrmbjge 1 298 train
+zhyvvkmgrl 1 300 val
+zhyxbtmhym 1 300 train
+zhyxisxvzh 1 300 train
+zhyxtjrsyz 1 300 train
+zhzbnpotys 1 300 train
+zhzcydvvlo 1 300 train
+zhzgqgjume 1 300 train
+zhzizyooba 1 300 train
+zhznykzuxe 1 300 train
+zhzrjgiung 1 300 train
+zhzvbsitqm 1 300 val
+zhzvjkjune 1 300 val
+zhzxaswqsd 1 300 train
+ziaaicongv 1 300 train
+ziagvqaznp 1 300 train
+ziajwzbmxr 1 300 train
+ziamwcklzy 1 300 train
+ziapicelup 0 300 train
+ziarxzoszg 1 300 train
+ziatdczqvp 0 300 train
+zibhbkbnwz 1 300 train
+zibigjmwbj 1 300 val
+zibmzgbvtt 1 300 train
+zibxfxktai 1 300 train
+zicraudyff 1 300 train
+zicrmtxhft 0 300 train
+zidhsojqyc 1 300 val
+zidktajohb 1 300 train
+zidsbdilrm 1 300 train
+zidtoxfqzr 1 300 train
+zidvmkvjzv 1 301 train
+zidvwkwbhg 0 300 train
+zidwhnnngf 1 300 train
+ziebyrydag 1 297 train
+ziegizulrl 1 300 val
+zieliszkaj 0 300 train
+zieqbadlrh 1 301 train
+zietoartkv 1 300 train
+zievpgbjrz 0 300 train
+ziexhtsluo 1 300 train
+ziexmsthog 0 300 train
+zieyfjzcqk 1 300 val
+zifbcajdlz 1 302 train
+ziffnybneu 1 301 val
+zifmjoryir 1 300 val
+zifrfihcoo 1 300 train
+zifzmugjdv 1 300 val
+zigbepfygf 0 300 train
+zigfgycokq 1 300 train
+zigkirnltw 1 300 train
+zigodhdawk 0 240 train
+zigzhwlpcd 1 300 test
+zihexottdz 1 300 train
+zihhfwedlg 1 301 val
+zihjooimpc 1 297 train
+zihnzbhbqg 0 300 train
+zihqkgktua 1 300 train
+zihzqhcbtw 1 300 train
+ziidzfzcwh 1 300 train
+ziijblwcgv 1 300 val
+ziimeatute 0 300 train
+ziipxxchai 0 300 test
+ziiwqegsgd 1 300 val
+zijoelafvh 1 300 train
+zijptahioc 1 300 train
+zijromfngg 1 300 train
+zijvekquyq 1 300 train
+zijwexwxyx 1 300 train
+zikdzoltmd 1 300 train
+zikedaxmlg 1 300 val
+zikjatxcbo 1 300 train
+zikogeqyhi 1 300 train
+zikqccjede 1 300 train
+ziktsjkugz 1 300 train
+zilalokmra 1 300 train
+ziletvhgfl 1 300 train
+zilhhuhjcv 1 300 val
+zilqcumfyv 1 300 train
+zilqngcakp 0 300 train
+zilqucorio 0 300 test
+zilrmpukur 1 300 train
+zilsfbpqek 1 300 train
+zilvencnfv 1 300 train
+zimcqqtpaf 1 300 train
+zimdadrfzq 0 300 train
+zimfsuotug 1 300 train
+zimlqltgnt 1 297 train
+zimpdejmec 1 300 val
+zimpvmmixy 1 300 train
+zimtxclvzo 1 300 train
+zinglpxgzx 1 300 train
+zinqomdewu 1 300 train
+zintyfpjqc 0 300 train
+zinxlasdqb 1 300 train
+zinzckbgcq 1 300 train
+ziokafgigc 1 300 train
+ziokunqfox 1 299 val
+ziolekhiec 1 300 train
+zioxkpvmxr 1 296 val
+zioyoocdjz 1 300 val
+ziozendwlt 1 300 val
+ziozxmgxcn 1 300 train
+zipanrktbp 1 240 train
+ziphbixywq 1 300 val
+ziphgdhodd 1 300 train
+zipiyxgagr 1 300 train
+zipmkclglh 0 300 train
+zipmkmnypt 1 300 train
+zipomtoogg 1 301 val
+zipqxrshza 1 241 train
+zipxvmcryh 1 300 train
+zipyfmbmdo 1 300 train
+ziqarwpdiz 1 299 val
+ziqatgubdi 1 300 train
+ziqbazrfdk 0 300 val
+ziqbklrtkb 1 300 train
+ziqjamfzlv 0 300 train
+ziqlpjibra 1 300 val
+ziqlslhkuz 1 300 val
+ziqqvrmtrt 1 300 train
+ziqsauaeho 1 300 train
+ziqzqbmfsw 1 300 val
+ziresgcahe 0 300 train
+zirgxpzmjj 0 300 train
+ziricwvglw 0 300 train
+zirjbinvxh 1 300 train
+zirmjdmepa 1 300 train
+zirrljzsmv 1 300 train
+zirujlklpw 0 300 val
+zisasluawf 0 300 val
+zisctfalnh 1 300 train
+zisdbcwbcc 1 300 train
+zisghjdoka 1 300 train
+zispkqyxvg 1 300 train
+ziswtwgxij 1 167 train
+zitaceokgz 1 301 train
+zitcrnscpq 1 300 train
+ziteikbmxv 1 300 train
+zitfegvoaf 1 300 train
+zitmjqoknk 1 300 train
+zitraaiwdz 1 300 val
+zitvbigzzs 1 300 train
+zitvbwxfle 1 300 train
+zityyrzshj 1 300 train
+zitzfjzqfr 1 297 val
+zitzsdalrw 1 241 train
+ziucuyijsa 0 300 train
+ziuhgdyzzn 1 300 train
+ziuiexhfxz 1 300 train
+ziumacwbnq 1 300 val
+ziuozuktfc 1 300 train
+ziuvwtedos 1 300 train
+ziuxnjobxl 1 300 train
+zivalunoux 1 299 train
+zivchrfmua 1 300 train
+zivfzytrjv 1 300 train
+zivjrgesjj 1 300 val
+zivoqdobmh 1 301 train
+zivqpuqkmw 1 298 val
+ziwcygqpgh 1 300 train
+ziwdakctrp 1 300 train
+ziwddwtkja 1 300 train
+ziweqaekhl 1 298 train
+ziwfuxerht 1 301 train
+ziwpawixei 1 300 val
+ziwpqmamiw 0 300 train
+ziwqkswrdn 1 300 train
+ziwqxziokk 0 300 train
+ziwrbqsqty 0 300 train
+zixatyddzp 1 300 train
+zixbqrfzvg 0 300 val
+zixcifegkz 1 300 val
+zixfqomcfk 1 300 val
+zixjeydihh 0 300 train
+zixngaurwv 0 300 train
+zixunbmytz 1 300 train
+zixyxcvboz 1 300 train
+ziybrtisgb 0 300 train
+ziykprdwjl 1 240 train
+ziyonetpzi 1 301 val
+ziypevdckg 1 300 val
+ziywolbbpy 1 300 val
+zizaftjixq 1 300 train
+zizcrzziht 1 301 train
+zizjnzldqg 1 241 train
+zizjyeieci 1 297 train
+zizlnckmtg 1 300 train
+zizmgdoifm 1 300 train
+zizxneidzr 1 300 val
+zizzdncjuw 1 300 train
+zjackflbnq 1 300 train
+zjaictewrz 1 300 train
+zjaliembub 1 300 train
+zjapypkstg 1 300 val
+zjatoyujpi 0 300 train
+zjaudlgxzj 1 300 train
+zjaxktvfmb 1 300 train
+zjbcxxwyav 1 300 train
+zjbdwiiehj 1 240 val
+zjbfxatjnq 1 240 val
+zjbhdpxmcs 1 298 train
+zjblqulrag 1 300 val
+zjbsxuvfnl 1 300 train
+zjbttvbyra 1 300 train
+zjbwxmmrgk 0 300 train
+zjbztdltti 1 302 train
+zjcchmzyjl 1 300 train
+zjcglwtlrz 1 300 val
+zjcicdzech 0 300 train
+zjcpgizmgd 1 300 test
+zjcqyzggnu 1 300 train
+zjcsrvxcqx 1 300 train
+zjcyecbxhs 1 300 train
+zjcywrtwif 1 300 train
+zjdbruzhct 1 301 train
+zjdkitvkrh 1 300 train
+zjdlqhmdcg 1 300 val
+zjdtqrroou 1 300 train
+zjearwbkcc 1 241 train
+zjeayrkzyp 1 300 train
+zjelymxrip 1 300 train
+zjembwbgxd 0 300 train
+zjepecsqpy 1 300 train
+zjeynyeajs 0 300 train
+zjfcssmwiu 1 300 train
+zjfjxitnny 1 301 val
+zjfkdebpni 1 300 train
+zjfllgltee 0 300 train
+zjflrppdhf 1 300 train
+zjgcvyfsws 1 300 train
+zjgfmunefo 1 301 val
+zjguxzvyom 1 300 test
+zjgvlfrdeh 1 300 train
+zjgyjsmmzb 1 300 train
+zjhdsaicrl 1 300 val
+zjhjdatzda 1 300 train
+zjhjmduiqm 1 300 train
+zjhmmibena 0 301 train
+zjhpgqxxky 0 300 train
+zjhviffldg 1 300 train
+zjiiefyrtf 0 300 train
+zjijfdkjxm 1 300 train
+zjintloxhp 0 300 train
+zjitrpvvyq 1 300 train
+zjixxnymmw 1 300 train
+zjjehvquaq 0 300 train
+zjjjwfhwfe 1 300 train
+zjjpwtqufy 1 300 val
+zjjqnafnwb 1 300 train
+zjjruolncf 1 301 train
+zjkhcepjdd 1 288 train
+zjkjmaogmb 1 300 train
+zjkpaxregt 1 300 train
+zjkwbritnu 1 300 train
+zjldvpxqcg 1 300 train
+zjlhfuxfdd 1 298 train
+zjliehpnzv 0 300 train
+zjllnlgcsi 1 300 train
+zjlmvoawrd 0 300 train
+zjlmxthqud 1 300 train
+zjlnuokiyt 1 301 train
+zjlsrrnpzq 1 301 val
+zjlzfdtyhe 1 300 val
+zjmcqoojbp 1 300 train
+zjmejucrdk 1 300 train
+zjmhvazsku 1 299 train
+zjmrxqtbvv 1 299 train
+zjmtrhfztk 0 300 train
+zjmzqnyhek 1 300 train
+zjnjspuqhm 1 301 val
+zjnlexixmn 1 300 train
+zjnqojdvak 1 300 train
+zjnqxbizzx 1 300 train
+zjnrllmowq 0 300 train
+zjnsaapwsk 0 300 val
+zjnyvurdqn 1 298 val
+zjodgqdrpb 0 301 train
+zjoedvvfin 1 300 train
+zjoonppreb 1 300 train
+zjoxltbmbw 1 300 train
+zjpesbfwpu 1 300 train
+zjpnijjrkr 1 300 train
+zjpqdixdzm 1 300 train
+zjpysqhdva 0 300 train
+zjqpffqyww 1 301 train
+zjqpxrpkpl 1 300 train
+zjqtfotyeo 1 300 train
+zjqyiwptph 1 300 train
+zjqzgnoudk 1 300 train
+zjraavhqac 1 300 train
+zjrcpdzigd 0 300 train
+zjrdqaomkh 1 300 train
+zjrdzhztvw 1 292 val
+zjrlrqhjla 0 300 val
+zjrnvqcjbx 1 300 train
+zjrshbpdik 0 300 train
+zjrsiwmzms 1 300 train
+zjrskmsqnb 1 300 val
+zjrtctbjjy 1 301 train
+zjrumznqoo 0 300 train
+zjsdeuxkwn 1 300 train
+zjsguxzwei 1 300 train
+zjslwbyvwf 1 300 train
+zjsomsojnf 1 300 train
+zjspjjxnac 1 301 train
+zjsqghmopl 1 300 train
+zjsqunvsrm 1 300 val
+zjsswdobca 1 300 train
+zjszrjllkg 1 301 train
+zjtbbycpbc 0 300 train
+zjtcbcbzgu 1 300 train
+zjtdksxbwl 1 300 val
+zjthkylwry 1 299 test
+zjtifyduih 0 300 val
+zjtjbzpqda 1 300 train
+zjtllebbus 1 300 train
+zjtloxnavk 1 300 test
+zjtrzigxsy 0 300 train
+zjtsmmmcyd 1 300 train
+zjtsnqocwo 1 300 train
+zjtzksqrim 1 300 train
+zjuaieuvfy 0 300 train
+zjuifgefyl 1 300 train
+zjulgvcxed 1 300 train
+zjumzsbgpa 0 300 val
+zjumzuhpjb 1 300 val
+zjunbednvj 1 300 val
+zjuqinpzps 1 300 train
+zjuvlxezpf 1 300 val
+zjuwskbqkt 1 300 val
+zjvarjmtnc 0 300 train
+zjvbdahhub 1 300 train
+zjvbrmqubl 1 300 train
+zjvdzswjpn 1 300 val
+zjvpfgmcre 1 300 val
+zjvtamtaen 1 241 train
+zjvzawdwyy 1 300 train
+zjwdrgxnzc 0 300 val
+zjwvherbso 1 300 train
+zjxdphteym 0 298 val
+zjxdvxwegq 1 296 val
+zjxeptlacm 0 300 train
+zjxgldsnew 1 300 val
+zjxheahiuc 1 300 train
+zjxtoubyhg 1 300 val
+zjxuekbqpi 1 297 train
+zjxusmyafe 1 300 val
+zjxwukjkfh 1 299 test
+zjyabnrolw 0 300 train
+zjyvyaxwbu 1 300 train
+zjyysmctet 1 300 val
+zjzddhzrwq 1 300 train
+zjzleqyzah 1 300 train
+zjzssdxwtf 1 300 train
+zjztvgpyhd 1 299 train
+zjzumoazqv 0 300 train
+zkabnqrdcy 1 300 train
+zkadsbaxmz 0 300 train
+zkaeyumllj 1 300 val
+zkamlyqzao 0 300 train
+zkarzsylvk 1 300 test
+zkaxyjzvcd 1 300 train
+zkayphgjyz 1 300 train
+zkbazetzby 1 300 val
+zkbevpnuqt 1 300 val
+zkbihwbthl 1 300 train
+zkbltyaknf 1 300 train
+zkbpmwndou 1 300 train
+zkbqjexrjh 1 301 train
+zkbxctkzwo 1 300 train
+zkcajdijeo 1 299 test
+zkcayqqbxn 1 296 train
+zkcbavmyno 1 300 train
+zkcchostsq 1 300 val
+zkccqabasj 1 241 train
+zkcnxwpxlh 1 298 train
+zkcrmohnam 1 300 val
+zkcskkvixr 1 300 train
+zkdawusiti 1 299 test
+zkdexfqvyz 0 301 train
+zkdnihhfry 0 300 train
+zkdothbbxi 1 300 train
+zkdqoqlvqn 1 300 train
+zkdsnulstk 1 300 train
+zkdteggfxg 1 298 train
+zkdukutclw 1 297 train
+zkdvxghvti 1 300 val
+zkebtotfla 1 300 train
+zkeeozyccr 1 300 train
+zkejjlxpoz 1 300 train
+zkejuxqzpj 0 300 train
+zkepglhvpq 1 300 train
+zkeqluxvjc 1 300 train
+zkesyskywb 1 300 val
+zkeyaqctgr 0 300 val
+zkfagiknuv 0 300 train
+zkfdqxjtiu 1 300 val
+zkffleuquq 1 300 train
+zkfgwczfmx 1 300 val
+zkfiwyrzxo 0 300 train
+zkfjcgqwdz 1 300 train
+zkfritmrde 1 300 train
+zkfuvqoxsx 1 300 train
+zkgbcaqdru 1 300 train
+zkghvjkgfv 0 300 train
+zkgiywurow 1 300 train
+zkgozxlaku 1 300 train
+zkhgoxsauo 0 301 train
+zkhiwtjnbz 1 300 val
+zkhqwwhwcz 1 300 train
+zkhrbpkcmt 0 300 train
+zkhvluurue 1 300 train
+zkhxfdbsco 1 300 train
+zkiakewvyo 1 300 train
+zkibdudrtn 1 300 train
+zkibgycnwg 1 300 train
+zkiglsizpx 0 300 train
+zkiqmjaieo 1 300 train
+zkiqwuxryr 1 300 train
+zkirsrrnos 1 301 train
+zkitcrbojz 1 300 train
+zkjepzwavf 1 300 val
+zkjeyhahsk 1 241 train
+zkjgcqxdwp 1 99 train
+zkjjmhhqtr 1 300 train
+zkjniprwjl 1 300 train
+zkjomadmod 1 301 train
+zkjotbhaqb 0 300 train
+zkjpgkcrss 1 300 train
+zkjpsozxve 1 241 train
+zkjsxgjesm 1 300 val
+zkjttzyncb 1 300 train
+zkjxbxhqxv 1 240 val
+zkkdaonrmo 1 300 val
+zkkgfmanbe 1 300 train
+zkkitpsbdz 1 300 train
+zkkrxnwjum 0 300 train
+zkksmnscsf 0 300 train
+zklaubmhwr 1 299 val
+zklcpnykal 1 300 train
+zklgqqrjax 1 300 train
+zklsugjfap 1 300 train
+zkmctignws 1 298 val
+zkmgmfmgkz 1 300 train
+zkmhhwmzgn 1 299 val
+zkmiirjgdg 1 300 train
+zkmkchoidn 1 300 train
+zkmuuksdbl 1 300 train
+zkmvojrtjn 1 300 train
+zkndonaybe 0 300 train
+zkngmtovkg 1 300 train
+zkngpopdzk 1 299 test
+zkniaqdfbd 1 300 train
+zkoidnajho 1 300 train
+zkojndxtsc 1 300 val
+zkokhikmle 1 300 train
+zkombljdfs 1 300 train
+zkoqrazsze 1 300 test
+zkorjbuopn 1 300 train
+zkozaicvhg 1 300 train
+zkozezzyrf 1 300 val
+zkpcgwxykg 1 300 train
+zkpifsiabk 1 301 val
+zkpkbdhfli 1 300 train
+zkpzaichfv 1 301 val
+zkqavyvuva 1 300 train
+zkqbuxsbiu 1 300 train
+zkqkqocqok 1 301 train
+zkqlqgfbqn 1 300 train
+zkqtjtsihn 1 300 train
+zkqwrqwjyf 1 299 train
+zkraugbwcs 1 301 train
+zkrdisxeoe 1 300 train
+zkrescvrba 0 301 train
+zkrhxlyyzg 1 300 train
+zkrlvwigbl 0 300 train
+zkrprjsqft 1 300 train
+zkrsmilvuo 1 300 val
+zkrzcwgvte 1 300 train
+zksahxputc 1 301 val
+zksexkccfm 1 300 train
+zksnqhxwsz 1 300 val
+zkszfdjgeu 1 300 train
+zktckdsoih 1 300 train
+zktejsqpoj 1 300 train
+zktfvbaupk 1 300 train
+zktphcwtih 1 300 train
+zktscxobhn 1 300 train
+zkttggxflu 1 301 train
+zktuaqrqqv 1 300 val
+zkukjxromb 1 300 train
+zkupfdqqel 0 300 val
+zkupunxtkn 1 300 train
+zkutyjeywz 1 300 train
+zkuwezbuma 1 300 val
+zkuxdgmvqr 1 300 train
+zkuxsxwskj 1 300 train
+zkvacdxjxu 1 300 train
+zkveoqsvfa 1 300 train
+zkvgyxfrbj 1 300 train
+zkvhsozira 1 300 train
+zkviwwceqx 1 300 train
+zkvngcfjoe 1 300 train
+zkvrtjbkqj 1 300 val
+zkvzrmwyab 0 300 train
+zkwczgwxfw 1 300 train
+zkwfpxpywa 1 298 train
+zkwfuokscu 1 300 train
+zkxcwqeuez 1 300 train
+zkxiwxvfrw 0 300 train
+zkxtysukpw 1 300 train
+zkxykfdzmx 1 300 train
+zkyfkpdbdl 1 300 train
+zkyrjofpty 1 241 train
+zkywnsacnu 1 300 train
+zkzayncogi 1 300 train
+zkzecjtvns 1 300 train
+zkziyhhmkk 1 296 train
+zkzjamutis 1 300 train
+zkzoorluhn 1 298 train
+zkzqeaagaa 0 300 train
+zkzqkhxfpo 1 300 train
+zkzqwuusyq 0 300 train
+zkzuicqchn 1 300 train
+zkzyzmavqg 1 300 train
+zlagymkquj 1 300 train
+zlahfpmwxf 1 292 val
+zlahvmfgwr 0 300 train
+zlalrqeven 0 300 val
+zlaqjxtcsf 0 300 train
+zlashfymdo 0 300 train
+zlatzsfntz 1 300 train
+zlawvcbsyy 0 300 train
+zlbaumprys 1 298 train
+zlbhertlbm 1 298 train
+zlbikqiqey 0 300 train
+zlbmpaujcs 1 300 train
+zlbofutdjp 1 301 train
+zlbqrmbiib 1 301 train
+zlbviszsid 1 300 train
+zlbwmqopvp 1 300 train
+zlbzpdspzt 1 300 train
+zlcblyhhvx 1 301 train
+zlcdbnskbo 1 300 val
+zlcfxbdymt 0 300 train
+zlcfxxlacy 1 288 train
+zlckqdfhvj 1 300 train
+zlcpzktorc 1 300 train
+zlcrzkuqei 1 300 train
+zlcuktacbv 1 288 train
+zlcyzxajax 1 300 train
+zldawkggge 1 300 val
+zlddeecxiv 0 300 train
+zldfcndqjg 1 300 train
+zldjyvutvd 1 302 train
+zldldzqwlz 1 298 train
+zldnahlsnc 1 300 train
+zldsrcythi 1 298 val
+zldvtqhkxl 1 300 train
+zldzgyuxam 0 300 train
+zldzjidexf 1 300 train
+zledwzbtou 1 301 train
+zlefeowppk 1 288 train
+zlegfqgjde 1 300 val
+zleixuogzr 1 300 train
+zlemkqmezq 1 300 train
+zleochgysa 1 300 train
+zleppppdag 1 301 train
+zlermrhoiy 1 300 val
+zlesoctcve 1 298 train
+zlfayrruye 1 302 val
+zlfbugvmmh 1 300 train
+zlfbumxcxs 0 300 train
+zlfddaayjy 1 300 val
+zlffazzzsb 1 300 train
+zlfuvvoiql 0 300 train
+zlfvpzjelz 1 300 train
+zlfwamrnis 1 300 train
+zlfzykkxwa 1 300 train
+zlgcshuedb 1 300 train
+zlgczuhlvy 1 300 train
+zlgjatxlum 1 300 val
+zlglisdedi 1 300 train
+zlgppvdhoe 1 300 train
+zlgswtevyi 1 241 train
+zlhjdxdvaw 1 298 train
+zlhmvhxdzz 1 300 train
+zlhpepgjha 1 300 train
+zlhpzckgxm 1 300 train
+zlhvoufjou 0 300 train
+zlhvsxtmmv 1 300 train
+zlhvtmibnh 1 297 val
+zlhxvdidyo 1 300 train
+zlidzhghkw 1 300 test
+zliedrqium 1 300 train
+zliflhnxdo 1 300 train
+zlihduzoul 1 300 train
+zliifyngle 1 301 train
+zliyslxwcm 0 300 train
+zljcaycjry 1 301 train
+zljezlbusc 1 300 val
+zljgzrtral 1 300 train
+zljngnguuo 1 300 train
+zljsjovxdj 1 300 train
+zljvknwzqa 1 300 test
+zljwapokve 1 300 train
+zlkbcmygmq 0 300 train
+zlkkclefsv 1 300 train
+zlkoohzpcf 1 298 train
+zlkrzyjprk 1 300 val
+zlkyjrodrd 1 300 val
+zlkzrpuczg 0 300 train
+zllckhngmk 1 300 train
+zllgbpslut 0 300 val
+zllsasgfkp 1 294 train
+zlluotxoxr 1 300 train
+zlluquadxb 1 300 val
+zlmfubudaj 1 300 train
+zlmihdrosp 1 300 train
+zlmjpjodcd 1 300 train
+zlmnrdvokw 1 300 train
+zlmzvhjsgf 1 300 train
+zlnerwgquu 1 300 train
+zlnfyhdumd 1 300 train
+zlngdjbmbo 1 300 train
+zlngvfexbl 1 300 train
+zlnjeoazys 1 300 train
+zlnkjnswjr 1 99 train
+zlnlecsdjv 1 300 val
+zlnnjsddtt 1 300 train
+zlnofgtmzv 0 300 train
+zlnphbedts 0 300 train
+zlnrauumox 1 300 train
+zlnsdrzdgb 1 300 train
+zlnzbyocxd 1 300 val
+zlobtgqkbc 1 300 train
+zloeyrtcdh 0 300 train
+zlofleoueb 0 300 val
+zlofprvzrk 1 300 train
+zlohmfufig 0 300 val
+zloicyfcxr 1 300 train
+zloimltonb 1 241 train
+zlooarutsa 1 300 train
+zloqzvocyt 1 300 train
+zlotmdahcz 1 300 train
+zlpnbyiieq 1 300 train
+zlpngbhrrq 1 300 train
+zlpnybqwsw 1 301 val
+zlptftgjro 1 300 test
+zlpuuklxnz 1 300 train
+zlpuvdtsrm 1 300 train
+zlqajglhvd 1 300 train
+zlqdcocjrc 1 300 train
+zlqgtpkchx 1 300 val
+zlqkjcnxbc 1 298 train
+zlqlajyayj 1 300 train
+zlqodeztmf 1 301 val
+zlqqrfajtd 1 301 train
+zlqsyhmxed 0 300 train
+zlqueoknqs 1 301 val
+zlqutqwkmi 1 300 train
+zlrhmdlhsf 1 300 train
+zlriooefkj 1 300 val
+zlrlhzjccv 1 241 train
+zlrmbsnyam 0 300 val
+zlrsnquxvr 1 241 train
+zlrsutdacm 1 300 train
+zlrzisczqb 1 301 train
+zlsdhvgfbl 1 300 train
+zlsfxohcow 1 300 train
+zlskogfing 1 300 train
+zlsqiyjmvt 0 300 train
+zlssbxtdgm 1 300 train
+zlsursjrgd 1 301 val
+zlsyvupxyk 1 301 train
+zltamubaab 1 300 train
+zltaqovcmc 1 302 train
+zltgjdlldn 1 300 val
+zltiuwqjzj 1 300 train
+zltkajhxde 1 300 train
+zltvuckvqi 1 300 train
+zltwghgilz 1 300 train
+zlukluvcyp 1 300 train
+zlumfhhkmg 1 301 train
+zluxoexqww 1 300 train
+zluyyagzlk 0 300 train
+zlvaklmmrp 0 300 train
+zlvbexwiov 1 300 train
+zlvcfewxik 1 300 val
+zlvhsymxaz 1 301 train
+zlvjwrgyhe 1 300 train
+zlvjzbvnyo 0 300 train
+zlvrvwhasm 1 300 train
+zlvzvervvw 1 300 train
+zlwczlpayj 1 300 train
+zlwkgbywyi 1 300 train
+zlwlidvmqe 1 300 train
+zlwmstcyhx 1 300 train
+zlwndjarnh 1 300 train
+zlwqjarygb 1 300 train
+zlwtkfbvhd 1 300 train
+zlwxftfkgo 1 301 train
+zlwyzqoiyy 1 300 train
+zlxdkxnhxi 1 300 train
+zlxfqidduw 0 299 test
+zlxhvpvfbv 1 301 train
+zlxkwrizrf 1 300 val
+zlxnuayicn 1 300 train
+zlxyufjqqr 1 298 val
+zlyapmufai 1 300 train
+zlyisjmutr 1 300 train
+zlyldootgk 1 300 train
+zlymfgthru 1 300 train
+zlyojfboxm 1 300 train
+zlypbulyok 1 300 val
+zlyrsopqij 1 300 train
+zlzbsmacvq 1 300 train
+zlzdnibhhe 1 300 train
+zlznhnpouv 1 300 val
+zlzyukcsfl 1 300 train
+zmanhgysnh 1 300 train
+zmaztxiejl 1 300 train
+zmbafcubci 0 300 train
+zmbchfblwp 1 296 train
+zmbdxewevl 1 300 train
+zmbkkotccm 1 300 train
+zmbmqjhvop 1 300 train
+zmbnitmulk 1 300 train
+zmbrljyujg 1 300 train
+zmcbfnjewa 1 300 train
+zmciszomkw 1 300 val
+zmciyeiebe 1 300 val
+zmcmnkhvmq 0 300 train
+zmcoflkskn 1 300 train
+zmcoxkuuoa 1 300 val
+zmctgaubpq 1 300 train
+zmcwaocaeu 1 300 train
+zmdkxnjejh 0 300 train
+zmdlpeuohf 0 300 train
+zmdzmbfneh 0 300 train
+zmdztoiikw 0 300 train
+zmeewqlqvb 1 300 train
+zmeilyqlbl 1 300 train
+zmejudhuef 1 301 train
+zmenfauxhm 1 300 train
+zmepibubhp 1 300 train
+zmeqyjacsd 1 298 train
+zmetnrgxme 1 300 train
+zmetpwttnz 1 300 train
+zmfiveruie 1 300 train
+zmfjyoofct 0 300 val
+zmfnxkcdnd 1 300 train
+zmfrwryubq 1 301 train
+zmfyipnyaq 1 300 train
+zmgbvezhdw 0 300 train
+zmgffszavc 1 301 train
+zmgfrsuogx 1 300 val
+zmgmriucvl 1 301 train
+zmgqgueebu 1 300 train
+zmgttoxvcx 1 300 train
+zmguhqjyff 1 300 train
+zmgwqzewad 0 300 train
+zmhgnygphy 1 300 train
+zmhloqmteo 1 300 train
+zmhlsdtyyg 1 298 train
+zmhmhgqzrk 0 300 val
+zmhrjjvejo 1 299 val
+zmiamlizsv 1 241 train
+zmiasptbnb 1 300 val
+zmiezeyaqw 1 300 train
+zmifggvalj 0 300 val
+zmipxejwbk 1 300 train
+zmiwnsmtbr 0 300 train
+zmizedgetx 1 300 train
+zmizrpixgp 1 300 val
+zmjakupoly 1 299 val
+zmjfcxwrjw 1 300 train
+zmjfpfvgls 1 300 train
+zmjgwqcasd 1 301 val
+zmjkexlnry 0 300 train
+zmjksiqxuu 0 301 train
+zmjrnwkrzp 0 300 train
+zmjszxzxpz 1 300 test
+zmjxnyvkfs 1 300 train
+zmkboyyjqq 1 300 train
+zmkgymepgr 1 299 train
+zmkjbubbbb 0 300 val
+zmkjddceiy 1 300 train
+zmkmyjlzpt 1 299 test
+zmkpfhjxru 1 300 train
+zmkpjobtvj 1 300 val
+zmldqnxgkl 1 300 train
+zmlgooxogx 1 301 train
+zmljdphwgh 1 300 train
+zmlktkupcz 1 300 train
+zmlmareozd 1 301 train
+zmlmavyfyv 1 300 train
+zmlpmfbryq 1 300 val
+zmlqlldrzf 1 300 train
+zmluvqegoo 1 300 train
+zmlydmyuke 1 300 train
+zmlywaummw 0 300 train
+zmmciosrix 1 300 train
+zmmdjdpjra 0 300 train
+zmmffefuoy 1 300 train
+zmmhalkfri 1 300 train
+zmmjuqyten 1 300 train
+zmmurguoqn 1 300 train
+zmmyaeivkm 1 300 train
+zmndlwmybr 1 300 test
+zmnkvseoxs 1 300 train
+zmnloauxzb 1 300 train
+zmnvnlpasy 1 300 val
+zmojpnsder 1 300 val
+zmommwswai 1 300 train
+zmomraqohp 1 301 train
+zmoppezrkz 1 292 train
+zmoryxsvex 1 301 train
+zmottuthgc 1 301 train
+zmoxegqwxn 1 300 train
+zmpatopznh 1 300 val
+zmpbajutwz 1 300 train
+zmpdsggxzg 1 300 train
+zmpdtksfaq 1 300 train
+zmpemoespr 1 300 train
+zmpimfofyq 0 300 val
+zmplbhkwns 0 300 train
+zmpqeyjebl 1 301 val
+zmpxacepht 1 298 train
+zmqnnddsdj 0 300 train
+zmqntjesto 1 301 train
+zmqoqpzpuf 1 300 train
+zmqrcyefna 0 301 train
+zmqwivgisv 1 300 val
+zmrdtdwdct 0 301 train
+zmrdtytqyr 0 300 train
+zmricazfew 1 300 train
+zmrnjhfxed 1 300 train
+zmrqqtqyfg 0 300 train
+zmrsgsucfr 1 300 train
+zmrvgvnqzp 1 300 train
+zmrxygchhj 1 300 train
+zmsahcjmuz 0 300 train
+zmsblizuum 1 301 train
+zmsfyoxdou 0 300 val
+zmsglbswcn 0 300 train
+zmsjlvvwsu 1 241 train
+zmsndvuunv 1 300 train
+zmtbjdustm 1 300 val
+zmtfwgcqys 1 299 test
+zmtiukzllb 1 300 train
+zmtpjnacpo 1 300 train
+zmubddazht 1 300 val
+zmucaayqdd 1 300 train
+zmujxezkrv 0 300 train
+zmuoatciyy 1 300 train
+zmurwgrlic 1 300 train
+zmutszwcza 1 300 train
+zmvegdrqoy 1 300 train
+zmvfdxddja 1 300 train
+zmvglkpjkj 1 300 train
+zmvpooqmiw 1 300 val
+zmvtautodz 1 300 train
+zmvwhjtsfc 1 300 train
+zmwcknizsv 1 300 train
+zmwdiinadz 1 300 train
+zmwizwimgb 1 300 train
+zmwriovmpy 0 300 train
+zmwuzyimmp 1 298 train
+zmxalgtdzf 1 300 train
+zmxawpxibp 1 300 train
+zmxeiipnqb 0 300 test
+zmximdyhie 1 300 train
+zmxogyqqkj 1 296 train
+zmxrwaoajx 0 300 train
+zmyeigednf 1 301 train
+zmyeqaxlni 1 300 train
+zmygxqyves 1 300 train
+zmylyqwwod 1 298 val
+zmzeftdvky 1 300 train
+zmzeokskyv 1 299 test
+zmzgorfqca 1 300 train
+zmzjexoihb 1 300 train
+zmzlvstizv 1 300 train
+zmzqkcdcmw 1 299 train
+zmzvxklvxr 1 300 val
+zmzyeqfwou 1 300 train
+znafprdfbj 1 299 test
+znagtzjmdg 0 300 train
+znajtjbxfy 0 300 val
+znapxxyyze 1 302 val
+znaqbrqxtd 1 300 train
+znaugjbtpm 1 300 train
+znavjwhxtq 0 300 train
+znbagkobmk 1 300 train
+znbebecequ 1 300 train
+znbfztfitn 1 300 train
+znbhvtmrem 1 300 train
+znbkflxgoy 1 300 train
+znbmktbykd 1 241 train
+znbpuuixqx 1 300 train
+znbqnaruby 1 300 train
+znbriecxut 0 301 val
+zncceguari 1 300 train
+znchkgvbqi 1 300 val
+znckxsojok 0 300 train
+znclzrxipl 1 301 val
+zncmtqidbs 1 300 train
+znctzspdxq 1 300 train
+zndeyiyxdq 1 300 train
+zndlrlpwto 1 300 val
+zndxhueoji 1 300 train
+zneabotzrc 1 241 train
+znejmlotdy 1 300 train
+znejuddszx 1 300 train
+znelfrgytp 1 300 train
+znemclcnts 1 300 val
+znenuwqkic 1 300 train
+zneqozkzoo 1 300 train
+znetakpeno 1 300 val
+znevocgbpw 1 300 train
+znewsbepfj 1 300 train
+znexholuwp 1 300 train
+zneydxtaie 0 300 train
+znfpmjncvp 1 300 train
+znfqykkuoh 1 300 train
+znftribnvs 1 300 train
+znfuvjjufb 1 300 test
+znfvedfobp 1 300 train
+zngeueghdu 1 300 train
+zngxfldaae 1 300 train
+zngynpjudu 1 300 train
+znhirrnscg 0 300 train
+znhkipfkjg 1 300 val
+znhmobdwnv 0 300 train
+znhrqqxtwf 1 300 val
+znhuenqsfk 1 300 train
+znhugpivfr 1 300 train
+znibqnddht 1 300 train
+znickltiqa 0 300 train
+znicqofizj 1 299 test
+znidfanpjo 1 300 test
+znimabcisi 0 300 train
+znistrajpw 1 300 train
+zniwqlsubp 1 297 train
+zniypobelc 1 300 train
+znizwghudb 1 300 train
+znjdxtjlst 1 300 val
+znjeqyaynn 0 300 train
+znjolcshxu 1 300 train
+znjrxvpcmk 1 299 test
+znjupdqnwo 0 300 train
+znkeatsnov 1 300 train
+znkmaevntx 1 300 train
+znkmpecjqw 1 300 train
+znkonfcobf 1 300 train
+znkosjekbl 1 300 val
+znkyncdchs 1 300 val
+znlfmwhizc 1 300 val
+znlmysziqs 1 300 train
+znlqssjeyx 1 299 test
+znlqxzozcf 1 300 train
+znlxatknva 1 300 train
+znlzegqkbp 0 301 train
+znmedydicq 1 300 train
+znmzmierff 0 300 train
+znnexvrgmu 1 300 train
+znnmvbvrko 1 300 train
+znnqbkpanr 1 300 val
+znnrfazojd 1 300 train
+znnxknrfrw 1 300 val
+znnzpyryjs 1 300 train
+znnzyhzdmf 1 300 train
+znoqrkxcop 1 300 train
+znozrqyqho 1 300 train
+znpdbbsfvj 0 300 train
+znpdzyiezt 1 300 train
+znpeqmngnf 0 300 train
+znppbuahtc 1 300 train
+znppggjiln 1 300 train
+znpreasolz 1 300 train
+znpuglpoap 1 241 train
+znqadnzyjr 1 300 train
+znqcnxtnts 1 300 train
+znqhvvdpzk 1 300 train
+znqsovyojs 0 249 train
+znqtcsxunr 1 300 val
+znreasaemn 1 300 train
+znrfccvvpw 1 300 train
+znrixntqqb 1 301 train
+znrjcttefv 0 300 train
+znrofuaoid 1 300 train
+znrzzqhmhk 1 300 train
+znscgchymg 1 300 train
+znsdvhdxbv 1 300 train
+znsmymclwg 1 300 train
+znsntylmoo 0 241 train
+znsoaxtask 0 300 train
+znsognljjn 1 300 train
+znsotfxyaj 1 300 train
+znsqdtgwzh 1 300 val
+znsxeanewc 0 300 train
+zntdqxplda 1 300 val
+zntghmrheq 1 300 train
+znubjobabe 1 300 val
+znudmrmyux 1 300 train
+znuezglcoc 1 300 train
+znufvqhauq 1 300 val
+znuhjtpdec 1 300 train
+znunktevhx 1 300 train
+znuqqszlax 1 300 train
+znuremjvhy 1 297 val
+znuumkhdbu 1 300 val
+znuvosyesy 1 300 test
+znvankuyaw 1 300 train
+znvbsjpfpy 1 300 val
+znvdxgaoay 0 300 test
+znvgtocjuu 1 300 train
+znvjmmoebs 1 299 train
+znvmzpbkjr 1 300 train
+znvpvbgzgf 1 300 val
+znvspdpyaa 1 300 train
+znvtjvatjp 1 301 train
+znvxtenesd 1 300 train
+znwaukihcj 1 300 train
+znwcfojslw 1 300 train
+znwdchvshz 1 300 train
+znwjfyowfe 1 299 train
+znwlsmcgar 0 300 train
+znwmszzebe 1 300 train
+znwpajalyb 1 298 train
+znwqwrogrj 0 300 train
+znwrixvfka 1 300 train
+znwvufkuyy 1 301 train
+znwwakpnxt 1 300 train
+znxooikpiq 1 193 train
+znxrplwvah 1 301 train
+znxwvoywiu 1 300 train
+znxxkuuaze 0 300 train
+znxykomjfj 1 300 val
+znxyqjeodn 1 300 test
+znycjndsxw 1 300 train
+znyeenzrhp 1 301 train
+znyfmjmrrn 1 300 train
+znygriwwnz 1 300 train
+znyoaqugyi 1 300 train
+znyrsbiwki 1 300 train
+znytebsgjb 0 300 val
+znywkwahfw 1 300 train
+znyxhfxhbp 0 300 train
+znzfbcvytf 1 298 val
+znzqdrkota 1 300 train
+znzsxieolq 1 298 train
+znzxtmcekd 1 301 train
+znzyepsblz 1 300 train
+zoaavzmtre 0 240 train
+zoaceluuhm 1 300 train
+zoacewygsl 1 300 train
+zoaeaczkyk 0 300 train
+zoaeviwshf 1 300 val
+zoahsqameh 1 300 train
+zoakkadtmb 1 299 test
+zoamlmhzns 1 300 train
+zoasqxfuin 1 300 train
+zobajaqgch 1 300 val
+zobcwjtlir 1 300 test
+zobedmiszl 1 300 train
+zobkhjwvzy 1 301 train
+zobmlnjbrm 1 300 train
+zobsyhkhmg 1 300 train
+zocbmgmxva 1 300 train
+zocddvybad 0 300 train
+zocemfhtus 0 300 val
+zocievtnrw 1 300 train
+zockbpfsuv 1 298 train
+zocvwatcsf 0 300 val
+zodkgjcyuz 1 300 val
+zodvjsiyuq 1 300 train
+zoedljismz 1 300 train
+zoehcmqzui 1 300 train
+zoepxgiyqp 1 300 train
+zoffdqyxzf 1 300 train
+zofkbbmrup 0 300 train
+zofkjjjixu 1 301 train
+zofkrnagry 1 300 train
+zoflovqzel 1 300 train
+zofmlpgzud 1 301 val
+zofzbebmco 1 300 val
+zofzzombql 1 300 val
+zogdbndsgu 1 300 train
+zogkhxddug 1 300 val
+zoglmajedn 0 300 train
+zogpehscmc 1 301 train
+zogrqkttlt 1 300 train
+zogsukesjz 1 300 train
+zogxbrkfmz 1 300 train
+zogziyczxe 1 300 train
+zohbmyoetx 1 300 train
+zoheiecpxt 1 300 val
+zohhhtlkex 0 300 train
+zohhrmgrdk 1 300 train
+zohjqnvqdm 1 300 train
+zohnelqggk 1 300 train
+zohoemsvxx 0 241 train
+zohrsrryio 0 300 train
+zohsnjmswm 1 302 train
+zohspgrgua 0 300 train
+zohzmybwjc 0 300 train
+zoibthwkra 1 300 train
+zoiiejlxam 0 301 train
+zoiiwzlsae 0 300 val
+zoiizdufqb 1 300 val
+zoioptmgwf 1 300 train
+zoivoisffu 0 300 train
+zojgamasxi 0 300 val
+zojgbkxnbv 1 300 train
+zojpocutky 1 300 train
+zojqqdxxuz 0 300 train
+zojuhtzdom 1 301 train
+zojuxidoxd 1 300 train
+zoknzhwsis 1 300 train
+zokpmwyjvo 1 300 train
+zokvpuvkuc 1 300 val
+zokwpzytba 1 300 train
+zokwtsqety 1 300 val
+zokzvmnohf 1 300 val
+zoladxjowi 1 300 train
+zoldccpqlo 1 300 train
+zoleicilsp 1 300 train
+zoleozlpfj 1 300 test
+zolgbdzxzz 1 255 train
+zoljqzexqk 1 300 val
+zoljzjrhzb 1 300 train
+zolkztbldx 1 301 val
+zolzgtvthc 0 300 train
+zomavewiba 1 299 val
+zomcpqjxpt 1 300 train
+zomiqkphfb 1 300 train
+zommrauaop 1 298 train
+zomnhvbuai 1 300 train
+zomnndmbzc 1 300 train
+zomwnkbdcg 0 300 train
+zomyunvudk 1 300 train
+zonckbbvds 1 300 train
+zondsvoyau 1 300 train
+zonkuejehn 1 300 train
+zonlxcunos 1 300 train
+zonmyghutc 1 300 val
+zonrjycmsu 1 300 train
+zonrppndye 1 299 val
+zoockldbfr 1 300 train
+zoohnbculw 1 300 train
+zookhyoypn 1 300 val
+zoolhzndpp 1 300 train
+zoolxfunat 1 300 val
+zootttujao 1 301 val
+zoowvgmich 1 300 val
+zopebmevjd 1 300 val
+zopewncbmq 1 300 train
+zopfkrshst 0 300 train
+zopjjkyezc 1 301 train
+zopmwgwndj 1 300 train
+zopponfxvj 1 300 val
+zopvfklfru 1 300 train
+zopvyhcwil 1 300 train
+zopwbknvuj 1 299 test
+zoqadbkqzt 1 302 train
+zoqbfkjwyk 1 300 train
+zoqddahwez 1 300 train
+zoqedckdum 1 300 val
+zoqfltbtfm 1 300 train
+zoqjagfrbq 0 300 train
+zoqlekryhy 1 300 train
+zoqlsbngxn 1 300 train
+zoqqntpxmi 1 300 train
+zoqusptprh 1 300 train
+zoqvryfubp 0 300 train
+zordaleopf 1 300 train
+zorglkajoy 1 300 train
+zoropdkinx 1 300 test
+zorspjgmyr 1 300 train
+zoruwaaiwg 1 300 train
+zoryaxqafb 1 300 train
+zosiogabqu 0 300 train
+zoslheybzn 1 300 train
+zosngjzpeu 1 300 train
+zosszswiak 1 300 train
+zostjgmbol 1 300 train
+zotiryggit 1 300 train
+zotoexpcot 1 300 train
+zotoimxmgl 1 300 train
+zotscldgqn 1 300 train
+zoucbtwdpb 1 300 train
+zoujxaixha 1 300 train
+zoumlvcxvv 1 300 train
+zoumtiuasu 1 300 train
+zouqndmlgi 1 300 val
+zouuowrchu 0 301 train
+zouwiklxpe 1 300 train
+zouylkmlnv 1 300 train
+zouzhaadrh 0 300 train
+zovadywage 1 300 val
+zovbjaovsc 1 300 train
+zovluogefm 1 300 train
+zovntpfyum 1 300 val
+zovvcyafzh 0 300 val
+zovznzxzfh 1 300 train
+zowbrmqxfp 0 300 train
+zowhwoylzk 1 300 train
+zowiiqindc 1 242 train
+zownomdhrp 0 300 train
+zowubmwxwh 0 300 train
+zowycvfypx 1 300 train
+zowzluhyxg 1 300 train
+zoxbpajlew 1 300 train
+zoxhjusmnw 1 300 train
+zoxnxjahfj 1 300 train
+zoxqkcxjma 1 300 train
+zoxqzhfqkt 1 300 train
+zoxsjljbkr 1 300 val
+zoxtjrburg 1 300 train
+zoxvvvytkn 0 300 val
+zoxxasqchp 1 300 train
+zoyauxtybi 1 298 train
+zoybyqsbad 0 300 train
+zoypjvzpzt 0 300 train
+zoytoxsliu 1 300 val
+zoyvxzzwfu 1 300 train
+zoyxuivwrw 0 300 train
+zoyydsqwmk 1 300 train
+zozjzdrvtp 0 300 train
+zozmhjqfoe 1 300 train
+zoznkayioy 0 300 val
+zozpwqpxle 1 300 val
+zozyvhytkl 1 300 train
+zpaopdvzho 1 193 train
+zpaotyzvij 1 300 train
+zpaoyzqjml 1 300 train
+zpatbyoymd 1 297 val
+zpbggelffo 1 300 test
+zpbhqridkr 0 300 train
+zpbmsgeust 0 301 train
+zpbquebwmq 1 299 val
+zpbqwwprks 0 300 train
+zpbrnpsdmo 0 300 val
+zpbrruocgp 0 300 train
+zpbvtapjcr 1 300 train
+zpcaseacnp 1 300 val
+zpcdhrjryy 1 299 test
+zpclcqmlid 1 300 train
+zpcmmpbiva 1 299 val
+zpcnotzcxp 0 300 val
+zpcozzntqt 1 300 train
+zpcpqjwhef 1 300 train
+zpctfcswha 1 270 train
+zpcyxgjqjq 0 300 val
+zpdbvhfidy 1 300 train
+zpdhflzrhq 0 300 val
+zpdiiroebs 1 300 train
+zpdmjkjasn 1 300 train
+zpdsqiajjo 1 300 train
+zpdvepqpcr 1 300 val
+zpdxcxnyop 1 301 train
+zpebhynukk 0 300 train
+zpebmqhgch 1 300 train
+zpehisldsf 1 298 train
+zpepytgxxs 0 300 train
+zpesavqyri 1 299 val
+zpfhgsrpsi 1 300 train
+zpfnwfylhf 1 300 train
+zpfozejujv 1 300 train
+zpfrhystkm 1 300 train
+zpfwzaffgq 1 300 train
+zpgasqyqda 0 300 train
+zpggtusdtk 1 300 train
+zpgmqlqcoi 1 300 train
+zpgnmvqtpk 0 300 val
+zpgqjxivpx 0 300 train
+zpgqqjrtko 1 300 train
+zpgsgbarxk 1 300 val
+zpgulixovo 1 301 val
+zpgwhpjqaw 0 300 train
+zphbpgdsie 1 300 train
+zphcipapdu 1 300 val
+zphckexzba 1 300 train
+zpheiovskl 1 300 train
+zphgfoxmsr 1 300 train
+zphgphhqep 1 300 val
+zphjkigclr 1 297 train
+zphjmdvfxu 1 241 train
+zphkhxzdke 1 300 train
+zphkqgicai 0 300 train
+zphkqntvul 1 300 train
+zphqzkcngr 1 300 train
+zphrsagruf 0 300 train
+zphubspqzh 1 241 train
+zphzbywpbw 1 300 train
+zpibtbmpvb 1 300 train
+zpibvzlpvg 1 300 train
+zpicylmrqw 1 300 train
+zpidqyqocx 1 300 test
+zpifpxxavk 1 300 val
+zpihvtiias 1 300 val
+zpilavstvx 1 300 test
+zpilmelszx 1 300 val
+zpirtfvviv 1 300 train
+zpiuumucpt 1 300 train
+zpiyeuiduz 1 241 train
+zpizcdikix 1 300 train
+zpizpnqfbo 1 300 train
+zpjeamgstz 1 300 train
+zpjeilpjrv 1 300 train
+zpjgfaswsc 1 300 train
+zpjhewnfzh 1 300 train
+zpjqhxpuip 1 300 test
+zpjuzvxgtb 1 300 train
+zpjvtheojp 1 300 val
+zpjwfdcxsi 1 300 val
+zpkazwnwoo 1 298 train
+zpkdvksplv 0 300 train
+zpkqgnkfnr 1 300 train
+zpkrfwzmjd 1 300 train
+zpktwkzmim 1 300 val
+zpkulndnys 1 300 train
+zpkwbipvem 0 300 train
+zpkwdojfnx 1 301 val
+zpkxdyujgw 1 299 test
+zpkyamaqmn 1 300 val
+zplbkgsjlx 1 300 train
+zpldblfwlx 1 300 val
+zplfztseex 1 300 train
+zpliffhrgz 1 300 train
+zpllznxapc 1 300 test
+zplmlkrwqj 1 300 train
+zplskoqmin 1 300 val
+zpluouxfcb 1 300 val
+zplvhdnvre 1 300 train
+zplyjqnfmv 1 300 test
+zpmbvwfgku 1 300 train
+zpmdiyglra 1 301 val
+zpmfajyqtt 1 300 val
+zpmklmzmfp 1 300 train
+zpmsbkiutu 1 301 train
+zpmuvcgqee 1 300 train
+zpnbxlfnqq 0 302 train
+zpncsjfzft 1 301 train
+zpninfabto 1 300 train
+zpnjiswgdt 1 300 train
+zpnnhshckz 1 300 train
+zpnpdavqsa 1 301 train
+zpnvetnict 1 300 train
+zpnwnxfjlc 1 300 train
+zpnyhufmbk 1 300 train
+zpocoqjiob 1 300 train
+zpoenwsjpr 1 301 train
+zpokbmqtrn 1 300 val
+zpompmamlx 0 600 train
+zpomptodng 1 300 train
+zpowliezqa 1 300 train
+zpoyymvqnx 1 300 val
+zppfsoprkc 1 301 train
+zppipbxmjv 1 300 train
+zppmsbtejv 1 296 val
+zppoaxgzot 1 298 train
+zppvkxpmbw 1 297 train
+zpqcrxjuxb 1 300 train
+zpqefkqpih 0 300 train
+zpqjnropol 1 300 train
+zpqmokjldk 1 300 train
+zpqojxgphv 0 300 train
+zpqoxwdgfx 1 300 val
+zpqtcsbdgp 1 300 train
+zprqkxxyim 1 300 train
+zprtmjwxkl 1 300 val
+zprvttgzvz 1 301 train
+zprvxnvgpb 1 292 train
+zpsbobfkhe 1 300 train
+zpsgquuwuv 1 300 train
+zpslzcdjac 0 300 train
+zpsmkrweby 1 300 val
+zpsnqtcsuo 1 300 train
+zpsuiwaqmd 0 300 train
+zptbaasntd 1 300 train
+zptiyrjnel 1 300 train
+zptkukgsrr 0 300 train
+zptldmuvqi 1 300 train
+zptnynsqbb 1 300 val
+zptrmtkaqo 0 300 train
+zptsjpkrnk 1 300 train
+zptvfzczsr 1 300 train
+zptxramuvv 1 300 train
+zptypbypsv 1 300 train
+zpugmlnyln 1 300 train
+zpujdfwivh 1 300 train
+zpukeudzly 1 300 train
+zpuzmmwctl 1 300 train
+zpvnxrfjhg 1 300 train
+zpvsselkos 1 300 train
+zpvtaoqimv 1 300 train
+zpwbgrhyxh 1 300 train
+zpwesxmqyb 1 241 train
+zpwfvymjlx 1 300 train
+zpwhxtbdfi 0 300 train
+zpwikgggfn 1 298 train
+zpwkfbfveq 1 300 val
+zpwnafulmo 1 300 train
+zpwroxqyln 1 300 train
+zpwscjlrfx 1 300 train
+zpwsogkjer 1 297 train
+zpxcukbkid 1 300 val
+zpxeydccsz 1 300 train
+zpxiojdhep 1 300 train
+zpxirfbfiw 0 301 train
+zpxjqxppos 1 300 train
+zpxnzkrocg 1 300 train
+zpxqwpvkcs 1 301 train
+zpyfyaetud 0 300 train
+zpykipigtu 0 300 val
+zpynwdivrx 1 300 val
+zpyoehlzbn 0 300 train
+zpysbxfhzw 1 300 train
+zpzcbreoqb 0 300 train
+zpzmxwidfr 1 300 train
+zpzoviupbm 1 300 train
+zpzwnughqc 1 300 train
+zpzycmsaik 0 301 train
+zpzywmwuie 1 300 train
+zpzznffzfq 1 300 val
+zqacsxjrmx 1 300 train
+zqadgbbxni 1 301 train
+zqaktsuyxx 1 300 train
+zqalfdiyeg 1 298 train
+zqandetlod 1 298 val
+zqawreoeaj 0 300 train
+zqazsixkvf 1 300 train
+zqbanssytf 1 300 val
+zqbdovjylg 1 300 train
+zqbjeqxzsv 1 300 train
+zqbpscfwtt 1 300 train
+zqbvflwruu 1 300 train
+zqbyxskkdv 1 300 train
+zqcdqzgnwp 1 300 val
+zqcguuzurx 0 300 train
+zqchqlowxs 1 300 train
+zqclcdrmhl 1 299 val
+zqcrjbkxlm 1 300 train
+zqcrjtrjqc 1 300 val
+zqcxxocizl 1 300 train
+zqcywjmwbd 1 300 train
+zqdbsrssdc 1 300 train
+zqddpuhqqt 1 300 train
+zqdjdmiihu 0 300 val
+zqdjzojzcp 1 300 val
+zqdlvewthj 1 300 val
+zqdqflbjtd 1 241 train
+zqebxtuzhn 1 300 val
+zqeisrsngi 1 300 train
+zqeqnwzuhe 1 301 train
+zqetaozpyy 1 240 train
+zqevwqlrho 1 300 val
+zqexfvzioy 0 300 train
+zqfntxsnna 0 300 train
+zqfqdmqkyj 0 300 train
+zqfsdlgkvx 0 300 train
+zqfzqwjkpe 1 300 train
+zqgaaqmicm 1 240 train
+zqgjmgjbts 0 300 train
+zqgpvedxfr 1 300 val
+zqhapzhcco 1 300 train
+zqhjeteelx 1 300 train
+zqhptuabhy 0 300 val
+zqhulfjphc 1 300 train
+zqhvtodslm 1 300 train
+zqibqemsix 0 300 train
+zqidbptnmb 1 300 train
+zqimyqbtgx 1 300 train
+zqinxaktji 1 300 train
+zqjeijteon 0 300 train
+zqjgnbjjdk 1 300 train
+zqjhzzfrdb 1 146 train
+zqjimveemq 1 300 train
+zqjllqcdzr 1 300 val
+zqjomwwebg 0 300 train
+zqjwfmtvup 1 300 train
+zqjxrluibx 1 300 train
+zqjzmarjbk 1 300 test
+zqkhjzxgzr 0 301 val
+zqkhqoiobb 0 300 train
+zqkxntcdxu 1 300 val
+zqkzoevkrz 1 300 val
+zqlagitbva 1 300 train
+zqlhcmhsdp 1 300 train
+zqlhddsyqo 1 300 train
+zqllwscvdy 1 300 train
+zqlszpudgw 1 241 train
+zqlupwiklp 1 300 val
+zqlxeiwpgo 1 300 train
+zqlyovqwda 1 300 train
+zqmegsnppa 1 301 train
+zqmelmbbvh 1 300 train
+zqmisucieo 0 300 train
+zqmnixhtbg 0 300 train
+zqncpqpdnf 1 300 train
+zqncvydvvs 1 299 val
+zqndkozuck 1 269 train
+zqndkvjfhh 1 300 train
+zqnoydawup 0 300 train
+zqnqlzswya 1 298 val
+zqnrulmcxf 1 300 train
+zqnsorqyyj 1 300 train
+zqnviupost 1 300 train
+zqoctnxzas 1 300 train
+zqodmfrtbs 1 300 test
+zqoehxbsgt 1 300 val
+zqogalfyzb 1 300 test
+zqoguluvlw 1 300 val
+zqojwrvktu 1 300 val
+zqokdifexu 1 300 train
+zqomopedct 1 300 train
+zqooagheho 1 300 val
+zqowwrbldk 1 300 val
+zqozmfbyht 1 298 train
+zqpadacaot 1 300 train
+zqpggrbyhn 1 300 train
+zqpgwbqbgh 1 300 train
+zqpmczpvwl 1 300 train
+zqppxkzzou 1 300 train
+zqpqeltkki 1 300 val
+zqptfbqbvq 1 300 val
+zqpvuvftex 0 300 train
+zqpxtommha 1 298 val
+zqqfrjeokp 1 299 val
+zqqghzebqn 1 300 val
+zqqidolxmd 1 300 train
+zqqilzrpho 0 300 train
+zqqkoufsyn 1 300 val
+zqqszoupkn 1 300 train
+zqribzxtqn 1 300 train
+zqriqgfsnb 1 301 train
+zqrnnjajih 1 300 val
+zqrptplbtm 1 300 train
+zqrupupckd 1 302 val
+zqrzqekofe 0 300 train
+zqrzqgqbmk 1 300 train
+zqsccblevl 1 300 train
+zqsikyafbu 1 300 train
+zqsmqkovmq 1 300 val
+zqsoegdgtp 1 300 val
+zqsujnlyvn 1 300 train
+zqsxpnbjnl 1 300 train
+zqsxtcalek 1 300 train
+zqtbxbjpaz 1 299 train
+zqtfkscpci 1 300 val
+zqthbrqavf 1 301 train
+zqtjjzxyik 1 300 test
+zqtozhzxcy 1 300 val
+zqtpcqmcwi 1 300 val
+zqtvyuoabj 1 300 test
+zqtxiygwyv 1 241 train
+zqtztjggwx 0 300 train
+zquacsqyqk 1 300 train
+zquignrzhj 0 300 train
+zqurwvqetz 1 300 train
+zquwsopags 1 301 train
+zquxifafzk 1 300 train
+zquymvyvwg 1 300 train
+zqvbioegmr 1 300 train
+zqvhutgneq 1 300 train
+zqvjhcemea 1 300 train
+zqvkwhegya 1 300 train
+zqvmwxjbja 1 300 train
+zqvnhvrktb 1 300 train
+zqvraxhzeo 1 301 val
+zqvuxzaapa 1 300 val
+zqwhemoxuz 1 298 train
+zqwrditadz 1 300 train
+zqwvdddsvt 1 300 train
+zqwyggtgfc 0 300 train
+zqwyncwauj 1 300 train
+zqwzlnrofa 0 300 train
+zqxeunjsks 1 300 train
+zqxidpoadq 0 300 train
+zqxmqnmymo 1 300 train
+zqxnyvsenm 1 301 val
+zqxqoclxqg 0 300 train
+zqxrawgbvf 1 300 train
+zqybmecvtk 1 300 train
+zqyftuakzq 1 300 train
+zqyhebqeno 1 300 val
+zqyistuydn 0 300 val
+zqynoyhqyn 1 300 train
+zqysqbfxej 0 300 train
+zqyukuumje 1 300 train
+zqyzobyqak 0 300 val
+zqzildamfi 0 300 train
+zqzngvkxhf 1 300 train
+zqzojohrvy 1 301 val
+zraazjafkf 1 300 train
+zracmwuwef 1 300 train
+zragelmdxi 1 301 train
+zraibwmzpw 1 300 val
+zraldwcfmh 1 298 train
+zraocmrlqd 0 300 train
+zrasmpcleh 1 300 train
+zrauvsfduh 0 300 val
+zravtdfuik 1 300 train
+zrazvwrlhe 1 300 train
+zrbdcdxzfw 1 300 test
+zrbewkvdbm 1 300 train
+zrbgqooosc 1 300 train
+zrbqxalxty 1 300 train
+zrbtsnpzid 1 300 train
+zrbwugzvsd 1 300 train
+zrbyosbzub 1 300 train
+zrbzxxlylo 1 300 test
+zrcebxhaan 1 300 train
+zrchjtofmr 1 300 train
+zrcmcmrpyk 1 300 val
+zrcugdtvws 1 298 train
+zrcxzijkkg 1 300 train
+zrddugdcqb 1 300 train
+zrdffsyque 1 300 train
+zrdokptoor 1 300 train
+zrdolspwgc 1 300 train
+zrdqqxhceo 1 300 train
+zrduwhdxtm 1 300 train
+zrdvdeptrk 1 300 train
+zreajkxded 1 241 train
+zrexvrjqwp 1 300 train
+zrezvvhcrd 1 300 train
+zrfcyimeeh 1 300 val
+zrfimjnuuz 1 298 train
+zrfmmcvplh 1 300 val
+zrfodlxbcf 1 300 train
+zrfrrljyok 1 241 train
+zrgdjvghdk 1 301 train
+zrggtdjmmn 1 300 train
+zrgiqpwnvc 1 240 val
+zrgisinrdd 0 300 train
+zrglgcysxz 1 300 train
+zrgpomavqq 0 300 train
+zrgrcpwvqa 1 300 val
+zrgvojzaxg 1 300 train
+zrgvtijtgx 0 300 train
+zrgwywbxjh 1 300 train
+zrhkcpsakv 0 300 val
+zrhotxgvyl 1 300 train
+zrhtdrilpy 1 300 train
+zrhxaamlrw 1 299 test
+zrhxpjbhnz 1 300 train
+zribmspnmq 0 300 train
+zrifypagub 1 300 train
+zriidrurdx 1 300 train
+zrijplebos 1 300 train
+zrimxsjbwk 1 301 train
+zripabghqm 1 298 val
+zriqxerfvh 0 300 val
+zrivntnlne 1 300 val
+zrivvmjwai 0 300 train
+zrjbnqcaop 1 300 train
+zrjfuucvzl 1 300 train
+zrjgjsaylw 1 300 val
+zrjhidkiwd 1 300 train
+zrjikpskgn 1 300 train
+zrjlhufyvp 1 300 train
+zrjlqabafz 1 302 train
+zrjophbsjb 1 300 train
+zrjorwdgdj 0 300 val
+zrjrpxbakr 1 300 val
+zrjvgoabkl 1 300 train
+zrjxkpfeao 1 301 train
+zrjziycpzt 1 241 train
+zrkcjlzkfl 1 300 train
+zrkdmdbhhh 1 300 train
+zrkevjrzul 0 300 train
+zrkfzcvtui 1 300 train
+zrkhstuynp 1 300 train
+zrkinjhsuq 0 300 train
+zrkkrxpxtf 1 299 train
+zrkmtzfaeu 1 300 train
+zrkodnsiwb 1 300 val
+zrkohjzwic 1 300 train
+zrljukexhf 1 241 train
+zrlqndyrtn 1 301 train
+zrlrhzfiny 1 300 train
+zrmahyoybq 1 300 val
+zrmanlljgg 1 300 train
+zrmdkbzswf 1 300 train
+zrmgejxnqt 0 300 train
+zrmgkutivc 1 300 train
+zrmjdvquxb 1 300 train
+zrmkbfcxnn 1 300 val
+zrmnmrzsgh 1 300 val
+zrmnpxsvus 0 300 train
+zrmpobkqgq 1 300 train
+zrmsmhjfwh 1 300 train
+zrnidvaiem 1 300 train
+zrnjocwiuq 1 300 train
+zrnwsrgrhm 1 300 train
+zrobwltwxr 1 300 train
+zrocimpulv 1 299 train
+zrodpjcasc 0 300 train
+zrogqfvrpk 1 300 train
+zrotqizyab 1 298 train
+zrouemrwtb 1 300 train
+zroxflyqph 1 300 train
+zrpdatssyc 1 300 train
+zrpggqazlc 1 300 train
+zrpiwojjve 1 300 train
+zrplhkcesw 1 300 test
+zrpomfnrjt 1 300 val
+zrpswfohne 1 300 train
+zrptdhjuoj 1 300 train
+zrptpzwgvb 0 300 train
+zrpwtuawai 1 300 train
+zrqciixgts 1 300 train
+zrqhffmqdi 1 300 train
+zrqhqmlwpy 1 300 train
+zrqmlzzkpt 1 300 train
+zrqrlvorqx 1 300 val
+zrqucrmyyk 0 300 train
+zrqwoysydk 1 300 val
+zrrcxhmffh 1 300 train
+zrrhnpyzeb 1 300 train
+zrrixksxws 1 300 val
+zrrncwxmdc 1 299 train
+zrroebhetq 1 300 train
+zrrrosmpxo 1 298 train
+zrrsqqqnrg 1 300 train
+zrsapyclqt 1 300 train
+zrshwhidyn 1 299 val
+zrsilmaqlg 1 300 train
+zrssdssejv 1 300 train
+zrssgrvqhu 1 300 val
+zrssszlosg 1 300 train
+zrszyojjxt 1 300 val
+zrtaylibdt 0 300 train
+zrtbiccvcx 1 298 train
+zrthtimxvs 1 300 val
+zrtmuovogf 1 300 val
+zrtnvqdgxd 0 300 train
+zrtoxhchui 1 300 train
+zrtqntvvkp 1 300 train
+zrtzordyjm 1 300 train
+zrueallpey 1 300 val
+zrummgqchc 1 300 train
+zrupxpmugm 1 300 val
+zruvngsxee 1 300 train
+zrvavqttuf 1 299 test
+zrvcibngmo 1 300 train
+zrviioaixg 1 300 train
+zrvkhmyxin 1 300 train
+zrvkpektsj 1 300 train
+zrvkvihvyc 1 300 train
+zrvnffustq 0 300 train
+zrvpexvkno 0 300 train
+zrvsugltth 1 299 train
+zrwahyklaz 1 300 train
+zrwasstqou 1 300 train
+zrwavkkujv 0 300 val
+zrwblmwcuj 1 300 val
+zrwdmaagyj 1 300 train
+zrwguuochl 1 300 train
+zrwhkhxuyt 0 300 train
+zrwrwbzlse 1 300 train
+zrxannzdbk 1 300 train
+zrxbysqqzl 0 300 train
+zrxhzkryrt 1 300 train
+zrxjbrgbys 0 300 train
+zrxngesosr 1 300 test
+zrxnxlkiyo 1 300 train
+zrxvbwmzll 1 300 train
+zrxywvpxnh 1 300 train
+zryazbhhpn 1 300 train
+zrydcfgsfr 1 300 train
+zryecpaojo 1 300 train
+zryezpvjff 1 300 train
+zrymqxdkvf 0 300 val
+zrypkpfkua 1 300 train
+zryvbiulqd 1 300 train
+zrywylqnkl 1 300 train
+zryzupcrcj 1 300 train
+zrzbolnrls 1 300 test
+zrzhvfiwbq 1 300 train
+zrznnrkryv 1 301 train
+zrzojynbbv 1 300 train
+zrzxyrmzos 1 300 train
+zsaaykscri 1 300 train
+zsabygwqbi 1 300 train
+zsacelfaih 1 300 train
+zsaeueutuh 1 300 train
+zsafalncdk 1 300 val
+zsasofskwf 1 241 train
+zsawisonrm 1 300 train
+zsaxyrlwct 1 302 train
+zsbkjqnbrt 0 300 train
+zsbthwqmxn 1 300 test
+zsbvjtwmfj 1 300 train
+zsbyjgxoxg 1 300 val
+zsbyytsmcp 1 300 val
+zscgwlyupt 1 300 train
+zschixswtr 1 297 train
+zscrfkkjph 1 300 train
+zscyegmiyv 1 300 train
+zsczitdovm 1 300 val
+zsdbqyrhsq 1 300 train
+zsdcdoxvqm 1 297 train
+zsdcjlbwhw 1 300 train
+zsdecnbgws 1 300 train
+zsdgdoluzg 1 300 val
+zsdmgllhck 1 301 train
+zsdvpgarrv 1 298 val
+zsedzmnbvn 1 299 val
+zsenghammn 1 302 train
+zseocisjvw 1 300 val
+zsepstyyfs 1 300 val
+zserolkqpz 1 300 train
+zsexowgobz 1 300 train
+zsfeioqphn 1 300 val
+zsfjofslee 1 300 train
+zsfpgzznoc 1 300 val
+zsfpyhgxmg 1 300 test
+zsgaikpcjb 1 299 test
+zsgguihyqd 1 298 train
+zsghrshqkx 1 300 train
+zsgrbnfqnd 1 300 train
+zsgrtjctyu 1 300 train
+zsgtmhucct 0 300 val
+zsgzopnkws 1 298 train
+zshdctzmtu 1 300 train
+zshjawldmi 1 300 train
+zshjbwvzdk 1 300 val
+zshjjkonar 1 300 train
+zshjkrgvzm 1 300 train
+zshpimlech 1 300 train
+zshwmtkvib 0 300 train
+zshznihfys 1 299 test
+zsihsznxjv 1 300 train
+zsiprannlk 1 297 train
+zsivpmsqez 1 300 val
+zsivxhdjsd 1 300 val
+zsiymgdlcu 1 300 val
+zsjokqhyrc 1 300 train
+zsjvxyelva 1 300 val
+zsjyfjipyn 1 300 val
+zskfkwqsrp 1 301 train
+zskgjfgusr 1 300 train
+zskoobhslf 1 300 train
+zskrlbicnm 1 300 val
+zskuvcwcos 0 300 train
+zskzidlpxr 1 301 train
+zslardonah 1 300 train
+zslcxopzbw 1 300 train
+zslhwdjflg 1 300 train
+zsliapjxdh 1 300 train
+zslrbxzppn 1 300 train
+zslziuxvdw 0 300 val
+zsmaqtyqdm 0 300 val
+zsmcjdxnnz 0 300 train
+zsmijkxqdu 1 300 train
+zsmsxxwnix 1 300 train
+zsmtlfucab 1 300 test
+zsmxriemzh 1 300 train
+zsmypwifma 1 300 train
+zsnakbjsau 1 300 val
+zsnnktadbl 1 300 train
+zsnrtfbeqg 1 300 train
+zsnuvrgufn 1 300 train
+zsnuzrtnyu 1 300 train
+zsoaygoibn 1 298 train
+zsodcejwnb 1 300 train
+zsoewhkpde 0 300 train
+zsoioujfsp 1 300 train
+zsokfnalpp 1 300 train
+zsoqixsiln 1 300 train
+zsordbmeoz 1 300 train
+zsormhyuwd 1 300 train
+zsotvxccbi 1 300 train
+zsphicqrkt 1 298 train
+zspjupikcs 1 300 train
+zspnlauwnx 0 302 train
+zspusqwvhe 0 300 train
+zsqacheers 1 300 train
+zsqjihgilv 1 269 train
+zsqpjapurh 1 300 train
+zsqygkbvxa 1 300 train
+zsrccztekv 1 300 train
+zsrekcfgwe 1 300 val
+zsrnjncbpl 1 300 train
+zsrpewsuwi 1 300 val
+zsrqnmhgtv 1 300 val
+zsrrgclwym 1 300 train
+zsrtkvllpo 1 300 train
+zsryreoyki 0 300 val
+zsscrtsmbe 1 300 train
+zssfbkgjnk 1 300 train
+zsshaznocz 1 301 train
+zsskwpbmum 1 300 train
+zsslarobyv 1 300 train
+zssqamefnk 1 300 train
+zstfzooaqe 1 298 train
+zstizbiqsj 0 300 val
+zstkgkncwp 1 300 train
+zstktfmxeb 0 300 train
+zstlnbsyid 0 300 train
+zstuohlfgc 1 601 train
+zstzjtjdti 1 300 train
+zsufrttqxb 1 300 train
+zsuhvcscph 1 300 train
+zsumimrkjg 1 302 train
+zsunivvdwt 1 300 train
+zsuppvalty 1 300 train
+zsurddprmz 1 300 train
+zsuvnzgxby 1 300 train
+zsuvwcyvee 1 300 train
+zsuwpfpajt 1 298 train
+zsuyxqkvxp 1 300 train
+zsvczhdpao 1 300 train
+zsvfzkpjur 0 300 train
+zsviojrhpc 1 300 train
+zsvpmgtmqv 1 300 train
+zsvwnicjfj 1 301 val
+zsvzmmbxac 1 300 train
+zswgzdclkx 1 241 train
+zswndcjeol 1 300 train
+zswnnnkzpr 0 300 val
+zswrzqggzw 1 301 train
+zswxmdopcv 1 297 train
+zswzbywyyp 1 300 train
+zsxcsmlaao 1 300 train
+zsxjsfkkbf 1 300 val
+zsxmssugdh 1 298 train
+zsxptmpehu 1 300 val
+zsxvikynhi 0 300 train
+zsxyrdqord 1 241 train
+zsxzeumppe 1 300 train
+zsybhetzmb 1 299 test
+zsyewlsafu 1 300 val
+zsylwfwxkf 1 300 train
+zsytybrfyo 1 300 train
+zsyyrmhisz 1 300 val
+zszfiqrufm 1 300 train
+zszopojehk 1 300 train
+ztacahdncb 1 300 val
+ztacuqleqx 1 300 val
+ztahbeislw 1 300 train
+ztaitjogri 1 300 train
+ztalfmvepw 1 298 val
+ztansuiscw 1 300 val
+ztbcihwfvi 1 300 val
+ztbelrvmzy 1 300 train
+ztbinwxgyu 0 300 train
+ztbwcqsqmf 0 300 train
+ztcejylnwd 1 300 val
+ztcfohxgym 1 300 val
+ztcmeoiaju 1 300 train
+ztcrwlhnbw 1 298 train
+ztcsszdmgj 1 300 train
+ztcugiinyj 1 300 train
+ztdatvxael 1 301 val
+ztddsfmuib 1 300 train
+ztdehegmqc 1 300 train
+ztdgbqtkzz 1 300 train
+ztdhmnieer 1 300 train
+ztdjmgydkj 1 300 train
+ztdkeziheo 0 300 train
+ztdqyxpoaq 1 300 train
+ztdtnirdhh 0 300 train
+ztduecykia 1 300 train
+ztdvycbyef 1 300 train
+ztdyatmirg 1 300 train
+ztdzaacgbv 1 300 train
+zteaaflrmj 1 300 train
+zteaauvmma 1 300 train
+ztehpvlhxm 1 300 train
+ztehwtrwpm 1 300 train
+ztejgfinsr 1 300 val
+ztfaeyngyh 1 300 train
+ztfagezbgi 1 300 train
+ztfbntazck 0 301 train
+ztfewzczcq 1 300 train
+ztfhhrizrm 1 297 train
+ztfjilznzu 0 301 train
+ztfpfuzvop 1 300 train
+ztfqfiplki 1 300 val
+ztfurcavci 1 300 val
+ztfvboxsgk 1 300 train
+ztfyiilllg 1 300 train
+ztgbvvxnfk 1 300 train
+ztgfcufjqz 1 301 train
+ztghrsonwe 1 300 train
+ztgissuoua 1 300 train
+ztgnevkisz 1 300 train
+ztgpchjjtb 1 300 train
+ztgrtlueqm 1 300 train
+zthexfjpgp 1 300 train
+zthhinxvap 1 300 train
+zthodrpbxy 0 300 val
+zthpwcdtfy 1 300 train
+zthtxdgijk 0 300 val
+zthufvtarm 0 300 train
+ztibhtdnjn 1 300 train
+ztijugrykc 1 249 train
+ztiooseaps 0 300 train
+ztiowelhvf 1 300 train
+ztirsgugwh 1 300 train
+ztiwbqylep 1 300 val
+ztizbcbjlq 1 300 val
+ztjbgdsqwo 1 300 train
+ztjepgwqcq 1 300 train
+ztjfjnenpy 0 300 train
+ztjowsrorh 1 300 train
+ztjsirwpno 1 300 train
+ztjvwkqgnt 0 300 train
+ztkgivrreb 1 300 train
+ztkncwntmq 1 300 train
+ztkrgzxdcx 1 300 val
+ztksheopqd 1 300 train
+ztkvgnguzj 1 300 train
+ztkwmmlvtj 1 240 train
+ztldegyyvb 1 300 train
+ztlgfhbcnq 1 300 train
+ztlpgxibmk 1 300 train
+ztltvgsgqe 1 300 train
+ztlwuwggsq 1 300 train
+ztlzkdgocv 1 300 train
+ztmahaikcs 1 300 train
+ztmaswitsf 1 300 train
+ztmcvkpxyt 1 300 val
+ztmpcibttz 1 298 train
+ztmqqyajex 1 298 val
+ztmsxmtroh 1 300 train
+ztmwpyrbjf 1 300 train
+ztngjkcfho 1 300 train
+ztngouttby 1 300 train
+ztniczrxsw 0 300 train
+ztnjetcnpo 0 300 train
+ztnkjcaubp 1 300 train
+ztnpaairbl 1 300 train
+ztnpurtugh 1 300 train
+ztnwaiazod 1 300 train
+ztoadzrymb 1 301 val
+ztopghzixw 1 300 val
+ztopycryjr 1 300 val
+ztosepwery 1 300 train
+ztowaossvz 1 300 train
+ztowdlviqv 1 300 val
+ztpoqnifoa 1 300 val
+ztpybckeqe 1 299 test
+ztpydbmofq 1 300 train
+ztpzbvukvp 1 300 train
+ztqaofrnbc 1 300 test
+ztqbozqyoz 1 300 train
+ztqqpjwpnf 0 300 train
+ztqqreybtl 1 300 train
+ztqrroigsu 0 300 train
+ztqzsdctbl 1 300 train
+ztrafoddby 1 300 train
+ztragcjjww 1 300 train
+ztredtkxzv 1 300 val
+ztrgmxwgll 1 300 train
+ztrkdtlvwl 1 300 train
+ztrkdyfbjl 1 300 train
+ztrtipbvxy 1 300 train
+ztrxrmpurv 1 301 val
+ztrzfwxcsw 1 300 train
+ztseivveca 1 300 train
+zttbanncxn 0 300 train
+zttdrxnsof 0 300 val
+zttleecrri 0 300 val
+zttpkicsug 1 300 train
+zttwbcqkrt 1 300 train
+zttzaudiwu 0 300 train
+ztuezpjijn 0 300 val
+ztugbstiqc 1 298 val
+ztujsxopnr 1 300 train
+ztuqdumcag 1 300 val
+ztureywpki 1 299 test
+zturqwahbq 1 300 train
+ztutsnlhtr 0 301 train
+ztuypfoowi 1 301 val
+ztvcjbboyi 1 300 train
+ztviroenji 1 300 train
+ztvuaubuyx 1 240 train
+ztvwajqdqs 1 300 val
+ztvzgkzdga 1 300 train
+ztvzwlrqoi 1 300 test
+ztwernvlim 1 300 train
+ztwewzsyce 1 297 train
+ztwkyjdgum 0 300 train
+ztwlbdwyni 1 300 test
+ztwqlvtumq 1 301 val
+ztxdkcoxvx 0 300 val
+ztxdsbewde 1 300 train
+ztxdvtbojn 1 300 train
+ztxgvakwhs 1 300 train
+ztxvsuitud 1 300 val
+ztxwqqtljy 0 300 train
+ztxzktcwsg 1 300 train
+ztyabnhene 1 300 val
+ztyamjnzyk 1 299 val
+ztybjanabb 1 300 val
+ztydeqfcmf 1 300 train
+ztydvwsfrn 0 301 train
+ztyhtzcxha 1 240 train
+ztyidfinmg 1 298 val
+ztykuuswas 1 301 train
+ztyuiqrhdk 0 299 test
+ztyvglkcsf 0 300 test
+ztyzrtnhxc 1 300 train
+ztzcmgxlcw 0 300 train
+ztzeeollwu 1 300 val
+ztzgbppoqf 1 300 train
+ztzkmfckln 1 300 val
+ztzoqcqdlo 1 301 val
+ztzpnmicgj 1 300 train
+ztzqgknvmk 0 300 train
+zuaawmpmky 1 300 train
+zubaiztkag 1 301 train
+zubpedtfeg 1 300 val
+zubufjhlcd 0 300 train
+zubuuhsqyw 1 300 train
+zubvebxghq 1 300 train
+zucaxhtocd 1 300 train
+zucewhjnjr 1 300 train
+zuchkajazc 1 300 train
+zuclwrauhh 1 301 train
+zucnmxavpt 1 300 train
+zudhjvyxjv 1 301 train
+zudktpsrfb 1 300 val
+zudmdjqdre 1 300 train
+zudnvkagjk 1 300 train
+zudqjywhqf 1 300 train
+zuduhdfojh 1 299 val
+zuduvanawx 0 167 train
+zueahrwdlx 1 300 train
+zueclxodar 0 300 train
+zuekxdugku 0 301 train
+zuenwyiufh 1 300 val
+zueosflyzz 1 300 train
+zuezauzeeb 1 300 train
+zufccxanfq 1 300 train
+zufgyuwklu 1 300 train
+zufjewvggs 0 300 train
+zufpmoswdd 1 301 train
+zufqxlkqjt 0 300 val
+zufuwhgnfp 1 296 train
+zufwpgkdyt 1 301 train
+zufxaqxiow 1 300 train
+zufxkughnk 1 300 train
+zugcxgrmcn 1 298 train
+zughkhgldy 1 300 train
+zugpusfgdw 1 301 train
+zugqdtkagr 1 300 train
+zugratemld 1 300 train
+zugunqhyry 1 300 train
+zuhcntlrdz 1 300 train
+zuhdtrdadc 1 302 train
+zuhfjrbeik 0 300 train
+zuhjkxjrjs 1 300 val
+zuhtskbolv 1 300 train
+zuhvjjqwwf 1 300 train
+zuhysdwipr 1 300 train
+zuiefbcdeq 1 300 train
+zuifqrgdqe 1 300 val
+zuinrxdaqf 1 298 train
+zuiymblqzu 1 301 val
+zuizxdbxbk 1 300 val
+zujtzfphwz 1 301 val
+zujvufthwo 1 300 train
+zujybilicl 1 300 train
+zukaprosgq 1 298 train
+zukdhmubyy 0 301 train
+zukhmsjuqw 1 300 train
+zukixaitgp 0 300 train
+zukprncuha 1 300 val
+zukpyqaxjh 1 300 train
+zuktjnmpmt 1 300 train
+zuktznezhv 1 300 val
+zukwxkywhc 1 300 train
+zukzbtpjkc 0 300 train
+zulfnbqcgb 0 300 train
+zulhdkbjrg 1 300 train
+zulizuysgy 1 300 train
+zullmkvlli 1 300 train
+zulncymvab 0 300 train
+zulqsagkwa 1 300 train
+zulsebrrrj 0 300 train
+zumbijsiax 1 298 train
+zumjtbxirr 1 298 val
+zumlkozsnt 1 301 train
+zumnfhmrmn 1 300 train
+zumqqvixhu 1 299 train
+zumqskdmht 1 300 test
+zumuygaymw 1 298 train
+zumvchnwtw 1 300 train
+zumwhdiajw 0 300 train
+zundaiguir 1 301 val
+zundzvtbla 1 300 train
+zunjrgoath 0 300 train
+zunmknkrhk 1 300 val
+zunrjechxr 1 298 train
+zuntwnzusg 1 300 train
+zunuthfegz 0 300 train
+zunwjokpdh 1 301 val
+zunwqypvfm 1 300 train
+zuodatdyzd 1 300 train
+zuoeuhzvvu 1 298 train
+zuofixpmjo 0 301 train
+zuofqfepit 1 300 train
+zuoihcvzvb 1 300 train
+zuojsaztso 1 241 train
+zuoketvpjf 0 300 train
+zuokqlkeec 1 300 train
+zuolebmpui 1 300 train
+zuonwqeych 1 300 train
+zupaaxqnil 1 297 train
+zupatqsmhr 0 300 train
+zupcmvnuzq 1 301 val
+zupgpraecw 1 300 train
+zupgwfiroe 1 300 train
+zupoaemzhg 1 300 train
+zuporxcref 1 300 train
+zupuexbntw 1 298 train
+zuqbohwiqx 1 300 train
+zuqgtostzc 1 300 train
+zuqgvnhhjk 1 300 val
+zuqkpukpbt 1 299 val
+zuqnzgsmny 1 300 train
+zuqqnlsmjf 1 300 train
+zuqqqfyypp 0 300 train
+zuqzirazzj 1 239 train
+zuraepqglv 1 300 val
+zurfgvksrl 0 300 train
+zurfscrjig 0 300 val
+zurgmztatt 0 300 train
+zurjedcmdx 0 300 train
+zusfhayfnt 1 301 train
+zushevdmir 1 300 val
+zusqjsuizg 0 300 train
+zusvsgxhiv 1 300 train
+zuswwdmccc 0 300 train
+zusyheiixs 1 300 train
+zusyrkfuah 1 300 train
+zutnbbaplr 1 301 train
+zutrffqdak 0 303 train
+zuugjwnqvi 1 300 train
+zuukdvgxvi 1 300 train
+zuumfowidp 1 300 train
+zuunotoqsc 1 300 val
+zuuyyherfc 1 300 train
+zuvajdhwtg 1 300 train
+zuvcruezzs 1 300 val
+zuvimkrodu 1 302 train
+zuvkniwuzf 1 300 val
+zuvktiyzzr 1 300 test
+zuvmhlzzai 1 300 val
+zuvvphkget 1 300 train
+zuvzynklgt 1 300 train
+zuwdseapsx 0 300 val
+zuwdyhtvra 1 125 val
+zuweqkkudv 1 300 train
+zuwlgnrcus 1 300 train
+zuwmkkdncq 1 298 train
+zuwnoclucw 1 300 train
+zuwvflozbr 0 300 train
+zuwwbbusgl 0 300 test
+zuwytlnmhp 0 301 train
+zuwzlexkhz 1 300 train
+zuxacskgoo 1 300 val
+zuxbaqskhv 0 300 val
+zuxcuhuapn 1 300 val
+zuxekuwllo 1 300 train
+zuxnsflity 0 300 train
+zuxovcnplh 1 300 train
+zuxsobeekp 1 300 train
+zuxzmwuxve 1 300 train
+zuycoqowpi 1 300 train
+zuywrarerk 1 300 train
+zuyxzefezl 1 300 train
+zuzbpafnbh 1 301 val
+zuzibvjhdp 1 301 val
+zuzkirnmlt 1 300 train
+zuzkjzqhlk 1 300 train
+zuzurbqxvg 1 300 val
+zvaaqizjie 1 300 train
+zvahbpkktj 1 300 train
+zvajhudwuo 1 300 train
+zvarigpkpx 1 300 train
+zvarrwbsot 1 300 train
+zvaujzjkwo 1 300 train
+zvaxlzecnn 1 300 train
+zvbmbhrgbu 0 300 train
+zvcjdvcvie 1 300 train
+zvcofmnrwu 1 300 train
+zvcruzophg 1 301 train
+zvdiusjdqa 1 300 val
+zvdlrxlloo 0 300 train
+zvdmkutiad 1 300 train
+zvdnduoknx 1 300 train
+zvdrcycdif 1 300 train
+zvdrjmmrdw 1 300 train
+zvdwntoxgu 1 301 val
+zvdymxfwvu 1 300 train
+zveccjeclt 1 300 val
+zvedcbblfc 1 300 train
+zvedgqgzra 1 297 train
+zvefoqtkmk 1 300 train
+zvekgbrkvh 1 300 train
+zveljcmzsw 1 300 val
+zveogsfnoz 0 239 val
+zverronpmt 1 300 train
+zverzcapzv 0 300 train
+zvfaghtqbw 1 300 train
+zvfandqqov 1 300 train
+zvfbytfang 1 300 train
+zvfcwbcitl 1 300 train
+zvfpgucyfu 1 300 val
+zvgcubaiwv 1 300 val
+zvgekhyszq 1 300 train
+zvgiifitup 1 300 train
+zvgmnnxktg 1 300 train
+zvgqooqaro 1 300 train
+zvgqxghhlr 1 300 val
+zvgtbrlbwk 1 300 train
+zvhdbuqdfl 1 300 train
+zvhdodqdst 1 300 train
+zvhdwittmk 1 301 train
+zvhjiuvmhw 1 300 train
+zvhrvaiewy 1 300 train
+zvhtrxgysa 1 301 train
+zvicfnknws 1 296 train
+zvidqudnxg 1 300 train
+zvikdhujvo 1 300 train
+zvimoqxcnh 1 300 train
+zviokoivcw 1 300 train
+zvirhabytf 1 300 val
+zvirvvwalc 1 300 val
+zvisvlokrd 1 300 train
+zviumthfql 1 300 train
+zviyfullci 0 300 val
+zvjhorhvmo 1 300 train
+zvjpsvawqe 0 300 val
+zvjtuuvrpo 1 300 train
+zvjzhuinck 1 300 test
+zvkawuniwb 0 300 train
+zvkciqikui 1 300 train
+zvkkcqcpcz 1 300 train
+zvktdlbnfa 1 300 train
+zvktgcmsll 0 298 train
+zvkxhhtvlx 1 299 test
+zvkyclkwsh 1 300 train
+zvkzreiigk 1 300 val
+zvldcgnaff 1 300 val
+zvlixjmizg 1 300 train
+zvlnsfaybb 1 300 train
+zvlyhokwsb 1 300 train
+zvlzkiuoop 1 300 train
+zvmbblatfz 1 300 train
+zvmdzpupbp 0 300 val
+zvmhsvccph 1 300 train
+zvmibdkmcz 1 300 train
+zvmiumiqor 1 300 train
+zvmlnptrpg 1 297 train
+zvnqedtknz 1 300 train
+zvnstsubcg 1 300 train
+zvnwnkfbpz 1 300 train
+zvocicxmqr 0 300 train
+zvoecjjeia 1 299 test
+zvofslkkif 1 300 train
+zvohlgbccy 1 300 train
+zvohvvrdyz 1 300 val
+zvonmnnyru 1 300 train
+zvoovcgnde 1 300 train
+zvopqrwxvz 1 300 train
+zvoprgutgr 1 300 train
+zvotmxwbza 1 300 train
+zvpgtyzzdv 0 301 train
+zvpjubyvow 1 298 train
+zvqegltlaj 1 300 train
+zvqgdjiotu 0 300 train
+zvqinhzeah 1 299 test
+zvqitdhxxh 1 300 train
+zvqkdhngcr 1 300 train
+zvqlcgbvcm 1 300 val
+zvqottoced 1 300 train
+zvqtbnxogu 0 99 train
+zvraxrjfqf 1 241 train
+zvredtbebe 1 301 train
+zvrlaibcze 1 288 train
+zvrqanmhyj 1 298 train
+zvrtpnrvth 1 301 train
+zvrvohflts 1 300 train
+zvrwhnlbwj 1 300 train
+zvrwnelvsc 1 300 train
+zvrywcqiea 1 300 train
+zvsfmkzlvy 1 299 train
+zvsfxwgmxq 1 300 val
+zvsivkdkak 1 300 train
+zvslbtcvwx 0 300 train
+zvstrtcyva 1 300 train
+zvtoalnnlp 1 300 train
+zvtoijpgcf 0 300 train
+zvtqhjmvqd 0 300 train
+zvtsppctnl 1 300 train
+zvttpjqdqh 1 301 val
+zvtupeotss 1 300 train
+zvtyqjtdlx 1 300 train
+zvuasfkpci 1 300 train
+zvuidmemcp 1 300 test
+zvuijcurze 1 300 val
+zvuogkdbmp 1 300 val
+zvupubvhpn 1 300 train
+zvutwayoxy 1 300 val
+zvuxjtmtfr 1 300 val
+zvvcbnvxgb 1 301 train
+zvvedpknnu 1 300 val
+zvveezfjjq 1 301 val
+zvvimkhmit 1 300 train
+zvvjlkjvyi 0 300 train
+zvvokzxzgj 0 300 train
+zvvrkioljg 1 269 train
+zvvynhuboy 1 300 train
+zvwdlvvlff 1 300 train
+zvwfzkeygq 0 301 val
+zvwmecniiv 1 300 train
+zvwpwwrcdf 1 296 train
+zvwrcwsbmo 1 300 val
+zvwsotwtsx 1 300 train
+zvwuuuljrq 1 300 train
+zvwyzdbtqb 1 300 train
+zvwzegcsso 1 300 train
+zvxaotymzf 1 298 train
+zvxmrxucqe 1 300 train
+zvxnokpsst 1 300 train
+zvxudeeuzh 0 300 train
+zvxvxfachh 1 300 train
+zvxwmdyiof 0 300 train
+zvxwmjfigv 1 300 train
+zvxyuluetb 1 300 train
+zvyakswpyv 1 300 train
+zvycqunwjs 1 300 val
+zvydmxecuo 1 300 train
+zvyiqezhzj 1 300 train
+zvyjhwkzqg 0 300 train
+zvymtvmrwy 1 300 val
+zvysdogzed 1 300 train
+zvysliqgbl 1 300 train
+zvywziripi 1 299 train
+zvyxgdeghs 0 300 val
+zvzlgmjdck 1 300 train
+zvznspbbtd 1 300 val
+zvzuwecqfh 1 300 train
+zvzwzdjikh 1 301 val
+zwacwfjwkv 1 300 train
+zwaddsfokw 0 300 train
+zwaektnero 1 300 val
+zwajpomhyy 1 300 train
+zwastsylgj 1 300 train
+zwaxouvabs 0 300 train
+zwaywaitdm 1 301 train
+zwbekqdqds 1 300 train
+zwbfcndeyj 1 300 train
+zwbjblztzx 0 300 train
+zwbmailjrn 1 302 train
+zwbyxvgygi 0 300 train
+zwcbibrzhm 1 298 train
+zwccuurlyb 1 300 val
+zwcduxtkca 1 300 train
+zwczgexljf 1 301 train
+zwczmuzcob 1 300 train
+zwdbwncozz 1 300 train
+zwdocryihs 1 300 train
+zwdumfoage 1 300 val
+zwdwslsryb 1 300 train
+zwdxabcayk 1 300 train
+zwefafjsmf 1 300 train
+zwefqfntxz 1 300 train
+zwejzjkulp 1 300 train
+zwepgxaiyn 1 301 train
+zwewkkjnfv 1 300 val
+zweypycsww 1 300 train
+zwfbwzixhd 1 300 train
+zwfebeiqat 0 300 train
+zwfhleykpi 0 300 train
+zwfljqaght 1 298 train
+zwfmecdddy 1 300 val
+zwfmtchbuw 1 298 train
+zwfoychxcc 1 300 train
+zwfpkoojfe 1 300 train
+zwfptqykrc 1 300 val
+zwgaptzuqt 0 300 val
+zwgfpjeerq 0 301 train
+zwghmplokl 1 301 train
+zwgkdunyvs 1 300 val
+zwgkshtnks 1 299 val
+zwgrutmnsn 1 300 test
+zwgsmtrknf 1 301 val
+zwhlxgwatn 1 300 train
+zwhtwpmkxf 1 300 train
+zwhvbhffxi 1 300 train
+zwhvgfdgid 1 300 train
+zwhxcbqfcg 1 241 train
+zwhyceyddh 0 241 train
+zwicvtbkbq 1 300 train
+zwiesboten 1 300 train
+zwinrstvvr 1 300 train
+zwiuallrrw 1 300 val
+zwiulizzwe 1 298 train
+zwixhwourk 1 300 train
+zwjbdovqfm 0 300 train
+zwjcktxrho 1 300 train
+zwjpuwynnh 1 300 train
+zwjsajctep 1 300 train
+zwjtfecxmk 1 300 train
+zwkeeczvam 0 300 train
+zwkipgjxns 1 300 train
+zwkjoldffa 1 300 train
+zwkmjjoytl 1 300 train
+zwkqpxfsfe 1 255 train
+zwlapnertc 1 300 train
+zwlasrtutr 1 300 test
+zwliipgfru 1 300 train
+zwllmdsjfa 1 300 train
+zwllttwmxb 1 300 train
+zwlslhmgyu 1 300 train
+zwlsppaldy 1 300 val
+zwltpjeicp 1 300 train
+zwmdsajboo 0 300 train
+zwmshsdehm 0 300 train
+zwmwinlgtd 1 298 train
+zwncfecfgm 1 300 train
+zwngzoclpv 1 300 train
+zwnjyuvjva 1 300 val
+zwnkaxgrub 1 300 train
+zwnlwbfqlk 1 300 train
+zwnptggpfh 0 300 val
+zwnugojtmc 1 300 val
+zwodigmyyl 1 300 val
+zwogfwhfwz 1 300 train
+zworihnhyn 1 301 train
+zwpjbejsta 1 240 val
+zwppgcggop 1 300 train
+zwpsxtwnkd 0 300 train
+zwpubbvmab 1 300 train
+zwqazrrqzn 1 300 train
+zwqdszjdop 0 300 train
+zwqiejhrps 1 300 val
+zwqifwfkzy 1 300 train
+zwqirzntgt 1 300 train
+zwqvespekh 1 300 train
+zwqzgmiese 1 300 train
+zwrcqfdsze 1 300 train
+zwrgzhbxjk 0 300 train
+zwrsdughvg 1 300 train
+zwruhrzcns 0 300 val
+zwrulgwqve 0 300 train
+zwsbdiyrpg 1 300 test
+zwsjjbxxlz 1 301 train
+zwsmwgibvh 1 300 train
+zwsojzqngn 1 300 val
+zwsrvandic 1 300 train
+zwssujnnir 0 300 train
+zwssxwqswm 1 300 train
+zwstozefkz 1 301 train
+zwswwwrefl 0 299 val
+zwtfcrlhtz 0 240 train
+zwtgiwqwql 1 300 val
+zwtlnvggvv 1 296 val
+zwtlxrtdrk 1 300 val
+zwtmeatpkq 0 300 train
+zwtoqsabjx 1 300 train
+zwtorekqra 1 300 train
+zwtxbucquf 1 300 train
+zwubhsxvqc 1 300 train
+zwuhapgzfz 1 300 train
+zwuklavkho 1 300 train
+zwupuzlefv 1 167 train
+zwuscnqdks 1 300 train
+zwuutlgrqz 1 292 val
+zwvbixepzf 1 300 train
+zwvppwzcgo 1 300 train
+zwvpshcpeb 1 300 val
+zwvsvzurcb 1 300 train
+zwvwkydfnp 1 300 train
+zwvyoudgvq 1 300 train
+zwwgmmfydd 1 297 train
+zwwgmtovgl 1 300 val
+zwwiltbegv 1 83 train
+zwwlkhfbyp 1 300 train
+zwwslmmdqb 1 241 train
+zwwtfetbcu 1 300 train
+zwwvhdnufx 1 301 train
+zwwvpycsis 1 300 train
+zwwvtnacah 1 301 train
+zwxdhuuujb 0 300 train
+zwxefbpfee 0 300 val
+zwxesnqmth 1 300 train
+zwxhezgqtr 1 143 train
+zwxiihvmlz 1 300 train
+zwxjktqpkt 1 298 train
+zwxjnztxyt 1 300 train
+zwxmakbntx 0 300 val
+zwxpyekywc 1 300 val
+zwyjkoceka 1 300 train
+zwymweqhco 1 300 train
+zwytpoelsd 1 300 train
+zwywilvgtj 1 300 val
+zwywjqlkhm 1 300 train
+zwyxnuxpds 1 300 train
+zwzeuapebq 1 300 train
+zwzihtdspl 1 300 train
+zwzlhvygxt 1 301 train
+zwzlsfkjqv 1 288 train
+zwznboftmp 1 300 train
+zwzpioeyuf 0 300 train
+zwzssopxfd 1 300 train
+zwzwucpuus 1 300 train
+zwzxvuiqdn 1 300 train
+zxaawpyxta 1 300 train
+zxacihctqp 0 300 test
+zxafputanf 0 136 train
+zxagpfbuki 1 241 train
+zxajwjvnqr 0 300 train
+zxanlfdyzj 1 300 val
+zxartpdagu 1 300 train
+zxaycruhkg 1 300 train
+zxbcokblzd 1 300 train
+zxbcozaftj 1 298 train
+zxbdjgjpag 1 300 train
+zxbfyieuvp 1 300 val
+zxbhozqcjd 1 300 train
+zxbmuxcjqa 1 300 train
+zxbwpycwlq 1 300 train
+zxbzfevdxh 1 300 train
+zxcebqtnzc 1 300 train
+zxcgyygtbk 0 300 val
+zxcheanzdn 1 298 train
+zxckmjvouc 1 302 train
+zxcoqdeopw 1 300 train
+zxctwuvupm 1 146 train
+zxdcqixnsm 1 300 val
+zxddbcqorr 1 300 val
+zxdnbljsem 1 300 val
+zxdncusydb 1 300 train
+zxdstqtatc 1 300 val
+zxdurhfbjs 1 300 train
+zxdxctlhpl 1 300 train
+zxdxhgkuvj 1 300 train
+zxebuyhswg 1 301 val
+zxehuvandn 1 300 val
+zxeligapyz 1 300 train
+zxerrsnhmj 1 300 val
+zxetlrqrwe 1 299 train
+zxetnidnow 1 300 test
+zxeutitzif 1 298 train
+zxfiryqdva 1 300 train
+zxfjmzmpdy 1 300 train
+zxfqeurdjp 1 300 val
+zxfradgwnh 1 300 val
+zxfvjulgbl 1 300 train
+zxfwbdxtwb 1 241 train
+zxfyxodvji 1 300 train
+zxgapgkdit 1 298 val
+zxgbuqsvnd 1 300 test
+zxgfmhnmap 1 298 train
+zxgherxwue 1 300 train
+zxgilwxjrx 1 300 train
+zxgkvraoyd 1 300 train
+zxgluforfs 1 300 val
+zxgnmlwlww 1 300 train
+zxgodrlflg 1 300 train
+zxgotsxjcd 1 300 train
+zxgpwyvrof 1 301 train
+zxgtewqkbf 1 300 train
+zxguphzcik 1 99 train
+zxhamskdfc 0 300 train
+zxhfdotzwa 1 302 val
+zxhhvqxtfp 1 300 train
+zxhidbjdus 1 300 train
+zxhjoguflb 0 300 train
+zxhpbrlmyj 1 288 train
+zxhqoxfvte 1 301 val
+zxicvptobj 1 300 train
+zxidkxogng 1 300 train
+zxigaqsoof 1 300 val
+zxiibxsiqs 1 300 train
+zxiivfkipf 1 298 val
+zxijjupjvf 1 300 train
+zxindbroqj 1 300 train
+zxiqjaivyp 1 300 train
+zxiwxpuuce 0 300 train
+zxjakmrviw 1 300 train
+zxjelygorl 1 300 train
+zxjgsupwsa 1 299 train
+zxjiwvyzbs 1 300 train
+zxjoffxykl 1 300 val
+zxkbfhgkcy 1 600 train
+zxkcortzrp 1 300 train
+zxkdsoaksc 1 300 train
+zxknocbndw 1 300 val
+zxknpaebqe 0 300 val
+zxknxorxvx 1 300 train
+zxkuksycqg 1 300 train
+zxkypeeftc 1 300 train
+zxkzvizefm 1 300 train
+zxlhpywprk 1 300 val
+zxlhtgbzse 1 300 train
+zxlspjlghi 1 300 train
+zxlvsasqet 1 300 train
+zxlwjltekg 1 300 train
+zxlxgfpwer 1 300 train
+zxmbdjqnkr 1 300 train
+zxmbqubekj 1 300 val
+zxmciqyvbn 1 300 val
+zxmclpnmby 1 302 train
+zxmiuaejbp 1 300 train
+zxmnefygfw 1 300 train
+zxmpacdrca 1 300 train
+zxmqmbakna 1 300 val
+zxmxqwwdwg 0 300 train
+zxnakwotls 1 300 val
+zxnbxrgfra 1 300 train
+zxnduqqkwq 1 300 train
+zxngkeihnz 1 300 val
+zxnhowtixm 1 300 train
+zxnjispgla 1 300 train
+zxnjklorwv 0 300 val
+zxnlihmbgb 1 298 train
+zxobfxqjrd 1 300 train
+zxoofzihjb 1 300 train
+zxoohthpew 1 300 train
+zxopgivqop 1 300 train
+zxoqhqjivy 1 300 train
+zxovcsbkxr 1 300 train
+zxowjkhmmo 1 301 train
+zxoyqbwofo 1 301 val
+zxoyxqyaqe 1 300 train
+zxpctggieo 1 301 val
+zxpdqfewec 1 300 val
+zxpgrtefvd 1 300 val
+zxpjdcqonr 1 240 train
+zxpoenypyy 1 300 train
+zxprilbsxp 1 300 test
+zxpvbbspqf 1 300 train
+zxpvpmlifa 1 300 val
+zxqbxbkmsy 0 300 train
+zxqjjhablw 1 300 train
+zxqlslxvqr 1 300 train
+zxqsroewpm 1 300 train
+zxrehrafcs 1 300 val
+zxrhetnqoi 1 300 train
+zxrkdfcbue 1 240 train
+zxrlcsrhvz 1 300 train
+zxrrlzkgwj 1 300 val
+zxrsbakshn 1 300 train
+zxrtnvmvnt 1 300 train
+zxsgcildut 1 300 train
+zxsgwpnhvn 1 300 train
+zxsnzkqzmn 1 300 train
+zxsrroebii 1 300 train
+zxswdwuogm 1 300 train
+zxsyfdspot 1 301 train
+zxszshlejw 1 300 train
+zxtgpmmtfp 0 300 train
+zxthainysa 1 300 val
+zxtljjyalk 1 300 train
+zxtlkqklfq 1 300 val
+zxtpkianjj 1 300 val
+zxtvtptusl 1 300 test
+zxtvwqwypy 1 298 train
+zxtyapsdjp 1 300 train
+zxudofbpiz 1 300 train
+zxufcfasvr 1 300 train
+zxunnxrvpf 0 300 train
+zxunzapupg 1 299 train
+zxuomjbsrf 1 300 train
+zxuopquqrt 0 300 val
+zxuqoykuqj 1 301 train
+zxurcycefs 1 300 train
+zxutdhzgtg 1 300 train
+zxutekhbcn 1 300 train
+zxuumssbni 1 300 train
+zxuuvcomyw 1 300 train
+zxvgazoudy 1 300 val
+zxvgnpuygs 1 300 train
+zxvhssxqza 0 298 val
+zxvhypkzta 1 300 train
+zxvhyqxeku 1 300 val
+zxvmtvsnen 0 300 train
+zxvuhcvsgi 1 300 val
+zxvvpotqfi 1 300 train
+zxweswyqws 1 298 train
+zxwkqpqwrh 1 300 train
+zxwogvvydf 1 300 train
+zxwpytqvlt 1 300 train
+zxwyxhuhkn 1 300 train
+zxxiourbtb 1 300 train
+zxxqatcrkd 1 300 val
+zxxupobpsu 1 300 train
+zxyapjmzyk 1 296 val
+zxybrrgzlh 1 300 train
+zxydiggxhv 1 300 train
+zxyezdwkka 1 300 train
+zxyiyuxrgz 1 298 val
+zxykwjxvjk 1 300 train
+zxypvavoji 0 300 train
+zxyrchltlj 0 300 train
+zxyszajdlz 1 300 train
+zxyvcnkeiz 1 300 test
+zxzhrmlsvt 1 300 val
+zxzjywnqtj 1 302 train
+zxzllcaktx 1 301 train
+zxznaxmzrd 1 300 train
+zxzpyrhvip 1 300 train
+zxzryhetzh 1 300 train
+zxzvzwtuem 1 302 val
+zxzxxexuxr 1 300 train
+zxzzrvjwey 1 300 train
+zyabsradrv 1 300 train
+zyaffufcvf 1 300 train
+zyaijxyfkp 1 300 train
+zyalofyyoi 0 300 val
+zyamcbyxgy 1 300 train
+zyastwiwje 1 300 train
+zyaxmcnurx 1 300 train
+zyayvgtpxo 1 300 train
+zybisykfiv 1 300 train
+zybjwxrhaa 1 300 train
+zybljvbscm 1 302 val
+zybphbxrxz 1 300 train
+zybskdxoxs 1 300 train
+zybteoksbl 0 300 train
+zybunacsgi 1 300 test
+zybvvznubo 1 300 train
+zybwbezhpo 1 300 train
+zybzlorlcv 1 300 train
+zybzsqdomc 1 300 train
+zychszfmjo 1 300 train
+zycjwyxruc 0 300 train
+zycouhitte 1 300 test
+zycppsjgun 1 300 train
+zycwasldje 0 300 train
+zyczrbkxlo 1 300 train
+zydfkhyurx 1 240 train
+zydiabasxy 1 298 val
+zydjivvzff 1 300 train
+zydkaweyjg 0 300 val
+zydowbohyr 0 300 train
+zydtvgxvyj 1 299 train
+zyeaapjwyg 0 300 train
+zyeakowujw 1 301 train
+zyeaksakrj 1 300 train
+zyedvwjqbu 1 301 train
+zyefmvhvuh 1 300 val
+zyejrdxaeo 1 300 train
+zyetffhvij 1 300 val
+zyewauxeyv 1 300 train
+zyfaihteim 1 300 train
+zyffkfxehz 1 299 train
+zyfxvtxrsk 0 299 train
+zyfyqwdvrs 1 301 train
+zygcgiatke 1 239 val
+zygioyxlvs 1 270 train
+zygtitnnwo 1 300 train
+zygttkqdgu 1 300 train
+zygukovcyn 0 300 train
+zygvghorbb 1 300 train
+zygvoffgde 1 300 train
+zygxrjofsd 1 300 train
+zyhbkqednk 1 300 val
+zyhcdvekuk 1 300 val
+zyhcrlqodu 1 300 train
+zyhedyfwqd 1 300 val
+zyhevzzjpk 1 300 train
+zyhheobbgh 1 300 train
+zyhmhdetex 1 300 val
+zyhmzrshhd 1 300 train
+zyhtqzqdsg 1 241 train
+zyhwrbriuf 1 301 train
+zyhygryska 1 300 train
+zyiarsefqm 1 300 train
+zyibhdvscb 1 300 val
+zyicfdblvi 0 300 val
+zyiekqlsyx 1 298 train
+zyiettizdx 1 300 train
+zyigzxuipb 1 300 val
+zyihsyoqik 1 300 train
+zyimeixasm 1 301 val
+zyiocqadta 1 300 val
+zyivbfjdvy 1 300 train
+zyizxcfaru 0 300 train
+zyjaoqjkpe 1 300 val
+zyjezlrjbm 1 299 test
+zyjguqtkks 1 300 train
+zyjjxfxymt 1 143 train
+zyjljwwuka 1 300 train
+zyjmvauuzw 1 300 test
+zyjppbsoyl 1 300 train
+zyjunwqlwb 1 303 train
+zykeontmuz 1 300 train
+zykjflyyev 1 300 val
+zyknmljwez 1 300 train
+zyksvdlfpn 1 241 train
+zykvkkndxb 1 300 val
+zykwtzlohf 1 300 train
+zykxvaotni 1 301 val
+zylgvbqkte 1 300 val
+zylribcaeu 0 300 train
+zylvctwqff 0 300 train
+zymdpmxghu 1 300 train
+zymqmekdyh 1 300 train
+zymrscfyxe 1 298 train
+zymsgxbhpx 1 300 train
+zyndcjxfwf 1 300 val
+zynhldmsao 1 300 train
+zynjpflhsl 1 300 train
+zynjzuvcpx 1 300 train
+zynngogshp 1 300 train
+zynojnokqg 1 300 train
+zynqifmnjl 1 167 train
+zynrdvlrwv 1 300 train
+zynttmrrcp 1 300 train
+zynvupimrt 1 300 train
+zynyqyfepf 1 300 train
+zyoajdecdm 0 301 train
+zyobeuzfji 0 300 train
+zyobhbmaba 1 301 train
+zyoexhuiye 1 300 val
+zyoiommcbw 1 300 train
+zyoqglshmp 0 300 val
+zyowzrcpck 0 300 train
+zyoxfqsafg 1 300 train
+zyoyobyfua 1 300 train
+zyozxuogpj 0 300 val
+zyozzukmuo 1 301 train
+zypkaxiras 1 300 test
+zyplkpnmib 0 300 train
+zypznqwlhg 1 300 train
+zyqelybefc 1 300 train
+zyqnumqkzk 1 300 train
+zyqphtqdii 0 300 train
+zyqrmwygjg 0 300 val
+zyqswnnlgb 1 300 train
+zyqueyykbh 1 300 train
+zyquhousxc 1 300 val
+zyrnjtbfrm 0 300 train
+zyrqmfanrq 0 300 train
+zyrrjszvrj 1 300 val
+zysabdsoyh 0 300 train
+zysdykbkha 1 300 train
+zysfmcdpbl 1 301 val
+zysmqgwwbk 1 300 train
+zysmvfuvvl 1 300 train
+zysoxzsjvi 1 300 val
+zyspyblfum 1 300 val
+zyswarqqer 1 300 train
+zysxmbezlh 1 300 train
+zysznyalcl 1 300 train
+zytgvkxooc 0 300 train
+zytkzbrsqd 1 300 val
+zytutkjzks 0 300 train
+zytvamtubq 1 300 train
+zytvescrfy 1 301 train
+zytvmqmpnf 1 300 train
+zytxjdcvcy 1 300 val
+zyufpqvpyu 1 300 test
+zyuiqqzwbh 1 300 val
+zyukjfuxnl 1 300 train
+zyulgkylts 1 300 train
+zyumjqzbyl 1 300 train
+zyuyqmoppr 1 300 train
+zyuzslkmkk 1 300 train
+zyvafancxz 0 300 train
+zyvphruzzu 1 300 train
+zyvpxgpebp 1 300 train
+zyvtnkjlen 0 301 train
+zyvzstrbdj 1 300 train
+zywciocdgu 1 300 train
+zywegctqrk 1 300 val
+zywlyzicux 1 300 train
+zywnhhdcku 1 300 val
+zywrxfyxhn 1 300 val
+zywyjdjupw 1 300 train
+zywzdkwpou 1 300 train
+zyxbdircjc 1 300 train
+zyxoniwfoo 0 300 val
+zyxpalvtsh 1 300 val
+zyxrpvarcw 1 300 test
+zyxycjceot 1 300 val
+zyxyoeyglv 1 300 val
+zyycuwdkyn 1 300 train
+zyydnvbdbu 1 300 train
+zyylpktfvt 1 300 train
+zyynehomtf 1 301 val
+zyyvhiftty 1 299 val
+zyyvnotzwg 1 300 train
+zyzejqikcg 1 300 train
+zyzgthbmcd 1 300 train
+zyzofwcols 1 300 train
+zyzugxpidl 1 298 train
+zyzwkaiuxg 1 300 train
+zyzwmreaeb 1 300 train
+zzabhljkkm 1 301 val
+zzaeerjotv 1 297 train
+zzafzthowz 1 300 train
+zzaifosmuw 1 300 test
+zzaiypxdnt 1 300 test
+zzaljrgfco 1 288 train
+zzamgvijbh 1 240 train
+zzaoxzcddu 1 300 test
+zzaqnjsinz 1 300 train
+zzatnepddy 1 300 train
+zzbaqjaiif 1 300 train
+zzbgacyfux 1 300 train
+zzbnecausd 1 300 val
+zzbrtjkzzq 1 300 train
+zzbtisnppv 1 300 train
+zzbyfpadlm 1 241 train
+zzbzqvtxrl 1 300 train
+zzcakihdts 1 300 train
+zzcbogdrup 1 300 train
+zzcbxvytum 0 300 train
+zzcdztipys 1 298 train
+zzcpcvbaln 1 302 train
+zzcrzuecap 1 300 val
+zzdawtcmlu 1 300 val
+zzdngyyjgj 1 300 train
+zzdqvspjwv 1 300 val
+zzdvaxbecl 1 300 train
+zzegrsgrjs 1 301 train
+zzeiqqfgcr 1 300 train
+zzeircwkbh 1 299 test
+zzemcopsns 1 300 train
+zzeyiqleib 1 300 train
+zzeynnherb 1 301 train
+zzeyphpsnj 0 301 val
+zzfcfcxjwc 1 300 train
+zzfejptuog 1 300 train
+zzfewrcsrx 0 300 train
+zzfgfcruta 1 300 train
+zzfyzzeelr 1 300 train
+zzgabsvcpo 1 241 train
+zzgavqmiit 1 299 val
+zzgbsjvyqq 0 301 val
+zzgljkniuj 1 300 val
+zzgsqccfuo 1 300 train
+zzgtjnoyoo 1 300 test
+zzgtpnamdc 1 300 val
+zzgtsepnfb 1 300 train
+zzgyzynrom 1 300 train
+zzheksypla 1 300 train
+zzhkvorcho 1 300 train
+zzhtdtgdur 0 300 train
+zzhtveafea 1 300 train
+zzifdmficx 1 300 train
+zzilgopnqe 0 300 train
+zzipflfowb 1 300 train
+zzipszjtvm 1 269 train
+zzitnsdmzp 1 297 train
+zzivhztyyn 1 300 train
+zzjaeempuv 1 300 val
+zzjfdhmcjv 0 300 train
+zzjfzeuizr 0 300 train
+zzjhtqolag 1 300 train
+zzjiszpgay 1 300 train
+zzjqngvean 1 298 train
+zzkbtgsnfs 1 300 train
+zzkfomgfoj 1 300 train
+zzkuddbixk 1 300 val
+zzkurmfrym 1 300 train
+zzkzxqgbcy 1 300 train
+zzlskuhaoa 1 300 train
+zzlsynxeff 1 300 test
+zzlwvkpdwl 1 300 train
+zzlzdkrepa 1 300 train
+zzmfzfphxb 1 300 val
+zzmgnglanj 0 300 test
+zzmprofhws 1 300 val
+zzmrcwawpe 0 300 val
+zzmtnaepvv 1 300 train
+zzmzxtdrfr 1 300 train
+zznanrtksj 1 300 val
+zznlgswxzy 1 300 train
+zznpeapdbo 1 300 train
+zznuigsflq 0 300 train
+zzogukbedf 1 300 val
+zzoimuggyc 0 300 train
+zzoluaiksl 1 300 train
+zzoprelcru 1 300 train
+zzovnywzuh 1 300 train
+zzoxcmmcfa 1 300 train
+zzpbsapyyf 0 300 train
+zzpdzuwhfp 1 300 train
+zzpjawovun 1 300 val
+zzpnyudlgp 0 300 train
+zzpokjyspw 1 299 val
+zzpvltkigb 1 301 train
+zzpyxttgbt 1 300 val
+zzpzemkknj 1 301 train
+zzpzjrfoes 1 300 train
+zzqbldltkt 1 241 train
+zzqbwhiots 1 300 train
+zzqhtdwcyl 1 300 train
+zzqtmsldbq 1 300 train
+zzrciegcfw 1 300 train
+zzrcypvrgw 1 300 train
+zzrgdemacp 1 300 train
+zzrhapbszk 1 300 train
+zzrhdjyrpw 1 300 train
+zzrjkevkzx 1 300 val
+zzrmokkxka 0 300 train
+zzrppdukls 1 300 val
+zzrscftuqp 1 300 train
+zzsdtyixai 1 300 val
+zzsfypmgfc 1 300 train
+zzshtqasij 1 300 train
+zzssjgskys 0 300 train
+zzssnqxsau 1 301 train
+zzstazxajm 1 300 train
+zzsuwijkkv 1 300 val
+zzsvsjkcva 1 300 train
+zzsxjtdivw 1 300 train
+zztfqtwbah 0 300 train
+zztlhlbxdk 1 301 train
+zztnoihwgg 1 300 train
+zzucondult 1 300 train
+zzuhwofwja 0 300 val
+zzuqbyaqar 1 300 train
+zzuqscbpsd 1 300 val
+zzurzlsmlv 1 300 train
+zzuvgnjlxi 0 300 train
+zzuxfrnjcz 1 300 train
+zzuyvxemjp 1 300 train
+zzvjfsjlyq 1 300 val
+zzvnjltqob 1 300 train
+zzvrfqhuvn 1 300 train
+zzvtesaaml 1 300 val
+zzvyiyglzc 1 241 train
+zzwfztrtaw 1 300 val
+zzxgqksisv 1 300 train
+zzxhamqacm 1 300 train
+zzxidpsxmv 1 299 val
+zzxireqbdi 1 300 train
+zzxjmkshuy 1 300 val
+zzxnpsjyyo 1 300 train
+zzxshthbxd 1 300 val
+zzxsqzxivm 1 301 val
+zzxtoqzmgo 1 300 train
+zzxysftvso 1 298 train
+zzybilxtdq 1 300 train
+zzycdovfhk 1 300 train
+zzylfwxjbb 1 300 train
+zzylooqabq 1 300 train
+zzyubuunjv 1 241 train
+zzyurmuxnj 1 301 train
+zzyyjpyuln 1 300 train
+zzzchyhnpx 1 300 train
+zzzmnklzau 1 300 train
+zzztvbnare 1 143 train
+zzzvjolglc 1 301 train
\ No newline at end of file
diff --git a/clean/video/mintime/preprocessing/save_folder_structure.py b/clean/video/mintime/preprocessing/save_folder_structure.py
new file mode 100644
index 0000000000000000000000000000000000000000..bbb7d5efbb9fa8de4a46d4d746569459c04bf4a9
--- /dev/null
+++ b/clean/video/mintime/preprocessing/save_folder_structure.py
@@ -0,0 +1,11 @@
+import os
+import csv
+import glob
+
+DATA_PATH = "../../datasets/ForgeryNet/faces"
+paths = glob.glob(f'{DATA_PATH}/*/**/*.png', recursive=True)
+print(len(paths))
+
+with open('../csv/faces_files_structure.csv', 'w+') as f:
+ for path in paths:
+ f.write(path + "\n")
diff --git a/clean/video/mintime/preprocessing/split_dataset.py b/clean/video/mintime/preprocessing/split_dataset.py
new file mode 100644
index 0000000000000000000000000000000000000000..33883edc54c0d601be5ec8c8f66ec43bc0b92a3d
--- /dev/null
+++ b/clean/video/mintime/preprocessing/split_dataset.py
@@ -0,0 +1,177 @@
+# ForgeryNet provided a training set and a validation set but not a complete test set. With this code, the validation set is moved into a folder so that it can be used as a test set,
+# while a new validation set is derived from the training set.
+# The latter is constructed so that it has a distribution of deepfake generation methods equal to that of the training set and is composed of a number of samples equal to 10%
+# of those in the training set.
+# A plot is also generated to show the distribution of the three datasets.
+
+import os
+import argparse
+import pandas as pd
+import math
+import matplotlib.pyplot as plt
+import collections
+import random
+import shutil
+import glob
+import csv
+
+seed = 42
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--train_list_file', default="../../datasets/ForgeryNet/Training/video_list_complete.txt", type=str,
+ help='Videos List txt file path for training set (to be splitted in train and validation)')
+ parser.add_argument('--validation_list_file', default="../../datasets/ForgeryNet/Validation/video_list.txt", type=str,
+ help='Videos List txt file path for validation set (our test set)')
+ parser.add_argument('--plots_output_path', default="../outputs", type=str,
+ help='Plots output path')
+ parser.add_argument('--faces_path', default="../../datasets/ForgeryNet/faces", type=str,
+ help='Images path')
+ parser.add_argument('--validation_set_output_path', default="../../datasets/ForgeryNet/faces/val", type=str,
+ help='Test set output path')
+ parser.add_argument('--train_faces_path', default="../../datasets/ForgeryNet/faces/train", type=str,
+ help='Train images path')
+ parser.add_argument('--test_faces_path', default="../../datasets/ForgeryNet/faces/test", type=str,
+ help='Test images path')
+
+ opt = parser.parse_args()
+ print(opt)
+ datasets = {"train": {}, "val": {}, "test": {}}
+
+ # Reading of the training set and extraction of its distribution excluding videos in which no faces were found.
+ paths = glob.glob(f'{opt.train_faces_path}/*/**/*.mp4', recursive=True)
+ with open(opt.train_list_file, 'r') as temp_f:
+ col_count = [ len(l.split(" ")) for l in temp_f.readlines() ]
+
+ column_names = [i for i in range(0, max(col_count))]
+ df = pd.read_csv(opt.train_list_file, sep=' ', names=column_names)
+
+ training_counter = {}
+ column_names.reverse()
+ skipped = 0
+ for index, row in df.iterrows():
+ video_name = os.path.join(opt.train_faces_path, row[1].split("train_video_release/")[-1])
+ if video_name not in paths:
+ skipped += 1
+ continue
+
+ for column_name in column_names:
+ if not math.isnan(row[column_name]):
+ deepfake_class = row[column_name]
+ break
+
+ if deepfake_class in training_counter:
+ training_counter[deepfake_class] += 1
+ else:
+ training_counter[deepfake_class] = 1
+
+ if deepfake_class in datasets["train"]:
+ datasets["train"][deepfake_class].append(video_name.replace("train_video_release", "train").replace(opt.train_faces_path, "train"))
+ else:
+ datasets["train"][deepfake_class] = [video_name.replace("train_video_release", "train").replace(opt.train_faces_path, "train")]
+
+ print(skipped, "videos in training set without detected faces skipped.")
+ training_counter = collections.OrderedDict(sorted(training_counter.items()))
+
+ # Construction of the validation set from the training set distribution
+ total_training_samples = len(df)
+ validation_size = total_training_samples/10
+ total = 0
+ validation_counter = {}
+ for key in training_counter:
+ percentage = training_counter[key]/total_training_samples
+ elements = validation_size*percentage
+ validation_counter[key] = int(elements)
+ training_counter[key] -= elements
+
+ validation_counter = collections.OrderedDict(sorted(validation_counter.items()))
+
+ # Plotting training set distribution
+ names = list(training_counter.keys())
+ values = list(training_counter.values())
+ x = [i-0.3 for i in range(len(training_counter))]
+ plt.bar(x, values, 0.3, tick_label=names, label = "Training Set")
+
+ # Plotting validation set distribution
+ names = list(validation_counter.keys())
+ values = list(validation_counter.values())
+ x = [i for i in range(len(training_counter))]
+ plt.bar(x, values, 0.3, tick_label=names, label = "Validation Set")
+
+ # Reading of the validation set (which will be used as a test set) and extraction of its distribution excluding videos in which no faces were found.
+ skipped = 0
+ with open(opt.validation_list_file, 'r') as temp_f:
+ col_count = [ len(l.split(" ")) for l in temp_f.readlines() ]
+
+ column_names = [i for i in range(0, max(col_count))]
+ df = pd.read_csv(opt.validation_list_file, sep=' ', names=column_names)
+
+ test_counter = {}
+ column_names.reverse()
+
+ paths = glob.glob(f'{opt.test_faces_path}/*/**/*.mp4', recursive=True)
+ for index, row in df.iterrows():
+ video_name = os.path.join(opt.test_faces_path, row[1].split("val_video_release/")[-1])
+ if video_name not in paths:
+ skipped += 1
+ continue
+
+ for column_name in column_names:
+ if not math.isnan(row[column_name]):
+ deepfake_class = row[column_name]
+ break
+
+ if deepfake_class in test_counter:
+ test_counter[deepfake_class] += 1
+ else:
+ test_counter[deepfake_class] = 1
+
+ if deepfake_class in datasets["test"]:
+ datasets["test"][deepfake_class].append(video_name.replace("val_video_release", "test").replace(opt.test_faces_path, "test"))
+ else:
+ datasets["test"][deepfake_class] = [video_name.replace("val_video_release", "test").replace(opt.test_faces_path, "test")]
+
+ print(skipped, "videos in test set without detected faces skipped.")
+ test_counter = collections.OrderedDict(sorted(test_counter.items()))
+
+ # Plotting test set distribution
+ names = list(test_counter.keys())
+ values = list(test_counter.values())
+
+ x = [i+0.3 for i in range(len(test_counter))]
+ plt.bar(x, values, 0.3, tick_label=names, label = "Test Set")
+
+ plt.legend()
+ plt.savefig(os.path.join(opt.plots_output_path, "distribution"))
+
+
+# Move selected training files for the validation set construction into validation folder
+for deepfake_class in datasets["train"]:
+ number_of_elements = validation_counter[deepfake_class]
+ extracted_elements = random.Random(seed).sample(datasets["train"][deepfake_class],number_of_elements)
+ for index, video_name in enumerate(extracted_elements):
+ out_path = os.path.join(opt.validation_set_output_path, video_name.split("Training/video")[-1]).replace("val/train", "val")
+ src_path = os.path.join(opt.faces_path, video_name).replace("train_video_release", "train")
+ datasets["train"][deepfake_class].remove(video_name)
+ if deepfake_class in datasets["val"]:
+ datasets["val"][deepfake_class].append(video_name.replace("train", "val"))
+ else:
+ datasets["val"][deepfake_class] = [video_name.replace("train", "val")]
+ if index % 500 == 0:
+ print("Moved", index, "videos into validation set.")
+ shutil.move(src_path, out_path)
+
+# Generate labels csv files for the three sets
+for key in datasets:
+ f = open(os.path.join(opt.faces_path, key+".csv"), 'w+')
+ dataset = datasets[key]
+ for deepfake_class in dataset:
+ if deepfake_class == 0:
+ binary_class = "0"
+ else:
+ binary_class = "1"
+ for video in dataset[deepfake_class]:
+ row = video + " " + binary_class + " " + str(int(deepfake_class)) + "\n"
+ f.write(row)
+
+ f.close()
diff --git a/clean/video/mintime/preprocessing/utils.py b/clean/video/mintime/preprocessing/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..ce21500677165f4fc7bc0555d59dc71f2d21b1f5
--- /dev/null
+++ b/clean/video/mintime/preprocessing/utils.py
@@ -0,0 +1,34 @@
+# Utility functions used in preprocessing steps
+
+import glob
+import os
+from torchvision.transforms import Resize, ToPILImage, ToTensor
+import networkx as nx
+
+# Returns all the files paths with a specific extension inside a requested root directory
+def get_paths(rootdir, ext="png"):
+ paths = []
+ for path in glob.glob(f'{rootdir}/*/**/*.'+ext, recursive=True):
+ paths.append(path)
+ return paths
+
+# Cluster the images generating a graph of connected components
+def _generate_connected_components(similarities, similarity_threshold=0.80):
+ graph = nx.Graph()
+ for i in range(len(similarities)):
+ for j in range(len(similarities)):
+ if i != j and similarities[i, j] > similarity_threshold:
+ graph.add_edge(i, j)
+
+ components_list = []
+ for component in nx.connected_components(graph):
+ components_list.append(list(component))
+ graph.clear()
+ graph = None
+
+ return components_list
+
+# Method used to preprocess the image before features extraction in clustering step
+def preprocess_images(img, shape=[128, 128]):
+ img = Resize(shape)(img)
+ return img
diff --git a/clean/video/mintime/requirements.txt b/clean/video/mintime/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c02b978a55438ff3e4a1fa68dfdda80f977cceea
--- /dev/null
+++ b/clean/video/mintime/requirements.txt
@@ -0,0 +1,124 @@
+absl-py==1.1.0
+albumentations==0.5.2
+astunparse==1.6.3
+blis==0.7.8
+Bottleneck==1.3.4
+brotlipy==0.7.0
+cachetools==5.2.0
+catalogue==2.0.7
+certifi==2022.5.18.1
+cffi==1.15.0
+charset-normalizer==2.0.4
+click==8.1.3
+colorama==0.4.4
+cryptography==37.0.1
+cycler==0.11.0
+cymem==2.0.6
+DateTime==4.5
+efficientnet-3D==1.0.2
+efficientnet-pytorch==0.7.1
+einops==0.4.1
+facenet-pytorch==2.5.2
+fastai==2.7.4
+fastcore==1.4.5
+fastdownload==0.0.6
+fastprogress==1.0.2
+filelock==3.7.1
+flatbuffers==1.12
+fonttools==4.33.3
+gast==0.4.0
+google-auth==2.8.0
+google-auth-oauthlib==0.4.6
+google-pasta==0.2.0
+grpcio==1.46.3
+h5py==3.7.0
+huggingface-hub==0.7.0
+idna==3.3
+imageio==2.19.3
+imgaug==0.4.0
+Jinja2==3.1.2
+joblib==1.1.0
+keras==2.9.0
+Keras-Preprocessing==1.1.2
+kiwisolver==1.4.2
+langcodes==3.3.0
+libclang==14.0.1
+Markdown==3.3.7
+MarkupSafe==2.1.1
+matplotlib==3.5.2
+mkl-fft==1.3.1
+mkl-random==1.2.2
+mkl-service==2.4.0
+murmurhash==1.0.7
+numexpr==2.7.3
+numpy==1.21.6
+oauthlib==3.2.0
+opencv-python==4.5.5.64
+opencv-python-headless==4.6.0.66
+opt-einsum==3.3.0
+packaging==21.3
+pandas==1.3.5
+pathy==0.6.2
+Pillow==9.0.1
+pip==21.2.4
+preshed==3.0.6
+progress==1.6
+protobuf==3.19.4
+pyasn1==0.4.8
+pyasn1-modules==0.2.8
+pycparser==2.21
+pydantic==1.8.2
+pyOpenSSL==22.0.0
+pyparsing==3.0.9
+PySocks==1.7.1
+python-dateutil==2.8.2
+python-magic==0.4.27
+pytorch-ranger==0.1.1
+pytz==2021.3
+PyWavelets==1.3.0
+PyYAML==6.0
+qudida==0.0.4
+regex==2022.6.2
+requests==2.27.1
+requests-oauthlib==1.3.1
+rsa==4.8
+scikit-image==0.18.3
+scikit-learn==1.0.1
+scipy==1.7.3
+seaborn==0.11.2
+setuptools==62.3.2
+Shapely==1.8.2
+six==1.16.0
+sklearn==0.0
+smart-open==5.2.1
+spacy==3.3.1
+spacy-legacy==3.0.9
+spacy-loggers==1.0.2
+srsly==2.4.3
+tensorboard==2.9.1
+tensorboard-data-server==0.6.1
+tensorboard-plugin-wit==1.8.1
+tensorflow==2.9.1
+tensorflow-estimator==2.9.0
+tensorflow-io-gcs-filesystem==0.26.0
+termcolor==1.1.0
+thinc==8.0.17
+threadpoolctl==3.1.0
+tifffile==2021.11.2
+timesformer-pytorch==0.4.1
+timm==0.5.4
+tokenizers==0.12.1
+torch==1.11.0
+torch-optimizer==0.3.0
+torchsummary==1.5.1
+torchvision==0.12.0
+tqdm==4.64.0
+transformers==4.20.0
+typer==0.4.1
+typing_extensions==4.1.1
+urllib3==1.26.9
+wasabi==0.9.1
+Werkzeug==2.1.2
+wheel==0.37.1
+wrapt==1.14.1
+zope.interface==5.4.0
diff --git a/clean/video/mintime/test.py b/clean/video/mintime/test.py
new file mode 100644
index 0000000000000000000000000000000000000000..c9d05e0ba3ee45d719e97e977a3d9b53f715fe40
--- /dev/null
+++ b/clean/video/mintime/test.py
@@ -0,0 +1,291 @@
+
+import torch
+import numpy as np
+import argparse
+from tqdm import tqdm
+import math
+import yaml
+from utils import check_correct, aggregate_attentions, save_attention_plots, count_parameters, slowfast_input_transform
+from torch.optim.lr_scheduler import LambdaLR
+from datetime import datetime, timedelta
+from statistics import mean
+import tensorflow as tf
+import collections
+import os
+import json
+from sklearn import metrics
+from sklearn.metrics import f1_score
+from itertools import chain
+import random
+from einops import rearrange, reduce
+import pandas as pd
+from os import cpu_count
+from multiprocessing.pool import Pool
+from functools import partial
+from multiprocessing import Manager
+from progress.bar import ChargingBar
+from torch.optim import lr_scheduler
+from deepfakes_dataset import DeepFakesDataset
+from models.size_invariant_timesformer import SizeInvariantTimeSformer
+from models.efficientnet.efficientnet_pytorch import EfficientNet
+from torch.utils.tensorboard import SummaryWriter
+import torch_optimizer as optim
+from timm.scheduler.cosine_lr import CosineLRScheduler
+from models.baseline import Baseline
+from models.xception import xception
+
+
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+
+ parser.add_argument('--test_list_file', default="../../datasets/ForgeryNet/faces/test.csv", type=str,
+ help='Test List txt file path)')
+ parser.add_argument('--data_path', default="../../datasets/ForgeryNet/faces", type=str,
+ help='Path to the dataset converted into identities.')
+ parser.add_argument('--video_path', default="../../datasets/ForgeryNet/videos", type=str,
+ help='Path to the dataset original videos (.mp4 files).')
+ parser.add_argument('--deepfake_methods', nargs='*', required=False,
+ help="For ForgeryNet dataset, filter some deepfake methods for partial training.")
+ parser.add_argument('--workers', default=8, type=int,
+ help='Number of data loader workers.')
+ parser.add_argument('--random_state', default=42, type=int,
+ help='Random state value')
+ parser.add_argument('--model_weights', type=str,
+ help='Model weights.')
+ parser.add_argument('--extractor_model', type=int, default=0,
+ help="Which model use for features extraction (0: EfficientNet; 1: XceptionNet).")
+ parser.add_argument('--extractor_weights', default='ImageNet', type=str,
+ help='Path to extractor weights or "imagenet".')
+ parser.add_argument('--gpu_id', default=0, type=int,
+ help='ID of GPU to be used.')
+ parser.add_argument('--max_videos', type=int, default=-1,
+ help="Maximum number of videos to use for training (default: all).")
+ parser.add_argument('--only_multiidentity', default=False, action="store_true",
+ help='Use only multiidentity videos.')
+ parser.add_argument('--config', type=str,
+ help="Which configuration to use. See into 'config' folder.")
+ parser.add_argument('--model', type=int,
+ help="Which model to use. (0: Baseline | 1: Size Invariant TimeSformer | 2: SlowFast).")
+ parser.add_argument('--identities_ordering', type=int, default = 0,
+ help="Which ordering rule to use. (0: Size-based | 1: Frequency-based | 2: Random).")
+ parser.add_argument('--save_attentions', default=False, action="store_true",
+ help='Save attentions plots.')
+ opt = parser.parse_args()
+
+ print(opt)
+ with open(opt.config, 'r') as ymlfile:
+ config = yaml.safe_load(ymlfile)
+
+ os.environ["CUDA_VISIBLE_DEVICES"] = "0,1"
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
+
+
+ # Check for integrity
+ if config['model']['num-frames'] != 8 and config['model']['num-frames'] != 16:
+ raise Exception("Invalid number of frames.")
+
+
+ # Setup CUDA settings
+ torch.backends.cudnn.deterministic = True
+ random.seed(opt.random_state)
+ torch.manual_seed(opt.random_state)
+ torch.cuda.manual_seed(opt.random_state)
+ np.random.seed(opt.random_state)
+
+ # Load required weights for feature extractor
+ if opt.model != 2:
+ if opt.extractor_model == 0: # EfficientNet-B0
+ if opt.extractor_weights.lower() == 'imagenet':
+ features_extractor = EfficientNet.from_pretrained('efficientnet-b0')
+ else:
+ features_extractor = EfficientNet.from_name('efficientnet-b0')
+ features_extractor.load_matching_state_dict(torch.load(opt.extractor_weights, map_location=torch.device('cpu')))
+ print("Custom features extractor weights loaded.")
+ else: # XceptionNet
+ if opt.extractor_weights.lower() == 'pretrained':
+ features_extractor = xception(num_classes=1, pretrain_path="weights/ckpt_iter.pth.tar")
+ else:
+ features_extractor = xception(num_classes=1, pretrain_path=opt.extractor_weights)
+ else:
+ features_extractor = None
+
+ # Init the required model
+ if opt.model == 0:
+ model = Baseline(config=config)
+ num_patches = None
+ elif opt.model == 1:
+ model = SizeInvariantTimeSformer(config=config, require_attention=True)
+ num_patches = config['model']['num-patches']
+ elif opt.model == 2:
+ torch.hub._validate_not_a_forked_repo=lambda a,b,c: True
+ model = torch.hub.load('facebookresearch/pytorchvideo', 'slowfast_r50', pretrained=True)
+ output_layer = torch.nn.Linear(2304 , 1)
+ model.blocks[6].proj = output_layer
+ num_patches = None
+
+
+ if features_extractor != None and opt.gpu_id == -1:
+ features_extractor = torch.nn.DataParallel(features_extractor)
+
+ if opt.gpu_id == -1:
+ model = torch.nn.DataParallel(model)
+
+
+ if os.path.exists(opt.model_weights):
+ model.load_state_dict(torch.load(opt.model_weights))
+ else:
+ raise Exception("No checkpoint loaded for the model.")
+
+ loss_fn = torch.nn.BCEWithLogitsLoss()
+
+ # Move into GPU
+ if features_extractor != None:
+ features_extractor = features_extractor.to(device)
+ features_extractor.eval()
+ print("Extractor Parameters: ", count_parameters(features_extractor))
+ print("Model Parameters: ", count_parameters(model))
+ model = model.to(device)
+ model.eval()
+
+ # Read all the paths and initialize data loaders for train and validation
+ paths = []
+ col_names = ["video", "label", "8_cls"]
+ df_test = pd.read_csv(opt.test_list_file, sep=' ', names=col_names)
+ df_test = df_test.sample(frac=1, random_state=opt.random_state).reset_index(drop=True)
+
+
+ # Filter out deepfake methods if requested for ForgeryNet
+ if opt.deepfake_methods is not None and len(opt.deepfake_methods) > 0:
+ opt.deepfake_methods = [int(method) for method in opt.deepfake_methods]
+ indexes_to_drop = []
+ for index, row in df_test.iterrows():
+ if row['8_cls'] not in opt.deepfake_methods:
+ indexes_to_drop.append(index)
+ df_test.drop(df_test.index[indexes_to_drop], inplace=True)
+
+ # Filter out non-multi-identity videos if requested
+ if opt.only_multiidentity:
+ indexes_to_drop = []
+ for index, row in df_test.iterrows():
+ video_path = os.path.join(opt.data_path, row['video'])
+ folders = os.listdir(video_path)
+ if len(folders) < 2:
+ indexes_to_drop.append(index)
+ else:
+ counter = 0
+ for folder in folders:
+ if os.path.isdir(os.path.join(opt.data_path, row['video'], folder)):
+ counter += 1
+ if counter < 2:
+ indexes_to_drop.append(index)
+
+ df_test.drop(df_test.index[indexes_to_drop], inplace=True)
+
+ # Split videos and labels and reduce to the required number of videos
+ test_videos = df_test['video'].tolist()
+ test_labels = df_test['label'].tolist()
+ multiclass_labels = df_test['8_cls'].tolist()
+ class_counter = collections.Counter(multiclass_labels)
+
+ if opt.max_videos > -1:
+ test_videos = test_videos[:opt.max_videos]
+ test_labels = test_labels[:opt.max_videos]
+
+ test_samples = len(test_videos)
+
+ # Create the data loaders
+ test_dataset = DeepFakesDataset(test_videos, test_labels, multiclass_labels = multiclass_labels, image_size=config['model']['image-size'], data_path=opt.data_path, video_path=opt.video_path, num_frames=config['model']['num-frames'], num_patches=num_patches, max_identities=config['model']['max-identities'], enable_identity_attention=config['model']['enable-identity-attention'], identities_ordering = opt.identities_ordering, mode='test')
+ test_dl = torch.utils.data.DataLoader(test_dataset, batch_size=config['test']['bs'], shuffle=False, sampler=None,
+ batch_sampler=None, num_workers=opt.workers, collate_fn=None,
+ pin_memory=False, drop_last=False, timeout=0,
+ worker_init_fn=None, prefetch_factor=2,
+ persistent_workers=False)
+
+ # Print some useful statistics
+ print("Test videos:", test_samples)
+ print("__TEST STATS__")
+ test_counters = collections.Counter(test_labels)
+ print(test_counters)
+
+ # Init variables
+ total_test_loss = 0
+ test_correct = 0
+ test_positive = 0
+ test_negative = 0
+ test_counter = 0
+
+ multiclass_errors = dict.fromkeys([i for i in range(9)])
+ for key in multiclass_errors:
+ multiclass_errors[key] = [0, class_counter[key]]
+
+ bar = ChargingBar('PREDICT', max=(len(test_dl)))
+ preds = []
+ videos_errors = []
+
+ # Test loop
+ for index, (videos, size_embeddings, masks, identities_masks, positions, tokens_per_identity, labels, multiclass_labels, video_ids) in enumerate(test_dl):
+ b, f, h, w, c = videos.shape
+ labels = labels.unsqueeze(1).float()
+ identities_masks = identities_masks.to(device)
+ masks = masks.to(device)
+ positions = positions.to(device)
+
+ with torch.no_grad():
+
+ if opt.model != 2: # Use the features extractor
+ videos = rearrange(videos, "b f h w c -> (b f) c h w")
+ videos = videos.to(device)
+
+ features = features_extractor(videos)
+ if opt.model == 0:
+ test_pred = model(features)
+ test_pred = torch.mean(test_pred.reshape(-1, config["model"]["num-frames"]), axis=1).unsqueeze(1)
+ elif opt.model == 1:
+ features = rearrange(features, '(b f) c h w -> b f c h w', b = b, f = f)
+ test_pred, attentions = model(features, mask=masks, size_embedding=size_embeddings, identities_mask=identities_masks, positions=positions)
+ if opt.save_attentions:
+ identity_names = [row[0] for row in tokens_per_identity]
+ frames_per_identity = [int(row[1] / config["model"]["num-patches"]) for row in tokens_per_identity]
+
+ aggregated_attentions, identity_attentions = aggregate_attentions(attentions, config['model']['heads'], config['model']['num-frames'], frames_per_identity)
+
+ save_attention_plots(aggregated_attentions, identity_names, frames_per_identity, config['model']['num-frames'], video_ids[0])
+ elif opt.model == 2:
+ videos = rearrange(videos, 'b f h w c -> b c f h w')
+ videos = slowfast_input_transform(videos)
+ videos = [torch.cat([v[None, ...].to(device) for v in videos[0]]), torch.cat([v[None, ...].to(device) for v in videos[1]])]
+ test_pred = model(videos)
+
+
+ if opt.model != 2:
+ videos = videos.cpu()
+ else:
+ videos = [torch.cat([v[None, ...].cpu() for v in videos[0]]), torch.cat([v[None, ...].cpu() for v in videos[1]])]
+
+ test_pred = test_pred.cpu()
+
+ test_loss = loss_fn(test_pred, labels)
+ total_test_loss += round(test_loss.item(), 2)
+ corrects, positive_class, negative_class, multiclass_errors, batch_errors = check_correct(test_pred, labels, multiclass_labels, multiclass_errors, video_ids)
+ videos_errors.extend(batch_errors)
+ test_correct += corrects
+ test_positive += positive_class
+ test_counter += 1
+ test_negative += negative_class
+ preds.extend(test_pred)
+ bar.next()
+
+ preds = [torch.sigmoid(torch.tensor(pred)) for pred in preds]
+ fpr, tpr, th = metrics.roc_curve(test_labels, preds)
+ auc = metrics.auc(fpr, tpr)
+ f1 = f1_score(test_labels, [round(pred.item()) for pred in preds])
+ bar.finish()
+ total_test_loss /= test_counter
+ test_correct /= test_samples
+ print("Videos errors", videos_errors)
+ print("Class errors", multiclass_errors)
+ print(str(opt.model_weights) + " test loss:" +
+ str(total_test_loss) + " f1 score: " + str(f1) + " test accuracy:" + str(test_correct) + " test_0s:" + str(test_negative) + "/" + str(test_counters[0]) + " test_1s:" + str(test_positive) + "/" + str(test_counters[1]) + " AUC " + str(auc))
+
\ No newline at end of file
diff --git a/clean/video/mintime/train.py b/clean/video/mintime/train.py
new file mode 100644
index 0000000000000000000000000000000000000000..d6c91478226d133a47628e7efde99f8ec3d42b17
--- /dev/null
+++ b/clean/video/mintime/train.py
@@ -0,0 +1,480 @@
+# The training process is conducted using this code and it can be customized on the specific model that you want to train.
+
+import numpy as np
+import argparse
+from tqdm import tqdm
+import math
+import yaml
+from utils import check_correct, unix_time_millis, slowfast_input_transform
+from torch.optim.lr_scheduler import LambdaLR
+from datetime import datetime, timedelta
+from statistics import mean
+import tensorflow as tf
+import collections
+import os
+import json
+from itertools import chain
+import random
+from einops import rearrange, reduce
+import pandas as pd
+from os import cpu_count
+from multiprocessing.pool import Pool
+from functools import partial
+from multiprocessing import Manager
+from progress.bar import ChargingBar
+from torch.optim import lr_scheduler
+from deepfakes_dataset import DeepFakesDataset
+from models.size_invariant_timesformer import SizeInvariantTimeSformer
+from models.efficientnet.efficientnet_pytorch import EfficientNet
+from torch.utils.tensorboard import SummaryWriter
+import torch_optimizer as optim
+from timm.scheduler.cosine_lr import CosineLRScheduler
+from models.baseline import Baseline
+from models.xception import xception
+import pytorchvideo
+from pytorchvideo.models.hub.slowfast import _slowfast
+from contextlib import redirect_stderr
+import sys
+os.environ["CUDA_VISIBLE_DEVICES"] = "1"
+
+import torch
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--train_list_file', default="../../datasets/ForgeryNet/faces/train_and_val.csv", type=str,
+ help='Training List txt file path)')
+ parser.add_argument('--validation_list_file', default="../../datasets/ForgeryNet/faces/test.csv", type=str,
+ help='Validation List txt file path)')
+ parser.add_argument('--data_path', default="../../datasets/ForgeryNet/faces", type=str,
+ help='Path to the dataset converted into identities.')
+ parser.add_argument('--video_path', default="../../datasets/ForgeryNet/videos", type=str,
+ help='Path to the dataset original videos (.mp4 files).')
+ parser.add_argument('--deepfake_methods', nargs='*', required=False,
+ help="For ForgeryNet dataset, filter some deepfake methods for partial training.")
+ parser.add_argument('--num_epochs', default=30, type=int,
+ help='Number of training epochs.')
+ parser.add_argument('--workers', default=8, type=int,
+ help='Number of data loader workers.')
+ parser.add_argument('--random_state', default=42, type=int,
+ help='Random state value')
+ parser.add_argument('--freeze_backbone', default=False, action="store_true",
+ help='Maintain the backbone freezed or train it.')
+ parser.add_argument('--restore_epoch', default=False, action="store_true",
+ help='When resume checkpoint specified, resume from the exact epoch.')
+ parser.add_argument('--extractor_model', type=int, default=0,
+ help="Which model use for features extraction (0: EfficientNet; 1: XceptionNet).")
+ parser.add_argument('--extractor_unfreeze_blocks', type=int, default=-1,
+ help="How many layers unfreeze in the extractor.")
+ parser.add_argument('--extractor_weights', default='ImageNet', type=str,
+ help='Path to extractor weights or "imagenet".')
+ parser.add_argument('--gpu_id', default=0, type=int,
+ help='ID of GPU to be used.')
+ parser.add_argument('--resume', default='', type=str, metavar='PATH',
+ help='Path to latest checkpoint (default: none).')
+ parser.add_argument('--max_videos', type=int, default=-1,
+ help="Maximum number of videos to use for training (default: all).")
+ parser.add_argument('--config', type=str,
+ help="Which configuration to use. See into 'config' folder.")
+ parser.add_argument('--model', type=int,
+ help="Which model to use. (0: Baseline | 1: Size Invariant TimeSformer | 2: SlowFast).")
+ parser.add_argument('--patience', type=int, default=5,
+ help="How many epochs wait before stopping for validation loss not improving.")
+ parser.add_argument('--logger_name', default='runs/train',
+ help='Path to save the model and Tensorboard log.')
+ parser.add_argument('--errors_logs_file', default=None,
+ help='Path to save the error logs.')
+ parser.add_argument('--identities_ordering', type=int, default = 0,
+ help="Which ordering rule to use. (0: Size-based | 1: Length-based | 2: Random).")
+ parser.add_argument('--models_output_path', default='"outputs/models"',
+ help='Output path for checkpoints.')
+ opt = parser.parse_args()
+
+ print(opt)
+ with open(opt.config, 'r') as ymlfile:
+ config = yaml.safe_load(ymlfile)
+
+ # Log errors to file
+ if opt.errors_logs_file is not None:
+ sys.stderr = open(opt.errors_logs_file, "w")
+
+ # Check for integrity
+ if config['model']['num-frames'] != 8 and config['model']['num-frames'] != 16 and config['model']['num-frames'] != 32:
+ raise Exception("Invalid number of frames.")
+
+ # Setup CUDA settings
+ if opt.gpu_id == -1:
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
+ else:
+ device = opt.gpu_id
+
+ torch.backends.cudnn.deterministic = True
+ random.seed(opt.random_state)
+ torch.manual_seed(opt.random_state)
+ torch.cuda.manual_seed(opt.random_state)
+ np.random.seed(opt.random_state)
+
+ # Create useful dirs
+ os.makedirs(opt.logger_name, exist_ok=True)
+ os.makedirs(opt.models_output_path, exist_ok=True)
+
+ # Load required weights for feature extractor
+ if opt.model != 2:
+ if opt.extractor_model == 0: # EfficientNet-B0
+ if opt.extractor_weights.lower() == 'imagenet':
+ features_extractor = EfficientNet.from_pretrained('efficientnet-b0')
+ else:
+ features_extractor = EfficientNet.from_name('efficientnet-b0')
+ features_extractor.load_matching_state_dict(torch.load(opt.extractor_weights, map_location=torch.device('cpu')))
+ print("Custom features extractor weights loaded.")
+ else: # XceptionNet
+ if opt.extractor_weights.lower() == 'pretrained':
+ features_extractor = xception(num_classes=1, pretrain_path="weights/ckpt_iter.pth.tar")
+ else:
+ features_extractor = xception(num_classes=1, pretrain_path=opt.extractor_weights)
+ else:
+ features_extractor = None
+ # Init the required model
+ if opt.model == 0:
+ model = Baseline(config=config)
+ num_patches = None
+ elif opt.model == 1:
+ model = SizeInvariantTimeSformer(config=config)
+ num_patches = config['model']['num-patches']
+ elif opt.model == 2:
+ torch.hub._validate_not_a_forked_repo=lambda a,b,c: True
+ model = torch.hub.load('facebookresearch/pytorchvideo', 'slowfast_r50', pretrained=True)
+ output_layer = torch.nn.Linear(2304 , 1)
+ model.blocks[6].proj = output_layer
+ num_patches = None
+
+
+
+ # Setup the requiring grad layers for features extractor
+ if features_extractor is not None:
+ if opt.freeze_backbone:
+ features_extractor.eval()
+ else:
+ features_extractor.train()
+ if opt.extractor_unfreeze_blocks > -1:
+ for name, param in features_extractor.named_parameters():
+ if "blocks" in name:
+ param_block = int(name.split(".")[1])
+ if param_block >= 16 - opt.extractor_unfreeze_blocks:
+ param.requires_grad = True
+ else:
+ param.requires_grad = False
+ else:
+ param.requires_grad = False
+ else:
+ for name, param in features_extractor.named_parameters():
+ param.requires_grad = True
+
+ # Move models to GPU
+ print(device, torch.cuda.device_count())
+ features_extractor = features_extractor.to(device)
+
+ model = model.to(device)
+ model.train()
+
+ # Init optimizers
+ if opt.freeze_backbone:
+ parameters = model.parameters()
+ else:
+ parameters = chain(features_extractor.parameters(), model.parameters())
+
+ if config['training']['optimizer'].lower() == 'sgd':
+ optimizer = torch.optim.SGD(parameters, lr=config['training']['lr'], weight_decay=config['training']['weight-decay'])
+ elif config['training']['optimizer'].lower() == 'adamw':
+ optimizer = torch.optim.AdamW(parameters, lr=config['training']['lr'], weight_decay=config['training']['weight-decay'])
+ elif config['training']['optimizer'].lower() == 'adam':
+ optimizer = torch.optim.Adam(parameters, lr=config['training']['lr'], weight_decay=config['training']['weight-decay'])
+ else:
+ print("Error: Invalid optimizer specified in the config file.")
+ exit()
+
+
+
+ # Read all the paths and initialize data loaders for train and validation
+ paths = []
+ col_names = ["video", "label", "8_cls"]
+ df_train = pd.read_csv(opt.train_list_file, sep=' ', names=col_names)
+ df_validation = pd.read_csv(opt.validation_list_file, sep=' ', names=col_names)
+
+ df_train = df_train.sample(frac=1, random_state=opt.random_state).reset_index(drop=True)
+ df_validation = df_validation.sample(frac=1, random_state=opt.random_state).reset_index(drop=True)
+
+
+ # Remove the videos without face detection from the list
+ for df in [df_train, df_validation]:
+ indexes_to_drop = []
+ for index, row in df.iterrows():
+ video_path = os.path.join(opt.data_path, row["video"])
+ if not os.path.exists(video_path) or len(os.listdir(video_path)) == 0:
+ indexes_to_drop.append(index)
+ df.drop(df.index[indexes_to_drop], inplace=True)
+
+ # Filter out deepfake methods if requested for ForgeryNet
+ if opt.deepfake_methods is not None and len(opt.deepfake_methods) > 0:
+ opt.deepfake_methods = [int(method) for method in opt.deepfake_methods]
+ for df in [df_train, df_validation]:
+ indexes_to_drop = []
+ for index, row in df.iterrows():
+ if row['8_cls'] not in opt.deepfake_methods:
+ indexes_to_drop.append(index)
+ df.drop(df.index[indexes_to_drop], inplace=True)
+
+ # Split videos and labels and reduce to the required number of videos
+ train_videos = df_train['video'].tolist()
+ train_labels = df_train['label'].tolist()
+
+ validation_videos = df_validation['video'].tolist()
+ validation_labels = df_validation['label'].tolist()
+
+ if opt.max_videos > -1:
+ train_videos = train_videos[:opt.max_videos]
+ train_labels = train_labels[:opt.max_videos]
+ validation_videos = validation_videos[:opt.max_videos]
+ validation_labels = validation_labels[:opt.max_videos]
+
+ train_samples = len(train_videos)
+ validation_samples = len(validation_videos)
+
+ # Print some useful statistics
+ print("Train videos:", train_samples, "Validation videos:", validation_samples)
+ print("__TRAINING STATS__")
+ train_counters = collections.Counter(train_labels)
+ print(train_counters)
+
+ class_weights = train_counters[0] / train_counters[1]
+ print("Weights", class_weights)
+
+ print("__VALIDATION STATS__")
+ val_counters = collections.Counter(validation_labels)
+ print(val_counters)
+ print("___________________")
+
+
+ # Init logger
+ tb_logger = SummaryWriter(log_dir=opt.logger_name, comment='')
+ experiment_path = tb_logger.get_logdir()
+
+ loss_fn = torch.nn.BCEWithLogitsLoss(pos_weight=torch.tensor([class_weights]))
+
+ # Create the data loaders
+ train_dataset = DeepFakesDataset(train_videos, train_labels, augmentation=config['training']['augmentation'], image_size=config['model']['image-size'], data_path=opt.data_path, video_path=opt.video_path, num_frames=config['model']['num-frames'], num_patches=num_patches, max_identities=config['model']['max-identities'], enable_identity_attention=config['model']['enable-identity-attention'], identities_ordering = opt.identities_ordering)
+ train_dl = torch.utils.data.DataLoader(train_dataset, batch_size=config['training']['bs'], shuffle=True, sampler=None,
+ batch_sampler=None, num_workers=opt.workers, collate_fn=None,
+ pin_memory=False, drop_last=False, timeout=0,
+ worker_init_fn=None, prefetch_factor=2,
+ persistent_workers=False)
+
+ validation_dataset = DeepFakesDataset(validation_videos, validation_labels, image_size=config['model']['image-size'], data_path=opt.data_path, video_path=opt.video_path, num_frames=config['model']['num-frames'], num_patches=num_patches, max_identities=config['model']['max-identities'], enable_identity_attention=config['model']['enable-identity-attention'], identities_ordering = opt.identities_ordering, mode='val')
+ val_dl = torch.utils.data.DataLoader(validation_dataset, batch_size=config['training']['val_bs'], shuffle=True, sampler=None,
+ batch_sampler=None, num_workers=opt.workers, collate_fn=None,
+ pin_memory=False, drop_last=False, timeout=0,
+ worker_init_fn=None, prefetch_factor=2,
+ persistent_workers=False)
+
+ # Init LR schedulers
+ if config['training']['scheduler'].lower() == 'steplr':
+ scheduler = lr_scheduler.StepLR(optimizer, step_size=config['training']['step-size'], gamma=config['training']['gamma'])
+ elif config['training']['scheduler'].lower() == 'cosinelr':
+ num_steps = int(opt.num_epochs * len(train_dl))
+ lr_scheduler = CosineLRScheduler(
+ optimizer,
+ t_initial=num_steps,
+ lr_min=config['training']['lr'] * 1e-1,
+ cycle_limit=1,
+ t_in_epochs=False,
+ )
+ else:
+ print("Warning: Invalid scheduler specified in the config file.")
+
+
+ if opt.gpu_id == -1:
+ features_extractor = torch.nn.DataParallel(features_extractor)
+ model = torch.nn.DataParallel(model)
+
+ starting_epoch = 0
+ if os.path.exists(opt.resume):
+ model.load_state_dict(torch.load(opt.resume))
+ if opt.restore_epoch:
+ starting_epoch = int(opt.resume.split("checkpoint")[1].split("_")[0]) + 1 # The checkpoint's file name format should be "checkpoint_EPOCH"
+ else:
+ print("No checkpoint loaded for the model.")
+
+
+
+
+ # Init variables for training
+ not_improved_loss = 0
+ previous_loss = math.inf
+
+ # Training loop
+ for t in range(starting_epoch, opt.num_epochs + 1):
+ model.train()
+ if not_improved_loss == opt.patience:
+ break
+
+ # Init epoch variables
+ counter = 0
+ total_loss = 0
+ total_val_loss = 0
+ train_correct = 0
+ positive = 0
+ negative = 0
+ train_batches = len(train_dl)
+ val_batches = len(val_dl)
+ total_batches = train_batches + val_batches
+
+ # Epoch loop
+ bar = ChargingBar('EPOCH #' + str(t), max=(len(train_dl)+len(val_dl)))
+ for index, (videos, size_embeddings, masks, identities_masks, positions, labels) in enumerate(train_dl):
+ start_time = datetime.now()
+ b, f, h, w, c = videos.shape
+ labels = labels.unsqueeze(1).float()
+ identities_masks = identities_masks.to(device)
+ masks = masks.to(device)
+ positions = positions.to(device)
+
+ if opt.model != 2: # Use the features extractor
+ videos = rearrange(videos, "b f h w c -> (b f) c h w")
+ videos = videos.to(device)
+
+ if opt.freeze_backbone:
+ with torch.no_grad():
+ features = features_extractor(videos)
+ else:
+ features = features_extractor(videos)
+
+ if opt.model == 0: # Baseline
+ y_pred = model(features)
+ y_pred = torch.mean(y_pred.reshape(-1, config["model"]["num-frames"]), axis=1).unsqueeze(1)
+ elif opt.model == 1: # Size-Invariant TimeSformer
+ features = rearrange(features, '(b f) c h w -> b f c h w', b = b, f = f)
+ y_pred = model(features, mask=masks, size_embedding=size_embeddings, identities_mask=identities_masks, positions=positions)
+ else: # SlowFast
+ videos = rearrange(videos, 'b f h w c -> b c f h w')
+ videos = slowfast_input_transform(videos)
+ videos = [torch.cat([v[None, ...].to(device) for v in videos[0]]), torch.cat([v[None, ...].to(device) for v in videos[1]])]
+ y_pred = model(videos)
+
+ # Calculate loss
+ if opt.model != 2:
+ videos = videos.cpu()
+ else:
+ videos = [torch.cat([v[None, ...].cpu() for v in videos[0]]), torch.cat([v[None, ...].cpu() for v in videos[1]])]
+ y_pred = y_pred.cpu()
+ loss = loss_fn(y_pred, labels)
+ corrects, positive_class, negative_class = check_correct(y_pred, labels)
+ train_correct += corrects
+ positive += positive_class
+ negative += negative_class
+ counter += 1
+ total_loss += round(loss.item(), 2)
+
+ optimizer.zero_grad()
+ loss.backward()
+ optimizer.step()
+
+ if config['training']['scheduler'].lower() == 'cosinelr':
+ lr_scheduler.step_update((t * (train_batches) + index))
+
+ # Update time per epoch
+ time_diff = unix_time_millis(datetime.now() - start_time)
+
+ bar.next()
+
+ # Print intermediate metrics
+ if index%100 == 0:
+ expected_time = str(datetime.fromtimestamp((time_diff)*(total_batches-index)/1000).strftime('%H:%M:%S.%f'))
+ print("\nLoss: ", total_loss/counter, "Accuracy: ", train_correct/(counter*config['training']['bs']) ,"Train 0s: ", negative, "Train 1s:", positive, "Expected Time:", expected_time)
+
+
+ # Clean variables before moving into validation
+ #torch.cuda.empty_cache()
+ val_correct = 0
+ val_positive = 0
+ val_negative = 0
+ val_counter = 0
+ train_correct /= train_samples
+ total_loss /= counter
+ model.eval()
+
+ # Epoch validation loop
+ for index, (videos, size_embeddings, masks, identities_masks, positions, labels) in enumerate(val_dl):
+ b, f, _, _, _= videos.shape
+ masks = masks.to(device)
+ positions = positions.to(device)
+ identities_masks = identities_masks.to(device)
+ labels = labels.unsqueeze(1).float()
+
+ # Do not update the gradient during validation
+ with torch.no_grad():
+ if opt.model == 0:
+ videos = videos.to(device)
+ videos = rearrange(videos, 'b f h w c -> (b f) c h w')
+ features = features_extractor(videos)
+ val_pred = model(features)
+ val_pred = torch.mean(val_pred.reshape(-1, config["model"]["num-frames"]), axis=1).unsqueeze(1)
+ elif opt.model == 1:
+ videos = videos.to(device)
+ videos = rearrange(videos, 'b f h w c -> (b f) c h w') # B*8 x 3 x 224 x 224
+ features = features_extractor(videos) # B*8 x 1280 x 7 x 7
+ features = rearrange(features, '(b f) c h w -> b f c h w', b = b, f = f)
+ val_pred = model(features, mask=masks, size_embedding=size_embeddings, identities_mask=identities_masks, positions=positions)
+ elif opt.model == 2:
+ videos = rearrange(videos, 'b f h w c -> b c f h w')
+ videos = slowfast_input_transform(videos)
+ videos = [torch.cat([v[None, ...].to(device) for v in videos[0]]), torch.cat([v[None, ...].to(device) for v in videos[1]])]
+ val_pred = model(videos)
+
+ videos = [torch.cat([v[None, ...].cpu() for v in videos[0]]), torch.cat([v[None, ...].cpu() for v in videos[1]])]
+
+ val_pred = val_pred.cpu()
+ val_loss = loss_fn(val_pred, labels)
+ total_val_loss += round(val_loss.item(), 2)
+ corrects, positive_class, negative_class = check_correct(val_pred, labels)
+ val_correct += corrects
+ val_positive += positive_class
+ val_counter += 1
+ val_negative += negative_class
+ bar.next()
+
+ if config['training']['scheduler'].lower() == 'steplr':
+ scheduler.step()
+
+
+ bar.finish()
+
+ total_val_loss /= val_counter
+ val_correct /= validation_samples
+
+ if previous_loss <= total_val_loss:
+ print("Validation loss did not improved")
+ not_improved_loss += 1
+ else:
+ not_improved_loss = 0
+
+
+ # Save checkpoint if the model's validation loss is improving
+ if previous_loss > total_val_loss:
+ if opt.model != 2:
+ torch.save(features_extractor.state_dict(), os.path.join(opt.models_output_path, "Extractor_checkpoint" + str(t)))
+ torch.save(model.state_dict(), os.path.join(opt.models_output_path, "Model_checkpoint" + str(t)))
+
+ previous_loss = total_val_loss
+ # Log some metrics into Tensorboard
+ tb_logger.add_scalar("Training/Accuracy", train_correct, t)
+ tb_logger.add_scalar("Training/Loss", total_loss, t)
+ tb_logger.add_scalar("Training/Learning_Rate", optimizer.param_groups[0]['lr'], t)
+ tb_logger.add_scalar("Validation/Loss", total_val_loss, t)
+ tb_logger.add_scalar("Validation/Accuracy", val_correct, t)
+
+ # Print epoch metrics
+ print("#" + str(t) + "/" + str(opt.num_epochs) + " loss:" +
+ str(total_loss) + " accuracy:" + str(train_correct) +" val_loss:" + str(total_val_loss) + " val_accuracy:" + str(val_correct) + " val_0s:" + str(val_negative) + "/" + str(val_counters[0]) + " val_1s:" + str(val_positive) + "/" + str(val_counters[1]))
+
+
+
+
diff --git a/clean/video/mintime/train_frame_level.py b/clean/video/mintime/train_frame_level.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/clean/video/mintime/transforms/albu.py b/clean/video/mintime/transforms/albu.py
new file mode 100644
index 0000000000000000000000000000000000000000..7cead378f8f9659a3db0387b9bac4156b13eb445
--- /dev/null
+++ b/clean/video/mintime/transforms/albu.py
@@ -0,0 +1,45 @@
+import random
+
+import cv2
+import numpy as np
+from albumentations import DualTransform, ImageOnlyTransform
+from albumentations.augmentations.functional import crop
+
+# Resize the image isotropically
+def isotropically_resize_image(img, size, interpolation_down=cv2.INTER_AREA, interpolation_up=cv2.INTER_CUBIC):
+ h, w = img.shape[:2]
+
+ if max(w, h) == size:
+ return img
+ if w > h:
+ scale = size / w
+ h = h * scale
+ w = size
+ else:
+ scale = size / h
+ w = w * scale
+ h = size
+ interpolation = interpolation_up if scale > 1 else interpolation_down
+
+ img = img.astype('uint8')
+ resized = cv2.resize(img, (int(w), int(h)), interpolation=interpolation)
+ return resized
+
+
+class IsotropicResize(DualTransform):
+ def __init__(self, max_side, interpolation_down=cv2.INTER_AREA, interpolation_up=cv2.INTER_CUBIC,
+ always_apply=False, p=1):
+ super(IsotropicResize, self).__init__(always_apply, p)
+ self.max_side = max_side
+ self.interpolation_down = interpolation_down
+ self.interpolation_up = interpolation_up
+
+ def apply(self, img, interpolation_down=cv2.INTER_AREA, interpolation_up=cv2.INTER_CUBIC, **params):
+ return isotropically_resize_image(img, size=self.max_side, interpolation_down=interpolation_down,
+ interpolation_up=interpolation_up)
+
+ def apply_to_mask(self, img, **params):
+ return self.apply(img, interpolation_down=cv2.INTER_NEAREST, interpolation_up=cv2.INTER_NEAREST, **params)
+
+ def get_transform_init_args_names(self):
+ return ("max_side", "interpolation_down", "interpolation_up")
diff --git a/clean/video/mintime/utils.py b/clean/video/mintime/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..8f8fbbd2a1d9ad42882e24a0c0b88404f322ba5b
--- /dev/null
+++ b/clean/video/mintime/utils.py
@@ -0,0 +1,186 @@
+# Utility functions for training process
+
+import numpy as np
+import torch
+from matplotlib import pyplot as plt
+from random import random
+from scipy.special import softmax
+from einops import rearrange
+from statistics import mean
+import cv2
+import math
+from typing import Dict
+import json
+import urllib
+from torchvision.transforms import Compose, Lambda
+from torchvision.transforms._transforms_video import (
+ CenterCropVideo,
+ NormalizeVideo,
+)
+from pytorchvideo.data.encoded_video import EncodedVideo
+from pytorchvideo.transforms import (
+ ApplyTransformToKey,
+ ShortSideScale,
+ UniformTemporalSubsample,
+ UniformCropVideo
+)
+
+PLOTS_NAMES = ["space", "time", "combined"]
+
+
+# Convert the preds into final video-level prediction
+def check_correct(preds, labels, multiclass_labels = None, multiclass_errors = None, videos_ids = None):
+ preds = [np.asarray(torch.sigmoid(pred).detach().numpy()).round() for pred in preds]
+
+ correct = 0
+ positive_class = 0
+ negative_class = 0
+ videos_errors = []
+ for i in range(len(labels)):
+ pred = int(preds[i])
+ if labels[i] == pred:
+ correct += 1
+ if labels[i] != pred:
+ if multiclass_labels is not None and not math.isnan(multiclass_labels[i]):
+ multiclass_errors[multiclass_labels[i].item()][0] += 1
+ if videos_ids != None:
+ videos_errors.append(videos_ids[i])
+
+ if pred == 1:
+ positive_class += 1
+ else:
+ negative_class += 1
+
+ if multiclass_errors != None:
+ return correct, positive_class, negative_class, multiclass_errors, videos_errors
+ else:
+ return correct, positive_class, negative_class
+
+
+def unix_time_millis(dt):
+ return dt.total_seconds() * 1000.0
+
+
+def multiple_lists_mean(a):
+ return sum(a) / len(a)
+
+# Aggregate space and time attention
+def aggregate_attentions(attentions, heads, num_frames, frames_per_identity, scale_factor = 50000):
+
+ # Collapse attentions heads for each attention separated
+ aggregated_attentions = []
+ for attention in attentions:
+ attention = attention.squeeze(1)
+ attention = rearrange(attention, '(b h) t -> b h t', h = heads)
+ tokens_means = [torch.max(attention[:, :, i]).item() for i in range(attention.shape[2])]
+ aggregated_attentions.append(tokens_means)
+
+ # Combined space and time attention
+ tokens_means_combined = list(np.sum(np.asarray(aggregated_attentions), axis=0))
+ aggregated_attentions.append(tokens_means_combined)
+
+ # Softmax all the attentions
+ for i in range(len(aggregated_attentions)):
+ aggregated_attentions[i] = np.array_split(np.asarray(aggregated_attentions[i]), num_frames)
+ aggregated_attentions[i] = softmax([mean(values)*scale_factor for values in aggregated_attentions[i]])
+
+ identity_attentions = []
+ for index, identity_frames in enumerate(frames_per_identity):
+ if index == 0:
+ identity_attention = sum(aggregated_attentions[-1][:identity_frames-1])
+ else:
+ previous_identity_frames = frames_per_identity[index-1]
+ identity_attention = sum(aggregated_attentions[-1][previous_identity_frames-1:identity_frames-1])
+ identity_attentions.append(identity_attention)
+
+ return aggregated_attentions, identity_attentions
+
+
+# Visualize the attention
+def save_attention_plots(aggregated_attentions, identity_names, frames_per_identity, num_frames, video_id):
+ colors = np.random.rand(len(frames_per_identity), 4)
+ for index, tokens_means in enumerate(aggregated_attentions):
+ plt.bar([i+1 for i in range(num_frames)], tokens_means)
+ for i in range(len(frames_per_identity)):
+ plt.vlines(frames_per_identity[i], ymin=min(tokens_means), ymax=max(tokens_means), colors=colors[i], label = str(identity_names[i]))
+ plt.legend()
+ plt.savefig("outputs/tokens/" + video_id + "_" + PLOTS_NAMES[index] + ".jpg")
+ plt.clf()
+
+
+def draw_border(img, pt1, pt2, color, thickness, r, d):
+ x1,y1 = pt1
+ x2,y2 = pt2
+
+ # Top left
+ cv2.line(img, (x1 + r, y1), (x1 + r + d, y1), color, thickness)
+ cv2.line(img, (x1, y1 + r), (x1, y1 + r + d), color, thickness)
+ cv2.ellipse(img, (x1 + r, y1 + r), (r, r), 180, 0, 90, color, thickness)
+
+ # Top right
+ cv2.line(img, (x2 - r, y1), (x2 - r - d, y1), color, thickness)
+ cv2.line(img, (x2, y1 + r), (x2, y1 + r + d), color, thickness)
+ cv2.ellipse(img, (x2 - r, y1 + r), (r, r), 270, 0, 90, color, thickness)
+
+ # Bottom left
+ cv2.line(img, (x1 + r, y2), (x1 + r + d, y2), color, thickness)
+ cv2.line(img, (x1, y2 - r), (x1, y2 - r - d), color, thickness)
+ cv2.ellipse(img, (x1 + r, y2 - r), (r, r), 90, 0, 90, color, thickness)
+
+ # Bottom right
+ cv2.line(img, (x2 - r, y2), (x2 - r - d, y2), color, thickness)
+ cv2.line(img, (x2, y2 - r), (x2, y2 - r - d), color, thickness)
+ cv2.ellipse(img, (x2 - r, y2 - r), (r, r), 0, 0, 90, color, thickness)
+ return img
+
+
+
+def count_parameters(model):
+ return sum(p.numel() for p in model.parameters() if p.requires_grad)
+
+
+
+
+SLOWFAST_ALPHA = 4
+
+class PackPathway(torch.nn.Module):
+ """
+ Transform for converting video frames as a list of tensors.
+ """
+ def __init__(self):
+ super().__init__()
+
+ def forward(self, frames: torch.Tensor):
+ fast_pathway = frames
+ # Perform temporal sampling from the fast pathway.
+ slow_pathway = torch.index_select(
+ frames,
+ 1,
+ torch.linspace(
+ 0, frames.shape[1] - 1, frames.shape[1] // SLOWFAST_ALPHA
+ ).long(),
+ )
+ frame_list = [slow_pathway, fast_pathway]
+ return frame_list
+
+def slowfast_input_transform(videos, crop_size = 256, side_size = 256, num_frames = 32, sampling_rate = 2, frames_per_second = 30, mean = [0.45, 0.45, 0.45], std = [0.225, 0.225, 0.225]):
+ transform=Compose(
+ [
+ UniformTemporalSubsample(num_frames),
+ Lambda(lambda x: x/255.0),
+ NormalizeVideo(mean, std),
+ ShortSideScale(
+ size=side_size
+ ),
+ CenterCropVideo(crop_size),
+ PackPathway()
+ ]
+ )
+ transformed_videos = [[],[]]
+ for video in videos:
+ output = transform(video)
+ transformed_videos[0].append(output[0])
+ transformed_videos[1].append(output[1])
+
+
+ return transformed_videos
\ No newline at end of file
diff --git a/clean/video/npr_video/README.md b/clean/video/npr_video/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..bc341d59ee9a81c3b447b1535a3ad23e7090aea6
--- /dev/null
+++ b/clean/video/npr_video/README.md
@@ -0,0 +1,260 @@
+# Rethinking the Up-Sampling Operations in CNN-based Generative Network for Generalizable Deepfake Detection
+
+
+
+ Beijing Jiaotong University, YanShan University, A*Star
+
+
+
+
+Reference github repository for the paper [Rethinking the Up-Sampling Operations in CNN-based Generative Network for Generalizable Deepfake Detection](https://arxiv.org/abs/2312.10461).
+```
+@misc{tan2023rethinking,
+ title={Rethinking the Up-Sampling Operations in CNN-based Generative Network for Generalizable Deepfake Detection},
+ author={Chuangchuang Tan and Huan Liu and Yao Zhao and Shikui Wei and Guanghua Gu and Ping Liu and Yunchao Wei},
+ year={2023},
+ eprint={2312.10461},
+ archivePrefix={arXiv},
+ primaryClass={cs.CV}
+}
+```
+
+## News 🆕
+- `2024/02`: NPR is accepted by CVPR 2024! Congratulations and thanks to my all co-authors!
+- `2024/05`: [🤗Online Demo](https://huggingface.co/spaces/tancc/Generalizable_Deepfake_Detection-NPR-CVPR2024)
+
+
+
+## Environment setup
+**Classification environment:**
+We recommend installing the required packages by running the command:
+```sh
+pip install -r requirements.txt
+```
+In order to ensure the reproducibility of the results, we provide the following suggestions:
+- Docker image: nvcr.io/nvidia/tensorflow:21.02-tf1-py3
+- Conda environment: [./pytorch18/bin/python](https://drive.google.com/file/d/16MK7KnPebBZx5yeN6jqJ49k7VWbEYQPr/view)
+- Random seed during testing period: [Random seed](https://github.com/chuangchuangtan/NPR-DeepfakeDetection/blob/b4e1bfa59ec58542ab5b1e78a3b75b54df67f3b8/test.py#L14)
+
+## Getting the data
+
+| | paper | Url |
+|:----------------------:|:-----:|:-----:|
+| Train set | [CNNDetection CVPR2020](https://github.com/PeterWang512/CNNDetection) | [Baidudrive](https://pan.baidu.com/s/1l-rXoVhoc8xJDl20Cdwy4Q?pwd=ft8b) |
+| Val set | [CNNDetection CVPR2020](https://github.com/PeterWang512/CNNDetection) | [Baidudrive](https://pan.baidu.com/s/1l-rXoVhoc8xJDl20Cdwy4Q?pwd=ft8b) |
+| Table1 Test | [CNNDetection CVPR2020](https://github.com/PeterWang512/CNNDetection) | [Baidudrive](https://pan.baidu.com/s/1l-rXoVhoc8xJDl20Cdwy4Q?pwd=ft8b) |
+| Table2 Test | [FreqNet AAAI2024](https://github.com/chuangchuangtan/FreqNet-DeepfakeDetection) | [googledrive](https://drive.google.com/drive/folders/11E0Knf9J1qlv2UuTnJSOFUjIIi90czSj?usp=sharing) |
+| Table3 Test | [DIRE ICCV2023](https://github.com/ZhendongWang6/DIRE) | [googledrive](https://drive.google.com/drive/folders/1jZE4hg6SxRvKaPYO_yyMeJN_DOcqGMEf?usp=sharing) |
+| Table4 Test | [UniversalFakeDetect CVPR2023](https://github.com/Yuheng-Li/UniversalFakeDetect) | [googledrive](https://drive.google.com/drive/folders/1nkCXClC7kFM01_fqmLrVNtnOYEFPtWO-?usp=sharing)|
+| Table5 Test | Diffusion1kStep | [googledrive](https://drive.google.com/drive/folders/14f0vApTLiukiPvIHukHDzLujrvJpDpRq?usp=sharing) |
+
+```
+pip install gdown==4.7.1
+
+chmod 777 ./download_dataset.sh
+
+./download_dataset.sh
+```
+## Directory structure
+
+ Click to expand the folder tree structure.
+
+```
+datasets
+|-- ForenSynths_train_val
+| |-- train
+| | |-- car
+| | |-- cat
+| | |-- chair
+| | `-- horse
+| `-- val
+| | |-- car
+| | |-- cat
+| | |-- chair
+| | `-- horse
+| |-- test
+| |-- biggan
+| |-- cyclegan
+| |-- deepfake
+| |-- gaugan
+| |-- progan
+| |-- stargan
+| |-- stylegan
+| `-- stylegan2
+`-- Generalization_Test
+ |-- ForenSynths_test # Table1
+ | |-- biggan
+ | |-- cyclegan
+ | |-- deepfake
+ | |-- gaugan
+ | |-- progan
+ | |-- stargan
+ | |-- stylegan
+ | `-- stylegan2
+ |-- GANGen-Detection # Table2
+ | |-- AttGAN
+ | |-- BEGAN
+ | |-- CramerGAN
+ | |-- InfoMaxGAN
+ | |-- MMDGAN
+ | |-- RelGAN
+ | |-- S3GAN
+ | |-- SNGAN
+ | `-- STGAN
+ |-- DiffusionForensics # Table3
+ | |-- adm
+ | |-- ddpm
+ | |-- iddpm
+ | |-- ldm
+ | |-- pndm
+ | |-- sdv1_new
+ | |-- sdv2
+ | `-- vqdiffusion
+ `-- UniversalFakeDetect # Table4
+ | |-- dalle
+ | |-- glide_100_10
+ | |-- glide_100_27
+ | |-- glide_50_27
+ | |-- guided # Also known as ADM.
+ | |-- ldm_100
+ | |-- ldm_200
+ | `-- ldm_200_cfg
+ |-- Diffusion1kStep # Table5
+ |-- DALLE
+ |-- ddpm
+ |-- guided-diffusion # Also known as ADM.
+ |-- improved-diffusion # Also known as IDDPM.
+ `-- midjourney
+
+
+```
+
+
+## Training the model
+```sh
+CUDA_VISIBLE_DEVICES=0 ./pytorch18/bin/python train.py --name 4class-resnet-car-cat-chair-horse --dataroot ./datasets/ForenSynths_train_val --classes car,cat,chair,horse --batch_size 32 --delr_freq 10 --lr 0.0002 --niter 50
+```
+
+## Testing the detector
+Modify the dataroot in test.py.
+```sh
+CUDA_VISIBLE_DEVICES=0 ./pytorch18/bin/python test.py --model_path ./NPR.pth --batch_size {BS}
+```
+
+## Detection Results
+
+### [AIGCDetectBenchmark](https://drive.google.com/drive/folders/1p4ewuAo7d5LbNJ4cKyh10Xl9Fg2yoFOw) using [ProGAN-4class checkpoint](https://github.com/chuangchuangtan/NPR-DeepfakeDetection/blob/main/model_epoch_last_3090.pth)
+
+When testing on AIGCDetectBenchmark, set no_resize and no_crop to True, and set batch_size to 1.
+To deal with images of odd sizes, add the following code in [network/resnet.py](https://github.com/chuangchuangtan/NPR-DeepfakeDetection/blob/e2dbbe673c69c0c7237726e809a725a0308ec43d/networks/resnet.py#L163).
+```
+n,c,w,h = x.shape
+if w%2 == 1 : x = x[:,:,:-1,:]
+if h%2 == 1 : x = x[:,:,:,:-1]
+```
+
+| Generator | CNNSpot | FreDect | Fusing | GramNet | LNP | LGrad | DIRE-G | DIRE-D | UnivFD | RPTCon | NPR |
+| :---------:| :-----: |:-------:| :--------:|:-------:|:-------:|:-------:|:-------:|:------:|:-------:|:-------:|:----:|
+| ProGAN | 100.00 | 99.36 | 100.00 | 99.99 | 99.67 | 99.83 | 95.19 | 52.75 | 99.81 | 100.00 | 99.9 |
+| StyleGan | 90.17 | 78.02 | 85.20 | 87.05 | 91.75 | 91.08 | 83.03 | 51.31 | 84.93 | 92.77 | 96.1 |
+| BigGAN | 71.17 | 81.97 | 77.40 | 67.33 | 77.75 | 85.62 | 70.12 | 49.70 | 95.08 | 95.80 | 87.3 |
+| CycleGAN | 87.62 | 78.77 | 87.00 | 86.07 | 84.10 | 86.94 | 74.19 | 49.58 | 98.33 | 70.17 | 90.3 |
+| StarGAN | 94.60 | 94.62 | 97.00 | 95.05 | 99.92 | 99.27 | 95.47 | 46.72 | 95.75 | 99.97 | 99.6 |
+| GauGAN | 81.42 | 80.57 | 77.00 | 69.35 | 75.39 | 78.46 | 67.79 | 51.23 | 99.47 | 71.58 | 85.4 |
+| Stylegan2 | 86.91 | 66.19 | 83.30 | 87.28 | 94.64 | 85.32 | 75.31 | 51.72 | 74.96 | 89.55 | 98.1 |
+| WFIR | 91.65 | 50.75 | 66.80 | 86.80 | 70.85 | 55.70 | 58.05 | 53.30 | 86.90 | 85.80 | 60.7 |
+| ADM | 60.39 | 63.42 | 49.00 | 58.61 | 84.73 | 67.15 | 75.78 | 98.25 | 66.87 | 82.17 | 84.9 |
+| Glide | 58.07 | 54.13 | 57.20 | 54.50 | 80.52 | 66.11 | 71.75 | 92.42 | 62.46 | 83.79 | 96.7 |
+| Midjourney | 51.39 | 45.87 | 52.20 | 50.02 | 65.55 | 65.35 | 58.01 | 89.45 | 56.13 | 90.12 | 92.6 |
+| SDv1.4 | 50.57 | 38.79 | 51.00 | 51.70 | 85.55 | 63.02 | 49.74 | 91.24 | 63.66 | 95.38 | 97.4 |
+| SDv1.5 | 50.53 | 39.21 | 51.40 | 52.16 | 85.67 | 63.67 | 49.83 | 91.63 | 63.49 | 95.30 | 97.5 |
+| VQDM | 56.46 | 77.80 | 55.10 | 52.86 | 74.46 | 72.99 | 53.68 | 91.90 | 85.31 | 88.91 | 90.1 |
+| Wukong | 51.03 | 40.30 | 51.70 | 50.76 | 82.06 | 59.55 | 54.46 | 90.90 | 70.93 | 91.07 | 91.7 |
+| DALLE2 | 50.45 | 34.70 | 52.80 | 49.25 | 88.75 | 65.45 | 66.48 | 92.45 | 50.75 | 96.60 | 99.6 |
+| Average | 70.78 | 64.03 | 68.38 | 68.67 | 83.84 | 75.34 | 68.68 | 71.53 | 78.43 | 89.31 | **91.7** |
+
+### [GenImage](https://github.com/GenImage-Dataset/GenImage)
+
+
+ (1) Change "resize" to "translate and duplicate". (2) Set random seed to 70. (3) During testing, set no_crop to False.
+
+(1)
+```
+dset = datasets.ImageFolder(
+ root,
+ transforms.Compose([
+ # rz_func,
+ transforms.Lambda(lambda img: translate_duplicate(img, opt.cropSize)),
+ crop_func,
+ flip_func,
+ transforms.ToTensor(),
+ transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
+ ]))
+
+import math
+def translate_duplicate(img, cropSize):
+ if min(img.size) < cropSize:
+ width, height = img.size
+
+ new_width = width * math.ceil(cropSize/width)
+ new_height = height * math.ceil(cropSize/height)
+
+ new_img = Image.new('RGB', (new_width, new_height))
+ for i in range(0, new_width, width):
+ for j in range(0, new_height, height):
+ new_img.paste(img, (i, j))
+ return new_img
+ else:
+ return img
+```
+(2)
+Set [random seed](https://github.com/chuangchuangtan/NPR-DeepfakeDetection/blob/bed4c2c9eb9b2000e9a24233d3b010afa3452f12/train.py#L48) to 70.
+
+(3)
+During testing, set [no_crop](https://github.com/chuangchuangtan/NPR-DeepfakeDetection/blob/bed4c2c9eb9b2000e9a24233d3b010afa3452f12/train.py#L69) to False. And set [test config](https://github.com/chuangchuangtan/NPR-DeepfakeDetection/blob/bed4c2c9eb9b2000e9a24233d3b010afa3452f12/train.py#L30)
+```
+vals = ['ADM', 'biggan', 'glide', 'midjourney', 'sdv5', 'vqdm', 'wukong']
+multiclass = [ 0, 0, 0, 0, 0, 0, 0 ]
+```
+
+
+```
+./pytorch18/bin/python train.py --dataroot {GenImage Path} --name sdv4_bs32_ --batch_size 32 --lr 0.0002 --niter 1 --cropSize 224 --classes sdv4
+```
+
+Train with sdv4 as the training set, using a random seed of 70. [Pretrained checkpoint](https://drive.google.com/drive/folders/1_mD17F94xMbJqEAsWRW1gVsZ5db6YamI?usp=sharing).
+
+|Generator | Acc. | A.P. |
+|:----------:|:----:|:----:|
+| ADM | 87.8 | 96.0 |
+| biggan | 80.7 | 89.8 |
+| glide | 93.2 | 99.1 |
+| midjourney | 91.7 | 97.9 |
+| sdv5 | 94.4 | 99.9 |
+| vqdm | 88.7 | 96.1 |
+| wukong | 94.0 | 99.7 |
+| Mean | 90.1 | 96.9 |
+
+
+
+## Acknowledgments
+
+This repository borrows partially from the [CNNDetection](https://github.com/peterwang512/CNNDetection).
diff --git a/clean/video/npr_video/SOURCE.md b/clean/video/npr_video/SOURCE.md
new file mode 100644
index 0000000000000000000000000000000000000000..9cf94762e3ff97ee2fcada53c4bc7c5cdafcc12d
--- /dev/null
+++ b/clean/video/npr_video/SOURCE.md
@@ -0,0 +1,20 @@
+# Source: video/npr_video
+
+| Field | Value |
+|---|---|
+| Upstream | **UNVERIFIED** -- provenance was lost when this code was vendored |
+| Paper | not recorded |
+| Commit SHA | **not recorded** -- the vendoring step did not preserve it |
+| Mirrored on | 2026-09-15 |
+| Upstream license | no license file present upstream (all rights reserved) |
+
+This is a **mirror**, stripped to the files needed for inference. The full
+untouched snapshot is at `archive/video__npr_video.tar.gz`.
+
+This code is the work of its original authors and is **not** covered by the
+DeepSafe project license. If you are an author and want this removed, open an
+issue on https://github.com/deepsafehq/deepsafe-bench and it will be taken down
+within 48 hours, no questions asked.
+
+**Alias.** This model shares its code with `image/npr`; only the
+weights differ. No separate archive is published.
diff --git a/clean/video/npr_video/download_dataset.sh b/clean/video/npr_video/download_dataset.sh
new file mode 100644
index 0000000000000000000000000000000000000000..41480868d59c8238d821902933209fd36ae0c9ea
--- /dev/null
+++ b/clean/video/npr_video/download_dataset.sh
@@ -0,0 +1,53 @@
+
+pwd=$(cd $(dirname $0); pwd)
+echo pwd: $pwd
+
+# pip install gdown==4.7.1
+
+mkdir dataset
+cd dataset
+
+# --proxy http://ip:port
+
+
+
+# https://github.com/Yuheng-Li/UniversalFakeDetect
+# https://drive.google.com/drive/folders/1nkCXClC7kFM01_fqmLrVNtnOYEFPtWO-
+gdown https://drive.google.com/drive/folders/1nkCXClC7kFM01_fqmLrVNtnOYEFPtWO- -O ./UniversalFakeDetect --folder
+cd ./UniversalFakeDetect
+ls | xargs -I pa sh -c "tar -zxvf pa; rm pa"
+cd $pwd/dataset
+
+# https://github.com/chuangchuangtan/FreqNet-DeepfakeDetection
+# https://drive.google.com/drive/folders/11E0Knf9J1qlv2UuTnJSOFUjIIi90czSj?usp=sharing
+gdown https://drive.google.com/drive/folders/11E0Knf9J1qlv2UuTnJSOFUjIIi90czSj -O ./GANGen-Detection --folder
+
+cd ./GANGen-Detection
+ls | xargs -I pa sh -c "tar -zxvf pa; rm pa"
+cd $pwd/dataset
+
+# https://github.com/ZhendongWang6/DIRE
+# https://drive.google.com/drive/folders/1tKsOU-6FDdstrrKLPYuZ7RpQwtOSHxUD?usp=sharing
+gdown https://drive.google.com/drive/folders/1tKsOU-6FDdstrrKLPYuZ7RpQwtOSHxUD -O ./DiffusionForensics --folder
+
+cd ./DiffusionForensics
+ls | xargs -I pa sh -c "tar -zxvf pa; rm pa"
+cd $pwd/dataset
+
+# https://github.com/Ekko-zn/AIGCDetectBenchmark
+# https://drive.google.com/drive/folders/1BUv1MT1cm90QN3WTMHLEr8PXBsKGxKC9?usp=sharing
+gdown https://drive.google.com/drive/folders/1BUv1MT1cm90QN3WTMHLEr8PXBsKGxKC9 -O ./AIGCDetect_testset --folder
+zip -s- test.zip -O test_full.zip
+unzip test_full.zip -d ./AIGCDetect_testset
+cd $pwd/dataset
+
+gdown https://drive.google.com/drive/folders/14f0vApTLiukiPvIHukHDzLujrvJpDpRq -O ./Diffusion1kStep --folder
+cd ./Diffusion1kStep
+ls | xargs -I pa sh -c "tar -zxvf pa; rm pa"
+cd $pwd/dataset
+
+
+# https://github.com/peterwang512/CNNDetection
+gdown 'https://drive.google.com/u/0/uc?id=1z_fD3UKgWQyOTZIBbYSaQ-hz4AzUrLC1' -O CNN_synth_testset.zip --continue
+tar -zxvf CNN_synth_testset.zip -C ./ForenSynths
+
diff --git a/clean/video/npr_video/networks/__init__.py b/clean/video/npr_video/networks/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/clean/video/npr_video/networks/base_model.py b/clean/video/npr_video/networks/base_model.py
new file mode 100644
index 0000000000000000000000000000000000000000..1e1024d01e417a118ac7047d21a9ffa9f561c82a
--- /dev/null
+++ b/clean/video/npr_video/networks/base_model.py
@@ -0,0 +1,91 @@
+# from pix2pix
+import os
+import torch
+import torch.nn as nn
+from torch.nn import init
+from torch.optim import lr_scheduler
+
+
+class BaseModel(nn.Module):
+ def __init__(self, opt):
+ super(BaseModel, self).__init__()
+ self.opt = opt
+ self.total_steps = 0
+ self.isTrain = opt.isTrain
+ self.lr = opt.lr
+ self.save_dir = os.path.join(opt.checkpoints_dir, opt.name)
+ self.device = torch.device('cuda:{}'.format(opt.gpu_ids[0])) if opt.gpu_ids else torch.device('cpu')
+
+ def save_networks(self, epoch):
+ save_filename = 'model_epoch_%s.pth' % epoch
+ save_path = os.path.join(self.save_dir, save_filename)
+
+ # serialize model and optimizer to dict
+ # state_dict = {
+ # 'model': self.model.state_dict(),
+ # 'optimizer' : self.optimizer.state_dict(),
+ # 'total_steps' : self.total_steps,
+ # }
+
+ torch.save(self.model.state_dict(), save_path)
+ print(f'Saving model {save_path}')
+
+ # load models from the disk
+ def load_networks(self, epoch):
+ load_filename = 'model_epoch_%s.pth' % epoch
+ load_path = os.path.join(self.save_dir, load_filename)
+
+ print('loading the model from %s' % load_path)
+ # if you are using PyTorch newer than 0.4 (e.g., built from
+ # GitHub source), you can remove str() on self.device
+ state_dict = torch.load(load_path, map_location=self.device)
+ if hasattr(state_dict, '_metadata'):
+ del state_dict._metadata
+
+ self.model.load_state_dict(state_dict['model'])
+ self.total_steps = state_dict['total_steps']
+
+ if self.isTrain and not self.opt.new_optim:
+ self.optimizer.load_state_dict(state_dict['optimizer'])
+ ### move optimizer state to GPU
+ for state in self.optimizer.state.values():
+ for k, v in state.items():
+ if torch.is_tensor(v):
+ state[k] = v.to(self.device)
+
+ for g in self.optimizer.param_groups:
+ g['lr'] = self.opt.lr
+
+ def eval(self):
+ self.model.eval()
+
+ def train(self):
+ self.model.train()
+
+ def test(self):
+ with torch.no_grad():
+ self.forward()
+
+
+def init_weights(net, init_type='normal', gain=0.02):
+ def init_func(m):
+ classname = m.__class__.__name__
+ if hasattr(m, 'weight') and (classname.find('Conv') != -1 or classname.find('Linear') != -1):
+ if init_type == 'normal':
+ init.normal_(m.weight.data, 0.0, gain)
+ elif init_type == 'xavier':
+ init.xavier_normal_(m.weight.data, gain=gain)
+ elif init_type == 'kaiming':
+ init.kaiming_normal_(m.weight.data, a=0, mode='fan_in')
+ elif init_type == 'orthogonal':
+ init.orthogonal_(m.weight.data, gain=gain)
+ else:
+ raise NotImplementedError('initialization method [%s] is not implemented' % init_type)
+ if hasattr(m, 'bias') and m.bias is not None:
+ init.constant_(m.bias.data, 0.0)
+ elif classname.find('BatchNorm2d') != -1:
+ init.normal_(m.weight.data, 1.0, gain)
+ init.constant_(m.bias.data, 0.0)
+
+ print('initialize network with %s' % init_type)
+ net.apply(init_func)
diff --git a/clean/video/npr_video/networks/resnet.py b/clean/video/npr_video/networks/resnet.py
new file mode 100644
index 0000000000000000000000000000000000000000..2a5f40ae344bb6e292c89cfb265dbf059829e5b4
--- /dev/null
+++ b/clean/video/npr_video/networks/resnet.py
@@ -0,0 +1,235 @@
+import torch.nn as nn
+import torch.utils.model_zoo as model_zoo
+from torch.nn import functional as F
+from typing import Any, cast, Dict, List, Optional, Union
+import numpy as np
+
+__all__ = ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101',
+ 'resnet152']
+
+
+model_urls = {
+ 'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth',
+ 'resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth',
+ 'resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth',
+ 'resnet101': 'https://download.pytorch.org/models/resnet101-5d3b4d8f.pth',
+ 'resnet152': 'https://download.pytorch.org/models/resnet152-b121ed2d.pth',
+}
+
+
+def conv3x3(in_planes, out_planes, stride=1):
+ """3x3 convolution with padding"""
+ return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,
+ padding=1, bias=False)
+
+
+def conv1x1(in_planes, out_planes, stride=1):
+ """1x1 convolution"""
+ return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False)
+
+
+class BasicBlock(nn.Module):
+ expansion = 1
+
+ def __init__(self, inplanes, planes, stride=1, downsample=None):
+ super(BasicBlock, self).__init__()
+ self.conv1 = conv3x3(inplanes, planes, stride)
+ self.bn1 = nn.BatchNorm2d(planes)
+ self.relu = nn.ReLU(inplace=True)
+ self.conv2 = conv3x3(planes, planes)
+ self.bn2 = nn.BatchNorm2d(planes)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x):
+ identity = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+
+ if self.downsample is not None:
+ identity = self.downsample(x)
+
+ out += identity
+ out = self.relu(out)
+
+ return out
+
+
+class Bottleneck(nn.Module):
+ expansion = 4
+
+ def __init__(self, inplanes, planes, stride=1, downsample=None):
+ super(Bottleneck, self).__init__()
+ self.conv1 = conv1x1(inplanes, planes)
+ self.bn1 = nn.BatchNorm2d(planes)
+ self.conv2 = conv3x3(planes, planes, stride)
+ self.bn2 = nn.BatchNorm2d(planes)
+ self.conv3 = conv1x1(planes, planes * self.expansion)
+ self.bn3 = nn.BatchNorm2d(planes * self.expansion)
+ self.relu = nn.ReLU(inplace=True)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x):
+ identity = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+ out = self.relu(out)
+
+ out = self.conv3(out)
+ out = self.bn3(out)
+
+ if self.downsample is not None:
+ identity = self.downsample(x)
+
+ out += identity
+ out = self.relu(out)
+
+ return out
+
+
+class ResNet(nn.Module):
+
+ def __init__(self, block, layers, num_classes=1, zero_init_residual=False):
+ super(ResNet, self).__init__()
+
+ self.unfoldSize = 2
+ self.unfoldIndex = 0
+ assert self.unfoldSize > 1
+ assert -1 < self.unfoldIndex and self.unfoldIndex < self.unfoldSize*self.unfoldSize
+ self.inplanes = 64
+ self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=2, padding=1, bias=False)
+ self.bn1 = nn.BatchNorm2d(64)
+ self.relu = nn.ReLU(inplace=True)
+ self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
+ self.layer1 = self._make_layer(block, 64 , layers[0])
+ self.layer2 = self._make_layer(block, 128, layers[1], stride=2)
+ self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
+ # self.fc1 = nn.Linear(512 * block.expansion, 1)
+ self.fc1 = nn.Linear(512, num_classes)
+
+ for m in self.modules():
+ if isinstance(m, nn.Conv2d):
+ nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
+ elif isinstance(m, nn.BatchNorm2d):
+ nn.init.constant_(m.weight, 1)
+ nn.init.constant_(m.bias, 0)
+
+ # Zero-initialize the last BN in each residual branch,
+ # so that the residual branch starts with zeros, and each residual block behaves like an identity.
+ # This improves the model by 0.2~0.3% according to https://arxiv.org/abs/1706.02677
+ if zero_init_residual:
+ for m in self.modules():
+ if isinstance(m, Bottleneck):
+ nn.init.constant_(m.bn3.weight, 0)
+ elif isinstance(m, BasicBlock):
+ nn.init.constant_(m.bn2.weight, 0)
+
+ def _make_layer(self, block, planes, blocks, stride=1):
+ downsample = None
+ if stride != 1 or self.inplanes != planes * block.expansion:
+ downsample = nn.Sequential(
+ conv1x1(self.inplanes, planes * block.expansion, stride),
+ nn.BatchNorm2d(planes * block.expansion),
+ )
+
+ layers = []
+ layers.append(block(self.inplanes, planes, stride, downsample))
+ self.inplanes = planes * block.expansion
+ for _ in range(1, blocks):
+ layers.append(block(self.inplanes, planes))
+
+ return nn.Sequential(*layers)
+ def interpolate(self, img, factor):
+ return F.interpolate(F.interpolate(img, scale_factor=factor, mode='nearest', recompute_scale_factor=True), scale_factor=1/factor, mode='nearest', recompute_scale_factor=True)
+ def forward(self, x):
+ # n,c,w,h = x.shape
+ # if -1*w%2 != 0: x = x[:,:,:w%2*-1,: ]
+ # if -1*h%2 != 0: x = x[:,:,: ,:h%2*-1]
+ # factor = 0.5
+ # x_half = F.interpolate(x, scale_factor=factor, mode='nearest', recompute_scale_factor=True)
+ # x_re = F.interpolate(x_half, scale_factor=1/factor, mode='nearest', recompute_scale_factor=True)
+ # NPR = x - x_re
+ # n,c,w,h = x.shape
+ # if w%2 == 1 : x = x[:,:,:-1,:]
+ # if h%2 == 1 : x = x[:,:,:,:-1]
+ NPR = x - self.interpolate(x, 0.5)
+
+ x = self.conv1(NPR*2.0/3.0)
+ x = self.bn1(x)
+ x = self.relu(x)
+ x = self.maxpool(x)
+
+ x = self.layer1(x)
+ x = self.layer2(x)
+
+ x = self.avgpool(x)
+ x = x.view(x.size(0), -1)
+ x = self.fc1(x)
+
+ return x
+
+
+def resnet18(pretrained=False, **kwargs):
+ """Constructs a ResNet-18 model.
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ """
+ model = ResNet(BasicBlock, [2, 2, 2, 2], **kwargs)
+ if pretrained:
+ model.load_state_dict(model_zoo.load_url(model_urls['resnet18']))
+ return model
+
+
+def resnet34(pretrained=False, **kwargs):
+ """Constructs a ResNet-34 model.
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ """
+ model = ResNet(BasicBlock, [3, 4, 6, 3], **kwargs)
+ if pretrained:
+ model.load_state_dict(model_zoo.load_url(model_urls['resnet34']))
+ return model
+
+
+def resnet50(pretrained=False, **kwargs):
+ """Constructs a ResNet-50 model.
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ """
+ model = ResNet(Bottleneck, [3, 4, 6, 3], **kwargs)
+ if pretrained:
+ model.load_state_dict(model_zoo.load_url(model_urls['resnet50']))
+ return model
+
+
+def resnet101(pretrained=False, **kwargs):
+ """Constructs a ResNet-101 model.
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ """
+ model = ResNet(Bottleneck, [3, 4, 23, 3], **kwargs)
+ if pretrained:
+ model.load_state_dict(model_zoo.load_url(model_urls['resnet101']))
+ return model
+
+
+def resnet152(pretrained=False, **kwargs):
+ """Constructs a ResNet-152 model.
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ """
+ model = ResNet(Bottleneck, [3, 8, 36, 3], **kwargs)
+ if pretrained:
+ model.load_state_dict(model_zoo.load_url(model_urls['resnet152']))
+ return model
diff --git a/clean/video/npr_video/networks/trainer.py b/clean/video/npr_video/networks/trainer.py
new file mode 100644
index 0000000000000000000000000000000000000000..217006e9e9b02b558bffa04600ab446c28d0e93e
--- /dev/null
+++ b/clean/video/npr_video/networks/trainer.py
@@ -0,0 +1,66 @@
+import functools
+import torch
+import torch.nn as nn
+from networks.resnet import resnet50
+from networks.base_model import BaseModel, init_weights
+
+
+class Trainer(BaseModel):
+ def name(self):
+ return 'Trainer'
+
+ def __init__(self, opt):
+ super(Trainer, self).__init__(opt)
+
+ if self.isTrain and not opt.continue_train:
+ self.model = resnet50(pretrained=False, num_classes=1)
+
+ if not self.isTrain or opt.continue_train:
+ self.model = resnet50(num_classes=1)
+
+ if self.isTrain:
+ self.loss_fn = nn.BCEWithLogitsLoss()
+ # initialize optimizers
+ if opt.optim == 'adam':
+ self.optimizer = torch.optim.Adam(filter(lambda p: p.requires_grad, self.model.parameters()),
+ lr=opt.lr, betas=(opt.beta1, 0.999))
+ elif opt.optim == 'sgd':
+ self.optimizer = torch.optim.SGD(filter(lambda p: p.requires_grad, self.model.parameters()),
+ lr=opt.lr, momentum=0.0, weight_decay=0)
+ else:
+ raise ValueError("optim should be [adam, sgd]")
+
+ if not self.isTrain or opt.continue_train:
+ self.load_networks(opt.epoch)
+ self.model.to(opt.gpu_ids[0])
+
+
+ def adjust_learning_rate(self, min_lr=1e-6):
+ for param_group in self.optimizer.param_groups:
+ param_group['lr'] *= 0.9
+ if param_group['lr'] < min_lr:
+ return False
+ self.lr = param_group['lr']
+ print('*'*25)
+ print(f'Changing lr from {param_group["lr"]/0.9} to {param_group["lr"]}')
+ print('*'*25)
+ return True
+
+ def set_input(self, input):
+ self.input = input[0].to(self.device)
+ self.label = input[1].to(self.device).float()
+
+
+ def forward(self):
+ self.output = self.model(self.input)
+
+ def get_loss(self):
+ return self.loss_fn(self.output.squeeze(1), self.label)
+
+ def optimize_parameters(self):
+ self.forward()
+ self.loss = self.loss_fn(self.output.squeeze(1), self.label)
+ self.optimizer.zero_grad()
+ self.loss.backward()
+ self.optimizer.step()
+
diff --git a/clean/video/npr_video/options/__init__.py b/clean/video/npr_video/options/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/clean/video/npr_video/options/base_options.py b/clean/video/npr_video/options/base_options.py
new file mode 100644
index 0000000000000000000000000000000000000000..1f67932869cb1e76049b9dbdee7ec606c3b541cc
--- /dev/null
+++ b/clean/video/npr_video/options/base_options.py
@@ -0,0 +1,118 @@
+import argparse
+import os
+import time
+import util
+import torch
+#import models
+#import data
+
+
+class BaseOptions():
+ def __init__(self):
+ self.initialized = False
+
+ def initialize(self, parser):
+ parser.add_argument('--mode', default='binary')
+ parser.add_argument('--arch', type=str, default='res50', help='architecture for binary classification')
+
+ # data augmentation
+ parser.add_argument('--rz_interp', default='bilinear')
+ parser.add_argument('--blur_prob', type=float, default=0)
+ parser.add_argument('--blur_sig', default='0.5')
+ parser.add_argument('--jpg_prob', type=float, default=0)
+ parser.add_argument('--jpg_method', default='cv2')
+ parser.add_argument('--jpg_qual', default='75')
+
+ parser.add_argument('--dataroot', default='./dataset/', help='path to images (should have subfolders trainA, trainB, valA, valB, etc)')
+ parser.add_argument('--classes', default='', help='image classes to train on')
+ parser.add_argument('--class_bal', action='store_true')
+ parser.add_argument('--batch_size', type=int, default=64, help='input batch size')
+ parser.add_argument('--loadSize', type=int, default=256, help='scale images to this size')
+ parser.add_argument('--cropSize', type=int, default=224, help='then crop to this size')
+ parser.add_argument('--gpu_ids', type=str, default='0', help='gpu ids: e.g. 0 0,1,2, 0,2. use -1 for CPU')
+ parser.add_argument('--name', type=str, default='experiment_name', help='name of the experiment. It decides where to store samples and models')
+ parser.add_argument('--epoch', type=str, default='latest', help='which epoch to load? set to latest to use latest cached model')
+ parser.add_argument('--num_threads', default=8, type=int, help='# threads for loading data')
+ parser.add_argument('--checkpoints_dir', type=str, default='./checkpoints', help='models are saved here')
+ parser.add_argument('--serial_batches', action='store_true', help='if true, takes images in order to make batches, otherwise takes them randomly')
+ parser.add_argument('--resize_or_crop', type=str, default='scale_and_crop', help='scaling and cropping of images at load time [resize_and_crop|crop|scale_width|scale_width_and_crop|none]')
+ parser.add_argument('--no_flip', action='store_true', help='if specified, do not flip the images for data augmentation')
+ parser.add_argument('--init_type', type=str, default='normal', help='network initialization [normal|xavier|kaiming|orthogonal]')
+ parser.add_argument('--init_gain', type=float, default=0.02, help='scaling factor for normal, xavier and orthogonal.')
+ parser.add_argument('--suffix', default='', type=str, help='customized suffix: opt.name = opt.name + suffix: e.g., {model}_{netG}_size{loadSize}')
+ parser.add_argument('--delr_freq', type=int, default=20, help='frequency of changing lr')
+
+
+ self.initialized = True
+ return parser
+
+ def gather_options(self):
+ # initialize parser with basic options
+ if not self.initialized:
+ parser = argparse.ArgumentParser(
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+ parser = self.initialize(parser)
+
+ # get the basic options
+ opt, _ = parser.parse_known_args()
+ self.parser = parser
+
+ return opt #parser.parse_args()
+
+ def print_options(self, opt):
+ message = ''
+ message += '----------------- Options ---------------\n'
+ for k, v in sorted(vars(opt).items()):
+ comment = ''
+ default = self.parser.get_default(k)
+ if v != default:
+ comment = '\t[default: %s]' % str(default)
+ message += '{:>25}: {:<30}{}\n'.format(str(k), str(v), comment)
+ message += '----------------- End -------------------'
+ print(message)
+
+ # save to the disk
+
+ expr_dir = os.path.join(opt.checkpoints_dir, opt.name)
+ util.mkdirs(expr_dir)
+ file_name = os.path.join(expr_dir, 'opt.txt')
+ with open(file_name, 'wt') as opt_file:
+ opt_file.write(message)
+ opt_file.write('\n')
+
+ def parse(self, print_options=True):
+
+ opt = self.gather_options()
+ opt.isTrain = self.isTrain # train or test
+ opt.name = opt.name + time.strftime("%Y_%m_%d_%H_%M_%S", time.localtime())
+ # process opt.suffix
+ if opt.suffix:
+ suffix = ('_' + opt.suffix.format(**vars(opt))) if opt.suffix != '' else ''
+ opt.name = opt.name + suffix
+
+ if print_options:
+ self.print_options(opt)
+
+ # set gpu ids
+ str_ids = opt.gpu_ids.split(',')
+ opt.gpu_ids = []
+ for str_id in str_ids:
+ id = int(str_id)
+ if id >= 0:
+ opt.gpu_ids.append(id)
+ if len(opt.gpu_ids) > 0:
+ torch.cuda.set_device(opt.gpu_ids[0])
+
+ # additional
+ opt.classes = opt.classes.split(',')
+ opt.rz_interp = opt.rz_interp.split(',')
+ opt.blur_sig = [float(s) for s in opt.blur_sig.split(',')]
+ opt.jpg_method = opt.jpg_method.split(',')
+ opt.jpg_qual = [int(s) for s in opt.jpg_qual.split(',')]
+ if len(opt.jpg_qual) == 2:
+ opt.jpg_qual = list(range(opt.jpg_qual[0], opt.jpg_qual[1] + 1))
+ elif len(opt.jpg_qual) > 2:
+ raise ValueError("Shouldn't have more than 2 values for --jpg_qual.")
+
+ self.opt = opt
+ return self.opt
diff --git a/clean/video/npr_video/options/test_options.py b/clean/video/npr_video/options/test_options.py
new file mode 100644
index 0000000000000000000000000000000000000000..1dba350e3cadf758c2dc39e99a55b4e844e7b16d
--- /dev/null
+++ b/clean/video/npr_video/options/test_options.py
@@ -0,0 +1,17 @@
+from .base_options import BaseOptions
+
+
+class TestOptions(BaseOptions):
+ def initialize(self, parser):
+ parser = BaseOptions.initialize(self, parser)
+ # parser.add_argument('--dataroot')
+ parser.add_argument('--model_path')
+ parser.add_argument('--no_resize', action='store_true')
+ parser.add_argument('--no_crop', action='store_true')
+ parser.add_argument('--eval', action='store_true', help='use eval mode during test time.')
+ parser.add_argument('--earlystop_epoch', type=int, default=15)
+ parser.add_argument('--lr', type=float, default=0.00002, help='initial learning rate for adam')
+ parser.add_argument('--niter', type=int, default=0, help='# of iter at starting learning rate')
+
+ self.isTrain = False
+ return parser
diff --git a/clean/video/npr_video/options/train_options.py b/clean/video/npr_video/options/train_options.py
new file mode 100644
index 0000000000000000000000000000000000000000..c0eeb5f8e71e910358b42a33a0f86a11edccc31c
--- /dev/null
+++ b/clean/video/npr_video/options/train_options.py
@@ -0,0 +1,26 @@
+from .base_options import BaseOptions
+
+
+class TrainOptions(BaseOptions):
+ def initialize(self, parser):
+ parser = BaseOptions.initialize(self, parser)
+ parser.add_argument('--earlystop_epoch', type=int, default=15)
+ parser.add_argument('--data_aug', action='store_true', help='if specified, perform additional data augmentation (photometric, blurring, jpegging)')
+ parser.add_argument('--optim', type=str, default='adam', help='optim to use [sgd, adam]')
+ parser.add_argument('--new_optim', action='store_true', help='new optimizer instead of loading the optim state')
+ parser.add_argument('--loss_freq', type=int, default=400, help='frequency of showing loss on tensorboard')
+ parser.add_argument('--save_latest_freq', type=int, default=2000, help='frequency of saving the latest results')
+ parser.add_argument('--save_epoch_freq', type=int, default=20, help='frequency of saving checkpoints at the end of epochs')
+ parser.add_argument('--continue_train', action='store_true', help='continue training: load the latest model')
+ parser.add_argument('--epoch_count', type=int, default=1, help='the starting epoch count, we save the model by , +, ...')
+ parser.add_argument('--last_epoch', type=int, default=-1, help='starting epoch count for scheduler intialization')
+ parser.add_argument('--train_split', type=str, default='train', help='train, val, test, etc')
+ parser.add_argument('--val_split', type=str, default='val', help='train, val, test, etc')
+ parser.add_argument('--niter', type=int, default=1000, help='# of iter at starting learning rate')
+ parser.add_argument('--beta1', type=float, default=0.9, help='momentum term of adam')
+ parser.add_argument('--lr', type=float, default=0.0001, help='initial learning rate for adam')
+ # parser.add_argument('--model_path')
+ # parser.add_argument('--no_resize', action='store_true')
+ # parser.add_argument('--no_crop', action='store_true')
+ self.isTrain = True
+ return parser
diff --git a/clean/video/npr_video/requirements.txt b/clean/video/npr_video/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..5229c276fd6097939ede4e2f015a95352cb177ec
--- /dev/null
+++ b/clean/video/npr_video/requirements.txt
@@ -0,0 +1,7 @@
+scipy
+scikit-learn
+numpy
+opencv_python
+Pillow
+torch>=1.2.0
+torchvision
diff --git a/clean/video/npr_video/test.py b/clean/video/npr_video/test.py
new file mode 100644
index 0000000000000000000000000000000000000000..07966fbe294b93c0eb1f09b4bc119a05c4275817
--- /dev/null
+++ b/clean/video/npr_video/test.py
@@ -0,0 +1,73 @@
+import sys
+import time
+import os
+import csv
+import torch
+from util import Logger, printSet
+from validate import validate
+from networks.resnet import resnet50
+from options.test_options import TestOptions
+import networks.resnet as resnet
+import numpy as np
+import random
+import random
+def seed_torch(seed=1029):
+ random.seed(seed)
+ os.environ['PYTHONHASHSEED'] = str(seed)
+ np.random.seed(seed)
+ torch.manual_seed(seed)
+ torch.cuda.manual_seed(seed)
+ torch.cuda.manual_seed_all(seed) # if you are using multi-GPU.
+ torch.backends.cudnn.benchmark = False
+ torch.backends.cudnn.deterministic = True
+ torch.backends.cudnn.enabled = False
+seed_torch(100)
+DetectionTests = {
+ 'ForenSynths': { 'dataroot' : '/opt/data/private/DeepfakeDetection/ForenSynths/',
+ 'no_resize' : False, # Due to the different shapes of images in the dataset, resizing is required during batch detection.
+ 'no_crop' : True,
+ },
+
+ 'GANGen-Detection': { 'dataroot' : '/opt/data/private/DeepfakeDetection/GANGen-Detection/',
+ 'no_resize' : True,
+ 'no_crop' : True,
+ },
+
+ 'DiffusionForensics': { 'dataroot' : '/opt/data/private/DeepfakeDetection/DiffusionForensics/',
+ 'no_resize' : False, # Due to the different shapes of images in the dataset, resizing is required during batch detection.
+ 'no_crop' : True,
+ },
+
+ 'UniversalFakeDetect': { 'dataroot' : '/opt/data/private/DeepfakeDetection/UniversalFakeDetect/',
+ 'no_resize' : False, # Due to the different shapes of images in the dataset, resizing is required during batch detection.
+ 'no_crop' : True,
+ },
+
+ }
+
+
+opt = TestOptions().parse(print_options=False)
+print(f'Model_path {opt.model_path}')
+
+# get model
+model = resnet50(num_classes=1)
+model.load_state_dict(torch.load(opt.model_path, map_location='cpu'), strict=True)
+model.cuda()
+model.eval()
+
+for testSet in DetectionTests.keys():
+ dataroot = DetectionTests[testSet]['dataroot']
+ printSet(testSet)
+
+ accs = [];aps = []
+ print(time.strftime("%Y_%m_%d_%H_%M_%S", time.localtime()))
+ for v_id, val in enumerate(os.listdir(dataroot)):
+ opt.dataroot = '{}/{}'.format(dataroot, val)
+ opt.classes = '' #os.listdir(opt.dataroot) if multiclass[v_id] else ['']
+ opt.no_resize = DetectionTests[testSet]['no_resize']
+ opt.no_crop = DetectionTests[testSet]['no_crop']
+ acc, ap, _, _, _, _ = validate(model, opt)
+ accs.append(acc);aps.append(ap)
+ print("({} {:12}) acc: {:.1f}; ap: {:.1f}".format(v_id, val, acc*100, ap*100))
+ print("({} {:10}) acc: {:.1f}; ap: {:.1f}".format(v_id+1,'Mean', np.array(accs).mean()*100, np.array(aps).mean()*100));print('*'*25)
+
diff --git a/clean/video/npr_video/train.py b/clean/video/npr_video/train.py
new file mode 100644
index 0000000000000000000000000000000000000000..48d5a3183e65cf6d0ee6a6b91c717bef4e7c47b4
--- /dev/null
+++ b/clean/video/npr_video/train.py
@@ -0,0 +1,111 @@
+import os
+import sys
+import time
+import torch
+import torch.nn
+import argparse
+from PIL import Image
+from tensorboardX import SummaryWriter
+import numpy as np
+from validate import validate
+from data import create_dataloader
+from networks.trainer import Trainer
+from options.train_options import TrainOptions
+from options.test_options import TestOptions
+from util import Logger
+
+import random
+def seed_torch(seed=1029):
+ random.seed(seed)
+ os.environ['PYTHONHASHSEED'] = str(seed)
+ np.random.seed(seed)
+ torch.manual_seed(seed)
+ torch.cuda.manual_seed(seed)
+ torch.cuda.manual_seed_all(seed) # if you are using multi-GPU.
+ torch.backends.cudnn.benchmark = False
+ torch.backends.cudnn.deterministic = True
+ torch.backends.cudnn.enabled = False
+
+
+# test config
+vals = ['progan', 'stylegan', 'stylegan2', 'biggan', 'cyclegan', 'stargan', 'gaugan', 'deepfake']
+multiclass = [1, 1, 1, 0, 1, 0, 0, 0]
+
+
+def get_val_opt():
+ val_opt = TrainOptions().parse(print_options=False)
+ val_opt.dataroot = '{}/{}/'.format(val_opt.dataroot, val_opt.val_split)
+ val_opt.isTrain = False
+ val_opt.no_resize = False
+ val_opt.no_crop = False
+ val_opt.serial_batches = True
+
+ return val_opt
+
+
+if __name__ == '__main__':
+ opt = TrainOptions().parse()
+ seed_torch(100)
+ Testdataroot = os.path.join(opt.dataroot, 'test')
+ opt.dataroot = '{}/{}/'.format(opt.dataroot, opt.train_split)
+ Logger(os.path.join(opt.checkpoints_dir, opt.name, 'log.log'))
+ print(' '.join(list(sys.argv)) )
+ val_opt = get_val_opt()
+ Testopt = TestOptions().parse(print_options=False)
+ data_loader = create_dataloader(opt)
+
+ train_writer = SummaryWriter(os.path.join(opt.checkpoints_dir, opt.name, "train"))
+ val_writer = SummaryWriter(os.path.join(opt.checkpoints_dir, opt.name, "val"))
+
+ model = Trainer(opt)
+
+ def testmodel():
+ print('*'*25);accs = [];aps = []
+ print(time.strftime("%Y_%m_%d_%H_%M_%S", time.localtime()))
+ for v_id, val in enumerate(vals):
+ Testopt.dataroot = '{}/{}'.format(Testdataroot, val)
+ Testopt.classes = os.listdir(Testopt.dataroot) if multiclass[v_id] else ['']
+ Testopt.no_resize = False
+ Testopt.no_crop = True
+ acc, ap, _, _, _, _ = validate(model.model, Testopt)
+ accs.append(acc);aps.append(ap)
+ print("({} {:10}) acc: {:.1f}; ap: {:.1f}".format(v_id, val, acc*100, ap*100))
+ print("({} {:10}) acc: {:.1f}; ap: {:.1f}".format(v_id+1,'Mean', np.array(accs).mean()*100, np.array(aps).mean()*100));print('*'*25)
+ print(time.strftime("%Y_%m_%d_%H_%M_%S", time.localtime()))
+ model.eval();testmodel();
+ model.train()
+ print(f'cwd: {os.getcwd()}')
+ for epoch in range(opt.niter):
+ epoch_start_time = time.time()
+ iter_data_time = time.time()
+ epoch_iter = 0
+
+ for i, data in enumerate(data_loader):
+ model.total_steps += 1
+ epoch_iter += opt.batch_size
+
+ model.set_input(data)
+ model.optimize_parameters()
+
+ if model.total_steps % opt.loss_freq == 0:
+ print(time.strftime("%Y_%m_%d_%H_%M_%S", time.localtime()), "Train loss: {} at step: {} lr {}".format(model.loss, model.total_steps, model.lr))
+ train_writer.add_scalar('loss', model.loss, model.total_steps)
+
+ if epoch % opt.delr_freq == 0 and epoch != 0:
+ print(time.strftime("%Y_%m_%d_%H_%M_%S", time.localtime()), 'changing lr at the end of epoch %d, iters %d' %
+ (epoch, model.total_steps))
+ model.adjust_learning_rate()
+
+
+ # Validation
+ model.eval()
+ acc, ap = validate(model.model, val_opt)[:2]
+ val_writer.add_scalar('accuracy', acc, model.total_steps)
+ val_writer.add_scalar('ap', ap, model.total_steps)
+ print("(Val @ epoch {}) acc: {}; ap: {}".format(epoch, acc, ap))
+ testmodel()
+ model.train()
+
+ model.eval();testmodel()
+ model.save_networks('last')
+
diff --git a/clean/video/npr_video/util.py b/clean/video/npr_video/util.py
new file mode 100644
index 0000000000000000000000000000000000000000..a41c60c8e33f942fe6cf8f09d57b0d538acb378b
--- /dev/null
+++ b/clean/video/npr_video/util.py
@@ -0,0 +1,48 @@
+import sys
+import os
+import torch
+
+
+def mkdirs(paths):
+ if isinstance(paths, list) and not isinstance(paths, str):
+ for path in paths:
+ mkdir(path)
+ else:
+ mkdir(paths)
+
+
+def mkdir(path):
+ if not os.path.exists(path):
+ os.makedirs(path)
+
+
+def unnormalize(tens, mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]):
+ # assume tensor of shape NxCxHxW
+ return tens * torch.Tensor(std)[None, :, None, None] + torch.Tensor(
+ mean)[None, :, None, None]
+
+
+
+
+class Logger(object):
+ """Log stdout messages."""
+
+ def __init__(self, outfile):
+ self.terminal = sys.stdout
+ self.log = open(outfile, "a")
+ sys.stdout = self
+
+ def write(self, message):
+ self.terminal.write(message)
+ self.log.write(message)
+
+ def flush(self):
+ self.terminal.flush()
+
+
+def printSet(set_str):
+ set_str = str(set_str)
+ num = len(set_str)
+ print("="*num*3)
+ print(" "*num + set_str)
+ print("="*num*3)
\ No newline at end of file
diff --git a/clean/video/npr_video/validate.py b/clean/video/npr_video/validate.py
new file mode 100644
index 0000000000000000000000000000000000000000..1f55e0fc6bd2d49cfada6b69d3f0fa354fe667f7
--- /dev/null
+++ b/clean/video/npr_video/validate.py
@@ -0,0 +1,42 @@
+import torch
+import numpy as np
+from networks.resnet import resnet50
+from sklearn.metrics import average_precision_score, precision_recall_curve, accuracy_score
+from options.test_options import TestOptions
+from data import create_dataloader
+
+
+def validate(model, opt):
+ data_loader = create_dataloader(opt)
+
+ with torch.no_grad():
+ y_true, y_pred = [], []
+ for img, label in data_loader:
+ in_tens = img.cuda()
+ y_pred.extend(model(in_tens).sigmoid().flatten().tolist())
+ y_true.extend(label.flatten().tolist())
+
+ y_true, y_pred = np.array(y_true), np.array(y_pred)
+ r_acc = accuracy_score(y_true[y_true==0], y_pred[y_true==0] > 0.5)
+ f_acc = accuracy_score(y_true[y_true==1], y_pred[y_true==1] > 0.5)
+ acc = accuracy_score(y_true, y_pred > 0.5)
+ ap = average_precision_score(y_true, y_pred)
+ return acc, ap, r_acc, f_acc, y_true, y_pred
+
+
+if __name__ == '__main__':
+ opt = TestOptions().parse(print_options=False)
+
+ model = resnet50(num_classes=1)
+ state_dict = torch.load(opt.model_path, map_location='cpu')
+ model.load_state_dict(state_dict['model'])
+ model.cuda()
+ model.eval()
+
+ acc, avg_precision, r_acc, f_acc, y_true, y_pred = validate(model, opt)
+
+ print("accuracy:", acc)
+ print("average precision:", avg_precision)
+
+ print("accuracy of real images:", r_acc)
+ print("accuracy of fake images:", f_acc)
diff --git a/clean/video/pwtf_dvd/LICENSE b/clean/video/pwtf_dvd/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..d6e183fe62fc2fd2e59b33c5ca8011f2d7b3d460
--- /dev/null
+++ b/clean/video/pwtf_dvd/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2025 TAEHOON KIM
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/clean/video/pwtf_dvd/README.md b/clean/video/pwtf_dvd/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..a31015e0dbe83425515c8a47825075f33c868bd2
--- /dev/null
+++ b/clean/video/pwtf_dvd/README.md
@@ -0,0 +1,56 @@
+# [ICCV 2025] Beyond Spatial Frequency: Pixel-wise Temporal Frequency-based Deepfake Video Detection
+This repository contains the official implementation of our ICCV 2025 paper,
+"Beyond Spatial Frequency: Pixel-wise Temporal Frequency-based Deepfake Video Detection."
+ [arxiv](https://arxiv.org/abs/2507.02398) [page](https://rama0126.github.io/PwTF-DVD/)
+
+
+
+
+
+# Abstract
+
+
+We introduce a deepfake video detection approach that exploits pixel-wise temporal inconsistencies, which traditional spatial frequency-based detectors often overlook. Traditional detectors represent temporal information merely by stacking spatial frequency spectra across frames, resulting in the failure to detect temporal artifacts in the pixel plane. Our approach performs a 1D Fourier transform on the time axis for each pixel, extracting features highly sensitive to temporal inconsistencies, especially in areas prone to unnatural movements. To precisely locate regions containing the temporal artifacts, we introduce an attention proposal module trained in an end-to-end manner. Additionally, our joint transformer module effectively integrates pixel-wise temporal frequency features with spatio-temporal context features, expanding the range of detectable forgery artifacts. Our framework represents a significant advancement in deepfake video detection, providing robust performance across diverse and challenging detection scenarios.
+
+## Environment Setting
+### System Setting
+```
+apt-get update
+
+apt-get -y install libgl1-mesa-glx &&
+apt-get -y install libglib2.0-0
+
+apt-get install -y libsm6 &&
+apt-get -y install libxext6 &&
+apt-get -y install libxrender-dev
+
+apt-get install -y libx11-6
+```
+### Python Dependencies
+```
+pip install opencv-python sympy timm simplejson fvcore
+pip install torchmetrics pytorch-losses
+```
+
+## Updates
+
+- inference: `./inference/test_on_raw_video.py --video [video_path] --out_dir [output_path] --model_path [model_path]`
+- model weights: [Google Drive](https://drive.google.com/file/d/10D74h8NhpZ2Ut3Te_ieTIAZYOTL6mNQd/view?usp=drive_link)
+
+## Key References for Video Deepfake Detection
+The following works have significantly influenced our understanding and design choices for video deepfake detection.
+
+[FTCN: Exploring Temporal Coherence for More General Video Face Forgery Detection (ICCV 2021)](https://arxiv.org/abs/2108.06693)
+- GitHub:[https://github.com/yinglinzheng/FTCN](https://github.com/yinglinzheng/FTCN)
+- Paper: [arXiv:2108.06693](https://arxiv.org/abs/2108.06693)
+
+
+[AltFreezing: Alternating Freezing for More General Video Face Forgery Detection (CVPR 2023)](https://openaccess.thecvf.com/content/CVPR2023/papers/Wang_AltFreezing_for_More_General_Video_Face_Forgery_Detection_CVPR_2023_paper.pdf)
+- GitHub: [https://github.com/ZhendongWang6/AltFreezing](https://github.com/ZhendongWang6/AltFreezing)
+- Paper: [CVPR 2023 Paper](https://openaccess.thecvf.com/content/CVPR2023/papers/Wang_AltFreezing_for_More_General_Video_Face_Forgery_Detection_CVPR_2023_paper.pdf)
+
+
+[StyleFlow: Exploiting Style Latent Flows for Generalizing Deepfake Video Detection (CVPR 2024)](https://arxiv.org/abs/2403.06592)
+- GitHub: [https://github.com/jongwook-Choi/StyleFlow](https://github.com/jongwook-Choi/StyleFlow)
+- Paper: [arXiv:2403.06592](https://arxiv.org/abs/2403.06592)
+
diff --git a/clean/video/pwtf_dvd/SOURCE.md b/clean/video/pwtf_dvd/SOURCE.md
new file mode 100644
index 0000000000000000000000000000000000000000..952a6f34624f749a80fff49a9afc50ed30083fcc
--- /dev/null
+++ b/clean/video/pwtf_dvd/SOURCE.md
@@ -0,0 +1,17 @@
+# Source: video/pwtf_dvd
+
+| Field | Value |
+|---|---|
+| Upstream | **UNVERIFIED** -- provenance was lost when this code was vendored |
+| Paper | https://arxiv.org/abs/2507.02398 |
+| Commit SHA | **not recorded** -- the vendoring step did not preserve it |
+| Mirrored on | 2026-09-15 |
+| Upstream license | LICENSE |
+
+This is a **mirror**, stripped to the files needed for inference. The full
+untouched snapshot is at `archive/video__pwtf_dvd.tar.gz`.
+
+This code is the work of its original authors and is **not** covered by the
+DeepSafe project license. If you are an author and want this removed, open an
+issue on https://github.com/deepsafehq/deepsafe-bench and it will be taken down
+within 48 hours, no questions asked.
diff --git a/clean/video/pwtf_dvd/index.html b/clean/video/pwtf_dvd/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..09c55b7ca9d722fbac96e8a8c3f4708bfbb6d9ff
--- /dev/null
+++ b/clean/video/pwtf_dvd/index.html
@@ -0,0 +1,515 @@
+
+
+
+
+
+ Beyond Spatial Frequency: Pixel-wise Temporal Frequency-based Deepfake Video Detection — ICCV 2025
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Beyond Spatial Frequency: Pixel‑wise Temporal Frequency‑based Deepfake Video Detection
+
Taehoon Kim, Jongwook Choi, Yonghyun Jeong, Haeun Noh, Jaejun Yoo, Seungryul Baek, Jongwon Choi*
+
Chung‑Ang Univ · NAVER Cloud · UNIST
+
+
+
+
+
+ ⭐ We got Highlight !
+
+
+
+
+
+
+ Interactive Demos
+
+
+
+
+
+
+
+ Abstract
+
+ We introduce a novel method for deepfake video detection that utilizes pixel‑wise temporal frequency spectra . Unlike previous approaches that stack 2D frame‑wise spatial frequency spectra, we extract pixel‑wise temporal frequency by performing a 1D Fourier transform on the time axis per pixel, effectively identifying temporal artifacts. We also propose an Attention Proposal Module (APM) to extract regions of interest for detecting these artifacts. Our method demonstrates outstanding generalizability and robustness in various challenging deepfake video detection scenarios.
+
+
+
+
+
+ Method & Architecture
+
+
+
+
+
+ Frequency Extraction : 1D FFT per‑pixel along time captures subtle temporal artifacts.
+
+
+
+
+
+
+
+ Architecture : Frequency Feature Extractor + APM → Joint Transformer for robust detection.
+
+
+
+
+
+ Pixel‑wise Temporal Frequency : 1D FFT on the time axis per pixel to capture subtle artifacts.
+ Attention Proposal Module (APM) : Weakly‑supervised focus on temporal‑artifact regions.
+ Joint Transformer : Fuses global/part‑based frequency signals and spatio‑temporal context.
+
+
+
+
+
+ Experiments & Results
+
+
+
+
+
+ APM highlights regions (eyes, mouth) where temporal incoherence is likely.
+
+
+
+
+
+
+
+ Consistent SOTA video‑level AUC across datasets demonstrates strong generalization.
+
+
+
+
+
+ SOTA performance on FF++, CDF, DFDC, KoDF, etc.
+ Strong cross‑deepfakes and cross‑synthesis generalization.
+ APM effectively identifies temporally inconsistent regions.
+
+
+
+
+
+ Limitations & Future Work
+
+
+
Known Limitation
+
+ Heavy compression (H.264/JPEG/WebP) merges neighboring pixels, weakening pixel‑level motion → temporal‑frequency shift.
+ Low‑frequency components align with raw signals, but high‑frequency components diverge after compression.
+
+
Future Work
+
We will investigate temporal‑frequency regularization to mitigate compression‑induced degradation.
+
+
+
+
+
+ Average temporal‑frequency under H.264/JPEG/WebP compression.
+
+
+
+
+
+
+
+
+ 📚 Citation
+
+
+
@InProceedings{Kim_2025_ICCV,
+ author = {Kim, Taehoon and Choi, Jongwook and Jeong, Yonghyun and Noh, Haeun and Yoo, Jaejun and Baek, Seungryul and Choi, Jongwon},
+ title = {Beyond Spatial Frequency: Pixel-wise Temporal Frequency-based Deepfake Video Detection},
+ booktitle = {Proceedings of the IEEE/CVF International Conference on Computer Vision (ICCV)},
+ month = {October},
+ year = {2025},
+ pages = {11198-11207}
+}
+
+
+
📋 Copy BibTeX
+
⬇️ Jump to Demos
+
📄 ICCV Paper (soon)
+
🤗 Hugging Face Demo (soon)
+
+
+
+
+
+ 🙏 Acknowledgement
+
+
This work was partly supported by the IITP grant funded by the Korea government (MSIT): No. RS-2025-02263841: Development of a Real-time Multimodal Framework for Comprehensive Deepfake Detection Incorporating Common Sense Error AnalysisRS-2021-II211341: Artificial Intelligence Graduate School Program (Chung-Ang University) No. RS-2020-II201336: AIGS program (UNIST)
+
+
+
+ © 2025 PwTF‑DVD. Design rev • Made with ❤ for ICCV 2025.
+
+ ⬆️
+
+
+
+
diff --git a/clean/video/pwtf_dvd/inference/config_ftcn.py b/clean/video/pwtf_dvd/inference/config_ftcn.py
new file mode 100644
index 0000000000000000000000000000000000000000..0469cec71147fafe83d496e20b08acf3cdf94853
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/config_ftcn.py
@@ -0,0 +1,138 @@
+#!/usr/bin/python
+# Borrow from tensorpack,credits goes to yuxin wu
+
+# the loaded sequnce is
+# default config in this file
+# -> provided setting file (you can not add new config after this)
+# -> manully overrided config
+# -> computed config in finalize config (you can change config after this)
+
+import os
+import pprint
+import yaml
+
+__all__ = ["config", "finalize_configs"]
+
+
+class AttrDict:
+ _freezed = False
+ """ Avoid accidental creation of new hierarchies. """
+
+ def __getattr__(self, name):
+ if self._freezed:
+ raise AttributeError(name)
+ ret = AttrDict()
+ setattr(self, name, ret)
+ return ret
+
+ def __setattr__(self, name, value):
+ if self._freezed and name not in self.__dict__:
+ raise AttributeError("Cannot create new attribute!")
+ super().__setattr__(name, value)
+
+ def __str__(self):
+ return pprint.pformat(self.to_dict(), indent=1)
+
+ __repr__ = __str__
+
+ def to_dict(self):
+ """Convert to a nested dict. """
+ return {
+ k: v.to_dict() if isinstance(v, AttrDict) else v
+ for k, v in self.__dict__.items()
+ if not k.startswith("_")
+ }
+
+ def update_args(self, args):
+ """Update from command line args. """
+ for cfg in args:
+ keys, v = cfg.split("=", maxsplit=1)
+ keylist = keys.split(".")
+ dic = self
+ # print(keylist)
+ if len(keylist) == 1:
+ assert keylist[0] in dir(dic), "Unknown config key: {}".format(
+ keylist[0]
+ )
+ for i, k in enumerate(keylist[:-1]):
+ assert k in dir(dic), "Unknown config key: {}".format(k)
+ dic = getattr(dic, k)
+ key = keylist[-1]
+ assert key in dir(dic), "Unknown config key: {}".format(key)
+ oldv = getattr(dic, key)
+ if not isinstance(oldv, str):
+ v = eval(v)
+ setattr(dic, key, v)
+
+ def update_with_yaml(self, rel_path):
+ base_path = os.path.dirname(os.path.abspath(__file__))
+ setting_path = os.path.normpath(os.path.join(base_path, "setting", rel_path))
+ setting_name = os.path.basename(setting_path).split(".")[0]
+
+ with open(setting_path, "r") as f:
+ overrided_setting = yaml.load(f,Loader=yaml.FullLoader)
+ # if 'setting_name' not in overrided_setting:
+ # raise RuntimeError('you must provide a setting name for non root_setting: {}'.format(rel_path))
+ self.update_with_dict(overrided_setting)
+ setattr(self, "setting_name", setting_name)
+
+ def init_with_yaml(self):
+ base_path = os.path.dirname(os.path.abspath(__file__))
+ setting_path = os.path.normpath(os.path.join(base_path, "root_setting.yaml"))
+ with open(setting_path, "r") as f:
+ overrided_setting = yaml.load(f,Loader=yaml.FullLoader)
+ self.update_with_dict(overrided_setting)
+
+ def update_with_text(self,text):
+ overrided_setting = yaml.load(text, Loader=yaml.FullLoader)
+ self.update_with_dict(overrided_setting)
+
+ def update_with_dict(self, dicts):
+ for k, v in dicts.items():
+ if isinstance(v, dict):
+ getattr(self, k).update_with_dict(v)
+ else:
+ setattr(self, k, v)
+
+ def freeze(self):
+ self._freezed = True
+ for v in self.__dict__.values():
+ if isinstance(v, AttrDict):
+ v.freeze()
+
+ # avoid silent bugs
+ def __eq__(self, _):
+ raise NotImplementedError()
+
+ def __ne__(self, _):
+ raise NotImplementedError()
+
+
+config = AttrDict()
+_C = config # short alias to avoid coding
+
+
+# you can directly write setting here as _C.model_dir='.\checkpoint' or in root_setting.yaml
+
+
+#
+
+
+def finalize_configs(input_cfg=_C, freeze=True, verbose=True):
+
+ # _C.base_path = os.path.dirname(os.path.abspath(__file__))
+ input_cfg.base_path = os.path.dirname(__file__)
+
+ # for running in remote server
+ # for k, v in input_cfg.path.__dict__.items():
+ # v = os.path.normpath(os.path.join(input_cfg.base_path, v))
+ # setattr(input_cfg.path, k, v)
+ if freeze:
+ input_cfg.freeze()
+ # if verbose:
+ # logger.info("Config: ------------------------------------------\n" + str(_C))
+
+
+if __name__ == "__main__":
+ print("?")
+ print(os.path.dirname(__file__))
diff --git a/clean/video/pwtf_dvd/inference/model/attention_network.py b/clean/video/pwtf_dvd/inference/model/attention_network.py
new file mode 100644
index 0000000000000000000000000000000000000000..13280c3acbbc7f134274d914d94315d3e12d88d4
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/model/attention_network.py
@@ -0,0 +1,193 @@
+import torch.nn as nn
+import math
+import torch
+import torch.utils.model_zoo as model_zoo
+import torch.nn.functional as F
+from torch.autograd import Variable
+from model.resnet_backbone import resnet50, oneByoneConvNet
+import numpy as np
+
+
+class CONV(nn.Module):
+ def __init__(self, partials_num=5, ori_dim=64):
+ super(CONV, self).__init__()
+ self.partials_num = partials_num
+ self.ori_dim = ori_dim
+ self.conv0 = nn.Conv2d(ori_dim, ori_dim, kernel_size=1)
+ # Create conv layers dynamically
+ self.convs = nn.ModuleList()
+ for i in range(partials_num):
+ self.convs.append(nn.Conv2d(ori_dim, ori_dim, kernel_size=1))
+
+ def forward(self, x_p, x):
+ batch_size = x.size(0)
+ h, w = x.size(2), x.size(3)
+
+ x_sum = self.conv0(x)
+
+ if self.partials_num > 0 and x_p is not None:
+ x_p = F.interpolate(x_p, size=(h, w), mode='bilinear', align_corners=True)
+ x_p = x_p.view(batch_size, self.partials_num, self.ori_dim, h, w)
+ x_p_p = x_p.permute(1, 0, 2, 3, 4)
+
+ for i in range(min(self.partials_num, len(self.convs))):
+ x_sum += self.convs[i](x_p_p[i])
+
+ return x_sum
+class AttentionCropFunction(torch.autograd.Function):
+ @staticmethod
+ def forward(self, images, locs):
+ h = lambda x: 1. / (1. + torch.exp(-10. * x))
+ in_size = images.size()[2]
+ unit = torch.stack([torch.arange(0, in_size)] * in_size).float()
+ x = torch.stack([unit.t()] * 16)
+ y = torch.stack([unit] * 16)
+ if isinstance(images, torch.cuda.FloatTensor):
+ x, y = x.cuda(), y.cuda()
+ in_size = images.size()[2]
+ ret = []
+ for i in range(images.size(0)):
+ tx, ty, tl = locs[i][0]*224, locs[i][1]*224, 44
+ tx = tx if tx > tl else tl
+ tx = tx if tx < in_size-tl else in_size-tl
+ ty = ty if ty > tl else tl
+ ty = ty if ty < in_size-tl else in_size-tl
+
+ w_off = int(tx-tl) if (tx-tl) > 0 else 0
+ h_off = int(ty-tl) if (ty-tl) > 0 else 0
+ w_end = int(tx+tl) if (tx+tl) < in_size else in_size
+ h_end = int(ty+tl) if (ty+tl) < in_size else in_size
+
+ mk = (h(x-w_off) - h(x-w_end)) * (h(y-h_off) - h(y-h_end))
+ xatt = images[i] * mk
+ xatt_cropped = xatt[:, w_off:w_end, h_off:h_end]
+ before_upsample = Variable(xatt_cropped.unsqueeze(0))
+ xamp = F.interpolate(before_upsample, size=(88,88), mode='bilinear', align_corners = True)
+ ret.append(xamp.data.squeeze())
+ ret_tensor = torch.stack(ret)
+ self.save_for_backward(images, ret_tensor)
+ return ret_tensor
+
+ @staticmethod
+ def backward(self, grad_output):
+ pass
+class AttentionCropLayer(nn.Module):
+ """
+ Crop function sholud be implemented with the nn.Function.
+ Detailed description is in 'Attention localization and amplification' part.
+ Forward function will not changed. backward function will not opearate with autograd, but munually implemented function
+ """
+ def forward(self, images, locs):
+ return AttentionCropFunction.apply(images, locs)
+class APN(nn.Module):
+ def __init__(self,depth=18, partials_num = 5):
+ super(APN, self).__init__()
+ self.localization = LocalizationCNN(depth)
+ self.partials_num = partials_num
+ self.region_proposal = nn.Sequential(
+ nn.Linear(2048 * 7 * 7, 1024),
+ nn.Tanh(),
+ nn.Linear(1024, 2*partials_num),
+ nn.Sigmoid(),
+ )
+ def forward(self, x, x_ft):
+ x_batch_size = x.size(0)
+ x_l = self.localization(x,x_ft)
+ x_l = x_l.view(-1, 2048*7*7)
+ xs = self.region_proposal(x_l)
+ xs_t = xs.view(x_batch_size * self.partials_num, 2)
+ return xs_t
+
+class LocalizationCNN(nn.Module):
+ def __init__(self,depth = 18):
+ super(LocalizationCNN, self).__init__()
+ self.depth = depth
+ self.conv1 = nn.Sequential( nn.Conv2d(16, 64, kernel_size=7, stride=2, padding=3, bias=False),
+ nn.BatchNorm2d(64),
+ nn.ReLU(inplace=True),
+ nn.MaxPool2d(kernel_size=3, stride=2, padding=1),
+ )
+ self.conv2 = nn.Sequential( nn.Conv2d(64, 256, kernel_size=3, stride=1, padding=1, bias=False),
+ nn.BatchNorm2d(256),
+ nn.ReLU(inplace=True)
+ )
+ self.conv3 = nn.Sequential( nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1, bias=False),
+ nn.BatchNorm2d(512),
+ nn.ReLU(inplace=True),
+ nn.MaxPool2d(kernel_size=3, stride=2, padding=1))
+ self.conv4 = nn.Sequential( nn.Conv2d(512, 1024, kernel_size=3, stride=1, padding=1, bias=False),
+ nn.BatchNorm2d(1024),
+ nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=3, stride=2, padding=1))
+ self.conv5 = nn.Sequential( nn.Conv2d(1024, 2048, kernel_size=3, stride=1, padding=1, bias=False),
+ nn.BatchNorm2d(2048),
+ nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=3, stride=2, padding=1))
+ def forward(self, x,x_ft):
+ x = self.conv1(x) + x_ft[0].detach().float()
+ x = self.conv2(x) + x_ft[1].detach().float()
+ x = self.conv3(x) + x_ft[2].detach().float()
+ x = self.conv4(x) + x_ft[3].detach().float()
+ x = self.conv5(x) + x_ft[4].detach().float()
+ return x
+h = lambda x: 1. / (1. + torch.exp(-100. * x))
+class APNResNet(nn.Module):
+ def __init__(self, partials_num = 5, depth= 18):
+ super(APNResNet, self).__init__()
+ self.partials_num = partials_num
+
+ self.whole_resnet = resnet50(pretrained=True)
+ self.oconv0 = oneByoneConvNet(64,32,64)
+ self.oconv1 = oneByoneConvNet(256,128,256)
+ self.oconv2 = oneByoneConvNet(512,256,512)
+ self.oconv3 = oneByoneConvNet(1024,512,1024)
+ self.oconv4 = oneByoneConvNet(2048,1024,2048)
+
+ self.attn_1 = CONV(partials_num=partials_num, ori_dim=64)
+ self.attn_2 = CONV(partials_num=partials_num, ori_dim=256)
+ self.attn_3 = CONV(partials_num=partials_num, ori_dim=512)
+ self.attn_4 = CONV(partials_num=partials_num, ori_dim=1024)
+ self.fn = nn.Linear(2048, 1024)
+ self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
+
+ self.APN = APN(depth, partials_num)
+ self.crop_resize = AttentionCropLayer()
+
+ def forward(self, x):
+ batch_size = x.size(0)
+ out1_w, out2_w, out3_w, out4_w, out5_w, out5_p_w = self.whole_resnet(x)
+
+ out5_p_w = out5_p_w.view(batch_size, -1)
+
+
+ xs_t= self.APN(x.clone(), (out1_w, out2_w, out3_w,out4_w,out5_w))
+ images = x
+ images = images.repeat_interleave(self.partials_num, dim=0)
+ scaled_x = self.crop_resize(images, xs_t)
+ scaled_x_b = scaled_x.view(-1, 16, 88, 88)
+ out1_p_b, out2_p_b, out3_p_b, out4_p_b, out5_p_b, out5_p_p_b = self.whole_resnet(scaled_x_b)
+ whole_box_num = 5
+ out1 = self.attention(out1_w, out1_p_b, 1, whole_box_num)
+ out2 = self.attention(out2_w, out2_p_b, 2, whole_box_num)
+ out3 = self.attention(out3_w, out3_p_b, 3, whole_box_num)
+ out4 = self.attention(out4_w, out4_p_b, 4, whole_box_num)
+ out5 = self.avgpool(self.oconv4(out5_p_b)).view(batch_size, self.partials_num, -1)
+
+ out1 = self.oconv0(out1)
+ out2 = self.oconv1(out2)
+ out3 = self.oconv2(out3)
+ out4 = self.oconv3(out4)
+ out6 = self.fn(out5_p_w)
+
+
+
+ return out1, out2, out3, out4, out5, out6, (xs_t, scaled_x)
+
+ def attention(self, x, x_p, stage, box_num):
+ if stage == 1:
+ out = self.attn_1(x_p, x)
+ if stage == 2:
+ out = self.attn_2(x_p, x)
+ if stage == 3:
+ out = self.attn_3(x_p, x)
+ if stage == 4:
+ out = self.attn_4(x_p, x)
+ return out
diff --git a/clean/video/pwtf_dvd/inference/model/framework.py b/clean/video/pwtf_dvd/inference/model/framework.py
new file mode 100644
index 0000000000000000000000000000000000000000..9839957b2d74c38a43074539388861f453c4ab36
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/model/framework.py
@@ -0,0 +1,38 @@
+
+import torch
+import torch.nn as nn
+from .video_encoder import I3D8x8
+from .attention_network import APNResNet
+from .transformers import TransformerHead, SpatialTransformerE
+
+
+# Model for deployment
+# Note: modified model structure for easier deployment combined with video encoder FTCN official repo code
+def get_model():
+ part_num = 5
+ model= I3D8x8()
+ model_ft = APNResNet(partials_num=part_num,depth =50)
+ params = dict(spatial_size=14, time_size=16, in_channels=1024,num_parts=part_num)
+ TTE = TransformerHead(**params)
+ STE = SpatialTransformerE(**params)
+ MLP = torch.nn.Linear(2048,1)
+ return Framework(model, model_ft, TTE, STE, MLP)
+
+
+class Framework(nn.Module):
+ def __init__(self, model, model_ft, TTE, STE, MLP):
+ super(Framework, self).__init__()
+ self.model = model
+ self.model_ft = model_ft
+ self.TTE = TTE
+ self.STE = STE
+ self.MLP = MLP
+
+ def forward(self, video_sample, ft_sample):
+ out1, out2, out3, out4, out5,out6, (xs, scaled_x) = self.model_ft(ft_sample.float())
+ ft_feats = [out1, out2, out3, out4, None]
+ x,_ = self.model(video_sample,ft_feats)
+ ft_s , _= self.STE(x,out5,xs)
+ ft_t, _ = self.TTE(x,out6)
+ outputs = self.MLP(torch.concat((ft_t, ft_s), dim = 1))
+ return outputs
diff --git a/clean/video/pwtf_dvd/inference/model/resnet_backbone.py b/clean/video/pwtf_dvd/inference/model/resnet_backbone.py
new file mode 100644
index 0000000000000000000000000000000000000000..5cf21e4bf7d02d292fcdd60a0929a5bd0f5772d8
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/model/resnet_backbone.py
@@ -0,0 +1,235 @@
+import torch.nn as nn
+import math
+import torch
+import torch.utils.model_zoo as model_zoo
+import torch.nn.functional as F
+__all__ = ['ResNet', 'resnet18', 'resnet50', ]
+
+
+normalization = nn.BatchNorm2d
+
+model_urls = {
+ 'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth',
+ 'resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth',
+ 'resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth',
+ 'resnet101': 'https://download.pytorch.org/models/resnet101-5d3b4d8f.pth',
+ 'resnet152': 'https://download.pytorch.org/models/resnet152-b121ed2d.pth',
+}
+def conv3x3(in_planes, out_planes, stride=1):
+ """3x3 convolution with padding"""
+ return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,
+ padding=1, bias=False)
+class BasicBlock(nn.Module):
+ expansion = 1
+
+ def __init__(self, inplanes, planes, stride=1, downsample=None):
+ super(BasicBlock, self).__init__()
+ self.conv1 = conv3x3(inplanes, planes, stride)
+ self.bn1 = normalization(planes)
+ self.relu = nn.ReLU(inplace=False)
+ self.conv2 = conv3x3(planes, planes)
+ self.bn2 = normalization(planes)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x):
+ residual = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+
+ if self.downsample is not None:
+ residual = self.downsample(x)
+
+ out = out + residual
+ out = self.relu(out)
+
+ return out
+
+ def forward_masked(self, x, mask=None):
+ residual = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+
+ if self.downsample is not None:
+ residual = self.downsample(x)
+
+
+ out = out + residual
+ if mask is not None:
+ out = out * mask[None,:,None,None]# + self.bn2.bias[None,:,None,None] * (1 - mask[None,:,None,None])
+
+ out = self.relu(out)
+
+ return out
+
+class Bottleneck(nn.Module):
+ expansion = 4
+
+ def __init__(self, inplanes, planes, stride=1, downsample=None):
+ super(Bottleneck, self).__init__()
+ self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False)
+ self.bn1 = normalization(planes)
+ self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride,
+ padding=1, bias=False)
+ self.bn2 = normalization(planes)
+ self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False)
+ self.bn3 = normalization(planes * 4)
+ self.relu = nn.ReLU(inplace=False)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x):
+ residual = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+ out = self.relu(out)
+
+ out = self.conv3(out)
+ out = self.bn3(out)
+
+ if self.downsample is not None:
+ residual = self.downsample(x)
+
+ out += residual
+ out = self.relu(out)
+
+ return out
+
+
+class AbstractResNet(nn.Module):
+
+ def __init__(self, block, layers, num_classes=1000, maxiter=-1):
+ super(AbstractResNet, self).__init__()
+ self.inplanes = 64
+ self.conv1 = nn.Conv2d(16, 64, kernel_size=7, stride=2, padding=3,
+ bias=False)
+ self.bn1 = normalization(64)
+ self.relu = nn.ReLU(inplace=False)
+ self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
+ self.layer1 = self._make_layer(block, 64, layers[0])
+ self.layer2 = self._make_layer(block, 128, layers[1], stride=2)
+ self.layer3 = self._make_layer(block, 256, layers[2], stride=2)
+ self.layer4 = self._make_layer(block, 512, layers[3], stride=2)
+ self.avgpool = nn.AdaptiveAvgPool2d(1)
+
+
+ def _make_layer(self, block, planes, blocks, stride=1):
+ downsample = None
+ if stride != 1 or self.inplanes != planes * block.expansion:
+ downsample = nn.Sequential(
+ nn.Conv2d(self.inplanes, planes * block.expansion,
+ kernel_size=1, stride=stride, bias=False),
+ normalization(planes * block.expansion),
+ )
+
+ layers = []
+ layers.append(block(self.inplanes, planes, stride, downsample))
+ self.inplanes = planes * block.expansion
+ for i in range(1, blocks):
+ layers.append(block(self.inplanes, planes))
+
+ return nn.Sequential(*layers)
+
+ def features(self,x):
+ x__ = self.maxpool(self.relu(self.bn1(self.conv1(x))))
+ x__1 = self.layer1(x__)
+ x__2 = self.layer2(x__1)
+ x__3 = self.layer3(x__2)
+ x__4 = self.layer4(x__3)
+ return x__, x__1, x__2, x__3, x__4
+
+
+
+ def load_state_dict(self, state_dict, strict=True):
+ missing_keys = []
+ unexpected_keys = []
+ error_msgs = []
+
+ # copy state_dict so _load_from_state_dict can modify it
+ metadata = getattr(state_dict, '_metadata', None)
+ state_dict = state_dict.copy()
+ if metadata is not None:
+ state_dict._metadata = metadata
+
+ def load(module, prefix=''):
+ local_metadata = {} if metadata is None else metadata.get(prefix[:-1], {})
+ module._load_from_state_dict(
+ state_dict, prefix, local_metadata, strict, missing_keys, unexpected_keys, error_msgs)
+ for name, child in module._modules.items():
+ if child is not None:
+ load(child, prefix + name + '.')
+
+ load(self)
+
+ if strict:
+ error_msg = ''
+ if len(unexpected_keys) > 0:
+ error_msgs.insert(
+ 0, 'Unexpected key(s) in state_dict: {}. '.format(
+ ', '.join('"{}"'.format(k) for k in unexpected_keys)))
+ if len(missing_keys) > 0:
+ error_msgs.insert(
+ 0, 'Missing key(s) in state_dict: {}. '.format(
+ ', '.join('"{}"'.format(k) for k in missing_keys)))
+
+ if len(error_msgs) > 0:
+ pass
+
+
+
+# Removed training-related classes for inference-only code
+class oneByoneConvNet(nn.Module):
+ def __init__(self, in_channels,hidden_channels,out_channels):
+ super(oneByoneConvNet, self).__init__()
+ self.conv1 = nn.Conv2d(in_channels=in_channels, out_channels=hidden_channels, kernel_size=1)
+
+ self.conv2 = nn.Conv2d(in_channels=hidden_channels, out_channels=out_channels, kernel_size=1)
+
+ def forward(self, x):
+ x = self.conv1(x)
+ x = F.relu(x)
+ x = self.conv2(x)
+ return x
+class ResNet(AbstractResNet):
+
+ def __init__(self, block, layers, num_classes=2, max_iter=-1, normalized=True, use_bias=False, simsiam=False):
+ super(ResNet, self).__init__(block, layers, num_classes)
+ def forward(self, x):
+ x__, x__1, x__2, x__3, x__4 = self.features(x)
+ x__4_p = self.avgpool(x__4).view(x__.size(0), -1).squeeze()
+ return x__, x__1, x__2, x__3,x__4, x__4_p
+
+def resnet50(pretrained=False, **kwargs):
+ model = ResNet(Bottleneck, [3, 4, 6, 3], **kwargs)
+ if pretrained:
+ weight = model_zoo.load_url(model_urls['resnet50'])
+ conv1_weight = weight['conv1.weight']
+ conv1_weight = conv1_weight.repeat(1, 5, 1, 1)
+ conv1_weight = torch.concat([conv1_weight, conv1_weight[:,:1,:,:]], dim=1)
+ model.load_state_dict(weight)
+ model.conv1.weight = nn.Parameter(conv1_weight)
+ return model
+
+class Normalize(nn.Module):
+ def __init__(self):
+ super(Normalize, self).__init__()
+
+ def forward(self, x):
+ return F.normalize(x, dim=-1)
+
+# Removed get_model function as it's not needed for inference
\ No newline at end of file
diff --git a/clean/video/pwtf_dvd/inference/model/transformers.py b/clean/video/pwtf_dvd/inference/model/transformers.py
new file mode 100644
index 0000000000000000000000000000000000000000..1cd59044dcc707b980e5cfc4bb78b54c435c794a
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/model/transformers.py
@@ -0,0 +1,474 @@
+
+import torch
+from torch import nn, einsum
+import torch.nn.functional as F
+from einops import rearrange, repeat
+# Removed Rearrange import - not used in inference
+# Removed unused imports for inference
+from math import sqrt
+from config_ftcn import config as my_cfg
+
+# Initialize config
+my_cfg.init_with_yaml()
+my_cfg.update_with_yaml("ftcn_tt.yaml")
+my_cfg.freeze()
+
+# =============================================================================
+# Basic Transformer Components
+# =============================================================================
+
+class Residual(nn.Module):
+ def __init__(self, fn):
+ super().__init__()
+ self.fn = fn
+ def forward(self, x, **kwargs):
+ return self.fn(x, **kwargs) + x
+
+class PreNorm(nn.Module):
+ def __init__(self, dim, fn):
+ super().__init__()
+ self.norm = nn.LayerNorm(dim)
+ self.fn = fn
+ def forward(self, x, **kwargs):
+ return self.fn(self.norm(x), **kwargs)
+
+class FeedForward(nn.Module):
+ def __init__(self, dim, hidden_dim, dropout = 0.):
+ super().__init__()
+ self.net = nn.Sequential(
+ nn.Linear(dim, hidden_dim),
+ nn.GELU(),
+ nn.Dropout(dropout),
+ nn.Linear(hidden_dim, dim),
+ nn.Dropout(dropout)
+ )
+ def forward(self, x):
+ return self.net(x)
+
+class Attention(nn.Module):
+ def __init__(self, dim, heads = 8, dim_head = 64, dropout = 0.):
+ super().__init__()
+ inner_dim = dim_head * heads
+ project_out = not (heads == 1 and dim_head == dim)
+
+ self.heads = heads
+ self.scale = dim_head ** -0.5
+
+ self.to_qkv = nn.Linear(dim, inner_dim * 3, bias = False)
+
+ self.to_out = nn.Sequential(
+ nn.Linear(inner_dim, dim),
+ nn.Dropout(dropout)
+ ) if project_out else nn.Identity()
+
+ def forward(self, x, mask = None):
+ b, n, _, h = *x.shape, self.heads
+ qkv = self.to_qkv(x).chunk(3, dim = -1)
+ q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> b h n d', h = h), qkv)
+
+ dots = einsum('b h i d, b h j d -> b h i j', q, k) * self.scale
+ mask_value = -torch.finfo(dots.dtype).max
+
+ if mask is not None:
+ mask = F.pad(mask.flatten(1), (1, 0), value = True)
+ assert mask.shape[-1] == dots.shape[-1], 'mask has incorrect dimensions'
+ mask = rearrange(mask, 'b i -> b () i ()') * rearrange(mask, 'b j -> b () () j')
+ dots.masked_fill_(~mask, mask_value)
+ del mask
+
+ attn = dots.softmax(dim=-1)
+
+ out = einsum('b h i j, b h j d -> b h i d', attn, v)
+ out = rearrange(out, 'b h n d -> b n (h d)')
+ out = self.to_out(out)
+ return out
+
+class Transformer(nn.Module):
+ def __init__(self, dim, depth, heads, dim_head, mlp_dim, dropout = 0.):
+ super().__init__()
+ self.layers = nn.ModuleList([])
+ for _ in range(depth):
+ self.layers.append(nn.ModuleList([
+ Residual(PreNorm(dim, Attention(dim, heads = heads, dim_head = dim_head, dropout = dropout))),
+ Residual(PreNorm(dim, FeedForward(dim, mlp_dim, dropout = dropout)))
+ ]))
+ def forward(self, x, mask = None):
+ for attn, ff in self.layers:
+ x = attn(x, mask = mask)
+ x = ff(x)
+ return x
+
+# =============================================================================
+# Utility Functions
+# =============================================================================
+
+def valid_idx(idx, h):
+ i = idx // h
+ j = idx % h
+ if j == 0 or i == h - 1 or j == h - 1:
+ return False
+ else:
+ return True
+
+
+# =============================================================================
+# Patch Pooling Classes (Simplified for Inference)
+# =============================================================================
+
+class CenterPatchPool(nn.Module):
+ """Simplified patch pooling for inference - always use center patch"""
+ def __init__(self):
+ super().__init__()
+
+ def forward(self, x):
+ # batch,channel,16,7x7
+ b, c, t, h, w = x.shape
+ x = x.reshape(b, c, t, h * w)
+ idx = h * w // 2 # Always use center patch for inference
+ x = x[..., idx]
+ return x
+
+class CenterAvgPool(nn.Module):
+ """Simplified average pooling for inference - use all valid patches"""
+ def __init__(self):
+ super().__init__()
+
+ def forward(self, x):
+ # batch,channel,16,7x7
+ b, c, t, h, w = x.shape
+ x = x.reshape(b, c, t, h * w)
+ candidates = list(range(h * w))
+ candidates = [idx for idx in candidates if valid_idx(idx, h)]
+ x = x[..., candidates].mean(-1)
+ return x
+
+class CenterSelect(nn.Module):
+ """Simplified selection for inference - use all valid patches"""
+ def __init__(self):
+ super().__init__()
+
+ def forward(self, x):
+ # batch,7x7
+ size = x.shape[1]
+ h = int(sqrt(size))
+ candidates = list(range(size))
+ candidates = [idx for idx in candidates if valid_idx(idx, h)]
+ x = x[:, candidates]
+ return x
+
+# =============================================================================
+# Vision Transformer Classes
+# =============================================================================
+
+# Removed ViT and VideoiT classes - not used in inference
+
+# =============================================================================
+# Specialized Transformer Classes
+# =============================================================================
+
+# SpatialTransformer class - used by SpatialTransformerE
+class SpatialTransformer(nn.Module):
+ def __init__(self,num_patches, num_classes, dim, depth, heads, mlp_dim, pool = 'cls', dim_head = 64, dropout = 0., emb_dropout = 0.):
+ super().__init__()
+ self.dim =dim
+ self.num_patches=num_patches
+ self.pos_embedding = nn.Parameter(posemb_sincos_2d(14,14,dim))
+ self.cls_token = nn.Parameter(torch.randn(1, 1, dim))
+ self.dropout = nn.Dropout(emb_dropout)
+ self.fre_pos = nn.Parameter(torch.randn(1, 1, dim))
+ self.transformer = Transformer(1024, depth, heads, dim_head, mlp_dim, dropout)
+ self.pool = pool
+ self.to_latent = nn.Identity()
+ self.mlp_head = nn.Sequential(
+ nn.LayerNorm(1024), nn.Linear(1024, 1024)
+ )
+ self.freq_embedding = nn.Sequential(nn.LayerNorm(dim),nn.Linear(dim,dim))
+ self.cls_token_pos = nn.Parameter(torch.randn(1, 1, dim))
+ self.mlp_head_ste = nn.Linear(dim, 1)
+
+ def posemb_loc(self, locs,batch_size):
+ if locs is not None:
+ b,n,_ = locs.shape
+
+ pos224 =self.pos_embedding.view(14,14,-1)
+ pos_locs = torch.zeros(batch_size,n, self.dim)
+ if locs is not None:
+ # locs[locs>=1] = 0.999999
+ loc_x = torch.floor(locs[:,:,0]*6)
+ loc_y = torch.floor(locs[:,:,1]*6)
+
+ loc_x = loc_x.long()
+ loc_y = loc_y.long()
+ x_a = locs[:,:,0]*6 - loc_x
+ y_a = locs[:,:,0]*6 - loc_y
+
+ x1_a = torch.sqrt( torch.pow(1-x_a,2) + torch.pow(1-y_a,2))
+ x2_a = torch.sqrt( torch.pow(1-x_a,2) + torch.pow(y_a,2))
+ x3_a = torch.sqrt( torch.pow(x_a,2) + torch.pow(1-y_a,2))
+ x4_a = torch.sqrt( torch.pow(x_a,2) + torch.pow(y_a,2))
+ pos_locs[:, :, :] = pos224[loc_x,loc_y,:]*x1_a.unsqueeze(-1)\
+ +pos224[loc_x+1,loc_y,:]*x2_a.unsqueeze(-1)\
+ +pos224[loc_x,loc_y+1,:]*x3_a.unsqueeze(-1)\
+ +pos224[loc_x+1,loc_y+1,:]*x4_a.unsqueeze(-1)
+
+ return pos_locs
+
+ def forward(self, x,ft_feature,locs):
+ b, n, _ = x.shape #batch,num_patches,channels #
+ cls_tokens_pos = repeat(self.cls_token_pos, '() n d -> b n d', b = b)
+ cls_tokens = repeat(self.cls_token, '() n d -> b n d', b = b)
+ cls_tokens = cls_tokens+cls_tokens_pos
+ x += self.pos_embedding
+ if locs is not None:
+ posemb_loc = self.posemb_loc(locs,b).clone().detach()
+ if torch.cuda.is_available() and x.is_cuda:
+ posemb_loc = posemb_loc.cuda()
+ posemb_loc += self.fre_pos
+
+ ft_feature = ft_feature+posemb_loc
+ ft_feature = self.freq_embedding(ft_feature)
+ x = torch.cat((cls_tokens, x,ft_feature), dim=1)
+ else :
+ x = torch.cat((cls_tokens, x), dim=1)
+ x = self.dropout(x)
+ x = self.transformer(x, mask=None)
+ x = x.mean(dim = 1) if self.pool == 'mean' else x[:, 0]
+
+ x = self.to_latent(x)
+ x = self.mlp_head(x)
+ return x, self.mlp_head_ste(x.clone())
+import torch
+from torch import nn
+import torch.nn.functional as F
+from einops import repeat
+
+def posemb_sincos_2d(h, w, dim, temperature: int = 10000, dtype=torch.float32):
+ assert (dim % 4) == 0, "dim must be multiple of 4"
+ y, x = torch.meshgrid(torch.arange(h), torch.arange(w), indexing="ij")
+ omega = torch.arange(dim // 4) / (dim // 4 - 1)
+ omega = 1.0 / (temperature ** omega)
+ y = y.flatten()[:, None] * omega[None, :]
+ x = x.flatten()[:, None] * omega[None, :]
+ pe = torch.cat((x.sin(), x.cos(), y.sin(), y.cos()), dim=1)
+ return pe.type(dtype)
+
+class SpatialTransformer(nn.Module):
+ def __init__(self, num_patches, num_classes, dim, depth, heads, mlp_dim,
+ pool='cls', dim_head=64, dropout=0., emb_dropout=0.):
+ super().__init__()
+ self.dim = dim
+ self.num_patches = num_patches
+ self.register_buffer('pos_embedding', posemb_sincos_2d(14, 14, dim))
+
+ self.cls_token = nn.Parameter(torch.randn(1, 1, dim))
+ self.cls_token_pos = nn.Parameter(torch.randn(1, 1, dim))
+ self.fre_pos = nn.Parameter(torch.randn(1, 1, dim))
+ self.dropout = nn.Dropout(emb_dropout)
+
+ self.spatial_proj = nn.Linear(dim, dim)
+ self.freq_embedding = nn.Sequential(nn.LayerNorm(dim), nn.Linear(dim, dim))
+ self.transformer = Transformer(dim, depth, heads, dim_head, mlp_dim, dropout)
+
+ self.pool = pool
+ self.to_latent = nn.Identity()
+
+ # output ES ∈ R^1024
+ self.mlp_head = nn.Sequential(nn.LayerNorm(dim), nn.Linear(dim, 1024))
+ self.mlp_head_ste = nn.Linear(dim, 1)
+
+ @torch.no_grad()
+ def posemb_loc(self, locs, batch_size):
+ if locs is None:
+ return None
+ # locs: (B, P, 2) in [0,1]
+ B, P, _ = locs.shape
+ device, dtype = locs.device, locs.dtype
+
+ pos_grid = self.pos_embedding.view(14, 14, self.dim).to(device) # (14,14,dim) - already [196, dim]
+
+ S = 13.0
+ x_f = (locs[:, :, 0] * S).clamp(0, 13 - 1e-6)
+ y_f = (locs[:, :, 1] * S).clamp(0, 13 - 1e-6)
+
+ ix = torch.floor(x_f).long().clamp(0, 12)
+ iy = torch.floor(y_f).long().clamp(0, 12)
+ ix1 = (ix + 1).clamp(max=13)
+ iy1 = (iy + 1).clamp(max=13)
+
+ x_a = (x_f - ix).to(dtype) # frac
+ y_a = (y_f - iy).to(dtype)
+
+ w11 = (1 - x_a) * (1 - y_a)
+ w12 = x_a * (1 - y_a)
+ w21 = (1 - x_a) * y_a
+ w22 = x_a * y_a
+
+ p11 = pos_grid[ix, iy, :] # (B,P,dim) via advanced indexing
+ p12 = pos_grid[ix1, iy, :]
+ p21 = pos_grid[ix, iy1, :]
+ p22 = pos_grid[ix1, iy1, :]
+
+ pos_locs = (p11 * w11.unsqueeze(-1) +
+ p12 * w12.unsqueeze(-1) +
+ p21 * w21.unsqueeze(-1) +
+ p22 * w22.unsqueeze(-1)) # (B,P,dim)
+ return pos_locs
+
+ def forward(self, x, ft_feature, locs):
+ # x: (B, N=14*14, dim), ft_feature: (B, P, dim), locs: (B, P, 2)
+ B, N, _ = x.shape
+
+ # cls token (+ pos)
+ cls_tokens = repeat(self.cls_token, '() n d -> b n d', b=B)
+ cls_tokens_pos = repeat(self.cls_token_pos, '() n d -> b n d', b=B)
+ cls_tokens = cls_tokens + cls_tokens_pos
+
+ # Wsp z_sp + pos_sp
+ x = self.spatial_proj(x)
+ x = x + self.pos_embedding.unsqueeze(0).to(x.device)
+
+ # part tokens: Wfreq Z_p + (interp(pos_sp) + pos_freq)
+ if locs is not None and ft_feature is not None:
+ pospart = self.posemb_loc(locs, B) # (B,P,dim)
+ if pospart is not None:
+ pospart = pospart + self.fre_pos # + posfreq
+ ft_feature = self.freq_embedding(ft_feature) # Wfreq
+ if pospart is not None:
+ ft_feature = ft_feature + pospart
+ tokens = torch.cat((cls_tokens, x, ft_feature), dim=1)
+ else:
+ tokens = torch.cat((cls_tokens, x), dim=1)
+
+ tokens = self.dropout(tokens)
+ tokens = self.transformer(tokens, mask=None)
+ out = tokens.mean(dim=1) if self.pool == 'mean' else tokens[:, 0]
+
+ out = self.to_latent(out)
+ es = self.mlp_head(out) # ES ∈ R^1024
+ ste_score = self.mlp_head_ste(out) # optional head
+
+ return es, ste_score
+
+class TimeTransformer(nn.Module):
+ def __init__(self,num_patches, num_classes, dim, depth, heads, mlp_dim, pool = 'cls', dim_head = 64, dropout = 0., emb_dropout = 0.):
+ super().__init__()
+ assert pool in {'cls', 'mean'}, 'pool type must be either cls (cls token) or mean (mean pooling)'
+
+ self.num_patches=num_patches
+ self.pos_embedding = nn.Parameter(torch.randn(1, num_patches + 1, dim))
+ self.cls_token = nn.Parameter(torch.randn(1, 1, dim))
+ self.dropout = nn.Dropout(emb_dropout)
+
+ self.transformer = Transformer(dim, depth, heads, dim_head, mlp_dim, dropout)
+ self.freq_embedding = nn.Sequential(nn.LayerNorm(dim),nn.Linear(dim,dim))
+ self.pool = pool
+ self.to_latent = nn.Identity()
+ self.LN = nn.LayerNorm(dim)
+
+ def forward(self, x,ft_t):
+ b, n, _ = x.shape #batch,num_patches,channels #
+ cls_tokens = repeat(self.cls_token, '() n d -> b n d', b = b)
+
+ ft_t = self.freq_embedding(ft_t)
+ x +=ft_t.unsqueeze(1)
+ x = torch.cat((cls_tokens, x), dim=1)
+ x += self.pos_embedding[:, :(n + 1)]
+
+ # x = torch.cat((x,ft_t), dim=1)
+ x = self.dropout(x)
+ x = self.transformer(x, mask=None)
+ x = x.mean(dim = 1) if self.pool == 'mean' else x[:, 0]
+ x = self.to_latent(x)
+ x = self.LN(x)
+
+ return x, None
+
+# =============================================================================
+# FTCN-specific Transformer Classes
+# =============================================================================
+
+class SpatialTransformerE(nn.Module):
+ def __init__(self, spatial_size=14, time_size = 16, in_channels = 1024, num_parts=5):
+ super().__init__()
+ self.num_parts = num_parts
+ self.in_channels = in_channels
+ default_params= dict(
+ dim=self.in_channels, depth=1, heads=16, mlp_dim=2048, dropout=0.1, emb_dropout=0.1,
+ num_patches = spatial_size ** 2, num_classes = 1
+ )
+ self.num_patches = spatial_size ** 2
+ self.freq_embedding = nn.Linear(2048,1024)
+ self.freq_embedding.weight.data.normal_(mean=0.0, std=0.02)
+ self.freq_embedding.bias.data.zero_()
+ self.pool = nn.AvgPool3d((time_size, 1, 1))
+ self.spatial_T = SpatialTransformer( **default_params )
+
+ def forward(self, x, ft, locs):
+ batch_size = x.shape[0]
+ x = self.pool(x)
+ if self.num_parts > 0:
+ ft = self.freq_embedding(ft.reshape(batch_size*self.num_parts,2048))
+ ft = ft.view(batch_size,self.num_parts,1024)
+ locs = locs.reshape(-1, self.num_parts, 2)
+ x = x.view(batch_size,self.num_patches,1024)
+ x = self.spatial_T(x,ft,locs)
+ return x
+
+class TransformerHead(nn.Module):
+ def __init__(self, spatial_size=7, time_size=16, in_channels=1024, num_parts=5):
+ super().__init__()
+ if my_cfg.model.inco.no_time_pool:
+ time_size = time_size * 2
+ patch_type = my_cfg.model.transformer.patch_type # time
+ if patch_type == "time":
+ self.pool = nn.AvgPool3d((1, spatial_size, spatial_size))
+ self.num_patches = time_size
+ elif patch_type == "spatial":
+ self.pool = nn.AvgPool3d((time_size, 1, 1))
+ self.num_patches = spatial_size ** 2
+ elif patch_type == "random":
+ self.pool = CenterPatchPool()
+ self.num_patches = time_size
+ elif patch_type == "random_avg":
+ self.pool = CenterAvgPool()
+ self.num_patches = time_size
+ elif patch_type == "all":
+ self.pool = nn.Identity()
+ self.num_patches = time_size * spatial_size * spatial_size
+ else:
+ raise NotImplementedError(patch_type)
+
+ self.dim = my_cfg.model.transformer.dim # False
+ if self.dim == -1:
+ self.dim = in_channels # 2048
+ my_cfg.model.transformer.dim = self.dim
+
+ self.in_channels = in_channels
+
+ if self.dim != self.in_channels:
+ self.fc = nn.Linear(self.in_channels, self.dim)
+
+ default_params = dict(
+ dim=self.dim, depth=6, heads=16, mlp_dim=2048, dropout=0.1, emb_dropout=0.1,
+ )
+ params = my_cfg.model.transformer.to_dict()
+ for key in default_params:
+ if key in params:
+ default_params[key] = params[key]
+
+ self.time_T = TimeTransformer(
+ num_patches=self.num_patches, num_classes=1, **default_params
+ )
+
+ self.sigmoid = nn.Sigmoid()
+
+ def forward(self, x,ft_t):
+ x = self.pool(x)
+ x = x.reshape(-1, self.in_channels, self.num_patches)
+ x = x.permute(0, 2, 1)
+ if self.dim != self.in_channels:
+ x = self.fc(x.reshape(-1, self.in_channels))
+ x = x.reshape(-1, self.num_patches, self.dim)
+
+ x = self.time_T(x,ft_t)
+ return x
\ No newline at end of file
diff --git a/clean/video/pwtf_dvd/inference/model/video_encoder.py b/clean/video/pwtf_dvd/inference/model/video_encoder.py
new file mode 100644
index 0000000000000000000000000000000000000000..e512f03f456c6c0351ff82173adaa1a4e1f83fa8
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/model/video_encoder.py
@@ -0,0 +1,227 @@
+import gc
+import math
+
+# Simplified config for inference
+config_text = """
+DATA:
+ NUM_FRAMES: 8
+ SAMPLING_RATE: 8
+ TEST_CROP_SIZE: 256
+ INPUT_CHANNEL_NUM: [3]
+RESNET:
+ ZERO_INIT_FINAL_BN: True
+ WIDTH_PER_GROUP: 64
+ NUM_GROUPS: 1
+ DEPTH: 50
+ TRANS_FUNC: bottleneck_transform
+ STRIDE_1X1: False
+ NUM_BLOCK_TEMP_KERNEL: [[3], [4], [6], [3]]
+NONLOCAL:
+ LOCATION: [[[]], [[]], [[]], [[]]]
+ GROUP: [[1], [1], [1], [1]]
+ INSTANTIATION: softmax
+BN:
+ USE_PRECISE_STATS: True
+ NUM_BATCHES_PRECISE: 200
+MODEL:
+ NUM_CLASSES: 1
+ ARCH: i3d
+ MODEL_NAME: ResNet
+ DROPOUT_RATE: 0.1
+ HEAD_ACT: sigmoid
+TEST:
+ ENABLE: True
+ DATASET: kinetics
+ BATCH_SIZE: 64
+DATA_LOADER:
+ NUM_WORKERS: 8
+ PIN_MEMORY: True
+NUM_GPUS: 8
+NUM_SHARDS: 1
+RNG_SEED: 0
+OUTPUT_DIR: .
+"""
+
+# from .f3net import FAD_Head
+from slowfast.models.video_model_builder import ResNet as ResNetOri
+from slowfast.config.defaults import get_cfg
+import torch
+from torch import nn
+from config_ftcn import config as my_cfg
+from inspect import signature
+# Removed TimeTransformer import - not used directly in this file
+# Removed random import - not used in inference
+
+my_cfg.init_with_yaml()
+my_cfg.update_with_yaml("ftcn_tt.yaml")
+my_cfg.freeze()
+
+
+
+class CenterPatchPool(nn.Module):
+ """Simplified patch pooling for inference - always use center patch"""
+ def __init__(self):
+ super().__init__()
+
+ def forward(self, x):
+ # batch,channel,16,7x7
+ b, c, t, h, w = x.shape
+ x = x.reshape(b, c, t, h * w)
+ idx = h * w // 2 # Always use center patch for inference
+ x = x[..., idx]
+ return x
+
+
+def valid_idx(idx, h):
+ i = idx // h
+ j = idx % h
+ if j == 0 or i == h - 1 or j == h - 1:
+ return False
+ else:
+ return True
+
+
+class CenterAvgPool(nn.Module):
+ """Simplified average pooling for inference - use all valid patches"""
+ def __init__(self):
+ super().__init__()
+
+ def forward(self, x):
+ # batch,channel,16,7x7
+ b, c, t, h, w = x.shape
+ x = x.reshape(b, c, t, h * w)
+ candidates = list(range(h * w))
+ candidates = [idx for idx in candidates if valid_idx(idx, h)]
+ x = x[..., candidates].mean(-1)
+ return x
+
+
+
+# Removed duplicate TransformerHead class - using the one from temporal_transformer.py
+
+
+parameters = [parameter for parameter in signature(nn.Conv3d).parameters]
+
+spatial_count = my_cfg.model.inco.spatial_count
+keep_stride_count = my_cfg.model.inco.keep_stride_count
+
+
+def temporal_only_conv(module, name, removed, stride_removed=0):
+ """
+ Recursively put desired batch norm in nn.module module.
+
+ set module = net to start code.
+ """
+ # go through all attributes of module nn.module (e.g. network or layer) and put batch norms if present
+ for attr_str in dir(module):
+ sub_module = getattr(module, attr_str)
+ if type(sub_module) == nn.Conv3d:
+ target_spatial_size = 1
+ predefine_padding = {1: 0, 3: 1, 5: 2, 7: 3}
+ kernel_size = list(sub_module.kernel_size)
+ assert kernel_size[1] == kernel_size[2]
+ stride = sub_module.stride
+ extra = None
+ if stride[1] == stride[2] == 2:
+ stride_removed += 1
+ if stride_removed > keep_stride_count:
+ stride = [1, 1, 1]
+ extra = nn.MaxPool3d((1, 2, 2))
+
+ if kernel_size[1] == 1 and extra is None:
+ continue
+ padding = list(sub_module.padding)
+
+ kernel_size[1] = kernel_size[2] = target_spatial_size
+ padding[1] = padding[2] = predefine_padding[target_spatial_size]
+ if 'device' in parameters:
+ parameters.remove('device')
+ if 'dtype' in parameters:
+ parameters.remove('dtype')
+ param_dict = {key: getattr(sub_module, key) for key in parameters}
+
+ param_dict.update(kernel_size=kernel_size, padding=padding, stride=stride)
+
+ conv = nn.Conv3d(**param_dict)
+
+ new_module = conv
+
+ removed += 1
+ if removed > spatial_count:
+ setattr(module, attr_str, new_module)
+ if extra is not None:
+ if attr_str == "conv":
+ bn_str = "bn"
+ else:
+ bn_str = f"{attr_str}_bn"
+ bn_module = getattr(module, bn_str)
+ assert isinstance(bn_module, nn.BatchNorm3d)
+ new_bn_module = nn.Sequential(bn_module, extra)
+ setattr(module, bn_str, new_bn_module)
+ else:
+ print("keep spatial")
+ elif type(sub_module) == nn.Dropout:
+ new_module = nn.Dropout(p=0.5)
+ setattr(module, attr_str, new_module)
+ if my_cfg.model.inco.no_time_pool:
+ if type(sub_module) == nn.MaxPool3d:
+ kernel_size = list(sub_module.kernel_size)
+ if kernel_size[0] == 2:
+ kernel_size[0] = 1
+ setattr(module, attr_str, nn.MaxPool3d(kernel_size))
+ elif type(sub_module) == nn.AvgPool3d:
+ kernel_size = list(sub_module.kernel_size)
+ kernel_size[0] = 2 * kernel_size[0]
+ setattr(module, attr_str, nn.AvgPool3d(kernel_size))
+
+ # iterate through immediate child modules. Note, the recursion is done by our code no need to use named_modules()
+ old_name = name
+ for name, immediate_child_module in module.named_children():
+ removed, stride_removed = temporal_only_conv(
+ immediate_child_module, old_name + "." + name, removed, stride_removed
+ )
+ return removed, stride_removed
+
+
+class I3D8x8(nn.Module):
+ def __init__(self) -> None:
+ super(I3D8x8, self).__init__()
+ cfg = get_cfg()
+ cfg.merge_from_str(config_text)
+ cfg.NUM_GPUS = 1
+ cfg.TEST.BATCH_SIZE = 1
+ cfg.TRAIN.BATCH_SIZE = 1
+
+ cfg.DATA.NUM_FRAMES = my_cfg.clip_size
+ SOLVER = my_cfg.model.inco.SOLVER
+ if SOLVER is not None:
+ for key, val in SOLVER.to_dict().items():
+ old_val = getattr(cfg.SOLVER, key)
+ val = type(old_val)(val)
+ setattr(cfg.SOLVER, key, val)
+
+ if my_cfg.model.inco.i3d_routine:
+ self.cfg = cfg
+ self.resnet = ResNetOri(cfg)
+ temporal_only_conv(self.resnet, "model", 0)
+
+ stop_point = my_cfg.model.transformer.stop_point
+
+ for i in [5, 4, 3]:
+ if stop_point <= i:
+ setattr(self.resnet, f"s{i}", nn.Identity())
+ if stop_point == 3:
+ setattr(self.resnet, f"pathway0_pool", nn.Identity())
+ gc.collect()
+ torch.cuda.empty_cache()
+
+ def forward(
+ self,
+ images, ft_features=None,
+ freeze_backbone=False
+ ):
+ assert not freeze_backbone
+
+ inputs = [images]
+ pred = self.resnet(inputs, ft_features)
+ return pred
diff --git a/clean/video/pwtf_dvd/inference/root_setting.yaml b/clean/video/pwtf_dvd/inference/root_setting.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..b66140f63b9d87e5a977503d7eaf65fdc5510f42
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/root_setting.yaml
@@ -0,0 +1,192 @@
+# this is the root setting of all setting and will be loaded in first place
+# the loading sequence is root_setting -> specific setting
+# -> manully overided setting -> computed setting in finalize_config()
+# which means access config before finalize can be dangerous
+# always remember to add a space after :
+
+setting_name: base
+test_dataset_type: null
+clip_size: 8
+var_clip_size: -1
+
+model:
+ teacher: null
+ pretrained: null
+ fc_weight: null
+ fc_bias: null
+ patch:
+ name: null
+ fc_only: false
+ feat_type: image
+ tester: null
+ tester_path: null
+ tester_data_mode: null
+ decodec:
+ reg_loss_type: l1
+ feat_loss_func: l1
+ dis_model: basic
+ gan_type: vanilla
+ inco:
+ kernel_size: 1
+ pool_ref_type: sum
+ temp_kernel_size: 3
+ spatial_sizes: []
+ spatial_count: 0
+ no_time_pool: false
+ keep_stride_count: 0
+ i3d_routine: true
+ SOLVER:
+ BASE_LR: 0.1
+ LR_POLICY: cosine
+ MAX_EPOCH: 196
+ MOMENTUM: 0.9
+ WEIGHT_DECAY: 1e-4
+ WARMUP_EPOCHS: 34.0
+ WARMUP_START_LR: 0.01
+ OPTIMIZING_METHOD: sgd
+ transformer:
+ patch_type: null #time,spatial,all
+ dim: -1
+ stop_point: 6
+ random_select: true
+ k: 8
+ sigmoid_before: false
+ denoise:
+ layers: []
+
+test_on_train: false
+
+test: false
+debug: false
+pre_load_data: false
+# for better compatiable with philly and potential running enviroment
+# all path under path should be rel_path w.r.t the config.py
+# and the abspath will be compute when finalize
+
+# python -m torch.distributed.launch --nproc_per_node=2 main.py --setting get_all_datas_id_emb_old.yaml main.py
+# --config trainer.default.log_step=1 trainer.default.sample_step=20
+
+trash_face: false
+
+strategies: []
+branches: ["continuous_same","continuous_diff","discontinuous"]
+epoch: -1
+
+reg_weight: 10
+class_weight: 1
+final_weight: 1
+feat_weight: 0
+gan_weight: 0
+
+noise_only: false
+error_only: false
+force_ds_scale: 1.0
+
+path:
+ model_dir: ../checkpoint
+ pretrain_dir: ../pretrain
+ log_dir: ../checkpoint
+ data_dir: ../data
+ precomputed_dir: ../precomputed
+ test_data_dir: null
+ extra_data_dir: ../extra_data
+ lmdb_dir: null
+
+patch_input: false
+input_noise: false
+mask_direct: false
+max_to_keep: 50
+base_count: -1
+enable_lmdb_cache: false
+
+aug_in_train: true
+aug_in_test: false
+vis_in_train: true
+
+data_mode: "image"
+data_source: "zip"
+
+aug:
+ flip_prob: 0
+ reverse_prob: 0
+ gray_prob: 0
+ size_aug_prob: 0
+ quantify_prob: 0
+ quantify_steps: [16,32]
+ min_size: 64
+ max_size: 256
+ jpeg_aug_prob: 0
+ dxy_gauss_prob: 0
+ dxy_gauss_scale: 0
+ min_quality: 60
+ max_quality: 100
+ gaussain: false
+ need_img_degrade: true
+ need_mask_distortion: true
+ need_color_match: true
+ feather_range: [0.2,0.2]
+ adaptive_clip_size: false
+ clip_sizes: null
+ cutout: 0
+ earse: 0
+ types: null
+ earse_type: null
+ time_earse_prob: 0
+ time_earse_type: null
+ jitter_prob: 0
+ test_types: null
+ raw_prob: 0
+ bi_types: null
+ bi_count: 1
+ face_sources: null
+ inplace_types: null
+ no_poisson_prob: 0
+ blend:
+ pseudo_prob: 0.5
+ from_real_prob: 1
+ skip_prob: 0
+ shuffle_prob: 0
+ multi_prob: 0
+ multi_config:
+ from_real_prob: 1
+ self_prob: 1
+ self:
+ one: 0
+ continuity: 1
+ other:
+ one: 0
+ all: 0
+ continuity: 1
+ celeb_prob: 0
+ fft:
+ type: null
+ fad:
+ type: null
+ flag: high
+ tta:
+ type: null
+ param: null
+
+
+batch_size: 64
+test_batch_size: 64
+imsize: 256
+next_frame_rate: 0.5
+trainer:
+ default:
+ apex_option: O0
+ n_worker: 12
+ optim: adam
+ model_save_step: 1000
+ log_step: 25
+ sample_step: 1000
+ init_lr: 3e-4
+ validation_step: 5000
+ test_sample_step: 20
+ one_test_step: 500
+ test_freq: 1
+ total_step: 100000
+ lr_step: 20000
+ freeze_backbone_step: 0
+ total_epoch: 200
+fetch_method: prefetch
\ No newline at end of file
diff --git a/clean/video/pwtf_dvd/inference/setting/ftcn_tt.yaml b/clean/video/pwtf_dvd/inference/setting/ftcn_tt.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..a6bb2fbe8b9c92f7d9260ea205ac714c5b3c6b4a
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/setting/ftcn_tt.yaml
@@ -0,0 +1,114 @@
+# this is the root setting of all setting and will be loaded in first place
+# the loading sequence is root_setting -> specific setting
+# -> manully overided setting -> computed setting in finalize_config()
+# which means access config before finalize can be dangerous
+# always remember to add a space after ":"
+
+setting_name: base
+data_mode: image
+# for better compatiable with philly and potential running enviroment
+# all path under path should be rel_path w.r.t the config.py
+# and the abspath will be compute when finalize
+
+# python -m torch.distributed.launch --nproc_per_node=2 main.py --setting naive_raw.yaml
+# --config trainer.default.log_step=1 trainer.default.sample_step=20
+strategies: ["scale_mean","scale_0","scale_1","scale_2","scale_3"]
+mask_direct: true
+
+clip_size: 32
+
+reg_weight: 1
+class_weight: 1
+final_weight: 1
+model:
+ inco:
+ spatial_count: 0
+ SOLVER:
+ BASE_LR: 0.1
+ LR_POLICY: cosine
+ MAX_EPOCH: 100
+ MOMENTUM: 0.9
+ WEIGHT_DECAY: 1e-4
+ WARMUP_EPOCHS: 10
+ WARMUP_START_LR: 0.01
+ OPTIMIZING_METHOD: sgd
+ transformer:
+ patch_type: time
+ stop_point: 5
+ depth: 1
+
+path:
+ model_dir: ../checkpoint
+ pretrain_dir: ../pretrain
+ log_dir: ../checkpoint
+ data_dir: host:lmdb_dir
+ precomputed_dir: null
+
+trainer_type: YL3DIncoPolicyS
+dataset_type: YL_3D_INCO_BASE_ZIP_PNG_S
+classifier_type: i3d_temporal_var_fix_dropout_tt_cfg
+
+imsize: 224
+base_count: 12
+aug_in_train: true
+test_on_train: true
+
+next_frame_rate: 0.0
+aug:
+ min_size: 64
+ max_size: 317
+ min_quality: 60
+ max_quality: 100
+ need_img_degrade: false
+ need_mask_distortion: true
+ need_color_match: true
+ max_step: 4
+ compression: false
+ cutout: 0
+ earse: 1
+ aug_prob: 0
+ types: ["C23_NOISE"]
+ earse_type: ["strong_black"]
+
+dataset:
+ real_train:
+ original_c23: 1
+ fake_train:
+ NeuralTextures_c23: 1
+ Face2Face_c23: 1
+ FaceSwap_c23: 1
+ Deepfakes_c23: 1
+ aug_online:
+ empty: 1
+ tests:
+ NeuralTextures_c23: ["NeuralTextures_c23"]
+ Face2Face_c23: ["Face2Face_c23"]
+ FaceSwap_c23: ["FaceSwap_c23"]
+ Deepfakes_c23: ["Deepfakes_c23"]
+
+max_to_keep: 100
+
+data_source: lmdb
+
+trainer:
+ default:
+ apex_option: O0
+ batch_size: 16
+ test_batch_size: 8
+ model_save_step: 10000
+ log_step: 200
+ sample_step: 1000
+ init_lr: 3e-4
+ total_epoch: 1000
+ one_test_step: 200
+ detach_step: 5000
+ validation_step: 10000
+ freeze_backbone_step: 0
+ total_step: 200000
+ lr_step: 100000
+
+
+
+#classifier:
+# default:
+# pretrained: false
\ No newline at end of file
diff --git a/clean/video/pwtf_dvd/inference/slowfast/__init__.py b/clean/video/pwtf_dvd/inference/slowfast/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..b65a8f9dc0cd5092e2dc879f6bb4aba8fafbb092
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/__init__.py
@@ -0,0 +1,6 @@
+#!/usr/bin/env python3
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+
+from slowfast.utils.env import setup_environment
+
+setup_environment()
diff --git a/clean/video/pwtf_dvd/inference/slowfast/config/__init__.py b/clean/video/pwtf_dvd/inference/slowfast/config/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..8dbe96a785072a24a9bcc4841a1934024f2b06a1
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/config/__init__.py
@@ -0,0 +1,2 @@
+#!/usr/bin/env python3
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
diff --git a/clean/video/pwtf_dvd/inference/slowfast/config/custom_config.py b/clean/video/pwtf_dvd/inference/slowfast/config/custom_config.py
new file mode 100644
index 0000000000000000000000000000000000000000..8131da2951d8cb629f664b39da4675d0ae5adee5
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/config/custom_config.py
@@ -0,0 +1,9 @@
+#!/usr/bin/env python3
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+
+"""Add custom configs and default values"""
+
+
+def add_custom_config(_C):
+ # Add your own customized configs.
+ pass
diff --git a/clean/video/pwtf_dvd/inference/slowfast/config/defaults.py b/clean/video/pwtf_dvd/inference/slowfast/config/defaults.py
new file mode 100644
index 0000000000000000000000000000000000000000..73f0f562c3f95d92382d364c8a8ccbe5b6c27ca3
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/config/defaults.py
@@ -0,0 +1,816 @@
+#!/usr/bin/env python3
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+
+"""Configs."""
+import yaml
+from fvcore.common.config import CfgNode as CfgNodeOri
+
+from . import custom_config
+def load_yaml_with_base(text: str, allow_unsafe: bool = False):
+ """
+ Just like `yaml.load(open(filename))`, but inherit attributes from its
+ `_BASE_`.
+ Args:
+ text (str): the file name of the current config. Will be used to
+ find the base config file.
+ allow_unsafe (bool): whether to allow loading the config file with
+ `yaml.unsafe_load`.
+ Returns:
+ (dict): the loaded yaml
+ """
+ cfg = yaml.load(text, Loader=yaml.FullLoader)
+ return cfg
+class CfgNode(CfgNodeOri):
+ def merge_from_str(self, text, allow_unsafe=False):
+ loaded_cfg = load_yaml_with_base(text, allow_unsafe=allow_unsafe)
+ loaded_cfg = type(self)(loaded_cfg)
+ self.merge_from_other_cfg(loaded_cfg)
+
+# -----------------------------------------------------------------------------
+# Config definition
+# -----------------------------------------------------------------------------
+_C = CfgNode()
+
+
+# ---------------------------------------------------------------------------- #
+# Batch norm options
+# ---------------------------------------------------------------------------- #
+_C.BN = CfgNode()
+
+# Precise BN stats.
+_C.BN.USE_PRECISE_STATS = False
+
+# Number of samples use to compute precise bn.
+_C.BN.NUM_BATCHES_PRECISE = 200
+
+# Weight decay value that applies on BN.
+_C.BN.WEIGHT_DECAY = 0.0
+
+# Norm type, options include `batchnorm`, `sub_batchnorm`, `sync_batchnorm`
+_C.BN.NORM_TYPE = "batchnorm"
+
+# Parameter for SubBatchNorm, where it splits the batch dimension into
+# NUM_SPLITS splits, and run BN on each of them separately independently.
+_C.BN.NUM_SPLITS = 1
+
+# Parameter for NaiveSyncBatchNorm3d, where the stats across `NUM_SYNC_DEVICES`
+# devices will be synchronized.
+_C.BN.NUM_SYNC_DEVICES = 1
+
+
+# ---------------------------------------------------------------------------- #
+# Training options.
+# ---------------------------------------------------------------------------- #
+_C.TRAIN = CfgNode()
+
+# If True Train the model, else skip training.
+_C.TRAIN.ENABLE = True
+
+# Dataset.
+_C.TRAIN.DATASET = "kinetics"
+
+# Total mini-batch size.
+_C.TRAIN.BATCH_SIZE = 64
+
+_C.TRAIN.SPLIT = "train_subset2.pth"
+# Evaluate model on test data every eval period epochs.
+_C.TRAIN.EVAL_PERIOD = 1
+
+# Save model checkpoint every checkpoint period epochs.
+_C.TRAIN.CHECKPOINT_PERIOD = 1
+
+# Save model checkpoint every checkpoint period iters.
+_C.TRAIN.CHECKPOINT_PERIOD_BY_ITER = 500
+
+
+# Resume training from the latest checkpoint in the output directory.
+_C.TRAIN.AUTO_RESUME = True
+
+# Path to the checkpoint to load the initial weight.
+_C.TRAIN.CHECKPOINT_FILE_PATH = ""
+
+# Checkpoint types include `caffe2` or `pytorch`.
+_C.TRAIN.CHECKPOINT_TYPE = "pytorch"
+
+# If True, perform inflation when loading checkpoint.
+_C.TRAIN.CHECKPOINT_INFLATE = False
+
+
+# ---------------------------------------------------------------------------- #
+# Testing options
+# ---------------------------------------------------------------------------- #
+_C.TEST = CfgNode()
+
+# If True test the model, else skip the testing.
+_C.TEST.ENABLE = True
+
+# Dataset for testing.
+_C.TEST.DATASET = "kinetics"
+
+_C.TEST.SPLIT = "test_subset2.pth"
+# Total mini-batch size
+_C.TEST.BATCH_SIZE = 8
+
+# Path to the checkpoint to load the initial weight.
+_C.TEST.CHECKPOINT_FILE_PATH = ""
+
+# Number of clips to sample from a video uniformly for aggregating the
+# prediction results.
+_C.TEST.NUM_ENSEMBLE_VIEWS = 10
+
+# Number of crops to sample from a frame spatially for aggregating the
+# prediction results.
+_C.TEST.NUM_SPATIAL_CROPS = 3
+
+# Checkpoint types include `caffe2` or `pytorch`.
+_C.TEST.CHECKPOINT_TYPE = "pytorch"
+# Path to saving prediction results file.
+_C.TEST.SAVE_RESULTS_PATH = ""
+# -----------------------------------------------------------------------------
+# ResNet options
+# -----------------------------------------------------------------------------
+_C.RESNET = CfgNode()
+
+# Transformation function.
+_C.RESNET.TRANS_FUNC = "bottleneck_transform"
+
+# Number of groups. 1 for ResNet, and larger than 1 for ResNeXt).
+_C.RESNET.NUM_GROUPS = 1
+
+# Width of each group (64 -> ResNet; 4 -> ResNeXt).
+_C.RESNET.WIDTH_PER_GROUP = 64
+
+# Apply relu in a inplace manner. ########## FIxed by TH for training FT #################
+_C.RESNET.INPLACE_RELU = False # Default True for C2 and torch.
+
+# Apply stride to 1x1 conv.
+_C.RESNET.STRIDE_1X1 = False
+
+# If true, initialize the gamma of the final BN of each block to zero.
+_C.RESNET.ZERO_INIT_FINAL_BN = False
+
+# Number of weight layers.
+_C.RESNET.DEPTH = 50
+
+
+# label of branchs
+_C.RESNET.LABELS = ["continus","discontinus"]
+
+# If the current block has more than NUM_BLOCK_TEMP_KERNEL blocks, use temporal
+# kernel of 1 for the rest of the blocks.
+_C.RESNET.NUM_BLOCK_TEMP_KERNEL = [[3], [4], [6], [3]]
+
+# Size of stride on different res stages.
+_C.RESNET.SPATIAL_STRIDES = [[1], [2], [2], [2]]
+
+# Size of dilation on different res stages.
+_C.RESNET.SPATIAL_DILATIONS = [[1], [1], [1], [1]]
+
+
+# -----------------------------------------------------------------------------
+# Nonlocal options
+# -----------------------------------------------------------------------------
+_C.NONLOCAL = CfgNode()
+
+# Index of each stage and block to add nonlocal layers.
+_C.NONLOCAL.LOCATION = [[[]], [[]], [[]], [[]]]
+
+# Number of group for nonlocal for each stage.
+_C.NONLOCAL.GROUP = [[1], [1], [1], [1]]
+
+# Instatiation to use for non-local layer.
+_C.NONLOCAL.INSTANTIATION = "dot_product"
+
+
+# Size of pooling layers used in Non-Local.
+_C.NONLOCAL.POOL = [
+ # Res2
+ [[1, 2, 2], [1, 2, 2]],
+ # Res3
+ [[1, 2, 2], [1, 2, 2]],
+ # Res4
+ [[1, 2, 2], [1, 2, 2]],
+ # Res5
+ [[1, 2, 2], [1, 2, 2]],
+]
+
+# -----------------------------------------------------------------------------
+# Model options
+# -----------------------------------------------------------------------------
+_C.MODEL = CfgNode()
+
+# Model architecture.
+_C.MODEL.ARCH = "slowfast"
+
+# Model name
+_C.MODEL.MODEL_NAME = "SlowFast"
+
+# The number of classes to predict for the model.
+_C.MODEL.NUM_CLASSES = 400
+
+# Loss function.
+_C.MODEL.LOSS_FUNC = "cross_entropy"
+
+_C.MODEL.MASK_WEIGHT = 100
+
+_C.MODEL.CLASS_WEIGHT = 1
+
+# Model architectures that has one single pathway.
+_C.MODEL.SINGLE_PATHWAY_ARCH = ["c2d", "i3d", "slow"]
+
+# Model architectures that has multiple pathways.
+_C.MODEL.MULTI_PATHWAY_ARCH = ["slowfast"]
+
+# Dropout rate before final projection in the backbone.
+_C.MODEL.DROPOUT_RATE = 0.5
+
+# The std to initialize the fc layer(s).
+_C.MODEL.FC_INIT_STD = 0.01
+
+# Activation layer for the output head.
+_C.MODEL.HEAD_ACT = "softmax"
+
+
+# -----------------------------------------------------------------------------
+# SlowFast options
+# -----------------------------------------------------------------------------
+_C.SLOWFAST = CfgNode()
+
+# Corresponds to the inverse of the channel reduction ratio, $\beta$ between
+# the Slow and Fast pathways.
+_C.SLOWFAST.BETA_INV = 8
+
+# Corresponds to the frame rate reduction ratio, $\alpha$ between the Slow and
+# Fast pathways.
+_C.SLOWFAST.ALPHA = 8
+
+# Ratio of channel dimensions between the Slow and Fast pathways.
+_C.SLOWFAST.FUSION_CONV_CHANNEL_RATIO = 2
+
+# Kernel dimension used for fusing information from Fast pathway to Slow
+# pathway.
+_C.SLOWFAST.FUSION_KERNEL_SZ = 5
+
+
+# -----------------------------------------------------------------------------
+# Data options
+# -----------------------------------------------------------------------------
+_C.DATA = CfgNode()
+
+# The path to the data directory.
+_C.DATA.PATH_TO_DATA_DIR = ""
+
+_C.DATA.DATASET = "faceforensics"
+
+_C.DATA.MODE = ""
+
+_C.DATA.ADAPTIVE = False
+
+_C.DATA.SCALE = 1.0
+# The separator used between path and label.
+_C.DATA.PATH_LABEL_SEPARATOR = " "
+
+# Video path prefix if any.
+_C.DATA.PATH_PREFIX = ""
+
+# The spatial crop size of the input clip.
+_C.DATA.CROP_SIZE = 224
+
+# The number of frames of the input clip.
+_C.DATA.NUM_FRAMES = 8
+
+_C.DATA.NUM_FRAMES_RANGE = [1,2,3,4,5,6,7,8]
+
+# The video sampling rate of the input clip.
+_C.DATA.SAMPLING_RATE = 8
+
+# The mean value of the video raw pixels across the R G B channels.
+_C.DATA.MEAN = [0.45, 0.45, 0.45]
+# List of input frame channel dimensions.
+
+_C.DATA.INPUT_CHANNEL_NUM = [12, 12]
+
+# The std value of the video raw pixels across the R G B channels.
+_C.DATA.STD = [0.225, 0.225, 0.225]
+
+# The spatial augmentation jitter scales for training.
+_C.DATA.TRAIN_JITTER_SCALES = [256, 320]
+
+# The spatial crop size for training.
+_C.DATA.TRAIN_CROP_SIZE = 224
+
+# The spatial crop size for testing.
+_C.DATA.TEST_CROP_SIZE = 256
+
+# Input videos may has different fps, convert it to the target video fps before
+# frame sampling.
+_C.DATA.TARGET_FPS = 30
+
+# Decoding backend, options include `pyav` or `torchvision`
+_C.DATA.DECODING_BACKEND = "pyav"
+
+# if True, sample uniformly in [1 / max_scale, 1 / min_scale] and take a
+# reciprocal to get the scale. If False, take a uniform sample from
+# [min_scale, max_scale].
+_C.DATA.INV_UNIFORM_SAMPLE = False
+
+# If True, perform random horizontal flip on the video frames during training.
+_C.DATA.RANDOM_FLIP = True
+
+# If True, calculdate the map as metric.
+_C.DATA.MULTI_LABEL = False
+
+# Method to perform the ensemble, options include "sum" and "max".
+_C.DATA.ENSEMBLE_METHOD = "sum"
+
+# If True, revert the default input channel (RBG <-> BGR).
+_C.DATA.REVERSE_INPUT_CHANNEL = False
+
+
+# ---------------------------------------------------------------------------- #
+# Optimizer options
+# ---------------------------------------------------------------------------- #
+_C.SOLVER = CfgNode()
+
+# Base learning rate.
+_C.SOLVER.BASE_LR = 0.1
+
+# Learning rate policy (see utils/lr_policy.py for options and examples).
+_C.SOLVER.LR_POLICY = "cosine"
+
+# Exponential decay factor.
+_C.SOLVER.GAMMA = 0.1
+
+# Step size for 'exp' and 'cos' policies (in epochs).
+_C.SOLVER.STEP_SIZE = 1
+
+# Steps for 'steps_' policies (in epochs).
+_C.SOLVER.STEPS = []
+
+# Learning rates for 'steps_' policies.
+_C.SOLVER.LRS = []
+
+# Maximal number of epochs.
+_C.SOLVER.MAX_EPOCH = 300
+
+# Momentum.
+_C.SOLVER.MOMENTUM = 0.9
+
+# Momentum dampening.
+_C.SOLVER.DAMPENING = 0.0
+
+# Nesterov momentum.
+_C.SOLVER.NESTEROV = True
+
+# L2 regularization.
+_C.SOLVER.WEIGHT_DECAY = 1e-4
+
+# Start the warm up from SOLVER.BASE_LR * SOLVER.WARMUP_FACTOR.
+_C.SOLVER.WARMUP_FACTOR = 0.1
+
+# Gradually warm up the SOLVER.BASE_LR over this number of epochs.
+_C.SOLVER.WARMUP_EPOCHS = 0.0
+
+# The start learning rate of the warm up.
+_C.SOLVER.WARMUP_START_LR = 0.01
+
+# Optimization method.
+_C.SOLVER.OPTIMIZING_METHOD = "sgd"
+
+_C.SOLVER.LR_STEP = 50000
+
+_C.SOLVER.TOTAL_STEP = 200000
+
+_C.SOLVER.FREEZE_STEP = 10000
+
+
+# ---------------------------------------------------------------------------- #
+# Misc options
+# ---------------------------------------------------------------------------- #
+
+# Number of GPUs to use (applies to both training and testing).
+_C.NUM_GPUS = 1
+
+# Number of machine to use for the job.
+_C.NUM_SHARDS = 1
+
+# The index of the current machine.
+_C.SHARD_ID = 0
+
+# Output basedir.
+_C.OUTPUT_DIR = "./tmp"
+
+# train module
+_C.TRAIN_MODULE= "train_unet_by_iter"
+
+# Note that non-determinism may still be present due to non-deterministic
+# operator implementations in GPU operator libraries.
+_C.RNG_SEED = 1
+
+# Log period in iters.
+_C.LOG_PERIOD = 10
+
+# If True, log the model info.
+_C.LOG_MODEL_INFO = True
+
+# Distributed backend.
+_C.DIST_BACKEND = "nccl"
+
+# ---------------------------------------------------------------------------- #
+# Benchmark options
+# ---------------------------------------------------------------------------- #
+_C.BENCHMARK = CfgNode()
+
+# Number of epochs for data loading benchmark.
+_C.BENCHMARK.NUM_EPOCHS = 5
+
+# Log period in iters for data loading benchmark.
+_C.BENCHMARK.LOG_PERIOD = 100
+
+# If True, shuffle dataloader for epoch during benchmark.
+_C.BENCHMARK.SHUFFLE = True
+
+
+# ---------------------------------------------------------------------------- #
+# Common train/test data loader options
+# ---------------------------------------------------------------------------- #
+_C.DATA_LOADER = CfgNode()
+
+# Number of data loader workers per training process.
+_C.DATA_LOADER.NUM_WORKERS = 8
+
+# Load data to pinned host memory.
+_C.DATA_LOADER.PIN_MEMORY = True
+
+# Enable multi thread decoding.
+_C.DATA_LOADER.ENABLE_MULTI_THREAD_DECODE = False
+
+
+# ---------------------------------------------------------------------------- #
+# Detection options.
+# ---------------------------------------------------------------------------- #
+_C.DETECTION = CfgNode()
+
+# Whether enable video detection.
+_C.DETECTION.ENABLE = False
+
+# Aligned version of RoI. More details can be found at slowfast/models/head_helper.py
+_C.DETECTION.ALIGNED = True
+
+# Spatial scale factor.
+_C.DETECTION.SPATIAL_SCALE_FACTOR = 16
+
+# RoI tranformation resolution.
+_C.DETECTION.ROI_XFORM_RESOLUTION = 7
+
+
+# -----------------------------------------------------------------------------
+# AVA Dataset options
+# -----------------------------------------------------------------------------
+_C.AVA = CfgNode()
+
+# Directory path of frames.
+_C.AVA.FRAME_DIR = "/mnt/fair-flash3-east/ava_trainval_frames.img/"
+
+# Directory path for files of frame lists.
+_C.AVA.FRAME_LIST_DIR = (
+ "/mnt/vol/gfsai-flash3-east/ai-group/users/haoqifan/ava/frame_list/"
+)
+
+# Directory path for annotation files.
+_C.AVA.ANNOTATION_DIR = (
+ "/mnt/vol/gfsai-flash3-east/ai-group/users/haoqifan/ava/frame_list/"
+)
+
+# Filenames of training samples list files.
+_C.AVA.TRAIN_LISTS = ["train.csv"]
+
+# Filenames of test samples list files.
+_C.AVA.TEST_LISTS = ["val.csv"]
+
+# Filenames of box list files for training. Note that we assume files which
+# contains predicted boxes will have a suffix "predicted_boxes" in the
+# filename.
+_C.AVA.TRAIN_GT_BOX_LISTS = ["ava_train_v2.2.csv"]
+_C.AVA.TRAIN_PREDICT_BOX_LISTS = []
+
+# Filenames of box list files for test.
+_C.AVA.TEST_PREDICT_BOX_LISTS = ["ava_val_predicted_boxes.csv"]
+
+# This option controls the score threshold for the predicted boxes to use.
+_C.AVA.DETECTION_SCORE_THRESH = 0.9
+
+# If use BGR as the format of input frames.
+_C.AVA.BGR = False
+
+# Training augmentation parameters
+# Whether to use color augmentation method.
+_C.AVA.TRAIN_USE_COLOR_AUGMENTATION = False
+
+# Whether to only use PCA jitter augmentation when using color augmentation
+# method (otherwise combine with color jitter method).
+_C.AVA.TRAIN_PCA_JITTER_ONLY = True
+
+# Eigenvalues for PCA jittering. Note PCA is RGB based.
+_C.AVA.TRAIN_PCA_EIGVAL = [0.225, 0.224, 0.229]
+
+# Eigenvectors for PCA jittering.
+_C.AVA.TRAIN_PCA_EIGVEC = [
+ [-0.5675, 0.7192, 0.4009],
+ [-0.5808, -0.0045, -0.8140],
+ [-0.5836, -0.6948, 0.4203],
+]
+
+# Whether to do horizontal flipping during test.
+_C.AVA.TEST_FORCE_FLIP = False
+
+# Whether to use full test set for validation split.
+_C.AVA.FULL_TEST_ON_VAL = False
+
+# The name of the file to the ava label map.
+_C.AVA.LABEL_MAP_FILE = "ava_action_list_v2.2_for_activitynet_2019.pbtxt"
+
+# The name of the file to the ava exclusion.
+_C.AVA.EXCLUSION_FILE = "ava_val_excluded_timestamps_v2.2.csv"
+
+# The name of the file to the ava groundtruth.
+_C.AVA.GROUNDTRUTH_FILE = "ava_val_v2.2.csv"
+
+# Backend to process image, includes `pytorch` and `cv2`.
+_C.AVA.IMG_PROC_BACKEND = "cv2"
+
+# ---------------------------------------------------------------------------- #
+# Multigrid training options
+# See https://arxiv.org/abs/1912.00998 for details about multigrid training.
+# ---------------------------------------------------------------------------- #
+_C.MULTIGRID = CfgNode()
+
+# Multigrid training allows us to train for more epochs with fewer iterations.
+# This hyperparameter specifies how many times more epochs to train.
+# The default setting in paper trains for 1.5x more epochs than baseline.
+_C.MULTIGRID.EPOCH_FACTOR = 1.5
+
+# Enable short cycles.
+_C.MULTIGRID.SHORT_CYCLE = False
+# Short cycle additional spatial dimensions relative to the default crop size.
+_C.MULTIGRID.SHORT_CYCLE_FACTORS = [0.5, 0.5 ** 0.5]
+
+_C.MULTIGRID.LONG_CYCLE = False
+# (Temporal, Spatial) dimensions relative to the default shape.
+_C.MULTIGRID.LONG_CYCLE_FACTORS = [
+ (0.25, 0.5 ** 0.5),
+ (0.5, 0.5 ** 0.5),
+ (0.5, 1),
+ (1, 1),
+]
+
+# While a standard BN computes stats across all examples in a GPU,
+# for multigrid training we fix the number of clips to compute BN stats on.
+# See https://arxiv.org/abs/1912.00998 for details.
+_C.MULTIGRID.BN_BASE_SIZE = 8
+
+# Multigrid training epochs are not proportional to actual training time or
+# computations, so _C.TRAIN.EVAL_PERIOD leads to too frequent or rare
+# evaluation. We use a multigrid-specific rule to determine when to evaluate:
+# This hyperparameter defines how many times to evaluate a model per long
+# cycle shape.
+_C.MULTIGRID.EVAL_FREQ = 3
+
+# No need to specify; Set automatically and used as global variables.
+_C.MULTIGRID.LONG_CYCLE_SAMPLING_RATE = 0
+_C.MULTIGRID.DEFAULT_B = 0
+_C.MULTIGRID.DEFAULT_T = 0
+_C.MULTIGRID.DEFAULT_S = 0
+
+# -----------------------------------------------------------------------------
+# Tensorboard Visualization Options
+# -----------------------------------------------------------------------------
+_C.TENSORBOARD = CfgNode()
+
+# Log to summary writer, this will automatically.
+# log loss, lr and metrics during train/eval.
+_C.TENSORBOARD.ENABLE = False
+# Provide path to prediction results for visualization.
+# This is a pickle file of [prediction_tensor, label_tensor]
+_C.TENSORBOARD.PREDICTIONS_PATH = ""
+# Path to directory for tensorboard logs.
+# Default to to cfg.OUTPUT_DIR/runs-{cfg.TRAIN.DATASET}.
+_C.TENSORBOARD.LOG_DIR = ""
+# Path to a json file providing class_name - id mapping
+# in the format {"class_name1": id1, "class_name2": id2, ...}.
+# This file must be provided to enable plotting confusion matrix
+# by a subset or parent categories.
+_C.TENSORBOARD.CLASS_NAMES_PATH = ""
+
+# Path to a json file for categories -> classes mapping
+# in the format {"parent_class": ["child_class1", "child_class2",...], ...}.
+_C.TENSORBOARD.CATEGORIES_PATH = ""
+
+# Config for confusion matrices visualization.
+_C.TENSORBOARD.CONFUSION_MATRIX = CfgNode()
+# Visualize confusion matrix.
+_C.TENSORBOARD.CONFUSION_MATRIX.ENABLE = False
+# Figure size of the confusion matrices plotted.
+_C.TENSORBOARD.CONFUSION_MATRIX.FIGSIZE = [8, 8]
+# Path to a subset of categories to visualize.
+# File contains class names separated by newline characters.
+_C.TENSORBOARD.CONFUSION_MATRIX.SUBSET_PATH = ""
+
+# Config for histogram visualization.
+_C.TENSORBOARD.HISTOGRAM = CfgNode()
+# Visualize histograms.
+_C.TENSORBOARD.HISTOGRAM.ENABLE = False
+# Path to a subset of classes to plot histograms.
+# Class names must be separated by newline characters.
+_C.TENSORBOARD.HISTOGRAM.SUBSET_PATH = ""
+# Visualize top-k most predicted classes on histograms for each
+# chosen true label.
+_C.TENSORBOARD.HISTOGRAM.TOPK = 10
+# Figure size of the histograms plotted.
+_C.TENSORBOARD.HISTOGRAM.FIGSIZE = [8, 8]
+
+# Config for layers' weights and activations visualization.
+# _C.TENSORBOARD.ENABLE must be True.
+_C.TENSORBOARD.MODEL_VIS = CfgNode()
+
+# If False, skip model visualization.
+_C.TENSORBOARD.MODEL_VIS.ENABLE = False
+
+# If False, skip visualizing model weights.
+_C.TENSORBOARD.MODEL_VIS.MODEL_WEIGHTS = False
+
+# If False, skip visualizing model activations.
+_C.TENSORBOARD.MODEL_VIS.ACTIVATIONS = False
+
+# If False, skip visualizing input videos.
+_C.TENSORBOARD.MODEL_VIS.INPUT_VIDEO = False
+
+
+# List of strings containing data about layer names and their indexing to
+# visualize weights and activations for. The indexing is meant for
+# choosing a subset of activations outputed by a layer for visualization.
+# If indexing is not specified, visualize all activations outputed by the layer.
+# For each string, layer name and indexing is separated by whitespaces.
+# e.g.: [layer1 1,2;1,2, layer2, layer3 150,151;3,4]; this means for each array `arr`
+# along the batch dimension in `layer1`, we take arr[[1, 2], [1, 2]]
+_C.TENSORBOARD.MODEL_VIS.LAYER_LIST = []
+# Top-k predictions to plot on videos
+_C.TENSORBOARD.MODEL_VIS.TOPK_PREDS = 1
+# Colormap to for text boxes and bounding boxes colors
+_C.TENSORBOARD.MODEL_VIS.COLORMAP = "Pastel2"
+# Config for visualization video inputs with Grad-CAM.
+# _C.TENSORBOARD.ENABLE must be True.
+_C.TENSORBOARD.MODEL_VIS.GRAD_CAM = CfgNode()
+# Whether to run visualization using Grad-CAM technique.
+_C.TENSORBOARD.MODEL_VIS.GRAD_CAM.ENABLE = True
+# CNN layers to use for Grad-CAM. The number of layers must be equal to
+# number of pathway(s).
+_C.TENSORBOARD.MODEL_VIS.GRAD_CAM.LAYER_LIST = []
+# If True, visualize Grad-CAM using true labels for each instances.
+# If False, use the highest predicted class.
+_C.TENSORBOARD.MODEL_VIS.GRAD_CAM.USE_TRUE_LABEL = False
+# Colormap to for text boxes and bounding boxes colors
+_C.TENSORBOARD.MODEL_VIS.GRAD_CAM.COLORMAP = "viridis"
+
+# Config for visualization for wrong prediction visualization.
+# _C.TENSORBOARD.ENABLE must be True.
+_C.TENSORBOARD.WRONG_PRED_VIS = CfgNode()
+_C.TENSORBOARD.WRONG_PRED_VIS.ENABLE = False
+# Folder tag to origanize model eval videos under.
+_C.TENSORBOARD.WRONG_PRED_VIS.TAG = "Incorrectly classified videos."
+# Subset of labels to visualize. Only wrong predictions with true labels
+# within this subset is visualized.
+_C.TENSORBOARD.WRONG_PRED_VIS.SUBSET_PATH = ""
+
+
+
+###############
+_C.JITTER = CfgNode()
+
+_C.JITTER.ENABLE = False
+
+_C.JITTER.CONTINUS_METHODS=["blend_diff_person","blend_downsampled","blend_same_person"]
+_C.JITTER.DISCONTINUS_METHODS=["light", "rotate", "skip"]
+
+_C.JITTER.STRONG_INNER_CLIP_MASK_JITTER= False
+
+# ---------------------------------------------------------------------------- #
+# Demo options
+# ---------------------------------------------------------------------------- #
+_C.DEMO = CfgNode()
+
+# Run model in DEMO mode.
+_C.DEMO.ENABLE = False
+
+# Path to a json file providing class_name - id mapping
+# in the format {"class_name1": id1, "class_name2": id2, ...}.
+_C.DEMO.LABEL_FILE_PATH = ""
+
+# Specify a camera device as input. This will be prioritized
+# over input video if set.
+# If -1, use input video instead.
+_C.DEMO.WEBCAM = -1
+
+# Path to input video for demo.
+_C.DEMO.INPUT_VIDEO = ""
+# Custom width for reading input video data.
+_C.DEMO.DISPLAY_WIDTH = 0
+# Custom height for reading input video data.
+_C.DEMO.DISPLAY_HEIGHT = 0
+# Path to Detectron2 object detection model configuration,
+# only used for detection tasks.
+_C.DEMO.DETECTRON2_CFG = "COCO-Detection/faster_rcnn_R_50_FPN_3x.yaml"
+# Path to Detectron2 object detection model pre-trained weights.
+_C.DEMO.DETECTRON2_WEIGHTS = "detectron2://COCO-Detection/faster_rcnn_R_50_FPN_3x/137849458/model_final_280758.pkl"
+# Threshold for choosing predicted bounding boxes by Detectron2.
+_C.DEMO.DETECTRON2_THRESH = 0.9
+# Number of overlapping frames between 2 consecutive clips.
+# Increase this number for more frequent action predictions.
+# The number of overlapping frames cannot be larger than
+# half of the sequence length `cfg.DATA.NUM_FRAMES * cfg.DATA.SAMPLING_RATE`
+_C.DEMO.BUFFER_SIZE = 0
+# If specified, the visualized outputs will be written this a video file of
+# this path. Otherwise, the visualized outputs will be displayed in a window.
+_C.DEMO.OUTPUT_FILE = ""
+# Frames per second rate for writing to output video file.
+# If not set (-1), use fps rate from input file.
+_C.DEMO.OUTPUT_FPS = -1
+# Input format from demo video reader ("RGB" or "BGR").
+_C.DEMO.INPUT_FORMAT = "BGR"
+# Draw visualization frames in [keyframe_idx - CLIP_VIS_SIZE, keyframe_idx + CLIP_VIS_SIZE] inclusively.
+_C.DEMO.CLIP_VIS_SIZE = 10
+# Number of processes to run video visualizer.
+_C.DEMO.NUM_VIS_INSTANCES = 2
+
+# Path to pre-computed predicted boxes
+_C.DEMO.PREDS_BOXES = ""
+# Whether to run in with multi-threaded video reader.
+_C.DEMO.THREAD_ENABLE = False
+# Take one clip for every `DEMO.NUM_CLIPS_SKIP` + 1 for prediction and visualization.
+# This is used for fast demo speed by reducing the prediction/visualiztion frequency.
+# If -1, take the most recent read clip for visualization. This mode is only supported
+# if `DEMO.THREAD_ENABLE` is set to True.
+_C.DEMO.NUM_CLIPS_SKIP = 0
+# Path to ground-truth boxes and labels (optional)
+_C.DEMO.GT_BOXES = ""
+# The starting second of the video w.r.t bounding boxes file.
+_C.DEMO.STARTING_SECOND = 900
+# Frames per second of the input video/folder of images.
+_C.DEMO.FPS = 30
+# Visualize with top-k predictions or predictions above certain threshold(s).
+# Option: {"thres", "top-k"}
+_C.DEMO.VIS_MODE = "thres"
+# Threshold for common class names.
+_C.DEMO.COMMON_CLASS_THRES = 0.7
+# Theshold for uncommon class names. This will not be
+# used if `_C.DEMO.COMMON_CLASS_NAMES` is empty.
+_C.DEMO.UNCOMMON_CLASS_THRES = 0.3
+# This is chosen based on distribution of examples in
+# each classes in AVA dataset.
+_C.DEMO.COMMON_CLASS_NAMES = [
+ "watch (a person)",
+ "talk to (e.g., self, a person, a group)",
+ "listen to (a person)",
+ "touch (an object)",
+ "carry/hold (an object)",
+ "walk",
+ "sit",
+ "lie/sleep",
+ "bend/bow (at the waist)",
+]
+# Slow-motion rate for the visualization. The visualized portions of the
+# video will be played `_C.DEMO.SLOWMO` times slower than usual speed.
+_C.DEMO.SLOWMO = 1
+
+# Add custom config with default values.
+custom_config.add_custom_config(_C)
+
+
+def _assert_and_infer_cfg(cfg):
+ # BN assertions.
+ if cfg.BN.USE_PRECISE_STATS:
+ assert cfg.BN.NUM_BATCHES_PRECISE >= 0
+ # TRAIN assertions.
+ assert cfg.TRAIN.CHECKPOINT_TYPE in ["pytorch", "caffe2"]
+ assert cfg.TRAIN.BATCH_SIZE % cfg.NUM_GPUS == 0
+
+ # TEST assertions.
+ assert cfg.TEST.CHECKPOINT_TYPE in ["pytorch", "caffe2"]
+ assert cfg.TEST.BATCH_SIZE % cfg.NUM_GPUS == 0
+ assert cfg.TEST.NUM_SPATIAL_CROPS == 3
+
+ # RESNET assertions.
+ assert cfg.RESNET.NUM_GROUPS > 0
+ assert cfg.RESNET.WIDTH_PER_GROUP > 0
+ assert cfg.RESNET.WIDTH_PER_GROUP % cfg.RESNET.NUM_GROUPS == 0
+
+ # General assertions.
+ assert cfg.SHARD_ID < cfg.NUM_SHARDS
+ return cfg
+
+
+def get_cfg():
+ """
+ Get a copy of the default config.
+ """
+ return _assert_and_infer_cfg(_C.clone())
diff --git a/clean/video/pwtf_dvd/inference/slowfast/models/__init__.py b/clean/video/pwtf_dvd/inference/slowfast/models/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..f82b3dc1e3af0dbabf4a3a6153e48b977eb1059e
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/models/__init__.py
@@ -0,0 +1,6 @@
+#!/usr/bin/env python3
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+
+from .build import MODEL_REGISTRY, build_model # noqa
+from .custom_video_model_builder import * # noqa
+from .video_model_builder import ResNet, SlowFast # noqa
\ No newline at end of file
diff --git a/clean/video/pwtf_dvd/inference/slowfast/models/batchnorm_helper.py b/clean/video/pwtf_dvd/inference/slowfast/models/batchnorm_helper.py
new file mode 100644
index 0000000000000000000000000000000000000000..4e52d50497d9c0a58e5ace0a2fde94b5418ef563
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/models/batchnorm_helper.py
@@ -0,0 +1,218 @@
+#!/usr/bin/env python3
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+
+"""BatchNorm (BN) utility functions and custom batch-size BN implementations"""
+
+from functools import partial
+import torch
+import torch.distributed as dist
+import torch.nn as nn
+from torch.autograd.function import Function
+
+import slowfast.utils.distributed as du
+
+
+def get_norm(cfg):
+ """
+ Args:
+ cfg (CfgNode): model building configs, details are in the comments of
+ the config file.
+ Returns:
+ nn.Module: the normalization layer.
+ """
+ if cfg.BN.NORM_TYPE == "batchnorm":
+ return nn.BatchNorm3d
+ elif cfg.BN.NORM_TYPE == "sub_batchnorm":
+ return partial(SubBatchNorm3d, num_splits=cfg.BN.NUM_SPLITS)
+ elif cfg.BN.NORM_TYPE == "sync_batchnorm":
+ return partial(
+ NaiveSyncBatchNorm3d, num_sync_devices=cfg.BN.NUM_SYNC_DEVICES
+ )
+ else:
+ raise NotImplementedError(
+ "Norm type {} is not supported".format(cfg.BN.NORM_TYPE)
+ )
+
+
+class SubBatchNorm3d(nn.Module):
+ """
+ The standard BN layer computes stats across all examples in a GPU. In some
+ cases it is desirable to compute stats across only a subset of examples
+ (e.g., in multigrid training https://arxiv.org/abs/1912.00998).
+ SubBatchNorm3d splits the batch dimension into N splits, and run BN on
+ each of them separately (so that the stats are computed on each subset of
+ examples (1/N of batch) independently. During evaluation, it aggregates
+ the stats from all splits into one BN.
+ """
+
+ def __init__(self, num_splits, **args):
+ """
+ Args:
+ num_splits (int): number of splits.
+ args (list): other arguments.
+ """
+ super(SubBatchNorm3d, self).__init__()
+ self.num_splits = num_splits
+ num_features = args["num_features"]
+ # Keep only one set of weight and bias.
+ if args.get("affine", True):
+ self.affine = True
+ args["affine"] = False
+ self.weight = torch.nn.Parameter(torch.ones(num_features))
+ self.bias = torch.nn.Parameter(torch.zeros(num_features))
+ else:
+ self.affine = False
+ self.bn = nn.BatchNorm3d(**args)
+ args["num_features"] = num_features * num_splits
+ self.split_bn = nn.BatchNorm3d(**args)
+
+ def _get_aggregated_mean_std(self, means, stds, n):
+ """
+ Calculate the aggregated mean and stds.
+ Args:
+ means (tensor): mean values.
+ stds (tensor): standard deviations.
+ n (int): number of sets of means and stds.
+ """
+ mean = means.view(n, -1).sum(0) / n
+ std = (
+ stds.view(n, -1).sum(0) / n
+ + ((means.view(n, -1) - mean) ** 2).view(n, -1).sum(0) / n
+ )
+ return mean.detach(), std.detach()
+
+ def aggregate_stats(self):
+ """
+ Synchronize running_mean, and running_var. Call this before eval.
+ """
+ if self.split_bn.track_running_stats:
+ (
+ self.bn.running_mean.data,
+ self.bn.running_var.data,
+ ) = self._get_aggregated_mean_std(
+ self.split_bn.running_mean,
+ self.split_bn.running_var,
+ self.num_splits,
+ )
+
+ def forward(self, x):
+ if self.training:
+ n, c, t, h, w = x.shape
+ x = x.view(n // self.num_splits, c * self.num_splits, t, h, w)
+ x = self.split_bn(x)
+ x = x.view(n, c, t, h, w)
+ else:
+ x = self.bn(x)
+ if self.affine:
+ x = x * self.weight.view((-1, 1, 1, 1))
+ x = x + self.bias.view((-1, 1, 1, 1))
+ return x
+
+
+class GroupGather(Function):
+ """
+ GroupGather performs all gather on each of the local process/ GPU groups.
+ """
+
+ @staticmethod
+ def forward(ctx, input, num_sync_devices, num_groups):
+ """
+ Perform forwarding, gathering the stats across different process/ GPU
+ group.
+ """
+ ctx.num_sync_devices = num_sync_devices
+ ctx.num_groups = num_groups
+
+ input_list = [
+ torch.zeros_like(input) for k in range(du.get_local_size())
+ ]
+ dist.all_gather(
+ input_list, input, async_op=False, group=du._LOCAL_PROCESS_GROUP
+ )
+
+ inputs = torch.stack(input_list, dim=0)
+ if num_groups > 1:
+ rank = du.get_local_rank()
+ group_idx = rank // num_sync_devices
+ inputs = inputs[
+ group_idx
+ * num_sync_devices : (group_idx + 1)
+ * num_sync_devices
+ ]
+ inputs = torch.sum(inputs, dim=0)
+ return inputs
+
+ @staticmethod
+ def backward(ctx, grad_output):
+ """
+ Perform backwarding, gathering the gradients across different process/ GPU
+ group.
+ """
+ grad_output_list = [
+ torch.zeros_like(grad_output) for k in range(du.get_local_size())
+ ]
+ dist.all_gather(
+ grad_output_list,
+ grad_output,
+ async_op=False,
+ group=du._LOCAL_PROCESS_GROUP,
+ )
+
+ grads = torch.stack(grad_output_list, dim=0)
+ if ctx.num_groups > 1:
+ rank = du.get_local_rank()
+ group_idx = rank // ctx.num_sync_devices
+ grads = grads[
+ group_idx
+ * ctx.num_sync_devices : (group_idx + 1)
+ * ctx.num_sync_devices
+ ]
+ grads = torch.sum(grads, dim=0)
+ return grads, None, None
+
+
+class NaiveSyncBatchNorm3d(nn.BatchNorm3d):
+ def __init__(self, num_sync_devices, **args):
+ """
+ Naive version of Synchronized 3D BatchNorm.
+ Args:
+ num_sync_devices (int): number of device to sync.
+ args (list): other arguments.
+ """
+ self.num_sync_devices = num_sync_devices
+ if self.num_sync_devices > 0:
+ assert du.get_local_size() % self.num_sync_devices == 0, (
+ du.get_local_size(),
+ self.num_sync_devices,
+ )
+ self.num_groups = du.get_local_size() // self.num_sync_devices
+ else:
+ self.num_sync_devices = du.get_local_size()
+ self.num_groups = 1
+ super(NaiveSyncBatchNorm3d, self).__init__(**args)
+
+ def forward(self, input):
+ if du.get_local_size() == 1 or not self.training:
+ return super().forward(input)
+
+ assert input.shape[0] > 0, "SyncBatchNorm does not support empty inputs"
+ C = input.shape[1]
+ mean = torch.mean(input, dim=[0, 2, 3, 4])
+ meansqr = torch.mean(input * input, dim=[0, 2, 3, 4])
+
+ vec = torch.cat([mean, meansqr], dim=0)
+ vec = GroupGather.apply(vec, self.num_sync_devices, self.num_groups) * (
+ 1.0 / self.num_sync_devices
+ )
+
+ mean, meansqr = torch.split(vec, C)
+ var = meansqr - mean * mean
+ self.running_mean += self.momentum * (mean.detach() - self.running_mean)
+ self.running_var += self.momentum * (var.detach() - self.running_var)
+
+ invstd = torch.rsqrt(var + self.eps)
+ scale = self.weight * invstd
+ bias = self.bias - mean * scale
+ scale = scale.reshape(1, -1, 1, 1, 1)
+ bias = bias.reshape(1, -1, 1, 1, 1)
+ return input * scale + bias
diff --git a/clean/video/pwtf_dvd/inference/slowfast/models/build.py b/clean/video/pwtf_dvd/inference/slowfast/models/build.py
new file mode 100644
index 0000000000000000000000000000000000000000..8dd9cca224b3e77bb8c3cd899489358737d4cd35
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/models/build.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python3
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+
+"""Model construction functions."""
+
+import torch
+from fvcore.common.registry import Registry
+
+MODEL_REGISTRY = Registry("MODEL")
+MODEL_REGISTRY.__doc__ = """
+Registry for video model.
+
+The registered object will be called with `obj(cfg)`.
+The call should return a `torch.nn.Module` object.
+"""
+
+
+def build_model(cfg, gpu_id=None):
+ """
+ Builds the video model.
+ Args:
+ cfg (configs): configs that contains the hyper-parameters to build the
+ backbone. Details can be seen in slowfast/config/defaults.py.
+ gpu_id (Optional[int]): specify the gpu index to build model.
+ """
+ if torch.cuda.is_available():
+ assert (
+ cfg.NUM_GPUS <= torch.cuda.device_count()
+ ), "Cannot use more GPU devices than available"
+ else:
+ assert (
+ cfg.NUM_GPUS == 0
+ ), "Cuda is not available. Please set `NUM_GPUS: 0 for running on CPUs."
+
+ # Construct the model
+ name = cfg.MODEL.MODEL_NAME
+ model = MODEL_REGISTRY.get(name)(cfg)
+
+ if cfg.NUM_GPUS:
+ if gpu_id is None:
+ # Determine the GPU used by the current process
+ cur_device = torch.cuda.current_device()
+ else:
+ cur_device = gpu_id
+ # Transfer the model to the current GPU device
+ model = model.cuda(device=cur_device)
+ # Use multi-process data parallel model in the multi-gpu setting
+ if cfg.NUM_GPUS > 1:
+ # Make model replica operate on the current device
+ model = torch.nn.parallel.DistributedDataParallel(
+ module=model, device_ids=[cur_device], output_device=cur_device,find_unused_parameters=True
+ )
+ return model
diff --git a/clean/video/pwtf_dvd/inference/slowfast/models/custom_video_model_builder.py b/clean/video/pwtf_dvd/inference/slowfast/models/custom_video_model_builder.py
new file mode 100644
index 0000000000000000000000000000000000000000..f261f67b95616b8582b10998a290611ee108b2a9
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/models/custom_video_model_builder.py
@@ -0,0 +1,5 @@
+#!/usr/bin/env python3
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+
+
+"""A More Flexible Video models."""
diff --git a/clean/video/pwtf_dvd/inference/slowfast/models/head_helper.py b/clean/video/pwtf_dvd/inference/slowfast/models/head_helper.py
new file mode 100644
index 0000000000000000000000000000000000000000..df04b010430b6000005676d52174243383873d05
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/models/head_helper.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python3
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+
+"""ResNe(X)t Head helper."""
+
+import torch
+import torch.nn as nn
+
+class ResNetBasicHead(nn.Module):
+ """
+ ResNe(X)t 3D head.
+ This layer performs a fully-connected projection during training, when the
+ input size is 1x1x1. It performs a convolutional projection during testing
+ when the input size is larger than 1x1x1. If the inputs are from multiple
+ different pathways, the inputs will be concatenated after pooling.
+ """
+
+ def __init__(
+ self,
+ dim_in,
+ num_classes,
+ pool_size,
+ dropout_rate=0.0,
+ act_func="softmax",
+ ):
+ """
+ The `__init__` method of any subclass should also contain these
+ arguments.
+ ResNetBasicHead takes p pathways as input where p in [1, infty].
+
+ Args:
+ dim_in (list): the list of channel dimensions of the p inputs to the
+ ResNetHead.
+ num_classes (int): the channel dimensions of the p outputs to the
+ ResNetHead.
+ pool_size (list): the list of kernel sizes of p spatial temporal
+ poolings, temporal pool kernel size, spatial pool kernel size,
+ spatial pool kernel size in order.
+ dropout_rate (float): dropout rate. If equal to 0.0, perform no
+ dropout.
+ act_func (string): activation function to use. 'softmax': applies
+ softmax on the output. 'sigmoid': applies sigmoid on the output.
+ """
+ super(ResNetBasicHead, self).__init__()
+ assert (
+ len({len(pool_size), len(dim_in)}) == 1
+ ), "pathway dimensions are not consistent."
+ self.num_pathways = len(pool_size)
+
+ for pathway in range(self.num_pathways):
+ if pool_size[pathway] is None:
+ avg_pool = nn.AdaptiveAvgPool3d((1, 1, 1))
+ else:
+ avg_pool = nn.AvgPool3d(pool_size[pathway], stride=1)
+ self.add_module("pathway{}_avgpool".format(pathway), avg_pool)
+
+ if dropout_rate > 0.0:
+ self.dropout = nn.Dropout(dropout_rate)
+ # Perform FC in a fully convolutional manner. The FC layer will be
+ # initialized with a different std comparing to convolutional layers.
+ self.projection = nn.Linear(sum(dim_in), num_classes, bias=True)
+
+ # Softmax for evaluation and testing.
+ if act_func == "softmax":
+ self.act = nn.Softmax(dim=4)
+ elif act_func == "sigmoid":
+ self.act = nn.Sigmoid()
+ else:
+ raise NotImplementedError(
+ "{} is not supported as an activation"
+ "function.".format(act_func)
+ )
+
+ def forward(self, inputs):
+ assert (
+ len(inputs) == self.num_pathways
+ ), "Input tensor does not contain {} pathway".format(self.num_pathways)
+ pool_out = []
+ for pathway in range(self.num_pathways):
+ m = getattr(self, "pathway{}_avgpool".format(pathway))
+ pool_out.append(m(inputs[pathway]))
+ x = torch.cat(pool_out, 1)
+ # (N, C, T, H, W) -> (N, T, H, W, C).
+ x = x.permute((0, 2, 3, 4, 1))
+ # Perform dropout.
+ if hasattr(self, "dropout"):
+ x = self.dropout(x)
+ x = self.projection(x)
+
+ # Performs fully convlutional inference.
+ # if not self.training:
+ # x = x.mean([1, 2, 3])
+ x = self.act(x)
+ x = x.view(x.shape[0], -1)
+ return x
diff --git a/clean/video/pwtf_dvd/inference/slowfast/models/losses.py b/clean/video/pwtf_dvd/inference/slowfast/models/losses.py
new file mode 100644
index 0000000000000000000000000000000000000000..7dda4eb19b2cf76275ba1778dc5f8730058a6c31
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/models/losses.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python3
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+
+"""Loss functions."""
+
+import torch.nn as nn
+
+_LOSSES = {
+ "cross_entropy": nn.CrossEntropyLoss,
+ "bce": nn.BCELoss,
+ "bce_logit": nn.BCEWithLogitsLoss,
+}
+
+
+def get_loss_func(loss_name):
+ """
+ Retrieve the loss given the loss name.
+ Args (int):
+ loss_name: the name of the loss to use.
+ """
+ if loss_name not in _LOSSES.keys():
+ raise NotImplementedError("Loss {} is not supported".format(loss_name))
+ return _LOSSES[loss_name]
diff --git a/clean/video/pwtf_dvd/inference/slowfast/models/nonlocal_helper.py b/clean/video/pwtf_dvd/inference/slowfast/models/nonlocal_helper.py
new file mode 100644
index 0000000000000000000000000000000000000000..6e68d05817256a66d0b6ecf0f96292446cf41270
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/models/nonlocal_helper.py
@@ -0,0 +1,148 @@
+#!/usr/bin/env python3
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+
+"""Non-local helper"""
+
+import torch
+import torch.nn as nn
+
+
+class Nonlocal(nn.Module):
+ """
+ Builds Non-local Neural Networks as a generic family of building
+ blocks for capturing long-range dependencies. Non-local Network
+ computes the response at a position as a weighted sum of the
+ features at all positions. This building block can be plugged into
+ many computer vision architectures.
+ More details in the paper: https://arxiv.org/pdf/1711.07971.pdf
+ """
+
+ def __init__(
+ self,
+ dim,
+ dim_inner,
+ pool_size=None,
+ instantiation="softmax",
+ zero_init_final_conv=False,
+ zero_init_final_norm=True,
+ norm_eps=1e-5,
+ norm_momentum=0.1,
+ norm_module=nn.BatchNorm3d,
+ ):
+ """
+ Args:
+ dim (int): number of dimension for the input.
+ dim_inner (int): number of dimension inside of the Non-local block.
+ pool_size (list): the kernel size of spatial temporal pooling,
+ temporal pool kernel size, spatial pool kernel size, spatial
+ pool kernel size in order. By default pool_size is None,
+ then there would be no pooling used.
+ instantiation (string): supports two different instantiation method:
+ "dot_product": normalizing correlation matrix with L2.
+ "softmax": normalizing correlation matrix with Softmax.
+ zero_init_final_conv (bool): If true, zero initializing the final
+ convolution of the Non-local block.
+ zero_init_final_norm (bool):
+ If true, zero initializing the final batch norm of the Non-local
+ block.
+ norm_module (nn.Module): nn.Module for the normalization layer. The
+ default is nn.BatchNorm3d.
+ """
+ super(Nonlocal, self).__init__()
+ self.dim = dim
+ self.dim_inner = dim_inner
+ self.pool_size = pool_size
+ self.instantiation = instantiation
+ self.use_pool = (
+ False
+ if pool_size is None
+ else any((size > 1 for size in pool_size))
+ )
+ self.norm_eps = norm_eps
+ self.norm_momentum = norm_momentum
+ self._construct_nonlocal(
+ zero_init_final_conv, zero_init_final_norm, norm_module
+ )
+
+ def _construct_nonlocal(
+ self, zero_init_final_conv, zero_init_final_norm, norm_module
+ ):
+ # Three convolution heads: theta, phi, and g.
+ self.conv_theta = nn.Conv3d(
+ self.dim, self.dim_inner, kernel_size=1, stride=1, padding=0
+ )
+ self.conv_phi = nn.Conv3d(
+ self.dim, self.dim_inner, kernel_size=1, stride=1, padding=0
+ )
+ self.conv_g = nn.Conv3d(
+ self.dim, self.dim_inner, kernel_size=1, stride=1, padding=0
+ )
+
+ # Final convolution output.
+ self.conv_out = nn.Conv3d(
+ self.dim_inner, self.dim, kernel_size=1, stride=1, padding=0
+ )
+ # Zero initializing the final convolution output.
+ self.conv_out.zero_init = zero_init_final_conv
+
+ # TODO: change the name to `norm`
+ self.bn = norm_module(
+ num_features=self.dim,
+ eps=self.norm_eps,
+ momentum=self.norm_momentum,
+ )
+ # Zero initializing the final bn.
+ self.bn.transform_final_bn = zero_init_final_norm
+
+ # Optional to add the spatial-temporal pooling.
+ if self.use_pool:
+ self.pool = nn.MaxPool3d(
+ kernel_size=self.pool_size,
+ stride=self.pool_size,
+ padding=[0, 0, 0],
+ )
+
+ def forward(self, x):
+ x_identity = x
+ N, C, T, H, W = x.size()
+
+ theta = self.conv_theta(x)
+
+ # Perform temporal-spatial pooling to reduce the computation.
+ if self.use_pool:
+ x = self.pool(x)
+
+ phi = self.conv_phi(x)
+ g = self.conv_g(x)
+
+ theta = theta.view(N, self.dim_inner, -1)
+ phi = phi.view(N, self.dim_inner, -1)
+ g = g.view(N, self.dim_inner, -1)
+
+ # (N, C, TxHxW) * (N, C, TxHxW) => (N, TxHxW, TxHxW).
+ theta_phi = torch.einsum("nct,ncp->ntp", (theta, phi))
+ # For original Non-local paper, there are two main ways to normalize
+ # the affinity tensor:
+ # 1) Softmax normalization (norm on exp).
+ # 2) dot_product normalization.
+ if self.instantiation == "softmax":
+ # Normalizing the affinity tensor theta_phi before softmax.
+ theta_phi = theta_phi * (self.dim_inner ** -0.5)
+ theta_phi = nn.functional.softmax(theta_phi, dim=2)
+ elif self.instantiation == "dot_product":
+ spatial_temporal_dim = theta_phi.shape[2]
+ theta_phi = theta_phi / spatial_temporal_dim
+ else:
+ raise NotImplementedError(
+ "Unknown norm type {}".format(self.instantiation)
+ )
+
+ # (N, TxHxW, TxHxW) * (N, C, TxHxW) => (N, C, TxHxW).
+ theta_phi_g = torch.einsum("ntg,ncg->nct", (theta_phi, g))
+
+ # (N, C, TxHxW) => (N, C, T, H, W).
+ theta_phi_g = theta_phi_g.view(N, self.dim_inner, T, H, W)
+
+ p = self.conv_out(theta_phi_g)
+ p = self.bn(p)
+ return x_identity + p
diff --git a/clean/video/pwtf_dvd/inference/slowfast/models/optimizer.py b/clean/video/pwtf_dvd/inference/slowfast/models/optimizer.py
new file mode 100644
index 0000000000000000000000000000000000000000..130f2cebf994741bc45a6519f07c5f0740c106ac
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/models/optimizer.py
@@ -0,0 +1,103 @@
+#!/usr/bin/env python3
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+
+"""Optimizer."""
+
+import torch
+
+import slowfast.utils.lr_policy as lr_policy
+
+
+def construct_optimizer(model, cfg):
+ """
+ Construct a stochastic gradient descent or ADAM optimizer with momentum.
+ Details can be found in:
+ Herbert Robbins, and Sutton Monro. "A stochastic approximation method."
+ and
+ Diederik P.Kingma, and Jimmy Ba.
+ "Adam: A Method for Stochastic Optimization."
+
+ Args:
+ model (model): model to perform stochastic gradient descent
+ optimization or ADAM optimization.
+ cfg (config): configs of hyper-parameters of SGD or ADAM, includes base
+ learning rate, momentum, weight_decay, dampening, and etc.
+ """
+ # Batchnorm parameters.
+ bn_params = []
+ # Non-batchnorm parameters.
+ non_bn_parameters = []
+ for name, p in model.named_parameters():
+ if "bn" in name:
+ bn_params.append(p)
+ else:
+ non_bn_parameters.append(p)
+ # Apply different weight decay to Batchnorm and non-batchnorm parameters.
+ # In Caffe2 classification codebase the weight decay for batchnorm is 0.0.
+ # Having a different weight decay on batchnorm might cause a performance
+ # drop.
+ optim_params = [
+ {"params": bn_params, "weight_decay": cfg.BN.WEIGHT_DECAY},
+ {"params": non_bn_parameters, "weight_decay": cfg.SOLVER.WEIGHT_DECAY},
+ ]
+ # Check all parameters will be passed into optimizer.
+ assert len(list(model.parameters())) == len(non_bn_parameters) + len(
+ bn_params
+ ), "parameter size does not match: {} + {} != {}".format(
+ len(non_bn_parameters), len(bn_params), len(list(model.parameters()))
+ )
+
+ if cfg.SOLVER.OPTIMIZING_METHOD == "sgd":
+ return torch.optim.SGD(
+ optim_params,
+ lr=cfg.SOLVER.BASE_LR,
+ momentum=cfg.SOLVER.MOMENTUM,
+ weight_decay=cfg.SOLVER.WEIGHT_DECAY,
+ dampening=cfg.SOLVER.DAMPENING,
+ nesterov=cfg.SOLVER.NESTEROV,
+ )
+ elif cfg.SOLVER.OPTIMIZING_METHOD == "adam":
+ return torch.optim.Adam(
+ optim_params,
+ lr=cfg.SOLVER.BASE_LR,
+ betas=(0.9, 0.999),
+ weight_decay=cfg.SOLVER.WEIGHT_DECAY,
+ )
+ else:
+ raise NotImplementedError(
+ "Does not support {} optimizer".format(cfg.SOLVER.OPTIMIZING_METHOD)
+ )
+
+
+def get_epoch_lr(cur_epoch, cfg):
+ """
+ Retrieves the lr for the given epoch (as specified by the lr policy).
+ Args:
+ cfg (config): configs of hyper-parameters of ADAM, includes base
+ learning rate, betas, and weight decays.
+ cur_epoch (float): the number of epoch of the current training stage.
+ """
+ return lr_policy.get_lr_at_epoch(cfg, cur_epoch)
+
+def get_iter_lr(cur_iter, cfg):
+ """
+ Retrieves the lr for the given iter (as specified by the lr policy).
+ Args:
+ cfg (config): configs of hyper-parameters of ADAM, includes base
+ learning rate, betas, and weight decays.
+ cur_epoch (float): the number of epoch of the current training stage.
+ """
+ lr=lr_policy.get_lr_at_iter(cfg, cur_iter)
+
+ return lr
+
+
+def set_lr(optimizer, new_lr):
+ """
+ Sets the optimizer lr to the specified value.
+ Args:
+ optimizer (optim): the optimizer using to optimize the current network.
+ new_lr (float): the new learning rate to set.
+ """
+ for param_group in optimizer.param_groups:
+ param_group["lr"] = new_lr
diff --git a/clean/video/pwtf_dvd/inference/slowfast/models/resnet_helper.py b/clean/video/pwtf_dvd/inference/slowfast/models/resnet_helper.py
new file mode 100644
index 0000000000000000000000000000000000000000..3e10df460ce94d2c816ab546188412989a4ed628
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/models/resnet_helper.py
@@ -0,0 +1,649 @@
+#!/usr/bin/env python3
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+
+"""Video models."""
+
+import torch.nn as nn
+
+from slowfast.models.nonlocal_helper import Nonlocal
+
+
+def get_trans_func(name):
+ """
+ Retrieves the transformation module by name.
+ """
+ trans_funcs = {
+ "bottleneck_transform": BottleneckTransform,
+ "basic_transform": BasicTransform,
+ "temporal_transform":TemporalTransform
+ }
+ assert (
+ name in trans_funcs.keys()
+ ), "Transformation function '{}' not supported".format(name)
+ return trans_funcs[name]
+
+
+class BasicTransform(nn.Module):
+ """
+ Basic transformation: Tx3x3, 1x3x3, where T is the size of temporal kernel.
+ """
+
+ def __init__(
+ self,
+ dim_in,
+ dim_out,
+ temp_kernel_size,
+ stride,
+ dim_inner=None,
+ num_groups=1,
+ stride_1x1=None,
+ inplace_relu=True,
+ eps=1e-5,
+ bn_mmt=0.1,
+ norm_module=nn.BatchNorm3d,
+ ):
+ """
+ Args:
+ dim_in (int): the channel dimensions of the input.
+ dim_out (int): the channel dimension of the output.
+ temp_kernel_size (int): the temporal kernel sizes of the first
+ convolution in the basic block.
+ stride (int): the stride of the bottleneck.
+ dim_inner (None): the inner dimension would not be used in
+ BasicTransform.
+ num_groups (int): number of groups for the convolution. Number of
+ group is always 1 for BasicTransform.
+ stride_1x1 (None): stride_1x1 will not be used in BasicTransform.
+ inplace_relu (bool): if True, calculate the relu on the original
+ input without allocating new memory.
+ eps (float): epsilon for batch norm.
+ bn_mmt (float): momentum for batch norm. Noted that BN momentum in
+ PyTorch = 1 - BN momentum in Caffe2.
+ norm_module (nn.Module): nn.Module for the normalization layer. The
+ default is nn.BatchNorm3d.
+ """
+ super(BasicTransform, self).__init__()
+ self.temp_kernel_size = temp_kernel_size
+ self._inplace_relu = inplace_relu
+ self._eps = eps
+ self._bn_mmt = bn_mmt
+ self._construct(dim_in, dim_out, stride, norm_module)
+
+ def _construct(self, dim_in, dim_out, stride, norm_module):
+ # Tx3x3, BN, ReLU.
+ self.a = nn.Conv3d(
+ dim_in,
+ dim_out,
+ kernel_size=[self.temp_kernel_size, 3, 3],
+ stride=[1, stride, stride],
+ padding=[int(self.temp_kernel_size // 2), 1, 1],
+ bias=False,
+ )
+ self.a_bn = norm_module(
+ num_features=dim_out, eps=self._eps, momentum=self._bn_mmt
+ )
+ self.a_relu = nn.ReLU(inplace=self._inplace_relu)
+ # 1x3x3, BN.
+ self.b = nn.Conv3d(
+ dim_out,
+ dim_out,
+ kernel_size=[1, 3, 3],
+ stride=[1, 1, 1],
+ padding=[0, 1, 1],
+ bias=False,
+ )
+ self.b_bn = norm_module(
+ num_features=dim_out, eps=self._eps, momentum=self._bn_mmt
+ )
+
+ self.b_bn.transform_final_bn = True
+
+ def forward(self, x):
+ x = self.a(x)
+ x = self.a_bn(x)
+ x = self.a_relu(x)
+
+ x = self.b(x)
+ x = self.b_bn(x)
+ return x
+
+class TemporalTransform(nn.Module):
+ """
+ Basic transformation: Tx3x3, 1x3x3, where T is the size of temporal kernel.
+ """
+
+ def __init__(
+ self,
+ dim_in,
+ dim_out,
+ temp_kernel_size,
+ stride,
+ dim_inner=None,
+ num_groups=1,
+ stride_1x1=None,
+ inplace_relu=True,
+ eps=1e-5,
+ bn_mmt=0.1,
+ norm_module=nn.BatchNorm3d,
+ dilation=1
+ ):
+ """
+ Args:
+ dim_in (int): the channel dimensions of the input.
+ dim_out (int): the channel dimension of the output.
+ temp_kernel_size (int): the temporal kernel sizes of the first
+ convolution in the basic block.
+ stride (int): the stride of the bottleneck.
+ dim_inner (None): the inner dimension would not be used in
+ BasicTransform.
+ num_groups (int): number of groups for the convolution. Number of
+ group is always 1 for BasicTransform.
+ stride_1x1 (None): stride_1x1 will not be used in BasicTransform.
+ inplace_relu (bool): if True, calculate the relu on the original
+ input without allocating new memory.
+ eps (float): epsilon for batch norm.
+ bn_mmt (float): momentum for batch norm. Noted that BN momentum in
+ PyTorch = 1 - BN momentum in Caffe2.
+ norm_module (nn.Module): nn.Module for the normalization layer. The
+ default is nn.BatchNorm3d.
+ """
+ super(TemporalTransform, self).__init__()
+ self.temp_kernel_size = temp_kernel_size
+ self._inplace_relu = inplace_relu
+ self._eps = eps
+ self._bn_mmt = bn_mmt
+ self._construct(dim_in, dim_out, stride, norm_module)
+
+ def _construct(self, dim_in, dim_out, stride, norm_module):
+ # Tx3x3, BN, ReLU.
+ self.a = nn.Conv3d(
+ dim_in,
+ dim_out,
+ kernel_size=[self.temp_kernel_size, 3, 3],
+ stride=[1, stride, stride],
+ padding=[int(self.temp_kernel_size // 2), 1, 1],
+ bias=False,
+ )
+ self.a_bn = norm_module(
+ num_features=dim_out, eps=self._eps, momentum=self._bn_mmt
+ )
+ self.a_relu = nn.ReLU(inplace=self._inplace_relu)
+ # 1x3x3, BN.
+ self.b = nn.Conv3d(
+ dim_out,
+ dim_out,
+ kernel_size=[1, 3, 3],
+ stride=[1, 1, 1],
+ padding=[0, 1, 1],
+ bias=False,
+ )
+ self.b_bn = norm_module(
+ num_features=dim_out, eps=self._eps, momentum=self._bn_mmt
+ )
+
+ self.b_bn.transform_final_bn = True
+
+ def forward(self, x):
+ x = self.a(x)
+ x = self.a_bn(x)
+ x = self.a_relu(x)
+
+ x = self.b(x)
+ x = self.b_bn(x)
+ return x
+
+
+class BottleneckTransform(nn.Module):
+ """
+ Bottleneck transformation: Tx1x1, 1x3x3, 1x1x1, where T is the size of
+ temporal kernel.
+ """
+
+ def __init__(
+ self,
+ dim_in,
+ dim_out,
+ temp_kernel_size,
+ stride,
+ dim_inner,
+ num_groups,
+ stride_1x1=False,
+ inplace_relu=True,
+ eps=1e-5,
+ bn_mmt=0.1,
+ dilation=1,
+ norm_module=nn.BatchNorm3d,
+ ):
+ """
+ Args:
+ dim_in (int): the channel dimensions of the input.
+ dim_out (int): the channel dimension of the output.
+ temp_kernel_size (int): the temporal kernel sizes of the first
+ convolution in the bottleneck.
+ stride (int): the stride of the bottleneck.
+ dim_inner (int): the inner dimension of the block.
+ num_groups (int): number of groups for the convolution. num_groups=1
+ is for standard ResNet like networks, and num_groups>1 is for
+ ResNeXt like networks.
+ stride_1x1 (bool): if True, apply stride to 1x1 conv, otherwise
+ apply stride to the 3x3 conv.
+ inplace_relu (bool): if True, calculate the relu on the original
+ input without allocating new memory.
+ eps (float): epsilon for batch norm.
+ bn_mmt (float): momentum for batch norm. Noted that BN momentum in
+ PyTorch = 1 - BN momentum in Caffe2.
+ dilation (int): size of dilation.
+ norm_module (nn.Module): nn.Module for the normalization layer. The
+ default is nn.BatchNorm3d.
+ """
+ super(BottleneckTransform, self).__init__()
+ self.temp_kernel_size = temp_kernel_size
+ self._inplace_relu = inplace_relu
+ self._eps = eps
+ self._bn_mmt = bn_mmt
+ self._stride_1x1 = stride_1x1
+ self._construct(
+ dim_in,
+ dim_out,
+ stride,
+ dim_inner,
+ num_groups,
+ dilation,
+ norm_module,
+ )
+
+ def _construct(
+ self,
+ dim_in,
+ dim_out,
+ stride,
+ dim_inner,
+ num_groups,
+ dilation,
+ norm_module,
+ ):
+ (str1x1, str3x3) = (stride, 1) if self._stride_1x1 else (1, stride)
+
+ # Tx1x1, BN, ReLU.
+ self.a = nn.Conv3d(
+ dim_in,
+ dim_inner,
+ kernel_size=[self.temp_kernel_size, 1, 1],
+ stride=[1, str1x1, str1x1],
+ padding=[int(self.temp_kernel_size // 2), 0, 0],
+ bias=False,
+ )
+ self.a_bn = norm_module(
+ num_features=dim_inner, eps=self._eps, momentum=self._bn_mmt
+ )
+ self.a_relu = nn.ReLU(inplace=self._inplace_relu)
+
+ # 1x3x3, BN, ReLU.
+ self.b = nn.Conv3d(
+ dim_inner,
+ dim_inner,
+ [1, 3, 3],
+ stride=[1, str3x3, str3x3],
+ padding=[0, dilation, dilation],
+ groups=num_groups,
+ bias=False,
+ dilation=[1, dilation, dilation],
+ )
+ self.b_bn = norm_module(
+ num_features=dim_inner, eps=self._eps, momentum=self._bn_mmt
+ )
+ self.b_relu = nn.ReLU(inplace=self._inplace_relu)
+
+ # 1x1x1, BN.
+ self.c = nn.Conv3d(
+ dim_inner,
+ dim_out,
+ kernel_size=[1, 1, 1],
+ stride=[1, 1, 1],
+ padding=[0, 0, 0],
+ bias=False,
+ )
+ self.c_bn = norm_module(
+ num_features=dim_out, eps=self._eps, momentum=self._bn_mmt
+ )
+ self.c_bn.transform_final_bn = True
+
+ def forward(self, x):
+ # Explicitly forward every layer.
+ # Branch2a.
+ x = self.a(x)
+ x = self.a_bn(x)
+ x = self.a_relu(x)
+
+ # Branch2b.
+ x = self.b(x)
+ x = self.b_bn(x)
+ x = self.b_relu(x)
+
+ # Branch2c
+ x = self.c(x)
+ x = self.c_bn(x)
+ return x
+
+
+class ResBlock(nn.Module):
+ """
+ Residual block.
+ """
+
+ def __init__(
+ self,
+ dim_in,
+ dim_out,
+ temp_kernel_size,
+ stride,
+ trans_func,
+ dim_inner,
+ num_groups=1,
+ stride_1x1=False,
+ inplace_relu=True, # default :: False
+ # ################### Fixed by TH for training FT###############################
+ eps=1e-5,
+ bn_mmt=0.1,
+ dilation=1,
+ norm_module=nn.BatchNorm3d,
+ ):
+ """
+ ResBlock class constructs redisual blocks. More details can be found in:
+ Kaiming He, Xiangyu Zhang, Shaoqing Ren, and Jian Sun.
+ "Deep residual learning for image recognition."
+ https://arxiv.org/abs/1512.03385
+ Args:
+ dim_in (int): the channel dimensions of the input.
+ dim_out (int): the channel dimension of the output.
+ temp_kernel_size (int): the temporal kernel sizes of the middle
+ convolution in the bottleneck.
+ stride (int): the stride of the bottleneck.
+ trans_func (string): transform function to be used to construct the
+ bottleneck.
+ dim_inner (int): the inner dimension of the block.
+ num_groups (int): number of groups for the convolution. num_groups=1
+ is for standard ResNet like networks, and num_groups>1 is for
+ ResNeXt like networks.
+ stride_1x1 (bool): if True, apply stride to 1x1 conv, otherwise
+ apply stride to the 3x3 conv.
+ inplace_relu (bool): calculate the relu on the original input
+ without allocating new memory.
+ eps (float): epsilon for batch norm.
+ bn_mmt (float): momentum for batch norm. Noted that BN momentum in
+ PyTorch = 1 - BN momentum in Caffe2.
+ dilation (int): size of dilation.
+ norm_module (nn.Module): nn.Module for the normalization layer. The
+ default is nn.BatchNorm3d.
+ """
+ super(ResBlock, self).__init__()
+ self._inplace_relu = inplace_relu
+ self._eps = eps
+ self._bn_mmt = bn_mmt
+ self._construct(
+ dim_in,
+ dim_out,
+ temp_kernel_size,
+ stride,
+ trans_func,
+ dim_inner,
+ num_groups,
+ stride_1x1,
+ inplace_relu,
+ dilation,
+ norm_module,
+ )
+
+ def _construct(
+ self,
+ dim_in,
+ dim_out,
+ temp_kernel_size,
+ stride,
+ trans_func,
+ dim_inner,
+ num_groups,
+ stride_1x1,
+ inplace_relu,
+ dilation,
+ norm_module,
+ ):
+ # Use skip connection with projection if dim or res change.
+ if (dim_in != dim_out) or (stride != 1):
+ self.branch1 = nn.Conv3d(
+ dim_in,
+ dim_out,
+ kernel_size=1,
+ stride=[1, stride, stride],
+ padding=0,
+ bias=False,
+ dilation=1,
+ )
+ self.branch1_bn = norm_module(
+ num_features=dim_out, eps=self._eps, momentum=self._bn_mmt
+ )
+ self.branch2 = trans_func(
+ dim_in,
+ dim_out,
+ temp_kernel_size,
+ stride,
+ dim_inner,
+ num_groups,
+ stride_1x1=stride_1x1,
+ inplace_relu=inplace_relu,
+ dilation=dilation,
+ norm_module=norm_module,
+ )
+ self.relu = nn.ReLU(self._inplace_relu)
+
+ def forward(self, x):
+ if hasattr(self, "branch1"):
+ x = self.branch1_bn(self.branch1(x)) + self.branch2(x)
+ else:
+ x = x + self.branch2(x)
+
+ x = self.relu(x)
+ return x
+
+
+class ResStage(nn.Module):
+ """
+ Stage of 3D ResNet. It expects to have one or more tensors as input for
+ single pathway (C2D, I3D, Slow), and multi-pathway (SlowFast) cases.
+ More details can be found here:
+
+ Christoph Feichtenhofer, Haoqi Fan, Jitendra Malik, and Kaiming He.
+ "SlowFast networks for video recognition."
+ https://arxiv.org/pdf/1812.03982.pdf
+ """
+
+ def __init__(
+ self,
+ dim_in,
+ dim_out,
+ stride,
+ temp_kernel_sizes,
+ num_blocks,
+ dim_inner,
+ num_groups,
+ num_block_temp_kernel,
+ nonlocal_inds,
+ nonlocal_group,
+ nonlocal_pool,
+ dilation,
+ instantiation="softmax",
+ trans_func_name="bottleneck_transform",
+ stride_1x1=False,
+ inplace_relu=True, ## Fixed by TH
+ norm_module=nn.BatchNorm3d,
+ ):
+ """
+ The `__init__` method of any subclass should also contain these arguments.
+ ResStage builds p streams, where p can be greater or equal to one.
+ Args:
+ dim_in (list): list of p the channel dimensions of the input.
+ Different channel dimensions control the input dimension of
+ different pathways.
+ dim_out (list): list of p the channel dimensions of the output.
+ Different channel dimensions control the input dimension of
+ different pathways.
+ temp_kernel_sizes (list): list of the p temporal kernel sizes of the
+ convolution in the bottleneck. Different temp_kernel_sizes
+ control different pathway.
+ stride (list): list of the p strides of the bottleneck. Different
+ stride control different pathway.
+ num_blocks (list): list of p numbers of blocks for each of the
+ pathway.
+ dim_inner (list): list of the p inner channel dimensions of the
+ input. Different channel dimensions control the input dimension
+ of different pathways.
+ num_groups (list): list of number of p groups for the convolution.
+ num_groups=1 is for standard ResNet like networks, and
+ num_groups>1 is for ResNeXt like networks.
+ num_block_temp_kernel (list): extent the temp_kernel_sizes to
+ num_block_temp_kernel blocks, then fill temporal kernel size
+ of 1 for the rest of the layers.
+ nonlocal_inds (list): If the tuple is empty, no nonlocal layer will
+ be added. If the tuple is not empty, add nonlocal layers after
+ the index-th block.
+ dilation (list): size of dilation for each pathway.
+ nonlocal_group (list): list of number of p nonlocal groups. Each
+ number controls how to fold temporal dimension to batch
+ dimension before applying nonlocal transformation.
+ https://github.com/facebookresearch/video-nonlocal-net.
+ instantiation (string): different instantiation for nonlocal layer.
+ Supports two different instantiation method:
+ "dot_product": normalizing correlation matrix with L2.
+ "softmax": normalizing correlation matrix with Softmax.
+ trans_func_name (string): name of the the transformation function apply
+ on the network.
+ norm_module (nn.Module): nn.Module for the normalization layer. The
+ default is nn.BatchNorm3d.
+ """
+ super(ResStage, self).__init__()
+ assert all(
+ (
+ num_block_temp_kernel[i] <= num_blocks[i]
+ for i in range(len(temp_kernel_sizes))
+ )
+ )
+ self.num_blocks = num_blocks
+ self.nonlocal_group = nonlocal_group
+ self.temp_kernel_sizes = [
+ (temp_kernel_sizes[i] * num_blocks[i])[: num_block_temp_kernel[i]]
+ + [1] * (num_blocks[i] - num_block_temp_kernel[i])
+ for i in range(len(temp_kernel_sizes))
+ ]
+ assert (
+ len(
+ {
+ len(dim_in),
+ len(dim_out),
+ len(temp_kernel_sizes),
+ len(stride),
+ len(num_blocks),
+ len(dim_inner),
+ len(num_groups),
+ len(num_block_temp_kernel),
+ len(nonlocal_inds),
+ len(nonlocal_group),
+ }
+ )
+ == 1
+ )
+ self.num_pathways = len(self.num_blocks)
+ self._construct(
+ dim_in,
+ dim_out,
+ stride,
+ dim_inner,
+ num_groups,
+ trans_func_name,
+ stride_1x1,
+ inplace_relu,
+ nonlocal_inds,
+ nonlocal_pool,
+ instantiation,
+ dilation,
+ norm_module,
+ )
+
+ def _construct(
+ self,
+ dim_in,
+ dim_out,
+ stride,
+ dim_inner,
+ num_groups,
+ trans_func_name,
+ stride_1x1,
+ inplace_relu,
+ nonlocal_inds,
+ nonlocal_pool,
+ instantiation,
+ dilation,
+ norm_module,
+ ):
+ for pathway in range(self.num_pathways):
+ for i in range(self.num_blocks[pathway]):
+ # Retrieve the transformation function.
+ trans_func = get_trans_func(trans_func_name)
+ # Construct the block.
+ res_block = ResBlock(
+ dim_in[pathway] if i == 0 else dim_out[pathway],
+ dim_out[pathway],
+ self.temp_kernel_sizes[pathway][i],
+ stride[pathway] if i == 0 else 1,
+ trans_func,
+ dim_inner[pathway],
+ num_groups[pathway],
+ stride_1x1=stride_1x1,
+ inplace_relu=inplace_relu,
+ dilation=dilation[pathway],
+ norm_module=norm_module,
+ )
+ self.add_module("pathway{}_res{}".format(pathway, i), res_block)
+ if i in nonlocal_inds[pathway]:
+ nln = Nonlocal(
+ dim_out[pathway],
+ dim_out[pathway] // 2,
+ nonlocal_pool[pathway],
+ instantiation=instantiation,
+ norm_module=norm_module,
+ )
+ self.add_module(
+ "pathway{}_nonlocal{}".format(pathway, i), nln
+ )
+
+ def forward(self, inputs):
+ output = []
+ for pathway in range(self.num_pathways):
+ x = inputs[pathway]
+ for i in range(self.num_blocks[pathway]):
+ m = getattr(self, "pathway{}_res{}".format(pathway, i))
+ x = m(x)
+ if hasattr(self, "pathway{}_nonlocal{}".format(pathway, i)):
+ nln = getattr(
+ self, "pathway{}_nonlocal{}".format(pathway, i)
+ )
+ b, c, t, h, w = x.shape
+ if self.nonlocal_group[pathway] > 1:
+ # Fold temporal dimension into batch dimension.
+ x = x.permute(0, 2, 1, 3, 4)
+ x = x.reshape(
+ b * self.nonlocal_group[pathway],
+ t // self.nonlocal_group[pathway],
+ c,
+ h,
+ w,
+ )
+ x = x.permute(0, 2, 1, 3, 4)
+ x = nln(x)
+ if self.nonlocal_group[pathway] > 1:
+ # Fold back to temporal dimension.
+ x = x.permute(0, 2, 1, 3, 4)
+ x = x.reshape(b, t, c, h, w)
+ x = x.permute(0, 2, 1, 3, 4)
+ output.append(x)
+
+ return output
diff --git a/clean/video/pwtf_dvd/inference/slowfast/models/stem_helper.py b/clean/video/pwtf_dvd/inference/slowfast/models/stem_helper.py
new file mode 100644
index 0000000000000000000000000000000000000000..481977b15a13edf54bfdb17fd3627b6657d56262
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/models/stem_helper.py
@@ -0,0 +1,178 @@
+#!/usr/bin/env python3
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+
+"""ResNe(X)t 3D stem helper."""
+
+import torch.nn as nn
+
+
+class VideoModelStem(nn.Module):
+ """
+ Video 3D stem module. Provides stem operations of Conv, BN, ReLU, MaxPool
+ on input data tensor for one or multiple pathways.
+ """
+
+ def __init__(
+ self,
+ dim_in,
+ dim_out,
+ kernel,
+ stride,
+ padding,
+ inplace_relu=True,
+ eps=1e-5,
+ bn_mmt=0.1,
+ norm_module=nn.BatchNorm3d,
+ ):
+ """
+ The `__init__` method of any subclass should also contain these
+ arguments. List size of 1 for single pathway models (C2D, I3D, Slow
+ and etc), list size of 2 for two pathway models (SlowFast).
+
+ Args:
+ dim_in (list): the list of channel dimensions of the inputs.
+ dim_out (list): the output dimension of the convolution in the stem
+ layer.
+ kernel (list): the kernels' size of the convolutions in the stem
+ layers. Temporal kernel size, height kernel size, width kernel
+ size in order.
+ stride (list): the stride sizes of the convolutions in the stem
+ layer. Temporal kernel stride, height kernel size, width kernel
+ size in order.
+ padding (list): the paddings' sizes of the convolutions in the stem
+ layer. Temporal padding size, height padding size, width padding
+ size in order.
+ inplace_relu (bool): calculate the relu on the original input
+ without allocating new memory.
+ eps (float): epsilon for batch norm.
+ bn_mmt (float): momentum for batch norm. Noted that BN momentum in
+ PyTorch = 1 - BN momentum in Caffe2.
+ norm_module (nn.Module): nn.Module for the normalization layer. The
+ default is nn.BatchNorm3d.
+ """
+ super(VideoModelStem, self).__init__()
+
+ assert (
+ len(
+ {
+ len(dim_in),
+ len(dim_out),
+ len(kernel),
+ len(stride),
+ len(padding),
+ }
+ )
+ == 1
+ ), "Input pathway dimensions are not consistent."
+ self.num_pathways = len(dim_in)
+ self.kernel = kernel
+ self.stride = stride
+ self.padding = padding
+ self.inplace_relu = inplace_relu
+ self.eps = eps
+ self.bn_mmt = bn_mmt
+ # Construct the stem layer.
+ self._construct_stem(dim_in, dim_out, norm_module)
+
+ def _construct_stem(self, dim_in, dim_out, norm_module):
+ for pathway in range(len(dim_in)):
+ stem = ResNetBasicStem(
+ dim_in[pathway],
+ dim_out[pathway],
+ self.kernel[pathway],
+ self.stride[pathway],
+ self.padding[pathway],
+ self.inplace_relu,
+ self.eps,
+ self.bn_mmt,
+ norm_module,
+ )
+ self.add_module("pathway{}_stem".format(pathway), stem)
+
+ def forward(self, x):
+ assert (
+ len(x) == self.num_pathways
+ ), "Input tensor does not contain {} pathway".format(self.num_pathways)
+ for pathway in range(len(x)):
+ m = getattr(self, "pathway{}_stem".format(pathway))
+ x[pathway] = m(x[pathway])
+ return x
+
+
+class ResNetBasicStem(nn.Module):
+ """
+ ResNe(X)t 3D stem module.
+ Performs spatiotemporal Convolution, BN, and Relu following by a
+ spatiotemporal pooling.
+ """
+
+ def __init__(
+ self,
+ dim_in,
+ dim_out,
+ kernel,
+ stride,
+ padding,
+ inplace_relu=True,
+ eps=1e-5,
+ bn_mmt=0.1,
+ norm_module=nn.BatchNorm3d,
+ ):
+ """
+ The `__init__` method of any subclass should also contain these arguments.
+
+ Args:
+ dim_in (int): the channel dimension of the input. Normally 3 is used
+ for rgb input, and 2 or 3 is used for optical flow input.
+ dim_out (int): the output dimension of the convolution in the stem
+ layer.
+ kernel (list): the kernel size of the convolution in the stem layer.
+ temporal kernel size, height kernel size, width kernel size in
+ order.
+ stride (list): the stride size of the convolution in the stem layer.
+ temporal kernel stride, height kernel size, width kernel size in
+ order.
+ padding (int): the padding size of the convolution in the stem
+ layer, temporal padding size, height padding size, width
+ padding size in order.
+ inplace_relu (bool): calculate the relu on the original input
+ without allocating new memory.
+ eps (float): epsilon for batch norm.
+ bn_mmt (float): momentum for batch norm. Noted that BN momentum in
+ PyTorch = 1 - BN momentum in Caffe2.
+ norm_module (nn.Module): nn.Module for the normalization layer. The
+ default is nn.BatchNorm3d.
+ """
+ super(ResNetBasicStem, self).__init__()
+ self.kernel = kernel
+ self.stride = stride
+ self.padding = padding
+ self.inplace_relu = inplace_relu
+ self.eps = eps
+ self.bn_mmt = bn_mmt
+ # Construct the stem layer.
+ self._construct_stem(dim_in, dim_out, norm_module)
+
+ def _construct_stem(self, dim_in, dim_out, norm_module):
+ self.conv = nn.Conv3d(
+ dim_in,
+ dim_out,
+ self.kernel,
+ stride=self.stride,
+ padding=self.padding,
+ bias=False,
+ )
+ self.bn = norm_module(
+ num_features=dim_out, eps=self.eps, momentum=self.bn_mmt
+ )
+ self.relu = nn.ReLU(self.inplace_relu)
+ self.pool_layer = nn.MaxPool3d(
+ kernel_size=[1, 3, 3], stride=[1, 2, 2], padding=[0, 1, 1]
+ )
+
+ def forward(self, x):
+ x = self.conv(x)
+ x = self.bn(x)
+ x = self.relu(x)
+ x = self.pool_layer(x)
+ return x
diff --git a/clean/video/pwtf_dvd/inference/slowfast/models/unet_helper.py b/clean/video/pwtf_dvd/inference/slowfast/models/unet_helper.py
new file mode 100644
index 0000000000000000000000000000000000000000..36b7202cd1936a433b193017f6c363e5dd317b4f
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/models/unet_helper.py
@@ -0,0 +1,157 @@
+InPlaceABN = None
+from torch import nn
+import torch.nn.functional as F
+
+
+class Conv3dReLU(nn.Sequential):
+ def __init__(
+ self,
+ in_channels,
+ out_channels,
+ kernel_size,
+ padding=0,
+ stride=1,
+ use_batchnorm=True,
+ ):
+
+ if use_batchnorm == "inplace" and InPlaceABN is None:
+ raise RuntimeError(
+ "In order to use `use_batchnorm='inplace'` inplace_abn package must be installed. "
+ + "To install see: https://github.com/mapillary/inplace_abn"
+ )
+
+ conv = nn.Conv3d(
+ in_channels,
+ out_channels,
+ kernel_size,
+ stride=stride,
+ padding=padding,
+ bias=not (use_batchnorm),
+ )
+ relu = nn.ReLU(inplace=True)
+
+ if use_batchnorm == "inplace":
+ bn = InPlaceABN(out_channels, activation="leaky_relu", activation_param=0.0)
+ relu = nn.Identity()
+
+ elif use_batchnorm and use_batchnorm != "inplace":
+ bn = nn.BatchNorm3d(out_channels)
+
+ else:
+ bn = nn.Identity()
+
+ super(Conv3dReLU, self).__init__(conv, bn, relu)
+
+
+class DecoderBlock(nn.Module):
+ def __init__(
+ self, in_channels, skip_channels, out_channels, use_batchnorm=True,
+ ):
+ super().__init__()
+ self.conv1 = Conv3dReLU(
+ in_channels + skip_channels,
+ out_channels,
+ kernel_size=3,
+ padding=1,
+ use_batchnorm=use_batchnorm,
+ )
+
+ self.conv2 = Conv3dReLU(
+ out_channels,
+ out_channels,
+ kernel_size=3,
+ padding=1,
+ use_batchnorm=use_batchnorm,
+ )
+
+ def forward(self, x):
+ x = self.conv1(x)
+ x = self.conv2(x)
+ return x
+
+
+class LightDecoderBlock(nn.Module):
+ def __init__(
+ self, in_channels, skip_channels, out_channels, use_batchnorm=True,
+ ):
+ super().__init__()
+ self.conv1 = Conv3dReLU(
+ in_channels + skip_channels,
+ out_channels,
+ kernel_size=3,
+ padding=1,
+ use_batchnorm=use_batchnorm,
+ )
+
+ def forward(self, x):
+ x = self.conv1(x)
+ return x
+
+
+def freeze_net(model: nn.Module, freeze_prefixs):
+ flag = False
+ for name, param in model.named_parameters():
+ items = name.split(".")
+ if items[0] == "module":
+ prefix = items[1]
+ else:
+ prefix = items[0]
+ if prefix in freeze_prefixs:
+ if param.requires_grad is True:
+ param.requires_grad = False
+ flag = True
+ # print("freeze",name)
+
+ assert flag
+
+
+def unfreeze_net(model: nn.Module):
+ for name, param in model.named_parameters():
+ param.requires_grad = True
+
+
+from .resnet_helper import ResBlock, get_trans_func
+
+
+class ResDecoderBlock(nn.Module):
+ def __init__(
+ self, in_channels, skip_channels, out_channels, use_batchnorm=True,
+ ):
+ super().__init__()
+ trans_func = get_trans_func("bottleneck_transform")
+ self.conv1 = ResBlock(
+ in_channels + skip_channels,
+ out_channels,
+ 3,
+ 1,
+ trans_func,
+ out_channels//2,
+ num_groups=1,
+ stride_1x1=False,
+ inplace_relu=True,
+ eps=1e-5,
+ bn_mmt=0.1,
+ dilation=1,
+ norm_module=nn.BatchNorm3d,
+ )
+
+ self.conv2 = ResBlock(
+ out_channels,
+ out_channels,
+ 3,
+ 1,
+ trans_func,
+ out_channels//2,
+ num_groups=1,
+ stride_1x1=False,
+ inplace_relu=True,
+ eps=1e-5,
+ bn_mmt=0.1,
+ dilation=1,
+ norm_module=nn.BatchNorm3d,
+ )
+
+ def forward(self, x):
+ x = self.conv1(x)
+ x = self.conv2(x)
+ return x
diff --git a/clean/video/pwtf_dvd/inference/slowfast/models/video_model_builder.py b/clean/video/pwtf_dvd/inference/slowfast/models/video_model_builder.py
new file mode 100644
index 0000000000000000000000000000000000000000..9a60fc57ccb7c2a322c2a43bc738650b97d7a958
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/models/video_model_builder.py
@@ -0,0 +1,2772 @@
+#!/usr/bin/env python3
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+
+"""Video models."""
+
+import torch
+import torch.nn as nn
+import copy
+
+import slowfast.utils.weight_init_helper as init_helper
+from slowfast.models.batchnorm_helper import get_norm
+
+from . import head_helper, resnet_helper, stem_helper
+from .build import MODEL_REGISTRY
+
+# Number of blocks for different stages given the model depth.
+_MODEL_STAGE_DEPTH = {18:(2,2,2,2),50: (3, 4, 6, 3), 101: (3, 4, 23, 3)}
+
+# Basis of temporal kernel sizes for each of the stage.
+_TEMPORAL_KERNEL_BASIS = {
+ "c2d": [
+ [[1]], # conv1 temporal kernel.
+ [[1]], # res2 temporal kernel.
+ [[1]], # res3 temporal kernel.
+ [[1]], # res4 temporal kernel.
+ [[1]], # res5 temporal kernel.
+ ],
+ "c2d_nopool": [
+ [[1]], # conv1 temporal kernel.
+ [[1]], # res2 temporal kernel.
+ [[1]], # res3 temporal kernel.
+ [[1]], # res4 temporal kernel.
+ [[1]], # res5 temporal kernel.
+ ],
+ "i3d": [
+ [[5]], # conv1 temporal kernel.
+ [[3]], # res2 temporal kernel.
+ [[3, 1]], # res3 temporal kernel.
+ [[3, 1]], # res4 temporal kernel.
+ [[1, 3]], # res5 temporal kernel.
+ ],
+ "r3d_18": [
+ [[3]], # conv1 temporal kernel.
+ [[3]], # res2 temporal kernel.
+ [[3, 1]], # res3 temporal kernel.
+ [[3, 1]], # res4 temporal kernel.
+ [[1, 3]], # res5 temporal kernel.
+ ],
+ "i3d_nopool": [
+ [[5]], # conv1 temporal kernel.
+ [[3]], # res2 temporal kernel.
+ [[3, 1]], # res3 temporal kernel.
+ [[3, 1]], # res4 temporal kernel.
+ [[1, 3]], # res5 temporal kernel.
+ ],
+ "slow": [
+ [[1]], # conv1 temporal kernel.
+ [[1]], # res2 temporal kernel.
+ [[1]], # res3 temporal kernel.
+ [[3]], # res4 temporal kernel.
+ [[3]], # res5 temporal kernel.
+ ],
+ "slowfast": [
+ [[1], [5]], # conv1 temporal kernel for slow and fast pathway.
+ [[1], [3]], # res2 temporal kernel for slow and fast pathway.
+ [[1], [3]], # res3 temporal kernel for slow and fast pathway.
+ [[3], [3]], # res4 temporal kernel for slow and fast pathway.
+ [[3], [3]], # res5 temporal kernel for slow and fast pathway.
+ ],
+}
+
+_POOL1 = {
+ "c2d": [[2, 1, 1]],
+ "c2d_nopool": [[1, 1, 1]],
+ "i3d": [[2, 1, 1]],
+ "r3d_18": [[2, 1, 1]],
+ "i3d_nopool": [[1, 1, 1]],
+ "slow": [[1, 1, 1]],
+ "slowfast": [[1, 1, 1], [1, 1, 1]],
+}
+
+
+
+
+class FuseFastToSlow(nn.Module):
+ """
+ Fuses the information from the Fast pathway to the Slow pathway. Given the
+ tensors from Slow pathway and Fast pathway, fuse information from Fast to
+ Slow, then return the fused tensors from Slow and Fast pathway in order.
+ """
+
+ def __init__(
+ self,
+ dim_in,
+ fusion_conv_channel_ratio,
+ fusion_kernel,
+ alpha,
+ eps=1e-5,
+ bn_mmt=0.1,
+ inplace_relu=True,
+ norm_module=nn.BatchNorm3d,
+ ):
+ """
+ Args:
+ dim_in (int): the channel dimension of the input.
+ fusion_conv_channel_ratio (int): channel ratio for the convolution
+ used to fuse from Fast pathway to Slow pathway.
+ fusion_kernel (int): kernel size of the convolution used to fuse
+ from Fast pathway to Slow pathway.
+ alpha (int): the frame rate ratio between the Fast and Slow pathway.
+ eps (float): epsilon for batch norm.
+ bn_mmt (float): momentum for batch norm. Noted that BN momentum in
+ PyTorch = 1 - BN momentum in Caffe2.
+ inplace_relu (bool): if True, calculate the relu on the original
+ input without allocating new memory.
+ norm_module (nn.Module): nn.Module for the normalization layer. The
+ default is nn.BatchNorm3d.
+ """
+ super(FuseFastToSlow, self).__init__()
+ self.conv_f2s = nn.Conv3d(
+ dim_in,
+ dim_in * fusion_conv_channel_ratio,
+ kernel_size=[fusion_kernel, 1, 1],
+ stride=[alpha, 1, 1],
+ padding=[fusion_kernel // 2, 0, 0],
+ bias=False,
+ )
+ self.bn = norm_module(
+ num_features=dim_in * fusion_conv_channel_ratio,
+ eps=eps,
+ momentum=bn_mmt,
+ )
+ self.relu = nn.ReLU(inplace_relu)
+
+ def forward(self, x):
+ x_s = x[0]
+ x_f = x[1]
+ fuse = self.conv_f2s(x_f)
+ fuse = self.bn(fuse)
+ fuse = self.relu(fuse)
+ x_s_fuse = torch.cat([x_s, fuse], 1)
+ return [x_s_fuse, x_f]
+
+
+
+@MODEL_REGISTRY.register()
+class SlowFast(nn.Module):
+ """
+ SlowFast model builder for SlowFast network.
+
+ Christoph Feichtenhofer, Haoqi Fan, Jitendra Malik, and Kaiming He.
+ "SlowFast networks for video recognition."
+ https://arxiv.org/pdf/1812.03982.pdf
+ """
+
+ def __init__(self, cfg):
+ """
+ The `__init__` method of any subclass should also contain these
+ arguments.
+ Args:
+ cfg (CfgNode): model building configs, details are in the
+ comments of the config file.
+ """
+ super(SlowFast, self).__init__()
+ self.norm_module = get_norm(cfg)
+ self.enable_detection = cfg.DETECTION.ENABLE
+ self.num_pathways = 2
+ self._construct_network(cfg)
+ init_helper.init_weights(
+ self, cfg.MODEL.FC_INIT_STD, cfg.RESNET.ZERO_INIT_FINAL_BN
+ )
+
+ def _construct_network(self, cfg):
+ """
+ Builds a SlowFast model. The first pathway is the Slow pathway and the
+ second pathway is the Fast pathway.
+ Args:
+ cfg (CfgNode): model building configs, details are in the
+ comments of the config file.
+ """
+ assert cfg.MODEL.ARCH in _POOL1.keys()
+ pool_size = _POOL1[cfg.MODEL.ARCH]
+ assert len({len(pool_size), self.num_pathways}) == 1
+ assert cfg.RESNET.DEPTH in _MODEL_STAGE_DEPTH.keys()
+
+ (d2, d3, d4, d5) = _MODEL_STAGE_DEPTH[cfg.RESNET.DEPTH]
+
+ num_groups = cfg.RESNET.NUM_GROUPS
+ width_per_group = cfg.RESNET.WIDTH_PER_GROUP
+ dim_inner = num_groups * width_per_group
+ out_dim_ratio = (
+ cfg.SLOWFAST.BETA_INV // cfg.SLOWFAST.FUSION_CONV_CHANNEL_RATIO
+ )
+
+ temp_kernel = _TEMPORAL_KERNEL_BASIS[cfg.MODEL.ARCH]
+
+ self.s1 = stem_helper.VideoModelStem(
+ dim_in=cfg.DATA.INPUT_CHANNEL_NUM,
+ dim_out=[width_per_group, width_per_group // cfg.SLOWFAST.BETA_INV],
+ kernel=[temp_kernel[0][0] + [7, 7], temp_kernel[0][1] + [7, 7]],
+ stride=[[1, 2, 2]] * 2,
+ padding=[
+ [temp_kernel[0][0][0] // 2, 3, 3],
+ [temp_kernel[0][1][0] // 2, 3, 3],
+ ],
+ norm_module=self.norm_module,
+ )
+ self.s1_fuse = FuseFastToSlow(
+ width_per_group // cfg.SLOWFAST.BETA_INV,
+ cfg.SLOWFAST.FUSION_CONV_CHANNEL_RATIO,
+ cfg.SLOWFAST.FUSION_KERNEL_SZ,
+ cfg.SLOWFAST.ALPHA,
+ norm_module=self.norm_module,
+ )
+
+ self.s2 = resnet_helper.ResStage(
+ dim_in=[
+ width_per_group + width_per_group // out_dim_ratio,
+ width_per_group // cfg.SLOWFAST.BETA_INV,
+ ],
+ dim_out=[
+ width_per_group * 4,
+ width_per_group * 4 // cfg.SLOWFAST.BETA_INV,
+ ],
+ dim_inner=[dim_inner, dim_inner // cfg.SLOWFAST.BETA_INV],
+ temp_kernel_sizes=temp_kernel[1],
+ stride=cfg.RESNET.SPATIAL_STRIDES[0],
+ num_blocks=[d2] * 2,
+ num_groups=[num_groups] * 2,
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[0],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[0],
+ nonlocal_group=cfg.NONLOCAL.GROUP[0],
+ nonlocal_pool=cfg.NONLOCAL.POOL[0],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[0],
+ norm_module=self.norm_module,
+ )
+ self.s2_fuse = FuseFastToSlow(
+ width_per_group * 4 // cfg.SLOWFAST.BETA_INV,
+ cfg.SLOWFAST.FUSION_CONV_CHANNEL_RATIO,
+ cfg.SLOWFAST.FUSION_KERNEL_SZ,
+ cfg.SLOWFAST.ALPHA,
+ norm_module=self.norm_module,
+ )
+
+ for pathway in range(self.num_pathways):
+ pool = nn.MaxPool3d(
+ kernel_size=pool_size[pathway],
+ stride=pool_size[pathway],
+ padding=[0, 0, 0],
+ )
+ self.add_module("pathway{}_pool".format(pathway), pool)
+
+ self.s3 = resnet_helper.ResStage(
+ dim_in=[
+ width_per_group * 4 + width_per_group * 4 // out_dim_ratio,
+ width_per_group * 4 // cfg.SLOWFAST.BETA_INV,
+ ],
+ dim_out=[
+ width_per_group * 8,
+ width_per_group * 8 // cfg.SLOWFAST.BETA_INV,
+ ],
+ dim_inner=[dim_inner * 2, dim_inner * 2 // cfg.SLOWFAST.BETA_INV],
+ temp_kernel_sizes=temp_kernel[2],
+ stride=cfg.RESNET.SPATIAL_STRIDES[1],
+ num_blocks=[d3] * 2,
+ num_groups=[num_groups] * 2,
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[1],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[1],
+ nonlocal_group=cfg.NONLOCAL.GROUP[1],
+ nonlocal_pool=cfg.NONLOCAL.POOL[1],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[1],
+ norm_module=self.norm_module,
+ )
+ self.s3_fuse = FuseFastToSlow(
+ width_per_group * 8 // cfg.SLOWFAST.BETA_INV,
+ cfg.SLOWFAST.FUSION_CONV_CHANNEL_RATIO,
+ cfg.SLOWFAST.FUSION_KERNEL_SZ,
+ cfg.SLOWFAST.ALPHA,
+ norm_module=self.norm_module,
+ )
+
+ self.s4 = resnet_helper.ResStage(
+ dim_in=[
+ width_per_group * 8 + width_per_group * 8 // out_dim_ratio,
+ width_per_group * 8 // cfg.SLOWFAST.BETA_INV,
+ ],
+ dim_out=[
+ width_per_group * 16,
+ width_per_group * 16 // cfg.SLOWFAST.BETA_INV,
+ ],
+ dim_inner=[dim_inner * 4, dim_inner * 4 // cfg.SLOWFAST.BETA_INV],
+ temp_kernel_sizes=temp_kernel[3],
+ stride=cfg.RESNET.SPATIAL_STRIDES[2],
+ num_blocks=[d4] * 2,
+ num_groups=[num_groups] * 2,
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[2],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[2],
+ nonlocal_group=cfg.NONLOCAL.GROUP[2],
+ nonlocal_pool=cfg.NONLOCAL.POOL[2],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[2],
+ norm_module=self.norm_module,
+ )
+ self.s4_fuse = FuseFastToSlow(
+ width_per_group * 16 // cfg.SLOWFAST.BETA_INV,
+ cfg.SLOWFAST.FUSION_CONV_CHANNEL_RATIO,
+ cfg.SLOWFAST.FUSION_KERNEL_SZ,
+ cfg.SLOWFAST.ALPHA,
+ norm_module=self.norm_module,
+ )
+
+ self.s5 = resnet_helper.ResStage(
+ dim_in=[
+ width_per_group * 16 + width_per_group * 16 // out_dim_ratio,
+ width_per_group * 16 // cfg.SLOWFAST.BETA_INV,
+ ],
+ dim_out=[
+ width_per_group * 32,
+ width_per_group * 32 // cfg.SLOWFAST.BETA_INV,
+ ],
+ dim_inner=[dim_inner * 8, dim_inner * 8 // cfg.SLOWFAST.BETA_INV],
+ temp_kernel_sizes=temp_kernel[4],
+ stride=cfg.RESNET.SPATIAL_STRIDES[3],
+ num_blocks=[d5] * 2,
+ num_groups=[num_groups] * 2,
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[3],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[3],
+ nonlocal_group=cfg.NONLOCAL.GROUP[3],
+ nonlocal_pool=cfg.NONLOCAL.POOL[3],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[3],
+ norm_module=self.norm_module,
+ )
+
+ if cfg.DETECTION.ENABLE:
+ raise NotImplementedError
+ else:
+ self.head = head_helper.ResNetBasicHead(
+ dim_in=[
+ width_per_group * 32,
+ width_per_group * 32 // cfg.SLOWFAST.BETA_INV,
+ ],
+ num_classes=cfg.MODEL.NUM_CLASSES,
+ pool_size=[None, None]
+ if cfg.MULTIGRID.SHORT_CYCLE
+ else [
+ [
+ cfg.DATA.NUM_FRAMES
+ // cfg.SLOWFAST.ALPHA
+ // pool_size[0][0],
+ cfg.DATA.CROP_SIZE // 32 // pool_size[0][1],
+ cfg.DATA.CROP_SIZE // 32 // pool_size[0][2],
+ ],
+ [
+ cfg.DATA.NUM_FRAMES // pool_size[1][0],
+ cfg.DATA.CROP_SIZE // 32 // pool_size[1][1],
+ cfg.DATA.CROP_SIZE // 32 // pool_size[1][2],
+ ],
+ ], # None for AdaptiveAvgPool3d((1, 1, 1))
+ dropout_rate=cfg.MODEL.DROPOUT_RATE,
+ act_func=cfg.MODEL.HEAD_ACT,
+ )
+
+ def forward(self, x, bboxes=None):
+ x = self.s1(x)
+ x = self.s1_fuse(x)
+ x = self.s2(x)
+ x = self.s2_fuse(x)
+ for pathway in range(self.num_pathways):
+ pool = getattr(self, "pathway{}_pool".format(pathway))
+ x[pathway] = pool(x[pathway])
+ x = self.s3(x)
+ x = self.s3_fuse(x)
+ x = self.s4(x)
+ x = self.s4_fuse(x)
+ x = self.s5(x)
+ if self.enable_detection:
+ x = self.head(x, bboxes)
+ else:
+ x = self.head(x)
+ return x
+
+#############################
+### ftcn using this Model ###
+#############################
+@MODEL_REGISTRY.register()
+class ResNet(nn.Module):
+ """
+ ResNet model builder. It builds a ResNet like network backbone without
+ lateral connection (C2D, I3D, Slow).
+
+ Christoph Feichtenhofer, Haoqi Fan, Jitendra Malik, and Kaiming He.
+ "SlowFast networks for video recognition."
+ https://arxiv.org/pdf/1812.03982.pdf
+
+ Xiaolong Wang, Ross Girshick, Abhinav Gupta, and Kaiming He.
+ "Non-local neural networks."
+ https://arxiv.org/pdf/1711.07971.pdf
+ """
+
+ def __init__(self, cfg):
+ """
+ The `__init__` method of any subclass should also contain these
+ arguments.
+
+ Args:
+ cfg (CfgNode): model building configs, details are in the
+ comments of the config file.
+ """
+ super(ResNet, self).__init__()
+ self.norm_module = get_norm(cfg)
+ self.enable_detection = cfg.DETECTION.ENABLE
+ self.num_pathways = 1
+ self._construct_network(cfg)
+ init_helper.init_weights(
+ self, cfg.MODEL.FC_INIT_STD, cfg.RESNET.ZERO_INIT_FINAL_BN
+ )
+
+ def _construct_network(self, cfg):
+ """
+ Builds a single pathway ResNet model.
+
+ Args:
+ cfg (CfgNode): model building configs, details are in the
+ comments of the config file.
+ """
+ assert cfg.MODEL.ARCH in _POOL1.keys()
+ pool_size = _POOL1[cfg.MODEL.ARCH]
+ assert len({len(pool_size), self.num_pathways}) == 1
+ assert cfg.RESNET.DEPTH in _MODEL_STAGE_DEPTH.keys()
+
+ (d2, d3, d4, d5) = _MODEL_STAGE_DEPTH[cfg.RESNET.DEPTH]
+
+ num_groups = cfg.RESNET.NUM_GROUPS
+ width_per_group = cfg.RESNET.WIDTH_PER_GROUP
+ dim_inner = num_groups * width_per_group
+
+ temp_kernel = _TEMPORAL_KERNEL_BASIS[cfg.MODEL.ARCH]
+
+ # fix: inplace_relu=True
+ self.s1 = stem_helper.VideoModelStem(
+ dim_in=cfg.DATA.INPUT_CHANNEL_NUM,
+ dim_out=[width_per_group],
+ kernel=[temp_kernel[0][0] + [7, 7]],
+ stride=[[1, 2, 2]],
+ padding=[[temp_kernel[0][0][0] // 2, 3, 3]],
+ norm_module=self.norm_module,
+ )
+
+ self.s2 = resnet_helper.ResStage(
+ dim_in=[width_per_group],
+ dim_out=[width_per_group * 4],
+ dim_inner=[dim_inner],
+ temp_kernel_sizes=temp_kernel[1],
+ stride=cfg.RESNET.SPATIAL_STRIDES[0],
+ num_blocks=[d2],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[0],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[0],
+ nonlocal_group=cfg.NONLOCAL.GROUP[0],
+ nonlocal_pool=cfg.NONLOCAL.POOL[0],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ # inplace_relu=cfg.RESNET.INPLACE_RELU,
+ inplace_relu=False, # default :: True
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[0],
+ norm_module=self.norm_module,
+ )
+
+ for pathway in range(self.num_pathways):
+ pool = nn.MaxPool3d(
+ kernel_size=pool_size[pathway],
+ stride=pool_size[pathway],
+ padding=[0, 0, 0],
+ )
+ self.add_module("pathway{}_pool".format(pathway), pool)
+
+ self.s3 = resnet_helper.ResStage(
+ dim_in=[width_per_group * 4],
+ dim_out=[width_per_group * 8],
+ dim_inner=[dim_inner * 2],
+ temp_kernel_sizes=temp_kernel[2],
+ stride=cfg.RESNET.SPATIAL_STRIDES[1],
+ num_blocks=[d3],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[1],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[1],
+ nonlocal_group=cfg.NONLOCAL.GROUP[1],
+ nonlocal_pool=cfg.NONLOCAL.POOL[1],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ # inplace_relu=cfg.RESNET.INPLACE_RELU,
+ inplace_relu=False, # default :: True
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[1],
+ norm_module=self.norm_module,
+ )
+
+ self.s4 = resnet_helper.ResStage(
+ dim_in=[width_per_group * 8],
+ dim_out=[width_per_group * 16],
+ dim_inner=[dim_inner * 4],
+ temp_kernel_sizes=temp_kernel[3],
+ stride=cfg.RESNET.SPATIAL_STRIDES[2],
+ num_blocks=[d4],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[2],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[2],
+ nonlocal_group=cfg.NONLOCAL.GROUP[2],
+ nonlocal_pool=cfg.NONLOCAL.POOL[2],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ # inplace_relu=cfg.RESNET.INPLACE_RELU,
+ inplace_relu=False, # default :: True ########### Fixed by TH ############ default :: True
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[2],
+ norm_module=self.norm_module,
+ )
+
+ self.s5 = resnet_helper.ResStage(
+ dim_in=[width_per_group * 16],
+ dim_out=[width_per_group * 32],
+ dim_inner=[dim_inner * 8],
+ temp_kernel_sizes=temp_kernel[4],
+ stride=cfg.RESNET.SPATIAL_STRIDES[3],
+ num_blocks=[d5],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[3],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[3],
+ nonlocal_group=cfg.NONLOCAL.GROUP[3],
+ nonlocal_pool=cfg.NONLOCAL.POOL[3],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ # inplace_relu=cfg.RESNET.INPLACE_RELU,
+ inplace_relu=False, # default :: True
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[3],
+ norm_module=self.norm_module,
+ )
+ ############################# 0918 Head X ###############################################
+ # if self.enable_detection:
+ # raise NotImplementedError
+ # else:
+ # self.head = head_helper.ResNetBasicHead(
+ # dim_in=[width_per_group * 32],
+ # num_classes=cfg.MODEL.NUM_CLASSES,
+ # pool_size=[None, None]
+ # if cfg.MULTIGRID.SHORT_CYCLE
+ # else [
+ # [
+ # cfg.DATA.NUM_FRAMES // pool_size[0][0],
+ # cfg.DATA.CROP_SIZE // 32 // pool_size[0][1],
+ # cfg.DATA.CROP_SIZE // 32 // pool_size[0][2],
+ # ]
+ # ], # None for AdaptiveAvgPool3d((1, 1, 1))
+ # dropout_rate=cfg.MODEL.DROPOUT_RATE,
+ # act_func=cfg.MODEL.HEAD_ACT,
+ # )
+ # x:[images, ]([16, 3, 32, 224, 224])
+ # ft_feats [out1, out2, out3, out4, out5]
+ def forward(self, x,ft_feats, bboxes=None):
+ ### FTCN ###
+ ################# Fourier Transform #################
+ # x shape s1 torch.Size([16, 64, 32, 56, 56])
+ # x shape s2 torch.Size([16, 256, 32, 56, 56])
+ # x shape s3 torch.Size([16, 512, 16, 28, 28])
+ # x shape s4 torch.Size([16, 1024, 16, 14, 14])
+ # x shape s5 torch.Size([16, 2048, 16, 7, 7])
+ #######################################################
+ # FTfeature : (torch.Size([16, 64, 56, 56]),
+ # torch.Size([16, 256, 56, 56]),
+ # torch.Size([16, 512, 28, 28]),
+ # torch.Size([16, 1024, 14, 14]),
+ # torch.Size([16, 2048]))
+ ############## #########################################
+
+ x = self.s1(x)
+ x[0] = x[0].clone() + ft_feats[0].unsqueeze(2).clone()
+ x = self.s2(x)
+ x[0] = x[0].clone() + ft_feats[1].unsqueeze(2).clone()
+ for pathway in range(self.num_pathways):
+ pool = getattr(self, "pathway{}_pool".format(pathway))
+ x[pathway] = pool(x[pathway])
+ x = self.s3(x)
+ x[0] = x[0].clone() + ft_feats[2].unsqueeze(2).clone()
+ x = self.s4(x)
+ x[0] = x[0].clone() + ft_feats[3].unsqueeze(2).clone()
+ x = self.s5(x)
+ ############################# 0918 Head X ###############################################
+ ### FTCN ###
+ # x shape input transformer torch.Size([16, 1024, 16, 14, 14])
+ # x shape input transformer torch.Size([16, 2048, 16, 7, 7])
+ # if self.enable_detection:
+ # x = self.head(x, bboxes)
+ # else:
+ # ### FTCN ###
+ # x = self.head(x,ft_feats[4].clone())
+
+ ###########
+ # x shape output transformer torch.Size([1])
+ return x[0] , ft_feats[4]
+################################################################
+@MODEL_REGISTRY.register()
+class ResNetVar(nn.Module):
+ """
+ ResNet model builder. It builds a ResNet like network backbone without
+ lateral connection (C2D, I3D, Slow).
+
+ Christoph Feichtenhofer, Haoqi Fan, Jitendra Malik, and Kaiming He.
+ "SlowFast networks for video recognition."
+ https://arxiv.org/pdf/1812.03982.pdf
+
+ Xiaolong Wang, Ross Girshick, Abhinav Gupta, and Kaiming He.
+ "Non-local neural networks."
+ https://arxiv.org/pdf/1711.07971.pdf
+ """
+
+ def __init__(self, cfg):
+ """
+ The `__init__` method of any subclass should also contain these
+ arguments.
+
+ Args:
+ cfg (CfgNode): model building configs, details are in the
+ comments of the config file.
+ """
+ super(ResNetVar, self).__init__()
+ self.norm_module = get_norm(cfg)
+ self.enable_detection = cfg.DETECTION.ENABLE
+ self.num_pathways = 1
+ self._construct_network(cfg)
+ init_helper.init_weights(
+ self, cfg.MODEL.FC_INIT_STD, cfg.RESNET.ZERO_INIT_FINAL_BN
+ )
+
+ def _construct_network(self, cfg):
+ """
+ Builds a single pathway ResNet model.
+
+ Args:
+ cfg (CfgNode): model building configs, details are in the
+ comments of the config file.
+ """
+ assert cfg.MODEL.ARCH in _POOL1.keys()
+ pool_size = _POOL1[cfg.MODEL.ARCH]
+ assert len({len(pool_size), self.num_pathways}) == 1
+ assert cfg.RESNET.DEPTH in _MODEL_STAGE_DEPTH.keys()
+
+ (d2, d3, d4, d5) = _MODEL_STAGE_DEPTH[cfg.RESNET.DEPTH]
+
+ num_groups = cfg.RESNET.NUM_GROUPS
+ width_per_group = cfg.RESNET.WIDTH_PER_GROUP
+ dim_inner = num_groups * width_per_group
+
+ temp_kernel = _TEMPORAL_KERNEL_BASIS[cfg.MODEL.ARCH]
+
+ self.s1 = stem_helper.VideoModelStem(
+ dim_in=cfg.DATA.INPUT_CHANNEL_NUM,
+ dim_out=[width_per_group],
+ kernel=[temp_kernel[0][0] + [7, 7]],
+ stride=[[1, 2, 2]],
+ padding=[[temp_kernel[0][0][0] // 2, 3, 3]],
+ norm_module=self.norm_module,
+ )
+
+ self.s2 = resnet_helper.ResStage(
+ dim_in=[width_per_group],
+ dim_out=[width_per_group * 4],
+ dim_inner=[dim_inner],
+ temp_kernel_sizes=temp_kernel[1],
+ stride=cfg.RESNET.SPATIAL_STRIDES[0],
+ num_blocks=[d2],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[0],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[0],
+ nonlocal_group=cfg.NONLOCAL.GROUP[0],
+ nonlocal_pool=cfg.NONLOCAL.POOL[0],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[0],
+ norm_module=self.norm_module,
+ )
+
+ for pathway in range(self.num_pathways):
+ pool = nn.MaxPool3d(
+ kernel_size=pool_size[pathway],
+ stride=pool_size[pathway],
+ padding=[0, 0, 0],
+ )
+ self.add_module("pathway{}_pool".format(pathway), pool)
+
+ self.s3 = resnet_helper.ResStage(
+ dim_in=[width_per_group * 4],
+ dim_out=[width_per_group * 8],
+ dim_inner=[dim_inner * 2],
+ temp_kernel_sizes=temp_kernel[2],
+ stride=cfg.RESNET.SPATIAL_STRIDES[1],
+ num_blocks=[d3],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[1],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[1],
+ nonlocal_group=cfg.NONLOCAL.GROUP[1],
+ nonlocal_pool=cfg.NONLOCAL.POOL[1],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[1],
+ norm_module=self.norm_module,
+ )
+
+ self.s4 = resnet_helper.ResStage(
+ dim_in=[width_per_group * 8],
+ dim_out=[width_per_group * 16],
+ dim_inner=[dim_inner * 4],
+ temp_kernel_sizes=temp_kernel[3],
+ stride=cfg.RESNET.SPATIAL_STRIDES[2],
+ num_blocks=[d4],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[2],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[2],
+ nonlocal_group=cfg.NONLOCAL.GROUP[2],
+ nonlocal_pool=cfg.NONLOCAL.POOL[2],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[2],
+ norm_module=self.norm_module,
+ )
+
+ self.s5 = resnet_helper.ResStage(
+ dim_in=[width_per_group * 16],
+ dim_out=[width_per_group * 32],
+ dim_inner=[dim_inner * 8],
+ temp_kernel_sizes=temp_kernel[4],
+ stride=cfg.RESNET.SPATIAL_STRIDES[3],
+ num_blocks=[d5],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[3],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[3],
+ nonlocal_group=cfg.NONLOCAL.GROUP[3],
+ nonlocal_pool=cfg.NONLOCAL.POOL[3],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[3],
+ norm_module=self.norm_module,
+ )
+
+ if self.enable_detection:
+ raise NotImplementedError
+ else:
+ self.head = head_helper.ResNetBasicHead(
+ dim_in=[width_per_group * 32],
+ num_classes=cfg.MODEL.NUM_CLASSES,
+ pool_size=[None],
+ dropout_rate=cfg.MODEL.DROPOUT_RATE,
+ act_func=cfg.MODEL.HEAD_ACT,
+ )
+
+ def forward(self, x, bboxes=None):
+ x = self.s1(x)
+ x = self.s2(x)
+ for pathway in range(self.num_pathways):
+ pool = getattr(self, "pathway{}_pool".format(pathway))
+ x[pathway] = pool(x[pathway])
+ x = self.s3(x)
+ x = self.s4(x)
+ x = self.s5(x)
+ if self.enable_detection:
+ x = self.head(x, bboxes)
+ else:
+ x = self.head(x)
+ return x
+
+@MODEL_REGISTRY.register()
+class ResNetBase(nn.Module):
+ """
+ ResNet model builder. It builds a ResNet like network backbone without
+ lateral connection (C2D, I3D, Slow).
+
+ Christoph Feichtenhofer, Haoqi Fan, Jitendra Malik, and Kaiming He.
+ "SlowFast networks for video recognition."
+ https://arxiv.org/pdf/1812.03982.pdf
+
+ Xiaolong Wang, Ross Girshick, Abhinav Gupta, and Kaiming He.
+ "Non-local neural networks."
+ https://arxiv.org/pdf/1711.07971.pdf
+ """
+
+ def __init__(self, cfg):
+ """
+ The `__init__` method of any subclass should also contain these
+ arguments.
+
+ Args:
+ cfg (CfgNode): model building configs, details are in the
+ comments of the config file.
+ """
+ super(ResNetBase, self).__init__()
+ self.norm_module = get_norm(cfg)
+ self.enable_detection = cfg.DETECTION.ENABLE
+ self.num_pathways = 1
+ self._construct_network(cfg)
+ init_helper.init_weights(
+ self, cfg.MODEL.FC_INIT_STD, cfg.RESNET.ZERO_INIT_FINAL_BN
+ )
+
+ def _construct_network(self, cfg):
+ """
+ Builds a single pathway ResNet model.
+
+ Args:
+ cfg (CfgNode): model building configs, details are in the
+ comments of the config file.
+ """
+ assert cfg.MODEL.ARCH in _POOL1.keys()
+ pool_size = _POOL1[cfg.MODEL.ARCH]
+ assert len({len(pool_size), self.num_pathways}) == 1
+ assert cfg.RESNET.DEPTH in _MODEL_STAGE_DEPTH.keys()
+
+ (d2, d3, d4, d5) = _MODEL_STAGE_DEPTH[cfg.RESNET.DEPTH]
+
+ num_groups = cfg.RESNET.NUM_GROUPS
+ width_per_group = cfg.RESNET.WIDTH_PER_GROUP
+ dim_inner = num_groups * width_per_group
+
+ temp_kernel = _TEMPORAL_KERNEL_BASIS[cfg.MODEL.ARCH]
+
+ self.s1 = stem_helper.VideoModelStem(
+ dim_in=cfg.DATA.INPUT_CHANNEL_NUM,
+ dim_out=[width_per_group],
+ kernel=[temp_kernel[0][0] + [7, 7]],
+ stride=[[1, 2, 2]],
+ padding=[[temp_kernel[0][0][0] // 2, 3, 3]],
+ norm_module=self.norm_module,
+ )
+
+ self.s2 = resnet_helper.ResStage(
+ dim_in=[width_per_group],
+ dim_out=[width_per_group * 4],
+ dim_inner=[dim_inner],
+ temp_kernel_sizes=temp_kernel[1],
+ stride=cfg.RESNET.SPATIAL_STRIDES[0],
+ num_blocks=[d2],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[0],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[0],
+ nonlocal_group=cfg.NONLOCAL.GROUP[0],
+ nonlocal_pool=cfg.NONLOCAL.POOL[0],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[0],
+ norm_module=self.norm_module,
+ )
+
+ for pathway in range(self.num_pathways):
+ pool = nn.MaxPool3d(
+ kernel_size=pool_size[pathway],
+ stride=pool_size[pathway],
+ padding=[0, 0, 0],
+ )
+ self.add_module("pathway{}_pool".format(pathway), pool)
+
+ self.s3 = resnet_helper.ResStage(
+ dim_in=[width_per_group * 4],
+ dim_out=[width_per_group * 8],
+ dim_inner=[dim_inner * 2],
+ temp_kernel_sizes=temp_kernel[2],
+ stride=cfg.RESNET.SPATIAL_STRIDES[1],
+ num_blocks=[d3],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[1],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[1],
+ nonlocal_group=cfg.NONLOCAL.GROUP[1],
+ nonlocal_pool=cfg.NONLOCAL.POOL[1],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[1],
+ norm_module=self.norm_module,
+ )
+
+ self.s4 = resnet_helper.ResStage(
+ dim_in=[width_per_group * 8],
+ dim_out=[width_per_group * 16],
+ dim_inner=[dim_inner * 4],
+ temp_kernel_sizes=temp_kernel[3],
+ stride=cfg.RESNET.SPATIAL_STRIDES[2],
+ num_blocks=[d4],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[2],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[2],
+ nonlocal_group=cfg.NONLOCAL.GROUP[2],
+ nonlocal_pool=cfg.NONLOCAL.POOL[2],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[2],
+ norm_module=self.norm_module,
+ )
+
+ self.s5 = resnet_helper.ResStage(
+ dim_in=[width_per_group * 16],
+ dim_out=[width_per_group * 32],
+ dim_inner=[dim_inner * 8],
+ temp_kernel_sizes=temp_kernel[4],
+ stride=cfg.RESNET.SPATIAL_STRIDES[3],
+ num_blocks=[d5],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[3],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[3],
+ nonlocal_group=cfg.NONLOCAL.GROUP[3],
+ nonlocal_pool=cfg.NONLOCAL.POOL[3],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[3],
+ norm_module=self.norm_module,
+ )
+
+ if self.enable_detection:
+ raise NotImplementedError
+ else:
+ self.head = head_helper.ResNetBasicHead(
+ dim_in=[width_per_group * 32],
+ num_classes=cfg.MODEL.NUM_CLASSES,
+ pool_size=[None, None]
+ if cfg.MULTIGRID.SHORT_CYCLE
+ else [
+ None
+ ], # None for AdaptiveAvgPool3d((1, 1, 1))
+ dropout_rate=cfg.MODEL.DROPOUT_RATE,
+ act_func=cfg.MODEL.HEAD_ACT,
+ )
+
+ def forward(self, x, bboxes=None):
+ x = self.s1(x)
+ x = self.s2(x)
+ for pathway in range(self.num_pathways):
+ pool = getattr(self, "pathway{}_pool".format(pathway))
+ x[pathway] = pool(x[pathway])
+ x = self.s3(x)
+ x = self.s4(x)
+ x = self.s5(x)
+ if self.enable_detection:
+ x = self.head(x, bboxes)
+ else:
+ x = self.head(x)
+ return x
+
+
+@MODEL_REGISTRY.register()
+class ResNetFreeze(nn.Module):
+ """
+ ResNet model builder. It builds a ResNet like network backbone without
+ lateral connection (C2D, I3D, Slow).
+
+ Christoph Feichtenhofer, Haoqi Fan, Jitendra Malik, and Kaiming He.
+ "SlowFast networks for video recognition."
+ https://arxiv.org/pdf/1812.03982.pdf
+
+ Xiaolong Wang, Ross Girshick, Abhinav Gupta, and Kaiming He.
+ "Non-local neural networks."
+ https://arxiv.org/pdf/1711.07971.pdf
+ """
+
+ def __init__(self, cfg):
+ """
+ The `__init__` method of any subclass should also contain these
+ arguments.
+
+ Args:
+ cfg (CfgNode): model building configs, details are in the
+ comments of the config file.
+ """
+ super(ResNetFreeze, self).__init__()
+ self.norm_module = get_norm(cfg)
+ self.enable_detection = cfg.DETECTION.ENABLE
+ self.num_pathways = 1
+ self._construct_network(cfg)
+ init_helper.init_weights(
+ self, cfg.MODEL.FC_INIT_STD, cfg.RESNET.ZERO_INIT_FINAL_BN
+ )
+
+ def _construct_network(self, cfg):
+ """
+ Builds a single pathway ResNet model.
+
+ Args:
+ cfg (CfgNode): model building configs, details are in the
+ comments of the config file.
+ """
+ assert cfg.MODEL.ARCH in _POOL1.keys()
+ pool_size = _POOL1[cfg.MODEL.ARCH]
+ assert len({len(pool_size), self.num_pathways}) == 1
+ assert cfg.RESNET.DEPTH in _MODEL_STAGE_DEPTH.keys()
+
+ (d2, d3, d4, d5) = _MODEL_STAGE_DEPTH[cfg.RESNET.DEPTH]
+
+ num_groups = cfg.RESNET.NUM_GROUPS
+ width_per_group = cfg.RESNET.WIDTH_PER_GROUP
+ dim_inner = num_groups * width_per_group
+
+ temp_kernel = _TEMPORAL_KERNEL_BASIS[cfg.MODEL.ARCH]
+
+ self.s1 = stem_helper.VideoModelStem(
+ dim_in=cfg.DATA.INPUT_CHANNEL_NUM,
+ dim_out=[width_per_group],
+ kernel=[temp_kernel[0][0] + [7, 7]],
+ stride=[[1, 2, 2]],
+ padding=[[temp_kernel[0][0][0] // 2, 3, 3]],
+ norm_module=self.norm_module,
+ )
+
+ self.s2 = resnet_helper.ResStage(
+ dim_in=[width_per_group],
+ dim_out=[width_per_group * 4],
+ dim_inner=[dim_inner],
+ temp_kernel_sizes=temp_kernel[1],
+ stride=cfg.RESNET.SPATIAL_STRIDES[0],
+ num_blocks=[d2],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[0],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[0],
+ nonlocal_group=cfg.NONLOCAL.GROUP[0],
+ nonlocal_pool=cfg.NONLOCAL.POOL[0],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[0],
+ norm_module=self.norm_module,
+ )
+
+ for pathway in range(self.num_pathways):
+ pool = nn.MaxPool3d(
+ kernel_size=pool_size[pathway],
+ stride=pool_size[pathway],
+ padding=[0, 0, 0],
+ )
+ self.add_module("pathway{}_pool".format(pathway), pool)
+
+ self.s3 = resnet_helper.ResStage(
+ dim_in=[width_per_group * 4],
+ dim_out=[width_per_group * 8],
+ dim_inner=[dim_inner * 2],
+ temp_kernel_sizes=temp_kernel[2],
+ stride=cfg.RESNET.SPATIAL_STRIDES[1],
+ num_blocks=[d3],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[1],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[1],
+ nonlocal_group=cfg.NONLOCAL.GROUP[1],
+ nonlocal_pool=cfg.NONLOCAL.POOL[1],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[1],
+ norm_module=self.norm_module,
+ )
+
+ self.s4 = resnet_helper.ResStage(
+ dim_in=[width_per_group * 8],
+ dim_out=[width_per_group * 16],
+ dim_inner=[dim_inner * 4],
+ temp_kernel_sizes=temp_kernel[3],
+ stride=cfg.RESNET.SPATIAL_STRIDES[2],
+ num_blocks=[d4],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[2],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[2],
+ nonlocal_group=cfg.NONLOCAL.GROUP[2],
+ nonlocal_pool=cfg.NONLOCAL.POOL[2],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[2],
+ norm_module=self.norm_module,
+ )
+
+ self.s5 = resnet_helper.ResStage(
+ dim_in=[width_per_group * 16],
+ dim_out=[width_per_group * 32],
+ dim_inner=[dim_inner * 8],
+ temp_kernel_sizes=temp_kernel[4],
+ stride=cfg.RESNET.SPATIAL_STRIDES[3],
+ num_blocks=[d5],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[3],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[3],
+ nonlocal_group=cfg.NONLOCAL.GROUP[3],
+ nonlocal_pool=cfg.NONLOCAL.POOL[3],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[3],
+ norm_module=self.norm_module,
+ )
+
+ if self.enable_detection:
+ raise NotImplementedError
+ else:
+ self.head = head_helper.ResNetBasicHead(
+ dim_in=[width_per_group * 32],
+ num_classes=cfg.MODEL.NUM_CLASSES,
+ pool_size=[None,None]
+ if cfg.MULTIGRID.SHORT_CYCLE
+ else [
+ None
+ ], # None for AdaptiveAvgPool3d((1, 1, 1))
+ dropout_rate=cfg.MODEL.DROPOUT_RATE,
+ act_func=cfg.MODEL.HEAD_ACT,
+ )
+
+ def forward(self, x, freeze_backbone=False):
+ assert isinstance(freeze_backbone,bool)
+ x = self.s1(x)
+ x = self.s2(x)
+ # for pathway in range(self.num_pathways):
+ # pool = getattr(self, "pathway{}_pool".format(pathway))
+ # x[pathway] = pool(x[pathway])
+ x = self.s3(x)
+ x = self.s4(x)
+ x = self.s5(x)
+ if freeze_backbone:
+ x=[item.detach() for item in x]
+
+ x = self.head(x)
+ return x
+
+
+
+import torch.nn.functional as F
+from .unet_helper import DecoderBlock,LightDecoderBlock,ResDecoderBlock
+
+
+@MODEL_REGISTRY.register()
+class ResUNet(nn.Module):
+ """
+ ResNet model builder. It builds a ResNet like network backbone without
+ lateral connection (C2D, I3D, Slow).
+
+ Christoph Feichtenhofer, Haoqi Fan, Jitendra Malik, and Kaiming He.
+ "SlowFast networks for video recognition."
+ https://arxiv.org/pdf/1812.03982.pdf
+
+ Xiaolong Wang, Ross Girshick, Abhinav Gupta, and Kaiming He.
+ "Non-local neural networks."
+ https://arxiv.org/pdf/1711.07971.pdf
+ """
+
+ def __init__(self, cfg):
+ """
+ The `__init__` method of any subclass should also contain these
+ arguments.
+
+ Args:
+ cfg (CfgNode): model building configs, details are in the
+ comments of the config file.
+ """
+ super(ResUNet, self).__init__()
+ self.norm_module = get_norm(cfg)
+ self.enable_detection = cfg.DETECTION.ENABLE
+ self.enable_jitter = cfg.JITTER.ENABLE
+ self.num_pathways = 1
+ assert cfg.DATA.TRAIN_CROP_SIZE == cfg.DATA.TEST_CROP_SIZE
+ self.image_size = cfg.DATA.TRAIN_CROP_SIZE
+ self.clip_size = cfg.DATA.NUM_FRAMES
+ self._construct_network(cfg)
+ init_helper.init_weights(
+ self, cfg.MODEL.FC_INIT_STD, cfg.RESNET.ZERO_INIT_FINAL_BN
+ )
+
+ def _construct_network(self, cfg):
+ """
+ Builds a single pathway ResNet model.
+
+ Args:
+ cfg (CfgNode): model building configs, details are in the
+ comments of the config file.
+ """
+ assert cfg.MODEL.ARCH in _POOL1.keys()
+ pool_size = _POOL1[cfg.MODEL.ARCH]
+ self.cfg = cfg
+ assert len({len(pool_size), self.num_pathways}) == 1
+ assert cfg.RESNET.DEPTH in _MODEL_STAGE_DEPTH.keys()
+
+ (d2, d3, d4, d5) = _MODEL_STAGE_DEPTH[cfg.RESNET.DEPTH]
+
+ num_groups = cfg.RESNET.NUM_GROUPS
+ width_per_group = cfg.RESNET.WIDTH_PER_GROUP
+ dim_inner = num_groups * width_per_group
+
+ temp_kernel = _TEMPORAL_KERNEL_BASIS[cfg.MODEL.ARCH]
+
+ self.s1 = stem_helper.VideoModelStem(
+ dim_in=cfg.DATA.INPUT_CHANNEL_NUM,
+ dim_out=[width_per_group],
+ kernel=[temp_kernel[0][0] + [7, 7]],
+ stride=[[1, 2, 2]],
+ padding=[[temp_kernel[0][0][0] // 2, 3, 3]],
+ norm_module=self.norm_module,
+ )
+
+ self.s2 = resnet_helper.ResStage(
+ dim_in=[width_per_group],
+ dim_out=[width_per_group * 4],
+ dim_inner=[dim_inner],
+ temp_kernel_sizes=temp_kernel[1],
+ stride=cfg.RESNET.SPATIAL_STRIDES[0],
+ num_blocks=[d2],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[0],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[0],
+ nonlocal_group=cfg.NONLOCAL.GROUP[0],
+ nonlocal_pool=cfg.NONLOCAL.POOL[0],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[0],
+ norm_module=self.norm_module,
+ )
+
+ for pathway in range(self.num_pathways):
+ pool = nn.MaxPool3d(
+ kernel_size=pool_size[pathway],
+ stride=pool_size[pathway],
+ padding=[0, 0, 0],
+ )
+ self.add_module("pathway{}_pool".format(pathway), pool)
+
+ self.s3 = resnet_helper.ResStage(
+ dim_in=[width_per_group * 4],
+ dim_out=[width_per_group * 8],
+ dim_inner=[dim_inner * 2],
+ temp_kernel_sizes=temp_kernel[2],
+ stride=cfg.RESNET.SPATIAL_STRIDES[1],
+ num_blocks=[d3],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[1],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[1],
+ nonlocal_group=cfg.NONLOCAL.GROUP[1],
+ nonlocal_pool=cfg.NONLOCAL.POOL[1],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[1],
+ norm_module=self.norm_module,
+ )
+
+ self.s4 = resnet_helper.ResStage(
+ dim_in=[width_per_group * 8],
+ dim_out=[width_per_group * 16],
+ dim_inner=[dim_inner * 4],
+ temp_kernel_sizes=temp_kernel[3],
+ stride=cfg.RESNET.SPATIAL_STRIDES[2],
+ num_blocks=[d4],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[2],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[2],
+ nonlocal_group=cfg.NONLOCAL.GROUP[2],
+ nonlocal_pool=cfg.NONLOCAL.POOL[2],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[2],
+ norm_module=self.norm_module,
+ )
+
+ # self.s5 = resnet_helper.ResStage(
+ # dim_in=[width_per_group * 16],
+ # dim_out=[width_per_group * 32],
+ # dim_inner=[dim_inner * 8],
+ # temp_kernel_sizes=temp_kernel[4],
+ # stride=cfg.RESNET.SPATIAL_STRIDES[3],
+ # num_blocks=[d5],
+ # num_groups=[num_groups],
+ # num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[3],
+ # nonlocal_inds=cfg.NONLOCAL.LOCATION[3],
+ # nonlocal_group=cfg.NONLOCAL.GROUP[3],
+ # nonlocal_pool=cfg.NONLOCAL.POOL[3],
+ # instantiation=cfg.NONLOCAL.INSTANTIATION,
+ # trans_func_name=cfg.RESNET.TRANS_FUNC,
+ # stride_1x1=cfg.RESNET.STRIDE_1X1,
+ # inplace_relu=cfg.RESNET.INPLACE_RELU,
+ # dilation=cfg.RESNET.SPATIAL_DILATIONS[3],
+ # norm_module=self.norm_module,
+ # )
+ self.labels=["rotate","light"]
+ self.dual_define("t4",self.labels,DecoderBlock(width_per_group * 16,width_per_group * 8,width_per_group * 8))
+ self.dual_define("t3",self.labels,DecoderBlock(width_per_group * 8,width_per_group * 4, 256))
+ self.dual_define("conv1x1",self.labels,nn.Sequential(
+ nn.Conv3d(width_per_group*4+width_per_group, 1, kernel_size=(1, 1, 1), stride=1, padding=0), nn.Sigmoid()
+ ))
+
+ self.linear = nn.Sequential(nn.Linear(1, 1), nn.Sigmoid())
+
+ def forward_plus(self, x, y, net):
+ return [net(x)[0] + y[0]]
+
+
+ def dual_define(self,name,labels,net):
+ for label in labels:
+ self.add_module(f"{name}_{label}",copy.deepcopy(net))
+
+
+
+ def upsample(self, x, dims=["space"]):
+ ori_size = x[0].shape[2:5]
+ t, h, w = ori_size
+ if "space" in dims:
+ h = 2 * h
+ w = 2 * w
+ if "time" in dims:
+ t = 2 * t
+ size = (t, h, w)
+ return [F.interpolate(x[0], size)]
+
+ def concat(self,x,y):
+ return [torch.cat([x[0],y[0]],1)]
+
+
+
+ # @torchsnooper.snoop()
+ def forward(self, x, bboxes=None):
+ x1 = self.s1(x) # 1,64,8,56,56
+ x2 = self.s2(x1) # 1,256,8,56,56
+ x3 = self.s3(x2) # 1,512,8,28, 28
+ x = self.s4(x3) # 1,1024,8,14,14
+ x = self.upsample(x) # 1,1024, 8, 28, 28
+ x = self.concat(x3,x)# 1,1024+512, 8, 28, 28
+ x=[self.forward_branch(x,x1,x2,label) for label in self.labels]
+ x=torch.cat(x,1)
+ out = x.mean([3, 4]).view(-1, 1)*100
+ out = self.linear(out)
+ out = out.view(x.size(0), -1)
+ return x,out
+
+
+
+ def forward_branch(self,x,x1,x2,label):
+ t4=getattr(self,f"t4_{label}")
+ x = t4(x[0])# 1,512, 8, 28, 28
+ x = self.upsample([x]) # 1,512, 8, 56, 56
+ x = self.concat(x2,x)# 1,256+512, 8, 56, 56
+ t3= getattr(self,f"t3_{label}")
+ x = t3(x[0]) # 1,256, 8, 56, 56
+ x = self.concat(x1,[x]) # 1,320, 8, 56, 56
+ conv1x1=getattr(self,f"conv1x1_{label}")
+ x = conv1x1(x[0]) # 1,2,8,56,56
+ return x
+
+
+
+@MODEL_REGISTRY.register()
+class ResUNetLight(nn.Module):
+ """
+ ResNet model builder. It builds a ResNet like network backbone without
+ lateral connection (C2D, I3D, Slow).
+
+ Christoph Feichtenhofer, Haoqi Fan, Jitendra Malik, and Kaiming He.
+ "SlowFast networks for video recognition."
+ https://arxiv.org/pdf/1812.03982.pdf
+
+ Xiaolong Wang, Ross Girshick, Abhinav Gupta, and Kaiming He.
+ "Non-local neural networks."
+ https://arxiv.org/pdf/1711.07971.pdf
+ """
+
+ def __init__(self, cfg):
+ """
+ The `__init__` method of any subclass should also contain these
+ arguments.
+
+ Args:
+ cfg (CfgNode): model building configs, details are in the
+ comments of the config file.
+ """
+ super(ResUNetLight, self).__init__()
+ self.norm_module = get_norm(cfg)
+ self.enable_detection = cfg.DETECTION.ENABLE
+ self.enable_jitter = cfg.JITTER.ENABLE
+ self.num_pathways = 1
+ assert cfg.DATA.TRAIN_CROP_SIZE == cfg.DATA.TEST_CROP_SIZE
+ self.image_size = cfg.DATA.TRAIN_CROP_SIZE
+ self.clip_size = cfg.DATA.NUM_FRAMES
+ self._construct_network(cfg)
+ init_helper.init_weights(
+ self, cfg.MODEL.FC_INIT_STD, cfg.RESNET.ZERO_INIT_FINAL_BN
+ )
+
+ def _construct_network(self, cfg):
+ """
+ Builds a single pathway ResNet model.
+
+ Args:
+ cfg (CfgNode): model building configs, details are in the
+ comments of the config file.
+ """
+ assert cfg.MODEL.ARCH in _POOL1.keys()
+ pool_size = _POOL1[cfg.MODEL.ARCH]
+ self.cfg = cfg
+ assert len({len(pool_size), self.num_pathways}) == 1
+ assert cfg.RESNET.DEPTH in _MODEL_STAGE_DEPTH.keys()
+
+ (d2, d3, d4, d5) = _MODEL_STAGE_DEPTH[cfg.RESNET.DEPTH]
+
+ num_groups = cfg.RESNET.NUM_GROUPS
+ width_per_group = cfg.RESNET.WIDTH_PER_GROUP
+ dim_inner = num_groups * width_per_group
+
+ temp_kernel = _TEMPORAL_KERNEL_BASIS[cfg.MODEL.ARCH]
+
+ self.s1 = stem_helper.VideoModelStem(
+ dim_in=cfg.DATA.INPUT_CHANNEL_NUM,
+ dim_out=[width_per_group],
+ kernel=[temp_kernel[0][0] + [7, 7]],
+ stride=[[1, 2, 2]],
+ padding=[[temp_kernel[0][0][0] // 2, 3, 3]],
+ norm_module=self.norm_module,
+ )
+
+ self.s2 = resnet_helper.ResStage(
+ dim_in=[width_per_group],
+ dim_out=[width_per_group * 4],
+ dim_inner=[dim_inner],
+ temp_kernel_sizes=temp_kernel[1],
+ stride=cfg.RESNET.SPATIAL_STRIDES[0],
+ num_blocks=[d2],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[0],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[0],
+ nonlocal_group=cfg.NONLOCAL.GROUP[0],
+ nonlocal_pool=cfg.NONLOCAL.POOL[0],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[0],
+ norm_module=self.norm_module,
+ )
+
+ for pathway in range(self.num_pathways):
+ pool = nn.MaxPool3d(
+ kernel_size=pool_size[pathway],
+ stride=pool_size[pathway],
+ padding=[0, 0, 0],
+ )
+ self.add_module("pathway{}_pool".format(pathway), pool)
+
+ self.s3 = resnet_helper.ResStage(
+ dim_in=[width_per_group * 4],
+ dim_out=[width_per_group * 8],
+ dim_inner=[dim_inner * 2],
+ temp_kernel_sizes=temp_kernel[2],
+ stride=cfg.RESNET.SPATIAL_STRIDES[1],
+ num_blocks=[d3],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[1],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[1],
+ nonlocal_group=cfg.NONLOCAL.GROUP[1],
+ nonlocal_pool=cfg.NONLOCAL.POOL[1],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[1],
+ norm_module=self.norm_module,
+ )
+
+ self.s4 = resnet_helper.ResStage(
+ dim_in=[width_per_group * 8],
+ dim_out=[width_per_group * 16],
+ dim_inner=[dim_inner * 4],
+ temp_kernel_sizes=temp_kernel[3],
+ stride=cfg.RESNET.SPATIAL_STRIDES[2],
+ num_blocks=[d4],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[2],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[2],
+ nonlocal_group=cfg.NONLOCAL.GROUP[2],
+ nonlocal_pool=cfg.NONLOCAL.POOL[2],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[2],
+ norm_module=self.norm_module,
+ )
+
+ # self.s5 = resnet_helper.ResStage(
+ # dim_in=[width_per_group * 16],
+ # dim_out=[width_per_group * 32],
+ # dim_inner=[dim_inner * 8],
+ # temp_kernel_sizes=temp_kernel[4],
+ # stride=cfg.RESNET.SPATIAL_STRIDES[3],
+ # num_blocks=[d5],
+ # num_groups=[num_groups],
+ # num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[3],
+ # nonlocal_inds=cfg.NONLOCAL.LOCATION[3],
+ # nonlocal_group=cfg.NONLOCAL.GROUP[3],
+ # nonlocal_pool=cfg.NONLOCAL.POOL[3],
+ # instantiation=cfg.NONLOCAL.INSTANTIATION,
+ # trans_func_name=cfg.RESNET.TRANS_FUNC,
+ # stride_1x1=cfg.RESNET.STRIDE_1X1,
+ # inplace_relu=cfg.RESNET.INPLACE_RELU,
+ # dilation=cfg.RESNET.SPATIAL_DILATIONS[3],
+ # norm_module=self.norm_module,
+ # )
+ self.labels=["rotate","light"]
+ self.dual_define("t4",self.labels,LightDecoderBlock(width_per_group * 16,width_per_group * 8,width_per_group * 4))
+ self.dual_define("t3",self.labels,LightDecoderBlock(width_per_group * 4,width_per_group * 4, 128))
+ self.dual_define("conv1x1",self.labels,nn.Sequential(
+ nn.Conv3d(128+width_per_group, 1, kernel_size=(1, 1, 1), stride=1, padding=0), nn.Sigmoid()
+ ))
+
+ self.linear = nn.Sequential(nn.Linear(1, 1), nn.Sigmoid())
+
+ def forward_plus(self, x, y, net):
+ return [net(x)[0] + y[0]]
+
+
+ def dual_define(self,name,labels,net):
+ for label in labels:
+ self.add_module(f"{name}_{label}",copy.deepcopy(net))
+
+
+
+ def upsample(self, x, dims=["space"]):
+ ori_size = x[0].shape[2:5]
+ t, h, w = ori_size
+ if "space" in dims:
+ h = 2 * h
+ w = 2 * w
+ if "time" in dims:
+ t = 2 * t
+ size = (t, h, w)
+ return [F.interpolate(x[0], size)]
+
+ def concat(self,x,y):
+ return [torch.cat([x[0],y[0]],1)]
+
+ def get_detach_var(self,x):
+ return [t.detach() for t in x]
+
+ # @torchsnooper.snoop()
+ def forward(self, x, freeze_backbone=False):
+ x1 = self.s1(x) # 1,64,8,56,56
+ x2 = self.s2(x1) # 1,256,8,56,56
+ x3 = self.s3(x2) # 1,512,8,28, 28
+ x = self.s4(x3) # 1,1024,8,14,14
+ assert isinstance(freeze_backbone,bool)
+ if freeze_backbone:
+ x=self.get_detach_var(x)
+ x1=self.get_detach_var(x1)
+ x2=self.get_detach_var(x2)
+ x3=self.get_detach_var(x3)
+
+ x = self.upsample(x) # 1,1024, 8, 28, 28
+ x = self.concat(x3,x)# 1,1024+512, 8, 28, 28
+ x=[self.forward_branch(x,x1,x2,label) for label in self.labels]
+ x=torch.cat(x,1)
+ out = x.mean([3, 4]).view(-1, 1)*100 # 1,2,8,56,56
+ out = self.linear(out)
+ out = out.view(x.size(0), -1)
+ return x,out
+
+
+
+ def forward_branch(self,x,x1,x2,label):
+ t4=getattr(self,f"t4_{label}")
+ x = t4(x[0])# 1,256, 8, 28, 28
+ x = self.upsample([x]) # 1,256, 8, 56, 56
+ x = self.concat(x2,x)# 1,256+256, 8, 56, 56
+ t3= getattr(self,f"t3_{label}")
+ x = t3(x[0]) # 1,128, 8, 56, 56
+ x = self.concat(x1,[x]) # 1,192, 8, 56, 56
+ conv1x1=getattr(self,f"conv1x1_{label}")
+ x = conv1x1(x[0]) # 1,2,8,56,56
+ return x
+
+
+
+@MODEL_REGISTRY.register()
+class ResUNetLightFix(nn.Module):
+ """
+ ResNet model builder. It builds a ResNet like network backbone without
+ lateral connection (C2D, I3D, Slow).
+
+ Christoph Feichtenhofer, Haoqi Fan, Jitendra Malik, and Kaiming He.
+ "SlowFast networks for video recognition."
+ https://arxiv.org/pdf/1812.03982.pdf
+
+ Xiaolong Wang, Ross Girshick, Abhinav Gupta, and Kaiming He.
+ "Non-local neural networks."
+ https://arxiv.org/pdf/1711.07971.pdf
+ """
+
+ def __init__(self, cfg):
+ """
+ The `__init__` method of any subclass should also contain these
+ arguments.
+
+ Args:
+ cfg (CfgNode): model building configs, details are in the
+ comments of the config file.
+ """
+ super(ResUNetLightFix, self).__init__()
+ self.norm_module = get_norm(cfg)
+ self.enable_detection = cfg.DETECTION.ENABLE
+ self.enable_jitter = cfg.JITTER.ENABLE
+ self.num_pathways = 1
+ assert cfg.DATA.TRAIN_CROP_SIZE == cfg.DATA.TEST_CROP_SIZE
+ self.image_size = cfg.DATA.TRAIN_CROP_SIZE
+ self.clip_size = cfg.DATA.NUM_FRAMES
+ self._construct_network(cfg)
+ init_helper.init_weights(
+ self, cfg.MODEL.FC_INIT_STD, cfg.RESNET.ZERO_INIT_FINAL_BN
+ )
+
+ def _construct_network(self, cfg):
+ """
+ Builds a single pathway ResNet model.
+
+ Args:
+ cfg (CfgNode): model building configs, details are in the
+ comments of the config file.
+ """
+ assert cfg.MODEL.ARCH in _POOL1.keys()
+ pool_size = _POOL1[cfg.MODEL.ARCH]
+ self.cfg = cfg
+ assert len({len(pool_size), self.num_pathways}) == 1
+ assert cfg.RESNET.DEPTH in _MODEL_STAGE_DEPTH.keys()
+
+ (d2, d3, d4, d5) = _MODEL_STAGE_DEPTH[cfg.RESNET.DEPTH]
+
+ num_groups = cfg.RESNET.NUM_GROUPS
+ width_per_group = cfg.RESNET.WIDTH_PER_GROUP
+ dim_inner = num_groups * width_per_group
+
+ temp_kernel = _TEMPORAL_KERNEL_BASIS[cfg.MODEL.ARCH]
+
+ self.s1 = stem_helper.VideoModelStem(
+ dim_in=cfg.DATA.INPUT_CHANNEL_NUM,
+ dim_out=[width_per_group],
+ kernel=[temp_kernel[0][0] + [7, 7]],
+ stride=[[1, 2, 2]],
+ padding=[[temp_kernel[0][0][0] // 2, 3, 3]],
+ norm_module=self.norm_module,
+ )
+
+ self.s2 = resnet_helper.ResStage(
+ dim_in=[width_per_group],
+ dim_out=[width_per_group * 4],
+ dim_inner=[dim_inner],
+ temp_kernel_sizes=temp_kernel[1],
+ stride=cfg.RESNET.SPATIAL_STRIDES[0],
+ num_blocks=[d2],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[0],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[0],
+ nonlocal_group=cfg.NONLOCAL.GROUP[0],
+ nonlocal_pool=cfg.NONLOCAL.POOL[0],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[0],
+ norm_module=self.norm_module,
+ )
+
+ for pathway in range(self.num_pathways):
+ pool = nn.MaxPool3d(
+ kernel_size=pool_size[pathway],
+ stride=pool_size[pathway],
+ padding=[0, 0, 0],
+ )
+ self.add_module("pathway{}_pool".format(pathway), pool)
+
+ self.s3 = resnet_helper.ResStage(
+ dim_in=[width_per_group * 4],
+ dim_out=[width_per_group * 8],
+ dim_inner=[dim_inner * 2],
+ temp_kernel_sizes=temp_kernel[2],
+ stride=cfg.RESNET.SPATIAL_STRIDES[1],
+ num_blocks=[d3],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[1],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[1],
+ nonlocal_group=cfg.NONLOCAL.GROUP[1],
+ nonlocal_pool=cfg.NONLOCAL.POOL[1],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[1],
+ norm_module=self.norm_module,
+ )
+
+ self.s4 = resnet_helper.ResStage(
+ dim_in=[width_per_group * 8],
+ dim_out=[width_per_group * 16],
+ dim_inner=[dim_inner * 4],
+ temp_kernel_sizes=temp_kernel[3],
+ stride=cfg.RESNET.SPATIAL_STRIDES[2],
+ num_blocks=[d4],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[2],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[2],
+ nonlocal_group=cfg.NONLOCAL.GROUP[2],
+ nonlocal_pool=cfg.NONLOCAL.POOL[2],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[2],
+ norm_module=self.norm_module,
+ )
+
+ # self.s5 = resnet_helper.ResStage(
+ # dim_in=[width_per_group * 16],
+ # dim_out=[width_per_group * 32],
+ # dim_inner=[dim_inner * 8],
+ # temp_kernel_sizes=temp_kernel[4],
+ # stride=cfg.RESNET.SPATIAL_STRIDES[3],
+ # num_blocks=[d5],
+ # num_groups=[num_groups],
+ # num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[3],
+ # nonlocal_inds=cfg.NONLOCAL.LOCATION[3],
+ # nonlocal_group=cfg.NONLOCAL.GROUP[3],
+ # nonlocal_pool=cfg.NONLOCAL.POOL[3],
+ # instantiation=cfg.NONLOCAL.INSTANTIATION,
+ # trans_func_name=cfg.RESNET.TRANS_FUNC,
+ # stride_1x1=cfg.RESNET.STRIDE_1X1,
+ # inplace_relu=cfg.RESNET.INPLACE_RELU,
+ # dilation=cfg.RESNET.SPATIAL_DILATIONS[3],
+ # norm_module=self.norm_module,
+ # )
+ self.labels=["rotate","light","skip"]
+ self.dual_define("t4",self.labels,LightDecoderBlock(width_per_group * 16,width_per_group * 8,width_per_group * 4))
+ self.dual_define("t3",self.labels,LightDecoderBlock(width_per_group * 4,width_per_group * 4, 128))
+ self.dual_define("conv1x1",self.labels,nn.Sequential(
+ nn.Conv3d(128+width_per_group, 64, kernel_size=(1, 1, 1), stride=1, padding=0),
+ nn.BatchNorm3d(64),
+ nn.ReLU(),
+ nn.Conv3d(64, 1, kernel_size=(1, 1, 1), stride=1, padding=0),
+ ))
+
+ self.linear = nn.Sequential(nn.Linear(1, 1))
+
+ def forward_plus(self, x, y, net):
+ return [net(x)[0] + y[0]]
+
+
+ def dual_define(self,name,labels,net):
+ for label in labels:
+ self.add_module(f"{name}_{label}",copy.deepcopy(net))
+
+
+
+ def upsample(self, x, dims=["space"]):
+ ori_size = x[0].shape[2:5]
+ t, h, w = ori_size
+ if "space" in dims:
+ h = 2 * h
+ w = 2 * w
+ if "time" in dims:
+ t = 2 * t
+ size = (t, h, w)
+ return [F.interpolate(x[0], size)]
+
+ def concat(self,x,y):
+ return [torch.cat([x[0],y[0]],1)]
+
+ def get_detach_var(self,x):
+ return [t.detach() for t in x]
+
+ # @torchsnooper.snoop()
+ def forward(self, x, freeze_backbone=False):
+ x1 = self.s1(x) # 1,64,8,56,56
+ x2 = self.s2(x1) # 1,256,8,56,56
+ x3 = self.s3(x2) # 1,512,8,28, 28
+ x = self.s4(x3) # 1,1024,8,14,14
+ assert isinstance(freeze_backbone,bool)
+ if freeze_backbone:
+ x=self.get_detach_var(x)
+ x1=self.get_detach_var(x1)
+ x2=self.get_detach_var(x2)
+ x3=self.get_detach_var(x3)
+
+ x = self.upsample(x) # 1,1024, 8, 28, 28
+ x = self.concat(x3,x)# 1,1024+512, 8, 28, 28
+ x=[self.forward_branch(x,x1,x2,label) for label in self.labels]
+ x=torch.cat(x,1)
+ x=torch.sigmoid(x)
+ out = x.mean([3, 4]).view(-1, 1)*100 # 1,2,8,56,56
+ out = self.linear(out)
+ out = out.view(x.size(0), -1)
+ out = torch.sigmoid(out)
+ return x,out
+
+
+
+ def forward_branch(self,x,x1,x2,label):
+ t4=getattr(self,f"t4_{label}")
+ x = t4(x[0])# 1,256, 8, 28, 28
+ x = self.upsample([x]) # 1,256, 8, 56, 56
+ x = self.concat(x2,x)# 1,256+256, 8, 56, 56
+ t3= getattr(self,f"t3_{label}")
+ x = t3(x[0]) # 1,128, 8, 56, 56
+ x = self.concat(x1,[x]) # 1,192, 8, 56, 56
+ conv1x1=getattr(self,f"conv1x1_{label}")
+ x = conv1x1(x[0]) # 1,2,8,56,56
+ return x
+
+
+
+@MODEL_REGISTRY.register()
+class ResUNetContinus(nn.Module):
+ """
+ ResNet model builder. It builds a ResNet like network backbone without
+ lateral connection (C2D, I3D, Slow).
+
+ Christoph Feichtenhofer, Haoqi Fan, Jitendra Malik, and Kaiming He.
+ "SlowFast networks for video recognition."
+ https://arxiv.org/pdf/1812.03982.pdf
+
+ Xiaolong Wang, Ross Girshick, Abhinav Gupta, and Kaiming He.
+ "Non-local neural networks."
+ https://arxiv.org/pdf/1711.07971.pdf
+ """
+
+ def __init__(self, cfg):
+ """
+ The `__init__` method of any subclass should also contain these
+ arguments.
+
+ Args:
+ cfg (CfgNode): model building configs, details are in the
+ comments of the config file.
+ """
+ super(ResUNetContinus, self).__init__()
+ self.norm_module = get_norm(cfg)
+ self.enable_detection = cfg.DETECTION.ENABLE
+ self.enable_jitter = cfg.JITTER.ENABLE
+ self.num_pathways = 1
+ assert cfg.DATA.TRAIN_CROP_SIZE == cfg.DATA.TEST_CROP_SIZE
+ self.image_size = cfg.DATA.TRAIN_CROP_SIZE
+ self.clip_size = cfg.DATA.NUM_FRAMES
+ self._construct_network(cfg)
+ init_helper.init_weights(
+ self, cfg.MODEL.FC_INIT_STD, cfg.RESNET.ZERO_INIT_FINAL_BN
+ )
+
+ def _construct_network(self, cfg):
+ """
+ Builds a single pathway ResNet model.
+
+ Args:
+ cfg (CfgNode): model building configs, details are in the
+ comments of the config file.
+ """
+ assert cfg.MODEL.ARCH in _POOL1.keys()
+ pool_size = _POOL1[cfg.MODEL.ARCH]
+ self.cfg = cfg
+ assert len({len(pool_size), self.num_pathways}) == 1
+ assert cfg.RESNET.DEPTH in _MODEL_STAGE_DEPTH.keys()
+
+ (d2, d3, d4, d5) = _MODEL_STAGE_DEPTH[cfg.RESNET.DEPTH]
+
+ num_groups = cfg.RESNET.NUM_GROUPS
+ width_per_group = cfg.RESNET.WIDTH_PER_GROUP
+ dim_inner = num_groups * width_per_group
+
+ temp_kernel = _TEMPORAL_KERNEL_BASIS[cfg.MODEL.ARCH]
+
+ self.s1 = stem_helper.VideoModelStem(
+ dim_in=cfg.DATA.INPUT_CHANNEL_NUM,
+ dim_out=[width_per_group],
+ kernel=[temp_kernel[0][0] + [7, 7]],
+ stride=[[1, 2, 2]],
+ padding=[[temp_kernel[0][0][0] // 2, 3, 3]],
+ norm_module=self.norm_module,
+ )
+
+ self.s2 = resnet_helper.ResStage(
+ dim_in=[width_per_group],
+ dim_out=[width_per_group * 4],
+ dim_inner=[dim_inner],
+ temp_kernel_sizes=temp_kernel[1],
+ stride=cfg.RESNET.SPATIAL_STRIDES[0],
+ num_blocks=[d2],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[0],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[0],
+ nonlocal_group=cfg.NONLOCAL.GROUP[0],
+ nonlocal_pool=cfg.NONLOCAL.POOL[0],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[0],
+ norm_module=self.norm_module,
+ )
+
+ for pathway in range(self.num_pathways):
+ pool = nn.MaxPool3d(
+ kernel_size=pool_size[pathway],
+ stride=pool_size[pathway],
+ padding=[0, 0, 0],
+ )
+ self.add_module("pathway{}_pool".format(pathway), pool)
+
+ self.s3 = resnet_helper.ResStage(
+ dim_in=[width_per_group * 4],
+ dim_out=[width_per_group * 8],
+ dim_inner=[dim_inner * 2],
+ temp_kernel_sizes=temp_kernel[2],
+ stride=cfg.RESNET.SPATIAL_STRIDES[1],
+ num_blocks=[d3],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[1],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[1],
+ nonlocal_group=cfg.NONLOCAL.GROUP[1],
+ nonlocal_pool=cfg.NONLOCAL.POOL[1],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[1],
+ norm_module=self.norm_module,
+ )
+
+ self.s4 = resnet_helper.ResStage(
+ dim_in=[width_per_group * 8],
+ dim_out=[width_per_group * 16],
+ dim_inner=[dim_inner * 4],
+ temp_kernel_sizes=temp_kernel[3],
+ stride=cfg.RESNET.SPATIAL_STRIDES[2],
+ num_blocks=[d4],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[2],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[2],
+ nonlocal_group=cfg.NONLOCAL.GROUP[2],
+ nonlocal_pool=cfg.NONLOCAL.POOL[2],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[2],
+ norm_module=self.norm_module,
+ )
+
+ # self.s5 = resnet_helper.ResStage(
+ # dim_in=[width_per_group * 16],
+ # dim_out=[width_per_group * 32],
+ # dim_inner=[dim_inner * 8],
+ # temp_kernel_sizes=temp_kernel[4],
+ # stride=cfg.RESNET.SPATIAL_STRIDES[3],
+ # num_blocks=[d5],
+ # num_groups=[num_groups],
+ # num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[3],
+ # nonlocal_inds=cfg.NONLOCAL.LOCATION[3],
+ # nonlocal_group=cfg.NONLOCAL.GROUP[3],
+ # nonlocal_pool=cfg.NONLOCAL.POOL[3],
+ # instantiation=cfg.NONLOCAL.INSTANTIATION,
+ # trans_func_name=cfg.RESNET.TRANS_FUNC,
+ # stride_1x1=cfg.RESNET.STRIDE_1X1,
+ # inplace_relu=cfg.RESNET.INPLACE_RELU,
+ # dilation=cfg.RESNET.SPATIAL_DILATIONS[3],
+ # norm_module=self.norm_module,
+ # )
+ self.labels=["all"]
+ self.dual_define("t4",self.labels,LightDecoderBlock(width_per_group * 16,width_per_group * 8,width_per_group * 4))
+ self.dual_define("t3",self.labels,LightDecoderBlock(width_per_group * 4,width_per_group * 4, 128))
+ self.dual_define("conv1x1",self.labels,nn.Sequential(
+ nn.Conv3d(128+width_per_group, 64, kernel_size=(1, 1, 1), stride=1, padding=0),
+ nn.BatchNorm3d(64),
+ nn.ReLU(),
+ nn.Conv3d(64, 1, kernel_size=(1, 1, 1), stride=1, padding=0),
+ ))
+
+ self.linear = nn.Sequential(nn.Linear(1, 1))
+
+ def forward_plus(self, x, y, net):
+ return [net(x)[0] + y[0]]
+
+
+ def dual_define(self,name,labels,net):
+ for label in labels:
+ self.add_module(f"{name}_{label}",copy.deepcopy(net))
+
+
+
+ def upsample(self, x, dims=["space"]):
+ ori_size = x[0].shape[2:5]
+ t, h, w = ori_size
+ if "space" in dims:
+ h = 2 * h
+ w = 2 * w
+ if "time" in dims:
+ t = 2 * t
+ size = (t, h, w)
+ return [F.interpolate(x[0], size)]
+
+ def concat(self,x,y):
+ return [torch.cat([x[0],y[0]],1)]
+
+ def get_detach_var(self,x):
+ return [t.detach() for t in x]
+
+ # @torchsnooper.snoop()
+ def forward(self, x, freeze_backbone=False):
+ x1 = self.s1(x) # 1,64,8,56,56
+ x2 = self.s2(x1) # 1,256,8,56,56
+ x3 = self.s3(x2) # 1,512,8,28, 28
+ x = self.s4(x3) # 1,1024,8,14,14
+ assert isinstance(freeze_backbone,bool)
+ if freeze_backbone:
+ x=self.get_detach_var(x)
+ x1=self.get_detach_var(x1)
+ x2=self.get_detach_var(x2)
+ x3=self.get_detach_var(x3)
+
+ x = self.upsample(x) # 1,1024, 8, 28, 28
+ x = self.concat(x3,x)# 1,1024+512, 8, 28, 28
+ x=[self.forward_branch(x,x1,x2,label) for label in self.labels]
+ x=torch.cat(x,1)
+ x=torch.sigmoid(x)
+ out = x.mean([3, 4]).view(-1, 1)*100 # 1,2,8,56,56
+ out = self.linear(out)
+ out = out.view(x.size(0), -1)
+ out = torch.sigmoid(out)
+ return x,out
+
+
+ def forward_branch(self,x,x1,x2,label):
+ t4= getattr(self,f"t4_{label}")
+ x = t4(x[0])# 1,256, 8, 28, 28
+ x = self.upsample([x]) # 1,256, 8, 56, 56
+ x = self.concat(x2,x)# 1,256+256, 8, 56, 56
+ t3= getattr(self,f"t3_{label}")
+ x = t3(x[0]) # 1,128, 8, 56, 56
+ x = self.concat(x1,[x]) # 1,192, 8, 56, 56
+ conv1x1=getattr(self,f"conv1x1_{label}")
+ x = conv1x1(x[0]) # 1,2,8,56,56
+ return x
+
+
+
+
+@MODEL_REGISTRY.register()
+class ResUNetCommon(nn.Module):
+ """
+ ResNet model builder. It builds a ResNet like network backbone without
+ lateral connection (C2D, I3D, Slow).
+
+ Christoph Feichtenhofer, Haoqi Fan, Jitendra Malik, and Kaiming He.
+ "SlowFast networks for video recognition."
+ https://arxiv.org/pdf/1812.03982.pdf
+
+ Xiaolong Wang, Ross Girshick, Abhinav Gupta, and Kaiming He.
+ "Non-local neural networks."
+ https://arxiv.org/pdf/1711.07971.pdf
+ """
+
+ def __init__(self, cfg):
+ """
+ The `__init__` method of any subclass should also contain these
+ arguments.
+
+ Args:
+ cfg (CfgNode): model building configs, details are in the
+ comments of the config file.
+ """
+ super(ResUNetCommon, self).__init__()
+ self.norm_module = get_norm(cfg)
+ self.enable_detection = cfg.DETECTION.ENABLE
+ self.enable_jitter = cfg.JITTER.ENABLE
+ self.num_pathways = 1
+ assert cfg.DATA.TRAIN_CROP_SIZE == cfg.DATA.TEST_CROP_SIZE
+ self.image_size = cfg.DATA.TRAIN_CROP_SIZE
+ self.clip_size = cfg.DATA.NUM_FRAMES
+ self._construct_network(cfg)
+ init_helper.init_weights(
+ self, cfg.MODEL.FC_INIT_STD, cfg.RESNET.ZERO_INIT_FINAL_BN
+ )
+
+ def _construct_network(self, cfg):
+ """
+ Builds a single pathway ResNet model.
+
+ Args:
+ cfg (CfgNode): model building configs, details are in the
+ comments of the config file.
+ """
+ assert cfg.MODEL.ARCH in _POOL1.keys()
+ pool_size = _POOL1[cfg.MODEL.ARCH]
+ self.cfg = cfg
+ assert len({len(pool_size), self.num_pathways}) == 1
+ assert cfg.RESNET.DEPTH in _MODEL_STAGE_DEPTH.keys()
+
+ (d2, d3, d4, d5) = _MODEL_STAGE_DEPTH[cfg.RESNET.DEPTH]
+
+ num_groups = cfg.RESNET.NUM_GROUPS
+ width_per_group = cfg.RESNET.WIDTH_PER_GROUP
+ dim_inner = num_groups * width_per_group
+
+ temp_kernel = _TEMPORAL_KERNEL_BASIS[cfg.MODEL.ARCH]
+
+ self.s1 = stem_helper.VideoModelStem(
+ dim_in=cfg.DATA.INPUT_CHANNEL_NUM,
+ dim_out=[width_per_group],
+ kernel=[temp_kernel[0][0] + [7, 7]],
+ stride=[[1, 2, 2]],
+ padding=[[temp_kernel[0][0][0] // 2, 3, 3]],
+ norm_module=self.norm_module,
+ )
+
+ self.s2 = resnet_helper.ResStage(
+ dim_in=[width_per_group],
+ dim_out=[width_per_group * 4],
+ dim_inner=[dim_inner],
+ temp_kernel_sizes=temp_kernel[1],
+ stride=cfg.RESNET.SPATIAL_STRIDES[0],
+ num_blocks=[d2],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[0],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[0],
+ nonlocal_group=cfg.NONLOCAL.GROUP[0],
+ nonlocal_pool=cfg.NONLOCAL.POOL[0],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[0],
+ norm_module=self.norm_module,
+ )
+
+ for pathway in range(self.num_pathways):
+ pool = nn.MaxPool3d(
+ kernel_size=pool_size[pathway],
+ stride=pool_size[pathway],
+ padding=[0, 0, 0],
+ )
+ self.add_module("pathway{}_pool".format(pathway), pool)
+
+ self.s3 = resnet_helper.ResStage(
+ dim_in=[width_per_group * 4],
+ dim_out=[width_per_group * 8],
+ dim_inner=[dim_inner * 2],
+ temp_kernel_sizes=temp_kernel[2],
+ stride=cfg.RESNET.SPATIAL_STRIDES[1],
+ num_blocks=[d3],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[1],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[1],
+ nonlocal_group=cfg.NONLOCAL.GROUP[1],
+ nonlocal_pool=cfg.NONLOCAL.POOL[1],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[1],
+ norm_module=self.norm_module,
+ )
+
+ self.s4 = resnet_helper.ResStage(
+ dim_in=[width_per_group * 8],
+ dim_out=[width_per_group * 16],
+ dim_inner=[dim_inner * 4],
+ temp_kernel_sizes=temp_kernel[3],
+ stride=cfg.RESNET.SPATIAL_STRIDES[2],
+ num_blocks=[d4],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[2],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[2],
+ nonlocal_group=cfg.NONLOCAL.GROUP[2],
+ nonlocal_pool=cfg.NONLOCAL.POOL[2],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[2],
+ norm_module=self.norm_module,
+ )
+
+ # self.s5 = resnet_helper.ResStage(
+ # dim_in=[width_per_group * 16],
+ # dim_out=[width_per_group * 32],
+ # dim_inner=[dim_inner * 8],
+ # temp_kernel_sizes=temp_kernel[4],
+ # stride=cfg.RESNET.SPATIAL_STRIDES[3],
+ # num_blocks=[d5],
+ # num_groups=[num_groups],
+ # num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[3],
+ # nonlocal_inds=cfg.NONLOCAL.LOCATION[3],
+ # nonlocal_group=cfg.NONLOCAL.GROUP[3],
+ # nonlocal_pool=cfg.NONLOCAL.POOL[3],
+ # instantiation=cfg.NONLOCAL.INSTANTIATION,
+ # trans_func_name=cfg.RESNET.TRANS_FUNC,
+ # stride_1x1=cfg.RESNET.STRIDE_1X1,
+ # inplace_relu=cfg.RESNET.INPLACE_RELU,
+ # dilation=cfg.RESNET.SPATIAL_DILATIONS[3],
+ # norm_module=self.norm_module,
+ # )
+ self.labels=cfg.RESNET.LABELS
+ self.dual_define("t4",self.labels,LightDecoderBlock(width_per_group * 16,width_per_group * 8,width_per_group * 4))
+ self.dual_define("t3",self.labels,LightDecoderBlock(width_per_group * 4,width_per_group * 4, 128))
+ self.dual_define("conv1x1",self.labels,nn.Sequential(
+ nn.Conv3d(128+width_per_group, 64, kernel_size=(1, 1, 1), stride=1, padding=0),
+ nn.BatchNorm3d(64),
+ nn.ReLU(),
+ nn.Conv3d(64, 1, kernel_size=(1, 1, 1), stride=1, padding=0),
+ ))
+
+ self.linear = nn.Linear(1, 2)
+
+ def forward_plus(self, x, y, net):
+ return [net(x)[0] + y[0]]
+
+
+ def dual_define(self,name,labels,net):
+ for label in labels:
+ self.add_module(f"{name}_{label}",copy.deepcopy(net))
+
+
+ def upsample(self, x, dims=["space"]):
+ ori_size = x[0].shape[2:5]
+ t, h, w = ori_size
+ if "space" in dims:
+ h = 2 * h
+ w = 2 * w
+ if "time" in dims:
+ t = 2 * t
+ size = (t, h, w)
+ return [F.interpolate(x[0], size)]
+
+ def concat(self,x,y):
+ return [torch.cat([x[0],y[0]],1)]
+
+ def get_detach_var(self,x):
+ return [t.detach() for t in x]
+
+ # @torchsnooper.snoop()
+ def forward(self, x, freeze_backbone=False):
+ x = self.get_detach_var(x)
+ x1 = self.s1(x) # 1,64,8,56,56
+ x2 = self.s2(x1) # 1,256,8,56,56
+ x3 = self.s3(x2) # 1,512,8,28, 28
+ feat= self.s4(x3) # 1,1024,8,14,14
+ assert isinstance(freeze_backbone,bool)
+ if freeze_backbone:
+ feat=self.get_detach_var(feat)
+ x1=self.get_detach_var(x1)
+ x2=self.get_detach_var(x2)
+ x3=self.get_detach_var(x3)
+
+ feat = self.upsample(feat) # 1,1024, 8, 28, 28
+ feat = self.concat(x3,feat)# 1,1024+512, 8, 28, 28
+ reg_out=[self.forward_branch(feat,x1,x2,label) for label in self.labels]
+ reg_out=torch.cat(reg_out,1)
+ reg_out=torch.sigmoid(reg_out)
+ class_out = reg_out.mean([3, 4]).view(-1, 1)*100 # 1,2,8,56,56
+ class_out = self.linear(class_out)
+ class_out = class_out.view(reg_out.size(0),len(self.labels),-1)
+ class_out = class_out
+ return reg_out,class_out
+
+
+ def forward_branch(self,feat,x1,x2,label):
+ t4= getattr(self,f"t4_{label}")
+ feat = t4(feat[0])# 1,256, 8, 28, 28
+ feat = self.upsample([feat]) # 1,256, 8, 56, 56
+ feat = self.concat(x2,feat)# 1,256+256, 8, 56, 56
+ t3= getattr(self,f"t3_{label}")
+ feat = t3(feat[0]) # 1,128, 8, 56, 56
+ feat = self.concat(x1,[feat]) # 1,192, 8, 56, 56
+ conv1x1=getattr(self,f"conv1x1_{label}")
+ feat = conv1x1(feat[0]) # 1,2,8,56,56
+ return feat
+
+
+
+
+@MODEL_REGISTRY.register()
+class ResUNetCommon2(nn.Module):
+ """
+ ResNet model builder. It builds a ResNet like network backbone without
+ lateral connection (C2D, I3D, Slow).
+
+ Christoph Feichtenhofer, Haoqi Fan, Jitendra Malik, and Kaiming He.
+ "SlowFast networks for video recognition."
+ https://arxiv.org/pdf/1812.03982.pdf
+
+ Xiaolong Wang, Ross Girshick, Abhinav Gupta, and Kaiming He.
+ "Non-local neural networks."
+ https://arxiv.org/pdf/1711.07971.pdf
+ """
+
+ def __init__(self, cfg):
+ """
+ The `__init__` method of any subclass should also contain these
+ arguments.
+
+ Args:
+ cfg (CfgNode): model building configs, details are in the
+ comments of the config file.
+ """
+ super(ResUNetCommon2, self).__init__()
+ self.norm_module = get_norm(cfg)
+ self.enable_detection = cfg.DETECTION.ENABLE
+ self.enable_jitter = cfg.JITTER.ENABLE
+ self.num_pathways = 1
+ assert cfg.DATA.TRAIN_CROP_SIZE == cfg.DATA.TEST_CROP_SIZE
+ self.image_size = cfg.DATA.TRAIN_CROP_SIZE
+ self.clip_size = cfg.DATA.NUM_FRAMES
+ self._construct_network(cfg)
+ init_helper.init_weights(
+ self, cfg.MODEL.FC_INIT_STD, cfg.RESNET.ZERO_INIT_FINAL_BN
+ )
+
+ def _construct_network(self, cfg):
+ """
+ Builds a single pathway ResNet model.
+
+ Args:
+ cfg (CfgNode): model building configs, details are in the
+ comments of the config file.
+ """
+ assert cfg.MODEL.ARCH in _POOL1.keys()
+ pool_size = _POOL1[cfg.MODEL.ARCH]
+ self.cfg = cfg
+ assert len({len(pool_size), self.num_pathways}) == 1
+ assert cfg.RESNET.DEPTH in _MODEL_STAGE_DEPTH.keys()
+
+ (d2, d3, d4, d5) = _MODEL_STAGE_DEPTH[cfg.RESNET.DEPTH]
+
+ num_groups = cfg.RESNET.NUM_GROUPS
+ width_per_group = cfg.RESNET.WIDTH_PER_GROUP
+ dim_inner = num_groups * width_per_group
+
+ temp_kernel = _TEMPORAL_KERNEL_BASIS[cfg.MODEL.ARCH]
+
+ self.s1 = stem_helper.VideoModelStem(
+ dim_in=cfg.DATA.INPUT_CHANNEL_NUM,
+ dim_out=[width_per_group],
+ kernel=[temp_kernel[0][0] + [7, 7]],
+ stride=[[1, 2, 2]],
+ padding=[[temp_kernel[0][0][0] // 2, 3, 3]],
+ norm_module=self.norm_module,
+ )
+
+ self.s2 = resnet_helper.ResStage(
+ dim_in=[width_per_group],
+ dim_out=[width_per_group * 4],
+ dim_inner=[dim_inner],
+ temp_kernel_sizes=temp_kernel[1],
+ stride=cfg.RESNET.SPATIAL_STRIDES[0],
+ num_blocks=[d2],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[0],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[0],
+ nonlocal_group=cfg.NONLOCAL.GROUP[0],
+ nonlocal_pool=cfg.NONLOCAL.POOL[0],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[0],
+ norm_module=self.norm_module,
+ )
+
+ for pathway in range(self.num_pathways):
+ pool = nn.MaxPool3d(
+ kernel_size=pool_size[pathway],
+ stride=pool_size[pathway],
+ padding=[0, 0, 0],
+ )
+ self.add_module("pathway{}_pool".format(pathway), pool)
+
+ self.s3 = resnet_helper.ResStage(
+ dim_in=[width_per_group * 4],
+ dim_out=[width_per_group * 8],
+ dim_inner=[dim_inner * 2],
+ temp_kernel_sizes=temp_kernel[2],
+ stride=cfg.RESNET.SPATIAL_STRIDES[1],
+ num_blocks=[d3],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[1],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[1],
+ nonlocal_group=cfg.NONLOCAL.GROUP[1],
+ nonlocal_pool=cfg.NONLOCAL.POOL[1],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[1],
+ norm_module=self.norm_module,
+ )
+
+ self.s4 = resnet_helper.ResStage(
+ dim_in=[width_per_group * 8],
+ dim_out=[width_per_group * 16],
+ dim_inner=[dim_inner * 4],
+ temp_kernel_sizes=temp_kernel[3],
+ stride=cfg.RESNET.SPATIAL_STRIDES[2],
+ num_blocks=[d4],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[2],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[2],
+ nonlocal_group=cfg.NONLOCAL.GROUP[2],
+ nonlocal_pool=cfg.NONLOCAL.POOL[2],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[2],
+ norm_module=self.norm_module,
+ )
+
+ # self.s5 = resnet_helper.ResStage(
+ # dim_in=[width_per_group * 16],
+ # dim_out=[width_per_group * 32],
+ # dim_inner=[dim_inner * 8],
+ # temp_kernel_sizes=temp_kernel[4],
+ # stride=cfg.RESNET.SPATIAL_STRIDES[3],
+ # num_blocks=[d5],
+ # num_groups=[num_groups],
+ # num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[3],
+ # nonlocal_inds=cfg.NONLOCAL.LOCATION[3],
+ # nonlocal_group=cfg.NONLOCAL.GROUP[3],
+ # nonlocal_pool=cfg.NONLOCAL.POOL[3],
+ # instantiation=cfg.NONLOCAL.INSTANTIATION,
+ # trans_func_name=cfg.RESNET.TRANS_FUNC,
+ # stride_1x1=cfg.RESNET.STRIDE_1X1,
+ # inplace_relu=cfg.RESNET.INPLACE_RELU,
+ # dilation=cfg.RESNET.SPATIAL_DILATIONS[3],
+ # norm_module=self.norm_module,
+ # )
+ self.labels=cfg.RESNET.LABELS
+ self.dual_define("t4",self.labels,LightDecoderBlock(width_per_group * 16,width_per_group * 8,width_per_group * 4))
+ self.dual_define("t3",self.labels,LightDecoderBlock(width_per_group * 4,width_per_group * 4, 128))
+ self.dual_define("conv1x1",self.labels,nn.Sequential(
+ nn.Conv3d(128+width_per_group, 64, kernel_size=(1, 1, 1), stride=1, padding=0),
+ nn.BatchNorm3d(64),
+ nn.ReLU(),
+ nn.Conv3d(64, 1, kernel_size=(1, 1, 1), stride=1, padding=0),
+ ))
+
+ self.linear = nn.Linear(1, 1)
+
+ def forward_plus(self, x, y, net):
+ return [net(x)[0] + y[0]]
+
+
+ def dual_define(self,name,labels,net):
+ for label in labels:
+ self.add_module(f"{name}_{label}",copy.deepcopy(net))
+
+
+ def upsample(self, x, dims=["space"]):
+ ori_size = x[0].shape[2:5]
+ t, h, w = ori_size
+ if "space" in dims:
+ h = 2 * h
+ w = 2 * w
+ if "time" in dims:
+ t = 2 * t
+ size = (t, h, w)
+ return [F.interpolate(x[0], size)]
+
+ def concat(self,x,y):
+ return [torch.cat([x[0],y[0]],1)]
+
+ def get_detach_var(self,x):
+ return [t.detach() for t in x]
+
+ # @torchsnooper.snoop()
+ def forward(self, x, freeze_backbone=False):
+ x = self.get_detach_var(x)
+ x1 = self.s1(x) # 1,64,8,56,56
+ x2 = self.s2(x1) # 1,256,8,56,56
+ x3 = self.s3(x2) # 1,512,8,28, 28
+ feat= self.s4(x3) # 1,1024,8,14,14
+ assert isinstance(freeze_backbone,bool)
+ if freeze_backbone:
+ feat=self.get_detach_var(feat)
+ x1=self.get_detach_var(x1)
+ x2=self.get_detach_var(x2)
+ x3=self.get_detach_var(x3)
+
+ feat = self.upsample(feat) # 1,1024, 8, 28, 28
+ feat = self.concat(x3,feat)# 1,1024+512, 8, 28, 28
+ reg_out=[self.forward_branch(feat,x1,x2,label) for label in self.labels]
+ reg_out=torch.cat(reg_out,1)
+ reg_out=torch.sigmoid(reg_out)
+ class_out = reg_out.mean([3, 4]).view(-1, 1)*100 # 1,2,8,56,56
+ class_out = self.linear(class_out)
+ class_out = class_out.view(reg_out.size(0),len(self.labels),-1)
+ class_out = torch.sigmoid(class_out)
+ return reg_out,class_out
+
+
+ def forward_branch(self,feat,x1,x2,label):
+ t4= getattr(self,f"t4_{label}")
+ feat = t4(feat[0])# 1,256, 8, 28, 28
+ feat = self.upsample([feat]) # 1,256, 8, 56, 56
+ feat = self.concat(x2,feat)# 1,256+256, 8, 56, 56
+ t3= getattr(self,f"t3_{label}")
+ feat = t3(feat[0]) # 1,128, 8, 56, 56
+ feat = self.concat(x1,[feat]) # 1,192, 8, 56, 56
+ conv1x1=getattr(self,f"conv1x1_{label}")
+ feat = conv1x1(feat[0]) # 1,2,8,56,56
+ return feat
+
+
+
+@MODEL_REGISTRY.register()
+class ResUNetStrong(nn.Module):
+ """
+ ResNet model builder. It builds a ResNet like network backbone without
+ lateral connection (C2D, I3D, Slow).
+
+ Christoph Feichtenhofer, Haoqi Fan, Jitendra Malik, and Kaiming He.
+ "SlowFast networks for video recognition."
+ https://arxiv.org/pdf/1812.03982.pdf
+
+ Xiaolong Wang, Ross Girshick, Abhinav Gupta, and Kaiming He.
+ "Non-local neural networks."
+ https://arxiv.org/pdf/1711.07971.pdf
+ """
+
+ def __init__(self, cfg):
+ """
+ The `__init__` method of any subclass should also contain these
+ arguments.
+
+ Args:
+ cfg (CfgNode): model building configs, details are in the
+ comments of the config file.
+ """
+ super(ResUNetStrong, self).__init__()
+ self.norm_module = get_norm(cfg)
+ self.enable_detection = cfg.DETECTION.ENABLE
+ self.enable_jitter = cfg.JITTER.ENABLE
+ self.num_pathways = 1
+ assert cfg.DATA.TRAIN_CROP_SIZE == cfg.DATA.TEST_CROP_SIZE
+ self.image_size = cfg.DATA.TRAIN_CROP_SIZE
+ self.clip_size = cfg.DATA.NUM_FRAMES
+ self._construct_network(cfg)
+ init_helper.init_weights(
+ self, cfg.MODEL.FC_INIT_STD, cfg.RESNET.ZERO_INIT_FINAL_BN
+ )
+
+ def _construct_network(self, cfg):
+ """
+ Builds a single pathway ResNet model.
+
+ Args:
+ cfg (CfgNode): model building configs, details are in the
+ comments of the config file.
+ """
+ assert cfg.MODEL.ARCH in _POOL1.keys()
+ pool_size = _POOL1[cfg.MODEL.ARCH]
+ self.cfg = cfg
+ assert len({len(pool_size), self.num_pathways}) == 1
+ assert cfg.RESNET.DEPTH in _MODEL_STAGE_DEPTH.keys()
+
+ (d2, d3, d4, d5) = _MODEL_STAGE_DEPTH[cfg.RESNET.DEPTH]
+
+ num_groups = cfg.RESNET.NUM_GROUPS
+ width_per_group = cfg.RESNET.WIDTH_PER_GROUP
+ dim_inner = num_groups * width_per_group
+
+ temp_kernel = _TEMPORAL_KERNEL_BASIS[cfg.MODEL.ARCH]
+
+ self.s1 = stem_helper.VideoModelStem(
+ dim_in=cfg.DATA.INPUT_CHANNEL_NUM,
+ dim_out=[width_per_group],
+ kernel=[temp_kernel[0][0] + [7, 7]],
+ stride=[[1, 2, 2]],
+ padding=[[temp_kernel[0][0][0] // 2, 3, 3]],
+ norm_module=self.norm_module,
+ )
+
+ self.s2 = resnet_helper.ResStage(
+ dim_in=[width_per_group],
+ dim_out=[width_per_group * 4],
+ dim_inner=[dim_inner],
+ temp_kernel_sizes=temp_kernel[1],
+ stride=cfg.RESNET.SPATIAL_STRIDES[0],
+ num_blocks=[d2],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[0],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[0],
+ nonlocal_group=cfg.NONLOCAL.GROUP[0],
+ nonlocal_pool=cfg.NONLOCAL.POOL[0],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[0],
+ norm_module=self.norm_module,
+ )
+
+ for pathway in range(self.num_pathways):
+ pool = nn.MaxPool3d(
+ kernel_size=pool_size[pathway],
+ stride=pool_size[pathway],
+ padding=[0, 0, 0],
+ )
+ self.add_module("pathway{}_pool".format(pathway), pool)
+
+ self.s3 = resnet_helper.ResStage(
+ dim_in=[width_per_group * 4],
+ dim_out=[width_per_group * 8],
+ dim_inner=[dim_inner * 2],
+ temp_kernel_sizes=temp_kernel[2],
+ stride=cfg.RESNET.SPATIAL_STRIDES[1],
+ num_blocks=[d3],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[1],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[1],
+ nonlocal_group=cfg.NONLOCAL.GROUP[1],
+ nonlocal_pool=cfg.NONLOCAL.POOL[1],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[1],
+ norm_module=self.norm_module,
+ )
+
+ self.s4 = resnet_helper.ResStage(
+ dim_in=[width_per_group * 8],
+ dim_out=[width_per_group * 16],
+ dim_inner=[dim_inner * 4],
+ temp_kernel_sizes=temp_kernel[3],
+ stride=cfg.RESNET.SPATIAL_STRIDES[2],
+ num_blocks=[d4],
+ num_groups=[num_groups],
+ num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[2],
+ nonlocal_inds=cfg.NONLOCAL.LOCATION[2],
+ nonlocal_group=cfg.NONLOCAL.GROUP[2],
+ nonlocal_pool=cfg.NONLOCAL.POOL[2],
+ instantiation=cfg.NONLOCAL.INSTANTIATION,
+ trans_func_name=cfg.RESNET.TRANS_FUNC,
+ stride_1x1=cfg.RESNET.STRIDE_1X1,
+ inplace_relu=cfg.RESNET.INPLACE_RELU,
+ dilation=cfg.RESNET.SPATIAL_DILATIONS[2],
+ norm_module=self.norm_module,
+ )
+
+ # self.s5 = resnet_helper.ResStage(
+ # dim_in=[width_per_group * 16],
+ # dim_out=[width_per_group * 32],
+ # dim_inner=[dim_inner * 8],
+ # temp_kernel_sizes=temp_kernel[4],
+ # stride=cfg.RESNET.SPATIAL_STRIDES[3],
+ # num_blocks=[d5],
+ # num_groups=[num_groups],
+ # num_block_temp_kernel=cfg.RESNET.NUM_BLOCK_TEMP_KERNEL[3],
+ # nonlocal_inds=cfg.NONLOCAL.LOCATION[3],
+ # nonlocal_group=cfg.NONLOCAL.GROUP[3],
+ # nonlocal_pool=cfg.NONLOCAL.POOL[3],
+ # instantiation=cfg.NONLOCAL.INSTANTIATION,
+ # trans_func_name=cfg.RESNET.TRANS_FUNC,
+ # stride_1x1=cfg.RESNET.STRIDE_1X1,
+ # inplace_relu=cfg.RESNET.INPLACE_RELU,
+ # dilation=cfg.RESNET.SPATIAL_DILATIONS[3],
+ # norm_module=self.norm_module,
+ # )
+
+ self.labels=cfg.RESNET.LABELS
+ self.dual_define("t4",self.labels,ResDecoderBlock(width_per_group * 16,width_per_group * 8,width_per_group * 8))
+ self.dual_define("t3",self.labels,ResDecoderBlock(width_per_group * 8,width_per_group * 4, 256))
+ self.dual_define("conv1x1",self.labels,nn.Sequential(
+ nn.Conv3d(width_per_group*4+width_per_group, 128, kernel_size=(1, 1, 1), stride=1, padding=0),
+ nn.BatchNorm3d(128),
+ nn.ReLU(),
+ nn.Conv3d(128, 1, kernel_size=(1, 1, 1), stride=1, padding=0),
+ ))
+
+ self.linear = nn.Linear(1, 1)
+
+ def forward_plus(self, x, y, net):
+ return [net(x)[0] + y[0]]
+
+
+ def dual_define(self,name,labels,net):
+ for label in labels:
+ self.add_module(f"{name}_{label}",copy.deepcopy(net))
+
+
+ def upsample(self, x, dims=["space"]):
+ ori_size = x[0].shape[2:5]
+ t, h, w = ori_size
+ if "space" in dims:
+ h = 2 * h
+ w = 2 * w
+ if "time" in dims:
+ t = 2 * t
+ size = (t, h, w)
+ return [F.interpolate(x[0], size)]
+
+ def concat(self,x,y):
+ return [torch.cat([x[0],y[0]],1)]
+
+ def get_detach_var(self,x):
+ return [t.detach() for t in x]
+
+ # @torchsnooper.snoop()
+ def forward(self, x, freeze_backbone=False):
+ x = self.get_detach_var(x)
+ x1 = self.s1(x) # 1,64,8,56,56
+ x2 = self.s2(x1) # 1,256,8,56,56
+ x3 = self.s3(x2) # 1,512,8,28, 28
+ feat= self.s4(x3) # 1,1024,8,14,14
+ assert isinstance(freeze_backbone,bool)
+ if freeze_backbone:
+ feat=self.get_detach_var(feat)
+ x1=self.get_detach_var(x1)
+ x2=self.get_detach_var(x2)
+ x3=self.get_detach_var(x3)
+
+ feat = self.upsample(feat) # 1,1024, 8, 28, 28
+ feat = self.concat(x3,feat)# 1,1024+512, 8, 28, 28
+ reg_out=[self.forward_branch(feat,x1,x2,label) for label in self.labels]
+ reg_out=torch.cat(reg_out,1)
+ reg_out=torch.sigmoid(reg_out)
+ class_out = reg_out.mean([3, 4]).view(-1, 1)*100 # 1,2,8,56,56
+ class_out = self.linear(class_out)
+ class_out = class_out.view(reg_out.size(0),len(self.labels),-1)
+ class_out = torch.sigmoid(class_out)
+ return reg_out,class_out
+
+
+ def forward_branch(self,feat,x1,x2,label):
+ t4= getattr(self,f"t4_{label}")
+ feat = t4(feat[0])# 1,256, 8, 28, 28
+ feat = self.upsample([feat]) # 1,256, 8, 56, 56
+ feat = self.concat(x2,feat)# 1,256+256, 8, 56, 56
+ t3= getattr(self,f"t3_{label}")
+ feat = t3(feat[0]) # 1,128, 8, 56, 56
+ feat = self.concat(x1,[feat]) # 1,192, 8, 56, 56
+ conv1x1=getattr(self,f"conv1x1_{label}")
+ feat = conv1x1(feat[0]) # 1,2,8,56,56
+ return feat
diff --git a/clean/video/pwtf_dvd/inference/slowfast/utils/__init__.py b/clean/video/pwtf_dvd/inference/slowfast/utils/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..8dbe96a785072a24a9bcc4841a1934024f2b06a1
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/utils/__init__.py
@@ -0,0 +1,2 @@
+#!/usr/bin/env python3
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
diff --git a/clean/video/pwtf_dvd/inference/slowfast/utils/ava_eval_helper.py b/clean/video/pwtf_dvd/inference/slowfast/utils/ava_eval_helper.py
new file mode 100644
index 0000000000000000000000000000000000000000..9e8ba5468077053a4dcf1920f25256a1a241f0b9
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/utils/ava_eval_helper.py
@@ -0,0 +1,302 @@
+# Copyright (c) Facebook, Inc. and its affiliates.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##############################################################################
+#
+# Based on:
+# --------------------------------------------------------
+# ActivityNet
+# Copyright (c) 2015 ActivityNet
+# Licensed under The MIT License
+# [see https://github.com/activitynet/ActivityNet/blob/master/LICENSE for details]
+# --------------------------------------------------------
+
+"""Helper functions for AVA evaluation."""
+
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
+import csv
+import logging
+import numpy as np
+import pprint
+import time
+from collections import defaultdict
+from fvcore.common.file_io import PathManager
+
+from slowfast.utils.ava_evaluation import (
+ object_detection_evaluation,
+ standard_fields,
+)
+
+logger = logging.getLogger(__name__)
+
+
+def make_image_key(video_id, timestamp):
+ """Returns a unique identifier for a video id & timestamp."""
+ return "%s,%04d" % (video_id, int(timestamp))
+
+
+def read_csv(csv_file, class_whitelist=None, load_score=False):
+ """Loads boxes and class labels from a CSV file in the AVA format.
+ CSV file format described at https://research.google.com/ava/download.html.
+ Args:
+ csv_file: A file object.
+ class_whitelist: If provided, boxes corresponding to (integer) class labels
+ not in this set are skipped.
+ Returns:
+ boxes: A dictionary mapping each unique image key (string) to a list of
+ boxes, given as coordinates [y1, x1, y2, x2].
+ labels: A dictionary mapping each unique image key (string) to a list of
+ integer class lables, matching the corresponding box in `boxes`.
+ scores: A dictionary mapping each unique image key (string) to a list of
+ score values lables, matching the corresponding label in `labels`. If
+ scores are not provided in the csv, then they will default to 1.0.
+ """
+ boxes = defaultdict(list)
+ labels = defaultdict(list)
+ scores = defaultdict(list)
+ with PathManager.open(csv_file, "r") as f:
+ reader = csv.reader(f)
+ for row in reader:
+ assert len(row) in [7, 8], "Wrong number of columns: " + row
+ image_key = make_image_key(row[0], row[1])
+ x1, y1, x2, y2 = [float(n) for n in row[2:6]]
+ action_id = int(row[6])
+ if class_whitelist and action_id not in class_whitelist:
+ continue
+ score = 1.0
+ if load_score:
+ score = float(row[7])
+ boxes[image_key].append([y1, x1, y2, x2])
+ labels[image_key].append(action_id)
+ scores[image_key].append(score)
+ return boxes, labels, scores
+
+
+def read_exclusions(exclusions_file):
+ """Reads a CSV file of excluded timestamps.
+ Args:
+ exclusions_file: A file object containing a csv of video-id,timestamp.
+ Returns:
+ A set of strings containing excluded image keys, e.g. "aaaaaaaaaaa,0904",
+ or an empty set if exclusions file is None.
+ """
+ excluded = set()
+ if exclusions_file:
+ with PathManager.open(exclusions_file, "r") as f:
+ reader = csv.reader(f)
+ for row in reader:
+ assert len(row) == 2, "Expected only 2 columns, got: " + row
+ excluded.add(make_image_key(row[0], row[1]))
+ return excluded
+
+
+def read_labelmap(labelmap_file):
+ """Read label map and class ids."""
+
+ labelmap = []
+ class_ids = set()
+ name = ""
+ class_id = ""
+ with PathManager.open(labelmap_file, "r") as f:
+ for line in f:
+ if line.startswith(" name:"):
+ name = line.split('"')[1]
+ elif line.startswith(" id:") or line.startswith(" label_id:"):
+ class_id = int(line.strip().split(" ")[-1])
+ labelmap.append({"id": class_id, "name": name})
+ class_ids.add(class_id)
+ return labelmap, class_ids
+
+
+def evaluate_ava_from_files(labelmap, groundtruth, detections, exclusions):
+ """Run AVA evaluation given annotation/prediction files."""
+
+ categories, class_whitelist = read_labelmap(labelmap)
+ excluded_keys = read_exclusions(exclusions)
+ groundtruth = read_csv(groundtruth, class_whitelist, load_score=False)
+ detections = read_csv(detections, class_whitelist, load_score=True)
+ run_evaluation(categories, groundtruth, detections, excluded_keys)
+
+
+def evaluate_ava(
+ preds,
+ original_boxes,
+ metadata,
+ excluded_keys,
+ class_whitelist,
+ categories,
+ groundtruth=None,
+ video_idx_to_name=None,
+ name="latest",
+):
+ """Run AVA evaluation given numpy arrays."""
+
+ eval_start = time.time()
+
+ detections = get_ava_eval_data(
+ preds,
+ original_boxes,
+ metadata,
+ class_whitelist,
+ video_idx_to_name=video_idx_to_name,
+ )
+
+ logger.info("Evaluating with %d unique GT frames." % len(groundtruth[0]))
+ logger.info(
+ "Evaluating with %d unique detection frames" % len(detections[0])
+ )
+
+ write_results(detections, "detections_%s.csv" % name)
+ write_results(groundtruth, "groundtruth_%s.csv" % name)
+
+ results = run_evaluation(categories, groundtruth, detections, excluded_keys)
+
+ logger.info("AVA eval done in %f seconds." % (time.time() - eval_start))
+ return results["PascalBoxes_Precision/mAP@0.5IOU"]
+
+
+def run_evaluation(
+ categories, groundtruth, detections, excluded_keys, verbose=True
+):
+ """AVA evaluation main logic."""
+
+ pascal_evaluator = object_detection_evaluation.PascalDetectionEvaluator(
+ categories
+ )
+
+ boxes, labels, _ = groundtruth
+
+ gt_keys = []
+ pred_keys = []
+
+ for image_key in boxes:
+ if image_key in excluded_keys:
+ logging.info(
+ (
+ "Found excluded timestamp in ground truth: %s. "
+ "It will be ignored."
+ ),
+ image_key,
+ )
+ continue
+ pascal_evaluator.add_single_ground_truth_image_info(
+ image_key,
+ {
+ standard_fields.InputDataFields.groundtruth_boxes: np.array(
+ boxes[image_key], dtype=float
+ ),
+ standard_fields.InputDataFields.groundtruth_classes: np.array(
+ labels[image_key], dtype=int
+ ),
+ standard_fields.InputDataFields.groundtruth_difficult: np.zeros(
+ len(boxes[image_key]), dtype=bool
+ ),
+ },
+ )
+
+ gt_keys.append(image_key)
+
+ boxes, labels, scores = detections
+
+ for image_key in boxes:
+ if image_key in excluded_keys:
+ logging.info(
+ (
+ "Found excluded timestamp in detections: %s. "
+ "It will be ignored."
+ ),
+ image_key,
+ )
+ continue
+ pascal_evaluator.add_single_detected_image_info(
+ image_key,
+ {
+ standard_fields.DetectionResultFields.detection_boxes: np.array(
+ boxes[image_key], dtype=float
+ ),
+ standard_fields.DetectionResultFields.detection_classes: np.array(
+ labels[image_key], dtype=int
+ ),
+ standard_fields.DetectionResultFields.detection_scores: np.array(
+ scores[image_key], dtype=float
+ ),
+ },
+ )
+
+ pred_keys.append(image_key)
+
+ metrics = pascal_evaluator.evaluate()
+
+ pprint.pprint(metrics, indent=2)
+ return metrics
+
+
+def get_ava_eval_data(
+ scores,
+ boxes,
+ metadata,
+ class_whitelist,
+ verbose=False,
+ video_idx_to_name=None,
+):
+ """
+ Convert our data format into the data format used in official AVA
+ evaluation.
+ """
+
+ out_scores = defaultdict(list)
+ out_labels = defaultdict(list)
+ out_boxes = defaultdict(list)
+ count = 0
+ for i in range(scores.shape[0]):
+ video_idx = int(np.round(metadata[i][0]))
+ sec = int(np.round(metadata[i][1]))
+
+ video = video_idx_to_name[video_idx]
+
+ key = video + "," + "%04d" % (sec)
+ batch_box = boxes[i].tolist()
+ # The first is batch idx.
+ batch_box = [batch_box[j] for j in [0, 2, 1, 4, 3]]
+
+ one_scores = scores[i].tolist()
+ for cls_idx, score in enumerate(one_scores):
+ if cls_idx + 1 in class_whitelist:
+ out_scores[key].append(score)
+ out_labels[key].append(cls_idx + 1)
+ out_boxes[key].append(batch_box[1:])
+ count += 1
+
+ return out_boxes, out_labels, out_scores
+
+
+def write_results(detections, filename):
+ """Write prediction results into official formats."""
+ start = time.time()
+
+ boxes, labels, scores = detections
+ with PathManager.open(filename, "w") as f:
+ for key in boxes.keys():
+ for box, label, score in zip(boxes[key], labels[key], scores[key]):
+ f.write(
+ "%s,%.03f,%.03f,%.03f,%.03f,%d,%.04f\n"
+ % (key, box[1], box[0], box[3], box[2], label, score)
+ )
+
+ logger.info("AVA results wrote to %s" % filename)
+ logger.info("\ttook %d seconds." % (time.time() - start))
diff --git a/clean/video/pwtf_dvd/inference/slowfast/utils/benchmark.py b/clean/video/pwtf_dvd/inference/slowfast/utils/benchmark.py
new file mode 100644
index 0000000000000000000000000000000000000000..33e5fe9073ad61ecec737d6b4a6a2880eec15cb9
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/utils/benchmark.py
@@ -0,0 +1,103 @@
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
+"""
+Functions for benchmarks.
+"""
+
+import numpy as np
+import pprint
+import torch
+import tqdm
+from fvcore.common.timer import Timer
+
+import slowfast.utils.logging as logging
+import slowfast.utils.misc as misc
+from slowfast.datasets import loader
+from slowfast.utils.env import setup_environment
+
+logger = logging.get_logger(__name__)
+
+
+def benchmark_data_loading(cfg):
+ """
+ Benchmark the speed of data loading in PySlowFast.
+ Args:
+
+ cfg (CfgNode): configs. Details can be found in
+ slowfast/config/defaults.py
+ """
+ # Set up environment.
+ setup_environment()
+ # Set random seed from configs.
+ np.random.seed(cfg.RNG_SEED)
+ torch.manual_seed(cfg.RNG_SEED)
+
+ # Setup logging format.
+ logging.setup_logging(cfg.OUTPUT_DIR)
+
+ # Print config.
+ logger.info("Benchmark data loading with config:")
+ logger.info(pprint.pformat(cfg))
+
+ timer = Timer()
+ dataloader = loader.construct_loader(cfg, "train")
+ logger.info(
+ "Initialize loader using {:.2f} seconds.".format(timer.seconds())
+ )
+ # Total batch size across different machines.
+ batch_size = cfg.TRAIN.BATCH_SIZE * cfg.NUM_SHARDS
+ log_period = cfg.BENCHMARK.LOG_PERIOD
+ epoch_times = []
+ # Test for a few epochs.
+ for cur_epoch in range(cfg.BENCHMARK.NUM_EPOCHS):
+ timer = Timer()
+ timer_epoch = Timer()
+ iter_times = []
+ if cfg.BENCHMARK.SHUFFLE:
+ loader.shuffle_dataset(dataloader, cur_epoch)
+ for cur_iter, _ in enumerate(tqdm.tqdm(dataloader)):
+ if cur_iter > 0 and cur_iter % log_period == 0:
+ iter_times.append(timer.seconds())
+ ram_usage, ram_total = misc.cpu_mem_usage()
+ logger.info(
+ "Epoch {}: {} iters ({} videos) in {:.2f} seconds. "
+ "RAM Usage: {:.2f}/{:.2f} GB.".format(
+ cur_epoch,
+ log_period,
+ log_period * batch_size,
+ iter_times[-1],
+ ram_usage,
+ ram_total,
+ )
+ )
+ timer.reset()
+ epoch_times.append(timer_epoch.seconds())
+ ram_usage, ram_total = misc.cpu_mem_usage()
+ logger.info(
+ "Epoch {}: in total {} iters ({} videos) in {:.2f} seconds. "
+ "RAM Usage: {:.2f}/{:.2f} GB.".format(
+ cur_epoch,
+ len(dataloader),
+ len(dataloader) * batch_size,
+ epoch_times[-1],
+ ram_usage,
+ ram_total,
+ )
+ )
+ logger.info(
+ "Epoch {}: on average every {} iters ({} videos) take {:.2f}/{:.2f} "
+ "(avg/std) seconds.".format(
+ cur_epoch,
+ log_period,
+ log_period * batch_size,
+ np.mean(iter_times),
+ np.std(iter_times),
+ )
+ )
+ logger.info(
+ "On average every epoch ({} videos) takes {:.2f}/{:.2f} "
+ "(avg/std) seconds.".format(
+ len(dataloader) * batch_size,
+ np.mean(epoch_times),
+ np.std(epoch_times),
+ )
+ )
diff --git a/clean/video/pwtf_dvd/inference/slowfast/utils/bn_helper.py b/clean/video/pwtf_dvd/inference/slowfast/utils/bn_helper.py
new file mode 100644
index 0000000000000000000000000000000000000000..b18d8c76c10d7598db61ba8ca192314140f9ba79
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/utils/bn_helper.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python3
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+
+"""bn helper."""
+
+import itertools
+import torch
+
+
+@torch.no_grad()
+def compute_and_update_bn_stats(model, data_loader, num_batches=200):
+ """
+ Compute and update the batch norm stats to make it more precise. During
+ training both bn stats and the weight are changing after every iteration,
+ so the bn can not precisely reflect the latest stats of the current model.
+ Here the bn stats is recomputed without change of weights, to make the
+ running mean and running var more precise.
+ Args:
+ model (model): the model using to compute and update the bn stats.
+ data_loader (dataloader): dataloader using to provide inputs.
+ num_batches (int): running iterations using to compute the stats.
+ """
+
+ # Prepares all the bn layers.
+ bn_layers = [
+ m
+ for m in model.modules()
+ if any(
+ (
+ isinstance(m, bn_type)
+ for bn_type in (
+ torch.nn.BatchNorm1d,
+ torch.nn.BatchNorm2d,
+ torch.nn.BatchNorm3d,
+ )
+ )
+ )
+ ]
+
+ # In order to make the running stats only reflect the current batch, the
+ # momentum is disabled.
+ # bn.running_mean = (1 - momentum) * bn.running_mean + momentum * batch_mean
+ # Setting the momentum to 1.0 to compute the stats without momentum.
+ momentum_actual = [bn.momentum for bn in bn_layers]
+ for bn in bn_layers:
+ bn.momentum = 1.0
+
+ # Calculates the running iterations for precise stats computation.
+ running_mean = [torch.zeros_like(bn.running_mean) for bn in bn_layers]
+ running_square_mean = [torch.zeros_like(bn.running_var) for bn in bn_layers]
+
+ for ind, (inputs, _, _) in enumerate(
+ itertools.islice(data_loader, num_batches)
+ ):
+ # Forwards the model to update the bn stats.
+ if isinstance(inputs, (list,)):
+ for i in range(len(inputs)):
+ inputs[i] = inputs[i].float().cuda(non_blocking=True)
+ else:
+ inputs = inputs.cuda(non_blocking=True)
+ model(inputs)
+
+ for i, bn in enumerate(bn_layers):
+ # Accumulates the bn stats.
+ running_mean[i] += (bn.running_mean - running_mean[i]) / (ind + 1)
+ # $E(x^2) = Var(x) + E(x)^2$.
+ cur_square_mean = bn.running_var + bn.running_mean ** 2
+ running_square_mean[i] += (
+ cur_square_mean - running_square_mean[i]
+ ) / (ind + 1)
+
+ for i, bn in enumerate(bn_layers):
+ bn.running_mean = running_mean[i]
+ # Var(x) = $E(x^2) - E(x)^2$.
+ bn.running_var = running_square_mean[i] - bn.running_mean ** 2
+ # Sets the precise bn stats.
+ bn.momentum = momentum_actual[i]
diff --git a/clean/video/pwtf_dvd/inference/slowfast/utils/c2_model_loading.py b/clean/video/pwtf_dvd/inference/slowfast/utils/c2_model_loading.py
new file mode 100644
index 0000000000000000000000000000000000000000..4bcc0759c484fd321917c55e9967835632c2ac54
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/utils/c2_model_loading.py
@@ -0,0 +1,112 @@
+#!/usr/bin/env python3
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+
+"""Caffe2 to PyTorch checkpoint name converting utility."""
+
+import re
+
+
+def get_name_convert_func():
+ """
+ Get the function to convert Caffe2 layer names to PyTorch layer names.
+ Returns:
+ (func): function to convert parameter name from Caffe2 format to PyTorch
+ format.
+ """
+ pairs = [
+ # ------------------------------------------------------------
+ # 'nonlocal_conv3_1_theta_w' -> 's3.pathway0_nonlocal3.conv_g.weight'
+ [
+ r"^nonlocal_conv([0-9]+)_([0-9]+)_(.*)",
+ r"s\1.pathway0_nonlocal\2_\3",
+ ],
+ # 'theta' -> 'conv_theta'
+ [r"^(.*)_nonlocal([0-9]+)_(theta)(.*)", r"\1_nonlocal\2.conv_\3\4"],
+ # 'g' -> 'conv_g'
+ [r"^(.*)_nonlocal([0-9]+)_(g)(.*)", r"\1_nonlocal\2.conv_\3\4"],
+ # 'phi' -> 'conv_phi'
+ [r"^(.*)_nonlocal([0-9]+)_(phi)(.*)", r"\1_nonlocal\2.conv_\3\4"],
+ # 'out' -> 'conv_out'
+ [r"^(.*)_nonlocal([0-9]+)_(out)(.*)", r"\1_nonlocal\2.conv_\3\4"],
+ # 'nonlocal_conv4_5_bn_s' -> 's4.pathway0_nonlocal3.bn.weight'
+ [r"^(.*)_nonlocal([0-9]+)_(bn)_(.*)", r"\1_nonlocal\2.\3.\4"],
+ # ------------------------------------------------------------
+ # 't_pool1_subsample_bn' -> 's1_fuse.conv_f2s.bn.running_mean'
+ [r"^t_pool1_subsample_bn_(.*)", r"s1_fuse.bn.\1"],
+ # 't_pool1_subsample' -> 's1_fuse.conv_f2s'
+ [r"^t_pool1_subsample_(.*)", r"s1_fuse.conv_f2s.\1"],
+ # 't_res4_5_branch2c_bn_subsample_bn_rm' -> 's4_fuse.conv_f2s.bias'
+ [
+ r"^t_res([0-9]+)_([0-9]+)_branch2c_bn_subsample_bn_(.*)",
+ r"s\1_fuse.bn.\3",
+ ],
+ # 't_pool1_subsample' -> 's1_fuse.conv_f2s'
+ [
+ r"^t_res([0-9]+)_([0-9]+)_branch2c_bn_subsample_(.*)",
+ r"s\1_fuse.conv_f2s.\3",
+ ],
+ # ------------------------------------------------------------
+ # 'res4_4_branch_2c_bn_b' -> 's4.pathway0_res4.branch2.c_bn_b'
+ [
+ r"^res([0-9]+)_([0-9]+)_branch([0-9]+)([a-z])_(.*)",
+ r"s\1.pathway0_res\2.branch\3.\4_\5",
+ ],
+ # 'res_conv1_bn_' -> 's1.pathway0_stem.bn.'
+ [r"^res_conv1_bn_(.*)", r"s1.pathway0_stem.bn.\1"],
+ # 'conv1_w_momentum' -> 's1.pathway0_stem.conv.'
+ [r"^conv1_(.*)", r"s1.pathway0_stem.conv.\1"],
+ # 'res4_0_branch1_w' -> 'S4.pathway0_res0.branch1.weight'
+ [
+ r"^res([0-9]+)_([0-9]+)_branch([0-9]+)_(.*)",
+ r"s\1.pathway0_res\2.branch\3_\4",
+ ],
+ # 'res_conv1_' -> 's1.pathway0_stem.conv.'
+ [r"^res_conv1_(.*)", r"s1.pathway0_stem.conv.\1"],
+ # ------------------------------------------------------------
+ # 'res4_4_branch_2c_bn_b' -> 's4.pathway0_res4.branch2.c_bn_b'
+ [
+ r"^t_res([0-9]+)_([0-9]+)_branch([0-9]+)([a-z])_(.*)",
+ r"s\1.pathway1_res\2.branch\3.\4_\5",
+ ],
+ # 'res_conv1_bn_' -> 's1.pathway0_stem.bn.'
+ [r"^t_res_conv1_bn_(.*)", r"s1.pathway1_stem.bn.\1"],
+ # 'conv1_w_momentum' -> 's1.pathway0_stem.conv.'
+ [r"^t_conv1_(.*)", r"s1.pathway1_stem.conv.\1"],
+ # 'res4_0_branch1_w' -> 'S4.pathway0_res0.branch1.weight'
+ [
+ r"^t_res([0-9]+)_([0-9]+)_branch([0-9]+)_(.*)",
+ r"s\1.pathway1_res\2.branch\3_\4",
+ ],
+ # 'res_conv1_' -> 's1.pathway0_stem.conv.'
+ [r"^t_res_conv1_(.*)", r"s1.pathway1_stem.conv.\1"],
+ # ------------------------------------------------------------
+ # pred_ -> head.projection.
+ [r"pred_(.*)", r"head.projection.\1"],
+ # '.bn_b' -> '.weight'
+ [r"(.*)bn.b\Z", r"\1bn.bias"],
+ # '.bn_s' -> '.weight'
+ [r"(.*)bn.s\Z", r"\1bn.weight"],
+ # '_bn_rm' -> '.running_mean'
+ [r"(.*)bn.rm\Z", r"\1bn.running_mean"],
+ # '_bn_riv' -> '.running_var'
+ [r"(.*)bn.riv\Z", r"\1bn.running_var"],
+ # '_b' -> '.bias'
+ [r"(.*)[\._]b\Z", r"\1.bias"],
+ # '_w' -> '.weight'
+ [r"(.*)[\._]w\Z", r"\1.weight"],
+ ]
+
+ def convert_caffe2_name_to_pytorch(caffe2_layer_name):
+ """
+ Convert the caffe2_layer_name to pytorch format by apply the list of
+ regular expressions.
+ Args:
+ caffe2_layer_name (str): caffe2 layer name.
+ Returns:
+ (str): pytorch layer name.
+ """
+ for source, dest in pairs:
+ caffe2_layer_name = re.sub(source, dest, caffe2_layer_name)
+ return caffe2_layer_name
+
+ return convert_caffe2_name_to_pytorch
diff --git a/clean/video/pwtf_dvd/inference/slowfast/utils/checkpoint.py b/clean/video/pwtf_dvd/inference/slowfast/utils/checkpoint.py
new file mode 100644
index 0000000000000000000000000000000000000000..05d5ac4624feecbbc1f868682f8ed921ac5fef2c
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/utils/checkpoint.py
@@ -0,0 +1,530 @@
+#!/usr/bin/env python3
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+
+"""Functions that handle saving and loading of checkpoints."""
+
+import copy
+import numpy as np
+import os
+import pickle
+from collections import OrderedDict
+import torch
+from fvcore.common.file_io import PathManager
+
+import slowfast.utils.distributed as du
+import slowfast.utils.logging as logging
+from slowfast.utils.c2_model_loading import get_name_convert_func
+
+logger = logging.get_logger(__name__)
+
+
+def make_checkpoint_dir(path_to_job):
+ """
+ Creates the checkpoint directory (if not present already).
+ Args:
+ path_to_job (string): the path to the folder of the current job.
+ """
+ checkpoint_dir = os.path.join(path_to_job, "checkpoints")
+ # Create the checkpoint dir from the master process
+ if du.is_master_proc() and not PathManager.exists(checkpoint_dir):
+ try:
+ PathManager.mkdirs(checkpoint_dir)
+ except Exception:
+ pass
+ return checkpoint_dir
+
+
+def get_checkpoint_dir(path_to_job):
+ """
+ Get path for storing checkpoints.
+ Args:
+ path_to_job (string): the path to the folder of the current job.
+ """
+ return os.path.join(path_to_job, "checkpoints")
+
+
+def get_path_to_checkpoint(path_to_job, epoch):
+ """
+ Get the full path to a checkpoint file.
+ Args:
+ path_to_job (string): the path to the folder of the current job.
+ epoch (int): the number of epoch for the checkpoint.
+ """
+ name = "checkpoint_epoch_{:07d}.pyth".format(epoch)
+ return os.path.join(get_checkpoint_dir(path_to_job), name)
+
+
+def get_last_checkpoint(path_to_job):
+ """
+ Get the last checkpoint from the checkpointing folder.
+ Args:
+ path_to_job (string): the path to the folder of the current job.
+ """
+
+ d = get_checkpoint_dir(path_to_job)
+ names = PathManager.ls(d) if PathManager.exists(d) else []
+ names = [f for f in names if "checkpoint" in f]
+ assert len(names), "No checkpoints found in '{}'.".format(d)
+ # Sort the checkpoints by epoch.
+ name = sorted(names)[-1]
+ return os.path.join(d, name)
+
+
+def has_checkpoint(path_to_job):
+ """
+ Determines if the given directory contains a checkpoint.
+ Args:
+ path_to_job (string): the path to the folder of the current job.
+ """
+ d = get_checkpoint_dir(path_to_job)
+ files = PathManager.ls(d) if PathManager.exists(d) else []
+ return any("checkpoint" in f for f in files)
+
+
+def is_checkpoint_epoch(cfg, cur_epoch, multigrid_schedule=None):
+ """
+ Determine if a checkpoint should be saved on current epoch.
+ Args:
+ cfg (CfgNode): configs to save.
+ cur_epoch (int): current number of epoch of the model.
+ multigrid_schedule (List): schedule for multigrid training.
+ """
+ if cur_epoch + 1 == cfg.SOLVER.MAX_EPOCH:
+ return True
+ if multigrid_schedule is not None:
+ prev_epoch = 0
+ for s in multigrid_schedule:
+ if cur_epoch < s[-1]:
+ period = max(
+ (s[-1] - prev_epoch) // cfg.MULTIGRID.EVAL_FREQ + 1, 1
+ )
+ return (s[-1] - 1 - cur_epoch) % period == 0
+ prev_epoch = s[-1]
+
+ return (cur_epoch + 1) % cfg.TRAIN.CHECKPOINT_PERIOD == 0
+
+
+def is_checkpoint_iter(cfg, cur_iter):
+ """
+ Determine if a checkpoint should be saved on current iter.
+ Args:
+ cfg (CfgNode): configs to save.
+ cur_epoch (int): current number of epoch of the model.
+ multigrid_schedule (List): schedule for multigrid training.
+ """
+
+ return (cur_iter+1) % cfg.TRAIN.CHECKPOINT_PERIOD_BY_ITER == 0
+
+
+
+def save_checkpoint_by_iter(path_to_job, model, optimizer, epoch,global_step,cfg):
+ """
+ Save a checkpoint.
+ Args:
+ model (model): model to save the weight to the checkpoint.
+ optimizer (optim): optimizer to save the historical state.
+ epoch (int): current number of epoch of the model.
+ cfg (CfgNode): configs to save.
+ """
+ # Save checkpoints only from the master process.
+ if not du.is_master_proc(cfg.NUM_GPUS * cfg.NUM_SHARDS):
+ return
+ # Ensure that the checkpoint dir exists.
+ PathManager.mkdirs(get_checkpoint_dir(path_to_job))
+ # Omit the DDP wrapper in the multi-gpu setting.
+ sd = model.module.state_dict() if cfg.NUM_GPUS > 1 else model.state_dict()
+ normalized_sd = sub_to_normal_bn(sd)
+
+ # Record the state.
+ checkpoint = {
+ "epoch": epoch,
+ "model_state": normalized_sd,
+ "optimizer_state": optimizer.state_dict(),
+ "global_step": global_step,
+ "cfg": cfg.dump(),
+ }
+ # Write the checkpoint.
+ path_to_checkpoint = get_path_to_checkpoint(path_to_job,global_step+1)
+ with PathManager.open(path_to_checkpoint, "wb") as f:
+ torch.save(checkpoint, f)
+ return path_to_checkpoint
+
+def save_checkpoint(path_to_job, model, optimizer, epoch, cfg):
+ """
+ Save a checkpoint.
+ Args:
+ model (model): model to save the weight to the checkpoint.
+ optimizer (optim): optimizer to save the historical state.
+ epoch (int): current number of epoch of the model.
+ cfg (CfgNode): configs to save.
+ """
+ # Save checkpoints only from the master process.
+ if not du.is_master_proc(cfg.NUM_GPUS * cfg.NUM_SHARDS):
+ return
+ # Ensure that the checkpoint dir exists.
+ PathManager.mkdirs(get_checkpoint_dir(path_to_job))
+ # Omit the DDP wrapper in the multi-gpu setting.
+ sd = model.module.state_dict() if cfg.NUM_GPUS > 1 else model.state_dict()
+ normalized_sd = sub_to_normal_bn(sd)
+
+ # Record the state.
+ checkpoint = {
+ "epoch": epoch,
+ "model_state": normalized_sd,
+ "optimizer_state": optimizer.state_dict(),
+ "cfg": cfg.dump(),
+ }
+ # Write the checkpoint.
+ path_to_checkpoint = get_path_to_checkpoint(path_to_job, epoch + 1)
+ with PathManager.open(path_to_checkpoint, "wb") as f:
+ torch.save(checkpoint, f)
+ return path_to_checkpoint
+
+
+def inflate_weight(state_dict_2d, state_dict_3d):
+ """
+ Inflate 2D model weights in state_dict_2d to the 3D model weights in
+ state_dict_3d. The details can be found in:
+ Joao Carreira, and Andrew Zisserman.
+ "Quo vadis, action recognition? a new model and the kinetics dataset."
+ Args:
+ state_dict_2d (OrderedDict): a dict of parameters from a 2D model.
+ state_dict_3d (OrderedDict): a dict of parameters from a 3D model.
+ Returns:
+ state_dict_inflated (OrderedDict): a dict of inflated parameters.
+ """
+ state_dict_inflated = OrderedDict()
+ for k, v2d in state_dict_2d.items():
+ assert k in state_dict_3d.keys()
+ v3d = state_dict_3d[k]
+ # Inflate the weight of 2D conv to 3D conv.
+ if len(v2d.shape) == 4 and len(v3d.shape) == 5:
+ logger.info(
+ "Inflate {}: {} -> {}: {}".format(k, v2d.shape, k, v3d.shape)
+ )
+ # Dimension need to be match.
+ assert v2d.shape[-2:] == v3d.shape[-2:]
+ assert v2d.shape[:2] == v3d.shape[:2]
+ v3d = (
+ v2d.unsqueeze(2).repeat(1, 1, v3d.shape[2], 1, 1) / v3d.shape[2]
+ )
+ elif v2d.shape == v3d.shape:
+ v3d = v2d
+ else:
+ logger.info(
+ "Unexpected {}: {} -|> {}: {}".format(
+ k, v2d.shape, k, v3d.shape
+ )
+ )
+ state_dict_inflated[k] = v3d.clone()
+ return state_dict_inflated
+
+
+def load_checkpoint(
+ path_to_checkpoint,
+ model,
+ data_parallel=True,
+ optimizer=None,
+ inflation=False,
+ convert_from_caffe2=False,
+):
+ """
+ Load the checkpoint from the given file. If inflation is True, inflate the
+ 2D Conv weights from the checkpoint to 3D Conv.
+ Args:
+ path_to_checkpoint (string): path to the checkpoint to load.
+ model (model): model to load the weights from the checkpoint.
+ data_parallel (bool): if true, model is wrapped by
+ torch.nn.parallel.DistributedDataParallel.
+ optimizer (optim): optimizer to load the historical state.
+ inflation (bool): if True, inflate the weights from the checkpoint.
+ convert_from_caffe2 (bool): if True, load the model from caffe2 and
+ convert it to pytorch.
+ Returns:
+ (int): the number of training epoch of the checkpoint.
+ """
+ assert PathManager.exists(
+ path_to_checkpoint
+ ), "Checkpoint '{}' not found".format(path_to_checkpoint)
+ # Account for the DDP wrapper in the multi-gpu setting.
+ ms = model.module if data_parallel else model
+ if convert_from_caffe2:
+ with PathManager.open(path_to_checkpoint, "rb") as f:
+ caffe2_checkpoint = pickle.load(f, encoding="latin1")
+ state_dict = OrderedDict()
+ name_convert_func = get_name_convert_func()
+ for key in caffe2_checkpoint["blobs"].keys():
+ converted_key = name_convert_func(key)
+ converted_key = c2_normal_to_sub_bn(converted_key, ms.state_dict())
+ if converted_key in ms.state_dict():
+ c2_blob_shape = caffe2_checkpoint["blobs"][key].shape
+ model_blob_shape = ms.state_dict()[converted_key].shape
+ # Load BN stats to Sub-BN.
+ if (
+ len(model_blob_shape) == 1
+ and len(c2_blob_shape) == 1
+ and model_blob_shape[0] > c2_blob_shape[0]
+ and model_blob_shape[0] % c2_blob_shape[0] == 0
+ ):
+ caffe2_checkpoint["blobs"][key] = np.concatenate(
+ [caffe2_checkpoint["blobs"][key]]
+ * (model_blob_shape[0] // c2_blob_shape[0])
+ )
+ c2_blob_shape = caffe2_checkpoint["blobs"][key].shape
+
+ if c2_blob_shape == tuple(model_blob_shape):
+ state_dict[converted_key] = torch.tensor(
+ caffe2_checkpoint["blobs"][key]
+ ).clone()
+ logger.info(
+ "{}: {} => {}: {}".format(
+ key,
+ c2_blob_shape,
+ converted_key,
+ tuple(model_blob_shape),
+ )
+ )
+ else:
+ logger.warn(
+ "!! {}: {} does not match {}: {}".format(
+ key,
+ c2_blob_shape,
+ converted_key,
+ tuple(model_blob_shape),
+ )
+ )
+ else:
+ if not any(
+ prefix in key for prefix in ["momentum", "lr", "model_iter"]
+ ):
+ logger.warn(
+ "!! {}: can not be converted, got {}".format(
+ key, converted_key
+ )
+ )
+ ms.load_state_dict(state_dict, strict=False)
+ epoch = -1
+ global_step=-1
+ else:
+ # Load the checkpoint on CPU to avoid GPU mem spike.
+ with PathManager.open(path_to_checkpoint, "rb") as f:
+ checkpoint = torch.load(f, map_location="cpu")
+ model_state_dict_3d = (
+ model.module.state_dict() if data_parallel else model.state_dict()
+ )
+ checkpoint["model_state"] = normal_to_sub_bn(
+ checkpoint["model_state"], model_state_dict_3d
+ )
+ if inflation:
+ # Try to inflate the model.
+ inflated_model_dict = inflate_weight(
+ checkpoint["model_state"], model_state_dict_3d
+ )
+ ms.load_state_dict(inflated_model_dict, strict=False)
+ else:
+ ms.load_state_dict(checkpoint["model_state"])
+ # Load the optimizer state (commonly not done when fine-tuning)
+ if optimizer:
+ optimizer.load_state_dict(checkpoint["optimizer_state"])
+ if "epoch" in checkpoint.keys():
+ epoch = checkpoint["epoch"]
+ else:
+ epoch = -1
+ if "global_step" in checkpoint.keys():
+ global_step=checkpoint["global_step"]
+ else:
+ global_step=-1
+ return epoch,global_step
+
+
+def sub_to_normal_bn(sd):
+ """
+ Convert the Sub-BN paprameters to normal BN parameters in a state dict.
+ There are two copies of BN layers in a Sub-BN implementation: `bn.bn` and
+ `bn.split_bn`. `bn.split_bn` is used during training and
+ "compute_precise_bn". Before saving or evaluation, its stats are copied to
+ `bn.bn`. We rename `bn.bn` to `bn` and store it to be consistent with normal
+ BN layers.
+ Args:
+ sd (OrderedDict): a dict of parameters whitch might contain Sub-BN
+ parameters.
+ Returns:
+ new_sd (OrderedDict): a dict with Sub-BN parameters reshaped to
+ normal parameters.
+ """
+ new_sd = copy.deepcopy(sd)
+ modifications = [
+ ("bn.bn.running_mean", "bn.running_mean"),
+ ("bn.bn.running_var", "bn.running_var"),
+ ("bn.split_bn.num_batches_tracked", "bn.num_batches_tracked"),
+ ]
+ to_remove = ["bn.bn.", ".split_bn."]
+ for key in sd:
+ for before, after in modifications:
+ if key.endswith(before):
+ new_key = key.split(before)[0] + after
+ new_sd[new_key] = new_sd.pop(key)
+
+ for rm in to_remove:
+ if rm in key and key in new_sd:
+ del new_sd[key]
+
+ for key in new_sd:
+ if key.endswith("bn.weight") or key.endswith("bn.bias"):
+ if len(new_sd[key].size()) == 4:
+ assert all(d == 1 for d in new_sd[key].size()[1:])
+ new_sd[key] = new_sd[key][:, 0, 0, 0]
+
+ return new_sd
+
+
+def c2_normal_to_sub_bn(key, model_keys):
+ """
+ Convert BN parameters to Sub-BN parameters if model contains Sub-BNs.
+ Args:
+ key (OrderedDict): source dict of parameters.
+ mdoel_key (OrderedDict): target dict of parameters.
+ Returns:
+ new_sd (OrderedDict): converted dict of parameters.
+ """
+ if "bn.running_" in key:
+ if key in model_keys:
+ return key
+
+ new_key = key.replace("bn.running_", "bn.split_bn.running_")
+ if new_key in model_keys:
+ return new_key
+ else:
+ return key
+
+
+def normal_to_sub_bn(checkpoint_sd, model_sd):
+ """
+ Convert BN parameters to Sub-BN parameters if model contains Sub-BNs.
+ Args:
+ checkpoint_sd (OrderedDict): source dict of parameters.
+ model_sd (OrderedDict): target dict of parameters.
+ Returns:
+ new_sd (OrderedDict): converted dict of parameters.
+ """
+ for key in model_sd:
+ if key not in checkpoint_sd:
+ if "bn.split_bn." in key:
+ load_key = key.replace("bn.split_bn.", "bn.")
+ bn_key = key.replace("bn.split_bn.", "bn.bn.")
+ checkpoint_sd[key] = checkpoint_sd.pop(load_key)
+ checkpoint_sd[bn_key] = checkpoint_sd[key]
+
+ for key in model_sd:
+ if key in checkpoint_sd:
+ model_blob_shape = model_sd[key].shape
+ c2_blob_shape = checkpoint_sd[key].shape
+
+ if (
+ len(model_blob_shape) == 1
+ and len(c2_blob_shape) == 1
+ and model_blob_shape[0] > c2_blob_shape[0]
+ and model_blob_shape[0] % c2_blob_shape[0] == 0
+ ):
+ before_shape = checkpoint_sd[key].shape
+ checkpoint_sd[key] = torch.cat(
+ [checkpoint_sd[key]]
+ * (model_blob_shape[0] // c2_blob_shape[0])
+ )
+ logger.info(
+ "{} {} -> {}".format(
+ key, before_shape, checkpoint_sd[key].shape
+ )
+ )
+ return checkpoint_sd
+
+
+def load_test_checkpoint(cfg, model):
+ """
+ Loading checkpoint logic for testing.
+ """
+ # Load a checkpoint to test if applicable.
+ if cfg.TEST.CHECKPOINT_FILE_PATH != "":
+ # If no checkpoint found in MODEL_VIS.CHECKPOINT_FILE_PATH or in the current
+ # checkpoint folder, try to load checkpoint from
+ # TEST.CHECKPOINT_FILE_PATH and test it.
+ load_checkpoint(
+ cfg.TEST.CHECKPOINT_FILE_PATH,
+ model,
+ cfg.NUM_GPUS > 1,
+ None,
+ inflation=False,
+ convert_from_caffe2=cfg.TEST.CHECKPOINT_TYPE == "caffe2",
+ )
+ elif has_checkpoint(cfg.OUTPUT_DIR):
+ last_checkpoint = get_last_checkpoint(cfg.OUTPUT_DIR)
+ load_checkpoint(last_checkpoint, model, cfg.NUM_GPUS > 1)
+ elif cfg.TRAIN.CHECKPOINT_FILE_PATH != "":
+ # If no checkpoint found in TEST.CHECKPOINT_FILE_PATH or in the current
+ # checkpoint folder, try to load checkpoint from
+ # TRAIN.CHECKPOINT_FILE_PATH and test it.
+ load_checkpoint(
+ cfg.TRAIN.CHECKPOINT_FILE_PATH,
+ model,
+ cfg.NUM_GPUS > 1,
+ None,
+ inflation=False,
+ convert_from_caffe2=cfg.TRAIN.CHECKPOINT_TYPE == "caffe2",
+ )
+ else:
+ logger.info(
+ "Unknown way of loading checkpoint. Using with random initialization, only for debugging."
+ )
+
+
+def load_train_checkpoint(cfg, model, optimizer):
+ """
+ Loading checkpoint logic for training.
+ """
+ if cfg.TRAIN.AUTO_RESUME and has_checkpoint(cfg.OUTPUT_DIR):
+ last_checkpoint = get_last_checkpoint(cfg.OUTPUT_DIR)
+ logger.info("Load from last checkpoint, {}.".format(last_checkpoint))
+ checkpoint_epoch,global_step = load_checkpoint(
+ last_checkpoint, model, cfg.NUM_GPUS > 1, optimizer
+ )
+ start_epoch = checkpoint_epoch + 1
+ global_step = global_step + 1
+ elif cfg.TRAIN.CHECKPOINT_FILE_PATH != "":
+ if cfg.TRAIN.CHECKPOINT_TYPE=="backbone":
+ logger.info("Load backbone from given checkpoint file.")
+ load_backbone(model,cfg.TRAIN.CHECKPOINT_FILE_PATH)
+ start_epoch = 0
+ global_step = 0
+ else:
+ logger.info("Load from given checkpoint file.")
+ checkpoint_epoch, global_step = load_checkpoint(
+ cfg.TRAIN.CHECKPOINT_FILE_PATH,
+ model,
+ cfg.NUM_GPUS > 1,
+ optimizer,
+ inflation=cfg.TRAIN.CHECKPOINT_INFLATE,
+ convert_from_caffe2=cfg.TRAIN.CHECKPOINT_TYPE == "caffe2",
+ )
+ start_epoch = checkpoint_epoch + 1
+ global_step = global_step + 1
+ else:
+ start_epoch = 0
+ global_step = 0
+
+ return start_epoch, global_step
+
+
+
+def load_backbone(model,file):
+ current_state=model.state_dict()
+ checkpoint=torch.load(file)
+
+ for key in checkpoint:
+ if key in current_state:
+ assert current_state[key].shape==checkpoint[key].shape
+ current_state[key]=checkpoint[key]
+ model.load_state_dict(current_state)
+
+ return model
+
+
diff --git a/clean/video/pwtf_dvd/inference/slowfast/utils/distributed.py b/clean/video/pwtf_dvd/inference/slowfast/utils/distributed.py
new file mode 100644
index 0000000000000000000000000000000000000000..bfbed8e8a4af5fc4b38c1558616fd3f640b587c0
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/utils/distributed.py
@@ -0,0 +1,299 @@
+#!/usr/bin/env python3
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+
+"""Distributed helpers."""
+
+import functools
+import logging
+import pickle
+import torch
+import torch.distributed as dist
+
+_LOCAL_PROCESS_GROUP = None
+
+
+def all_gather(tensors):
+ """
+ All gathers the provided tensors from all processes across machines.
+ Args:
+ tensors (list): tensors to perform all gather across all processes in
+ all machines.
+ """
+
+ gather_list = []
+ output_tensor = []
+ world_size = dist.get_world_size()
+ for tensor in tensors:
+ tensor_placeholder = [
+ torch.ones_like(tensor) for _ in range(world_size)
+ ]
+ dist.all_gather(tensor_placeholder, tensor, async_op=False)
+ gather_list.append(tensor_placeholder)
+ for gathered_tensor in gather_list:
+ output_tensor.append(torch.cat(gathered_tensor, dim=0))
+ return output_tensor
+
+
+def all_reduce(tensors, average=True):
+ """
+ All reduce the provided tensors from all processes across machines.
+ Args:
+ tensors (list): tensors to perform all reduce across all processes in
+ all machines.
+ average (bool): scales the reduced tensor by the number of overall
+ processes across all machines.
+ """
+
+ for tensor in tensors:
+ dist.all_reduce(tensor, async_op=False)
+ if average:
+ world_size = dist.get_world_size()
+ for tensor in tensors:
+ tensor.mul_(1.0 / world_size)
+ return tensors
+
+
+def init_process_group(
+ local_rank,
+ local_world_size,
+ shard_id,
+ num_shards,
+ init_method,
+ dist_backend="nccl",
+):
+ """
+ Initializes the default process group.
+ Args:
+ local_rank (int): the rank on the current local machine.
+ local_world_size (int): the world size (number of processes running) on
+ the current local machine.
+ shard_id (int): the shard index (machine rank) of the current machine.
+ num_shards (int): number of shards for distributed training.
+ init_method (string): supporting three different methods for
+ initializing process groups:
+ "file": use shared file system to initialize the groups across
+ different processes.
+ "tcp": use tcp address to initialize the groups across different
+ dist_backend (string): backend to use for distributed training. Options
+ includes gloo, mpi and nccl, the details can be found here:
+ https://pytorch.org/docs/stable/distributed.html
+ """
+ # Sets the GPU to use.
+ torch.cuda.set_device(local_rank)
+ # Initialize the process group.
+ proc_rank = local_rank + shard_id * local_world_size
+ world_size = local_world_size * num_shards
+ dist.init_process_group(
+ backend=dist_backend,
+ init_method=init_method,
+ world_size=world_size,
+ rank=proc_rank,
+ )
+
+
+def is_master_proc(num_gpus=8):
+ """
+ Determines if the current process is the master process.
+ """
+ if torch.distributed.is_initialized():
+ return dist.get_rank() % num_gpus == 0
+ else:
+ return True
+
+
+def get_world_size():
+ """
+ Get the size of the world.
+ """
+ if not dist.is_available():
+ return 1
+ if not dist.is_initialized():
+ return 1
+ return dist.get_world_size()
+
+
+def get_rank():
+ """
+ Get the rank of the current process.
+ """
+ if not dist.is_available():
+ return 0
+ if not dist.is_initialized():
+ return 0
+ return dist.get_rank()
+
+
+def synchronize():
+ """
+ Helper function to synchronize (barrier) among all processes when
+ using distributed training
+ """
+ if not dist.is_available():
+ return
+ if not dist.is_initialized():
+ return
+ world_size = dist.get_world_size()
+ if world_size == 1:
+ return
+ dist.barrier()
+
+
+@functools.lru_cache()
+def _get_global_gloo_group():
+ """
+ Return a process group based on gloo backend, containing all the ranks
+ The result is cached.
+ Returns:
+ (group): pytorch dist group.
+ """
+ if dist.get_backend() == "nccl":
+ return dist.new_group(backend="gloo")
+ else:
+ return dist.group.WORLD
+
+
+def _serialize_to_tensor(data, group):
+ """
+ Seriialize the tensor to ByteTensor. Note that only `gloo` and `nccl`
+ backend is supported.
+ Args:
+ data (data): data to be serialized.
+ group (group): pytorch dist group.
+ Returns:
+ tensor (ByteTensor): tensor that serialized.
+ """
+
+ backend = dist.get_backend(group)
+ assert backend in ["gloo", "nccl"]
+ device = torch.device("cpu" if backend == "gloo" else "cuda")
+
+ buffer = pickle.dumps(data)
+ if len(buffer) > 1024 ** 3:
+ logger = logging.getLogger(__name__)
+ logger.warning(
+ "Rank {} trying to all-gather {:.2f} GB of data on device {}".format(
+ get_rank(), len(buffer) / (1024 ** 3), device
+ )
+ )
+ storage = torch.ByteStorage.from_buffer(buffer)
+ tensor = torch.ByteTensor(storage).to(device=device)
+ return tensor
+
+
+def _pad_to_largest_tensor(tensor, group):
+ """
+ Padding all the tensors from different GPUs to the largest ones.
+ Args:
+ tensor (tensor): tensor to pad.
+ group (group): pytorch dist group.
+ Returns:
+ list[int]: size of the tensor, on each rank
+ Tensor: padded tensor that has the max size
+ """
+ world_size = dist.get_world_size(group=group)
+ assert (
+ world_size >= 1
+ ), "comm.gather/all_gather must be called from ranks within the given group!"
+ local_size = torch.tensor(
+ [tensor.numel()], dtype=torch.int64, device=tensor.device
+ )
+ size_list = [
+ torch.zeros([1], dtype=torch.int64, device=tensor.device)
+ for _ in range(world_size)
+ ]
+ dist.all_gather(size_list, local_size, group=group)
+ size_list = [int(size.item()) for size in size_list]
+
+ max_size = max(size_list)
+
+ # we pad the tensor because torch all_gather does not support
+ # gathering tensors of different shapes
+ if local_size != max_size:
+ padding = torch.zeros(
+ (max_size - local_size,), dtype=torch.uint8, device=tensor.device
+ )
+ tensor = torch.cat((tensor, padding), dim=0)
+ return size_list, tensor
+
+
+def all_gather_unaligned(data, group=None):
+ """
+ Run all_gather on arbitrary picklable data (not necessarily tensors).
+
+ Args:
+ data: any picklable object
+ group: a torch process group. By default, will use a group which
+ contains all ranks on gloo backend.
+
+ Returns:
+ list[data]: list of data gathered from each rank
+ """
+ if get_world_size() == 1:
+ return [data]
+ if group is None:
+ group = _get_global_gloo_group()
+ if dist.get_world_size(group) == 1:
+ return [data]
+
+ tensor = _serialize_to_tensor(data, group)
+
+ size_list, tensor = _pad_to_largest_tensor(tensor, group)
+ max_size = max(size_list)
+
+ # receiving Tensor from all ranks
+ tensor_list = [
+ torch.empty((max_size,), dtype=torch.uint8, device=tensor.device)
+ for _ in size_list
+ ]
+ dist.all_gather(tensor_list, tensor, group=group)
+
+ data_list = []
+ for size, tensor in zip(size_list, tensor_list):
+ buffer = tensor.cpu().numpy().tobytes()[:size]
+ data_list.append(pickle.loads(buffer))
+
+ return data_list
+
+
+def init_distributed_training(cfg):
+ """
+ Initialize variables needed for distributed training.
+ """
+ if cfg.NUM_GPUS <= 1:
+ return
+ num_gpus_per_machine = cfg.NUM_GPUS
+ num_machines = dist.get_world_size() // num_gpus_per_machine
+ for i in range(num_machines):
+ ranks_on_i = list(
+ range(i * num_gpus_per_machine, (i + 1) * num_gpus_per_machine)
+ )
+ pg = dist.new_group(ranks_on_i)
+ if i == cfg.SHARD_ID:
+ global _LOCAL_PROCESS_GROUP
+ _LOCAL_PROCESS_GROUP = pg
+
+
+def get_local_size() -> int:
+ """
+ Returns:
+ The size of the per-machine process group,
+ i.e. the number of processes per machine.
+ """
+ if not dist.is_available():
+ return 1
+ if not dist.is_initialized():
+ return 1
+ return dist.get_world_size(group=_LOCAL_PROCESS_GROUP)
+
+
+def get_local_rank() -> int:
+ """
+ Returns:
+ The rank of the current process within the local (per-machine) process group.
+ """
+ if not dist.is_available():
+ return 0
+ if not dist.is_initialized():
+ return 0
+ assert _LOCAL_PROCESS_GROUP is not None
+ return dist.get_rank(group=_LOCAL_PROCESS_GROUP)
diff --git a/clean/video/pwtf_dvd/inference/slowfast/utils/env.py b/clean/video/pwtf_dvd/inference/slowfast/utils/env.py
new file mode 100644
index 0000000000000000000000000000000000000000..2554915089a6e20c9ce58bba7fa59136ed65c887
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/utils/env.py
@@ -0,0 +1,15 @@
+#!/usr/bin/env python3
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+
+"""Set up Environment."""
+
+import slowfast.utils.logging as logging
+
+_ENV_SETUP_DONE = False
+
+
+def setup_environment():
+ global _ENV_SETUP_DONE
+ if _ENV_SETUP_DONE:
+ return
+ _ENV_SETUP_DONE = True
diff --git a/clean/video/pwtf_dvd/inference/slowfast/utils/logging.py b/clean/video/pwtf_dvd/inference/slowfast/utils/logging.py
new file mode 100644
index 0000000000000000000000000000000000000000..f2763b3000c9be4a5499b310a3bc052fd5472d50
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/utils/logging.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python3
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+
+"""Logging."""
+
+import builtins
+import decimal
+import functools
+import logging
+import os
+import sys
+import simplejson
+from fvcore.common.file_io import PathManager
+
+import slowfast.utils.distributed as du
+
+
+def _suppress_print():
+ """
+ Suppresses printing from the current process.
+ """
+
+ def print_pass(*objects, sep=" ", end="\n", file=sys.stdout, flush=False):
+ pass
+
+ builtins.print = print_pass
+
+
+@functools.lru_cache(maxsize=None)
+def _cached_log_stream(filename):
+ return PathManager.open(filename, "a")
+
+
+def setup_logging(output_dir=None):
+ """
+ Sets up the logging for multiple processes. Only enable the logging for the
+ master process, and suppress logging for the non-master processes.
+ """
+ # Set up logging format.
+ _FORMAT = "[%(levelname)s: %(filename)s: %(lineno)4d]: %(message)s"
+
+ if du.is_master_proc():
+ # Enable logging for the master process.
+ logging.root.handlers = []
+ else:
+ # Suppress logging for non-master processes.
+ _suppress_print()
+
+ logger = logging.getLogger()
+ logger.setLevel(logging.DEBUG)
+ logger.propagate = False
+ plain_formatter = logging.Formatter(
+ "[%(asctime)s][%(levelname)s] %(name)s: %(lineno)4d: %(message)s",
+ datefmt="%m/%d %H:%M:%S",
+ )
+
+ if du.is_master_proc():
+ ch = logging.StreamHandler(stream=sys.stdout)
+ ch.setLevel(logging.DEBUG)
+ ch.setFormatter(plain_formatter)
+ logger.addHandler(ch)
+
+ if output_dir is not None and du.is_master_proc(du.get_world_size()):
+ filename = os.path.join(output_dir, "stdout.log")
+ fh = logging.StreamHandler(_cached_log_stream(filename))
+ fh.setLevel(logging.DEBUG)
+ fh.setFormatter(plain_formatter)
+ logger.addHandler(fh)
+
+
+def get_logger(name):
+ """
+ Retrieve the logger with the specified name or, if name is None, return a
+ logger which is the root logger of the hierarchy.
+ Args:
+ name (string): name of the logger.
+ """
+ return logging.getLogger(name)
+
+
+def log_json_stats(stats):
+ """
+ Logs json stats.
+ Args:
+ stats (dict): a dictionary of statistical information to log.
+ """
+ stats = {
+ k: decimal.Decimal("{:.6f}".format(v)) if isinstance(v, float) else v
+ for k, v in stats.items()
+ }
+ json_stats = simplejson.dumps(stats, sort_keys=True, use_decimal=True)
+ logger = get_logger(__name__)
+ logger.info("json_stats: {:s}".format(json_stats))
diff --git a/clean/video/pwtf_dvd/inference/slowfast/utils/lr_policy.py b/clean/video/pwtf_dvd/inference/slowfast/utils/lr_policy.py
new file mode 100644
index 0000000000000000000000000000000000000000..4c67f8e5d9d6d576928986521dbe2eac8b1ca7e5
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/utils/lr_policy.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python3
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+
+"""Learning rate policy."""
+
+import math
+
+
+def get_lr_at_epoch(cfg, cur_epoch):
+ """
+ Retrieve the learning rate of the current epoch with the option to perform
+ warm up in the beginning of the training stage.
+ Args:
+ cfg (CfgNode): configs. Details can be found in
+ slowfast/config/defaults.py
+ cur_epoch (float): the number of epoch of the current training stage.
+ """
+ lr = get_lr_func(cfg.SOLVER.LR_POLICY)(cfg, cur_epoch)
+ # Perform warm up.
+ if cur_epoch < cfg.SOLVER.WARMUP_EPOCHS:
+ lr_start = cfg.SOLVER.WARMUP_START_LR
+ lr_end = get_lr_func(cfg.SOLVER.LR_POLICY)(
+ cfg, cfg.SOLVER.WARMUP_EPOCHS
+ )
+ alpha = (lr_end - lr_start) / cfg.SOLVER.WARMUP_EPOCHS
+ lr = cur_epoch * alpha + lr_start
+ return lr
+
+def get_lr_at_iter(cfg,cur_iter):
+ """LR schedule that should yield 76% converged accuracy with batch size 256"""
+ start_step = cfg.SOLVER.TOTAL_STEP- cfg.SOLVER.LR_STEP
+ duration_step = cfg.SOLVER.LR_STEP
+ base_lr=float(cfg.SOLVER.BASE_LR)
+ if cur_iter <= start_step:
+ return base_lr
+ else:
+ this_step = cur_iter - start_step
+ lr = base_lr * ((this_step / duration_step) ** 2.0)
+ return lr
+
+
+def lr_func_cosine(cfg, cur_epoch):
+ """
+ Retrieve the learning rate to specified values at specified epoch with the
+ cosine learning rate schedule. Details can be found in:
+ Ilya Loshchilov, and Frank Hutter
+ SGDR: Stochastic Gradient Descent With Warm Restarts.
+ Args:
+ cfg (CfgNode): configs. Details can be found in
+ slowfast/config/defaults.py
+ cur_epoch (float): the number of epoch of the current training stage.
+ """
+ return (
+ cfg.SOLVER.BASE_LR
+ * (math.cos(math.pi * cur_epoch / cfg.SOLVER.MAX_EPOCH) + 1.0)
+ * 0.5
+ )
+
+
+def lr_func_steps_with_relative_lrs(cfg, cur_epoch):
+ """
+ Retrieve the learning rate to specified values at specified epoch with the
+ steps with relative learning rate schedule.
+ Args:
+ cfg (CfgNode): configs. Details can be found in
+ slowfast/config/defaults.py
+ cur_epoch (float): the number of epoch of the current training stage.
+ """
+ ind = get_step_index(cfg, cur_epoch)
+ return cfg.SOLVER.LRS[ind] * cfg.SOLVER.BASE_LR
+
+
+def get_step_index(cfg, cur_epoch):
+ """
+ Retrieves the lr step index for the given epoch.
+ Args:
+ cfg (CfgNode): configs. Details can be found in
+ slowfast/config/defaults.py
+ cur_epoch (float): the number of epoch of the current training stage.
+ """
+ steps = cfg.SOLVER.STEPS + [cfg.SOLVER.MAX_EPOCH]
+ for ind, step in enumerate(steps): # NoQA
+ if cur_epoch < step:
+ break
+ return ind - 1
+
+
+def get_lr_func(lr_policy):
+ """
+ Given the configs, retrieve the specified lr policy function.
+ Args:
+ lr_policy (string): the learning rate policy to use for the job.
+ """
+ policy = "lr_func_" + lr_policy
+ if policy not in globals():
+ raise NotImplementedError("Unknown LR policy: {}".format(lr_policy))
+ else:
+ return globals()[policy]
diff --git a/clean/video/pwtf_dvd/inference/slowfast/utils/meters.py b/clean/video/pwtf_dvd/inference/slowfast/utils/meters.py
new file mode 100644
index 0000000000000000000000000000000000000000..2c4e9582a2bb5f6685987ce1f0ce391ac3950419
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/utils/meters.py
@@ -0,0 +1,841 @@
+#!/usr/bin/env python3
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+
+"""Meters."""
+
+import datetime
+import numpy as np
+import os
+from collections import defaultdict, deque
+import torch
+from fvcore.common.timer import Timer
+from sklearn.metrics import average_precision_score
+
+import slowfast.datasets.ava_helper as ava_helper
+import slowfast.utils.logging as logging
+import slowfast.utils.metrics as metrics
+import slowfast.utils.misc as misc
+from slowfast.utils.ava_eval_helper import (
+ evaluate_ava,
+ read_csv,
+ read_exclusions,
+ read_labelmap,
+)
+
+logger = logging.get_logger(__name__)
+
+
+def get_ava_mini_groundtruth(full_groundtruth):
+ """
+ Get the groundtruth annotations corresponding the "subset" of AVA val set.
+ We define the subset to be the frames such that (second % 4 == 0).
+ We optionally use subset for faster evaluation during training
+ (in order to track training progress).
+ Args:
+ full_groundtruth(dict): list of groundtruth.
+ """
+ ret = [defaultdict(list), defaultdict(list), defaultdict(list)]
+
+ for i in range(3):
+ for key in full_groundtruth[i].keys():
+ if int(key.split(",")[1]) % 4 == 0:
+ ret[i][key] = full_groundtruth[i][key]
+ return ret
+
+
+class AVAMeter(object):
+ """
+ Measure the AVA train, val, and test stats.
+ """
+
+ def __init__(self, overall_iters, cfg, mode):
+ """
+ overall_iters (int): the overall number of iterations of one epoch.
+ cfg (CfgNode): configs.
+ mode (str): `train`, `val`, or `test` mode.
+ """
+ self.cfg = cfg
+ self.lr = None
+ self.loss = ScalarMeter(cfg.LOG_PERIOD)
+ self.full_ava_test = cfg.AVA.FULL_TEST_ON_VAL
+ self.mode = mode
+ self.iter_timer = Timer()
+ self.all_preds = []
+ self.all_ori_boxes = []
+ self.all_metadata = []
+ self.overall_iters = overall_iters
+ self.excluded_keys = read_exclusions(
+ os.path.join(cfg.AVA.ANNOTATION_DIR, cfg.AVA.EXCLUSION_FILE)
+ )
+ self.categories, self.class_whitelist = read_labelmap(
+ os.path.join(cfg.AVA.ANNOTATION_DIR, cfg.AVA.LABEL_MAP_FILE)
+ )
+ gt_filename = os.path.join(
+ cfg.AVA.ANNOTATION_DIR, cfg.AVA.GROUNDTRUTH_FILE
+ )
+ self.full_groundtruth = read_csv(gt_filename, self.class_whitelist)
+ self.mini_groundtruth = get_ava_mini_groundtruth(self.full_groundtruth)
+
+ _, self.video_idx_to_name = ava_helper.load_image_lists(
+ cfg, mode == "train"
+ )
+
+ def log_iter_stats(self, cur_epoch, cur_iter):
+ """
+ Log the stats.
+ Args:
+ cur_epoch (int): the current epoch.
+ cur_iter (int): the current iteration.
+ """
+
+ if (cur_iter + 1) % self.cfg.LOG_PERIOD != 0:
+ return
+
+ eta_sec = self.iter_timer.seconds() * (self.overall_iters - cur_iter)
+ eta = str(datetime.timedelta(seconds=int(eta_sec)))
+ if self.mode == "train":
+ stats = {
+ "_type": "{}_iter".format(self.mode),
+ "cur_epoch": "{}".format(cur_epoch + 1),
+ "cur_iter": "{}".format(cur_iter + 1),
+ "eta": eta,
+ "time_diff": self.iter_timer.seconds(),
+ "mode": self.mode,
+ "loss": self.loss.get_win_median(),
+ "lr": self.lr,
+ }
+ elif self.mode == "val":
+ stats = {
+ "_type": "{}_iter".format(self.mode),
+ "cur_epoch": "{}".format(cur_epoch + 1),
+ "cur_iter": "{}".format(cur_iter + 1),
+ "eta": eta,
+ "time_diff": self.iter_timer.seconds(),
+ "mode": self.mode,
+ }
+ elif self.mode == "test":
+ stats = {
+ "_type": "{}_iter".format(self.mode),
+ "cur_iter": "{}".format(cur_iter + 1),
+ "eta": eta,
+ "time_diff": self.iter_timer.seconds(),
+ "mode": self.mode,
+ }
+ else:
+ raise NotImplementedError("Unknown mode: {}".format(self.mode))
+
+ logging.log_json_stats(stats)
+
+ def iter_tic(self):
+ """
+ Start to record time.
+ """
+ self.iter_timer.reset()
+
+ def iter_toc(self):
+ """
+ Stop to record time.
+ """
+ self.iter_timer.pause()
+
+ def reset(self):
+ """
+ Reset the Meter.
+ """
+ self.loss.reset()
+
+ self.all_preds = []
+ self.all_ori_boxes = []
+ self.all_metadata = []
+
+ def update_stats(self, preds, ori_boxes, metadata, loss=None, lr=None):
+ """
+ Update the current stats.
+ Args:
+ preds (tensor): prediction embedding.
+ ori_boxes (tensor): original boxes (x1, y1, x2, y2).
+ metadata (tensor): metadata of the AVA data.
+ loss (float): loss value.
+ lr (float): learning rate.
+ """
+ if self.mode in ["val", "test"]:
+ self.all_preds.append(preds)
+ self.all_ori_boxes.append(ori_boxes)
+ self.all_metadata.append(metadata)
+ if loss is not None:
+ self.loss.add_value(loss)
+ if lr is not None:
+ self.lr = lr
+
+ def finalize_metrics(self, log=True):
+ """
+ Calculate and log the final AVA metrics.
+ """
+ all_preds = torch.cat(self.all_preds, dim=0)
+ all_ori_boxes = torch.cat(self.all_ori_boxes, dim=0)
+ all_metadata = torch.cat(self.all_metadata, dim=0)
+
+ if self.mode == "test" or (self.full_ava_test and self.mode == "val"):
+ groundtruth = self.full_groundtruth
+ else:
+ groundtruth = self.mini_groundtruth
+
+ self.full_map = evaluate_ava(
+ all_preds,
+ all_ori_boxes,
+ all_metadata.tolist(),
+ self.excluded_keys,
+ self.class_whitelist,
+ self.categories,
+ groundtruth=groundtruth,
+ video_idx_to_name=self.video_idx_to_name,
+ )
+ if log:
+ stats = {"mode": self.mode, "map": self.full_map}
+ logging.log_json_stats(stats)
+
+ def log_epoch_stats(self, cur_epoch):
+ """
+ Log the stats of the current epoch.
+ Args:
+ cur_epoch (int): the number of current epoch.
+ """
+ if self.mode in ["val", "test"]:
+ self.finalize_metrics(log=False)
+ stats = {
+ "_type": "{}_epoch".format(self.mode),
+ "cur_epoch": "{}".format(cur_epoch + 1),
+ "mode": self.mode,
+ "map": self.full_map,
+ "gpu_mem": "{:.2f} GB".format(misc.gpu_mem_usage()),
+ "RAM": "{:.2f}/{:.2f} GB".format(*misc.cpu_mem_usage()),
+ }
+ logging.log_json_stats(stats)
+
+
+class TestMeter(object):
+ """
+ Perform the multi-view ensemble for testing: each video with an unique index
+ will be sampled with multiple clips, and the predictions of the clips will
+ be aggregated to produce the final prediction for the video.
+ The accuracy is calculated with the given ground truth labels.
+ """
+
+ def __init__(
+ self,
+ num_videos,
+ num_clips,
+ num_cls,
+ overall_iters,
+ multi_label=False,
+ ensemble_method="sum",
+ ):
+ """
+ Construct tensors to store the predictions and labels. Expect to get
+ num_clips predictions from each video, and calculate the metrics on
+ num_videos videos.
+ Args:
+ num_videos (int): number of videos to test.
+ num_clips (int): number of clips sampled from each video for
+ aggregating the final prediction for the video.
+ num_cls (int): number of classes for each prediction.
+ overall_iters (int): overall iterations for testing.
+ multi_label (bool): if True, use map as the metric.
+ ensemble_method (str): method to perform the ensemble, options
+ include "sum", and "max".
+ """
+
+ self.iter_timer = Timer()
+ self.num_clips = num_clips
+ self.overall_iters = overall_iters
+ self.multi_label = multi_label
+ self.ensemble_method = ensemble_method
+ # Initialize tensors.
+ self.video_preds = torch.zeros((num_videos, num_cls))
+ if multi_label:
+ self.video_preds -= 1e10
+
+ self.video_labels = (
+ torch.zeros((num_videos, num_cls))
+ if multi_label
+ else torch.zeros((num_videos)).long()
+ )
+ self.clip_count = torch.zeros((num_videos)).long()
+ # Reset metric.
+ self.reset()
+
+ def reset(self):
+ """
+ Reset the metric.
+ """
+ self.clip_count.zero_()
+ self.video_preds.zero_()
+ if self.multi_label:
+ self.video_preds -= 1e10
+ self.video_labels.zero_()
+
+ def update_stats(self, preds, labels, clip_ids):
+ """
+ Collect the predictions from the current batch and perform on-the-flight
+ summation as ensemble.
+ Args:
+ preds (tensor): predictions from the current batch. Dimension is
+ N x C where N is the batch size and C is the channel size
+ (num_cls).
+ labels (tensor): the corresponding labels of the current batch.
+ Dimension is N.
+ clip_ids (tensor): clip indexes of the current batch, dimension is
+ N.
+ """
+ for ind in range(preds.shape[0]):
+ vid_id = int(clip_ids[ind]) // self.num_clips
+ if self.video_labels[vid_id].sum() > 0:
+ assert torch.equal(
+ self.video_labels[vid_id].type(torch.FloatTensor),
+ labels[ind].type(torch.FloatTensor),
+ )
+ self.video_labels[vid_id] = labels[ind]
+ if self.ensemble_method == "sum":
+ self.video_preds[vid_id] += preds[ind]
+ elif self.ensemble_method == "max":
+ self.video_preds[vid_id] = torch.max(
+ self.video_preds[vid_id], preds[ind]
+ )
+ else:
+ raise NotImplementedError(
+ "Ensemble Method {} is not supported".format(
+ self.ensemble_method
+ )
+ )
+ self.clip_count[vid_id] += 1
+
+ def log_iter_stats(self, cur_iter):
+ """
+ Log the stats.
+ Args:
+ cur_iter (int): the current iteration of testing.
+ """
+ eta_sec = self.iter_timer.seconds() * (self.overall_iters - cur_iter)
+ eta = str(datetime.timedelta(seconds=int(eta_sec)))
+ stats = {
+ "split": "test_iter",
+ "cur_iter": "{}".format(cur_iter + 1),
+ "eta": eta,
+ "time_diff": self.iter_timer.seconds(),
+ }
+ logging.log_json_stats(stats)
+
+ def iter_tic(self):
+ self.iter_timer.reset()
+
+ def iter_toc(self):
+ self.iter_timer.pause()
+
+ def finalize_metrics(self, ks=(1, 5)):
+ """
+ Calculate and log the final ensembled metrics.
+ ks (tuple): list of top-k values for topk_accuracies. For example,
+ ks = (1, 5) correspods to top-1 and top-5 accuracy.
+ """
+ if not all(self.clip_count == self.num_clips):
+ logger.warning(
+ "clip count {} ~= num clips {}".format(
+ ", ".join(
+ [
+ "{}: {}".format(i, k)
+ for i, k in enumerate(self.clip_count.tolist())
+ ]
+ ),
+ self.num_clips,
+ )
+ )
+
+ stats = {"split": "test_final"}
+ if self.multi_label:
+ map = get_map(
+ self.video_preds.cpu().numpy(), self.video_labels.cpu().numpy()
+ )
+ stats["map"] = map
+ else:
+ num_topks_correct = metrics.topks_correct(
+ self.video_preds, self.video_labels, ks
+ )
+ topks = [
+ (x / self.video_preds.size(0)) * 100.0
+ for x in num_topks_correct
+ ]
+ assert len({len(ks), len(topks)}) == 1
+ for k, topk in zip(ks, topks):
+ stats["top{}_acc".format(k)] = "{:.{prec}f}".format(
+ topk, prec=2
+ )
+ logging.log_json_stats(stats)
+
+
+class ScalarMeter(object):
+ """
+ A scalar meter uses a deque to track a series of scaler values with a given
+ window size. It supports calculating the median and average values of the
+ window, and also supports calculating the global average.
+ """
+
+ def __init__(self, window_size):
+ """
+ Args:
+ window_size (int): size of the max length of the deque.
+ """
+ self.deque = deque(maxlen=window_size)
+ self.total = 0.0
+ self.count = 0
+
+ def reset(self):
+ """
+ Reset the deque.
+ """
+ self.deque.clear()
+ self.total = 0.0
+ self.count = 0
+
+ def add_value(self, value):
+ """
+ Add a new scalar value to the deque.
+ """
+ self.deque.append(value)
+ self.count += 1
+ self.total += value
+
+ def get_win_median(self):
+ """
+ Calculate the current median value of the deque.
+ """
+ return np.median(self.deque)
+
+ def get_win_avg(self):
+ """
+ Calculate the current average value of the deque.
+ """
+ return np.mean(self.deque)
+
+ def get_global_avg(self):
+ """
+ Calculate the global mean value.
+ """
+ return self.total / self.count
+
+
+class TrainMeter(object):
+ """
+ Measure training stats.
+ """
+
+ def __init__(self, epoch_iters, cfg):
+ """
+ Args:
+ epoch_iters (int): the overall number of iterations of one epoch.
+ cfg (CfgNode): configs.
+ """
+ self._cfg = cfg
+ self.epoch_iters = epoch_iters
+ self.MAX_EPOCH = cfg.SOLVER.MAX_EPOCH * epoch_iters
+ self.iter_timer = Timer()
+ self.loss = ScalarMeter(cfg.LOG_PERIOD)
+ self.loss_total = 0.0
+ self.lr = None
+ # Current minibatch errors (smoothed over a window).
+ self.mb_top1_err = ScalarMeter(cfg.LOG_PERIOD)
+ self.mb_top5_err = ScalarMeter(cfg.LOG_PERIOD)
+ # Number of misclassified examples.
+ self.num_top1_mis = 0
+ self.num_top5_mis = 0
+ self.num_samples = 0
+
+ def reset(self):
+ """
+ Reset the Meter.
+ """
+ self.loss.reset()
+ self.loss_total = 0.0
+ self.lr = None
+ self.mb_top1_err.reset()
+ self.mb_top5_err.reset()
+ self.num_top1_mis = 0
+ self.num_top5_mis = 0
+ self.num_samples = 0
+
+ def iter_tic(self):
+ """
+ Start to record time.
+ """
+ self.iter_timer.reset()
+
+ def iter_toc(self):
+ """
+ Stop to record time.
+ """
+ self.iter_timer.pause()
+
+ def update_stats(self, top1_err, top5_err, loss, lr, mb_size):
+ """
+ Update the current stats.
+ Args:
+ top1_err (float): top1 error rate.
+ top5_err (float): top5 error rate.
+ loss (float): loss value.
+ lr (float): learning rate.
+ mb_size (int): mini batch size.
+ """
+ self.loss.add_value(loss)
+ self.lr = lr
+ self.loss_total += loss * mb_size
+ self.num_samples += mb_size
+
+ if not self._cfg.DATA.MULTI_LABEL:
+ # Current minibatch stats
+ self.mb_top1_err.add_value(top1_err)
+ self.mb_top5_err.add_value(top5_err)
+ # Aggregate stats
+ self.num_top1_mis += top1_err * mb_size
+ self.num_top5_mis += top5_err * mb_size
+
+ def log_iter_stats(self, cur_epoch, cur_iter):
+ """
+ log the stats of the current iteration.
+ Args:
+ cur_epoch (int): the number of current epoch.
+ cur_iter (int): the number of current iteration.
+ """
+ if (cur_iter + 1) % self._cfg.LOG_PERIOD != 0:
+ return
+ eta_sec = self.iter_timer.seconds() * (
+ self.MAX_EPOCH - (cur_epoch * self.epoch_iters + cur_iter + 1)
+ )
+ eta = str(datetime.timedelta(seconds=int(eta_sec)))
+ stats = {
+ "_type": "train_iter",
+ "epoch": "{}/{}".format(cur_epoch + 1, self._cfg.SOLVER.MAX_EPOCH),
+ "iter": "{}/{}".format(cur_iter + 1, self.epoch_iters),
+ "time_diff": self.iter_timer.seconds(),
+ "eta": eta,
+ "loss": self.loss.get_win_median(),
+ "lr": self.lr,
+ "gpu_mem": "{:.2f} GB".format(misc.gpu_mem_usage()),
+ }
+ if not self._cfg.DATA.MULTI_LABEL:
+ stats["top1_err"] = self.mb_top1_err.get_win_median()
+ stats["top5_err"] = self.mb_top5_err.get_win_median()
+ logging.log_json_stats(stats)
+
+ def log_epoch_stats(self, cur_epoch):
+ """
+ Log the stats of the current epoch.
+ Args:
+ cur_epoch (int): the number of current epoch.
+ """
+ eta_sec = self.iter_timer.seconds() * (
+ self.MAX_EPOCH - (cur_epoch + 1) * self.epoch_iters
+ )
+ eta = str(datetime.timedelta(seconds=int(eta_sec)))
+ stats = {
+ "_type": "train_epoch",
+ "epoch": "{}/{}".format(cur_epoch + 1, self._cfg.SOLVER.MAX_EPOCH),
+ "time_diff": self.iter_timer.seconds(),
+ "eta": eta,
+ "lr": self.lr,
+ "gpu_mem": "{:.2f} GB".format(misc.gpu_mem_usage()),
+ "RAM": "{:.2f}/{:.2f} GB".format(*misc.cpu_mem_usage()),
+ }
+ if not self._cfg.DATA.MULTI_LABEL:
+ top1_err = self.num_top1_mis / self.num_samples
+ top5_err = self.num_top5_mis / self.num_samples
+ avg_loss = self.loss_total / self.num_samples
+ stats["top1_err"] = top1_err
+ stats["top5_err"] = top5_err
+ stats["loss"] = avg_loss
+ logging.log_json_stats(stats)
+
+
+class TrainIterMeter(object):
+ """
+ Measure training stats.
+ """
+
+ def __init__(self, epoch_iters, cfg,extra=[]):
+ """
+ Args:
+ epoch_iters (int): the overall number of iterations of one epoch.
+ cfg (CfgNode): configs.
+ """
+ self._cfg = cfg
+ self.epoch_iters = epoch_iters
+ self.MAX_EPOCH = cfg.SOLVER.MAX_EPOCH * epoch_iters
+ self.iter_timer = Timer()
+ self.loss = ScalarMeter(cfg.LOG_PERIOD)
+ self.loss_total = 0.0
+ self.lr = None
+
+ # Number of misclassified examples.
+ self.num_samples = 0
+
+ self.meters={key:ScalarMeter(cfg.LOG_PERIOD) for key in extra}
+
+ def reset(self):
+ """
+ Reset the Meter.
+ """
+ self.loss.reset()
+ self.loss_total = 0.0
+ self.lr = None
+
+
+ self.num_samples = 0
+
+ for meter in self.meters.values():
+ meter.reset()
+
+ def iter_tic(self):
+ """
+ Start to record time.
+ """
+ self.iter_timer.reset()
+
+ def iter_toc(self):
+ """
+ Stop to record time.
+ """
+ self.iter_timer.pause()
+
+ def update_stats(self, loss, lr, mb_size,extra={}):
+ """
+ Update the current stats.
+ Args:
+ top1_err (float): top1 error rate.
+ top5_err (float): top5 error rate.
+ loss (float): loss value.
+ lr (float): learning rate.
+ mb_size (int): mini batch size.
+ """
+ self.loss.add_value(loss)
+ self.lr = lr
+ self.loss_total += loss * mb_size
+ self.num_samples += mb_size
+
+
+ for key,val in extra.items():
+ self.meters[key].add_value(val)
+
+ def log_iter_stats(self, cur_epoch, cur_iter,extra={}):
+ """
+ log the stats of the current iteration.
+ Args:
+ cur_epoch (int): the number of current epoch.
+ cur_iter (int): the number of current iteration.
+ """
+ if (cur_iter + 1) % self._cfg.LOG_PERIOD != 0:
+ return
+ eta_sec = self.iter_timer.seconds() * (
+ self.MAX_EPOCH - (cur_epoch * self.epoch_iters + cur_iter + 1)
+ )
+ eta = str(datetime.timedelta(seconds=int(eta_sec)))
+ stats = {
+ "_type": "train_iter",
+ "epoch": "{}/{}".format(cur_epoch + 1, self._cfg.SOLVER.MAX_EPOCH),
+ "iter": "{}/{}".format(cur_iter + 1, self.epoch_iters),
+ "time_diff": self.iter_timer.seconds(),
+ "eta": eta,
+ "loss": self.loss.get_win_median(),
+ "lr": self.lr,
+ "gpu_mem": "{:.2f} GB".format(misc.gpu_mem_usage()),
+ }
+
+ for key,meter in self.meters.items():
+ stats[key]=meter.get_win_median()
+ for key,val in extra.items():
+ stats[key]=val
+
+ logging.log_json_stats(stats)
+
+ def log_epoch_stats(self, cur_epoch):
+ """
+ Log the stats of the current epoch.
+ Args:
+ cur_epoch (int): the number of current epoch.
+ """
+ eta_sec = self.iter_timer.seconds() * (
+ self.MAX_EPOCH - (cur_epoch + 1) * self.epoch_iters
+ )
+ eta = str(datetime.timedelta(seconds=int(eta_sec)))
+ stats = {
+ "_type": "train_epoch",
+ "epoch": "{}/{}".format(cur_epoch + 1, self._cfg.SOLVER.MAX_EPOCH),
+ "time_diff": self.iter_timer.seconds(),
+ "eta": eta,
+ "lr": self.lr,
+ "gpu_mem": "{:.2f} GB".format(misc.gpu_mem_usage()),
+ "RAM": "{:.2f}/{:.2f} GB".format(*misc.cpu_mem_usage()),
+ }
+ if not self._cfg.DATA.MULTI_LABEL:
+ avg_loss = self.loss_total / self.num_samples
+ stats["loss"] = avg_loss
+ logging.log_json_stats(stats)
+
+
+
+
+class ValMeter(object):
+ """
+ Measures validation stats.
+ """
+
+ def __init__(self, max_iter, cfg):
+ """
+ Args:
+ max_iter (int): the max number of iteration of the current epoch.
+ cfg (CfgNode): configs.
+ """
+ self._cfg = cfg
+ self.max_iter = max_iter
+ self.iter_timer = Timer()
+ # Current minibatch errors (smoothed over a window).
+ self.mb_top1_err = ScalarMeter(cfg.LOG_PERIOD)
+ self.mb_top5_err = ScalarMeter(cfg.LOG_PERIOD)
+ # Min errors (over the full val set).
+ self.min_top1_err = 100.0
+ self.min_top5_err = 100.0
+ # Number of misclassified examples.
+ self.num_top1_mis = 0
+ self.num_top5_mis = 0
+ self.num_samples = 0
+ self.all_preds = []
+ self.all_labels = []
+
+ def reset(self):
+ """
+ Reset the Meter.
+ """
+ self.iter_timer.reset()
+ self.mb_top1_err.reset()
+ self.mb_top5_err.reset()
+ self.num_top1_mis = 0
+ self.num_top5_mis = 0
+ self.num_samples = 0
+ self.all_preds = []
+ self.all_labels = []
+
+ def iter_tic(self):
+ """
+ Start to record time.
+ """
+ self.iter_timer.reset()
+
+ def iter_toc(self):
+ """
+ Stop to record time.
+ """
+ self.iter_timer.pause()
+
+ def update_stats(self, top1_err, top5_err, mb_size):
+ """
+ Update the current stats.
+ Args:
+ top1_err (float): top1 error rate.
+ top5_err (float): top5 error rate.
+ mb_size (int): mini batch size.
+ """
+ self.mb_top1_err.add_value(top1_err)
+ self.mb_top5_err.add_value(top5_err)
+ self.num_top1_mis += top1_err * mb_size
+ self.num_top5_mis += top5_err * mb_size
+ self.num_samples += mb_size
+
+ def update_predictions(self, preds, labels):
+ """
+ Update predictions and labels.
+ Args:
+ preds (tensor): model output predictions.
+ labels (tensor): labels.
+ """
+ # TODO: merge update_prediction with update_stats.
+ self.all_preds.append(preds)
+ self.all_labels.append(labels)
+
+ def log_iter_stats(self, cur_epoch, cur_iter):
+ """
+ log the stats of the current iteration.
+ Args:
+ cur_epoch (int): the number of current epoch.
+ cur_iter (int): the number of current iteration.
+ """
+ if (cur_iter + 1) % self._cfg.LOG_PERIOD != 0:
+ return
+ eta_sec = self.iter_timer.seconds() * (self.max_iter - cur_iter - 1)
+ eta = str(datetime.timedelta(seconds=int(eta_sec)))
+ stats = {
+ "_type": "val_iter",
+ "epoch": "{}/{}".format(cur_epoch + 1, self._cfg.SOLVER.MAX_EPOCH),
+ "iter": "{}/{}".format(cur_iter + 1, self.max_iter),
+ "time_diff": self.iter_timer.seconds(),
+ "eta": eta,
+ "gpu_mem": "{:.2f} GB".format(misc.gpu_mem_usage()),
+ }
+ if not self._cfg.DATA.MULTI_LABEL:
+ stats["top1_err"] = self.mb_top1_err.get_win_median()
+ stats["top5_err"] = self.mb_top5_err.get_win_median()
+ logging.log_json_stats(stats)
+
+ def log_epoch_stats(self, cur_epoch):
+ """
+ Log the stats of the current epoch.
+ Args:
+ cur_epoch (int): the number of current epoch.
+ """
+ stats = {
+ "_type": "val_epoch",
+ "epoch": "{}/{}".format(cur_epoch + 1, self._cfg.SOLVER.MAX_EPOCH),
+ "time_diff": self.iter_timer.seconds(),
+ "gpu_mem": "{:.2f} GB".format(misc.gpu_mem_usage()),
+ "RAM": "{:.2f}/{:.2f} GB".format(*misc.cpu_mem_usage()),
+ }
+ if self._cfg.DATA.MULTI_LABEL:
+ stats["map"] = get_map(
+ torch.cat(self.all_preds).cpu().numpy(),
+ torch.cat(self.all_labels).cpu().numpy(),
+ )
+ else:
+ top1_err = self.num_top1_mis / self.num_samples
+ top5_err = self.num_top5_mis / self.num_samples
+ self.min_top1_err = min(self.min_top1_err, top1_err)
+ self.min_top5_err = min(self.min_top5_err, top5_err)
+
+ stats["top1_err"] = top1_err
+ stats["top5_err"] = top5_err
+ stats["min_top1_err"] = self.min_top1_err
+ stats["min_top5_err"] = self.min_top5_err
+
+ logging.log_json_stats(stats)
+
+
+def get_map(preds, labels):
+ """
+ Compute mAP for multi-label case.
+ Args:
+ preds (numpy tensor): num_examples x num_classes.
+ labels (numpy tensor): num_examples x num_classes.
+ Returns:
+ mean_ap (int): final mAP score.
+ """
+
+ logger.info("Getting mAP for {} examples".format(preds.shape[0]))
+
+ preds = preds[:, ~(np.all(labels == 0, axis=0))]
+ labels = labels[:, ~(np.all(labels == 0, axis=0))]
+ aps = [0]
+ try:
+ aps = average_precision_score(labels, preds, average=None)
+ except ValueError:
+ print(
+ "Average precision requires a sufficient number of samples \
+ in a batch which are missing in this sample."
+ )
+
+ mean_ap = np.mean(aps)
+ return mean_ap
diff --git a/clean/video/pwtf_dvd/inference/slowfast/utils/metrics.py b/clean/video/pwtf_dvd/inference/slowfast/utils/metrics.py
new file mode 100644
index 0000000000000000000000000000000000000000..0ef01b174aa5c3d54da77923f515f244327c4e80
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/utils/metrics.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python3
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+
+"""Functions for computing metrics."""
+
+import torch
+
+
+def topks_correct(preds, labels, ks):
+ """
+ Given the predictions, labels, and a list of top-k values, compute the
+ number of correct predictions for each top-k value.
+
+ Args:
+ preds (array): array of predictions. Dimension is batchsize
+ N x ClassNum.
+ labels (array): array of labels. Dimension is batchsize N.
+ ks (list): list of top-k values. For example, ks = [1, 5] correspods
+ to top-1 and top-5.
+
+ Returns:
+ topks_correct (list): list of numbers, where the `i`-th entry
+ corresponds to the number of top-`ks[i]` correct predictions.
+ """
+ assert preds.size(0) == labels.size(
+ 0
+ ), "Batch dim of predictions and labels must match"
+ # Find the top max_k predictions for each sample
+ _top_max_k_vals, top_max_k_inds = torch.topk(
+ preds, max(ks), dim=1, largest=True, sorted=True
+ )
+ # (batch_size, max_k) -> (max_k, batch_size).
+ top_max_k_inds = top_max_k_inds.t()
+ # (batch_size, ) -> (max_k, batch_size).
+ rep_max_k_labels = labels.view(1, -1).expand_as(top_max_k_inds)
+ # (i, j) = 1 if top i-th prediction for the j-th sample is correct.
+ top_max_k_correct = top_max_k_inds.eq(rep_max_k_labels)
+ # Compute the number of topk correct predictions for each k.
+ topks_correct = [
+ top_max_k_correct[:k, :].view(-1).float().sum() for k in ks
+ ]
+ return topks_correct
+
+
+def topk_errors(preds, labels, ks):
+ """
+ Computes the top-k error for each k.
+ Args:
+ preds (array): array of predictions. Dimension is N.
+ labels (array): array of labels. Dimension is N.
+ ks (list): list of ks to calculate the top accuracies.
+ """
+ num_topks_correct = topks_correct(preds, labels, ks)
+ return [(1.0 - x / preds.size(0)) * 100.0 for x in num_topks_correct]
+
+
+def topk_accuracies(preds, labels, ks):
+ """
+ Computes the top-k accuracy for each k.
+ Args:
+ preds (array): array of predictions. Dimension is N.
+ labels (array): array of labels. Dimension is N.
+ ks (list): list of ks to calculate the top accuracies.
+ """
+ num_topks_correct = topks_correct(preds, labels, ks)
+ return [(x / preds.size(0)) * 100.0 for x in num_topks_correct]
diff --git a/clean/video/pwtf_dvd/inference/slowfast/utils/misc.py b/clean/video/pwtf_dvd/inference/slowfast/utils/misc.py
new file mode 100644
index 0000000000000000000000000000000000000000..13fea609bca56845d61819707a66cbd807b956d8
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/utils/misc.py
@@ -0,0 +1,359 @@
+#!/usr/bin/env python3
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+
+import json
+import logging
+import math
+import numpy as np
+import os
+from datetime import datetime
+import psutil
+import torch
+from fvcore.common.file_io import PathManager
+from fvcore.nn.activation_count import activation_count
+from fvcore.nn.flop_count import flop_count
+from matplotlib import pyplot as plt
+from torch import nn
+
+import slowfast.utils.logging as logging
+import slowfast.utils.multiprocessing as mpu
+from slowfast.datasets.utils import pack_pathway_output
+from slowfast.models.batchnorm_helper import SubBatchNorm3d
+
+logger = logging.get_logger(__name__)
+
+
+def check_nan_losses(loss):
+ """
+ Determine whether the loss is NaN (not a number).
+ Args:
+ loss (loss): loss to check whether is NaN.
+ """
+ if math.isnan(loss):
+ raise RuntimeError("ERROR: Got NaN losses {}".format(datetime.now()))
+
+
+def params_count(model):
+ """
+ Compute the number of parameters.
+ Args:
+ model (model): model to count the number of parameters.
+ """
+ return np.sum([p.numel() for p in model.parameters()]).item()
+
+
+def gpu_mem_usage():
+ """
+ Compute the GPU memory usage for the current device (GB).
+ """
+ if torch.cuda.is_available():
+ mem_usage_bytes = torch.cuda.max_memory_allocated()
+ else:
+ mem_usage_bytes = 0
+ return mem_usage_bytes / 1024 ** 3
+
+
+def cpu_mem_usage():
+ """
+ Compute the system memory (RAM) usage for the current device (GB).
+ Returns:
+ usage (float): used memory (GB).
+ total (float): total memory (GB).
+ """
+ vram = psutil.virtual_memory()
+ usage = (vram.total - vram.available) / 1024 ** 3
+ total = vram.total / 1024 ** 3
+
+ return usage, total
+
+
+def _get_model_analysis_input(cfg, use_train_input):
+ """
+ Return a dummy input for model analysis with batch size 1. The input is
+ used for analyzing the model (counting flops and activations etc.).
+ Args:
+ cfg (CfgNode): configs. Details can be found in
+ slowfast/config/defaults.py
+ use_train_input (bool): if True, return the input for training. Otherwise,
+ return the input for testing.
+
+ Returns:
+ inputs: the input for model analysis.
+ """
+ rgb_dimension = 3
+ if use_train_input:
+ input_tensors = torch.rand(
+ rgb_dimension,
+ cfg.DATA.NUM_FRAMES,
+ cfg.DATA.TRAIN_CROP_SIZE,
+ cfg.DATA.TRAIN_CROP_SIZE,
+ )
+ else:
+ input_tensors = torch.rand(
+ rgb_dimension,
+ cfg.DATA.NUM_FRAMES,
+ cfg.DATA.TEST_CROP_SIZE,
+ cfg.DATA.TEST_CROP_SIZE,
+ )
+ model_inputs = pack_pathway_output(cfg, input_tensors)
+ for i in range(len(model_inputs)):
+ model_inputs[i] = model_inputs[i].unsqueeze(0)
+ if cfg.NUM_GPUS:
+ model_inputs[i] = model_inputs[i].cuda(non_blocking=True)
+
+ # If detection is enabled, count flops for one proposal.
+ if cfg.DETECTION.ENABLE:
+ bbox = torch.tensor([[0, 0, 1.0, 0, 1.0]])
+ if cfg.NUM_GPUS:
+ bbox = bbox.cuda()
+ inputs = (model_inputs, bbox)
+ else:
+ inputs = (model_inputs,)
+ return inputs
+
+
+def get_model_stats(model, cfg, mode, use_train_input):
+ """
+ Compute statistics for the current model given the config.
+ Args:
+ model (model): model to perform analysis.
+ cfg (CfgNode): configs. Details can be found in
+ slowfast/config/defaults.py
+ mode (str): Options include `flop` or `activation`. Compute either flop
+ (gflops) or activation count (mega).
+ use_train_input (bool): if True, compute statistics for training. Otherwise,
+ compute statistics for testing.
+
+ Returns:
+ float: the total number of count of the given model.
+ """
+ assert mode in [
+ "flop",
+ "activation",
+ ], "'{}' not supported for model analysis".format(mode)
+ if mode == "flop":
+ model_stats_fun = flop_count
+ elif mode == "activation":
+ model_stats_fun = activation_count
+
+ # Set model to evaluation mode for analysis.
+ # Evaluation mode can avoid getting stuck with sync batchnorm.
+ model_mode = model.training
+ model.eval()
+ inputs = _get_model_analysis_input(cfg, use_train_input)
+ count_dict, _ = model_stats_fun(model, inputs)
+ count = sum(count_dict.values())
+ model.train(model_mode)
+ return count
+
+
+def log_model_info(model, cfg, use_train_input=True):
+ """
+ Log info, includes number of parameters, gpu usage, gflops and activation count.
+ The model info is computed when the model is in validation mode.
+ Args:
+ model (model): model to log the info.
+ cfg (CfgNode): configs. Details can be found in
+ slowfast/config/defaults.py
+ use_train_input (bool): if True, log info for training. Otherwise,
+ log info for testing.
+ """
+ print("Model:\n{}".format(model))
+ print("Params: {:,}".format(params_count(model)))
+ print("Mem: {:,} MB".format(gpu_mem_usage()))
+ print(
+ "Flops: {:,} G".format(
+ get_model_stats(model, cfg, "flop", use_train_input)
+ )
+ )
+ print(
+ "Activations: {:,} M".format(
+ get_model_stats(model, cfg, "activation", use_train_input)
+ )
+ )
+ logger.info("nvidia-smi")
+ os.system("nvidia-smi")
+
+def is_eval_epoch(cfg, cur_epoch, multigrid_schedule):
+ """
+ Determine if the model should be evaluated at the current epoch.
+ Args:
+ cfg (CfgNode): configs. Details can be found in
+ slowfast/config/defaults.py
+ cur_epoch (int): current epoch.
+ multigrid_schedule (List): schedule for multigrid training.
+ """
+ if cur_epoch + 1 == cfg.SOLVER.MAX_EPOCH:
+ return True
+ if multigrid_schedule is not None:
+ prev_epoch = 0
+ for s in multigrid_schedule:
+ if cur_epoch < s[-1]:
+ period = max(
+ (s[-1] - prev_epoch) // cfg.MULTIGRID.EVAL_FREQ + 1, 1
+ )
+ return (s[-1] - 1 - cur_epoch) % period == 0
+ prev_epoch = s[-1]
+
+ return (cur_epoch + 1) % cfg.TRAIN.EVAL_PERIOD == 0
+
+
+def plot_input(tensor, bboxes=(), texts=(), path="./tmp_vis.png"):
+ """
+ Plot the input tensor with the optional bounding box and save it to disk.
+ Args:
+ tensor (tensor): a tensor with shape of `NxCxHxW`.
+ bboxes (tuple): bounding boxes with format of [[x, y, h, w]].
+ texts (tuple): a tuple of string to plot.
+ path (str): path to the image to save to.
+ """
+ tensor = tensor - tensor.min()
+ tensor = tensor / tensor.max()
+ f, ax = plt.subplots(nrows=1, ncols=tensor.shape[0], figsize=(50, 20))
+ for i in range(tensor.shape[0]):
+ ax[i].axis("off")
+ ax[i].imshow(tensor[i].permute(1, 2, 0))
+ # ax[1][0].axis('off')
+ if bboxes is not None and len(bboxes) > i:
+ for box in bboxes[i]:
+ x1, y1, x2, y2 = box
+ ax[i].vlines(x1, y1, y2, colors="g", linestyles="solid")
+ ax[i].vlines(x2, y1, y2, colors="g", linestyles="solid")
+ ax[i].hlines(y1, x1, x2, colors="g", linestyles="solid")
+ ax[i].hlines(y2, x1, x2, colors="g", linestyles="solid")
+
+ if texts is not None and len(texts) > i:
+ ax[i].text(0, 0, texts[i])
+ f.savefig(path)
+
+
+def frozen_bn_stats(model):
+ """
+ Set all the bn layers to eval mode.
+ Args:
+ model (model): model to set bn layers to eval mode.
+ """
+ for m in model.modules():
+ if isinstance(m, nn.BatchNorm3d):
+ m.eval()
+
+
+def aggregate_sub_bn_stats(module):
+ """
+ Recursively find all SubBN modules and aggregate sub-BN stats.
+ Args:
+ module (nn.Module)
+ Returns:
+ count (int): number of SubBN module found.
+ """
+ count = 0
+ for child in module.children():
+ if isinstance(child, SubBatchNorm3d):
+ child.aggregate_stats()
+ count += 1
+ else:
+ count += aggregate_sub_bn_stats(child)
+ return count
+
+
+def launch_job(cfg, init_method, func, daemon=False):
+ """
+ Run 'func' on one or more GPUs, specified in cfg
+ Args:
+ cfg (CfgNode): configs. Details can be found in
+ slowfast/config/defaults.py
+ init_method (str): initialization method to launch the job with multiple
+ devices.
+ func (function): job to run on GPU(s)
+ daemon (bool): The spawned processes’ daemon flag. If set to True,
+ daemonic processes will be created
+ """
+ if cfg.NUM_GPUS > 1:
+ torch.multiprocessing.spawn(
+ mpu.run,
+ nprocs=cfg.NUM_GPUS,
+ args=(
+ cfg.NUM_GPUS,
+ func,
+ init_method,
+ cfg.SHARD_ID,
+ cfg.NUM_SHARDS,
+ cfg.DIST_BACKEND,
+ cfg,
+ ),
+ daemon=daemon,
+ )
+ else:
+ func(cfg=cfg)
+
+
+def get_class_names(path, parent_path=None, subset_path=None):
+ """
+ Read json file with entries {classname: index} and return
+ an array of class names in order.
+ If parent_path is provided, load and map all children to their ids.
+ Args:
+ path (str): path to class ids json file.
+ File must be in the format {"class1": id1, "class2": id2, ...}
+ parent_path (Optional[str]): path to parent-child json file.
+ File must be in the format {"parent1": ["child1", "child2", ...], ...}
+ subset_path (Optional[str]): path to text file containing a subset
+ of class names, separated by newline characters.
+ Returns:
+ class_names (list of strs): list of class names.
+ class_parents (dict): a dictionary where key is the name of the parent class
+ and value is a list of ids of the children classes.
+ subset_ids (list of ints): list of ids of the classes provided in the
+ subset file.
+ """
+ try:
+ with PathManager.open(path, "r") as f:
+ class2idx = json.load(f)
+ except Exception as err:
+ print("Fail to load file from {} with error {}".format(path, err))
+ return
+
+ max_key = max(class2idx.values())
+ class_names = [None] * (max_key + 1)
+
+ for k, i in class2idx.items():
+ class_names[i] = k
+
+ class_parent = None
+ if parent_path is not None and parent_path != "":
+ try:
+ with PathManager.open(parent_path, "r") as f:
+ d_parent = json.load(f)
+ except EnvironmentError as err:
+ print(
+ "Fail to load file from {} with error {}".format(
+ parent_path, err
+ )
+ )
+ return
+ class_parent = {}
+ for parent, children in d_parent.items():
+ indices = [
+ class2idx[c] for c in children if class2idx.get(c) is not None
+ ]
+ class_parent[parent] = indices
+
+ subset_ids = None
+ if subset_path is not None and subset_path != "":
+ try:
+ with PathManager.open(subset_path, "r") as f:
+ subset = f.read().split("\n")
+ subset_ids = [
+ class2idx[name]
+ for name in subset
+ if class2idx.get(name) is not None
+ ]
+ except EnvironmentError as err:
+ print(
+ "Fail to load file from {} with error {}".format(
+ subset_path, err
+ )
+ )
+ return
+
+ return class_names, class_parent, subset_ids
diff --git a/clean/video/pwtf_dvd/inference/slowfast/utils/multigrid.py b/clean/video/pwtf_dvd/inference/slowfast/utils/multigrid.py
new file mode 100644
index 0000000000000000000000000000000000000000..4aed24bb4889d30960cec5ca94ab20a73b40b9e1
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/utils/multigrid.py
@@ -0,0 +1,240 @@
+#!/usr/bin/env python3
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+
+"""Helper functions for multigrid training."""
+
+import numpy as np
+
+import slowfast.utils.logging as logging
+
+logger = logging.get_logger(__name__)
+
+
+class MultigridSchedule(object):
+ """
+ This class defines multigrid training schedule and update cfg accordingly.
+ """
+
+ def init_multigrid(self, cfg):
+ """
+ Update cfg based on multigrid settings.
+ Args:
+ cfg (configs): configs that contains training and multigrid specific
+ hyperparameters. Details can be seen in
+ slowfast/config/defaults.py.
+ Returns:
+ cfg (configs): the updated cfg.
+ """
+ self.schedule = None
+ # We may modify cfg.TRAIN.BATCH_SIZE, cfg.DATA.NUM_FRAMES, and
+ # cfg.DATA.TRAIN_CROP_SIZE during training, so we store their original
+ # value in cfg and use them as global variables.
+ cfg.MULTIGRID.DEFAULT_B = cfg.TRAIN.BATCH_SIZE
+ cfg.MULTIGRID.DEFAULT_T = cfg.DATA.NUM_FRAMES
+ cfg.MULTIGRID.DEFAULT_S = cfg.DATA.TRAIN_CROP_SIZE
+
+ if cfg.MULTIGRID.LONG_CYCLE:
+ self.schedule = self.get_long_cycle_schedule(cfg)
+ cfg.SOLVER.STEPS = [0] + [s[-1] for s in self.schedule]
+ # Fine-tuning phase.
+ cfg.SOLVER.STEPS[-1] = (
+ cfg.SOLVER.STEPS[-2] + cfg.SOLVER.STEPS[-1]
+ ) // 2
+ cfg.SOLVER.LRS = [
+ cfg.SOLVER.GAMMA ** s[0] * s[1][0] for s in self.schedule
+ ]
+ # Fine-tuning phase.
+ cfg.SOLVER.LRS = cfg.SOLVER.LRS[:-1] + [
+ cfg.SOLVER.LRS[-2],
+ cfg.SOLVER.LRS[-1],
+ ]
+
+ cfg.SOLVER.MAX_EPOCH = self.schedule[-1][-1]
+
+ elif cfg.MULTIGRID.SHORT_CYCLE:
+ cfg.SOLVER.STEPS = [
+ int(s * cfg.MULTIGRID.EPOCH_FACTOR) for s in cfg.SOLVER.STEPS
+ ]
+ cfg.SOLVER.MAX_EPOCH = int(
+ cfg.SOLVER.MAX_EPOCH * cfg.MULTIGRID.EPOCH_FACTOR
+ )
+ return cfg
+
+ def update_long_cycle(self, cfg, cur_epoch):
+ """
+ Before every epoch, check if long cycle shape should change. If it
+ should, update cfg accordingly.
+ Args:
+ cfg (configs): configs that contains training and multigrid specific
+ hyperparameters. Details can be seen in
+ slowfast/config/defaults.py.
+ cur_epoch (int): current epoch index.
+ Returns:
+ cfg (configs): the updated cfg.
+ changed (bool): do we change long cycle shape at this epoch?
+ """
+ base_b, base_t, base_s = get_current_long_cycle_shape(
+ self.schedule, cur_epoch
+ )
+ if base_s != cfg.DATA.TRAIN_CROP_SIZE or base_t != cfg.DATA.NUM_FRAMES:
+
+ cfg.DATA.NUM_FRAMES = base_t
+ cfg.DATA.TRAIN_CROP_SIZE = base_s
+ cfg.TRAIN.BATCH_SIZE = base_b * cfg.MULTIGRID.DEFAULT_B
+
+ bs_factor = (
+ float(cfg.TRAIN.BATCH_SIZE / cfg.NUM_GPUS)
+ / cfg.MULTIGRID.BN_BASE_SIZE
+ )
+
+ if bs_factor < 1:
+ cfg.BN.NORM_TYPE = "sync_batchnorm"
+ cfg.BN.NUM_SYNC_DEVICES = int(1.0 / bs_factor)
+ elif bs_factor > 1:
+ cfg.BN.NORM_TYPE = "sub_batchnorm"
+ cfg.BN.NUM_SPLITS = int(bs_factor)
+ else:
+ cfg.BN.NORM_TYPE = "batchnorm"
+
+ cfg.MULTIGRID.LONG_CYCLE_SAMPLING_RATE = cfg.DATA.SAMPLING_RATE * (
+ cfg.MULTIGRID.DEFAULT_T // cfg.DATA.NUM_FRAMES
+ )
+ logger.info("Long cycle updates:")
+ logger.info("\tBN.NORM_TYPE: {}".format(cfg.BN.NORM_TYPE))
+ if cfg.BN.NORM_TYPE == "sync_batchnorm":
+ logger.info(
+ "\tBN.NUM_SYNC_DEVICES: {}".format(cfg.BN.NUM_SYNC_DEVICES)
+ )
+ elif cfg.BN.NORM_TYPE == "sub_batchnorm":
+ logger.info("\tBN.NUM_SPLITS: {}".format(cfg.BN.NUM_SPLITS))
+ logger.info("\tTRAIN.BATCH_SIZE: {}".format(cfg.TRAIN.BATCH_SIZE))
+ logger.info(
+ "\tDATA.NUM_FRAMES x LONG_CYCLE_SAMPLING_RATE: {}x{}".format(
+ cfg.DATA.NUM_FRAMES, cfg.MULTIGRID.LONG_CYCLE_SAMPLING_RATE
+ )
+ )
+ logger.info(
+ "\tDATA.TRAIN_CROP_SIZE: {}".format(cfg.DATA.TRAIN_CROP_SIZE)
+ )
+ return cfg, True
+ else:
+ return cfg, False
+
+ def get_long_cycle_schedule(self, cfg):
+ """
+ Based on multigrid hyperparameters, define the schedule of a long cycle.
+ Args:
+ cfg (configs): configs that contains training and multigrid specific
+ hyperparameters. Details can be seen in
+ slowfast/config/defaults.py.
+ Returns:
+ schedule (list): Specifies a list long cycle base shapes and their
+ corresponding training epochs.
+ """
+
+ steps = cfg.SOLVER.STEPS
+
+ default_size = float(
+ cfg.DATA.NUM_FRAMES * cfg.DATA.TRAIN_CROP_SIZE ** 2
+ )
+ default_iters = steps[-1]
+
+ # Get shapes and average batch size for each long cycle shape.
+ avg_bs = []
+ all_shapes = []
+ for t_factor, s_factor in cfg.MULTIGRID.LONG_CYCLE_FACTORS:
+ base_t = int(round(cfg.DATA.NUM_FRAMES * t_factor))
+ base_s = int(round(cfg.DATA.TRAIN_CROP_SIZE * s_factor))
+ if cfg.MULTIGRID.SHORT_CYCLE:
+ shapes = [
+ [
+ base_t,
+ cfg.MULTIGRID.DEFAULT_S
+ * cfg.MULTIGRID.SHORT_CYCLE_FACTORS[0],
+ ],
+ [
+ base_t,
+ cfg.MULTIGRID.DEFAULT_S
+ * cfg.MULTIGRID.SHORT_CYCLE_FACTORS[1],
+ ],
+ [base_t, base_s],
+ ]
+ else:
+ shapes = [[base_t, base_s]]
+
+ # (T, S) -> (B, T, S)
+ shapes = [
+ [int(round(default_size / (s[0] * s[1] * s[1]))), s[0], s[1]]
+ for s in shapes
+ ]
+ avg_bs.append(np.mean([s[0] for s in shapes]))
+ all_shapes.append(shapes)
+
+ # Get schedule regardless of cfg.MULTIGRID.EPOCH_FACTOR.
+ total_iters = 0
+ schedule = []
+ for step_index in range(len(steps) - 1):
+ step_epochs = steps[step_index + 1] - steps[step_index]
+
+ for long_cycle_index, shapes in enumerate(all_shapes):
+ cur_epochs = (
+ step_epochs * avg_bs[long_cycle_index] / sum(avg_bs)
+ )
+
+ cur_iters = cur_epochs / avg_bs[long_cycle_index]
+ total_iters += cur_iters
+ schedule.append((step_index, shapes[-1], cur_epochs))
+
+ iter_saving = default_iters / total_iters
+
+ final_step_epochs = cfg.SOLVER.MAX_EPOCH - steps[-1]
+
+ # We define the fine-tuning phase to have the same amount of iteration
+ # saving as the rest of the training.
+ ft_epochs = final_step_epochs / iter_saving * avg_bs[-1]
+
+ schedule.append((step_index + 1, all_shapes[-1][2], ft_epochs))
+
+ # Obtrain final schedule given desired cfg.MULTIGRID.EPOCH_FACTOR.
+ x = (
+ cfg.SOLVER.MAX_EPOCH
+ * cfg.MULTIGRID.EPOCH_FACTOR
+ / sum(s[-1] for s in schedule)
+ )
+
+ final_schedule = []
+ total_epochs = 0
+ for s in schedule:
+ epochs = s[2] * x
+ total_epochs += epochs
+ final_schedule.append((s[0], s[1], int(round(total_epochs))))
+ print_schedule(final_schedule)
+ return final_schedule
+
+
+def print_schedule(schedule):
+ """
+ Log schedule.
+ """
+ logger.info("Long cycle index\tBase shape\tEpochs")
+ for s in schedule:
+ logger.info("{}\t{}\t{}".format(s[0], s[1], s[2]))
+
+
+def get_current_long_cycle_shape(schedule, epoch):
+ """
+ Given a schedule and epoch index, return the long cycle base shape.
+ Args:
+ schedule (configs): configs that contains training and multigrid specific
+ hyperparameters. Details can be seen in
+ slowfast/config/defaults.py.
+ cur_epoch (int): current epoch index.
+ Returns:
+ shapes (list): A list describing the base shape in a long cycle:
+ [batch size relative to default,
+ number of frames, spatial dimension].
+ """
+ for s in schedule:
+ if epoch < s[-1]:
+ return s[1]
+ return schedule[-1][1]
diff --git a/clean/video/pwtf_dvd/inference/slowfast/utils/multiprocessing.py b/clean/video/pwtf_dvd/inference/slowfast/utils/multiprocessing.py
new file mode 100644
index 0000000000000000000000000000000000000000..a56aa603697dd3a6a37871ddd4407523aeebbb8c
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/utils/multiprocessing.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python3
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+
+"""Multiprocessing helpers."""
+
+import torch
+
+
+def run(
+ local_rank, num_proc, func, init_method, shard_id, num_shards, backend, cfg
+):
+ """
+ Runs a function from a child process.
+ Args:
+ local_rank (int): rank of the current process on the current machine.
+ num_proc (int): number of processes per machine.
+ func (function): function to execute on each of the process.
+ init_method (string): method to initialize the distributed training.
+ TCP initialization: equiring a network address reachable from all
+ processes followed by the port.
+ Shared file-system initialization: makes use of a file system that
+ is shared and visible from all machines. The URL should start with
+ file:// and contain a path to a non-existent file on a shared file
+ system.
+ shard_id (int): the rank of the current machine.
+ num_shards (int): number of overall machines for the distributed
+ training job.
+ backend (string): three distributed backends ('nccl', 'gloo', 'mpi') are
+ supports, each with different capabilities. Details can be found
+ here:
+ https://pytorch.org/docs/stable/distributed.html
+ cfg (CfgNode): configs. Details can be found in
+ slowfast/config/defaults.py
+ """
+ # Initialize the process group.
+ world_size = num_proc * num_shards
+ rank = shard_id * num_proc + local_rank
+
+ try:
+ torch.distributed.init_process_group(
+ backend=backend,
+ init_method=init_method,
+ world_size=world_size,
+ rank=rank,
+ )
+ except Exception as e:
+ raise e
+
+ torch.cuda.set_device(local_rank)
+ func(cfg)
diff --git a/clean/video/pwtf_dvd/inference/slowfast/utils/parser.py b/clean/video/pwtf_dvd/inference/slowfast/utils/parser.py
new file mode 100644
index 0000000000000000000000000000000000000000..06b4373e3b3736ceb310eed465fbc75e3bae1eb5
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/utils/parser.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env python3
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+
+"""Argument parser functions."""
+
+import argparse
+import sys
+
+import slowfast.utils.checkpoint as cu
+from slowfast.config.defaults import get_cfg
+
+
+def parse_args():
+ """
+ Parse the following arguments for a default parser for PySlowFast users.
+ Args:
+ shard_id (int): shard id for the current machine. Starts from 0 to
+ num_shards - 1. If single machine is used, then set shard id to 0.
+ num_shards (int): number of shards using by the job.
+ init_method (str): initialization method to launch the job with multiple
+ devices. Options includes TCP or shared file-system for
+ initialization. details can be find in
+ https://pytorch.org/docs/stable/distributed.html#tcp-initialization
+ cfg (str): path to the config file.
+ opts (argument): provide addtional options from the command line, it
+ overwrites the config loaded from file.
+ """
+ parser = argparse.ArgumentParser(
+ description="Provide SlowFast video training and testing pipeline."
+ )
+ parser.add_argument(
+ "--shard_id",
+ help="The shard id of current node, Starts from 0 to num_shards - 1",
+ default=0,
+ type=int,
+ )
+ parser.add_argument(
+ "--num_shards",
+ help="Number of shards using by the job",
+ default=1,
+ type=int,
+ )
+ parser.add_argument(
+ "--init_method",
+ help="Initialization method, includes TCP or shared file-system",
+ default="tcp://localhost:9999",
+ type=str,
+ )
+ parser.add_argument(
+ "--cfg",
+ dest="cfg_file",
+ help="Path to the config file",
+ default="configs/Kinetics/SLOWFAST_4x16_R50.yaml",
+ type=str,
+ )
+ parser.add_argument(
+ "opts",
+ help="See slowfast/config/defaults.py for all options",
+ default=None,
+ nargs=argparse.REMAINDER,
+ )
+ if len(sys.argv) == 1:
+ parser.print_help()
+ return parser.parse_args()
+
+
+def load_config(args):
+ """
+ Given the arguemnts, load and initialize the configs.
+ Args:
+ args (argument): arguments includes `shard_id`, `num_shards`,
+ `init_method`, `cfg_file`, and `opts`.
+ """
+ # Setup cfg.
+ cfg = get_cfg()
+ # Load config from cfg.
+ if args.cfg_file is not None:
+ cfg.merge_from_file(args.cfg_file)
+ # Load config from command line, overwrite config from opts.
+ if args.opts is not None:
+ cfg.merge_from_list(args.opts)
+
+ # Inherit parameters from args.
+ if hasattr(args, "num_shards") and hasattr(args, "shard_id"):
+ cfg.NUM_SHARDS = args.num_shards
+ cfg.SHARD_ID = args.shard_id
+ if hasattr(args, "rng_seed"):
+ cfg.RNG_SEED = args.rng_seed
+ if hasattr(args, "output_dir"):
+ cfg.OUTPUT_DIR = args.output_dir
+
+ # Create the checkpoint dir.
+ cu.make_checkpoint_dir(cfg.OUTPUT_DIR)
+ return cfg
diff --git a/clean/video/pwtf_dvd/inference/slowfast/utils/weight_init_helper.py b/clean/video/pwtf_dvd/inference/slowfast/utils/weight_init_helper.py
new file mode 100644
index 0000000000000000000000000000000000000000..0b5544a70529f5dd1b06ba05a6aca4c7f508bdf3
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/slowfast/utils/weight_init_helper.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python3
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+
+"""Utility function for weight initialization"""
+
+import torch.nn as nn
+from fvcore.nn.weight_init import c2_msra_fill
+
+
+def init_weights(model, fc_init_std=0.01, zero_init_final_bn=True):
+ """
+ Performs ResNet style weight initialization.
+ Args:
+ fc_init_std (float): the expected standard deviation for fc layer.
+ zero_init_final_bn (bool): if True, zero initialize the final bn for
+ every bottleneck.
+ """
+ for m in model.modules():
+ if isinstance(m, nn.Conv3d):
+ """
+ Follow the initialization method proposed in:
+ {He, Kaiming, et al.
+ "Delving deep into rectifiers: Surpassing human-level
+ performance on imagenet classification."
+ arXiv preprint arXiv:1502.01852 (2015)}
+ """
+ c2_msra_fill(m)
+ elif isinstance(m, nn.BatchNorm3d):
+ if (
+ hasattr(m, "transform_final_bn")
+ and m.transform_final_bn
+ and zero_init_final_bn
+ ):
+ batchnorm_weight = 0.0
+ else:
+ batchnorm_weight = 1.0
+ if m.weight is not None:
+ m.weight.data.fill_(batchnorm_weight)
+ if m.bias is not None:
+ m.bias.data.zero_()
+ if isinstance(m, nn.Linear):
+ m.weight.data.normal_(mean=0.0, std=fc_init_std)
+ m.bias.data.zero_()
diff --git a/clean/video/pwtf_dvd/inference/test_on_raw_video.py b/clean/video/pwtf_dvd/inference/test_on_raw_video.py
new file mode 100644
index 0000000000000000000000000000000000000000..9074dcd8ab946d4db33467594722f9e3e83199a7
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/test_on_raw_video.py
@@ -0,0 +1,251 @@
+
+import torch
+from torch.nn import functional as F
+import os
+import numpy as np
+from test_tools.common import detect_all, grab_all_frames
+from test_tools.utils import get_crop_box
+from test_tools.ct.operations import find_longest, multiple_tracking
+from test_tools.faster_crop_align_xray import FasterCropAlignXRay
+from test_tools.supply_writer import SupplyWriter
+import argparse
+from tqdm import tqdm
+from torchvision.transforms import Compose, ToTensor, Normalize
+from model.framework import get_model
+import cv2
+from PIL import Image
+
+mean = torch.tensor([0.485 * 255, 0.456 * 255, 0.406 * 255,]).cuda().view(1, 3, 1, 1, 1)
+std = torch.tensor([0.229 * 255, 0.224 * 255, 0.225 * 255,]).cuda().view(1, 3, 1, 1, 1)
+
+def main():
+ """Main inference function"""
+ parser = argparse.ArgumentParser(description="FTCN Face Depth Estimation Inference")
+ parser.add_argument("--video", type=str, help="Input video path", default="./examples/shining.mp4")
+ parser.add_argument("--out_dir", type=str, help="Output directory", default="./examples")
+ parser.add_argument("--model_path", type=str, help="Model checkpoint path", default="./model/for_deploy_model3.pth")
+ parser.add_argument("--max_frame", type=int, help="Maximum number of frames to process", default=768)
+ args = parser.parse_args()
+
+ # Load model
+ print("Loading model...")
+ model = get_model()
+ model.load_state_dict(torch.load(args.model_path, map_location='cpu'))
+ model.eval()
+ model.cuda()
+ print("Model loaded successfully!")
+
+ # Initialize preprocessing functions
+ crop_align_func = FasterCropAlignXRay(224)
+
+ # Setup input/output paths
+ input_file = args.video
+ os.makedirs(args.out_dir, exist_ok=True)
+ basename = os.path.splitext(os.path.basename(input_file))[0] +"_detect.mp4"
+ out_file = os.path.join(args.out_dir, basename)
+
+ # Process video frames
+ max_frame = args.max_frame
+ cache_file = f"{input_file}_{str(max_frame)}.pth"
+
+ if os.path.exists(cache_file):
+ print("Loading cached detection results...")
+ detect_res, all_lm68 = torch.load(cache_file)
+ frames = grab_all_frames(input_file, max_size=max_frame, cvt=True)
+ print("Detection results loaded from cache")
+ else:
+ print("Performing face detection...")
+ detect_res, all_lm68, frames = detect_all(
+ input_file, return_frames=True, max_size=max_frame
+ )
+ torch.save((detect_res, all_lm68), cache_file)
+ print("Face detection completed")
+
+ print(f"Processing {len(frames)} frames")
+
+
+ # Process detection results
+ shape = frames[0].shape[:2]
+ all_detect_res = []
+
+ assert len(all_lm68) == len(detect_res)
+
+ for faces, faces_lm68 in zip(detect_res, all_lm68):
+ new_faces = []
+ for (box, lm5, score), face_lm68 in zip(faces, faces_lm68):
+ new_face = (box, lm5, face_lm68, score)
+ new_faces.append(new_face)
+ all_detect_res.append(new_faces)
+
+ detect_res = all_detect_res
+
+ # Track faces across frames
+ print("Tracking faces across frames...")
+ tracks = multiple_tracking(detect_res)
+ tuples = [(0, len(detect_res))] * len(tracks)
+
+ print(f"Found {len(tracks)} face tracks")
+
+ if len(tracks) == 0:
+ print("No tracks found, using longest sequence...")
+ tuples, tracks = find_longest(detect_res)
+
+ # Extract face crops and landmarks
+ data_storage = {}
+ frame_boxes = {}
+ super_clips = []
+
+ for track_i, ((start, end), track) in enumerate(zip(tuples, tracks)):
+ print(f"Processing track {track_i}: frames {start}-{end}")
+ assert len(detect_res[start:end]) == len(track)
+
+ super_clips.append(len(track))
+
+ for face, frame_idx, j in zip(track, range(start, end), range(len(track))):
+ box, lm5, lm68 = face[:3]
+ big_box = get_crop_box(shape, box, scale=0.5)
+
+ top_left = big_box[:2][None, :]
+
+ new_lm5 = lm5 - top_left
+ new_lm68 = lm68 - top_left
+ new_box = (box.reshape(2, 2) - top_left).reshape(-1)
+
+ info = (new_box, new_lm5, new_lm68, big_box)
+
+ x1, y1, x2, y2 = big_box
+ cropped = frames[frame_idx][y1:y2, x1:x2]
+
+ base_key = f"{track_i}_{j}_"
+ data_storage[base_key + "img"] = cropped
+ data_storage[base_key + "ldm"] = info
+ data_storage[base_key + "idx"] = frame_idx
+
+ frame_boxes[frame_idx] = np.rint(box).astype(np.int32)
+
+ print(f"Sampling clips from super clips: {super_clips}")
+
+ # Generate clips for temporal analysis
+ clips_for_video = []
+ clip_size = 32
+ pad_length = clip_size - 1
+
+ for super_clip_idx, super_clip_size in enumerate(super_clips):
+ inner_index = list(range(super_clip_size))
+
+ if super_clip_size < clip_size: # Need padding for short sequences
+ post_module = inner_index[1:-1][::-1] + inner_index
+ l_post = len(post_module)
+ post_module = post_module * (pad_length // l_post + 1)
+ post_module = post_module[:pad_length]
+
+ if len(post_module) != pad_length:
+ continue # Skip sequences that are too short
+
+ pre_module = inner_index + inner_index[1:-1][::-1]
+ l_pre = len(post_module)
+ pre_module = pre_module * (pad_length // l_pre + 1)
+ pre_module = pre_module[-pad_length:]
+
+ if len(pre_module) != pad_length:
+ continue # Skip sequences that are too short
+
+ inner_index = pre_module + inner_index + post_module
+
+ super_clip_size = len(inner_index)
+
+ # Generate sliding window clips
+ frame_range = [
+ inner_index[i : i + clip_size]
+ for i in range(super_clip_size)
+ if i + clip_size <= super_clip_size
+ ]
+
+ for indices in frame_range:
+ clip = [(super_clip_idx, t) for t in indices]
+ clips_for_video.append(clip)
+
+ # Run inference on clips
+ preds = []
+ frame_res = {}
+ test_transform = Compose([
+ ToTensor(),
+ Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
+ ])
+
+ print(f"Running inference on {len(clips_for_video)} clips...")
+ for clip in tqdm(clips_for_video, desc="Processing clips"):
+ # Prepare data for this clip
+ images = [data_storage[f"{i}_{j}_img"] for i, j in clip]
+ landmarks = [data_storage[f"{i}_{j}_ldm"] for i, j in clip]
+ frame_ids = [data_storage[f"{i}_{j}_idx"] for i, j in clip]
+
+ # Align and crop faces
+ landmarks, images = crop_align_func(landmarks, images)
+
+ # Convert to temporal frequency domain
+ images_tensor = []
+ ft_images = []
+ for image in images:
+ image = np.array(image)
+ img_pil = Image.fromarray(image)
+ img_pil = test_transform(img_pil)
+ images_tensor.append(img_pil)
+
+ # Apply median filter and compute frequency domain
+ img_filtered = cv2.medianBlur(image.copy(), 5)
+ ft_images.append(cv2.cvtColor((image - img_filtered), cv2.COLOR_RGB2GRAY))
+
+ # Compute FFT for temporal analysis
+ ft_images = np.array(ft_images)
+ ft_images = np.absolute(np.fft.fft(ft_images, axis=0)[:clip_size//2] * 1/clip_size)
+ ft_images = torch.from_numpy(ft_images).cuda()
+ ft_images = ft_images.unsqueeze(0)
+
+ # Prepare image tensor
+ images = torch.stack(images_tensor, dim=1)
+ images = images.unsqueeze(0)
+ images = images.cuda()
+
+ # Run model inference
+ with torch.no_grad():
+ output = model(images, ft_images)
+ output = F.sigmoid(output)
+ output = output.squeeze(0)
+
+ pred = float(output.item())
+
+ # Store predictions for each frame
+ for f_id in frame_ids:
+ if f_id not in frame_res:
+ frame_res[f_id] = []
+ frame_res[f_id].append(pred)
+ preds.append(pred)
+
+
+ # Aggregate results
+ mean_pred = np.mean(preds)
+ print(f"Average prediction score: {mean_pred:.4f}")
+
+ # Prepare final results
+ boxes = []
+ scores = []
+
+ for frame_idx in range(len(frames)):
+ if frame_idx in frame_res:
+ pred_prob = np.mean(frame_res[frame_idx])
+ rect = frame_boxes[frame_idx]
+ else:
+ pred_prob = None
+ rect = None
+ scores.append(pred_prob)
+ boxes.append(rect)
+
+ # Save results to video
+ print(f"Saving results to {out_file}")
+ SupplyWriter(args.video, out_file, 0.002584857167676091).run(frames, scores, boxes)
+ print("Inference completed successfully!")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/clean/video/pwtf_dvd/inference/test_tools/__init__.py b/clean/video/pwtf_dvd/inference/test_tools/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/clean/video/pwtf_dvd/inference/test_tools/common.py b/clean/video/pwtf_dvd/inference/test_tools/common.py
new file mode 100644
index 0000000000000000000000000000000000000000..e76ac698b8fe9a32dfbdf4e294d5afa521250e71
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/test_tools/common.py
@@ -0,0 +1,122 @@
+import os
+
+os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"
+
+from .ct.detection.utils import grab_all_frames, get_valid_faces, sample_chunks
+from .ct.operations import multiple_tracking
+import numpy as np
+from .ct.face_alignment import LandmarkPredictor
+from .ct.detection import FaceDetector
+import cv2
+from .utils import flatten,partition
+
+
+detector = FaceDetector(0)
+predictor = LandmarkPredictor(0)
+
+
+def get_five(ldm68):
+ groups = [range(36, 42), range(42, 48), [30], [48], [54]]
+ points = []
+ for group in groups:
+ points.append(ldm68[group].mean(0))
+ return np.array(points)
+
+
+def get_bbox(mask):
+ try:
+ y, x = np.nonzero(mask[..., 0])
+ return x.min() - 1, y.min() - 1, x.max() + 1, y.max() + 1
+ except:
+ return None
+
+
+def get_bigger_box(image, box, scale=0.5):
+ height, width = image.shape[:2]
+ box = np.rint(box).astype(np.int)
+ new_box = box.reshape(2, 2)
+ size = new_box[1] - new_box[0]
+ diff = scale * size
+ diff = diff[None, :] * np.array([-1, 1])[:, None]
+ new_box = new_box + diff
+ new_box[:, 0] = np.clip(new_box[:, 0], 0, width - 1)
+ new_box[:, 1] = np.clip(new_box[:, 1], 0, height - 1)
+ new_box = np.rint(new_box).astype(np.int)
+ return new_box.reshape(-1)
+
+
+def process_bigger_clips(clips, dete_res, clip_size, step, scale=0.5):
+ assert len(clips) % clip_size == 0
+ detect_results = sample_chunks(dete_res, clip_size, step)
+ clips = sample_chunks(clips, clip_size, step)
+ new_clips = []
+ for i, (frame_clip, record_clip) in enumerate(zip(clips, detect_results)):
+ tracks = multiple_tracking(record_clip)
+ for j, track in enumerate(tracks):
+ new_images = []
+ for (box, ldm, _), frame in zip(track, frame_clip):
+ big_box = get_bigger_box(frame, box, scale)
+ x1, y1, x2, y2 = big_box
+ top_left = big_box[:2][None, :]
+ new_ldm5 = ldm - top_left
+ box = np.rint(box).astype(np.int)
+ new_box = (box.reshape(2, 2) - top_left).reshape(-1)
+ feed = LandmarkPredictor.prepare_feed(frame, box)
+ ldm68 = predictor(feed) - top_left
+ new_images.append(
+ (frame[y1:y2, x1:x2], big_box, new_box, new_ldm5, ldm68)
+ )
+ new_clips.append(new_images)
+ return new_clips
+
+
+def post(detected_faces):
+ return [[face[:4], None, face[-1]] for face in detected_faces]
+
+
+def check(detect_res):
+ return min([len(faces) for faces in detect_res]) != 0
+
+
+def detect_all(file, sfd_only=False, return_frames=False, max_size=None):
+ frames = grab_all_frames(file, max_size=max_size, cvt=True)
+ if not sfd_only:
+ detect_res = flatten(
+ [detector.detect(item) for item in partition(frames, 50)]
+ )
+ detect_res = get_valid_faces(detect_res, thres=0.5)
+ else:
+ raise NotImplementedError
+
+ all_68 = get_lm68(frames, detect_res)
+ if not return_frames:
+ return detect_res, all_68
+ else:
+ return detect_res, all_68, frames
+
+
+def get_lm68(frames, detect_res):
+ assert len(frames) == len(detect_res)
+ frame_count = len(frames)
+ all_68 = []
+ for i in range(frame_count):
+ frame = frames[i]
+ faces = detect_res[i]
+ if len(faces) == 0:
+ res_68 = []
+ else:
+ feeds = []
+ for face in faces:
+ assert len(face) == 3
+ box = face[0]
+ feed = LandmarkPredictor.prepare_feed(frame, box)
+ feeds.append(feed)
+ res_68 = predictor(feeds)
+ assert len(res_68) == len(faces)
+ for face, l_68 in zip(faces, res_68):
+ if face[1] is None:
+ face[1] = get_five(l_68)
+ all_68.append(res_68)
+
+ assert len(all_68) == len(detect_res)
+ return all_68
diff --git a/clean/video/pwtf_dvd/inference/test_tools/ct/detection/__init__.py b/clean/video/pwtf_dvd/inference/test_tools/ct/detection/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..23447e84f4f5f23a4c4818df2f26cc19a9200363
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/test_tools/ct/detection/__init__.py
@@ -0,0 +1,56 @@
+import cv2
+from .detector import RetinaFace
+from .utils import *
+
+
+def assert_bounded(val, low, up):
+ return val >= low and val < up
+
+
+def check_valid(face, w, h):
+ box = face[0]
+ if box[0] > box[2]:
+ return False
+ if box[1] > box[3]:
+ return False
+ for idx, bound in zip([0, 1, 2, 3], [w, h, w, h]):
+ if not assert_bounded(box[idx], 0, bound):
+ return False
+ pts = face[1]
+ for p in pts:
+ for idx, bound in zip([0, 1], [w, h]):
+ if not assert_bounded(p[idx], 0, bound):
+ return False
+ return True
+
+
+def post_detect(detect_results, scale, w, h):
+ new_results = []
+ for frame_faces in detect_results:
+ new_frame_faces = []
+ for box, ldm, score in frame_faces:
+ box = box * scale
+ ldm = ldm * scale
+ face = (box, ldm, score)
+ if check_valid(face, w=w, h=h):
+ new_frame_faces.append(face)
+ new_results.append(new_frame_faces)
+ return new_results
+
+
+class FaceDetector(RetinaFace):
+ def scale_detect(self, images):
+ max_res = 1920
+ h, w = images[0].shape[:2]
+ if max(h, w) > max_res:
+ init_scale = max(h, w) / max_res
+ else:
+ init_scale = 1
+ resize_scale = 2 * init_scale
+ resize_w = int(w / resize_scale)
+ resize_h = int(h / resize_scale)
+ detect_input = [cv2.resize(frame, (resize_w, resize_h)) for frame in images]
+ detect_results = post_detect(
+ self.detect(detect_input), scale=resize_scale, w=w, h=h,
+ )
+ return detect_results
diff --git a/clean/video/pwtf_dvd/inference/test_tools/ct/detection/alignment.py b/clean/video/pwtf_dvd/inference/test_tools/ct/detection/alignment.py
new file mode 100644
index 0000000000000000000000000000000000000000..64692a3490c7e8e29e399bd174c5906716b3e6fc
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/test_tools/ct/detection/alignment.py
@@ -0,0 +1,608 @@
+from itertools import product as product
+from math import ceil
+
+import numpy as np
+import torch
+import torch.backends.cudnn as cudnn
+import torch.nn as nn
+import torch.nn.functional as F
+import torchvision.models._utils as _utils
+
+
+def conv_bn(inp, oup, stride=1, leaky=0):
+ return nn.Sequential(
+ nn.Conv2d(inp, oup, 3, stride, 1, bias=False),
+ nn.BatchNorm2d(oup),
+ nn.LeakyReLU(negative_slope=leaky, inplace=True),
+ )
+
+
+def conv_bn_no_relu(inp, oup, stride):
+ return nn.Sequential(
+ nn.Conv2d(inp, oup, 3, stride, 1, bias=False), nn.BatchNorm2d(oup),
+ )
+
+
+def conv_bn1X1(inp, oup, stride, leaky=0):
+ return nn.Sequential(
+ nn.Conv2d(inp, oup, 1, stride, padding=0, bias=False),
+ nn.BatchNorm2d(oup),
+ nn.LeakyReLU(negative_slope=leaky, inplace=True),
+ )
+
+
+def conv_dw(inp, oup, stride, leaky=0.1):
+ return nn.Sequential(
+ nn.Conv2d(inp, inp, 3, stride, 1, groups=inp, bias=False),
+ nn.BatchNorm2d(inp),
+ nn.LeakyReLU(negative_slope=leaky, inplace=True),
+ nn.Conv2d(inp, oup, 1, 1, 0, bias=False),
+ nn.BatchNorm2d(oup),
+ nn.LeakyReLU(negative_slope=leaky, inplace=True),
+ )
+
+
+class SSH(nn.Module):
+ def __init__(self, in_channel, out_channel):
+ super(SSH, self).__init__()
+ assert out_channel % 4 == 0
+ leaky = 0
+ if out_channel <= 64:
+ leaky = 0.1
+ self.conv3X3 = conv_bn_no_relu(in_channel, out_channel // 2, stride=1)
+
+ self.conv5X5_1 = conv_bn(in_channel, out_channel // 4, stride=1, leaky=leaky)
+ self.conv5X5_2 = conv_bn_no_relu(out_channel // 4, out_channel // 4, stride=1)
+
+ self.conv7X7_2 = conv_bn(
+ out_channel // 4, out_channel // 4, stride=1, leaky=leaky
+ )
+ self.conv7x7_3 = conv_bn_no_relu(out_channel // 4, out_channel // 4, stride=1)
+
+ def forward(self, input):
+ conv3X3 = self.conv3X3(input)
+
+ conv5X5_1 = self.conv5X5_1(input)
+ conv5X5 = self.conv5X5_2(conv5X5_1)
+
+ conv7X7_2 = self.conv7X7_2(conv5X5_1)
+ conv7X7 = self.conv7x7_3(conv7X7_2)
+
+ out = torch.cat([conv3X3, conv5X5, conv7X7], dim=1)
+ out = F.relu(out)
+ return out
+
+
+class FPN(nn.Module):
+ def __init__(self, in_channels_list, out_channels):
+ super(FPN, self).__init__()
+ leaky = 0
+ if out_channels <= 64:
+ leaky = 0.1
+ self.output1 = conv_bn1X1(
+ in_channels_list[0], out_channels, stride=1, leaky=leaky
+ )
+ self.output2 = conv_bn1X1(
+ in_channels_list[1], out_channels, stride=1, leaky=leaky
+ )
+ self.output3 = conv_bn1X1(
+ in_channels_list[2], out_channels, stride=1, leaky=leaky
+ )
+
+ self.merge1 = conv_bn(out_channels, out_channels, leaky=leaky)
+ self.merge2 = conv_bn(out_channels, out_channels, leaky=leaky)
+
+ def forward(self, input):
+ # names = list(input.keys())
+ input = list(input.values())
+
+ output1 = self.output1(input[0])
+ output2 = self.output2(input[1])
+ output3 = self.output3(input[2])
+
+ up3 = F.interpolate(
+ output3, size=[output2.size(2), output2.size(3)], mode="nearest"
+ )
+ output2 = output2 + up3
+ output2 = self.merge2(output2)
+
+ up2 = F.interpolate(
+ output2, size=[output1.size(2), output1.size(3)], mode="nearest"
+ )
+ output1 = output1 + up2
+ output1 = self.merge1(output1)
+
+ out = [output1, output2, output3]
+ return out
+
+
+class MobileNetV1(nn.Module):
+ def __init__(self):
+ super(MobileNetV1, self).__init__()
+ self.stage1 = nn.Sequential(
+ conv_bn(3, 8, 2, leaky=0.1), # 3
+ conv_dw(8, 16, 1), # 7
+ conv_dw(16, 32, 2), # 11
+ conv_dw(32, 32, 1), # 19
+ conv_dw(32, 64, 2), # 27
+ conv_dw(64, 64, 1), # 43
+ )
+ self.stage2 = nn.Sequential(
+ conv_dw(64, 128, 2), # 43 + 16 = 59
+ conv_dw(128, 128, 1), # 59 + 32 = 91
+ conv_dw(128, 128, 1), # 91 + 32 = 123
+ conv_dw(128, 128, 1), # 123 + 32 = 155
+ conv_dw(128, 128, 1), # 155 + 32 = 187
+ conv_dw(128, 128, 1), # 187 + 32 = 219
+ )
+ self.stage3 = nn.Sequential(
+ conv_dw(128, 256, 2), # 219 +3 2 = 241
+ conv_dw(256, 256, 1), # 241 + 64 = 301
+ )
+ self.avg = nn.AdaptiveAvgPool2d((1, 1))
+ self.fc = nn.Linear(256, 1000)
+
+ def forward(self, x):
+ x = self.stage1(x)
+ x = self.stage2(x)
+ x = self.stage3(x)
+ x = self.avg(x)
+ # x = self.model(x)
+ x = x.view(-1, 256)
+ x = self.fc(x)
+ return x
+
+
+class ClassHead(nn.Module):
+ def __init__(self, inchannels=512, num_anchors=3):
+ super(ClassHead, self).__init__()
+ self.num_anchors = num_anchors
+ self.conv1x1 = nn.Conv2d(
+ inchannels, self.num_anchors * 2, kernel_size=(1, 1), stride=1, padding=0
+ )
+
+ def forward(self, x):
+ out = self.conv1x1(x)
+ out = out.permute(0, 2, 3, 1).contiguous()
+
+ return out.view(out.shape[0], -1, 2)
+
+
+class BboxHead(nn.Module):
+ def __init__(self, inchannels=512, num_anchors=3):
+ super(BboxHead, self).__init__()
+ self.conv1x1 = nn.Conv2d(
+ inchannels, num_anchors * 4, kernel_size=(1, 1), stride=1, padding=0
+ )
+
+ def forward(self, x):
+ out = self.conv1x1(x)
+ out = out.permute(0, 2, 3, 1).contiguous()
+
+ return out.view(out.shape[0], -1, 4)
+
+
+class LandmarkHead(nn.Module):
+ def __init__(self, inchannels=512, num_anchors=3):
+ super(LandmarkHead, self).__init__()
+ self.conv1x1 = nn.Conv2d(
+ inchannels, num_anchors * 10, kernel_size=(1, 1), stride=1, padding=0
+ )
+
+ def forward(self, x):
+ out = self.conv1x1(x)
+ out = out.permute(0, 2, 3, 1).contiguous()
+
+ return out.view(out.shape[0], -1, 10)
+
+
+class RetinaFace(nn.Module):
+ def __init__(self, cfg=None, phase="train"):
+ """
+ :param cfg: Network related settings.
+ :param phase: train or test.
+ """
+ super(RetinaFace, self).__init__()
+ self.phase = phase
+ backbone = None
+ if cfg["name"] == "mobilenet0.25":
+ backbone = MobileNetV1()
+ elif cfg["name"] == "Resnet50":
+ import torchvision.models as models
+
+ backbone = models.resnet50(pretrained=cfg["pretrain"])
+
+ self.body = _utils.IntermediateLayerGetter(backbone, cfg["return_layers"])
+ in_channels_stage2 = cfg["in_channel"]
+ in_channels_list = [
+ in_channels_stage2 * 2,
+ in_channels_stage2 * 4,
+ in_channels_stage2 * 8,
+ ]
+ out_channels = cfg["out_channel"]
+ self.fpn = FPN(in_channels_list, out_channels)
+ self.ssh1 = SSH(out_channels, out_channels)
+ self.ssh2 = SSH(out_channels, out_channels)
+ self.ssh3 = SSH(out_channels, out_channels)
+
+ self.ClassHead = self._make_class_head(fpn_num=3, inchannels=cfg["out_channel"])
+ self.BboxHead = self._make_bbox_head(fpn_num=3, inchannels=cfg["out_channel"])
+ self.LandmarkHead = self._make_landmark_head(
+ fpn_num=3, inchannels=cfg["out_channel"]
+ )
+
+ def _make_class_head(self, fpn_num=3, inchannels=64, anchor_num=2):
+ classhead = nn.ModuleList()
+ for i in range(fpn_num):
+ classhead.append(ClassHead(inchannels, anchor_num))
+ return classhead
+
+ def _make_bbox_head(self, fpn_num=3, inchannels=64, anchor_num=2):
+ bboxhead = nn.ModuleList()
+ for i in range(fpn_num):
+ bboxhead.append(BboxHead(inchannels, anchor_num))
+ return bboxhead
+
+ def _make_landmark_head(self, fpn_num=3, inchannels=64, anchor_num=2):
+ landmarkhead = nn.ModuleList()
+ for i in range(fpn_num):
+ landmarkhead.append(LandmarkHead(inchannels, anchor_num))
+ return landmarkhead
+
+ def forward(self, inputs):
+ out = self.body(inputs)
+
+ # FPN
+ fpn = self.fpn(out)
+
+ # SSH
+ feature1 = self.ssh1(fpn[0])
+ feature2 = self.ssh2(fpn[1])
+ feature3 = self.ssh3(fpn[2])
+ features = [feature1, feature2, feature3]
+
+ bbox_regressions = torch.cat(
+ [self.BboxHead[i](feature) for i, feature in enumerate(features)], dim=1
+ )
+ classifications = torch.cat(
+ [self.ClassHead[i](feature) for i, feature in enumerate(features)], dim=1
+ )
+ ldm_regressions = torch.cat(
+ [self.LandmarkHead[i](feature) for i, feature in enumerate(features)], dim=1
+ )
+
+ if self.phase == "train":
+ output = (bbox_regressions, classifications, ldm_regressions)
+ else:
+ output = (
+ bbox_regressions,
+ F.softmax(classifications, dim=-1),
+ ldm_regressions,
+ )
+ return output
+
+
+# Adapted from https://github.com/Hakuyume/chainer-ssd
+def decode(loc, priors, variances):
+ boxes = torch.cat(
+ (
+ priors[:, :2] + loc[:, :2] * variances[0] * priors[:, 2:],
+ priors[:, 2:] * torch.exp(loc[:, 2:] * variances[1]),
+ ),
+ 1,
+ )
+ boxes[:, :2] -= boxes[:, 2:] / 2
+ boxes[:, 2:] += boxes[:, :2]
+ return boxes
+
+
+def decode_landm(pre, priors, variances):
+ landms = torch.cat(
+ (
+ priors[:, :2] + pre[:, :2] * variances[0] * priors[:, 2:],
+ priors[:, :2] + pre[:, 2:4] * variances[0] * priors[:, 2:],
+ priors[:, :2] + pre[:, 4:6] * variances[0] * priors[:, 2:],
+ priors[:, :2] + pre[:, 6:8] * variances[0] * priors[:, 2:],
+ priors[:, :2] + pre[:, 8:10] * variances[0] * priors[:, 2:],
+ ),
+ dim=1,
+ )
+ return landms
+
+
+def py_cpu_nms(dets, thresh):
+ """Pure Python NMS baseline."""
+ x1 = dets[:, 0]
+ y1 = dets[:, 1]
+ x2 = dets[:, 2]
+ y2 = dets[:, 3]
+ scores = dets[:, 4]
+
+ areas = (x2 - x1 + 1) * (y2 - y1 + 1)
+ order = scores.argsort()[::-1]
+
+ keep = []
+ while order.size > 0:
+ i = order[0]
+ keep.append(i)
+ xx1 = np.maximum(x1[i], x1[order[1:]])
+ yy1 = np.maximum(y1[i], y1[order[1:]])
+ xx2 = np.minimum(x2[i], x2[order[1:]])
+ yy2 = np.minimum(y2[i], y2[order[1:]])
+
+ w = np.maximum(0.0, xx2 - xx1 + 1)
+ h = np.maximum(0.0, yy2 - yy1 + 1)
+ inter = w * h
+ ovr = inter / (areas[i] + areas[order[1:]] - inter)
+
+ inds = np.where(ovr <= thresh)[0]
+ order = order[inds + 1]
+
+ return keep
+
+
+class PriorBox(object):
+ def __init__(self, cfg, image_size=None, phase="train"):
+ super(PriorBox, self).__init__()
+ self.min_sizes = cfg["min_sizes"]
+ self.steps = cfg["steps"]
+ self.clip = cfg["clip"]
+ self.image_size = image_size
+ self.feature_maps = [
+ [ceil(self.image_size[0] / step), ceil(self.image_size[1] / step)]
+ for step in self.steps
+ ]
+ self.name = "s"
+
+ def forward(self):
+ anchors = []
+ for k, f in enumerate(self.feature_maps):
+ min_sizes = self.min_sizes[k]
+ for i, j in product(range(f[0]), range(f[1])):
+ for min_size in min_sizes:
+ s_kx = min_size / self.image_size[1]
+ s_ky = min_size / self.image_size[0]
+ dense_cx = [
+ x * self.steps[k] / self.image_size[1] for x in [j + 0.5]
+ ]
+ dense_cy = [
+ y * self.steps[k] / self.image_size[0] for y in [i + 0.5]
+ ]
+ for cy, cx in product(dense_cy, dense_cx):
+ anchors += [cx, cy, s_kx, s_ky]
+
+ # back to torch land
+ output = torch.Tensor(anchors).view(-1, 4)
+ if self.clip:
+ output.clamp_(max=1, min=0)
+ return output
+
+
+cfg_mnet = {
+ "name": "mobilenet0.25",
+ "min_sizes": [[16, 32], [64, 128], [256, 512]],
+ "steps": [8, 16, 32],
+ "variance": [0.1, 0.2],
+ "clip": False,
+ "loc_weight": 2.0,
+ "gpu_train": True,
+ "batch_size": 32,
+ "ngpu": 1,
+ "epoch": 250,
+ "decay1": 190,
+ "decay2": 220,
+ "image_size": 640,
+ "pretrain": True,
+ "return_layers": {"stage1": 1, "stage2": 2, "stage3": 3},
+ "in_channel": 32,
+ "out_channel": 64,
+}
+
+cfg_re50 = {
+ "name": "Resnet50",
+ "min_sizes": [[16, 32], [64, 128], [256, 512]],
+ "steps": [8, 16, 32],
+ "variance": [0.1, 0.2],
+ "clip": False,
+ "loc_weight": 2.0,
+ "gpu_train": True,
+ "batch_size": 24,
+ "ngpu": 4,
+ "epoch": 100,
+ "decay1": 70,
+ "decay2": 90,
+ "image_size": 840,
+ "pretrain": False,
+ "return_layers": {"layer2": 1, "layer3": 2, "layer4": 3},
+ "in_channel": 256,
+ "out_channel": 256,
+}
+
+
+def check_keys(model, pretrained_state_dict):
+ ckpt_keys = set(pretrained_state_dict.keys())
+ model_keys = set(model.state_dict().keys())
+ used_pretrained_keys = model_keys & ckpt_keys
+ assert len(used_pretrained_keys) > 0, "load NONE from pretrained checkpoint"
+ return True
+
+
+def remove_prefix(state_dict, prefix):
+ """ Old style model is stored with all names of parameters sharing common prefix 'module.' """
+ f = lambda x: x.split(prefix, 1)[-1] if x.startswith(prefix) else x
+ return {f(key): value for key, value in state_dict.items()}
+
+
+def load_model(model, pretrained_path, load_to_cpu):
+ if load_to_cpu:
+ if pretrained_path is None:
+ url = "https://github.com/yinglinzheng/face_weights/releases/download/v1/mobilenet0.25_Final.pth"
+ pretrained_dict = torch.utils.model_zoo.load_url(url)
+ else:
+ pretrained_dict = torch.load(
+ pretrained_path, map_location=lambda storage, loc: storage
+ )
+ else:
+ device = torch.cuda.current_device()
+ pretrained_dict = torch.load(
+ pretrained_path, map_location=lambda storage, loc: storage.cuda(device)
+ )
+ if "state_dict" in pretrained_dict.keys():
+ pretrained_dict = remove_prefix(pretrained_dict["state_dict"], "module.")
+ else:
+ pretrained_dict = remove_prefix(pretrained_dict, "module.")
+ check_keys(model, pretrained_dict)
+ model.load_state_dict(pretrained_dict, strict=False)
+ return model
+
+
+def load_net(model_path, device, network="mobilenet"):
+ if network == "mobilenet":
+ cfg = cfg_mnet
+ elif network == "resnet50":
+ cfg = cfg_re50
+ # net and model
+ net = RetinaFace(cfg=cfg, phase="test")
+ net = load_model(net, model_path, True)
+ net.eval()
+ cudnn.benchmark = True
+ net = net.to(device)
+ return net
+
+
+def parse_det(det):
+ landmarks = det[5:].reshape(5, 2)
+ box = det[:4]
+ score = det[4]
+ return box, landmarks, score
+
+
+def post_process(
+ loc,
+ conf,
+ landms,
+ prior_data,
+ cfg,
+ scale,
+ scale1,
+ resize,
+ confidence_threshold,
+ top_k,
+ nms_threshold,
+ keep_top_k,
+):
+ boxes = decode(loc, prior_data, cfg["variance"])
+ boxes = boxes * scale / resize
+ boxes = boxes.cpu().numpy()
+ scores = conf.cpu().numpy()[:, 1]
+ landms_copy = decode_landm(landms, prior_data, cfg["variance"])
+
+ landms_copy = landms_copy * scale1 / resize
+ landms_copy = landms_copy.cpu().numpy()
+
+ # ignore low scores
+ inds = np.where(scores > confidence_threshold)[0]
+ boxes = boxes[inds]
+ landms_copy = landms_copy[inds]
+ scores = scores[inds]
+
+ # keep top-K before NMS
+ order = scores.argsort()[::-1][:top_k]
+ boxes = boxes[order]
+ landms_copy = landms_copy[order]
+ scores = scores[order]
+
+ # do NMS
+ dets = np.hstack((boxes, scores[:, np.newaxis])).astype(np.float32, copy=False)
+ keep = py_cpu_nms(dets, nms_threshold)
+ # keep = nms(dets, args.nms_threshold,force_cpu=args.cpu)
+ dets = dets[keep, :]
+ landms_copy = landms_copy[keep]
+
+ # keep top-K faster NMS
+ dets = dets[:keep_top_k, :]
+ landms_copy = landms_copy[:keep_top_k, :]
+
+ dets = np.concatenate((dets, landms_copy), axis=1)
+ # show image
+ dets = sorted(dets, key=lambda x: x[4], reverse=True)
+ dets = [parse_det(x) for x in dets]
+
+ return dets
+
+
+def batch_detect(net, images, device, is_tensor=False, normalized=False):
+ with torch.no_grad():
+ confidence_threshold = 0.02
+ cfg = cfg_mnet
+ top_k = 5000
+ nms_threshold = 0.4
+ keep_top_k = 750
+ resize = 1
+ if not is_tensor:
+ try:
+ img = np.float32(images)
+ except ValueError:
+ raise NotImplementedError("Input images must of same size")
+ img = torch.from_numpy(img)
+ else:
+ img = images.float()
+ img = img.to(device)
+ mean = (
+ torch.as_tensor([104, 117, 123], dtype=img.dtype, device=img.device)
+ .unsqueeze(0)
+ .unsqueeze(0)
+ .unsqueeze(0)
+ )
+ img -= mean
+ img = img.permute(0, 3, 1, 2)
+ (batch_size, _, im_height, im_width,) = img.shape
+ scale = torch.as_tensor(
+ [im_width, im_height, im_width, im_height],
+ dtype=img.dtype,
+ device=img.device,
+ )
+ scale = scale.to(device)
+
+ loc, conf, landms = net(img) # forward pass
+
+ priorbox = PriorBox(cfg, image_size=(im_height, im_width))
+ priors = priorbox.forward()
+ prior_data = priors.to(device)
+ scale1 = torch.as_tensor(
+ [
+ img.shape[3],
+ img.shape[2],
+ img.shape[3],
+ img.shape[2],
+ img.shape[3],
+ img.shape[2],
+ img.shape[3],
+ img.shape[2],
+ img.shape[3],
+ img.shape[2],
+ ],
+ dtype=img.dtype,
+ device=img.device,
+ )
+ scale1 = scale1.to(device)
+
+ all_dets = [
+ post_process(
+ loc_i,
+ conf_i,
+ landms_i,
+ prior_data,
+ cfg,
+ scale,
+ scale1,
+ resize,
+ confidence_threshold,
+ top_k,
+ nms_threshold,
+ keep_top_k,
+ )
+ for loc_i, conf_i, landms_i in zip(loc, conf, landms)
+ ]
+
+ return all_dets
diff --git a/clean/video/pwtf_dvd/inference/test_tools/ct/detection/detector.py b/clean/video/pwtf_dvd/inference/test_tools/ct/detection/detector.py
new file mode 100644
index 0000000000000000000000000000000000000000..f38050e7a050eeb05323e7d710a63c2bf1a12455
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/test_tools/ct/detection/detector.py
@@ -0,0 +1,46 @@
+import os
+
+import numpy as np
+import torch
+
+from .alignment import load_net, batch_detect
+
+
+def get_project_dir():
+ current_path = os.path.abspath(os.path.join(__file__, "../"))
+ return current_path
+
+
+def relative(path):
+ path = os.path.join(get_project_dir(), path)
+ return os.path.abspath(path)
+
+
+class RetinaFace:
+ def __init__(
+ self, gpu_id=-1, model_path=None, network="mobilenet",
+ ):
+ self.gpu_id = gpu_id
+ self.device = (
+ torch.device("cpu") if gpu_id == -1 else torch.device("cuda", gpu_id)
+ )
+ self.model = load_net(model_path, self.device, network)
+
+ def detect(self, images):
+ if isinstance(images, np.ndarray):
+ if len(images.shape) == 3:
+ return batch_detect(self.model, [images], self.device)[0]
+ elif len(images.shape) == 4:
+ return batch_detect(self.model, images, self.device)
+ elif isinstance(images, list):
+ return batch_detect(self.model, np.array(images), self.device)
+ elif isinstance(images, torch.Tensor):
+ if len(images.shape) == 3:
+ return batch_detect(self.model, images.unsqueeze(0), self.device)[0]
+ elif len(images.shape) == 4:
+ return batch_detect(self.model, images, self.device)
+ else:
+ raise NotImplementedError()
+
+ def __call__(self, images):
+ return self.detect(images)
diff --git a/clean/video/pwtf_dvd/inference/test_tools/ct/detection/utils.py b/clean/video/pwtf_dvd/inference/test_tools/ct/detection/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..512d824f02645ae9473331a553b18850e642b08f
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/test_tools/ct/detection/utils.py
@@ -0,0 +1,146 @@
+import cv2
+from test_tools.utils import flatten
+import numpy as np
+
+
+def chunks(l, n, step=None):
+ if step is None:
+ step = n
+ return [l[i : i + n] for i in range(0, len(l), step)]
+
+
+def sample_chunks(l, n, step=None):
+ return [l[i : i + n] for i in range(0, len(l), step) if i + n <= len(l)]
+
+
+def grab_all_frames(path, max_size, cvt=False):
+ capture = cv2.VideoCapture(path)
+ ret = True
+ frames = []
+ while ret:
+ ret, frame = capture.read()
+ if ret:
+ if cvt:
+ frame = frame[..., ::-1]
+ frames.append(frame)
+ if len(frames) == max_size:
+ break
+ capture.release()
+ return frames
+
+
+def get_clips_uniform(path, count, clip_size):
+ capture = cv2.VideoCapture(path)
+ n_frames = int(capture.get(cv2.CAP_PROP_FRAME_COUNT))
+ max_clip_available = n_frames + 1 - clip_size
+ if count > max_clip_available:
+ count = max_clip_available
+ final_start = max_clip_available - 1
+ start_indices = np.linspace(0, final_start, count, endpoint=True, dtype=np.int)
+ all_clip_idx = [list(range(start, start + clip_size)) for start in start_indices]
+ valid = set(flatten(all_clip_idx))
+ max_idx = max(valid)
+
+ frames = {}
+ for idx in range(max_idx + 1):
+ # Get the next frame, but don't decode if we're not using it.
+ ret = capture.grab()
+ if not ret:
+ continue
+
+ if idx in valid:
+ ret, frame = capture.retrieve()
+ if not ret or frame is None:
+ continue
+ else:
+ # frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
+ frames[idx] = frame
+
+ capture.release()
+ clips = []
+ for clip_idx in all_clip_idx:
+ clip = []
+ flag = True
+ for idx in clip_idx:
+ if idx not in frames:
+ flag = False
+ break
+ clip.append(frames[idx])
+ if flag:
+ clips.append(clip)
+ return clips
+
+
+def get_valid_faces(detect_results, max_count=10, thres=0.5, at_least=False):
+ new_results = []
+ for i, faces in enumerate(detect_results):
+ if len(faces) > max_count:
+ faces = faces[:max_count]
+ l = []
+ for j, face in enumerate(faces):
+ if face[-1] < thres and not (j == 0 and at_least):
+ continue
+ box, lm, score = face
+ box = box.astype(np.float32)
+ lm = lm.astype(np.float32)
+ l.append((box, lm, score))
+ new_results.append(l)
+ return new_results
+
+
+def scale_box(box, scale_h, scale_w, h, w):
+ x1, y1, x2, y2 = box.astype(np.int32)
+ center_x = (x1 + x2) // 2
+ center_y = (y1 + y2) // 2
+ box_h = int((y2 - y1) * scale_h)
+ box_w = int((x2 - x1) * scale_w)
+ new_x1 = center_x - box_w // 2
+ new_x2 = new_x1 + box_w
+ new_y1 = center_y - box_h // 2
+ new_y2 = new_y1 + box_h
+ new_x1 = max(new_x1, 0)
+ new_y1 = max(new_y1, 0)
+ new_y2 = min(new_y2, h)
+ new_x2 = min(new_x2, w)
+ return new_x1, new_y1, new_x2, new_y2
+
+
+def get_bbox(detect_res):
+ tmp_detect_res = get_valid_faces(detect_res, max_count=4, thres=0.5)
+ all_face_bboxs = []
+ for faces in tmp_detect_res:
+ all_face_bboxs.extend([face[0] for face in faces])
+ all_face_bboxs = np.array(all_face_bboxs).astype(np.int)
+ x1 = all_face_bboxs[:, 0].min()
+ x2 = all_face_bboxs[:, 2].max()
+ y1 = all_face_bboxs[:, 1].min()
+ y2 = all_face_bboxs[:, 3].max()
+
+ return x1, y1, x2, y2
+
+
+def delta_detect_res(detect_res, x1, y1):
+ diff = np.array([[x1, y1]])
+ new_detect_res = []
+ for faces in detect_res:
+ f = []
+ for face in faces:
+ box, lm, score = face
+ box = box.astype(np.float)
+ box[[0, 2]] -= x1
+ box[[1, 3]] -= y1
+ lm = lm.astype(np.float) - diff
+ f.append((box, lm, score))
+ new_detect_res.append(f)
+ return new_detect_res
+
+
+def pre_crop(clips, detect_res):
+ box = np.array(get_bbox(detect_res))
+ w = box[2] - box[0]
+ h = box[3] - box[1]
+ x1, y1, x2, y2 = scale_box(
+ box, 1.5, 1.2 if w > 2 * h else 1.5, clips[0].shape[0], clips[0].shape[1]
+ )
+ clips = np.array(clips)
+ return clips[:, y1:y2, x1:x2], delta_detect_res(detect_res, x1, y1)
diff --git a/clean/video/pwtf_dvd/inference/test_tools/ct/face_alignment/__init__.py b/clean/video/pwtf_dvd/inference/test_tools/ct/face_alignment/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..b0545f2f8c2aa872a127bf4e815c1e614a971723
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/test_tools/ct/face_alignment/__init__.py
@@ -0,0 +1 @@
+from .predictor import LandmarkPredictor
\ No newline at end of file
diff --git a/clean/video/pwtf_dvd/inference/test_tools/ct/face_alignment/basenet.py b/clean/video/pwtf_dvd/inference/test_tools/ct/face_alignment/basenet.py
new file mode 100644
index 0000000000000000000000000000000000000000..699b163e0584d56cc6d8f916b171f7ba86326efa
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/test_tools/ct/face_alignment/basenet.py
@@ -0,0 +1,107 @@
+# Backbone networks used for face landmark detection
+# Cunjian Chen (cunjian@msu.edu)
+
+import torch.nn as nn
+import torchvision.models as models
+
+
+class ConvBlock(nn.Module):
+ def __init__(self, inp, oup, k, s, p, dw=False, linear=False):
+ super(ConvBlock, self).__init__()
+ self.linear = linear
+ if dw:
+ self.conv = nn.Conv2d(inp, oup, k, s, p, groups=inp, bias=False)
+ else:
+ self.conv = nn.Conv2d(inp, oup, k, s, p, bias=False)
+ self.bn = nn.BatchNorm2d(oup)
+ if not linear:
+ self.prelu = nn.PReLU(oup)
+
+ def forward(self, x):
+ x = self.conv(x)
+ x = self.bn(x)
+ if self.linear:
+ return x
+ else:
+ return self.prelu(x)
+
+
+# SE module
+# https://github.com/wujiyang/Face_Pytorch/blob/master/backbone/cbam.py
+class SEModule(nn.Module):
+ """Squeeze and Excitation Module"""
+
+ def __init__(self, channels, reduction):
+ super(SEModule, self).__init__()
+ self.avg_pool = nn.AdaptiveAvgPool2d(1)
+ self.fc1 = nn.Conv2d(
+ channels, channels // reduction, kernel_size=1, padding=0, bias=False
+ )
+ self.relu = nn.ReLU(inplace=True)
+ self.fc2 = nn.Conv2d(
+ channels // reduction, channels, kernel_size=1, padding=0, bias=False
+ )
+ self.sigmoid = nn.Sigmoid()
+
+ def forward(self, x):
+ input = x
+ x = self.avg_pool(x)
+ x = self.fc1(x)
+ x = self.relu(x)
+ x = self.fc2(x)
+ x = self.sigmoid(x)
+
+ return input * x
+
+
+# USE global depthwise convolution layer. Compatible with MobileNetV2 (224×224), MobileNetV2_ExternalData (224×224)
+class MobileNet_GDConv(nn.Module):
+ def __init__(self, num_classes):
+ super(MobileNet_GDConv, self).__init__()
+ self.pretrain_net = models.mobilenet_v2(pretrained=False)
+ self.base_net = nn.Sequential(*list(self.pretrain_net.children())[:-1])
+ self.linear7 = ConvBlock(1280, 1280, (7, 7), 1, 0, dw=True, linear=True)
+ self.linear1 = ConvBlock(1280, num_classes, 1, 1, 0, linear=True)
+
+ def forward(self, x):
+ x = self.base_net(x)
+ x = self.linear7(x)
+ x = self.linear1(x)
+ x = x.view(x.size(0), -1)
+ return x
+
+
+# USE global depthwise convolution layer. Compatible with MobileNetV2 (56×56)
+class MobileNet_GDConv_56(nn.Module):
+ def __init__(self, num_classes):
+ super(MobileNet_GDConv_56, self).__init__()
+ self.pretrain_net = models.mobilenet_v2(pretrained=False)
+ self.base_net = nn.Sequential(*list(self.pretrain_net.children())[:-1])
+ self.linear7 = ConvBlock(1280, 1280, (2, 2), 1, 0, dw=True, linear=True)
+ self.linear1 = ConvBlock(1280, num_classes, 1, 1, 0, linear=True)
+
+ def forward(self, x):
+ x = self.base_net(x)
+ x = self.linear7(x)
+ x = self.linear1(x)
+ x = x.view(x.size(0), -1)
+ return x
+
+
+# MobileNetV2 with SE; Compatible with MobileNetV2_SE (224×224) and MobileNetV2_SE_RE (224×224)
+class MobileNet_GDConv_SE(nn.Module):
+ def __init__(self, num_classes):
+ super(MobileNet_GDConv_SE, self).__init__()
+ self.pretrain_net = models.mobilenet_v2(pretrained=True)
+ self.base_net = nn.Sequential(*list(self.pretrain_net.children())[:-1])
+ self.linear7 = ConvBlock(1280, 1280, (7, 7), 1, 0, dw=True, linear=True)
+ self.linear1 = ConvBlock(1280, num_classes, 1, 1, 0, linear=True)
+ self.attention = SEModule(1280, 8)
+
+ def forward(self, x):
+ x = self.base_net(x)
+ x = self.attention(x)
+ x = self.linear7(x)
+ x = self.linear1(x)
+ x = x.view(x.size(0), -1)
+ return x
diff --git a/clean/video/pwtf_dvd/inference/test_tools/ct/face_alignment/predictor.py b/clean/video/pwtf_dvd/inference/test_tools/ct/face_alignment/predictor.py
new file mode 100644
index 0000000000000000000000000000000000000000..b210b673ab3af90d805e7fff9b0b66b00826fd1f
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/test_tools/ct/face_alignment/predictor.py
@@ -0,0 +1,143 @@
+# Face alignment demo
+# Uses MTCNN as face detector
+# Cunjian Chen (ccunjian@gmail.com)
+import torch
+import cv2
+import numpy as np
+from torch.utils.data import DataLoader
+from .basenet import MobileNet_GDConv
+
+
+def get_device(gpu_id):
+ if gpu_id > -1:
+ return torch.device(f"cuda:{str(gpu_id)}")
+ else:
+ return torch.device("cpu")
+
+
+def load_model(file):
+ model = MobileNet_GDConv(136)
+ if file is not None:
+ model.load_state_dict(torch.load(file, map_location="cpu"))
+ else:
+ url = "https://github.com/yinglinzheng/face_weights/releases/download/v1/mobilenet_224_model_best_gdconv_external.pth"
+ model.load_state_dict(torch.utils.model_zoo.load_url(url))
+ return model
+
+
+# landmark of (5L, 2L) from [0,1] to real range
+def reproject(bbox, landmark):
+ landmark_ = landmark.clone()
+ x1, y1, x2, y2 = bbox
+ w = x2 - x1
+ h = y2 - y1
+ landmark_[:, 0] *= w
+ landmark_[:, 0] += x1
+ landmark_[:, 1] *= h
+ landmark_[:, 1] += y1
+ return landmark_
+
+
+def prepare_feed(img, face):
+ height, width, _ = img.shape
+ mean = np.asarray([0.485, 0.456, 0.406])
+ std = np.asarray([0.229, 0.224, 0.225])
+ out_size = 224
+ x1, y1, x2, y2 = face[:4]
+
+ w = x2 - x1 + 1
+ h = y2 - y1 + 1
+ size = int(min([w, h]) * 1.2)
+ cx = x1 + w // 2
+ cy = y1 + h // 2
+ x1 = cx - size // 2
+ x2 = x1 + size
+ y1 = cy - size // 2
+ y2 = y1 + size
+
+ dx = max(0, -x1)
+ dy = max(0, -y1)
+ x1 = max(0, x1)
+ y1 = max(0, y1)
+
+ edx = max(0, x2 - width)
+ edy = max(0, y2 - height)
+ x2 = min(width, x2)
+ y2 = min(height, y2)
+ new_bbox = torch.Tensor([x1, y1, x2, y2]).int()
+ x1, y1, x2, y2 = new_bbox
+ cropped = img[y1:y2, x1:x2]
+ if dx > 0 or dy > 0 or edx > 0 or edy > 0:
+ cropped = cv2.copyMakeBorder(
+ cropped, int(dy), int(edy), int(dx), int(edx), cv2.BORDER_CONSTANT, 0
+ )
+ cropped_face = cv2.resize(cropped, (out_size, out_size))
+
+ if cropped_face.shape[0] <= 0 or cropped_face.shape[1] <= 0:
+ return None
+ test_face = cropped_face.copy()
+ test_face = test_face / 255.0
+ test_face = (test_face - mean) / std
+ test_face = test_face.transpose((2, 0, 1))
+ data = torch.from_numpy(test_face).float()
+ return dict(data=data, bbox=new_bbox)
+
+
+@torch.no_grad()
+def single_predict(model, feed, device):
+ landmark = model(feed["data"].unsqueeze(0).to(device)).cpu()
+ landmark = landmark.reshape(-1, 2)
+ landmark = reproject(feed["bbox"], landmark)
+ return landmark.numpy()
+
+
+@torch.no_grad()
+def batch_predict(model, feeds, device):
+ if not isinstance(feeds, list):
+ feeds = [feeds]
+ # loader = DataLoader(FeedDataset(feeds), batch_size=50, shuffle=False)
+ data = []
+ for feed in feeds:
+ data.append(feed["data"].unsqueeze(0))
+ data = torch.cat(data, 0).to(device)
+ results = []
+
+ landmarks = model(data).cpu()
+ for landmark, feed in zip(landmarks, feeds):
+ landmark = landmark.reshape(-1, 2)
+ landmark = reproject(feed["bbox"], landmark)
+ results.append(landmark.numpy())
+ return results
+
+
+@torch.no_grad()
+def batch_predict2(model, feeds, device, batch_size=None):
+ if not isinstance(feeds, list):
+ feeds = [feeds]
+ if batch_size is None:
+ batch_size = len(feeds)
+ loader = DataLoader(feeds, batch_size=len(feeds), shuffle=False)
+ results = []
+ for feed in loader:
+ landmarks = model(feed["data"].to(device)).cpu()
+ for landmark, bbox in zip(landmarks, feed["bbox"]):
+ landmark = landmark.reshape(-1, 2)
+ landmark = reproject(bbox, landmark)
+ results.append(landmark.numpy())
+ return results
+
+
+class LandmarkPredictor:
+ def __init__(self, gpu_id=0, file=None):
+ self.device = get_device(gpu_id)
+ self.model = load_model(file).to(self.device).eval()
+
+ def __call__(self, feeds):
+ results = batch_predict2(self.model, feeds, self.device)
+ if not isinstance(feeds, list):
+ results = results[0]
+ return results
+
+ @staticmethod
+ def prepare_feed(img, face):
+ return prepare_feed(img, face)
diff --git a/clean/video/pwtf_dvd/inference/test_tools/ct/face_alignment/utils.py b/clean/video/pwtf_dvd/inference/test_tools/ct/face_alignment/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..e871b155963b0d1ce6891589d32615c5fc97bb66
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/test_tools/ct/face_alignment/utils.py
@@ -0,0 +1,17 @@
+import cv2
+
+
+def drawLandmark_multiple(img, bbox, landmark):
+ """
+ Input:
+ - img: gray or RGB
+ - bbox: type of BBox
+ - landmark: reproject landmark of (5L, 2L)
+ Output:
+ - img marked with landmark and bbox
+ """
+ x1, y1, x2, y2 = bbox
+ cv2.rectangle(img, (x1, y1), (x2, y2), (0, 0, 255), 2)
+ for x, y in landmark:
+ cv2.circle(img, (int(x), int(y)), 2, (0, 255, 0), -1)
+ return img
diff --git a/clean/video/pwtf_dvd/inference/test_tools/ct/operations.py b/clean/video/pwtf_dvd/inference/test_tools/ct/operations.py
new file mode 100644
index 0000000000000000000000000000000000000000..68375fcc4efd768abcfddf39521af21d574c4aac
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/test_tools/ct/operations.py
@@ -0,0 +1,79 @@
+import os
+
+import os
+import cv2
+import numpy as np
+from .tracking.sort import iou
+
+
+def face_iou(f1, f2):
+ return iou(f1[0], f2[0])
+
+
+def simple_tracking(batch_landmarks, index=0, thres=0.5):
+ track = []
+
+ for i, faces in enumerate(batch_landmarks):
+ if i == 0:
+ if len(faces) <= index or faces[index][-1] < 0.8:
+ return None
+ if index != 0:
+ for idx in range(index):
+ if face_iou(faces[idx], faces[index]) > thres:
+ return None
+ track.append(faces[index])
+ else:
+ last = track[i - 1]
+ if len(faces) == 0:
+ return None
+ sorted_faces = sorted(faces, key=lambda x: face_iou(x, last), reverse=True)
+ if face_iou(sorted_faces[0], last) < thres:
+ return None
+ track.append(sorted_faces[0])
+ return track
+
+
+def multiple_tracking(batch_landmarks):
+ tracks = []
+ for i in range(len(batch_landmarks[0])):
+ track = simple_tracking(batch_landmarks, index=i)
+ if track is None:
+ continue
+ tracks.append(track)
+ return tracks
+
+def find_longest(detect_res):
+ fc = len(detect_res)
+ tuples = []
+ start = 0
+ end = 0
+ previous_count = -1
+ all_tracks = []
+ # start 取得到,end 取不到
+ while start < (fc - 1):
+ for end in range(start + 2, fc + 1):
+ tracks = multiple_tracking(detect_res[start:end])
+ if (len(tracks) != previous_count and previous_count != -1) or len(
+ tracks
+ ) == 0:
+ break
+ previous_count = len(tracks)
+ if end - start > 2:
+ if end != fc:
+ un_reach_end = end - 1
+ else:
+ un_reach_end = end
+ sub_tracks = multiple_tracking(detect_res[start:un_reach_end])
+ if end == fc and len(sub_tracks) == 0:
+ un_reach_end = end - 1
+ sub_tracks = multiple_tracking(detect_res[start:un_reach_end])
+ if len(sub_tracks) > 0:
+ tpl = (start, un_reach_end)
+ tuples.append(tpl)
+ all_tracks.append(sub_tracks[0])
+ else:
+ raise NotImplementedError
+ previous_count = -1
+ end = un_reach_end
+ start = end
+ return tuples, all_tracks
\ No newline at end of file
diff --git a/clean/video/pwtf_dvd/inference/test_tools/ct/tracking/__init__.py b/clean/video/pwtf_dvd/inference/test_tools/ct/tracking/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/clean/video/pwtf_dvd/inference/test_tools/ct/tracking/sort.py b/clean/video/pwtf_dvd/inference/test_tools/ct/tracking/sort.py
new file mode 100644
index 0000000000000000000000000000000000000000..dc7b0838e7110a2d3521c6d4cfefbb40cc266c23
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/test_tools/ct/tracking/sort.py
@@ -0,0 +1,285 @@
+"""
+ SORT: A Simple, Online and Realtime Tracker
+ Copyright (C) 2016 Alex Bewley alex@dynamicdetection.com
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+"""
+from __future__ import print_function
+import os.path
+import numpy as np
+import matplotlib.pyplot as plt
+import matplotlib.patches as patches
+from scipy.optimize import linear_sum_assignment
+import glob
+import time
+import argparse
+from filterpy.kalman import KalmanFilter
+
+
+def iou(bb_test, bb_gt):
+ """
+ Computes IUO between two bboxes in the form [x1,y1,x2,y2]
+ """
+ xx1 = np.maximum(bb_test[0], bb_gt[0])
+ yy1 = np.maximum(bb_test[1], bb_gt[1])
+ xx2 = np.minimum(bb_test[2], bb_gt[2])
+ yy2 = np.minimum(bb_test[3], bb_gt[3])
+ w = np.maximum(0.0, xx2 - xx1)
+ h = np.maximum(0.0, yy2 - yy1)
+ wh = w * h
+ o = wh / (
+ (bb_test[2] - bb_test[0]) * (bb_test[3] - bb_test[1])
+ + (bb_gt[2] - bb_gt[0]) * (bb_gt[3] - bb_gt[1])
+ - wh
+ )
+ return o
+
+
+def convert_bbox_to_z(bbox):
+ """
+ Takes a bounding box in the form [x1,y1,x2,y2] and returns z in the form
+ [x,y,s,r] where x,y is the centre of the box and s is the scale/area and r is
+ the aspect ratio
+ """
+ w = bbox[2] - bbox[0]
+ h = bbox[3] - bbox[1]
+ x = bbox[0] + w / 2.0
+ y = bbox[1] + h / 2.0
+ s = w * h # scale is just area
+ r = w / float(h)
+ return np.array([x, y, s, r]).reshape((4, 1))
+
+
+def convert_x_to_bbox(x, score=None):
+ """
+ Takes a bounding box in the centre form [x,y,s,r] and returns it in the form
+ [x1,y1,x2,y2] where x1,y1 is the top left and x2,y2 is the bottom right
+ """
+ w = np.sqrt(x[2] * x[3])
+ h = x[2] / w
+ if score == None:
+ return np.array(
+ [x[0] - w / 2.0, x[1] - h / 2.0, x[0] + w / 2.0, x[1] + h / 2.0]
+ ).reshape((1, 4))
+ else:
+ return np.array(
+ [x[0] - w / 2.0, x[1] - h / 2.0, x[0] + w / 2.0, x[1] + h / 2.0, score]
+ ).reshape((1, 5))
+
+
+class KalmanBoxTracker(object):
+ """
+ This class represents the internel state of individual tracked objects observed as bbox.
+ """
+
+ count = 0
+
+ def __init__(self, bbox):
+ """
+ Initialises a tracker using initial bounding box.
+ """
+ # define constant velocity model
+ self.kf = KalmanFilter(dim_x=7, dim_z=4)
+ self.kf.F = np.array(
+ [
+ [1, 0, 0, 0, 1, 0, 0],
+ [0, 1, 0, 0, 0, 1, 0],
+ [0, 0, 1, 0, 0, 0, 1],
+ [0, 0, 0, 1, 0, 0, 0],
+ [0, 0, 0, 0, 1, 0, 0],
+ [0, 0, 0, 0, 0, 1, 0],
+ [0, 0, 0, 0, 0, 0, 1],
+ ]
+ )
+ self.kf.H = np.array(
+ [
+ [1, 0, 0, 0, 0, 0, 0],
+ [0, 1, 0, 0, 0, 0, 0],
+ [0, 0, 1, 0, 0, 0, 0],
+ [0, 0, 0, 1, 0, 0, 0],
+ ]
+ )
+
+ self.kf.R[2:, 2:] *= 10.0
+ self.kf.P[
+ 4:, 4:
+ ] *= 1000.0 # give high uncertainty to the unobservable initial velocities
+ self.kf.P *= 10.0
+ self.kf.Q[-1, -1] *= 0.01
+ self.kf.Q[4:, 4:] *= 0.01
+
+ self.kf.x[:4] = convert_bbox_to_z(bbox)
+ self.time_since_update = 0
+ self.id = KalmanBoxTracker.count
+ KalmanBoxTracker.count += 1
+ self.history = []
+ self.hits = 0
+ self.hit_streak = 0
+ self.age = 0
+
+ def update(self, bbox):
+ """
+ Updates the state vector with observed bbox.
+ """
+ self.time_since_update = 0
+ self.history = []
+ self.hits += 1
+ self.hit_streak += 1
+ self.kf.update(convert_bbox_to_z(bbox))
+
+ def predict(self):
+ """
+ Advances the state vector and returns the predicted bounding box estimate.
+ """
+ if (self.kf.x[6] + self.kf.x[2]) <= 0:
+ self.kf.x[6] *= 0.0
+ self.kf.predict()
+ self.age += 1
+ if self.time_since_update > 0:
+ self.hit_streak = 0
+ self.time_since_update += 1
+ self.history.append(convert_x_to_bbox(self.kf.x))
+ return self.history[-1]
+
+ def get_state(self):
+ """
+ Returns the current bounding box estimate.
+ """
+ return convert_x_to_bbox(self.kf.x)
+
+
+def associate_detections_to_trackers(detections, trackers, iou_threshold=0.3):
+ """
+ Assigns detections to tracked object (both represented as bounding boxes)
+
+ Returns 3 lists of matches, unmatched_detections and unmatched_trackers
+ """
+ if len(trackers) == 0:
+ return (
+ np.empty((0, 2), dtype=int),
+ np.arange(len(detections)),
+ np.empty((0, 5), dtype=int),
+ )
+ iou_matrix = np.zeros((len(detections), len(trackers)), dtype=np.float32)
+
+ for d, det in enumerate(detections):
+ for t, trk in enumerate(trackers):
+ iou_matrix[d, t] = iou(det, trk)
+
+ matched_indices = linear_sum_assignment(-iou_matrix)
+ matched_indices = np.array(list(zip(*matched_indices)), dtype=np.int)
+ matched_indices.shape = (-1, 2)
+ # print(matched_indices)
+ # print(type(matched_indices))
+
+ unmatched_detections = []
+ for d, det in enumerate(detections):
+ if d not in matched_indices[:, 0]:
+ unmatched_detections.append(d)
+ unmatched_trackers = []
+ for t, trk in enumerate(trackers):
+ if t not in matched_indices[:, 1]:
+ unmatched_trackers.append(t)
+
+ # filter out matched with low IOU
+ matches = []
+ for m in matched_indices:
+ if iou_matrix[m[0], m[1]] < iou_threshold:
+ unmatched_detections.append(m[0])
+ unmatched_trackers.append(m[1])
+ else:
+ matches.append(m.reshape(1, 2))
+ if len(matches) == 0:
+ matches = np.empty((0, 2), dtype=int)
+ else:
+ matches = np.concatenate(matches, axis=0)
+
+ return matches, np.array(unmatched_detections), np.array(unmatched_trackers)
+
+
+class Sort(object):
+ def __init__(self, max_age=1, min_hits=3):
+ """
+ Sets key parameters for SORT
+ """
+ self.max_age = max_age
+ self.min_hits = min_hits
+ self.trackers = []
+ self.frame_count = 0
+
+ def update(self, dets):
+ """
+ Params:
+ dets - a numpy array of detections in the format [[x1,y1,x2,y2,score],[x1,y1,x2,y2,score],...]
+ Requires: this method must be called once for each frame even with empty detections.
+ Returns the a similar array, where the last column is the object ID.
+
+ NOTE: The number of objects returned may differ from the number of detections provided.
+ """
+ self.frame_count += 1
+ # get predicted locations from existing trackers.
+ trks = np.zeros((len(self.trackers), 5))
+ to_del = []
+ ret = []
+ for t, trk in enumerate(trks):
+ pos = self.trackers[t].predict()[0]
+ trk[:] = [pos[0], pos[1], pos[2], pos[3], 0]
+ if np.any(np.isnan(pos)):
+ to_del.append(t)
+ trks = np.ma.compress_rows(np.ma.masked_invalid(trks))
+ for t in reversed(to_del):
+ self.trackers.pop(t)
+ matched, unmatched_dets, unmatched_trks = associate_detections_to_trackers(
+ dets, trks
+ )
+
+ # update matched trackers with assigned detections
+ for t, trk in enumerate(self.trackers):
+ if t not in unmatched_trks:
+ d = matched[np.where(matched[:, 1] == t)[0], 0]
+ trk.update(dets[d, :][0])
+
+ # create and initialise new trackers for unmatched detections
+ for i in unmatched_dets:
+ trk = KalmanBoxTracker(dets[i, :])
+ self.trackers.append(trk)
+ i = len(self.trackers)
+ for trk in reversed(self.trackers):
+ d = trk.get_state()[0]
+ if (trk.time_since_update < 1) and (
+ trk.hit_streak >= self.min_hits or self.frame_count <= self.min_hits
+ ):
+ ret.append(
+ np.concatenate((d, [trk.id + 1])).reshape(1, -1)
+ ) # +1 as MOT benchmark requires positive
+ i -= 1
+ # remove dead tracklet
+ if trk.time_since_update > self.max_age:
+ self.trackers.pop(i)
+ if len(ret) > 0:
+ return np.concatenate(ret)
+ return np.empty((0, 5))
+
+
+def parse_args():
+ """Parse input arguments."""
+ parser = argparse.ArgumentParser(description="SORT demo")
+ parser.add_argument(
+ "--display",
+ dest="display",
+ help="Display online tracker output (slow) [False]",
+ action="store_true",
+ )
+ args = parser.parse_args()
+ return args
diff --git a/clean/video/pwtf_dvd/inference/test_tools/ct/tracking/tracker.py b/clean/video/pwtf_dvd/inference/test_tools/ct/tracking/tracker.py
new file mode 100644
index 0000000000000000000000000000000000000000..20dd79f41a56bcb4873e83bb9c76db9ffbf0f627
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/test_tools/ct/tracking/tracker.py
@@ -0,0 +1,27 @@
+from .sort import Sort
+import numpy as np
+
+
+def get_detections(faces):
+ detections = []
+ for face in faces:
+ x1, y1, x2, y2 = face[0]
+ detections.append((x1, y1, x2, y2, face[-1]))
+ return np.array(detections)
+
+
+def get_tracks(detect_results):
+ tracks = {}
+ mot_tracker = Sort()
+ for faces in detect_results:
+ detections = get_detections(faces)
+ track_bbs_ids = mot_tracker.update(detections)
+ for track in track_bbs_ids: # 单独框出每一张人脸
+ id = int(track[-1])
+ box = track[:4]
+ if id in tracks:
+ tracks[id].append(box)
+ else:
+ tracks[id] = [box]
+
+ return [track for id, track in tracks.items() if len(track) == len(detect_results)]
diff --git a/clean/video/pwtf_dvd/inference/test_tools/ct/utils.py b/clean/video/pwtf_dvd/inference/test_tools/ct/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..5ff180fb2a24b9e8bd673d3428e3b101da16a6b0
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/test_tools/ct/utils.py
@@ -0,0 +1,5 @@
+import cv2
+
+
+def write_img(file, img):
+ cv2.imwrite(file, img, [cv2.IMWRITE_PNG_COMPRESSION, 0])
diff --git a/clean/video/pwtf_dvd/inference/test_tools/faster_crop_align_xray.py b/clean/video/pwtf_dvd/inference/test_tools/faster_crop_align_xray.py
new file mode 100644
index 0000000000000000000000000000000000000000..3e99f2f0930e26539793e3d76d74e9df7afc186b
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/test_tools/faster_crop_align_xray.py
@@ -0,0 +1,73 @@
+import numpy as np
+import cv2
+from .warp_for_xray import (
+ estimiate_batch_transform,
+ transform_landmarks,
+ std_points_256,
+)
+import numpy as np
+
+
+class FasterCropAlignXRay:
+ """
+ 修正到统一坐标系,统一图像大小到标准尺寸
+ """
+
+ def __init__(self, size=256):
+ self.image_size = size
+ self.std_points = std_points_256 * size / 256.0
+
+ def __call__(self, landmarks, images=None, jitter=False):
+ landmarks = [landmark[:4] for landmark in landmarks]
+ ori_boxes = np.array([ori_box for _, _, _, ori_box in landmarks])
+ five_landmarks = np.array([ldm5 for _, ldm5, _, _ in landmarks])
+ landmarks68 = np.array([ldm68 for _, _, ldm68, _ in landmarks])
+ # assert landmarks68.min() > 0
+
+ left_top = ori_boxes[:, :2].min(0)
+
+ right_bottom = ori_boxes[:, 2:].max(0)
+
+ size = right_bottom - left_top
+
+ w, h = size
+
+ diff = ori_boxes[:, :2] - left_top[None, ...]
+
+ new_five_landmarks = five_landmarks + diff[:, None, :]
+ new_landmarks68 = landmarks68 + diff[:, None, :]
+
+ landmark_for_estimiate = new_five_landmarks.copy()
+ if jitter:
+ landmark_for_estimiate += np.random.uniform(
+ -4, 4, landmark_for_estimiate.shape
+ )
+
+ tfm, trans = estimiate_batch_transform(
+ landmark_for_estimiate, tgt_pts=self.std_points
+ )
+
+ transformed_landmarks68 = np.array(
+ [transform_landmarks(ldm68, trans) for ldm68 in new_landmarks68]
+ )
+
+ if images is not None:
+ transformed_images = [
+ self.process_sinlge(tfm, image, d, h, w)
+ for image, d in zip(images, diff)
+ ] # 拼接 func 的参数
+ transformed_images = np.stack(transformed_images)
+ return transformed_landmarks68, transformed_images
+ else:
+ return transformed_landmarks68
+
+ def process_sinlge(self, tfm, image, d, h, w):
+ assert isinstance(image, np.ndarray)
+ new_image = np.zeros((h, w, 3), dtype=np.uint8)
+ x, y = d
+ ih, iw, _ = image.shape
+ new_image[y : y + ih, x : x + iw] = image
+ transformed_image = cv2.warpAffine(
+ new_image, tfm, (self.image_size, self.image_size)
+ )
+ return transformed_image
diff --git a/clean/video/pwtf_dvd/inference/test_tools/supply_writer.py b/clean/video/pwtf_dvd/inference/test_tools/supply_writer.py
new file mode 100644
index 0000000000000000000000000000000000000000..0394dfbb8fc50d47984eaa937537de144e51ee81
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/test_tools/supply_writer.py
@@ -0,0 +1,49 @@
+import cv2
+
+class SupplyWriter:
+ def __init__(self, intput_video, output_video, opt_thres, rgb_input=True):
+ reader = cv2.VideoCapture(intput_video)
+ fourcc = cv2.VideoWriter_fourcc(*"XVID")
+ fps = reader.get(cv2.CAP_PROP_FPS)
+ width = int(reader.get(3))
+ height = int(reader.get(4))
+ reader.release()
+ self.padding = 40
+
+ self.writer = cv2.VideoWriter(output_video, fourcc, fps, (height, width)[::-1])
+ self.rgb_input = rgb_input
+ self.opt_thres = opt_thres
+
+ def run(self, images, scores, boxes):
+ # Text variables
+ font_face = cv2.FONT_HERSHEY_SIMPLEX
+ thickness = 5
+ font_scale = 3
+
+ for image, score, box in zip(images, scores, boxes):
+ if self.rgb_input:
+ image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
+ if box is not None:
+ label = "fake" if score > self.opt_thres else "real"
+ x1, y1, x2, y2 = box
+ x = int(x1)
+ y = int(y1)
+ w = int(x2 - x1)
+ h = int(y2 - y1)
+ color = (
+ (255, 255, 0) if label == "real" else (0, 255, 255)
+ ) # BGR 255 0
+ cv2.putText(
+ image,
+ label,
+ (x, y + h + 68),
+ font_face,
+ font_scale,
+ color,
+ thickness,
+ 2,
+ )
+ # draw box over face
+ cv2.rectangle(image, (x, y), (x + w, y + h), color, 10)
+ self.writer.write(image)
+ self.writer.release()
diff --git a/clean/video/pwtf_dvd/inference/test_tools/utils.py b/clean/video/pwtf_dvd/inference/test_tools/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..8069d72b1db1bab8155f88782b5fb6a15fb9563c
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/test_tools/utils.py
@@ -0,0 +1,115 @@
+import numpy as np
+import cv2
+import os
+import platform
+import json
+import errno
+
+
+
+def weak_check(detect_res):
+ return sum([len(faces) for faces in detect_res]) > len(detect_res) * 0.75
+
+
+def get_crop_box(shape, box, scale=0.5):
+ height, width = shape
+ box = np.rint(box).astype(np.int32)
+ new_box = box.reshape(2, 2)
+ size = new_box[1] - new_box[0]
+ diff = scale * size
+ diff = diff[None, :] * np.array([-1, 1])[:, None]
+ new_box = new_box + diff
+ new_box[:, 0] = np.clip(new_box[:, 0], 0, width - 1)
+ new_box[:, 1] = np.clip(new_box[:, 1], 0, height - 1)
+ new_box = np.rint(new_box).astype(np.int32)
+ return new_box.reshape(-1)
+
+
+def get_fps(input_file):
+ reader = cv2.VideoCapture(input_file)
+ fps = reader.get(cv2.CAP_PROP_FPS)
+ reader.release()
+ return fps
+
+
+
+def mkdir_p(dirname):
+ """Like "mkdir -p", make a dir recursively, but do nothing if the dir exists
+ 这个是线程安全的, from Lingzhi Li
+ Args:
+ dirname(str):
+ """
+ assert dirname is not None
+ if dirname == "" or os.path.isdir(dirname):
+ return
+ try:
+ os.makedirs(dirname)
+ except OSError as e:
+ if e.errno != errno.EEXIST:
+ raise e
+
+
+def mkdir(*args):
+ for folder in args:
+ if not os.path.isdir(folder):
+ mkdir_p(folder)
+
+
+def make_join(*args):
+ folder = os.path.join(*args)
+ mkdir(folder)
+ return folder
+
+
+def list_dir(folder, condition=None, key=lambda x: x, reverse=False, co_join=[]):
+ files = os.listdir(folder)
+ if condition is not None:
+ files = filter(condition, files)
+ co_join = [folder] + co_join
+ if key is not None:
+ files = sorted(files, key=key, reverse=reverse)
+ files = [(file, *[os.path.join(fold, file) for fold in co_join]) for file in files]
+ return files
+
+def get_jointer(file):
+ def jointer(folder):
+ return os.path.join(folder, file)
+
+ return jointer
+
+def flatten(l):
+ return [item for sublist in l for item in sublist]
+
+
+def is_win():
+ return platform.system() == "Windows"
+
+
+def get_postfix(post_fix):
+ return lambda x: x.endswith(post_fix)
+
+
+def partition(images, size):
+ """
+ Returns a new list with elements
+ of which is a list of certain size.
+
+ >>> partition([1, 2, 3, 4], 3)
+ [[1, 2, 3], [4]]
+ """
+ return [
+ images[i : i + size] if i + size <= len(images) else images[i:]
+ for i in range(0, len(images), size)
+ ]
+
+
+def load_json(file):
+ with open(file, "r") as f:
+ res = json.load(f)
+ return res
+
+
+def save_json(file, obj):
+ with open(file, "w", encoding="utf-8") as f:
+ json.dump(obj, f, indent=4, ensure_ascii=False)
+
diff --git a/clean/video/pwtf_dvd/inference/test_tools/warp_for_xray.py b/clean/video/pwtf_dvd/inference/test_tools/warp_for_xray.py
new file mode 100644
index 0000000000000000000000000000000000000000..ea68def0bcc6b384f1198f21fb0d72253f8085d6
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/test_tools/warp_for_xray.py
@@ -0,0 +1,574 @@
+import numpy as np
+import cv2
+
+# -*- coding: utf-8 -*-
+"""
+Created on Tue Jul 11 06:54:28 2017
+
+@author: zhaoyafei
+"""
+
+import numpy as np
+from numpy.linalg import inv, norm, lstsq
+from numpy.linalg import matrix_rank as rank
+
+"""
+Introduction:
+----------
+numpy implemetation form matlab function CP2TFORM(...)
+with 'transformtype':
+ 1) 'nonreflective similarity'
+ 2) 'similarity'
+
+
+MATLAB code:
+----------
+%--------------------------------------
+% Function findNonreflectiveSimilarity
+%
+function [trans, output] = findNonreflectiveSimilarity(uv,xy,options)
+%
+% For a nonreflective similarity:
+%
+% let sc = s*cos(theta)
+% let ss = s*sin(theta)
+%
+% [ sc -ss
+% [u v] = [x y 1] * ss sc
+% tx ty]
+%
+% There are 4 unknowns: sc,ss,tx,ty.
+%
+% Another way to write this is:
+%
+% u = [x y 1 0] * [sc
+% ss
+% tx
+% ty]
+%
+% v = [y -x 0 1] * [sc
+% ss
+% tx
+% ty]
+%
+% With 2 or more correspondence points we can combine the u equations and
+% the v equations for one linear system to solve for sc,ss,tx,ty.
+%
+% [ u1 ] = [ x1 y1 1 0 ] * [sc]
+% [ u2 ] [ x2 y2 1 0 ] [ss]
+% [ ... ] [ ... ] [tx]
+% [ un ] [ xn yn 1 0 ] [ty]
+% [ v1 ] [ y1 -x1 0 1 ]
+% [ v2 ] [ y2 -x2 0 1 ]
+% [ ... ] [ ... ]
+% [ vn ] [ yn -xn 0 1 ]
+%
+% Or rewriting the above matrix equation:
+% U = X * r, where r = [sc ss tx ty]'
+% so r = X\ U.
+%
+
+K = options.K;
+M = size(xy,1);
+x = xy(:,1);
+y = xy(:,2);
+X = [x y ones(M,1) zeros(M,1);
+ y -x zeros(M,1) ones(M,1) ];
+
+u = uv(:,1);
+v = uv(:,2);
+U = [u; v];
+
+% We know that X * r = U
+if rank(X) >= 2*K
+ r = X \ U;
+else
+ error(message('images:cp2tform:twoUniquePointsReq'))
+end
+
+sc = r(1);
+ss = r(2);
+tx = r(3);
+ty = r(4);
+
+Tinv = [sc -ss 0;
+ ss sc 0;
+ tx ty 1];
+
+T = inv(Tinv);
+T(:,3) = [0 0 1]';
+
+trans = maketform('affine', T);
+output = [];
+
+%-------------------------
+% Function findSimilarity
+%
+function [trans, output] = findSimilarity(uv,xy,options)
+%
+% The similarities are a superset of the nonreflective similarities as they may
+% also include reflection.
+%
+% let sc = s*cos(theta)
+% let ss = s*sin(theta)
+%
+% [ sc -ss
+% [u v] = [x y 1] * ss sc
+% tx ty]
+%
+% OR
+%
+% [ sc ss
+% [u v] = [x y 1] * ss -sc
+% tx ty]
+%
+% Algorithm:
+% 1) Solve for trans1, a nonreflective similarity.
+% 2) Reflect the xy data across the Y-axis,
+% and solve for trans2r, also a nonreflective similarity.
+% 3) Transform trans2r to trans2, undoing the reflection done in step 2.
+% 4) Use TFORMFWD to transform uv using both trans1 and trans2,
+% and compare the results, Returnsing the transformation corresponding
+% to the smaller L2 norm.
+
+% Need to reset options.K to prepare for calls to findNonreflectiveSimilarity.
+% This is safe because we already checked that there are enough point pairs.
+options.K = 2;
+
+% Solve for trans1
+[trans1, output] = findNonreflectiveSimilarity(uv,xy,options);
+
+
+% Solve for trans2
+
+% manually reflect the xy data across the Y-axis
+xyR = xy;
+xyR(:,1) = -1*xyR(:,1);
+
+trans2r = findNonreflectiveSimilarity(uv,xyR,options);
+
+% manually reflect the tform to undo the reflection done on xyR
+TreflectY = [-1 0 0;
+ 0 1 0;
+ 0 0 1];
+trans2 = maketform('affine', trans2r.tdata.T * TreflectY);
+
+
+% Figure out if trans1 or trans2 is better
+xy1 = tformfwd(trans1,uv);
+norm1 = norm(xy1-xy);
+
+xy2 = tformfwd(trans2,uv);
+norm2 = norm(xy2-xy);
+
+if norm1 <= norm2
+ trans = trans1;
+else
+ trans = trans2;
+end
+"""
+
+
+class MatlabCp2tormException(Exception):
+ def __str__(self):
+ return "In File {}:{}".format(__file__, super.__str__(self))
+
+
+def tformfwd(trans, uv):
+ """
+ Function:
+ ----------
+ apply affine transform 'trans' to uv
+
+ Parameters:
+ ----------
+ @trans: 3x3 np.array
+ transform matrix
+ @uv: Kx2 np.array
+ each row is a pair of coordinates (x, y)
+
+ Returns:
+ ----------
+ @xy: Kx2 np.array
+ each row is a pair of transformed coordinates (x, y)
+ """
+ uv = np.hstack((uv, np.ones((uv.shape[0], 1))))
+ xy = np.dot(uv, trans)
+ xy = xy[:, 0:-1]
+ return xy
+
+
+def tforminv(trans, uv):
+ """
+ Function:
+ ----------
+ apply the inverse of affine transform 'trans' to uv
+
+ Parameters:
+ ----------
+ @trans: 3x3 np.array
+ transform matrix
+ @uv: Kx2 np.array
+ each row is a pair of coordinates (x, y)
+
+ Returns:
+ ----------
+ @xy: Kx2 np.array
+ each row is a pair of inverse-transformed coordinates (x, y)
+ """
+ Tinv = inv(trans)
+ xy = tformfwd(Tinv, uv)
+ return xy
+
+
+def findNonreflectiveSimilarity(uv, xy, options=None):
+ """
+ Function:
+ ----------
+ Find Non-reflective Similarity Transform Matrix 'trans':
+ u = uv[:, 0]
+ v = uv[:, 1]
+ x = xy[:, 0]
+ y = xy[:, 1]
+ [x, y, 1] = [u, v, 1] * trans
+
+ Parameters:
+ ----------
+ @uv: Kx2 np.array
+ source points each row is a pair of coordinates (x, y)
+ @xy: Kx2 np.array
+ each row is a pair of inverse-transformed
+ @option: not used, keep it as None
+
+ Returns:
+ @trans: 3x3 np.array
+ transform matrix from uv to xy
+ @trans_inv: 3x3 np.array
+ inverse of trans, transform matrix from xy to uv
+
+ Matlab:
+ ----------
+ % For a nonreflective similarity:
+ %
+ % let sc = s*cos(theta)
+ % let ss = s*sin(theta)
+ %
+ % [ sc -ss
+ % [u v] = [x y 1] * ss sc
+ % tx ty]
+ %
+ % There are 4 unknowns: sc,ss,tx,ty.
+ %
+ % Another way to write this is:
+ %
+ % u = [x y 1 0] * [sc
+ % ss
+ % tx
+ % ty]
+ %
+ % v = [y -x 0 1] * [sc
+ % ss
+ % tx
+ % ty]
+ %
+ % With 2 or more correspondence points we can combine the u equations and
+ % the v equations for one linear system to solve for sc,ss,tx,ty.
+ %
+ % [ u1 ] = [ x1 y1 1 0 ] * [sc]
+ % [ u2 ] [ x2 y2 1 0 ] [ss]
+ % [ ... ] [ ... ] [tx]
+ % [ un ] [ xn yn 1 0 ] [ty]
+ % [ v1 ] [ y1 -x1 0 1 ]
+ % [ v2 ] [ y2 -x2 0 1 ]
+ % [ ... ] [ ... ]
+ % [ vn ] [ yn -xn 0 1 ]
+ %
+ % Or rewriting the above matrix equation:
+ % U = X * r, where r = [sc ss tx ty]'
+ % so r = X\ U.
+ %
+ """
+ options = {"K": 2}
+
+ K = options["K"]
+ M = xy.shape[0]
+ x = xy[:, 0].reshape((-1, 1)) # use reshape to keep a column vector
+ y = xy[:, 1].reshape((-1, 1)) # use reshape to keep a column vector
+ # print '--->x, y:\n', x, y
+
+ tmp1 = np.hstack((x, y, np.ones((M, 1)), np.zeros((M, 1))))
+ tmp2 = np.hstack((y, -x, np.zeros((M, 1)), np.ones((M, 1))))
+ X = np.vstack((tmp1, tmp2))
+ # print '--->X.shape: ', X.shape
+ # print 'X:\n', X
+
+ u = uv[:, 0].reshape((-1, 1)) # use reshape to keep a column vector
+ v = uv[:, 1].reshape((-1, 1)) # use reshape to keep a column vector
+ U = np.vstack((u, v))
+ # print '--->U.shape: ', U.shape
+ # print 'U:\n', U
+
+ # We know that X * r = U
+ if rank(X) >= 2 * K:
+ r, _, _, _ = lstsq(X, U, rcond=-1)
+ r = np.squeeze(r)
+ else:
+ raise Exception("cp2tform:twoUniquePointsReq")
+
+ # print '--->r:\n', r
+
+ sc = r[0]
+ ss = r[1]
+ tx = r[2]
+ ty = r[3]
+
+ Tinv = np.array([[sc, -ss, 0], [ss, sc, 0], [tx, ty, 1]])
+
+ # print '--->Tinv:\n', Tinv
+
+ T = inv(Tinv)
+ # print '--->T:\n', T
+
+ T[:, 2] = np.array([0, 0, 1])
+
+ return T, Tinv
+
+
+def findSimilarity(uv, xy, options=None):
+ """
+ Function:
+ ----------
+ Find Reflective Similarity Transform Matrix 'trans':
+ u = uv[:, 0]
+ v = uv[:, 1]
+ x = xy[:, 0]
+ y = xy[:, 1]
+ [x, y, 1] = [u, v, 1] * trans
+
+ Parameters:
+ ----------
+ @uv: Kx2 np.array
+ source points each row is a pair of coordinates (x, y)
+ @xy: Kx2 np.array
+ each row is a pair of inverse-transformed
+ @option: not used, keep it as None
+
+ Returns:
+ ----------
+ @trans: 3x3 np.array
+ transform matrix from uv to xy
+ @trans_inv: 3x3 np.array
+ inverse of trans, transform matrix from xy to uv
+
+ Matlab:
+ ----------
+ % The similarities are a superset of the nonreflective similarities as they may
+ % also include reflection.
+ %
+ % let sc = s*cos(theta)
+ % let ss = s*sin(theta)
+ %
+ % [ sc -ss
+ % [u v] = [x y 1] * ss sc
+ % tx ty]
+ %
+ % OR
+ %
+ % [ sc ss
+ % [u v] = [x y 1] * ss -sc
+ % tx ty]
+ %
+ % Algorithm:
+ % 1) Solve for trans1, a nonreflective similarity.
+ % 2) Reflect the xy data across the Y-axis,
+ % and solve for trans2r, also a nonreflective similarity.
+ % 3) Transform trans2r to trans2, undoing the reflection done in step 2.
+ % 4) Use TFORMFWD to transform uv using both trans1 and trans2,
+ % and compare the results, Returnsing the transformation corresponding
+ % to the smaller L2 norm.
+
+ % Need to reset options.K to prepare for calls to findNonreflectiveSimilarity.
+ % This is safe because we already checked that there are enough point pairs.
+ """
+ options = {"K": 2}
+
+ # uv = np.array(uv)
+ # xy = np.array(xy)
+
+ # Solve for trans1
+ trans1, trans1_inv = findNonreflectiveSimilarity(uv, xy, options)
+
+ # Solve for trans2
+
+ # manually reflect the xy data across the Y-axis
+ xyR = xy
+ xyR[:, 0] = -1 * xyR[:, 0]
+
+ trans2r, trans2r_inv = findNonreflectiveSimilarity(uv, xyR, options)
+
+ # manually reflect the tform to undo the reflection done on xyR
+ TreflectY = np.array([[-1, 0, 0], [0, 1, 0], [0, 0, 1]])
+
+ trans2 = np.dot(trans2r, TreflectY)
+
+ # Figure out if trans1 or trans2 is better
+ xy1 = tformfwd(trans1, uv)
+ norm1 = norm(xy1 - xy)
+
+ xy2 = tformfwd(trans2, uv)
+ norm2 = norm(xy2 - xy)
+
+ if norm1 <= norm2:
+ return trans1, trans1_inv
+ else:
+ trans2_inv = inv(trans2)
+ return trans2, trans2_inv
+
+
+def get_similarity_transform(src_pts, dst_pts, reflective=True):
+ """
+ Function:
+ ----------
+ Find Similarity Transform Matrix 'trans':
+ u = src_pts[:, 0]
+ v = src_pts[:, 1]
+ x = dst_pts[:, 0]
+ y = dst_pts[:, 1]
+ [x, y, 1] = [u, v, 1] * trans
+
+ Parameters:
+ ----------
+ @src_pts: Kx2 np.array
+ source points, each row is a pair of coordinates (x, y)
+ @dst_pts: Kx2 np.array
+ destination points, each row is a pair of transformed
+ coordinates (x, y)
+ @reflective: True or False
+ if True:
+ use reflective similarity transform
+ else:
+ use non-reflective similarity transform
+
+ Returns:
+ ----------
+ @trans: 3x3 np.array
+ transform matrix from uv to xy
+ trans_inv: 3x3 np.array
+ inverse of trans, transform matrix from xy to uv
+ """
+
+ if reflective:
+ trans, trans_inv = findSimilarity(src_pts, dst_pts)
+ else:
+ trans, trans_inv = findNonreflectiveSimilarity(src_pts, dst_pts)
+
+ return trans, trans_inv
+
+
+def cvt_tform_mat_for_cv2(trans):
+ """
+ Function:
+ ----------
+ Convert Transform Matrix 'trans' into 'cv2_trans' which could be
+ directly used by cv2.warpAffine():
+ u = src_pts[:, 0]
+ v = src_pts[:, 1]
+ x = dst_pts[:, 0]
+ y = dst_pts[:, 1]
+ [x, y].T = cv_trans * [u, v, 1].T
+
+ Parameters:
+ ----------
+ @trans: 3x3 np.array
+ transform matrix from uv to xy
+
+ Returns:
+ ----------
+ @cv2_trans: 2x3 np.array
+ transform matrix from src_pts to dst_pts, could be directly used
+ for cv2.warpAffine()
+ """
+ cv2_trans = trans[:, 0:2].T
+
+ return cv2_trans
+
+
+def get_similarity_transform_for_cv2(src_pts, dst_pts, reflective=True):
+ """
+ Function:
+ ----------
+ Find Similarity Transform Matrix 'cv2_trans' which could be
+ directly used by cv2.warpAffine():
+ u = src_pts[:, 0]
+ v = src_pts[:, 1]
+ x = dst_pts[:, 0]
+ y = dst_pts[:, 1]
+ [x, y].T = cv_trans * [u, v, 1].T
+
+ Parameters:
+ ----------
+ @src_pts: Kx2 np.array
+ source points, each row is a pair of coordinates (x, y)
+ @dst_pts: Kx2 np.array
+ destination points, each row is a pair of transformed
+ coordinates (x, y)
+ reflective: True or False
+ if True:
+ use reflective similarity transform
+ else:
+ use non-reflective similarity transform
+
+ Returns:
+ ----------
+ @cv2_trans: 2x3 np.array
+ transform matrix from src_pts to dst_pts, could be directly used
+ for cv2.warpAffine()
+ """
+ trans, trans_inv = get_similarity_transform(src_pts, dst_pts, reflective)
+ cv2_trans = cvt_tform_mat_for_cv2(trans)
+ return cv2_trans, trans
+
+
+std_points_317 = np.array(
+ [
+ [85.82991, 115.7792],
+ [169.0532, 114.3381],
+ [127.574, 167.0006],
+ [90.6964, 204.7014],
+ [167.3069, 203.3733],
+ ]
+)
+
+
+padding = 30
+
+std_points_317 = std_points_317 + padding
+
+std_points_256=std_points_317.copy()
+std_points_256[..., 0] -= 30
+std_points_256[..., 1] -= 60
+
+def warp_as_face_x_ray(img, src_pts, tgt_pts=std_points_317):
+ tfm, trans = get_similarity_transform_for_cv2(src_pts.copy(), tgt_pts.copy())
+ return cv2.warpAffine(img, tfm, (317, 317)), trans
+
+
+def estimiate_batch_transform(all_src_pts, tgt_pts=std_points_317):
+ tgt_pts = np.repeat(tgt_pts[None, ...], len(all_src_pts), 0).reshape(-1, 2)
+ src_pts = np.array(all_src_pts).reshape(-1, 2)
+ tfm, trans = get_similarity_transform_for_cv2(src_pts, tgt_pts)
+ return tfm, trans
+
+
+def batch_warp_as_face_x_ray(images, all_src_pts, tgt_pts=std_points_317):
+ tfm, trans = estimiate_batch_transform(all_src_pts, tgt_pts)
+ return [cv2.warpAffine(img, tfm, (317, 317)) for img in images], trans
+
+
+def transform_landmarks(landmarks, trans):
+ transformed = np.hstack((landmarks, np.ones((landmarks.shape[0], 1))))
+ transformed = np.dot(transformed, trans)
+ return transformed[:, :2]
+
+def compute_reverse_trans(trans):
+ return np.linalg.inv(trans)
\ No newline at end of file
diff --git a/clean/video/pwtf_dvd/inference/utils/__init__.py b/clean/video/pwtf_dvd/inference/utils/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..7437239283d4494444c4b0993d34c90f6891e0c8
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/utils/__init__.py
@@ -0,0 +1,7 @@
+
+__all__ = [] # do not use ' from utils import *'
+
+from .common import *
+from .plugin_loader import PluginLoader
+#from .plugin_loaderv2 import PluginLoader as PluginLoaderV2
+from .model_loader import add_loader
\ No newline at end of file
diff --git a/clean/video/pwtf_dvd/inference/utils/common.py b/clean/video/pwtf_dvd/inference/utils/common.py
new file mode 100644
index 0000000000000000000000000000000000000000..7c975bf6a08077296351bd10c03ea719538e48a3
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/utils/common.py
@@ -0,0 +1,80 @@
+#!/usr/bin/python
+# -*- coding: UTF-8 -*-
+
+
+import os
+import torch
+from torch.autograd import Variable
+import errno
+import torch.distributed as dist
+import math
+from functools import reduce
+def make_folder(path, version):
+ if not os.path.exists(os.path.join(path, version)):
+ print(os.path.join(path, version))
+ os.makedirs(os.path.join(path, version))
+
+
+def tensor2var(x, grad=False):
+ if torch.cuda.is_available():
+ x = x.cuda()
+ return Variable(x, requires_grad=grad)
+
+def var2tensor(x):
+ return x.data.cpu()
+
+def var2numpy(x):
+ return x.data.cpu().numpy()
+
+def denorm(x):
+ out = (x + 1) / 2
+ return out.clamp_(0, 1)
+
+def mkdir_p(dirname):
+ """ Like "mkdir -p", make a dir recursively, but do nothing if the dir exists
+ Args:
+ dirname(str):
+ """
+ assert dirname is not None
+ if dirname == '' or os.path.isdir(dirname):
+ return
+ try:
+ os.makedirs(dirname)
+ except OSError as e:
+ if e.errno != errno.EEXIST:
+ raise e
+
+
+def skipShardSplit(aList, drop_last=False, num_replicas=None, rank=None):
+ if not isinstance(aList, list) and not isinstance(aList, tuple):
+ aList = List
+
+ if num_replicas is None:
+ num_replicas = dist.get_world_size() if dist.is_initialized() else 1
+ if rank is None:
+ rank = dist.get_rank() if dist.is_initialized() else 0
+
+ num_replicas = num_replicas
+ rank = rank
+ drop_last = drop_last
+
+ if drop_last:
+ aList = aList[0: (len(aList) // num_replicas) * num_replicas]
+
+ # subsample
+ aList = aList[rank::num_replicas]
+
+ return aList
+
+def mixb2a(a,b):
+ if len(b) > len(a):
+ a,b = b,a
+ if len(b) == 0:
+ return a
+ chunk_num = (len(b))
+ a_chunk = splitIntoChunk(a, chunk_num)
+ b_chunk = list(map(lambda x:[x],b))
+ return reduce(lambda x, y: x+y, [_a+_b for _a,_b in zip(a_chunk, b_chunk)])
+
+def splitIntoChunk(aList, chunk_num):
+ return [aList[math.ceil(k * (len(aList) / chunk_num)):math.ceil((k + 1) * (len(aList) / chunk_num)):] for k in range(chunk_num)]
\ No newline at end of file
diff --git a/clean/video/pwtf_dvd/inference/utils/logger.py b/clean/video/pwtf_dvd/inference/utils/logger.py
new file mode 100644
index 0000000000000000000000000000000000000000..b5e3c52c3ae53a698ba67581a43bf20d832eca0d
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/utils/logger.py
@@ -0,0 +1,182 @@
+#!/usr/bin/python
+# -*- coding: UTF-8 -*-
+# Modified by: algohunt
+# Microsoft Research & Peking University
+# lilingzhi@pku.edu.cn
+# Copyright (c) 2019
+
+
+# -*- coding: utf-8 -*-
+
+"""
+Borrow from tensorpack credit goes to yuxin wu
+The logger module itself has the common logging functions of Python's
+:class:`logging.Logger`. For example:
+
+.. code-block:: python
+
+ from utils import logger
+ logger.set_logger_dir('train_log/test')
+ logger.info("Test")
+ logger.error("Error happened!")
+"""
+
+
+import logging
+import os
+import os.path
+import shutil
+import sys
+from datetime import datetime, timedelta
+from six.moves import input
+from termcolor import colored
+import time
+
+__all__ = ['set_logger_dir', 'auto_set_dir', 'get_logger_dir']
+
+
+class _MyFormatter(logging.Formatter):
+ def format(self, record):
+ date = colored('[%(asctime)s @%(filename)s:%(lineno)d]', 'green')
+ msg = '%(message)s'
+ if record.levelno == logging.WARNING:
+ fmt = date + ' ' + colored('WRN', 'red', attrs=['blink']) + ' ' + msg
+ elif record.levelno == logging.ERROR or record.levelno == logging.CRITICAL:
+ fmt = date + ' ' + colored('ERR', 'red', attrs=['blink', 'underline']) + ' ' + msg
+ elif record.levelno == logging.DEBUG:
+ fmt = date + ' ' + colored('DBG', 'yellow', attrs=['blink']) + ' ' + msg
+ else:
+ fmt = date + ' ' + msg
+ if hasattr(self, '_style'):
+ # Python3 compatibility
+ self._style._fmt = fmt
+ self._fmt = fmt
+ return super(_MyFormatter, self).format(record)
+
+
+def _getlogger():
+ logger = logging.getLogger('tensorpack')
+ logger.propagate = False
+ logger.setLevel(logging.INFO)
+ handler = logging.StreamHandler(sys.stdout)
+ handler.setFormatter(_MyFormatter(datefmt='%m%d %H:%M:%S'))
+ logger.addHandler(handler)
+ return logger
+
+
+_logger = _getlogger()
+_LOGGING_METHOD = ['info', 'warning', 'error', 'critical', 'exception', 'debug', 'setLevel']
+# export logger functions
+for func in _LOGGING_METHOD:
+ locals()[func] = getattr(_logger, func)
+ __all__.append(func)
+# 'warn' is deprecated in logging module
+warn = _logger.warning
+__all__.append('warn')
+
+
+def _get_time_str():
+ utc_time = datetime.utcfromtimestamp(time.time())
+ beijing_time = utc_time- timedelta(hours=8)
+ return beijing_time.strftime('%m%d-%H%M%S')
+
+
+# globals: logger file and directory:
+LOG_DIR = None
+_FILE_HANDLER = None
+
+
+def _set_file(path):
+ global _FILE_HANDLER
+ if os.path.isfile(path):
+ backup_name = path + '.' + _get_time_str()
+ shutil.move(path, backup_name)
+ _logger.info("Existing log file '{}' backuped to '{}'".format(path, backup_name)) # noqa: F821
+ hdl = logging.FileHandler(
+ filename=path, encoding='utf-8', mode='w')
+ hdl.setFormatter(_MyFormatter(datefmt='%m%d %H:%M:%S'))
+
+ _FILE_HANDLER = hdl
+ _logger.addHandler(hdl)
+ _logger.info("Argv: " + ' '.join(sys.argv))
+
+
+def set_logger_dir(dirname, action=None):
+ """
+ Set the directory for global logging.
+
+ Args:
+ dirname(str): log directory
+ action(str): an action of ["k","d","q"] to be performed
+ when the directory exists. Will ask user by default.
+
+ "d": delete the directory. Note that the deletion may fail when
+ the directory is used by tensorboard.
+
+ "k": keep the directory. This is useful when you resume from a
+ previous training and want the directory to look as if the
+ training was not interrupted.
+ Note that this option does not load old models or any other
+ old states for you. It simply does nothing.
+
+ """
+ global LOG_DIR, _FILE_HANDLER
+ if _FILE_HANDLER:
+ # unload and close the old file handler, so that we may safely delete the logger directory
+ _logger.removeHandler(_FILE_HANDLER)
+ del _FILE_HANDLER
+
+ def dir_nonempty(dirname):
+ # If directory exists and nonempty (ignore hidden files), prompt for action
+ return os.path.isdir(dirname) and len([x for x in os.listdir(dirname) if x[0] != '.'])
+
+ if dir_nonempty(dirname):
+ if not action:
+ _logger.warn("""\
+Log directory {} exists! Use 'd' to delete it. """.format(dirname))
+ _logger.warn("""\
+If you're resuming from a previous run, you can choose to keep it.
+Press any other key to exit. """)
+ while not action:
+ action = input("Select Action: k (keep) / d (delete) / q (quit):").lower().strip()
+ act = action
+ if act == 'b':
+ backup_name = dirname + _get_time_str()
+ shutil.move(dirname, backup_name)
+ info("Directory '{}' backuped to '{}'".format(dirname, backup_name)) # noqa: F821
+ elif act == 'd':
+ shutil.rmtree(dirname, ignore_errors=True)
+ if dir_nonempty(dirname):
+ shutil.rmtree(dirname, ignore_errors=False)
+ elif act == 'n':
+ dirname = dirname + _get_time_str()
+ info("Use a new log directory {}".format(dirname)) # noqa: F821
+ elif act == 'k':
+ pass
+ else:
+ raise OSError("Directory {} exits!".format(dirname))
+ LOG_DIR = dirname
+ from . import mkdir_p
+ mkdir_p(dirname)
+ _set_file(os.path.join(dirname, 'log.log'))
+
+
+def auto_set_dir(action=None, name=None):
+ """
+ Use :func:`logger.set_logger_dir` to set log directory to
+ "./train_log/{scriptname}:{name}". "scriptname" is the name of the main python file currently running"""
+ mod = sys.modules['__main__']
+ basename = os.path.basename(mod.__file__)
+ auto_dirname = os.path.join('train_log', basename[:basename.rfind('.')])
+ if name:
+ auto_dirname += '_%s' % name if os.name == 'nt' else ':%s' % name
+ set_logger_dir(auto_dirname, action=action)
+
+
+def get_logger_dir():
+ """
+ Returns:
+ The logger directory, or None if not set.
+ The directory is used for general logging, tensorboard events, checkpoints, etc.
+ """
+ return LOG_DIR
diff --git a/clean/video/pwtf_dvd/inference/utils/model_loader.py b/clean/video/pwtf_dvd/inference/utils/model_loader.py
new file mode 100644
index 0000000000000000000000000000000000000000..9be6e723022cd03a23018a72181230caf9525282
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/utils/model_loader.py
@@ -0,0 +1,117 @@
+#!/usr/bin/python
+# -*- coding: UTF-8 -*-
+
+
+import types
+from utils import logger
+from config import config as cfg
+import os
+import sys
+import glob
+import torch
+import traceback
+import types
+import torch.distributed as dist
+import copy
+from .torch_save import torch_save
+
+def add_loader(target, name,max_to_keep=2):
+
+ def get_rank(self):
+ return dist.get_rank() if dist.is_initialized() else 0
+
+ def save_models(self, epoch):
+ """ Backup and save the models """
+ if self.get_rank() == 0:
+ logger.debug("Backing up and saving models")
+ if not os.path.exists(self.model_dir):
+ os.mkdir(self.model_dir)
+
+ torch_save(self.state_dict(), self.get_checkpoint_path(epoch))
+ if os.path.exists(self.get_checkpoint_path(epoch - self.max_to_keep)):
+ os.remove(self.get_checkpoint_path(epoch - self.max_to_keep))
+ logger.info("{} models saved".format(self.name))
+
+ def load(self, fullpath=None, epoch=-1):
+ """ Force Loading a model, or load the latest model"""
+ if fullpath is None:
+ fullpath, loaded_epoch = self.find_last(epoch)
+ else:
+ loaded_epoch = epoch
+
+ if fullpath is None:
+ logger.info("No existing {} model found".format(self.name))
+ return False, -1
+ logger.debug("Loading model: '%s'", fullpath)
+ try:
+ saved_state_dict = torch.load(fullpath, map_location='cpu')
+ self.load_state_dict(saved_state_dict)
+ logger.info(" consume training from {}".format(fullpath))
+ except ValueError as err:
+ logger.warning("Failed loading existing training data for {}. Generating new models".format(self.name))
+ logger.debug("Exception: %s", str(err))
+ return False, -1
+ except OSError as err:
+ logger.warning("Failed loading existing training data for {}. Generating new models".format(self.name))
+ logger.debug("Exception: %s", str(err))
+ return False, -1
+ except RuntimeError as err:
+ logger.warning("{} model has corrupted, try to load earlier one".format(self.name))
+ logger.debug("Exception: %s", str(err))
+ return False, -1
+ except:
+ logger.error(traceback.format_exc())
+ raise
+
+ return True, loaded_epoch
+
+ def get_checkpoint_path(self, epoch):
+ """" returning the checkpoint path w.r.t epoch which should be {name}_{epoch}.pth"""
+ return os.path.join(self.model_dir, self.name + '_' +str(epoch) + '.pth')
+
+
+ def find_last(self, epoch=-1, model_dir=None):
+ """Finds the last checkpoint file of the last trained model in the
+ model directory.
+ Returns:
+ checkpoint :The path of the last checkpoint file
+
+ """
+ if model_dir is None:
+ model_dir = self.model_dir
+ if not os.path.exists(model_dir):
+ logger.info("model dir not exists {} ".format(model_dir))
+ return None, -1
+ #assert os.path.exists(self.model_dir), "model dir not exists {}".format(self.model_dir)
+ checkpoints = glob.glob(os.path.join(model_dir, '*.pth'))
+
+
+ checkpoints = list(filter(lambda x: os.path.basename(x).startswith(self.name), checkpoints))
+ if len(checkpoints) == 0:
+ return None, -1
+ checkpoints = {int(os.path.basename(x).split('.')[0].split('_')[-1]):x for x in checkpoints}
+
+ start = min(checkpoints.keys())
+ end = max(checkpoints.keys())
+
+ if epoch == -1:
+ return checkpoints[end], end
+ elif epoch < start :
+ raise RuntimeError(
+ "model for epoch {} has been deleted as we only keep {} models".format(epoch,self.max_to_keep))
+ elif epoch > end:
+ raise RuntimeError(
+ "epoch {} is bigger than all exist checkpoints".format(epoch))
+ else:
+ return checkpoints[epoch], epoch
+
+ target.find_last = types.MethodType(find_last, target)
+ target.get_checkpoint_path = types.MethodType(get_checkpoint_path, target)
+ target.load = types.MethodType(load, target)
+ target.save_models = types.MethodType(save_models, target)
+ target.get_rank = types.MethodType(get_rank, target)
+
+ target.max_to_keep = max_to_keep
+ target.name = name
+ target.model_dir = os.path.join(cfg.path.model_dir, cfg.setting_name)
+ return target
\ No newline at end of file
diff --git a/clean/video/pwtf_dvd/inference/utils/plugin_loader.py b/clean/video/pwtf_dvd/inference/utils/plugin_loader.py
new file mode 100644
index 0000000000000000000000000000000000000000..bcd5ababfeb1bb358ef15fe56f35f58d164b7c62
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/utils/plugin_loader.py
@@ -0,0 +1,69 @@
+#!/usr/bin/python
+# -*- coding: UTF-8 -*-
+
+
+
+""" Plugin loader for extract, training and model tasks """
+
+from utils import logger
+import os
+from importlib import import_module
+from typing import Type
+from trainer._base import TrainerBase
+from torch.utils.data import Dataset
+from model._base import ModelBase
+
+class PluginLoader():
+ """
+ Plugin loader for extract, training and model tasks
+ function: get_{model_type}
+ args: {model_name}
+ will return the a class named model_type under model_type.model_name.py
+
+ as it return a class you should also annotate the returning classtype to make
+ code linting avaliable in some IDE
+ """
+ @staticmethod
+ def get_classifier(name) -> Type[ModelBase]:
+ """ Return requested attribute encoder plugin """
+ return PluginLoader._import("model.classifier", name)
+
+ @staticmethod
+ def get_trainer(name) -> Type[TrainerBase]:
+ """ Return requested trainer plugin """
+ return PluginLoader._import("trainer", name)
+
+ @staticmethod
+ def get_dataset(name) -> Type[Dataset]:
+ """ Return requested trainer plugin """
+ return PluginLoader._import("dataset", name)
+
+ @staticmethod
+ def _import(attr, name):
+ """ Import the plugin's module """
+ name = name.replace("-", "_")
+ ttl = attr.split(".")[-1].title()
+ logger.info("Loading %s from %s plugin...", ttl, name.title())
+ attr = "model" if attr == "Trainer" else attr.lower()
+ mod = ".".join((attr, name))
+ module = import_module(mod)
+ logger.info(str(module) + str(ttl))
+ return getattr(module, ttl)
+
+ @staticmethod
+ def get_available_trainer():
+ """ Return a list of available models """
+ modelpath = os.path.join(os.path.dirname(__file__), "trainer")
+ models = sorted(item.name.replace(".py", "").replace("_", "-")
+ for item in os.scandir(modelpath)
+ if not item.name.startswith("_")
+ and item.name.endswith(".py"))
+ return models
+
+ @staticmethod
+ def get_default_model():
+ """ Return the default model """
+ models = PluginLoader.get_available_models()
+ return 'original' if 'original' in models else models[0]
+
+
diff --git a/clean/video/pwtf_dvd/inference/utils/torch_save.py b/clean/video/pwtf_dvd/inference/utils/torch_save.py
new file mode 100644
index 0000000000000000000000000000000000000000..88fce6ba32ac66b3607a8496a03ae6e8f6321866
--- /dev/null
+++ b/clean/video/pwtf_dvd/inference/utils/torch_save.py
@@ -0,0 +1,9 @@
+import torch
+
+def torch_save(arr,file):
+ if torch.__version__>="1.6.0":
+ torch.save(arr, file, _use_new_zipfile_serialization=False)
+ else:
+ torch.save(arr, file)
+
+
diff --git a/clean/video/pwtf_dvd/preprocessing/preprocess.py b/clean/video/pwtf_dvd/preprocessing/preprocess.py
new file mode 100644
index 0000000000000000000000000000000000000000..f0ffc0860ecc92f717b459d3e299ec6313848db6
--- /dev/null
+++ b/clean/video/pwtf_dvd/preprocessing/preprocess.py
@@ -0,0 +1,258 @@
+import os
+from os.path import join
+import argparse
+import glob
+import subprocess
+import cv2
+from tqdm import tqdm
+import numpy as np
+import logging
+import torch
+from test_tools.common import detect_all, grab_all_frames
+from test_tools.faster_crop_align_xray import FasterCropAlignXRay
+from test_tools.warp_for_xray import (
+ estimiate_batch_transform,
+ transform_landmarks,
+ std_points_256,
+)
+from test_tools.ct.operations import find_longest, multiple_tracking
+from test_tools.utils import get_crop_box
+import datetime
+# from FaceForensics.face_detection_save import get_boundingbox
+
+os.environ['CUDA_LAUNCH_BLOCKING'] = "1"
+os.environ["CUDA_VISIBLE_DEVICES"] = "0"
+
+device=torch.device('cuda')
+#Date
+now = datetime.datetime.now()
+logger = logging.getLogger("main") #Logger 선언
+stream_handler = logging.StreamHandler() # Logger output 방법 선언
+formatter = logging.Formatter('[%(asctime)s][%(levelname)s|%(filename)s:%(lineno)s] >> %(message)s')
+stream_handler.setFormatter(formatter)
+logger.addHandler(stream_handler)
+logger.setLevel(logging.DEBUG)
+
+crop_align_func = FasterCropAlignXRay(256)
+max_frame= 10000
+
+### video path를 받으면 crop된 face를 저장하는 함수 ###
+def crop_face_from_video(video_path,cache_path,crop_path,clip_size):
+ # mp4 파일이 아니면 return
+ if 'mp4' not in video_path : return
+ # video name
+ video_name = video_path.split('/')[-1].replace('.mp4','')
+ # 만약 crop image path에 crop된 이미지가 110개 이상이면 return
+
+ if os.path.exists(crop_path):
+ if len(os.listdir(crop_path))>clip_limit:
+ logger.info(f'{video_name} already exists')
+ return
+
+ ##########################################
+ # detect_res : list, 전체 frame, whole frame
+ # detect_res [] : list, len = 사람 수로 예상 the number of detected face in a frame
+ # detect_res [] [] : tuple, length = 3
+ # detect_res [] [] 의 각 요소는 각각 box, lm5 : landmark (5,2) , score
+ ##########################################
+ # all_lm68 : list, 전체 frame, whole frame
+ # all_lm68 : list, len = 사람 수로 예상, the number of detected face in a frame
+ # all_lm68 : np.array : landmark 68개 (68,2)
+ ##########################################
+ # frames : each frame's np.array
+
+
+ # cache_file : cache file path
+ # landmark와 box를 저장하는 cache file
+ cache_file = f"{cache_path}.pth"
+
+ if os.path.exists(cache_file):
+ # cache file이 존재하면 load하고 frame만 불러옴
+ detect_res, all_lm68 = torch.load(cache_file)
+ frames = grab_all_frames(video_path, max_size=max_frame, cvt=True)
+ logger.info("detection result loaded from cache")
+ else:
+ # cache file이 존재하지 않으면 detect_all 함수를 통해 detect_res, all_lm68, frames를 불러옴
+ # detection_all 함수는 retina_face를 이용해서 box와 landmark를 찾는 함수
+ detect_res, all_lm68, frames = detect_all(
+ video_path, return_frames=True, max_size=10000
+ )
+ torch.save((detect_res, all_lm68), cache_file)
+ try:
+ shape = frames[0].shape[:2]
+ except IndexError: # if there is no frame in the video, error list에 저장
+ f = open("./indexerror.txt", 'a')
+ f.write("{}\n".format(video_path))
+ f.close()
+ return
+
+ # 모든 detect_res
+ all_detect_res = []
+
+ assert len(all_lm68) == len(detect_res)
+ # in each frame, save the detected face's bounding box, landmark(5, 68), score as a tuple and save it in a list
+ for faces, faces_lm68 in zip(detect_res, all_lm68):
+ new_faces = []
+ for (box, lm5, score), face_lm68 in zip(faces, faces_lm68):
+ new_face = (box, lm5, face_lm68, score)
+ new_faces.append(new_face)
+ all_detect_res.append(new_faces)
+ detect_res = all_detect_res
+ # SORT tracking
+ # tracks : list, len = 사람 수로 예상, the number of detected face in a frame
+ # tracks [] : list, len = 프레임 수, the number of frames
+ # tracks [] [] : tuple, length = 4, 각각 box, lm5 : landmark (5,2) , lm68 : landmark (68,2), score
+ tracks = multiple_tracking(detect_res)
+ # tuples : list, len = 사람 수로 예상, the number of detected face in a frame
+ # tuples [] : tuple, length = 2, 각각 0, 프레임 수 the number of frames
+ tuples = [(0, len(detect_res))] * len(tracks)
+ # if there is no face detected, find the longest face in the video
+ if len(tracks) == 0:
+ tuples, tracks = find_longest(detect_res)
+ data_storage = {}
+ frame_boxes = {}
+ super_clips = []
+ frame_res = {}
+ super_clips_start_end = []
+ # super_clips : tracking된 face들을 의미하는 것으로 보임
+ for track_i, ((start, end), track) in enumerate(zip(tuples, tracks)): # each track(=face)
+
+ # if detect_res's length is not equal to track's length, raise error
+ assert len(detect_res[start:end]) == len(track)
+
+ super_clips.append(len(track))
+ super_clips_start_end.append((start, end))
+ for face, frame_idx, j in zip(track, range(start, end), range(len(track))): # frame에서 각각의 face
+ box,lm5,lm68 = face[:3] # box, lm5, lm68
+ big_box = get_crop_box(shape, box, scale=0.5) # get crop box
+
+ top_left = big_box[:2][None, :] # top left point
+
+ new_lm5 = lm5 - top_left
+ new_lm68 = lm68 - top_left
+
+ new_box = (box.reshape(2, 2) - top_left).reshape(-1)
+
+ info = (new_box, new_lm5, new_lm68, big_box) # face info
+
+
+ x1, y1, x2, y2 = big_box
+ cropped = frames[frame_idx][y1:y2, x1:x2]
+ # cropped = cv2.resize(cropped, (512, 512))
+ # face들을 tracking한 박스들로 crop함
+ # landmark들도 box에 맞게 변환
+ # data_storage에 저장 i는 face id, j는 frame을 의미
+ base_key = f"{track_i}_{j}_" # i : face, j : frame
+ data_storage[base_key + "img"] = cropped
+ data_storage[base_key + "ldm"] = info
+ data_storage[base_key + "idx"] = frame_idx
+ frame_boxes[frame_idx] = np.rint(box).astype(np.int64)
+ # 총 crop된 face들과 그 face들의 frame 수를 알려줌
+ logger.info(f"{crop_path} : sampling clips from super clips {super_clips}")
+ clips_for_video = []
+ clip_size = clip_size
+ pad_length = clip_size - 1
+
+ # 각 face id 별로 clip을 만듦
+ # 아래의 영어 표기로는 8clip을 의미하지만 정확하겐 clip size 만큼 함
+ for super_clip_idx, super_clip_size in enumerate(super_clips): # cut the super clip into clips, overlap 7frames, 8frames per clip
+ inner_index = list(range(super_clip_size))
+
+ if super_clip_size < clip_size: # if there is not enough frames to make a clip, pad the frames
+ # to do : how to operate the padding
+ # 정확하게 이 코드가 어떻게 동작하는지 모르겠지만
+ # 대략적으로 frame들을 clipsize로 나눌때 부족하면
+ # clip size만큼의 frame이 되도록 padding을 함
+ if super_clip_size < clip_size//2 : continue
+ post_module = inner_index[1:-1][::-1] + inner_index
+
+ l_post = len(post_module)
+ post_module = post_module * (pad_length // l_post + 1)
+ post_module = post_module[:pad_length]
+ assert len(post_module) == pad_length
+
+ pre_module = inner_index + inner_index[1:-1][::-1]
+ l_pre = len(post_module)
+ pre_module = pre_module * (pad_length // l_pre + 1)
+ pre_module = pre_module[-pad_length:]
+ assert len(pre_module) == pad_length
+
+ inner_index = pre_module + inner_index + post_module
+
+ super_clip_size = len(inner_index)
+
+ frame_range = [
+ inner_index[i : i + clip_size] for i in range(super_clip_size) if i + clip_size <= super_clip_size
+ ]
+ for indices in frame_range:
+ clip = [(super_clip_idx, t) for t in indices]
+ clips_for_video.append(clip)
+
+ # landmarks, images = crop_align_func(landmarks, images) # i : face, j : frame
+ processed_clips = 0 # Track number of processed clips
+ for clip in clips_for_video:
+ # Check if we've reached the clip limit
+ if processed_clips >= clip_limit:
+ logger.info(f"Reached clip limit of {clip_limit}, stopping processing")
+ break
+
+ # 각 자른 clip에 대해서 진행
+ images = [data_storage[f"{i}_{j}_img"] for i, j in clip] # call cropped face images from data_storage, i : face, j : frame
+ landmarks = [data_storage[f"{i}_{j}_ldm"] for i, j in clip] # call landmarks from data_storage, i : face, j : frame
+ # landmark를 기준으로 crop align func을 진행
+ # 해당 함수가 clip에 있는 얼굴들의 landmark 평균을 기준으로 박스를 설정하고
+ # 박스를 기준으로 crop align을 진행
+ # 다르게 말하면, landmark 평균을 기준으로 박스의 geometry를 설정하고
+ # 박스의 geometry는 고정한체로 얼굴이 움직이는 걸 찍었다 생각하면 됨
+ # 다시 또 말하면, 카메라를 고정하고 사람이 움직이는 것을 찍은것처럼
+ # PPT 참조
+ landmarks, images = crop_align_func(landmarks, images) # align the face images by landmarks in the clip
+ i, j = clip[-1]
+ k = super_clips[i]%clip_size
+
+ ##########################################################################
+ # 코드 변경시 이 함수에서는 이부분만 변경할 것을 권고 !!!!!!!!!!!!!!!!!!!!!!!!
+ # 특히, cv2.imwrite함수만 변경할 것을 추천
+ ##########################################################################
+ if (j+1)%clip_size==0: # if last frame number of the clip is multiple of clip_size, save all images in the clip
+ # it means save face alignments in 8 frames in the video so that they don't overlap
+ for f, (i,j) in enumerate(clip) :
+ cv2.imwrite(join(crop_path, f'{i:02}_{j:04}.png'), cv2.cvtColor(images[f], cv2.COLOR_BGR2RGB))
+ if j == super_clips[i]-1: # if the clip have last frame image, save all images in the clip
+ if k!=0 : # if the clip is not multiple of clip_size, save the last k images in the clip
+ # k is the number of frames that are not overlapped
+ for l in range(clip_size-k,clip_size):
+ ci,cj = clip[l]
+ cv2.imwrite(join(crop_path, f'{ci:02}_{cj:04}.png'), cv2.cvtColor(images[l], cv2.COLOR_BGR2RGB)) # clip means face alignment images in 8 frames, non-overlap
+
+ processed_clips += 1 # Increment processed clip counter
+ ##########################################################################
+
+
+if __name__ == '__main__':
+ p = argparse.ArgumentParser(
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter
+ )
+ p.add_argument('--video_path','-i', type=str, default='/videos.mp4', help='path to input video')
+ p.add_argument('--save_path','-s', type=str, default='/data/crop_face', help='path to save cropped faces')
+ p.add_argument('--cachepath', '-c', type=str, default='/data/cache', help='path to cache detection results')
+ p.add_argument('--clipsize','-l',type=int,default=32, help='number of frames in a clip')
+ args = p.parse_args()
+ video_path = args.video_path
+ save_path = args.save_path
+ cache_path = args.cachepath
+ clip_size = args.clipsize
+
+ crop_face_from_video(video_path, cache_path, crop_path, clip_size)
+
+
+
+
+###################### reference ######################
+
+# this code reference from FTCN Official Code in git hub
+# link is https://github.com/yinglinzheng/FTCN
+
+# - Zheng, Y., Bao, J., Chen, D., Zeng, M., & Wen, F. (2021). Exploring Temporal Coherence for More General Video Face Forgery Detection. In Proceedings of the IEEE/CVF International Conference on Computer Vision (pp. 15044–15054).
+
+
diff --git a/clean/video/pwtf_dvd/preprocessing/test_tools/__init__.py b/clean/video/pwtf_dvd/preprocessing/test_tools/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/clean/video/pwtf_dvd/preprocessing/test_tools/common.py b/clean/video/pwtf_dvd/preprocessing/test_tools/common.py
new file mode 100644
index 0000000000000000000000000000000000000000..e76ac698b8fe9a32dfbdf4e294d5afa521250e71
--- /dev/null
+++ b/clean/video/pwtf_dvd/preprocessing/test_tools/common.py
@@ -0,0 +1,122 @@
+import os
+
+os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"
+
+from .ct.detection.utils import grab_all_frames, get_valid_faces, sample_chunks
+from .ct.operations import multiple_tracking
+import numpy as np
+from .ct.face_alignment import LandmarkPredictor
+from .ct.detection import FaceDetector
+import cv2
+from .utils import flatten,partition
+
+
+detector = FaceDetector(0)
+predictor = LandmarkPredictor(0)
+
+
+def get_five(ldm68):
+ groups = [range(36, 42), range(42, 48), [30], [48], [54]]
+ points = []
+ for group in groups:
+ points.append(ldm68[group].mean(0))
+ return np.array(points)
+
+
+def get_bbox(mask):
+ try:
+ y, x = np.nonzero(mask[..., 0])
+ return x.min() - 1, y.min() - 1, x.max() + 1, y.max() + 1
+ except:
+ return None
+
+
+def get_bigger_box(image, box, scale=0.5):
+ height, width = image.shape[:2]
+ box = np.rint(box).astype(np.int)
+ new_box = box.reshape(2, 2)
+ size = new_box[1] - new_box[0]
+ diff = scale * size
+ diff = diff[None, :] * np.array([-1, 1])[:, None]
+ new_box = new_box + diff
+ new_box[:, 0] = np.clip(new_box[:, 0], 0, width - 1)
+ new_box[:, 1] = np.clip(new_box[:, 1], 0, height - 1)
+ new_box = np.rint(new_box).astype(np.int)
+ return new_box.reshape(-1)
+
+
+def process_bigger_clips(clips, dete_res, clip_size, step, scale=0.5):
+ assert len(clips) % clip_size == 0
+ detect_results = sample_chunks(dete_res, clip_size, step)
+ clips = sample_chunks(clips, clip_size, step)
+ new_clips = []
+ for i, (frame_clip, record_clip) in enumerate(zip(clips, detect_results)):
+ tracks = multiple_tracking(record_clip)
+ for j, track in enumerate(tracks):
+ new_images = []
+ for (box, ldm, _), frame in zip(track, frame_clip):
+ big_box = get_bigger_box(frame, box, scale)
+ x1, y1, x2, y2 = big_box
+ top_left = big_box[:2][None, :]
+ new_ldm5 = ldm - top_left
+ box = np.rint(box).astype(np.int)
+ new_box = (box.reshape(2, 2) - top_left).reshape(-1)
+ feed = LandmarkPredictor.prepare_feed(frame, box)
+ ldm68 = predictor(feed) - top_left
+ new_images.append(
+ (frame[y1:y2, x1:x2], big_box, new_box, new_ldm5, ldm68)
+ )
+ new_clips.append(new_images)
+ return new_clips
+
+
+def post(detected_faces):
+ return [[face[:4], None, face[-1]] for face in detected_faces]
+
+
+def check(detect_res):
+ return min([len(faces) for faces in detect_res]) != 0
+
+
+def detect_all(file, sfd_only=False, return_frames=False, max_size=None):
+ frames = grab_all_frames(file, max_size=max_size, cvt=True)
+ if not sfd_only:
+ detect_res = flatten(
+ [detector.detect(item) for item in partition(frames, 50)]
+ )
+ detect_res = get_valid_faces(detect_res, thres=0.5)
+ else:
+ raise NotImplementedError
+
+ all_68 = get_lm68(frames, detect_res)
+ if not return_frames:
+ return detect_res, all_68
+ else:
+ return detect_res, all_68, frames
+
+
+def get_lm68(frames, detect_res):
+ assert len(frames) == len(detect_res)
+ frame_count = len(frames)
+ all_68 = []
+ for i in range(frame_count):
+ frame = frames[i]
+ faces = detect_res[i]
+ if len(faces) == 0:
+ res_68 = []
+ else:
+ feeds = []
+ for face in faces:
+ assert len(face) == 3
+ box = face[0]
+ feed = LandmarkPredictor.prepare_feed(frame, box)
+ feeds.append(feed)
+ res_68 = predictor(feeds)
+ assert len(res_68) == len(faces)
+ for face, l_68 in zip(faces, res_68):
+ if face[1] is None:
+ face[1] = get_five(l_68)
+ all_68.append(res_68)
+
+ assert len(all_68) == len(detect_res)
+ return all_68
diff --git a/clean/video/pwtf_dvd/preprocessing/test_tools/ct/detection/__init__.py b/clean/video/pwtf_dvd/preprocessing/test_tools/ct/detection/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..23447e84f4f5f23a4c4818df2f26cc19a9200363
--- /dev/null
+++ b/clean/video/pwtf_dvd/preprocessing/test_tools/ct/detection/__init__.py
@@ -0,0 +1,56 @@
+import cv2
+from .detector import RetinaFace
+from .utils import *
+
+
+def assert_bounded(val, low, up):
+ return val >= low and val < up
+
+
+def check_valid(face, w, h):
+ box = face[0]
+ if box[0] > box[2]:
+ return False
+ if box[1] > box[3]:
+ return False
+ for idx, bound in zip([0, 1, 2, 3], [w, h, w, h]):
+ if not assert_bounded(box[idx], 0, bound):
+ return False
+ pts = face[1]
+ for p in pts:
+ for idx, bound in zip([0, 1], [w, h]):
+ if not assert_bounded(p[idx], 0, bound):
+ return False
+ return True
+
+
+def post_detect(detect_results, scale, w, h):
+ new_results = []
+ for frame_faces in detect_results:
+ new_frame_faces = []
+ for box, ldm, score in frame_faces:
+ box = box * scale
+ ldm = ldm * scale
+ face = (box, ldm, score)
+ if check_valid(face, w=w, h=h):
+ new_frame_faces.append(face)
+ new_results.append(new_frame_faces)
+ return new_results
+
+
+class FaceDetector(RetinaFace):
+ def scale_detect(self, images):
+ max_res = 1920
+ h, w = images[0].shape[:2]
+ if max(h, w) > max_res:
+ init_scale = max(h, w) / max_res
+ else:
+ init_scale = 1
+ resize_scale = 2 * init_scale
+ resize_w = int(w / resize_scale)
+ resize_h = int(h / resize_scale)
+ detect_input = [cv2.resize(frame, (resize_w, resize_h)) for frame in images]
+ detect_results = post_detect(
+ self.detect(detect_input), scale=resize_scale, w=w, h=h,
+ )
+ return detect_results
diff --git a/clean/video/pwtf_dvd/preprocessing/test_tools/ct/detection/alignment.py b/clean/video/pwtf_dvd/preprocessing/test_tools/ct/detection/alignment.py
new file mode 100644
index 0000000000000000000000000000000000000000..64692a3490c7e8e29e399bd174c5906716b3e6fc
--- /dev/null
+++ b/clean/video/pwtf_dvd/preprocessing/test_tools/ct/detection/alignment.py
@@ -0,0 +1,608 @@
+from itertools import product as product
+from math import ceil
+
+import numpy as np
+import torch
+import torch.backends.cudnn as cudnn
+import torch.nn as nn
+import torch.nn.functional as F
+import torchvision.models._utils as _utils
+
+
+def conv_bn(inp, oup, stride=1, leaky=0):
+ return nn.Sequential(
+ nn.Conv2d(inp, oup, 3, stride, 1, bias=False),
+ nn.BatchNorm2d(oup),
+ nn.LeakyReLU(negative_slope=leaky, inplace=True),
+ )
+
+
+def conv_bn_no_relu(inp, oup, stride):
+ return nn.Sequential(
+ nn.Conv2d(inp, oup, 3, stride, 1, bias=False), nn.BatchNorm2d(oup),
+ )
+
+
+def conv_bn1X1(inp, oup, stride, leaky=0):
+ return nn.Sequential(
+ nn.Conv2d(inp, oup, 1, stride, padding=0, bias=False),
+ nn.BatchNorm2d(oup),
+ nn.LeakyReLU(negative_slope=leaky, inplace=True),
+ )
+
+
+def conv_dw(inp, oup, stride, leaky=0.1):
+ return nn.Sequential(
+ nn.Conv2d(inp, inp, 3, stride, 1, groups=inp, bias=False),
+ nn.BatchNorm2d(inp),
+ nn.LeakyReLU(negative_slope=leaky, inplace=True),
+ nn.Conv2d(inp, oup, 1, 1, 0, bias=False),
+ nn.BatchNorm2d(oup),
+ nn.LeakyReLU(negative_slope=leaky, inplace=True),
+ )
+
+
+class SSH(nn.Module):
+ def __init__(self, in_channel, out_channel):
+ super(SSH, self).__init__()
+ assert out_channel % 4 == 0
+ leaky = 0
+ if out_channel <= 64:
+ leaky = 0.1
+ self.conv3X3 = conv_bn_no_relu(in_channel, out_channel // 2, stride=1)
+
+ self.conv5X5_1 = conv_bn(in_channel, out_channel // 4, stride=1, leaky=leaky)
+ self.conv5X5_2 = conv_bn_no_relu(out_channel // 4, out_channel // 4, stride=1)
+
+ self.conv7X7_2 = conv_bn(
+ out_channel // 4, out_channel // 4, stride=1, leaky=leaky
+ )
+ self.conv7x7_3 = conv_bn_no_relu(out_channel // 4, out_channel // 4, stride=1)
+
+ def forward(self, input):
+ conv3X3 = self.conv3X3(input)
+
+ conv5X5_1 = self.conv5X5_1(input)
+ conv5X5 = self.conv5X5_2(conv5X5_1)
+
+ conv7X7_2 = self.conv7X7_2(conv5X5_1)
+ conv7X7 = self.conv7x7_3(conv7X7_2)
+
+ out = torch.cat([conv3X3, conv5X5, conv7X7], dim=1)
+ out = F.relu(out)
+ return out
+
+
+class FPN(nn.Module):
+ def __init__(self, in_channels_list, out_channels):
+ super(FPN, self).__init__()
+ leaky = 0
+ if out_channels <= 64:
+ leaky = 0.1
+ self.output1 = conv_bn1X1(
+ in_channels_list[0], out_channels, stride=1, leaky=leaky
+ )
+ self.output2 = conv_bn1X1(
+ in_channels_list[1], out_channels, stride=1, leaky=leaky
+ )
+ self.output3 = conv_bn1X1(
+ in_channels_list[2], out_channels, stride=1, leaky=leaky
+ )
+
+ self.merge1 = conv_bn(out_channels, out_channels, leaky=leaky)
+ self.merge2 = conv_bn(out_channels, out_channels, leaky=leaky)
+
+ def forward(self, input):
+ # names = list(input.keys())
+ input = list(input.values())
+
+ output1 = self.output1(input[0])
+ output2 = self.output2(input[1])
+ output3 = self.output3(input[2])
+
+ up3 = F.interpolate(
+ output3, size=[output2.size(2), output2.size(3)], mode="nearest"
+ )
+ output2 = output2 + up3
+ output2 = self.merge2(output2)
+
+ up2 = F.interpolate(
+ output2, size=[output1.size(2), output1.size(3)], mode="nearest"
+ )
+ output1 = output1 + up2
+ output1 = self.merge1(output1)
+
+ out = [output1, output2, output3]
+ return out
+
+
+class MobileNetV1(nn.Module):
+ def __init__(self):
+ super(MobileNetV1, self).__init__()
+ self.stage1 = nn.Sequential(
+ conv_bn(3, 8, 2, leaky=0.1), # 3
+ conv_dw(8, 16, 1), # 7
+ conv_dw(16, 32, 2), # 11
+ conv_dw(32, 32, 1), # 19
+ conv_dw(32, 64, 2), # 27
+ conv_dw(64, 64, 1), # 43
+ )
+ self.stage2 = nn.Sequential(
+ conv_dw(64, 128, 2), # 43 + 16 = 59
+ conv_dw(128, 128, 1), # 59 + 32 = 91
+ conv_dw(128, 128, 1), # 91 + 32 = 123
+ conv_dw(128, 128, 1), # 123 + 32 = 155
+ conv_dw(128, 128, 1), # 155 + 32 = 187
+ conv_dw(128, 128, 1), # 187 + 32 = 219
+ )
+ self.stage3 = nn.Sequential(
+ conv_dw(128, 256, 2), # 219 +3 2 = 241
+ conv_dw(256, 256, 1), # 241 + 64 = 301
+ )
+ self.avg = nn.AdaptiveAvgPool2d((1, 1))
+ self.fc = nn.Linear(256, 1000)
+
+ def forward(self, x):
+ x = self.stage1(x)
+ x = self.stage2(x)
+ x = self.stage3(x)
+ x = self.avg(x)
+ # x = self.model(x)
+ x = x.view(-1, 256)
+ x = self.fc(x)
+ return x
+
+
+class ClassHead(nn.Module):
+ def __init__(self, inchannels=512, num_anchors=3):
+ super(ClassHead, self).__init__()
+ self.num_anchors = num_anchors
+ self.conv1x1 = nn.Conv2d(
+ inchannels, self.num_anchors * 2, kernel_size=(1, 1), stride=1, padding=0
+ )
+
+ def forward(self, x):
+ out = self.conv1x1(x)
+ out = out.permute(0, 2, 3, 1).contiguous()
+
+ return out.view(out.shape[0], -1, 2)
+
+
+class BboxHead(nn.Module):
+ def __init__(self, inchannels=512, num_anchors=3):
+ super(BboxHead, self).__init__()
+ self.conv1x1 = nn.Conv2d(
+ inchannels, num_anchors * 4, kernel_size=(1, 1), stride=1, padding=0
+ )
+
+ def forward(self, x):
+ out = self.conv1x1(x)
+ out = out.permute(0, 2, 3, 1).contiguous()
+
+ return out.view(out.shape[0], -1, 4)
+
+
+class LandmarkHead(nn.Module):
+ def __init__(self, inchannels=512, num_anchors=3):
+ super(LandmarkHead, self).__init__()
+ self.conv1x1 = nn.Conv2d(
+ inchannels, num_anchors * 10, kernel_size=(1, 1), stride=1, padding=0
+ )
+
+ def forward(self, x):
+ out = self.conv1x1(x)
+ out = out.permute(0, 2, 3, 1).contiguous()
+
+ return out.view(out.shape[0], -1, 10)
+
+
+class RetinaFace(nn.Module):
+ def __init__(self, cfg=None, phase="train"):
+ """
+ :param cfg: Network related settings.
+ :param phase: train or test.
+ """
+ super(RetinaFace, self).__init__()
+ self.phase = phase
+ backbone = None
+ if cfg["name"] == "mobilenet0.25":
+ backbone = MobileNetV1()
+ elif cfg["name"] == "Resnet50":
+ import torchvision.models as models
+
+ backbone = models.resnet50(pretrained=cfg["pretrain"])
+
+ self.body = _utils.IntermediateLayerGetter(backbone, cfg["return_layers"])
+ in_channels_stage2 = cfg["in_channel"]
+ in_channels_list = [
+ in_channels_stage2 * 2,
+ in_channels_stage2 * 4,
+ in_channels_stage2 * 8,
+ ]
+ out_channels = cfg["out_channel"]
+ self.fpn = FPN(in_channels_list, out_channels)
+ self.ssh1 = SSH(out_channels, out_channels)
+ self.ssh2 = SSH(out_channels, out_channels)
+ self.ssh3 = SSH(out_channels, out_channels)
+
+ self.ClassHead = self._make_class_head(fpn_num=3, inchannels=cfg["out_channel"])
+ self.BboxHead = self._make_bbox_head(fpn_num=3, inchannels=cfg["out_channel"])
+ self.LandmarkHead = self._make_landmark_head(
+ fpn_num=3, inchannels=cfg["out_channel"]
+ )
+
+ def _make_class_head(self, fpn_num=3, inchannels=64, anchor_num=2):
+ classhead = nn.ModuleList()
+ for i in range(fpn_num):
+ classhead.append(ClassHead(inchannels, anchor_num))
+ return classhead
+
+ def _make_bbox_head(self, fpn_num=3, inchannels=64, anchor_num=2):
+ bboxhead = nn.ModuleList()
+ for i in range(fpn_num):
+ bboxhead.append(BboxHead(inchannels, anchor_num))
+ return bboxhead
+
+ def _make_landmark_head(self, fpn_num=3, inchannels=64, anchor_num=2):
+ landmarkhead = nn.ModuleList()
+ for i in range(fpn_num):
+ landmarkhead.append(LandmarkHead(inchannels, anchor_num))
+ return landmarkhead
+
+ def forward(self, inputs):
+ out = self.body(inputs)
+
+ # FPN
+ fpn = self.fpn(out)
+
+ # SSH
+ feature1 = self.ssh1(fpn[0])
+ feature2 = self.ssh2(fpn[1])
+ feature3 = self.ssh3(fpn[2])
+ features = [feature1, feature2, feature3]
+
+ bbox_regressions = torch.cat(
+ [self.BboxHead[i](feature) for i, feature in enumerate(features)], dim=1
+ )
+ classifications = torch.cat(
+ [self.ClassHead[i](feature) for i, feature in enumerate(features)], dim=1
+ )
+ ldm_regressions = torch.cat(
+ [self.LandmarkHead[i](feature) for i, feature in enumerate(features)], dim=1
+ )
+
+ if self.phase == "train":
+ output = (bbox_regressions, classifications, ldm_regressions)
+ else:
+ output = (
+ bbox_regressions,
+ F.softmax(classifications, dim=-1),
+ ldm_regressions,
+ )
+ return output
+
+
+# Adapted from https://github.com/Hakuyume/chainer-ssd
+def decode(loc, priors, variances):
+ boxes = torch.cat(
+ (
+ priors[:, :2] + loc[:, :2] * variances[0] * priors[:, 2:],
+ priors[:, 2:] * torch.exp(loc[:, 2:] * variances[1]),
+ ),
+ 1,
+ )
+ boxes[:, :2] -= boxes[:, 2:] / 2
+ boxes[:, 2:] += boxes[:, :2]
+ return boxes
+
+
+def decode_landm(pre, priors, variances):
+ landms = torch.cat(
+ (
+ priors[:, :2] + pre[:, :2] * variances[0] * priors[:, 2:],
+ priors[:, :2] + pre[:, 2:4] * variances[0] * priors[:, 2:],
+ priors[:, :2] + pre[:, 4:6] * variances[0] * priors[:, 2:],
+ priors[:, :2] + pre[:, 6:8] * variances[0] * priors[:, 2:],
+ priors[:, :2] + pre[:, 8:10] * variances[0] * priors[:, 2:],
+ ),
+ dim=1,
+ )
+ return landms
+
+
+def py_cpu_nms(dets, thresh):
+ """Pure Python NMS baseline."""
+ x1 = dets[:, 0]
+ y1 = dets[:, 1]
+ x2 = dets[:, 2]
+ y2 = dets[:, 3]
+ scores = dets[:, 4]
+
+ areas = (x2 - x1 + 1) * (y2 - y1 + 1)
+ order = scores.argsort()[::-1]
+
+ keep = []
+ while order.size > 0:
+ i = order[0]
+ keep.append(i)
+ xx1 = np.maximum(x1[i], x1[order[1:]])
+ yy1 = np.maximum(y1[i], y1[order[1:]])
+ xx2 = np.minimum(x2[i], x2[order[1:]])
+ yy2 = np.minimum(y2[i], y2[order[1:]])
+
+ w = np.maximum(0.0, xx2 - xx1 + 1)
+ h = np.maximum(0.0, yy2 - yy1 + 1)
+ inter = w * h
+ ovr = inter / (areas[i] + areas[order[1:]] - inter)
+
+ inds = np.where(ovr <= thresh)[0]
+ order = order[inds + 1]
+
+ return keep
+
+
+class PriorBox(object):
+ def __init__(self, cfg, image_size=None, phase="train"):
+ super(PriorBox, self).__init__()
+ self.min_sizes = cfg["min_sizes"]
+ self.steps = cfg["steps"]
+ self.clip = cfg["clip"]
+ self.image_size = image_size
+ self.feature_maps = [
+ [ceil(self.image_size[0] / step), ceil(self.image_size[1] / step)]
+ for step in self.steps
+ ]
+ self.name = "s"
+
+ def forward(self):
+ anchors = []
+ for k, f in enumerate(self.feature_maps):
+ min_sizes = self.min_sizes[k]
+ for i, j in product(range(f[0]), range(f[1])):
+ for min_size in min_sizes:
+ s_kx = min_size / self.image_size[1]
+ s_ky = min_size / self.image_size[0]
+ dense_cx = [
+ x * self.steps[k] / self.image_size[1] for x in [j + 0.5]
+ ]
+ dense_cy = [
+ y * self.steps[k] / self.image_size[0] for y in [i + 0.5]
+ ]
+ for cy, cx in product(dense_cy, dense_cx):
+ anchors += [cx, cy, s_kx, s_ky]
+
+ # back to torch land
+ output = torch.Tensor(anchors).view(-1, 4)
+ if self.clip:
+ output.clamp_(max=1, min=0)
+ return output
+
+
+cfg_mnet = {
+ "name": "mobilenet0.25",
+ "min_sizes": [[16, 32], [64, 128], [256, 512]],
+ "steps": [8, 16, 32],
+ "variance": [0.1, 0.2],
+ "clip": False,
+ "loc_weight": 2.0,
+ "gpu_train": True,
+ "batch_size": 32,
+ "ngpu": 1,
+ "epoch": 250,
+ "decay1": 190,
+ "decay2": 220,
+ "image_size": 640,
+ "pretrain": True,
+ "return_layers": {"stage1": 1, "stage2": 2, "stage3": 3},
+ "in_channel": 32,
+ "out_channel": 64,
+}
+
+cfg_re50 = {
+ "name": "Resnet50",
+ "min_sizes": [[16, 32], [64, 128], [256, 512]],
+ "steps": [8, 16, 32],
+ "variance": [0.1, 0.2],
+ "clip": False,
+ "loc_weight": 2.0,
+ "gpu_train": True,
+ "batch_size": 24,
+ "ngpu": 4,
+ "epoch": 100,
+ "decay1": 70,
+ "decay2": 90,
+ "image_size": 840,
+ "pretrain": False,
+ "return_layers": {"layer2": 1, "layer3": 2, "layer4": 3},
+ "in_channel": 256,
+ "out_channel": 256,
+}
+
+
+def check_keys(model, pretrained_state_dict):
+ ckpt_keys = set(pretrained_state_dict.keys())
+ model_keys = set(model.state_dict().keys())
+ used_pretrained_keys = model_keys & ckpt_keys
+ assert len(used_pretrained_keys) > 0, "load NONE from pretrained checkpoint"
+ return True
+
+
+def remove_prefix(state_dict, prefix):
+ """ Old style model is stored with all names of parameters sharing common prefix 'module.' """
+ f = lambda x: x.split(prefix, 1)[-1] if x.startswith(prefix) else x
+ return {f(key): value for key, value in state_dict.items()}
+
+
+def load_model(model, pretrained_path, load_to_cpu):
+ if load_to_cpu:
+ if pretrained_path is None:
+ url = "https://github.com/yinglinzheng/face_weights/releases/download/v1/mobilenet0.25_Final.pth"
+ pretrained_dict = torch.utils.model_zoo.load_url(url)
+ else:
+ pretrained_dict = torch.load(
+ pretrained_path, map_location=lambda storage, loc: storage
+ )
+ else:
+ device = torch.cuda.current_device()
+ pretrained_dict = torch.load(
+ pretrained_path, map_location=lambda storage, loc: storage.cuda(device)
+ )
+ if "state_dict" in pretrained_dict.keys():
+ pretrained_dict = remove_prefix(pretrained_dict["state_dict"], "module.")
+ else:
+ pretrained_dict = remove_prefix(pretrained_dict, "module.")
+ check_keys(model, pretrained_dict)
+ model.load_state_dict(pretrained_dict, strict=False)
+ return model
+
+
+def load_net(model_path, device, network="mobilenet"):
+ if network == "mobilenet":
+ cfg = cfg_mnet
+ elif network == "resnet50":
+ cfg = cfg_re50
+ # net and model
+ net = RetinaFace(cfg=cfg, phase="test")
+ net = load_model(net, model_path, True)
+ net.eval()
+ cudnn.benchmark = True
+ net = net.to(device)
+ return net
+
+
+def parse_det(det):
+ landmarks = det[5:].reshape(5, 2)
+ box = det[:4]
+ score = det[4]
+ return box, landmarks, score
+
+
+def post_process(
+ loc,
+ conf,
+ landms,
+ prior_data,
+ cfg,
+ scale,
+ scale1,
+ resize,
+ confidence_threshold,
+ top_k,
+ nms_threshold,
+ keep_top_k,
+):
+ boxes = decode(loc, prior_data, cfg["variance"])
+ boxes = boxes * scale / resize
+ boxes = boxes.cpu().numpy()
+ scores = conf.cpu().numpy()[:, 1]
+ landms_copy = decode_landm(landms, prior_data, cfg["variance"])
+
+ landms_copy = landms_copy * scale1 / resize
+ landms_copy = landms_copy.cpu().numpy()
+
+ # ignore low scores
+ inds = np.where(scores > confidence_threshold)[0]
+ boxes = boxes[inds]
+ landms_copy = landms_copy[inds]
+ scores = scores[inds]
+
+ # keep top-K before NMS
+ order = scores.argsort()[::-1][:top_k]
+ boxes = boxes[order]
+ landms_copy = landms_copy[order]
+ scores = scores[order]
+
+ # do NMS
+ dets = np.hstack((boxes, scores[:, np.newaxis])).astype(np.float32, copy=False)
+ keep = py_cpu_nms(dets, nms_threshold)
+ # keep = nms(dets, args.nms_threshold,force_cpu=args.cpu)
+ dets = dets[keep, :]
+ landms_copy = landms_copy[keep]
+
+ # keep top-K faster NMS
+ dets = dets[:keep_top_k, :]
+ landms_copy = landms_copy[:keep_top_k, :]
+
+ dets = np.concatenate((dets, landms_copy), axis=1)
+ # show image
+ dets = sorted(dets, key=lambda x: x[4], reverse=True)
+ dets = [parse_det(x) for x in dets]
+
+ return dets
+
+
+def batch_detect(net, images, device, is_tensor=False, normalized=False):
+ with torch.no_grad():
+ confidence_threshold = 0.02
+ cfg = cfg_mnet
+ top_k = 5000
+ nms_threshold = 0.4
+ keep_top_k = 750
+ resize = 1
+ if not is_tensor:
+ try:
+ img = np.float32(images)
+ except ValueError:
+ raise NotImplementedError("Input images must of same size")
+ img = torch.from_numpy(img)
+ else:
+ img = images.float()
+ img = img.to(device)
+ mean = (
+ torch.as_tensor([104, 117, 123], dtype=img.dtype, device=img.device)
+ .unsqueeze(0)
+ .unsqueeze(0)
+ .unsqueeze(0)
+ )
+ img -= mean
+ img = img.permute(0, 3, 1, 2)
+ (batch_size, _, im_height, im_width,) = img.shape
+ scale = torch.as_tensor(
+ [im_width, im_height, im_width, im_height],
+ dtype=img.dtype,
+ device=img.device,
+ )
+ scale = scale.to(device)
+
+ loc, conf, landms = net(img) # forward pass
+
+ priorbox = PriorBox(cfg, image_size=(im_height, im_width))
+ priors = priorbox.forward()
+ prior_data = priors.to(device)
+ scale1 = torch.as_tensor(
+ [
+ img.shape[3],
+ img.shape[2],
+ img.shape[3],
+ img.shape[2],
+ img.shape[3],
+ img.shape[2],
+ img.shape[3],
+ img.shape[2],
+ img.shape[3],
+ img.shape[2],
+ ],
+ dtype=img.dtype,
+ device=img.device,
+ )
+ scale1 = scale1.to(device)
+
+ all_dets = [
+ post_process(
+ loc_i,
+ conf_i,
+ landms_i,
+ prior_data,
+ cfg,
+ scale,
+ scale1,
+ resize,
+ confidence_threshold,
+ top_k,
+ nms_threshold,
+ keep_top_k,
+ )
+ for loc_i, conf_i, landms_i in zip(loc, conf, landms)
+ ]
+
+ return all_dets
diff --git a/clean/video/pwtf_dvd/preprocessing/test_tools/ct/detection/detector.py b/clean/video/pwtf_dvd/preprocessing/test_tools/ct/detection/detector.py
new file mode 100644
index 0000000000000000000000000000000000000000..f38050e7a050eeb05323e7d710a63c2bf1a12455
--- /dev/null
+++ b/clean/video/pwtf_dvd/preprocessing/test_tools/ct/detection/detector.py
@@ -0,0 +1,46 @@
+import os
+
+import numpy as np
+import torch
+
+from .alignment import load_net, batch_detect
+
+
+def get_project_dir():
+ current_path = os.path.abspath(os.path.join(__file__, "../"))
+ return current_path
+
+
+def relative(path):
+ path = os.path.join(get_project_dir(), path)
+ return os.path.abspath(path)
+
+
+class RetinaFace:
+ def __init__(
+ self, gpu_id=-1, model_path=None, network="mobilenet",
+ ):
+ self.gpu_id = gpu_id
+ self.device = (
+ torch.device("cpu") if gpu_id == -1 else torch.device("cuda", gpu_id)
+ )
+ self.model = load_net(model_path, self.device, network)
+
+ def detect(self, images):
+ if isinstance(images, np.ndarray):
+ if len(images.shape) == 3:
+ return batch_detect(self.model, [images], self.device)[0]
+ elif len(images.shape) == 4:
+ return batch_detect(self.model, images, self.device)
+ elif isinstance(images, list):
+ return batch_detect(self.model, np.array(images), self.device)
+ elif isinstance(images, torch.Tensor):
+ if len(images.shape) == 3:
+ return batch_detect(self.model, images.unsqueeze(0), self.device)[0]
+ elif len(images.shape) == 4:
+ return batch_detect(self.model, images, self.device)
+ else:
+ raise NotImplementedError()
+
+ def __call__(self, images):
+ return self.detect(images)
diff --git a/clean/video/pwtf_dvd/preprocessing/test_tools/ct/detection/utils.py b/clean/video/pwtf_dvd/preprocessing/test_tools/ct/detection/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..381fe3c717daeced48806cd273aecd971a16e84c
--- /dev/null
+++ b/clean/video/pwtf_dvd/preprocessing/test_tools/ct/detection/utils.py
@@ -0,0 +1,147 @@
+import cv2
+# from test_tools.utils import flatten
+import numpy as np
+def flatten(l):
+ return [item for sublist in l for item in sublist]
+
+def chunks(l, n, step=None):
+ if step is None:
+ step = n
+ return [l[i : i + n] for i in range(0, len(l), step)]
+
+
+def sample_chunks(l, n, step=None):
+ return [l[i : i + n] for i in range(0, len(l), step) if i + n <= len(l)]
+
+
+def grab_all_frames(path, max_size, cvt=False):
+ capture = cv2.VideoCapture(path)
+ ret = True
+ frames = []
+ while ret:
+ ret, frame = capture.read()
+ if ret:
+ if cvt:
+ frame = frame[..., ::-1]
+ frames.append(frame)
+ if len(frames) == max_size:
+ break
+ capture.release()
+ return frames
+
+
+def get_clips_uniform(path, count, clip_size):
+ capture = cv2.VideoCapture(path)
+ n_frames = int(capture.get(cv2.CAP_PROP_FRAME_COUNT))
+ max_clip_available = n_frames + 1 - clip_size
+ if count > max_clip_available:
+ count = max_clip_available
+ final_start = max_clip_available - 1
+ start_indices = np.linspace(0, final_start, count, endpoint=True, dtype=np.int)
+ all_clip_idx = [list(range(start, start + clip_size)) for start in start_indices]
+ valid = set(flatten(all_clip_idx))
+ max_idx = max(valid)
+
+ frames = {}
+ for idx in range(max_idx + 1):
+ # Get the next frame, but don't decode if we're not using it.
+ ret = capture.grab()
+ if not ret:
+ continue
+
+ if idx in valid:
+ ret, frame = capture.retrieve()
+ if not ret or frame is None:
+ continue
+ else:
+ # frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
+ frames[idx] = frame
+
+ capture.release()
+ clips = []
+ for clip_idx in all_clip_idx:
+ clip = []
+ flag = True
+ for idx in clip_idx:
+ if idx not in frames:
+ flag = False
+ break
+ clip.append(frames[idx])
+ if flag:
+ clips.append(clip)
+ return clips
+
+
+def get_valid_faces(detect_results, max_count=10, thres=0.5, at_least=False):
+ new_results = []
+ for i, faces in enumerate(detect_results):
+ if len(faces) > max_count:
+ faces = faces[:max_count]
+ l = []
+ for j, face in enumerate(faces):
+ if face[-1] < thres and not (j == 0 and at_least):
+ continue
+ box, lm, score = face
+ box = box.astype(np.float64)
+ lm = lm.astype(np.float64)
+ l.append((box, lm, score))
+ new_results.append(l)
+ return new_results
+
+
+def scale_box(box, scale_h, scale_w, h, w):
+ x1, y1, x2, y2 = box.astype(np.int32)
+ center_x = (x1 + x2) // 2
+ center_y = (y1 + y2) // 2
+ box_h = int((y2 - y1) * scale_h)
+ box_w = int((x2 - x1) * scale_w)
+ new_x1 = center_x - box_w // 2
+ new_x2 = new_x1 + box_w
+ new_y1 = center_y - box_h // 2
+ new_y2 = new_y1 + box_h
+ new_x1 = max(new_x1, 0)
+ new_y1 = max(new_y1, 0)
+ new_y2 = min(new_y2, h)
+ new_x2 = min(new_x2, w)
+ return new_x1, new_y1, new_x2, new_y2
+
+
+def get_bbox(detect_res):
+ tmp_detect_res = get_valid_faces(detect_res, max_count=4, thres=0.5)
+ all_face_bboxs = []
+ for faces in tmp_detect_res:
+ all_face_bboxs.extend([face[0] for face in faces])
+ all_face_bboxs = np.array(all_face_bboxs).astype(np.int)
+ x1 = all_face_bboxs[:, 0].min()
+ x2 = all_face_bboxs[:, 2].max()
+ y1 = all_face_bboxs[:, 1].min()
+ y2 = all_face_bboxs[:, 3].max()
+
+ return x1, y1, x2, y2
+
+
+def delta_detect_res(detect_res, x1, y1):
+ diff = np.array([[x1, y1]])
+ new_detect_res = []
+ for faces in detect_res:
+ f = []
+ for face in faces:
+ box, lm, score = face
+ box = box.astype(np.float64)
+ box[[0, 2]] -= x1
+ box[[1, 3]] -= y1
+ lm = lm.astype(np.float64) - diff
+ f.append((box, lm, score))
+ new_detect_res.append(f)
+ return new_detect_res
+
+
+def pre_crop(clips, detect_res):
+ box = np.array(get_bbox(detect_res))
+ w = box[2] - box[0]
+ h = box[3] - box[1]
+ x1, y1, x2, y2 = scale_box(
+ box, 1.5, 1.2 if w > 2 * h else 1.5, clips[0].shape[0], clips[0].shape[1]
+ )
+ clips = np.array(clips)
+ return clips[:, y1:y2, x1:x2], delta_detect_res(detect_res, x1, y1)
diff --git a/clean/video/pwtf_dvd/preprocessing/test_tools/ct/face_alignment/__init__.py b/clean/video/pwtf_dvd/preprocessing/test_tools/ct/face_alignment/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..b0545f2f8c2aa872a127bf4e815c1e614a971723
--- /dev/null
+++ b/clean/video/pwtf_dvd/preprocessing/test_tools/ct/face_alignment/__init__.py
@@ -0,0 +1 @@
+from .predictor import LandmarkPredictor
\ No newline at end of file
diff --git a/clean/video/pwtf_dvd/preprocessing/test_tools/ct/face_alignment/basenet.py b/clean/video/pwtf_dvd/preprocessing/test_tools/ct/face_alignment/basenet.py
new file mode 100644
index 0000000000000000000000000000000000000000..699b163e0584d56cc6d8f916b171f7ba86326efa
--- /dev/null
+++ b/clean/video/pwtf_dvd/preprocessing/test_tools/ct/face_alignment/basenet.py
@@ -0,0 +1,107 @@
+# Backbone networks used for face landmark detection
+# Cunjian Chen (cunjian@msu.edu)
+
+import torch.nn as nn
+import torchvision.models as models
+
+
+class ConvBlock(nn.Module):
+ def __init__(self, inp, oup, k, s, p, dw=False, linear=False):
+ super(ConvBlock, self).__init__()
+ self.linear = linear
+ if dw:
+ self.conv = nn.Conv2d(inp, oup, k, s, p, groups=inp, bias=False)
+ else:
+ self.conv = nn.Conv2d(inp, oup, k, s, p, bias=False)
+ self.bn = nn.BatchNorm2d(oup)
+ if not linear:
+ self.prelu = nn.PReLU(oup)
+
+ def forward(self, x):
+ x = self.conv(x)
+ x = self.bn(x)
+ if self.linear:
+ return x
+ else:
+ return self.prelu(x)
+
+
+# SE module
+# https://github.com/wujiyang/Face_Pytorch/blob/master/backbone/cbam.py
+class SEModule(nn.Module):
+ """Squeeze and Excitation Module"""
+
+ def __init__(self, channels, reduction):
+ super(SEModule, self).__init__()
+ self.avg_pool = nn.AdaptiveAvgPool2d(1)
+ self.fc1 = nn.Conv2d(
+ channels, channels // reduction, kernel_size=1, padding=0, bias=False
+ )
+ self.relu = nn.ReLU(inplace=True)
+ self.fc2 = nn.Conv2d(
+ channels // reduction, channels, kernel_size=1, padding=0, bias=False
+ )
+ self.sigmoid = nn.Sigmoid()
+
+ def forward(self, x):
+ input = x
+ x = self.avg_pool(x)
+ x = self.fc1(x)
+ x = self.relu(x)
+ x = self.fc2(x)
+ x = self.sigmoid(x)
+
+ return input * x
+
+
+# USE global depthwise convolution layer. Compatible with MobileNetV2 (224×224), MobileNetV2_ExternalData (224×224)
+class MobileNet_GDConv(nn.Module):
+ def __init__(self, num_classes):
+ super(MobileNet_GDConv, self).__init__()
+ self.pretrain_net = models.mobilenet_v2(pretrained=False)
+ self.base_net = nn.Sequential(*list(self.pretrain_net.children())[:-1])
+ self.linear7 = ConvBlock(1280, 1280, (7, 7), 1, 0, dw=True, linear=True)
+ self.linear1 = ConvBlock(1280, num_classes, 1, 1, 0, linear=True)
+
+ def forward(self, x):
+ x = self.base_net(x)
+ x = self.linear7(x)
+ x = self.linear1(x)
+ x = x.view(x.size(0), -1)
+ return x
+
+
+# USE global depthwise convolution layer. Compatible with MobileNetV2 (56×56)
+class MobileNet_GDConv_56(nn.Module):
+ def __init__(self, num_classes):
+ super(MobileNet_GDConv_56, self).__init__()
+ self.pretrain_net = models.mobilenet_v2(pretrained=False)
+ self.base_net = nn.Sequential(*list(self.pretrain_net.children())[:-1])
+ self.linear7 = ConvBlock(1280, 1280, (2, 2), 1, 0, dw=True, linear=True)
+ self.linear1 = ConvBlock(1280, num_classes, 1, 1, 0, linear=True)
+
+ def forward(self, x):
+ x = self.base_net(x)
+ x = self.linear7(x)
+ x = self.linear1(x)
+ x = x.view(x.size(0), -1)
+ return x
+
+
+# MobileNetV2 with SE; Compatible with MobileNetV2_SE (224×224) and MobileNetV2_SE_RE (224×224)
+class MobileNet_GDConv_SE(nn.Module):
+ def __init__(self, num_classes):
+ super(MobileNet_GDConv_SE, self).__init__()
+ self.pretrain_net = models.mobilenet_v2(pretrained=True)
+ self.base_net = nn.Sequential(*list(self.pretrain_net.children())[:-1])
+ self.linear7 = ConvBlock(1280, 1280, (7, 7), 1, 0, dw=True, linear=True)
+ self.linear1 = ConvBlock(1280, num_classes, 1, 1, 0, linear=True)
+ self.attention = SEModule(1280, 8)
+
+ def forward(self, x):
+ x = self.base_net(x)
+ x = self.attention(x)
+ x = self.linear7(x)
+ x = self.linear1(x)
+ x = x.view(x.size(0), -1)
+ return x
diff --git a/clean/video/pwtf_dvd/preprocessing/test_tools/ct/face_alignment/predictor.py b/clean/video/pwtf_dvd/preprocessing/test_tools/ct/face_alignment/predictor.py
new file mode 100644
index 0000000000000000000000000000000000000000..b210b673ab3af90d805e7fff9b0b66b00826fd1f
--- /dev/null
+++ b/clean/video/pwtf_dvd/preprocessing/test_tools/ct/face_alignment/predictor.py
@@ -0,0 +1,143 @@
+# Face alignment demo
+# Uses MTCNN as face detector
+# Cunjian Chen (ccunjian@gmail.com)
+import torch
+import cv2
+import numpy as np
+from torch.utils.data import DataLoader
+from .basenet import MobileNet_GDConv
+
+
+def get_device(gpu_id):
+ if gpu_id > -1:
+ return torch.device(f"cuda:{str(gpu_id)}")
+ else:
+ return torch.device("cpu")
+
+
+def load_model(file):
+ model = MobileNet_GDConv(136)
+ if file is not None:
+ model.load_state_dict(torch.load(file, map_location="cpu"))
+ else:
+ url = "https://github.com/yinglinzheng/face_weights/releases/download/v1/mobilenet_224_model_best_gdconv_external.pth"
+ model.load_state_dict(torch.utils.model_zoo.load_url(url))
+ return model
+
+
+# landmark of (5L, 2L) from [0,1] to real range
+def reproject(bbox, landmark):
+ landmark_ = landmark.clone()
+ x1, y1, x2, y2 = bbox
+ w = x2 - x1
+ h = y2 - y1
+ landmark_[:, 0] *= w
+ landmark_[:, 0] += x1
+ landmark_[:, 1] *= h
+ landmark_[:, 1] += y1
+ return landmark_
+
+
+def prepare_feed(img, face):
+ height, width, _ = img.shape
+ mean = np.asarray([0.485, 0.456, 0.406])
+ std = np.asarray([0.229, 0.224, 0.225])
+ out_size = 224
+ x1, y1, x2, y2 = face[:4]
+
+ w = x2 - x1 + 1
+ h = y2 - y1 + 1
+ size = int(min([w, h]) * 1.2)
+ cx = x1 + w // 2
+ cy = y1 + h // 2
+ x1 = cx - size // 2
+ x2 = x1 + size
+ y1 = cy - size // 2
+ y2 = y1 + size
+
+ dx = max(0, -x1)
+ dy = max(0, -y1)
+ x1 = max(0, x1)
+ y1 = max(0, y1)
+
+ edx = max(0, x2 - width)
+ edy = max(0, y2 - height)
+ x2 = min(width, x2)
+ y2 = min(height, y2)
+ new_bbox = torch.Tensor([x1, y1, x2, y2]).int()
+ x1, y1, x2, y2 = new_bbox
+ cropped = img[y1:y2, x1:x2]
+ if dx > 0 or dy > 0 or edx > 0 or edy > 0:
+ cropped = cv2.copyMakeBorder(
+ cropped, int(dy), int(edy), int(dx), int(edx), cv2.BORDER_CONSTANT, 0
+ )
+ cropped_face = cv2.resize(cropped, (out_size, out_size))
+
+ if cropped_face.shape[0] <= 0 or cropped_face.shape[1] <= 0:
+ return None
+ test_face = cropped_face.copy()
+ test_face = test_face / 255.0
+ test_face = (test_face - mean) / std
+ test_face = test_face.transpose((2, 0, 1))
+ data = torch.from_numpy(test_face).float()
+ return dict(data=data, bbox=new_bbox)
+
+
+@torch.no_grad()
+def single_predict(model, feed, device):
+ landmark = model(feed["data"].unsqueeze(0).to(device)).cpu()
+ landmark = landmark.reshape(-1, 2)
+ landmark = reproject(feed["bbox"], landmark)
+ return landmark.numpy()
+
+
+@torch.no_grad()
+def batch_predict(model, feeds, device):
+ if not isinstance(feeds, list):
+ feeds = [feeds]
+ # loader = DataLoader(FeedDataset(feeds), batch_size=50, shuffle=False)
+ data = []
+ for feed in feeds:
+ data.append(feed["data"].unsqueeze(0))
+ data = torch.cat(data, 0).to(device)
+ results = []
+
+ landmarks = model(data).cpu()
+ for landmark, feed in zip(landmarks, feeds):
+ landmark = landmark.reshape(-1, 2)
+ landmark = reproject(feed["bbox"], landmark)
+ results.append(landmark.numpy())
+ return results
+
+
+@torch.no_grad()
+def batch_predict2(model, feeds, device, batch_size=None):
+ if not isinstance(feeds, list):
+ feeds = [feeds]
+ if batch_size is None:
+ batch_size = len(feeds)
+ loader = DataLoader(feeds, batch_size=len(feeds), shuffle=False)
+ results = []
+ for feed in loader:
+ landmarks = model(feed["data"].to(device)).cpu()
+ for landmark, bbox in zip(landmarks, feed["bbox"]):
+ landmark = landmark.reshape(-1, 2)
+ landmark = reproject(bbox, landmark)
+ results.append(landmark.numpy())
+ return results
+
+
+class LandmarkPredictor:
+ def __init__(self, gpu_id=0, file=None):
+ self.device = get_device(gpu_id)
+ self.model = load_model(file).to(self.device).eval()
+
+ def __call__(self, feeds):
+ results = batch_predict2(self.model, feeds, self.device)
+ if not isinstance(feeds, list):
+ results = results[0]
+ return results
+
+ @staticmethod
+ def prepare_feed(img, face):
+ return prepare_feed(img, face)
diff --git a/clean/video/pwtf_dvd/preprocessing/test_tools/ct/face_alignment/utils.py b/clean/video/pwtf_dvd/preprocessing/test_tools/ct/face_alignment/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..e871b155963b0d1ce6891589d32615c5fc97bb66
--- /dev/null
+++ b/clean/video/pwtf_dvd/preprocessing/test_tools/ct/face_alignment/utils.py
@@ -0,0 +1,17 @@
+import cv2
+
+
+def drawLandmark_multiple(img, bbox, landmark):
+ """
+ Input:
+ - img: gray or RGB
+ - bbox: type of BBox
+ - landmark: reproject landmark of (5L, 2L)
+ Output:
+ - img marked with landmark and bbox
+ """
+ x1, y1, x2, y2 = bbox
+ cv2.rectangle(img, (x1, y1), (x2, y2), (0, 0, 255), 2)
+ for x, y in landmark:
+ cv2.circle(img, (int(x), int(y)), 2, (0, 255, 0), -1)
+ return img
diff --git a/clean/video/pwtf_dvd/preprocessing/test_tools/ct/operations.py b/clean/video/pwtf_dvd/preprocessing/test_tools/ct/operations.py
new file mode 100644
index 0000000000000000000000000000000000000000..68375fcc4efd768abcfddf39521af21d574c4aac
--- /dev/null
+++ b/clean/video/pwtf_dvd/preprocessing/test_tools/ct/operations.py
@@ -0,0 +1,79 @@
+import os
+
+import os
+import cv2
+import numpy as np
+from .tracking.sort import iou
+
+
+def face_iou(f1, f2):
+ return iou(f1[0], f2[0])
+
+
+def simple_tracking(batch_landmarks, index=0, thres=0.5):
+ track = []
+
+ for i, faces in enumerate(batch_landmarks):
+ if i == 0:
+ if len(faces) <= index or faces[index][-1] < 0.8:
+ return None
+ if index != 0:
+ for idx in range(index):
+ if face_iou(faces[idx], faces[index]) > thres:
+ return None
+ track.append(faces[index])
+ else:
+ last = track[i - 1]
+ if len(faces) == 0:
+ return None
+ sorted_faces = sorted(faces, key=lambda x: face_iou(x, last), reverse=True)
+ if face_iou(sorted_faces[0], last) < thres:
+ return None
+ track.append(sorted_faces[0])
+ return track
+
+
+def multiple_tracking(batch_landmarks):
+ tracks = []
+ for i in range(len(batch_landmarks[0])):
+ track = simple_tracking(batch_landmarks, index=i)
+ if track is None:
+ continue
+ tracks.append(track)
+ return tracks
+
+def find_longest(detect_res):
+ fc = len(detect_res)
+ tuples = []
+ start = 0
+ end = 0
+ previous_count = -1
+ all_tracks = []
+ # start 取得到,end 取不到
+ while start < (fc - 1):
+ for end in range(start + 2, fc + 1):
+ tracks = multiple_tracking(detect_res[start:end])
+ if (len(tracks) != previous_count and previous_count != -1) or len(
+ tracks
+ ) == 0:
+ break
+ previous_count = len(tracks)
+ if end - start > 2:
+ if end != fc:
+ un_reach_end = end - 1
+ else:
+ un_reach_end = end
+ sub_tracks = multiple_tracking(detect_res[start:un_reach_end])
+ if end == fc and len(sub_tracks) == 0:
+ un_reach_end = end - 1
+ sub_tracks = multiple_tracking(detect_res[start:un_reach_end])
+ if len(sub_tracks) > 0:
+ tpl = (start, un_reach_end)
+ tuples.append(tpl)
+ all_tracks.append(sub_tracks[0])
+ else:
+ raise NotImplementedError
+ previous_count = -1
+ end = un_reach_end
+ start = end
+ return tuples, all_tracks
\ No newline at end of file
diff --git a/clean/video/pwtf_dvd/preprocessing/test_tools/ct/tracking/__init__.py b/clean/video/pwtf_dvd/preprocessing/test_tools/ct/tracking/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/clean/video/pwtf_dvd/preprocessing/test_tools/ct/tracking/sort.py b/clean/video/pwtf_dvd/preprocessing/test_tools/ct/tracking/sort.py
new file mode 100644
index 0000000000000000000000000000000000000000..dc7b0838e7110a2d3521c6d4cfefbb40cc266c23
--- /dev/null
+++ b/clean/video/pwtf_dvd/preprocessing/test_tools/ct/tracking/sort.py
@@ -0,0 +1,285 @@
+"""
+ SORT: A Simple, Online and Realtime Tracker
+ Copyright (C) 2016 Alex Bewley alex@dynamicdetection.com
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+"""
+from __future__ import print_function
+import os.path
+import numpy as np
+import matplotlib.pyplot as plt
+import matplotlib.patches as patches
+from scipy.optimize import linear_sum_assignment
+import glob
+import time
+import argparse
+from filterpy.kalman import KalmanFilter
+
+
+def iou(bb_test, bb_gt):
+ """
+ Computes IUO between two bboxes in the form [x1,y1,x2,y2]
+ """
+ xx1 = np.maximum(bb_test[0], bb_gt[0])
+ yy1 = np.maximum(bb_test[1], bb_gt[1])
+ xx2 = np.minimum(bb_test[2], bb_gt[2])
+ yy2 = np.minimum(bb_test[3], bb_gt[3])
+ w = np.maximum(0.0, xx2 - xx1)
+ h = np.maximum(0.0, yy2 - yy1)
+ wh = w * h
+ o = wh / (
+ (bb_test[2] - bb_test[0]) * (bb_test[3] - bb_test[1])
+ + (bb_gt[2] - bb_gt[0]) * (bb_gt[3] - bb_gt[1])
+ - wh
+ )
+ return o
+
+
+def convert_bbox_to_z(bbox):
+ """
+ Takes a bounding box in the form [x1,y1,x2,y2] and returns z in the form
+ [x,y,s,r] where x,y is the centre of the box and s is the scale/area and r is
+ the aspect ratio
+ """
+ w = bbox[2] - bbox[0]
+ h = bbox[3] - bbox[1]
+ x = bbox[0] + w / 2.0
+ y = bbox[1] + h / 2.0
+ s = w * h # scale is just area
+ r = w / float(h)
+ return np.array([x, y, s, r]).reshape((4, 1))
+
+
+def convert_x_to_bbox(x, score=None):
+ """
+ Takes a bounding box in the centre form [x,y,s,r] and returns it in the form
+ [x1,y1,x2,y2] where x1,y1 is the top left and x2,y2 is the bottom right
+ """
+ w = np.sqrt(x[2] * x[3])
+ h = x[2] / w
+ if score == None:
+ return np.array(
+ [x[0] - w / 2.0, x[1] - h / 2.0, x[0] + w / 2.0, x[1] + h / 2.0]
+ ).reshape((1, 4))
+ else:
+ return np.array(
+ [x[0] - w / 2.0, x[1] - h / 2.0, x[0] + w / 2.0, x[1] + h / 2.0, score]
+ ).reshape((1, 5))
+
+
+class KalmanBoxTracker(object):
+ """
+ This class represents the internel state of individual tracked objects observed as bbox.
+ """
+
+ count = 0
+
+ def __init__(self, bbox):
+ """
+ Initialises a tracker using initial bounding box.
+ """
+ # define constant velocity model
+ self.kf = KalmanFilter(dim_x=7, dim_z=4)
+ self.kf.F = np.array(
+ [
+ [1, 0, 0, 0, 1, 0, 0],
+ [0, 1, 0, 0, 0, 1, 0],
+ [0, 0, 1, 0, 0, 0, 1],
+ [0, 0, 0, 1, 0, 0, 0],
+ [0, 0, 0, 0, 1, 0, 0],
+ [0, 0, 0, 0, 0, 1, 0],
+ [0, 0, 0, 0, 0, 0, 1],
+ ]
+ )
+ self.kf.H = np.array(
+ [
+ [1, 0, 0, 0, 0, 0, 0],
+ [0, 1, 0, 0, 0, 0, 0],
+ [0, 0, 1, 0, 0, 0, 0],
+ [0, 0, 0, 1, 0, 0, 0],
+ ]
+ )
+
+ self.kf.R[2:, 2:] *= 10.0
+ self.kf.P[
+ 4:, 4:
+ ] *= 1000.0 # give high uncertainty to the unobservable initial velocities
+ self.kf.P *= 10.0
+ self.kf.Q[-1, -1] *= 0.01
+ self.kf.Q[4:, 4:] *= 0.01
+
+ self.kf.x[:4] = convert_bbox_to_z(bbox)
+ self.time_since_update = 0
+ self.id = KalmanBoxTracker.count
+ KalmanBoxTracker.count += 1
+ self.history = []
+ self.hits = 0
+ self.hit_streak = 0
+ self.age = 0
+
+ def update(self, bbox):
+ """
+ Updates the state vector with observed bbox.
+ """
+ self.time_since_update = 0
+ self.history = []
+ self.hits += 1
+ self.hit_streak += 1
+ self.kf.update(convert_bbox_to_z(bbox))
+
+ def predict(self):
+ """
+ Advances the state vector and returns the predicted bounding box estimate.
+ """
+ if (self.kf.x[6] + self.kf.x[2]) <= 0:
+ self.kf.x[6] *= 0.0
+ self.kf.predict()
+ self.age += 1
+ if self.time_since_update > 0:
+ self.hit_streak = 0
+ self.time_since_update += 1
+ self.history.append(convert_x_to_bbox(self.kf.x))
+ return self.history[-1]
+
+ def get_state(self):
+ """
+ Returns the current bounding box estimate.
+ """
+ return convert_x_to_bbox(self.kf.x)
+
+
+def associate_detections_to_trackers(detections, trackers, iou_threshold=0.3):
+ """
+ Assigns detections to tracked object (both represented as bounding boxes)
+
+ Returns 3 lists of matches, unmatched_detections and unmatched_trackers
+ """
+ if len(trackers) == 0:
+ return (
+ np.empty((0, 2), dtype=int),
+ np.arange(len(detections)),
+ np.empty((0, 5), dtype=int),
+ )
+ iou_matrix = np.zeros((len(detections), len(trackers)), dtype=np.float32)
+
+ for d, det in enumerate(detections):
+ for t, trk in enumerate(trackers):
+ iou_matrix[d, t] = iou(det, trk)
+
+ matched_indices = linear_sum_assignment(-iou_matrix)
+ matched_indices = np.array(list(zip(*matched_indices)), dtype=np.int)
+ matched_indices.shape = (-1, 2)
+ # print(matched_indices)
+ # print(type(matched_indices))
+
+ unmatched_detections = []
+ for d, det in enumerate(detections):
+ if d not in matched_indices[:, 0]:
+ unmatched_detections.append(d)
+ unmatched_trackers = []
+ for t, trk in enumerate(trackers):
+ if t not in matched_indices[:, 1]:
+ unmatched_trackers.append(t)
+
+ # filter out matched with low IOU
+ matches = []
+ for m in matched_indices:
+ if iou_matrix[m[0], m[1]] < iou_threshold:
+ unmatched_detections.append(m[0])
+ unmatched_trackers.append(m[1])
+ else:
+ matches.append(m.reshape(1, 2))
+ if len(matches) == 0:
+ matches = np.empty((0, 2), dtype=int)
+ else:
+ matches = np.concatenate(matches, axis=0)
+
+ return matches, np.array(unmatched_detections), np.array(unmatched_trackers)
+
+
+class Sort(object):
+ def __init__(self, max_age=1, min_hits=3):
+ """
+ Sets key parameters for SORT
+ """
+ self.max_age = max_age
+ self.min_hits = min_hits
+ self.trackers = []
+ self.frame_count = 0
+
+ def update(self, dets):
+ """
+ Params:
+ dets - a numpy array of detections in the format [[x1,y1,x2,y2,score],[x1,y1,x2,y2,score],...]
+ Requires: this method must be called once for each frame even with empty detections.
+ Returns the a similar array, where the last column is the object ID.
+
+ NOTE: The number of objects returned may differ from the number of detections provided.
+ """
+ self.frame_count += 1
+ # get predicted locations from existing trackers.
+ trks = np.zeros((len(self.trackers), 5))
+ to_del = []
+ ret = []
+ for t, trk in enumerate(trks):
+ pos = self.trackers[t].predict()[0]
+ trk[:] = [pos[0], pos[1], pos[2], pos[3], 0]
+ if np.any(np.isnan(pos)):
+ to_del.append(t)
+ trks = np.ma.compress_rows(np.ma.masked_invalid(trks))
+ for t in reversed(to_del):
+ self.trackers.pop(t)
+ matched, unmatched_dets, unmatched_trks = associate_detections_to_trackers(
+ dets, trks
+ )
+
+ # update matched trackers with assigned detections
+ for t, trk in enumerate(self.trackers):
+ if t not in unmatched_trks:
+ d = matched[np.where(matched[:, 1] == t)[0], 0]
+ trk.update(dets[d, :][0])
+
+ # create and initialise new trackers for unmatched detections
+ for i in unmatched_dets:
+ trk = KalmanBoxTracker(dets[i, :])
+ self.trackers.append(trk)
+ i = len(self.trackers)
+ for trk in reversed(self.trackers):
+ d = trk.get_state()[0]
+ if (trk.time_since_update < 1) and (
+ trk.hit_streak >= self.min_hits or self.frame_count <= self.min_hits
+ ):
+ ret.append(
+ np.concatenate((d, [trk.id + 1])).reshape(1, -1)
+ ) # +1 as MOT benchmark requires positive
+ i -= 1
+ # remove dead tracklet
+ if trk.time_since_update > self.max_age:
+ self.trackers.pop(i)
+ if len(ret) > 0:
+ return np.concatenate(ret)
+ return np.empty((0, 5))
+
+
+def parse_args():
+ """Parse input arguments."""
+ parser = argparse.ArgumentParser(description="SORT demo")
+ parser.add_argument(
+ "--display",
+ dest="display",
+ help="Display online tracker output (slow) [False]",
+ action="store_true",
+ )
+ args = parser.parse_args()
+ return args
diff --git a/clean/video/pwtf_dvd/preprocessing/test_tools/ct/tracking/tracker.py b/clean/video/pwtf_dvd/preprocessing/test_tools/ct/tracking/tracker.py
new file mode 100644
index 0000000000000000000000000000000000000000..20dd79f41a56bcb4873e83bb9c76db9ffbf0f627
--- /dev/null
+++ b/clean/video/pwtf_dvd/preprocessing/test_tools/ct/tracking/tracker.py
@@ -0,0 +1,27 @@
+from .sort import Sort
+import numpy as np
+
+
+def get_detections(faces):
+ detections = []
+ for face in faces:
+ x1, y1, x2, y2 = face[0]
+ detections.append((x1, y1, x2, y2, face[-1]))
+ return np.array(detections)
+
+
+def get_tracks(detect_results):
+ tracks = {}
+ mot_tracker = Sort()
+ for faces in detect_results:
+ detections = get_detections(faces)
+ track_bbs_ids = mot_tracker.update(detections)
+ for track in track_bbs_ids: # 单独框出每一张人脸
+ id = int(track[-1])
+ box = track[:4]
+ if id in tracks:
+ tracks[id].append(box)
+ else:
+ tracks[id] = [box]
+
+ return [track for id, track in tracks.items() if len(track) == len(detect_results)]
diff --git a/clean/video/pwtf_dvd/preprocessing/test_tools/ct/utils.py b/clean/video/pwtf_dvd/preprocessing/test_tools/ct/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..5ff180fb2a24b9e8bd673d3428e3b101da16a6b0
--- /dev/null
+++ b/clean/video/pwtf_dvd/preprocessing/test_tools/ct/utils.py
@@ -0,0 +1,5 @@
+import cv2
+
+
+def write_img(file, img):
+ cv2.imwrite(file, img, [cv2.IMWRITE_PNG_COMPRESSION, 0])
diff --git a/clean/video/pwtf_dvd/preprocessing/test_tools/faster_crop_align_xray.py b/clean/video/pwtf_dvd/preprocessing/test_tools/faster_crop_align_xray.py
new file mode 100644
index 0000000000000000000000000000000000000000..3e99f2f0930e26539793e3d76d74e9df7afc186b
--- /dev/null
+++ b/clean/video/pwtf_dvd/preprocessing/test_tools/faster_crop_align_xray.py
@@ -0,0 +1,73 @@
+import numpy as np
+import cv2
+from .warp_for_xray import (
+ estimiate_batch_transform,
+ transform_landmarks,
+ std_points_256,
+)
+import numpy as np
+
+
+class FasterCropAlignXRay:
+ """
+ 修正到统一坐标系,统一图像大小到标准尺寸
+ """
+
+ def __init__(self, size=256):
+ self.image_size = size
+ self.std_points = std_points_256 * size / 256.0
+
+ def __call__(self, landmarks, images=None, jitter=False):
+ landmarks = [landmark[:4] for landmark in landmarks]
+ ori_boxes = np.array([ori_box for _, _, _, ori_box in landmarks])
+ five_landmarks = np.array([ldm5 for _, ldm5, _, _ in landmarks])
+ landmarks68 = np.array([ldm68 for _, _, ldm68, _ in landmarks])
+ # assert landmarks68.min() > 0
+
+ left_top = ori_boxes[:, :2].min(0)
+
+ right_bottom = ori_boxes[:, 2:].max(0)
+
+ size = right_bottom - left_top
+
+ w, h = size
+
+ diff = ori_boxes[:, :2] - left_top[None, ...]
+
+ new_five_landmarks = five_landmarks + diff[:, None, :]
+ new_landmarks68 = landmarks68 + diff[:, None, :]
+
+ landmark_for_estimiate = new_five_landmarks.copy()
+ if jitter:
+ landmark_for_estimiate += np.random.uniform(
+ -4, 4, landmark_for_estimiate.shape
+ )
+
+ tfm, trans = estimiate_batch_transform(
+ landmark_for_estimiate, tgt_pts=self.std_points
+ )
+
+ transformed_landmarks68 = np.array(
+ [transform_landmarks(ldm68, trans) for ldm68 in new_landmarks68]
+ )
+
+ if images is not None:
+ transformed_images = [
+ self.process_sinlge(tfm, image, d, h, w)
+ for image, d in zip(images, diff)
+ ] # 拼接 func 的参数
+ transformed_images = np.stack(transformed_images)
+ return transformed_landmarks68, transformed_images
+ else:
+ return transformed_landmarks68
+
+ def process_sinlge(self, tfm, image, d, h, w):
+ assert isinstance(image, np.ndarray)
+ new_image = np.zeros((h, w, 3), dtype=np.uint8)
+ x, y = d
+ ih, iw, _ = image.shape
+ new_image[y : y + ih, x : x + iw] = image
+ transformed_image = cv2.warpAffine(
+ new_image, tfm, (self.image_size, self.image_size)
+ )
+ return transformed_image
diff --git a/clean/video/pwtf_dvd/preprocessing/test_tools/supply_writer.py b/clean/video/pwtf_dvd/preprocessing/test_tools/supply_writer.py
new file mode 100644
index 0000000000000000000000000000000000000000..0394dfbb8fc50d47984eaa937537de144e51ee81
--- /dev/null
+++ b/clean/video/pwtf_dvd/preprocessing/test_tools/supply_writer.py
@@ -0,0 +1,49 @@
+import cv2
+
+class SupplyWriter:
+ def __init__(self, intput_video, output_video, opt_thres, rgb_input=True):
+ reader = cv2.VideoCapture(intput_video)
+ fourcc = cv2.VideoWriter_fourcc(*"XVID")
+ fps = reader.get(cv2.CAP_PROP_FPS)
+ width = int(reader.get(3))
+ height = int(reader.get(4))
+ reader.release()
+ self.padding = 40
+
+ self.writer = cv2.VideoWriter(output_video, fourcc, fps, (height, width)[::-1])
+ self.rgb_input = rgb_input
+ self.opt_thres = opt_thres
+
+ def run(self, images, scores, boxes):
+ # Text variables
+ font_face = cv2.FONT_HERSHEY_SIMPLEX
+ thickness = 5
+ font_scale = 3
+
+ for image, score, box in zip(images, scores, boxes):
+ if self.rgb_input:
+ image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
+ if box is not None:
+ label = "fake" if score > self.opt_thres else "real"
+ x1, y1, x2, y2 = box
+ x = int(x1)
+ y = int(y1)
+ w = int(x2 - x1)
+ h = int(y2 - y1)
+ color = (
+ (255, 255, 0) if label == "real" else (0, 255, 255)
+ ) # BGR 255 0
+ cv2.putText(
+ image,
+ label,
+ (x, y + h + 68),
+ font_face,
+ font_scale,
+ color,
+ thickness,
+ 2,
+ )
+ # draw box over face
+ cv2.rectangle(image, (x, y), (x + w, y + h), color, 10)
+ self.writer.write(image)
+ self.writer.release()
diff --git a/clean/video/pwtf_dvd/preprocessing/test_tools/utils.py b/clean/video/pwtf_dvd/preprocessing/test_tools/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..051f29c7c5808fd08aae14b6a44c54490986ce3a
--- /dev/null
+++ b/clean/video/pwtf_dvd/preprocessing/test_tools/utils.py
@@ -0,0 +1,115 @@
+import numpy as np
+import cv2
+import os
+import platform
+import json
+import errno
+
+
+
+def weak_check(detect_res):
+ return sum([len(faces) for faces in detect_res]) > len(detect_res) * 0.75
+
+
+def get_crop_box(shape, box, scale=0.5):
+ height, width = shape
+ box = np.rint(box).astype(np.int64)
+ new_box = box.reshape(2, 2)
+ size = new_box[1] - new_box[0]
+ diff = scale * size
+ diff = diff[None, :] * np.array([-1, 1])[:, None]
+ new_box = new_box + diff
+ new_box[:, 0] = np.clip(new_box[:, 0], 0, width - 1)
+ new_box[:, 1] = np.clip(new_box[:, 1], 0, height - 1)
+ new_box = np.rint(new_box).astype(np.int64)
+ return new_box.reshape(-1)
+
+
+def get_fps(input_file):
+ reader = cv2.VideoCapture(input_file)
+ fps = reader.get(cv2.CAP_PROP_FPS)
+ reader.release()
+ return fps
+
+
+
+def mkdir_p(dirname):
+ """Like "mkdir -p", make a dir recursively, but do nothing if the dir exists
+ 这个是线程安全的, from Lingzhi Li
+ Args:
+ dirname(str):
+ """
+ assert dirname is not None
+ if dirname == "" or os.path.isdir(dirname):
+ return
+ try:
+ os.makedirs(dirname)
+ except OSError as e:
+ if e.errno != errno.EEXIST:
+ raise e
+
+
+def mkdir(*args):
+ for folder in args:
+ if not os.path.isdir(folder):
+ mkdir_p(folder)
+
+
+def make_join(*args):
+ folder = os.path.join(*args)
+ mkdir(folder)
+ return folder
+
+
+def list_dir(folder, condition=None, key=lambda x: x, reverse=False, co_join=[]):
+ files = os.listdir(folder)
+ if condition is not None:
+ files = filter(condition, files)
+ co_join = [folder] + co_join
+ if key is not None:
+ files = sorted(files, key=key, reverse=reverse)
+ files = [(file, *[os.path.join(fold, file) for fold in co_join]) for file in files]
+ return files
+
+def get_jointer(file):
+ def jointer(folder):
+ return os.path.join(folder, file)
+
+ return jointer
+
+def flatten(l):
+ return [item for sublist in l for item in sublist]
+
+
+def is_win():
+ return platform.system() == "Windows"
+
+
+def get_postfix(post_fix):
+ return lambda x: x.endswith(post_fix)
+
+
+def partition(images, size):
+ """
+ Returns a new list with elements
+ of which is a list of certain size.
+
+ >>> partition([1, 2, 3, 4], 3)
+ [[1, 2, 3], [4]]
+ """
+ return [
+ images[i : i + size] if i + size <= len(images) else images[i:]
+ for i in range(0, len(images), size)
+ ]
+
+
+def load_json(file):
+ with open(file, "r") as f:
+ res = json.load(f)
+ return res
+
+
+def save_json(file, obj):
+ with open(file, "w", encoding="utf-8") as f:
+ json.dump(obj, f, indent=4, ensure_ascii=False)
+
diff --git a/clean/video/pwtf_dvd/preprocessing/test_tools/warp_for_xray.py b/clean/video/pwtf_dvd/preprocessing/test_tools/warp_for_xray.py
new file mode 100644
index 0000000000000000000000000000000000000000..ea68def0bcc6b384f1198f21fb0d72253f8085d6
--- /dev/null
+++ b/clean/video/pwtf_dvd/preprocessing/test_tools/warp_for_xray.py
@@ -0,0 +1,574 @@
+import numpy as np
+import cv2
+
+# -*- coding: utf-8 -*-
+"""
+Created on Tue Jul 11 06:54:28 2017
+
+@author: zhaoyafei
+"""
+
+import numpy as np
+from numpy.linalg import inv, norm, lstsq
+from numpy.linalg import matrix_rank as rank
+
+"""
+Introduction:
+----------
+numpy implemetation form matlab function CP2TFORM(...)
+with 'transformtype':
+ 1) 'nonreflective similarity'
+ 2) 'similarity'
+
+
+MATLAB code:
+----------
+%--------------------------------------
+% Function findNonreflectiveSimilarity
+%
+function [trans, output] = findNonreflectiveSimilarity(uv,xy,options)
+%
+% For a nonreflective similarity:
+%
+% let sc = s*cos(theta)
+% let ss = s*sin(theta)
+%
+% [ sc -ss
+% [u v] = [x y 1] * ss sc
+% tx ty]
+%
+% There are 4 unknowns: sc,ss,tx,ty.
+%
+% Another way to write this is:
+%
+% u = [x y 1 0] * [sc
+% ss
+% tx
+% ty]
+%
+% v = [y -x 0 1] * [sc
+% ss
+% tx
+% ty]
+%
+% With 2 or more correspondence points we can combine the u equations and
+% the v equations for one linear system to solve for sc,ss,tx,ty.
+%
+% [ u1 ] = [ x1 y1 1 0 ] * [sc]
+% [ u2 ] [ x2 y2 1 0 ] [ss]
+% [ ... ] [ ... ] [tx]
+% [ un ] [ xn yn 1 0 ] [ty]
+% [ v1 ] [ y1 -x1 0 1 ]
+% [ v2 ] [ y2 -x2 0 1 ]
+% [ ... ] [ ... ]
+% [ vn ] [ yn -xn 0 1 ]
+%
+% Or rewriting the above matrix equation:
+% U = X * r, where r = [sc ss tx ty]'
+% so r = X\ U.
+%
+
+K = options.K;
+M = size(xy,1);
+x = xy(:,1);
+y = xy(:,2);
+X = [x y ones(M,1) zeros(M,1);
+ y -x zeros(M,1) ones(M,1) ];
+
+u = uv(:,1);
+v = uv(:,2);
+U = [u; v];
+
+% We know that X * r = U
+if rank(X) >= 2*K
+ r = X \ U;
+else
+ error(message('images:cp2tform:twoUniquePointsReq'))
+end
+
+sc = r(1);
+ss = r(2);
+tx = r(3);
+ty = r(4);
+
+Tinv = [sc -ss 0;
+ ss sc 0;
+ tx ty 1];
+
+T = inv(Tinv);
+T(:,3) = [0 0 1]';
+
+trans = maketform('affine', T);
+output = [];
+
+%-------------------------
+% Function findSimilarity
+%
+function [trans, output] = findSimilarity(uv,xy,options)
+%
+% The similarities are a superset of the nonreflective similarities as they may
+% also include reflection.
+%
+% let sc = s*cos(theta)
+% let ss = s*sin(theta)
+%
+% [ sc -ss
+% [u v] = [x y 1] * ss sc
+% tx ty]
+%
+% OR
+%
+% [ sc ss
+% [u v] = [x y 1] * ss -sc
+% tx ty]
+%
+% Algorithm:
+% 1) Solve for trans1, a nonreflective similarity.
+% 2) Reflect the xy data across the Y-axis,
+% and solve for trans2r, also a nonreflective similarity.
+% 3) Transform trans2r to trans2, undoing the reflection done in step 2.
+% 4) Use TFORMFWD to transform uv using both trans1 and trans2,
+% and compare the results, Returnsing the transformation corresponding
+% to the smaller L2 norm.
+
+% Need to reset options.K to prepare for calls to findNonreflectiveSimilarity.
+% This is safe because we already checked that there are enough point pairs.
+options.K = 2;
+
+% Solve for trans1
+[trans1, output] = findNonreflectiveSimilarity(uv,xy,options);
+
+
+% Solve for trans2
+
+% manually reflect the xy data across the Y-axis
+xyR = xy;
+xyR(:,1) = -1*xyR(:,1);
+
+trans2r = findNonreflectiveSimilarity(uv,xyR,options);
+
+% manually reflect the tform to undo the reflection done on xyR
+TreflectY = [-1 0 0;
+ 0 1 0;
+ 0 0 1];
+trans2 = maketform('affine', trans2r.tdata.T * TreflectY);
+
+
+% Figure out if trans1 or trans2 is better
+xy1 = tformfwd(trans1,uv);
+norm1 = norm(xy1-xy);
+
+xy2 = tformfwd(trans2,uv);
+norm2 = norm(xy2-xy);
+
+if norm1 <= norm2
+ trans = trans1;
+else
+ trans = trans2;
+end
+"""
+
+
+class MatlabCp2tormException(Exception):
+ def __str__(self):
+ return "In File {}:{}".format(__file__, super.__str__(self))
+
+
+def tformfwd(trans, uv):
+ """
+ Function:
+ ----------
+ apply affine transform 'trans' to uv
+
+ Parameters:
+ ----------
+ @trans: 3x3 np.array
+ transform matrix
+ @uv: Kx2 np.array
+ each row is a pair of coordinates (x, y)
+
+ Returns:
+ ----------
+ @xy: Kx2 np.array
+ each row is a pair of transformed coordinates (x, y)
+ """
+ uv = np.hstack((uv, np.ones((uv.shape[0], 1))))
+ xy = np.dot(uv, trans)
+ xy = xy[:, 0:-1]
+ return xy
+
+
+def tforminv(trans, uv):
+ """
+ Function:
+ ----------
+ apply the inverse of affine transform 'trans' to uv
+
+ Parameters:
+ ----------
+ @trans: 3x3 np.array
+ transform matrix
+ @uv: Kx2 np.array
+ each row is a pair of coordinates (x, y)
+
+ Returns:
+ ----------
+ @xy: Kx2 np.array
+ each row is a pair of inverse-transformed coordinates (x, y)
+ """
+ Tinv = inv(trans)
+ xy = tformfwd(Tinv, uv)
+ return xy
+
+
+def findNonreflectiveSimilarity(uv, xy, options=None):
+ """
+ Function:
+ ----------
+ Find Non-reflective Similarity Transform Matrix 'trans':
+ u = uv[:, 0]
+ v = uv[:, 1]
+ x = xy[:, 0]
+ y = xy[:, 1]
+ [x, y, 1] = [u, v, 1] * trans
+
+ Parameters:
+ ----------
+ @uv: Kx2 np.array
+ source points each row is a pair of coordinates (x, y)
+ @xy: Kx2 np.array
+ each row is a pair of inverse-transformed
+ @option: not used, keep it as None
+
+ Returns:
+ @trans: 3x3 np.array
+ transform matrix from uv to xy
+ @trans_inv: 3x3 np.array
+ inverse of trans, transform matrix from xy to uv
+
+ Matlab:
+ ----------
+ % For a nonreflective similarity:
+ %
+ % let sc = s*cos(theta)
+ % let ss = s*sin(theta)
+ %
+ % [ sc -ss
+ % [u v] = [x y 1] * ss sc
+ % tx ty]
+ %
+ % There are 4 unknowns: sc,ss,tx,ty.
+ %
+ % Another way to write this is:
+ %
+ % u = [x y 1 0] * [sc
+ % ss
+ % tx
+ % ty]
+ %
+ % v = [y -x 0 1] * [sc
+ % ss
+ % tx
+ % ty]
+ %
+ % With 2 or more correspondence points we can combine the u equations and
+ % the v equations for one linear system to solve for sc,ss,tx,ty.
+ %
+ % [ u1 ] = [ x1 y1 1 0 ] * [sc]
+ % [ u2 ] [ x2 y2 1 0 ] [ss]
+ % [ ... ] [ ... ] [tx]
+ % [ un ] [ xn yn 1 0 ] [ty]
+ % [ v1 ] [ y1 -x1 0 1 ]
+ % [ v2 ] [ y2 -x2 0 1 ]
+ % [ ... ] [ ... ]
+ % [ vn ] [ yn -xn 0 1 ]
+ %
+ % Or rewriting the above matrix equation:
+ % U = X * r, where r = [sc ss tx ty]'
+ % so r = X\ U.
+ %
+ """
+ options = {"K": 2}
+
+ K = options["K"]
+ M = xy.shape[0]
+ x = xy[:, 0].reshape((-1, 1)) # use reshape to keep a column vector
+ y = xy[:, 1].reshape((-1, 1)) # use reshape to keep a column vector
+ # print '--->x, y:\n', x, y
+
+ tmp1 = np.hstack((x, y, np.ones((M, 1)), np.zeros((M, 1))))
+ tmp2 = np.hstack((y, -x, np.zeros((M, 1)), np.ones((M, 1))))
+ X = np.vstack((tmp1, tmp2))
+ # print '--->X.shape: ', X.shape
+ # print 'X:\n', X
+
+ u = uv[:, 0].reshape((-1, 1)) # use reshape to keep a column vector
+ v = uv[:, 1].reshape((-1, 1)) # use reshape to keep a column vector
+ U = np.vstack((u, v))
+ # print '--->U.shape: ', U.shape
+ # print 'U:\n', U
+
+ # We know that X * r = U
+ if rank(X) >= 2 * K:
+ r, _, _, _ = lstsq(X, U, rcond=-1)
+ r = np.squeeze(r)
+ else:
+ raise Exception("cp2tform:twoUniquePointsReq")
+
+ # print '--->r:\n', r
+
+ sc = r[0]
+ ss = r[1]
+ tx = r[2]
+ ty = r[3]
+
+ Tinv = np.array([[sc, -ss, 0], [ss, sc, 0], [tx, ty, 1]])
+
+ # print '--->Tinv:\n', Tinv
+
+ T = inv(Tinv)
+ # print '--->T:\n', T
+
+ T[:, 2] = np.array([0, 0, 1])
+
+ return T, Tinv
+
+
+def findSimilarity(uv, xy, options=None):
+ """
+ Function:
+ ----------
+ Find Reflective Similarity Transform Matrix 'trans':
+ u = uv[:, 0]
+ v = uv[:, 1]
+ x = xy[:, 0]
+ y = xy[:, 1]
+ [x, y, 1] = [u, v, 1] * trans
+
+ Parameters:
+ ----------
+ @uv: Kx2 np.array
+ source points each row is a pair of coordinates (x, y)
+ @xy: Kx2 np.array
+ each row is a pair of inverse-transformed
+ @option: not used, keep it as None
+
+ Returns:
+ ----------
+ @trans: 3x3 np.array
+ transform matrix from uv to xy
+ @trans_inv: 3x3 np.array
+ inverse of trans, transform matrix from xy to uv
+
+ Matlab:
+ ----------
+ % The similarities are a superset of the nonreflective similarities as they may
+ % also include reflection.
+ %
+ % let sc = s*cos(theta)
+ % let ss = s*sin(theta)
+ %
+ % [ sc -ss
+ % [u v] = [x y 1] * ss sc
+ % tx ty]
+ %
+ % OR
+ %
+ % [ sc ss
+ % [u v] = [x y 1] * ss -sc
+ % tx ty]
+ %
+ % Algorithm:
+ % 1) Solve for trans1, a nonreflective similarity.
+ % 2) Reflect the xy data across the Y-axis,
+ % and solve for trans2r, also a nonreflective similarity.
+ % 3) Transform trans2r to trans2, undoing the reflection done in step 2.
+ % 4) Use TFORMFWD to transform uv using both trans1 and trans2,
+ % and compare the results, Returnsing the transformation corresponding
+ % to the smaller L2 norm.
+
+ % Need to reset options.K to prepare for calls to findNonreflectiveSimilarity.
+ % This is safe because we already checked that there are enough point pairs.
+ """
+ options = {"K": 2}
+
+ # uv = np.array(uv)
+ # xy = np.array(xy)
+
+ # Solve for trans1
+ trans1, trans1_inv = findNonreflectiveSimilarity(uv, xy, options)
+
+ # Solve for trans2
+
+ # manually reflect the xy data across the Y-axis
+ xyR = xy
+ xyR[:, 0] = -1 * xyR[:, 0]
+
+ trans2r, trans2r_inv = findNonreflectiveSimilarity(uv, xyR, options)
+
+ # manually reflect the tform to undo the reflection done on xyR
+ TreflectY = np.array([[-1, 0, 0], [0, 1, 0], [0, 0, 1]])
+
+ trans2 = np.dot(trans2r, TreflectY)
+
+ # Figure out if trans1 or trans2 is better
+ xy1 = tformfwd(trans1, uv)
+ norm1 = norm(xy1 - xy)
+
+ xy2 = tformfwd(trans2, uv)
+ norm2 = norm(xy2 - xy)
+
+ if norm1 <= norm2:
+ return trans1, trans1_inv
+ else:
+ trans2_inv = inv(trans2)
+ return trans2, trans2_inv
+
+
+def get_similarity_transform(src_pts, dst_pts, reflective=True):
+ """
+ Function:
+ ----------
+ Find Similarity Transform Matrix 'trans':
+ u = src_pts[:, 0]
+ v = src_pts[:, 1]
+ x = dst_pts[:, 0]
+ y = dst_pts[:, 1]
+ [x, y, 1] = [u, v, 1] * trans
+
+ Parameters:
+ ----------
+ @src_pts: Kx2 np.array
+ source points, each row is a pair of coordinates (x, y)
+ @dst_pts: Kx2 np.array
+ destination points, each row is a pair of transformed
+ coordinates (x, y)
+ @reflective: True or False
+ if True:
+ use reflective similarity transform
+ else:
+ use non-reflective similarity transform
+
+ Returns:
+ ----------
+ @trans: 3x3 np.array
+ transform matrix from uv to xy
+ trans_inv: 3x3 np.array
+ inverse of trans, transform matrix from xy to uv
+ """
+
+ if reflective:
+ trans, trans_inv = findSimilarity(src_pts, dst_pts)
+ else:
+ trans, trans_inv = findNonreflectiveSimilarity(src_pts, dst_pts)
+
+ return trans, trans_inv
+
+
+def cvt_tform_mat_for_cv2(trans):
+ """
+ Function:
+ ----------
+ Convert Transform Matrix 'trans' into 'cv2_trans' which could be
+ directly used by cv2.warpAffine():
+ u = src_pts[:, 0]
+ v = src_pts[:, 1]
+ x = dst_pts[:, 0]
+ y = dst_pts[:, 1]
+ [x, y].T = cv_trans * [u, v, 1].T
+
+ Parameters:
+ ----------
+ @trans: 3x3 np.array
+ transform matrix from uv to xy
+
+ Returns:
+ ----------
+ @cv2_trans: 2x3 np.array
+ transform matrix from src_pts to dst_pts, could be directly used
+ for cv2.warpAffine()
+ """
+ cv2_trans = trans[:, 0:2].T
+
+ return cv2_trans
+
+
+def get_similarity_transform_for_cv2(src_pts, dst_pts, reflective=True):
+ """
+ Function:
+ ----------
+ Find Similarity Transform Matrix 'cv2_trans' which could be
+ directly used by cv2.warpAffine():
+ u = src_pts[:, 0]
+ v = src_pts[:, 1]
+ x = dst_pts[:, 0]
+ y = dst_pts[:, 1]
+ [x, y].T = cv_trans * [u, v, 1].T
+
+ Parameters:
+ ----------
+ @src_pts: Kx2 np.array
+ source points, each row is a pair of coordinates (x, y)
+ @dst_pts: Kx2 np.array
+ destination points, each row is a pair of transformed
+ coordinates (x, y)
+ reflective: True or False
+ if True:
+ use reflective similarity transform
+ else:
+ use non-reflective similarity transform
+
+ Returns:
+ ----------
+ @cv2_trans: 2x3 np.array
+ transform matrix from src_pts to dst_pts, could be directly used
+ for cv2.warpAffine()
+ """
+ trans, trans_inv = get_similarity_transform(src_pts, dst_pts, reflective)
+ cv2_trans = cvt_tform_mat_for_cv2(trans)
+ return cv2_trans, trans
+
+
+std_points_317 = np.array(
+ [
+ [85.82991, 115.7792],
+ [169.0532, 114.3381],
+ [127.574, 167.0006],
+ [90.6964, 204.7014],
+ [167.3069, 203.3733],
+ ]
+)
+
+
+padding = 30
+
+std_points_317 = std_points_317 + padding
+
+std_points_256=std_points_317.copy()
+std_points_256[..., 0] -= 30
+std_points_256[..., 1] -= 60
+
+def warp_as_face_x_ray(img, src_pts, tgt_pts=std_points_317):
+ tfm, trans = get_similarity_transform_for_cv2(src_pts.copy(), tgt_pts.copy())
+ return cv2.warpAffine(img, tfm, (317, 317)), trans
+
+
+def estimiate_batch_transform(all_src_pts, tgt_pts=std_points_317):
+ tgt_pts = np.repeat(tgt_pts[None, ...], len(all_src_pts), 0).reshape(-1, 2)
+ src_pts = np.array(all_src_pts).reshape(-1, 2)
+ tfm, trans = get_similarity_transform_for_cv2(src_pts, tgt_pts)
+ return tfm, trans
+
+
+def batch_warp_as_face_x_ray(images, all_src_pts, tgt_pts=std_points_317):
+ tfm, trans = estimiate_batch_transform(all_src_pts, tgt_pts)
+ return [cv2.warpAffine(img, tfm, (317, 317)) for img in images], trans
+
+
+def transform_landmarks(landmarks, trans):
+ transformed = np.hstack((landmarks, np.ones((landmarks.shape[0], 1))))
+ transformed = np.dot(transformed, trans)
+ return transformed[:, :2]
+
+def compute_reverse_trans(trans):
+ return np.linalg.inv(trans)
\ No newline at end of file
diff --git a/clean/video/recce/.gitignore b/clean/video/recce/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..4c59502f6d5d0ac94d4206f836bb4bb32f975057
--- /dev/null
+++ b/clean/video/recce/.gitignore
@@ -0,0 +1,134 @@
+# ignore directory
+runs/
+.idea/
+
+
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+pip-wheel-metadata/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+.python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
diff --git a/clean/video/recce/LICENSE b/clean/video/recce/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..0db8340366af7e7f31596692ad9de4e746e1e3da
--- /dev/null
+++ b/clean/video/recce/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2022 SJTU Vision and Learning Group
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/clean/video/recce/README.md b/clean/video/recce/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..1547c5c58097d5a9fc718458e3a8c4fcf9ddf5a8
--- /dev/null
+++ b/clean/video/recce/README.md
@@ -0,0 +1,82 @@
+# RECCE CVPR 2022
+
+:page_facing_up: End-to-End Reconstruction-Classification Learning for Face Forgery Detection
+
+:boy: Junyi Cao, Chao Ma, Taiping Yao, Shen Chen, Shouhong Ding, Xiaokang Yang
+
+**Please consider citing our paper if you find it interesting or helpful to your research.**
+```
+@InProceedings{Cao_2022_CVPR,
+ author = {Cao, Junyi and Ma, Chao and Yao, Taiping and Chen, Shen and Ding, Shouhong and Yang, Xiaokang},
+ title = {End-to-End Reconstruction-Classification Learning for Face Forgery Detection},
+ booktitle = {Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR)},
+ month = {June},
+ year = {2022},
+ pages = {4113-4122}
+}
+```
+
+----
+
+### Introduction
+
+This repository is an implementation for *End-to-End Reconstruction-Classification Learning for Face Forgery Detection* presented in CVPR 2022. In the paper, we propose a novel **REC**onstruction-**C**lassification l**E**arning framework called **RECCE** to detect face forgeries. The code is based on Pytorch. Please follow the instructions below to get started.
+
+
+### Motivation
+
+Briefly, we train a reconstruction network over genuine images only and use the output of the latent feature by the encoder to perform binary classification. Due to the discrepancy in the data distribution between genuine and forged faces, the reconstruction differences of forged faces are obvious and also indicate the probably forged regions.
+
+
+### Basic Requirements
+Please ensure that you have already installed the following packages.
+- [Pytorch](https://pytorch.org/get-started/previous-versions/) 1.7.1
+- [Torchvision](https://pytorch.org/get-started/previous-versions/) 0.8.2
+- [Albumentations](https://github.com/albumentations-team/albumentations#spatial-level-transforms) 1.0.3
+- [Timm](https://github.com/rwightman/pytorch-image-models) 0.3.4
+- [TensorboardX](https://pypi.org/project/tensorboardX/#history) 2.1
+- [Scipy](https://pypi.org/project/scipy/#history) 1.5.2
+- [PyYaml](https://pypi.org/project/PyYAML/#history) 5.3.1
+
+### Dataset Preparation
+- We include the dataset loaders for several commonly-used face forgery datasets, *i.e.,* [FaceForensics++](https://github.com/ondyari/FaceForensics), [Celeb-DF](https://www.cs.albany.edu/~lsw/celeb-deepfakeforensics.html), [WildDeepfake](https://github.com/deepfakeinthewild/deepfake-in-the-wild), and [DFDC](https://ai.facebook.com/datasets/dfdc). You can enter the dataset website to download the original data.
+- For FaceForensics++, Celeb-DF, and DFDC, since the original data are in video format, you should first extract the facial images from the sequences and store them. We use [RetinaFace](https://github.com/biubug6/Pytorch_Retinaface) to do this.
+
+### Config Files
+- We have already provided the config templates in `config/`. You can adjust the parameters in the yaml files to specify a training process. More information is presented in [config/README.md](./config/README.md).
+
+### Training
+- We use `torch.distributed` package to train the models, for more information, please refer to [PyTorch Distributed Overview](https://pytorch.org/tutorials/beginner/dist_overview.html).
+- To train a model, run the following script in your console.
+```{bash}
+CUDA_VISIBLE_DEVICES=0 python -m torch.distributed.launch --nproc_per_node=1 --master_port 12345 train.py --config path/to/config.yaml
+```
+- `--config`: Specify the path of the config file.
+
+### Testing
+- To test a model, run the following script in your console.
+```{bash}
+python test.py --config path/to/config.yaml
+```
+- `--config`: Specify the path of the config file.
+
+### Inference
+- We provide the script in `inference.py` to help you do inference using custom data.
+- To do inference, run the following script in your console.
+```{bash}
+python inference.py --bin path/to/model.bin --image_folder path/to/image_folder --device $DEVICE --image_size $IMAGE_SIZE
+```
+- `--bin`: Specify the path of the model bin generated by the training script of this project.
+- `--image_folder`: Specify the directory of custom facial images. The script accepts images end with `.jpg` or `.png`.
+- `--device`: Specify the device to run the experiment, e.g., `cpu`, `cuda:0`.
+- `--image_size`: Specify the spatial size of input images.
+- The program will output the fake probability for each input image like this:
+ ```
+ path: path/to/image1.jpg | fake probability: 0.1296 | prediction: real
+ path: path/to/image2.jpg | fake probability: 0.9146 | prediction: fake
+ ```
+- Type `python inference.py -h` in your console for more information about available arguments.
+
+
+### Acknowledgement
+- We thank Qiqi Gu for helping plot the schematic diagram of the proposed method in the manuscript.
diff --git a/clean/video/recce/SOURCE.md b/clean/video/recce/SOURCE.md
new file mode 100644
index 0000000000000000000000000000000000000000..f33f4e7b7717bf51e16d577505cfbc92f5208112
--- /dev/null
+++ b/clean/video/recce/SOURCE.md
@@ -0,0 +1,17 @@
+# Source: video/recce
+
+| Field | Value |
+|---|---|
+| Upstream | **UNVERIFIED** -- provenance was lost when this code was vendored |
+| Paper | not recorded |
+| Commit SHA | **not recorded** -- the vendoring step did not preserve it |
+| Mirrored on | 2026-09-15 |
+| Upstream license | LICENSE |
+
+This is a **mirror**, stripped to the files needed for inference. The full
+untouched snapshot is at `archive/video__recce.tar.gz`.
+
+This code is the work of its original authors and is **not** covered by the
+DeepSafe project license. If you are an author and want this removed, open an
+issue on https://github.com/deepsafehq/deepsafe-bench and it will be taken down
+within 48 hours, no questions asked.
diff --git a/clean/video/recce/config/README.md b/clean/video/recce/config/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..dfb996189a40279bef13deb836f4b1b87ef0e57f
--- /dev/null
+++ b/clean/video/recce/config/README.md
@@ -0,0 +1,50 @@
+## Configuration Files
+
+#### Model Configuration
+- We use a yaml file to specify the hyperparameters of a model. All the training logs will be placed in `${project_root}/runs/${model_name}/${experiment_id}`. An example are shown below.
+
+```yaml
+model:
+ name: Recce # Model Name
+ num_classes: 1
+config:
+ lambda_1: 0.1 # balancing weight for L_r
+ lambda_2: 0.1 # balancing weight for L_m
+ distribute:
+ backend: nccl
+ optimizer:
+ name: adam
+ lr: 0.0002
+ weight_decay: 0.00001
+ scheduler:
+ name: StepLR
+ step_size: 22500
+ gamma: 0.5
+ resume: False
+ resume_best: False
+ id: FF++c40 # Specify a unique experiment id.
+ loss: binary_ce # Loss type, either 'binary_ce' or 'cross_entropy'.
+ metric: Acc # Main metric, either 'Acc', 'AUC', or 'LogLoss'.
+ debug: False
+ device: "cuda:1" # NOTE: Used only when testing, annotation this line when training.
+ ckpt: best_model_1000 # NOTE: Used only when testing to specify a checkpoint id, annotating this line when training.
+data:
+ train_batch_size: 32
+ val_batch_size: 64
+ test_batch_size: 64
+ name: FaceForensics
+ file: "./config/dataset/faceforensics.yml" # config file for a dataset
+ train_branch: "train_cfg"
+ val_branch: "test_cfg"
+ test_branch: "test_cfg"
+```
+
+- We set different hyper-parameters for the learning rate scheduler according to the used dataset as follows:
+ - FaceForensics++: The learning rate is decayed by 0.5 every 10 epochs.
+ - Celeb-DF: The learning rate is decayed by 0.5 every 10 epochs.
+ - WildDeepfake: The learning rate is decayed by 0.9 every 3000 iterations.
+ - DFDC: The learning rate is decayed by 0.5 every 3 epochs.
+
+#### Dataset Configuration
+- We also use a yaml file to specify the dataset to load for the experiment. These files are placed under `config/dataset/` subfold.
+- Briefly, you should change the `root` parameter according to your storage path.
\ No newline at end of file
diff --git a/clean/video/recce/config/Recce.yml b/clean/video/recce/config/Recce.yml
new file mode 100644
index 0000000000000000000000000000000000000000..beb2f60001712ef0ceab1c03bfd0d2b46aa832b9
--- /dev/null
+++ b/clean/video/recce/config/Recce.yml
@@ -0,0 +1,33 @@
+model:
+ name: Recce
+ num_classes: 1
+config:
+ lambda_1: 0.1
+ lambda_2: 0.1
+ distribute:
+ backend: nccl
+ optimizer:
+ name: adam
+ lr: 0.0002
+ weight_decay: 0.00001
+ scheduler:
+ name: StepLR
+ step_size: 22500
+ gamma: 0.5
+ resume: False
+ resume_best: False
+ id: FF++c40
+ loss: binary_ce
+ metric: Acc
+ debug: False
+# device: "cuda:1"
+# ckpt: best_model_1000
+data:
+ train_batch_size: 32
+ val_batch_size: 64
+ test_batch_size: 64
+ name: FaceForensics
+ file: "./config/dataset/faceforensics.yml"
+ train_branch: "train_cfg"
+ val_branch: "test_cfg"
+ test_branch: "test_cfg"
diff --git a/clean/video/recce/inference.py b/clean/video/recce/inference.py
new file mode 100644
index 0000000000000000000000000000000000000000..02c6d70219b2cf02dad6551d1fda5d9946014a4f
--- /dev/null
+++ b/clean/video/recce/inference.py
@@ -0,0 +1,129 @@
+import cv2
+import torch
+import random
+import argparse
+from glob import glob
+from os.path import join
+from model.network import Recce
+from model.common import freeze_weights
+from albumentations import Compose, Normalize, Resize
+from albumentations.pytorch.transforms import ToTensorV2
+
+# fix random seed
+seed = 0
+random.seed(seed)
+torch.manual_seed(seed)
+torch.cuda.manual_seed(seed)
+torch.cuda.manual_seed_all(seed)
+
+parser = argparse.ArgumentParser(description="This code helps you use a trained model to "
+ "do inference.")
+parser.add_argument("--weight", "-w",
+ type=str,
+ default=None,
+ help="Specify the path to the model weight (the state dict file). "
+ "Do not use this argument when '--bin' is set.")
+parser.add_argument("--bin", "-b",
+ type=str,
+ default=None,
+ help="Specify the path to the model bin which ends up with '.bin' "
+ "(which is generated by the trainer of this project). "
+ "Do not use this argument when '--weight' is set.")
+parser.add_argument("--image", "-i",
+ type=str,
+ default=None,
+ help="Specify the path to the input image. "
+ "Do not use this argument when '--image_folder' is set.")
+parser.add_argument("--image_folder", "-f",
+ type=str,
+ default=None,
+ help="Specify the directory to evaluate all the images. "
+ "Do not use this argument when '--image' is set.")
+parser.add_argument('--device', '-d', type=str,
+ default="cpu",
+ help="Specify the device to load the model. Default: 'cpu'.")
+parser.add_argument('--image_size', '-s', type=int,
+ default=299,
+ help="Specify the spatial size of the input image(s). Default: 299.")
+parser.add_argument('--visualize', '-v', action="store_true",
+ default=False, help='Visualize images.')
+
+
+def preprocess(file_path):
+ img = cv2.imread(file_path)
+ img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
+ compose = Compose([Resize(height=args.image_size, width=args.image_size),
+ Normalize(mean=[0.5] * 3, std=[0.5] * 3),
+ ToTensorV2()])
+ img = compose(image=img)['image'].unsqueeze(0)
+ return img
+
+
+def prepare_data():
+ paths = list()
+ images = list()
+ # check the console arguments
+ if args.image and args.image_folder:
+ raise ValueError("Only one of '--image' or '--image_folder' can be set.")
+ elif args.image:
+ images.append(preprocess(args.image))
+ paths.append(args.image)
+ elif args.image_folder:
+ image_paths = glob(join(args.image_folder, "*.jpg"))
+ image_paths.extend(glob(join(args.image_folder, "*.png")))
+ for _ in image_paths:
+ images.append(preprocess(_))
+ paths.append(_)
+ else:
+ raise ValueError("Neither of '--image' nor '--image_folder' is set. Please specify either "
+ "one of these two arguments to load input image(s) properly.")
+ return paths, images
+
+
+def inference(model, images, paths, device):
+ for img, pt in zip(images, paths):
+ img = img.to(device)
+ prediction = model(img)
+ prediction = torch.sigmoid(prediction).cpu()
+ fake = True if prediction >= 0.5 else False
+ print(f"path: {pt} \t\t| fake probability: {prediction.item():.4f} \t| "
+ f"prediction: {'fake' if fake else 'real'}")
+ if args.visualize:
+ cvimg = cv2.imread(pt)
+ cvimg = cv2.putText(cvimg, f'p: {prediction.item():.2f}, ' + f"{'fake' if fake else 'real'}",
+ (5, 50), cv2.FONT_HERSHEY_SIMPLEX, 0.5,
+ (0, 0, 255) if fake else (255, 0, 0), 2)
+ cv2.imshow("image", cvimg)
+ cv2.waitKey(0)
+ cv2.destroyWindow("image")
+
+
+def main():
+ print("Arguments:\n", args, end="\n\n")
+ # set device
+ device = torch.device(args.device)
+ # load model
+ model = eval("Recce")(num_classes=1)
+ # check the console arguments
+ if args.weight and args.bin:
+ raise ValueError("Only one of '--weight' or '--bin' can be set.")
+ elif args.weight:
+ weights = torch.load(args.weight, map_location="cpu")
+ elif args.bin:
+ weights = torch.load(args.bin, map_location="cpu")["model"]
+ else:
+ raise ValueError("Neither of '--weight' nor '--bin' is set. Please specify either "
+ "one of these two arguments to load model's weight properly.")
+ model.load_state_dict(weights)
+ model = model.to(device)
+ freeze_weights(model)
+ model.eval()
+
+ paths, images = prepare_data()
+ print("Inference:")
+ inference(model, images=images, paths=paths, device=device)
+
+
+if __name__ == '__main__':
+ args = parser.parse_args()
+ main()
diff --git a/clean/video/recce/loss/__init__.py b/clean/video/recce/loss/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..fb8d2007cb4a3f852c7bde93fe84b0e162408d71
--- /dev/null
+++ b/clean/video/recce/loss/__init__.py
@@ -0,0 +1,12 @@
+import torch.nn as nn
+
+
+def get_loss(name="cross_entropy", device="cuda:0"):
+ print(f"Using loss: '{LOSSES[name]}'")
+ return LOSSES[name].to(device)
+
+
+LOSSES = {
+ "binary_ce": nn.BCEWithLogitsLoss(),
+ "cross_entropy": nn.CrossEntropyLoss()
+}
diff --git a/clean/video/recce/model/__init__.py b/clean/video/recce/model/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..c8028d946b3ef30ba6b9ade62b503c3455c49ed6
--- /dev/null
+++ b/clean/video/recce/model/__init__.py
@@ -0,0 +1,12 @@
+from .network import *
+from .common import *
+
+MODELS = {
+ "Recce": Recce
+}
+
+
+def load_model(name="Recce"):
+ assert name in MODELS.keys(), f"Model name can only be one of {MODELS.keys()}."
+ print(f"Using model: '{name}'")
+ return MODELS[name]
diff --git a/clean/video/recce/model/common.py b/clean/video/recce/model/common.py
new file mode 100644
index 0000000000000000000000000000000000000000..1c8a1b962ac277a2164d4387d60083632ce9096b
--- /dev/null
+++ b/clean/video/recce/model/common.py
@@ -0,0 +1,200 @@
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+
+
+def freeze_weights(module):
+ for param in module.parameters():
+ param.requires_grad = False
+
+
+def l1_regularize(module):
+ reg_loss = 0.
+ for key, param in module.reg_params.items():
+ if "weight" in key and param.requires_grad:
+ reg_loss += torch.sum(torch.abs(param))
+ return reg_loss
+
+
+class SeparableConv2d(nn.Module):
+ def __init__(self, in_channels, out_channels, kernel_size=1, stride=1, padding=0, dilation=1, bias=False):
+ super(SeparableConv2d, self).__init__()
+
+ self.conv1 = nn.Conv2d(in_channels, in_channels, kernel_size, stride, padding, dilation,
+ groups=in_channels, bias=bias)
+ self.pointwise = nn.Conv2d(in_channels, out_channels, 1, 1, 0, 1, 1, bias=bias)
+
+ def forward(self, x):
+ x = self.conv1(x)
+ x = self.pointwise(x)
+ return x
+
+
+class Block(nn.Module):
+ def __init__(self, in_channels, out_channels, reps, strides=1,
+ start_with_relu=True, grow_first=True, with_bn=True):
+ super(Block, self).__init__()
+
+ self.with_bn = with_bn
+
+ if out_channels != in_channels or strides != 1:
+ self.skip = nn.Conv2d(in_channels, out_channels, 1, stride=strides, bias=False)
+ if with_bn:
+ self.skipbn = nn.BatchNorm2d(out_channels)
+ else:
+ self.skip = None
+
+ rep = []
+ for i in range(reps):
+ if grow_first:
+ inc = in_channels if i == 0 else out_channels
+ outc = out_channels
+ else:
+ inc = in_channels
+ outc = in_channels if i < (reps - 1) else out_channels
+ rep.append(nn.ReLU(inplace=True))
+ rep.append(SeparableConv2d(inc, outc, 3, stride=1, padding=1))
+ if with_bn:
+ rep.append(nn.BatchNorm2d(outc))
+
+ if not start_with_relu:
+ rep = rep[1:]
+ else:
+ rep[0] = nn.ReLU(inplace=False)
+
+ if strides != 1:
+ rep.append(nn.MaxPool2d(3, strides, 1))
+ self.rep = nn.Sequential(*rep)
+
+ def forward(self, inp):
+ x = self.rep(inp)
+
+ if self.skip is not None:
+ skip = self.skip(inp)
+ if self.with_bn:
+ skip = self.skipbn(skip)
+ else:
+ skip = inp
+
+ x += skip
+ return x
+
+
+class GraphReasoning(nn.Module):
+ """ Graph Reasoning Module for information aggregation. """
+
+ def __init__(self, va_in, va_out, vb_in, vb_out, vc_in, vc_out, spatial_ratio, drop_rate):
+ super(GraphReasoning, self).__init__()
+ self.ratio = spatial_ratio
+ self.va_embedding = nn.Sequential(
+ nn.Conv2d(va_in, va_out, 1, bias=False),
+ nn.ReLU(True),
+ nn.Conv2d(va_out, va_out, 1, bias=False),
+ )
+ self.va_gated_b = nn.Sequential(
+ nn.Conv2d(va_in, va_out, 1, bias=False),
+ nn.Sigmoid()
+ )
+ self.va_gated_c = nn.Sequential(
+ nn.Conv2d(va_in, va_out, 1, bias=False),
+ nn.Sigmoid()
+ )
+ self.vb_embedding = nn.Sequential(
+ nn.Linear(vb_in, vb_out, bias=False),
+ nn.ReLU(True),
+ nn.Linear(vb_out, vb_out, bias=False),
+ )
+ self.vc_embedding = nn.Sequential(
+ nn.Linear(vc_in, vc_out, bias=False),
+ nn.ReLU(True),
+ nn.Linear(vc_out, vc_out, bias=False),
+ )
+ self.unfold_b = nn.Unfold(kernel_size=spatial_ratio[0], stride=spatial_ratio[0])
+ self.unfold_c = nn.Unfold(kernel_size=spatial_ratio[1], stride=spatial_ratio[1])
+ self.reweight_ab = nn.Sequential(
+ nn.Linear(va_out + vb_out, 1, bias=False),
+ nn.ReLU(True),
+ nn.Softmax(dim=1)
+ )
+ self.reweight_ac = nn.Sequential(
+ nn.Linear(va_out + vc_out, 1, bias=False),
+ nn.ReLU(True),
+ nn.Softmax(dim=1)
+ )
+ self.reproject = nn.Sequential(
+ nn.Conv2d(va_out + vb_out + vc_out, va_in, kernel_size=1, bias=False),
+ nn.ReLU(True),
+ nn.Conv2d(va_in, va_in, kernel_size=1, bias=False),
+ nn.Dropout(drop_rate) if drop_rate is not None else nn.Identity(),
+ )
+
+ def forward(self, vert_a, vert_b, vert_c):
+ emb_vert_a = self.va_embedding(vert_a)
+ emb_vert_a = emb_vert_a.reshape([emb_vert_a.shape[0], emb_vert_a.shape[1], -1])
+
+ gate_vert_b = 1 - self.va_gated_b(vert_a)
+ gate_vert_b = gate_vert_b.reshape(*emb_vert_a.shape)
+ gate_vert_c = 1 - self.va_gated_c(vert_a)
+ gate_vert_c = gate_vert_c.reshape(*emb_vert_a.shape)
+
+ vert_b = self.unfold_b(vert_b).reshape(
+ [vert_b.shape[0], vert_b.shape[1], self.ratio[0] * self.ratio[0], -1])
+ vert_b = vert_b.permute([0, 2, 3, 1])
+ emb_vert_b = self.vb_embedding(vert_b)
+
+ vert_c = self.unfold_c(vert_c).reshape(
+ [vert_c.shape[0], vert_c.shape[1], self.ratio[1] * self.ratio[1], -1])
+ vert_c = vert_c.permute([0, 2, 3, 1])
+ emb_vert_c = self.vc_embedding(vert_c)
+
+ agg_vb = list()
+ agg_vc = list()
+ for j in range(emb_vert_a.shape[-1]):
+ # ab propagating
+ emb_v_a = torch.stack([emb_vert_a[:, :, j]] * (self.ratio[0] ** 2), dim=1)
+ emb_v_b = emb_vert_b[:, :, j, :]
+ emb_v_ab = torch.cat([emb_v_a, emb_v_b], dim=-1)
+ w = self.reweight_ab(emb_v_ab)
+ agg_vb.append(torch.bmm(emb_v_b.transpose(1, 2), w).squeeze() * gate_vert_b[:, :, j])
+
+ # ac propagating
+ emb_v_a = torch.stack([emb_vert_a[:, :, j]] * (self.ratio[1] ** 2), dim=1)
+ emb_v_c = emb_vert_c[:, :, j, :]
+ emb_v_ac = torch.cat([emb_v_a, emb_v_c], dim=-1)
+ w = self.reweight_ac(emb_v_ac)
+ agg_vc.append(torch.bmm(emb_v_c.transpose(1, 2), w).squeeze() * gate_vert_c[:, :, j])
+
+ agg_vert_b = torch.stack(agg_vb, dim=-1)
+ agg_vert_c = torch.stack(agg_vc, dim=-1)
+ agg_vert_bc = torch.cat([agg_vert_b, agg_vert_c], dim=1)
+ agg_vert_abc = torch.cat([agg_vert_bc, emb_vert_a], dim=1)
+ agg_vert_abc = torch.sigmoid(agg_vert_abc)
+ agg_vert_abc = agg_vert_abc.reshape(vert_a.shape[0], -1, vert_a.shape[2], vert_a.shape[3])
+ return self.reproject(agg_vert_abc)
+
+
+class GuidedAttention(nn.Module):
+ """ Reconstruction Guided Attention. """
+
+ def __init__(self, depth=728, drop_rate=0.2):
+ super(GuidedAttention, self).__init__()
+ self.depth = depth
+ self.gated = nn.Sequential(
+ nn.Conv2d(3, 3, kernel_size=3, stride=1, padding=1, bias=False),
+ nn.ReLU(True),
+ nn.Conv2d(3, 1, 1, bias=False),
+ nn.Sigmoid()
+ )
+ self.h = nn.Sequential(
+ nn.Conv2d(depth, depth, 1, 1, bias=False),
+ nn.BatchNorm2d(depth),
+ nn.ReLU(True),
+ )
+ self.dropout = nn.Dropout(drop_rate)
+
+ def forward(self, x, pred_x, embedding):
+ residual_full = torch.abs(x - pred_x)
+ residual_x = F.interpolate(residual_full, size=embedding.shape[-2:],
+ mode='bilinear', align_corners=True)
+ res_map = self.gated(residual_x)
+ return res_map * self.h(embedding) + self.dropout(embedding)
diff --git a/clean/video/recce/model/network/Recce.py b/clean/video/recce/model/network/Recce.py
new file mode 100644
index 0000000000000000000000000000000000000000..eb647cfc245542108bf4de3450ee3db05c55fb6d
--- /dev/null
+++ b/clean/video/recce/model/network/Recce.py
@@ -0,0 +1,133 @@
+from functools import partial
+from timm.models import xception
+from model.common import SeparableConv2d, Block
+from model.common import GuidedAttention, GraphReasoning
+
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+
+encoder_params = {
+ "xception": {
+ "features": 2048,
+ "init_op": partial(xception, pretrained=True)
+ }
+}
+
+
+class Recce(nn.Module):
+ """ End-to-End Reconstruction-Classification Learning for Face Forgery Detection """
+
+ def __init__(self, num_classes, drop_rate=0.2):
+ super(Recce, self).__init__()
+ self.name = "xception"
+ self.loss_inputs = dict()
+ self.encoder = encoder_params[self.name]["init_op"]()
+ self.global_pool = nn.AdaptiveAvgPool2d((1, 1))
+ self.dropout = nn.Dropout(drop_rate)
+ self.fc = nn.Linear(encoder_params[self.name]["features"], num_classes)
+
+ self.attention = GuidedAttention(depth=728, drop_rate=drop_rate)
+ self.reasoning = GraphReasoning(728, 256, 256, 256, 128, 256, [2, 4], drop_rate)
+
+ self.decoder1 = nn.Sequential(
+ nn.UpsamplingNearest2d(scale_factor=2),
+ SeparableConv2d(728, 256, 3, 1, 1, bias=False),
+ nn.BatchNorm2d(256),
+ nn.ReLU(inplace=True)
+ )
+ self.decoder2 = Block(256, 256, 3, 1)
+ self.decoder3 = nn.Sequential(
+ nn.UpsamplingNearest2d(scale_factor=2),
+ SeparableConv2d(256, 128, 3, 1, 1, bias=False),
+ nn.BatchNorm2d(128),
+ nn.ReLU(inplace=True)
+ )
+ self.decoder4 = Block(128, 128, 3, 1)
+ self.decoder5 = nn.Sequential(
+ nn.UpsamplingNearest2d(scale_factor=2),
+ SeparableConv2d(128, 64, 3, 1, 1, bias=False),
+ nn.BatchNorm2d(64),
+ nn.ReLU(inplace=True)
+ )
+ self.decoder6 = nn.Sequential(
+ nn.Conv2d(64, 3, 1, 1, bias=False),
+ nn.Tanh()
+ )
+
+ def norm_n_corr(self, x):
+ norm_embed = F.normalize(self.global_pool(x), p=2, dim=1)
+ corr = (torch.matmul(norm_embed.squeeze(), norm_embed.squeeze().T) + 1.) / 2.
+ return norm_embed, corr
+
+ @staticmethod
+ def add_white_noise(tensor, mean=0., std=1e-6):
+ rand = torch.rand([tensor.shape[0], 1, 1, 1])
+ rand = torch.where(rand > 0.5, 1., 0.).to(tensor.device)
+ white_noise = torch.normal(mean, std, size=tensor.shape, device=tensor.device)
+ noise_t = tensor + white_noise * rand
+ noise_t = torch.clip(noise_t, -1., 1.)
+ return noise_t
+
+ def forward(self, x):
+ # clear the loss inputs
+ self.loss_inputs = dict(recons=[], contra=[])
+ noise_x = self.add_white_noise(x) if self.training else x
+ out = self.encoder.conv1(noise_x)
+ out = self.encoder.bn1(out)
+ out = self.encoder.act1(out)
+ out = self.encoder.conv2(out)
+ out = self.encoder.bn2(out)
+ out = self.encoder.act2(out)
+ out = self.encoder.block1(out)
+ out = self.encoder.block2(out)
+ out = self.encoder.block3(out)
+ embedding = self.encoder.block4(out)
+
+ norm_embed, corr = self.norm_n_corr(embedding)
+ self.loss_inputs['contra'].append(corr)
+
+ out = self.dropout(embedding)
+ out = self.decoder1(out)
+ out_d2 = self.decoder2(out)
+
+ norm_embed, corr = self.norm_n_corr(out_d2)
+ self.loss_inputs['contra'].append(corr)
+
+ out = self.decoder3(out_d2)
+ out_d4 = self.decoder4(out)
+
+ norm_embed, corr = self.norm_n_corr(out_d4)
+ self.loss_inputs['contra'].append(corr)
+
+ out = self.decoder5(out_d4)
+ pred = self.decoder6(out)
+
+ recons_x = F.interpolate(pred, size=x.shape[-2:], mode='bilinear', align_corners=True)
+ self.loss_inputs['recons'].append(recons_x)
+
+ embedding = self.encoder.block5(embedding)
+ embedding = self.encoder.block6(embedding)
+ embedding = self.encoder.block7(embedding)
+
+ fusion = self.reasoning(embedding, out_d2, out_d4) + embedding
+
+ embedding = self.encoder.block8(fusion)
+ img_att = self.attention(x, recons_x, embedding)
+
+ embedding = self.encoder.block9(img_att)
+ embedding = self.encoder.block10(embedding)
+ embedding = self.encoder.block11(embedding)
+ embedding = self.encoder.block12(embedding)
+
+ embedding = self.encoder.conv3(embedding)
+ embedding = self.encoder.bn3(embedding)
+ embedding = self.encoder.act3(embedding)
+ embedding = self.encoder.conv4(embedding)
+ embedding = self.encoder.bn4(embedding)
+ embedding = self.encoder.act4(embedding)
+
+ embedding = self.global_pool(embedding).squeeze()
+
+ out = self.dropout(embedding)
+ return self.fc(out)
diff --git a/clean/video/recce/model/network/__init__.py b/clean/video/recce/model/network/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e552eb84c758d2b1ac6542725d7faed4d1fca3bd
--- /dev/null
+++ b/clean/video/recce/model/network/__init__.py
@@ -0,0 +1 @@
+from .Recce import Recce
diff --git a/clean/video/recce/optimizer/__init__.py b/clean/video/recce/optimizer/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..74db9744a1f35e9f082e3a61997025ad4c22a8e7
--- /dev/null
+++ b/clean/video/recce/optimizer/__init__.py
@@ -0,0 +1,30 @@
+from torch.optim import SGD
+from torch.optim import Adam
+from torch.optim import ASGD
+from torch.optim import Adamax
+from torch.optim import Adadelta
+from torch.optim import Adagrad
+from torch.optim import RMSprop
+
+key2opt = {
+ 'sgd': SGD,
+ 'adam': Adam,
+ 'asgd': ASGD,
+ 'adamax': Adamax,
+ 'adadelta': Adadelta,
+ 'adagrad': Adagrad,
+ 'rmsprop': RMSprop,
+}
+
+
+def get_optimizer(optimizer_name=None):
+ if optimizer_name is None:
+ print("Using default 'SGD' optimizer")
+ return SGD
+
+ else:
+ if optimizer_name not in key2opt:
+ raise NotImplementedError(f"Optimizer '{optimizer_name}' not implemented")
+
+ print(f"Using optimizer: '{optimizer_name}'")
+ return key2opt[optimizer_name]
diff --git a/clean/video/recce/scheduler/__init__.py b/clean/video/recce/scheduler/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..d02f3edf959d8e10b66c08e276ced619ecfd15dd
--- /dev/null
+++ b/clean/video/recce/scheduler/__init__.py
@@ -0,0 +1,36 @@
+from torch.optim.lr_scheduler import _LRScheduler
+from torch.optim.lr_scheduler import StepLR
+from torch.optim.lr_scheduler import MultiStepLR
+from torch.optim.lr_scheduler import ExponentialLR
+from torch.optim.lr_scheduler import CosineAnnealingLR
+from torch.optim.lr_scheduler import CosineAnnealingWarmRestarts
+from torch.optim.lr_scheduler import ReduceLROnPlateau
+
+
+class ConstantLR(_LRScheduler):
+ def __init__(self, optimizer, last_epoch=-1):
+ super(ConstantLR, self).__init__(optimizer, last_epoch)
+
+ def get_lr(self):
+ return [base_lr for base_lr in self.base_lrs]
+
+
+SCHEDULERS = {
+ 'ConstantLR': ConstantLR,
+ "StepLR": StepLR,
+ "MultiStepLR": MultiStepLR,
+ "CosineAnnealingLR": CosineAnnealingLR,
+ "CosineAnnealingWarmRestarts": CosineAnnealingWarmRestarts,
+ "ExponentialLR": ExponentialLR,
+ "ReduceLROnPlateau": ReduceLROnPlateau
+}
+
+
+def get_scheduler(optimizer, kwargs):
+ if kwargs is None:
+ print("No lr scheduler is used.")
+ return ConstantLR(optimizer)
+ name = kwargs["name"]
+ kwargs.pop("name")
+ print("Using scheduler: '%s' with params: %s" % (name, kwargs))
+ return SCHEDULERS[name](optimizer, **kwargs)
diff --git a/clean/video/recce/test.py b/clean/video/recce/test.py
new file mode 100644
index 0000000000000000000000000000000000000000..7467842f9affda299fbd5a06bb44cc6d691600f9
--- /dev/null
+++ b/clean/video/recce/test.py
@@ -0,0 +1,31 @@
+import yaml
+import argparse
+
+from trainer import ExpTester
+
+
+def arg_parser():
+ parser = argparse.ArgumentParser(description="config")
+ parser.add_argument("--config",
+ type=str,
+ default="config/Recce.yml",
+ help="Specify the path of configuration file to be used.")
+ parser.add_argument('--display', '-d', action="store_true",
+ default=False, help='Display some images.')
+ return parser.parse_args()
+
+
+if __name__ == '__main__':
+ import torch
+
+ torch.backends.cudnn.benchmark = True
+ torch.backends.cudnn.enabled = True
+
+ arg = arg_parser()
+ config = arg.config
+
+ with open(config) as config_file:
+ config = yaml.load(config_file, Loader=yaml.FullLoader)
+
+ trainer = ExpTester(config, stage="Test")
+ trainer.test(display_images=arg.display)
diff --git a/clean/video/recce/train.py b/clean/video/recce/train.py
new file mode 100644
index 0000000000000000000000000000000000000000..cae7ad48eddf9d945142cc77c818df3dd8b30a71
--- /dev/null
+++ b/clean/video/recce/train.py
@@ -0,0 +1,33 @@
+import yaml
+import argparse
+
+from trainer import ExpMultiGpuTrainer
+
+
+def arg_parser():
+ parser = argparse.ArgumentParser(description="config")
+ parser.add_argument("--config",
+ type=str,
+ default="config/Recce.yml",
+ help="Specified the path of configuration file to be used.")
+ parser.add_argument("--local_rank", default=0,
+ type=int,
+ help="Specified the node rank for distributed training.")
+ return parser.parse_args()
+
+
+if __name__ == '__main__':
+ import torch
+
+ torch.backends.cudnn.benchmark = True
+ torch.backends.cudnn.enabled = True
+
+ arg = arg_parser()
+ config = arg.config
+
+ with open(config) as config_file:
+ config = yaml.load(config_file, Loader=yaml.FullLoader)
+ config["config"]["local_rank"] = arg.local_rank
+
+ trainer = ExpMultiGpuTrainer(config, stage="Train")
+ trainer.train()
diff --git a/clean/video/recce/trainer/__init__.py b/clean/video/recce/trainer/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..d7f4da6b97a20cf6c6dae6761dffea145a336cea
--- /dev/null
+++ b/clean/video/recce/trainer/__init__.py
@@ -0,0 +1,5 @@
+from .abstract_trainer import AbstractTrainer, LEGAL_METRIC
+from .exp_mgpu_trainer import ExpMultiGpuTrainer
+from .exp_tester import ExpTester
+from .utils import center_print, reduce_tensor
+from .utils import exp_recons_loss
diff --git a/clean/video/recce/trainer/abstract_trainer.py b/clean/video/recce/trainer/abstract_trainer.py
new file mode 100644
index 0000000000000000000000000000000000000000..4e1354a94ec55db2fcad0d951ecaca2f7b804fbe
--- /dev/null
+++ b/clean/video/recce/trainer/abstract_trainer.py
@@ -0,0 +1,100 @@
+import os
+import torch
+import random
+from collections import OrderedDict
+from torchvision.utils import make_grid
+
+LEGAL_METRIC = ['Acc', 'AUC', 'LogLoss']
+
+
+class AbstractTrainer(object):
+ def __init__(self, config, stage="Train"):
+ feasible_stage = ["Train", "Test"]
+ if stage not in feasible_stage:
+ raise ValueError(f"stage should be in {feasible_stage}, but found '{stage}'")
+
+ self.config = config
+ model_cfg = config.get("model", None)
+ data_cfg = config.get("data", None)
+ config_cfg = config.get("config", None)
+
+ self.model_name = model_cfg.pop("name")
+
+ self.gpu = None
+ self.dir = None
+ self.debug = None
+ self.device = None
+ self.resume = None
+ self.local_rank = None
+ self.num_classes = None
+
+ self.best_metric = 0.0
+ self.best_step = 1
+ self.start_step = 1
+
+ self._initiated_settings(model_cfg, data_cfg, config_cfg)
+
+ if stage == 'Train':
+ self._train_settings(model_cfg, data_cfg, config_cfg)
+ if stage == 'Test':
+ self._test_settings(model_cfg, data_cfg, config_cfg)
+
+ def _initiated_settings(self, model_cfg, data_cfg, config_cfg):
+ raise NotImplementedError("Not implemented in abstract class.")
+
+ def _train_settings(self, model_cfg, data_cfg, config_cfg):
+ raise NotImplementedError("Not implemented in abstract class.")
+
+ def _test_settings(self, model_cfg, data_cfg, config_cfg):
+ raise NotImplementedError("Not implemented in abstract class.")
+
+ def _save_ckpt(self, step, best=False):
+ raise NotImplementedError("Not implemented in abstract class.")
+
+ def _load_ckpt(self, best=False, train=False):
+ raise NotImplementedError("Not implemented in abstract class.")
+
+ def to_device(self, items):
+ return [obj.to(self.device) for obj in items]
+
+ @staticmethod
+ def fixed_randomness():
+ random.seed(0)
+ torch.manual_seed(0)
+ torch.cuda.manual_seed(0)
+ torch.cuda.manual_seed_all(0)
+
+ def train(self):
+ raise NotImplementedError("Not implemented in abstract class.")
+
+ def validate(self, epoch, step, timer, writer):
+ raise NotImplementedError("Not implemented in abstract class.")
+
+ def test(self):
+ raise NotImplementedError("Not implemented in abstract class.")
+
+ def plot_figure(self, images, pred, gt, nrow, categories=None, show=True):
+ import matplotlib.pyplot as plt
+ plot = make_grid(
+ images, nrow, padding=4, normalize=True, scale_each=True, pad_value=1)
+ if self.num_classes == 1:
+ pred = (pred >= 0.5).cpu().numpy()
+ else:
+ pred = pred.argmax(1).cpu().numpy()
+ gt = gt.cpu().numpy()
+ if categories is not None:
+ pred = [categories[i] for i in pred]
+ gt = [categories[i] for i in gt]
+ plot = plot.permute([1, 2, 0])
+ plot = plot.cpu().numpy()
+ ret = plt.figure()
+ plt.imshow(plot)
+ plt.title("pred: %s\ngt: %s" % (pred, gt))
+ plt.axis("off")
+ if show:
+ plt.savefig(os.path.join(self.dir, "test_image.png"), dpi=300)
+ plt.show()
+ plt.close()
+ else:
+ plt.close()
+ return ret
diff --git a/clean/video/recce/trainer/exp_mgpu_trainer.py b/clean/video/recce/trainer/exp_mgpu_trainer.py
new file mode 100644
index 0000000000000000000000000000000000000000..f9e2d43c4e040b4390870b7ca5af07809f5e30c3
--- /dev/null
+++ b/clean/video/recce/trainer/exp_mgpu_trainer.py
@@ -0,0 +1,370 @@
+import os
+import sys
+import time
+import math
+import yaml
+import torch
+import random
+import numpy as np
+
+from tqdm import tqdm
+from pprint import pprint
+from torch.utils import data
+import torch.distributed as dist
+from torch.cuda.amp import autocast, GradScaler
+from tensorboardX import SummaryWriter
+
+from dataset import load_dataset
+from loss import get_loss
+from model import load_model
+from optimizer import get_optimizer
+from scheduler import get_scheduler
+from trainer import AbstractTrainer, LEGAL_METRIC
+from trainer.utils import exp_recons_loss, MLLoss, reduce_tensor, center_print
+from trainer.utils import MODELS_PATH, AccMeter, AUCMeter, AverageMeter, Logger, Timer
+
+
+class ExpMultiGpuTrainer(AbstractTrainer):
+ def __init__(self, config, stage="Train"):
+ super(ExpMultiGpuTrainer, self).__init__(config, stage)
+ np.random.seed(2021)
+
+ def _mprint(self, content=""):
+ if self.local_rank == 0:
+ print(content)
+
+ def _initiated_settings(self, model_cfg=None, data_cfg=None, config_cfg=None):
+ self.local_rank = config_cfg["local_rank"]
+
+ def _train_settings(self, model_cfg, data_cfg, config_cfg):
+ # debug mode: no log dir, no train_val operation.
+ self.debug = config_cfg["debug"]
+ self._mprint(f"Using debug mode: {self.debug}.")
+ self._mprint("*" * 20)
+
+ self.eval_metric = config_cfg["metric"]
+ if self.eval_metric not in LEGAL_METRIC:
+ raise ValueError(f"Evaluation metric must be in {LEGAL_METRIC}, but found "
+ f"{self.eval_metric}.")
+ if self.eval_metric == LEGAL_METRIC[-1]:
+ self.best_metric = 1.0e8
+
+ # distribution
+ dist.init_process_group(config_cfg["distribute"]["backend"])
+
+ # load training dataset
+ train_dataset = data_cfg["file"]
+ branch = data_cfg["train_branch"]
+ name = data_cfg["name"]
+ with open(train_dataset, "r") as f:
+ options = yaml.load(f, Loader=yaml.FullLoader)
+ train_options = options[branch]
+ self.train_set = load_dataset(name)(train_options)
+ # define training sampler
+ self.train_sampler = data.distributed.DistributedSampler(self.train_set)
+ # wrapped with data loader
+ self.train_loader = data.DataLoader(self.train_set, shuffle=False,
+ sampler=self.train_sampler,
+ num_workers=data_cfg.get("num_workers", 4),
+ batch_size=data_cfg["train_batch_size"])
+
+ if self.local_rank == 0:
+ # load validation dataset
+ val_options = options[data_cfg["val_branch"]]
+ self.val_set = load_dataset(name)(val_options)
+ # wrapped with data loader
+ self.val_loader = data.DataLoader(self.val_set, shuffle=True,
+ num_workers=data_cfg.get("num_workers", 4),
+ batch_size=data_cfg["val_batch_size"])
+
+ self.resume = config_cfg.get("resume", False)
+
+ if not self.debug:
+ time_format = "%Y-%m-%d...%H.%M.%S"
+ run_id = time.strftime(time_format, time.localtime(time.time()))
+ self.run_id = config_cfg.get("id", run_id)
+ self.dir = os.path.join("runs", self.model_name, self.run_id)
+
+ if self.local_rank == 0:
+ if not self.resume:
+ if os.path.exists(self.dir):
+ raise ValueError("Error: given id '%s' already exists." % self.run_id)
+ os.makedirs(self.dir, exist_ok=True)
+ print(f"Writing config file to file directory: {self.dir}.")
+ yaml.dump({"config": self.config,
+ "train_data": train_options,
+ "val_data": val_options},
+ open(os.path.join(self.dir, 'train_config.yml'), 'w'))
+ # copy the script for the training model
+ model_file = MODELS_PATH[self.model_name]
+ os.system("cp " + model_file + " " + self.dir)
+ else:
+ print(f"Resuming the history in file directory: {self.dir}.")
+
+ print(f"Logging directory: {self.dir}.")
+
+ # redirect the std out stream
+ sys.stdout = Logger(os.path.join(self.dir, 'records.txt'))
+ center_print('Train configurations begins.')
+ pprint(self.config)
+ pprint(train_options)
+ pprint(val_options)
+ center_print('Train configurations ends.')
+
+ # load model
+ self.num_classes = model_cfg["num_classes"]
+ self.device = "cuda:" + str(self.local_rank)
+ self.model = load_model(self.model_name)(**model_cfg)
+ self.model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(self.model).to(self.device)
+ self._mprint(f"Using SyncBatchNorm.")
+ self.model = torch.nn.parallel.DistributedDataParallel(
+ self.model, device_ids=[self.local_rank], find_unused_parameters=True)
+
+ # load optimizer
+ optim_cfg = config_cfg.get("optimizer", None)
+ optim_name = optim_cfg.pop("name")
+ self.optimizer = get_optimizer(optim_name)(self.model.parameters(), **optim_cfg)
+ # load scheduler
+ self.scheduler = get_scheduler(self.optimizer, config_cfg.get("scheduler", None))
+ # load loss
+ self.loss_criterion = get_loss(config_cfg.get("loss", None), device=self.device)
+
+ # total number of steps (or epoch) to train
+ self.num_steps = train_options["num_steps"]
+ self.num_epoch = math.ceil(self.num_steps / len(self.train_loader))
+
+ # the number of steps to write down a log
+ self.log_steps = train_options["log_steps"]
+ # the number of steps to validate on val dataset once
+ self.val_steps = train_options["val_steps"]
+
+ # balance coefficients
+ self.lambda_1 = config_cfg["lambda_1"]
+ self.lambda_2 = config_cfg["lambda_2"]
+ self.warmup_step = config_cfg.get('warmup_step', 0)
+
+ self.contra_loss = MLLoss()
+ self.acc_meter = AccMeter()
+ self.loss_meter = AverageMeter()
+ self.recons_loss_meter = AverageMeter()
+ self.contra_loss_meter = AverageMeter()
+
+ if self.resume and self.local_rank == 0:
+ self._load_ckpt(best=config_cfg.get("resume_best", False), train=True)
+
+ def _test_settings(self, model_cfg, data_cfg, config_cfg):
+ # Not used.
+ raise NotImplementedError("The function is not intended to be used here.")
+
+ def _load_ckpt(self, best=False, train=False):
+ # Not used.
+ raise NotImplementedError("The function is not intended to be used here.")
+
+ def _save_ckpt(self, step, best=False):
+ save_dir = os.path.join(self.dir, f"best_model_{step}.bin" if best else "latest_model.bin")
+ torch.save({
+ "step": step,
+ "best_step": self.best_step,
+ "best_metric": self.best_metric,
+ "eval_metric": self.eval_metric,
+ "model": self.model.module.state_dict(),
+ "optimizer": self.optimizer.state_dict(),
+ "scheduler": self.scheduler.state_dict(),
+ }, save_dir)
+
+ def train(self):
+ try:
+ timer = Timer()
+ grad_scalar = GradScaler(2 ** 10)
+ if self.local_rank == 0:
+ writer = None if self.debug else SummaryWriter(log_dir=self.dir)
+ center_print("Training begins......")
+ else:
+ writer = None
+ start_epoch = self.start_step // len(self.train_loader) + 1
+ for epoch_idx in range(start_epoch, self.num_epoch + 1):
+ # set sampler
+ self.train_sampler.set_epoch(epoch_idx)
+
+ # reset meter
+ self.acc_meter.reset()
+ self.loss_meter.reset()
+ self.recons_loss_meter.reset()
+ self.contra_loss_meter.reset()
+ self.optimizer.step()
+
+ train_generator = enumerate(self.train_loader, 1)
+ # wrap train generator with tqdm for process 0
+ if self.local_rank == 0:
+ train_generator = tqdm(train_generator, position=0, leave=True)
+
+ for batch_idx, train_data in train_generator:
+ global_step = (epoch_idx - 1) * len(self.train_loader) + batch_idx
+ self.model.train()
+ I, Y = train_data
+ I = self.train_loader.dataset.load_item(I)
+ in_I, Y = self.to_device((I, Y))
+
+ # warm-up lr
+ if self.warmup_step != 0 and global_step <= self.warmup_step:
+ lr = self.config['config']['optimizer']['lr'] * float(global_step) / self.warmup_step
+ for param_group in self.optimizer.param_groups:
+ param_group['lr'] = lr
+
+ self.optimizer.zero_grad()
+ with autocast():
+ Y_pre = self.model(in_I)
+
+ # for BCE Setting:
+ if self.num_classes == 1:
+ Y_pre = Y_pre.squeeze()
+ loss = self.loss_criterion(Y_pre, Y.float())
+ Y_pre = torch.sigmoid(Y_pre)
+ else:
+ loss = self.loss_criterion(Y_pre, Y)
+
+ # flood
+ loss = (loss - 0.04).abs() + 0.04
+ recons_loss = exp_recons_loss(self.model.module.loss_inputs['recons'], (in_I, Y))
+ contra_loss = self.contra_loss(self.model.module.loss_inputs['contra'], Y)
+ loss += self.lambda_1 * recons_loss + self.lambda_2 * contra_loss
+
+ grad_scalar.scale(loss).backward()
+ grad_scalar.step(self.optimizer)
+ grad_scalar.update()
+ if self.warmup_step == 0 or global_step > self.warmup_step:
+ self.scheduler.step()
+
+ self.acc_meter.update(Y_pre, Y, self.num_classes == 1)
+ self.loss_meter.update(reduce_tensor(loss).item())
+ self.recons_loss_meter.update(reduce_tensor(recons_loss).item())
+ self.contra_loss_meter.update(reduce_tensor(contra_loss).item())
+ iter_acc = reduce_tensor(self.acc_meter.mean_acc()).item()
+
+ if self.local_rank == 0:
+ if global_step % self.log_steps == 0 and writer is not None:
+ writer.add_scalar("train/Acc", iter_acc, global_step)
+ writer.add_scalar("train/Loss", self.loss_meter.avg, global_step)
+ writer.add_scalar("train/Recons_Loss",
+ self.recons_loss_meter.avg if self.lambda_1 != 0 else 0.,
+ global_step)
+ writer.add_scalar("train/Contra_Loss", self.contra_loss_meter.avg, global_step)
+ writer.add_scalar("train/LR", self.scheduler.get_last_lr()[0], global_step)
+
+ # log training step
+ train_generator.set_description(
+ "Train Epoch %d (%d/%d), Global Step %d, Loss %.4f, Recons %.4f, con %.4f, "
+ "ACC %.4f, LR %.6f" % (
+ epoch_idx, batch_idx, len(self.train_loader), global_step,
+ self.loss_meter.avg, self.recons_loss_meter.avg, self.contra_loss_meter.avg,
+ iter_acc, self.scheduler.get_last_lr()[0])
+ )
+
+ # validating process
+ if global_step % self.val_steps == 0 and not self.debug:
+ print()
+ self.validate(epoch_idx, global_step, timer, writer)
+
+ # when num_steps has been set and the training process will
+ # be stopped earlier than the specified num_epochs, then stop.
+ if self.num_steps is not None and global_step == self.num_steps:
+ if writer is not None:
+ writer.close()
+ if self.local_rank == 0:
+ print()
+ center_print("Training process ends.")
+ dist.destroy_process_group()
+ return
+ # close the tqdm bar when one epoch ends
+ if self.local_rank == 0:
+ train_generator.close()
+ print()
+ # training ends with integer epochs
+ if self.local_rank == 0:
+ if writer is not None:
+ writer.close()
+ center_print("Training process ends.")
+ dist.destroy_process_group()
+ except Exception as e:
+ dist.destroy_process_group()
+ raise e
+
+ def validate(self, epoch, step, timer, writer):
+ v_idx = random.randint(1, len(self.val_loader) + 1)
+ categories = self.val_loader.dataset.categories
+ self.model.eval()
+ with torch.no_grad():
+ acc = AccMeter()
+ auc = AUCMeter()
+ loss_meter = AverageMeter()
+ cur_acc = 0.0 # Higher is better
+ cur_auc = 0.0 # Higher is better
+ cur_loss = 1e8 # Lower is better
+ val_generator = tqdm(enumerate(self.val_loader, 1), position=0, leave=True)
+ for val_idx, val_data in val_generator:
+ I, Y = val_data
+ I = self.val_loader.dataset.load_item(I)
+ in_I, Y = self.to_device((I, Y))
+ Y_pre = self.model(in_I)
+
+ # for BCE Setting:
+ if self.num_classes == 1:
+ Y_pre = Y_pre.squeeze()
+ loss = self.loss_criterion(Y_pre, Y.float())
+ Y_pre = torch.sigmoid(Y_pre)
+ else:
+ loss = self.loss_criterion(Y_pre, Y)
+
+ acc.update(Y_pre, Y, self.num_classes == 1)
+ auc.update(Y_pre, Y, self.num_classes == 1)
+ loss_meter.update(loss.item())
+
+ cur_acc = acc.mean_acc()
+ cur_loss = loss_meter.avg
+
+ val_generator.set_description(
+ "Eval Epoch %d (%d/%d), Global Step %d, Loss %.4f, ACC %.4f" % (
+ epoch, val_idx, len(self.val_loader), step,
+ cur_loss, cur_acc)
+ )
+
+ if val_idx == v_idx or val_idx == 1:
+ sample_recons = list()
+ for _ in self.model.module.loss_inputs['recons']:
+ sample_recons.append(_[:4].to("cpu"))
+ # show images
+ images = I[:4]
+ images = torch.cat([images, *sample_recons], dim=0)
+ pred = Y_pre[:4]
+ gt = Y[:4]
+ figure = self.plot_figure(images, pred, gt, 4, categories, show=False)
+
+ cur_auc = auc.mean_auc()
+ print("Eval Epoch %d, Loss %.4f, ACC %.4f, AUC %.4f" % (epoch, cur_loss, cur_acc, cur_auc))
+ if writer is not None:
+ writer.add_scalar("val/Loss", cur_loss, step)
+ writer.add_scalar("val/Acc", cur_acc, step)
+ writer.add_scalar("val/AUC", cur_auc, step)
+ writer.add_figure("val/Figures", figure, step)
+ # record the best acc and the corresponding step
+ if self.eval_metric == 'Acc' and cur_acc >= self.best_metric:
+ self.best_metric = cur_acc
+ self.best_step = step
+ self._save_ckpt(step, best=True)
+ elif self.eval_metric == 'AUC' and cur_auc >= self.best_metric:
+ self.best_metric = cur_auc
+ self.best_step = step
+ self._save_ckpt(step, best=True)
+ elif self.eval_metric == 'LogLoss' and cur_loss <= self.best_metric:
+ self.best_metric = cur_loss
+ self.best_step = step
+ self._save_ckpt(step, best=True)
+ print("Best Step %d, Best %s %.4f, Running Time: %s, Estimated Time: %s" % (
+ self.best_step, self.eval_metric, self.best_metric,
+ timer.measure(), timer.measure(step / self.num_steps)
+ ))
+ self._save_ckpt(step, best=False)
+
+ def test(self):
+ # Not used.
+ raise NotImplementedError("The function is not intended to be used here.")
diff --git a/clean/video/recce/trainer/exp_tester.py b/clean/video/recce/trainer/exp_tester.py
new file mode 100644
index 0000000000000000000000000000000000000000..ee4f219f0ba60c6ded44e3b7c95eb7b21fc0be46
--- /dev/null
+++ b/clean/video/recce/trainer/exp_tester.py
@@ -0,0 +1,144 @@
+import os
+import sys
+import yaml
+import torch
+import random
+
+from tqdm import tqdm
+from pprint import pprint
+from torch.utils import data
+
+from dataset import load_dataset
+from loss import get_loss
+from model import load_model
+from model.common import freeze_weights
+from trainer import AbstractTrainer
+from trainer.utils import AccMeter, AUCMeter, AverageMeter, Logger, center_print
+
+
+class ExpTester(AbstractTrainer):
+ def __init__(self, config, stage="Test"):
+ super(ExpTester, self).__init__(config, stage)
+
+ if torch.cuda.is_available() and self.device is not None:
+ print(f"Using cuda device: {self.device}.")
+ self.gpu = True
+ self.model = self.model.to(self.device)
+ else:
+ print("Using cpu device.")
+ self.device = torch.device("cpu")
+
+ def _initiated_settings(self, model_cfg=None, data_cfg=None, config_cfg=None):
+ self.gpu = False
+ self.device = config_cfg.get("device", None)
+
+ def _train_settings(self, model_cfg=None, data_cfg=None, config_cfg=None):
+ # Not used.
+ raise NotImplementedError("The function is not intended to be used here.")
+
+ def _test_settings(self, model_cfg=None, data_cfg=None, config_cfg=None):
+ # load test dataset
+ test_dataset = data_cfg["file"]
+ branch = data_cfg["test_branch"]
+ name = data_cfg["name"]
+ with open(test_dataset, "r") as f:
+ options = yaml.load(f, Loader=yaml.FullLoader)
+ test_options = options[branch]
+ self.test_set = load_dataset(name)(test_options)
+ # wrapped with data loader
+ self.test_batch_size = data_cfg["test_batch_size"]
+ self.test_loader = data.DataLoader(self.test_set, shuffle=False,
+ batch_size=self.test_batch_size)
+ self.run_id = config_cfg["id"]
+ self.ckpt_fold = config_cfg.get("ckpt_fold", "runs")
+ self.dir = os.path.join(self.ckpt_fold, self.model_name, self.run_id)
+
+ # load model
+ self.num_classes = model_cfg["num_classes"]
+ self.model = load_model(self.model_name)(**model_cfg)
+
+ # load loss
+ self.loss_criterion = get_loss(config_cfg.get("loss", None))
+
+ # redirect the std out stream
+ sys.stdout = Logger(os.path.join(self.dir, "test_result.txt"))
+ print('Run dir: {}'.format(self.dir))
+
+ center_print('Test configurations begins')
+ pprint(self.config)
+ pprint(test_options)
+ center_print('Test configurations ends')
+
+ self.ckpt = config_cfg.get("ckpt", "best_model")
+ self._load_ckpt(best=True, train=False)
+
+ def _save_ckpt(self, step, best=False):
+ # Not used.
+ raise NotImplementedError("The function is not intended to be used here.")
+
+ def _load_ckpt(self, best=False, train=False):
+ load_dir = os.path.join(self.dir, self.ckpt + ".bin" if best else "latest_model.bin")
+ load_dict = torch.load(load_dir, map_location=self.device)
+ self.start_step = load_dict["step"]
+ self.best_step = load_dict["best_step"]
+ self.best_metric = load_dict.get("best_metric", None)
+ if self.best_metric is None:
+ self.best_metric = load_dict.get("best_acc")
+ self.eval_metric = load_dict.get("eval_metric", None)
+ if self.eval_metric is None:
+ self.eval_metric = load_dict.get("Acc")
+ self.model.load_state_dict(load_dict["model"])
+ print(f"Loading checkpoint from {load_dir}, best step: {self.best_step}, "
+ f"best {self.eval_metric}: {round(self.best_metric.item(), 4)}.")
+
+ def train(self):
+ # Not used.
+ raise NotImplementedError("The function is not intended to be used here.")
+
+ def validate(self, epoch, step, timer, writer):
+ # Not used.
+ raise NotImplementedError("The function is not intended to be used here.")
+
+ def test(self, display_images=False):
+ freeze_weights(self.model)
+ t_idx = random.randint(1, len(self.test_loader) + 1)
+ self.fixed_randomness() # for reproduction
+
+ acc = AccMeter()
+ auc = AUCMeter()
+ logloss = AverageMeter()
+ test_generator = tqdm(enumerate(self.test_loader, 1))
+ categories = self.test_loader.dataset.categories
+ for idx, test_data in test_generator:
+ self.model.eval()
+ I, Y = test_data
+ I = self.test_loader.dataset.load_item(I)
+ if self.gpu:
+ in_I, Y = self.to_device((I, Y))
+ else:
+ in_I, Y = (I, Y)
+ Y_pre = self.model(in_I)
+
+ # for BCE Setting:
+ if self.num_classes == 1:
+ Y_pre = Y_pre.squeeze()
+ loss = self.loss_criterion(Y_pre, Y.float())
+ Y_pre = torch.sigmoid(Y_pre)
+ else:
+ loss = self.loss_criterion(Y_pre, Y)
+
+ acc.update(Y_pre, Y, use_bce=self.num_classes == 1)
+ auc.update(Y_pre, Y, use_bce=self.num_classes == 1)
+ logloss.update(loss.item())
+
+ test_generator.set_description("Test %d/%d" % (idx, len(self.test_loader)))
+ if display_images and idx == t_idx:
+ # show images
+ images = I[:4]
+ pred = Y_pre[:4]
+ gt = Y[:4]
+ self.plot_figure(images, pred, gt, 2, categories)
+
+ print("Test, FINAL LOSS %.4f, FINAL ACC %.4f, FINAL AUC %.4f" %
+ (logloss.avg, acc.mean_acc(), auc.mean_auc()))
+ auc.curve(self.dir)
diff --git a/clean/video/recce/trainer/utils.py b/clean/video/recce/trainer/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..fcf1c4a864d34a18133667293c9dc76215af1011
--- /dev/null
+++ b/clean/video/recce/trainer/utils.py
@@ -0,0 +1,183 @@
+import os
+import sys
+import time
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+import torch.distributed as dist
+from collections import OrderedDict
+
+import numpy as np
+from sklearn.metrics import roc_auc_score, roc_curve
+from scipy.optimize import brentq
+from scipy.interpolate import interp1d
+
+# Tracking the path to the definition of the model.
+MODELS_PATH = {
+ "Recce": "model/network/Recce.py"
+}
+
+
+def exp_recons_loss(recons, x):
+ x, y = x
+ loss = torch.tensor(0., device=y.device)
+ real_index = torch.where(1 - y)[0]
+ for r in recons:
+ if real_index.numel() > 0:
+ real_x = torch.index_select(x, dim=0, index=real_index)
+ real_rec = torch.index_select(r, dim=0, index=real_index)
+ real_rec = F.interpolate(real_rec, size=x.shape[-2:], mode='bilinear', align_corners=True)
+ loss += torch.mean(torch.abs(real_rec - real_x))
+ return loss
+
+
+def center_print(content, around='*', repeat_around=10):
+ num = repeat_around
+ s = around
+ print(num * s + ' %s ' % content + num * s)
+
+
+def reduce_tensor(t):
+ rt = t.clone()
+ dist.all_reduce(rt)
+ rt /= float(dist.get_world_size())
+ return rt
+
+
+def tensor2image(tensor):
+ image = tensor.permute([1, 2, 0]).cpu().detach().numpy()
+ return (image - np.min(image)) / (np.max(image) - np.min(image))
+
+
+def state_dict(state_dict):
+ """ Remove 'module' keyword in state dictionary. """
+ weights = OrderedDict()
+ for k, v in state_dict.items():
+ weights.update({k.replace("module.", ""): v})
+ return weights
+
+
+class Logger(object):
+ def __init__(self, filename):
+ self.terminal = sys.stdout
+ self.log = open(filename, "a")
+
+ def write(self, message):
+ self.terminal.write(message)
+ self.log.write(message)
+ self.log.flush()
+
+ def flush(self):
+ pass
+
+
+class Timer(object):
+ """The class for timer."""
+
+ def __init__(self):
+ self.o = time.time()
+
+ def measure(self, p=1):
+ x = (time.time() - self.o) / p
+ x = int(x)
+ if x >= 3600:
+ return '{:.1f}h'.format(x / 3600)
+ if x >= 60:
+ return '{}m'.format(round(x / 60))
+ return '{}s'.format(x)
+
+
+class MLLoss(nn.Module):
+ def __init__(self):
+ super(MLLoss, self).__init__()
+
+ def forward(self, input, target, eps=1e-6):
+ # 0 - real; 1 - fake.
+ loss = torch.tensor(0., device=target.device)
+ batch_size = target.shape[0]
+ mat_1 = torch.hstack([target.unsqueeze(-1)] * batch_size)
+ mat_2 = torch.vstack([target] * batch_size)
+ diff_mat = torch.logical_xor(mat_1, mat_2).float()
+ or_mat = torch.logical_or(mat_1, mat_2)
+ eye = torch.eye(batch_size, device=target.device)
+ or_mat = torch.logical_or(or_mat, eye).float()
+ sim_mat = 1. - or_mat
+ for _ in input:
+ diff = torch.sum(_ * diff_mat, dim=[0, 1]) / (torch.sum(diff_mat, dim=[0, 1]) + eps)
+ sim = torch.sum(_ * sim_mat, dim=[0, 1]) / (torch.sum(sim_mat, dim=[0, 1]) + eps)
+ partial_loss = 1. - sim + diff
+ loss += max(partial_loss, torch.zeros_like(partial_loss))
+ return loss
+
+
+class AccMeter(object):
+ def __init__(self):
+ self.nums = 0
+ self.acc = 0
+
+ def reset(self):
+ self.nums = 0
+ self.acc = 0
+
+ def update(self, pred, target, use_bce=False):
+ if use_bce:
+ pred = (pred >= 0.5).int()
+ else:
+ pred = pred.argmax(1)
+ self.nums += target.shape[0]
+ self.acc += torch.sum(pred == target)
+
+ def mean_acc(self):
+ return self.acc / self.nums
+
+
+class AUCMeter(object):
+ def __init__(self):
+ self.score = None
+ self.true = None
+
+ def reset(self):
+ self.score = None
+ self.true = None
+
+ def update(self, score, true, use_bce=False):
+ if use_bce:
+ score = score.detach().cpu().numpy()
+ else:
+ score = torch.softmax(score.detach(), dim=-1)
+ score = torch.select(score, 1, 1).cpu().numpy()
+ true = true.flatten().cpu().numpy()
+ self.score = score if self.score is None else np.concatenate([self.score, score])
+ self.true = true if self.true is None else np.concatenate([self.true, true])
+
+ def mean_auc(self):
+ return roc_auc_score(self.true, self.score)
+
+ def curve(self, prefix):
+ fpr, tpr, thresholds = roc_curve(self.true, self.score, pos_label=1)
+ eer = brentq(lambda x: 1. - x - interp1d(fpr, tpr)(x), 0., 1.)
+ thresh = interp1d(fpr, thresholds)(eer)
+ print(f"# EER: {eer:.4f}(thresh: {thresh:.4f})")
+ torch.save([fpr, tpr, thresholds], os.path.join(prefix, "roc_curve.pickle"))
+
+
+class AverageMeter(object):
+ """Computes and stores the average and current value"""
+
+ def __init__(self):
+ self.val = 0
+ self.avg = 0
+ self.sum = 0
+ self.count = 0
+
+ def reset(self):
+ self.val = 0
+ self.avg = 0
+ self.sum = 0
+ self.count = 0
+
+ def update(self, val, n=1):
+ self.val = val
+ self.sum += val * n
+ self.count += n
+ self.avg = self.sum / self.count
diff --git a/clean/video/univfd_video/LICENSE b/clean/video/univfd_video/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..7bcf6bcca73c769ede1f597bb73794e567039fb8
--- /dev/null
+++ b/clean/video/univfd_video/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2025 Wisconsin AI and Vision Lab (WAIV)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/clean/video/univfd_video/README.md b/clean/video/univfd_video/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..393d091108d187521780a0c53f1260fa8967cad6
--- /dev/null
+++ b/clean/video/univfd_video/README.md
@@ -0,0 +1,110 @@
+# Detecting fake images
+
+**Towards Universal Fake Image Detectors that Generalize Across Generative Models**
+[Utkarsh Ojha*](https://utkarshojha.github.io/), [Yuheng Li*](https://yuheng-li.github.io/), [Yong Jae Lee](https://pages.cs.wisc.edu/~yongjaelee/)
+(*Equal contribution)
+CVPR 2023
+
+[[Project Page](https://utkarshojha.github.io/universal-fake-detection/)] [[Paper](https://arxiv.org/abs/2302.10174)]
+
+
+ >
+ Using images from one type of generative model (e.g., GAN), detect fake images from other breeds (e.g., Diffusion models)
+
+
+## Contents
+
+- [Setup](#setup)
+- [Pretrained model](#weights)
+- [Data](#data)
+- [Evaluation](#evaluation)
+- [Training](#training)
+
+
+## Setup
+
+1. Clone this repository
+```bash
+git clone https://github.com/Yuheng-Li/UniversalFakeDetect
+cd UniversalFakeDetect
+```
+
+2. Install the necessary libraries
+```bash
+pip install torch torchvision
+```
+
+## Data
+
+- Of the 19 models studied overall (Table 1/2 in the main paper), 11 are taken from a [previous work](https://arxiv.org/abs/1912.11035). Download the test set, i.e., real/fake images for those 11 models given by the authors from [here](https://drive.google.com/file/d/1z_fD3UKgWQyOTZIBbYSaQ-hz4AzUrLC1/view) (dataset size ~19GB).
+- Download the file and unzip it in `datasets/test`. You could also use the bash scripts provided by the authors, as described [here](https://github.com/PeterWang512/CNNDetection#download-the-dataset) in their code repository.
+- This should create a directory structure as follows:
+```
+
+datasets
+└── test
+ ├── progan
+ │── cyclegan
+ │── biggan
+ │ .
+ │ .
+
+```
+- Each directory (e.g., progan) will contain real/fake images under `0_real` and `1_fake` folders respectively.
+- Dataset for the diffusion models (e.g., LDM/Glide) can be found [here](https://drive.google.com/file/d/1FXlGIRh_Ud3cScMgSVDbEWmPDmjcrm1t/view?usp=drive_link). Note that in the paper (Table 2/3), we had reported the results over 10k randomly sampled images. Since providing that many images for all the domains will take up too much space, we are only releasing 1k images for each domain; i.e., 1k images fake images and 1k real images for each domain (e.g., LDM-200).
+- Download and unzip the file into `./diffusion_datasets` directory.
+
+
+## Evaluation
+
+- You can evaluate the model on all the dataset at once by running:
+```bash
+python validate.py --arch=CLIP:ViT-L/14 --ckpt=pretrained_weights/fc_weights.pth --result_folder=clip_vitl14
+```
+
+- You can also evaluate the model on one generative model by specifying the paths of real and fake datasets
+```bash
+python validate.py --arch=CLIP:ViT-L/14 --ckpt=pretrained_weights/fc_weights.pth --result_folder=clip_vitl14 --real_path datasets/test/progan/0_real --fake_path datasets/test/progan/1_fake
+```
+
+Note that if no arguments are provided for `real_path` and `fake_path`, the script will perform the evaluation on all the domains specified in `dataset_paths.py`.
+
+- The results will be stored in `results/` in two files: `ap.txt` stores the Average Prevision for each of the test domains, and `acc.txt` stores the accuracy (with 0.5 as the threshold) for the same domains.
+
+## Training
+
+- Our main model is trained on the same dataset used by the authors of [this work](https://arxiv.org/abs/1912.11035). Download the official training dataset provided [here](https://drive.google.com/file/d/1iVNBV0glknyTYGA9bCxT_d0CVTOgGcKh/view) (dataset size ~ 72GB).
+
+- Download and unzip the dataset in `datasets/train` directory. The overall structure should look like the following:
+```
+datasets
+└── train
+ └── progan
+ ├── airplane
+ │── bird
+ │── boat
+ │ .
+ │ .
+```
+- A total of 20 different object categories, with each folder containing the corresponding real and fake images in `0_real` and `1_fake` folders.
+- The model can then be trained with the following command:
+```bash
+python train.py --name=clip_vitl14 --wang2020_data_path=datasets/ --data_mode=wang2020 --arch=CLIP:ViT-L/14 --fix_backbone
+```
+- **Important**: do not forget to use the `--fix_backbone` argument during training, which makes sure that the only the linear layer's parameters will be trained.
+
+## Acknowledgement
+
+We would like to thank [Sheng-Yu Wang](https://github.com/PeterWang512) for releasing the real/fake images from different generative models. Our training pipeline is also inspired by his [open-source code](https://github.com/PeterWang512/CNNDetection). We would also like to thank [CompVis](https://github.com/CompVis) for releasing the pre-trained [LDMs](https://github.com/CompVis/latent-diffusion) and [LAION](https://laion.ai/) for open-sourcing [LAION-400M dataset](https://laion.ai/blog/laion-400-open-dataset/).
+
+## Citation
+
+If you find our work helpful in your research, please cite it using the following:
+```bibtex
+@inproceedings{ojha2023fakedetect,
+ title={Towards Universal Fake Image Detectors that Generalize Across Generative Models},
+ author={Ojha, Utkarsh and Li, Yuheng and Lee, Yong Jae},
+ booktitle={CVPR},
+ year={2023},
+}
+```
diff --git a/clean/video/univfd_video/SOURCE.md b/clean/video/univfd_video/SOURCE.md
new file mode 100644
index 0000000000000000000000000000000000000000..616eb7fb3256d53790d32235fdf82c9da84153c0
--- /dev/null
+++ b/clean/video/univfd_video/SOURCE.md
@@ -0,0 +1,20 @@
+# Source: video/univfd_video
+
+| Field | Value |
+|---|---|
+| Upstream | **UNVERIFIED** -- provenance was lost when this code was vendored |
+| Paper | not recorded |
+| Commit SHA | **not recorded** -- the vendoring step did not preserve it |
+| Mirrored on | 2026-09-15 |
+| Upstream license | LICENSE |
+
+This is a **mirror**, stripped to the files needed for inference. The full
+untouched snapshot is at `archive/video__univfd_video.tar.gz`.
+
+This code is the work of its original authors and is **not** covered by the
+DeepSafe project license. If you are an author and want this removed, open an
+issue on https://github.com/deepsafehq/deepsafe-bench and it will be taken down
+within 48 hours, no questions asked.
+
+**Alias.** This model shares its code with `image/universal`; only the
+weights differ. No separate archive is published.
diff --git a/clean/video/univfd_video/dataset_paths.py b/clean/video/univfd_video/dataset_paths.py
new file mode 100644
index 0000000000000000000000000000000000000000..3e1c8acfecfda1f209e29cb109e1ad26c64a0ab4
--- /dev/null
+++ b/clean/video/univfd_video/dataset_paths.py
@@ -0,0 +1,153 @@
+DATASET_PATHS = [
+
+
+ dict(
+ real_path='../FAKE_IMAGES/CNN/test/progan',
+ fake_path='../FAKE_IMAGES/CNN/test/progan',
+ data_mode='wang2020',
+ key='progan'
+ ),
+
+ dict(
+ real_path='../FAKE_IMAGES/CNN/test/cyclegan',
+ fake_path='../FAKE_IMAGES/CNN/test/cyclegan',
+ data_mode='wang2020',
+ key='cyclegan'
+ ),
+
+ dict(
+ real_path='../FAKE_IMAGES/CNN/test/biggan/', # Imagenet
+ fake_path='../FAKE_IMAGES/CNN/test/biggan/',
+ data_mode='wang2020',
+ key='biggan'
+ ),
+
+
+ dict(
+ real_path='../FAKE_IMAGES/CNN/test/stylegan',
+ fake_path='../FAKE_IMAGES/CNN/test/stylegan',
+ data_mode='wang2020',
+ key='stylegan'
+ ),
+
+
+ dict(
+ real_path='../FAKE_IMAGES/CNN/test/gaugan', # It is COCO
+ fake_path='../FAKE_IMAGES/CNN/test/gaugan',
+ data_mode='wang2020',
+ key='gaugan'
+ ),
+
+
+ dict(
+ real_path='../FAKE_IMAGES/CNN/test/stargan',
+ fake_path='../FAKE_IMAGES/CNN/test/stargan',
+ data_mode='wang2020',
+ key='stargan'
+ ),
+
+
+ dict(
+ real_path='../FAKE_IMAGES/CNN/test/deepfake',
+ fake_path='../FAKE_IMAGES/CNN/test/deepfake',
+ data_mode='wang2020',
+ key='deepfake'
+ ),
+
+
+ dict(
+ real_path='../FAKE_IMAGES/CNN/test/seeingdark',
+ fake_path='../FAKE_IMAGES/CNN/test/seeingdark',
+ data_mode='wang2020',
+ key='sitd'
+ ),
+
+
+ dict(
+ real_path='../FAKE_IMAGES/CNN/test/san',
+ fake_path='../FAKE_IMAGES/CNN/test/san',
+ data_mode='wang2020',
+ key='san'
+ ),
+
+
+ dict(
+ real_path='../FAKE_IMAGES/CNN/test/crn', # Images from some video games
+ fake_path='../FAKE_IMAGES/CNN/test/crn',
+ data_mode='wang2020',
+ key='crn'
+ ),
+
+
+ dict(
+ real_path='../FAKE_IMAGES/CNN/test/imle', # Images from some video games
+ fake_path='../FAKE_IMAGES/CNN/test/imle',
+ data_mode='wang2020',
+ key='imle'
+ ),
+
+
+ dict(
+ real_path='./diffusion_datasets/imagenet',
+ fake_path='./diffusion_datasets/guided',
+ data_mode='wang2020',
+ key='guided'
+ ),
+
+
+ dict(
+ real_path='./diffusion_datasets/laion',
+ fake_path='./diffusion_datasets/ldm_200',
+ data_mode='wang2020',
+ key='ldm_200'
+ ),
+
+ dict(
+ real_path='./diffusion_datasets/laion',
+ fake_path='./diffusion_datasets/ldm_200_cfg',
+ data_mode='wang2020',
+ key='ldm_200_cfg'
+ ),
+
+ dict(
+ real_path='./diffusion_datasets/laion',
+ fake_path='./diffusion_datasets/ldm_100',
+ data_mode='wang2020',
+ key='ldm_100'
+ ),
+
+
+ dict(
+ real_path='./diffusion_datasets/laion',
+ fake_path='./diffusion_datasets/glide_100_27',
+ data_mode='wang2020',
+ key='glide_100_27'
+ ),
+
+
+ dict(
+ real_path='./diffusion_datasets/laion',
+ fake_path='./diffusion_datasets/glide_50_27',
+ data_mode='wang2020',
+ key='glide_50_27'
+ ),
+
+
+ dict(
+ real_path='./diffusion_datasets/laion',
+ fake_path='./diffusion_datasets/glide_100_10',
+ data_mode='wang2020',
+ key='glide_100_10'
+ ),
+
+
+ dict(
+ real_path='./diffusion_datasets/laion',
+ fake_path='./diffusion_datasets/dalle',
+ data_mode='wang2020',
+ key='dalle'
+ ),
+
+
+
+]
diff --git a/clean/video/univfd_video/models/__init__.py b/clean/video/univfd_video/models/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..d7b790b40d29d1f3bf02f398f3522eea8e4c2c22
--- /dev/null
+++ b/clean/video/univfd_video/models/__init__.py
@@ -0,0 +1,43 @@
+from .clip_models import CLIPModel
+from .imagenet_models import ImagenetModel
+
+
+VALID_NAMES = [
+ 'Imagenet:resnet18',
+ 'Imagenet:resnet34',
+ 'Imagenet:resnet50',
+ 'Imagenet:resnet101',
+ 'Imagenet:resnet152',
+ 'Imagenet:vgg11',
+ 'Imagenet:vgg19',
+ 'Imagenet:swin-b',
+ 'Imagenet:swin-s',
+ 'Imagenet:swin-t',
+ 'Imagenet:vit_b_16',
+ 'Imagenet:vit_b_32',
+ 'Imagenet:vit_l_16',
+ 'Imagenet:vit_l_32',
+
+ 'CLIP:RN50',
+ 'CLIP:RN101',
+ 'CLIP:RN50x4',
+ 'CLIP:RN50x16',
+ 'CLIP:RN50x64',
+ 'CLIP:ViT-B/32',
+ 'CLIP:ViT-B/16',
+ 'CLIP:ViT-L/14',
+ 'CLIP:ViT-L/14@336px',
+]
+
+
+
+
+
+def get_model(name):
+ assert name in VALID_NAMES
+ if name.startswith("Imagenet:"):
+ return ImagenetModel(name[9:])
+ elif name.startswith("CLIP:"):
+ return CLIPModel(name[5:])
+ else:
+ assert False
diff --git a/clean/video/univfd_video/models/clip/__init__.py b/clean/video/univfd_video/models/clip/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..dcc5619538c0f7c782508bdbd9587259d805e0d9
--- /dev/null
+++ b/clean/video/univfd_video/models/clip/__init__.py
@@ -0,0 +1 @@
+from .clip import *
diff --git a/clean/video/univfd_video/models/clip/bpe_simple_vocab_16e6.txt.gz b/clean/video/univfd_video/models/clip/bpe_simple_vocab_16e6.txt.gz
new file mode 100644
index 0000000000000000000000000000000000000000..36a15856e00a06a9fbed8cdd34d2393fea4a3113
--- /dev/null
+++ b/clean/video/univfd_video/models/clip/bpe_simple_vocab_16e6.txt.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:924691ac288e54409236115652ad4aa250f48203de50a9e4722a6ecd48d6804a
+size 1356917
diff --git a/clean/video/univfd_video/models/clip/clip.py b/clean/video/univfd_video/models/clip/clip.py
new file mode 100644
index 0000000000000000000000000000000000000000..257511e1d40c120e0d64a0f1562d44b2b8a40a17
--- /dev/null
+++ b/clean/video/univfd_video/models/clip/clip.py
@@ -0,0 +1,237 @@
+import hashlib
+import os
+import urllib
+import warnings
+from typing import Any, Union, List
+from pkg_resources import packaging
+
+import torch
+from PIL import Image
+from torchvision.transforms import Compose, Resize, CenterCrop, ToTensor, Normalize
+from tqdm import tqdm
+
+from .model import build_model
+from .simple_tokenizer import SimpleTokenizer as _Tokenizer
+
+try:
+ from torchvision.transforms import InterpolationMode
+ BICUBIC = InterpolationMode.BICUBIC
+except ImportError:
+ BICUBIC = Image.BICUBIC
+
+
+if packaging.version.parse(torch.__version__) < packaging.version.parse("1.7.1"):
+ warnings.warn("PyTorch version 1.7.1 or higher is recommended")
+
+
+__all__ = ["available_models", "load", "tokenize"]
+_tokenizer = _Tokenizer()
+
+_MODELS = {
+ "RN50": "https://openaipublic.azureedge.net/clip/models/afeb0e10f9e5a86da6080e35cf09123aca3b358a0c3e3b6c78a7b63bc04b6762/RN50.pt",
+ "RN101": "https://openaipublic.azureedge.net/clip/models/8fa8567bab74a42d41c5915025a8e4538c3bdbe8804a470a72f30b0d94fab599/RN101.pt",
+ "RN50x4": "https://openaipublic.azureedge.net/clip/models/7e526bd135e493cef0776de27d5f42653e6b4c8bf9e0f653bb11773263205fdd/RN50x4.pt",
+ "RN50x16": "https://openaipublic.azureedge.net/clip/models/52378b407f34354e150460fe41077663dd5b39c54cd0bfd2b27167a4a06ec9aa/RN50x16.pt",
+ "RN50x64": "https://openaipublic.azureedge.net/clip/models/be1cfb55d75a9666199fb2206c106743da0f6468c9d327f3e0d0a543a9919d9c/RN50x64.pt",
+ "ViT-B/32": "https://openaipublic.azureedge.net/clip/models/40d365715913c9da98579312b702a82c18be219cc2a73407c4526f58eba950af/ViT-B-32.pt",
+ "ViT-B/16": "https://openaipublic.azureedge.net/clip/models/5806e77cd80f8b59890b7e101eabd078d9fb84e6937f9e85e4ecb61988df416f/ViT-B-16.pt",
+ "ViT-L/14": "https://openaipublic.azureedge.net/clip/models/b8cca3fd41ae0c99ba7e8951adf17d267cdb84cd88be6f7c2e0eca1737a03836/ViT-L-14.pt",
+ "ViT-L/14@336px": "https://openaipublic.azureedge.net/clip/models/3035c92b350959924f9f00213499208652fc7ea050643e8b385c2dac08641f02/ViT-L-14-336px.pt",
+}
+
+
+def _download(url: str, root: str):
+ os.makedirs(root, exist_ok=True)
+ filename = os.path.basename(url)
+
+ expected_sha256 = url.split("/")[-2]
+ download_target = os.path.join(root, filename)
+
+ if os.path.exists(download_target) and not os.path.isfile(download_target):
+ raise RuntimeError(f"{download_target} exists and is not a regular file")
+
+ if os.path.isfile(download_target):
+ if hashlib.sha256(open(download_target, "rb").read()).hexdigest() == expected_sha256:
+ return download_target
+ else:
+ warnings.warn(f"{download_target} exists, but the SHA256 checksum does not match; re-downloading the file")
+
+ with urllib.request.urlopen(url) as source, open(download_target, "wb") as output:
+ with tqdm(total=int(source.info().get("Content-Length")), ncols=80, unit='iB', unit_scale=True, unit_divisor=1024) as loop:
+ while True:
+ buffer = source.read(8192)
+ if not buffer:
+ break
+
+ output.write(buffer)
+ loop.update(len(buffer))
+
+ if hashlib.sha256(open(download_target, "rb").read()).hexdigest() != expected_sha256:
+ raise RuntimeError("Model has been downloaded but the SHA256 checksum does not not match")
+
+ return download_target
+
+
+def _convert_image_to_rgb(image):
+ return image.convert("RGB")
+
+
+def _transform(n_px):
+ return Compose([
+ Resize(n_px, interpolation=BICUBIC),
+ CenterCrop(n_px),
+ _convert_image_to_rgb,
+ ToTensor(),
+ Normalize((0.48145466, 0.4578275, 0.40821073), (0.26862954, 0.26130258, 0.27577711)),
+ ])
+
+
+def available_models() -> List[str]:
+ """Returns the names of available CLIP models"""
+ return list(_MODELS.keys())
+
+
+def load(name: str, device: Union[str, torch.device] = "cuda" if torch.cuda.is_available() else "cpu", jit: bool = False, download_root: str = None):
+ """Load a CLIP model
+
+ Parameters
+ ----------
+ name : str
+ A model name listed by `clip.available_models()`, or the path to a model checkpoint containing the state_dict
+
+ device : Union[str, torch.device]
+ The device to put the loaded model
+
+ jit : bool
+ Whether to load the optimized JIT model or more hackable non-JIT model (default).
+
+ download_root: str
+ path to download the model files; by default, it uses "~/.cache/clip"
+
+ Returns
+ -------
+ model : torch.nn.Module
+ The CLIP model
+
+ preprocess : Callable[[PIL.Image], torch.Tensor]
+ A torchvision transform that converts a PIL image into a tensor that the returned model can take as its input
+ """
+ if name in _MODELS:
+ model_path = _download(_MODELS[name], download_root or os.path.expanduser("~/.cache/clip"))
+ elif os.path.isfile(name):
+ model_path = name
+ else:
+ raise RuntimeError(f"Model {name} not found; available models = {available_models()}")
+
+ with open(model_path, 'rb') as opened_file:
+ try:
+ # loading JIT archive
+ model = torch.jit.load(opened_file, map_location=device if jit else "cpu").eval()
+ state_dict = None
+ except RuntimeError:
+ # loading saved state dict
+ if jit:
+ warnings.warn(f"File {model_path} is not a JIT archive. Loading as a state dict instead")
+ jit = False
+ state_dict = torch.load(opened_file, map_location="cpu")
+
+ if not jit:
+ model = build_model(state_dict or model.state_dict()).to(device)
+ if str(device) == "cpu":
+ model.float()
+ return model, _transform(model.visual.input_resolution)
+
+ # patch the device names
+ device_holder = torch.jit.trace(lambda: torch.ones([]).to(torch.device(device)), example_inputs=[])
+ device_node = [n for n in device_holder.graph.findAllNodes("prim::Constant") if "Device" in repr(n)][-1]
+
+ def patch_device(module):
+ try:
+ graphs = [module.graph] if hasattr(module, "graph") else []
+ except RuntimeError:
+ graphs = []
+
+ if hasattr(module, "forward1"):
+ graphs.append(module.forward1.graph)
+
+ for graph in graphs:
+ for node in graph.findAllNodes("prim::Constant"):
+ if "value" in node.attributeNames() and str(node["value"]).startswith("cuda"):
+ node.copyAttributes(device_node)
+
+ model.apply(patch_device)
+ patch_device(model.encode_image)
+ patch_device(model.encode_text)
+
+ # patch dtype to float32 on CPU
+ if str(device) == "cpu":
+ float_holder = torch.jit.trace(lambda: torch.ones([]).float(), example_inputs=[])
+ float_input = list(float_holder.graph.findNode("aten::to").inputs())[1]
+ float_node = float_input.node()
+
+ def patch_float(module):
+ try:
+ graphs = [module.graph] if hasattr(module, "graph") else []
+ except RuntimeError:
+ graphs = []
+
+ if hasattr(module, "forward1"):
+ graphs.append(module.forward1.graph)
+
+ for graph in graphs:
+ for node in graph.findAllNodes("aten::to"):
+ inputs = list(node.inputs())
+ for i in [1, 2]: # dtype can be the second or third argument to aten::to()
+ if inputs[i].node()["value"] == 5:
+ inputs[i].node().copyAttributes(float_node)
+
+ model.apply(patch_float)
+ patch_float(model.encode_image)
+ patch_float(model.encode_text)
+
+ model.float()
+
+ return model, _transform(model.input_resolution.item())
+
+
+def tokenize(texts: Union[str, List[str]], context_length: int = 77, truncate: bool = False) -> Union[torch.IntTensor, torch.LongTensor]:
+ """
+ Returns the tokenized representation of given input string(s)
+
+ Parameters
+ ----------
+ texts : Union[str, List[str]]
+ An input string or a list of input strings to tokenize
+
+ context_length : int
+ The context length to use; all CLIP models use 77 as the context length
+
+ truncate: bool
+ Whether to truncate the text in case its encoding is longer than the context length
+
+ Returns
+ -------
+ A two-dimensional tensor containing the resulting tokens, shape = [number of input strings, context_length].
+ We return LongTensor when torch version is <1.8.0, since older index_select requires indices to be long.
+ """
+ if isinstance(texts, str):
+ texts = [texts]
+
+ sot_token = _tokenizer.encoder["<|startoftext|>"]
+ eot_token = _tokenizer.encoder["<|endoftext|>"]
+ all_tokens = [[sot_token] + _tokenizer.encode(text) + [eot_token] for text in texts]
+ if packaging.version.parse(torch.__version__) < packaging.version.parse("1.8.0"):
+ result = torch.zeros(len(all_tokens), context_length, dtype=torch.long)
+ else:
+ result = torch.zeros(len(all_tokens), context_length, dtype=torch.int)
+
+ for i, tokens in enumerate(all_tokens):
+ if len(tokens) > context_length:
+ if truncate:
+ tokens = tokens[:context_length]
+ tokens[-1] = eot_token
+ else:
+ raise RuntimeError(f"Input {texts[i]} is too long for context length {context_length}")
+ result[i, :len(tokens)] = torch.tensor(tokens)
+
+ return result
diff --git a/clean/video/univfd_video/models/clip/model.py b/clean/video/univfd_video/models/clip/model.py
new file mode 100644
index 0000000000000000000000000000000000000000..c60bda69ab0d35af0b64517d32595d9c03f8721c
--- /dev/null
+++ b/clean/video/univfd_video/models/clip/model.py
@@ -0,0 +1,452 @@
+from collections import OrderedDict
+from typing import Tuple, Union
+
+import numpy as np
+import torch
+import torch.nn.functional as F
+from torch import nn
+
+
+class Bottleneck(nn.Module):
+ expansion = 4
+
+ def __init__(self, inplanes, planes, stride=1):
+ super().__init__()
+
+ # all conv layers have stride 1. an avgpool is performed after the second convolution when stride > 1
+ self.conv1 = nn.Conv2d(inplanes, planes, 1, bias=False)
+ self.bn1 = nn.BatchNorm2d(planes)
+ self.relu1 = nn.ReLU(inplace=True)
+
+ self.conv2 = nn.Conv2d(planes, planes, 3, padding=1, bias=False)
+ self.bn2 = nn.BatchNorm2d(planes)
+ self.relu2 = nn.ReLU(inplace=True)
+
+ self.avgpool = nn.AvgPool2d(stride) if stride > 1 else nn.Identity()
+
+ self.conv3 = nn.Conv2d(planes, planes * self.expansion, 1, bias=False)
+ self.bn3 = nn.BatchNorm2d(planes * self.expansion)
+ self.relu3 = nn.ReLU(inplace=True)
+
+ self.downsample = None
+ self.stride = stride
+
+ if stride > 1 or inplanes != planes * Bottleneck.expansion:
+ # downsampling layer is prepended with an avgpool, and the subsequent convolution has stride 1
+ self.downsample = nn.Sequential(OrderedDict([
+ ("-1", nn.AvgPool2d(stride)),
+ ("0", nn.Conv2d(inplanes, planes * self.expansion, 1, stride=1, bias=False)),
+ ("1", nn.BatchNorm2d(planes * self.expansion))
+ ]))
+
+ def forward(self, x: torch.Tensor):
+ identity = x
+
+ out = self.relu1(self.bn1(self.conv1(x)))
+ out = self.relu2(self.bn2(self.conv2(out)))
+ out = self.avgpool(out)
+ out = self.bn3(self.conv3(out))
+
+ if self.downsample is not None:
+ identity = self.downsample(x)
+
+ out += identity
+ out = self.relu3(out)
+ return out
+
+
+class AttentionPool2d(nn.Module):
+ def __init__(self, spacial_dim: int, embed_dim: int, num_heads: int, output_dim: int = None):
+ super().__init__()
+ self.positional_embedding = nn.Parameter(torch.randn(spacial_dim ** 2 + 1, embed_dim) / embed_dim ** 0.5)
+ self.k_proj = nn.Linear(embed_dim, embed_dim)
+ self.q_proj = nn.Linear(embed_dim, embed_dim)
+ self.v_proj = nn.Linear(embed_dim, embed_dim)
+ self.c_proj = nn.Linear(embed_dim, output_dim or embed_dim)
+ self.num_heads = num_heads
+
+ def forward(self, x):
+ x = x.flatten(start_dim=2).permute(2, 0, 1) # NCHW -> (HW)NC
+ x = torch.cat([x.mean(dim=0, keepdim=True), x], dim=0) # (HW+1)NC
+ x = x + self.positional_embedding[:, None, :].to(x.dtype) # (HW+1)NC
+ x, _ = F.multi_head_attention_forward(
+ query=x[:1], key=x, value=x,
+ embed_dim_to_check=x.shape[-1],
+ num_heads=self.num_heads,
+ q_proj_weight=self.q_proj.weight,
+ k_proj_weight=self.k_proj.weight,
+ v_proj_weight=self.v_proj.weight,
+ in_proj_weight=None,
+ in_proj_bias=torch.cat([self.q_proj.bias, self.k_proj.bias, self.v_proj.bias]),
+ bias_k=None,
+ bias_v=None,
+ add_zero_attn=False,
+ dropout_p=0,
+ out_proj_weight=self.c_proj.weight,
+ out_proj_bias=self.c_proj.bias,
+ use_separate_proj_weight=True,
+ training=self.training,
+ need_weights=False
+ )
+ return x.squeeze(0)
+
+
+class ModifiedResNet(nn.Module):
+ """
+ A ResNet class that is similar to torchvision's but contains the following changes:
+ - There are now 3 "stem" convolutions as opposed to 1, with an average pool instead of a max pool.
+ - Performs anti-aliasing strided convolutions, where an avgpool is prepended to convolutions with stride > 1
+ - The final pooling layer is a QKV attention instead of an average pool
+ """
+
+ def __init__(self, layers, output_dim, heads, input_resolution=224, width=64):
+ super().__init__()
+ self.output_dim = output_dim
+ self.input_resolution = input_resolution
+
+ # the 3-layer stem
+ self.conv1 = nn.Conv2d(3, width // 2, kernel_size=3, stride=2, padding=1, bias=False)
+ self.bn1 = nn.BatchNorm2d(width // 2)
+ self.relu1 = nn.ReLU(inplace=True)
+ self.conv2 = nn.Conv2d(width // 2, width // 2, kernel_size=3, padding=1, bias=False)
+ self.bn2 = nn.BatchNorm2d(width // 2)
+ self.relu2 = nn.ReLU(inplace=True)
+ self.conv3 = nn.Conv2d(width // 2, width, kernel_size=3, padding=1, bias=False)
+ self.bn3 = nn.BatchNorm2d(width)
+ self.relu3 = nn.ReLU(inplace=True)
+ self.avgpool = nn.AvgPool2d(2)
+
+ # residual layers
+ self._inplanes = width # this is a *mutable* variable used during construction
+ self.layer1 = self._make_layer(width, layers[0])
+ self.layer2 = self._make_layer(width * 2, layers[1], stride=2)
+ self.layer3 = self._make_layer(width * 4, layers[2], stride=2)
+ self.layer4 = self._make_layer(width * 8, layers[3], stride=2)
+
+ embed_dim = width * 32 # the ResNet feature dimension
+ self.attnpool = AttentionPool2d(input_resolution // 32, embed_dim, heads, output_dim)
+
+ def _make_layer(self, planes, blocks, stride=1):
+ layers = [Bottleneck(self._inplanes, planes, stride)]
+
+ self._inplanes = planes * Bottleneck.expansion
+ for _ in range(1, blocks):
+ layers.append(Bottleneck(self._inplanes, planes))
+
+ return nn.Sequential(*layers)
+
+ def forward(self, x):
+ def stem(x):
+ x = self.relu1(self.bn1(self.conv1(x)))
+ x = self.relu2(self.bn2(self.conv2(x)))
+ x = self.relu3(self.bn3(self.conv3(x)))
+ x = self.avgpool(x)
+ return x
+
+ x = x.type(self.conv1.weight.dtype)
+ x = stem(x)
+ x = self.layer1(x)
+ x = self.layer2(x)
+ x = self.layer3(x)
+ x = self.layer4(x)
+ x = self.attnpool(x)
+
+ return x
+
+
+class LayerNorm(nn.LayerNorm):
+ """Subclass torch's LayerNorm to handle fp16."""
+
+ def forward(self, x: torch.Tensor):
+ orig_type = x.dtype
+ ret = super().forward(x.type(torch.float32))
+ return ret.type(orig_type)
+
+
+class QuickGELU(nn.Module):
+ def forward(self, x: torch.Tensor):
+ return x * torch.sigmoid(1.702 * x)
+
+
+class ResidualAttentionBlock(nn.Module):
+ def __init__(self, d_model: int, n_head: int, attn_mask: torch.Tensor = None):
+ super().__init__()
+
+ self.attn = nn.MultiheadAttention(d_model, n_head)
+ self.ln_1 = LayerNorm(d_model)
+ self.mlp = nn.Sequential(OrderedDict([
+ ("c_fc", nn.Linear(d_model, d_model * 4)),
+ ("gelu", QuickGELU()),
+ ("c_proj", nn.Linear(d_model * 4, d_model))
+ ]))
+ self.ln_2 = LayerNorm(d_model)
+ self.attn_mask = attn_mask
+
+ def attention(self, x: torch.Tensor):
+ self.attn_mask = self.attn_mask.to(dtype=x.dtype, device=x.device) if self.attn_mask is not None else None
+ return self.attn(x, x, x, need_weights=False, attn_mask=self.attn_mask)[0]
+
+ def forward(self, x: torch.Tensor):
+ x = x + self.attention(self.ln_1(x))
+ x = x + self.mlp(self.ln_2(x))
+ return x
+
+
+class Transformer(nn.Module):
+ def __init__(self, width: int, layers: int, heads: int, attn_mask: torch.Tensor = None):
+ super().__init__()
+ self.width = width
+ self.layers = layers
+ self.resblocks = nn.Sequential(*[ResidualAttentionBlock(width, heads, attn_mask) for _ in range(layers)])
+
+ def forward(self, x: torch.Tensor):
+ out = {}
+ for idx, layer in enumerate(self.resblocks.children()):
+ x = layer(x)
+ out['layer'+str(idx)] = x[0] # shape:LND. choose cls token feature
+ return out, x
+
+ # return self.resblocks(x) # This is the original code
+
+
+class VisionTransformer(nn.Module):
+ def __init__(self, input_resolution: int, patch_size: int, width: int, layers: int, heads: int, output_dim: int):
+ super().__init__()
+ self.input_resolution = input_resolution
+ self.output_dim = output_dim
+ self.conv1 = nn.Conv2d(in_channels=3, out_channels=width, kernel_size=patch_size, stride=patch_size, bias=False)
+
+ scale = width ** -0.5
+ self.class_embedding = nn.Parameter(scale * torch.randn(width))
+ self.positional_embedding = nn.Parameter(scale * torch.randn((input_resolution // patch_size) ** 2 + 1, width))
+ self.ln_pre = LayerNorm(width)
+
+ self.transformer = Transformer(width, layers, heads)
+
+ self.ln_post = LayerNorm(width)
+ self.proj = nn.Parameter(scale * torch.randn(width, output_dim))
+
+
+
+ def forward(self, x: torch.Tensor):
+ x = self.conv1(x) # shape = [*, width, grid, grid]
+ x = x.reshape(x.shape[0], x.shape[1], -1) # shape = [*, width, grid ** 2]
+ x = x.permute(0, 2, 1) # shape = [*, grid ** 2, width]
+ x = torch.cat([self.class_embedding.to(x.dtype) + torch.zeros(x.shape[0], 1, x.shape[-1], dtype=x.dtype, device=x.device), x], dim=1) # shape = [*, grid ** 2 + 1, width]
+ x = x + self.positional_embedding.to(x.dtype)
+ x = self.ln_pre(x)
+
+ x = x.permute(1, 0, 2) # NLD -> LND
+ out, x = self.transformer(x)
+ x = x.permute(1, 0, 2) # LND -> NLD
+
+ x = self.ln_post(x[:, 0, :])
+
+
+ out['before_projection'] = x
+
+ if self.proj is not None:
+ x = x @ self.proj
+ out['after_projection'] = x
+
+ # Return both intermediate features and final clip feature
+ # return out
+
+ # This only returns CLIP features
+ return x
+
+
+class CLIP(nn.Module):
+ def __init__(self,
+ embed_dim: int,
+ # vision
+ image_resolution: int,
+ vision_layers: Union[Tuple[int, int, int, int], int],
+ vision_width: int,
+ vision_patch_size: int,
+ # text
+ context_length: int,
+ vocab_size: int,
+ transformer_width: int,
+ transformer_heads: int,
+ transformer_layers: int
+ ):
+ super().__init__()
+
+ self.context_length = context_length
+
+ if isinstance(vision_layers, (tuple, list)):
+ vision_heads = vision_width * 32 // 64
+ self.visual = ModifiedResNet(
+ layers=vision_layers,
+ output_dim=embed_dim,
+ heads=vision_heads,
+ input_resolution=image_resolution,
+ width=vision_width
+ )
+ else:
+ vision_heads = vision_width // 64
+ self.visual = VisionTransformer(
+ input_resolution=image_resolution,
+ patch_size=vision_patch_size,
+ width=vision_width,
+ layers=vision_layers,
+ heads=vision_heads,
+ output_dim=embed_dim
+ )
+
+ self.transformer = Transformer(
+ width=transformer_width,
+ layers=transformer_layers,
+ heads=transformer_heads,
+ attn_mask=self.build_attention_mask()
+ )
+
+ self.vocab_size = vocab_size
+ self.token_embedding = nn.Embedding(vocab_size, transformer_width)
+ self.positional_embedding = nn.Parameter(torch.empty(self.context_length, transformer_width))
+ self.ln_final = LayerNorm(transformer_width)
+
+ self.text_projection = nn.Parameter(torch.empty(transformer_width, embed_dim))
+ self.logit_scale = nn.Parameter(torch.ones([]) * np.log(1 / 0.07))
+
+ self.initialize_parameters()
+
+ def initialize_parameters(self):
+ nn.init.normal_(self.token_embedding.weight, std=0.02)
+ nn.init.normal_(self.positional_embedding, std=0.01)
+
+ if isinstance(self.visual, ModifiedResNet):
+ if self.visual.attnpool is not None:
+ std = self.visual.attnpool.c_proj.in_features ** -0.5
+ nn.init.normal_(self.visual.attnpool.q_proj.weight, std=std)
+ nn.init.normal_(self.visual.attnpool.k_proj.weight, std=std)
+ nn.init.normal_(self.visual.attnpool.v_proj.weight, std=std)
+ nn.init.normal_(self.visual.attnpool.c_proj.weight, std=std)
+
+ for resnet_block in [self.visual.layer1, self.visual.layer2, self.visual.layer3, self.visual.layer4]:
+ for name, param in resnet_block.named_parameters():
+ if name.endswith("bn3.weight"):
+ nn.init.zeros_(param)
+
+ proj_std = (self.transformer.width ** -0.5) * ((2 * self.transformer.layers) ** -0.5)
+ attn_std = self.transformer.width ** -0.5
+ fc_std = (2 * self.transformer.width) ** -0.5
+ for block in self.transformer.resblocks:
+ nn.init.normal_(block.attn.in_proj_weight, std=attn_std)
+ nn.init.normal_(block.attn.out_proj.weight, std=proj_std)
+ nn.init.normal_(block.mlp.c_fc.weight, std=fc_std)
+ nn.init.normal_(block.mlp.c_proj.weight, std=proj_std)
+
+ if self.text_projection is not None:
+ nn.init.normal_(self.text_projection, std=self.transformer.width ** -0.5)
+
+ def build_attention_mask(self):
+ # lazily create causal attention mask, with full attention between the vision tokens
+ # pytorch uses additive attention mask; fill with -inf
+ mask = torch.empty(self.context_length, self.context_length)
+ mask.fill_(float("-inf"))
+ mask.triu_(1) # zero out the lower diagonal
+ return mask
+
+ @property
+ def dtype(self):
+ return self.visual.conv1.weight.dtype
+
+ def encode_image(self, image):
+ return self.visual(image.type(self.dtype))
+
+ def encode_text(self, text):
+ x = self.token_embedding(text).type(self.dtype) # [batch_size, n_ctx, d_model]
+
+ x = x + self.positional_embedding.type(self.dtype)
+ x = x.permute(1, 0, 2) # NLD -> LND
+ x = self.transformer(x)
+ x = x.permute(1, 0, 2) # LND -> NLD
+ x = self.ln_final(x).type(self.dtype)
+
+ # x.shape = [batch_size, n_ctx, transformer.width]
+ # take features from the eot embedding (eot_token is the highest number in each sequence)
+ x = x[torch.arange(x.shape[0]), text.argmax(dim=-1)] @ self.text_projection
+
+ return x
+
+ def forward(self, image, text):
+ image_features = self.encode_image(image)
+ text_features = self.encode_text(text)
+
+ # normalized features
+ image_features = image_features / image_features.norm(dim=1, keepdim=True)
+ text_features = text_features / text_features.norm(dim=1, keepdim=True)
+
+ # cosine similarity as logits
+ logit_scale = self.logit_scale.exp()
+ logits_per_image = logit_scale * image_features @ text_features.t()
+ logits_per_text = logits_per_image.t()
+
+ # shape = [global_batch_size, global_batch_size]
+ return logits_per_image, logits_per_text
+
+
+def convert_weights(model: nn.Module):
+ """Convert applicable model parameters to fp16"""
+
+ def _convert_weights_to_fp16(l):
+ if isinstance(l, (nn.Conv1d, nn.Conv2d, nn.Linear)):
+ l.weight.data = l.weight.data.half()
+ if l.bias is not None:
+ l.bias.data = l.bias.data.half()
+
+ if isinstance(l, nn.MultiheadAttention):
+ for attr in [*[f"{s}_proj_weight" for s in ["in", "q", "k", "v"]], "in_proj_bias", "bias_k", "bias_v"]:
+ tensor = getattr(l, attr)
+ if tensor is not None:
+ tensor.data = tensor.data.half()
+
+ for name in ["text_projection", "proj"]:
+ if hasattr(l, name):
+ attr = getattr(l, name)
+ if attr is not None:
+ attr.data = attr.data.half()
+
+ model.apply(_convert_weights_to_fp16)
+
+
+def build_model(state_dict: dict):
+ vit = "visual.proj" in state_dict
+
+ if vit:
+ vision_width = state_dict["visual.conv1.weight"].shape[0]
+ vision_layers = len([k for k in state_dict.keys() if k.startswith("visual.") and k.endswith(".attn.in_proj_weight")])
+ vision_patch_size = state_dict["visual.conv1.weight"].shape[-1]
+ grid_size = round((state_dict["visual.positional_embedding"].shape[0] - 1) ** 0.5)
+ image_resolution = vision_patch_size * grid_size
+ else:
+ counts: list = [len(set(k.split(".")[2] for k in state_dict if k.startswith(f"visual.layer{b}"))) for b in [1, 2, 3, 4]]
+ vision_layers = tuple(counts)
+ vision_width = state_dict["visual.layer1.0.conv1.weight"].shape[0]
+ output_width = round((state_dict["visual.attnpool.positional_embedding"].shape[0] - 1) ** 0.5)
+ vision_patch_size = None
+ assert output_width ** 2 + 1 == state_dict["visual.attnpool.positional_embedding"].shape[0]
+ image_resolution = output_width * 32
+
+ embed_dim = state_dict["text_projection"].shape[1]
+ context_length = state_dict["positional_embedding"].shape[0]
+ vocab_size = state_dict["token_embedding.weight"].shape[0]
+ transformer_width = state_dict["ln_final.weight"].shape[0]
+ transformer_heads = transformer_width // 64
+ transformer_layers = len(set(k.split(".")[2] for k in state_dict if k.startswith("transformer.resblocks")))
+
+ model = CLIP(
+ embed_dim,
+ image_resolution, vision_layers, vision_width, vision_patch_size,
+ context_length, vocab_size, transformer_width, transformer_heads, transformer_layers
+ )
+
+ for key in ["input_resolution", "context_length", "vocab_size"]:
+ if key in state_dict:
+ del state_dict[key]
+
+ convert_weights(model)
+ model.load_state_dict(state_dict)
+ return model.eval()
diff --git a/clean/video/univfd_video/models/clip/simple_tokenizer.py b/clean/video/univfd_video/models/clip/simple_tokenizer.py
new file mode 100644
index 0000000000000000000000000000000000000000..0a66286b7d5019c6e221932a813768038f839c91
--- /dev/null
+++ b/clean/video/univfd_video/models/clip/simple_tokenizer.py
@@ -0,0 +1,132 @@
+import gzip
+import html
+import os
+from functools import lru_cache
+
+import ftfy
+import regex as re
+
+
+@lru_cache()
+def default_bpe():
+ return os.path.join(os.path.dirname(os.path.abspath(__file__)), "bpe_simple_vocab_16e6.txt.gz")
+
+
+@lru_cache()
+def bytes_to_unicode():
+ """
+ Returns list of utf-8 byte and a corresponding list of unicode strings.
+ The reversible bpe codes work on unicode strings.
+ This means you need a large # of unicode characters in your vocab if you want to avoid UNKs.
+ When you're at something like a 10B token dataset you end up needing around 5K for decent coverage.
+ This is a signficant percentage of your normal, say, 32K bpe vocab.
+ To avoid that, we want lookup tables between utf-8 bytes and unicode strings.
+ And avoids mapping to whitespace/control characters the bpe code barfs on.
+ """
+ bs = list(range(ord("!"), ord("~")+1))+list(range(ord("¡"), ord("¬")+1))+list(range(ord("®"), ord("ÿ")+1))
+ cs = bs[:]
+ n = 0
+ for b in range(2**8):
+ if b not in bs:
+ bs.append(b)
+ cs.append(2**8+n)
+ n += 1
+ cs = [chr(n) for n in cs]
+ return dict(zip(bs, cs))
+
+
+def get_pairs(word):
+ """Return set of symbol pairs in a word.
+ Word is represented as tuple of symbols (symbols being variable-length strings).
+ """
+ pairs = set()
+ prev_char = word[0]
+ for char in word[1:]:
+ pairs.add((prev_char, char))
+ prev_char = char
+ return pairs
+
+
+def basic_clean(text):
+ text = ftfy.fix_text(text)
+ text = html.unescape(html.unescape(text))
+ return text.strip()
+
+
+def whitespace_clean(text):
+ text = re.sub(r'\s+', ' ', text)
+ text = text.strip()
+ return text
+
+
+class SimpleTokenizer(object):
+ def __init__(self, bpe_path: str = default_bpe()):
+ self.byte_encoder = bytes_to_unicode()
+ self.byte_decoder = {v: k for k, v in self.byte_encoder.items()}
+ merges = gzip.open(bpe_path).read().decode("utf-8").split('\n')
+ merges = merges[1:49152-256-2+1]
+ merges = [tuple(merge.split()) for merge in merges]
+ vocab = list(bytes_to_unicode().values())
+ vocab = vocab + [v+'' for v in vocab]
+ for merge in merges:
+ vocab.append(''.join(merge))
+ vocab.extend(['<|startoftext|>', '<|endoftext|>'])
+ self.encoder = dict(zip(vocab, range(len(vocab))))
+ self.decoder = {v: k for k, v in self.encoder.items()}
+ self.bpe_ranks = dict(zip(merges, range(len(merges))))
+ self.cache = {'<|startoftext|>': '<|startoftext|>', '<|endoftext|>': '<|endoftext|>'}
+ self.pat = re.compile(r"""<\|startoftext\|>|<\|endoftext\|>|'s|'t|'re|'ve|'m|'ll|'d|[\p{L}]+|[\p{N}]|[^\s\p{L}\p{N}]+""", re.IGNORECASE)
+
+ def bpe(self, token):
+ if token in self.cache:
+ return self.cache[token]
+ word = tuple(token[:-1]) + ( token[-1] + '',)
+ pairs = get_pairs(word)
+
+ if not pairs:
+ return token+''
+
+ while True:
+ bigram = min(pairs, key = lambda pair: self.bpe_ranks.get(pair, float('inf')))
+ if bigram not in self.bpe_ranks:
+ break
+ first, second = bigram
+ new_word = []
+ i = 0
+ while i < len(word):
+ try:
+ j = word.index(first, i)
+ new_word.extend(word[i:j])
+ i = j
+ except:
+ new_word.extend(word[i:])
+ break
+
+ if word[i] == first and i < len(word)-1 and word[i+1] == second:
+ new_word.append(first+second)
+ i += 2
+ else:
+ new_word.append(word[i])
+ i += 1
+ new_word = tuple(new_word)
+ word = new_word
+ if len(word) == 1:
+ break
+ else:
+ pairs = get_pairs(word)
+ word = ' '.join(word)
+ self.cache[token] = word
+ return word
+
+ def encode(self, text):
+ bpe_tokens = []
+ text = whitespace_clean(basic_clean(text)).lower()
+ for token in re.findall(self.pat, text):
+ token = ''.join(self.byte_encoder[b] for b in token.encode('utf-8'))
+ bpe_tokens.extend(self.encoder[bpe_token] for bpe_token in self.bpe(token).split(' '))
+ return bpe_tokens
+
+ def decode(self, tokens):
+ text = ''.join([self.decoder[token] for token in tokens])
+ text = bytearray([self.byte_decoder[c] for c in text]).decode('utf-8', errors="replace").replace('', ' ')
+ return text
diff --git a/clean/video/univfd_video/models/clip_models.py b/clean/video/univfd_video/models/clip_models.py
new file mode 100644
index 0000000000000000000000000000000000000000..44de4db8ee4dd77690970fc76eb671b1b3a43882
--- /dev/null
+++ b/clean/video/univfd_video/models/clip_models.py
@@ -0,0 +1,24 @@
+from .clip import clip
+from PIL import Image
+import torch.nn as nn
+
+
+CHANNELS = {
+ "RN50" : 1024,
+ "ViT-L/14" : 768
+}
+
+class CLIPModel(nn.Module):
+ def __init__(self, name, num_classes=1):
+ super(CLIPModel, self).__init__()
+
+ self.model, self.preprocess = clip.load(name, device="cpu") # self.preprecess will not be used during training, which is handled in Dataset class
+ self.fc = nn.Linear( CHANNELS[name], num_classes )
+
+
+ def forward(self, x, return_feature=False):
+ features = self.model.encode_image(x)
+ if return_feature:
+ return features
+ return self.fc(features)
+
diff --git a/clean/video/univfd_video/models/imagenet_models.py b/clean/video/univfd_video/models/imagenet_models.py
new file mode 100644
index 0000000000000000000000000000000000000000..20a40b916793d926c915aa2f62602651613fec04
--- /dev/null
+++ b/clean/video/univfd_video/models/imagenet_models.py
@@ -0,0 +1,40 @@
+from .resnet import resnet18, resnet34, resnet50, resnet101, resnet152
+from .vision_transformer import vit_b_16, vit_b_32, vit_l_16, vit_l_32
+
+from torchvision import transforms
+from PIL import Image
+import torch
+import torch.nn as nn
+
+
+model_dict = {
+ 'resnet18': resnet18,
+ 'resnet34': resnet34,
+ 'resnet50': resnet50,
+ 'resnet101': resnet101,
+ 'resnet152': resnet152,
+ 'vit_b_16': vit_b_16,
+ 'vit_b_32': vit_b_32,
+ 'vit_l_16': vit_l_16,
+ 'vit_l_32': vit_l_32
+}
+
+
+CHANNELS = {
+ "resnet50" : 2048,
+ "vit_b_16" : 768,
+}
+
+
+
+class ImagenetModel(nn.Module):
+ def __init__(self, name, num_classes=1):
+ super(ImagenetModel, self).__init__()
+
+ self.model = model_dict[name](pretrained=True)
+ self.fc = nn.Linear(CHANNELS[name], num_classes) #manually define a fc layer here
+
+
+ def forward(self, x):
+ feature = self.model(x)["penultimate"]
+ return self.fc(feature)
diff --git a/clean/video/univfd_video/models/resnet.py b/clean/video/univfd_video/models/resnet.py
new file mode 100644
index 0000000000000000000000000000000000000000..a78e3d65e263cb9dbd1afa0e1a88dba9f5ddd164
--- /dev/null
+++ b/clean/video/univfd_video/models/resnet.py
@@ -0,0 +1,337 @@
+import torch
+from torch import Tensor
+import torch.nn as nn
+from typing import Type, Any, Callable, Union, List, Optional
+
+try:
+ from torch.hub import load_state_dict_from_url
+except ImportError:
+ from torch.utils.model_zoo import load_url as load_state_dict_from_url
+
+
+model_urls = {
+ 'resnet18': 'https://download.pytorch.org/models/resnet18-f37072fd.pth',
+ 'resnet34': 'https://download.pytorch.org/models/resnet34-b627a593.pth',
+ 'resnet50': 'https://download.pytorch.org/models/resnet50-0676ba61.pth',
+ 'resnet101': 'https://download.pytorch.org/models/resnet101-63fe2227.pth',
+ 'resnet152': 'https://download.pytorch.org/models/resnet152-394f9c45.pth',
+ 'resnext50_32x4d': 'https://download.pytorch.org/models/resnext50_32x4d-7cdf4587.pth',
+ 'resnext101_32x8d': 'https://download.pytorch.org/models/resnext101_32x8d-8ba56ff5.pth',
+ 'wide_resnet50_2': 'https://download.pytorch.org/models/wide_resnet50_2-95faca4d.pth',
+ 'wide_resnet101_2': 'https://download.pytorch.org/models/wide_resnet101_2-32ee1156.pth',
+}
+
+
+
+
+def conv3x3(in_planes: int, out_planes: int, stride: int = 1, groups: int = 1, dilation: int = 1) -> nn.Conv2d:
+ """3x3 convolution with padding"""
+ return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,
+ padding=dilation, groups=groups, bias=False, dilation=dilation)
+
+
+def conv1x1(in_planes: int, out_planes: int, stride: int = 1) -> nn.Conv2d:
+ """1x1 convolution"""
+ return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False)
+
+
+class BasicBlock(nn.Module):
+ expansion: int = 1
+
+ def __init__(
+ self,
+ inplanes: int,
+ planes: int,
+ stride: int = 1,
+ downsample: Optional[nn.Module] = None,
+ groups: int = 1,
+ base_width: int = 64,
+ dilation: int = 1,
+ norm_layer: Optional[Callable[..., nn.Module]] = None
+ ) -> None:
+ super(BasicBlock, self).__init__()
+ if norm_layer is None:
+ norm_layer = nn.BatchNorm2d
+ if groups != 1 or base_width != 64:
+ raise ValueError('BasicBlock only supports groups=1 and base_width=64')
+ if dilation > 1:
+ raise NotImplementedError("Dilation > 1 not supported in BasicBlock")
+ # Both self.conv1 and self.downsample layers downsample the input when stride != 1
+ self.conv1 = conv3x3(inplanes, planes, stride)
+ self.bn1 = norm_layer(planes)
+ self.relu = nn.ReLU(inplace=True)
+ self.conv2 = conv3x3(planes, planes)
+ self.bn2 = norm_layer(planes)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x: Tensor) -> Tensor:
+ identity = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+
+ if self.downsample is not None:
+ identity = self.downsample(x)
+
+ out += identity
+ out = self.relu(out)
+
+ return out
+
+
+class Bottleneck(nn.Module):
+ # Bottleneck in torchvision places the stride for downsampling at 3x3 convolution(self.conv2)
+ # while original implementation places the stride at the first 1x1 convolution(self.conv1)
+ # according to "Deep residual learning for image recognition"https://arxiv.org/abs/1512.03385.
+ # This variant is also known as ResNet V1.5 and improves accuracy according to
+ # https://ngc.nvidia.com/catalog/model-scripts/nvidia:resnet_50_v1_5_for_pytorch.
+
+ expansion: int = 4
+
+ def __init__(
+ self,
+ inplanes: int,
+ planes: int,
+ stride: int = 1,
+ downsample: Optional[nn.Module] = None,
+ groups: int = 1,
+ base_width: int = 64,
+ dilation: int = 1,
+ norm_layer: Optional[Callable[..., nn.Module]] = None
+ ) -> None:
+ super(Bottleneck, self).__init__()
+ if norm_layer is None:
+ norm_layer = nn.BatchNorm2d
+ width = int(planes * (base_width / 64.)) * groups
+ # Both self.conv2 and self.downsample layers downsample the input when stride != 1
+ self.conv1 = conv1x1(inplanes, width)
+ self.bn1 = norm_layer(width)
+ self.conv2 = conv3x3(width, width, stride, groups, dilation)
+ self.bn2 = norm_layer(width)
+ self.conv3 = conv1x1(width, planes * self.expansion)
+ self.bn3 = norm_layer(planes * self.expansion)
+ self.relu = nn.ReLU(inplace=True)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x: Tensor) -> Tensor:
+ identity = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+ out = self.relu(out)
+
+ out = self.conv3(out)
+ out = self.bn3(out)
+
+ if self.downsample is not None:
+ identity = self.downsample(x)
+
+ out += identity
+ out = self.relu(out)
+
+ return out
+
+
+class ResNet(nn.Module):
+
+ def __init__(
+ self,
+ block: Type[Union[BasicBlock, Bottleneck]],
+ layers: List[int],
+ num_classes: int = 1000,
+ zero_init_residual: bool = False,
+ groups: int = 1,
+ width_per_group: int = 64,
+ replace_stride_with_dilation: Optional[List[bool]] = None,
+ norm_layer: Optional[Callable[..., nn.Module]] = None
+ ) -> None:
+ super(ResNet, self).__init__()
+ if norm_layer is None:
+ norm_layer = nn.BatchNorm2d
+ self._norm_layer = norm_layer
+
+ self.inplanes = 64
+ self.dilation = 1
+ if replace_stride_with_dilation is None:
+ # each element in the tuple indicates if we should replace
+ # the 2x2 stride with a dilated convolution instead
+ replace_stride_with_dilation = [False, False, False]
+ if len(replace_stride_with_dilation) != 3:
+ raise ValueError("replace_stride_with_dilation should be None "
+ "or a 3-element tuple, got {}".format(replace_stride_with_dilation))
+ self.groups = groups
+ self.base_width = width_per_group
+ self.conv1 = nn.Conv2d(3, self.inplanes, kernel_size=7, stride=2, padding=3,
+ bias=False)
+ self.bn1 = norm_layer(self.inplanes)
+ self.relu = nn.ReLU(inplace=True)
+ self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
+ self.layer1 = self._make_layer(block, 64, layers[0])
+ self.layer2 = self._make_layer(block, 128, layers[1], stride=2,
+ dilate=replace_stride_with_dilation[0])
+ self.layer3 = self._make_layer(block, 256, layers[2], stride=2,
+ dilate=replace_stride_with_dilation[1])
+ self.layer4 = self._make_layer(block, 512, layers[3], stride=2,
+ dilate=replace_stride_with_dilation[2])
+ self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
+ self.fc = nn.Linear(512 * block.expansion, num_classes)
+
+ for m in self.modules():
+ if isinstance(m, nn.Conv2d):
+ nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
+ elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
+ nn.init.constant_(m.weight, 1)
+ nn.init.constant_(m.bias, 0)
+
+ # Zero-initialize the last BN in each residual branch,
+ # so that the residual branch starts with zeros, and each residual block behaves like an identity.
+ # This improves the model by 0.2~0.3% according to https://arxiv.org/abs/1706.02677
+ if zero_init_residual:
+ for m in self.modules():
+ if isinstance(m, Bottleneck):
+ nn.init.constant_(m.bn3.weight, 0) # type: ignore[arg-type]
+ elif isinstance(m, BasicBlock):
+ nn.init.constant_(m.bn2.weight, 0) # type: ignore[arg-type]
+
+ def _make_layer(self, block: Type[Union[BasicBlock, Bottleneck]], planes: int, blocks: int,
+ stride: int = 1, dilate: bool = False) -> nn.Sequential:
+ norm_layer = self._norm_layer
+ downsample = None
+ previous_dilation = self.dilation
+ if dilate:
+ self.dilation *= stride
+ stride = 1
+ if stride != 1 or self.inplanes != planes * block.expansion:
+ downsample = nn.Sequential(
+ conv1x1(self.inplanes, planes * block.expansion, stride),
+ norm_layer(planes * block.expansion),
+ )
+
+ layers = []
+ layers.append(block(self.inplanes, planes, stride, downsample, self.groups,
+ self.base_width, previous_dilation, norm_layer))
+ self.inplanes = planes * block.expansion
+ for _ in range(1, blocks):
+ layers.append(block(self.inplanes, planes, groups=self.groups,
+ base_width=self.base_width, dilation=self.dilation,
+ norm_layer=norm_layer))
+
+ return nn.Sequential(*layers)
+
+ def _forward_impl(self, x):
+ # The comment resolution is based on input size is 224*224 imagenet
+ out = {}
+ x = self.conv1(x)
+ x = self.bn1(x)
+ x = self.relu(x)
+ x = self.maxpool(x)
+ out['f0'] = x # N*64*56*56
+
+ x = self.layer1(x)
+ out['f1'] = x # N*64*56*56
+
+ x = self.layer2(x)
+ out['f2'] = x # N*128*28*28
+
+ x = self.layer3(x)
+ out['f3'] = x # N*256*14*14
+
+ x = self.layer4(x)
+ out['f4'] = x # N*512*7*7
+
+ x = self.avgpool(x)
+ x = torch.flatten(x, 1)
+ out['penultimate'] = x # N*512
+
+ x = self.fc(x)
+ out['logits'] = x # N*1000
+
+ # return all features
+ return out
+
+ # return final classification result
+ # return x
+
+ def forward(self, x):
+ return self._forward_impl(x)
+
+
+def _resnet(
+ arch: str,
+ block: Type[Union[BasicBlock, Bottleneck]],
+ layers: List[int],
+ pretrained: bool,
+ progress: bool,
+ **kwargs: Any
+) -> ResNet:
+ model = ResNet(block, layers, **kwargs)
+ if pretrained:
+ state_dict = load_state_dict_from_url(model_urls[arch], progress=progress)
+ model.load_state_dict(state_dict)
+ return model
+
+
+def resnet18(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> ResNet:
+ r"""ResNet-18 model from
+ `"Deep Residual Learning for Image Recognition" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return _resnet('resnet18', BasicBlock, [2, 2, 2, 2], pretrained, progress, **kwargs)
+
+
+def resnet34(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> ResNet:
+ r"""ResNet-34 model from
+ `"Deep Residual Learning for Image Recognition" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return _resnet('resnet34', BasicBlock, [3, 4, 6, 3], pretrained, progress, **kwargs)
+
+
+def resnet50(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> ResNet:
+ r"""ResNet-50 model from
+ `"Deep Residual Learning for Image Recognition" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return _resnet('resnet50', Bottleneck, [3, 4, 6, 3], pretrained, progress, **kwargs)
+
+
+def resnet101(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> ResNet:
+ r"""ResNet-101 model from
+ `"Deep Residual Learning for Image Recognition" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return _resnet('resnet101', Bottleneck, [3, 4, 23, 3], pretrained, progress, **kwargs)
+
+
+def resnet152(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> ResNet:
+ r"""ResNet-152 model from
+ `"Deep Residual Learning for Image Recognition" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return _resnet('resnet152', Bottleneck, [3, 8, 36, 3], pretrained, progress, **kwargs)
+
diff --git a/clean/video/univfd_video/models/vgg.py b/clean/video/univfd_video/models/vgg.py
new file mode 100644
index 0000000000000000000000000000000000000000..a30a1df18a64f9ab2ca309b264cd4e8409b0cf64
--- /dev/null
+++ b/clean/video/univfd_video/models/vgg.py
@@ -0,0 +1,120 @@
+import torch
+import torch.nn as nn
+from typing import Union, List, Dict, Any, cast
+import torchvision
+import torch.nn.functional as F
+
+
+
+
+
+class VGG(torch.nn.Module):
+ def __init__(self, arch_type, pretrained, progress):
+ super().__init__()
+
+ self.layer1 = torch.nn.Sequential()
+ self.layer2 = torch.nn.Sequential()
+ self.layer3 = torch.nn.Sequential()
+ self.layer4 = torch.nn.Sequential()
+ self.layer5 = torch.nn.Sequential()
+
+ if arch_type == 'vgg11':
+ official_vgg = torchvision.models.vgg11(pretrained=pretrained, progress=progress)
+ blocks = [ [0,2], [2,5], [5,10], [10,15], [15,20] ]
+ last_idx = 20
+ elif arch_type == 'vgg19':
+ official_vgg = torchvision.models.vgg19(pretrained=pretrained, progress=progress)
+ blocks = [ [0,4], [4,9], [9,18], [18,27], [27,36] ]
+ last_idx = 36
+ else:
+ raise NotImplementedError
+
+
+ for x in range( *blocks[0] ):
+ self.layer1.add_module(str(x), official_vgg.features[x])
+ for x in range( *blocks[1] ):
+ self.layer2.add_module(str(x), official_vgg.features[x])
+ for x in range( *blocks[2] ):
+ self.layer3.add_module(str(x), official_vgg.features[x])
+ for x in range( *blocks[3] ):
+ self.layer4.add_module(str(x), official_vgg.features[x])
+ for x in range( *blocks[4] ):
+ self.layer5.add_module(str(x), official_vgg.features[x])
+
+ self.max_pool = official_vgg.features[last_idx]
+ self.avgpool = nn.AdaptiveAvgPool2d((7, 7))
+
+ self.fc1 = official_vgg.classifier[0]
+ self.fc2 = official_vgg.classifier[3]
+ self.fc3 = official_vgg.classifier[6]
+ self.dropout = nn.Dropout()
+
+
+ def forward(self, x):
+ out = {}
+
+ x = self.layer1(x)
+ out['f0'] = x
+
+ x = self.layer2(x)
+ out['f1'] = x
+
+ x = self.layer3(x)
+ out['f2'] = x
+
+ x = self.layer4(x)
+ out['f3'] = x
+
+ x = self.layer5(x)
+ out['f4'] = x
+
+ x = self.max_pool(x)
+ x = self.avgpool(x)
+ x = x.view(-1,512*7*7)
+
+ x = self.fc1(x)
+ x = F.relu(x)
+ x = self.dropout(x)
+ x = self.fc2(x)
+ x = F.relu(x)
+ out['penultimate'] = x
+ x = self.dropout(x)
+ x = self.fc3(x)
+ out['logits'] = x
+
+ return out
+
+
+
+
+
+
+
+
+
+
+def vgg11(pretrained=False, progress=True):
+ r"""VGG 11-layer model (configuration "A") from
+ `"Very Deep Convolutional Networks For Large-Scale Image Recognition" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return VGG('vgg11', pretrained, progress)
+
+
+
+def vgg19(pretrained=False, progress=True):
+ r"""VGG 19-layer model (configuration "E")
+ `"Very Deep Convolutional Networks For Large-Scale Image Recognition" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return VGG('vgg19', pretrained, progress)
+
+
+
+
diff --git a/clean/video/univfd_video/models/vision_transformer.py b/clean/video/univfd_video/models/vision_transformer.py
new file mode 100644
index 0000000000000000000000000000000000000000..618e9626ca43f1afdb3419e19be11f3a3048f81e
--- /dev/null
+++ b/clean/video/univfd_video/models/vision_transformer.py
@@ -0,0 +1,481 @@
+import math
+from collections import OrderedDict
+from functools import partial
+from typing import Any, Callable, List, NamedTuple, Optional
+
+import torch
+import torch.nn as nn
+
+# from .._internally_replaced_utils import load_state_dict_from_url
+from .vision_transformer_misc import ConvNormActivation
+from .vision_transformer_utils import _log_api_usage_once
+
+try:
+ from torch.hub import load_state_dict_from_url
+except ImportError:
+ from torch.utils.model_zoo import load_url as load_state_dict_from_url
+
+# __all__ = [
+# "VisionTransformer",
+# "vit_b_16",
+# "vit_b_32",
+# "vit_l_16",
+# "vit_l_32",
+# ]
+
+model_urls = {
+ "vit_b_16": "https://download.pytorch.org/models/vit_b_16-c867db91.pth",
+ "vit_b_32": "https://download.pytorch.org/models/vit_b_32-d86f8d99.pth",
+ "vit_l_16": "https://download.pytorch.org/models/vit_l_16-852ce7e3.pth",
+ "vit_l_32": "https://download.pytorch.org/models/vit_l_32-c7638314.pth",
+}
+
+
+class ConvStemConfig(NamedTuple):
+ out_channels: int
+ kernel_size: int
+ stride: int
+ norm_layer: Callable[..., nn.Module] = nn.BatchNorm2d
+ activation_layer: Callable[..., nn.Module] = nn.ReLU
+
+
+class MLPBlock(nn.Sequential):
+ """Transformer MLP block."""
+
+ def __init__(self, in_dim: int, mlp_dim: int, dropout: float):
+ super().__init__()
+ self.linear_1 = nn.Linear(in_dim, mlp_dim)
+ self.act = nn.GELU()
+ self.dropout_1 = nn.Dropout(dropout)
+ self.linear_2 = nn.Linear(mlp_dim, in_dim)
+ self.dropout_2 = nn.Dropout(dropout)
+
+ nn.init.xavier_uniform_(self.linear_1.weight)
+ nn.init.xavier_uniform_(self.linear_2.weight)
+ nn.init.normal_(self.linear_1.bias, std=1e-6)
+ nn.init.normal_(self.linear_2.bias, std=1e-6)
+
+
+class EncoderBlock(nn.Module):
+ """Transformer encoder block."""
+
+ def __init__(
+ self,
+ num_heads: int,
+ hidden_dim: int,
+ mlp_dim: int,
+ dropout: float,
+ attention_dropout: float,
+ norm_layer: Callable[..., torch.nn.Module] = partial(nn.LayerNorm, eps=1e-6),
+ ):
+ super().__init__()
+ self.num_heads = num_heads
+
+ # Attention block
+ self.ln_1 = norm_layer(hidden_dim)
+ self.self_attention = nn.MultiheadAttention(hidden_dim, num_heads, dropout=attention_dropout, batch_first=True)
+ self.dropout = nn.Dropout(dropout)
+
+ # MLP block
+ self.ln_2 = norm_layer(hidden_dim)
+ self.mlp = MLPBlock(hidden_dim, mlp_dim, dropout)
+
+ def forward(self, input: torch.Tensor):
+ torch._assert(input.dim() == 3, f"Expected (seq_length, batch_size, hidden_dim) got {input.shape}")
+ x = self.ln_1(input)
+ x, _ = self.self_attention(query=x, key=x, value=x, need_weights=False)
+ x = self.dropout(x)
+ x = x + input
+
+ y = self.ln_2(x)
+ y = self.mlp(y)
+ return x + y
+
+
+class Encoder(nn.Module):
+ """Transformer Model Encoder for sequence to sequence translation."""
+
+ def __init__(
+ self,
+ seq_length: int,
+ num_layers: int,
+ num_heads: int,
+ hidden_dim: int,
+ mlp_dim: int,
+ dropout: float,
+ attention_dropout: float,
+ norm_layer: Callable[..., torch.nn.Module] = partial(nn.LayerNorm, eps=1e-6),
+ ):
+ super().__init__()
+ # Note that batch_size is on the first dim because
+ # we have batch_first=True in nn.MultiAttention() by default
+ self.pos_embedding = nn.Parameter(torch.empty(1, seq_length, hidden_dim).normal_(std=0.02)) # from BERT
+ self.dropout = nn.Dropout(dropout)
+ layers: OrderedDict[str, nn.Module] = OrderedDict()
+ for i in range(num_layers):
+ layers[f"encoder_layer_{i}"] = EncoderBlock(
+ num_heads,
+ hidden_dim,
+ mlp_dim,
+ dropout,
+ attention_dropout,
+ norm_layer,
+ )
+ self.layers = nn.Sequential(layers)
+ self.ln = norm_layer(hidden_dim)
+
+ def forward(self, input: torch.Tensor):
+ torch._assert(input.dim() == 3, f"Expected (batch_size, seq_length, hidden_dim) got {input.shape}")
+ input = input + self.pos_embedding
+ return self.ln(self.layers(self.dropout(input)))
+
+
+class VisionTransformer(nn.Module):
+ """Vision Transformer as per https://arxiv.org/abs/2010.11929."""
+
+ def __init__(
+ self,
+ image_size: int,
+ patch_size: int,
+ num_layers: int,
+ num_heads: int,
+ hidden_dim: int,
+ mlp_dim: int,
+ dropout: float = 0.0,
+ attention_dropout: float = 0.0,
+ num_classes: int = 1000,
+ representation_size: Optional[int] = None,
+ norm_layer: Callable[..., torch.nn.Module] = partial(nn.LayerNorm, eps=1e-6),
+ conv_stem_configs: Optional[List[ConvStemConfig]] = None,
+ ):
+ super().__init__()
+ _log_api_usage_once(self)
+ torch._assert(image_size % patch_size == 0, "Input shape indivisible by patch size!")
+ self.image_size = image_size
+ self.patch_size = patch_size
+ self.hidden_dim = hidden_dim
+ self.mlp_dim = mlp_dim
+ self.attention_dropout = attention_dropout
+ self.dropout = dropout
+ self.num_classes = num_classes
+ self.representation_size = representation_size
+ self.norm_layer = norm_layer
+
+ if conv_stem_configs is not None:
+ # As per https://arxiv.org/abs/2106.14881
+ seq_proj = nn.Sequential()
+ prev_channels = 3
+ for i, conv_stem_layer_config in enumerate(conv_stem_configs):
+ seq_proj.add_module(
+ f"conv_bn_relu_{i}",
+ ConvNormActivation(
+ in_channels=prev_channels,
+ out_channels=conv_stem_layer_config.out_channels,
+ kernel_size=conv_stem_layer_config.kernel_size,
+ stride=conv_stem_layer_config.stride,
+ norm_layer=conv_stem_layer_config.norm_layer,
+ activation_layer=conv_stem_layer_config.activation_layer,
+ ),
+ )
+ prev_channels = conv_stem_layer_config.out_channels
+ seq_proj.add_module(
+ "conv_last", nn.Conv2d(in_channels=prev_channels, out_channels=hidden_dim, kernel_size=1)
+ )
+ self.conv_proj: nn.Module = seq_proj
+ else:
+ self.conv_proj = nn.Conv2d(
+ in_channels=3, out_channels=hidden_dim, kernel_size=patch_size, stride=patch_size
+ )
+
+ seq_length = (image_size // patch_size) ** 2
+
+ # Add a class token
+ self.class_token = nn.Parameter(torch.zeros(1, 1, hidden_dim))
+ seq_length += 1
+
+ self.encoder = Encoder(
+ seq_length,
+ num_layers,
+ num_heads,
+ hidden_dim,
+ mlp_dim,
+ dropout,
+ attention_dropout,
+ norm_layer,
+ )
+ self.seq_length = seq_length
+
+ heads_layers: OrderedDict[str, nn.Module] = OrderedDict()
+ if representation_size is None:
+ heads_layers["head"] = nn.Linear(hidden_dim, num_classes)
+ else:
+ heads_layers["pre_logits"] = nn.Linear(hidden_dim, representation_size)
+ heads_layers["act"] = nn.Tanh()
+ heads_layers["head"] = nn.Linear(representation_size, num_classes)
+
+ self.heads = nn.Sequential(heads_layers)
+
+ if isinstance(self.conv_proj, nn.Conv2d):
+ # Init the patchify stem
+ fan_in = self.conv_proj.in_channels * self.conv_proj.kernel_size[0] * self.conv_proj.kernel_size[1]
+ nn.init.trunc_normal_(self.conv_proj.weight, std=math.sqrt(1 / fan_in))
+ if self.conv_proj.bias is not None:
+ nn.init.zeros_(self.conv_proj.bias)
+ elif self.conv_proj.conv_last is not None and isinstance(self.conv_proj.conv_last, nn.Conv2d):
+ # Init the last 1x1 conv of the conv stem
+ nn.init.normal_(
+ self.conv_proj.conv_last.weight, mean=0.0, std=math.sqrt(2.0 / self.conv_proj.conv_last.out_channels)
+ )
+ if self.conv_proj.conv_last.bias is not None:
+ nn.init.zeros_(self.conv_proj.conv_last.bias)
+
+ if hasattr(self.heads, "pre_logits") and isinstance(self.heads.pre_logits, nn.Linear):
+ fan_in = self.heads.pre_logits.in_features
+ nn.init.trunc_normal_(self.heads.pre_logits.weight, std=math.sqrt(1 / fan_in))
+ nn.init.zeros_(self.heads.pre_logits.bias)
+
+ if isinstance(self.heads.head, nn.Linear):
+ nn.init.zeros_(self.heads.head.weight)
+ nn.init.zeros_(self.heads.head.bias)
+
+ def _process_input(self, x: torch.Tensor) -> torch.Tensor:
+ n, c, h, w = x.shape
+ p = self.patch_size
+ torch._assert(h == self.image_size, "Wrong image height!")
+ torch._assert(w == self.image_size, "Wrong image width!")
+ n_h = h // p
+ n_w = w // p
+
+ # (n, c, h, w) -> (n, hidden_dim, n_h, n_w)
+ x = self.conv_proj(x)
+ # (n, hidden_dim, n_h, n_w) -> (n, hidden_dim, (n_h * n_w))
+ x = x.reshape(n, self.hidden_dim, n_h * n_w)
+
+ # (n, hidden_dim, (n_h * n_w)) -> (n, (n_h * n_w), hidden_dim)
+ # The self attention layer expects inputs in the format (N, S, E)
+ # where S is the source sequence length, N is the batch size, E is the
+ # embedding dimension
+ x = x.permute(0, 2, 1)
+
+ return x
+
+ def forward(self, x: torch.Tensor):
+ out = {}
+
+ # Reshape and permute the input tensor
+ x = self._process_input(x)
+ n = x.shape[0]
+
+ # Expand the class token to the full batch
+ batch_class_token = self.class_token.expand(n, -1, -1)
+ x = torch.cat([batch_class_token, x], dim=1)
+
+
+ x = self.encoder(x)
+ img_feature = x[:,1:]
+ H = W = int(self.image_size / self.patch_size)
+ out['f4'] = img_feature.view(n, H, W, self.hidden_dim).permute(0,3,1,2)
+
+ # Classifier "token" as used by standard language architectures
+ x = x[:, 0]
+ out['penultimate'] = x
+
+ x = self.heads(x) # I checked that for all pretrained ViT, this is just a fc
+ out['logits'] = x
+
+ return out
+
+
+def _vision_transformer(
+ arch: str,
+ patch_size: int,
+ num_layers: int,
+ num_heads: int,
+ hidden_dim: int,
+ mlp_dim: int,
+ pretrained: bool,
+ progress: bool,
+ **kwargs: Any,
+) -> VisionTransformer:
+ image_size = kwargs.pop("image_size", 224)
+
+ model = VisionTransformer(
+ image_size=image_size,
+ patch_size=patch_size,
+ num_layers=num_layers,
+ num_heads=num_heads,
+ hidden_dim=hidden_dim,
+ mlp_dim=mlp_dim,
+ **kwargs,
+ )
+
+ if pretrained:
+ if arch not in model_urls:
+ raise ValueError(f"No checkpoint is available for model type '{arch}'!")
+ state_dict = load_state_dict_from_url(model_urls[arch], progress=progress)
+ model.load_state_dict(state_dict)
+
+ return model
+
+
+def vit_b_16(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> VisionTransformer:
+ """
+ Constructs a vit_b_16 architecture from
+ `"An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return _vision_transformer(
+ arch="vit_b_16",
+ patch_size=16,
+ num_layers=12,
+ num_heads=12,
+ hidden_dim=768,
+ mlp_dim=3072,
+ pretrained=pretrained,
+ progress=progress,
+ **kwargs,
+ )
+
+
+def vit_b_32(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> VisionTransformer:
+ """
+ Constructs a vit_b_32 architecture from
+ `"An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return _vision_transformer(
+ arch="vit_b_32",
+ patch_size=32,
+ num_layers=12,
+ num_heads=12,
+ hidden_dim=768,
+ mlp_dim=3072,
+ pretrained=pretrained,
+ progress=progress,
+ **kwargs,
+ )
+
+
+def vit_l_16(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> VisionTransformer:
+ """
+ Constructs a vit_l_16 architecture from
+ `"An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return _vision_transformer(
+ arch="vit_l_16",
+ patch_size=16,
+ num_layers=24,
+ num_heads=16,
+ hidden_dim=1024,
+ mlp_dim=4096,
+ pretrained=pretrained,
+ progress=progress,
+ **kwargs,
+ )
+
+
+def vit_l_32(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> VisionTransformer:
+ """
+ Constructs a vit_l_32 architecture from
+ `"An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale" `_.
+
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ progress (bool): If True, displays a progress bar of the download to stderr
+ """
+ return _vision_transformer(
+ arch="vit_l_32",
+ patch_size=32,
+ num_layers=24,
+ num_heads=16,
+ hidden_dim=1024,
+ mlp_dim=4096,
+ pretrained=pretrained,
+ progress=progress,
+ **kwargs,
+ )
+
+
+def interpolate_embeddings(
+ image_size: int,
+ patch_size: int,
+ model_state: "OrderedDict[str, torch.Tensor]",
+ interpolation_mode: str = "bicubic",
+ reset_heads: bool = False,
+) -> "OrderedDict[str, torch.Tensor]":
+ """This function helps interpolating positional embeddings during checkpoint loading,
+ especially when you want to apply a pre-trained model on images with different resolution.
+
+ Args:
+ image_size (int): Image size of the new model.
+ patch_size (int): Patch size of the new model.
+ model_state (OrderedDict[str, torch.Tensor]): State dict of the pre-trained model.
+ interpolation_mode (str): The algorithm used for upsampling. Default: bicubic.
+ reset_heads (bool): If true, not copying the state of heads. Default: False.
+
+ Returns:
+ OrderedDict[str, torch.Tensor]: A state dict which can be loaded into the new model.
+ """
+ # Shape of pos_embedding is (1, seq_length, hidden_dim)
+ pos_embedding = model_state["encoder.pos_embedding"]
+ n, seq_length, hidden_dim = pos_embedding.shape
+ if n != 1:
+ raise ValueError(f"Unexpected position embedding shape: {pos_embedding.shape}")
+
+ new_seq_length = (image_size // patch_size) ** 2 + 1
+
+ # Need to interpolate the weights for the position embedding.
+ # We do this by reshaping the positions embeddings to a 2d grid, performing
+ # an interpolation in the (h, w) space and then reshaping back to a 1d grid.
+ if new_seq_length != seq_length:
+ # The class token embedding shouldn't be interpolated so we split it up.
+ seq_length -= 1
+ new_seq_length -= 1
+ pos_embedding_token = pos_embedding[:, :1, :]
+ pos_embedding_img = pos_embedding[:, 1:, :]
+
+ # (1, seq_length, hidden_dim) -> (1, hidden_dim, seq_length)
+ pos_embedding_img = pos_embedding_img.permute(0, 2, 1)
+ seq_length_1d = int(math.sqrt(seq_length))
+ torch._assert(seq_length_1d * seq_length_1d == seq_length, "seq_length is not a perfect square!")
+
+ # (1, hidden_dim, seq_length) -> (1, hidden_dim, seq_l_1d, seq_l_1d)
+ pos_embedding_img = pos_embedding_img.reshape(1, hidden_dim, seq_length_1d, seq_length_1d)
+ new_seq_length_1d = image_size // patch_size
+
+ # Perform interpolation.
+ # (1, hidden_dim, seq_l_1d, seq_l_1d) -> (1, hidden_dim, new_seq_l_1d, new_seq_l_1d)
+ new_pos_embedding_img = nn.functional.interpolate(
+ pos_embedding_img,
+ size=new_seq_length_1d,
+ mode=interpolation_mode,
+ align_corners=True,
+ )
+
+ # (1, hidden_dim, new_seq_l_1d, new_seq_l_1d) -> (1, hidden_dim, new_seq_length)
+ new_pos_embedding_img = new_pos_embedding_img.reshape(1, hidden_dim, new_seq_length)
+
+ # (1, hidden_dim, new_seq_length) -> (1, new_seq_length, hidden_dim)
+ new_pos_embedding_img = new_pos_embedding_img.permute(0, 2, 1)
+ new_pos_embedding = torch.cat([pos_embedding_token, new_pos_embedding_img], dim=1)
+
+ model_state["encoder.pos_embedding"] = new_pos_embedding
+
+ if reset_heads:
+ model_state_copy: "OrderedDict[str, torch.Tensor]" = OrderedDict()
+ for k, v in model_state.items():
+ if not k.startswith("heads"):
+ model_state_copy[k] = v
+ model_state = model_state_copy
+
+ return model_state
diff --git a/clean/video/univfd_video/models/vision_transformer_misc.py b/clean/video/univfd_video/models/vision_transformer_misc.py
new file mode 100644
index 0000000000000000000000000000000000000000..7915f036c00f0d9c57c176e621afc9f1e69dcb30
--- /dev/null
+++ b/clean/video/univfd_video/models/vision_transformer_misc.py
@@ -0,0 +1,163 @@
+from typing import Callable, List, Optional
+
+import torch
+from torch import Tensor
+
+from .vision_transformer_utils import _log_api_usage_once
+
+
+interpolate = torch.nn.functional.interpolate
+
+
+# This is not in nn
+class FrozenBatchNorm2d(torch.nn.Module):
+ """
+ BatchNorm2d where the batch statistics and the affine parameters are fixed
+
+ Args:
+ num_features (int): Number of features ``C`` from an expected input of size ``(N, C, H, W)``
+ eps (float): a value added to the denominator for numerical stability. Default: 1e-5
+ """
+
+ def __init__(
+ self,
+ num_features: int,
+ eps: float = 1e-5,
+ ):
+ super().__init__()
+ _log_api_usage_once(self)
+ self.eps = eps
+ self.register_buffer("weight", torch.ones(num_features))
+ self.register_buffer("bias", torch.zeros(num_features))
+ self.register_buffer("running_mean", torch.zeros(num_features))
+ self.register_buffer("running_var", torch.ones(num_features))
+
+ def _load_from_state_dict(
+ self,
+ state_dict: dict,
+ prefix: str,
+ local_metadata: dict,
+ strict: bool,
+ missing_keys: List[str],
+ unexpected_keys: List[str],
+ error_msgs: List[str],
+ ):
+ num_batches_tracked_key = prefix + "num_batches_tracked"
+ if num_batches_tracked_key in state_dict:
+ del state_dict[num_batches_tracked_key]
+
+ super()._load_from_state_dict(
+ state_dict, prefix, local_metadata, strict, missing_keys, unexpected_keys, error_msgs
+ )
+
+ def forward(self, x: Tensor) -> Tensor:
+ # move reshapes to the beginning
+ # to make it fuser-friendly
+ w = self.weight.reshape(1, -1, 1, 1)
+ b = self.bias.reshape(1, -1, 1, 1)
+ rv = self.running_var.reshape(1, -1, 1, 1)
+ rm = self.running_mean.reshape(1, -1, 1, 1)
+ scale = w * (rv + self.eps).rsqrt()
+ bias = b - rm * scale
+ return x * scale + bias
+
+ def __repr__(self) -> str:
+ return f"{self.__class__.__name__}({self.weight.shape[0]}, eps={self.eps})"
+
+
+class ConvNormActivation(torch.nn.Sequential):
+ """
+ Configurable block used for Convolution-Normalzation-Activation blocks.
+
+ Args:
+ in_channels (int): Number of channels in the input image
+ out_channels (int): Number of channels produced by the Convolution-Normalzation-Activation block
+ kernel_size: (int, optional): Size of the convolving kernel. Default: 3
+ stride (int, optional): Stride of the convolution. Default: 1
+ padding (int, tuple or str, optional): Padding added to all four sides of the input. Default: None, in wich case it will calculated as ``padding = (kernel_size - 1) // 2 * dilation``
+ groups (int, optional): Number of blocked connections from input channels to output channels. Default: 1
+ norm_layer (Callable[..., torch.nn.Module], optional): Norm layer that will be stacked on top of the convolutiuon layer. If ``None`` this layer wont be used. Default: ``torch.nn.BatchNorm2d``
+ activation_layer (Callable[..., torch.nn.Module], optinal): Activation function which will be stacked on top of the normalization layer (if not None), otherwise on top of the conv layer. If ``None`` this layer wont be used. Default: ``torch.nn.ReLU``
+ dilation (int): Spacing between kernel elements. Default: 1
+ inplace (bool): Parameter for the activation layer, which can optionally do the operation in-place. Default ``True``
+ bias (bool, optional): Whether to use bias in the convolution layer. By default, biases are included if ``norm_layer is None``.
+
+ """
+
+ def __init__(
+ self,
+ in_channels: int,
+ out_channels: int,
+ kernel_size: int = 3,
+ stride: int = 1,
+ padding: Optional[int] = None,
+ groups: int = 1,
+ norm_layer: Optional[Callable[..., torch.nn.Module]] = torch.nn.BatchNorm2d,
+ activation_layer: Optional[Callable[..., torch.nn.Module]] = torch.nn.ReLU,
+ dilation: int = 1,
+ inplace: Optional[bool] = True,
+ bias: Optional[bool] = None,
+ ) -> None:
+ if padding is None:
+ padding = (kernel_size - 1) // 2 * dilation
+ if bias is None:
+ bias = norm_layer is None
+ layers = [
+ torch.nn.Conv2d(
+ in_channels,
+ out_channels,
+ kernel_size,
+ stride,
+ padding,
+ dilation=dilation,
+ groups=groups,
+ bias=bias,
+ )
+ ]
+ if norm_layer is not None:
+ layers.append(norm_layer(out_channels))
+ if activation_layer is not None:
+ params = {} if inplace is None else {"inplace": inplace}
+ layers.append(activation_layer(**params))
+ super().__init__(*layers)
+ _log_api_usage_once(self)
+ self.out_channels = out_channels
+
+
+class SqueezeExcitation(torch.nn.Module):
+ """
+ This block implements the Squeeze-and-Excitation block from https://arxiv.org/abs/1709.01507 (see Fig. 1).
+ Parameters ``activation``, and ``scale_activation`` correspond to ``delta`` and ``sigma`` in in eq. 3.
+
+ Args:
+ input_channels (int): Number of channels in the input image
+ squeeze_channels (int): Number of squeeze channels
+ activation (Callable[..., torch.nn.Module], optional): ``delta`` activation. Default: ``torch.nn.ReLU``
+ scale_activation (Callable[..., torch.nn.Module]): ``sigma`` activation. Default: ``torch.nn.Sigmoid``
+ """
+
+ def __init__(
+ self,
+ input_channels: int,
+ squeeze_channels: int,
+ activation: Callable[..., torch.nn.Module] = torch.nn.ReLU,
+ scale_activation: Callable[..., torch.nn.Module] = torch.nn.Sigmoid,
+ ) -> None:
+ super().__init__()
+ _log_api_usage_once(self)
+ self.avgpool = torch.nn.AdaptiveAvgPool2d(1)
+ self.fc1 = torch.nn.Conv2d(input_channels, squeeze_channels, 1)
+ self.fc2 = torch.nn.Conv2d(squeeze_channels, input_channels, 1)
+ self.activation = activation()
+ self.scale_activation = scale_activation()
+
+ def _scale(self, input: Tensor) -> Tensor:
+ scale = self.avgpool(input)
+ scale = self.fc1(scale)
+ scale = self.activation(scale)
+ scale = self.fc2(scale)
+ return self.scale_activation(scale)
+
+ def forward(self, input: Tensor) -> Tensor:
+ scale = self._scale(input)
+ return scale * input
diff --git a/clean/video/univfd_video/models/vision_transformer_utils.py b/clean/video/univfd_video/models/vision_transformer_utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..6d3293d103d0e186a1244e7cc0c6e3bde63d1df3
--- /dev/null
+++ b/clean/video/univfd_video/models/vision_transformer_utils.py
@@ -0,0 +1,549 @@
+import math
+import pathlib
+import warnings
+from types import FunctionType
+from typing import Any, BinaryIO, List, Optional, Tuple, Union
+
+import numpy as np
+import torch
+from PIL import Image, ImageColor, ImageDraw, ImageFont
+
+__all__ = [
+ "make_grid",
+ "save_image",
+ "draw_bounding_boxes",
+ "draw_segmentation_masks",
+ "draw_keypoints",
+ "flow_to_image",
+]
+
+
+@torch.no_grad()
+def make_grid(
+ tensor: Union[torch.Tensor, List[torch.Tensor]],
+ nrow: int = 8,
+ padding: int = 2,
+ normalize: bool = False,
+ value_range: Optional[Tuple[int, int]] = None,
+ scale_each: bool = False,
+ pad_value: float = 0.0,
+ **kwargs,
+) -> torch.Tensor:
+ """
+ Make a grid of images.
+
+ Args:
+ tensor (Tensor or list): 4D mini-batch Tensor of shape (B x C x H x W)
+ or a list of images all of the same size.
+ nrow (int, optional): Number of images displayed in each row of the grid.
+ The final grid size is ``(B / nrow, nrow)``. Default: ``8``.
+ padding (int, optional): amount of padding. Default: ``2``.
+ normalize (bool, optional): If True, shift the image to the range (0, 1),
+ by the min and max values specified by ``value_range``. Default: ``False``.
+ value_range (tuple, optional): tuple (min, max) where min and max are numbers,
+ then these numbers are used to normalize the image. By default, min and max
+ are computed from the tensor.
+ range (tuple. optional):
+ .. warning::
+ This parameter was deprecated in ``0.12`` and will be removed in ``0.14``. Please use ``value_range``
+ instead.
+ scale_each (bool, optional): If ``True``, scale each image in the batch of
+ images separately rather than the (min, max) over all images. Default: ``False``.
+ pad_value (float, optional): Value for the padded pixels. Default: ``0``.
+
+ Returns:
+ grid (Tensor): the tensor containing grid of images.
+ """
+ if not torch.jit.is_scripting() and not torch.jit.is_tracing():
+ _log_api_usage_once(make_grid)
+ if not (torch.is_tensor(tensor) or (isinstance(tensor, list) and all(torch.is_tensor(t) for t in tensor))):
+ raise TypeError(f"tensor or list of tensors expected, got {type(tensor)}")
+
+ if "range" in kwargs.keys():
+ warnings.warn(
+ "The parameter 'range' is deprecated since 0.12 and will be removed in 0.14. "
+ "Please use 'value_range' instead."
+ )
+ value_range = kwargs["range"]
+
+ # if list of tensors, convert to a 4D mini-batch Tensor
+ if isinstance(tensor, list):
+ tensor = torch.stack(tensor, dim=0)
+
+ if tensor.dim() == 2: # single image H x W
+ tensor = tensor.unsqueeze(0)
+ if tensor.dim() == 3: # single image
+ if tensor.size(0) == 1: # if single-channel, convert to 3-channel
+ tensor = torch.cat((tensor, tensor, tensor), 0)
+ tensor = tensor.unsqueeze(0)
+
+ if tensor.dim() == 4 and tensor.size(1) == 1: # single-channel images
+ tensor = torch.cat((tensor, tensor, tensor), 1)
+
+ if normalize is True:
+ tensor = tensor.clone() # avoid modifying tensor in-place
+ if value_range is not None:
+ assert isinstance(
+ value_range, tuple
+ ), "value_range has to be a tuple (min, max) if specified. min and max are numbers"
+
+ def norm_ip(img, low, high):
+ img.clamp_(min=low, max=high)
+ img.sub_(low).div_(max(high - low, 1e-5))
+
+ def norm_range(t, value_range):
+ if value_range is not None:
+ norm_ip(t, value_range[0], value_range[1])
+ else:
+ norm_ip(t, float(t.min()), float(t.max()))
+
+ if scale_each is True:
+ for t in tensor: # loop over mini-batch dimension
+ norm_range(t, value_range)
+ else:
+ norm_range(tensor, value_range)
+
+ assert isinstance(tensor, torch.Tensor)
+ if tensor.size(0) == 1:
+ return tensor.squeeze(0)
+
+ # make the mini-batch of images into a grid
+ nmaps = tensor.size(0)
+ xmaps = min(nrow, nmaps)
+ ymaps = int(math.ceil(float(nmaps) / xmaps))
+ height, width = int(tensor.size(2) + padding), int(tensor.size(3) + padding)
+ num_channels = tensor.size(1)
+ grid = tensor.new_full((num_channels, height * ymaps + padding, width * xmaps + padding), pad_value)
+ k = 0
+ for y in range(ymaps):
+ for x in range(xmaps):
+ if k >= nmaps:
+ break
+ # Tensor.copy_() is a valid method but seems to be missing from the stubs
+ # https://pytorch.org/docs/stable/tensors.html#torch.Tensor.copy_
+ grid.narrow(1, y * height + padding, height - padding).narrow( # type: ignore[attr-defined]
+ 2, x * width + padding, width - padding
+ ).copy_(tensor[k])
+ k = k + 1
+ return grid
+
+
+@torch.no_grad()
+def save_image(
+ tensor: Union[torch.Tensor, List[torch.Tensor]],
+ fp: Union[str, pathlib.Path, BinaryIO],
+ format: Optional[str] = None,
+ **kwargs,
+) -> None:
+ """
+ Save a given Tensor into an image file.
+
+ Args:
+ tensor (Tensor or list): Image to be saved. If given a mini-batch tensor,
+ saves the tensor as a grid of images by calling ``make_grid``.
+ fp (string or file object): A filename or a file object
+ format(Optional): If omitted, the format to use is determined from the filename extension.
+ If a file object was used instead of a filename, this parameter should always be used.
+ **kwargs: Other arguments are documented in ``make_grid``.
+ """
+
+ if not torch.jit.is_scripting() and not torch.jit.is_tracing():
+ _log_api_usage_once(save_image)
+ grid = make_grid(tensor, **kwargs)
+ # Add 0.5 after unnormalizing to [0, 255] to round to nearest integer
+ ndarr = grid.mul(255).add_(0.5).clamp_(0, 255).permute(1, 2, 0).to("cpu", torch.uint8).numpy()
+ im = Image.fromarray(ndarr)
+ im.save(fp, format=format)
+
+
+@torch.no_grad()
+def draw_bounding_boxes(
+ image: torch.Tensor,
+ boxes: torch.Tensor,
+ labels: Optional[List[str]] = None,
+ colors: Optional[Union[List[Union[str, Tuple[int, int, int]]], str, Tuple[int, int, int]]] = None,
+ fill: Optional[bool] = False,
+ width: int = 1,
+ font: Optional[str] = None,
+ font_size: int = 10,
+) -> torch.Tensor:
+
+ """
+ Draws bounding boxes on given image.
+ The values of the input image should be uint8 between 0 and 255.
+ If fill is True, Resulting Tensor should be saved as PNG image.
+
+ Args:
+ image (Tensor): Tensor of shape (C x H x W) and dtype uint8.
+ boxes (Tensor): Tensor of size (N, 4) containing bounding boxes in (xmin, ymin, xmax, ymax) format. Note that
+ the boxes are absolute coordinates with respect to the image. In other words: `0 <= xmin < xmax < W` and
+ `0 <= ymin < ymax < H`.
+ labels (List[str]): List containing the labels of bounding boxes.
+ colors (color or list of colors, optional): List containing the colors
+ of the boxes or single color for all boxes. The color can be represented as
+ PIL strings e.g. "red" or "#FF00FF", or as RGB tuples e.g. ``(240, 10, 157)``.
+ By default, random colors are generated for boxes.
+ fill (bool): If `True` fills the bounding box with specified color.
+ width (int): Width of bounding box.
+ font (str): A filename containing a TrueType font. If the file is not found in this filename, the loader may
+ also search in other directories, such as the `fonts/` directory on Windows or `/Library/Fonts/`,
+ `/System/Library/Fonts/` and `~/Library/Fonts/` on macOS.
+ font_size (int): The requested font size in points.
+
+ Returns:
+ img (Tensor[C, H, W]): Image Tensor of dtype uint8 with bounding boxes plotted.
+ """
+
+ if not torch.jit.is_scripting() and not torch.jit.is_tracing():
+ _log_api_usage_once(draw_bounding_boxes)
+ if not isinstance(image, torch.Tensor):
+ raise TypeError(f"Tensor expected, got {type(image)}")
+ elif image.dtype != torch.uint8:
+ raise ValueError(f"Tensor uint8 expected, got {image.dtype}")
+ elif image.dim() != 3:
+ raise ValueError("Pass individual images, not batches")
+ elif image.size(0) not in {1, 3}:
+ raise ValueError("Only grayscale and RGB images are supported")
+
+ num_boxes = boxes.shape[0]
+
+ if labels is None:
+ labels: Union[List[str], List[None]] = [None] * num_boxes # type: ignore[no-redef]
+ elif len(labels) != num_boxes:
+ raise ValueError(
+ f"Number of boxes ({num_boxes}) and labels ({len(labels)}) mismatch. Please specify labels for each box."
+ )
+
+ if colors is None:
+ colors = _generate_color_palette(num_boxes)
+ elif isinstance(colors, list):
+ if len(colors) < num_boxes:
+ raise ValueError(f"Number of colors ({len(colors)}) is less than number of boxes ({num_boxes}). ")
+ else: # colors specifies a single color for all boxes
+ colors = [colors] * num_boxes
+
+ colors = [(ImageColor.getrgb(color) if isinstance(color, str) else color) for color in colors]
+
+ # Handle Grayscale images
+ if image.size(0) == 1:
+ image = torch.tile(image, (3, 1, 1))
+
+ ndarr = image.permute(1, 2, 0).cpu().numpy()
+ img_to_draw = Image.fromarray(ndarr)
+ img_boxes = boxes.to(torch.int64).tolist()
+
+ if fill:
+ draw = ImageDraw.Draw(img_to_draw, "RGBA")
+ else:
+ draw = ImageDraw.Draw(img_to_draw)
+
+ txt_font = ImageFont.load_default() if font is None else ImageFont.truetype(font=font, size=font_size)
+
+ for bbox, color, label in zip(img_boxes, colors, labels): # type: ignore[arg-type]
+ if fill:
+ fill_color = color + (100,)
+ draw.rectangle(bbox, width=width, outline=color, fill=fill_color)
+ else:
+ draw.rectangle(bbox, width=width, outline=color)
+
+ if label is not None:
+ margin = width + 1
+ draw.text((bbox[0] + margin, bbox[1] + margin), label, fill=color, font=txt_font)
+
+ return torch.from_numpy(np.array(img_to_draw)).permute(2, 0, 1).to(dtype=torch.uint8)
+
+
+@torch.no_grad()
+def draw_segmentation_masks(
+ image: torch.Tensor,
+ masks: torch.Tensor,
+ alpha: float = 0.8,
+ colors: Optional[Union[List[Union[str, Tuple[int, int, int]]], str, Tuple[int, int, int]]] = None,
+) -> torch.Tensor:
+
+ """
+ Draws segmentation masks on given RGB image.
+ The values of the input image should be uint8 between 0 and 255.
+
+ Args:
+ image (Tensor): Tensor of shape (3, H, W) and dtype uint8.
+ masks (Tensor): Tensor of shape (num_masks, H, W) or (H, W) and dtype bool.
+ alpha (float): Float number between 0 and 1 denoting the transparency of the masks.
+ 0 means full transparency, 1 means no transparency.
+ colors (color or list of colors, optional): List containing the colors
+ of the masks or single color for all masks. The color can be represented as
+ PIL strings e.g. "red" or "#FF00FF", or as RGB tuples e.g. ``(240, 10, 157)``.
+ By default, random colors are generated for each mask.
+
+ Returns:
+ img (Tensor[C, H, W]): Image Tensor, with segmentation masks drawn on top.
+ """
+
+ if not torch.jit.is_scripting() and not torch.jit.is_tracing():
+ _log_api_usage_once(draw_segmentation_masks)
+ if not isinstance(image, torch.Tensor):
+ raise TypeError(f"The image must be a tensor, got {type(image)}")
+ elif image.dtype != torch.uint8:
+ raise ValueError(f"The image dtype must be uint8, got {image.dtype}")
+ elif image.dim() != 3:
+ raise ValueError("Pass individual images, not batches")
+ elif image.size()[0] != 3:
+ raise ValueError("Pass an RGB image. Other Image formats are not supported")
+ if masks.ndim == 2:
+ masks = masks[None, :, :]
+ if masks.ndim != 3:
+ raise ValueError("masks must be of shape (H, W) or (batch_size, H, W)")
+ if masks.dtype != torch.bool:
+ raise ValueError(f"The masks must be of dtype bool. Got {masks.dtype}")
+ if masks.shape[-2:] != image.shape[-2:]:
+ raise ValueError("The image and the masks must have the same height and width")
+
+ num_masks = masks.size()[0]
+ if colors is not None and num_masks > len(colors):
+ raise ValueError(f"There are more masks ({num_masks}) than colors ({len(colors)})")
+
+ if colors is None:
+ colors = _generate_color_palette(num_masks)
+
+ if not isinstance(colors, list):
+ colors = [colors]
+ if not isinstance(colors[0], (tuple, str)):
+ raise ValueError("colors must be a tuple or a string, or a list thereof")
+ if isinstance(colors[0], tuple) and len(colors[0]) != 3:
+ raise ValueError("It seems that you passed a tuple of colors instead of a list of colors")
+
+ out_dtype = torch.uint8
+
+ colors_ = []
+ for color in colors:
+ if isinstance(color, str):
+ color = ImageColor.getrgb(color)
+ colors_.append(torch.tensor(color, dtype=out_dtype))
+
+ img_to_draw = image.detach().clone()
+ # TODO: There might be a way to vectorize this
+ for mask, color in zip(masks, colors_):
+ img_to_draw[:, mask] = color[:, None]
+
+ out = image * (1 - alpha) + img_to_draw * alpha
+ return out.to(out_dtype)
+
+
+@torch.no_grad()
+def draw_keypoints(
+ image: torch.Tensor,
+ keypoints: torch.Tensor,
+ connectivity: Optional[List[Tuple[int, int]]] = None,
+ colors: Optional[Union[str, Tuple[int, int, int]]] = None,
+ radius: int = 2,
+ width: int = 3,
+) -> torch.Tensor:
+
+ """
+ Draws Keypoints on given RGB image.
+ The values of the input image should be uint8 between 0 and 255.
+
+ Args:
+ image (Tensor): Tensor of shape (3, H, W) and dtype uint8.
+ keypoints (Tensor): Tensor of shape (num_instances, K, 2) the K keypoints location for each of the N instances,
+ in the format [x, y].
+ connectivity (List[Tuple[int, int]]]): A List of tuple where,
+ each tuple contains pair of keypoints to be connected.
+ colors (str, Tuple): The color can be represented as
+ PIL strings e.g. "red" or "#FF00FF", or as RGB tuples e.g. ``(240, 10, 157)``.
+ radius (int): Integer denoting radius of keypoint.
+ width (int): Integer denoting width of line connecting keypoints.
+
+ Returns:
+ img (Tensor[C, H, W]): Image Tensor of dtype uint8 with keypoints drawn.
+ """
+
+ if not torch.jit.is_scripting() and not torch.jit.is_tracing():
+ _log_api_usage_once(draw_keypoints)
+ if not isinstance(image, torch.Tensor):
+ raise TypeError(f"The image must be a tensor, got {type(image)}")
+ elif image.dtype != torch.uint8:
+ raise ValueError(f"The image dtype must be uint8, got {image.dtype}")
+ elif image.dim() != 3:
+ raise ValueError("Pass individual images, not batches")
+ elif image.size()[0] != 3:
+ raise ValueError("Pass an RGB image. Other Image formats are not supported")
+
+ if keypoints.ndim != 3:
+ raise ValueError("keypoints must be of shape (num_instances, K, 2)")
+
+ ndarr = image.permute(1, 2, 0).cpu().numpy()
+ img_to_draw = Image.fromarray(ndarr)
+ draw = ImageDraw.Draw(img_to_draw)
+ img_kpts = keypoints.to(torch.int64).tolist()
+
+ for kpt_id, kpt_inst in enumerate(img_kpts):
+ for inst_id, kpt in enumerate(kpt_inst):
+ x1 = kpt[0] - radius
+ x2 = kpt[0] + radius
+ y1 = kpt[1] - radius
+ y2 = kpt[1] + radius
+ draw.ellipse([x1, y1, x2, y2], fill=colors, outline=None, width=0)
+
+ if connectivity:
+ for connection in connectivity:
+ start_pt_x = kpt_inst[connection[0]][0]
+ start_pt_y = kpt_inst[connection[0]][1]
+
+ end_pt_x = kpt_inst[connection[1]][0]
+ end_pt_y = kpt_inst[connection[1]][1]
+
+ draw.line(
+ ((start_pt_x, start_pt_y), (end_pt_x, end_pt_y)),
+ width=width,
+ )
+
+ return torch.from_numpy(np.array(img_to_draw)).permute(2, 0, 1).to(dtype=torch.uint8)
+
+
+# Flow visualization code adapted from https://github.com/tomrunia/OpticalFlow_Visualization
+@torch.no_grad()
+def flow_to_image(flow: torch.Tensor) -> torch.Tensor:
+
+ """
+ Converts a flow to an RGB image.
+
+ Args:
+ flow (Tensor): Flow of shape (N, 2, H, W) or (2, H, W) and dtype torch.float.
+
+ Returns:
+ img (Tensor): Image Tensor of dtype uint8 where each color corresponds
+ to a given flow direction. Shape is (N, 3, H, W) or (3, H, W) depending on the input.
+ """
+
+ if flow.dtype != torch.float:
+ raise ValueError(f"Flow should be of dtype torch.float, got {flow.dtype}.")
+
+ orig_shape = flow.shape
+ if flow.ndim == 3:
+ flow = flow[None] # Add batch dim
+
+ if flow.ndim != 4 or flow.shape[1] != 2:
+ raise ValueError(f"Input flow should have shape (2, H, W) or (N, 2, H, W), got {orig_shape}.")
+
+ max_norm = torch.sum(flow ** 2, dim=1).sqrt().max()
+ epsilon = torch.finfo((flow).dtype).eps
+ normalized_flow = flow / (max_norm + epsilon)
+ img = _normalized_flow_to_image(normalized_flow)
+
+ if len(orig_shape) == 3:
+ img = img[0] # Remove batch dim
+ return img
+
+
+@torch.no_grad()
+def _normalized_flow_to_image(normalized_flow: torch.Tensor) -> torch.Tensor:
+
+ """
+ Converts a batch of normalized flow to an RGB image.
+
+ Args:
+ normalized_flow (torch.Tensor): Normalized flow tensor of shape (N, 2, H, W)
+ Returns:
+ img (Tensor(N, 3, H, W)): Flow visualization image of dtype uint8.
+ """
+
+ N, _, H, W = normalized_flow.shape
+ device = normalized_flow.device
+ flow_image = torch.zeros((N, 3, H, W), dtype=torch.uint8, device=device)
+ colorwheel = _make_colorwheel().to(device) # shape [55x3]
+ num_cols = colorwheel.shape[0]
+ norm = torch.sum(normalized_flow ** 2, dim=1).sqrt()
+ a = torch.atan2(-normalized_flow[:, 1, :, :], -normalized_flow[:, 0, :, :]) / torch.pi
+ fk = (a + 1) / 2 * (num_cols - 1)
+ k0 = torch.floor(fk).to(torch.long)
+ k1 = k0 + 1
+ k1[k1 == num_cols] = 0
+ f = fk - k0
+
+ for c in range(colorwheel.shape[1]):
+ tmp = colorwheel[:, c]
+ col0 = tmp[k0] / 255.0
+ col1 = tmp[k1] / 255.0
+ col = (1 - f) * col0 + f * col1
+ col = 1 - norm * (1 - col)
+ flow_image[:, c, :, :] = torch.floor(255 * col)
+ return flow_image
+
+
+def _make_colorwheel() -> torch.Tensor:
+ """
+ Generates a color wheel for optical flow visualization as presented in:
+ Baker et al. "A Database and Evaluation Methodology for Optical Flow" (ICCV, 2007)
+ URL: http://vision.middlebury.edu/flow/flowEval-iccv07.pdf.
+
+ Returns:
+ colorwheel (Tensor[55, 3]): Colorwheel Tensor.
+ """
+
+ RY = 15
+ YG = 6
+ GC = 4
+ CB = 11
+ BM = 13
+ MR = 6
+
+ ncols = RY + YG + GC + CB + BM + MR
+ colorwheel = torch.zeros((ncols, 3))
+ col = 0
+
+ # RY
+ colorwheel[0:RY, 0] = 255
+ colorwheel[0:RY, 1] = torch.floor(255 * torch.arange(0, RY) / RY)
+ col = col + RY
+ # YG
+ colorwheel[col : col + YG, 0] = 255 - torch.floor(255 * torch.arange(0, YG) / YG)
+ colorwheel[col : col + YG, 1] = 255
+ col = col + YG
+ # GC
+ colorwheel[col : col + GC, 1] = 255
+ colorwheel[col : col + GC, 2] = torch.floor(255 * torch.arange(0, GC) / GC)
+ col = col + GC
+ # CB
+ colorwheel[col : col + CB, 1] = 255 - torch.floor(255 * torch.arange(CB) / CB)
+ colorwheel[col : col + CB, 2] = 255
+ col = col + CB
+ # BM
+ colorwheel[col : col + BM, 2] = 255
+ colorwheel[col : col + BM, 0] = torch.floor(255 * torch.arange(0, BM) / BM)
+ col = col + BM
+ # MR
+ colorwheel[col : col + MR, 2] = 255 - torch.floor(255 * torch.arange(MR) / MR)
+ colorwheel[col : col + MR, 0] = 255
+ return colorwheel
+
+
+def _generate_color_palette(num_objects: int):
+ palette = torch.tensor([2 ** 25 - 1, 2 ** 15 - 1, 2 ** 21 - 1])
+ return [tuple((i * palette) % 255) for i in range(num_objects)]
+
+
+def _log_api_usage_once(obj: Any) -> None:
+
+ """
+ Logs API usage(module and name) within an organization.
+ In a large ecosystem, it's often useful to track the PyTorch and
+ TorchVision APIs usage. This API provides the similar functionality to the
+ logging module in the Python stdlib. It can be used for debugging purpose
+ to log which methods are used and by default it is inactive, unless the user
+ manually subscribes a logger via the `SetAPIUsageLogger method `_.
+ Please note it is triggered only once for the same API call within a process.
+ It does not collect any data from open-source users since it is no-op by default.
+ For more information, please refer to
+ * PyTorch note: https://pytorch.org/docs/stable/notes/large_scale_deployments.html#api-usage-logging;
+ * Logging policy: https://github.com/pytorch/vision/issues/5052;
+
+ Args:
+ obj (class instance or method): an object to extract info from.
+ """
+ if not obj.__module__.startswith("torchvision"):
+ return
+ name = obj.__class__.__name__
+ if isinstance(obj, FunctionType):
+ name = obj.__name__
+ torch._C._log_api_usage_once(f"{obj.__module__}.{name}")
diff --git a/clean/video/univfd_video/networks/__init__.py b/clean/video/univfd_video/networks/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/clean/video/univfd_video/networks/base_model.py b/clean/video/univfd_video/networks/base_model.py
new file mode 100644
index 0000000000000000000000000000000000000000..684bdd31004eb9d5664da1aba08dc3ba3b7c4d80
--- /dev/null
+++ b/clean/video/univfd_video/networks/base_model.py
@@ -0,0 +1,58 @@
+import os
+import torch
+import torch.nn as nn
+from torch.nn import init
+from torch.optim import lr_scheduler
+
+
+class BaseModel(nn.Module):
+ def __init__(self, opt):
+ super(BaseModel, self).__init__()
+ self.opt = opt
+ self.total_steps = 0
+ self.save_dir = os.path.join(opt.checkpoints_dir, opt.name)
+ self.device = torch.device('cuda:{}'.format(opt.gpu_ids[0])) if opt.gpu_ids else torch.device('cpu')
+
+ def save_networks(self, save_filename):
+ save_path = os.path.join(self.save_dir, save_filename)
+
+ # serialize model and optimizer to dict
+ state_dict = {
+ 'model': self.model.state_dict(),
+ 'optimizer' : self.optimizer.state_dict(),
+ 'total_steps' : self.total_steps,
+ }
+
+ torch.save(state_dict, save_path)
+
+
+ def eval(self):
+ self.model.eval()
+
+ def test(self):
+ with torch.no_grad():
+ self.forward()
+
+
+def init_weights(net, init_type='normal', gain=0.02):
+ def init_func(m):
+ classname = m.__class__.__name__
+ if hasattr(m, 'weight') and (classname.find('Conv') != -1 or classname.find('Linear') != -1):
+ if init_type == 'normal':
+ init.normal_(m.weight.data, 0.0, gain)
+ elif init_type == 'xavier':
+ init.xavier_normal_(m.weight.data, gain=gain)
+ elif init_type == 'kaiming':
+ init.kaiming_normal_(m.weight.data, a=0, mode='fan_in')
+ elif init_type == 'orthogonal':
+ init.orthogonal_(m.weight.data, gain=gain)
+ else:
+ raise NotImplementedError('initialization method [%s] is not implemented' % init_type)
+ if hasattr(m, 'bias') and m.bias is not None:
+ init.constant_(m.bias.data, 0.0)
+ elif classname.find('BatchNorm2d') != -1:
+ init.normal_(m.weight.data, 1.0, gain)
+ init.constant_(m.bias.data, 0.0)
+
+ print('initialize network with %s' % init_type)
+ net.apply(init_func)
diff --git a/clean/video/univfd_video/networks/lpf.py b/clean/video/univfd_video/networks/lpf.py
new file mode 100644
index 0000000000000000000000000000000000000000..f64030bd9a73786f249e03b4d6ce02b32d5ecf92
--- /dev/null
+++ b/clean/video/univfd_video/networks/lpf.py
@@ -0,0 +1,120 @@
+# Copyright (c) 2019, Adobe Inc. All rights reserved.
+#
+# This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike
+# 4.0 International Public License. To view a copy of this license, visit
+# https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode.
+
+import torch
+import torch.nn.parallel
+import numpy as np
+import torch.nn as nn
+import torch.nn.functional as F
+from IPython import embed
+
+class Downsample(nn.Module):
+ def __init__(self, pad_type='reflect', filt_size=3, stride=2, channels=None, pad_off=0):
+ super(Downsample, self).__init__()
+ self.filt_size = filt_size
+ self.pad_off = pad_off
+ self.pad_sizes = [int(1.*(filt_size-1)/2), int(np.ceil(1.*(filt_size-1)/2)), int(1.*(filt_size-1)/2), int(np.ceil(1.*(filt_size-1)/2))]
+ self.pad_sizes = [pad_size+pad_off for pad_size in self.pad_sizes]
+ self.stride = stride
+ self.off = int((self.stride-1)/2.)
+ self.channels = channels
+
+ # print('Filter size [%i]'%filt_size)
+ if(self.filt_size==1):
+ a = np.array([1.,])
+ elif(self.filt_size==2):
+ a = np.array([1., 1.])
+ elif(self.filt_size==3):
+ a = np.array([1., 2., 1.])
+ elif(self.filt_size==4):
+ a = np.array([1., 3., 3., 1.])
+ elif(self.filt_size==5):
+ a = np.array([1., 4., 6., 4., 1.])
+ elif(self.filt_size==6):
+ a = np.array([1., 5., 10., 10., 5., 1.])
+ elif(self.filt_size==7):
+ a = np.array([1., 6., 15., 20., 15., 6., 1.])
+
+ filt = torch.Tensor(a[:,None]*a[None,:])
+ filt = filt/torch.sum(filt)
+ self.register_buffer('filt', filt[None,None,:,:].repeat((self.channels,1,1,1)))
+
+ self.pad = get_pad_layer(pad_type)(self.pad_sizes)
+
+ def forward(self, inp):
+ if(self.filt_size==1):
+ if(self.pad_off==0):
+ return inp[:,:,::self.stride,::self.stride]
+ else:
+ return self.pad(inp)[:,:,::self.stride,::self.stride]
+ else:
+ return F.conv2d(self.pad(inp), self.filt, stride=self.stride, groups=inp.shape[1])
+
+def get_pad_layer(pad_type):
+ if(pad_type in ['refl','reflect']):
+ PadLayer = nn.ReflectionPad2d
+ elif(pad_type in ['repl','replicate']):
+ PadLayer = nn.ReplicationPad2d
+ elif(pad_type=='zero'):
+ PadLayer = nn.ZeroPad2d
+ else:
+ print('Pad type [%s] not recognized'%pad_type)
+ return PadLayer
+
+
+class Downsample1D(nn.Module):
+ def __init__(self, pad_type='reflect', filt_size=3, stride=2, channels=None, pad_off=0):
+ super(Downsample1D, self).__init__()
+ self.filt_size = filt_size
+ self.pad_off = pad_off
+ self.pad_sizes = [int(1. * (filt_size - 1) / 2), int(np.ceil(1. * (filt_size - 1) / 2))]
+ self.pad_sizes = [pad_size + pad_off for pad_size in self.pad_sizes]
+ self.stride = stride
+ self.off = int((self.stride - 1) / 2.)
+ self.channels = channels
+
+ # print('Filter size [%i]' % filt_size)
+ if(self.filt_size == 1):
+ a = np.array([1., ])
+ elif(self.filt_size == 2):
+ a = np.array([1., 1.])
+ elif(self.filt_size == 3):
+ a = np.array([1., 2., 1.])
+ elif(self.filt_size == 4):
+ a = np.array([1., 3., 3., 1.])
+ elif(self.filt_size == 5):
+ a = np.array([1., 4., 6., 4., 1.])
+ elif(self.filt_size == 6):
+ a = np.array([1., 5., 10., 10., 5., 1.])
+ elif(self.filt_size == 7):
+ a = np.array([1., 6., 15., 20., 15., 6., 1.])
+
+ filt = torch.Tensor(a)
+ filt = filt / torch.sum(filt)
+ self.register_buffer('filt', filt[None, None, :].repeat((self.channels, 1, 1)))
+
+ self.pad = get_pad_layer_1d(pad_type)(self.pad_sizes)
+
+ def forward(self, inp):
+ if(self.filt_size == 1):
+ if(self.pad_off == 0):
+ return inp[:, :, ::self.stride]
+ else:
+ return self.pad(inp)[:, :, ::self.stride]
+ else:
+ return F.conv1d(self.pad(inp), self.filt, stride=self.stride, groups=inp.shape[1])
+
+
+def get_pad_layer_1d(pad_type):
+ if(pad_type in ['refl', 'reflect']):
+ PadLayer = nn.ReflectionPad1d
+ elif(pad_type in ['repl', 'replicate']):
+ PadLayer = nn.ReplicationPad1d
+ elif(pad_type == 'zero'):
+ PadLayer = nn.ZeroPad1d
+ else:
+ print('Pad type [%s] not recognized' % pad_type)
+ return PadLayer
diff --git a/clean/video/univfd_video/networks/resnet_lpf.py b/clean/video/univfd_video/networks/resnet_lpf.py
new file mode 100644
index 0000000000000000000000000000000000000000..f9e34254eadc00e701245d03ffd86c25c114ce3f
--- /dev/null
+++ b/clean/video/univfd_video/networks/resnet_lpf.py
@@ -0,0 +1,313 @@
+# This code is built from the PyTorch examples repository: https://github.com/pytorch/vision/tree/master/torchvision/models.
+# Copyright (c) 2017 Torch Contributors.
+# The Pytorch examples are available under the BSD 3-Clause License.
+#
+# ==========================================================================================
+#
+# Adobe’s modifications are Copyright 2019 Adobe. All rights reserved.
+# Adobe’s modifications are licensed under the Creative Commons Attribution-NonCommercial-ShareAlike
+# 4.0 International Public License (CC-NC-SA-4.0). To view a copy of the license, visit
+# https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode.
+#
+# ==========================================================================================
+#
+# BSD-3 License
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+
+import torch.nn as nn
+import torch.utils.model_zoo as model_zoo
+from .lpf import *
+
+__all__ = ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101',
+ 'resnet152', 'resnext50_32x4d', 'resnext101_32x8d']
+
+
+# model_urls = {
+# 'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth',
+# 'resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth',
+# 'resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth',
+# 'resnet101': 'https://download.pytorch.org/models/resnet101-5d3b4d8f.pth',
+# 'resnet152': 'https://download.pytorch.org/models/resnet152-b121ed2d.pth',
+# }
+
+
+def conv3x3(in_planes, out_planes, stride=1, groups=1):
+ """3x3 convolution with padding"""
+ return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,
+ padding=1, groups=groups, bias=False)
+
+def conv1x1(in_planes, out_planes, stride=1):
+ """1x1 convolution"""
+ return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False)
+
+class BasicBlock(nn.Module):
+ expansion = 1
+
+ def __init__(self, inplanes, planes, stride=1, downsample=None, groups=1, norm_layer=None, filter_size=1):
+ super(BasicBlock, self).__init__()
+ if norm_layer is None:
+ norm_layer = nn.BatchNorm2d
+ if groups != 1:
+ raise ValueError('BasicBlock only supports groups=1')
+ # Both self.conv1 and self.downsample layers downsample the input when stride != 1
+ self.conv1 = conv3x3(inplanes, planes)
+ self.bn1 = norm_layer(planes)
+ self.relu = nn.ReLU(inplace=True)
+ if(stride==1):
+ self.conv2 = conv3x3(planes,planes)
+ else:
+ self.conv2 = nn.Sequential(Downsample(filt_size=filter_size, stride=stride, channels=planes),
+ conv3x3(planes, planes),)
+ self.bn2 = norm_layer(planes)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x):
+ identity = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+
+ if self.downsample is not None:
+ identity = self.downsample(x)
+
+ out += identity
+ out = self.relu(out)
+
+ return out
+
+
+class Bottleneck(nn.Module):
+ expansion = 4
+
+ def __init__(self, inplanes, planes, stride=1, downsample=None, groups=1, norm_layer=None, filter_size=1):
+ super(Bottleneck, self).__init__()
+ if norm_layer is None:
+ norm_layer = nn.BatchNorm2d
+ # Both self.conv2 and self.downsample layers downsample the input when stride != 1
+ self.conv1 = conv1x1(inplanes, planes)
+ self.bn1 = norm_layer(planes)
+ self.conv2 = conv3x3(planes, planes, groups) # stride moved
+ self.bn2 = norm_layer(planes)
+ if(stride==1):
+ self.conv3 = conv1x1(planes, planes * self.expansion)
+ else:
+ self.conv3 = nn.Sequential(Downsample(filt_size=filter_size, stride=stride, channels=planes),
+ conv1x1(planes, planes * self.expansion))
+ self.bn3 = norm_layer(planes * self.expansion)
+ self.relu = nn.ReLU(inplace=True)
+ self.downsample = downsample
+ self.stride = stride
+
+ def forward(self, x):
+ identity = x
+
+ out = self.conv1(x)
+ out = self.bn1(out)
+ out = self.relu(out)
+
+ out = self.conv2(out)
+ out = self.bn2(out)
+ out = self.relu(out)
+
+ out = self.conv3(out)
+ out = self.bn3(out)
+
+ if self.downsample is not None:
+ identity = self.downsample(x)
+
+ out += identity
+ out = self.relu(out)
+
+ return out
+
+
+class ResNet(nn.Module):
+
+ def __init__(self, block, layers, num_classes=1000, zero_init_residual=False,
+ groups=1, width_per_group=64, norm_layer=None, filter_size=1, pool_only=True):
+ super(ResNet, self).__init__()
+ if norm_layer is None:
+ norm_layer = nn.BatchNorm2d
+ planes = [int(width_per_group * groups * 2 ** i) for i in range(4)]
+ self.inplanes = planes[0]
+
+ if(pool_only):
+ self.conv1 = nn.Conv2d(3, planes[0], kernel_size=7, stride=2, padding=3, bias=False)
+ else:
+ self.conv1 = nn.Conv2d(3, planes[0], kernel_size=7, stride=1, padding=3, bias=False)
+ self.bn1 = norm_layer(planes[0])
+ self.relu = nn.ReLU(inplace=True)
+
+ if(pool_only):
+ self.maxpool = nn.Sequential(*[nn.MaxPool2d(kernel_size=2, stride=1),
+ Downsample(filt_size=filter_size, stride=2, channels=planes[0])])
+ else:
+ self.maxpool = nn.Sequential(*[Downsample(filt_size=filter_size, stride=2, channels=planes[0]),
+ nn.MaxPool2d(kernel_size=2, stride=1),
+ Downsample(filt_size=filter_size, stride=2, channels=planes[0])])
+
+ self.layer1 = self._make_layer(block, planes[0], layers[0], groups=groups, norm_layer=norm_layer)
+ self.layer2 = self._make_layer(block, planes[1], layers[1], stride=2, groups=groups, norm_layer=norm_layer, filter_size=filter_size)
+ self.layer3 = self._make_layer(block, planes[2], layers[2], stride=2, groups=groups, norm_layer=norm_layer, filter_size=filter_size)
+ self.layer4 = self._make_layer(block, planes[3], layers[3], stride=2, groups=groups, norm_layer=norm_layer, filter_size=filter_size)
+ self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
+ self.fc = nn.Linear(planes[3] * block.expansion, num_classes)
+
+ for m in self.modules():
+ if isinstance(m, nn.Conv2d):
+ if(m.in_channels!=m.out_channels or m.out_channels!=m.groups or m.bias is not None):
+ # don't want to reinitialize downsample layers, code assuming normal conv layers will not have these characteristics
+ nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
+ else:
+ print('Not initializing')
+ elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
+ nn.init.constant_(m.weight, 1)
+ nn.init.constant_(m.bias, 0)
+
+ # Zero-initialize the last BN in each residual branch,
+ # so that the residual branch starts with zeros, and each residual block behaves like an identity.
+ # This improves the model by 0.2~0.3% according to https://arxiv.org/abs/1706.02677
+ if zero_init_residual:
+ for m in self.modules():
+ if isinstance(m, Bottleneck):
+ nn.init.constant_(m.bn3.weight, 0)
+ elif isinstance(m, BasicBlock):
+ nn.init.constant_(m.bn2.weight, 0)
+
+ def _make_layer(self, block, planes, blocks, stride=1, groups=1, norm_layer=None, filter_size=1):
+ if norm_layer is None:
+ norm_layer = nn.BatchNorm2d
+ downsample = None
+ if stride != 1 or self.inplanes != planes * block.expansion:
+ # downsample = nn.Sequential(
+ # conv1x1(self.inplanes, planes * block.expansion, stride, filter_size=filter_size),
+ # norm_layer(planes * block.expansion),
+ # )
+
+ downsample = [Downsample(filt_size=filter_size, stride=stride, channels=self.inplanes),] if(stride !=1) else []
+ downsample += [conv1x1(self.inplanes, planes * block.expansion, 1),
+ norm_layer(planes * block.expansion)]
+ # print(downsample)
+ downsample = nn.Sequential(*downsample)
+
+ layers = []
+ layers.append(block(self.inplanes, planes, stride, downsample, groups, norm_layer, filter_size=filter_size))
+ self.inplanes = planes * block.expansion
+ for _ in range(1, blocks):
+ layers.append(block(self.inplanes, planes, groups=groups, norm_layer=norm_layer, filter_size=filter_size))
+
+ return nn.Sequential(*layers)
+
+ def forward(self, x):
+ x = self.conv1(x)
+ x = self.bn1(x)
+ x = self.relu(x)
+ x = self.maxpool(x)
+
+ x = self.layer1(x)
+ x = self.layer2(x)
+ x = self.layer3(x)
+ x = self.layer4(x)
+
+ x = self.avgpool(x)
+ x = x.view(x.size(0), -1)
+ x = self.fc(x)
+
+ return x
+
+
+def resnet18(pretrained=False, filter_size=1, pool_only=True, **kwargs):
+ """Constructs a ResNet-18 model.
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ """
+ model = ResNet(BasicBlock, [2, 2, 2, 2], filter_size=filter_size, pool_only=pool_only, **kwargs)
+ if pretrained:
+ model.load_state_dict(model_zoo.load_url(model_urls['resnet18']))
+ return model
+
+
+def resnet34(pretrained=False, filter_size=1, pool_only=True, **kwargs):
+ """Constructs a ResNet-34 model.
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ """
+ model = ResNet(BasicBlock, [3, 4, 6, 3], filter_size=filter_size, pool_only=pool_only, **kwargs)
+ if pretrained:
+ model.load_state_dict(model_zoo.load_url(model_urls['resnet34']))
+ return model
+
+
+def resnet50(pretrained=False, filter_size=1, pool_only=True, **kwargs):
+ """Constructs a ResNet-50 model.
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ """
+ model = ResNet(Bottleneck, [3, 4, 6, 3], filter_size=filter_size, pool_only=pool_only, **kwargs)
+ if pretrained:
+ model.load_state_dict(model_zoo.load_url(model_urls['resnet50']))
+ return model
+
+
+def resnet101(pretrained=False, filter_size=1, pool_only=True, **kwargs):
+ """Constructs a ResNet-101 model.
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ """
+ model = ResNet(Bottleneck, [3, 4, 23, 3], filter_size=filter_size, pool_only=pool_only, **kwargs)
+ if pretrained:
+ model.load_state_dict(model_zoo.load_url(model_urls['resnet101']))
+ return model
+
+
+def resnet152(pretrained=False, filter_size=1, pool_only=True, **kwargs):
+ """Constructs a ResNet-152 model.
+ Args:
+ pretrained (bool): If True, returns a model pre-trained on ImageNet
+ """
+ model = ResNet(Bottleneck, [3, 8, 36, 3], filter_size=filter_size, pool_only=pool_only, **kwargs)
+ if pretrained:
+ model.load_state_dict(model_zoo.load_url(model_urls['resnet152']))
+ return model
+
+
+def resnext50_32x4d(pretrained=False, filter_size=1, pool_only=True, **kwargs):
+ model = ResNet(Bottleneck, [3, 4, 6, 3], groups=4, width_per_group=32, filter_size=filter_size, pool_only=pool_only, **kwargs)
+ # if pretrained:
+ # model.load_state_dict(model_zoo.load_url(model_urls['resnet50']))
+ return model
+
+
+def resnext101_32x8d(pretrained=False, filter_size=1, pool_only=True, **kwargs):
+ model = ResNet(Bottleneck, [3, 4, 23, 3], groups=8, width_per_group=32, filter_size=filter_size, pool_only=pool_only, **kwargs)
+ # if pretrained:
+ # model.load_state_dict(model_zoo.load_url(model_urls['resnet50']))
+ return model
diff --git a/clean/video/univfd_video/networks/trainer.py b/clean/video/univfd_video/networks/trainer.py
new file mode 100644
index 0000000000000000000000000000000000000000..73d5bc0bcf5d48117e473900b38088c738f9c555
--- /dev/null
+++ b/clean/video/univfd_video/networks/trainer.py
@@ -0,0 +1,74 @@
+import functools
+import torch
+import torch.nn as nn
+from networks.base_model import BaseModel, init_weights
+import sys
+from models import get_model
+
+class Trainer(BaseModel):
+ def name(self):
+ return 'Trainer'
+
+ def __init__(self, opt):
+ super(Trainer, self).__init__(opt)
+ self.opt = opt
+ self.model = get_model(opt.arch)
+ torch.nn.init.normal_(self.model.fc.weight.data, 0.0, opt.init_gain)
+
+ if opt.fix_backbone:
+ params = []
+ for name, p in self.model.named_parameters():
+ if name=="fc.weight" or name=="fc.bias":
+ params.append(p)
+ else:
+ p.requires_grad = False
+ else:
+ print("Your backbone is not fixed. Are you sure you want to proceed? If this is a mistake, enable the --fix_backbone command during training and rerun")
+ import time
+ time.sleep(3)
+ params = self.model.parameters()
+
+
+
+ if opt.optim == 'adam':
+ self.optimizer = torch.optim.AdamW(params, lr=opt.lr, betas=(opt.beta1, 0.999), weight_decay=opt.weight_decay)
+ elif opt.optim == 'sgd':
+ self.optimizer = torch.optim.SGD(params, lr=opt.lr, momentum=0.0, weight_decay=opt.weight_decay)
+ else:
+ raise ValueError("optim should be [adam, sgd]")
+
+ self.loss_fn = nn.BCEWithLogitsLoss()
+
+ self.model.to(opt.gpu_ids[0])
+
+
+ def adjust_learning_rate(self, min_lr=1e-6):
+ for param_group in self.optimizer.param_groups:
+ param_group['lr'] /= 10.
+ if param_group['lr'] < min_lr:
+ return False
+ return True
+
+
+ def set_input(self, input):
+ self.input = input[0].to(self.device)
+ self.label = input[1].to(self.device).float()
+
+
+ def forward(self):
+ self.output = self.model(self.input)
+ self.output = self.output.view(-1).unsqueeze(1)
+
+
+ def get_loss(self):
+ return self.loss_fn(self.output.squeeze(1), self.label)
+
+ def optimize_parameters(self):
+ self.forward()
+ self.loss = self.loss_fn(self.output.squeeze(1), self.label)
+ self.optimizer.zero_grad()
+ self.loss.backward()
+ self.optimizer.step()
+
+
+
diff --git a/clean/video/univfd_video/options/__init__.py b/clean/video/univfd_video/options/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/clean/video/univfd_video/options/base_options.py b/clean/video/univfd_video/options/base_options.py
new file mode 100644
index 0000000000000000000000000000000000000000..69d35b17cf409eac0a55a74ed187f23028cb93c5
--- /dev/null
+++ b/clean/video/univfd_video/options/base_options.py
@@ -0,0 +1,117 @@
+import argparse
+import os
+import util
+import torch
+
+
+class BaseOptions():
+ def __init__(self):
+ self.initialized = False
+
+ def initialize(self, parser):
+ parser.add_argument('--mode', default='binary')
+ parser.add_argument('--arch', type=str, default='res50', help='see my_models/__init__.py')
+ parser.add_argument('--fix_backbone', action='store_true')
+
+ # data augmentation
+ parser.add_argument('--rz_interp', default='bilinear')
+ parser.add_argument('--blur_prob', type=float, default=0.5)
+ parser.add_argument('--blur_sig', default='0.0,3.0')
+ parser.add_argument('--jpg_prob', type=float, default=0.5)
+ parser.add_argument('--jpg_method', default='cv2,pil')
+ parser.add_argument('--jpg_qual', default='30,100')
+
+
+ parser.add_argument('--real_list_path', default=None, help='only used if data_mode==ours: path for the list of real images, which should contain train.pickle and val.pickle')
+ parser.add_argument('--fake_list_path', default=None, help='only used if data_mode==ours: path for the list of fake images, which should contain train.pickle and val.pickle')
+ parser.add_argument('--wang2020_data_path', default=None, help='only used if data_mode==wang2020 it should contain train and test folders')
+ parser.add_argument('--data_mode', default='ours', help='wang2020 or ours')
+ parser.add_argument('--data_label', default='train', help='label to decide whether train or validation dataset')
+ parser.add_argument('--weight_decay', type=float, default=0.0, help='loss weight for l2 reg')
+
+ parser.add_argument('--class_bal', action='store_true') # what is this ?
+ parser.add_argument('--batch_size', type=int, default=256, help='input batch size')
+ parser.add_argument('--loadSize', type=int, default=256, help='scale images to this size')
+ parser.add_argument('--cropSize', type=int, default=224, help='then crop to this size')
+ parser.add_argument('--gpu_ids', type=str, default='0', help='gpu ids: e.g. 0 0,1,2, 0,2. use -1 for CPU')
+ parser.add_argument('--name', type=str, default='experiment_name', help='name of the experiment. It decides where to store samples and models')
+ parser.add_argument('--num_threads', default=4, type=int, help='# threads for loading data')
+ parser.add_argument('--checkpoints_dir', type=str, default='./checkpoints', help='models are saved here')
+ parser.add_argument('--serial_batches', action='store_true', help='if true, takes images in order to make batches, otherwise takes them randomly')
+ parser.add_argument('--resize_or_crop', type=str, default='scale_and_crop', help='scaling and cropping of images at load time [resize_and_crop|crop|scale_width|scale_width_and_crop|none]')
+ parser.add_argument('--no_flip', action='store_true', help='if specified, do not flip the images for data augmentation')
+ parser.add_argument('--init_type', type=str, default='normal', help='network initialization [normal|xavier|kaiming|orthogonal]')
+ parser.add_argument('--init_gain', type=float, default=0.02, help='scaling factor for normal, xavier and orthogonal.')
+ parser.add_argument('--suffix', default='', type=str, help='customized suffix: opt.name = opt.name + suffix: e.g., {model}_{netG}_size{loadSize}')
+ self.initialized = True
+ return parser
+
+ def gather_options(self):
+ # initialize parser with basic options
+ if not self.initialized:
+ parser = argparse.ArgumentParser(
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+ parser = self.initialize(parser)
+
+ # get the basic options
+ opt, _ = parser.parse_known_args()
+ self.parser = parser
+
+ return parser.parse_args()
+
+ def print_options(self, opt):
+ message = ''
+ message += '----------------- Options ---------------\n'
+ for k, v in sorted(vars(opt).items()):
+ comment = ''
+ default = self.parser.get_default(k)
+ if v != default:
+ comment = '\t[default: %s]' % str(default)
+ message += '{:>25}: {:<30}{}\n'.format(str(k), str(v), comment)
+ message += '----------------- End -------------------'
+ print(message)
+
+ # save to the disk
+ expr_dir = os.path.join(opt.checkpoints_dir, opt.name)
+ util.mkdirs(expr_dir)
+ file_name = os.path.join(expr_dir, 'opt.txt')
+ with open(file_name, 'wt') as opt_file:
+ opt_file.write(message)
+ opt_file.write('\n')
+
+ def parse(self, print_options=True):
+
+ opt = self.gather_options()
+ opt.isTrain = self.isTrain # train or test
+
+ # process opt.suffix
+ if opt.suffix:
+ suffix = ('_' + opt.suffix.format(**vars(opt))) if opt.suffix != '' else ''
+ opt.name = opt.name + suffix
+
+ if print_options:
+ self.print_options(opt)
+
+ # set gpu ids
+ str_ids = opt.gpu_ids.split(',')
+ opt.gpu_ids = []
+ for str_id in str_ids:
+ id = int(str_id)
+ if id >= 0:
+ opt.gpu_ids.append(id)
+ if len(opt.gpu_ids) > 0:
+ torch.cuda.set_device(opt.gpu_ids[0])
+
+ # additional
+ #opt.classes = opt.classes.split(',')
+ opt.rz_interp = opt.rz_interp.split(',')
+ opt.blur_sig = [float(s) for s in opt.blur_sig.split(',')]
+ opt.jpg_method = opt.jpg_method.split(',')
+ opt.jpg_qual = [int(s) for s in opt.jpg_qual.split(',')]
+ if len(opt.jpg_qual) == 2:
+ opt.jpg_qual = list(range(opt.jpg_qual[0], opt.jpg_qual[1] + 1))
+ elif len(opt.jpg_qual) > 2:
+ raise ValueError("Shouldn't have more than 2 values for --jpg_qual.")
+
+ self.opt = opt
+ return self.opt
diff --git a/clean/video/univfd_video/options/test_options.py b/clean/video/univfd_video/options/test_options.py
new file mode 100644
index 0000000000000000000000000000000000000000..f824c7aae81d325bf81e16c5a5e2c1931ccd5b34
--- /dev/null
+++ b/clean/video/univfd_video/options/test_options.py
@@ -0,0 +1,13 @@
+from .base_options import BaseOptions
+
+
+class TestOptions(BaseOptions):
+ def initialize(self, parser):
+ parser = BaseOptions.initialize(self, parser)
+ parser.add_argument('--model_path')
+ parser.add_argument('--no_resize', action='store_true')
+ parser.add_argument('--no_crop', action='store_true')
+ parser.add_argument('--eval', action='store_true', help='use eval mode during test time.')
+
+ self.isTrain = False
+ return parser
diff --git a/clean/video/univfd_video/options/train_options.py b/clean/video/univfd_video/options/train_options.py
new file mode 100644
index 0000000000000000000000000000000000000000..e7f1e54cea63ef424ad84d1ccaa1538e74119466
--- /dev/null
+++ b/clean/video/univfd_video/options/train_options.py
@@ -0,0 +1,22 @@
+from .base_options import BaseOptions
+
+
+class TrainOptions(BaseOptions):
+ def initialize(self, parser):
+ parser = BaseOptions.initialize(self, parser)
+ parser.add_argument('--earlystop_epoch', type=int, default=5)
+ parser.add_argument('--data_aug', action='store_true', help='if specified, perform additional data augmentation (photometric, blurring, jpegging)')
+ parser.add_argument('--optim', type=str, default='adam', help='optim to use [sgd, adam]')
+ parser.add_argument('--new_optim', action='store_true', help='new optimizer instead of loading the optim state')
+ parser.add_argument('--loss_freq', type=int, default=400, help='frequency of showing loss on tensorboard')
+ parser.add_argument('--save_epoch_freq', type=int, default=1, help='frequency of saving checkpoints at the end of epochs')
+ parser.add_argument('--epoch_count', type=int, default=1, help='the starting epoch count, we save the model by , +, ...')
+ parser.add_argument('--last_epoch', type=int, default=-1, help='starting epoch count for scheduler intialization')
+ parser.add_argument('--train_split', type=str, default='train', help='train, val, test, etc')
+ parser.add_argument('--val_split', type=str, default='val', help='train, val, test, etc')
+ parser.add_argument('--niter', type=int, default=100, help='total epoches')
+ parser.add_argument('--beta1', type=float, default=0.9, help='momentum term of adam')
+ parser.add_argument('--lr', type=float, default=0.0001, help='initial learning rate for adam')
+
+ self.isTrain = True
+ return parser
diff --git a/clean/video/univfd_video/pretrained_weights/fc_weights.pth b/clean/video/univfd_video/pretrained_weights/fc_weights.pth
new file mode 100644
index 0000000000000000000000000000000000000000..989708188fa14aa3f7ddfcddb579d7b9426d5e8e
--- /dev/null
+++ b/clean/video/univfd_video/pretrained_weights/fc_weights.pth
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:477100745713bcc957beb2b40859536859b6483fd6301b3b9293151b194c7847
+size 4083
diff --git a/clean/video/univfd_video/test.sh b/clean/video/univfd_video/test.sh
new file mode 100644
index 0000000000000000000000000000000000000000..983d05b7c4cf0e8b0a977b835849a102fa8b75fc
--- /dev/null
+++ b/clean/video/univfd_video/test.sh
@@ -0,0 +1 @@
+CUDA_VISIBLE_DEVICES=0 python3 validate.py --arch=CLIP:ViT-L/14 --ckpt=pretrained_weights/fc_weights.pth --result_folder=clip_vitl14
diff --git a/clean/video/univfd_video/train.py b/clean/video/univfd_video/train.py
new file mode 100644
index 0000000000000000000000000000000000000000..c24917730db61c90f62015ca68572b83219e2050
--- /dev/null
+++ b/clean/video/univfd_video/train.py
@@ -0,0 +1,85 @@
+import os
+import time
+from tensorboardX import SummaryWriter
+
+from validate import validate
+from data import create_dataloader
+from earlystop import EarlyStopping
+from networks.trainer import Trainer
+from options.train_options import TrainOptions
+
+
+"""Currently assumes jpg_prob, blur_prob 0 or 1"""
+def get_val_opt():
+ val_opt = TrainOptions().parse(print_options=False)
+ val_opt.isTrain = False
+ val_opt.no_resize = False
+ val_opt.no_crop = False
+ val_opt.serial_batches = True
+ val_opt.data_label = 'val'
+ val_opt.jpg_method = ['pil']
+ if len(val_opt.blur_sig) == 2:
+ b_sig = val_opt.blur_sig
+ val_opt.blur_sig = [(b_sig[0] + b_sig[1]) / 2]
+ if len(val_opt.jpg_qual) != 1:
+ j_qual = val_opt.jpg_qual
+ val_opt.jpg_qual = [int((j_qual[0] + j_qual[-1]) / 2)]
+
+ return val_opt
+
+
+
+if __name__ == '__main__':
+ opt = TrainOptions().parse()
+ val_opt = get_val_opt()
+
+ model = Trainer(opt)
+
+ data_loader = create_dataloader(opt)
+ val_loader = create_dataloader(val_opt)
+
+ train_writer = SummaryWriter(os.path.join(opt.checkpoints_dir, opt.name, "train"))
+ val_writer = SummaryWriter(os.path.join(opt.checkpoints_dir, opt.name, "val"))
+
+ early_stopping = EarlyStopping(patience=opt.earlystop_epoch, delta=-0.001, verbose=True)
+ start_time = time.time()
+ print ("Length of data loader: %d" %(len(data_loader)))
+ for epoch in range(opt.niter):
+
+ for i, data in enumerate(data_loader):
+ model.total_steps += 1
+
+ model.set_input(data)
+ model.optimize_parameters()
+
+ if model.total_steps % opt.loss_freq == 0:
+ print("Train loss: {} at step: {}".format(model.loss, model.total_steps))
+ train_writer.add_scalar('loss', model.loss, model.total_steps)
+ print("Iter time: ", ((time.time()-start_time)/model.total_steps) )
+
+ if model.total_steps in [10,30,50,100,1000,5000,10000] and False: # save models at these iters
+ model.save_networks('model_iters_%s.pth' % model.total_steps)
+
+ if epoch % opt.save_epoch_freq == 0:
+ print('saving the model at the end of epoch %d' % (epoch))
+ model.save_networks( 'model_epoch_best.pth' )
+ model.save_networks( 'model_epoch_%s.pth' % epoch )
+
+ # Validation
+ model.eval()
+ ap, r_acc, f_acc, acc = validate(model.model, val_loader)
+ val_writer.add_scalar('accuracy', acc, model.total_steps)
+ val_writer.add_scalar('ap', ap, model.total_steps)
+ print("(Val @ epoch {}) acc: {}; ap: {}".format(epoch, acc, ap))
+
+ early_stopping(acc, model)
+ if early_stopping.early_stop:
+ cont_train = model.adjust_learning_rate()
+ if cont_train:
+ print("Learning rate dropped by 10, continue training...")
+ early_stopping = EarlyStopping(patience=opt.earlystop_epoch, delta=-0.002, verbose=True)
+ else:
+ print("Early stopping.")
+ break
+ model.train()
+
diff --git a/clean/video/univfd_video/validate.py b/clean/video/univfd_video/validate.py
new file mode 100644
index 0000000000000000000000000000000000000000..4887014457e584b5801e868a229db98bbd70117c
--- /dev/null
+++ b/clean/video/univfd_video/validate.py
@@ -0,0 +1,312 @@
+import argparse
+from ast import arg
+import os
+import csv
+import torch
+import torchvision.transforms as transforms
+import torch.utils.data
+import numpy as np
+from sklearn.metrics import average_precision_score, precision_recall_curve, accuracy_score
+from torch.utils.data import Dataset
+import sys
+from models import get_model
+from PIL import Image
+import pickle
+from tqdm import tqdm
+from io import BytesIO
+from copy import deepcopy
+from dataset_paths import DATASET_PATHS
+import random
+import shutil
+from scipy.ndimage.filters import gaussian_filter
+
+SEED = 0
+def set_seed():
+ torch.manual_seed(SEED)
+ torch.cuda.manual_seed(SEED)
+ np.random.seed(SEED)
+ random.seed(SEED)
+
+
+MEAN = {
+ "imagenet":[0.485, 0.456, 0.406],
+ "clip":[0.48145466, 0.4578275, 0.40821073]
+}
+
+STD = {
+ "imagenet":[0.229, 0.224, 0.225],
+ "clip":[0.26862954, 0.26130258, 0.27577711]
+}
+
+
+
+
+
+def find_best_threshold(y_true, y_pred):
+ "We assume first half is real 0, and the second half is fake 1"
+
+ N = y_true.shape[0]
+
+ if y_pred[0:N//2].max() <= y_pred[N//2:N].min(): # perfectly separable case
+ return (y_pred[0:N//2].max() + y_pred[N//2:N].min()) / 2
+
+ best_acc = 0
+ best_thres = 0
+ for thres in y_pred:
+ temp = deepcopy(y_pred)
+ temp[temp>=thres] = 1
+ temp[temp= best_acc:
+ best_thres = thres
+ best_acc = acc
+
+ return best_thres
+
+
+
+def png2jpg(img, quality):
+ out = BytesIO()
+ img.save(out, format='jpeg', quality=quality) # ranging from 0-95, 75 is default
+ img = Image.open(out)
+ # load from memory before ByteIO closes
+ img = np.array(img)
+ out.close()
+ return Image.fromarray(img)
+
+
+def gaussian_blur(img, sigma):
+ img = np.array(img)
+
+ gaussian_filter(img[:,:,0], output=img[:,:,0], sigma=sigma)
+ gaussian_filter(img[:,:,1], output=img[:,:,1], sigma=sigma)
+ gaussian_filter(img[:,:,2], output=img[:,:,2], sigma=sigma)
+
+ return Image.fromarray(img)
+
+
+
+def calculate_acc(y_true, y_pred, thres):
+ r_acc = accuracy_score(y_true[y_true==0], y_pred[y_true==0] > thres)
+ f_acc = accuracy_score(y_true[y_true==1], y_pred[y_true==1] > thres)
+ acc = accuracy_score(y_true, y_pred > thres)
+ return r_acc, f_acc, acc
+
+
+def validate(model, loader, find_thres=False):
+
+ with torch.no_grad():
+ y_true, y_pred = [], []
+ print ("Length of dataset: %d" %(len(loader)))
+ for img, label in loader:
+ in_tens = img.cuda()
+
+ y_pred.extend(model(in_tens).sigmoid().flatten().tolist())
+ y_true.extend(label.flatten().tolist())
+
+ y_true, y_pred = np.array(y_true), np.array(y_pred)
+
+ # ================== save this if you want to plot the curves =========== #
+ # torch.save( torch.stack( [torch.tensor(y_true), torch.tensor(y_pred)] ), 'baseline_predication_for_pr_roc_curve.pth' )
+ # exit()
+ # =================================================================== #
+
+ # Get AP
+ ap = average_precision_score(y_true, y_pred)
+
+ # Acc based on 0.5
+ r_acc0, f_acc0, acc0 = calculate_acc(y_true, y_pred, 0.5)
+ if not find_thres:
+ return ap, r_acc0, f_acc0, acc0
+
+
+ # Acc based on the best thres
+ best_thres = find_best_threshold(y_true, y_pred)
+ r_acc1, f_acc1, acc1 = calculate_acc(y_true, y_pred, best_thres)
+
+ return ap, r_acc0, f_acc0, acc0, r_acc1, f_acc1, acc1, best_thres
+
+
+
+
+
+
+# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = #
+
+
+
+
+def recursively_read(rootdir, must_contain, exts=["png", "jpg", "JPEG", "jpeg", "bmp"]):
+ out = []
+ for r, d, f in os.walk(rootdir):
+ for file in f:
+ if (file.split('.')[1] in exts) and (must_contain in os.path.join(r, file)):
+ out.append(os.path.join(r, file))
+ return out
+
+
+def get_list(path, must_contain=''):
+ if ".pickle" in path:
+ with open(path, 'rb') as f:
+ image_list = pickle.load(f)
+ image_list = [ item for item in image_list if must_contain in item ]
+ else:
+ image_list = recursively_read(path, must_contain)
+ return image_list
+
+
+
+
+
+class RealFakeDataset(Dataset):
+ def __init__(self, real_path,
+ fake_path,
+ data_mode,
+ max_sample,
+ arch,
+ jpeg_quality=None,
+ gaussian_sigma=None):
+
+ assert data_mode in ["wang2020", "ours"]
+ self.jpeg_quality = jpeg_quality
+ self.gaussian_sigma = gaussian_sigma
+
+ # = = = = = = data path = = = = = = = = = #
+ if type(real_path) == str and type(fake_path) == str:
+ real_list, fake_list = self.read_path(real_path, fake_path, data_mode, max_sample)
+ else:
+ real_list = []
+ fake_list = []
+ for real_p, fake_p in zip(real_path, fake_path):
+ real_l, fake_l = self.read_path(real_p, fake_p, data_mode, max_sample)
+ real_list += real_l
+ fake_list += fake_l
+
+ self.total_list = real_list + fake_list
+
+
+ # = = = = = = label = = = = = = = = = #
+
+ self.labels_dict = {}
+ for i in real_list:
+ self.labels_dict[i] = 0
+ for i in fake_list:
+ self.labels_dict[i] = 1
+
+ stat_from = "imagenet" if arch.lower().startswith("imagenet") else "clip"
+ self.transform = transforms.Compose([
+ transforms.CenterCrop(224),
+ transforms.ToTensor(),
+ transforms.Normalize( mean=MEAN[stat_from], std=STD[stat_from] ),
+ ])
+
+
+ def read_path(self, real_path, fake_path, data_mode, max_sample):
+
+ if data_mode == 'wang2020':
+ real_list = get_list(real_path, must_contain='0_real')
+ fake_list = get_list(fake_path, must_contain='1_fake')
+ else:
+ real_list = get_list(real_path)
+ fake_list = get_list(fake_path)
+
+
+ if max_sample is not None:
+ if (max_sample > len(real_list)) or (max_sample > len(fake_list)):
+ max_sample = 100
+ print("not enough images, max_sample falling to 100")
+ random.shuffle(real_list)
+ random.shuffle(fake_list)
+ real_list = real_list[0:max_sample]
+ fake_list = fake_list[0:max_sample]
+
+ assert len(real_list) == len(fake_list)
+
+ return real_list, fake_list
+
+
+
+ def __len__(self):
+ return len(self.total_list)
+
+ def __getitem__(self, idx):
+
+ img_path = self.total_list[idx]
+
+ label = self.labels_dict[img_path]
+ img = Image.open(img_path).convert("RGB")
+
+ if self.gaussian_sigma is not None:
+ img = gaussian_blur(img, self.gaussian_sigma)
+ if self.jpeg_quality is not None:
+ img = png2jpg(img, self.jpeg_quality)
+
+ img = self.transform(img)
+ return img, label
+
+
+
+
+
+if __name__ == '__main__':
+
+
+ parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+ parser.add_argument('--real_path', type=str, default=None, help='dir name or a pickle')
+ parser.add_argument('--fake_path', type=str, default=None, help='dir name or a pickle')
+ parser.add_argument('--data_mode', type=str, default=None, help='wang2020 or ours')
+ parser.add_argument('--max_sample', type=int, default=1000, help='only check this number of images for both fake/real')
+
+ parser.add_argument('--arch', type=str, default='res50')
+ parser.add_argument('--ckpt', type=str, default='./pretrained_weights/fc_weights.pth')
+
+ parser.add_argument('--result_folder', type=str, default='result', help='')
+ parser.add_argument('--batch_size', type=int, default=128)
+
+ parser.add_argument('--jpeg_quality', type=int, default=None, help="100, 90, 80, ... 30. Used to test robustness of our model. Not apply if None")
+ parser.add_argument('--gaussian_sigma', type=int, default=None, help="0,1,2,3,4. Used to test robustness of our model. Not apply if None")
+
+
+ opt = parser.parse_args()
+
+
+ if os.path.exists(opt.result_folder):
+ shutil.rmtree(opt.result_folder)
+ os.makedirs(opt.result_folder)
+
+ model = get_model(opt.arch)
+ state_dict = torch.load(opt.ckpt, map_location='cpu')
+ model.fc.load_state_dict(state_dict)
+ print ("Model loaded..")
+ model.eval()
+ model.cuda()
+
+ if (opt.real_path == None) or (opt.fake_path == None) or (opt.data_mode == None):
+ dataset_paths = DATASET_PATHS
+ else:
+ dataset_paths = [ dict(real_path=opt.real_path, fake_path=opt.fake_path, data_mode=opt.data_mode) ]
+
+
+
+ for dataset_path in (dataset_paths):
+ set_seed()
+
+ dataset = RealFakeDataset( dataset_path['real_path'],
+ dataset_path['fake_path'],
+ dataset_path['data_mode'],
+ opt.max_sample,
+ opt.arch,
+ jpeg_quality=opt.jpeg_quality,
+ gaussian_sigma=opt.gaussian_sigma,
+ )
+
+ loader = torch.utils.data.DataLoader(dataset, batch_size=opt.batch_size, shuffle=False, num_workers=4)
+ ap, r_acc0, f_acc0, acc0, r_acc1, f_acc1, acc1, best_thres = validate(model, loader, find_thres=True)
+
+ with open( os.path.join(opt.result_folder,'ap.txt'), 'a') as f:
+ f.write(dataset_path['key']+': ' + str(round(ap*100, 2))+'\n' )
+
+ with open( os.path.join(opt.result_folder,'acc0.txt'), 'a') as f:
+ f.write(dataset_path['key']+': ' + str(round(r_acc0*100, 2))+' '+str(round(f_acc0*100, 2))+' '+str(round(acc0*100, 2))+'\n' )
+