From da36c557f763cb4e515f71ba7c49191fede8966f Mon Sep 17 00:00:00 2001 From: NielsRogge <48327001+NielsRogge@users.noreply.github.com> Date: Thu, 18 Nov 2021 16:24:34 +0100 Subject: [PATCH] Add ImageGPT (#14240) * First draft * More improvements * Improve conversion script * Fix init weights for layer norm * Fix correct model for conversion script * Don't tie input and output embeddings * Add print statements for debugging * Add print statements for debugging * Fix vocab size of model * Improve documentation, remove fast tokenizer * Add ImageGPTForImageClassification, improve docs * Fix docs issue * Set verbosity level back to info * Improve tests * Fix tests and add figure * Delete tokenizer file * Remove ImageGPTTokenizer from init files * Remove ImageGPTLayer from init files * Remove ImageGPT tokenizer from docs * First draft of ImageGPTFeatureExtractor * Fix typo * Fix bug * More improvements * Apply suggestions from code review, add tests for feature extractor * Fix layernorm * Update save_pretrained method * Fix issue * Make all tests of ImageGPTFeatureExtractor pass * Update code examples * Rename model inputs to pixel_values * Improve code examples * Update init_weights to post_init * Fix post_init --- README.md | 1 + README_ko.md | 1 + README_zh-hans.md | 1 + README_zh-hant.md | 1 + docs/source/imgs/ImageGPT.png | Bin 0 -> 181424 bytes docs/source/index.rst | 94 +- docs/source/model_doc/imagegpt.rst | 110 ++ src/transformers/__init__.py | 22 + src/transformers/feature_extraction_utils.py | 8 +- src/transformers/models/__init__.py | 1 + .../models/auto/configuration_auto.py | 3 + src/transformers/models/auto/modeling_auto.py | 3 + src/transformers/models/imagegpt/__init__.py | 61 + .../models/imagegpt/configuration_imagegpt.py | 142 ++ ...onvert_imagegpt_original_tf2_to_pytorch.py | 73 ++ .../imagegpt/feature_extraction_imagegpt.py | 176 +++ .../models/imagegpt/modeling_imagegpt.py | 1159 +++++++++++++++++ src/transformers/utils/dummy_pt_objects.py | 48 + .../utils/dummy_vision_objects.py | 5 + tests/test_feature_extraction_imagegpt.py | 177 +++ tests/test_modeling_imagegpt.py | 498 +++++++ utils/check_repo.py | 1 + 22 files changed, 2540 insertions(+), 45 deletions(-) create mode 100644 docs/source/imgs/ImageGPT.png create mode 100644 docs/source/model_doc/imagegpt.rst create mode 100644 src/transformers/models/imagegpt/__init__.py create mode 100644 src/transformers/models/imagegpt/configuration_imagegpt.py create mode 100644 src/transformers/models/imagegpt/convert_imagegpt_original_tf2_to_pytorch.py create mode 100644 src/transformers/models/imagegpt/feature_extraction_imagegpt.py create mode 100755 src/transformers/models/imagegpt/modeling_imagegpt.py create mode 100644 tests/test_feature_extraction_imagegpt.py create mode 100644 tests/test_modeling_imagegpt.py diff --git a/README.md b/README.md index 4a3be48850..bc926907d2 100644 --- a/README.md +++ b/README.md @@ -249,6 +249,7 @@ Min, Patrick Lewis, Ledell Wu, Sergey Edunov, Danqi Chen, and Wen-tau Yih. 1. **[GPT Neo](https://huggingface.co/transformers/model_doc/gpt_neo.html)** (from EleutherAI) released in the repository [EleutherAI/gpt-neo](https://github.com/EleutherAI/gpt-neo) by Sid Black, Stella Biderman, Leo Gao, Phil Wang and Connor Leahy. 1. **[Hubert](https://huggingface.co/transformers/model_doc/hubert.html)** (from Facebook) released with the paper [HuBERT: Self-Supervised Speech Representation Learning by Masked Prediction of Hidden Units](https://arxiv.org/abs/2106.07447) by Wei-Ning Hsu, Benjamin Bolte, Yao-Hung Hubert Tsai, Kushal Lakhotia, Ruslan Salakhutdinov, Abdelrahman Mohamed. 1. **[I-BERT](https://huggingface.co/transformers/model_doc/ibert.html)** (from Berkeley) released with the paper [I-BERT: Integer-only BERT Quantization](https://arxiv.org/abs/2101.01321) by Sehoon Kim, Amir Gholami, Zhewei Yao, Michael W. Mahoney, Kurt Keutzer. +1. **[ImageGPT](https://huggingface.co/transformers/master/model_doc/imagegpt.html)** (from OpenAI) released with the paper [Generative Pretraining from Pixes](https://openai.com/blog/image-gpt/) by Mark Chen, Alec Radford, Rewon Child, Jeffrey Wu, Heewoo Jun, David Luan, Ilya Sutskever. 1. **[LayoutLM](https://huggingface.co/transformers/model_doc/layoutlm.html)** (from Microsoft Research Asia) released with the paper [LayoutLM: Pre-training of Text and Layout for Document Image Understanding](https://arxiv.org/abs/1912.13318) by Yiheng Xu, Minghao Li, Lei Cui, Shaohan Huang, Furu Wei, Ming Zhou. 1. **[LayoutLMv2](https://huggingface.co/transformers/model_doc/layoutlmv2.html)** (from Microsoft Research Asia) released with the paper [LayoutLMv2: Multi-modal Pre-training for Visually-Rich Document Understanding](https://arxiv.org/abs/2012.14740) by Yang Xu, Yiheng Xu, Tengchao Lv, Lei Cui, Furu Wei, Guoxin Wang, Yijuan Lu, Dinei Florencio, Cha Zhang, Wanxiang Che, Min Zhang, Lidong Zhou. 1. **[LayoutXLM](https://huggingface.co/transformers/model_doc/layoutlmv2.html)** (from Microsoft Research Asia) released with the paper [LayoutXLM: Multimodal Pre-training for Multilingual Visually-rich Document Understanding](https://arxiv.org/abs/2104.08836) by Yiheng Xu, Tengchao Lv, Lei Cui, Guoxin Wang, Yijuan Lu, Dinei Florencio, Cha Zhang, Furu Wei. diff --git a/README_ko.md b/README_ko.md index 11bfa0e061..48a443dbac 100644 --- a/README_ko.md +++ b/README_ko.md @@ -247,6 +247,7 @@ Flax, PyTorch, TensorFlow 설치 페이지에서 이들을 conda로 설치하는 1. **[GPT-J](https://huggingface.co/transformers/model_doc/gptj.html)** (from EleutherAI) released in the repository [kingoflolz/mesh-transformer-jax](https://github.com/kingoflolz/mesh-transformer-jax/) by Ben Wang and Aran Komatsuzaki. 1. **[Hubert](https://huggingface.co/transformers/model_doc/hubert.html)** (from Facebook) released with the paper [HuBERT: Self-Supervised Speech Representation Learning by Masked Prediction of Hidden Units](https://arxiv.org/abs/2106.07447) by Wei-Ning Hsu, Benjamin Bolte, Yao-Hung Hubert Tsai, Kushal Lakhotia, Ruslan Salakhutdinov, Abdelrahman Mohamed. 1. **[I-BERT](https://huggingface.co/transformers/model_doc/ibert.html)** (from Berkeley) released with the paper [I-BERT: Integer-only BERT Quantization](https://arxiv.org/abs/2101.01321) by Sehoon Kim, Amir Gholami, Zhewei Yao, Michael W. Mahoney, Kurt Keutzer. +1. **[ImageGPT](https://huggingface.co/transformers/master/model_doc/imagegpt.html)** (from OpenAI) released with the paper [Generative Pretraining from Pixes](https://openai.com/blog/image-gpt/) by Mark Chen, Alec Radford, Rewon Child, Jeffrey Wu, Heewoo Jun, David Luan, Ilya Sutskever. 1. **[LayoutLM](https://huggingface.co/transformers/model_doc/layoutlm.html)** (from Microsoft Research Asia) released with the paper [LayoutLM: Pre-training of Text and Layout for Document Image Understanding](https://arxiv.org/abs/1912.13318) by Yiheng Xu, Minghao Li, Lei Cui, Shaohan Huang, Furu Wei, Ming Zhou. 1. **[LayoutLMv2](https://huggingface.co/transformers/model_doc/layoutlmv2.html)** (from Microsoft Research Asia) released with the paper [LayoutLMv2: Multi-modal Pre-training for Visually-Rich Document Understanding](https://arxiv.org/abs/2012.14740) by Yang Xu, Yiheng Xu, Tengchao Lv, Lei Cui, Furu Wei, Guoxin Wang, Yijuan Lu, Dinei Florencio, Cha Zhang, Wanxiang Che, Min Zhang, Lidong Zhou. 1. **[LayoutXLM](https://huggingface.co/transformers/model_doc/layoutlmv2.html)** (from Microsoft Research Asia) released with the paper [LayoutXLM: Multimodal Pre-training for Multilingual Visually-rich Document Understanding](https://arxiv.org/abs/2104.08836) by Yiheng Xu, Tengchao Lv, Lei Cui, Guoxin Wang, Yijuan Lu, Dinei Florencio, Cha Zhang, Furu Wei. diff --git a/README_zh-hans.md b/README_zh-hans.md index d46bcbc1ef..150e8e62b3 100644 --- a/README_zh-hans.md +++ b/README_zh-hans.md @@ -271,6 +271,7 @@ conda install -c huggingface transformers 1. **[GPT-J](https://huggingface.co/transformers/model_doc/gptj.html)** (来自 EleutherAI) 伴随论文 [kingoflolz/mesh-transformer-jax](https://github.com/kingoflolz/mesh-transformer-jax/) 由 Ben Wang and Aran Komatsuzaki 发布。 1. **[Hubert](https://huggingface.co/transformers/model_doc/hubert.html)** (来自 Facebook) 伴随论文 [HuBERT: Self-Supervised Speech Representation Learning by Masked Prediction of Hidden Units](https://arxiv.org/abs/2106.07447) 由 Wei-Ning Hsu, Benjamin Bolte, Yao-Hung Hubert Tsai, Kushal Lakhotia, Ruslan Salakhutdinov, Abdelrahman Mohamed 发布。 1. **[I-BERT](https://huggingface.co/transformers/model_doc/ibert.html)** (来自 Berkeley) 伴随论文 [I-BERT: Integer-only BERT Quantization](https://arxiv.org/abs/2101.01321) 由 Sehoon Kim, Amir Gholami, Zhewei Yao, Michael W. Mahoney, Kurt Keutzer 发布。 +1. **[ImageGPT](https://huggingface.co/transformers/master/model_doc/imagegpt.html)** (来自 OpenAI) 伴随论文 [Generative Pretraining from Pixes](https://openai.com/blog/image-gpt/) 由 Mark Chen, Alec Radford, Rewon Child, Jeffrey Wu, Heewoo Jun, David Luan, Ilya Sutskever 发布。 1. **[LayoutLM](https://huggingface.co/transformers/model_doc/layoutlm.html)** (来自 Microsoft Research Asia) 伴随论文 [LayoutLM: Pre-training of Text and Layout for Document Image Understanding](https://arxiv.org/abs/1912.13318) 由 Yiheng Xu, Minghao Li, Lei Cui, Shaohan Huang, Furu Wei, Ming Zhou 发布。 1. **[LayoutLMv2](https://huggingface.co/transformers/model_doc/layoutlmv2.html)** (来自 Microsoft Research Asia) 伴随论文 [LayoutLMv2: Multi-modal Pre-training for Visually-Rich Document Understanding](https://arxiv.org/abs/2012.14740) 由 Yang Xu, Yiheng Xu, Tengchao Lv, Lei Cui, Furu Wei, Guoxin Wang, Yijuan Lu, Dinei Florencio, Cha Zhang, Wanxiang Che, Min Zhang, Lidong Zhou 发布。 1. **[LayoutXLM](https://huggingface.co/transformers/model_doc/layoutlmv2.html)** (来自 Microsoft Research Asia) 伴随论文 [LayoutXLM: Multimodal Pre-training for Multilingual Visually-rich Document Understanding](https://arxiv.org/abs/2104.08836) 由 Yiheng Xu, Tengchao Lv, Lei Cui, Guoxin Wang, Yijuan Lu, Dinei Florencio, Cha Zhang, Furu Wei 发布。 diff --git a/README_zh-hant.md b/README_zh-hant.md index 0728f8764d..5e5f29dfac 100644 --- a/README_zh-hant.md +++ b/README_zh-hant.md @@ -283,6 +283,7 @@ conda install -c huggingface transformers 1. **[GPT-J](https://huggingface.co/transformers/model_doc/gptj.html)** (from EleutherAI) released with the paper [kingoflolz/mesh-transformer-jax](https://github.com/kingoflolz/mesh-transformer-jax/) by Ben Wang and Aran Komatsuzaki. 1. **[Hubert](https://huggingface.co/transformers/model_doc/hubert.html)** (from Facebook) released with the paper [HuBERT: Self-Supervised Speech Representation Learning by Masked Prediction of Hidden Units](https://arxiv.org/abs/2106.07447) by Wei-Ning Hsu, Benjamin Bolte, Yao-Hung Hubert Tsai, Kushal Lakhotia, Ruslan Salakhutdinov, Abdelrahman Mohamed. 1. **[I-BERT](https://huggingface.co/transformers/model_doc/ibert.html)** (from Berkeley) released with the paper [I-BERT: Integer-only BERT Quantization](https://arxiv.org/abs/2101.01321) by Sehoon Kim, Amir Gholami, Zhewei Yao, Michael W. Mahoney, Kurt Keutzer. +1. **[ImageGPT](https://huggingface.co/transformers/master/model_doc/imagegpt.html)** (from OpenAI) released with the paper [Generative Pretraining from Pixes](https://openai.com/blog/image-gpt/) by Mark Chen, Alec Radford, Rewon Child, Jeffrey Wu, Heewoo Jun, David Luan, Ilya Sutskever. 1. **[LayoutLM](https://huggingface.co/transformers/model_doc/layoutlm.html)** (from Microsoft Research Asia) released with the paper [LayoutLM: Pre-training of Text and Layout for Document Image Understanding](https://arxiv.org/abs/1912.13318) by Yiheng Xu, Minghao Li, Lei Cui, Shaohan Huang, Furu Wei, Ming Zhou. 1. **[LayoutLMv2](https://huggingface.co/transformers/model_doc/layoutlmv2.html)** (from Microsoft Research Asia) released with the paper [LayoutLMv2: Multi-modal Pre-training for Visually-Rich Document Understanding](https://arxiv.org/abs/2012.14740) by Yang Xu, Yiheng Xu, Tengchao Lv, Lei Cui, Furu Wei, Guoxin Wang, Yijuan Lu, Dinei Florencio, Cha Zhang, Wanxiang Che, Min Zhang, Lidong Zhou. 1. **[LayoutXLM](https://huggingface.co/transformers/model_doc/layoutlmv2.html)** (from Microsoft Research Asia) released with the paper [LayoutXLM: Multimodal Pre-training for Multilingual Visually-rich Document Understanding](https://arxiv.org/abs/2104.08836) by Yiheng Xu, Tengchao Lv, Lei Cui, Guoxin Wang, Yijuan Lu, Dinei Florencio, Cha Zhang, Furu Wei. diff --git a/docs/source/imgs/ImageGPT.png b/docs/source/imgs/ImageGPT.png new file mode 100644 index 0000000000000000000000000000000000000000..87b21ba622ab8cfe88983f7adadbbf3f532e9a0a GIT binary patch literal 181424 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 literal 0 HcmV?d00001 diff --git a/docs/source/index.rst b/docs/source/index.rst index cea20ecf7f..5b621e9be3 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -213,139 +213,142 @@ Supported models Benjamin Bolte, Yao-Hung Hubert Tsai, Kushal Lakhotia, Ruslan Salakhutdinov, Abdelrahman Mohamed. 38. :doc:`I-BERT ` (from Berkeley) released with the paper `I-BERT: Integer-only BERT Quantization `__ by Sehoon Kim, Amir Gholami, Zhewei Yao, Michael W. Mahoney, Kurt Keutzer. -39. :doc:`LayoutLM ` (from Microsoft Research Asia) released with the paper `LayoutLM: Pre-training +39. `ImageGPT `__ (from OpenAI) released with the + paper `Generative Pretraining from Pixes `__ by Mark Chen, Alec Radford, Rewon + Child, Jeffrey Wu, Heewoo Jun, David Luan, Ilya Sutskever. +40. :doc:`LayoutLM ` (from Microsoft Research Asia) released with the paper `LayoutLM: Pre-training of Text and Layout for Document Image Understanding `__ by Yiheng Xu, Minghao Li, Lei Cui, Shaohan Huang, Furu Wei, Ming Zhou. -40. :doc:`LayoutLMv2 ` (from Microsoft Research Asia) released with the paper `LayoutLMv2: +41. :doc:`LayoutLMv2 ` (from Microsoft Research Asia) released with the paper `LayoutLMv2: Multi-modal Pre-training for Visually-Rich Document Understanding `__ by Yang Xu, Yiheng Xu, Tengchao Lv, Lei Cui, Furu Wei, Guoxin Wang, Yijuan Lu, Dinei Florencio, Cha Zhang, Wanxiang Che, Min Zhang, Lidong Zhou. -41. :doc:`LayoutXLM ` (from Microsoft Research Asia) released with the paper `LayoutXLM: +42. :doc:`LayoutXLM ` (from Microsoft Research Asia) released with the paper `LayoutXLM: Multimodal Pre-training for Multilingual Visually-rich Document Understanding `__ by Yiheng Xu, Tengchao Lv, Lei Cui, Guoxin Wang, Yijuan Lu, Dinei Florencio, Cha Zhang, Furu Wei. -42. :doc:`LED ` (from AllenAI) released with the paper `Longformer: The Long-Document Transformer +43. :doc:`LED ` (from AllenAI) released with the paper `Longformer: The Long-Document Transformer `__ by Iz Beltagy, Matthew E. Peters, Arman Cohan. -43. :doc:`Longformer ` (from AllenAI) released with the paper `Longformer: The Long-Document +44. :doc:`Longformer ` (from AllenAI) released with the paper `Longformer: The Long-Document Transformer `__ by Iz Beltagy, Matthew E. Peters, Arman Cohan. -44. :doc:`LUKE ` (from Studio Ousia) released with the paper `LUKE: Deep Contextualized Entity +45. :doc:`LUKE ` (from Studio Ousia) released with the paper `LUKE: Deep Contextualized Entity Representations with Entity-aware Self-attention `__ by Ikuya Yamada, Akari Asai, Hiroyuki Shindo, Hideaki Takeda, Yuji Matsumoto. -45. :doc:`LXMERT ` (from UNC Chapel Hill) released with the paper `LXMERT: Learning Cross-Modality +46. :doc:`LXMERT ` (from UNC Chapel Hill) released with the paper `LXMERT: Learning Cross-Modality Encoder Representations from Transformers for Open-Domain Question Answering `__ by Hao Tan and Mohit Bansal. -46. :doc:`M2M100 ` (from Facebook) released with the paper `Beyond English-Centric Multilingual +47. :doc:`M2M100 ` (from Facebook) released with the paper `Beyond English-Centric Multilingual Machine Translation `__ by Angela Fan, Shruti Bhosale, Holger Schwenk, Zhiyi Ma, Ahmed El-Kishky, Siddharth Goyal, Mandeep Baines, Onur Celebi, Guillaume Wenzek, Vishrav Chaudhary, Naman Goyal, Tom Birch, Vitaliy Liptchinsky, Sergey Edunov, Edouard Grave, Michael Auli, Armand Joulin. -47. :doc:`MarianMT ` Machine translation models trained using `OPUS `__ data by +48. :doc:`MarianMT ` Machine translation models trained using `OPUS `__ data by Jörg Tiedemann. The `Marian Framework `__ is being developed by the Microsoft Translator Team. -48. :doc:`MBart ` (from Facebook) released with the paper `Multilingual Denoising Pre-training for +49. :doc:`MBart ` (from Facebook) released with the paper `Multilingual Denoising Pre-training for Neural Machine Translation `__ by Yinhan Liu, Jiatao Gu, Naman Goyal, Xian Li, Sergey Edunov, Marjan Ghazvininejad, Mike Lewis, Luke Zettlemoyer. -49. :doc:`MBart-50 ` (from Facebook) released with the paper `Multilingual Translation with Extensible +50. :doc:`MBart-50 ` (from Facebook) released with the paper `Multilingual Translation with Extensible Multilingual Pretraining and Finetuning `__ by Yuqing Tang, Chau Tran, Xian Li, Peng-Jen Chen, Naman Goyal, Vishrav Chaudhary, Jiatao Gu, Angela Fan. -50. :doc:`Megatron-BERT ` (from NVIDIA) released with the paper `Megatron-LM: Training +51. :doc:`Megatron-BERT ` (from NVIDIA) released with the paper `Megatron-LM: Training Multi-Billion Parameter Language Models Using Model Parallelism `__ by Mohammad Shoeybi, Mostofa Patwary, Raul Puri, Patrick LeGresley, Jared Casper and Bryan Catanzaro. -51. :doc:`Megatron-GPT2 ` (from NVIDIA) released with the paper `Megatron-LM: Training +52. :doc:`Megatron-GPT2 ` (from NVIDIA) released with the paper `Megatron-LM: Training Multi-Billion Parameter Language Models Using Model Parallelism `__ by Mohammad Shoeybi, Mostofa Patwary, Raul Puri, Patrick LeGresley, Jared Casper and Bryan Catanzaro. -52. :doc:`MPNet ` (from Microsoft Research) released with the paper `MPNet: Masked and Permuted +53. :doc:`MPNet ` (from Microsoft Research) released with the paper `MPNet: Masked and Permuted Pre-training for Language Understanding `__ by Kaitao Song, Xu Tan, Tao Qin, Jianfeng Lu, Tie-Yan Liu. -53. :doc:`MT5 ` (from Google AI) released with the paper `mT5: A massively multilingual pre-trained +54. :doc:`MT5 ` (from Google AI) released with the paper `mT5: A massively multilingual pre-trained text-to-text transformer `__ by Linting Xue, Noah Constant, Adam Roberts, Mihir Kale, Rami Al-Rfou, Aditya Siddhant, Aditya Barua, Colin Raffel. -54. :doc:`Pegasus ` (from Google) released with the paper `PEGASUS: Pre-training with Extracted +55. :doc:`Pegasus ` (from Google) released with the paper `PEGASUS: Pre-training with Extracted Gap-sentences for Abstractive Summarization `__ by Jingqing Zhang, Yao Zhao, Mohammad Saleh and Peter J. Liu. -55. :doc:`PhoBERT ` (from VinAI Research) released with the paper `PhoBERT: Pre-trained language +56. :doc:`PhoBERT ` (from VinAI Research) released with the paper `PhoBERT: Pre-trained language models for Vietnamese `__ by Dat Quoc Nguyen and Anh Tuan Nguyen. -56. :doc:`ProphetNet ` (from Microsoft Research) released with the paper `ProphetNet: Predicting +57. :doc:`ProphetNet ` (from Microsoft Research) released with the paper `ProphetNet: Predicting Future N-gram for Sequence-to-Sequence Pre-training `__ by Yu Yan, Weizhen Qi, Yeyun Gong, Dayiheng Liu, Nan Duan, Jiusheng Chen, Ruofei Zhang and Ming Zhou. -57. :doc:`Reformer ` (from Google Research) released with the paper `Reformer: The Efficient +58. :doc:`Reformer ` (from Google Research) released with the paper `Reformer: The Efficient Transformer `__ by Nikita Kitaev, Łukasz Kaiser, Anselm Levskaya. -58. :doc:`RemBERT ` (from Google Research) released with the paper `Rethinking embedding coupling in +59. :doc:`RemBERT ` (from Google Research) released with the paper `Rethinking embedding coupling in pre-trained language models `__ by Hyung Won Chung, Thibault Févry, Henry Tsai, M. Johnson, Sebastian Ruder. -59. :doc:`RoBERTa ` (from Facebook), released together with the paper a `Robustly Optimized BERT +60. :doc:`RoBERTa ` (from Facebook), released together with the paper a `Robustly Optimized BERT Pretraining Approach `__ by Yinhan Liu, Myle Ott, Naman Goyal, Jingfei Du, Mandar Joshi, Danqi Chen, Omer Levy, Mike Lewis, Luke Zettlemoyer, Veselin Stoyanov. -60. :doc:`RoFormer ` (from ZhuiyiTechnology), released together with the paper a `RoFormer: +61. :doc:`RoFormer ` (from ZhuiyiTechnology), released together with the paper a `RoFormer: Enhanced Transformer with Rotary Position Embedding `__ by Jianlin Su and Yu Lu and Shengfeng Pan and Bo Wen and Yunfeng Liu. -61. :doc:`SegFormer ` (from NVIDIA) released with the paper `SegFormer: Simple and Efficient +62. :doc:`SegFormer ` (from NVIDIA) released with the paper `SegFormer: Simple and Efficient Design for Semantic Segmentation with Transformers `__ by Enze Xie, Wenhai Wang, Zhiding Yu, Anima Anandkumar, Jose M. Alvarez, Ping Luo. -62. :doc:`SEW ` (from ASAPP) released with the paper `Performance-Efficiency Trade-offs in Unsupervised +63. :doc:`SEW ` (from ASAPP) released with the paper `Performance-Efficiency Trade-offs in Unsupervised Pre-training for Speech Recognition `__ by Felix Wu, Kwangyoun Kim, Jing Pan, Kyu Han, Kilian Q. Weinberger, Yoav Artzi. -63. :doc:`SEW-D ` (from ASAPP) released with the paper `Performance-Efficiency Trade-offs in +64. :doc:`SEW-D ` (from ASAPP) released with the paper `Performance-Efficiency Trade-offs in Unsupervised Pre-training for Speech Recognition `__ by Felix Wu, Kwangyoun Kim, Jing Pan, Kyu Han, Kilian Q. Weinberger, Yoav Artzi. -64. :doc:`SpeechToTextTransformer ` (from Facebook), released together with the paper +65. :doc:`SpeechToTextTransformer ` (from Facebook), released together with the paper `fairseq S2T: Fast Speech-to-Text Modeling with fairseq `__ by Changhan Wang, Yun Tang, Xutai Ma, Anne Wu, Dmytro Okhonko, Juan Pino. -65. :doc:`SpeechToTextTransformer2 ` (from Facebook), released together with the paper +66. :doc:`SpeechToTextTransformer2 ` (from Facebook), released together with the paper `Large-Scale Self- and Semi-Supervised Learning for Speech Translation `__ by Changhan Wang, Anne Wu, Juan Pino, Alexei Baevski, Michael Auli, Alexis Conneau. -66. :doc:`Splinter ` (from Tel Aviv University), released together with the paper `Few-Shot +67. :doc:`Splinter ` (from Tel Aviv University), released together with the paper `Few-Shot Question Answering by Pretraining Span Selection `__ by Ori Ram, Yuval Kirstain, Jonathan Berant, Amir Globerson, Omer Levy. -67. :doc:`SqueezeBert ` (from Berkeley) released with the paper `SqueezeBERT: What can computer +68. :doc:`SqueezeBert ` (from Berkeley) released with the paper `SqueezeBERT: What can computer vision teach NLP about efficient neural networks? `__ by Forrest N. Iandola, Albert E. Shaw, Ravi Krishna, and Kurt W. Keutzer. -68. :doc:`T5 ` (from Google AI) released with the paper `Exploring the Limits of Transfer Learning with a +69. :doc:`T5 ` (from Google AI) released with the paper `Exploring the Limits of Transfer Learning with a Unified Text-to-Text Transformer `__ by Colin Raffel and Noam Shazeer and Adam Roberts and Katherine Lee and Sharan Narang and Michael Matena and Yanqi Zhou and Wei Li and Peter J. Liu. -69. :doc:`T5v1.1 ` (from Google AI) released in the repository +70. :doc:`T5v1.1 ` (from Google AI) released in the repository `google-research/text-to-text-transfer-transformer `__ by Colin Raffel and Noam Shazeer and Adam Roberts and Katherine Lee and Sharan Narang and Michael Matena and Yanqi Zhou and Wei Li and Peter J. Liu. -70. :doc:`TAPAS ` (from Google AI) released with the paper `TAPAS: Weakly Supervised Table Parsing via +71. :doc:`TAPAS ` (from Google AI) released with the paper `TAPAS: Weakly Supervised Table Parsing via Pre-training `__ by Jonathan Herzig, Paweł Krzysztof Nowak, Thomas Müller, Francesco Piccinno and Julian Martin Eisenschlos. -71. :doc:`Transformer-XL ` (from Google/CMU) released with the paper `Transformer-XL: +72. :doc:`Transformer-XL ` (from Google/CMU) released with the paper `Transformer-XL: Attentive Language Models Beyond a Fixed-Length Context `__ by Zihang Dai*, Zhilin Yang*, Yiming Yang, Jaime Carbonell, Quoc V. Le, Ruslan Salakhutdinov. -72. :doc:`TrOCR ` (from Microsoft), released together with the paper `TrOCR: Transformer-based Optical +73. :doc:`TrOCR ` (from Microsoft), released together with the paper `TrOCR: Transformer-based Optical Character Recognition with Pre-trained Models `__ by Minghao Li, Tengchao Lv, Lei Cui, Yijuan Lu, Dinei Florencio, Cha Zhang, Zhoujun Li, Furu Wei. -73. :doc:`UniSpeech ` (from Microsoft Research) released with the paper `UniSpeech: Unified Speech +74. :doc:`UniSpeech ` (from Microsoft Research) released with the paper `UniSpeech: Unified Speech Representation Learning with Labeled and Unlabeled Data `__ by Chengyi Wang, Yu Wu, Yao Qian, Kenichi Kumatani, Shujie Liu, Furu Wei, Michael Zeng, Xuedong Huang. -74. :doc:`UniSpeechSat ` (from Microsoft Research) released with the paper `UNISPEECH-SAT: +75. :doc:`UniSpeechSat ` (from Microsoft Research) released with the paper `UNISPEECH-SAT: UNIVERSAL SPEECH REPRESENTATION LEARNING WITH SPEAKER AWARE PRE-TRAINING `__ by Sanyuan Chen, Yu Wu, Chengyi Wang, Zhengyang Chen, Zhuo Chen, Shujie Liu, Jian Wu, Yao Qian, Furu Wei, Jinyu Li, Xiangzhan Yu. -75. :doc:`Vision Transformer (ViT) ` (from Google AI) released with the paper `An Image is Worth 16x16 +76. :doc:`Vision Transformer (ViT) ` (from Google AI) released with the paper `An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale `__ by Alexey Dosovitskiy, Lucas Beyer, Alexander Kolesnikov, Dirk Weissenborn, Xiaohua Zhai, Thomas Unterthiner, Mostafa Dehghani, Matthias Minderer, Georg Heigold, Sylvain Gelly, Jakob Uszkoreit, Neil Houlsby. -76. :doc:`VisualBERT ` (from UCLA NLP) released with the paper `VisualBERT: A Simple and +77. :doc:`VisualBERT ` (from UCLA NLP) released with the paper `VisualBERT: A Simple and Performant Baseline for Vision and Language `__ by Liunian Harold Li, Mark Yatskar, Da Yin, Cho-Jui Hsieh, Kai-Wei Chang. -77. :doc:`Wav2Vec2 ` (from Facebook AI) released with the paper `wav2vec 2.0: A Framework for +78. :doc:`Wav2Vec2 ` (from Facebook AI) released with the paper `wav2vec 2.0: A Framework for Self-Supervised Learning of Speech Representations `__ by Alexei Baevski, Henry Zhou, Abdelrahman Mohamed, Michael Auli. -78. :doc:`XLM ` (from Facebook) released together with the paper `Cross-lingual Language Model +79. :doc:`XLM ` (from Facebook) released together with the paper `Cross-lingual Language Model Pretraining `__ by Guillaume Lample and Alexis Conneau. -79. :doc:`XLM-ProphetNet ` (from Microsoft Research) released with the paper `ProphetNet: +80. :doc:`XLM-ProphetNet ` (from Microsoft Research) released with the paper `ProphetNet: Predicting Future N-gram for Sequence-to-Sequence Pre-training `__ by Yu Yan, Weizhen Qi, Yeyun Gong, Dayiheng Liu, Nan Duan, Jiusheng Chen, Ruofei Zhang and Ming Zhou. -80. :doc:`XLM-RoBERTa ` (from Facebook AI), released together with the paper `Unsupervised +81. :doc:`XLM-RoBERTa ` (from Facebook AI), released together with the paper `Unsupervised Cross-lingual Representation Learning at Scale `__ by Alexis Conneau*, Kartikay Khandelwal*, Naman Goyal, Vishrav Chaudhary, Guillaume Wenzek, Francisco Guzmán, Edouard Grave, Myle Ott, Luke Zettlemoyer and Veselin Stoyanov. -81. :doc:`XLNet ` (from Google/CMU) released with the paper `​XLNet: Generalized Autoregressive +82. :doc:`XLNet ` (from Google/CMU) released with the paper `​XLNet: Generalized Autoregressive Pretraining for Language Understanding `__ by Zhilin Yang*, Zihang Dai*, Yiming Yang, Jaime Carbonell, Ruslan Salakhutdinov, Quoc V. Le. -82. :doc:`XLSR-Wav2Vec2 ` (from Facebook AI) released with the paper `Unsupervised +83. :doc:`XLSR-Wav2Vec2 ` (from Facebook AI) released with the paper `Unsupervised Cross-Lingual Representation Learning For Speech Recognition `__ by Alexis Conneau, Alexei Baevski, Ronan Collobert, Abdelrahman Mohamed, Michael Auli. @@ -425,6 +428,8 @@ Flax), PyTorch, and/or TensorFlow. +-----------------------------+----------------+----------------+-----------------+--------------------+--------------+ | I-BERT | ❌ | ❌ | ✅ | ❌ | ❌ | +-----------------------------+----------------+----------------+-----------------+--------------------+--------------+ +| ImageGPT | ❌ | ❌ | ✅ | ❌ | ❌ | ++-----------------------------+----------------+----------------+-----------------+--------------------+--------------+ | LayoutLM | ✅ | ✅ | ✅ | ✅ | ❌ | +-----------------------------+----------------+----------------+-----------------+--------------------+--------------+ | LayoutLMv2 | ✅ | ✅ | ✅ | ❌ | ❌ | @@ -629,6 +634,7 @@ Flax), PyTorch, and/or TensorFlow. model_doc/funnel model_doc/herbert model_doc/ibert + model_doc/imagegpt model_doc/layoutlm model_doc/layoutlmv2 model_doc/layoutxlm diff --git a/docs/source/model_doc/imagegpt.rst b/docs/source/model_doc/imagegpt.rst new file mode 100644 index 0000000000..2f332aa645 --- /dev/null +++ b/docs/source/model_doc/imagegpt.rst @@ -0,0 +1,110 @@ +.. + Copyright 2021 The HuggingFace Team. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + specific language governing permissions and limitations under the License. + +ImageGPT +----------------------------------------------------------------------------------------------------------------------- + +Overview +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ImageGPT model was proposed in `Generative Pretraining from Pixels `__ by Mark +Chen, Alec Radford, Rewon Child, Jeffrey Wu, Heewoo Jun, David Luan, Ilya Sutskever. ImageGPT (iGPT) is a GPT-2-like +model trained to predict the next pixel value, allowing for both unconditional and conditional image generation. + +The abstract from the paper is the following: + +*Inspired by progress in unsupervised representation learning for natural language, we examine whether similar models +can learn useful representations for images. We train a sequence Transformer to auto-regressively predict pixels, +without incorporating knowledge of the 2D input structure. Despite training on low-resolution ImageNet without labels, +we find that a GPT-2 scale model learns strong image representations as measured by linear probing, fine-tuning, and +low-data classification. On CIFAR-10, we achieve 96.3% accuracy with a linear probe, outperforming a supervised Wide +ResNet, and 99.0% accuracy with full fine-tuning, matching the top supervised pre-trained models. We are also +competitive with self-supervised benchmarks on ImageNet when substituting pixels for a VQVAE encoding, achieving 69.0% +top-1 accuracy on a linear probe of our features.* + +The figure below summarizes the approach (taken from the `original paper +`__): + +.. image:: https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/imagegpt_architecture.png + :width: 600 + +Tips: + +- ImageGPT is almost exactly the same as :doc:`GPT-2 `, with the exception that a different activation function + is used (namely "quick gelu"), and the layer normalization layers don't mean center the inputs. ImageGPT also doesn't + have tied input- and output embeddings. +- As the time- and memory requirements of the attention mechanism of Transformers scales quadratically in the sequence + length, the authors pre-trained ImageGPT on smaller input resolutions, such as 32x32 and 64x64. However, feeding a + sequence of 32x32x3=3072 tokens from 0..255 into a Transformer is still prohibitively large. Therefore, the authors + applied k-means clustering to the (R,G,B) pixel values with k=512. This way, we only have a 32*32 = 1024-long + sequence, but now of integers in the range 0..511. So we are shrinking the sequence length at the cost of a bigger + embedding matrix. In other words, the vocabulary size of ImageGPT is 512, + 1 for a special "start of sentence" (SOS) + token, used at the beginning of every sequence. One can use :class:`~transformers.ImageGPTFeatureExtractor` to + prepare images for the model. +- Despite being pre-trained entirely unsupervised (i.e. without the use of any labels), ImageGPT produces fairly + performant image features useful for downstream tasks, such as image classification. The authors showed that the + features in the middle of the network are the most performant, and can be used as-is to train a linear model (such as + a sklearn logistic regression model for example). This is also referred to as "linear probing". Features can be + easily obtained by first forwarding the image through the model, then specifying `output_hidden_states=True`, and + then average-pool the hidden states at whatever layer you like. +- Alternatively, one can further fine-tune the entire model on a downstream dataset, similar to BERT. For this, you can + use :class:`~transformers.ImageGPTForImageClassification`. +- ImageGPT comes in different sizes: there's ImageGPT-small, ImageGPT-medium and ImageGPT-large. The authors did also + train an XL variant, which they didn't release. The differences in size are summarized in the following table: + ++-------------------+----------------------+-----------------+---------------------+--------------+ +| **Model variant** | **Number of layers** | **Hidden size** | **Number of heads** | **# params** | ++-------------------+----------------------+-----------------+---------------------+--------------+ +| iGPT-small | 24 | 512 | 8 | 76 million | ++-------------------+----------------------+-----------------+---------------------+--------------+ +| iGPT-medium | 36 | 1024 | 8 | 455 million | ++-------------------+----------------------+-----------------+---------------------+--------------+ +| iGPT-large | 48 | 1536 | 16 | 1.4 million | ++-------------------+----------------------+-----------------+---------------------+--------------+ +| iGPT-XL | 60 | 3072 | not specified | 6.8 billion | ++-------------------+----------------------+-----------------+---------------------+--------------+ + +This model was contributed by `nielsr `__, based on `this issue +`__. The original code can be found `here +`__. + +ImageGPTConfig +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autoclass:: transformers.ImageGPTConfig + :members: + +ImageGPTFeatureExtractor +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autoclass:: transformers.ImageGPTFeatureExtractor + :members: __call__ + +ImageGPTModel +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autoclass:: transformers.ImageGPTModel + :members: forward + + +ImageGPTForCausalLM +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autoclass:: transformers.ImageGPTForCausalLM + :members: forward + + +ImageGPTForImageClassification +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autoclass:: transformers.ImageGPTForImageClassification + :members: forward diff --git a/src/transformers/__init__.py b/src/transformers/__init__.py index 6af1df7469..09b8d37466 100755 --- a/src/transformers/__init__.py +++ b/src/transformers/__init__.py @@ -221,6 +221,7 @@ _import_structure = { "models.herbert": ["HerbertTokenizer"], "models.hubert": ["HUBERT_PRETRAINED_CONFIG_ARCHIVE_MAP", "HubertConfig"], "models.ibert": ["IBERT_PRETRAINED_CONFIG_ARCHIVE_MAP", "IBertConfig"], + "models.imagegpt": ["IMAGEGPT_PRETRAINED_CONFIG_ARCHIVE_MAP", "ImageGPTConfig"], "models.layoutlm": ["LAYOUTLM_PRETRAINED_CONFIG_ARCHIVE_MAP", "LayoutLMConfig", "LayoutLMTokenizer"], "models.layoutlmv2": [ "LAYOUTLMV2_PRETRAINED_CONFIG_ARCHIVE_MAP", @@ -478,6 +479,7 @@ if is_vision_available(): _import_structure["models.clip"].append("CLIPProcessor") _import_structure["models.deit"].append("DeiTFeatureExtractor") _import_structure["models.detr"].append("DetrFeatureExtractor") + _import_structure["models.imagegpt"].append("ImageGPTFeatureExtractor") _import_structure["models.layoutlmv2"].append("LayoutLMv2FeatureExtractor") _import_structure["models.layoutlmv2"].append("LayoutLMv2Processor") _import_structure["models.layoutxlm"].append("LayoutXLMProcessor") @@ -943,6 +945,16 @@ if is_torch_available(): "IBertPreTrainedModel", ] ) + _import_structure["models.imagegpt"].extend( + [ + "IMAGEGPT_PRETRAINED_MODEL_ARCHIVE_LIST", + "ImageGPTForCausalLM", + "ImageGPTForImageClassification", + "ImageGPTModel", + "ImageGPTPreTrainedModel", + "load_tf_weights_in_imagegpt", + ] + ) _import_structure["models.layoutlm"].extend( [ "LAYOUTLM_PRETRAINED_MODEL_ARCHIVE_LIST", @@ -2150,6 +2162,7 @@ if TYPE_CHECKING: from .models.herbert import HerbertTokenizer from .models.hubert import HUBERT_PRETRAINED_CONFIG_ARCHIVE_MAP, HubertConfig from .models.ibert import IBERT_PRETRAINED_CONFIG_ARCHIVE_MAP, IBertConfig + from .models.imagegpt import IMAGEGPT_PRETRAINED_CONFIG_ARCHIVE_MAP, ImageGPTConfig from .models.layoutlm import LAYOUTLM_PRETRAINED_CONFIG_ARCHIVE_MAP, LayoutLMConfig, LayoutLMTokenizer from .models.layoutlmv2 import ( LAYOUTLMV2_PRETRAINED_CONFIG_ARCHIVE_MAP, @@ -2369,6 +2382,7 @@ if TYPE_CHECKING: from .models.clip import CLIPFeatureExtractor, CLIPProcessor from .models.deit import DeiTFeatureExtractor from .models.detr import DetrFeatureExtractor + from .models.imagegpt import ImageGPTFeatureExtractor from .models.layoutlmv2 import LayoutLMv2FeatureExtractor, LayoutLMv2Processor from .models.layoutxlm import LayoutXLMProcessor from .models.segformer import SegformerFeatureExtractor @@ -2756,6 +2770,14 @@ if TYPE_CHECKING: IBertModel, IBertPreTrainedModel, ) + from .models.imagegpt import ( + IMAGEGPT_PRETRAINED_MODEL_ARCHIVE_LIST, + ImageGPTForCausalLM, + ImageGPTForImageClassification, + ImageGPTModel, + ImageGPTPreTrainedModel, + load_tf_weights_in_imagegpt, + ) from .models.layoutlm import ( LAYOUTLM_PRETRAINED_MODEL_ARCHIVE_LIST, LayoutLMForMaskedLM, diff --git a/src/transformers/feature_extraction_utils.py b/src/transformers/feature_extraction_utils.py index adc4a8afb1..fd616b59cf 100644 --- a/src/transformers/feature_extraction_utils.py +++ b/src/transformers/feature_extraction_utils.py @@ -470,7 +470,13 @@ class FeatureExtractionMixin: :obj:`str`: String containing all the attributes that make up this feature_extractor instance in JSON format. """ - return json.dumps(self.to_dict(), indent=2, sort_keys=True) + "\n" + dictionary = self.to_dict() + + for key, value in dictionary.items(): + if isinstance(value, np.ndarray): + dictionary[key] = value.tolist() + + return json.dumps(dictionary, indent=2, sort_keys=True) + "\n" def to_json_file(self, json_file_path: Union[str, os.PathLike]): """ diff --git a/src/transformers/models/__init__.py b/src/transformers/models/__init__.py index e166cd2e70..e103d3056d 100644 --- a/src/transformers/models/__init__.py +++ b/src/transformers/models/__init__.py @@ -57,6 +57,7 @@ from . import ( herbert, hubert, ibert, + imagegpt, layoutlm, layoutlmv2, layoutxlm, diff --git a/src/transformers/models/auto/configuration_auto.py b/src/transformers/models/auto/configuration_auto.py index 06c5bdc226..11223da732 100644 --- a/src/transformers/models/auto/configuration_auto.py +++ b/src/transformers/models/auto/configuration_auto.py @@ -30,6 +30,7 @@ logger = logging.get_logger(__name__) CONFIG_MAPPING_NAMES = OrderedDict( [ # Add configs here + ("imagegpt", "ImageGPTConfig"), ("vision-encoder-decoder", "VisionEncoderDecoderConfig"), ("trocr", "TrOCRConfig"), ("fnet", "FNetConfig"), @@ -111,6 +112,7 @@ CONFIG_MAPPING_NAMES = OrderedDict( CONFIG_ARCHIVE_MAP_MAPPING_NAMES = OrderedDict( [ # Add archive maps here + ("imagegpt", "IMAGEGPT_PRETRAINED_CONFIG_ARCHIVE_MAP"), ("fnet", "FNET_PRETRAINED_CONFIG_ARCHIVE_MAP"), ("pegasus", "PEGASUS_PRETRAINED_CONFIG_ARCHIVE_MAP"), ("segformer", "SEGFORMER_PRETRAINED_CONFIG_ARCHIVE_MAP"), @@ -182,6 +184,7 @@ CONFIG_ARCHIVE_MAP_MAPPING_NAMES = OrderedDict( MODEL_NAMES_MAPPING = OrderedDict( [ # Add full (and cased) model names here + ("imagegpt", "ImageGPT"), ("vision-encoder-decoder", "Vision Encoder decoder"), ("trocr", "TrOCR"), ("fnet", "FNet"), diff --git a/src/transformers/models/auto/modeling_auto.py b/src/transformers/models/auto/modeling_auto.py index dec7fdc164..b2de640a91 100644 --- a/src/transformers/models/auto/modeling_auto.py +++ b/src/transformers/models/auto/modeling_auto.py @@ -28,6 +28,7 @@ logger = logging.get_logger(__name__) MODEL_MAPPING_NAMES = OrderedDict( [ # Base model mapping + ("imagegpt", "ImageGPTModel"), ("fnet", "FNetModel"), ("segformer", "SegformerModel"), ("gptj", "GPTJModel"), @@ -145,6 +146,7 @@ MODEL_FOR_PRETRAINING_MAPPING_NAMES = OrderedDict( MODEL_WITH_LM_HEAD_MAPPING_NAMES = OrderedDict( [ # Model with LM heads mapping + ("imagegpt", "ImageGPTForCausalLM"), ("fnet", "FNetForMaskedLM"), ("gptj", "GPTJForCausalLM"), ("rembert", "RemBertForMaskedLM"), @@ -195,6 +197,7 @@ MODEL_WITH_LM_HEAD_MAPPING_NAMES = OrderedDict( MODEL_FOR_CAUSAL_LM_MAPPING_NAMES = OrderedDict( [ # Model for Causal LM mapping + ("imagegpt", "ImageGPTForCausalLM"), ("trocr", "TrOCRForCausalLM"), ("gptj", "GPTJForCausalLM"), ("rembert", "RemBertForCausalLM"), diff --git a/src/transformers/models/imagegpt/__init__.py b/src/transformers/models/imagegpt/__init__.py new file mode 100644 index 0000000000..16be206d41 --- /dev/null +++ b/src/transformers/models/imagegpt/__init__.py @@ -0,0 +1,61 @@ +# flake8: noqa +# There's no way to ignore "F401 '...' imported but unused" warnings in this +# module, but to preserve other warnings. So, don't check this module at all. + +# Copyright 2020 The HuggingFace Team. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import TYPE_CHECKING + +from ...file_utils import _LazyModule, is_torch_available, is_vision_available + + +_import_structure = { + "configuration_imagegpt": ["IMAGEGPT_PRETRAINED_CONFIG_ARCHIVE_MAP", "ImageGPTConfig"], +} + +if is_vision_available(): + _import_structure["feature_extraction_imagegpt"] = ["ImageGPTFeatureExtractor"] + +if is_torch_available(): + _import_structure["modeling_imagegpt"] = [ + "IMAGEGPT_PRETRAINED_MODEL_ARCHIVE_LIST", + "ImageGPTForCausalLM", + "ImageGPTForImageClassification", + "ImageGPTModel", + "ImageGPTPreTrainedModel", + "load_tf_weights_in_imagegpt", + ] + + +if TYPE_CHECKING: + from .configuration_imagegpt import IMAGEGPT_PRETRAINED_CONFIG_ARCHIVE_MAP, ImageGPTConfig + + if is_vision_available(): + from .feature_extraction_imagegpt import ImageGPTFeatureExtractor + + if is_torch_available(): + from .modeling_imagegpt import ( + IMAGEGPT_PRETRAINED_MODEL_ARCHIVE_LIST, + ImageGPTForCausalLM, + ImageGPTForImageClassification, + ImageGPTModel, + ImageGPTPreTrainedModel, + load_tf_weights_in_imagegpt, + ) + +else: + import sys + + sys.modules[__name__] = _LazyModule(__name__, globals()["__file__"], _import_structure) diff --git a/src/transformers/models/imagegpt/configuration_imagegpt.py b/src/transformers/models/imagegpt/configuration_imagegpt.py new file mode 100644 index 0000000000..5a8d0db144 --- /dev/null +++ b/src/transformers/models/imagegpt/configuration_imagegpt.py @@ -0,0 +1,142 @@ +# coding=utf-8 +# Copyright 2021 The HuggingFace Inc. team. +# +# 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. +""" OpenAI ImageGPT configuration """ + +from ...configuration_utils import PretrainedConfig +from ...utils import logging + + +logger = logging.get_logger(__name__) + +IMAGEGPT_PRETRAINED_CONFIG_ARCHIVE_MAP = { + "openai/imagegpt-small": "", + "openai/imagegpt-medium": "", + "openai/imagegpt-large": "", +} + + +class ImageGPTConfig(PretrainedConfig): + """ + This is the configuration class to store the configuration of a :class:`~transformers.ImageGPTModel` or a + :class:`~transformers.TFImageGPTModel`. It is used to instantiate a GPT-2 model according to the specified + arguments, defining the model architecture. Instantiating a configuration with the defaults will yield a similar + configuration to that of the ImageGPT `small `__ architecture. + + Configuration objects inherit from :class:`~transformers.PretrainedConfig` and can be used to control the model + outputs. Read the documentation from :class:`~transformers.PretrainedConfig` for more information. + + + Args: + vocab_size (:obj:`int`, `optional`, defaults to 512): + Vocabulary size of the GPT-2 model. Defines the number of different tokens that can be represented by the + :obj:`inputs_ids` passed when calling :class:`~transformers.ImageGPTModel` or + :class:`~transformers.TFImageGPTModel`. + n_positions (:obj:`int`, `optional`, defaults to 32*32): + The maximum sequence length that this model might ever be used with. Typically set this to something large + just in case (e.g., 512 or 1024 or 2048). + n_embd (:obj:`int`, `optional`, defaults to 512): + Dimensionality of the embeddings and hidden states. + n_layer (:obj:`int`, `optional`, defaults to 24): + Number of hidden layers in the Transformer encoder. + n_head (:obj:`int`, `optional`, defaults to 8): + Number of attention heads for each attention layer in the Transformer encoder. + n_inner (:obj:`int`, `optional`, defaults to None): + Dimensionality of the inner feed-forward layers. :obj:`None` will set it to 4 times n_embd + activation_function (:obj:`str`, `optional`, defaults to :obj:`"quick_gelu"`): + Activation function (can be one of the activation functions defined in src/transformers/activations.py). + Defaults to "quick_gelu". + resid_pdrop (:obj:`float`, `optional`, defaults to 0.1): + The dropout probability for all fully connected layers in the embeddings, encoder, and pooler. + embd_pdrop (:obj:`int`, `optional`, defaults to 0.1): + The dropout ratio for the embeddings. + attn_pdrop (:obj:`float`, `optional`, defaults to 0.1): + The dropout ratio for the attention. + layer_norm_epsilon (:obj:`float`, `optional`, defaults to 1e-5): + The epsilon to use in the layer normalization layers. + initializer_range (:obj:`float`, `optional`, defaults to 0.02): + The standard deviation of the truncated_normal_initializer for initializing all weight matrices. + scale_attn_weights (:obj:`bool`, `optional`, defaults to :obj:`True`): + Scale attention weights by dividing by sqrt(hidden_size).. + use_cache (:obj:`bool`, `optional`, defaults to :obj:`True`): + Whether or not the model should return the last key/values attentions (not used by all models). + scale_attn_by_inverse_layer_idx (:obj:`bool`, `optional`, defaults to :obj:`False`): + Whether to additionally scale attention weights by ``1 / layer_idx + 1``. + reorder_and_upcast_attn (:obj:`bool`, `optional`, defaults to :obj:`False`): + Whether to scale keys (K) prior to computing attention (dot-product) and upcast attention + dot-product/softmax to float() when training with mixed precision. + + Example:: + + >>> from transformers import ImageGPTModel, ImageGPTConfig + + >>> # Initializing a ImageGPT configuration + >>> configuration = ImageGPTConfig() + + >>> # Initializing a model from the configuration + >>> model = ImageGPTModel(configuration) + + >>> # Accessing the model configuration + >>> configuration = model.config + """ + + model_type = "imagegpt" + keys_to_ignore_at_inference = ["past_key_values"] + attribute_map = { + "hidden_size": "n_embd", + "max_position_embeddings": "n_positions", + "num_attention_heads": "n_head", + "num_hidden_layers": "n_layer", + } + + def __init__( + self, + vocab_size=512 + 1, # add one for start of sentence (sos) token + n_positions=32 * 32, + n_embd=512, + n_layer=24, + n_head=8, + n_inner=None, + activation_function="quick_gelu", + resid_pdrop=0.1, + embd_pdrop=0.1, + attn_pdrop=0.1, + layer_norm_epsilon=1e-5, + initializer_range=0.02, + scale_attn_weights=True, + use_cache=True, + tie_word_embeddings=False, + scale_attn_by_inverse_layer_idx=False, + reorder_and_upcast_attn=False, + **kwargs, + ): + self.vocab_size = vocab_size + self.n_positions = n_positions + self.n_embd = n_embd + self.n_layer = n_layer + self.n_head = n_head + self.n_inner = n_inner + self.activation_function = activation_function + self.resid_pdrop = resid_pdrop + self.embd_pdrop = embd_pdrop + self.attn_pdrop = attn_pdrop + self.layer_norm_epsilon = layer_norm_epsilon + self.initializer_range = initializer_range + self.scale_attn_weights = scale_attn_weights + self.use_cache = use_cache + self.scale_attn_by_inverse_layer_idx = scale_attn_by_inverse_layer_idx + self.reorder_and_upcast_attn = reorder_and_upcast_attn + self.tie_word_embeddings = tie_word_embeddings + + super().__init__(tie_word_embeddings=tie_word_embeddings, **kwargs) diff --git a/src/transformers/models/imagegpt/convert_imagegpt_original_tf2_to_pytorch.py b/src/transformers/models/imagegpt/convert_imagegpt_original_tf2_to_pytorch.py new file mode 100644 index 0000000000..7fb6813f7a --- /dev/null +++ b/src/transformers/models/imagegpt/convert_imagegpt_original_tf2_to_pytorch.py @@ -0,0 +1,73 @@ +# coding=utf-8 +# Copyright 2021 The HuggingFace Inc. team. +# +# 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. +"""Convert OpenAI Image GPT checkpoints.""" + + +import argparse + +import torch + +from transformers import ImageGPTConfig, ImageGPTForCausalLM, load_tf_weights_in_imagegpt +from transformers.file_utils import CONFIG_NAME, WEIGHTS_NAME +from transformers.utils import logging + + +logging.set_verbosity_info() + + +def convert_imagegpt_checkpoint_to_pytorch(imagegpt_checkpoint_path, model_size, pytorch_dump_folder_path): + # Construct configuration depending on size + MODELS = {"small": (512, 8, 24), "medium": (1024, 8, 36), "large": (1536, 16, 48)} + n_embd, n_head, n_layer = MODELS[model_size] # set model hyperparameters + config = ImageGPTConfig(n_embd=n_embd, n_layer=n_layer, n_head=n_head) + model = ImageGPTForCausalLM(config) + + # Load weights from numpy + load_tf_weights_in_imagegpt(model, config, imagegpt_checkpoint_path) + + # Save pytorch-model + pytorch_weights_dump_path = pytorch_dump_folder_path + "/" + WEIGHTS_NAME + pytorch_config_dump_path = pytorch_dump_folder_path + "/" + CONFIG_NAME + print(f"Save PyTorch model to {pytorch_weights_dump_path}") + torch.save(model.state_dict(), pytorch_weights_dump_path) + print(f"Save configuration file to {pytorch_config_dump_path}") + with open(pytorch_config_dump_path, "w", encoding="utf-8") as f: + f.write(config.to_json_string()) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + # Required parameters + parser.add_argument( + "--imagegpt_checkpoint_path", + default=None, + type=str, + required=True, + help="Path to the TensorFlow checkpoint path.", + ) + parser.add_argument( + "--model_size", + default=None, + type=str, + required=True, + help="Size of the model (can be either 'small', 'medium' or 'large').", + ) + parser.add_argument( + "--pytorch_dump_folder_path", default=None, type=str, required=True, help="Path to the output PyTorch model." + ) + args = parser.parse_args() + convert_imagegpt_checkpoint_to_pytorch( + args.imagegpt_checkpoint_path, args.model_size, args.pytorch_dump_folder_path + ) diff --git a/src/transformers/models/imagegpt/feature_extraction_imagegpt.py b/src/transformers/models/imagegpt/feature_extraction_imagegpt.py new file mode 100644 index 0000000000..85aec8a634 --- /dev/null +++ b/src/transformers/models/imagegpt/feature_extraction_imagegpt.py @@ -0,0 +1,176 @@ +# coding=utf-8 +# Copyright 2021 The HuggingFace Inc. team. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Feature extractor class for ImageGPT.""" + +from typing import List, Optional, Union + +import numpy as np +from PIL import Image + +from ...feature_extraction_utils import BatchFeature, FeatureExtractionMixin +from ...file_utils import TensorType +from ...image_utils import ImageFeatureExtractionMixin, is_torch_tensor +from ...utils import logging + + +logger = logging.get_logger(__name__) + + +def squared_euclidean_distance(a, b): + b = b.T + a2 = np.sum(np.square(a), axis=1) + b2 = np.sum(np.square(b), axis=0) + ab = np.matmul(a, b) + d = a2[:, None] - 2 * ab + b2[None, :] + return d + + +def color_quantize(x, clusters): + x = x.reshape(-1, 3) + d = squared_euclidean_distance(x, clusters) + return np.argmin(d, axis=1) + + +class ImageGPTFeatureExtractor(FeatureExtractionMixin, ImageFeatureExtractionMixin): + r""" + Constructs an ImageGPT feature extractor. This feature extractor can be used to resize images to a smaller + resolution (such as 32x32 or 64x64), normalize them and finally color quantize them to obtain sequences of "pixel + values" (color clusters). + + This feature extractor inherits from :class:`~transformers.FeatureExtractionMixin` which contains most of the main + methods. Users should refer to this superclass for more information regarding those methods. + + Args: + clusters (:obj:`np.ndarray`): + The color clusters to use, as a :obj:`np.ndarray` of shape :obj:`(n_clusters, 3)`. + do_resize (:obj:`bool`, `optional`, defaults to :obj:`True`): + Whether to resize the input to a certain :obj:`size`. + size (:obj:`int` or :obj:`Tuple(int)`, `optional`, defaults to 32): + Resize the input to the given size. If a tuple is provided, it should be (width, height). If only an + integer is provided, then the input will be resized to (size, size). Only has an effect if :obj:`do_resize` + is set to :obj:`True`. + resample (:obj:`int`, `optional`, defaults to :obj:`PIL.Image.BILINEAR`): + An optional resampling filter. This can be one of :obj:`PIL.Image.NEAREST`, :obj:`PIL.Image.BOX`, + :obj:`PIL.Image.BILINEAR`, :obj:`PIL.Image.HAMMING`, :obj:`PIL.Image.BICUBIC` or :obj:`PIL.Image.LANCZOS`. + Only has an effect if :obj:`do_resize` is set to :obj:`True`. + do_normalize (:obj:`bool`, `optional`, defaults to :obj:`True`): + Whether or not to normalize the input to the range between -1 and +1. + """ + + model_input_names = ["pixel_values"] + + def __init__(self, clusters, do_resize=True, size=32, resample=Image.BILINEAR, do_normalize=True, **kwargs): + super().__init__(**kwargs) + self.clusters = np.asarray(clusters) + self.do_resize = do_resize + self.size = size + self.resample = resample + self.do_normalize = do_normalize + + def normalize(self, image): + """ + Normalizes :obj:`image` into the range -1 to +1. + + Args: + image (:obj:`PIL.Image.Image` or :obj:`np.ndarray` or :obj:`torch.Tensor`): + The image to normalize. + + Returns: + :obj:`np.ndarray`: The normalized image. + """ + image = self.to_numpy_array(image, rescale=False, channel_first=False) + + return image / 127.5 - 1 + + def __call__( + self, + images: Union[ + Image.Image, np.ndarray, "torch.Tensor", List[Image.Image], List[np.ndarray], List["torch.Tensor"] # noqa + ], + return_tensors: Optional[Union[str, TensorType]] = None, + **kwargs + ) -> BatchFeature: + """ + Main method to prepare for the model one or several image(s). + + .. warning:: + + NumPy arrays and PyTorch tensors are converted to PIL images when resizing, so the most efficient is to pass + PIL images. + + Args: + images (:obj:`PIL.Image.Image`, :obj:`np.ndarray`, :obj:`torch.Tensor`, :obj:`List[PIL.Image.Image]`, :obj:`List[np.ndarray]`, :obj:`List[torch.Tensor]`): + The image or batch of images to be prepared. Each image can be a PIL image, NumPy array or PyTorch + tensor. In case of a NumPy array/PyTorch tensor, each image should be of shape (C, H, W), where C is a + number of channels, H and W are image height and width. + + return_tensors (:obj:`str` or :class:`~transformers.file_utils.TensorType`, `optional`, defaults to :obj:`'np'`): + If set, will return tensors of a particular framework. Acceptable values are: + + * :obj:`'tf'`: Return TensorFlow :obj:`tf.constant` objects. + * :obj:`'pt'`: Return PyTorch :obj:`torch.Tensor` objects. + * :obj:`'np'`: Return NumPy :obj:`np.ndarray` objects. + * :obj:`'jax'`: Return JAX :obj:`jnp.ndarray` objects. + + Returns: + :class:`~transformers.BatchFeature`: A :class:`~transformers.BatchFeature` with the following fields: + + - **pixel_values** -- Pixel values to be fed to a model, of shape (batch_size, num_channels, height, + width). + """ + # Input type checking for clearer error + valid_images = False + + # Check that images has a valid type + if isinstance(images, (Image.Image, np.ndarray)) or is_torch_tensor(images): + valid_images = True + elif isinstance(images, (list, tuple)): + if len(images) == 0 or isinstance(images[0], (Image.Image, np.ndarray)) or is_torch_tensor(images[0]): + valid_images = True + + if not valid_images: + raise ValueError( + "Images must of type `PIL.Image.Image`, `np.ndarray` or `torch.Tensor` (single example), " + "`List[PIL.Image.Image]`, `List[np.ndarray]` or `List[torch.Tensor]` (batch of examples)." + ) + + is_batched = bool( + isinstance(images, (list, tuple)) + and (isinstance(images[0], (Image.Image, np.ndarray)) or is_torch_tensor(images[0])) + ) + + if not is_batched: + images = [images] + + # transformations (resizing + normalization) + if self.do_resize and self.size is not None: + images = [self.resize(image, size=self.size, resample=self.resample) for image in images] + + if self.do_normalize: + images = [self.normalize(image) for image in images] + + # color quantize from (batch_size, height, width, 3) to (batch_size, height, width) + images = np.array(images) + images = color_quantize(images, self.clusters).reshape(images.shape[:-1]) + + # flatten to (batch_size, height*width) + batch_size = images.shape[0] + images = images.reshape(batch_size, -1) + + # return as BatchFeature + data = {"pixel_values": images} + encoded_inputs = BatchFeature(data=data, tensor_type=return_tensors) + + return encoded_inputs diff --git a/src/transformers/models/imagegpt/modeling_imagegpt.py b/src/transformers/models/imagegpt/modeling_imagegpt.py new file mode 100755 index 0000000000..6f3a3c3c2a --- /dev/null +++ b/src/transformers/models/imagegpt/modeling_imagegpt.py @@ -0,0 +1,1159 @@ +# coding=utf-8 +# Copyright 2021 The OpenAI Team Authors and HuggingFace Inc. team. +# +# 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. +"""PyTorch OpenAI ImageGPT model.""" + +import math +import os +from typing import Tuple + +import torch +import torch.utils.checkpoint +from packaging import version +from torch import nn +from torch.nn import BCEWithLogitsLoss, CrossEntropyLoss, MSELoss + + +if version.parse(torch.__version__) >= version.parse("1.6"): + is_amp_available = True + from torch.cuda.amp import autocast +else: + is_amp_available = False + +from ...activations import ACT2FN +from ...file_utils import add_start_docstrings, add_start_docstrings_to_model_forward, replace_return_docstrings +from ...modeling_outputs import ( + BaseModelOutputWithPastAndCrossAttentions, + CausalLMOutputWithCrossAttentions, + SequenceClassifierOutputWithPast, +) +from ...modeling_utils import Conv1D, PreTrainedModel, find_pruneable_heads_and_indices, prune_conv1d_layer +from ...utils import logging +from .configuration_imagegpt import ImageGPTConfig + + +logger = logging.get_logger(__name__) + +_CHECKPOINT_FOR_DOC = "openai/imagegpt-small" +_CONFIG_FOR_DOC = "ImageGPTConfig" +_TOKENIZER_FOR_DOC = "ImageGPTTokenizer" + +IMAGEGPT_PRETRAINED_MODEL_ARCHIVE_LIST = [ + "openai/imagegpt-small", + "openai/imagegpt-medium", + "openai/imagegpt-large", + # See all Image GPT models at https://huggingface.co/models?filter=imagegpt +] + + +def load_tf_weights_in_imagegpt(model, config, imagegpt_checkpoint_path): + """ + Load tf checkpoints in a pytorch model + """ + try: + import re + + import tensorflow as tf + except ImportError: + logger.error( + "Loading a TensorFlow model in PyTorch, requires TensorFlow to be installed. Please see " + "https://www.tensorflow.org/install/ for installation instructions." + ) + raise + tf_path = os.path.abspath(imagegpt_checkpoint_path) + logger.info("Converting TensorFlow checkpoint from {}".format(tf_path)) + # Load weights from TF model + init_vars = tf.train.list_variables(tf_path) + names = [] + arrays = [] + + for name, shape in init_vars: + logger.info("Loading TF weight {} with shape {}".format(name, shape)) + array = tf.train.load_variable(tf_path, name) + names.append(name) + arrays.append(array.squeeze()) + + for name, array in zip(names, arrays): + name = name[6:] # skip "model/" + name = name.split("/") + + # adam_v and adam_m are variables used in AdamWeightDecayOptimizer to calculated m and v + # which are not required for using pretrained model + if any( + n in ["adam_v", "adam_m", "AdamWeightDecayOptimizer", "AdamWeightDecayOptimizer_1", "global_step"] + for n in name + ) or name[-1] in ["_step"]: + logger.info("Skipping {}".format("/".join(name))) + continue + + pointer = model + if name[-1] not in ["wtet"]: + pointer = getattr(pointer, "transformer") + + for m_name in name: + if re.fullmatch(r"[A-Za-z]+\d+", m_name): + scope_names = re.split(r"(\d+)", m_name) + else: + scope_names = [m_name] + + if scope_names[0] == "w" or scope_names[0] == "g": + pointer = getattr(pointer, "weight") + elif scope_names[0] == "b": + pointer = getattr(pointer, "bias") + elif scope_names[0] == "wpe" or scope_names[0] == "wte": + pointer = getattr(pointer, scope_names[0]) + pointer = getattr(pointer, "weight") + elif scope_names[0] in ["q_proj", "k_proj", "v_proj"]: + pointer = getattr(pointer, "c_attn") + pointer = getattr(pointer, "weight") + elif len(name) == 3 and name[1] == "attn" and scope_names[0] == "c_proj": + pointer = getattr(pointer, scope_names[0]) + pointer = getattr(pointer, "weight") + elif scope_names[0] == "wtet": + pointer = getattr(pointer, "lm_head") + pointer = getattr(pointer, "weight") + elif scope_names[0] == "sos": + pointer = getattr(pointer, "wte") + pointer = getattr(pointer, "weight") + else: + pointer = getattr(pointer, scope_names[0]) + if len(scope_names) >= 2: + num = int(scope_names[1]) + pointer = pointer[num] + + if len(name) > 1 and name[1] == "attn" or name[-1] == "wtet" or name[-1] == "sos" or name[-1] == "wte": + pass # array is used to initialize only part of the pointer so sizes won't match + else: + try: + assert pointer.shape == array.shape + except AssertionError as e: + e.args += (pointer.shape, array.shape) + raise + + logger.info("Initialize PyTorch weight {}".format(name)) + + if name[-1] == "q_proj": + pointer.data[:, : config.n_embd] = torch.from_numpy(array.reshape(config.n_embd, config.n_embd)).T + elif name[-1] == "k_proj": + pointer.data[:, config.n_embd : 2 * config.n_embd] = torch.from_numpy( + array.reshape(config.n_embd, config.n_embd) + ).T + elif name[-1] == "v_proj": + pointer.data[:, 2 * config.n_embd :] = torch.from_numpy(array.reshape(config.n_embd, config.n_embd)).T + elif len(name) == 3 and name[1] == "attn" and name[2] == "c_proj": + pointer.data = torch.from_numpy(array.reshape(config.n_embd, config.n_embd)) + elif name[-1] == "wtet": + pointer.data = torch.from_numpy(array) + elif name[-1] == "wte": + pointer.data[: config.vocab_size - 1, :] = torch.from_numpy(array) + elif name[-1] == "sos": + pointer.data[-1] = torch.from_numpy(array) + else: + pointer.data = torch.from_numpy(array) + + return model + + +class ImageGPTLayerNorm(nn.Module): + def __init__(self, hidden_size, eps=1e-5): + super().__init__() + self.eps = eps + self.weight = nn.Parameter(torch.Tensor(hidden_size)) + + def forward(self, tensor): + # input is not mean centered + return ( + tensor + / torch.sqrt(torch.mean(torch.square(tensor), axis=-1, keepdim=True) + self.eps) + * self.weight.data[..., :] + ) + + +class ImageGPTAttention(nn.Module): + def __init__(self, config, is_cross_attention=False, layer_idx=None): + super().__init__() + + max_positions = config.max_position_embeddings + self.register_buffer( + "bias", + torch.tril(torch.ones((max_positions, max_positions), dtype=torch.uint8)).view( + 1, 1, max_positions, max_positions + ), + ) + self.register_buffer("masked_bias", torch.tensor(-1e4)) + + self.embed_dim = config.hidden_size + self.num_heads = config.num_attention_heads + self.head_dim = self.embed_dim // self.num_heads + self.split_size = self.embed_dim + if self.head_dim * self.num_heads != self.embed_dim: + raise ValueError( + f"`embed_dim` must be divisible by num_heads (got `embed_dim`: {self.embed_dim} and `num_heads`: {self.num_heads})." + ) + + self.scale_attn_weights = config.scale_attn_weights + self.is_cross_attention = is_cross_attention + + # Layer-wise attention scaling, reordering, and upcasting + self.scale_attn_by_inverse_layer_idx = config.scale_attn_by_inverse_layer_idx + self.layer_idx = layer_idx + self.reorder_and_upcast_attn = config.reorder_and_upcast_attn + + if self.is_cross_attention: + self.c_attn = Conv1D(2 * self.embed_dim, self.embed_dim) + self.q_attn = Conv1D(self.embed_dim, self.embed_dim) + else: + self.c_attn = Conv1D(3 * self.embed_dim, self.embed_dim) + self.c_proj = Conv1D(self.embed_dim, self.embed_dim) + + self.attn_dropout = nn.Dropout(config.attn_pdrop) + self.resid_dropout = nn.Dropout(config.resid_pdrop) + + self.pruned_heads = set() + + def prune_heads(self, heads): + if len(heads) == 0: + return + heads, index = find_pruneable_heads_and_indices(heads, self.num_heads, self.head_dim, self.pruned_heads) + index_attn = torch.cat([index, index + self.split_size, index + (2 * self.split_size)]) + + # Prune conv1d layers + self.c_attn = prune_conv1d_layer(self.c_attn, index_attn, dim=1) + self.c_proj = prune_conv1d_layer(self.c_proj, index, dim=0) + + # Update hyper params + self.split_size = (self.split_size // self.num_heads) * (self.num_heads - len(heads)) + self.num_heads = self.num_heads - len(heads) + self.pruned_heads = self.pruned_heads.union(heads) + + def _attn(self, query, key, value, attention_mask=None, head_mask=None): + attn_weights = torch.matmul(query, key.transpose(-1, -2)) + + if self.scale_attn_weights: + attn_weights = attn_weights / (float(value.size(-1)) ** 0.5) + + # Layer-wise attention scaling + if self.scale_attn_by_inverse_layer_idx: + attn_weights = attn_weights / float(self.layer_idx + 1) + + if not self.is_cross_attention: + # if only "normal" attention layer implements causal mask + query_length, key_length = query.size(-2), key.size(-2) + causal_mask = self.bias[:, :, key_length - query_length : key_length, :key_length].bool() + attn_weights = torch.where(causal_mask, attn_weights, self.masked_bias.to(attn_weights.dtype)) + + if attention_mask is not None: + # Apply the attention mask + attn_weights = attn_weights + attention_mask + + attn_weights = nn.Softmax(dim=-1)(attn_weights) + + # Downcast (if necessary) back to V's dtype (if in mixed-precision) -- No-Op otherwise + attn_weights = attn_weights.type(value.dtype) + attn_weights = self.attn_dropout(attn_weights) + + # Mask heads if we want to + if head_mask is not None: + attn_weights = attn_weights * head_mask + + attn_output = torch.matmul(attn_weights, value) + + return attn_output, attn_weights + + def _upcast_and_reordered_attn(self, query, key, value, attention_mask=None, head_mask=None): + # Use `torch.baddbmm` (a bit more efficient w/ alpha param for scaling -- from Megatron-LM) + bsz, num_heads, q_seq_len, dk = query.size() + _, _, k_seq_len, _ = key.size() + + # Preallocate attn_weights for `baddbmm` + attn_weights = torch.empty(bsz * num_heads, q_seq_len, k_seq_len, dtype=torch.float32, device=query.device) + + # Compute Scale Factor + scale_factor = 1.0 + if self.scale_attn_weights: + scale_factor /= float(value.size(-1)) ** 0.5 + + if self.scale_attn_by_inverse_layer_idx: + scale_factor /= float(self.layer_idx + 1) + + # Upcast (turn off autocast) and reorder (Scale K by 1 / root(dk)) + if is_amp_available: + with autocast(enabled=False): + q, k = query.reshape(-1, q_seq_len, dk), key.transpose(-1, -2).reshape(-1, dk, k_seq_len) + attn_weights = torch.baddbmm(attn_weights, q.float(), k.float(), beta=0, alpha=scale_factor) + attn_weights = attn_weights.reshape(bsz, num_heads, q_seq_len, k_seq_len) + else: + q, k = query.reshape(-1, q_seq_len, dk), key.transpose(-1, -2).reshape(-1, dk, k_seq_len) + attn_weights = torch.baddbmm(attn_weights, q.float(), k.float(), beta=0, alpha=scale_factor) + attn_weights = attn_weights.reshape(bsz, num_heads, q_seq_len, k_seq_len) + + if not self.is_cross_attention: + # if only "normal" attention layer implements causal mask + query_length, key_length = query.size(-2), key.size(-2) + causal_mask = self.bias[:, :, key_length - query_length : key_length, :key_length].bool() + attn_weights = torch.where(causal_mask, attn_weights, self.masked_bias.to(attn_weights.dtype)) + + if attention_mask is not None: + # Apply the attention mask + attn_weights = attn_weights + attention_mask + + attn_weights = nn.Softmax(dim=-1)(attn_weights) + + # Downcast (if necessary) back to V's dtype (if in mixed-precision) -- No-Op if otherwise + if attn_weights.dtype != torch.float32: + raise RuntimeError("Error with upcasting, attn_weights does not have dtype torch.float32") + attn_weights = attn_weights.type(value.dtype) + attn_weights = self.attn_dropout(attn_weights) + + # Mask heads if we want to + if head_mask is not None: + attn_weights = attn_weights * head_mask + + attn_output = torch.matmul(attn_weights, value) + + return attn_output, attn_weights + + def _split_heads(self, tensor, num_heads, attn_head_size): + """ + Splits hidden_size dim into attn_head_size and num_heads + """ + new_shape = tensor.size()[:-1] + (num_heads, attn_head_size) + tensor = tensor.view(*new_shape) + return tensor.permute(0, 2, 1, 3) # (batch, head, seq_length, head_features) + + def _merge_heads(self, tensor, num_heads, attn_head_size): + """ + Merges attn_head_size dim and num_attn_heads dim into hidden_size + """ + tensor = tensor.permute(0, 2, 1, 3).contiguous() + new_shape = tensor.size()[:-2] + (num_heads * attn_head_size,) + return tensor.view(new_shape) + + def forward( + self, + hidden_states, + layer_past=None, + attention_mask=None, + head_mask=None, + encoder_hidden_states=None, + encoder_attention_mask=None, + use_cache=False, + output_attentions=False, + ): + if encoder_hidden_states is not None: + if not hasattr(self, "q_attn"): + raise ValueError( + "If class is used as cross attention, the weights `q_attn` have to be defined. " + "Please make sure to instantiate class with `ImageGPTAttention(..., is_cross_attention=True)`." + ) + + query = self.q_attn(hidden_states) + key, value = self.c_attn(encoder_hidden_states).split(self.split_size, dim=2) + attention_mask = encoder_attention_mask + else: + query, key, value = self.c_attn(hidden_states).split(self.split_size, dim=2) + + query = self._split_heads(query, self.num_heads, self.head_dim) + key = self._split_heads(key, self.num_heads, self.head_dim) + value = self._split_heads(value, self.num_heads, self.head_dim) + + if layer_past is not None: + past_key, past_value = layer_past + key = torch.cat((past_key, key), dim=-2) + value = torch.cat((past_value, value), dim=-2) + + if use_cache is True: + present = (key, value) + else: + present = None + + if self.reorder_and_upcast_attn: + attn_output, attn_weights = self._upcast_and_reordered_attn(query, key, value, attention_mask, head_mask) + else: + attn_output, attn_weights = self._attn(query, key, value, attention_mask, head_mask) + + attn_output = self._merge_heads(attn_output, self.num_heads, self.head_dim) + attn_output = self.c_proj(attn_output) + attn_output = self.resid_dropout(attn_output) + + outputs = (attn_output, present) + if output_attentions: + outputs += (attn_weights,) + + return outputs # a, present, (attentions) + + +class ImageGPTMLP(nn.Module): + def __init__(self, intermediate_size, config): + super().__init__() + embed_dim = config.hidden_size + self.c_fc = Conv1D(intermediate_size, embed_dim) + self.c_proj = Conv1D(embed_dim, intermediate_size) + self.act = ACT2FN[config.activation_function] + self.dropout = nn.Dropout(config.resid_pdrop) + + def forward(self, hidden_states): + hidden_states = self.c_fc(hidden_states) + hidden_states = self.act(hidden_states) + hidden_states = self.c_proj(hidden_states) + hidden_states = self.dropout(hidden_states) + return hidden_states + + +class ImageGPTBlock(nn.Module): + def __init__(self, config, layer_idx=None): + super().__init__() + hidden_size = config.hidden_size + inner_dim = config.n_inner if config.n_inner is not None else 4 * hidden_size + + self.ln_1 = ImageGPTLayerNorm(hidden_size, eps=config.layer_norm_epsilon) + self.attn = ImageGPTAttention(config, layer_idx=layer_idx) + self.ln_2 = ImageGPTLayerNorm(hidden_size, eps=config.layer_norm_epsilon) + + if config.add_cross_attention: + self.crossattention = ImageGPTAttention(config, is_cross_attention=True) + self.ln_cross_attn = ImageGPTLayerNorm(hidden_size, eps=config.layer_norm_epsilon) + + self.mlp = ImageGPTMLP(inner_dim, config) + + def forward( + self, + hidden_states, + layer_past=None, + attention_mask=None, + head_mask=None, + encoder_hidden_states=None, + encoder_attention_mask=None, + use_cache=False, + output_attentions=False, + ): + residual = hidden_states + hidden_states = self.ln_1(hidden_states) + attn_outputs = self.attn( + hidden_states, + layer_past=layer_past, + attention_mask=attention_mask, + head_mask=head_mask, + use_cache=use_cache, + output_attentions=output_attentions, + ) + attn_output = attn_outputs[0] # output_attn: a, present, (attentions) + outputs = attn_outputs[1:] + # residual connection + hidden_states = attn_output + residual + + if encoder_hidden_states is not None: + # add one self-attention block for cross-attention + if not hasattr(self, "crossattention"): + raise ValueError( + f"If `encoder_hidden_states` are passed, {self} has to be instantiated with " + "cross-attention layers by setting `config.add_cross_attention=True`" + ) + residual = hidden_states + hidden_states = self.ln_cross_attn(hidden_states) + cross_attn_outputs = self.crossattention( + hidden_states, + attention_mask=attention_mask, + head_mask=head_mask, + encoder_hidden_states=encoder_hidden_states, + encoder_attention_mask=encoder_attention_mask, + output_attentions=output_attentions, + ) + attn_output = cross_attn_outputs[0] + # residual connection + hidden_states = residual + attn_output + outputs = outputs + cross_attn_outputs[2:] # add cross attentions if we output attention weights + + residual = hidden_states + hidden_states = self.ln_2(hidden_states) + feed_forward_hidden_states = self.mlp(hidden_states) + # residual connection + hidden_states = residual + feed_forward_hidden_states + + outputs = (hidden_states,) + (outputs if use_cache else outputs[1:]) + + return outputs # hidden_states, present, (attentions, cross_attentions) + + +class ImageGPTPreTrainedModel(PreTrainedModel): + """ + An abstract class to handle weights initialization and a simple interface for downloading and loading pretrained + models. + """ + + config_class = ImageGPTConfig + load_tf_weights = load_tf_weights_in_imagegpt + base_model_prefix = "transformer" + supports_gradient_checkpointing = True + + def __init__(self, *inputs, **kwargs): + super().__init__(*inputs, **kwargs) + + def _init_weights(self, module): + """Initialize the weights.""" + if isinstance(module, (nn.Linear, Conv1D)): + # Slightly different from the TF version which uses truncated_normal for initialization + # cf https://github.com/pytorch/pytorch/pull/5617 + module.weight.data.normal_(mean=0.0, std=self.config.initializer_range) + if module.bias is not None: + module.bias.data.zero_() + elif isinstance(module, nn.Embedding): + module.weight.data.normal_(mean=0.0, std=self.config.initializer_range) + if module.padding_idx is not None: + module.weight.data[module.padding_idx].zero_() + elif isinstance(module, ImageGPTLayerNorm): + module.weight.data.fill_(1.0) + + # Reinitialize selected weights subject to the OpenAI GPT-2 Paper Scheme: + # > A modified initialization which accounts for the accumulation on the residual path with model depth. Scale + # > the weights of residual layers at initialization by a factor of 1/√N where N is the # of residual layers. + # > -- GPT-2 :: https://openai.com/blog/better-language-models/ + # + # Reference (Megatron-LM): https://github.com/NVIDIA/Megatron-LM/blob/main/megatron/model/gpt_model.py + for name, p in module.named_parameters(): + if "c_proj" in name and "weight" in name: + # Special Scaled Initialization --> There are 2 Layer Norms per Transformer Block + p.data.normal_(mean=0.0, std=(self.config.initializer_range / math.sqrt(2 * self.config.n_layer))) + + def _set_gradient_checkpointing(self, module, value=False): + if isinstance(module, ImageGPTModel): + module.gradient_checkpointing = value + + +IMAGEGPT_START_DOCSTRING = r""" + + This model inherits from :class:`~transformers.PreTrainedModel`. Check the superclass documentation for the generic + methods the library implements for all its model (such as downloading or saving, resizing the input embeddings, + pruning heads etc.) + + This model is also a PyTorch `torch.nn.Module `__ + subclass. Use it as a regular PyTorch Module and refer to the PyTorch documentation for all matter related to + general usage and behavior. + + Parameters: + config (:class:`~transformers.ImageGPTConfig`): Model configuration class with all the parameters of the model. + Initializing with a config file does not load the weights associated with the model, only the + configuration. Check out the :meth:`~transformers.PreTrainedModel.from_pretrained` method to load the model + weights. +""" + +IMAGEGPT_INPUTS_DOCSTRING = r""" + Args: + pixel_values (:obj:`torch.LongTensor` of shape :obj:`(batch_size, pixel_values_length)`): + :obj:`pixel_values_length` = ``sequence_length`` if :obj:`past_key_values` is ``None`` else + ``past_key_values[0][0].shape[-2]`` (``sequence_length`` of input past key value states). Indices of input + sequence tokens in the vocabulary. + + If :obj:`past_key_values` is used, only ``pixel_values`` that do not have their past calculated should be + passed as ``pixel_values``. + + Indices can be obtained using :class:`~transformers.ImageGPTFeatureExtractor`. See + :meth:`transformers.ImageGPTFeatureExtractor.__call__` for details. + + past_key_values (:obj:`Tuple[Tuple[torch.Tensor]]` of length :obj:`config.n_layers`): + Contains precomputed hidden-states (key and values in the attention blocks) as computed by the model (see + :obj:`past_key_values` output below). Can be used to speed up sequential decoding. The ``pixel_values`` + which have their past given to this model should not be passed as ``pixel_values`` as they have already + been computed. + attention_mask (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length)`, `optional`): + Mask to avoid performing attention on padding token indices. Mask values selected in ``[0, 1]``: + + - 1 for tokens that are **not masked**, + - 0 for tokens that are **masked**. + + `What are attention masks? <../glossary.html#attention-mask>`__ + token_type_ids (:obj:`torch.LongTensor` of shape :obj:`(batch_size, pixel_values_length)`, `optional`): + Segment token indices to indicate first and second portions of the inputs. Indices are selected in ``[0, + 1]``: + + - 0 corresponds to a `sentence A` token, + - 1 corresponds to a `sentence B` token. + + `What are token type IDs? <../glossary.html#token-type-ids>`_ + position_ids (:obj:`torch.LongTensor` of shape :obj:`(batch_size, sequence_length)`, `optional`): + Indices of positions of each input sequence tokens in the position embeddings. Selected in the range ``[0, + config.max_position_embeddings - 1]``. + + `What are position IDs? <../glossary.html#position-ids>`_ + head_mask (:obj:`torch.FloatTensor` of shape :obj:`(num_heads,)` or :obj:`(num_layers, num_heads)`, `optional`): + Mask to nullify selected heads of the self-attention modules. Mask values selected in ``[0, 1]``: + + - 1 indicates the head is **not masked**, + - 0 indicates the head is **masked**. + + inputs_embeds (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length, hidden_size)`, `optional`): + Optionally, instead of passing :obj:`pixel_values` you can choose to directly pass an embedded + representation. This is useful if you want more control over how to convert :obj:`pixel_values` indices + into associated vectors than the model's internal embedding lookup matrix. + + If :obj:`past_key_values` is used, optionally only the last :obj:`inputs_embeds` have to be input (see + :obj:`past_key_values`). + use_cache (:obj:`bool`, `optional`): + If set to :obj:`True`, :obj:`past_key_values` key value states are returned and can be used to speed up + decoding (see :obj:`past_key_values`). + output_attentions (:obj:`bool`, `optional`): + Whether or not to return the attentions tensors of all attention layers. See ``attentions`` under returned + tensors for more detail. + output_hidden_states (:obj:`bool`, `optional`): + Whether or not to return the hidden states of all layers. See ``hidden_states`` under returned tensors for + more detail. + return_dict (:obj:`bool`, `optional`): + Whether or not to return a :class:`~transformers.file_utils.ModelOutput` instead of a plain tuple. +""" + + +@add_start_docstrings( + "The bare ImageGPT Model transformer outputting raw hidden-states without any specific head on top.", + IMAGEGPT_START_DOCSTRING, +) +class ImageGPTModel(ImageGPTPreTrainedModel): + _keys_to_ignore_on_load_missing = ["attn.masked_bias"] + + def __init__(self, config): + super().__init__(config) + + self.embed_dim = config.hidden_size + + self.wte = nn.Embedding(config.vocab_size, self.embed_dim) + self.wpe = nn.Embedding(config.max_position_embeddings, self.embed_dim) + + self.drop = nn.Dropout(config.embd_pdrop) + self.h = nn.ModuleList([ImageGPTBlock(config, layer_idx=i) for i in range(config.num_hidden_layers)]) + self.ln_f = ImageGPTLayerNorm(self.embed_dim, eps=config.layer_norm_epsilon) + + # Model parallel + self.model_parallel = False + self.device_map = None + self.gradient_checkpointing = False + # Initialize weights and apply final processing + self.post_init() + + def get_input_embeddings(self): + return self.wte + + def set_input_embeddings(self, new_embeddings): + self.wte = new_embeddings + + def _prune_heads(self, heads_to_prune): + """ + Prunes heads of the model. heads_to_prune: dict of {layer_num: list of heads to prune in this layer} + """ + for layer, heads in heads_to_prune.items(): + self.h[layer].attn.prune_heads(heads) + + @add_start_docstrings_to_model_forward(IMAGEGPT_INPUTS_DOCSTRING) + @replace_return_docstrings(output_type=BaseModelOutputWithPastAndCrossAttentions, config_class=_CONFIG_FOR_DOC) + def forward( + self, + pixel_values=None, + past_key_values=None, + attention_mask=None, + token_type_ids=None, + position_ids=None, + head_mask=None, + inputs_embeds=None, + encoder_hidden_states=None, + encoder_attention_mask=None, + use_cache=None, + output_attentions=None, + output_hidden_states=None, + return_dict=None, + ): + r""" + labels (:obj:`torch.LongTensor` of shape :obj:`(batch_size, sequence_length)`, `optional`): + Labels for language modeling. Note that the labels **are shifted** inside the model, i.e. you can set + ``labels = pixel_values`` Indices are selected in ``[-100, 0, ..., config.vocab_size]`` All labels set to + ``-100`` are ignored (masked), the loss is only computed for labels in ``[0, ..., config.vocab_size]`` + + Returns: + + Examples:: + + >>> from transformers import ImageGPTFeatureExtractor, ImageGPTModel + >>> from PIL import Image + >>> import requests + + >>> url = 'http://images.cocodataset.org/val2017/000000039769.jpg' + >>> image = Image.open(requests.get(url, stream=True).raw) + + >>> feature_extractor = ImageGPTFeatureExtractor.from_pretrained('openai/imagegpt-small') + >>> model = ImageGPTModel.from_pretrained('openai/imagegpt-small') + + >>> inputs = feature_extractor(images=image, return_tensors="pt") + >>> outputs = model(**inputs) + >>> last_hidden_states = outputs.last_hidden_state + """ + + output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions + output_hidden_states = ( + output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states + ) + use_cache = use_cache if use_cache is not None else self.config.use_cache + return_dict = return_dict if return_dict is not None else self.config.use_return_dict + + if pixel_values is not None and inputs_embeds is not None: + raise ValueError("You cannot specify both pixel_values and inputs_embeds at the same time") + elif pixel_values is not None: + input_shape = pixel_values.size() + pixel_values = pixel_values.view(-1, input_shape[-1]) + batch_size = pixel_values.shape[0] + elif inputs_embeds is not None: + input_shape = inputs_embeds.size()[:-1] + batch_size = inputs_embeds.shape[0] + else: + raise ValueError("You have to specify either pixel_values or inputs_embeds") + + device = pixel_values.device if pixel_values is not None else inputs_embeds.device + + if token_type_ids is not None: + token_type_ids = token_type_ids.view(-1, input_shape[-1]) + if position_ids is not None: + position_ids = position_ids.view(-1, input_shape[-1]) + + if past_key_values is None: + past_length = 0 + past_key_values = tuple([None] * len(self.h)) + else: + past_length = past_key_values[0][0].size(-2) + if position_ids is None: + position_ids = torch.arange(past_length, input_shape[-1] + past_length, dtype=torch.long, device=device) + position_ids = position_ids.unsqueeze(0).view(-1, input_shape[-1]) + + # ImageGPTAttention mask. + if attention_mask is not None: + if batch_size <= 0: + raise ValueError("batch_size has to be defined and > 0") + attention_mask = attention_mask.view(batch_size, -1) + # We create a 3D attention mask from a 2D tensor mask. + # Sizes are [batch_size, 1, 1, to_seq_length] + # So we can broadcast to [batch_size, num_heads, from_seq_length, to_seq_length] + # this attention mask is more simple than the triangular masking of causal attention + # used in OpenAI GPT, we just need to prepare the broadcast dimension here. + attention_mask = attention_mask[:, None, None, :] + + # Since attention_mask is 1.0 for positions we want to attend and 0.0 for + # masked positions, this operation will create a tensor which is 0.0 for + # positions we want to attend and -10000.0 for masked positions. + # Since we are adding it to the raw scores before the softmax, this is + # effectively the same as removing these entirely. + attention_mask = attention_mask.to(dtype=self.dtype) # fp16 compatibility + attention_mask = (1.0 - attention_mask) * -10000.0 + + # If a 2D or 3D attention mask is provided for the cross-attention + # we need to make broadcastable to [batch_size, num_heads, seq_length, seq_length] + if self.config.add_cross_attention and encoder_hidden_states is not None: + encoder_batch_size, encoder_sequence_length, _ = encoder_hidden_states.size() + encoder_hidden_shape = (encoder_batch_size, encoder_sequence_length) + if encoder_attention_mask is None: + encoder_attention_mask = torch.ones(encoder_hidden_shape, device=device) + encoder_attention_mask = self.invert_attention_mask(encoder_attention_mask) + else: + encoder_attention_mask = None + + # Prepare head mask if needed + # 1.0 in head_mask indicate we keep the head + # attention_probs has shape bsz x n_heads x N x N + # head_mask has shape n_layer x batch x n_heads x N x N + head_mask = self.get_head_mask(head_mask, self.config.n_layer) + + if inputs_embeds is None: + inputs_embeds = self.wte(pixel_values) + position_embeds = self.wpe(position_ids) + hidden_states = inputs_embeds + position_embeds + + if token_type_ids is not None: + token_type_embeds = self.wte(token_type_ids) + hidden_states = hidden_states + token_type_embeds + + hidden_states = self.drop(hidden_states) + + output_shape = input_shape + (hidden_states.size(-1),) + + presents = () if use_cache else None + all_self_attentions = () if output_attentions else None + all_cross_attentions = () if output_attentions and self.config.add_cross_attention else None + all_hidden_states = () if output_hidden_states else None + for i, (block, layer_past) in enumerate(zip(self.h, past_key_values)): + + # Model parallel + if self.model_parallel: + torch.cuda.set_device(hidden_states.device) + # Ensure layer_past is on same device as hidden_states (might not be correct) + if layer_past is not None: + layer_past = tuple(past_state.to(hidden_states.device) for past_state in layer_past) + # Ensure that attention_mask is always on the same device as hidden_states + if attention_mask is not None: + attention_mask = attention_mask.to(hidden_states.device) + if isinstance(head_mask, torch.Tensor): + head_mask = head_mask.to(hidden_states.device) + if output_hidden_states: + all_hidden_states = all_hidden_states + (hidden_states,) + + if self.gradient_checkpointing and self.training: + + if use_cache: + logger.warning( + "`use_cache=True` is incompatible with gradient checkpointing. Setting `use_cache=False`..." + ) + use_cache = False + + def create_custom_forward(module): + def custom_forward(*inputs): + # None for past_key_value + return module(*inputs, use_cache, output_attentions) + + return custom_forward + + outputs = torch.utils.checkpoint.checkpoint( + create_custom_forward(block), + hidden_states, + None, + attention_mask, + head_mask[i], + encoder_hidden_states, + encoder_attention_mask, + ) + else: + outputs = block( + hidden_states, + layer_past=layer_past, + attention_mask=attention_mask, + head_mask=head_mask[i], + encoder_hidden_states=encoder_hidden_states, + encoder_attention_mask=encoder_attention_mask, + use_cache=use_cache, + output_attentions=output_attentions, + ) + + hidden_states = outputs[0] + if use_cache is True: + presents = presents + (outputs[1],) + + if output_attentions: + all_self_attentions = all_self_attentions + (outputs[2 if use_cache else 1],) + if self.config.add_cross_attention: + all_cross_attentions = all_cross_attentions + (outputs[3 if use_cache else 2],) + + # Model Parallel: If it's the last layer for that device, put things on the next device + if self.model_parallel: + for k, v in self.device_map.items(): + if i == v[-1] and "cuda:" + str(k) != self.last_device: + hidden_states = hidden_states.to("cuda:" + str(k + 1)) + + hidden_states = self.ln_f(hidden_states) + + hidden_states = hidden_states.view(*output_shape) + # Add last hidden state + if output_hidden_states: + all_hidden_states = all_hidden_states + (hidden_states,) + + if not return_dict: + return tuple( + v + for v in [hidden_states, presents, all_hidden_states, all_self_attentions, all_cross_attentions] + if v is not None + ) + + return BaseModelOutputWithPastAndCrossAttentions( + last_hidden_state=hidden_states, + past_key_values=presents, + hidden_states=all_hidden_states, + attentions=all_self_attentions, + cross_attentions=all_cross_attentions, + ) + + +@add_start_docstrings( + """ + The ImageGPT Model transformer with a language modeling head on top (linear layer with weights tied to the input + embeddings). + """, + IMAGEGPT_START_DOCSTRING, +) +class ImageGPTForCausalLM(ImageGPTPreTrainedModel): + _keys_to_ignore_on_load_missing = [r"attn.masked_bias", r"attn.bias", r"lm_head.weight"] + + def __init__(self, config): + super().__init__(config) + self.transformer = ImageGPTModel(config) + self.lm_head = nn.Linear(config.n_embd, config.vocab_size - 1, bias=False) + + # Model parallel + self.model_parallel = False + self.device_map = None + # Initialize weights and apply final processing + self.post_init() + + def get_output_embeddings(self): + return self.lm_head + + def set_output_embeddings(self, new_embeddings): + self.lm_head = new_embeddings + + def prepare_inputs_for_generation(self, pixel_values, past=None, **kwargs): + token_type_ids = kwargs.get("token_type_ids", None) + # only last token for inputs_ids if past is defined in kwargs + if past: + pixel_values = pixel_values[:, -1].unsqueeze(-1) + if token_type_ids is not None: + token_type_ids = token_type_ids[:, -1].unsqueeze(-1) + + attention_mask = kwargs.get("attention_mask", None) + position_ids = kwargs.get("position_ids", None) + + if attention_mask is not None and position_ids is None: + # create position_ids on the fly for batch generation + position_ids = attention_mask.long().cumsum(-1) - 1 + position_ids.masked_fill_(attention_mask == 0, 1) + if past: + position_ids = position_ids[:, -1].unsqueeze(-1) + else: + position_ids = None + return { + "pixel_values": pixel_values, + "past_key_values": past, + "use_cache": kwargs.get("use_cache"), + "position_ids": position_ids, + "attention_mask": attention_mask, + "token_type_ids": token_type_ids, + } + + @add_start_docstrings_to_model_forward(IMAGEGPT_INPUTS_DOCSTRING) + @replace_return_docstrings(output_type=CausalLMOutputWithCrossAttentions, config_class=_CONFIG_FOR_DOC) + def forward( + self, + pixel_values=None, + past_key_values=None, + attention_mask=None, + token_type_ids=None, + position_ids=None, + head_mask=None, + inputs_embeds=None, + encoder_hidden_states=None, + encoder_attention_mask=None, + labels=None, + use_cache=None, + output_attentions=None, + output_hidden_states=None, + return_dict=None, + ): + r""" + labels (:obj:`torch.LongTensor` of shape :obj:`(batch_size, sequence_length)`, `optional`): + Labels for language modeling. Note that the labels **are shifted** inside the model, i.e. you can set + ``labels = pixel_values`` Indices are selected in ``[-100, 0, ..., config.vocab_size]`` All labels set to + ``-100`` are ignored (masked), the loss is only computed for labels in ``[0, ..., config.vocab_size]`` + + Returns: + + Examples:: + + >>> from transformers import ImageGPTFeatureExtractor, ImageGPTForCausalLM + >>> import torch + >>> import matplotlib.pyplot as plt + >>> import numpy as np + + >>> feature_extractor = ImageGPTFeatureExtractor.from_pretrained('openai/imagegpt-small') + >>> model = ImageGPTForCausalLM.from_pretrained('openai/imagegpt-small') + >>> device = torch.device("cuda" if torch.cuda.is_available() else "cpu") + >>> model.to(device) + + >>> # unconditional generation of 8 images + >>> batch_size = 8 + >>> context = torch.full((batch_size, 1), model.config.vocab_size - 1) #initialize with SOS token + >>> context = torch.tensor(context).to(device) + >>> output = model.generate(pixel_values=context, max_length=model.config.n_positions + 1, temperature=1.0, do_sample=True, top_k=40) + + >>> clusters = feature_extractor.clusters + >>> n_px = feature_extractor.size + + >>> samples = output[:,1:].cpu().detach().numpy() + >>> samples_img = [np.reshape(np.rint(127.5 * (clusters[s] + 1.0)), [n_px, n_px, 3]).astype(np.uint8) for s in samples] # convert color cluster tokens back to pixels + >>> f, axes = plt.subplots(1, batch_size, dpi=300) + + >>> for img, ax in zip(samples_img, axes): + ... ax.axis('off') + ... ax.imshow(img) + """ + + return_dict = return_dict if return_dict is not None else self.config.use_return_dict + + transformer_outputs = self.transformer( + pixel_values, + past_key_values=past_key_values, + attention_mask=attention_mask, + token_type_ids=token_type_ids, + position_ids=position_ids, + head_mask=head_mask, + inputs_embeds=inputs_embeds, + encoder_hidden_states=encoder_hidden_states, + encoder_attention_mask=encoder_attention_mask, + use_cache=use_cache, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + return_dict=return_dict, + ) + hidden_states = transformer_outputs[0] + + lm_logits = self.lm_head(hidden_states) + + loss = None + if labels is not None: + # Shift so that tokens < n predict n + shift_logits = lm_logits[..., :-1, :].contiguous() + shift_labels = labels[..., 1:].contiguous() + # Flatten the tokens + loss_fct = CrossEntropyLoss() + loss = loss_fct(shift_logits.view(-1, shift_logits.size(-1)), shift_labels.view(-1)) + + if not return_dict: + output = (lm_logits,) + transformer_outputs[1:] + return ((loss,) + output) if loss is not None else output + + return CausalLMOutputWithCrossAttentions( + loss=loss, + logits=lm_logits, + past_key_values=transformer_outputs.past_key_values, + hidden_states=transformer_outputs.hidden_states, + attentions=transformer_outputs.attentions, + cross_attentions=transformer_outputs.cross_attentions, + ) + + @staticmethod + def _reorder_cache(past: Tuple[Tuple[torch.Tensor]], beam_idx: torch.Tensor) -> Tuple[Tuple[torch.Tensor]]: + """ + This function is used to re-order the :obj:`past_key_values` cache if + :meth:`~transformers.PreTrainedModel.beam_search` or :meth:`~transformers.PreTrainedModel.beam_sample` is + called. This is required to match :obj:`past_key_values` with the correct beam_idx at every generation step. + """ + return tuple( + tuple(past_state.index_select(0, beam_idx.to(past_state.device)) for past_state in layer_past) + for layer_past in past + ) + + +@add_start_docstrings( + """ + The ImageGPT Model transformer with an image classification head on top (linear layer). + :class:`~transformers.ImageGPTForImageClassification` average-pools the hidden states in order to do the + classification. + """, + IMAGEGPT_START_DOCSTRING, +) +class ImageGPTForImageClassification(ImageGPTPreTrainedModel): + _keys_to_ignore_on_load_missing = [r"h\.\d+\.attn\.masked_bias", r"lm_head\.weight"] + + def __init__(self, config): + super().__init__(config) + self.num_labels = config.num_labels + self.transformer = ImageGPTModel(config) + self.score = nn.Linear(config.n_embd, self.num_labels, bias=False) + + # Initialize weights and apply final processing + self.post_init() + + @add_start_docstrings_to_model_forward(IMAGEGPT_INPUTS_DOCSTRING) + @replace_return_docstrings(output_type=SequenceClassifierOutputWithPast, config_class=_CONFIG_FOR_DOC) + def forward( + self, + pixel_values=None, + past_key_values=None, + attention_mask=None, + token_type_ids=None, + position_ids=None, + head_mask=None, + inputs_embeds=None, + labels=None, + use_cache=None, + output_attentions=None, + output_hidden_states=None, + return_dict=None, + ): + r""" + labels (:obj:`torch.LongTensor` of shape :obj:`(batch_size,)`, `optional`): + Labels for computing the sequence classification/regression loss. Indices should be in :obj:`[0, ..., + config.num_labels - 1]`. If :obj:`config.num_labels == 1` a regression loss is computed (Mean-Square loss), + If :obj:`config.num_labels > 1` a classification loss is computed (Cross-Entropy). + + Returns: + + Examples:: + + >>> from transformers import ImageGPTFeatureExtractor, ImageGPTForImageClassification + >>> from PIL import Image + >>> import requests + + >>> url = 'http://images.cocodataset.org/val2017/000000039769.jpg' + >>> image = Image.open(requests.get(url, stream=True).raw) + + >>> feature_extractor = ImageGPTFeatureExtractor.from_pretrained('openai/imagegpt-small') + >>> model = ImageGPTForImageClassification.from_pretrained('openai/imagegpt-small') + + >>> inputs = feature_extractor(images=image, return_tensors="pt") + >>> outputs = model(**inputs) + >>> logits = outputs.logits + """ + return_dict = return_dict if return_dict is not None else self.config.use_return_dict + + transformer_outputs = self.transformer( + pixel_values, + past_key_values=past_key_values, + attention_mask=attention_mask, + token_type_ids=token_type_ids, + position_ids=position_ids, + head_mask=head_mask, + inputs_embeds=inputs_embeds, + use_cache=use_cache, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + return_dict=return_dict, + ) + hidden_states = transformer_outputs[0] + # average-pool the hidden states along the sequence dimension + pooled_hidden_states = hidden_states.mean(dim=1) + # project from (batch_size, hidden_size) to (batch_size, num_labels) + logits = self.score(pooled_hidden_states) + + loss = None + if labels is not None: + if self.config.problem_type is None: + if self.num_labels == 1: + self.config.problem_type = "regression" + elif self.num_labels > 1 and (labels.dtype == torch.long or labels.dtype == torch.int): + self.config.problem_type = "single_label_classification" + else: + self.config.problem_type = "multi_label_classification" + + if self.config.problem_type == "regression": + loss_fct = MSELoss() + if self.num_labels == 1: + loss = loss_fct(logits.squeeze(), labels.squeeze()) + else: + loss = loss_fct(logits, labels) + elif self.config.problem_type == "single_label_classification": + loss_fct = CrossEntropyLoss() + loss = loss_fct(logits.view(-1, self.num_labels), labels.view(-1)) + elif self.config.problem_type == "multi_label_classification": + loss_fct = BCEWithLogitsLoss() + loss = loss_fct(logits, labels) + if not return_dict: + output = (logits,) + transformer_outputs[1:] + return ((loss,) + output) if loss is not None else output + + return SequenceClassifierOutputWithPast( + loss=loss, + logits=logits, + past_key_values=transformer_outputs.past_key_values, + hidden_states=transformer_outputs.hidden_states, + attentions=transformer_outputs.attentions, + ) diff --git a/src/transformers/utils/dummy_pt_objects.py b/src/transformers/utils/dummy_pt_objects.py index 9e2d466dab..0ed3cf3dbd 100644 --- a/src/transformers/utils/dummy_pt_objects.py +++ b/src/transformers/utils/dummy_pt_objects.py @@ -2637,6 +2637,54 @@ class IBertPreTrainedModel: requires_backends(self, ["torch"]) +IMAGEGPT_PRETRAINED_MODEL_ARCHIVE_LIST = None + + +class ImageGPTForCausalLM: + def __init__(self, *args, **kwargs): + requires_backends(self, ["torch"]) + + @classmethod + def from_pretrained(cls, *args, **kwargs): + requires_backends(cls, ["torch"]) + + def forward(self, *args, **kwargs): + requires_backends(self, ["torch"]) + + +class ImageGPTForImageClassification: + def __init__(self, *args, **kwargs): + requires_backends(self, ["torch"]) + + +class ImageGPTModel: + def __init__(self, *args, **kwargs): + requires_backends(self, ["torch"]) + + @classmethod + def from_pretrained(cls, *args, **kwargs): + requires_backends(cls, ["torch"]) + + def forward(self, *args, **kwargs): + requires_backends(self, ["torch"]) + + +class ImageGPTPreTrainedModel: + def __init__(self, *args, **kwargs): + requires_backends(self, ["torch"]) + + @classmethod + def from_pretrained(cls, *args, **kwargs): + requires_backends(cls, ["torch"]) + + def forward(self, *args, **kwargs): + requires_backends(self, ["torch"]) + + +def load_tf_weights_in_imagegpt(*args, **kwargs): + requires_backends(load_tf_weights_in_imagegpt, ["torch"]) + + LAYOUTLM_PRETRAINED_MODEL_ARCHIVE_LIST = None diff --git a/src/transformers/utils/dummy_vision_objects.py b/src/transformers/utils/dummy_vision_objects.py index 615c20e080..a9f2c9e949 100644 --- a/src/transformers/utils/dummy_vision_objects.py +++ b/src/transformers/utils/dummy_vision_objects.py @@ -36,6 +36,11 @@ class DetrFeatureExtractor: requires_backends(self, ["vision"]) +class ImageGPTFeatureExtractor: + def __init__(self, *args, **kwargs): + requires_backends(self, ["vision"]) + + class LayoutLMv2FeatureExtractor: def __init__(self, *args, **kwargs): requires_backends(self, ["vision"]) diff --git a/tests/test_feature_extraction_imagegpt.py b/tests/test_feature_extraction_imagegpt.py new file mode 100644 index 0000000000..f8744cfa32 --- /dev/null +++ b/tests/test_feature_extraction_imagegpt.py @@ -0,0 +1,177 @@ +# coding=utf-8 +# Copyright 2021 HuggingFace Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import json +import os +import tempfile +import unittest + +import numpy as np +from datasets import load_dataset + +from transformers.file_utils import is_torch_available, is_vision_available +from transformers.testing_utils import require_torch, require_vision, slow + +from .test_feature_extraction_common import FeatureExtractionSavingTestMixin + + +if is_torch_available(): + import torch + +if is_vision_available(): + from PIL import Image + + from transformers import ImageGPTFeatureExtractor + + +class ImageGPTFeatureExtractionTester(unittest.TestCase): + def __init__( + self, + parent, + batch_size=7, + num_channels=3, + image_size=18, + min_resolution=30, + max_resolution=400, + do_resize=True, + size=18, + do_normalize=True, + ): + self.parent = parent + self.batch_size = batch_size + self.num_channels = num_channels + self.image_size = image_size + self.min_resolution = min_resolution + self.max_resolution = max_resolution + self.do_resize = do_resize + self.size = size + self.do_normalize = do_normalize + + def prepare_feat_extract_dict(self): + return { + # here we create 2 clusters for the sake of simplicity + "clusters": np.asarray( + [ + [0.8866443634033203, 0.6618829369544983, 0.3891746401786804], + [-0.6042559146881104, -0.02295008860528469, 0.5423797369003296], + ] + ), + "do_resize": self.do_resize, + "size": self.size, + "do_normalize": self.do_normalize, + } + + +@require_torch +@require_vision +class ImageGPTFeatureExtractionTest(FeatureExtractionSavingTestMixin, unittest.TestCase): + + feature_extraction_class = ImageGPTFeatureExtractor if is_vision_available() else None + + def setUp(self): + self.feature_extract_tester = ImageGPTFeatureExtractionTester(self) + + @property + def feat_extract_dict(self): + return self.feature_extract_tester.prepare_feat_extract_dict() + + def test_feat_extract_properties(self): + feature_extractor = self.feature_extraction_class(**self.feat_extract_dict) + self.assertTrue(hasattr(feature_extractor, "clusters")) + self.assertTrue(hasattr(feature_extractor, "do_resize")) + self.assertTrue(hasattr(feature_extractor, "size")) + self.assertTrue(hasattr(feature_extractor, "do_normalize")) + + def test_feat_extract_to_json_string(self): + feat_extract = self.feature_extraction_class(**self.feat_extract_dict) + obj = json.loads(feat_extract.to_json_string()) + for key, value in self.feat_extract_dict.items(): + if key == "clusters": + self.assertTrue(np.array_equal(value, obj[key])) + else: + self.assertEqual(obj[key], value) + + def test_feat_extract_to_json_file(self): + feat_extract_first = self.feature_extraction_class(**self.feat_extract_dict) + + with tempfile.TemporaryDirectory() as tmpdirname: + json_file_path = os.path.join(tmpdirname, "feat_extract.json") + feat_extract_first.to_json_file(json_file_path) + feat_extract_second = self.feature_extraction_class.from_json_file(json_file_path).to_dict() + + feat_extract_first = feat_extract_first.to_dict() + for key, value in feat_extract_first.items(): + if key == "clusters": + self.assertTrue(np.array_equal(value, feat_extract_second[key])) + else: + self.assertEqual(feat_extract_first[key], value) + + def test_feat_extract_from_and_save_pretrained(self): + feat_extract_first = self.feature_extraction_class(**self.feat_extract_dict) + + with tempfile.TemporaryDirectory() as tmpdirname: + feat_extract_first.save_pretrained(tmpdirname) + feat_extract_second = self.feature_extraction_class.from_pretrained(tmpdirname).to_dict() + + feat_extract_first = feat_extract_first.to_dict() + for key, value in feat_extract_first.items(): + if key == "clusters": + self.assertTrue(np.array_equal(value, feat_extract_second[key])) + else: + self.assertEqual(feat_extract_first[key], value) + + @unittest.skip("ImageGPT requires clusters at initialization") + def test_init_without_params(self): + pass + + +def prepare_images(): + dataset = load_dataset("hf-internal-testing/fixtures_image_utils", split="test") + + image1 = Image.open(dataset[4]["file"]) + image2 = Image.open(dataset[5]["file"]) + + images = [image1, image2] + + return images + + +@require_vision +@require_torch +class ImageGPTFeatureExtractorIntegrationTest(unittest.TestCase): + @slow + def test_image(self): + feature_extractor = ImageGPTFeatureExtractor.from_pretrained("openai/imagegpt-small") + + images = prepare_images() + + # test non-batched + encoding = feature_extractor(images[0], return_tensors="pt") + + self.assertIsInstance(encoding.pixel_values, torch.LongTensor) + self.assertEqual(encoding.pixel_values.shape, (1, 1024)) + + expected_slice = [306, 191, 191] + self.assertEqual(encoding.pixel_values[0, :3].tolist(), expected_slice) + + # test batched + encoding = feature_extractor(images, return_tensors="pt") + + self.assertIsInstance(encoding.pixel_values, torch.LongTensor) + self.assertEqual(encoding.pixel_values.shape, (2, 1024)) + + expected_slice = [303, 13, 13] + self.assertEqual(encoding.pixel_values[1, -3:].tolist(), expected_slice) diff --git a/tests/test_modeling_imagegpt.py b/tests/test_modeling_imagegpt.py new file mode 100644 index 0000000000..c78dce4a67 --- /dev/null +++ b/tests/test_modeling_imagegpt.py @@ -0,0 +1,498 @@ +# coding=utf-8 +# Copyright 2021 The HuggingFace Team. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import copy +import inspect +import os +import tempfile +import unittest + +from transformers import ImageGPTConfig, is_torch_available +from transformers.testing_utils import require_torch, slow, torch_device + +from .test_configuration_common import ConfigTester +from .test_generation_utils import GenerationTesterMixin +from .test_modeling_common import ModelTesterMixin, _config_zero_init, floats_tensor, ids_tensor, random_attention_mask + + +if is_torch_available(): + import torch + + from transformers import ( + IMAGEGPT_PRETRAINED_MODEL_ARCHIVE_LIST, + ImageGPTForCausalLM, + ImageGPTForImageClassification, + ImageGPTModel, + ) + + +class ImageGPTModelTester: + def __init__( + self, + parent, + batch_size=14, + seq_length=7, + is_training=True, + use_token_type_ids=True, + use_input_mask=True, + use_labels=True, + use_mc_token_ids=True, + vocab_size=99, + hidden_size=32, + num_hidden_layers=5, + num_attention_heads=4, + intermediate_size=37, + hidden_act="gelu", + hidden_dropout_prob=0.1, + attention_probs_dropout_prob=0.1, + max_position_embeddings=512, + type_vocab_size=16, + type_sequence_label_size=2, + initializer_range=0.02, + num_labels=3, + num_choices=4, + scope=None, + ): + self.parent = parent + self.batch_size = batch_size + self.seq_length = seq_length + self.is_training = is_training + self.use_token_type_ids = use_token_type_ids + self.use_input_mask = use_input_mask + self.use_labels = use_labels + self.use_mc_token_ids = use_mc_token_ids + self.vocab_size = vocab_size + self.hidden_size = hidden_size + self.num_hidden_layers = num_hidden_layers + self.num_attention_heads = num_attention_heads + self.intermediate_size = intermediate_size + self.hidden_act = hidden_act + self.hidden_dropout_prob = hidden_dropout_prob + self.attention_probs_dropout_prob = attention_probs_dropout_prob + self.max_position_embeddings = max_position_embeddings + self.type_vocab_size = type_vocab_size + self.type_sequence_label_size = type_sequence_label_size + self.initializer_range = initializer_range + self.num_labels = num_labels + self.num_choices = num_choices + self.scope = None + + def get_large_model_config(self): + return ImageGPTConfig.from_pretrained("imagegpt") + + def prepare_config_and_inputs( + self, gradient_checkpointing=False, scale_attn_by_inverse_layer_idx=False, reorder_and_upcast_attn=False + ): + pixel_values = ids_tensor([self.batch_size, self.seq_length], self.vocab_size - 1) + + input_mask = None + if self.use_input_mask: + input_mask = random_attention_mask([self.batch_size, self.seq_length]) + + token_type_ids = None + if self.use_token_type_ids: + token_type_ids = ids_tensor([self.batch_size, self.seq_length], self.type_vocab_size) + + mc_token_ids = None + if self.use_mc_token_ids: + mc_token_ids = ids_tensor([self.batch_size, self.num_choices], self.seq_length) + + sequence_labels = None + token_labels = None + choice_labels = None + if self.use_labels: + sequence_labels = ids_tensor([self.batch_size], self.type_sequence_label_size) + token_labels = ids_tensor([self.batch_size, self.seq_length], self.num_labels) + choice_labels = ids_tensor([self.batch_size], self.num_choices) + + config = self.get_config( + gradient_checkpointing=gradient_checkpointing, + scale_attn_by_inverse_layer_idx=scale_attn_by_inverse_layer_idx, + reorder_and_upcast_attn=reorder_and_upcast_attn, + ) + + head_mask = ids_tensor([self.num_hidden_layers, self.num_attention_heads], 2) + + return ( + config, + pixel_values, + input_mask, + head_mask, + token_type_ids, + mc_token_ids, + sequence_labels, + token_labels, + choice_labels, + ) + + def get_config( + self, gradient_checkpointing=False, scale_attn_by_inverse_layer_idx=False, reorder_and_upcast_attn=False + ): + return ImageGPTConfig( + vocab_size=self.vocab_size, + n_embd=self.hidden_size, + n_layer=self.num_hidden_layers, + n_head=self.num_attention_heads, + n_inner=self.intermediate_size, + activation_function=self.hidden_act, + resid_pdrop=self.hidden_dropout_prob, + attn_pdrop=self.attention_probs_dropout_prob, + n_positions=self.max_position_embeddings, + type_vocab_size=self.type_vocab_size, + initializer_range=self.initializer_range, + use_cache=True, + gradient_checkpointing=gradient_checkpointing, + scale_attn_by_inverse_layer_idx=scale_attn_by_inverse_layer_idx, + reorder_and_upcast_attn=reorder_and_upcast_attn, + ) + + def prepare_config_and_inputs_for_decoder(self): + ( + config, + pixel_values, + input_mask, + head_mask, + token_type_ids, + mc_token_ids, + sequence_labels, + token_labels, + choice_labels, + ) = self.prepare_config_and_inputs() + + encoder_hidden_states = floats_tensor([self.batch_size, self.seq_length, self.hidden_size]) + encoder_attention_mask = ids_tensor([self.batch_size, self.seq_length], vocab_size=2) + + return ( + config, + pixel_values, + input_mask, + head_mask, + token_type_ids, + sequence_labels, + token_labels, + choice_labels, + encoder_hidden_states, + encoder_attention_mask, + ) + + def create_and_check_imagegpt_model(self, config, pixel_values, input_mask, head_mask, token_type_ids, *args): + model = ImageGPTModel(config=config) + model.to(torch_device) + model.eval() + + result = model(pixel_values, token_type_ids=token_type_ids, head_mask=head_mask) + result = model(pixel_values, token_type_ids=token_type_ids) + result = model(pixel_values) + + self.parent.assertEqual(result.last_hidden_state.shape, (self.batch_size, self.seq_length, self.hidden_size)) + self.parent.assertEqual(len(result.past_key_values), config.n_layer) + + def create_and_check_lm_head_model(self, config, pixel_values, input_mask, head_mask, token_type_ids, *args): + model = ImageGPTForCausalLM(config) + model.to(torch_device) + model.eval() + + labels = ids_tensor([self.batch_size, self.seq_length], self.vocab_size - 1) + result = model(pixel_values, token_type_ids=token_type_ids, labels=labels) + self.parent.assertEqual(result.loss.shape, ()) + # ImageGPTForCausalLM doens't have tied input- and output embeddings + self.parent.assertEqual(result.logits.shape, (self.batch_size, self.seq_length, self.vocab_size - 1)) + + def create_and_check_imagegpt_for_image_classification( + self, config, pixel_values, input_mask, head_mask, token_type_ids, mc_token_ids, sequence_labels, *args + ): + config.num_labels = self.num_labels + model = ImageGPTForImageClassification(config) + model.to(torch_device) + model.eval() + result = model(pixel_values, attention_mask=input_mask, token_type_ids=token_type_ids, labels=sequence_labels) + self.parent.assertEqual(result.logits.shape, (self.batch_size, self.num_labels)) + + def prepare_config_and_inputs_for_common(self): + config_and_inputs = self.prepare_config_and_inputs() + + ( + config, + pixel_values, + input_mask, + head_mask, + token_type_ids, + mc_token_ids, + sequence_labels, + token_labels, + choice_labels, + ) = config_and_inputs + + inputs_dict = { + "pixel_values": pixel_values, + "token_type_ids": token_type_ids, + "head_mask": head_mask, + } + + return config, inputs_dict + + +@require_torch +class ImageGPTModelTest(ModelTesterMixin, GenerationTesterMixin, unittest.TestCase): + + all_model_classes = ( + (ImageGPTForCausalLM, ImageGPTForImageClassification, ImageGPTModel) if is_torch_available() else () + ) + all_generative_model_classes = (ImageGPTForCausalLM,) if is_torch_available() else () + test_missing_keys = False + input_name = "pixel_values" + + # as ImageGPTForImageClassification isn't included in any auto mapping, we add labels here + def _prepare_for_class(self, inputs_dict, model_class, return_labels=False): + inputs_dict = super()._prepare_for_class(inputs_dict, model_class, return_labels=return_labels) + + if return_labels: + if model_class.__name__ == "ImageGPTForImageClassification": + inputs_dict["labels"] = torch.zeros( + self.model_tester.batch_size, dtype=torch.long, device=torch_device + ) + + return inputs_dict + + # we overwrite the _check_scores method of GenerationTesterMixin, as ImageGPTForCausalLM doesn't have tied input- and output embeddings + def _check_scores(self, batch_size, scores, length, config): + expected_shape = (batch_size, config.vocab_size - 1) + self.assertIsInstance(scores, tuple) + self.assertEqual(len(scores), length) + self.assertListEqual([iter_scores.shape for iter_scores in scores], [expected_shape] * len(scores)) + + def setUp(self): + self.model_tester = ImageGPTModelTester(self) + self.config_tester = ConfigTester(self, config_class=ImageGPTConfig, n_embd=37) + + def test_config(self): + self.config_tester.run_common_tests() + + def test_imagegpt_model(self): + config_and_inputs = self.model_tester.prepare_config_and_inputs() + self.model_tester.create_and_check_imagegpt_model(*config_and_inputs) + + def test_imagegpt_causal_lm(self): + config_and_inputs = self.model_tester.prepare_config_and_inputs() + self.model_tester.create_and_check_lm_head_model(*config_and_inputs) + + def test_imagegpt_image_classification(self): + config_and_inputs = self.model_tester.prepare_config_and_inputs() + self.model_tester.create_and_check_imagegpt_for_image_classification(*config_and_inputs) + + @slow + def test_model_from_pretrained(self): + for model_name in IMAGEGPT_PRETRAINED_MODEL_ARCHIVE_LIST[:1]: + model = ImageGPTModel.from_pretrained(model_name) + self.assertIsNotNone(model) + + def test_forward_signature(self): + config, _ = self.model_tester.prepare_config_and_inputs_for_common() + + for model_class in self.all_model_classes: + model = model_class(config) + signature = inspect.signature(model.forward) + # signature.parameters is an OrderedDict => so arg_names order is deterministic + arg_names = [*signature.parameters.keys()] + + expected_arg_names = ["pixel_values"] + self.assertListEqual(arg_names[:1], expected_arg_names) + + def test_resize_tokens_embeddings(self): + ( + original_config, + inputs_dict, + ) = self.model_tester.prepare_config_and_inputs_for_common() + if not self.test_resize_embeddings: + return + + for model_class in self.all_model_classes: + config = copy.deepcopy(original_config) + model = model_class(config) + model.to(torch_device) + + if self.model_tester.is_training is False: + model.eval() + + model_vocab_size = config.vocab_size + # Retrieve the embeddings and clone theme + model_embed = model.resize_token_embeddings(model_vocab_size) + cloned_embeddings = model_embed.weight.clone() + + # Check that resizing the token embeddings with a larger vocab size increases the model's vocab size + model_embed = model.resize_token_embeddings(model_vocab_size + 10) + self.assertEqual(model.config.vocab_size, model_vocab_size + 10) + # Check that it actually resizes the embeddings matrix + self.assertEqual(model_embed.weight.shape[0], cloned_embeddings.shape[0] + 10) + # Check that the model can still do a forward pass successfully (every parameter should be resized) + model(**self._prepare_for_class(inputs_dict, model_class)) + + # Check that resizing the token embeddings with a smaller vocab size decreases the model's vocab size + model_embed = model.resize_token_embeddings(model_vocab_size - 15) + self.assertEqual(model.config.vocab_size, model_vocab_size - 15) + # Check that it actually resizes the embeddings matrix + self.assertEqual(model_embed.weight.shape[0], cloned_embeddings.shape[0] - 15) + + # Check that the model can still do a forward pass successfully (every parameter should be resized) + # Input ids should be clamped to the maximum size of the vocabulary + inputs_dict["pixel_values"].clamp_(max=model_vocab_size - 15 - 1) + + # Check that adding and removing tokens has not modified the first part of the embedding matrix. + models_equal = True + for p1, p2 in zip(cloned_embeddings, model_embed.weight): + if p1.data.ne(p2.data).sum() > 0: + models_equal = False + + self.assertTrue(models_equal) + + def test_resize_embeddings_untied(self): + ( + original_config, + inputs_dict, + ) = self.model_tester.prepare_config_and_inputs_for_common() + if not self.test_resize_embeddings: + return + + original_config.tie_word_embeddings = False + + # if model cannot untied embeddings -> leave test + if original_config.tie_word_embeddings: + return + + for model_class in self.all_model_classes: + config = copy.deepcopy(original_config) + model = model_class(config).to(torch_device) + + # if no output embeddings -> leave test + if model.get_output_embeddings() is None: + continue + + # Check that resizing the token embeddings with a larger vocab size increases the model's vocab size + model_vocab_size = config.vocab_size + model.resize_token_embeddings(model_vocab_size + 10) + self.assertEqual(model.config.vocab_size, model_vocab_size + 10) + output_embeds = model.get_output_embeddings() + self.assertEqual(output_embeds.weight.shape[0], model_vocab_size + 10) + # Check bias if present + if output_embeds.bias is not None: + self.assertEqual(output_embeds.bias.shape[0], model_vocab_size + 10) + # Check that the model can still do a forward pass successfully (every parameter should be resized) + model(**self._prepare_for_class(inputs_dict, model_class)) + + # Check that resizing the token embeddings with a smaller vocab size decreases the model's vocab size + model.resize_token_embeddings(model_vocab_size - 15) + self.assertEqual(model.config.vocab_size, model_vocab_size - 15) + # Check that it actually resizes the embeddings matrix + output_embeds = model.get_output_embeddings() + self.assertEqual(output_embeds.weight.shape[0], model_vocab_size - 15) + # Check bias if present + if output_embeds.bias is not None: + self.assertEqual(output_embeds.bias.shape[0], model_vocab_size - 15) + # Check that the model can still do a forward pass successfully (every parameter should be resized) + # Input ids should be clamped to the maximum size of the vocabulary + inputs_dict["pixel_values"].clamp_(max=model_vocab_size - 15 - 1) + # Check that the model can still do a forward pass successfully (every parameter should be resized) + model(**self._prepare_for_class(inputs_dict, model_class)) + + def test_inputs_embeds(self): + config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common() + + for model_class in self.all_model_classes: + model = model_class(config) + model.to(torch_device) + model.eval() + + inputs = copy.deepcopy(self._prepare_for_class(inputs_dict, model_class)) + + pixel_values = inputs["pixel_values"] + del inputs["pixel_values"] + + wte = model.get_input_embeddings() + inputs["inputs_embeds"] = wte(pixel_values) + + with torch.no_grad(): + model(**inputs)[0] + + def _create_and_check_torchscript(self, config, inputs_dict): + if not self.test_torchscript: + return + + configs_no_init = _config_zero_init(config) # To be sure we have no Nan + configs_no_init.torchscript = True + for model_class in self.all_model_classes: + model = model_class(config=configs_no_init) + model.to(torch_device) + model.eval() + inputs = self._prepare_for_class(inputs_dict, model_class) + + try: + pixel_values = inputs["pixel_values"] + traced_model = torch.jit.trace(model, pixel_values) + except RuntimeError: + self.fail("Couldn't trace module.") + + with tempfile.TemporaryDirectory() as tmp_dir_name: + pt_file_name = os.path.join(tmp_dir_name, "traced_model.pt") + + try: + torch.jit.save(traced_model, pt_file_name) + except Exception: + self.fail("Couldn't save module.") + + try: + loaded_model = torch.jit.load(pt_file_name) + except Exception: + self.fail("Couldn't load module.") + + model.to(torch_device) + model.eval() + + loaded_model.to(torch_device) + loaded_model.eval() + + model_state_dict = model.state_dict() + loaded_model_state_dict = loaded_model.state_dict() + + non_persistent_buffers = {} + for key in loaded_model_state_dict.keys(): + if key not in model_state_dict.keys(): + non_persistent_buffers[key] = loaded_model_state_dict[key] + + loaded_model_state_dict = { + key: value for key, value in loaded_model_state_dict.items() if key not in non_persistent_buffers + } + + self.assertEqual(set(model_state_dict.keys()), set(loaded_model_state_dict.keys())) + + model_buffers = list(model.buffers()) + for non_persistent_buffer in non_persistent_buffers.values(): + found_buffer = False + for i, model_buffer in enumerate(model_buffers): + if torch.equal(non_persistent_buffer, model_buffer): + found_buffer = True + break + + self.assertTrue(found_buffer) + model_buffers.pop(i) + + models_equal = True + for layer_name, p1 in model_state_dict.items(): + if layer_name in loaded_model_state_dict: + p2 = loaded_model_state_dict[layer_name] + if p1.data.ne(p2.data).sum() > 0: + models_equal = False + + self.assertTrue(models_equal) diff --git a/utils/check_repo.py b/utils/check_repo.py index 9082ca4b88..8d8445cfee 100644 --- a/utils/check_repo.py +++ b/utils/check_repo.py @@ -100,6 +100,7 @@ TEST_FILES_WITH_NO_COMMON_TESTS = [ # should **not** be the rule. IGNORE_NON_AUTO_CONFIGURED = PRIVATE_MODELS.copy() + [ # models to ignore for model xxx mapping + "ImageGPTForImageClassification", "SegformerDecodeHead", "SegformerForSemanticSegmentation", "BeitForSemanticSegmentation",