megadetector 5.0.11__py3-none-any.whl → 5.0.12__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of megadetector might be problematic. Click here for more details.

Files changed (201) hide show
  1. megadetector/api/__init__.py +0 -0
  2. megadetector/api/batch_processing/__init__.py +0 -0
  3. megadetector/api/batch_processing/api_core/__init__.py +0 -0
  4. megadetector/api/batch_processing/api_core/batch_service/__init__.py +0 -0
  5. megadetector/api/batch_processing/api_core/batch_service/score.py +439 -0
  6. megadetector/api/batch_processing/api_core/server.py +294 -0
  7. megadetector/api/batch_processing/api_core/server_api_config.py +98 -0
  8. megadetector/api/batch_processing/api_core/server_app_config.py +55 -0
  9. megadetector/api/batch_processing/api_core/server_batch_job_manager.py +220 -0
  10. megadetector/api/batch_processing/api_core/server_job_status_table.py +152 -0
  11. megadetector/api/batch_processing/api_core/server_orchestration.py +360 -0
  12. megadetector/api/batch_processing/api_core/server_utils.py +92 -0
  13. megadetector/api/batch_processing/api_core_support/__init__.py +0 -0
  14. megadetector/api/batch_processing/api_core_support/aggregate_results_manually.py +46 -0
  15. megadetector/api/batch_processing/api_support/__init__.py +0 -0
  16. megadetector/api/batch_processing/api_support/summarize_daily_activity.py +152 -0
  17. megadetector/api/batch_processing/data_preparation/__init__.py +0 -0
  18. megadetector/api/batch_processing/integration/digiKam/setup.py +6 -0
  19. megadetector/api/batch_processing/integration/digiKam/xmp_integration.py +465 -0
  20. megadetector/api/batch_processing/integration/eMammal/test_scripts/config_template.py +5 -0
  21. megadetector/api/batch_processing/integration/eMammal/test_scripts/push_annotations_to_emammal.py +126 -0
  22. megadetector/api/batch_processing/integration/eMammal/test_scripts/select_images_for_testing.py +55 -0
  23. megadetector/api/synchronous/__init__.py +0 -0
  24. megadetector/api/synchronous/api_core/animal_detection_api/__init__.py +0 -0
  25. megadetector/api/synchronous/api_core/animal_detection_api/api_backend.py +152 -0
  26. megadetector/api/synchronous/api_core/animal_detection_api/api_frontend.py +266 -0
  27. megadetector/api/synchronous/api_core/animal_detection_api/config.py +35 -0
  28. megadetector/api/synchronous/api_core/tests/__init__.py +0 -0
  29. megadetector/api/synchronous/api_core/tests/load_test.py +110 -0
  30. megadetector/classification/__init__.py +0 -0
  31. megadetector/classification/aggregate_classifier_probs.py +108 -0
  32. megadetector/classification/analyze_failed_images.py +227 -0
  33. megadetector/classification/cache_batchapi_outputs.py +198 -0
  34. megadetector/classification/create_classification_dataset.py +627 -0
  35. megadetector/classification/crop_detections.py +516 -0
  36. megadetector/classification/csv_to_json.py +226 -0
  37. megadetector/classification/detect_and_crop.py +855 -0
  38. megadetector/classification/efficientnet/__init__.py +9 -0
  39. megadetector/classification/efficientnet/model.py +415 -0
  40. megadetector/classification/efficientnet/utils.py +610 -0
  41. megadetector/classification/evaluate_model.py +520 -0
  42. megadetector/classification/identify_mislabeled_candidates.py +152 -0
  43. megadetector/classification/json_to_azcopy_list.py +63 -0
  44. megadetector/classification/json_validator.py +699 -0
  45. megadetector/classification/map_classification_categories.py +276 -0
  46. megadetector/classification/merge_classification_detection_output.py +506 -0
  47. megadetector/classification/prepare_classification_script.py +194 -0
  48. megadetector/classification/prepare_classification_script_mc.py +228 -0
  49. megadetector/classification/run_classifier.py +287 -0
  50. megadetector/classification/save_mislabeled.py +110 -0
  51. megadetector/classification/train_classifier.py +827 -0
  52. megadetector/classification/train_classifier_tf.py +725 -0
  53. megadetector/classification/train_utils.py +323 -0
  54. megadetector/data_management/__init__.py +0 -0
  55. megadetector/data_management/annotations/__init__.py +0 -0
  56. megadetector/data_management/annotations/annotation_constants.py +34 -0
  57. megadetector/data_management/camtrap_dp_to_coco.py +239 -0
  58. megadetector/data_management/cct_json_utils.py +395 -0
  59. megadetector/data_management/cct_to_md.py +176 -0
  60. megadetector/data_management/cct_to_wi.py +289 -0
  61. megadetector/data_management/coco_to_labelme.py +272 -0
  62. megadetector/data_management/coco_to_yolo.py +662 -0
  63. megadetector/data_management/databases/__init__.py +0 -0
  64. megadetector/data_management/databases/add_width_and_height_to_db.py +33 -0
  65. megadetector/data_management/databases/combine_coco_camera_traps_files.py +206 -0
  66. megadetector/data_management/databases/integrity_check_json_db.py +477 -0
  67. megadetector/data_management/databases/subset_json_db.py +115 -0
  68. megadetector/data_management/generate_crops_from_cct.py +149 -0
  69. megadetector/data_management/get_image_sizes.py +189 -0
  70. megadetector/data_management/importers/add_nacti_sizes.py +52 -0
  71. megadetector/data_management/importers/add_timestamps_to_icct.py +79 -0
  72. megadetector/data_management/importers/animl_results_to_md_results.py +158 -0
  73. megadetector/data_management/importers/auckland_doc_test_to_json.py +373 -0
  74. megadetector/data_management/importers/auckland_doc_to_json.py +201 -0
  75. megadetector/data_management/importers/awc_to_json.py +191 -0
  76. megadetector/data_management/importers/bellevue_to_json.py +273 -0
  77. megadetector/data_management/importers/cacophony-thermal-importer.py +796 -0
  78. megadetector/data_management/importers/carrizo_shrubfree_2018.py +269 -0
  79. megadetector/data_management/importers/carrizo_trail_cam_2017.py +289 -0
  80. megadetector/data_management/importers/cct_field_adjustments.py +58 -0
  81. megadetector/data_management/importers/channel_islands_to_cct.py +913 -0
  82. megadetector/data_management/importers/eMammal/copy_and_unzip_emammal.py +180 -0
  83. megadetector/data_management/importers/eMammal/eMammal_helpers.py +249 -0
  84. megadetector/data_management/importers/eMammal/make_eMammal_json.py +223 -0
  85. megadetector/data_management/importers/ena24_to_json.py +276 -0
  86. megadetector/data_management/importers/filenames_to_json.py +386 -0
  87. megadetector/data_management/importers/helena_to_cct.py +283 -0
  88. megadetector/data_management/importers/idaho-camera-traps.py +1407 -0
  89. megadetector/data_management/importers/idfg_iwildcam_lila_prep.py +294 -0
  90. megadetector/data_management/importers/jb_csv_to_json.py +150 -0
  91. megadetector/data_management/importers/mcgill_to_json.py +250 -0
  92. megadetector/data_management/importers/missouri_to_json.py +490 -0
  93. megadetector/data_management/importers/nacti_fieldname_adjustments.py +79 -0
  94. megadetector/data_management/importers/noaa_seals_2019.py +181 -0
  95. megadetector/data_management/importers/pc_to_json.py +365 -0
  96. megadetector/data_management/importers/plot_wni_giraffes.py +123 -0
  97. megadetector/data_management/importers/prepare-noaa-fish-data-for-lila.py +359 -0
  98. megadetector/data_management/importers/prepare_zsl_imerit.py +131 -0
  99. megadetector/data_management/importers/rspb_to_json.py +356 -0
  100. megadetector/data_management/importers/save_the_elephants_survey_A.py +320 -0
  101. megadetector/data_management/importers/save_the_elephants_survey_B.py +329 -0
  102. megadetector/data_management/importers/snapshot_safari_importer.py +758 -0
  103. megadetector/data_management/importers/snapshot_safari_importer_reprise.py +665 -0
  104. megadetector/data_management/importers/snapshot_serengeti_lila.py +1067 -0
  105. megadetector/data_management/importers/snapshotserengeti/make_full_SS_json.py +150 -0
  106. megadetector/data_management/importers/snapshotserengeti/make_per_season_SS_json.py +153 -0
  107. megadetector/data_management/importers/sulross_get_exif.py +65 -0
  108. megadetector/data_management/importers/timelapse_csv_set_to_json.py +490 -0
  109. megadetector/data_management/importers/ubc_to_json.py +399 -0
  110. megadetector/data_management/importers/umn_to_json.py +507 -0
  111. megadetector/data_management/importers/wellington_to_json.py +263 -0
  112. megadetector/data_management/importers/wi_to_json.py +442 -0
  113. megadetector/data_management/importers/zamba_results_to_md_results.py +181 -0
  114. megadetector/data_management/labelme_to_coco.py +547 -0
  115. megadetector/data_management/labelme_to_yolo.py +272 -0
  116. megadetector/data_management/lila/__init__.py +0 -0
  117. megadetector/data_management/lila/add_locations_to_island_camera_traps.py +97 -0
  118. megadetector/data_management/lila/add_locations_to_nacti.py +147 -0
  119. megadetector/data_management/lila/create_lila_blank_set.py +558 -0
  120. megadetector/data_management/lila/create_lila_test_set.py +152 -0
  121. megadetector/data_management/lila/create_links_to_md_results_files.py +106 -0
  122. megadetector/data_management/lila/download_lila_subset.py +178 -0
  123. megadetector/data_management/lila/generate_lila_per_image_labels.py +516 -0
  124. megadetector/data_management/lila/get_lila_annotation_counts.py +170 -0
  125. megadetector/data_management/lila/get_lila_image_counts.py +112 -0
  126. megadetector/data_management/lila/lila_common.py +300 -0
  127. megadetector/data_management/lila/test_lila_metadata_urls.py +132 -0
  128. megadetector/data_management/ocr_tools.py +874 -0
  129. megadetector/data_management/read_exif.py +681 -0
  130. megadetector/data_management/remap_coco_categories.py +84 -0
  131. megadetector/data_management/remove_exif.py +66 -0
  132. megadetector/data_management/resize_coco_dataset.py +189 -0
  133. megadetector/data_management/wi_download_csv_to_coco.py +246 -0
  134. megadetector/data_management/yolo_output_to_md_output.py +441 -0
  135. megadetector/data_management/yolo_to_coco.py +676 -0
  136. megadetector/detection/__init__.py +0 -0
  137. megadetector/detection/detector_training/__init__.py +0 -0
  138. megadetector/detection/detector_training/model_main_tf2.py +114 -0
  139. megadetector/detection/process_video.py +702 -0
  140. megadetector/detection/pytorch_detector.py +341 -0
  141. megadetector/detection/run_detector.py +779 -0
  142. megadetector/detection/run_detector_batch.py +1219 -0
  143. megadetector/detection/run_inference_with_yolov5_val.py +917 -0
  144. megadetector/detection/run_tiled_inference.py +934 -0
  145. megadetector/detection/tf_detector.py +189 -0
  146. megadetector/detection/video_utils.py +606 -0
  147. megadetector/postprocessing/__init__.py +0 -0
  148. megadetector/postprocessing/add_max_conf.py +64 -0
  149. megadetector/postprocessing/categorize_detections_by_size.py +163 -0
  150. megadetector/postprocessing/combine_api_outputs.py +249 -0
  151. megadetector/postprocessing/compare_batch_results.py +958 -0
  152. megadetector/postprocessing/convert_output_format.py +396 -0
  153. megadetector/postprocessing/load_api_results.py +195 -0
  154. megadetector/postprocessing/md_to_coco.py +310 -0
  155. megadetector/postprocessing/md_to_labelme.py +330 -0
  156. megadetector/postprocessing/merge_detections.py +401 -0
  157. megadetector/postprocessing/postprocess_batch_results.py +1902 -0
  158. megadetector/postprocessing/remap_detection_categories.py +170 -0
  159. megadetector/postprocessing/render_detection_confusion_matrix.py +660 -0
  160. megadetector/postprocessing/repeat_detection_elimination/find_repeat_detections.py +211 -0
  161. megadetector/postprocessing/repeat_detection_elimination/remove_repeat_detections.py +83 -0
  162. megadetector/postprocessing/repeat_detection_elimination/repeat_detections_core.py +1631 -0
  163. megadetector/postprocessing/separate_detections_into_folders.py +730 -0
  164. megadetector/postprocessing/subset_json_detector_output.py +696 -0
  165. megadetector/postprocessing/top_folders_to_bottom.py +223 -0
  166. megadetector/taxonomy_mapping/__init__.py +0 -0
  167. megadetector/taxonomy_mapping/map_lila_taxonomy_to_wi_taxonomy.py +491 -0
  168. megadetector/taxonomy_mapping/map_new_lila_datasets.py +150 -0
  169. megadetector/taxonomy_mapping/prepare_lila_taxonomy_release.py +142 -0
  170. megadetector/taxonomy_mapping/preview_lila_taxonomy.py +590 -0
  171. megadetector/taxonomy_mapping/retrieve_sample_image.py +71 -0
  172. megadetector/taxonomy_mapping/simple_image_download.py +219 -0
  173. megadetector/taxonomy_mapping/species_lookup.py +834 -0
  174. megadetector/taxonomy_mapping/taxonomy_csv_checker.py +159 -0
  175. megadetector/taxonomy_mapping/taxonomy_graph.py +346 -0
  176. megadetector/taxonomy_mapping/validate_lila_category_mappings.py +83 -0
  177. megadetector/utils/__init__.py +0 -0
  178. megadetector/utils/azure_utils.py +178 -0
  179. megadetector/utils/ct_utils.py +612 -0
  180. megadetector/utils/directory_listing.py +246 -0
  181. megadetector/utils/md_tests.py +968 -0
  182. megadetector/utils/path_utils.py +1044 -0
  183. megadetector/utils/process_utils.py +157 -0
  184. megadetector/utils/sas_blob_utils.py +509 -0
  185. megadetector/utils/split_locations_into_train_val.py +228 -0
  186. megadetector/utils/string_utils.py +92 -0
  187. megadetector/utils/url_utils.py +323 -0
  188. megadetector/utils/write_html_image_list.py +225 -0
  189. megadetector/visualization/__init__.py +0 -0
  190. megadetector/visualization/plot_utils.py +293 -0
  191. megadetector/visualization/render_images_with_thumbnails.py +275 -0
  192. megadetector/visualization/visualization_utils.py +1536 -0
  193. megadetector/visualization/visualize_db.py +550 -0
  194. megadetector/visualization/visualize_detector_output.py +405 -0
  195. {megadetector-5.0.11.dist-info → megadetector-5.0.12.dist-info}/METADATA +1 -1
  196. megadetector-5.0.12.dist-info/RECORD +199 -0
  197. megadetector-5.0.12.dist-info/top_level.txt +1 -0
  198. megadetector-5.0.11.dist-info/RECORD +0 -5
  199. megadetector-5.0.11.dist-info/top_level.txt +0 -1
  200. {megadetector-5.0.11.dist-info → megadetector-5.0.12.dist-info}/LICENSE +0 -0
  201. {megadetector-5.0.11.dist-info → megadetector-5.0.12.dist-info}/WHEEL +0 -0
