diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/LICENSE b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..a6b1b1f81516e54b703287701c163c04f59c44dd --- /dev/null +++ b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/LICENSE @@ -0,0 +1,203 @@ +Copyright 2019 The TensorFlow Authors. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/README.md b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/README.md new file mode 100644 index 0000000000000000000000000000000000000000..e8b2ac84876a98d583152ba6984185d665c475e3 --- /dev/null +++ b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/README.md @@ -0,0 +1,49 @@ +# Efficientnet-CondConv +Condconv即有条件参数化卷积,为每个样本学习专有的卷积内核。用CondConv替换正常卷积,能够增加网络的大小和容量,同时保持有效的推理。参考文章为 CondConv: Conditionally Parameterized Convolutions for Efficient Inference 参考项目:https://github.com/tensorflow/tpu/tree/master/models/official/efficientnet/condconv. + + +# setup +* python 3.7.5+ +* tensorflow-gpu 1.15.0+ +* numpy 1.14.1+ + + +# Train + +数据集: 请用户自行准备好数据集,包含训练集和验证集两部分,可选用的数据集包括ImageNet2012,CIFAR10、Flower等,包含train和val两部分。格式为TFRecord文件。 + +Boot File:boot_modelarts.py + +Pretrained: obs://cann-lhz/MA-new-efficientnet-condconv_tensorflow_ID2074-11-26-22-22/output/result/archive/ + + +# 精度对比 +测试集:Imagenet2012 + +论文精度: + +| Precision | +| :--------: | +| 78.3% | + +GPU目标精度: + +| Precision | +| :--------: | +| 80.0% | + +Ascend精度: + +| Precision | +| :--------: | +| 80.9% | + + +# 性能对比: + +| GPU V100 | Ascend 910 | +| :--------: | --------| +| 1.90global_step/s | 2.47global_step/s | + + + diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/__init__.py b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..24bdf40107d2ba295b23a7fc81cbb25424167c16 --- /dev/null +++ b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/__init__.py @@ -0,0 +1,28 @@ +# Copyright 2019 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""The initial file of the efficientnet.""" \ No newline at end of file diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/autoaugment.py b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/autoaugment.py new file mode 100644 index 0000000000000000000000000000000000000000..e76245cf6fd15537d13d7cfc5f1d2e117da78b0f --- /dev/null +++ b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/autoaugment.py @@ -0,0 +1,735 @@ +# Copyright 2019 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""AutoAugment and RandAugment policies for enhanced image preprocessing. + +AutoAugment Reference: https://arxiv.org/abs/1805.09501 +RandAugment Reference: https://arxiv.org/abs/1909.13719 +""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import inspect +import math +import tensorflow.compat.v1 as tf +from tensorflow.contrib import image as contrib_image +from tensorflow.contrib import training as contrib_training + + +# This signifies the max integer that the controller RNN could predict for the +# augmentation scheme. +_MAX_LEVEL = 10. + + +def policy_v0(): + """Autoaugment policy that was used in AutoAugment Paper.""" + # Each tuple is an augmentation operation of the form + # (operation, probability, magnitude). Each element in policy is a + # sub-policy that will be applied sequentially on the image. + policy = [ + [('Equalize', 0.8, 1), ('ShearY', 0.8, 4)], + [('Color', 0.4, 9), ('Equalize', 0.6, 3)], + [('Color', 0.4, 1), ('Rotate', 0.6, 8)], + [('Solarize', 0.8, 3), ('Equalize', 0.4, 7)], + [('Solarize', 0.4, 2), ('Solarize', 0.6, 2)], + [('Color', 0.2, 0), ('Equalize', 0.8, 8)], + [('Equalize', 0.4, 8), ('SolarizeAdd', 0.8, 3)], + [('ShearX', 0.2, 9), ('Rotate', 0.6, 8)], + [('Color', 0.6, 1), ('Equalize', 1.0, 2)], + [('Invert', 0.4, 9), ('Rotate', 0.6, 0)], + [('Equalize', 1.0, 9), ('ShearY', 0.6, 3)], + [('Color', 0.4, 7), ('Equalize', 0.6, 0)], + [('Posterize', 0.4, 6), ('AutoContrast', 0.4, 7)], + [('Solarize', 0.6, 8), ('Color', 0.6, 9)], + [('Solarize', 0.2, 4), ('Rotate', 0.8, 9)], + [('Rotate', 1.0, 7), ('TranslateY', 0.8, 9)], + [('ShearX', 0.0, 0), ('Solarize', 0.8, 4)], + [('ShearY', 0.8, 0), ('Color', 0.6, 4)], + [('Color', 1.0, 0), ('Rotate', 0.6, 2)], + [('Equalize', 0.8, 4), ('Equalize', 0.0, 8)], + [('Equalize', 1.0, 4), ('AutoContrast', 0.6, 2)], + [('ShearY', 0.4, 7), ('SolarizeAdd', 0.6, 7)], + [('Posterize', 0.8, 2), ('Solarize', 0.6, 10)], + [('Solarize', 0.6, 8), ('Equalize', 0.6, 1)], + [('Color', 0.8, 6), ('Rotate', 0.4, 5)], + ] + return policy + + +def policy_vtest(): + """Autoaugment test policy for debugging.""" + # Each tuple is an augmentation operation of the form + # (operation, probability, magnitude). Each element in policy is a + # sub-policy that will be applied sequentially on the image. + policy = [ + [('TranslateX', 1.0, 4), ('Equalize', 1.0, 10)], + ] + return policy + + +def blend(image1, image2, factor): + """Blend image1 and image2 using 'factor'. + + Factor can be above 0.0. A value of 0.0 means only image1 is used. + A value of 1.0 means only image2 is used. A value between 0.0 and + 1.0 means we linearly interpolate the pixel values between the two + images. A value greater than 1.0 "extrapolates" the difference + between the two pixel values, and we clip the results to values + between 0 and 255. + + Args: + image1: An image Tensor of type uint8. + image2: An image Tensor of type uint8. + factor: A floating point value above 0.0. + + Returns: + A blended image Tensor of type uint8. + """ + if factor == 0.0: + return tf.convert_to_tensor(image1) + if factor == 1.0: + return tf.convert_to_tensor(image2) + + image1 = tf.to_float(image1) + image2 = tf.to_float(image2) + + difference = image2 - image1 + scaled = factor * difference + + # Do addition in float. + temp = tf.to_float(image1) + scaled + + # Interpolate + if factor > 0.0 and factor < 1.0: + # Interpolation means we always stay within 0 and 255. + return tf.cast(temp, tf.uint8) + + # Extrapolate: + # + # We need to clip and then cast. + return tf.cast(tf.clip_by_value(temp, 0.0, 255.0), tf.uint8) + + +def cutout(image, pad_size, replace=0): + """Apply cutout (https://arxiv.org/abs/1708.04552) to image. + + This operation applies a (2*pad_size x 2*pad_size) mask of zeros to + a random location within `img`. The pixel values filled in will be of the + value `replace`. The located where the mask will be applied is randomly + chosen uniformly over the whole image. + + Args: + image: An image Tensor of type uint8. + pad_size: Specifies how big the zero mask that will be generated is that + is applied to the image. The mask will be of size + (2*pad_size x 2*pad_size). + replace: What pixel value to fill in the image in the area that has + the cutout mask applied to it. + + Returns: + An image Tensor that is of type uint8. + """ + image_height = tf.shape(image)[0] + image_width = tf.shape(image)[1] + + # Sample the center location in the image where the zero mask will be applied. + cutout_center_height = tf.random_uniform( + shape=[], minval=0, maxval=image_height, + dtype=tf.int32) + + cutout_center_width = tf.random_uniform( + shape=[], minval=0, maxval=image_width, + dtype=tf.int32) + + lower_pad = tf.maximum(0, cutout_center_height - pad_size) + upper_pad = tf.maximum(0, image_height - cutout_center_height - pad_size) + left_pad = tf.maximum(0, cutout_center_width - pad_size) + right_pad = tf.maximum(0, image_width - cutout_center_width - pad_size) + + cutout_shape = [image_height - (lower_pad + upper_pad), + image_width - (left_pad + right_pad)] + padding_dims = [[lower_pad, upper_pad], [left_pad, right_pad]] + mask = tf.pad( + tf.zeros(cutout_shape, dtype=image.dtype), + padding_dims, constant_values=1) + mask = tf.expand_dims(mask, -1) + mask = tf.tile(mask, [1, 1, 3]) + image = tf.where( + tf.equal(mask, 0), + tf.ones_like(image, dtype=image.dtype) * replace, + image) + return image + + +def solarize(image, threshold=128): + """For each pixel in the image, select the pixel + if the value is less than the threshold. + Otherwise, subtract 255 from the pixel. + """ + return tf.where(image < threshold, image, 255 - image) + + +def solarize_add(image, addition=0, threshold=128): + """For each pixel in the image less than threshold + we add 'addition' amount to it and then clip the + pixel value to be between 0 and 255. The value + of 'addition' is between -128 and 128. + """ + added_image = tf.cast(image, tf.int64) + addition + added_image = tf.cast(tf.clip_by_value(added_image, 0, 255), tf.uint8) + return tf.where(image < threshold, added_image, image) + + +def color(image, factor): + """Equivalent of PIL Color.""" + degenerate = tf.image.grayscale_to_rgb(tf.image.rgb_to_grayscale(image)) + return blend(degenerate, image, factor) + + +def contrast(image, factor): + """Equivalent of PIL Contrast.""" + degenerate = tf.image.rgb_to_grayscale(image) + # Cast before calling tf.histogram. + degenerate = tf.cast(degenerate, tf.int32) + + # Compute the grayscale histogram, then compute the mean pixel value, + # and create a constant image size of that value. Use that as the + # blending degenerate target of the original image. + hist = tf.histogram_fixed_width(degenerate, [0, 255], nbins=256) + mean = tf.reduce_sum(tf.cast(hist, tf.float32)) / 256.0 + degenerate = tf.ones_like(degenerate, dtype=tf.float32) * mean + degenerate = tf.clip_by_value(degenerate, 0.0, 255.0) + degenerate = tf.image.grayscale_to_rgb(tf.cast(degenerate, tf.uint8)) + return blend(degenerate, image, factor) + + +def brightness(image, factor): + """Equivalent of PIL Brightness.""" + degenerate = tf.zeros_like(image) + return blend(degenerate, image, factor) + + +def posterize(image, bits): + """Equivalent of PIL Posterize.""" + shift = 8 - bits + return tf.bitwise.left_shift(tf.bitwise.right_shift(image, shift), shift) + + +def rotate(image, degrees, replace): + """Rotates the image by degrees either clockwise or counterclockwise. + + Args: + image: An image Tensor of type uint8. + degrees: Float, a scalar angle in degrees to rotate all images by. If + degrees is positive the image will be rotated clockwise otherwise it will + be rotated counterclockwise. + replace: A one or three value 1D tensor to fill empty pixels caused by + the rotate operation. + + Returns: + The rotated version of image. + """ + # Convert from degrees to radians. + degrees_to_radians = math.pi / 180.0 + radians = degrees * degrees_to_radians + + # In practice, we should randomize the rotation degrees by flipping + # it negatively half the time, but that's done on 'degrees' outside + # of the function. + image = contrib_image.rotate(wrap(image), radians) + return unwrap(image, replace) + + +def translate_x(image, pixels, replace): + """Equivalent of PIL Translate in X dimension.""" + image = contrib_image.translate(wrap(image), [-pixels, 0]) + return unwrap(image, replace) + + +def translate_y(image, pixels, replace): + """Equivalent of PIL Translate in Y dimension.""" + image = contrib_image.translate(wrap(image), [0, -pixels]) + return unwrap(image, replace) + + +def shear_x(image, level, replace): + """Equivalent of PIL Shearing in X dimension.""" + # Shear parallel to x axis is a projective transform + # with a matrix form of: + # [1 level + # 0 1]. + image = contrib_image.transform( + wrap(image), [1., level, 0., 0., 1., 0., 0., 0.]) + return unwrap(image, replace) + + +def shear_y(image, level, replace): + """Equivalent of PIL Shearing in Y dimension.""" + # Shear parallel to y axis is a projective transform + # with a matrix form of: + # [1 0 + # level 1]. + image = contrib_image.transform( + wrap(image), [1., 0., 0., level, 1., 0., 0., 0.]) + return unwrap(image, replace) + + +def autocontrast(image): + """Implements Autocontrast function from PIL using TF ops. + + Args: + image: A 3D uint8 tensor. + + Returns: + The image after it has had autocontrast applied to it and will be of type + uint8. + """ + + def scale_channel(image): + """Scale the 2D image using the autocontrast rule.""" + # A possibly cheaper version can be done using cumsum/unique_with_counts + # over the histogram values, rather than iterating over the entire image. + # to compute mins and maxes. + lo = tf.to_float(tf.reduce_min(image)) + hi = tf.to_float(tf.reduce_max(image)) + + + def scale_values(im): + """Scale the image, making the lowest value 0 and the highest value 255.""" + scale = 255.0 / (hi - lo) + offset = -lo * scale + im = tf.to_float(im) * scale + offset + im = tf.clip_by_value(im, 0.0, 255.0) + return tf.cast(im, tf.uint8) + + result = tf.cond(hi > lo, lambda: scale_values(image), lambda: image) + return result + + # Assumes RGB for now. Scales each channel independently + # and then stacks the result. + s1 = scale_channel(image[:, :, 0]) + s2 = scale_channel(image[:, :, 1]) + s3 = scale_channel(image[:, :, 2]) + image = tf.stack([s1, s2, s3], 2) + return image + + +def sharpness(image, factor): + """Implements Sharpness function from PIL using TF ops.""" + orig_image = image + image = tf.cast(image, tf.float32) + # Make image 4D for conv operation. + image = tf.expand_dims(image, 0) + # SMOOTH PIL Kernel. + kernel = tf.constant( + [[1, 1, 1], [1, 5, 1], [1, 1, 1]], dtype=tf.float32, + shape=[3, 3, 1, 1]) / 13. + # Tile across channel dimension. + kernel = tf.tile(kernel, [1, 1, 3, 1]) + strides = [1, 1, 1, 1] + with tf.device('/cpu:0'): + # Some augmentation that uses depth-wise conv will cause crashing when + # training on GPU. See (b/156242594) for details. + degenerate = tf.nn.depthwise_conv2d( + image, kernel, strides, padding='VALID', rate=[1, 1]) + degenerate = tf.clip_by_value(degenerate, 0.0, 255.0) + degenerate = tf.squeeze(tf.cast(degenerate, tf.uint8), [0]) + + # For the borders of the resulting image, fill in the values of the + # original image. + mask = tf.ones_like(degenerate) + padded_mask = tf.pad(mask, [[1, 1], [1, 1], [0, 0]]) + padded_degenerate = tf.pad(degenerate, [[1, 1], [1, 1], [0, 0]]) + result = tf.where(tf.equal(padded_mask, 1), padded_degenerate, orig_image) + + # Blend the final result. + return blend(result, orig_image, factor) + + +def equalize(image): + """Implements Equalize function from PIL using TF ops.""" + def scale_channel(im, c): + """Scale the data in the channel to implement equalize.""" + im = tf.cast(im[:, :, c], tf.int32) + # Compute the histogram of the image channel. + histo = tf.histogram_fixed_width(im, [0, 255], nbins=256) + + # For the purposes of computing the step, filter out the nonzeros. + nonzero = tf.where(tf.not_equal(histo, 0)) + nonzero_histo = tf.reshape(tf.gather(histo, nonzero), [-1]) + step = (tf.reduce_sum(nonzero_histo) - nonzero_histo[-1]) // 255 + + def build_lut(histo, step): + """ Compute the cumulative sum, shifting by step // 2 and then normalization by step. """ + lut = (tf.cumsum(histo) + (step // 2)) // step + # Shift lut, prepending with 0. + lut = tf.concat([[0], lut[:-1]], 0) + # Clip the counts to be in range. This is done + # in the C code for image.point. + return tf.clip_by_value(lut, 0, 255) + + # If step is zero, return the original image. Otherwise, build + # lut from the full histogram and step and then index from it. + result = tf.cond(tf.equal(step, 0), + lambda: im, + lambda: tf.gather(build_lut(histo, step), im)) + + return tf.cast(result, tf.uint8) + + # Assumes RGB for now. Scales each channel independently + # and then stacks the result. + s1 = scale_channel(image, 0) + s2 = scale_channel(image, 1) + s3 = scale_channel(image, 2) + image = tf.stack([s1, s2, s3], 2) + return image + + +def invert(image): + """Inverts the image pixels.""" + image = tf.convert_to_tensor(image) + return 255 - image + + +def wrap(image): + """Returns 'image' with an extra channel set to all 1s.""" + shape = tf.shape(image) + extended_channel = tf.ones([shape[0], shape[1], 1], image.dtype) + extended = tf.concat([image, extended_channel], 2) + return extended + + +def unwrap(image, replace): + """Unwraps an image produced by wrap. + + Where there is a 0 in the last channel for every spatial position, + the rest of the three channels in that spatial dimension are grayed + (set to 128). Operations like translate and shear on a wrapped + Tensor will leave 0s in empty locations. Some transformations look + at the intensity of values to do preprocessing, and we want these + empty pixels to assume the 'average' value, rather than pure black. + + + Args: + image: A 3D Image Tensor with 4 channels. + replace: A one or three value 1D tensor to fill empty pixels. + + Returns: + image: A 3D image Tensor with 3 channels. + """ + image_shape = tf.shape(image) + # Flatten the spatial dimensions. + flattened_image = tf.reshape(image, [-1, image_shape[2]]) + + # Find all pixels where the last channel is zero. + alpha_channel = flattened_image[:, 3] + + replace = tf.concat([replace, tf.ones([1], image.dtype)], 0) + + # Where they are zero, fill them in with 'replace'. + flattened_image = tf.where( + tf.equal(alpha_channel, 0), + tf.ones_like(flattened_image, dtype=image.dtype) * replace, + flattened_image) + + image = tf.reshape(flattened_image, image_shape) + image = tf.slice(image, [0, 0, 0], [image_shape[0], image_shape[1], 3]) + return image + + +NAME_TO_FUNC = { + 'AutoContrast': autocontrast, + 'Equalize': equalize, + 'Invert': invert, + 'Rotate': rotate, + 'Posterize': posterize, + 'Solarize': solarize, + 'SolarizeAdd': solarize_add, + 'Color': color, + 'Contrast': contrast, + 'Brightness': brightness, + 'Sharpness': sharpness, + 'ShearX': shear_x, + 'ShearY': shear_y, + 'TranslateX': translate_x, + 'TranslateY': translate_y, + 'Cutout': cutout, +} + + +def _randomly_negate_tensor(tensor): + """With 50% prob turn the tensor negative.""" + should_flip = tf.cast(tf.floor(tf.random_uniform([]) + 0.5), tf.bool) + final_tensor = tf.cond(should_flip, lambda: tensor, lambda: -tensor) + return final_tensor + + +def _rotate_level_to_arg(level): + level = (level / _MAX_LEVEL) * 30. + level = _randomly_negate_tensor(level) + return (level,) + + +def _shrink_level_to_arg(level): + """Converts level to ratio by which we shrink the image content.""" + if level == 0: + return (1.0,) # if level is zero, do not shrink the image + # Maximum shrinking ratio is 2.9. + level = 2. / (_MAX_LEVEL / level) + 0.9 + return (level,) + + +def _enhance_level_to_arg(level): + return ((level / _MAX_LEVEL) * 1.8 + 0.1,) + + +def _shear_level_to_arg(level): + level = (level / _MAX_LEVEL) * 0.3 + # Flip level to negative with 50% chance. + level = _randomly_negate_tensor(level) + return (level,) + + +def _translate_level_to_arg(level, translate_const): + level = (level / _MAX_LEVEL) * float(translate_const) + # Flip level to negative with 50% chance. + level = _randomly_negate_tensor(level) + return (level,) + + +def level_to_arg(hparams): + """Transform parameters from level to arguement.""" + return { + 'AutoContrast': lambda level: (), + 'Equalize': lambda level: (), + 'Invert': lambda level: (), + 'Rotate': _rotate_level_to_arg, + 'Posterize': lambda level: (int((level / _MAX_LEVEL) * 4),), + 'Solarize': lambda level: (int((level / _MAX_LEVEL) * 256),), + 'SolarizeAdd': lambda level: (int((level / _MAX_LEVEL) * 110),), + 'Color': _enhance_level_to_arg, + 'Contrast': _enhance_level_to_arg, + 'Brightness': _enhance_level_to_arg, + 'Sharpness': _enhance_level_to_arg, + 'ShearX': _shear_level_to_arg, + 'ShearY': _shear_level_to_arg, + 'Cutout': lambda level: (int((level / _MAX_LEVEL) * hparams.cutout_const),), + # pylint:disable=g-long-lambda + 'TranslateX': lambda level: _translate_level_to_arg(level, hparams.translate_const), + 'TranslateY': lambda level: _translate_level_to_arg(level, hparams.translate_const), + # pylint:enable=g-long-lambda + } + + +def _parse_policy_info(name, prob, level, replace_value, augmentation_hparams): + """Return the function that corresponds to `name` and update `level` param.""" + func = NAME_TO_FUNC[name] + args = level_to_arg(augmentation_hparams)[name](level) + + # Check to see if prob is passed into function. This is used for operations + # where we alter bboxes independently. + # pytype:disable=wrong-arg-types + if 'prob' in inspect.getargspec(func)[0]: + args = tuple([prob] + list(args)) + # pytype:enable=wrong-arg-types + + # Add in replace arg if it is required for the function that is being called. + # pytype:disable=wrong-arg-types + if 'replace' in inspect.getargspec(func)[0]: + # Make sure replace is the final argument + assert 'replace' == inspect.getargspec(func)[0][-1] + args = tuple(list(args) + [replace_value]) + # pytype:enable=wrong-arg-types + + return (func, prob, args) + + +def _apply_func_with_prob(func, image, args, prob): + """Apply `func` to image w/ `args` as input with probability `prob`.""" + assert isinstance(args, tuple) + + # If prob is a function argument, then this randomness is being handled + # inside the function, so make sure it is always called. + # pytype:disable=wrong-arg-types + if 'prob' in inspect.getargspec(func)[0]: + prob = 1.0 + # pytype:enable=wrong-arg-types + + # Apply the function with probability `prob`. + should_apply_op = tf.cast( + tf.floor(tf.random_uniform([], dtype=tf.float32) + prob), tf.bool) + augmented_image = tf.cond( + should_apply_op, + lambda: func(image, *args), + lambda: image) + return augmented_image + + +def select_and_apply_random_policy(policies, image): + """Select a random policy from `policies` and apply it to `image`.""" + policy_to_select = tf.random_uniform( + [], maxval=len(policies), dtype=tf.int32) + # Note that using tf.case instead of tf.conds would result in significantly + # larger graphs and would even break export for some larger policies. + for (i, policy) in enumerate(policies): + image = tf.cond( + tf.equal(i, policy_to_select), + lambda selected_policy=policy: selected_policy(image), + lambda: image) + return image + + +def build_and_apply_nas_policy(policies, image, + augmentation_hparams): + """Build a policy from the given policies passed in and apply to image. + + Args: + policies: list of lists of tuples in the form `(func, prob, level)`, `func` + is a string name of the augmentation function, `prob` is the probability + of applying the `func` operation, `level` is the input argument for + `func`. + image: tf.Tensor that the resulting policy will be applied to. + augmentation_hparams: Hparams associated with the NAS learned policy. + + Returns: + A version of image that now has data augmentation applied to it based on + the `policies` pass into the function. + """ + replace_value = [128, 128, 128] + + # func is the string name of the augmentation function, prob is the + # probability of applying the operation and level is the parameter associated + # with the tf op. + + # tf_policies are functions that take in an image and return an augmented + # image. + tf_policies = [] + for policy in policies: + tf_policy = [] + # Link string name to the correct python function and make sure the correct + # argument is passed into that function. + for policy_info in policy: + policy_info = list(policy_info) + \ + [replace_value, augmentation_hparams] + + tf_policy.append(_parse_policy_info(*policy_info)) + # Now build the tf policy that will apply the augmentation procedue + # on image. + + def make_final_policy(tf_policy_): + """Make the final policy.""" + def final_policy(image_): + """The final policy.""" + for func, prob, args in tf_policy_: + image_ = _apply_func_with_prob( + func, image_, args, prob) + return image_ + return final_policy + tf_policies.append(make_final_policy(tf_policy)) + + augmented_image = select_and_apply_random_policy( + tf_policies, image) + return augmented_image + + +def distort_image_with_autoaugment(image, augmentation_name): + """Applies the AutoAugment policy to `image`. + + AutoAugment is from the paper: https://arxiv.org/abs/1805.09501. + + Args: + image: `Tensor` of shape [height, width, 3] representing an image. + augmentation_name: The name of the AutoAugment policy to use. The available + options are `v0` and `test`. `v0` is the policy used for + all of the results in the paper and was found to achieve the best results + on the COCO dataset. `v1`, `v2` and `v3` are additional good policies + found on the COCO dataset that have slight variation in what operations + were used during the search procedure along with how many operations are + applied in parallel to a single image (2 vs 3). + + Returns: + A tuple containing the augmented versions of `image`. + """ + available_policies = {'v0': policy_v0, + 'test': policy_vtest} + if augmentation_name not in available_policies: + raise ValueError( + 'Invalid augmentation_name: {}'.format(augmentation_name)) + + policy = available_policies[augmentation_name]() + # Hparams that will be used for AutoAugment. + augmentation_hparams = contrib_training.HParams( + cutout_const=100, translate_const=250) + + return build_and_apply_nas_policy(policy, image, augmentation_hparams) + + +def distort_image_with_randaugment(image, num_layers, magnitude): + """Applies the RandAugment policy to `image`. + + RandAugment is from the paper https://arxiv.org/abs/1909.13719, + + Args: + image: `Tensor` of shape [height, width, 3] representing an image. + num_layers: Integer, the number of augmentation transformations to apply + sequentially to an image. Represented as (N) in the paper. Usually best + values will be in the range [1, 3]. + magnitude: Integer, shared magnitude across all augmentation operations. + Represented as (M) in the paper. Usually best values are in the range + [5, 30]. + + Returns: + The augmented version of `image`. + """ + replace_value = [128] * 3 + tf.logging.info('Using RandAug.') + augmentation_hparams = contrib_training.HParams( + cutout_const=40, translate_const=100) + available_ops = [ + 'AutoContrast', 'Equalize', 'Invert', 'Rotate', 'Posterize', + 'Solarize', 'Color', 'Contrast', 'Brightness', 'Sharpness', + 'ShearX', 'ShearY', 'TranslateX', 'TranslateY', 'Cutout', 'SolarizeAdd'] + + for layer_num in range(num_layers): + op_to_select = tf.random_uniform( + [], maxval=len(available_ops), dtype=tf.int32) + random_magnitude = float(magnitude) + with tf.name_scope('randaug_layer_{}'.format(layer_num)): + for (i, op_name) in enumerate(available_ops): + prob = tf.random_uniform( + [], minval=0.2, maxval=0.8, dtype=tf.float32) + func, _, args = _parse_policy_info(op_name, prob, random_magnitude, + replace_value, augmentation_hparams) + image = tf.cond( + tf.equal(i, op_to_select), + # pylint:disable=g-long-lambda + lambda selected_func=func, selected_args=args: selected_func(image, *selected_args), + # pylint:enable=g-long-lambda + lambda: image) + return image diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/boot_modelarts.py b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/boot_modelarts.py new file mode 100644 index 0000000000000000000000000000000000000000..dcbf0d9d1c1baa53eef80d391e6a121a1441dfca --- /dev/null +++ b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/boot_modelarts.py @@ -0,0 +1,53 @@ +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +""" +This is the boot file for ModelArts platform. +Firstly, the train datasets are copyed from obs to ModelArts. +Then, the string of train shell command is concated and using 'os.system()' to execute +""" +import os +import numpy as np +import argparse +from help_modelarts import obs_data2modelarts + +print(os.system('env')) + +if __name__ == '__main__': + # Note: the code dir is not the same as work dir on ModelArts Platform!!! + code_dir = os.path.dirname(__file__) + work_dir = os.getcwd() + print("===>>>code_dir:{}, work_dir:{}".format(code_dir, work_dir)) + + parser = argparse.ArgumentParser() + parser.add_argument("--data_url", type=str, default=None) + parser.add_argument("--train_url", type=str, default=None) + parser.add_argument("--modelarts_data_dir", type=str, + default="/cache/data_url") + config = parser.parse_args() + + print("--------config----------") + for k in list(vars(config).keys()): + print("key:{}: value:{}".format(k, vars(config)[k])) + print("--------config----------") + + # copy dataset from obs to modelarts + obs_data2modelarts(config) + + # start to train on Modelarts platform + bash_header = os.path.join(code_dir, 'run_1p.sh') + arg_url = '%s %s %s %s' % (code_dir, config.modelarts_data_dir + + '/ILSVRC2012', config.modelarts_data_dir+'/result_eff', config.train_url) + bash_command = 'bash %s %s' % (bash_header, arg_url) + print("bash command:", bash_command) + os.system(bash_command) diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/condconv/__init__.py b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/condconv/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e58dedf12375e12ad97f34320fe4430d3a740a9a --- /dev/null +++ b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/condconv/__init__.py @@ -0,0 +1,28 @@ +# Copyright 2019 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""The initial file of condconv.""" \ No newline at end of file diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/condconv/condconv_layers.py b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/condconv/condconv_layers.py new file mode 100644 index 0000000000000000000000000000000000000000..3aff578424f24de8bcef8ae412d44857ad38c5fe --- /dev/null +++ b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/condconv/condconv_layers.py @@ -0,0 +1,481 @@ +# Copyright 2019 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""CondConv implementations in Tensorflow Layers. + +[1] Brandon Yang, Gabriel Bender, Quoc V. Le, Jiquan Ngiam + CondConv: Conditionally Parameterized Convolutions for Efficient Inference. + NeurIPS'19, https://arxiv.org/abs/1904.04971 +""" + +from __future__ import absolute_import +from __future__ import division +# Standard imports +from __future__ import print_function + +import numpy as np +import tensorflow.compat.v1 as tf + + +def get_condconv_initializer(initializer, num_experts, expert_shape): + """Wraps the initializer to correctly initialize CondConv variables. + + CondConv initializes biases and kernels in a num_experts x num_params + matrix for efficient computation. This wrapper ensures that each expert + is correctly initialized with the given initializer before being flattened + into the correctly shaped CondConv variable. + + Arguments: + initializer: The initializer to apply for each individual expert. + num_experts: The number of experts to be initialized. + expert_shape: The original shape of each individual expert. + + Returns: + The initializer for the num_experts x num_params CondConv variable. + """ + def condconv_initializer(expected_shape, dtype=None, partition=None): + """CondConv initializer function.""" + num_params = np.prod(expert_shape) + if (len(expected_shape) != 2 or expected_shape[0] != num_experts or + expected_shape[1] != num_params): + raise (ValueError( + 'CondConv variables must have shape [num_experts, num_params]')) + flattened_kernels = [] + for _ in range(num_experts): + kernel = initializer(expert_shape, dtype, partition) + flattened_kernels.append(tf.reshape(kernel, [-1])) + return tf.stack(flattened_kernels) + + return condconv_initializer + + +class CondConv2D(tf.keras.layers.Conv2D): + """2D conditional convolution layer (e.g. spatial convolution over images). + + Attributes: + filters: Integer, the dimensionality of the output space (i.e. the number of + output filters in the convolution). + kernel_size: An integer or tuple/list of 2 integers, specifying the height + and width of the 2D convolution window. Can be a single integer to specify + the same value for all spatial dimensions. + num_experts: The number of expert kernels and biases in the CondConv layer. + strides: An integer or tuple/list of 2 integers, specifying the strides of + the convolution along the height and width. Can be a single integer to + specify the same value for all spatial dimensions. Specifying any stride + value != 1 is incompatible with specifying any `dilation_rate` value != 1. + padding: one of `"valid"` or `"same"` (case-insensitive). + data_format: A string, one of `channels_last` (default) or `channels_first`. + The ordering of the dimensions in the inputs. `channels_last` corresponds + to inputs with shape `(batch, height, width, channels)` while + `channels_first` corresponds to inputs with shape `(batch, channels, + height, width)`. It defaults to the `image_data_format` value found in + your Keras config file at `~/.keras/keras.json`. If you never set it, then + it will be "channels_last". + dilation_rate: an integer or tuple/list of 2 integers, specifying the + dilation rate to use for dilated convolution. Can be a single integer to + specify the same value for all spatial dimensions. Currently, specifying + any `dilation_rate` value != 1 is incompatible with specifying any stride + value != 1. + activation: Activation function to use. If you don't specify anything, no + activation is applied + (ie. "linear" activation: `a(x) = x`). + use_bias: Boolean, whether the layer uses a bias vector. + kernel_initializer: Initializer for the `kernel` weights matrix. + bias_initializer: Initializer for the bias vector. + kernel_regularizer: Regularizer function applied to the `kernel` weights + matrix. + bias_regularizer: Regularizer function applied to the bias vector. + activity_regularizer: Regularizer function applied to the output of the + layer (its "activation").. + kernel_constraint: Constraint function applied to the kernel matrix. + bias_constraint: Constraint function applied to the bias vector. + Input shape: + 4D tensor with shape: `(samples, channels, rows, cols)` if + data_format='channels_first' + or 4D tensor with shape: `(samples, rows, cols, channels)` if + data_format='channels_last'. + Output shape: + 4D tensor with shape: `(samples, filters, new_rows, new_cols)` if + data_format='channels_first' + or 4D tensor with shape: `(samples, new_rows, new_cols, filters)` if + data_format='channels_last'. `rows` and `cols` values might have changed + due to padding. + """ + + def __init__(self, + filters, + kernel_size, + num_experts, + strides=(1, 1), + padding='valid', + data_format=None, + dilation_rate=(1, 1), + activation=None, + use_bias=True, + kernel_initializer='glorot_uniform', + bias_initializer='zeros', + kernel_regularizer=None, + bias_regularizer=None, + activity_regularizer=None, + kernel_constraint=None, + bias_constraint=None, + **kwargs): + super(CondConv2D, self).__init__( + filters=filters, + kernel_size=kernel_size, + strides=strides, + padding=padding, + data_format=data_format, + dilation_rate=dilation_rate, + activation=activation, + use_bias=use_bias, + kernel_initializer=kernel_initializer, + bias_initializer=bias_initializer, + kernel_regularizer=kernel_regularizer, + bias_regularizer=bias_regularizer, + activity_regularizer=activity_regularizer, + kernel_constraint=kernel_constraint, + bias_constraint=bias_constraint, + **kwargs) + if num_experts < 1: + raise ValueError('A CondConv layer must have at least one expert.') + self.num_experts = num_experts + if self.data_format == 'channels_first': + self.converted_data_format = 'NCHW' + else: + self.converted_data_format = 'NHWC' + + def build(self, input_shape): + if len(input_shape) != 4: + raise ValueError( + 'Inputs to `CondConv2D` should have rank 4. ' + 'Received input shape:', str(input_shape)) + input_shape = tf.TensorShape(input_shape) + channel_axis = self._get_channel_axis() + if input_shape.dims[channel_axis].value is None: + raise ValueError('The channel dimension of the inputs ' + 'should be defined. Found `None`.') + input_dim = int(input_shape[channel_axis]) + + self.kernel_shape = self.kernel_size + (input_dim, self.filters) + kernel_num_params = 1 + for kernel_dim in self.kernel_shape: + kernel_num_params *= kernel_dim + condconv_kernel_shape = (self.num_experts, kernel_num_params) + self.condconv_kernel = self.add_weight( + name='condconv_kernel', + shape=condconv_kernel_shape, + initializer=get_condconv_initializer(self.kernel_initializer, + self.num_experts, + self.kernel_shape), + regularizer=self.kernel_regularizer, + constraint=self.kernel_constraint, + trainable=True, + dtype=self.dtype) + + if self.use_bias: + self.bias_shape = (self.filters,) + condconv_bias_shape = (self.num_experts, self.filters) + self.condconv_bias = self.add_weight( + name='condconv_bias', + shape=condconv_bias_shape, + initializer=get_condconv_initializer(self.bias_initializer, + self.num_experts, + self.bias_shape), + regularizer=self.bias_regularizer, + constraint=self.bias_constraint, + trainable=True, + dtype=self.dtype) + else: + self.bias = None + + self.input_spec = tf.layers.InputSpec( + ndim=self.rank + 2, axes={channel_axis: input_dim}) + + self.built = True + + def call(self, inputs, routing_weights): + # Compute example dependent kernels + kernels = tf.matmul(routing_weights, self.condconv_kernel) + batch_size = inputs.shape[0].value + inputs = tf.split(inputs, batch_size, 0) + kernels = tf.split(kernels, batch_size, 0) + # Apply example-dependent convolution to each example in the batch + outputs_list = [] + for input_tensor, kernel in zip(inputs, kernels): + kernel = tf.reshape(kernel, self.kernel_shape) + outputs_list.append( + tf.nn.convolution( + input_tensor, + kernel, + strides=self.strides, + padding=self._get_padding_op(), + dilations=self.dilation_rate, + data_format=self.converted_data_format)) + outputs = tf.concat(outputs_list, 0) + + if self.use_bias: + # Compute example-dependent biases + biases = tf.matmul(routing_weights, self.condconv_bias) + outputs = tf.split(outputs, batch_size, 0) + biases = tf.split(biases, batch_size, 0) + # Add example-dependent bias to each example in the batch + bias_outputs_list = [] + for output, bias in zip(outputs, biases): + bias = tf.squeeze(bias, axis=0) + bias_outputs_list.append( + tf.nn.bias_add(output, bias, + data_format=self.converted_data_format)) + outputs = tf.concat(bias_outputs_list, 0) + + if self.activation is not None: + return self.activation(outputs) + return outputs + + def get_config(self): + config = {'num_experts': self.num_experts} + base_config = super(CondConv2D, self).get_config() + return dict(list(base_config.items()) + list(config.items())) + + def _get_channel_axis(self): + if self.data_format == 'channels_first': + return 1 + else: + return -1 + + def _get_padding_op(self): + if self.padding == 'causal': + op_padding = 'valid' + else: + op_padding = self.padding + if not isinstance(op_padding, (list, tuple)): + op_padding = op_padding.upper() + return op_padding + + +class DepthwiseCondConv2D(tf.keras.layers.DepthwiseConv2D): + """Depthwise separable 2D conditional convolution layer. + + This layer extends the base depthwise 2D convolution layer to compute + example-dependent parameters. A DepthwiseCondConv2D layer has 'num_experts` + kernels and biases. It computes a kernel and bias for each example as a + weighted sum of experts using the input example-dependent routing weights, + then applies the depthwise convolution to each example. + + Attributes: + kernel_size: An integer or tuple/list of 2 integers, specifying the height + and width of the 2D convolution window. Can be a single integer to specify + the same value for all spatial dimensions. + num_experts: The number of expert kernels and biases in the + DepthwiseCondConv2D layer. + strides: An integer or tuple/list of 2 integers, specifying the strides of + the convolution along the height and width. Can be a single integer to + specify the same value for all spatial dimensions. Specifying any stride + value != 1 is incompatible with specifying any `dilation_rate` value != 1. + padding: one of `'valid'` or `'same'` (case-insensitive). + depth_multiplier: The number of depthwise convolution output channels for + each input channel. The total number of depthwise convolution output + channels will be equal to `filters_in * depth_multiplier`. + data_format: A string, one of `channels_last` (default) or `channels_first`. + The ordering of the dimensions in the inputs. `channels_last` corresponds + to inputs with shape `(batch, height, width, channels)` while + `channels_first` corresponds to inputs with shape `(batch, channels, + height, width)`. It defaults to the `image_data_format` value found in + your Keras config file at `~/.keras/keras.json`. If you never set it, then + it will be 'channels_last'. + activation: Activation function to use. If you don't specify anything, no + activation is applied + (ie. 'linear' activation: `a(x) = x`). + use_bias: Boolean, whether the layer uses a bias vector. + depthwise_initializer: Initializer for the depthwise kernel matrix. + bias_initializer: Initializer for the bias vector. + depthwise_regularizer: Regularizer function applied to the depthwise kernel + matrix. + bias_regularizer: Regularizer function applied to the bias vector. + activity_regularizer: Regularizer function applied to the output of the + layer (its 'activation'). + depthwise_constraint: Constraint function applied to the depthwise kernel + matrix. + bias_constraint: Constraint function applied to the bias vector. + Input shape: + 4D tensor with shape: `[batch, channels, rows, cols]` if + data_format='channels_first' + or 4D tensor with shape: `[batch, rows, cols, channels]` if + data_format='channels_last'. + Output shape: + 4D tensor with shape: `[batch, filters, new_rows, new_cols]` if + data_format='channels_first' + or 4D tensor with shape: `[batch, new_rows, new_cols, filters]` if + data_format='channels_last'. `rows` and `cols` values might have changed + due to padding. + """ + + def __init__(self, + kernel_size, + num_experts, + strides=(1, 1), + padding='valid', + depth_multiplier=1, + data_format=None, + activation=None, + use_bias=True, + depthwise_initializer='glorot_uniform', + bias_initializer='zeros', + depthwise_regularizer=None, + bias_regularizer=None, + activity_regularizer=None, + depthwise_constraint=None, + bias_constraint=None, + **kwargs): + super(DepthwiseCondConv2D, self).__init__( + kernel_size=kernel_size, + strides=strides, + padding=padding, + depth_multiplier=depth_multiplier, + data_format=data_format, + activation=activation, + use_bias=use_bias, + depthwise_initializer=depthwise_initializer, + bias_initializer=bias_initializer, + depthwise_regularizer=depthwise_regularizer, + bias_regularizer=bias_regularizer, + activity_regularizer=activity_regularizer, + depthwise_constraint=depthwise_constraint, + bias_constraint=bias_constraint, + **kwargs) + if num_experts < 1: + raise ValueError('A CondConv layer must have at least one expert.') + self.num_experts = num_experts + if self.data_format == 'channels_first': + self.converted_data_format = 'NCHW' + else: + self.converted_data_format = 'NHWC' + + def build(self, input_shape): + if len(input_shape) < 4: + raise ValueError( + 'Inputs to `DepthwiseCondConv2D` should have rank 4. ' + 'Received input shape:', str(input_shape)) + input_shape = tf.TensorShape(input_shape) + if self.data_format == 'channels_first': + channel_axis = 1 + else: + channel_axis = 3 + if input_shape.dims[channel_axis].value is None: + raise ValueError('The channel dimension of the inputs to ' + '`DepthwiseConv2D` ' + 'should be defined. Found `None`.') + input_dim = int(input_shape[channel_axis]) + self.depthwise_kernel_shape = (self.kernel_size[0], self.kernel_size[1], + input_dim, self.depth_multiplier) + + depthwise_kernel_num_params = 1 + for dim in self.depthwise_kernel_shape: + depthwise_kernel_num_params *= dim + depthwise_condconv_kernel_shape = (self.num_experts, + depthwise_kernel_num_params) + + self.depthwise_condconv_kernel = self.add_weight( + shape=depthwise_condconv_kernel_shape, + initializer=get_condconv_initializer(self.depthwise_initializer, + self.num_experts, + self.depthwise_kernel_shape), + name='depthwise_condconv_kernel', + regularizer=self.depthwise_regularizer, + constraint=self.depthwise_constraint, + trainable=True) + + if self.use_bias: + bias_dim = input_dim * self.depth_multiplier + self.bias_shape = (bias_dim,) + condconv_bias_shape = (self.num_experts, bias_dim) + self.condconv_bias = self.add_weight( + name='condconv_bias', + shape=condconv_bias_shape, + initializer=get_condconv_initializer(self.bias_initializer, + self.num_experts, + self.bias_shape), + regularizer=self.bias_regularizer, + constraint=self.bias_constraint, + trainable=True, + dtype=self.dtype) + else: + self.bias = None + # Set input spec. + self.input_spec = tf.layers.InputSpec( + ndim=4, axes={channel_axis: input_dim}) + self.built = True + + def call(self, inputs, routing_weights): + # Compute example dependent depthwise kernels + depthwise_kernels = tf.matmul(routing_weights, + self.depthwise_condconv_kernel) + batch_size = inputs.shape[0].value + inputs = tf.split(inputs, batch_size, 0) + depthwise_kernels = tf.split(depthwise_kernels, batch_size, 0) + # Apply example-dependent depthwise convolution to each example in the batch + outputs_list = [] + for input_tensor, depthwise_kernel in zip(inputs, depthwise_kernels): + depthwise_kernel = tf.reshape(depthwise_kernel, + self.depthwise_kernel_shape) + if self.data_format == 'channels_first': + converted_strides = (1, 1) + self.strides + else: + converted_strides = (1,) + self.strides + (1,) + outputs_list.append( + tf.nn.depthwise_conv2d( + input_tensor, + depthwise_kernel, + strides=converted_strides, + padding=self.padding.upper(), + dilations=self.dilation_rate, + data_format=self.converted_data_format)) + outputs = tf.concat(outputs_list, 0) + + if self.use_bias: + # Compute example-dependent biases + biases = tf.matmul(routing_weights, self.condconv_bias) + outputs = tf.split(outputs, batch_size, 0) + biases = tf.split(biases, batch_size, 0) + # Add example-dependent bias to each example in the batch + bias_outputs_list = [] + for output, bias in zip(outputs, biases): + bias = tf.squeeze(bias, axis=0) + bias_outputs_list.append( + tf.nn.bias_add(output, bias, + data_format=self.converted_data_format)) + outputs = tf.concat(bias_outputs_list, 0) + + if self.activation is not None: + return self.activation(outputs) + + return outputs + + def get_config(self): + config = {'num_experts': self.num_experts} + base_config = super(DepthwiseCondConv2D, self).get_config() + return dict(list(base_config.items()) + list(config.items())) diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/condconv/efficientnet_condconv_builder.py b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/condconv/efficientnet_condconv_builder.py new file mode 100644 index 0000000000000000000000000000000000000000..04562242f4d5de1f8c01e048d84d5b555e8f75c6 --- /dev/null +++ b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/condconv/efficientnet_condconv_builder.py @@ -0,0 +1,200 @@ +# Copyright 2019 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Builder for EfficientNet-CondConv models.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import os +import tensorflow.compat.v1 as tf + +import efficientnet_builder +import efficientnet_model +import utils + +# The input tensor is in the range of [0, 255], we need to scale them to the +# range of [0, 1] +MEAN_RGB = [127.0, 127.0, 127.0] +STDDEV_RGB = [128.0, 128.0, 128.0] + + +def efficientnet_condconv_params(model_name): + """Get efficientnet-condconv params based on model name.""" + params_dict = { + # (width_coefficient, depth_coefficient, resolution, dropout_rate, + # condconv_num_experts) + 'efficientnet-condconv-b0-4e': (1.0, 1.0, 224, 0.25, 4), + 'efficientnet-condconv-b0-8e': (1.0, 1.0, 224, 0.25, 8), + 'efficientnet-condconv-b0-8e-depth': (1.0, 1.1, 224, 0.25, 8) + } + return params_dict[model_name] + + +def efficientnet_condconv(width_coefficient=None, + depth_coefficient=None, + dropout_rate=0.2, + survival_prob=0.8, + condconv_num_experts=None): + """Creates an efficientnet-condconv model.""" + blocks_args = [ + 'r1_k3_s11_e1_i32_o16_se0.25', + 'r2_k3_s22_e6_i16_o24_se0.25', + 'r2_k5_s22_e6_i24_o40_se0.25', + 'r3_k3_s22_e6_i40_o80_se0.25', + 'r3_k5_s11_e6_i80_o112_se0.25_cc', + 'r4_k5_s22_e6_i112_o192_se0.25_cc', + 'r1_k3_s11_e6_i192_o320_se0.25_cc', + ] + global_params = efficientnet_model.GlobalParams( + batch_norm_momentum=0.99, + batch_norm_epsilon=1e-3, + dropout_rate=dropout_rate, + survival_prob=survival_prob, + data_format='channels_last', + num_classes=1000, + width_coefficient=width_coefficient, + depth_coefficient=depth_coefficient, + depth_divisor=8, + min_depth=None, + relu_fn=tf.nn.swish, + # The default is TPU-specific batch norm. + # The alternative is tf.layers.BatchNormalization. + batch_norm=utils.TpuBatchNormalization, # TPU-specific requirement. + use_se=True, + condconv_num_experts=condconv_num_experts) + decoder = efficientnet_builder.BlockDecoder() + return decoder.decode(blocks_args), global_params + + +def get_model_params(model_name, override_params): + """Get the block args and global params for a given model.""" + if model_name.startswith('efficientnet-condconv'): + (width_coefficient, depth_coefficient, _, dropout_rate, + condconv_num_experts) = ( + efficientnet_condconv_params(model_name)) + blocks_args, global_params = efficientnet_condconv( + width_coefficient=width_coefficient, + depth_coefficient=depth_coefficient, + dropout_rate=dropout_rate, + condconv_num_experts=condconv_num_experts) + else: + raise NotImplementedError( + 'model name is not pre-defined: %s' % model_name) + + if override_params: + # ValueError will be raised here if override_params has fields not included + # in global_params. + global_params = global_params._replace(**override_params) + + tf.logging.info('global_params= %s', global_params) + tf.logging.info('blocks_args= %s', blocks_args) + return blocks_args, global_params + + +def build_model(images, + model_name, + training, + override_params=None, + model_dir=None, + fine_tuning=False): + """A helper functiion to creates a model and returns predicted logits. + + Args: + images: input images tensor. + model_name: string, the predefined model name. + training: boolean, whether the model is constructed for training. + override_params: A dictionary of params for overriding. Fields must exist in + efficientnet_model.GlobalParams. + model_dir: string, optional model dir for saving configs. + fine_tuning: boolean, whether the model is used for finetuning. + + Returns: + logits: the logits tensor of classes. + endpoints: the endpoints for each layer. + + Raises: + When model_name specified an undefined model, raises NotImplementedError. + When override_params has invalid fields, raises ValueError. + """ + assert isinstance(images, tf.Tensor) + if not training or fine_tuning: + if not override_params: + override_params = {} + override_params['batch_norm'] = utils.BatchNormalization + blocks_args, global_params = get_model_params(model_name, override_params) + if not training or fine_tuning: + global_params = global_params._replace( + batch_norm=utils.BatchNormalization) + + if model_dir: + param_file = os.path.join(model_dir, 'model_params.txt') + if not tf.gfile.Exists(param_file): + if not tf.gfile.Exists(model_dir): + tf.gfile.MakeDirs(model_dir) + with tf.gfile.GFile(param_file, 'w') as f: + tf.logging.info('writing to %s' % param_file) + f.write('model_name= %s\n\n' % model_name) + f.write('global_params= %s\n\n' % str(global_params)) + f.write('blocks_args= %s\n\n' % str(blocks_args)) + + with tf.variable_scope(model_name): + model = efficientnet_model.Model(blocks_args, global_params) + logits = model(images, training=training) + + logits = tf.identity(logits, 'logits') + return logits, model.endpoints + + +def build_model_base(images, model_name, training, override_params=None): + """A helper functiion to create a base model and return global_pool. + + Args: + images: input images tensor. + model_name: string, the model name of a pre-defined MnasNet. + training: boolean, whether the model is constructed for training. + override_params: A dictionary of params for overriding. Fields must exist in + mnasnet_model.GlobalParams. + + Returns: + features: global pool features. + endpoints: the endpoints for each layer. + + Raises: + When model_name specified an undefined model, raises NotImplementedError. + When override_params has invalid fields, raises ValueError. + """ + assert isinstance(images, tf.Tensor) + blocks_args, global_params = get_model_params(model_name, override_params) + + with tf.variable_scope(model_name): + model = efficientnet_model.Model(blocks_args, global_params) + features = model(images, training=training, features_only=True) + + features = tf.identity(features, 'global_pool') + return features, model.endpoints diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/edgetpu/__init__.py b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/edgetpu/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..5804427ded961057b3cba09485c01fa205f84c1f --- /dev/null +++ b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/edgetpu/__init__.py @@ -0,0 +1,28 @@ +# Copyright 2019 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""The initial file of edgetpu.""" \ No newline at end of file diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/edgetpu/efficientnet_edgetpu_builder.py b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/edgetpu/efficientnet_edgetpu_builder.py new file mode 100644 index 0000000000000000000000000000000000000000..1d98e7aa42661a800dc22ea24aed1abd4d92362b --- /dev/null +++ b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/edgetpu/efficientnet_edgetpu_builder.py @@ -0,0 +1,195 @@ +# Copyright 2019 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Builder for EfficientNet-EdgeTPU models.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import os +from absl import logging +import tensorflow.compat.v1 as tf + +import efficientnet_builder +import efficientnet_model +import utils + +# The input tensor is in the range of [0, 255], we need to scale them to the +# range of [0, 1] +MEAN_RGB = [127.0, 127.0, 127.0] +STDDEV_RGB = [128.0, 128.0, 128.0] + + +def efficientnet_edgetpu_params(model_name): + """Get efficientnet-edgetpu params based on model name.""" + params_dict = { + # (width_coefficient, depth_coefficient, resolution, dropout_rate) + 'efficientnet-edgetpu-S': (1.0, 1.0, 224, 0.2), + 'efficientnet-edgetpu-M': (1.0, 1.1, 240, 0.2), + 'efficientnet-edgetpu-L': (1.2, 1.4, 300, 0.3), + } + return params_dict[model_name] + + +def efficientnet_edgetpu(width_coefficient=None, + depth_coefficient=None, + dropout_rate=0.2, + survival_prob=0.8): + """Creates an efficientnet-edgetpu model.""" + blocks_args = [ + 'r1_k3_s11_e4_i24_o24_c1_noskip', + 'r2_k3_s22_e8_i24_o32_c1', + 'r4_k3_s22_e8_i32_o48_c1', + 'r5_k5_s22_e8_i48_o96', + 'r4_k5_s11_e8_i96_o144', + 'r2_k5_s22_e8_i144_o192', + ] + global_params = efficientnet_model.GlobalParams( + batch_norm_momentum=0.99, + batch_norm_epsilon=1e-3, + dropout_rate=dropout_rate, + survival_prob=survival_prob, + data_format='channels_last', + num_classes=1001, + width_coefficient=width_coefficient, + depth_coefficient=depth_coefficient, + depth_divisor=8, + min_depth=None, + relu_fn=tf.nn.relu, + # The default is TPU-specific batch norm. + # The alternative is tf.layers.BatchNormalization. + batch_norm=utils.TpuBatchNormalization, # TPU-specific requirement. + local_pooling=True, # for EdgeTPU. + use_se=False) + decoder = efficientnet_builder.BlockDecoder() + return decoder.decode(blocks_args), global_params + + +def get_model_params(model_name, override_params): + """Get the block args and global params for a given model.""" + if model_name.startswith('efficientnet-edgetpu'): + width_coefficient, depth_coefficient, _, dropout_rate = ( + efficientnet_edgetpu_params(model_name)) + blocks_args, global_params = efficientnet_edgetpu(width_coefficient, + depth_coefficient, + dropout_rate) + else: + raise NotImplementedError( + 'model name is not pre-defined: %s' % model_name) + + if override_params: + # ValueError will be raised here if override_params has fields not included + # in global_params. + global_params = global_params._replace(**override_params) + + logging.info('global_params= %s', global_params) + logging.info('blocks_args= %s', blocks_args) + return blocks_args, global_params + + +def build_model(images, + model_name, + training, + override_params=None, + model_dir=None, + fine_tuning=False): + """A helper functiion to creates a model and returns predicted logits. + + Args: + images: input images tensor. + model_name: string, the predefined model name. + training: boolean, whether the model is constructed for training. + override_params: A dictionary of params for overriding. Fields must exist in + efficientnet_model.GlobalParams. + model_dir: string, optional model dir for saving configs. + fine_tuning: boolean, whether the model is used for finetuning. + + Returns: + logits: the logits tensor of classes. + endpoints: the endpoints for each layer. + + Raises: + When model_name specified an undefined model, raises NotImplementedError. + When override_params has invalid fields, raises ValueError. + """ + assert isinstance(images, tf.Tensor) + if not training or fine_tuning: + if not override_params: + override_params = {} + override_params['batch_norm'] = utils.BatchNormalization + blocks_args, global_params = get_model_params(model_name, override_params) + if not training or fine_tuning: + global_params = global_params._replace( + batch_norm=utils.BatchNormalization) + + if model_dir: + param_file = os.path.join(model_dir, 'model_params.txt') + if not tf.gfile.Exists(param_file): + if not tf.gfile.Exists(model_dir): + tf.gfile.MakeDirs(model_dir) + with tf.gfile.GFile(param_file, 'w') as f: + logging.info('writing to %s', param_file) + f.write('model_name= %s\n\n' % model_name) + f.write('global_params= %s\n\n' % str(global_params)) + f.write('blocks_args= %s\n\n' % str(blocks_args)) + + with tf.variable_scope(model_name): + model = efficientnet_model.Model(blocks_args, global_params) + logits = model(images, training=training) + + logits = tf.identity(logits, 'logits') + return logits, model.endpoints + + +def build_model_base(images, model_name, training, override_params=None): + """A helper functiion to create a base model and return global_pool. + + Args: + images: input images tensor. + model_name: string, the model name of a pre-defined MnasNet. + training: boolean, whether the model is constructed for training. + override_params: A dictionary of params for overriding. Fields must exist in + mnasnet_model.GlobalParams. + + Returns: + features: global pool features. + endpoints: the endpoints for each layer. + + Raises: + When model_name specified an undefined model, raises NotImplementedError. + When override_params has invalid fields, raises ValueError. + """ + assert isinstance(images, tf.Tensor) + blocks_args, global_params = get_model_params(model_name, override_params) + + with tf.variable_scope(model_name): + model = efficientnet_model.Model(blocks_args, global_params) + features = model(images, training=training, features_only=True) + + features = tf.identity(features, 'global_pool') + return features, model.endpoints diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/efficientnet_builder.py b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/efficientnet_builder.py new file mode 100644 index 0000000000000000000000000000000000000000..5d45ce676c48d67fa163e2500aeaeaf5861300bb --- /dev/null +++ b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/efficientnet_builder.py @@ -0,0 +1,348 @@ +# Copyright 2019 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Model Builder for EfficientNet.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import functools +import os +import re +from absl import logging +import numpy as np +import six +import tensorflow.compat.v1 as tf + +import efficientnet_model +import utils +MEAN_RGB = [0.485 * 255, 0.456 * 255, 0.406 * 255] +STDDEV_RGB = [0.229 * 255, 0.224 * 255, 0.225 * 255] + + +def efficientnet_params(model_name): + """Get efficientnet params based on model name.""" + params_dict = { + # (width_coefficient, depth_coefficient, resolution, dropout_rate) + 'efficientnet-b0': (1.0, 1.0, 224, 0.2), + 'efficientnet-b1': (1.0, 1.1, 240, 0.2), + 'efficientnet-b2': (1.1, 1.2, 260, 0.3), + 'efficientnet-b3': (1.2, 1.4, 300, 0.3), + 'efficientnet-b4': (1.4, 1.8, 380, 0.4), + 'efficientnet-b5': (1.6, 2.2, 456, 0.4), + 'efficientnet-b6': (1.8, 2.6, 528, 0.5), + 'efficientnet-b7': (2.0, 3.1, 600, 0.5), + 'efficientnet-b8': (2.2, 3.6, 672, 0.5), + 'efficientnet-l2': (4.3, 5.3, 800, 0.5), + } + return params_dict[model_name] + + +class BlockDecoder(object): + """Block Decoder for readability.""" + + def _decode_block_string(self, block_string): + """Gets a block through a string notation of arguments.""" + if six.PY2: + assert isinstance(block_string, (str, unicode)) + else: + assert isinstance(block_string, str) + ops = block_string.split('_') + options = {} + for op in ops: + splits = re.split(r'(\d.*)', op) + if len(splits) >= 2: + key, value = splits[:2] + options[key] = value + + if 's' not in options or len(options['s']) != 2: + raise ValueError('Strides options should be a pair of integers.') + + return efficientnet_model.BlockArgs( + kernel_size=int(options['k']), + num_repeat=int(options['r']), + input_filters=int(options['i']), + output_filters=int(options['o']), + expand_ratio=int(options['e']), + id_skip=('noskip' not in block_string), + se_ratio=float(options['se']) if 'se' in options else None, + strides=[int(options['s'][0]), + int(options['s'][1])], + conv_type=int(options['c']) if 'c' in options else 0, + fused_conv=int(options['f']) if 'f' in options else 0, + space2depth=int(options['d']) if 'd' in options else 0, + condconv=('cc' in block_string), + activation_fn=(tf.nn.relu if int(options['a']) == 0 + else tf.nn.swish) if 'a' in options else None) + + def _encode_block_string(self, block): + """Encodes a block to a string.""" + args = [ + 'r%d' % block.num_repeat, + 'k%d' % block.kernel_size, + 's%d%d' % (block.strides[0], block.strides[1]), + 'e%s' % block.expand_ratio, + 'i%d' % block.input_filters, + 'o%d' % block.output_filters, + 'c%d' % block.conv_type, + 'f%d' % block.fused_conv, + 'd%d' % block.space2depth, + ] + if block.se_ratio > 0 and block.se_ratio <= 1: + args.append('se%s' % block.se_ratio) + if block.id_skip is False: # pylint: disable=g-bool-id-comparison + args.append('noskip') + if block.condconv: + args.append('cc') + return '_'.join(args) + + def decode(self, string_list): + """Decodes a list of string notations to specify blocks inside the network. + + Args: + string_list: a list of strings, each string is a notation of block. + + Returns: + A list of namedtuples to represent blocks arguments. + """ + assert isinstance(string_list, list) + blocks_args = [] + for block_string in string_list: + blocks_args.append(self._decode_block_string(block_string)) + return blocks_args + + def encode(self, blocks_args): + """Encodes a list of Blocks to a list of strings. + + Args: + blocks_args: A list of namedtuples to represent blocks arguments. + Returns: + a list of strings, each string is a notation of block. + """ + block_strings = [] + for block in blocks_args: + block_strings.append(self._encode_block_string(block)) + return block_strings + + +def swish(features, use_native=True, use_hard=False): + """Computes the Swish activation function. + + We provide three alternnatives: + - Native tf.nn.swish, use less memory during training than composable swish. + - Quantization friendly hard swish. + - A composable swish, equivalant to tf.nn.swish, but more general for + finetuning and TF-Hub. + + Args: + features: A `Tensor` representing preactivation values. + use_native: Whether to use the native swish from tf.nn that uses a custom + gradient to reduce memory usage, or to use customized swish that uses + default TensorFlow gradient computation. + use_hard: Whether to use quantization-friendly hard swish. + + Returns: + The activation value. + """ + if use_native and use_hard: + raise ValueError('Cannot specify both use_native and use_hard.') + + if use_native: + return tf.nn.swish(features) + + if use_hard: + return features * tf.nn.relu6(features + np.float32(3)) * (1. / 6.) + + features = tf.convert_to_tensor(features, name='features') + return features * tf.nn.sigmoid(features) + + +_DEFAULT_BLOCKS_ARGS = [ + 'r1_k3_s11_e1_i32_o16_se0.25', 'r2_k3_s22_e6_i16_o24_se0.25', + 'r2_k5_s22_e6_i24_o40_se0.25', 'r3_k3_s22_e6_i40_o80_se0.25', + 'r3_k5_s11_e6_i80_o112_se0.25', 'r4_k5_s22_e6_i112_o192_se0.25', + 'r1_k3_s11_e6_i192_o320_se0.25', +] + + +def efficientnet(width_coefficient=None, + depth_coefficient=None, + dropout_rate=0.2, + survival_prob=0.8): + """Creates a efficientnet model.""" + global_params = efficientnet_model.GlobalParams( + blocks_args=_DEFAULT_BLOCKS_ARGS, + batch_norm_momentum=0.99, + batch_norm_epsilon=1e-3, + dropout_rate=dropout_rate, + survival_prob=survival_prob, + data_format='channels_last', + num_classes=1000, + width_coefficient=width_coefficient, + depth_coefficient=depth_coefficient, + depth_divisor=8, + min_depth=None, + relu_fn=tf.nn.swish, + # The default is TPU-specific batch norm. + # The alternative is tf.layers.BatchNormalization. + batch_norm=utils.train_batch_norm, # TPU-specific requirement. + use_se=True, + clip_projection_output=False) + return global_params + + +def get_model_params(model_name, override_params): + """Get the block args and global params for a given model.""" + if model_name.startswith('efficientnet'): + width_coefficient, depth_coefficient, _, dropout_rate = ( + efficientnet_params(model_name)) + global_params = efficientnet( + width_coefficient, depth_coefficient, dropout_rate) + else: + raise NotImplementedError( + 'model name is not pre-defined: %s' % model_name) + + if override_params: + # ValueError will be raised here if override_params has fields not included + # in global_params. + global_params = global_params._replace(**override_params) + + decoder = BlockDecoder() + blocks_args = decoder.decode(global_params.blocks_args) + + logging.info('global_params= %s', global_params) + return blocks_args, global_params + + +def build_model(images, + model_name, + training, + override_params=None, + model_dir=None, + fine_tuning=False, + features_only=False, + pooled_features_only=False): + """A helper function to create a model and return predicted logits. + + Args: + images: input images tensor. + model_name: string, the predefined model name. + training: boolean, whether the model is constructed for training. + override_params: A dictionary of params for overriding. Fields must exist in + efficientnet_model.GlobalParams. + model_dir: string, optional model dir for saving configs. + fine_tuning: boolean, whether the model is used for finetuning. + features_only: build the base feature network only (excluding final + 1x1 conv layer, global pooling, dropout and fc head). + pooled_features_only: build the base network for features extraction (after + 1x1 conv layer and global pooling, but before dropout and fc head). + + Returns: + logits: the logits tensor of classes. + endpoints: the endpoints for each layer. + + Raises: + When model_name specified an undefined model, raises NotImplementedError. + When override_params has invalid fields, raises ValueError. + """ + assert isinstance(images, tf.Tensor) + assert not (features_only and pooled_features_only) + + # For backward compatibility. + if override_params and override_params.get('drop_connect_rate', None): + override_params['survival_prob'] = 1 - \ + override_params['drop_connect_rate'] + + if not training or fine_tuning: + if not override_params: + override_params = {} + override_params['batch_norm'] = utils.eval_batch_norm + if fine_tuning: + override_params['relu_fn'] = functools.partial( + swish, use_native=False) + blocks_args, global_params = get_model_params(model_name, override_params) + + if model_dir: + param_file = os.path.join(model_dir, 'model_params.txt') + if not tf.gfile.Exists(param_file): + if not tf.gfile.Exists(model_dir): + tf.gfile.MakeDirs(model_dir) + with tf.gfile.GFile(param_file, 'w') as f: + logging.info('writing to %s', param_file) + f.write('model_name= %s\n\n' % model_name) + f.write('global_params= %s\n\n' % str(global_params)) + f.write('blocks_args= %s\n\n' % str(blocks_args)) + + with tf.variable_scope(model_name): + model = efficientnet_model.Model(blocks_args, global_params) + outputs = model( + images, + training=training, + features_only=features_only, + pooled_features_only=pooled_features_only) + if features_only: + outputs = tf.identity(outputs, 'features') + elif pooled_features_only: + outputs = tf.identity(outputs, 'pooled_features') + else: + outputs = tf.identity(outputs, 'logits') + return outputs, model.endpoints + + +def build_model_base(images, model_name, training, override_params=None): + """Create a base feature network and return the features before pooling. + + Args: + images: input images tensor. + model_name: string, the predefined model name. + training: boolean, whether the model is constructed for training. + override_params: A dictionary of params for overriding. Fields must exist in + efficientnet_model.GlobalParams. + + Returns: + features: base features before pooling. + endpoints: the endpoints for each layer. + + Raises: + When model_name specified an undefined model, raises NotImplementedError. + When override_params has invalid fields, raises ValueError. + """ + assert isinstance(images, tf.Tensor) + # For backward compatibility. + if override_params and override_params.get('drop_connect_rate', None): + override_params['survival_prob'] = 1 - \ + override_params['drop_connect_rate'] + + blocks_args, global_params = get_model_params(model_name, override_params) + + with tf.variable_scope(model_name): + model = efficientnet_model.Model(blocks_args, global_params) + features = model(images, training=training, features_only=True) + + features = tf.identity(features, 'features') + return features, model.endpoints diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/efficientnet_model.py b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/efficientnet_model.py new file mode 100644 index 0000000000000000000000000000000000000000..03c248ad05718a60cdf92be9adae2f5db3e68b95 --- /dev/null +++ b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/efficientnet_model.py @@ -0,0 +1,736 @@ +# Copyright 2019 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Contains definitions for EfficientNet model. + +[1] Mingxing Tan, Quoc V. Le + EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks. + ICML'19, https://arxiv.org/abs/1905.11946 +""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import collections +import functools +import math + +from absl import logging +import numpy as np +import six +from six.moves import xrange +import tensorflow.compat.v1 as tf + +import utils +from condconv import condconv_layers + +GlobalParams = collections.namedtuple('GlobalParams', [ + 'batch_norm_momentum', 'batch_norm_epsilon', 'dropout_rate', 'data_format', + 'num_classes', 'width_coefficient', 'depth_coefficient', 'depth_divisor', + 'min_depth', 'survival_prob', 'relu_fn', 'batch_norm', 'use_se', + 'se_coefficient', 'local_pooling', 'condconv_num_experts', + 'clip_projection_output', 'blocks_args', 'fix_head_stem', +]) +# Note: the default value of None is not necessarily valid. It is valid to leave +# width_coefficient, depth_coefficient at None, which is treated as 1.0 (and +# which also allows depth_divisor and min_depth to be left at None). +GlobalParams.__new__.__defaults__ = (None,) * len(GlobalParams._fields) + +BlockArgs = collections.namedtuple('BlockArgs', [ + 'kernel_size', 'num_repeat', 'input_filters', 'output_filters', + 'expand_ratio', 'id_skip', 'strides', 'se_ratio', 'conv_type', 'fused_conv', + 'space2depth', 'condconv', 'activation_fn' +]) +# defaults will be a public argument for namedtuple in Python 3.7 +# https://docs.python.org/3/library/collections.html#collections.namedtuple +BlockArgs.__new__.__defaults__ = (None,) * len(BlockArgs._fields) + + +def conv_kernel_initializer(shape, dtype=None, partition_info=None): + """Initialization for convolutional kernels. + + The main difference with tf.variance_scaling_initializer is that + tf.variance_scaling_initializer uses a truncated normal with an uncorrected + standard deviation, whereas here we use a normal distribution. Similarly, + tf.initializers.variance_scaling uses a truncated normal with + a corrected standard deviation. + + Args: + shape: shape of variable + dtype: dtype of variable + partition_info: unused + + Returns: + an initialization for the variable + """ + del partition_info + kernel_height, kernel_width, _, out_filters = shape + fan_out = int(kernel_height * kernel_width * out_filters) + return tf.random_normal( + shape, mean=0.0, stddev=np.sqrt(2.0 / fan_out), dtype=dtype) + + +def dense_kernel_initializer(shape, dtype=None, partition_info=None): + """Initialization for dense kernels. + + This initialization is equal to + tf.variance_scaling_initializer(scale=1.0/3.0, mode='fan_out', + distribution='uniform'). + It is written out explicitly here for clarity. + + Args: + shape: shape of variable + dtype: dtype of variable + partition_info: unused + + Returns: + an initialization for the variable + """ + del partition_info + init_range = 1.0 / np.sqrt(shape[1]) + return tf.random_uniform(shape, -init_range, init_range, dtype=dtype) + + +def round_filters(filters, global_params, skip=False): + """Round number of filters based on depth multiplier.""" + orig_f = filters + multiplier = global_params.width_coefficient + divisor = global_params.depth_divisor + min_depth = global_params.min_depth + if skip or not multiplier: + return filters + + filters *= multiplier + min_depth = min_depth or divisor + new_filters = max(min_depth, int( + filters + divisor / 2) // divisor * divisor) + # Make sure that round down does not go down by more than 10%. + if new_filters < 0.9 * filters: + new_filters += divisor + logging.info('round_filter input=%s output=%s', orig_f, new_filters) + return int(new_filters) + + +def round_repeats(repeats, global_params, skip=False): + """Round number of filters based on depth multiplier.""" + multiplier = global_params.depth_coefficient + if skip or not multiplier: + return repeats + return int(math.ceil(multiplier * repeats)) + + +class MBConvBlock(tf.keras.layers.Layer): + """A class of MBConv: Mobile Inverted Residual Bottleneck. + + Attributes: + endpoints: dict. A list of internal tensors. + """ + + def __init__(self, block_args, global_params): + """Initializes a MBConv block. + + Args: + block_args: BlockArgs, arguments to create a Block. + global_params: GlobalParams, a set of global parameters. + """ + super(MBConvBlock, self).__init__() + self._block_args = block_args + self._local_pooling = global_params.local_pooling + self._batch_norm_momentum = global_params.batch_norm_momentum + self._batch_norm_epsilon = global_params.batch_norm_epsilon + self._batch_norm = global_params.batch_norm + self._condconv_num_experts = global_params.condconv_num_experts + self._data_format = global_params.data_format + self._se_coefficient = global_params.se_coefficient + if self._data_format == 'channels_first': + self._channel_axis = 1 + self._spatial_dims = [2, 3] + else: + self._channel_axis = -1 + self._spatial_dims = [1, 2] + + self._relu_fn = (self._block_args.activation_fn + or global_params.relu_fn or tf.nn.swish) + self._has_se = ( + global_params.use_se and self._block_args.se_ratio is not None and + 0 < self._block_args.se_ratio <= 1) + + self._clip_projection_output = global_params.clip_projection_output + + self.endpoints = None + + self.conv_cls = utils.Conv2D + self.depthwise_conv_cls = utils.DepthwiseConv2D + if self._block_args.condconv: + self.conv_cls = functools.partial( + condconv_layers.CondConv2D, num_experts=self._condconv_num_experts) + self.depthwise_conv_cls = functools.partial( + condconv_layers.DepthwiseCondConv2D, + num_experts=self._condconv_num_experts) + + # Builds the block accordings to arguments. + self._build() + + def block_args(self): + """Call the function of block_args.""" + return self._block_args + + def _build(self): + """Builds block according to the arguments.""" + if self._block_args.space2depth == 1: + self._space2depth = tf.layers.Conv2D( + self._block_args.input_filters, + kernel_size=[2, 2], + strides=[2, 2], + kernel_initializer=conv_kernel_initializer, + padding='same', + data_format=self._data_format, + use_bias=False) + self._bnsp = self._batch_norm( + axis=self._channel_axis, + momentum=self._batch_norm_momentum, + epsilon=self._batch_norm_epsilon) + + if self._block_args.condconv: + # Add the example-dependent routing function + self._avg_pooling = tf.keras.layers.GlobalAveragePooling2D( + data_format=self._data_format) + self._routing_fn = tf.layers.Dense( + self._condconv_num_experts, activation=tf.nn.sigmoid) + + filters = self._block_args.input_filters * self._block_args.expand_ratio + kernel_size = self._block_args.kernel_size + + # Fused expansion phase. Called if using fused convolutions. + self._fused_conv = self.conv_cls( + filters=filters, + kernel_size=[kernel_size, kernel_size], + strides=self._block_args.strides, + kernel_initializer=conv_kernel_initializer, + padding='same', + data_format=self._data_format, + use_bias=False) + + # Expansion phase. Called if not using fused convolutions and expansion + # phase is necessary. + self._expand_conv = self.conv_cls( + filters=filters, + kernel_size=[1, 1], + strides=[1, 1], + kernel_initializer=conv_kernel_initializer, + padding='same', + data_format=self._data_format, + use_bias=False) + self._bn0 = self._batch_norm( + axis=self._channel_axis, + momentum=self._batch_norm_momentum, + epsilon=self._batch_norm_epsilon) + + # Depth-wise convolution phase. Called if not using fused convolutions. + self._depthwise_conv = self.depthwise_conv_cls( + kernel_size=[kernel_size, kernel_size], + strides=self._block_args.strides, + depthwise_initializer=conv_kernel_initializer, + padding='same', + data_format=self._data_format, + use_bias=False) + + self._bn1 = self._batch_norm( + axis=self._channel_axis, + momentum=self._batch_norm_momentum, + epsilon=self._batch_norm_epsilon) + + if self._has_se: + num_reduced_filters = int(self._block_args.input_filters * ( + self._block_args.se_ratio * (self._se_coefficient + if self._se_coefficient else 1))) + # account for space2depth transformation in SE filter depth, since + # the SE compression ratio is w.r.t. the original filter depth before + # space2depth is applied. + num_reduced_filters = (num_reduced_filters // 4 + if self._block_args.space2depth == 1 + else num_reduced_filters) + num_reduced_filters = max(1, num_reduced_filters) + # Squeeze and Excitation layer. + self._se_reduce = utils.Conv2D( + num_reduced_filters, + kernel_size=[1, 1], + strides=[1, 1], + kernel_initializer=conv_kernel_initializer, + padding='same', + data_format=self._data_format, + use_bias=True) + self._se_expand = utils.Conv2D( + filters, + kernel_size=[1, 1], + strides=[1, 1], + kernel_initializer=conv_kernel_initializer, + padding='same', + data_format=self._data_format, + use_bias=True) + + # Output phase. + filters = self._block_args.output_filters + self._project_conv = self.conv_cls( + filters=filters, + kernel_size=[1, 1], + strides=[1, 1], + kernel_initializer=conv_kernel_initializer, + padding='same', + data_format=self._data_format, + use_bias=False) + self._bn2 = self._batch_norm( + axis=self._channel_axis, + momentum=self._batch_norm_momentum, + epsilon=self._batch_norm_epsilon) + + def _call_se(self, input_tensor): + """Call Squeeze and Excitation layer. + + Args: + input_tensor: Tensor, a single input tensor for Squeeze/Excitation layer. + + Returns: + A output tensor, which should have the same shape as input. + """ + if self._local_pooling: + shape = input_tensor.get_shape().as_list() + kernel_size = [ + 1, shape[self._spatial_dims[0]], shape[self._spatial_dims[1]], 1] + se_tensor = tf.nn.avg_pool( + input_tensor, + ksize=kernel_size, + strides=[1, 1, 1, 1], + padding='VALID', + data_format=self._data_format) + else: + se_tensor = tf.reduce_mean( + input_tensor, self._spatial_dims, keepdims=True) + se_tensor = self._se_expand(self._relu_fn(self._se_reduce(se_tensor))) + logging.info('Built SE %s : %s', self.name, se_tensor.shape) + return tf.sigmoid(se_tensor) * input_tensor + + def call(self, inputs, training=True, survival_prob=None): + """Implementation of call(). + + Args: + inputs: the inputs tensor. + training: boolean, whether the model is constructed for training. + survival_prob: float, between 0 to 1, drop connect rate. + + Returns: + A output tensor. + """ + logging.info('Block %s input shape: %s', self.name, inputs.shape) + x = inputs + + fused_conv_fn = self._fused_conv + expand_conv_fn = self._expand_conv + depthwise_conv_fn = self._depthwise_conv + project_conv_fn = self._project_conv + + if self._block_args.condconv: + pooled_inputs = self._avg_pooling(inputs) + routing_weights = self._routing_fn(pooled_inputs) + # Capture routing weights as additional input to CondConv layers + fused_conv_fn = functools.partial( + self._fused_conv, routing_weights=routing_weights) + expand_conv_fn = functools.partial( + self._expand_conv, routing_weights=routing_weights) + depthwise_conv_fn = functools.partial( + self._depthwise_conv, routing_weights=routing_weights) + project_conv_fn = functools.partial( + self._project_conv, routing_weights=routing_weights) + + # creates conv 2x2 kernel + if self._block_args.space2depth == 1: + with tf.variable_scope('space2depth'): + x = self._relu_fn( + self._bnsp(self._space2depth(x), training=training)) + logging.info('Block start with space2depth shape: %s', x.shape) + + if self._block_args.fused_conv: + # If use fused mbconv, skip expansion and use regular conv. + x = self._relu_fn(self._bn1(fused_conv_fn(x), training=training)) + logging.info('Conv2D shape: %s', x.shape) + else: + # Otherwise, first apply expansion and then apply depthwise conv. + if self._block_args.expand_ratio != 1: + x = self._relu_fn( + self._bn0(expand_conv_fn(x), training=training)) + logging.info('Expand shape: %s', x.shape) + + x = self._relu_fn( + self._bn1(depthwise_conv_fn(x), training=training)) + logging.info('DWConv shape: %s', x.shape) + + if self._has_se: + with tf.variable_scope('se'): + x = self._call_se(x) + + self.endpoints = {'expansion_output': x} + + x = self._bn2(project_conv_fn(x), training=training) + # Add identity so that quantization-aware training can insert quantization + # ops correctly. + x = tf.identity(x) + if self._clip_projection_output: + x = tf.clip_by_value(x, -6, 6) + if self._block_args.id_skip: + if all( + s == 1 for s in self._block_args.strides + ) and inputs.get_shape().as_list()[-1] == x.get_shape().as_list()[-1]: + # Apply only if skip connection presents. + if survival_prob: + x = utils.drop_connect(x, training, survival_prob) + x = tf.add(x, inputs) + logging.info('Project shape: %s', x.shape) + return x + + +class MBConvBlockWithoutDepthwise(MBConvBlock): + """MBConv-like block without depthwise convolution and squeeze-and-excite.""" + + def _build(self): + """Builds block according to the arguments.""" + filters = self._block_args.input_filters * self._block_args.expand_ratio + if self._block_args.expand_ratio != 1: + # Expansion phase: + self._expand_conv = tf.layers.Conv2D( + filters, + kernel_size=[3, 3], + strides=self._block_args.strides, + kernel_initializer=conv_kernel_initializer, + padding='same', + use_bias=False) + self._bn0 = self._batch_norm( + axis=self._channel_axis, + momentum=self._batch_norm_momentum, + epsilon=self._batch_norm_epsilon) + + # Output phase: + filters = self._block_args.output_filters + self._project_conv = tf.layers.Conv2D( + filters, + kernel_size=[1, 1], + strides=[1, 1], + kernel_initializer=conv_kernel_initializer, + padding='same', + use_bias=False) + self._bn1 = self._batch_norm( + axis=self._channel_axis, + momentum=self._batch_norm_momentum, + epsilon=self._batch_norm_epsilon) + + def call(self, inputs, training=True, survival_prob=None): + """Implementation of call(). + + Args: + inputs: the inputs tensor. + training: boolean, whether the model is constructed for training. + survival_prob: float, between 0 to 1, drop connect rate. + + Returns: + A output tensor. + """ + logging.info('Block input shape: %s', inputs.shape) + if self._block_args.expand_ratio != 1: + x = self._relu_fn( + self._bn0(self._expand_conv(inputs), training=training)) + else: + x = inputs + logging.info('Expand shape: %s', x.shape) + + self.endpoints = {'expansion_output': x} + + x = self._bn1(self._project_conv(x), training=training) + # Add identity so that quantization-aware training can insert quantization + # ops correctly. + x = tf.identity(x) + if self._clip_projection_output: + x = tf.clip_by_value(x, -6, 6) + + if self._block_args.id_skip: + if all( + s == 1 for s in self._block_args.strides + ) and self._block_args.input_filters == self._block_args.output_filters: + # Apply only if skip connection presents. + if survival_prob: + x = utils.drop_connect(x, training, survival_prob) + x = tf.add(x, inputs) + logging.info('Project shape: %s', x.shape) + return x + + +class Model(tf.keras.Model): + """A class implements tf.keras.Model for MNAS-like model. + + Reference: https://arxiv.org/abs/1807.11626 + """ + + def __init__(self, blocks_args=None, global_params=None): + """Initializes an `Model` instance. + + Args: + blocks_args: A list of BlockArgs to construct block modules. + global_params: GlobalParams, a set of global parameters. + + Raises: + ValueError: when blocks_args is not specified as a list. + """ + super(Model, self).__init__() + if not isinstance(blocks_args, list): + raise ValueError('blocks_args should be a list.') + self._global_params = global_params + self._blocks_args = blocks_args + self._relu_fn = global_params.relu_fn or tf.nn.swish + self._batch_norm = global_params.batch_norm + self._fix_head_stem = global_params.fix_head_stem + + self.endpoints = None + + self._build() + + def _get_conv_block(self, conv_type): + conv_block_map = {0: MBConvBlock, 1: MBConvBlockWithoutDepthwise} + return conv_block_map[conv_type] + + def _build(self): + """Builds a model.""" + self._blocks = [] + batch_norm_momentum = self._global_params.batch_norm_momentum + batch_norm_epsilon = self._global_params.batch_norm_epsilon + if self._global_params.data_format == 'channels_first': + channel_axis = 1 + self._spatial_dims = [2, 3] + else: + channel_axis = -1 + self._spatial_dims = [1, 2] + + # Stem part. + self._conv_stem = utils.Conv2D( + filters=round_filters(32, self._global_params, + self._fix_head_stem), + kernel_size=[3, 3], + strides=[2, 2], + kernel_initializer=conv_kernel_initializer, + padding='same', + data_format=self._global_params.data_format, + use_bias=False) + self._bn0 = self._batch_norm( + axis=channel_axis, + momentum=batch_norm_momentum, + epsilon=batch_norm_epsilon) + + # Builds blocks. + for i, block_args in enumerate(self._blocks_args): + assert block_args.num_repeat > 0 + assert block_args.space2depth in [0, 1, 2] + # Update block input and output filters based on depth multiplier. + input_filters = round_filters(block_args.input_filters, + self._global_params) + + output_filters = round_filters(block_args.output_filters, + self._global_params) + kernel_size = block_args.kernel_size + if self._fix_head_stem and (i == 0 or i == len(self._blocks_args) - 1): + repeats = block_args.num_repeat + else: + repeats = round_repeats( + block_args.num_repeat, self._global_params) + block_args = block_args._replace( + input_filters=input_filters, + output_filters=output_filters, + num_repeat=repeats) + + # The first block needs to take care of stride and filter size increase. + conv_block = self._get_conv_block(block_args.conv_type) + if not block_args.space2depth: # no space2depth at all + self._blocks.append(conv_block( + block_args, self._global_params)) + else: + # if space2depth, adjust filters, kernels, and strides. + depth_factor = int( + 4 / block_args.strides[0] / block_args.strides[1]) + block_args = block_args._replace( + input_filters=block_args.input_filters * depth_factor, + output_filters=block_args.output_filters * depth_factor, + kernel_size=((block_args.kernel_size + 1) // 2 if depth_factor > 1 + else block_args.kernel_size)) + # if the first block has stride-2 and space2depth transformation + if (block_args.strides[0] == 2 and block_args.strides[1] == 2): + block_args = block_args._replace(strides=[1, 1]) + self._blocks.append(conv_block( + block_args, self._global_params)) + block_args = block_args._replace( # sp stops at stride-2 + space2depth=0, + input_filters=input_filters, + output_filters=output_filters, + kernel_size=kernel_size) + elif block_args.space2depth == 1: + self._blocks.append(conv_block( + block_args, self._global_params)) + block_args = block_args._replace(space2depth=2) + else: + self._blocks.append(conv_block( + block_args, self._global_params)) + if block_args.num_repeat > 1: # rest of blocks with the same block_arg + # pylint: disable=protected-access + block_args = block_args._replace( + input_filters=block_args.output_filters, strides=[1, 1]) + # pylint: enable=protected-access + for _ in xrange(block_args.num_repeat - 1): + self._blocks.append(conv_block( + block_args, self._global_params)) + + # Head part. + self._conv_head = utils.Conv2D( + filters=round_filters( + 1280, self._global_params, self._fix_head_stem), + kernel_size=[1, 1], + strides=[1, 1], + kernel_initializer=conv_kernel_initializer, + padding='same', + data_format=self._global_params.data_format, + use_bias=False) + self._bn1 = self._batch_norm( + axis=channel_axis, + momentum=batch_norm_momentum, + epsilon=batch_norm_epsilon) + + self._avg_pooling = tf.keras.layers.GlobalAveragePooling2D( + data_format=self._global_params.data_format) + if self._global_params.num_classes: + self._fc = tf.layers.Dense( + self._global_params.num_classes, + kernel_initializer=dense_kernel_initializer) + else: + self._fc = None + + if self._global_params.dropout_rate > 0: + self._dropout = tf.keras.layers.Dropout( + self._global_params.dropout_rate) + else: + self._dropout = None + + def call(self, + inputs, + training=True, + features_only=None, + pooled_features_only=False): + """Implementation of call(). + + Args: + inputs: input tensors. + training: boolean, whether the model is constructed for training. + features_only: build the base feature network only. + pooled_features_only: build the base network for features extraction + (after 1x1 conv layer and global pooling, but before dropout and fc + head). + + Returns: + output tensors. + """ + outputs = None + self.endpoints = {} + reduction_idx = 0 + # Calls Stem layers + with tf.variable_scope('stem'): + outputs = self._relu_fn( + self._bn0(self._conv_stem(inputs), training=training)) + logging.info('Built stem layers with output shape: %s', outputs.shape) + self.endpoints['stem'] = outputs + + # Calls blocks. + for idx, block in enumerate(self._blocks): + is_reduction = False # reduction flag for blocks after the stem layer + # If the first block has space-to-depth layer, then stem is + # the first reduction point. + if (block.block_args().space2depth == 1 and idx == 0): + reduction_idx += 1 + self.endpoints['reduction_%s' % reduction_idx] = outputs + + elif ((idx == len(self._blocks) - 1) or + self._blocks[idx + 1].block_args().strides[0] > 1): + is_reduction = True + reduction_idx += 1 + + with tf.variable_scope('blocks_%s' % idx): + survival_prob = self._global_params.survival_prob + if survival_prob: + drop_rate = 1.0 - survival_prob + survival_prob = 1.0 - drop_rate * \ + float(idx) / len(self._blocks) + logging.info('block_%s survival_prob: %s', + idx, survival_prob) + outputs = block.call( + outputs, training=training, survival_prob=survival_prob) + self.endpoints['block_%s' % idx] = outputs + if is_reduction: + self.endpoints['reduction_%s' % reduction_idx] = outputs + if block.endpoints: + for k, v in six.iteritems(block.endpoints): + self.endpoints['block_%s/%s' % (idx, k)] = v + if is_reduction: + self.endpoints['reduction_%s/%s' % + (reduction_idx, k)] = v + self.endpoints['features'] = outputs + + if not features_only: + # Calls final layers and returns logits. + with tf.variable_scope('head'): + outputs = self._relu_fn( + self._bn1(self._conv_head(outputs), training=training)) + self.endpoints['head_1x1'] = outputs + + if self._global_params.local_pooling: + shape = outputs.get_shape().as_list() + kernel_size = [ + 1, shape[self._spatial_dims[0]], shape[self._spatial_dims[1]], 1] + outputs = tf.nn.avg_pool( + outputs, ksize=kernel_size, strides=[1, 1, 1, 1], padding='VALID') + self.endpoints['pooled_features'] = outputs + if not pooled_features_only: + if self._dropout: + outputs = self._dropout(outputs, training=training) + self.endpoints['global_pool'] = outputs + if self._fc: + outputs = tf.squeeze(outputs, self._spatial_dims) + outputs = self._fc(outputs) + self.endpoints['head'] = outputs + else: + outputs = self._avg_pooling(outputs) + self.endpoints['pooled_features'] = outputs + if not pooled_features_only: + if self._dropout: + outputs = self._dropout(outputs, training=training) + self.endpoints['global_pool'] = outputs + if self._fc: + outputs = self._fc(outputs) + self.endpoints['head'] = outputs + return outputs diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/eval_ckpt_main.py b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/eval_ckpt_main.py new file mode 100644 index 0000000000000000000000000000000000000000..6f86c49ad96d28c1d820c04e4109d09abac9d0cc --- /dev/null +++ b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/eval_ckpt_main.py @@ -0,0 +1,137 @@ +# Copyright 2019 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Eval checkpoint driver. + +This is an example evaluation script for users to understand the EfficientNet +model checkpoints on CPU. To serve EfficientNet, please consider to export a +`SavedModel` from checkpoints and use tf-serving to serve. +""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from absl import app +from absl import flags +from absl import logging +import tensorflow.compat.v1 as tf + +import model_builder_factory +import preprocessing +import utils + +flags.DEFINE_string('model_name', 'efficientnet-b0', 'Model name to eval.') +flags.DEFINE_string('runmode', 'examples', + 'Running mode: examples or imagenet') +flags.DEFINE_string( + 'imagenet_eval_glob', None, 'Imagenet eval image glob, ' + 'such as /imagenet/ILSVRC2012*.JPEG') +flags.DEFINE_string( + 'imagenet_eval_label', None, 'Imagenet eval label file path, ' + 'such as /imagenet/ILSVRC2012_validation_ground_truth.txt') +flags.DEFINE_string('ckpt_dir', '/tmp/ckpt/', 'Checkpoint folders') +flags.DEFINE_boolean('enable_ema', True, 'Enable exponential moving average.') +flags.DEFINE_string('export_ckpt', None, 'Exported ckpt for eval graph.') +flags.DEFINE_string('example_img', '/tmp/panda.jpg', + 'Filepath for a single example image.') +flags.DEFINE_string('labels_map_file', '/tmp/labels_map.txt', + 'Labels map from label id to its meaning.') +flags.DEFINE_bool('include_background_label', False, + 'Whether to include background as label #0') +flags.DEFINE_bool('advprop_preprocessing', False, + 'Whether to use AdvProp preprocessing.') +flags.DEFINE_integer('num_images', 5000, + 'Number of images to eval. Use -1 to eval all images.') + + +class EvalCkptDriver(utils.EvalCkptDriver): + """A driver for running eval inference.""" + + def build_model(self, features, is_training): + """Build model with input features.""" + tf.logging.info(self.model_name) + model_builder = model_builder_factory.get_model_builder( + self.model_name) + + if self.advprop_preprocessing: + # AdvProp uses Inception preprocessing. + features = features * 2.0 / 255 - 1.0 + else: + features -= tf.constant( + model_builder.MEAN_RGB, shape=[1, 1, 3], dtype=features.dtype) + features /= tf.constant( + model_builder.STDDEV_RGB, shape=[1, 1, 3], dtype=features.dtype) + logits, _ = model_builder.build_model( + features, self.model_name, is_training) + probs = tf.nn.softmax(logits) + probs = tf.squeeze(probs) + return probs + + def get_preprocess_fn(self): + """Build input dataset.""" + return preprocessing.preprocess_image + + +def get_eval_driver(model_name, + include_background_label=False, + advprop_preprocessing=False): + """Get a eval driver.""" + image_size = model_builder_factory.get_model_input_size(model_name) + return EvalCkptDriver( + model_name=model_name, + batch_size=1, + image_size=image_size, + include_background_label=include_background_label, + advprop_preprocessing=advprop_preprocessing) + + +# FLAGS should not be used before main. +FLAGS = flags.FLAGS + + +def main(unused_argv): + """The main function of evaluation.""" + logging.set_verbosity(logging.ERROR) + driver = get_eval_driver(FLAGS.model_name, FLAGS.include_background_label, + FLAGS.advprop_preprocessing) + if FLAGS.runmode == 'examples': + # Run inference for an example image. + driver.eval_example_images(FLAGS.ckpt_dir, [FLAGS.example_img], + FLAGS.labels_map_file, FLAGS.enable_ema, + FLAGS.export_ckpt) + elif FLAGS.runmode == 'imagenet': + # Run inference for imagenet. + driver.eval_imagenet(FLAGS.ckpt_dir, FLAGS.imagenet_eval_glob, + FLAGS.imagenet_eval_label, FLAGS.num_images, + FLAGS.enable_ema, FLAGS.export_ckpt) + else: + print('must specify runmode: examples or imagenet') + + +if __name__ == '__main__': + app.run(main) diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/export_model.py b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/export_model.py new file mode 100644 index 0000000000000000000000000000000000000000..26c42d07f66bfd115fcb7f128c3ce67f73403b00 --- /dev/null +++ b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/export_model.py @@ -0,0 +1,181 @@ +# Copyright 2019 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Export model (float or quantized tflite, and saved model) from a trained checkpoint.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from absl import app +from absl import flags +import tensorflow.compat.v1 as tf + +import imagenet_input +import model_builder_factory + +flags.DEFINE_string("model_name", None, "Model name to eval.") +flags.DEFINE_string("ckpt_dir", None, "Path to the training checkpoint") +flags.DEFINE_boolean("enable_ema", True, "Enable exponential moving average.") +flags.DEFINE_string("data_dir", None, + "Image dataset directory for post training quantization.") +flags.DEFINE_string("output_tflite", None, "Path to output tflite file.") +flags.DEFINE_bool("quantize", True, + "Quantize model to uint8 before exporting tflite model.") +flags.DEFINE_integer( + "num_steps", 2000, + "Number of post-training quantization calibration steps to run.") +flags.DEFINE_integer("image_size", 224, "Size of the input image.") +flags.DEFINE_integer("batch_size", 1, "Batch size of input tensor.") +flags.DEFINE_string("endpoint_name", None, "Endpoint name") +flags.DEFINE_string("output_saved_model_dir", None, + "Directory in which to save the saved_model.") +FLAGS = flags.FLAGS + + +def restore_model(sess, ckpt_dir, enable_ema=True): + """Restore variables from checkpoint dir.""" + sess.run(tf.global_variables_initializer()) + checkpoint = tf.train.latest_checkpoint(ckpt_dir) + if enable_ema: + ema = tf.train.ExponentialMovingAverage(decay=0.0) + ema_vars = tf.trainable_variables() + tf.get_collection("moving_vars") + for v in tf.global_variables(): + if "moving_mean" in v.name or "moving_variance" in v.name: + ema_vars.append(v) + ema_vars = list(set(ema_vars)) + var_dict = ema.variables_to_restore(ema_vars) + else: + var_dict = None + + sess.run(tf.global_variables_initializer()) + saver = tf.train.Saver(var_dict, max_to_keep=1) + saver.restore(sess, checkpoint) + + +def representative_dataset_gen(): + """Gets a python generator of image numpy arrays for ImageNet.""" + params = dict(batch_size=FLAGS.batch_size) + imagenet_eval = imagenet_input.ImageNetInput( + is_training=False, + data_dir=FLAGS.data_dir, + transpose_input=False, + cache=False, + image_size=FLAGS.image_size, + num_parallel_calls=1, + use_bfloat16=False, + include_background_label=True, + ) + + data = imagenet_eval.input_fn(params) + + def preprocess_map_fn(images, labels): + """The function of preprocess the map.""" + del labels + model_builder = model_builder_factory.get_model_builder( + FLAGS.model_name) + images -= tf.constant( + model_builder.MEAN_RGB, shape=[1, 1, 3], dtype=images.dtype) + images /= tf.constant( + model_builder.STDDEV_RGB, shape=[1, 1, 3], dtype=images.dtype) + return images + + data = data.map(preprocess_map_fn) + iterator = data.make_one_shot_iterator() + for _ in range(FLAGS.num_steps): + # In eager context, we can get a python generator from a dataset iterator. + images = iterator.get_next() + yield [images] + + +def main(_): + """Enables eager context for TF 1.x. TF 2.x will use eager by default. + This is used to conveniently get a representative dataset generator using + TensorFlow training input helper. + """ + tf.enable_eager_execution() + + model_builder = model_builder_factory.get_model_builder(FLAGS.model_name) + + with tf.Graph().as_default(), tf.Session() as sess: + images = tf.placeholder( + tf.float32, + shape=(1, FLAGS.image_size, FLAGS.image_size, 3), + name="images") + + logits, endpoints = model_builder.build_model(images, FLAGS.model_name, + False) + if FLAGS.endpoint_name: + output_tensor = endpoints[FLAGS.endpoint_name] + else: + output_tensor = tf.nn.softmax(logits) + + restore_model(sess, FLAGS.ckpt_dir, FLAGS.enable_ema) + + if FLAGS.output_saved_model_dir: + signature_def_map = { + "serving_default": + tf.compat.v1.saved_model.signature_def_utils + .predict_signature_def({"input": images}, + {"output": output_tensor}) + } + + builder = tf.compat.v1.saved_model.Builder( + FLAGS.output_saved_model_dir) + builder.add_meta_graph_and_variables( + sess, ["serve"], signature_def_map=signature_def_map) + builder.save() + print("Saved model written to %s" % FLAGS.output_saved_model_dir) + + converter = tf.lite.TFLiteConverter.from_session(sess, [images], + [output_tensor]) + if FLAGS.quantize: + if not FLAGS.data_dir: + raise ValueError( + "Post training quantization requires data_dir flag to point to the " + "calibration dataset. To export a float model, set " + "--quantize=False.") + + converter.representative_dataset = tf.lite.RepresentativeDataset( + representative_dataset_gen) + converter.optimizations = [tf.lite.Optimize.DEFAULT] + converter.inference_input_type = tf.lite.constants.QUANTIZED_UINT8 + converter.inference_output_type = tf.lite.constants.QUANTIZED_UINT8 + converter.target_spec.supported_ops = [ + tf.lite.OpsSet.TFLITE_BUILTINS_INT8 + ] + + tflite_buffer = converter.convert() + tf.gfile.GFile(FLAGS.output_tflite, "wb").write(tflite_buffer) + print("tflite model written to %s" % FLAGS.output_tflite) + + +if __name__ == "__main__": + flags.mark_flag_as_required("model_name") + flags.mark_flag_as_required("ckpt_dir") + flags.mark_flag_as_required("output_tflite") + app.run(main) diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/g3doc/condconv-layer.png b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/g3doc/condconv-layer.png new file mode 100644 index 0000000000000000000000000000000000000000..4410f7df42759f42fe8a51d7ebe0d2ea2dfb1ff4 Binary files /dev/null and b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/g3doc/condconv-layer.png differ diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/g3doc/efficientnet-edgetpu.png b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/g3doc/efficientnet-edgetpu.png new file mode 100644 index 0000000000000000000000000000000000000000..de59e48f812f51da13e1163c2cab5e16e66a463d Binary files /dev/null and b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/g3doc/efficientnet-edgetpu.png differ diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/g3doc/flops.png b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/g3doc/flops.png new file mode 100644 index 0000000000000000000000000000000000000000..540e2285933527e65fec8b47006ff258900f07a5 Binary files /dev/null and b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/g3doc/flops.png differ diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/g3doc/lite-float-gpu.png b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/g3doc/lite-float-gpu.png new file mode 100644 index 0000000000000000000000000000000000000000..b013ac1298215284f9881543befef0d51c63dd38 Binary files /dev/null and b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/g3doc/lite-float-gpu.png differ diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/g3doc/lite-quant-cpu.png b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/g3doc/lite-quant-cpu.png new file mode 100644 index 0000000000000000000000000000000000000000..41edfb439bd421de8c1302817c266a948de0128e Binary files /dev/null and b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/g3doc/lite-quant-cpu.png differ diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/g3doc/lite-quant-size.png b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/g3doc/lite-quant-size.png new file mode 100644 index 0000000000000000000000000000000000000000..4e1a3807a54eb50536eec7cf8d2daf401b49220c Binary files /dev/null and b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/g3doc/lite-quant-size.png differ diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/g3doc/params.png b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/g3doc/params.png new file mode 100644 index 0000000000000000000000000000000000000000..b95e059b919bc0e3772ca7d285ee16004f98cb23 Binary files /dev/null and b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/g3doc/params.png differ diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/help_modelarts.py b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/help_modelarts.py new file mode 100644 index 0000000000000000000000000000000000000000..2d15a0774fc9ee9301e85dc90457d3186bcd6ca8 --- /dev/null +++ b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/help_modelarts.py @@ -0,0 +1,89 @@ +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os +import datetime +import moxing as mox + + +def obs_data2modelarts(config): + """ + Copy train data from obs to modelarts by using moxing api. + """ + start = datetime.datetime.now() + print("===>>>Copy files from obs:{} to modelarts dir:{}".format( + config.data_url, config.modelarts_data_dir)) + mox.file.copy_parallel(src_url=config.data_url, + dst_url=config.modelarts_data_dir) + end = datetime.datetime.now() + print("===>>>Copy from obs to modelarts, time use:{}(s)".format( + (end - start).seconds)) + files = os.listdir(config.modelarts_data_dir) + print("===>>>Files:", files) + print("===>>>File_nums:", len(files)) + + +def modelarts_result2obs(FLAGS): + """ + Copy debug data from modelarts to obs. + According to the swich flags, the debug data may contains auto tune repository, + dump data for precision comparision, even the computation graph and profiling data. + """ + work_dir = os.getcwd() + + # copy result from modelarts to obs + obs_result_dir = os.path.join(FLAGS.obs_dir, 'result') + if not mox.file.exists(obs_result_dir): + mox.file.make_dirs(obs_result_dir) + mox.file.copy_parallel(src_url=FLAGS.model_dir, dst_url=obs_result_dir) + print("===>>>Copy Event or Checkpoint from modelarts dir:{} to obs:{}".format( + FLAGS.model_dir, obs_result_dir)) + + # Copy dump data. Comment this snippets if npu_dump_data is off. + if FLAGS.npu_dump_data: + obs_dump_data_dir = os.path.join(FLAGS.obs_dir, 'npu_dump_data') + if not mox.file.exists(obs_dump_data_dir): + mox.file.make_dirs(obs_dump_data_dir) + mox.file.copy_parallel(FLAGS.dump_dir, obs_dump_data_dir) + print("===>>>Dumped graph:{} on OBS dir:{}".format( + mox.file.list_directory(obs_dump_data_dir), obs_dump_data_dir)) + + if FLAGS.npu_profiling: + obs_profiling_dir = os.path.join(FLAGS.obs_dir, 'npu_profiling') + if not mox.file.exists(obs_profiling_dir): + mox.file.make_dirs(obs_profiling_dir) + mox.file.copy_parallel(FLAGS.profiling_dir, obs_profiling_dir) + print("===>>>Profiling data:{} on OBS dir:{}".format( + mox.file.list_directory(obs_profiling_dir), obs_profiling_dir)) + + # Copy compute graph. Comment this snippets if npu_dump_graph is off. + if FLAGS.npu_dump_graph: + modelarts_dump_graph_dir = os.path.join(work_dir, "npu_dump_graph") + obs_dump_graph_dir = os.path.join(FLAGS.obs_dir, 'npu_dump_graph') + if not mox.file.exists(obs_dump_graph_dir): + mox.file.make_dirs(obs_dump_graph_dir) + mox.file.copy_parallel(modelarts_dump_graph_dir, obs_dump_graph_dir) + print("===>>>Dumped data:{} on OBS dir:{}".format( + mox.file.list_directory(obs_dump_graph_dir), obs_dump_graph_dir)) + + # Copy profiling data. Comment this snippets if npu_profiling is off. + + # Copy auto tune repository. Comment this snippets if npu_auto_tune is off. + if FLAGS.npu_auto_tune: + modelarts_auto_tune_dir = os.path.join(work_dir, "npu_auto_tune") + obs_auto_tune_dir = os.path.join(FLAGS.obs_dir, 'npu_auto_tune') + if not mox.file.exists(obs_auto_tune_dir): + mox.file.make_dirs(obs_auto_tune_dir) + mox.file.copy_parallel(modelarts_auto_tune_dir, obs_auto_tune_dir) + print("===>>>Auto tune:{} on OBS dir:{}".format( + mox.file.list_directory(obs_auto_tune_dir), obs_auto_tune_dir)) diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/imagenet_input.py b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/imagenet_input.py new file mode 100644 index 0000000000000000000000000000000000000000..86e8a1c9fb0701360dccd810eb7ff49c6529fd23 --- /dev/null +++ b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/imagenet_input.py @@ -0,0 +1,528 @@ +# Copyright 2019 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Efficient ImageNet input pipeline using tf.data.Dataset.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import abc +import collections +import functools +import os + +from absl import logging +import six +import tensorflow.compat.v1 as tf + +import preprocessing + + +def build_image_serving_input_fn(image_size, + batch_size=None, + resize_method=None): + """Builds a serving input fn for raw images.""" + + def _image_serving_input_fn(): + """Serving input fn for raw images.""" + + def _preprocess_image(image_bytes): + """Preprocess a single raw image.""" + image = preprocessing.preprocess_image( + image_bytes=image_bytes, + is_training=False, + image_size=image_size, + resize_method=resize_method) + return image + + image_bytes_list = tf.placeholder( + shape=[batch_size], + dtype=tf.string, + ) + images = tf.map_fn( + _preprocess_image, image_bytes_list, back_prop=False, dtype=tf.float32) + return tf.estimator.export.ServingInputReceiver( + images, {'image_bytes': image_bytes_list}) + return _image_serving_input_fn + + +class ImageNetTFExampleInput(six.with_metaclass(abc.ABCMeta, object)): + """Base class for ImageNet input_fn generator.""" + + def __init__(self, + is_training, + use_bfloat16, + num_cores=8, + image_size=224, + transpose_input=False, + num_label_classes=1000, + include_background_label=False, + augment_name=None, + mixup_alpha=0.0, + randaug_num_layers=None, + randaug_magnitude=None, + resize_method=None): + """Constructor. + + Args: + is_training: `bool` for whether the input is for training + use_bfloat16: If True, use bfloat16 precision; else use float32. + num_cores: `int` for the number of TPU cores + image_size: `int` for image size (both width and height). + transpose_input: 'bool' for whether to use the double transpose trick + num_label_classes: number of label classes. Default to 1000 for ImageNet. + include_background_label: If true, label #0 is reserved for background. + augment_name: `string` that is the name of the augmentation method to + apply to the image. `autoaugment` if AutoAugment is to be used or + `randaugment` if RandAugment is to be used. If the value is `None` no no + augmentation method will be applied applied. See autoaugment.py for more + details. + mixup_alpha: float to control the strength of Mixup regularization, set to + 0.0 to disable. + randaug_num_layers: 'int', if RandAug is used, what should the number of + layers be. See autoaugment.py for detailed description. + randaug_magnitude: 'int', if RandAug is used, what should the magnitude + be. See autoaugment.py for detailed description. + resize_method: If None, use bicubic in default. + """ + self.image_preprocessing_fn = preprocessing.preprocess_image + self.is_training = is_training + self.use_bfloat16 = use_bfloat16 + self.num_cores = num_cores + self.transpose_input = transpose_input + self.image_size = image_size + self.include_background_label = include_background_label + self.num_label_classes = num_label_classes + if include_background_label: + self.num_label_classes += 1 + self.augment_name = augment_name + self.mixup_alpha = mixup_alpha + self.randaug_num_layers = randaug_num_layers + self.randaug_magnitude = randaug_magnitude + self.resize_method = resize_method + + def set_shapes(self, batch_size, images, labels): + """Statically set the batch_size dimension.""" + if self.transpose_input: + images.set_shape(images.get_shape().merge_with( + tf.TensorShape([None, None, None, batch_size]))) + labels.set_shape(labels.get_shape().merge_with( + tf.TensorShape([batch_size, None]))) + # Convert to R1 tensors for fast transfer to device. + images = tf.reshape(images, [-1]) + else: + images.set_shape(images.get_shape().merge_with( + tf.TensorShape([batch_size, None, None, None]))) + labels.set_shape(labels.get_shape().merge_with( + tf.TensorShape([batch_size, None]))) + + return images, labels + + def mixup(self, batch_size, alpha, images, labels): + """Applies Mixup regularization to a batch of images and labels. + + [1] Hongyi Zhang, Moustapha Cisse, Yann N. Dauphin, David Lopez-Paz + Mixup: Beyond Empirical Risk Minimization. + ICLR'18, https://arxiv.org/abs/1710.09412 + + Arguments: + batch_size: The input batch size for images and labels. + alpha: Float that controls the strength of Mixup regularization. + images: A batch of images of shape [batch_size, ...] + labels: A batch of labels of shape [batch_size, num_classes] + + Returns: + A tuple of (images, labels) with the same dimensions as the input with + Mixup regularization applied. + """ + mix_weight = tf.distributions.Beta( + alpha, alpha).sample([batch_size, 1]) + mix_weight = tf.maximum(mix_weight, 1. - mix_weight) + images_mix_weight = tf.cast( + tf.reshape(mix_weight, [batch_size, 1, 1, 1]), images.dtype) + # Mixup on a single batch is implemented by taking a weighted sum with the + # same batch in reverse. + images_mix = ( + images * images_mix_weight + images[::-1] * (1. - images_mix_weight)) + labels_mix = labels * mix_weight + labels[::-1] * (1. - mix_weight) + return images_mix, labels_mix + + def dataset_parser(self, value): + """Parses an image and its label from a serialized ResNet-50 TFExample. + + Args: + value: serialized string containing an ImageNet TFExample. + + Returns: + Returns a tuple of (image, label) from the TFExample. + """ + keys_to_features = { + 'image/encoded': tf.FixedLenFeature((), tf.string, ''), + 'image/class/label': tf.FixedLenFeature([], tf.int64, -1), + } + + parsed = tf.parse_single_example(value, keys_to_features) + image_bytes = tf.reshape(parsed['image/encoded'], shape=[]) + + image = self.image_preprocessing_fn( + image_bytes=image_bytes, + is_training=self.is_training, + image_size=self.image_size, + use_bfloat16=self.use_bfloat16, + augment_name=self.augment_name, + randaug_num_layers=self.randaug_num_layers, + randaug_magnitude=self.randaug_magnitude, + resize_method=self.resize_method) + + # The labels will be in range [1,1000], 0 is reserved for background + label = tf.cast( + tf.reshape(parsed['image/class/label'], shape=[]), dtype=tf.int32) + + if not self.include_background_label: + # Subtract 1 if the background label is discarded. + label -= 1 + + onehot_label = tf.one_hot(label, self.num_label_classes) + + return image, onehot_label + + @abc.abstractmethod + def make_source_dataset(self, index, num_hosts): + """Makes dataset of serialized TFExamples. + + The returned dataset will contain `tf.string` tensors, but these strings are + serialized `TFExample` records that will be parsed by `dataset_parser`. + + If self.is_training, the dataset should be infinite. + + Args: + index: current host index. + num_hosts: total number of hosts. + + Returns: + A `tf.data.Dataset` object. + """ + return + + def input_fn(self, params): + """Input function which provides a single batch for train or eval. + + Args: + params: `dict` of parameters passed from the `TPUEstimator`. + `params['batch_size']` is always provided and should be used as the + effective batch size. + + Returns: + A `tf.data.Dataset` object. + """ + # Retrieves the batch size for the current shard. The # of shards is + # computed according to the input pipeline deployment. See + # tf.estimator.tpu.RunConfig for details. + batch_size = params['batch_size'] + + if 'context' in params: + current_host = params['context'].current_input_fn_deployment()[1] + num_hosts = params['context'].num_hosts + else: + current_host = 0 + num_hosts = 1 + + dataset = self.make_source_dataset(current_host, num_hosts) + + # Use the fused map-and-batch operation. + # + # For XLA, we must used fixed shapes. Because we repeat the source training + # dataset indefinitely, we can use `drop_remainder=True` to get fixed-size + # batches without dropping any training examples. + # + # When evaluating, `drop_remainder=True` prevents accidentally evaluating + # the same image twice by dropping the final batch if it is less than a full + # batch size. As long as this validation is done with consistent batch size, + # exactly the same images will be used. + dataset = dataset.map(self.dataset_parser, 64).batch(batch_size, True) + + # Apply Mixup + if self.is_training and self.mixup_alpha > 0.0: + dataset = dataset.map( + functools.partial(self.mixup, batch_size, self.mixup_alpha), + num_parallel_calls=64) + + # Transpose for performance on TPU + if self.transpose_input: + dataset = dataset.map( + lambda images, labels: (tf.transpose( + images, [1, 2, 3, 0]), labels), + num_parallel_calls=64) + + # Assign static batch size dimension + dataset = dataset.map(functools.partial( + self.set_shapes, batch_size), 64) + + # Prefetch overlaps in-feed with training + dataset = dataset.prefetch(tf.data.experimental.AUTOTUNE) + options = tf.data.Options() + options.experimental_deterministic = False + options.experimental_threading.max_intra_op_parallelism = 1 + options.experimental_threading.private_threadpool_size = 48 + dataset = dataset.with_options(options) + + return dataset + + +class ImageNetInput(ImageNetTFExampleInput): + """Generates ImageNet input_fn from a series of TFRecord files. + + The training data is assumed to be in TFRecord format with keys as specified + in the dataset_parser below, sharded across 1024 files, named sequentially: + + train-00000-of-01024 + train-00001-of-01024 + ... + train-01023-of-01024 + + The validation data is in the same format but sharded in 128 files. + + The format of the data required is created by the script at: + https://github.com/tensorflow/tpu/blob/master/tools/datasets/imagenet_to_gcs.py + """ + + def __init__(self, + is_training, + use_bfloat16, + transpose_input, + data_dir, + image_size=224, + num_parallel_calls=64, + cache=False, + num_label_classes=1000, + include_background_label=False, + augment_name=None, + mixup_alpha=0.0, + randaug_num_layers=None, + randaug_magnitude=None, + resize_method=None, + holdout_shards=None): + """Create an input from TFRecord files. + + Args: + is_training: `bool` for whether the input is for training + use_bfloat16: If True, use bfloat16 precision; else use float32. + transpose_input: 'bool' for whether to use the double transpose trick + data_dir: `str` for the directory of the training and validation data; + if 'null' (the literal string 'null') or implicitly False + then construct a null pipeline, consisting of empty images + and blank labels. + image_size: `int` for image size (both width and height). + num_parallel_calls: concurrency level to use when reading data from disk. + cache: if true, fill the dataset by repeating from its cache. + num_label_classes: number of label classes. Default to 1000 for ImageNet. + include_background_label: if true, label #0 is reserved for background. + augment_name: `string` that is the name of the augmentation method + to apply to the image. `autoaugment` if AutoAugment is to be used or + `randaugment` if RandAugment is to be used. If the value is `None` no + no augmentation method will be applied applied. See autoaugment.py + for more details. + mixup_alpha: float to control the strength of Mixup regularization, set + to 0.0 to disable. + randaug_num_layers: 'int', if RandAug is used, what should the number of + layers be. See autoaugment.py for detailed description. + randaug_magnitude: 'int', if RandAug is used, what should the magnitude + be. See autoaugment.py for detailed description. + resize_method: If None, use bicubic in default. + holdout_shards: number of holdout training shards for validation. + """ + super(ImageNetInput, self).__init__( + is_training=is_training, + image_size=image_size, + use_bfloat16=use_bfloat16, + transpose_input=transpose_input, + num_label_classes=num_label_classes, + include_background_label=include_background_label, + augment_name=augment_name, + mixup_alpha=mixup_alpha, + randaug_num_layers=randaug_num_layers, + randaug_magnitude=randaug_magnitude) + self.data_dir = data_dir + if self.data_dir == 'null' or not self.data_dir: + self.data_dir = None + self.num_parallel_calls = num_parallel_calls + self.cache = cache + self.holdout_shards = holdout_shards + + def _get_null_input(self, data): + """Returns a null image (all black pixels). + + Args: + data: element of a dataset, ignored in this method, since it produces + the same null image regardless of the element. + + Returns: + a tensor representing a null image. + """ + del data # Unused since output is constant regardless of input + return tf.zeros([self.image_size, self.image_size, 3], tf.bfloat16 + if self.use_bfloat16 else tf.float32) + + def dataset_parser(self, value): + """See base class.""" + if not self.data_dir: + return value, tf.constant(0., tf.float32, (1000,)) + return super(ImageNetInput, self).dataset_parser(value) + + def make_source_dataset(self, index, num_hosts): + """See base class.""" + if not self.data_dir: + logging.info('Undefined data_dir implies null input') + return tf.data.Dataset.range(1).repeat().map(self._get_null_input) + + if self.holdout_shards: + if self.is_training: + filenames = [ + os.path.join(self.data_dir, 'train-%05d-of-01024' % i) + for i in range(self.holdout_shards, 1024) + ] + else: + filenames = [ + os.path.join(self.data_dir, 'train-%05d-of-01024' % i) + for i in range(0, self.holdout_shards) + ] + for f in filenames[:10]: + logging.info('datafiles: %s', f) + dataset = tf.data.Dataset.from_tensor_slices(filenames) + else: + file_pattern = os.path.join( + self.data_dir, 'train-*' if self.is_training else 'validation-*') + logging.info('datafiles: %s', file_pattern) + dataset = tf.data.Dataset.list_files(file_pattern, shuffle=False) + + # For multi-host training, we want each hosts to always process the same + # subset of files. Each host only sees a subset of the entire dataset, + # allowing us to cache larger datasets in memory. + dataset = dataset.shard(num_hosts, index) + + if self.is_training and not self.cache: + dataset = dataset.repeat() + + def fetch_dataset(filename): + buffer_size = 8 * 1024 * 1024 # 8 MiB per file + dataset = tf.data.TFRecordDataset( + filename, buffer_size=buffer_size) + return dataset + + # Read the data from disk in parallel + dataset = dataset.interleave( + fetch_dataset, cycle_length=self.num_parallel_calls, + num_parallel_calls=self.num_parallel_calls) + + if self.cache: + dataset = dataset.cache().shuffle(1024 * 16).repeat() + else: + dataset = dataset.shuffle(1024) + + return dataset + + +# Defines a selection of data from a Cloud Bigtable. +BigtableSelection = collections.namedtuple('BigtableSelection', [ + 'project', 'instance', 'table', 'prefix', 'column_family', + 'column_qualifier' +]) + + +class ImageNetBigtableInput(ImageNetTFExampleInput): + """Generates ImageNet input_fn from a Bigtable for training or evaluation. + """ + + def __init__(self, + is_training, + use_bfloat16, + transpose_input, + selection, + augment_name=None, + num_label_classes=1000, + include_background_label=False, + mixup_alpha=0.0, + randaug_num_layers=None, + randaug_magnitude=None, + resize_method=None): + """Constructs an ImageNet input from a BigtableSelection. + + Args: + is_training: `bool` for whether the input is for training + use_bfloat16: If True, use bfloat16 precision; else use float32. + transpose_input: 'bool' for whether to use the double transpose trick + selection: a BigtableSelection specifying a part of a Bigtable. + augment_name: `string` that is the name of the augmentation method + to apply to the image. `autoaugment` if AutoAugment is to be used or + `randaugment` if RandAugment is to be used. If the value is `None` no + no augmentation method will be applied applied. See autoaugment.py + for more details. + num_label_classes: number of label classes. Default to 1000 for ImageNet. + include_background_label: if true, label #0 is reserved for background. + mixup_alpha: float to control the strength of Mixup regularization, set + to 0.0 to disable. + randaug_num_layers: 'int', if RandAug is used, what should the number of + layers be. See autoaugment.py for detailed description. + randaug_magnitude: 'int', if RandAug is used, what should the magnitude + be. See autoaugment.py for detailed description.s + resize_method: if None, use bicubic. + """ + super(ImageNetBigtableInput, self).__init__( + is_training=is_training, + use_bfloat16=use_bfloat16, + transpose_input=transpose_input, + num_label_classes=num_label_classes, + include_background_label=include_background_label, + augment_name=augment_name, + mixup_alpha=mixup_alpha, + randaug_num_layers=randaug_num_layers, + randaug_magnitude=randaug_magnitude, + resize_method=resize_method) + self.selection = selection + + def make_source_dataset(self, index, num_hosts): + """See base class.""" + try: + from tensorflow.contrib.cloud import BigtableClient # pylint: disable=g-import-not-at-top + except ImportError as e: + logging.exception('Bigtable is not supported in TensorFlow 2.x.') + raise e + + data = self.selection + client = BigtableClient(data.project, data.instance) + table = client.table(data.table) + ds = table.parallel_scan_prefix(data.prefix, + columns=[(data.column_family, + data.column_qualifier)]) + # The Bigtable datasets will have the shape (row_key, data) + ds_data = ds.map(lambda index, data: data) + + if self.is_training: + ds_data = ds_data.repeat() + + return ds_data diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/inspect_model_architecture.py b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/inspect_model_architecture.py new file mode 100644 index 0000000000000000000000000000000000000000..2de42f13efac1f4dedb6cc64828211e6b0091824 --- /dev/null +++ b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/inspect_model_architecture.py @@ -0,0 +1,90 @@ +# Copyright 2019 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Export a dummy-quantized tflite model corresponding to the given model.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from absl import app +from absl import flags +import tensorflow as tf + +import efficientnet_builder +from edgetpu import efficientnet_edgetpu_builder + +flags.DEFINE_string('model_name', 'efficientnet-b0', 'Model name to inspect.') +flags.DEFINE_integer('image_res', 224, 'The size of the input image') +flags.DEFINE_string('output_tflite', '/tmp/model.tflite', + 'Location of the generated tflite model') + +# FLAGS should not be used before main. +FLAGS = flags.FLAGS + + +def main(unused_argv): + tf.logging.set_verbosity(tf.logging.ERROR) + image_res = FLAGS.image_res + model_name = FLAGS.model_name + model_builder_fn = None + if model_name.startswith('efficientnet-edgetpu'): + model_builder_fn = efficientnet_edgetpu_builder + elif model_name.startswith('efficientnet'): + model_builder_fn = efficientnet_builder + + else: + raise ValueError( + 'Model must be either efficientnet-b* or efficientnet-edgetpu*') + + with tf.Graph().as_default(), tf.Session() as sess: + images = tf.placeholder( + tf.float32, shape=(1, image_res, image_res, 3), name='input') + output, _ = model_builder_fn.build_model( + images, FLAGS.model_name, training=False) + + tf.global_variables_initializer().run() + updates = [] + for var in tf.trainable_variables(): + noise = tf.random.normal(shape=var.shape, stddev=0.001) + updates.append(var.assign_add(noise)) + sess.run(updates) + converter = tf.lite.TFLiteConverter.from_session( + sess, [images], [output]) # pytype: disable=attribute-error + converter.inference_type = tf.lite.constants.QUANTIZED_UINT8 + converter.quantized_input_stats = {'input': (0, 1.)} + converter.default_ranges_stats = (-10, 10) + + tflite_model = converter.convert() + tf.gfile.Open(FLAGS.output_tflite, 'wb').write(tflite_model) + + print('Model %s, image size %d' % (model_name, image_res)) + print('TfLite model stored at %s' % FLAGS.output_tflite) + + +if __name__ == '__main__': + app.run(main) diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/lars_optimizer.py b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/lars_optimizer.py new file mode 100644 index 0000000000000000000000000000000000000000..4db7b4ac140a307b9d65164a074316e571a041fe --- /dev/null +++ b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/lars_optimizer.py @@ -0,0 +1,188 @@ +# Copyright 2018 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Layer-wise Adaptive Rate Scaling optimizer for large-batch training.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import tensorflow.compat.v1 as tf + + +class LARSOptimizer(tf.train.Optimizer): + """Layer-wise Adaptive Rate Scaling for large batch training. + + Introduced by "Large Batch Training of Convolutional Networks" by Y. You, + I. Gitman, and B. Ginsburg. (https://arxiv.org/abs/1708.03888) + + Implements the LARS learning rate scheme presented in the paper above. This + optimizer is useful when scaling the batch size to up to 32K without + significant performance degradation. It is recommended to use the optimizer + in conjunction with: + - Gradual learning rate warm-up + - Linear learning rate scaling + - Poly rule learning rate decay + + Note, LARS scaling is currently only enabled for dense tensors. Sparse tensors + use the default momentum optimizer. + """ + + def __init__( + self, + learning_rate, + momentum=0.9, + weight_decay=0.0001, + # The LARS coefficient is a hyperparameter + eeta=0.001, + epsilon=0.0, + name="LARSOptimizer", + # Enable skipping variables from LARS scaling. + # TODO(sameerkm): Enable a direct mechanism to pass a + # subset of variables to the optimizer. + skip_list=None, + use_nesterov=False): + """Construct a new LARS Optimizer. + + Args: + learning_rate: A `Tensor` or floating point value. The base learning rate. + momentum: A floating point value. Momentum hyperparameter. + weight_decay: A floating point value. Weight decay hyperparameter. + eeta: LARS coefficient as used in the paper. Dfault set to LARS + coefficient from the paper. (eeta / weight_decay) determines the highest + scaling factor in LARS. + epsilon: Optional epsilon parameter to be set in models that have very + small gradients. Default set to 0.0. + name: Optional name prefix for variables and ops created by LARSOptimizer. + skip_list: List of strings to enable skipping variables from LARS scaling. + If any of the strings in skip_list is a subset of var.name, variable + 'var' is skipped from LARS scaling. For a typical classification model + with batch normalization, the skip_list is ['batch_normalization', + 'bias'] + use_nesterov: when set to True, nesterov momentum will be enabled + + Raises: + ValueError: If a hyperparameter is set to a non-sensical value. + """ + if momentum < 0.0: + raise ValueError("momentum should be positive: %s" % momentum) + if weight_decay < 0.0: + raise ValueError( + "weight_decay should be positive: %s" % weight_decay) + super(LARSOptimizer, self).__init__(use_locking=False, name=name) + + self._learning_rate = learning_rate + self._momentum = momentum + self._weight_decay = weight_decay + self._eeta = eeta + self._epsilon = epsilon + self._name = name + self._skip_list = skip_list + self._use_nesterov = use_nesterov + + def _create_slots(self, var_list): + for v in var_list: + self._zeros_slot(v, "momentum", self._name) + + def compute_lr(self, grad, var): + """Compute the learning rate according to the grad and var.""" + scaled_lr = self._learning_rate + if self._skip_list is None or not any(v in var.name + for v in self._skip_list): + w_norm = tf.norm(var, ord=2) + g_norm = tf.norm(grad, ord=2) + trust_ratio = tf.where( + tf.math.greater(w_norm, 0), + tf.where( + tf.math.greater(g_norm, 0), + (self._eeta * w_norm / + (g_norm + self._weight_decay * w_norm + self._epsilon)), 1.0), + 1.0) + scaled_lr = self._learning_rate * trust_ratio + # Add the weight regularization gradient + grad = grad + self._weight_decay * var + return scaled_lr, grad + + def _apply_dense(self, grad, var): + scaled_lr, grad = self.compute_lr(grad, var) + mom = self.get_slot(var, "momentum") + return tf.raw_ops.ApplyMomentum( + var, + mom, + tf.cast(1.0, var.dtype.base_dtype), + grad * scaled_lr, + self._momentum, + use_locking=False, + use_nesterov=self._use_nesterov) + + def _resource_apply_dense(self, grad, var): + scaled_lr, grad = self.compute_lr(grad, var) + mom = self.get_slot(var, "momentum") + return tf.raw_ops.ResourceApplyMomentum( + var=var.handle, + accum=mom.handle, + lr=tf.cast(1.0, var.dtype.base_dtype), + grad=grad * scaled_lr, + momentum=self._momentum, + use_locking=False, + use_nesterov=self._use_nesterov) + + # Fallback to momentum optimizer for sparse tensors + def _apply_sparse(self, grad, var): + mom = self.get_slot(var, "momentum") + return tf.raw_ops.SparseApplyMomentum( + var, + mom, + tf.cast(self._learning_rate_tensor, var.dtype.base_dtype), + grad.values, + grad.indices, + tf.cast(self._momentum_tensor, var.dtype.base_dtype), + use_locking=self._use_locking, + use_nesterov=self._use_nesterov).op + + def _resource_apply_sparse(self, grad, var, indices): + mom = self.get_slot(var, "momentum") + return tf.raw_ops.ResourceSparseApplyMomentum( + var.handle, + mom.handle, + tf.cast(self._learning_rate_tensor, grad.dtype), + grad, + indices, + tf.cast(self._momentum_tensor, grad.dtype), + use_locking=self._use_locking, + use_nesterov=self._use_nesterov) + + def _prepare(self): + learning_rate = self._learning_rate + if callable(learning_rate): + learning_rate = learning_rate() + self._learning_rate_tensor = tf.convert_to_tensor( + learning_rate, name="learning_rate") + momentum = self._momentum + if callable(momentum): + momentum = momentum() + self._momentum_tensor = tf.convert_to_tensor(momentum, name="momentum") diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/lite/__init__.py b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/lite/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..6078e15fd7eb52f31876003d4ee7d22a871e08cd --- /dev/null +++ b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/lite/__init__.py @@ -0,0 +1,28 @@ +# Copyright 2020 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""The initial file of lite.""" \ No newline at end of file diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/lite/efficientnet_lite_builder.py b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/lite/efficientnet_lite_builder.py new file mode 100644 index 0000000000000000000000000000000000000000..7f88779c4d3f757df124d3b3668d6c4b89da1184 --- /dev/null +++ b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/lite/efficientnet_lite_builder.py @@ -0,0 +1,221 @@ +# Copyright 2020 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Model Builder for EfficientNet Edge Models.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import os +from absl import logging +import tensorflow.compat.v1 as tf + +import efficientnet_builder +import efficientnet_model +import utils +# Edge models use inception-style MEAN and STDDEV for better post-quantization. +MEAN_RGB = [127.0, 127.0, 127.0] +STDDEV_RGB = [128.0, 128.0, 128.0] + + +def efficientnet_lite_params(model_name): + """Get efficientnet params based on model name.""" + params_dict = { + # (width_coefficient, depth_coefficient, resolution, dropout_rate) + 'efficientnet-lite0': (1.0, 1.0, 224, 0.2), + 'efficientnet-lite1': (1.0, 1.1, 240, 0.2), + 'efficientnet-lite2': (1.1, 1.2, 260, 0.3), + 'efficientnet-lite3': (1.2, 1.4, 280, 0.3), + 'efficientnet-lite4': (1.4, 1.8, 300, 0.3), + } + return params_dict[model_name] + + +_DEFAULT_BLOCKS_ARGS = [ + 'r1_k3_s11_e1_i32_o16_se0.25', 'r2_k3_s22_e6_i16_o24_se0.25', + 'r2_k5_s22_e6_i24_o40_se0.25', 'r3_k3_s22_e6_i40_o80_se0.25', + 'r3_k5_s11_e6_i80_o112_se0.25', 'r4_k5_s22_e6_i112_o192_se0.25', + 'r1_k3_s11_e6_i192_o320_se0.25', +] + + +def efficientnet_lite(width_coefficient=None, + depth_coefficient=None, + dropout_rate=0.2, + survival_prob=0.8): + """Creates a efficientnet model.""" + global_params = efficientnet_model.GlobalParams( + blocks_args=_DEFAULT_BLOCKS_ARGS, + batch_norm_momentum=0.99, + batch_norm_epsilon=1e-3, + dropout_rate=dropout_rate, + survival_prob=survival_prob, + data_format='channels_last', + num_classes=1000, + width_coefficient=width_coefficient, + depth_coefficient=depth_coefficient, + depth_divisor=8, + min_depth=None, + relu_fn=tf.nn.relu6, # Relu6 is for easier quantization. + # The default is TPU-specific batch norm. + # The alternative is tf.layers.BatchNormalization. + batch_norm=utils.TpuBatchNormalization, # TPU-specific requirement. + clip_projection_output=False, + fix_head_stem=True, # Don't scale stem and head. + local_pooling=True, # special cases for tflite issues. + use_se=False) # SE is not well supported on many lite devices. + return global_params + + +def get_model_params(model_name, override_params): + """Get the block args and global params for a given model.""" + if model_name.startswith('efficientnet-lite'): + width_coefficient, depth_coefficient, _, dropout_rate = ( + efficientnet_lite_params(model_name)) + global_params = efficientnet_lite( + width_coefficient, depth_coefficient, dropout_rate) + else: + raise NotImplementedError( + 'model name is not pre-defined: %s' % model_name) + + if override_params: + # ValueError will be raised here if override_params has fields not included + # in global_params. + global_params = global_params._replace(**override_params) + + decoder = efficientnet_builder.BlockDecoder() + blocks_args = decoder.decode(global_params.blocks_args) + + logging.info('global_params= %s', global_params) + return blocks_args, global_params + + +def build_model(images, + model_name, + training, + override_params=None, + model_dir=None, + fine_tuning=False, + features_only=False, + pooled_features_only=False): + """A helper function to create a model and return predicted logits. + + Args: + images: input images tensor. + model_name: string, the predefined model name. + training: boolean, whether the model is constructed for training. + override_params: A dictionary of params for overriding. Fields must exist in + efficientnet_model.GlobalParams. + model_dir: string, optional model dir for saving configs. + fine_tuning: boolean, whether the model is used for finetuning. + features_only: build the base feature network only (excluding final + 1x1 conv layer, global pooling, dropout and fc head). + pooled_features_only: build the base network for features extraction (after + 1x1 conv layer and global pooling, but before dropout and fc head). + + Returns: + logits: the logits tensor of classes. + endpoints: the endpoints for each layer. + + Raises: + When model_name specified an undefined model, raises NotImplementedError. + When override_params has invalid fields, raises ValueError. + """ + assert isinstance(images, tf.Tensor) + assert not (features_only and pooled_features_only) + + # For backward compatibility. + if override_params and override_params.get('drop_connect_rate', None): + override_params['survival_prob'] = 1 - \ + override_params['drop_connect_rate'] + + if not training or fine_tuning: + if not override_params: + override_params = {} + override_params['batch_norm'] = utils.BatchNormalization + blocks_args, global_params = get_model_params(model_name, override_params) + + if model_dir: + param_file = os.path.join(model_dir, 'model_params.txt') + if not tf.gfile.Exists(param_file): + if not tf.gfile.Exists(model_dir): + tf.gfile.MakeDirs(model_dir) + with tf.gfile.GFile(param_file, 'w') as f: + logging.info('writing to %s', param_file) + f.write('model_name= %s\n\n' % model_name) + f.write('global_params= %s\n\n' % str(global_params)) + f.write('blocks_args= %s\n\n' % str(blocks_args)) + + with tf.variable_scope(model_name): + model = efficientnet_model.Model(blocks_args, global_params) + outputs = model( + images, + training=training, + features_only=features_only, + pooled_features_only=pooled_features_only) + if features_only: + outputs = tf.identity(outputs, 'features') + elif pooled_features_only: + outputs = tf.identity(outputs, 'pooled_features') + else: + outputs = tf.identity(outputs, 'logits') + return outputs, model.endpoints + + +def build_model_base(images, model_name, training, override_params=None): + """Create a base feature network and return the features before pooling. + + Args: + images: input images tensor. + model_name: string, the predefined model name. + training: boolean, whether the model is constructed for training. + override_params: A dictionary of params for overriding. Fields must exist in + efficientnet_model.GlobalParams. + + Returns: + features: base features before pooling. + endpoints: the endpoints for each layer. + + Raises: + When model_name specified an undefined model, raises NotImplementedError. + When override_params has invalid fields, raises ValueError. + """ + assert isinstance(images, tf.Tensor) + # For backward compatibility. + if override_params and override_params.get('drop_connect_rate', None): + override_params['survival_prob'] = 1 - \ + override_params['drop_connect_rate'] + + blocks_args, global_params = get_model_params(model_name, override_params) + + with tf.variable_scope(model_name): + model = efficientnet_model.Model(blocks_args, global_params) + features = model(images, training=training, features_only=True) + + features = tf.identity(features, 'features') + return features, model.endpoints diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/lite/efficientnet_lite_builder_test.py b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/lite/efficientnet_lite_builder_test.py new file mode 100644 index 0000000000000000000000000000000000000000..f9416c7862d4fda817fe6116b60f8e0e56a7ec93 --- /dev/null +++ b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/lite/efficientnet_lite_builder_test.py @@ -0,0 +1,84 @@ +# Copyright 2020 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Tests for efficientnet_lite_builder.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import numpy as np +import tensorflow.compat.v1 as tf + +from lite import efficientnet_lite_builder + + +class EfficientnetBuilderTest(tf.test.TestCase): + + def _test_model_params(self, + model_name, + input_size, + expected_params, + override_params=None, + features_only=False, + pooled_features_only=False): + images = tf.zeros((1, input_size, input_size, 3), dtype=tf.float32) + efficientnet_lite_builder.build_model( + images, + model_name=model_name, + override_params=override_params, + training=True, + features_only=features_only, + pooled_features_only=pooled_features_only) + num_params = np.sum([np.prod(v.shape) + for v in tf.trainable_variables()]) + + self.assertEqual(num_params, expected_params) + + def test_efficientnet_b0(self): + self._test_model_params( + 'efficientnet-lite0', 224, expected_params=4652008) + + def test_efficientnet_b1(self): + self._test_model_params( + 'efficientnet-lite1', 240, expected_params=5416680) + + def test_efficientnet_b2(self): + self._test_model_params( + 'efficientnet-lite2', 260, expected_params=6092072) + + def test_efficientnet_b3(self): + self._test_model_params( + 'efficientnet-lite3', 280, expected_params=8197096) + + def test_efficientnet_b4(self): + self._test_model_params( + 'efficientnet-lite4', 300, expected_params=13006568) + + +if __name__ == '__main__': + tf.test.main() diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/main.py b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/main.py new file mode 100644 index 0000000000000000000000000000000000000000..ada95db1627a737617697c686fc11f4b8a2e67f1 --- /dev/null +++ b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/main.py @@ -0,0 +1,948 @@ +# Copyright 2019 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Train a EfficientNets on ImageNet on TPU.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import os +import time +import argparse +from absl import app +from absl import flags +from absl import logging +import numpy as np +import tensorflow.compat.v1 as tf +import tensorflow.compat.v2 as tf2 # used for summaries only. + +import imagenet_input +import model_builder_factory +import utils +# pylint: disable=g-direct-tensorflow-import +from tensorflow.core.protobuf import rewriter_config_pb2 +from tensorflow.python.estimator import estimator +from npu_bridge.npu_init import * +from npu_bridge.estimator.npu.npu_config import NPURunConfig +from npu_bridge.estimator import npu_ops +from npu_bridge.estimator.npu.npu_estimator import NPUEstimator, NPUEstimatorSpec + +# pylint: enable=g-direct-tensorflow-import + + +FLAGS = flags.FLAGS + +# Required parameters +flags.DEFINE_string( + 'data_dir', default=None, + help='The directory where the ImageNet input data is stored.' + 'Please see the README.md for the expected data format.') + +flags.DEFINE_string( + 'model_dir', default=None, + help='The directory where the model and training/evaluation summaries are stored.') + +flags.DEFINE_string( + 'dump_dir', default="/cache/dump_dir", + help='The directory where the dump data are stored.') + +flags.DEFINE_string( + 'profiling_dir', default="/cache/profiling_dir", + help='The directory where the profiling data are stored.' + 'You need create it first and have the permissions of read and write.') + +flags.DEFINE_string("obs_dir", None, "obs dir") + +flags.DEFINE_string( + 'model_name', + default='efficientnet-condconv-b0-8e', + help='The model name among existing configurations.') + +flags.DEFINE_integer( + 'batch_size', default=128, help='Batch size for me.') + + +# The following params only useful on NPU chip mode +flags.DEFINE_boolean("npu_dump_data", False, "dump data for precision or not") +flags.DEFINE_boolean("npu_dump_graph", False, "dump graph or not") +flags.DEFINE_boolean("npu_profiling", False, + "profiling for performance or not") +flags.DEFINE_boolean("npu_auto_tune", False, + "auto tune or not. And you must set tune_bank_path param.") + + +FAKE_DATA_DIR = 'gs://cloud-tpu-test-datasets/fake_imagenet' + +flags.DEFINE_bool( + 'use_tpu', default=False, + help=('Use TPU to execute the model for training and evaluation. If' + ' --use_tpu=false, will use whatever devices are available to' + ' TensorFlow by default (e.g. CPU and GPU)')) + +flags.DEFINE_string('tpu_job_name', None, help=('Name of worker binary.')) + +# Cloud TPU Cluster Resolvers +flags.DEFINE_string( + 'tpu', default=None, + help='The Cloud TPU to use for training. This should be either the name ' + 'used when creating the Cloud TPU, or a grpc://ip.address.of.tpu:8470 url.') + +flags.DEFINE_string( + 'gcp_project', default=None, + help='Project name for the Cloud TPU-enabled project. If not specified, we ' + 'will attempt to automatically detect the GCE project from metadata.') + +flags.DEFINE_string( + 'tpu_zone', default=None, + help='GCE zone where the Cloud TPU is located in. If not specified, we ' + 'will attempt to automatically detect the GCE project from metadata.') + +# Model specific flags + +flags.DEFINE_integer( + 'holdout_shards', + default=None, + help=('Number of holdout shards for validation. Recommended 20.')) + +flags.DEFINE_string('eval_name', default=None, help=('Evaluation name.')) + +flags.DEFINE_bool( + 'archive_ckpt', default=True, help=('If true, archive the best ckpt.')) + +flags.DEFINE_string( + 'mode', default='train_and_eval', + help='One of {"train_and_eval", "train", "eval"}.') + +flags.DEFINE_string( + 'augment_name', default=None, + help='`string` that is the name of the augmentation method' + 'to apply to the image. `autoaugment` if AutoAugment is to be used or' + '`randaugment` if RandAugment is to be used. If the value is `None` no' + 'augmentation method will be applied applied. See autoaugment.py for ' + 'more details.') + + +flags.DEFINE_integer( + 'randaug_num_layers', default=2, + help='If RandAug is used, what should the number of layers be.' + 'See autoaugment.py for detailed description.') + +flags.DEFINE_integer( + 'randaug_magnitude', default=10, + help='If RandAug is used, what should the magnitude be. ' + 'See autoaugment.py for detailed description.') + + +flags.DEFINE_integer( + 'train_steps', default=250000, + help=('The number of steps to use for training. Default is 218949 steps' + ' which is approximately 350 epochs at batch size 96. This flag' + ' should be adjusted according to the --train_batch_size flag.')) + +flags.DEFINE_integer( + 'input_image_size', default=None, + help='Input image size: it depends on specific model name.') + +flags.DEFINE_integer( + 'train_batch_size', default=128, help='Batch size for training.') + +flags.DEFINE_integer( + 'eval_batch_size', default=8, help='Batch size for evaluation.') + +flags.DEFINE_integer( + 'batch_norm_batch_size', + default=8, + help='Per-group batch size for distributed batch normalization.') + +flags.DEFINE_integer( + 'num_train_images', default=1281167, help='Size of training data set.') + +flags.DEFINE_integer( + 'num_eval_images', default=50000, help='Size of evaluation data set.') + +flags.DEFINE_integer( + 'steps_per_eval', default=6255, + help=('Controls how often evaluation is performed. Since evaluation is' + ' fairly expensive, it is advised to evaluate as infrequently as' + ' possible (i.e. up to --train_steps, which evaluates the model only' + ' after finishing the entire training regime).')) + +flags.DEFINE_integer( + 'eval_timeout', + default=None, + help='Maximum seconds between checkpoints before evaluation terminates.') + +flags.DEFINE_bool( + 'skip_host_call', default=False, + help=('Skip the host_call which is executed every training step. This is' + ' generally used for generating training summaries (train loss,' + ' learning rate, etc...). When --skip_host_call=false, there could' + ' be a performance drop if host_call function is slow and cannot' + ' keep up with the TPU-side computation.')) + +flags.DEFINE_integer( + 'iterations_per_loop', default=1251, + help=('Number of steps to run on TPU before outfeeding metrics to the CPU.' + ' If the number of iterations in the loop would exceed the number of' + ' train steps, the loop will exit before reaching' + ' --iterations_per_loop. The larger this value is, the higher the' + ' utilization on the TPU.')) + +flags.DEFINE_integer( + 'num_parallel_calls', default=64, + help=('Number of parallel threads in CPU for the input pipeline')) + +flags.DEFINE_string( + 'bigtable_project', None, + 'The Cloud Bigtable project. If None, --gcp_project will be used.') +flags.DEFINE_string( + 'bigtable_instance', None, + 'The Cloud Bigtable instance to load data from.') +flags.DEFINE_string( + 'bigtable_table', 'imagenet', + 'The Cloud Bigtable table to load data from.') +flags.DEFINE_string( + 'bigtable_train_prefix', 'train_', + 'The prefix identifying training rows.') +flags.DEFINE_string( + 'bigtable_eval_prefix', 'validation_', + 'The prefix identifying evaluation rows.') +flags.DEFINE_string( + 'bigtable_column_family', 'tfexample', + 'The column family storing TFExamples.') +flags.DEFINE_string( + 'bigtable_column_qualifier', 'example', + 'The column name storing TFExamples.') + +flags.DEFINE_string( + 'data_format', default='channels_last', + help=('A flag to override the data format used in the model. The value' + ' is either channels_first or channels_last. To run the network on' + ' CPU or TPU, channels_last should be used. For GPU, channels_first' + ' will improve performance.')) +flags.DEFINE_integer( + 'num_label_classes', default=1000, help='Number of classes, at least 2') + +flags.DEFINE_float( + 'batch_norm_momentum', + default=None, + help=('Batch normalization layer momentum of moving average to override.')) +flags.DEFINE_float( + 'batch_norm_epsilon', + default=None, + help=('Batch normalization layer epsilon to override..')) + +flags.DEFINE_bool( + 'transpose_input', default=True, + help='Use TPU double transpose optimization') + +flags.DEFINE_bool( + 'use_bfloat16', + default=False, + help=('Whether to use bfloat16 as activation for training.')) + +flags.DEFINE_string( + 'export_dir', + default=None, + help=('The directory where the exported SavedModel will be stored.')) +flags.DEFINE_bool( + 'export_to_tpu', default=False, + help=('Whether to export additional metagraph with "serve, tpu" tags' + ' in addition to "serve" only metagraph.')) + +flags.DEFINE_float( + 'base_learning_rate', + default=0.016, + help=('Base learning rate when train batch size is 256.')) + +flags.DEFINE_float('lr_decay_epoch', default=2.4, help='LR decay epoch.') + +flags.DEFINE_float( + 'moving_average_decay', default=0.9999, + help=('Moving average decay rate.')) + +flags.DEFINE_float( + 'weight_decay', default=1e-5, + help=('Weight decay coefficiant for l2 regularization.')) + +flags.DEFINE_float( + 'label_smoothing', default=0.1, + help=('Label smoothing parameter used in the softmax_cross_entropy')) + +flags.DEFINE_float( + 'dropout_rate', default=None, + help=('Dropout rate for the final output layer.')) + +flags.DEFINE_float( + 'survival_prob', default=None, + help=('Drop connect rate for the network.')) + +flags.DEFINE_float( + 'mixup_alpha', + default=0.0, + help=('Alpha parameter for mixup regularization, 0.0 to disable.')) + +flags.DEFINE_integer('log_step_count_steps', 64, 'The number of steps at ' + 'which the global step information is logged.') + +flags.DEFINE_bool( + 'use_cache', default=False, help=('Enable cache for training input.')) + +flags.DEFINE_float( + 'depth_coefficient', default=None, + help=('Depth coefficient for scaling number of layers.')) + +flags.DEFINE_float( + 'width_coefficient', default=None, + help=('Width coefficient for scaling channel size.')) + +flags.DEFINE_bool( + 'use_async_checkpointing', default=True, help=('Enable async checkpoint')) + +flags.DEFINE_string( + 'optimizer', + default='rmsprop', + help='The optimizer to use. Can be either rmsprop, sgd, momentum, or lars.') + +flags.DEFINE_string( + 'lr_schedule', default='exponential', help=('learning rate schedule')) + +flags.DEFINE_float( + 'lr_decay_factor', default=0.97, help=('Learning rate decay factor.')) + +flags.DEFINE_float( + 'lr_warmup_epochs', default=5, help=('warmup epochs for learning rate')) + +flags.DEFINE_float( + 'lars_weight_decay', + default=0.00001, + help=('Weight decay for LARS optimizer.')) + +flags.DEFINE_float( + 'lars_epsilon', default=0.0, help=('Epsilon for LARS optimizer.')) + +flags.DEFINE_integer( + 'num_replicas', default=32, help=('Number of TPU replicas.')) + + +def model_fn(features, labels, mode, params): + """The model_fn to be used with TPUEstimator. + + Args: + features: `Tensor` of batched images. + labels: `Tensor` of one hot labels for the data samples + mode: one of `tf.estimator.ModeKeys.{TRAIN,EVAL,PREDICT}` + params: `dict` of parameters passed to the model from the TPUEstimator, + `params['batch_size']` is always provided and should be used as the + effective batch size. + + Returns: + A `(TPU)EstimatorSpec` for the model + """ + if isinstance(features, dict): + features = features['feature'] + + # In most cases, the default data format NCHW instead of NHWC should be + # used for a significant performance boost on GPU. NHWC should be used + # only if the network needs to be run on CPU since the pooling operations + # are only supported on NHWC. TPU uses XLA compiler to figure out best layout. + if FLAGS.data_format == 'channels_first': + assert not FLAGS.transpose_input # channels_first only for GPU + features = tf.transpose(features, [0, 3, 1, 2]) + stats_shape = [3, 1, 1] + else: + stats_shape = [1, 1, 3] + + input_image_size = FLAGS.input_image_size + if not input_image_size: + input_image_size = model_builder_factory.get_model_input_size( + FLAGS.model_name) + + if FLAGS.transpose_input and mode != tf.estimator.ModeKeys.PREDICT: + features = tf.reshape(features, + [input_image_size, input_image_size, 3, -1]) + features = tf.transpose(features, [3, 0, 1, 2]) # HWCN to NHWC + + is_training = (mode == tf.estimator.ModeKeys.TRAIN) + has_moving_average_decay = (FLAGS.moving_average_decay > 0) + # This is essential, if using a keras-derived model. + tf.keras.backend.set_learning_phase(is_training) + logging.info('Using open-source implementation.') + override_params = {} + if FLAGS.batch_norm_momentum is not None: + override_params['batch_norm_momentum'] = FLAGS.batch_norm_momentum + if FLAGS.batch_norm_epsilon is not None: + override_params['batch_norm_epsilon'] = FLAGS.batch_norm_epsilon + if FLAGS.dropout_rate is not None: + override_params['dropout_rate'] = FLAGS.dropout_rate + if FLAGS.survival_prob is not None: + override_params['survival_prob'] = FLAGS.survival_prob + if FLAGS.data_format: + override_params['data_format'] = FLAGS.data_format + if FLAGS.num_label_classes: + override_params['num_classes'] = FLAGS.num_label_classes + if FLAGS.depth_coefficient: + override_params['depth_coefficient'] = FLAGS.depth_coefficient + if FLAGS.width_coefficient: + override_params['width_coefficient'] = FLAGS.width_coefficient + + def normalize_features(features, mean_rgb, stddev_rgb): + """Normalize the image given the means and stddevs.""" + features -= tf.constant(mean_rgb, shape=stats_shape, + dtype=features.dtype) + features /= tf.constant(stddev_rgb, + shape=stats_shape, dtype=features.dtype) + return features + + def build_model(): + """Build model using the model_name given through the command line.""" + model_builder = model_builder_factory.get_model_builder( + FLAGS.model_name) + normalized_features = normalize_features(features, model_builder.MEAN_RGB, + model_builder.STDDEV_RGB) + logits, _ = model_builder.build_model( + normalized_features, + model_name=FLAGS.model_name, + training=is_training, + override_params=override_params, + model_dir=FLAGS.model_dir) + return logits + + if params['use_bfloat16']: + with tf.tpu.bfloat16_scope(): + logits = tf.cast(build_model(), tf.float32) + else: + logits = build_model() + + if mode == tf.estimator.ModeKeys.PREDICT: + predictions = { + 'classes': tf.argmax(logits, axis=1), + 'probabilities': tf.nn.softmax(logits, name='softmax_tensor') + } + return NPUEstimatorSpec( + mode=mode, + predictions=predictions, + export_outputs={ + 'classify': tf.estimator.export.PredictOutput(predictions) + }) + + # If necessary, in the model_fn, use params['batch_size'] instead the batch + # size flags (--train_batch_size or --eval_batch_size). + batch_size = params['batch_size'] # pylint: disable=unused-variable + + # Calculate loss, which includes softmax cross entropy and L2 regularization. + cross_entropy = tf.losses.softmax_cross_entropy( + logits=logits, + onehot_labels=labels, + label_smoothing=FLAGS.label_smoothing) + + # Add weight decay to the loss for non-batch-normalization variables. + loss = cross_entropy + FLAGS.weight_decay * tf.add_n( + [tf.nn.l2_loss(v) for v in tf.trainable_variables() + if 'batch_normalization' not in v.name]) + + global_step = tf.train.get_global_step() + if has_moving_average_decay: + ema = tf.train.ExponentialMovingAverage( + decay=FLAGS.moving_average_decay, num_updates=global_step) + ema_vars = utils.get_ema_vars() + + host_call = None + restore_vars_dict = None + if is_training: + # Compute the current epoch and associated learning rate from global_step. + current_epoch = ( + tf.cast(global_step, tf.float32) / params['steps_per_epoch']) + + scaled_lr = FLAGS.base_learning_rate * (FLAGS.train_batch_size / 256.0) + logging.info('base_learning_rate = %f', FLAGS.base_learning_rate) + learning_rate = utils.build_learning_rate( + scaled_lr, + global_step, + params['steps_per_epoch'], + decay_epochs=FLAGS.lr_decay_epoch, + warmup_epochs=FLAGS.lr_warmup_epochs, + decay_factor=FLAGS.lr_decay_factor, + lr_decay_type=FLAGS.lr_schedule, + total_steps=FLAGS.train_steps) + optimizer = utils.build_optimizer( + learning_rate, + optimizer_name=FLAGS.optimizer, + lars_weight_decay=FLAGS.lars_weight_decay, + lars_epsilon=FLAGS.lars_epsilon) + if FLAGS.use_tpu: + # When using TPU, wrap the optimizer with CrossShardOptimizer which + # handles synchronization details between different TPU cores. To the + # user, this should look like regular synchronous training. + optimizer = tf.tpu.CrossShardOptimizer(optimizer) + + # Batch normalization requires UPDATE_OPS to be added as a dependency to + # the train operation. + update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS) + with tf.control_dependencies(update_ops): + train_op = optimizer.minimize(loss, global_step) + + if has_moving_average_decay: + with tf.control_dependencies([train_op]): + train_op = ema.apply(ema_vars) + + if not FLAGS.skip_host_call: + def host_call_fn(gs, lr, ce): + """Training host call. Creates scalar summaries for training metrics. + + This function is executed on the CPU and should not directly reference + any Tensors in the rest of the `model_fn`. To pass Tensors from the + model to the `metric_fn`, provide as part of the `host_call`. See + https://www.tensorflow.org/api_docs/python/tf/estimator/tpu/TPUEstimatorSpec + for more information. + + Arguments should match the list of `Tensor` objects passed as the second + element in the tuple passed to `host_call`. + + Args: + gs: `Tensor with shape `[batch]` for the global_step + lr: `Tensor` with shape `[batch]` for the learning_rate. + ce: `Tensor` with shape `[batch]` for the current_epoch. + + Returns: + List of summary ops to run on the CPU host. + """ + gs = gs[0] + # Host call fns are executed FLAGS.iterations_per_loop times after one + # TPU loop is finished, setting max_queue value to the same as number of + # iterations will make the summary writer only flush the data to storage + # once per loop. + with tf2.summary.create_file_writer( + FLAGS.model_dir, max_queue=FLAGS.iterations_per_loop).as_default(): + with tf2.summary.record_if(True): + tf2.summary.scalar('learning_rate', lr[0], step=gs) + tf2.summary.scalar('current_epoch', ce[0], step=gs) + + return tf.summary.all_v2_summary_ops() + + # To log the loss, current learning rate, and epoch for Tensorboard, the + # summary op needs to be run on the host CPU via host_call. host_call + # expects [batch_size, ...] Tensors, thus reshape to introduce a batch + # dimension. These Tensors are implicitly concatenated to + # [params['batch_size']]. + gs_t = tf.reshape(global_step, [1]) + lr_t = tf.reshape(learning_rate, [1]) + ce_t = tf.reshape(current_epoch, [1]) + + host_call = (host_call_fn, [gs_t, lr_t, ce_t]) + + else: + train_op = None + if has_moving_average_decay: + # Load moving average variables for eval. + restore_vars_dict = ema.variables_to_restore(ema_vars) + + eval_metrics = None + if mode == tf.estimator.ModeKeys.EVAL: + def metric_fn(labels, logits): + """Evaluation metric function. Evaluates accuracy. + + This function is executed on the CPU and should not directly reference + any Tensors in the rest of the `model_fn`. To pass Tensors from the model + to the `metric_fn`, provide as part of the `eval_metrics`. See + https://www.tensorflow.org/api_docs/python/tf/estimator/tpu/TPUEstimatorSpec + for more information. + + Arguments should match the list of `Tensor` objects passed as the second + element in the tuple passed to `eval_metrics`. + + Args: + labels: `Tensor` with shape `[batch, num_classes]`. + logits: `Tensor` with shape `[batch, num_classes]`. + + Returns: + A dict of the metrics to return from evaluation. + """ + labels = tf.argmax(labels, axis=1) + predictions = tf.argmax(logits, axis=1) + top_1_accuracy = tf.metrics.accuracy(labels, predictions) + in_top_5 = tf.cast(tf.nn.in_top_k(logits, labels, 5), tf.float32) + top_5_accuracy = tf.metrics.mean(in_top_5) + + return { + 'top_1_accuracy': top_1_accuracy, + 'top_5_accuracy': top_5_accuracy, + } + + #eval_metrics = (metric_fn, [labels, logits]) + eval_metrics = metric_fn(labels, logits) + + num_params = np.sum([np.prod(v.shape) for v in tf.trainable_variables()]) + logging.info('number of trainable parameters: %d', num_params) + + saver = tf.train.Saver(restore_vars_dict) + + return NPUEstimatorSpec( + mode=mode, + loss=loss, + train_op=train_op, + eval_metric_ops=eval_metrics, + scaffold=tf.train.Scaffold(saver=saver)) + + +def _verify_non_empty_string(value, field_name): + """Ensures that a given proposed field value is a non-empty string. + + Args: + value: proposed value for the field. + field_name: string name of the field, e.g. `project`. + + Returns: + The given value, provided that it passed the checks. + + Raises: + ValueError: the value is not a string, or is a blank string. + """ + if not isinstance(value, str): + raise ValueError( + 'Bigtable parameter "%s" must be a string.' % field_name) + if not value: + raise ValueError( + 'Bigtable parameter "%s" must be non-empty.' % field_name) + return value + + +def _select_tables_from_flags(): + """Construct training and evaluation Bigtable selections from flags. + + Returns: + [training_selection, evaluation_selection] + """ + project = _verify_non_empty_string( + FLAGS.bigtable_project or FLAGS.gcp_project, + 'project') + instance = _verify_non_empty_string(FLAGS.bigtable_instance, 'instance') + table = _verify_non_empty_string(FLAGS.bigtable_table, 'table') + train_prefix = _verify_non_empty_string(FLAGS.bigtable_train_prefix, + 'train_prefix') + eval_prefix = _verify_non_empty_string(FLAGS.bigtable_eval_prefix, + 'eval_prefix') + column_family = _verify_non_empty_string(FLAGS.bigtable_column_family, + 'column_family') + column_qualifier = _verify_non_empty_string(FLAGS.bigtable_column_qualifier, + 'column_qualifier') + return [ + imagenet_input.BigtableSelection( # pylint: disable=g-complex-comprehension + project=project, + instance=instance, + table=table, + prefix=p, + column_family=column_family, + column_qualifier=column_qualifier) + for p in (train_prefix, eval_prefix) + ] + + +def export(est, export_dir, input_image_size=None): + """Export graph to SavedModel and TensorFlow Lite. + + Args: + est: estimator instance. + export_dir: string, exporting directory. + input_image_size: int, input image size. + + Raises: + ValueError: the export directory path is not specified. + """ + if not export_dir: + raise ValueError('The export directory path is not specified.') + + if not input_image_size: + input_image_size = FLAGS.input_image_size + is_cond_conv = FLAGS.model_name.startswith('efficientnet-condconv') + # Use fixed batch size for condconv. + batch_size = 1 if is_cond_conv else None + + logging.info('Starting to export model.') + if (FLAGS.model_name.startswith('efficientnet-lite') or + FLAGS.model_name.startswith('efficientnet-edgetpu')): + # lite or edgetpu use binlinear for easier post-quantization. + resize_method = tf.image.ResizeMethod.BILINEAR + else: + resize_method = None + image_serving_input_fn = imagenet_input.build_image_serving_input_fn( + input_image_size, batch_size=batch_size, resize_method=resize_method) + est.export_saved_model( + export_dir_base=export_dir, + serving_input_receiver_fn=image_serving_input_fn) + + +def main(unused_argv): + logging.set_verbosity(logging.INFO) + + print("===>>>dataset:{}".format(FLAGS.data_dir)) + print("===>>>result:{}".format(FLAGS.model_dir)) + print("===>>>train_steps:{}".format(FLAGS.train_steps)) + + input_image_size = FLAGS.input_image_size + if not input_image_size: + input_image_size = model_builder_factory.get_model_input_size( + FLAGS.model_name) + + if FLAGS.holdout_shards: + holdout_images = int(FLAGS.num_train_images * + FLAGS.holdout_shards / 1024.0) + FLAGS.num_train_images -= holdout_images + if FLAGS.eval_name and 'test' in FLAGS.eval_name: + FLAGS.holdout_shards = None # do not use holdout if eval test set. + else: + FLAGS.num_eval_images = holdout_images + + # For imagenet dataset, include background label if number of output classes + # is 1001 + include_background_label = (FLAGS.num_label_classes == 1001) + + if FLAGS.use_async_checkpointing: + save_checkpoints_steps = None + else: + save_checkpoints_steps = max(100, FLAGS.iterations_per_loop) + + from tensorflow.core.protobuf.rewriter_config_pb2 import RewriterConfig + config = tf.ConfigProto() + custom_op = config.graph_options.rewrite_options.custom_optimizers.add() + custom_op.name = "NpuOptimizer" + + # Set the precision_mode + custom_op.parameter_map['precision_mode'].s = tf.compat.as_bytes( + 'allow_mix_precision') + custom_op.parameter_map["use_off_line"].b = True + + # Set the dump path + os.mkdir(FLAGS.dump_dir) + custom_op.parameter_map['dump_path'].s = tf.compat.as_bytes(FLAGS.dump_dir) + # Set dump debug + custom_op.parameter_map['enable_dump_debug'].b = True + custom_op.parameter_map['dump_debug_mode'].s = tf.compat.as_bytes('all') + + """ + # Can not profiling from session.run + os.mkdir("/tmp/profiling") + custom_op.parameter_map["profiling_mode"].b = True + custom_op.parameter_map["profiling_options"].s = tf.compat.as_bytes('{"output":"/tmp/profiling","task_trace":"on"}') + """ + + config.graph_options.rewrite_options.remapping = RewriterConfig.OFF # Must be OFF + config.graph_options.rewrite_options.memory_optimization = RewriterConfig.OFF # Must be OFF + + os.mkdir(FLAGS.profiling_dir) + profiling_options = '{"output":"%s","task_trace":"on"}' % FLAGS.profiling_dir + profiling_config = ProfilingConfig( + enable_profiling=True, profiling_options=profiling_options) + + runconfig = NPURunConfig( + profiling_config=profiling_config, + model_dir=FLAGS.model_dir, + save_checkpoints_steps=save_checkpoints_steps, + log_step_count_steps=FLAGS.log_step_count_steps, + session_config=config) # pylint: disable=line-too-long + + # Initializes model parameters. + params = dict( + steps_per_epoch=FLAGS.num_train_images / FLAGS.train_batch_size, + use_bfloat16=FLAGS.use_bfloat16, + batch_size=FLAGS.batch_size) + est = NPUEstimator( + model_fn=model_fn, + config=runconfig, + model_dir=FLAGS.model_dir, + params=params) + + if (FLAGS.model_name.startswith('efficientnet-lite') or + FLAGS.model_name.startswith('efficientnet-edgetpu')): + # lite or edgetpu use binlinear for easier post-quantization. + resize_method = tf.image.ResizeMethod.BILINEAR + else: + resize_method = None + # Input pipelines are slightly different (with regards to shuffling and + # preprocessing) between training and evaluation. + + def build_imagenet_input(is_training): + """Generate ImageNetInput for training and eval.""" + if FLAGS.bigtable_instance: + logging.info('Using Bigtable dataset, table %s', + FLAGS.bigtable_table) + select_train, select_eval = _select_tables_from_flags() + return imagenet_input.ImageNetBigtableInput( + is_training=is_training, + use_bfloat16=FLAGS.use_bfloat16, + transpose_input=FLAGS.transpose_input, + selection=select_train if is_training else select_eval, + num_label_classes=FLAGS.num_label_classes, + include_background_label=include_background_label, + augment_name=FLAGS.augment_name, + mixup_alpha=FLAGS.mixup_alpha, + randaug_num_layers=FLAGS.randaug_num_layers, + randaug_magnitude=FLAGS.randaug_magnitude, + resize_method=resize_method) + else: + if FLAGS.data_dir == FAKE_DATA_DIR: + logging.info('Using fake dataset.') + else: + logging.info('Using dataset: %s', FLAGS.data_dir) + + return imagenet_input.ImageNetInput( + is_training=is_training, + data_dir=FLAGS.data_dir, + transpose_input=FLAGS.transpose_input, + cache=FLAGS.use_cache and is_training, + image_size=input_image_size, + num_parallel_calls=FLAGS.num_parallel_calls, + use_bfloat16=FLAGS.use_bfloat16, + num_label_classes=FLAGS.num_label_classes, + include_background_label=include_background_label, + augment_name=FLAGS.augment_name, + mixup_alpha=FLAGS.mixup_alpha, + randaug_num_layers=FLAGS.randaug_num_layers, + randaug_magnitude=FLAGS.randaug_magnitude, + resize_method=resize_method, + holdout_shards=FLAGS.holdout_shards) + + imagenet_train = build_imagenet_input(is_training=True) + imagenet_eval = build_imagenet_input(is_training=False) + + if FLAGS.mode == 'eval': + eval_steps = FLAGS.num_eval_images // FLAGS.eval_batch_size + # Run evaluation when there's a new checkpoint + for ckpt in tf.train.checkpoints_iterator( + FLAGS.model_dir, timeout=FLAGS.eval_timeout): + logging.info('Starting to evaluate.') + try: + start_timestamp = time.time() # This time will include compilation time + eval_results = est.evaluate( + input_fn=imagenet_eval.input_fn, + steps=eval_steps, + checkpoint_path=ckpt, + name=FLAGS.eval_name) + elapsed_time = int(time.time() - start_timestamp) + logging.info('Eval results: %s. Elapsed seconds: %d', + eval_results, elapsed_time) + if FLAGS.archive_ckpt: + utils.archive_ckpt( + eval_results, eval_results['top_1_accuracy'], ckpt) + + # Terminate eval job when final checkpoint is reached + try: + current_step = int(os.path.basename(ckpt).split('-')[1]) + except IndexError: + logging.info('%s has no global step info: stop!', ckpt) + break + + if current_step >= FLAGS.train_steps: + logging.info( + 'Evaluation finished after training step %d', current_step) + break + + except tf.errors.NotFoundError: + # Since the coordinator is on a different job than the TPU worker, + # sometimes the TPU worker does not finish initializing until long after + # the CPU job tells it to start evaluating. In this case, the checkpoint + # file could have been deleted already. + logging.info( + 'Checkpoint %s no longer exists, skipping checkpoint', ckpt) + else: # FLAGS.mode == 'train' or FLAGS.mode == 'train_and_eval' + current_step = estimator._load_global_step_from_checkpoint_dir( + FLAGS.model_dir) # pylint: disable=protected-access,line-too-long + + logging.info( + 'Training for %d steps (%.2f epochs in total). Current' + ' step %d.', FLAGS.train_steps, + FLAGS.train_steps / params['steps_per_epoch'], current_step) + + start_timestamp = time.time() # This time will include compilation time + + if FLAGS.mode == 'train': + hooks = [] + if FLAGS.use_async_checkpointing: + try: + from tensorflow.contrib.tpu.python.tpu import async_checkpoint # pylint: disable=g-import-not-at-top + except ImportError as e: + logging.exception( + 'Async checkpointing is not supported in TensorFlow 2.x') + raise e + + hooks.append( + async_checkpoint.AsyncCheckpointSaverHook( + checkpoint_dir=FLAGS.model_dir, + save_steps=max(100, FLAGS.iterations_per_loop))) + est.train( + input_fn=imagenet_train.input_fn, + max_steps=FLAGS.train_steps, + hooks=hooks) + + else: + assert FLAGS.mode == 'train_and_eval' + while current_step < FLAGS.train_steps: + # Train for up to steps_per_eval number of steps. + # At the end of training, a checkpoint will be written to --model_dir. + next_checkpoint = min(current_step + FLAGS.steps_per_eval, + FLAGS.train_steps) + est.train(input_fn=imagenet_train.input_fn, + max_steps=next_checkpoint) + current_step = next_checkpoint + + logging.info('Finished training up to step %d. Elapsed seconds %d.', + next_checkpoint, int(time.time() - start_timestamp)) + + # Evaluate the model on the most recent model in --model_dir. + # Since evaluation happens in batches of --eval_batch_size, some images + # may be excluded modulo the batch size. As long as the batch size is + # consistent, the evaluated images are also consistent. + logging.info('Starting to evaluate.') + eval_results = est.evaluate( + input_fn=imagenet_eval.input_fn, + steps=FLAGS.num_eval_images // FLAGS.eval_batch_size, + name=FLAGS.eval_name) + logging.info('Eval results at step %d: %s', + next_checkpoint, eval_results) + ckpt = tf.train.latest_checkpoint(FLAGS.model_dir) + if FLAGS.archive_ckpt: + utils.archive_ckpt( + eval_results, eval_results['top_1_accuracy'], ckpt) + + elapsed_time = int(time.time() - start_timestamp) + logging.info('Finished training up to step %d. Elapsed seconds %d.', + FLAGS.train_steps, elapsed_time) + if FLAGS.export_dir: + export(est, FLAGS.export_dir, input_image_size) + + from help_modelarts import modelarts_result2obs + modelarts_result2obs(FLAGS) + + +if __name__ == '__main__': + flags.mark_flag_as_required("data_dir") + flags.mark_flag_as_required("model_dir") + flags.mark_flag_as_required("obs_dir") + flags.mark_flag_as_required("model_name") + + app.run(main) diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/model_builder_factory.py b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/model_builder_factory.py new file mode 100644 index 0000000000000000000000000000000000000000..77f9756ea46cd50c8cb998aab363407d69e2ff01 --- /dev/null +++ b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/model_builder_factory.py @@ -0,0 +1,76 @@ +# Copyright 2020 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Utilities for model builder or input size.""" + +import efficientnet_builder +from condconv import efficientnet_condconv_builder +from edgetpu import efficientnet_edgetpu_builder +from lite import efficientnet_lite_builder +from tpu import efficientnet_x_builder + + +def get_model_builder(model_name): + """Get the model_builder module for a given model name.""" + if model_name.startswith('efficientnet-lite'): + return efficientnet_lite_builder + elif model_name.startswith('efficientnet-edgetpu-'): + return efficientnet_edgetpu_builder + elif model_name.startswith('efficientnet-condconv-'): + return efficientnet_condconv_builder + elif model_name.startswith('efficientnet-x-'): + return efficientnet_x_builder + elif model_name.startswith('efficientnet-'): + return efficientnet_builder + else: + raise ValueError( + 'Model must be either efficientnet-b* or efficientnet-edgetpu* or' + 'efficientnet-condconv*, efficientnet-lite*') + + +def get_model_input_size(model_name): + """Get model input size for a given model name.""" + if model_name.startswith('efficientnet-lite'): + _, _, image_size, _ = ( + efficientnet_lite_builder.efficientnet_lite_params(model_name)) + elif model_name.startswith('efficientnet-edgetpu-'): + _, _, image_size, _ = ( + efficientnet_edgetpu_builder.efficientnet_edgetpu_params(model_name)) + elif model_name.startswith('efficientnet-condconv-'): + _, _, image_size, _, _ = ( + efficientnet_condconv_builder.efficientnet_condconv_params(model_name)) + elif model_name.startswith('efficientnet-x'): + _, _, image_size, _, _ = efficientnet_x_builder.efficientnet_x_params( + model_name) + elif model_name.startswith('efficientnet'): + _, _, image_size, _ = efficientnet_builder.efficientnet_params( + model_name) + else: + raise ValueError( + 'Model must be either efficientnet-b* or efficientnet-x-b* or efficientnet-edgetpu* or ' + 'efficientnet-condconv*, efficientnet-lite*') + return image_size diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/modelzoo_level.txt b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/modelzoo_level.txt new file mode 100644 index 0000000000000000000000000000000000000000..83f8226cf34b739ad69eb22437e37c3279262d04 --- /dev/null +++ b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/modelzoo_level.txt @@ -0,0 +1,7 @@ +GPUStatus:OK +NPUMigrationStatus:OK + +FuncStatus:OK +PrecisionStatus:OK +AutoTune:OK +PerfStatus:OK \ No newline at end of file diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/preprocessing.py b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/preprocessing.py new file mode 100644 index 0000000000000000000000000000000000000000..3c3dc62b1d13dd5d036102d688f2dd84503f35eb --- /dev/null +++ b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/preprocessing.py @@ -0,0 +1,277 @@ +# Copyright 2019 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""ImageNet preprocessing.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from absl import logging + +import tensorflow.compat.v1 as tf + + +IMAGE_SIZE = 224 +CROP_PADDING = 32 + + +def distorted_bounding_box_crop(image_bytes, + bbox, + min_object_covered=0.1, + aspect_ratio_range=(0.75, 1.33), + area_range=(0.05, 1.0), + max_attempts=100, + scope=None): + """Generates cropped_image using one of the bboxes randomly distorted. + + See `tf.image.sample_distorted_bounding_box` for more documentation. + + Args: + image_bytes: `Tensor` of binary image data. + bbox: `Tensor` of bounding boxes arranged `[1, num_boxes, coords]` + where each coordinate is [0, 1) and the coordinates are arranged + as `[ymin, xmin, ymax, xmax]`. If num_boxes is 0 then use the whole + image. + min_object_covered: An optional `float`. Defaults to `0.1`. The cropped + area of the image must contain at least this fraction of any bounding + box supplied. + aspect_ratio_range: An optional list of `float`s. The cropped area of the + image must have an aspect ratio = width / height within this range. + area_range: An optional list of `float`s. The cropped area of the image + must contain a fraction of the supplied image within in this range. + max_attempts: An optional `int`. Number of attempts at generating a cropped + region of the image of the specified constraints. After `max_attempts` + failures, return the entire image. + scope: Optional `str` for name scope. + Returns: + cropped image `Tensor` + """ + with tf.name_scope(scope, 'distorted_bounding_box_crop', [image_bytes, bbox]): + shape = tf.image.extract_jpeg_shape(image_bytes) + sample_distorted_bounding_box = tf.image.sample_distorted_bounding_box( + shape, + bounding_boxes=bbox, + min_object_covered=min_object_covered, + aspect_ratio_range=aspect_ratio_range, + area_range=area_range, + max_attempts=max_attempts, + use_image_if_no_bounding_boxes=True) + bbox_begin, bbox_size, _ = sample_distorted_bounding_box + + # Crop the image to the specified bounding box. + offset_y, offset_x, _ = tf.unstack(bbox_begin) + target_height, target_width, _ = tf.unstack(bbox_size) + crop_window = tf.stack( + [offset_y, offset_x, target_height, target_width]) + image = tf.image.decode_and_crop_jpeg( + image_bytes, crop_window, channels=3) + + return image + + +def _at_least_x_are_equal(a, b, x): + """At least `x` of `a` and `b` `Tensors` are equal.""" + match = tf.equal(a, b) + match = tf.cast(match, tf.int32) + return tf.greater_equal(tf.reduce_sum(match), x) + + +def _resize_image(image, image_size, method=None): + if method is not None: + tf.logging.info('Use customized resize method {}'.format(method)) + return tf.image.resize([image], [image_size, image_size], method)[0] + tf.logging.info('Use default resize_bicubic.') + return tf.image.resize_bicubic([image], [image_size, image_size])[0] + + +def _decode_and_random_crop(image_bytes, image_size, resize_method=None): + """Make a random crop of image_size.""" + bbox = tf.constant([0.0, 0.0, 1.0, 1.0], dtype=tf.float32, shape=[1, 1, 4]) + image = distorted_bounding_box_crop( + image_bytes, + bbox, + min_object_covered=0.1, + aspect_ratio_range=(3. / 4, 4. / 3.), + area_range=(0.08, 1.0), + max_attempts=10, + scope=None) + original_shape = tf.image.extract_jpeg_shape(image_bytes) + bad = _at_least_x_are_equal(original_shape, tf.shape(image), 3) + + image = tf.cond( + bad, + lambda: _decode_and_center_crop(image_bytes, image_size), + lambda: _resize_image(image, image_size, resize_method)) + + return image + + +def _decode_and_center_crop(image_bytes, image_size, resize_method=None): + """Crops to center of image with padding then scales image_size.""" + shape = tf.image.extract_jpeg_shape(image_bytes) + image_height = shape[0] + image_width = shape[1] + + padded_center_crop_size = tf.cast( + ((image_size / (image_size + CROP_PADDING)) * + tf.cast(tf.minimum(image_height, image_width), tf.float32)), + tf.int32) + + offset_height = ((image_height - padded_center_crop_size) + 1) // 2 + offset_width = ((image_width - padded_center_crop_size) + 1) // 2 + crop_window = tf.stack([offset_height, offset_width, + padded_center_crop_size, padded_center_crop_size]) + image = tf.image.decode_and_crop_jpeg(image_bytes, crop_window, channels=3) + image = _resize_image(image, image_size, resize_method) + return image + + +def _flip(image): + """Random horizontal image flip.""" + image = tf.image.random_flip_left_right(image) + return image + + +def preprocess_for_train(image_bytes, + use_bfloat16, + image_size=IMAGE_SIZE, + augment_name=None, + randaug_num_layers=None, + randaug_magnitude=None, + resize_method=None): + """Preprocesses the given image for evaluation. + + Args: + image_bytes: `Tensor` representing an image binary of arbitrary size. + use_bfloat16: `bool` for whether to use bfloat16. + image_size: image size. + augment_name: `string` that is the name of the augmentation method + to apply to the image. `autoaugment` if AutoAugment is to be used or + `randaugment` if RandAugment is to be used. If the value is `None` no + augmentation method will be applied applied. See autoaugment.py for more + details. + randaug_num_layers: 'int', if RandAug is used, what should the number of + layers be. See autoaugment.py for detailed description. + randaug_magnitude: 'int', if RandAug is used, what should the magnitude + be. See autoaugment.py for detailed description. + resize_method: resize method. If none, use bicubic. + + Returns: + A preprocessed image `Tensor`. + """ + image = _decode_and_random_crop(image_bytes, image_size, resize_method) + image = _flip(image) + image = tf.reshape(image, [image_size, image_size, 3]) + + if augment_name: + try: + import autoaugment # pylint: disable=g-import-not-at-top + except ImportError as e: + logging.exception('Autoaugment is not supported in TF 2.x.') + raise e + + logging.info('Apply AutoAugment policy %s', augment_name) + input_image_type = image.dtype + image = tf.clip_by_value(image, 0.0, 255.0) + image = tf.cast(image, dtype=tf.uint8) + + if augment_name == 'autoaugment': + logging.info('Apply AutoAugment policy %s', augment_name) + image = autoaugment.distort_image_with_autoaugment(image, 'v0') + elif augment_name == 'randaugment': + image = autoaugment.distort_image_with_randaugment( + image, randaug_num_layers, randaug_magnitude) + else: + raise ValueError( + 'Invalid value for augment_name: %s' % (augment_name)) + + image = tf.cast(image, dtype=input_image_type) + + image = tf.image.convert_image_dtype( + image, dtype=tf.bfloat16 if use_bfloat16 else tf.float32) + + return image + + +def preprocess_for_eval(image_bytes, + use_bfloat16, + image_size=IMAGE_SIZE, + resize_method=None): + """Preprocesses the given image for evaluation. + + Args: + image_bytes: `Tensor` representing an image binary of arbitrary size. + use_bfloat16: `bool` for whether to use bfloat16. + image_size: image size. + resize_method: if None, use bicubic. + + Returns: + A preprocessed image `Tensor`. + """ + image = _decode_and_center_crop(image_bytes, image_size, resize_method) + image = tf.reshape(image, [image_size, image_size, 3]) + image = tf.image.convert_image_dtype( + image, dtype=tf.bfloat16 if use_bfloat16 else tf.float32) + return image + + +def preprocess_image(image_bytes, + is_training=False, + use_bfloat16=False, + image_size=IMAGE_SIZE, + augment_name=None, + randaug_num_layers=None, + randaug_magnitude=None, + resize_method=None): + """Preprocesses the given image. + + Args: + image_bytes: `Tensor` representing an image binary of arbitrary size. + is_training: `bool` for whether the preprocessing is for training. + use_bfloat16: `bool` for whether to use bfloat16. + image_size: image size. + augment_name: `string` that is the name of the augmentation method + to apply to the image. `autoaugment` if AutoAugment is to be used or + `randaugment` if RandAugment is to be used. If the value is `None` no + augmentation method will be applied applied. See autoaugment.py for more + details. + randaug_num_layers: 'int', if RandAug is used, what should the number of + layers be. See autoaugment.py for detailed description. + randaug_magnitude: 'int', if RandAug is used, what should the magnitude + be. See autoaugment.py for detailed description. + resize_method: 'string' or None. Use resize_bicubic in default. + + Returns: + A preprocessed image `Tensor` with value range of [0, 255]. + """ + if is_training: + return preprocess_for_train( + image_bytes, use_bfloat16, image_size, augment_name, + randaug_num_layers, randaug_magnitude, resize_method) + else: + return preprocess_for_eval(image_bytes, use_bfloat16, image_size, + resize_method) diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/requirements.txt b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/run_1p.sh b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/run_1p.sh new file mode 100644 index 0000000000000000000000000000000000000000..4232be514af98a137201b9b8a78d8ac9b6601935 --- /dev/null +++ b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/run_1p.sh @@ -0,0 +1,22 @@ +#!/bin/bash +### Do not need to Configure CANN Environment on Modelarts Platform, because it has been set already. +### Modelarts Platform command for train +export TF_CPP_MIN_LOG_LEVEL=2 ## Tensorflow api print Log Config +export ASCEND_SLOG_PRINT_TO_STDOUT=0 ## Print log on terminal on(1), off(0) + +code_dir=${1} +data_dir=${2} +result_dir=${3} +obs_url=${4} + +current_time=`date "+%Y-%m-%d-%H-%M-%S"` + +python3.7 ${code_dir}/main.py \ + --data_dir=${data_dir} \ + --model_dir=${result_dir} \ + --obs_dir=${obs_url} \ + --model_name='efficientnet-condconv-b0-8e' \ + --npu_dump_data=True \ + --npu_profiling=True \ + --npu_dump_graph=False \ + --npu_auto_tune=False 2>&1 | tee ${result_dir}/${current_time}_train_npu.log \ No newline at end of file diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/tpu/__init__.py b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/tpu/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..cd928fdd60b83c0a54ca2ffc76bf0604587e66c0 --- /dev/null +++ b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/tpu/__init__.py @@ -0,0 +1,28 @@ +# Copyright 2019 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License +"""The initial file of tpu.""" \ No newline at end of file diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/tpu/efficientnet_x_builder.py b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/tpu/efficientnet_x_builder.py new file mode 100644 index 0000000000000000000000000000000000000000..d21a4b2f81bff32753bb53be2b5a2ee5b61044b7 --- /dev/null +++ b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/tpu/efficientnet_x_builder.py @@ -0,0 +1,233 @@ +# Copyright 2019 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Model Builder for EfficientNet-X.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import functools +import os + +from absl import logging +import tensorflow.compat.v1 as tf + +import efficientnet_builder +import efficientnet_model +import utils + +MEAN_RGB = [0.485 * 255, 0.456 * 255, 0.406 * 255] +STDDEV_RGB = [0.229 * 255, 0.224 * 255, 0.225 * 255] + + +def efficientnet_x_params(model_name): + """Get efficientnet params based on model name.""" + params_dict = { + # (width_coefficient, depth_coefficient, resolution, dropout_rate, + # se_coefficient) + 'efficientnet-x-b0': (1.0, 1.0, 224, 0.2, 4), + 'efficientnet-x-b1': (1.0, 1.1, 240, 0.2, 2), + 'efficientnet-x-b2': (1.1, 1.2, 260, 0.3, 1), + 'efficientnet-x-b3': (1.2, 1.4, 300, 0.3, 1), + 'efficientnet-x-b4': (1.4, 1.8, 380, 0.4, 1), + 'efficientnet-x-b5': (1.6, 2.2, 456, 0.4, 1), + 'efficientnet-x-b6': (1.8, 2.6, 528, 0.5, 1), + 'efficientnet-x-b7': (2.0, 3.1, 600, 0.5, 1), + 'efficientnet-x-tpu-b0': (1.0, 1.0, 224, 0.2, 4), + 'efficientnet-x-tpu-b1': (1.05, 1.09, 229, 0.2, 2), + 'efficientnet-x-tpu-b2': (1.13, 1.29, 244, 0.3, 1), + 'efficientnet-x-tpu-b3': (1.27, 1.62, 263, 0.3, 1), + 'efficientnet-x-tpu-b4': (1.54, 2.38, 299, 0.4, 1), + 'efficientnet-x-tpu-b5': (1.96, 2.76, 332, 0.4, 1), + 'efficientnet-x-tpu-b6': (2.75, 3.01, 328, 0.5, 1), + 'efficientnet-x-tpu-b7': (3.26, 3.44, 350, 0.5, 1), + 'efficientnet-x-gpu-b0': (1.0, 1.0, 224, 0.2, 4), + 'efficientnet-x-gpu-b1': (1.05, 1.09, 229, 0.2, 2), + 'efficientnet-x-gpu-b2': (1.13, 1.24, 237, 0.3, 1), + 'efficientnet-x-gpu-b3': (1.31, 1.63, 255, 0.3, 1), + 'efficientnet-x-gpu-b4': (1.63, 2.4, 282, 0.4, 1), + 'efficientnet-x-gpu-b5': (1.94, 3.29, 306, 0.4, 1), + 'efficientnet-x-gpu-b6': (2.25, 4.28, 328, 0.5, 1), + 'efficientnet-x-gpu-b7': (2.58, 5.46, 350, 0.5, 1), + } + return params_dict[model_name] + + +def efficientnet_x(width_coefficient=None, + depth_coefficient=None, + se_coefficient=None, + dropout_rate=0.2, + survival_prob=0.8): + """Creates a efficientnet model.""" + blocks_args = [ + 'r1_k3_s11_e1_i32_o16_se0.25_d1_a0', + 'r2_k3_s22_e6_i16_o24_se0.25_f1_d2_a1', + 'r2_k5_s22_e6_i24_o40_se0.25_f1_a1', + 'r3_k3_s22_e6_i40_o80_se0.25_a0', + 'r3_k5_s11_e6_i80_o112_se0.25_a0', + 'r4_k5_s22_e6_i112_o192_se0.25_a0', + 'r1_k3_s11_e6_i192_o320_se0.25_a0', + ] + global_params = efficientnet_model.GlobalParams( + batch_norm_momentum=0.99, + batch_norm_epsilon=1e-3, + dropout_rate=dropout_rate, + survival_prob=survival_prob, + data_format='channels_last', + num_classes=1000, + width_coefficient=width_coefficient, + depth_coefficient=depth_coefficient, + depth_divisor=8, + min_depth=None, + relu_fn=tf.nn.relu, + # The default is TPU-specific batch norm. + # The alternative is tf.layers.BatchNormalization. + batch_norm=utils.TpuBatchNormalization, # TPU-specific requirement. + use_se=True, + se_coefficient=se_coefficient) + decoder = efficientnet_builder.BlockDecoder() + return decoder.decode(blocks_args), global_params + + +def get_model_params(model_name, override_params): + """Get the block args and global params for a given model.""" + if model_name.startswith('efficientnet'): + width_coefficient, depth_coefficient, _, dropout_rate, se_coefficient = ( + efficientnet_x_params(model_name)) + blocks_args, global_params = efficientnet_x( + width_coefficient, depth_coefficient, se_coefficient, dropout_rate) + else: + raise NotImplementedError( + 'model name is not pre-defined: %s' % model_name) + + if override_params: + # ValueError will be raised here if override_params has fields not included + # in global_params. + global_params = global_params._replace(**override_params) + + logging.info('global_params= %s', global_params) + logging.info('blocks_args= %s', blocks_args) + return blocks_args, global_params + + +def build_model(images, + model_name, + training, + override_params=None, + model_dir=None, + fine_tuning=False, + features_only=False, + pooled_features_only=False): + """A helper function to creates a model and returns predicted logits. + + Args: + images: input images tensor. + model_name: string, the predefined model name. + training: boolean, whether the model is constructed for training. + override_params: A dictionary of params for overriding. Fields must exist in + efficientnet_model.GlobalParams. + model_dir: string, optional model dir for saving configs. + fine_tuning: boolean, whether the model is used for finetuning. + features_only: build the base feature network only (excluding final + 1x1 conv layer, global pooling, dropout and fc head). + pooled_features_only: build the base network for features extraction (after + 1x1 conv layer and global pooling, but before dropout and fc head). + + Returns: + logits: the logits tensor of classes. + endpoints: the endpoints for each layer. + + Raises: + When model_name specified an undefined model, raises NotImplementedError. + When override_params has invalid fields, raises ValueError. + """ + assert isinstance(images, tf.Tensor) + assert not (features_only and pooled_features_only) + if not training or fine_tuning: + if not override_params: + override_params = {} + override_params['batch_norm'] = utils.BatchNormalization + if fine_tuning: + override_params['relu_fn'] = functools.partial( + efficientnet_builder.swish, use_native=False) + blocks_args, global_params = get_model_params(model_name, override_params) + + if model_dir: + param_file = os.path.join(model_dir, 'model_params.txt') + if not tf.gfile.Exists(param_file): + if not tf.gfile.Exists(model_dir): + tf.gfile.MakeDirs(model_dir) + with tf.gfile.GFile(param_file, 'w') as f: + logging.info('writing to %s', param_file) + f.write('model_name= %s\n\n' % model_name) + f.write('global_params= %s\n\n' % str(global_params)) + f.write('blocks_args= %s\n\n' % str(blocks_args)) + + with tf.variable_scope(model_name): + model = efficientnet_model.Model(blocks_args, global_params) + outputs = model( + images, + training=training, + features_only=features_only, + pooled_features_only=pooled_features_only) + if features_only: + outputs = tf.identity(outputs, 'features') + elif pooled_features_only: + outputs = tf.identity(outputs, 'pooled_features') + else: + outputs = tf.identity(outputs, 'logits') + return outputs, model.endpoints + + +def build_model_base(images, model_name, training, override_params=None): + """Create a base feature network and return the features before pooling. + + Args: + images: input images tensor. + model_name: string, the predefined model name. + training: boolean, whether the model is constructed for training. + override_params: A dictionary of params for overriding. Fields must exist in + efficientnet_model.GlobalParams. + + Returns: + features: base features before pooling. + endpoints: the endpoints for each layer. + + Raises: + When model_name specified an undefined model, raises NotImplementedError. + When override_params has invalid fields, raises ValueError. + """ + assert isinstance(images, tf.Tensor) + blocks_args, global_params = get_model_params(model_name, override_params) + + with tf.variable_scope(model_name): + model = efficientnet_model.Model(blocks_args, global_params) + features = model(images, training=training, features_only=True) + + features = tf.identity(features, 'features') + return features, model.endpoints diff --git a/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/utils.py b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..af65ed3fed77d44e83b2bcecb4ce00846cf31fdd --- /dev/null +++ b/TensorFlow/contrib/cv/Efficientnet-Condconv_ID2074_for_Tensorflow/utils.py @@ -0,0 +1,596 @@ +# Copyright 2019 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Model utilities.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import json +import os +import sys + +from absl import flags +from absl import logging +import numpy as np +import tensorflow.compat.v1 as tf + +import lars_optimizer +from tensorflow.python.tpu import tpu_function # pylint:disable=g-direct-tensorflow-import + +FLAGS = flags.FLAGS + + +def build_learning_rate(initial_lr, + global_step, + steps_per_epoch=None, + lr_decay_type='exponential', + decay_factor=0.97, + decay_epochs=2.4, + total_steps=None, + warmup_epochs=5): + """Build learning rate.""" + if lr_decay_type == 'exponential': + assert steps_per_epoch is not None + decay_steps = steps_per_epoch * decay_epochs + lr = tf.train.exponential_decay( + initial_lr, global_step, decay_steps, decay_factor, staircase=True) + elif lr_decay_type == 'cosine': + assert total_steps is not None + lr = 0.5 * initial_lr * ( + 1 + tf.cos(np.pi * tf.cast(global_step, tf.float32) / total_steps)) + elif lr_decay_type == 'constant': + lr = initial_lr + elif lr_decay_type == 'poly': + tf.logging.info('Using poly LR schedule') + assert steps_per_epoch is not None + assert total_steps is not None + warmup_steps = int(steps_per_epoch * warmup_epochs) + min_step = tf.constant(1, dtype=tf.int64) + decay_steps = tf.maximum( + min_step, tf.subtract(global_step, warmup_steps)) + lr = tf.train.polynomial_decay( + initial_lr, + decay_steps, + total_steps - warmup_steps + 1, + end_learning_rate=0.1, + power=2.0) + else: + assert False, 'Unknown lr_decay_type : %s' % lr_decay_type + + if warmup_epochs: + logging.info('Learning rate warmup_epochs: %d', warmup_epochs) + warmup_steps = int(warmup_epochs * steps_per_epoch) + warmup_lr = ( + initial_lr * tf.cast(global_step, tf.float32) / tf.cast( + warmup_steps, tf.float32)) + lr = tf.cond(global_step < warmup_steps, lambda: warmup_lr, lambda: lr) + + return lr + + +def build_optimizer(learning_rate, + optimizer_name='rmsprop', + decay=0.9, + epsilon=0.001, + momentum=0.9, + lars_weight_decay=None, + lars_epsilon=None): + """Build optimizer.""" + if optimizer_name == 'sgd': + logging.info('Using SGD optimizer') + optimizer = tf.train.GradientDescentOptimizer( + learning_rate=learning_rate) + elif optimizer_name == 'momentum': + logging.info('Using Momentum optimizer') + optimizer = tf.train.MomentumOptimizer( + learning_rate=learning_rate, momentum=momentum) + elif optimizer_name == 'rmsprop': + logging.info('Using RMSProp optimizer') + optimizer = tf.train.RMSPropOptimizer(learning_rate, decay, momentum, + epsilon) + elif optimizer_name == 'lars': + logging.info('Using LARS optimizer') + assert lars_weight_decay is not None, 'LARS weight decay is None.' + assert lars_epsilon is not None, 'LARS epsilon is None.' + optimizer = lars_optimizer.LARSOptimizer( + learning_rate, + momentum=momentum, + weight_decay=lars_weight_decay, + skip_list=['batch_normalization', 'bias', 'beta', 'gamma'], + epsilon=lars_epsilon) + else: + logging.fatal('Unknown optimizer: %s', optimizer_name) + + return optimizer + + +class TpuBatchNormalization(tf.layers.BatchNormalization): + # class TpuBatchNormalization(tf.layers.BatchNormalization): + """Cross replica batch normalization.""" + + def __init__(self, fused=False, **kwargs): + if fused in (True, None): + raise ValueError( + 'TpuBatchNormalization does not support fused=True.') + super(TpuBatchNormalization, self).__init__(fused=fused, **kwargs) + + def _cross_replica_average(self, t, num_shards_per_group): + """Calculates the average value of input tensor across TPU replicas.""" + num_shards = tpu_function.get_tpu_context().number_of_shards + group_assignment = None + if num_shards_per_group > 1: + if num_shards % num_shards_per_group != 0: + raise ValueError('num_shards: %d mod shards_per_group: %d, should be 0' + % (num_shards, num_shards_per_group)) + num_groups = num_shards // num_shards_per_group + group_assignment = [[ + x for x in range(num_shards) if x // num_shards_per_group == y + ] for y in range(num_groups)] + return tf.tpu.cross_replica_sum(t, group_assignment) / tf.cast( + num_shards_per_group, t.dtype) + + def _moments(self, inputs, reduction_axes, keep_dims): + """Compute the mean and variance: it overrides the original _moments.""" + shard_mean, shard_variance = super(TpuBatchNormalization, self)._moments( + inputs, reduction_axes, keep_dims=keep_dims) + + num_shards = tpu_function.get_tpu_context().number_of_shards or 1 + if num_shards <= 8: # Skip cross_replica for 2x2 or smaller slices. + num_shards_per_group = 1 + else: + num_shards_per_group = max(8, num_shards // 8) + logging.info('TpuBatchNormalization with num_shards_per_group %s', + num_shards_per_group) + if num_shards_per_group > 1: + # Compute variance using: Var[X]= E[X^2] - E[X]^2. + shard_square_of_mean = tf.math.square(shard_mean) + shard_mean_of_square = shard_variance + shard_square_of_mean + group_mean = self._cross_replica_average( + shard_mean, num_shards_per_group) + group_mean_of_square = self._cross_replica_average( + shard_mean_of_square, num_shards_per_group) + group_variance = group_mean_of_square - tf.math.square(group_mean) + return (group_mean, group_variance) + else: + return (shard_mean, shard_variance) + + +class BatchNormalization(tf.layers.BatchNormalization): + """Fixed default name of BatchNormalization to match TpuBatchNormalization.""" + + def __init__(self, name='tpu_batch_normalization', **kwargs): + super(BatchNormalization, self).__init__(name=name, **kwargs) + + +def train_batch_norm(**kwargs): + if 'optimizer' in FLAGS and FLAGS.optimizer == 'lars': + return DistributedBatchNormalization(**kwargs) + return TpuBatchNormalization(**kwargs) + + +def eval_batch_norm(**kwargs): + if 'optimizer' in FLAGS and FLAGS.optimizer == 'lars': + return DistributedBatchNormalization(**kwargs) + return BatchNormalization(**kwargs) + + +class DistributedBatchNormalization: + """Distributed batch normalization used in https://arxiv.org/abs/2011.00071.""" + + def __init__(self, axis, momentum, epsilon): + self.axis = axis + self.momentum = momentum + self.epsilon = epsilon + + def __call__(self, x, training, distname='batch_normalization'): + shape = [x.shape[-1]] + with tf.variable_scope('batch_normalization'): + ones = tf.initializers.ones() + zeros = tf.initializers.zeros() + gamma = tf.get_variable( + 'gamma', shape, initializer=ones, trainable=True, use_resource=True) + beta = tf.get_variable( + 'beta', shape, initializer=zeros, trainable=True, use_resource=True) + moving_mean = tf.get_variable( + 'moving_mean', + shape, + initializer=zeros, + trainable=False, + use_resource=True) + moving_variance = tf.get_variable( + 'moving_variance', + shape, + initializer=ones, + trainable=False, + use_resource=True) + num_replicas = FLAGS.num_replicas + + x = tf.cast(x, tf.float32) + if training: + if num_replicas <= 8: + group_assign = None + group_shards = tf.cast(num_replicas, tf.float32) + else: + + group_shards = max( + 1, + int(FLAGS.batch_norm_batch_size / + (FLAGS.train_batch_size / num_replicas))) + group_assign = np.arange(num_replicas, dtype=np.int32) + group_assign = group_assign.reshape([-1, group_shards]) + group_assign = group_assign.tolist() + group_shards = tf.cast(group_shards, tf.float32) + + mean = tf.reduce_mean(x, [0, 1, 2]) + mean = tf.tpu.cross_replica_sum(mean, group_assign) / group_shards + + # Var[x] = E[x^2] - E[x]^2 + mean_sq = tf.reduce_mean(tf.math.square(x), [0, 1, 2]) + mean_sq = tf.tpu.cross_replica_sum( + mean_sq, group_assign) / group_shards + variance = mean_sq - tf.math.square(mean) + + decay = tf.cast(1. - self.momentum, tf.float32) + + def u(moving, normal, name): + num_replicas_fp = tf.cast(num_replicas, tf.float32) + normal = tf.tpu.cross_replica_sum(normal) / num_replicas_fp + diff = decay * (moving - normal) + return tf.assign_sub(moving, diff, use_locking=True, name=name) + + tf.add_to_collection(tf.GraphKeys.UPDATE_OPS, + u(moving_mean, mean, name='moving_mean')) + tf.add_to_collection(tf.GraphKeys.UPDATE_OPS, + u(moving_variance, variance, name='moving_variance')) + + x = tf.nn.batch_normalization( + x, + mean=mean, + variance=variance, + offset=beta, + scale=gamma, + variance_epsilon=self.epsilon) + else: + + x, _, _ = tf.nn.fused_batch_norm( + x, + scale=gamma, + offset=beta, + mean=moving_mean, + variance=moving_variance, + epsilon=self.epsilon, + is_training=False) + + return x + + +def drop_connect(inputs, is_training, survival_prob): + """Drop the entire conv with given survival probability.""" + # "Deep Networks with Stochastic Depth", https://arxiv.org/pdf/1603.09382.pdf + if not is_training: + return inputs + + # Compute tensor. + batch_size = tf.shape(inputs)[0] + random_tensor = survival_prob + random_tensor += tf.random_uniform([batch_size, + 1, 1, 1], dtype=inputs.dtype) + binary_tensor = tf.floor(random_tensor) + # Unlike conventional way that multiply survival_prob at test time, here we + # divide survival_prob at training time, such that no addition compute is + # needed at test time. + output = tf.div(inputs, survival_prob) * binary_tensor + return output + + +def archive_ckpt(ckpt_eval, ckpt_objective, ckpt_path): + """Archive a checkpoint if the metric is better.""" + ckpt_dir, ckpt_name = os.path.split(ckpt_path) + + saved_objective_path = os.path.join(ckpt_dir, 'best_objective.txt') + saved_objective = float('-inf') + if tf.gfile.Exists(saved_objective_path): + with tf.gfile.GFile(saved_objective_path, 'r') as f: + saved_objective = float(f.read()) + if saved_objective > ckpt_objective: + logging.info('Ckpt %s is worse than %s', + ckpt_objective, saved_objective) + return False + + filenames = tf.gfile.Glob(ckpt_path + '.*') + if filenames is None: + logging.info('No files to copy for checkpoint %s', ckpt_path) + return False + + # Clear the old folder. + dst_dir = os.path.join(ckpt_dir, 'archive') + if tf.gfile.Exists(dst_dir): + tf.gfile.DeleteRecursively(dst_dir) + tf.gfile.MakeDirs(dst_dir) + + # Write checkpoints. + for f in filenames: + dest = os.path.join(dst_dir, os.path.basename(f)) + tf.gfile.Copy(f, dest, overwrite=True) + ckpt_state = tf.train.generate_checkpoint_state_proto( + dst_dir, + model_checkpoint_path=ckpt_name, + all_model_checkpoint_paths=[ckpt_name]) + with tf.gfile.GFile(os.path.join(dst_dir, 'checkpoint'), 'w') as f: + f.write(str(ckpt_state)) + with tf.gfile.GFile(os.path.join(dst_dir, 'best_eval.txt'), 'w') as f: + f.write('%s' % ckpt_eval) + + # Update the best objective. + with tf.gfile.GFile(saved_objective_path, 'w') as f: + f.write('%f' % ckpt_objective) + + logging.info('Copying checkpoint %s to %s', ckpt_path, dst_dir) + return True + + +def get_ema_vars(): + """Get all exponential moving average (ema) variables.""" + ema_vars = tf.trainable_variables() + tf.get_collection('moving_vars') + for v in tf.global_variables(): + # We maintain mva for batch norm moving mean and variance as well. + if 'moving_mean' in v.name or 'moving_variance' in v.name: + ema_vars.append(v) + return list(set(ema_vars)) + + +class DepthwiseConv2D(tf.keras.layers.DepthwiseConv2D, tf.layers.Layer): + """Wrap keras DepthwiseConv2D to tf.layers.""" + + pass + + +class Conv2D(tf.layers.Conv2D): + """Wrapper for Conv2D with specialization for fast inference.""" + + def _bias_activation(self, outputs): + if self.use_bias: + outputs = tf.nn.bias_add(outputs, self.bias, data_format='NCHW') + if self.activation is not None: + return self.activation(outputs) + return outputs + + def _can_run_fast_1x1(self, inputs): + batch_size = inputs.shape.as_list()[0] + return (self.data_format == 'channels_first' and + batch_size == 1 and + self.kernel_size == (1, 1)) + + def _call_fast_1x1(self, inputs): + # Compute the 1x1 convolution as a matmul. + inputs_shape = tf.shape(inputs) + flat_inputs = tf.reshape(inputs, [inputs_shape[1], -1]) + flat_outputs = tf.matmul( + tf.squeeze(self.kernel), + flat_inputs, + transpose_a=True) + outputs_shape = tf.concat( + [[1, self.filters], inputs_shape[2:]], axis=0) + outputs = tf.reshape(flat_outputs, outputs_shape) + + # Handle the bias and activation function. + return self._bias_activation(outputs) + + def call(self, inputs): + if self._can_run_fast_1x1(inputs): + return self._call_fast_1x1(inputs) + return super(Conv2D, self).call(inputs) + + +class EvalCkptDriver(object): + """A driver for running eval inference. + + Attributes: + model_name: str. Model name to eval. + batch_size: int. Eval batch size. + image_size: int. Input image size, determined by model name. + num_classes: int. Number of classes, default to 1000 for ImageNet. + include_background_label: whether to include extra background label. + advprop_preprocessing: whether to use advprop preprocessing. + """ + + def __init__(self, + model_name, + batch_size=1, + image_size=224, + num_classes=1000, + include_background_label=False, + advprop_preprocessing=False): + """Initialize internal variables.""" + self.model_name = model_name + self.batch_size = batch_size + self.num_classes = num_classes + self.include_background_label = include_background_label + self.image_size = image_size + self.advprop_preprocessing = advprop_preprocessing + + def restore_model(self, sess, ckpt_dir, enable_ema=True, export_ckpt=None): + """Restore variables from checkpoint dir.""" + sess.run(tf.global_variables_initializer()) + checkpoint = tf.train.latest_checkpoint(ckpt_dir) + if enable_ema: + ema = tf.train.ExponentialMovingAverage(decay=0.0) + ema_vars = get_ema_vars() + var_dict = ema.variables_to_restore(ema_vars) + ema_assign_op = ema.apply(ema_vars) + else: + var_dict = get_ema_vars() + ema_assign_op = None + + tf.train.get_or_create_global_step() + sess.run(tf.global_variables_initializer()) + saver = tf.train.Saver(var_dict, max_to_keep=1) + saver.restore(sess, checkpoint) + + if export_ckpt: + if ema_assign_op is not None: + sess.run(ema_assign_op) + saver = tf.train.Saver(max_to_keep=1, save_relative_paths=True) + saver.save(sess, export_ckpt) + + def build_model(self, features, is_training): + """Build model with input features.""" + del features, is_training + raise ValueError('Must be implemented by subclasses.') + + def get_preprocess_fn(self): + raise ValueError('Must be implemented by subclsses.') + + def build_dataset(self, filenames, labels, is_training): + """Build input dataset.""" + batch_drop_remainder = False + if 'condconv' in self.model_name and not is_training: + # CondConv layers can only be called with known batch dimension. Thus, we + # must drop all remaining examples that do not make up one full batch. + # To ensure all examples are evaluated, use a batch size that evenly + # divides the number of files. + batch_drop_remainder = True + num_files = len(filenames) + if num_files % self.batch_size != 0: + tf.logging.warn('Remaining examples in last batch are not being ' + 'evaluated.') + filenames = tf.constant(filenames) + labels = tf.constant(labels) + dataset = tf.data.Dataset.from_tensor_slices((filenames, labels)) + + def _parse_function(filename, label): + image_string = tf.read_file(filename) + preprocess_fn = self.get_preprocess_fn() + image_decoded = preprocess_fn( + image_string, is_training, image_size=self.image_size) + image = tf.cast(image_decoded, tf.float32) + return image, label + + dataset = dataset.map(_parse_function) + dataset = dataset.batch(self.batch_size, + drop_remainder=batch_drop_remainder) + + iterator = dataset.make_one_shot_iterator() + images, labels = iterator.get_next() + return images, labels + + def run_inference(self, + ckpt_dir, + image_files, + labels, + enable_ema=True, + export_ckpt=None): + """Build and run inference on the target images and labels.""" + label_offset = 1 if self.include_background_label else 0 + with tf.Graph().as_default(), tf.Session() as sess: + images, labels = self.build_dataset(image_files, labels, False) + probs = self.build_model(images, is_training=False) + if isinstance(probs, tuple): + probs = probs[0] + + self.restore_model(sess, ckpt_dir, enable_ema, export_ckpt) + + prediction_idx = [] + prediction_prob = [] + for _ in range(len(image_files) // self.batch_size): + out_probs = sess.run(probs) + idx = np.argsort(out_probs)[::-1] + prediction_idx.append(idx[:5] - label_offset) + prediction_prob.append([out_probs[pid] for pid in idx[:5]]) + + # Return the top 5 predictions (idx and prob) for each image. + return prediction_idx, prediction_prob + + def eval_example_images(self, + ckpt_dir, + image_files, + labels_map_file, + enable_ema=True, + export_ckpt=None): + """Eval a list of example images. + + Args: + ckpt_dir: str. Checkpoint directory path. + image_files: List[str]. A list of image file paths. + labels_map_file: str. The labels map file path. + enable_ema: enable expotential moving average. + export_ckpt: export ckpt folder. + + Returns: + A tuple (pred_idx, and pred_prob), where pred_idx is the top 5 prediction + index and pred_prob is the top 5 prediction probability. + """ + classes = json.loads(tf.gfile.Open(labels_map_file).read()) + pred_idx, pred_prob = self.run_inference( + ckpt_dir, image_files, [0] * len(image_files), enable_ema, export_ckpt) + for i in range(len(image_files)): + print('predicted class for image {}: '.format(image_files[i])) + for j, idx in enumerate(pred_idx[i]): + print(' -> top_{} ({:4.2f}%): {} '.format(j, pred_prob[i][j] * 100, + classes[str(idx)])) + return pred_idx, pred_prob + + def eval_imagenet(self, ckpt_dir, imagenet_eval_glob, + imagenet_eval_label, num_images, enable_ema, export_ckpt): + """Eval ImageNet images and report top1/top5 accuracy. + + Args: + ckpt_dir: str. Checkpoint directory path. + imagenet_eval_glob: str. File path glob for all eval images. + imagenet_eval_label: str. File path for eval label. + num_images: int. Number of images to eval: -1 means eval the whole + dataset. + enable_ema: enable expotential moving average. + export_ckpt: export checkpoint folder. + + Returns: + A tuple (top1, top5) for top1 and top5 accuracy. + """ + imagenet_val_labels = [int(i) + for i in tf.gfile.GFile(imagenet_eval_label)] + imagenet_filenames = sorted(tf.gfile.Glob(imagenet_eval_glob)) + if num_images < 0: + num_images = len(imagenet_filenames) + image_files = imagenet_filenames[:num_images] + labels = imagenet_val_labels[:num_images] + + pred_idx, _ = self.run_inference( + ckpt_dir, image_files, labels, enable_ema, export_ckpt) + top1_cnt, top5_cnt = 0.0, 0.0 + for i, label in enumerate(labels): + top1_cnt += label in pred_idx[i][:1] + top5_cnt += label in pred_idx[i][:5] + if i % 100 == 0: + print('Step {}: top1_acc = {:4.2f}% top5_acc = {:4.2f}%'.format( + i, 100 * top1_cnt / (i + 1), 100 * top5_cnt / (i + 1))) + sys.stdout.flush() + top1, top5 = 100 * top1_cnt / num_images, 100 * top5_cnt / num_images + print( + 'Final: top1_acc = {:4.2f}% top5_acc = {:4.2f}%'.format(top1, top5)) + return top1, top5