From 99534a610db5ed8ee48a7721d1f7f9aee8c0701d Mon Sep 17 00:00:00 2001 From: shimoda-uec Date: Thu, 4 Jan 2024 13:57:34 +0900 Subject: [PATCH] remove unused files --- .gitignore | 17 - LICENSE | 201 ------ README.md | 121 ---- data/cluster/canvas_aspect_ratio_16.pkl | Bin 213 -> 0 bytes data/cluster/text_angle_16.pkl | Bin 213 -> 0 bytes data/cluster/text_center_x_64.pkl | Bin 408 -> 0 bytes data/cluster/text_center_y_64.pkl | Bin 408 -> 0 bytes data/cluster/text_font_color_64.pkl | Bin 1688 -> 0 bytes data/cluster/text_font_size_16.pkl | Bin 213 -> 0 bytes data/cluster/text_height_16.pkl | Bin 213 -> 0 bytes data/cluster/text_left_64.pkl | Bin 408 -> 0 bytes data/cluster/text_letter_spacing_16.pkl | Bin 213 -> 0 bytes data/cluster/text_line_height_scale_16.pkl | Bin 213 -> 0 bytes data/cluster/text_top_64.pkl | Bin 408 -> 0 bytes data/cluster/text_width_16.pkl | Bin 213 -> 0 bytes .../canvas_embedding_attribute_config.yaml | 0 .../bart/canvas_embedding_flag_config.yaml | 5 - data/config/bart/data_config.yaml | 8 - data/config/bart/metainfo.yaml | 3 - data/config/bart/model_config.yaml | 9 - data/config/bart/test_config.yaml | 4 - ...xt_element_embedding_attribute_config.yaml | 0 .../text_element_embedding_flag_config.yaml | 19 - ...t_element_prediction_attribute_config.yaml | 0 .../text_element_prediction_flag_config.yaml | 9 - data/config/bart/train_config.yaml | 7 - data/font2ttf.pkl | Bin 42614 -> 0 bytes data/fonttype2fontid_fix.pkl | Bin 5797 -> 0 bytes data/svgid2scaleinfo.pkl | Bin 1360839 -> 0 bytes notebooks/score.ipynb | 114 --- pyproject.toml | 50 -- src/typography_generation/__init__.py | 1 - src/typography_generation/__main__.py | 415 ----------- src/typography_generation/config/__init__.py | 1 - .../config/attribute_config.py | 533 -------------- .../config/base_config_object.py | 147 ---- .../config/config_args_util.py | 199 ------ src/typography_generation/config/default.py | 128 ---- src/typography_generation/io/__init__.py | 1 - src/typography_generation/io/build_dataset.py | 85 --- src/typography_generation/io/crello_util.py | 490 ------------- src/typography_generation/io/data_loader.py | 123 ---- src/typography_generation/io/data_object.py | 266 ------- src/typography_generation/io/data_utils.py | 89 --- src/typography_generation/model/__init__.py | 1 - src/typography_generation/model/bart.py | 522 -------------- src/typography_generation/model/baseline.py | 343 --------- src/typography_generation/model/bottleneck.py | 100 --- src/typography_generation/model/canvas_vae.py | 207 ------ src/typography_generation/model/common.py | 446 ------------ src/typography_generation/model/decoder.py | 210 ------ src/typography_generation/model/embedding.py | 407 ----------- src/typography_generation/model/encoder.py | 48 -- src/typography_generation/model/mfc.py | 154 ---- src/typography_generation/model/mlp.py | 175 ----- src/typography_generation/model/model.py | 25 - .../preprocess/__init__.py | 1 - .../preprocess/map_features.py | 280 -------- src/typography_generation/tools/__init__.py | 1 - src/typography_generation/tools/color_func.py | 457 ------------ .../tools/denormalizer.py | 154 ---- src/typography_generation/tools/evaluator.py | 225 ------ src/typography_generation/tools/loss.py | 194 ------ .../tools/prediction_recorder.py | 141 ---- src/typography_generation/tools/sampler.py | 150 ---- src/typography_generation/tools/score_func.py | 657 ------------------ .../tools/structure_preserved_sampler.py | 103 --- src/typography_generation/tools/tokenizer.py | 95 --- src/typography_generation/tools/train.py | 293 -------- .../visualization/__init__.py | 1 - .../visualization/renderer.py | 183 ----- .../visualization/renderer_util.py | 225 ------ .../visualization/visualizer.py | 190 ----- tests/__init__.py | 1 - tests/conftest.py | 92 --- tests/io/__init__.py | 1 - tests/io/test_data_loader.py | 59 -- tests/model/__init__.py | 1 - tests/model/test_model.py | 49 -- tests/test_main.py | 106 --- tests/tool/__init__.py | 1 - tests/tool/test_eval.py | 95 --- tests/tool/test_sample.py | 90 --- .../tool/test_structure_preserved_sampler.py | 49 -- tests/tool/test_train.py | 167 ----- 85 files changed, 9744 deletions(-) delete mode 100644 .gitignore delete mode 100644 LICENSE delete mode 100644 README.md delete mode 100644 data/cluster/canvas_aspect_ratio_16.pkl delete mode 100644 data/cluster/text_angle_16.pkl delete mode 100644 data/cluster/text_center_x_64.pkl delete mode 100644 data/cluster/text_center_y_64.pkl delete mode 100644 data/cluster/text_font_color_64.pkl delete mode 100644 data/cluster/text_font_size_16.pkl delete mode 100644 data/cluster/text_height_16.pkl delete mode 100644 data/cluster/text_left_64.pkl delete mode 100644 data/cluster/text_letter_spacing_16.pkl delete mode 100644 data/cluster/text_line_height_scale_16.pkl delete mode 100644 data/cluster/text_top_64.pkl delete mode 100644 data/cluster/text_width_16.pkl delete mode 100644 data/config/bart/canvas_embedding_attribute_config.yaml delete mode 100644 data/config/bart/canvas_embedding_flag_config.yaml delete mode 100644 data/config/bart/data_config.yaml delete mode 100644 data/config/bart/metainfo.yaml delete mode 100644 data/config/bart/model_config.yaml delete mode 100644 data/config/bart/test_config.yaml delete mode 100644 data/config/bart/text_element_embedding_attribute_config.yaml delete mode 100644 data/config/bart/text_element_embedding_flag_config.yaml delete mode 100644 data/config/bart/text_element_prediction_attribute_config.yaml delete mode 100644 data/config/bart/text_element_prediction_flag_config.yaml delete mode 100644 data/config/bart/train_config.yaml delete mode 100644 data/font2ttf.pkl delete mode 100644 data/fonttype2fontid_fix.pkl delete mode 100644 data/svgid2scaleinfo.pkl delete mode 100644 notebooks/score.ipynb delete mode 100644 pyproject.toml delete mode 100644 src/typography_generation/__init__.py delete mode 100644 src/typography_generation/__main__.py delete mode 100644 src/typography_generation/config/__init__.py delete mode 100644 src/typography_generation/config/attribute_config.py delete mode 100644 src/typography_generation/config/base_config_object.py delete mode 100644 src/typography_generation/config/config_args_util.py delete mode 100644 src/typography_generation/config/default.py delete mode 100644 src/typography_generation/io/__init__.py delete mode 100644 src/typography_generation/io/build_dataset.py delete mode 100644 src/typography_generation/io/crello_util.py delete mode 100644 src/typography_generation/io/data_loader.py delete mode 100644 src/typography_generation/io/data_object.py delete mode 100644 src/typography_generation/io/data_utils.py delete mode 100644 src/typography_generation/model/__init__.py delete mode 100644 src/typography_generation/model/bart.py delete mode 100644 src/typography_generation/model/baseline.py delete mode 100644 src/typography_generation/model/bottleneck.py delete mode 100644 src/typography_generation/model/canvas_vae.py delete mode 100644 src/typography_generation/model/common.py delete mode 100644 src/typography_generation/model/decoder.py delete mode 100644 src/typography_generation/model/embedding.py delete mode 100644 src/typography_generation/model/encoder.py delete mode 100644 src/typography_generation/model/mfc.py delete mode 100644 src/typography_generation/model/mlp.py delete mode 100644 src/typography_generation/model/model.py delete mode 100644 src/typography_generation/preprocess/__init__.py delete mode 100644 src/typography_generation/preprocess/map_features.py delete mode 100644 src/typography_generation/tools/__init__.py delete mode 100644 src/typography_generation/tools/color_func.py delete mode 100644 src/typography_generation/tools/denormalizer.py delete mode 100644 src/typography_generation/tools/evaluator.py delete mode 100644 src/typography_generation/tools/loss.py delete mode 100644 src/typography_generation/tools/prediction_recorder.py delete mode 100644 src/typography_generation/tools/sampler.py delete mode 100644 src/typography_generation/tools/score_func.py delete mode 100644 src/typography_generation/tools/structure_preserved_sampler.py delete mode 100644 src/typography_generation/tools/tokenizer.py delete mode 100644 src/typography_generation/tools/train.py delete mode 100644 src/typography_generation/visualization/__init__.py delete mode 100644 src/typography_generation/visualization/renderer.py delete mode 100644 src/typography_generation/visualization/renderer_util.py delete mode 100644 src/typography_generation/visualization/visualizer.py delete mode 100644 tests/__init__.py delete mode 100644 tests/conftest.py delete mode 100644 tests/io/__init__.py delete mode 100644 tests/io/test_data_loader.py delete mode 100644 tests/model/__init__.py delete mode 100644 tests/model/test_model.py delete mode 100644 tests/test_main.py delete mode 100644 tests/tool/__init__.py delete mode 100644 tests/tool/test_eval.py delete mode 100644 tests/tool/test_sample.py delete mode 100644 tests/tool/test_structure_preserved_sampler.py delete mode 100644 tests/tool/test_train.py diff --git a/.gitignore b/.gitignore deleted file mode 100644 index dfaefa2..0000000 --- a/.gitignore +++ /dev/null @@ -1,17 +0,0 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ - -# Jupyter Notebook -.ipynb_checkpoints - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm -__pypackages__/ - -# Environments -.env -.venv - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json \ No newline at end of file diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 261eeb9..0000000 --- a/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - 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/README.md b/README.md deleted file mode 100644 index cbde2ad..0000000 --- a/README.md +++ /dev/null @@ -1,121 +0,0 @@ -## Paper: Towards Diverse and Consistent Typography Generation -Wataru Shimoda1, Daichi Haraguchi2, Seiichi Uchida2, Kota Yamaguchi1 -1CyberAgent.Inc, 2 Kyushu University -Accepted to WACV2024. -[[Arxiv](https://arxiv.org/abs/2309.02099)] -[[project-page]()] - -## Introduction -This repository contains the codes for ["Towards Diverse and Consistent Typography Generation"](https://arxiv.org/abs/2309.02099). - - - -## Requirements -We check the reproducibility under the environment. -- Ubuntu (>=20.04) -- Python3 (>=3.8) - - -## Install -Clone this repository and navigate to the folder - -``` sh -git clone https://github.com/CyberAgentAILab/tdc-typography-generation.git -cd tdc-typography-generation -``` - -We manage the dependencies of python libraries by [pyproject.toml](https://github.com/CyberAgentAILab/tdc-typography-generation/blob/main/pyproject.toml). -Please install the dependencies via pip or poetry using [pyproject.toml](https://github.com/CyberAgentAILab/tdc-typography-generation/blob/main/pyproject.toml). - - -If the version of setuptools is `setuptools >=61.0.0`, the following command installs the dependencies via pip: -``` sh -pip install . -``` -or -We recommend installing the dependencies using Poetry (see [official docs](https://python-poetry.org/docs/)): -``` sh -poetry install -``` -Note that we omit the head of commands `poetry run` in the after guidance for simplification. - -## Dataset -Our model is trained and tested on [Crello dataset](https://huggingface.co/datasets/cyberagent/crello), and this dataset is open on [Hugging Face](https://huggingface.co/). -We can download this dataset through the [Hugging Face Dataset API](https://huggingface.co/docs/datasets/index), but this dataset does not contain high-resolution background images. - -We provide background images via Google Drive ([link](https://storage.googleapis.com/ailab-public/tdc_typography_generation/generate_bg_png.tar.gz), 3.6GB). -Please download the background images and locate them to `data/generate_bg_png/`. -``` sh -tar zxvf generate_bg_png.tar.gz -mv generate_bg_png data/ -rm generate_bg_png.tar.gz -``` - -We also provide font files for rendering designs and computing appropriate text sizes via Google Drive ([link](https://storage.googleapis.com/ailab-public/tdc_typography_generation/font.tar.gz), 43MB). -Please download the font files and locate them to `data/font/`. -``` sh -tar zxvf font.tar.gz -mv font data/ -rm font.tar.gz -``` - -## Usage -We prepare scripts for experiments as the following. - -### Preprocessing -We recommend adding features to the dataset in advance, it makes training and testing faster. -We provide a script for preprocessing: -``` sh -python -m typography_generation map_features --datadir data -``` -This script extends the dataset via [map function](https://huggingface.co/docs/datasets/v2.15.0/en/package_reference/main_classes#datasets.Dataset.map). -The extended dataset is saved in `data/map_featreus`, and `--use_extended_dataset` option manages the use of the extended dataset. - -### Training -The following command trains a model, it takes a half day with the preprocessed dataset and a NVIDIA T4 machine. -We handle the detail of training via configuration files in `data/config/*.yaml`. -The basic configurations are in `src/typography_generation/config/*.py`. - -``` sh -python -m typography_generation train_eval \ - --configname bart \ - --jobdir ${OUTPUT_DIR} \ - --datadir data \ - --use_extended_dataset \ - --gpu \ -``` -The outputs are in ${OUTPUT_DIR}. - -### Sampling -The following command samples typographic attributes. -This command requires `--weight` option, which is a path for loading weights of a trained model. -A weight file obtained by the avobe training command is in `${OUTPUT_DIR}/weight.pth`. -Please assign a path of a weight file to `${WEIGHT_FILE}`. -``` sh -python -m typography_generation structure_preserved_sample \ - --configname bart \ - --jobdir ${OUTPUT_DIR} \ - --datadir data \ - --weight=${WEIGHT_FILE} \ - --use_extended_dataset \ - --gpu \ -``` - - -## Visualization -We provides notebooks for showing results. -- `notebooks/score.ipnyb` shows scores of the saved results in `${OUTPUT_DIR}`. -- `notebooks/vis.ipnyb` shows generated graphic designs in `${OUTPUT_DIR}`. - -## Reference -```bibtex -@misc{shimoda_2024_tdctg, - author = {Shimoda, Wataru and Haraguchi, Daichi and Uchida, Seiichi and Yamaguchi, Kota}, - title = {Towards Diverse and Consistent Typography Generation}, - publisher = {arXiv:2309.02099}, - year = {2024}, -} -``` - -## Contact -This repository is maintained by Wataru shimoda(wataru_shimoda[at]cyberagent.co.jp). \ No newline at end of file diff --git a/data/cluster/canvas_aspect_ratio_16.pkl b/data/cluster/canvas_aspect_ratio_16.pkl deleted file mode 100644 index 189ec37b6b55e59638222d7d4a1d26687c0d2b61..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 213 zcmZo*nRB6-urJcbVlM+jqS=MYD>hLNLv3H(X0)4h sx!z9V%Rf7{m-hDI8VU9chjQ$vrIy&wjHZQ`)BlP0{dX^mg!OY@3q7+{2nuQdy7+(!`WzGNrQv zBG25zXfwsn&(G^W5P%79hLR~solXouw|scNXWtuh@qHdWe6|6HCfQEVK5e_A_^)ji zi>RH*A`QE59hP=lR$g{Bxsi4m9T|47CY9M~d~LK-6Y8{Mike{85ir9pzGQ)2RLu&z zm}eX8w7hoOT{Aso7Z7pU?!(n9cBQlK*|C+qu=|n!$?gpAZ@XXj{@b}vVYK&8VX=2} zX?E3TP9QcW!0AU`(E4H zrx`ohZ`kT)Z&K=Qe@r~UeuG%3z4!Vk`!7BT_FImm*-vB5v(NlnYHxJ1#XjuTMEjV+ oh4xzhyX`O4ys>}SF67YC?do8*y3Aqoqt_0~X&jDIfFYp=0D#r0p#T5? diff --git a/data/cluster/text_center_y_64.pkl b/data/cluster/text_center_y_64.pkl deleted file mode 100644 index 0eec0ea941f469b489aeb1ebedcd0febc5a3bf50..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 408 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 A1^@s6 diff --git a/data/cluster/text_font_size_16.pkl b/data/cluster/text_font_size_16.pkl deleted file mode 100644 index 3cea5bfc57d78599d808e153431158e32b56ac13..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 213 zcmZo*nRKt3Pv=g>s%D-%{ tdPv&&T(Pp-?44-0Wow7swhhbdUR^z7S9O)izBs|qUPxn#{S=@vdI0o{SG@oL diff --git a/data/cluster/text_height_16.pkl b/data/cluster/text_height_16.pkl deleted file mode 100644 index d00a399fecef244e1a2899f77b08361bc70ee6e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 213 zcmZo*nR#fe|YTJPw3k{ t5f8V!BHd`WIc=65kHro<1@60ch8`UDBE~xQW=aY6b<>a8PXQXE2LMb8Qr!Rm diff --git a/data/cluster/text_left_64.pkl b/data/cluster/text_left_64.pkl deleted file mode 100644 index 5e4dc1c425662aaf3e08e5b9acc0c63041640f51..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 408 zcmZo*ncB<900upxd8N4pm3qnfMX7qZr8y;;iA6<;l~a0n;)_y~^Ye;Jib|79rc9pF z!wOb7rH4H)1)^l~6mN#sDb9>ZQ`)BlP0{dX^mg!OY@3q7+{2nuQdy7+(!`WzGNrQv zBG25zXfwsn&(G^W5P%79hLR~solXouw^XVv+;5`LuzyjC!v2kE@AmNrEZet9F=^k1 z1#0^))ZE(3v9xBdLBr`i3}$-PAEJ-jOjxdNdm|*)mgh&CtU73>7X_3X4AZR}PVc-tv%jkH@TlVMk7S8lgSquK7{{VuzP$Vqm} z3ufB6&s<=~Q?cA`Vc$AC(cN3^x{mCzd$8oN-L40x?9_`c*}dw!Wyc!!*zR!48@sL1 z-|XZjGT1xbVzswD$z>n4i{DCvkuwMmAPYIbM%k> uyJKPw(*$fBCOpe>2r`-Ikhfs1gZsl94!@g49D7uQ9T^xnoTdPc(E|WiyI8CM diff --git a/data/cluster/text_top_64.pkl b/data/cluster/text_top_64.pkl deleted file mode 100644 index e0971268ed2a87cdf3aa70244e1dfc797f634856..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 408 zcmZo*ncB<900upxd8N4pm3qnfMX7qZr8y;;iA6<;l~a0n;)_y~^Ye;Jib|79rc9pF z!wOb7rH4H)1)^l~6mN#sDb9>ZQ`)BlP0{dX^mg!OY@3q7+{2nuQdy7+(!`WzGNrQv zBG25zXfwsn&(G^W5P%79hLR~solXouxA0zYIPif(|G+lQ<@;h-B=#}rFWPOefy?%X zY?ken+p}$tY~F1f<9)-n;{GSwErx7%mre-VJy@k|r+44Pu3(mnoymh>JCFWkyXYsy zb`MWB*{Q|%*tyP}X2n!cNp4!?cymPb{c;{*__rueEim9Ldx40nt qAB|!5&Zna6HUGrfpAAm7H_*+nm&nSskGfcF|F8O-{S;tG=m7vN9Is>m diff --git a/data/cluster/text_width_16.pkl b/data/cluster/text_width_16.pkl deleted file mode 100644 index bedb57705674092d34d50b5dccbcbfc445cc3d73..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 213 zcmZo*nRv%Pjo t**EP3ZGYHJJ;7@)b6e5gNZ8Uo;(egK#QQvZ{oJYcvyZ>Ep8_;S4*--3RssM3 diff --git a/data/config/bart/canvas_embedding_attribute_config.yaml b/data/config/bart/canvas_embedding_attribute_config.yaml deleted file mode 100644 index e69de29..0000000 diff --git a/data/config/bart/canvas_embedding_flag_config.yaml b/data/config/bart/canvas_embedding_flag_config.yaml deleted file mode 100644 index 867fe77..0000000 --- a/data/config/bart/canvas_embedding_flag_config.yaml +++ /dev/null @@ -1,5 +0,0 @@ -canvas_embedding_flag: - canvas_bg_img: False - canvas_bg_img_emb: True - canvas_aspect_ratio: True - canvas_text_num: True diff --git a/data/config/bart/data_config.yaml b/data/config/bart/data_config.yaml deleted file mode 100644 index 097add5..0000000 --- a/data/config/bart/data_config.yaml +++ /dev/null @@ -1,8 +0,0 @@ -data_config: - font_num: 261 - large_spatio_bin: 64 - small_spatio_bin: 16 - color_bin: 64 - max_text_line_count: 50 - font_emb_type: "label" - order_type: "rasterscan_asc" diff --git a/data/config/bart/metainfo.yaml b/data/config/bart/metainfo.yaml deleted file mode 100644 index 91da1d4..0000000 --- a/data/config/bart/metainfo.yaml +++ /dev/null @@ -1,3 +0,0 @@ -meta_info: - model_name: "bart" - dataset: "crello" diff --git a/data/config/bart/model_config.yaml b/data/config/bart/model_config.yaml deleted file mode 100644 index 6f5a014..0000000 --- a/data/config/bart/model_config.yaml +++ /dev/null @@ -1,9 +0,0 @@ -model_config: - d_model: 256 - num_encoder_layers: 8 - num_decoder_layers: 8 - n_head: 8 - dropout: 0.1 - bert_dim: 768 - clip_dim: 512 - mlp_dim: 1792 diff --git a/data/config/bart/test_config.yaml b/data/config/bart/test_config.yaml deleted file mode 100644 index 1831047..0000000 --- a/data/config/bart/test_config.yaml +++ /dev/null @@ -1,4 +0,0 @@ -test_config: - sampling_param: 0.9 - sampling_param_geometry: 0.1 - sampling_param_semantic: 0.9 diff --git a/data/config/bart/text_element_embedding_attribute_config.yaml b/data/config/bart/text_element_embedding_attribute_config.yaml deleted file mode 100644 index e69de29..0000000 diff --git a/data/config/bart/text_element_embedding_flag_config.yaml b/data/config/bart/text_element_embedding_flag_config.yaml deleted file mode 100644 index 119d966..0000000 --- a/data/config/bart/text_element_embedding_flag_config.yaml +++ /dev/null @@ -1,19 +0,0 @@ -text_element_embedding_flag: - text_font: False - text_font_size: False - text_font_color: False - text_angle: False - text_letter_spacing: False - text_line_height_scale: False - text_capitalize: False - text_line_count: True - text_char_count: True - text_height: False - text_width: False - text_top: False - text_left: False - text_center_y: True - text_center_x: True - text_align_type: False - text_emb: True - text_local_img_emb: True diff --git a/data/config/bart/text_element_prediction_attribute_config.yaml b/data/config/bart/text_element_prediction_attribute_config.yaml deleted file mode 100644 index e69de29..0000000 diff --git a/data/config/bart/text_element_prediction_flag_config.yaml b/data/config/bart/text_element_prediction_flag_config.yaml deleted file mode 100644 index dda973f..0000000 --- a/data/config/bart/text_element_prediction_flag_config.yaml +++ /dev/null @@ -1,9 +0,0 @@ -text_element_prediction_flag: - text_font: True - text_font_size: True - text_font_color: True - text_angle: True - text_letter_spacing: True - text_line_height_scale: True - text_capitalize: True - text_align_type: True diff --git a/data/config/bart/train_config.yaml b/data/config/bart/train_config.yaml deleted file mode 100644 index 12780fd..0000000 --- a/data/config/bart/train_config.yaml +++ /dev/null @@ -1,7 +0,0 @@ -train_config: - epochs: 31 - save_epoch: 5 - batch_size: 32 - num_worker: 2 - train_only: False - show_interval: 100 diff --git a/data/font2ttf.pkl b/data/font2ttf.pkl deleted file mode 100644 index 9903ce61bcd8696440c629714e486d9086481c9e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 42614 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 diff --git a/data/fonttype2fontid_fix.pkl b/data/fonttype2fontid_fix.pkl deleted file mode 100644 index f2ea1a4a0a9ed9e4b1fd207cdf17e9f6798992f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5797 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νVB*}34EyEth*2xvi@ekVywM5T8%GVav7 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 z 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 Q(c||6CpCUhr3reP*~Aa1dH$i1(TBF5lSG$E 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

