Register
Login
Resources
Docs Blog Datasets Glossary Case Studies Tutorials & Webinars
Product
Data Engine LLMs Platform Enterprise
Pricing Explore
Connect to our Discord channel
Karl Hornlund 35192b07c4
updated readme
4 years ago
f382f848d6
Trained tight cropped model
4 years ago
f382f848d6
Trained tight cropped model
4 years ago
928224a714
Added plots for custom LR scheduler
4 years ago
87c0b730dc
End of competition
4 years ago
01f40e3fed
Added preprocessing images
4 years ago
5edd7a7e2f
removed broken tests
4 years ago
cd5e0885d4
Returned to adaptive robust loss, added ranger optimizer, and CLI to upload dataset to kaggle
4 years ago
35192b07c4
updated readme
4 years ago
613c8a0cea
removed unused packages from robust_loss
4 years ago
53e39bb954
Changed .yaml extensions to .yml
4 years ago
0d27edb027
Working implementation
4 years ago
862ca80fab
first commit
4 years ago
Storage Buckets

README.rst

You have to be logged in to leave a comment. Sign In
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
  1. ===================================================================================================
  2. `Aptos 2019 Blindness Detection <https://www.kaggle.com/c/aptos2019-blindness-detection/overview>`_
  3. ===================================================================================================
  4. *"Millions of people suffer from diabetic retinopathy, the leading cause of blindness among working
  5. aged adults. Aravind Eye Hospital in India hopes to detect and prevent this disease among people
  6. living in rural areas where medical screening is difficult to conduct."*
  7. This competition was a lot of fun and gave me the opportunity to explore a variety of ML techniques.
  8. .. contents:: **Table of Contents**
  9. :depth: 3
  10. Competition Report
  11. ==================
  12. Results
  13. -------
  14. 83rd/2987 | Top 3% | Silver Medal
  15. Overview
  16. --------
  17. 1. `EfficientNet <https://github.com/lukemelas/EfficientNet-PyTorch>`_ (pretrained on ImageNet)
  18. 2. Regression
  19. 3. Variety of preprocessing/augmentation techniques
  20. 4. Train on 2015 train + test data
  21. 5. Fine-tune on 2019 data
  22. 6. Ensemble 5 models
  23. Network + Training Loop
  24. -----------------------
  25. Architecture
  26. ~~~~~~~~~~~~
  27. I primarily used ``EfficientNet-b2``. I experimented with the ``b3`` but didn't notice a
  28. significant improvement, and larger models were limited by using my GPU at home.
  29. I tried using `Apex <https://github.com/NVIDIA/apex>`_ to train using half-precision but had
  30. problems saving/loading models, and problems installing ``Apex`` in the Kaggle kernels.
  31. Loss
  32. ~~~~
  33. Participants had a choice in this competition to approach it as classification or regression
  34. problem. I had best results treating it as a regression problem with ``MSE``.
  35. Other things I tried:
  36. 1. `Robust Loss <https://github.com/jonbarron/robust_loss_pytorch>`_, which was introduced at CVPR
  37. recently.
  38. 2. `Wassertein metric <https://en.wikipedia.org/wiki/Wasserstein_metric>`_ AKA
  39. `Earth Mover's Distance <https://en.wikipedia.org/wiki/Earth_mover%27s_distance>`_. I couldn't find
  40. a good implementation of it so I wrote my own. It seemed to work - but didn't perform better than
  41. ``MSE``.
  42. Some competitors had success with ordinal classification, or using a mixed loss function.
  43. Optimizer
  44. ~~~~~~~~~
  45. I experimented with ``Adam``, ``RMSProp``, and ``SGD`` early on and found ``Adam`` to perform best.
  46. Later on I switched to using
  47. `Ranger <https://github.com/lessw2020/Ranger-Deep-Learning-Optimizer>`_, which is
  48. ``RAdam`` + ``LookAhead``.
  49. LR Scheduler
  50. ~~~~~~~~~~~~
  51. I implemented some custom LR schedulers and found Flat Cosine Annealing to work best:
  52. .. image:: ./resources/flat-cosine-annealing-scheduler.png
  53. .. image:: ./resources/slow-start-cosine-annealing-scheduler.png
  54. .. image:: ./resources/cyclical-decay-scheduler.png
  55. Noisy Labels
  56. ~~~~~~~~~~~~
  57. I figured that with >80,000 images in the 2015 dataset and heavy augmentation I could train for
  58. many epochs. In order to guard against overfitting and smooth out the regression target labels,
  59. I added some normally distributed noise (mean=0, std=0.1) to the labels. I found this helped
  60. slightly although it was difficult to evaluate given the uncertainty around public LB scores.
  61. Data
  62. ----
  63. I pretrained on the train + test data from 2015, before fine-tuning on the 2019 training set.
  64. Image Size
  65. ~~~~~~~~~~
  66. While I experimented a little with image size, almost all models I trained used ``256x256`` images.
  67. Many of the best submissions used a variety of image sizes, and often much larger images. I should
  68. do this in future competitions.
  69. Preprocessing & Augmentation
  70. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  71. I used a variety of preprocessing and augmentation techniques, outlined below.
  72. Ben's Cropping
  73. **************
  74. I started out by using a technique similar to the
  75. `winner of the 2015 competition <https://www.kaggle.com/c/diabetic-retinopathy-detection/discussion/15801#latest-370950>`_.
  76. Early on in the competition I got to rank 8 with this model (Public 0.781, Private 0.902).
  77. .. image:: ./resources/bencrop.png
  78. Circle Crop
  79. ***********
  80. I tried a simple circle crop, which led to my best performing single model
  81. (Public 0.791, Private 0.913).
  82. .. image:: ./resources/circlecrop.png
  83. Tight Crop
  84. **********
  85. The test set images looked quite different from the training set, so I tried a *tight* cropping
  86. method to try to make the training examples more similar to the test set. I implemented this on the
  87. final day of the competition and didn't use a submission to evaluate it independently - I just took
  88. a chance and included it in my final ensemble.
  89. .. image:: ./resources/tightcrop.png
  90. Mixup
  91. *****
  92. I implemented mixup hoping to smooth out the distribution of regression targets. When an image was
  93. selected by the sampler I would mix it with a random image from a neighbouring class, choosing a
  94. blend parameter from a Beta distribution (0.4, 0.4).
  95. I tried this with some different preprocessing techniques as shown below, but found it yielded
  96. poor results (Public 0.760, Private 0.908). Other contestants who tried mixup also reported poor
  97. results. Thinking about it now, the private LB score is actually not bad for a single model - I
  98. probably gave up on this prematurely because of the low public LB score.
  99. .. image:: ./resources/mixup-bencrop.png
  100. .. image:: ./resources/mixup-bencrop-tight.png
  101. .. image:: ./resources/mixup-tight.png
  102. Sampling Strategy
  103. ~~~~~~~~~~~~~~~~~
  104. The data for this competition had quite imbalanced classes, so I wrote a custom ``PyTorch``
  105. ``BatchSampler`` to help with this problem.
  106. See ``aptos.data_loader.sampler`` for implementation details.
  107. Class Balancing
  108. ***************
  109. Based on the choice of an ``alpha`` parameter in ``[0, 1]`` the sampler would adjust the sample
  110. distribution to be between true distribution (``alpha = 0``), and a uniform distribution
  111. (``alpha = 1``).
  112. Overrepresented classes would be undersampled, and underrepresented classes oversampled.
  113. .. image:: ./resources/sample-distributions-2019-data.png
  114. Note the extreme imbalance for the 2015 data.
  115. .. image:: ./resources/sample-distributions-2015-data.png
  116. Typically for training on the 2015 data I used an ``alpha`` value of 0.8, and for fine-tuning on
  117. the 2019 data I used alpha values in the range 0.2 to 0.8.
  118. Standardised Batches
  119. ********************
  120. Each sample generated would contain exactly the specified proportion of classes.
  121. Here are a few sample batches of labels from a sampler with ``alpha = 0.5`` and ``batch_size = 32``
  122. .. code::
  123. Batch: 0
  124. Classes: [1, 0, 0, 0, 2, 4, 0, 2, 0, 0, 3, 2, 1, 0, 2, 0, 0, 3, 0, 0, 4, 4, 0, 2, 1, 3, 3, 1, 2, 0, 0, 4]
  125. Counts: {0: 14, 1: 4, 2: 6, 3: 4, 4: 4}
  126. Batch: 1
  127. Classes: [4, 1, 1, 2, 0, 0, 0, 4, 2, 4, 0, 3, 1, 3, 0, 0, 3, 2, 0, 2, 4, 2, 0, 0, 2, 3, 0, 1, 0, 0, 0, 0]
  128. Counts: {0: 14, 1: 4, 2: 6, 3: 4, 4: 4}
  129. Batch: 2
  130. Classes: [0, 4, 0, 0, 0, 3, 3, 2, 0, 4, 2, 3, 0, 3, 2, 0, 0, 1, 2, 2, 0, 1, 0, 0, 4, 0, 2, 1, 1, 4, 0, 0]
  131. Counts: {0: 14, 1: 4, 2: 6, 3: 4, 4: 4}
  132. Note that the class counts are the same for each batch. I found this helped training converge
  133. faster, and my models generalised better. It was also a way to create diversity of models trained
  134. with the same architecture - much like how people use varying image sizes.
  135. Ensemble
  136. --------
  137. My final ensemble was as follows:
  138. 1. 3x bencrop models, different seeds, 4x TTA (rot90)
  139. 2. 3x circlecrop models, different seeds + sampling alpha, 4x TTA (rot90)
  140. 3. 2x tightcrop models, different seeds + sampling alpha, 4x TTA (rot90)
  141. 4. 2x mixup models, different seeds + sampling alpha, 4x TTA (rot90)
  142. 5. 5x EfficientNet B5 with img sizes 224, 232, 240, 248, 256 from `this kernel <https://www.kaggle.com/xwxw2929/starter-kernel-for-0-79>`_.
  143. I took the mean of each ensemble group, and took a weighted average of those means:
  144. .. code:: python
  145. w_bencrop = 0.8
  146. w_karl = 1.0
  147. w_tight = 0.7
  148. w_mixup = 0.6
  149. w_fastai = 1.4
  150. This led to the final public LB score of 0.809 and private 0.922.
  151. Funnily enough, I made a final submission using the following weights:
  152. .. code:: python
  153. w_bencrop = 0.9
  154. w_karl = 1.0
  155. w_tight = 0.9
  156. w_mixup = 0.9
  157. w_fastai = 1.1
  158. Which gave a public score of 0.804 but the same private score of 0.922.
  159. Afterthoughts
  160. -------------
  161. While I was able to boost my score by ensembling models trained with diverse preprocessing methods,
  162. I should have explored using different architectures. Some of the other participants achieved great
  163. results using Inception and SEResNext models (in fact, the 1st place winner used only these models).
  164. Others had success using the larger EfficientNet models, and larger image sizes. I think training
  165. using fp16 will be increasingly popular because of the huge GPU memory efficiency gains.
  166. Interestingly, many of the top performers did minimal preprocessing. The winning solution only
  167. resized the images to 512x512.
  168. Apparently others found pseudo-labelling to be highly effective for this competition. I hadn't
  169. heard of it before reading about it in their post-competition reports - I'll have to give this a
  170. try in future.
  171. I had the idea to combine regression and categorical loss functions, but didn't end up implementing
  172. it. Now with the knowledge of how others did it, I think I would try that in the future.
  173. Gold Medal Solutions
  174. --------------------
  175. `1st <https://www.kaggle.com/c/aptos2019-blindness-detection/discussion/108065>`_ |
  176. `2nd <https://www.kaggle.com/c/aptos2019-blindness-detection/discussion/107926>`_ |
  177. `4th <https://www.kaggle.com/c/aptos2019-blindness-detection/discussion/107987>`_ |
  178. `5th <https://www.kaggle.com/c/aptos2019-blindness-detection/discussion/107960>`_ |
  179. `7th <https://www.kaggle.com/c/aptos2019-blindness-detection/discussion/108058>`_ |
  180. `8th <https://www.kaggle.com/c/aptos2019-blindness-detection/discussion/108030>`_ |
  181. `9th <https://www.kaggle.com/c/aptos2019-blindness-detection/discussion/107990>`_ and
  182. `9th <https://www.kaggle.com/c/aptos2019-blindness-detection/discussion/108072>`_ |
  183. `10th <https://www.kaggle.com/c/aptos2019-blindness-detection/discussion/107944>`_ |
  184. `11th <https://www.kaggle.com/c/aptos2019-blindness-detection/discussion/107958>`_ |
  185. `12th <https://www.kaggle.com/c/aptos2019-blindness-detection/discussion/107995>`_
  186. User Guide
  187. ==========
  188. Requirements
  189. ------------
  190. * Python >= 3.6
  191. * PyTorch >= 1.1
  192. * Tensorboard >= 1.4
  193. Folder Structure
  194. ----------------
  195. ::
  196. aptos2019-blindness-detection/
  197. ├── aptos/
  198. │ │
  199. │ ├── cli.py - command line interface
  200. │ ├── main.py - main script to start train/test
  201. │ │
  202. │ ├── base/ - abstract base classes
  203. │ │ ├── base_model.py - abstract base class for models
  204. │ │ └── base_trainer.py - abstract base class for trainers
  205. │ │
  206. │ ├── data_loader/ - anything about data loading goes here
  207. │ │ ├── augmentation.py
  208. │ │ ├── data_loaders.py
  209. │ │ ├── datasets.py
  210. │ │ ├── preprocess.py
  211. │ │ └── sampler.py
  212. │ │
  213. │ ├── model/ - models, losses, and metrics
  214. │ │ ├── loss.py
  215. │ │ ├── metric.py
  216. │ │ ├── model.py
  217. │ │ ├── optimizer.py
  218. │ │ └── scheduler.py
  219. │ │
  220. │ ├── trainer/ - trainers
  221. │ │ └── trainer.py
  222. │ │
  223. │ └── utils/
  224. │ ├── flatten.py - outputs codebase as a flat file for running in a kernel
  225. │ ├── logger.py - class for train logging
  226. │ ├── saving.py - manages pathing for saving models + logs
  227. │ ├── upload.py - uploads trained model to Kaggle using Kaggle API
  228. │ └── visualization.py - class for Tensorboard visualization support
  229. ├── logging.yml - logging configuration
  230. ├── environment.yml - conda environment recipe
  231. ├── data/ - directory for storing raw/processed data
  232. ├── experiments/ - directory for storing configuration files
  233. ├── notebook/ - directory for jupyter notebooks
  234. ├── reference/ - directory for reference documentation
  235. ├── resources/ - directory for images to show in README
  236. ├── saved/ - directory for checkpoints and logs
  237. └── tests/ - directory for tests
  238. Usage
  239. -----
  240. Setup
  241. ~~~~~
  242. 1. Create Anaconda environment:
  243. .. code-block:: bash
  244. $ conda env create --file environment.yml
  245. $ conda activate aptos
  246. 2. Download the data (you will need `Kaggle API <https://github.com/Kaggle/kaggle-api>`_ set up)
  247. Official competition data:
  248. .. code-block:: bash
  249. $ mkdir data/raw
  250. $ cd data/raw
  251. $ kaggle competitions download -c aptos2019-blindness-detection
  252. $ unzip train_images.zip train_images/
  253. 2015 training data:
  254. .. code-block:: bash
  255. $ mkdir diabetic-retinopathy-detection
  256. $ cd diabetic-retinopathy-detection
  257. $ kaggle datasets download -d tanlikesmath/diabetic-retinopathy-resized
  258. $ unzip resized_train_cropped.zip resized_train_cropped/
  259. 2015 test data:
  260. .. code-block:: bash
  261. $ kaggle datasets download -d benjaminwarner/resized-2015-2019-blindness-detection-images -f "resized test 15.zip"
  262. $ kaggle datasets download -d benjaminwarner/resized-2015-2019-blindness-detection-images -f "labels.zip"
  263. $ unzip "resized test 15.zip" resized_test/
  264. $ unzip labels.zip
  265. $ cp labels/testLabels15.csv testLabels.csv
  266. 3. Preprocess the data. See ``notebooks/preprocess.ipynb``
  267. and ``notebooks/preprocess-diabetic-retinopathy.ipynb``
  268. Training
  269. ~~~~~~~~
  270. 1. Create a config file eg. ``experiments/config.yml``
  271. 2. Start training using your config:
  272. .. code-block:: bash
  273. $ aptos train -c experiments/config.yml
  274. 3. Fine-tune as necessary:
  275. .. code-block:: bash
  276. $ aptos train -c experiments/config.yml -r path/to/trained/model.pt
  277. Tensorboard Visualization
  278. ~~~~~~~~~~~~~~~~~~~~~~~~~
  279. This project supports `<https://pytorch.org/docs/stable/tensorboard.html>`_ visualization.
  280. All runs are logged to the ``saved/`` folder by default. You can launch tensorboard using:
  281. .. code:: bash
  282. $ tensorboard --logdir saved/
  283. Cookiecutter Template
  284. =====================
  285. This project was generated using
  286. `PyTorch Cookiecutter Template <https://github.com/khornlund/cookiecutter-pytorch>`_.
Tip!

Press p or to see the previous file or, n or to see the next file

About

No description

Collaborators 1

Comments

Loading...