@@ -0,0 +1,610 @@
1
+ """utils.py - Helper functions for building the model and for loading model parameters.
2
+ These helper functions are built to mirror those in the official TensorFlow implementation.
3
+ """
4
+
5
+ # Author: lukemelas (github username)
6
+ # Github repo: https://github.com/lukemelas/EfficientNet-PyTorch
7
+ # With adjustments and added comments by workingcoder (github username).
8
+
9
+ import re
10
+ import math
11
+ import collections
12
+ from functools import partial
13
+ import torch
14
+ from torch import nn
15
+ from torch.nn import functional as F
16
+ from torch.utils import model_zoo
17
+
18
+
19
+ ################################################################################
20
+ ### Help functions for model architecture
21
+ ################################################################################
22
+
23
+ # GlobalParams and BlockArgs: Two namedtuples
24
+ # Swish and MemoryEfficientSwish: Two implementations of the method
25
+ # round_filters and round_repeats:
26
+ # Functions to calculate params for scaling model width and depth ! ! !
27
+ # get_width_and_height_from_size and calculate_output_image_size
28
+ # drop_connect: A structural design
29
+ # get_same_padding_conv2d:
30
+ # Conv2dDynamicSamePadding
31
+ # Conv2dStaticSamePadding
32
+ # get_same_padding_maxPool2d:
33
+ # MaxPool2dDynamicSamePadding
34
+ # MaxPool2dStaticSamePadding
35
+ # It's an additional function, not used in EfficientNet,
36
+ # but can be used in other model (such as EfficientDet).
37
+
38
+ # Parameters for the entire model (stem, all blocks, and head)
39
+ GlobalParams = collections.namedtuple('GlobalParams', [
40
+ 'width_coefficient', 'depth_coefficient', 'image_size', 'dropout_rate',
41
+ 'num_classes', 'batch_norm_momentum', 'batch_norm_epsilon',
42
+ 'drop_connect_rate', 'depth_divisor', 'min_depth', 'include_top'])
43
+
44
+ # Parameters for an individual model block
45
+ BlockArgs = collections.namedtuple('BlockArgs', [
46
+ 'num_repeat', 'kernel_size', 'stride', 'expand_ratio',
47
+ 'input_filters', 'output_filters', 'se_ratio', 'id_skip'])
48
+
49
+ # Set GlobalParams and BlockArgs's defaults
50
+ GlobalParams.__new__.__defaults__ = (None,) * len(GlobalParams._fields)
51
+ BlockArgs.__new__.__defaults__ = (None,) * len(BlockArgs._fields)
52
+
53
+
54
+ # An ordinary implementation of Swish function
55
+ class Swish(nn.Module):
56
+ def forward(self, x):
57
+ return x * torch.sigmoid(x)
58
+
59
+
60
+ # A memory-efficient implementation of Swish function
61
+ class SwishImplementation(torch.autograd.Function):
62
+ @staticmethod
63
+ def forward(ctx, i):
64
+ result = i * torch.sigmoid(i)
65
+ ctx.save_for_backward(i)
66
+ return result
67
+
68
+ @staticmethod
69
+ def backward(ctx, grad_output):
70
+ i = ctx.saved_tensors[0]
71
+ sigmoid_i = torch.sigmoid(i)
72
+ return grad_output * (sigmoid_i * (1 + i * (1 - sigmoid_i)))
73
+
74
+ class MemoryEfficientSwish(nn.Module):
75
+ def forward(self, x):
76
+ return SwishImplementation.apply(x)
77
+
78
+
79
+ def round_filters(filters, global_params):
80
+ """Calculate and round number of filters based on width multiplier.
81
+ Use width_coefficient, depth_divisor and min_depth of global_params.
82
+
83
+ Args:
84
+ filters (int): Filters number to be calculated.
85
+ global_params (namedtuple): Global params of the model.
86
+
87
+ Returns:
88
+ new_filters: New filters number after calculating.
89
+ """
90
+ multiplier = global_params.width_coefficient
91
+ if not multiplier:
92
+ return filters
93
+ # TODO: modify the params names.
94
+ # maybe the names (width_divisor,min_width)
95
+ # are more suitable than (depth_divisor,min_depth).
96
+ divisor = global_params.depth_divisor
97
+ min_depth = global_params.min_depth
98
+ filters *= multiplier
99
+ min_depth = min_depth or divisor # pay attention to this line when using min_depth
100
+ # follow the formula transferred from official TensorFlow implementation
101
+ new_filters = max(min_depth, int(filters + divisor / 2) // divisor * divisor)
102
+ if new_filters < 0.9 * filters: # prevent rounding by more than 10%
103
+ new_filters += divisor
104
+ return int(new_filters)
105
+
106
+
107
+ def round_repeats(repeats, global_params):
108
+ """Calculate module's repeat number of a block based on depth multiplier.
109
+ Use depth_coefficient of global_params.
110
+
111
+ Args:
112
+ repeats (int): num_repeat to be calculated.
113
+ global_params (namedtuple): Global params of the model.
114
+
115
+ Returns:
116
+ new repeat: New repeat number after calculating.
117
+ """
118
+ multiplier = global_params.depth_coefficient
119
+ if not multiplier:
120
+ return repeats
121
+ # follow the formula transferred from official TensorFlow implementation
122
+ return int(math.ceil(multiplier * repeats))
123
+
124
+
125
+ def drop_connect(inputs, p, training):
126
+ """Drop connect.
127
+
128
+ Args:
129
+ input (tensor: BCWH): Input of this structure.
130
+ p (float: 0.0~1.0): Probability of drop connection.
131
+ training (bool): The running mode.
132
+
133
+ Returns:
134
+ output: Output after drop connection.
135
+ """
136
+ assert 0 <= p <= 1, 'p must be in range of [0,1]'
137
+
138
+ if not training:
139
+ return inputs
140
+
141
+ batch_size = inputs.shape[0]
142
+ keep_prob = 1 - p
143
+
144
+ # generate binary_tensor mask according to probability (p for 0, 1-p for 1)
145
+ random_tensor = keep_prob
146
+ random_tensor += torch.rand([batch_size, 1, 1, 1], dtype=inputs.dtype, device=inputs.device)
147
+ binary_tensor = torch.floor(random_tensor)
148
+
149
+ output = inputs / keep_prob * binary_tensor
150
+ return output
151
+
152
+
153
+ def get_width_and_height_from_size(x):
154
+ """Obtain height and width from x.
155
+
156
+ Args:
157
+ x (int, tuple or list): Data size.
158
+
159
+ Returns:
160
+ size: A tuple or list (H,W).
161
+ """
162
+ if isinstance(x, int):
163
+ return x, x
164
+ if isinstance(x, list) or isinstance(x, tuple):
165
+ return x
166
+ else:
167
+ raise TypeError()
168
+
169
+
170
+ def calculate_output_image_size(input_image_size, stride):
171
+ """Calculates the output image size when using Conv2dSamePadding with a stride.
172
+ Necessary for static padding. Thanks to mannatsingh for pointing this out.
173
+
174
+ Args:
175
+ input_image_size (int, tuple or list): Size of input image.
176
+ stride (int, tuple or list): Conv2d operation's stride.
177
+
178
+ Returns:
179
+ output_image_size: A list [H,W].
180
+ """
181
+ if input_image_size is None:
182
+ return None
183
+ image_height, image_width = get_width_and_height_from_size(input_image_size)
184
+ stride = stride if isinstance(stride, int) else stride[0]
185
+ image_height = int(math.ceil(image_height / stride))
186
+ image_width = int(math.ceil(image_width / stride))
187
+ return [image_height, image_width]
188
+
189
+
190
+ # Note:
191
+ # The following 'SamePadding' functions make output size equal ceil(input size/stride).
192
+ # Only when stride equals 1, can the output size be the same as input size.
193
+ # Don't be confused by their function names ! ! !
194
+
195
+ def get_same_padding_conv2d(image_size=None):
196
+ """Chooses static padding if you have specified an image size, and dynamic padding otherwise.
197
+ Static padding is necessary for ONNX exporting of models.
198
+
199
+ Args:
200
+ image_size (int or tuple): Size of the image.
201
+
202
+ Returns:
203
+ Conv2dDynamicSamePadding or Conv2dStaticSamePadding.
204
+ """
205
+ if image_size is None:
206
+ return Conv2dDynamicSamePadding
207
+ else:
208
+ return partial(Conv2dStaticSamePadding, image_size=image_size)
209
+
210
+
211
+ class Conv2dDynamicSamePadding(nn.Conv2d):
212
+ """2D Convolutions like TensorFlow, for a dynamic image size.
213
+ The padding is operated in forward function by calculating dynamically.
214
+ """
215
+
216
+ # Tips for 'SAME' mode padding.
217
+ # Given the following:
218
+ # i: width or height
219
+ # s: stride
220
+ # k: kernel size
221
+ # d: dilation
222
+ # p: padding
223
+ # Output after Conv2d:
224
+ # o = floor((i+p-((k-1)*d+1))/s+1)
225
+ # If o equals i, i = floor((i+p-((k-1)*d+1))/s+1),
226
+ # => p = (i-1)*s+((k-1)*d+1)-i
227
+
228
+ def __init__(self, in_channels, out_channels, kernel_size, stride=1, dilation=1, groups=1, bias=True):
229
+ super().__init__(in_channels, out_channels, kernel_size, stride, 0, dilation, groups, bias)
230
+ self.stride = self.stride if len(self.stride) == 2 else [self.stride[0]] * 2
231
+
232
+ def forward(self, x):
233
+ ih, iw = x.size()[-2:]
234
+ kh, kw = self.weight.size()[-2:]
235
+ sh, sw = self.stride
236
+ oh, ow = math.ceil(ih / sh), math.ceil(iw / sw) # change the output size according to stride ! ! !
237
+ pad_h = max((oh - 1) * self.stride[0] + (kh - 1) * self.dilation[0] + 1 - ih, 0)
238
+ pad_w = max((ow - 1) * self.stride[1] + (kw - 1) * self.dilation[1] + 1 - iw, 0)
239
+ if pad_h > 0 or pad_w > 0:
240
+ x = F.pad(x, [pad_w // 2, pad_w - pad_w // 2, pad_h // 2, pad_h - pad_h // 2])
241
+ return F.conv2d(x, self.weight, self.bias, self.stride, self.padding, self.dilation, self.groups)
242
+
243
+
244
+ class Conv2dStaticSamePadding(nn.Conv2d):
245
+ """2D Convolutions like TensorFlow's 'SAME' mode, with the given input image size.
246
+ The padding module is calculated in construction function, then used in forward.
247
+ """
248
+
249
+ # With the same calculation as Conv2dDynamicSamePadding
250
+
251
+ def __init__(self, in_channels, out_channels, kernel_size, stride=1, image_size=None, **kwargs):
252
+ super().__init__(in_channels, out_channels, kernel_size, stride, **kwargs)
253
+ self.stride = self.stride if len(self.stride) == 2 else [self.stride[0]] * 2
254
+
255
+ # Calculate padding based on image size and save it
256
+ assert image_size is not None
257
+ ih, iw = (image_size, image_size) if isinstance(image_size, int) else image_size
258
+ kh, kw = self.weight.size()[-2:]
259
+ sh, sw = self.stride
260
+ oh, ow = math.ceil(ih / sh), math.ceil(iw / sw)
261
+ pad_h = max((oh - 1) * self.stride[0] + (kh - 1) * self.dilation[0] + 1 - ih, 0)
262
+ pad_w = max((ow - 1) * self.stride[1] + (kw - 1) * self.dilation[1] + 1 - iw, 0)
263
+ if pad_h > 0 or pad_w > 0:
264
+ self.static_padding = nn.ZeroPad2d((pad_w - pad_w // 2, pad_w - pad_w // 2,
265
+ pad_h - pad_h // 2, pad_h - pad_h // 2))
266
+ else:
267
+ self.static_padding = nn.Identity()
268
+
269
+ def forward(self, x):
270
+ x = self.static_padding(x)
271
+ x = F.conv2d(x, self.weight, self.bias, self.stride, self.padding, self.dilation, self.groups)
272
+ return x
273
+
274
+
275
+ def get_same_padding_maxPool2d(image_size=None):
276
+ """Chooses static padding if you have specified an image size, and dynamic padding otherwise.
277
+ Static padding is necessary for ONNX exporting of models.
278
+
279
+ Args:
280
+ image_size (int or tuple): Size of the image.
281
+
282
+ Returns:
283
+ MaxPool2dDynamicSamePadding or MaxPool2dStaticSamePadding.
284
+ """
285
+ if image_size is None:
286
+ return MaxPool2dDynamicSamePadding
287
+ else:
288
+ return partial(MaxPool2dStaticSamePadding, image_size=image_size)
289
+
290
+
291
+ class MaxPool2dDynamicSamePadding(nn.MaxPool2d):
292
+ """2D MaxPooling like TensorFlow's 'SAME' mode, with a dynamic image size.
293
+ The padding is operated in forward function by calculating dynamically.
294
+ """
295
+
296
+ def __init__(self, kernel_size, stride, padding=0, dilation=1, return_indices=False, ceil_mode=False):
297
+ super().__init__(kernel_size, stride, padding, dilation, return_indices, ceil_mode)
298
+ self.stride = [self.stride] * 2 if isinstance(self.stride, int) else self.stride
299
+ self.kernel_size = [self.kernel_size] * 2 if isinstance(self.kernel_size, int) else self.kernel_size
300
+ self.dilation = [self.dilation] * 2 if isinstance(self.dilation, int) else self.dilation
301
+
302
+ def forward(self, x):
303
+ ih, iw = x.size()[-2:]
304
+ kh, kw = self.kernel_size
305
+ sh, sw = self.stride
306
+ oh, ow = math.ceil(ih / sh), math.ceil(iw / sw)
307
+ pad_h = max((oh - 1) * self.stride[0] + (kh - 1) * self.dilation[0] + 1 - ih, 0)
308
+ pad_w = max((ow - 1) * self.stride[1] + (kw - 1) * self.dilation[1] + 1 - iw, 0)
309
+ if pad_h > 0 or pad_w > 0:
310
+ x = F.pad(x, [pad_w // 2, pad_w - pad_w // 2, pad_h // 2, pad_h - pad_h // 2])
311
+ return F.max_pool2d(x, self.kernel_size, self.stride, self.padding,
312
+ self.dilation, self.ceil_mode, self.return_indices)
313
+
314
+ class MaxPool2dStaticSamePadding(nn.MaxPool2d):
315
+ """2D MaxPooling like TensorFlow's 'SAME' mode, with the given input image size.
316
+ The padding module is calculated in construction function, then used in forward.
317
+ """
318
+
319
+ def __init__(self, kernel_size, stride, image_size=None, **kwargs):
320
+ super().__init__(kernel_size, stride, **kwargs)
321
+ self.stride = [self.stride] * 2 if isinstance(self.stride, int) else self.stride
322
+ self.kernel_size = [self.kernel_size] * 2 if isinstance(self.kernel_size, int) else self.kernel_size
323
+ self.dilation = [self.dilation] * 2 if isinstance(self.dilation, int) else self.dilation
324
+
325
+ # Calculate padding based on image size and save it
326
+ assert image_size is not None
327
+ ih, iw = (image_size, image_size) if isinstance(image_size, int) else image_size
328
+ kh, kw = self.kernel_size
329
+ sh, sw = self.stride
330
+ oh, ow = math.ceil(ih / sh), math.ceil(iw / sw)
331
+ pad_h = max((oh - 1) * self.stride[0] + (kh - 1) * self.dilation[0] + 1 - ih, 0)
332
+ pad_w = max((ow - 1) * self.stride[1] + (kw - 1) * self.dilation[1] + 1 - iw, 0)
333
+ if pad_h > 0 or pad_w > 0:
334
+ self.static_padding = nn.ZeroPad2d((pad_w // 2, pad_w - pad_w // 2, pad_h // 2, pad_h - pad_h // 2))
335
+ else:
336
+ self.static_padding = nn.Identity()
337
+
338
+ def forward(self, x):
339
+ x = self.static_padding(x)
340
+ x = F.max_pool2d(x, self.kernel_size, self.stride, self.padding,
341
+ self.dilation, self.ceil_mode, self.return_indices)
342
+ return x
343
+
344
+
345
+ ################################################################################
346
+ ### Helper functions for loading model params
347
+ ################################################################################
348
+
349
+ # BlockDecoder: A Class for encoding and decoding BlockArgs
350
+ # efficientnet_params: A function to query compound coefficient
351
+ # get_model_params and efficientnet:
352
+ # Functions to get BlockArgs and GlobalParams for efficientnet
353
+ # url_map and url_map_advprop: Dicts of url_map for pretrained weights
354
+ # load_pretrained_weights: A function to load pretrained weights
355
+
356
+ class BlockDecoder(object):
357
+ """Block Decoder for readability,
358
+ straight from the official TensorFlow repository.
359
+ """
360
+
361
+ @staticmethod
362
+ def _decode_block_string(block_string):
363
+ """Get a block through a string notation of arguments.
364
+
365
+ Args:
366
+ block_string (str): A string notation of arguments.
367
+ Examples: 'r1_k3_s11_e1_i32_o16_se0.25_noskip'.
368
+
369
+ Returns:
370
+ BlockArgs: The namedtuple defined at the top of this file.
371
+ """
372
+ assert isinstance(block_string, str)
373
+
374
+ ops = block_string.split('_')
375
+ options = {}
376
+ for op in ops:
377
+ splits = re.split(r'(\d.*)', op)
378
+ if len(splits) >= 2:
379
+ key, value = splits[:2]
380
+ options[key] = value
381
+
382
+ # Check stride
383
+ assert (('s' in options and len(options['s']) == 1) or
384
+ (len(options['s']) == 2 and options['s'][0] == options['s'][1]))
385
+
386
+ return BlockArgs(
387
+ num_repeat=int(options['r']),
388
+ kernel_size=int(options['k']),
389
+ stride=[int(options['s'][0])],
390
+ expand_ratio=int(options['e']),
391
+ input_filters=int(options['i']),
392
+ output_filters=int(options['o']),
393
+ se_ratio=float(options['se']) if 'se' in options else None,
394
+ id_skip=('noskip' not in block_string))
395
+
396
+ @staticmethod
397
+ def _encode_block_string(block):
398
+ """Encode a block to a string.
399
+
400
+ Args:
401
+ block (namedtuple): A BlockArgs type argument.
402
+
403
+ Returns:
404
+ block_string: A String form of BlockArgs.
405
+ """
406
+ args = [
407
+ 'r%d' % block.num_repeat,
408
+ 'k%d' % block.kernel_size,
409
+ 's%d%d' % (block.strides[0], block.strides[1]),
410
+ 'e%s' % block.expand_ratio,
411
+ 'i%d' % block.input_filters,
412
+ 'o%d' % block.output_filters
413
+ ]
414
+ if 0 < block.se_ratio <= 1:
415
+ args.append('se%s' % block.se_ratio)
416
+ if block.id_skip is False:
417
+ args.append('noskip')
418
+ return '_'.join(args)
419
+
420
+ @staticmethod
421
+ def decode(string_list):
422
+ """Decode a list of string notations to specify blocks inside the network.
423
+
424
+ Args:
425
+ string_list (list[str]): A list of strings, each string is a notation of block.
426
+
427
+ Returns:
428
+ blocks_args: A list of BlockArgs namedtuples of block args.
429
+ """
430
+ assert isinstance(string_list, list)
431
+ blocks_args = []
432
+ for block_string in string_list:
433
+ blocks_args.append(BlockDecoder._decode_block_string(block_string))
434
+ return blocks_args
435
+
436
+ @staticmethod
437
+ def encode(blocks_args):
438
+ """Encode a list of BlockArgs to a list of strings.
439
+
440
+ Args:
441
+ blocks_args (list[namedtuples]): A list of BlockArgs namedtuples of block args.
442
+
443
+ Returns:
444
+ block_strings: A list of strings, each string is a notation of block.
445
+ """
446
+ block_strings = []
447
+ for block in blocks_args:
448
+ block_strings.append(BlockDecoder._encode_block_string(block))
449
+ return block_strings
450
+
451
+
452
+ def efficientnet_params(model_name):
453
+ """Map EfficientNet model name to parameter coefficients.
454
+
455
+ Args:
456
+ model_name (str): Model name to be queried.
457
+
458
+ Returns:
459
+ params_dict[model_name]: A (width,depth,res,dropout) tuple.
460
+ """
461
+ params_dict = {
462
+ # Coefficients: width,depth,res,dropout
463
+ 'efficientnet-b0': (1.0, 1.0, 224, 0.2),
464
+ 'efficientnet-b1': (1.0, 1.1, 240, 0.2),
465
+ 'efficientnet-b2': (1.1, 1.2, 260, 0.3),
466
+ 'efficientnet-b3': (1.2, 1.4, 300, 0.3),
467
+ 'efficientnet-b4': (1.4, 1.8, 380, 0.4),
468
+ 'efficientnet-b5': (1.6, 2.2, 456, 0.4),
469
+ 'efficientnet-b6': (1.8, 2.6, 528, 0.5),
470
+ 'efficientnet-b7': (2.0, 3.1, 600, 0.5),
471
+ 'efficientnet-b8': (2.2, 3.6, 672, 0.5),
472
+ 'efficientnet-l2': (4.3, 5.3, 800, 0.5),
473
+ }
474
+ return params_dict[model_name]
475
+
476
+
477
+ def efficientnet(width_coefficient=None, depth_coefficient=None, image_size=None,
478
+ dropout_rate=0.2, drop_connect_rate=0.2, num_classes=1000, include_top=True):
479
+ """Create BlockArgs and GlobalParams for efficientnet model.
480
+
481
+ Args:
482
+ width_coefficient (float)
483
+ depth_coefficient (float)
484
+ image_size (int)
485
+ dropout_rate (float)
486
+ drop_connect_rate (float)
487
+ num_classes (int)
488
+
489
+ Meaning as the name suggests.
490
+
491
+ Returns:
492
+ blocks_args, global_params.
493
+ """
494
+
495
+ # Blocks args for the whole model(efficientnet-b0 by default)
496
+ # It will be modified in the construction of EfficientNet Class according to model
497
+ blocks_args = [
498
+ 'r1_k3_s11_e1_i32_o16_se0.25',
499
+ 'r2_k3_s22_e6_i16_o24_se0.25',
500
+ 'r2_k5_s22_e6_i24_o40_se0.25',
501
+ 'r3_k3_s22_e6_i40_o80_se0.25',
502
+ 'r3_k5_s11_e6_i80_o112_se0.25',
503
+ 'r4_k5_s22_e6_i112_o192_se0.25',
504
+ 'r1_k3_s11_e6_i192_o320_se0.25',
505
+ ]
506
+ blocks_args = BlockDecoder.decode(blocks_args)
507
+
508
+ global_params = GlobalParams(
509
+ width_coefficient=width_coefficient,
510
+ depth_coefficient=depth_coefficient,
511
+ image_size=image_size,
512
+ dropout_rate=dropout_rate,
513
+
514
+ num_classes=num_classes,
515
+ batch_norm_momentum=0.99,
516
+ batch_norm_epsilon=1e-3,
517
+ drop_connect_rate=drop_connect_rate,
518
+ depth_divisor=8,
519
+ min_depth=None,
520
+ include_top=include_top,
521
+ )
522
+
523
+ return blocks_args, global_params
524
+
525
+
526
+ def get_model_params(model_name, override_params):
527
+ """Get the block args and global params for a given model name.
528
+
529
+ Args:
530
+ model_name (str): Model's name.
531
+ override_params (dict): A dict to modify global_params.
532
+
533
+ Returns:
534
+ blocks_args, global_params
535
+ """
536
+ if model_name.startswith('efficientnet'):
537
+ w, d, s, p = efficientnet_params(model_name)
538
+ # note: all models have drop connect rate = 0.2
539
+ blocks_args, global_params = efficientnet(
540
+ width_coefficient=w, depth_coefficient=d, dropout_rate=p, image_size=s)
541
+ else:
542
+ raise NotImplementedError('model name is not pre-defined: {}'.format(model_name))
543
+ if override_params:
544
+ # ValueError will be raised here if override_params has fields not included in global_params.
545
+ global_params = global_params._replace(**override_params)
546
+ return blocks_args, global_params
547
+
548
+
549
+ # train with Standard methods
550
+ # check more details in paper(EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks)
551
+ url_map = {
552
+ 'efficientnet-b0': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b0-355c32eb.pth',
553
+ 'efficientnet-b1': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b1-f1951068.pth',
554
+ 'efficientnet-b2': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b2-8bb594d6.pth',
555
+ 'efficientnet-b3': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b3-5fb5a3c3.pth',
556
+ 'efficientnet-b4': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b4-6ed6700e.pth',
557
+ 'efficientnet-b5': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b5-b6417697.pth',
558
+ 'efficientnet-b6': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b6-c76e70fd.pth',
559
+ 'efficientnet-b7': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b7-dcc49843.pth',
560
+ }
561
+
562
+ # train with Adversarial Examples(AdvProp)
563
+ # check more details in paper(Adversarial Examples Improve Image Recognition)
564
+ url_map_advprop = {
565
+ 'efficientnet-b0': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b0-b64d5a18.pth',
566
+ 'efficientnet-b1': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b1-0f3ce85a.pth',
567
+ 'efficientnet-b2': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b2-6e9d97e5.pth',
568
+ 'efficientnet-b3': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b3-cdd7c0f4.pth',
569
+ 'efficientnet-b4': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b4-44fb3a87.pth',
570
+ 'efficientnet-b5': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b5-86493f6b.pth',
571
+ 'efficientnet-b6': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b6-ac80338e.pth',
572
+ 'efficientnet-b7': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b7-4652b6dd.pth',
573
+ 'efficientnet-b8': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b8-22a8fe65.pth',
574
+ }
575
+
576
+ # TODO: add the petrained weights url map of 'efficientnet-l2'
577
+
578
+
579
+ def load_pretrained_weights(model, model_name, weights_path=None, load_fc=True, advprop=False):
580
+ """Loads pretrained weights from weights path or download using url.
581
+
582
+ Args:
583
+ model (Module): The whole model of efficientnet.
584
+ model_name (str): Model name of efficientnet.
585
+ weights_path (None or str):
586
+ str: path to pretrained weights file on the local disk.
587
+ None: use pretrained weights downloaded from the Internet.
588
+ load_fc (bool): Whether to load pretrained weights for fc layer at the end of the model.
589
+ advprop (bool): Whether to load pretrained weights
590
+ trained with advprop (valid when weights_path is None).
591
+ """
592
+ if isinstance(weights_path, str):
593
+ state_dict = torch.load(weights_path)
594
+ else:
595
+ # AutoAugment or Advprop (different preprocessing)
596
+ url_map_ = url_map_advprop if advprop else url_map
597
+ state_dict = model_zoo.load_url(url_map_[model_name])
598
+
599
+ if load_fc:
600
+ ret = model.load_state_dict(state_dict, strict=False)
601
+ assert not ret.missing_keys, 'Missing keys when loading pretrained weights: {}'.format(ret.missing_keys)
602
+ else:
603
+ state_dict.pop('_fc.weight')
604
+ state_dict.pop('_fc.bias')
605
+ ret = model.load_state_dict(state_dict, strict=False)
606
+ assert set(ret.missing_keys) == set(
607
+ ['_fc.weight', '_fc.bias']), 'Missing keys when loading pretrained weights: {}'.format(ret.missing_keys)
608
+ assert not ret.unexpected_keys, 'Missing keys when loading pretrained weights: {}'.format(ret.unexpected_keys)
609
+
610
+ print('Loaded pretrained weights for {}'.format(model_name))