ooYQkSHAg4J=08-Oo(%qgyk~ZGv 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 diff --git a/notebooks/score.ipynb b/notebooks/score.ipynb deleted file mode 100644 index 8363651..0000000 --- a/notebooks/score.ipynb +++ /dev/null @@ -1,114 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "18.186068109361116\n", - "59.10895250864158\n", - "89.43196472690855\n", - "99.98559492941517\n", - "29.720623040124977\n", - "0.381246451385764\n", - "2.807381701892659\n", - "0.07559504299962953\n" - ] - } - ], - "source": [ - "import os\n", - "from matplotlib import pylab as plt\n", - "import numpy as np\n", - "import statistics\n", - "import math\n", - "\n", - "def get_score(prefix, score_index, scalar):\n", - " tmppath = f\"{prefix}/logs/score.txt\"\n", - " with open(tmppath) as f:\n", - " scores = f.readlines()\n", - " score = scores[score_index].replace('\\n', '').split(\" \")[-2]\n", - " score = float(score)*scalar\n", - " return score\n", - "\n", - "def get_structure_score(prefix, score_index,scalar,type=None):\n", - " gcspath = f\"gs://ailab-ephemeral/s09275/job_gcp_eval/{prefix}/logs/score.txt\"\n", - " _prefix = prefix.split(\"/\")[-1]\n", - " tmppath = f\"tmp_data/dl/{_prefix}.txt\"\n", - " com = f\"gsutil cp {gcspath} {tmppath}\"\n", - " if os.path.isfile(tmppath) is False:\n", - " os.system(com)\n", - " with open(tmppath) as f:\n", - " scores = f.readlines()\n", - " score0 = scores[score_index].replace('\\n', '').split(\" \")[-2]\n", - " score0 = float(score0)*scalar\n", - " count0 = int(scores[score_index].replace('\\n', '').split(\" \")[-3].split(\":\")[-1])\n", - " score1 = scores[score_index+1].replace('\\n', '').split(\" \")[-2]\n", - " score1 = float(score1)*scalar\n", - " count1 = int(scores[score_index+1].replace('\\n', '').split(\" \")[-3].split(\":\")[-1])\n", - " score2 = scores[score_index+2].replace('\\n', '').split(\" \")[-2]\n", - " score2 = float(score2)*scalar\n", - " count2 = int(scores[score_index+2].replace('\\n', '').split(\" \")[-3].split(\":\")[-1])\n", - " if type is None:\n", - " count = float(count0+count1+count2)\n", - " score = score0*count0/count + score1*count1/count + score2*count2/count\n", - " #print(count0,count1,count2)\n", - " elif type==0:\n", - " score = score0\n", - " elif type==1:\n", - " score = score1\n", - " elif type==2:\n", - " score = score2\n", - " return score\n", - "\n", - "output_dir = \"tmp\" # please set your output directory here\n", - "tarscore2index1={\n", - " \"font_score\": (1,100,\"a\"),\n", - " \"font_color_score\": (25,1,\"a\"),\n", - " \"font_capitalize_score\": (9,100,\"a\"),\n", - " \"font_align_score\": (5,100,\"a\"),\n", - " \"font_size_score\": (13,1,\"a\"),\n", - " \"font_angle_score\": (19,1,\"b\"),\n", - " \"font_letter_score\": (16,1,\"b\"),\n", - " \"font_lline_height_score\": (22,1,\"c\"),\n", - "}\n", - "for att, (index,k, type) in tarscore2index1.items():\n", - "\n", - " font_score = get_score(output_dir, index,k)\n", - " print(font_score)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": ".venv", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.1" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 30a21d2..0000000 --- a/pyproject.toml +++ /dev/null @@ -1,50 +0,0 @@ -[tool.pysen] -version = "0.9" - -[tool.pysen.lint] -enable_black = true -enable_flake8 = true -enable_isort = true -enable_mypy = true -mypy_preset = "strict" -line_length = 88 -[tool.pysen.lint.source] - excludes = [".venv/",".git/", ".pytest_cache/", ".python-version/","data","tmp_data/"] -[[tool.pysen.lint.mypy_targets]] - paths = ["."] - -[tool.poetry] -name = "typography-generation" -version = "0.1.0" -description = "" -authors = ["shimoda-uec "] -readme = "README.md" -packages = [{include = "typography_generation", from = "src"}] - - -[tool.poetry.dependencies] -python = "^3.9" -skia-python = "^87.5" -einops = "^0.6.1" -hydra-core = "^1.3.2" -logzero = "^1.7.0" -datasets = "^2.12.0" -torch = "^1.13" -scikit-learn = "^1.0" -pytest = "^7.3.1" -pillow = "9.0.1" -matplotlib = "3.5" -transformers = "4.30.2" -openpyxl = "^3.1.2" -tensorboard = "^2.14.1" -gcsfs = "^2023.9.2" -seam-carving = "^1.1.0" - - -[tool.poetry.group.dev.dependencies] -jupyter = "^1.0.0" -notebook = "^6.5.4" - -[build-system] -requires = ["poetry-core"] -build-backend = "poetry.core.masonry.api" diff --git a/src/typography_generation/__init__.py b/src/typography_generation/__init__.py deleted file mode 100644 index 8b13789..0000000 --- a/src/typography_generation/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/typography_generation/__main__.py b/src/typography_generation/__main__.py deleted file mode 100644 index 6303516..0000000 --- a/src/typography_generation/__main__.py +++ /dev/null @@ -1,415 +0,0 @@ -import argparse -import logging -import os -from typing import Any, Dict, Tuple - -import logzero -import torch -from logzero import logger -from typography_generation.config.config_args_util import ( - args2add_data_inputs, - get_global_config, - get_global_config_input, - get_model_config_input, - get_prefix_lists, - get_sampling_config, - get_train_config_input, -) -from typography_generation.config.default import ( - get_datapreprocess_config, - get_font_config, -) -from typography_generation.io.build_dataset import ( - build_test_dataset, - build_train_dataset, -) -from typography_generation.model.model import create_model - -from typography_generation.preprocess.map_features import map_features - -from typography_generation.tools.evaluator import Evaluator - -from typography_generation.tools.sampler import Sampler -from typography_generation.tools.structure_preserved_sampler import ( - StructurePreservedSampler, -) -from typography_generation.tools.train import Trainer - - -def get_save_dir(job_dir: str) -> str: - save_dir = os.path.join(job_dir, "logs") - os.makedirs(save_dir, exist_ok=True) - return save_dir - - -def make_logfile(job_dir: str, debug: bool = False) -> None: - if debug is True: - logzero.loglevel(logging.DEBUG) - else: - logzero.loglevel(logging.INFO) - - os.makedirs(job_dir, exist_ok=True) - file_name = f"{job_dir}/log.log" - logzero.logfile(file_name) - - -def train(args: Any) -> None: - logger.info("training") - data_dir = args.datadir - global_config_input = get_global_config_input(data_dir, args) - config = get_global_config(**global_config_input) - gpu = args.gpu - model_name, model_kwargs = get_model_config_input(config) - - logger.info("model creation") - model = create_model( - model_name, - **model_kwargs, - ) - - logger.info(f"log file location {args.jobdir}/log.log") - make_logfile(args.jobdir, args.debug) - save_dir = get_save_dir(args.jobdir) - logger.info(f"save_dir {save_dir}") - prefix_list_object = get_prefix_lists(config) - font_config = get_font_config(config) - prediction_config_element = config.text_element_prediction_attribute_config - - train_kwargs = get_train_config_input(config, args.debug) - logger.info(f"build trainer") - dataset, dataset_val = build_train_dataset( - data_dir, - prefix_list_object, - font_config, - use_extended_dataset=args.use_extended_dataset, - debug=args.debug, - ) - - model_trainer = Trainer( - model, - gpu, - save_dir, - dataset, - dataset_val, - prefix_list_object, - prediction_config_element, - **train_kwargs, - ) - logger.info("start training") - model_trainer.train_model() - - -def train_eval(args: Any) -> None: - logger.info("training") - data_dir = args.datadir - global_config_input = get_global_config_input(data_dir, args) - config = get_global_config(**global_config_input) - gpu = args.gpu - model_name, model_kwargs = get_model_config_input(config) - - logger.info("model creation") - model = create_model( - model_name, - **model_kwargs, - ) - - logger.info(f"log file location {args.jobdir}/log.log") - make_logfile(args.jobdir, args.debug) - save_dir = get_save_dir(args.jobdir) - logger.info(f"save_dir {save_dir}") - prefix_list_object = get_prefix_lists(config) - font_config = get_font_config(config) - prediction_config_element = config.text_element_prediction_attribute_config - - train_kwargs = get_train_config_input(config, args.debug) - logger.info(f"build trainer") - - dataset, dataset_val = build_train_dataset( - data_dir, - prefix_list_object, - font_config, - use_extended_dataset=args.use_extended_dataset, - debug=args.debug, - ) - - model_trainer = Trainer( - model, - gpu, - save_dir, - dataset, - dataset_val, - prefix_list_object, - prediction_config_element, - **train_kwargs, - ) - logger.info("start training") - model_trainer.train_model() - - dataset = build_test_dataset( - data_dir, - prefix_list_object, - font_config, - use_extended_dataset=args.use_extended_dataset, - debug=args.debug, - ) - - evaluator = Evaluator( - model, - gpu, - save_dir, - dataset, - prefix_list_object, - debug=args.debug, - ) - logger.info("start evaluation") - evaluator.eval_model() - - -# def _train_font_embedding(args: Any) -> None: -# train_font_embedding(args.datadir, args.jobdir, args.gpu) - - -def loadweight(weight_file: Any, gpu: bool, model: Any) -> Any: - if weight_file == "": - pass - else: - if gpu is False: - state_dict = torch.load(weight_file, map_location=torch.device("cpu")) - else: - state_dict = torch.load(weight_file) - model.load_state_dict(state_dict) - return model - - -def sample(args: Any) -> None: - data_dir = args.datadir - global_config_input = get_global_config_input(data_dir, args) - config = get_global_config(**global_config_input) - gpu = args.gpu - model_name, model_kwargs = get_model_config_input(config) - - logger.info("model creation") - model = create_model( - model_name, - **model_kwargs, - ) - weight = args.weight - model = loadweight(weight, gpu, model) - - logger.info(f"log file location {args.jobdir}/log.log") - make_logfile(args.jobdir, args.debug) - save_dir = get_save_dir(args.jobdir) - logger.info(f"save_dir {save_dir}") - prefix_list_object = get_prefix_lists(config) - font_config = get_font_config(config) - sampling_config = get_sampling_config(config) - - dataset = build_test_dataset( - data_dir, - prefix_list_object, - font_config, - use_extended_dataset=args.use_extended_dataset, - debug=args.debug, - ) - - sampler = Sampler( - model, - gpu, - save_dir, - dataset, - prefix_list_object, - sampling_config, - debug=args.debug, - ) - logger.info("start sampling") - sampler.sample() - - -def structure_preserved_sample(args: Any) -> None: - data_dir = args.datadir - global_config_input = get_global_config_input(data_dir, args) - config = get_global_config(**global_config_input) - gpu = args.gpu - model_name, model_kwargs = get_model_config_input(config) - - logger.info("model creation") - model = create_model( - model_name, - **model_kwargs, - ) - weight = args.weight - model = loadweight(weight, gpu, model) - - logger.info(f"log file location {args.jobdir}/log.log") - make_logfile(args.jobdir, args.debug) - save_dir = get_save_dir(args.jobdir) - logger.info(f"save_dir {save_dir}") - prefix_list_object = get_prefix_lists(config) - font_config = get_font_config(config) - sampling_config = get_sampling_config(config) - - dataset = build_test_dataset( - data_dir, - prefix_list_object, - font_config, - use_extended_dataset=args.use_extended_dataset, - debug=args.debug, - ) - - sampler = StructurePreservedSampler( - model, - gpu, - save_dir, - dataset, - prefix_list_object, - sampling_config, - debug=args.debug, - ) - logger.info("start sampling") - sampler.sample() - - -def evaluation_pattern(args: Any, prefix: str, evaluation_class: Any) -> None: - logger.info(f"{prefix}") - data_dir = args.datadir - global_config_input = get_global_config_input(data_dir, args) - config = get_global_config(**global_config_input) - gpu = args.gpu - model_name, model_kwargs = get_model_config_input(config) - - logger.info("model creation") - model = create_model( - model_name, - **model_kwargs, - ) - weight = args.weight - model = loadweight(weight, gpu, model) - - logger.info(f"log file location {args.jobdir}/log.log") - make_logfile(args.jobdir, args.debug) - save_dir = get_save_dir(args.jobdir) - logger.info(f"save_dir {save_dir}") - prefix_list_object = get_prefix_lists(config) - font_config = get_font_config(config) - - dataset = build_test_dataset( - data_dir, - prefix_list_object, - font_config, - use_extended_dataset=args.use_extended_dataset, - debug=args.debug, - ) - evaluator = evaluation_class( - model, - gpu, - save_dir, - dataset, - prefix_list_object, - dataset_division="test", - debug=args.debug, - ) - logger.info("start evaluation") - evaluator.eval_model() - - -def evaluation(args: Any) -> None: - evaluation_pattern(args, "evaluation", Evaluator) - - -def _map_features(args: Any) -> None: - logger.info(f"map_features") - map_features(args.datadir) - - -COMMANDS = { - "train": train, - "train_evaluation": train_eval, - "sample": sample, - "structure_preserved_sample": structure_preserved_sample, - "evaluation": evaluation, - "map_features": _map_features, -} - - -if __name__ == "__main__": - logger.info("start") - parser = argparse.ArgumentParser() - parser.add_argument("command", help="job option") - parser.add_argument( - "--configname", - type=str, - default="bart", - help="config option", - ) - parser.add_argument( - "--testconfigname", - type=str, - default="test_config", - help="test config option", - ) - parser.add_argument( - "--modelconfigname", - type=str, - default="model_config", - help="test config option", - ) - parser.add_argument( - "--canvasembeddingflagconfigname", - type=str, - default="canvas_embedding_flag_config", - help="canvas embedding flag config option", - ) - parser.add_argument( - "--elementembeddingflagconfigname", - type=str, - default="text_element_embedding_flag_config", - help="element embedding flag config option", - ) - parser.add_argument( - "--elementpredictionflagconfigname", - type=str, - default="text_element_prediction_flag_config", - help="element prediction flag config option", - ) - parser.add_argument( - "--datadir", - type=str, - default="data", - help="data location", - ) - parser.add_argument( - "--jobdir", - type=str, - default=".", - help="results location", - ) - parser.add_argument( - "--job-dir", - type=str, - default=".", - help="dummy", - ) - parser.add_argument( - "--weight", - type=str, - default="", - help="weight file location", - ) - parser.add_argument( - "--gpu", - action="store_true", - help="gpu option", - ) - parser.add_argument( - "--use_extended_dataset", - action="store_true", - help="dataset option", - ) - parser.add_argument( - "--debug", - action="store_true", - help="debug option", - ) - args = parser.parse_args() - module = COMMANDS[args.command] - module(args) diff --git a/src/typography_generation/config/__init__.py b/src/typography_generation/config/__init__.py deleted file mode 100644 index 8b13789..0000000 --- a/src/typography_generation/config/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/typography_generation/config/attribute_config.py b/src/typography_generation/config/attribute_config.py deleted file mode 100644 index 8e15c20..0000000 --- a/src/typography_generation/config/attribute_config.py +++ /dev/null @@ -1,533 +0,0 @@ -from dataclasses import dataclass -from typing import Any, Union - - -@dataclass -class EmbeddingConfig: - flag: bool = True - inp_space: int = 256 - input_prefix: str = "prefix" - emb_layer: Union[str, None] = "nn.Embedding" - emb_layer_kwargs: Any = None - specific_build: Union[str, None] = None - specific_func: Union[str, None] = None - - -@dataclass -class PredictionConfig: - flag: bool = True - out_dim: int = 256 - layer: Union[str, None] = "nn.Linear" - loss_type: str = "cre" - loss_weight: float = 1.0 - ignore_label: int = -1 - decode_format: str = "cl" - att_type: str = "semantic" - - -@dataclass -class TextElementContextPredictionAttributeConfig: - text_font: PredictionConfig = PredictionConfig( - "${text_element_prediction_flag.text_font}", - "${data_config.font_num}", - "nn.Linear", - "cre", - 1.0, - -1, - "cl", - "semantic", - ) - text_font_emb: PredictionConfig = PredictionConfig( - "${text_element_prediction_flag.text_font_emb}", - "${data_config.font_emb_dim}", - "nn.Linear", - "mfc_gan", - 1.0, - -10000, - "emb", - "semantic", - ) - text_font_size: PredictionConfig = PredictionConfig( - "${text_element_prediction_flag.text_font_size}", - "${data_config.small_spatio_bin}", - "nn.Linear", - "cre", - 1.0, - -1, - "cl", - "geometry", - ) - text_font_size_raw: PredictionConfig = PredictionConfig( - "${text_element_prediction_flag.text_font_size_raw}", - "1", - "nn.Linear", - "l1", - 1.0, - -1, - "scalar", - "geometry", - ) - text_font_color: PredictionConfig = PredictionConfig( - "${text_element_prediction_flag.text_font_color}", - "${data_config.color_bin}", - "nn.Linear", - "cre", - 1.0, - -1, - "cl", - "semantic", - ) - text_angle: PredictionConfig = PredictionConfig( - "${text_element_prediction_flag.text_angle}", - "${data_config.small_spatio_bin}", - "nn.Linear", - "cre", - 1.0, - -1, - "cl", - "geometry", - ) - text_letter_spacing: PredictionConfig = PredictionConfig( - "${text_element_prediction_flag.text_letter_spacing}", - "${data_config.small_spatio_bin}", - "nn.Linear", - "cre", - 1.0, - -1, - "cl", - "geometry", - ) - text_line_height_scale: PredictionConfig = PredictionConfig( - "${text_element_prediction_flag.text_line_height_scale}", - "${data_config.small_spatio_bin}", - "nn.Linear", - "cre", - 1.0, - -1, - "cl", - "geometry", - ) - text_line_height_size: PredictionConfig = PredictionConfig( - "${text_element_prediction_flag.text_line_height_size}", - "${data_config.small_spatio_bin}", - "nn.Linear", - "cre", - 1.0, - -1, - "cl", - "geometry", - ) - text_capitalize: PredictionConfig = PredictionConfig( - "${text_element_prediction_flag.text_capitalize}", - 2, - "nn.Linear", - "cre", - 1.0, - -1, - "cl", - "semantic", - ) - text_align_type: PredictionConfig = PredictionConfig( - "${text_element_prediction_flag.text_align_type}", - 3, - "nn.Linear", - "cre", - 1.0, - -1, - "cl", - "semantic", - ) - text_center_y: PredictionConfig = PredictionConfig( - "${text_element_prediction_flag.text_center_y}", - "${data_config.large_spatio_bin}", - "nn.Linear", - "cre", - 1.0, - -1, - "cl", - "geometry", - ) - text_center_x: PredictionConfig = PredictionConfig( - "${text_element_prediction_flag.text_center_x}", - "${data_config.large_spatio_bin}", - "nn.Linear", - "cre", - 1.0, - -1, - "cl", - "geometry", - ) - text_height: PredictionConfig = PredictionConfig( - "${text_element_prediction_flag.text_height}", - "${data_config.small_spatio_bin}", - "nn.Linear", - "cre", - 1.0, - -1, - "cl", - "geometry", - ) - text_width: PredictionConfig = PredictionConfig( - "${text_element_prediction_flag.text_width}", - "${data_config.large_spatio_bin}", - "nn.Linear", - "cre", - 1.0, - -1, - "cl", - "geometry", - ) - - -@dataclass -class TextElementContextEmbeddingAttributeConfig: - text_font: EmbeddingConfig = EmbeddingConfig( - "${text_element_embedding_flag.text_font}", - "${data_config.font_num}", - "text_font", - "nn.Embedding", - { - "num_embeddings": "${data_config.font_num}", - "embedding_dim": "${model_config.d_model}", - }, - None, - None, - ) - text_font_size: EmbeddingConfig = EmbeddingConfig( - "${text_element_embedding_flag.text_font_size}", - "${data_config.small_spatio_bin}", - "text_font_size", - "nn.Embedding", - { - "num_embeddings": "${data_config.small_spatio_bin}", - "embedding_dim": "${model_config.d_model}", - }, - None, - None, - ) - text_font_size_raw: EmbeddingConfig = EmbeddingConfig( - "${text_element_embedding_flag.text_font_size_raw}", - "${data_config.small_spatio_bin}", - "text_font_size", - "nn.Embedding", - { - "num_embeddings": "${data_config.small_spatio_bin}", - "embedding_dim": "${model_config.d_model}", - }, - None, - None, - ) - text_font_color: EmbeddingConfig = EmbeddingConfig( - "${text_element_embedding_flag.text_font_color}", - "${data_config.color_bin}", - "text_font_color", - "nn.Embedding", - { - "num_embeddings": "${data_config.color_bin}", - "embedding_dim": "${model_config.d_model}", - }, - None, - None, - ) - text_line_count: EmbeddingConfig = EmbeddingConfig( - "${text_element_embedding_flag.text_line_count}", - "${data_config.max_text_line_count}", - "text_line_count", - "nn.Embedding", - { - "num_embeddings": "${data_config.max_text_line_count}", - "embedding_dim": "${model_config.d_model}", - }, - None, - None, - ) - text_char_count: EmbeddingConfig = EmbeddingConfig( - "${text_element_embedding_flag.text_char_count}", - "${data_config.max_text_char_count}", - "text_char_count", - "nn.Embedding", - { - "num_embeddings": "${data_config.max_text_char_count}", - "embedding_dim": "${model_config.d_model}", - }, - None, - None, - ) - text_height: EmbeddingConfig = EmbeddingConfig( - "${text_element_embedding_flag.text_height}", - "${data_config.large_spatio_bin}", - "text_height", - "nn.Embedding", - { - "num_embeddings": "${data_config.large_spatio_bin}", - "embedding_dim": "${model_config.d_model}", - }, - None, - None, - ) - text_width: EmbeddingConfig = EmbeddingConfig( - "${text_element_embedding_flag.text_width}", - "${data_config.large_spatio_bin}", - "text_width", - "nn.Embedding", - { - "num_embeddings": "${data_config.large_spatio_bin}", - "embedding_dim": "${model_config.d_model}", - }, - None, - None, - ) - text_top: EmbeddingConfig = EmbeddingConfig( - "${text_element_embedding_flag.text_top}", - "${data_config.large_spatio_bin}", - "text_top", - "nn.Embedding", - { - "num_embeddings": "${data_config.large_spatio_bin}", - "embedding_dim": "${model_config.d_model}", - }, - None, - None, - ) - text_left: EmbeddingConfig = EmbeddingConfig( - "${text_element_embedding_flag.text_left}", - "${data_config.large_spatio_bin}", - "text_left", - "nn.Embedding", - { - "num_embeddings": "${data_config.large_spatio_bin}", - "embedding_dim": "${model_config.d_model}", - }, - None, - None, - ) - text_center_y: EmbeddingConfig = EmbeddingConfig( - "${text_element_embedding_flag.text_center_y}", - "${data_config.large_spatio_bin}", - "text_center_y", - "nn.Embedding", - { - "num_embeddings": "${data_config.large_spatio_bin}", - "embedding_dim": "${model_config.d_model}", - }, - None, - None, - ) - text_center_x: EmbeddingConfig = EmbeddingConfig( - "${text_element_embedding_flag.text_center_x}", - "${data_config.large_spatio_bin}", - "text_center_x", - "nn.Embedding", - { - "num_embeddings": "${data_config.large_spatio_bin}", - "embedding_dim": "${model_config.d_model}", - }, - None, - None, - ) - text_align_type: EmbeddingConfig = EmbeddingConfig( - "${text_element_embedding_flag.text_align_type}", - "3", - "text_align_type", - "nn.Embedding", - { - "num_embeddings": "3", - "embedding_dim": "${model_config.d_model}", - }, - None, - None, - ) - text_angle: EmbeddingConfig = EmbeddingConfig( - "${text_element_embedding_flag.text_angle}", - "${data_config.small_spatio_bin}", - "text_angle", - "nn.Embedding", - { - "num_embeddings": "${data_config.small_spatio_bin}", - "embedding_dim": "${model_config.d_model}", - }, - None, - None, - ) - text_letter_spacing: EmbeddingConfig = EmbeddingConfig( - "${text_element_embedding_flag.text_letter_spacing}", - "${data_config.small_spatio_bin}", - "text_letter_spacing", - "nn.Embedding", - { - "num_embeddings": "${data_config.small_spatio_bin}", - "embedding_dim": "${model_config.d_model}", - }, - None, - None, - ) - text_line_height_scale: EmbeddingConfig = EmbeddingConfig( - "${text_element_embedding_flag.text_line_height_scale}", - "${data_config.small_spatio_bin}", - "text_line_height_scale", - "nn.Embedding", - { - "num_embeddings": "${data_config.small_spatio_bin}", - "embedding_dim": "${model_config.d_model}", - }, - None, - None, - ) - text_line_height_size: EmbeddingConfig = EmbeddingConfig( - "${text_element_embedding_flag.text_line_height_size}", - "${data_config.small_spatio_bin}", - "text_line_height_size", - "nn.Embedding", - { - "num_embeddings": "${data_config.small_spatio_bin}", - "embedding_dim": "${model_config.d_model}", - }, - None, - None, - ) - - text_capitalize: EmbeddingConfig = EmbeddingConfig( - "${text_element_embedding_flag.text_capitalize}", - "2", - "text_capitalize", - "nn.Embedding", - { - "num_embeddings": "2", - "embedding_dim": "${model_config.d_model}", - }, - None, - None, - ) - text_emb: EmbeddingConfig = EmbeddingConfig( - "${text_element_embedding_flag.text_emb}", - "${model_config.clip_dim}", - "text_emb", - "nn.Linear", - { - "in_features": "${model_config.clip_dim}", - "out_features": "${model_config.d_model}", - }, - None, - None, - ) - text_local_img_emb: EmbeddingConfig = EmbeddingConfig( - "${text_element_embedding_flag.text_local_img_emb}", - "${model_config.clip_dim}", - "text_local_img_emb", - "nn.Linear", - { - "in_features": "${model_config.clip_dim}", - "out_features": "${model_config.d_model}", - }, - None, - None, - ) - - -@dataclass -class CanvasContextEmbeddingAttributeConfig: - canvas_bg_img: EmbeddingConfig = EmbeddingConfig( - "${canvas_embedding_flag.canvas_bg_img}", - 2048, - "canvas_bg_img", - None, - None, - "build_resnet_feat_extractor", - "get_feat", - ) - canvas_aspect_ratio: EmbeddingConfig = EmbeddingConfig( - "${canvas_embedding_flag.canvas_aspect_ratio}", - "${data_config.small_spatio_bin}", - "canvas_aspect_ratio", - "nn.Embedding", - { - "num_embeddings": "${data_config.small_spatio_bin}", - "embedding_dim": "${model_config.d_model}", - }, - None, - None, - ) - canvas_text_num: EmbeddingConfig = EmbeddingConfig( - "${canvas_embedding_flag.canvas_text_num}", - 50, - "canvas_text_num", - "nn.Embedding", - { - "num_embeddings": 50, - "embedding_dim": "${model_config.d_model}", - }, - None, - None, - ) - canvas_group: EmbeddingConfig = EmbeddingConfig( - "${canvas_embedding_flag.canvas_group}", - 6, - "canvas_group", - "nn.Embedding", - { - "num_embeddings": 6, - "embedding_dim": "${model_config.d_model}", - }, - None, - None, - ) - canvas_format: EmbeddingConfig = EmbeddingConfig( - "${canvas_embedding_flag.canvas_format}", - 67, - "canvas_format", - "nn.Embedding", - { - "num_embeddings": 67, - "embedding_dim": "${model_config.d_model}", - }, - None, - None, - ) - canvas_category: EmbeddingConfig = EmbeddingConfig( - "${canvas_embedding_flag.canvas_category}", - 23, - "canvas_category", - "nn.Embedding", - { - "num_embeddings": 23, - "embedding_dim": "${model_config.d_model}", - }, - None, - None, - ) - canvas_height: EmbeddingConfig = EmbeddingConfig( - "${canvas_embedding_flag.canvas_height}", - 46, - "canvas_height", - "nn.Embedding", - { - "num_embeddings": 46, - "embedding_dim": "${model_config.d_model}", - }, - None, - None, - ) - canvas_width: EmbeddingConfig = EmbeddingConfig( - "${canvas_embedding_flag.canvas_width}", - 41, - "canvas_width", - "nn.Embedding", - { - "num_embeddings": 41, - "embedding_dim": "${model_config.d_model}", - }, - None, - None, - ) - canvas_bg_img_emb: EmbeddingConfig = EmbeddingConfig( - "${canvas_embedding_flag.canvas_bg_img_emb}", - "${model_config.clip_dim}", - "canvas_bg_img_emb", - "nn.Linear", - { - "in_features": "${model_config.clip_dim}", - "out_features": "${model_config.d_model}", - }, - None, - "canvas_bg_img_emb_layer", - ) diff --git a/src/typography_generation/config/base_config_object.py b/src/typography_generation/config/base_config_object.py deleted file mode 100644 index ece0512..0000000 --- a/src/typography_generation/config/base_config_object.py +++ /dev/null @@ -1,147 +0,0 @@ -from dataclasses import dataclass -from typography_generation.config.attribute_config import ( - CanvasContextEmbeddingAttributeConfig, - TextElementContextEmbeddingAttributeConfig, - TextElementContextPredictionAttributeConfig, -) - - -@dataclass -class MetaInfo: - model_name: str = "bart" - dataset: str = "crello" - data_dir: str = "crello" - - -@dataclass -class DataConfig: - font_num: int = 288 - large_spatio_bin: int = 64 - small_spatio_bin: int = 16 - color_bin: int = 64 - max_text_char_count: int = 50 - max_text_line_count: int = 50 - font_emb_type: str = "label" - font_emb_weight: float = 1.0 - font_emb_dim: int = 40 - font_emb_name: str = "mfc" - order_type: str = "raster_scan_order" - seq_length: int = 50 - - -@dataclass -class ModelConfig: - d_model: int = 256 - num_encoder_layers: int = 4 - num_decoder_layers: int = 4 - n_head: int = 8 - dropout: float = 0.1 - bert_dim: int = 768 - clip_dim: int = 512 - mlp_dim: int = 3584 - mfc_dim: int = 3584 - bypass: bool = True - seq_length: int = 50 - std_ratio: float = 1.0 - - -@dataclass -class TrainConfig: - epochs: int = 31 - save_epoch: int = 5 - batch_size: int = 32 - num_worker: int = 2 - train_only: bool = False - show_interval: int = 100 - learning_rate: float = 0.0002 - weight_decay: float = 0.01 - optimizer: str = "adam" - - -@dataclass -class TestConfig: - autoregressive_prediction: bool = False - sampling_mode: str = "topp" - sampling_param: float = 0 - sampling_param_geometry: float = 0 - sampling_param_semantic: float = 0 - sampling_num: int = 10 - - -@dataclass -class TextElementEmbeddingFlag: - text_font: bool = True - text_font_size: bool = True - text_font_size_raw: bool = False - text_font_color: bool = True - text_line_count: bool = True - text_char_count: bool = True - text_height: bool = False - text_width: bool = False - text_top: bool = False - text_left: bool = False - text_center_y: bool = True - text_center_x: bool = True - text_align_type: bool = False - text_angle: bool = False - text_letter_spacing: bool = False - text_line_height_scale: bool = False - text_line_height_size: bool = False - text_capitalize: bool = False - text_emb: bool = True - text_local_img_emb: bool = True - - -@dataclass -class CanvasEmbeddingFlag: - canvas_bg_img: bool = False - canvas_bg_img_emb: bool = True - canvas_aspect_ratio: bool = True - canvas_text_num: bool = True - canvas_group: bool = False - canvas_format: bool = False - canvas_category: bool = False - canvas_width: bool = False - canvas_height: bool = False - - -@dataclass -class TextElementPredictionTargetFlag: - text_font: bool = True - text_font_emb: bool = False - text_font_size: bool = True - text_font_size_raw: bool = False - text_font_color: bool = True - text_angle: bool = True - text_letter_spacing: bool = True - text_line_height_scale: bool = True - text_line_height_size: bool = False - text_capitalize: bool = True - text_align_type: bool = True - text_center_y: bool = False - text_center_x: bool = False - text_height: bool = False - text_width: bool = False - - -@dataclass -class GlobalConfig: - meta_info: MetaInfo = MetaInfo() - model_config: ModelConfig = ModelConfig() - data_config: DataConfig = DataConfig() - train_config: TrainConfig = TrainConfig() - test_config: TestConfig = TestConfig() - text_element_embedding_flag: TextElementEmbeddingFlag = TextElementEmbeddingFlag() - canvas_embedding_flag: CanvasEmbeddingFlag = CanvasEmbeddingFlag() - text_element_prediction_flag: TextElementPredictionTargetFlag = ( - TextElementPredictionTargetFlag() - ) - canvas_embedding_attribute_config: CanvasContextEmbeddingAttributeConfig = ( - CanvasContextEmbeddingAttributeConfig() - ) - text_element_embedding_attribute_config: TextElementContextEmbeddingAttributeConfig = ( - TextElementContextEmbeddingAttributeConfig() - ) - text_element_prediction_attribute_config: TextElementContextPredictionAttributeConfig = ( - TextElementContextPredictionAttributeConfig() - ) diff --git a/src/typography_generation/config/config_args_util.py b/src/typography_generation/config/config_args_util.py deleted file mode 100644 index fbe8adb..0000000 --- a/src/typography_generation/config/config_args_util.py +++ /dev/null @@ -1,199 +0,0 @@ -from typing import Any, Dict, Tuple - -import omegaconf -from logzero import logger - -from typography_generation.config.base_config_object import GlobalConfig -from typography_generation.config.default import ( - build_config, - get_bindata, - get_datapreprocess_config, - get_font_config, - get_model_input_prefix_list, - get_target_prefix_list, -) -from typography_generation.io.data_object import ( - BinsData, - DataPreprocessConfig, - FontConfig, - PrefixListObject, - SamplingConfig, -) - - -def args2add_data_inputs(args: Any) -> Tuple: - add_data_inputs = {} - add_data_inputs["data_dir"] = args.datadir - add_data_inputs["global_config_input"] = get_global_config_input(args.datadir, args) - add_data_inputs["gpu"] = args.gpu - add_data_inputs["weight"] = args.weight - add_data_inputs["jobdir"] = args.jobdir - add_data_inputs["debug"] = args.debug - return add_data_inputs - - -def get_conf(yaml_file: str) -> omegaconf: - logger.info(f"load {yaml_file}") - conf = omegaconf.OmegaConf.load(yaml_file) - return conf - - -def get_global_config( - data_dir: str, - model_name: str, - test_config_name: str = "test_config", - model_config_name: str = "model_config", - elementembeddingflag_config_name: str = "text_element_embedding_flag_config", - elementpredictionflag_config_name: str = "text_element_prediction_flag_config", - canvasembeddingflag_config_name: str = "canvas_embedding_flag_config", - elementembeddingatt_config_name: str = "text_element_embedding_attribute_config", - elementpredictionatt_config_name: str = "text_element_prediction_attribute_config", - canvasembeddingatt_config_name: str = "canvas_embedding_attribute_config", -) -> GlobalConfig: - metainfo_conf = get_conf(f"{data_dir}/config/{model_name}/metainfo.yaml") - data_conf = get_conf(f"{data_dir}/config/{model_name}/data_config.yaml") - model_conf = get_conf(f"{data_dir}/config/{model_name}/{model_config_name}.yaml") - train_conf = get_conf(f"{data_dir}/config/{model_name}/train_config.yaml") - test_conf = get_conf(f"{data_dir}/config/{model_name}/{test_config_name}.yaml") - text_element_emb_flag_conf = get_conf( - f"{data_dir}/config/{model_name}/{elementembeddingflag_config_name}.yaml" - ) - canvas_emb_flag_conf = get_conf( - f"{data_dir}/config/{model_name}/{canvasembeddingflag_config_name}.yaml" - ) - text_element_pred_flag_conf = get_conf( - f"{data_dir}/config/{model_name}/{elementpredictionflag_config_name}.yaml" - ) - text_element_emb_attribute_conf = get_conf( - f"{data_dir}/config/{model_name}/{elementembeddingatt_config_name}.yaml" - ) - canvas_emb_attribute_conf = get_conf( - f"{data_dir}/config/{model_name}/{canvasembeddingatt_config_name}.yaml" - ) - text_element_pred_attribute_conf = get_conf( - f"{data_dir}/config/{model_name}/{elementpredictionatt_config_name}.yaml" - ) - config = build_config( - metainfo_conf, - data_conf, - model_conf, - train_conf, - test_conf, - text_element_emb_flag_conf, - canvas_emb_flag_conf, - text_element_pred_flag_conf, - text_element_emb_attribute_conf, - canvas_emb_attribute_conf, - text_element_pred_attribute_conf, - ) - return config - - -def get_data_config( - config: GlobalConfig, -) -> Tuple[BinsData, FontConfig, DataPreprocessConfig]: - bin_data = get_bindata(config) - font_config = get_font_config(config) - data_preprocess_config = get_datapreprocess_config(config) - return bin_data, font_config, data_preprocess_config - - -def get_sampling_config( - config: GlobalConfig, -) -> SamplingConfig: - sampling_param = config.test_config.sampling_param - sampling_param_geometry = config.test_config.sampling_param_geometry - sampling_param_semantic = config.test_config.sampling_param_semantic - sampling_num = config.test_config.sampling_num - return SamplingConfig( - sampling_param, sampling_param_geometry, sampling_param_semantic, sampling_num - ) - - -def get_global_config_input(data_dir: str, args: Any) -> Dict: - global_config_input = {} - global_config_input["data_dir"] = data_dir - global_config_input["model_name"] = args.configname - global_config_input["test_config_name"] = args.testconfigname - global_config_input["model_config_name"] = args.modelconfigname - global_config_input[ - "elementembeddingflag_config_name" - ] = args.elementembeddingflagconfigname - global_config_input[ - "canvasembeddingflag_config_name" - ] = args.canvasembeddingflagconfigname - global_config_input[ - "elementpredictionflag_config_name" - ] = args.elementpredictionflagconfigname - - return global_config_input - - -def get_model_config_input(config: GlobalConfig) -> Tuple[str, Dict]: - model_kwargs = {} - - model_kwargs["prefix_list_element"] = get_target_prefix_list( - config.text_element_embedding_attribute_config - ) - model_kwargs["prefix_list_canvas"] = get_target_prefix_list( - config.canvas_embedding_attribute_config - ) - model_kwargs["prefix_list_target"] = get_target_prefix_list( - config.text_element_prediction_attribute_config - ) - model_kwargs[ - "embedding_config_element" - ] = config.text_element_embedding_attribute_config - model_kwargs["embedding_config_canvas"] = config.canvas_embedding_attribute_config - model_kwargs[ - "prediction_config_element" - ] = config.text_element_prediction_attribute_config - model_kwargs["d_model"] = config.model_config.d_model - model_kwargs["n_head"] = config.model_config.n_head - model_kwargs["dropout"] = config.model_config.dropout - model_kwargs["num_encoder_layers"] = config.model_config.num_encoder_layers - model_kwargs["num_decoder_layers"] = config.model_config.num_decoder_layers - model_kwargs["seq_length"] = config.model_config.seq_length - model_kwargs["std_ratio"] = config.model_config.std_ratio - model_kwargs["bypass"] = config.model_config.bypass - - model_name = config.meta_info.model_name - return model_name, model_kwargs - - -def get_train_config_input(config: GlobalConfig, debug: bool) -> Dict: - train_kwargs = {} - if debug is True: - train_kwargs["epochs"] = 1 - train_kwargs["batch_size"] = 2 - else: - train_kwargs["epochs"] = config.train_config.epochs - train_kwargs["batch_size"] = config.train_config.batch_size - train_kwargs["save_epoch"] = config.train_config.save_epoch - train_kwargs["num_worker"] = config.train_config.num_worker - train_kwargs["learning_rate"] = config.train_config.learning_rate - train_kwargs["show_interval"] = config.train_config.show_interval - train_kwargs["optimizer_option"] = config.train_config.optimizer - train_kwargs["weight_decay"] = config.train_config.weight_decay - train_kwargs["debug"] = debug - return train_kwargs - - -def get_prefix_lists(config: GlobalConfig) -> PrefixListObject: - prefix_list_textelement = get_target_prefix_list( - config.text_element_embedding_attribute_config - ) - prefix_list_canvas = get_target_prefix_list( - config.canvas_embedding_attribute_config - ) - prefix_list_model_input = get_model_input_prefix_list(config) - prefix_list_target = get_target_prefix_list( - config.text_element_prediction_attribute_config - ) - prefix_list_object = PrefixListObject( - prefix_list_textelement, - prefix_list_canvas, - prefix_list_model_input, - prefix_list_target, - ) - return prefix_list_object diff --git a/src/typography_generation/config/default.py b/src/typography_generation/config/default.py deleted file mode 100644 index c10b5f1..0000000 --- a/src/typography_generation/config/default.py +++ /dev/null @@ -1,128 +0,0 @@ -from typing import Any, List, Union -from logzero import logger -from omegaconf import OmegaConf -from typography_generation.config.attribute_config import ( - CanvasContextEmbeddingAttributeConfig, - TextElementContextEmbeddingAttributeConfig, - TextElementContextPredictionAttributeConfig, -) -from typography_generation.config.base_config_object import ( - CanvasEmbeddingFlag, - DataConfig, - GlobalConfig, - MetaInfo, - ModelConfig, - TestConfig, - TextElementEmbeddingFlag, - TextElementPredictionTargetFlag, - TrainConfig, -) -from typography_generation.io.data_object import ( - BinsData, - DataPreprocessConfig, - FontConfig, -) - - -def get_bindata(config: GlobalConfig) -> BinsData: - bin_data = BinsData( - config.data_config.color_bin, - config.data_config.small_spatio_bin, - config.data_config.large_spatio_bin, - ) - return bin_data - - -def get_font_config(config: GlobalConfig) -> FontConfig: - font_config = FontConfig( - config.data_config.font_num, - config.data_config.font_emb_type, - config.data_config.font_emb_weight, - config.data_config.font_emb_dim, - config.data_config.font_emb_name, - ) - return font_config - - -def get_datapreprocess_config(config: GlobalConfig) -> DataPreprocessConfig: - datapreprocess_config = DataPreprocessConfig( - config.data_config.order_type, - config.data_config.seq_length, - ) - return datapreprocess_config - - -def get_target_prefix_list(tar_cls: Any) -> List: - all_text_prefix_list = dir(tar_cls) - target_prefix_list = [] - for prefix in all_text_prefix_list: - elm = getattr(tar_cls, prefix) - if elm.flag is True: - target_prefix_list.append(prefix) - return target_prefix_list - - -def get_model_input_prefix_list(conf: GlobalConfig) -> List: - input_prefix_list = [] - input_prefix_list += get_target_prefix_list( - conf.text_element_embedding_attribute_config - ) - input_prefix_list += get_target_prefix_list(conf.canvas_embedding_attribute_config) - input_prefix_list += get_target_prefix_list( - conf.text_element_prediction_attribute_config - ) - if "canvas_text_num" in input_prefix_list: - pass - else: - input_prefix_list.append("canvas_text_num") - return list(set(input_prefix_list)) - - -def plusone_num_embeddings(config: GlobalConfig) -> None: - prefix_lists = dir(config.text_element_embedding_attribute_config) - for prefix in prefix_lists: - elm = getattr(config.text_element_embedding_attribute_config, f"{prefix}") - if elm.emb_layer == "nn.Embedding": - elm.emb_layer_kwargs["num_embeddings"] = ( - int(elm.emb_layer_kwargs["num_embeddings"]) + 1 - ) - - -def show_class_attributes(_class: Any): - class_dict = _class.__dict__["_content"] - logger.info(f"{class_dict}") - - -def build_config( - metainfo_conf: MetaInfo, - data_conf: DataConfig, - model_conf: ModelConfig, - train_conf: TrainConfig, - test_conf: TestConfig, - text_element_emb_flag_conf: TextElementEmbeddingFlag, - canvas_emb_flag_conf: CanvasEmbeddingFlag, - text_element_pred_flag_conf: TextElementPredictionTargetFlag, - text_element_emb_attribute_conf: TextElementContextEmbeddingAttributeConfig, - canvas_emb_attribute_conf: CanvasContextEmbeddingAttributeConfig, - text_element_pred_attribute_conf: TextElementContextPredictionAttributeConfig, -) -> Union[Any, GlobalConfig]: - conf = OmegaConf.structured(GlobalConfig) - show_class_attributes(text_element_emb_flag_conf) - show_class_attributes(canvas_emb_flag_conf) - show_class_attributes(text_element_pred_flag_conf) - conf = OmegaConf.merge( - conf, - metainfo_conf, - data_conf, - model_conf, - train_conf, - test_conf, - text_element_emb_flag_conf, - canvas_emb_flag_conf, - text_element_pred_flag_conf, - text_element_emb_attribute_conf, - canvas_emb_attribute_conf, - text_element_pred_attribute_conf, - ) - plusone_num_embeddings(conf) - return conf diff --git a/src/typography_generation/io/__init__.py b/src/typography_generation/io/__init__.py deleted file mode 100644 index 8b13789..0000000 --- a/src/typography_generation/io/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/typography_generation/io/build_dataset.py b/src/typography_generation/io/build_dataset.py deleted file mode 100644 index 14bacd3..0000000 --- a/src/typography_generation/io/build_dataset.py +++ /dev/null @@ -1,85 +0,0 @@ -from typing import Tuple -from typography_generation.io.data_loader import CrelloLoader -from typography_generation.io.data_object import ( - FontConfig, - PrefixListObject, -) -from typography_generation.tools.tokenizer import Tokenizer -import datasets -from logzero import logger -import os - - -def build_train_dataset( - data_dir: str, - prefix_list_object: PrefixListObject, - font_config: FontConfig, - use_extended_dataset: bool = True, - dataset_name: str = "crello", - debug: bool = False, -) -> Tuple[CrelloLoader, CrelloLoader]: - tokenizer = Tokenizer(data_dir) - - if dataset_name == "crello": - logger.info("load hugging dataset start") - if use_extended_dataset is True: - _dataset = datasets.load_from_disk( - os.path.join(data_dir, "crello_map_features") - ) - else: - _dataset = datasets.load_dataset("cyberagent/crello", revision="3.1") - logger.info("load hugging dataset done") - dataset = CrelloLoader( - data_dir, - tokenizer, - _dataset["train"], - prefix_list_object, - font_config, - use_extended_dataset=use_extended_dataset, - debug=debug, - ) - dataset_val = CrelloLoader( - data_dir, - tokenizer, - _dataset["validation"], - prefix_list_object, - font_config, - use_extended_dataset=use_extended_dataset, - debug=debug, - ) - else: - raise NotImplementedError() - return dataset, dataset_val - - -def build_test_dataset( - data_dir: str, - prefix_list_object: PrefixListObject, - font_config: FontConfig, - use_extended_dataset: bool = True, - dataset_name: str = "crello", - debug: bool = False, -) -> CrelloLoader: - tokenizer = Tokenizer(data_dir) - - if dataset_name == "crello": - logger.info("load hugging dataset start") - if use_extended_dataset is True: - _dataset = datasets.load_from_disk( - os.path.join(data_dir, "crello_map_features") - ) - else: - _dataset = datasets.load_dataset("cyberagent/crello", revision="3.1") - logger.info("load hugging dataset done") - dataset = CrelloLoader( - data_dir, - tokenizer, - _dataset["test"], - prefix_list_object, - font_config, - use_extended_dataset=use_extended_dataset, - debug=debug, - ) - else: - raise NotImplementedError() - return dataset diff --git a/src/typography_generation/io/crello_util.py b/src/typography_generation/io/crello_util.py deleted file mode 100644 index 85f1e7d..0000000 --- a/src/typography_generation/io/crello_util.py +++ /dev/null @@ -1,490 +0,0 @@ -import math -import os -import pickle -from typing import Any, Dict, List, Tuple -from einops import repeat -import skia -import numpy as np -import PIL -from PIL import Image -import torch -from typography_generation.io.data_object import FontConfig -from typography_generation.tools.tokenizer import Tokenizer - -from transformers import CLIPProcessor, CLIPModel, CLIPTokenizer - -from typography_generation.visualization.renderer_util import ( - get_skia_font, - get_text_actual_width, - get_texts, -) - -fontmgr = skia.FontMgr() - - -class CrelloProcessor: - def __init__( - self, - data_dir: str, - tokenizer: Tokenizer, - dataset: Any, - font_config: FontConfig, - use_extended_dataset: bool = True, - seq_length: int = 50, - ) -> None: - self.data_dir = data_dir - self.tokenizer = tokenizer - self.font_config = font_config - self.dataset = dataset - self.seq_length = seq_length - if font_config is not None: - fn = os.path.join( - self.data_dir, "font_emb", f"{font_config.font_emb_name}.pkl" - ) - self.fontid2fontemb = pickle.load(open(fn, "rb")) - self.use_extended_dataset = use_extended_dataset - if not use_extended_dataset: - fn = os.path.join(data_dir, "font2ttf.pkl") - _font2ttf = pickle.load(open(fn, "rb")) - font2ttf = {} - for key in _font2ttf.keys(): - tmp = _font2ttf[key].split("/data/dataset/crello/")[1] - fn = os.path.join(data_dir, tmp) - font2ttf[key] = fn - self.font2ttf = font2ttf - - fn = os.path.join(data_dir, "svgid2scaleinfo.pkl") - self.svgid2scaleinfo = pickle.load(open(fn, "rb")) - self.fontlabel2fontname = self.dataset.features["font"].feature.int2str - - self.processor = CLIPProcessor.from_pretrained( - "openai/clip-vit-base-patch32" - ) - self.text_tokenizer = CLIPTokenizer.from_pretrained( - "openai/clip-vit-base-patch32" - ) - self.model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32") - # self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu") - self.device = torch.device("cpu") - self.model.to(self.device) - - def get_canvas_text_num( - self, element_data: dict, **kwargs: Any - ) -> Tuple[int, List]: - text_num = 0 - for k in range(len(element_data["text"])): - if element_data["text"][k] == "": - pass - else: - text_num += 1 - text_num = min(text_num, self.seq_length) - return text_num - - def get_canvas_text_ids( - self, element_data: dict, **kwargs: Any - ) -> Tuple[int, List]: - text_ids = [] - for k in range(len(element_data["text"])): - if element_data["text"][k] == "": - pass - else: - text_ids.append(k) - return text_ids - - def get_canvas_bg_size(self, element_data: dict) -> Tuple[int, int]: - return element_data["canvas_bg_size"] - - def get_scale_box(self, element_data: dict) -> List: - if self.use_extended_dataset: - return tuple(element_data["scale_box"]) - else: - svgid = element_data["id"] - return self.svgid2scaleinfo[svgid] - - def get_text_font(self, element_data: dict, text_index: int, **kwargs: Any) -> int: - font = element_data["font"][text_index] - 1 - return int(font) - - def denorm_text_font(self, val: int, **kwargs: Any) -> int: - val += 1 - return val - - def get_text_font_emb( - self, - element_data: dict, - text_index: int, - **kwargs: Any, - ) -> np.array: - font = element_data["font"][text_index] - font_emb = self.fontid2fontemb[font - 1] - return font_emb - - def raw2token_text_font_emb( - self, - val: np.array, - **kwargs: Any, - ) -> int: - vec = repeat(val, "c -> n c", n=len(self.fontid2fontemb)) - diff = (vec - self.fontid2fontemb) ** 2 - diff = diff.sum(1) - font = int(np.argsort(diff)[0]) - return font - - def denorm_text_font_emb(self, val: int, **kwargs: Any) -> int: - val += 1 - return val - - def get_skia_font( - self, element_data: dict, text_index: int, scaleinfo: Tuple, **kwargs: Any - ) -> int: - font_label = element_data["font"][text_index] - font_name = self.fontlabel2fontname(int(font_label)) - font_name = font_name.replace(" ", "_") - scale_h, _ = scaleinfo - font_skia, _ = get_skia_font( - self.font2ttf, - fontmgr, - element_data, - text_index, - font_name, - scale_h, - ) - return font_skia - - def get_text_font_size( - self, - element_data: dict, - text_index: int, - img_size: Tuple, - scaleinfo: Tuple, - **kwargs: Any, - ) -> float: - fs = element_data["font_size"][text_index] - scale_h, _ = scaleinfo - h, _ = img_size - val = fs * scale_h / h - return float(val) - - def denorm_text_font_size( - self, val: float, img_height: int, scale_h: float, **kwargs: Any - ) -> float: - val = val * img_height / scale_h - return val - - def get_text_font_size_raw( - self, - element_data: dict, - text_index: int, - img_size: Tuple, - scaleinfo: Tuple, - **kwargs: Any, - ) -> float: - val = self.get_text_font_size(element_data, text_index, img_size, scaleinfo) - return val - - def raw2token_text_font_size_raw( - self, - val: float, - **kwargs: Any, - ) -> int: - val = self.tokenizer.tokenize("text_font_size", float(val)) - return val - - def denorm_text_font_size_raw( - self, val: float, img_height: int, scale_h: float, **kwargs: Any - ) -> float: - val = val * img_height / scale_h - return val - - def get_text_font_color( - self, element_data: dict, text_index: int, **kwargs: Any - ) -> Tuple[int, int, int]: - B, G, R = element_data["color"][text_index] - return (R, G, B) - - def get_text_height( - self, element_data: dict, text_index: int, **kwargs: Any - ) -> float: - height = element_data["height"][text_index] - return float(height) - - def denorm_text_height(self, val: float, img_height: int, **kwargs: Any) -> float: - val = val * img_height - return val - - def get_text_width( - self, element_data: dict, text_index: int, **kwargs: Any - ) -> float: - width = element_data["width"][text_index] - return float(width) - - def denorm_text_width(self, val: float, img_width: int, **kwargs: Any) -> float: - val = val * img_width - return val - - def get_text_top(self, element_data: dict, text_index: int, **kwargs: Any) -> float: - top = element_data["top"][text_index] - return float(top) - - def denorm_text_top(self, val: float, img_height: int, **kwargs: Any) -> float: - val = val * img_height - return val - - def get_text_left( - self, element_data: dict, text_index: int, **kwargs: Any - ) -> float: - left = element_data["left"][text_index] - return float(left) - - def denorm_text_left(self, val: float, img_width: int, **kwargs: Any) -> float: - val = val * img_width - return val - - def get_text_actual_width( - self, - element_data: dict, - text_index: int, - texts: List[str], - font_skia: skia.Font, - scaleinfo: Tuple[float, float], - **kwargs: Any, - ) -> float: - _, scale_w = scaleinfo - text_width = get_text_actual_width( - element_data, text_index, texts, font_skia, scale_w - ) - return text_width - - def get_text_center_y( - self, element_data: dict, text_index: int, **kwargs: Any - ) -> float: - if self.use_extended_dataset: - return element_data["text_center_y"][text_index] - else: - text_height = element_data["height"][text_index] - top = element_data["top"][text_index] - center_y = (top + top + text_height) / 2.0 - return float(center_y) - - def get_text_center_x( - self, - element_data: dict, - text_index: int, - scaleinfo: Tuple, - **kwargs: Any, - ) -> float: - if self.use_extended_dataset: - return element_data["text_center_x"][text_index] - else: - left = element_data["left"][text_index] - w = element_data["width"][text_index] - textAlign = element_data["text_align"][text_index] - texts = get_texts(element_data, text_index) - font_skia = self.get_skia_font(element_data, text_index, scaleinfo) - text_actual_width = self.get_text_actual_width( - element_data, text_index, texts, font_skia, scaleinfo - ) - right = left + w - if textAlign == 1: - center_x = (left + right) / 2.0 - elif textAlign == 3: - center_x = right - text_actual_width / 2.0 - elif textAlign == 2: - center_x = left + text_actual_width / 2.0 - return float(center_x) - - def get_text_align_type( - self, element_data: dict, text_index: int, **kwargs: Any - ) -> int: - align_type = element_data["text_align"][text_index] - 1 - return int(align_type) - - def denorm_text_align_type(self, val: int, **kwargs: Any) -> int: - val += 1 - return val - - def get_text_capitalize( - self, element_data: dict, text_index: int, **kwargs: Any - ) -> int: - capitalize = element_data["capitalize"][text_index] - return int(capitalize) - - def get_text_angle( - self, element_data: dict, text_index: int, **kwargs: Any - ) -> float: - angle = element_data["angle"][text_index] - angle = (float(angle) * 180 / math.pi) / 360.0 - angle = math.modf(angle)[0] - return float(angle) - - def denorm_text_angle(self, val: float, **kwargs: Any) -> float: - val = val * 360 / 180.0 * math.pi - return val - - def get_text_letter_spacing( - self, - element_data: dict, - text_index: int, - scaleinfo: Tuple, - img_size: Tuple, - **kwargs: Any, - ) -> float: - _, scale_w = scaleinfo - _, W = img_size - letter_space = element_data["letter_spacing"][text_index] * scale_w / W - return float(letter_space) - - def denorm_text_letter_spacing( - self, val: float, img_width: int, scale_w: float, **kwargs: Any - ) -> float: - val = val * img_width / scale_w - return val - - def get_text_line_height_scale( - self, element_data: dict, text_index: int, **kwargs: Any - ) -> float: - line_height_scale = element_data["line_height"][text_index] - return float(line_height_scale) - - def get_text_char_count( - self, element_data: dict, text_index: int, **kwargs: Any - ) -> int: - text = self.get_text(element_data, text_index) - texts = text.split(os.linesep) - max_char_count = 0 - for t in texts: - max_char_count = max(max_char_count, len(t)) - return min(max_char_count, 50 - 1) - - def get_text_line_count( - self, element_data: dict, text_index: int, **kwargs: Any - ) -> int: - texts = element_data["text"][text_index].split(os.linesep) - line_count = 0 - for t in texts: - if t == "": - pass - else: - line_count += 1 - return min(line_count, 49) - - def get_text(self, element_data: dict, text_index: int) -> str: - text = element_data["text"][text_index] - return str(text) - - def get_canvas_aspect_ratio( - self, element_data: dict, bg_img: Any, **kwargs: Any - ) -> float: - h, w = bg_img.size[1], bg_img.size[0] - ratio = float(h) / float(w) - return ratio - - def get_canvas_group(self, element_data: dict, **kwargs: Any) -> int: - return element_data["group"] - - def get_canvas_format(self, element_data: dict, **kwargs: Any) -> int: - return element_data["format"] - - def get_canvas_category(self, element_data: dict, **kwargs: Any) -> int: - return element_data["category"] - - def get_canvas_width(self, element_data: dict, **kwargs: Any) -> int: - return element_data["canvas_width"] - - def get_canvas_height(self, element_data: dict, **kwargs: Any) -> int: - return element_data["canvas_height"] - - def get_canvas_bg_img_emb( - self, element_data: dict, bg_img: PIL.Image, **kwargs: Any - ) -> np.array: - if self.use_extended_dataset: - return np.array(element_data["canvas_bg_img_emb"]) - else: - inputs = self.processor(images=[bg_img], return_tensors="pt") - inputs["pixel_values"] = inputs["pixel_values"].to(self.device) - image_feature = self.model.get_image_features(**inputs) - return image_feature.data.numpy() - - def get_text_emb( - self, - element_data: dict, - text_index: int, - **kwargs: Any, - ) -> np.array: - if self.use_extended_dataset: - return np.array(element_data["text_emb"][text_index]) - else: - text = element_data["text"][text_index] - inputs = self.text_tokenizer([text], padding=True, return_tensors="pt") - if inputs["input_ids"].shape[1] > 77: - inp = inputs["input_ids"][:, :77] - else: - inp = inputs["input_ids"] - text_features = self.model.get_text_features(inp).data.numpy()[0] - return text_features - - def get_text_local_img( - self, - img: Any, - text_center_y: float, - text_center_x: float, - H: int, - W: int, - ) -> np.array: - text_center_y = text_center_y * H - text_center_x = text_center_x * W - - text_center_y = min(max(text_center_y, 0), H) - text_center_x = min(max(text_center_x, 0), W) - img = img.resize((640, 640)) - img = np.array(img) - local_img_size = 64 * 5 - local_img_size_half = local_img_size // 2 - img_pad = np.zeros((640 + local_img_size, 640 + local_img_size, 3)) - img_pad[ - local_img_size_half : 640 + local_img_size_half, - local_img_size_half : 640 + local_img_size_half, - ] = img - h_rate = 640 / float(H) - w_rate = 640 / float(W) - text_center_y = int(np.round(text_center_y * h_rate + local_img_size_half)) - text_center_x = int(np.round(text_center_x * w_rate + local_img_size_half)) - local_img = img_pad[ - text_center_y - local_img_size_half : text_center_y + local_img_size_half, - text_center_x - local_img_size_half : text_center_x + local_img_size_half, - ] - return local_img - - def get_text_local_img_emb( - self, - element_data: dict, - text_index: int, - scaleinfo: Tuple, - img_size: Tuple, - bg_img: Any, - **kwargs: Any, - ) -> np.array: - if self.use_extended_dataset: - return np.array(element_data["text_local_img_emb"][text_index]) - else: - H, W = img_size - text_center_x = self.get_text_center_x(element_data, text_index, scaleinfo) - text_center_y = self.get_text_center_y(element_data, text_index) - local_img = self.get_text_local_img( - bg_img.copy(), text_center_y, text_center_x, H, W - ) - local_img = Image.fromarray(local_img.astype(np.uint8)).resize((224, 224)) - inputs = self.processor(images=[local_img], return_tensors="pt") - inputs["pixel_values"] = inputs["pixel_values"].to(self.device) - image_feature = self.model.get_image_features(**inputs) - return image_feature.data.numpy() - - def load_samples(self, index: int) -> Tuple[Dict, Any, str, int]: - element_data = self.dataset[index] - svg_id = element_data["id"] - fn = os.path.join(self.data_dir, "generate_bg_png", f"{svg_id}.png") - bg = Image.open(fn).convert("RGB") # background image - return element_data, bg, svg_id, index - - def __len__(self) -> int: - return len(self.dataset) diff --git a/src/typography_generation/io/data_loader.py b/src/typography_generation/io/data_loader.py deleted file mode 100644 index 89b1771..0000000 --- a/src/typography_generation/io/data_loader.py +++ /dev/null @@ -1,123 +0,0 @@ -import time -from typing import Any, Dict, List, Tuple -import numpy as np - -import torch -from logzero import logger -from typography_generation.io.crello_util import CrelloProcessor -from typography_generation.io.data_object import ( - DesignContext, - FontConfig, - PrefixListObject, -) -from typography_generation.io.data_utils import get_canvas_context, get_element_context -from typography_generation.tools.tokenizer import Tokenizer - - -class CrelloLoader(torch.utils.data.Dataset): - def __init__( - self, - data_dir: str, - tokenizer: Tokenizer, - dataset: Any, - prefix_list_object: PrefixListObject, - font_config: FontConfig, - use_extended_dataset: bool = True, - seq_length: int = 50, - debug: bool = False, - ) -> None: - super().__init__() - self.data_dir = data_dir - self.prefix_list_object = prefix_list_object - self.debug = debug - logger.debug("create crello dataset processor") - self.dataset = CrelloProcessor( - data_dir, - tokenizer, - dataset, - font_config, - use_extended_dataset=use_extended_dataset, - ) - logger.debug("create crello dataset processor done") - self.seq_length = seq_length - - def get_ordered_text_ids(self, element_data, order_list) -> List: - text_ids = [] - for i in order_list: - if element_data["text"][i] == "": - pass - else: - text_ids.append(i) - return text_ids - - def get_order_list(self, elm: Dict[str, Any]) -> List[int]: - if self.dataset.use_extended_dataset: - return elm["order_list"] - else: - """ - Sort elments based on the raster scan order. - """ - center_y = [] - center_x = [] - scaleinfo = self.dataset.get_scale_box(elm) - for text_id in range(len(elm["text"])): - center_y.append(self.dataset.get_text_center_y(elm, text_id)) - center_x.append(self.dataset.get_text_center_x(elm, text_id, scaleinfo)) - center_y = np.array(center_y) - center_x = np.array(center_x) - sortedid = np.argsort(center_y * 1000 + center_x) - return list(sortedid) - - def load_data(self, index: int) -> Tuple: - logger.debug("load samples") - element_data, bg_img, svg_id, index = self.dataset.load_samples(index) - - # extract text element indexes - text_num = self.dataset.get_canvas_text_num(element_data) - - logger.debug("order elements") - order_list = self.get_order_list(element_data) - text_ids = self.get_ordered_text_ids(element_data, order_list) - elment_prefix_list = ( - self.prefix_list_object.textelement + self.prefix_list_object.target - ) - logger.debug("get_element_context") - text_context = get_element_context( - element_data, - bg_img, - self.dataset, - elment_prefix_list, - text_num, - text_ids, - ) - - logger.debug("get_canvas_context") - canvas_context = get_canvas_context( - element_data, - self.dataset, - self.prefix_list_object.canvas, - bg_img, - text_num, - ) - logger.debug("build design context object") - design_context = DesignContext(text_context, canvas_context) - return design_context, svg_id, element_data - - def __getitem__(self, index: int) -> Tuple[DesignContext, List, str]: - logger.debug("load data") - start = time.time() - design_context, svg_id, element_data = self.load_data(index) - logger.debug(f"load data {time.time() -start}") - logger.debug("get model input list") - model_input_list = design_context.get_model_inputs_from_prefix_list( - self.prefix_list_object.model_input - ) - logger.debug(f"get model input list {time.time() -start}") - logger.debug("get model input list done") - return design_context, model_input_list, svg_id, index - - def __len__(self) -> int: - if self.debug is True: - return 2 - else: - return len(self.dataset) diff --git a/src/typography_generation/io/data_object.py b/src/typography_generation/io/data_object.py deleted file mode 100644 index f0fb0eb..0000000 --- a/src/typography_generation/io/data_object.py +++ /dev/null @@ -1,266 +0,0 @@ -from dataclasses import dataclass -from typing import Any, Dict, List, Tuple, Union - -import numpy as np -import torch -from logzero import logger -from torch import Tensor - -from typography_generation.config.attribute_config import ( - TextElementContextEmbeddingAttributeConfig, -) - - -@dataclass -class PrefixListObject: - textelement: List - canvas: List - model_input: List - target: List - - -@dataclass -class BinsData: - color_bin: int - small_spatio_bin: int - large_spatio_bin: int - - -@dataclass -class FontConfig: - font_num: int - font_emb_type: str = "label" - font_emb_weight: float = 1.0 - font_emb_dim: int = 40 - font_emb_name: str = "mfc" - - -@dataclass -class DataPreprocessConfig: - order_type: str - seq_length: int - - -@dataclass -class SamplingConfig: - sampling_param: str - sampling_param_geometry: float - sampling_param_semantic: float - sampling_num: int - - -class ModelInput: - def __init__(self, design_context_list: List, model_input: List, gpu: bool) -> None: - self.design_context_list = design_context_list - self.model_input = model_input - self.prefix_list = self.design_context_list[0].model_input_prefix_list - self.gpu = gpu - self.reset() - - def reset(self) -> None: - self.setgt() - if self.gpu is True: - self.cuda() - - def setgt(self) -> None: - if len(self.prefix_list) != len(self.model_input): - raise ValueError("The length between list and input is different.") - self.batch_num = self.model_input[0].shape[0] - for prefix, elm in zip(self.prefix_list, self.model_input): - setattr(self, f"{prefix}", elm.clone()) - if prefix == "canvas_text_num": - self.canvas_text_num = elm.clone() - - def cuda(self) -> None: - for prefix in self.prefix_list: - tar = getattr(self, f"{prefix}") - if type(tar) == Tensor: - setattr(self, f"{prefix}", tar.cuda()) - - def target_register(self, prefix: str, elm: Any) -> None: - setattr(self, f"{prefix}", elm) - - def zeroinitialize_style_attributes(self, prefix_list: List) -> None: - for prefix in prefix_list: - if prefix == "canvas_text_num": - continue - tar = getattr(self, f"{prefix}") - tar_rep = torch.zeros_like(tar) - setattr(self, f"{prefix}", tar_rep) - - def zeroinitialize_specific_attribute(self, prefix: str) -> None: - tar = getattr(self, f"{prefix}") - if prefix != "canvas_text_num": - setattr(self, f"{prefix}", torch.zeros_like(tar)) - - def setgt_specific_attribute(self, prefix_tar: str) -> None: - for prefix, elm in zip(self.prefix_list, self.model_input): - if prefix == prefix_tar: - tar = elm.clone() - if self.gpu is True and type(tar) == Tensor: - tar = tar.cuda() - setattr(self, f"{prefix}", tar) - - def update_th_style_attributes( - self, - embedding_config_element: TextElementContextEmbeddingAttributeConfig, - prefix_list: List, - model_output: Tensor, - text_index: int, - batch_index: int = 0, - ) -> None: - for prefix in prefix_list: - target_embedding_config = getattr(embedding_config_element, prefix) - tar = getattr(self, f"{prefix}") - out = model_output[f"{prefix}"] - tar[batch_index, text_index] = out - setattr(self, f"{target_embedding_config.input_prefix}", tar) - - def zeroinitialize_th_style_attributes( - self, - prefix_list: List, - text_index: int, - batch_index: int = 0, - ) -> None: - for prefix in prefix_list: - tar = getattr(self, f"{prefix}") - tar[batch_index, text_index] = 0 - setattr(self, f"{prefix}", tar) - - def additional_input_from_design_context_list( - self, design_context_list: List - ) -> None: - self.texts = [] - for design_context in design_context_list: - self.texts.append(design_context.text_context.texts) - - -@dataclass -class ElementContext: - prefix_list: List - rawdata2token: Dict - img_size: Tuple - scaleinfo: Tuple - seq_length: int - - def __post_init__(self) -> None: - for prefix in self.prefix_list: - setattr(self, prefix, []) - if prefix == "text_local_img": - self.text_local_img_model_input = np.zeros( - (self.seq_length, 3, 224, 224), dtype=np.float32 - ) - elif prefix == "text_local_img_emb": - self.text_local_img_emb_model_input = np.zeros( - (self.seq_length, 512), dtype=np.float32 - ) - elif prefix == "text_emb": - self.text_emb_model_input = np.zeros( - (self.seq_length, 512), dtype=np.float32 - ) - elif prefix == "text_font_emb": - self.text_font_emb_model_input = ( - np.zeros((self.seq_length, 40), dtype=np.float32) - 10000 - ) - else: - setattr( - self, - f"{prefix}_model_input", - np.zeros((self.seq_length), dtype=np.float32) - 1, - ) - - if prefix in self.rawdata2token.keys(): - setattr( - self, - f"{self.rawdata2token[prefix]}_model_input", - np.zeros((self.seq_length), dtype=np.float32) - 1, - ) - - -@dataclass -class CanvasContext: - canvas_bg_img: np.array - canvas_text_num: int - img_size: Tuple - scale_box: Tuple - prefix_list: List - - -@dataclass -class DesignContext: - element_context: ElementContext - canvas_context: CanvasContext - - def __post_init__(self) -> None: - self.prepare_keys() - - def prepare_keys(self) -> None: - self.canvas_context_keys = dir(self.canvas_context) - self.element_context_keys = dir(self.element_context) - - def get_text_num(self) -> int: - return self.canvas_context.canvas_text_num - - def convert_target_to_torch_format( - self, - tar: Any, - ) -> Any: - if type(tar) == np.ndarray: - tar = torch.from_numpy(tar) - elif type(tar) == float or type(tar) == int: - tar = torch.Tensor([tar]) - elif type(tar) == str or type(tar) == list: - pass - else: - logger.info(tar) - raise NotImplementedError() - return tar - - def search_class(self, prefix: str) -> Union[ElementContext, CanvasContext]: - if prefix in self.canvas_context_keys: - return self.canvas_context - elif prefix in self.element_context_keys: - return self.element_context - else: - logger.info( - f"{prefix}, {self.canvas_context_keys}, {self.element_context_keys}" - ) - raise NotImplementedError() - - def get_model_inputs_from_prefix_list(self, prefix_list: List) -> List: - self.model_input_prefix_list = prefix_list - model_inputs = [] - for prefix in prefix_list: - logger.debug(f"convert_target_to_torch_format {prefix}") - tar_cls = self.search_class(f"{prefix}") - tar = getattr(tar_cls, f"{prefix}_model_input") - tar = self.convert_target_to_torch_format(tar) - model_inputs.append(tar) - return model_inputs - - def get_data(self, prefix: str) -> Any: - tar_cls = self.search_class(f"{prefix}") - tar = getattr(tar_cls, f"{prefix}") - return tar - - def get_canvas_size(self) -> Tuple: - canvas_size = ( - self.canvas_context.canvas_img_size_h, - self.canvas_context.canvas_img_size_w, - ) - return canvas_size - - def get_text_context(self) -> ElementContext: - return self.element_context - - def get_bg(self) -> np.array: - return self.canvas_context.canvas_bg_img - - def get_scaleinfo(self) -> Tuple: - return (self.canvas_context.canvas_h_scale, self.canvas_context.canvas_w_scale) - - def convert_torch_format(self, prefix: str) -> None: - tar_cls = self.search_class(prefix) - tar = getattr(tar_cls, prefix) - tar = self.convert_target_to_torch_format(tar) - setattr(tar_cls, prefix, tar) diff --git a/src/typography_generation/io/data_utils.py b/src/typography_generation/io/data_utils.py deleted file mode 100644 index 3d76d71..0000000 --- a/src/typography_generation/io/data_utils.py +++ /dev/null @@ -1,89 +0,0 @@ -import time -from typing import List, Tuple -import PIL -import numpy as np -from typography_generation.io.crello_util import CrelloProcessor -from typography_generation.io.data_object import CanvasContext, ElementContext -from logzero import logger - - -def get_canvas_context( - element_data: dict, - dataset: CrelloProcessor, - canvas_prefix_list: List, - bg_img: np.array, - text_num: int, -) -> CanvasContext: - img_size = (bg_img.size[1], bg_img.size[0]) # (h,w) - scale_box = dataset.get_scale_box(element_data) - canvas_context = CanvasContext( - bg_img, text_num, img_size, scale_box, canvas_prefix_list - ) - for prefix in canvas_prefix_list: - data_info = {"element_data": element_data, "bg_img": bg_img} - data = getattr(dataset, f"get_{prefix}")(**data_info) - setattr(canvas_context, f"{prefix}", data) - setattr(canvas_context, f"{prefix}_model_input", data) - - return canvas_context - - -def get_element_context( - element_data: dict, - bg_img: PIL.Image, - dataset: CrelloProcessor, - element_prefix_list: List, - text_num: int, - text_ids: List, -) -> ElementContext: - scaleinfo = dataset.get_scale_box(element_data) - img_size = (bg_img.size[1], bg_img.size[0]) # (h,w) - element_context = ElementContext( - element_prefix_list, - dataset.tokenizer.rawdata2token, - img_size, - scaleinfo, - dataset.seq_length, - ) - for i in range(text_num): - text_index = text_ids[i] - for prefix in element_prefix_list: - start = time.time() - - data_info = { - "element_data": element_data, - "text_index": text_index, - "img_size": img_size, - "scaleinfo": scaleinfo, - "bg_img": bg_img, - } - if prefix == "text_emb": - data = getattr(dataset, f"get_{prefix}")(**data_info) - element_context.text_emb_model_input[i] = data - elif prefix == "text_local_img_emb": - data = getattr(dataset, f"get_{prefix}")(**data_info) - element_context.text_local_img_emb_model_input[i] = data - elif prefix == "text_font_emb": - data = dataset.get_text_font_emb(element_data, text_index) - getattr(element_context, prefix).append(data) - element_context.text_font_emb_model_input[i] = data - else: - data = getattr(dataset, f"get_{prefix}")(**data_info) - getattr(element_context, prefix).append(data) - if prefix in dataset.tokenizer.prefix_list: - model_input = dataset.tokenizer.tokenize(prefix, data) - else: - model_input = data - getattr(element_context, f"{prefix}_model_input")[i] = model_input - - if prefix in dataset.tokenizer.rawdata_list: - token = getattr(dataset, f"raw2token_{prefix}")(data) - getattr( - element_context, - f"{dataset.tokenizer.rawdata2token[prefix]}_model_input", - )[i] = token - - end = time.time() - logger.debug(f"{prefix} {end - start}") - - return element_context diff --git a/src/typography_generation/model/__init__.py b/src/typography_generation/model/__init__.py deleted file mode 100644 index 8b13789..0000000 --- a/src/typography_generation/model/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/typography_generation/model/bart.py b/src/typography_generation/model/bart.py deleted file mode 100644 index 77a8fe7..0000000 --- a/src/typography_generation/model/bart.py +++ /dev/null @@ -1,522 +0,0 @@ -import random -import time -from typing import Any, Dict, List, Tuple, Union - -import numpy as np -import torch -from logzero import logger -from torch import Tensor, nn -from torch.functional import F -from typography_generation.config.attribute_config import ( - CanvasContextEmbeddingAttributeConfig, - TextElementContextEmbeddingAttributeConfig, - TextElementContextPredictionAttributeConfig, -) -from typography_generation.io.crello_util import CrelloProcessor -from typography_generation.io.data_object import ModelInput -from typography_generation.model.decoder import Decoder, MultiTask -from typography_generation.model.embedding import Embedding -from typography_generation.model.encoder import Encoder - -FILTER_VALUE = -float("Inf") - - -def top_p( - prior: Tensor, - text_index: int, - sampling_param: float, -) -> int: - prior = F.softmax(prior, 1) - sorted_prob, sorted_label = torch.sort(input=prior, dim=1, descending=True) - prior = sorted_prob[text_index] - sum_p = 0 - for k in range(len(prior)): - sum_p += prior[k].item() - if sum_p > sampling_param: # prior - break - - range_class = k - if range_class == 0: - index = 0 - else: - index = random.randint(0, range_class) - out_label = sorted_label[text_index][index].item() - return out_label - - -def top_p_weight( - logits: Tensor, - text_index: int, - sampling_param: float, -) -> int: - sorted_logits, sorted_indices = torch.sort(logits, descending=True, dim=1) - cumulative_probs = torch.cumsum(F.softmax(sorted_logits, dim=1), dim=1) - S = logits.size(1) - indices = torch.arange(S).view(1, S).to(logits.device) - # make sure to keep the first logit (most likely one) - sorted_logits[(cumulative_probs > sampling_param) & (indices > 0)] = FILTER_VALUE - logits = sorted_logits.gather(dim=1, index=sorted_indices.argsort(dim=1)) - probs = F.softmax(logits, dim=1) - output = torch.multinomial(probs, num_samples=1) # (B, 1) - logger.debug(f"{output.shape}=") - return output[text_index][0].item() - - -sampler_dict = {"top_p": top_p, "top_p_weight": top_p_weight} - - -def sample_label( - logits: Tensor, text_index: int, sampling_param: float, mode: str = "top_p" -) -> int: - return sampler_dict[mode](logits, text_index, sampling_param) - - -def get_structure(pred: np.array, indexes: List) -> Dict: - index2samestructureindexes: Dict[str, List] - index2samestructureindexes = {} - for i in indexes: - index2samestructureindexes[i] = [] - label_i = pred[i] - for j in indexes: - label_j = pred[j] - if label_i == label_j: - index2samestructureindexes[i].append(j) - return index2samestructureindexes - - -def get_structure_dict(prefix_list: List, preds: Dict, indexes: List) -> Dict: - index2samestructureindexes = {} - for prefix in prefix_list: - index2samestructureindexes[prefix] = get_structure( - preds[prefix], - indexes, - ) - return index2samestructureindexes - - -def get_init_label_link(indexes: List) -> Dict: - label_link: Dict[str, Union[int, None]] - label_link = {} - for i in indexes: - label_link[i] = None - return label_link - - -def initialize_link(prefix_list: List, indexes: List) -> Tuple[Dict, Dict]: - label_link: Dict[str, Dict] - label_link = {} - used_labels: Dict[str, List] - used_labels = {} - for prefix in prefix_list: - label_link[prefix] = get_init_label_link(indexes) - used_labels[prefix] = [] - return label_link, used_labels - - -def label_linkage( - prefix_list: List, - text_num: int, - preds: Dict, -) -> Tuple[Dict, Dict, Dict]: - indexes = list(range(text_num)) - index2samestructureindexes = get_structure_dict(prefix_list, preds, indexes) - label_link, used_labels = initialize_link(prefix_list, indexes) - return index2samestructureindexes, label_link, used_labels - - -def update_label_link(label_link: Dict, samestructureindexes: List, label: int) -> Dict: - for i in samestructureindexes: - label_link[i] = label - return label_link - - -class BART(nn.Module): - def __init__( - self, - prefix_list_element: List, - prefix_list_canvas: List, - prefix_list_target: List, - embedding_config_element: TextElementContextEmbeddingAttributeConfig, - embedding_config_canvas: CanvasContextEmbeddingAttributeConfig, - prediction_config_element: TextElementContextPredictionAttributeConfig, - d_model: int = 256, - n_head: int = 8, - dropout: float = 0.1, - num_encoder_layers: int = 4, - num_decoder_layers: int = 4, - seq_length: int = 50, - bypass: bool = True, - **kwargs: Any, - ) -> None: - super().__init__() - logger.info(f"BART settings") - logger.info(f"d_model: {d_model}") - logger.info(f"n_head: {n_head}") - logger.info(f"num_encoder_layers: {num_encoder_layers}") - logger.info(f"num_decoder_layers: {num_decoder_layers}") - logger.info(f"seq_length: {seq_length}") - self.embedding_config_element = embedding_config_element - - self.emb = Embedding( - prefix_list_element, - prefix_list_canvas, - embedding_config_element, - embedding_config_canvas, - d_model=d_model, - dropout=dropout, - seq_length=seq_length, - ) - self.enc = Encoder( - d_model=d_model, - n_head=n_head, - dropout=dropout, - num_encoder_layers=num_encoder_layers, - ) - self.dec = Decoder( - prefix_list_target, - embedding_config_element, - d_model=d_model, - n_head=n_head, - dropout=dropout, - num_decoder_layers=num_decoder_layers, - seq_length=seq_length, - ) - self.head = MultiTask( - prefix_list_target, - prediction_config_element, - d_model, - bypass=bypass, - ) - self.initialize_weights() - - for prefix in prefix_list_target: - target_prediction_config = getattr(prediction_config_element, prefix) - setattr(self, f"{prefix}_att_type", target_prediction_config.att_type) - - def forward(self, model_inputs: ModelInput) -> Tensor: - start = time.time() - ( - src, - text_mask_src, - feat_cat, - ) = self.emb(model_inputs) - logger.debug(f"{time.time()-start} sec emb") - start = time.time() - z = self.enc(src, text_mask_src) - logger.debug(f"{time.time()-start} sec enc") - start = time.time() - zd = self.dec(feat_cat, z, model_inputs) - logger.debug(f"{time.time()-start} sec dec") - start = time.time() - outs = self.head(zd, feat_cat) - logger.debug(f"{time.time()-start} sec head") - return outs - - def tokenize_model_out( - self, - dataset: CrelloProcessor, - prefix: str, - model_out: Tensor, - batch_index, - text_index, - ) -> int: - if prefix in dataset.tokenizer.rawdata_list: - data = model_out[batch_index][text_index].data.cpu().numpy() - out_label = getattr(dataset, f"raw2token_{prefix}")(data) - else: - sorted_label = torch.sort( - input=model_out[batch_index], dim=1, descending=True - )[1] - target_label = 0 # top1 - out_label = sorted_label[text_index][target_label].item() - return out_label - - def get_labels( - self, - model_outs: Dict, - dataset: CrelloProcessor, - target_prefix_list: List, - text_index: int, - batch_index: int = 0, - ) -> Dict: - out_labels = {} - for prefix in target_prefix_list: - out = model_outs[f"{prefix}"] - out_label = self.tokenize_model_out( - dataset, prefix, out, batch_index, text_index - ) - - out_labels[f"{prefix}"] = out_label - - return out_labels - - def get_outs( - self, - model_outs: Dict, - dataset: CrelloProcessor, - target_prefix_list: List, - text_index: int, - batch_index: int = 0, - ) -> Dict: - outs = {} - for prefix in target_prefix_list: - out = model_outs[f"{prefix}"] - if prefix in dataset.tokenizer.rawdata_list: - data = out[batch_index][text_index].data.cpu().numpy() - else: - sorted_label = torch.sort( - input=out[batch_index], dim=1, descending=True - )[1] - target_label = 0 # top1 - data = sorted_label[text_index][target_label].item() - - outs[f"{prefix}"] = data - - return outs - - def store( - self, - outs_all: Dict, - outs: Dict, - target_prefix_list: List, - text_index: int, - ) -> Dict: - for prefix in target_prefix_list: - outs_all[f"{prefix}"][text_index] = outs[f"{prefix}"] - return outs_all - - def prediction( - self, - model_inputs: ModelInput, - dataset: CrelloProcessor, - target_prefix_list: List, - start_index: int = 0, - ) -> Tensor: - target_text_num = int(model_inputs.canvas_text_num[0].item()) - start_index = min(start_index, target_text_num) - for t in range(start_index, target_text_num): - model_inputs.zeroinitialize_th_style_attributes(target_prefix_list, t) - src, text_mask_src, feat_cat = self.emb(model_inputs) - z = self.enc(src, text_mask_src) - - outs_all = {} - for prefix in target_prefix_list: - outs_all[prefix] = {} - for t in range(0, start_index): - tar = getattr(model_inputs, f"{prefix}")[0, t].item() - outs_all[prefix][t] = tar - for t in range(start_index, target_text_num): - zd = self.dec(feat_cat, z, model_inputs) - model_outs = self.head(zd, feat_cat) - out_labels = self.get_labels(model_outs, dataset, target_prefix_list, t) - outs = self.get_outs(model_outs, dataset, target_prefix_list, t) - model_inputs.update_th_style_attributes( - self.embedding_config_element, target_prefix_list, out_labels, t - ) - outs_all = self.store(outs_all, outs, target_prefix_list, t) - return outs_all - - def get_transformer_weight( - self, - model_inputs: ModelInput, - dataset: CrelloProcessor, - target_prefix_list: List, - start_index: int = 0, - ) -> Tensor: - target_text_num = int(model_inputs.canvas_text_num[0].item()) - start_index = min(start_index, target_text_num) - for t in range(start_index, target_text_num): - model_inputs.zeroinitialize_th_style_attributes(target_prefix_list, t) - src, text_mask_src, feat_cat = self.emb(model_inputs) - z = self.enc(src, text_mask_src) - out_labels_all = {} - for prefix in target_prefix_list: - out_labels_all[prefix] = np.zeros((target_text_num, 1)) - for t in range(0, start_index): - tar = getattr(model_inputs, f"{prefix}")[0, t].item() - out_labels_all[prefix][t, 0] = tar - weights = [] - for t in range(start_index, target_text_num): - zd, _weights = self.dec.get_transformer_weight(feat_cat, z, model_inputs) - weights.append(_weights[0, t]) - model_outs = self.head(zd, feat_cat) - out_labels = self.get_labels(model_outs, dataset, target_prefix_list, t) - model_inputs.update_th_style_attributes( - self.embedding_config_element, target_prefix_list, out_labels, t - ) - out_labels_all = self.store( - out_labels_all, out_labels, target_prefix_list, t - ) - if len(weights) > 0: - weights = torch.stack(weights, dim=0) - return weights - else: - dummy_weights = torch.zeros((1, 1)).to(src.device) - return dummy_weights - - def sample_labels( - self, - model_outs: Dict, - target_prefix_list: List, - text_index: int, - sampling_param_geometry: float = 0.5, - sampling_param_semantic: float = 0.9, - batch_index: int = 0, - ) -> Dict: - out_labels = {} - for prefix in target_prefix_list: - out = model_outs[f"{prefix}"][batch_index] - if getattr(self, f"{prefix}_att_type") == "semantic": - sampling_param = sampling_param_semantic - elif getattr(self, f"{prefix}_att_type") == "geometry": - sampling_param = sampling_param_geometry - out_label = sample_label(out, text_index, sampling_param) - out_labels[f"{prefix}"] = out_label - - return out_labels - - def sample( - self, - model_inputs: ModelInput, - target_prefix_list: List, - sampling_param_geometry: float = 0.7, - sampling_param_semantic: float = 0.7, - start_index: int = 0, - **kwargs: Any, - ) -> Tensor: - target_text_num = int(model_inputs.canvas_text_num[0].item()) - start_index = min(start_index, target_text_num) - for t in range(start_index, target_text_num): - model_inputs.zeroinitialize_th_style_attributes(target_prefix_list, t) - src, text_mask_src, feat_cat = self.emb(model_inputs) - z = self.enc(src, text_mask_src) - - outs_all = {} - for prefix in target_prefix_list: - outs_all[prefix] = {} - for t in range(start_index, target_text_num): - zd = self.dec(feat_cat, z, model_inputs) - model_outs = self.head(zd, feat_cat) - out_labels = self.sample_labels( - model_outs, - target_prefix_list, - t, - sampling_param_geometry, - sampling_param_semantic, - ) - model_inputs.update_th_style_attributes( - self.embedding_config_element, target_prefix_list, out_labels, t - ) - outs_all = self.store(outs_all, out_labels, target_prefix_list, t) - return outs_all - - def sample_labels_with_structure( - self, - model_outs: Dict, - target_prefix_list: List, - text_index: int, - label_link: Dict, - used_labels: Dict, - index2samestructureindexes: Dict, - sampling_param_geometry: float = 0.5, - sampling_param_semantic: float = 0.9, - batch_index: int = 0, - ) -> Dict: - outs_all = {} - for prefix in target_prefix_list: - _label_link = label_link[prefix][text_index] - _used_labels = used_labels[prefix] - if _label_link is None: - out = model_outs[f"{prefix}"][batch_index] - cnt = 0 - sampling_type = getattr(self, f"{prefix}_att_type") - if sampling_type == "semantic": - sampling_param = sampling_param_semantic - elif sampling_type == "geometry": - sampling_param = sampling_param_geometry - - out_label = sample_label(out, text_index, sampling_param) - max_val = max( - torch.sum(F.softmax(out, 1)[text_index]).item(), sampling_param - ) - while out_label in _used_labels: - out_label = sample_label(out, text_index, sampling_param) - cnt += 1 - if cnt > 10: - sampling_param += abs((max_val - sampling_param) * 0.1) - if cnt > 1000: - sampling_param *= 2 - - samestructureindexes = index2samestructureindexes[prefix][text_index] - label_link[prefix] = update_label_link( - label_link[prefix], samestructureindexes, out_label - ) - used_labels[prefix].append(out_label) - else: - out_label = _label_link - outs_all[f"{prefix}"] = out_label - - return outs_all - - def structure_preserved_sample( - self, - model_inputs: ModelInput, - dataset: CrelloProcessor, - target_prefix_list: List, - sampling_param_geometry: float = 0.7, - sampling_param_semantic: float = 0.7, - start_index: int = 0, - ) -> Tensor: - target_text_num = int(model_inputs.canvas_text_num[0].item()) - preds = self.prediction(model_inputs, dataset, target_prefix_list) - index2samestructureindexes, label_link, used_labels = label_linkage( - target_prefix_list, target_text_num, preds - ) - - for t in range(start_index, target_text_num): - model_inputs.zeroinitialize_th_style_attributes(target_prefix_list, t) - src, text_mask_src, feat_cat = self.emb(model_inputs) - z = self.enc(src, text_mask_src) - - outs_all = {} - for prefix in target_prefix_list: - outs_all[prefix] = {} - for t in range(start_index, target_text_num): - zd = self.dec(feat_cat, z, model_inputs) - model_outs = self.head(zd, feat_cat) - out_labels = self.sample_labels_with_structure( - model_outs, - target_prefix_list, - t, - label_link, - used_labels, - index2samestructureindexes, - sampling_param_geometry, - sampling_param_semantic, - ) - model_inputs.update_th_style_attributes( - self.embedding_config_element, target_prefix_list, out_labels, t - ) - outs_all = self.store(outs_all, out_labels, target_prefix_list, t) - return outs_all - - def initialize_weights(self) -> None: - for m in self.modules(): - if isinstance(m, nn.Conv2d): - nn.init.xavier_normal_(m.weight) - 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): - m.weight.data.normal_(mean=0.0, std=0.02) - if m.bias is not None: - m.bias.data.zero_() - elif isinstance(m, nn.LayerNorm): - if m.weight is not None: - m.weight.data.fill_(1) - if m.bias is not None: - m.bias.data.zero_() - elif isinstance(m, nn.Embedding): - m.weight.data.normal_(mean=0.0, std=0.02) diff --git a/src/typography_generation/model/baseline.py b/src/typography_generation/model/baseline.py deleted file mode 100644 index 2fd67a2..0000000 --- a/src/typography_generation/model/baseline.py +++ /dev/null @@ -1,343 +0,0 @@ -import pickle -import random -from typing import Any, Dict, List, Tuple, Union -import numpy as np - -import torch -from logzero import logger -from torch import Tensor, nn -from typography_generation.config.attribute_config import ( - CanvasContextEmbeddingAttributeConfig, - TextElementContextEmbeddingAttributeConfig, - TextElementContextPredictionAttributeConfig, -) -from typography_generation.io.data_object import ModelInput -from typography_generation.model.bottleneck import ImlevelLF -from typography_generation.model.decoder import Decoder, MultiTask -from typography_generation.model.embedding import Embedding -from typography_generation.model.encoder import Encoder - - -class Baseline(nn.Module): - def __init__( - self, - prefix_list_element: List, - prefix_list_canvas: List, - prefix_list_target: List, - embedding_config_element: TextElementContextEmbeddingAttributeConfig, - embedding_config_canvas: CanvasContextEmbeddingAttributeConfig, - prediction_config_element: TextElementContextPredictionAttributeConfig, - d_model: int = 256, - n_head: int = 8, - dropout: float = 0.1, - num_encoder_layers: int = 4, - num_decoder_layers: int = 4, - seq_length: int = 50, - std_ratio: float = 1.0, - **kwargs: Any, - ) -> None: - super().__init__() - logger.info(f"CanvasVAE settings") - logger.info(f"d_model: {d_model}") - logger.info(f"n_head: {n_head}") - logger.info(f"num_encoder_layers: {num_encoder_layers}") - logger.info(f"num_decoder_layers: {num_decoder_layers}") - logger.info(f"seq_length: {seq_length}") - - self.emb = Embedding( - prefix_list_element, - prefix_list_canvas, - embedding_config_element, - embedding_config_canvas, - d_model, - dropout, - seq_length, - ) - self.enc = Encoder( - d_model=d_model, - n_head=n_head, - dropout=dropout, - num_encoder_layers=num_encoder_layers, - ) - self.lf = ImlevelLF(vae=True, std_ratio=std_ratio) - - self.dec = Decoder( - prefix_list_target, - embedding_config_element, - d_model=d_model, - n_head=n_head, - dropout=dropout, - num_decoder_layers=num_decoder_layers, - seq_length=seq_length, - autoregressive_scheme=False, - ) - self.head = MultiTask( - prefix_list_target, prediction_config_element, d_model, bypass=False - ) - self.initialize_weights() - - def forward(self, model_inputs: ModelInput) -> Tensor: - ( - src, - text_mask_src, - feat_cat, - ) = self.emb(model_inputs) - z = self.enc(src, text_mask_src) - z, vae_data = self.lf(z, text_mask_src) - zd = self.dec(feat_cat, z, model_inputs) - outs = self.head(zd, feat_cat) - outs["vae_data"] = vae_data - return outs - - def store( - self, - out_labels_all: Dict, - out_labels: Dict, - target_prefix_list: List, - text_index: int, - ) -> Dict: - for prefix in target_prefix_list: - out_labels_all[f"{prefix}"][text_index, 0] = out_labels[f"{prefix}"] - return out_labels_all - - def prediction( - self, - model_inputs: ModelInput, - target_prefix_list: List, - start_index: int = 0, - ) -> Tensor: - target_text_num = int(model_inputs.canvas_text_num[0].item()) - start_index = min(start_index, target_text_num) - for t in range(start_index, target_text_num): - model_inputs.zeroinitialize_th_style_attributes(target_prefix_list, t) - ( - src, - text_mask_src, - feat_cat, - ) = self.emb(model_inputs) - z = self.enc(src, text_mask_src) - z = self.lf.prediction(z, text_mask_src) - zd = self.dec(feat_cat, z, model_inputs) - model_outs = self.head(zd, feat_cat) - - out_labels_all = {} - for prefix in target_prefix_list: - out_labels_all[prefix] = np.zeros((target_text_num, 1)) - for t in range(0, start_index): - tar = getattr(model_inputs, f"{prefix}")[0, t].item() - out_labels_all[prefix][t, 0] = tar - - for t in range(start_index, target_text_num): - out_labels = self.get_labels(model_outs, target_prefix_list, t) - out_labels_all = self.store( - out_labels_all, out_labels, target_prefix_list, t - ) - return out_labels_all - - def sample( - self, - model_inputs: ModelInput, - target_prefix_list: List, - start_index: int = 0, - **kwargs: Any, - ) -> Tensor: - target_text_num = int(model_inputs.canvas_text_num[0].item()) - start_index = min(start_index, target_text_num) - for t in range(start_index, target_text_num): - model_inputs.zeroinitialize_th_style_attributes(target_prefix_list, t) - ( - src, - text_mask_src, - feat_cat, - ) = self.emb(model_inputs) - z = self.enc(src, text_mask_src) - z = self.lf.sample(z, text_mask_src) - zd = self.dec(feat_cat, z, model_inputs) - model_outs = self.head(zd, feat_cat) - out_labels_all = {} - for prefix in target_prefix_list: - out_labels_all[prefix] = np.zeros((target_text_num, 1)) - for t in range(0, start_index): - tar = getattr(model_inputs, f"{prefix}")[0, t].item() - out_labels_all[prefix][t, 0] = tar - - for t in range(start_index, target_text_num): - out_labels = self.get_labels(model_outs, target_prefix_list, t) - out_labels_all = self.store( - out_labels_all, out_labels, target_prefix_list, t - ) - return out_labels_all - - def initialize_weights(self) -> None: - for m in self.modules(): - if isinstance(m, nn.Conv2d): - nn.init.xavier_normal_(m.weight) - 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): - m.weight.data.normal_(mean=0.0, std=0.02) - if m.bias is not None: - m.bias.data.zero_() - elif isinstance(m, nn.LayerNorm): - if m.weight is not None: - m.weight.data.fill_(1) - if m.bias is not None: - m.bias.data.zero_() - elif isinstance(m, nn.Embedding): - m.weight.data.normal_(mean=0.0, std=0.02) - - -class AllZero(Baseline): - def __init__( - self, - prefix_list_element: List, - prefix_list_canvas: List, - prefix_list_target: List, - embedding_config_element: TextElementContextEmbeddingAttributeConfig, - embedding_config_canvas: CanvasContextEmbeddingAttributeConfig, - prediction_config_element: TextElementContextPredictionAttributeConfig, - d_model: int = 256, - n_head: int = 8, - dropout: float = 0.1, - num_encoder_layers: int = 4, - num_decoder_layers: int = 4, - seq_length: int = 50, - std_ratio: float = 1.0, - **kwargs: Any, - ) -> None: - super().__init__( - prefix_list_element, - prefix_list_canvas, - prefix_list_target, - embedding_config_element, - embedding_config_canvas, - prediction_config_element, - d_model, - n_head, - dropout, - num_encoder_layers, - num_decoder_layers, - seq_length, - std_ratio, - ) - - def get_labels( - self, - model_outs: Union[Dict, None], - target_prefix_list: List, - text_index: int, - batch_index: int = 0, - ) -> Dict: - out_labels = {} - for prefix in target_prefix_list: - out_labels[f"{prefix}"] = 0 - - return out_labels - - -class AllRandom(Baseline): - def __init__( - self, - prefix_list_element: List, - prefix_list_canvas: List, - prefix_list_target: List, - embedding_config_element: TextElementContextEmbeddingAttributeConfig, - embedding_config_canvas: CanvasContextEmbeddingAttributeConfig, - prediction_config_element: TextElementContextPredictionAttributeConfig, - d_model: int = 256, - n_head: int = 8, - dropout: float = 0.1, - num_encoder_layers: int = 4, - num_decoder_layers: int = 4, - seq_length: int = 50, - std_ratio: float = 1.0, - **kwargs: Any, - ) -> None: - super().__init__( - prefix_list_element, - prefix_list_canvas, - prefix_list_target, - embedding_config_element, - embedding_config_canvas, - prediction_config_element, - d_model, - n_head, - dropout, - num_encoder_layers, - num_decoder_layers, - seq_length, - std_ratio, - ) - - def get_labels( - self, - model_outs: Dict, - target_prefix_list: List, - text_index: int, - batch_index: int = 0, - ) -> Dict: - out_labels = {} - for prefix in target_prefix_list: - out = model_outs[f"{prefix}"] - label_range = len(out[batch_index][text_index]) - out_labels[f"{prefix}"] = random.randint(0, label_range - 1) - - return out_labels - - -class Mode(Baseline): - def __init__( - self, - prefix_list_element: List, - prefix_list_canvas: List, - prefix_list_target: List, - embedding_config_element: TextElementContextEmbeddingAttributeConfig, - embedding_config_canvas: CanvasContextEmbeddingAttributeConfig, - prediction_config_element: TextElementContextPredictionAttributeConfig, - d_model: int = 256, - n_head: int = 8, - dropout: float = 0.1, - num_encoder_layers: int = 4, - num_decoder_layers: int = 4, - seq_length: int = 50, - std_ratio: float = 1.0, - **kwargs: Any, - ) -> None: - super().__init__( - prefix_list_element, - prefix_list_canvas, - prefix_list_target, - embedding_config_element, - embedding_config_canvas, - prediction_config_element, - d_model, - n_head, - dropout, - num_encoder_layers, - num_decoder_layers, - seq_length, - std_ratio, - ) - self.prefix2mode = pickle.load( - open( - f"prefix2mode.pkl", - "rb", - ) - ) - - def get_labels( - self, - model_outs: Dict, - target_prefix_list: List, - text_index: int, - batch_index: int = 0, - ) -> Dict: - out_labels = {} - for prefix in target_prefix_list: - out = model_outs[f"{prefix}"] - out_labels[f"{prefix}"] = self.prefix2mode[prefix] - - return out_labels diff --git a/src/typography_generation/model/bottleneck.py b/src/typography_generation/model/bottleneck.py deleted file mode 100644 index 0c7569e..0000000 --- a/src/typography_generation/model/bottleneck.py +++ /dev/null @@ -1,100 +0,0 @@ -from typing import Tuple - -import torch -from torch import Tensor, nn - - -class VAE(nn.Module): - def __init__( - self, - d_model: int = 256, - reparametric: bool = True, - std_ratio: float = 1.0, - ): - super(VAE, self).__init__() - self.d_model = d_model - self.enc_mu_fcn = nn.Linear(d_model, d_model) - self.enc_sigma_fcn = nn.Linear(d_model, d_model) - self.reparametoric = reparametric - self.stdrate = std_ratio - - def _init_embeddings(self) -> None: - nn.init.normal_(self.enc_mu_fcn.weight, std=0.001) - nn.init.constant_(self.enc_mu_fcn.bias, 0) - nn.init.normal_(self.enc_sigma_fcn.weight, std=0.001) - nn.init.constant_(self.enc_sigma_fcn.bias, 0) - - def forward(self, z: Tensor) -> Tuple: - mu, logsigma = self.enc_mu_fcn(z), self.enc_sigma_fcn(z) - sigma = torch.exp(logsigma / 2.0) - z = mu + sigma * torch.randn_like(sigma) * self.stdrate - return z, (mu, logsigma) - - def prediction(self, z: Tensor) -> Tensor: - mu = self.enc_mu_fcn(z) - z = mu - return z - - def sample(self, z: Tensor) -> Tensor: - mu, logsigma = self.enc_mu_fcn(z), self.enc_sigma_fcn(z) - sigma = torch.exp(logsigma / 2.0) - z = mu + sigma * torch.randn_like(sigma) * self.stdrate - return z - - -class ImlevelLF(nn.Module): - def __init__( - self, - vae: bool = False, - std_ratio: float = 1.0, - ): - super().__init__() - self.vae_flag = vae - if vae is True: - self.vae = VAE(std_ratio=std_ratio) - - def forward(self, z: Tensor, text_mask: Tensor) -> Tensor: - text_mask = ( - text_mask.permute(1, 0) - .view(z.shape[0], z.shape[1], 1) - .repeat(1, 1, z.shape[2]) - ) - z_tmp = torch.sum(z * text_mask, dim=0) / (torch.sum(text_mask, dim=0) + 1e-20) - - vae_item = [] - if self.vae_flag is True: - z_tmp, vae_item_iml = self.vae(z_tmp) - vae_item.append(vae_item_iml) - return z_tmp.unsqueeze(0), vae_item - - def prediction(self, z: Tensor, text_mask: Tensor) -> Tensor: - text_mask = ( - text_mask.permute(1, 0) - .view(z.shape[0], z.shape[1], 1) - .repeat(1, 1, z.shape[2]) - ) - z_tmp = torch.sum(z * text_mask, dim=0) / (torch.sum(text_mask, dim=0) + 1e-20) - - if self.vae_flag is True: - z_tmp = self.vae.prediction(z_tmp) - return z_tmp.unsqueeze(0) - - def sample(self, z: Tensor, text_mask: Tensor) -> Tensor: - text_mask = ( - text_mask.permute(1, 0) - .view(z.shape[0], z.shape[1], 1) - .repeat(1, 1, z.shape[2]) - ) - z_tmp = torch.sum(z * text_mask, dim=0) / (torch.sum(text_mask, dim=0) + 1e-20) - - z_tmp = self.vae.sample(z_tmp) - return z_tmp.unsqueeze(0) - - -class Bottleneck(nn.Module): - def __init__(self) -> None: - super(Bottleneck, self).__init__() - pass - - def forward(self, z: Tensor) -> Tensor: - return z diff --git a/src/typography_generation/model/canvas_vae.py b/src/typography_generation/model/canvas_vae.py deleted file mode 100644 index b05bb8f..0000000 --- a/src/typography_generation/model/canvas_vae.py +++ /dev/null @@ -1,207 +0,0 @@ -from typing import Any, Dict, List, Tuple -import numpy as np - -import torch -from logzero import logger -from torch import Tensor, nn -from typography_generation.config.attribute_config import ( - CanvasContextEmbeddingAttributeConfig, - TextElementContextEmbeddingAttributeConfig, - TextElementContextPredictionAttributeConfig, -) -from typography_generation.io.crello_util import CrelloProcessor -from typography_generation.io.data_object import ModelInput -from typography_generation.model.bottleneck import ImlevelLF -from typography_generation.model.decoder import Decoder, MultiTask -from typography_generation.model.embedding import Embedding -from typography_generation.model.encoder import Encoder - - -class CanvasVAE(nn.Module): - def __init__( - self, - prefix_list_element: List, - prefix_list_canvas: List, - prefix_list_target: List, - embedding_config_element: TextElementContextEmbeddingAttributeConfig, - embedding_config_canvas: CanvasContextEmbeddingAttributeConfig, - prediction_config_element: TextElementContextPredictionAttributeConfig, - d_model: int = 256, - n_head: int = 8, - dropout: float = 0.1, - num_encoder_layers: int = 4, - num_decoder_layers: int = 4, - seq_length: int = 50, - std_ratio: float = 1.0, - **kwargs: Any, - ) -> None: - super().__init__() - logger.info(f"CanvasVAE settings") - logger.info(f"d_model: {d_model}") - logger.info(f"n_head: {n_head}") - logger.info(f"num_encoder_layers: {num_encoder_layers}") - logger.info(f"num_decoder_layers: {num_decoder_layers}") - logger.info(f"seq_length: {seq_length}") - - self.emb = Embedding( - prefix_list_element, - prefix_list_canvas, - embedding_config_element, - embedding_config_canvas, - d_model, - dropout, - seq_length, - ) - self.enc = Encoder( - d_model=d_model, - n_head=n_head, - dropout=dropout, - num_encoder_layers=num_encoder_layers, - ) - self.lf = ImlevelLF(vae=True, std_ratio=std_ratio) - - self.dec = Decoder( - prefix_list_target, - embedding_config_element, - d_model=d_model, - n_head=n_head, - dropout=dropout, - num_decoder_layers=num_decoder_layers, - seq_length=seq_length, - autoregressive_scheme=False, - ) - self.head = MultiTask( - prefix_list_target, prediction_config_element, d_model, bypass=False - ) - self.initialize_weights() - - def forward(self, model_inputs: ModelInput) -> Tensor: - ( - src, - text_mask_src, - feat_cat, - ) = self.emb(model_inputs) - z = self.enc(src, text_mask_src) - z, vae_data = self.lf(z, text_mask_src) - zd = self.dec(feat_cat, z, model_inputs) - outs = self.head(zd, feat_cat) - outs["vae_data"] = vae_data - return outs - - def get_labels( - self, - model_outs: Dict, - target_prefix_list: List, - text_index: int, - batch_index: int = 0, - ) -> Dict: - out_labels = {} - for prefix in target_prefix_list: - out = model_outs[f"{prefix}"] - sorted_label = torch.sort(input=out[batch_index], dim=1, descending=True)[1] - target_label = 0 # top1 - out_label = sorted_label[text_index][target_label] - out_labels[f"{prefix}"] = out_label - - return out_labels - - def store( - self, - out_labels_all: Dict, - out_labels: Dict, - target_prefix_list: List, - text_index: int, - ) -> Dict: - for prefix in target_prefix_list: - out_labels_all[f"{prefix}"][text_index] = out_labels[f"{prefix}"].item() - return out_labels_all - - def prediction( - self, - model_inputs: ModelInput, - dataset: CrelloProcessor, - target_prefix_list: List, - start_index: int = 0, - ) -> Tensor: - target_text_num = int(model_inputs.canvas_text_num[0].item()) - start_index = min(start_index, target_text_num) - for t in range(start_index, target_text_num): - model_inputs.zeroinitialize_th_style_attributes(target_prefix_list, t) - ( - src, - text_mask_src, - feat_cat, - ) = self.emb(model_inputs) - z = self.enc(src, text_mask_src) - z = self.lf.prediction(z, text_mask_src) - zd = self.dec(feat_cat, z, model_inputs) - model_outs = self.head(zd, feat_cat) - - out_labels_all = {} - for prefix in target_prefix_list: - out_labels_all[prefix] = np.zeros((target_text_num, 1)) - for t in range(0, start_index): - tar = getattr(model_inputs, f"{prefix}")[0, t].item() - out_labels_all[prefix][t, 0] = tar - - for t in range(start_index, target_text_num): - out_labels = self.get_labels(model_outs, target_prefix_list, t) - out_labels_all = self.store( - out_labels_all, out_labels, target_prefix_list, t - ) - return out_labels_all - - def sample( - self, - model_inputs: ModelInput, - target_prefix_list: List, - start_index: int = 0, - **kwargs: Any, - ) -> Tensor: - target_text_num = int(model_inputs.canvas_text_num[0].item()) - start_index = min(start_index, target_text_num) - for t in range(start_index, target_text_num): - model_inputs.zeroinitialize_th_style_attributes(target_prefix_list, t) - ( - src, - text_mask_src, - feat_cat, - ) = self.emb(model_inputs) - z = self.enc(src, text_mask_src) - z = self.lf.sample(z, text_mask_src) - zd = self.dec(feat_cat, z, model_inputs) - model_outs = self.head(zd, feat_cat) - out_labels_all = {} - for prefix in target_prefix_list: - out_labels_all[prefix] = np.zeros((target_text_num, 1)) - for t in range(0, start_index): - tar = getattr(model_inputs, f"{prefix}")[0, t].item() - out_labels_all[prefix][t, 0] = tar - - for t in range(start_index, target_text_num): - out_labels = self.get_labels(model_outs, target_prefix_list, t) - out_labels_all = self.store( - out_labels_all, out_labels, target_prefix_list, t - ) - return out_labels_all - - def initialize_weights(self) -> None: - for m in self.modules(): - if isinstance(m, nn.Conv2d): - nn.init.xavier_normal_(m.weight) - 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): - m.weight.data.normal_(mean=0.0, std=0.02) - if m.bias is not None: - m.bias.data.zero_() - elif isinstance(m, nn.LayerNorm): - if m.weight is not None: - m.weight.data.fill_(1) - if m.bias is not None: - m.bias.data.zero_() - elif isinstance(m, nn.Embedding): - m.weight.data.normal_(mean=0.0, std=0.02) diff --git a/src/typography_generation/model/common.py b/src/typography_generation/model/common.py deleted file mode 100644 index 30296b2..0000000 --- a/src/typography_generation/model/common.py +++ /dev/null @@ -1,446 +0,0 @@ -import copy -from collections import OrderedDict -from typing import Any, Callable, Optional, Union - -import torch -from torch import Tensor, nn -from torch.functional import F - - -def _get_clones(module: Any, N: int) -> nn.ModuleList: - return nn.ModuleList([copy.deepcopy(module) for i in range(N)]) - - -def _get_activation_fn(activation: Any) -> Any: - if activation == "relu": - return F.relu - elif activation == "gelu": - return F.gelu - raise RuntimeError("activation should be relu/gelu, not {}".format(activation)) - - -def _get_seq_len(src: Tensor, batch_first: bool) -> Optional[int]: - if src.is_nested: - return None - else: - src_size = src.size() - if len(src_size) == 2: - # unbatched: S, E - return src_size[0] - else: - # batched: B, S, E if batch_first else S, B, E - seq_len_pos = 1 if batch_first else 0 - return src_size[seq_len_pos] - - -def _generate_square_subsequent_mask( - sz: int, - device: torch.device = torch.device( - torch._C._get_default_device() - ), # torch.device('cpu'), - dtype: torch.dtype = torch.get_default_dtype(), -) -> Tensor: - r"""Generate a square causal mask for the sequence. The masked positions are filled with float('-inf'). - Unmasked positions are filled with float(0.0). - """ - return torch.triu( - torch.full((sz, sz), float("-inf"), dtype=dtype, device=device), - diagonal=1, - ) - - -def _detect_is_causal_mask( - mask: Optional[Tensor], - is_causal: Optional[bool] = None, - size: Optional[int] = None, -) -> bool: - # Prevent type refinement - make_causal = is_causal is True - - if is_causal is None and mask is not None: - sz = size if size is not None else mask.size(-2) - causal_comparison = _generate_square_subsequent_mask( - sz, device=mask.device, dtype=mask.dtype - ) - - # Do not use `torch.equal` so we handle batched masks by - # broadcasting the comparison. - if mask.size() == causal_comparison.size(): - make_causal = bool((mask == causal_comparison).all()) - else: - make_causal = False - - return make_causal - - -class MyTransformerDecoder(nn.Module): - __constants__ = ["norm"] - - def __init__(self, decoder_layer, num_layers, norm=None): - super().__init__() - torch._C._log_api_usage_once(f"torch.nn.modules.{self.__class__.__name__}") - self.layers = _get_clones(decoder_layer, num_layers) - self.num_layers = num_layers - self.norm = norm - - def forward( - self, - tgt: Tensor, - memory: Tensor, - tgt_mask: Optional[Tensor] = None, - memory_mask: Optional[Tensor] = None, - tgt_key_padding_mask: Optional[Tensor] = None, - memory_key_padding_mask: Optional[Tensor] = None, - get_weight: bool = False, - ) -> Tensor: - output = tgt - - seq_len = _get_seq_len(tgt, self.layers[0].self_attn.batch_first) - - for mod in self.layers: - output, w = mod( - output, - memory, - tgt_mask=tgt_mask, - memory_mask=memory_mask, - tgt_key_padding_mask=tgt_key_padding_mask, - memory_key_padding_mask=memory_key_padding_mask, - ) - - if self.norm is not None: - output = self.norm(output) - - if get_weight is True: - return output, w - else: - return output - - -class MyTransformerDecoderLayer(nn.Module): - __constants__ = ["batch_first"] - - def __init__( - self, - d_model: float = 256, - nhead: int = 8, - dim_feedforward: int = 2048, - dropout: float = 0.1, - activation: str = "relu", - layer_norm_eps: float = 1e-5, - batch_first: bool = False, - device: Any = None, - dtype: Any = None, - ) -> None: - factory_kwargs = {"device": device, "dtype": dtype} - super().__init__() - self.self_attn = nn.MultiheadAttention( - d_model, nhead, dropout=dropout, batch_first=batch_first, **factory_kwargs - ) - self.multihead_attn = nn.MultiheadAttention( - d_model, nhead, dropout=dropout, batch_first=batch_first, **factory_kwargs - ) - # Implementation of Feedforward model - self.linear1 = nn.Linear(d_model, dim_feedforward, **factory_kwargs) - self.linear2 = nn.Linear(dim_feedforward, d_model, **factory_kwargs) - self.dropout = nn.Dropout(dropout) - self.norm1 = nn.LayerNorm(d_model, eps=layer_norm_eps, **factory_kwargs) - self.norm2 = nn.LayerNorm(d_model, eps=layer_norm_eps, **factory_kwargs) - self.norm3 = nn.LayerNorm(d_model, eps=layer_norm_eps, **factory_kwargs) - self.dropout1 = nn.Dropout(dropout) - self.dropout2 = nn.Dropout(dropout) - self.dropout3 = nn.Dropout(dropout) - - self.activation = _get_activation_fn(activation) - - def __setstate__(self, state: Any) -> None: - if "activation" not in state: - state["activation"] = F.relu - super().__setstate__(state) - - def forward( - self, - tgt: torch.Tensor, - memory: torch.Tensor, - tgt_mask: Optional[torch.Tensor] = None, - memory_mask: Optional[torch.Tensor] = None, - tgt_key_padding_mask: Optional[torch.Tensor] = None, - memory_key_padding_mask: Optional[torch.Tensor] = None, - ) -> torch.Tensor: - tgt2 = self.self_attn( - tgt, tgt, tgt, attn_mask=tgt_mask, key_padding_mask=tgt_key_padding_mask - )[0] - tgt = tgt + self.dropout1(tgt2) - tgt = self.norm1(tgt) - tgt2, weight = self.multihead_attn( - tgt, - memory, - memory, - attn_mask=memory_mask, - key_padding_mask=memory_key_padding_mask, - ) - tgt = tgt + self.dropout2(tgt2) - tgt = self.norm2(tgt) - tgt2 = self.linear2(self.dropout(self.activation(self.linear1(tgt)))) - tgt = tgt + self.dropout3(tgt2) - tgt = self.norm3(tgt) - return tgt, weight - - -class MyTransformerEncoder(nn.Module): - __constants__ = ["norm"] - - def __init__( - self, encoder_layer: nn.Module, num_layers: int, norm: Any = None - ) -> None: - super(MyTransformerEncoder, self).__init__() - self.layers = _get_clones(encoder_layer, num_layers) - self.num_layers = num_layers - self.norm = norm - - def forward( - self, - src: Tensor, - mask: Optional[Tensor] = None, - src_key_padding_mask: Optional[Tensor] = None, - get_weight: bool = False, - ) -> Tensor: - output = src - for mod in self.layers: - output, w = mod( - output, - src_mask=mask, - src_key_padding_mask=src_key_padding_mask, - ) - - if self.norm is not None: - output = self.norm(output) - if get_weight is True: - return output, w - else: - return output - - -class MyTransformerEncoderLayer(nn.Module): - __constants__ = ["batch_first"] - - def __init__( - self, - d_model: int, - nhead: int, - dim_feedforward: int = 2048, - dropout: float = 0.1, - activation: Union[str, Callable[[Tensor], Tensor]] = F.relu, - layer_norm_eps: float = 1e-5, - batch_first: bool = False, - norm_first: bool = False, - device: Any = None, - dtype: Any = None, - ) -> None: - factory_kwargs = {"device": device, "dtype": dtype} - super(MyTransformerEncoderLayer, self).__init__() - self.self_attn = nn.MultiheadAttention( - d_model, nhead, dropout=dropout, batch_first=batch_first, **factory_kwargs - ) - # Implementation of Feedforward model - self.linear1 = nn.Linear(d_model, dim_feedforward, **factory_kwargs) - self.dropout = nn.Dropout(dropout) - self.linear2 = nn.Linear(dim_feedforward, d_model, **factory_kwargs) - - self.norm_first = norm_first - self.norm1 = nn.LayerNorm(d_model, eps=layer_norm_eps, **factory_kwargs) - self.norm2 = nn.LayerNorm(d_model, eps=layer_norm_eps, **factory_kwargs) - self.dropout1 = nn.Dropout(dropout) - self.dropout2 = nn.Dropout(dropout) - - # Legacy string support for activation function. - if isinstance(activation, str): - self.activation = _get_activation_fn(activation) - else: - self.activation = activation - - def __setstate__(self, state: Any) -> None: - if "activation" not in state: - state["activation"] = F.relu - super(MyTransformerEncoderLayer, self).__setstate__(state) - - def forward( - self, - src: Tensor, - src_mask: Optional[Tensor] = None, - src_key_padding_mask: Optional[Tensor] = None, - ) -> Tensor: - x = src - if self.norm_first: - sa, w = self._sa_block(self.norm1(x), src_mask, src_key_padding_mask) - x = x + sa - x = x + self._ff_block(self.norm2(x)) - else: - sa, w = self._sa_block(x, src_mask, src_key_padding_mask) - x = self.norm1(x + sa) - x = self.norm2(x + self._ff_block(x)) - - return x, w - - # self-attention block - def _sa_block( - self, x: Tensor, attn_mask: Optional[Tensor], key_padding_mask: Optional[Tensor] - ) -> Tensor: - x, w = self.self_attn( - x, - x, - x, - attn_mask=attn_mask, - key_padding_mask=key_padding_mask, - need_weights=True, - ) - return self.dropout1(x), w - - # feed forward block - def _ff_block(self, x: Tensor) -> Tensor: - x = self.linear2(self.dropout(self.activation(self.linear1(x)))) - return self.dropout2(x) - - -def _conv3x3_bn_relu( - in_channels: int, - out_channels: int, - dilation: int = 1, - kernel_size: int = 3, - stride: int = 1, -) -> nn.Sequential: - if dilation == 0: - dilation = 1 - padding = 0 - else: - padding = dilation - return nn.Sequential( - OrderedDict( - [ - ( - "conv", - nn.Conv2d( - in_channels, - out_channels, - kernel_size=kernel_size, - stride=stride, - padding=padding, - dilation=dilation, - bias=False, - ), - ), - ("bn", nn.BatchNorm2d(out_channels)), - ("relu", nn.ReLU()), - ] - ) - ) - - -class LinearView(nn.Module): - def __init__(self, channel: int) -> None: - super(LinearView, self).__init__() - self.channel = channel - - def forward(self, x: Tensor) -> Tensor: - if len(x.shape) == 3: - BN, CHARN, CN = x.shape - if CHARN == 1: - x = x.view(BN, self.channel) - return x - - -def fn_ln_relu(fn: Any, out_channels: int, dp: float = 0.1) -> nn.Sequential: - return nn.Sequential( - OrderedDict( - [ - ("fn", fn), - ("ln", nn.LayerNorm(out_channels)), - ("view", LinearView(out_channels)), - ("dp", nn.Dropout(dp)), - ] - ) - ) - - -class Linearx2(nn.Module): - def __init__(self, in_ch: int, out_ch: int) -> None: - super().__init__() - self.fcn = nn.Sequential( - OrderedDict( - [ - ("l1", nn.Linear(in_ch, in_ch)), - ("r1", nn.LeakyReLU(0.2)), - ("l2", nn.Linear(in_ch, out_ch)), - ] - ) - ) - - def forward(self, out: Tensor) -> Tensor: - logits = self.fcn(out) # Shape [G, N, 2] - return logits - - -class Linearx3(nn.Module): - def __init__(self, in_ch: int, out_ch: int) -> None: - super().__init__() - self.fcn = nn.Sequential( - OrderedDict( - [ - ("l1", nn.Linear(in_ch, in_ch)), - ("r1", nn.LeakyReLU(0.2)), - ("l1", nn.Linear(in_ch, in_ch)), - ("r1", nn.LeakyReLU(0.2)), - ("l2", nn.Linear(in_ch, out_ch)), - ] - ) - ) - - def forward(self, out: Tensor) -> Tensor: - logits = self.fcn(out) # Shape [G, N, 2] - return logits - - -class ConstEmbedding(nn.Module): - def __init__( - self, d_model: int = 256, seq_len: int = 50, positional_encoding: bool = True - ): - super().__init__() - self.d_model = d_model - self.seq_len = seq_len - self.PE = PositionalEncodingLUT( - d_model, max_len=seq_len, positional_encoding=positional_encoding - ) - - def forward(self, z: Tensor) -> Tensor: - if len(z.shape) == 2: - N = z.size(0) - elif len(z.shape) == 3: - N = z.size(1) - else: - raise Exception - pos = self.PE(z.new_zeros(self.seq_len, N, self.d_model)) - return pos - - -class PositionalEncodingLUT(nn.Module): - def __init__( - self, - d_model: int = 256, - dropout: float = 0.1, - max_len: int = 50, - positional_encoding: bool = True, - ): - super(PositionalEncodingLUT, self).__init__() - self.PS = positional_encoding - self.dropout = nn.Dropout(p=dropout) - position = torch.arange(0, max_len, dtype=torch.long).unsqueeze(1) - self.register_buffer("position", position) - self.pos_embed = nn.Embedding(max_len, d_model) - self._init_embeddings() - - def _init_embeddings(self) -> None: - nn.init.kaiming_normal_(self.pos_embed.weight, mode="fan_in") - - def forward(self, x: Tensor, inp_ignore: bool = False) -> Tensor: - pos = self.position[: x.size(0)] - x = self.pos_embed(pos).repeat(1, x.size(1), 1) - return self.dropout(x) diff --git a/src/typography_generation/model/decoder.py b/src/typography_generation/model/decoder.py deleted file mode 100644 index a2b33ff..0000000 --- a/src/typography_generation/model/decoder.py +++ /dev/null @@ -1,210 +0,0 @@ -from typing import Any, List, Tuple - -import torch -from torch import Tensor, nn -from typography_generation.config.attribute_config import ( - TextElementContextEmbeddingAttributeConfig, - TextElementContextPredictionAttributeConfig, -) -from typography_generation.io.data_object import ModelInput -from typography_generation.model.common import ( - ConstEmbedding, - Linearx2, - MyTransformerDecoder, - MyTransformerDecoderLayer, - fn_ln_relu, -) - - -class Decoder(nn.Module): - def __init__( - self, - prefix_list_target: List, - embedding_config_element: TextElementContextEmbeddingAttributeConfig, - d_model: int = 256, - n_head: int = 8, - dropout: float = 0.1, - num_decoder_layers: int = 4, - seq_length: int = 50, - positional_encoding: bool = True, - autoregressive_scheme: bool = True, - ): - super().__init__() - - self.prefix_list_target = prefix_list_target - self.d_model = d_model - self.dropout_element = dropout - self.seq_length = seq_length - self.autoregressive_scheme = autoregressive_scheme - dim_feedforward = d_model * 2 - - # Positional encoding in transformer - position = torch.arange(0, 1, dtype=torch.long).unsqueeze(1) - self.register_buffer("position", position) - self.pos_embed = nn.Embedding(1, d_model) - self.embedding = ConstEmbedding(d_model, seq_length, positional_encoding) - - # Decoder layer - # decoder_layer = nn.TransformerDecoderLayer( - # d_model, n_head, dim_feedforward, dropout - # ) - decoder_norm = nn.LayerNorm(d_model) - # self.decoder = nn.TransformerDecoder( - # decoder_layer, num_decoder_layers, decoder_norm - # ) - decoder_layer = MyTransformerDecoderLayer( - d_model, n_head, dim_feedforward, dropout - ) - self.decoder = MyTransformerDecoder( - decoder_layer, num_decoder_layers, decoder_norm - ) - - # mask config in training - mask_tgt = torch.ones((seq_length, seq_length)) - mask_tgt = torch.triu(mask_tgt == 1).transpose(0, 1) - self.mask_tgt = mask_tgt.float().masked_fill(mask_tgt == 0, float("-inf")) - # Build bart embedding - self.build_bart_embedding(prefix_list_target, embedding_config_element) - - def build_bart_embedding( - self, - prefix_list_target: List, - embedding_config_element: TextElementContextEmbeddingAttributeConfig, - ) -> None: - for prefix in prefix_list_target: - target_embedding_config = getattr(embedding_config_element, prefix) - kwargs = target_embedding_config.emb_layer_kwargs # dict of args - emb_layer = nn.Embedding(**kwargs) - emb_layer = fn_ln_relu(emb_layer, self.d_model, self.dropout_element) - setattr(self, f"{prefix}_emb", emb_layer) - setattr(self, f"{prefix}_flag", target_embedding_config.flag) - - def get_features_via_fn( - self, fn: Any, inputs: List, batch_num: int, text_num: Tensor - ) -> Tensor: - inputs_fn = [] - for b in range(batch_num): - tn = int(text_num[b].item()) - for t in range(tn): - inputs_fn.append(inputs[b][t].view(-1)) - outs = None - if len(inputs_fn) > 0: - inputs_fn = torch.stack(inputs_fn) - outs = fn(inputs_fn) - outs = outs.view(len(inputs_fn), self.d_model) - feat = torch.zeros(self.seq_length, batch_num, self.d_model) - feat = feat.to(text_num.device).float() - cnt = 0 - for b in range(batch_num): - tn = int(text_num[b].item()) - for t in range(tn): - if outs is not None: - feat[t, b] = outs[cnt] - cnt += 1 - return feat - - def get_style_context_embedding( - self, model_inputs: ModelInput, batch_num: int, text_num: Tensor - ) -> Tensor: - feat = torch.zeros(self.seq_length, batch_num, self.d_model) - feat = feat.to(text_num.device).float() - for prefix in self.prefix_list_target: - inp = getattr(model_inputs, prefix).long() - layer = getattr(self, f"{prefix}_emb") - f = self.get_features_via_fn(layer, inp, batch_num, text_num) - feat = feat + f - feat = feat / len(self.prefix_list_target) - return feat - - def shift_context_feat( - self, context_feat: Tensor, batch_num: int, text_num: Tensor - ) -> Tensor: - shifted_context_feat = torch.zeros(self.seq_length, batch_num, self.d_model) - shifted_context_feat = shifted_context_feat.to(text_num.device).float() - for b in range(batch_num): - tn = int(text_num[b].item()) - for t in range(tn - 1): - shifted_context_feat[t + 1, b] = context_feat[t, b] - return shifted_context_feat - - def get_bart_embedding(self, src: Tensor, model_inputs: ModelInput) -> Tensor: - batch_num, text_num = model_inputs.batch_num, model_inputs.canvas_text_num - context_feat = self.get_style_context_embedding( - model_inputs, batch_num, text_num - ) - shifted_context_feat = self.shift_context_feat( - context_feat, batch_num, text_num - ) - position_feat = self.embedding(src) - return shifted_context_feat + position_feat - - def forward( - self, - src: Tensor, - z: Tensor, - model_inputs: ModelInput, - ) -> Tensor: - if self.autoregressive_scheme is True: - src = self.get_bart_embedding(src, model_inputs) - else: - src = self.embedding(src) - mask_tgt = self.mask_tgt.to(src.device) - out = self.decoder(src, z, mask_tgt, tgt_key_padding_mask=None) - return out - - def get_transformer_weight( - self, - src: Tensor, - z: Tensor, - model_inputs: ModelInput, - ) -> Tuple: - if self.autoregressive_scheme is True: - src = self.get_bart_embedding(src, model_inputs) - else: - src = self.embedding(src) - mask_tgt = self.mask_tgt.to(src.device) - out, weights = self.decoder( - src, z, mask_tgt, tgt_key_padding_mask=None, get_weight=True - ) - return out, weights - - -class FCN(nn.Module): - def __init__(self, d_model: int, label_num: int, bypass: bool) -> None: - super().__init__() - self.bypass = bypass - if bypass is True: - self.fcn = Linearx2(d_model * 2, label_num) - else: - self.fcn = Linearx2(d_model, label_num) - - def forward(self, inp: Tensor, elm_agg_emb: Tensor = None) -> Tensor: - if self.bypass is True: - inp = torch.cat((inp, elm_agg_emb), 2) - logits = inp.permute(1, 0, 2) - logits = self.fcn(logits) # Shape [G, N, 2] - return logits - - -class MultiTask(nn.Module): - def __init__( - self, - prefix_list_target: List, - prediction_config: TextElementContextPredictionAttributeConfig, - d_model: int = 256, - bypass: bool = True, - ): - super().__init__() - self.prefix_list_target = prefix_list_target - for prefix in self.prefix_list_target: - target_prediction_config = getattr(prediction_config, prefix) - layer = FCN(d_model, target_prediction_config.out_dim, bypass) - setattr(self, f"{prefix}_layer", layer) - - def forward(self, z: Tensor, elm_agg_emb: Tensor) -> dict: - outputs = {} - for prefix in self.prefix_list_target: - layer = getattr(self, f"{prefix}_layer") - out = layer(z, elm_agg_emb) - outputs[prefix] = out - return outputs diff --git a/src/typography_generation/model/embedding.py b/src/typography_generation/model/embedding.py deleted file mode 100644 index 725ddfa..0000000 --- a/src/typography_generation/model/embedding.py +++ /dev/null @@ -1,407 +0,0 @@ -from collections import OrderedDict -import time -from typing import Any, List, Tuple -from einops import rearrange, repeat -from logzero import logger -import torch -from torch import Tensor, nn -from torch.functional import F -from typography_generation.config.attribute_config import ( - CanvasContextEmbeddingAttributeConfig, - TextElementContextEmbeddingAttributeConfig, - EmbeddingConfig, -) -from typography_generation.io.data_object import ModelInput -from typography_generation.model.common import ( - _conv3x3_bn_relu, - fn_ln_relu, -) - - -def set_tensor_type(inp: Tensor, tensor_type: str) -> Tensor: - if tensor_type == "float": - inp = inp.float() - elif tensor_type == "long": - inp = inp.long() - else: - raise NotImplementedError() - return inp - - -def setup_emb_layer( - self: nn.Module, prefix: str, target_embedding_config: EmbeddingConfig -) -> None: - if target_embedding_config.emb_layer is not None: - kwargs = target_embedding_config.emb_layer_kwargs # dict of args - if target_embedding_config.emb_layer == "nn.Embedding": - emb_layer = nn.Embedding(**kwargs) - setattr(self, f"{prefix}_type", "long") - elif target_embedding_config.emb_layer == "nn.Linear": - emb_layer = nn.Linear(**kwargs) - setattr(self, f"{prefix}_type", "float") - else: - raise NotImplementedError() - emb_layer = fn_ln_relu(emb_layer, self.d_model, self.dropout) - setattr(self, f"{prefix}_emb", emb_layer) - else: - setattr(self, f"{prefix}_type", "float") - setattr(self, f"{prefix}_flag", target_embedding_config.flag) - setattr(self, f"{prefix}_specific", target_embedding_config.specific_func) - setattr(self, f"{prefix}_inp", target_embedding_config.input_prefix) - - -def get_output( - self: nn.Module, prefix: str, model_inputs: ModelInput, batch_num: int -) -> Tensor: - inp_prefix = getattr(self, f"{prefix}_inp") - specific_func = getattr(self, f"{prefix}_specific") - tensor_type = getattr(self, f"{prefix}_type") - inp = getattr(model_inputs, inp_prefix) - text_num = getattr(model_inputs, "canvas_text_num") - inp = set_tensor_type(inp, tensor_type) - if specific_func is not None: - fn = getattr(self, specific_func) - out = fn( - inputs=inp, - batch_num=batch_num, - text_num=text_num, - ) - else: - fn = getattr(self, f"{prefix}_emb") - out = self.get_features_via_fn( - fn=fn, inputs=inp, batch_num=batch_num, text_num=text_num - ) - return out - - -class Down(nn.Module): - def __init__(self, input_dim: int, output_dim: int) -> None: - super(Down, self).__init__() - self.conv1 = _conv3x3_bn_relu(input_dim, output_dim, kernel_size=3) - self.drop = nn.Dropout() - - def forward(self, feat: Tensor) -> Tensor: - feat = self.conv1(feat) - return self.drop(feat) - - -class Embedding(nn.Module): - def __init__( - self, - prefix_list_element: List, - prefix_list_canvas: List, - embedding_config_element: TextElementContextEmbeddingAttributeConfig, - embedding_config_canvas: CanvasContextEmbeddingAttributeConfig, - d_model: int = 256, - dropout: float = 0.1, - seq_length: int = 50, - ) -> None: - super(Embedding, self).__init__() - self.emb_element = EmbeddingElementContext( - prefix_list_element, embedding_config_element, d_model, dropout, seq_length - ) - self.emb_canvas = EmbeddingCanvasContext( - prefix_list_canvas, - embedding_config_canvas, - d_model, - dropout, - ) - self.prefix_list_element = prefix_list_element - self.prefix_list_canvas = prefix_list_canvas - - self.d_model = d_model - self.seq_length = seq_length - - mlp_dim = ( - self.compute_modality_num(embedding_config_canvas, embedding_config_element) - * d_model - ) - self.mlp = nn.Sequential( - OrderedDict( - [ - ("l1", nn.Linear(mlp_dim, d_model)), - ("r1", nn.LeakyReLU(0.2)), - ("l2", nn.Linear(d_model, d_model)), - ("r2", nn.LeakyReLU(0.2)), - ] - ) - ) - self.mlp_dim = mlp_dim - - def compute_modality_num( - self, - embedding_config_canvas: CanvasContextEmbeddingAttributeConfig, - embedding_config_text: TextElementContextEmbeddingAttributeConfig, - ) -> int: - modality_num = 0 - for prefix in self.prefix_list_element: - target_embedding_config = getattr(embedding_config_text, prefix) - flag = target_embedding_config.flag - if flag is False: - pass - else: - modality_num += 1 - for prefix in self.prefix_list_canvas: - target_embedding_config = getattr(embedding_config_canvas, prefix) - flag = target_embedding_config.flag - if flag is True: - modality_num += 1 - return modality_num - - def flatten_feature( - self, - feats: List, - ) -> Tensor: - feats_flatten = [] - modarity_num = len(feats) - for m in range(modarity_num): - feats_flatten.append(feats[m]) - return feats_flatten - - def reshape_tbc( - self, - feat_elements: List, # modality num(M) x [B, S, C] - feat_canvas: List, # canvas num(CV) x [B, C] - batch_num: int, - text_num: Tensor, - ) -> Tensor: - feat_elements = torch.stack(feat_elements) # M, B, S, C - feat_elements = rearrange(feat_elements, "m b s c -> s b (m c)") - feat_canvas = torch.stack(feat_canvas) # CV, B, C - feat_canvas = rearrange(feat_canvas, "cv b c -> 1 b (cv c)") - feat_canvas = repeat(feat_canvas, "1 b c -> s b c", s=self.seq_length) - feat = torch.cat((feat_canvas, feat_elements), dim=2) - feat = self.mlp(feat) - return feat - - def get_transformer_inputs( - self, - feat_elements: List[Tensor], - feat_canvas: Tensor, - batch_num: int, - text_num: Tensor, - ) -> Tuple[Tensor, Tensor]: - feat_element, text_mask_element = self.lineup_features( - feat_elements, batch_num, text_num - ) - feat_canvas = torch.stack(feat_canvas) - feat_canvas = feat_canvas.view( - feat_canvas.shape[0], feat_element.shape[1], feat_element.shape[2] - ) - src = torch.cat((feat_canvas, feat_element), dim=0) - canvas_mask = torch.zeros(src.shape[1], feat_canvas.shape[0]) + 1 - canvas_mask = canvas_mask.float().to(text_num.device) - text_mask_src = torch.cat((canvas_mask, text_mask_element), dim=1) - return src, text_mask_src - - def lineup_features( - self, feats: Tensor, batch_num: int, text_num: Tensor - ) -> Tuple[Tensor, Tensor]: - modality_num = len(feats) - device = text_num.device - feat = ( - torch.zeros(self.seq_length, modality_num, batch_num, self.d_model) - .float() - .to(device) - ) - for m in range(modality_num): - logger.debug(f"{feats[m].shape=}") - feat[:, m, :, :] = rearrange(feats[m], "b t c -> t b c") - feat = rearrange(feat, "t m b c -> (t m) b c") - indices = rearrange(torch.arange(self.seq_length), "s -> 1 s").to(device) - mask = ( - (indices < text_num).to(device).float() - ) # (B, S), indicating valid attribute locations - text_mask = repeat(mask, "b s -> b (s m)", m=modality_num) - return feat, text_mask - - def forward(self, model_inputs: ModelInput) -> Tuple[Tensor, Tensor, Tensor]: - feat_elements = self.emb_element(model_inputs) - feat_canvas = self.emb_canvas(model_inputs) - - src, text_mask_src = self.get_transformer_inputs( - feat_elements, - feat_canvas, - model_inputs.batch_num, - model_inputs.canvas_text_num, - ) - feat_cat = self.reshape_tbc( - feat_elements, - feat_canvas, - model_inputs.batch_num, - model_inputs.canvas_text_num, - ) - - return (src, text_mask_src, feat_cat) - - -class EmbeddingElementContext(nn.Module): - def __init__( - self, - prefix_list_element: List, - embedding_config_element: TextElementContextEmbeddingAttributeConfig, - d_model: int, - dropout: float = 0.1, - seq_length: int = 50, - ): - super(EmbeddingElementContext, self).__init__() - self.d_model = d_model - self.dropout = dropout - self.seq_length = seq_length - self.prefix_list_element = prefix_list_element - - for prefix in self.prefix_list_element: - target_embedding_config = getattr(embedding_config_element, prefix) - setup_emb_layer(self, prefix, target_embedding_config) - if target_embedding_config.specific_build is not None: - build_func = getattr(self, target_embedding_config.specific_build) - build_func() - - def get_local_feat( - self, inputs: Tensor, batch_num: int, text_num: Tensor, **kwargs: Any - ) -> Tensor: - inputs_fn = [] - for b in range(batch_num): - tn = int(text_num[b].item()) - for t in range(tn): - inputs_fn.append(inputs[b, t]) - outs = None - if len(inputs_fn) > 0: - inputs_fn = torch.stack(inputs_fn) - with torch.no_grad(): - outs = self.imgencoder(inputs_fn).detach() - outs = self.downdim(outs) - outs = outs.view(len(outs), -1) - outs = self.fcimg(outs) - return outs - - # def get_features_via_fn( - # self, fn: Any, inputs: List, batch_num: int, text_num: Tensor - # ) -> Tensor: - # inputs_layer = [] - # for b in range(batch_num): - # tn = int(text_num[b].item()) - # for t in range(tn): - # inputs_layer.append(inputs[b][t].view(-1)) - # outs = None - # if len(inputs_layer) > 0: - # inputs_layer = torch.stack(inputs_layer) - # outs = fn(inputs_layer) - # outs = outs.view(len(inputs_layer), self.d_model) - # return outs - - def get_features_via_fn( - self, fn: Any, inputs: Tensor, batch_num: int, text_num: Tensor - ) -> Tensor: - device = inputs.device - feat = torch.zeros(batch_num, self.seq_length, self.d_model).float().to(device) - indices = rearrange(torch.arange(self.seq_length), "s -> 1 s").to(device) - mask = (indices < text_num).to( - device - ) # (B, S), indicating valid attribute locations - feat[mask] = fn(inputs[mask]) # (B, S, C) - return feat - - def text_emb_layer( - self, inputs: Tensor, batch_num: int, text_num: Tensor, **kwargs: Any - ) -> Tensor: - inputs_fn = [] - for b in range(batch_num): - tn = int(text_num[b].item()) - for t in range(tn): - inputs_fn.append(inputs[b, t].view(-1)) - outs = None - if len(inputs_fn) > 0: - inputs_fn = torch.stack(inputs_fn) - outs = self.text_emb_emb(inputs_fn) - outs = outs.view(len(inputs_fn), self.d_model) - return outs - - def text_local_img_emb_layer( - self, inputs: Tensor, batch_num: int, text_num: Tensor, **kwargs: Any - ) -> Tensor: - inputs_fn = [] - for b in range(batch_num): - tn = int(text_num[b].item()) - for t in range(tn): - inputs_fn.append(inputs[b, t].view(-1)) - outs = None - if len(inputs_fn) > 0: - inputs_fn = torch.stack(inputs_fn) - outs = self.text_local_img_emb_emb(inputs_fn) - outs = outs.view(len(inputs_fn), self.d_model) - return outs - - def text_font_emb_layer( - self, inputs: Tensor, batch_num: int, text_num: Tensor - ) -> Tensor: - inputs_fn = [] - for b in range(batch_num): - tn = int(text_num[b].item()) - for t in range(tn): - inputs_fn.append(inputs[b, t].view(-1)) - outs = None - if len(inputs_fn) > 0: - inputs_fn = torch.stack(inputs_fn) - outs = self.text_font_emb_emb(inputs_fn) - outs = outs.view(len(inputs_fn), self.d_model) - return outs - - def forward(self, model_inputs: ModelInput) -> Tensor: - feats = [] - for prefix in self.prefix_list_element: - flag = getattr(self, f"{prefix}_flag") - if flag is True: - start = time.time() - logger.debug(f"{prefix=}") - out = get_output(self, prefix, model_inputs, model_inputs.batch_num) - logger.debug(f"{prefix=} {out.shape=} {time.time()-start}") - feats.append(out) - return feats - - -class EmbeddingCanvasContext(nn.Module): - def __init__( - self, - canvas_prefix_list: List, - embedding_config_canvas: CanvasContextEmbeddingAttributeConfig, - d_model: int, - dropout: float, - ): - super(EmbeddingCanvasContext, self).__init__() - self.d_model = d_model - self.dropout = dropout - self.prefix_list = canvas_prefix_list - for prefix in self.prefix_list: - target_embedding_config = getattr(embedding_config_canvas, prefix) - setup_emb_layer(self, prefix, target_embedding_config) - if target_embedding_config.specific_build is not None: - build_func = getattr(self, target_embedding_config.specific_build) - build_func() - - def get_feat(self, inputs: Tensor, **kwargs: Any) -> Tensor: - with torch.no_grad(): - feat = self.imgencoder(inputs.float()).detach() - feat = F.relu(self.avgpool(feat)) - feat = self.downdim(feat) - feat = feat.view(feat.shape[0], feat.shape[1]) - return feat - - def canvas_bg_img_emb_layer(self, inputs: Tensor, **kwargs: Any) -> Tensor: - feat = self.canvas_bg_img_emb_emb(inputs.float()) - feat = feat.view(feat.shape[0], feat.shape[1]) - return feat - - def get_features_via_fn(self, fn: Any, inputs: Tensor, **kwargs: Any) -> Tensor: - out = fn(inputs) - return out - - def forward(self, model_inputs: ModelInput) -> List: - feats = [] - for prefix in self.prefix_list: - flag = getattr(self, f"{prefix}_flag") - if flag is True: - logger.debug(f"canvas prefix {prefix}") - out = get_output(self, prefix, model_inputs, model_inputs.batch_num) - feats.append(out) - return feats diff --git a/src/typography_generation/model/encoder.py b/src/typography_generation/model/encoder.py deleted file mode 100644 index a8ce865..0000000 --- a/src/typography_generation/model/encoder.py +++ /dev/null @@ -1,48 +0,0 @@ -from typing import Tuple - -import torch -from torch import Tensor, nn - -from typography_generation.model.common import ( - MyTransformerEncoder, - MyTransformerEncoderLayer, -) - - -class Encoder(nn.Module): - def __init__( - self, - d_model: int = 256, - n_head: int = 8, - dropout: float = 0.1, - num_encoder_layers: int = 4, - ): - super(Encoder, self).__init__() - encoder_norm = nn.LayerNorm(d_model) - dim_feedforward = d_model * 2 - encoder_layer = MyTransformerEncoderLayer( - d_model, n_head, dim_feedforward, dropout - ) - self.encoder = MyTransformerEncoder( - encoder_layer, num_encoder_layers, encoder_norm - ) - - def forward(self, src: Tensor, text_mask: Tensor) -> Tuple: - text_mask_fill = text_mask.masked_fill( - text_mask == 0, float("-inf") - ).masked_fill(text_mask == 1, float(0.0)) - z = self.encoder(src, mask=None, src_key_padding_mask=text_mask_fill.bool()) - if torch.sum(torch.isnan(z)) > 0: - z = z.masked_fill(torch.isnan(z), 0) - return z - - def get_transformer_weight(self, src: Tensor, text_mask: Tensor) -> Tuple: - text_mask_fill = text_mask.masked_fill( - text_mask == 0, float("-inf") - ).masked_fill(text_mask == 1, float(0.0)) - z, weights = self.encoder( - src, mask=None, src_key_padding_mask=text_mask_fill, get_weight=True - ) - if torch.sum(torch.isnan(z)) > 0: - z = z.masked_fill(torch.isnan(z), 0) - return z, weights diff --git a/src/typography_generation/model/mfc.py b/src/typography_generation/model/mfc.py deleted file mode 100644 index cc83c2e..0000000 --- a/src/typography_generation/model/mfc.py +++ /dev/null @@ -1,154 +0,0 @@ -from typing import Any, List, Dict -import numpy as np - -import torch -from torch import Tensor, nn -from typography_generation.config.attribute_config import ( - CanvasContextEmbeddingAttributeConfig, - TextElementContextEmbeddingAttributeConfig, - TextElementContextPredictionAttributeConfig, -) -from typography_generation.io.crello_util import CrelloProcessor -from typography_generation.io.data_object import ModelInput - -from logzero import logger - -from typography_generation.model.mlp import MLP - - -class MFC(MLP): - def __init__( - self, - prefix_list_element: List, - prefix_list_canvas: List, - prefix_list_target: List, - embedding_config_element: TextElementContextEmbeddingAttributeConfig, - embedding_config_canvas: CanvasContextEmbeddingAttributeConfig, - prediction_config_element: TextElementContextPredictionAttributeConfig, - d_model: int = 256, - dropout: float = 0.1, - seq_length: int = 50, - **kwargs: Any, - ) -> None: - logger.info(f"MFC model") - super().__init__( - prefix_list_element, - prefix_list_canvas, - prefix_list_target, - embedding_config_element, - embedding_config_canvas, - prediction_config_element, - d_model, - dropout, - seq_length, - ) - for prefix in prefix_list_target: - target_prediction_config = getattr(prediction_config_element, prefix) - setattr(self, f"{prefix}_loss_type", target_prediction_config.loss_type) - - def get_label( - self, - out: Tensor, - text_index: int, - batch_index: int = 0, - ) -> Tensor: - sorted_label = torch.sort(input=out[batch_index], dim=1, descending=True)[1] - target_label = 0 # top1 - out_label = sorted_label[text_index][target_label].item() - return out_label - - def get_out( - self, - out: Tensor, - text_index: int, - batch_index: int = 0, - ) -> Tensor: - _out = out[batch_index, text_index].data.cpu().numpy() - return _out - - def get_outs( - self, - model_outs: Dict, - target_prefix_list: List, - text_index: int, - batch_index: int = 0, - ) -> Dict: - outs = {} - for prefix in target_prefix_list: - out = model_outs[f"{prefix}"] - loss_type = getattr(self, f"{prefix}_loss_type") - if loss_type == "cre": - _out = self.get_label(out, text_index, batch_index) - else: - _out = self.get_out(out, text_index, batch_index) - outs[f"{prefix}"] = _out - return outs - - def store( - self, - out_all: Dict, - out_labels: Dict, - target_prefix_list: List, - text_index: int, - ) -> Dict: - for prefix in target_prefix_list: - out_all[f"{prefix}"][text_index, 0] = out_labels[f"{prefix}"] - return out_all - - def prediction( - self, - model_inputs: ModelInput, - dataset: CrelloProcessor, - target_prefix_list: List, - start_index: int = 0, - ) -> Tensor: - target_text_num = int(model_inputs.canvas_text_num[0].item()) - start_index = min(start_index, target_text_num) - for t in range(start_index, target_text_num): - model_inputs.zeroinitialize_th_style_attributes(target_prefix_list, t) - - out_all = {} - for prefix in target_prefix_list: - loss_type = getattr(self, f"{prefix}_loss_type") - if loss_type == "cre": - out_all[prefix] = np.zeros((target_text_num, 1)) - else: - out_all[prefix] = [] - for t in range(0, start_index): - tar = getattr(model_inputs, f"{prefix}")[0, t].item() - if loss_type == "cre": - out_all[prefix][t, 0] = tar - else: - out_all[prefix].append(tar) - for t in range(start_index, target_text_num): - _, _, feat_cat = self.emb(model_inputs) - model_outs = self.head(feat_cat) - out = self.get_outs(model_outs, target_prefix_list, t) - for prefix in target_prefix_list: - loss_type = getattr(self, f"{prefix}_loss_type") - if loss_type == "cre": - out_all[f"{prefix}"][t, 0] = out[f"{prefix}"] - else: - out_all[f"{prefix}"].append(out[f"{prefix}"]) - return out_all - - def initialize_weights(self) -> None: - for m in self.modules(): - if isinstance(m, nn.Conv2d): - nn.init.xavier_normal_(m.weight) - 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): - m.weight.data.normal_(mean=0.0, std=0.02) - if m.bias is not None: - m.bias.data.zero_() - elif isinstance(m, nn.LayerNorm): - if m.weight is not None: - m.weight.data.fill_(1) - if m.bias is not None: - m.bias.data.zero_() - elif isinstance(m, nn.Embedding): - m.weight.data.normal_(mean=0.0, std=0.02) diff --git a/src/typography_generation/model/mlp.py b/src/typography_generation/model/mlp.py deleted file mode 100644 index 81491f4..0000000 --- a/src/typography_generation/model/mlp.py +++ /dev/null @@ -1,175 +0,0 @@ -from typing import Any, List, Dict -import numpy as np - -import torch -from torch import Tensor, nn -from typography_generation.config.attribute_config import ( - CanvasContextEmbeddingAttributeConfig, - TextElementContextEmbeddingAttributeConfig, - TextElementContextPredictionAttributeConfig, -) -from typography_generation.io.crello_util import CrelloProcessor -from typography_generation.io.data_object import ModelInput -from typography_generation.model.common import Linearx2 -from typography_generation.model.embedding import Embedding - -from logzero import logger - - -class FCN(nn.Module): - def __init__(self, d_model: int, label_num: int) -> None: - super().__init__() - self.fcn = Linearx2(d_model, label_num) - - def forward(self, elm_agg_emb: Tensor = None) -> Tensor: - logits = elm_agg_emb.permute(1, 0, 2) - logits = self.fcn(logits) # Shape [G, N, 2] - return logits - - -class MultiTask(nn.Module): - def __init__( - self, - prefix_list_target: List, - prediction_config: TextElementContextPredictionAttributeConfig, - d_model: int = 256, - ): - super().__init__() - self.prefix_list_target = prefix_list_target - for prefix in self.prefix_list_target: - target_prediction_config = getattr(prediction_config, prefix) - layer = FCN(d_model, target_prediction_config.out_dim) - setattr(self, f"{prefix}_layer", layer) - - def forward(self, elm_agg_emb: Tensor) -> dict: - outputs = {} - for prefix in self.prefix_list_target: - layer = getattr(self, f"{prefix}_layer") - out = layer(elm_agg_emb) - outputs[prefix] = out - return outputs - - -class MLP(nn.Module): - def __init__( - self, - prefix_list_element: List, - prefix_list_canvas: List, - prefix_list_target: List, - embedding_config_element: TextElementContextEmbeddingAttributeConfig, - embedding_config_canvas: CanvasContextEmbeddingAttributeConfig, - prediction_config_element: TextElementContextPredictionAttributeConfig, - d_model: int = 256, - dropout: float = 0.1, - seq_length: int = 50, - **kwargs: Any, - ) -> None: - super().__init__() - logger.info(f"MLP settings") - logger.info(f"d_model: {d_model}") - logger.info(f"seq_length: {seq_length}") - self.embedding_config_element = embedding_config_element - - self.emb = Embedding( - prefix_list_element, - prefix_list_canvas, - embedding_config_element, - embedding_config_canvas, - d_model, - dropout, - seq_length, - ) - self.head = MultiTask( - prefix_list_target, - prediction_config_element, - d_model, - ) - self.initialize_weights() - - def forward(self, model_inputs: ModelInput) -> Tensor: - ( - _, - _, - feat_cat, - ) = self.emb(model_inputs) - outs = self.head(feat_cat) - return outs - - def get_labels( - self, - model_outs: Dict, - target_prefix_list: List, - text_index: int, - batch_index: int = 0, - ) -> Dict: - out_labels = {} - for prefix in target_prefix_list: - out = model_outs[f"{prefix}"] - sorted_label = torch.sort(input=out[batch_index], dim=1, descending=True)[1] - target_label = 0 # top1 - out_label = sorted_label[text_index][target_label] - out_labels[f"{prefix}"] = out_label - - return out_labels - - def store( - self, - out_labels_all: Dict, - out_labels: Dict, - target_prefix_list: List, - text_index: int, - ) -> Dict: - for prefix in target_prefix_list: - out_labels_all[f"{prefix}"][text_index, 0] = out_labels[f"{prefix}"].item() - return out_labels_all - - def prediction( - self, - model_inputs: ModelInput, - dataset: CrelloProcessor, - target_prefix_list: List, - start_index: int = 0, - ) -> Tensor: - target_text_num = int(model_inputs.canvas_text_num[0].item()) - start_index = min(start_index, target_text_num) - for t in range(start_index, target_text_num): - model_inputs.zeroinitialize_th_style_attributes(target_prefix_list, t) - - out_labels_all = {} - for prefix in target_prefix_list: - out_labels_all[prefix] = np.zeros((target_text_num, 1)) - for t in range(0, start_index): - tar = getattr(model_inputs, f"{prefix}")[0, t].item() - out_labels_all[prefix][t, 0] = tar - for t in range(start_index, target_text_num): - _, _, feat_cat = self.emb(model_inputs) - model_outs = self.head(feat_cat) - out_labels = self.get_labels(model_outs, target_prefix_list, t) - model_inputs.update_th_style_attributes( - self.embedding_config_element, target_prefix_list, out_labels, t - ) - out_labels_all = self.store( - out_labels_all, out_labels, target_prefix_list, t - ) - return out_labels_all - - def initialize_weights(self) -> None: - for m in self.modules(): - if isinstance(m, nn.Conv2d): - nn.init.xavier_normal_(m.weight) - 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): - m.weight.data.normal_(mean=0.0, std=0.02) - if m.bias is not None: - m.bias.data.zero_() - elif isinstance(m, nn.LayerNorm): - if m.weight is not None: - m.weight.data.fill_(1) - if m.bias is not None: - m.bias.data.zero_() - elif isinstance(m, nn.Embedding): - m.weight.data.normal_(mean=0.0, std=0.02) diff --git a/src/typography_generation/model/model.py b/src/typography_generation/model/model.py deleted file mode 100644 index 6b0d633..0000000 --- a/src/typography_generation/model/model.py +++ /dev/null @@ -1,25 +0,0 @@ -from typing import Any, Dict -from torch import nn - -from typography_generation.model.bart import BART -from typography_generation.model.baseline import AllRandom, AllZero, Mode -from typography_generation.model.canvas_vae import CanvasVAE -from typography_generation.model.mfc import MFC -from typography_generation.model.mlp import MLP - -MODEL_REGISTRY: Dict[str, nn.Module] = { - "bart": BART, - "mlp": MLP, - "mfc": MFC, - "canvasvae": CanvasVAE, - "allzero": AllZero, - "allrandom": AllRandom, - "mode": Mode, -} - - -def create_model(model_name: str, **kwargs: Any) -> nn.Module: - """Factory function to create a model instance.""" - model = MODEL_REGISTRY[model_name](**kwargs) - model.model_name = model_name - return model diff --git a/src/typography_generation/preprocess/__init__.py b/src/typography_generation/preprocess/__init__.py deleted file mode 100644 index 8b13789..0000000 --- a/src/typography_generation/preprocess/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/typography_generation/preprocess/map_features.py b/src/typography_generation/preprocess/map_features.py deleted file mode 100644 index ece5c2d..0000000 --- a/src/typography_generation/preprocess/map_features.py +++ /dev/null @@ -1,280 +0,0 @@ -import pickle -from typing import Any, Dict, List, Tuple -import datasets -import os -import numpy as np -from PIL import Image -from logzero import logger -import torch -import skia -from transformers import CLIPProcessor, CLIPModel, CLIPTokenizer - -from typography_generation.visualization.renderer_util import ( - get_skia_font, - get_text_actual_width, - get_texts, -) - - -def get_scaleinfo( - element_data: Dict, -) -> List: - svgid = element_data["id"] - scaleinfo = svgid2scaleinfo[svgid] - return list(scaleinfo) - - -def get_canvassize( - bg_img: Any, -) -> List: - img_size = (bg_img.size[1], bg_img.size[0]) - return list(img_size) - - -def get_canvas_bg_img_emb(bg_img: Any, **kwargs: Any) -> np.array: - inputs = processor(images=[bg_img], return_tensors="pt") - inputs["pixel_values"] = inputs["pixel_values"].to(device) - image_feature = model.get_image_features(**inputs) - return list(image_feature.data.cpu().numpy().flatten()) - - -def get_text_emb_list( - element_data: Dict, -) -> List: - text_emb_list: List[List] - text_emb_list = [] - for k in range(len(element_data["text"])): - text = element_data["text"][k] - inputs = text_tokenizer([text], padding=True, return_tensors="pt") - if inputs["input_ids"].shape[1] > 77: - inp = inputs["input_ids"][:, :77] - else: - inp = inputs["input_ids"] - inp = inp.to(device) - text_features = model.get_text_features(inp).data.cpu().numpy()[0] - text_emb_list.append(text_features) - return text_emb_list - - -def _get_text_actual_width( - element_data: Dict, - W: int, -) -> List: - svgid = element_data["id"] - scaleinfo = svgid2scaleinfo[svgid] - scale_h, scale_w = scaleinfo - text_actual_width_list = [] - element_num = len(element_data["text"]) - - for i in range(element_num): - if element_data["text"][i] == "": - text_actual_width_list.append(None) - else: - texts = get_texts(element_data, i) - - font_label = element_data["font"][i] - font_name = fontlabel2fontname(int(font_label)) - font_name = font_name.replace(" ", "_") - font_skia, _ = get_skia_font( - font2ttf, fontmgr, element_data, i, font_name, scale_h - ) - text_width = get_text_actual_width( - element_data, i, texts, font_skia, scale_w - ) - text_actual_width_list.append(text_width / float(W)) - return text_actual_width_list - - -def get_text_center_y(element_data: dict, text_index: int) -> float: - text_height = element_data["height"][text_index] - top = element_data["top"][text_index] - center_y = (top + top + text_height) / 2.0 - return float(center_y) - - -def get_text_center_y_list( - element_data: dict, -) -> List: - text_center_y_list = [] - element_num = len(element_data["text"]) - for text_id in range(element_num): - if element_data["text"][text_id] == "": - text_center_y_list.append(None) - else: - text_center_y_list.append(get_text_center_y(element_data, text_id)) - return text_center_y_list - - -def get_text_center_x( - element_data: dict, - text_index: int, - text_actual_width: float, -) -> float: - left = element_data["left"][text_index] - w = element_data["width"][text_index] - textAlign = element_data["text_align"][text_index] - right = left + w - if textAlign == 1: - center_x = (left + right) / 2.0 - elif textAlign == 3: - center_x = right - text_actual_width / 2.0 - elif textAlign == 2: - center_x = left + text_actual_width / 2.0 - return float(center_x) - - -def get_text_center_x_list( - element_data: dict, - text_actual_width: float, -) -> List: - svgid = element_data["id"] - text_center_x_list = [] - element_num = len(element_data["text"]) - for text_id in range(element_num): - if element_data["text"][text_id] == "": - text_center_x_list.append(None) - else: - _text_actual_width = text_actual_width[text_id] - text_center_x_list.append( - get_text_center_x(element_data, text_id, _text_actual_width) - ) - return text_center_x_list - - -def get_text_local_img( - img: Any, - text_center_y: float, - text_center_x: float, - H: int, - W: int, -) -> np.array: - text_center_y = text_center_y * H - text_center_x = text_center_x * W - - text_center_y = min(max(text_center_y, 0), H) - text_center_x = min(max(text_center_x, 0), W) - img = img.resize((640, 640)) - img = np.array(img) - local_img_size = 64 * 5 - local_img_size_half = local_img_size // 2 - img_pad = np.zeros((640 + local_img_size, 640 + local_img_size, 3)) - img_pad[ - local_img_size_half : 640 + local_img_size_half, - local_img_size_half : 640 + local_img_size_half, - ] = img - h_rate = 640 / float(H) - w_rate = 640 / float(W) - text_center_y = int(np.round(text_center_y * h_rate + local_img_size_half)) - text_center_x = int(np.round(text_center_x * w_rate + local_img_size_half)) - local_img = img_pad[ - text_center_y - local_img_size_half : text_center_y + local_img_size_half, - text_center_x - local_img_size_half : text_center_x + local_img_size_half, - ] - return local_img - - -def get_text_local_img_emb_list( - element_data: Dict, - bg_img: Any, - text_center_y: float, - text_center_x: float, -) -> List: - text_local_img_emb_list: List[List] - text_local_img_emb_list = [] - for k in range(len(element_data["text"])): - if element_data["text"][k] == "": - text_local_img_emb_list.append([]) - else: - H, W = bg_img.size[1], bg_img.size[0] - local_img = get_text_local_img( - bg_img.copy(), text_center_y[k], text_center_x[k], H, W - ) - local_img = Image.fromarray(local_img.astype(np.uint8)).resize((224, 224)) - inputs = processor(images=[local_img], return_tensors="pt") - inputs["pixel_values"] = inputs["pixel_values"].to(device) - image_feature = model.get_image_features(**inputs) - text_local_img_emb_list.append(image_feature.data.cpu().numpy()) - - return text_local_img_emb_list - - -def get_orderlist( - center_y: List[float], - center_x: List[float], -) -> List: - """ - Sort elments based on the raster scan order. - """ - center_y = [10000 if y is None else y for y in center_y] - center_x = [10000 if x is None else x for x in center_x] - center_y = np.array(center_y) - center_x = np.array(center_x) - sortedid = np.argsort(center_y * 1000 + center_x) - return list(sortedid) - - -def add_features( - element_data: Dict, -) -> Dict: - svgid = element_data["id"] - fn = os.path.join(data_dir, "generate_bg_png", f"{svgid}.png") - bg_img = Image.open(fn).convert("RGB") # background image - element_data["scale_box"] = get_scaleinfo(element_data) - element_data["canvas_bg_size"] = get_canvassize(bg_img) - element_data["canvas_bg_img_emb"] = get_canvas_bg_img_emb(bg_img) - element_data["text_emb"] = get_text_emb_list(element_data) - text_actual_width = _get_text_actual_width(element_data, bg_img.size[0]) - text_center_y = get_text_center_y_list(element_data) - text_center_x = get_text_center_x_list(element_data, text_actual_width) - element_data["text_center_y"] = text_center_y - element_data["text_center_x"] = text_center_x - element_data["text_actual_width"] = text_actual_width - element_data["text_local_img_emb"] = get_text_local_img_emb_list( - element_data, bg_img, text_center_y, text_center_x - ) - element_data["order_list"] = get_orderlist(text_center_y, text_center_x) - return element_data - - -def map_features( - _data_dir: str, -): - fn = os.path.join(_data_dir, "svgid2scaleinfo.pkl") - global svgid2scaleinfo - global processor - global text_tokenizer - global model - global device - global data_dir - global font2ttf - global fontmgr - global fontlabel2fontname - - dataset = datasets.load_dataset("cyberagent/crello", revision="3.1") - - data_dir = _data_dir - svgid2scaleinfo = pickle.load(open(fn, "rb")) - processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32") - text_tokenizer = CLIPTokenizer.from_pretrained("openai/clip-vit-base-patch32") - model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32") - device = torch.device("cuda" if torch.cuda.is_available() else "cpu") - model.to(device) - - fn = os.path.join(data_dir, "font2ttf.pkl") - _font2ttf = pickle.load(open(fn, "rb")) - font2ttf = {} - for key in _font2ttf.keys(): - tmp = _font2ttf[key].split("/data/dataset/crello/")[1] - fn = os.path.join(data_dir, tmp) - font2ttf[key] = fn - font2ttf = font2ttf - fontmgr = skia.FontMgr() - fontlabel2fontname = dataset["train"].features["font"].feature.int2str - - dataset_new = {} - for dataset_division in ["train", "validation", "test"]: - logger.info(f"{dataset_division=}") - _dataset = dataset[dataset_division] - dataset_new[dataset_division] = _dataset.map(add_features) - dataset_new = datasets.DatasetDict(dataset_new) - dataset_new.save_to_disk(f"{_data_dir}/crello_map_features") diff --git a/src/typography_generation/tools/__init__.py b/src/typography_generation/tools/__init__.py deleted file mode 100644 index 8b13789..0000000 --- a/src/typography_generation/tools/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/typography_generation/tools/color_func.py b/src/typography_generation/tools/color_func.py deleted file mode 100644 index 2675bbf..0000000 --- a/src/typography_generation/tools/color_func.py +++ /dev/null @@ -1,457 +0,0 @@ -from typing import Any, Tuple -import numpy as np - -_illuminants = { - "A": { - "2": (1.098466069456375, 1, 0.3558228003436005), - "10": (1.111420406956693, 1, 0.3519978321919493), - "R": (1.098466069456375, 1, 0.3558228003436005), - }, - "B": { - "2": (0.9909274480248003, 1, 0.8531327322886154), - "10": (0.9917777147717607, 1, 0.8434930535866175), - "R": (0.9909274480248003, 1, 0.8531327322886154), - }, - "C": { - "2": (0.980705971659919, 1, 1.1822494939271255), - "10": (0.9728569189782166, 1, 1.1614480488951577), - "R": (0.980705971659919, 1, 1.1822494939271255), - }, - "D50": { - "2": (0.9642119944211994, 1, 0.8251882845188288), - "10": (0.9672062750333777, 1, 0.8142801513128616), - "R": (0.9639501491621826, 1, 0.8241280285499208), - }, - "D55": { - "2": (0.956797052643698, 1, 0.9214805860173273), - "10": (0.9579665682254781, 1, 0.9092525159847462), - "R": (0.9565317453467969, 1, 0.9202554587037198), - }, - "D65": { - "2": (0.95047, 1.0, 1.08883), # This was: `lab_ref_white` - "10": (0.94809667673716, 1, 1.0730513595166162), - "R": (0.9532057125493769, 1, 1.0853843816469158), - }, - "D75": { - "2": (0.9497220898840717, 1, 1.226393520724154), - "10": (0.9441713925645873, 1, 1.2064272211720228), - "R": (0.9497220898840717, 1, 1.226393520724154), - }, - "E": {"2": (1.0, 1.0, 1.0), "10": (1.0, 1.0, 1.0), "R": (1.0, 1.0, 1.0)}, -} -xyz_from_rgb = np.array( - [ - [0.412453, 0.357580, 0.180423], - [0.212671, 0.715160, 0.072169], - [0.019334, 0.119193, 0.950227], - ] -) - - -def xyz_tristimulus_values(illuminant: str, observer: str, dtype: Any) -> np.array: - """Get the CIE XYZ tristimulus values. - - Given an illuminant and observer, this function returns the CIE XYZ tristimulus - values [2]_ scaled such that :math:`Y = 1`. - - Parameters - ---------- - illuminant : {"A", "B", "C", "D50", "D55", "D65", "D75", "E"} - The name of the illuminant (the function is NOT case sensitive). - observer : {"2", "10", "R"} - One of: 2-degree observer, 10-degree observer, or 'R' observer as in - R function ``grDevices::convertColor`` [3]_. - dtype: dtype, optional - Output data type. - - Returns - ------- - values : array - Array with 3 elements :math:`X, Y, Z` containing the CIE XYZ tristimulus values - of the given illuminant. - - Raises - ------ - ValueError - If either the illuminant or the observer angle are not supported or - unknown. - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/Standard_illuminant#White_points_of_standard_illuminants - .. [2] https://en.wikipedia.org/wiki/CIE_1931_color_space#Meaning_of_X,_Y_and_Z - .. [3] https://www.rdocumentation.org/packages/grDevices/versions/3.6.2/topics/convertColor - - Notes - ----- - The CIE XYZ tristimulus values are calculated from :math:`x, y` [1]_, using the - formula - - .. math:: X = x / y - - .. math:: Y = 1 - - .. math:: Z = (1 - x - y) / y - - The only exception is the illuminant "D65" with aperture angle 2° for - backward-compatibility reasons. - - Examples - -------- - Get the CIE XYZ tristimulus values for a "D65" illuminant for a 10 degree field of - view - - >>> xyz_tristimulus_values(illuminant="D65", observer="10") - array([0.94809668, 1. , 1.07305136]) - """ - illuminant = illuminant.upper() - observer = observer.upper() - try: - return np.asarray(_illuminants[illuminant][observer], dtype=dtype) - except KeyError: - raise ValueError( - f"Unknown illuminant/observer combination " - f"(`{illuminant}`, `{observer}`)" - ) - - -def xyz2lab( - xyz: np.array, illuminant: str = "D65", observer: str = "2", channel_axis: int = -1 -) -> np.array: - """XYZ to CIE-LAB color space conversion. - - Parameters - ---------- - xyz : (..., 3, ...) array_like - The image in XYZ format. By default, the final dimension denotes - channels. - illuminant : {"A", "B", "C", "D50", "D55", "D65", "D75", "E"}, optional - The name of the illuminant (the function is NOT case sensitive). - observer : {"2", "10", "R"}, optional - One of: 2-degree observer, 10-degree observer, or 'R' observer as in - R function grDevices::convertColor. - channel_axis : int, optional - This parameter indicates which axis of the array corresponds to - channels. - - .. versionadded:: 0.19 - ``channel_axis`` was added in 0.19. - - Returns - ------- - out : (..., 3, ...) ndarray - The image in CIE-LAB format. Same dimensions as input. - - Raises - ------ - ValueError - If `xyz` is not at least 2-D with shape (..., 3, ...). - ValueError - If either the illuminant or the observer angle is unsupported or - unknown. - - Notes - ----- - By default Observer="2", Illuminant="D65". CIE XYZ tristimulus values - x_ref=95.047, y_ref=100., z_ref=108.883. See function - :func:`~.xyz_tristimulus_values` for a list of supported illuminants. - - References - ---------- - .. [1] http://www.easyrgb.com/en/math.php - .. [2] https://en.wikipedia.org/wiki/CIELAB_color_space - - Examples - -------- - >>> from skimage import data - >>> from skimage.color import rgb2xyz, xyz2lab - >>> img = data.astronaut() - >>> img_xyz = rgb2xyz(img) - >>> img_lab = xyz2lab(img_xyz) - """ - arr = np.array(xyz) - - xyz_ref_white = xyz_tristimulus_values( - illuminant=illuminant, observer=observer, dtype=arr.dtype - ) - - # scale by CIE XYZ tristimulus values of the reference white point - arr = arr / xyz_ref_white - - # Nonlinear distortion and linear transformation - mask = arr > 0.008856 - arr[mask] = np.cbrt(arr[mask]) - arr[~mask] = 7.787 * arr[~mask] + 16.0 / 116.0 - - x, y, z = arr[..., 0], arr[..., 1], arr[..., 2] - - # Vector scaling - L = (116.0 * y) - 16.0 - a = 500.0 * (x - y) - b = 200.0 * (y - z) - - return np.concatenate([x[..., np.newaxis] for x in [L, a, b]], axis=-1) - - -def rgb2xyz(rgb: np.array, channel_axis: int = -1) -> np.array: - """RGB to XYZ color space conversion. - - Parameters - ---------- - rgb : (..., 3, ...) array_like - The image in RGB format. By default, the final dimension denotes - channels. - channel_axis : int, optional - This parameter indicates which axis of the array corresponds to - channels. - - .. versionadded:: 0.19 - ``channel_axis`` was added in 0.19. - - Returns - ------- - out : (..., 3, ...) ndarray - The image in XYZ format. Same dimensions as input. - - Raises - ------ - ValueError - If `rgb` is not at least 2-D with shape (..., 3, ...). - - Notes - ----- - The CIE XYZ color space is derived from the CIE RGB color space. Note - however that this function converts from sRGB. - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/CIE_1931_color_space - - Examples - -------- - >>> from skimage import data - >>> img = data.astronaut() - >>> img_xyz = rgb2xyz(img) - """ - # Follow the algorithm from http://www.easyrgb.com/index.php - # except we don't multiply/divide by 100 in the conversion - arr = np.array(rgb) - mask = arr > 0.04045 - arr[mask] = np.power((arr[mask] + 0.055) / 1.055, 2.4) - arr[~mask] /= 12.92 - return arr @ xyz_from_rgb.T.astype(arr.dtype) - - -def rgb2lab( - rgb: np.array, - illuminant: str = "D65", - observer: str = "2", - channel_axis: int = -1, -) -> np.array: - """Conversion from the sRGB color space (IEC 61966-2-1:1999) - to the CIE Lab colorspace under the given illuminant and observer. - - Parameters - ---------- - rgb : (..., 3, ...) array_like - The image in RGB format. By default, the final dimension denotes - channels. - illuminant : {"A", "B", "C", "D50", "D55", "D65", "D75", "E"}, optional - The name of the illuminant (the function is NOT case sensitive). - observer : {"2", "10", "R"}, optional - The aperture angle of the observer. - channel_axis : int, optional - This parameter indicates which axis of the array corresponds to - channels. - - .. versionadded:: 0.19 - ``channel_axis`` was added in 0.19. - - Returns - ------- - out : (..., 3, ...) ndarray - The image in Lab format. Same dimensions as input. - - Raises - ------ - ValueError - If `rgb` is not at least 2-D with shape (..., 3, ...). - - Notes - ----- - RGB is a device-dependent color space so, if you use this function, be - sure that the image you are analyzing has been mapped to the sRGB color - space. - - This function uses rgb2xyz and xyz2lab. - By default Observer="2", Illuminant="D65". CIE XYZ tristimulus values - x_ref=95.047, y_ref=100., z_ref=108.883. See function - :func:`~.xyz_tristimulus_values` for a list of supported illuminants. - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/Standard_illuminant - """ - return xyz2lab(rgb2xyz(rgb), illuminant, observer) - - -def _cart2polar_2pi(x: np.array, y: np.array) -> Tuple[np.array, np.array]: - """convert cartesian coordinates to polar (uses non-standard theta range!) - - NON-STANDARD RANGE! Maps to ``(0, 2*pi)`` rather than usual ``(-pi, +pi)`` - """ - r, t = np.hypot(x, y), np.arctan2(y, x) - t += np.where(t < 0.0, 2 * np.pi, 0) - return r, t - - -def _float_inputs( - lab1: np.array, lab2: np.array, allow_float32: bool = True -) -> Tuple[np.array, np.array]: - lab1 = np.asarray(lab1) - lab2 = np.asarray(lab2) - float_dtype = np.float64 - lab1 = lab1.astype(float_dtype, copy=False) - lab2 = lab2.astype(float_dtype, copy=False) - return lab1, lab2 - - -def deltaE_ciede2000( - lab1: np.array, - lab2: np.array, - kL: int = 1, - kC: int = 1, - kH: int = 1, - channel_axis: int = -1, -) -> np.array: - """Color difference as given by the CIEDE 2000 standard. - - CIEDE 2000 is a major revision of CIDE94. The perceptual calibration is - largely based on experience with automotive paint on smooth surfaces. - - Parameters - ---------- - lab1 : array_like - reference color (Lab colorspace) - lab2 : array_like - comparison color (Lab colorspace) - kL : float (range), optional - lightness scale factor, 1 for "acceptably close"; 2 for "imperceptible" - see deltaE_cmc - kC : float (range), optional - chroma scale factor, usually 1 - kH : float (range), optional - hue scale factor, usually 1 - channel_axis : int, optional - This parameter indicates which axis of the arrays corresponds to - channels. - - .. versionadded:: 0.19 - ``channel_axis`` was added in 0.19. - - Returns - ------- - deltaE : array_like - The distance between `lab1` and `lab2` - - Notes - ----- - CIEDE 2000 assumes parametric weighting factors for the lightness, chroma, - and hue (`kL`, `kC`, `kH` respectively). These default to 1. - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/Color_difference - .. [2] http://www.ece.rochester.edu/~gsharma/ciede2000/ciede2000noteCRNA.pdf - :DOI:`10.1364/AO.33.008069` - .. [3] M. Melgosa, J. Quesada, and E. Hita, "Uniformity of some recent - color metrics tested with an accurate color-difference tolerance - dataset," Appl. Opt. 33, 8069-8077 (1994). - """ - lab1, lab2 = _float_inputs(lab1, lab2, allow_float32=True) - - channel_axis = channel_axis % lab1.ndim - unroll = False - if lab1.ndim == 1 and lab2.ndim == 1: - unroll = True - if lab1.ndim == 1: - lab1 = lab1[None, :] - if lab2.ndim == 1: - lab2 = lab2[None, :] - channel_axis += 1 - L1, a1, b1 = np.moveaxis(lab1, source=channel_axis, destination=0)[:3] - L2, a2, b2 = np.moveaxis(lab2, source=channel_axis, destination=0)[:3] - - # distort `a` based on average chroma - # then convert to lch coordinates from distorted `a` - # all subsequence calculations are in the new coordinates - # (often denoted "prime" in the literature) - Cbar = 0.5 * (np.hypot(a1, b1) + np.hypot(a2, b2)) - c7 = Cbar**7 - G = 0.5 * (1 - np.sqrt(c7 / (c7 + 25**7))) - scale = 1 + G - C1, h1 = _cart2polar_2pi(a1 * scale, b1) - C2, h2 = _cart2polar_2pi(a2 * scale, b2) - # recall that c, h are polar coordinates. c==r, h==theta - - # cide2000 has four terms to delta_e: - # 1) Luminance term - # 2) Hue term - # 3) Chroma term - # 4) hue Rotation term - - # lightness term - Lbar = 0.5 * (L1 + L2) - tmp = (Lbar - 50) ** 2 - SL = 1 + 0.015 * tmp / np.sqrt(20 + tmp) - L_term = (L2 - L1) / (kL * SL) - - # chroma term - Cbar = 0.5 * (C1 + C2) # new coordinates - SC = 1 + 0.045 * Cbar - C_term = (C2 - C1) / (kC * SC) - - # hue term - h_diff = h2 - h1 - h_sum = h1 + h2 - CC = C1 * C2 - - dH = h_diff.copy() - dH[h_diff > np.pi] -= 2 * np.pi - dH[h_diff < -np.pi] += 2 * np.pi - dH[CC == 0.0] = 0.0 # if r == 0, dtheta == 0 - dH_term = 2 * np.sqrt(CC) * np.sin(dH / 2) - - Hbar = h_sum.copy() - mask = np.logical_and(CC != 0.0, np.abs(h_diff) > np.pi) - Hbar[mask * (h_sum < 2 * np.pi)] += 2 * np.pi - Hbar[mask * (h_sum >= 2 * np.pi)] -= 2 * np.pi - Hbar[CC == 0.0] *= 2 - Hbar *= 0.5 - - T = ( - 1 - - 0.17 * np.cos(Hbar - np.deg2rad(30)) - + 0.24 * np.cos(2 * Hbar) - + 0.32 * np.cos(3 * Hbar + np.deg2rad(6)) - - 0.20 * np.cos(4 * Hbar - np.deg2rad(63)) - ) - SH = 1 + 0.015 * Cbar * T - - H_term = dH_term / (kH * SH) - - # hue rotation - c7 = Cbar**7 - Rc = 2 * np.sqrt(c7 / (c7 + 25**7)) - dtheta = np.deg2rad(30) * np.exp(-(((np.rad2deg(Hbar) - 275) / 25) ** 2)) - R_term = -np.sin(2 * dtheta) * Rc * C_term * H_term - - # put it all together - dE2 = L_term**2 - dE2 += C_term**2 - dE2 += H_term**2 - dE2 += R_term - ans = np.sqrt(np.maximum(dE2, 0)) - if unroll: - ans = ans[0] - return ans diff --git a/src/typography_generation/tools/denormalizer.py b/src/typography_generation/tools/denormalizer.py deleted file mode 100644 index d0d06d2..0000000 --- a/src/typography_generation/tools/denormalizer.py +++ /dev/null @@ -1,154 +0,0 @@ -from typing import Dict, List, Tuple, Union - -import numpy as np -from typography_generation.io.crello_util import CrelloProcessor -from typography_generation.io.data_object import DesignContext -from logzero import logger - - -class Denormalizer: - def __init__(self, dataset: CrelloProcessor): - self.dataset = dataset - - def denormalize( - self, - prefix: str, - text_num: int, - prediction: np.array, - design_context: DesignContext, - ) -> Tuple: - pred = prediction[prefix] - gt = design_context.get_data(prefix) - pred_token = [] - gt_token = [] - pred_denorm = [] - gt_denorm = [] - canvas_img_size_h, canvas_img_size_w = design_context.canvas_context.img_size - canvas_h_scale, canvas_w_scale = design_context.canvas_context.scale_box - for t in range(text_num): - g = gt[t] - if prefix in self.dataset.tokenizer.prefix_list: - p_token = pred[t] - p = self.dataset.tokenizer.detokenize(prefix, p_token) - g_token = self.dataset.tokenizer.tokenize(prefix, g) - elif prefix in self.dataset.tokenizer.rawdata_list: - p = pred[t] - p_token = getattr(self.dataset, f"raw2token_{prefix}")(p) - g_token = getattr(self.dataset, f"raw2token_{prefix}")(g) - if self.dataset.tokenizer.rawdata_out_format[prefix] == "token": - p = p_token - g = g_token - else: - p = pred[t] - else: - p_token = pred[t] - p = p_token - g_token = g - p = self.denormalize_elm( - prefix, - p, - canvas_img_size_h, - canvas_img_size_w, - canvas_h_scale, - canvas_w_scale, - ) - g = self.denormalize_elm( - prefix, - g, - canvas_img_size_h, - canvas_img_size_w, - canvas_h_scale, - canvas_w_scale, - ) - pred_token.append([p_token]) - gt_token.append(g_token) - pred_denorm.append([p]) - gt_denorm.append(g) - return pred_token, gt_token, pred_denorm, gt_denorm - - def denormalize_gt( - self, - prefix: str, - text_num: int, - design_context: DesignContext, - ) -> Tuple: - gt = design_context.get_data(prefix) - gt_token = [] - gt_denorm = [] - canvas_img_size_h, canvas_img_size_w = design_context.canvas_context.img_size - canvas_h_scale, canvas_w_scale = design_context.canvas_context.scale_box - logger.debug(f"{prefix} {gt}") - for t in range(text_num): - g = gt[t] - if prefix in self.dataset.tokenizer.prefix_list: - g_token = self.dataset.tokenizer.tokenize(prefix, g) - elif prefix in self.dataset.tokenizer.rawdata_list: - g_token = getattr(self.dataset, f"raw2token_{prefix}")(g) - if self.dataset.tokenizer.rawdata_out_format[prefix] == "token": - g = g_token - else: - g_token = g - g = self.denormalize_elm( - prefix, - g, - canvas_img_size_h, - canvas_img_size_w, - canvas_h_scale, - canvas_w_scale, - ) - gt_token.append(g_token) - gt_denorm.append(g) - return gt_token, gt_denorm - - def denormalize_elm( - self, - prefix: str, - val: Union[int, float, Tuple], - canvas_img_size_h: int, - canvas_img_size_w: int, - canvas_h_scale: float, - canvas_w_scale: float, - ) -> Union[int, float, Tuple]: - if hasattr(self.dataset, f"denorm_{prefix}"): - func = getattr(self.dataset, f"denorm_{prefix}") - data_info = { - "val": val, - "img_height": canvas_img_size_h, - "img_width": canvas_img_size_w, - "scale_h": canvas_h_scale, - "scale_w": canvas_w_scale, - } - val = func(**data_info) - return val - - def convert_attributes( - self, - prefix: str, - pred: List, - element_data: Dict, - text_ids: List, - scale_h: float, - ) -> Dict: - converter = getattr(self.dataset, f"convert_{prefix}") - converted_attributes = [] - for i, text_index in enumerate(text_ids): - inputs = { - "val": pred[i][0], - "element_data": element_data, - "text_index": text_index, - "scale_h": scale_h, - } - _converted_attributes = converter(**inputs) - converted_attributes.append(_converted_attributes) - if len(text_ids) > 0: - converted_attribute_prefixes = list(_converted_attributes.keys()) - converted_attribute_dict = {} - for prefix in converted_attribute_prefixes: - attribute_data = [] - for _converted_attributes in converted_attributes: - val = _converted_attributes[prefix] - attribute_data.append([val]) - converted_attribute_dict[prefix] = attribute_data - return converted_attribute_dict - else: - return None diff --git a/src/typography_generation/tools/evaluator.py b/src/typography_generation/tools/evaluator.py deleted file mode 100644 index 1099221..0000000 --- a/src/typography_generation/tools/evaluator.py +++ /dev/null @@ -1,225 +0,0 @@ -import os -import pickle -import time -from typing import Dict, List - -import torch -import torch.nn as nn -import torch.utils.data -from logzero import logger -from typography_generation.io.data_loader import CrelloLoader -from typography_generation.io.data_object import ( - DesignContext, - ModelInput, - PrefixListObject, -) -from typography_generation.tools.denormalizer import Denormalizer -from typography_generation.tools.score_func import ( - EvalDataEntire, - EvalDataInstance, -) -from typography_generation.tools.train import collate_batch -from typography_generation.visualization.renderer import TextRenderer -from typography_generation.visualization.visualizer import ( - get_text_ids, -) - -show_classfication_score_att = [ - "text_font", - "text_font_emb", - "text_align_type", - "text_capitalize", -] -show_abs_erros_att = [ - "text_font_size", - "text_font_size_raw", - "text_center_y", - "text_center_x", - "text_letter_spacing", - "text_angle", - "text_line_height_scale", -] - -show_bigram_score_att = [ - "text_font", - "text_font_emb", - "text_font_color", - "text_align_type", - "text_capitalize", - "text_font_size", - "text_font_size_raw", - "text_center_y", - "text_center_x", - "text_angle", - "text_letter_spacing", - "text_line_height_scale", -] - - -############################################################ -# Evaluator -############################################################ -class Evaluator: - def __init__( - self, - model: nn.Module, - gpu: bool, - save_dir: str, - dataset: CrelloLoader, - prefix_list_object: PrefixListObject, - batch_size: int = 1, - num_worker: int = 2, - show_interval: int = 100, - dataset_division: str = "test", - save_file_prefix: str = "score", - debug: bool = False, - ) -> None: - self.gpu = gpu - self.save_dir = save_dir - self.batch_size = batch_size - self.num_worker = num_worker - self.show_interval = show_interval - self.debug = debug - self.prefix_list_target = prefix_list_object.target - self.dataset_division = dataset_division - - self.dataset = dataset - - self.model = model - if gpu is True: - self.model.cuda() - - self.entire_data = EvalDataEntire( - self.prefix_list_target, - save_dir, - save_file_prefix=save_file_prefix, - ) - self.denormalizer = Denormalizer(self.dataset.dataset) - - self.save_data: Dict[str, Dict[str, List]] - self.save_data = dict() - - fontlabel2fontname = dataset.dataset.dataset.features["font"].feature.int2str - - self.renderer = TextRenderer(dataset.data_dir, fontlabel2fontname) - - def eval_model(self) -> None: - # Data generators - dataloader = torch.utils.data.DataLoader( - self.dataset, - batch_size=self.batch_size, - shuffle=False, - num_workers=self.num_worker, - pin_memory=True, - collate_fn=collate_batch, - ) - with torch.no_grad(): - self.steps = len(dataloader) - self.step = 0 - self.cnt = 0 - self.model.eval() - end = time.time() - for inputs in dataloader: - ( - design_context_list, - model_input_batchdata, - svg_id, - index, - ) = inputs - self.eval_step( - design_context_list, - model_input_batchdata, - svg_id, - index, - end, - ) - end = time.time() - self.step += 1 - - self.show_scores() - if self.dataset_division == "test": - self.save_prediction() - - def eval_step( - self, - design_context_list: List[DesignContext], - model_input_batchdata: List, - svg_id: List, - index: List, - end: float, - ) -> None: - start = time.time() - model_inputs = ModelInput(design_context_list, model_input_batchdata, self.gpu) - predictions = self.model.prediction( - model_inputs, self.dataset.dataset, self.prefix_list_target - ) - data_index = svg_id[0] - - self.instance_data = EvalDataInstance(self.prefix_list_target) - - text_num = design_context_list[0].canvas_context.canvas_text_num - - self.save_data[data_index] = dict() - for prefix in self.prefix_list_target: - pred_token, gt_token, pred, gt = self.denormalizer.denormalize( - prefix, text_num, predictions, design_context_list[0] - ) - self.instance_data.rigister_att( - text_num, - prefix, - pred_token, - gt_token, - pred, - gt, - ) - self.entire_data.update_prediction_data( - data_index, self.instance_data, f"{prefix}" - ) - self.save_data[data_index][prefix] = pred - if hasattr(self.denormalizer.dataset, f"convert_{prefix}"): - element_data = self.dataset.dataset.dataset[index[0]] - text_ids = get_text_ids(element_data) - canvas_h_scale = design_context_list[0].canvas_context.scale_box[0] - converted_attribute_dict = self.denormalizer.convert_attributes( - prefix, - pred, - element_data, - text_ids, - canvas_h_scale, - ) - if converted_attribute_dict is not None: - for prefix, v in converted_attribute_dict.items(): - self.save_data[data_index][prefix] = v - self.entire_data.text_num[data_index] = text_num - - forward_time = time.time() - if self.step % 200 == 0: - data_show = "{}/{}/{}, forward_time: {:.3f} data {:.3f}".format( - self.cnt, - self.step + 1, - self.steps, - forward_time - start, - (start - end), - ) - logger.info(data_show) - - def show_scores(self) -> None: - for prefix in show_classfication_score_att: - if prefix in self.prefix_list_target: - self.entire_data.show_classification_score( - prefix, topk=5, show_topk=[0, 2, 4] - ) - for prefix in show_abs_erros_att: - if prefix in self.prefix_list_target: - self.entire_data.show_abs_erros(prefix) - if "text_font_color" in self.prefix_list_target: - self.entire_data.show_font_color_scores() - for prefix in show_bigram_score_att: - if prefix in self.prefix_list_target: - self.entire_data.show_structure_score(prefix) - self.entire_data.show_alpha_overlap_score() - - def save_prediction(self) -> None: - file_name = os.path.join(self.save_dir, "prediction.pkl") - with open(file_name, mode="wb") as f: - pickle.dump(self.save_data, f) diff --git a/src/typography_generation/tools/loss.py b/src/typography_generation/tools/loss.py deleted file mode 100644 index 2960fa6..0000000 --- a/src/typography_generation/tools/loss.py +++ /dev/null @@ -1,194 +0,0 @@ -from typing import Dict, List, Tuple, Union - -import numpy as np -import torch -from logzero import logger -from torch import Tensor, nn -from torch.functional import F -from typography_generation.config.attribute_config import ( - TextElementContextPredictionAttributeConfig, -) -from typography_generation.io.data_object import ModelInput -from typography_generation.model.common import Linearx3 - - -class LossFunc(object): - def __init__( - self, - model_name: str, - prefix_list_target: List, - prediction_config_element: TextElementContextPredictionAttributeConfig, - gpu: bool, - topk: int = 5, - ) -> None: - super(LossFunc, self).__init__() - self.prefix_list_target = prefix_list_target - self.topk = topk - for prefix in self.prefix_list_target: - target_prediction_config = getattr(prediction_config_element, prefix) - setattr( - self, f"{prefix}_ignore_label", target_prediction_config.ignore_label - ) - setattr(self, f"{prefix}_loss_type", target_prediction_config.loss_type) - if model_name == "canvasvae": - self.vae_weight = 0 - self.fix_vae_weight = 0.002 - if model_name == "mfc": - self.d = Linearx3(40, 1) - if gpu is True: - self.d.cuda() - self.d_optimizer = torch.optim.AdamW( - self.d.parameters(), - lr=0.0002, - betas=(0.5, 0.999), - weight_decay=0.01, - ) - - def get_loss( - self, prefix: str, pred: Tensor, gt: Tensor, loss_type: str, training: bool - ) -> Tensor: - if loss_type == "cre": - loc = gt != getattr(self, f"{prefix}_ignore_label") - pred = pred[loc] - gt = gt[loc] - loss = F.cross_entropy(pred, gt.long()) - elif loss_type == "l1": - loc = gt != getattr(self, f"{prefix}_ignore_label") - pred = pred[loc] - gt = gt[loc] - logger.debug(f"get loss {prefix} {loss_type} {gt}") - loss = F.l1_loss(pred.reshape(gt.shape), gt.float()) - elif loss_type == "mfc_gan": - fake_output = self.d(pred.reshape(gt.shape).detach()) - real_output = self.d(gt) - loc = gt[:, :, 0:1] != getattr(self, f"{prefix}_ignore_label") - if training is True: - real_output = real_output[loc] - Ldadv = ( - fake_output.mean() - - real_output.mean() # + self.lambda_gp * gradient_penalty - ) - self.d_optimizer.zero_grad() - Ldadv.backward() - self.d_optimizer.step() - fake_output = self.d(pred.reshape(gt.shape)) - fake_output = fake_output[loc] - Lsadv = -fake_output.mean() - loc = gt != getattr(self, f"{prefix}_ignore_label") - pred = pred[loc] - gt = gt[loc] - loss = 10 * F.mse_loss(pred.reshape(gt.shape), gt.float()) + Lsadv - else: - raise NotImplementedError() - return loss - - def update_vae_weight(self, epoch: int, epochs: int, step: int, steps: int) -> None: - logger.debug("update vae weight") - self.vae_weight = (epoch + step / steps) / epochs - logger.debug(f"vae weight value {self.vae_weight}") - - def vae_loss(self, mu: Tensor, logsigma: Tensor) -> Tuple: - loss_kl = -0.5 * torch.mean( - 1 + logsigma - mu.pow(2) - torch.exp(logsigma) - ) # vae kl divergence - loss_kl_weighted = loss_kl * self.vae_weight * self.fix_vae_weight - return loss_kl_weighted, loss_kl - - def get_vae_loss(self, vae_items: Tuple) -> Tensor: - loss_kl_weighted = 0 - for mu, logsigma in vae_items: - loss, _ = self.vae_loss(mu, logsigma) - loss_kl_weighted += loss - return loss_kl_weighted # +self.config.VAE_L2_LOSS_WEIGHT*loss_l2 - - def __call__(self, model_inputs: ModelInput, preds: Dict, training: bool) -> Tuple: - total_loss = 0 - record_items = {} - - for prefix in self.prefix_list_target: - pred = preds[prefix] - gt = getattr(model_inputs, prefix) - loss_type = getattr(self, f"{prefix}_loss_type") - loss = self.get_loss( - prefix, - pred, - gt, - loss_type, - training, - ) - pred_label, gt_data = self.get_pred_gt_label(prefix, pred, gt, loss_type) - record_items[prefix] = (pred_label, gt_data, loss.item()) - total_loss += loss - - if "vae_data" in preds.keys(): - logger.debug("compute vae loss") - vae_loss = self.get_vae_loss(preds["vae_data"]) - total_loss = total_loss + vae_loss - logger.debug(f"vae loss {vae_loss}") - return total_loss, record_items - - def get_pred_gt_label( - self, prefix: str, pred: Tensor, gt: Tensor, loss_type: str - ) -> Tuple[List, Union[List, np.array]]: - loc = gt != getattr(self, f"{prefix}_ignore_label") - pred = pred[loc] - gt = gt[loc] - pred_label = self.get_pred_label(pred, loss_type) - gt_label = self.get_gt_label(gt, loss_type) - return pred_label, gt_label - - def get_pred_label( - self, - pred: Tensor, - loss_type: str = "cre", - ) -> List: - if loss_type == "cre": - pred = torch.sort(input=pred, dim=1, descending=True)[1].data.cpu().numpy() - preds = [] - for i in range(len(pred)): - p = [] - for k in range(min(self.topk, pred.shape[1])): - p.append(pred[i, k]) - preds.append(p) - elif loss_type == "l1": - preds = [] - for i in range(len(pred)): - p = [] - for k in range(self.topk): - p.append(0) # dummy data - preds.append(p) - elif loss_type == "mfc_gan": - preds = [] - for i in range(len(pred)): - p = [] - for k in range(self.topk): - p.append(0) # dummy data - preds.append(p) - else: - raise NotImplementedError() - return preds - - def get_gt_label( - self, - gt: Tensor, - loss_type: str = "cre", - ) -> Union[List, np.array]: - if loss_type == "cre": - gt_labels = gt.data.cpu().numpy() - elif loss_type == "l1": - gt_labels = [] - for i in range(len(gt)): - g = [] - for k in range(self.topk): - g.append(0) # dummy data - gt_labels.append(g) - elif loss_type == "mfc_gan": - gt_labels = [] - for i in range(len(gt)): - g = [] - for k in range(self.topk): - g.append(0) # dummy data - gt_labels.append(g) - else: - raise NotImplementedError() - return gt_labels diff --git a/src/typography_generation/tools/prediction_recorder.py b/src/typography_generation/tools/prediction_recorder.py deleted file mode 100644 index 9743990..0000000 --- a/src/typography_generation/tools/prediction_recorder.py +++ /dev/null @@ -1,141 +0,0 @@ -from typing import Dict, List -from logzero import logger - -############################################################ -# Prediction Recoder -############################################################ - - -class PredictionRecoder: - def __init__(self, prefix_list_target: List, topk: int = 5): - super(PredictionRecoder, self).__init__() - self.prefix_list_target = prefix_list_target - self.topk = topk - self.show_topk = list(range(self.topk)) - self.register(prefix_list_target) - self.epoch = 0 - - def register(self, prefix_list_target: List) -> None: - self.all_target_list = [] - self.cl_target_list = [] - self.loss_target_list = [] - for prefix in prefix_list_target: - self.all_target_list.append(f"{prefix}_cl") - self.all_target_list.append(f"{prefix}_loss") - self.cl_target_list.append(f"{prefix}_cl") - self.loss_target_list.append(f"{prefix}_loss") - self.regist_cl_recorder_set(self.cl_target_list) - self.regist_recorder_set(self.loss_target_list) - - def regist_recorder_set(self, target_list: List) -> None: - for tar in target_list: - self.regist_record_target(tar) - - def regist_cl_recorder_set(self, target_list: List) -> None: - for tar in target_list: - self.regist_cl_recorder(tar) - - def regist_cl_recorder(self, registration_name: str) -> None: - self.regist_record_target(f"{registration_name}_pred") - self.regist_record_target(f"{registration_name}_gt") - - def regist_record_target(self, registration_name: str) -> None: - setattr(self, registration_name, []) - setattr(self, f"{registration_name}_history", []) - for k in range(len(self.show_topk)): - setattr(self, f"{registration_name}_history_{self.show_topk[k]}", []) - - def __call__(self, recoder_items: Dict) -> None: - for name, (pred, gt, loss) in recoder_items.items(): - clname = f"{name}_cl" - lossname = f"{name}_loss" - if clname in self.cl_target_list: - for p, g in zip(pred, gt): - getattr(self, f"{clname}_pred").append(p) - getattr(self, f"{clname}_gt").append(g) - if lossname in self.loss_target_list: - getattr(self, lossname).append(loss) - - def reset(self) -> None: - for name in self.all_target_list: - if name in self.cl_target_list: - setattr(self, f"{name}_pred", []) - setattr(self, f"{name}_gt", []) - if name in self.loss_target_list: - setattr(self, name, []) - - def store_score(self) -> None: - for name in self.all_target_list: - if name in self.cl_target_list: - for k in range(len(self.show_topk)): - getattr(self, f"{name}_pred_history_{self.show_topk[k]}").append( - getattr(self, f"{name}{self.show_topk[k]}_acc") - ) - if name in (self.loss_target_list): - getattr(self, f"{name}_history").append(getattr(self, f"{name}_mean")) - - def compute_score(self) -> None: - for name in self.all_target_list: - if name in self.cl_target_list: - topkacc = {} - for k in range(self.topk): - topkacc[k] = 0 - for p, g in zip( - getattr(self, f"{name}_pred"), getattr(self, f"{name}_gt") - ): - flag = 0 - for k in range(min(self.topk, len(p))): - if p[k] == g: - flag = 1 - topkacc[k] += flag - for k in range(min(self.topk, len(topkacc))): - setattr( - self, - f"{name}{k}_acc", - topkacc[k] / max(len(getattr(self, f"{name}_pred")), 1), - ) - if name in (self.loss_target_list): - mean_loss = 0 - for l in getattr(self, f"{name}"): - mean_loss += l - setattr( - self, - f"{name}_mean", - mean_loss / max(len(getattr(self, f"{name}")), 1), - ) - score_dict = self.show_scores() - return score_dict - - def show_scores(self) -> None: - score_dict = {} - for name in self.all_target_list: - if name in self.cl_target_list: - for k in range(len(self.show_topk)): - logger.info( - f"{name}{self.show_topk[k]}_acc:{getattr(self, f'{name}{self.show_topk[k]}_acc')}" - ) - score_dict[name] = getattr(self, f"{name}{self.show_topk[0]}_acc") - if name in self.loss_target_list: - logger.info(f"{name}_mean:{getattr(self, f'{name}_mean')}") - score_dict[name] = getattr(self, f"{name}_mean") - return score_dict - - def show_history_scores(self) -> None: - for i in range(self.epoch): - logger.info(f"epoch {i}") - for name in self.all_target_list: - if name in self.cl_target_list: - for k in range(len(self.show_topk)): - logger.info( - f"{name}{self.show_topk[k]}acc:{getattr(self, f'{name}_pred_history_{self.show_topk[k]}')[i]}" - ) - if name in self.loss_target_list: - logger.info(f"{name}_mean:{getattr(self, f'{name}_history')[i]}") - - def step_epoch(self) -> None: - self.compute_score() - self.store_score() - self.update_epoch() - - def update_epoch(self) -> None: - self.epoch += 1 diff --git a/src/typography_generation/tools/sampler.py b/src/typography_generation/tools/sampler.py deleted file mode 100644 index 1808e32..0000000 --- a/src/typography_generation/tools/sampler.py +++ /dev/null @@ -1,150 +0,0 @@ -import time -from typing import List - -import torch -import torch.nn as nn -import torch.utils.data -from typography_generation.io.data_loader import CrelloLoader -from typography_generation.tools.score_func import EvalDataInstance -from typography_generation.io.data_object import ( - DataPreprocessConfig, - DesignContext, - FontConfig, - ModelInput, - PrefixListObject, - SamplingConfig, -) -from logzero import logger - -from typography_generation.tools.train import collate_batch - -from typography_generation.tools.evaluator import ( - Evaluator, -) - - -############################################################ -# Sampler -############################################################ -class Sampler(Evaluator): - def __init__( - self, - model: nn.Module, - gpu: bool, - save_dir: str, - dataset: CrelloLoader, - prefix_list_object: PrefixListObject, - sampling_config: SamplingConfig, - batch_size: int = 1, - num_worker: int = 2, - show_interval: int = 100, - dataset_division: str = "test", - debug: bool = False, - ) -> None: - super().__init__( - model, - gpu, - save_dir, - dataset, - prefix_list_object, - batch_size=batch_size, - num_worker=num_worker, - show_interval=show_interval, - dataset_division=dataset_division, - debug=debug, - ) - self.sampling_config = sampling_config - - def sample(self) -> None: - # Data generators - dataloader = torch.utils.data.DataLoader( - self.dataset, - batch_size=self.batch_size, - shuffle=False, - num_workers=self.num_worker, - pin_memory=True, - collate_fn=collate_batch, - ) - with torch.no_grad(): - self.steps = len(dataloader) - self.step = 0 - self.cnt = 0 - self.model.eval() - end = time.time() - for inputs in dataloader: - design_context_list, model_input_batchdata, svg_id, _ = inputs - self.sample_step( - design_context_list, model_input_batchdata, svg_id, end - ) - end = time.time() - self.step += 1 - - self.show_scores() - self.entire_data.show_diversity_scores(self.prefix_list_target) - self.save_prediction() - - def sample_step( - self, - design_context_list: List[DesignContext], - model_input_batchdata: List, - svg_id: List, - end: float, - ) -> None: - _data_index = svg_id[0] - self.entire_data.data_index_list.append(_data_index) - for iter in range(self.sampling_config.sampling_num): - data_index = f"{_data_index}_{iter}" - self.sample_iter( - design_context_list, model_input_batchdata, data_index, end - ) - - def sample_iter( - self, - design_context_list: List[DesignContext], - model_input_batchdata: List, - data_index: str, - end: float, - ) -> None: - start = time.time() - model_inputs = ModelInput(design_context_list, model_input_batchdata, self.gpu) - sampler_input = { - "model_inputs": model_inputs, - "target_prefix_list": self.prefix_list_target, - "sampling_param_geometry": self.sampling_config.sampling_param_geometry, - "sampling_param_semantic": self.sampling_config.sampling_param_semantic, - } - predictions = self.model.sample(**sampler_input) - - self.instance_data = EvalDataInstance(self.prefix_list_target) - - text_num = design_context_list[0].canvas_context.canvas_text_num - - self.save_data[data_index] = dict() - for prefix in self.prefix_list_target: - pred_token, gt_token, pred, gt = self.denormalizer.denormalize( - prefix, text_num, predictions, design_context_list[0] - ) - self.instance_data.rigister_att( - text_num, - prefix, - pred_token, - gt_token, - pred, - gt, - ) - self.entire_data.update_prediction_data( - data_index, self.instance_data, f"{prefix}" - ) - self.save_data[data_index][prefix] = pred - self.entire_data.text_num[data_index] = text_num - - forward_time = time.time() - if self.step % 200 == 0: - data_show = "{}/{}/{}, forward_time: {:.3f} data {:.3f}".format( - self.cnt, - self.step + 1, - self.steps, - forward_time - start, - (start - end), - ) - logger.info(data_show) diff --git a/src/typography_generation/tools/score_func.py b/src/typography_generation/tools/score_func.py deleted file mode 100644 index f8a1709..0000000 --- a/src/typography_generation/tools/score_func.py +++ /dev/null @@ -1,657 +0,0 @@ -import itertools -from typing import Dict, List, Tuple - -import numpy as np -from _io import TextIOWrapper -from logzero import logger as log -from typography_generation.tools.color_func import deltaE_ciede2000, rgb2lab - - -class EvalDataInstance: - def __init__( - self, - attribute_list: List, - ) -> None: - self.attribute_list = attribute_list - self.target_list = ["pred_token", "gt_token", "pred", "gt"] - self.reset() - - def reset(self) -> None: - for att in self.attribute_list: - for tar in self.target_list: - registration_name = f"{att}_{tar}" - setattr(self, registration_name, []) - - def rigister_att( - self, - text_num: int, - prefix: str, - target_pred_token: np.array, - target_gt_token: np.array, - target_pred: np.array, - target_gt: np.array, - start_index: int = 0, - ) -> None: - for i in range(start_index, text_num): - registration_name = f"{prefix}_pred_token" - getattr(self, registration_name).append(target_pred_token[i]) - registration_name = f"{prefix}_gt_token" - getattr(self, registration_name).append(target_gt_token[i]) - registration_name = f"{prefix}_pred" - getattr(self, registration_name).append(target_pred[i]) - registration_name = f"{prefix}_gt" - getattr(self, registration_name).append(target_gt[i]) - - -class EvalDataEntire: - def __init__( - self, attribute_list: List, save_dir: str, save_file_prefix: str = "score" - ) -> None: - self.attribute_list = attribute_list - self.text_num = {} - self.overlap_scores = {} - self.data_index_list = [] - self.target_list = ["pred_token", "gt_token", "pred", "gt"] - for att in self.attribute_list: - for tar in self.target_list: - registration_name = f"{att}_{tar}" - setattr(self, registration_name, {}) - - save_file = f"{save_dir}/{save_file_prefix}.txt" - self.f = open(save_file, "w") - - def update_prediction_data( - self, - index: str, - instance_obj: EvalDataInstance, - prefix: str, - ) -> None: - getattr(self, f"{prefix}_pred_token")[index] = getattr( - instance_obj, f"{prefix}_pred_token" - ) - getattr(self, f"{prefix}_gt_token")[index] = getattr( - instance_obj, f"{prefix}_gt_token" - ) - getattr(self, f"{prefix}_pred")[index] = getattr(instance_obj, f"{prefix}_pred") - getattr(self, f"{prefix}_gt")[index] = getattr(instance_obj, f"{prefix}_gt") - - def update_sampling_data( - self, - index: str, - instance_obj: EvalDataInstance, - prefix: str, - ) -> None: - primary_index, sub_index = index.split("_") - if int(sub_index) > 0: - getattr(self, prefix)[primary_index].append(getattr(instance_obj, prefix)) - else: - getattr(self, prefix)[primary_index] = [] - getattr(self, prefix)[primary_index].append(getattr(instance_obj, prefix)) - - def show_classification_score( - self, att: str, topk: int = 10, show_topk: List = [0, 5] - ) -> None: - log.info(f"{att}") - self.f.write(f"{att} \n") - compute_score( - getattr(self, f"{att}_pred"), - getattr(self, f"{att}_gt"), - topk, - show_topk, - self.f, - ) - - def show_abs_erros( - self, prefix: str, blanktype: str = "", topk: int = 10, show_topk: List = [0, 5] - ) -> None: - log.info(f"{prefix}") - self.f.write(f"{prefix} \n") - compute_abs_error_score( - getattr(self, f"{prefix}_pred"), - getattr(self, f"{prefix}_gt"), - self.f, - ) - - def show_font_color_scores( - self, blanktype: str = "", topk: int = 10, show_topk: List = [0, 5] - ) -> None: - log.info(f"font_color") - self.f.write(f"font_color \n") - compute_color_score( - getattr(self, f"text_font_color_pred"), - getattr(self, f"text_font_color_gt"), - self.f, - ) - - def show_structure_score(self, att: str) -> None: - log.info(f"{att}") - self.f.write(f"{att} \n") - compute_bigram_score( - getattr(self, f"text_num"), - getattr(self, f"{att}_pred_token"), - getattr(self, f"{att}_gt_token"), - self.f, - ) - - def show_visual_similarity_scores(self) -> None: - registration_name = "l2error" - dict_average_score(registration_name, getattr(self, registration_name)) - registration_name = "psnr" - dict_average_score(registration_name, getattr(self, registration_name)) - - def show_time_score(self) -> None: - registration_name = "time" - dict_average_score(registration_name, getattr(self, registration_name)) - - def show_diversity_scores(self, attribute_list: List) -> None: - for att in attribute_list: - log.info(f"{att}") - self.f.write(f"{att} \n") - compute_label_diversity_score( - getattr(self, "data_index_list"), - getattr(self, f"text_num"), - getattr(self, f"{att}_pred_token"), - self.f, - ) - - def show_alpha_overlap_score(self) -> None: - compute_alpha_overlap( - getattr(self, "overlap_scores"), - self.f, - ) - - -def compute_abs_error_score( - eval_list: dict, - gt_list: dict, - f: TextIOWrapper, -) -> None: - cnt_img = 0 - l1_distance = 0.0 - r_l1_distance = 0.0 - for index in eval_list.keys(): - g = gt_list[index] - if len(g) > 0: - e = eval_list[index] - d = 0.0 - rd = 0.0 - for i, (pred, gt) in enumerate(zip(e, g)): - pred = pred[0] - _d = abs(gt - pred) - _rd = abs(gt - pred) / max(abs(float(gt)), 1e-5) - d += _d - rd += _rd - l1_distance += d / len(g) - r_l1_distance += rd / len(g) - cnt_img += 1 - l1_distance /= cnt_img - log.info(f"l1_distance {l1_distance}") - f.write(f"l1_distance {l1_distance} \n") - r_l1_distance /= cnt_img - log.info(f"r_l1_distance {r_l1_distance}") - f.write(f"r_l1_distance {r_l1_distance} \n") - - -def compute_color_score( - font_color_eval_list: dict, - font_color_gt_list: dict, - f: TextIOWrapper, -) -> None: - cnt_img = 0 - color_distance = 0.0 - for index in font_color_eval_list.keys(): - e = font_color_eval_list[index] - g = font_color_gt_list[index] - if len(g) > 0: - d = 0.0 - for i, (pred, gt) in enumerate(zip(e, g)): - pred = pred[0] - lab_p = rgb2lab(np.array(pred).reshape(1, 1, 3).astype(np.float32)) - lab_g = rgb2lab(np.array(gt).reshape(1, 1, 3).astype(np.float32)) - _d = deltaE_ciede2000(lab_p, lab_g) - d += _d[0][0] - color_distance += d / len(g) - cnt_img += 1 - color_distance /= cnt_img - log.info(f"color_distance {color_distance}") - f.write(f"color_distance {color_distance} \n") - - -def compute_score( - eval_list: dict, - gt_list: dict, - topk: int, - show_topk: List, - f: TextIOWrapper, -) -> Tuple: - cnt_elm = 0 - cnt_img = 0 - topk_acc_elm = {} - topk_acc_img = {} - for k in range(topk): - topk_acc_elm[k] = 0.0 - topk_acc_img[k] = 0.0 - for index in eval_list.keys(): - e = eval_list[index] - g = gt_list[index] - topk_acc_tmp = {} - for k in range(topk): - topk_acc_tmp[k] = 0.0 - if len(g) > 0: - cnt_gt = 0 - for i, gt in enumerate(g): - flag = 0 - for k in range(min(topk, len(e[i]))): - if int(gt) == int(e[i][k]): - flag = 1.0 - topk_acc_elm[k] += flag - topk_acc_tmp[k] += flag - cnt_gt += 1 - cnt_elm += 1 - for k in range(topk): - if cnt_gt > 0: - topk_acc_img[k] += topk_acc_tmp[k] / cnt_gt - cnt_img += 1 - for k in range(topk): - topk_acc_elm[k] /= cnt_elm - topk_acc_img[k] /= cnt_img - if k in show_topk: - log.info(f"top{k} img_level_acc {topk_acc_img[k]}") - f.write(f"top{k} img_level_acc {topk_acc_img[k]} \n") - return topk_acc_elm, topk_acc_img - - -def dict_average_score(prefix: str, score_dict: dict) -> None: - score_mean = 0 - cnt = 0 - for index in score_dict.keys(): - score_mean += score_dict[index] - cnt += 1 - log.info("{} {}".format(prefix, score_mean / cnt)) - - -def compute_unigram_label_score( - text_num: int, - text_target_mask: np.array, - font_pred: np.array, - font_gt: np.array, - ignore_labels: List[int], -) -> float: - cnt = 0 - correct_cnt = 0 - for i in range(text_num): - fi = font_pred[i] - if fi in ignore_labels or text_target_mask[i] == 0: - continue - else: - cnt += 1 - for j in range(text_num): - fj = int(font_gt[j]) - if fi == fj: - correct_cnt += 1 - break - if cnt > 0: - score = float(correct_cnt) / cnt - else: - score = 0 - return score - - -def compute_bigram_label_score( - pred: np.array, - gt: np.array, -) -> float: - text_num = len(gt) - text_cmb = list(itertools.combinations(list(range(text_num)), 2)) - cnt = 0 - correct_cnt = 0 - for pi, pj in text_cmb: - fpi = pred[pi][0] - fpj = pred[pj][0] - cnt += 1 - for gi, gj in text_cmb: - fgi = int(gt[gi]) - fgj = int(gt[gj]) - if (fpi == fgi) and (fpj == fgj): - correct_cnt += 1 - break - elif (fpi == fgj) and (fpj == fgi): - correct_cnt += 1 - break - if cnt > 0: - score = float(correct_cnt) / cnt - else: - score = 0 - return score - - -def get_binary_classification_scores( - l11cnt: int, l00cnt: int, l10cnt: int, l01cnt: int -) -> Tuple: - if l11cnt + l10cnt > 0: - precision = float(l11cnt) / (l11cnt + l10cnt) - else: - precision = 0 - - if l11cnt + l01cnt > 0: - recall = float(l11cnt) / (l11cnt + l01cnt) - else: - recall = 0 - - if l00cnt + l01cnt > 0: - precision_inv = float(l00cnt) / (l00cnt + l01cnt) - else: - precision_inv = 0 - - if l00cnt + l10cnt > 0: - recall_inv = float(l00cnt) / (l00cnt + l10cnt) - else: - recall_inv = 0 - - if precision + recall > 0: - fvalue = 2 * precision * recall / (precision + recall) - else: - fvalue = 0 - - if 2 * l11cnt + l01cnt + l10cnt == 0: - _fvalue = np.nan - else: - _fvalue = 2 * l11cnt / (2 * l11cnt + l01cnt + l10cnt) - - if precision_inv + recall_inv > 0: - fvalue_inv = 2 * precision_inv * recall_inv / (precision_inv + recall_inv) - else: - fvalue_inv = 0 - - if 2 * l00cnt + l01cnt + l10cnt == 0: - _fvalue_inv = np.nan - else: - _fvalue_inv = 2 * l00cnt / (2 * l00cnt + l01cnt + l10cnt) - - if l11cnt + l00cnt + l01cnt + l10cnt > 0: - accuracy = float(l11cnt + l00cnt) / (l11cnt + l00cnt + l01cnt + l10cnt) - else: - accuracy = 0 - if l00cnt + l01cnt > 0: - spcecificity = float(l00cnt) / (l00cnt + l01cnt) - else: - spcecificity = 0 - return ( - accuracy, - spcecificity, - precision, - recall, - fvalue, - precision_inv, - recall_inv, - fvalue_inv, - _fvalue, - _fvalue_inv, - ) - - -def compute_bigram_structure_score( - pred: np.array, - gt: np.array, -) -> Tuple: - text_num = len(gt) - text_cmb = list(itertools.combinations(list(range(text_num)), 2)) - l11cnt = 0 - l00cnt = 0 - l10cnt = 0 - l01cnt = 0 - for pi, pj in text_cmb: - fpi = pred[pi][0] - fpj = pred[pj][0] - fgi = int(gt[pi]) - fgj = int(gt[pj]) - if (fpi == fpj) and (fgi == fgj): - l11cnt += 1 - # l00cnt += 1 - if (fpi != fpj) and (fgi != fgj): - l00cnt += 1 - # l11cnt += 1 - if (fpi != fpj) and (fgi == fgj): - l10cnt += 1 - # l01cnt += 1 - if (fpi == fpj) and (fgi != fgj): - l01cnt += 1 - # l10cnt += 1 - scores = get_binary_classification_scores(l11cnt, l00cnt, l10cnt, l01cnt) - return scores, (l11cnt, l00cnt, l10cnt, l01cnt) - - -def get_structure_type( - gt: np.array, -) -> float: - text_num = len(gt) - text_cmb = list(itertools.combinations(list(range(text_num)), 2)) - consistency_num = 0 - contrast_num = 0 - for pi, pj in text_cmb: - fgi = int(gt[pi]) - fgj = int(gt[pj]) - if fgi == fgj: - consistency_num += 1 - else: - contrast_num += 1 - if text_num <= 1: - flag = 0 # uncount - elif consistency_num == 0: - flag = 1 # no consistency - elif contrast_num == 0: - flag = 2 # no contrast - else: - flag = 3 # others - return flag - - -def compute_bigram_score( - text_num_list: dict, - pred_list: dict, - gt_list: dict, - f: TextIOWrapper, -) -> Tuple: - cnt = 0 - structure_accuracy_mean = 0.0 - structure_precision_mean = 0.0 - structure_recall_mean = 0.0 - structure_fvalue_mean = 0.0 - structure_spcecificity_mean = 0.0 - structure_precision_inv_mean = 0.0 - structure_recall_inv_mean = 0.0 - structure_fvalue_inv_mean = 0.0 - label_score_mean = 0.0 - l11cnt_all = 0 - l00cnt_all = 0 - l10cnt_all = 0 - l01cnt_all = 0 - diff_case_scores = {} - diff_case_counts = {} - diff_case_scores[1] = 0.0 # no consistency - diff_case_scores[2] = 0.0 # no contrast - diff_case_scores[3] = 0.0 # others - diff_case_counts[1] = 0 - diff_case_counts[2] = 0 - diff_case_counts[3] = 0 - structure_nanmean = [] - for index in pred_list.keys(): - text_num = text_num_list[index] - if text_num == 0: - continue - pred = pred_list[index] - gt = gt_list[index] - flag = get_structure_type(gt) - scores, counts = compute_bigram_structure_score(pred, gt) - ( - structure_accuracy, - structure_spcecificity, - structure_precision, - structure_recall, - structure_fvalue, - structure_precision_inv, - structure_recall_inv, - structure_fvalue_inv, - _structure_fvalue, - _structure_fvalue_inv, - ) = scores - l11cnt, l00cnt, l10cnt, l01cnt = counts - l11cnt_all += l11cnt - l00cnt_all += l00cnt - l10cnt_all += l10cnt - l01cnt_all += l01cnt - label_score = compute_bigram_label_score(pred, gt) - structure_accuracy_mean += structure_accuracy - structure_spcecificity_mean += structure_spcecificity - structure_precision_mean += structure_precision - structure_recall_mean += structure_recall - structure_fvalue_mean += structure_fvalue - structure_precision_inv_mean += structure_precision_inv - structure_recall_inv_mean += structure_recall_inv - structure_fvalue_inv_mean += structure_fvalue_inv - label_score_mean += label_score - - if flag == 0: - pass - elif flag == 1: # no consistency - diff_case_scores[1] += structure_fvalue_inv - diff_case_counts[1] += 1 - elif flag == 2: # no contrast - diff_case_scores[2] += structure_fvalue - diff_case_counts[2] += 1 - elif flag == 3: # others - diff_case_scores[3] += (structure_fvalue + structure_fvalue_inv) / 2.0 - diff_case_counts[3] += 1 - structure_nanmean.append(_structure_fvalue) - structure_nanmean.append(_structure_fvalue_inv) - - cnt += 1 - structure_accuracy_mean /= cnt - structure_spcecificity_mean /= cnt - structure_precision_mean /= cnt - structure_recall_mean /= cnt - structure_fvalue_mean /= cnt - structure_precision_inv_mean /= cnt - structure_recall_inv_mean /= cnt - structure_fvalue_inv_mean /= cnt - label_score_mean /= cnt - log.info("structure_accuracy {:.3f}".format(structure_accuracy_mean)) - f.write("structure_accuracy {:.3f} \n".format(structure_accuracy_mean)) - - # log.info("label_score {:.3f}".format(label_score_mean)) - # f.write("label_score {:.3f} \n".format(label_score_mean)) - log.info("structure nanmean {:.3f}".format(np.nanmean(structure_nanmean))) - f.write("structure nanmean {:.3f} \n".format(np.nanmean(structure_nanmean))) - for i in range(1, 4): - if diff_case_counts[i] > 0: - log.info( - "structure_case_score{} count:{} {:.3f}".format( - i, diff_case_counts[i], diff_case_scores[i] / diff_case_counts[i] - ) - ) - f.write( - "structure_case_score{} count:{} {:.3f} \n".format( - i, diff_case_counts[i], diff_case_scores[i] / diff_case_counts[i] - ) - ) - else: - log.info("structure_case_score{} count:{} -".format(i, diff_case_counts[i])) - f.write( - "structure_case_score{} count:{} - \n".format(i, diff_case_counts[i]) - ) - - scores = get_binary_classification_scores( - l11cnt_all, l00cnt_all, l10cnt_all, l01cnt_all - ) - ( - structure_accuracy, - structure_spcecificity, - structure_precision, - structure_recall, - structure_fvalue, - structure_precision_inv, - structure_recall_inv, - structure_fvalue_inv, - _structure_fvalue, - _structure_fvalue_inv, - ) = scores - return structure_accuracy_mean, label_score_mean - - -def compute_label_diversity_score( - data_index_list: List, - text_num_list: Dict, - pred_list: Dict, - f: TextIOWrapper, - sampling_num: int = 10, -) -> None: - def compute_label_diversity(pred_labels: List, text_num: int) -> float: - unique_num_rate_avg = 0.0 - for k in range(text_num): - labels = [] - for j in range(len(pred_labels)): - l = int(pred_labels[j][k][0]) - labels.append(l) - unique_num_rate = len(set(labels)) / float(len(pred_labels)) - unique_num_rate_avg += unique_num_rate - unique_num_rate_avg /= text_num - return unique_num_rate_avg - - label_diversity_avg = 0.0 - cnt = 0 - for index in data_index_list: - text_num = text_num_list[f"{index}_0"] - pred_lists = [] - for n in range(sampling_num): - preds = pred_list[f"{index}_{n}"] - pred_lists.append(preds) - if text_num > 0: - label_diversity = compute_label_diversity(pred_lists, text_num) - label_diversity_avg += label_diversity - cnt += 1 - label_diversity_avg /= cnt - log.info("diversity score {:.1f}".format(label_diversity_avg * 100)) - f.write("diversity score {:.1f}\n".format(label_diversity_avg * 100)) - - -def compute_alpha_overlap( - overlap_scores: Dict, - f: TextIOWrapper, -) -> None: - overlap_score_all = 0 - cnt_all = 0 - data_index_list = list(overlap_scores.keys()) - for index in data_index_list: - overlap_score = overlap_scores[f"{index}"] - if overlap_score is not None: - overlap_score_all += overlap_score - cnt_all += 1 - if cnt_all > 0: - overlap_score_all = overlap_score_all / cnt_all - - log.info("alpha overlap score {:.2f}".format(overlap_score_all)) - f.write("alpha overlap score {:.2f}\n".format(overlap_score_all)) - - -def _compute_alpha_overlap( - alpha_map_list: List, -) -> None: - overlap_score = 0 - cnt = 0 - for i in range(len(alpha_map_list)): - alpha_i = alpha_map_list[i] - for j in range(len(alpha_map_list)): - if i == j: - continue - else: - alpha_j = alpha_map_list[j] - overlap = np.sum(alpha_i * alpha_j) - if np.sum(alpha_i) > 0: - recall = overlap / np.sum(alpha_i) - overlap_score += recall - cnt += 1 - if cnt > 0: - overlap_score = overlap_score / cnt - return overlap_score - else: - return None diff --git a/src/typography_generation/tools/structure_preserved_sampler.py b/src/typography_generation/tools/structure_preserved_sampler.py deleted file mode 100644 index d8e5c96..0000000 --- a/src/typography_generation/tools/structure_preserved_sampler.py +++ /dev/null @@ -1,103 +0,0 @@ -import time -from typing import List - -import torch -import torch.nn as nn -import torch.utils.data -from typography_generation.io.data_loader import CrelloLoader -from typography_generation.tools.sampler import Sampler -from typography_generation.tools.score_func import EvalDataInstance -from typography_generation.io.data_object import ( - DataPreprocessConfig, - DesignContext, - FontConfig, - ModelInput, - PrefixListObject, - SamplingConfig, -) -from logzero import logger - - -############################################################ -# Structure Preserved Sampler -############################################################ -class StructurePreservedSampler(Sampler): - def __init__( - self, - model: nn.Module, - gpu: bool, - save_dir: str, - dataset: CrelloLoader, - prefix_list_object: PrefixListObject, - sampling_config: SamplingConfig, - batch_size: int = 1, - num_worker: int = 2, - show_interval: int = 100, - dataset_division: str = "test", - debug: bool = False, - ) -> None: - super().__init__( - model, - gpu, - save_dir, - dataset, - prefix_list_object, - sampling_config, - batch_size=batch_size, - num_worker=num_worker, - show_interval=show_interval, - dataset_division=dataset_division, - debug=debug, - ) - - def sample_iter( - self, - design_context_list: List[DesignContext], - model_input_batchdata: List, - data_index: str, - end: float, - ) -> None: - start = time.time() - model_inputs = ModelInput(design_context_list, model_input_batchdata, self.gpu) - sampler_input = { - "model_inputs": model_inputs, - "dataset": self.dataset.dataset, - "target_prefix_list": self.prefix_list_target, - "sampling_param_geometry": self.sampling_config.sampling_param_geometry, - "sampling_param_semantic": self.sampling_config.sampling_param_semantic, - } - predictions = self.model.structure_preserved_sample(**sampler_input) - - self.instance_data = EvalDataInstance(self.prefix_list_target) - - text_num = design_context_list[0].canvas_context.canvas_text_num - - self.save_data[data_index] = dict() - for prefix in self.prefix_list_target: - pred_token, gt_token, pred, gt = self.denormalizer.denormalize( - prefix, text_num, predictions, design_context_list[0] - ) - self.instance_data.rigister_att( - text_num, - prefix, - pred_token, - gt_token, - pred, - gt, - ) - self.entire_data.update_prediction_data( - data_index, self.instance_data, f"{prefix}" - ) - self.save_data[data_index][prefix] = pred - self.entire_data.text_num[data_index] = text_num - - forward_time = time.time() - # if self.step % 200 == 0: - data_show = "{}/{}/{}, forward_time: {:.3f} data {:.3f}".format( - self.cnt, - self.step + 1, - self.steps, - forward_time - start, - (start - end), - ) - logger.info(data_show) diff --git a/src/typography_generation/tools/tokenizer.py b/src/typography_generation/tools/tokenizer.py deleted file mode 100644 index 178c85f..0000000 --- a/src/typography_generation/tools/tokenizer.py +++ /dev/null @@ -1,95 +0,0 @@ -import pickle -from typing import Dict, Tuple, Union -from einops import repeat -import numpy as np -from torch import Tensor -import torch - -default_cluster_num_dict = { - "text_font_size": 16, - "text_font_color": 64, - "text_height": 16, - "text_width": 16, - "text_top": 64, - "text_left": 64, - "text_center_y": 64, - "text_center_x": 64, - "text_angle": 16, - "text_letter_spacing": 16, - "text_line_height_scale": 16, - "canvas_aspect_ratio": 16, -} - - -class Tokenizer: - def __init__( - self, - data_dir: str, - cluster_num_dict: Union[Dict, None] = None, - load_cluster: bool = True, - ) -> None: - self.prefix_list = [ - "text_font_size", - "text_font_color", - "text_height", - "text_width", - "text_top", - "text_left", - "text_center_y", - "text_center_x", - "text_angle", - "text_letter_spacing", - "text_line_height_scale", - "canvas_aspect_ratio", - ] - self.rawdata2token = { - "text_font_emb": "text_font", - "text_font_size_raw": "text_font_size", - } - self.rawdata_list = list(self.rawdata2token.keys()) - self.rawdata_out_format = { - "text_font_emb": "token", - "text_font_size_raw": "raw", - } - - self.prediction_token_list = [ - "text_font_emb", - ] - if cluster_num_dict is None: - cluster_num_dict = default_cluster_num_dict - if load_cluster is True: - for prefix in self.prefix_list: - cluster_num = cluster_num_dict[prefix] - fn = f"{data_dir}/cluster/{prefix}_{cluster_num}.pkl" - if prefix == "text_font_color": - cluster = np.array(pickle.load(open(fn, "rb"))) - else: - cluster = np.array(pickle.load(open(fn, "rb"))).flatten() - setattr(self, f"{prefix}_cluster", cluster) - - def assign_label(self, val: Union[float, int], bins: np.array) -> int: - label = int(np.argsort(np.square(bins - val))[0]) - return label - - def assign_color_label(self, val: Union[float, int], bins: np.array) -> int: - val = np.tile(np.array(val)[np.newaxis, :], (len(bins), 1)) - d = np.square(bins - val).sum(1) - label = int(np.argsort(d, axis=0)[0]) - return label - - def tokenize(self, prefix: str, val: Union[float, int]) -> int: - if prefix == "text_font_color": - label = self.assign_color_label(val, getattr(self, f"{prefix}_cluster")) - else: - label = self.assign_label(val, getattr(self, f"{prefix}_cluster")) - return label - - def detokenize(self, prefix: str, label: Union[int, float]) -> Union[Tuple, float]: - if prefix == "text_font_color": - b, g, r = getattr(self, f"{prefix}_cluster")[int(label)] - return (r, g, b) - elif prefix == "text_font_size_raw": - val = float(getattr(self, f"text_font_size_cluster")[int(label)]) - else: - val = float(getattr(self, f"{prefix}_cluster")[int(label)]) - return val diff --git a/src/typography_generation/tools/train.py b/src/typography_generation/tools/train.py deleted file mode 100644 index c7e18b9..0000000 --- a/src/typography_generation/tools/train.py +++ /dev/null @@ -1,293 +0,0 @@ -import gc -import os -import re -import time -from typing import Any, List, Tuple, Union - -import datasets -import torch -import torch.nn as nn -import torch.utils.data -from logzero import logger -from torch.utils.data._utils.collate import default_collate -from torch.utils.tensorboard import SummaryWriter - -from typography_generation.config.attribute_config import ( - TextElementContextPredictionAttributeConfig, -) -from typography_generation.io.data_loader import CrelloLoader -from typography_generation.io.data_object import ( - ModelInput, - PrefixListObject, -) -from typography_generation.tools.loss import LossFunc -from typography_generation.tools.prediction_recorder import PredictionRecoder -from typography_generation.tools.tokenizer import Tokenizer - - -############################################################ -# DataParallel_withLoss -############################################################ -class FullModel(nn.Module): - def __init__(self, model: nn.Module, loss: LossFunc, gpu: bool) -> None: - super(FullModel, self).__init__() - self.model = model - self.loss = loss - self.gpu = gpu - - def forward( - self, - design_context_list: List, - model_input_batchdata: List, - ) -> Tuple: - model_inputs = ModelInput(design_context_list, model_input_batchdata, self.gpu) - outputs = self.model(model_inputs) - total_loss, record_items = self.loss(model_inputs, outputs, self.training) - return (outputs, torch.unsqueeze(total_loss, 0), record_items) - - def update(self, epoch: int, epochs: int, step: int, steps: int) -> None: - if self.model.model_name == "canvasvae": - self.loss.update_vae_weight(epoch, epochs, step, steps) - - -def collate_batch(batch: Tuple[Any, List, str]) -> Tuple: - design_contexts_list = [] - input_batch = [] - svg_id_list = [] - index_list = [] - for design_contexts, model_input_list, svg_id, index in batch: - design_contexts_list.append(design_contexts) - input_batch.append(model_input_list) - svg_id_list.append(svg_id) - index_list.append(index) - input_batch = default_collate(input_batch) - return design_contexts_list, input_batch, svg_id_list, index_list - - -OPTIMIZER_DICT = { - "adam": (torch.optim.AdamW, {"betas": (0.5, 0.999)}), - "sgd": (torch.optim.SGD, {}), -} - - -############################################################ -# Trainer -############################################################ -class Trainer: - def __init__( - self, - model: nn.Module, - gpu: bool, - save_dir: str, - dataset: CrelloLoader, - dataset_val: CrelloLoader, - prefix_list_object: PrefixListObject, - prediction_config_element: TextElementContextPredictionAttributeConfig, - epochs: int = 31, - save_epoch: int = 5, - batch_size: int = 32, - num_worker: int = 2, - learning_rate: float = 0.0002, - weight_decay: float = 0.01, - optimizer_option: str = "adam", - show_interval: int = 100, - train_only: bool = False, - debug: bool = False, - ) -> None: - self.gpu = gpu - self.save_dir = save_dir - self.epochs = epochs - self.save_epoch = save_epoch - self.batch_size = batch_size - self.num_worker = num_worker - self.show_interval = show_interval - self.train_only = train_only - self.debug = debug - self.dataset = dataset - self.dataset_val = dataset_val - self.prefix_list_target = prefix_list_object.target - - layer_regex = { - "lr1": r"(emb.*)|(enc.*)|(lf.*)|(dec.*)|(head.*)", - } - self.epoch = 0 - # model.emb.emb_canvas.load_resnet_weight(data_dir) - # model.emb.emb_element.load_resnet_weight(data_dir) - param = [ - p - for name, p in model.named_parameters() - if bool(re.fullmatch(layer_regex["lr1"], name)) - ] - param_name = [ - name - for name, _ in model.named_parameters() - if bool(re.fullmatch(layer_regex["lr1"], name)) - ] - lossfunc = LossFunc( - model.model_name, - self.prefix_list_target, - prediction_config_element, - gpu, - topk=1, - ) - logger.info(optimizer_option) - optimizer_func, optimizer_kwarg = OPTIMIZER_DICT[optimizer_option] - optimizer_kwarg["lr"] = learning_rate - optimizer_kwarg["weight_decay"] = weight_decay - self.optimizer = optimizer_func(param, **optimizer_kwarg) - self.fullmodel = FullModel(model, lossfunc, gpu) - self.writer = SummaryWriter(os.path.join(save_dir, "tensorboard")) - if gpu is True: - logger.info("use gpu") - logger.info(f"torch.cuda.is_available() {torch.cuda.is_available()}") - self.fullmodel.cuda() - logger.info("model to cuda") - - def train_model(self) -> None: - # Data generators - dataloader = torch.utils.data.DataLoader( - self.dataset, - batch_size=self.batch_size, - shuffle=True, - num_workers=self.num_worker, - pin_memory=True, - collate_fn=collate_batch, - ) - self.fullmodel.train() - self.pr_train = PredictionRecoder(self.prefix_list_target) - self.pr_val = PredictionRecoder(self.prefix_list_target) - self.epoch = 0 - self.iter_count_train = 0 - self.iter_count_val = 0 - for epoch in range(0, self.epochs): - logger.info("Epoch {}/{}.".format(epoch, self.epochs)) - self.epoch = epoch - # Training - self.pr_train.reset() - logger.info("training") - self.train_epoch(dataloader) - self.pr_train.step_epoch() - torch.cuda.empty_cache() - gc.collect() - logger.info("validation") - self.pr_val.reset() - if self.train_only is False: - self.val_model() - self.pr_val.step_epoch() - if epoch % self.save_epoch == 0: - torch.save( - self.fullmodel.model.state_dict(), - os.path.join(self.save_dir, "model.pth".format(epoch)), - ) - torch.cuda.empty_cache() - gc.collect() - logger.info("training finished") - logger.info("show data") - self.pr_train.show_history_scores() - self.pr_val.show_history_scores() - - def train_epoch(self, dataloader: Any) -> None: - self.steps = len(dataloader) - self.fullmodel.train() - self.step = 0 - self.cnt = 0 - end = time.time() - for inputs in dataloader: - logger.debug("load data") - design_context_list, model_input_batchdata, _, _ = inputs - logger.debug("train step") - self.train_step(design_context_list, model_input_batchdata, end) - end = time.time() - self.step += 1 - self.fullmodel.update(self.epoch, self.epochs, self.step, self.steps) - if self.debug is True: - break - - def train_step( - self, - design_context_list: List, - model_input_batchdata: List, - end: float, - ) -> None: - start = time.time() - logger.debug("model apply") - _, total_loss, recoder_items = self.fullmodel( - design_context_list, model_input_batchdata - ) - logger.debug(f"model apply {time.time()-start}") - logger.debug("record prediction and gt") - self.pr_train(recoder_items) - logger.debug(f"record {time.time()-start}") - logger.debug("update parameters") - total_loss = torch.mean(total_loss) - self.optimizer.zero_grad() - total_loss.backward() - self.optimizer.step() - logger.debug(f"optimize {time.time()-start}") - forward_time = time.time() - if self.step % self.show_interval == 0: - if self.gpu is True: - torch.cuda.empty_cache() - data_show = "{}/{}/{}/{}, forward_time: {:.3f} data {:.3f}".format( - self.epoch, - self.cnt, - self.step + 1, - self.steps, - forward_time - start, - (start - end), - ) - logger.info(data_show) - data_show = "total_loss: {:.3f}".format(total_loss.item()) - logger.info(data_show) - score_dict = self.pr_train.compute_score() - for k, v in score_dict.items(): - self.writer.add_scalar(f"train/{k}", v, self.iter_count_train) - self.iter_count_train += 1 - - def val_model(self) -> None: - # Data generators - dataloader = torch.utils.data.DataLoader( - self.dataset_val, - batch_size=self.batch_size, - shuffle=False, - num_workers=self.num_worker, - pin_memory=True, - collate_fn=collate_batch, - ) - with torch.no_grad(): - self.steps = len(dataloader) - self.step = 0 - self.cnt = 0 - self.fullmodel.eval() - end = time.time() - for inputs in dataloader: - design_context_list, model_input_batchdata, _, _ = inputs - self.val_step(design_context_list, model_input_batchdata, end) - end = time.time() - self.step += 1 - - def val_step( - self, - design_context_list: List, - model_input_batchdata: List, - end: float, - ) -> None: - start = time.time() - _, _, recoder_items = self.fullmodel(design_context_list, model_input_batchdata) - self.pr_val(recoder_items) - forward_time = time.time() - if self.step % 40 == 0: - data_show = "{}/{}/{}, forward_time: {:.3f} data {:.3f}".format( - self.cnt, - self.step + 1, - self.steps, - forward_time - start, - (start - end), - ) - logger.info(data_show) - score_dict = self.pr_val.compute_score() - for k, v in score_dict.items(): - self.writer.add_scalar(f"val/{k}", v, self.iter_count_val) - self.iter_count_val += 1 - torch.cuda.empty_cache() - gc.collect() diff --git a/src/typography_generation/visualization/__init__.py b/src/typography_generation/visualization/__init__.py deleted file mode 100644 index 8b13789..0000000 --- a/src/typography_generation/visualization/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/typography_generation/visualization/renderer.py b/src/typography_generation/visualization/renderer.py deleted file mode 100644 index 5a7d8ee..0000000 --- a/src/typography_generation/visualization/renderer.py +++ /dev/null @@ -1,183 +0,0 @@ -from typing import Any, List, Tuple -import skia -import os -import pickle -import numpy as np - -from typography_generation.visualization.renderer_util import ( - get_color_map, - get_skia_font, - get_text_actual_height, - get_text_actual_width, - get_text_alpha, - get_texts, -) - - -class TextRenderer: - def __init__( - self, - data_dir: str, - fontlabel2fontname: Any, - ) -> None: - self.fontmgr = skia.FontMgr() - fn = os.path.join(data_dir, "font2ttf.pkl") - _font2ttf = pickle.load(open(fn, "rb")) - font2ttf = {} - for key in _font2ttf.keys(): - tmp = _font2ttf[key].split("/data/dataset/crello/")[1] - fn = os.path.join(data_dir, tmp) - font2ttf[key] = fn - self.font2ttf = font2ttf - fn = os.path.join(data_dir, "fonttype2fontid_fix.pkl") - fonttype2fontid = pickle.load(open(fn, "rb")) - - self.fontid2fonttype = {} - for k, v in fonttype2fontid.items(): - self.fontid2fonttype[v] = k - self.fontlabel2fontname = fontlabel2fontname - - def draw_texts( - self, - element_data: dict, - text_ids: List, - bg: np.array, - scaleinfo: Tuple, - ) -> np.array: - H, W = bg.shape[0], bg.shape[1] - h_rate, w_rate = scaleinfo - canvas = bg.copy() - for text_id in text_ids: - font_label = element_data["font"][text_id] - font_name = self.fontlabel2fontname(int(font_label)) - font_name = font_name.replace(" ", "_") - texts = get_texts(element_data, text_id) - font, _ = get_skia_font( - self.font2ttf, - self.fontmgr, - element_data, - text_id, - font_name, - h_rate, - ) - text_alpha = get_text_alpha( - element_data, - text_id, - texts, - font, - H, - W, - w_rate, - ) - text_rgb_map = get_color_map(element_data, text_id, H, W) - canvas = canvas * (1 - text_alpha) + text_alpha * text_rgb_map - return canvas - - def get_text_alpha_list( - self, - element_data: dict, - text_ids: List, - image_size: Tuple[int, int], - scaleinfo: Tuple[float, float], - ) -> List: - H, W = image_size - h_rate, w_rate = scaleinfo - text_alpha_list = [] - for text_id in text_ids: - font_label = element_data["font"][text_id] - font_name = self.fontlabel2fontname(int(font_label)) - font_name = font_name.replace(" ", "_") - texts = get_texts(element_data, text_id) - font, _ = get_skia_font( - self.font2ttf, - self.fontmgr, - element_data, - text_id, - font_name, - h_rate, - ) - text_alpha = get_text_alpha( - element_data, - text_id, - texts, - font, - H, - W, - w_rate, - ) - text_alpha_list.append(text_alpha) - return text_alpha_list - - def get_text_actual_height_list( - self, element_data: dict, text_ids: List, scaleinfo: Tuple[float, float] - ) -> List: - text_actual_height_list = [] - h_rate, _ = scaleinfo - for text_id in text_ids: - font_label = element_data["font"][text_id] - font_name = self.fontlabel2fontname(int(font_label)) - font_name = font_name.replace(" ", "_") - font, _ = get_skia_font( - self.font2ttf, - self.fontmgr, - element_data, - text_id, - font_name, - h_rate, - ) - text_actual_height = get_text_actual_height(font) - text_actual_height_list.append(text_actual_height) - return text_actual_height_list - - def compute_and_set_text_actual_width( - self, - element_data: dict, - text_ids: List, - scaleinfo: Tuple, - ) -> None: - h_rate, w_rate = scaleinfo - text_actual_width = {} - for text_id in text_ids: - font_label = element_data["font"][text_id] - font_name = self.fontlabel2fontname(int(font_label)) - font_name = font_name.replace(" ", "_") - texts = get_texts(element_data, text_id) - font, _ = get_skia_font( - self.font2ttf, - self.fontmgr, - element_data, - text_id, - font_name, - h_rate, - ) - _text_actual_width = get_text_actual_width( - element_data, text_id, texts, font, w_rate - ) - text_actual_width[text_id] = _text_actual_width - element_data["text_actual_width"] = text_actual_width - - def compute_and_set_text_center( - self, element_data: dict, text_ids: List, image_size: Tuple[int, int] - ) -> None: - H, W = image_size - text_center_x = {} - text_center_y = {} - for text_id in text_ids: - left = element_data["left"][text_id] * W - w = element_data["width"][text_id] * W - textAlign = element_data["text_align"][text_id] - right = left + w - actual_w = element_data["text_actual_width"][text_id] - if textAlign == 1: - _text_center_x = (left + right) / 2.0 - elif textAlign == 3: - _text_center_x = right - actual_w / 2.0 - elif textAlign == 2: - _text_center_x = left + actual_w / 2.0 - text_height = element_data["height"][text_id] * H - top = element_data["top"][text_id] * H - _text_center_y = (top + top + text_height) / 2.0 - text_center_y[text_id] = _text_center_y - text_center_x[text_id] = _text_center_x - element_data["text_center_y"] = text_center_y - element_data["text_center_x"] = text_center_x diff --git a/src/typography_generation/visualization/renderer_util.py b/src/typography_generation/visualization/renderer_util.py deleted file mode 100644 index a4e6504..0000000 --- a/src/typography_generation/visualization/renderer_util.py +++ /dev/null @@ -1,225 +0,0 @@ -import html -import math -import os -from typing import Any, Dict, List, Tuple, Union - -import numpy as np -import skia - - -def capitalize_text(text: str, capitalize: int) -> str: - text_tmp = "" - for character in text: - if capitalize == 1: - character = character.upper() - text_tmp += character - return text_tmp - - -def text_align( - textAlign: int, left: float, center: float, right: float, text_alpha_width: float -) -> float: - if textAlign == 1: - x = center - text_alpha_width / 2.0 - elif textAlign == 3: - x = right - text_alpha_width - elif textAlign == 2: - x = left - return x - - -def get_text_location_info(font: skia.Font, text_tmp: str) -> Tuple: - glyphs = font.textToGlyphs(text_tmp) - positions = font.getPos(glyphs) - rects = font.getBounds(glyphs) - return glyphs, positions, rects - - -def compute_text_alpha_width( - positions: List, rects: List, letterSpacing: float -) -> Union[float, Any]: - twidth = positions[-1].x() + rects[-1].right() - if letterSpacing is not None: - twidth += letterSpacing * (len(rects) - 1) - return twidth - - -def add_letter_margin(x: float, letterSpacing: float) -> float: - if letterSpacing is not None: - x = x + letterSpacing - return x - - -def get_text_actual_height( - font: skia.Font, -): - ascender = -1 * font.getMetrics().fAscent - descender = font.getMetrics().fDescent - leading = font.getMetrics().fLeading - text_height = ascender + descender + leading - return text_height - - -def get_text_alpha( - element_data: Any, - text_index: int, - texts: List, - font: skia.Font, - H: int, - W: int, - w_rate: float, -) -> np.array: - center_y = element_data["text_center_y"][text_index] * H - center_x = element_data["text_center_x"][text_index] * W - text_width = get_text_actual_width(element_data, text_index, texts, font, w_rate) - left = center_x - text_width / 2.0 - right = center_x + text_width / 2.0 - ascender = -1 * font.getMetrics().fAscent - descender = font.getMetrics().fDescent - leading = font.getMetrics().fLeading - line_height_scale = element_data["line_height"][text_index] - line_height = (ascender + descender + leading) * line_height_scale - surface = skia.Surface(W, H) - canvas = surface.getCanvas() - fill_paint = skia.Paint( - AntiAlias=True, - Color=skia.ColorSetRGB(255, 0, 0), - Style=skia.Paint.kFill_Style, - ) - fill_paint.setBlendMode(skia.BlendMode.kSrcOver) - y = center_y - line_height * len(texts) / 2.0 - for text in texts: - text = html.unescape(text) - text = capitalize_text(text, element_data["capitalize"][text_index]) - _, positions, rects = get_text_location_info(font, text) - if len(positions) == 0: - continue - text_alpha_width = compute_text_alpha_width( - positions, rects, element_data["letter_spacing"][text_index] * w_rate - ) - # print(text,element_data["letter_spacing"][text_index],element_data["capitalize"][text_index]) - angle = float(element_data["angle"][text_index]) * 180 / math.pi - x = text_align( - element_data["text_align"][text_index], - left, - center_x, - right, - text_alpha_width, - ) - canvas.rotate(angle, center_x, center_y) - for i, character in enumerate(text): - ydp = np.round(y + positions[i].y() + ascender) - xdp = np.round(x + positions[i].x()) - textblob = skia.TextBlob(character, font) - canvas.drawTextBlob(textblob, xdp, ydp, fill_paint) - x = add_letter_margin( - x, element_data["letter_spacing"][text_index] * w_rate - ) - canvas.rotate(-1 * angle, center_x, y) - y += line_height - text_alpha = surface.makeImageSnapshot().toarray()[:, :, 0] - text_alpha = text_alpha / 255.0 - text_alpha = np.tile(text_alpha[:, :, np.newaxis], (1, 1, 3)) - return np.minimum(text_alpha, np.zeros_like(text_alpha) + 1) - - -def get_text_actual_width( - element_data: Any, - text_index: int, - texts: List, - font: skia.Font, - w_rate: float, -) -> np.array: - text_alpha_width = 0.0 - for text in texts: - text = html.unescape(text) - text = capitalize_text(text, element_data["capitalize"][text_index]) - _, positions, rects = get_text_location_info(font, text) - if len(positions) == 0: - continue - _text_alpha_width = compute_text_alpha_width( - positions, rects, element_data["letter_spacing"][text_index] * w_rate - ) - text_alpha_width = max(text_alpha_width, _text_alpha_width) - return text_alpha_width - - -def font_name_fix(font_name: str) -> str: - if font_name == "Exo_2": - font_name = "Exo\_2" - if font_name == "Press_Start_2P": - font_name = "Press_Start\_2P" - if font_name == "quattrocento": - font_name = "Quattrocento" - if font_name == "yellowtail": - font_name = "Yellowtail" - if font_name == "sunday": - font_name = "Sunday" - if font_name == "bebas_neue": - font_name = "Bebas_Neue" - if font_name == "Brusher": - font_name = "Brusher_Regular" - if font_name == "Amatic_Sc": - font_name = "Amatic_SC" - if font_name == "Pt_Sans": - font_name = "PT_Sans" - if font_name == "Old_Standard_Tt": - font_name = "Old_Standard_TT" - if font_name == "Eb_Garamond": - font_name = "EB_Garamond" - if font_name == "Gfs_Didot": - font_name = "GFS_Didot" - if font_name == "Im_Fell": - font_name = "IM_Fell" - if font_name == "Im_Fell_Dw_Pica_Sc": - font_name = "IM_Fell_DW_Pica_SC" - if font_name == "Marcellus_Sc": - font_name = "Marcellus_SC" - return font_name - - -def get_skia_font( - font2ttf: dict, - fontmgr: skia.FontMgr, - element_data: Dict, - targetid: int, - font_name: str, - scale_h: float, - font_scale: float = 1.0, -) -> Tuple: - font_name = font_name_fix(font_name) - if font_name in font2ttf: - ttf = font2ttf[font_name] - ft = fontmgr.makeFromFile(ttf, 0) - font = skia.Font( - ft, element_data["font_size"][targetid] * scale_h, font_scale, 1e-20 - ) - - return font, font_name - else: - ft = fontmgr.makeFromFile("", 0) - font = skia.Font( - ft, element_data["font_size"][targetid] * scale_h, font_scale, 1e-20 - ) - return None, None - - -def get_color_map(element_data: Any, targetid: int, H: int, W: int) -> np.array: - B, G, R = element_data["color"][targetid] - rgb_map = np.zeros((H, W, 3), dtype=np.uint8) - rgb_map[:, :, 0] = B - rgb_map[:, :, 1] = G - rgb_map[:, :, 2] = R - return rgb_map - - -def get_texts(element_data: Dict, target_id: int) -> List: - text = html.unescape(element_data["text"][target_id]) - _texts = text.split(os.linesep) - texts = [] - for t in _texts: - if t == "": - pass - else: - texts.append(t) - return texts diff --git a/src/typography_generation/visualization/visualizer.py b/src/typography_generation/visualization/visualizer.py deleted file mode 100644 index 1ef6d6c..0000000 --- a/src/typography_generation/visualization/visualizer.py +++ /dev/null @@ -1,190 +0,0 @@ -import copy -from typing import Dict, List, Tuple - -import numpy as np -from typography_generation.tools.denormalizer import Denormalizer -from typography_generation.tools.tokenizer import Tokenizer -from typography_generation.visualization.renderer import TextRenderer - -crelloattstr2pkgattstr = { - "text_font": "font", - "text_font_color": "color", - "text_align_type": "text_align", - "text_capitalize": "capitalize", - "text_font_size": "font_size", - "text_font_size_raw": "font_size", - "text_angle": "angle", - "text_letter_spacing": "letter_spacing", - "text_line_height_scale": "line_height", - "text_center_y": "text_center_y", - "text_center_x": "text_center_x", -} - - -def get_text_ids(element_data: Dict) -> List: - text_ids = [] - for k in range(len(element_data["text"])): - if element_data["text"][k] == "": - pass - else: - text_ids.append(k) - return text_ids - - -def replace_style_data_by_prediction( - prediction: Dict, element_data: Dict, text_ids: List -) -> Dict: - element_data = copy.deepcopy(element_data) - for prefix_pred, prefix_vec in crelloattstr2pkgattstr.items(): - if prefix_pred in prediction.keys(): - for i, t in enumerate(text_ids): - element_data[prefix_vec][t] = prediction[prefix_pred][i][0] - return element_data - - -def get_ordered_text_ids(element_data, order_list) -> List: - text_ids = [] - for i in order_list: - if element_data["text"][i] == "": - pass - else: - text_ids.append(i) - return text_ids - - -def visualize_prediction( - renderer: TextRenderer, - element_data: Dict, - prediction: Dict, - bg_img: np.array, -) -> np.array: - text_ids = get_text_ids(element_data) - order_list = element_data["order_list"] - scaleinfo = element_data["scale_box"] - text_ids = get_ordered_text_ids(element_data, order_list) - element_data = replace_style_data_by_prediction(prediction, element_data, text_ids) - img = renderer.draw_texts(element_data, text_ids, np.array(bg_img), scaleinfo) - return img - - -def get_predicted_alphamaps( - renderer: TextRenderer, - element_data: Dict, - prediction: Dict, - image_size: Tuple[int, int], - order_list: List = None, -) -> List: - text_ids = get_text_ids(element_data) - if order_list is None: - order_list = element_data["order_list"] - scaleinfo = element_data["scale_box"] - text_ids = ordering_text_ids(order_list, text_ids) - element_data = replace_style_data_by_prediction(prediction, element_data, text_ids) - alpha_list = renderer.get_text_alpha_list( - element_data, text_ids, image_size, scaleinfo - ) - return alpha_list - - -def get_element_alphamaps( - renderer: TextRenderer, - element_data: Dict, -) -> List: - text_ids = get_text_ids(element_data) - order_list = element_data["order_list"] - scaleinfo = element_data["scale_box"] - image_size = element_data["canvas_bg_size"] - text_ids = ordering_text_ids(order_list, text_ids) - alpha_list = renderer.get_text_alpha_list( - element_data, text_ids, image_size, scaleinfo - ) - return alpha_list - - -def visualize_data( - renderer: TextRenderer, - element_data: Dict, - bg_img: np.array, -) -> np.array: - text_ids = get_text_ids(element_data) - scaleinfo = element_data["scale_box"] - img = renderer.draw_texts(element_data, text_ids, np.array(bg_img), scaleinfo) - return img - - -def tokenize( - _element_data: Dict, - tokenizer: Tokenizer, - denormalizer: Denormalizer, - text_ids: List, - bg_img: np.array, - scaleinfo: Tuple, -) -> Dict: - element_data = copy.deepcopy(_element_data) - h, w = bg_img.size[1], bg_img.size[0] - for prefix_pred, prefix_vec in crelloattstr2pkgattstr.items(): - for i, t in enumerate(text_ids): - data_info = { - "element_data": _element_data, - "text_index": t, - "img_size": (h, w), - "scaleinfo": scaleinfo, - "text_actual_width": _element_data["text_actual_width"][t], - "text": None, - } - data = getattr(denormalizer.dataset, f"get_{prefix_pred}")(**data_info) - if prefix_pred in denormalizer.dataset.tokenizer.prefix_list: - data = tokenizer.tokenize(prefix_pred, data) - data = tokenizer.detokenize(prefix_pred, data) - data = denormalizer.denormalize_elm( - prefix_pred, data, h, w, scaleinfo[0], scaleinfo[1] - ) - element_data[prefix_vec][t] = data - return element_data - - -def visualize_tokenization( - renderer: TextRenderer, - tokenizer: Tokenizer, - denormalizer: Denormalizer, - element_data: Dict, - bg_img: np.array, -) -> np.array: - text_ids = get_text_ids(element_data) - scaleinfo = element_data["scale_box"] - element_data = tokenize( - element_data, tokenizer, denormalizer, text_ids, bg_img, scaleinfo - ) - img = renderer.draw_texts(element_data, text_ids, np.array(bg_img), scaleinfo) - return img - - -def get_text_coords(element_data: Dict, text_index: int, img_size: Tuple) -> Tuple: - h, w = img_size - top = int(element_data["top"][text_index] * h) - left = int(element_data["left"][text_index] * w) - height = int(element_data["height"][text_index] * h) - width = int(element_data["width"][text_index] * w) - return top, left, top + height, left + width - - -def colorize_text( - element_data: Dict, - canvas: np.array, - text_index: int, - color: Tuple = (255, 0, 0), - w: float = 0.5, -) -> np.array: - text_ids = get_text_ids(element_data) - order_list = element_data["order_list"] - scaleinfo = element_data["scale_box"] - text_ids = ordering_text_ids(order_list, text_ids) - y0, x0, y1, x1 = get_text_coords( - element_data, text_ids[text_index], canvas.shape[:2] - ) - tmp = canvas.copy() - tmp[y0:y1, x0:x1, :] = np.array(color) - canvas[y0:y1, x0:x1, :] = ( - w * canvas[y0:y1, x0:x1, :] + (1 - w) * tmp[y0:y1, x0:x1, :] - ) - return canvas diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index 8b13789..0000000 --- a/tests/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/conftest.py b/tests/conftest.py deleted file mode 100644 index 4254d4d..0000000 --- a/tests/conftest.py +++ /dev/null @@ -1,92 +0,0 @@ -import pytest -import torch - -from typography_generation.config.config_args_util import ( - get_global_config, - get_model_config_input, - get_prefix_lists, -) -from typography_generation.config.default import get_font_config -from typography_generation.io.build_dataset import ( - build_test_dataset, - build_train_dataset, -) -from typography_generation.model.model import create_model -from typography_generation.tools.train import collate_batch - - -@pytest.fixture -def bartconfig(): - data_dir = "data" - config_name = "bart" - bartconfig = get_global_config(data_dir, config_name) - return bartconfig - - -@pytest.fixture -def bartconfigdataset_test(bartconfig): - data_dir = "data" - prefix_list_object = get_prefix_lists(bartconfig) - font_config = get_font_config(bartconfig) - - bartconfigdataset_test = build_test_dataset( - data_dir, - prefix_list_object, - font_config, - debug=True, - ) - return bartconfigdataset_test - - -@pytest.fixture -def bartconfigdataset(bartconfig): - data_dir = "data" - prefix_list_object = get_prefix_lists(bartconfig) - font_config = get_font_config(bartconfig) - - bartconfigdataset, _ = build_train_dataset( - data_dir, - prefix_list_object, - font_config, - debug=True, - ) - return bartconfigdataset - - -@pytest.fixture -def bartconfigdataset_val(bartconfig): - data_dir = "data" - prefix_list_object = get_prefix_lists(bartconfig) - font_config = get_font_config(bartconfig) - - _, bartconfigdataset_val = build_train_dataset( - data_dir, - prefix_list_object, - font_config, - debug=True, - ) - return bartconfigdataset_val - - -@pytest.fixture -def bartconfigdataloader(bartconfigdataset): - bartconfigdataloader = torch.utils.data.DataLoader( - bartconfigdataset, - batch_size=2, - shuffle=False, - num_workers=1, - pin_memory=True, - collate_fn=collate_batch, - ) - return bartconfigdataloader - - -@pytest.fixture -def bartmodel(bartconfig): - model_name, model_kwargs = get_model_config_input(bartconfig) - - bertmodel = create_model( - model_name, - **model_kwargs, - ) - return bertmodel diff --git a/tests/io/__init__.py b/tests/io/__init__.py deleted file mode 100644 index 8b13789..0000000 --- a/tests/io/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/io/test_data_loader.py b/tests/io/test_data_loader.py deleted file mode 100644 index 3967126..0000000 --- a/tests/io/test_data_loader.py +++ /dev/null @@ -1,59 +0,0 @@ -import pytest -import datasets -import torch -from typography_generation.__main__ import ( - get_global_config, - get_prefix_lists, -) -from typography_generation.config.default import ( - get_datapreprocess_config, - get_font_config, -) -from typography_generation.io.build_dataset import build_test_dataset -from typography_generation.io.data_loader import CrelloLoader -from typography_generation.tools.tokenizer import Tokenizer - -from typography_generation.tools.train import collate_batch - -params = {"normal 1": ("data", "bart", 0), "normal 2": ("data", "bart", 1)} - - -@pytest.mark.parametrize("data_dir, config_name, index", list(params.values())) -def test_get_item(data_dir: str, config_name: str, index: int) -> None: - config = get_global_config(data_dir, config_name) - prefix_list_object = get_prefix_lists(config) - font_config = get_font_config(config) - - dataset = build_test_dataset( - data_dir, - prefix_list_object, - font_config, - debug=True, - ) - dataset.__getitem__(index) - - -@pytest.mark.parametrize("data_dir, config_name", [["data", "bart"]]) -def test_dataloader_iteration(data_dir: str, config_name: str) -> None: - config = get_global_config(data_dir, config_name) - prefix_list_object = get_prefix_lists(config) - font_config = get_font_config(config) - - dataset = build_test_dataset( - data_dir, - prefix_list_object, - font_config, - debug=True, - ) - - dataloader = torch.utils.data.DataLoader( - dataset, - batch_size=1, - shuffle=False, - num_workers=1, - pin_memory=True, - collate_fn=collate_batch, - ) - tmp = dataloader.__iter__() - next(tmp) - next(tmp) diff --git a/tests/model/__init__.py b/tests/model/__init__.py deleted file mode 100644 index 8b13789..0000000 --- a/tests/model/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/model/test_model.py b/tests/model/test_model.py deleted file mode 100644 index 70d3298..0000000 --- a/tests/model/test_model.py +++ /dev/null @@ -1,49 +0,0 @@ -from typing import Any -import pytest -import datasets -import torch -from typography_generation.__main__ import ( - get_global_config, - get_model_config_input, - get_prefix_lists, -) -from typography_generation.config.default import ( - get_datapreprocess_config, - get_font_config, -) -from typography_generation.io.build_dataset import build_test_dataset -from typography_generation.io.data_object import ModelInput -from typography_generation.model.model import create_model -from typography_generation.tools.train import collate_batch - - -@pytest.mark.parametrize( - "data_dir, config_name", - [ - ["data", "bart"], - # ["crello", "mlp"], - # ["crello", "canvasvae"], - # ["crello", "mfc"], - ], -) -def test_model(dataset: Any, data_dir: str, config_name: str) -> None: - config = get_global_config(data_dir, config_name) - model_name, model_kwargs = get_model_config_input(config) - - model = create_model( - model_name, - **model_kwargs, - ) - - dataloader = torch.utils.data.DataLoader( - dataset, - batch_size=2, - shuffle=False, - num_workers=1, - pin_memory=True, - collate_fn=collate_batch, - ) - tmp = dataloader.__iter__() - design_context_list, model_input_batchdata, _, _ = next(tmp) - model_inputs = ModelInput(design_context_list, model_input_batchdata, gpu=False) - model(model_inputs) diff --git a/tests/test_main.py b/tests/test_main.py deleted file mode 100644 index 47fda27..0000000 --- a/tests/test_main.py +++ /dev/null @@ -1,106 +0,0 @@ -import datasets -import pytest -from logzero import logger -import os -from typography_generation.__main__ import ( - get_global_config, - get_model_config_input, - get_prefix_lists, -) -from typography_generation.config.default import ( - get_datapreprocess_config, - get_font_config, - get_model_input_prefix_list, -) -from typography_generation.io.build_dataset import build_train_dataset -from typography_generation.io.data_loader import CrelloLoader -from typography_generation.model.model import create_model -from typography_generation.tools.tokenizer import Tokenizer -from typography_generation.tools.train import Trainer - - -@pytest.mark.parametrize("data_dir, config_name", [["crello", "bart"]]) -def test_model_creation(data_dir: str, config_name: str) -> None: - config = get_global_config(data_dir, config_name) - model_name, model_kwargs = get_model_config_input(config) - - create_model( - model_name, - **model_kwargs, - ) - - -@pytest.mark.parametrize("data_dir, config_name", [["crello", "bart"]]) -def test_loader_creation(data_dir: str, config_name: str) -> None: - config = get_global_config(data_dir, config_name) - prefix_list_model_input = get_model_input_prefix_list(config) - font_config = get_font_config(config) - datapreprocess_config = get_datapreprocess_config(config) - hugging_dataset = datasets.load_from_disk( - os.path.join(data_dir, "extended_dataset", "map_features.hf") - ) - tokenizer = Tokenizer(data_dir) - CrelloLoader( - data_dir, - tokenizer, - hugging_dataset, - prefix_list_model_input, - font_config, - datapreprocess_config, - train=True, - dataset_division="train", - ) - - -@pytest.mark.parametrize( - "data_dir, save_dir, config_name", - [["crello", "job", "bart"]], -) -def test_trainer_creation(data_dir: str, save_dir: str, config_name: str) -> None: - logger.info(config_name) - config = get_global_config(data_dir, config_name) - model_name, model_kwargs = get_model_config_input(config) - - model = create_model( - model_name, - **model_kwargs, - ) - prefix_list_object = get_prefix_lists(config) - prediction_config_element = config.text_element_prediction_attribute_config - font_config = get_font_config(config) - datapreprocess_config = get_datapreprocess_config(config) - optimizer_option = config.train_config.optimizer - - dataset, dataset_val = build_train_dataset( - data_dir, - prefix_list_object, - font_config, - datapreprocess_config, - debug=True, - ) - - gpu = False - Trainer( - model, - gpu, - save_dir, - dataset, - dataset_val, - prefix_list_object, - prediction_config_element, - optimizer_option=optimizer_option, - ) - - -@pytest.mark.parametrize( - "data_dir, config_name", - [["crello", "bart"]], -) -def test_model_config(data_dir: str, config_name: str) -> None: - logger.info(f"config_name {config_name}") - config = get_global_config(data_dir, config_name) - model_name, model_kwargs = get_model_config_input(config) - create_model( - model_name, - **model_kwargs, - ) diff --git a/tests/tool/__init__.py b/tests/tool/__init__.py deleted file mode 100644 index 8b13789..0000000 --- a/tests/tool/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/tool/test_eval.py b/tests/tool/test_eval.py deleted file mode 100644 index fcf9252..0000000 --- a/tests/tool/test_eval.py +++ /dev/null @@ -1,95 +0,0 @@ -import pytest -from typography_generation.__main__ import ( - get_global_config, - get_model_config_input, - get_prefix_lists, -) -from typography_generation.config.default import ( - get_font_config, -) -from typography_generation.io.build_dataset import build_test_dataset -from typography_generation.model.model import create_model -from typography_generation.tools.evaluator import Evaluator - - -def test_eval_iter(bartconfig, bartconfigdataset_test, bartmodel) -> None: - prefix_list_object = get_prefix_lists(bartconfig) - - gpu = False - save_dir = "job" - evaluator = Evaluator( - bartmodel, - gpu, - save_dir, - bartconfigdataset_test, - prefix_list_object, - debug=True, - ) - evaluator.eval_model() - - -@pytest.mark.parametrize( - "data_dir, save_dir, config_name, elementembeddingflagconfigname, canvasembeddingflagconfigname, elementpredictionflagconfigname", - [ - [ - "data", - "job", - "bart", - "text_element_embedding_flag_config/wofontsize", - "canvas_embedding_flag_config/canvas_detail_given", - "text_element_prediction_flag_config/rawfontsize", - ], - ], -) -def test_flag_config_eval( - data_dir: str, - save_dir: str, - config_name: str, - elementembeddingflagconfigname: str, - canvasembeddingflagconfigname: str, - elementpredictionflagconfigname, -) -> None: - global_config_input = {} - global_config_input["data_dir"] = data_dir - global_config_input["model_name"] = config_name - global_config_input["test_config_name"] = "test_config" - global_config_input["model_config_name"] = "model_config" - global_config_input[ - "elementembeddingflag_config_name" - ] = elementembeddingflagconfigname - global_config_input[ - "canvasembeddingflag_config_name" - ] = canvasembeddingflagconfigname - global_config_input[ - "elementpredictionflag_config_name" - ] = elementpredictionflagconfigname - - config = get_global_config(**global_config_input) - model_name, model_kwargs = get_model_config_input(config) - - model = create_model( - model_name, - **model_kwargs, - ) - # import torch - # model.load_state_dict(torch.load("job/weight.pth", map_location="cpu")) - prefix_list_object = get_prefix_lists(config) - font_config = get_font_config(config) - - dataset = build_test_dataset( - data_dir, - prefix_list_object, - font_config, - debug=True, - ) - - gpu = False - evaluator = Evaluator( - model, - gpu, - save_dir, - dataset, - prefix_list_object, - debug=True, - ) - evaluator.eval_model() diff --git a/tests/tool/test_sample.py b/tests/tool/test_sample.py deleted file mode 100644 index 75240c6..0000000 --- a/tests/tool/test_sample.py +++ /dev/null @@ -1,90 +0,0 @@ -from typing import Dict, List -import pytest -from typography_generation.__main__ import ( - get_global_config, - get_model_config_input, - get_prefix_lists, - get_sampling_config, -) -from typography_generation.config.default import ( - get_font_config, -) -from typography_generation.io.build_dataset import build_test_dataset -from typography_generation.model.model import create_model -from typography_generation.tools.sampler import Sampler - - -@pytest.mark.parametrize( - "data_dir, save_dir, config_name, test_config, model_config", - [ - ["data", "job", "bart", "test_config/topp07", "model_config"], - ], -) -def test_sample_iter( - bartconfigdataset_test, - bartmodel, - data_dir: str, - save_dir: str, - config_name: str, - test_config: str, - model_config: str, -) -> None: - config = get_global_config( - data_dir, - config_name, - test_config_name=test_config, - model_config_name=model_config, - ) - prefix_list_object = get_prefix_lists(config) - sampling_config = get_sampling_config(config) - - gpu = False - sampler = Sampler( - bartmodel, - gpu, - save_dir, - bartconfigdataset_test, - prefix_list_object, - sampling_config, - debug=True, - ) - sampler.sample() - - -@pytest.mark.parametrize( - "data_dir,save_dir,config_name", - [ - ["data", "job", "canvasvae"], - ], -) -def test_sample_canvasvae(data_dir: str, save_dir: str, config_name: str) -> None: - config = get_global_config(data_dir, config_name) - model_name, model_kwargs = get_model_config_input(config) - - model = create_model( - model_name, - **model_kwargs, - ) - prefix_list_object = get_prefix_lists(config) - font_config = get_font_config(config) - sampling_config = get_sampling_config(config) - - gpu = False - dataset = build_test_dataset( - data_dir, - prefix_list_object, - font_config, - debug=True, - ) - - gpu = False - sampler = Sampler( - model, - gpu, - save_dir, - dataset, - prefix_list_object, - sampling_config, - debug=True, - ) - sampler.sample() diff --git a/tests/tool/test_structure_preserved_sampler.py b/tests/tool/test_structure_preserved_sampler.py deleted file mode 100644 index 0f4a042..0000000 --- a/tests/tool/test_structure_preserved_sampler.py +++ /dev/null @@ -1,49 +0,0 @@ -from typing import Dict, List -import pytest -import os -import pickle -import torch -from typography_generation.__main__ import ( - get_global_config, - get_model_config_input, - get_prefix_lists, - get_sampling_config, -) -from typography_generation.config.default import ( - get_datapreprocess_config, - get_font_config, -) -from typography_generation.io.build_dataset import build_test_dataset -from typography_generation.io.data_loader import CrelloLoader -from typography_generation.io.data_object import ModelInput -from typography_generation.model.model import create_model -from typography_generation.tools.denormalizer import Denormalizer -from typography_generation.tools.structure_preserved_sampler import ( - StructurePreservedSampler, -) -from typography_generation.tools.tokenizer import Tokenizer -import datasets - -from typography_generation.tools.train import collate_batch - -import logzero -from logzero import logger -import logging - - -def test_sample_iter(bartconfig, bartconfigdataset_test, bartmodel) -> None: - prefix_list_object = get_prefix_lists(bartconfig) - sampling_config = get_sampling_config(bartconfig) - - gpu = False - save_dir = "job" - sampler = StructurePreservedSampler( - bartmodel, - gpu, - save_dir, - bartconfigdataset_test, - prefix_list_object, - sampling_config, - debug=True, - ) - sampler.sample() diff --git a/tests/tool/test_train.py b/tests/tool/test_train.py deleted file mode 100644 index 5734b28..0000000 --- a/tests/tool/test_train.py +++ /dev/null @@ -1,167 +0,0 @@ -import pytest -from typography_generation.__main__ import ( - get_global_config, - get_model_config_input, - get_prefix_lists, -) -from typography_generation.config.default import ( - get_font_config, -) -from typography_generation.io.build_dataset import ( - build_test_dataset, - build_train_dataset, -) -from typography_generation.io.data_object import ModelInput -from typography_generation.model.model import create_model -from typography_generation.tools.loss import LossFunc -from typography_generation.tools.train import Trainer - - -def test_compute_loss(bartconfig, bartconfigdataloader, bartmodel) -> None: - prefix_list_object = get_prefix_lists(bartconfig) - - tmp = bartconfigdataloader.__iter__() - design_context_list, model_input_batchdata, _, _ = next(tmp) - model_inputs = ModelInput(design_context_list, model_input_batchdata, gpu=False) - outputs = bartmodel(model_inputs) - prediction_config_element = bartconfig.text_element_prediction_attribute_config - loss = LossFunc( - bartmodel.model_name, - prefix_list_object.target, - prediction_config_element, - gpu=False, - ) - loss(model_inputs, outputs, training=True) - - -def test_train_iter( - bartconfig, bartconfigdataset, bartconfigdataset_val, bartmodel -) -> None: - save_dir = "job" - optimizer_option = bartconfig.train_config.optimizer - prefix_list_object = get_prefix_lists(bartconfig) - prediction_config_element = bartconfig.text_element_prediction_attribute_config - trainer = Trainer( - bartmodel, - False, - save_dir, - bartconfigdataset, - bartconfigdataset_val, - prefix_list_object, - prediction_config_element, - optimizer_option=optimizer_option, - debug=True, - epochs=1, - ) - trainer.train_model() - - -@pytest.mark.parametrize( - "data_dir, config_name", - [["data", "mfc"], ["data", "canvasvae"]], -) -def test_train_config(data_dir: str, config_name: str) -> None: - config = get_global_config(data_dir, config_name) - model_name, model_kwargs = get_model_config_input(config) - - model = create_model( - model_name, - **model_kwargs, - ) - font_config = get_font_config(config) - optimizer_option = config.train_config.optimizer - prefix_list_object = get_prefix_lists(config) - prediction_config_element = config.text_element_prediction_attribute_config - - dataset, dataset_val = build_train_dataset( - data_dir, - prefix_list_object, - font_config, - debug=True, - ) - - save_dir = "job" - trainer = Trainer( - model, - False, - save_dir, - dataset, - dataset_val, - prefix_list_object, - prediction_config_element, - optimizer_option=optimizer_option, - debug=True, - epochs=1, - ) - trainer.train_model() - - -@pytest.mark.parametrize( - "data_dir, save_dir, config_name, elementembeddingflagconfigname, canvasembeddingflagconfigname, elementpredictionflagconfigname", - [ - [ - "data", - "job", - "bart", - "text_element_embedding_flag_config/wofontsize", - "canvas_embedding_flag_config/canvas_detail_given", - "text_element_prediction_flag_config/rawfontsize", - ], - ], -) -def test_flag_config_train( - data_dir: str, - save_dir: str, - config_name: str, - elementembeddingflagconfigname: str, - canvasembeddingflagconfigname: str, - elementpredictionflagconfigname, -) -> None: - global_config_input = {} - global_config_input["data_dir"] = data_dir - global_config_input["model_name"] = config_name - global_config_input["test_config_name"] = "test_config" - global_config_input["model_config_name"] = "model_config" - global_config_input[ - "elementembeddingflag_config_name" - ] = elementembeddingflagconfigname - global_config_input[ - "canvasembeddingflag_config_name" - ] = canvasembeddingflagconfigname - global_config_input[ - "elementpredictionflag_config_name" - ] = elementpredictionflagconfigname - - config = get_global_config(**global_config_input) - model_name, model_kwargs = get_model_config_input(config) - - model = create_model( - model_name, - **model_kwargs, - ) - prefix_list_object = get_prefix_lists(config) - font_config = get_font_config(config) - prediction_config_element = config.text_element_prediction_attribute_config - optimizer_option = config.train_config.optimizer - - dataset, dataset_val = build_train_dataset( - data_dir, - prefix_list_object, - font_config, - debug=True, - ) - - gpu = False - trainer = Trainer( - model, - False, - save_dir, - dataset, - dataset_val, - prefix_list_object, - prediction_config_element, - optimizer_option=optimizer_option, - debug=True, - epochs=1, - ) - trainer.train_model()