├── LICENSE.txt ├── README.md ├── document ├── Chinese.md └── version.md ├── image ├── keras_wechat.jpg └── tensorcv.png ├── setup.cfg ├── setup.py └── tensorcv ├── Classification ├── __init__.py ├── _alexnet.py ├── _darknet.py ├── _densenet.py ├── _inception.py ├── _resnet.py ├── _resnetv1b.py ├── _resnext.py ├── _senet.py ├── _squeezenet.py └── _vgg.py ├── Detection ├── __init__.py └── bbox │ ├── __init__.py │ └── _bbox.py ├── Segmentation └── __init__.py ├── __init__.py ├── data ├── __init__.py ├── _sample.py └── datasets │ └── __init__.py ├── image ├── __init__.py └── _image_ops.py ├── losses ├── __init__.py └── _losses.py └── nd ├── __init__.py ├── _distance.py └── _nd.py /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](https://github.com/Hourout/tensorcv/blob/master/image/tensorcv.png) 2 | 3 | Keras and TensorFlow CV Toolkit 4 | 5 | ![PyPI version](https://img.shields.io/pypi/pyversions/tensorcv.svg) 6 | ![Github license](https://img.shields.io/github/license/Hourout/tensorcv.svg) 7 | [![PyPI](https://img.shields.io/pypi/v/tensorcv.svg)](https://pypi.python.org/pypi/tensorcv) 8 | ![PyPI format](https://img.shields.io/pypi/format/tensorcv.svg) 9 | 10 | | [中文介绍](https://github.com/Hourout/tensorcv/blob/master/document/Chinese.md) |[ Version ](https://github.com/Hourout/tensorcv/blob/master/document/version.md)| 11 | 12 | ## Installation 13 | To install [this verson from PyPI](https://pypi.org/project/tensorcv/), type: 14 | 15 | ``` 16 | pip install tensorcv 17 | ``` 18 | 19 | To get the newest one from this repo (note that we are in the alpha stage, so there may be frequent updates), type: 20 | 21 | ``` 22 | pip install git+git://github.com/Hourout/tensorcv.git 23 | ``` 24 | -------------------------------------------------------------------------------- /document/Chinese.md: -------------------------------------------------------------------------------- 1 | ![](https://github.com/Hourout/tensorcv/blob/master/image/tensorcv.png) 2 | 3 | ![PyPI version](https://img.shields.io/pypi/pyversions/tensorcv.svg) 4 | ![Github license](https://img.shields.io/github/license/Hourout/tensorcv.svg) 5 | [![PyPI](https://img.shields.io/pypi/v/tensorcv.svg)](https://pypi.python.org/pypi/tensorcv) 6 | ![PyPI format](https://img.shields.io/pypi/format/tensorcv.svg) 7 | 8 | ## 介绍 9 | TensorCV是一个由TensorFlow实现的计算机视觉工具箱。 10 | 11 | TensorCV是一个面向 tensorflow 和 keras 用户的计算机视觉工具库,指在为用户提供简洁、稳定的标准化网络框架。 12 | TensorCV功能涵盖图像分类、目标检测、语义分割、实例分割、风格迁移、超分辨率还原、图像修复等诸多计算机视觉领域。 13 | 14 | TensorCV 设计灵感来源于 gluonCV,致力于像 gluonCV 那样为 keras 生态贡献一份自己的力量。 15 | 16 | ## Installation 17 | 支持pip安装[tensorcv](https://pypi.org/project/tensorcv/): 18 | 19 | ``` 20 | pip install tensorcv 21 | ``` 22 | 23 | 也可以用git安装最新的开发版本 24 | 25 | ``` 26 | pip install git+git://github.com/Hourout/tensorcv.git 27 | ``` 28 | 29 | ## 版本 30 | 31 | 目前 tensorcv 不支持预训练模型,当然如果只想要中间的结构层,而不需要输出层,可以通过参数 include_top=False 来实现。 32 | 33 | tensorcv 目前还在快速开发中,未来将支持更多的功能,欢迎keras以及tensorflow社区的同学们一起加入开发。 34 | 35 | ## 博客 36 | 欢迎关注keras中文社区博客,扫码关注微信公众号 37 | 38 | ![](https://github.com/Hourout/tensorcv/blob/master/image/keras_wechat.jpg) 39 | -------------------------------------------------------------------------------- /document/version.md: -------------------------------------------------------------------------------- 1 | #### tensorcv-0.2.0 2 | - fix some bug tc.data.datasets module 3 | - add doc with tc.data.datasets module 4 | #### tensorcv-0.1.9 5 | - add tc.data.datasets.mnist_tibetan() 6 | #### tensorcv-0.1.8 7 | - add tc.data.datasets.cifar10() 8 | - add tc.data.datasets.cifar100() 9 | #### tensorcv-0.1.7 10 | - add tc.data.datasets.mnist_kuzushiji10() 11 | - add tc.data.datasets.mnist_kuzushiji49() 12 | #### tensorcv-0.1.6 13 | - add tc.data.datasets.mnist() 14 | - add tc.data.datasets.mnist_fashion() 15 | #### tensorcv-0.1.5 16 | - fix some bug tc.image module 17 | - add doc with tc.image module 18 | #### tensorcv-0.1.4 19 | - add tc.image.RandomNoiseRainbow() 20 | - add tc.image.RandomRescale() 21 | #### tensorcv-0.1.3 22 | - add tc.image.RandomNoiseMask() 23 | - add tc.image.RandomNoiseSaltPepper() 24 | #### tensorcv-0.1.2 25 | - add tc.image.Normalize() 26 | - add tc.image.RandomNoiseGaussian() 27 | - add tc.image.RandomNoisePoisson() 28 | #### tensorcv-0.1.1 29 | - add tc.image.RandomCropCentralResize() 30 | - add tc.image.RandomCropPointResize() 31 | - add tc.data.ImageClassificationFolderDataset() 32 | #### tensorcv-0.1.0 33 | - add tc.image.RandomBrightness() 34 | - add tc.image.RandomContrast() 35 | - add tc.image.RandomHue() 36 | - add tc.image.RandomSaturation() 37 | - add tc.image.RandomGamma() 38 | #### tensorcv-0.0.9 39 | - add tc.image.read_image() 40 | - add tc.image.RandomFlipLeftRight() 41 | - add tc.image.RandomFlipTopBottom() 42 | - add tc.image.RandomTranspose() 43 | - add tc.image.RandomRotation() 44 | #### tensorcv-0.0.8 45 | - add resnetv1b 46 | #### tensorcv-0.0.7 47 | - add resnext 48 | #### tensorcv-0.0.6 49 | - add squeezenet 50 | #### tensorcv-0.0.5 51 | - add resnet 52 | #### tensorcv-0.0.4 53 | - add inception 54 | #### tensorcv-0.0.3 55 | - add densenet, senet 56 | #### tensorcv-0.0.2 57 | - add vgg 58 | #### tensorcv-0.0.1 59 | - add alexnet 60 | -------------------------------------------------------------------------------- /image/keras_wechat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hourout/tensorcv/620559ee90921e036c8a84877d806a5c21010511/image/keras_wechat.jpg -------------------------------------------------------------------------------- /image/tensorcv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hourout/tensorcv/620559ee90921e036c8a84877d806a5c21010511/image/tensorcv.png -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description-file = README.md 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from io import open 2 | from setuptools import setup, find_packages 3 | 4 | def readme(): 5 | with open('README.md', encoding='utf-8') as f: 6 | return f.read() 7 | 8 | setup(name='tensorcv', 9 | version='0.3.0', 10 | install_requires=['tensorflow>=2.0.0'], 11 | description='tf.Keras implementations of a Deep Learning Toolkit for Computer Vision.', 12 | long_description=readme(), 13 | long_description_content_type='text/markdown', 14 | url='https://github.com/Hourout/tensorcv', 15 | author='JinQing Lee', 16 | author_email='hourout@163.com', 17 | keywords=['computer-vision', 'keras', 'tf.keras', 'deep-learning'], 18 | license='Apache License Version 2.0', 19 | classifiers=[ 20 | 'Intended Audience :: Developers', 21 | 'Intended Audience :: Education', 22 | 'Intended Audience :: Science/Research', 23 | 'Topic :: Scientific/Engineering', 24 | 'Topic :: Scientific/Engineering :: Artificial Intelligence', 25 | 'Topic :: Scientific/Engineering :: Visualization', 26 | 'License :: OSI Approved :: Apache Software License', 27 | 'Programming Language :: Python :: 3.5', 28 | 'Programming Language :: Python :: 3.6', 29 | 'Programming Language :: Python :: 3.7', 30 | ], 31 | packages=find_packages(), 32 | zip_safe=False) 33 | -------------------------------------------------------------------------------- /tensorcv/Classification/__init__.py: -------------------------------------------------------------------------------- 1 | from tensorcv.Classification._alexnet import alexnet 2 | 3 | from tensorcv.Classification._vgg import vgg11, vgg11_bn 4 | from tensorcv.Classification._vgg import vgg13, vgg13_bn 5 | from tensorcv.Classification._vgg import vgg16, vgg16_bn 6 | from tensorcv.Classification._vgg import vgg19, vgg19_bn 7 | 8 | from tensorcv.Classification._densenet import densenet121, densenet161, densenet169, densenet201 9 | 10 | from tensorcv.Classification._senet import senet_50, senet_101, senet_152 11 | 12 | from tensorcv.Classification._inception import inception_v3 13 | 14 | from tensorcv.Classification._resnet import resnet18_v1, resnet18_v2 15 | from tensorcv.Classification._resnet import resnet34_v1, resnet34_v2 16 | from tensorcv.Classification._resnet import resnet50_v1, resnet50_v2 17 | from tensorcv.Classification._resnet import resnet101_v1, resnet101_v2 18 | from tensorcv.Classification._resnet import resnet152_v1, resnet152_v2 19 | from tensorcv.Classification._resnet import se_resnet18_v1, se_resnet18_v2 20 | from tensorcv.Classification._resnet import se_resnet34_v1, se_resnet34_v2 21 | from tensorcv.Classification._resnet import se_resnet50_v1, se_resnet50_v2 22 | from tensorcv.Classification._resnet import se_resnet101_v1, se_resnet101_v2 23 | from tensorcv.Classification._resnet import se_resnet152_v1, se_resnet152_v2 24 | 25 | from tensorcv.Classification._squeezenet import squeezenet1_0, squeezenet1_1 26 | 27 | from tensorcv.Classification._resnext import resnext50_32x4d, se_resnext50_32x4d 28 | from tensorcv.Classification._resnext import resnext101_32x4d, se_resnext101_32x4d 29 | from tensorcv.Classification._resnext import resnext101_64x4d, se_resnext101_64x4d 30 | 31 | from tensorcv.Classification._resnetv1b import resnet18_v1b, resnet34_v1b 32 | from tensorcv.Classification._resnetv1b import resnet50_v1b, resnet101_v1b, resnet152_v1b 33 | from tensorcv.Classification._resnetv1b import resnet50_v1c, resnet101_v1c, resnet152_v1c 34 | from tensorcv.Classification._resnetv1b import resnet50_v1d, resnet101_v1d, resnet152_v1d 35 | from tensorcv.Classification._resnetv1b import resnet50_v1e, resnet101_v1e, resnet152_v1e 36 | from tensorcv.Classification._resnetv1b import resnet50_v1s, resnet101_v1s, resnet152_v1s 37 | 38 | from tensorcv.Classification._darknet import darknet53 39 | -------------------------------------------------------------------------------- /tensorcv/Classification/_alexnet.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | 3 | alexnet_url = None 4 | 5 | def Alexnet(tensor): 6 | x = tf.keras.layers.ZeroPadding2D(2)(tensor) 7 | x = tf.keras.layers.Conv2D(64, 11, 4, activation='relu')(x) 8 | x = tf.keras.layers.MaxPool2D(3, 2)(x) 9 | x = tf.keras.layers.ZeroPadding2D(2)(x) 10 | x = tf.keras.layers.Conv2D(192, 5, activation='relu')(x) 11 | x = tf.keras.layers.MaxPool2D(3, 2)(x) 12 | x = tf.keras.layers.ZeroPadding2D(1)(x) 13 | x = tf.keras.layers.Conv2D(384, 3, activation='relu')(x) 14 | x = tf.keras.layers.ZeroPadding2D(1)(x) 15 | x = tf.keras.layers.Conv2D(256, 3, activation='relu')(x) 16 | x = tf.keras.layers.ZeroPadding2D(1)(x) 17 | x = tf.keras.layers.Conv2D(256, 3, activation='relu')(x) 18 | x = tf.keras.layers.MaxPool2D(3, 2)(x) 19 | return x 20 | 21 | def get_alexnet(input_shape, include_top, pretrain_file, classes): 22 | if isinstance(pretrain_file, str) and include_top and classes != 1000: 23 | raise ValueError('If using `pretrain weights` with `include_top` as true, `classes` should be 1000') 24 | image = tf.keras.Input(shape=input_shape) 25 | x = Alexnet(image) 26 | if include_top: 27 | x = tf.keras.layers.Flatten()(x) 28 | x = tf.keras.layers.Dense(4096, activation='relu')(x) 29 | x = tf.keras.layers.Dropout(0.5)(x) 30 | x = tf.keras.layers.Dense(4096, activation='relu')(x) 31 | x = tf.keras.layers.Dropout(0.5)(x) 32 | x = tf.keras.layers.Dense(classes)(x) 33 | model = tf.keras.Model(image, x, name='alexnet') 34 | if isinstance(pretrain_file, str): 35 | if tf.gfile.Exists(pretrain_file): 36 | model.load_weights(pretrain_file) 37 | else: 38 | tf.gfile.MakeDirs(pretrain_file) 39 | tf.gfile.DeleteRecursively(pretrain_file) 40 | tf.keras.utils.get_file(pretrain_file, alexnet_url) 41 | model.load_weights(pretrain_file) 42 | return model 43 | 44 | def alexnet(input_shape, include_top=True, pretrain_file=False, classes=1000): 45 | r"""AlexNet model from the `"One weird trick..." `_ paper. 46 | Parameters 47 | ---------- 48 | input_shape : tuple of 3 ints, input image shape. 49 | include_top : whether to include the fully-connected layer at the top of the network. 50 | pretrain_file : bool or str 51 | Boolean value controls whether to load the default pretrained weights for model. 52 | String value represents the hashtag for a certain version of pretrained weights. 53 | String value must be absolute path of the pretrained weights file, 54 | if pretrain file is not exists, will auto create dir and download pretrained weights. 55 | classes: optional number of classes to classify images into, 56 | only to be specified if `include_top` is True. 57 | """ 58 | return get_alexnet(input_shape, include_top, pretrain_file, classes) 59 | -------------------------------------------------------------------------------- /tensorcv/Classification/_darknet.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | 3 | def _conv2d(tensor, channel, kernel, padding, stride): 4 | x = tf.keras.layers.ZeroPadding2D(padding)(tensor) 5 | x = tf.keras.layers.Conv2D(channel, kernel, stride, use_bias=False)(x) 6 | x = tf.keras.layers.BatchNormalization(epsilon=1e-5, momentum=0.9)(x) 7 | x = tf.keras.layers.LeakyReLU(0.1)(x) 8 | return x 9 | 10 | def DarknetBasicBlockV3(tensor, channel): 11 | x = _conv2d(tensor, channel, 1, 0, 1) 12 | x = _conv2d(x, channel, 3, 1, 1) 13 | x = tf.keras.layers.Add()([tensor, x]) 14 | return x 15 | 16 | def DarknetV3(tensor, layers, channels): 17 | assert len(layers) == len(channels) - 1, ( 18 | "len(channels) should equal to len(layers) + 1, given {} vs {}".format( 19 | len(channels), len(layers))) 20 | x = _conv2d(tensor, channels[0], 3, 1, 1) 21 | for nlayer, channel in zip(layers, channels[1:]): 22 | assert channel % 2 == 0, "channel {} cannot be divided by 2".format(channel) 23 | x = _conv2d(x, channel, 3, 1, 2) 24 | for _ in range(nlayer): 25 | x = DarknetBasicBlockV3(x, channel // 2) 26 | return x 27 | 28 | 29 | darknet_versions = {'v3': DarknetV3} 30 | darknet_spec = {'v3': {53: ([1, 2, 8, 8, 4], [32, 64, 128, 256, 512, 1024]),}} 31 | 32 | def get_darknet(mode, num_layers, input_shape, include_top, pretrain_file, classes): 33 | specs = darknet_spec[mode] 34 | assert num_layers in specs, "Invalid number of layers: {}. Options are {}".format(num_layers, str(specs.keys())) 35 | layers, channels = specs[num_layers] 36 | darknet_class = darknet_versions[mode] 37 | image = tf.keras.Input(shape=input_shape) 38 | x = darknet_class(image, layers, channels) 39 | if include_top: 40 | x = tf.keras.layers.GlobalAvgPool2D()(x) 41 | x = tf.keras.layers.Dense(classes)(x) 42 | model = tf.keras.Model(image, x) 43 | if isinstance(pretrain_file, str): 44 | if tf.gfile.Exists(pretrain_file): 45 | model.load_weights(pretrain_file, by_name=True) 46 | else: 47 | tf.gfile.MakeDirs(pretrain_file) 48 | tf.gfile.DeleteRecursively(pretrain_file) 49 | tf.keras.utils.get_file(pretrain_file, alexnet_url) 50 | model.load_weights(pretrain_file, by_name=True) 51 | return model 52 | 53 | def darknet53(input_shape, include_top=True, pretrain_file=False, classes=1000): 54 | return get_darknet('v3', 53, input_shape, include_top, pretrain_file, classes) 55 | -------------------------------------------------------------------------------- /tensorcv/Classification/_densenet.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | 3 | densenet_url = {'densenet121': None, 4 | 'densenet161': None, 5 | 'densenet169': None, 6 | 'densenet201': None} 7 | 8 | densenet_spec = {121: (64, 32, [6, 12, 24, 16]), 9 | 161: (96, 48, [6, 12, 36, 24]), 10 | 169: (64, 32, [6, 12, 32, 32]), 11 | 201: (64, 32, [6, 12, 48, 32])} 12 | 13 | def DenseNet(tensor, num_init_features, growth_rate, block_config): 14 | x = tf.keras.layers.ZeroPadding2D(padding=((3, 3), (3, 3)))(tensor) 15 | x = tf.keras.layers.Conv2D(num_init_features, 7, 2, use_bias=False)(x) 16 | x = tf.keras.layers.BatchNormalization()(x) 17 | x = tf.keras.layers.ReLU()(x) 18 | x = tf.keras.layers.ZeroPadding2D(padding=((1, 1), (1, 1)))(x) 19 | x = tf.keras.layers.MaxPool2D(3, 2)(x) 20 | num_features = num_init_features 21 | for i, num_layers in enumerate(block_config): 22 | for j in range(num_layers): 23 | x = tf.keras.layers.BatchNormalization()(x) 24 | x = tf.keras.layers.ReLU()(x) 25 | x = tf.keras.layers.Conv2D(bn_size * growth_rate, 1, use_bias=False)(x) 26 | x = tf.keras.layers.BatchNormalization()(x) 27 | x = tf.keras.layers.ReLU()(x) 28 | x = tf.keras.layers.ZeroPadding2D(padding=((1, 1), (1, 1)))(x) 29 | x = tf.keras.layers.Conv2D(growth_rate, 3, use_bias=False)(x) 30 | num_features = num_features + num_layers * growth_rate 31 | if i != len(block_config) - 1: 32 | x = tf.keras.layers.BatchNormalization()(x) 33 | x = tf.keras.layers.ReLU()(x) 34 | x = tf.keras.layers.Conv2D(num_features // 2, 1, use_bias=False)(x) 35 | x = tf.keras.layers.AvgPool2D(2, 2)(x) 36 | num_features = num_features // 2 37 | x = tf.keras.layers.BatchNormalization()(x) 38 | x = tf.keras.layers.ReLU()(x) 39 | x = tf.keras.layers.AvgPool2D(7)(x) 40 | return x 41 | 42 | def get_densenet(num_layers, mode, input_shape, include_top, pretrain_file, classes): 43 | if isinstance(pretrain_file, str) and include_top and classes != 1000: 44 | raise ValueError('If using `pretrain weights` with `include_top` as true, `classes` should be 1000') 45 | num_init_features, growth_rate, block_config = densenet_spec[num_layers] 46 | image = tf.keras.Input(shape=input_shape) 47 | x = DenseNet(image, num_init_features, growth_rate, block_config) 48 | if include_top: 49 | x = tf.keras.layers.Flatten()(x) 50 | x = tf.keras.layers.Dense(classes)(x) 51 | model = tf.keras.Model(image, x, name=mode) 52 | if isinstance(pretrain_file, str): 53 | if tf.gfile.Exists(pretrain_file): 54 | model.load_weights(pretrain_file, by_name=True) 55 | else: 56 | tf.gfile.MakeDirs(pretrain_file) 57 | tf.gfile.DeleteRecursively(pretrain_file) 58 | tf.keras.utils.get_file(pretrain_file, densenet_url(mode)) 59 | model.load_weights(pretrain_file, by_name=True) 60 | return model 61 | 62 | def densenet121(input_shape, include_top=True, pretrain_file=False, classes=1000): 63 | return get_densenet(121, 'densenet121', input_shape, include_top, pretrain_file, classes) 64 | 65 | def densenet161(input_shape, include_top=True, pretrain_file=False, classes=1000): 66 | return get_densenet(161, 'densenet161', input_shape, include_top, pretrain_file, classes) 67 | 68 | def densenet169(input_shape, include_top=True, pretrain_file=False, classes=1000): 69 | return get_densenet(169, 'densenet169', input_shape, include_top, pretrain_file, classes) 70 | 71 | def densenet201(input_shape, include_top=True, pretrain_file=False, classes=1000): 72 | return get_densenet(201, 'densenet201', input_shape, include_top, pretrain_file, classes) 73 | -------------------------------------------------------------------------------- /tensorcv/Classification/_inception.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | 3 | inception3_url = None 4 | 5 | def _make_branch(tensor, use_pool, *conv_settings): 6 | if use_pool == 'avg': 7 | x = tf.keras.layers.ZeroPadding2D(((1,1), (1,1)))(tensor) 8 | x = tf.keras.layers.AvgPool2D(3, 1)(x) 9 | elif use_pool == 'max': 10 | x = tf.keras.layers.MaxPool2D(pool_size=3, strides=2)(tensor) 11 | for setting in conv_settings: 12 | if setting[3] is not None: 13 | x = tf.keras.layers.ZeroPadding2D(setting[3])(x) 14 | x = tf.keras.layers.Conv2D(setting[0], setting[1], setting[2], use_bias=False)(x) 15 | x = tf.keras.layers.BatchNormalization()(x) 16 | x = tf.keras.layers.ReLU()(x) 17 | return x 18 | 19 | def _make_A(tensor, pool_features): 20 | a1 = _make_branch(tensor, None, (64, 1, 1, None)) 21 | a2 = _make_branch(tensor, None, (48, 1, 1, None), (64, 5, 1, 2)) 22 | a3 = _make_branch(tensor, None, (64, 1, 1, None), (96, 3, 1, 1), (96, 3, 1, 1)) 23 | a4 = _make_branch(tensor, 'avg', (pool_features, 1, 1, None)) 24 | x = tf.keras.layers.Concatenate()([a1, a2, a3, a4]) 25 | return x 26 | 27 | def _make_B(tensor): 28 | a1 = _make_branch(tensor, None, (384, 3, 2, None)) 29 | a2 = _make_branch(tensor, None, (64, 1, 1, None), (96, 3, 1, 1), (96, 3, 2, None)) 30 | a3 = _make_branch(tensor, 'max') 31 | x = tf.keras.layers.Concatenate()([a1, a2, a3]) 32 | return x 33 | 34 | def _make_C(tensor, channels_7x7): 35 | a1 = _make_branch(tensor, None, (192, 1, 1, None)) 36 | a2 = _make_branch(tensor, None, (channels_7x7, 1, 1, None), (channels_7x7, (1, 7), 1, (0, 3)), (192, (7, 1), 1, (3, 0))) 37 | a3 = _make_branch(tensor, None, (channels_7x7, 1, 1, None), (channels_7x7, (7, 1), 1, (3, 0)), (channels_7x7, (1, 7), 1, (0, 3)), 38 | (channels_7x7, (7, 1), 1, (3, 0)), (192, (1, 7), 1, (0, 3))) 39 | a4 = _make_branch(tensor, 'avg', (192, 1, 1, None)) 40 | x = tf.keras.layers.Concatenate()([a1, a2, a3, a4]) 41 | return x 42 | 43 | def _make_D(tensor): 44 | a1 = _make_branch(tensor, None, (192, 1, 1, None), (320, 3, 2, None)) 45 | a2 = _make_branch(tensor, None, (192, 1, 1, None), (192, (1, 7), 1, (0, 3)), (192, (7, 1), 1, (3, 0)), (192, 3, 2, None)) 46 | a3 = _make_branch(tensor, 'max') 47 | x = tf.keras.layers.Concatenate()([a1, a2, a3]) 48 | return x 49 | 50 | 51 | def _make_E(tensor): 52 | a1 = _make_branch(tensor, None, (320, 1, 1, None)) 53 | a2 = _make_branch(tensor, None, (384, 1, 1, None)) 54 | a3 = _make_branch(a2, None, (384, (1, 3), 1, (0, 1))) 55 | a4 = _make_branch(a2, None, (384, (3, 1), 1, (1, 0))) 56 | a5 = tf.keras.layers.Concatenate()([a3, a4]) 57 | a6 = _make_branch(tensor, None, (448, 1, 1, None), (384, 3, 1, 1)) 58 | a7 = _make_branch(a6, None, (384, (1, 3), 1, (0, 1))) 59 | a8 = _make_branch(a6, None, (384, (3, 1), 1, (1, 0))) 60 | a9 = tf.keras.layers.Concatenate()([a7, a8]) 61 | a10 = _make_branch(tensor, 'avg', (192, 1, 1, None)) 62 | x = tf.keras.layers.Concatenate()([a1, a5, a9, a10]) 63 | return x 64 | 65 | def Inception3(tensor): 66 | x = tf.keras.layers.Conv2D(32, 3, 2, use_bias=False)(tensor) 67 | x = tf.keras.layers.BatchNormalization()(x) 68 | x = tf.keras.layers.ReLU()(x) 69 | x = tf.keras.layers.Conv2D(32, 3, 1, use_bias=False)(x) 70 | x = tf.keras.layers.BatchNormalization()(x) 71 | x = tf.keras.layers.ReLU()(x) 72 | x = tf.keras.layers.ZeroPadding2D(((1,1), (1,1)))(x) 73 | x = tf.keras.layers.Conv2D(64, 3, 1, use_bias=False)(x) 74 | x = tf.keras.layers.BatchNormalization()(x) 75 | x = tf.keras.layers.ReLU()(x) 76 | x = tf.keras.layers.MaxPool2D(3, 2)(x) 77 | x = tf.keras.layers.Conv2D(80, 1, 1, use_bias=False)(x) 78 | x = tf.keras.layers.BatchNormalization()(x) 79 | x = tf.keras.layers.ReLU()(x) 80 | x = tf.keras.layers.Conv2D(192, 3, 1, use_bias=False)(x) 81 | x = tf.keras.layers.BatchNormalization()(x) 82 | x = tf.keras.layers.ReLU()(x) 83 | x = tf.keras.layers.MaxPool2D(3, 2)(x) 84 | x = _make_A(x, 32) 85 | x = _make_A(x, 64) 86 | x = _make_A(x, 64) 87 | x = _make_B(x) 88 | x = _make_C(x, 128) 89 | x = _make_C(x, 160) 90 | x = _make_C(x, 160) 91 | x = _make_C(x, 192) 92 | x = _make_D(x) 93 | x = _make_E(x) 94 | x = _make_E(x) 95 | x = tf.keras.layers.AvgPool2D(8)(x) 96 | return x 97 | 98 | def inception_v3(input_shape, include_top=True, pretrain_file=False, classes=1000): 99 | if isinstance(pretrain_file, str) and include_top and classes != 1000: 100 | raise ValueError('If using `pretrain weights` with `include_top` as true, `classes` should be 1000') 101 | image = tf.keras.Input(shape=input_shape) 102 | x = Inception3(image) 103 | if include_top: 104 | x = tf.keras.layers.Flatten()(x) 105 | x = tf.keras.layers.Dropout(0.5)(x) 106 | x = tf.keras.layers.Dense(classes)(x) 107 | model = tf.keras.Model(image, x) 108 | if isinstance(pretrain_file, str): 109 | if tf.gfile.Exists(pretrain_file): 110 | model.load_weights(pretrain_file, by_name=True) 111 | else: 112 | tf.gfile.MakeDirs(pretrain_file) 113 | tf.gfile.DeleteRecursively(pretrain_file) 114 | tf.keras.utils.get_file(pretrain_file, inception3_url) 115 | model.load_weights(pretrain_file, by_name=True) 116 | return model 117 | -------------------------------------------------------------------------------- /tensorcv/Classification/_resnet.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | 3 | 4 | def BasicBlockV1(tensor, channels, stride, downsample=False, last_gamma=False, use_se=False): 5 | x = tf.keras.layers.ZeroPadding2D(1)(tensor) 6 | x = tf.keras.layers.Conv2D(channels, 3, stride, use_bias=False)(x) 7 | x = tf.keras.layers.BatchNormalization()(x) 8 | x = tf.keras.layers.ReLU()(body) 9 | x = tf.keras.layers.ZeroPadding2D(1)(x) 10 | x = tf.keras.layers.Conv2D(channels, 3, use_bias=False)(x) 11 | if not last_gamma: 12 | x = tf.keras.layers.BatchNormalization()(x) 13 | else: 14 | x = tf.keras.layers.BatchNormalization(gamma_initializer='zeros')(x) 15 | if use_se: 16 | se = tf.keras.layers.GlobalAvgPool2D()(x) 17 | se = tf.keras.layers.Dense(channels//16, activation='relu', use_bias=False)(se) 18 | se = tf.keras.layers.Dense(channels, activation='sigmoid', use_bias=False)(se) 19 | se = tf.keras.layers.Reshape((1,1,channels))(se) 20 | se = tf.keras.layers.Lambda(lambda x:tf.broadcast_to(x, [x.shape.as_list()[0], x.shape.as_list()[1], channels]))(se) 21 | x = tf.keras.layers.Multiply()([se, x]) 22 | if downsample: 23 | ds = tf.keras.layers.Conv2D(channels, 1, stride, use_bias=False)(tensor) 24 | ds = tf.keras.layers.BatchNormalization()(ds) 25 | x = tf.keras.layers.Add()([ds, x]) 26 | else: 27 | x = tf.keras.layers.Add()([tensor, x]) 28 | x = tf.keras.layers.ReLU()(x) 29 | return x 30 | 31 | def BottleneckV1(tensor, channels, stride, downsample=False, last_gamma=False, use_se=False): 32 | x = tf.keras.layers.Conv2D(channels//4, 1, stride)(tensor) 33 | x = tf.keras.layers.BatchNormalization()(x) 34 | x = tf.keras.layers.ReLU()(x) 35 | x = tf.keras.layers.ZeroPadding2D(1)(x) 36 | x = tf.keras.layers.Conv2D(channels//4, 3, use_bias=False)(x) 37 | x = tf.keras.layers.BatchNormalization()(x) 38 | x = tf.keras.layers.ReLU()(x) 39 | x = tf.keras.layers.Conv2D(channels, 1)(x) 40 | if not last_gamma: 41 | x = tf.keras.layers.BatchNormalization()(x) 42 | else: 43 | x = tf.keras.layers.BatchNormalization(gamma_initializer='zeros')(x) 44 | if use_se: 45 | se = tf.keras.layers.GlobalAvgPool2D()(x) 46 | se = tf.keras.layers.Dense(channels//16, activation='relu', use_bias=False)(se) 47 | se = tf.keras.layers.Dense(channels, activation='sigmoid', use_bias=False)(se) 48 | se = tf.keras.layers.Reshape((1,1,channels))(se) 49 | se = tf.keras.layers.Lambda(lambda x:tf.broadcast_to(x, [x.shape.as_list()[0], x.shape.as_list()[1], channels]))(se) 50 | x = tf.keras.layers.Multiply()([se, x]) 51 | if downsample: 52 | ds = tf.keras.layers.Conv2D(channels, 1, stride, use_bias=False)(tensor) 53 | ds = tf.keras.layers.BatchNormalization()(ds) 54 | x = tf.keras.layers.Add()([ds, x]) 55 | else: 56 | x = tf.keras.layers.Add()([tensor, x]) 57 | x = tf.keras.layers.ReLU()(x) 58 | return x 59 | 60 | def BasicBlockV2(tensor, channels, stride, downsample=False, last_gamma=False, use_se=False): 61 | x = tf.keras.layers.BatchNormalization()(tensor) 62 | x = tf.keras.layers.ReLU()(x) 63 | if downsample: 64 | ds = tf.keras.layers.Conv2D(channels, 1, stride, use_bias=False)(x) 65 | x = tf.keras.layers.ZeroPadding2D(1)(x) 66 | x = tf.keras.layers.Conv2D(channels, 3, stride, use_bias=False)(x) 67 | if not last_gamma: 68 | x = tf.keras.layers.BatchNormalization()(x) 69 | else: 70 | x = tf.keras.layers.BatchNormalization(gamma_initializer='zeros')(x) 71 | x = tf.keras.layers.ReLU()(x) 72 | x = tf.keras.layers.ZeroPadding2D(1)(x) 73 | x = tf.keras.layers.Conv2D(channels, 3, use_bias=False)(x) 74 | if use_se: 75 | se = tf.keras.layers.GlobalAvgPool2D()(x) 76 | se = tf.keras.layers.Dense(channels//16, activation='relu', use_bias=False)(se) 77 | se = tf.keras.layers.Dense(channels, activation='sigmoid', use_bias=False)(se) 78 | se = tf.keras.layers.Reshape((1,1,channels))(se) 79 | se = tf.keras.layers.Lambda(lambda x:tf.broadcast_to(x, [x.shape.as_list()[0], x.shape.as_list()[1], channels]))(se) 80 | x = tf.keras.layers.Multiply()([se, x]) 81 | if downsample: 82 | x = tf.keras.layers.Add()([ds, x]) 83 | else: 84 | x = tf.keras.layers.Add()([tensor, x]) 85 | return x 86 | 87 | def BottleneckV2(tensor, channels, stride, downsample=False, last_gamma=False, use_se=False): 88 | x = tf.keras.layers.BatchNormalization()(tensor) 89 | x = tf.keras.layers.ReLU()(x) 90 | if downsample: 91 | ds = tf.keras.layers.Conv2D(channels, 1, stride, use_bias=False)(x) 92 | x = tf.keras.layers.Conv2D(channels//4, 1, use_bias=False)(x) 93 | x = tf.keras.layers.BatchNormalization()(x) 94 | x = tf.keras.layers.ReLU()(x) 95 | x = tf.keras.layers.ZeroPadding2D(1)(x) 96 | x = tf.keras.layers.Conv2D(channels//4, 3, stride, use_bias=False)(x) 97 | if not last_gamma: 98 | x = tf.keras.layers.BatchNormalization()(x) 99 | else: 100 | x = tf.keras.layers.BatchNormalization(gamma_initializer='zeros')(x) 101 | x = tf.keras.layers.ReLU()(x) 102 | x = tf.keras.layers.Conv2D(channels, 1, use_bias=False)(x) 103 | if use_se: 104 | se = tf.keras.layers.GlobalAvgPool2D()(x) 105 | se = tf.keras.layers.Dense(channels//16, activation='relu', use_bias=False)(se) 106 | se = tf.keras.layers.Dense(channels, activation='sigmoid', use_bias=False)(se) 107 | se = tf.keras.layers.Reshape((1,1,channels))(se) 108 | se = tf.keras.layers.Lambda(lambda x:tf.broadcast_to(x, [x.shape.as_list()[0], x.shape.as_list()[1], channels]))(se) 109 | x = tf.keras.layers.Multiply()([se, x]) 110 | if downsample: 111 | x = tf.keras.layers.Add()([ds, x]) 112 | else: 113 | x = tf.keras.layers.Add()([tensor, x]) 114 | return x 115 | 116 | def ResNetV1(tensor, block, layers, channels, thumbnail=False, last_gamma=False, use_se=False): 117 | assert len(layers) == len(channels) - 1 118 | if thumbnail: 119 | x = tf.keras.layers.ZeroPadding2D(1)(tensor) 120 | x = tf.keras.layers.Conv2D(channels[0], 3, use_bias=False)(x) 121 | else: 122 | x = tf.keras.layers.ZeroPadding2D(3)(tensor) 123 | x = tf.keras.layers.Conv2D(channels[0], 7, 2, use_bias=False)(x) 124 | x = tf.keras.layers.BatchNormalization()(x) 125 | x = tf.keras.layers.ReLU()(x) 126 | x = tf.keras.layers.MaxPool2D(3, 2)(x) 127 | for i, num_layer in enumerate(layers): 128 | stride = 1 if i == 0 else 2 129 | x = block(x, channels[i+1], stride, channels[i+1]!=channels[i], last_gamma, use_se) 130 | for _ in range(num_layer-1): 131 | x = block(x, channels[i+1], 1, False, last_gamma, use_se) 132 | return x 133 | 134 | def ResNetV2(tensor, block, layers, channels, thumbnail=False, last_gamma=False, use_se=False): 135 | assert len(layers) == len(channels) - 1 136 | x = tf.keras.layers.BatchNormalization(scale=False, center=False)(tensor) 137 | if thumbnail: 138 | x = tf.keras.layers.ZeroPadding2D(1)(x) 139 | x = tf.keras.layers.Conv2D(channels[0], 3, use_bias=False)(x) 140 | else: 141 | x = tf.keras.layers.ZeroPadding2D(3)(x) 142 | x = tf.keras.layers.Conv2D(channels[0], 7, 2, use_bias=False)(x) 143 | x = tf.keras.layers.BatchNormalization()(x) 144 | x = tf.keras.layers.ReLU()(x) 145 | x = tf.keras.layers.MaxPool2D(3, 2)(x) 146 | in_channels = channels[0] 147 | for i, num_layer in enumerate(layers): 148 | stride = 1 if i == 0 else 2 149 | x = block(x, channels[i+1], stride, channels[i+1]!=in_channels, last_gamma, use_se) 150 | for _ in range(num_layer-1): 151 | x = block(x, channels[i+1], 1, False, last_gamma, use_se) 152 | in_channels = channels[i+1] 153 | x = tf.keras.layers.BatchNormalization()(x) 154 | x = tf.keras.layers.ReLU()(x) 155 | return x 156 | 157 | resnet_spec = {18: ('basic_block', [2, 2, 2, 2], [64, 64, 128, 256, 512]), 158 | 34: ('basic_block', [3, 4, 6, 3], [64, 64, 128, 256, 512]), 159 | 50: ('bottle_neck', [3, 4, 6, 3], [64, 256, 512, 1024, 2048]), 160 | 101: ('bottle_neck', [3, 4, 23, 3], [64, 256, 512, 1024, 2048]), 161 | 152: ('bottle_neck', [3, 8, 36, 3], [64, 256, 512, 1024, 2048])} 162 | 163 | resnet_net_versions = [ResNetV1, ResNetV2] 164 | resnet_block_versions = [{'basic_block': BasicBlockV1, 'bottle_neck': BottleneckV1}, 165 | {'basic_block': BasicBlockV2, 'bottle_neck': BottleneckV2}] 166 | 167 | resnet_url = {'resnet18_v1':None, 168 | 'resnet34_v1':None, 169 | 'resnet50_v1':None, 170 | 'resnet101_v1':None, 171 | 'resnet152_v1':None, 172 | 'resnet18_v2':None, 173 | 'resnet34_v2':None, 174 | 'resnet50_v2':None, 175 | 'resnet101_v2':None, 176 | 'resnet152_v2':None, 177 | 'se_resnet18_v1':None, 178 | 'se_resnet34_v1':None, 179 | 'se_resnet50_v1':None, 180 | 'se_resnet101_v1':None, 181 | 'se_resnet152_v1':None, 182 | 'se_resnet18_v2':None, 183 | 'se_resnet34_v2':None, 184 | 'se_resnet34_v2':None, 185 | 'se_resnet101_v2':None, 186 | 'se_resnet152_v2':None} 187 | 188 | def get_resnet(version, num_layers, mode, input_shape, include_top, pretrain_file, classes, use_se): 189 | assert num_layers in resnet_spec, "Invalid number of layers: %d. Options are %s"%(num_layers, str(resnet_spec.keys())) 190 | assert 1 <= version <= 2, "Invalid resnet version: %d. Options are 1 and 2."%version 191 | if isinstance(pretrain_file, str) and include_top and classes != 1000: 192 | raise ValueError('If using `pretrain weights` with `include_top` as true, `classes` should be 1000') 193 | block_type, layers, channels = resnet_spec[num_layers] 194 | resnet_class = resnet_net_versions[version-1] 195 | block_class = resnet_block_versions[version-1][block_type] 196 | 197 | image = tf.keras.Input(shape=input_shape) 198 | x = resnet_class(image, block_class, layers, channels, use_se=use_se) 199 | if include_top: 200 | x = tf.keras.layers.GlobalAvgPool2D()(x) 201 | x = tf.keras.layers.Dense(classes)(x) 202 | model = tf.keras.Model(image, x, name=mode) 203 | 204 | if isinstance(pretrain_file, str): 205 | if tf.gfile.Exists(pretrain_file): 206 | model.load_weights(pretrain_file) 207 | else: 208 | tf.gfile.MakeDirs(pretrain_file) 209 | tf.gfile.DeleteRecursively(pretrain_file) 210 | tf.keras.utils.get_file(pretrain_file, resnet_url(mode)) 211 | model.load_weights(pretrain_file) 212 | return model 213 | 214 | def resnet18_v1(input_shape, include_top=True, pretrain_file=False, classes=1000): 215 | return get_resnet(1, 18, 'resnet18_v1', input_shape, include_top, pretrain_file, classes, False) 216 | 217 | def resnet34_v1(input_shape, include_top=True, pretrain_file=False, classes=1000): 218 | return get_resnet(1, 34, 'resnet34_v1', input_shape, include_top, pretrain_file, classes, False) 219 | 220 | def resnet50_v1(input_shape, include_top=True, pretrain_file=False, classes=1000): 221 | return get_resnet(1, 50, 'resnet50_v1', input_shape, include_top, pretrain_file, classes, False) 222 | 223 | def resnet101_v1(input_shape, include_top=True, pretrain_file=False, classes=1000): 224 | return get_resnet(1, 101, 'resnet101_v1', input_shape, include_top, pretrain_file, classes, False) 225 | 226 | def resnet152_v1(input_shape, include_top=True, pretrain_file=False, classes=1000): 227 | return get_resnet(1, 152, 'resnet152_v1', input_shape, include_top, pretrain_file, classes, False) 228 | 229 | def resnet18_v2(input_shape, include_top=True, pretrain_file=False, classes=1000): 230 | return get_resnet(2, 18, 'resnet18_v2', input_shape, include_top, pretrain_file, classes, False) 231 | 232 | def resnet34_v2(input_shape, include_top=True, pretrain_file=False, classes=1000): 233 | return get_resnet(2, 34, 'resnet34_v2', input_shape, include_top, pretrain_file, classes, False) 234 | 235 | def resnet50_v2(input_shape, include_top=True, pretrain_file=False, classes=1000): 236 | return get_resnet(2, 50, 'resnet50_v2', input_shape, include_top, pretrain_file, classes, False) 237 | 238 | def resnet101_v2(input_shape, include_top=True, pretrain_file=False, classes=1000): 239 | return get_resnet(2, 101, 'resnet101_v2',input_shape, include_top, pretrain_file, classes, False) 240 | 241 | def resnet152_v2(input_shape, include_top=True, pretrain_file=False, classes=1000): 242 | return get_resnet(2, 152, 'resnet152_v2', input_shape, include_top, pretrain_file, classes, False) 243 | 244 | def se_resnet18_v1(input_shape, include_top=True, pretrain_file=False, classes=1000): 245 | return get_resnet(1, 18, 'se_resnet18_v1', input_shape, include_top, pretrain_file, classes, True) 246 | 247 | def se_resnet34_v1(input_shape, include_top=True, pretrain_file=False, classes=1000): 248 | return get_resnet(1, 34, 'se_resnet34_v1', input_shape, include_top, pretrain_file, classes, True) 249 | 250 | def se_resnet50_v1(input_shape, include_top=True, pretrain_file=False, classes=1000): 251 | return get_resnet(1, 50, 'se_resnet50_v1', input_shape, include_top, pretrain_file, classes, True) 252 | 253 | def se_resnet101_v1(input_shape, include_top=True, pretrain_file=False, classes=1000): 254 | return get_resnet(1, 101, 'se_resnet101_v1', input_shape, include_top, pretrain_file, classes, True) 255 | 256 | def se_resnet152_v1(input_shape, include_top=True, pretrain_file=False, classes=1000): 257 | return get_resnet(1, 152, 'se_resnet152_v1', input_shape, include_top, pretrain_file, classes, True) 258 | 259 | def se_resnet18_v2(input_shape, include_top=True, pretrain_file=False, classes=1000): 260 | return get_resnet(2, 18, 'se_resnet18_v2', input_shape, include_top, pretrain_file, classes, True) 261 | 262 | def se_resnet34_v2(input_shape, include_top=True, pretrain_file=False, classes=1000): 263 | return get_resnet(2, 34, 'se_resnet34_v2', input_shape, include_top, pretrain_file, classes, True) 264 | 265 | def se_resnet50_v2(input_shape, include_top=True, pretrain_file=False, classes=1000): 266 | return get_resnet(2, 50, 'se_resnet34_v2', input_shape, include_top, pretrain_file, classes, True) 267 | 268 | def se_resnet101_v2(input_shape, include_top=True, pretrain_file=False, classes=1000): 269 | return get_resnet(2, 101, 'se_resnet101_v2', input_shape, include_top, pretrain_file, classes, True) 270 | 271 | def se_resnet152_v2(input_shape, include_top=True, pretrain_file=False, classes=1000): 272 | return get_resnet(2, 152, 'se_resnet152_v2', input_shape, include_top, pretrain_file, classes, True) 273 | -------------------------------------------------------------------------------- /tensorcv/Classification/_resnetv1b.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | 3 | def BasicBlockV1b(tensor, channels, strides, dilation, downsample, previous_dilation, last_gamma, avg_down): 4 | expansion = 1 5 | x = tf.keras.layers.ZeroPadding2D(dilation)(tensor) 6 | x = tf.keras.layers.Conv2D(channels, 3, strides, dilation_rate=dilation, use_bias=False)(x) 7 | x = tf.keras.layers.BatchNormalization()(x) 8 | x = tf.keras.layers.ReLU()(x) 9 | x = tf.keras.layers.ZeroPadding2D(previous_dilation)(x) 10 | x = tf.keras.layers.Conv2D(channels, 3, dilation_rate=previous_dilation, use_bias=False)(x) 11 | x = tf.keras.layers.BatchNormalization()(x) 12 | if downsample: 13 | if avg_down: 14 | if dilation == 1: 15 | ds = tf.keras.layers.AvgPool2D(strides, strides)(tensor) 16 | else: 17 | ds = tf.keras.layers.AvgPool2D(1, 1)(tensor) 18 | ds = tf.keras.layers.Conv2D(channels*expansion, 1, use_bias=False)(ds) 19 | ds = tf.keras.layers.BatchNormalization()(ds) 20 | else: 21 | ds = tf.keras.layers.Conv2D(channels*expansion, 1, strides, use_bias=False)(tensor) 22 | ds = tf.keras.layers.BatchNormalization()(ds) 23 | x = tf.keras.layers.Add()([ds, x]) 24 | else: 25 | x = tf.keras.layers.Add()([tensor, x]) 26 | x = tf.keras.layers.ReLU()(x) 27 | return x 28 | 29 | def BottleneckV1b(tensor, channels, strides, dilation, downsample, previous_dilation, last_gamma, avg_down): 30 | expansion = 4 31 | x = tf.keras.layers.Conv2D(channels, 1, use_bias=False)(tensor) 32 | x = tf.keras.layers.BatchNormalization()(x) 33 | x = tf.keras.layers.ReLU()(x) 34 | x = tf.keras.layers.ZeroPadding2D(dilation)(x) 35 | x = tf.keras.layers.Conv2D(channels, 3, strides, dilation_rate=dilation, use_bias=False)(x) 36 | x = tf.keras.layers.BatchNormalization()(x) 37 | x = tf.keras.layers.ReLU()(x) 38 | x = tf.keras.layers.Conv2D(channel*4, 1, use_bias=False)(x) 39 | if not last_gamma: 40 | x = tf.keras.layers.BatchNormalization()(x) 41 | else: 42 | x = tf.keras.layers.BatchNormalization(gamma_initializer='zeros')(x) 43 | if downsample: 44 | if avg_down: 45 | if dilation == 1: 46 | ds = tf.keras.layers.AvgPool2D(strides, strides)(tensor) 47 | else: 48 | ds = tf.keras.layers.AvgPool2D(1, 1)(tensor) 49 | ds = tf.keras.layers.nn.Conv2D(channels*expansion, 1, use_bias=False)(ds) 50 | ds = tf.keras.layers.BatchNormalization()(ds) 51 | else: 52 | ds = tf.keras.layers.Conv2D(channels*expansion, 1, strides, use_bias=False)(tensor) 53 | ds = tf.keras.layers.BatchNormalization()(ds) 54 | x = tf.keras.layers.Add()([ds, x]) 55 | else: 56 | x = tf.keras.layers.Add()([tensor, x]) 57 | x = tf.keras.layers.ReLU()(x) 58 | return x 59 | 60 | def ResNetV1b(tensor, block, layers, expansion, dilated=False, last_gamma=False, deep_stem=False, stem_width=32, avg_down=False): 61 | inplanes = stem_width*2 if deep_stem else 64 62 | if not deep_stem: 63 | x = tf.keras.layers.ZeroPadding2D(3)(tensor) 64 | x = tf.keras.layers.Conv2D(64, 7, 2, use_bias=False)(x) 65 | else: 66 | x = tf.keras.layers.ZeroPadding2D(1)(tensor) 67 | x = tf.keras.layers.Conv2D(stem_width, 3, 2, use_bias=False)(x) 68 | x = tf.keras.layers.BatchNormalization()(x) 69 | x = tf.keras.layers.ReLU()(x) 70 | x = tf.keras.layers.ZeroPadding2D(1)(x) 71 | x = tf.keras.layers.Conv2D(stem_width, 3, use_bias=False)(x) 72 | x = tf.keras.layers.BatchNormalization()(x) 73 | x = tf.keras.layers.ReLU()(x) 74 | x = tf.keras.layers.ZeroPadding2D(1)(x) 75 | x = tf.keras.layers.Conv2D(stem_width*2, 3, use_bias=False)(x) 76 | x = tf.keras.layers.BatchNormalization()(x) 77 | x = tf.keras.layers.ReLU()(x) 78 | x = tf.keras.layers.ZeroPadding2D(1)(x) 79 | x = tf.keras.layers.MaxPool2D(3, 2)(x) 80 | x, inplanes = _make_layer(x, inplanes, block, 64, layers[0], 1, 1, avg_down, last_gamma) 81 | x, inplanes = _make_layer(x, inplanes, block, 128, layers[1], 2, 1, avg_down, last_gamma) 82 | if dilated: 83 | x, inplanes= _make_layer(x, inplanes, block, 256, layers[2], 1, 2, avg_down, last_gamma) 84 | x, inplanes = _make_layer(x, inplanes, block, 512, layers[3], 1, 4, avg_down, last_gamma) 85 | else: 86 | x, inplanes = _make_layer(x, inplanes, block, 256, layers[2], 2, 1, avg_down, last_gamma) 87 | x, inplanes = _make_layer(x, inplanes, block, 512, layers[3], 2, 1, avg_down, last_gamma) 88 | 89 | def _make_layer(tensor, inplanes, block, channels, blocks, strides=1, dilation=1, avg_down=False, last_gamma=False): 90 | downsample = strides != 1 or inplanes != channels * expansion 91 | if dilation in (1, 2): 92 | x = block(tensor, channels, strides, 1, downsample, dilation, last_gamma, avg_down) 93 | elif dilation == 4: 94 | x = block(tensor, channels, strides, 2, downsample, dilation, last_gamma, avg_down) 95 | else: 96 | raise RuntimeError("=> unknown dilation size: {}".format(dilation)) 97 | inplanes = channels * expansion 98 | for i in range(1, blocks): 99 | x = block(x, channels, 1, dilation, False, dilation, last_gamma) 100 | return x, inplanes 101 | return x 102 | 103 | def get_resnet_v(mode, input_shape, include_top, pretrain_file, classes, **kwargs): 104 | if isinstance(pretrain_file, str) and include_top and classes != 1000: 105 | raise ValueError('If using `pretrain weights` with `include_top` as true, `classes` should be 1000') 106 | block, expansion = resnet_v_block_versions[mode] 107 | layers = resnet_v_layer[mode] 108 | image = tf.keras.Input(shape=input_shape) 109 | x = ResNetV1b(image, block, layers, expansion, **kwargs) 110 | if include_top: 111 | x = tf.keras.layers.GlobalAvgPool2D()(x) 112 | x = tf.keras.layers.Dense(classes)(x) 113 | model = tf.keras.Model(image, x, name=mode) 114 | if isinstance(pretrain_file, str): 115 | if tf.gfile.Exists(pretrain_file): 116 | model.load_weights(pretrain_file, by_name=True) 117 | else: 118 | tf.gfile.MakeDirs(pretrain_file) 119 | tf.gfile.DeleteRecursively(pretrain_file) 120 | tf.keras.utils.get_file(pretrain_file, senet_url(mode)) 121 | model.load_weights(pretrain_file, by_name=True) 122 | return model 123 | 124 | resnet_v_url = {'resnet18_v1b':None, 125 | 'resnet34_v1b':None, 126 | 'resnet50_v1b':None, 127 | 'resnet101_v1b':None, 128 | 'resnet152_v1b':None, 129 | 'resnet50_v1c':None, 130 | 'resnet101_v1c':None, 131 | 'resnet152_v1c':None, 132 | 'resnet50_v1d':None, 133 | 'resnet101_v1d':None, 134 | 'resnet152_v1d':None, 135 | 'resnet50_v1e':None, 136 | 'resnet101_v1e':None, 137 | 'resnet152_v1e':None, 138 | 'resnet50_v1s':None, 139 | 'resnet101_v1s':None, 140 | 'resnet152_v1s':None} 141 | 142 | resnet_v_block_versions = {'resnet18_v1b': (BasicBlockV1b, 1), 143 | 'resnet34_v1b': (BasicBlockV1b, 1), 144 | 'resnet50_v1b': (BottleneckV1b, 4), 145 | 'resnet101_v1b': (BottleneckV1b, 4), 146 | 'resnet152_v1b': (BottleneckV1b, 4), 147 | 'resnet50_v1c': (BottleneckV1b, 4), 148 | 'resnet101_v1c': (BottleneckV1b, 4), 149 | 'resnet152_v1c': (BottleneckV1b, 4), 150 | 'resnet50_v1d': (BottleneckV1b, 4), 151 | 'resnet101_v1d': (BottleneckV1b, 4), 152 | 'resnet152_v1d': (BottleneckV1b, 4), 153 | 'resnet50_v1e': (BottleneckV1b, 4), 154 | 'resnet101_v1e': (BottleneckV1b, 4), 155 | 'resnet152_v1e': (BottleneckV1b, 4), 156 | 'resnet50_v1s': (BottleneckV1b, 4), 157 | 'resnet101_v1s': (BottleneckV1b, 4), 158 | 'resnet152_v1s': (BottleneckV1b, 4)} 159 | 160 | resnet_v_layer = {'resnet18_v1b': [2, 2, 2, 2], 161 | 'resnet34_v1b': [3, 4, 6, 3], 162 | 'resnet50_v1b': [3, 4, 6, 3], 163 | 'resnet101_v1b': [3, 4, 23, 3], 164 | 'resnet152_v1b': [3, 8, 36, 3], 165 | 'resnet50_v1c': [3, 4, 6, 3], 166 | 'resnet101_v1c': [3, 4, 23, 3], 167 | 'resnet152_v1c': [3, 8, 36, 3], 168 | 'resnet50_v1d': [3, 4, 6, 3], 169 | 'resnet101_v1d': [3, 4, 23, 3], 170 | 'resnet152_v1d': [3, 8, 36, 3], 171 | 'resnet50_v1e': [3, 4, 6, 3], 172 | 'resnet101_v1e': [3, 4, 23, 3], 173 | 'resnet152_v1e': [3, 8, 36, 3], 174 | 'resnet50_v1s': [3, 4, 6, 3], 175 | 'resnet101_v1s': [3, 4, 23, 3], 176 | 'resnet152_v1s': [3, 8, 36, 3]} 177 | 178 | def resnet18_v1b(input_shape, include_top=True, pretrain_file=False, classes=1000): 179 | return get_resnet_v('resnet18_v1b', input_shape, include_top, pretrain_file, classes) 180 | 181 | def resnet34_v1b(input_shape, include_top=True, pretrain_file=False, classes=1000): 182 | return get_resnet_v('resnet34_v1b', input_shape, include_top, pretrain_file, classes) 183 | 184 | def resnet50_v1b(input_shape, include_top=True, pretrain_file=False, classes=1000): 185 | return get_resnet_v('resnet50_v1b', input_shape, include_top, pretrain_file, classes) 186 | 187 | def resnet101_v1b(input_shape, include_top=True, pretrain_file=False, classes=1000): 188 | return get_resnet_v('resnet101_v1b', input_shape, include_top, pretrain_file, classes) 189 | 190 | def resnet152_v1b(input_shape, include_top=True, pretrain_file=False, classes=1000): 191 | return get_resnet_v('resnet152_v1b', input_shape, include_top, pretrain_file, classes) 192 | 193 | def resnet50_v1c(input_shape, include_top=True, pretrain_file=False, classes=1000): 194 | return get_resnet_v('resnet50_v1c', input_shape, include_top, pretrain_file, classes, deep_stem=True) 195 | 196 | def resnet101_v1c(input_shape, include_top=True, pretrain_file=False, classes=1000): 197 | return get_resnet_v('resnet101_v1c', input_shape, include_top, pretrain_file, classes, deep_stem=True) 198 | 199 | def resnet152_v1c(input_shape, include_top=True, pretrain_file=False, classes=1000): 200 | return get_resnet_v('resnet152_v1c', input_shape, include_top, pretrain_file, classes, deep_stem=True) 201 | 202 | def resnet50_v1d(input_shape, include_top=True, pretrain_file=False, classes=1000): 203 | return get_resnet_v('resnet50_v1d', input_shape, include_top, pretrain_file, classes, deep_stem=True, avg_down=True) 204 | 205 | def resnet101_v1d(input_shape, include_top=True, pretrain_file=False, classes=1000): 206 | return get_resnet_v('resnet101_v1d', input_shape, include_top, pretrain_file, classes, deep_stem=True, avg_down=True) 207 | 208 | def resnet152_v1d(input_shape, include_top=True, pretrain_file=False, classes=1000): 209 | return get_resnet_v('resnet152_v1d', input_shape, include_top, pretrain_file, classes, deep_stem=True, avg_down=True) 210 | 211 | def resnet50_v1e(input_shape, include_top=True, pretrain_file=False, classes=1000): 212 | return get_resnet_v('resnet50_v1e', input_shape, include_top, pretrain_file, classes, deep_stem=True, avg_down=True, stem_width=64) 213 | 214 | def resnet101_v1e(input_shape, include_top=True, pretrain_file=False, classes=1000): 215 | return get_resnet_v('resnet101_v1e', input_shape, include_top, pretrain_file, classes, deep_stem=True, avg_down=True, stem_width=64) 216 | 217 | def resnet152_v1e(input_shape, include_top=True, pretrain_file=False, classes=1000): 218 | return get_resnet_v('resnet152_v1e', input_shape, include_top, pretrain_file, classes, deep_stem=True, avg_down=True, stem_width=64) 219 | 220 | def resnet50_v1s(input_shape, include_top=True, pretrain_file=False, classes=1000): 221 | return get_resnet_v('resnet50_v1s', input_shape, include_top, pretrain_file, classes, deep_stem=True, stem_width=64) 222 | 223 | def resnet101_v1s(input_shape, include_top=True, pretrain_file=False, classes=1000): 224 | return get_resnet_v('resnet101_v1s', input_shape, include_top, pretrain_file, classes, deep_stem=True, stem_width=64) 225 | 226 | def resnet152_v1s(input_shape, include_top=True, pretrain_file=False, classes=1000): 227 | return get_resnet_v('resnet152_v1s', input_shape, include_top, pretrain_file, classes, deep_stem=True, stem_width=64) 228 | -------------------------------------------------------------------------------- /tensorcv/Classification/_resnext.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | 3 | def Block(tensor, channels, cardinality, bottleneck_width, stride, downsample, last_gamma, use_se): 4 | D = int(math.floor(channels * (bottleneck_width / 64))) 5 | group_width = cardinality * D 6 | x = tf.keras.layers.Conv2D(group_width, 1, use_bias=False)(tensor) 7 | x = tf.keras.layers.BatchNormalization()(x) 8 | x = tf.keras.layers.ReLU()(x) 9 | x = tf.keras.layers.ZeroPadding2D(1)(x) 10 | x = tf.keras.layers.Conv2D(group_width, 3, stride, use_bias=False)(x) 11 | x = tf.keras.layers.BatchNormalization()(x) 12 | x = tf.keras.layers.ReLU()(x) 13 | x = tf.keras.layers.Conv2D(channels * 4, 1, use_bias=False)(x) 14 | if not last_gamma: 15 | x = tf.keras.layers.BatchNormalization()(x) 16 | else: 17 | x = tf.keras.layers.BatchNormalization(gamma_initializer='zeros')(x) 18 | if use_se: 19 | se = tf.keras.layers.GlobalAvgPool2D()(x) 20 | se = tf.keras.layers.Dense(channels//4, activation='relu', use_bias=False)(se) 21 | se = tf.keras.layers.Dense(channels*4, activation='sigmoid', use_bias=False)(se) 22 | se = tf.keras.layers.Reshape((1,1,channels*4))(se) 23 | se = tf.keras.layers.Lambda(lambda x:tf.broadcast_to(x, [x.shape.as_list()[0], x.shape.as_list()[1], channels*4]))(se) 24 | x = tf.keras.layers.Multiply()([se, x]) 25 | if downsample: 26 | ds = tf.keras.layers.Conv2D(channels*4, 1, stride, use_bias=False)(tensor) 27 | ds = tf.keras.layers.BatchNormalization()(ds) 28 | x = tf.keras.layers.Add()([ds, x]) 29 | else: 30 | x = tf.keras.layers.Add()([tensor, x]) 31 | x = tf.keras.layers.ReLU()(x) 32 | return x 33 | 34 | def ResNext(tensor, layers, cardinality, bottleneck_width, last_gamma=False, use_se=False): 35 | channels = 64 36 | x = tf.keras.layers.ZeroPadding2D(3)(tensor) 37 | x = tf.keras.layers.Conv2D(channels, 7, 2, use_bias=False)(x) 38 | x = tf.keras.layers.BatchNormalization()(x) 39 | x = tf.keras.layers.ReLU()(x) 40 | x = tf.keras.layers.ZeroPadding2D(1)(x) 41 | x = tf.keras.layers.MaxPool2D(3, 2)(x) 42 | for i, num_layer in enumerate(layers): 43 | stride = 1 if i == 0 else 2 44 | x = Block(x, channels, cardinality, bottleneck_width, stride, True, last_gamma, use_se) 45 | for _ in range(num_layer-1): 46 | x = Block(x, channels, cardinality, bottleneck_width, 1, False, last_gamma, use_se) 47 | channels *= 2 48 | return x 49 | 50 | resnext_url = {'resnext50_32x4d':None, 51 | 'resnext101_32x4d':None, 52 | 'resnext101_64x4d':None, 53 | 'se_resnext50_32x4d':None, 54 | 'se_resnext50_32x4d':None, 55 | 'se_resnext101_32x4d':None, 56 | 'se_resnext101_64x4d':None} 57 | 58 | resnext_spec = {50: [3, 4, 6, 3], 59 | 101: [3, 4, 23, 3]} 60 | 61 | def get_resnext(num_layers, cardinality, bottleneck_width, mode, input_shape, include_top, pretrain_file, classes, use_se): 62 | if isinstance(pretrain_file, str) and include_top and classes != 1000: 63 | raise ValueError('If using `pretrain weights` with `include_top` as true, `classes` should be 1000') 64 | layers = resnext_spec[num_layers] 65 | image = tf.keras.Input(shape=input_shape) 66 | x = ResNext(image, layers, cardinality, bottleneck_width, use_se) 67 | if include_top: 68 | x = tf.keras.layers.GlobalAvgPool2D()(x) 69 | x = tf.keras.layers.Dense(classes)(x) 70 | model = tf.keras.Model(image, x, name=mode) 71 | 72 | if isinstance(pretrain_file, str): 73 | if tf.gfile.Exists(pretrain_file): 74 | model.load_weights(pretrain_file) 75 | else: 76 | tf.gfile.MakeDirs(pretrain_file) 77 | tf.gfile.DeleteRecursively(pretrain_file) 78 | tf.keras.utils.get_file(pretrain_file, resnext_url(mode)) 79 | model.load_weights(pretrain_file) 80 | return model 81 | 82 | def resnext50_32x4d(input_shape, include_top=True, pretrain_file=False, classes=1000): 83 | return get_resnext(50, 32, 4, 'resnext50_32x4d', input_shape, include_top, pretrain_file, classes, False) 84 | 85 | def resnext101_32x4d(input_shape, include_top=True, pretrain_file=False, classes=1000): 86 | return get_resnext(101, 32, 4, 'resnext101_32x4d', input_shape, include_top, pretrain_file, classes, False) 87 | 88 | def resnext101_64x4d(input_shape, include_top=True, pretrain_file=False, classes=1000): 89 | return get_resnext(101, 64, 4, 'resnext101_64x4d', input_shape, include_top, pretrain_file, classes, False) 90 | 91 | def se_resnext50_32x4d(input_shape, include_top=True, pretrain_file=False, classes=1000): 92 | return get_resnext(50, 32, 4, 'se_resnext50_32x4d', input_shape, include_top, pretrain_file, classes, True) 93 | 94 | def se_resnext101_32x4d(input_shape, include_top=True, pretrain_file=False, classes=1000): 95 | return get_resnext(101, 32, 4, 'se_resnext101_32x4d', input_shape, include_top, pretrain_file, classes, True) 96 | 97 | def se_resnext101_64x4d(input_shape, include_top=True, pretrain_file=False, classes=1000): 98 | return get_resnext(101, 64, 4, 'se_resnext101_64x4d', input_shape, include_top, pretrain_file, classes, True) 99 | -------------------------------------------------------------------------------- /tensorcv/Classification/_senet.py: -------------------------------------------------------------------------------- 1 | import math 2 | import tensorflow as tf 3 | 4 | def SEBlock(tensor, channels, cardinality, bottleneck_width, stride, downsample, downsample_kernel_size): 5 | group_width = cardinality * int(math.floor(channels * (bottleneck_width / 64))) 6 | x = tf.keras.layers.Conv2D(group_width//2, 1, use_bias=False)(tensor) 7 | x = tf.keras.layers.BatchNormalization()(x) 8 | x = tf.keras.layers.ReLU()(x) 9 | x = tf.keras.layers.ZeroPadding2D(((1, 1), (1, 1)))(x) 10 | x = tf.keras.layers.Conv2D(group_width, 3, stride, use_bias=False)(x) 11 | x = tf.keras.layers.BatchNormalization()(x) 12 | x = tf.keras.layers.ReLU()(x) 13 | x = tf.keras.layers.Conv2D(channels*4, 1, use_bias=False)(x) 14 | x = tf.keras.layers.BatchNormalization()(x) 15 | se = tf.keras.layers.GlobalAvgPool2D()(x) 16 | se = tf.keras.layers.Conv2D(channels//4, 1, activation='relu')(se) 17 | se = tf.keras.layers.Conv2D(channels*4, 1, activation='sigmoid')(se) 18 | se = tf.keras.layers.Reshape((1,1,channels*4))(se) 19 | se = tf.keras.layers.Lambda(lambda x:tf.broadcast_to(x, [x.shape.as_list()[0], x.shape.as_list()[1], channels*4]))(se) 20 | x = tf.keras.layers.Multiply()([se, x]) 21 | if downsample: 22 | if downsample_kernel_size == 3: 23 | ds = tf.keras.layers.ZeroPadding2D(((1, 1), (1, 1)))(tensor) 24 | ds = tf.keras.layers.Conv2D(channels*4, downsample_kernel_size, stride, use_bias=False)(ds) 25 | else: 26 | ds = tf.keras.layers.Conv2D(channels*4, downsample_kernel_size, stride, use_bias=False)(tensor) 27 | ds = tf.keras.layers.BatchNormalization()(ds) 28 | x = tf.keras.layers.Add()([x, ds]) 29 | else: 30 | x = tf.keras.layers.Add()([x, tensor]) 31 | x = tf.keras.layers.ReLU()(x) 32 | return x 33 | 34 | def SENet(tensor, layers, cardinality, bottleneck_width, channels=64): 35 | x = tf.keras.layers.ZeroPadding2D(((1, 1), (1, 1)))(tensor) 36 | x = tf.keras.layers.Conv2D(channels, 3, 2, use_bias=False)(x) 37 | x = tf.keras.layers.BatchNormalization()(x) 38 | x = tf.keras.layers.ReLU()(x) 39 | x = tf.keras.layers.ZeroPadding2D(((1, 1), (1, 1)))(x) 40 | x = tf.keras.layers.Conv2D(channels, 3, use_bias=False)(x) 41 | x = tf.keras.layers.BatchNormalization()(x) 42 | x = tf.keras.layers.ReLU()(x) 43 | x = tf.keras.layers.ZeroPadding2D(((1, 1), (1, 1)))(x) 44 | x = tf.keras.layers.Conv2D(channels*2, 3, use_bias=False)(x) 45 | x = tf.keras.layers.BatchNormalization()(x) 46 | x = tf.keras.layers.ReLU()(x) 47 | x = tf.keras.layers.MaxPool2D(3, 2)(x) 48 | for i, num_layer in enumerate(layers): 49 | stride = 1 if i == 0 else 2 50 | downsample_kernel_size = 1 if i==0 else 3 51 | x = SEBlock(x, channels, cardinality, bottleneck_width, stride, True, downsample_kernel_size) 52 | for _ in range(num_layers-1): 53 | x = SEBlock(x, channels, cardinality, bottleneck_width, 1, False, 3) 54 | channels *= 2 55 | x = tf.keras.layers.GlobalAvgPool2D()(x) 56 | return x 57 | 58 | senet_url = {'senet_50': None, 59 | 'senet_101': None, 60 | 'senet_152': None} 61 | 62 | senet_spec = {50: [3, 4, 6, 3], 63 | 101: [3, 4, 23, 3], 64 | 152: [3, 8, 36, 3]} 65 | 66 | def get_senet(num_layers, mode, input_shape, include_top, pretrain_file, classes, cardinality=64, bottleneck_width=4): 67 | if isinstance(pretrain_file, str) and include_top and classes != 1000: 68 | raise ValueError('If using `pretrain weights` with `include_top` as true, `classes` should be 1000') 69 | layers = senet_spec[num_layers] 70 | image = tf.keras.Input(shape=input_shape) 71 | x = SENet(image, layers, cardinality, bottleneck_width, channels=64) 72 | if include_top: 73 | x = tf.keras.layers.Flatten()(x) 74 | x = rf.keras.layers.Dropout(0.2)(x) 75 | x = tf.keras.layers.Dense(classes)(x) 76 | model = tf.keras.Model(image, x, name=mode) 77 | if isinstance(pretrain_file, str): 78 | if tf.gfile.Exists(pretrain_file): 79 | model.load_weights(pretrain_file, by_name=True) 80 | else: 81 | tf.gfile.MakeDirs(pretrain_file) 82 | tf.gfile.DeleteRecursively(pretrain_file) 83 | tf.keras.utils.get_file(pretrain_file, senet_url(mode)) 84 | model.load_weights(pretrain_file, by_name=True) 85 | return model 86 | 87 | def senet_50(input_shape, include_top=True, pretrain_file=False, classes=1000): 88 | return get_senet(50, 'senet_50', input_shape, include_top, pretrain_file, classes, 64, 4) 89 | 90 | def senet_101(input_shape, include_top=True, pretrain_file=False, classes=1000): 91 | return get_senet(101, 'senet_101', input_shape, include_top, pretrain_file, classes, 64, 4) 92 | 93 | def senet_152(input_shape, include_top=True, pretrain_file=False, classes=1000): 94 | return get_senet(152, 'senet_152', input_shape, include_top, pretrain_file, classes, 64, 4) 95 | -------------------------------------------------------------------------------- /tensorcv/Classification/_squeezenet.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | 3 | def _make_fire(tensor, squeeze_channels, expand1x1_channels, expand3x3_channels): 4 | x = tf.keras.layers.Conv2D(squeeze_channels, 1)(tensor) 5 | x = tf.keras.layers.ReLU()(x) 6 | x_left = tf.keras.layers.Conv2D(expand1x1_channels, 1)(x) 7 | x_left = tf.keras.layers.ReLU()(x_left) 8 | x_right = tf.keras.layers.ZeroPadding2D(1)(x) 9 | x_right = tf.keras.layers.Conv2D(expand3x3_channels, 3)(x_right) 10 | x_right = tf.keras.layers.ReLU()(x_right) 11 | x = tf.keras.layers.Concatenate()([x_left, x_right]) 12 | return x 13 | 14 | def SqueezeNet(tensor, mode): 15 | if mode == 'squeezenet1.0': 16 | x = tf.keras.layers.Conv2D(96, 7, 2)(tensor) 17 | x = tf.keras.layers.ReLU()(x) 18 | x = tf.keras.layers.MaxPool2D(3, 2)(x) 19 | x = _make_fire(x, 16, 64, 64) 20 | x = _make_fire(x, 16, 64, 64) 21 | x = _make_fire(x, 32, 128, 128) 22 | x = tf.keras.layers.MaxPool2D(3, 2)(x) 23 | x = _make_fire(x, 32, 128, 128) 24 | x = _make_fire(x, 48, 192, 192) 25 | x = _make_fire(x, 48, 192, 192) 26 | x = _make_fire(x, 64, 256, 256) 27 | x = tf.keras.layers.MaxPool2D(3, 2)(x) 28 | x = _make_fire(x, 64, 256, 256) 29 | else: 30 | x = tf.keras.layers.Conv2D(64, 3, 2)(tensor) 31 | x = tf.keras.layers.ReLU()(x) 32 | x = tf.keras.layers.MaxPool2D(3, 2)(x) 33 | x = _make_fire(x, 16, 64, 64) 34 | x = _make_fire(x, 16, 64, 64) 35 | x = tf.keras.layers.MaxPool2D(3, 2)(x) 36 | x = _make_fire(x, 32, 128, 128) 37 | x = _make_fire(x, 32, 128, 128) 38 | x = tf.keras.layers.MaxPool2D(3, 2)(x) 39 | x = _make_fire(x, 48, 192, 192) 40 | x = _make_fire(x, 48, 192, 192) 41 | x = _make_fire(x, 64, 256, 256) 42 | x = _make_fire(x, 64, 256, 256) 43 | x = tf.keras.layers.Dropout(0.5)(x) 44 | return x 45 | 46 | squeezenet_url = {'squeezenet1.0':None, 47 | 'squeezenet1.1':None} 48 | 49 | def get_squeezenet(mode, input_shape, include_top, pretrain_file, classes): 50 | if isinstance(pretrain_file, str) and include_top and classes != 1000: 51 | raise ValueError('If using `pretrain weights` with `include_top` as true, `classes` should be 1000') 52 | image = tf.keras.Input(shape=input_shape) 53 | x = SqueezeNet(image, mode) 54 | if include_top: 55 | x = tf.keras.layers.Conv2D(classes, 1)(x) 56 | x = tf.keras.layers.ReLU()(x) 57 | x = tf.keras.layers.GlobalAvgPool2D()(x) 58 | model = tf.keras.Model(image, x, name=mode) 59 | if isinstance(pretrain_file, str): 60 | if tf.gfile.Exists(pretrain_file): 61 | model.load_weights(pretrain_file, by_name=True) 62 | else: 63 | tf.gfile.MakeDirs(pretrain_file) 64 | tf.gfile.DeleteRecursively(pretrain_file) 65 | tf.keras.utils.get_file(pretrain_file, squeezenet_url(mode)) 66 | model.load_weights(pretrain_file, by_name=True) 67 | return model 68 | 69 | def squeezenet1_0(input_shape, include_top=True, pretrain_file=False, classes=1000): 70 | return get_squeezenet('squeezenet1.0', input_shape, include_top, pretrain_file, classes) 71 | 72 | def squeezenet1_1(input_shape, include_top=True, pretrain_file=False, classes=1000): 73 | return get_squeezenet('squeezenet1.1', input_shape, include_top, pretrain_file, classes) 74 | -------------------------------------------------------------------------------- /tensorcv/Classification/_vgg.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | 3 | __all__ = ['vgg11', 'vgg13', 'vgg16', 'vgg19', 'vgg11_bn', 'vgg13_bn', 'vgg16_bn', 'vgg19_bn'] 4 | 5 | vgg_url = {'vgg11': None, 6 | 'vgg13': None, 7 | 'vgg16': None, 8 | 'vgg19': None, 9 | 'vgg11_bn': None, 10 | 'vgg13_bn': None, 11 | 'vgg16_bn': None, 12 | 'vgg19_bn': None} 13 | 14 | vgg_spec = {11: ([1, 1, 2, 2, 2], [64, 128, 256, 512, 512]), 15 | 13: ([2, 2, 2, 2, 2], [64, 128, 256, 512, 512]), 16 | 16: ([2, 2, 3, 3, 3], [64, 128, 256, 512, 512]), 17 | 19: ([2, 2, 4, 4, 4], [64, 128, 256, 512, 512])} 18 | 19 | def VGG(num_layers, mode, input_shape, include_top, pretrain_file, classes, use_bn): 20 | if isinstance(pretrain_file, str) and include_top and classes != 1000: 21 | raise ValueError('If using `pretrain weights` with `include_top` as true, `classes` should be 1000') 22 | layers, filters = vgg_spec[num_layers] 23 | assert len(layers) == len(filters) 24 | image = tf.keras.Input(shape=input_shape) 25 | for i, num in enumerate(layers): 26 | for j in range(num): 27 | if (i==0)&(j==0): 28 | x = tf.keras.layers.Conv2D(filters[i], 3, 1, 'same', name='conv'+str(i+1)+'_'+str(j+1))(image) 29 | else: 30 | x = tf.keras.layers.Conv2D(filters[i], 3, 1, 'same', name='conv'+str(i+1)+'_'+str(j+1))(x) 31 | if use_bn: 32 | x = tf.keras.layers.BatchNormalization(name='bn'+str(i+1)+'_'+str(j+1))(x) 33 | x = tf.keras.layers.ReLU(name='relu'+str(i+1)+'_'+str(j+1))(x) 34 | x = tf.keras.layers.MaxPool2D(2, 2, name='pool'+str(i+1)+'_'+str(j+1))(x) 35 | if include_top: 36 | x = tf.keras.layers.Flatten(name='flatten')(x) 37 | x = tf.keras.layers.Dense(4096, 'relu', name='liner1')(x) 38 | x = tf.keras.layers.Dropout(0.5, name='drop1')(x) 39 | x = tf.keras.layers.Dense(4096, 'relu', name='liner2')(x) 40 | x = tf.keras.layers.Dropout(0.5, name='drop2')(x) 41 | x = tf.keras.layers.Dense(classes, name='predictions')(x) 42 | model = tf.keras.Model(image, x, name=mode) 43 | if isinstance(pretrain_file, str): 44 | if tf.gfile.Exists(pretrain_file): 45 | model.load_weights(pretrain_file, by_name=True) 46 | else: 47 | tf.gfile.MakeDirs(pretrain_file) 48 | tf.gfile.DeleteRecursively(pretrain_file) 49 | tf.keras.utils.get_file(pretrain_file, vgg_url(mode)) 50 | model.load_weights(pretrain_file, by_name=True) 51 | return model 52 | 53 | def vgg11(input_shape, include_top=True, pretrain_file=False, classes=1000): 54 | r"""VGG-11 model from the `"Very Deep Convolutional Networks for Large-Scale Image Recognition" 55 | `_ paper. 56 | 57 | Parameters 58 | ---------- 59 | input_shape : tuple of 3 ints, input image shape. 60 | include_top : whether to include the fully-connected layer at the top of the network. 61 | pretrain_file : bool or str 62 | Boolean value controls whether to load the default pretrained weights for model. 63 | String value represents the hashtag for a certain version of pretrained weights. 64 | String value must be absolute path of the pretrained weights file, 65 | if pretrain file is not exists, will auto create dir and download pretrained weights. 66 | classes: optional number of classes to classify images into, 67 | only to be specified if `include_top` is True. 68 | """ 69 | return VGG(11, 'vgg11', input_shape, include_top, pretrain_file, classes, False) 70 | 71 | def vgg13(input_shape, include_top=True, pretrain_file=False, classes=1000): 72 | r"""VGG-13 model from the `"Very Deep Convolutional Networks for Large-Scale Image Recognition" 73 | `_ paper. 74 | 75 | ---------- 76 | input_shape : tuple of 3 ints, input image shape. 77 | include_top : whether to include the fully-connected layer at the top of the network. 78 | pretrain_file : bool or str 79 | Boolean value controls whether to load the default pretrained weights for model. 80 | String value represents the hashtag for a certain version of pretrained weights. 81 | String value must be absolute path of the pretrained weights file, 82 | if pretrain file is not exists, will auto create dir and download pretrained weights. 83 | classes: optional number of classes to classify images into, 84 | only to be specified if `include_top` is True. 85 | """ 86 | return VGG(13, 'vgg13', input_shape, include_top, pretrain_file, classes, False) 87 | 88 | def vgg16(input_shape, include_top=True, pretrain_file=False, classes=1000): 89 | r"""VGG-16 model from the `"Very Deep Convolutional Networks for Large-Scale Image Recognition" 90 | `_ paper. 91 | 92 | ---------- 93 | input_shape : tuple of 3 ints, input image shape. 94 | include_top : whether to include the fully-connected layer at the top of the network. 95 | pretrain_file : bool or str 96 | Boolean value controls whether to load the default pretrained weights for model. 97 | String value represents the hashtag for a certain version of pretrained weights. 98 | String value must be absolute path of the pretrained weights file, 99 | if pretrain file is not exists, will auto create dir and download pretrained weights. 100 | classes: optional number of classes to classify images into, 101 | only to be specified if `include_top` is True. 102 | """ 103 | return VGG(16, 'vgg16', input_shape, include_top, pretrain_file, classes, False) 104 | 105 | def vgg19(input_shape, include_top=True, pretrain_file=False, classes=1000): 106 | r"""VGG-19 model from the `"Very Deep Convolutional Networks for Large-Scale Image Recognition" 107 | `_ paper. 108 | 109 | ---------- 110 | input_shape : tuple of 3 ints, input image shape. 111 | include_top : whether to include the fully-connected layer at the top of the network. 112 | pretrain_file : bool or str 113 | Boolean value controls whether to load the default pretrained weights for model. 114 | String value represents the hashtag for a certain version of pretrained weights. 115 | String value must be absolute path of the pretrained weights file, 116 | if pretrain file is not exists, will auto create dir and download pretrained weights. 117 | classes: optional number of classes to classify images into, 118 | only to be specified if `include_top` is True. 119 | """ 120 | return VGG(19, 'vgg19', input_shape, include_top, pretrain_file, classes, False) 121 | 122 | def vgg11_bn(input_shape, include_top=True, pretrain_file=False, classes=1000): 123 | r"""VGG-11 model with batch normalization from the 124 | `"Very Deep Convolutional Networks for Large-Scale Image Recognition" 125 | `_ paper. 126 | 127 | ---------- 128 | input_shape : tuple of 3 ints, input image shape. 129 | include_top : whether to include the fully-connected layer at the top of the network. 130 | pretrain_file : bool or str 131 | Boolean value controls whether to load the default pretrained weights for model. 132 | String value represents the hashtag for a certain version of pretrained weights. 133 | String value must be absolute path of the pretrained weights file, 134 | if pretrain file is not exists, will auto create dir and download pretrained weights. 135 | classes: optional number of classes to classify images into, 136 | only to be specified if `include_top` is True. 137 | """ 138 | return VGG(11, 'vgg11_bn', input_shape, include_top, pretrain_file, classes, True) 139 | 140 | def vgg13_bn(input_shape, include_top=True, pretrain_file=False, classes=1000): 141 | r"""VGG-13 model with batch normalization from the 142 | `"Very Deep Convolutional Networks for Large-Scale Image Recognition" 143 | `_ paper. 144 | 145 | ---------- 146 | input_shape : tuple of 3 ints, input image shape. 147 | include_top : whether to include the fully-connected layer at the top of the network. 148 | pretrain_file : bool or str 149 | Boolean value controls whether to load the default pretrained weights for model. 150 | String value represents the hashtag for a certain version of pretrained weights. 151 | String value must be absolute path of the pretrained weights file, 152 | if pretrain file is not exists, will auto create dir and download pretrained weights. 153 | classes: optional number of classes to classify images into, 154 | only to be specified if `include_top` is True. 155 | """ 156 | return VGG(13, 'vgg13_bn', input_shape, include_top, pretrain_file, classes, True) 157 | 158 | def vgg16_bn(input_shape, include_top=True, pretrain_file=False, classes=1000): 159 | r"""VGG-16 model with batch normalization from the 160 | `"Very Deep Convolutional Networks for Large-Scale Image Recognition" 161 | `_ paper. 162 | 163 | ---------- 164 | input_shape : tuple of 3 ints, input image shape. 165 | include_top : whether to include the fully-connected layer at the top of the network. 166 | pretrain_file : bool or str 167 | Boolean value controls whether to load the default pretrained weights for model. 168 | String value represents the hashtag for a certain version of pretrained weights. 169 | String value must be absolute path of the pretrained weights file, 170 | if pretrain file is not exists, will auto create dir and download pretrained weights. 171 | classes: optional number of classes to classify images into, 172 | only to be specified if `include_top` is True. 173 | """ 174 | return VGG(16, 'vgg16_bn', input_shape, include_top, pretrain_file, classes, True) 175 | 176 | def vgg19_bn(input_shape, include_top=True, pretrain_file=False, classes=1000): 177 | r"""VGG-19 model with batch normalization from the 178 | `"Very Deep Convolutional Networks for Large-Scale Image Recognition" 179 | `_ paper. 180 | 181 | ---------- 182 | input_shape : tuple of 3 ints, input image shape. 183 | include_top : whether to include the fully-connected layer at the top of the network. 184 | pretrain_file : bool or str 185 | Boolean value controls whether to load the default pretrained weights for model. 186 | String value represents the hashtag for a certain version of pretrained weights. 187 | String value must be absolute path of the pretrained weights file, 188 | if pretrain file is not exists, will auto create dir and download pretrained weights. 189 | classes: optional number of classes to classify images into, 190 | only to be specified if `include_top` is True. 191 | """ 192 | return VGG(19, 'vgg19_bn', input_shape, include_top, pretrain_file, classes, True) 193 | -------------------------------------------------------------------------------- /tensorcv/Detection/__init__.py: -------------------------------------------------------------------------------- 1 | from tensocv.Detection import bbox 2 | -------------------------------------------------------------------------------- /tensorcv/Detection/bbox/__init__.py: -------------------------------------------------------------------------------- 1 | from tensorcv.Detection.bbox._bbox import BBoxCornerToCenter 2 | from tensorcv.Detection.bbox._bbox import BBoxCenterToCorner 3 | from tensorcv.Detection.bbox._bbox import BBoxSplit 4 | from tensorcv.Detection.bbox._bbox import BBoxArea 5 | from tensorcv.Detection.bbox._bbox import BBoxBatchIOU 6 | from tensorcv.Detection.bbox._bbox import BBoxClipToImage 7 | -------------------------------------------------------------------------------- /tensorcv/Detection/bbox/_bbox.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | 3 | def BBoxCornerToCenter(tensor, axis=-1, split=False): 4 | xmin, ymin, xmax, ymax = tf.split(tensor, 4, axis) 5 | width = tf.math.subtract(xmax, xmin) 6 | height = tf.math.subtract(ymax, ymin) 7 | x = tf.math.add(xmin, tf.math.divide(width, 2)) 8 | y = tf.math.add(ymin, tf.math.divide(height, 2)) 9 | if not split: 10 | return tf.concat([x, y, width, height], axis) 11 | else: 12 | return x, y, width, height 13 | 14 | def BBoxCenterToCorner(tensor, axis=-1, split=False): 15 | x, y, w, h = tf.split(tensor, 4, axis) 16 | hw = tf.math.divide(w, 2) 17 | hh = tf.math.divide(h, 2) 18 | xmin = tf.math.subtract(x, hw) 19 | ymin = tf.math.subtract(y, hh) 20 | xmax = tf.math.add(x, hw) 21 | ymax = tf.math.add(y, hh) 22 | if not split: 23 | return tf.concat([xmin, ymin, xmax, ymax], axis) 24 | else: 25 | return xmin, ymin, xmax, ymax 26 | 27 | def BBoxSplit(tensor, axis=-1): 28 | return tf.split(tensor, 4, axis) 29 | 30 | def BBoxArea(tensor, axis=-1, fmt='corner'): 31 | if fmt.lower() == 'corner': 32 | _, _, width, height = BBoxCornerToCenter(tensor, split=True) 33 | elif fmt.lower() == 'center': 34 | _, _, width, height = BBoxSplit(tensor, axis=axis) 35 | else: 36 | raise ValueError("Unsupported format: {}. Use 'corner' or 'center'.".format(fmt)) 37 | width = tf.where(tf.math.greater(width, 0), width, tf.zeros_like(width)) 38 | height = tf.where(tf.math.greater(height, 0), height, tf.zeros_like(height)) 39 | return tf.math.multiply(width, height) 40 | 41 | def BBoxBatchIOU(tensor1, tensor2, axis=-1, fmt='corner', offset=0, eps=1e-15): 42 | if fmt.lower() == 'center': 43 | al, at, ar, ab = BBoxCenterToCorner(tensor1, split=True) 44 | bl, bt, br, bb = BBoxCenterToCorner(tensor2, split=True) 45 | elif fmt.lower() == 'corner': 46 | al, at, ar, ab = BBoxSplit(tensor1, axis=axis, squeeze_axis=True) 47 | bl, bt, br, bb = BBoxSplit(tensor2, axis=axis, squeeze_axis=True) 48 | else: 49 | raise ValueError("Unsupported format: {}. Use 'corner' or 'center'.".format(fmt)) 50 | 51 | left = tf.math.maximum(tf.expand_dims(al, -1), tf.expand_dims(bl, -2)) 52 | right = tf.math.minimum(tf.expand_dims(ar, -1), tf.expand_dims(br, -2)) 53 | top = tf.math.maximum(tf.expand_dims(at, -1), tf.expand_dims(bt, -2)) 54 | bot = tf.math.minimum(tf.expand_dims(ab, -1), tf.expand_dims(bb, -2)) 55 | 56 | iw = tf.clip_by_value(tf.math.add(tf.math.subtract(right, left), offset), 0, 6.55040e+04) 57 | ih = tf.clip_by_value(tf.math.add(tf.math.subtract(bot, top), offset), 0, 6.55040e+04) 58 | i = tf.math.multiply(iw, ih) 59 | 60 | area_a = tf.expand_dims(tf.math.multiply(tf.math.add(tf.math.subtract(ar, al), offset), tf.math.add(tf.math.subtract(ab, at), offset)), -1) 61 | area_b = tf.expand_dims(tf.math.multiply(tf.math.add(tf.math.subtract(br, bl), offset), tf.math.add(tf.math.subtract(bb, bt), offset)), -2) 62 | union = tf.math.subtract(tf.math.add(area_a, area_b) - i) 63 | return tf.math.divide(i, tf.math.add(union, eps)) 64 | 65 | def BBoxClipToImage(): 66 | x = tf.math.maximum(x, 0.0) 67 | window = tf.expand_dims(tf.slice(tf.shape(img), begin=2), 0) 68 | m = tf.manip.reshape(tf.tile(tf.manip.reverse(window, axis=1), [2]), [0, -4, 1, -1]) 69 | return tf.math.minimum(x, tf.cast(m, dtype=tf.float32)) 70 | -------------------------------------------------------------------------------- /tensorcv/Segmentation/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tensorcv/__init__.py: -------------------------------------------------------------------------------- 1 | from tensorcv import Classification 2 | from tensorcv import image 3 | from tensorcv import data 4 | from tensorcv import losses 5 | 6 | __version__ = '0.2.0' 7 | __author__ = 'JinQing Lee' 8 | -------------------------------------------------------------------------------- /tensorcv/data/__init__.py: -------------------------------------------------------------------------------- 1 | from tensorcv.data._sample import ImageClassificationFolderDataset 2 | from tensorcv.data import datasets 3 | -------------------------------------------------------------------------------- /tensorcv/data/_sample.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import tensorflow as tf 3 | 4 | class ImageClassificationFolderDataset(): 5 | def __init__(self, root, image_format=['png', 'jpg', 'jpeg']): 6 | self.root = root 7 | self.image_format = image_format 8 | 9 | file = tf.gfile.ListDirectory(self.root) 10 | file = [i for i in file if tf.gfile.IsDirectory(self.root+'/'+i) and i[0]!='.'] 11 | data = pd.DataFrame() 12 | for i in file: 13 | data = pd.concat([data, pd.DataFrame({'image':tf.gfile.ListDirectory(self.root+'/'+i), 'label':i})]) 14 | data = data.reset_index(drop=True) 15 | data['image'] = self.root+'/'+data.label+'/'+data.image 16 | data = data[data.image.map(lambda x: True if '.' in x.split('/')[-1] else False)] 17 | data = data[data.image.map(lambda x: True if x.split('/')[-1][0]!='.' else False)] 18 | data = data[data.image.map(lambda x: True if len(x.split('/')[-1].split('.'))==2 else False)] 19 | data = data[data.image.map(lambda x: True if str.lower(x.split('/')[-1].split('.')[1]) in self.image_format else False)] 20 | self.dataset = data.reset_index(drop=True) 21 | self.name_label_dict = {j: i for i, j in enumerate(data.label.unique())} 22 | -------------------------------------------------------------------------------- /tensorcv/data/datasets/__init__.py: -------------------------------------------------------------------------------- 1 | from tensordata.cv import * 2 | -------------------------------------------------------------------------------- /tensorcv/image/__init__.py: -------------------------------------------------------------------------------- 1 | from tensorcv.image._image_ops import read_image 2 | from tensorcv.image._image_ops import RandomBrightness 3 | from tensorcv.image._image_ops import RandomContrast 4 | from tensorcv.image._image_ops import RandomHue 5 | from tensorcv.image._image_ops import RandomSaturation 6 | from tensorcv.image._image_ops import RandomGamma 7 | from tensorcv.image._image_ops import RandomFlipLeftRight 8 | from tensorcv.image._image_ops import RandomFlipTopBottom 9 | from tensorcv.image._image_ops import RandomTranspose 10 | from tensorcv.image._image_ops import RandomRotation 11 | from tensorcv.image._image_ops import RandomCropCentralResize 12 | from tensorcv.image._image_ops import RandomCropPointResize 13 | from tensorcv.image._image_ops import Normalize 14 | from tensorcv.image._image_ops import RandomRescale 15 | from tensorcv.image._image_ops import RandomNoiseGaussian 16 | from tensorcv.image._image_ops import RandomNoisePoisson 17 | from tensorcv.image._image_ops import RandomNoiseMask 18 | from tensorcv.image._image_ops import RandomNoiseSaltPepper 19 | from tensorcv.image._image_ops import RandomNoiseRainbow 20 | -------------------------------------------------------------------------------- /tensorcv/image/_image_ops.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | from tensorflow.python.ops.image_ops_impl import _ImageDimensions 3 | 4 | __all__ = ['read_image', 'RandomBrightness', 'RandomContrast', 'RandomHue', 5 | 'RandomSaturation', 'RandomGamma', 'RandomFlipLeftRight', 'RandomFlipTopBottom', 6 | 'RandomTranspose', 'RandomRotation', 'RandomCropCentralResize', 'RandomCropPointResize', 7 | 'Normalize', 'RandomRescale', 'RandomNoiseGaussian', 'RandomNoisePoisson', 8 | 'RandomNoiseMask', 'RandomNoiseSaltPepper', 'RandomNoiseRainbow'] 9 | 10 | def read_image(filename, channel=0, image_format='mix'): 11 | """Convenience function for read image type one of `bmp`, `gif`, `jpeg`, `jpg`, and `png`. 12 | 13 | Detects whether an image is a BMP, GIF, JPEG, JPG, or PNG, and performs the 14 | appropriate operation to convert the input bytes `string` into a `Tensor` 15 | of type `dtype`. 16 | 17 | Note: `gif` returns a 4-D array `[num_frames, height, width, 3]`, as 18 | opposed to `bmp`, `jpeg`, `jpg` and `png`, which return 3-D 19 | arrays `[height, width, num_channels]`. Make sure to take this into account 20 | when constructing your graph if you are intermixing GIF files with BMP, JPEG, JPG, 21 | and/or PNG files. 22 | Args: 23 | filename: 0-D `string`. image absolute path. 24 | channels: An optional `int`. Defaults to `0`. Number of color channels for 25 | the decoded image. 1 for `grayscale` and 3 for `rgb`. 26 | image_format: 0-D `string`. image format type one of `bmp`, `gif`, `jpeg`, 27 | `jpg`, `png` and `mix`. `mix` mean contains many types image format. 28 | Returns: 29 | `Tensor` with type uint8 and shape `[height, width, num_channels]` for 30 | BMP, JPEG, and PNG images and shape `[num_frames, height, width, 3]` for 31 | GIF images. 32 | Raises: 33 | ValueError: On incorrect number of channels. 34 | """ 35 | assert channel in [0, 1, 3], 'channel should be one of [0, 1, 3].' 36 | image = tf.io.read_file(filename) 37 | if image_format=='png': 38 | image = tf.image.decode_png(image, channel) 39 | elif image_format=='bmp': 40 | image = tf.image.decode_bmp(image, channel) 41 | elif image_format=='gif': 42 | image = tf.image.decode_gif(image) 43 | elif image_format in ["jpg", "jpeg"]: 44 | image = tf.image.decode_jpeg(image, channel) 45 | elif image_format=='mix': 46 | image = tf.image.decode_image(image) 47 | else: 48 | raise ValueError('image_format should be one of "mix", "jpg", "jpeg", "png", "gif", "bmp".') 49 | return image 50 | 51 | def RandomBrightness(image, delta, seed=None): 52 | """Adjust the brightness of RGB or Grayscale images. 53 | 54 | Tips: 55 | delta extreme value in the interval [-1, 1], >1 to white, <-1 to black. 56 | a suitable interval is [-0.5, 0.5]. 57 | 0 means pixel value no change. 58 | Args: 59 | image: Tensor or array. An image. 60 | delta: if int, float, Amount to add to the pixel values. 61 | if list, tuple, randomly picked in the interval 62 | `[delta[0], delta[1])` to add to the pixel values. 63 | seed: A Python integer. Used to create a random seed. See 64 | `tf.set_random_seed` for behavior. 65 | Returns: 66 | A brightness-adjusted tensor of the same shape and type as `image`. 67 | Raises: 68 | ValueError: if `delta` type is error. 69 | """ 70 | if isinstance(delta, (int, float)): 71 | assert -1<=delta<=1, 'delta should be in the interval [-1, 1].' 72 | image = tf.image.adjust_brightness(image, delta) 73 | elif isinstance(delta, (list, tuple)): 74 | assert -1<=delta[0]= delta[1] > delta[0] >= -1.' 75 | random_delta = tf.random.uniform([], delta[0], delta[1], seed=seed) 76 | image = tf.image.adjust_brightness(image, random_delta) 77 | else: 78 | raise ValueError('delta should be one of int, float, list, tuple.') 79 | return image 80 | 81 | def RandomContrast(image, delta, seed=None): 82 | """Adjust contrast of RGB or grayscale images. 83 | 84 | `images` is a tensor of at least 3 dimensions. The last 3 dimensions are 85 | interpreted as `[height, width, channels]`. The other dimensions only 86 | represent a collection of images, such as `[batch, height, width, channels].` 87 | 88 | Contrast is adjusted independently for each channel of each image. 89 | 90 | For each channel, this Ops computes the mean of the image pixels in the 91 | channel and then adjusts each component `x` of each pixel to 92 | `(x - mean) * delta + mean`. 93 | 94 | Tips: 95 | 1 means pixel value no change. 96 | 0 means all pixel equal. 97 | a suitable interval is (0, 4]. 98 | Args: 99 | images: Tensor or array. An image. At least 3-D. 100 | delta: if int, float, a float multiplier for adjusting contrast. 101 | if list, tuple, randomly picked in the interval 102 | `[delta[0], delta[1])` , value is float multiplier for adjusting contrast. 103 | seed: A Python integer. Used to create a random seed. See 104 | `tf.set_random_seed` for behavior. 105 | Returns: 106 | The contrast-adjusted image or images tensor of the same shape and type as `image`. 107 | Raises: 108 | ValueError: if `delta` type is error. 109 | """ 110 | if isinstance(delta, (int, float)): 111 | image = tf.image.adjust_contrast(image, delta) 112 | elif isinstance(delta, (list, tuple)): 113 | assert delta[0] delta[0].' 114 | random_delta = tf.random.uniform([], delta[0], delta[1], seed=seed) 115 | image = tf.image.adjust_contrast(image, random_delta) 116 | else: 117 | raise ValueError('delta should be one of int, float, list, tuple.') 118 | return image 119 | 120 | def RandomHue(image, delta, seed=None): 121 | """Adjust hue of an RGB image. 122 | 123 | `image` is an RGB image. The image hue is adjusted by converting the 124 | image to HSV and rotating the hue channel (H) by `delta`. 125 | The image is then converted back to RGB. 126 | 127 | Tips: 128 | `delta` should be in the interval `[-1, 1]`, but any value is allowed. 129 | a suitable interval is [-0.5, 0.5]. 130 | int value means pixel value no change. 131 | Args: 132 | image: Tensor or array. RGB image or images. Size of the last dimension must be 3. 133 | delta: if float, How much to add to the hue channel. 134 | if list, tuple, randomly picked in the interval 135 | `[delta[0], delta[1])` , value is how much to add to the hue channel. 136 | seed: A Python integer. Used to create a random seed. See 137 | `tf.set_random_seed` for behavior. 138 | Returns: 139 | The hue-adjusted image or images tensor of the same shape and type as `image`. 140 | Raises: 141 | ValueError: if `delta` type is error. 142 | """ 143 | if isinstance(delta, (int, float)): 144 | image = tf.image.adjust_hue(image, delta) 145 | elif isinstance(delta, (list, tuple)): 146 | assert delta[0] delta[0].' 147 | random_delta = tf.random.uniform([], delta[0], delta[1], seed=seed) 148 | image = tf.image.adjust_hue(image, random_delta) 149 | else: 150 | raise ValueError('delta should be one of int, float, list, tuple.') 151 | return image 152 | 153 | def RandomSaturation(image, delta, seed=None): 154 | """Adjust saturation of an RGB image. 155 | 156 | `image` is an RGB image. The image saturation is adjusted by converting the 157 | image to HSV and multiplying the saturation (S) channel by `delta` and clipping. 158 | The image is then converted back to RGB. 159 | 160 | Tips: 161 | if delta <= 0, image channels value are equal, image color is gray. 162 | a suitable interval is delta >0 163 | Args: 164 | image: RGB image or images. Size of the last dimension must be 3. 165 | delta: if int, float, Factor to multiply the saturation by. 166 | if list, tuple, randomly picked in the interval 167 | `[delta[0], delta[1])` , value is factor to multiply the saturation by. 168 | seed: A Python integer. Used to create a random seed. See 169 | `tf.set_random_seed` for behavior. 170 | Returns: 171 | The saturation-adjusted image or images tensor of the same shape and type as `image`. 172 | Raises: 173 | ValueError: if `delta` type is error. 174 | """ 175 | if isinstance(delta, (int, float)): 176 | image = tf.image.adjust_saturation(image, delta) 177 | elif isinstance(delta, (list, tuple)): 178 | assert delta[0] delta[0].' 179 | image = tf.image.random_saturation(image, delta[0], delta[1], seed=seed) 180 | else: 181 | raise ValueError('delta should be one of int, float, list, tuple.') 182 | return image 183 | 184 | def RandomGamma(image, gamma, seed=None): 185 | """Performs Gamma Correction on the input image. 186 | 187 | Also known as Power Law Transform. This function transforms the 188 | input image pixelwise according to the equation `Out = In**gamma` 189 | after scaling each pixel to the range 0 to 1. 190 | 191 | Tips: 192 | For gamma greater than 1, the histogram will shift towards left and 193 | the output image will be darker than the input image. 194 | For gamma less than 1, the histogram will shift towards right and 195 | the output image will be brighter than the input image. 196 | if gamma is 1, image pixel value no change. 197 | Args: 198 | image : A Tensor. 199 | gamma : if int, float, Non negative real number. 200 | if list, tuple, randomly picked in the interval 201 | `[delta[0], delta[1])` , value is Non negative real number. 202 | seed: A Python integer. Used to create a random seed. See 203 | `tf.set_random_seed` for behavior. 204 | Returns: 205 | A float Tensor. Gamma corrected output image. 206 | Raises: 207 | ValueError: If gamma is negative. 208 | References: 209 | [1] http://en.wikipedia.org/wiki/Gamma_correction 210 | """ 211 | image = tf.cast(image, dtype=tf.float32) 212 | if isinstance(gamma, (int, float)): 213 | assert 0 0.' 214 | image = tf.image.adjust_gamma(image, gamma, gain=1) 215 | elif isinstance(gamma, (list, tuple)): 216 | assert 0 gamma[0] > 0.' 217 | random_gamma = tf.random.uniform([], gamma[0], gamma[1], seed=seed) 218 | image = tf.image.adjust_gamma(image, random_gamma, gain=1) 219 | else: 220 | raise ValueError('gamma should be one of int, float, list, tuple.') 221 | return image 222 | 223 | def RandomFlipLeftRight(image, random=True, seed=None): 224 | """Randomly flip an image horizontally (left to right). 225 | 226 | With a 1 in 2 chance, outputs the contents of `image` flipped along the 227 | second dimension, which is `width`. Otherwise output the image as-is. 228 | Args: 229 | image: 4-D Tensor of shape `[batch, height, width, channels]` or 230 | 3-D Tensor of shape `[height, width, channels]`. 231 | random: bool, default True. 232 | if True, random flip left or rignt image. 233 | if False, flip left or right image. 234 | seed: A Python integer. Used to create a random seed. See 235 | `tf.set_random_seed` for behavior. 236 | Returns: 237 | A tensor of the same type and shape as `image`. 238 | Raises: 239 | ValueError: if the shape of `image` not supported or `random` dtype not bool. 240 | """ 241 | assert isinstance(random, bool), 'random should be bool type.' 242 | if random: 243 | image = tf.image.random_flip_left_right(image, seed=seed) 244 | else: 245 | image = tf.image.flip_left_right(image) 246 | return image 247 | 248 | def RandomFlipTopBottom(image, random=True, seed=None): 249 | """Randomly flips an image vertically (upside down). 250 | 251 | With a 1 in 2 chance, outputs the contents of `image` flipped along the first 252 | dimension, which is `height`. Otherwise output the image as-is. 253 | Args: 254 | image: 4-D Tensor of shape `[batch, height, width, channels]` or 255 | 3-D Tensor of shape `[height, width, channels]`. 256 | random: bool, default True. 257 | if True, random flip top or bottom image. 258 | if False, flip top or bottom image. 259 | seed: A Python integer. Used to create a random seed. See 260 | `tf.set_random_seed` for behavior. 261 | Returns: 262 | A tensor of the same type and shape as `image`. 263 | Raises: 264 | ValueError: if the shape of `image` not supported or `random` dtype not bool. 265 | """ 266 | assert isinstance(random, bool), 'random should be bool type.' 267 | if random: 268 | image = tf.image.random_flip_up_down(image, seed=seed) 269 | else: 270 | image = tf.image.flip_up_down(image) 271 | return image 272 | 273 | def RandomTranspose(image, random=True, seed=None): 274 | """Transpose image(s) by swapping the height and width dimension. 275 | 276 | Args: 277 | image: 4-D Tensor of shape `[batch, height, width, channels]` or 278 | 3-D Tensor of shape `[height, width, channels]`. 279 | random: bool, default True. 280 | if True, random transpose image. 281 | if False, transpose image. 282 | seed: A Python integer. Used to create a random seed. 283 | See `tf.set_random_seed` for behavior. 284 | Returns: 285 | If `image` was 4-D, a 4-D float Tensor of shape `[batch, width, height, channels]`. 286 | If `image` was 3-D, a 3-D float Tensor of shape `[width, height, channels]`. 287 | Raises: 288 | ValueError: if the shape of `image` not supported or `random` dtype not bool. 289 | """ 290 | assert isinstance(random, bool), 'random should be bool type.' 291 | if random: 292 | r = tf.random.uniform([2], 0, 1, seed=seed) 293 | image = tf.case([(tf.less(r[0], r[1]), lambda: tf.image.transpose_image(image))], 294 | default=lambda: image) 295 | else: 296 | image = tf.image.transpose_image(image) 297 | return image 298 | 299 | def RandomRotation(image, k=[0, 1, 2, 3], seed=None): 300 | """Rotate image(s) counter-clockwise by 90 degrees. 301 | 302 | Tips: 303 | k should be int one of [1, 2, 3] or sublist in the [0, 1, 2, 3]. 304 | Args: 305 | image: 4-D Tensor of shape `[batch, height, width, channels]` or 306 | 3-D Tensor of shape `[height, width, channels]`. 307 | k: if k is list, random select t form k, rotation image by 90 degrees * t. 308 | if k is int, rotation image by 90 degrees * k. 309 | seed: A Python integer. Used to create a random seed. 310 | See `tf.set_random_seed` for behavior. 311 | Returns: 312 | A rotated tensor of the same type and shape as `image`. 313 | Raises: 314 | ValueError: if the shape of `image` not supported or `k` dtype not int or list. 315 | """ 316 | if isinstance(k, list): 317 | k_value = tf.convert_to_tensor(k) 318 | index = tf.argmax(tf.random.uniform([tf.shape(k_value)[0]], 0, 1)) 319 | image = tf.image.rot90(image, k=k_value[index]) 320 | elif k in [1, 2, 3]: 321 | image = tf.image.rot90(image, k) 322 | else: 323 | raise ValueError('k should be int one of [1, 2, 3] or sublist in the [0, 1, 2, 3].') 324 | return image 325 | 326 | def RandomCropCentralResize(image, central_rate, size, method=0, seed=None): 327 | """Crop the central region of the image(s) and resize specify shape. 328 | 329 | Remove the outer parts of an image but retain the central region of the image 330 | along each dimension. If we specify central_fraction = 0.5, this function 331 | returns the region marked with "X" in the below diagram. 332 | -------- 333 | | | 334 | | XXXX | 335 | | XXXX | 336 | | | where "X" is the central 50% of the image. 337 | -------- 338 | 339 | This function works on either a single image (`image` is a 3-D Tensor), or a 340 | batch of images (`image` is a 4-D Tensor). 341 | 342 | Tips: 343 | method should be one of [0, 1, 2, 3], "0:bilinear", "1:nearest_neighbor", "2:bicubic", "3:area". 344 | Args: 345 | image: Either a 3-D float Tensor of shape [height, width, depth], or a 4-D 346 | Tensor of shape [batch_size, height, width, depth]. 347 | central_rate: if int float, should be in the interval (0, 1], fraction of size to crop. 348 | if tuple list, randomly picked in the interval 349 | `[central_rate[0], central_rate[1])`, value is fraction of size to crop. 350 | size: A 1-D int32 Tensor of 2 elements: `new_height, new_width`. 351 | The new size for the images. 352 | method: int, default 0. resize image shape method. 353 | should be one of "0:bilinear", "1:nearest_neighbor", "2:bicubic", "3:area" 354 | seed: A Python integer. Used to create a random seed. 355 | See `tf.set_random_seed` for behavior. 356 | Returns: 357 | 3-D / 4-D float Tensor, as per the input. 358 | Raises: 359 | ValueError: if central_crop_fraction is not within (0, 1]. 360 | """ 361 | assert isinstance(size, (tuple, list)), 'size should be one of tuple, list.' 362 | assert method in [0, 1, 2, 3], 'method should be one of "0:bilinear", "1:nearest_neighbor", "2:bicubic", "3:area"' 363 | if isinstance(central_rate, (int, float)): 364 | assert 0= central_rate[1] > central_rate[0] > 0.' 368 | random_central_rate = tf.random.uniform([], central_rate[0], central_rate[1], seed=seed) 369 | image = tf.image.central_crop(image, central_fraction=random_central_rate) 370 | else: 371 | raise ValueError('central_rate should be one of int, float, tuple, list.') 372 | image = tf.image.resize_images(image, size=size, method=method) 373 | return image 374 | 375 | def RandomCropPointResize(image, height_rate, width_rate, size, method=0, seed=None): 376 | """Crop the any region of the image(s) and resize specify shape. 377 | 378 | Crop region area = height_rate * width_rate *image_height * image_width 379 | 380 | This function works on either a single image (`image` is a 3-D Tensor), or a 381 | batch of images (`image` is a 4-D Tensor). 382 | 383 | Tips: 384 | method should be one of [0, 1, 2, 3], "0:bilinear", "1:nearest_neighbor", "2:bicubic", "3:area". 385 | Args: 386 | image: Either a 3-D float Tensor of shape [height, width, depth], or a 4-D 387 | Tensor of shape [batch_size, height, width, depth]. 388 | height_rate: flaot, in the interval (0, 1]. 389 | width_rate: flaot, in the interval (0, 1]. 390 | size: A 1-D int32 Tensor of 2 elements: `new_height, new_width`. 391 | The new size for the images. 392 | method: int, default 0. resize image shape method. 393 | should be one of "0:bilinear", "1:nearest_neighbor", "2:bicubic", "3:area" 394 | seed: A Python integer. Used to create a random seed. 395 | See `tf.set_random_seed` for behavior. 396 | Returns: 397 | 3-D / 4-D float Tensor, as per the input. 398 | Raises: 399 | ValueError: if central_crop_fraction is not within (0, 1]. 400 | """ 401 | assert isinstance(height_rate, (int, float)), 'height_rate should be one of int, float.' 402 | assert isinstance(width_rate, (int, float)), 'width_rate should be one of int, float.' 403 | assert 0 delta, output = x - delta; 9 | if x < -delta, output = x + delta; 10 | otherwise, output = 0 11 | Args: 12 | x: A Tensor with type float32 or float64. 13 | delta: the value for the Softshrink formulation. Default: 0.5 14 | name: A name for the operation (optional). 15 | Returns: 16 | A Tensor with the same type as x. 17 | """ 18 | def f1(): return x+delta 19 | def f2(): return x-delta 20 | def f3(): return 0. 21 | return tf.case({tf.less(x, -delta): f1, 22 | tf.greater(x, delta): f2}, 23 | default=f3, exclusive=True) 24 | 25 | def tanhshrink(x, name=None): 26 | """Applies the tanh shrinkage function elementwise: 27 | 28 | output = x - tanh(x) 29 | Args: 30 | x: A Tensor with type float32 or float64. 31 | name: A name for the operation (optional). 32 | Returns: 33 | A Tensor with the same type as x. 34 | """ 35 | return tf.math.subtract(x, tf.math.tanh(x)) 36 | 37 | def softmin(x, axis=None, name=None): 38 | """Applies the Softmin function to an n-dimensional 39 | input Tensor rescaling them so that the elements of 40 | the n-dimensional output Tensor lie in the range (0, 1) and sum to 1 41 | 42 | output = exp(-x)/sum(exp(-x)) 43 | Args: 44 | x: A Tensor with type float32 or float64. 45 | axis: The dimension softmax would be performed on. The default is -1 which indicates the last dimension. 46 | name: A name for the operation (optional). 47 | Returns: 48 | A Tensor with the same type as x. 49 | """ 50 | return tf.exp(-x) / tf.reduce_sum(tf.exp(-x), axis) 51 | 52 | def log_softmin(x, axis=None, name=None): 53 | """Applies the log Softmin function to an n-dimensional 54 | input Tensor rescaling them so that the elements of 55 | the n-dimensional output Tensor lie in the range (0, 1) and sum to 1 56 | 57 | output = log(exp(-x)/sum(exp(-x))) 58 | Args: 59 | x: A Tensor with type float32 or float64. 60 | axis: The dimension softmax would be performed on. The default is -1 which indicates the last dimension. 61 | name: A name for the operation (optional). 62 | Returns: 63 | A Tensor with the same type as x. 64 | """ 65 | return tf.math.log(tf.exp(-x) / tf.reduce_sum(tf.exp(-x), axis)) 66 | --------------------------------------------------------------------------------